### SyncAdapter Setup and Resource Testing in Ruby Source: https://github.com/terminalwire/ruby/blob/main/examples/testing_approach_summary.md Demonstrates the setup of the SyncAdapter for testing server-client resource communication. It shows how to initialize the adapter, configure client resources, create server resources, and perform a test read operation. ```ruby # 1. Create sync adapter sync_adapter = SyncAdapter.new # 2. Setup client resources client_handler = Terminalwire::Client::Resource::Handler.new do |handler| handler << Terminalwire::Client::Resource::File.new("file", sync_adapter.client_adapter, entitlement: entitlement) end sync_adapter.connect_client(client_handler) # 3. Create server resources server_file = Terminalwire::Server::Resource::File.new("file", sync_adapter) # 4. Test direct communication result = server_file.read("/tmp/test.txt") # Server -> SyncAdapter -> Client -> SyncAdapter -> Server expect(result).to eq("file contents") ``` -------------------------------- ### Ruby Integration Test Example Source: https://github.com/terminalwire/ruby/blob/main/spec/README.md Demonstrates a basic integration test using SyncAdapter for server-client communication. It initializes a SyncAdapter and a File resource, then reads a file to test the communication path. This is suitable for rapid development feedback. ```ruby # Fast, reliable testing of server-client communication sync_adapter = SyncAdapter.new server_file = Terminalwire::Server::Resource::File.new("file", sync_adapter) result = server_file.read("/tmp/test.txt") # Tests full communication path ``` -------------------------------- ### Ruby Terminalwire Client WebSocket Connection Example Source: https://context7.com/terminalwire/ruby/llms.txt Demonstrates how to establish a WebSocket connection for the Terminalwire client in Ruby, specifying the server URL and passing command-line arguments. ```ruby # bin/my-app #!/usr/bin/env ruby require 'terminalwire-client' url = "http://localhost:3000/terminal/main" Terminalwire::Client.websocket(url: url, arguments: ARGV) ``` -------------------------------- ### Ruby SyncAdapter Integration Test Setup Source: https://github.com/terminalwire/ruby/blob/main/spec/integration/README.md Demonstrates setting up a SyncAdapter for integration testing in Ruby. It shows how to initialize the adapter, configure client resources using a handler, connect the client, and set up server resources to test direct communication. ```ruby sync_adapter = SyncAdapter.new client_handler = Terminalwire::Client::Resource::Handler.new do |handler| handler << Terminalwire::Client::Resource::File.new("file", sync_adapter.client_adapter, entitlement: entitlement) # ... other resources end sync_adapter.connect_client(client_handler) server_file = Terminalwire::Server::Resource::File.new("file", sync_adapter) result = server_file.read("/tmp/test.txt") # Goes through sync adapter to client expect(result).to eq("file contents") ``` -------------------------------- ### Bash command to install terminalwire-rails gem Source: https://context7.com/terminalwire/ruby/llms.txt Installs the `terminalwire-rails` gem into a Rails project using Bundler. This command should be run within the Rails application's root directory. ```bash # Install the terminalwire-rails gem bundle add terminalwire-rails ``` -------------------------------- ### Develop Server-Side Custom Resource Proxy Source: https://context7.com/terminalwire/ruby/llms.txt Defines a server-side proxy for the `Database` resource, enabling server-side code to interact with client-side database operations. It includes methods to proxy `query` and `backup` calls to the client. The example shows how to initialize and use this resource within a server context. ```ruby # Server-side custom resource proxy module Terminalwire::Server::Resource class Database < Base def query(sql) command("query", sql: sql) end def backup(path) command("backup", path: path) end end end # Use in server context context = Terminalwire::Server::Context.new(adapter: adapter, entitlement: entitlement) # Initialize custom resource database = Terminalwire::Server::Resource::Database.new("database", context.adapter) # Execute queries on client database results = database.query("SELECT * FROM users LIMIT 10") users = JSON.parse(results) users.each do |user| context.puts "User: #{user['name']} (#{user['email']})" end # Backup client database backup_path = "/tmp/backup-#{Time.now.to_i}.db" database.backup(backup_path) context.puts "Database backed up to #{backup_path}" ``` -------------------------------- ### Rails Routes Configuration in Ruby Source: https://context7.com/terminalwire/ruby/llms.txt This Ruby code configures Rails routes to mount the Main Terminal channel for the terminal interface. It depends on Rails application setup and Terminalwire channel mounting. Inputs are the route definitions; outputs are the mounted paths. Limitations include requiring a properly set up Rails environment and the MainTerminal channel. ```ruby Rails.application.routes.draw do mount MainTerminal.channel => "/terminal/main" end ``` -------------------------------- ### Integration Test for File Resource Read Operation in Ruby Source: https://github.com/terminalwire/ruby/blob/main/examples/testing_approach_summary.md An example integration test case for the `Terminalwire::Server::Resource::File` class using RSpec. It specifically tests the `#read` method to ensure file content is correctly read through the client. ```ruby describe Terminalwire::Server::Resource::File do let(:server_file) { described_class.new("file", sync_adapter) } # Assuming sync_adapter is defined elsewhere describe '#read' do it 'reads file content through client' do # Assuming test_path is defined and points to a valid file File.write(test_path, "test content") result = server_file.read(test_path) expect(result).to eq("test content") end end end ``` -------------------------------- ### Run and Manage CLI Application Source: https://context7.com/terminalwire/ruby/llms.txt Demonstrates how to execute commands from the command line, view help information, and deploy the thin client. It shows the expected output for running the 'hello' command and listing available commands. ```bash # Run the CLI ./bin/my-app hello World # => Hello World # List commands ./bin/my-app help # Commands: # my-app hello NAME # say hello to NAME # my-app help [COMMAND] # Describe available commands # Deploy: users install the thin client curl -sSL https://terminalwire.sh/ | bash # Then run commands against production my-app --url=https://app.example.com/terminal/main hello World ``` -------------------------------- ### Main Terminal Commands in Ruby (hello, login, whoami, upload, download) Source: https://context7.com/terminalwire/ruby/llms.txt This Ruby class defines a set of Thor-based terminal commands for user greeting, authentication, session checking, file uploading to server, and downloading files to client. It depends on Rails Terminalwire for session management and client-server communication. Inputs include user names, credentials, and file paths; outputs are text confirmations or errors. Limitations include assuming authenticated sessions for uploads and requiring valid user credentials for login. ```ruby class MainTerminal < ApplicationTerminal desc "hello NAME", "Greet a user" def hello(name) puts "Hello #{name}!" end desc "login", "Authenticate user" def login print "Email: " email = gets.chomp print "Password: " password = getpass user = User.find_for_authentication(email: email) if user && user.valid_password?(password) # Store in JWT session on client session[:user_id] = user.id session[:email] = user.email puts "Successfully logged in as #{user.email}" else fail "Invalid credentials" end end desc "whoami", "Show current user" def whoami if session[:user_id] puts "Logged in as #{session[:email]}" else fail "Not logged in" end end desc "upload FILE", "Upload file to server" def upload(file_path) # Read file from client content = client.file.read(file_path) # Process on server attachment = Attachment.create!( user_id: session[:user_id], filename: File.basename(file_path), content: content ) puts "Uploaded: #{attachment.filename}" end desc "download ID", "Download file to client" def download(id) attachment = Attachment.find(id) # Write file to client filesystem output_path = "/tmp/#{attachment.filename}" client.file.write(output_path, attachment.content) puts "Downloaded to: #{output_path}" end end ``` -------------------------------- ### Development Workflow Commands in Bash Source: https://github.com/terminalwire/ruby/blob/main/examples/testing_approach_summary.md Provides bash commands to execute different levels of tests within the Terminalwire project. It includes commands for fast daily development, pre-commit validation, and release validation. ```bash # Fast daily development bundle exec rake spec:integration # ~30ms # Pre-commit validation bundle exec rake spec:isolate spec:integration # ~1s # Release validation bundle exec rake spec # ~30s (includes fullstack) ``` -------------------------------- ### Ruby Client Resource Implementation for Browser Launch Source: https://context7.com/terminalwire/ruby/llms.txt Enables launching URLs in the default web browser from the client-side for Terminalwire. It uses the `Launchy` gem and checks URL schemes against permitted entitlements. ```ruby # Client resource example (simplified from actual implementation) module Terminalwire::Client::Resource class Browser < Base def self.key "browser" end def launch(url:) Launchy.open(URI(url)) nil end protected def permit(command, url:, **) @entitlement.schemes.permitted?(url) end end end ``` -------------------------------- ### Server WebSocket Handler and Rails Mount Source: https://context7.com/terminalwire/ruby/llms.txt Demonstrates the server-side implementation of a WebSocket handler using `Terminalwire::Server::WebSocket`. It shows how to handle incoming messages, dispatch CLI commands, and mount the WebSocket endpoint within a Rails application. ```ruby # Usage - server (Rails/Rack) class TerminalSocket < Terminalwire::Server::WebSocket def handle(adapter:, env:) while message = adapter.read case message[:event] when "initialization" context = Terminalwire::Server::Context.new( adapter: adapter, entitlement: message[:entitlement] ) # Process CLI commands CLI.dispatch(message[:program][:arguments], context) context.exit(0) end end end end # Mount in Rails mount TerminalSocket.new => "/terminal" ``` -------------------------------- ### Bash Commands for Running Terminalwire Tests Source: https://github.com/terminalwire/ruby/blob/main/spec/README.md Provides various bash commands for executing the Terminalwire test suite at different levels of scope. Includes commands for development workflow, pre-commit checks, release testing, and focused testing on specific gems or test files. ```bash # Fast feedback during development bundle exec rake spec:integration # Individual resource testing bundle exec rspec spec/integration/server_client_resources_spec.rb # Specific resource method bundle exec rspec spec/integration/server_client_resources_spec.rb -e "File#read" # Run unit and integration tests (fast) bundle exec rake spec:isolate spec:integration # Skip slow fullstack tests during development bundle exec rspec --exclude-pattern="spec/fullstack/**/*" # Run everything including heavy tests bundle exec rake spec # Just fullstack tests bundle exec rake spec:fullstack # Complete test suite with packages bundle exec rake default # Test specific gem cd gem/terminalwire-server && bundle exec rspec # Test specific integration bundle exec rspec spec/integration/server_client_resources_spec.rb # Test specific fullstack workflow bundle exec rspec spec/fullstack/example_usage_spec.rb ``` -------------------------------- ### Access Client Resources via Server Context in Ruby Source: https://context7.com/terminalwire/ruby/llms.txt This Ruby code demonstrates server-side access to client resources using the terminalwire-server gem's Context object. It covers I/O operations like stdout, stdin, file and directory manipulations, environment variables, browser launching, and session management. Entitlements ensure secure access, with all operations executed client-side after permission checks. ```ruby require 'terminalwire-server' # Inside a server handler (Rails controller, Thor command, etc.) context = Terminalwire::Server::Context.new(adapter: adapter, entitlement: entitlement) # Write to client stdout context.stdout.puts "Hello from server!" context.print "No newline" # Read from client stdin context.print "Enter your name: " name = context.gets.chomp context.print "Enter password: " password = context.getpass # Hidden input # File operations on client filesystem content = context.file.read("/tmp/config.json") context.file.write("/tmp/output.txt", "data") context.file.append("/tmp/log.txt", "entry\n") context.file.delete("/tmp/temp.txt") exists = context.file.exist?("/tmp/file.txt") # => true/false context.file.chmod("/tmp/script.sh", 0755) # Directory operations files = context.directory.list("/tmp/*.txt") context.directory.mkdir("/tmp/newdir") dir_exists = context.directory.exist?("/tmp/mydir") # => true/false context.directory.rm("/tmp/olddir") # Environment variables (client-side) home = context.environment_variable.read("HOME") tw_home = context.ENV["TERMINALWIRE_HOME"] # Launch browser on client context.browser.launch("https://example.com") # Authority and storage paths puts context.authority # => "example.com" puts context.root_path # => Pathname("~/.terminalwire") puts context.storage_path # => Pathname("~/.terminalwire/authorities/example.com/storage") context.exit(0) # Exit with status code ``` -------------------------------- ### Define CLI Application with Thor Source: https://context7.com/terminalwire/ruby/llms.txt Defines a base CLI application class and a specific command-line interface using the Thor gem. The `MainTerminal` class inherits from `ApplicationTerminal` and implements a 'hello' command. This allows for defining commands, their descriptions, and their execution logic. ```ruby class ApplicationTerminal include Terminalwire::Thor def self.channel Terminalwire::Rails::Thor.new(self) end end class MainTerminal < ApplicationTerminal desc "hello NAME", "say hello to NAME" def hello(name) puts "Hello #{name}" end end # config/routes.rb Rails.application.routes.draw do mount MainTerminal.channel => "/terminal/main" end ``` -------------------------------- ### Develop Client-Side Custom Resource Source: https://context7.com/terminalwire/ruby/llms.txt Implements a client-side custom resource for interacting with a local SQLite database. The `Database` resource allows querying and backing up the database. It includes protected `permit` method for custom permission logic based on the command and parameters. ```ruby # Client-side custom resource module Terminalwire::Client::Resource class Database < Base def self.key "database" end def query(sql:) # Execute on client's local database results = SQLite3::Database.new("local.db").execute(sql) results.to_json end def backup(path:) # Backup client database FileUtils.cp("local.db", path) "Backup created" end protected def permit(command, **params) # Custom permission logic case command when "query" params[:sql] !~ /DROP|DELETE/i when "backup" @entitlement.paths.permitted?(params[:path]) else false end end end end # Register in client handler Terminalwire::Client.websocket(url: url) do |handler| handler.resources << Database end ``` -------------------------------- ### Bash Commands for Running Ruby Tests Source: https://github.com/terminalwire/ruby/blob/main/spec/integration/README.md Provides bash commands to execute different test suites within the Ruby project. Includes commands for running lightweight integration tests, heavy fullstack tests, specific resource tests, and all resource tests. ```bash # Run lightweight integration tests (fast) bundle exec rspec spec/integration/ # Run heavy fullstack tests (slow) bundle exec rspec spec/fullstack/ # Run specific resource tests bundle exec rspec spec/integration/resources/file_spec.rb bundle exec rspec spec/integration/resources/stdout_spec.rb # Run all resource tests bundle exec rspec spec/integration/resources/ ``` -------------------------------- ### Client WebSocket Connection and Event Loop Source: https://context7.com/terminalwire/ruby/llms.txt Illustrates the client-side usage of the transport and adapter layers to establish a WebSocket connection and process messages. It includes sending an initialization message and handling incoming messages within an event loop. ```ruby # Usage - client connection Async do endpoint = Async::HTTP::Endpoint.parse("wss://example.com/terminal") Async::WebSocket::Client.connect(endpoint) do |connection| transport = Terminalwire::Transport::WebSocket.new(connection) adapter = Terminalwire::Adapter::Socket.new(transport) # Send initialization adapter.write({ event: "initialization", protocol: { version: "0.1.0" }, program: { arguments: ["hello", "world"] }, entitlement: { authority: "example.com", paths: [], schemes: [], environment_variables: [] } }) # Event loop loop do message = adapter.read break if message.nil? case message[:event] when "resource" # Dispatch to resource handler when "exit" break end end adapter.close end end ``` -------------------------------- ### Client Entitlement Policy Configuration in Ruby Source: https://context7.com/terminalwire/ruby/llms.txt This Ruby code configures security entitlements for Terminalwire client to control server access to client resources like paths, schemes, and environment variables. It depends on the terminalwire-client gem and WebSocket connections. Inputs are permission specifications; outputs are configured handlers. Limitations include denying unauthorized access with errors and using glob patterns for path matching, with defaults for storage and schemes. ```ruby require 'terminalwire-client' url = "wss://example.com/terminal" Terminalwire::Client.websocket(url: url) do |handler| # File and directory path permissions handler.entitlement.paths.permit "/home/user/projects/**/*" handler.entitlement.paths.permit "/tmp/**/*" handler.entitlement.paths.permit "/var/log/app.log" # Path with specific file mode (for executable files) handler.entitlement.paths.permit "/home/user/bin/*", mode: 0755 # URL scheme permissions for browser.launch handler.entitlement.schemes.permit "http" handler.entitlement.schemes.permit "https" handler.entitlement.schemes.permit "mailto" handler.entitlement.schemes.permit "slack" # Environment variable read permissions handler.entitlement.environment_variables.permit "USER" handler.entitlement.environment_variables.permit "HOME" handler.entitlement.environment_variables.permit "PATH" handler.entitlement.environment_variables.permit "DATABASE_URL" # Authority determines storage path and server identity puts handler.entitlement.authority # => "example.com" end ``` -------------------------------- ### Establish WebSocket Connection in Ruby Client Source: https://context7.com/terminalwire/ruby/llms.txt This Ruby code establishes a WebSocket connection to a Terminalwire server using the terminalwire-client gem. It allows customization of entitlements for paths, schemes, and environment variables before connecting. The client sends an initialization message and enters a bidirectional communication loop for command execution. ```ruby require 'terminalwire-client' # Connect to a Terminalwire server url = "wss://example.com/terminal" Terminalwire::Client.websocket(url: url, arguments: ARGV) do |handler| # Optional: customize entitlements before connecting handler.entitlement.paths.permit "/tmp/**/*" handler.entitlement.schemes.permit "mailto" handler.entitlement.environment_variables.permit "USER" end # Output when connected successfully: # Client establishes WebSocket connection # Sends initialization message with entitlements # Server processes commands and returns responses # Connection remains open for bidirectional communication ``` -------------------------------- ### Ruby Client Resource Implementation for File Operations Source: https://context7.com/terminalwire/ruby/llms.txt Implements file system operations (read, write, delete, etc.) on the client-side for Terminalwire. It relies on the `permit` method to enforce security entitlements before executing file commands. Handles file paths and modes. ```ruby # Client resource example (simplified from actual implementation) module Terminalwire::Client::Resource class File < Base def self.key "file" end # Called by Handler when server requests file.read def command(command, **parameters) if permit(command, **parameters) result = public_send(command, **parameters) succeed(result) else fail("Client denied #{command}") end end def read(path:) ::File.read(::File.expand_path(path)) end def write(path:, content:, mode: nil) ::File.open(::File.expand_path(path), "w", mode) { |f| f.write(content) } end def append(path:, content:, mode: nil) ::File.open(::File.expand_path(path), "a", mode) { |f| f.write(content) } end def delete(path:) ::File.delete(::File.expand_path(path)) end def exist(path:) ::File.exist?(::File.expand_path(path)) end def change_mode(path:, mode:) ::File.chmod(mode, ::File.expand_path(path)) end protected def permit(command, path:, mode: nil, **) @entitlement.paths.permitted?(path, mode: mode) end end end ``` -------------------------------- ### Ruby WebSocket Initialization Message for Terminalwire Client Source: https://context7.com/terminalwire/ruby/llms.txt Represents the initial JSON message sent from the Terminalwire client to the server upon connection. It includes protocol version, program details, and client entitlements like paths and schemes. ```json { "event": "initialization", "protocol": { "version": "0.1.0" }, "program": { "name": "my-app", "arguments": ["hello", "world"] }, "entitlement": { "authority": "example.com", "paths": ["/tmp/**/*", "/home/user/**/*"], "schemes": ["http", "https"], "environment_variables": ["HOME", "USER"] } } ``` -------------------------------- ### Implement MessagePack Adapter Layer Source: https://context7.com/terminalwire/ruby/llms.txt Defines an `Adapter::Socket` class that uses MessagePack for serialization and deserialization of data over a transport layer. This adapter handles packing data before sending and unpacking received data, ensuring efficient and structured communication. ```ruby # Adapter layer - MessagePack serialization require 'msgpack' module Terminalwire::Adapter class Socket def initialize(transport) @transport = transport end def write(data) packed_data = MessagePack.pack(data, symbolize_keys: true) @transport.write(packed_data) end def read packed_data = @transport.read return nil if packed_data.nil? MessagePack.unpack(packed_data, symbolize_keys: true) end def close @transport.close end end end ``` -------------------------------- ### Bash command to generate Terminalwire CLI scaffold in Rails Source: https://context7.com/terminalwire/ruby/llms.txt Generates the necessary files and configurations for a Terminalwire CLI application within a Rails project. This command creates an executable stub, base classes, and configures routing. ```bash # Generate CLI scaffold rails generate terminalwire:install my-app ``` -------------------------------- ### Account Terminal Commands in Ruby (login, profile, logout) Source: https://context7.com/terminalwire/ruby/llms.txt This Ruby Thor command class handles user authentication, profile display, and logout in a Terminalwire app. It depends on User model for authentication and Terminalwire session management. Inputs include email, password, and session data; outputs are success messages or user profiles. Limitations include session persistence relying on client-side JWT and requiring active user sessions for profile access. ```ruby class AccountTerminal < ApplicationTerminal desc "login EMAIL", "Login user" def login(email) print "Password: " password = getpass user = User.authenticate(email, password) if user # Write to session (stored as JWT on client) session[:user_id] = user.id session[:email] = user.email session[:token] = user.generate_token session[:expires_at] = 1.hour.from_now.to_i puts "Login successful!" else fail "Authentication failed" end end desc "profile", "Show user profile" def profile # Read from session user_id = session[:user_id] email = session[:email] unless user_id fail "Not logged in. Run: #{self.class.basename} login" end user = User.find(user_id) puts "Email: #{user.email}" puts "Name: #{user.name}" puts "Member since: #{user.created_at.to_date}" end desc "logout", "Logout user" def logout # Clear session file on client session.reset puts "Logged out successfully" end private def current_user @current_user ||= User.find_by(id: session[:user_id]) end def current_user=(user) session[:user_id] = user.id @current_user = user end end ``` -------------------------------- ### Implement WebSocket Transport Layer Source: https://context7.com/terminalwire/ruby/llms.txt Provides a `WebSocket` transport layer implementation using `async-websocket`. This class handles raw WebSocket communication, defining `read`, `write`, and `close` methods for interacting with the underlying WebSocket connection. ```ruby # Transport layer - raw WebSocket communication require 'async' require 'async/websocket/client' module Terminalwire::Transport class WebSocket def initialize(websocket) @websocket = websocket end def read @websocket.read&.buffer end def write(data) @websocket.write(data) end def close @websocket.close end end end ``` -------------------------------- ### Ruby WebSocket Resource Request Message Format Source: https://context7.com/terminalwire/ruby/llms.txt Defines the JSON structure for a server-initiated resource request to the Terminalwire client. It specifies the resource name, action, command, and parameters required for the operation. ```json { "event": "resource", "name": "file", "action": "command", "command": "read", "parameters": { "path": "/tmp/config.json" } } ``` -------------------------------- ### Ruby WebSocket Resource Response Message Format (Success) Source: https://context7.com/terminalwire/ruby/llms.txt The JSON format for a successful resource operation response from the Terminalwire client to the server. It includes the resource name, status, and the actual response data. ```json { "event": "resource", "name": "file", "status": "success", "response": "{\"key\": \"value\"}" } ``` -------------------------------- ### Ruby WebSocket Resource Response Message Format (Failure) Source: https://context7.com/terminalwire/ruby/llms.txt The JSON format for a failed resource operation response from the Terminalwire client to the server. It indicates the resource name, status, and an error message detailing the failure. ```json { "event": "resource", "name": "file", "status": "failure", "response": "Client denied read" } ``` -------------------------------- ### Ruby WebSocket Exit Command Message Format Source: https://context7.com/terminalwire/ruby/llms.txt The JSON message used by the server to signal an exit command to the Terminalwire client. It includes the event type and an exit status code. ```json { "event": "exit", "status": 0 } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.