@visual-z/xeno 0.8.3 → 0.9.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 (348) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +31 -746
  3. package/bin/xeno.exe +26 -0
  4. package/install.cjs +88 -0
  5. package/package.json +18 -48
  6. package/docs/app-server.md +0 -115
  7. package/docs/foundations.md +0 -88
  8. package/docs/install.md +0 -244
  9. package/docs/providers.md +0 -172
  10. package/docs/research/foundation-clients-2026-10-09.md +0 -27
  11. package/docs/research/foundation-editing-2026-10-09.md +0 -56
  12. package/docs/research/foundation-network-2026-10-09.md +0 -37
  13. package/docs/research/foundation-workflow-2026-10-09.md +0 -37
  14. package/src/apps/acp-server.ts +0 -41
  15. package/src/apps/agent-profiles.ts +0 -19
  16. package/src/apps/app-server.ts +0 -30
  17. package/src/apps/approve.ts +0 -49
  18. package/src/apps/cli.ts +0 -99
  19. package/src/apps/commands.ts +0 -319
  20. package/src/apps/completions.ts +0 -87
  21. package/src/apps/control-transport.ts +0 -90
  22. package/src/apps/export-cli.ts +0 -24
  23. package/src/apps/goal-flow.ts +0 -70
  24. package/src/apps/image-draft.ts +0 -46
  25. package/src/apps/input.ts +0 -312
  26. package/src/apps/model-catalog.ts +0 -69
  27. package/src/apps/preferences.ts +0 -20
  28. package/src/apps/project-trust.ts +0 -9
  29. package/src/apps/provider-connect.ts +0 -346
  30. package/src/apps/question-ui.ts +0 -27
  31. package/src/apps/render.ts +0 -181
  32. package/src/apps/resources.ts +0 -66
  33. package/src/apps/review.ts +0 -109
  34. package/src/apps/session-hub.ts +0 -96
  35. package/src/apps/session-lifecycle.ts +0 -64
  36. package/src/apps/shell.ts +0 -2066
  37. package/src/apps/startup-input.ts +0 -135
  38. package/src/apps/startup.ts +0 -1677
  39. package/src/apps/ui/app.ts +0 -1713
  40. package/src/apps/ui/control-model.ts +0 -43
  41. package/src/apps/ui/extension-host.ts +0 -194
  42. package/src/apps/ui/image-cache.ts +0 -121
  43. package/src/apps/ui/palette.ts +0 -88
  44. package/src/apps/ui/project.ts +0 -127
  45. package/src/apps/ui/standalone.ts +0 -148
  46. package/src/apps/ui/status-model.ts +0 -68
  47. package/src/apps/ui/surface.ts +0 -91
  48. package/src/apps/ui/theme.ts +0 -86
  49. package/src/apps/update-check.ts +0 -112
  50. package/src/apps/workflow.ts +0 -58
  51. package/src/core/acceptance.ts +0 -139
  52. package/src/core/action-defaults.ts +0 -58
  53. package/src/core/activity-status.ts +0 -52
  54. package/src/core/agent-profile.ts +0 -130
  55. package/src/core/attachment-input.ts +0 -17
  56. package/src/core/blind-checks.ts +0 -72
  57. package/src/core/boundary.ts +0 -174
  58. package/src/core/branch-receipt.ts +0 -26
  59. package/src/core/catalog-merge.ts +0 -19
  60. package/src/core/checkpoints.ts +0 -85
  61. package/src/core/churn.ts +0 -61
  62. package/src/core/command-artifacts.ts +0 -94
  63. package/src/core/command-contract.ts +0 -151
  64. package/src/core/completion-action.ts +0 -20
  65. package/src/core/completion-review.ts +0 -98
  66. package/src/core/context-detail.ts +0 -37
  67. package/src/core/context-policy.ts +0 -133
  68. package/src/core/context-window.ts +0 -54
  69. package/src/core/continuation.ts +0 -130
  70. package/src/core/control-protocol.ts +0 -69
  71. package/src/core/control-view.ts +0 -39
  72. package/src/core/cycle.ts +0 -17
  73. package/src/core/data-query.ts +0 -201
  74. package/src/core/deadline.ts +0 -40
  75. package/src/core/derive.ts +0 -516
  76. package/src/core/draft-images.ts +0 -56
  77. package/src/core/edit-plan.ts +0 -200
  78. package/src/core/environment.ts +0 -181
  79. package/src/core/event-validation.ts +0 -220
  80. package/src/core/events.ts +0 -670
  81. package/src/core/evidence-ladder.ts +0 -62
  82. package/src/core/evidence-links.ts +0 -68
  83. package/src/core/evidence.ts +0 -240
  84. package/src/core/execution.ts +0 -18
  85. package/src/core/exhaustive.ts +0 -18
  86. package/src/core/export.ts +0 -179
  87. package/src/core/extension-flags.ts +0 -14
  88. package/src/core/external-effects.ts +0 -488
  89. package/src/core/failure-recovery.ts +0 -173
  90. package/src/core/file-precondition.ts +0 -78
  91. package/src/core/file-references.ts +0 -35
  92. package/src/core/frontmatter.ts +0 -213
  93. package/src/core/git-status.ts +0 -29
  94. package/src/core/goal-view.ts +0 -64
  95. package/src/core/goal.ts +0 -200
  96. package/src/core/handoff.ts +0 -479
  97. package/src/core/history-query.ts +0 -139
  98. package/src/core/history.ts +0 -237
  99. package/src/core/image-limits.ts +0 -72
  100. package/src/core/images.ts +0 -46
  101. package/src/core/integration-health.ts +0 -34
  102. package/src/core/json-event.ts +0 -131
  103. package/src/core/json-pointer.ts +0 -46
  104. package/src/core/keymap.ts +0 -153
  105. package/src/core/lsp-framing.ts +0 -34
  106. package/src/core/mcp-config.ts +0 -68
  107. package/src/core/model-picker.ts +0 -64
  108. package/src/core/model-preferences.ts +0 -28
  109. package/src/core/model-replay.ts +0 -22
  110. package/src/core/model-scope.ts +0 -53
  111. package/src/core/note-guidance.ts +0 -34
  112. package/src/core/oauth-fields.ts +0 -44
  113. package/src/core/observation-view.ts +0 -152
  114. package/src/core/outcome.ts +0 -44
  115. package/src/core/overflow.ts +0 -59
  116. package/src/core/packages.ts +0 -47
  117. package/src/core/patch.ts +0 -130
  118. package/src/core/path-suggestions.ts +0 -59
  119. package/src/core/permissions.ts +0 -410
  120. package/src/core/process-receipt.ts +0 -105
  121. package/src/core/process-state.ts +0 -37
  122. package/src/core/program-status.ts +0 -40
  123. package/src/core/progress.ts +0 -150
  124. package/src/core/project.ts +0 -431
  125. package/src/core/prompt-policy.ts +0 -46
  126. package/src/core/prompts.ts +0 -111
  127. package/src/core/question.ts +0 -94
  128. package/src/core/queue.ts +0 -78
  129. package/src/core/read-bounds.ts +0 -24
  130. package/src/core/read-observation.ts +0 -106
  131. package/src/core/recovery-sources.ts +0 -74
  132. package/src/core/regex-dialect.ts +0 -25
  133. package/src/core/request-budget.ts +0 -23
  134. package/src/core/request-progress.ts +0 -87
  135. package/src/core/request-state.ts +0 -273
  136. package/src/core/resource-selection.ts +0 -36
  137. package/src/core/response-recovery.ts +0 -59
  138. package/src/core/resume.ts +0 -59
  139. package/src/core/review.ts +0 -68
  140. package/src/core/ripgrep-release.ts +0 -64
  141. package/src/core/runtime-target.ts +0 -94
  142. package/src/core/scheduling.ts +0 -8
  143. package/src/core/search-observation.ts +0 -97
  144. package/src/core/secrets.ts +0 -188
  145. package/src/core/session-archive.ts +0 -4
  146. package/src/core/session-browser.ts +0 -82
  147. package/src/core/session-entry.ts +0 -61
  148. package/src/core/session-exit.ts +0 -42
  149. package/src/core/session-format.ts +0 -169
  150. package/src/core/session-position.ts +0 -26
  151. package/src/core/session-tree.ts +0 -147
  152. package/src/core/settings.ts +0 -192
  153. package/src/core/skills.ts +0 -165
  154. package/src/core/sql-query.ts +0 -211
  155. package/src/core/stall.ts +0 -128
  156. package/src/core/stop-report.ts +0 -68
  157. package/src/core/text-normalize.ts +0 -81
  158. package/src/core/theme.ts +0 -166
  159. package/src/core/thinking.ts +0 -26
  160. package/src/core/tokens.ts +0 -151
  161. package/src/core/tool-contract.ts +0 -153
  162. package/src/core/tool-discovery.ts +0 -87
  163. package/src/core/tool-failure.ts +0 -81
  164. package/src/core/tool-input.ts +0 -44
  165. package/src/core/transcript.ts +0 -108
  166. package/src/core/tui-mode.ts +0 -29
  167. package/src/core/update-check.ts +0 -157
  168. package/src/core/version.ts +0 -55
  169. package/src/core/web-content.ts +0 -80
  170. package/src/core/work-state.ts +0 -154
  171. package/src/core/workflow-mode.ts +0 -34
  172. package/src/core/working-set.ts +0 -119
  173. package/src/core/yaml.ts +0 -282
  174. package/src/runtime/acp-agent.ts +0 -289
  175. package/src/runtime/agent-profiles.ts +0 -21
  176. package/src/runtime/auth.ts +0 -367
  177. package/src/runtime/blind-check.ts +0 -36
  178. package/src/runtime/branch-jobs.ts +0 -36
  179. package/src/runtime/catalog.ts +0 -285
  180. package/src/runtime/clipboard.ts +0 -125
  181. package/src/runtime/command-artifacts.ts +0 -64
  182. package/src/runtime/connection-reuse.ts +0 -40
  183. package/src/runtime/control-client.ts +0 -149
  184. package/src/runtime/control-connection.ts +0 -139
  185. package/src/runtime/counter-check.ts +0 -74
  186. package/src/runtime/environment-tools.ts +0 -60
  187. package/src/runtime/evidence-notes.ts +0 -35
  188. package/src/runtime/exec-sessions.ts +0 -456
  189. package/src/runtime/execution-control.ts +0 -40
  190. package/src/runtime/extension-loader.ts +0 -37
  191. package/src/runtime/extension-ui.ts +0 -47
  192. package/src/runtime/extensions.ts +0 -370
  193. package/src/runtime/formatter-tool.ts +0 -38
  194. package/src/runtime/formatter.ts +0 -50
  195. package/src/runtime/foundation.ts +0 -116
  196. package/src/runtime/history-cache.ts +0 -57
  197. package/src/runtime/history-tools.ts +0 -168
  198. package/src/runtime/images.ts +0 -80
  199. package/src/runtime/integrations.ts +0 -216
  200. package/src/runtime/loop.ts +0 -3001
  201. package/src/runtime/lsp-client.ts +0 -201
  202. package/src/runtime/mcp-client.ts +0 -264
  203. package/src/runtime/mcp-oauth.ts +0 -168
  204. package/src/runtime/mcp-schema.ts +0 -51
  205. package/src/runtime/model-config.ts +0 -232
  206. package/src/runtime/model-data.LICENSE +0 -27
  207. package/src/runtime/model-data.ts +0 -21
  208. package/src/runtime/model-discovery.ts +0 -208
  209. package/src/runtime/model-replay.ts +0 -10
  210. package/src/runtime/model-scope.ts +0 -20
  211. package/src/runtime/model-sources.ts +0 -151
  212. package/src/runtime/model.ts +0 -686
  213. package/src/runtime/models-fetch.ts +0 -57
  214. package/src/runtime/oauth-device.ts +0 -86
  215. package/src/runtime/oauth.ts +0 -853
  216. package/src/runtime/open-image.ts +0 -42
  217. package/src/runtime/openai-responses.ts +0 -304
  218. package/src/runtime/openai.ts +0 -697
  219. package/src/runtime/output-schema.ts +0 -26
  220. package/src/runtime/package-manager.ts +0 -125
  221. package/src/runtime/patch-tool.ts +0 -38
  222. package/src/runtime/permission-resources.ts +0 -18
  223. package/src/runtime/pi-provider.ts +0 -423
  224. package/src/runtime/program-status.ts +0 -38
  225. package/src/runtime/progress.ts +0 -26
  226. package/src/runtime/provider-access.ts +0 -21
  227. package/src/runtime/provider-connect.ts +0 -109
  228. package/src/runtime/provider-presets.ts +0 -98
  229. package/src/runtime/provider-protocols.ts +0 -29
  230. package/src/runtime/provider-request.ts +0 -87
  231. package/src/runtime/provider-tool-policy.ts +0 -33
  232. package/src/runtime/provider.ts +0 -580
  233. package/src/runtime/question-tool.ts +0 -62
  234. package/src/runtime/retry.ts +0 -447
  235. package/src/runtime/review-tool.ts +0 -48
  236. package/src/runtime/rich-text.ts +0 -36
  237. package/src/runtime/runtime-target.ts +0 -149
  238. package/src/runtime/secrets.ts +0 -79
  239. package/src/runtime/self-update.ts +0 -74
  240. package/src/runtime/session-control.ts +0 -265
  241. package/src/runtime/session-hub.ts +0 -85
  242. package/src/runtime/stream-idle.ts +0 -80
  243. package/src/runtime/tool-broker.ts +0 -137
  244. package/src/runtime/tool-discovery.ts +0 -58
  245. package/src/runtime/tool-queue.ts +0 -77
  246. package/src/runtime/tools.ts +0 -1820
  247. package/src/runtime/turn-effects.ts +0 -31
  248. package/src/runtime/update-check.ts +0 -48
  249. package/src/runtime/usage.ts +0 -253
  250. package/src/runtime/version.ts +0 -12
  251. package/src/runtime/web-http.ts +0 -56
  252. package/src/runtime/web-tools.ts +0 -88
  253. package/src/runtime/working-notes.ts +0 -60
  254. package/src/runtime/workspace-lifecycle.ts +0 -141
  255. package/src/store/acceptance.ts +0 -15
  256. package/src/store/agent-profile-files.ts +0 -13
  257. package/src/store/atomic.ts +0 -31
  258. package/src/store/auth-store.ts +0 -50
  259. package/src/store/blind-checks.ts +0 -32
  260. package/src/store/blobs.ts +0 -143
  261. package/src/store/checkpoint-history.ts +0 -32
  262. package/src/store/command-artifacts.ts +0 -96
  263. package/src/store/command.ts +0 -111
  264. package/src/store/config.ts +0 -69
  265. package/src/store/context-files.ts +0 -436
  266. package/src/store/file-checkpoints.ts +0 -108
  267. package/src/store/file-index.ts +0 -174
  268. package/src/store/foundation-config.ts +0 -24
  269. package/src/store/git-checkpoints.ts +0 -67
  270. package/src/store/git-status.ts +0 -15
  271. package/src/store/history-search.ts +0 -19
  272. package/src/store/log.ts +0 -725
  273. package/src/store/lsp-document.ts +0 -30
  274. package/src/store/mcp-credentials.ts +0 -85
  275. package/src/store/models.ts +0 -60
  276. package/src/store/observations.ts +0 -224
  277. package/src/store/packages.ts +0 -98
  278. package/src/store/patch.ts +0 -92
  279. package/src/store/permission-paths.ts +0 -34
  280. package/src/store/process-receipts.ts +0 -34
  281. package/src/store/query-source.ts +0 -49
  282. package/src/store/recovery.ts +0 -44
  283. package/src/store/replay.ts +0 -76
  284. package/src/store/resource-index.ts +0 -170
  285. package/src/store/resources.ts +0 -285
  286. package/src/store/restore.ts +0 -110
  287. package/src/store/review.ts +0 -109
  288. package/src/store/runtime-target.ts +0 -64
  289. package/src/store/search.ts +0 -728
  290. package/src/store/secrets.ts +0 -44
  291. package/src/store/serial.ts +0 -13
  292. package/src/store/session-archive.ts +0 -165
  293. package/src/store/session-browser.ts +0 -68
  294. package/src/store/session-position.ts +0 -27
  295. package/src/store/sessions.ts +0 -525
  296. package/src/store/source-cancellation.ts +0 -6
  297. package/src/store/tool-binaries.ts +0 -90
  298. package/src/store/trust.ts +0 -82
  299. package/src/store/update-cache.ts +0 -36
  300. package/src/store/user-settings.ts +0 -30
  301. package/src/store/workspace-clone.ts +0 -42
  302. package/src/store/workspace-observation.ts +0 -113
  303. package/src/store/workspace.ts +0 -115
  304. package/src/store/worktree.ts +0 -278
  305. package/src/tui/ansi-spans.ts +0 -126
  306. package/src/tui/diff.ts +0 -160
  307. package/src/tui/exhaustive.ts +0 -14
  308. package/src/tui/fuzzy.ts +0 -75
  309. package/src/tui/style.ts +0 -208
  310. package/src/tui/ui/atomic-draft.ts +0 -121
  311. package/src/tui/ui/canvas.ts +0 -96
  312. package/src/tui/ui/colors.ts +0 -70
  313. package/src/tui/ui/composer.ts +0 -200
  314. package/src/tui/ui/control-panel.ts +0 -25
  315. package/src/tui/ui/control-sidebar.ts +0 -49
  316. package/src/tui/ui/dialog.ts +0 -398
  317. package/src/tui/ui/draft.ts +0 -23
  318. package/src/tui/ui/duration.ts +0 -16
  319. package/src/tui/ui/edge.ts +0 -186
  320. package/src/tui/ui/image-size.ts +0 -44
  321. package/src/tui/ui/ink.ts +0 -210
  322. package/src/tui/ui/items.ts +0 -42
  323. package/src/tui/ui/keys.ts +0 -40
  324. package/src/tui/ui/layout.ts +0 -74
  325. package/src/tui/ui/list-model.ts +0 -86
  326. package/src/tui/ui/list-view.ts +0 -172
  327. package/src/tui/ui/mascot.ts +0 -67
  328. package/src/tui/ui/messages.ts +0 -518
  329. package/src/tui/ui/motion.ts +0 -28
  330. package/src/tui/ui/paths.ts +0 -10
  331. package/src/tui/ui/pictures.ts +0 -108
  332. package/src/tui/ui/screen.ts +0 -548
  333. package/src/tui/ui/status.ts +0 -403
  334. package/src/tui/ui/styled.ts +0 -85
  335. package/src/tui/ui/tool-card.ts +0 -150
  336. package/src/tui/width.ts +0 -567
  337. package/src/vendor/pi-rich/LICENSE.upstream +0 -21
  338. package/src/vendor/pi-rich/UPSTREAM.json +0 -17
  339. package/src/vendor/pi-rich/clipboard-command.ts +0 -44
  340. package/src/vendor/pi-rich/exif-orientation.ts +0 -182
  341. package/src/vendor/pi-rich/html.ts +0 -51
  342. package/src/vendor/pi-rich/image-convert.ts +0 -49
  343. package/src/vendor/pi-rich/image-resize-core.ts +0 -164
  344. package/src/vendor/pi-rich/image-resize-worker.ts +0 -42
  345. package/src/vendor/pi-rich/image-resize.ts +0 -123
  346. package/src/vendor/pi-rich/mime.ts +0 -116
  347. package/src/vendor/pi-rich/photon.ts +0 -139
  348. package/src/vendor/pi-rich/syntax-highlight.ts +0 -214
