GatewayService/liveGateway over the real Python tui_gateway: JSON-RPC stdio
framing (Bun.spawn), 16ms event coalescing flushed inside Solid batch(), typed
GatewayError, and a decode-once GatewayEvent Schema (~35-member tagged union;
unknown/malformed events skip via Option.none, never crash the stream).
The Solid sync-v2-style store grows to: streaming text concat (prefer
payload.text), gateway.ready{skin}/skin.changed -> fromSkin reactive re-theme,
LRU id-dedup, and hydrate-while-buffering (resume scaffold). Theming is a 1:1
port of Ink's theme.ts (DARK/LIGHT, detectLightMode, ANSI-256 normalization,
fromSkin) behind a Solid ThemeProvider so existing skins work unchanged and the
view carries NO hardcoded styles. A console-safe diagnostics log (in-memory
ring + NDJSON file) is the single logging path.
Entry gains a live launch path (default; HERMES_TUI_FAKE=1 -> scripted hello)
with an initial-prompt bootstrap (session.create -> prompt.submit) as the
Phase-2-composer stand-in, plus a minimal Ctrl+C graceful quit
(renderer.destroy -> shutdown Deferred -> scope finalizers -> client.stop) so
the engine reaps its own gateway child instead of orphaning it.
Verified: bun run check green (tsc + eslint + 12 tests / 4 files); live tmux
drive connect -> gateway.ready -> prompt -> streamed reply ("pong") -> clean
teardown with no orphan bun/python. Parity matrix + smoke P1 run log updated.
30 lines
1.2 KiB
TypeScript
30 lines
1.2 KiB
TypeScript
/**
|
|
* ThemeProvider — the Solid context that exposes the current Theme to the view
|
|
* (spec v4 §7.5; mirrors opencode `context/theme.tsx`). The view reads
|
|
* `useTheme()().color.*` / `.brand.*` and NEVER hardcodes styles.
|
|
*
|
|
* The theme is a reactive accessor: when the boundary applies a skin
|
|
* (gateway.ready{skin} / skin.changed → store updates the theme), Solid
|
|
* fine-grained reactivity re-styles only the affected cells.
|
|
*/
|
|
import { type Accessor, createContext, type JSX, useContext } from 'solid-js'
|
|
|
|
import { DEFAULT_THEME, type Theme } from '../logic/theme.ts'
|
|
|
|
const ThemeContext = createContext<Accessor<Theme>>(() => DEFAULT_THEME)
|
|
|
|
export interface ThemeProviderProps {
|
|
/** Reactive theme accessor (from the store). Defaults to DEFAULT_THEME if omitted. */
|
|
readonly theme?: Accessor<Theme>
|
|
readonly children: JSX.Element
|
|
}
|
|
|
|
export function ThemeProvider(props: ThemeProviderProps) {
|
|
return <ThemeContext.Provider value={props.theme ?? (() => DEFAULT_THEME)}>{props.children}</ThemeContext.Provider>
|
|
}
|
|
|
|
/** Read the current theme inside a component. Call it (`useTheme()()`) to get the Theme. */
|
|
export function useTheme(): Accessor<Theme> {
|
|
return useContext(ThemeContext)
|
|
}
|