@chengchenccc/oh-my-agent 0.1.1-rc.1

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 (276) hide show
  1. package/README.md +79 -0
  2. package/dist/cli/args.d.ts +24 -0
  3. package/dist/cli/args.d.ts.map +1 -0
  4. package/dist/cli/args.js +120 -0
  5. package/dist/cli/initial-input.d.ts +32 -0
  6. package/dist/cli/initial-input.d.ts.map +1 -0
  7. package/dist/cli/initial-input.js +131 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +3 -0
  11. package/dist/core/__fixtures__/echo-model.d.ts +6 -0
  12. package/dist/core/__fixtures__/echo-model.d.ts.map +1 -0
  13. package/dist/core/__fixtures__/echo-model.js +10 -0
  14. package/dist/core/__fixtures__/mcp-echo-server.d.ts +2 -0
  15. package/dist/core/__fixtures__/mcp-echo-server.d.ts.map +1 -0
  16. package/dist/core/__fixtures__/mcp-echo-server.js +54 -0
  17. package/dist/core/agent-runtime.d.ts +21 -0
  18. package/dist/core/agent-runtime.d.ts.map +1 -0
  19. package/dist/core/agent-runtime.js +14 -0
  20. package/dist/core/memory/autonomous-memory.d.ts +21 -0
  21. package/dist/core/memory/autonomous-memory.d.ts.map +1 -0
  22. package/dist/core/memory/autonomous-memory.js +202 -0
  23. package/dist/core/persistence/in-memory-session-store.d.ts +3 -0
  24. package/dist/core/persistence/in-memory-session-store.d.ts.map +1 -0
  25. package/dist/core/persistence/in-memory-session-store.js +109 -0
  26. package/dist/core/persistence/session-store.contract.d.ts +5 -0
  27. package/dist/core/persistence/session-store.contract.d.ts.map +1 -0
  28. package/dist/core/persistence/session-store.contract.js +183 -0
  29. package/dist/core/persistence/session-store.d.ts +33 -0
  30. package/dist/core/persistence/session-store.d.ts.map +1 -0
  31. package/dist/core/persistence/session-store.js +22 -0
  32. package/dist/core/persistence/session-tree.d.ts +49 -0
  33. package/dist/core/persistence/session-tree.d.ts.map +1 -0
  34. package/dist/core/persistence/session-tree.js +1 -0
  35. package/dist/core/plugins/plugin-code.d.ts +13 -0
  36. package/dist/core/plugins/plugin-code.d.ts.map +1 -0
  37. package/dist/core/plugins/plugin-code.js +62 -0
  38. package/dist/core/plugins/plugin-marketplace.d.ts +72 -0
  39. package/dist/core/plugins/plugin-marketplace.d.ts.map +1 -0
  40. package/dist/core/plugins/plugin-marketplace.js +340 -0
  41. package/dist/core/plugins/plugin-resolve.d.ts +32 -0
  42. package/dist/core/plugins/plugin-resolve.d.ts.map +1 -0
  43. package/dist/core/plugins/plugin-resolve.js +101 -0
  44. package/dist/core/plugins/plugin-trust.d.ts +24 -0
  45. package/dist/core/plugins/plugin-trust.d.ts.map +1 -0
  46. package/dist/core/plugins/plugin-trust.js +89 -0
  47. package/dist/core/runtime/agent-event.d.ts +98 -0
  48. package/dist/core/runtime/agent-event.d.ts.map +1 -0
  49. package/dist/core/runtime/agent-event.js +1 -0
  50. package/dist/core/runtime/agent-loop.d.ts +142 -0
  51. package/dist/core/runtime/agent-loop.d.ts.map +1 -0
  52. package/dist/core/runtime/agent-loop.js +1008 -0
  53. package/dist/core/runtime/approval.d.ts +23 -0
  54. package/dist/core/runtime/approval.d.ts.map +1 -0
  55. package/dist/core/runtime/approval.js +25 -0
  56. package/dist/core/runtime/compaction.d.ts +22 -0
  57. package/dist/core/runtime/compaction.d.ts.map +1 -0
  58. package/dist/core/runtime/compaction.js +90 -0
  59. package/dist/core/runtime/context-estimate.d.ts +42 -0
  60. package/dist/core/runtime/context-estimate.d.ts.map +1 -0
  61. package/dist/core/runtime/context-estimate.js +34 -0
  62. package/dist/core/runtime/create-runtime.d.ts +81 -0
  63. package/dist/core/runtime/create-runtime.d.ts.map +1 -0
  64. package/dist/core/runtime/create-runtime.js +250 -0
  65. package/dist/core/runtime/fake-provider.d.ts +3 -0
  66. package/dist/core/runtime/fake-provider.d.ts.map +1 -0
  67. package/dist/core/runtime/fake-provider.js +87 -0
  68. package/dist/core/runtime/logger.d.ts +13 -0
  69. package/dist/core/runtime/logger.d.ts.map +1 -0
  70. package/dist/core/runtime/logger.js +38 -0
  71. package/dist/core/runtime/loop-input.d.ts +39 -0
  72. package/dist/core/runtime/loop-input.d.ts.map +1 -0
  73. package/dist/core/runtime/loop-input.js +38 -0
  74. package/dist/core/runtime/message-cache.d.ts +16 -0
  75. package/dist/core/runtime/message-cache.d.ts.map +1 -0
  76. package/dist/core/runtime/message-cache.js +23 -0
  77. package/dist/core/runtime/model-catalog.d.ts +10 -0
  78. package/dist/core/runtime/model-catalog.d.ts.map +1 -0
  79. package/dist/core/runtime/model-catalog.js +14 -0
  80. package/dist/core/runtime/plugin-runtime.d.ts +41 -0
  81. package/dist/core/runtime/plugin-runtime.d.ts.map +1 -0
  82. package/dist/core/runtime/plugin-runtime.js +1 -0
  83. package/dist/core/runtime/plugin.d.ts +86 -0
  84. package/dist/core/runtime/plugin.d.ts.map +1 -0
  85. package/dist/core/runtime/plugin.js +23 -0
  86. package/dist/core/runtime/process-tree.d.ts +12 -0
  87. package/dist/core/runtime/process-tree.d.ts.map +1 -0
  88. package/dist/core/runtime/process-tree.js +40 -0
  89. package/dist/core/runtime/prompt.d.ts +23 -0
  90. package/dist/core/runtime/prompt.d.ts.map +1 -0
  91. package/dist/core/runtime/prompt.js +29 -0
  92. package/dist/core/runtime/prompts.d.ts +16 -0
  93. package/dist/core/runtime/prompts.d.ts.map +1 -0
  94. package/dist/core/runtime/prompts.js +36 -0
  95. package/dist/core/runtime/retry.d.ts +20 -0
  96. package/dist/core/runtime/retry.d.ts.map +1 -0
  97. package/dist/core/runtime/retry.js +60 -0
  98. package/dist/core/runtime/run-runtime.d.ts +93 -0
  99. package/dist/core/runtime/run-runtime.d.ts.map +1 -0
  100. package/dist/core/runtime/run-runtime.js +664 -0
  101. package/dist/core/runtime/runtime-catalog.d.ts +12 -0
  102. package/dist/core/runtime/runtime-catalog.d.ts.map +1 -0
  103. package/dist/core/runtime/runtime-catalog.js +89 -0
  104. package/dist/core/runtime/stream-rules.d.ts +9 -0
  105. package/dist/core/runtime/stream-rules.d.ts.map +1 -0
  106. package/dist/core/runtime/stream-rules.js +44 -0
  107. package/dist/core/runtime/title.d.ts +7 -0
  108. package/dist/core/runtime/title.d.ts.map +1 -0
  109. package/dist/core/runtime/title.js +114 -0
  110. package/dist/core/runtime/todo.d.ts +16 -0
  111. package/dist/core/runtime/todo.d.ts.map +1 -0
  112. package/dist/core/runtime/todo.js +40 -0
  113. package/dist/core/runtime/tool-filter.d.ts +12 -0
  114. package/dist/core/runtime/tool-filter.d.ts.map +1 -0
  115. package/dist/core/runtime/tool-filter.js +23 -0
  116. package/dist/core/runtime/tool-pruning.d.ts +29 -0
  117. package/dist/core/runtime/tool-pruning.d.ts.map +1 -0
  118. package/dist/core/runtime/tool-pruning.js +105 -0
  119. package/dist/core/session/input-history.d.ts +8 -0
  120. package/dist/core/session/input-history.d.ts.map +1 -0
  121. package/dist/core/session/input-history.js +41 -0
  122. package/dist/core/session/session-file.d.ts +84 -0
  123. package/dist/core/session/session-file.d.ts.map +1 -0
  124. package/dist/core/session/session-file.js +392 -0
  125. package/dist/core/session/session-loop.d.ts +33 -0
  126. package/dist/core/session/session-loop.d.ts.map +1 -0
  127. package/dist/core/session/session-loop.js +30 -0
  128. package/dist/core/settings/project-settings.d.ts +46 -0
  129. package/dist/core/settings/project-settings.d.ts.map +1 -0
  130. package/dist/core/settings/project-settings.js +85 -0
  131. package/dist/core/settings/workspace-context.d.ts +10 -0
  132. package/dist/core/settings/workspace-context.d.ts.map +1 -0
  133. package/dist/core/settings/workspace-context.js +48 -0
  134. package/dist/core/tools/agent-fs-like.d.ts +15 -0
  135. package/dist/core/tools/agent-fs-like.d.ts.map +1 -0
  136. package/dist/core/tools/agent-fs-like.js +4 -0
  137. package/dist/core/tools/ask-question.d.ts +5 -0
  138. package/dist/core/tools/ask-question.d.ts.map +1 -0
  139. package/dist/core/tools/ask-question.js +51 -0
  140. package/dist/core/tools/bash.d.ts +5 -0
  141. package/dist/core/tools/bash.d.ts.map +1 -0
  142. package/dist/core/tools/bash.js +109 -0
  143. package/dist/core/tools/eval.d.ts +10 -0
  144. package/dist/core/tools/eval.d.ts.map +1 -0
  145. package/dist/core/tools/eval.js +83 -0
  146. package/dist/core/tools/file-tools.d.ts +18 -0
  147. package/dist/core/tools/file-tools.d.ts.map +1 -0
  148. package/dist/core/tools/file-tools.js +249 -0
  149. package/dist/core/tools/glob.d.ts +5 -0
  150. package/dist/core/tools/glob.d.ts.map +1 -0
  151. package/dist/core/tools/glob.js +54 -0
  152. package/dist/core/tools/grep.d.ts +5 -0
  153. package/dist/core/tools/grep.d.ts.map +1 -0
  154. package/dist/core/tools/grep.js +61 -0
  155. package/dist/core/tools/index.d.ts +14 -0
  156. package/dist/core/tools/index.d.ts.map +1 -0
  157. package/dist/core/tools/index.js +14 -0
  158. package/dist/core/tools/ls-tree.d.ts +10 -0
  159. package/dist/core/tools/ls-tree.d.ts.map +1 -0
  160. package/dist/core/tools/ls-tree.js +177 -0
  161. package/dist/core/tools/mcp-mount.d.ts +63 -0
  162. package/dist/core/tools/mcp-mount.d.ts.map +1 -0
  163. package/dist/core/tools/mcp-mount.js +287 -0
  164. package/dist/core/tools/read-image.d.ts +6 -0
  165. package/dist/core/tools/read-image.d.ts.map +1 -0
  166. package/dist/core/tools/read-image.js +98 -0
  167. package/dist/core/tools/skill.d.ts +11 -0
  168. package/dist/core/tools/skill.d.ts.map +1 -0
  169. package/dist/core/tools/skill.js +65 -0
  170. package/dist/core/tools/skills.d.ts +10 -0
  171. package/dist/core/tools/skills.d.ts.map +1 -0
  172. package/dist/core/tools/skills.js +116 -0
  173. package/dist/core/tools/todo-store.d.ts +8 -0
  174. package/dist/core/tools/todo-store.d.ts.map +1 -0
  175. package/dist/core/tools/todo-store.js +100 -0
  176. package/dist/core/tools/todo.d.ts +8 -0
  177. package/dist/core/tools/todo.d.ts.map +1 -0
  178. package/dist/core/tools/todo.js +91 -0
  179. package/dist/core/tools/url-guard.d.ts +12 -0
  180. package/dist/core/tools/url-guard.d.ts.map +1 -0
  181. package/dist/core/tools/url-guard.js +58 -0
  182. package/dist/core/tools/web-ports-std.d.ts +6 -0
  183. package/dist/core/tools/web-ports-std.d.ts.map +1 -0
  184. package/dist/core/tools/web-ports-std.js +145 -0
  185. package/dist/core/tools/web-ports.d.ts +56 -0
  186. package/dist/core/tools/web-ports.d.ts.map +1 -0
  187. package/dist/core/tools/web-ports.js +62 -0
  188. package/dist/core/tools/workspace-sandbox.d.ts +20 -0
  189. package/dist/core/tools/workspace-sandbox.d.ts.map +1 -0
  190. package/dist/core/tools/workspace-sandbox.js +84 -0
  191. package/dist/core/workflow/subagent-registry.d.ts +40 -0
  192. package/dist/core/workflow/subagent-registry.d.ts.map +1 -0
  193. package/dist/core/workflow/subagent-registry.js +118 -0
  194. package/dist/core/workflow/workflow-evaluator.d.ts +23 -0
  195. package/dist/core/workflow/workflow-evaluator.d.ts.map +1 -0
  196. package/dist/core/workflow/workflow-evaluator.js +21 -0
  197. package/dist/core/workflow/workflow-executor.d.ts +108 -0
  198. package/dist/core/workflow/workflow-executor.d.ts.map +1 -0
  199. package/dist/core/workflow/workflow-executor.js +549 -0
  200. package/dist/core/workflow/workflow-tools.d.ts +50 -0
  201. package/dist/core/workflow/workflow-tools.d.ts.map +1 -0
  202. package/dist/core/workflow/workflow-tools.js +217 -0
  203. package/dist/index.d.ts +14 -0
  204. package/dist/index.d.ts.map +1 -0
  205. package/dist/index.js +13 -0
  206. package/dist/main.d.ts +9 -0
  207. package/dist/main.d.ts.map +1 -0
  208. package/dist/main.js +97 -0
  209. package/dist/modes/json-mode.d.ts +5 -0
  210. package/dist/modes/json-mode.d.ts.map +1 -0
  211. package/dist/modes/json-mode.js +46 -0
  212. package/dist/modes/print-mode.d.ts +20 -0
  213. package/dist/modes/print-mode.d.ts.map +1 -0
  214. package/dist/modes/print-mode.js +82 -0
  215. package/dist/modes/rpc/jsonl.d.ts +23 -0
  216. package/dist/modes/rpc/jsonl.d.ts.map +1 -0
  217. package/dist/modes/rpc/jsonl.js +88 -0
  218. package/dist/modes/rpc/rpc-mode.d.ts +18 -0
  219. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
  220. package/dist/modes/rpc/rpc-mode.js +326 -0
  221. package/dist/modes/tui/settings-overlay.d.ts +23 -0
  222. package/dist/modes/tui/settings-overlay.d.ts.map +1 -0
  223. package/dist/modes/tui/settings-overlay.js +136 -0
  224. package/dist/modes/tui/tui-commands-session.d.ts +3 -0
  225. package/dist/modes/tui/tui-commands-session.d.ts.map +1 -0
  226. package/dist/modes/tui/tui-commands-session.js +191 -0
  227. package/dist/modes/tui/tui-commands.d.ts +52 -0
  228. package/dist/modes/tui/tui-commands.d.ts.map +1 -0
  229. package/dist/modes/tui/tui-commands.js +373 -0
  230. package/dist/modes/tui/tui-components.d.ts +81 -0
  231. package/dist/modes/tui/tui-components.d.ts.map +1 -0
  232. package/dist/modes/tui/tui-components.js +248 -0
  233. package/dist/modes/tui/tui-format.d.ts +65 -0
  234. package/dist/modes/tui/tui-format.d.ts.map +1 -0
  235. package/dist/modes/tui/tui-format.js +246 -0
  236. package/dist/modes/tui/tui-frame-provider.d.ts +16 -0
  237. package/dist/modes/tui/tui-frame-provider.d.ts.map +1 -0
  238. package/dist/modes/tui/tui-frame-provider.js +31 -0
  239. package/dist/modes/tui/tui-interactive.d.ts +16 -0
  240. package/dist/modes/tui/tui-interactive.d.ts.map +1 -0
  241. package/dist/modes/tui/tui-interactive.js +123 -0
  242. package/dist/modes/tui/tui-io.d.ts +12 -0
  243. package/dist/modes/tui/tui-io.d.ts.map +1 -0
  244. package/dist/modes/tui/tui-io.js +620 -0
  245. package/dist/modes/tui/tui-mode.d.ts +120 -0
  246. package/dist/modes/tui/tui-mode.d.ts.map +1 -0
  247. package/dist/modes/tui/tui-mode.js +391 -0
  248. package/dist/modes/tui/tui-render.d.ts +54 -0
  249. package/dist/modes/tui/tui-render.d.ts.map +1 -0
  250. package/dist/modes/tui/tui-render.js +399 -0
  251. package/dist/modes/tui/tui-slash.d.ts +12 -0
  252. package/dist/modes/tui/tui-slash.d.ts.map +1 -0
  253. package/dist/modes/tui/tui-slash.js +64 -0
  254. package/dist/modes/tui/tui-tool-render.d.ts +6 -0
  255. package/dist/modes/tui/tui-tool-render.d.ts.map +1 -0
  256. package/dist/modes/tui/tui-tool-render.js +79 -0
  257. package/dist/modes/tui/tui-transcript-reconciler.d.ts +25 -0
  258. package/dist/modes/tui/tui-transcript-reconciler.d.ts.map +1 -0
  259. package/dist/modes/tui/tui-transcript-reconciler.js +97 -0
  260. package/dist/modes/tui/view-state.d.ts +67 -0
  261. package/dist/modes/tui/view-state.d.ts.map +1 -0
  262. package/dist/modes/tui/view-state.js +353 -0
  263. package/dist/prompts/agents/subagent.md +26 -0
  264. package/dist/prompts/system/base.md +20 -0
  265. package/dist/prompts/system/memory.md +23 -0
  266. package/dist/prompts/system/safety.md +12 -0
  267. package/dist/protocol/index.d.ts +5 -0
  268. package/dist/protocol/index.d.ts.map +1 -0
  269. package/dist/protocol/index.js +2 -0
  270. package/dist/protocol/mapping.d.ts +25 -0
  271. package/dist/protocol/mapping.d.ts.map +1 -0
  272. package/dist/protocol/mapping.js +115 -0
  273. package/dist/protocol/transport.d.ts +1396 -0
  274. package/dist/protocol/transport.d.ts.map +1 -0
  275. package/dist/protocol/transport.js +170 -0
  276. package/package.json +49 -0