package/src/tui/style.ts DELETED
@@ -1,208 +0,0 @@
1
- /**
2
- * SGR composition for markdown.
3
- *
4
- * Terminals do not keep attributes across a newline, and the differential
5
- * renderer rewrites by line (`src/tui/render.ts`). A wrap-the-whole-string
6
- * helper would leave only the first row with an open code, so a later
7
- * rewrite of row 2 paints in the default style. Every output row therefore
8
- * carries its own open and close.
9
- *
10
- * Identity emits no ESC bytes: `-p` and pipes parse the transcript, and a
11
- * CSI in that stream is a parse error waiting for a script (D17, same
12
- * reason `createPalette(false)` exists).
13
- *
14
- * Colours are data: createStyle reads token → SGR params. Hard-coding a
15
- * CSI colour here would be a colour the theme cannot reach.
16
- */
17
-
18
- export interface Attrs {
19
- readonly bold: boolean;
20
- readonly italic: boolean;
21
- readonly dim: boolean;
22
- readonly code: boolean;
23
- readonly heading: boolean;
24
- readonly link: boolean;
25
- /** Optional: tool diffs and exit codes. Absent keeps markdown Attrs unchanged. */
26
- readonly red?: boolean;
27
- readonly green?: boolean;
28
- readonly yellow?: boolean;
29
- readonly thinking?: boolean;
30
- readonly tool?: boolean;
31
- readonly result?: boolean;
32
- readonly error?: boolean;
33
- readonly status?: boolean;
34
- readonly prompt?: boolean;
35
- readonly selected?: boolean;
36
- }
37
-
38
- export const PLAIN_ATTRS: Attrs = {
39
- bold: false,
40
- italic: false,
41
- dim: false,
42
- code: false,
43
- heading: false,
44
- link: false,
45
- };
46
-
47
- export interface Style {
48
- open(attrs: Attrs): string;
49
- close(attrs: Attrs): string;
50
- token?(name: string, text: string): string;
51
- }
52
-
53
- /**
54
- * Token → SGR colour params. Same names as core/theme.ts; duplicated so
55
- * tui never imports core. Empty string is the terminal default.
56
- */
57
- export type ColorTokens = {
58
- readonly text: string;
59
- readonly thinkingText: string;
60
- readonly toolTitle: string;
61
- readonly toolOutput: string;
62
- readonly error: string;
63
- readonly toolDiffAdded: string;
64
- readonly toolDiffRemoved: string;
65
- readonly status: string;
66
- readonly prompt: string;
67
- readonly selectedBg: string;
68
- readonly muted: string;
69
- readonly warning: string;
70
- readonly mdHeading: string;
71
- readonly mdCode: string;
72
- readonly mdLink: string;
73
- };
74
-
75
- /**
76
- * Must stay in lockstep with core/theme.ts dark builtin: terminal slots only,
77
- * no truecolor, no background, no SGR faint for muted text.
78
- */
79
- export const DEFAULT_COLORS: ColorTokens = {
80
- "text": "",
81
- "thinkingText": "95",
82
- "toolTitle": "",
83
- "toolOutput": "37",
84
- "error": "91",
85
- "toolDiffAdded": "92",
86
- "toolDiffRemoved": "91",
87
- "status": "37",
88
- "prompt": "",
89
- "selectedBg": "",
90
- "muted": "37",
91
- "warning": "93",
92
- "mdHeading": "94",
93
- "mdCode": "96",
94
- "mdLink": "94"
95
- };
96
-
97
- function anyAttr(a: Attrs, color: string): boolean {
98
- return (
99
- a.bold ||
100
- a.italic ||
101
- a.dim ||
102
- a.code ||
103
- a.heading ||
104
- a.link ||
105
- a.red === true ||
106
- a.green === true ||
107
- a.yellow === true ||
108
- a.thinking === true ||
109
- a.tool === true ||
110
- a.result === true ||
111
- a.error === true ||
112
- a.status === true ||
113
- a.prompt === true ||
114
- a.selected === true ||
115
- color.length > 0
116
- );
117
- }
118
-
119
- function pickColor(attrs: Attrs, colors: ColorTokens): string {
120
- if (attrs.selected === true) return colors.selectedBg;
121
- if (attrs.prompt === true) return colors.prompt;
122
- if (attrs.status === true) return colors.status;
123
- if (attrs.thinking === true) return colors.thinkingText;
124
- if (attrs.error === true) return colors.error;
125
- if (attrs.red === true) return colors.toolDiffRemoved;
126
- if (attrs.green === true) return colors.toolDiffAdded;
127
- if (attrs.yellow === true) return colors.warning;
128
- if (attrs.tool === true) return colors.toolTitle;
129
- if (attrs.result === true) return colors.toolOutput;
130
- if (attrs.code) return colors.mdCode;
131
- if (attrs.heading) return colors.mdHeading;
132
- if (attrs.link) return colors.mdLink;
133
- if (attrs.dim) return colors.muted;
134
- return colors.text;
135
- }
136
-
137
- /** Full reset, not a stacked 22/23/24. Nested closes would drop a wrapping attr on wrap. */
138
- const RESET = "\x1b[0m";
139
-
140
- export const IDENTITY: Style = {
141
- open: () => "",
142
- close: () => "",
143
- };
144
-
145
- /**
146
- * Build a Style from theme tokens. `enabled` is the NO_COLOR / non-tty gate:
147
- * a themed Style that still emits ESC in a pipe is the same class of bug as
148
- * createPalette(true) on stdout that is not a tty.
149
- */
150
- export function createStyle(colors: { readonly [token: string]: string }, enabled = true): Style {
151
- if (!enabled) return IDENTITY;
152
- const tokens: ColorTokens = {
153
- text: colors["text"] ?? "",
154
- thinkingText: colors["thinkingText"] ?? "",
155
- toolTitle: colors["toolTitle"] ?? "",
156
- toolOutput: colors["toolOutput"] ?? "",
157
- error: colors["error"] ?? "",
158
- toolDiffAdded: colors["toolDiffAdded"] ?? "",
159
- toolDiffRemoved: colors["toolDiffRemoved"] ?? "",
160
- status: colors["status"] ?? "",
161
- prompt: colors["prompt"] ?? "",
162
- selectedBg: colors["selectedBg"] ?? "",
163
- muted: colors["muted"] ?? "",
164
- warning: colors["warning"] ?? "",
165
- mdHeading: colors["mdHeading"] ?? "",
166
- mdCode: colors["mdCode"] ?? "",
167
- mdLink: colors["mdLink"] ?? "",
168
- };
169
- return {
170
- token(name, text) {
171
- const color = colors[name];
172
- return color ? `\x1b[${color}m${text}${RESET}` : text;
173
- },
174
- open(attrs) {
175
- const color = pickColor(attrs, tokens);
176
- if (!anyAttr(attrs, color)) return "";
177
- const params: string[] = [];
178
- if (attrs.bold || attrs.heading) params.push("1");
179
- if (attrs.italic) params.push("3");
180
- if (attrs.link) params.push("4");
181
- if (color.length > 0) params.push(...color.split(";"));
182
- const dim = attrs.dim ? "\x1b[2m" : "";
183
- return dim + (params.length > 0 ? `\x1b[${params.join(";")}m` : "");
184
- },
185
- close(attrs) {
186
- const color = pickColor(attrs, tokens);
187
- return anyAttr(attrs, color) ? RESET : "";
188
- },
189
- };
190
- }
191
-
192
- export const ANSI: Style = createStyle(DEFAULT_COLORS);
193
-
194
- export function withDim(base: Style): Style {
195
- return {
196
- open(attrs) {
197
- return base.open({ ...attrs, dim: true });
198
- },
199
- close(attrs) {
200
- return base.close({ ...attrs, dim: true });
201
- },
202
- };
203
- }
204
-
205
- export function paint(text: string, attrs: Attrs, style: Style): string {
206
- if (text.length === 0) return text;
207
- return style.open(attrs) + text + style.close(attrs);
208
- }
@@ -1,121 +0,0 @@
1
- import { TextareaRenderable, type OptimizedBuffer, type KeyEvent } from "@opentui/core";
2
-
3
- /** D20: the native editor owns text and undo; this adapter only protects registered ASCII tokens.
4
- * Offsets in OpenTUI are terminal cells, while app projections use UTF-16. Resolve token starts
5
- * through the native buffer, so wide glyphs, combining marks, tabs and newlines stay its concern.
6
- * Native virtual extmarks in 0.5.14 subtract one on left navigation and do not expand word or
7
- * selection deletion; use one range policy for every edit rather than patching their internals.
8
- */
9
- export interface DraftAtom { readonly start: number; readonly end: number }
10
-
11
- export class AtomicDraftArea extends TextareaRenderable {
12
- atoms: ((text: string) => readonly DraftAtom[]) | undefined;
13
- onRendered: (() => void) | undefined;
14
- private killed = "";
15
-
16
- get textCursor(): number { return this.editBuffer.getTextRange(0, this.cursorOffset).length; }
17
-
18
- private ranges(): DraftAtom[] {
19
- const text = this.plainText;
20
- return (this.atoms?.(text) ?? []).map(atom => {
21
- // Every token starts with one ASCII character. The first native prefix containing it
22
- // ends exactly one cell after its start, irrespective of the preceding Unicode text.
23
- let low = 0, high = text.length * Math.max(2, this.editBuffer.getTabWidth()) + 1;
24
- while (low < high) {
25
- const middle = Math.floor((low + high) / 2);
26
- if (this.editBuffer.getTextRange(0, middle).length > atom.start) high = middle;
27
- else low = middle + 1;
28
- }
29
- const start = Math.max(0, low - 1);
30
- return { start, end: start + atom.end - atom.start };
31
- });
32
- }
33
-
34
- private snap(direction = 0): void {
35
- if (this.hasSelection()) return;
36
- const cursor = this.cursorOffset;
37
- const atom = this.ranges().find(range => cursor > range.start && cursor < range.end);
38
- if (!atom) return;
39
- this.editorView.setCursorByOffset(direction < 0 ? atom.start : direction > 0 ? atom.end :
40
- cursor - atom.start < atom.end - cursor ? atom.start : atom.end);
41
- this.requestRender();
42
- }
43
-
44
- private move(action: () => boolean, direction: number): boolean {
45
- const result = action(); this.snap(direction); return result;
46
- }
47
- override moveCursorLeft(options?: { select?: boolean }): boolean { return this.move(() => super.moveCursorLeft(options), -1); }
48
- override moveCursorRight(options?: { select?: boolean }): boolean { return this.move(() => super.moveCursorRight(options), 1); }
49
- override moveCursorUp(options?: { select?: boolean }): boolean { return this.move(() => super.moveCursorUp(options), 0); }
50
- override moveCursorDown(options?: { select?: boolean }): boolean { return this.move(() => super.moveCursorDown(options), 0); }
51
- override moveWordBackward(options?: { select?: boolean }): boolean { return this.move(() => super.moveWordBackward(options), -1); }
52
- override moveWordForward(options?: { select?: boolean }): boolean { return this.move(() => super.moveWordForward(options), 1); }
53
- override gotoVisualLineHome(options?: { select?: boolean }): boolean { return this.move(() => super.gotoVisualLineHome(options), -1); }
54
- override gotoVisualLineEnd(options?: { select?: boolean }): boolean { return this.move(() => super.gotoVisualLineEnd(options), 1); }
55
- override setCursor(row: number, col: number): void { super.setCursor(row, col); this.snap(); }
56
-
57
- private erase(start: number, end: number, kill = false): boolean {
58
- if (start > end) [start, end] = [end, start];
59
- if (start === end) return true;
60
- for (const atom of this.ranges()) {
61
- if (atom.start < end && atom.end > start) { start = Math.min(start, atom.start); end = Math.max(end, atom.end); }
62
- }
63
- if (kill) this.killed = this.editBuffer.getTextRange(start, end);
64
- const a = this.editBuffer.offsetToPosition(start), b = this.editBuffer.offsetToPosition(end);
65
- if (!a || !b) return false;
66
- this.clearSelection();
67
- this.editBuffer.deleteRange(a.row, a.col, b.row, b.col);
68
- this.requestRender();
69
- return true;
70
- }
71
- override deleteSelection(): boolean {
72
- const selection = this.getSelection();
73
- return selection ? this.erase(selection.start, selection.end) : false;
74
- }
75
- override deleteCharBackward(): boolean {
76
- if (this.hasSelection()) return this.deleteSelection();
77
- const atom = this.ranges().find(range => this.cursorOffset > range.start && this.cursorOffset <= range.end);
78
- return atom ? this.erase(atom.start, atom.end) : super.deleteCharBackward();
79
- }
80
- override deleteChar(): boolean {
81
- if (this.hasSelection()) return this.deleteSelection();
82
- const atom = this.ranges().find(range => this.cursorOffset >= range.start && this.cursorOffset < range.end);
83
- return atom ? this.erase(atom.start, atom.end) : super.deleteChar();
84
- }
85
- override deleteWordBackward(): boolean {
86
- if (this.hasSelection()) return this.deleteSelection();
87
- return this.erase(this.editBuffer.getPrevWordBoundary().offset, this.cursorOffset, true);
88
- }
89
- override deleteWordForward(): boolean {
90
- if (this.hasSelection()) return this.deleteSelection();
91
- return this.erase(this.cursorOffset, this.editBuffer.getNextWordBoundary().offset, true);
92
- }
93
- override deleteToLineStart(): boolean {
94
- const cursor = this.editBuffer.getCursorPosition();
95
- return cursor.col ? this.erase(this.editBuffer.getLineStartOffset(cursor.row), cursor.offset, true) : super.deleteToLineStart();
96
- }
97
- override deleteToLineEnd(): boolean {
98
- const end = this.editBuffer.getEOL().offset;
99
- return end > this.cursorOffset ? this.erase(this.cursorOffset, end, true) : super.deleteToLineEnd();
100
- }
101
- override insertText(text: string): void {
102
- if (this.hasSelection()) this.deleteSelection();
103
- this.snap(); super.insertText(text);
104
- }
105
- override insertChar(char: string): void {
106
- if (this.hasSelection()) this.deleteSelection();
107
- this.snap(); super.insertChar(char);
108
- }
109
- override newLine(): boolean {
110
- if (this.hasSelection()) this.deleteSelection();
111
- this.snap(); return super.newLine();
112
- }
113
- override handleKeyPress(event: KeyEvent): boolean {
114
- if (event.ctrl && event.name === "y" && this.killed) { this.insertText(this.killed); return true; }
115
- return super.handleKeyPress(event);
116
- }
117
- clearKilledText(): void { this.killed = ""; }
118
- override render(buffer: OptimizedBuffer, deltaTime: number): void {
119
- this.snap(); super.render(buffer, deltaTime); this.onRendered?.();
120
- }
121
- }
@@ -1,96 +0,0 @@
1
- /**
2
- * Rows of styled segments drawn straight into the frame buffer.
3
- *
4
- * Chrome (input box edges, top bar, sidebar, greeting, completion list)
5
- * changes often and never needs wrapping or selection, so it skips the text
6
- * layout machinery: setting a TextRenderable's content re-measures the node
7
- * and dirties Yoga, even for an identical string (OpenTUI 0.5.14,
8
- * TextBufferRenderable). A Canvas only stores rows and requests a frame;
9
- * the activity glyph is read at paint time, so a spinner tick touches no
10
- * node at all (docs/tasks/refactor-tui-dock-layout.md DoD 9).
11
- */
12
- import { Renderable, TextAttributes, type OptimizedBuffer, type RenderContext, type RenderableOptions, type RGBA } from "@opentui/core";
13
- import type { UiColors } from "./colors.ts";
14
- import type { Role } from "./edge.ts";
15
- import type { Line } from "./status.ts";
16
- import { displayWidth } from "../width.ts";
17
-
18
- export interface CanvasOptions extends RenderableOptions<Canvas> {
19
- readonly colors: UiColors;
20
- /** The current activity glyph for `spin` segments. */
21
- readonly glyph?: () => string;
22
- }
23
-
24
- export function roleColor(colors: UiColors, role: Role): RGBA {
25
- switch (role) {
26
- case "text": return colors.text;
27
- case "muted": return colors.muted;
28
- case "edge": return colors.edge;
29
- case "line": return colors.line;
30
- case "accent": return colors.accent;
31
- case "success": return colors.success;
32
- case "error": return colors.error;
33
- case "warning": return colors.warning;
34
- case "reasoning": return colors.reasoning;
35
- case "code": return colors.code;
36
- }
37
- }
38
-
39
- export class Canvas extends Renderable {
40
- private rows: readonly Line[] = [];
41
- private colors: UiColors;
42
- private readonly glyph: () => string;
43
-
44
- constructor(ctx: RenderContext, options: CanvasOptions) {
45
- super(ctx, options);
46
- this.colors = options.colors;
47
- this.glyph = options.glyph ?? (() => "●");
48
- }
49
-
50
- get lines(): readonly Line[] { return this.rows; }
51
- /** Plain text of what is drawn (tests, /debug). */
52
- get text(): string { return this.rows.map(row => row.map(seg => seg.spin ? this.glyph() : seg.text).join("")).join("\n"); }
53
-
54
- /** Store new rows; an identical set requests nothing. */
55
- setRows(rows: readonly Line[]): void {
56
- if (sameRows(rows, this.rows)) return;
57
- this.rows = rows;
58
- this.requestRender();
59
- }
60
-
61
- setColors(colors: UiColors): void { this.colors = colors; this.requestRender(); }
62
-
63
- protected override renderSelf(buffer: OptimizedBuffer): void {
64
- const x0 = this.screenX, y0 = this.screenY, width = this.width, height = this.height;
65
- for (let row = 0; row < Math.min(height, this.rows.length); row++) {
66
- // Rows scrolled above the buffer must be skipped here: the native drawText
67
- // clamps a negative row to 0, where the scissor (the scroll viewport) lets it through.
68
- const y = y0 + row;
69
- if (y < 0 || y >= buffer.height) continue;
70
- let x = x0;
71
- for (const seg of this.rows[row]!) {
72
- const text = seg.spin ? this.glyph() : seg.text;
73
- if (!text) continue;
74
- const w = seg.spin ? 1 : displayWidth(text);
75
- if (x - x0 + w > width) break;
76
- const attributes = (seg.bold ? TextAttributes.BOLD : 0) | (seg.italic ? TextAttributes.ITALIC : 0);
77
- buffer.drawText(text, x, y, roleColor(this.colors, seg.role), undefined, attributes);
78
- x += w;
79
- }
80
- }
81
- }
82
- }
83
-
84
- function sameRows(a: readonly Line[], b: readonly Line[]): boolean {
85
- if (a === b) return true;
86
- if (a.length !== b.length) return false;
87
- for (let i = 0; i < a.length; i++) {
88
- const x = a[i]!, y = b[i]!;
89
- if (x.length !== y.length) return false;
90
- for (let j = 0; j < x.length; j++) {
91
- const p = x[j]!, q = y[j]!;
92
- if (p.text !== q.text || p.role !== q.role || p.bold !== q.bold || p.italic !== q.italic || p.spin !== q.spin) return false;
93
- }
94
- }
95
- return true;
96
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * The view's colour vocabulary, as OpenTUI colours ready to draw with.
3
- *
4
- * Built-in appearances come from the terminal's own palette (ink.ts): the
5
- * background is never painted and body text is the terminal's foreground.
6
- * A custom theme file supplies explicit colours instead. `src/tui` may not
7
- * import core, so the app maps its Theme into this record (apps/ui/theme.ts).
8
- *
9
- * Colour carries a stable role: one accent for navigation, success/error
10
- * only for logged outcomes (D11), warning for things waiting on the user.
11
- */
12
- import { RGBA } from "@opentui/core";
13
- import { terminalInks, type InkSet, type InkSpec } from "./ink.ts";
14
-
15
- export interface UiColors {
16
- /** The terminal default unless a custom theme sets one explicitly. */
17
- readonly background: RGBA;
18
- readonly text: RGBA;
19
- readonly muted: RGBA;
20
- /** The input box border. */
21
- readonly edge: RGBA;
22
- /** Rules, separators and scrollbar tracks. */
23
- readonly line: RGBA;
24
- readonly accent: RGBA;
25
- readonly success: RGBA;
26
- readonly error: RGBA;
27
- readonly warning: RGBA;
28
- readonly reasoning: RGBA;
29
- readonly code: RGBA;
30
- /** Mouse-selected text (feat-tui-copy-selection). */
31
- readonly selectionBg: RGBA;
32
- readonly selectionFg: RGBA;
33
- }
34
-
35
- const cache = new Map<string, RGBA>();
36
- function cached(key: string, make: () => RGBA): RGBA {
37
- let value = cache.get(key);
38
- if (!value) { value = make(); cache.set(key, value); }
39
- return value;
40
- }
41
-
42
- export function inkColor(spec: InkSpec): RGBA {
43
- switch (spec.kind) {
44
- case "default": return cached("default:fg", () => RGBA.defaultForeground());
45
- case "index": return cached(`index:${spec.index}`, () => RGBA.fromIndex(spec.index));
46
- case "rgb": return rgba(spec.hex);
47
- }
48
- }
49
-
50
- /** The terminal's own background: SGR 49, so transparency and blur survive. */
51
- export const TERMINAL_BACKGROUND: RGBA = RGBA.defaultBackground();
52
- /** Nothing at all (OpenTUI skips the cell's background). */
53
- export const CLEAR: RGBA = RGBA.fromValues(0, 0, 0, 0);
54
-
55
- export function colorsFromInks(inks: InkSet): UiColors {
56
- return {
57
- background: inks.background.kind === "default" ? TERMINAL_BACKGROUND : inkColor(inks.background),
58
- text: inkColor(inks.text), muted: inkColor(inks.muted), edge: inkColor(inks.edge), line: inkColor(inks.line),
59
- accent: inkColor(inks.accent), success: inkColor(inks.success), error: inkColor(inks.error),
60
- warning: inkColor(inks.warning), reasoning: inkColor(inks.reasoning), code: inkColor(inks.code),
61
- selectionBg: inkColor(inks.selectionBg), selectionFg: inkColor(inks.selectionFg),
62
- };
63
- }
64
-
65
- /** Before the terminal answers (or when it never does). */
66
- export const FALLBACK_COLORS: UiColors = colorsFromInks(terminalInks(null, "dark"));
67
-
68
- export function rgba(hex: string): RGBA {
69
- return cached(`hex:${hex}`, () => RGBA.fromHex(hex));
70
- }