@visual-z/xeno 0.2.1 → 0.4.0

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 (282) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +126 -34
  3. package/docs/app-server.md +84 -0
  4. package/docs/install.md +51 -13
  5. package/docs/providers.md +24 -3
  6. package/package.json +7 -5
  7. package/src/apps/app-server.ts +28 -0
  8. package/src/apps/approve.ts +3 -3
  9. package/src/apps/cli.ts +25 -10
  10. package/src/apps/commands.ts +45 -8
  11. package/src/apps/completions.ts +78 -22
  12. package/src/apps/control-transport.ts +89 -0
  13. package/src/apps/image-draft.ts +46 -0
  14. package/src/apps/model-catalog.ts +2 -1
  15. package/src/apps/project-trust.ts +2 -42
  16. package/src/apps/provider-connect.ts +346 -0
  17. package/src/apps/render.ts +22 -47
  18. package/src/apps/resources.ts +5 -2
  19. package/src/apps/shell.ts +333 -1542
  20. package/src/apps/startup-input.ts +45 -9
  21. package/src/apps/startup.ts +149 -94
  22. package/src/apps/ui/app.ts +1553 -0
  23. package/src/apps/ui/control-model.ts +26 -0
  24. package/src/apps/ui/extension-host.ts +194 -0
  25. package/src/apps/ui/image-cache.ts +78 -0
  26. package/src/apps/ui/palette.ts +88 -0
  27. package/src/apps/ui/project.ts +127 -0
  28. package/src/apps/ui/standalone.ts +146 -0
  29. package/src/apps/ui/status-model.ts +68 -0
  30. package/src/apps/ui/surface.ts +86 -0
  31. package/src/apps/ui/theme.ts +86 -0
  32. package/src/core/acceptance.ts +107 -0
  33. package/src/core/action-defaults.ts +47 -295
  34. package/src/core/benchmark.ts +2 -2
  35. package/src/core/branch-receipt.ts +24 -0
  36. package/src/core/checkpoints.ts +64 -0
  37. package/src/core/churn.ts +2 -0
  38. package/src/core/command-artifacts.ts +94 -0
  39. package/src/core/command-contract.ts +35 -0
  40. package/src/core/completion-action.ts +20 -0
  41. package/src/core/completion-review.ts +37 -21
  42. package/src/core/context-detail.ts +37 -0
  43. package/src/core/context-policy.ts +74 -1
  44. package/src/core/continuation.ts +17 -2
  45. package/src/core/control-protocol.ts +62 -0
  46. package/src/core/control-view.ts +42 -0
  47. package/src/core/derive.ts +29 -3
  48. package/src/core/draft-images.ts +56 -0
  49. package/src/core/environment.ts +145 -0
  50. package/src/core/evaluation-coverage.ts +74 -0
  51. package/src/core/event-validation.ts +81 -6
  52. package/src/core/events.ts +99 -3
  53. package/src/core/evidence-links.ts +7 -0
  54. package/src/core/evidence.ts +13 -3
  55. package/src/core/execution.ts +8 -2
  56. package/src/core/experiment.ts +133 -0
  57. package/src/core/export.ts +9 -0
  58. package/src/core/failure-recovery.ts +173 -0
  59. package/src/core/file-precondition.ts +72 -0
  60. package/src/core/handoff.ts +65 -4
  61. package/src/core/harness-diagnostics.ts +206 -0
  62. package/src/core/history-query.ts +38 -2
  63. package/src/core/history.ts +38 -1
  64. package/src/core/integration-health.ts +34 -0
  65. package/src/core/keymap.ts +8 -20
  66. package/src/core/model-picker.ts +64 -0
  67. package/src/core/native-eval.ts +25 -0
  68. package/src/core/note-guidance.ts +34 -0
  69. package/src/core/oauth-fields.ts +44 -0
  70. package/src/core/observation-view.ts +49 -8
  71. package/src/core/permissions.ts +24 -2
  72. package/src/core/process-receipt.ts +105 -0
  73. package/src/core/process-state.ts +37 -0
  74. package/src/core/program-status.ts +31 -0
  75. package/src/core/project.ts +70 -19
  76. package/src/core/prompt-policy.ts +37 -0
  77. package/src/core/query-eval-contract.ts +14 -0
  78. package/src/core/read-observation.ts +82 -0
  79. package/src/core/recovery-corpus.ts +17 -0
  80. package/src/core/recovery-evaluation.ts +60 -0
  81. package/src/core/recovery-sources.ts +74 -0
  82. package/src/core/request-progress.ts +87 -0
  83. package/src/core/request-state.ts +114 -0
  84. package/src/core/runtime-target.ts +94 -0
  85. package/src/core/search-observation.ts +97 -0
  86. package/src/core/session-tree.ts +147 -0
  87. package/src/core/settings.ts +33 -10
  88. package/src/core/skills.ts +44 -0
  89. package/src/core/sql-query.ts +211 -0
  90. package/src/core/theme.ts +36 -58
  91. package/src/core/tool-contract.ts +51 -2
  92. package/src/core/tool-discovery.ts +87 -0
  93. package/src/core/tool-failure.ts +60 -0
  94. package/src/core/tool-input.ts +6 -0
  95. package/src/core/tool-mode-protocol.ts +25 -0
  96. package/src/core/transcript.ts +19 -4
  97. package/src/core/trial-lifecycle.ts +14 -0
  98. package/src/core/tui-mode.ts +29 -0
  99. package/src/core/update-check.ts +97 -0
  100. package/src/core/version.ts +55 -0
  101. package/src/core/work-state.ts +49 -3
  102. package/src/core/working-set.ts +91 -0
  103. package/src/runtime/auth.ts +11 -4
  104. package/src/runtime/branch-jobs.ts +36 -0
  105. package/src/runtime/catalog.ts +13 -3
  106. package/src/runtime/clipboard.ts +15 -4
  107. package/src/runtime/command-artifacts.ts +64 -0
  108. package/src/runtime/control-connection.ts +104 -0
  109. package/src/runtime/environment-tools.ts +60 -0
  110. package/src/runtime/evidence-notes.ts +4 -2
  111. package/src/runtime/exec-sessions.ts +206 -61
  112. package/src/runtime/execution-control.ts +1 -0
  113. package/src/runtime/extension-ui.ts +22 -30
  114. package/src/runtime/extensions.ts +95 -16
  115. package/src/runtime/harness-comparison.ts +27 -7
  116. package/src/runtime/harness-eval.ts +462 -0
  117. package/src/runtime/history-cache.ts +57 -0
  118. package/src/runtime/history-tools.ts +62 -12
  119. package/src/runtime/integrations.ts +210 -0
  120. package/src/runtime/loop.ts +1088 -282
  121. package/src/runtime/model-discovery.ts +208 -0
  122. package/src/runtime/model.ts +9 -0
  123. package/src/runtime/native-eval-fixtures.ts +33 -0
  124. package/src/runtime/native-eval.ts +146 -0
  125. package/src/runtime/oauth.ts +80 -3
  126. package/src/runtime/pi-provider.ts +169 -12
  127. package/src/runtime/program-status.ts +38 -0
  128. package/src/runtime/provider-connect.ts +109 -0
  129. package/src/runtime/provider-presets.ts +87 -0
  130. package/src/runtime/provider-request.ts +13 -2
  131. package/src/runtime/provider.ts +23 -9
  132. package/src/runtime/query-eval-verifier.ts +28 -0
  133. package/src/runtime/recovery-coverage.ts +71 -0
  134. package/src/runtime/recovery-evidence.ts +76 -0
  135. package/src/runtime/recovery-fixtures.ts +116 -0
  136. package/src/runtime/runtime-target.ts +149 -0
  137. package/src/runtime/session-control.ts +198 -0
  138. package/src/runtime/tool-broker.ts +137 -0
  139. package/src/runtime/tool-discovery.ts +57 -0
  140. package/src/runtime/tool-mode-eval.ts +146 -0
  141. package/src/runtime/tool-queue.ts +77 -0
  142. package/src/runtime/tools.ts +628 -183
  143. package/src/runtime/trial-control.ts +45 -0
  144. package/src/runtime/update-check.ts +47 -0
  145. package/src/runtime/window-trial.ts +2 -1
  146. package/src/runtime/working-notes.ts +33 -3
  147. package/src/runtime/workspace-lifecycle.ts +97 -0
  148. package/src/store/acceptance.ts +15 -0
  149. package/src/store/checkpoint-history.ts +43 -0
  150. package/src/store/command-artifacts.ts +96 -0
  151. package/src/store/command.ts +65 -37
  152. package/src/store/file-checkpoints.ts +104 -0
  153. package/src/store/file-index.ts +13 -1
  154. package/src/store/git-checkpoints.ts +67 -0
  155. package/src/store/observations.ts +61 -20
  156. package/src/store/process-receipts.ts +34 -0
  157. package/src/store/query-source.ts +13 -8
  158. package/src/store/recovery.ts +2 -3
  159. package/src/store/replay.ts +16 -4
  160. package/src/store/runtime-target.ts +64 -0
  161. package/src/store/search.ts +171 -132
  162. package/src/store/session-archive.ts +4 -0
  163. package/src/store/source-cancellation.ts +6 -0
  164. package/src/store/update-cache.ts +36 -0
  165. package/src/store/workspace-observation.ts +113 -0
  166. package/src/tui/ansi-spans.ts +126 -0
  167. package/src/tui/style.ts +19 -16
  168. package/src/tui/ui/atomic-draft.ts +121 -0
  169. package/src/tui/ui/canvas.ts +96 -0
  170. package/src/tui/ui/colors.ts +70 -0
  171. package/src/tui/ui/composer.ts +200 -0
  172. package/src/tui/ui/control-panel.ts +23 -0
  173. package/src/tui/ui/dialog.ts +379 -0
  174. package/src/tui/ui/draft.ts +23 -0
  175. package/src/tui/ui/edge.ts +186 -0
  176. package/src/tui/ui/image-size.ts +40 -0
  177. package/src/tui/ui/ink.ts +210 -0
  178. package/src/tui/ui/items.ts +40 -0
  179. package/src/tui/ui/keys.ts +40 -0
  180. package/src/tui/ui/layout.ts +74 -0
  181. package/src/tui/ui/list-model.ts +86 -0
  182. package/src/tui/ui/list-view.ts +172 -0
  183. package/src/tui/ui/mascot.ts +67 -0
  184. package/src/tui/ui/messages.ts +518 -0
  185. package/src/tui/ui/motion.ts +28 -0
  186. package/src/tui/ui/paths.ts +10 -0
  187. package/src/tui/ui/pictures.ts +78 -0
  188. package/src/tui/ui/screen.ts +421 -0
  189. package/src/tui/ui/status.ts +279 -0
  190. package/src/tui/ui/styled.ts +85 -0
  191. package/src/tui/ui/testing.ts +5 -0
  192. package/src/tui/ui/tool-card.ts +150 -0
  193. package/src/apps/extension-ui.ts +0 -330
  194. package/src/apps/resource-browser.ts +0 -75
  195. package/src/apps/session-browser.ts +0 -113
  196. package/src/apps/session-picker.ts +0 -55
  197. package/src/tui/ansi.ts +0 -67
  198. package/src/tui/autocomplete.ts +0 -29
  199. package/src/tui/chat-viewport.ts +0 -47
  200. package/src/tui/complete.ts +0 -87
  201. package/src/tui/editor.ts +0 -940
  202. package/src/tui/host.ts +0 -264
  203. package/src/tui/input.ts +0 -75
  204. package/src/tui/keys.ts +0 -378
  205. package/src/tui/markdown.ts +0 -17
  206. package/src/tui/render.ts +0 -153
  207. package/src/tui/select.ts +0 -258
  208. package/src/tui/settings.ts +0 -44
  209. package/src/tui/statusline.ts +0 -162
  210. package/src/tui/system-theme.ts +0 -700
  211. package/src/tui/terminal.ts +0 -30
  212. package/src/tui/text.ts +0 -52
  213. package/src/tui/toolview.ts +0 -386
  214. package/src/tui/transcript.ts +0 -123
  215. package/src/tui/tree.ts +0 -471
  216. package/src/vendor/pi-tui/LICENSE.upstream +0 -21
  217. package/src/vendor/pi-tui/UPSTREAM.json +0 -50
  218. package/src/vendor/pi-tui/VENDOR.md +0 -25
  219. package/src/vendor/pi-tui/alt-screen-search.ts +0 -327
  220. package/src/vendor/pi-tui/autocomplete.ts +0 -860
  221. package/src/vendor/pi-tui/colors.ts +0 -367
  222. package/src/vendor/pi-tui/components/alt-screen-flash.ts +0 -51
  223. package/src/vendor/pi-tui/components/box.ts +0 -166
  224. package/src/vendor/pi-tui/components/cancellable-loader.ts +0 -40
  225. package/src/vendor/pi-tui/components/editor.ts +0 -2472
  226. package/src/vendor/pi-tui/components/h-stack.ts +0 -44
  227. package/src/vendor/pi-tui/components/image.ts +0 -127
  228. package/src/vendor/pi-tui/components/input.ts +0 -494
  229. package/src/vendor/pi-tui/components/loader.ts +0 -101
  230. package/src/vendor/pi-tui/components/markdown.ts +0 -1021
  231. package/src/vendor/pi-tui/components/mouse-region.ts +0 -33
  232. package/src/vendor/pi-tui/components/scroll-view.ts +0 -224
  233. package/src/vendor/pi-tui/components/select-list.ts +0 -273
  234. package/src/vendor/pi-tui/components/settings-list.ts +0 -328
  235. package/src/vendor/pi-tui/components/spacer.ts +0 -28
  236. package/src/vendor/pi-tui/components/stack.ts +0 -154
  237. package/src/vendor/pi-tui/components/text.ts +0 -107
  238. package/src/vendor/pi-tui/components/truncated-text.ts +0 -65
  239. package/src/vendor/pi-tui/components/v-stack.ts +0 -33
  240. package/src/vendor/pi-tui/editor-component.ts +0 -74
  241. package/src/vendor/pi-tui/fuzzy.ts +0 -138
  242. package/src/vendor/pi-tui/index.ts +0 -186
  243. package/src/vendor/pi-tui/keybindings.ts +0 -320
  244. package/src/vendor/pi-tui/keys.ts +0 -1401
  245. package/src/vendor/pi-tui/kill-ring.ts +0 -46
  246. package/src/vendor/pi-tui/latex.ts +0 -1506
  247. package/src/vendor/pi-tui/layout-node.ts +0 -51
  248. package/src/vendor/pi-tui/layout.ts +0 -449
  249. package/src/vendor/pi-tui/native/UPSTREAM.json +0 -23
  250. package/src/vendor/pi-tui/native/clipboard.h +0 -208
  251. package/src/vendor/pi-tui/native/darwin/README.md +0 -22
  252. package/src/vendor/pi-tui/native/darwin/build.sh +0 -69
  253. package/src/vendor/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
  254. package/src/vendor/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
  255. package/src/vendor/pi-tui/native/darwin/src/darwin-platform.m +0 -132
  256. package/src/vendor/pi-tui/native/linux/README.md +0 -23
  257. package/src/vendor/pi-tui/native/linux/build.sh +0 -65
  258. package/src/vendor/pi-tui/native/linux/prebuilds/linux-arm64/linux-platform-x11.node +0 -0
  259. package/src/vendor/pi-tui/native/linux/prebuilds/linux-x64/linux-platform-x11.node +0 -0
  260. package/src/vendor/pi-tui/native/linux/src/clipboard-worker.h +0 -70
  261. package/src/vendor/pi-tui/native/linux/src/linux-platform-x11.c +0 -274
  262. package/src/vendor/pi-tui/native/napi.h +0 -91
  263. package/src/vendor/pi-tui/native/win32/README.md +0 -31
  264. package/src/vendor/pi-tui/native/win32/build.mjs +0 -232
  265. package/src/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
  266. package/src/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
  267. package/src/vendor/pi-tui/native/win32/src/win32-platform.c +0 -241
  268. package/src/vendor/pi-tui/native-modifiers.ts +0 -13
  269. package/src/vendor/pi-tui/native-module-path.ts +0 -31
  270. package/src/vendor/pi-tui/native-platform.ts +0 -65
  271. package/src/vendor/pi-tui/oklab.ts +0 -233
  272. package/src/vendor/pi-tui/stdin-buffer.ts +0 -444
  273. package/src/vendor/pi-tui/terminal-colors.ts +0 -91
  274. package/src/vendor/pi-tui/terminal-image.ts +0 -731
  275. package/src/vendor/pi-tui/terminal.ts +0 -554
  276. package/src/vendor/pi-tui/tui-alt-screen.ts +0 -1750
  277. package/src/vendor/pi-tui/tui-main-screen.ts +0 -655
  278. package/src/vendor/pi-tui/tui.ts +0 -1493
  279. package/src/vendor/pi-tui/undo-stack.ts +0 -28
  280. package/src/vendor/pi-tui/utils.ts +0 -1385
  281. package/src/vendor/pi-tui/wheel-scroll.ts +0 -82
  282. package/src/vendor/pi-tui/word-navigation.ts +0 -117