@@ -0,0 +1,120 @@
1
+ import type { AskQuestionInput, AskQuestionResult } from "@chengchenccc/agent-contract";
2
+ import type { ModelRuntime } from "@chengchenccc/ai";
3
+ import { type SlashCommand } from "@chengchenccc/tui";
4
+ import type { ToolFilter } from "../../core/runtime/tool-filter.js";
5
+ import { type SessionBranchNode } from "../../core/session/session-file.js";
6
+ import { type ProjectSettings } from "../../core/settings/project-settings.js";
7
+ import { type TuiViewState } from "./view-state.js";
8
+ /** TUI mode: oma's standalone interactive surface. One process = N
9
+ * consecutive Runs over ONE session file; each Run is its own Runtime
10
+ * (one Runtime = one Run invariant preserved). Enter submits; while a Run
11
+ * is live, Enter STEERS the message into the loop immediately (pi's
12
+ * streamingBehavior:"steer") and a steer rejected because the loop is
13
+ * settling falls back to a queue that auto-drains as the next Run's input
14
+ * (pi's AgentBusyError -> followUp) — no message is ever dropped. Esc
15
+ * aborts; ctrl+t toggles thinking; ctrl+o toggles tool detail; /exit
16
+ * quits.
17
+ *
18
+ * All terminal wiring lives behind the TerminalIo seam so tests can drive
19
+ * the whole loop headlessly. */
20
+ export interface TuiModeOptions {
21
+ modelRuntime: ModelRuntime;
22
+ workspaceRoot: string;
23
+ /** Canonical `<provider>/<model>` id; undefined = first available. */
24
+ model?: string;
25
+ /** Resume a specific session file instead of starting fresh. */
26
+ sessionId?: string;
27
+ /** Prefill the editor with this text on boot (`oma "prompt"`). The user
28
+ * hits Enter to send it like any other input. */
29
+ initialPrompt?: string;
30
+ /** --tools filter (CLI): applied to the final tool table. */
31
+ toolFilter?: ToolFilter;
32
+ }
33
+ /** View/abort commands from the terminal (Esc abort, ctrl+t, ctrl+o, ctrl+p). */
34
+ export type TuiCommand = "toggleThinking" | "toggleToolDetail" | "abort" | "pickModel" | "forkTree";
35
+ export interface TuiIo {
36
+ /** Render the current view state. */
37
+ render(state: TuiViewState): void;
38
+ /** Wait for the next user submit; resolves null on quit (Ctrl-D / /exit).
39
+ * Submits that arrive while a run is live (busy) are delivered to
40
+ * onLiveInput instead - waitForInput only resolves between runs. */
41
+ waitForInput(): Promise<string | null>;
42
+ /** Called once when a run goes live or settles, to toggle input mode. */
43
+ setBusy?(busy: boolean): void;
44
+ /** Subscriber for inputs submitted while a run is live (steer). */
45
+ onLiveInput?(handler: ((text: string) => void) | null): void;
46
+ /** Subscriber for slash commands submitted while a run is live; the
47
+ * session loop executes them instead of steering the text (pi's
48
+ * LiveCommandController). */
49
+ onLiveCommand?(handler: ((text: string) => void) | null): void;
50
+ /** Subscriber for view/abort commands (Esc, ctrl+t, ctrl+o). */
51
+ onCommand?(handler: ((cmd: TuiCommand) => void) | null): void;
52
+ /** Register the slash-command list for editor autocomplete. */
53
+ setSlashCommands?(commands: readonly SlashCommand[]): void;
54
+ /** Interactive session picker overlay; resolves the chosen session id,
55
+ * or null when cancelled. Absent = caller falls back to a text list. */
56
+ pickSession?(sessions: ReadonlyArray<{
57
+ id: string;
58
+ title?: string;
59
+ preview: string;
60
+ modifiedAt: number;
61
+ workspace?: string;
62
+ forkOf?: string;
63
+ }>): Promise<string | null>;
64
+ /** Interactive model picker overlay (ctrl+p); resolves the chosen
65
+ * canonical `<provider>/<model>` id, or null when cancelled. */
66
+ pickModel?(models: ReadonlyArray<{
67
+ id: string;
68
+ label: string;
69
+ description?: string;
70
+ }>): Promise<string | null>;
71
+ /** Interactive approval confirm (HITL); resolves "allow"/"deny", null on
72
+ * cancel (treated as deny — fail-closed). Absent = deny. */
73
+ confirmApproval?(req: {
74
+ toolName: string;
75
+ reason?: string;
76
+ }): Promise<"allow" | "deny" | null>;
77
+ /** Interactive ask_question form (HITL); resolves answers or null on
78
+ * cancel/unsupported question kind (fail-closed). */
79
+ askQuestions?(input: AskQuestionInput): Promise<AskQuestionResult | null>;
80
+ /** Interactive fork-point picker (pi's user-message selector): lists the
81
+ * session's user messages; resolves the chosen 1-based ordinal, or null
82
+ * when cancelled. Absent = caller falls back to /fork <n>. */
83
+ pickForkPoint?(points: ReadonlyArray<{
84
+ ordinal: number;
85
+ text: string;
86
+ }>): Promise<number | null>;
87
+ /** Interactive branch-tree fork picker: lists the session's parentId-
88
+ * chained message nodes; resolves the chosen node id, or null when
89
+ * cancelled. Absent = caller falls back to the /fork text path. */
90
+ pickBranchTree?(nodes: ReadonlyArray<SessionBranchNode>): Promise<string | null>;
91
+ /** Interactive settings editor; resolves the updated settings or null on
92
+ * cancel. Absent = caller falls back to text status. */
93
+ editSettings?(settings: ProjectSettings): Promise<ProjectSettings | null>;
94
+ /** Update the fixed header's model/session line. `context` is sticky:
95
+ * once set it stays until the next value arrives. */
96
+ setHeader?(info: {
97
+ model?: string;
98
+ sessionId?: string;
99
+ title?: string;
100
+ context?: string;
101
+ }): void;
102
+ /** Prefill the editor text (used for `oma "<prompt>"`). */
103
+ setInputText?(text: string): void;
104
+ /** True while the terminal window holds focus (CSI 1004 reporting).
105
+ * Absent = always considered focused. */
106
+ isFocused?(): boolean;
107
+ /** Subscriber for terminal focus transitions (CSI 1004 reporting). */
108
+ onFocus?(handler: ((focused: boolean) => void) | null): void;
109
+ /** Best-effort completion ping (BEL). Absent = silent. */
110
+ notify?(): void;
111
+ /** Stop the terminal (restore modes). */
112
+ close(): void;
113
+ }
114
+ /** The full interactive session loop, driver-agnostic. */
115
+ export declare function runTuiSession(opts: TuiModeOptions, io: TuiIo): Promise<number>;
116
+ /** CLI entry: run the interactive session over the real terminal. */
117
+ export declare function runTuiMode(opts: TuiModeOptions): Promise<number>;
118
+ export { formatModelMeta } from "./tui-format.js";
119
+ export { createTerminalIo } from "./tui-io.js";
120
+ //# sourceMappingURL=tui-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-mode.d.ts","sourceRoot":"","sources":["../../../src/modes/tui/tui-mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,391 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { ProcessTerminal } from "@chengchenccc/tui";
3
+ import { buildCliRunInput } from "../../cli/initial-input.js";
4
+ import { assemblePluginRuntime } from "../../core/plugins/plugin-resolve.js";
5
+ import { createOmaRuntime } from "../../core/runtime/create-runtime.js";
6
+ import { appendSessionMessages, listSessions, } from "../../core/session/session-file.js";
7
+ import { persistSessionTurn, resolveSession } from "../../core/session/session-loop.js";
8
+ import { loadProjectSettings } from "../../core/settings/project-settings.js";
9
+ import { buildCommands } from "./tui-commands.js";
10
+ import { formatTokens } from "./tui-format.js";
11
+ import { forkTreeInteractive, lastRunRecap, listModelRows, listModels, pickModelInteractive, registerIoHandlers, } from "./tui-interactive.js";
12
+ import { createTerminalIo } from "./tui-io.js";
13
+ import { buildSlashSystem } from "./tui-slash.js";
14
+ import { addUserInput, applyEvent, applyOutcome, hydrateTranscript, initialViewState, settleSteeredMessages, } from "./view-state.js";
15
+ /** A saved project model is used only when it still resolves in the catalog;
16
+ * a stale provider/model must not brick TUI startup. */
17
+ async function savedModelIsAvailable(modelRuntime, modelId) {
18
+ try {
19
+ const catalog = await modelRuntime.getCatalog();
20
+ return catalog.models.some((m) => `${m.providerId}/${m.modelId}` === modelId && m.available !== false);
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ /** The full interactive session loop, driver-agnostic. */
27
+ export async function runTuiSession(opts, io) {
28
+ let session = resolveSession(opts.sessionId);
29
+ const state = initialViewState();
30
+ hydrateTranscript(state, session.messages);
31
+ let modelId;
32
+ if (opts.model) {
33
+ modelId = opts.model;
34
+ }
35
+ else {
36
+ const saved = loadProjectSettings(opts.workspaceRoot).model;
37
+ modelId = saved && (await savedModelIsAvailable(opts.modelRuntime, saved)) ? saved : undefined;
38
+ }
39
+ let liveRuntime = null;
40
+ let sessionTitle;
41
+ let quitting = false;
42
+ let exitArmed = false;
43
+ /** Estimated context tokens after the last run: drives the picker's
44
+ * over-context warning (pi grays out models smaller than the session). */
45
+ let lastContextTokens;
46
+ /** Recap shown when the terminal regains focus after an unfocused run. */
47
+ let pendingFocusRecap;
48
+ /** Prompt queued by a command (skill invocations): submitted as the next
49
+ * normal run. */
50
+ let pendingPrompt;
51
+ /** Workflow script queued by /workflow: injected into the next run input. */
52
+ let pendingWorkflowScript;
53
+ function pushStatus(lines, replacePrefix) {
54
+ const items = (typeof lines === "string" ? [lines] : lines).map((text) => ({
55
+ kind: "status",
56
+ text,
57
+ streaming: false,
58
+ }));
59
+ if (replacePrefix) {
60
+ for (let i = state.runs.length - 1; i >= 0; i--) {
61
+ const first = state.runs[i].items[0];
62
+ if (first?.kind === "status" && first.text.startsWith(replacePrefix)) {
63
+ state.runs[i] = { items, running: false };
64
+ return;
65
+ }
66
+ }
67
+ }
68
+ state.runs.push({ items, running: false });
69
+ }
70
+ /** Compact recap text for the most recent run: last assistant message
71
+ * first line, falling back to the auto title. */
72
+ io.setHeader?.({ model: modelId, sessionId: session.sessionId, title: sessionTitle });
73
+ // `oma "<prompt>"` opens the TUI with the prompt prefilled in the editor.
74
+ if (opts.initialPrompt)
75
+ io.setInputText?.(opts.initialPrompt);
76
+ const ctx = {
77
+ state,
78
+ io,
79
+ opts,
80
+ get session() {
81
+ return session;
82
+ },
83
+ set session(value) {
84
+ session = value;
85
+ },
86
+ get sessionTitle() {
87
+ return sessionTitle;
88
+ },
89
+ set sessionTitle(value) {
90
+ sessionTitle = value;
91
+ },
92
+ get modelId() {
93
+ return modelId;
94
+ },
95
+ set modelId(value) {
96
+ modelId = value;
97
+ },
98
+ get quitting() {
99
+ return quitting;
100
+ },
101
+ set quitting(value) {
102
+ quitting = value;
103
+ },
104
+ get exitArmed() {
105
+ return exitArmed;
106
+ },
107
+ set exitArmed(value) {
108
+ exitArmed = value;
109
+ },
110
+ get pendingPrompt() {
111
+ return pendingPrompt;
112
+ },
113
+ set pendingPrompt(value) {
114
+ pendingPrompt = value;
115
+ },
116
+ get pendingWorkflowScript() {
117
+ return pendingWorkflowScript;
118
+ },
119
+ set pendingWorkflowScript(value) {
120
+ pendingWorkflowScript = value;
121
+ },
122
+ get liveRuntime() {
123
+ return liveRuntime;
124
+ },
125
+ set liveRuntime(value) {
126
+ liveRuntime = value;
127
+ },
128
+ get lastContextTokens() {
129
+ return lastContextTokens;
130
+ },
131
+ set lastContextTokens(value) {
132
+ lastContextTokens = value;
133
+ },
134
+ get pendingFocusRecap() {
135
+ return pendingFocusRecap;
136
+ },
137
+ set pendingFocusRecap(value) {
138
+ pendingFocusRecap = value;
139
+ },
140
+ pushStatus,
141
+ listModels: () => listModels(ctx),
142
+ listModelRows: () => listModelRows(ctx),
143
+ listSessions,
144
+ pickModelInteractive: () => pickModelInteractive(ctx),
145
+ forkTreeInteractive: () => forkTreeInteractive(ctx),
146
+ };
147
+ const commands = buildCommands(ctx);
148
+ const { slashCommands, runCommandText } = buildSlashSystem(ctx, commands);
149
+ ctx.runCommandText = runCommandText;
150
+ io.setSlashCommands?.(slashCommands);
151
+ registerIoHandlers(ctx);
152
+ io.onLiveCommand?.((text) => {
153
+ void runCommandText(text).then(() => io.render(state));
154
+ });
155
+ /** Steers rejected while the loop was settling; drained as the next
156
+ * Run's prompt when the current Run ends (pi's followUp fallback). */
157
+ const pendingFollowUps = [];
158
+ for (;;) {
159
+ io.render(state);
160
+ // Steers that arrived while the previous loop was settling are drained
161
+ // here as the next Run's prompt (already echoed as » items — no re-echo).
162
+ let text;
163
+ let fromFollowUp = false;
164
+ if (pendingFollowUps.length > 0) {
165
+ const drained = pendingFollowUps.splice(0);
166
+ text = drained.join("\n\n");
167
+ fromFollowUp = true;
168
+ // Settle the queued » echoes in place — no re-echo (pi moves queued
169
+ // messages into the chat when they are delivered).
170
+ settleSteeredMessages(state, drained);
171
+ }
172
+ else {
173
+ const input = await io.waitForInput();
174
+ if (input === null)
175
+ return 0;
176
+ text = input.trim();
177
+ if (!text)
178
+ continue;
179
+ }
180
+ if (text.startsWith("/")) {
181
+ await runCommandText(text);
182
+ if (quitting)
183
+ return 0;
184
+ // A command queued a prompt (skill invocation, workflow): submit it as
185
+ // the next run instead of returning to the editor.
186
+ if (pendingPrompt === undefined)
187
+ continue;
188
+ text = pendingPrompt;
189
+ pendingPrompt = undefined;
190
+ }
191
+ if (!fromFollowUp)
192
+ addUserInput(state, text);
193
+ const built = await buildCliRunInput({
194
+ prompt: text,
195
+ workspaceRoot: opts.workspaceRoot,
196
+ modelRuntime: opts.modelRuntime,
197
+ modelId,
198
+ });
199
+ modelId = built.run.model.modelId;
200
+ // /workflow queued a script: this run executes the vm workflow instead
201
+ // of a conversational loop (create-runtime branches on input.workflow).
202
+ let runInput = built;
203
+ if (pendingWorkflowScript !== undefined) {
204
+ runInput = { ...built, workflow: { script: pendingWorkflowScript } };
205
+ pendingWorkflowScript = undefined;
206
+ }
207
+ const pluginRt = await assemblePluginRuntime(opts.workspaceRoot, "tui");
208
+ for (const w of pluginRt.warnings)
209
+ pushStatus(`[plugin] ${w}`);
210
+ const runtime = await createOmaRuntime({
211
+ runId: `tui-${randomUUID()}`,
212
+ modelId: built.run.model.modelId,
213
+ workspaceRoot: opts.workspaceRoot,
214
+ workspaceAccess: "read_write",
215
+ modelRuntime: opts.modelRuntime,
216
+ skillRoots: built.run.skillRoots ?? [],
217
+ gateWorkspaceMcp: true,
218
+ // HITL: interactive approval overlay; absent picker or cancel = deny.
219
+ approvalHandler: async (req) => {
220
+ const verdict = await io.confirmApproval?.({
221
+ toolName: req.toolName,
222
+ ...(req.reason ? { reason: req.reason } : {}),
223
+ });
224
+ return verdict === "allow"
225
+ ? { decision: "allow" }
226
+ : { decision: "deny", reason: "user denied" };
227
+ },
228
+ // HITL ask_question: interactive overlay; absent/cancel = null (tool
229
+ // fails closed with "no answer").
230
+ ...(io.askQuestions ? { askHandler: io.askQuestions } : {}),
231
+ ...(pluginRt.plugins.length || pluginRt.mcpServers.length
232
+ ? { pluginComponents: { plugins: pluginRt.plugins, mcpServers: pluginRt.mcpServers } }
233
+ : {}),
234
+ ...(built.run.permissionMode ? { permissionMode: built.run.permissionMode } : {}),
235
+ ...(opts.toolFilter ? { toolFilter: opts.toolFilter } : {}),
236
+ sessionTranscript: session.messages.length
237
+ ? session.messages.map((m, i) => ({
238
+ productEntryId: `session:${i}`,
239
+ message: m,
240
+ }))
241
+ : undefined,
242
+ // Render on every event so model chunks (message_update) hit the
243
+ // screen incrementally; the TUI's requestRender throttles/coalesces,
244
+ // so high-frequency chunk events are safe here.
245
+ onEvent: (envelope) => {
246
+ applyEvent(state, envelope.data);
247
+ io.render(state);
248
+ },
249
+ // Real-time session persistence (pi appendMessage): every
250
+ // conversational persist (user prompt, steer, assistant, tool result)
251
+ // lands in the session file immediately, so even a killed/failed
252
+ // process leaves its context for the next turn.
253
+ onPersistMessages: (messages) => {
254
+ appendSessionMessages(session.sessionId, opts.workspaceRoot, messages, session.dir);
255
+ // The session file is wire-loose; the in-memory transcript keeps the
256
+ // same loose shape so it round-trips into sessionTranscript verbatim.
257
+ session.messages = [
258
+ ...session.messages,
259
+ ...messages.map((m) => ({ ...m })),
260
+ ];
261
+ },
262
+ });
263
+ io.setBusy?.(true);
264
+ liveRuntime = runtime;
265
+ let outcome;
266
+ try {
267
+ // Steer: a submit while the run is live injects immediately (pi's
268
+ // streamingBehavior:"steer" — the loop buffers to a safe boundary).
269
+ // A steer rejected because the loop is settling falls back to the
270
+ // follow-up queue and is delivered as the next Run's input — the
271
+ // message is never dropped (pi's AgentBusyError -> followUp).
272
+ const steerHandler = (text) => {
273
+ addUserInput(state, text, true);
274
+ io.render(state);
275
+ runtime
276
+ .steer({
277
+ inputId: `steer-${randomUUID()}`,
278
+ message: { role: "user", text },
279
+ })
280
+ .catch(() => {
281
+ pendingFollowUps.push(text);
282
+ pushStatus("queued: run is settling — sends when it ends");
283
+ io.render(state);
284
+ });
285
+ };
286
+ io.onLiveInput?.(steerHandler);
287
+ const segment = await runtime.run(runInput);
288
+ outcome = await segment.outcome;
289
+ io.onLiveInput?.(null);
290
+ }
291
+ catch (err) {
292
+ outcome = {
293
+ status: "failed",
294
+ error: err instanceof Error ? err.message : String(err),
295
+ };
296
+ io.onLiveInput?.(null);
297
+ }
298
+ liveRuntime = null;
299
+ applyOutcome(state, outcome);
300
+ io.setBusy?.(false);
301
+ // Long runs often outlast the user's attention: ping when the terminal
302
+ // lost focus so switching back is prompted (pi's desktop-notify analog).
303
+ if (io.isFocused?.() === false) {
304
+ pendingFocusRecap = lastRunRecap(ctx);
305
+ pushStatus("run finished — switch back for recap");
306
+ io.notify?.();
307
+ }
308
+ // Messages were persisted in real time (onPersistMessages); only the
309
+ // end-of-run artifacts (compaction summaries, auto title) remain.
310
+ await persistSessionTurn({
311
+ sessionId: session.sessionId,
312
+ cwd: opts.workspaceRoot,
313
+ runtime,
314
+ dir: session.dir,
315
+ ...(outcome.status === "completed" ? { title: outcome.title } : {}),
316
+ });
317
+ if (outcome.status === "completed") {
318
+ sessionTitle = outcome.title ?? sessionTitle;
319
+ io.setHeader?.({ model: modelId, sessionId: session.sessionId, title: sessionTitle });
320
+ }
321
+ // Compaction happened mid-run: surface what was folded away so the
322
+ // user knows the context was summarized.
323
+ for (const summary of await runtime.compactions()) {
324
+ pushStatus(`compacted: ${summary.slice(0, 160)}${summary.length > 160 ? "…" : ""}`);
325
+ }
326
+ // omp AutoLearn-style indicator: the run's background memory-learn pass
327
+ // shows on the transcript without blocking the editor (the promise
328
+ // resolves even after close()).
329
+ const learning = runtime.memoryLearning();
330
+ if (learning) {
331
+ pushStatus("memory: learning…");
332
+ io.render(state);
333
+ void learning.then((res) => {
334
+ pushStatus(res.freshFacts > 0
335
+ ? `memory: learned ${res.freshFacts} fact${res.freshFacts === 1 ? "" : "s"}`
336
+ : res.ran
337
+ ? "memory: nothing new to learn"
338
+ : "memory: skipped", "memory: ");
339
+ io.render(state);
340
+ });
341
+ }
342
+ // Context footprint of the settled branch under the run model's window
343
+ // (pi's context-usage display); read BEFORE close() like compactions().
344
+ const usage = await runtime.contextUsage().catch(() => undefined);
345
+ if (usage)
346
+ lastContextTokens = usage.estimatedTokens;
347
+ const usageParts = [];
348
+ if (outcome.usage) {
349
+ if (outcome.usage.inputTokens)
350
+ usageParts.push(`↑${outcome.usage.inputTokens}`);
351
+ if (outcome.usage.outputTokens)
352
+ usageParts.push(`↓${outcome.usage.outputTokens}`);
353
+ if (outcome.usage.cacheReadTokens)
354
+ usageParts.push(`cache ${outcome.usage.cacheReadTokens}`);
355
+ }
356
+ if ((usage && usage.limit > 0) || usageParts.length > 0) {
357
+ const ctx = usage && usage.limit > 0
358
+ ? `ctx ${formatTokens(usage.estimatedTokens)}/${formatTokens(usage.limit)}`
359
+ : "";
360
+ const pct = usage && usage.limit > 0
361
+ ? Math.min(100, Math.round((usage.estimatedTokens / usage.limit) * 100))
362
+ : 0;
363
+ const context = [ctx, ...(usageParts.length > 0 ? [usageParts.join(" ")] : [])]
364
+ .filter(Boolean)
365
+ .join(" · ");
366
+ io.setHeader?.({
367
+ model: modelId,
368
+ sessionId: session.sessionId,
369
+ title: sessionTitle,
370
+ context: pct > 0 ? `${context} · ${pct}%` : context,
371
+ });
372
+ }
373
+ await runtime.close().catch(() => { });
374
+ // /exit (or a second ctrl+c path) may have run via the live-command
375
+ // channel while the Run was live — honor it now that the Run settled.
376
+ if (quitting)
377
+ return 0;
378
+ }
379
+ }
380
+ /** CLI entry: run the interactive session over the real terminal. */
381
+ export async function runTuiMode(opts) {
382
+ const io = createTerminalIo(new ProcessTerminal(), opts.workspaceRoot);
383
+ try {
384
+ return await runTuiSession(opts, io);
385
+ }
386
+ finally {
387
+ io.close();
388
+ }
389
+ }
390
+ export { formatModelMeta } from "./tui-format.js";
391
+ export { createTerminalIo } from "./tui-io.js";
@@ -0,0 +1,54 @@
1
+ import { type Container, type Loader, type TUI } from "@chengchenccc/tui";
2
+ import type { OmaTranscriptContainer } from "./tui-components.js";
3
+ import type { TranscriptItem, TuiViewState } from "./view-state.js";
4
+ /** Renders transcript items to display lines, memoizing markdown/tool blocks.
5
+ * Extracted from tui-io.ts to keep the io assembly file under 500 lines. */
6
+ export declare class TuiItemRenderer {
7
+ private readonly tui;
8
+ private readonly markdownCache;
9
+ private readonly itemLineCache;
10
+ private readonly toolBlockCache;
11
+ constructor(tui: TUI);
12
+ renderItem(item: TranscriptItem, state: TuiViewState): string[];
13
+ private computeRenderItem;
14
+ private markdownLines;
15
+ private renderThinking;
16
+ private renderTool;
17
+ }
18
+ /** Header/status/transcript render shell for createTerminalIo. Owns the
19
+ * display-only mutable state (header fields, busy, status line) so the io
20
+ * assembly file stays small. */
21
+ export declare class TuiRenderShell {
22
+ private readonly tui;
23
+ private readonly headerContainer;
24
+ private readonly transcript;
25
+ private readonly statusContainer;
26
+ private readonly workspaceRoot;
27
+ private readonly welcomeTip;
28
+ private headerInfo;
29
+ private headerModel;
30
+ private headerSession;
31
+ private headerTitle;
32
+ private headerContext;
33
+ private busy;
34
+ private loader;
35
+ private busySeconds;
36
+ private currentState;
37
+ statusLineText: string;
38
+ private readonly itemRenderer;
39
+ private readonly reconciler;
40
+ lastLiveStartRow: number;
41
+ lastTotalRows: number;
42
+ constructor(tui: TUI, headerContainer: Container, transcript: OmaTranscriptContainer, statusContainer: Container, workspaceRoot: string, welcomeTip: string);
43
+ setHeader(model: string, session: string, title: string, context?: string): void;
44
+ setBusy(busy: boolean, loader: Loader | null, busySeconds: number): void;
45
+ setBusySeconds(busySeconds: number): void;
46
+ setCurrentState(state: TuiViewState): void;
47
+ renderHeader(): void;
48
+ currentActivitySummary(): string | undefined;
49
+ updateWorkingMessage(): void;
50
+ addStatusBar(): void;
51
+ renderIdleFooter(): void;
52
+ render(state: TuiViewState): void;
53
+ }
54
+ //# sourceMappingURL=tui-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-render.d.ts","sourceRoot":"","sources":["../../../src/modes/tui/tui-render.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EAEd,KAAK,MAAM,EAMX,KAAK,GAAG,EAGT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAgBlE,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpE;6EAC6E;AAC7E,qBAAa,eAAe;IAQd,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPhC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2C;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAG1B;IACJ,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoD;gBAEtD,GAAG,EAAE,GAAG;IAErC,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,EAAE;IAuB/D,OAAO,CAAC,iBAAiB;IAyBzB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,UAAU;CAyHnB;AAED;;iCAEiC;AACjC,qBAAa,cAAc;IAiBvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IArB7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,aAAa,CAAM;IAC3B,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,aAAa,CAAM;IAC3B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAA6B;IACjD,cAAc,SAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkB;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,gBAAgB,SAAK;IACrB,aAAa,SAAK;gBAGC,GAAG,EAAE,GAAG,EACR,eAAe,EAAE,SAAS,EAC1B,UAAU,EAAE,sBAAsB,EAClC,eAAe,EAAE,SAAS,EAC1B,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM;IAMrC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAahF,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAMxE,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAIzC,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAI1C,YAAY,IAAI,IAAI;IAiDpB,sBAAsB,IAAI,MAAM,GAAG,SAAS;IAyC5C,oBAAoB,IAAI,IAAI;IAU5B,YAAY,IAAI,IAAI;IAqBpB,gBAAgB,IAAI,IAAI;IAKxB,MAAM,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;CA6BlC"}