silvery 0.17.2 → 0.17.4

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.
@@ -1,7 +1,7 @@
1
1
  import { c as TermContext, o as StderrContext, s as StdoutContext } from "./context-QreF3UHr.mjs";
2
- import { At as bufferToStyledText, Lt as init_buffer, S as createTerm, a as hostConfig, jt as bufferToText, r as getContainerRoot, t as createContainer } from "./reconciler-2lp5VXK7.mjs";
2
+ import { At as bufferToStyledText, Lt as init_buffer, S as createTerm, a as hostConfig, jt as bufferToText, r as getContainerRoot, t as createContainer } from "./reconciler-B-NaZvbO.mjs";
3
3
  import { i as isLayoutEngineInitialized } from "./layout-engine-B3dsnVLU.mjs";
4
- import { t as executeRender } from "./pipeline-DDOPrjuY.mjs";
4
+ import { t as executeRender } from "./pipeline-BmfaZb1O.mjs";
5
5
  import React, { act } from "react";
6
6
  import Reconciler from "react-reconciler";
7
7
  //#region packages/ag-react/src/reconciler/string-reconciler.ts
@@ -198,4 +198,4 @@ function withActEnvironment(fn) {
198
198
  //#endregion
199
199
  export { renderStringSync as n, renderString as t };
200
200
 
201
- //# sourceMappingURL=render-string-BXvxTg5P.mjs.map
201
+ //# sourceMappingURL=render-string-Bvh1XzBv.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"render-string-BXvxTg5P.mjs","names":[],"sources":["../packages/ag-react/src/reconciler/string-reconciler.ts","../packages/ag-react/src/render-string.tsx"],"sourcesContent":["/**\n * Separate React reconciler instance for renderStringSync.\n *\n * renderStringSync may be called from within React effects (e.g., useScrollback\n * freezing items to scrollback). If it uses the same reconciler singleton as the\n * main render tree, this causes re-entrancy: the nested reconciliation interferes\n * with the outer one, producing empty output.\n *\n * By using a dedicated reconciler instance, renderStringSync operates on an\n * independent fiber tree with no shared reconciler state.\n */\n\n// @ts-expect-error - react-reconciler has no type declarations\nimport Reconciler from \"react-reconciler\"\nimport { hostConfig } from \"./host-config\"\n\n/**\n * Dedicated reconciler for string rendering.\n *\n * Uses the same host config functions but overrides isPrimaryRenderer to false,\n * since this is a secondary renderer used only for one-shot string rendering.\n * This avoids conflicts with the main reconciler's hook ownership.\n */\nexport const stringReconciler = Reconciler({\n ...hostConfig,\n isPrimaryRenderer: false,\n})\n","/**\n * renderString - Static one-shot rendering to string\n *\n * Renders a React element to a string without needing a terminal.\n * Use for:\n * - CI output (no cursor control needed)\n * - Piped output\n * - One-shot reports/summaries\n * - Testing component output\n *\n * @example\n * ```tsx\n * import { renderString, Box, Text } from '@silvery/ag-react'\n *\n * // Basic usage\n * const output = renderString(<Summary stats={stats} />)\n * console.log(output)\n *\n * // Custom width\n * const wide = renderString(<Report />, { width: 120 })\n *\n * // Plain text (no ANSI)\n * const plain = renderString(<Report />, { plain: true })\n * ```\n */\n\nimport React, { type ReactElement, act } from \"react\"\n\nimport { createTerm } from \"@silvery/ag-term/ansi\"\n\nimport { bufferToStyledText, bufferToText, type TerminalBuffer } from \"@silvery/ag-term/buffer\"\nimport { StdoutContext, StderrContext, TermContext } from \"./context\"\nimport { isLayoutEngineInitialized } from \"@silvery/ag-term/layout-engine\"\nimport { executeRender, type PipelineConfig } from \"@silvery/ag-term/pipeline\"\nimport { createContainer, getContainerRoot } from \"./reconciler\"\nimport { stringReconciler } from \"./reconciler/string-reconciler\"\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Options for renderString().\n */\nexport interface RenderStringOptions {\n /**\n * Width in columns for layout calculations.\n * Default: 80\n */\n width?: number\n\n /**\n * Height in rows for layout calculations.\n * Default: 24\n */\n height?: number\n\n /**\n * Strip ANSI codes for plain text output.\n * Default: false (includes ANSI styling)\n */\n plain?: boolean\n\n /**\n * Pipeline configuration (scoped width measurer + output phase).\n * When provided, the render pipeline uses these for width measurement\n * and output generation instead of the global defaults.\n */\n pipelineConfig?: PipelineConfig\n\n /**\n * Trim trailing whitespace from each line.\n * Default: true (trims trailing spaces)\n *\n * Set to false when rendering to stdout where trailing spaces are\n * semantically significant (e.g., ink compat static renders).\n */\n trimTrailingWhitespace?: boolean\n\n /**\n * Trim trailing empty lines from the output.\n * Default: true (removes trailing empty lines)\n *\n * Set to false when padding/margin at the bottom should be preserved\n * (e.g., ink compat renders where `\\n\\n` padding is significant).\n */\n trimEmptyLines?: boolean\n\n /**\n * Callback to receive the computed content height (root node layout height).\n * Useful for callers that need to know the actual content bounds\n * (e.g., Ink compat layer needs to trim buffer padding but preserve\n * content-area empty lines).\n */\n onContentHeight?: (height: number) => void\n\n /**\n * Always use styled output (bufferToStyledText) even when plain=true.\n * Default: false\n *\n * When true, the output includes ANSI codes from embedded sequences in text\n * content (SGR, OSC hyperlinks) even though the mock term has no color\n * support (plain=true). This is needed for Ink compatibility: Ink passes\n * embedded ANSI sequences through regardless of chalk's color level, but\n * silvery's plain mode would strip them via bufferToText.\n *\n * The `plain` flag still controls whether the mock term has color support,\n * which determines whether Text component style props (color, bold, etc.)\n * produce style attributes in the buffer.\n */\n alwaysStyled?: boolean\n}\n\n// ============================================================================\n// Module State\n// ============================================================================\n\n// Track if we've initialized to avoid redundant imports\nlet engineInitialized = false\n\nasync function ensureLayoutEngine(): Promise<void> {\n if (engineInitialized || isLayoutEngineInitialized()) {\n return\n }\n // Use centralized default engine initialization\n const { ensureDefaultLayoutEngine } = await import(\"@silvery/ag-term/layout-engine\")\n await ensureDefaultLayoutEngine()\n engineInitialized = true\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Render a React element to a string (async version).\n *\n * Automatically initializes the layout engine if needed.\n * Use this when you're not sure if the layout engine is ready.\n *\n * @param element - React element to render\n * @param options - Render options (width, height, plain)\n * @returns Rendered string (with or without ANSI codes)\n *\n * @example\n * ```tsx\n * const output = await renderString(<Summary stats={stats} />)\n * console.log(output)\n * ```\n */\nexport async function renderString(element: ReactElement, options: RenderStringOptions = {}): Promise<string> {\n await ensureLayoutEngine()\n return renderStringSync(element, options)\n}\n\n/**\n * Render a React element to a string (sync version).\n *\n * Requires the layout engine to be already initialized.\n * Throws if the layout engine is not ready.\n *\n * @param element - React element to render\n * @param options - Render options (width, height, plain)\n * @returns Rendered string (with or without ANSI codes)\n *\n * @example\n * ```tsx\n * // After layout engine is initialized\n * const output = renderStringSync(<Summary stats={stats} />)\n * console.log(output)\n * ```\n */\nexport function renderStringSync(element: ReactElement, options: RenderStringOptions = {}): string {\n if (!isLayoutEngineInitialized()) {\n throw new Error(\"Layout engine not initialized. Use renderString() (async) or initialize with setLayoutEngine().\")\n }\n\n const {\n width = 80,\n height = 24,\n plain = false,\n pipelineConfig,\n trimTrailingWhitespace = true,\n trimEmptyLines = true,\n onContentHeight,\n alwaysStyled = false,\n } = options\n\n // Track whether React committed new work (from layout notifications etc.)\n let hadReactCommit = false\n const container = createContainer(() => {\n hadReactCommit = true\n })\n\n // Capture uncaught errors from the reconciler so they propagate to the caller\n let uncaughtError: unknown = null\n const onUncaughtError = (error: unknown) => {\n uncaughtError = error\n }\n\n // Create fiber root using the dedicated string reconciler (not the main one)\n const fiberRoot = stringReconciler.createContainer(\n container,\n 1, // ConcurrentRoot\n null, // hydrationCallbacks\n false, // isStrictMode\n null, // concurrentUpdatesByDefaultOverride\n \"\", // identifierPrefix\n onUncaughtError, // onUncaughtError\n () => {}, // onCaughtError\n () => {}, // onRecoverableError\n null, // onDefaultTransitionIndicator\n )\n\n // Create minimal mock stdout for components that use useStdout\n const mockStdout = {\n columns: width,\n rows: height,\n write: () => true,\n isTTY: false,\n on: () => mockStdout,\n off: () => mockStdout,\n once: () => mockStdout,\n removeListener: () => mockStdout,\n addListener: () => mockStdout,\n } as unknown as NodeJS.WriteStream\n\n // Create mock term for components that use useTerm()\n const mockTerm = createTerm({ color: plain ? null : \"truecolor\" })\n\n // Wrap with minimal contexts (no input handling needed)\n const wrapped = React.createElement(\n TermContext.Provider,\n { value: mockTerm },\n React.createElement(\n StdoutContext.Provider,\n {\n value: {\n stdout: mockStdout,\n write: () => {},\n },\n },\n React.createElement(\n StderrContext.Provider,\n {\n value: {\n stderr: process.stderr,\n write: (data: string) => {\n process.stderr.write(data)\n },\n },\n },\n element,\n ),\n ),\n )\n\n // Mount the React tree inside act() so layout feedback works\n withActEnvironment(() => {\n act(() => {\n stringReconciler.updateContainerSync(wrapped, fiberRoot, null, null)\n stringReconciler.flushSyncWork()\n })\n })\n\n // Propagate any uncaught render errors (e.g., text outside <Text> in strict mode)\n if (uncaughtError) {\n throw uncaughtError instanceof Error ? uncaughtError : new Error(String(uncaughtError))\n }\n\n // Layout stabilization loop: run the pipeline, flush React work from\n // layout notifications (useBoxRect forceUpdate etc.), repeat until stable.\n // This matches the test renderer's multi-pass approach.\n let buffer!: TerminalBuffer\n let rootNode: ReturnType<typeof getContainerRoot> | undefined\n const MAX_ITERATIONS = 5\n for (let i = 0; i < MAX_ITERATIONS; i++) {\n hadReactCommit = false\n withActEnvironment(() => {\n act(() => {\n const root = getContainerRoot(container)\n rootNode = root\n const result = executeRender(root, width, height, null, undefined, pipelineConfig)\n buffer = result.buffer\n })\n if (!hadReactCommit) {\n act(() => {\n stringReconciler.flushSyncWork()\n })\n }\n })\n if (!hadReactCommit) break\n }\n\n // Report content height if callback provided.\n // Compute from children's outer bottom edges (including margins) rather than\n // root.boxRect.height which equals the buffer height (root stretches to fill).\n if (onContentHeight && rootNode) {\n let maxBottom = 0\n let hasChildren = false\n for (const child of rootNode.children) {\n if (child.boxRect) {\n hasChildren = true\n const props = child.props as Record<string, unknown>\n const mb = (props.marginBottom as number) ?? (props.marginY as number) ?? (props.margin as number) ?? 0\n const childBottom = child.boxRect.y + child.boxRect.height + mb\n if (childBottom > maxBottom) maxBottom = childBottom\n }\n }\n onContentHeight(hasChildren ? maxBottom : 0)\n }\n\n // Unmount (cleanup)\n withActEnvironment(() => {\n act(() => {\n stringReconciler.updateContainerSync(null, fiberRoot, null, null)\n stringReconciler.flushSyncWork()\n })\n })\n\n return plain && !alwaysStyled\n ? bufferToText(buffer, { trimTrailingWhitespace, trimEmptyLines })\n : bufferToStyledText(buffer, { trimTrailingWhitespace, trimEmptyLines })\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Run a function with IS_REACT_ACT_ENVIRONMENT temporarily set to true.\n * This ensures act() captures forceUpdate/setState from layout notifications.\n */\nfunction withActEnvironment(fn: () => void): void {\n const prev = (globalThis as any).IS_REACT_ACT_ENVIRONMENT\n ;(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true\n try {\n fn()\n } finally {\n ;(globalThis as any).IS_REACT_ACT_ENVIRONMENT = prev\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"render-string-Bvh1XzBv.mjs","names":[],"sources":["../packages/ag-react/src/reconciler/string-reconciler.ts","../packages/ag-react/src/render-string.tsx"],"sourcesContent":["/**\n * Separate React reconciler instance for renderStringSync.\n *\n * renderStringSync may be called from within React effects (e.g., useScrollback\n * freezing items to scrollback). If it uses the same reconciler singleton as the\n * main render tree, this causes re-entrancy: the nested reconciliation interferes\n * with the outer one, producing empty output.\n *\n * By using a dedicated reconciler instance, renderStringSync operates on an\n * independent fiber tree with no shared reconciler state.\n */\n\n// @ts-expect-error - react-reconciler has no type declarations\nimport Reconciler from \"react-reconciler\"\nimport { hostConfig } from \"./host-config\"\n\n/**\n * Dedicated reconciler for string rendering.\n *\n * Uses the same host config functions but overrides isPrimaryRenderer to false,\n * since this is a secondary renderer used only for one-shot string rendering.\n * This avoids conflicts with the main reconciler's hook ownership.\n */\nexport const stringReconciler = Reconciler({\n ...hostConfig,\n isPrimaryRenderer: false,\n})\n","/**\n * renderString - Static one-shot rendering to string\n *\n * Renders a React element to a string without needing a terminal.\n * Use for:\n * - CI output (no cursor control needed)\n * - Piped output\n * - One-shot reports/summaries\n * - Testing component output\n *\n * @example\n * ```tsx\n * import { renderString, Box, Text } from '@silvery/ag-react'\n *\n * // Basic usage\n * const output = renderString(<Summary stats={stats} />)\n * console.log(output)\n *\n * // Custom width\n * const wide = renderString(<Report />, { width: 120 })\n *\n * // Plain text (no ANSI)\n * const plain = renderString(<Report />, { plain: true })\n * ```\n */\n\nimport React, { type ReactElement, act } from \"react\"\n\nimport { createTerm } from \"@silvery/ag-term/ansi\"\n\nimport { bufferToStyledText, bufferToText, type TerminalBuffer } from \"@silvery/ag-term/buffer\"\nimport { StdoutContext, StderrContext, TermContext } from \"./context\"\nimport { isLayoutEngineInitialized } from \"@silvery/ag-term/layout-engine\"\nimport { executeRender, type PipelineConfig } from \"@silvery/ag-term/pipeline\"\nimport { createContainer, getContainerRoot } from \"./reconciler\"\nimport { stringReconciler } from \"./reconciler/string-reconciler\"\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Options for renderString().\n */\nexport interface RenderStringOptions {\n /**\n * Width in columns for layout calculations.\n * Default: 80\n */\n width?: number\n\n /**\n * Height in rows for layout calculations.\n * Default: 24\n */\n height?: number\n\n /**\n * Strip ANSI codes for plain text output.\n * Default: false (includes ANSI styling)\n */\n plain?: boolean\n\n /**\n * Pipeline configuration (scoped width measurer + output phase).\n * When provided, the render pipeline uses these for width measurement\n * and output generation instead of the global defaults.\n */\n pipelineConfig?: PipelineConfig\n\n /**\n * Trim trailing whitespace from each line.\n * Default: true (trims trailing spaces)\n *\n * Set to false when rendering to stdout where trailing spaces are\n * semantically significant (e.g., ink compat static renders).\n */\n trimTrailingWhitespace?: boolean\n\n /**\n * Trim trailing empty lines from the output.\n * Default: true (removes trailing empty lines)\n *\n * Set to false when padding/margin at the bottom should be preserved\n * (e.g., ink compat renders where `\\n\\n` padding is significant).\n */\n trimEmptyLines?: boolean\n\n /**\n * Callback to receive the computed content height (root node layout height).\n * Useful for callers that need to know the actual content bounds\n * (e.g., Ink compat layer needs to trim buffer padding but preserve\n * content-area empty lines).\n */\n onContentHeight?: (height: number) => void\n\n /**\n * Always use styled output (bufferToStyledText) even when plain=true.\n * Default: false\n *\n * When true, the output includes ANSI codes from embedded sequences in text\n * content (SGR, OSC hyperlinks) even though the mock term has no color\n * support (plain=true). This is needed for Ink compatibility: Ink passes\n * embedded ANSI sequences through regardless of chalk's color level, but\n * silvery's plain mode would strip them via bufferToText.\n *\n * The `plain` flag still controls whether the mock term has color support,\n * which determines whether Text component style props (color, bold, etc.)\n * produce style attributes in the buffer.\n */\n alwaysStyled?: boolean\n}\n\n// ============================================================================\n// Module State\n// ============================================================================\n\n// Track if we've initialized to avoid redundant imports\nlet engineInitialized = false\n\nasync function ensureLayoutEngine(): Promise<void> {\n if (engineInitialized || isLayoutEngineInitialized()) {\n return\n }\n // Use centralized default engine initialization\n const { ensureDefaultLayoutEngine } = await import(\"@silvery/ag-term/layout-engine\")\n await ensureDefaultLayoutEngine()\n engineInitialized = true\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Render a React element to a string (async version).\n *\n * Automatically initializes the layout engine if needed.\n * Use this when you're not sure if the layout engine is ready.\n *\n * @param element - React element to render\n * @param options - Render options (width, height, plain)\n * @returns Rendered string (with or without ANSI codes)\n *\n * @example\n * ```tsx\n * const output = await renderString(<Summary stats={stats} />)\n * console.log(output)\n * ```\n */\nexport async function renderString(element: ReactElement, options: RenderStringOptions = {}): Promise<string> {\n await ensureLayoutEngine()\n return renderStringSync(element, options)\n}\n\n/**\n * Render a React element to a string (sync version).\n *\n * Requires the layout engine to be already initialized.\n * Throws if the layout engine is not ready.\n *\n * @param element - React element to render\n * @param options - Render options (width, height, plain)\n * @returns Rendered string (with or without ANSI codes)\n *\n * @example\n * ```tsx\n * // After layout engine is initialized\n * const output = renderStringSync(<Summary stats={stats} />)\n * console.log(output)\n * ```\n */\nexport function renderStringSync(element: ReactElement, options: RenderStringOptions = {}): string {\n if (!isLayoutEngineInitialized()) {\n throw new Error(\"Layout engine not initialized. Use renderString() (async) or initialize with setLayoutEngine().\")\n }\n\n const {\n width = 80,\n height = 24,\n plain = false,\n pipelineConfig,\n trimTrailingWhitespace = true,\n trimEmptyLines = true,\n onContentHeight,\n alwaysStyled = false,\n } = options\n\n // Track whether React committed new work (from layout notifications etc.)\n let hadReactCommit = false\n const container = createContainer(() => {\n hadReactCommit = true\n })\n\n // Capture uncaught errors from the reconciler so they propagate to the caller\n let uncaughtError: unknown = null\n const onUncaughtError = (error: unknown) => {\n uncaughtError = error\n }\n\n // Create fiber root using the dedicated string reconciler (not the main one)\n const fiberRoot = stringReconciler.createContainer(\n container,\n 1, // ConcurrentRoot\n null, // hydrationCallbacks\n false, // isStrictMode\n null, // concurrentUpdatesByDefaultOverride\n \"\", // identifierPrefix\n onUncaughtError, // onUncaughtError\n () => {}, // onCaughtError\n () => {}, // onRecoverableError\n null, // onDefaultTransitionIndicator\n )\n\n // Create minimal mock stdout for components that use useStdout\n const mockStdout = {\n columns: width,\n rows: height,\n write: () => true,\n isTTY: false,\n on: () => mockStdout,\n off: () => mockStdout,\n once: () => mockStdout,\n removeListener: () => mockStdout,\n addListener: () => mockStdout,\n } as unknown as NodeJS.WriteStream\n\n // Create mock term for components that use useTerm()\n const mockTerm = createTerm({ color: plain ? null : \"truecolor\" })\n\n // Wrap with minimal contexts (no input handling needed)\n const wrapped = React.createElement(\n TermContext.Provider,\n { value: mockTerm },\n React.createElement(\n StdoutContext.Provider,\n {\n value: {\n stdout: mockStdout,\n write: () => {},\n },\n },\n React.createElement(\n StderrContext.Provider,\n {\n value: {\n stderr: process.stderr,\n write: (data: string) => {\n process.stderr.write(data)\n },\n },\n },\n element,\n ),\n ),\n )\n\n // Mount the React tree inside act() so layout feedback works\n withActEnvironment(() => {\n act(() => {\n stringReconciler.updateContainerSync(wrapped, fiberRoot, null, null)\n stringReconciler.flushSyncWork()\n })\n })\n\n // Propagate any uncaught render errors (e.g., text outside <Text> in strict mode)\n if (uncaughtError) {\n throw uncaughtError instanceof Error ? uncaughtError : new Error(String(uncaughtError))\n }\n\n // Layout stabilization loop: run the pipeline, flush React work from\n // layout notifications (useBoxRect forceUpdate etc.), repeat until stable.\n // This matches the test renderer's multi-pass approach.\n let buffer!: TerminalBuffer\n let rootNode: ReturnType<typeof getContainerRoot> | undefined\n const MAX_ITERATIONS = 5\n for (let i = 0; i < MAX_ITERATIONS; i++) {\n hadReactCommit = false\n withActEnvironment(() => {\n act(() => {\n const root = getContainerRoot(container)\n rootNode = root\n const result = executeRender(root, width, height, null, undefined, pipelineConfig)\n buffer = result.buffer\n })\n if (!hadReactCommit) {\n act(() => {\n stringReconciler.flushSyncWork()\n })\n }\n })\n if (!hadReactCommit) break\n }\n\n // Report content height if callback provided.\n // Compute from children's outer bottom edges (including margins) rather than\n // root.boxRect.height which equals the buffer height (root stretches to fill).\n if (onContentHeight && rootNode) {\n let maxBottom = 0\n let hasChildren = false\n for (const child of rootNode.children) {\n if (child.boxRect) {\n hasChildren = true\n const props = child.props as Record<string, unknown>\n const mb = (props.marginBottom as number) ?? (props.marginY as number) ?? (props.margin as number) ?? 0\n const childBottom = child.boxRect.y + child.boxRect.height + mb\n if (childBottom > maxBottom) maxBottom = childBottom\n }\n }\n onContentHeight(hasChildren ? maxBottom : 0)\n }\n\n // Unmount (cleanup)\n withActEnvironment(() => {\n act(() => {\n stringReconciler.updateContainerSync(null, fiberRoot, null, null)\n stringReconciler.flushSyncWork()\n })\n })\n\n return plain && !alwaysStyled\n ? bufferToText(buffer, { trimTrailingWhitespace, trimEmptyLines })\n : bufferToStyledText(buffer, { trimTrailingWhitespace, trimEmptyLines })\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Run a function with IS_REACT_ACT_ENVIRONMENT temporarily set to true.\n * This ensures act() captures forceUpdate/setState from layout notifications.\n */\nfunction withActEnvironment(fn: () => void): void {\n const prev = (globalThis as any).IS_REACT_ACT_ENVIRONMENT\n ;(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true\n try {\n fn()\n } finally {\n ;(globalThis as any).IS_REACT_ACT_ENVIRONMENT = prev\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,mBAAmB,WAAW;CACzC,GAAG;CACH,mBAAmB;CACpB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;aCI6F;AAwF/F,IAAI,oBAAoB;AAExB,eAAe,qBAAoC;AACjD,KAAI,qBAAqB,2BAA2B,CAClD;CAGF,MAAM,EAAE,8BAA8B,MAAM,OAAO;AACnD,OAAM,2BAA2B;AACjC,qBAAoB;;;;;;;;;;;;;;;;;;AAuBtB,eAAsB,aAAa,SAAuB,UAA+B,EAAE,EAAmB;AAC5G,OAAM,oBAAoB;AAC1B,QAAO,iBAAiB,SAAS,QAAQ;;;;;;;;;;;;;;;;;;;AAoB3C,SAAgB,iBAAiB,SAAuB,UAA+B,EAAE,EAAU;AACjG,KAAI,CAAC,2BAA2B,CAC9B,OAAM,IAAI,MAAM,kGAAkG;CAGpH,MAAM,EACJ,QAAQ,IACR,SAAS,IACT,QAAQ,OACR,gBACA,yBAAyB,MACzB,iBAAiB,MACjB,iBACA,eAAe,UACb;CAGJ,IAAI,iBAAiB;CACrB,MAAM,YAAY,sBAAsB;AACtC,mBAAiB;GACjB;CAGF,IAAI,gBAAyB;CAC7B,MAAM,mBAAmB,UAAmB;AAC1C,kBAAgB;;CAIlB,MAAM,YAAY,iBAAiB,gBACjC,WACA,GACA,MACA,OACA,MACA,IACA,uBACM,UACA,IACN,KACD;CAGD,MAAM,aAAa;EACjB,SAAS;EACT,MAAM;EACN,aAAa;EACb,OAAO;EACP,UAAU;EACV,WAAW;EACX,YAAY;EACZ,sBAAsB;EACtB,mBAAmB;EACpB;CAGD,MAAM,WAAW,WAAW,EAAE,OAAO,QAAQ,OAAO,aAAa,CAAC;CAGlE,MAAM,UAAU,MAAM,cACpB,YAAY,UACZ,EAAE,OAAO,UAAU,EACnB,MAAM,cACJ,cAAc,UACd,EACE,OAAO;EACL,QAAQ;EACR,aAAa;EACd,EACF,EACD,MAAM,cACJ,cAAc,UACd,EACE,OAAO;EACL,QAAQ,QAAQ;EAChB,QAAQ,SAAiB;AACvB,WAAQ,OAAO,MAAM,KAAK;;EAE7B,EACF,EACD,QACD,CACF,CACF;AAGD,0BAAyB;AACvB,YAAU;AACR,oBAAiB,oBAAoB,SAAS,WAAW,MAAM,KAAK;AACpE,oBAAiB,eAAe;IAChC;GACF;AAGF,KAAI,cACF,OAAM,yBAAyB,QAAQ,gBAAgB,IAAI,MAAM,OAAO,cAAc,CAAC;CAMzF,IAAI;CACJ,IAAI;CACJ,MAAM,iBAAiB;AACvB,MAAK,IAAI,IAAI,GAAG,IAAI,gBAAgB,KAAK;AACvC,mBAAiB;AACjB,2BAAyB;AACvB,aAAU;IACR,MAAM,OAAO,iBAAiB,UAAU;AACxC,eAAW;AAEX,aADe,cAAc,MAAM,OAAO,QAAQ,MAAM,KAAA,GAAW,eAAe,CAClE;KAChB;AACF,OAAI,CAAC,eACH,WAAU;AACR,qBAAiB,eAAe;KAChC;IAEJ;AACF,MAAI,CAAC,eAAgB;;AAMvB,KAAI,mBAAmB,UAAU;EAC/B,IAAI,YAAY;EAChB,IAAI,cAAc;AAClB,OAAK,MAAM,SAAS,SAAS,SAC3B,KAAI,MAAM,SAAS;AACjB,iBAAc;GACd,MAAM,QAAQ,MAAM;GACpB,MAAM,KAAM,MAAM,gBAA4B,MAAM,WAAuB,MAAM,UAAqB;GACtG,MAAM,cAAc,MAAM,QAAQ,IAAI,MAAM,QAAQ,SAAS;AAC7D,OAAI,cAAc,UAAW,aAAY;;AAG7C,kBAAgB,cAAc,YAAY,EAAE;;AAI9C,0BAAyB;AACvB,YAAU;AACR,oBAAiB,oBAAoB,MAAM,WAAW,MAAM,KAAK;AACjE,oBAAiB,eAAe;IAChC;GACF;AAEF,QAAO,SAAS,CAAC,eACb,aAAa,QAAQ;EAAE;EAAwB;EAAgB,CAAC,GAChE,mBAAmB,QAAQ;EAAE;EAAwB;EAAgB,CAAC;;;;;;AAW5E,SAAS,mBAAmB,IAAsB;CAChD,MAAM,OAAQ,WAAmB;AAC/B,YAAmB,2BAA2B;AAChD,KAAI;AACF,MAAI;WACI;AACN,aAAmB,2BAA2B"}
@@ -1,2 +1,2 @@
1
- import { n as renderStringSync, t as renderString } from "./render-string-BXvxTg5P.mjs";
1
+ import { n as renderStringSync, t as renderString } from "./render-string-Bvh1XzBv.mjs";
2
2
  export { renderString, renderStringSync };
@@ -1,10 +1,10 @@
1
1
  import { a as __toCommonJS, i as __require } from "./chunk-BSw8zbkd.mjs";
2
2
  import { a as RuntimeContext, c as TermContext, i as NodeContext, n as CapabilityRegistryContext, o as StderrContext, r as FocusManagerContext, s as StdoutContext, t as CacheBackendContext } from "./context-QreF3UHr.mjs";
3
- import { At as bufferToStyledText, Bt as keyToAnsi, C as createTermProvider, Ct as detectTextSizingSupport, Et as isTextSizingLikelySupported, F as outputPhase, Kt as parseKey, L as IncrementalRenderMismatchError, Lt as init_buffer, Mt as buffer_exports, Nt as cellEquals, P as createOutputPhase, S as createTerm, T as enableFocusReporting, V as createWidthMeasurer, Vt as keyToKittyAnsi, b as createOutputGuard, g as isAnyDirty, gt as stripAnsi, i as reconciler, jt as bufferToText, n as createFiberRoot, r as getContainerRoot, s as setOnNodeRemoved, t as createContainer, v as isDirty, wt as getCachedProbeResult, zt as isModifierOnlyEvent } from "./reconciler-2lp5VXK7.mjs";
3
+ import { At as bufferToStyledText, Bt as keyToAnsi, C as createTermProvider, Ct as detectTextSizingSupport, Et as isTextSizingLikelySupported, F as outputPhase, Kt as parseKey, L as IncrementalRenderMismatchError, Lt as init_buffer, Mt as buffer_exports, Nt as cellEquals, P as createOutputPhase, S as createTerm, T as enableFocusReporting, V as createWidthMeasurer, Vt as keyToKittyAnsi, b as createOutputGuard, g as isAnyDirty, gt as stripAnsi, i as reconciler, jt as bufferToText, n as createFiberRoot, r as getContainerRoot, s as setOnNodeRemoved, t as createContainer, v as isDirty, wt as getCachedProbeResult, zt as isModifierOnlyEvent } from "./reconciler-B-NaZvbO.mjs";
4
4
  import { B as enableKittyKeyboard$1, J as detectTerminalCaps, R as disableKittyKeyboard$1, V as enableMouse$1, t as init_src, z as disableMouse$1 } from "./src-9B5k0JmY.mjs";
5
5
  import { C as ThemeProvider, i as init_detect, r as detectTheme, w as init_ThemeContext } from "./src-C9f3hiVG.mjs";
6
6
  import { i as isLayoutEngineInitialized, t as ensureDefaultLayoutEngine } from "./layout-engine-B3dsnVLU.mjs";
7
- import { i as signal, n as createAg, r as _usingCtx, t as executeRender } from "./pipeline-DDOPrjuY.mjs";
7
+ import { i as signal, n as createAg, r as _usingCtx, t as executeRender } from "./pipeline-BmfaZb1O.mjs";
8
8
  import { r as useScrollRect } from "./useLayout-BG2cGl15.mjs";
9
9
  import React, { Component, createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef } from "react";
10
10
  import { jsx } from "react/jsx-runtime";
@@ -8720,4 +8720,4 @@ function createAdaptiveTick(targetFps = 60, signal) {
8720
8720
  //#endregion
8721
8721
  export { dispatchMouseEvent as $, SilveryErrorBoundary as $t, fromArrayWithDelay as A, setCursorStyle as An, resolveFromTerm as At, withFocusManagement as B, splitPane as Bn, generateHitRegionId as Bt, layoutSync as C, notifyITerm2 as Cn, runTermtest as Ct, filter as D, resetCursorStyle as Dn, createInputEvents as Dt, debounce as E, reportDirectory as En, OSC133 as Et, throttle as F, findAdjacentPane as Fn, requestClipboard as Ft, inspectTree as G, createTextSurface as Gn, dispatchKeyEvent as Gt, disableInspector as H, createSearchState as Hn, createFocusEvent as Ht, zip as I, getPaneIds as In, isTTY as It, computeEnterLeave as J, createHistoryItem as Jn, findEnclosingScope as Jt, isInspectorEnabled as K, createListDocument as Kn, createFocusManager as Kt, createStore$1 as L, getTabOrder$1 as Ln, resolveNonTTYMode as Lt, merge as M, setWindowAndIconTitle as Mn, RenderScheduler as Mt, take as N, setWindowTitle as Nn, copyToClipboard as Nt, filterMap as O, resetMouseCursorShape as On, isTerm$1 as Ot, takeUntil as P, createLeaf as Pn, parseClipboardResponse as Pt, createWheelEvent as Q, getTabOrder as Qt, defaultInit as R, removePane as Rn, HitRegistry as Rt, layout as S, notify as Sn, TERMTEST_SECTIONS as St, concat as T, queryKittyKeyboard as Tn, detectKittySupport as Tt, enableInspector as U, searchUpdate as Un, createKeyEvent as Ut, autoEnableInspector as V, swapPanes as Vn, resetHitRegionIdCounter as Vt, inspectFrame as W, composeViewport as Wn, dispatchFocusEvent as Wt, createMouseEvent as X, calcEdgeBasedScrollOffset as Xn, findSpatialTarget as Xt, createDoubleClickState as Y, useInput as Yn, findFocusableAncestor as Yt, createMouseEventProcessor as Z, getExplicitFocusLink as Zt, createRuntime as _, disableMouse as _n, queryTertiaryDA as _t, run as a, useCursor as an, CanvasRenderBuffer as at, render as b, enterAlternateScreen as bn, createPipeline as bt, createApp as c, scrollDown as cn, queryTextAreaPixels as ct, CTRL_C as d, supportsScrollRegions as dn, queryMode as dt, CursorProvider as en, hitTest as et, CTRL_Z as f, useExit as fn, queryModes as ft, resumeTerminalState as g, disableKittyKeyboard as gn, queryTerminalVersion as gt, restoreTerminalState as h, KittyFlags as hn, querySecondaryDA as ht, createTick as i, subscribeCursor as in, injectDOMStyles as it, map as j, setMouseCursorShape as jn, resolveTermDef as jt, fromArray as k, resetWindowTitle as kn, isTermDef as kt, useApp as l, scrollUp as ln, queryTextAreaSize as lt, performSuspend as m, BEL$1 as mn, queryPrimaryDA as mt, createFrameTick as n, getCursorState as nn, DOMRenderBuffer as nt, usePasteCallback as o, moveCursor as on, createCanvasAdapter as ot, captureTerminalState as p, ANSI as pn, queryDeviceAttributes as pt, checkDoubleClick as q, createHistoryBuffer as qn, findByTestID as qt, createSecondTick as r, resetCursorState as rn, createDOMAdapter as rt, StoreContext as s, resetScrollRegion as sn, queryCellSize as st, createAdaptiveTick as t, createCursorStore as tn, processMouseEvent as tt, useAppShallow as u, setScrollRegion as un, DecMode as ut, createBuffer as v, enableKittyKeyboard as vn, queryCursorFromStdio as vt, batch as w, notifyKitty as wn, detectKittyFromStdio as wt, ensureLayoutEngine as x, leaveAlternateScreen as xn, withMeasurer as xt, diff as y, enableMouse as yn, queryCursorPosition as yt, silveryUpdate as z, resizeSplit as zn, Z_INDEX as zt };
8722
8722
 
8723
- //# sourceMappingURL=runtime-BjDHNTxJ.mjs.map
8723
+ //# sourceMappingURL=runtime-PH2xY1DM.mjs.map