@xenosystem/blocks 0.13.28 → 0.13.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -469,6 +469,8 @@ var ICON_UNITS = Object.keys(ICONS);
469
469
  export {
470
470
  Svg,
471
471
  RefreshGlyph,
472
+ XGlyph,
473
+ PlusGlyph,
472
474
  ChevronGlyph,
473
475
  SortAscGlyph,
474
476
  SortDescGlyph,
@@ -12,7 +12,7 @@ import {
12
12
  RefreshGlyph,
13
13
  SortAscGlyph,
14
14
  SortDescGlyph
15
- } from "../chunk-7S2RKUAM.js";
15
+ } from "../chunk-4IDY5FHM.js";
16
16
  import "../chunk-2KG3PWR4.js";
17
17
 
18
18
  // src/data/table/panel.ts
@@ -21,7 +21,7 @@ import {
21
21
  VisibilityIcon,
22
22
  XIcon,
23
23
  XIcon2
24
- } from "../chunk-7S2RKUAM.js";
24
+ } from "../chunk-4IDY5FHM.js";
25
25
  import "../chunk-2KG3PWR4.js";
26
26
 
27
27
  // src/edit/layers/panel.ts
@@ -2,7 +2,7 @@ import {
2
2
  ICONS,
3
3
  ICON_UNITS,
4
4
  Svg
5
- } from "../chunk-7S2RKUAM.js";
5
+ } from "../chunk-4IDY5FHM.js";
6
6
  import "../chunk-2KG3PWR4.js";
