[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
143
domain/terminalInlineImages.ts
Normal file
143
domain/terminalInlineImages.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import type { TerminalSettings } from "./models/terminal";
|
||||
|
||||
/**
|
||||
* Inline raster image output (Kitty graphics, SIXEL, iTerm IIP) rendered by
|
||||
* `@xterm/addon-image`. The addon keeps decoded bitmaps outside the terminal
|
||||
* buffer, so every limit here is a memory guard rather than a cosmetic option:
|
||||
*
|
||||
* - `storageLimit` caps the FIFO image cache of a single terminal (MB, RGBA8888).
|
||||
* - `pixelLimit` caps a single decoded image; the decoder holds up to two pixel
|
||||
* buffers of that size while working, so 4 bytes * pixels * 2 is the transient
|
||||
* peak per decoding terminal.
|
||||
* - the sequence limit caps the raw escape-sequence payload before decoding, so
|
||||
* an oversized or corrupt sequence is rejected before it allocates anything.
|
||||
*/
|
||||
|
||||
/** Compile-time kill switch for inline terminal images. */
|
||||
export const TERMINAL_INLINE_IMAGES_ENABLED = true;
|
||||
|
||||
/** Per-terminal image cache size in MB. */
|
||||
export const TERMINAL_INLINE_IMAGE_STORAGE_LIMIT_MB_DEFAULT = 128;
|
||||
|
||||
export const TERMINAL_INLINE_IMAGE_STORAGE_LIMIT_MB_MIN = 8;
|
||||
|
||||
export const TERMINAL_INLINE_IMAGE_STORAGE_LIMIT_MB_MAX = 512;
|
||||
|
||||
/** Largest single decoded image, in megapixels (16 MP == 4096 x 4096). */
|
||||
export const TERMINAL_INLINE_IMAGE_MAX_MEGAPIXELS_DEFAULT = 16;
|
||||
|
||||
export const TERMINAL_INLINE_IMAGE_MAX_MEGAPIXELS_MIN = 1;
|
||||
|
||||
export const TERMINAL_INLINE_IMAGE_MAX_MEGAPIXELS_MAX = 64;
|
||||
|
||||
/** Largest single image escape sequence, in MB, before decoding is attempted. */
|
||||
export const TERMINAL_INLINE_IMAGE_SEQUENCE_LIMIT_MB_DEFAULT = 24;
|
||||
|
||||
export const TERMINAL_INLINE_IMAGE_SEQUENCE_LIMIT_MB_MIN = 1;
|
||||
|
||||
export const TERMINAL_INLINE_IMAGE_SEQUENCE_LIMIT_MB_MAX = 64;
|
||||
|
||||
const BYTES_PER_MB = 1024 * 1024;
|
||||
|
||||
const PIXELS_PER_MEGAPIXEL = 1024 * 1024;
|
||||
|
||||
const clampInteger = (value: unknown, min: number, max: number, fallback: number): number => {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
||||
return Math.min(max, Math.max(min, Math.round(value)));
|
||||
};
|
||||
|
||||
export function normalizeInlineImageStorageLimitMb(value: unknown): number {
|
||||
return clampInteger(
|
||||
value,
|
||||
TERMINAL_INLINE_IMAGE_STORAGE_LIMIT_MB_MIN,
|
||||
TERMINAL_INLINE_IMAGE_STORAGE_LIMIT_MB_MAX,
|
||||
TERMINAL_INLINE_IMAGE_STORAGE_LIMIT_MB_DEFAULT,
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeInlineImageMaxMegapixels(value: unknown): number {
|
||||
return clampInteger(
|
||||
value,
|
||||
TERMINAL_INLINE_IMAGE_MAX_MEGAPIXELS_MIN,
|
||||
TERMINAL_INLINE_IMAGE_MAX_MEGAPIXELS_MAX,
|
||||
TERMINAL_INLINE_IMAGE_MAX_MEGAPIXELS_DEFAULT,
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeInlineImageSequenceLimitMb(value: unknown): number {
|
||||
return clampInteger(
|
||||
value,
|
||||
TERMINAL_INLINE_IMAGE_SEQUENCE_LIMIT_MB_MIN,
|
||||
TERMINAL_INLINE_IMAGE_SEQUENCE_LIMIT_MB_MAX,
|
||||
TERMINAL_INLINE_IMAGE_SEQUENCE_LIMIT_MB_DEFAULT,
|
||||
);
|
||||
}
|
||||
|
||||
export type TerminalInlineImageSettings = Pick<
|
||||
TerminalSettings,
|
||||
| "inlineImagesEnabled"
|
||||
| "inlineImageKittyEnabled"
|
||||
| "inlineImageSixelEnabled"
|
||||
| "inlineImageIipEnabled"
|
||||
| "inlineImageStorageLimitMb"
|
||||
| "inlineImageMaxMegapixels"
|
||||
| "inlineImageSequenceLimitMb"
|
||||
>;
|
||||
|
||||
/**
|
||||
* Structural mirror of `IImageAddonOptions` from `@xterm/addon-image`. Declared
|
||||
* here so the domain layer stays free of renderer dependencies; the runtime
|
||||
* passes the result straight into the addon constructor.
|
||||
*/
|
||||
export type TerminalInlineImageAddonOptions = {
|
||||
enableSizeReports: boolean;
|
||||
pixelLimit: number;
|
||||
storageLimit: number;
|
||||
showPlaceholder: boolean;
|
||||
sixelSupport: boolean;
|
||||
sixelSizeLimit: number;
|
||||
iipSupport: boolean;
|
||||
iipSizeLimit: number;
|
||||
kittySupport: boolean;
|
||||
kittySizeLimit: number;
|
||||
};
|
||||
|
||||
export function resolveTerminalInlineImagesEnabled(
|
||||
settings?: Partial<TerminalInlineImageSettings> | null,
|
||||
): boolean {
|
||||
if (!TERMINAL_INLINE_IMAGES_ENABLED) return false;
|
||||
if (settings?.inlineImagesEnabled !== true) return false;
|
||||
return (
|
||||
settings.inlineImageKittyEnabled === true
|
||||
|| settings.inlineImageSixelEnabled === true
|
||||
|| settings.inlineImageIipEnabled === true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the addon options for a terminal, or `null` when inline images are off
|
||||
* (master switch, or every protocol disabled). A `null` result means the addon
|
||||
* must not be loaded at all, so the terminal keeps advertising no graphics
|
||||
* capability to the remote side.
|
||||
*/
|
||||
export function resolveTerminalInlineImageAddonOptions(
|
||||
settings?: Partial<TerminalInlineImageSettings> | null,
|
||||
): TerminalInlineImageAddonOptions | null {
|
||||
if (!resolveTerminalInlineImagesEnabled(settings)) return null;
|
||||
const sequenceLimitBytes =
|
||||
normalizeInlineImageSequenceLimitMb(settings?.inlineImageSequenceLimitMb) * BYTES_PER_MB;
|
||||
return {
|
||||
// Image producers need CSI 14/16/18 t to size their output to the grid.
|
||||
enableSizeReports: true,
|
||||
pixelLimit:
|
||||
normalizeInlineImageMaxMegapixels(settings?.inlineImageMaxMegapixels) * PIXELS_PER_MEGAPIXEL,
|
||||
storageLimit: normalizeInlineImageStorageLimitMb(settings?.inlineImageStorageLimitMb),
|
||||
showPlaceholder: true,
|
||||
sixelSupport: settings?.inlineImageSixelEnabled === true,
|
||||
sixelSizeLimit: sequenceLimitBytes,
|
||||
iipSupport: settings?.inlineImageIipEnabled === true,
|
||||
iipSizeLimit: sequenceLimitBytes,
|
||||
kittySupport: settings?.inlineImageKittyEnabled === true,
|
||||
kittySizeLimit: sequenceLimitBytes,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user