dsh-blue/blue--packages-core ↗★ 1
@dsh-blue/blue-core
Blue terminal UI core: the tree's only @earendil-works/pi-tui adapter, owning terminal lifecycle and the blueScreen/blueKeymap/blueTerminalInfo/blueComponents services plus the blue-theme-dark/light/auto/custom palette entries
安装
此插件尚未提供可验证的 bundle,或兼容性检查未通过。请先阅读仓库说明。 阅读完整 README ↗
说明文档
阅读完整 README ↗@dsh-blue/blue-core
English | 中文
Blue terminal UI core: the only package in the tree that imports @earendil-works/pi-tui. Loading the plugin probes the terminal background (OSC 11, before raw mode), starts the terminal (a main-screen TuiMainScreen renderer over ProcessTerminal: raw mode, bracketed paste, Kitty keyboard negotiation), and registers the L1 services; unloading the plugin stops the terminal and restores its state. The package imports no harness package — only pi-tui and Cordis.
L1 services
The L1 contracts in src/types.ts are self-owned narrow interfaces: no pi-tui type, harness business type, or concrete renderer class appears in them; L0 (src/terminal.ts) delegates to pi-tui internally.
ctx.blueScreen(BlueScreen) — component mounting.addChildreturns a disposer,showOverlayreturns a focus/unfocus handle,setFocusowns the single focus slot,requestRenderschedules throttled redraws,columnsreports the terminal width.BlueComponentis structurally compatible with pi-tui'sComponentbut type-independent.ctx.blueTheme(BlueTheme) — the semantic color table contract. Every value is a(text: string) => stringANSI wrapper over the 28-tokenBlueSemanticColorsset (all required; v2 addsprimary— the interactive color: selection, links, spinner, running indicators — andtextMuted, the deepest gray tier for counters, key hints, and truncation rows). The contract lives in this package'ssrc/types.ts; implementations ship as four subpath plugins, so a theme provider swap needs no consumer change:./theme-dark(blue-theme-dark, the built-in dark palette and plain-baseline default, exportingDARK_COLORS),./theme-light(blue-theme-light, the built-in light palette, exportingLIGHT_COLORS),./theme-auto(blue-theme-auto, injectsblueTerminalInfoto pick dark/light from the probed terminal background and re-provides the palette — swaps serialized through a promise chain — whenever'blue/terminal-theme-changed'fires), and./theme-custom(blue-theme-custom, a JSON file mapping token names to#rrggbblayered over a built-in base palette; its config is validated with@deepseek-ai/schemastery, invalid entries fall back to the base entry with a warning, and an unreadable file falls back to the whole base palette). All four are built on the internalsrc/theme-palette.tsmodule: the hex→ANSI helpers, thecolorsFromForegroundsfrozen-table builder, and thedefineThemeServiceService-subclass factory.ctx.blueKeymap(BlueKeymap) — the keybinding registry, split into a contextual and a global half.register(actions)validates the batch (duplicate ids, keys already claimed by another action) before committing and returns a disposer;matches(data, action)tests an input sequence;getKeys(action)resolves bound keys. An action carrying the optionalhandleris a focus-independent global action; one without it is contextual, resolved by components throughmatches.dispatch(data)runs the global half: handler-carrying actions fire in registration order and it reports whether any handler consumed the input. This plugin'sapplywires the global half itself — a pi-tui input listener mounted ahead of focus routing consumes whateverdispatchclaims — and instantiates the service directly (new BlueKeymapService(ctx)) rather than throughctx.plugin, because the CordisContextproxy rejects a service that was never injected and a service cannot inject itself.ctx.blueTerminalInfo(BlueTerminalInfo) — read-only terminal facts:background('dark' | 'light' | undefined, from the startup OSC 11 probe) andkittyKeyboard(whether the Kitty keyboard protocol negotiated). Later DEC theme reports emit'blue/terminal-theme-changed'('dark' | 'light').ctx.blueComponents(BlueComponents) — the component factory.createEditor/createMarkdown/createSelectList/createSettingsListbuild pi-tui-backed components behind pi-tui-independent interfaces, mapping the activeblueThemepalette onto pi-tui themes (the markdown mapping is the S10 v2 one: headings carry their level through bold, unordered markers normalize to•, and fenced code is colored by cli-highlight behind thehighlightCodehook — unknown languages fall back to plain text, and highlighting never changes line count; the S17 dogfood adds a horizontal-rule post-process to the markdown adapter: pi-tui caps rules at 80 columns regardless of the render width, so the adapter re-paints the capped rule to the full render width — exact string match on the theme's known output, tolerating pi-tui's row padding, so fenced code lines keep their own styling); the editor theme's default border is the neutralbordertoken, with slash/bash contexts recoloring it throughsetBorderColor;visibleWidth/wrapText/truncateToWidthare the shared width pure functions, and — since S14 — the fuzzy pairfuzzyMatch(query, text)(pi-tui's subsequence matcher,{matches, score}with lower-is-better) andfuzzyFilter(items, query, getText)re-export through the contract for every completion surface. The editor built here also owns the S14 dropdown treatment: a/-prefixed autocomplete menu renders through the internalWrappingSelectList(the repo's only pi-tui subclass — descriptions wrap onto at most two lines), other completions keep the stock list, andsetGhostHint(text | undefined)(its first consumer) drives the argument-hint ghost the chrome layer splices in. The factory also providescreateImage(options)(aBlueImage, theBlueComponentalias wrapping pi-tui's Image; terminals without an image protocol get a styled text fallback) andimageDimensions(data)(a pure dimension probe over PNG/JPEG/GIF/WebP bytes,undefinedwhen unrecognized). TheBlueEditorcontract also exposessetAutocompleteProvider(BlueAutocompleteProvider)— the type-independentBlueAutocompleteItem/BlueAutocompleteSuggestions/BlueAutocompleteProvidertrio the L0 adapter passes straight through to the underlying renderer — andgetExpandedText(), which expands paste markers to their full pasted content for submission.BlueEditorfurther carries the pre-dispatch hookonKey?(data)— invoked before the pi-tui Editor handles a sequence, returningtrueconsumes it (the editor-context key chains live here, because pi-tui's Editor swallows Ctrl-C with no fallback exit) —isShowingAutocomplete(), andinsertText(text)— atomic insertion at the cursor, the seam clipboard-image markers use. Since S11 the editor renders as a rounded box: the adapter post-processes each render through the shared chrome helpers (setPromptSymbol('>' | '!' | undefined)overlays a prompt symbol on the first content row — the bash!shares the border hue, the neutral>stays default-foreground;setBorderLabel(text)lays pre-styled text into the top rule, never into scroll indicators;setConnectedAbove(bool)switches the top corners to├┤for a docked panel above), and corners/bars repaint through the live border color so a host recolor stays in sync. The factory injectsblueTheme, so a provider swap rebuilds it through Cordis reload semantics.
Shared chrome helpers
The ./chrome subpath (src/chrome.ts, opened by S11) exports the theme-agnostic pure functions the framed surfaces are drawn with: withSideBorders(lines, paint, {connectedAbove?, label?}) turns pi-tui-style rule rows into ╭╮/╰╯-cornered boxes (repainting pre-painted rules as one span, overlaying │ only on literal outer spaces so the inverse-video cursor survives, and fitting labels only into pure dash runs), injectPromptSymbol(line, symbol, paint?) overlays a prompt symbol on a paddingX: 4 content row, and — since S12 — framePanel(body, width, opts) frames a dialog body in kimi's full-width flat ─ rules (an indented title (kimi: help · Esc …) with an optional muted hint and a key-row footer, every paint defaulting to identity, ANSI-safe truncated) with hintRow(parts, paint) joining key-hint parts with ·. S13 adds the panel chrome: topRule(width, {title, titlePaint, hint, hintPaint, paint}) renders the kimi in-border title row (╭ BTW ─ Esc close ────╮ — the ─ joiner only when both a title and a hint are present, the composite clipped ANSI-safe with the dash fill taking the remainder) and padColumns(lines, n) prefixes a gutter of literal spaces (the pure GutterContainer equivalent; consumption landed with the S17 dogfood margin ruling — the GutterComponent exported from the package root wraps a child at width - 2n and pads the left gutter through it). S14 adds the completion chrome: highlightLeadingSlashToken(line, paint) re-paints the leading /command token through visible-index math (ANSI pass-through survives, so an inverse-video cursor on the row is kept) and injectGhostHint(line, hint, textLength, width, paint) splices the argument-hint ghost after the inverse-video cursor block, consuming trailing padding so the row width holds, ellipsizing on overflow, and returning the row unchanged when the cursor sits mid-text. Paint functions are injected — the module holds no theme and no pi-tui component machinery; further helpers land with their first consumers.
All five contracts are mounted as Cordis Service subclasses (blueTheme by a theme subpath plugin, the rest by this plugin's apply); each unregisters automatically when its plugin's fiber unloads. Components consume the interfaces, never pi-tui types.
Terminal lifecycle
createTerminalRelease() returns the release function for installFailLoud(binName, proc, release) from @deepseek-ai/dsh-app-boot: on a fatal load failure it stops the active terminal stack (draining pending input first) so raw mode and bracketed paste are restored before the process exits. It is a no-op when no Blue terminal is active. Services delegate through a stable proxy reference so a future renderer swap (main/alt screen) needs no consumer change.
Model Experience
None, as the terminal UI core renders to the user and registers nothing model-facing.
KV Cache effect
None; the package adds nothing to any model request prefix.
Known Limitations and Deferred Work
- Crash-log directory is pi's default —
TuiMainScreenwrites its width-overflow crash log to~/.pi/agent(orPI_CODING_AGENT_DIR) because pi-tui hardcodes that default and Blue has no dsh-owned path to thread through yet; a dsh-side log directory is deferred to the alt-screen phase. - Main-screen renderer only — the alternate-screen viewport and runtime renderer swap are deferred; the stable proxy reference is the only seam in place.
- Keymap conflict scope — conflict detection covers actions registered through
ctx.blueKeymap; pi-tui components (Editor, SelectList) resolve their own bindings from pi-tui's global keybindings table, which this package leaves untouched.