# XO-CLI & XO-TUI ## Installation ```bash # Clone the CLI Repo git clone https://git.harvmaster.com/Harvmaster/xo-cli.git # Move into the cli directory cd xo-cli git checkout engine-v0.0.2 # Install the dependencies npm ci # Run the CLI npm run dev ``` ### Run TUI in dev mode ```bash npm run dev ``` # Not fully tested past this point ### Install globally ```bash # (From the xo-cli directory) npm install -g . ``` ### Install autocomplete completions (From the xo-cli directory) These commands add `XO_CONFIG_DIR` to your shell config with a default of `~/.config/xo-cli`. Set it to an absolute path before installing, or edit the generated assignment, to use a different wallet-state directory. #### Install for bash ```bash npm run autocomplete:install:bash ``` #### Install for zsh ```bash npm run autocomplete:install:zsh ``` #### Install for fish ```bash npm run autocomplete:install:fish ``` ### Run the CLI ```bash # If globally installed (Not really usable if not globally installed) xo-cli ``` ### Run the TUI ```bash # If globally installed xo-tui # If not globally installed npm run dev ``` ## TODO ### Track invitation sync-server connectivity without blocking the UI Each `Invitation` currently owns a `SyncServer` instance for its invitation identifier. The invitation uses that instance to open an SSE connection, fetch remote state, and publish local changes. Publish requests are intentionally fire-and-forget so that invitation actions and the TUI stay responsive when the sync server is slow or unavailable. The tradeoff is that failed background requests and SSE connection changes are not represented as application state. `SyncServer` already emits `connected`, `disconnected`, and `error` events, and `Invitation` emits errors from failed publishes, but there is no app-level owner that aggregates those events. The UI therefore cannot reliably tell the user that an invitation may only be updated locally and is not currently syncing with other participants. Implement an app-owned `InvitationConnectivityService` (or similarly named invitation watcher) with the following responsibilities: - Register an invitation and its `SyncServer` when `AppService` creates or loads it, and unregister it when the invitation is removed or stopped. - Listen for each sync server's `connected`, `disconnected`, and `error` events, plus invitation publish failures. - Track connectivity separately from the invitation's business status (`actionable`, `signed`, `ready`, and so on). Suggested transport states are `connecting`, `online`, `offline`, and `degraded`, with the last error and last successful connection timestamp available for diagnostics. - Expose both per-invitation state and an aggregate app-level state such as "one or more invitations are not syncing". - Emit normalized connectivity-change events that the CLI can log and the TUI can subscribe to without awaiting sync-server requests. Keep local persistence and local invitation actions independent from remote sync health. Failed sync attempts should not freeze normal wallet interaction. The service should provide a retry path, or observe retry events from the SSE client, and clear the warning after connectivity recovers. If publish retries are added, make the retry policy explicit and preserve commit idempotency. For UI integration, inject a small notification function or subscribe at the app-context layer rather than having invitation instances render UI directly. The first version can show an error dialog when the aggregate state becomes unhealthy. A less intrusive version can expose the same state as a warning icon or message in the TUI status bar and reserve dialogs for prolonged failures or explicit user actions. While making this change, consolidate invitation startup ownership. Startup is currently triggered during `Invitation.create()` and again by `AppService.createInvitation()`. The watcher should have one clear lifecycle point so connections, listeners, retries, and cleanup are registered exactly once.