package/src/tui/host.ts DELETED
@@ -1,264 +0,0 @@
1
- /**
2
- * Adapter between xeno's tiny Terminal (columns/rows/write) and pi's TUI.
3
- *
4
- * Vendor is copied unmodified (D19). Anything we need to change — a stub
5
- * terminal for tests, thinking-coloured editor borders, wrapping a string[]
6
- * as a Component — lives here so the next recopy does not wipe it.
7
- */
8
- import type { Terminal as SimpleTerminal } from "./terminal.ts";
9
- import type { Style } from "./style.ts";
10
- import { IDENTITY, PLAIN_ATTRS, paint, type Attrs } from "./style.ts";
11
- import {
12
- Container,
13
- Markdown,
14
- ProcessTerminal,
15
- Text as PiText,
16
- type Component,
17
- type DefaultTextStyle,
18
- type EditorTheme,
19
- type MarkdownTheme,
20
- type SelectListTheme,
21
- type Terminal,
22
- type TUI,
23
- TuiMainScreen,
24
- TuiAltScreen,
25
- stripTerminalSequences,
26
- } from "../vendor/pi-tui/index.ts";
27
-
28
- export { Container, Markdown, PiText };
29
- export type { TuiMainScreen };
30
- /** A single document inset keeps committed and streaming messages aligned. */
31
- export class PaddedDocument extends Container {
32
- padding = 1;
33
- override render(width: number): string[] {
34
- const padding = Math.min(this.padding, Math.max(0, Math.floor((width - 1) / 2)));
35
- return super.render(Math.max(1, width - padding * 2)).map(line => line.startsWith("\x1b]133;A\x07")
36
- ? "\x1b]133;A\x07" + " ".repeat(padding) + line.slice(8) : " ".repeat(padding) + line);
37
- }
38
- }
39
- export type InteractiveScreen = TuiMainScreen | TuiAltScreen;
40
- export interface ScreenOptions {
41
- tuiMode?: "regular" | "fullscreen";
42
- fullscreenCopyOnSelect?: boolean;
43
- fullscreenWheelScrollLines?: "auto" | number;
44
- copySelection?: (text: string) => Promise<boolean | string>;
45
- }
46
-
47
- /**
48
- * Wraps the injectible {columns, rows, write} terminal tests already use.
49
- * Tests inject a silent terminal; the application uses ProcessTerminal.
50
- */
51
- export class AdapterTerminal implements Terminal {
52
- private readonly inner: SimpleTerminal;
53
- constructor(inner: SimpleTerminal) {
54
- this.inner = inner;
55
- }
56
-
57
- start(_onInput: (data: string) => void, _onResize: () => void): void {}
58
- stop(): void {}
59
- async drainInput(_maxMs?: number, _idleMs?: number): Promise<void> {}
60
- write(data: string): void {
61
- this.inner.write(data);
62
- }
63
- get columns(): number {
64
- return this.inner.columns;
65
- }
66
- get rows(): number {
67
- return this.inner.rows;
68
- }
69
- get kittyProtocolActive(): boolean {
70
- return false;
71
- }
72
- moveBy(lines: number): void {
73
- if (lines < 0) this.write(`\x1b[${-lines}A`);
74
- else if (lines > 0) this.write(`\x1b[${lines}B`);
75
- }
76
- hideCursor(): void {
77
- this.write("\x1b[?25l");
78
- }
79
- showCursor(): void {
80
- this.write("\x1b[?25h");
81
- }
82
- clearLine(): void {
83
- this.write("\x1b[2K");
84
- }
85
- clearFromCursor(): void {
86
- this.write("\x1b[J");
87
- }
88
- clearScreen(): void {
89
- this.write("\x1b[2J\x1b[H");
90
- }
91
- setTitle(_title: string): void {}
92
- setProgress(_active: boolean): void {}
93
- }
94
-
95
- /** TuiMainScreen without ProcessTerminal — tests inject a FakeTerminal. */
96
- export function createInteractiveTui(term?: SimpleTerminal, showHardwareCursor = true, options: ScreenOptions = {}): InteractiveScreen {
97
- return screenFor(term ? new AdapterTerminal(term) : new ProcessTerminal(), showHardwareCursor, options);
98
- }
99
-
100
- export function replaceInteractiveTui(previous: InteractiveScreen, options: ScreenOptions): InteractiveScreen {
101
- return screenFor(previous.terminal, previous.getShowHardwareCursor(), options);
102
- }
103
-
104
- function screenFor(terminal: Terminal, cursor: boolean, options: ScreenOptions): InteractiveScreen {
105
- return options.tuiMode === "fullscreen" ? new TuiAltScreen(terminal, cursor, undefined, {
106
- wheelScrollLines: options.fullscreenWheelScrollLines ?? "auto", copyOnSelect: options.fullscreenCopyOnSelect ?? true,
107
- ...(options.copySelection ? { copySelection: options.copySelection } : {}), scrollToEndIndicator: () => "↓ Latest",
108
- }) : new TuiMainScreen(terminal, cursor);
109
- }
110
-
111
- /**
112
- * Vendor Editor.render only reads tui.terminal.rows. A full TuiMainScreen
113
- * would write on construct; a silent stub keeps `new Editor().render()` a
114
- * unit test.
115
- */
116
- export function stubTui(rows = 24, columns = 80): TUI {
117
- return new TuiMainScreen(new AdapterTerminal({ columns, rows, write() {} }), false);
118
- }
119
-
120
- export function identitySelectListTheme(): SelectListTheme {
121
- return {
122
- selectedPrefix: (text) => text,
123
- selectedText: (text) => text,
124
- description: (text) => text,
125
- scrollInfo: (text) => text,
126
- noMatch: (text) => text,
127
- };
128
- }
129
-
130
- export function identityEditorTheme(): EditorTheme {
131
- return {
132
- borderColor: (text) => text,
133
- selectList: identitySelectListTheme(),
134
- };
135
- }
136
-
137
- /**
138
- * Border colour follows the thinking level, which is pi's cue that the
139
- * next turn will spend a different budget. Uncoloured when the style
140
- * emits no SGR (IDENTITY / NO_COLOR) so a pipe cannot pick up CSI.
141
- */
142
- export function thinkingBorderColor(level: string, colored: boolean, style?: Style): (s: string) => string {
143
- if (!colored) return (s) => s;
144
- if (style?.token) return (s) => style.token!(`thinking${level[0]?.toUpperCase()}${level.slice(1)}`, s);
145
- const code =
146
- level === "max" || level === "xhigh" ? "35" :
147
- level === "high" ? "33" :
148
- level === "medium" ? "36" :
149
- level === "low" ? "32" :
150
- "90";
151
- return (s) => `\x1b[${code}m${s}\x1b[0m`;
152
- }
153
-
154
- function wrapAttr(style: Style, attrs: Attrs): (text: string) => string {
155
- return (text) => paint(text, attrs, style);
156
- }
157
-
158
- export function defaultTextStyleFrom(style: Style): DefaultTextStyle {
159
- return { color: (text) => paint(text, PLAIN_ATTRS, style) };
160
- }
161
-
162
- /**
163
- * Vendor Markdown may emit OSC 8 even when the theme is identity. IDENTITY
164
- * is the -p / NO_COLOR gate: those bytes must not leak into a pipe.
165
- */
166
- export function renderMarkdownLines(text: string, width: number, style: Style): string[] {
167
- const md = new Markdown(text, 0, 0, markdownThemeFromStyle(style), defaultTextStyleFrom(style));
168
- const lines = md.render(Math.max(0, width));
169
- // Vendor pads every row to `width` for backgrounds we do not use. Trailing
170
- // spaces would change tool-view snapshots and a pipe's visible payload.
171
- const trimmed = lines.map((line) => line.replace(/[ \t]+$/, ""));
172
- return style === IDENTITY ? trimmed.map(stripTerminalSequences) : trimmed;
173
- }
174
-
175
- /** Activity-area assistant text: pi's Markdown, themed from our Style. */
176
- export function assistantMarkdown(text: string, style: Style, features?: MarkdownFeatures): Component {
177
- return new MarkdownBlock(text, style, features);
178
- }
179
-
180
- export interface MarkdownFeatures {
181
- highlight: (code: string, language: string | undefined, style: Style) => string[];
182
- transform: (text: string, width: number, streaming: boolean, style: Style, messageType?: "user" | "assistant" | "assistant-thinking") => string;
183
- }
184
-
185
- /** Keep Pi's parse/layout cache alive across keystrokes and streaming deltas. */
186
- export class MarkdownBlock implements Component {
187
- private readonly markdown: Markdown;
188
- private readonly style: Style;
189
- private text: string;
190
- private readonly features: MarkdownFeatures | undefined;
191
- private readonly streaming: boolean;
192
- private renderedText: string | undefined;
193
- constructor(text: string, style: Style, features?: MarkdownFeatures, streaming = false) {
194
- this.text = text;
195
- this.style = style;
196
- this.features = features; this.streaming = streaming;
197
- this.markdown = new Markdown(text, 0, 0, { ...markdownThemeFromStyle(style),
198
- ...(features && style !== IDENTITY ? { highlightCode: (code: string, lang?: string) => features.highlight(code, lang, style) } : {}),
199
- }, defaultTextStyleFrom(style));
200
- }
201
- setText(text: string): void {
202
- if (text === this.text) return;
203
- this.text = text;
204
- this.renderedText = undefined;
205
- }
206
- invalidate(): void { this.markdown.invalidate(); }
207
- render(width: number): string[] {
208
- if (width <= 0) return [""];
209
- const transformed = this.features?.transform(this.text, width, this.streaming, this.style) ?? this.text;
210
- if (this.renderedText !== transformed) { this.markdown.setText(transformed); this.renderedText = transformed; }
211
- const lines = this.markdown.render(Math.max(1, width)).map((line) => line.trimEnd());
212
- return this.style === IDENTITY ? lines.map(stripTerminalSequences) : lines;
213
- }
214
- }
215
-
216
- export function markdownThemeFromStyle(style: Style): MarkdownTheme {
217
- const plain = style.open(PLAIN_ATTRS) === "" && style === IDENTITY;
218
- if (plain) {
219
- return {
220
- heading: (t) => t,
221
- link: (t) => t,
222
- linkUrl: (t) => t,
223
- code: (t) => t,
224
- codeBlock: (t) => t,
225
- codeBlockBorder: (t) => t,
226
- quote: (t) => t,
227
- quoteBorder: (t) => t,
228
- hr: (t) => t,
229
- listBullet: (t) => t,
230
- bold: (t) => t,
231
- italic: (t) => t,
232
- strikethrough: (t) => t,
233
- underline: (t) => t,
234
- };
235
- }
236
- return {
237
- heading: wrapAttr(style, { ...PLAIN_ATTRS, heading: true, bold: true }),
238
- link: wrapAttr(style, { ...PLAIN_ATTRS, link: true }),
239
- linkUrl: wrapAttr(style, { ...PLAIN_ATTRS, link: true, dim: true }),
240
- code: wrapAttr(style, { ...PLAIN_ATTRS, code: true }),
241
- codeBlock: wrapAttr(style, { ...PLAIN_ATTRS, code: true }),
242
- codeBlockBorder: wrapAttr(style, { ...PLAIN_ATTRS, dim: true }),
243
- quote: wrapAttr(style, { ...PLAIN_ATTRS, dim: true }),
244
- quoteBorder: wrapAttr(style, { ...PLAIN_ATTRS, dim: true }),
245
- hr: wrapAttr(style, { ...PLAIN_ATTRS, dim: true }),
246
- listBullet: wrapAttr(style, { ...PLAIN_ATTRS, dim: true }),
247
- bold: wrapAttr(style, { ...PLAIN_ATTRS, bold: true }),
248
- italic: wrapAttr(style, { ...PLAIN_ATTRS, italic: true }),
249
- strikethrough: (t) => `\x1b[9m${t}\x1b[29m`,
250
- underline: (t) => `\x1b[4m${t}\x1b[24m`,
251
- };
252
- }
253
-
254
- /** Lift a render(width) → string[] into pi's Component (needs invalidate). */
255
- export class Lines implements Component {
256
- private readonly paint: (width: number) => string[];
257
- constructor(paint: (width: number) => string[]) {
258
- this.paint = paint;
259
- }
260
- invalidate(): void {}
261
- render(width: number): string[] {
262
- return this.paint(width);
263
- }
264
- }
package/src/tui/input.ts DELETED
@@ -1,75 +0,0 @@
1
- /** Pi owns decoding. Encoding exists only for programmatic actions and legacy tests. */
2
- import { KeybindingsManager, TUI_KEYBINDINGS, setKeybindings, type KeybindingsConfig } from "../vendor/pi-tui/keybindings.ts";
3
- import { matchesKey, parseKey, type KeyId } from "../vendor/pi-tui/keys.ts";
4
- import { formatTuiKey, type Key } from "./keys.ts";
5
-
6
- export function keyMatches(data: string, chord: string): boolean {
7
- return matchesKey(data, chord.replace("pageup", "pageUp").replace("pagedown", "pageDown") as KeyId);
8
- }
9
-
10
- export function inputKey(data: string): Key | null {
11
- const parsed = parseKey(data);
12
- if (parsed === undefined) return data.startsWith("\x1b") ? null : { type: "char", grapheme: data };
13
- const parts = parsed.toLowerCase().split("+");
14
- const name = parts.pop()!;
15
- const mods = { ctrl: parts.includes("ctrl"), alt: parts.includes("alt"), shift: parts.includes("shift") };
16
- switch (name) {
17
- case "enter": return mods.alt ? { type: "alt", key: "\r" } : { type: "enter", shift: mods.shift };
18
- case "tab": return { type: "tab", shift: mods.shift };
19
- case "escape": return { type: "escape" };
20
- case "backspace": if (!mods.alt && !mods.ctrl) return { type: "backspace" }; break;
21
- case "up": case "down": case "left": case "right": case "home": case "end":
22
- case "delete": case "pageup": case "pagedown": return { type: name, mods };
23
- }
24
- if (mods.ctrl) return { type: "ctrl", key: name, shift: mods.shift };
25
- if (mods.alt) return { type: "alt", key: name };
26
- return { type: "char", grapheme: data };
27
- }
28
-
29
- export function encodeKey(key: Key): string {
30
- if (key.type === "char") return key.grapheme;
31
- return encodeChord(formatTuiKey(key));
32
- }
33
-
34
- export function encodeChord(chord: string): string {
35
- const parts = chord.split("+");
36
- const name = parts.pop()!;
37
- const ctrl = parts.includes("ctrl");
38
- const alt = parts.includes("alt");
39
- const shift = parts.includes("shift");
40
- const modifier = 1 + (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0);
41
- const arrow: Record<string, string> = { up: "A", down: "B", right: "C", left: "D", home: "H", end: "F" };
42
- const suffix = arrow[name];
43
- if (suffix) return modifier === 1 ? `\x1b[${suffix}` : `\x1b[1;${modifier}${suffix}`;
44
- if (name === "escape") return "\x1b";
45
- if (name === "tab") return shift ? "\x1b[Z" : "\t";
46
- if (name === "backspace") return `${alt ? "\x1b" : ""}\x7f`;
47
- const code = name === "enter" ? 13 : name === "space" ? 32 : name.codePointAt(0)!;
48
- if (name === "delete" || name === "pageup" || name === "pagedown") {
49
- const num = name === "delete" ? 3 : name === "pageup" ? 5 : 6;
50
- return `\x1b[${num}${modifier === 1 ? "" : `;${modifier}`}~`;
51
- }
52
- if (shift || (ctrl && alt)) return `\x1b[${code};${modifier}u`;
53
- if (ctrl) return String.fromCharCode(code & 31);
54
- return `${alt ? "\x1b" : ""}${String.fromCodePoint(code)}`;
55
- }
56
-
57
- const INPUT_ACTIONS: Record<string, string> = {
58
- "editor.submit": "tui.input.submit", "editor.newLine": "tui.input.newLine", "editor.complete": "tui.input.tab",
59
- };
60
-
61
- /** Translate existing settings names once, without translating terminal bytes. */
62
- export function editorBindings(byAction: Readonly<Record<string, readonly string[]>>): KeybindingsManager {
63
- const config: KeybindingsConfig = {};
64
- for (const [action, chords] of Object.entries(byAction)) {
65
- const id = action.startsWith("tui.") ? action : INPUT_ACTIONS[action] ?? `tui.${action}`;
66
- if (id in TUI_KEYBINDINGS) config[id] = [...chords] as KeyId[];
67
- }
68
- return new KeybindingsManager(TUI_KEYBINDINGS, config);
69
- }
70
-
71
- export function installBindings(byAction: Readonly<Record<string, readonly string[]>>): KeybindingsManager {
72
- const manager = editorBindings(byAction);
73
- setKeybindings(manager);
74
- return manager;
75
- }