Share the shell/terminal integration as a package (v1.15.0) - #46
Merged
Conversation
OmnyShell Web is now a package as well as an app: any Dart web app can embed a real remote shell — PTY sizing, soft-keyboard insets, line editing, history and flow control already solved — instead of rebuilding the hard parts. The first consumer is the OmnyServer fleet dashboard, whose Hub can host an OmnyShell broker on the same port. The app itself is unchanged: same screens, same behaviour, same tests, passing unmodified. What moved is what had to, to make the terminal embeddable. - Three public barrels: terminal.dart, ui_kit.dart, client.dart (plus foundation.dart, the DOM-free half, so a consumer's service and controller layers stay unit-testable on the VM instead of needing headless Chrome). app/, ui/screens/ and settings_panel stay app-private — exporting them is what would let the shared tier re-acquire AppContext coupling. - TerminalFitter: the sizing engine, lifted out of SessionViewScreen where it was ~140 private lines. It is the hardest code here (a terminal that grows but never shrinks, renders 0x0, or hides its last line behind a keyboard is what a wrong piece of it produces) and no consumer should copy it. - bin/copy_assets.dart: a package ships its web/ inside the pub archive but pub never serves it to a consumer, so without this the terminal loads to a blank box and the widgets render unstyled. - Storage prefixes are parameterized (default unchanged). localStorage is per-origin and one Hub can serve two apps, which would otherwise clobber each other's theme, Hub and token. - XtermTheme: xterm paints to a canvas and cannot inherit CSS custom properties, so an embedding app must be able to state its colours. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Another web app can now embed an OmnyShell terminal — xterm view, PTY bridge, mobile fit engine, accessory bar — by depending on this package, instead of copying the hardest 600 lines in the repo.
The app is unchanged: same screens, same behaviour, same 151 VM + 65 Chrome tests passing, same dart2js size gate.
What was blocking reuse
WebShellHost(475 lines) already had zero app coupling. Three things around it did not:SessionViewScreen— fitting cols/rows to the viewport, scaling the font, and holding the prompt above the iOS keyboard viavisualViewport. Extracted toTerminalFitterinlib/terminal/terminal_fitter.dart, which the screen now delegates to.omnyshell.. Two omny apps served from the same Hub origin share onelocalStorage, so the second would clobber the first's theme, hub and token.SettingsStore,NodeCacheandCommandHistorynow take aprefix, defaulting toomnyshell.— existing keys unchanged.XtermTerminalViewnow takes anXtermTheme.Public surface
Four barrels, so consumers never deep-import:
terminal.dart,ui_kit.dart,client.dartandfoundation.dart— the last being the DOM-free half, so a consumer's own logic stays testable on the VM.app/,ui/screens/andui/settings_panel.dartstay app-private.Assets ship in the archive and
dart run omnyshell_web:copy_assetscopies the xterm bundle and CSS into a consumer'sweb/.web/styles.cssis split intokit.css(tokens, widgets, modal, toasts) andterminal.css(terminal chrome, keyboard insets), so an app can take the terminal without the look.The README leads with the package recipe and
example/is a standalone terminal in ~40 lines — which also proves the barrels suffice.omnyserver_webis the first consumer.🤖 Generated with Claude Code