Repository: anomalyco/opentui Branch: main Commit: 8cb2a5ae0023 Files: 663 Total size: 8.0 MB Directory structure: gitextract_ou224iei/ ├── .editorconfig ├── .github/ │ ├── CODEOWNERS │ └── workflows/ │ ├── build-core.yml │ ├── build-examples.yml │ ├── build-native.yml │ ├── build-react.yml │ ├── build-solid.yml │ ├── deploy.yml │ ├── npm-latest-release.yml │ ├── npm-release.yml │ ├── opencode.yml │ ├── pkg-pr-new.yml │ ├── prettier.yml │ ├── release.yml │ └── review.yml ├── .gitignore ├── .prettierignore ├── .zig-version ├── AGENTS.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── opentui.pc.in ├── package.json ├── packages/ │ ├── core/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── dev/ │ │ │ ├── keypress-debug-renderer.ts │ │ │ ├── keypress-debug.ts │ │ │ ├── print-env-vars.ts │ │ │ ├── test-tmux-graphics-334.sh │ │ │ └── thai-debug-test.ts │ │ ├── docs/ │ │ │ └── development.md │ │ ├── package.json │ │ ├── scripts/ │ │ │ ├── build.ts │ │ │ └── publish.ts │ │ ├── src/ │ │ │ ├── 3d/ │ │ │ │ ├── SpriteResourceManager.ts │ │ │ │ ├── SpriteUtils.ts │ │ │ │ ├── TextureUtils.ts │ │ │ │ ├── ThreeRenderable.ts │ │ │ │ ├── WGPURenderer.ts │ │ │ │ ├── animation/ │ │ │ │ │ ├── ExplodingSpriteEffect.ts │ │ │ │ │ ├── PhysicsExplodingSpriteEffect.ts │ │ │ │ │ ├── SpriteAnimator.ts │ │ │ │ │ └── SpriteParticleGenerator.ts │ │ │ │ ├── canvas.ts │ │ │ │ ├── index.ts │ │ │ │ ├── physics/ │ │ │ │ │ ├── PlanckPhysicsAdapter.ts │ │ │ │ │ ├── RapierPhysicsAdapter.ts │ │ │ │ │ └── physics-interface.ts │ │ │ │ └── shaders/ │ │ │ │ └── supersampling.wgsl │ │ │ ├── 3d.ts │ │ │ ├── NativeSpanFeed.ts │ │ │ ├── Renderable.ts │ │ │ ├── __snapshots__/ │ │ │ │ └── buffer.test.ts.snap │ │ │ ├── animation/ │ │ │ │ ├── Timeline.test.ts │ │ │ │ └── Timeline.ts │ │ │ ├── ansi.ts │ │ │ ├── benchmark/ │ │ │ │ ├── .gitignore │ │ │ │ ├── attenuation-benchmark.ts │ │ │ │ ├── colormatrix-benchmark.ts │ │ │ │ ├── gain-benchmark.ts │ │ │ │ ├── latest-all-bench-run.json │ │ │ │ ├── latest-async-bench-run.json │ │ │ │ ├── latest-default-bench-run.json │ │ │ │ ├── latest-large-bench-run.json │ │ │ │ ├── latest-quick-bench-run.json │ │ │ │ ├── markdown-benchmark.ts │ │ │ │ ├── native-span-feed-async-benchmark.ts │ │ │ │ ├── native-span-feed-benchmark.md │ │ │ │ ├── native-span-feed-benchmark.ts │ │ │ │ ├── native-span-feed-compare.ts │ │ │ │ ├── renderer-benchmark.ts │ │ │ │ └── text-table-benchmark.ts │ │ │ ├── buffer.test.ts │ │ │ ├── buffer.ts │ │ │ ├── console.test.ts │ │ │ ├── console.ts │ │ │ ├── edit-buffer.test.ts │ │ │ ├── edit-buffer.ts │ │ │ ├── editor-view.test.ts │ │ │ ├── editor-view.ts │ │ │ ├── examples/ │ │ │ │ ├── ascii-font-selection-demo.ts │ │ │ │ ├── assets/ │ │ │ │ │ └── hast-example.json │ │ │ │ ├── build.ts │ │ │ │ ├── code-demo.ts │ │ │ │ ├── console-demo.ts │ │ │ │ ├── core-plugin-slots-demo.ts │ │ │ │ ├── diff-demo.ts │ │ │ │ ├── draggable-three-demo.ts │ │ │ │ ├── editor-demo.ts │ │ │ │ ├── extmarks-demo.ts │ │ │ │ ├── focus-restore-demo.ts │ │ │ │ ├── fonts.ts │ │ │ │ ├── fractal-shader-demo.ts │ │ │ │ ├── framebuffer-demo.ts │ │ │ │ ├── full-unicode-demo.ts │ │ │ │ ├── golden-star-demo.ts │ │ │ │ ├── grayscale-buffer-demo.ts │ │ │ │ ├── hast-syntax-highlighting-demo.ts │ │ │ │ ├── index.ts │ │ │ │ ├── input-demo.ts │ │ │ │ ├── input-select-layout-demo.ts │ │ │ │ ├── install.sh │ │ │ │ ├── keypress-debug-demo.ts │ │ │ │ ├── lib/ │ │ │ │ │ ├── HexList.ts │ │ │ │ │ ├── PaletteGrid.ts │ │ │ │ │ ├── standalone-keys.ts │ │ │ │ │ └── tab-controller.ts │ │ │ │ ├── lights-phong-demo.ts │ │ │ │ ├── link-demo.ts │ │ │ │ ├── live-state-demo.ts │ │ │ │ ├── markdown-demo.ts │ │ │ │ ├── mouse-interaction-demo.ts │ │ │ │ ├── nested-zindex-demo.ts │ │ │ │ ├── opacity-example.ts │ │ │ │ ├── opentui-demo.ts │ │ │ │ ├── physx-planck-2d-demo.ts │ │ │ │ ├── physx-rapier-2d-demo.ts │ │ │ │ ├── relative-positioning-demo.ts │ │ │ │ ├── scroll-example.ts │ │ │ │ ├── scrollbox-mouse-test.ts │ │ │ │ ├── scrollbox-overlay-hit-test.ts │ │ │ │ ├── select-demo.ts │ │ │ │ ├── shader-cube-demo.ts │ │ │ │ ├── simple-layout-example.ts │ │ │ │ ├── slider-demo.ts │ │ │ │ ├── split-mode-demo.ts │ │ │ │ ├── sprite-animation-demo.ts │ │ │ │ ├── sprite-particle-generator-demo.ts │ │ │ │ ├── static-sprite-demo.ts │ │ │ │ ├── sticky-scroll-example.ts │ │ │ │ ├── styled-text-demo.ts │ │ │ │ ├── tab-select-demo.ts │ │ │ │ ├── terminal-title.ts │ │ │ │ ├── terminal.ts │ │ │ │ ├── text-node-demo.ts │ │ │ │ ├── text-selection-demo.ts │ │ │ │ ├── text-table-demo.ts │ │ │ │ ├── text-truncation-demo.ts │ │ │ │ ├── text-wrap.ts │ │ │ │ ├── texture-loading-demo.ts │ │ │ │ ├── timeline-example.ts │ │ │ │ ├── transparency-demo.ts │ │ │ │ └── vnode-composition-demo.ts │ │ │ ├── index.ts │ │ │ ├── lib/ │ │ │ │ ├── KeyHandler.integration.test.ts │ │ │ │ ├── KeyHandler.stopPropagation.test.ts │ │ │ │ ├── KeyHandler.test.ts │ │ │ │ ├── KeyHandler.ts │ │ │ │ ├── RGBA.test.ts │ │ │ │ ├── RGBA.ts │ │ │ │ ├── ascii.font.ts │ │ │ │ ├── border.test.ts │ │ │ │ ├── border.ts │ │ │ │ ├── bunfs.test.ts │ │ │ │ ├── bunfs.ts │ │ │ │ ├── clipboard.test.ts │ │ │ │ ├── clipboard.ts │ │ │ │ ├── clock.ts │ │ │ │ ├── data-paths.test.ts │ │ │ │ ├── data-paths.ts │ │ │ │ ├── debounce.ts │ │ │ │ ├── detect-links.test.ts │ │ │ │ ├── detect-links.ts │ │ │ │ ├── env.test.ts │ │ │ │ ├── env.ts │ │ │ │ ├── extmarks-history.ts │ │ │ │ ├── extmarks-multiwidth.test.ts │ │ │ │ ├── extmarks.test.ts │ │ │ │ ├── extmarks.ts │ │ │ │ ├── fonts/ │ │ │ │ │ ├── block.json │ │ │ │ │ ├── grid.json │ │ │ │ │ ├── huge.json │ │ │ │ │ ├── pallet.json │ │ │ │ │ ├── shade.json │ │ │ │ │ ├── slick.json │ │ │ │ │ └── tiny.json │ │ │ │ ├── hast-styled-text.ts │ │ │ │ ├── index.ts │ │ │ │ ├── keymapping.test.ts │ │ │ │ ├── keymapping.ts │ │ │ │ ├── objects-in-viewport.test.ts │ │ │ │ ├── objects-in-viewport.ts │ │ │ │ ├── output.capture.ts │ │ │ │ ├── parse.keypress-kitty.protocol.test.ts │ │ │ │ ├── parse.keypress-kitty.test.ts │ │ │ │ ├── parse.keypress-kitty.ts │ │ │ │ ├── parse.keypress.test.ts │ │ │ │ ├── parse.keypress.ts │ │ │ │ ├── parse.mouse.test.ts │ │ │ │ ├── parse.mouse.ts │ │ │ │ ├── paste.ts │ │ │ │ ├── queue.ts │ │ │ │ ├── renderable.validations.test.ts │ │ │ │ ├── renderable.validations.ts │ │ │ │ ├── scroll-acceleration.ts │ │ │ │ ├── selection.ts │ │ │ │ ├── singleton.ts │ │ │ │ ├── stdin-parser.test.ts │ │ │ │ ├── stdin-parser.ts │ │ │ │ ├── styled-text.ts │ │ │ │ ├── terminal-capability-detection.test.ts │ │ │ │ ├── terminal-capability-detection.ts │ │ │ │ ├── terminal-palette.test.ts │ │ │ │ ├── terminal-palette.ts │ │ │ │ ├── tree-sitter/ │ │ │ │ │ ├── assets/ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ ├── javascript/ │ │ │ │ │ │ │ ├── highlights.scm │ │ │ │ │ │ │ └── tree-sitter-javascript.wasm │ │ │ │ │ │ ├── markdown/ │ │ │ │ │ │ │ ├── highlights.scm │ │ │ │ │ │ │ ├── injections.scm │ │ │ │ │ │ │ └── tree-sitter-markdown.wasm │ │ │ │ │ │ ├── markdown_inline/ │ │ │ │ │ │ │ ├── highlights.scm │ │ │ │ │ │ │ └── tree-sitter-markdown_inline.wasm │ │ │ │ │ │ ├── typescript/ │ │ │ │ │ │ │ ├── highlights.scm │ │ │ │ │ │ │ └── tree-sitter-typescript.wasm │ │ │ │ │ │ ├── update.ts │ │ │ │ │ │ └── zig/ │ │ │ │ │ │ ├── highlights.scm │ │ │ │ │ │ └── tree-sitter-zig.wasm │ │ │ │ │ ├── assets.d.ts │ │ │ │ │ ├── cache.test.ts │ │ │ │ │ ├── client.test.ts │ │ │ │ │ ├── client.ts │ │ │ │ │ ├── default-parsers.ts │ │ │ │ │ ├── download-utils.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── parser.worker.ts │ │ │ │ │ ├── parsers-config.ts │ │ │ │ │ ├── resolve-ft.test.ts │ │ │ │ │ ├── resolve-ft.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── tree-sitter-styled-text.test.ts │ │ │ │ ├── tree-sitter-styled-text.ts │ │ │ │ ├── validate-dir-name.ts │ │ │ │ ├── yoga.options.test.ts │ │ │ │ └── yoga.options.ts │ │ │ ├── plugins/ │ │ │ │ ├── core-slot.ts │ │ │ │ ├── registry.ts │ │ │ │ └── types.ts │ │ │ ├── post/ │ │ │ │ ├── effects.ts │ │ │ │ ├── filters.ts │ │ │ │ └── matrices.ts │ │ │ ├── renderables/ │ │ │ │ ├── ASCIIFont.ts │ │ │ │ ├── Box.test.ts │ │ │ │ ├── Box.ts │ │ │ │ ├── Code.test.ts │ │ │ │ ├── Code.ts │ │ │ │ ├── Diff.regression.test.ts │ │ │ │ ├── Diff.test.ts │ │ │ │ ├── Diff.ts │ │ │ │ ├── EditBufferRenderable.ts │ │ │ │ ├── FrameBuffer.ts │ │ │ │ ├── Input.test.ts │ │ │ │ ├── Input.ts │ │ │ │ ├── LineNumberRenderable.ts │ │ │ │ ├── Markdown.ts │ │ │ │ ├── ScrollBar.ts │ │ │ │ ├── ScrollBox.ts │ │ │ │ ├── Select.test.ts │ │ │ │ ├── Select.ts │ │ │ │ ├── Slider.test.ts │ │ │ │ ├── Slider.ts │ │ │ │ ├── TabSelect.test.ts │ │ │ │ ├── TabSelect.ts │ │ │ │ ├── Text.selection-buffer.test.ts │ │ │ │ ├── Text.test.ts │ │ │ │ ├── Text.ts │ │ │ │ ├── TextBufferRenderable.ts │ │ │ │ ├── TextNode.test.ts │ │ │ │ ├── TextNode.ts │ │ │ │ ├── TextTable.test.ts │ │ │ │ ├── TextTable.ts │ │ │ │ ├── Textarea.ts │ │ │ │ ├── TimeToFirstDraw.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── Code.test.ts.snap │ │ │ │ │ ├── Diff.test.ts.snap │ │ │ │ │ ├── Text.test.ts.snap │ │ │ │ │ └── TextTable.test.ts.snap │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── LineNumberRenderable.scrollbox-simple.test.ts │ │ │ │ │ ├── LineNumberRenderable.scrollbox.test.ts │ │ │ │ │ ├── LineNumberRenderable.test.ts │ │ │ │ │ ├── LineNumberRenderable.wrapping.test.ts │ │ │ │ │ ├── Markdown.code-colors.test.ts │ │ │ │ │ ├── Markdown.test.ts │ │ │ │ │ ├── MultiRenderable.selection.test.ts │ │ │ │ │ ├── Textarea.buffer.test.ts │ │ │ │ │ ├── Textarea.destroyed-events.test.ts │ │ │ │ │ ├── Textarea.editing.test.ts │ │ │ │ │ ├── Textarea.error-handling.test.ts │ │ │ │ │ ├── Textarea.events.test.ts │ │ │ │ │ ├── Textarea.highlights.test.ts │ │ │ │ │ ├── Textarea.keybinding.test.ts │ │ │ │ │ ├── Textarea.paste.test.ts │ │ │ │ │ ├── Textarea.rendering.test.ts │ │ │ │ │ ├── Textarea.scroll.test.ts │ │ │ │ │ ├── Textarea.selection.test.ts │ │ │ │ │ ├── Textarea.stress.test.ts │ │ │ │ │ ├── Textarea.undo-redo.test.ts │ │ │ │ │ ├── Textarea.visual-lines.test.ts │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ ├── LineNumberRenderable.code.test.ts.snap │ │ │ │ │ │ ├── LineNumberRenderable.scrollbox-simple.test.ts.snap │ │ │ │ │ │ ├── LineNumberRenderable.scrollbox.test.ts.snap │ │ │ │ │ │ ├── LineNumberRenderable.test.ts.snap │ │ │ │ │ │ └── Textarea.rendering.test.ts.snap │ │ │ │ │ ├── markdown-parser.test.ts │ │ │ │ │ └── renderable-test-utils.ts │ │ │ │ ├── composition/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── VRenderable.ts │ │ │ │ │ ├── constructs.ts │ │ │ │ │ └── vnode.ts │ │ │ │ ├── index.ts │ │ │ │ └── markdown-parser.ts │ │ │ ├── renderer.ts │ │ │ ├── runtime-plugin-support.ts │ │ │ ├── runtime-plugin.ts │ │ │ ├── syntax-style.test.ts │ │ │ ├── syntax-style.ts │ │ │ ├── testing/ │ │ │ │ ├── README.md │ │ │ │ ├── capture-spans.test.ts │ │ │ │ ├── integration.test.ts │ │ │ │ ├── manual-clock.ts │ │ │ │ ├── mock-keys.test.ts │ │ │ │ ├── mock-keys.ts │ │ │ │ ├── mock-mouse.test.ts │ │ │ │ ├── mock-mouse.ts │ │ │ │ ├── mock-tree-sitter-client.ts │ │ │ │ ├── spy.ts │ │ │ │ ├── test-recorder.test.ts │ │ │ │ ├── test-recorder.ts │ │ │ │ └── test-renderer.ts │ │ │ ├── testing.ts │ │ │ ├── tests/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── absolute-positioning.snapshot.test.ts.snap │ │ │ │ │ ├── renderable.snapshot.test.ts.snap │ │ │ │ │ └── scrollbox.test.ts.snap │ │ │ │ ├── absolute-positioning.snapshot.test.ts │ │ │ │ ├── allocator-stats.test.ts │ │ │ │ ├── destroy-during-render.test.ts │ │ │ │ ├── hover-cursor.test.ts │ │ │ │ ├── native-span-feed-async.test.ts │ │ │ │ ├── native-span-feed-close.test.ts │ │ │ │ ├── native-span-feed-coverage.test.ts │ │ │ │ ├── native-span-feed-edge-cases.test.ts │ │ │ │ ├── native-span-feed-use-after-free.test.ts │ │ │ │ ├── opacity.test.ts │ │ │ │ ├── renderable.snapshot.test.ts │ │ │ │ ├── renderable.test.ts │ │ │ │ ├── renderer.clock.test.ts │ │ │ │ ├── renderer.console-startup.test.ts │ │ │ │ ├── renderer.control.test.ts │ │ │ │ ├── renderer.core-slot-binding.test.ts │ │ │ │ ├── renderer.cursor.test.ts │ │ │ │ ├── renderer.destroy-during-render.test.ts │ │ │ │ ├── renderer.focus-restore.test.ts │ │ │ │ ├── renderer.focus.test.ts │ │ │ │ ├── renderer.idle.test.ts │ │ │ │ ├── renderer.input.test.ts │ │ │ │ ├── renderer.kitty-flags.test.ts │ │ │ │ ├── renderer.mouse.test.ts │ │ │ │ ├── renderer.palette.test.ts │ │ │ │ ├── renderer.selection.test.ts │ │ │ │ ├── renderer.slot-registry.test.ts │ │ │ │ ├── renderer.useMouse.test.ts │ │ │ │ ├── runtime-plugin-resolve-roots.fixture.ts │ │ │ │ ├── runtime-plugin-support.fixture.ts │ │ │ │ ├── runtime-plugin-support.test.ts │ │ │ │ ├── runtime-plugin.fixture.ts │ │ │ │ ├── runtime-plugin.test.ts │ │ │ │ ├── scrollbox-culling-bug.test.ts │ │ │ │ ├── scrollbox-hitgrid-resize.test.ts │ │ │ │ ├── scrollbox-hitgrid.test.ts │ │ │ │ ├── scrollbox.test.ts │ │ │ │ ├── wrap-resize-perf.test.ts │ │ │ │ └── yoga-setters.test.ts │ │ │ ├── text-buffer-view.test.ts │ │ │ ├── text-buffer-view.ts │ │ │ ├── text-buffer.test.ts │ │ │ ├── text-buffer.ts │ │ │ ├── types.ts │ │ │ ├── utils.ts │ │ │ ├── zig/ │ │ │ │ ├── ansi.zig │ │ │ │ ├── bench/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── buffer-draw-text-buffer_bench.zig │ │ │ │ │ ├── edit-buffer_bench.zig │ │ │ │ │ ├── native-span-feed_bench.zig │ │ │ │ │ ├── rope-markers_bench.zig │ │ │ │ │ ├── rope_bench.zig │ │ │ │ │ ├── styled-text_bench.zig │ │ │ │ │ ├── text-buffer-coords_bench.zig │ │ │ │ │ ├── text-buffer-view_bench.zig │ │ │ │ │ ├── text-chunk-graphemes_bench.zig │ │ │ │ │ └── utf8_bench.zig │ │ │ │ ├── bench-utils.zig │ │ │ │ ├── bench.zig │ │ │ │ ├── buffer-methods.zig │ │ │ │ ├── buffer.zig │ │ │ │ ├── build.zig │ │ │ │ ├── build.zig.zon │ │ │ │ ├── edit-buffer.zig │ │ │ │ ├── editor-view.zig │ │ │ │ ├── event-bus.zig │ │ │ │ ├── event-emitter.zig │ │ │ │ ├── file-logger.zig │ │ │ │ ├── grapheme.zig │ │ │ │ ├── lib.zig │ │ │ │ ├── link.zig │ │ │ │ ├── logger.zig │ │ │ │ ├── mem-registry.zig │ │ │ │ ├── native-span-feed-bench-lib.zig │ │ │ │ ├── native-span-feed.zig │ │ │ │ ├── renderer.zig │ │ │ │ ├── rope.zig │ │ │ │ ├── syntax-style.zig │ │ │ │ ├── terminal.zig │ │ │ │ ├── test.zig │ │ │ │ ├── tests/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── buffer-methods_test.zig │ │ │ │ │ ├── buffer_test.zig │ │ │ │ │ ├── edit-buffer-history_test.zig │ │ │ │ │ ├── edit-buffer_test.zig │ │ │ │ │ ├── editor-view_test.zig │ │ │ │ │ ├── event-emitter_test.zig │ │ │ │ │ ├── grapheme_test.zig │ │ │ │ │ ├── link_test.zig │ │ │ │ │ ├── mem-registry_test.zig │ │ │ │ │ ├── memory_leak_regression_test.zig │ │ │ │ │ ├── native-span-feed_test.zig │ │ │ │ │ ├── renderer_test.zig │ │ │ │ │ ├── rope-nested_test.zig │ │ │ │ │ ├── rope_fuzz_test.zig │ │ │ │ │ ├── rope_test.zig │ │ │ │ │ ├── segment-merge.test.zig │ │ │ │ │ ├── syntax-style_test.zig │ │ │ │ │ ├── terminal_test.zig │ │ │ │ │ ├── text-buffer-drawing_test.zig │ │ │ │ │ ├── text-buffer-highlights_test.zig │ │ │ │ │ ├── text-buffer-iterators_test.zig │ │ │ │ │ ├── text-buffer-segment_test.zig │ │ │ │ │ ├── text-buffer-selection_test.zig │ │ │ │ │ ├── text-buffer-selection_viewport_test.zig │ │ │ │ │ ├── text-buffer-view_test.zig │ │ │ │ │ ├── text-buffer_test.zig │ │ │ │ │ ├── unicode-width-map.zon │ │ │ │ │ ├── utf8_no_zwj_test.zig │ │ │ │ │ ├── utf8_test.zig │ │ │ │ │ ├── utf8_wcwidth_cursor_test.zig │ │ │ │ │ ├── utf8_wcwidth_test.zig │ │ │ │ │ ├── word-wrap-editing_test.zig │ │ │ │ │ └── wrap-cache-perf_test.zig │ │ │ │ ├── text-buffer-iterators.zig │ │ │ │ ├── text-buffer-segment.zig │ │ │ │ ├── text-buffer-view.zig │ │ │ │ ├── text-buffer.zig │ │ │ │ ├── utf8.zig │ │ │ │ └── utils.zig │ │ │ ├── zig-structs.ts │ │ │ └── zig.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── react/ │ │ ├── README.md │ │ ├── docs/ │ │ │ └── EXTEND.md │ │ ├── examples/ │ │ │ ├── .plugin/ │ │ │ │ ├── index.tsx │ │ │ │ └── slot-components.tsx │ │ │ ├── animation.tsx │ │ │ ├── ascii.tsx │ │ │ ├── basic.tsx │ │ │ ├── borders.tsx │ │ │ ├── box.tsx │ │ │ ├── build.ts │ │ │ ├── counter.tsx │ │ │ ├── diff.tsx │ │ │ ├── extend-example.tsx │ │ │ ├── external-plugin-slots-demo.tsx │ │ │ ├── flush-sync.tsx │ │ │ ├── index.tsx │ │ │ ├── line-number.tsx │ │ │ ├── opacity.tsx │ │ │ ├── plugin-slots-errors.tsx │ │ │ ├── scroll.tsx │ │ │ ├── text.tsx │ │ │ └── tsconfig.json │ │ ├── jsx-dev-runtime.d.ts │ │ ├── jsx-dev-runtime.js │ │ ├── jsx-namespace.d.ts │ │ ├── jsx-runtime.d.ts │ │ ├── jsx-runtime.js │ │ ├── package.json │ │ ├── scripts/ │ │ │ ├── build.ts │ │ │ ├── publish.ts │ │ │ └── runtime-plugin-support.ts │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── app.tsx │ │ │ │ ├── error-boundary.tsx │ │ │ │ ├── index.ts │ │ │ │ └── text.ts │ │ │ ├── hooks/ │ │ │ │ ├── index.ts │ │ │ │ ├── use-event.ts │ │ │ │ ├── use-keyboard.ts │ │ │ │ ├── use-renderer.ts │ │ │ │ ├── use-resize.ts │ │ │ │ ├── use-terminal-dimensions.ts │ │ │ │ └── use-timeline.ts │ │ │ ├── index.ts │ │ │ ├── plugins/ │ │ │ │ └── slot.tsx │ │ │ ├── reconciler/ │ │ │ │ ├── devtools-polyfill.ts │ │ │ │ ├── devtools.ts │ │ │ │ ├── host-config.ts │ │ │ │ ├── reconciler.ts │ │ │ │ └── renderer.ts │ │ │ ├── test-utils.ts │ │ │ ├── time-to-first-draw.tsx │ │ │ ├── types/ │ │ │ │ ├── components.ts │ │ │ │ └── host.ts │ │ │ └── utils/ │ │ │ ├── id.ts │ │ │ └── index.ts │ │ ├── tests/ │ │ │ ├── __snapshots__/ │ │ │ │ └── layout.test.tsx.snap │ │ │ ├── destroy-crash.test.tsx │ │ │ ├── layout.test.tsx │ │ │ ├── link.test.tsx │ │ │ ├── runtime-plugin-support.fixture.ts │ │ │ ├── runtime-plugin-support.test.ts │ │ │ └── slot.test.tsx │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── solid/ │ │ ├── README.md │ │ ├── bunfig.toml │ │ ├── examples/ │ │ │ ├── .plugin/ │ │ │ │ ├── index.tsx │ │ │ │ ├── package.json │ │ │ │ └── slot-components.tsx │ │ │ ├── build.ts │ │ │ ├── components/ │ │ │ │ ├── ExampleSelector.tsx │ │ │ │ ├── animation-demo.tsx │ │ │ │ ├── autocomplete-demo.tsx │ │ │ │ ├── code-demo.tsx │ │ │ │ ├── custom-scroll-accel-demo.tsx │ │ │ │ ├── diff-demo.tsx │ │ │ │ ├── extend-demo.tsx │ │ │ │ ├── external-plugin-path.test.ts │ │ │ │ ├── external-plugin-path.ts │ │ │ │ ├── external-plugin-runtime.ts │ │ │ │ ├── external-plugin-slots-demo.tsx │ │ │ │ ├── input-demo.tsx │ │ │ │ ├── line-number-demo.tsx │ │ │ │ ├── mouse-demo.tsx │ │ │ │ ├── plugin-slots-demo.tsx │ │ │ │ ├── scroll-demo.tsx │ │ │ │ ├── tab-select-demo.tsx │ │ │ │ ├── text-selection-demo.tsx │ │ │ │ ├── text-style-demo.tsx │ │ │ │ ├── text-truncation-demo.tsx │ │ │ │ ├── textarea-demo.tsx │ │ │ │ ├── textarea-keybindings.ts │ │ │ │ └── textarea-minimal-demo.tsx │ │ │ ├── index.tsx │ │ │ ├── package.json │ │ │ ├── repro-empty-styled-text.tsx │ │ │ ├── repro-filter-list.tsx │ │ │ ├── repro-onSubmit.tsx │ │ │ ├── session.tsx │ │ │ └── tsconfig.json │ │ ├── index.ts │ │ ├── jsx-runtime.d.ts │ │ ├── package.json │ │ ├── scripts/ │ │ │ ├── build.ts │ │ │ ├── preload.ts │ │ │ ├── publish.ts │ │ │ ├── runtime-plugin-support.ts │ │ │ └── solid-plugin.ts │ │ ├── src/ │ │ │ ├── elements/ │ │ │ │ ├── extras.ts │ │ │ │ ├── hooks.ts │ │ │ │ ├── index.ts │ │ │ │ └── slot.ts │ │ │ ├── plugins/ │ │ │ │ └── slot.tsx │ │ │ ├── reconciler.ts │ │ │ ├── renderer/ │ │ │ │ ├── index.ts │ │ │ │ ├── universal.d.ts │ │ │ │ └── universal.js │ │ │ ├── time-to-first-draw.tsx │ │ │ ├── types/ │ │ │ │ └── elements.ts │ │ │ └── utils/ │ │ │ ├── id-counter.ts │ │ │ └── log.ts │ │ ├── tests/ │ │ │ ├── __snapshots__/ │ │ │ │ ├── control-flow.test.tsx.snap │ │ │ │ ├── dynamic-collections.test.tsx.snap │ │ │ │ ├── dynamic-portal.test.tsx.snap │ │ │ │ ├── layout.test.tsx.snap │ │ │ │ ├── line-number-debug.test.tsx.snap │ │ │ │ ├── line-number-scrollbox.test.tsx.snap │ │ │ │ └── textarea.test.tsx.snap │ │ │ ├── box.test.tsx │ │ │ ├── control-flow.test.tsx │ │ │ ├── cursor-behavior.test.tsx │ │ │ ├── destroy-crash.test.tsx │ │ │ ├── destroy-race-repro.test.ts │ │ │ ├── destroy-race.fixture.tsx │ │ │ ├── diff.test.tsx │ │ │ ├── dynamic-collections.test.tsx │ │ │ ├── dynamic-portal.test.tsx │ │ │ ├── events.test.tsx │ │ │ ├── layout.test.tsx │ │ │ ├── line-number-scrollbox.test.tsx │ │ │ ├── line-number.test.tsx │ │ │ ├── link.test.tsx │ │ │ ├── runtime-plugin-support-preload.fixture.ts │ │ │ ├── runtime-plugin-support-preload.test.ts │ │ │ ├── runtime-plugin-support.fixture.ts │ │ │ ├── runtime-plugin-support.test.ts │ │ │ ├── scrollbox-cleanchildren.test.tsx │ │ │ ├── scrollbox-content.test.tsx │ │ │ ├── slot.test.tsx │ │ │ ├── solid-plugin.fixture.ts │ │ │ ├── solid-plugin.test.ts │ │ │ ├── sticky-scroll.test.tsx │ │ │ └── textarea.test.tsx │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ └── web/ │ ├── .gitignore │ ├── astro.config.mjs │ ├── package.json │ ├── scripts/ │ │ ├── test-doc-examples.ts │ │ └── verify-doc-examples.ts │ ├── src/ │ │ ├── components/ │ │ │ └── TuiSurface.astro │ │ ├── content/ │ │ │ ├── config.ts │ │ │ └── docs/ │ │ │ ├── bindings/ │ │ │ │ ├── react.mdx │ │ │ │ └── solid.mdx │ │ │ ├── components/ │ │ │ │ ├── ascii-font.mdx │ │ │ │ ├── box.mdx │ │ │ │ ├── code.mdx │ │ │ │ ├── diff.mdx │ │ │ │ ├── frame-buffer.mdx │ │ │ │ ├── input.mdx │ │ │ │ ├── line-number.mdx │ │ │ │ ├── markdown.mdx │ │ │ │ ├── scrollbar.mdx │ │ │ │ ├── scrollbox.mdx │ │ │ │ ├── select.mdx │ │ │ │ ├── slider.mdx │ │ │ │ ├── tab-select.mdx │ │ │ │ ├── text.mdx │ │ │ │ └── textarea.mdx │ │ │ ├── core-concepts/ │ │ │ │ ├── colors.mdx │ │ │ │ ├── console.mdx │ │ │ │ ├── constructs.mdx │ │ │ │ ├── keyboard.mdx │ │ │ │ ├── layout.mdx │ │ │ │ ├── lifecycle.mdx │ │ │ │ ├── renderables-vs-constructs.mdx │ │ │ │ ├── renderables.mdx │ │ │ │ └── renderer.mdx │ │ │ ├── getting-started.mdx │ │ │ ├── plugins/ │ │ │ │ ├── core.mdx │ │ │ │ ├── react.mdx │ │ │ │ ├── slots.mdx │ │ │ │ └── solid.mdx │ │ │ └── reference/ │ │ │ ├── env-vars.mdx │ │ │ └── tree-sitter.mdx │ │ ├── layouts/ │ │ │ ├── Base.astro │ │ │ └── Docs.astro │ │ ├── pages/ │ │ │ ├── 404.astro │ │ │ ├── docs/ │ │ │ │ └── [...slug].astro │ │ │ └── index.astro │ │ └── styles/ │ │ └── global.css │ └── tsconfig.json └── scripts/ ├── create-snapshot.sh ├── link-opentui-dev.sh ├── pre-publish.ts └── prepare-release.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 insert_final_newline = true end_of_line = lf indent_style = space indent_size = 2 max_line_length = 120 ================================================ FILE: .github/CODEOWNERS ================================================ * @kommander @msmps @Hona @simonklee /packages/react/ @msmps @Adictya @fezproof @kommander @Hona @simonklee /packages/solid/ @Adictya @fezproof @msmps @kommander @Hona @simonklee ================================================ FILE: .github/workflows/build-core.yml ================================================ name: Build Core on: push: pull_request: branches: [main] env: ZIG_VERSION: 0.15.2 # Workaround for bug in Zig 0.15.2 (fixed in next version) # https://github.com/ziglang/zig/issues/25805 ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-global-cache jobs: build: name: Build Native Libraries runs-on: macos-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Zig uses: goto-bus-stop/setup-zig@v2 with: version: ${{ env.ZIG_VERSION }} - name: Install dependencies run: bun install - name: Build native libraries (cross-compile all platforms) run: | cd packages/core bun run build:native --all - name: Upload native artifacts uses: actions/upload-artifact@v4 with: name: native-libraries path: packages/core/node_modules/@opentui/ retention-days: 1 test: name: Test (${{ matrix.os }}) needs: build strategy: matrix: include: - os: macos-latest platform: darwin-arm64 - os: ubuntu-latest platform: linux-x64 - os: windows-latest platform: win32-x64 runs-on: ${{ matrix.os }} defaults: run: shell: bash steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Zig uses: goto-bus-stop/setup-zig@v2 with: version: ${{ env.ZIG_VERSION }} - name: Install dependencies run: bun install - name: Download native artifacts uses: actions/download-artifact@v4 with: name: native-libraries path: packages/core/node_modules/@opentui/ - name: Verify native library run: | echo "Checking for ${{ matrix.platform }} native library..." ls -la packages/core/node_modules/@opentui/ ls -la packages/core/node_modules/@opentui/core-${{ matrix.platform }}/ - name: Run native tests run: | cd packages/core/src/zig zig build test --summary all - name: Build TypeScript library run: | cd packages/core bun run build:lib - name: Run TypeScript tests run: | cd packages/core bun run test:js # Gate job for branch protection build-complete: name: Core - Build and Test needs: [test] runs-on: ubuntu-latest if: always() steps: - name: Check test results run: | if [ "${{ needs.test.result }}" != "success" ]; then echo "Tests failed" exit 1 fi echo "All tests passed" ================================================ FILE: .github/workflows/build-examples.yml ================================================ name: Build Examples on: workflow_call: inputs: version: description: "Version being released" required: true type: string isDryRun: description: "Whether this is a dry run release" required: false type: boolean default: false jobs: build-examples: name: Build Example Executables runs-on: macos-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install dependencies FIRST (before copying built packages) run: | echo "Installing base dependencies..." bun install echo "" echo "✅ Base dependencies installed" echo "Note: bun-webgpu will be installed by the build script (src/examples/build.ts) for all platforms" - name: Download npm packages artifact uses: actions/download-artifact@v4 with: name: npm-packages-${{ inputs.version }} - name: Extract and install npm packages run: | set -e echo "Extracting npm packages..." test -f npm-packages.zip || (echo "❌ npm-packages.zip not found!" && exit 1) unzip -q npm-packages.zip # Create node_modules structure mkdir -p node_modules/@opentui mkdir -p packages/core/node_modules/@opentui # Copy core dist (required) echo "Copying core dist..." test -d "npm-packages/core-dist" || (echo "❌ core-dist not found in artifact!" && exit 1) cp -r npm-packages/core-dist packages/core/dist test -f packages/core/dist/package.json || (echo "❌ core dist/package.json missing after copy!" && exit 1) echo "✅ Core dist copied" # Copy native packages to core's node_modules (required - these OVERRIDE the npm versions) echo "Copying built native packages (overriding any npm versions)..." test -d "npm-packages/core-native-packages" || (echo "❌ core-native-packages not found in artifact!" && exit 1) cp -r npm-packages/core-native-packages/* packages/core/node_modules/@opentui/ test -n "$(ls -A packages/core/node_modules/@opentui/)" || (echo "❌ No native packages copied!" && exit 1) echo "✅ Native packages copied" # Copy other package dists (optional) if [ -d "npm-packages/react-dist" ]; then cp -r npm-packages/react-dist packages/react/dist echo "✅ React dist copied" fi if [ -d "npm-packages/solid-dist" ]; then cp -r npm-packages/solid-dist packages/solid/dist echo "✅ Solid dist copied" fi echo "" echo "Package extraction complete:" ls -lah packages/core/dist/ ls -lah packages/core/node_modules/@opentui/ - name: Verify bun-webgpu is available for build run: | echo "Checking bun-webgpu installation..." # Check root node_modules first if [ -d node_modules/bun-webgpu ]; then echo "✅ bun-webgpu found in root node_modules" # Check packages/core/node_modules elif [ -d packages/core/node_modules/bun-webgpu ]; then echo "✅ bun-webgpu found in packages/core/node_modules" else echo "❌ bun-webgpu not found in root or packages/core/node_modules!" echo "Note: The build script will install it, but it should already be present" exit 1 fi # Check for platform-specific packages in .bun cache (where bun install --os="*" --cpu="*" puts them) echo "" echo "Checking for platform-specific bun-webgpu packages in cache..." if [ -d node_modules/.bun/bun-webgpu-darwin-arm64@0.1.4 ]; then echo "✅ bun-webgpu-darwin-arm64 found in cache" else echo "⚠️ bun-webgpu-darwin-arm64 not found (will be installed during build)" fi if [ -d node_modules/.bun/bun-webgpu-darwin-x64@0.1.4 ]; then echo "✅ bun-webgpu-darwin-x64 found in cache" else echo "⚠️ bun-webgpu-darwin-x64 not found (will be installed during build)" fi if [ -d node_modules/.bun/bun-webgpu-linux-x64@0.1.4 ]; then echo "✅ bun-webgpu-linux-x64 found in cache" else echo "⚠️ bun-webgpu-linux-x64 not found (will be installed during build)" fi if [ -d node_modules/.bun/bun-webgpu-win32-x64@0.1.4 ]; then echo "✅ bun-webgpu-win32-x64 found in cache" else echo "⚠️ bun-webgpu-win32-x64 not found (will be installed during build)" fi echo "" echo "✅ bun-webgpu ready for bundling" - name: Build examples run: | set -e cd packages/core bun src/examples/build.ts - name: Verify example builds run: | set -e echo "Verifying example executables..." test -f "packages/core/src/examples/dist/darwin-x64/opentui-examples" || (echo "❌ darwin-x64 example missing!" && exit 1) test -f "packages/core/src/examples/dist/darwin-arm64/opentui-examples" || (echo "❌ darwin-arm64 example missing!" && exit 1) test -f "packages/core/src/examples/dist/linux-x64/opentui-examples" || (echo "❌ linux-x64 example missing!" && exit 1) test -f "packages/core/src/examples/dist/windows-x64/opentui-examples.exe" || (echo "❌ windows-x64 example missing!" && exit 1) echo "✅ All example executables verified" echo "" ls -lah packages/core/src/examples/dist/*/ # Create separate zips for each platform's examples - name: Package examples - darwin-x64 run: | set -e mkdir -p artifacts/examples-darwin-x64 cp packages/core/src/examples/dist/darwin-x64/opentui-examples artifacts/examples-darwin-x64/ cd artifacts zip -r examples-darwin-x64.zip examples-darwin-x64/ test -f examples-darwin-x64.zip || (echo "❌ Failed to create darwin-x64 zip" && exit 1) test -s examples-darwin-x64.zip || (echo "❌ darwin-x64 zip is empty" && exit 1) echo "✅ darwin-x64 packaged successfully ($(du -h examples-darwin-x64.zip | cut -f1))" - name: Package examples - darwin-arm64 run: | set -e mkdir -p artifacts/examples-darwin-arm64 cp packages/core/src/examples/dist/darwin-arm64/opentui-examples artifacts/examples-darwin-arm64/ cd artifacts zip -r examples-darwin-arm64.zip examples-darwin-arm64/ test -f examples-darwin-arm64.zip || (echo "❌ Failed to create darwin-arm64 zip" && exit 1) test -s examples-darwin-arm64.zip || (echo "❌ darwin-arm64 zip is empty" && exit 1) echo "✅ darwin-arm64 packaged successfully ($(du -h examples-darwin-arm64.zip | cut -f1))" - name: Package examples - linux-x64 run: | set -e mkdir -p artifacts/examples-linux-x64 cp packages/core/src/examples/dist/linux-x64/opentui-examples artifacts/examples-linux-x64/ cd artifacts zip -r examples-linux-x64.zip examples-linux-x64/ test -f examples-linux-x64.zip || (echo "❌ Failed to create linux-x64 zip" && exit 1) test -s examples-linux-x64.zip || (echo "❌ linux-x64 zip is empty" && exit 1) echo "✅ linux-x64 packaged successfully ($(du -h examples-linux-x64.zip | cut -f1))" - name: Package examples - windows-x64 run: | set -e mkdir -p artifacts/examples-windows-x64 cp packages/core/src/examples/dist/windows-x64/opentui-examples.exe artifacts/examples-windows-x64/ cd artifacts zip -r examples-windows-x64.zip examples-windows-x64/ test -f examples-windows-x64.zip || (echo "❌ Failed to create windows-x64 zip" && exit 1) test -s examples-windows-x64.zip || (echo "❌ windows-x64 zip is empty" && exit 1) echo "✅ windows-x64 packaged successfully ($(du -h examples-windows-x64.zip | cut -f1))" - name: Verify all artifacts before upload run: | set -e echo "Verifying all artifacts exist..." test -f artifacts/examples-darwin-x64.zip || (echo "❌ examples-darwin-x64.zip missing!" && exit 1) test -f artifacts/examples-darwin-arm64.zip || (echo "❌ examples-darwin-arm64.zip missing!" && exit 1) test -f artifacts/examples-linux-x64.zip || (echo "❌ examples-linux-x64.zip missing!" && exit 1) test -f artifacts/examples-windows-x64.zip || (echo "❌ examples-windows-x64.zip missing!" && exit 1) echo "" echo "✅ All artifacts verified. Ready to upload:" ls -lah artifacts/*.zip - name: Upload example executables uses: actions/upload-artifact@v4 with: name: example-executables-${{ inputs.version }} path: | artifacts/examples-darwin-x64.zip artifacts/examples-darwin-arm64.zip artifacts/examples-linux-x64.zip artifacts/examples-windows-x64.zip if-no-files-found: error retention-days: 30 ================================================ FILE: .github/workflows/build-native.yml ================================================ name: Build Native on: workflow_call: inputs: version: description: "Version being released" required: true type: string isDryRun: description: "Whether this is a dry run release" required: false type: boolean default: false env: ZIG_VERSION: 0.15.2 jobs: build-native: name: Build Native Libraries runs-on: macos-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Zig uses: goto-bus-stop/setup-zig@v2 with: version: ${{ env.ZIG_VERSION }} - name: Install dependencies run: bun install - name: Build packages (cross-compile for all platforms) run: | cd packages/core bun run build:native --all bun run build:lib cd ../react bun run build cd ../solid bun run build - name: Verify build outputs run: | set -e echo "Checking for native binary packages..." ls -lah packages/core/node_modules/@opentui/ echo "Checking for dist packages..." ls -lah packages/*/dist/ # Verify critical files exist (all 6 platforms) echo "" echo "Verifying native binaries exist..." test -f packages/core/node_modules/@opentui/core-darwin-x64/libopentui.dylib || (echo "❌ darwin-x64 binary missing!" && exit 1) test -f packages/core/node_modules/@opentui/core-darwin-arm64/libopentui.dylib || (echo "❌ darwin-arm64 binary missing!" && exit 1) test -f packages/core/node_modules/@opentui/core-linux-x64/libopentui.so || (echo "❌ linux-x64 binary missing!" && exit 1) test -f packages/core/node_modules/@opentui/core-linux-arm64/libopentui.so || (echo "❌ linux-arm64 binary missing!" && exit 1) test -f packages/core/node_modules/@opentui/core-win32-x64/opentui.dll || (echo "❌ windows-x64 binary missing!" && exit 1) test -f packages/core/node_modules/@opentui/core-win32-arm64/opentui.dll || (echo "❌ windows-arm64 binary missing!" && exit 1) echo "Verifying dist packages exist..." test -d packages/core/dist || (echo "❌ core dist missing!" && exit 1) test -f packages/core/dist/package.json || (echo "❌ core dist/package.json missing!" && exit 1) echo "✅ All required build outputs verified (6 platforms)" # Create separate zips for each platform's native binaries - name: Package native binaries - darwin-x64 run: | set -e mkdir -p artifacts/native-darwin-x64 cp packages/core/node_modules/@opentui/core-darwin-x64/libopentui.dylib artifacts/native-darwin-x64/ cd artifacts zip -r native-darwin-x64.zip native-darwin-x64/ test -f native-darwin-x64.zip || (echo "❌ Failed to create darwin-x64 zip" && exit 1) test -s native-darwin-x64.zip || (echo "❌ darwin-x64 zip is empty" && exit 1) echo "✅ darwin-x64 packaged successfully ($(du -h native-darwin-x64.zip | cut -f1))" - name: Package native binaries - darwin-arm64 run: | set -e mkdir -p artifacts/native-darwin-arm64 cp packages/core/node_modules/@opentui/core-darwin-arm64/libopentui.dylib artifacts/native-darwin-arm64/ cd artifacts zip -r native-darwin-arm64.zip native-darwin-arm64/ test -f native-darwin-arm64.zip || (echo "❌ Failed to create darwin-arm64 zip" && exit 1) test -s native-darwin-arm64.zip || (echo "❌ darwin-arm64 zip is empty" && exit 1) echo "✅ darwin-arm64 packaged successfully ($(du -h native-darwin-arm64.zip | cut -f1))" - name: Package native binaries - linux-x64 run: | set -e mkdir -p artifacts/native-linux-x64 cp packages/core/node_modules/@opentui/core-linux-x64/libopentui.so artifacts/native-linux-x64/ cd artifacts zip -r native-linux-x64.zip native-linux-x64/ test -f native-linux-x64.zip || (echo "❌ Failed to create linux-x64 zip" && exit 1) test -s native-linux-x64.zip || (echo "❌ linux-x64 zip is empty" && exit 1) echo "✅ linux-x64 packaged successfully ($(du -h native-linux-x64.zip | cut -f1))" - name: Package native binaries - windows-x64 run: | set -e mkdir -p artifacts/native-windows-x64 cp packages/core/node_modules/@opentui/core-win32-x64/opentui.dll artifacts/native-windows-x64/ cd artifacts zip -r native-windows-x64.zip native-windows-x64/ test -f native-windows-x64.zip || (echo "❌ Failed to create windows-x64 zip" && exit 1) test -s native-windows-x64.zip || (echo "❌ windows-x64 zip is empty" && exit 1) echo "✅ windows-x64 packaged successfully ($(du -h native-windows-x64.zip | cut -f1))" - name: Package native binaries - linux-arm64 run: | set -e mkdir -p artifacts/native-linux-arm64 cp packages/core/node_modules/@opentui/core-linux-arm64/libopentui.so artifacts/native-linux-arm64/ cd artifacts zip -r native-linux-arm64.zip native-linux-arm64/ test -f native-linux-arm64.zip || (echo "❌ Failed to create linux-arm64 zip" && exit 1) test -s native-linux-arm64.zip || (echo "❌ linux-arm64 zip is empty" && exit 1) echo "✅ linux-arm64 packaged successfully ($(du -h native-linux-arm64.zip | cut -f1))" - name: Package native binaries - windows-arm64 run: | set -e mkdir -p artifacts/native-windows-arm64 cp packages/core/node_modules/@opentui/core-win32-arm64/opentui.dll artifacts/native-windows-arm64/ cd artifacts zip -r native-windows-arm64.zip native-windows-arm64/ test -f native-windows-arm64.zip || (echo "❌ Failed to create windows-arm64 zip" && exit 1) test -s native-windows-arm64.zip || (echo "❌ windows-arm64 zip is empty" && exit 1) echo "✅ windows-arm64 packaged successfully ($(du -h native-windows-arm64.zip | cut -f1))" # Package the built npm packages (for use by build-examples and npm-publish) - name: Package npm packages run: | set -e mkdir -p artifacts/npm-packages # Copy core package dist and native packages echo "Packaging core dist..." cp -r packages/core/dist artifacts/npm-packages/core-dist test -f artifacts/npm-packages/core-dist/package.json || (echo "❌ core dist/package.json missing after copy!" && exit 1) echo "Packaging core native packages..." cp -r packages/core/node_modules/@opentui artifacts/npm-packages/core-native-packages # Copy other package dists (optional - don't fail if missing) echo "Packaging other packages..." if [ -d packages/react/dist ]; then cp -r packages/react/dist artifacts/npm-packages/react-dist echo "✅ React dist packaged" else echo "⚠️ React dist not found (skipping)" fi if [ -d packages/solid/dist ]; then cp -r packages/solid/dist artifacts/npm-packages/solid-dist echo "✅ Solid dist packaged" else echo "⚠️ Solid dist not found (skipping)" fi cd artifacts zip -r npm-packages.zip npm-packages/ test -f npm-packages.zip || (echo "❌ Failed to create npm-packages zip" && exit 1) test -s npm-packages.zip || (echo "❌ npm-packages zip is empty" && exit 1) echo "✅ npm packages packaged successfully ($(du -h npm-packages.zip | cut -f1))" - name: Verify all artifacts before upload run: | set -e echo "Verifying all artifacts exist..." test -f artifacts/native-darwin-x64.zip || (echo "❌ native-darwin-x64.zip missing!" && exit 1) test -f artifacts/native-darwin-arm64.zip || (echo "❌ native-darwin-arm64.zip missing!" && exit 1) test -f artifacts/native-linux-x64.zip || (echo "❌ native-linux-x64.zip missing!" && exit 1) test -f artifacts/native-linux-arm64.zip || (echo "❌ native-linux-arm64.zip missing!" && exit 1) test -f artifacts/native-windows-x64.zip || (echo "❌ native-windows-x64.zip missing!" && exit 1) test -f artifacts/native-windows-arm64.zip || (echo "❌ native-windows-arm64.zip missing!" && exit 1) test -f artifacts/npm-packages.zip || (echo "❌ npm-packages.zip missing!" && exit 1) echo "" echo "✅ All 6 platform artifacts verified. Ready to upload:" ls -lah artifacts/*.zip - name: Upload native binaries artifacts uses: actions/upload-artifact@v4 with: name: native-binaries-${{ inputs.version }} path: | artifacts/native-darwin-x64.zip artifacts/native-darwin-arm64.zip artifacts/native-linux-x64.zip artifacts/native-linux-arm64.zip artifacts/native-windows-x64.zip artifacts/native-windows-arm64.zip if-no-files-found: error retention-days: 30 - name: Upload npm packages artifact uses: actions/upload-artifact@v4 with: name: npm-packages-${{ inputs.version }} path: artifacts/npm-packages.zip if-no-files-found: error retention-days: 30 ================================================ FILE: .github/workflows/build-react.yml ================================================ name: Build React on: push: pull_request: branches: [main] env: # Workaround for bug in Zig 0.15.2 (fixed in next version) # https://github.com/ziglang/zig/issues/25805 ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-global-cache jobs: test: name: Test (${{ matrix.os }}) strategy: matrix: os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} defaults: run: shell: bash steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Zig uses: goto-bus-stop/setup-zig@v2 with: version: 0.15.2 - name: Install dependencies run: bun install - name: Build core run: | cd packages/core bun run build - name: Build run: | cd packages/react bun run build --ci - name: Run tests run: | cd packages/react bun run test # Gate job for branch protection build-complete: name: React - Build and Test needs: [test] runs-on: ubuntu-latest if: always() steps: - name: Check test results run: | if [ "${{ needs.test.result }}" != "success" ]; then echo "Tests failed" exit 1 fi echo "All tests passed" ================================================ FILE: .github/workflows/build-solid.yml ================================================ name: Build Solid on: push: pull_request: branches: [main] env: # Workaround for bug in Zig 0.15.2 (fixed in next version) # https://github.com/ziglang/zig/issues/25805 ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-global-cache jobs: test: name: Test (${{ matrix.os }}) strategy: matrix: os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} defaults: run: shell: bash steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Zig uses: goto-bus-stop/setup-zig@v2 with: version: 0.15.2 - name: Install dependencies run: bun install - name: Build core run: | cd packages/core bun run build - name: Build run: | cd packages/solid bun run build --ci - name: Run tests run: | cd packages/solid bun run test # Gate job for branch protection build-complete: name: Solid - Build and Test needs: [test] runs-on: ubuntu-latest if: always() steps: - name: Check test results run: | if [ "${{ needs.test.result }}" != "success" ]; then echo "Tests failed" exit 1 fi echo "All tests passed" ================================================ FILE: .github/workflows/deploy.yml ================================================ name: Deploy to GitHub Pages on: push: branches: [main] workflow_dispatch: permissions: contents: read pages: write id-token: write jobs: build: runs-on: ubuntu-latest steps: - name: Checkout your repository using git uses: actions/checkout@v6 - name: Install, build, and upload your site uses: withastro/action@v5 with: path: ./packages/web package-manager: bun@latest deploy: needs: build runs-on: ubuntu-latest environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ================================================ FILE: .github/workflows/npm-latest-release.yml ================================================ name: NPM Publish on: workflow_call: inputs: version: description: "Version being published" required: true type: string isDryRun: description: "Whether this is a dry run (npm publish --dry-run)" required: false type: boolean default: false secrets: NPM_TOKEN: required: true permissions: contents: write pull-requests: write jobs: publish: runs-on: macos-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install dependencies run: bun install - name: Download npm packages artifact uses: actions/download-artifact@v4 with: name: npm-packages-${{ inputs.version }} - name: Extract npm packages run: | echo "Extracting npm packages..." unzip -q npm-packages.zip # Copy core dist if [ -d "npm-packages/core-dist" ]; then cp -r npm-packages/core-dist packages/core/dist echo "Copied core dist" fi # Copy native packages to core's node_modules if [ -d "npm-packages/core-native-packages" ]; then mkdir -p packages/core/node_modules/@opentui cp -r npm-packages/core-native-packages/* packages/core/node_modules/@opentui/ echo "Copied native packages" fi # Copy other package dists if [ -d "npm-packages/react-dist" ]; then cp -r npm-packages/react-dist packages/react/dist echo "Copied react dist" fi if [ -d "npm-packages/solid-dist" ]; then cp -r npm-packages/solid-dist packages/solid/dist echo "Copied solid dist" fi echo "Package extraction complete" - name: Publish packages (dry-run) if: ${{ inputs.isDryRun }} run: | echo "==========================================" echo "DRY RUN MODE - Not publishing to npm" echo "==========================================" echo "" echo "Skipping pre-publish validation (npm version check would fail for dry-runs)" echo "" # Show what would be published (just check if packages can be packed) echo "Packages that would be published:" echo "" echo "📦 Checking @opentui/core..." cd packages/core/dist && npm pack --dry-run echo "" echo "📦 Checking @opentui/react..." cd ../../react/dist && npm pack --dry-run echo "" echo "📦 Checking @opentui/solid..." cd ../../solid/dist && npm pack --dry-run echo "" echo "==========================================" echo "DRY RUN COMPLETE - All packages validated" echo "==========================================" env: NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} CI: true - name: Publish packages (production) if: ${{ !inputs.isDryRun }} run: | echo "==========================================" echo "PRODUCTION MODE - Publishing to npm" echo "==========================================" # Run pre-publish validation bun run pre-publish # Publish packages bun run publish echo "" echo "==========================================" echo "PUBLISH COMPLETE" echo "==========================================" env: NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} CI: true ================================================ FILE: .github/workflows/npm-release.yml ================================================ name: NPM Snapshot Release on: push: tags: - "*snapshot*" permissions: contents: write pull-requests: write jobs: release: runs-on: macos-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Zig uses: goto-bus-stop/setup-zig@v2 with: version: 0.15.2 - name: Extract version from tag id: extract_version run: | TAG=${GITHUB_REF#refs/tags/v} echo "version=$TAG" >> $GITHUB_OUTPUT echo "Extracted version: $TAG" - name: Generate snapshot version id: version_scheme run: | TAG_VERSION="${{ steps.extract_version.outputs.version }}" COMMIT_SHA=$(git rev-parse --short=8 HEAD) # Pre-release snapshot VERSION="0.0.0-$(date +%Y%m%d)-${COMMIT_SHA}" echo "version=$VERSION" >> $GITHUB_OUTPUT echo "Using snapshot version: $VERSION" - name: Install dependencies run: bun i - name: Prepare release versions run: bun run prepare-release "${{ steps.version_scheme.outputs.version }}" - name: Build packages (cross-compile for all platforms) run: | cd packages/core bun run build:native --all bun run build:lib cd ../solid && bun run build cd ../react && bun run build - name: Publish packages run: bun run publish env: NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} CI: true ================================================ FILE: .github/workflows/opencode.yml ================================================ name: opencode on: issue_comment: types: [created] jobs: opencode: if: | contains(github.event.comment.body, ' /oc') || startsWith(github.event.comment.body, '/oc') || contains(github.event.comment.body, ' /opencode') || startsWith(github.event.comment.body, '/opencode') runs-on: ubuntu-latest permissions: contents: read id-token: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Run opencode uses: sst/opencode/github@latest env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} with: model: anthropic/claude-sonnet-4-20250514 ================================================ FILE: .github/workflows/pkg-pr-new.yml ================================================ name: Publish Preview Packages on: issue_comment: types: [created] permissions: {} jobs: publish: name: Publish Preview if: | github.event.issue.pull_request && github.event.issue.state == 'open' && (contains(github.event.comment.body, ' /pkg-preview') || startsWith(github.event.comment.body, '/pkg-preview')) && contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) runs-on: ubuntu-latest steps: - name: Checkout PR branch uses: actions/checkout@v4 with: ref: refs/pull/${{ github.event.issue.number }}/head - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Zig uses: goto-bus-stop/setup-zig@v2 with: version: 0.15.2 - name: Install dependencies run: bun install - name: Build core (all platforms via cross-compilation) run: bun scripts/build.ts --native --all && bun scripts/build.ts --lib working-directory: packages/core - name: Get native package directories id: native-packages run: | NATIVE_DIRS=$(find ./packages/core/node_modules/@opentui -maxdepth 1 -type d -name 'core-*' -printf '%p ' | sed 's/ $//') echo "dirs=$NATIVE_DIRS" >> $GITHUB_OUTPUT echo "Found native packages: $NATIVE_DIRS" - name: Build react run: bun run build --ci working-directory: packages/react - name: Build solid run: bun run build --ci working-directory: packages/solid - name: Publish preview packages run: | npx pkg-pr-new publish --no-template --commentWithSha --bun \ './packages/core/dist' \ ${{ steps.native-packages.outputs.dirs }} \ './packages/react/dist' \ './packages/solid/dist' ================================================ FILE: .github/workflows/prettier.yml ================================================ name: Format on: pull_request: branches: [main] jobs: prettier-core: name: Prettier Check runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Check Prettier formatting run: | PRETTIER_VERSION=$(bun -e 'console.log(require("./package.json").devDependencies.prettier)') bunx prettier@$PRETTIER_VERSION --check --log-level warn . - name: Show formatting differences if: failure() run: | echo "=== Showing differences for each file ===" PRETTIER_VERSION=$(bun -e 'console.log(require("./package.json").devDependencies.prettier)') bunx prettier@$PRETTIER_VERSION --write . git diff --color=always ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: push: tags: - "v*" permissions: contents: write pull-requests: write jobs: # Extract version and check if it's a dry run prepare: name: Prepare Release runs-on: ubuntu-latest outputs: version: ${{ steps.extract.outputs.version }} fullTag: ${{ steps.extract.outputs.fullTag }} isDryRun: ${{ steps.extract.outputs.isDryRun }} releaseTitle: ${{ steps.extract.outputs.releaseTitle }} steps: - name: Extract version and dry-run flag id: extract run: | TAG=${GITHUB_REF#refs/tags/v} echo "Full tag: $TAG" # Check if this is a dry run (contains -dry.) if [[ "$TAG" =~ -dry\. ]]; then IS_DRY_RUN=true # Extract base version (remove -dry.X suffix for validation) VERSION=$(echo "$TAG" | sed -E 's/-dry\.[0-9]+$//') RELEASE_TITLE="Release v$TAG (DRY RUN)" echo "This is a DRY RUN release" else IS_DRY_RUN=false VERSION="$TAG" RELEASE_TITLE="Release v$TAG" echo "This is a PRODUCTION release" fi echo "version=$VERSION" >> $GITHUB_OUTPUT echo "fullTag=$TAG" >> $GITHUB_OUTPUT echo "isDryRun=$IS_DRY_RUN" >> $GITHUB_OUTPUT echo "releaseTitle=$RELEASE_TITLE" >> $GITHUB_OUTPUT echo "Version (for validation): $VERSION" echo "Full Tag (for artifacts): $TAG" echo "Is Dry Run: $IS_DRY_RUN" echo "Release Title: $RELEASE_TITLE" # Version validation check validate-version: name: Validate Version needs: prepare runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Check version matches package.json files run: | TAG_VERSION="${{ needs.prepare.outputs.version }}" echo "Validating version: $TAG_VERSION" # Check package.json versions (exclude web, not published to npm) FAILED=false for pkg in packages/*/; do if [ -f "$pkg/package.json" ]; then if [ "$(basename "$pkg")" = "web" ]; then echo "INFO: Skipping $pkg (not published to npm)" continue fi PKG_VERSION=$(node -p "require('./$pkg/package.json').version") if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then echo "❌ Package $pkg version ($PKG_VERSION) does not match tag version ($TAG_VERSION)" FAILED=true else echo "✅ Package $pkg version matches: $PKG_VERSION" fi fi done if [ "$FAILED" = true ]; then echo "" echo "Version validation FAILED!" echo "Please update package.json versions to match the tag version: $TAG_VERSION" exit 1 fi echo "" echo "✅ All package versions match tag version: $TAG_VERSION" # Build native libraries and packages build-native: name: Build Native needs: [prepare, validate-version] uses: ./.github/workflows/build-native.yml with: version: ${{ needs.prepare.outputs.fullTag }} isDryRun: ${{ needs.prepare.outputs.isDryRun == 'true' }} # Build example executables build-examples: name: Build Examples needs: [prepare, validate-version, build-native] uses: ./.github/workflows/build-examples.yml with: version: ${{ needs.prepare.outputs.fullTag }} isDryRun: ${{ needs.prepare.outputs.isDryRun == 'true' }} # Publish to npm npm-publish: name: NPM Publish needs: [prepare, validate-version, build-native] uses: ./.github/workflows/npm-latest-release.yml secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} with: version: ${{ needs.prepare.outputs.fullTag }} isDryRun: ${{ needs.prepare.outputs.isDryRun == 'true' }} # Create GitHub release with assets github-release: name: Create GitHub Release needs: [prepare, build-native, build-examples, npm-publish] runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: Organize release assets run: | set -e WORK_DIR=$(pwd) mkdir -p "$WORK_DIR/release-assets" FULL_TAG="${{ needs.prepare.outputs.fullTag }}" echo "Organizing release assets for tag: $FULL_TAG" echo "Working directory: $WORK_DIR" # Verify artifact directories exist test -d "artifacts/native-binaries-$FULL_TAG" || (echo "❌ native-binaries artifact directory not found!" && exit 1) test -d "artifacts/example-executables-$FULL_TAG" || (echo "❌ example-executables artifact directory not found!" && exit 1) # Copy native binaries (unzip and rezip with versioned names) echo "Processing native binaries..." cd "artifacts/native-binaries-$FULL_TAG" for zip_file in native-*.zip; do if [ -f "$zip_file" ]; then platform=$(echo "$zip_file" | sed 's/native-//' | sed 's/.zip//') echo " Processing $platform..." unzip -q "$zip_file" # Repackage with versioned name dir_name=$(echo "$zip_file" | sed 's/.zip//') if [ -d "$dir_name" ]; then cd "$dir_name" zip -r "$WORK_DIR/release-assets/opentui-native-v${FULL_TAG}-${platform}.zip" . cd .. # Verify the output test -f "$WORK_DIR/release-assets/opentui-native-v${FULL_TAG}-${platform}.zip" || (echo "❌ Failed to create native $platform release asset!" && exit 1) echo " ✅ opentui-native-v${FULL_TAG}-${platform}.zip created" else echo "❌ Directory $dir_name not found after unzip!" && exit 1 fi fi done cd "$WORK_DIR" # Copy example executables (unzip and rezip with versioned names) echo "Processing example executables..." cd "artifacts/example-executables-$FULL_TAG" for zip_file in examples-*.zip; do if [ -f "$zip_file" ]; then platform=$(echo "$zip_file" | sed 's/examples-//' | sed 's/.zip//') echo " Processing $platform..." unzip -q "$zip_file" # Repackage with versioned name dir_name=$(echo "$zip_file" | sed 's/.zip//') if [ -d "$dir_name" ]; then cd "$dir_name" zip -r "$WORK_DIR/release-assets/opentui-examples-v${FULL_TAG}-${platform}.zip" . cd .. # Verify the output test -f "$WORK_DIR/release-assets/opentui-examples-v${FULL_TAG}-${platform}.zip" || (echo "❌ Failed to create examples $platform release asset!" && exit 1) echo " ✅ opentui-examples-v${FULL_TAG}-${platform}.zip created" else echo "❌ Directory $dir_name not found after unzip!" && exit 1 fi fi done cd "$WORK_DIR" # Verify all expected release assets exist echo "" echo "Verifying all release assets..." EXPECTED_ASSETS=10 # 6 native (darwin-x64, darwin-arm64, linux-x64, linux-arm64, windows-x64, windows-arm64) + 4 examples (no linux-arm64, no windows-arm64) ACTUAL_ASSETS=$(ls -1 release-assets/*.zip 2>/dev/null | wc -l | tr -d ' ') if [ "$ACTUAL_ASSETS" -ne "$EXPECTED_ASSETS" ]; then echo "❌ Expected $EXPECTED_ASSETS release assets, found $ACTUAL_ASSETS" ls -lah release-assets/ || echo "No release assets found" exit 1 fi echo "✅ All $ACTUAL_ASSETS release assets prepared:" echo " - 6 native binaries (all platforms)" echo " - 4 example executables (darwin-x64, darwin-arm64, linux-x64, windows-x64)" ls -lah release-assets/ - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: name: ${{ needs.prepare.outputs.releaseTitle }} files: release-assets/*.zip generate_release_notes: true draft: false prerelease: ${{ needs.prepare.outputs.isDryRun == 'true' }} token: ${{ secrets.GITHUB_TOKEN }} fail_on_unmatched_files: true ================================================ FILE: .github/workflows/review.yml ================================================ name: Guidelines Check on: issue_comment: types: [created] jobs: check-guidelines: if: | github.event.issue.pull_request && startsWith(github.event.comment.body, '/review') && contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association) runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: - name: Get PR number id: pr-number run: | if [ "${{ github.event_name }}" = "pull_request_target" ]; then echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT else echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT fi - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 1 - name: Install opencode run: curl -fsSL https://opencode.ai/install | bash - name: Get PR details id: pr-details run: | gh api /repos/${{ github.repository }}/pulls/${{ steps.pr-number.outputs.number }} > pr_data.json echo "title=$(jq -r .title pr_data.json)" >> $GITHUB_OUTPUT echo "sha=$(jq -r .head.sha pr_data.json)" >> $GITHUB_OUTPUT env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Check PR guidelines compliance env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENCODE_PERMISSION: '{ "bash": { "gh*": "allow", "gh pr review*": "deny", "*": "deny" } }' run: | PR_BODY=$(jq -r .body pr_data.json) opencode run -m anthropic/claude-sonnet-4-5 "A new pull request has been created: '${{ steps.pr-details.outputs.title }}' ${{ steps.pr-number.outputs.number }} $PR_BODY Please check all the code changes in this pull request against the style guide, also look for any bugs if they exist. Diffs are important but make sure you read the entire file to get proper context. Make it clear the suggestions are merely suggestions and the human can decide what to do When critiquing code against the style guide, be sure that the code is ACTUALLY in violation, don't complain about else statements if they already use early returns there. You may complain about excessive nesting though, regardless of else statement usage. When critiquing code style don't be a zealot, we don't like "let" statements but sometimes they are the simpliest option, if someone does a bunch of nesting with let, they should consider using iife (see packages/opencode/src/util.iife.ts) Use the gh cli to create comments on the files for the violations. Try to leave the comment on the exact line number. If you have a suggested fix include it in a suggestion code block. Command MUST be like this. \`\`\` gh api \ --method POST \ -H \"Accept: application/vnd.github+json\" \ -H \"X-GitHub-Api-Version: 2022-11-28\" \ /repos/${{ github.repository }}/pulls/${{ steps.pr-number.outputs.number }}/comments \ -f 'body=[summary of issue]' -f 'commit_id=${{ steps.pr-details.outputs.sha }}' -f 'path=[path-to-file]' -F \"line=[line]\" -f 'side=RIGHT' \`\`\` Only create comments for actual violations. If the code follows all guidelines, comment 'lgtm' AND NOTHING ELSE!!!!." ================================================ FILE: .gitignore ================================================ # dependencies (bun install) node_modules Session.vim # output out dist packed *.tgz *.log *.txt # code coverage coverage *.lcov # logs logs _.log report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json # dotenv environment variable files .env .env.development.local .env.test.local .env.production.local .env.local # caches .eslintcache .cache *.tsbuildinfo # IntelliJ based IDEs .idea # Finder (MacOS) folder config .DS_Store screenshot-*.png ================================================ FILE: .prettierignore ================================================ **/.zig-cache/** packages/core/src/lib/tree-sitter/default-parsers.ts ================================================ FILE: .zig-version ================================================ 0.15.2 ================================================ FILE: AGENTS.md ================================================ # Agent Guidelines for opentui Default to using Bun instead of Node.js. - Use `bun ` instead of `node ` or `ts-node ` - Use `bun test` instead of `jest` or `vitest` - Use `bun install` instead of `npm install` or `yarn install` or `pnpm install` - Use `bun run ================================================ FILE: packages/web/src/content/config.ts ================================================ import { defineCollection, z } from "astro:content" const docs = defineCollection({ type: "content", schema: z.object({ title: z.string(), description: z.string().optional(), order: z.number().optional(), }), }) export const collections = { docs, } ================================================ FILE: packages/web/src/content/docs/bindings/react.mdx ================================================ --- title: React description: Build terminal UIs with React and OpenTUI order: 2 --- # React bindings Build terminal user interfaces using React with familiar patterns and components. ## Installation Quick start with [bun](https://bun.sh) and [create-tui](https://github.com/msmps/create-tui): ```bash bun create tui --template react ``` Manual installation: ```bash bun install @opentui/react @opentui/core react ``` ## Quick start ```tsx import { createCliRenderer } from "@opentui/core" import { createRoot } from "@opentui/react" function App() { return Hello, world! } const renderer = await createCliRenderer() createRoot(renderer).render() ``` ## TypeScript configuration Configure your `tsconfig.json`: ```json { "compilerOptions": { "lib": ["ESNext", "DOM"], "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "jsx": "react-jsx", "jsxImportSource": "@opentui/react", "strict": true, "skipLibCheck": true } } ``` ## Runtime-loaded plugin support (if needed) If your app loads external TS/TSX modules at runtime (for example a file-based plugin system), import this once in your app entry before dynamic imports: ```ts import "@opentui/react/runtime-plugin-support" ``` Use this for both normal Bun runs and standalone compiled executables. ## Components OpenTUI React provides JSX intrinsic elements that map to core renderables: ### Layout & display - `` - Text display with styling - `` - Container with borders and layout - `` - Scrollable container - `` - ASCII art text ### Input - `` - Single-line text input - `