@ai-zen/cli 1.0.0-alpha.3 → 1.0.0-alpha.30
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.
- package/CHANGELOG.md +885 -0
- package/LICENSE +21 -0
- package/README.md +135 -30
- package/README.zh.md +135 -30
- package/dist/agent-creator.d.ts +11 -0
- package/dist/agent-creator.d.ts.map +1 -1
- package/dist/agent-creator.js +50 -20
- package/dist/agent-creator.js.map +1 -1
- package/dist/agent-switch.d.ts +61 -0
- package/dist/agent-switch.d.ts.map +1 -0
- package/dist/agent-switch.js +83 -0
- package/dist/agent-switch.js.map +1 -0
- package/dist/agents-store.d.ts +6 -1
- package/dist/agents-store.d.ts.map +1 -1
- package/dist/agents-store.js +46 -4
- package/dist/agents-store.js.map +1 -1
- package/dist/auto-migrate-confirm.d.ts +43 -0
- package/dist/auto-migrate-confirm.d.ts.map +1 -0
- package/dist/auto-migrate-confirm.js +47 -0
- package/dist/auto-migrate-confirm.js.map +1 -0
- package/dist/clipboard.d.ts +68 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +177 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/config-editor.d.ts +42 -5
- package/dist/config-editor.d.ts.map +1 -1
- package/dist/config-editor.js +80 -27
- package/dist/config-editor.js.map +1 -1
- package/dist/config.d.ts +76 -17
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +143 -39
- package/dist/config.js.map +1 -1
- package/dist/conversation-commands/registry.d.ts +127 -4
- package/dist/conversation-commands/registry.d.ts.map +1 -1
- package/dist/conversation-commands/registry.js +93 -14
- package/dist/conversation-commands/registry.js.map +1 -1
- package/dist/conversation-persist-plugin.d.ts +0 -1
- package/dist/conversation-persist-plugin.d.ts.map +1 -1
- package/dist/conversation-persist-plugin.js +7 -16
- package/dist/conversation-persist-plugin.js.map +1 -1
- package/dist/conversation-repository.d.ts +79 -18
- package/dist/conversation-repository.d.ts.map +1 -1
- package/dist/conversation-repository.js +96 -30
- package/dist/conversation-repository.js.map +1 -1
- package/dist/cwd-tracker-plugin.d.ts.map +1 -1
- package/dist/cwd-tracker-plugin.js +22 -7
- package/dist/cwd-tracker-plugin.js.map +1 -1
- package/dist/format-time.d.ts +17 -6
- package/dist/format-time.d.ts.map +1 -1
- package/dist/format-time.js +32 -14
- package/dist/format-time.js.map +1 -1
- package/dist/handoff-service.d.ts +19 -0
- package/dist/handoff-service.d.ts.map +1 -0
- package/dist/handoff-service.js +89 -0
- package/dist/handoff-service.js.map +1 -0
- package/dist/hook.d.ts.map +1 -1
- package/dist/hook.js +69 -15
- package/dist/hook.js.map +1 -1
- package/dist/i18n/en-wizard.d.ts +8 -0
- package/dist/i18n/en-wizard.d.ts.map +1 -0
- package/dist/i18n/en-wizard.js +303 -0
- package/dist/i18n/en-wizard.js.map +1 -0
- package/dist/i18n/en.d.ts +7 -0
- package/dist/i18n/en.d.ts.map +1 -0
- package/dist/i18n/en.js +247 -0
- package/dist/i18n/en.js.map +1 -0
- package/dist/i18n/index.d.ts +57 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +109 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/preferences.d.ts +37 -0
- package/dist/i18n/preferences.d.ts.map +1 -0
- package/dist/i18n/preferences.js +73 -0
- package/dist/i18n/preferences.js.map +1 -0
- package/dist/i18n/zh-wizard.d.ts +11 -0
- package/dist/i18n/zh-wizard.d.ts.map +1 -0
- package/dist/i18n/zh-wizard.js +306 -0
- package/dist/i18n/zh-wizard.js.map +1 -0
- package/dist/i18n/zh.d.ts +10 -0
- package/dist/i18n/zh.d.ts.map +1 -0
- package/dist/i18n/zh.js +251 -0
- package/dist/i18n/zh.js.map +1 -0
- package/dist/index.js +72 -25
- package/dist/index.js.map +1 -1
- package/dist/mcp-command.d.ts +32 -0
- package/dist/mcp-command.d.ts.map +1 -0
- package/dist/mcp-command.js +37 -0
- package/dist/mcp-command.js.map +1 -0
- package/dist/mode.d.ts +31 -4
- package/dist/mode.d.ts.map +1 -1
- package/dist/mode.js +42 -7
- package/dist/mode.js.map +1 -1
- package/dist/model-switch.d.ts +58 -0
- package/dist/model-switch.d.ts.map +1 -0
- package/dist/model-switch.js +62 -0
- package/dist/model-switch.js.map +1 -0
- package/dist/reasoning-effort.d.ts +96 -0
- package/dist/reasoning-effort.d.ts.map +1 -0
- package/dist/reasoning-effort.js +164 -0
- package/dist/reasoning-effort.js.map +1 -0
- package/dist/reasoning-presets.d.ts +34 -0
- package/dist/reasoning-presets.d.ts.map +1 -0
- package/dist/reasoning-presets.js +85 -0
- package/dist/reasoning-presets.js.map +1 -0
- package/dist/sdk-log.d.ts +84 -0
- package/dist/sdk-log.d.ts.map +1 -0
- package/dist/sdk-log.js +167 -0
- package/dist/sdk-log.js.map +1 -0
- package/dist/session-pointer.d.ts.map +1 -1
- package/dist/session-pointer.js +10 -4
- package/dist/session-pointer.js.map +1 -1
- package/dist/stdio-runner.d.ts.map +1 -1
- package/dist/stdio-runner.js +32 -30
- package/dist/stdio-runner.js.map +1 -1
- package/dist/sub-agent-guard-plugin.d.ts +10 -7
- package/dist/sub-agent-guard-plugin.d.ts.map +1 -1
- package/dist/sub-agent-guard-plugin.js +12 -9
- package/dist/sub-agent-guard-plugin.js.map +1 -1
- package/dist/tui/chat-history.d.ts +29 -0
- package/dist/tui/chat-history.d.ts.map +1 -0
- package/dist/tui/chat-history.js +55 -0
- package/dist/tui/chat-history.js.map +1 -0
- package/dist/tui/chat-session.d.ts +177 -57
- package/dist/tui/chat-session.d.ts.map +1 -1
- package/dist/tui/chat-session.js +362 -126
- package/dist/tui/chat-session.js.map +1 -1
- package/dist/tui/components.d.ts +113 -7
- package/dist/tui/components.d.ts.map +1 -1
- package/dist/tui/components.js +177 -12
- package/dist/tui/components.js.map +1 -1
- package/dist/tui/config-wizard/detail.d.ts +18 -10
- package/dist/tui/config-wizard/detail.d.ts.map +1 -1
- package/dist/tui/config-wizard/detail.js +53 -46
- package/dist/tui/config-wizard/detail.js.map +1 -1
- package/dist/tui/config-wizard/engine.d.ts +2 -2
- package/dist/tui/config-wizard/engine.d.ts.map +1 -1
- package/dist/tui/config-wizard/engine.js +48 -26
- package/dist/tui/config-wizard/engine.js.map +1 -1
- package/dist/tui/config-wizard/fields.d.ts +3 -1
- package/dist/tui/config-wizard/fields.d.ts.map +1 -1
- package/dist/tui/config-wizard/fields.js +202 -167
- package/dist/tui/config-wizard/fields.js.map +1 -1
- package/dist/tui/config-wizard/frame.js +1 -1
- package/dist/tui/config-wizard/kv-editor.d.ts.map +1 -1
- package/dist/tui/config-wizard/kv-editor.js +13 -5
- package/dist/tui/config-wizard/kv-editor.js.map +1 -1
- package/dist/tui/config-wizard/list.d.ts +3 -1
- package/dist/tui/config-wizard/list.d.ts.map +1 -1
- package/dist/tui/config-wizard/list.js +4 -4
- package/dist/tui/config-wizard/list.js.map +1 -1
- package/dist/tui/config-wizard/mcp-helpers.d.ts.map +1 -1
- package/dist/tui/config-wizard/mcp-helpers.js +4 -3
- package/dist/tui/config-wizard/mcp-helpers.js.map +1 -1
- package/dist/tui/config-wizard/menu.d.ts.map +1 -1
- package/dist/tui/config-wizard/menu.js +33 -21
- package/dist/tui/config-wizard/menu.js.map +1 -1
- package/dist/tui/config-wizard/prompt-editor.d.ts +8 -1
- package/dist/tui/config-wizard/prompt-editor.d.ts.map +1 -1
- package/dist/tui/config-wizard/prompt-editor.js +11 -7
- package/dist/tui/config-wizard/prompt-editor.js.map +1 -1
- package/dist/tui/config-wizard/prompt.d.ts.map +1 -1
- package/dist/tui/config-wizard/prompt.js +8 -7
- package/dist/tui/config-wizard/prompt.js.map +1 -1
- package/dist/tui/config-wizard/step-agents.d.ts.map +1 -1
- package/dist/tui/config-wizard/step-agents.js +50 -29
- package/dist/tui/config-wizard/step-agents.js.map +1 -1
- package/dist/tui/config-wizard/step-defaults.d.ts.map +1 -1
- package/dist/tui/config-wizard/step-defaults.js +77 -27
- package/dist/tui/config-wizard/step-defaults.js.map +1 -1
- package/dist/tui/config-wizard/step-endpoints.d.ts.map +1 -1
- package/dist/tui/config-wizard/step-endpoints.js +27 -14
- package/dist/tui/config-wizard/step-endpoints.js.map +1 -1
- package/dist/tui/config-wizard/step-mcp.d.ts.map +1 -1
- package/dist/tui/config-wizard/step-mcp.js +29 -25
- package/dist/tui/config-wizard/step-mcp.js.map +1 -1
- package/dist/tui/config-wizard/step-models.d.ts.map +1 -1
- package/dist/tui/config-wizard/step-models.js +98 -43
- package/dist/tui/config-wizard/step-models.js.map +1 -1
- package/dist/tui/config-wizard/step-new-endpoint.d.ts.map +1 -1
- package/dist/tui/config-wizard/step-new-endpoint.js +16 -12
- package/dist/tui/config-wizard/step-new-endpoint.js.map +1 -1
- package/dist/tui/config-wizard/step-simple.d.ts.map +1 -1
- package/dist/tui/config-wizard/step-simple.js +18 -17
- package/dist/tui/config-wizard/step-simple.js.map +1 -1
- package/dist/tui/config-wizard/types.d.ts +31 -3
- package/dist/tui/config-wizard/types.d.ts.map +1 -1
- package/dist/tui/config-wizard/types.js.map +1 -1
- package/dist/tui/file-index.d.ts +38 -0
- package/dist/tui/file-index.d.ts.map +1 -0
- package/dist/tui/file-index.js +117 -0
- package/dist/tui/file-index.js.map +1 -0
- package/dist/tui/index.d.ts +18 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +107 -49
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/input-editing.d.ts +52 -0
- package/dist/tui/input-editing.d.ts.map +1 -0
- package/dist/tui/input-editing.js +91 -0
- package/dist/tui/input-editing.js.map +1 -0
- package/dist/tui/key-debug.d.ts +62 -0
- package/dist/tui/key-debug.d.ts.map +1 -0
- package/dist/tui/key-debug.js +92 -0
- package/dist/tui/key-debug.js.map +1 -0
- package/dist/tui/mention.d.ts +47 -0
- package/dist/tui/mention.d.ts.map +1 -0
- package/dist/tui/mention.js +152 -0
- package/dist/tui/mention.js.map +1 -0
- package/dist/tui/mouse.d.ts +55 -0
- package/dist/tui/mouse.d.ts.map +1 -0
- package/dist/tui/mouse.js +74 -0
- package/dist/tui/mouse.js.map +1 -0
- package/dist/tui/phase.d.ts +64 -0
- package/dist/tui/phase.d.ts.map +1 -0
- package/dist/tui/phase.js +112 -0
- package/dist/tui/phase.js.map +1 -0
- package/dist/tui/screens/agent-tabs.d.ts +53 -0
- package/dist/tui/screens/agent-tabs.d.ts.map +1 -0
- package/dist/tui/screens/agent-tabs.js +81 -0
- package/dist/tui/screens/agent-tabs.js.map +1 -0
- package/dist/tui/screens/chat-commands.d.ts +82 -3
- package/dist/tui/screens/chat-commands.d.ts.map +1 -1
- package/dist/tui/screens/chat-commands.js +688 -160
- package/dist/tui/screens/chat-commands.js.map +1 -1
- package/dist/tui/screens/chat.d.ts +57 -5
- package/dist/tui/screens/chat.d.ts.map +1 -1
- package/dist/tui/screens/chat.js +799 -304
- package/dist/tui/screens/chat.js.map +1 -1
- package/dist/tui/screens/common-keys.d.ts +36 -0
- package/dist/tui/screens/common-keys.d.ts.map +1 -0
- package/dist/tui/screens/common-keys.js +67 -0
- package/dist/tui/screens/common-keys.js.map +1 -0
- package/dist/tui/screens/frame-buffer.d.ts +47 -0
- package/dist/tui/screens/frame-buffer.d.ts.map +1 -0
- package/dist/tui/screens/frame-buffer.js +78 -0
- package/dist/tui/screens/frame-buffer.js.map +1 -0
- package/dist/tui/screens/handoff-choice.d.ts +37 -0
- package/dist/tui/screens/handoff-choice.d.ts.map +1 -0
- package/dist/tui/screens/handoff-choice.js +42 -0
- package/dist/tui/screens/handoff-choice.js.map +1 -0
- package/dist/tui/screens/index.d.ts +11 -9
- package/dist/tui/screens/index.d.ts.map +1 -1
- package/dist/tui/screens/index.js +9 -8
- package/dist/tui/screens/index.js.map +1 -1
- package/dist/tui/screens/input-row.d.ts +64 -0
- package/dist/tui/screens/input-row.d.ts.map +1 -0
- package/dist/tui/screens/input-row.js +67 -0
- package/dist/tui/screens/input-row.js.map +1 -0
- package/dist/tui/screens/input.d.ts +77 -1
- package/dist/tui/screens/input.d.ts.map +1 -1
- package/dist/tui/screens/input.js +125 -8
- package/dist/tui/screens/input.js.map +1 -1
- package/dist/tui/screens/layout.d.ts +42 -3
- package/dist/tui/screens/layout.d.ts.map +1 -1
- package/dist/tui/screens/layout.js +43 -13
- package/dist/tui/screens/layout.js.map +1 -1
- package/dist/tui/screens/lines.d.ts +6 -36
- package/dist/tui/screens/lines.d.ts.map +1 -1
- package/dist/tui/screens/lines.js +8 -71
- package/dist/tui/screens/lines.js.map +1 -1
- package/dist/tui/screens/messages-view.d.ts +29 -0
- package/dist/tui/screens/messages-view.d.ts.map +1 -0
- package/dist/tui/screens/messages-view.js +162 -0
- package/dist/tui/screens/messages-view.js.map +1 -0
- package/dist/tui/screens/notice-bar.d.ts +5 -0
- package/dist/tui/screens/notice-bar.d.ts.map +1 -0
- package/dist/tui/screens/notice-bar.js +21 -0
- package/dist/tui/screens/notice-bar.js.map +1 -0
- package/dist/tui/screens/notice.d.ts +66 -0
- package/dist/tui/screens/notice.d.ts.map +1 -0
- package/dist/tui/screens/notice.js +106 -0
- package/dist/tui/screens/notice.js.map +1 -0
- package/dist/tui/screens/overlays.d.ts.map +1 -1
- package/dist/tui/screens/overlays.js +4 -3
- package/dist/tui/screens/overlays.js.map +1 -1
- package/dist/tui/screens/render.d.ts +2 -4
- package/dist/tui/screens/render.d.ts.map +1 -1
- package/dist/tui/screens/render.js +19 -50
- package/dist/tui/screens/render.js.map +1 -1
- package/dist/tui/screens/splash.d.ts +1 -1
- package/dist/tui/screens/splash.d.ts.map +1 -1
- package/dist/tui/screens/splash.js +12 -3
- package/dist/tui/screens/splash.js.map +1 -1
- package/dist/tui/screens/use-chat-viewport.d.ts +22 -0
- package/dist/tui/screens/use-chat-viewport.d.ts.map +1 -0
- package/dist/tui/screens/use-chat-viewport.js +50 -0
- package/dist/tui/screens/use-chat-viewport.js.map +1 -0
- package/dist/tui/screens/use-input-editing.d.ts +69 -0
- package/dist/tui/screens/use-input-editing.d.ts.map +1 -0
- package/dist/tui/screens/use-input-editing.js +220 -0
- package/dist/tui/screens/use-input-editing.js.map +1 -0
- package/dist/tui/screens/use-overlays.d.ts +25 -0
- package/dist/tui/screens/use-overlays.d.ts.map +1 -0
- package/dist/tui/screens/use-overlays.js +32 -0
- package/dist/tui/screens/use-overlays.js.map +1 -0
- package/dist/tui/screens/use-wizard-host.d.ts +46 -0
- package/dist/tui/screens/use-wizard-host.d.ts.map +1 -0
- package/dist/tui/screens/use-wizard-host.js +123 -0
- package/dist/tui/screens/use-wizard-host.js.map +1 -0
- package/dist/tui/status-segments.d.ts +37 -0
- package/dist/tui/status-segments.d.ts.map +1 -0
- package/dist/tui/status-segments.js +166 -0
- package/dist/tui/status-segments.js.map +1 -0
- package/dist/tui/text.d.ts +27 -7
- package/dist/tui/text.d.ts.map +1 -1
- package/dist/tui/text.js +116 -38
- package/dist/tui/text.js.map +1 -1
- package/dist/tui/theme.d.ts +2 -0
- package/dist/tui/theme.d.ts.map +1 -1
- package/dist/tui/theme.js +2 -0
- package/dist/tui/theme.js.map +1 -1
- package/dist/tui/token-rate.d.ts +83 -0
- package/dist/tui/token-rate.d.ts.map +1 -0
- package/dist/tui/token-rate.js +195 -0
- package/dist/tui/token-rate.js.map +1 -0
- package/dist/types.d.ts +7 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/user-content.d.ts +41 -0
- package/dist/user-content.d.ts.map +1 -0
- package/dist/user-content.js +37 -0
- package/dist/user-content.js.map +1 -0
- package/dist/version-compare.d.ts +37 -0
- package/dist/version-compare.d.ts.map +1 -0
- package/dist/version-compare.js +105 -0
- package/dist/version-compare.js.map +1 -0
- package/dist/version.js.map +1 -1
- package/package.json +5 -4
- package/dist/auto-migrate-confirm-plugin.d.ts +0 -58
- package/dist/auto-migrate-confirm-plugin.d.ts.map +0 -1
- package/dist/auto-migrate-confirm-plugin.js +0 -61
- package/dist/auto-migrate-confirm-plugin.js.map +0 -1
- package/dist/migration-service.d.ts +0 -15
- package/dist/migration-service.d.ts.map +0 -1
- package/dist/migration-service.js +0 -59
- package/dist/migration-service.js.map +0 -1
- package/dist/tui/screens/state.d.ts +0 -30
- package/dist/tui/screens/state.d.ts.map +0 -1
- package/dist/tui/screens/state.js +0 -100
- package/dist/tui/screens/state.js.map +0 -1
package/dist/tui/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tui/index.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAiB,MAAM,KAAK,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tui/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 输入框编辑的纯逻辑层 —— 与 Claude Code / readline 的键位语义对齐。
|
|
3
|
+
*
|
|
4
|
+
* 全部函数都是「(文本, 光标) → (文本, 光标)」的纯变换,便于单测;
|
|
5
|
+
* chat.tsx 只负责把按键映射过来、套用结果、维护 kill ring 与撤销栈。
|
|
6
|
+
*
|
|
7
|
+
* 光标单位是**字素簇**(`graphemes`),不是 code point:`✌️` 是 2 个 code point
|
|
8
|
+
* 但只是 1 个簇,按 code point 删会只删掉半个 emoji、留下孤立的变体选择符。
|
|
9
|
+
*
|
|
10
|
+
* 键位语义依据 Claude Code 官方文档(interactive-mode.md):
|
|
11
|
+
* - `Ctrl+W` 删到**前一空白**(标点不切分:`src/utils/foo.ts` 一次删掉整条路径)
|
|
12
|
+
* - `Alt+B/F/D` 按「词」处理(标点算分隔符:停在 `ts` / `foo` / `utils` / `src`)
|
|
13
|
+
*/
|
|
14
|
+
/** 一段可撤销的编辑状态(文本 + 字素簇光标) */
|
|
15
|
+
export interface EditState {
|
|
16
|
+
text: string;
|
|
17
|
+
cursor: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 删到前一空白(Ctrl+W):先吃掉光标前的空白,再吃掉一整段非空白。
|
|
21
|
+
*
|
|
22
|
+
* 与 `deleteWordLeft` 的区别在于标点:本函数只认空白为边界,
|
|
23
|
+
* 因此 `src/utils/foo.ts` 会被整段删除,而不是只删 `foo.ts`。
|
|
24
|
+
*/
|
|
25
|
+
export declare function deleteToPrevWhitespace(text: string, cursor: number): EditState;
|
|
26
|
+
/**
|
|
27
|
+
* 求「被删掉的文本」:比较编辑前后,取中间不重合的那一段。
|
|
28
|
+
*
|
|
29
|
+
* 用于把 `Ctrl+W/U/K` 删掉的内容放进 kill ring 供 `Ctrl+Y` 取回,
|
|
30
|
+
* 免去每个删除函数各自返回「删了什么」。
|
|
31
|
+
*/
|
|
32
|
+
export declare function killedText(before: string, after: string): string;
|
|
33
|
+
export declare const KILL_RING_SIZE = 5;
|
|
34
|
+
/**
|
|
35
|
+
* 记录一段被删除的文本。
|
|
36
|
+
*
|
|
37
|
+
* 空串不入环;与栈顶相同的连续删除(如连按 `Ctrl+W` 删同一个词)不重复入栈,
|
|
38
|
+
* 否则 `Alt+Y` 会在同一段文本上空转。
|
|
39
|
+
*/
|
|
40
|
+
export declare function pushKill(ring: string[], killed: string, limit?: number): string[];
|
|
41
|
+
/** 取环中第 index 段(越界返回 undefined);index 0 为最近一次删除 */
|
|
42
|
+
export declare function killAt(ring: string[], index: number): string | undefined;
|
|
43
|
+
/** 撤销栈上限:编辑很密,但每条只是一个短字符串,100 条足够 */
|
|
44
|
+
export declare const UNDO_LIMIT = 100;
|
|
45
|
+
/** 入栈一条编辑前快照;与栈顶相同的状态不重复入栈 */
|
|
46
|
+
export declare function pushUndo(stack: EditState[], state: EditState, limit?: number): EditState[];
|
|
47
|
+
/** 出栈一条快照(无历史时返回 null) */
|
|
48
|
+
export declare function popUndo(stack: EditState[]): {
|
|
49
|
+
state: EditState;
|
|
50
|
+
rest: EditState[];
|
|
51
|
+
} | null;
|
|
52
|
+
//# sourceMappingURL=input-editing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-editing.d.ts","sourceRoot":"","sources":["../../src/tui/input-editing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,6BAA6B;AAC7B,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAU9E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQhE;AAGD,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,SAAiB,GAAG,MAAM,EAAE,CAIzF;AAED,mDAAmD;AACnD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;AAID,qCAAqC;AACrC,eAAO,MAAM,UAAU,MAAM,CAAC;AAE9B,8BAA8B;AAC9B,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,SAAa,GAAG,SAAS,EAAE,CAI9F;AAED,0BAA0B;AAC1B,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,SAAS,EAAE,CAAA;CAAE,GAAG,IAAI,CAG1F"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 输入框编辑的纯逻辑层 —— 与 Claude Code / readline 的键位语义对齐。
|
|
3
|
+
*
|
|
4
|
+
* 全部函数都是「(文本, 光标) → (文本, 光标)」的纯变换,便于单测;
|
|
5
|
+
* chat.tsx 只负责把按键映射过来、套用结果、维护 kill ring 与撤销栈。
|
|
6
|
+
*
|
|
7
|
+
* 光标单位是**字素簇**(`graphemes`),不是 code point:`✌️` 是 2 个 code point
|
|
8
|
+
* 但只是 1 个簇,按 code point 删会只删掉半个 emoji、留下孤立的变体选择符。
|
|
9
|
+
*
|
|
10
|
+
* 键位语义依据 Claude Code 官方文档(interactive-mode.md):
|
|
11
|
+
* - `Ctrl+W` 删到**前一空白**(标点不切分:`src/utils/foo.ts` 一次删掉整条路径)
|
|
12
|
+
* - `Alt+B/F/D` 按「词」处理(标点算分隔符:停在 `ts` / `foo` / `utils` / `src`)
|
|
13
|
+
*/
|
|
14
|
+
import { graphemes } from "./text.js";
|
|
15
|
+
function clampCursor(chars, cursor) {
|
|
16
|
+
return Math.max(0, Math.min(cursor, chars.length));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 删到前一空白(Ctrl+W):先吃掉光标前的空白,再吃掉一整段非空白。
|
|
20
|
+
*
|
|
21
|
+
* 与 `deleteWordLeft` 的区别在于标点:本函数只认空白为边界,
|
|
22
|
+
* 因此 `src/utils/foo.ts` 会被整段删除,而不是只删 `foo.ts`。
|
|
23
|
+
*/
|
|
24
|
+
export function deleteToPrevWhitespace(text, cursor) {
|
|
25
|
+
const chars = graphemes(text);
|
|
26
|
+
const cp = clampCursor(chars, cursor);
|
|
27
|
+
let from = cp;
|
|
28
|
+
while (from > 0 && /\s/.test(chars[from - 1]))
|
|
29
|
+
from -= 1;
|
|
30
|
+
while (from > 0 && !/\s/.test(chars[from - 1]))
|
|
31
|
+
from -= 1;
|
|
32
|
+
return {
|
|
33
|
+
text: chars.slice(0, from).join("") + chars.slice(cp).join(""),
|
|
34
|
+
cursor: from,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 求「被删掉的文本」:比较编辑前后,取中间不重合的那一段。
|
|
39
|
+
*
|
|
40
|
+
* 用于把 `Ctrl+W/U/K` 删掉的内容放进 kill ring 供 `Ctrl+Y` 取回,
|
|
41
|
+
* 免去每个删除函数各自返回「删了什么」。
|
|
42
|
+
*/
|
|
43
|
+
export function killedText(before, after) {
|
|
44
|
+
const a = graphemes(before);
|
|
45
|
+
const b = graphemes(after);
|
|
46
|
+
let prefix = 0;
|
|
47
|
+
while (prefix < b.length && a[prefix] === b[prefix])
|
|
48
|
+
prefix += 1;
|
|
49
|
+
let suffix = 0;
|
|
50
|
+
while (suffix < b.length - prefix && a[a.length - 1 - suffix] === b[b.length - 1 - suffix])
|
|
51
|
+
suffix += 1;
|
|
52
|
+
return a.slice(prefix, a.length - suffix).join("");
|
|
53
|
+
}
|
|
54
|
+
// ==================== kill ring(Ctrl+Y / Alt+Y)====================/** kill ring 最大长度(够 Alt+Y 循环几次即可,不做无限历史) */
|
|
55
|
+
export const KILL_RING_SIZE = 5;
|
|
56
|
+
/**
|
|
57
|
+
* 记录一段被删除的文本。
|
|
58
|
+
*
|
|
59
|
+
* 空串不入环;与栈顶相同的连续删除(如连按 `Ctrl+W` 删同一个词)不重复入栈,
|
|
60
|
+
* 否则 `Alt+Y` 会在同一段文本上空转。
|
|
61
|
+
*/
|
|
62
|
+
export function pushKill(ring, killed, limit = KILL_RING_SIZE) {
|
|
63
|
+
if (!killed)
|
|
64
|
+
return ring;
|
|
65
|
+
if (ring[0] === killed)
|
|
66
|
+
return ring;
|
|
67
|
+
return [killed, ...ring].slice(0, limit);
|
|
68
|
+
}
|
|
69
|
+
/** 取环中第 index 段(越界返回 undefined);index 0 为最近一次删除 */
|
|
70
|
+
export function killAt(ring, index) {
|
|
71
|
+
if (index < 0 || index >= ring.length)
|
|
72
|
+
return undefined;
|
|
73
|
+
return ring[index];
|
|
74
|
+
}
|
|
75
|
+
// ==================== 撤销栈(Ctrl+_)====================
|
|
76
|
+
/** 撤销栈上限:编辑很密,但每条只是一个短字符串,100 条足够 */
|
|
77
|
+
export const UNDO_LIMIT = 100;
|
|
78
|
+
/** 入栈一条编辑前快照;与栈顶相同的状态不重复入栈 */
|
|
79
|
+
export function pushUndo(stack, state, limit = UNDO_LIMIT) {
|
|
80
|
+
const top = stack[stack.length - 1];
|
|
81
|
+
if (top && top.text === state.text && top.cursor === state.cursor)
|
|
82
|
+
return stack;
|
|
83
|
+
return [...stack, state].slice(-limit);
|
|
84
|
+
}
|
|
85
|
+
/** 出栈一条快照(无历史时返回 null) */
|
|
86
|
+
export function popUndo(stack) {
|
|
87
|
+
if (stack.length === 0)
|
|
88
|
+
return null;
|
|
89
|
+
return { state: stack[stack.length - 1], rest: stack.slice(0, -1) };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=input-editing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-editing.js","sourceRoot":"","sources":["../../src/tui/input-editing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 按键诊断 —— 不同终端的按键编码差异极大(macOS 的 Option、PageUp/PageDown 尤其),
|
|
3
|
+
* 「某个键在我机器上没反应」这类问题靠猜毫无意义:要么键被 OS/终端吞掉,
|
|
4
|
+
* 要么终端发来的序列和我们认的不一样。两种情况的判定方法是同一个 —— 看日志里有几行。
|
|
5
|
+
*
|
|
6
|
+
* 用法:
|
|
7
|
+
* AIZ_DEBUG_KEYS=1 aiz → 追加写到 <tmp>/aiz-key-debug.log
|
|
8
|
+
* AIZ_DEBUG_KEYS=1 AIZ_KEYS_FILE=/path aiz → 写到指定文件
|
|
9
|
+
*
|
|
10
|
+
* 判读:
|
|
11
|
+
* - 按了键但日志里没有新增行 → 键根本没到应用(被 OS 快捷键或终端键位映射截走)
|
|
12
|
+
* - 有行但 `input`/`flags` 与预期不符 → 序列认识,是匹配逻辑的问题
|
|
13
|
+
* - 有行且 `raw=false` → 终端没处于 raw mode,键被终端自己解释了(如滚动 scrollback)
|
|
14
|
+
*
|
|
15
|
+
* 刻意在 `useInput` 回调里记录而不是直接监听 `stdin` 的 data 事件:
|
|
16
|
+
* 后者会把流切成 flowing 模式,与 Ink 内部的 readable 读取抢数据。
|
|
17
|
+
*/
|
|
18
|
+
export declare const KEY_DEBUG_ENABLED: boolean;
|
|
19
|
+
/** 日志落盘路径(测试与用户都可能改写,故导出常量) */
|
|
20
|
+
export declare const KEY_DEBUG_FILE: string;
|
|
21
|
+
/** Ink `useInput` 的 key 对象里我们关心的字段(结构化,避免依赖 ink 的类型导出) */
|
|
22
|
+
export interface KeyFlags {
|
|
23
|
+
upArrow?: boolean;
|
|
24
|
+
downArrow?: boolean;
|
|
25
|
+
leftArrow?: boolean;
|
|
26
|
+
rightArrow?: boolean;
|
|
27
|
+
pageUp?: boolean;
|
|
28
|
+
pageDown?: boolean;
|
|
29
|
+
return?: boolean;
|
|
30
|
+
escape?: boolean;
|
|
31
|
+
tab?: boolean;
|
|
32
|
+
backspace?: boolean;
|
|
33
|
+
delete?: boolean;
|
|
34
|
+
home?: boolean;
|
|
35
|
+
end?: boolean;
|
|
36
|
+
ctrl?: boolean;
|
|
37
|
+
shift?: boolean;
|
|
38
|
+
meta?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** 终端环境摘要:排查「只在某终端失灵」时先看这一行 */
|
|
41
|
+
export declare function terminalSummary(env?: NodeJS.ProcessEnv): string;
|
|
42
|
+
/**
|
|
43
|
+
* 把一次按键格式化成单行记录。
|
|
44
|
+
*
|
|
45
|
+
* `input` 用 JSON.stringify 转义(控制字符会变成 `\u001b` 这类可读形式),
|
|
46
|
+
* `raw` 表示按下时 stdin 是否仍在 raw mode —— 为 false 时键会被终端自己吃掉。
|
|
47
|
+
*/
|
|
48
|
+
export declare function formatKeyEvent(input: string, key: KeyFlags, raw: boolean): string;
|
|
49
|
+
/** 当前 stdin 是否处于 raw mode(非 TTY 或平台不支持时视为 false) */
|
|
50
|
+
export declare function stdinIsRaw(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* 记录一行到诊断日志;仅在 `AIZ_DEBUG_KEYS=1` 时生效。
|
|
53
|
+
*
|
|
54
|
+
* 同步写:调试期每次按键都写一行,量小;异步写反而可能在崩溃时丢最后几行
|
|
55
|
+
* —— 而那几行往往正是要看的那几行。
|
|
56
|
+
*/
|
|
57
|
+
export declare function keyDebugLog(line: string): void;
|
|
58
|
+
/** 会话开始时写一行环境摘要(同一次运行只写一次) */
|
|
59
|
+
export declare function keyDebugStart(): void;
|
|
60
|
+
/** 记录一次按键 */
|
|
61
|
+
export declare function keyDebug(input: string, key: KeyFlags): void;
|
|
62
|
+
//# sourceMappingURL=key-debug.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-debug.d.ts","sourceRoot":"","sources":["../../src/tui/key-debug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,eAAO,MAAM,iBAAiB,SAAqC,CAAC;AAEpE,+BAA+B;AAC/B,eAAO,MAAM,cAAc,QAAwD,CAAC;AAEpF,0DAA0D;AAC1D,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,+BAA+B;AAC/B,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAK5E;AAqBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAGjF;AAED,oDAAoD;AACpD,wBAAgB,UAAU,IAAI,OAAO,CAGpC;AAID;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAO9C;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,IAAI,IAAI,CAIpC;AAED,aAAa;AACb,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAG3D"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 按键诊断 —— 不同终端的按键编码差异极大(macOS 的 Option、PageUp/PageDown 尤其),
|
|
3
|
+
* 「某个键在我机器上没反应」这类问题靠猜毫无意义:要么键被 OS/终端吞掉,
|
|
4
|
+
* 要么终端发来的序列和我们认的不一样。两种情况的判定方法是同一个 —— 看日志里有几行。
|
|
5
|
+
*
|
|
6
|
+
* 用法:
|
|
7
|
+
* AIZ_DEBUG_KEYS=1 aiz → 追加写到 <tmp>/aiz-key-debug.log
|
|
8
|
+
* AIZ_DEBUG_KEYS=1 AIZ_KEYS_FILE=/path aiz → 写到指定文件
|
|
9
|
+
*
|
|
10
|
+
* 判读:
|
|
11
|
+
* - 按了键但日志里没有新增行 → 键根本没到应用(被 OS 快捷键或终端键位映射截走)
|
|
12
|
+
* - 有行但 `input`/`flags` 与预期不符 → 序列认识,是匹配逻辑的问题
|
|
13
|
+
* - 有行且 `raw=false` → 终端没处于 raw mode,键被终端自己解释了(如滚动 scrollback)
|
|
14
|
+
*
|
|
15
|
+
* 刻意在 `useInput` 回调里记录而不是直接监听 `stdin` 的 data 事件:
|
|
16
|
+
* 后者会把流切成 flowing 模式,与 Ink 内部的 readable 读取抢数据。
|
|
17
|
+
*/
|
|
18
|
+
import { appendFileSync } from "node:fs";
|
|
19
|
+
export const KEY_DEBUG_ENABLED = process.env.AIZ_DEBUG_KEYS === "1";
|
|
20
|
+
/** 日志落盘路径(测试与用户都可能改写,故导出常量) */
|
|
21
|
+
export const KEY_DEBUG_FILE = process.env.AIZ_KEYS_FILE || "/tmp/aiz-key-debug.log";
|
|
22
|
+
/** 终端环境摘要:排查「只在某终端失灵」时先看这一行 */
|
|
23
|
+
export function terminalSummary(env = process.env) {
|
|
24
|
+
const keys = ["TERM", "TERM_PROGRAM", "TERM_PROGRAM_VERSION", "COLORTERM", "LANG", "COLUMNS", "LINES"];
|
|
25
|
+
const parts = keys.map((k) => `${k}=${env[k] ?? "-"}`);
|
|
26
|
+
parts.push(`platform=${process.platform}`, `node=${process.version}`);
|
|
27
|
+
return parts.join(" ");
|
|
28
|
+
}
|
|
29
|
+
const FLAG_NAMES = [
|
|
30
|
+
"ctrl",
|
|
31
|
+
"meta",
|
|
32
|
+
"shift",
|
|
33
|
+
"upArrow",
|
|
34
|
+
"downArrow",
|
|
35
|
+
"leftArrow",
|
|
36
|
+
"rightArrow",
|
|
37
|
+
"pageUp",
|
|
38
|
+
"pageDown",
|
|
39
|
+
"home",
|
|
40
|
+
"end",
|
|
41
|
+
"return",
|
|
42
|
+
"escape",
|
|
43
|
+
"tab",
|
|
44
|
+
"backspace",
|
|
45
|
+
"delete",
|
|
46
|
+
];
|
|
47
|
+
/**
|
|
48
|
+
* 把一次按键格式化成单行记录。
|
|
49
|
+
*
|
|
50
|
+
* `input` 用 JSON.stringify 转义(控制字符会变成 `\u001b` 这类可读形式),
|
|
51
|
+
* `raw` 表示按下时 stdin 是否仍在 raw mode —— 为 false 时键会被终端自己吃掉。
|
|
52
|
+
*/
|
|
53
|
+
export function formatKeyEvent(input, key, raw) {
|
|
54
|
+
const flags = FLAG_NAMES.filter((name) => key[name]).join(",");
|
|
55
|
+
return `key input=${JSON.stringify(input ?? "")} flags=[${flags}] raw=${raw}`;
|
|
56
|
+
}
|
|
57
|
+
/** 当前 stdin 是否处于 raw mode(非 TTY 或平台不支持时视为 false) */
|
|
58
|
+
export function stdinIsRaw() {
|
|
59
|
+
const stdin = process.stdin;
|
|
60
|
+
return Boolean(stdin.isRaw);
|
|
61
|
+
}
|
|
62
|
+
let started = false;
|
|
63
|
+
/**
|
|
64
|
+
* 记录一行到诊断日志;仅在 `AIZ_DEBUG_KEYS=1` 时生效。
|
|
65
|
+
*
|
|
66
|
+
* 同步写:调试期每次按键都写一行,量小;异步写反而可能在崩溃时丢最后几行
|
|
67
|
+
* —— 而那几行往往正是要看的那几行。
|
|
68
|
+
*/
|
|
69
|
+
export function keyDebugLog(line) {
|
|
70
|
+
if (!KEY_DEBUG_ENABLED)
|
|
71
|
+
return;
|
|
72
|
+
try {
|
|
73
|
+
appendFileSync(KEY_DEBUG_FILE, `${new Date().toISOString()} ${line}\n`);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* 诊断失败绝不能影响主流程 */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** 会话开始时写一行环境摘要(同一次运行只写一次) */
|
|
80
|
+
export function keyDebugStart() {
|
|
81
|
+
if (!KEY_DEBUG_ENABLED || started)
|
|
82
|
+
return;
|
|
83
|
+
started = true;
|
|
84
|
+
keyDebugLog(`=== start ${terminalSummary()} file=${KEY_DEBUG_FILE} ===`);
|
|
85
|
+
}
|
|
86
|
+
/** 记录一次按键 */
|
|
87
|
+
export function keyDebug(input, key) {
|
|
88
|
+
if (!KEY_DEBUG_ENABLED)
|
|
89
|
+
return;
|
|
90
|
+
keyDebugLog(formatKeyEvent(input, key, stdinIsRaw()));
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=key-debug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-debug.js","sourceRoot":"","sources":["../../src/tui/key-debug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,GAAG,CAAC;AAEpE,+BAA+B;AAC/B,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,wBAAwB,CAAC;AAsBpF,+BAA+B;AAC/B,MAAM,UAAU,eAAe,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IAClE,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACvG,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACtE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,GAAuB;IACrC,MAAM;IACN,MAAM;IACN,OAAO;IACP,SAAS;IACT,WAAW;IACX,WAAW;IACX,YAAY;IACZ,QAAQ;IACR,UAAU;IACV,MAAM;IACN,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,KAAK;IACL,WAAW;IACX,QAAQ;CACT,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,GAAa,EAAE,GAAY;IACvE,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,OAAO,aAAa,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,WAAW,KAAK,SAAS,GAAG,EAAE,CAAC;AAChF,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,OAAO,CAAC,KAA4B,CAAC;IACnD,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,IAAI,OAAO,GAAG,KAAK,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,CAAC,iBAAiB;QAAE,OAAO;IAC/B,IAAI,CAAC;QACH,cAAc,CAAC,cAAc,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;AACH,CAAC;AAED,8BAA8B;AAC9B,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,iBAAiB,IAAI,OAAO;QAAE,OAAO;IAC1C,OAAO,GAAG,IAAI,CAAC;IACf,WAAW,CAAC,aAAa,eAAe,EAAE,SAAS,cAAc,MAAM,CAAC,CAAC;AAC3E,CAAC;AAED,aAAa;AACb,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,GAAa;IACnD,IAAI,CAAC,iBAAiB;QAAE,OAAO;IAC/B,WAAW,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** 一次 `@` 补全的上下文 */
|
|
2
|
+
export interface Mention {
|
|
3
|
+
/** `@` 之后到**光标**之间的原文(不含 `@`)—— 即用户当前敲的查询串 */
|
|
4
|
+
query: string;
|
|
5
|
+
/** `@` 的字素簇索引 */
|
|
6
|
+
start: number;
|
|
7
|
+
/** token 结束位置(字素簇索引,不含):补全时替换 `[start, end)` */
|
|
8
|
+
end: number;
|
|
9
|
+
}
|
|
10
|
+
/** 索引里的一条候选路径 */
|
|
11
|
+
export interface PathEntry {
|
|
12
|
+
/** 相对 cwd 的路径(`/` 分隔,不带 `./` 前缀) */
|
|
13
|
+
path: string;
|
|
14
|
+
/** 是否目录 —— 决定补全后是否补一个 `/`,让用户可以继续往里钻 */
|
|
15
|
+
dir: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** 候选上限:再多也没人翻;同时给每次按键的内存过滤定个上界(10k 候选实测约 9ms) */
|
|
18
|
+
export declare const MENTION_LIMIT = 50;
|
|
19
|
+
/**
|
|
20
|
+
* 取出光标所在的 `@token`;光标不在 token 里(或不在 mention 语境里)返回 `null`。
|
|
21
|
+
*
|
|
22
|
+
* 纯扫描、无正则回溯:文本长度就是输入框长度,逐字素走一遍即可。
|
|
23
|
+
*/
|
|
24
|
+
export declare function extractMention(text: string, cursor: number): Mention | null;
|
|
25
|
+
/** 补全要插入的文本:`@路径`,目录补一个 `/` 以便继续往下钻 */
|
|
26
|
+
export declare function mentionInsertText(path: string, dir: boolean): string;
|
|
27
|
+
/**
|
|
28
|
+
* 子序列打分(**越小越靠前**);不匹配返回 `null`。
|
|
29
|
+
*
|
|
30
|
+
* 依据实测(10k 条候选、每次按键):贪婪子序列 + 三种加权就够用 ——
|
|
31
|
+
* `tuicha` 能直达 `src/tui/screens/chat.tsx`,不必让用户逐段敲路径。
|
|
32
|
+
*
|
|
33
|
+
* 加权:
|
|
34
|
+
* · 跳跃惩罚:命中间隔越大越差(`t..u..i` 不如 `tui` 连续);
|
|
35
|
+
* · 连续命中奖励:连着的字符是同一段词;
|
|
36
|
+
* · **整体前缀** > **文件名前缀**:`src/tui/` 这种逐段输入要能压过散落命中;
|
|
37
|
+
* · 同分时浅的、短的优先:根目录文件比深埋的图标库更可能被点名。
|
|
38
|
+
*/
|
|
39
|
+
export declare function scorePath(query: string, path: string): number | null;
|
|
40
|
+
/**
|
|
41
|
+
* 过滤 + 排序,取前 `limit` 条。
|
|
42
|
+
*
|
|
43
|
+
* 每次按键都会全量扫一遍(候选只来自内存数组),因此这里不做任何渐进/缓存:
|
|
44
|
+
* 实测 10k 条最长 8.4ms,比一次渲染便宜。
|
|
45
|
+
*/
|
|
46
|
+
export declare function rankPaths(query: string, entries: readonly PathEntry[], limit?: number): PathEntry[];
|
|
47
|
+
//# sourceMappingURL=mention.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mention.d.ts","sourceRoot":"","sources":["../../src/tui/mention.ts"],"names":[],"mappings":"AA6CA,oBAAoB;AACpB,MAAM,WAAW,OAAO;IACtB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,iBAAiB;AACjB,MAAM,WAAW,SAAS;IACxB,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,GAAG,EAAE,OAAO,CAAC;CACd;AAED,kDAAkD;AAClD,eAAO,MAAM,aAAa,KAAK,CAAC;AAMhC;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CA4B3E;AAED,uCAAuC;AACvC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAEpE;AAaD;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBpE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,KAAK,SAAgB,GACpB,SAAS,EAAE,CAQb"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@` 文件路径补全 —— 纯逻辑层:识别 token、给候选排序、算出要插入什么。
|
|
3
|
+
*
|
|
4
|
+
* ## 三层分工
|
|
5
|
+
*
|
|
6
|
+
* · `mention.ts`(本文件):无 IO、无 React,全是可单测的纯函数;
|
|
7
|
+
* · `file-index.ts`:扫描项目文件(git 优先 / `fs.glob` 兜底)并缓存;
|
|
8
|
+
* · `screens/chat.tsx`:只做「按键 → 调上面两者 → 落字」的接线。
|
|
9
|
+
*
|
|
10
|
+
* ## 为什么只插路径文本,不附带文件内容
|
|
11
|
+
*
|
|
12
|
+
* `@` 只把**相对路径**写进草稿,消息本身仍是普通文本,模型用 `read` 工具自己去读。
|
|
13
|
+
* 这样消息契约(core 的 `Message`)一点不动、插入可撤销、超大文件也不会把一条消息
|
|
14
|
+
* 撑成巨型 payload —— 代价是多一轮工具调用,这是刻意的取舍。
|
|
15
|
+
*
|
|
16
|
+
* ## 判据落在字符事实上
|
|
17
|
+
*
|
|
18
|
+
* 「光标是否处在一个 `@token` 里」只看**光标之前的原始字符**:从光标往回扫到空白 /
|
|
19
|
+
* 行首,途中遇到 `@` 且其**前一个字符**是行首、空白或分隔符才算 mention。于是:
|
|
20
|
+
*
|
|
21
|
+
* · `a@b.com` 不算(`@` 前是 `a`)—— 邮箱不会突然弹出文件列表;
|
|
22
|
+
* · `@src/tui` 算,query 为 `src/tui`;
|
|
23
|
+
* · 光标停在 token 中间(`@src|/foo.ts`)也算,且 `end` 会**向后吃掉整个 token**:
|
|
24
|
+
* 补全要替换的是整段,只替换到光标会留下半截残字。
|
|
25
|
+
*/
|
|
26
|
+
import { graphemes } from "./text.js";
|
|
27
|
+
/**
|
|
28
|
+
* `@` token 两侧的分隔符 —— 让 `(@src/x)` / `"@src/x"` / `@src/x,` 也能触发,
|
|
29
|
+
* 并且右端在 `)` 之前就收住(否则补全会把右括号一起替换掉)。
|
|
30
|
+
*
|
|
31
|
+
* 反向的代价是有意接受的:路径里出现这些字符(如 `a,b.txt`)时 token 会在那里截断,
|
|
32
|
+
* 属于极少数情况,且补全仍可手动补完。
|
|
33
|
+
*/
|
|
34
|
+
const BOUNDARY = new Set([
|
|
35
|
+
"(", ")", "[", "]", "{", "}", "<", ">",
|
|
36
|
+
'"', "'", "`", "“", "”", "‘", "’",
|
|
37
|
+
",", ",", ":", ":", ";", ";",
|
|
38
|
+
// 中文行文的标点:`@src/x。这里有问题` 里的 `。` 必须收住 token,否则补全会把
|
|
39
|
+
// 后面整句一起替换掉,用户写句子时菜单也会一直弹着不走
|
|
40
|
+
"。", "、", "!", "?", "(", ")", "《", "》",
|
|
41
|
+
"【", "】", "〔", "〕", "「", "」", "『", "』",
|
|
42
|
+
"…", "—", "~",
|
|
43
|
+
]);
|
|
44
|
+
/** 候选上限:再多也没人翻;同时给每次按键的内存过滤定个上界(10k 候选实测约 9ms) */
|
|
45
|
+
export const MENTION_LIMIT = 50;
|
|
46
|
+
function isSpace(ch) {
|
|
47
|
+
return ch !== "" && /\s/.test(ch);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 取出光标所在的 `@token`;光标不在 token 里(或不在 mention 语境里)返回 `null`。
|
|
51
|
+
*
|
|
52
|
+
* 纯扫描、无正则回溯:文本长度就是输入框长度,逐字素走一遍即可。
|
|
53
|
+
*/
|
|
54
|
+
export function extractMention(text, cursor) {
|
|
55
|
+
const chars = graphemes(text);
|
|
56
|
+
const cp = Math.max(0, Math.min(cursor, chars.length));
|
|
57
|
+
// 1) 往回找 `@`:中途遇到空白,说明光标不在任何 token 内
|
|
58
|
+
let i = cp;
|
|
59
|
+
while (i > 0) {
|
|
60
|
+
const ch = chars[i - 1];
|
|
61
|
+
if (ch === "@")
|
|
62
|
+
break;
|
|
63
|
+
if (isSpace(ch) || BOUNDARY.has(ch))
|
|
64
|
+
return null;
|
|
65
|
+
i -= 1;
|
|
66
|
+
}
|
|
67
|
+
if (i === 0)
|
|
68
|
+
return null; // 一路扫到开头也没有 `@`
|
|
69
|
+
const start = i - 1; // `@` 的下标
|
|
70
|
+
// 2) 边界:`@` 前的字符必须是行首 / 空白 / 分隔符,否则当普通字符(邮箱里的 `@`)
|
|
71
|
+
const prev = start > 0 ? chars[start - 1] : "";
|
|
72
|
+
if (prev && !isSpace(prev) && !BOUNDARY.has(prev))
|
|
73
|
+
return null;
|
|
74
|
+
// 3) 右端:向后扫到空白或分隔符。光标停在 token 中间时也要吃掉整段
|
|
75
|
+
let end = cp;
|
|
76
|
+
while (end < chars.length) {
|
|
77
|
+
const ch = chars[end];
|
|
78
|
+
if (isSpace(ch) || BOUNDARY.has(ch))
|
|
79
|
+
break;
|
|
80
|
+
end += 1;
|
|
81
|
+
}
|
|
82
|
+
return { query: chars.slice(start + 1, cp).join(""), start, end };
|
|
83
|
+
}
|
|
84
|
+
/** 补全要插入的文本:`@路径`,目录补一个 `/` 以便继续往下钻 */
|
|
85
|
+
export function mentionInsertText(path, dir) {
|
|
86
|
+
return `@${path}${dir ? "/" : ""}`;
|
|
87
|
+
}
|
|
88
|
+
function basename(path) {
|
|
89
|
+
return path.slice(path.lastIndexOf("/") + 1);
|
|
90
|
+
}
|
|
91
|
+
/** 路径深度(`a.ts` = 0,`src/a.ts` = 1) */
|
|
92
|
+
function depth(path) {
|
|
93
|
+
let n = 0;
|
|
94
|
+
for (const ch of path)
|
|
95
|
+
if (ch === "/")
|
|
96
|
+
n += 1;
|
|
97
|
+
return n;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 子序列打分(**越小越靠前**);不匹配返回 `null`。
|
|
101
|
+
*
|
|
102
|
+
* 依据实测(10k 条候选、每次按键):贪婪子序列 + 三种加权就够用 ——
|
|
103
|
+
* `tuicha` 能直达 `src/tui/screens/chat.tsx`,不必让用户逐段敲路径。
|
|
104
|
+
*
|
|
105
|
+
* 加权:
|
|
106
|
+
* · 跳跃惩罚:命中间隔越大越差(`t..u..i` 不如 `tui` 连续);
|
|
107
|
+
* · 连续命中奖励:连着的字符是同一段词;
|
|
108
|
+
* · **整体前缀** > **文件名前缀**:`src/tui/` 这种逐段输入要能压过散落命中;
|
|
109
|
+
* · 同分时浅的、短的优先:根目录文件比深埋的图标库更可能被点名。
|
|
110
|
+
*/
|
|
111
|
+
export function scorePath(query, path) {
|
|
112
|
+
// 空 query(刚敲下 `@`):按「浅 → 短 → 字典序」铺开
|
|
113
|
+
if (!query)
|
|
114
|
+
return depth(path) * 4 + path.length * 0.05;
|
|
115
|
+
const q = query.toLowerCase();
|
|
116
|
+
const p = path.toLowerCase();
|
|
117
|
+
let pi = 0;
|
|
118
|
+
let score = 0;
|
|
119
|
+
let lastHit = -1;
|
|
120
|
+
for (const ch of q) {
|
|
121
|
+
const hit = p.indexOf(ch, pi);
|
|
122
|
+
if (hit === -1)
|
|
123
|
+
return null;
|
|
124
|
+
score += hit - pi; // 跳跃惩罚
|
|
125
|
+
if (hit === lastHit + 1)
|
|
126
|
+
score -= 1; // 连续命中
|
|
127
|
+
lastHit = hit;
|
|
128
|
+
pi = hit + 1;
|
|
129
|
+
}
|
|
130
|
+
if (p.startsWith(q))
|
|
131
|
+
score -= 200;
|
|
132
|
+
else if (basename(p).startsWith(q))
|
|
133
|
+
score -= 40;
|
|
134
|
+
return score + path.length * 0.05 + depth(path) * 2;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 过滤 + 排序,取前 `limit` 条。
|
|
138
|
+
*
|
|
139
|
+
* 每次按键都会全量扫一遍(候选只来自内存数组),因此这里不做任何渐进/缓存:
|
|
140
|
+
* 实测 10k 条最长 8.4ms,比一次渲染便宜。
|
|
141
|
+
*/
|
|
142
|
+
export function rankPaths(query, entries, limit = MENTION_LIMIT) {
|
|
143
|
+
const scored = [];
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
const score = scorePath(query, entry.path);
|
|
146
|
+
if (score !== null)
|
|
147
|
+
scored.push({ entry, score });
|
|
148
|
+
}
|
|
149
|
+
scored.sort((a, b) => a.score - b.score || (a.entry.path < b.entry.path ? -1 : a.entry.path > b.entry.path ? 1 : 0));
|
|
150
|
+
return scored.slice(0, Math.max(0, limit)).map((item) => item.entry);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=mention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mention.js","sourceRoot":"","sources":["../../src/tui/mention.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 鼠标滚轮支持 —— 终端模式开关 + SGR 上报解析
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要自己实现:Ink 7 没有 `useMouse`(整个 `ink/build` 里 "mouse" 只出现在
|
|
5
|
+
* `measure-element.js` 的一句注释中),终端也默认**不把**鼠标事件发给应用——滚轮被
|
|
6
|
+
* 终端自己拿去滚 scrollback。要收到滚轮,必须由应用主动打开终端上报模式。
|
|
7
|
+
*
|
|
8
|
+
* 两种编码,只认后者:
|
|
9
|
+
* - `DECSET 1000`:上报「按钮按下 / 释放」(滚轮也算按钮),是收到滚轮的前提;
|
|
10
|
+
* - `DECSET 1006`:改用 SGR 扩展坐标 `CSI < b ; x ; y M`(释放为 `m`)。**必须开**:
|
|
11
|
+
* 老的 X10 编码(`CSI M` + 3 个原始字节)会被 Ink 的输入解析器拆成 `[M` 和三个
|
|
12
|
+
* 普通字符两条事件,后者会被当正文插进输入框(已实测重现)。
|
|
13
|
+
*
|
|
14
|
+
* 上报到 Ink 的形态(pty 实测):`useInput` 的 `char` 是 `"[<64;10;5M"`,`key` 的
|
|
15
|
+
* 所有标志位都是 false。也就是说**鼠标序列和用户打字走的是同一条路**——任何可能插入
|
|
16
|
+
* 文本的处理器都必须先拦一道(见 `isTerminalReply` 与各屏守卫)。
|
|
17
|
+
*
|
|
18
|
+
* 取舍(用户已知情并选择开启):
|
|
19
|
+
* - 点击 / 拖拽被应用吃掉,多数终端需按住 `Shift` 才回退到原生选词复制;
|
|
20
|
+
* - tmux / screen 需 `set -g mouse off`,否则滚轮先被多路复用器拦进 copy-mode;
|
|
21
|
+
* - 应用内滚动只动视口,不产生终端 scrollback。
|
|
22
|
+
*/
|
|
23
|
+
/** 开启上报:1000(按钮事件,含滚轮)+ 1006(SGR 扩展坐标) */
|
|
24
|
+
export declare const MOUSE_ENABLE = "\u001B[?1000h\u001B[?1006h";
|
|
25
|
+
/** 关闭上报。任何退出路径都必须下发,否则 shell 提示符后面会开始吐 `^[[<64;…M` */
|
|
26
|
+
export declare const MOUSE_DISABLE = "\u001B[?1000l\u001B[?1006l";
|
|
27
|
+
/** 滚轮一格滚动的行数(各终端应用的通行值) */
|
|
28
|
+
export declare const WHEEL_STEP = 3;
|
|
29
|
+
export interface WheelEvent {
|
|
30
|
+
/** `-1` = 向上滚(回看更早的内容),`1` = 向下滚(回到更新的内容) */
|
|
31
|
+
direction: -1 | 1;
|
|
32
|
+
/** 终端列(1-based),当前仅用于将来做「按鼠标位置定位」 */
|
|
33
|
+
x: number;
|
|
34
|
+
/** 终端行(1-based) */
|
|
35
|
+
y: number;
|
|
36
|
+
}
|
|
37
|
+
/** 是否为鼠标上报序列(滚轮、点击、拖拽、移动都算) */
|
|
38
|
+
export declare function isMouseSequence(input: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* 从鼠标序列中解出滚轮事件;不是滚轮(点击 / 拖拽 / 横向滚轮)返回 `null`。
|
|
41
|
+
*
|
|
42
|
+
* SGR 的按钮码:`64` 滚轮上、`65` 滚轮下、`66` / `67` 横向滚轮。横向在这个视口里
|
|
43
|
+
* 没有对应维度,直接丢弃——否则横向滚一下就莫名其妙跳几行。
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseWheel(input: string): WheelEvent | null;
|
|
46
|
+
/**
|
|
47
|
+
* 打开终端鼠标上报。
|
|
48
|
+
*
|
|
49
|
+
* 输出的是纯模式设置序列(不打印字符、不移动光标),因此可以安全地直接写 stdout,
|
|
50
|
+
* 不会与 Ink 的增量重绘打架。重复下发是幂等的。
|
|
51
|
+
*/
|
|
52
|
+
export declare function enableMouseTracking(stream?: NodeJS.WriteStream): void;
|
|
53
|
+
/** 关闭终端鼠标上报(幂等)。退出 / 信号 / 异常路径都要调用。 */
|
|
54
|
+
export declare function disableMouseTracking(stream?: NodeJS.WriteStream): void;
|
|
55
|
+
//# sourceMappingURL=mouse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mouse.d.ts","sourceRoot":"","sources":["../../src/tui/mouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,0CAA0C;AAC1C,eAAO,MAAM,YAAY,+BAA+B,CAAC;AAEzD,sDAAsD;AACtD,eAAO,MAAM,aAAa,+BAA+B,CAAC;AAE1D,2BAA2B;AAC3B,eAAO,MAAM,UAAU,IAAI,CAAC;AAa5B,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAClB,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAC;IACV,mBAAmB;IACnB,CAAC,EAAE,MAAM,CAAC;CACX;AAED,+BAA+B;AAC/B,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAU3D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,GAAE,MAAM,CAAC,WAA4B,GAAG,IAAI,CAErF;AAED,uCAAuC;AACvC,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,MAAM,CAAC,WAA4B,GAAG,IAAI,CAEtF"}
|