diff options
| author | Dax Raad <[email protected]> | 2026-04-14 23:10:07 -0400 |
|---|---|---|
| committer | Dax Raad <[email protected]> | 2026-04-14 23:10:25 -0400 |
| commit | 627159acac04409d7697a6739e2c572c2a010943 (patch) | |
| tree | 5f87465ea69f41aff0cd96ae5411fe438da480b3 /packages/app/src | |
| parent | f44aa02e2677b2b89a1a9f517c0ff8990383deaa (diff) | |
| download | opencode-627159acac04409d7697a6739e2c572c2a010943.tar.gz opencode-627159acac04409d7697a6739e2c572c2a010943.zip | |
delete all e2e tests (#22501)
Cherry-picked from ea463e604cdd2a3e83e1c286e39b789455f0d413
Diffstat (limited to 'packages/app/src')
| -rw-r--r-- | packages/app/src/components/prompt-input.tsx | 17 | ||||
| -rw-r--r-- | packages/app/src/components/prompt-input/submit.ts | 3 | ||||
| -rw-r--r-- | packages/app/src/components/terminal.tsx | 16 | ||||
| -rw-r--r-- | packages/app/src/context/local.tsx | 50 | ||||
| -rw-r--r-- | packages/app/src/pages/error.tsx | 10 | ||||
| -rw-r--r-- | packages/app/src/pages/session/composer/session-composer-state.ts | 55 | ||||
| -rw-r--r-- | packages/app/src/pages/session/composer/session-todo-dock.tsx | 22 | ||||
| -rw-r--r-- | packages/app/src/pages/session/terminal-panel.tsx | 6 | ||||
| -rw-r--r-- | packages/app/src/testing/model-selection.ts | 109 | ||||
| -rw-r--r-- | packages/app/src/testing/prompt.ts | 83 | ||||
| -rw-r--r-- | packages/app/src/testing/session-composer.ts | 84 | ||||
| -rw-r--r-- | packages/app/src/testing/terminal.ts | 119 |
12 files changed, 5 insertions, 569 deletions
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index eedbc91cf..8ddb10a90 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -35,7 +35,6 @@ import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" import { useSessionLayout } from "@/pages/session/session-layout" import { createSessionTabs } from "@/pages/session/helpers" -import { promptEnabled, promptProbe } from "@/testing/prompt" import { createTextFragment, getCursorPosition, setCursorPosition, setRangeEdge } from "./prompt-input/editor-dom" import { createPromptAttachments } from "./prompt-input/attachments" import { ACCEPTED_FILE_TYPES } from "./prompt-input/files" @@ -639,7 +638,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => { const handleSlashSelect = (cmd: SlashCommand | undefined) => { if (!cmd) return - promptProbe.select(cmd.id) closePopover() const images = imageAttachments() @@ -728,21 +726,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => { element?.scrollIntoView({ block: "nearest", behavior: "smooth" }) }) }) - - if (promptEnabled()) { - createEffect(() => { - promptProbe.set({ - popover: store.popover, - slash: { - active: slashActive() ?? null, - ids: slashFlat().map((cmd) => cmd.id), - }, - }) - }) - - onCleanup(() => promptProbe.clear()) - } - const selectPopoverActive = () => { if (store.popover === "at") { const items = atFlat() diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts index 2a3a3d0e9..ad759d08e 100644 --- a/packages/app/src/components/prompt-input/submit.ts +++ b/packages/app/src/components/prompt-input/submit.ts @@ -13,7 +13,6 @@ import { usePermission } from "@/context/permission" import { type ContextItem, type ImageAttachmentPart, type Prompt, usePrompt } from "@/context/prompt" import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" -import { promptProbe } from "@/testing/prompt" import { Identifier } from "@/utils/id" import { Worktree as WorktreeState } from "@/utils/worktree" import { buildRequestParts } from "./build-request-parts" @@ -307,7 +306,6 @@ export function createPromptSubmit(input: PromptSubmitInput) { input.addToHistory(currentPrompt, mode) input.resetHistoryNavigation() - promptProbe.start() const projectDirectory = sdk.directory const isNewSession = !params.id @@ -427,7 +425,6 @@ export function createPromptSubmit(input: PromptSubmitInput) { return } - promptProbe.submit({ sessionID: session.id, directory: sessionDirectory }) input.onSubmit?.() if (mode === "shell") { diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx index c8430d8bb..96a865b9e 100644 --- a/packages/app/src/components/terminal.tsx +++ b/packages/app/src/components/terminal.tsx @@ -13,7 +13,6 @@ import { useSDK } from "@/context/sdk" import { useServer } from "@/context/server" import { monoFontFamily, useSettings } from "@/context/settings" import type { LocalPTY } from "@/context/terminal" -import { terminalAttr, terminalProbe } from "@/testing/terminal" import { disposeIfDisposable, getHoveredLinkText, setOptionIfSupported } from "@/utils/runtime-adapters" import { terminalWriter } from "@/utils/terminal-writer" @@ -178,7 +177,6 @@ export const Terminal = (props: TerminalProps) => { let container!: HTMLDivElement const [local, others] = splitProps(props, ["pty", "class", "classList", "autoFocus", "onConnect", "onConnectError"]) const id = local.pty.id - const probe = terminalProbe(id) const restore = typeof local.pty.buffer === "string" ? local.pty.buffer : "" const restoreSize = restore && @@ -349,9 +347,6 @@ export const Terminal = (props: TerminalProps) => { } onMount(() => { - probe.init() - cleanups.push(() => probe.drop()) - const run = async () => { const loaded = await loadGhostty() if (disposed) return @@ -381,8 +376,6 @@ export const Terminal = (props: TerminalProps) => { term = t output = terminalWriter((data, done) => t.write(data, () => { - probe.render(data) - probe.settle() done?.() }), ) @@ -534,7 +527,6 @@ export const Terminal = (props: TerminalProps) => { const handleOpen = () => { if (disposed) return tries = 0 - probe.connect() local.onConnect?.() scheduleSize(t.cols, t.rows) } @@ -599,13 +591,6 @@ export const Terminal = (props: TerminalProps) => { socket.addEventListener("close", handleClose) } - probe.control({ - disconnect: () => { - if (!ws) return - ws.close(4_000, "e2e") - }, - }) - open() } @@ -645,7 +630,6 @@ export const Terminal = (props: TerminalProps) => { <div ref={container} data-component="terminal" - {...{ [terminalAttr]: id }} data-prevent-autofocus tabIndex={-1} style={{ "background-color": terminalColors().background }} diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx index 1633607de..28ce2770d 100644 --- a/packages/app/src/context/local.tsx +++ b/packages/app/src/context/local.tsx @@ -1,11 +1,10 @@ import { createSimpleContext } from "@opencode-ai/ui/context" import { base64Encode } from "@opencode-ai/util/encode" import { useParams } from "@solidjs/router" -import { batch, createEffect, createMemo, onCleanup } from "solid-js" +import { batch, createEffect, createMemo } from "solid-js" import { createStore } from "solid-js/store" import { useModels } from "@/context/models" import { useProviders } from "@/hooks/use-providers" -import { modelEnabled, modelProbe } from "@/testing/model-selection" import { Persist, persisted } from "@/utils/persist" import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant" import { useSDK } from "./sdk" @@ -388,53 +387,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ }, }, } - - if (modelEnabled()) { - const probe = Symbol("model-probe") - - modelProbe.bind(probe, { - setAgent: agent.set, - setModel: model.set, - setVariant: model.variant.set, - }) - - createEffect(() => { - const agent = result.agent.current() - const model = result.model.current() - modelProbe.set(probe, { - dir: sdk.directory, - sessionID: id(), - last: store.last, - agent: agent?.name, - model: model - ? { - providerID: model.provider.id, - modelID: model.id, - name: model.name, - } - : undefined, - variant: result.model.variant.current() ?? null, - selected: result.model.variant.selected(), - configured: result.model.variant.configured(), - pick: scope(), - base: undefined, - current: store.current, - variants: result.model.variant.list(), - models: result.model - .list() - .filter((item) => result.model.visible({ providerID: item.provider.id, modelID: item.id })) - .map((item) => ({ - providerID: item.provider.id, - modelID: item.id, - name: item.name, - })), - agents: result.agent.list().map((item) => ({ name: item.name })), - }) - }) - - onCleanup(() => modelProbe.clear(probe)) - } - return result }, }) diff --git a/packages/app/src/pages/error.tsx b/packages/app/src/pages/error.tsx index 1cdc06116..11284b3d2 100644 --- a/packages/app/src/pages/error.tsx +++ b/packages/app/src/pages/error.tsx @@ -1,12 +1,11 @@ import { TextField } from "@opencode-ai/ui/text-field" import { Logo } from "@opencode-ai/ui/logo" import { Button } from "@opencode-ai/ui/button" -import { Component, Show, onMount } from "solid-js" +import { Component, Show } from "solid-js" import { createStore } from "solid-js/store" import { usePlatform } from "@/context/platform" import { useLanguage } from "@/context/language" import { Icon } from "@opencode-ai/ui/icon" -import type { E2EWindow } from "@/testing/terminal" export type InitError = { name: string @@ -227,13 +226,6 @@ export const ErrorPage: Component<ErrorPageProps> = (props) => { actionError: undefined as string | undefined, }) - onMount(() => { - const win = window as E2EWindow - if (!win.__opencode_e2e) return - const detail = formatError(props.error, language.t) - console.error(`[e2e:error-boundary] ${window.location.pathname}\n${detail}`) - }) - async function checkForUpdates() { if (!platform.checkUpdate) return setStore("checking", true) diff --git a/packages/app/src/pages/session/composer/session-composer-state.ts b/packages/app/src/pages/session/composer/session-composer-state.ts index eab210868..525766dcf 100644 --- a/packages/app/src/pages/session/composer/session-composer-state.ts +++ b/packages/app/src/pages/session/composer/session-composer-state.ts @@ -1,6 +1,5 @@ -import { createEffect, createMemo, on, onCleanup, onMount } from "solid-js" +import { createEffect, createMemo, on, onCleanup } from "solid-js" import { createStore } from "solid-js/store" -import { makeEventListener } from "@solid-primitives/event-listener" import type { PermissionRequest, QuestionRequest, Todo } from "@opencode-ai/sdk/v2" import { useParams } from "@solidjs/router" import { showToast } from "@opencode-ai/ui/toast" @@ -9,7 +8,6 @@ import { useLanguage } from "@/context/language" import { usePermission } from "@/context/permission" import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" -import { composerDriver, composerEnabled, composerEvent } from "@/testing/session-composer" import { sessionPermissionRequest, sessionQuestionRequest } from "./session-request-tree" export const todoState = (input: { @@ -49,49 +47,7 @@ export function createSessionComposerState(options?: { closeMs?: number | (() => return !!permissionRequest() || !!questionRequest() }) - const [test, setTest] = createStore({ - on: false, - live: undefined as boolean | undefined, - todos: undefined as Todo[] | undefined, - }) - - const pull = () => { - const id = params.id - if (!id) { - setTest({ on: false, live: undefined, todos: undefined }) - return - } - - const next = composerDriver(id) - if (!next) { - setTest({ on: false, live: undefined, todos: undefined }) - return - } - - setTest({ - on: true, - live: next.live, - todos: next.todos?.map((todo) => ({ ...todo })), - }) - } - - onMount(() => { - if (!composerEnabled()) return - - pull() - createEffect(on(() => params.id, pull, { defer: true })) - - const onEvent = (event: Event) => { - const detail = (event as CustomEvent<{ sessionID?: string }>).detail - if (detail?.sessionID !== params.id) return - pull() - } - - makeEventListener(window, composerEvent, onEvent) - }) - const todos = createMemo((): Todo[] => { - if (test.on && test.todos !== undefined) return test.todos const id = params.id if (!id) return [] return globalSync.data.session_todo[id] ?? [] @@ -108,10 +64,7 @@ export function createSessionComposerState(options?: { closeMs?: number | (() => }) const busy = createMemo(() => status().type !== "idle") - const live = createMemo(() => { - if (test.on && test.live !== undefined) return test.live - return busy() || blocked() - }) + const live = createMemo(() => busy() || blocked()) const [store, setStore] = createStore({ responding: undefined as string | undefined, @@ -163,10 +116,6 @@ export function createSessionComposerState(options?: { closeMs?: number | (() => // Keep stale turn todos from reopening if the model never clears them. const clear = () => { - if (test.on && test.todos !== undefined) { - setTest("todos", []) - return - } const id = params.id if (!id) return globalSync.todo.set(id, []) diff --git a/packages/app/src/pages/session/composer/session-todo-dock.tsx b/packages/app/src/pages/session/composer/session-todo-dock.tsx index 2214248b1..fa8c17734 100644 --- a/packages/app/src/pages/session/composer/session-todo-dock.tsx +++ b/packages/app/src/pages/session/composer/session-todo-dock.tsx @@ -7,9 +7,8 @@ import { useSpring } from "@opencode-ai/ui/motion-spring" import { TextReveal } from "@opencode-ai/ui/text-reveal" import { TextStrikethrough } from "@opencode-ai/ui/text-strikethrough" import { createResizeObserver } from "@solid-primitives/resize-observer" -import { Index, createEffect, createMemo, onCleanup } from "solid-js" +import { Index, createEffect, createMemo } from "solid-js" import { createStore } from "solid-js/store" -import { composerEnabled, composerProbe } from "@/testing/session-composer" import { useLanguage } from "@/context/language" const doneToken = "\u0000done\u0000" @@ -81,8 +80,6 @@ export function SessionTodoDock(props: { const off = createMemo(() => hide() > 0.98) const turn = createMemo(() => Math.max(0, Math.min(1, value()))) const full = createMemo(() => Math.max(78, store.height)) - const e2e = composerEnabled() - const probe = composerProbe(props.sessionID) let contentRef: HTMLDivElement | undefined createEffect(() => { @@ -95,23 +92,6 @@ export function SessionTodoDock(props: { createResizeObserver(el, update) }) - createEffect(() => { - if (!e2e) return - - probe.set({ - mounted: true, - collapsed: store.collapsed, - hidden: store.collapsed || off(), - count: props.todos.length, - states: props.todos.map((todo) => todo.status), - }) - }) - - onCleanup(() => { - if (!e2e) return - probe.drop() - }) - return ( <DockTray data-component="session-todo-dock" diff --git a/packages/app/src/pages/session/terminal-panel.tsx b/packages/app/src/pages/session/terminal-panel.tsx index 1161d565a..2c2d9817f 100644 --- a/packages/app/src/pages/session/terminal-panel.tsx +++ b/packages/app/src/pages/session/terminal-panel.tsx @@ -19,7 +19,6 @@ import { terminalTabLabel } from "@/pages/session/terminal-label" import { createSizing, focusTerminalById } from "@/pages/session/helpers" import { getTerminalHandoff, setTerminalHandoff } from "@/pages/session/handoff" import { useSessionLayout } from "@/pages/session/session-layout" -import { terminalProbe } from "@/testing/terminal" export function TerminalPanel() { const delays = [120, 240] @@ -78,12 +77,9 @@ export function TerminalPanel() { ) const focus = (id: string) => { - const probe = terminalProbe(id) - probe.focus(delays.length + 1) focusTerminalById(id) const frame = requestAnimationFrame(() => { - probe.step() if (!opened()) return if (terminal.active() !== id) return focusTerminalById(id) @@ -91,7 +87,6 @@ export function TerminalPanel() { const timers = delays.map((ms) => window.setTimeout(() => { - probe.step() if (!opened()) return if (terminal.active() !== id) return focusTerminalById(id) @@ -99,7 +94,6 @@ export function TerminalPanel() { ) return () => { - probe.focus(0) cancelAnimationFrame(frame) for (const timer of timers) clearTimeout(timer) } diff --git a/packages/app/src/testing/model-selection.ts b/packages/app/src/testing/model-selection.ts deleted file mode 100644 index d2770fe28..000000000 --- a/packages/app/src/testing/model-selection.ts +++ /dev/null @@ -1,109 +0,0 @@ -type ModelKey = { - providerID: string - modelID: string -} - -type ModelItem = ModelKey & { - name: string -} - -type AgentItem = { - name: string -} - -type State = { - agent?: string - model?: ModelKey | null - variant?: string | null -} - -export type ModelProbeState = { - dir?: string - sessionID?: string - last?: { - type: "agent" | "model" | "variant" - agent?: string - model?: ModelKey | null - variant?: string | null - } - agent?: string - model?: (ModelKey & { name?: string }) | undefined - variant?: string | null - selected?: string | null - configured?: string - pick?: State - base?: State - current?: string - variants?: string[] - models?: ModelItem[] - agents?: AgentItem[] -} - -export type ModelWindow = Window & { - __opencode_e2e?: { - model?: { - enabled?: boolean - current?: ModelProbeState - controls?: { - setAgent?: (name: string | undefined) => void - setModel?: (value: ModelKey | undefined) => void - setVariant?: (value: string | undefined) => void - } - } - } -} - -const clone = (state?: State) => { - if (!state) return undefined - return { - ...state, - model: state.model ? { ...state.model } : state.model, - } -} - -let active: symbol | undefined - -export const modelEnabled = () => { - if (typeof window === "undefined") return false - return (window as ModelWindow).__opencode_e2e?.model?.enabled === true -} - -const root = () => { - if (!modelEnabled()) return - return (window as ModelWindow).__opencode_e2e?.model -} - -export const modelProbe = { - bind(id: symbol, input: NonNullable<NonNullable<ModelWindow["__opencode_e2e"]>["model"]>["controls"]) { - const state = root() - if (!state) return - active = id - state.controls = input - }, - set(id: symbol, input: ModelProbeState) { - const state = root() - if (!state || active !== id) return - state.current = { - ...input, - model: input.model ? { ...input.model } : undefined, - last: input.last - ? { - ...input.last, - model: input.last.model ? { ...input.last.model } : input.last.model, - } - : undefined, - pick: clone(input.pick), - base: clone(input.base), - variants: input.variants?.slice(), - models: input.models?.map((item) => ({ ...item })), - agents: input.agents?.map((item) => ({ ...item })), - } - }, - clear(id: symbol) { - const state = root() - if (!state || active !== id) return - active = undefined - state.current = undefined - state.controls = undefined - }, -} diff --git a/packages/app/src/testing/prompt.ts b/packages/app/src/testing/prompt.ts deleted file mode 100644 index 5102ed825..000000000 --- a/packages/app/src/testing/prompt.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { E2EWindow } from "./terminal" - -export type PromptProbeState = { - popover: "at" | "slash" | null - slash: { - active: string | null - ids: string[] - } - selected: string | null - selects: number -} - -export type PromptSendState = { - started: number - count: number - sessionID?: string - directory?: string -} - -export const promptEnabled = () => { - if (typeof window === "undefined") return false - return (window as E2EWindow).__opencode_e2e?.prompt?.enabled === true -} - -const root = () => { - if (!promptEnabled()) return - return (window as E2EWindow).__opencode_e2e?.prompt -} - -export const promptProbe = { - set(input: Omit<PromptProbeState, "selected" | "selects">) { - const state = root() - if (!state) return - state.current = { - popover: input.popover, - slash: { - active: input.slash.active, - ids: [...input.slash.ids], - }, - selected: state.current?.selected ?? null, - selects: state.current?.selects ?? 0, - } - }, - select(id: string) { - const state = root() - if (!state) return - const prev = state.current - state.current = { - popover: prev?.popover ?? null, - slash: { - active: prev?.slash.active ?? null, - ids: [...(prev?.slash.ids ?? [])], - }, - selected: id, - selects: (prev?.selects ?? 0) + 1, - } - }, - clear() { - const state = root() - if (!state) return - state.current = undefined - }, - start() { - const state = root() - if (!state) return - state.sent = { - started: (state.sent?.started ?? 0) + 1, - count: state.sent?.count ?? 0, - sessionID: state.sent?.sessionID, - directory: state.sent?.directory, - } - }, - submit(input: { sessionID: string; directory: string }) { - const state = root() - if (!state) return - state.sent = { - started: state.sent?.started ?? 0, - count: (state.sent?.count ?? 0) + 1, - sessionID: input.sessionID, - directory: input.directory, - } - }, -} diff --git a/packages/app/src/testing/session-composer.ts b/packages/app/src/testing/session-composer.ts deleted file mode 100644 index 01c809e4c..000000000 --- a/packages/app/src/testing/session-composer.ts +++ /dev/null @@ -1,84 +0,0 @@ -import type { Todo } from "@opencode-ai/sdk/v2" - -export const composerEvent = "opencode:e2e:composer" - -export type ComposerDriverState = { - live?: boolean - todos?: Array<Pick<Todo, "content" | "status" | "priority">> -} - -export type ComposerProbeState = { - mounted: boolean - collapsed: boolean - hidden: boolean - count: number - states: Todo["status"][] -} - -type ComposerState = { - driver?: ComposerDriverState - probe?: ComposerProbeState -} - -export type ComposerWindow = Window & { - __opencode_e2e?: { - composer?: { - enabled?: boolean - sessions?: Record<string, ComposerState> - } - } -} - -const clone = (driver: ComposerDriverState) => ({ - live: driver.live, - todos: driver.todos?.map((todo) => ({ ...todo })), -}) - -export const composerEnabled = () => { - if (typeof window === "undefined") return false - return (window as ComposerWindow).__opencode_e2e?.composer?.enabled === true -} - -const root = () => { - if (!composerEnabled()) return - const state = (window as ComposerWindow).__opencode_e2e?.composer - if (!state) return - state.sessions ??= {} - return state.sessions -} - -export const composerDriver = (sessionID?: string) => { - if (!sessionID) return - const state = root()?.[sessionID]?.driver - if (!state) return - return clone(state) -} - -export const composerProbe = (sessionID?: string) => { - const set = (next: ComposerProbeState) => { - if (!sessionID) return - const sessions = root() - if (!sessions) return - const prev = sessions[sessionID] ?? {} - sessions[sessionID] = { - ...prev, - probe: { - ...next, - states: [...next.states], - }, - } - } - - return { - set, - drop() { - set({ - mounted: false, - collapsed: false, - hidden: true, - count: 0, - states: [], - }) - }, - } -} diff --git a/packages/app/src/testing/terminal.ts b/packages/app/src/testing/terminal.ts deleted file mode 100644 index db8001ddf..000000000 --- a/packages/app/src/testing/terminal.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type { ModelProbeState } from "./model-selection" - -export const terminalAttr = "data-pty-id" - -export type TerminalProbeState = { - connected: boolean - connects: number - rendered: string - settled: number - focusing: number -} - -type TerminalProbeControl = { - disconnect?: VoidFunction -} - -export type E2EWindow = Window & { - __opencode_e2e?: { - model?: { - enabled?: boolean - current?: ModelProbeState - } - prompt?: { - enabled?: boolean - current?: import("./prompt").PromptProbeState - sent?: import("./prompt").PromptSendState - } - terminal?: { - enabled?: boolean - terminals?: Record<string, TerminalProbeState> - controls?: Record<string, TerminalProbeControl> - } - } -} - -const seed = (): TerminalProbeState => ({ - connected: false, - connects: 0, - rendered: "", - settled: 0, - focusing: 0, -}) - -const root = () => { - if (typeof window === "undefined") return - const state = (window as E2EWindow).__opencode_e2e?.terminal - if (!state?.enabled) return - return state -} - -const terms = () => { - const state = root() - if (!state) return - state.terminals ??= {} - return state.terminals -} - -const controls = () => { - const state = root() - if (!state) return - state.controls ??= {} - return state.controls -} - -export const terminalProbe = (id: string) => { - const set = (next: Partial<TerminalProbeState>) => { - const state = terms() - if (!state) return - state[id] = { ...(state[id] ?? seed()), ...next } - } - - return { - init() { - set(seed()) - }, - connect() { - const state = terms() - if (!state) return - const prev = state[id] ?? seed() - state[id] = { - ...prev, - connected: true, - connects: prev.connects + 1, - } - }, - render(data: string) { - const state = terms() - if (!state) return - const prev = state[id] ?? seed() - state[id] = { ...prev, rendered: prev.rendered + data } - }, - settle() { - const state = terms() - if (!state) return - const prev = state[id] ?? seed() - state[id] = { ...prev, settled: prev.settled + 1 } - }, - focus(count: number) { - set({ focusing: Math.max(0, count) }) - }, - step() { - const state = terms() - if (!state) return - const prev = state[id] ?? seed() - state[id] = { ...prev, focusing: Math.max(0, prev.focusing - 1) } - }, - control(next: Partial<TerminalProbeControl>) { - const state = controls() - if (!state) return - state[id] = { ...(state[id] ?? {}), ...next } - }, - drop() { - const state = terms() - if (state) delete state[id] - const control = controls() - if (control) delete control[id] - }, - } -} |
