@luan.sh/pi-libtui 0.3.8

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 (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +208 -0
  3. package/native-revision +1 -0
  4. package/package.json +58 -0
  5. package/src/activity-presentation.ts +75 -0
  6. package/src/appearance.ts +632 -0
  7. package/src/background-surface.ts +125 -0
  8. package/src/color/palette.ts +186 -0
  9. package/src/color/preview.ts +157 -0
  10. package/src/color/resolver.ts +75 -0
  11. package/src/color/theme.ts +531 -0
  12. package/src/component-stack.ts +247 -0
  13. package/src/content/markdown-code.ts +60 -0
  14. package/src/content/terminal-text.ts +135 -0
  15. package/src/content/text.ts +105 -0
  16. package/src/controls/action-panel.ts +420 -0
  17. package/src/controls/dialog-button-bar.ts +287 -0
  18. package/src/controls/multi-select.ts +467 -0
  19. package/src/controls/picker-panel.ts +447 -0
  20. package/src/controls/screen-icon-actions.ts +134 -0
  21. package/src/controls/searchable-select.ts +394 -0
  22. package/src/controls/select-box.ts +224 -0
  23. package/src/controls/selectable-list.ts +433 -0
  24. package/src/controls/selection-action-bar.ts +382 -0
  25. package/src/controls/semantic-input.ts +23 -0
  26. package/src/controls/tab.ts +189 -0
  27. package/src/cursor.ts +288 -0
  28. package/src/decoration/editor-pills.ts +156 -0
  29. package/src/decoration/glyphs.ts +326 -0
  30. package/src/decoration/pointer-interaction.ts +123 -0
  31. package/src/decoration/powerline-pill.ts +104 -0
  32. package/src/decoration/status.ts +185 -0
  33. package/src/decoration/transient-pill.ts +176 -0
  34. package/src/diff/index.ts +21 -0
  35. package/src/diff/model.ts +76 -0
  36. package/src/diff/parse.ts +310 -0
  37. package/src/diff/pierre-syntax.ts +86 -0
  38. package/src/diff/render.ts +504 -0
  39. package/src/diff/structured.ts +264 -0
  40. package/src/diff/view.ts +75 -0
  41. package/src/editor/chrome.ts +341 -0
  42. package/src/editor/composition.ts +53 -0
  43. package/src/editor/layout.ts +81 -0
  44. package/src/editor/presentation.ts +35 -0
  45. package/src/editor/protocol.ts +188 -0
  46. package/src/editor.ts +41 -0
  47. package/src/extension.ts +30 -0
  48. package/src/folding.ts +192 -0
  49. package/src/host/cursor-bridge.ts +210 -0
  50. package/src/host/editor-bridge.ts +148 -0
  51. package/src/host/extension-host.ts +231 -0
  52. package/src/host/mouse-bridge.ts +212 -0
  53. package/src/host/mouse-dispatch.ts +400 -0
  54. package/src/host/mouse-input.ts +85 -0
  55. package/src/host/mouse-targets.ts +238 -0
  56. package/src/host/pi-layout-adapter.ts +298 -0
  57. package/src/host/pi-native-selection.ts +227 -0
  58. package/src/host/split-pane-bridge.ts +720 -0
  59. package/src/host/transcript-bridge.ts +236 -0
  60. package/src/index.ts +334 -0
  61. package/src/line-layout.ts +6 -0
  62. package/src/motion.ts +1409 -0
  63. package/src/mouse/events.ts +55 -0
  64. package/src/mouse/fullscreen-layout.ts +260 -0
  65. package/src/mouse/registry.ts +348 -0
  66. package/src/mouse.ts +37 -0
  67. package/src/native-binary.ts +189 -0
  68. package/src/overlay/anchored.ts +91 -0
  69. package/src/overlay/detail-card.ts +158 -0
  70. package/src/overlay/dialog.ts +266 -0
  71. package/src/overlay/floating.ts +106 -0
  72. package/src/overlay/framed-editor.ts +236 -0
  73. package/src/overlay/fullscreen.ts +170 -0
  74. package/src/overlay/hover-tooltip.ts +109 -0
  75. package/src/overlay/modal-mount.ts +118 -0
  76. package/src/panels.ts +207 -0
  77. package/src/render-cache.ts +80 -0
  78. package/src/render-epoch.ts +48 -0
  79. package/src/request-animation.ts +160 -0
  80. package/src/scrollbar.ts +27 -0
  81. package/src/selection.ts +148 -0
  82. package/src/split-pane.ts +232 -0
  83. package/src/status-presentation.ts +411 -0
  84. package/src/stream.ts +543 -0
  85. package/src/syntax.ts +316 -0
  86. package/src/terminal/bridge-client.ts +243 -0
  87. package/src/terminal/embedding.ts +6 -0
  88. package/src/terminal/output.ts +151 -0
  89. package/src/terminal/projection.ts +362 -0
  90. package/src/terminal/pty-host.ts +263 -0
  91. package/src/terminal/pty-pane.ts +308 -0
  92. package/src/terminal-colors.ts +334 -0
  93. package/src/tool/action.ts +170 -0
  94. package/src/tool/activity.ts +500 -0
  95. package/src/tool/call-preview.ts +44 -0
  96. package/src/tool/disclosure-action.ts +89 -0
  97. package/src/tool/expanded-region-viewport.ts +103 -0
  98. package/src/tool/index.ts +26 -0
  99. package/src/tool/output.ts +271 -0
  100. package/src/tool/transcript.ts +150 -0
  101. package/src/tool/view-region.ts +581 -0
  102. package/test/appearance.test.ts +183 -0
  103. package/test/bounded-stream.test.ts +150 -0
  104. package/test/bridge-client.test.ts +42 -0
  105. package/test/color-preview.test.ts +23 -0
  106. package/test/component-stack.test.ts +206 -0
  107. package/test/components.test.ts +1165 -0
  108. package/test/content-text.test.ts +21 -0
  109. package/test/cursor-bridge.test.ts +151 -0
  110. package/test/cursor.test.ts +147 -0
  111. package/test/editor-chrome.test.ts +119 -0
  112. package/test/editor-layout.test.ts +30 -0
  113. package/test/editor-registry.test.ts +203 -0
  114. package/test/editor-theme.test.ts +33 -0
  115. package/test/editor-token-pill.test.ts +72 -0
  116. package/test/floating-overlay.test.ts +57 -0
  117. package/test/folding.test.ts +147 -0
  118. package/test/harmonious-theme.test.ts +23 -0
  119. package/test/interaction.test.ts +104 -0
  120. package/test/key-icons.test.ts +62 -0
  121. package/test/markdown-code.test.ts +24 -0
  122. package/test/modal-overlay-mount.test.ts +94 -0
  123. package/test/motion.test.ts +649 -0
  124. package/test/mouse/bridge.test.ts +1302 -0
  125. package/test/mouse/extension.test.ts +205 -0
  126. package/test/mouse/registry.test.ts +140 -0
  127. package/test/mouse/screen-decoration.test.ts +167 -0
  128. package/test/native-binary.test.ts +52 -0
  129. package/test/palette.test.ts +32 -0
  130. package/test/panels.test.ts +74 -0
  131. package/test/pointer-components.test.ts +151 -0
  132. package/test/progress.test.ts +54 -0
  133. package/test/pty-host.test.ts +126 -0
  134. package/test/pty-pane.test.ts +62 -0
  135. package/test/public-surface.test.ts +75 -0
  136. package/test/render-cache.test.ts +25 -0
  137. package/test/render-epoch.test.ts +119 -0
  138. package/test/request-animation.test.ts +193 -0
  139. package/test/screen-icon-actions.test.ts +69 -0
  140. package/test/select-box.test.ts +86 -0
  141. package/test/select-pointer.test.ts +369 -0
  142. package/test/selectable-list.test.ts +258 -0
  143. package/test/selection/registry.test.ts +44 -0
  144. package/test/selection-action-bar.test.ts +204 -0
  145. package/test/split-pane-bridge.test.ts +944 -0
  146. package/test/split-pane.test.ts +134 -0
  147. package/test/status-presentation.test.ts +39 -0
  148. package/test/syntax.test.ts +59 -0
  149. package/test/terminal-colors.test.ts +115 -0
  150. package/test/terminal-embedding.test.ts +12 -0
  151. package/test/terminal-projection.test.ts +312 -0
  152. package/test/theme-colors.test.ts +175 -0
  153. package/test/tool-output.test.ts +160 -0
  154. package/test/tool-transcript.test.ts +1190 -0
  155. package/test/unified-diff.test.ts +691 -0
  156. package/themes/harmonious.json +61 -0
  157. package/tsconfig.json +16 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luan Santos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # @luan.sh/pi-libtui
2
+
3
+ [Pi gallery](https://pi.dev/packages/@luan.sh/pi-libtui)
4
+
5
+ Shared terminal UI for Pi extensions: layouts, split panes, dialogs, pickers,
6
+ selection actions, semantic colors, icons, cursors, syntax highlighting,
7
+ animated tool surfaces, streamed output, diffs, terminal projection, and the
8
+ protocols those pieces need. The primary audience is extension authors.
9
+
10
+ The package has two surfaces. `import "@luan.sh/pi-libtui"` is a
11
+ side-effect-free library: it does not start Pi, probe the terminal, register a
12
+ tool, or install UI. `src/extension.ts` is a Pi extension (listed in the
13
+ package's `pi.extensions`) that installs the generic mouse, cursor, and
14
+ editor-token bridges, keeps the shared native PTY host alive, measures terminal
15
+ colors, applies the `harmonious` theme fallback, drives Pi's streaming status
16
+ row, and registers the `/libtui:colors` 256-color palette diagnostic. It
17
+ registers no model-facing tools, keybindings, or feature-specific UI.
18
+
19
+ ## Preview
20
+
21
+ The native palette diagnostic and shared picker components in Xsettings.
22
+
23
+ ![@luan.sh/pi-libtui in Bootty](https://github.com/luan/agents/releases/download/v0.3.2/pi-libtui.png)
24
+
25
+ [Watch the demo](https://github.com/luan/agents/releases/download/v0.3.2/pi-libtui.mp4).
26
+
27
+ ## Install
28
+
29
+ ```sh
30
+ pi install npm:@luan.sh/pi-libtui
31
+ ```
32
+
33
+ This loads the host extension and the `harmonious` theme on its own. Feature
34
+ packages normally bundle their own copy instead: add `@luan.sh/pi-libtui` to
35
+ both `dependencies` and `bundledDependencies` in `package.json`, and list
36
+ `"./node_modules/pi-libtui/src/extension.ts"` in the package's
37
+ `pi.extensions` so the mouse/cursor bridge is active. The host claims itself
38
+ once per process, so several installed copies do not conflict.
39
+
40
+ Optional companion: `pi install npm:@luan.sh/pi-xsettings` adds the `/xsettings`
41
+ UI that publishes the appearance settings below; without it the compiled
42
+ defaults apply.
43
+
44
+ ## Themes
45
+
46
+ The manifest exposes `themes/harmonious.json`, which relies on the terminal's
47
+ indexed palette. If `harmonious` is active and the measured terminal reports
48
+ neither a generated 256-color palette nor an ANSI base-16 palette, the host
49
+ switches to Pi's built-in theme for the detected light or dark scheme (dark if
50
+ the measurement fails).
51
+
52
+ ## Public modules
53
+
54
+ Every entry point is a side-effect-free import. "Host required" means the
55
+ Pi-native behaviour also needs the extension loaded.
56
+
57
+ | Import path | Principal exports / capability | Host required |
58
+ | --- | --- | --- |
59
+ | `@luan.sh/pi-libtui` | Layouts, split panes, side-panel protocol, dialogs, pickers, inputs, selection actions, semantic colors, icons, cursors, `PtyProcess`, `PtyPane`, `applyScrollbar`, `PointerInteractionController`, `RenderedLinesCache`, `SyntaxText`, motion/progress, appearance (`getTuiAppearance`, `configureTuiAppearance`, `subscribeTuiAppearance`), `ensureNativeBinary` | Rendering no; panes, PTYs, and bridges yes |
60
+ | `@luan.sh/pi-libtui/diff` | `createUnifiedDiffModel`, `parseUnifiedDiff`, `renderUnifiedDiff`, `UnifiedDiffView`, bounded diff models/viewports | No |
61
+ | `@luan.sh/pi-libtui/editor` | `ensureEditorRegistry`, `dispatchEditorPaste`, `dispatchEditorRender`, `SemanticEditor`, `semanticEditorTheme`, editor registry contracts | Only to connect the registry to Pi's editor |
62
+ | `@luan.sh/pi-libtui/folding` | `ensureFoldingRegistry`, `foldTargetAt`, `clearFoldingCurrent`, fold-target contracts | Only for copy-mode keyboard integration |
63
+ | `@luan.sh/pi-libtui/mouse` | `ensureMouseRegistry`, `registerModalPointerShield`, viewport handlers, pointer contracts, `getFullscreenLayoutCapability`, `publishFullscreenLayoutCapability`, `resolveFullscreenLayout` | Yes for terminal pointer events and layout geometry |
64
+ | `@luan.sh/pi-libtui/selection` | `ensureSelectionRegistry`, native selection geometry, completion events, action contracts | Yes for Pi-native selection events |
65
+ | `@luan.sh/pi-libtui/stream` | `BoundedStreamBuffer`, bounded UTF-8/ANSI-safe stream snapshots | No |
66
+ | `@luan.sh/pi-libtui/terminal` | `TerminalProjection`, incremental `TerminalOutput` for bounded PTY/ANSI projection | No |
67
+ | `@luan.sh/pi-libtui/tool` | `ToolAction`, `LiveToolAction`, `ToolDisclosureAction`, `ToolActivity`, `ToolOutput`, `ToolTranscript`, `ToolViewRegion`, tool-call preview helpers | No for rendering |
68
+
69
+ The `ensure*Registry` functions create or reuse a process-global capability
70
+ keyed by `Symbol.for`, so feature packages and the host share one instance.
71
+ Tool presentation has three layers: `ToolTranscript` (copy-friendly action plus
72
+ payload), `ToolActivity` (streaming, diff, terminal, and viewport state for a
73
+ live surface), and `ToolOutput` for text streams. `mountTranscriptProjection`
74
+ exposes native transcript entries to a feature-owned component through a
75
+ guarded Pi 0.84–0.85 adapter; unsupported hosts keep their native transcript.
76
+
77
+ ## Native binaries
78
+
79
+ Feature packages shell out to Rust binaries such as `terminal_bridge` (the
80
+ exported `TERMINAL_BRIDGE` descriptor). Requires a Rust toolchain
81
+ (https://rustup.rs). The `terminal_bridge` binary builds itself on first use
82
+ under Pi's agent directory (`native/terminal-bridge/<revision>/`), where
83
+ `<revision>` is the source commit recorded in the packaged `native-revision` file. Set `PI_TERMINAL_BRIDGE_BINARY` to use
84
+ a prebuilt binary; it must point at an executable file.
85
+
86
+ `ensureNativeBinary(binary, hooks?)` resolves in this order: the descriptor's
87
+ env override, then `<agentDir>/native/<crate>/<revision>/bin/<name>`, building
88
+ it on first use when absent. Builds are keyed by crate and source commit, so every
89
+ installed copy shares them, and concurrent requests within one process share
90
+ one build. Pass `onBuild` to show the delay in the UI. The extension host keeps
91
+ the shared PTY host alive across an extension reload; a session switch or quit
92
+ shuts it down.
93
+
94
+ ## Fullscreen split panes
95
+
96
+ `mountSplitPane()` composes one extension-owned pane beside Pi's complete
97
+ fullscreen layout. Pi's transcript, editor, widgets, status, and footer stay in
98
+ the main pane and reflow to its width. The highest-priority contribution is
99
+ visible, with the latest mount breaking ties; disposing it restores the
100
+ previous contribution or Pi's unwrapped layout.
101
+
102
+ ```ts
103
+ const unmount = mountSplitPane({
104
+ id: "example.details",
105
+ position: "right",
106
+ size: 32,
107
+ initialRatio: 0.4,
108
+ minMainSize: 1,
109
+ priority: 10,
110
+ onResize: (size) => saveCommittedWidth(size),
111
+ component: (host, theme) => new DetailsPane(host, theme),
112
+ });
113
+ ```
114
+
115
+ A draggable vertical border separates the pane from the main surface; Pi keeps
116
+ only `minMainSize`. `initialRatio` derives the first width when none is
117
+ restored, and `onResize` runs once when a drag commits. The pane hides when the
118
+ terminal cannot fit one pane cell, the border and gap, and the minimum main
119
+ size. The factory receives the active `tui`, viewport size, render requests,
120
+ and `focus()`, `blur()`, `isFocused()`; clicking either pane focuses it without
121
+ consuming the click. Split panes exist only in fullscreen mode. Pi 0.84.x has
122
+ `setLayoutRoot()` but no getter, so the host validates one private field
123
+ through a ref-counted prototype lease and leaves the layout unchanged if the
124
+ shape is absent.
125
+
126
+ ## Appearance settings
127
+
128
+ This package has no settings store of its own. It exposes an appearance
129
+ registry with compiled defaults (`DEFAULT_TUI_APPEARANCE`) that a settings host
130
+ such as `@luan.sh/pi-xsettings` overrides through `configureTuiAppearance()`;
131
+ with @luan.sh/pi-xsettings installed they are edited live via `/xsettings`. Keys and
132
+ defaults:
133
+
134
+ | Key | Default | Values |
135
+ | --- | --- | --- |
136
+ | `iconPack` | `unicode` | `unicode`, `nerd-fonts`, `emoji` |
137
+ | `activityIndicator` | `spinner` | `off`, `spinner`, `static`, and the Unicode/ASCII/Braille/Nerd Font animations in `TUI_ACTIVITY_INDICATOR_OPTIONS` |
138
+ | `activityMessage` | `phase` | `phase`, `typewriter` |
139
+ | `textEffect` | `off` | `off`, `sweep`, `glow`, `rainbow`, `rainbow-glow`, `lightning`, `aurora`, `glitch`, `crush` |
140
+ | `textEffectScope` | `message` | message only or the whole indicator, separator, and message unit |
141
+ | `pulseEffect` | `off` | dim-to-bright or contrasting-color pulse over any indicator/text effect |
142
+ | `statusPresentation` | `standard` | `standard`, mixed compositions such as `brainstorm`, or exclusive scenes in `TUI_STATUS_PRESENTATION_OPTIONS` |
143
+ | `animationSpeed` | `normal` | `slow`, `relaxed`, `normal`, `fast`, `very-fast` |
144
+ | `animationSmoothness` | `balanced` | `economy`, `balanced`, `smooth`, `ultra` (roughly 13 to 60 redraws per second) |
145
+ | `thinking*`, `working*`, `tool*` (`Indicator`, `Message`, `TextEffect`, `PulseEffect`, `Presentation`) | `inherit` | per-phase overrides of the general value |
146
+ | `powerline`, `powerlineButtons`, `softCursor` | `false` | Powerline separators, button caps, softer virtual cursor |
147
+ | `insertionCursor`, `navigationCursor`, `selectionCursor` | `virtual` | cursor styles |
148
+
149
+ Inline activity is composed as `indicator + message`, then the effect scope is
150
+ painted; an exclusive scene replaces that composition. The extension applies
151
+ the same renderer to Pi's streaming status row: Thinking takes priority over
152
+ Tool, which takes priority over Working. Feature surfaces may pass
153
+ `ActivityAnimationOverrides` to `activityFrame()` and
154
+ `mountConfiguredAnimation()`; omitted fields inherit the live appearance.
155
+
156
+ ## Architecture
157
+
158
+ | Responsibility | Owner |
159
+ | --- | --- |
160
+ | Tool definition | None; the package adds no model-facing tool |
161
+ | Execution | None in the library; `src/extension.ts` owns host setup |
162
+ | State | Components own local state; `MouseBridgeHost` owns bridge state; `RequestAnimationController` owns request phase state |
163
+ | Shared contracts | `src/editor/protocol.ts` (via `src/editor.ts`), `src/folding.ts`, `src/selection.ts`, `src/decoration/pointer-interaction.ts`, the public contracts selected by `src/mouse.ts` |
164
+ | Native boundary | Mouse/cursor compatibility, terminal color queries, PTY host, host bridges in `src/host/` |
165
+
166
+ The host knows only generic TUI mechanics; feature labels, settings, actions,
167
+ and workflows stay in their owning packages. Color resolution has one path:
168
+ `src/color/theme.ts` owns the semantic-token table and resolves every paint
169
+ through `src/color/resolver.ts`. Feature code uses only the root color API:
170
+ `tuiTheme(theme)`, `createTuiThemeVariation(theme, name)`,
171
+ `tuiThemeAppearance(theme)`, `TuiForegroundToken`/`TuiBackgroundToken`,
172
+ `TuiSwatch` (seven ramps at shades `0`–`5`), opaque `TuiColor` handles, and
173
+ `TuiTheme.mixForeground()`.
174
+
175
+ ## Layout
176
+
177
+ | Responsibility | Source |
178
+ | --- | --- |
179
+ | Extension entry and host | `src/extension.ts`, `src/host/` |
180
+ | Layout and rendering infrastructure | `src/background-surface.ts`, `src/component-stack.ts`, `src/line-layout.ts`, `src/render-cache.ts`, `src/scrollbar.ts` |
181
+ | Split panes and side panel | `src/split-pane.ts`, `src/host/split-pane-bridge.ts`, `src/panels.ts` |
182
+ | Overlays | `src/overlay/` |
183
+ | Controls | `src/controls/` |
184
+ | Text content, glyphs, status, pills, editor | `src/content/`, `src/decoration/`, `src/editor.ts`, `src/editor/` |
185
+ | Appearance, motion, request animation | `src/appearance.ts`, `src/motion.ts`, `src/request-animation.ts` |
186
+ | Colors and syntax | `src/color/`, `src/terminal-colors.ts`, `src/syntax.ts` |
187
+ | Streams, terminal projection, PTY host, diffs, tools | `src/stream.ts`, `src/terminal/`, `src/diff/`, `src/tool/` |
188
+ | Native binary discovery and first-use builds | `src/native-binary.ts` |
189
+
190
+ ## Troubleshooting
191
+
192
+ - A feature renders but clicks do nothing: the host extension is not loaded.
193
+ Install `@luan.sh/pi-libtui` as a Pi package or list its `src/extension.ts`
194
+ in the feature package's `pi.extensions`.
195
+ - Nerd Font or Powerline glyphs are missing: set the icon pack to `unicode` and
196
+ disable Powerline in `/xsettings`. Those are also the compiled defaults.
197
+ - `cargo was not found`: install Rust from https://rustup.rs, or set the
198
+ binary's env override to a prebuilt executable.
199
+
200
+ ## Develop
201
+
202
+ Source: https://github.com/luan/agents, directory
203
+ harnesses/pi/agent/packages/pi-libtui. Run `bun run typecheck` and
204
+ `bun test test` in that directory. When running from that checkout,
205
+ `ensureNativeBinary` also looks for `target/{release,debug}/<name>` in the Cargo
206
+ workspace and reports an unbuilt checkout instead of building. `just pi-pack`
207
+ records the checkout commit in every bundled `@luan.sh/pi-libtui/native-revision` file,
208
+ so native builds do not depend on npm versions or repository-wide release tags.
@@ -0,0 +1 @@
1
+ 6ed73340be70e909918ec92adc31ba920bfc8cd4
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@luan.sh/pi-libtui",
3
+ "version": "0.3.8",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/luan/agents.git",
8
+ "directory": "harnesses/pi/agent/packages/pi-libtui"
9
+ },
10
+ "description": "Shared TUI components and generic mouse compatibility for local Pi extensions",
11
+ "type": "module",
12
+ "keywords": [
13
+ "pi-package"
14
+ ],
15
+ "exports": {
16
+ ".": "./src/index.ts",
17
+ "./diff": "./src/diff/index.ts",
18
+ "./editor": "./src/editor.ts",
19
+ "./folding": "./src/folding.ts",
20
+ "./mouse": "./src/mouse.ts",
21
+ "./selection": "./src/selection.ts",
22
+ "./stream": "./src/stream.ts",
23
+ "./terminal": "./src/terminal/output.ts",
24
+ "./tool": "./src/tool/index.ts"
25
+ },
26
+ "pi": {
27
+ "extensions": [
28
+ "./src/extension.ts"
29
+ ],
30
+ "themes": [
31
+ "./themes"
32
+ ],
33
+ "image": "https://github.com/luan/agents/releases/download/v0.3.2/pi-libtui.png",
34
+ "video": "https://github.com/luan/agents/releases/download/v0.3.2/pi-libtui.mp4"
35
+ },
36
+ "peerDependencies": {
37
+ "@earendil-works/pi-coding-agent": "*",
38
+ "@earendil-works/pi-tui": "*"
39
+ },
40
+ "dependencies": {
41
+ "@pierre/diffs": "1.3.5",
42
+ "@xterm/headless": "6.0.0"
43
+ },
44
+ "devDependencies": {
45
+ "@biomejs/biome": "2.5.10",
46
+ "@earendil-works/pi-coding-agent": "0.84.2",
47
+ "@earendil-works/pi-tui": "0.84.2",
48
+ "@types/bun": "^1.3.0"
49
+ },
50
+ "scripts": {
51
+ "typecheck": "tsc --build",
52
+ "test": "bun test --only-failures --timeout 15000 test"
53
+ },
54
+ "bundledDependencies": [],
55
+ "publishAliases": [
56
+ "pi-libtui"
57
+ ]
58
+ }
@@ -0,0 +1,75 @@
1
+ import { statusPresentationFrame, activityMessageFrame } from "./status-presentation.ts";
2
+ import type {
3
+ TuiActivityPresentation,
4
+ TuiAnimationSmoothness,
5
+ TuiAnimationSpeed,
6
+ TuiRequestPhase,
7
+ } from "./appearance.ts";
8
+ import type { TuiTheme } from "./color/theme.ts";
9
+ import {
10
+ activityFrame,
11
+ animationSmoothnessCadenceMs,
12
+ configuredAnimationCadenceMs,
13
+ type ActivityFrame,
14
+ } from "./motion.ts";
15
+
16
+ export interface ActivityPresentationOptions {
17
+ animationSpeed?: TuiAnimationSpeed;
18
+ animationSmoothness?: TuiAnimationSmoothness;
19
+ reducedMotion?: boolean;
20
+ }
21
+
22
+ /** Render an inline activity composition or one exclusive status presentation. */
23
+ export function activityPresentationFrame(
24
+ colors: TuiTheme,
25
+ presentation: TuiActivityPresentation,
26
+ phase: TuiRequestPhase,
27
+ phaseLabel: string,
28
+ elapsedMs: number,
29
+ width: number,
30
+ options: ActivityPresentationOptions = {},
31
+ ): ActivityFrame {
32
+ if (presentation.kind === "inline") {
33
+ const text =
34
+ presentation.messageStyle === "phase"
35
+ ? phaseLabel
36
+ : activityMessageFrame(elapsedMs, {
37
+ animationSpeed: options.animationSpeed,
38
+ reducedMotion: options.reducedMotion,
39
+ });
40
+ return activityFrame(colors, text, elapsedMs, {
41
+ indicatorStyle: presentation.indicatorStyle,
42
+ textEffectStyle: presentation.textEffectStyle,
43
+ textEffectScope: presentation.textEffectScope,
44
+ pulseEffectStyle: presentation.pulseEffectStyle,
45
+ animationSpeed: options.animationSpeed,
46
+ animationSmoothness: options.animationSmoothness,
47
+ reducedMotion: options.reducedMotion,
48
+ });
49
+ }
50
+ return {
51
+ marker: "",
52
+ text: statusPresentationFrame(colors, presentation.style, elapsedMs, width, {
53
+ animationSpeed: options.animationSpeed,
54
+ phase,
55
+ reducedMotion: options.reducedMotion,
56
+ }),
57
+ };
58
+ }
59
+
60
+ /** Resolve the repaint cadence from the same presentation plan used to render frames. */
61
+ export function activityPresentationCadenceMs(
62
+ presentation: TuiActivityPresentation,
63
+ smoothness: TuiAnimationSmoothness,
64
+ speed: TuiAnimationSpeed,
65
+ ): number | undefined {
66
+ return presentation.kind === "inline"
67
+ ? configuredAnimationCadenceMs(
68
+ presentation.indicatorStyle,
69
+ presentation.textEffectStyle,
70
+ smoothness,
71
+ speed,
72
+ presentation.pulseEffectStyle,
73
+ )
74
+ : animationSmoothnessCadenceMs(smoothness);
75
+ }