{"id":50816051,"url":"https://github.com/ydah/rterm","last_synced_at":"2026-06-13T09:33:42.761Z","repository":{"id":341394256,"uuid":"1169853621","full_name":"ydah/rterm","owner":"ydah","description":"Headless terminal emulator library for Ruby.","archived":false,"fork":false,"pushed_at":"2026-05-13T05:46:07.000Z","size":245,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-13T07:26:04.168Z","etag":null,"topics":["emulator","headless","library","ruby","terminal","terminal-emulator"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ydah.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-01T10:21:57.000Z","updated_at":"2026-05-13T05:46:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ydah/rterm","commit_stats":null,"previous_names":["ydah/rterm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ydah/rterm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydah%2Frterm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydah%2Frterm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydah%2Frterm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydah%2Frterm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ydah","download_url":"https://codeload.github.com/ydah/rterm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydah%2Frterm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34279898,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["emulator","headless","library","ruby","terminal","terminal-emulator"],"created_at":"2026-06-13T09:33:42.662Z","updated_at":"2026-06-13T09:33:42.756Z","avatar_url":"https://github.com/ydah.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RTerm\n\nRTerm is a headless terminal emulator library for Ruby. It parses ANSI/VT\nstreams, owns terminal state, and exposes PTY, rendering, image, and browser\nbridge APIs without forcing a native UI.\n\n## Current Scope\n\n- Terminal core: buffer state, scrollback, reflow, selection, mouse reporting,\n  modes, OSC, DCS, colors, hyperlinks, clipboard policy, and window operations.\n- Process integration: Unix PTY support and a Windows ConPTY boundary.\n- Rendering: screen trees, HTML/ARIA output, RGBA raster frames, renderer\n  lifecycle state, and browser-side DOM/WebGL assets.\n- Images: Sixel and iTerm2 image payload tracking with PNG, GIF, and JPEG\n  decoding paths.\n- BrowserBridge: WebSocket session transport with resume, attach policies,\n  rate limits, heartbeats, origin checks, and binary frames.\n- Addons: search, serialization, clipboard, links, fonts, Unicode widths,\n  graphemes, ligatures, progress, images, and host integration.\n\n## Requirements\n\n- Ruby 3.2 or later\n- `faye-websocket` for BrowserBridge WebSocket deployments\n- npm 9 or later when packaging browser adapter assets\n\n## Installation\n\n```ruby\n# Gemfile\ngem \"rterm\"\ngem \"faye-websocket\" # only for BrowserBridge WebSocket servers\n```\n\n```bash\ngem install rterm\n```\n\n## Quick Start\n\n```ruby\nrequire \"rterm\"\n\nterm = RTerm::Terminal.new(cols: 80, rows: 24, scrollback: 1_000)\nterm.write(\"Hello \\e[1;31mWorld\\e[0m!\\r\\n\")\n\nline = term.buffer.active.get_line(0)\nputs line.to_string # =\u003e \"Hello World!\"\n```\n\n## Common Usage\n\n### Terminal State\n\n```ruby\nterm.write(\"open https://example.com\\r\\n\")\nterm.select_url(8, 0)\nputs term.selection\n\ncell = term.buffer.active.get_line(0).get_cell(0)\nputs term.cell_colors(cell)\nputs term.cursor_info(active: false)\n```\n\nUseful options can be passed in snake_case or camelCase:\n\n```ruby\nterm = RTerm::Terminal.new(\n  reflowCursorLine: true,\n  scrollOnEraseInDisplay: true,\n  ignoreBracketedPasteMode: true\n)\n```\n\n### Addons\n\n```ruby\nsearch = RTerm::Addon::Search.new\nterm.load_addon(search)\nterm.write(\"error: failed\\r\\nerror: retrying\")\nputs search.find_all(\"error\").length # =\u003e 2\n\nserializer = RTerm::Addon::Serialize.new\nterm.load_addon(serializer)\nsnapshot = serializer.snapshot(scrollback: 100)\n\nlinks = RTerm::Addon::WebLinks.new\nterm.load_addon(links)\nterm.write(\"open https://example.com\")\nlinks.open_link(links.find_links.first)\n```\n\n### Rendering\n\n```ruby\nscreen = RTerm::Addon::ScreenRenderer.new\nterm.load_addon(screen)\nputs screen.text\nputs screen.accessibility_tree[:children].first[:text]\n\nhtml = RTerm::Addon::HtmlRenderer.new\nterm.load_addon(html)\nputs html.to_html\n\nraster = RTerm::Addon::RasterRenderer.new(cell_width: 8, cell_height: 16)\nterm.load_addon(raster)\nFile.write(\"terminal.ppm\", raster.to_ppm)\n```\n\nRenderer lifecycle addons keep host renderer state close to terminal state:\n\n```ruby\nrenderer = RTerm::Addon::WebGL.new\nterm.load_addon(renderer)\n\nrenderer.attach_host(:canvas, viewport: { cellWidth: 9, cellHeight: 18 })\nrenderer.update_scrollbar(visible: true, width: 12)\nrenderer.on_context_loss { |event| warn event[:reason] }\n```\n\n### Images\n\n```ruby\nimages = RTerm::Addon::Image.new\nterm.load_addon(images)\n\n# After terminal output emits an image payload:\nterm.write(\"\\ePqABCDEF\\e\\\\\")\nimage = images.by_protocol(:sixel).first\ndecoded = images.decode(image) if image\nputs decoded[:result][:format] if decoded\n```\n\n### PTY\n\n```ruby\npty = RTerm::Pty.new(\n  command: ENV[\"SHELL\"] || \"/bin/sh\",\n  env: { \"TERM\" =\u003e \"xterm-256color\" },\n  cwd: Dir.pwd,\n  process_group: true\n)\n\npty.on_data { |data| term.write(data) }\npty.write(\"printf 'hello\\\\n'\\r\")\npty.close\n```\n\nWindows hosts can provide or configure a ConPTY backend:\n\n```ruby\nconpty = RTerm::ConPTY.new(command: \"cmd.exe\", cols: 80, rows: 24)\nconpty.on_data { |data| term.write(data) }\nconpty.kill(:TERM, group: true) if conpty.process_group_enabled?\n\nRTerm::ConPTY.configure_backend(lambda { |**options| MyConPTYBackend.new(**options) })\n```\n\n### BrowserBridge\n\n```ruby\nmanager = RTerm::BrowserBridge::SessionManager.new(\n  max_sessions: 10,\n  idle_timeout: 600,\n  attach_policy: :single\n)\n\nmessage = RTerm::BrowserBridge::ProtocolHandler.decode(\n  '{\"type\":\"create_session\",\"payload\":{\"cols\":80,\"rows\":24}}'\n)\nresponse = manager.process_message(message)\n```\n\nBrowserBridge production servers should start from secure defaults:\n\n```ruby\nRTerm::BrowserBridge::WebSocketServer.configure_secure_defaults do |config|\n  config.allowed_origins = [\"https://your-app.example\"]\n  config.authenticator = lambda do |message|\n    payload = message[:payload] || message[\"payload\"] || {}\n    token = payload[:token] || payload[\"token\"]\n    token == ENV.fetch(\"RTERM_BRIDGE_TOKEN\")\n  end\nend\n```\n\nThe bundled browser adapter can mount a BrowserBridge session in a page:\n\n```ruby\n[\n  RTerm::BrowserAdapter.style_tag,\n  %(\u003cdiv id=\"terminal\" style=\"height: 480px\"\u003e\u003c/div\u003e),\n  RTerm::BrowserAdapter.script_tag,\n  %(\u003cscript\u003enew RTermBrowserAdapter(\"#terminal\", { url: \"wss://your-app.example/terminal\", renderer: \"webgl\", raster: true });\u003c/script\u003e)\n]\n```\n\nThe same browser adapter assets can be consumed from JavaScript tooling:\n\n```js\nimport RTermBrowserAdapter, { RTermWebGLRenderer } from \"rterm-browser-adapter\";\nimport \"rterm-browser-adapter/style.css\";\n\nnew RTermBrowserAdapter(\"#terminal\", {\n  url: \"wss://your-app.example/terminal\",\n  renderer: \"webgl\",\n  raster: true\n});\n```\n\n## Addon Summary\n\n| Addon | Purpose |\n| --- | --- |\n| `Attach` | Forward terminal input and remote output through socket-like objects. |\n| `Search` | Find text, regex matches, captures, and optional decorations. |\n| `Serialize` | Export ANSI replay, HTML, and structured snapshots. |\n| `Fit` | Compute terminal dimensions from available space. |\n| `Clipboard` | Handle text copy/paste and OSC 52 policy flows. |\n| `Progress` | Track OSC 9 progress state. |\n| `Image` | Track, decode, filter, and dispatch Sixel, PNG, GIF, and JPEG payloads. |\n| `Ligatures` | Compute character join ranges. |\n| `Unicode11`, `UnicodeGraphemes` | Switch width providers and measure grapheme clusters. |\n| `WebFonts` | Register font faces, expose CSS, estimate cells, and trigger relayout events. |\n| `WebLinks` | Detect and activate links with provider hooks. |\n| `HostIntegration` | Bridge host mount, input, clipboard, font, renderer, and accessibility events. |\n| `ScreenRenderer`, `HtmlRenderer`, `RasterRenderer` | Produce screen trees, HTML/ARIA output, and RGBA frames. |\n| `Canvas`, `WebGL` | Track renderer lifecycle and cache state. |\n\n## Operational Notes\n\n- `RTerm::Pty` is available on Unix-like systems.\n- `RTerm::ConPTY` defines the Windows process boundary, uses the bundled native\n  backend on Windows, and reports group termination support when available.\n- Keep BrowserBridge origins, message size limits, rate limits, and heartbeats\n  enabled in production.\n- Disable clipboard handling for untrusted remote output with\n  `clipboard_enabled: false`.\n- Do not connect untrusted browser input directly to a privileged shell.\n- Validate URI schemes before activating OSC 8 hyperlinks.\n\n## Examples\n\n- `examples/basic_usage.rb`\n- `examples/addons.rb`\n- `examples/browser_adapter.html`\n- `examples/websocket_server.rb`\n- `examples/browser_bridge_production.rb`\n\n## Documentation\n\n- Security policy: `docs/security_policy.md`\n- Renderer and font measurement scope: `docs/renderer_scope.md`\n- Release checklist: `docs/release_checklist.md`\n\n## Development\n\n```bash\ngit clone https://github.com/ydah/rterm.git\ncd rterm\nbundle install\nbundle exec rspec\nbundle exec rake package:verify_contents\nnpm pack --dry-run\n```\n\nStrict integration checks require external terminal tools and browser automation:\n\n```bash\nbundle exec rake e2e:strict\n```\n\nSet `RTERM_BROWSER_E2E=1` to require the Playwright browser smoke in local runs.\nBenchmarks live under `spec/benchmarks/`.\n\n## License\n\nMIT. See [LICENSE.txt](LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fydah%2Frterm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fydah%2Frterm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fydah%2Frterm/lists"}