7
7
  export {
8
8
  ICONS,
@@ -607,7 +607,7 @@ interface ConsoleViewOptions {
607
607
  declare function consoleViewState(c: ConsoleController, options?: ConsoleViewOptions): ConsoleViewModel;
608
608
  declare function applyConsoleUi(c: ConsoleController, intent: ConsoleUiIntent): void;
609
609
  declare const consoleViewManifest: PanelManifest;
610
- declare const BEHAVIOURS$2: {
610
+ declare const BEHAVIOURS$3: {
611
611
  'ops/consolePanelView': (inputs: Record<string, unknown>) => ConsoleViewModel;
612
612
  };
613
613
  /** The runtime-bound unit: the scroller the virtualizer measures and follow-mode pins. */
@@ -1518,7 +1518,7 @@ interface RunsViewOptions {
1518
1518
  declare function runsViewState(c: RunsController, options?: RunsViewOptions): RunsViewModel;
1519
1519
  declare function applyRunsUi(c: RunsController, intent: RunsUiIntent): void;
1520
1520
  declare const runsViewManifest: PanelManifest;
1521
- declare const BEHAVIOURS$1: {
1521
+ declare const BEHAVIOURS$2: {
1522
1522
  'ops/runsPanelView': (inputs: Record<string, unknown>) => RunsViewModel;
1523
1523
  };
1524
1524
  declare const RUNS_RUNTIME_UNITS: readonly [];
@@ -1981,18 +1981,86 @@ declare const TERMINAL_PANEL_ID = "xeno.core.terminal";
1981
1981
  declare const terminalManifest: PanelManifest;
1982
1982
 
1983
1983
  /**
1984
- * The Terminal panel view.
1984
+ * The Terminal panel AS A DECLARATION — the twenty-fifth block written the §8d way, the fourth
1985
+ * DRAWN surface. The CHROME is data: the session strip (a `chrome/TabStrip` of `Tab`s — title, a
1986
+ * status chip, a pointer-only close whose keyboard path is Delete on the strip), the new-terminal and find actions, the find bar, the empty states,
1987
+ * the cwd and size readouts. The SURFACES are one runtime unit (`terminal/Surfaces`) bound to the
1988
+ * controller and the host's emulator factory: one bare `<div>` per session that the emulator owns
1989
+ * outright — hidden, never unmounted, when another tab is active, so the on-screen buffer survives.
1985
1990
  *
1986
- * **Where primitives fit and where they do not.** The tab strip, status chips and find bar use
1987
- * `Toolbar`/`Badge`/`SearchField`/`TextButton`. The terminal body does not use a primitive at all —
1988
- * it is a bare `<div>` that xterm owns outright, and wrapping it in anything that sets padding,
1989
- * overflow or transform breaks the emulator's own measurement. That div is deliberately plain.
1991
+ * Presentation contract: input `view` (a {@link TerminalViewModel}), output `ui` (a
1992
+ * {@link TerminalUiIntent}) applied by the runtime to the controller's own methods.
1993
+ */
1994
+
1995
+ /** The half of a renderer's config the view reads. */
1996
+ interface TerminalViewOptions {
1997
+ multiInstance?: boolean;
1998
+ /** Whether the runtime has an emulator to render into — without one the panel says so. */
1999
+ hasEmulator?: boolean;
2000
+ }
2001
+ interface TerminalViewTab {
2002
+ key: string;
2003
+ id: string;
2004
+ title: string;
2005
+ selected: boolean;
2006
+ chip: string | null;
2007
+ chipTone: 'error' | 'neutral';
2008
+ closeLabel: string;
2009
+ }
2010
+ interface TerminalViewModel {
2011
+ noEmulator: boolean;
2012
+ ready: boolean;
2013
+ stripShown: boolean;
2014
+ tabs: TerminalViewTab[];
2015
+ tabIds: string[];
2016
+ activeId: string;
2017
+ findShown: boolean;
2018
+ find: string;
2019
+ empty: boolean;
2020
+ surfacesShown: boolean;
2021
+ cwdLabel?: string;
2022
+ sizeLabel?: string;
2023
+ }
2024
+ type TerminalUiIntent = {
2025
+ kind: 'activate';
2026
+ id: string;
2027
+ } | {
2028
+ kind: 'close';
2029
+ id: string;
2030
+ } | {
2031
+ kind: 'open';
2032
+ } | {
2033
+ kind: 'toggleFind';
2034
+ } | {
2035
+ kind: 'find';
2036
+ value: string;
2037
+ } | {
2038
+ kind: 'findStep';
2039
+ direction: 'next' | 'previous';
2040
+ };
2041
+ /** Derive the view model from the live controller — the runtime calls this on every draw. */
2042
+ declare function terminalViewState(c: TerminalController, options?: TerminalViewOptions): TerminalViewModel;
2043
+ /** Apply a `ui` intent to the controller — the runtime's half of the contract. */
2044
+ declare function applyTerminalUi(c: TerminalController, intent: TerminalUiIntent): void;
2045
+ declare const terminalViewManifest: PanelManifest;
2046
+ declare const BEHAVIOURS$1: {
2047
+ 'ops/terminalPanelView': (inputs: Record<string, unknown>) => TerminalViewModel;
2048
+ };
2049
+ declare const TERMINAL_DECLARATION: BlockDeclaration;
2050
+
2051
+ /**
2052
+ * The Terminal panel view — the CODE VIEW of `TERMINAL_DECLARATION`, drawing the same
2053
+ * {@link TerminalViewModel} byte-identical (the equivalence suite holds the two together). The one
2054
+ * runtime-bound unit is the SURFACES (`terminal/Surfaces`): one bare `<div>` per session that xterm
2055
+ * owns outright — wrapping it in anything that sets padding, overflow or transform breaks the
2056
+ * emulator's own measurement, so that div is deliberately plain. Every chrome intent goes through
2057
+ * `applyTerminalUi`.
1990
2058
  *
1991
2059
  * @module
1992
2060
  */
1993
2061
 
1994
2062
  /** Props for {@link TerminalPanelView}. */
1995
- interface TerminalPanelViewProps {
2063
+ interface TerminalPanelViewProps extends Omit<TerminalViewOptions, 'hasEmulator'> {
1996
2064
  controller: TerminalController;
1997
2065
  /**
1998
2066
  * Build an emulator. Async so the default xterm adapter can be dynamically imported.
@@ -2001,10 +2069,18 @@ interface TerminalPanelViewProps {
2001
2069
  * rectangle — a terminal with no emulator is a configuration mistake, and it should say so.
2002
2070
  */
2003
2071
  createEmulator?: () => Promise<XenoTerminalEmulator>;
2004
- multiInstance?: boolean;
2005
2072
  }
2073
+ /** Every session's surface, the active one shown — `terminal/Surfaces` in the declaration. */
2074
+ declare function TerminalSurfaces({ controller, createEmulator }: {
2075
+ controller: TerminalController;
2076
+ createEmulator: () => Promise<XenoTerminalEmulator>;
2077
+ }): ReactNode;
2006
2078
  /** The Terminal panel view. */
2007
- declare function TerminalPanelView({ controller, createEmulator, multiInstance, }: TerminalPanelViewProps): ReactNode;
2079
+ declare function TerminalPanelView({ controller, createEmulator, multiInstance }: TerminalPanelViewProps): ReactNode;
2080
+ /** The unit names the runtime supplies for this block — what a host's registry check must accept beside the shared families. */
2081
+ declare const TERMINAL_RUNTIME_UNITS: readonly ["terminal/Surfaces"];
2082
+ /** The units the runtime registers for `TERMINAL_DECLARATION`, bound to ITS controller and emulator factory. */
2083
+ declare function terminalRuntimeComponents(controller: TerminalController, createEmulator: () => Promise<XenoTerminalEmulator>): Record<(typeof TERMINAL_RUNTIME_UNITS)[number], React.ComponentType<any>>;
2008
2084
 
2009
2085
  /**
2010
2086
  * The Diff contract.
@@ -2594,4 +2670,4 @@ declare function DiffPanelView({ controller, ...options }: DiffPanelViewProps):
2594
2670
  /** The unit names the runtime supplies for this block — none; every unit is a chrome unit. */
2595
2671
  declare const DIFF_RUNTIME_UNITS: readonly [];
2596
2672
 
2597
- export { ALL_STATUSES, BEHAVIOURS$2 as CONSOLE_BEHAVIOURS, CONSOLE_DECLARATION, CONSOLE_PANEL_ID, CONSOLE_RUNTIME_UNITS, ConsoleController, type ConsoleControllerOptions, type ConsoleHostBridge, type ConsolePanelState, ConsolePanelView, type ConsolePanelViewProps, type ConsoleRenderContext, ConsoleScroller, type ConsoleUiIntent, type ConsoleViewModel, type ConsoleViewOptions, type ConsoleViewRow, type ConsoleViewSource, type ConsoleViewState, type CreateConsolePanelOptions, type CreateDiffPanelOptions, type CreateRunsPanelOptions, type CreateTerminalPanelOptions, DEFAULT_MAX_STEP_DEPTH, BEHAVIOURS as DIFF_BEHAVIOURS, DIFF_DECLARATION, DIFF_PANEL_ID, DIFF_RUNTIME_UNITS, DiffController, type DiffControllerOptions, type DiffFileView, type DiffHostBridge, type DiffPanelState, DiffPanelView, type DiffPanelViewProps, type DiffRenderContext, type DiffUiIntent, type DiffViewFile, type DiffViewHunk, type DiffViewLine, type DiffViewModel, type DiffViewOptions, type DiffViewRun, type DiffViewSplitRow, type DiffViewState, type FlattenOptions, LEVEL_ORDER, MESSAGE_ELISION, REDACTION_CARRY, BEHAVIOURS$1 as RUNS_BEHAVIOURS, RUNS_DECLARATION, RUNS_PANEL_ID, RUNS_RUNTIME_UNITS, RUN_PATH_SEPARATOR, RUN_STATUSES, RunsController, type RunsControllerOptions, type RunsHostBridge, type RunsPanelState, RunsPanelView, type RunsPanelViewProps, type RunsRenderContext, type RunsUiIntent, type RunsViewChip, type RunsViewModel, type RunsViewOptions, type RunsViewRow, type RunsViewState, TERMINAL_PANEL_ID, TERMINAL_STATUSES, TerminalController, type TerminalControllerOptions, type TerminalHostBridge, type TerminalInstanceView, type TerminalPanelState, TerminalPanelView, type TerminalPanelViewProps, type TerminalRenderContext, type TerminalViewState, XENO_TERMINAL_THEME_KEYS, type XenoDiffAction, type XenoDiffDecision, type XenoDiffDecisionIntent, type XenoDiffDecisionState, type XenoDiffFile, type XenoDiffFileOmission, type XenoDiffHighlighter, type XenoDiffHunk, type XenoDiffLine, type XenoDiffLineKind, type XenoDiffModel, type XenoDiffNavigate, type XenoDiffSegment, type XenoDiffStatus, type XenoDiffView, type XenoLogActivate, type XenoLogDelta, type XenoLogFilter, type XenoLogLevel, type XenoLogPatch, type XenoLogRecord, type XenoLogSource, type XenoRun, type XenoRunAction, type XenoRunActivate, type XenoRunDelta, type XenoRunError, type XenoRunFilter, type XenoRunLifecycle, type XenoRunPath, type XenoRunRow, type XenoRunRunRow, type XenoRunStats, type XenoRunStatus, type XenoRunStep, type XenoRunStepAppend, type XenoRunStepPatch, type XenoRunStepRow, type XenoRunTruncation, type XenoTerminalData, type XenoTerminalEmulator, type XenoTerminalId, type XenoTerminalIntent, type XenoTerminalSession, type XenoTerminalStatus, type XenoTerminalTheme, appendStepsAtPath, applyConsoleUi, applyDiffUi, applyRunsUi, canCancel, canRetry, collapseAdjacent, computeStats, consoleManifest, consolePanel, consoleRuntimeComponents, consoleViewManifest, consoleViewState, countChanges, createConsolePanel, createDiffPanel, createRunsPanel, createTerminalPanel, decodeRunPath, diffManifest, diffPanel, diffViewManifest, diffViewState, durationOf, encodeRunPath, flattenHunks, flattenRunRows, formatDuration, formatRecord, isActive, isLive, isSettled, isTerminal, isWaiting, lifecycleOf, matchesSearch as matchesRunSearch, matchesSearch$1 as matchesSearch, measuredSize, meetsLevel, needsAttention, omissionLabel, patchStepAtPath, queueDurationOf, readTerminalTheme, resolveStepPath, runsManifest, runsPanel, runsViewManifest, runsViewState, safeJson, spliceRedactedAppend, splitRows, statusLabel, terminalManifest, terminalPanel, terminalThemeVar, toneOf, truncateLogMessage };
2673
+ export { ALL_STATUSES, BEHAVIOURS$3 as CONSOLE_BEHAVIOURS, CONSOLE_DECLARATION, CONSOLE_PANEL_ID, CONSOLE_RUNTIME_UNITS, ConsoleController, type ConsoleControllerOptions, type ConsoleHostBridge, type ConsolePanelState, ConsolePanelView, type ConsolePanelViewProps, type ConsoleRenderContext, ConsoleScroller, type ConsoleUiIntent, type ConsoleViewModel, type ConsoleViewOptions, type ConsoleViewRow, type ConsoleViewSource, type ConsoleViewState, type CreateConsolePanelOptions, type CreateDiffPanelOptions, type CreateRunsPanelOptions, type CreateTerminalPanelOptions, DEFAULT_MAX_STEP_DEPTH, BEHAVIOURS as DIFF_BEHAVIOURS, DIFF_DECLARATION, DIFF_PANEL_ID, DIFF_RUNTIME_UNITS, DiffController, type DiffControllerOptions, type DiffFileView, type DiffHostBridge, type DiffPanelState, DiffPanelView, type DiffPanelViewProps, type DiffRenderContext, type DiffUiIntent, type DiffViewFile, type DiffViewHunk, type DiffViewLine, type DiffViewModel, type DiffViewOptions, type DiffViewRun, type DiffViewSplitRow, type DiffViewState, type FlattenOptions, LEVEL_ORDER, MESSAGE_ELISION, REDACTION_CARRY, BEHAVIOURS$2 as RUNS_BEHAVIOURS, RUNS_DECLARATION, RUNS_PANEL_ID, RUNS_RUNTIME_UNITS, RUN_PATH_SEPARATOR, RUN_STATUSES, RunsController, type RunsControllerOptions, type RunsHostBridge, type RunsPanelState, RunsPanelView, type RunsPanelViewProps, type RunsRenderContext, type RunsUiIntent, type RunsViewChip, type RunsViewModel, type RunsViewOptions, type RunsViewRow, type RunsViewState, BEHAVIOURS$1 as TERMINAL_BEHAVIOURS, TERMINAL_DECLARATION, TERMINAL_PANEL_ID, TERMINAL_RUNTIME_UNITS, TERMINAL_STATUSES, TerminalController, type TerminalControllerOptions, type TerminalHostBridge, type TerminalInstanceView, type TerminalPanelState, TerminalPanelView, type TerminalPanelViewProps, type TerminalRenderContext, TerminalSurfaces, type TerminalUiIntent, type TerminalViewModel, type TerminalViewOptions, type TerminalViewState, type TerminalViewTab, XENO_TERMINAL_THEME_KEYS, type XenoDiffAction, type XenoDiffDecision, type XenoDiffDecisionIntent, type XenoDiffDecisionState, type XenoDiffFile, type XenoDiffFileOmission, type XenoDiffHighlighter, type XenoDiffHunk, type XenoDiffLine, type XenoDiffLineKind, type XenoDiffModel, type XenoDiffNavigate, type XenoDiffSegment, type XenoDiffStatus, type XenoDiffView, type XenoLogActivate, type XenoLogDelta, type XenoLogFilter, type XenoLogLevel, type XenoLogPatch, type XenoLogRecord, type XenoLogSource, type XenoRun, type XenoRunAction, type XenoRunActivate, type XenoRunDelta, type XenoRunError, type XenoRunFilter, type XenoRunLifecycle, type XenoRunPath, type XenoRunRow, type XenoRunRunRow, type XenoRunStats, type XenoRunStatus, type XenoRunStep, type XenoRunStepAppend, type XenoRunStepPatch, type XenoRunStepRow, type XenoRunTruncation, type XenoTerminalData, type XenoTerminalEmulator, type XenoTerminalId, type XenoTerminalIntent, type XenoTerminalSession, type XenoTerminalStatus, type XenoTerminalTheme, appendStepsAtPath, applyConsoleUi, applyDiffUi, applyRunsUi, applyTerminalUi, canCancel, canRetry, collapseAdjacent, computeStats, consoleManifest, consolePanel, consoleRuntimeComponents, consoleViewManifest, consoleViewState, countChanges, createConsolePanel, createDiffPanel, createRunsPanel, createTerminalPanel, decodeRunPath, diffManifest, diffPanel, diffViewManifest, diffViewState, durationOf, encodeRunPath, flattenHunks, flattenRunRows, formatDuration, formatRecord, isActive, isLive, isSettled, isTerminal, isWaiting, lifecycleOf, matchesSearch as matchesRunSearch, matchesSearch$1 as matchesSearch, measuredSize, meetsLevel, needsAttention, omissionLabel, patchStepAtPath, queueDurationOf, readTerminalTheme, resolveStepPath, runsManifest, runsPanel, runsViewManifest, runsViewState, safeJson, spliceRedactedAppend, splitRows, statusLabel, terminalManifest, terminalPanel, terminalRuntimeComponents, terminalThemeVar, terminalViewManifest, terminalViewState, toneOf, truncateLogMessage };
package/dist/ops/index.js CHANGED
@@ -7,8 +7,10 @@ import {
7
7
  terminalThemeVar
8
8
  } from "../chunk-WE6A2DTY.js";
9
9
  import {
10
- ICONS
11
- } from "../chunk-7S2RKUAM.js";
10
+ ICONS,
11
+ PlusGlyph,
12
+ XGlyph
13
+ } from "../chunk-4IDY5FHM.js";
12
14
  import "../chunk-2KG3PWR4.js";
13
15
 
14
16
  // src/ops/console/panel.ts
@@ -60,10 +62,10 @@ function spliceRedactedAppend(existing, addition, redact, carry = REDACTION_CARR
60
62
  const tail = existing.slice(cut);
61
63
  return head + redact(tail + addition);
62
64
  }
63
- function truncateLogMessage(text4, max) {
64
- if (max <= 0 || text4.length <= max) return text4;
65
- if (max <= MESSAGE_ELISION.length) return text4.slice(text4.length - max);
66
- return MESSAGE_ELISION + text4.slice(text4.length - (max - MESSAGE_ELISION.length));
65
+ function truncateLogMessage(text5, max) {
66
+ if (max <= 0 || text5.length <= max) return text5;
67
+ if (max <= MESSAGE_ELISION.length) return text5.slice(text5.length - max);
68
+ return MESSAGE_ELISION + text5.slice(text5.length - (max - MESSAGE_ELISION.length));
67
69
  }
68
70
  function formatRecord(record) {
69
71
  const time = new Date(record.ts).toISOString();
@@ -240,7 +242,7 @@ var ConsoleController = class {
240
242
  */
241
243
  merge(existing, patch) {
242
244
  const secrets = [...this.host.getSecrets?.() ?? []];
243
- const redact = (text4) => redactForLog(text4, secrets);
245
+ const redact = (text5) => redactForLog(text5, secrets);
244
246
  let message = existing.message;
245
247
  if (typeof patch.message === "string") message = redact(patch.message);
246
248
  if (typeof patch.appendMessage === "string" && patch.appendMessage.length > 0) {
@@ -870,24 +872,24 @@ function consoleRuntimeComponents(controller, rowHeight) {
870
872
  function ConsolePanelView({ controller, ...options }) {
871
873
  useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
872
874
  const view = consoleViewState(controller, options);
873
- const ui4 = (intent) => applyConsoleUi(controller, intent);
875
+ const ui5 = (intent) => applyConsoleUi(controller, intent);
874
876
  return /* @__PURE__ */ jsxs(Column, { children: [
875
877
  /* @__PURE__ */ jsx(
876
878
  Toolbar,
877
879
  {
878
880
  left: /* @__PURE__ */ jsxs(Fragment, { children: [
879
- /* @__PURE__ */ jsx(SearchField, { value: view.search, placeholder: "Filter\u2026", onChange: (value) => ui4({ kind: "search", value }) }),
880
- /* @__PURE__ */ jsx(SegmentedControl, { size: "sm", label: "Minimum level", options: view.levels, value: view.level, onChange: (level) => ui4({ kind: "level", level }) })
881
+ /* @__PURE__ */ jsx(SearchField, { value: view.search, placeholder: "Filter\u2026", onChange: (value) => ui5({ kind: "search", value }) }),
882
+ /* @__PURE__ */ jsx(SegmentedControl, { size: "sm", label: "Minimum level", options: view.levels, value: view.level, onChange: (level) => ui5({ kind: "level", level }) })
881
883
  ] }),
882
884
  right: /* @__PURE__ */ jsxs(ToolbarGroup, { end: true, children: [
883
885
  view.errors ? /* @__PURE__ */ jsx(Badge, { tone: "error", children: view.errors }) : null,
884
886
  view.warns ? /* @__PURE__ */ jsx(Badge, { tone: "warning", children: view.warns }) : null,
885
- /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(CopyGlyph, {}), label: "Copy visible", onClick: () => ui4({ kind: "copyVisible" }) }),
886
- /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(ClearGlyph, {}), label: "Clear", onClick: () => ui4({ kind: "clear" }) })
887
+ /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(CopyGlyph, {}), label: "Copy visible", onClick: () => ui5({ kind: "copyVisible" }) }),
888
+ /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(ClearGlyph, {}), label: "Clear", onClick: () => ui5({ kind: "clear" }) })
887
889
  ] })
888
890
  }
889
891
  ),
890
- view.multiSource ? /* @__PURE__ */ jsx(Stack, { direction: "row", gap: 4, pad: "inset", children: view.sources.map((source) => /* @__PURE__ */ jsx(FilterChip, { on: source.on, title: source.title, onChange: (on) => ui4({ kind: "source", id: source.id, on }), children: source.label }, source.id)) }) : null,
892
+ view.multiSource ? /* @__PURE__ */ jsx(Stack, { direction: "row", gap: 4, pad: "inset", children: view.sources.map((source) => /* @__PURE__ */ jsx(FilterChip, { on: source.on, title: source.title, onChange: (on) => ui5({ kind: "source", id: source.id, on }), children: source.label }, source.id)) }) : null,
891
893
  view.empty ? /* @__PURE__ */ jsx(EmptyState, { title: view.emptyTitle, hint: view.emptyHint }) : null,
892
894
  view.listed ? /* @__PURE__ */ jsx(ConsoleScroller, { controller, rowHeight: view.rowHeight, children: /* @__PURE__ */ jsx(VirtualWindow, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: /* @__PURE__ */ jsx(RowList, { role: "log", children: view.rows.map((row) => /* @__PURE__ */ jsxs(Fragment, { children: [
893
895
  /* @__PURE__ */ jsx(
@@ -902,8 +904,8 @@ function ConsolePanelView({ controller, ...options }) {
902
904
  /* @__PURE__ */ jsx(Text, { children: row.message })
903
905
  ] }),
904
906
  trailing: row.repeat ? /* @__PURE__ */ jsx(Badge, { title: "Repeated consecutively", children: row.repeat }) : null,
905
- onClick: () => ui4({ kind: "row", id: row.id }),
906
- onContextMenuAt: (x, y) => ui4({ kind: "contextMenu", id: row.id, x, y })
907
+ onClick: () => ui5({ kind: "row", id: row.id }),
908
+ onContextMenuAt: (x, y) => ui5({ kind: "contextMenu", id: row.id, x, y })
907
909
  },
908
910
  row.id
909
911
  ),
@@ -2085,19 +2087,19 @@ var RetryGlyph = ICONS["icons/Retry"];
2085
2087
  function RunsPanelView({ controller, ...options }) {
2086
2088
  useSyncExternalStore2(controller.subscribe, controller.getState, controller.getState);
2087
2089
  const view = runsViewState(controller, options);
2088
- const ui4 = (intent) => applyRunsUi(controller, intent);
2090
+ const ui5 = (intent) => applyRunsUi(controller, intent);
2089
2091
  const chip2 = (c, onChange) => /* @__PURE__ */ jsx2(FilterChip2, { on: c.on, title: c.title, onChange, children: /* @__PURE__ */ jsx2(Badge2, { tone: c.tone, children: c.label }) }, c.id);
2090
2092
  return /* @__PURE__ */ jsxs2(Column2, { children: [
2091
2093
  /* @__PURE__ */ jsx2(
2092
2094
  Toolbar2,
2093
2095
  {
2094
- left: /* @__PURE__ */ jsx2(SearchField2, { value: view.search, placeholder: "Filter runs\u2026", onChange: (value) => ui4({ kind: "search", value }) }),
2095
- right: /* @__PURE__ */ jsx2(ToolbarGroup2, { end: true, children: /* @__PURE__ */ jsx2(TextButton, { onClick: () => ui4({ kind: "clearTerminal" }), children: "Clear finished" }) })
2096
+ left: /* @__PURE__ */ jsx2(SearchField2, { value: view.search, placeholder: "Filter runs\u2026", onChange: (value) => ui5({ kind: "search", value }) }),
2097
+ right: /* @__PURE__ */ jsx2(ToolbarGroup2, { end: true, children: /* @__PURE__ */ jsx2(TextButton, { onClick: () => ui5({ kind: "clearTerminal" }), children: "Clear finished" }) })
2096
2098
  }
2097
2099
  ),
2098
2100
  view.hasChips ? /* @__PURE__ */ jsxs2(Stack2, { direction: "row", gap: 4, pad: "inset", children: [
2099
- view.statuses.map((c) => chip2(c, (on) => ui4({ kind: "status", status: c.id, on }))),
2100
- view.sources.map((c) => chip2(c, (on) => ui4({ kind: "source", id: c.id, on })))
2101
+ view.statuses.map((c) => chip2(c, (on) => ui5({ kind: "status", status: c.id, on }))),
2102
+ view.sources.map((c) => chip2(c, (on) => ui5({ kind: "source", id: c.id, on })))
2101
2103
  ] }) : null,
2102
2104
  view.empty ? /* @__PURE__ */ jsx2(EmptyState2, { title: view.emptyTitle, hint: view.emptyHint }) : null,
2103
2105
  view.listed ? /* @__PURE__ */ jsx2(ScrollArea2, { children: /* @__PURE__ */ jsx2(RowList2, { children: view.rows.map((row) => /* @__PURE__ */ jsxs2(Fragment2, { children: [
@@ -2119,11 +2121,11 @@ function RunsPanelView({ controller, ...options }) {
2119
2121
  row.duration ? /* @__PURE__ */ jsx2(Text2, { role: "number", children: row.duration }) : null
2120
2122
  ] }),
2121
2123
  trailing: /* @__PURE__ */ jsxs2(Fragment2, { children: [
2122
- row.canCancel ? /* @__PURE__ */ jsx2(IconButton2, { size: "sm", icon: /* @__PURE__ */ jsx2(CancelGlyph, {}), label: row.cancelLabel, onClick: () => ui4({ kind: "cancel", runId: row.runId }) }) : null,
2123
- row.canRetry ? /* @__PURE__ */ jsx2(IconButton2, { size: "sm", icon: /* @__PURE__ */ jsx2(RetryGlyph, {}), label: row.retryLabel, onClick: () => ui4({ kind: "retry", runId: row.runId }) }) : null
2124
+ row.canCancel ? /* @__PURE__ */ jsx2(IconButton2, { size: "sm", icon: /* @__PURE__ */ jsx2(CancelGlyph, {}), label: row.cancelLabel, onClick: () => ui5({ kind: "cancel", runId: row.runId }) }) : null,
2125
+ row.canRetry ? /* @__PURE__ */ jsx2(IconButton2, { size: "sm", icon: /* @__PURE__ */ jsx2(RetryGlyph, {}), label: row.retryLabel, onClick: () => ui5({ kind: "retry", runId: row.runId }) }) : null
2124
2126
  ] }),
2125
- onClick: () => ui4({ kind: "row", runId: row.runId, stepPath: row.stepPath }),
2126
- onContextMenuAt: (x, y) => ui4({ kind: "contextMenu", runId: row.runId, x, y })
2127
+ onClick: () => ui5({ kind: "row", runId: row.runId, stepPath: row.stepPath }),
2128
+ onContextMenuAt: (x, y) => ui5({ kind: "contextMenu", runId: row.runId, x, y })
2127
2129
  },
2128
2130
  row.key
2129
2131
  ),
@@ -2681,23 +2683,155 @@ var terminalManifest = {
2681
2683
 
2682
2684
  // src/ops/terminal/react/TerminalPanelView.tsx
2683
2685
  import { useEffect as useEffect2, useRef as useRef2, useSyncExternalStore as useSyncExternalStore3 } from "react";
2684
- import {
2685
- Badge as Badge3,
2686
- EmptyState as EmptyState3,
2687
- IconButton as IconButton3,
2688
- SearchField as SearchField3,
2689
- StatusBar as StatusBar3,
2690
- TextButton as TextButton2,
2691
- Toolbar as Toolbar3,
2692
- ToolbarGroup as ToolbarGroup3
2693
- } from "@xenosystem/components/chrome";
2694
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2695
- function CloseIcon() {
2696
- return /* @__PURE__ */ jsx3("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx3("path", { d: "M18 6 6 18M6 6l12 12" }) });
2686
+ import { Badge as Badge3, Column as Column3, EmptyState as EmptyState3, IconButton as IconButton3, SearchField as SearchField3, StatusBar as StatusBar3, Tab, TabStrip, TextButton as TextButton2, Toolbar as Toolbar3, ToolbarGroup as ToolbarGroup3 } from "@xenosystem/components/chrome";
2687
+
2688
+ // src/ops/terminal/declaration.ts
2689
+ function terminalViewState(c, options = {}) {
2690
+ const { multiInstance = true, hasEmulator = true } = options;
2691
+ const state = c.getState();
2692
+ const active = state.instances.find((i) => i.active);
2693
+ return {
2694
+ noEmulator: !hasEmulator,
2695
+ ready: hasEmulator,
2696
+ stripShown: hasEmulator && multiInstance,
2697
+ tabs: state.instances.map((instance) => {
2698
+ const label = statusLabel(instance.session);
2699
+ const title = instance.session.title ?? instance.session.id.slice(0, 8);
2700
+ return {
2701
+ key: instance.session.id,
2702
+ id: instance.session.id,
2703
+ title,
2704
+ selected: instance.active,
2705
+ chip: label,
2706
+ chipTone: instance.session.status === "failed" ? "error" : "neutral",
2707
+ closeLabel: `Close ${title}`
2708
+ };
2709
+ }),
2710
+ tabIds: state.instances.map((i) => i.session.id),
2711
+ activeId: active?.session.id ?? "",
2712
+ findShown: hasEmulator && state.search !== null,
2713
+ find: state.search ?? "",
2714
+ empty: hasEmulator && state.instances.length === 0,
2715
+ surfacesShown: hasEmulator && state.instances.length > 0,
2716
+ cwdLabel: active?.session.cwd,
2717
+ sizeLabel: active && active.cols ? `${active.cols}\xD7${active.rows}` : void 0
2718
+ };
2697
2719
  }
2698
- function PlusIcon() {
2699
- return /* @__PURE__ */ jsx3("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx3("path", { d: "M12 5v14M5 12h14" }) });
2720
+ function applyTerminalUi(c, intent) {
2721
+ switch (intent.kind) {
2722
+ case "activate":
2723
+ c.setActive(intent.id);
2724
+ break;
2725
+ case "close":
2726
+ c.close(intent.id);
2727
+ break;
2728
+ case "open":
2729
+ c.open();
2730
+ break;
2731
+ case "toggleFind":
2732
+ c.setSearch(c.getState().search === null ? "" : null);
2733
+ break;
2734
+ case "find":
2735
+ c.setSearch(intent.value);
2736
+ break;
2737
+ case "findStep":
2738
+ c.find(intent.direction);
2739
+ break;
2740
+ }
2700
2741
  }
2742
+ var terminalViewManifest = {
2743
+ id: terminalManifest.id,
2744
+ version: "1.0.0",
2745
+ title: "Terminal",
2746
+ category: "ops",
2747
+ layout: { slot: "bottom" },
2748
+ inputs: [{ id: "view", type: "object", label: "View state", description: "The TerminalViewModel the runtime derives from the controller on every draw." }],
2749
+ outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, id?, value?, direction? } \u2014 applied by the runtime to the controller." }],
2750
+ commands: []
2751
+ };
2752
+ var EMPTY3 = { noEmulator: false, ready: true, stripShown: true, tabs: [], tabIds: [], activeId: "", findShown: false, find: "", empty: true, surfacesShown: false };
2753
+ var BEHAVIOURS3 = {
2754
+ "ops/terminalPanelView": (inputs) => inputs.view ?? EMPTY3
2755
+ };
2756
+ var text3 = (b) => ({ component: "text", props: { text: b } });
2757
+ var ui3 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
2758
+ var TERMINAL_DECLARATION = {
2759
+ format: "xeno.block@1",
2760
+ manifest: terminalViewManifest,
2761
+ behaviour: "ops/terminalPanelView",
2762
+ composition: {
2763
+ component: "fragment",
2764
+ children: [
2765
+ { component: "chrome/EmptyState", when: { input: "view.noEmulator" }, props: { title: { value: "No emulator configured" }, hint: { value: "Pass `createEmulator` (or use `createXtermEmulator`) so the panel has something to render into." } } },
2766
+ {
2767
+ component: "chrome/Column",
2768
+ when: { input: "view.ready" },
2769
+ children: [
2770
+ {
2771
+ component: "chrome/Toolbar",
2772
+ when: { input: "view.stripShown" },
2773
+ props: {
2774
+ left: {
2775
+ node: {
2776
+ component: "chrome/TabStrip",
2777
+ props: { label: { value: "Terminals" }, value: { input: "view.activeId" }, ids: { input: "view.tabIds" } },
2778
+ on: { onChange: ui3("activate", { id: { arg: "" } }), onClose: ui3("close", { id: { arg: "" } }) },
2779
+ children: [
2780
+ {
2781
+ component: "chrome/Tab",
2782
+ each: { input: "view.tabs", key: "key" },
2783
+ props: {
2784
+ selected: { item: "selected" },
2785
+ closeLabel: { item: "closeLabel" },
2786
+ closeIcon: { node: { component: "icons/Close" } },
2787
+ chip: { node: { component: "chrome/Badge", when: { item: "chip" }, props: { tone: { item: "chipTone" } }, children: [text3({ item: "chip" })] } }
2788
+ },
2789
+ children: [text3({ item: "title" })],
2790
+ on: { onSelect: ui3("activate", { id: { item: "id" } }), onClose: ui3("close", { id: { item: "id" } }) }
2791
+ }
2792
+ ]
2793
+ }
2794
+ },
2795
+ right: {
2796
+ node: {
2797
+ component: "chrome/ToolbarGroup",
2798
+ props: { end: { value: true } },
2799
+ children: [
2800
+ { component: "chrome/IconButton", props: { label: { value: "New terminal" }, icon: { node: { component: "icons/Plus" } } }, on: { onClick: ui3("open") } },
2801
+ { component: "chrome/TextButton", children: [text3({ value: "Find" })], on: { onClick: ui3("toggleFind") } }
2802
+ ]
2803
+ }
2804
+ }
2805
+ }
2806
+ },
2807
+ {
2808
+ component: "chrome/Toolbar",
2809
+ when: { input: "view.findShown" },
2810
+ props: {
2811
+ left: { node: { component: "chrome/SearchField", props: { value: { input: "view.find" }, placeholder: { value: "Find in terminal" }, autoFocus: { value: true } }, on: { onChange: ui3("find", { value: { arg: "" } }) } } },
2812
+ right: {
2813
+ node: {
2814
+ component: "chrome/ToolbarGroup",
2815
+ props: { end: { value: true } },
2816
+ children: [
2817
+ { component: "chrome/TextButton", children: [text3({ value: "Previous" })], on: { onClick: ui3("findStep", { direction: { value: "previous" } }) } },
2818
+ { component: "chrome/TextButton", children: [text3({ value: "Next" })], on: { onClick: ui3("findStep", { direction: { value: "next" } }) } }
2819
+ ]
2820
+ }
2821
+ }
2822
+ }
2823
+ },
2824
+ { component: "chrome/EmptyState", when: { input: "view.empty" }, props: { title: { value: "No terminal" }, hint: { value: "Open one to get a shell." } } },
2825
+ { component: "terminal/Surfaces", when: { input: "view.surfacesShown" } },
2826
+ { component: "chrome/StatusBar", props: { left: { input: "view.cwdLabel" }, right: { input: "view.sizeLabel" } } }
2827
+ ]
2828
+ }
2829
+ ]
2830
+ }
2831
+ };
2832
+
2833
+ // src/ops/terminal/react/TerminalPanelView.tsx
2834
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2701
2835
  function TerminalSurface({
2702
2836
  id,
2703
2837
  controller,
@@ -2743,99 +2877,47 @@ function TerminalSurface({
2743
2877
  }
2744
2878
  );
2745
2879
  }
2746
- function TerminalPanelView({
2747
- controller,
2748
- createEmulator,
2749
- multiInstance = true
2750
- }) {
2880
+ function TerminalSurfaces({ controller, createEmulator }) {
2751
2881
  const state = useSyncExternalStore3(controller.subscribe, controller.getState, controller.getState);
2752
- const active = state.instances.find((i) => i.active);
2753
- if (!createEmulator) {
2754
- return /* @__PURE__ */ jsx3(
2755
- EmptyState3,
2756
- {
2757
- title: "No emulator configured",
2758
- hint: "Pass `createEmulator` (or use `createXtermEmulator`) so the panel has something to render into."
2759
- }
2760
- );
2761
- }
2762
- return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 }, children: [
2763
- multiInstance ? /* @__PURE__ */ jsx3(
2764
- Toolbar3,
2765
- {
2766
- left: /* @__PURE__ */ jsx3("div", { style: { display: "flex", gap: 2, alignItems: "center", overflowX: "auto" }, children: state.instances.map((instance) => {
2767
- const label = statusLabel(instance.session);
2768
- return /* @__PURE__ */ jsxs3(
2769
- "div",
2770
- {
2771
- style: { display: "flex", alignItems: "center", gap: 2 },
2772
- children: [
2773
- /* @__PURE__ */ jsx3(
2774
- TextButton2,
2775
- {
2776
- strong: instance.active,
2777
- onClick: () => controller.setActive(instance.session.id),
2778
- children: instance.session.title ?? instance.session.id.slice(0, 8)
2779
- }
2780
- ),
2781
- label ? /* @__PURE__ */ jsx3(Badge3, { tone: instance.session.status === "failed" ? "error" : "neutral", children: label }) : null,
2782
- /* @__PURE__ */ jsx3(
2783
- IconButton3,
2784
- {
2785
- label: "Close terminal",
2786
- size: "sm",
2787
- icon: /* @__PURE__ */ jsx3(CloseIcon, {}),
2788
- onClick: () => controller.close(instance.session.id)
2789
- }
2790
- )
2791
- ]
2792
- },
2793
- instance.session.id
2794
- );
2795
- }) }),
2796
- right: /* @__PURE__ */ jsxs3(ToolbarGroup3, { end: true, children: [
2797
- /* @__PURE__ */ jsx3(IconButton3, { label: "New terminal", icon: /* @__PURE__ */ jsx3(PlusIcon, {}), onClick: () => controller.open() }),
2798
- /* @__PURE__ */ jsx3(TextButton2, { onClick: () => controller.setSearch(state.search === null ? "" : null), children: "Find" })
2799
- ] })
2800
- }
2801
- ) : null,
2802
- state.search !== null ? /* @__PURE__ */ jsx3(
2803
- Toolbar3,
2804
- {
2805
- left: /* @__PURE__ */ jsx3(
2806
- SearchField3,
2807
- {
2808
- value: state.search,
2809
- onChange: (value) => controller.setSearch(value),
2810
- placeholder: "Find in terminal",
2811
- autoFocus: true
2812
- }
2813
- ),
2814
- right: /* @__PURE__ */ jsxs3(ToolbarGroup3, { end: true, children: [
2815
- /* @__PURE__ */ jsx3(TextButton2, { onClick: () => controller.find("previous"), children: "Previous" }),
2816
- /* @__PURE__ */ jsx3(TextButton2, { onClick: () => controller.find("next"), children: "Next" })
2817
- ] })
2818
- }
2819
- ) : null,
2820
- /* @__PURE__ */ jsx3("div", { style: { position: "relative", flex: 1, minHeight: 0 }, children: state.instances.length === 0 ? /* @__PURE__ */ jsx3(EmptyState3, { title: "No terminal", hint: "Open one to get a shell." }) : state.instances.map((instance) => /* @__PURE__ */ jsx3(
2821
- TerminalSurface,
2822
- {
2823
- id: instance.session.id,
2824
- controller,
2825
- createEmulator,
2826
- visible: instance.active
2827
- },
2828
- instance.session.id
2829
- )) }),
2830
- /* @__PURE__ */ jsx3(
2831
- StatusBar3,
2832
- {
2833
- left: active?.session.cwd,
2834
- right: active && active.cols ? `${active.cols}\xD7${active.rows}` : void 0
2835
- }
2836
- )
2882
+ return /* @__PURE__ */ jsx3("div", { style: { position: "relative", flex: 1, minHeight: 0 }, children: state.instances.map((instance) => /* @__PURE__ */ jsx3(TerminalSurface, { id: instance.session.id, controller, createEmulator, visible: instance.active }, instance.session.id)) });
2883
+ }
2884
+ function TerminalPanelView({ controller, createEmulator, multiInstance = true }) {
2885
+ useSyncExternalStore3(controller.subscribe, controller.getState, controller.getState);
2886
+ const view = terminalViewState(controller, { multiInstance, hasEmulator: !!createEmulator });
2887
+ const ui5 = (intent) => applyTerminalUi(controller, intent);
2888
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
2889
+ view.noEmulator ? /* @__PURE__ */ jsx3(EmptyState3, { title: "No emulator configured", hint: "Pass `createEmulator` (or use `createXtermEmulator`) so the panel has something to render into." }) : null,
2890
+ view.ready ? /* @__PURE__ */ jsxs3(Column3, { children: [
2891
+ view.stripShown ? /* @__PURE__ */ jsx3(
2892
+ Toolbar3,
2893
+ {
2894
+ left: /* @__PURE__ */ jsx3(TabStrip, { label: "Terminals", value: view.activeId, ids: view.tabIds, onChange: (id) => ui5({ kind: "activate", id }), onClose: (id) => ui5({ kind: "close", id }), children: view.tabs.map((t) => /* @__PURE__ */ jsx3(Tab, { selected: t.selected, closeLabel: t.closeLabel, closeIcon: /* @__PURE__ */ jsx3(XGlyph, {}), chip: t.chip ? /* @__PURE__ */ jsx3(Badge3, { tone: t.chipTone, children: t.chip }) : null, onSelect: () => ui5({ kind: "activate", id: t.id }), onClose: () => ui5({ kind: "close", id: t.id }), children: t.title }, t.key)) }),
2895
+ right: /* @__PURE__ */ jsxs3(ToolbarGroup3, { end: true, children: [
2896
+ /* @__PURE__ */ jsx3(IconButton3, { label: "New terminal", icon: /* @__PURE__ */ jsx3(PlusGlyph, {}), onClick: () => ui5({ kind: "open" }) }),
2897
+ /* @__PURE__ */ jsx3(TextButton2, { onClick: () => ui5({ kind: "toggleFind" }), children: "Find" })
2898
+ ] })
2899
+ }
2900
+ ) : null,
2901
+ view.findShown ? /* @__PURE__ */ jsx3(
2902
+ Toolbar3,
2903
+ {
2904
+ left: /* @__PURE__ */ jsx3(SearchField3, { value: view.find, placeholder: "Find in terminal", autoFocus: true, onChange: (value) => ui5({ kind: "find", value }) }),
2905
+ right: /* @__PURE__ */ jsxs3(ToolbarGroup3, { end: true, children: [
2906
+ /* @__PURE__ */ jsx3(TextButton2, { onClick: () => ui5({ kind: "findStep", direction: "previous" }), children: "Previous" }),
2907
+ /* @__PURE__ */ jsx3(TextButton2, { onClick: () => ui5({ kind: "findStep", direction: "next" }), children: "Next" })
2908
+ ] })
2909
+ }
2910
+ ) : null,
2911
+ view.empty ? /* @__PURE__ */ jsx3(EmptyState3, { title: "No terminal", hint: "Open one to get a shell." }) : null,
2912
+ view.surfacesShown && createEmulator ? /* @__PURE__ */ jsx3(TerminalSurfaces, { controller, createEmulator }) : null,
2913
+ /* @__PURE__ */ jsx3(StatusBar3, { left: view.cwdLabel, right: view.sizeLabel })
2914
+ ] }) : null
2837
2915
  ] });
2838
2916
  }
2917
+ var TERMINAL_RUNTIME_UNITS = ["terminal/Surfaces"];
2918
+ function terminalRuntimeComponents(controller, createEmulator) {
2919
+ return { "terminal/Surfaces": () => /* @__PURE__ */ jsx3(TerminalSurfaces, { controller, createEmulator }) };
2920
+ }
2839
2921
 
2840
2922
  // src/ops/terminal/panel.ts
2841
2923
  function createTerminalPanel(options = {}) {
@@ -3025,11 +3107,11 @@ function omissionLabel(omission) {
3025
3107
  }
3026
3108
 
3027
3109
  // src/ops/diff/controller.ts
3028
- var EMPTY3 = { files: [], status: "idle" };
3110
+ var EMPTY4 = { files: [], status: "idle" };
3029
3111
  var DiffController = class {
3030
3112
  host;
3031
3113
  reviewEnabled;
3032
- model = EMPTY3;
3114
+ model = EMPTY4;
3033
3115
  rev = -1;
3034
3116
  decisions = /* @__PURE__ */ new Map();
3035
3117
  view;
@@ -3292,7 +3374,7 @@ var DiffController = class {
3292
3374
  /** Tear down. */
3293
3375
  dispose() {
3294
3376
  this.listeners.clear();
3295
- this.model = EMPTY3;
3377
+ this.model = EMPTY4;
3296
3378
  this.decisions.clear();
3297
3379
  }
3298
3380
  };
@@ -3433,7 +3515,7 @@ var diffManifest = {
3433
3515
  import { useSyncExternalStore as useSyncExternalStore4 } from "react";
3434
3516
  import {
3435
3517
  Badge as Badge4,
3436
- Column as Column3,
3518
+ Column as Column4,
3437
3519
  DiffLine,
3438
3520
  DiffSplitRow,
3439
3521
  EmptyState as EmptyState4,
@@ -3450,7 +3532,7 @@ import {
3450
3532
  } from "@xenosystem/components/chrome";
3451
3533
 
3452
3534
  // src/ops/diff/declaration.ts
3453
- var visible = (text4, show) => show ? text4.replace(/\t/g, "\u2192 ").replace(/ /g, "\xB7") : text4;
3535
+ var visible = (text5, show) => show ? text5.replace(/\t/g, "\u2192 ").replace(/ /g, "\xB7") : text5;
3454
3536
  var runsOf = (line, language, highlighter, showWhitespace) => {
3455
3537
  if (line.segments?.length) {
3456
3538
  return line.segments.map((s) => s.kind === "equal" ? { text: visible(s.text, showWhitespace) } : { text: visible(s.text, showWhitespace), mark: s.kind });
@@ -3578,7 +3660,7 @@ var diffViewManifest = {
3578
3660
  outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, view?, path?, id?, collapsed?, action?, x?, y? } \u2014 applied by the runtime to the controller." }],
3579
3661
  commands: []
3580
3662
  };
3581
- var EMPTY4 = {
3663
+ var EMPTY5 = {
3582
3664
  idle: true,
3583
3665
  computing: false,
3584
3666
  failed: false,
@@ -3594,11 +3676,11 @@ var EMPTY4 = {
3594
3676
  countLabel: "0 files \xB7 +0 \u22120",
3595
3677
  rightLabel: ""
3596
3678
  };
3597
- var BEHAVIOURS3 = {
3598
- "ops/diffPanelView": (inputs) => inputs.view ?? EMPTY4
3679
+ var BEHAVIOURS4 = {
3680
+ "ops/diffPanelView": (inputs) => inputs.view ?? EMPTY5
3599
3681
  };
3600
- var text3 = (b) => ({ component: "text", props: { text: b } });
3601
- var ui3 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
3682
+ var text4 = (b) => ({ component: "text", props: { text: b } });
3683
+ var ui4 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
3602
3684
  var LINE = (kindKey) => ({
3603
3685
  component: "chrome/DiffLine",
3604
3686
  each: { item: kindKey, key: "key" },
@@ -3622,22 +3704,22 @@ var DIFF_DECLARATION = {
3622
3704
  {
3623
3705
  component: "chrome/Toolbar",
3624
3706
  props: {
3625
- left: { node: { component: "chrome/SegmentedControl", props: { label: { value: "View" }, value: { input: "view.view" }, options: { input: "view.views" } }, on: { onChange: ui3("view", { view: { arg: "" } }) } } },
3707
+ left: { node: { component: "chrome/SegmentedControl", props: { label: { value: "View" }, value: { input: "view.view" }, options: { input: "view.views" } }, on: { onChange: ui4("view", { view: { arg: "" } }) } } },
3626
3708
  right: {
3627
3709
  node: {
3628
3710
  component: "chrome/ToolbarGroup",
3629
3711
  props: { end: { value: true } },
3630
3712
  children: [
3631
- { component: "chrome/TextButton", children: [text3({ input: "view.wrapLabel" })], on: { onClick: ui3("toggleWrap") } },
3632
- { component: "chrome/TextButton", children: [text3({ input: "view.whitespaceLabel" })], on: { onClick: ui3("toggleWhitespace") } },
3633
- { component: "chrome/TextButton", children: [text3({ value: "Prev" })], on: { onClick: ui3("prev") } },
3634
- { component: "chrome/TextButton", children: [text3({ value: "Next" })], on: { onClick: ui3("next") } }
3713
+ { component: "chrome/TextButton", children: [text4({ input: "view.wrapLabel" })], on: { onClick: ui4("toggleWrap") } },
3714
+ { component: "chrome/TextButton", children: [text4({ input: "view.whitespaceLabel" })], on: { onClick: ui4("toggleWhitespace") } },
3715
+ { component: "chrome/TextButton", children: [text4({ value: "Prev" })], on: { onClick: ui4("prev") } },
3716
+ { component: "chrome/TextButton", children: [text4({ value: "Next" })], on: { onClick: ui4("next") } }
3635
3717
  ]
3636
3718
  }
3637
3719
  }
3638
3720
  }
3639
3721
  },
3640
- { component: "chrome/Note", when: { input: "view.conflictNotice" }, children: [{ component: "chrome/Badge", props: { tone: { value: "error" } }, children: [text3({ input: "view.conflictNotice" })] }] },
3722
+ { component: "chrome/Note", when: { input: "view.conflictNotice" }, children: [{ component: "chrome/Badge", props: { tone: { value: "error" } }, children: [text4({ input: "view.conflictNotice" })] }] },
3641
3723
  {
3642
3724
  component: "chrome/ScrollArea",
3643
3725
  children: [
@@ -3645,17 +3727,17 @@ var DIFF_DECLARATION = {
3645
3727
  component: "chrome/Section",
3646
3728
  each: { input: "view.files", key: "key" },
3647
3729
  props: {
3648
- title: { node: { component: "chrome/Text", children: [text3({ item: "title" })] } },
3649
- badge: { node: { component: "chrome/Badge", children: [text3({ item: "status" })] } },
3650
- actions: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text3({ item: "counts" })] } },
3730
+ title: { node: { component: "chrome/Text", children: [text4({ item: "title" })] } },
3731
+ badge: { node: { component: "chrome/Badge", children: [text4({ item: "status" })] } },
3732
+ actions: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text4({ item: "counts" })] } },
3651
3733
  collapsible: { value: true },
3652
3734
  collapsed: { item: "collapsed" },
3653
3735
  flush: { value: true }
3654
3736
  },
3655
- on: { onCollapsedChange: ui3("collapse", { path: { item: "path" }, collapsed: { arg: "" } }) },
3737
+ on: { onCollapsedChange: ui4("collapse", { path: { item: "path" }, collapsed: { arg: "" } }) },
3656
3738
  children: [
3657
3739
  // 🔴 Never an empty body. "Binary — not compared" and "no changes" are different facts.
3658
- { component: "chrome/Text", when: { item: "omitted" }, props: { role: { value: "meta" } }, children: [text3({ item: "omission" })] },
3740
+ { component: "chrome/Text", when: { item: "omitted" }, props: { role: { value: "meta" } }, children: [text4({ item: "omission" })] },
3659
3741
  {
3660
3742
  component: "chrome/Hunk",
3661
3743
  each: { item: "hunks", key: "key" },
@@ -3666,11 +3748,11 @@ var DIFF_DECLARATION = {
3666
3748
  node: {
3667
3749
  component: "fragment",
3668
3750
  children: [
3669
- text3({ item: "header" }),
3670
- { component: "chrome/Badge", when: { item: "chipPending" }, children: [text3({ value: "deciding\u2026" })] },
3671
- { component: "chrome/Badge", when: { item: "chipConflict" }, props: { tone: { value: "error" }, title: { item: "conflictTitle" } }, children: [text3({ value: "conflict \u2014 re-review" })] },
3672
- { component: "chrome/Badge", when: { item: "chipFailed" }, props: { tone: { value: "error" }, title: { item: "failedTitle" } }, children: [text3({ value: "failed" })] },
3673
- { component: "chrome/Badge", when: { item: "chipApplied" }, props: { tone: { value: "success" } }, children: [text3({ item: "appliedText" })] }
3751
+ text4({ item: "header" }),
3752
+ { component: "chrome/Badge", when: { item: "chipPending" }, children: [text4({ value: "deciding\u2026" })] },
3753
+ { component: "chrome/Badge", when: { item: "chipConflict" }, props: { tone: { value: "error" }, title: { item: "conflictTitle" } }, children: [text4({ value: "conflict \u2014 re-review" })] },
3754
+ { component: "chrome/Badge", when: { item: "chipFailed" }, props: { tone: { value: "error" }, title: { item: "failedTitle" } }, children: [text4({ value: "failed" })] },
3755
+ { component: "chrome/Badge", when: { item: "chipApplied" }, props: { tone: { value: "success" } }, children: [text4({ item: "appliedText" })] }
3674
3756
  ]
3675
3757
  }
3676
3758
  },
@@ -3679,14 +3761,14 @@ var DIFF_DECLARATION = {
3679
3761
  component: "fragment",
3680
3762
  when: { item: "review" },
3681
3763
  children: [
3682
- { component: "chrome/TextButton", when: { item: "attention" }, children: [text3({ value: "Re-review" })], on: { onClick: ui3("reReview", { path: { item: "path" }, id: { item: "id" } }) } },
3683
- { component: "chrome/TextButton", when: { not: { item: "attention" } }, props: { disabled: { item: "deciding" } }, children: [text3({ value: "Accept" })], on: { onClick: ui3("decide", { path: { item: "path" }, id: { item: "id" }, action: { value: "accept" } }) } },
3684
- { component: "chrome/TextButton", when: { not: { item: "attention" } }, props: { disabled: { item: "deciding" } }, children: [text3({ value: "Reject" })], on: { onClick: ui3("decide", { path: { item: "path" }, id: { item: "id" }, action: { value: "reject" } }) } }
3764
+ { component: "chrome/TextButton", when: { item: "attention" }, children: [text4({ value: "Re-review" })], on: { onClick: ui4("reReview", { path: { item: "path" }, id: { item: "id" } }) } },
3765
+ { component: "chrome/TextButton", when: { not: { item: "attention" } }, props: { disabled: { item: "deciding" } }, children: [text4({ value: "Accept" })], on: { onClick: ui4("decide", { path: { item: "path" }, id: { item: "id" }, action: { value: "accept" } }) } },
3766
+ { component: "chrome/TextButton", when: { not: { item: "attention" } }, props: { disabled: { item: "deciding" } }, children: [text4({ value: "Reject" })], on: { onClick: ui4("decide", { path: { item: "path" }, id: { item: "id" }, action: { value: "reject" } }) } }
3685
3767
  ]
3686
3768
  }
3687
3769
  }
3688
3770
  },
3689
- on: { onContextMenuAt: ui3("contextMenu", { path: { item: "path" }, id: { item: "id" }, x: { arg: "" }, y: { arg: "", index: 1 } }) },
3771
+ on: { onContextMenuAt: ui4("contextMenu", { path: { item: "path" }, id: { item: "id" }, x: { arg: "" }, y: { arg: "", index: 1 } }) },
3690
3772
  children: [
3691
3773
  LINE("lines"),
3692
3774
  {
@@ -3706,8 +3788,8 @@ var DIFF_DECLARATION = {
3706
3788
  {
3707
3789
  component: "chrome/StatusBar",
3708
3790
  props: {
3709
- left: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text3({ input: "view.countLabel" })] } },
3710
- right: { node: { component: "chrome/Text", props: { role: { value: "meta" } }, children: [text3({ input: "view.rightLabel" })] } }
3791
+ left: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text4({ input: "view.countLabel" })] } },
3792
+ right: { node: { component: "chrome/Text", props: { role: { value: "meta" } }, children: [text4({ input: "view.rightLabel" })] } }
3711
3793
  }
3712
3794
  }
3713
3795
  ]
@@ -3717,29 +3799,29 @@ var DIFF_DECLARATION = {
3717
3799
  };
3718
3800
 
3719
3801
  // src/ops/diff/react/DiffPanelView.tsx
3720
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
3802
+ import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
3721
3803
  function DiffPanelView({ controller, ...options }) {
3722
3804
  useSyncExternalStore4(controller.subscribe, controller.getState, controller.getState);
3723
3805
  const view = diffViewState(controller, options);
3724
- const ui4 = (intent) => applyDiffUi(controller, intent);
3806
+ const ui5 = (intent) => applyDiffUi(controller, intent);
3725
3807
  const hunk = (h) => /* @__PURE__ */ jsxs4(
3726
3808
  Hunk,
3727
3809
  {
3728
3810
  focused: h.focused,
3729
3811
  settled: h.settled,
3730
- header: /* @__PURE__ */ jsxs4(Fragment3, { children: [
3812
+ header: /* @__PURE__ */ jsxs4(Fragment4, { children: [
3731
3813
  h.header,
3732
3814
  h.chipPending ? /* @__PURE__ */ jsx4(Badge4, { children: "deciding\u2026" }) : null,
3733
3815
  h.chipConflict ? /* @__PURE__ */ jsx4(Badge4, { tone: "error", title: h.conflictTitle, children: "conflict \u2014 re-review" }) : null,
3734
3816
  h.chipFailed ? /* @__PURE__ */ jsx4(Badge4, { tone: "error", title: h.failedTitle, children: "failed" }) : null,
3735
3817
  h.chipApplied ? /* @__PURE__ */ jsx4(Badge4, { tone: "success", children: h.appliedText }) : null
3736
3818
  ] }),
3737
- actions: h.review ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
3738
- h.attention ? /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui4({ kind: "reReview", path: h.path, id: h.id }), children: "Re-review" }) : null,
3739
- !h.attention ? /* @__PURE__ */ jsx4(TextButton3, { disabled: h.deciding, onClick: () => ui4({ kind: "decide", path: h.path, id: h.id, action: "accept" }), children: "Accept" }) : null,
3740
- !h.attention ? /* @__PURE__ */ jsx4(TextButton3, { disabled: h.deciding, onClick: () => ui4({ kind: "decide", path: h.path, id: h.id, action: "reject" }), children: "Reject" }) : null
3819
+ actions: h.review ? /* @__PURE__ */ jsxs4(Fragment4, { children: [
3820
+ h.attention ? /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui5({ kind: "reReview", path: h.path, id: h.id }), children: "Re-review" }) : null,
3821
+ !h.attention ? /* @__PURE__ */ jsx4(TextButton3, { disabled: h.deciding, onClick: () => ui5({ kind: "decide", path: h.path, id: h.id, action: "accept" }), children: "Accept" }) : null,
3822
+ !h.attention ? /* @__PURE__ */ jsx4(TextButton3, { disabled: h.deciding, onClick: () => ui5({ kind: "decide", path: h.path, id: h.id, action: "reject" }), children: "Reject" }) : null
3741
3823
  ] }) : null,
3742
- onContextMenuAt: (x, y) => ui4({ kind: "contextMenu", path: h.path, id: h.id, x, y }),
3824
+ onContextMenuAt: (x, y) => ui5({ kind: "contextMenu", path: h.path, id: h.id, x, y }),
3743
3825
  children: [
3744
3826
  h.lines.map((l) => /* @__PURE__ */ jsx4(DiffLine, { kind: l.kind, gutter: l.gutter, sigil: l.sigil, wrap: view.wrap, runs: l.runs }, l.key)),
3745
3827
  h.rows.map((r) => /* @__PURE__ */ jsxs4(DiffSplitRow, { children: [
@@ -3750,21 +3832,21 @@ function DiffPanelView({ controller, ...options }) {
3750
3832
  },
3751
3833
  h.key
3752
3834
  );
3753
- return /* @__PURE__ */ jsxs4(Fragment3, { children: [
3835
+ return /* @__PURE__ */ jsxs4(Fragment4, { children: [
3754
3836
  view.idle ? /* @__PURE__ */ jsx4(EmptyState4, { title: "Diff", hint: "Nothing to compare yet." }) : null,
3755
3837
  view.computing ? /* @__PURE__ */ jsx4(EmptyState4, { title: "Comparing\u2026", hint: "The host is computing the differences." }) : null,
3756
3838
  view.failed ? /* @__PURE__ */ jsx4(EmptyState4, { title: "Comparison failed", hint: view.failedHint }) : null,
3757
3839
  view.identical ? /* @__PURE__ */ jsx4(EmptyState4, { title: "No changes", hint: "The two sides are identical." }) : null,
3758
- view.active ? /* @__PURE__ */ jsxs4(Column3, { children: [
3840
+ view.active ? /* @__PURE__ */ jsxs4(Column4, { children: [
3759
3841
  /* @__PURE__ */ jsx4(
3760
3842
  Toolbar4,
3761
3843
  {
3762
- left: /* @__PURE__ */ jsx4(SegmentedControl2, { label: "View", value: view.view, options: view.views, onChange: (value) => ui4({ kind: "view", view: value }) }),
3844
+ left: /* @__PURE__ */ jsx4(SegmentedControl2, { label: "View", value: view.view, options: view.views, onChange: (value) => ui5({ kind: "view", view: value }) }),
3763
3845
  right: /* @__PURE__ */ jsxs4(ToolbarGroup4, { end: true, children: [
3764
- /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui4({ kind: "toggleWrap" }), children: view.wrapLabel }),
3765
- /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui4({ kind: "toggleWhitespace" }), children: view.whitespaceLabel }),
3766
- /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui4({ kind: "prev" }), children: "Prev" }),
3767
- /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui4({ kind: "next" }), children: "Next" })
3846
+ /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui5({ kind: "toggleWrap" }), children: view.wrapLabel }),
3847
+ /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui5({ kind: "toggleWhitespace" }), children: view.whitespaceLabel }),
3848
+ /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui5({ kind: "prev" }), children: "Prev" }),
3849
+ /* @__PURE__ */ jsx4(TextButton3, { onClick: () => ui5({ kind: "next" }), children: "Next" })
3768
3850
  ] })
3769
3851
  }
3770
3852
  ),
@@ -3778,7 +3860,7 @@ function DiffPanelView({ controller, ...options }) {
3778
3860
  collapsible: true,
3779
3861
  collapsed: f.collapsed,
3780
3862
  flush: true,
3781
- onCollapsedChange: (collapsed) => ui4({ kind: "collapse", path: f.path, collapsed }),
3863
+ onCollapsedChange: (collapsed) => ui5({ kind: "collapse", path: f.path, collapsed }),
3782
3864
  children: [
3783
3865
  f.omitted ? /* @__PURE__ */ jsx4(Text3, { role: "meta", children: f.omission }) : null,
3784
3866
  f.hunks.map(hunk)
@@ -3913,7 +3995,7 @@ export {
3913
3995
  ConsolePanelView,
3914
3996
  ConsoleScroller,
3915
3997
  DEFAULT_MAX_STEP_DEPTH,
3916
- BEHAVIOURS3 as DIFF_BEHAVIOURS,
3998
+ BEHAVIOURS4 as DIFF_BEHAVIOURS,
3917
3999
  DIFF_DECLARATION,
3918
4000
  DIFF_PANEL_ID,
3919
4001
  DIFF_RUNTIME_UNITS,
@@ -3930,15 +4012,20 @@ export {
3930
4012
  RUN_STATUSES,
3931
4013
  RunsController,
3932
4014
  RunsPanelView,
4015
+ BEHAVIOURS3 as TERMINAL_BEHAVIOURS,
4016
+ TERMINAL_DECLARATION,
3933
4017
  TERMINAL_PANEL_ID,
4018
+ TERMINAL_RUNTIME_UNITS,
3934
4019
  TERMINAL_STATUSES,
3935
4020
  TerminalController,
3936
4021
  TerminalPanelView,
4022
+ TerminalSurfaces,
3937
4023
  XENO_TERMINAL_THEME_KEYS,
3938
4024
  appendStepsAtPath,
3939
4025
  applyConsoleUi,
3940
4026
  applyDiffUi,
3941
4027
  applyRunsUi,
4028
+ applyTerminalUi,
3942
4029
  canCancel,
3943
4030
  canRetry,
3944
4031
  collapseAdjacent,
@@ -3990,7 +4077,10 @@ export {
3990
4077
  statusLabel,
3991
4078
  terminalManifest,
3992
4079
  terminalPanel,
4080
+ terminalRuntimeComponents,
3993
4081
  terminalThemeVar,
4082
+ terminalViewManifest,
4083
+ terminalViewState,
3994
4084
  toneOf,
3995
4085
  truncateLogMessage
3996
4086
  };
@@ -13,7 +13,7 @@ import {
13
13
  StopIcon,
14
14
  TRANSPORT_ICONS,
15
15
  TRANSPORT_RUNTIME_UNITS
16
- } from "../chunk-7S2RKUAM.js";
16
+ } from "../chunk-4IDY5FHM.js";
17
17
  import {
18
18
  __reExport
19
19
  } from "../chunk-2KG3PWR4.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenosystem/blocks",
3
- "version": "0.13.28",
3
+ "version": "0.13.30",
4
4
  "description": "XENO Blocks — rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block — XENO PACKAGE NAMING - STANDARD.md.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -64,7 +64,7 @@
64
64
  "peerDependencies": {
65
65
  "@duckdb/duckdb-wasm": ">=1.28.0",
66
66
  "@xenosystem/block-sdk": ">=0.3.4 <1",
67
- "@xenosystem/components": ">=0.29.1 <1",
67
+ "@xenosystem/components": ">=0.31.0 <1",
68
68
  "@xenosystem/data-core": "^0.1.0",
69
69
  "@xenosystem/elements": ">=0.0.1",
70
70
  "@xenosystem/elements-react": ">=0.0.1",
@@ -81,7 +81,7 @@
81
81
  "@types/react": "^19.0.0",
82
82
  "@types/react-dom": "^19.0.0",
83
83
  "@xenosystem/block-sdk": "^0.3.4",
84
- "@xenosystem/components": "^0.29.1",
84
+ "@xenosystem/components": "^0.31.0",
85
85
  "@xenosystem/data-core": "^0.1.0",
86
86
  "@xenosystem/elements": "0.0.1",
87
87
  "@xenosystem/elements-react": "0.0.1",