@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,81 @@
1
+ import { Container, type FramePlan, type NativeScrollbackCommittedRows, type NativeScrollbackLiveRegion, type NativeScrollbackReplay, type RenderStablePrefix, SelectList, type SelectListTheme, type TerminalFrameProvider, type Text } from "@chengchenccc/tui";
2
+ export declare class PickerOverlay extends Container {
3
+ private readonly list;
4
+ constructor(title: Text, list: SelectList);
5
+ handleInput(data: string): void;
6
+ render(width: number): string[];
7
+ }
8
+ /** Overlay for ctrl+r history search (pi's HistorySearchComponent, lazy
9
+ * form): a query input plus a SelectList rebuilt per keystroke. Navigation
10
+ * keys go to the list; everything else edits the query. */
11
+ export declare class HistorySearchOverlay extends Container {
12
+ private readonly listSlot;
13
+ private readonly query;
14
+ private list;
15
+ private readonly entries;
16
+ private readonly theme;
17
+ private readonly selectCb;
18
+ private readonly cancelCb;
19
+ constructor(title: Text, entries: readonly string[], theme: SelectListTheme, onSelect: (value: string) => void, onCancel: () => void);
20
+ private buildList;
21
+ handleInput(data: string): void;
22
+ render(width: number): string[];
23
+ }
24
+ export declare class OmaTranscriptContainer extends Container implements NativeScrollbackCommittedRows, NativeScrollbackLiveRegion, NativeScrollbackReplay, RenderStablePrefix, TerminalFrameProvider {
25
+ /** Rows already written to native scrollback (acknowledged frontier). */
26
+ private committedRows;
27
+ /** Desired commit boundary set by the render shell each frame. */
28
+ private targetCommittedRows;
29
+ private lastLines;
30
+ private lastWidth;
31
+ private nextBatchId;
32
+ private offeredBatch;
33
+ private deferCommit;
34
+ /** While a run is live, mermaid/code rows may still re-layout on a later
35
+ * chunk; don't advance the scrollback frontier until the run settles
36
+ * (omp defers native-scrollback settling wholesale for live blocks). */
37
+ setDeferCommit(defer: boolean): void;
38
+ /** Records the desired commit boundary; `peekFinalizedBatch` turns it into
39
+ * an incremental history packet only when it is behind the frontier. */
40
+ setNativeScrollbackCommittedRows(rows: number): void;
41
+ getNativeScrollbackLiveRegionStart(): number | undefined;
42
+ getRenderStablePrefixRows(): number;
43
+ prepareNativeScrollbackReplay(): void;
44
+ clear(): void;
45
+ /** Total rows currently in the live (not-yet-committed) tail. */
46
+ liveRowCount(width: number): number;
47
+ /** Render only the live tail, keeping the most recent `maxRows`. */
48
+ renderViewport(width: number, maxRows: number): string[];
49
+ /** Populate the cached full-render baseline on first paint or a width change. */
50
+ private ensureFullRender;
51
+ /** Offer the next uncommitted prefix as one history batch (omp peek).
52
+ * Returns only the *new* rows (from the frontier), never the cumulative
53
+ * prefix, so the terminal appends each packet exactly once. */
54
+ peekFinalizedBatch(width: number): {
55
+ id: number;
56
+ end: number;
57
+ } | undefined;
58
+ /** Acknowledges the offered batch, advancing the frontier (omp ack). */
59
+ acknowledgeFinalizedBatch(id: number): void;
60
+ /** Render the currently-offered history packet rows (no full re-render). */
61
+ renderOfferedHistory(width: number): {
62
+ id: number;
63
+ rows: string[];
64
+ } | undefined;
65
+ /** Render the children in `[start, end)` as rows (used for history packets). */
66
+ renderRange(start: number, end: number, width: number): string[];
67
+ /** Frame provider viewport = full render; history = uncommitted frontier
68
+ * rows to append to native scrollback. */
69
+ renderFrame(opts: {
70
+ columns: number;
71
+ rows: number;
72
+ }): FramePlan;
73
+ /** Replay the committed prefix after a resize/replay (force full re-compose). */
74
+ beginReplay(): void;
75
+ /** Graceful shutdown flush: offer + ack the committed prefix, then reset. */
76
+ beginHistoryFlush(): void;
77
+ render(width: number): string[];
78
+ }
79
+ /** Production TuiIo over the real terminal. The optional terminal override
80
+ * is the test seam: e2e tests inject a VirtualTerminal (xterm headless). */
81
+ //# sourceMappingURL=tui-components.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-components.d.ts","sourceRoot":"","sources":["../../../src/modes/tui/tui-components.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,248 @@
1
+ import { Container, Input, matchesKey, SelectList, } from "@chengchenccc/tui";
2
+ import { overlayLines } from "./tui-format.js";
3
+ export class PickerOverlay extends Container {
4
+ list;
5
+ constructor(title, list) {
6
+ super();
7
+ this.list = list;
8
+ this.addChild(title);
9
+ this.addChild(list);
10
+ }
11
+ handleInput(data) {
12
+ this.list.handleInput(data);
13
+ }
14
+ render(width) {
15
+ return overlayLines(super.render(Math.max(1, width - 2)), width);
16
+ }
17
+ }
18
+ /** Overlay for ctrl+r history search (pi's HistorySearchComponent, lazy
19
+ * form): a query input plus a SelectList rebuilt per keystroke. Navigation
20
+ * keys go to the list; everything else edits the query. */
21
+ export class HistorySearchOverlay extends Container {
22
+ listSlot = new Container();
23
+ query;
24
+ list;
25
+ entries;
26
+ theme;
27
+ selectCb;
28
+ cancelCb;
29
+ constructor(title, entries, theme, onSelect, onCancel) {
30
+ super();
31
+ this.entries = entries;
32
+ this.theme = theme;
33
+ this.selectCb = onSelect;
34
+ this.cancelCb = onCancel;
35
+ this.query = new Input();
36
+ this.list = this.buildList();
37
+ this.addChild(title);
38
+ this.addChild(this.query);
39
+ this.addChild(this.listSlot);
40
+ this.listSlot.addChild(this.list);
41
+ }
42
+ buildList() {
43
+ const needle = this.query.getValue().trim().toLowerCase();
44
+ const matches = this.entries.filter((e) => e.toLowerCase().includes(needle)).slice(0, 100);
45
+ const items = matches.map((value) => ({
46
+ value,
47
+ label: value.length > 48 ? `${value.slice(0, 48)}...` : value,
48
+ }));
49
+ const list = new SelectList(items, 10, this.theme);
50
+ list.onSelect = (item) => this.selectCb(item.value);
51
+ list.onCancel = () => this.cancelCb();
52
+ return list;
53
+ }
54
+ handleInput(data) {
55
+ const navigates = matchesKey(data, "up") ||
56
+ matchesKey(data, "down") ||
57
+ matchesKey(data, "pageUp") ||
58
+ matchesKey(data, "pageDown") ||
59
+ matchesKey(data, "enter");
60
+ if (navigates) {
61
+ this.list.handleInput(data);
62
+ return;
63
+ }
64
+ if (matchesKey(data, "escape")) {
65
+ this.list.onCancel?.();
66
+ return;
67
+ }
68
+ this.query.handleInput(data);
69
+ this.listSlot.clear();
70
+ this.list = this.buildList();
71
+ this.listSlot.addChild(this.list);
72
+ }
73
+ render(width) {
74
+ return overlayLines(super.render(Math.max(1, width - 2)), width);
75
+ }
76
+ }
77
+ export class OmaTranscriptContainer extends Container {
78
+ /** Rows already written to native scrollback (acknowledged frontier). */
79
+ committedRows = 0;
80
+ /** Desired commit boundary set by the render shell each frame. */
81
+ targetCommittedRows = 0;
82
+ lastLines = [];
83
+ lastWidth = -1;
84
+ nextBatchId = 1;
85
+ offeredBatch;
86
+ deferCommit = false;
87
+ /** While a run is live, mermaid/code rows may still re-layout on a later
88
+ * chunk; don't advance the scrollback frontier until the run settles
89
+ * (omp defers native-scrollback settling wholesale for live blocks). */
90
+ setDeferCommit(defer) {
91
+ this.deferCommit = defer;
92
+ }
93
+ /** Records the desired commit boundary; `peekFinalizedBatch` turns it into
94
+ * an incremental history packet only when it is behind the frontier. */
95
+ setNativeScrollbackCommittedRows(rows) {
96
+ if (this.deferCommit)
97
+ return;
98
+ this.targetCommittedRows = Number.isFinite(rows) ? Math.max(0, Math.trunc(rows)) : 0;
99
+ if (this.targetCommittedRows < this.committedRows)
100
+ this.targetCommittedRows = this.committedRows;
101
+ }
102
+ getNativeScrollbackLiveRegionStart() {
103
+ return this.committedRows;
104
+ }
105
+ getRenderStablePrefixRows() {
106
+ return this.committedRows;
107
+ }
108
+ prepareNativeScrollbackReplay() {
109
+ this.lastLines = [];
110
+ this.lastWidth = -1;
111
+ }
112
+ clear() {
113
+ super.clear();
114
+ this.lastLines = [];
115
+ this.lastWidth = -1;
116
+ this.committedRows = 0;
117
+ this.targetCommittedRows = 0;
118
+ this.offeredBatch = undefined;
119
+ }
120
+ /** Total rows currently in the live (not-yet-committed) tail. */
121
+ liveRowCount(width) {
122
+ this.ensureFullRender(width);
123
+ let rows = 0;
124
+ for (let i = Math.min(this.committedRows, this.children.length); i < this.children.length; i++) {
125
+ rows += this.children[i].render(width).length;
126
+ }
127
+ return rows;
128
+ }
129
+ /** Render only the live tail, keeping the most recent `maxRows`. */
130
+ renderViewport(width, maxRows) {
131
+ this.ensureFullRender(width);
132
+ const live = [];
133
+ for (let i = Math.min(this.committedRows, this.children.length); i < this.children.length; i++) {
134
+ const childLines = this.children[i].render(width);
135
+ for (const line of childLines)
136
+ live.push(line);
137
+ }
138
+ if (live.length > maxRows)
139
+ return live.slice(live.length - maxRows);
140
+ return live;
141
+ }
142
+ /** Populate the cached full-render baseline on first paint or a width change. */
143
+ ensureFullRender(width) {
144
+ if (this.lastWidth !== width || this.lastLines.length === 0) {
145
+ this.lastLines = super.render(width);
146
+ this.lastWidth = width;
147
+ }
148
+ }
149
+ /** Offer the next uncommitted prefix as one history batch (omp peek).
150
+ * Returns only the *new* rows (from the frontier), never the cumulative
151
+ * prefix, so the terminal appends each packet exactly once. */
152
+ peekFinalizedBatch(width) {
153
+ if (this.deferCommit)
154
+ return undefined;
155
+ if (this.offeredBatch !== undefined)
156
+ return this.offeredBatch;
157
+ if (this.targetCommittedRows <= this.committedRows || this.lastWidth !== width)
158
+ return undefined;
159
+ const end = this.targetCommittedRows;
160
+ const batch = { id: this.nextBatchId++, end };
161
+ this.offeredBatch = batch;
162
+ return batch;
163
+ }
164
+ /** Acknowledges the offered batch, advancing the frontier (omp ack). */
165
+ acknowledgeFinalizedBatch(id) {
166
+ if (this.offeredBatch === undefined || this.offeredBatch.id !== id)
167
+ return;
168
+ this.committedRows = Math.max(this.committedRows, this.offeredBatch.end);
169
+ this.offeredBatch = undefined;
170
+ }
171
+ /** Render the currently-offered history packet rows (no full re-render). */
172
+ renderOfferedHistory(width) {
173
+ const batch = this.peekFinalizedBatch(width);
174
+ if (!batch)
175
+ return undefined;
176
+ return { id: batch.id, rows: this.renderRange(this.committedRows, batch.end, width) };
177
+ }
178
+ /** Render the children in `[start, end)` as rows (used for history packets). */
179
+ renderRange(start, end, width) {
180
+ const out = [];
181
+ for (let i = start; i < Math.min(end, this.children.length); i++) {
182
+ const childLines = this.children[i].render(width);
183
+ for (const line of childLines)
184
+ out.push(line);
185
+ }
186
+ return out;
187
+ }
188
+ /** Frame provider viewport = full render; history = uncommitted frontier
189
+ * rows to append to native scrollback. */
190
+ renderFrame(opts) {
191
+ const viewport = this.render(opts.columns);
192
+ const batch = this.peekFinalizedBatch(opts.columns);
193
+ return {
194
+ viewport,
195
+ history: batch
196
+ ? { id: batch.id, rows: this.renderRange(this.committedRows, batch.end, opts.columns) }
197
+ : undefined,
198
+ };
199
+ }
200
+ /** Replay the committed prefix after a resize/replay (force full re-compose). */
201
+ beginReplay() {
202
+ this.offeredBatch = undefined;
203
+ this.committedRows = 0;
204
+ this.targetCommittedRows = 0;
205
+ this.lastLines = [];
206
+ this.lastWidth = -1;
207
+ }
208
+ /** Graceful shutdown flush: offer + ack the committed prefix, then reset. */
209
+ beginHistoryFlush() {
210
+ const batch = this.peekFinalizedBatch(this.lastWidth);
211
+ if (batch)
212
+ this.acknowledgeFinalizedBatch(batch.id);
213
+ this.beginReplay();
214
+ }
215
+ render(width) {
216
+ // Steady-state frames reuse the committed prefix (rows already in native
217
+ // scrollback) and only compose children at/after the seam, making each
218
+ // frame O(live tail) instead of O(history). A width change forces a full
219
+ // re-layout of the prefix too.
220
+ if (this.lastWidth !== width || this.children.length === 0) {
221
+ const all = super.render(width);
222
+ this.lastLines = all;
223
+ this.lastWidth = width;
224
+ return all;
225
+ }
226
+ const start = Math.min(this.committedRows, this.children.length);
227
+ // Cheap committed-prefix audit: the last committed row must still match
228
+ // its cached bytes, otherwise the prefix drifted and we re-layout fully.
229
+ if (start > 0) {
230
+ const audit = this.children[start - 1]?.render(width)?.[0] ?? "";
231
+ if (audit !== this.lastLines[start - 1]) {
232
+ const all = super.render(width);
233
+ this.lastLines = all;
234
+ this.lastWidth = width;
235
+ return all;
236
+ }
237
+ }
238
+ const prefix = this.lastLines.slice(0, Math.max(0, start));
239
+ const tail = [];
240
+ for (let i = start; i < this.children.length; i++) {
241
+ tail.push(...this.children[i].render(width));
242
+ }
243
+ this.lastLines = [...prefix, ...tail];
244
+ return this.lastLines;
245
+ }
246
+ }
247
+ /** Production TuiIo over the real terminal. The optional terminal override
248
+ * is the test seam: e2e tests inject a VirtualTerminal (xterm headless). */
@@ -0,0 +1,65 @@
1
+ import type { DefaultTextStyle, EditorTheme, MarkdownTheme } from "@chengchenccc/tui";
2
+ export declare const MAX_TOOL_ARGS = 200;
3
+ export declare const MAX_TOOL_DETAIL = 8000;
4
+ export declare const MAX_DIFF_LINES = 6;
5
+ /** Compact single-line JSON, truncated with an ellipsis marker. */
6
+ export declare function compactJson(value: unknown, max: number): string;
7
+ /** Multi-line pretty JSON, truncated at MAX_TOOL_DETAIL with an ellipsis. */
8
+ export declare function prettyJson(value: unknown): string;
9
+ /** Collapsed tool-result summary: prefer result.content as a human
10
+ * sentence, keeping the exit marker; fall back to compact JSON only
11
+ * when content is not a string. */
12
+ export declare function summarizeResult(result: Readonly<Record<string, unknown>>): string;
13
+ /** Pi-style collapsed arg summaries: a human sentence per common tool
14
+ * (bash's `$ cmd`, read's `path:a-b`), falling back to compact JSON. */
15
+ export declare const TOOL_ARG_SUMMARIES: Record<string, (input: Record<string, unknown>) => string>;
16
+ export declare function summarizeToolArgs(toolName: string, input: Readonly<Record<string, unknown>>): string;
17
+ export declare const EDITOR_THEME: EditorTheme;
18
+ /** Compact relative age for the session picker's label column. */
19
+ export declare function relativeTime(modifiedAt: number): string;
20
+ /** Markdown theme for assistant output: plain readable text with ANSI
21
+ * emphasis — bold/italic/links/code styled, headings bold, no colors
22
+ * beyond dim (pi renders through its theme; oma keeps it monochrome+dim
23
+ * so the cyan user bubble stays the only saturated element). */
24
+ export declare const MARKDOWN_THEME: MarkdownTheme;
25
+ /** User bubble: markdown text on a deep-blue background tint with cyan
26
+ * text (pi's UserMessageComponent look). */
27
+ export declare const USER_TEXT_STYLE: DefaultTextStyle;
28
+ /** Compact token count for the header: 12k / 200k. */
29
+ export declare function formatTokens(n: number): string;
30
+ /** Compact model meta line (pi's ModelBrowser columns): display name,
31
+ * context window, $in/out per-million cost (free when both legs are zero),
32
+ * current-model mark, and an over-context warning when the session's
33
+ * estimated tokens exceed the model's window. */
34
+ export declare function formatModelMeta(model: {
35
+ displayName: string;
36
+ contextWindow: number;
37
+ cost?: {
38
+ input: number;
39
+ output: number;
40
+ };
41
+ }, opts?: {
42
+ current?: boolean;
43
+ contextTokens?: number;
44
+ }): string;
45
+ export declare const OVERLAY_BG: (s: string) => string;
46
+ /** Pad + frame overlay lines so they cover the underlying transcript
47
+ * (a plain Container's unshaped whitespace lets the base text bleed
48
+ * through). */
49
+ export declare function overlayLines(lines: readonly string[], width: number): string[];
50
+ /** Overlay root for the session picker: renders title + list and routes
51
+ * key input to the list (a plain Container has no handleInput). */
52
+ /** Clean a session title for the header line: strip markdown heading
53
+ * markers/whitespace, collapse whitespace, cap at 32 chars. */
54
+ export declare function cleanHeaderTitle(title: string): string;
55
+ /** Compact git branch + dirty count for the idle status line. */
56
+ export declare function gitStatus(workspaceRoot: string): string;
57
+ /** Shorten the workspace path for display (~/... when under HOME). */
58
+ export declare function formatWorkspace(root: string): string;
59
+ /** Branch cyan, dirty count ember (omp gitClean/gitDirty colors). */
60
+ export declare function renderGitSegment(git: string): string;
61
+ /** Threshold color for context percent (omp contextPct). */
62
+ export declare function contextColor(ctx: string): string;
63
+ /** One-time welcome easter eggs, rotated per session (omp welcome tip). */
64
+ export declare const WELCOME_TIPS: readonly string[];
65
+ //# sourceMappingURL=tui-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-format.d.ts","sourceRoot":"","sources":["../../../src/modes/tui/tui-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGtF,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,eAAe,OAAQ,CAAC;AACrC,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGjD;AAED;;oCAEoC;AACpC,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAoCjF;AAED;yEACyE;AACzE,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAsBzF,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,MAAM,CAOR;AACD,eAAO,MAAM,YAAY,EAAE,WAS1B,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CASvD;AAED;;;iEAGiE;AACjE,eAAO,MAAM,cAAc,EAAE,aAe5B,CAAC;AAEF;6CAC6C;AAC7C,eAAO,MAAM,eAAe,EAAE,gBAG7B,CAAC;AAEF,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED;;;kDAGkD;AAClD,wBAAgB,eAAe,CAC7B,KAAK,EAAE;IACL,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C,EACD,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvD,MAAM,CAUR;AAED,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,KAAG,MAAyC,CAAC;AAEjF;;gBAEgB;AAChB,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAM9E;AAED;oEACoE;AACpE;gEACgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED,iEAAiE;AACjE,wBAAgB,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAoBvD;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpD;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED,2EAA2E;AAC3E,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAMzC,CAAC"}
@@ -0,0 +1,246 @@
1
+ import { applyBackgroundToLine, truncateToWidth } from "@chengchenccc/tui";
2
+ export const MAX_TOOL_ARGS = 200;
3
+ export const MAX_TOOL_DETAIL = 8_000;
4
+ export const MAX_DIFF_LINES = 6;
5
+ /** Compact single-line JSON, truncated with an ellipsis marker. */
6
+ export function compactJson(value, max) {
7
+ const json = JSON.stringify(value) ?? String(value);
8
+ return json.length > max ? `${json.slice(0, max)}…` : json;
9
+ }
10
+ /** Multi-line pretty JSON, truncated at MAX_TOOL_DETAIL with an ellipsis. */
11
+ export function prettyJson(value) {
12
+ const json = JSON.stringify(value, null, 2) ?? String(value);
13
+ return json.length > MAX_TOOL_DETAIL ? `${json.slice(0, MAX_TOOL_DETAIL)}…` : json;
14
+ }
15
+ /** Collapsed tool-result summary: prefer result.content as a human
16
+ * sentence, keeping the exit marker; fall back to compact JSON only
17
+ * when content is not a string. */
18
+ export function summarizeResult(result) {
19
+ const content = result.content;
20
+ if (typeof content === "string") {
21
+ const lines = content
22
+ .split("\n")
23
+ .map((s) => s.trim())
24
+ .filter(Boolean);
25
+ const isError = result.isError === true || result.error !== undefined;
26
+ // Success: strip the `[exit: 0]` notice (omp's stripExitCodeNotice) so
27
+ // the line stays human; error keeps a red exit marker (renderTool colors it).
28
+ const contentLines = isError ? lines : lines.filter((l) => !/^\[exit: \d+\]$/.test(l));
29
+ if (contentLines.length > 0) {
30
+ const first = contentLines[0];
31
+ const exit = isError ? lines.find((l) => /^\[exit: \d+\]$/.test(l)) : undefined;
32
+ const summary = exit && exit !== first ? `${first} · ${exit}` : first;
33
+ const remaining = contentLines.filter((l) => l !== first && l !== exit).length;
34
+ const suffix = remaining > 0 ? ` (+${remaining} line${remaining === 1 ? "" : "s"}, ctrl+o)` : "";
35
+ const base = summary.length > MAX_TOOL_ARGS ? `${summary.slice(0, MAX_TOOL_ARGS)}…` : summary;
36
+ return `${base}${suffix}`;
37
+ }
38
+ return "";
39
+ }
40
+ const json = JSON.stringify(result) ?? "";
41
+ if (json.length <= MAX_TOOL_ARGS)
42
+ return json;
43
+ let firstLine = json;
44
+ for (const value of Object.values(result)) {
45
+ if (typeof value === "string" && value.trim()) {
46
+ firstLine = value.trim().split("\n", 1)[0] ?? value;
47
+ break;
48
+ }
49
+ }
50
+ if (firstLine.length > MAX_TOOL_ARGS) {
51
+ firstLine = `${firstLine.slice(0, MAX_TOOL_ARGS)}…`;
52
+ }
53
+ return `${firstLine} (+${json.length - firstLine.length} chars, ctrl+o)`;
54
+ }
55
+ /** Pi-style collapsed arg summaries: a human sentence per common tool
56
+ * (bash's `$ cmd`, read's `path:a-b`), falling back to compact JSON. */
57
+ export const TOOL_ARG_SUMMARIES = {
58
+ bash: (i) => {
59
+ const command = typeof i.command === "string" ? i.command : "";
60
+ const timeout = typeof i.timeout === "number" ? ` (timeout ${Math.round(i.timeout / 1000)}s)` : "";
61
+ return `$ ${command}${timeout}`;
62
+ },
63
+ read: (i) => {
64
+ const path = typeof i.path === "string" ? i.path : "";
65
+ if (typeof i.offset === "number" && typeof i.limit === "number") {
66
+ return `${path}:${i.offset}-${i.offset + i.limit - 1}`;
67
+ }
68
+ return path;
69
+ },
70
+ write: (i) => (typeof i.path === "string" ? i.path : ""),
71
+ edit: (i) => (typeof i.path === "string" ? i.path : ""),
72
+ grep: (i) => {
73
+ const pattern = typeof i.pattern === "string" ? i.pattern : "";
74
+ const path = typeof i.path === "string" ? ` ${i.path}` : "";
75
+ return `${pattern}${path}`;
76
+ },
77
+ glob: (i) => (typeof i.pattern === "string" ? i.pattern : ""),
78
+ };
79
+ export function summarizeToolArgs(toolName, input) {
80
+ const summarize = TOOL_ARG_SUMMARIES[toolName];
81
+ if (summarize) {
82
+ const summary = summarize(input);
83
+ if (summary.trim())
84
+ return summary;
85
+ }
86
+ return compactJson(input, MAX_TOOL_ARGS);
87
+ }
88
+ export const EDITOR_THEME = {
89
+ borderColor: (s) => `\u001b[2m${s}\u001b[0m`,
90
+ selectList: {
91
+ selectedPrefix: (s) => `\u001b[36m${s}\u001b[0m`,
92
+ selectedText: (s) => `\u001b[1m${s}\u001b[0m`,
93
+ description: (s) => `\u001b[2m${s}\u001b[0m`,
94
+ scrollInfo: (s) => `\u001b[2m${s}\u001b[0m`,
95
+ noMatch: (s) => `\u001b[2m${s}\u001b[0m`,
96
+ },
97
+ };
98
+ /** Compact relative age for the session picker's label column. */
99
+ export function relativeTime(modifiedAt) {
100
+ const minutes = Math.floor((Date.now() - modifiedAt) / 60_000);
101
+ if (minutes < 1)
102
+ return "now";
103
+ if (minutes < 60)
104
+ return `${minutes}m`;
105
+ const hours = Math.floor(minutes / 60);
106
+ if (hours < 24)
107
+ return `${hours}h`;
108
+ const days = Math.floor(hours / 24);
109
+ if (days < 30)
110
+ return `${days}d`;
111
+ return `${Math.floor(days / 30)}mo`;
112
+ }
113
+ /** Markdown theme for assistant output: plain readable text with ANSI
114
+ * emphasis — bold/italic/links/code styled, headings bold, no colors
115
+ * beyond dim (pi renders through its theme; oma keeps it monochrome+dim
116
+ * so the cyan user bubble stays the only saturated element). */
117
+ export const MARKDOWN_THEME = {
118
+ heading: (s) => `\u001b[1m${s}\u001b[0m`,
119
+ link: (s) => `\u001b[4m${s}\u001b[0m`,
120
+ linkUrl: (s) => `\u001b[2m${s}\u001b[0m`,
121
+ code: (s) => `\u001b[36m${s}\u001b[0m`,
122
+ codeBlock: (s) => `\u001b[36m${s}\u001b[0m`,
123
+ codeBlockBorder: (s) => `\u001b[2m${s}\u001b[0m`,
124
+ quote: (s) => `\u001b[2m${s}\u001b[0m`,
125
+ quoteBorder: (s) => `\u001b[2m${s}\u001b[0m`,
126
+ hr: (s) => `\u001b[2m${s}\u001b[0m`,
127
+ listBullet: (s) => `\u001b[2m${s}\u001b[0m`,
128
+ bold: (s) => `\u001b[1m${s}\u001b[0m`,
129
+ italic: (s) => `\u001b[3m${s}\u001b[0m`,
130
+ strikethrough: (s) => `\u001b[9m${s}\u001b[0m`,
131
+ underline: (s) => `\u001b[4m${s}\u001b[0m`,
132
+ };
133
+ /** User bubble: markdown text on a deep-blue background tint with cyan
134
+ * text (pi's UserMessageComponent look). */
135
+ export const USER_TEXT_STYLE = {
136
+ color: (s) => `\u001b[36m${s}\u001b[0m`,
137
+ bgColor: (s) => `\u001b[48;5;234m${s}\u001b[0m`,
138
+ };
139
+ /** Compact token count for the header: 12k / 200k. */
140
+ export function formatTokens(n) {
141
+ if (n >= 1000)
142
+ return `${Math.round(n / 1000)}k`;
143
+ return `${n}`;
144
+ }
145
+ /** Compact model meta line (pi's ModelBrowser columns): display name,
146
+ * context window, $in/out per-million cost (free when both legs are zero),
147
+ * current-model mark, and an over-context warning when the session's
148
+ * estimated tokens exceed the model's window. */
149
+ export function formatModelMeta(model, opts = {}) {
150
+ const input = model.cost?.input ?? 0;
151
+ const output = model.cost?.output ?? 0;
152
+ const cost = input <= 0 && output <= 0 ? "free" : `$${input}/${output}`;
153
+ const parts = [model.displayName, `ctx ${formatTokens(model.contextWindow)}`, cost];
154
+ if (opts.current)
155
+ parts.push("current");
156
+ if (opts.contextTokens !== undefined && model.contextWindow < opts.contextTokens) {
157
+ parts.push("over current context!");
158
+ }
159
+ return parts.join(" · ");
160
+ }
161
+ export const OVERLAY_BG = (s) => `\u001b[48;5;235m${s}\u001b[0m`;
162
+ /** Pad + frame overlay lines so they cover the underlying transcript
163
+ * (a plain Container's unshaped whitespace lets the base text bleed
164
+ * through). */
165
+ export function overlayLines(lines, width) {
166
+ const innerWidth = Math.max(1, width - 2);
167
+ return lines.map((line) => {
168
+ const content = truncateToWidth(line, innerWidth, "", true);
169
+ return `\u001b[36m\u2502\u001b[0m${applyBackgroundToLine(content, innerWidth, OVERLAY_BG)}\u001b[36m\u2502\u001b[0m`;
170
+ });
171
+ }
172
+ /** Overlay root for the session picker: renders title + list and routes
173
+ * key input to the list (a plain Container has no handleInput). */
174
+ /** Clean a session title for the header line: strip markdown heading
175
+ * markers/whitespace, collapse whitespace, cap at 32 chars. */
176
+ export function cleanHeaderTitle(title) {
177
+ const cleaned = title
178
+ .replace(/^[#>*\s]+/, "")
179
+ .replace(/\s+/g, " ")
180
+ .trim();
181
+ if (!cleaned)
182
+ return "";
183
+ const truncated = cleaned.length > 32 ? `${cleaned.slice(0, 32)}…` : cleaned;
184
+ return ` — ${truncated}`;
185
+ }
186
+ /** Compact git branch + dirty count for the idle status line. */
187
+ export function gitStatus(workspaceRoot) {
188
+ try {
189
+ const branchResult = Bun.spawnSync([
190
+ "git",
191
+ "-C",
192
+ workspaceRoot,
193
+ "rev-parse",
194
+ "--abbrev-ref",
195
+ "HEAD",
196
+ ]);
197
+ if (branchResult.exitCode !== 0)
198
+ return "";
199
+ const branch = branchResult.stdout.toString().trim();
200
+ if (!branch)
201
+ return "";
202
+ const porcelain = Bun.spawnSync(["git", "-C", workspaceRoot, "status", "--porcelain"]);
203
+ if (porcelain.exitCode !== 0)
204
+ return branch;
205
+ const changes = porcelain.stdout.toString().split("\n").filter(Boolean).length;
206
+ return changes > 0 ? `${branch}+${changes}` : branch;
207
+ }
208
+ catch {
209
+ return "";
210
+ }
211
+ }
212
+ /** Shorten the workspace path for display (~/... when under HOME). */
213
+ export function formatWorkspace(root) {
214
+ const home = process.env.HOME;
215
+ if (home && (root === home || root.startsWith(`${home}/`))) {
216
+ return root === home ? "~" : `~${root.slice(home.length)}`;
217
+ }
218
+ return root;
219
+ }
220
+ /** Branch cyan, dirty count ember (omp gitClean/gitDirty colors). */
221
+ export function renderGitSegment(git) {
222
+ if (!git)
223
+ return "";
224
+ const plus = git.indexOf("+");
225
+ if (plus === -1)
226
+ return `\u001b[38;5;42m${git}\u001b[0m`;
227
+ return `\u001b[38;5;39m${git.slice(0, plus)}\u001b[0m\u001b[38;5;172m${git.slice(plus)}\u001b[0m`;
228
+ }
229
+ /** Threshold color for context percent (omp contextPct). */
230
+ export function contextColor(ctx) {
231
+ const m = ctx.match(/(\d+)%/);
232
+ const pct = m ? Number(m[1]) : 0;
233
+ if (pct >= 90)
234
+ return "\u001b[38;5;196m";
235
+ if (pct >= 70)
236
+ return "\u001b[38;5;172m";
237
+ return "\u001b[2m";
238
+ }
239
+ /** One-time welcome easter eggs, rotated per session (omp welcome tip). */
240
+ export const WELCOME_TIPS = [
241
+ "Tip: press ctrl+t to expand thinking, ctrl+o for tool detail",
242
+ "Tip: /mcp test <name> checks a configured MCP server",
243
+ "Tip: /resume lists saved sessions; /session shows the current id",
244
+ "Tip: /workflow runs a script with subagents",
245
+ "Tip: /exit twice quits; /help lists all commands",
246
+ ];
@@ -0,0 +1,16 @@
1
+ import type { Container, Editor, TerminalFrameProvider } from "@chengchenccc/tui";
2
+ import type { OmaTranscriptContainer } from "./tui-components.js";
3
+ import type { TuiRenderShell } from "./tui-render.js";
4
+ export interface OmaFrameProviderOptions {
5
+ headerContainer: Container;
6
+ transcript: OmaTranscriptContainer;
7
+ statusContainer: Container;
8
+ editor: Editor;
9
+ shell: TuiRenderShell;
10
+ }
11
+ /** Composes the bounded mutable viewport (header + live transcript tail +
12
+ * status/editor) and offers incremental transcript history for native
13
+ * scrollback. Header is rendered as live chrome; when the transcript fills
14
+ * the available rows, settled prefix commits via `history`. */
15
+ export declare function createOmaFrameProvider({ headerContainer, transcript, statusContainer, editor, shell, }: OmaFrameProviderOptions): TerminalFrameProvider;
16
+ //# sourceMappingURL=tui-frame-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-frame-provider.d.ts","sourceRoot":"","sources":["../../../src/modes/tui/tui-frame-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,WAAW,uBAAuB;IACtC,eAAe,EAAE,SAAS,CAAC;IAC3B,UAAU,EAAE,sBAAsB,CAAC;IACnC,eAAe,EAAE,SAAS,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,CAAC;CACvB;AAED;;;gEAGgE;AAChE,wBAAgB,sBAAsB,CAAC,EACrC,eAAe,EACf,UAAU,EACV,eAAe,EACf,MAAM,EACN,KAAK,GACN,EAAE,uBAAuB,GAAG,qBAAqB,CA0BjD"}