@lijian-ui/dsh-file-manager 0.1.21 → 0.2.0

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.
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["css","scmCss","dirOf","explorerCss","previewCss","previewCss","previewCss","CodeBlock","previewCss","dragCss","previewCss","apply","pickerCss"],"sources":["../src/client/api.ts","../src/client/PluginSettingsCard.tsx","../src/client/settings-form.ts","../src/client/FileManagerSettingsCard.tsx","../src/client/drag.ts","../src/client/fileType.ts","../src/client/persist.ts","../src/client/store.ts","../src/client/maximize.ts","../src/client/floating.ts","../src/client/layout.ts","../src/client/locales.ts","../src/client/hooks/useStore.ts","../src/client/components/icons.tsx","../src/client/components/FileIcon.tsx","../src/client/components/overlay.tsx","../src/client/components/a11y.ts","../src/client/components/ScmPanel.tsx","../src/client/drag/file-drag.ts","../src/client/components/ExplorerPanel.tsx","../src/client/preview/PreviewTabs.tsx","../src/client/preview/PreviewToolbar.tsx","../src/client/hooks/useResizableSplit.ts","../src/client/preview/markdown.ts","../src/client/preview/mermaid.ts","../src/client/preview/content.tsx","../src/client/preview/selection.ts","../src/client/preview/PreviewPanel.tsx","../src/client/mount.tsx","../src/client/drag/DragFileInlay.tsx","../src/client/chat/mermaid-chat.tsx","../src/client/chat/placeholder-hint.tsx","../src/client/picker/file-picker.ts","../src/client/reference.ts","../src/client/picker/FilePickerModal.tsx","../src/client/chat/file-ref.ts","../src/client/file-source.ts","../src/client/index.ts"],"sourcesContent":["/**\n * Browser client for the host /filemgr/* routes: typed JSON envelope\n * calls plus the SSE change subscription. Same-origin relative fetch (the\n * page and the routes share the webserver).\n * @module dsh-filemgr/client/api\n */\n\nimport type {\n DirListing, FileRead, GitBatchResult, GitStatusView, PanelEnvelope, PanelError, SearchView,\n} from '../core/types.ts'\n\n/** Transport failure (fetch threw or the response was not JSON). */\nconst TRANSPORT_ERROR: PanelError = { code: 'internal', message: 'panel route unavailable' }\n\n/** POST one JSON payload and decode the envelope; never throws. */\nasync function post<T>(path: string, payload: Record<string, unknown>): Promise<PanelEnvelope<T>> {\n let response: Response\n try {\n response = await fetch(path, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch {\n return { ok: false, error: TRANSPORT_ERROR }\n }\n try {\n const envelope = await response.json() as unknown\n if (typeof envelope !== 'object' || envelope === null) return { ok: false, error: TRANSPORT_ERROR }\n const record = envelope as Record<string, unknown>\n if (record.ok === true) return { ok: true, value: record.value as T }\n return { ok: false, error: (record.error as PanelError | undefined) ?? TRANSPORT_ERROR }\n } catch {\n return { ok: false, error: TRANSPORT_ERROR }\n }\n}\n\n/** Typed panel operations over the wire. */\nexport class PanelApi {\n /** List one directory of the project root (rel path; '' = root). */\n list(root: string, path: string): Promise<PanelEnvelope<DirListing>> {\n return post('/filemgr/list', { root, path })\n }\n\n /** Read one file (text or image data URL). */\n read(root: string, path: string, asImage: boolean): Promise<PanelEnvelope<FileRead>> {\n return post('/filemgr/read', { root, path, asImage })\n }\n\n /** Write text content back with an optional mtime conflict base. */\n write(root: string, path: string, content: string, baseMtime?: number): Promise<PanelEnvelope<{ mtime: number }>> {\n return post('/filemgr/write', { root, path, content, baseMtime })\n }\n\n /** Filename search under the root. */\n search(root: string, query: string): Promise<PanelEnvelope<SearchView>> {\n return post('/filemgr/search', { root, query })\n }\n\n /** Delete a path (untracked discard). */\n delete(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/delete', { root, path })\n }\n\n /** Reveal a path in the OS file manager (selecting the entry). */\n reveal(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/reveal', { root, path })\n }\n\n /** Open a path with the OS default app. */\n openWithDefault(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/open-with-default', { root, path })\n }\n\n /** Rename a path (newName is a bare name, no separators). */\n rename(root: string, path: string, newName: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/rename', { root, path, newName })\n }\n\n /** Create a directory at a relative path (parent must exist). */\n mkdir(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/mkdir', { root, path })\n }\n\n /** Create an empty file at a relative path (refuses to overwrite). */\n newFile(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/new-file', { root, path })\n }\n\n /** The repo status view; null when the root is not a repository. */\n gitStatus(root: string): Promise<PanelEnvelope<GitStatusView | null>> {\n return post('/filemgr/git-status', { root })\n }\n\n /** The unified diff text of one path (staged = index vs HEAD). */\n gitDiff(root: string, path: string, staged: boolean): Promise<PanelEnvelope<{ content: string }>> {\n return post('/filemgr/git-diff', { root, path, staged })\n }\n\n /** Stage paths. */\n gitStage(root: string, paths: string[]): Promise<PanelEnvelope<GitBatchResult>> {\n return post('/filemgr/git-stage', { root, paths })\n }\n\n /** Unstage paths. */\n gitUnstage(root: string, paths: string[]): Promise<PanelEnvelope<GitBatchResult>> {\n return post('/filemgr/git-unstage', { root, paths })\n }\n\n /** Discard paths (worktree side; untracked paths are deleted). */\n gitDiscard(root: string, paths: string[]): Promise<PanelEnvelope<GitBatchResult>> {\n return post('/filemgr/git-discard', { root, paths })\n }\n}\n\n/** One SSE change event pushed by the host. */\nexport type PanelChangeEvent =\n | { kind: 'fs' }\n | { kind: 'git'; status: GitStatusView }\n | { kind: 'gitUnavailable' }\n\n/**\n * Subscribe to host-pushed changes for one project root (fs watch events and\n * git status polls). Reconnects are handled by the EventSource; the caller\n * re-subscribes when the root changes.\n * @param root - project root to watch.\n * @param onChange - fired on every pushed change.\n * @returns the disposer closing the stream.\n */\nexport function subscribePanelEvents(root: string, onChange: (event: PanelChangeEvent) => void): () => void {\n const source = new EventSource(`/filemgr/events?root=${encodeURIComponent(root)}`)\n source.addEventListener('change', (raw) => {\n try {\n const event = JSON.parse((raw as MessageEvent).data as string) as PanelChangeEvent\n onChange(event)\n } catch {\n // malformed push; ignore\n }\n })\n return () => { source.close() }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/PluginSettingsCard.tsx. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Family-shared chrome for plugin settings cards: a disclosure header naming\n * the plugin and what its settings govern, the controls inside, and the save\n * that writes them. Renders nothing while the namespace is unavailable — a\n * deployment that does not compose the owning plugin should show no trace of\n * it. Inlined into each consumer's client bundle; mirrors the official\n * ui-plugin-config PluginCard in a self-contained slice.\n */\n\nimport { useState, type ReactNode } from 'react'\nimport type { CardShell } from './settings-form.ts'\nimport css from './settings-card.module.css'\n\n/** Copy keys the card chrome itself reads; every consumer locale carries this shared vocabulary. */\nexport const CARD_COPY_KEYS = [\n 'settings.collapse',\n 'settings.expand',\n 'settings.notExposed',\n 'settings.unsaved',\n 'settings.readOnly',\n 'settings.saveFailed',\n 'settings.discard',\n 'settings.save',\n 'settings.saving',\n] as const\n\n/** Copy key the card chrome itself reads. */\nexport type CardCopyKey = (typeof CARD_COPY_KEYS)[number]\n\n/** Key domain for the plugin's own copy (inferred per consumer). */\nexport type SettingsCardKey<TKey extends string = string> = TKey | CardCopyKey\n\n/** Card chrome shared by every plugin settings card. */\nexport interface PluginSettingsCardProps<TKey extends string = string> {\n /** Locale reader for this card's copy. */\n t: (key: SettingsCardKey<TKey>, params?: Record<string, string | number>) => string\n /** Locale key of the plugin's name. */\n titleKey: TKey\n /** Locale key of the line describing what this plugin's settings govern. */\n descriptionKey: TKey\n /** The card's form state: availability, writability, and what a save would do. */\n state: CardShell\n /** Write every staged edit. */\n onSave: () => void\n /** Drop every staged edit. */\n onDiscard: () => void\n /**\n * Render the controls expanded on arrival (still collapsible). Defaults to\n * true: promoted first-level sections show their settings immediately.\n */\n defaultOpen?: boolean\n /**\n * Render without the collapse affordance: a static header and an always\n * visible body. Used by first-level settings sections whose nav entry\n * already provides the selection.\n */\n alwaysOpen?: boolean\n /** The plugin's controls. */\n children: ReactNode\n}\n\n/**\n * Render one plugin settings card.\n * @param props - the plugin's copy keys, its form state, and its controls.\n * @returns the card, or nothing while the namespace is still loading.\n */\nexport function PluginSettingsCard<TKey extends string = string>(props: PluginSettingsCardProps<TKey>) {\n const [open, setOpen] = useState(props.defaultOpen ?? true)\n const { state, alwaysOpen } = props\n if (!state.available) return null\n const title = props.t(props.titleKey)\n const description = props.t(props.descriptionKey)\n const blocked = !state.dirty || state.invalid || state.saving\n const expanded = alwaysOpen === true || open\n const cardClass = expanded ? `${css.cardOpen} ${css.card}` : css.card\n // With alwaysOpen the nav entry already provides the selection, so the\n // header is a static title row instead of a disclosure button.\n const header = alwaysOpen === true\n ? (\n <div className={css.headerStatic}>\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n </div>\n )\n : (\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.chevron} ${css.chevronOpen}` : css.chevron}\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n )\n // The namespace exists but the Host does not serve it to this client (the\n // official settings allowlist omits third-party namespaces): show a card\n // that explains the gap instead of vanishing, so a missing card never\n // reads as a missing plugin.\n if (!state.exposed) {\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n <p className={css.notExposed} role=\"status\">{props.t('settings.notExposed')}</p>\n </div>\n )\n : null}\n </li>\n )\n }\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n {!state.writable ? <p className={css.readOnly} role=\"status\">{props.t('settings.readOnly')}</p> : null}\n {props.children}\n <div className={css.footer}>\n {state.failed\n ? (\n <p className={css.failed} role=\"status\">\n {props.t('settings.saveFailed')}{state.failedReason ? ' - ' + state.failedReason : ''}\n </p>\n )\n : null}\n <button\n type=\"button\"\n className={css.discard}\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('settings.discard')}\n </button>\n <button\n type=\"button\"\n className={css.save}\n disabled={blocked}\n onClick={props.onSave}\n >\n {props.t(!state.saving ? 'settings.save' : 'settings.saving')}\n </button>\n </div>\n </div>\n )\n : null}\n </li>\n )\n}\n\n/** Props every field control needs regardless of its value type. */\nexport interface FieldProps {\n /** Stable id associating the label with its control. */\n id: string\n /** Visible label. */\n label: string\n /** One-line explanation rendered under the control. */\n hint: string\n /** Draft text this control renders. */\n text: string\n /** True when saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** True when the draft is not a value this field accepts. */\n invalid: boolean\n /** Copy for the overridden badge. */\n overriddenLabel: string\n /** Copy for the reset control. */\n resetLabel: string\n /** Copy shown in place of the hint while the draft is invalid. */\n invalidLabel: string\n /** Disables every control (read-only document, or an unavailable namespace). */\n disabled: boolean\n /** Stage draft text. */\n onEdit: (text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n onReset: () => void\n}\n\n/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */\nexport function ValueField(props: FieldProps & {\n /** Hints a numeric keypad without narrowing what the control accepts. */\n numeric?: boolean\n /** Placeholder shown while the draft is empty. */\n placeholder?: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? css.inputInvalid : css.input}\n type=\"text\"\n {...props.numeric === true ? { inputMode: 'numeric' as const } : {}}\n {...props.invalid ? { 'aria-invalid': true } : {}}\n value={props.text}\n placeholder={props.placeholder ?? ''}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n\n/** A staged boolean field: 继承 / 开 / 关. */\nexport function BooleanField(props: FieldProps & {\n /** Copy for the inherit option. */\n inheritLabel: string\n /** Copy for the on option. */\n onLabel: string\n /** Copy for the off option. */\n offLabel: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <select\n id={props.id}\n className={css.select}\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n >\n <option value=\"\">{props.inheritLabel}</option>\n <option value=\"true\">{props.onLabel}</option>\n <option value=\"false\">{props.offLabel}</option>\n </select>\n <p className={css.hint}>{props.hint}</p>\n </div>\n )\n}\n\n/** A staged enumerated field rendered as a select. */\nexport function ChoiceField(props: FieldProps & {\n /** Copy for the inherit option (draft text is the empty string). */\n inheritLabel: string\n /** Choices rendered in order; `value` is the draft/stored text. */\n choices: ReadonlyArray<{ value: string; label: string }>\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <select\n id={props.id}\n className={css.select}\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n >\n <option value=\"\">{props.inheritLabel}</option>\n {props.choices.map(choice => (\n <option key={choice.value} value={choice.value}>{choice.label}</option>\n ))}\n </select>\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/settings-form.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Staged form model behind the plugin settings card. A card stages what the\n * user types and writes it only when they save — the settings write is a\n * durable, revision-fenced document mutation, so staging keeps what is on\n * screen exactly what a save would store. Family-shared slice inlined into\n * each plugin's client bundle; mirrors the official ui-plugin-config\n * card-store pattern.\n */\n\nimport type { SettingsScope, SettingsScopeSnapshot, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\n\n/** The write one field's staged text performs when the card is saved. */\nexport type FieldWrite =\n | { kind: 'set'; value: unknown }\n | { kind: 'clear' }\n\n/** How one field converts between its stored value and its draft text. */\nexport interface FieldSpec {\n /** Field name inside the namespace section. */\n field: string\n /**\n * Whether the Host treats this field as a secret and redacts its value from\n * the read-back (role('secret') in the section schema). Redacted secrets are\n * never compared against the draft on save; the field lands when the scope\n * reports the write succeeded (its secret-set marker under the bridge), so\n * a successful secret save is not misreported as failed.\n */\n secret?: boolean\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string\n /**\n * The write this draft text stages, or undefined when the text is not a\n * value this field accepts — which blocks the save rather than discarding it.\n */\n parse: (text: string) => FieldWrite | undefined\n}\n\n/** One field as the card renders it. */\nexport interface FieldState {\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts, which blocks saving. */\n invalid: boolean\n}\n\n/** Form state every plugin settings card shares. */\nexport interface CardShell {\n /** False while the namespace is still loading; the card renders nothing. */\n available: boolean\n /**\n * Whether the namespace is actually served to this client. False when the\n * Host deployment does not expose it (e.g. the official apiproxy settings\n * allowlist omits third-party namespaces): the card renders an explanation\n * instead of its form, so a missing namespace never looks like a missing\n * plugin.\n */\n exposed: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the form holds edits that a save would write. */\n dirty: boolean\n /** Whether any staged draft is invalid, which blocks the save. */\n invalid: boolean\n /** Whether a save is crossing the wire. */\n saving: boolean\n /** Whether the last save did not land as staged; cleared by the next edit or save. */\n failed: boolean\n /**\n * The rejection code/message the Host returned for the last failed save,\n * surfaced next to the generic failure text. Undefined while no save has\n * failed (or the failure carried no server reason).\n */\n failedReason?: string\n}\n\n/** The write actions the card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void\n /** Stage a clear, so saving lets the field re-inherit the composition layer. */\n resetField: (field: string) => void\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void\n /** Drop every staged edit. */\n discard: () => void\n}\n\n/** One field's staged edit. */\ninterface StagedEdit {\n /** Draft text the control renders. */\n text: string\n /** True when this edit clears the field whatever text it shows. */\n clear: boolean\n}\n\n/** One staged edit resolved into the write a save performs. */\ninterface PlannedWrite {\n /** Field this entry writes. */\n field: string\n /** The durable write this entry performs, described for a batched scope. */\n op: BatchedWrite\n /** Perform the write and report whether the Host holds the staged value afterwards. */\n run: (() => Promise<boolean>) | undefined\n}\n\n/** One durable write a batched settings scope performs. */\nexport interface BatchedWrite {\n /** Field this entry writes. */\n field: string\n /** set stores a value; unset drops the leaf. */\n op: 'set' | 'unset'\n /** Value for op set (absent for unset). */\n value?: unknown\n}\n\n/** Per-field outcome of one batched scope write. */\nexport interface BatchedFieldResult {\n /** Field this entry writes. */\n field: string\n /** Whether the Host accepted this field's write (per the read-back view). */\n landed: boolean\n}\n\n/**\n * Result of a batched scope write. The bridge scope posts every planned write\n * in one /mutate so the Host validate hook judges baseURL+model together; a\n * batched refusal fails the whole save rather than per-field.\n */\nexport interface BatchResult {\n /** Whether the whole mutate was accepted. */\n ok: boolean\n /** Per-field success, in the request order (always present when ok). */\n fields: BatchedFieldResult[]\n /** Host rejection code (mutate refused). */\n code?: string\n /** Host rejection message (mutate refused). */\n message?: string\n}\n\n/** The optional batch surface the bridge scope adds over the SettingsScope contract. */\ninterface BatchedSettingsScope {\n /** Write every operation in one scope mutation, reporting per-field success. */\n mutate: (writes: BatchedWrite[]) => Promise<BatchResult>\n}\n\n/** Constraints a numeric field's accepted drafts must satisfy, mirroring the host schema. */\nexport interface NumberConstraints {\n /** The accepted value must be a whole number. */\n integer?: boolean\n /** The accepted value must be at least this. */\n min?: number\n}\n\n/** A whole- or decimal-number field. An empty draft clears the field; any other draft that is not a finite number within the constraints blocks the save. */\nexport function numberField(field: string, constraints: NumberConstraints = {}): FieldSpec {\n const { integer = false, min } = constraints\n return {\n field,\n format: value => typeof value === 'number' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n if (!Number.isFinite(parsed)) return undefined\n if (integer && !Number.isInteger(parsed)) return undefined\n if (min !== undefined && parsed < min) return undefined\n return { kind: 'set', value: parsed }\n },\n }\n}\n\n/** A free-text field. An empty draft clears the field. */\nexport function textField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' ? value : '',\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/**\n * A free-text field the Host treats as a secret and redacts from the read-back\n * (role('secret') in the section schema). The card still edits it like text,\n * but a save never compares the redacted value back and relies on the scope\n * reporting the write landed.\n */\nexport function secretField(field: string): FieldSpec {\n return { ...textField(field), secret: true }\n}\n\n/** A boolean field, edited through true/false draft text. */\nexport function booleanField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'boolean' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return undefined\n },\n }\n}\n\n/** An enumerated string field; only the listed choices are accepted. An empty draft clears the field. */\nexport function choiceField(field: string, choices: readonly string[]): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' && choices.includes(value) ? value : '',\n parse: (text) => {\n if (text === '') return { kind: 'clear' }\n return choices.includes(text) ? { kind: 'set', value: text } : undefined\n },\n }\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n *\n * The Host is the only authority on whether a value was accepted — its\n * validators own the constraints no schema can express — so the outcome is\n * read back from the section rather than predicted here. A save that did not\n * land keeps its drafts, so the user can correct them instead of retyping.\n */\nexport class CardForm<T> {\n private readonly specs: Map<string, FieldSpec>\n private readonly staged = new Map<string, StagedEdit>()\n private readonly listeners = new Set<() => void>()\n /** The scope subscription installed in the constructor; released by dispose(). */\n private readonly disposeScope: () => void\n private disposed = false\n private saving = false\n private failed = false\n private failedReason: string | undefined\n\n /** @param scope - the bound settings scope for this card's namespace. */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: FieldSpec[],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.disposeScope = scope.subscribe(() => { this.publish() })\n }\n\n /**\n * Release the scope subscription and every bound store listener. The card\n * must call this on teardown; later calls are no-ops.\n */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.disposeScope()\n this.listeners.clear()\n }\n\n /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */\n bind<S>(project: () => S): SnapshotStore<S> {\n const store = createSnapshotStore(project())\n this.listeners.add(() => { store.set(project()) })\n return store\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status !== 'loading',\n exposed: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some(item => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n ...this.failedReason === undefined ? {} : { failedReason: this.failedReason },\n }\n }\n\n /** Read one field's state from the effective section and its staged draft. */\n field(field: string): FieldState {\n const spec = this.specOf(field)\n const staged = this.staged.get(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n }\n }\n\n /** The actions the card's slot registration injects. */\n actions(): CardActions {\n return {\n edit: (field, text) => { this.stage(field, { text, clear: false }) },\n resetField: (field) => {\n this.stage(field, { text: this.specOf(field).format(this.baseValue(field)), clear: true })\n },\n save: () => { void this.save() },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.failed = false\n this.failedReason = undefined\n this.publish()\n },\n }\n }\n\n /**\n * Write every staged edit, then re-seed from what the Host accepted.\n *\n * When the scope carries the optional batch surface (the dsh-web-ui\n * bridge scope), every planned write rides one mutation so cross-field\n * validate hooks (baseURL+model) judge the batch as a unit instead of\n * deadlocking on per-field writes. Otherwise the per-field loop runs.\n * A field lands only when the Host reports it held the staged value; a\n * landed field's draft is dropped, a failed one stays staged for the user.\n * @returns settlement after every write and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n const valid = plan.filter(item => item.run !== undefined)\n if (plan.length === 0 || this.saving || valid.length !== plan.length) return\n const plannedWrites = valid.map(item => item.op)\n // Snapshot the fields this save writes, so edits staged while it is in\n // flight survive: only the staged keys this save actually wrote are cleared.\n const fields = new Set(plan.map(item => item.field))\n this.saving = true\n this.failed = false\n this.failedReason = undefined\n this.publish()\n const landed = new Set<string>()\n const batch = this.batchedScope()\n if (batch !== undefined) {\n const result = await batch.mutate(plannedWrites)\n if (result.ok) {\n for (const field of result.fields) {\n if (field.landed) landed.add(field.field)\n }\n } else {\n this.failedReason = result.message\n }\n } else {\n for (const item of valid) {\n if (await item.run!()) landed.add(item.field)\n }\n }\n for (const field of fields) {\n if (landed.has(field)) this.staged.delete(field)\n }\n this.saving = false\n this.failed = landed.size !== fields.size\n this.publish()\n }\n\n /** The scope's batch surface when it supports one; undefined conservatively otherwise. */\n private batchedScope(): BatchedSettingsScope | undefined {\n const candidate = this.scope as unknown as BatchedSettingsScope | undefined\n return typeof candidate?.mutate === 'function' ? candidate : undefined\n }\n\n /**\n * Every staged edit a save would write. An entry whose draft is not a value\n * its field accepts carries no write: the form is still dirty, and the save\n * refuses rather than dropping the edit. A staged edit that matches the\n * effective section is not a write at all.\n * @returns the planned writes, in the order the fields were staged.\n */\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const spec = this.specOf(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, op: { field, op: 'unset' }, run: undefined })\n else if (write.kind === 'clear') plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n else plan.push({ field, op: { field, op: 'set', value: write.value }, run: () => this.store(field, write.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value)\n // A redacted secret never appears in the user layer read-back; judging it\n // by value would misreport a successful secret save as failed. The bridge\n // reports secret writes through its secret-set markers (batch path); on\n // the per-field path the scope resolved, so the write is landed.\n if (this.specOf(field).secret) return true\n return this.userLayer()?.[field] === value\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit)\n this.failed = false\n this.failedReason = undefined\n this.publish()\n }\n\n private specOf(field: string): FieldSpec {\n const spec = this.specs.get(field)\n // Every call site names a field this card declared; a missing one is a\n // wiring mistake that must not degrade into a silently inert control.\n if (spec === undefined) throw new Error(`settings card has no field ${field}`)\n return spec\n }\n\n private snapshotOf(): SettingsScopeSnapshot<T> {\n return this.scope.getSnapshot()\n }\n\n private sectionValue(field: string): unknown {\n return (this.snapshotOf().value as Record<string, unknown> | undefined)?.[field]\n }\n\n private baseValue(field: string): unknown {\n return (this.snapshotOf().base as Record<string, unknown> | undefined)?.[field]\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.snapshotOf().user as Record<string, unknown> | undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.hasOwn(user, field)\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * The filemgr settings card: the total on/off switch (issue #307).\n * Registers into the `web-ui.plugin.item` slot the Web UI Plugins group\n * renders, bound to the `filemgr` settings namespace through the family\n * settings bridge (or the official settings scope when the deployment exposes\n * the namespace directly). Turning the panel off unmounts the right-panel\n * columns, the floating expand button, the /filemgr/* routes and the\n * workspace fs watch + git polling behind them.\n * @module @lijian-ui/dsh-file-manager/client/FileManagerSettingsCard\n */\n\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { PluginSettingsCard, BooleanField } from './PluginSettingsCard.tsx'\nimport { CardForm, booleanField, type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts'\n\n/** The filemgr fields this card edits (the namespace's full schema). */\nexport interface FileManagerPanelSettings {\n /** Whether the right-panel system (columns, floating button, routes, watch/polling) is mounted at all; default on. */\n enabled?: boolean\n}\n\n/** What the filemgr card renders. */\nexport interface FileManagerSettingsCardState extends CardShell {\n enabled: CardFieldState\n}\n\n/** The registration-side face the card's slot entry injects. */\nexport interface FileManagerSettingsCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useFilemgrSettingsCard. */\n filemgrSettingsCard: SnapshotStore<FileManagerSettingsCardState>\n }\n}\n\n/** Bridges the `filemgr` scope onto the card's staged form. */\nexport class FileManagerSettingsCardController {\n private readonly form: CardForm<FileManagerPanelSettings>\n private readonly store: SnapshotStore<FileManagerSettingsCardState>\n\n /** @param scope - the bound settings scope for the `filemgr` namespace. */\n constructor(scope: SettingsScope<FileManagerPanelSettings>) {\n this.form = new CardForm(scope, [\n booleanField('enabled'),\n ])\n this.store = this.form.bind(() => this.projection())\n }\n\n private projection(): FileManagerSettingsCardState {\n return {\n ...this.form.shell(),\n enabled: this.form.field('enabled'),\n }\n }\n\n /**\n * Build the face the card's slot registration injects.\n * @returns the card's snapshot and its form actions.\n */\n inject(): FileManagerSettingsCardFace {\n return { hooks: { filemgrSettingsCard: this.store }, ...this.form.actions() }\n }\n\n /**\n * Release the card's scope subscription and bound stores; the slot\n * disposer calls this on teardown.\n */\n dispose(): void {\n this.form.dispose()\n }\n}\n\n/** Props the renderer binds for the filemgr card. */\nexport type FileManagerSettingsCardProps =\n PropsRuntime<'web-ui.plugin.item'>\n & PropsLocale<'filemgr'>\n & InjectFace<FileManagerSettingsCardFace>\n\n/**\n * Render the filemgr card.\n * @param props - locale copy, the card snapshot, and its form actions.\n * @returns the card.\n */\nexport function FileManagerSettingsCard(props: FileManagerSettingsCardProps) {\n const { t } = props\n const state = props.useFilemgrSettingsCard(snapshot => snapshot)\n const disabled = !state.writable\n const fieldProps = {\n overriddenLabel: t('settings.overridden'),\n resetLabel: t('settings.reset'),\n invalidLabel: t('settings.invalidNumber'),\n disabled,\n }\n return (\n <PluginSettingsCard\n t={t}\n titleKey=\"settings.title\"\n descriptionKey=\"settings.description\"\n state={state}\n onSave={props.save}\n onDiscard={props.discard}\n >\n <BooleanField\n id=\"settings-filemgr-enabled\"\n label={t('settings.enabled')}\n hint={t('settings.enabledHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.enabled}\n onEdit={(text) => { props.edit('enabled', text) }}\n onReset={() => { props.resetField('enabled') }}\n />\n </PluginSettingsCard>\n )\n}\n","/**\n * Framework-free drag machinery shared by the React hook (useResizableSplit)\n * and the DOM layout controller: one pointer-down handler that owns capture,\n * the rAF-flush loop, the e.buttons === 0 fallback, every end path, and the\n * drag styles. Pure DOM — no React, so both callers run the exact same\n * smoothness core (FileManager's useResizableSplit architecture, re-implemented).\n * @module dsh-filemgr/client/drag\n */\n\nexport interface DragStartOptions {\n /** Drag left = grow (handle on the left edge of its container). */\n reverse: boolean\n /** Width at drag start (read at pointer-down time). */\n getStartWidth: () => number\n /** Clamped width from the raw delta (px mode adds deltaX directly). */\n compute: (startWidth: number, deltaX: number) => number\n /** Per-frame flush (rAF-merged; called at most once per frame). */\n onFrame: (width: number) => void\n /** Final commit (also fired on every end path). */\n onEnd: (width: number) => void\n}\n\n/** Whether a pointer event is the primary (left) button or touch. */\nfunction isPrimaryPointer(event: PointerEvent): boolean {\n return event.pointerType === 'touch' || event.button === 0\n}\n\n/**\n * Handle one pointer-down: wire capture + window listeners, run the rAF\n * loop, and end on any of the five termination paths. Call from a\n * onPointerDown handler (React or plain DOM).\n * @param event - the raw pointerdown event.\n * @param el - the handle element (capture target + reverse marker source).\n * @param opts - drag behavior.\n * @returns a disposer (idempotent; also called internally on end).\n */\nexport function handlePointerDragStart(event: PointerEvent, el: HTMLElement, opts: DragStartOptions): () => void {\n if (!isPrimaryPointer(event)) return () => {}\n event.preventDefault()\n\n const startX = event.clientX\n const startWidth = opts.getStartWidth()\n const pointerId = event.pointerId\n const reverse = opts.reverse\n\n let rafId: number | null = null\n let pendingWidth: number | null = null\n let latestWidth = startWidth\n let isDragging = true\n let cleanup: (() => void) | null = null\n\n const flushPending = (): void => {\n if (pendingWidth === null) return\n latestWidth = pendingWidth\n opts.onFrame(pendingWidth)\n }\n\n const addWindowListener = <K extends keyof WindowEventMap>(\n key: K,\n handler: (e: WindowEventMap[K]) => void,\n ): (() => void) => {\n window.addEventListener(key, handler)\n return () => window.removeEventListener(key, handler)\n }\n\n const computeWidth = (clientX: number): number => {\n const deltaX = reverse ? startX - clientX : clientX - startX\n return opts.compute(startWidth, deltaX)\n }\n\n const finishDrag = (e?: PointerEvent | MouseEvent | FocusEvent): void => {\n if (!isDragging) return\n isDragging = false\n if (rafId !== null) {\n cancelAnimationFrame(rafId)\n rafId = null\n }\n flushPending()\n let finalWidth = latestWidth\n if (e !== undefined && 'clientX' in e && typeof e.clientX === 'number') {\n finalWidth = computeWidth(e.clientX)\n }\n opts.onEnd(finalWidth)\n cleanup?.()\n }\n\n const handlePointerMove = (e: PointerEvent): void => {\n if (!isDragging) return\n if (e.buttons === 0) {\n // Lost pointerup (capture steal / release outside): end now.\n finishDrag(e)\n return\n }\n pendingWidth = computeWidth(e.clientX)\n if (rafId === null) {\n rafId = requestAnimationFrame(() => {\n rafId = null\n flushPending()\n })\n }\n }\n const handlePointerUp = (e: PointerEvent): void => finishDrag(e)\n const handlePointerCancel = (e: PointerEvent): void => finishDrag(e)\n const handleMouseUp = (e: MouseEvent): void => finishDrag(e)\n const handleLostCapture = (): void => finishDrag()\n\n // Drag styles: no text selection, col-resize cursor, disable transitions.\n const previousUserSelect = document.body.style.userSelect\n const previousCursor = document.body.style.cursor\n document.body.style.userSelect = 'none'\n document.body.style.cursor = 'col-resize'\n const frame = el.closest('[data-dsh-frame]')\n frame?.setAttribute('data-filemgr-instant', '')\n\n const restore = (): void => {\n document.body.style.userSelect = previousUserSelect\n document.body.style.cursor = previousCursor\n frame?.removeAttribute('data-filemgr-instant')\n }\n\n if (el.setPointerCapture) {\n try {\n el.setPointerCapture(pointerId)\n el.addEventListener('lostpointercapture', handleLostCapture)\n } catch {\n // capture failed; the window listeners cover the drag\n }\n }\n\n const releaseCapture = (): void => {\n try {\n if (el.releasePointerCapture && el.hasPointerCapture?.(pointerId)) {\n el.releasePointerCapture(pointerId)\n }\n } catch {\n // already released\n }\n el.removeEventListener('lostpointercapture', handleLostCapture)\n }\n\n const listeners = [\n addWindowListener('pointermove', handlePointerMove),\n addWindowListener('pointerup', handlePointerUp),\n addWindowListener('pointercancel', handlePointerCancel),\n addWindowListener('mouseup', handleMouseUp),\n addWindowListener('blur', () => finishDrag()),\n ]\n cleanup = () => {\n restore()\n releaseCapture()\n for (const dispose of listeners) dispose()\n }\n return cleanup\n}\n","/**\n * Preview content-type detection from a file name — the router's single\n * source of truth for what a file becomes when opened (mirrors FileManager's\n * getFileTypeInfo table, re-derived for the panel's format set).\n * @module dsh-filemgr/client/fileType\n */\n\nimport type { PreviewContentType } from '../core/types.ts'\n\n/** Markdown extensions. */\nconst MARKDOWN_EXT = new Set(['md', 'markdown', 'mdx'])\n/** HTML extensions. */\nconst HTML_EXT = new Set(['html', 'htm', 'xhtml'])\n/** Diff extensions. */\nconst DIFF_EXT = new Set(['diff', 'patch'])\n/** CSV. */\nconst CSV_EXT = new Set(['csv'])\n/** PDF. */\nconst PDF_EXT = new Set(['pdf'])\n/** Office documents. */\nconst WORD_EXT = new Set(['doc', 'docx', 'odt', 'rtf'])\nconst EXCEL_EXT = new Set(['xls', 'xlsx', 'ods'])\nconst PPT_EXT = new Set(['ppt', 'pptx', 'odp'])\n/** Images. */\nconst IMAGE_EXT = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'ico', 'bmp', 'avif'])\n/** Extensions treated as editable code/text. */\nconst CODE_EXT = new Set([\n 'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'json', 'jsonc', 'css', 'scss', 'less',\n 'yml', 'yaml', 'toml', 'xml', 'sh', 'bash', 'zsh', 'fish', 'rs', 'py', 'go',\n 'java', 'c', 'h', 'cpp', 'hpp', 'cc', 'cs', 'sql', 'php', 'rb', 'swift', 'kt',\n 'vue', 'svelte', 'astro', 'txt', 'log', 'ini', 'env', 'conf', 'cfg', 'gitignore',\n 'dockerfile', 'makefile', 'graphql', 'proto', 'prisma', 'zig', 'lua', 'r', 'dart',\n 'ex', 'exs', 'erl', 'hs', 'clj', 'scala', 'groovy', 'vb', 'ps1', 'bat', 'cmd',\n 'pl', 'pm', 'tcl', 'asm', 's', 'f', 'f90', 'jl', 'nim', 'ml', 'elm', 'purs',\n 'solidity', 'sol', 'tf', 'hcl', 'dockerignore', 'editorconfig', 'prettierrc',\n 'eslintrc', 'babelrc', 'npmrc', 'nix', 'lock', 'map',\n])\n/** No-extension names that are plain text. */\nconst TEXT_NAMES = new Set([\n 'license', 'licence', 'readme', 'changelog', 'contributing', 'authors', 'notice',\n 'makefile', 'dockerfile', 'justfile', 'gemfile', 'rakefile', 'procfile',\n])\n/**\n * Leading-dot config dotfiles whose full (dotted) basename is plain text. The\n * de-dot rule below maps most single-dot files (`.gitignore` -> ext `gitignore`)\n * into CODE_EXT; these multi-suffix / uncommon ones have no useful extension\n * (`.env.local` -> `local`), so we match them by their whole dotted name.\n */\nconst DOTFILE_TEXT_NAMES = new Set([\n '.gitignore', '.gitattributes', '.gitmodules', '.env', '.env.local',\n '.env.production', '.env.development', '.env.test', '.npmrc', '.npmrc.template',\n '.prettierrc', '.prettierrc.json', '.prettierrc.yaml', '.babelrc', '.babelrc.json',\n '.eslintrc', '.eslintrc.json', '.eslintrc.js', '.editorconfig', '.dockerignore',\n '.eslintignore', '.prettierignore', '.gitignore.local', '.hgignore',\n])\n\n/** Detect the preview content type of a file by name (lowercased). */\nexport function detectContentType(name: string): PreviewContentType {\n const base = name.split('/').pop() ?? name\n const lower = base.toLowerCase()\n const dot = lower.lastIndexOf('.')\n // Leading-dot files: the first dot is the hidden-file marker, not a\n // separator — take the text after it (`.gitignore` -> `gitignore`).\n const ext = lower[0] === '.'\n ? (dot > 0 ? lower.slice(dot + 1) : lower.slice(1))\n : (dot > 0 ? lower.slice(dot + 1) : '')\n const stem = dot > 0 ? lower.slice(0, dot) : lower\n if (lower[0] === '.' && DOTFILE_TEXT_NAMES.has(lower)) return 'text'\n if (ext === '' && TEXT_NAMES.has(stem)) return 'text'\n if (ext === '') return 'unsupported'\n if (MARKDOWN_EXT.has(ext)) return 'markdown'\n if (HTML_EXT.has(ext)) return 'html'\n if (DIFF_EXT.has(ext)) return 'diff'\n if (CSV_EXT.has(ext)) return 'csv'\n if (PDF_EXT.has(ext)) return 'pdf'\n if (WORD_EXT.has(ext)) return 'word'\n if (EXCEL_EXT.has(ext)) return 'excel'\n if (PPT_EXT.has(ext)) return 'ppt'\n if (IMAGE_EXT.has(ext)) return 'image'\n if (CODE_EXT.has(ext)) return 'code'\n return 'unsupported'\n}\n\n/** Whether the type can be edited and saved back. */\nexport function isEditableType(type: PreviewContentType): boolean {\n return type === 'markdown' || type === 'html' || type === 'code' || type === 'csv' || type === 'text'\n}\n\n/** Whether the type reads its content as text (vs image data URL). */\nexport function isTextType(type: PreviewContentType): boolean {\n return type !== 'image' && type !== 'pdf' && type !== 'word' && type !== 'excel'\n && type !== 'ppt' && type !== 'unsupported' && type !== 'url'\n}\n\n/** A stable tab id from the file identity (root + path + type). */\nexport function tabIdOf(root: string, path: string, type: PreviewContentType): string {\n return `${root}\\u0000${path}\\u0000${type}`\n}\n\n/** The language hint for code tabs (extension without the dot). */\nexport function languageOf(name: string): string {\n const base = name.split('/').pop() ?? name\n const dot = base.lastIndexOf('.')\n return dot > 0 ? base.slice(dot + 1) : ''\n}\n\n/** The title for a tab: the basename. */\nexport function basenameOf(path: string): string {\n const parts = path.split('/')\n return parts[parts.length - 1] ?? path\n}\n\n/** The parent relative path of a path ('' for a root-level item). */\nexport function parentRel(path: string): string {\n const idx = path.lastIndexOf('/')\n return idx > 0 ? path.slice(0, idx) : ''\n}\n\n/**\n * The streaming URL a pdf tab renders: the host raw route serves the bytes\n * with mime application/pdf, so the preview iframe loads them directly — no\n * base64 round-trip and no read-size cap. The nonce defeats browser caching\n * when the tab is refreshed after the file changed on disk.\n *\n * Contributed by EricWang1358 (#239).\n */\nexport function pdfPreviewUrl(root: string, path: string, nonce: number): string {\n return `/filemgr/raw?root=${encodeURIComponent(root)}&path=${encodeURIComponent(path)}&v=${nonce}`\n}\n","/**\n * Persistence helpers for panel preferences: range-validated reads (invalid\n * stored values fall back to defaults — a broken or hand-edited value must\n * never produce a 0px or NaN panel), debounced writes, and the LRU registry\n * for preview scopes (at most 12 scopes; the oldest savedAt evicts).\n *\n * Keys follow the FileManager contract verbatim:\n * chat-workspace-width-px, chat-preview-width-px, preview-panel-split-ratio,\n * project-panel-collapse:<root>, explorer-ui:<root>, scm-ui:<root>,\n * preview-ui:<root>.\n * @module dsh-filemgr/client/persist\n */\n\n/** Read a stored number, validating it against [min, max]; fallback otherwise. */\nexport function readStoredNumber(key: string, min: number, max: number, fallback: number): number {\n try {\n const raw = localStorage.getItem(key)\n if (raw === null) return fallback\n const value = Number(raw)\n if (!Number.isFinite(value)) return fallback\n if (value < min || value > max) return fallback\n return value\n } catch {\n return fallback\n }\n}\n\n/** Write a number if it differs from the stored value (avoids churn). */\nexport function writeStoredNumber(key: string, value: number): void {\n try {\n const raw = String(Math.round(value))\n if (localStorage.getItem(key) === raw) return\n localStorage.setItem(key, raw)\n } catch {\n // persistence is best-effort; the panel still works\n }\n}\n\n/**\n * A single debounce pipeline used by the stores for its search and persist\n * timers: coalesces rapid schedules into one trailing run (the latest fn wins).\n * `flush` runs the pending fn immediately (pagehide/beforeunload), `dispose`\n * cancels a pending schedule. Behavior is equivalent to the stores' previous\n * hand-rolled setTimeout + clearTimeout pairs, just centralized.\n */\nexport interface Debounced {\n /** Queue a fn; repeated calls before the delay replaces the pending fn. */\n schedule: (fn: () => void) => void\n /** Run the pending fn now and clear the timer. */\n flush: () => void\n /** Cancel the pending fn and timer. */\n dispose: () => void\n}\n\n/** Create one debounced scheduler (default 150ms). */\nexport function createDebounced(delayMs = 150): Debounced {\n let timer: ReturnType<typeof setTimeout> | undefined\n let pending: (() => void) | null = null\n const flush = (): void => {\n if (timer !== undefined) clearTimeout(timer)\n timer = undefined\n const fn = pending\n pending = null\n if (fn !== null) fn()\n }\n return {\n schedule(fn: () => void) {\n pending = fn\n // Reset on every schedule so the run trails the LAST change (the same\n // trailing-edge semantics the stores' former clear+setTimeout had).\n if (timer !== undefined) clearTimeout(timer)\n timer = setTimeout(flush, delayMs)\n },\n flush,\n dispose() {\n if (timer !== undefined) clearTimeout(timer)\n timer = undefined\n pending = null\n },\n }\n}\n\n/** The preview-ui scope registry: keys, savedAt values, eviction. */\nexport const PREVIEW_SCOPE_PREFIX = 'preview-ui:'\n/** LRU cap on distinct preview scopes. */\nexport const PREVIEW_SCOPE_CAP = 12\n\n/**\n * Collect every stored key under a prefix. localStorage has no prefix index,\n * so the whole store is swept once, then filtered to the package's own keys\n * — enumeration is never interleaved with removal (removals would shift the\n * indices mid-loop and skip entries).\n */\nfunction listStoredKeysByPrefix(prefix: string): string[] {\n const keys: string[] = []\n try {\n for (let i = 0; i < localStorage.length; i += 1) {\n const key = localStorage.key(i)\n if (key !== null && key.startsWith(prefix)) keys.push(key)\n }\n } catch {\n return []\n }\n return keys\n}\n\n/**\n * Precisely delete every stored key under a prefix. Only this package's own\n * prefixed keys are removed — foreign-application keys are never touched,\n * replacing the former all-at-once `localStorage.clear()` sweep.\n */\nexport function removeStoredByPrefix(prefix: string): number {\n const keys = listStoredKeysByPrefix(prefix)\n let removed = 0\n for (const key of keys) {\n try {\n localStorage.removeItem(key)\n removed += 1\n } catch {\n // best-effort; a storage failure does not abort the rest\n }\n }\n return removed\n}\n\n/** All stored preview scopes with their savedAt timestamps, oldest first. */\nexport function listPreviewScopes(): Array<{ root: string; savedAt: number }> {\n const out: Array<{ root: string; savedAt: number }> = []\n for (const key of listStoredKeysByPrefix(PREVIEW_SCOPE_PREFIX)) {\n const root = key.slice(PREVIEW_SCOPE_PREFIX.length)\n let savedAt = 0\n try {\n const raw = localStorage.getItem(key)\n if (raw !== null) {\n const parsed = JSON.parse(raw) as { savedAt?: unknown }\n if (typeof parsed.savedAt === 'number') savedAt = parsed.savedAt\n }\n } catch {\n savedAt = 0\n }\n out.push({ root, savedAt })\n }\n out.sort((a, b) => a.savedAt - b.savedAt)\n return out\n}\n\n/** Evict the oldest scopes beyond the cap. */\nexport function evictPreviewScopes(keep: string): void {\n // Cheap pre-check first: enumerate keys only (no JSON.parse, no sort).\n // Writes far below the cap — the common case — return here instead of\n // parsing and sorting every stored preview scope on each persist.\n if (listStoredKeysByPrefix(PREVIEW_SCOPE_PREFIX).length <= PREVIEW_SCOPE_CAP) return\n const scopes = listPreviewScopes().filter((scope) => scope.root !== keep)\n let excess = scopes.length - (PREVIEW_SCOPE_CAP - 1)\n for (const scope of scopes) {\n if (excess <= 0) break\n try {\n localStorage.removeItem(`${PREVIEW_SCOPE_PREFIX}${scope.root}`)\n } catch {\n // best-effort\n }\n excess -= 1\n }\n}\n\n/** Serialize a JSON value with a size guard (quota failures degrade silently). */\nexport function writeJson(key: string, value: unknown): boolean {\n try {\n localStorage.setItem(key, JSON.stringify(value))\n return true\n } catch {\n try {\n localStorage.removeItem(key)\n } catch {\n // storage unavailable entirely\n }\n return false\n }\n}\n\n/** Parse a stored JSON value; fallback on any failure. */\nexport function readJson<T>(key: string, fallback: T): T {\n try {\n const raw = localStorage.getItem(key)\n if (raw === null) return fallback\n const parsed = JSON.parse(raw) as unknown\n // JSON.parse('null') yields null without throwing; descending callers\n // expect an object and would throw on null/primitive, killing their effect.\n if (parsed === null || typeof parsed !== 'object') return fallback\n return parsed as T\n } catch {\n return fallback\n }\n}\n","/**\n * Framework-free state core of the panel system: four small stores (layout,\n * explorer, scm, preview) built on a minimal subscribe/getSnapshot primitive\n * so every decision lives outside React (StrictMode-safe: update reducers are\n * pure; async work — fetches, persistence — runs in the action layer).\n *\n * FileManager's right-panel architecture (Apache-2.0, re-implemented): the width\n * clamps below are the exact ordered pair that keeps the chat area >= 360px\n * at all times (see the research report's section 4.2).\n * @module dsh-filemgr/client/store\n */\n\nimport type { FileRead, FsEntry, GitStatusView, PreviewContentType, SearchHit } from '../core/types.ts'\nimport type { PanelApi } from './api.ts'\nimport { detectContentType, isTextType, pdfPreviewUrl, tabIdOf } from './fileType.ts'\nimport {\n createDebounced, evictPreviewScopes, readJson, readStoredNumber, writeJson, writeStoredNumber,\n} from './persist.ts'\n\n// ─── state primitive ────────────────────────────────────────────────────────\n\n/** Internal channel for the stored-layout flush used by pagehide flushing. */\nconst FLUSH_PERSIST = Symbol('flushPersist')\n\n/** A minimal external store usable with useSyncExternalStore. */\nexport interface StateHandle<S> {\n getSnapshot: () => S\n subscribe: (listener: () => void) => () => void\n /** Pure update: fn receives the previous state and returns the next. */\n update: (fn: (prev: S) => S) => void\n}\n\n/** Create a state handle with an immutable snapshot (new object per update). */\nexport function createState<S>(initial: S): StateHandle<S> {\n let state = initial\n const listeners = new Set<() => void>()\n return {\n getSnapshot: () => state,\n subscribe(listener) {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n },\n update(fn) {\n const next = fn(state)\n if (next === state) return\n state = next\n for (const listener of listeners) listener()\n },\n }\n}\n\n// ─── layout: constants, clamps, store ───────────────────────────────────────\n\n/** Chat-area floor the two clamps guarantee (never below this). */\nexport const MIN_CHAT_PANEL_PX = 360\n/** Preview region width contract. */\nexport const MIN_PREVIEW_PANEL_PX = 340\nexport const DEFAULT_PREVIEW_REGION_PX = 480\nexport const MAX_PREVIEW_REGION_PX = 1200\n/** Explorer (workspace) width contract. */\nexport const MIN_WORKSPACE_PANEL_PX = 220\nexport const MAX_WORKSPACE_PANEL_PX = 500\nexport const DEFAULT_WORKSPACE_PANEL_PX = 260\n/** Preview region horizontal chrome (margins + borders) the clamps subtract. */\nexport const PREVIEW_REGION_CHROME_PX = 24\n\n/** Storage keys (FileManager contract, verbatim). */\nexport const KEY_EXPLORER_WIDTH = 'chat-workspace-width-px'\nexport const KEY_PREVIEW_WIDTH = 'chat-preview-width-px'\nexport const KEY_COLLAPSE = 'project-panel-collapse:'\nexport const KEY_EXPLORER_UI = 'explorer-ui:'\n/** Trailing window for coalescing explorer fs-event refetches (ms). */\nexport const FS_COALESCE_MS = 200\nexport const KEY_SCM_UI = 'scm-ui:'\n\n/**\n * Explorer clamp (runs first): reserve chat's floor plus the preview region\n * (min + chrome) when open, so the explorer never grows into the preview's\n * space; floor at the explorer minimum so a narrow container cannot squeeze\n * it to nothing.\n */\nexport function clampExplorerWidth(requested: number, available: number, previewOpen: boolean): number {\n const reserve = MIN_CHAT_PANEL_PX + (previewOpen ? MIN_PREVIEW_PANEL_PX + PREVIEW_REGION_CHROME_PX : 0)\n const maxByContainer = Math.max(MIN_WORKSPACE_PANEL_PX, available - reserve)\n return Math.min(requested, maxByContainer)\n}\n\n/**\n * Preview clamp (runs after the explorer clamp): reserve chat's floor plus\n * the already-clamped explorer width plus the region chrome. The ordered pair\n * guarantees chat = available - explorer - preview >= 360.\n */\nexport function clampPreviewWidth(requested: number, available: number, explorerWidth: number): number {\n const maxByContainer = Math.max(\n MIN_PREVIEW_PANEL_PX,\n available - MIN_CHAT_PANEL_PX - explorerWidth - PREVIEW_REGION_CHROME_PX,\n )\n return Math.min(requested, maxByContainer)\n}\n\n/** Which panel is maximized (null = normal layout). */\nexport type MaximizeTarget = 'explorer' | 'preview'\n\n/** Layout panel state (project-scoped). */\nexport interface LayoutState {\n /** The project root ('' when no project is bound). */\n root: string\n /** Requested explorer width (persisted; clamped on render). */\n explorerWidth: number\n /** Requested preview width (persisted; clamped on render). */\n previewWidth: number\n /** Explorer collapsed (width 0, kept mounted). */\n explorerCollapsed: boolean\n /** Preview region visible. */\n previewOpen: boolean\n /** Measured available width of the [content | panels] row. */\n availableWidth: number\n /** True while a panel drag is in flight (disables transitions). */\n dragging: boolean\n /**\n * Maximized panel (transient, never persisted): the panel takes over the\n * whole frame row (or the viewport as an overlay on narrow screens) while\n * the other panel, the chat area and the shell side columns hide. Restoring\n * re-applies the stored widths/collapse — nothing else changes.\n */\n maximized: MaximizeTarget | null\n}\n\n/** The layout store plus its pure width math. */\nexport interface LayoutStore extends StateHandle<LayoutState> {\n /** Effective explorer width after the ordered clamp. */\n explorerWidthPx: (state: LayoutState) => number\n /** Effective preview width after the ordered clamp. */\n previewWidthPx: (state: LayoutState) => number\n /** Persist a clamped shrink when the stored width no longer fits. */\n shrinkToFit: (state: LayoutState) => void\n}\n\n/** Storage key of the collapse preference for one root. */\nexport const collapseKey = (root: string): string => `${KEY_COLLAPSE}${root}`\n\n/** Create the layout store (reads persisted widths on init). */\nexport function createLayoutStore(): LayoutStore {\n const handle = createState<LayoutState>({\n root: '',\n explorerWidth: readStoredNumber(KEY_EXPLORER_WIDTH, MIN_WORKSPACE_PANEL_PX, MAX_WORKSPACE_PANEL_PX, DEFAULT_WORKSPACE_PANEL_PX),\n previewWidth: readStoredNumber(KEY_PREVIEW_WIDTH, MIN_PREVIEW_PANEL_PX, MAX_PREVIEW_REGION_PX, DEFAULT_PREVIEW_REGION_PX),\n explorerCollapsed: true,\n previewOpen: false,\n availableWidth: 0,\n dragging: false,\n maximized: null,\n })\n const store: LayoutStore = Object.assign(handle, {\n explorerWidthPx(state: LayoutState): number {\n return state.explorerCollapsed ? 0 : clampExplorerWidth(state.explorerWidth, state.availableWidth, state.previewOpen)\n },\n previewWidthPx(state: LayoutState): number {\n if (!state.previewOpen) return 0\n const explorer = state.explorerCollapsed ? 0 : clampExplorerWidth(state.explorerWidth, state.availableWidth, true)\n return clampPreviewWidth(state.previewWidth, state.availableWidth, explorer)\n },\n shrinkToFit(state: LayoutState): void {\n if (state.availableWidth <= 0) return\n const explorer = clampExplorerWidth(state.explorerWidth, state.availableWidth, state.previewOpen)\n if (state.explorerWidth > explorer && !state.explorerCollapsed) {\n writeStoredNumber(KEY_EXPLORER_WIDTH, explorer)\n handle.update((prev) => ({ ...prev, explorerWidth: explorer }))\n }\n const preview = clampPreviewWidth(state.previewWidth, state.availableWidth, explorer)\n if (state.previewOpen && state.previewWidth > preview) {\n writeStoredNumber(KEY_PREVIEW_WIDTH, preview)\n handle.update((prev) => ({ ...prev, previewWidth: preview }))\n }\n },\n })\n return store\n}\n\n/** Switch the layout to a project root (restores collapse + widths). */\nexport function layoutSetRoot(store: LayoutStore, root: string, previewOpen: boolean): void {\n store.update((prev) => {\n if (prev.root === root && prev.previewOpen === previewOpen) return prev\n let collapsed = prev.explorerCollapsed\n if (prev.root !== root) {\n try {\n collapsed = localStorage.getItem(collapseKey(root)) === 'collapsed'\n } catch {\n collapsed = false\n }\n }\n // Maximize is a transient layout state: it must never leak from one\n // project/session into another (issue #315 acceptance).\n return { ...prev, root, explorerCollapsed: collapsed, previewOpen, maximized: prev.root === root ? prev.maximized : null }\n })\n}\n\n// ─── explorer store ─────────────────────────────────────────────────────────\n\n/** Explorer panel state. */\nexport interface ExplorerState {\n root: string\n /** rel path -> listing cache ('' = root). */\n dirs: Record<string, FsEntry[]>\n /** Expanded dir rel paths (order = display order). */\n expanded: string[]\n /** Selected node rel path (null = none). */\n selected: string | null\n /** Dirs currently fetching. */\n loading: string[]\n /** Active tab: files | changes. */\n activeTab: 'files' | 'changes'\n /** Filename search state. */\n search: {\n query: string\n status: 'idle' | 'searching' | 'done' | 'error'\n hits: SearchHit[]\n truncated: boolean\n }\n /** Bumped on every fs change event (drives refetch + re-render). */\n version: number\n}\n\n/** The explorer store with its async actions. */\nexport interface ExplorerStore extends StateHandle<ExplorerState> {\n setRoot: (root: string) => void\n setActiveTab: (tab: 'files' | 'changes') => void\n toggleDir: (rel: string) => void\n select: (rel: string | null) => void\n reveal: (rel: string) => void\n setSearchQuery: (query: string) => void\n cancelSearch: () => void\n /** Refetch every expanded dir + active search after a host change event. */\n handleFsChange: () => void\n /** Reveal a path in the OS file manager (right-click menu). */\n revealInFileManager: (rel: string) => Promise<boolean>\n /** Open a path with the OS default app (files only, right-click menu). */\n openWithDefaultApp: (rel: string) => Promise<boolean>\n /** Rename a path (newName is a bare name). */\n renameEntry: (rel: string, newName: string) => Promise<boolean>\n /** Create a directory at rel (parent dirs untouched). */\n createDir: (rel: string) => Promise<boolean>\n /** Create an empty file at rel. */\n createFile: (rel: string) => Promise<boolean>\n /** Delete a path (recursive for directories). */\n deleteEntry: (rel: string) => Promise<boolean>\n}\n\n/** Read the persisted explorer UI state for a root (range-guarded). */\nexport function readExplorerUi(root: string): { expanded: string[]; selected: string | null } {\n const stored = readJson<{ expanded?: unknown; selected?: unknown }>(`${KEY_EXPLORER_UI}${root}`, {})\n const expanded = Array.isArray(stored.expanded)\n ? stored.expanded.filter((item): item is string => typeof item === 'string')\n : []\n const selected = typeof stored.selected === 'string' ? stored.selected : null\n return { expanded, selected }\n}\n\nconst EMPTY_SEARCH = { query: '', status: 'idle' as const, hits: [], truncated: false }\n\n/** Create the explorer store (per-root persistence, debounced writes). */\nexport function createExplorerStore(api: PanelApi): ExplorerStore {\n const handle = createState<ExplorerState>({\n root: '',\n dirs: {},\n expanded: [],\n selected: null,\n loading: [],\n activeTab: 'files',\n search: { ...EMPTY_SEARCH },\n version: 0,\n })\n\n const persistDebounced = createDebounced()\n const searchDebounced = createDebounced()\n let fsVersion = 0\n let fsInFlight = false\n let fsScheduled: ReturnType<typeof setTimeout> | undefined\n let persistRoot = ''\n let persistExpanded: string[] = []\n let persistSelected: string | null = null\n // The debounced write (schedulePersist queues this; flushNow runs it now).\n const persistWrite = (): void => {\n if (persistRoot !== '') writeJson(`${KEY_EXPLORER_UI}${persistRoot}`, { expanded: persistExpanded, selected: persistSelected })\n }\n const flushPersist = (): void => { persistDebounced.flush() }\n const schedulePersist = (root: string, expanded: string[], selected: string | null): void => {\n if (root === '') return\n persistRoot = root\n persistExpanded = expanded\n persistSelected = selected\n persistDebounced.schedule(persistWrite)\n }\n\n /** Load one dir's listing into the cache (no-op when already present). */\n const ensureDir = async (root: string, rel: string): Promise<void> => {\n const state = handle.getSnapshot()\n if (state.root !== root || state.dirs[rel] !== undefined || state.loading.includes(rel)) return\n handle.update((prev) => ({ ...prev, loading: [...prev.loading, rel] }))\n const result = await api.list(root, rel)\n handle.update((prev) => {\n if (prev.root !== root) return prev\n // A listing that landed after its dir collapsed must not re-populate\n // the cache (the expand/collapse race would resurrect stale children).\n if (rel !== '' && !prev.expanded.includes(rel)) {\n return { ...prev, loading: prev.loading.filter((item) => item !== rel) }\n }\n const dirs = { ...prev.dirs }\n if (result.ok) dirs[rel] = result.value.entries\n else delete dirs[rel]\n return { ...prev, dirs, loading: prev.loading.filter((item) => item !== rel) }\n })\n }\n\n /** Drop cached subtrees under a collapsed dir (its own key included). */\n const dropSubtree = (dirs: Record<string, FsEntry[]>, rel: string): Record<string, FsEntry[]> => {\n const prefix = rel === '' ? '' : `${rel}/`\n const next: Record<string, FsEntry[]> = {}\n for (const key of Object.keys(dirs)) {\n if (rel !== '' && (key === rel || key.startsWith(prefix))) continue\n next[key] = dirs[key]\n }\n return next\n }\n\n /** A dir's ancestor chain ('' .. parent). */\n const ancestors = (rel: string): string[] => {\n const out: string[] = []\n const parts = rel.split('/').filter(Boolean)\n let acc = ''\n for (const part of parts) {\n acc = acc === '' ? part : `${acc}/${part}`\n out.push(acc)\n }\n return out\n }\n\n /**\n * Refetch the root plus every expanded dir (seq-guarded against stale\n * results) and the active search after an fs change event.\n */\n const runFsRefresh = async (): Promise<void> => {\n const state = handle.getSnapshot()\n const root = state.root\n if (root === '') return\n const dirs = [...new Set(['', ...state.expanded])]\n const seq = ++fsVersion\n const results = await Promise.allSettled(dirs.map((rel) => api.list(root, rel)))\n handle.update((prev) => {\n if (prev.root !== root || seq !== fsVersion) return prev\n const nextDirs = { ...prev.dirs }\n results.forEach((result, index) => {\n const rel = dirs[index]\n if (result.status !== 'fulfilled' || !result.value.ok) return\n // A dir folded while the event burst was in flight must not be\n // re-populated (the collapse would revive from a stale snapshot).\n if (rel !== '' && !prev.expanded.includes(rel)) return\n nextDirs[rel] = result.value.value.entries\n })\n return { ...prev, dirs: nextDirs, version: prev.version + 1 }\n })\n if (state.search.query !== '') {\n void api.search(root, state.search.query).then((result) => {\n handle.update((prev) => {\n if (prev.root !== root || prev.search.query !== state.search.query) return prev\n return {\n ...prev,\n search: result.ok\n ? { query: state.search.query, status: 'done', hits: result.value.hits, truncated: result.value.truncated }\n : prev.search,\n }\n })\n })\n }\n }\n\n const store: ExplorerStore = Object.assign(handle, {\n setRoot(root: string) {\n handle.update((prev) => {\n if (prev.root === root) return prev\n const ui = readExplorerUi(root)\n return {\n ...prev,\n root,\n dirs: {},\n expanded: ui.expanded,\n selected: ui.selected,\n loading: [],\n search: { ...EMPTY_SEARCH },\n }\n })\n void ensureDir(root, '')\n },\n setActiveTab(tab: 'files' | 'changes') {\n handle.update((prev) => (prev.activeTab === tab ? prev : { ...prev, activeTab: tab }))\n },\n toggleDir(rel: string) {\n const state = handle.getSnapshot()\n const isExpanded = state.expanded.includes(rel)\n if (isExpanded) {\n handle.update((prev) => ({\n ...prev,\n expanded: prev.expanded.filter((item) => item !== rel),\n dirs: dropSubtree(prev.dirs, rel),\n }))\n } else {\n handle.update((prev) => ({ ...prev, expanded: [...prev.expanded, rel] }))\n void ensureDir(state.root, rel)\n }\n schedulePersist(state.root, isExpanded ? state.expanded.filter((item) => item !== rel) : [...state.expanded, rel], state.selected)\n },\n select(rel: string | null) {\n handle.update((prev) => (prev.selected === rel ? prev : { ...prev, selected: rel }))\n const state = handle.getSnapshot()\n schedulePersist(state.root, state.expanded, rel)\n },\n reveal(rel: string) {\n const state = handle.getSnapshot()\n const chain = ancestors(rel)\n const missing = chain.filter((item) => !state.expanded.includes(item))\n handle.update((prev) => {\n const expanded = [...prev.expanded]\n for (const item of missing) {\n if (!expanded.includes(item)) expanded.push(item)\n }\n return { ...prev, expanded, selected: rel, search: { ...EMPTY_SEARCH } }\n })\n for (const item of missing) void ensureDir(state.root, item)\n schedulePersist(state.root, [...state.expanded, ...missing], rel)\n },\n setSearchQuery(query: string) {\n const trimmed = query.trim()\n handle.update((prev) => {\n if (trimmed === '' && prev.search.query === '') return prev\n return {\n ...prev,\n search: trimmed === ''\n ? { ...EMPTY_SEARCH }\n : { ...prev.search, query: trimmed, status: 'searching' },\n }\n })\n searchDebounced.dispose()\n if (trimmed === '') return\n const root = handle.getSnapshot().root\n searchDebounced.schedule(() => {\n void api.search(root, trimmed).then((result) => {\n handle.update((prev) => {\n if (prev.root !== root || prev.search.query !== trimmed) return prev\n return {\n ...prev,\n search: result.ok\n ? { query: trimmed, status: 'done', hits: result.value.hits, truncated: result.value.truncated }\n : { ...prev.search, status: 'error', hits: [] },\n }\n })\n })\n })\n },\n cancelSearch() {\n searchDebounced.dispose()\n handle.update((prev) => (prev.search.query === '' ? prev : { ...prev, search: { ...EMPTY_SEARCH } }))\n },\n async revealInFileManager(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '') return false\n const result = await api.reveal(root, rel)\n return result.ok\n },\n async openWithDefaultApp(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '') return false\n const result = await api.openWithDefault(root, rel)\n return result.ok\n },\n async renameEntry(rel: string, newName: string) {\n const root = handle.getSnapshot().root\n if (root === '' || rel === '') return false\n const result = await api.rename(root, rel, newName)\n if (result.ok) {\n // Drop the old subtree, move the selection to the new path, and\n // forget the expansion of the renamed dir (its cache is gone).\n handle.update((prev) => {\n const parent = rel.includes('/') ? rel.slice(0, rel.lastIndexOf('/')) : ''\n const newRel = parent === '' ? newName : `${parent}/${newName}`\n const next: ExplorerState = {\n ...prev,\n dirs: dropSubtree(prev.dirs, rel),\n expanded: prev.expanded.filter((item) => item !== rel),\n }\n if (prev.selected === rel) next.selected = newRel\n return next\n })\n void this.handleFsChange()\n }\n return result.ok\n },\n async createDir(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '') return false\n const result = await api.mkdir(root, rel)\n if (result.ok) {\n // Expand the parent so the new directory shows up immediately.\n const parent = rel.includes('/') ? rel.slice(0, rel.lastIndexOf('/')) : ''\n const state = handle.getSnapshot()\n if (parent !== '' && !state.expanded.includes(parent)) this.toggleDir(parent)\n void this.handleFsChange()\n }\n return result.ok\n },\n async createFile(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '') return false\n const result = await api.newFile(root, rel)\n if (result.ok) {\n // Expand the parent so the new file shows up immediately.\n const parent = rel.includes('/') ? rel.slice(0, rel.lastIndexOf('/')) : ''\n const state = handle.getSnapshot()\n if (parent !== '' && !state.expanded.includes(parent)) this.toggleDir(parent)\n void this.handleFsChange()\n }\n return result.ok\n },\n async deleteEntry(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '' || rel === '') return false\n const result = await api.delete(root, rel)\n if (result.ok) {\n handle.update((prev) => ({\n ...prev,\n selected: prev.selected === rel || prev.selected?.startsWith(rel + '/') ? null : prev.selected,\n dirs: dropSubtree(prev.dirs, rel),\n }))\n void this.handleFsChange()\n }\n return result.ok\n },\n async handleFsChange() {\n const root = handle.getSnapshot().root\n if (root === '') return\n if (fsInFlight) {\n // Collapse a burst of events into one trailing pass: schedule it\n // once, then let the timer re-enter here once it fires.\n if (fsScheduled === undefined) {\n fsScheduled = setTimeout(() => {\n fsScheduled = undefined\n void this.handleFsChange()\n }, FS_COALESCE_MS)\n }\n return\n }\n fsInFlight = true\n try {\n await runFsRefresh()\n } finally {\n fsInFlight = false\n }\n },\n })\n ;(store as unknown as Record<symbol, unknown>)[FLUSH_PERSIST] = flushPersist\n return store\n}\n\n// ─── scm store ──────────────────────────────────────────────────────────────\n\n/** SCM panel state. */\nexport interface ScmState {\n root: string\n /** null: not a git repository (or still loading). */\n status: GitStatusView | null\n /** True when the host reported git is not installed (SSE gitUnavailable). */\n gitMissing: boolean\n loading: boolean\n /** Paths with an action in flight. */\n busy: string[]\n /** Paths the last action reported failed. */\n failed: string[]\n /** list | tree. */\n viewMode: 'list' | 'tree'\n /** Section collapse map (repositories | changes). */\n sectionCollapsed: Record<string, boolean>\n /** Tree-view expanded dir keys. */\n treeExpanded: string[]\n /** Path of the last row opened in the preview panel (null = none). */\n selected: string | null\n}\n\n/** The scm store with its async actions. */\nexport interface ScmStore extends StateHandle<ScmState> {\n setRoot: (root: string) => void\n refresh: () => Promise<void>\n stage: (paths: string[]) => Promise<void>\n unstage: (paths: string[]) => Promise<void>\n discard: (paths: string[]) => Promise<void>\n discardAll: () => Promise<void>\n setViewMode: (mode: 'list' | 'tree') => void\n setSectionCollapsed: (id: string, collapsed: boolean) => void\n setTreeExpanded: (keys: string[]) => void\n setFailed: (paths: string[]) => void\n select: (path: string | null) => void\n}\n\n/** Read the persisted scm UI state for a root (guarded). */\nexport function readScmUi(root: string): { viewMode: 'list' | 'tree'; sectionCollapsed: Record<string, boolean>; treeExpanded: string[]; selected: string | null } {\n const stored = readJson<{ viewMode?: unknown; sectionCollapsed?: unknown; treeExpanded?: unknown; selected?: unknown }>(`${KEY_SCM_UI}${root}`, {})\n const viewMode = stored.viewMode === 'tree' ? 'tree' : 'list'\n const sectionCollapsed: Record<string, boolean> = typeof stored.sectionCollapsed === 'object' && stored.sectionCollapsed !== null\n ? Object.fromEntries(Object.entries(stored.sectionCollapsed as Record<string, unknown>).filter(([, v]) => typeof v === 'boolean')) as Record<string, boolean>\n : {}\n const treeExpanded = Array.isArray(stored.treeExpanded)\n ? stored.treeExpanded.filter((item): item is string => typeof item === 'string')\n : []\n const selected = typeof stored.selected === 'string' ? stored.selected : null\n return { viewMode, sectionCollapsed, treeExpanded, selected }\n}\n\n/** Create the scm store (host status is the only truth — no optimistic rows). */\nexport function createScmStore(api: PanelApi): ScmStore {\n const handle = createState<ScmState>({\n root: '',\n status: null,\n gitMissing: false,\n loading: false,\n busy: [],\n failed: [],\n viewMode: 'list',\n sectionCollapsed: {},\n treeExpanded: [],\n selected: null,\n })\n\n const persistDebounced = createDebounced()\n let persistState: ScmState | null = null\n let loadSeq = 0\n const persistWrite = (): void => {\n if (persistState !== null && persistState.root !== '') {\n writeJson(`${KEY_SCM_UI}${persistState.root}`, {\n viewMode: persistState.viewMode,\n sectionCollapsed: persistState.sectionCollapsed,\n treeExpanded: persistState.treeExpanded,\n selected: persistState.selected,\n })\n }\n }\n const flushPersist = (): void => { persistDebounced.flush() }\n const schedulePersist = (state: ScmState): void => {\n if (state.root === '') return\n persistState = state\n persistDebounced.schedule(persistWrite)\n }\n\n /** Fetch the status and land it (guarded against root switches + out-of-order). */\n const load = async (root: string, keepBusy: string[] = []): Promise<void> => {\n const seq = ++loadSeq\n handle.update((prev) => ({ ...prev, loading: true }))\n const result = await api.gitStatus(root)\n handle.update((prev) => {\n // Only the newest in-flight load may land; a stale response must not\n // overwrite fresher state (focus refresh vs SSE push race).\n if (prev.root !== root || seq !== loadSeq) return prev\n return {\n ...prev,\n status: result.ok ? result.value : prev.status,\n // A real repo view clears the missing-git banner; null keeps it.\n gitMissing: result.ok && result.value !== null ? false : prev.gitMissing,\n loading: false,\n busy: keepBusy,\n }\n })\n }\n\n const store: ScmStore = Object.assign(handle, {\n setRoot(root: string) {\n handle.update((prev) => {\n if (prev.root === root) return prev\n const ui = readScmUi(root)\n return {\n ...prev,\n root,\n status: null,\n gitMissing: false,\n loading: true,\n busy: [],\n failed: [],\n viewMode: ui.viewMode,\n sectionCollapsed: ui.sectionCollapsed,\n treeExpanded: ui.treeExpanded,\n selected: ui.selected,\n }\n })\n void load(root)\n },\n async refresh() {\n const root = handle.getSnapshot().root\n if (root !== '') await load(root)\n },\n async stage(paths: string[]) {\n const root = handle.getSnapshot().root\n if (root === '' || paths.length === 0) return\n handle.update((prev) => ({ ...prev, busy: [...prev.busy, ...paths] }))\n const result = await api.gitStage(root, paths)\n handle.update((prev) => ({\n ...prev,\n failed: result.ok && Array.isArray(result.value?.failed) ? result.value.failed : (result.ok ? [] : paths),\n busy: prev.busy.filter((item) => !paths.includes(item)),\n }))\n await load(root)\n },\n async unstage(paths: string[]) {\n const root = handle.getSnapshot().root\n if (root === '' || paths.length === 0) return\n handle.update((prev) => ({ ...prev, busy: [...prev.busy, ...paths] }))\n const result = await api.gitUnstage(root, paths)\n handle.update((prev) => ({\n ...prev,\n failed: result.ok && Array.isArray(result.value?.failed) ? result.value.failed : (result.ok ? [] : paths),\n busy: prev.busy.filter((item) => !paths.includes(item)),\n }))\n await load(root)\n },\n async discard(paths: string[]) {\n const root = handle.getSnapshot().root\n if (root === '' || paths.length === 0) return\n handle.update((prev) => ({ ...prev, busy: [...prev.busy, ...paths] }))\n const result = await api.gitDiscard(root, paths)\n handle.update((prev) => ({\n ...prev,\n failed: result.ok && Array.isArray(result.value?.failed) ? result.value.failed : (result.ok ? [] : paths),\n busy: prev.busy.filter((item) => !paths.includes(item)),\n }))\n await load(root)\n },\n async discardAll() {\n const state = handle.getSnapshot()\n const paths = [\n ...(state.status?.unstaged ?? []),\n ...(state.status?.untracked ?? []),\n ].map((row) => row.path)\n await this.discard(paths)\n },\n setViewMode(mode: 'list' | 'tree') {\n handle.update((prev) => (prev.viewMode === mode ? prev : { ...prev, viewMode: mode }))\n schedulePersist(handle.getSnapshot())\n },\n setSectionCollapsed(id: string, collapsed: boolean) {\n handle.update((prev) => ({ ...prev, sectionCollapsed: { ...prev.sectionCollapsed, [id]: collapsed } }))\n schedulePersist(handle.getSnapshot())\n },\n setTreeExpanded(keys: string[]) {\n handle.update((prev) => ({ ...prev, treeExpanded: keys }))\n schedulePersist(handle.getSnapshot())\n },\n setFailed(paths: string[]) {\n handle.update((prev) => ({ ...prev, failed: paths }))\n },\n select(path: string | null) {\n handle.update((prev) => (prev.selected === path ? prev : { ...prev, selected: path }))\n schedulePersist(handle.getSnapshot())\n },\n })\n ;(store as unknown as Record<symbol, unknown>)[FLUSH_PERSIST] = flushPersist\n return store\n}\n\n// ─── preview store ──────────────────────────────────────────────────────────\n\n/** One preview tab. */\nexport interface PreviewTabState {\n id: string\n title: string\n root: string\n path: string\n contentType: PreviewContentType\n /** Diff tabs (opened from the SCM panel): content is the path's git diff. */\n diff?: { staged: boolean }\n /** URL tabs: bumped by reloadTab to re-navigate the preview frame. */\n reloadNonce?: number\n /** null: content not loaded yet. */\n content: string | null\n /** Image dimensions for image tabs. */\n image?: { width: number; height: number }\n dirty: boolean\n /** mtime the loaded/saved content is based on (write-conflict base). */\n mtime?: number\n /** Disk is newer than the loaded content (refresh affordance). */\n updated: boolean\n loading: boolean\n truncated: boolean\n error: string | null\n savedAt: number\n}\n\n/** Preview panel state. */\nexport interface PreviewState {\n root: string\n open: boolean\n tabs: PreviewTabState[]\n activeTabId: string | null\n /** Bumped on every fs change event (drives staleness checks). */\n version: number\n}\n\n/** The preview store with its async actions. */\nexport interface PreviewStore extends StateHandle<PreviewState> {\n setRoot: (root: string) => void\n openFile: (root: string, path: string) => void\n openDiff: (root: string, path: string, staged: boolean) => void\n switchTab: (id: string) => void\n closeTabs: (ids: string[]) => void\n updateContent: (id: string, content: string) => void\n saveTab: (id: string) => Promise<void>\n reloadTab: (id: string) => Promise<void>\n setOpen: (open: boolean) => void\n handleFsChange: () => void\n handleGitChange: (root: string) => void\n}\n\n/** Persisted tab meta (content is re-fetched on restore). */\ninterface PersistedTab {\n id: string\n title: string\n root: string\n path: string\n contentType: PreviewContentType\n diff?: { staged: boolean }\n savedAt: number\n}\n\n/** Read persisted tabs for a root (guarded, content-less). */\nexport function readPreviewTabs(root: string): PersistedTab[] {\n const stored = readJson<{ savedAt?: unknown; tabs?: unknown }>(`preview-ui:${root}`, {})\n if (!Array.isArray(stored.tabs)) return []\n const out: PersistedTab[] = []\n for (const item of stored.tabs) {\n if (typeof item !== 'object' || item === null) continue\n const record = item as Record<string, unknown>\n if (typeof record.id !== 'string' || typeof record.path !== 'string') continue\n const rawDiff = record.diff\n const diff = typeof rawDiff === 'object' && rawDiff !== null\n && typeof (rawDiff as Record<string, unknown>).staged === 'boolean'\n ? { staged: (rawDiff as { staged: boolean }).staged }\n : undefined\n out.push({\n id: record.id,\n title: typeof record.title === 'string' ? record.title : record.path,\n root: typeof record.root === 'string' ? record.root : root,\n path: record.path,\n contentType: typeof record.contentType === 'string' ? record.contentType as PreviewContentType : 'text',\n diff,\n savedAt: typeof record.savedAt === 'number' ? record.savedAt : 0,\n })\n }\n return out\n}\n\n/** Create the preview store (per-root tab persistence with LRU scopes). */\nexport function createPreviewStore(api: PanelApi): PreviewStore {\n const handle = createState<PreviewState>({\n root: '',\n open: false,\n tabs: [],\n activeTabId: null,\n version: 0,\n })\n\n // handleFsChange single-flight + trailing coalesce (see its guard).\n let previewFsInFlight = false\n let previewFsScheduled: ReturnType<typeof setTimeout> | undefined\n\n const persistDebounced = createDebounced()\n const persistWrite = (): void => {\n const current = handle.getSnapshot()\n if (current.root === '') return\n const meta: PersistedTab[] = current.tabs.map((tab) => ({\n id: tab.id,\n title: tab.title,\n root: tab.root,\n path: tab.path,\n contentType: tab.contentType,\n diff: tab.diff,\n savedAt: tab.savedAt,\n }))\n writeJson(`preview-ui:${current.root}`, { savedAt: Date.now(), tabs: meta })\n evictPreviewScopes(current.root)\n }\n const flushPersist = (): void => { persistDebounced.flush() }\n const schedulePersist = (state: PreviewState): void => {\n if (state.root === '') return\n persistDebounced.schedule(persistWrite)\n }\n\n /** Load content for one tab (text or image data URL, or git diff). */\n const loadContent = async (root: string, id: string): Promise<void> => {\n const tab = handle.getSnapshot().tabs.find((item) => item.id === id)\n if (tab === undefined || tab.content !== null || tab.loading) return\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id ? { ...item, loading: true, error: null } : item)),\n }))\n // Pdf tabs never fetch through /read: the raw route streams the bytes\n // straight into the preview iframe, so the tab content is the route URL.\n if (tab.contentType === 'pdf') {\n handle.update((prev) => {\n if (prev.root !== root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id\n ? { ...item, loading: false, content: pdfPreviewUrl(root, item.path, Date.now()), updated: false }\n : item)),\n }\n })\n return\n }\n const asImage = tab.contentType === 'image'\n const result = tab.diff !== undefined\n ? await api.gitDiff(root, tab.path, tab.diff.staged)\n : await api.read(root, tab.path, asImage)\n handle.update((prev) => {\n if (prev.root !== root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => {\n if (item.id !== id) return item\n if (!result.ok) {\n return { ...item, loading: false, error: result.error.message }\n }\n // The user started typing while the fetch was in flight: their newer\n // content must not be overwritten by this (already stale) disk read.\n if (item.dirty) return { ...item, loading: false }\n // read and gitDiff share the content field; only read carries the\n // rest (image/mtime/truncated), so the union is read as its merge.\n const loaded = result.value as { content: string; image?: FileRead['image']; mtime?: number; truncated?: boolean }\n return {\n ...item,\n loading: false,\n content: loaded.content,\n image: loaded.image,\n mtime: loaded.mtime,\n truncated: loaded.truncated ?? false,\n updated: false,\n }\n }),\n }\n })\n }\n\n /** Touch a tab's savedAt (LRU order within the scope). */\n const touch = (id: string): void => {\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id ? { ...item, savedAt: Date.now() } : item)),\n }))\n }\n\n /**\n * Re-fetch every loaded diff tab of the root in place (fs/git change\n * events). In-flight or not-yet-loaded tabs are skipped — the next load or\n * event covers them; landing guards keep a newer edit from being clobbered.\n */\n const refreshDiffs = async (root: string): Promise<void> => {\n if (handle.getSnapshot().root !== root) return\n const diffs = handle.getSnapshot().tabs\n .filter((tab): tab is PreviewTabState & { diff: { staged: boolean } } => tab.diff !== undefined)\n await Promise.all(diffs.map(async (tab) => {\n if (tab.content === null || tab.loading) return\n const result = await api.gitDiff(root, tab.path, tab.diff.staged)\n handle.update((prev) => {\n if (prev.root !== root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => {\n if (item.id !== tab.id || !result.ok) return item\n if (item.dirty || item.loading) return item\n return { ...item, content: result.value.content, error: null }\n }),\n }\n })\n }))\n }\n\n const store: PreviewStore = Object.assign(handle, {\n setRoot(root: string) {\n handle.update((prev) => {\n if (prev.root === root) return prev\n const persisted = readPreviewTabs(root)\n const tabs: PreviewTabState[] = persisted.map((meta) => ({\n id: meta.id,\n title: meta.title,\n root: meta.root,\n path: meta.path,\n contentType: meta.contentType,\n diff: meta.diff,\n content: null,\n dirty: false,\n updated: false,\n loading: false,\n truncated: false,\n error: null,\n savedAt: meta.savedAt,\n }))\n const activeTabId = tabs.length > 0 ? tabs[tabs.length - 1].id : null\n return { ...prev, root, tabs, activeTabId, open: tabs.length > 0 }\n })\n const state = handle.getSnapshot()\n if (state.activeTabId !== null) void loadContent(root, state.activeTabId)\n },\n openFile(root: string, path: string) {\n const type = detectContentType(path)\n const id = tabIdOf(root, path, type)\n const existing = handle.getSnapshot().tabs.find((tab) => tab.id === id)\n if (existing !== undefined) {\n handle.update((prev) => ({\n ...prev,\n root,\n open: true,\n activeTabId: id,\n tabs: prev.tabs.map((tab) => (tab.id === id ? { ...tab, savedAt: Date.now() } : tab)),\n }))\n void loadContent(root, id)\n schedulePersist(handle.getSnapshot())\n return\n }\n handle.update((prev) => {\n if (prev.root !== root) return prev\n const tab: PreviewTabState = {\n id,\n title: path.split('/').pop() ?? path,\n root,\n path,\n contentType: type,\n content: null,\n dirty: false,\n updated: false,\n loading: false,\n truncated: false,\n error: null,\n savedAt: Date.now(),\n }\n return { ...prev, open: true, tabs: [...prev.tabs, tab], activeTabId: id }\n })\n void loadContent(root, id)\n schedulePersist(handle.getSnapshot())\n },\n openDiff(root: string, path: string, staged: boolean) {\n // A distinct id space (scm-diff: side + root + path) so the same file\n // can carry a diff tab AND a file tab, and staged/unstaged diffs of one\n // path are separate tabs — each reflects the side it was opened from.\n const id = `scm-diff:${staged ? 's' : 'u'}\\u0000${root}\\u0000${path}`\n const existing = handle.getSnapshot().tabs.find((tab) => tab.id === id)\n if (existing !== undefined) {\n handle.update((prev) => ({\n ...prev,\n root,\n open: true,\n activeTabId: id,\n tabs: prev.tabs.map((tab) => (tab.id === id ? { ...tab, savedAt: Date.now() } : tab)),\n }))\n void loadContent(root, id)\n schedulePersist(handle.getSnapshot())\n return\n }\n handle.update((prev) => {\n if (prev.root !== root) return prev\n const tab: PreviewTabState = {\n id,\n title: path.split('/').pop() ?? path,\n root,\n path,\n contentType: 'diff',\n diff: { staged },\n content: null,\n dirty: false,\n updated: false,\n loading: false,\n truncated: false,\n error: null,\n savedAt: Date.now(),\n }\n return { ...prev, open: true, tabs: [...prev.tabs, tab], activeTabId: id }\n })\n void loadContent(root, id)\n schedulePersist(handle.getSnapshot())\n },\n switchTab(id: string) {\n const state = handle.getSnapshot()\n if (state.activeTabId === id) return\n handle.update((prev) => ({ ...prev, activeTabId: id }))\n touch(id)\n const tab = handle.getSnapshot().tabs.find((item) => item.id === id)\n if (tab !== undefined && tab.content === null) void loadContent(state.root, id)\n schedulePersist(handle.getSnapshot())\n },\n closeTabs(ids: string[]) {\n const state = handle.getSnapshot()\n const remaining = state.tabs.filter((tab) => !ids.includes(tab.id))\n const active = remaining.some((tab) => tab.id === state.activeTabId)\n const activeTabId = active\n ? state.activeTabId\n : remaining.length > 0\n ? remaining[Math.min(state.tabs.findIndex((tab) => tab.id === state.activeTabId), remaining.length - 1)]?.id ?? remaining[remaining.length - 1].id\n : null\n handle.update((prev) => ({\n ...prev,\n tabs: remaining,\n activeTabId,\n open: remaining.length > 0 ? prev.open : false,\n }))\n schedulePersist(handle.getSnapshot())\n },\n updateContent(id: string, content: string) {\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((tab) => (tab.id === id ? { ...tab, content, dirty: true, updated: false } : tab)),\n }))\n },\n async saveTab(id: string) {\n const state = handle.getSnapshot()\n const tab = state.tabs.find((item) => item.id === id)\n if (tab === undefined || tab.content === null || !isTextType(tab.contentType) || tab.diff !== undefined) return\n const sentContent = tab.content\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id ? { ...item, loading: true, error: null } : item)),\n }))\n const result = await api.write(state.root, tab.path, tab.content, tab.mtime)\n handle.update((prev) => {\n if (prev.root !== state.root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => {\n if (item.id !== id) return item\n if (!result.ok) {\n return {\n ...item,\n loading: false,\n error: result.error.code === 'write-conflict'\n ? '文件已在磁盘上被修改,保存冲突:请刷新后重试'\n : result.error.message,\n }\n }\n if (item.content !== sentContent) {\n // The user kept typing while the save was in flight: the disk now\n // holds the sent snapshot, but the tab's newer edits are unsaved.\n // Refresh the write base so the next save is conflict-safe and\n // keep the dirty flag so the UI still shows an unsaved edit.\n return { ...item, loading: false, mtime: result.value.mtime, error: null }\n }\n return { ...item, loading: false, dirty: false, mtime: result.value.mtime, error: null }\n }),\n }\n })\n },\n async reloadTab(id: string) {\n const state = handle.getSnapshot()\n const tab = state.tabs.find((item) => item.id === id)\n if (tab === undefined) return\n if (tab.contentType === 'url') {\n // URL tabs own a live document inside the frame; reload bumps the\n // nonce so UrlViewer re-navigates the frame to its address.\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) =>\n item.id === id ? { ...item, reloadNonce: (item.reloadNonce ?? 0) + 1 } : item,\n ),\n }))\n return\n }\n if (tab.contentType === 'pdf') {\n // Streamed tab: re-point the iframe at the raw route with a fresh\n // nonce so the browser re-fetches the bytes (no /read round-trip).\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id\n ? { ...item, content: pdfPreviewUrl(state.root, item.path, Date.now()), updated: false, error: null }\n : item)),\n }))\n return\n }\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id ? { ...item, loading: true } : item)),\n }))\n const result = tab.diff !== undefined\n ? await api.gitDiff(state.root, tab.path, tab.diff.staged)\n : await api.read(state.root, tab.path, tab.contentType === 'image')\n handle.update((prev) => {\n if (prev.root !== state.root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => {\n if (item.id !== id) return item\n if (!result.ok) return { ...item, loading: false, error: result.error.message }\n const loaded = result.value as { content: string; image?: FileRead['image']; mtime?: number; truncated?: boolean }\n return {\n ...item,\n loading: false,\n content: loaded.content,\n image: loaded.image,\n mtime: loaded.mtime,\n truncated: loaded.truncated ?? false,\n updated: false,\n dirty: false,\n error: null,\n }\n }),\n }\n })\n },\n setOpen(open: boolean) {\n handle.update((prev) => (prev.open === open ? prev : { ...prev, open }))\n },\n async handleFsChange() {\n const state = handle.getSnapshot()\n if (state.root === '') return\n if (previewFsInFlight) {\n // Collapse a burst of fs events into one trailing pass: each refresh\n // respawns git per diff tab and re-reads the active file, so a write\n // storm must not queue one full round per event.\n if (previewFsScheduled === undefined) {\n previewFsScheduled = setTimeout(() => {\n previewFsScheduled = undefined\n void this.handleFsChange()\n }, FS_COALESCE_MS)\n }\n return\n }\n previewFsInFlight = true\n try {\n handle.update((prev) => ({ ...prev, version: prev.version + 1 }))\n // Diff tabs are derived views: any fs change may alter them, so refresh\n // them in place (never mark \"updated\" — the refresh is automatic).\n await refreshDiffs(state.root)\n // Staleness probe for the ACTIVE file tab only (cheap; the fs watcher\n // debounces bursts). A newer disk mtime flips the tab to \"updated\".\n const active = handle.getSnapshot().tabs.find((tab) => tab.id === handle.getSnapshot().activeTabId)\n if (active === undefined || active.content === null || active.dirty || active.diff !== undefined || !isTextType(active.contentType)) return\n const result = await api.read(state.root, active.path, false)\n handle.update((prev) => {\n if (prev.root !== state.root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((tab) => {\n if (tab.id !== active.id || tab.dirty) return tab\n if (!result.ok) return tab\n return { ...tab, updated: tab.mtime !== undefined && result.value.mtime > tab.mtime + 1 }\n }),\n }\n })\n } finally {\n previewFsInFlight = false\n }\n },\n async handleGitChange(root: string) {\n // A git push means the index/worktree moved (stage/unstage/discard or\n // external git): every open diff tab is stale by definition.\n await refreshDiffs(root)\n },\n })\n ;(store as unknown as Record<symbol, unknown>)[FLUSH_PERSIST] = flushPersist\n return store\n}\n\n/** Convenience bundle: the four stores wired to one api. */\nexport interface PanelStores {\n layout: LayoutStore\n explorer: ExplorerStore\n scm: ScmStore\n preview: PreviewStore\n}\n\n/** PanelStores plus a pagehide flush hook. */\nexport interface PanelStoresWithFlush extends PanelStores {\n /** Flush every pending debounced persist immediately (pagehide/beforeunload). */\n flushNow: () => void\n}\n\n/** Create the full store bundle. */\nexport function createPanelStores(api: PanelApi): PanelStoresWithFlush {\n const layout = createLayoutStore()\n const explorer = createExplorerStore(api)\n const scm = createScmStore(api)\n const preview = createPreviewStore(api)\n const flushNow = (): void => {\n for (const store of [explorer, scm, preview]) {\n const flush = (store as unknown as Record<symbol, unknown>)[FLUSH_PERSIST]\n if (typeof flush === 'function') (flush as () => void)()\n }\n }\n const stores: PanelStoresWithFlush = { layout, explorer, scm, preview, flushNow }\n return stores\n}\n","/**\n * Maximize-mode geometry (issue #315): when a panel is maximized the layout\n * controller rewrites the frame grid so the target column takes the whole\n * row (sidebar, details, chat and the other panel collapse to 0px tracks —\n * everything stays mounted, nothing unmounts). On narrow viewports the\n * maximized column instead leaves the grid and renders as a fixed\n * full-screen overlay (mobile-friendly full-screen mode), so the shell's\n * own narrow layout stays untouched behind it.\n * @module dsh-filemgr/client/maximize\n */\n\nimport type { MaximizeTarget } from './store.ts'\n\n/** Below this available row width the maximized panel renders as a fixed\n * full-screen overlay instead of a grid takeover. */\nexport const MAXIMIZE_OVERLAY_BREAKPOINT_PX = 640\n\n/**\n * The five grid tracks while one panel is maximized: shell sidebar, chat,\n * shell details and the other panel all collapse to 0px; the target column\n * takes the whole measured frame width. Tracks are the same string shape the\n * shell's own inline style uses (px + fr), so nothing else needs to change.\n */\nexport function maximizedGridTracks(target: MaximizeTarget, frameWidth: number): string {\n const wide = `${Math.max(0, Math.round(frameWidth))}px`\n return target === 'explorer'\n ? `0px 0px 0px 0px ${wide}`\n : `0px 0px 0px ${wide} 0px`\n}\n\n/** Whether the maximized panel should render as a fixed full-screen overlay. */\nexport function maximizedOverlay(availableWidth: number): boolean {\n return availableWidth > 0 && availableWidth < MAXIMIZE_OVERLAY_BREAKPOINT_PX\n}\n","/**\n * Floating expand button geometry (issues #374 / #292): the button is a\n * fixed chrome element docked at the viewport's top-right corner, just\n * below the shell conversation header — the horizontal divider under the\n * \"Session log\" row — so the re-expand control sits below the header\n * chrome instead of overlapping it. Its top stays below the Window\n * Controls Overlay titlebar strip when dsh-desktop reports one (issue\n * #292). Every computed position is clamped into the usable range.\n * @module dsh-filemgr/client/floating\n */\n\n/** Breathing room above/below the button (px). */\nexport const FLOATING_MARGIN_PX = 6\n/** Gap between the shell header's bottom divider and the button top (px). */\nexport const FLOATING_HEADER_GAP_PX = 8\n/** The button's rendered size (kept in sync with tokens.module.css). */\nexport const FLOATING_BUTTON_HEIGHT_PX = 24\n/** Top offset of the explorer's collapse chevron inside its tab bar (px).\n * Used only as a fallback when the shell conversation header is not found\n * (kept in sync with the chevron rule in tokens.module.css). */\nexport const COLLAPSE_CHEVRON_TOP_PX = 6\n\n/** Minimal Window Controls Overlay surface (untyped in older TS DOM libs). */\ninterface WindowControlsOverlayLike {\n visible: boolean\n getTitlebarAreaRect?: () => { height?: number }\n}\n\n/** The WCO titlebar height when visible; 0 in a plain browser tab. */\nexport function titlebarAreaHeight(): number {\n const wco = (navigator as Navigator & { windowControlsOverlay?: WindowControlsOverlayLike }).windowControlsOverlay\n if (wco === undefined || !wco.visible || wco.getTitlebarAreaRect === undefined) return 0\n try {\n const rect = wco.getTitlebarAreaRect()\n const height = rect?.height ?? 0\n return height > 0 ? Math.round(height) : 0\n } catch {\n return 0\n }\n}\n\n/** Clamp a requested top px into the usable vertical range. */\nexport function clampFloatingTop(\n top: number,\n viewportHeight: number,\n buttonHeight: number,\n titlebar: number,\n): number {\n const min = titlebar + FLOATING_MARGIN_PX\n const max = Math.max(min, viewportHeight - buttonHeight - FLOATING_MARGIN_PX)\n if (!Number.isFinite(top)) return min\n return Math.min(max, Math.max(min, top))\n}\n\n/** The default top: aligned with the collapse chevron at the top-right. */\nexport function topAlignedFloatingTop(viewportHeight: number, buttonHeight: number, titlebar: number): number {\n return clampFloatingTop(\n titlebar + COLLAPSE_CHEVRON_TOP_PX,\n viewportHeight,\n buttonHeight,\n titlebar,\n )\n}\n","/**\n * The DOM layout controller: extends the web shell's three-column frame\n * (`[data-dsh-frame]`, a grid) with two trailing grid tracks — the preview\n * region and the explorer column — by mirroring the shell's own inline\n * grid-template-columns string and re-appending the two panel tracks on every\n * shell update (MutationObserver, same frame before paint). Also owns the\n * absolute drag handles (12px explorer / 20px preview hit zones), the\n * floating expand button (docked at the top-right corner, just below the\n * shell header's divider — issues #374 / #292), the collapse-as-width-0\n * keep-mounted behavior, and the transient\n * maximize mode (issue #315): while a panel is maximized the target column\n * takes over the whole frame row (or renders as a fixed full-screen overlay\n * on narrow viewports), and Esc / the header button restore the layout.\n *\n * The shell's inline style is the source of truth for the sidebar and details\n * tracks; this controller never guesses their widths. Handles are out-of-flow\n * (absolute), so appending tracks never disturbs the shell's own children.\n *\n * FileManager Layout architecture (Apache-2.0, re-implemented): the explorer\n * column collapses to width 0 while staying mounted; the preview region keeps\n * a 1px left border only (no outer margins — gaps would expose the window\n * background, jarring in dark mode).\n * @module dsh-filemgr/client/layout\n */\n\nimport { handlePointerDragStart } from './drag.ts'\nimport {\n DEFAULT_PREVIEW_REGION_PX, DEFAULT_WORKSPACE_PANEL_PX,\n MAX_PREVIEW_REGION_PX, MAX_WORKSPACE_PANEL_PX,\n MIN_PREVIEW_PANEL_PX, MIN_WORKSPACE_PANEL_PX,\n KEY_EXPLORER_WIDTH, KEY_PREVIEW_WIDTH,\n clampExplorerWidth, clampPreviewWidth,\n type MaximizeTarget,\n} from './store.ts'\nimport { writeStoredNumber } from './persist.ts'\nimport { maximizedGridTracks, maximizedOverlay } from './maximize.ts'\nimport {\n FLOATING_BUTTON_HEIGHT_PX, FLOATING_HEADER_GAP_PX,\n clampFloatingTop, titlebarAreaHeight, topAlignedFloatingTop,\n} from './floating.ts'\nimport type { LayoutStore } from './store.ts'\n\n/** The frame grid element (portals target it). */\nlet frameElement: HTMLElement | null = null\n\n/** Read the current frame element (undefined while the shell is not mounted). */\nexport function getFrameElement(): HTMLElement | null {\n return frameElement\n}\n\n/**\n * Locate the frame grid element the two panel columns append into. The web-ui\n * aggregate's compat shim stamps `data-dsh-frame` onto the grid, but a\n * STANDALONE install of this package has no shim (the attribute never\n * appears), so the panel would wait forever and never mount (issue #56). Fall\n * back to the rc.6-native structure: the frame grid is the parent of the\n * sidebar column, exactly the element the shim would stamp.\n */\nfunction findFrame(): HTMLElement | null {\n const stamped = document.querySelector<HTMLElement>('[data-dsh-frame]')\n if (stamped !== null) return stamped\n return document.querySelector<HTMLElement>('[class*=\"sidebarCol\"]')?.parentElement ?? null\n}\n\n/**\n * Parse an inline grid-template-columns string into its tracks. Handles\n * \"minmax(0, 1fr)\" (spaces inside parens must not split). Empty on failure.\n */\nexport function parseGridTracks(input: string): string[] {\n const tracks: string[] = []\n let depth = 0\n let current = ''\n for (const char of input) {\n if (char === '(') depth += 1\n if (char === ')') depth = Math.max(0, depth - 1)\n if (char === ' ' && depth === 0) {\n if (current !== '') {\n tracks.push(current)\n current = ''\n }\n continue\n }\n current += char\n }\n if (current !== '') tracks.push(current)\n return tracks\n}\n\n/** Extract a px width from one track (0 for fr/minmax/non-px tracks). */\nexport function trackPx(track: string): number {\n const match = /^(-?[\\d.]+)px$/.exec(track.trim())\n return match === null ? 0 : Number(match[1])\n}\n\n/** One drag handle's geometry (hit zone + visual line) — pure CSS in the module. */\nexport const EXPLORER_HANDLE_WIDTH = 12\nexport const PREVIEW_HANDLE_WIDTH = 20\n\n/**\n * Drag target width: apply the hard px bounds (the same min/max the handle\n * always enforced), then the store's ordered container-aware clamp so the\n * grid never re-clamps a width the drag showed.\n */\nexport function dragTargetWidth(\n kind: 'explorer' | 'preview',\n startWidth: number,\n deltaX: number,\n snapshot: { availableWidth: number; previewOpen: boolean; explorerWidth: number },\n): number {\n const requested = startWidth + deltaX\n if (kind === 'explorer') {\n const bounded = Math.min(MAX_WORKSPACE_PANEL_PX, Math.max(MIN_WORKSPACE_PANEL_PX, requested))\n return clampExplorerWidth(bounded, snapshot.availableWidth, snapshot.previewOpen)\n }\n const bounded = Math.min(MAX_PREVIEW_REGION_PX, Math.max(MIN_PREVIEW_PANEL_PX, requested))\n return clampPreviewWidth(bounded, snapshot.availableWidth, snapshot.explorerWidth)\n}\n\n/** The layout controller: frame sync, handles, floating button, width math. */\nexport class PanelLayoutController {\n private frame: HTMLElement | null = null\n private previewCol: HTMLDivElement | null = null\n private explorerCol: HTMLDivElement | null = null\n private explorerHandle: HTMLDivElement | null = null\n private previewHandle: HTMLDivElement | null = null\n private floatingButton: HTMLButtonElement | null = null\n private styleObserver: MutationObserver | null = null\n private sizeObserver: ResizeObserver | null = null\n private waitObserver: MutationObserver | null = null\n private frameWidth = 0\n /** Cached shell details handle (re-resolved when the shell rebuilds it). */\n private detailsHandle: HTMLElement | null = null\n /** The shell's own 3 tracks (sidebar, center, details) — mirror of its inline style. */\n private shellTracks: string[] = []\n private instantTimer: ReturnType<typeof setTimeout> | undefined\n private disposers: Array<() => void> = []\n constructor(private readonly layout: LayoutStore) {}\n\n /** Start watching for the frame and attach once it appears. */\n mount(): void {\n const tryAttach = (): void => {\n if (this.frame !== null) return\n const frame = findFrame()\n if (frame === null) return\n this.attach(frame)\n }\n this.waitObserver = new MutationObserver(() => { tryAttach() })\n this.waitObserver.observe(document.body, { childList: true, subtree: true })\n tryAttach()\n }\n\n /** Attach to the frame: columns, handles, observers, store subscription. */\n private attach(frame: HTMLElement): void {\n this.frame = frame\n frameElement = frame\n // The wait observer's only job was finding the frame; a document-wide\n // MutationObserver left running would fire on every chat render for the\n // rest of the session.\n this.waitObserver?.disconnect()\n this.waitObserver = null\n this.detailsHandle = null\n\n // The two panel columns: trailing grid items (tracks 4 and 5).\n const previewCol = document.createElement('div')\n previewCol.dataset.filemgrPreviewCol = ''\n previewCol.className = 'filemgr-preview-col'\n previewCol.style.minWidth = '0'\n previewCol.style.overflow = 'hidden'\n previewCol.style.display = 'flex'\n previewCol.style.flexDirection = 'column'\n previewCol.style.borderLeft = '1px solid var(--aion-bg-3, #e5e6eb)'\n\n const explorerCol = document.createElement('div')\n explorerCol.dataset.filemgrExplorerCol = ''\n explorerCol.className = 'filemgr-explorer-col'\n explorerCol.style.minWidth = '0'\n explorerCol.style.overflow = 'hidden'\n explorerCol.style.display = 'flex'\n explorerCol.style.flexDirection = 'column'\n explorerCol.style.borderLeft = '1px solid var(--aion-bg-3, #e5e6eb)'\n\n frame.appendChild(previewCol)\n frame.appendChild(explorerCol)\n this.previewCol = previewCol\n this.explorerCol = explorerCol\n\n // The absolute drag handles (out of the grid flow). Both sit on the left\n // edge of their panel: dragging left widens (reverse).\n this.explorerHandle = this.createHandle('filemgr-explorer-handle', EXPLORER_HANDLE_WIDTH, true, 'explorer')\n this.previewHandle = this.createHandle('filemgr-preview-handle', PREVIEW_HANDLE_WIDTH, true, 'preview')\n frame.appendChild(this.explorerHandle)\n frame.appendChild(this.previewHandle)\n\n // The floating expand button (fixed, top-right corner) — DOM-level,\n // no React. Docked exactly where the explorer's collapse chevron sits,\n // so collapsing and re-expanding toggle in place (issue #374 follow-up);\n // a click toggles the explorer.\n this.floatingButton = document.createElement('button')\n this.floatingButton.type = 'button'\n this.floatingButton.className = 'filemgr-floating-expand'\n this.floatingButton.setAttribute('aria-label', 'Expand explorer')\n this.floatingButton.innerHTML = '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M6 3l5 5-5 5\"/></svg>'\n this.floatingButton.addEventListener('click', () => { this.toggleExplorer() })\n document.body.appendChild(this.floatingButton)\n\n // Window Controls Overlay (dsh-desktop, issue #292): re-position when\n // the titlebar area changes (button must stay below the window buttons).\n const overlay = (navigator as Navigator & { windowControlsOverlay?: EventTarget }).windowControlsOverlay\n if (overlay !== undefined) {\n const onGeometryChange = (): void => { this.positionFloatingButton() }\n overlay.addEventListener('geometrychange', onGeometryChange)\n this.disposers.push(() => overlay.removeEventListener('geometrychange', onGeometryChange))\n }\n\n // Esc restores a maximized panel (issue #315). Editing surfaces own Esc:\n // while an input/textarea/contenteditable is focused, leave it alone.\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return\n const target = event.target instanceof Element ? event.target : null\n if (target !== null && target.closest('input, textarea, [contenteditable=\"true\"]') !== null) return\n this.layout.update((prev) => (prev.maximized === null ? prev : { ...prev, maximized: null }))\n }\n window.addEventListener('keydown', onKeyDown)\n this.disposers.push(() => window.removeEventListener('keydown', onKeyDown))\n\n // Sync the shell's inline grid: any shell write re-appends our tracks.\n const syncGrid = (): void => {\n const el = this.frame\n if (el === null) return\n const inline = el.style.gridTemplateColumns\n if (inline === '') return\n const tracks = parseGridTracks(inline)\n if (tracks.length >= 2 && tracks.length <= 3) {\n // The shell's own write (3 tracks) — remember it and re-append ours.\n this.shellTracks = tracks\n this.applyGrid()\n return\n }\n if (tracks.length === 5 && this.shellTracks.length === 3) {\n // Our own write — keep it (the shell tracks are already mirrored).\n return\n }\n }\n this.styleObserver = new MutationObserver(syncGrid)\n this.styleObserver.observe(frame, { attributes: true, attributeFilter: ['style'] })\n\n // Measure the row width: frame minus the shell's sidebar + details tracks.\n const measure = (): void => {\n if (this.frame === null) return\n this.frameWidth = this.frame.getBoundingClientRect().width\n const sidebar = this.shellTracks.length >= 1 ? trackPx(this.shellTracks[0]) : 0\n const details = this.shellTracks.length >= 3 ? trackPx(this.shellTracks[2]) : 0\n const available = Math.max(0, this.frameWidth - sidebar - details)\n const state = this.layout.getSnapshot()\n if (Math.abs(state.availableWidth - available) > 0.5) {\n this.layout.update((prev) => ({ ...prev, availableWidth: available }))\n }\n this.layout.shrinkToFit(this.layout.getSnapshot())\n }\n this.sizeObserver = new ResizeObserver(() => {\n measure()\n this.applyGrid()\n })\n this.sizeObserver.observe(frame)\n\n // Store -> DOM: grid, handles, floating button.\n this.disposers.push(this.layout.subscribe(() => this.applyGrid()))\n\n // Initial sync: read the shell's inline style (it is already applied).\n const initial = frame.style.gridTemplateColumns\n if (initial !== '') {\n const tracks = parseGridTracks(initial)\n if (tracks.length >= 2 && tracks.length <= 3) {\n this.shellTracks = tracks\n } else if (tracks.length === 5 && trackPx(tracks[0]) > 0) {\n // The frame may already carry our own previous 5-track write: the\n // plugin hot-reloads in place (client HMR re-materializes the fiber),\n // and the shell's grid is then the first three tracks. A zero-width\n // first track is never a shell write (the shell collapses to the 56px\n // rail, drags clamp at 280px) — treat it as untrusted and wait for\n // the next shell write instead of mirroring the damage.\n this.shellTracks = tracks.slice(0, 3)\n }\n }\n measure()\n this.applyGrid()\n }\n\n /** Create one drag handle element with its pointer wiring. */\n private createHandle(\n className: string,\n hitWidth: number,\n reverse: boolean,\n kind: 'explorer' | 'preview',\n ): HTMLDivElement {\n const el = document.createElement('div')\n el.className = className\n el.style.position = 'absolute'\n el.style.top = '0'\n el.style.bottom = '0'\n // Same layer as the columns (z 30): the handle strips overlap the\n // column tracks, so anything lower would be painted under the opaque\n // columns and stop receiving pointer events (issue #234 follow-up).\n // Full-screen overlay drawers must render at the ROOT stacking context\n // (z 100~1000) to cover both the columns and the handles — see the\n // columns' stacking-contract note in tokens.module.css.\n el.style.zIndex = '30'\n el.style.cursor = 'col-resize'\n el.style.width = `${hitWidth}px`\n if (reverse) {\n // The preview handle extends LEFT of the preview region's left edge.\n el.style.marginLeft = `-${hitWidth}px`\n }\n el.addEventListener('pointerdown', (event: PointerEvent) => {\n const isExplorer = kind === 'explorer'\n handlePointerDragStart(event, el, {\n reverse,\n getStartWidth: () => {\n const state = this.layout.getSnapshot()\n return isExplorer ? state.explorerWidth : state.previewWidth\n },\n compute: (startWidth, deltaX) => dragTargetWidth(\n isExplorer ? 'explorer' : 'preview',\n startWidth,\n deltaX,\n this.layout.getSnapshot(),\n ),\n onFrame: (width) => {\n // layout.update notifies the subscribers (subscribe -> applyGrid),\n // so no explicit applyGrid here — double-writing every frame.\n this.layout.update((prev) => (\n isExplorer ? { ...prev, explorerWidth: width } : { ...prev, previewWidth: width }\n ))\n },\n onEnd: (width) => {\n writeStoredNumber(isExplorer ? KEY_EXPLORER_WIDTH : KEY_PREVIEW_WIDTH, width)\n },\n })\n })\n // Double-click resets THIS panel to its default width (instant, like\n // every panel width change — the shell's grid transition must not lag).\n el.addEventListener('dblclick', () => {\n this.instant(() => {\n const width = kind === 'explorer' ? DEFAULT_WORKSPACE_PANEL_PX : DEFAULT_PREVIEW_REGION_PX\n this.layout.update((prev) => (\n kind === 'explorer' ? { ...prev, explorerWidth: width } : { ...prev, previewWidth: width }\n ))\n writeStoredNumber(kind === 'explorer' ? KEY_EXPLORER_WIDTH : KEY_PREVIEW_WIDTH, width)\n this.applyGrid()\n })\n })\n // The visual line is drawn by CSS (::after) — the hit zone is transparent.\n return el\n }\n\n /** Toggle explorer collapse (width 0, kept mounted; no transition). */\n toggleExplorer(): void {\n const state = this.layout.getSnapshot()\n const next = !state.explorerCollapsed\n this.instant(() => {\n this.layout.update((prev) => ({ ...prev, explorerCollapsed: next }))\n try {\n localStorage.setItem(`project-panel-collapse:${state.root}`, next ? 'collapsed' : 'expanded')\n } catch {\n // best-effort\n }\n this.applyGrid()\n })\n }\n\n /** Toggle the preview region (open = tabs exist; close keeps tabs). */\n setPreviewOpen(open: boolean): void {\n this.instant(() => {\n this.layout.update((prev) => ({ ...prev, previewOpen: open }))\n this.applyGrid()\n })\n }\n\n /**\n * Locate the shell conversation header: its bottom border is the\n * horizontal divider under the \"Session log\" row the button should\n * sit below. Resolved per call (the shell may mount it late); null when\n * the shell has no header (standalone installs, desktop variants).\n */\n private findHeaderBottom(): number | null {\n const frame = this.frame\n if (frame === null) return null\n const header = frame.querySelector<HTMLElement>(\n '[data-pane=\"conversation\"] header, [class*=\"centerCol\"] header',\n )\n if (header === null) return null\n const bottom = header.getBoundingClientRect().bottom\n return Number.isFinite(bottom) ? bottom : null\n }\n\n /** Position the floating button: docked at the top-right corner, just\n * below the shell header's bottom divider (fallback: the chevron row). */\n private positionFloatingButton(): void {\n const el = this.floatingButton\n if (el === null) return\n const height = window.innerHeight\n const titlebar = titlebarAreaHeight()\n const headerBottom = this.findHeaderBottom()\n const top = headerBottom !== null\n ? clampFloatingTop(headerBottom + FLOATING_HEADER_GAP_PX, height, FLOATING_BUTTON_HEIGHT_PX, titlebar)\n : topAlignedFloatingTop(height, FLOATING_BUTTON_HEIGHT_PX, titlebar)\n el.style.top = `${Math.round(top)}px`\n el.style.transform = 'none'\n }\n\n /** Apply one store update with transitions disabled for exactly one frame. */\n private instant(fn: () => void): void {\n const frame = this.frame\n if (frame === null) {\n fn()\n return\n }\n frame.setAttribute('data-filemgr-instant', '')\n if (this.instantTimer !== undefined) clearTimeout(this.instantTimer)\n this.instantTimer = setTimeout(() => {\n this.instantTimer = undefined\n frame.removeAttribute('data-filemgr-instant')\n }, 0)\n fn()\n }\n\n /** Re-write the frame grid and reposition handles + floating button. */\n private applyGrid(): void {\n const frame = this.frame\n if (frame === null) return\n // Never guess the shell tracks: without a mirrored shell write, the old\n // fallback zeroed the sidebar track (the bug where the left sidebar\n // vanished after a hot reload). Skip the write until syncGrid observes\n // the shell's own 3-track grid.\n if (this.shellTracks.length !== 3) return\n const state = this.layout.getSnapshot()\n const width = this.frameWidth > 0 ? this.frameWidth : frame.getBoundingClientRect().width\n\n if (state.maximized !== null) {\n this.applyMaximized(frame, state.maximized, width)\n return\n }\n this.clearMaximizedChrome()\n\n const explorer = this.layout.explorerWidthPx(state)\n const preview = this.layout.previewWidthPx(state)\n\n // Five tracks: shell sidebar, center, shell details, preview, explorer.\n frame.style.gridTemplateColumns =\n `${this.shellTracks[0]} minmax(0, 1fr) ${this.shellTracks[2]} ${Math.round(preview)}px ${Math.round(explorer)}px`\n\n // Column contents follow the tracks (both columns always mounted).\n if (this.explorerCol !== null) {\n this.explorerCol.style.visibility = explorer > 0 ? 'visible' : 'hidden'\n }\n if (this.previewCol !== null) {\n this.previewCol.style.visibility = preview > 0 ? 'visible' : 'hidden'\n }\n\n // Handles: at the left edge of each panel.\n if (this.explorerHandle !== null) {\n const left = Math.round(width - explorer)\n this.explorerHandle.style.left = `${left}px`\n this.explorerHandle.style.marginLeft = `${-EXPLORER_HANDLE_WIDTH / 2}px`\n this.explorerHandle.style.display = explorer > 0 && state.root !== '' ? 'block' : 'none'\n }\n if (this.previewHandle !== null) {\n const left = Math.round(width - explorer - preview)\n this.previewHandle.style.left = `${left}px`\n this.previewHandle.style.display = preview > 0 && state.root !== '' ? 'block' : 'none'\n }\n\n // The official shell renders its own details drag handle at\n // `viewport - details` (details treated as the last track). Once this\n // panel extends the grid with preview/explorer tracks, the real\n // center/details boundary shifts left by preview + explorer — re-derive\n // the handle position from the actual tracks so it stays on the details\n // column's left edge (degenerates to the official value when both panels\n // are closed).\n const detailsTrack = trackPx(this.shellTracks[2])\n // applyGrid runs on every drag frame: resolve the shell handle once and\n // cache it instead of scanning the whole frame subtree each call. The\n // cache resets on attach (the shell may rebuild its chrome on HMR).\n if (this.detailsHandle === null || !this.detailsHandle.isConnected) {\n this.detailsHandle = frame.querySelector<HTMLElement>('[data-side=\"details\"]')\n }\n if (this.detailsHandle !== null) {\n this.detailsHandle.style.left = `${Math.round(width - detailsTrack - preview - explorer)}px`\n }\n\n // Floating expand button: visible only when the explorer is collapsed.\n if (this.floatingButton !== null) {\n const show = state.root !== '' && state.explorerCollapsed\n this.floatingButton.style.display = show ? 'flex' : 'none'\n this.positionFloatingButton()\n }\n }\n\n /**\n * Maximize layout: the target column takes over the whole frame row (the\n * other tracks collapse to 0px). On narrow viewports the takeover grid is\n * skipped and the column renders as a fixed full-screen overlay instead\n * (issue #315). Everything stays mounted — only geometry changes.\n */\n private applyMaximized(frame: HTMLElement, target: MaximizeTarget, width: number): void {\n const overlay = maximizedOverlay(this.layout.getSnapshot().availableWidth)\n if (!overlay) {\n frame.style.gridTemplateColumns = maximizedGridTracks(target, width)\n }\n if (this.explorerCol !== null) {\n this.explorerCol.style.visibility = target === 'explorer' ? 'visible' : 'hidden'\n this.explorerCol.classList.toggle('filemgr-maximized', target === 'explorer' && overlay)\n }\n if (this.previewCol !== null) {\n this.previewCol.style.visibility = target === 'preview' ? 'visible' : 'hidden'\n this.previewCol.classList.toggle('filemgr-maximized', target === 'preview' && overlay)\n }\n // No drag chrome while maximized: nothing to resize, and the floating\n // button only makes sense for the collapsed explorer.\n if (this.explorerHandle !== null) this.explorerHandle.style.display = 'none'\n if (this.previewHandle !== null) this.previewHandle.style.display = 'none'\n if (this.floatingButton !== null) this.floatingButton.style.display = 'none'\n }\n\n /** Remove the narrow-screen overlay class from both columns. */\n private clearMaximizedChrome(): void {\n this.explorerCol?.classList.remove('filemgr-maximized')\n this.previewCol?.classList.remove('filemgr-maximized')\n }\n\n /** Detach everything (plugin unload). */\n dispose(): void {\n this.waitObserver?.disconnect()\n this.styleObserver?.disconnect()\n this.sizeObserver?.disconnect()\n for (const dispose of this.disposers) dispose()\n this.previewCol?.remove()\n this.explorerCol?.remove()\n this.explorerHandle?.remove()\n this.previewHandle?.remove()\n this.floatingButton?.remove()\n if (this.instantTimer !== undefined) clearTimeout(this.instantTimer)\n if (frameElement === this.frame) frameElement = null\n this.frame = null\n }\n}\n","/**\n * Locale strings for the panel surfaces (zh/en). The client registers the\n * dictionary through the locale service like the sibling plugins; copy is\n * deliberately short and technical.\n * @module dsh-filemgr/client/locales\n */\n\nconst zh = {\n 'explorer.tabs.files': '文件',\n 'explorer.tabs.changes': '变更',\n 'explorer.search.placeholder': '按文件名搜索',\n 'explorer.search.searching': '搜索中…',\n 'explorer.search.empty': '没有匹配的文件',\n 'explorer.search.error': '搜索失败',\n 'explorer.search.truncated': '结果过多,仅显示前 {count} 条',\n 'explorer.tree.empty': '项目为空',\n 'explorer.collapse': '收起面板',\n 'explorer.expand': '展开面板',\n 'explorer.maximize': '最大化文件面板',\n 'explorer.restore': '还原面板',\n 'explorer.openPreview': '打开预览',\n 'explorer.drag.dropHint': '松手插入文件路径',\n 'scm.repositories': '存储库',\n 'scm.changes': '变更',\n 'scm.staged': '已暂存',\n 'scm.unstaged': '变更',\n 'scm.untracked': '未跟踪',\n 'scm.conflicted': '冲突',\n 'scm.stage': '暂存',\n 'scm.unstage': '取消暂存',\n 'scm.discard': '放弃更改',\n 'scm.stageAll': '全部暂存',\n 'scm.discardAll': '全部放弃',\n 'scm.empty': '没有更改',\n 'scm.notRepo': '当前目录不是 git 仓库',\n 'scm.gitMissing': '未检测到 git,请先安装 git 后重试',\n 'scm.loading': '读取状态中…',\n 'scm.failed': '操作失败',\n 'scm.viewList': '列表视图',\n 'scm.viewTree': '树视图',\n 'scm.discardConfirmTracked': '放弃对 {count} 个文件的更改?此操作不可恢复。',\n 'scm.discardConfirmUntracked': '删除 {count} 个未跟踪文件?此操作不可恢复。',\n 'preview.noTabs': '没有打开的预览',\n 'preview.newUrlTab': '新建 URL 预览',\n 'preview.collapsePanel': '收起预览面板',\n 'preview.maximize': '最大化预览面板',\n 'preview.restore': '还原面板',\n 'preview.source': '源码',\n 'preview.preview': '预览',\n 'preview.editor': '编辑器',\n 'preview.split': '分屏',\n 'preview.refresh': '刷新',\n 'preview.refresh.updated': '文件已在磁盘更新',\n 'preview.save': '保存',\n 'preview.download': '下载',\n 'preview.copyCode': '复制代码',\n 'preview.copyCodeDone': '已复制',\n 'preview.openExternal': '在系统应用中打开',\n 'preview.dirty': '未保存的更改',\n 'preview.closeLeft': '关闭左侧',\n 'preview.closeRight': '关闭右侧',\n 'preview.closeOthers': '关闭其他',\n 'preview.closeAll': '关闭全部',\n 'preview.closeConfirmTitle': '关闭未保存的标签页',\n 'preview.closeConfirmBody': '{count} 个标签页有未保存的更改,关闭将丢失这些更改。',\n 'preview.saved': '已保存',\n 'preview.saveConflict': '文件已在磁盘上被修改,保存冲突:请刷新后重试',\n 'preview.errorOversized': '文件过大,仅加载前 80,000 字符',\n 'preview.unsupported': '此格式暂不支持预览',\n 'preview.downloadHint': '可在系统应用中打开或下载查看',\n 'preview.url.placeholder': '输入网址,回车打开',\n 'preview.url.hint': '按 Esc 还原',\n 'common.cancel': '取消',\n 'common.confirm': '确定',\n 'common.close': '关闭',\n 'common.delete': '删除',\n 'common.copyPath': '复制路径',\n 'common.copied': '已复制',\n 'explorer.menu.copyPath': '复制路径',\n 'explorer.menu.copyName': '复制名称',\n 'explorer.menu.reveal': '在文件管理器中显示',\n 'explorer.menu.openWithDefault': '用默认应用打开',\n 'explorer.menu.rename': '重命名',\n 'explorer.menu.newFile': '新建文件',\n 'explorer.menu.newFolder': '新建文件夹',\n 'explorer.menu.delete': '删除',\n 'explorer.rename.title': '重命名',\n 'explorer.newFile.title': '新建文件',\n 'explorer.newFolder.title': '新建文件夹',\n 'explorer.deleteConfirmTitle': '删除确认',\n 'explorer.deleteConfirmBody': '确定要删除「{name}」吗?此操作不可恢复。',\n 'explorer.opFailed': '操作失败',\n 'explorer.refToInput': '引用到输入框',\n 'settings.title': '右侧面板',\n 'settings.description': 'Explorer / Preview 与 SCM 变更面板的总开关。',\n 'settings.enabled': '启用右侧面板',\n 'settings.enabledHint': '关闭后不再挂载右侧文件树与预览列、不显示浮动展开按钮、不注册 /filemgr 路由,也不做工作区监视与 git 轮询;聚合包其余插件不受影响。',\n 'settings.overridden': '已覆盖',\n 'settings.reset': '恢复默认',\n 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或为 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES 白名单补充本命名空间后重启。',\n 'settings.readOnly': '当前部署的设置只读。',\n 'settings.inherit': '继承',\n 'settings.on': '开',\n 'settings.off': '关',\n 'settings.expand': '展开设置',\n 'settings.collapse': '收起设置',\n 'settings.save': '保存',\n 'settings.saving': '保存中…',\n 'settings.discard': '放弃',\n 'settings.unsaved': '未保存',\n 'settings.saveFailed': '部署未接受这些值,已保留供你修改。',\n 'settings.invalidNumber': '请输入数字,留空则使用默认值。',\n} as const\n\nconst en: Record<keyof typeof zh, string> = {\n 'explorer.tabs.files': 'Files',\n 'explorer.tabs.changes': 'Changes',\n 'explorer.search.placeholder': 'Search file names',\n 'explorer.search.searching': 'Searching…',\n 'explorer.search.empty': 'No matching files',\n 'explorer.search.error': 'Search failed',\n 'explorer.search.truncated': 'Too many results, showing first {count}',\n 'explorer.tree.empty': 'The project is empty',\n 'explorer.collapse': 'Collapse panel',\n 'explorer.expand': 'Expand panel',\n 'explorer.maximize': 'Maximize files panel',\n 'explorer.restore': 'Restore panel',\n 'explorer.openPreview': 'Open preview',\n 'explorer.drag.dropHint': 'Release to insert the file path',\n 'scm.repositories': 'Repositories',\n 'scm.changes': 'Changes',\n 'scm.staged': 'Staged',\n 'scm.unstaged': 'Changes',\n 'scm.untracked': 'Untracked',\n 'scm.conflicted': 'Conflict',\n 'scm.stage': 'Stage',\n 'scm.unstage': 'Unstage',\n 'scm.discard': 'Discard',\n 'scm.stageAll': 'Stage all',\n 'scm.discardAll': 'Discard all',\n 'scm.empty': 'No changes',\n 'scm.notRepo': 'Not a git repository',\n 'scm.gitMissing': 'Git is not installed. Install git and reload to use the changes panel',\n 'scm.loading': 'Loading status…',\n 'scm.failed': 'Operation failed',\n 'scm.viewList': 'List view',\n 'scm.viewTree': 'Tree view',\n 'scm.discardConfirmTracked': 'Discard changes in {count} files? This cannot be undone.',\n 'scm.discardConfirmUntracked': 'Delete {count} untracked files? This cannot be undone.',\n 'preview.noTabs': 'No open previews',\n 'preview.newUrlTab': 'New URL preview',\n 'preview.collapsePanel': 'Collapse preview panel',\n 'preview.maximize': 'Maximize preview panel',\n 'preview.restore': 'Restore panel',\n 'preview.source': 'Source',\n 'preview.preview': 'Preview',\n 'preview.editor': 'Editor',\n 'preview.split': 'Split',\n 'preview.refresh': 'Refresh',\n 'preview.refresh.updated': 'File updated on disk',\n 'preview.save': 'Save',\n 'preview.download': 'Download',\n 'preview.copyCode': 'Copy code',\n 'preview.copyCodeDone': 'Copied',\n 'preview.openExternal': 'Open in system app',\n 'preview.dirty': 'Unsaved changes',\n 'preview.closeLeft': 'Close left',\n 'preview.closeRight': 'Close right',\n 'preview.closeOthers': 'Close others',\n 'preview.closeAll': 'Close all',\n 'preview.closeConfirmTitle': 'Close unsaved tabs',\n 'preview.closeConfirmBody': '{count} tabs have unsaved changes. Closing will lose them.',\n 'preview.saved': 'Saved',\n 'preview.saveConflict': 'File changed on disk. Save conflict: refresh and retry',\n 'preview.errorOversized': 'File too large, only the first 80,000 characters loaded',\n 'preview.unsupported': 'Preview not supported for this format',\n 'preview.downloadHint': 'Open in a system app or download to view',\n 'preview.url.placeholder': 'Enter a URL and press Enter',\n 'preview.url.hint': 'Press Esc to revert',\n 'common.cancel': 'Cancel',\n 'common.confirm': 'OK',\n 'common.close': 'Close',\n 'common.delete': 'Delete',\n 'common.copyPath': 'Copy path',\n 'common.copied': 'Copied',\n 'explorer.menu.copyPath': 'Copy path',\n 'explorer.menu.copyName': 'Copy name',\n 'explorer.menu.reveal': 'Reveal in file manager',\n 'explorer.menu.openWithDefault': 'Open with default app',\n 'explorer.menu.rename': 'Rename',\n 'explorer.menu.newFile': 'New file',\n 'explorer.menu.newFolder': 'New folder',\n 'explorer.menu.delete': 'Delete',\n 'explorer.rename.title': 'Rename',\n 'explorer.newFile.title': 'New file',\n 'explorer.newFolder.title': 'New folder',\n 'explorer.deleteConfirmTitle': 'Confirm delete',\n 'explorer.deleteConfirmBody': 'Delete \"{name}\"? This cannot be undone.',\n 'explorer.opFailed': 'Operation failed',\n 'explorer.refToInput': 'Reference to input',\n 'settings.title': 'Right panel',\n 'settings.description': 'Master switch for the Explorer / Preview and SCM changes panels.',\n 'settings.enabled': 'Enable the right panel',\n 'settings.enabledHint': 'When off, the Explorer and Preview columns are not mounted, the floating expand button disappears, the /filemgr routes are not registered, and workspace watching and git polling stop. The rest of the family bundle is unaffected.',\n 'settings.overridden': 'Overridden',\n 'settings.reset': 'Reset',\n 'settings.notExposed': 'This DSH version does not expose this plugin\\'s settings namespace; the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to the WEB_SETTINGS_NAMESPACES allowlist of dsh-host-apiproxy and restart.',\n 'settings.readOnly': 'Settings are read-only in this deployment.',\n 'settings.inherit': 'Inherit',\n 'settings.on': 'On',\n 'settings.off': 'Off',\n 'settings.expand': 'Expand settings',\n 'settings.collapse': 'Collapse settings',\n 'settings.save': 'Save',\n 'settings.saving': 'Saving…',\n 'settings.discard': 'Discard',\n 'settings.unsaved': 'Unsaved',\n 'settings.saveFailed': 'The deployment rejected these values; your edits are kept.',\n 'settings.invalidNumber': 'Enter a number, or leave it empty to use the default.',\n}\n\nexport type FileManagerPanelKey = keyof typeof zh\n\n/** The dictionary namespace this plugin owns. */\nexport const NS = 'filemgr'\n\n/** Format one copy string with {name} placeholders. */\nexport function format(template: string, params: Record<string, string | number>): string {\n return template.replace(/\\{(\\w+)\\}/g, (_, key: string) => String(params[key] ?? `{${key}}`))\n}\n\n/** Simple dictionary access (zh/en by a global flag the client sets). */\nexport const dictionaries: Record<'zh' | 'en', Record<FileManagerPanelKey, string>> = { zh, en }\n\nlet currentLanguage: 'zh' | 'en' = 'zh'\n\n/** Set the active language (the client mirrors the locale service). */\nexport function setLanguage(language: string): void {\n currentLanguage = language === 'en' ? 'en' : 'zh'\n}\n\n/** Translate one key with optional params. */\nexport function t(key: FileManagerPanelKey, params?: Record<string, string | number>): string {\n const table = dictionaries[currentLanguage] ?? zh\n const template = table[key] ?? zh[key]\n return params === undefined ? template : format(template, params)\n}\n","/**\n * React bindings for the framework-free stores: useSyncExternalStore with a\n * stable snapshot (the stores return immutable snapshots, so selector-free\n * subscription is safe), plus a stable-callback helper for event handlers.\n * @module dsh-filemgr/client/hooks/useStore\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type { StateHandle } from '../store.ts'\n\n/** Subscribe a component to one store (full snapshot). */\nexport function useStore<S>(store: StateHandle<S>): S {\n return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)\n}\n\n","/**\n * Inline 16px icon set for the panel surfaces (outline style, currentColor).\n * No icon package is introduced; the set covers the explorer tree, SCM rows,\n * and the preview toolbar/tabs with plain geometric shapes.\n * @module dsh-filemgr/client/components/icons\n */\n\nimport type { JSX, SVGProps } from 'react'\n\ninterface IconProps {\n size?: number\n className?: string\n}\n\nconst base = (size: number): SVGProps<SVGSVGElement> => ({\n width: size,\n height: size,\n viewBox: '0 0 16 16',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.3,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': true,\n})\n\nexport function FolderIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2 3.5h4l1.5 2H14a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4.5a1 1 0 0 1 1-1Z\" />\n </svg>\n )\n}\n\nexport function FolderOpenIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2 3.5h4l1.5 2H14a1 1 0 0 1 1 1v1H3.5a1 1 0 0 0-.96.72L1 13.5V4.5a1 1 0 0 1 1-1Z\" />\n <path d=\"M2.8 11.5 4 7.5h11l-1.4 4a1 1 0 0 1-.96.72H3.76a1 1 0 0 1-.96-.72Z\" />\n </svg>\n )\n}\n\nexport function FileIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M4 2h5l3 3v9H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\" />\n <path d=\"M9 2v3h3\" />\n </svg>\n )\n}\n\nexport function FileCodeIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M4 2h5l3 3v9H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\" />\n <path d=\"M9 2v3h3\" />\n <path d=\"m6.2 8.6-1.4 1.4 1.4 1.4M9.8 8.6l1.4 1.4-1.4 1.4\" />\n </svg>\n )\n}\n\nexport function FileImageIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M4 2h5l3 3v9H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\" />\n <path d=\"M9 2v3h3\" />\n <circle cx=\"6.2\" cy=\"6.8\" r=\"1\" />\n <path d=\"m5 11 1.8-1.8 1.4 1.4 1.3-1.3L12 12\" />\n </svg>\n )\n}\n\nexport function FileTextIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M4 2h5l3 3v9H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\" />\n <path d=\"M9 2v3h3\" />\n <path d=\"M6 9h4M6 11.2h4\" />\n </svg>\n )\n}\n\nexport function ChevronRightIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"m6 3.5 4.5 4.5L6 12.5\" />\n </svg>\n )\n}\n\nexport function ChevronDownIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"m3.5 6 4.5 4.5L12.5 6\" />\n </svg>\n )\n}\n\nexport function CloseIcon({ size = 12, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"m3.5 3.5 9 9M12.5 3.5l-9 9\" />\n </svg>\n )\n}\n\nexport function PlusIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M8 3v10M3 8h10\" />\n </svg>\n )\n}\n\nexport function MinusIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M3 8h10\" />\n </svg>\n )\n}\n\nexport function UndoIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M5 3.5 2.5 6 5 8.5\" />\n <path d=\"M2.5 6h8a3.5 3.5 0 0 1 0 7h-3\" />\n </svg>\n )\n}\n\nexport function RefreshIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M13 8a5 5 0 1 1-1.6-3.65\" />\n <path d=\"M13.5 2v2.8h-2.8\" />\n </svg>\n )\n}\n\nexport function SplitIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <rect x=\"2\" y=\"2.5\" width=\"12\" height=\"11\" rx=\"1\" />\n <path d=\"M8 2.5v11\" />\n </svg>\n )\n}\n\nexport function CodeIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"m5.5 4.5-4 3.5 4 3.5M10.5 4.5l4 3.5-4 3.5\" />\n </svg>\n )\n}\n\nexport function EyeIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M1.5 8s2.5-4.5 6.5-4.5S14.5 8 14.5 8 12 12.5 8 12.5 1.5 8 1.5 8Z\" />\n <circle cx=\"8\" cy=\"8\" r=\"2\" />\n </svg>\n )\n}\n\nexport function SaveIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M3 2.5h8l2.5 2.5v8.5a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1Z\" />\n <path d=\"M5 2.5v3.5h4.5V2.5M5 13.5V9.5h6v4\" />\n </svg>\n )\n}\n\nexport function DownloadIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M8 2v7.5M4.5 6.5 8 10l3.5-3.5\" />\n <path d=\"M2.5 13h11\" />\n </svg>\n )\n}\n\nexport function ExternalIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M9 2.5h4.5V7\" />\n <path d=\"M13.5 2.5 7.5 8.5\" />\n <path d=\"M11.5 9v3.5a1 1 0 0 1-1 1H3.5a1 1 0 0 1-1-1V5.5a1 1 0 0 1 1-1H7\" />\n </svg>\n )\n}\n\nexport function SearchIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" />\n <path d=\"m10.5 10.5 3 3\" />\n </svg>\n )\n}\n\nexport function BranchIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <circle cx=\"4\" cy=\"3.5\" r=\"1.5\" />\n <circle cx=\"4\" cy=\"12.5\" r=\"1.5\" />\n <circle cx=\"12\" cy=\"6.5\" r=\"1.5\" />\n <path d=\"M4 5v5M4 10.5c0-2 2-2.5 4-2.5s4-.5 4-1.5\" />\n </svg>\n )\n}\n\nexport function ListIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2.5 4h11M2.5 8h11M2.5 12h11\" />\n </svg>\n )\n}\n\nexport function TreeIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2.5 3.5h6M8.5 8h5M2.5 8h2\" />\n <path d=\"M6 3.5v7\" />\n <path d=\"M11 8v4.5h-2.5\" />\n </svg>\n )\n}\n\nexport function ShrinkIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M14 14 10 10M10 14v-4h4\" />\n <path d=\"M2 2l4 4M6 2v4H2\" />\n </svg>\n )\n}\n\nexport function ExpandRightIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M6 3.5 11.5 8 6 12.5\" />\n </svg>\n )\n}\n\nexport function EmptyFolderIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2 3.5h4l1.5 2H14a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4.5a1 1 0 0 1 1-1Z\" opacity=\"0.55\" />\n </svg>\n )\n}\n\nexport function MaximizeIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <rect x=\"3\" y=\"3\" width=\"10\" height=\"10\" rx=\"1\" />\n </svg>\n )\n}\n\nexport function RestoreIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <rect x=\"3\" y=\"5\" width=\"8\" height=\"8\" rx=\"1\" />\n <path d=\"M6.5 3.5h5a1 1 0 0 1 1 1V10\" />\n </svg>\n )\n}\n","/**\n * 16x16 file/folder icons for the tree — a small built-in set (folder\n * open/closed, file variants by kind) using the token colors, so both themes\n * stay consistent without pulling in a vscode-icons package.\n * @module dsh-filemgr/client/components/FileIcon\n */\n\nimport type { JSX } from 'react'\nimport { detectContentType } from '../fileType.ts'\nimport {\n FileCodeIcon, FileIcon, FileImageIcon, FileTextIcon, FolderIcon, FolderOpenIcon,\n} from './icons.tsx'\n\n/** The icon for one tree entry (16x16, currentColor). */\nexport function FileTypeIcon({\n name,\n isDir,\n expanded,\n className,\n}: {\n name: string\n isDir: boolean\n expanded: boolean\n className?: string\n}): JSX.Element {\n if (isDir) {\n return expanded\n ? <FolderOpenIcon size={16} className={className} />\n : <FolderIcon size={16} className={className} />\n }\n const type = detectContentType(name)\n switch (type) {\n case 'image':\n return <FileImageIcon size={16} className={className} />\n case 'markdown':\n case 'text':\n return <FileTextIcon size={16} className={className} />\n case 'code':\n case 'diff':\n case 'csv':\n case 'html':\n return <FileCodeIcon size={16} className={className} />\n default:\n return <FileIcon size={16} className={className} />\n }\n}\n","/**\n * Minimal overlay primitives for the panel: a toast and a context menu,\n * rendered through plain DOM + portals so they can live outside the grid\n * columns (fixed positioning, high z-index).\n * @module dsh-filemgr/client/components/overlay\n */\n\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport type { JSX } from 'react'\nimport { t } from '../locales.ts'\nimport type { FileManagerPanelKey } from '../locales.ts'\n\n/** One transient toast message. */\nexport function toast(message: string): void {\n const el = document.createElement('div')\n el.className = 'filemgr-toast'\n el.textContent = message\n document.body.appendChild(el)\n setTimeout(() => {\n el.style.opacity = '0'\n el.style.transition = 'opacity 0.2s ease'\n }, 1800)\n setTimeout(() => el.remove(), 2100)\n}\n\n/** One context-menu entry (separators carry no handler). */\nexport interface MenuEntry {\n key: string\n label: string\n disabled?: boolean\n danger?: boolean\n onSelect?: () => void\n}\n\nexport interface MenuState {\n x: number\n y: number\n entries: MenuEntry[]\n}\n\n/** The shared context-menu portal host (one at a time). */\nexport function ContextMenu({ state, onClose }: { state: MenuState | null; onClose: () => void }): JSX.Element | null {\n const [position, setPosition] = useState<{ x: number; y: number } | null>(null)\n\n useLayoutEffect(() => {\n if (state === null) {\n setPosition(null)\n return\n }\n // Keep the menu inside the viewport.\n const width = 180\n const height = state.entries.length * 28 + 12\n setPosition({\n x: Math.min(state.x, window.innerWidth - width - 8),\n y: Math.min(state.y, window.innerHeight - height - 8),\n })\n }, [state])\n\n useEffect(() => {\n if (state === null) return\n const close = (event: Event): void => {\n // A pointerdown inside the menu must not close it — the menu item's own\n // onClick still needs to run (and microtask-less onClose before onSelect\n // would unmount the item mid-click). Only close on outside clicks.\n if (event.target instanceof Element && event.target.closest('[data-menu-root]') !== null) return\n onClose()\n }\n const key = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') onClose()\n }\n window.addEventListener('pointerdown', close, { capture: true })\n window.addEventListener('blur', onClose)\n window.addEventListener('keydown', key)\n window.addEventListener('contextmenu', onClose)\n return () => {\n window.removeEventListener('pointerdown', close, { capture: true })\n window.removeEventListener('blur', onClose)\n window.removeEventListener('keydown', key)\n window.removeEventListener('contextmenu', onClose)\n }\n }, [state, onClose])\n\n if (state === null || position === null) return null\n return createPortal(\n <div\n className=\"filemgr-menu\"\n data-menu-root=\"\"\n style={{ left: position.x, top: position.y }}\n onPointerDown={(event) => event.stopPropagation()}\n onContextMenu={(event) => event.preventDefault()}\n >\n {state.entries.map((entry) => (\n <div key={entry.key}>\n {entry.label === '---' ? (\n <div className=\"filemgr-menu-sep\" />\n ) : (\n <div\n className={`filemgr-menu-item${entry.disabled === true ? ' filemgr-menu-item-disabled' : ''}`}\n onClick={() => {\n if (entry.disabled === true) return\n onClose()\n entry.onSelect?.()\n }}\n role=\"menuitem\"\n >\n {entry.label}\n </div>\n )}\n </div>\n ))}\n </div>,\n document.body,\n )\n}\n\n/** A single-text-input dialog (rename, new file / new folder). */\nexport function PromptDialog({\n title,\n initialValue,\n confirmLabel,\n onConfirm,\n onCancel,\n}: {\n title: string\n initialValue?: string\n confirmLabel?: string\n onConfirm: (value: string) => void\n onCancel: () => void\n}): JSX.Element {\n const [value, setValue] = useState(initialValue ?? '')\n const inputRef = useRef<HTMLInputElement>(null)\n useLayoutEffect(() => {\n inputRef.current?.focus()\n inputRef.current?.select()\n }, [])\n const commit = (): void => {\n const trimmed = value.trim()\n if (trimmed === '') return\n onConfirm(trimmed)\n }\n useEffect(() => {\n const key = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') onCancel()\n }\n window.addEventListener('keydown', key)\n return () => window.removeEventListener('keydown', key)\n }, [onCancel])\n return createPortal(\n <div className=\"filemgr-overlay\" onPointerDown={onCancel}>\n <div className=\"filemgr-dialog\" onPointerDown={(event) => event.stopPropagation()}>\n <div className=\"filemgr-dialog-title\">{title}</div>\n <div className=\"filemgr-dialog-body\">\n <input\n ref={inputRef}\n className=\"filemgr-input\"\n value={value}\n placeholder={initialValue ?? ''}\n aria-label={title}\n onChange={(event) => setValue(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n />\n </div>\n <div className=\"filemgr-dialog-actions\">\n <button type=\"button\" className=\"filemgr-btn\" onClick={onCancel}>{t('common.cancel')}</button>\n <button\n type=\"button\"\n className=\"filemgr-btn filemgr-btn-primary\"\n disabled={value.trim() === ''}\n onClick={commit}\n >\n {confirmLabel ?? t('common.confirm')}\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n\n/** A confirmation dialog (dirty-close confirm, discard confirm). */\nexport function ConfirmDialog({\n title,\n body,\n confirmLabel,\n danger,\n onConfirm,\n onCancel,\n}: {\n title: string\n body: string\n confirmLabel?: string\n danger?: boolean\n onConfirm: () => void\n onCancel: () => void\n}): JSX.Element {\n useEffect(() => {\n const key = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') onCancel()\n }\n window.addEventListener('keydown', key)\n return () => window.removeEventListener('keydown', key)\n }, [onCancel])\n return createPortal(\n <div className=\"filemgr-overlay\" onPointerDown={onCancel}>\n <div className=\"filemgr-dialog\" onPointerDown={(event) => event.stopPropagation()}>\n <div className=\"filemgr-dialog-title\">{title}</div>\n <div className=\"filemgr-dialog-body\">{body}</div>\n <div className=\"filemgr-dialog-actions\">\n <button type=\"button\" className=\"filemgr-btn\" onClick={onCancel}>{t('common.cancel')}</button>\n <button\n type=\"button\"\n className={`filemgr-btn ${danger === true ? 'filemgr-btn-danger' : 'filemgr-btn-primary'}`}\n onClick={onConfirm}\n >\n {confirmLabel ?? t('common.confirm')}\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n","import type { KeyboardEvent } from 'react'\n\n/**\n * Keyboard activation parity for focusable rows/divs styled as buttons\n * (role=\"button\" + tabIndex={0}): Enter and Space trigger the same action as\n * a click, and events bubbling out of nested interactive elements (a row's\n * inline action buttons, a tab's close control) are ignored so they never\n * double-activate the row.\n * @param handler - the activation handler (the element's click action).\n * @returns a keydown handler for the focusable element.\n */\nexport function activateOnKey(handler: () => void) {\n return (event: KeyboardEvent<HTMLElement>): void => {\n if (event.target !== event.currentTarget) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handler()\n }\n }\n}\n","/**\n * The Changes (SCM) panel: per-repo working-tree status grouped into staged /\n * unstaged / untracked, with stage/unstage/discard actions on every row and\n * bulk actions in the section header. The host status is the only truth — no\n * optimistic rows; a failed batch surfaces its paths and the next refresh\n * clears the flag. Discard confirms with copy split by recoverability\n * (untracked = delete vs tracked = irreversible restore).\n *\n * FileManager ScmPanel behavior (Apache-2.0, re-implemented): window focus\n * refreshes (external editors write without git events), unknown states\n * render as a quiet '?', conflicted rows are visually distinct AND have no\n * actions.\n * @module dsh-filemgr/client/components/ScmPanel\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport type { GitChangeRow } from '../../core/types.ts'\nimport { t, format } from '../locales.ts'\nimport { useStore } from '../hooks/useStore.ts'\nimport type { PanelStores } from '../store.ts'\nimport { ConfirmDialog } from './overlay.tsx'\nimport { activateOnKey } from './a11y.ts'\nimport { FileTypeIcon } from './FileIcon.tsx'\nimport { BranchIcon, ChevronDownIcon, ChevronRightIcon, ListIcon, MinusIcon, PlusIcon, TreeIcon, UndoIcon } from './icons.tsx'\nimport scmCss from '../styles/scm.module.css'\n\n/** Minimum gap between window-focus SCM refreshes (ms). */\nconst FOCUS_REFRESH_MIN_MS = 5_000\n\n/** Badge letter + color class per state. */\nconst BADGE: Record<string, { letter: string; className: string }> = {\n created: { letter: 'A', className: scmCss.badgeCreated },\n modified: { letter: 'M', className: scmCss.badgeModified },\n deleted: { letter: 'D', className: scmCss.badgeDeleted },\n renamed: { letter: 'R', className: scmCss.badgeCreated },\n conflicted: { letter: '!', className: scmCss.badgeConflicted },\n untracked: { letter: '?', className: scmCss.badgeUntracked },\n unknown: { letter: '?', className: scmCss.badgeUntracked },\n}\n\n/** The parent dir of a path ('' for root-level). */\nfunction dirOf(path: string): string {\n const idx = path.lastIndexOf('/')\n return idx > 0 ? path.slice(0, idx) : ''\n}\n\n/** Build a display-only directory tree from rows. */\nfunction buildTree(rows: GitChangeRow[]): Map<string, GitChangeRow[]> {\n const byDir = new Map<string, GitChangeRow[]>()\n for (const row of rows) {\n const dir = dirOf(row.path)\n const list = byDir.get(dir)\n if (list === undefined) byDir.set(dir, [row])\n else list.push(row)\n }\n return byDir\n}\n\n/** The SCM tab body.\n * @param stores - the panel store bundle.\n */\nexport function ScmPanel({ stores }: { stores: PanelStores }): JSX.Element {\n const scm = stores.scm\n const preview = stores.preview\n const state = useStore(scm)\n const [discardTargets, setDiscardTargets] = useState<GitChangeRow[] | null>(null)\n\n // Window focus refreshes (catches external editors writing the tree).\n // Throttled: a focus burst must not spawn a git status per event — the\n // fs watch (host) and the 30s host poll already cover the steady state.\n // -Infinity so the first focus after mount always fires (production\n // Date.now() is enormous anyway; the sentinel makes the throttle explicit\n // and testable at clock 0).\n const lastFocusRefresh = useRef(-Infinity)\n useEffect(() => {\n const onFocus = (): void => {\n const now = Date.now()\n if (now - lastFocusRefresh.current < FOCUS_REFRESH_MIN_MS) return\n lastFocusRefresh.current = now\n void scm.refresh()\n }\n window.addEventListener('focus', onFocus)\n return () => window.removeEventListener('focus', onFocus)\n }, [scm])\n\n const status = state.status\n const changesSectionOpen = state.sectionCollapsed['changes'] !== true\n\n const requestDiscard = (rows: GitChangeRow[]): void => {\n if (rows.length === 0) return\n setDiscardTargets(rows)\n }\n const confirmDiscard = (): void => {\n if (discardTargets === null) return\n void scm.discard(discardTargets.map((row) => row.path))\n setDiscardTargets(null)\n }\n\n if (state.loading && status === null) {\n return <div className={`filemgr-root ${scmCss.panel}`}><div className={scmCss.loading}>{t('scm.loading')}</div></div>\n }\n if (state.gitMissing) {\n return <div className={`filemgr-root ${scmCss.panel}`}><div className={scmCss.notRepo}>{t('scm.gitMissing')}</div></div>\n }\n if (status === null) {\n return <div className={`filemgr-root ${scmCss.panel}`}><div className={scmCss.notRepo}>{t('scm.notRepo')}</div></div>\n }\n\n const staged = status.staged\n const unstaged = status.unstaged\n const untracked = status.untracked\n const hasChanges = staged.length + unstaged.length + untracked.length > 0\n const allUntracked = discardTargets !== null && discardTargets.every((row) => row.state === 'untracked')\n\n return (\n <div className={`filemgr-root ${scmCss.panel}`}>\n {/* Changes section. */}\n <div className={scmCss.section} style={{ flex: changesSectionOpen ? 1 : undefined, maxHeight: changesSectionOpen ? undefined : 24 }}>\n <div\n className={scmCss.sectionHeader}\n onClick={() => scm.setSectionCollapsed('changes', changesSectionOpen)}\n onKeyDown={activateOnKey(() => { scm.setSectionCollapsed('changes', changesSectionOpen) })}\n role=\"button\"\n tabIndex={0}\n aria-expanded={changesSectionOpen}\n >\n <span className={`${scmCss.sectionChevron}${changesSectionOpen ? ` ${scmCss.sectionChevronOpen}` : ''}`}>\n <ChevronRightIcon size={13} />\n </span>\n <span className={scmCss.sectionTitle}>{t('scm.changes')}</span>\n {status.branch !== '' && (\n <span className={scmCss.branchName} style={{ fontSize: 11, color: 'var(--aion-text-tertiary)', display: 'flex', alignItems: 'center', gap: 4 }}>\n <BranchIcon size={12} />\n {status.branch}\n </span>\n )}\n <span\n style={{ display: 'flex', alignItems: 'center', gap: 2, marginLeft: 'auto' }}\n onClick={(event) => event.stopPropagation()}\n >\n <button\n type=\"button\"\n className={scmCss.sectionAction}\n title={t('scm.stageAll')}\n onClick={() => void scm.stage(unstaged.map((row) => row.path))}\n disabled={unstaged.length === 0}\n >\n <PlusIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.sectionAction}\n title={t('scm.discardAll')}\n onClick={() => requestDiscard([...unstaged, ...untracked])}\n disabled={unstaged.length + untracked.length === 0}\n >\n <UndoIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.sectionAction}\n title={t('scm.viewList')}\n style={{ color: state.viewMode === 'list' ? 'var(--aion-brand)' : undefined }}\n onClick={() => scm.setViewMode('list')}\n >\n <ListIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.sectionAction}\n title={t('scm.viewTree')}\n style={{ color: state.viewMode === 'tree' ? 'var(--aion-brand)' : undefined }}\n onClick={() => scm.setViewMode('tree')}\n >\n <TreeIcon size={13} />\n </button>\n </span>\n </div>\n\n {changesSectionOpen && (\n <div className={scmCss.sectionBody}>\n {!hasChanges && <div className={scmCss.empty}>{t('scm.empty')}</div>}\n {hasChanges && (\n <Group\n scm={scm}\n preview={preview}\n title={staged.length > 0 ? t('scm.staged') : undefined}\n rows={staged}\n bulkLabel={t('scm.unstage')}\n onBulk={(rows) => void scm.unstage(rows.map((row) => row.path))}\n onDiscard={requestDiscard}\n />\n )}\n {hasChanges && unstaged.length > 0 && (\n <Group\n scm={scm}\n preview={preview}\n rows={unstaged}\n bulkLabel={t('scm.stage')}\n onBulk={(rows) => void scm.stage(rows.map((row) => row.path))}\n onDiscard={requestDiscard}\n />\n )}\n {untracked.length > 0 && (\n <Group\n scm={scm}\n preview={preview}\n title={t('scm.untracked')}\n rows={untracked}\n bulkLabel={t('scm.stage')}\n onBulk={(rows) => void scm.stage(rows.map((row) => row.path))}\n onDiscard={requestDiscard}\n />\n )}\n </div>\n )}\n </div>\n\n {discardTargets !== null && (\n <ConfirmDialog\n title={t('scm.discard')}\n body={allUntracked\n ? format(t('scm.discardConfirmUntracked'), { count: discardTargets.length })\n : format(t('scm.discardConfirmTracked'), { count: discardTargets.length })}\n confirmLabel={t('common.delete')}\n danger\n onConfirm={confirmDiscard}\n onCancel={() => setDiscardTargets(null)}\n />\n )}\n </div>\n )\n}\n\n/** One change group (staged / unstaged / untracked) with list or tree body. */\nfunction Group({\n scm,\n preview,\n rows,\n title,\n bulkLabel,\n onBulk,\n onDiscard,\n}: {\n scm: PanelStores['scm']\n preview: PanelStores['preview']\n rows: GitChangeRow[]\n title?: string\n bulkLabel: string\n onBulk: (rows: GitChangeRow[]) => void\n onDiscard: (rows: GitChangeRow[]) => void\n}): JSX.Element {\n const state = useStore(scm)\n const tree = useMemo(() => buildTree(rows), [rows])\n const viewTree = state.viewMode === 'tree'\n const allActionable = rows.filter((row) => row.state !== 'conflicted')\n // O(1) lookups for row rendering: an includes() per row per array is\n // O(rows x ops) on every batch operation.\n const busySet = useMemo(() => new Set(state.busy), [state.busy])\n const failedSet = useMemo(() => new Set(state.failed), [state.failed])\n const expandedSet = useMemo(() => new Set(state.treeExpanded), [state.treeExpanded])\n\n return (\n <div>\n {title !== undefined && (\n <div className={scmCss.groupTitle}>\n {title}\n <button\n type=\"button\"\n className={scmCss.groupAction}\n title={bulkLabel}\n onClick={() => onBulk(allActionable)}\n disabled={allActionable.length === 0}\n >\n {bulkLabel === t('scm.unstage') ? <MinusIcon size={12} /> : <PlusIcon size={12} />}\n </button>\n </div>\n )}\n {viewTree ? (\n [...tree.entries()].map(([dir, dirRows]) => (\n <DirNode\n key={dir === '' ? '\\u0000' : dir}\n dir={dir}\n rows={dirRows}\n depth={0}\n state={state}\n expandedSet={expandedSet}\n busySet={busySet}\n failedSet={failedSet}\n scm={scm}\n preview={preview}\n onDiscard={onDiscard}\n />\n ))\n ) : (\n rows.map((row) => (\n <ChangeRow\n key={`${row.staged ? 's' : 'u'}:${row.path}`}\n row={row}\n state={state}\n busy={busySet.has(row.path)}\n failed={failedSet.has(row.path)}\n scm={scm}\n preview={preview}\n onDiscard={onDiscard}\n />\n ))\n )}\n </div>\n )\n}\n\n/** Tree-view directory node (expandable). */\nfunction DirNode({\n dir,\n rows,\n depth,\n state,\n expandedSet,\n busySet,\n failedSet,\n scm,\n preview,\n onDiscard,\n}: {\n dir: string\n rows: GitChangeRow[]\n depth: number\n state: ReturnType<PanelStores['scm']['getSnapshot']>\n expandedSet: ReadonlySet<string>\n busySet: ReadonlySet<string>\n failedSet: ReadonlySet<string>\n scm: PanelStores['scm']\n preview: PanelStores['preview']\n onDiscard: (rows: GitChangeRow[]) => void\n}): JSX.Element {\n const expanded = expandedSet.has(dir)\n const label = dir === '' ? '/' : dir.split('/').pop() ?? dir\n const toggleExpanded = (): void => {\n const next = expanded\n ? state.treeExpanded.filter((item) => item !== dir)\n : [...state.treeExpanded, dir]\n scm.setTreeExpanded(next)\n }\n return (\n <>\n <div\n className={scmCss.dirRow}\n style={{ paddingLeft: 12 + depth * 12 }}\n title={dir}\n role=\"button\"\n tabIndex={0}\n aria-expanded={expanded}\n onClick={toggleExpanded}\n onKeyDown={activateOnKey(toggleExpanded)}\n >\n <span className={`${scmCss.dirArrow}${expanded ? ` ${scmCss.dirArrowOpen}` : ''}`}>\n <ChevronRightIcon size={13} />\n </span>\n <FileTypeIcon name={label} isDir expanded={expanded} />\n <span style={{ fontSize: 13, color: 'var(--aion-text-primary)' }}>{label}</span>\n </div>\n {expanded &&\n rows.map((row) => (\n <ChangeRow\n key={`${row.staged ? 's' : 'u'}:${row.path}`}\n row={row}\n state={state}\n busy={busySet.has(row.path)}\n failed={failedSet.has(row.path)}\n scm={scm}\n preview={preview}\n onDiscard={onDiscard}\n indent={depth + 1}\n hideDir\n />\n ))}\n </>\n )\n}\n\n/** One change row: badge + name + dimmed dir + hover actions.\n * Clicking the row opens the path's diff in the preview panel (every state\n * has a diff — deleted rows show the removal, untracked rows a new-file diff).\n */\nfunction ChangeRow({\n row,\n state,\n busy,\n failed,\n scm,\n preview,\n onDiscard,\n indent = 0,\n hideDir = false,\n}: {\n row: GitChangeRow\n state: ReturnType<PanelStores['scm']['getSnapshot']>\n busy: boolean\n failed: boolean\n scm: PanelStores['scm']\n preview: PanelStores['preview']\n onDiscard: (rows: GitChangeRow[]) => void\n indent?: number\n hideDir?: boolean\n}): JSX.Element {\n const badge = BADGE[row.state] ?? BADGE.unknown\n const conflicted = row.state === 'conflicted'\n const displayName = row.oldPath !== undefined ? `${row.oldPath.split('/').pop()} -> ${row.path.split('/').pop()}` : (row.path.split('/').pop() ?? row.path)\n const dir = dirOf(row.path)\n\n const openInPreview = (): void => {\n scm.select(row.path)\n // Staged rows diff the index against HEAD; unstaged rows the worktree\n // against the index — the side the row was listed under.\n preview.openDiff(state.root, row.path, row.staged)\n }\n\n return (\n <div\n className={`${scmCss.changeRow}${state.selected === row.path ? ` ${scmCss.changeRowSelected}` : ''}${failed ? ` ${scmCss.rowFailed}` : ''}`}\n style={{ paddingLeft: 12 + indent * 12 }}\n title={row.path}\n onClick={openInPreview}\n onKeyDown={activateOnKey(openInPreview)}\n role=\"button\"\n tabIndex={0}\n >\n <span className={`${scmCss.badge} ${badge.className}`}>{badge.letter}</span>\n <span className={scmCss.changeName}>{displayName}</span>\n {!hideDir && dir !== '' && <span className={scmCss.changeDir}>{dir}</span>}\n <span className={`${scmCss.rowActions}${busy || failed ? ` ${scmCss.rowActionsVisible}` : ''}`}>\n {conflicted ? null : row.staged ? (\n <>\n <button\n type=\"button\"\n className={scmCss.rowAction}\n title={t('scm.unstage')}\n disabled={busy}\n onClick={(event) => { event.stopPropagation(); void scm.unstage([row.path]) }}\n >\n <MinusIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.rowAction}\n title={t('scm.discard')}\n disabled={busy}\n onClick={(event) => { event.stopPropagation(); onDiscard([row]) }}\n >\n <UndoIcon size={13} />\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n className={scmCss.rowAction}\n title={t('scm.stage')}\n disabled={busy}\n onClick={(event) => { event.stopPropagation(); void scm.stage([row.path]) }}\n >\n <PlusIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.rowAction}\n title={t('scm.discard')}\n disabled={busy}\n onClick={(event) => { event.stopPropagation(); onDiscard([row]) }}\n >\n <UndoIcon size={13} />\n </button>\n </>\n )}\n </span>\n </div>\n )\n}\n","/**\n * Pure drag-to-composer helpers shared by the explorer rows (the drag\n * source) and the composer dock inlay (the drop target): the custom MIME\n * type, the drag-state detector, and the draft-splicing rule. Deliberately\n * framework-free so the splicing math is unit-testable in isolation.\n *\n * The composer host only accepts OS image drops (its document-level drop\n * handler checks `dataTransfer.types` for `Files` and routes through the\n * image pipeline), so a workspace file needs its own MIME. A plain relative\n * path is inserted into the draft — the agent reads the file through its\n * existing tools without any prefix grammar.\n * @module dsh-filemgr/client/drag/file-drag\n */\n\n/** Custom MIME carrying a workspace-relative file path. */\nexport const FILE_DRAG_MIME = 'application/x-dsh-file'\n\n/**\n * Whether a drag event carries our file payload.\n * @param types - the live `dataTransfer.types` list (read-only during drag).\n * @returns true when our MIME is present.\n */\nexport function hasFileDrag(types: readonly string[] | undefined): boolean {\n return types !== undefined && types.includes(FILE_DRAG_MIME)\n}\n\n/**\n * Whether a drop payload is a plausible workspace-relative path. The custom\n * MIME only proves the drag carries *some* string — a foreign page can set it\n * too, so the payload itself is validated before it reaches the draft:\n * relative POSIX shape only; no absolute paths, no '..' segments, no\n * backslashes, no control characters, and a sane length.\n * @param path - the raw payload from dataTransfer.\n * @returns true when the payload is safe to splice into the draft.\n */\nexport function isValidFileDragPayload(path: string): boolean {\n if (path === '' || path.length > 512) return false\n if (path.startsWith('/') || path.includes('\\\\')) return false\n // eslint-disable-next-line no-control-regex\n if (/[\\x00-\\x1f\\x7f]/.test(path)) return false\n if (path.split('/').some(segment => segment === '..')) return false\n return true\n}\n\n/**\n * Splice a workspace-relative path into a composer draft at the caret.\n *\n * Separator rule: one space is added before the path unless the caret sits\n * at the start of the draft or right after whitespace; one space is added\n * after the path unless the caret sits at the end of the draft or right\n * before whitespace. Empty path or an out-of-range caret are no-ops.\n *\n * @param draft - the current draft text.\n * @param path - the relative path to insert.\n * @param caret - insertion offset (default: the end of the draft).\n * @returns the next draft; the caller owns writing it through the input\n * facade.\n */\nexport function insertPathIntoDraft(draft: string, path: string, caret?: number): string {\n if (path === '') return draft\n const at = caret === undefined ? draft.length : Math.min(Math.max(caret, 0), draft.length)\n const before = draft.slice(0, at)\n const after = draft.slice(at)\n const needBefore = before !== '' && !/\\s$/.test(before)\n const needAfter = after !== '' && !/^\\s/.test(after)\n return before + (needBefore ? ' ' : '') + path + (needAfter ? ' ' : '') + after\n}\n","/**\n * The Explorer column: Files/Changes tab bar (37px), the persistent filename\n * search at the top of the Files tab (150ms debounced; a hit click REVEALS\n * the file in the tree — expand ancestors + select — never opens preview),\n * the lazy file tree (34px rows, full-row expand/collapse, 16px icons), and\n * the in-column collapse chevron.\n *\n * FileManager Explorer behavior (Apache-2.0, re-implemented): row click toggles\n * folders (no need to hit the arrow), search results are reveal-only, and\n * clicking a file opens it in the preview panel (dedup focuses the tab).\n * @module dsh-filemgr/client/components/ExplorerPanel\n */\n\nimport { memo, useCallback, useMemo, useRef, useState } from 'react'\nimport type { DragEvent, JSX, MouseEvent as ReactMouseEvent } from 'react'\nimport type { FsEntry } from '../../core/types.ts'\nimport { parentRel } from '../fileType.ts'\nimport { t } from '../locales.ts'\nimport { useStore } from '../hooks/useStore.ts'\nimport type { PanelStores } from '../store.ts'\nimport { FileTypeIcon } from './FileIcon.tsx'\nimport { ChevronRightIcon, CloseIcon, ExpandRightIcon, MaximizeIcon, RestoreIcon, SearchIcon } from './icons.tsx'\nimport { ConfirmDialog, ContextMenu, PromptDialog, toast, type MenuEntry, type MenuState } from './overlay.tsx'\nimport { ScmPanel } from './ScmPanel.tsx'\nimport { activateOnKey } from './a11y.ts'\nimport { FILE_DRAG_MIME } from '../drag/file-drag.ts'\nimport explorerCss from '../styles/explorer.module.css'\nimport '../styles/tokens.module.css'\n\n/** Row indent step per tree depth (px). */\nconst INDENT_STEP = 16\n\n/**\n * The whole explorer column content.\n * @param stores - the panel store bundle.\n * @param onToggleCollapse - collapse the column (host chrome).\n */\nexport function ExplorerPanel({\n stores,\n onToggleCollapse,\n onReference,\n}: {\n stores: PanelStores\n onToggleCollapse: () => void\n onReference: (path: string, isDir: boolean) => void\n}): JSX.Element {\n const state = useStore(stores.explorer)\n const layoutState = useStore(stores.layout)\n const maximizedExplorer = layoutState.maximized === 'explorer'\n const [searchFocus, setSearchFocus] = useState(false)\n const [menu, setMenu] = useState<MenuState | null>(null)\n const [prompt, setPrompt] = useState<{\n kind: 'rename' | 'newFile' | 'newFolder'\n targetRel: string\n initialValue: string\n } | null>(null)\n const [deleteTarget, setDeleteTarget] = useState<FsEntry | null>(null)\n\n /** Absolute path of one entry (root + rel), for copy/reveal. */\n const absolutePath = (entry: FsEntry): string => {\n const basePath = state.root.replace(/[\\\\/]+$/, '')\n const sep = state.root.includes('\\\\') ? '\\\\' : '/'\n return entry.path === '' ? basePath : `${basePath}${sep}${entry.path.split('/').join(sep)}`\n }\n\n const copyText = async (text: string): Promise<void> => {\n try {\n await navigator.clipboard.writeText(text)\n toast(t('common.copied'))\n } catch {\n toast(t('explorer.opFailed'))\n }\n }\n\n /**\n * Open the file-tree context menu. Stable across re-renders (useCallback\n * on root + stores) so the memoized tree rows do not re-render when the\n * panel state changes.\n */\n const openMenu = useCallback((event: ReactMouseEvent, entry: FsEntry): void => {\n event.preventDefault()\n event.stopPropagation()\n const explorerStore = stores.explorer\n explorerStore.select(entry.path)\n const parent = parentRel(entry.path)\n const createTarget = entry.isDir ? entry.path : parent\n const entries: MenuEntry[] = [\n {\n key: 'copy-path',\n label: t('explorer.menu.copyPath'),\n onSelect: () => void copyText(absolutePath(entry)),\n },\n {\n key: 'copy-name',\n label: t('explorer.menu.copyName'),\n onSelect: () => void copyText(entry.name),\n },\n { key: 'sep-1', label: '---' },\n {\n key: 'reveal',\n label: t('explorer.menu.reveal'),\n onSelect: () => {\n void explorerStore.revealInFileManager(entry.path).then((ok) => {\n if (!ok) toast(t('explorer.opFailed'))\n })\n },\n },\n ]\n if (!entry.isDir) {\n entries.push({\n key: 'open-with-default',\n label: t('explorer.menu.openWithDefault'),\n onSelect: () => {\n void explorerStore.openWithDefaultApp(entry.path).then((ok) => {\n if (!ok) toast(t('explorer.opFailed'))\n })\n },\n })\n }\n entries.push(\n { key: 'sep-2', label: '---' },\n {\n key: 'rename',\n label: t('explorer.menu.rename'),\n onSelect: () => setPrompt({ kind: 'rename', targetRel: entry.path, initialValue: entry.name }),\n },\n {\n key: 'new-file',\n label: t('explorer.menu.newFile'),\n onSelect: () => setPrompt({ kind: 'newFile', targetRel: createTarget, initialValue: '' }),\n },\n {\n key: 'new-folder',\n label: t('explorer.menu.newFolder'),\n onSelect: () => setPrompt({ kind: 'newFolder', targetRel: createTarget, initialValue: '' }),\n },\n { key: 'sep-3', label: '---' },\n {\n key: 'delete',\n label: t('explorer.menu.delete'),\n danger: true,\n onSelect: () => setDeleteTarget(entry),\n },\n )\n setMenu({ x: event.clientX, y: event.clientY, entries })\n }, [state.root, stores])\n\n const submitPrompt = (value: string): void => {\n if (prompt === null) return\n const { kind, targetRel } = prompt\n const name = value.trim()\n if (name === '') return\n const op = kind === 'rename'\n ? stores.explorer.renameEntry(prompt.targetRel, name)\n : kind === 'newFolder'\n ? stores.explorer.createDir(targetRel === '' ? name : `${targetRel}/${name}`)\n : stores.explorer.createFile(targetRel === '' ? name : `${targetRel}/${name}`)\n void op.then((ok) => {\n if (!ok) toast(t('explorer.opFailed'))\n })\n setPrompt(null)\n }\n\n return (\n <div className=\"filemgr-root\" style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>\n {/* The Files/Changes tab bar. */}\n <div className={explorerCss.tabBar}>\n <button\n type=\"button\"\n className={state.activeTab === 'files' ? explorerCss.tabBtnActive : explorerCss.tabBtn}\n onClick={() => stores.explorer.setActiveTab('files')}\n >\n {t('explorer.tabs.files')}\n </button>\n <button\n type=\"button\"\n className={state.activeTab === 'changes' ? explorerCss.tabBtnActive : explorerCss.tabBtn}\n onClick={() => stores.explorer.setActiveTab('changes')}\n >\n {t('explorer.tabs.changes')}\n </button>\n {/* Maximize/restore (issue #315): transient — the layout controller\n owns the grid takeover, Esc and the restore path. */}\n <button\n type=\"button\"\n className={explorerCss.tabIconBtn}\n style={{ marginLeft: 'auto' }}\n onClick={() => {\n stores.layout.update((prev) => ({ ...prev, maximized: maximizedExplorer ? null : 'explorer' }))\n }}\n title={t(maximizedExplorer ? 'explorer.restore' : 'explorer.maximize')}\n aria-label={t(maximizedExplorer ? 'explorer.restore' : 'explorer.maximize')}\n >\n {maximizedExplorer ? <RestoreIcon size={14} /> : <MaximizeIcon size={14} />}\n </button>\n <button\n type=\"button\"\n className=\"filemgr-collapse-chevron\"\n onClick={onToggleCollapse}\n title={t('explorer.collapse')}\n aria-label={t('explorer.collapse')}\n >\n <ExpandRightIcon size={16} />\n </button>\n </div>\n\n {/* Files tab: search + tree (kept mounted; hidden when changes is active). */}\n <div style={{ display: state.activeTab === 'files' ? 'flex' : 'none', flexDirection: 'column', flex: 1, minHeight: 0 }}>\n <SearchArea\n stores={stores}\n searchFocus={searchFocus}\n onFocusChange={setSearchFocus}\n />\n <FileTree stores={stores} onContextMenu={openMenu} onReference={onReference} />\n </div>\n\n {/* Changes tab: SCM (mounted on demand; its store outlives the tab). */}\n {state.activeTab === 'changes' && <ScmPanel stores={stores} />}\n\n {/* Right-click menu + dialogs (portaled). */}\n <ContextMenu state={menu} onClose={() => setMenu(null)} />\n {prompt !== null && (\n <PromptDialog\n title={t(prompt.kind === 'rename' ? 'explorer.rename.title' : prompt.kind === 'newFolder' ? 'explorer.newFolder.title' : 'explorer.newFile.title')}\n initialValue={prompt.initialValue}\n onConfirm={submitPrompt}\n onCancel={() => setPrompt(null)}\n />\n )}\n {deleteTarget !== null && (\n <ConfirmDialog\n title={t('explorer.deleteConfirmTitle')}\n body={t('explorer.deleteConfirmBody', { name: deleteTarget.name })}\n danger\n onConfirm={() => {\n const target = deleteTarget\n setDeleteTarget(null)\n void stores.explorer.deleteEntry(target.path).then((ok) => {\n if (!ok) toast(t('explorer.opFailed'))\n })\n }}\n onCancel={() => setDeleteTarget(null)}\n />\n )}\n </div>\n )\n}\n\n/** The search box + results (the tree stays mounted underneath). */\nfunction SearchArea({\n stores,\n searchFocus,\n onFocusChange,\n}: {\n stores: PanelStores\n searchFocus: boolean\n onFocusChange: (focused: boolean) => void\n}): JSX.Element {\n const explorer = stores.explorer\n const state = useStore(explorer)\n const search = state.search\n const active = search.query !== ''\n const inputRef = useRef<HTMLInputElement>(null)\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', minHeight: 0, flex: active ? 1 : undefined }}>\n <div className={explorerCss.searchArea}>\n <div\n className={`${explorerCss.searchBox}${searchFocus ? ` ${explorerCss.searchAreaFocus}` : ''}`}\n style={{ borderColor: searchFocus ? 'var(--aion-primary)' : undefined }}\n >\n <span className={explorerCss.searchIcon}><SearchIcon size={14} /></span>\n <input\n ref={inputRef}\n className={explorerCss.searchInput}\n value={search.query}\n placeholder={t('explorer.search.placeholder')}\n aria-label={t('explorer.search.placeholder')}\n onFocus={() => onFocusChange(true)}\n onBlur={() => onFocusChange(false)}\n onChange={(event) => explorer.setSearchQuery(event.target.value)}\n />\n {search.query !== '' && (\n <button\n type=\"button\"\n className={explorerCss.searchClear}\n onClick={() => { explorer.cancelSearch(); inputRef.current?.focus() }}\n aria-label={t('common.close')}\n >\n <CloseIcon size={12} />\n </button>\n )}\n </div>\n </div>\n\n {/* Result list replaces the tree while the query is active (the tree\n underneath stays mounted — subscriptions never thrash). */}\n {active ? (\n <SearchResults stores={stores} />\n ) : null}\n </div>\n )\n}\n\n/** The flat search-result stream (click = reveal in tree). */\nfunction SearchResults({ stores }: { stores: PanelStores }): JSX.Element {\n const explorer = stores.explorer\n const state = useStore(explorer)\n const search = state.search\n return (\n <div className={explorerCss.scrollArea}>\n {search.status === 'searching' && search.hits.length === 0 && (\n <div className={explorerCss.searchStatus}>{t('explorer.search.searching')}</div>\n )}\n {search.status === 'error' && <div className={explorerCss.searchStatus}>{t('explorer.search.error')}</div>}\n {search.status === 'done' && search.hits.length === 0 && (\n <div className={explorerCss.searchStatus}>{t('explorer.search.empty')}</div>\n )}\n {search.hits.map((hit) => (\n <div\n key={hit.path}\n className={explorerCss.resultRow}\n role=\"button\"\n tabIndex={0}\n title={hit.path}\n onClick={() => {\n // Reveal: expand the ancestor chain and select — not preview.\n explorer.reveal(hit.path)\n }}\n onKeyDown={activateOnKey(() => { explorer.reveal(hit.path) })}\n >\n <FileTypeIcon name={hit.name} isDir={hit.isDir} expanded={false} />\n <span className={explorerCss.resultName}>{hit.name}</span>\n <span className={explorerCss.resultPath}>{parentRel(hit.path)}</span>\n </div>\n ))}\n {search.truncated && search.hits.length > 0 && (\n <div className={explorerCss.searchStatus}>{t('explorer.search.truncated', { count: search.hits.length })}</div>\n )}\n </div>\n )\n}\n\n/** The lazy file tree. */\nfunction FileTree({\n stores,\n onContextMenu,\n onReference,\n}: {\n stores: PanelStores\n onContextMenu: (event: ReactMouseEvent, entry: FsEntry) => void\n onReference: (path: string, isDir: boolean) => void\n}): JSX.Element {\n const explorer = stores.explorer\n const preview = stores.preview\n const state = useStore(explorer)\n const root = state.root\n // One Set per expansion change: O(1) membership for rows, and the memo\n // comparator below can compare membership instead of array identity.\n // (Hooks precede the early returns below.)\n const expandedSet = useMemo(() => new Set(state.expanded), [state.expanded])\n\n if (root === '') return <div className={explorerCss.emptyState}>{t('explorer.tree.empty')}</div>\n const entries = state.dirs['']\n if (entries === undefined) {\n return <div className={explorerCss.searchStatus}>{t('scm.loading')}</div>\n }\n if (entries.length === 0) return <div className={explorerCss.emptyState}>{t('explorer.tree.empty')}</div>\n\n return (\n <div className={`${explorerCss.scrollArea} ${explorerCss.tree}`}>\n {entries.map((entry) => (\n <TreeRow\n key={entry.path}\n entry={entry}\n depth={0}\n expanded={expandedSet}\n selected={state.selected}\n dirs={state.dirs}\n root={state.root}\n stores={stores}\n onContextMenu={onContextMenu}\n onReference={onReference}\n />\n ))}\n </div>\n )\n}\n\n/** One tree row (recursive for children). */\nfunction TreeRowBase({\n entry,\n depth,\n expanded,\n selected,\n dirs,\n root,\n stores,\n onContextMenu,\n onReference,\n}: {\n entry: FsEntry\n depth: number\n expanded: ReadonlySet<string>\n selected: string | null\n dirs: Record<string, FsEntry[]>\n root: string\n stores: PanelStores\n onContextMenu: (event: ReactMouseEvent, entry: FsEntry) => void\n onReference: (path: string, isDir: boolean) => void\n}): JSX.Element {\n const explorer = stores.explorer\n const preview = stores.preview\n const isExpanded = expanded.has(entry.path)\n const isSelected = selected === entry.path\n const children = entry.isDir ? dirs[entry.path] : undefined\n const [draggingRow, setDraggingRow] = useState(false)\n\n const handleClick = (): void => {\n if (entry.isDir) {\n // Full-row expand/collapse toggle.\n explorer.toggleDir(entry.path)\n return\n }\n // A file: select + open in preview (dedup focuses the open tab).\n explorer.select(entry.path)\n preview.openFile(root, entry.path)\n }\n\n // Files are draggable into the composer (the drag MIME carries the\n // workspace-relative path); directory rows stay click-only.\n const onDragStart = (event: DragEvent): void => {\n if (entry.isDir) return\n event.dataTransfer.setData(FILE_DRAG_MIME, entry.path)\n event.dataTransfer.setData('text/plain', entry.path)\n event.dataTransfer.effectAllowed = 'copy'\n setDraggingRow(true)\n }\n const onDragEnd = (): void => {\n setDraggingRow(false)\n }\n\n return (\n <>\n <div\n className={`${explorerCss.treeRow}${isSelected ? ` ${explorerCss.treeRowSelected}` : ''}${draggingRow ? ` ${explorerCss.treeRowDragging}` : ''}`}\n style={{ paddingLeft: 12 + 8 + depth * INDENT_STEP }}\n onClick={handleClick}\n onKeyDown={activateOnKey(handleClick)}\n onContextMenu={(event) => onContextMenu(event, entry)}\n onDoubleClick={(event) => {\n // Double-click on a file: same as click (open). Folders: keep toggle.\n event.stopPropagation()\n }}\n draggable={!entry.isDir}\n onDragStart={onDragStart}\n onDragEnd={onDragEnd}\n role=\"button\"\n tabIndex={0}\n aria-expanded={entry.isDir ? isExpanded : undefined}\n title={entry.path}\n >\n {entry.isDir ? (\n <span className={`${explorerCss.treeArrow}${isExpanded ? ` ${explorerCss.treeArrowOpen}` : ''}`}>\n <ChevronRightIcon size={13} />\n </span>\n ) : (\n <span className={explorerCss.treeArrowEmpty} />\n )}\n <FileTypeIcon name={entry.name} isDir={entry.isDir} expanded={isExpanded} />\n <span className={explorerCss.treeName}>{entry.name}</span>\n <button\n type=\"button\"\n className={explorerCss.refBtn}\n title={t('explorer.refToInput')}\n aria-label={t('explorer.refToInput')}\n onClick={(event) => {\n // Insert a file-reference chip (or plain text for folders).\n event.stopPropagation()\n event.preventDefault()\n onReference(entry.path, entry.isDir)\n }}\n onMouseDown={(event) => event.stopPropagation()}\n >\n @\n </button>\n </div>\n {entry.isDir && isExpanded && children !== undefined && (\n <div>\n {children.map((child) => (\n <TreeRow\n key={child.path}\n entry={child}\n depth={depth + 1}\n expanded={expanded}\n selected={selected}\n dirs={dirs}\n root={root}\n stores={stores}\n onContextMenu={onContextMenu}\n onReference={onReference}\n />\n ))}\n </div>\n )}\n </>\n )\n}\n\n/**\n * A memoized tree row so the whole tree does not re-render on every explorer\n * state change (search keystrokes, tab switches, fs version bumps). The row\n * takes the `state` fields it actually reads as individual props — `expanded`,\n * `selected`, `dirs` — whose references only change when the corresponding\n * data changed, so the default shallow comparison skips rows whose own entry,\n * ancestor, expansion or selection are unaffected. A `dirs` re-fetch (an fs\n * event that relists the expanded dirs) still re-renders the rows under those\n * dirs — the unavoidable O(open-dirs) cost — but transient UI state no longer\n * invalidates the tree.\n */\nconst TreeRow = memo(TreeRowBase, (prev, next) =>\n // The expansion array gets a fresh identity on every toggle; what this row\n // actually reads is its own membership, so compare that instead of the\n // container — plus the other props by identity.\n prev.expanded.has(prev.entry.path) === next.expanded.has(next.entry.path)\n && prev.entry === next.entry\n && prev.depth === next.depth\n && prev.selected === next.selected\n && prev.dirs === next.dirs\n && prev.root === next.root\n && prev.stores === next.stores\n && prev.onContextMenu === next.onContextMenu\n && prev.onReference === next.onReference,\n)\n","/**\n * The preview tab strip: 36px bar, tabs capped at 180px (padding 0 10, gap 6,\n * 12px title), dirty dot (6px, primary), close glyph (16px box, 12px icon),\n * middle-click close, right-click menu (close left/right/others/all), the\n * 32px left/right overflow fade indicators (ResizeObserver + scroll), the\n * new-URL-tab plus, and the panel collapse button.\n * @module dsh-filemgr/client/preview/PreviewTabs\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport type { PreviewTabState } from '../store.ts'\nimport { t } from '../locales.ts'\nimport { CloseIcon, MaximizeIcon, PlusIcon, RestoreIcon, ShrinkIcon } from '../components/icons.tsx'\nimport { activateOnKey } from '../components/a11y.ts'\nimport previewCss from '../styles/preview.module.css'\n\n/** Tab width cap (FileManager measured). */\nexport const MAX_TAB_WIDTH_PX = 180\n/** Fade indicator width. */\nconst FADE_WIDTH = 32\n\n/** Left/right overflow state. */\nexport interface TabFadeState {\n left: boolean\n right: boolean\n}\n\n/** The tab strip. */\nexport function PreviewTabs({\n tabs,\n activeTabId,\n onSwitch,\n onClose,\n onContextMenu,\n onNewUrlTab,\n onClosePanel,\n maximized,\n onMaximize,\n}: {\n tabs: PreviewTabState[]\n activeTabId: string | null\n onSwitch: (id: string) => void\n onClose: (id: string) => void\n onContextMenu: (event: React.MouseEvent, tab: PreviewTabState) => void\n onNewUrlTab: () => void\n onClosePanel: () => void\n maximized: boolean\n onMaximize: () => void\n}): JSX.Element {\n const scrollRef = useRef<HTMLDivElement>(null)\n const [fade, setFade] = useState<TabFadeState>({ left: false, right: false })\n\n // Overflow fades: ResizeObserver + scroll listener, setState only on change.\n useEffect(() => {\n const el = scrollRef.current\n if (el === null) return\n const update = (): void => {\n const next = {\n left: el.scrollLeft > 1,\n right: el.scrollLeft + el.clientWidth < el.scrollWidth - 1,\n }\n setFade((prev) => (prev.left === next.left && prev.right === next.right ? prev : next))\n }\n const observer = new ResizeObserver(update)\n observer.observe(el)\n el.addEventListener('scroll', update, { passive: true })\n window.addEventListener('resize', update)\n update()\n return () => {\n observer.disconnect()\n el.removeEventListener('scroll', update)\n window.removeEventListener('resize', update)\n }\n }, [tabs.length])\n\n return (\n <div className={previewCss.tabBar}>\n <div ref={scrollRef} className={previewCss.tabScroll}>\n {tabs.length === 0 && <div className={previewCss.noTabs}>{t('preview.noTabs')}</div>}\n {tabs.map((tab) => (\n <div\n key={tab.id}\n className={`${previewCss.tab}${tab.id === activeTabId ? ` ${previewCss.tabActive}` : ` ${previewCss.tabInactive}`}`}\n style={{ maxWidth: MAX_TAB_WIDTH_PX }}\n role=\"button\"\n tabIndex={0}\n title={tab.path}\n aria-label={tab.title}\n onClick={() => onSwitch(tab.id)}\n onKeyDown={activateOnKey(() => { onSwitch(tab.id) })}\n onContextMenu={(event) => onContextMenu(event, tab)}\n onAuxClick={(event) => {\n if (event.button !== 1) return\n event.preventDefault()\n event.stopPropagation()\n onClose(tab.id)\n }}\n >\n <span className={previewCss.tabTitle} title={tab.path}>{tab.title}</span>\n {tab.dirty && <span className={previewCss.tabDotDirty} title={t('preview.dirty')} />}\n <span\n className={previewCss.tabClose}\n role=\"button\"\n tabIndex={0}\n title={t('common.close')}\n aria-label={t('common.close')}\n onClick={(event) => {\n event.stopPropagation()\n onClose(tab.id)\n }}\n onKeyDown={activateOnKey(() => { onClose(tab.id) })}\n >\n <CloseIcon size={12} />\n </span>\n </div>\n ))}\n <div\n className={previewCss.tabPlus}\n role=\"button\"\n tabIndex={0}\n onClick={onNewUrlTab}\n onKeyDown={activateOnKey(onNewUrlTab)}\n title={t('preview.newUrlTab')}\n >\n <PlusIcon size={14} />\n </div>\n </div>\n <div className={previewCss.tabBarRight}>\n {/* Maximize/restore (issue #315): the layout controller owns the grid\n takeover, Esc and the restore path. */}\n <div\n className={previewCss.panelMaximize}\n role=\"button\"\n tabIndex={0}\n onClick={onMaximize}\n onKeyDown={activateOnKey(onMaximize)}\n title={t(maximized ? 'preview.restore' : 'preview.maximize')}\n aria-label={t(maximized ? 'preview.restore' : 'preview.maximize')}\n >\n {maximized ? <RestoreIcon size={14} /> : <MaximizeIcon size={14} />}\n </div>\n <div\n className={previewCss.panelCollapse}\n role=\"button\"\n tabIndex={0}\n onClick={onClosePanel}\n onKeyDown={activateOnKey(onClosePanel)}\n title={t('preview.collapsePanel')}\n aria-label={t('preview.collapsePanel')}\n >\n <ShrinkIcon size={14} />\n </div>\n </div>\n {fade.left && <div className={previewCss.tabFadeLeft} style={{ width: FADE_WIDTH }} />}\n {fade.right && <div className={previewCss.tabFadeRight} style={{ width: FADE_WIDTH }} />}\n </div>\n )\n}\n","/**\n * The preview toolbar: 32px bar (padding 0 10). Left: source/preview toggle\n * (markdown/html), split-screen toggle (editable types), download. Right: the\n * refresh button (4-state: hidden/disabled/idle/updated — never a dead\n * button) and save (editable + dirty, Cmd/Ctrl+S too).\n * @module dsh-filemgr/client/preview/PreviewToolbar\n */\n\nimport type { JSX } from 'react'\nimport type { PreviewContentType } from '../../core/types.ts'\nimport { isEditableType } from '../fileType.ts'\nimport { t } from '../locales.ts'\nimport { CodeIcon, DownloadIcon, EyeIcon, RefreshIcon, SaveIcon, SplitIcon } from '../components/icons.tsx'\nimport previewCss from '../styles/preview.module.css'\n\n/** Refresh button states (FileManager's 4-state machine). */\nexport type RefreshState = 'hidden' | 'disabled' | 'idle' | 'updated'\n\n/** Derive the refresh state for one tab. */\nexport function refreshStateFor(\n contentType: PreviewContentType,\n hasContent: boolean,\n loading: boolean,\n updated: boolean,\n): RefreshState {\n // URL tabs reload their frame (cross-origin documents can only be\n // re-navigated to the tab's address, never reloaded in place).\n if (contentType === 'url') return 'idle'\n if (contentType === 'word' || contentType === 'excel'\n || contentType === 'ppt' || contentType === 'unsupported' || contentType === 'image') {\n return 'hidden'\n }\n if (!hasContent || loading) return 'disabled'\n return updated ? 'updated' : 'idle'\n}\n\n/** Download the current tab's content as a file. */\nexport function downloadTab(tab: { title: string; content: string | null; contentType: PreviewContentType }): void {\n if (tab.content === null) return\n const isDataUrl = tab.content.startsWith('data:')\n // Pdf tabs hold a same-origin raw-route URL: anchor it directly (the\n // download attribute forces a save), no blob copy needed.\n const isRouteUrl = tab.content.startsWith('/filemgr/raw')\n const href = isDataUrl || isRouteUrl\n ? tab.content\n : URL.createObjectURL(new Blob([tab.content], { type: 'text/plain;charset=utf-8' }))\n const anchor = document.createElement('a')\n anchor.href = href\n anchor.download = tab.title\n anchor.style.display = 'none'\n document.body.appendChild(anchor)\n anchor.click()\n anchor.remove()\n if (!isDataUrl && !isRouteUrl) setTimeout(() => URL.revokeObjectURL(href), 10_000)\n}\n\n/** The toolbar. */\nexport function PreviewToolbar({\n contentType,\n hasContent,\n loading,\n dirty,\n updated,\n viewMode,\n canToggleView,\n split,\n canSplit,\n onViewModeChange,\n onSplitChange,\n onRefresh,\n onSave,\n onDownload,\n}: {\n contentType: PreviewContentType\n hasContent: boolean\n loading: boolean\n dirty: boolean\n updated: boolean\n viewMode: 'source' | 'preview'\n canToggleView: boolean\n split: boolean\n canSplit: boolean\n onViewModeChange: (mode: 'source' | 'preview') => void\n onSplitChange: (split: boolean) => void\n onRefresh: () => void\n onSave: () => void\n onDownload: () => void\n}): JSX.Element {\n const refreshState = refreshStateFor(contentType, hasContent, loading, updated)\n const editable = isEditableType(contentType)\n\n return (\n <div className={previewCss.toolbar}>\n {canToggleView && (\n <>\n <button\n type=\"button\"\n className={`${previewCss.toolbarBtn}${viewMode === 'source' ? ` ${previewCss.toolbarBtnActive}` : ''}`}\n onClick={() => onViewModeChange('source')}\n >\n <CodeIcon size={13} />\n {t('preview.source')}\n </button>\n <button\n type=\"button\"\n className={`${previewCss.toolbarBtn}${viewMode === 'preview' ? ` ${previewCss.toolbarBtnActive}` : ''}`}\n onClick={() => onViewModeChange('preview')}\n >\n <EyeIcon size={13} />\n {t('preview.preview')}\n </button>\n </>\n )}\n {canSplit && (\n <button\n type=\"button\"\n className={`${previewCss.toolbarBtn}${split ? ` ${previewCss.toolbarBtnActive}` : ''}`}\n title={t('preview.split')}\n onClick={() => onSplitChange(!split)}\n >\n <SplitIcon size={13} />\n {t('preview.split')}\n </button>\n )}\n <button\n type=\"button\"\n className={previewCss.toolbarBtn}\n title={t('preview.download')}\n disabled={!hasContent}\n onClick={onDownload}\n >\n <DownloadIcon size={13} />\n </button>\n <span className={previewCss.toolbarSpacer} />\n {refreshState !== 'hidden' && (\n <button\n type=\"button\"\n className={`${previewCss.toolbarBtn}${refreshState === 'updated' ? ` ${previewCss.toolbarBtnWarn}` : ''}`}\n title={refreshState === 'updated' ? t('preview.refresh.updated') : t('preview.refresh')}\n disabled={refreshState === 'disabled'}\n onClick={onRefresh}\n >\n <RefreshIcon size={13} />\n {t('preview.refresh')}\n </button>\n )}\n {editable && dirty && (\n <button\n type=\"button\"\n className={previewCss.toolbarBtn}\n onClick={onSave}\n disabled={loading}\n >\n <SaveIcon size={13} />\n {t('preview.save')}\n </button>\n )}\n </div>\n )\n}\n","/**\n * The panel system's single drag engine hook — a thin React wrapper over the\n * framework-free machinery in drag.ts (FileManager's useResizableSplit\n * architecture, re-implemented): px or ratio units, range-validated\n * localStorage persistence, double-click reset to the default width.\n * @module dsh-filemgr/client/hooks/useResizableSplit\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PointerEvent as ReactPointerEvent } from 'react'\nimport { handlePointerDragStart } from '../drag.ts'\nimport { readStoredNumber, writeStoredNumber } from '../persist.ts'\n\nexport interface UseResizableSplitOptions {\n /** Default width (px or percent). */\n defaultWidth?: number\n /** Minimum (same unit). */\n minWidth?: number\n /** Maximum (same unit). */\n maxWidth?: number\n /** localStorage key (preference persistence). */\n storageKey?: string\n /** 'px' for fixed pixel widths, 'ratio' for percents (default 'ratio'). */\n unit?: 'px' | 'ratio'\n}\n\nexport interface DragHandleProps {\n onPointerDown: (event: ReactPointerEvent<HTMLDivElement>) => void\n onDoubleClick: () => void\n}\n\n/**\n * Resizable-split engine.\n * @param options - width contract + persistence key.\n * @returns current width, the committed setter, handle props, and the clamp.\n */\nexport function useResizableSplit(options: UseResizableSplitOptions = {}) {\n const {\n defaultWidth = 50,\n minWidth = 20,\n maxWidth = 80,\n storageKey,\n unit = 'ratio',\n } = options\n const isPx = unit === 'px'\n\n const [width, setWidthState] = useState(() =>\n storageKey === undefined\n ? defaultWidth\n : readStoredNumber(storageKey, minWidth, maxWidth, defaultWidth))\n\n // The pointer-down closure reads the width at drag START without rebinding.\n const widthRef = useRef(width)\n useEffect(() => {\n widthRef.current = width\n }, [width])\n\n /** The committed setter: state + storage (validated) + resize event. */\n const setWidth = useCallback((value: number) => {\n setWidthState(value)\n if (storageKey !== undefined) writeStoredNumber(storageKey, value)\n try {\n window.dispatchEvent(new CustomEvent('preview-panel-resize', { detail: { width: value } }))\n } catch {\n // event dispatch is best-effort\n }\n }, [storageKey])\n\n const clamp = useCallback((value: number): number => {\n return Math.min(maxWidth, Math.max(minWidth, value))\n }, [minWidth, maxWidth])\n\n const handlePointerDown = useCallback((event: ReactPointerEvent<HTMLDivElement>) => {\n const el = event.currentTarget as HTMLDivElement\n handlePointerDragStart(event.nativeEvent, el, {\n reverse: el.dataset.reverse === 'true',\n getStartWidth: () => widthRef.current,\n compute: (startWidth, deltaX) => clamp(startWidth + deltaX),\n onFrame: (value) => setWidthState(value),\n onEnd: (value) => setWidth(value),\n })\n }, [clamp, setWidth])\n\n const handleDoubleClick = useCallback(() => {\n setWidth(defaultWidth)\n }, [defaultWidth, setWidth])\n\n const handleProps: DragHandleProps = { onPointerDown: handlePointerDown, onDoubleClick: handleDoubleClick }\n\n return { width, setWidth, handleProps, clamp, isPx }\n}\n","/**\n * A compact markdown renderer for the preview panel: headings, paragraphs,\n * fenced + inline code, bold/italic, links/images, lists, blockquotes, hr,\n * and tables. All HTML is escaped before transformation — the output only\n * ever contains the renderer's own tags. Pure and exported for tests.\n * @module dsh-filemgr/client/preview/markdown\n */\n\n/** Escape HTML special characters. */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\n/** How one image src resolves against the markdown file's location. */\nexport type MarkdownImageResolution =\n /** Scheme URL or fragment: the browser resolves it as-is. */\n | { kind: 'absolute' }\n /** Workspace-relative target: resolved path plus any ?query#fragment suffix. */\n | { kind: 'relative'; path: string; suffix: string }\n /** `..` escaped the project root: the image must be dropped. */\n | { kind: 'escape' }\n\n/** Directory of a workspace-relative file path ('' when at the root). */\nfunction dirOf(filePath: string): string {\n const slash = filePath.lastIndexOf('/')\n return slash === -1 ? '' : filePath.slice(0, slash)\n}\n\n/** Collapse . and .. segments; null when .. escapes the base. */\nfunction normalizeRelPath(rel: string): string | null {\n const out: string[] = []\n for (const part of rel.split('/')) {\n if (part === '' || part === '.') continue\n if (part === '..') {\n if (out.length === 0) return null\n out.pop()\n continue\n }\n out.push(part)\n }\n return out.join('/')\n}\n\n/** Percent-decode a path portion (best effort; never throws). */\nfunction decodePathPart(raw: string): string {\n try {\n return decodeURIComponent(raw)\n } catch {\n return raw\n }\n}\n\n/**\n * Resolve one markdown image src against the markdown file's location:\n * - Absolute URLs (http/https/data:/...) and fragment-only srcs are left to\n * the browser ('absolute').\n * - Root-relative srcs (/img.png) resolve from the project root; other\n * relative srcs resolve against the file's directory. `..` escaping the\n * project root is rejected ('escape').\n * - The path portion is percent-decoded (markdown authors encode spaces in\n * filenames) and any ?query#fragment suffix is preserved verbatim, so\n * cache-busting srcs like ./img.png?v=2 still fetch img.png.\n */\nexport function resolveMarkdownImage(filePath: string, src: string): MarkdownImageResolution {\n const trimmed = src.trim()\n if (trimmed === '' || trimmed.startsWith('#')) return { kind: 'absolute' }\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return { kind: 'absolute' }\n const decoded = decodePathPart(trimmed)\n const q = decoded.indexOf('?')\n const h = decoded.indexOf('#')\n let cut = decoded.length\n if (q !== -1) cut = Math.min(cut, q)\n if (h !== -1) cut = Math.min(cut, h)\n const pathPart = decoded.slice(0, cut)\n const suffix = decoded.slice(cut)\n const base = pathPart.startsWith('/') ? '' : dirOf(filePath)\n const joined = base === '' ? pathPart : `${base}/${pathPart}`\n const normalized = normalizeRelPath(joined)\n if (normalized === null) return { kind: 'escape' }\n return { kind: 'relative', path: normalized, suffix }\n}\n\n/** Options controlling markdown rendering. */\nexport interface MarkdownRenderOptions {\n /**\n * Rewrite image srcs before they are emitted. Return the URL to use, or\n * null to drop the image (alt text only). Relative workspace paths are\n * typically resolved to absolute URLs here.\n */\n resolveImageSrc?: (src: string) => string | null\n}\n\n/**\n * Guard a raw link/image target against dangerous protocols. Returns the\n * (trimmed) raw string when safe, else null. Only these schemes are allowed:\n * http:, https:, mailto: and fragment anchors (#...). Scheme-less relative\n * paths (./ ../ / and plain filenames) pass through unchanged. Anything with\n * a scheme outside the allow-list — javascript:, data:, vbscript:, etc. —\n * is rejected so the value never reaches dangerouslySetInnerHTML.\n */\nexport function safeUrl(raw: string): string | null {\n const trimmed = raw.trim()\n if (trimmed === '') return null\n if (trimmed.startsWith('#')) return trimmed\n const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed)\n if (scheme === null) return trimmed\n const name = scheme[1].toLowerCase()\n return name === 'http' || name === 'https' || name === 'mailto' ? trimmed : null\n}\n\n/** Inline pass: code spans, bold, italic, images, links. */\nexport function renderInline(text: string, options?: MarkdownRenderOptions): string {\n let out = ''\n let i = 0\n const n = text.length\n while (i < n) {\n const char = text[i]\n // Fenced inline code first.\n if (char === '`') {\n const end = text.indexOf('`', i + 1)\n if (end !== -1) {\n out += `<code>${escapeHtml(text.slice(i + 1, end))}</code>`\n i = end + 1\n continue\n }\n }\n // Image ![alt](src)\n if (char === '!' && text[i + 1] === '[') {\n const close = text.indexOf('](', i + 2)\n if (close !== -1) {\n const parenEnd = text.indexOf(')', close + 2)\n if (parenEnd !== -1) {\n const alt = text.slice(i + 2, close)\n const src = text.slice(close + 2, parenEnd)\n const safe = safeUrl(src)\n if (safe === null) {\n // Unsafe image target: drop the img, keep the alt text.\n out += escapeHtml(alt)\n } else {\n let target: string | null = safe\n if (options?.resolveImageSrc !== undefined) {\n target = options.resolveImageSrc(safe)\n }\n if (target === null) {\n // The resolver dropped the image (unresolvable path): alt only.\n out += escapeHtml(alt)\n } else {\n const srcEsc = escapeHtml(target).replace(/\\s+/g, '%20')\n out += `<img alt=\"${escapeHtml(alt)}\" src=\"${srcEsc}\" />`\n }\n }\n i = parenEnd + 1\n continue\n }\n }\n }\n // Link [text](href)\n if (char === '[') {\n const close = text.indexOf('](', i + 1)\n if (close !== -1) {\n const parenEnd = text.indexOf(')', close + 2)\n if (parenEnd !== -1) {\n const label = text.slice(i + 1, close)\n const href = text.slice(close + 2, parenEnd)\n const safe = safeUrl(href)\n if (safe === null) {\n // Unsafe link target: render the label as plain text, no <a>.\n out += renderInline(label, options)\n } else {\n out += `<a href=\"${escapeHtml(safe)}\" target=\"_blank\" rel=\"noopener noreferrer\">${renderInline(label, options)}</a>`\n }\n i = parenEnd + 1\n continue\n }\n }\n }\n // Bold **text**\n if (char === '*' && text[i + 1] === '*') {\n const end = text.indexOf('**', i + 2)\n if (end !== -1) {\n out += `<strong>${renderInline(text.slice(i + 2, end), options)}</strong>`\n i = end + 2\n continue\n }\n }\n // Italic *text*\n if (char === '*' && text[i - 1] !== '*' && text[i + 1] !== '*') {\n const end = text.indexOf('*', i + 1)\n if (end !== -1 && text[end + 1] !== '*') {\n out += `<em>${renderInline(text.slice(i + 1, end), options)}</em>`\n i = end + 1\n continue\n }\n }\n // Strikethrough ~~text~~\n if (char === '~' && text[i + 1] === '~') {\n const end = text.indexOf('~~', i + 2)\n if (end !== -1) {\n out += `<del>${renderInline(text.slice(i + 2, end), options)}</del>`\n i = end + 2\n continue\n }\n }\n out += escapeHtml(char)\n i += 1\n }\n return out\n}\n\n/** Render a markdown document to HTML (block pass). */\nexport function renderMarkdown(source: string, options?: MarkdownRenderOptions): string {\n const lines = source.replace(/\\r\\n/g, '\\n').split('\\n')\n const out: string[] = []\n let i = 0\n const n = lines.length\n\n const flushParagraph = (buffer: string[]): void => {\n if (buffer.length === 0) return\n out.push(`<p>${renderInline(buffer.join(\"\\n\"), options)}</p>`)\n buffer.length = 0\n }\n\n let paragraph: string[] = []\n while (i < n) {\n const line = lines[i]\n\n // Fenced code block.\n const fence = /^```([\\w+-]*)\\s*$/.exec(line)\n if (fence !== null) {\n flushParagraph(paragraph)\n const lang = fence[1] ?? ''\n i += 1\n const code: string[] = []\n while (i < n && !/^```\\s*$/.test(lines[i])) {\n code.push(lines[i])\n i += 1\n }\n i += 1 // closing fence\n const langAttr = lang === '' ? '' : ` class=\"language-${escapeHtml(lang)}\"`\n out.push(`<pre${langAttr}><code>${escapeHtml(code.join('\\n'))}</code></pre>`)\n continue\n }\n\n // Heading.\n const heading = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (heading !== null) {\n flushParagraph(paragraph)\n const level = heading[1].length\n out.push(`<h${level}>${renderInline(heading[2] ?? '', options)}</h${level}>`)\n i += 1\n continue\n }\n\n // Horizontal rule.\n if (/^\\s*(---+|\\*\\*\\*+|___+)\\s*$/.test(line)) {\n flushParagraph(paragraph)\n out.push('<hr />')\n i += 1\n continue\n }\n\n // Table: header row then separator row.\n if (line.includes('|') && i + 1 < n && /^\\s*\\|?[\\s:|-]+\\|?\\s*$/.test(lines[i + 1]) && lines[i + 1].includes('-')) {\n flushParagraph(paragraph)\n const headerCells = splitTableRow(line)\n i += 2\n const rows: string[][] = []\n while (i < n && lines[i].includes('|')) {\n rows.push(splitTableRow(lines[i]))\n i += 1\n }\n out.push('<table>')\n out.push(`<thead><tr>${headerCells.map((cell) => `<th>${renderInline(cell, options)}</th>`).join('')}</tr></thead>`)\n if (rows.length > 0) {\n out.push(`<tbody>${rows.map((row) => `<tr>${row.map((cell) => `<td>${renderInline(cell, options)}</td>`).join('')}</tr>`).join('')}</tbody>`)\n }\n out.push('</table>')\n continue\n }\n\n // Blockquote (one level).\n const quote = /^>\\s?(.*)$/.exec(line)\n if (quote !== null) {\n flushParagraph(paragraph)\n const body: string[] = []\n while (i < n) {\n const q = /^>\\s?(.*)$/.exec(lines[i])\n if (q === null) break\n body.push(q[1] ?? '')\n i += 1\n }\n out.push(`<blockquote><p>${body.map((line) => renderInline(line, options)).join('<br />')}</p></blockquote>`)\n continue\n }\n\n // Unordered list.\n const ul = /^\\s*([-*+])\\s+(.*)$/.exec(line)\n if (ul !== null) {\n flushParagraph(paragraph)\n const items: string[] = []\n while (i < n) {\n const item = /^\\s*([-*+])\\s+(.*)$/.exec(lines[i])\n if (item === null) break\n items.push(`<li>${renderInline(item[2] ?? '', options)}</li>`)\n i += 1\n }\n out.push(`<ul>${items.join('')}</ul>`)\n continue\n }\n\n // Ordered list.\n const ol = /^\\s*\\d+[.)]\\s+(.*)$/.exec(line)\n if (ol !== null) {\n flushParagraph(paragraph)\n const items: string[] = []\n while (i < n) {\n const item = /^\\s*\\d+[.)]\\s+(.*)$/.exec(lines[i])\n if (item === null) break\n items.push(`<li>${renderInline(item[1] ?? '', options)}</li>`)\n i += 1\n }\n out.push(`<ol>${items.join('')}</ol>`)\n continue\n }\n\n // Blank line: flush the paragraph.\n if (line.trim() === '') {\n flushParagraph(paragraph)\n i += 1\n continue\n }\n\n paragraph.push(line)\n i += 1\n }\n flushParagraph(paragraph)\n return out.join('\\n')\n}\n\n/** Split one table row into cells (respecting the leading/trailing pipes). */\nfunction splitTableRow(line: string): string[] {\n const trimmed = line.trim()\n const inner = trimmed.startsWith('|') ? trimmed.slice(1) : trimmed\n const withoutTrailing = inner.endsWith('|') ? inner.slice(0, -1) : inner\n return withoutTrailing.split('|').map((cell) => cell.trim())\n}\n","/**\n * Mermaid diagram enhancement for markdown surfaces: lazily loads the\n * mermaid runtime from the host vendor route (same origin, no CDN), renders\n * every fenced ```mermaid code block in place, and re-renders on theme\n * flips. Framework-free so both the preview panel (React effect) and the\n * chat transcript observer can drive it over disjoint DOM scopes.\n *\n * Failure policy: any load/render failure leaves the original code block\n * untouched (or restores it verbatim); nothing here throws to the caller.\n * @module dsh-filemgr/client/preview/mermaid\n */\n\n/** Minimal structural type of the mermaid runtime this module consumes. */\ninterface MermaidRuntime {\n initialize: (config: Record<string, unknown>) => void\n render: (id: string, text: string, container?: HTMLElement) => Promise<{ svg: string }>\n}\n\n/** Host-served mermaid IIFE bundle (lib/assets/mermaid.min.js behind the route). */\nexport const MERMAID_VENDOR_URL = '/filemgr/vendor/mermaid.js'\n\n/** Lifecycle state stamped on diagram containers (`pending`/`rendering`/`done`). */\nconst DATA_STATE = 'data-mermaid-state'\n\n/** State stamped on a code block once its container exists (`claimed`). */\nconst DATA_CLAIMED = 'data-mermaid-claimed'\n\n/** The verbatim diagram source kept on the container for theme re-renders. */\nconst DATA_SOURCE = 'data-mermaid-source'\n\n/** Marker the preview viewer stamps on its own subtree (chat enhancement skips it). */\nexport const DATA_MD_SCOPE = 'data-filemgr-md-scope'\n\nlet loadPromise: Promise<MermaidRuntime> | undefined\n\n/**\n * Resolve the mermaid global left by the vendor IIFE bundle, or null while\n * absent. Narrow and defensive: the bundle is a third-party artifact.\n */\nfunction mermaidGlobal(): MermaidRuntime | null {\n const candidate = (globalThis as Record<string, unknown>).mermaid\n if (typeof candidate !== 'object' || candidate === null) return null\n const checked = candidate as Record<string, unknown>\n if (typeof checked.initialize !== 'function' || typeof checked.render !== 'function') return null\n return checked as unknown as MermaidRuntime\n}\n\n/**\n * Load the mermaid runtime once per page: injects a <script> for the host\n * vendor route and resolves with the runtime. Concurrent callers share one\n * injection; a failure clears the cache so a later surface can retry.\n */\nexport function loadMermaidLibrary(): Promise<MermaidRuntime> {\n const existing = mermaidGlobal()\n if (existing !== null) return Promise.resolve(existing)\n if (loadPromise !== undefined) return loadPromise\n loadPromise = new Promise<MermaidRuntime>((resolve, reject) => {\n const script = document.createElement('script')\n script.src = MERMAID_VENDOR_URL\n script.async = true\n script.onload = () => {\n const runtime = mermaidGlobal()\n if (runtime === null) {\n loadPromise = undefined\n reject(new Error('mermaid vendor script loaded but window.mermaid is missing'))\n return\n }\n resolve(runtime)\n }\n script.onerror = () => {\n loadPromise = undefined\n reject(new Error(`failed to load ${MERMAID_VENDOR_URL}`))\n }\n document.head.appendChild(script)\n })\n return loadPromise\n}\n\n/** Mermaid theme name for the shell theme marker (`default` or `dark`). */\nexport function mermaidTheme(isDark: boolean): 'default' | 'dark' {\n return isDark ? 'dark' : 'default'\n}\n\n/** Whether the shell currently carries the dark marker attribute. */\nexport function shellIsDark(): boolean {\n return document.body.hasAttribute('data-ds-dark-theme')\n}\n\n/** Monotonic id source for render calls (mermaid keys its <svg> by id). */\nlet renderSeq = 0\n\n/**\n * Configure the mermaid runtime for the current theme. Called once per\n * render batch (enhance or retheme), not per diagram, so a surface with\n * many diagrams initializes the runtime a single time.\n */\nfunction initializeRuntime(runtime: MermaidRuntime, theme: string): void {\n runtime.initialize({\n startOnLoad: false,\n theme,\n securityLevel: 'strict',\n fontFamily: '\"trebuchet ms\", verdana, arial, sans-serif',\n })\n}\n\n/** Render one diagram source to SVG with the already-initialized runtime. */\nasync function renderSvg(runtime: MermaidRuntime, source: string): Promise<string> {\n const { svg } = await runtime.render(`filemgr-mermaid-${(renderSeq += 1)}`, source)\n return svg\n}\n\n/** Disallowed elements removed from mermaid SVG output before innerHTML. */\nconst DISALLOWED_ELEMENTS = ['script', 'foreignObject', 'iframe', 'object', 'embed']\n\n/** Whether an attribute name is an { on* } event-handler (case-insensitive). */\nfunction isEventHandler(name: string): boolean {\n return /^on/i.test(name)\n}\n\n/** Whether an href/xlink:href value carries an executable javascript: URL. */\nfunction isDangerousHref(value: string): boolean {\n return /^javascript:/i.test(value.trim())\n}\n\n/**\n * Application-level defense-in-depth on top of mermaid's own strict-mode\n * escaping: parse the rendered SVG in a detached container, remove disallowed\n * elements and dangerous attributes, and return the serialized cleaned markup.\n * Throws when the input cannot be parsed as markup or still carries dangerous\n * raw tokens, so callers fall back to their failure path.\n */\nexport function sanitizeSvg(svg: string): string {\n const template = document.createElement('template')\n template.innerHTML = svg\n const root = template.content\n\n // Remove disallowed elements; loop because removals can expose nested ones.\n for (let found = true; found; ) {\n found = false\n for (const el of Array.from(root.querySelectorAll('*'))) {\n if (DISALLOWED_ELEMENTS.some((tag) => el.tagName.toLowerCase() === tag.toLowerCase())) {\n el.remove()\n found = true\n }\n }\n }\n\n // Strip event-handler attributes and javascript: hrefs from every element.\n for (const el of Array.from(root.querySelectorAll('*'))) {\n for (const attr of Array.from(el.attributes)) {\n if (isEventHandler(attr.name) || isDangerousHref(attr.value)) el.removeAttribute(attr.name)\n }\n }\n\n const cleaned = template.innerHTML\n const lower = cleaned.toLowerCase()\n if (lower.includes('<script') || lower.includes('javascript:')) {\n throw new Error('mermaid SVG still contains dangerous tokens after sanitization')\n }\n return cleaned\n}\n\n/**\n * Collect the still-unclaimed fenced mermaid code blocks under one scope.\n * Both shapes are found: the panel renderer's `pre.language-mermaid` and\n * the chat renderer's `pre > code.language-mermaid` (the claim always\n * targets the <pre>). Empty blocks and blocks another driver already\n * claimed are skipped. Pure (DOM-read only) so tests can drive it in jsdom.\n */\nexport function findMermaidCodeBlocks(scope: ParentNode): HTMLPreElement[] {\n const found: HTMLPreElement[] = []\n const seen = new Set<Element>()\n for (const el of Array.from(scope.querySelectorAll('pre.language-mermaid, code.language-mermaid'))) {\n const pre = el instanceof HTMLPreElement ? el : el.parentElement\n if (pre === null || !(pre instanceof HTMLPreElement)) continue\n if (seen.has(pre)) continue\n seen.add(pre)\n if (pre.hasAttribute(DATA_CLAIMED)) continue\n if ((pre.textContent ?? '').trim() === '') continue\n found.push(pre)\n }\n return found\n}\n\n/**\n * Swap one code block for a diagram container. The original <pre> stays in\n * the tree (hidden once the render lands) so a failure can restore it\n * verbatim; the container carries the source for theme re-renders.\n */\nfunction claimBlock(pre: HTMLPreElement, className: string): HTMLElement {\n pre.setAttribute(DATA_CLAIMED, '1')\n const container = document.createElement('div')\n container.className = className\n container.setAttribute(DATA_STATE, 'pending')\n container.setAttribute(DATA_SOURCE, pre.textContent ?? '')\n pre.insertAdjacentElement('afterend', container)\n return container\n}\n\n/** Options for {@link enhanceMermaidBlocks}. */\nexport interface EnhanceOptions {\n /** Class for the diagram container (a CSS module export). */\n className: string\n /** Resolved mermaid theme name. */\n theme: string\n /** Optional extra exclusion for scopes another driver owns. */\n skip?: (pre: HTMLPreElement) => boolean\n}\n\n/**\n * Render every unclaimed ```mermaid block under `scope` into an inline SVG\n * diagram. Idempotent per block across drivers (claimed blocks are skipped);\n * failures restore the original code block. Never rejects.\n */\nexport async function enhanceMermaidBlocks(scope: ParentNode, options: EnhanceOptions): Promise<void> {\n let runtime: MermaidRuntime\n try {\n runtime = await loadMermaidLibrary()\n } catch {\n return // no vendor route (asset missing): keep plain code blocks\n }\n initializeRuntime(runtime, options.theme)\n const jobs: Array<Promise<void>> = []\n for (const pre of findMermaidCodeBlocks(scope)) {\n if (options.skip?.(pre) === true) continue\n const container = claimBlock(pre, options.className)\n jobs.push((async () => {\n try {\n container.setAttribute(DATA_STATE, 'rendering')\n const source = container.getAttribute(DATA_SOURCE) ?? ''\n const svg = await renderSvg(runtime, source)\n container.innerHTML = sanitizeSvg(svg)\n container.setAttribute(DATA_STATE, 'done')\n pre.style.display = 'none'\n } catch {\n // Syntax error or render failure: restore the untouched code block.\n container.remove()\n pre.removeAttribute(DATA_CLAIMED)\n }\n })())\n }\n await Promise.all(jobs)\n}\n\n/**\n * Re-render every completed diagram container under `scope` after a theme\n * flip (stored sources re-render with the new theme). Containers not in the\n * `done` state are skipped; a failure keeps the previous render.\n */\nexport async function rethemeMermaidBlocks(scope: ParentNode, options: { theme: string }): Promise<void> {\n const runtime = mermaidGlobal()\n if (runtime === null) return\n initializeRuntime(runtime, options.theme)\n const containers = Array.from(scope.querySelectorAll<HTMLElement>('[data-mermaid-state=\"done\"]'))\n await Promise.all(containers.map(async (container) => {\n const source = container.getAttribute(DATA_SOURCE) ?? ''\n try {\n const svg = await renderSvg(runtime, source)\n container.innerHTML = sanitizeSvg(svg)\n } catch {\n // Keep the previous render; a theme flip must not blank diagrams.\n }\n }))\n}\n\n/**\n * One dark-marker watcher per surface: fires on body attribute flips so the\n * caller can retheme. Returns the disposer.\n */\nexport function watchShellTheme(onChange: (isDark: boolean) => void): () => void {\n const observer = new MutationObserver(() => { onChange(shellIsDark()) })\n observer.observe(document.body, { attributes: true, attributeFilter: ['data-ds-dark-theme'] })\n return () => { observer.disconnect() }\n}\n","/**\n * Preview content routing: the renderers for every content type plus the\n * split-screen editor|preview layout. View mode (source/preview) resets to\n * preview when the displayed FILE changes (keyed on path+type, not tab id —\n * FileManager contract), and the split ratio is persisted under\n * preview-panel-split-ratio with a 20..80 clamp.\n * @module dsh-filemgr/client/preview/content\n */\n\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport { CodeBlock } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PreviewTabState } from '../store.ts'\nimport { useResizableSplit } from '../hooks/useResizableSplit.ts'\nimport { t } from '../locales.ts'\nimport { renderMarkdown, resolveMarkdownImage } from './markdown.ts'\nimport {\n DATA_MD_SCOPE,\n enhanceMermaidBlocks,\n mermaidTheme,\n rethemeMermaidBlocks,\n shellIsDark,\n watchShellTheme,\n} from './mermaid.ts'\nimport previewCss from '../styles/preview.module.css'\n\n/** Split-ratio persistence key (FileManager contract). */\nexport const KEY_SPLIT_RATIO = 'preview-panel-split-ratio'\n\n/** The rendered content of one tab (viewMode/split are controlled by the panel). */\nexport function TabContent({\n tab,\n viewMode,\n split,\n onContentChange,\n onSave,\n}: {\n tab: PreviewTabState\n viewMode: 'source' | 'preview'\n split: boolean\n onContentChange: (content: string) => void\n onSave: () => void\n}): JSX.Element {\n if (tab.error !== null) {\n return <div className={previewCss.placeholder}>\n <div className={previewCss.placeholderTitle}>{tab.title}</div>\n <div className={previewCss.placeholderError}>{tab.error}</div>\n </div>\n }\n\n const editable = tab.contentType === 'markdown' || tab.contentType === 'html'\n || tab.contentType === 'code' || tab.contentType === 'csv' || tab.contentType === 'text'\n\n // Split screen: editable types only; editor | preview with a ratio handle.\n if (split && editable) {\n return (\n <SplitPane\n tab={tab}\n onContentChange={onContentChange}\n onSave={onSave}\n />\n )\n }\n\n return (\n <div className={previewCss.content}>\n {tab.truncated && tab.content !== null && (\n <div className={previewCss.truncatedNote}>{t('preview.errorOversized')}</div>\n )}\n {tab.contentType === 'markdown' && tab.content !== null && (\n <MarkdownViewer\n content={tab.content}\n root={tab.root}\n path={tab.path}\n sourceMode={viewMode === 'source'}\n onContentChange={onContentChange}\n />\n )}\n {tab.contentType === 'html' && tab.content !== null && (\n <HtmlViewer\n content={tab.content}\n sourceMode={viewMode === 'source'}\n onContentChange={onContentChange}\n />\n )}\n {(tab.contentType === 'code' || tab.contentType === 'text') && tab.content !== null && (\n <CodeViewer content={tab.content} language={tab.title.split('.').pop() ?? ''} />\n )}\n {tab.contentType === 'csv' && tab.content !== null && <CsvViewer content={tab.content} />}\n {tab.contentType === 'diff' && tab.content !== null && <DiffViewer content={tab.content} />}\n {tab.contentType === 'image' && tab.content !== null && (\n <ImageViewer src={tab.content} meta={`${tab.image?.width ?? ''}${tab.image ? ' x ' : ''}${tab.image?.height ?? ''}`} />\n )}\n {tab.contentType === 'pdf' && tab.content !== null && <PdfViewer dataUrl={tab.content} title={tab.title} />}\n {tab.contentType === 'url' && <UrlViewer tab={tab} />}\n {(tab.contentType === 'word' || tab.contentType === 'excel' || tab.contentType === 'ppt' || tab.contentType === 'unsupported') && (\n <UnsupportedViewer tab={tab} />\n )}\n {tab.content === null && !tab.loading && (\n <div className={previewCss.placeholder}>\n <div className={previewCss.placeholderTitle}>{tab.title}</div>\n <div className={previewCss.placeholderMeta}>{t('preview.downloadHint')}</div>\n </div>\n )}\n {tab.loading && <div className={previewCss.placeholder}>{t('scm.loading')}</div>}\n </div>\n )\n}\n\n/** Split screen: textarea editor | rendered preview, ratio persisted. */\nfunction SplitPane({\n tab,\n onContentChange,\n onSave,\n}: {\n tab: PreviewTabState\n onContentChange: (content: string) => void\n onSave: () => void\n}): JSX.Element {\n const { width: splitRatio, handleProps } = useResizableSplit({\n unit: 'ratio',\n defaultWidth: 50,\n minWidth: 20,\n maxWidth: 80,\n storageKey: KEY_SPLIT_RATIO,\n })\n const content = tab.content ?? ''\n\n return (\n <div className={previewCss.splitPane}>\n <div className={previewCss.splitPaneLeft} style={{ width: `${splitRatio}%` }}>\n <div className={previewCss.splitHeader}>{t('preview.editor')}</div>\n <div className={previewCss.splitBody}>\n <textarea\n className={previewCss.textEditor}\n value={content}\n spellCheck={false}\n onChange={(event) => onContentChange(event.target.value)}\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 's') {\n event.preventDefault()\n onSave()\n }\n }}\n />\n </div>\n </div>\n <div\n className={previewCss.splitHandle}\n data-reverse=\"false\"\n style={{ left: `calc(${splitRatio}% - 6px)` }}\n {...handleProps}\n />\n <div className={previewCss.splitPaneRight} style={{ width: `${100 - splitRatio}%` }}>\n <div className={previewCss.splitHeader}>{t('preview.preview')}</div>\n <div className={previewCss.splitBody}>\n {tab.contentType === 'markdown' && <MarkdownViewer content={content} root={tab.root} path={tab.path} />}\n {tab.contentType === 'html' && <HtmlViewer content={content} />}\n {tab.contentType === 'csv' && <CsvViewer content={content} />}\n {tab.contentType === 'code' && <CodeViewer content={content} language={tab.title.split('.').pop() ?? ''} />}\n </div>\n </div>\n </div>\n )\n}\n\n/** Markdown viewer with an optional source mode (textarea). */\nfunction MarkdownViewer({\n content,\n root,\n path,\n sourceMode = false,\n onContentChange,\n}: {\n content: string\n /** Project root of the markdown file (image srcs resolve against it). */\n root: string\n /** The markdown file's workspace-relative path (image dir base). */\n path: string\n sourceMode?: boolean\n onContentChange?: (content: string) => void\n}): JSX.Element {\n const resolveImageSrc = useCallback((src: string): string | null => {\n if (root === '' || path === '') return null\n const resolution = resolveMarkdownImage(path, src)\n if (resolution.kind === 'absolute') return src\n if (resolution.kind === 'escape') return null\n // Workspace-relative target: serve the bytes through the host raw route\n // (same origin as the GUI), preserving any ?query#fragment suffix.\n return `/filemgr/raw?root=${encodeURIComponent(root)}&path=${encodeURIComponent(resolution.path)}${resolution.suffix}`\n }, [root, path])\n const html = useMemo(\n () => renderMarkdown(content, { resolveImageSrc }),\n [content, resolveImageSrc],\n )\n if (sourceMode && onContentChange !== undefined) {\n return (\n <div className={previewCss.content}>\n <textarea\n className={previewCss.textEditor}\n value={content}\n spellCheck={false}\n onChange={(event) => onContentChange(event.target.value)}\n />\n </div>\n )\n }\n return <MermaidAwareMarkdown html={html} />\n}\n\n/**\n * Rendered markdown body plus the mermaid enhancement lifecycle: fresh\n * blocks render once per html, completed diagrams re-render on shell theme\n * flips. The scope marker lets the chat-transcript enhancer skip this\n * subtree (each surface owns its blocks).\n */\nfunction MermaidAwareMarkdown({ html }: { html: string }): JSX.Element {\n const ref = useRef<HTMLDivElement | null>(null)\n useEffect(() => {\n const el = ref.current\n if (el === null) return undefined\n void enhanceMermaidBlocks(el, { className: previewCss.mermaidBlock, theme: mermaidTheme(shellIsDark()) })\n return watchShellTheme((isDark) => {\n void rethemeMermaidBlocks(el, { theme: mermaidTheme(isDark) })\n })\n }, [html])\n return (\n <div\n ref={ref}\n className={previewCss.mdViewer}\n {...{ [DATA_MD_SCOPE]: '1' }}\n dangerouslySetInnerHTML={{ __html: html }}\n />\n )\n}\n\n/** HTML viewer: sandboxed iframe (scripts off) or source textarea. */\nfunction HtmlViewer({\n content,\n sourceMode = false,\n onContentChange,\n}: {\n content: string\n sourceMode?: boolean\n onContentChange?: (content: string) => void\n}): JSX.Element {\n const srcDoc = useMemo(() => {\n // Base styles so the embedded page inherits the theme background.\n return `<!doctype html><html><head><meta charset=\"utf-8\"><style>body{margin:0;font-family:-apple-system,\"system-ui\",\"Segoe UI\",Roboto,\"PingFang SC\",sans-serif;color:#1d2129}@media (prefers-color-scheme:dark){body{color:rgba(255,255,255,0.9)}}</style></head><body>${content}</body></html>`\n }, [content])\n if (sourceMode && onContentChange !== undefined) {\n return (\n <div className={previewCss.content}>\n <textarea\n className={previewCss.textEditor}\n value={content}\n spellCheck={false}\n onChange={(event) => onContentChange(event.target.value)}\n />\n </div>\n )\n }\n return <iframe className={previewCss.pdfViewer} srcDoc={srcDoc} sandbox=\"\" title=\"html preview\" />\n}\n\n/**\n * Syntax-highlighted code/text viewer (official shiki core via CodeBlock),\n * wrapped in a line-number gutter.\n *\n * Alignment strategy: instead of trusting CSS to mirror the code block's\n * internal metrics (its language banner, `pre` padding and line-height are\n * owned by the primitives package), the gutter is measured against the live\n * `pre` — its top offset inside the shell (the banner's height) and its\n * computed line-height are read after render and applied as inline styles.\n * This keeps the numbers exactly on their lines regardless of the primitives'\n * internal layout. The trailing newline is not counted (CodeBlock trims it).\n */\nexport function CodeViewer({ content, language }: { content: string; language: string }): JSX.Element {\n const shellRef = useRef<HTMLDivElement | null>(null)\n const [gutterStyle, setGutterStyle] = useState<{ paddingTop: number; lineHeight: number } | null>(null)\n\n const lineCount = useMemo(() => {\n const trimmed = content.endsWith('\\n') ? content.slice(0, -1) : content\n return trimmed === '' ? 1 : trimmed.split('\\n').length\n }, [content])\n const numbers = useMemo(() => {\n const rows: number[] = []\n for (let i = 1; i <= lineCount; i += 1) rows.push(i)\n return rows\n }, [lineCount])\n\n // Measure the live `pre` and align the gutter (banner offset + line height).\n useEffect(() => {\n const shell = shellRef.current\n if (shell === null) return\n const measure = (): void => {\n const pre = shell.querySelector('pre')\n if (pre === null) {\n setGutterStyle(null)\n return\n }\n const shellRect = shell.getBoundingClientRect()\n const preRect = pre.getBoundingClientRect()\n const preStyle = getComputedStyle(pre)\n const lineHeight = parseFloat(preStyle.lineHeight)\n const padTop = parseFloat(preStyle.paddingTop)\n // First code line's top = pre's top offset (banner) + pre's own padding.\n const offsetTop = preRect.top - shellRect.top\n setGutterStyle({\n paddingTop: (Number.isFinite(offsetTop) ? offsetTop : 0) + (Number.isFinite(padTop) ? padTop : 0),\n lineHeight: Number.isFinite(lineHeight) ? lineHeight : 19.2,\n })\n }\n measure()\n // The shiki grammar loads asynchronously and re-renders the pre; watch for\n // structural changes and re-measure (line-height/padding rarely change,\n // but the banner's presence may settle late).\n const observer = new MutationObserver(measure)\n observer.observe(shell, { childList: true, subtree: true })\n return () => observer.disconnect()\n }, [content])\n\n return (\n <div className={previewCss.codeShell} ref={shellRef}>\n <div\n className={previewCss.lineGutter}\n aria-hidden=\"true\"\n style={gutterStyle !== null ? { paddingTop: gutterStyle.paddingTop } : undefined}\n >\n {numbers.map((number) => (\n <div\n key={number}\n className={previewCss.lineNo}\n style={gutterStyle !== null ? { height: gutterStyle.lineHeight, lineHeight: `${gutterStyle.lineHeight}px` } : undefined}\n >\n {number}\n </div>\n ))}\n </div>\n <div className={previewCss.codeBody}>\n <CodeBlock code={content} lang={language === '' ? undefined : language} className={previewCss.codeViewer} copyLabel={t('preview.copyCode')} copiedLabel={t('preview.copyCodeDone')} />\n </div>\n </div>\n )\n}\n\n/**\n * One memoized CSV row. The cells array reference is stable (it comes from the\n * memoized parsed rows), so an untouched row skips re-rendering when a sibling\n * cell changes or the panel re-renders for another reason.\n */\nconst CsvRow = memo(function CsvRow({ cells, isHeader }: { cells: string[]; isHeader: boolean }): JSX.Element {\n return (\n <tr>\n {cells.map((cell, cellIndex) => (\n isHeader ? <th key={cellIndex}>{cell}</th> : <td key={cellIndex}>{cell}</td>\n ))}\n </tr>\n )\n})\n\n/**\n * Stable, content-derived key for a CSV row. Rows have no ids, so the cell\n * content (JSON, occurrence-disambiguated for duplicates) anchors the key\n * instead of the array position — a reordered or shifted table keeps stable\n * React identities instead of reusing DOM nodes by index.\n * @param row - the raw row cells.\n * @param occurrence - how many identical rows were already keyed.\n */\nfunction csvRowKey(row: string[], occurrence: number): string {\n return `${JSON.stringify(row)}\\u0000${occurrence}`\n}\n\n/** CSV table. */\nfunction CsvViewer({ content }: { content: string }): JSX.Element {\n const rows = useMemo(() => parseCsv(content), [content])\n const keyedRows = useMemo(() => {\n const counts = new Map<string, number>()\n return rows.map((row) => {\n const seen = counts.get(JSON.stringify(row)) ?? 0\n counts.set(JSON.stringify(row), seen + 1)\n return { cells: row, key: csvRowKey(row, seen) }\n })\n }, [rows])\n return (\n <div className={previewCss.csvViewer}>\n <table className={previewCss.csvTable}>\n {keyedRows.map((entry, index) => (\n <CsvRow key={entry.key} cells={entry.cells} isHeader={index === 0} />\n ))}\n </table>\n </div>\n )\n}\n\n/** Parse CSV lines (quoted cells with escaped quotes). */\nexport function parseCsv(text: string): string[][] {\n const rows: string[][] = []\n let row: string[] = []\n let cell = ''\n let inQuotes = false\n for (let i = 0; i < text.length; i += 1) {\n const char = text[i]\n if (inQuotes) {\n if (char === '\"') {\n if (text[i + 1] === '\"') {\n cell += '\"'\n i += 1\n } else {\n inQuotes = false\n }\n } else {\n cell += char\n }\n continue\n }\n if (char === '\"') {\n inQuotes = true\n continue\n }\n if (char === ',') {\n row.push(cell)\n cell = ''\n continue\n }\n if (char === '\\n') {\n row.push(cell)\n rows.push(row)\n row = []\n cell = ''\n continue\n }\n if (char !== '\\r') cell += char\n }\n row.push(cell)\n if (row.length > 1 || row[0] !== '') rows.push(row)\n return rows\n}\n\n/** Unified diff viewer. */\nfunction DiffViewer({ content }: { content: string }): JSX.Element {\n const lines = content.split('\\n')\n return (\n <div className={previewCss.diffViewer}>\n {lines.map((line, index) => {\n let className = previewCss.diffLineMeta\n if (line.startsWith('+++') || line.startsWith('---') || line.startsWith('diff ') || line.startsWith('index ')) {\n className = previewCss.diffLineMeta\n } else if (line.startsWith('@@')) {\n className = previewCss.diffLineHunk\n } else if (line.startsWith('+')) {\n className = previewCss.diffLineAdd\n } else if (line.startsWith('-')) {\n className = previewCss.diffLineDel\n }\n return (\n <div key={index} className={className}>\n {line === '' ? ' ' : line}\n </div>\n )\n })}\n </div>\n )\n}\n\n/** Image viewer. */\nfunction ImageViewer({ src, meta }: { src: string; meta: string }): JSX.Element {\n return (\n <div className={previewCss.content}>\n <div className={previewCss.imageViewer}>\n <img src={src} alt=\"\" />\n </div>\n {meta.trim() !== '' && <div className={previewCss.imageMeta}>{meta}</div>}\n </div>\n )\n}\n\n/** PDF viewer: streamed route URL (iframe src) or a legacy data URL (blob). */\nfunction PdfViewer({ dataUrl, title }: { dataUrl: string; title: string }): JSX.Element {\n const [url, setUrl] = useState<string | null>(null)\n useEffect(() => {\n if (!dataUrl.startsWith('data:')) {\n // Same-origin /filemgr/raw URL: the iframe loads the stream\n // directly (mime application/pdf, no size cap, no base64 copy).\n setUrl(dataUrl === '' ? null : dataUrl)\n return\n }\n const blob = dataUrlToBlob(dataUrl)\n if (blob === null) {\n setUrl(null)\n return\n }\n const objectUrl = URL.createObjectURL(blob)\n setUrl(objectUrl)\n return () => URL.revokeObjectURL(objectUrl)\n }, [dataUrl])\n return url === null\n ? <div className={previewCss.placeholder}>{t('preview.unsupported')}</div>\n : <iframe className={previewCss.pdfViewer} src={url} title={title} />\n}\n\n/** Convert a data URL to a Blob (null on failure). */\nexport function dataUrlToBlob(dataUrl: string): Blob | null {\n const comma = dataUrl.indexOf(',')\n if (comma === -1) return null\n const meta = dataUrl.slice(0, comma)\n const mime = /data:([^;]+)/.exec(meta)?.[1] ?? 'application/octet-stream'\n try {\n const binary = atob(dataUrl.slice(comma + 1))\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i)\n return new Blob([bytes], { type: mime })\n } catch {\n return null\n }\n}\n\n/** URL tab: address bar + iframe. */\nfunction UrlViewer({ tab }: { tab: PreviewTabState }): JSX.Element {\n const [input, setInput] = useState(tab.content ?? '')\n const [url, setUrl] = useState(() => normalizeUrl(tab.content ?? ''))\n const frameRef = useRef<HTMLIFrameElement>(null)\n useEffect(() => {\n setInput(tab.content ?? '')\n setUrl(normalizeUrl(tab.content ?? ''))\n }, [tab.id, tab.content])\n\n // The frame is sandboxed WITH allow-popups: sites like bilibili hardcode\n // target=_blank on their nav links, so popups are permitted rather than\n // silently dropped. allow-same-origin is intentionally OMITTED, so the\n // embedded site runs in an OPAQUE origin: it cannot reach window.parent or\n // touch same-origin storage, which also means localStorage access inside\n // the frame throws. The load guard and normalizeUrl's same-origin block\n // remain as defense-in-depth for any frame that still lands on the GUI\n // origin.\n const guardFrameNavigation = (): void => {\n const frame = frameRef.current\n if (frame === null) return\n try {\n const href = frame.contentWindow?.location.href\n if (href !== undefined && !href.startsWith('about:') && new URL(href).origin === window.location.origin) {\n frame.src = 'about:blank'\n }\n } catch {\n // Cross-origin frame: nothing to guard.\n }\n }\n\n return (\n <div className={previewCss.content}>\n <div className={previewCss.urlBar}>\n <input\n className={previewCss.urlInput}\n value={input}\n placeholder={t('preview.url.placeholder')}\n spellCheck={false}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') setUrl(normalizeUrl(input))\n if (event.key === 'Escape') {\n setInput(tab.content ?? '')\n setUrl(normalizeUrl(tab.content ?? ''))\n }\n }}\n onFocus={(event) => event.currentTarget.select()}\n />\n </div>\n <iframe\n // Keyed on url + reloadNonce: a refresh (or a new address) remounts\n // the frame, which re-navigates it — cross-origin documents cannot\n // be reloaded in place from the parent, and re-setting the src\n // attribute does not re-navigate when the value is unchanged.\n key={`${url}\\u0000${tab.reloadNonce ?? 0}`}\n ref={frameRef}\n className={previewCss.urlFrame}\n src={url}\n title={tab.title}\n sandbox=\"allow-scripts allow-forms allow-popups\"\n allow=\"autoplay; fullscreen; picture-in-picture; encrypted-media; clipboard-write\"\n allowFullScreen\n onLoad={guardFrameNavigation}\n />\n </div>\n )\n}\n\n/** Bare domains get https://; whitespace queries go to a search engine. */\nexport function normalizeUrl(input: string): string {\n const trimmed = input.trim()\n if (trimmed === '') return 'about:blank'\n if (/\\s/.test(trimmed)) return `https://www.bing.com/search?q=${encodeURIComponent(trimmed)}`\n const candidate = /^https?:\\/\\//i.test(trimmed) ? trimmed : `https://${trimmed}`\n // Never embed a URL that points back at the harness host: the url frame\n // runs with allow-scripts + allow-same-origin, so a same-origin page there\n // could reach the shell document (the onLoad guard resets indirect\n // same-origin navigations, but a directly typed address must not land at\n // all). Degrade it instead.\n if (typeof window !== 'undefined') {\n try {\n if (new URL(candidate).origin === window.location.origin) return 'about:blank'\n } catch {\n // Malformed URL: fall through and return the best-effort candidate.\n }\n }\n return candidate\n}\n\n/** Office / unsupported placeholder. */\nfunction UnsupportedViewer({ tab }: { tab: PreviewTabState }): JSX.Element {\n return (\n <div className={previewCss.placeholder}>\n <div className={previewCss.placeholderTitle}>{tab.title}</div>\n <div className={previewCss.placeholderMeta}>{t('preview.unsupported')}</div>\n <div className={previewCss.placeholderMeta}>{t('preview.downloadHint')}</div>\n </div>\n )\n}\n","/**\n * Translate a text selection inside the preview into a file reference (path\n * plus start/end line). The selection must live inside a `<pre>` of a file-\n * backed preview (code / text / markdown source / diff); returns null for\n * anything else so the caller can hide the floating action.\n *\n * The reference carries only what the agent needs: the workspace-relative\n * path of the file and the 1-based line range. The selected text itself is\n * not copied into the composer — the agent re-reads the file at the line\n * range when the message is sent.\n * @module dsh-filemgr/client/preview/selection\n */\n\nimport type { PreviewTabState } from '../store.ts'\n\n/** The file-backed reference we surface from a preview selection. */\nexport interface FileReferenceSelection {\n path: string\n startLine: number\n endLine: number\n}\n\n/** Content types that map cleanly to line-based references. */\nconst LINE_BASED_CONTENT_TYPES: ReadonlySet<PreviewTabState['contentType']> = new Set([\n 'code',\n 'text',\n 'markdown', // markdown source-mode selection still maps to text lines\n 'diff',\n])\n\n/** Number the 1-based line of `offset` within `text` (counting newlines before it). */\nfunction lineOf(text: string, offset: number): number {\n const upto = text.length === 0 ? '' : text.slice(0, Math.max(0, Math.min(offset, text.length)))\n let line = 1\n for (let i = 0; i < upto.length; i += 1) {\n if (upto.charCodeAt(i) === 10) line += 1\n }\n return line\n}\n\n/** Return the character offset of (node, offset) measured from the start of `pre`. */\nfunction offsetInPre(pre: HTMLPreElement, node: Node | null, offset: number): number | null {\n if (node === null) return null\n try {\n const range = document.createRange()\n range.setStart(pre, 0)\n range.setEnd(node, offset)\n return range.toString().length\n } catch {\n // Cross-boundary nodes (e.g. detached text) raise; fall through.\n return null\n }\n}\n\n/**\n * Build a FileReferenceSelection from a browser selection if it points to a\n * supported preview's `<pre>`. Returns null otherwise (image / pdf / url /\n * non-line content, or a selection that lives outside any code block).\n */\nexport function findFileReferenceSelection(\n anchorElement: Element | null,\n selection: Selection,\n tab: PreviewTabState | null,\n): FileReferenceSelection | null {\n if (anchorElement === null) return null\n if (tab === null || tab.content === null) return null\n if (!LINE_BASED_CONTENT_TYPES.has(tab.contentType)) return null\n const pre = anchorElement.closest('pre') as HTMLPreElement | null\n if (pre === null) return null\n const startInPre = offsetInPre(pre, selection.anchorNode, selection.anchorOffset)\n const endInPre = offsetInPre(pre, selection.focusNode, selection.focusOffset)\n if (startInPre === null || endInPre === null) return null\n const start = Math.min(startInPre, endInPre)\n const end = Math.max(startInPre, endInPre)\n if (start === end) return null\n const text = pre.textContent ?? ''\n return {\n path: tab.path,\n startLine: lineOf(text, start),\n endLine: lineOf(text, end),\n }\n}\n","/**\n * The preview panel root: tab strip + toolbar + content router, the tab\n * context menu (close left/right/others/all), the dirty-close confirmation\n * (the single entry for every batch close — middle-click included), and the\n * panel collapse button. View mode and split live here so the toolbar and the\n * content share one source; both reset when the displayed file changes.\n * @module dsh-filemgr/client/preview/PreviewPanel\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport { isEditableType } from '../fileType.ts'\nimport { t, format } from '../locales.ts'\nimport { useStore } from '../hooks/useStore.ts'\nimport type { PanelStores, PreviewTabState } from '../store.ts'\nimport { ConfirmDialog, ContextMenu, type MenuState } from '../components/overlay.tsx'\nimport { PreviewTabs } from './PreviewTabs.tsx'\nimport { PreviewToolbar, downloadTab } from './PreviewToolbar.tsx'\nimport { TabContent } from './content.tsx'\nimport { findFileReferenceSelection, type FileReferenceSelection } from './selection.ts'\nimport previewCss from '../styles/preview.module.css'\n\n/** Coords + a fully-resolved file-reference payload (path + line range). */\ninterface AddToChatState {\n x: number\n y: number\n ref: FileReferenceSelection\n}\n\n/** The preview panel (mounted in the preview grid column). */\nexport function PreviewPanel({ stores, onAddFileReference }: { stores: PanelStores; onAddFileReference: (selection: FileReferenceSelection) => boolean }): JSX.Element {\n const preview = stores.preview\n const state = useStore(preview)\n const layoutState = useStore(stores.layout)\n const maximizedPreview = layoutState.maximized === 'preview'\n const [menu, setMenu] = useState<MenuState | null>(null)\n const [closingIds, setClosingIds] = useState<string[] | null>(null)\n const [viewMode, setViewMode] = useState<'source' | 'preview'>('preview')\n const [split, setSplit] = useState(false)\n const lastDirtyCheck = useRef<Set<string>>(new Set())\n const panelRef = useRef<HTMLDivElement | null>(null)\n\n /** The \"add selection to the composer\" floating action. */\n const [addToChat, setAddToChat] = useState<AddToChatState | null>(null)\n\n const activeTab = state.tabs.find((tab) => tab.id === state.activeTabId) ?? null\n\n // View mode resets to preview when the displayed FILE changes (path+type).\n const identity = activeTab === null ? '' : `${activeTab.path}\\u0000${activeTab.contentType}`\n useEffect(() => {\n setViewMode('preview')\n setSplit(false)\n }, [identity])\n\n // Selection → \"添加到对话\" floating action: a non-collapsed selection inside\n // a file-backed (code/text) preview is translated into a file reference\n // (path + start/end line) and surfaces a button under the selection.\n useEffect(() => {\n const onSelectionChange = (): void => {\n const selection = window.getSelection()\n if (selection === null || selection.isCollapsed || selection.rangeCount === 0) {\n setAddToChat(null)\n return\n }\n const node = selection.anchorNode\n const el = node instanceof Element ? node : node?.parentElement\n if (el === undefined || panelRef.current === null || !panelRef.current.contains(el)) {\n setAddToChat(null)\n return\n }\n const ref = findFileReferenceSelection(el, selection, activeTab)\n if (ref === null) {\n setAddToChat(null)\n return\n }\n const rect = selection.getRangeAt(0).getBoundingClientRect()\n setAddToChat({ x: rect.left, y: rect.bottom + 8, ref })\n }\n const onPointerDown = (event: MouseEvent): void => {\n if (addToChat === null) return\n const target = event.target as Element\n if (target.closest(`.${previewCss.addToChat}`) === null) setAddToChat(null)\n }\n document.addEventListener('selectionchange', onSelectionChange)\n document.addEventListener('mousedown', onPointerDown)\n return () => {\n document.removeEventListener('selectionchange', onSelectionChange)\n document.removeEventListener('mousedown', onPointerDown)\n }\n }, [addToChat, activeTab])\n\n const handleAddToChat = (): void => {\n if (addToChat === null) return\n if (onAddFileReference(addToChat.ref)) setAddToChat(null)\n }\n\n /** Close a batch; dirty tabs route through the confirmation first. */\n const requestClose = (ids: string[]): void => {\n const dirty = state.tabs.filter((tab) => ids.includes(tab.id) && tab.dirty)\n if (dirty.length === 0) {\n preview.closeTabs(ids)\n return\n }\n lastDirtyCheck.current = new Set(dirty.map((tab) => tab.id))\n setClosingIds(ids)\n }\n\n const closeMenuFor = (event: React.MouseEvent, tab: PreviewTabState): void => {\n event.preventDefault()\n event.stopPropagation()\n const index = state.tabs.findIndex((item) => item.id === tab.id)\n setMenu({\n x: event.clientX,\n y: event.clientY,\n entries: [\n {\n key: 'close-left',\n label: t('preview.closeLeft'),\n disabled: index <= 0,\n onSelect: () => requestClose(state.tabs.slice(0, index).map((item) => item.id)),\n },\n {\n key: 'close-right',\n label: t('preview.closeRight'),\n disabled: index >= state.tabs.length - 1,\n onSelect: () => requestClose(state.tabs.slice(index + 1).map((item) => item.id)),\n },\n { key: 'sep-1', label: '---', onSelect: () => {} },\n {\n key: 'close-others',\n label: t('preview.closeOthers'),\n disabled: state.tabs.length <= 1,\n onSelect: () => requestClose(state.tabs.filter((item) => item.id !== tab.id).map((item) => item.id)),\n },\n {\n key: 'close-all',\n label: t('preview.closeAll'),\n onSelect: () => requestClose(state.tabs.map((item) => item.id)),\n },\n ],\n })\n }\n\n /** A fresh url tab (empty address; the viewer owns the input). */\n const newUrlTab = (): void => {\n const stamp = Date.now()\n const tab: PreviewTabState = {\n id: `url:${stamp}`,\n title: 'new tab',\n root: state.root,\n path: `url:${stamp}`,\n contentType: 'url',\n content: '',\n dirty: false,\n updated: false,\n loading: false,\n truncated: false,\n error: null,\n savedAt: Date.now(),\n }\n preview.update((prev) => ({ ...prev, open: true, tabs: [...prev.tabs, tab], activeTabId: tab.id }))\n }\n\n return (\n <div ref={panelRef} className={`filemgr-root ${previewCss.panel}`}>\n <PreviewTabs\n tabs={state.tabs}\n activeTabId={state.activeTabId}\n onSwitch={(id) => preview.switchTab(id)}\n onClose={(id) => requestClose([id])}\n onContextMenu={closeMenuFor}\n onNewUrlTab={newUrlTab}\n onClosePanel={() => preview.setOpen(false)}\n maximized={maximizedPreview}\n onMaximize={() => {\n stores.layout.update((prev) => ({ ...prev, maximized: maximizedPreview ? null : 'preview' }))\n }}\n />\n {activeTab !== null && (\n <>\n <PreviewToolbar\n contentType={activeTab.contentType}\n hasContent={activeTab.content !== null}\n loading={activeTab.loading}\n dirty={activeTab.dirty}\n updated={activeTab.updated}\n viewMode={viewMode}\n canToggleView={activeTab.contentType === 'markdown' || activeTab.contentType === 'html'}\n split={split}\n canSplit={isEditableType(activeTab.contentType) && activeTab.content !== null}\n onViewModeChange={setViewMode}\n onSplitChange={setSplit}\n onRefresh={() => void preview.reloadTab(activeTab.id)}\n onSave={() => void preview.saveTab(activeTab.id)}\n onDownload={() => downloadTab(activeTab)}\n />\n <TabContent\n tab={activeTab}\n viewMode={viewMode}\n split={split}\n onContentChange={(content) => preview.updateContent(activeTab.id, content)}\n onSave={() => void preview.saveTab(activeTab.id)}\n />\n </>\n )}\n {menu !== null && <ContextMenu state={menu} onClose={() => setMenu(null)} />}\n {addToChat !== null && (\n <div\n className={previewCss.addToChat}\n style={{ left: addToChat.x, top: addToChat.y }}\n onClick={handleAddToChat}\n role=\"button\"\n tabIndex={-1}\n >\n 添加到对话\n </div>\n )}\n {closingIds !== null && (\n <ConfirmDialog\n title={t('preview.closeConfirmTitle')}\n body={format(t('preview.closeConfirmBody'), { count: lastDirtyCheck.current.size })}\n confirmLabel={t('common.close')}\n danger\n onConfirm={() => {\n preview.closeTabs(closingIds)\n setClosingIds(null)\n }}\n onCancel={() => setClosingIds(null)}\n />\n )}\n </div>\n )\n}\n","/**\n * DOM mounting: two React roots rendered into the panel columns the layout\n * controller appends to the frame grid. The roots wait for their columns\n * (the shell mounts asynchronously), and everything is wrapped so a DOM\n * failure degrades the panels, never the GUI boot.\n * @module dsh-filemgr/client/mount\n */\n\nimport { createRoot, type Root } from 'react-dom/client'\nimport type { PanelStores } from './store.ts'\nimport { ExplorerPanel } from './components/ExplorerPanel.tsx'\nimport { PreviewPanel } from './preview/PreviewPanel.tsx'\nimport type { FileReferenceSelection } from './preview/selection.ts'\n\nconst EXPLORER_COL_SELECTOR = '[data-filemgr-explorer-col]'\nconst PREVIEW_COL_SELECTOR = '[data-filemgr-preview-col]'\n\n/** Wait for one selector (the shell/frame mounts after boot settlement). */\nfunction waitForElement(selector: string, onFound: (el: HTMLElement) => void): () => void {\n let disposed = false\n let observer: MutationObserver | undefined\n const tryFind = (): void => {\n if (disposed) return\n const el = document.querySelector<HTMLElement>(selector)\n if (el !== null) {\n observer?.disconnect()\n onFound(el)\n }\n }\n observer = new MutationObserver(() => { tryFind() })\n observer.observe(document.body, { childList: true, subtree: true })\n tryFind()\n return () => {\n disposed = true\n observer?.disconnect()\n }\n}\n\n/**\n * Mount both panel roots.\n * @param stores - the panel store bundle.\n * @param onToggleExplorer - collapse toggle (owned by the layout controller).\n * @param onReference - insert a file-reference chip into the draft for a file\n * (the Explorer row @-reference button); folders should call a different\n * helper because the chip has no line concept for them.\n * @param onAddFileReference - insert a file-reference chip into the draft for\n * a preview selection (path + start/end line).\n * @returns a disposer unmounting both trees.\n */\nexport function mountPanels(\n stores: PanelStores,\n onToggleExplorer: () => void,\n onReference: (path: string, isDir: boolean) => void,\n onAddFileReference: (selection: FileReferenceSelection) => boolean,\n): () => void {\n let explorerRoot: Root | undefined\n let previewRoot: Root | undefined\n const disposers: Array<() => void> = []\n\n disposers.push(waitForElement(EXPLORER_COL_SELECTOR, (el) => {\n explorerRoot = createRoot(el)\n explorerRoot.render(<ExplorerPanel stores={stores} onToggleCollapse={onToggleExplorer} onReference={onReference} />)\n }))\n disposers.push(waitForElement(PREVIEW_COL_SELECTOR, (el) => {\n previewRoot = createRoot(el)\n previewRoot.render(<PreviewPanel stores={stores} onAddFileReference={onAddFileReference} />)\n }))\n\n return () => {\n for (const dispose of disposers) dispose()\n explorerRoot?.unmount()\n previewRoot?.unmount()\n }\n}\n","/**\n * Composer dock inlay: the drop target for explorer file drags. It mounts\n * in the official `conversation.input.dock` band (a session-scoped list\n * slot declared by the shipped ui-conversation rc.6 shell), so it stacks\n * with the git-graph chip above the composer card. While a file row is\n * dragged over the page it shows a hint strip; on drop it splices the\n * workspace-relative path into the active session's draft through the\n * conversation input facade.\n *\n * The document-level listeners only claim drags carrying our custom MIME —\n * the composer host's own drop handling (OS image files) is untouched. The\n * host's `dragover` refuses every drop it does not claim, so this inlay\n * must `preventDefault` its own drags to make the drop land.\n * @module dsh-filemgr/client/drag/DragFileInlay\n */\n\nimport { useEffect, useRef, useState, type ReactElement } from 'react'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { FILE_DRAG_MIME, hasFileDrag, isValidFileDragPayload } from './file-drag.ts'\nimport { t } from '../locales.ts'\nimport dragCss from '../styles/drag.module.css'\n\n/** Injected business face of the drag inlay (session-routed). */\nexport interface DragFileInjected {\n /** Splice a workspace-relative path into the active session's draft. */\n insertPath: (path: string) => boolean\n}\n\n/** Composed props: the dock's runtime share (sessionId) + the injected verb. */\nexport type DragFileInlayProps =\n PropsRuntime<'conversation.input.dock'>\n & DragFileInjected\n\n/**\n * The composer dock entry: a zero-height anchor that shows a hint strip\n * while a file row is dragged over the page and inserts the path on drop.\n * @param props - the composed dock entry props.\n */\nexport function DragFileInlay(props: DragFileInlayProps): ReactElement {\n const [active, setActive] = useState(false)\n const depth = useRef(0)\n\n useEffect(() => {\n const reset = (): void => {\n depth.current = 0\n setActive(false)\n }\n const onDragOver = (event: DragEvent): void => {\n if (!hasFileDrag(event.dataTransfer?.types)) return\n event.preventDefault()\n depth.current += 1\n setActive(true)\n }\n const onDragLeave = (event: DragEvent): void => {\n if (!hasFileDrag(event.dataTransfer?.types)) return\n depth.current = Math.max(0, depth.current - 1)\n if (depth.current === 0) setActive(false)\n }\n const onDrop = (event: DragEvent): void => {\n if (!hasFileDrag(event.dataTransfer?.types)) return\n event.preventDefault()\n const path = event.dataTransfer?.getData(FILE_DRAG_MIME) ?? ''\n reset()\n if (isValidFileDragPayload(path)) props.insertPath(path)\n }\n const onDragEnd = (): void => reset()\n document.addEventListener('dragover', onDragOver)\n document.addEventListener('dragleave', onDragLeave)\n document.addEventListener('drop', onDrop)\n window.addEventListener('dragend', onDragEnd)\n return () => {\n document.removeEventListener('dragover', onDragOver)\n document.removeEventListener('dragleave', onDragLeave)\n document.removeEventListener('drop', onDrop)\n window.removeEventListener('dragend', onDragEnd)\n }\n }, [props.insertPath])\n\n return (\n <div\n className={active ? `${dragCss.strip} ${dragCss.stripActive}` : dragCss.strip}\n data-testid=\"filemgr-drag-inlay\"\n aria-live=\"polite\"\n >\n {active ? <span className={dragCss.stripText}>{t('explorer.drag.dropHint')}</span> : null}\n </div>\n )\n}\n","/**\n * Chat-transcript mermaid enhancement: the core conversation renderer emits\n * fenced code as `pre > code.language-mermaid`, and the shell has no slot\n * for message-body post-processing — so this component rides the\n * conversation input dock as a zero-render sentinel and observes the\n * document for mermaid blocks the transcript mounts. Blocks inside the\n * preview panel's own subtree are excluded (each surface owns its blocks).\n *\n * Streaming awareness: an assistant message re-renders continuously, so a\n * diagram fence is often incomplete mid-stream. Renders that fail restore\n * the block and the next mutation retries it — once the fence closes the\n * diagram lands. Mutations are debounced to one rAF so long transcripts do\n * not re-scan the whole document: each batch is mapped to the minimal\n * mutated subtrees and scoped per-frame while the first scheduled pass scans\n * the body once. The observer is disconnected on unmount.\n * @module dsh-filemgr/client/chat/mermaid-chat\n */\n\nimport { useEffect } from 'react'\nimport type { JSX } from 'react'\nimport { DATA_MD_SCOPE, enhanceMermaidBlocks, mermaidTheme, rethemeMermaidBlocks, shellIsDark, watchShellTheme } from '../preview/mermaid.ts'\nimport previewCss from '../styles/preview.module.css'\n\n/**\n * Map a mutation batch to the minimal scan scopes that may contain new\n * mermaid fences. Each record contributes its target and its added nodes\n * (an added element directly; otherwise that node's parentElement), deduped\n * by identity. Disconnected nodes and removed-only records yield nothing —\n * removal never introduces a fence. Pure (DOM-read only) so tests can drive\n * it in jsdom.\n */\nexport function enhanceScopesFor(records: MutationRecord[]): Element[] {\n const scopes = new Set<Element>()\n for (const record of records) {\n // Removal-only batches do not introduce a fence: without additions the\n // target scan is wasted, so only records carrying added nodes contribute.\n if (record.addedNodes.length === 0) continue\n if (record.target instanceof Element && record.target.isConnected) {\n scopes.add(record.target)\n }\n for (const node of record.addedNodes) {\n const element = node instanceof Element ? node : node.parentElement\n if (element !== null && element.isConnected) scopes.add(element)\n }\n }\n return Array.from(scopes)\n}\n\n/** Hidden sentinel: renders nothing, owns the transcript observer. */\nexport function MermaidChatEnhancer(): JSX.Element | null {\n useEffect(() => {\n let scheduled = false\n let pendingFrame = 0\n let firstPass = true\n let pendingRecords: MutationRecord[] = []\n const run = (): void => {\n scheduled = false\n const records = pendingRecords\n pendingRecords = []\n const scopes = enhanceScopesFor(records)\n if (firstPass) {\n // First scheduled pass only: scan the whole document exactly once.\n // Later batches (even removal-only ones that yield no scopes) never\n // fall back to a full-body scan.\n firstPass = false\n void enhanceMermaidBlocks(document.body, {\n className: previewCss.mermaidBlock,\n theme: mermaidTheme(shellIsDark()),\n skip: (pre) => pre.closest(`[${DATA_MD_SCOPE}]`) !== null,\n })\n return\n }\n for (const scope of scopes) {\n void enhanceMermaidBlocks(scope, {\n className: previewCss.mermaidBlock,\n theme: mermaidTheme(shellIsDark()),\n skip: (pre) => pre.closest(`[${DATA_MD_SCOPE}]`) !== null,\n })\n }\n }\n const schedule = (): void => {\n if (scheduled) return\n scheduled = true\n pendingFrame = requestAnimationFrame(run)\n }\n const observer = new MutationObserver((records) => {\n pendingRecords = pendingRecords.concat(records)\n schedule()\n })\n observer.observe(document.body, { childList: true, subtree: true })\n schedule()\n const disposeTheme = watchShellTheme((isDark) => {\n void rethemeMermaidBlocks(document.body, { theme: mermaidTheme(isDark) })\n })\n return () => {\n observer.disconnect()\n disposeTheme()\n cancelAnimationFrame(pendingFrame)\n }\n }, [])\n return null\n}\n","/**\n * Composer placeholder hint: the shell owns the input-bar placeholder\n * (\"给智能体发消息\") and exposes no override seam (the composer bar is a\n * single slot owned by ui-conversation, and its locale namespace rejects\n * duplicate registration), so this zero-render sentinel — riding the same\n * `conversation.input.dock` band as the mermaid enhancer — rewrites the\n * placeholder attribute in the DOM. It re-applies on any placeholder\n * attribute change or node insert, which covers React re-renders that\n * reset the attribute to the shell default. English UI is left untouched\n * (exact-match on the Chinese string only).\n * @module dsh-filemgr/client/chat/placeholder-hint\n */\n\nimport { useEffect } from 'react'\nimport type { JSX } from 'react'\n\nconst OLD_PLACEHOLDER = '给智能体发消息'\nconst NEW_PLACEHOLDER = '给智能体发消息。@引用项目文件,/ 调用技能与指令'\n\n/** Rewrite every composer input whose placeholder matches the shell default. */\nfunction apply(): void {\n for (const el of document.querySelectorAll<HTMLTextAreaElement | HTMLInputElement>('textarea, input[type=\"text\"]')) {\n if (el.placeholder === OLD_PLACEHOLDER) el.placeholder = NEW_PLACEHOLDER\n }\n}\n\n/** Hidden sentinel: renders nothing, owns the placeholder rewriting observer. */\nexport function PlaceholderHint(): JSX.Element | null {\n useEffect(() => {\n apply()\n const observer = new MutationObserver((records) => {\n const relevant = records.some(\n (record) => record.type === 'attributes' || record.addedNodes.length > 0,\n )\n if (relevant) apply()\n })\n observer.observe(document.body, {\n attributes: true,\n attributeFilter: ['placeholder'],\n childList: true,\n subtree: true,\n })\n return () => { observer.disconnect() }\n }, [])\n return null\n}\n","/**\n * File-picker bridge: the single channel between the '@' trigger source\n * (which asks for a directory) and the tree-browser modal (which renders it).\n *\n * Why a modal and not the inline trigger menu: the shell's trigger menu is a\n * flat candidate list with no tree affordance — picking a directory cannot\n * expand it (the menu closes on pick, and the shell only re-runs trigger\n * detection on keyboard input, not on programmatic draft writes). The modal\n * is the pi-desktop-style answer: a real directory tree with lazy expansion,\n * a search box, and one-click insertion.\n *\n * The bridge is framework-free (subscribe/getSnapshot/open/close) so the\n * trigger source can open the picker without touching React; the modal host\n * component subscribes and renders. Insertion happens through the\n * conversation input shell, replacing the exact `@` token span the picker\n * was opened from.\n * @module dsh-filemgr/client/picker/file-picker\n */\n\nimport type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\n\n/** The `@` token span captured when the picker opened (replace-on-insert). */\nexport interface PickSpan {\n /** Start offset of the `@` token in the draft. */\n start: number\n /** End offset (the caret). */\n end: number\n}\n\n/** What the picker is currently anchored to. */\nexport interface PickRequest {\n /** Session whose draft the picker will edit. */\n sessionId: SessionId\n /** Project root (canonical cwd) everything is relative to. */\n root: string\n /** Directory to start browsing at ('' = root). */\n initialDir: string\n /** The `@` token span to replace on insert. */\n span: PickSpan\n}\n\n/** The bridge's public snapshot. */\nexport interface PickState {\n open: boolean\n req: PickRequest | null\n}\n\n/** Minimal listener shape. */\ntype Listener = (state: PickState) => void\n\n/** Framework-free singleton store backing the modal. */\nclass FilePickerBridge {\n private state: PickState = { open: false, req: null }\n private readonly listeners = new Set<Listener>()\n\n /** Current snapshot (stable reference until the next open/close). */\n getSnapshot(): PickState {\n return this.state\n }\n\n /** Subscribe to open/close transitions. */\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n /** Open the picker anchored to one `@` token. */\n open(req: PickRequest): void {\n this.state = { open: true, req }\n this.emit()\n }\n\n /** Close the picker without inserting anything. */\n close(): void {\n if (!this.state.open) return\n this.state = { open: false, req: null }\n this.emit()\n }\n\n private emit(): void {\n for (const listener of this.listeners) listener(this.state)\n }\n}\n\n/** The shared singleton instance. */\nexport const filePicker = new FilePickerBridge()\n","import type { ClientContext, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\n\n/**\n * Composer draft helpers for file references.\n *\n * References ride the shell's native U+FFFC chip pipeline\n * (`slash/input-insert-reference` bail): the composer shows one chip pill in\n * place of the hidden `@path:lines` token, and the model text is serialized\n * on submit through the `file` reference source's codec (registered in\n * file-source.ts). Without that codec the submit attempt fails with\n * `slash: no serializer for reference source \"file\"` — the codec MUST stay\n * registered while any chip is in a draft.\n */\n\n/**\n * Minimal structural view of the conversation input service. Declared locally\n * so this helper has no value import from the conversation package (keeps the\n * client bundle purity gate happy).\n */\ninterface DraftInput {\n state: { getSnapshot(): { draft: string; draftRev: number } }\n setDraft(draft: string): void\n}\nexport interface ConversationService {\n input: { for(actx: ClientContext): DraftInput }\n}\n\n/** The file-backed reference a composer chip stands for. */\nexport interface FileReference {\n /** Workspace-relative path (what the agent will read). */\n path: string\n /** First line of the referenced range (1-based, inclusive). */\n startLine: number\n /** Last line of the referenced range (1-based, inclusive). */\n endLine: number\n}\n\n/** Basename of a `/`-separated relative path ('' when empty). */\nfunction basenameOf(rel: string): string {\n const idx = rel.lastIndexOf('/')\n return idx >= 0 ? rel.slice(idx + 1) : rel\n}\n\n/** Directory of a `/`-separated relative path ('' when none). */\nfunction dirnameOf(rel: string): string {\n const idx = rel.lastIndexOf('/')\n return idx > 0 ? rel.slice(0, idx) : ''\n}\n\n/**\n * The chip label: basename, or `basename - dir` when the basename is\n * ambiguous across the workspace (matches the reference screenshot: a short\n * name plus the line range, never the full path).\n */\nfunction formatRefLabel(ref: FileReference): string {\n const basename = basenameOf(ref.path)\n const dirname = dirnameOf(ref.path)\n const name = dirname === '' ? basename : `${basename} - ${dirname}`\n return ref.endLine > ref.startLine ? `${name} ${ref.startLine}-${ref.endLine}` : `${name} ${ref.startLine}`\n}\n\n/** The `@path:lines` model form (what the codec serializes to on submit). */\nexport function formatFileRefToken(ref: { path: string; startLine: number; endLine: number }): string {\n const range = ref.endLine > ref.startLine ? `${ref.startLine}-${ref.endLine}` : `${ref.startLine}`\n return `@${ref.path}:${range}`\n}\n\n/** Reference shape the conversation machine mints into a chip occurrence. */\ninterface ConversationReference {\n source: string\n ref: string\n label: string\n clipboardText: string\n}\n\n/** The DRAFT-REV+CAS span the conversation machine expects for chip inserts. */\nexport interface RefSpan {\n start: number\n end: number\n draftRev: number\n}\n\n/** Append `text` to the session's composer draft (plain text — no chip). */\nexport function appendToDraft(ctx: ClientContext, sessionId: SessionId | undefined, text: string): boolean {\n try {\n if (sessionId === undefined) return false\n const actx = ctx.sessions.scope(sessionId)\n if (actx === undefined) return false\n const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation\n if (conversation === undefined) return false\n const input = conversation.input.for(actx as unknown as ClientContext)\n const draft = input.state.getSnapshot().draft\n input.setDraft(draft.trim() === '' ? text : `${draft} ${text}`)\n return true\n } catch (error) {\n console.warn('[dsh-filemgr] draft insert failed:', error)\n return false\n }\n}\n\n/**\n * Insert a file-reference chip into the composer draft at `span`, replacing\n * its range with an occurrence the machine renders as a `</> name N-M`\n * pill. The model text (`@path:lines`) is serialized on submit by the `file`\n * source's codec (file-source.ts) — never the clipboard text.\n *\n * @returns true when the bail was accepted (CAS will still reject on\n * stale draftRev — caller can re-read draft after).\n */\nexport function insertFileReference(\n ctx: ClientContext,\n sessionId: SessionId | undefined,\n ref: FileReference,\n span: RefSpan,\n): boolean {\n try {\n if (sessionId === undefined) return false\n const actx = ctx.sessions.scope(sessionId)\n if (actx === undefined) return false\n const reference: ConversationReference = {\n source: 'file',\n ref: formatFileRefToken(ref),\n label: formatRefLabel(ref),\n clipboardText: formatFileRefToken(ref),\n }\n return (actx as unknown as {\n bail(target: unknown, event: string, payload: unknown): boolean\n }).bail(actx, 'slash/input-insert-reference', { reference, span })\n } catch (error) {\n console.warn('[dsh-filemgr] file-reference insert failed:', error)\n return false\n }\n}\n\n/**\n * Append a file-reference chip at the end of the current draft (the explorer\n * `@` button and the preview \"添加到对话\" action path). Reads the latest\n * draft + draftRev from the conversation shell and inserts a zero-length chip\n * there, so the chip lands after whatever the user has already typed.\n *\n * @returns true on success.\n */\nexport function appendFileReferenceChip(\n ctx: ClientContext,\n sessionId: SessionId | undefined,\n ref: FileReference,\n): boolean {\n if (sessionId === undefined) return false\n const actx = ctx.sessions.scope(sessionId)\n if (actx === undefined) return false\n const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation\n if (conversation === undefined) return false\n const shell = conversation.input.for(actx as unknown as ClientContext)\n const snap = shell.state.getSnapshot()\n return insertFileReference(\n ctx,\n sessionId,\n ref,\n { start: snap.draft.length, end: snap.draft.length, draftRev: snap.draftRev },\n )\n}\n","/**\n * File-picker modal: a pi-desktop-style multi-select tree browser for '@'\n * file/folder references.\n *\n * Trigger: typing `@` (with nothing after it) in the composer opens this\n * modal directly — no inline trigger menu (the shell's trigger menu is a\n * flat candidate list that cannot host a tree). The modal owns a recursive\n * tree with lazy expansion, a workspace filename search, per-row checkboxes\n * for multi-selection, and a chip row of the picked paths.\n *\n * Insertion replaces the `@` token the picker was opened from with the\n * picked references joined by spaces (`@a.ts @src/ @b.md`); cancel drops\n * the stray `@`.\n * @module dsh-filemgr/client/picker/FilePickerModal\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport { createPortal } from 'react-dom'\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { FsEntry, SearchHit } from '../../core/types.ts'\nimport type { PanelApi } from '../api.ts'\nimport { filePicker, type PickState } from './file-picker.ts'\nimport { ChevronDownIcon, ChevronRightIcon, CloseIcon, FileIcon, FolderIcon, FolderOpenIcon, SearchIcon } from '../components/icons.tsx'\nimport { appendToDraft, insertFileReference, type RefSpan } from '../reference.ts'\nimport pickerCss from '../styles/picker.module.css'\n\n/** Debounce for the workspace search box. */\nconst SEARCH_DEBOUNCE_MS = 200\n\n/** Split a relative path into its ancestor chain ('' when empty). */\nfunction ancestors(rel: string): string[] {\n const out: string[] = []\n let acc = ''\n for (const part of rel.split('/')) {\n if (part === '') continue\n acc = acc === '' ? part : `${acc}/${part}`\n out.push(acc)\n }\n return out\n}\n\n/** One picked path with its kind (drives the trailing slash on insert). */\nexport interface PickedPath {\n path: string\n isDir: boolean\n}\n\n/** The modal surface (portal target; renders only while open). */\nexport function FilePickerModal({\n state,\n api,\n onInsert,\n onClose,\n}: {\n state: PickState\n api: PanelApi\n onInsert: (paths: PickedPath[]) => void\n onClose: () => void\n}): JSX.Element | null {\n const req = state.req\n const root = req?.root ?? ''\n const [expanded, setExpanded] = useState<Set<string>>(new Set())\n const [dirs, setDirs] = useState<Record<string, FsEntry[]>>({})\n const [loading, setLoading] = useState<Record<string, boolean>>({})\n const [selected, setSelected] = useState<Map<string, boolean>>(new Map())\n const [search, setSearch] = useState('')\n const [searchResults, setSearchResults] = useState<SearchHit[] | null>(null)\n const [searching, setSearching] = useState(false)\n const searchSeq = useRef(0)\n\n /** Load one directory listing into the tree cache (guarded). */\n const loadDir = (dir: string): void => {\n if (dirs[dir] !== undefined || loading[dir]) return\n setLoading((prev) => ({ ...prev, [dir]: true }))\n void api.list(root, dir).then((result) => {\n setLoading((prev) => ({ ...prev, [dir]: false }))\n if (result.ok) setDirs((prev) => ({ ...prev, [dir]: result.value.entries }))\n })\n }\n\n /** Prime the tree: root + the initial directory's ancestor chain. */\n useEffect(() => {\n setExpanded(new Set())\n setDirs({})\n setLoading({})\n setSelected(new Map())\n setSearch('')\n setSearchResults(null)\n if (root === '') return\n loadDir('')\n if (req !== null && req.initialDir !== '') {\n for (const dir of ancestors(req.initialDir)) {\n setExpanded((prev) => new Set(prev).add(dir))\n loadDir(dir)\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [root, req?.initialDir])\n\n // Debounced, seq-guarded workspace filename search.\n useEffect(() => {\n const q = search.trim()\n if (q === '') {\n searchSeq.current += 1\n setSearchResults(null)\n setSearching(false)\n return\n }\n const seq = ++searchSeq.current\n setSearching(true)\n const timer = setTimeout(() => {\n void api.search(root, q).then((result) => {\n if (searchSeq.current !== seq) return\n setSearching(false)\n setSearchResults(result.ok ? result.value.hits : [])\n })\n }, SEARCH_DEBOUNCE_MS)\n return () => { clearTimeout(timer) }\n }, [search, root, api])\n\n const toggleDir = (dir: string): void => {\n setExpanded((prev) => {\n const next = new Set(prev)\n if (next.has(dir)) next.delete(dir)\n else {\n next.add(dir)\n loadDir(dir)\n }\n return next\n })\n }\n\n /** Toggle one path in the multi-selection (checkbox semantics). */\n const toggleSelect = (path: string, isDir: boolean): void => {\n setSelected((prev) => {\n const next = new Map(prev)\n if (next.has(path)) next.delete(path)\n else next.set(path, isDir)\n return next\n })\n }\n\n // Escape closes.\n useEffect(() => {\n if (!state.open) return\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') onClose()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [state.open, onClose])\n\n const tree = useMemo(() => {\n const renderNode = (entry: FsEntry, depth: number): JSX.Element => {\n const isDir = entry.isDir\n const isOpen = expanded.has(entry.path)\n const isSel = selected.has(entry.path)\n const children = dirs[entry.path] ?? []\n const isLoading = loading[entry.path] === true\n return (\n <div key={entry.path}>\n <div\n className={`${pickerCss.row}${isSel ? ` ${pickerCss.rowSelected}` : ''}`}\n style={{ paddingLeft: 8 + depth * 16 }}\n onClick={() => toggleSelect(entry.path, isDir)}\n >\n <span\n className={pickerCss.chev}\n role=\"button\"\n tabIndex={-1}\n onClick={(e) => {\n if (!isDir) return\n e.stopPropagation()\n toggleDir(entry.path)\n }}\n >\n {isDir ? (isOpen ? <ChevronDownIcon size={14} /> : <ChevronRightIcon size={14} />) : <span className={pickerCss.chevSpacer} />}\n </span>\n <span className={pickerCss.icon}>\n {isDir ? (isOpen ? <FolderOpenIcon size={15} /> : <FolderIcon size={15} />) : <FileIcon size={15} />}\n </span>\n <span className={pickerCss.name} title={entry.path}>{entry.name}</span>\n <span\n className={`${pickerCss.check}${isSel ? ` ${pickerCss.checkOn}` : ''}`}\n onClick={(e) => {\n e.stopPropagation()\n toggleSelect(entry.path, isDir)\n }}\n >\n {isSel ? <CheckIcon size={12} /> : null}\n </span>\n </div>\n {isDir && isOpen && (\n <div>\n {isLoading ? (\n <div className={pickerCss.note} style={{ paddingLeft: 8 + (depth + 1) * 16 }}>加载中…</div>\n ) : children.length === 0 ? (\n <div className={pickerCss.note} style={{ paddingLeft: 8 + (depth + 1) * 16 }}>(空目录)</div>\n ) : (\n children.map((child) => renderNode(child, depth + 1))\n )}\n </div>\n )}\n </div>\n )\n }\n return renderNode\n }, [expanded, dirs, loading, selected, toggleDir, toggleSelect])\n\n if (!state.open || req === null) return null\n const rootEntries = dirs[''] ?? []\n const rootLoading = loading[''] === true\n const selectedList: PickedPath[] = Array.from(selected.entries()).map(([path, isDir]) => ({ path, isDir }))\n\n return createPortal(\n <div className={pickerCss.overlay} onMouseDown={(e) => { if (e.target === e.currentTarget) onClose() }}>\n <div className={pickerCss.modal} onClick={(e) => e.stopPropagation()}>\n <div className={pickerCss.header}>\n <div className={pickerCss.titleRow}>\n <span className={pickerCss.title}>引用项目文件</span>\n <button type=\"button\" className={pickerCss.closeBtn} onClick={onClose} aria-label=\"关闭\">\n <CloseIcon size={16} />\n </button>\n </div>\n <div className={pickerCss.searchWrap}>\n <span className={pickerCss.searchIcon}><SearchIcon size={14} /></span>\n <input\n className={pickerCss.searchInput}\n placeholder=\"搜索工作区文件…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n autoFocus\n />\n {search !== '' && (\n <button type=\"button\" className={pickerCss.searchClear} onClick={() => setSearch('')} aria-label=\"清空\">\n <CloseIcon size={13} />\n </button>\n )}\n </div>\n <div className={pickerCss.rootPath} title={root}>{root}</div>\n </div>\n\n <div className={pickerCss.body}>\n {searchResults !== null ? (\n searching ? (\n <div className={pickerCss.note}>搜索中…</div>\n ) : searchResults.length === 0 ? (\n <div className={pickerCss.note}>没有匹配的文件</div>\n ) : (\n searchResults.map((hit) => {\n const isSel = selected.has(hit.path)\n return (\n <div\n key={hit.path}\n className={`${pickerCss.row}${isSel ? ` ${pickerCss.rowSelected}` : ''}`}\n onClick={() => toggleSelect(hit.path, false)}\n >\n <span className={pickerCss.chevSpacer} />\n <span className={pickerCss.icon}><FileIcon size={15} /></span>\n <span className={pickerCss.name} title={hit.path}>\n <span>{hit.name}</span>\n <span className={pickerCss.subpath}>{hit.path}</span>\n </span>\n <span\n className={`${pickerCss.check}${isSel ? ` ${pickerCss.checkOn}` : ''}`}\n onClick={(e) => {\n e.stopPropagation()\n toggleSelect(hit.path, false)\n }}\n >\n {isSel ? <CheckIcon size={12} /> : null}\n </span>\n </div>\n )\n })\n )\n ) : rootLoading ? (\n <div className={pickerCss.note}>加载中…</div>\n ) : rootEntries.length === 0 ? (\n <div className={pickerCss.note}>(空目录)</div>\n ) : (\n rootEntries.map((entry) => tree(entry, 0))\n )}\n </div>\n\n <div className={pickerCss.footer}>\n <div className={pickerCss.chips}>\n {selectedList.length === 0 ? (\n <span className={pickerCss.chipsEmpty}>选择文件或目录(可多选)</span>\n ) : (\n selectedList.map((pick) => (\n <span key={pick.path} className={pickerCss.chip}>\n <span>@{pick.path}{pick.isDir ? '/' : ''}</span>\n <button\n type=\"button\"\n className={pickerCss.chipX}\n onClick={() => toggleSelect(pick.path, pick.isDir)}\n aria-label=\"移除\"\n >\n <CloseIcon size={11} />\n </button>\n </span>\n ))\n )}\n </div>\n <div className={pickerCss.footerActions}>\n <button type=\"button\" className={pickerCss.cancelBtn} onClick={onClose}>取消</button>\n <button\n type=\"button\"\n className={pickerCss.insertBtn}\n disabled={selectedList.length === 0}\n onClick={() => onInsert(selectedList)}\n >\n 插入{selectedList.length > 0 ? ` (${selectedList.length})` : ''}\n </button>\n </div>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n\n/** Minimal inline check glyph (avoids an extra icon import cycle). */\nfunction CheckIcon({ size }: { size: number }): JSX.Element {\n return (\n <svg width={size} height={size} viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2.5 6.2 4.8 8.5 9.5 3.5\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\n/** Minimal structural view of the conversation input service (see reference.ts). */\ninterface DraftInput {\n state: { getSnapshot(): { draft: string; draftRev: number } }\n setDraft(draft: string): void\n}\ninterface ConversationService {\n input: { for(actx: ClientContext): DraftInput }\n}\n\n/** Active `@` mention candidate in the draft (mimics pi-desktop's getActiveMention). */\nexport function findAtMention(value: string, caret: number): { start: number; query: string } | null {\n const before = value.slice(0, caret)\n const at = before.lastIndexOf('@')\n if (at < 0) return null\n // The '@' must sit at a token boundary (start or after whitespace/punctuation).\n if (at > 0 && !/[\\s,;.!?()[\\]{}\"'/\\\\]/.test(before[at - 1])) return null\n return { start: at, query: before.slice(at + 1) }\n}\n\n/**\n * The picker host: watches the composer textarea for a bare `@` (opening the\n * modal directly, pi-desktop style — no inline trigger menu), subscribes to\n * the bridge, and renders the modal. Insertion replaces the `@` token span\n * with the picked references joined by spaces; cancel drops the stray `@`.\n */\nexport function FilePickerHost({ ctx, api }: { ctx: ClientContext; api: PanelApi }): JSX.Element {\n const [state, setState] = useState<PickState>(filePicker.getSnapshot())\n useEffect(() => filePicker.subscribe(setState), [])\n\n // When the modal opens, close the shell's inline trigger menu: the `file`\n // codec source registers under '@' (and any other '@' sources exist), so a\n // bare `@` also pops the flat menu — the modal must be the only surface.\n useEffect(() => {\n if (!state.open || state.req === null) return\n try {\n const actx = ctx.sessions.scope(state.req.sessionId)\n if (actx === undefined) return\n const inputTriggers = (ctx as unknown as {\n get(name: string): unknown\n }).get('inputTriggers') as { sessionOf(a: ClientContext): { dismiss(): void } } | undefined\n inputTriggers?.sessionOf(actx).dismiss()\n } catch {\n // Menu dismissal is best-effort; the modal stands alone regardless.\n }\n }, [state.open, state.req, ctx])\n\n // Composer `@` watcher: open the picker the moment a bare `@` lands.\n useEffect(() => {\n const watched = new WeakSet<HTMLTextAreaElement>()\n const onInput = (e: Event): void => {\n if (filePicker.getSnapshot().open) return\n const ta = e.target as HTMLTextAreaElement\n const caret = ta.selectionStart ?? ta.value.length\n const mention = findAtMention(ta.value, caret)\n if (mention === null || mention.query !== '') return\n const snapshot = ctx.sessions.list.getSnapshot()\n const sessionId = snapshot.current\n if (sessionId === undefined) return\n const cwd = snapshot.byId[sessionId]?.cwd\n const root = typeof cwd === 'string' && cwd !== '' ? cwd : ''\n if (root === '') return\n filePicker.open({\n sessionId,\n root,\n initialDir: '',\n span: { start: mention.start, end: mention.start + 1 },\n })\n }\n const attach = (): void => {\n for (const ta of document.querySelectorAll<HTMLTextAreaElement>('textarea')) {\n if (watched.has(ta)) continue\n watched.add(ta)\n ta.addEventListener('input', onInput)\n }\n }\n attach()\n const observer = new MutationObserver(attach)\n observer.observe(document.body, { childList: true, subtree: true })\n return () => {\n observer.disconnect()\n for (const ta of document.querySelectorAll<HTMLTextAreaElement>('textarea')) {\n ta.removeEventListener('input', onInput)\n }\n }\n }, [ctx])\n\n /**\n * Insert the picked references into the composer draft as file-reference\n * chips (one `slash/input-insert-reference` bail per file; the `file`\n * source codec serializes each to `@path:lines` on submit). Folders fall\n * back to plain `@path/ ` text since the chip has no line concept.\n * Multiple selections land as adjacent chips.\n */\n const insert = async (paths: PickedPath[]): Promise<void> => {\n const current = filePicker.getSnapshot()\n if (!current.open || current.req === null || paths.length === 0) return\n const { sessionId, root, span } = current.req\n try {\n const actx = ctx.sessions.scope(sessionId)\n if (actx === undefined) return\n const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation\n if (conversation === undefined) return\n const shell = conversation.input.for(actx)\n // Pre-fetch every file's line count in parallel (bails are serial so\n // they share the same draft; reads are independent).\n const lineCounts = await Promise.all(paths.map(async (pick) => {\n if (pick.isDir) return { pick, lines: null }\n const result = await api.read(root, pick.path, false)\n if (!result.ok) return { pick, lines: null }\n const text = result.value.content\n const trimmed = text.endsWith('\\n') ? text.slice(0, -1) : text\n const lines = trimmed === '' ? 1 : trimmed.split('\\n').length\n return { pick, lines }\n }))\n // Walk in original order. The first chip replaces the `@` token; the\n // rest insert at the current cursor (0-length span) so the machine\n // appends each one in turn.\n let cursor = span.end\n let firstSpan = true\n for (const { pick, lines } of lineCounts) {\n if (pick.isDir) {\n appendToDraft(ctx, sessionId, `@${pick.path}/ `)\n continue\n }\n if (lines === null) continue\n const snap = shell.state.getSnapshot()\n const currentSpan: RefSpan = firstSpan\n ? { start: span.start, end: span.end, draftRev: snap.draftRev }\n : { start: cursor, end: cursor, draftRev: snap.draftRev }\n const ok = insertFileReference(\n ctx,\n sessionId,\n { path: pick.path, startLine: 1, endLine: lines },\n currentSpan,\n )\n if (ok) {\n firstSpan = false\n // The machine replaces [start,end) with U+FFFC and an optional\n // trailing space; the cursor advances by 2 for the new characters.\n cursor += 2\n }\n }\n filePicker.close()\n } catch (error) {\n console.warn('[dsh-filemgr] picker insert failed:', error)\n }\n }\n\n /** Cancel: drop the stray `@` the picker was opened from. */\n const close = (): void => {\n const current = filePicker.getSnapshot()\n if (current.open && current.req !== null) {\n const { sessionId, span } = current.req\n try {\n const actx = ctx.sessions.scope(sessionId)\n const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation\n if (actx !== undefined && conversation !== undefined) {\n const shell = conversation.input.for(actx)\n const draft = shell.state.getSnapshot().draft\n const token = draft.slice(span.start, span.end)\n if (token.startsWith('@')) {\n shell.setDraft(draft.slice(0, span.start) + draft.slice(span.end))\n }\n }\n } catch {\n // Best-effort cleanup; the picker still closes.\n }\n }\n filePicker.close()\n }\n\n return <FilePickerModal state={state} api={api} onInsert={insert} onClose={close} />\n}\n","/**\n * Chat file-reference click handling (issue #314): the transcript renders\n * workspace file paths as inline code, and clicking one should locate the\n * file in the Explorer (switch to the Files tab, expand the ancestor chain,\n * select the node) and open it in the Preview panel — directories are\n * reveal-only. A document-level click listener (wired in the client apply)\n * recognizes a conservative subset: a single-line `code` element whose text\n * is a workspace-relative path or an absolute path under the project root.\n * Links (`a`), multi-line fences, URLs, escaped (`..`) paths and anything\n * inside the panels' own subtrees keep their existing behavior.\n * @module dsh-filemgr/client/chat/file-ref\n */\n\nimport type { PanelApi } from '../api.ts'\nimport type { PanelStores } from '../store.ts'\nimport { parentRel } from '../fileType.ts'\n\n/** Longest candidate text (arbitrary safety cap against huge code spans). */\nconst MAX_REF_LENGTH = 512\n\n/** Normalize both separators to '/'. */\nfunction normalizeSlashes(value: string): string {\n return value.replace(/\\\\/g, '/')\n}\n\n/**\n * Interpret a code span's text as a workspace path. Returns the workspace\n * RELATIVE path ('' = the root itself), or null when the text is not a\n * recognizable in-workspace path. Never resolves above the root: `..`\n * segments, absolute outside paths, URLs and whitespace/multi-line text all\n * fall back to null so the transcript keeps its normal behavior.\n */\nexport function pathFromText(text: string, root: string): string | null {\n const raw = text.trim()\n if (raw === '' || raw.length > MAX_REF_LENGTH) return null\n if (/[\\r\\n]/.test(raw)) return null\n if (raw.includes('://')) return null\n const normalized = normalizeSlashes(raw)\n const rootNorm = normalizeSlashes(root).replace(/\\/+$/, '')\n if (rootNorm === '') return null\n\n // Absolute path inside the workspace. Posix paths start with '/'\n // (case-sensitive prefix match); Windows drive paths carry a drive\n // letter (case-insensitive prefix match with a separator boundary).\n if (normalized.startsWith('/')) {\n if (normalized === rootNorm) return ''\n if (!normalized.startsWith(rootNorm + '/')) return null\n const rel = normalized.slice(rootNorm.length).replace(/^\\/+/, '')\n return validRelative(rel) ? rel : null\n }\n if (/^[a-zA-Z]:/.test(normalized)) {\n const lower = normalized.toLowerCase()\n const lowerRoot = rootNorm.toLowerCase()\n if (lower === lowerRoot) return ''\n if (!lower.startsWith(lowerRoot + '/')) return null\n const rel = normalized.slice(rootNorm.length).replace(/^\\/+/, '')\n return validRelative(rel) ? rel : null\n }\n\n // Workspace-relative path ('.' prefix stripped).\n const rel = normalized.startsWith('./') ? normalized.slice(2) : normalized\n return validRelative(rel) ? rel : null\n}\n\n/** Validate a relative path: no escapes, no whitespace, looks path-like. */\nfunction validRelative(rel: string): boolean {\n if (rel === '' || rel.length > MAX_REF_LENGTH) return false\n if (/\\s/.test(rel)) return false\n const segments = rel.split('/')\n if (segments.length < 2) {\n // A bare name is accepted only when it looks like a file (dotted), so\n // ordinary words in code spans never trigger a locate.\n return /^[^/]*\\.[^/]+$/.test(rel)\n }\n for (const segment of segments) {\n if (segment === '' || segment === '.' || segment === '..') return false\n }\n return true\n}\n\n/** The `code` element a click targets, when it is a candidate file ref. */\nexport function fileRefElement(target: EventTarget | null): HTMLElement | null {\n if (!(target instanceof Element)) return null\n const code = target.closest('code')\n if (code === null) return null\n // Links keep their own navigation; the panels' own code blocks (preview\n // editors, tree rows) never trigger the transcript locate.\n if (code.closest('a') !== null) return null\n if (code.closest('.filemgr-root') !== null) return null\n if (code.closest('[data-filemgr-preview-col], [data-filemgr-explorer-col]') !== null) return null\n return code\n}\n\n/**\n * Locate a workspace-relative path from the transcript: Files tab + expand\n * ancestors + select; directories stay reveal-only, files also open in the\n * Preview panel (dedup focuses the existing tab). The parent listing is\n * consulted to classify the node; unknown paths keep the reveal and never\n * issue a preview request.\n */\nexport async function locateFileRef(stores: PanelStores, api: PanelApi, rel: string): Promise<void> {\n const explorer = stores.explorer\n explorer.setActiveTab('files')\n if (rel !== '') explorer.reveal(rel)\n\n const root = stores.layout.getSnapshot().root\n if (root === '' || rel === '') return\n\n const name = rel.split('/').pop() ?? ''\n const parent = parentRel(rel)\n let entry = explorer.getSnapshot().dirs[parent]?.find((item) => item.name === name)\n if (entry === undefined) {\n const result = await api.list(root, parent)\n if (result.ok) entry = result.value.entries.find((item) => item.name === name)\n }\n // Known directories: reveal-only (their children list is the tree's job).\n // Known files: open in the preview panel. Unknown: no preview request.\n if (entry !== undefined && !entry.isDir) {\n stores.preview.openFile(root, rel)\n }\n}\n\n/** Document-level click handler: locate recognized chat file references. */\nexport function handleFileRefClick(stores: PanelStores, api: PanelApi, event: MouseEvent): void {\n if (event.defaultPrevented || event.button !== 0) return\n const code = fileRefElement(event.target)\n if (code === null) return\n const root = stores.layout.getSnapshot().root\n if (root === '') return\n const rel = pathFromText(code.textContent ?? '', root)\n if (rel === null) return\n // The explorer must be visible for the reveal to be seen: un-collapse the\n // column (persisted like the chevron toggle does).\n const layout = stores.layout.getSnapshot()\n if (layout.explorerCollapsed) {\n stores.layout.update((prev) => ({ ...prev, explorerCollapsed: false }))\n try {\n localStorage.setItem(`project-panel-collapse:${root}`, 'expanded')\n } catch {\n // best-effort\n }\n }\n void locateFileRef(stores, api, rel)\n}\n","/**\n * The `file` input-trigger source: registers the reference codec the shell's\n * submit pipeline needs to serialize a file chip (`slash: no serializer for\n * reference source \"file\"` disappears once this source is in the roster).\n *\n * The source is deliberately INERT as a menu participant: the file picker is\n * our own pi-desktop-style tree modal (see picker/FilePickerModal.tsx), not\n * the shell's flat trigger menu, so `candidates` returns nothing and `onPick`\n * never fires. Its only jobs are (1) to be findable by\n * `inputTriggers.serializeReference('file', ref)` and (2) to own the model\n * projection of a chip — the `@path:lines` plain-text token.\n *\n * Trigger '@' keeps the chip family visually consistent with the other '@'\n * sources; the menu group this source contributes is empty and is covered by\n * the picker modal the moment a bare `@` lands.\n * @module dsh-filemgr/client/file-source\n */\n\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { InputTriggerSource } from '@deepseek-ai/dsh-client-ui-input-trigger/client'\n\n/** The roster name the chip occurrences address (see reference.ts). */\nexport const FILE_SOURCE_NAME = 'file'\n\n/** Required services: the trigger roster plus the session scope carrier. */\nexport const inject = ['inputTriggers']\n\n/**\n * Register the inert `file` reference source (codec only). Safe to call\n * multiple times (each call returns a disposer; the roster rejects a\n * duplicate (trigger, name) seat, so guard with a module flag).\n */\nexport function registerFileReferenceSource(ctx: ClientContext): () => void {\n // ctx.get — not property access: the caller (index.ts apply) does not\n // declare 'inputTriggers' in its inject list, and property access would\n // throw \"cannot get property without inject\". get() needs no inject.\n const inputTriggers = (ctx.get as (name: string) => unknown)('inputTriggers') as\n | { registerSource(src: InputTriggerSource): () => void }\n | undefined\n if (inputTriggers === undefined) return () => {}\n const source: InputTriggerSource = {\n trigger: '@',\n name: FILE_SOURCE_NAME,\n candidates: async () => [],\n onPick: () => undefined,\n codec: {\n clipboardText: (ref) => ref,\n serialize: (ref, _signal) => Promise.resolve(ref),\n },\n }\n try {\n return inputTriggers.registerSource(source)\n } catch (error) {\n // Duplicate registration (HMR remount) is not a failure.\n console.warn('[dsh-filemgr] file reference source already registered:', error)\n return () => {}\n }\n}\n","/**\n * FileManager right-panel system — browser half: mounts the explorer and preview\n * columns into the web shell's frame grid (through the layout controller),\n * binds the four stores to the live client runtime (the active session's cwd\n * is the project root), subscribes to the host change stream (fs + git), and\n * follows the shell's dark marker (body[data-ds-dark-theme]) via CSS only.\n *\n * Failure policy: every DOM/runtime wiring failure is logged, never thrown —\n * the web shell fails the whole boot when a plugin apply throws.\n *\n * FileManager right-panel design (Apache-2.0, iOfficeAI/FileManager) — re-implemented\n * from measured behavior and architecture, not copied code.\n * @module dsh-filemgr/client\n */\n\nimport { createElement } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport type { ClientContext, SessionId, SettingsScope, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the official settings-scope service onto the client Context.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: pulls the ui-conversation SlotMap merge (the input dock entry).\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { PanelApi, subscribePanelEvents } from './api.ts'\nimport { FileManagerSettingsCard, FileManagerSettingsCardController, type FileManagerPanelSettings } from './FileManagerSettingsCard.tsx'\nimport { PanelLayoutController } from './layout.ts'\nimport { createPanelStores, layoutSetRoot } from './store.ts'\nimport { mountPanels } from './mount.tsx'\nimport { NS, dictionaries, setLanguage, type FileManagerPanelKey } from './locales.ts'\nimport { DragFileInlay, type DragFileInjected } from './drag/DragFileInlay.tsx'\nimport { insertPathIntoDraft } from './drag/file-drag.ts'\nimport { MermaidChatEnhancer } from './chat/mermaid-chat.tsx'\nimport { PlaceholderHint } from './chat/placeholder-hint.tsx'\nimport { FilePickerHost } from './picker/FilePickerModal.tsx'\nimport { handleFileRefClick } from './chat/file-ref.ts'\nimport { appendToDraft, appendFileReferenceChip } from './reference.ts'\nimport { registerFileReferenceSource } from './file-source.ts'\nimport type { FileReferenceSelection } from './preview/selection.ts'\nimport './styles/chip.module.css'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Panel surface copy. */\n 'filemgr': FileManagerPanelKey\n }\n\n interface SlotMap {\n /**\n * One family plugin card inside the Web UI Plugins group. Spelled here\n * with the same shape so this package can register without depending on\n * the sibling web-ui-settings package.\n */\n 'web-ui.plugin.item': { kind: 'list'; scope: 'root'; owner: SettingsPluginItemOwnerProps }\n }\n}\n\n/** Owner share of a plugin card (the section supplies nothing). */\nexport interface SettingsPluginItemOwnerProps {\n /** Marker field: card owner props are intentionally empty. */\n children?: never\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /**\n * Optional rc.6 compatibility binder provided by dsh-web-ui-settings;\n * absent when that group plugin is not installed, so callers fall back to\n * the official settings scope.\n */\n webUiSettings?: { bind<S>(spec: SettingsScopeSpec<S>): SettingsScope<S> }\n }\n}\n\n/** Required services: sessions for the project root, locale for the copy, the settings scope for the master switch, and conversation for the composer draft edits (picker insert / @ button). */\nexport const inject = ['sessions', 'locale', 'settingsScope', 'conversation']\n\n/** Shared, stateless fs client (the PanelApi only wraps fetch calls). */\nconst panelApi = new PanelApi()\n\n/** Apply the browser half. */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, dictionaries), 'dsh-filemgr: dictionaries')\n\n // The `file` reference source: registers the codec that serializes file\n // chips on submit (`@path:lines`), which the shell requires before any\n // `slash/input-insert-reference` chip can send. Inert as a menu\n // participant — the '@' tree modal is our own picker, not the shell menu.\n ctx.effect(() => registerFileReferenceSource(ctx), 'dsh-filemgr: file reference source')\n\n // The '@' picker is our own tree modal (pi-desktop style), NOT the shell's\n // flat trigger menu: a bare `@` in the composer opens FilePickerHost\n // directly. The one inputTriggers registration above is codec-only and\n // inert in the menu; the modal covers any residual menu the moment it\n // opens.\n\n // The composer drop target for explorer file drags: mounted in the\n // official `conversation.input.dock` band (declared by the shipped\n // ui-conversation rc.6 shell), session-routed through the conversation\n // input facade. A missing session scope or conversation service degrades\n // to no-op — the panels themselves never depend on the dock entry.\n ctx.inject(['slots', 'conversation', 'sessions'], (scope: ClientContext) => {\n const sessions = scope.sessions\n const conversation = scope.conversation\n scope.slots.inject('conversation.input.dock', () =>\n scope.slots.register({\n name: 'conversation.input.dock',\n id: 'filemgr-drag-file',\n order: 90,\n locale: NS,\n inject: (sessionId: SessionId | undefined): DragFileInjected => ({\n insertPath: (path: string): boolean => {\n if (sessionId === undefined) return false\n const actx = sessions.scope(sessionId)\n if (actx === undefined) return false\n const input = conversation.input\n if (input === undefined) return false\n const shell = input.for(actx)\n const draft = shell.state.getSnapshot().draft\n shell.setDraft(insertPathIntoDraft(draft, path))\n return true\n },\n }),\n }, DragFileInlay))\n })\n\n // Transcript mermaid enhancement rides the same dock as a zero-render\n // sentinel: the shell has no message-body slot, so the sentinel observes\n // the document for the chat renderer's `code.language-mermaid` blocks.\n ctx.inject(['slots'], (scope: ClientContext) => {\n scope.slots.inject('conversation.input.dock', () =>\n scope.slots.register({\n name: 'conversation.input.dock',\n id: 'filemgr-mermaid-chat',\n order: 91,\n }, MermaidChatEnhancer))\n })\n\n // Composer placeholder hint rides the same band: the shell's input bar\n // placeholder (\"给智能体发消息\") has no plugin override seam, so a sentinel\n // rewrites the DOM attribute to advertise the '@' file reference and the\n // '/' command trigger (see placeholder-hint.tsx).\n ctx.inject(['slots'], (scope: ClientContext) => {\n scope.slots.inject('conversation.input.dock', () =>\n scope.slots.register({\n name: 'conversation.input.dock',\n id: 'filemgr-placeholder-hint',\n order: 92,\n }, PlaceholderHint))\n })\n\n // The settings card: one master switch (issue #307) in the Web UI Plugins\n // group, bound to the 'filemgr' namespace through the family bridge\n // (or the official settings scope when the deployment exposes it).\n ctx.inject(['slots', 'settingsScope'], (settingsCtx: ClientContext) => {\n const binder = settingsCtx.get('webUiSettings') ?? settingsCtx.settingsScope\n const panelScope = binder.bind<FileManagerPanelSettings>({ namespace: NS })\n const settingsCard = new FileManagerSettingsCardController(panelScope)\n settingsCtx.slots.inject('web-ui.plugin.item', () => {\n const unregister = settingsCtx.slots.register({\n name: 'web-ui.plugin.item',\n id: 'filemgr',\n order: 110,\n locale: NS,\n inject: () => settingsCard.inject(),\n }, FileManagerSettingsCard)\n return () => {\n settingsCard.dispose()\n unregister()\n }\n })\n })\n\n ctx.effect(() => {\n // Master switch (issue #307): the settings card edits the 'filemgr'\n // namespace through the family settings bridge (or the official scope).\n // While off, the panels, the floating button and the change stream stay\n // unmounted; toggling the switch re-mounts them live (the pet's model).\n let panelScope: SettingsScope<FileManagerPanelSettings> | undefined\n try {\n const binder = ctx.get('webUiSettings') ?? ctx.settingsScope\n if (binder !== undefined) panelScope = binder.bind<FileManagerPanelSettings>({ namespace: NS })\n } catch (error) {\n // A missing settings seam must not break the panel boot: default on.\n panelScope = undefined\n }\n const enabled = (): boolean => panelScope?.getSnapshot().value?.enabled ?? true\n let disposeUi: (() => void) | undefined\n\n /**\n * Mount the whole panel UI (columns, handles, floating button, change\n * stream, persists) and return its teardown. A fresh lifecycle per\n * enable keeps toggling idempotent (the layout controller cannot be\n * reused after dispose).\n */\n const mountUi = (): (() => void) => {\n const stores = createPanelStores(panelApi)\n const layout = new PanelLayoutController(stores.layout)\n const disposers: Array<() => void> = []\n let disposeGitEvents: (() => void) | undefined\n let currentRoot = ''\n let lastPreviewOpen = false\n\n // The Explorer row '@' button: insert a file-reference chip for files\n // (path + 1..N) or plain `@<rel-path>/` text for folders. File lines\n // are fetched from the host so the chip can carry an accurate line\n // range; failures fall back to plain text.\n const onReference = (path: string, isDir: boolean): void => {\n const sessionId = ctx.sessions.list.getSnapshot().current as SessionId | undefined\n if (sessionId === undefined) {\n console.warn('[dsh-filemgr] @ 引用插入失败:没有活动会话')\n return\n }\n if (isDir) {\n appendToDraft(ctx, sessionId, `@${path}/ `)\n return\n }\n void panelApi.read(currentRoot, path, false).then((result) => {\n if (!result.ok) {\n appendToDraft(ctx, sessionId, `@${path} `)\n return\n }\n const text = result.value.content\n const trimmed = text.endsWith('\\n') ? text.slice(0, -1) : text\n const lines = trimmed === '' ? 1 : trimmed.split('\\n').length\n appendFileReferenceChip(ctx, sessionId, { path, startLine: 1, endLine: lines })\n })\n }\n\n // The preview \"添加到对话\" action: insert a file-reference chip\n // carrying the selected line range, appended at the draft end.\n const onAddFileReference = (selection: FileReferenceSelection): boolean => {\n const sessionId = ctx.sessions.list.getSnapshot().current as SessionId | undefined\n return appendFileReferenceChip(ctx, sessionId, selection)\n }\n\n // The project root follows the active session's cwd; switching sessions\n // re-binds every store (widths, collapse, tree, tabs persist per root).\n const bindRoot = (): void => {\n const snapshot = ctx.sessions.list.getSnapshot()\n const sessionId = snapshot.current as SessionId | undefined\n const cwd = sessionId === undefined ? undefined : snapshot.byId[sessionId]?.cwd\n const root = typeof cwd === 'string' && cwd !== '' ? cwd : ''\n if (root === currentRoot) return\n currentRoot = root\n\n // The change stream is git-only and lives exactly as long as the SCM\n // tab is visible (no fs watch — the explorer/preview refresh on user\n // actions, see the host route layer). Drop the old stream on root\n // switches; syncGitSubscription re-evaluates it below.\n disposeGitEvents?.()\n disposeGitEvents = undefined\n const previewOpen = stores.preview.getSnapshot().open\n lastPreviewOpen = previewOpen\n layoutSetRoot(stores.layout, root, previewOpen)\n stores.explorer.setRoot(root)\n stores.scm.setRoot(root)\n stores.preview.setRoot(root)\n\n syncGitSubscription()\n }\n\n /**\n * Keep the git change stream in lockstep with SCM-tab visibility:\n * opening the changes tab starts the subscription (and fetches status\n * once immediately — the host poll only ticks on its own cadence);\n * switching away closes it, so git polling happens only while the SCM\n * panel is actually on screen. Idempotent — explorer state changes\n * (expansion, selection) call it and it no-ops unless the tab flipped.\n */\n const syncGitSubscription = (): void => {\n const root = currentRoot\n const want = root !== '' && stores.explorer.getSnapshot().activeTab === 'changes'\n if (want && disposeGitEvents === undefined) {\n void stores.scm.refresh()\n disposeGitEvents = subscribePanelEvents(root, (event) => {\n if (event.kind === 'git') {\n // The host status is the only truth; land it directly.\n stores.scm.update((prev) => (prev.root !== root ? prev : { ...prev, status: event.status, loading: false }))\n // The index/worktree moved: every open diff tab is stale by now.\n void stores.preview.handleGitChange(root)\n }\n if (event.kind === 'gitUnavailable') {\n // The host could not run git at all: land the friendly\n // unavailable state once instead of a \"not a repository\" view.\n stores.scm.update((prev) => (prev.root !== root ? prev : { ...prev, status: null, loading: false, gitMissing: true }))\n }\n })\n } else if (!want && disposeGitEvents !== undefined) {\n disposeGitEvents()\n disposeGitEvents = undefined\n }\n }\n disposers.push(ctx.sessions.list.subscribe(bindRoot))\n disposers.push(stores.explorer.subscribe(syncGitSubscription))\n bindRoot()\n\n // Header tool-dock bridge (dsh-term's AnimatedDock): the \"file panel\"\n // icon toggles this plugin's explorer through a window event, so the two\n // bundles stay decoupled. We also mirror explorerCollapsed back so the\n // dock icon highlights in lockstep.\n const onToggleFile = (): void => layout.toggleExplorer()\n window.addEventListener('dsh-dock:toggle-filepanel', onToggleFile)\n const unsubFileState = stores.layout.subscribe(() => {\n window.dispatchEvent(new CustomEvent('dsh-dock:filepanel-state', {\n detail: !stores.layout.getSnapshot().explorerCollapsed,\n }))\n })\n window.dispatchEvent(new CustomEvent('dsh-dock:filepanel-state', {\n detail: !stores.layout.getSnapshot().explorerCollapsed,\n }))\n\n // Mirror the preview open state into the layout store (single source: the\n // preview store), and play the enter animation when the region opens.\n const mirrorPreviewOpen = (): void => {\n const open = stores.preview.getSnapshot().open\n if (open === lastPreviewOpen) return\n lastPreviewOpen = open\n stores.layout.update((prev) => ({ ...prev, previewOpen: open }))\n if (open) {\n const col = document.querySelector<HTMLElement>('[data-filemgr-preview-col]')\n col?.classList.add('filemgr-preview-enter')\n setTimeout(() => col?.classList.remove('filemgr-preview-enter'), 300)\n }\n }\n disposers.push(stores.preview.subscribe(mirrorPreviewOpen))\n\n // Language mirroring (the shell owns <html lang>; the dictionary follows).\n let langObserver: MutationObserver | undefined\n const syncLanguage = (): void => {\n setLanguage(document.documentElement.lang?.startsWith('zh') ? 'zh' : 'en')\n }\n langObserver = new MutationObserver(syncLanguage)\n langObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n syncLanguage()\n\n // Mount everything. DOM failures degrade the panels, never the GUI.\n try {\n layout.mount()\n mountPanels(stores, () => layout.toggleExplorer(), onReference, onAddFileReference)\n } catch (error) {\n console.error('[dsh-filemgr] mount failed:', error)\n }\n\n // The '@' tree-browser modal host: a dedicated root appended to body so\n // the modal portals above the shell chrome regardless of panel state.\n const pickerHostEl = document.createElement('div')\n document.body.appendChild(pickerHostEl)\n const pickerRoot = createRoot(pickerHostEl)\n pickerRoot.render(createElement(FilePickerHost, { ctx, api: panelApi }))\n\n // Chat file-reference clicks (issue #314): recognize workspace paths in\n // transcript code spans and locate them in the Explorer / Preview.\n const onFileRefClick = (event: MouseEvent): void => {\n try {\n handleFileRefClick(stores, panelApi, event)\n } catch (error) {\n // A broken locate must never break the transcript's own clicks.\n console.error('[dsh-filemgr] file ref locate failed:', error)\n }\n }\n document.addEventListener('click', onFileRefClick)\n\n // Debounced persists (explorer/scm/preview) may be pending when the page\n // hides; flush them so a close/background never drops the last 150ms.\n const flushOnHide = (): void => stores.flushNow()\n const onVisibilityChange = (): void => {\n if (document.visibilityState === 'hidden') flushOnHide()\n }\n window.addEventListener('pagehide', flushOnHide)\n document.addEventListener('visibilitychange', onVisibilityChange)\n\n return () => {\n flushOnHide()\n window.removeEventListener('pagehide', flushOnHide)\n window.removeEventListener('dsh-dock:toggle-filepanel', onToggleFile)\n unsubFileState()\n document.removeEventListener('visibilitychange', onVisibilityChange)\n document.removeEventListener('click', onFileRefClick)\n disposeGitEvents?.()\n langObserver?.disconnect()\n pickerRoot.unmount()\n pickerHostEl.remove()\n for (const dispose of disposers) dispose()\n layout.dispose()\n }\n }\n const syncUi = (): void => {\n if (enabled() && disposeUi === undefined) {\n disposeUi = mountUi()\n } else if (!enabled() && disposeUi !== undefined) {\n disposeUi()\n disposeUi = undefined\n }\n }\n syncUi()\n const unsubscribeSettings = panelScope?.subscribe(syncUi)\n return () => {\n unsubscribeSettings?.()\n if (disposeUi !== undefined) {\n disposeUi()\n disposeUi = undefined\n }\n }\n }, 'dsh-filemgr: wiring')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["css","scmCss","dirOf","explorerCss","previewCss","previewCss","previewCss","CodeBlock","previewCss","dragCss","previewCss","apply","pickerCss"],"sources":["../src/client/api.ts","../src/client/PluginSettingsCard.tsx","../src/client/settings-form.ts","../src/client/FileManagerSettingsCard.tsx","../src/client/drag.ts","../src/client/fileType.ts","../src/client/persist.ts","../src/client/store.ts","../src/client/maximize.ts","../src/client/layout.ts","../src/client/locales.ts","../src/client/hooks/useStore.ts","../src/client/components/icons.tsx","../src/client/components/FileIcon.tsx","../src/client/components/overlay.tsx","../src/client/components/a11y.ts","../src/client/components/ScmPanel.tsx","../src/client/drag/file-drag.ts","../src/client/components/ExplorerPanel.tsx","../src/client/preview/PreviewTabs.tsx","../src/client/preview/PreviewToolbar.tsx","../src/client/hooks/useResizableSplit.ts","../src/client/preview/markdown.ts","../src/client/preview/mermaid.ts","../src/client/preview/content.tsx","../src/client/preview/selection.ts","../src/client/preview/PreviewPanel.tsx","../src/client/mount.tsx","../src/client/drag/DragFileInlay.tsx","../src/client/chat/mermaid-chat.tsx","../src/client/chat/placeholder-hint.tsx","../src/client/picker/file-picker.ts","../src/client/reference.ts","../src/client/picker/FilePickerModal.tsx","../src/client/chat/file-ref.ts","../src/client/file-source.ts","../src/client/DockItem.tsx","../src/client/FilePanelDockItem.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Browser client for the host /filemgr/* routes: typed JSON envelope\n * calls plus the SSE change subscription. Same-origin relative fetch (the\n * page and the routes share the webserver).\n * @module dsh-filemgr/client/api\n */\n\nimport type {\n DirListing, FileRead, GitBatchResult, GitStatusView, PanelEnvelope, PanelError, SearchView,\n} from '../core/types.ts'\n\n/** Transport failure (fetch threw or the response was not JSON). */\nconst TRANSPORT_ERROR: PanelError = { code: 'internal', message: 'panel route unavailable' }\n\n/** POST one JSON payload and decode the envelope; never throws. */\nasync function post<T>(path: string, payload: Record<string, unknown>): Promise<PanelEnvelope<T>> {\n let response: Response\n try {\n response = await fetch(path, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch {\n return { ok: false, error: TRANSPORT_ERROR }\n }\n try {\n const envelope = await response.json() as unknown\n if (typeof envelope !== 'object' || envelope === null) return { ok: false, error: TRANSPORT_ERROR }\n const record = envelope as Record<string, unknown>\n if (record.ok === true) return { ok: true, value: record.value as T }\n return { ok: false, error: (record.error as PanelError | undefined) ?? TRANSPORT_ERROR }\n } catch {\n return { ok: false, error: TRANSPORT_ERROR }\n }\n}\n\n/** Typed panel operations over the wire. */\nexport class PanelApi {\n /** List one directory of the project root (rel path; '' = root). */\n list(root: string, path: string): Promise<PanelEnvelope<DirListing>> {\n return post('/filemgr/list', { root, path })\n }\n\n /** Read one file (text or image data URL). */\n read(root: string, path: string, asImage: boolean): Promise<PanelEnvelope<FileRead>> {\n return post('/filemgr/read', { root, path, asImage })\n }\n\n /** Write text content back with an optional mtime conflict base. */\n write(root: string, path: string, content: string, baseMtime?: number): Promise<PanelEnvelope<{ mtime: number }>> {\n return post('/filemgr/write', { root, path, content, baseMtime })\n }\n\n /** Filename search under the root. */\n search(root: string, query: string): Promise<PanelEnvelope<SearchView>> {\n return post('/filemgr/search', { root, query })\n }\n\n /** Delete a path (untracked discard). */\n delete(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/delete', { root, path })\n }\n\n /** Reveal a path in the OS file manager (selecting the entry). */\n reveal(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/reveal', { root, path })\n }\n\n /** Open a path with the OS default app. */\n openWithDefault(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/open-with-default', { root, path })\n }\n\n /** Rename a path (newName is a bare name, no separators). */\n rename(root: string, path: string, newName: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/rename', { root, path, newName })\n }\n\n /** Create a directory at a relative path (parent must exist). */\n mkdir(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/mkdir', { root, path })\n }\n\n /** Create an empty file at a relative path (refuses to overwrite). */\n newFile(root: string, path: string): Promise<PanelEnvelope<{ ok: true }>> {\n return post('/filemgr/new-file', { root, path })\n }\n\n /** The repo status view; null when the root is not a repository. */\n gitStatus(root: string): Promise<PanelEnvelope<GitStatusView | null>> {\n return post('/filemgr/git-status', { root })\n }\n\n /** The unified diff text of one path (staged = index vs HEAD). */\n gitDiff(root: string, path: string, staged: boolean): Promise<PanelEnvelope<{ content: string }>> {\n return post('/filemgr/git-diff', { root, path, staged })\n }\n\n /** Stage paths. */\n gitStage(root: string, paths: string[]): Promise<PanelEnvelope<GitBatchResult>> {\n return post('/filemgr/git-stage', { root, paths })\n }\n\n /** Unstage paths. */\n gitUnstage(root: string, paths: string[]): Promise<PanelEnvelope<GitBatchResult>> {\n return post('/filemgr/git-unstage', { root, paths })\n }\n\n /** Discard paths (worktree side; untracked paths are deleted). */\n gitDiscard(root: string, paths: string[]): Promise<PanelEnvelope<GitBatchResult>> {\n return post('/filemgr/git-discard', { root, paths })\n }\n}\n\n/** One SSE change event pushed by the host. */\nexport type PanelChangeEvent =\n | { kind: 'fs' }\n | { kind: 'git'; status: GitStatusView }\n | { kind: 'gitUnavailable' }\n\n/**\n * Subscribe to host-pushed changes for one project root (fs watch events and\n * git status polls). Reconnects are handled by the EventSource; the caller\n * re-subscribes when the root changes.\n * @param root - project root to watch.\n * @param onChange - fired on every pushed change.\n * @returns the disposer closing the stream.\n */\nexport function subscribePanelEvents(root: string, onChange: (event: PanelChangeEvent) => void): () => void {\n const source = new EventSource(`/filemgr/events?root=${encodeURIComponent(root)}`)\n source.addEventListener('change', (raw) => {\n try {\n const event = JSON.parse((raw as MessageEvent).data as string) as PanelChangeEvent\n onChange(event)\n } catch {\n // malformed push; ignore\n }\n })\n return () => { source.close() }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/PluginSettingsCard.tsx. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Family-shared chrome for plugin settings cards: a disclosure header naming\n * the plugin and what its settings govern, the controls inside, and the save\n * that writes them. Renders nothing while the namespace is unavailable — a\n * deployment that does not compose the owning plugin should show no trace of\n * it. Inlined into each consumer's client bundle; mirrors the official\n * ui-plugin-config PluginCard in a self-contained slice.\n */\n\nimport { useState, type ReactNode } from 'react'\nimport type { CardShell } from './settings-form.ts'\nimport css from './settings-card.module.css'\n\n/** Copy keys the card chrome itself reads; every consumer locale carries this shared vocabulary. */\nexport const CARD_COPY_KEYS = [\n 'settings.collapse',\n 'settings.expand',\n 'settings.notExposed',\n 'settings.unsaved',\n 'settings.readOnly',\n 'settings.saveFailed',\n 'settings.discard',\n 'settings.save',\n 'settings.saving',\n] as const\n\n/** Copy key the card chrome itself reads. */\nexport type CardCopyKey = (typeof CARD_COPY_KEYS)[number]\n\n/** Key domain for the plugin's own copy (inferred per consumer). */\nexport type SettingsCardKey<TKey extends string = string> = TKey | CardCopyKey\n\n/** Card chrome shared by every plugin settings card. */\nexport interface PluginSettingsCardProps<TKey extends string = string> {\n /** Locale reader for this card's copy. */\n t: (key: SettingsCardKey<TKey>, params?: Record<string, string | number>) => string\n /** Locale key of the plugin's name. */\n titleKey: TKey\n /** Locale key of the line describing what this plugin's settings govern. */\n descriptionKey: TKey\n /** The card's form state: availability, writability, and what a save would do. */\n state: CardShell\n /** Write every staged edit. */\n onSave: () => void\n /** Drop every staged edit. */\n onDiscard: () => void\n /**\n * Render the controls expanded on arrival (still collapsible). Defaults to\n * true: promoted first-level sections show their settings immediately.\n */\n defaultOpen?: boolean\n /**\n * Render without the collapse affordance: a static header and an always\n * visible body. Used by first-level settings sections whose nav entry\n * already provides the selection.\n */\n alwaysOpen?: boolean\n /** The plugin's controls. */\n children: ReactNode\n}\n\n/**\n * Render one plugin settings card.\n * @param props - the plugin's copy keys, its form state, and its controls.\n * @returns the card, or nothing while the namespace is still loading.\n */\nexport function PluginSettingsCard<TKey extends string = string>(props: PluginSettingsCardProps<TKey>) {\n const [open, setOpen] = useState(props.defaultOpen ?? true)\n const { state, alwaysOpen } = props\n if (!state.available) return null\n const title = props.t(props.titleKey)\n const description = props.t(props.descriptionKey)\n const blocked = !state.dirty || state.invalid || state.saving\n const expanded = alwaysOpen === true || open\n const cardClass = expanded ? `${css.cardOpen} ${css.card}` : css.card\n // With alwaysOpen the nav entry already provides the selection, so the\n // header is a static title row instead of a disclosure button.\n const header = alwaysOpen === true\n ? (\n <div className={css.headerStatic}>\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n </div>\n )\n : (\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.chevron} ${css.chevronOpen}` : css.chevron}\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n )\n // The namespace exists but the Host does not serve it to this client (the\n // official settings allowlist omits third-party namespaces): show a card\n // that explains the gap instead of vanishing, so a missing card never\n // reads as a missing plugin.\n if (!state.exposed) {\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n <p className={css.notExposed} role=\"status\">{props.t('settings.notExposed')}</p>\n </div>\n )\n : null}\n </li>\n )\n }\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n {!state.writable ? <p className={css.readOnly} role=\"status\">{props.t('settings.readOnly')}</p> : null}\n {props.children}\n <div className={css.footer}>\n {state.failed\n ? (\n <p className={css.failed} role=\"status\">\n {props.t('settings.saveFailed')}{state.failedReason ? ' - ' + state.failedReason : ''}\n </p>\n )\n : null}\n <button\n type=\"button\"\n className={css.discard}\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('settings.discard')}\n </button>\n <button\n type=\"button\"\n className={css.save}\n disabled={blocked}\n onClick={props.onSave}\n >\n {props.t(!state.saving ? 'settings.save' : 'settings.saving')}\n </button>\n </div>\n </div>\n )\n : null}\n </li>\n )\n}\n\n/** Props every field control needs regardless of its value type. */\nexport interface FieldProps {\n /** Stable id associating the label with its control. */\n id: string\n /** Visible label. */\n label: string\n /** One-line explanation rendered under the control. */\n hint: string\n /** Draft text this control renders. */\n text: string\n /** True when saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** True when the draft is not a value this field accepts. */\n invalid: boolean\n /** Copy for the overridden badge. */\n overriddenLabel: string\n /** Copy for the reset control. */\n resetLabel: string\n /** Copy shown in place of the hint while the draft is invalid. */\n invalidLabel: string\n /** Disables every control (read-only document, or an unavailable namespace). */\n disabled: boolean\n /** Stage draft text. */\n onEdit: (text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n onReset: () => void\n}\n\n/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */\nexport function ValueField(props: FieldProps & {\n /** Hints a numeric keypad without narrowing what the control accepts. */\n numeric?: boolean\n /** Placeholder shown while the draft is empty. */\n placeholder?: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? css.inputInvalid : css.input}\n type=\"text\"\n {...props.numeric === true ? { inputMode: 'numeric' as const } : {}}\n {...props.invalid ? { 'aria-invalid': true } : {}}\n value={props.text}\n placeholder={props.placeholder ?? ''}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n\n/** A staged boolean field: 继承 / 开 / 关. */\nexport function BooleanField(props: FieldProps & {\n /** Copy for the inherit option. */\n inheritLabel: string\n /** Copy for the on option. */\n onLabel: string\n /** Copy for the off option. */\n offLabel: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <select\n id={props.id}\n className={css.select}\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n >\n <option value=\"\">{props.inheritLabel}</option>\n <option value=\"true\">{props.onLabel}</option>\n <option value=\"false\">{props.offLabel}</option>\n </select>\n <p className={css.hint}>{props.hint}</p>\n </div>\n )\n}\n\n/** A staged enumerated field rendered as a select. */\nexport function ChoiceField(props: FieldProps & {\n /** Copy for the inherit option (draft text is the empty string). */\n inheritLabel: string\n /** Choices rendered in order; `value` is the draft/stored text. */\n choices: ReadonlyArray<{ value: string; label: string }>\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <select\n id={props.id}\n className={css.select}\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n >\n <option value=\"\">{props.inheritLabel}</option>\n {props.choices.map(choice => (\n <option key={choice.value} value={choice.value}>{choice.label}</option>\n ))}\n </select>\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/settings-form.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Staged form model behind the plugin settings card. A card stages what the\n * user types and writes it only when they save — the settings write is a\n * durable, revision-fenced document mutation, so staging keeps what is on\n * screen exactly what a save would store. Family-shared slice inlined into\n * each plugin's client bundle; mirrors the official ui-plugin-config\n * card-store pattern.\n */\n\nimport type { SettingsScope, SettingsScopeSnapshot, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\n\n/** The write one field's staged text performs when the card is saved. */\nexport type FieldWrite =\n | { kind: 'set'; value: unknown }\n | { kind: 'clear' }\n\n/** How one field converts between its stored value and its draft text. */\nexport interface FieldSpec {\n /** Field name inside the namespace section. */\n field: string\n /**\n * Whether the Host treats this field as a secret and redacts its value from\n * the read-back (role('secret') in the section schema). Redacted secrets are\n * never compared against the draft on save; the field lands when the scope\n * reports the write succeeded (its secret-set marker under the bridge), so\n * a successful secret save is not misreported as failed.\n */\n secret?: boolean\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string\n /**\n * The write this draft text stages, or undefined when the text is not a\n * value this field accepts — which blocks the save rather than discarding it.\n */\n parse: (text: string) => FieldWrite | undefined\n}\n\n/** One field as the card renders it. */\nexport interface FieldState {\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts, which blocks saving. */\n invalid: boolean\n}\n\n/** Form state every plugin settings card shares. */\nexport interface CardShell {\n /** False while the namespace is still loading; the card renders nothing. */\n available: boolean\n /**\n * Whether the namespace is actually served to this client. False when the\n * Host deployment does not expose it (e.g. the official apiproxy settings\n * allowlist omits third-party namespaces): the card renders an explanation\n * instead of its form, so a missing namespace never looks like a missing\n * plugin.\n */\n exposed: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the form holds edits that a save would write. */\n dirty: boolean\n /** Whether any staged draft is invalid, which blocks the save. */\n invalid: boolean\n /** Whether a save is crossing the wire. */\n saving: boolean\n /** Whether the last save did not land as staged; cleared by the next edit or save. */\n failed: boolean\n /**\n * The rejection code/message the Host returned for the last failed save,\n * surfaced next to the generic failure text. Undefined while no save has\n * failed (or the failure carried no server reason).\n */\n failedReason?: string\n}\n\n/** The write actions the card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void\n /** Stage a clear, so saving lets the field re-inherit the composition layer. */\n resetField: (field: string) => void\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void\n /** Drop every staged edit. */\n discard: () => void\n}\n\n/** One field's staged edit. */\ninterface StagedEdit {\n /** Draft text the control renders. */\n text: string\n /** True when this edit clears the field whatever text it shows. */\n clear: boolean\n}\n\n/** One staged edit resolved into the write a save performs. */\ninterface PlannedWrite {\n /** Field this entry writes. */\n field: string\n /** The durable write this entry performs, described for a batched scope. */\n op: BatchedWrite\n /** Perform the write and report whether the Host holds the staged value afterwards. */\n run: (() => Promise<boolean>) | undefined\n}\n\n/** One durable write a batched settings scope performs. */\nexport interface BatchedWrite {\n /** Field this entry writes. */\n field: string\n /** set stores a value; unset drops the leaf. */\n op: 'set' | 'unset'\n /** Value for op set (absent for unset). */\n value?: unknown\n}\n\n/** Per-field outcome of one batched scope write. */\nexport interface BatchedFieldResult {\n /** Field this entry writes. */\n field: string\n /** Whether the Host accepted this field's write (per the read-back view). */\n landed: boolean\n}\n\n/**\n * Result of a batched scope write. The bridge scope posts every planned write\n * in one /mutate so the Host validate hook judges baseURL+model together; a\n * batched refusal fails the whole save rather than per-field.\n */\nexport interface BatchResult {\n /** Whether the whole mutate was accepted. */\n ok: boolean\n /** Per-field success, in the request order (always present when ok). */\n fields: BatchedFieldResult[]\n /** Host rejection code (mutate refused). */\n code?: string\n /** Host rejection message (mutate refused). */\n message?: string\n}\n\n/** The optional batch surface the bridge scope adds over the SettingsScope contract. */\ninterface BatchedSettingsScope {\n /** Write every operation in one scope mutation, reporting per-field success. */\n mutate: (writes: BatchedWrite[]) => Promise<BatchResult>\n}\n\n/** Constraints a numeric field's accepted drafts must satisfy, mirroring the host schema. */\nexport interface NumberConstraints {\n /** The accepted value must be a whole number. */\n integer?: boolean\n /** The accepted value must be at least this. */\n min?: number\n}\n\n/** A whole- or decimal-number field. An empty draft clears the field; any other draft that is not a finite number within the constraints blocks the save. */\nexport function numberField(field: string, constraints: NumberConstraints = {}): FieldSpec {\n const { integer = false, min } = constraints\n return {\n field,\n format: value => typeof value === 'number' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n if (!Number.isFinite(parsed)) return undefined\n if (integer && !Number.isInteger(parsed)) return undefined\n if (min !== undefined && parsed < min) return undefined\n return { kind: 'set', value: parsed }\n },\n }\n}\n\n/** A free-text field. An empty draft clears the field. */\nexport function textField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' ? value : '',\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/**\n * A free-text field the Host treats as a secret and redacts from the read-back\n * (role('secret') in the section schema). The card still edits it like text,\n * but a save never compares the redacted value back and relies on the scope\n * reporting the write landed.\n */\nexport function secretField(field: string): FieldSpec {\n return { ...textField(field), secret: true }\n}\n\n/** A boolean field, edited through true/false draft text. */\nexport function booleanField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'boolean' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return undefined\n },\n }\n}\n\n/** An enumerated string field; only the listed choices are accepted. An empty draft clears the field. */\nexport function choiceField(field: string, choices: readonly string[]): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' && choices.includes(value) ? value : '',\n parse: (text) => {\n if (text === '') return { kind: 'clear' }\n return choices.includes(text) ? { kind: 'set', value: text } : undefined\n },\n }\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n *\n * The Host is the only authority on whether a value was accepted — its\n * validators own the constraints no schema can express — so the outcome is\n * read back from the section rather than predicted here. A save that did not\n * land keeps its drafts, so the user can correct them instead of retyping.\n */\nexport class CardForm<T> {\n private readonly specs: Map<string, FieldSpec>\n private readonly staged = new Map<string, StagedEdit>()\n private readonly listeners = new Set<() => void>()\n /** The scope subscription installed in the constructor; released by dispose(). */\n private readonly disposeScope: () => void\n private disposed = false\n private saving = false\n private failed = false\n private failedReason: string | undefined\n\n /** @param scope - the bound settings scope for this card's namespace. */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: FieldSpec[],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.disposeScope = scope.subscribe(() => { this.publish() })\n }\n\n /**\n * Release the scope subscription and every bound store listener. The card\n * must call this on teardown; later calls are no-ops.\n */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.disposeScope()\n this.listeners.clear()\n }\n\n /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */\n bind<S>(project: () => S): SnapshotStore<S> {\n const store = createSnapshotStore(project())\n this.listeners.add(() => { store.set(project()) })\n return store\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status !== 'loading',\n exposed: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some(item => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n ...this.failedReason === undefined ? {} : { failedReason: this.failedReason },\n }\n }\n\n /** Read one field's state from the effective section and its staged draft. */\n field(field: string): FieldState {\n const spec = this.specOf(field)\n const staged = this.staged.get(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n }\n }\n\n /** The actions the card's slot registration injects. */\n actions(): CardActions {\n return {\n edit: (field, text) => { this.stage(field, { text, clear: false }) },\n resetField: (field) => {\n this.stage(field, { text: this.specOf(field).format(this.baseValue(field)), clear: true })\n },\n save: () => { void this.save() },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.failed = false\n this.failedReason = undefined\n this.publish()\n },\n }\n }\n\n /**\n * Write every staged edit, then re-seed from what the Host accepted.\n *\n * When the scope carries the optional batch surface (the dsh-web-ui\n * bridge scope), every planned write rides one mutation so cross-field\n * validate hooks (baseURL+model) judge the batch as a unit instead of\n * deadlocking on per-field writes. Otherwise the per-field loop runs.\n * A field lands only when the Host reports it held the staged value; a\n * landed field's draft is dropped, a failed one stays staged for the user.\n * @returns settlement after every write and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n const valid = plan.filter(item => item.run !== undefined)\n if (plan.length === 0 || this.saving || valid.length !== plan.length) return\n const plannedWrites = valid.map(item => item.op)\n // Snapshot the fields this save writes, so edits staged while it is in\n // flight survive: only the staged keys this save actually wrote are cleared.\n const fields = new Set(plan.map(item => item.field))\n this.saving = true\n this.failed = false\n this.failedReason = undefined\n this.publish()\n const landed = new Set<string>()\n const batch = this.batchedScope()\n if (batch !== undefined) {\n const result = await batch.mutate(plannedWrites)\n if (result.ok) {\n for (const field of result.fields) {\n if (field.landed) landed.add(field.field)\n }\n } else {\n this.failedReason = result.message\n }\n } else {\n for (const item of valid) {\n if (await item.run!()) landed.add(item.field)\n }\n }\n for (const field of fields) {\n if (landed.has(field)) this.staged.delete(field)\n }\n this.saving = false\n this.failed = landed.size !== fields.size\n this.publish()\n }\n\n /** The scope's batch surface when it supports one; undefined conservatively otherwise. */\n private batchedScope(): BatchedSettingsScope | undefined {\n const candidate = this.scope as unknown as BatchedSettingsScope | undefined\n return typeof candidate?.mutate === 'function' ? candidate : undefined\n }\n\n /**\n * Every staged edit a save would write. An entry whose draft is not a value\n * its field accepts carries no write: the form is still dirty, and the save\n * refuses rather than dropping the edit. A staged edit that matches the\n * effective section is not a write at all.\n * @returns the planned writes, in the order the fields were staged.\n */\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const spec = this.specOf(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, op: { field, op: 'unset' }, run: undefined })\n else if (write.kind === 'clear') plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n else plan.push({ field, op: { field, op: 'set', value: write.value }, run: () => this.store(field, write.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value)\n // A redacted secret never appears in the user layer read-back; judging it\n // by value would misreport a successful secret save as failed. The bridge\n // reports secret writes through its secret-set markers (batch path); on\n // the per-field path the scope resolved, so the write is landed.\n if (this.specOf(field).secret) return true\n return this.userLayer()?.[field] === value\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit)\n this.failed = false\n this.failedReason = undefined\n this.publish()\n }\n\n private specOf(field: string): FieldSpec {\n const spec = this.specs.get(field)\n // Every call site names a field this card declared; a missing one is a\n // wiring mistake that must not degrade into a silently inert control.\n if (spec === undefined) throw new Error(`settings card has no field ${field}`)\n return spec\n }\n\n private snapshotOf(): SettingsScopeSnapshot<T> {\n return this.scope.getSnapshot()\n }\n\n private sectionValue(field: string): unknown {\n return (this.snapshotOf().value as Record<string, unknown> | undefined)?.[field]\n }\n\n private baseValue(field: string): unknown {\n return (this.snapshotOf().base as Record<string, unknown> | undefined)?.[field]\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.snapshotOf().user as Record<string, unknown> | undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.hasOwn(user, field)\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * The filemgr settings card: the total on/off switch (issue #307).\n * Registers into the `web-ui.plugin.item` slot the Web UI Plugins group\n * renders, bound to the `filemgr` settings namespace through the family\n * settings bridge (or the official settings scope when the deployment exposes\n * the namespace directly). Turning the panel off unmounts the right-panel\n * columns, the floating expand button, the /filemgr/* routes and the\n * workspace fs watch + git polling behind them.\n * @module @lijian-ui/dsh-file-manager/client/FileManagerSettingsCard\n */\n\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { PluginSettingsCard, BooleanField } from './PluginSettingsCard.tsx'\nimport { CardForm, booleanField, type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts'\n\n/** The filemgr fields this card edits (the namespace's full schema). */\nexport interface FileManagerPanelSettings {\n /** Whether the right-panel system (columns, floating button, routes, watch/polling) is mounted at all; default on. */\n enabled?: boolean\n}\n\n/** What the filemgr card renders. */\nexport interface FileManagerSettingsCardState extends CardShell {\n enabled: CardFieldState\n}\n\n/** The registration-side face the card's slot entry injects. */\nexport interface FileManagerSettingsCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useFilemgrSettingsCard. */\n filemgrSettingsCard: SnapshotStore<FileManagerSettingsCardState>\n }\n}\n\n/** Bridges the `filemgr` scope onto the card's staged form. */\nexport class FileManagerSettingsCardController {\n private readonly form: CardForm<FileManagerPanelSettings>\n private readonly store: SnapshotStore<FileManagerSettingsCardState>\n\n /** @param scope - the bound settings scope for the `filemgr` namespace. */\n constructor(scope: SettingsScope<FileManagerPanelSettings>) {\n this.form = new CardForm(scope, [\n booleanField('enabled'),\n ])\n this.store = this.form.bind(() => this.projection())\n }\n\n private projection(): FileManagerSettingsCardState {\n return {\n ...this.form.shell(),\n enabled: this.form.field('enabled'),\n }\n }\n\n /**\n * Build the face the card's slot registration injects.\n * @returns the card's snapshot and its form actions.\n */\n inject(): FileManagerSettingsCardFace {\n return { hooks: { filemgrSettingsCard: this.store }, ...this.form.actions() }\n }\n\n /**\n * Release the card's scope subscription and bound stores; the slot\n * disposer calls this on teardown.\n */\n dispose(): void {\n this.form.dispose()\n }\n}\n\n/** Props the renderer binds for the filemgr card. */\nexport type FileManagerSettingsCardProps =\n PropsRuntime<'web-ui.plugin.item'>\n & PropsLocale<'filemgr'>\n & InjectFace<FileManagerSettingsCardFace>\n\n/**\n * Render the filemgr card.\n * @param props - locale copy, the card snapshot, and its form actions.\n * @returns the card.\n */\nexport function FileManagerSettingsCard(props: FileManagerSettingsCardProps) {\n const { t } = props\n const state = props.useFilemgrSettingsCard(snapshot => snapshot)\n const disabled = !state.writable\n const fieldProps = {\n overriddenLabel: t('settings.overridden'),\n resetLabel: t('settings.reset'),\n invalidLabel: t('settings.invalidNumber'),\n disabled,\n }\n return (\n <PluginSettingsCard\n t={t}\n titleKey=\"settings.title\"\n descriptionKey=\"settings.description\"\n state={state}\n onSave={props.save}\n onDiscard={props.discard}\n >\n <BooleanField\n id=\"settings-filemgr-enabled\"\n label={t('settings.enabled')}\n hint={t('settings.enabledHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.enabled}\n onEdit={(text) => { props.edit('enabled', text) }}\n onReset={() => { props.resetField('enabled') }}\n />\n </PluginSettingsCard>\n )\n}\n","/**\n * Framework-free drag machinery shared by the React hook (useResizableSplit)\n * and the DOM layout controller: one pointer-down handler that owns capture,\n * the rAF-flush loop, the e.buttons === 0 fallback, every end path, and the\n * drag styles. Pure DOM — no React, so both callers run the exact same\n * smoothness core (FileManager's useResizableSplit architecture, re-implemented).\n * @module dsh-filemgr/client/drag\n */\n\nexport interface DragStartOptions {\n /** Drag left = grow (handle on the left edge of its container). */\n reverse: boolean\n /** Width at drag start (read at pointer-down time). */\n getStartWidth: () => number\n /** Clamped width from the raw delta (px mode adds deltaX directly). */\n compute: (startWidth: number, deltaX: number) => number\n /** Per-frame flush (rAF-merged; called at most once per frame). */\n onFrame: (width: number) => void\n /** Final commit (also fired on every end path). */\n onEnd: (width: number) => void\n}\n\n/** Whether a pointer event is the primary (left) button or touch. */\nfunction isPrimaryPointer(event: PointerEvent): boolean {\n return event.pointerType === 'touch' || event.button === 0\n}\n\n/**\n * Handle one pointer-down: wire capture + window listeners, run the rAF\n * loop, and end on any of the five termination paths. Call from a\n * onPointerDown handler (React or plain DOM).\n * @param event - the raw pointerdown event.\n * @param el - the handle element (capture target + reverse marker source).\n * @param opts - drag behavior.\n * @returns a disposer (idempotent; also called internally on end).\n */\nexport function handlePointerDragStart(event: PointerEvent, el: HTMLElement, opts: DragStartOptions): () => void {\n if (!isPrimaryPointer(event)) return () => {}\n event.preventDefault()\n\n const startX = event.clientX\n const startWidth = opts.getStartWidth()\n const pointerId = event.pointerId\n const reverse = opts.reverse\n\n let rafId: number | null = null\n let pendingWidth: number | null = null\n let latestWidth = startWidth\n let isDragging = true\n let cleanup: (() => void) | null = null\n\n const flushPending = (): void => {\n if (pendingWidth === null) return\n latestWidth = pendingWidth\n opts.onFrame(pendingWidth)\n }\n\n const addWindowListener = <K extends keyof WindowEventMap>(\n key: K,\n handler: (e: WindowEventMap[K]) => void,\n ): (() => void) => {\n window.addEventListener(key, handler)\n return () => window.removeEventListener(key, handler)\n }\n\n const computeWidth = (clientX: number): number => {\n const deltaX = reverse ? startX - clientX : clientX - startX\n return opts.compute(startWidth, deltaX)\n }\n\n const finishDrag = (e?: PointerEvent | MouseEvent | FocusEvent): void => {\n if (!isDragging) return\n isDragging = false\n if (rafId !== null) {\n cancelAnimationFrame(rafId)\n rafId = null\n }\n flushPending()\n let finalWidth = latestWidth\n if (e !== undefined && 'clientX' in e && typeof e.clientX === 'number') {\n finalWidth = computeWidth(e.clientX)\n }\n opts.onEnd(finalWidth)\n cleanup?.()\n }\n\n const handlePointerMove = (e: PointerEvent): void => {\n if (!isDragging) return\n if (e.buttons === 0) {\n // Lost pointerup (capture steal / release outside): end now.\n finishDrag(e)\n return\n }\n pendingWidth = computeWidth(e.clientX)\n if (rafId === null) {\n rafId = requestAnimationFrame(() => {\n rafId = null\n flushPending()\n })\n }\n }\n const handlePointerUp = (e: PointerEvent): void => finishDrag(e)\n const handlePointerCancel = (e: PointerEvent): void => finishDrag(e)\n const handleMouseUp = (e: MouseEvent): void => finishDrag(e)\n const handleLostCapture = (): void => finishDrag()\n\n // Drag styles: no text selection, col-resize cursor, disable transitions.\n const previousUserSelect = document.body.style.userSelect\n const previousCursor = document.body.style.cursor\n document.body.style.userSelect = 'none'\n document.body.style.cursor = 'col-resize'\n const frame = el.closest('[data-dsh-frame]')\n frame?.setAttribute('data-filemgr-instant', '')\n\n const restore = (): void => {\n document.body.style.userSelect = previousUserSelect\n document.body.style.cursor = previousCursor\n frame?.removeAttribute('data-filemgr-instant')\n }\n\n if (el.setPointerCapture) {\n try {\n el.setPointerCapture(pointerId)\n el.addEventListener('lostpointercapture', handleLostCapture)\n } catch {\n // capture failed; the window listeners cover the drag\n }\n }\n\n const releaseCapture = (): void => {\n try {\n if (el.releasePointerCapture && el.hasPointerCapture?.(pointerId)) {\n el.releasePointerCapture(pointerId)\n }\n } catch {\n // already released\n }\n el.removeEventListener('lostpointercapture', handleLostCapture)\n }\n\n const listeners = [\n addWindowListener('pointermove', handlePointerMove),\n addWindowListener('pointerup', handlePointerUp),\n addWindowListener('pointercancel', handlePointerCancel),\n addWindowListener('mouseup', handleMouseUp),\n addWindowListener('blur', () => finishDrag()),\n ]\n cleanup = () => {\n restore()\n releaseCapture()\n for (const dispose of listeners) dispose()\n }\n return cleanup\n}\n","/**\n * Preview content-type detection from a file name — the router's single\n * source of truth for what a file becomes when opened (mirrors FileManager's\n * getFileTypeInfo table, re-derived for the panel's format set).\n * @module dsh-filemgr/client/fileType\n */\n\nimport type { PreviewContentType } from '../core/types.ts'\n\n/** Markdown extensions. */\nconst MARKDOWN_EXT = new Set(['md', 'markdown', 'mdx'])\n/** HTML extensions. */\nconst HTML_EXT = new Set(['html', 'htm', 'xhtml'])\n/** Diff extensions. */\nconst DIFF_EXT = new Set(['diff', 'patch'])\n/** CSV. */\nconst CSV_EXT = new Set(['csv'])\n/** PDF. */\nconst PDF_EXT = new Set(['pdf'])\n/** Office documents. */\nconst WORD_EXT = new Set(['doc', 'docx', 'odt', 'rtf'])\nconst EXCEL_EXT = new Set(['xls', 'xlsx', 'ods'])\nconst PPT_EXT = new Set(['ppt', 'pptx', 'odp'])\n/** Images. */\nconst IMAGE_EXT = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'ico', 'bmp', 'avif'])\n/** Extensions treated as editable code/text. */\nconst CODE_EXT = new Set([\n 'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'json', 'jsonc', 'css', 'scss', 'less',\n 'yml', 'yaml', 'toml', 'xml', 'sh', 'bash', 'zsh', 'fish', 'rs', 'py', 'go',\n 'java', 'c', 'h', 'cpp', 'hpp', 'cc', 'cs', 'sql', 'php', 'rb', 'swift', 'kt',\n 'vue', 'svelte', 'astro', 'txt', 'log', 'ini', 'env', 'conf', 'cfg', 'gitignore',\n 'dockerfile', 'makefile', 'graphql', 'proto', 'prisma', 'zig', 'lua', 'r', 'dart',\n 'ex', 'exs', 'erl', 'hs', 'clj', 'scala', 'groovy', 'vb', 'ps1', 'bat', 'cmd',\n 'pl', 'pm', 'tcl', 'asm', 's', 'f', 'f90', 'jl', 'nim', 'ml', 'elm', 'purs',\n 'solidity', 'sol', 'tf', 'hcl', 'dockerignore', 'editorconfig', 'prettierrc',\n 'eslintrc', 'babelrc', 'npmrc', 'nix', 'lock', 'map',\n])\n/** No-extension names that are plain text. */\nconst TEXT_NAMES = new Set([\n 'license', 'licence', 'readme', 'changelog', 'contributing', 'authors', 'notice',\n 'makefile', 'dockerfile', 'justfile', 'gemfile', 'rakefile', 'procfile',\n])\n/**\n * Leading-dot config dotfiles whose full (dotted) basename is plain text. The\n * de-dot rule below maps most single-dot files (`.gitignore` -> ext `gitignore`)\n * into CODE_EXT; these multi-suffix / uncommon ones have no useful extension\n * (`.env.local` -> `local`), so we match them by their whole dotted name.\n */\nconst DOTFILE_TEXT_NAMES = new Set([\n '.gitignore', '.gitattributes', '.gitmodules', '.env', '.env.local',\n '.env.production', '.env.development', '.env.test', '.npmrc', '.npmrc.template',\n '.prettierrc', '.prettierrc.json', '.prettierrc.yaml', '.babelrc', '.babelrc.json',\n '.eslintrc', '.eslintrc.json', '.eslintrc.js', '.editorconfig', '.dockerignore',\n '.eslintignore', '.prettierignore', '.gitignore.local', '.hgignore',\n])\n\n/** Detect the preview content type of a file by name (lowercased). */\nexport function detectContentType(name: string): PreviewContentType {\n const base = name.split('/').pop() ?? name\n const lower = base.toLowerCase()\n const dot = lower.lastIndexOf('.')\n // Leading-dot files: the first dot is the hidden-file marker, not a\n // separator — take the text after it (`.gitignore` -> `gitignore`).\n const ext = lower[0] === '.'\n ? (dot > 0 ? lower.slice(dot + 1) : lower.slice(1))\n : (dot > 0 ? lower.slice(dot + 1) : '')\n const stem = dot > 0 ? lower.slice(0, dot) : lower\n if (lower[0] === '.' && DOTFILE_TEXT_NAMES.has(lower)) return 'text'\n if (ext === '' && TEXT_NAMES.has(stem)) return 'text'\n if (ext === '') return 'unsupported'\n if (MARKDOWN_EXT.has(ext)) return 'markdown'\n if (HTML_EXT.has(ext)) return 'html'\n if (DIFF_EXT.has(ext)) return 'diff'\n if (CSV_EXT.has(ext)) return 'csv'\n if (PDF_EXT.has(ext)) return 'pdf'\n if (WORD_EXT.has(ext)) return 'word'\n if (EXCEL_EXT.has(ext)) return 'excel'\n if (PPT_EXT.has(ext)) return 'ppt'\n if (IMAGE_EXT.has(ext)) return 'image'\n if (CODE_EXT.has(ext)) return 'code'\n return 'unsupported'\n}\n\n/** Whether the type can be edited and saved back. */\nexport function isEditableType(type: PreviewContentType): boolean {\n return type === 'markdown' || type === 'html' || type === 'code' || type === 'csv' || type === 'text'\n}\n\n/** Whether the type reads its content as text (vs image data URL). */\nexport function isTextType(type: PreviewContentType): boolean {\n return type !== 'image' && type !== 'pdf' && type !== 'word' && type !== 'excel'\n && type !== 'ppt' && type !== 'unsupported' && type !== 'url'\n}\n\n/** A stable tab id from the file identity (root + path + type). */\nexport function tabIdOf(root: string, path: string, type: PreviewContentType): string {\n return `${root}\\u0000${path}\\u0000${type}`\n}\n\n/** The language hint for code tabs (extension without the dot). */\nexport function languageOf(name: string): string {\n const base = name.split('/').pop() ?? name\n const dot = base.lastIndexOf('.')\n return dot > 0 ? base.slice(dot + 1) : ''\n}\n\n/** The title for a tab: the basename. */\nexport function basenameOf(path: string): string {\n const parts = path.split('/')\n return parts[parts.length - 1] ?? path\n}\n\n/** The parent relative path of a path ('' for a root-level item). */\nexport function parentRel(path: string): string {\n const idx = path.lastIndexOf('/')\n return idx > 0 ? path.slice(0, idx) : ''\n}\n\n/**\n * The streaming URL a pdf tab renders: the host raw route serves the bytes\n * with mime application/pdf, so the preview iframe loads them directly — no\n * base64 round-trip and no read-size cap. The nonce defeats browser caching\n * when the tab is refreshed after the file changed on disk.\n *\n * Contributed by EricWang1358 (#239).\n */\nexport function pdfPreviewUrl(root: string, path: string, nonce: number): string {\n return `/filemgr/raw?root=${encodeURIComponent(root)}&path=${encodeURIComponent(path)}&v=${nonce}`\n}\n","/**\n * Persistence helpers for panel preferences: range-validated reads (invalid\n * stored values fall back to defaults — a broken or hand-edited value must\n * never produce a 0px or NaN panel), debounced writes, and the LRU registry\n * for preview scopes (at most 12 scopes; the oldest savedAt evicts).\n *\n * Keys follow the FileManager contract verbatim:\n * chat-workspace-width-px, chat-preview-width-px, preview-panel-split-ratio,\n * project-panel-collapse:<root>, explorer-ui:<root>, scm-ui:<root>,\n * preview-ui:<root>.\n * @module dsh-filemgr/client/persist\n */\n\n/** Read a stored number, validating it against [min, max]; fallback otherwise. */\nexport function readStoredNumber(key: string, min: number, max: number, fallback: number): number {\n try {\n const raw = localStorage.getItem(key)\n if (raw === null) return fallback\n const value = Number(raw)\n if (!Number.isFinite(value)) return fallback\n if (value < min || value > max) return fallback\n return value\n } catch {\n return fallback\n }\n}\n\n/** Write a number if it differs from the stored value (avoids churn). */\nexport function writeStoredNumber(key: string, value: number): void {\n try {\n const raw = String(Math.round(value))\n if (localStorage.getItem(key) === raw) return\n localStorage.setItem(key, raw)\n } catch {\n // persistence is best-effort; the panel still works\n }\n}\n\n/**\n * A single debounce pipeline used by the stores for its search and persist\n * timers: coalesces rapid schedules into one trailing run (the latest fn wins).\n * `flush` runs the pending fn immediately (pagehide/beforeunload), `dispose`\n * cancels a pending schedule. Behavior is equivalent to the stores' previous\n * hand-rolled setTimeout + clearTimeout pairs, just centralized.\n */\nexport interface Debounced {\n /** Queue a fn; repeated calls before the delay replaces the pending fn. */\n schedule: (fn: () => void) => void\n /** Run the pending fn now and clear the timer. */\n flush: () => void\n /** Cancel the pending fn and timer. */\n dispose: () => void\n}\n\n/** Create one debounced scheduler (default 150ms). */\nexport function createDebounced(delayMs = 150): Debounced {\n let timer: ReturnType<typeof setTimeout> | undefined\n let pending: (() => void) | null = null\n const flush = (): void => {\n if (timer !== undefined) clearTimeout(timer)\n timer = undefined\n const fn = pending\n pending = null\n if (fn !== null) fn()\n }\n return {\n schedule(fn: () => void) {\n pending = fn\n // Reset on every schedule so the run trails the LAST change (the same\n // trailing-edge semantics the stores' former clear+setTimeout had).\n if (timer !== undefined) clearTimeout(timer)\n timer = setTimeout(flush, delayMs)\n },\n flush,\n dispose() {\n if (timer !== undefined) clearTimeout(timer)\n timer = undefined\n pending = null\n },\n }\n}\n\n/** The preview-ui scope registry: keys, savedAt values, eviction. */\nexport const PREVIEW_SCOPE_PREFIX = 'preview-ui:'\n/** LRU cap on distinct preview scopes. */\nexport const PREVIEW_SCOPE_CAP = 12\n\n/**\n * Collect every stored key under a prefix. localStorage has no prefix index,\n * so the whole store is swept once, then filtered to the package's own keys\n * — enumeration is never interleaved with removal (removals would shift the\n * indices mid-loop and skip entries).\n */\nfunction listStoredKeysByPrefix(prefix: string): string[] {\n const keys: string[] = []\n try {\n for (let i = 0; i < localStorage.length; i += 1) {\n const key = localStorage.key(i)\n if (key !== null && key.startsWith(prefix)) keys.push(key)\n }\n } catch {\n return []\n }\n return keys\n}\n\n/**\n * Precisely delete every stored key under a prefix. Only this package's own\n * prefixed keys are removed — foreign-application keys are never touched,\n * replacing the former all-at-once `localStorage.clear()` sweep.\n */\nexport function removeStoredByPrefix(prefix: string): number {\n const keys = listStoredKeysByPrefix(prefix)\n let removed = 0\n for (const key of keys) {\n try {\n localStorage.removeItem(key)\n removed += 1\n } catch {\n // best-effort; a storage failure does not abort the rest\n }\n }\n return removed\n}\n\n/** All stored preview scopes with their savedAt timestamps, oldest first. */\nexport function listPreviewScopes(): Array<{ root: string; savedAt: number }> {\n const out: Array<{ root: string; savedAt: number }> = []\n for (const key of listStoredKeysByPrefix(PREVIEW_SCOPE_PREFIX)) {\n const root = key.slice(PREVIEW_SCOPE_PREFIX.length)\n let savedAt = 0\n try {\n const raw = localStorage.getItem(key)\n if (raw !== null) {\n const parsed = JSON.parse(raw) as { savedAt?: unknown }\n if (typeof parsed.savedAt === 'number') savedAt = parsed.savedAt\n }\n } catch {\n savedAt = 0\n }\n out.push({ root, savedAt })\n }\n out.sort((a, b) => a.savedAt - b.savedAt)\n return out\n}\n\n/** Evict the oldest scopes beyond the cap. */\nexport function evictPreviewScopes(keep: string): void {\n // Cheap pre-check first: enumerate keys only (no JSON.parse, no sort).\n // Writes far below the cap — the common case — return here instead of\n // parsing and sorting every stored preview scope on each persist.\n if (listStoredKeysByPrefix(PREVIEW_SCOPE_PREFIX).length <= PREVIEW_SCOPE_CAP) return\n const scopes = listPreviewScopes().filter((scope) => scope.root !== keep)\n let excess = scopes.length - (PREVIEW_SCOPE_CAP - 1)\n for (const scope of scopes) {\n if (excess <= 0) break\n try {\n localStorage.removeItem(`${PREVIEW_SCOPE_PREFIX}${scope.root}`)\n } catch {\n // best-effort\n }\n excess -= 1\n }\n}\n\n/** Serialize a JSON value with a size guard (quota failures degrade silently). */\nexport function writeJson(key: string, value: unknown): boolean {\n try {\n localStorage.setItem(key, JSON.stringify(value))\n return true\n } catch {\n try {\n localStorage.removeItem(key)\n } catch {\n // storage unavailable entirely\n }\n return false\n }\n}\n\n/** Parse a stored JSON value; fallback on any failure. */\nexport function readJson<T>(key: string, fallback: T): T {\n try {\n const raw = localStorage.getItem(key)\n if (raw === null) return fallback\n const parsed = JSON.parse(raw) as unknown\n // JSON.parse('null') yields null without throwing; descending callers\n // expect an object and would throw on null/primitive, killing their effect.\n if (parsed === null || typeof parsed !== 'object') return fallback\n return parsed as T\n } catch {\n return fallback\n }\n}\n","/**\n * Framework-free state core of the panel system: four small stores (layout,\n * explorer, scm, preview) built on a minimal subscribe/getSnapshot primitive\n * so every decision lives outside React (StrictMode-safe: update reducers are\n * pure; async work — fetches, persistence — runs in the action layer).\n *\n * FileManager's right-panel architecture (Apache-2.0, re-implemented): the width\n * clamps below are the exact ordered pair that keeps the chat area >= 360px\n * at all times (see the research report's section 4.2).\n * @module dsh-filemgr/client/store\n */\n\nimport type { FileRead, FsEntry, GitStatusView, PreviewContentType, SearchHit } from '../core/types.ts'\nimport type { PanelApi } from './api.ts'\nimport { detectContentType, isTextType, pdfPreviewUrl, tabIdOf } from './fileType.ts'\nimport {\n createDebounced, evictPreviewScopes, readJson, readStoredNumber, writeJson, writeStoredNumber,\n} from './persist.ts'\n\n// ─── state primitive ────────────────────────────────────────────────────────\n\n/** Internal channel for the stored-layout flush used by pagehide flushing. */\nconst FLUSH_PERSIST = Symbol('flushPersist')\n\n/** A minimal external store usable with useSyncExternalStore. */\nexport interface StateHandle<S> {\n getSnapshot: () => S\n subscribe: (listener: () => void) => () => void\n /** Pure update: fn receives the previous state and returns the next. */\n update: (fn: (prev: S) => S) => void\n}\n\n/** Create a state handle with an immutable snapshot (new object per update). */\nexport function createState<S>(initial: S): StateHandle<S> {\n let state = initial\n const listeners = new Set<() => void>()\n return {\n getSnapshot: () => state,\n subscribe(listener) {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n },\n update(fn) {\n const next = fn(state)\n if (next === state) return\n state = next\n for (const listener of listeners) listener()\n },\n }\n}\n\n// ─── layout: constants, clamps, store ───────────────────────────────────────\n\n/** Chat-area floor the two clamps guarantee (never below this). */\nexport const MIN_CHAT_PANEL_PX = 360\n/** Preview region width contract. */\nexport const MIN_PREVIEW_PANEL_PX = 340\nexport const DEFAULT_PREVIEW_REGION_PX = 480\nexport const MAX_PREVIEW_REGION_PX = 1200\n/** Explorer (workspace) width contract. */\nexport const MIN_WORKSPACE_PANEL_PX = 220\nexport const MAX_WORKSPACE_PANEL_PX = 500\nexport const DEFAULT_WORKSPACE_PANEL_PX = 260\n/** Preview region horizontal chrome (margins + borders) the clamps subtract. */\nexport const PREVIEW_REGION_CHROME_PX = 24\n\n/** Storage keys (FileManager contract, verbatim). */\nexport const KEY_EXPLORER_WIDTH = 'chat-workspace-width-px'\nexport const KEY_PREVIEW_WIDTH = 'chat-preview-width-px'\nexport const KEY_COLLAPSE = 'project-panel-collapse:'\nexport const KEY_EXPLORER_UI = 'explorer-ui:'\n/** Trailing window for coalescing explorer fs-event refetches (ms). */\nexport const FS_COALESCE_MS = 200\nexport const KEY_SCM_UI = 'scm-ui:'\n\n/**\n * Explorer clamp (runs first): reserve chat's floor plus the preview region\n * (min + chrome) when open, so the explorer never grows into the preview's\n * space; floor at the explorer minimum so a narrow container cannot squeeze\n * it to nothing.\n */\nexport function clampExplorerWidth(requested: number, available: number, previewOpen: boolean): number {\n const reserve = MIN_CHAT_PANEL_PX + (previewOpen ? MIN_PREVIEW_PANEL_PX + PREVIEW_REGION_CHROME_PX : 0)\n const maxByContainer = Math.max(MIN_WORKSPACE_PANEL_PX, available - reserve)\n return Math.min(requested, maxByContainer)\n}\n\n/**\n * Preview clamp (runs after the explorer clamp): reserve chat's floor plus\n * the already-clamped explorer width plus the region chrome. The ordered pair\n * guarantees chat = available - explorer - preview >= 360.\n */\nexport function clampPreviewWidth(requested: number, available: number, explorerWidth: number): number {\n const maxByContainer = Math.max(\n MIN_PREVIEW_PANEL_PX,\n available - MIN_CHAT_PANEL_PX - explorerWidth - PREVIEW_REGION_CHROME_PX,\n )\n return Math.min(requested, maxByContainer)\n}\n\n/** Which panel is maximized (null = normal layout). */\nexport type MaximizeTarget = 'explorer' | 'preview'\n\n/** Layout panel state (project-scoped). */\nexport interface LayoutState {\n /** The project root ('' when no project is bound). */\n root: string\n /** Requested explorer width (persisted; clamped on render). */\n explorerWidth: number\n /** Requested preview width (persisted; clamped on render). */\n previewWidth: number\n /** Explorer collapsed (width 0, kept mounted). */\n explorerCollapsed: boolean\n /** Preview region visible. */\n previewOpen: boolean\n /** Measured available width of the [content | panels] row. */\n availableWidth: number\n /** True while a panel drag is in flight (disables transitions). */\n dragging: boolean\n /**\n * Maximized panel (transient, never persisted): the panel takes over the\n * whole frame row (or the viewport as an overlay on narrow screens) while\n * the other panel, the chat area and the shell side columns hide. Restoring\n * re-applies the stored widths/collapse — nothing else changes.\n */\n maximized: MaximizeTarget | null\n}\n\n/** The layout store plus its pure width math. */\nexport interface LayoutStore extends StateHandle<LayoutState> {\n /** Effective explorer width after the ordered clamp. */\n explorerWidthPx: (state: LayoutState) => number\n /** Effective preview width after the ordered clamp. */\n previewWidthPx: (state: LayoutState) => number\n /** Persist a clamped shrink when the stored width no longer fits. */\n shrinkToFit: (state: LayoutState) => void\n}\n\n/** Storage key of the collapse preference for one root. */\nexport const collapseKey = (root: string): string => `${KEY_COLLAPSE}${root}`\n\n/** Create the layout store (reads persisted widths on init). */\nexport function createLayoutStore(): LayoutStore {\n const handle = createState<LayoutState>({\n root: '',\n explorerWidth: readStoredNumber(KEY_EXPLORER_WIDTH, MIN_WORKSPACE_PANEL_PX, MAX_WORKSPACE_PANEL_PX, DEFAULT_WORKSPACE_PANEL_PX),\n previewWidth: readStoredNumber(KEY_PREVIEW_WIDTH, MIN_PREVIEW_PANEL_PX, MAX_PREVIEW_REGION_PX, DEFAULT_PREVIEW_REGION_PX),\n explorerCollapsed: true,\n previewOpen: false,\n availableWidth: 0,\n dragging: false,\n maximized: null,\n })\n const store: LayoutStore = Object.assign(handle, {\n explorerWidthPx(state: LayoutState): number {\n return state.explorerCollapsed ? 0 : clampExplorerWidth(state.explorerWidth, state.availableWidth, state.previewOpen)\n },\n previewWidthPx(state: LayoutState): number {\n if (!state.previewOpen) return 0\n const explorer = state.explorerCollapsed ? 0 : clampExplorerWidth(state.explorerWidth, state.availableWidth, true)\n return clampPreviewWidth(state.previewWidth, state.availableWidth, explorer)\n },\n shrinkToFit(state: LayoutState): void {\n if (state.availableWidth <= 0) return\n const explorer = clampExplorerWidth(state.explorerWidth, state.availableWidth, state.previewOpen)\n if (state.explorerWidth > explorer && !state.explorerCollapsed) {\n writeStoredNumber(KEY_EXPLORER_WIDTH, explorer)\n handle.update((prev) => ({ ...prev, explorerWidth: explorer }))\n }\n const preview = clampPreviewWidth(state.previewWidth, state.availableWidth, explorer)\n if (state.previewOpen && state.previewWidth > preview) {\n writeStoredNumber(KEY_PREVIEW_WIDTH, preview)\n handle.update((prev) => ({ ...prev, previewWidth: preview }))\n }\n },\n })\n return store\n}\n\n/** Switch the layout to a project root (restores collapse + widths). */\nexport function layoutSetRoot(store: LayoutStore, root: string, previewOpen: boolean): void {\n store.update((prev) => {\n if (prev.root === root && prev.previewOpen === previewOpen) return prev\n let collapsed = prev.explorerCollapsed\n if (prev.root !== root) {\n try {\n collapsed = localStorage.getItem(collapseKey(root)) === 'collapsed'\n } catch {\n collapsed = false\n }\n }\n // Maximize is a transient layout state: it must never leak from one\n // project/session into another (issue #315 acceptance).\n return { ...prev, root, explorerCollapsed: collapsed, previewOpen, maximized: prev.root === root ? prev.maximized : null }\n })\n}\n\n// ─── explorer store ─────────────────────────────────────────────────────────\n\n/** Explorer panel state. */\nexport interface ExplorerState {\n root: string\n /** rel path -> listing cache ('' = root). */\n dirs: Record<string, FsEntry[]>\n /** Expanded dir rel paths (order = display order). */\n expanded: string[]\n /** Selected node rel path (null = none). */\n selected: string | null\n /** Dirs currently fetching. */\n loading: string[]\n /** Active tab: files | changes. */\n activeTab: 'files' | 'changes'\n /** Filename search state. */\n search: {\n query: string\n status: 'idle' | 'searching' | 'done' | 'error'\n hits: SearchHit[]\n truncated: boolean\n }\n /** Bumped on every fs change event (drives refetch + re-render). */\n version: number\n}\n\n/** The explorer store with its async actions. */\nexport interface ExplorerStore extends StateHandle<ExplorerState> {\n setRoot: (root: string) => void\n setActiveTab: (tab: 'files' | 'changes') => void\n toggleDir: (rel: string) => void\n select: (rel: string | null) => void\n reveal: (rel: string) => void\n setSearchQuery: (query: string) => void\n cancelSearch: () => void\n /** Refetch every expanded dir + active search after a host change event. */\n handleFsChange: () => void\n /** Reveal a path in the OS file manager (right-click menu). */\n revealInFileManager: (rel: string) => Promise<boolean>\n /** Open a path with the OS default app (files only, right-click menu). */\n openWithDefaultApp: (rel: string) => Promise<boolean>\n /** Rename a path (newName is a bare name). */\n renameEntry: (rel: string, newName: string) => Promise<boolean>\n /** Create a directory at rel (parent dirs untouched). */\n createDir: (rel: string) => Promise<boolean>\n /** Create an empty file at rel. */\n createFile: (rel: string) => Promise<boolean>\n /** Delete a path (recursive for directories). */\n deleteEntry: (rel: string) => Promise<boolean>\n}\n\n/** Read the persisted explorer UI state for a root (range-guarded). */\nexport function readExplorerUi(root: string): { expanded: string[]; selected: string | null } {\n const stored = readJson<{ expanded?: unknown; selected?: unknown }>(`${KEY_EXPLORER_UI}${root}`, {})\n const expanded = Array.isArray(stored.expanded)\n ? stored.expanded.filter((item): item is string => typeof item === 'string')\n : []\n const selected = typeof stored.selected === 'string' ? stored.selected : null\n return { expanded, selected }\n}\n\nconst EMPTY_SEARCH = { query: '', status: 'idle' as const, hits: [], truncated: false }\n\n/** Create the explorer store (per-root persistence, debounced writes). */\nexport function createExplorerStore(api: PanelApi): ExplorerStore {\n const handle = createState<ExplorerState>({\n root: '',\n dirs: {},\n expanded: [],\n selected: null,\n loading: [],\n activeTab: 'files',\n search: { ...EMPTY_SEARCH },\n version: 0,\n })\n\n const persistDebounced = createDebounced()\n const searchDebounced = createDebounced()\n let fsVersion = 0\n let fsInFlight = false\n let fsScheduled: ReturnType<typeof setTimeout> | undefined\n let persistRoot = ''\n let persistExpanded: string[] = []\n let persistSelected: string | null = null\n // The debounced write (schedulePersist queues this; flushNow runs it now).\n const persistWrite = (): void => {\n if (persistRoot !== '') writeJson(`${KEY_EXPLORER_UI}${persistRoot}`, { expanded: persistExpanded, selected: persistSelected })\n }\n const flushPersist = (): void => { persistDebounced.flush() }\n const schedulePersist = (root: string, expanded: string[], selected: string | null): void => {\n if (root === '') return\n persistRoot = root\n persistExpanded = expanded\n persistSelected = selected\n persistDebounced.schedule(persistWrite)\n }\n\n /** Load one dir's listing into the cache (no-op when already present). */\n const ensureDir = async (root: string, rel: string): Promise<void> => {\n const state = handle.getSnapshot()\n if (state.root !== root || state.dirs[rel] !== undefined || state.loading.includes(rel)) return\n handle.update((prev) => ({ ...prev, loading: [...prev.loading, rel] }))\n const result = await api.list(root, rel)\n handle.update((prev) => {\n if (prev.root !== root) return prev\n // A listing that landed after its dir collapsed must not re-populate\n // the cache (the expand/collapse race would resurrect stale children).\n if (rel !== '' && !prev.expanded.includes(rel)) {\n return { ...prev, loading: prev.loading.filter((item) => item !== rel) }\n }\n const dirs = { ...prev.dirs }\n if (result.ok) dirs[rel] = result.value.entries\n else delete dirs[rel]\n return { ...prev, dirs, loading: prev.loading.filter((item) => item !== rel) }\n })\n }\n\n /** Drop cached subtrees under a collapsed dir (its own key included). */\n const dropSubtree = (dirs: Record<string, FsEntry[]>, rel: string): Record<string, FsEntry[]> => {\n const prefix = rel === '' ? '' : `${rel}/`\n const next: Record<string, FsEntry[]> = {}\n for (const key of Object.keys(dirs)) {\n if (rel !== '' && (key === rel || key.startsWith(prefix))) continue\n next[key] = dirs[key]\n }\n return next\n }\n\n /** A dir's ancestor chain ('' .. parent). */\n const ancestors = (rel: string): string[] => {\n const out: string[] = []\n const parts = rel.split('/').filter(Boolean)\n let acc = ''\n for (const part of parts) {\n acc = acc === '' ? part : `${acc}/${part}`\n out.push(acc)\n }\n return out\n }\n\n /**\n * Refetch the root plus every expanded dir (seq-guarded against stale\n * results) and the active search after an fs change event.\n */\n const runFsRefresh = async (): Promise<void> => {\n const state = handle.getSnapshot()\n const root = state.root\n if (root === '') return\n const dirs = [...new Set(['', ...state.expanded])]\n const seq = ++fsVersion\n const results = await Promise.allSettled(dirs.map((rel) => api.list(root, rel)))\n handle.update((prev) => {\n if (prev.root !== root || seq !== fsVersion) return prev\n const nextDirs = { ...prev.dirs }\n results.forEach((result, index) => {\n const rel = dirs[index]\n if (result.status !== 'fulfilled' || !result.value.ok) return\n // A dir folded while the event burst was in flight must not be\n // re-populated (the collapse would revive from a stale snapshot).\n if (rel !== '' && !prev.expanded.includes(rel)) return\n nextDirs[rel] = result.value.value.entries\n })\n return { ...prev, dirs: nextDirs, version: prev.version + 1 }\n })\n if (state.search.query !== '') {\n void api.search(root, state.search.query).then((result) => {\n handle.update((prev) => {\n if (prev.root !== root || prev.search.query !== state.search.query) return prev\n return {\n ...prev,\n search: result.ok\n ? { query: state.search.query, status: 'done', hits: result.value.hits, truncated: result.value.truncated }\n : prev.search,\n }\n })\n })\n }\n }\n\n const store: ExplorerStore = Object.assign(handle, {\n setRoot(root: string) {\n handle.update((prev) => {\n if (prev.root === root) return prev\n const ui = readExplorerUi(root)\n return {\n ...prev,\n root,\n dirs: {},\n expanded: ui.expanded,\n selected: ui.selected,\n loading: [],\n search: { ...EMPTY_SEARCH },\n }\n })\n void ensureDir(root, '')\n },\n setActiveTab(tab: 'files' | 'changes') {\n handle.update((prev) => (prev.activeTab === tab ? prev : { ...prev, activeTab: tab }))\n },\n toggleDir(rel: string) {\n const state = handle.getSnapshot()\n const isExpanded = state.expanded.includes(rel)\n if (isExpanded) {\n handle.update((prev) => ({\n ...prev,\n expanded: prev.expanded.filter((item) => item !== rel),\n dirs: dropSubtree(prev.dirs, rel),\n }))\n } else {\n handle.update((prev) => ({ ...prev, expanded: [...prev.expanded, rel] }))\n void ensureDir(state.root, rel)\n }\n schedulePersist(state.root, isExpanded ? state.expanded.filter((item) => item !== rel) : [...state.expanded, rel], state.selected)\n },\n select(rel: string | null) {\n handle.update((prev) => (prev.selected === rel ? prev : { ...prev, selected: rel }))\n const state = handle.getSnapshot()\n schedulePersist(state.root, state.expanded, rel)\n },\n reveal(rel: string) {\n const state = handle.getSnapshot()\n const chain = ancestors(rel)\n const missing = chain.filter((item) => !state.expanded.includes(item))\n handle.update((prev) => {\n const expanded = [...prev.expanded]\n for (const item of missing) {\n if (!expanded.includes(item)) expanded.push(item)\n }\n return { ...prev, expanded, selected: rel, search: { ...EMPTY_SEARCH } }\n })\n for (const item of missing) void ensureDir(state.root, item)\n schedulePersist(state.root, [...state.expanded, ...missing], rel)\n },\n setSearchQuery(query: string) {\n const trimmed = query.trim()\n handle.update((prev) => {\n if (trimmed === '' && prev.search.query === '') return prev\n return {\n ...prev,\n search: trimmed === ''\n ? { ...EMPTY_SEARCH }\n : { ...prev.search, query: trimmed, status: 'searching' },\n }\n })\n searchDebounced.dispose()\n if (trimmed === '') return\n const root = handle.getSnapshot().root\n searchDebounced.schedule(() => {\n void api.search(root, trimmed).then((result) => {\n handle.update((prev) => {\n if (prev.root !== root || prev.search.query !== trimmed) return prev\n return {\n ...prev,\n search: result.ok\n ? { query: trimmed, status: 'done', hits: result.value.hits, truncated: result.value.truncated }\n : { ...prev.search, status: 'error', hits: [] },\n }\n })\n })\n })\n },\n cancelSearch() {\n searchDebounced.dispose()\n handle.update((prev) => (prev.search.query === '' ? prev : { ...prev, search: { ...EMPTY_SEARCH } }))\n },\n async revealInFileManager(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '') return false\n const result = await api.reveal(root, rel)\n return result.ok\n },\n async openWithDefaultApp(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '') return false\n const result = await api.openWithDefault(root, rel)\n return result.ok\n },\n async renameEntry(rel: string, newName: string) {\n const root = handle.getSnapshot().root\n if (root === '' || rel === '') return false\n const result = await api.rename(root, rel, newName)\n if (result.ok) {\n // Drop the old subtree, move the selection to the new path, and\n // forget the expansion of the renamed dir (its cache is gone).\n handle.update((prev) => {\n const parent = rel.includes('/') ? rel.slice(0, rel.lastIndexOf('/')) : ''\n const newRel = parent === '' ? newName : `${parent}/${newName}`\n const next: ExplorerState = {\n ...prev,\n dirs: dropSubtree(prev.dirs, rel),\n expanded: prev.expanded.filter((item) => item !== rel),\n }\n if (prev.selected === rel) next.selected = newRel\n return next\n })\n void this.handleFsChange()\n }\n return result.ok\n },\n async createDir(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '') return false\n const result = await api.mkdir(root, rel)\n if (result.ok) {\n // Expand the parent so the new directory shows up immediately.\n const parent = rel.includes('/') ? rel.slice(0, rel.lastIndexOf('/')) : ''\n const state = handle.getSnapshot()\n if (parent !== '' && !state.expanded.includes(parent)) this.toggleDir(parent)\n void this.handleFsChange()\n }\n return result.ok\n },\n async createFile(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '') return false\n const result = await api.newFile(root, rel)\n if (result.ok) {\n // Expand the parent so the new file shows up immediately.\n const parent = rel.includes('/') ? rel.slice(0, rel.lastIndexOf('/')) : ''\n const state = handle.getSnapshot()\n if (parent !== '' && !state.expanded.includes(parent)) this.toggleDir(parent)\n void this.handleFsChange()\n }\n return result.ok\n },\n async deleteEntry(rel: string) {\n const root = handle.getSnapshot().root\n if (root === '' || rel === '') return false\n const result = await api.delete(root, rel)\n if (result.ok) {\n handle.update((prev) => ({\n ...prev,\n selected: prev.selected === rel || prev.selected?.startsWith(rel + '/') ? null : prev.selected,\n dirs: dropSubtree(prev.dirs, rel),\n }))\n void this.handleFsChange()\n }\n return result.ok\n },\n async handleFsChange() {\n const root = handle.getSnapshot().root\n if (root === '') return\n if (fsInFlight) {\n // Collapse a burst of events into one trailing pass: schedule it\n // once, then let the timer re-enter here once it fires.\n if (fsScheduled === undefined) {\n fsScheduled = setTimeout(() => {\n fsScheduled = undefined\n void this.handleFsChange()\n }, FS_COALESCE_MS)\n }\n return\n }\n fsInFlight = true\n try {\n await runFsRefresh()\n } finally {\n fsInFlight = false\n }\n },\n })\n ;(store as unknown as Record<symbol, unknown>)[FLUSH_PERSIST] = flushPersist\n return store\n}\n\n// ─── scm store ──────────────────────────────────────────────────────────────\n\n/** SCM panel state. */\nexport interface ScmState {\n root: string\n /** null: not a git repository (or still loading). */\n status: GitStatusView | null\n /** True when the host reported git is not installed (SSE gitUnavailable). */\n gitMissing: boolean\n loading: boolean\n /** Paths with an action in flight. */\n busy: string[]\n /** Paths the last action reported failed. */\n failed: string[]\n /** list | tree. */\n viewMode: 'list' | 'tree'\n /** Section collapse map (repositories | changes). */\n sectionCollapsed: Record<string, boolean>\n /** Tree-view expanded dir keys. */\n treeExpanded: string[]\n /** Path of the last row opened in the preview panel (null = none). */\n selected: string | null\n}\n\n/** The scm store with its async actions. */\nexport interface ScmStore extends StateHandle<ScmState> {\n setRoot: (root: string) => void\n refresh: () => Promise<void>\n stage: (paths: string[]) => Promise<void>\n unstage: (paths: string[]) => Promise<void>\n discard: (paths: string[]) => Promise<void>\n discardAll: () => Promise<void>\n setViewMode: (mode: 'list' | 'tree') => void\n setSectionCollapsed: (id: string, collapsed: boolean) => void\n setTreeExpanded: (keys: string[]) => void\n setFailed: (paths: string[]) => void\n select: (path: string | null) => void\n}\n\n/** Read the persisted scm UI state for a root (guarded). */\nexport function readScmUi(root: string): { viewMode: 'list' | 'tree'; sectionCollapsed: Record<string, boolean>; treeExpanded: string[]; selected: string | null } {\n const stored = readJson<{ viewMode?: unknown; sectionCollapsed?: unknown; treeExpanded?: unknown; selected?: unknown }>(`${KEY_SCM_UI}${root}`, {})\n const viewMode = stored.viewMode === 'tree' ? 'tree' : 'list'\n const sectionCollapsed: Record<string, boolean> = typeof stored.sectionCollapsed === 'object' && stored.sectionCollapsed !== null\n ? Object.fromEntries(Object.entries(stored.sectionCollapsed as Record<string, unknown>).filter(([, v]) => typeof v === 'boolean')) as Record<string, boolean>\n : {}\n const treeExpanded = Array.isArray(stored.treeExpanded)\n ? stored.treeExpanded.filter((item): item is string => typeof item === 'string')\n : []\n const selected = typeof stored.selected === 'string' ? stored.selected : null\n return { viewMode, sectionCollapsed, treeExpanded, selected }\n}\n\n/** Create the scm store (host status is the only truth — no optimistic rows). */\nexport function createScmStore(api: PanelApi): ScmStore {\n const handle = createState<ScmState>({\n root: '',\n status: null,\n gitMissing: false,\n loading: false,\n busy: [],\n failed: [],\n viewMode: 'list',\n sectionCollapsed: {},\n treeExpanded: [],\n selected: null,\n })\n\n const persistDebounced = createDebounced()\n let persistState: ScmState | null = null\n let loadSeq = 0\n const persistWrite = (): void => {\n if (persistState !== null && persistState.root !== '') {\n writeJson(`${KEY_SCM_UI}${persistState.root}`, {\n viewMode: persistState.viewMode,\n sectionCollapsed: persistState.sectionCollapsed,\n treeExpanded: persistState.treeExpanded,\n selected: persistState.selected,\n })\n }\n }\n const flushPersist = (): void => { persistDebounced.flush() }\n const schedulePersist = (state: ScmState): void => {\n if (state.root === '') return\n persistState = state\n persistDebounced.schedule(persistWrite)\n }\n\n /** Fetch the status and land it (guarded against root switches + out-of-order). */\n const load = async (root: string, keepBusy: string[] = []): Promise<void> => {\n const seq = ++loadSeq\n handle.update((prev) => ({ ...prev, loading: true }))\n const result = await api.gitStatus(root)\n handle.update((prev) => {\n // Only the newest in-flight load may land; a stale response must not\n // overwrite fresher state (focus refresh vs SSE push race).\n if (prev.root !== root || seq !== loadSeq) return prev\n return {\n ...prev,\n status: result.ok ? result.value : prev.status,\n // A real repo view clears the missing-git banner; null keeps it.\n gitMissing: result.ok && result.value !== null ? false : prev.gitMissing,\n loading: false,\n busy: keepBusy,\n }\n })\n }\n\n const store: ScmStore = Object.assign(handle, {\n setRoot(root: string) {\n handle.update((prev) => {\n if (prev.root === root) return prev\n const ui = readScmUi(root)\n return {\n ...prev,\n root,\n status: null,\n gitMissing: false,\n loading: true,\n busy: [],\n failed: [],\n viewMode: ui.viewMode,\n sectionCollapsed: ui.sectionCollapsed,\n treeExpanded: ui.treeExpanded,\n selected: ui.selected,\n }\n })\n void load(root)\n },\n async refresh() {\n const root = handle.getSnapshot().root\n if (root !== '') await load(root)\n },\n async stage(paths: string[]) {\n const root = handle.getSnapshot().root\n if (root === '' || paths.length === 0) return\n handle.update((prev) => ({ ...prev, busy: [...prev.busy, ...paths] }))\n const result = await api.gitStage(root, paths)\n handle.update((prev) => ({\n ...prev,\n failed: result.ok && Array.isArray(result.value?.failed) ? result.value.failed : (result.ok ? [] : paths),\n busy: prev.busy.filter((item) => !paths.includes(item)),\n }))\n await load(root)\n },\n async unstage(paths: string[]) {\n const root = handle.getSnapshot().root\n if (root === '' || paths.length === 0) return\n handle.update((prev) => ({ ...prev, busy: [...prev.busy, ...paths] }))\n const result = await api.gitUnstage(root, paths)\n handle.update((prev) => ({\n ...prev,\n failed: result.ok && Array.isArray(result.value?.failed) ? result.value.failed : (result.ok ? [] : paths),\n busy: prev.busy.filter((item) => !paths.includes(item)),\n }))\n await load(root)\n },\n async discard(paths: string[]) {\n const root = handle.getSnapshot().root\n if (root === '' || paths.length === 0) return\n handle.update((prev) => ({ ...prev, busy: [...prev.busy, ...paths] }))\n const result = await api.gitDiscard(root, paths)\n handle.update((prev) => ({\n ...prev,\n failed: result.ok && Array.isArray(result.value?.failed) ? result.value.failed : (result.ok ? [] : paths),\n busy: prev.busy.filter((item) => !paths.includes(item)),\n }))\n await load(root)\n },\n async discardAll() {\n const state = handle.getSnapshot()\n const paths = [\n ...(state.status?.unstaged ?? []),\n ...(state.status?.untracked ?? []),\n ].map((row) => row.path)\n await this.discard(paths)\n },\n setViewMode(mode: 'list' | 'tree') {\n handle.update((prev) => (prev.viewMode === mode ? prev : { ...prev, viewMode: mode }))\n schedulePersist(handle.getSnapshot())\n },\n setSectionCollapsed(id: string, collapsed: boolean) {\n handle.update((prev) => ({ ...prev, sectionCollapsed: { ...prev.sectionCollapsed, [id]: collapsed } }))\n schedulePersist(handle.getSnapshot())\n },\n setTreeExpanded(keys: string[]) {\n handle.update((prev) => ({ ...prev, treeExpanded: keys }))\n schedulePersist(handle.getSnapshot())\n },\n setFailed(paths: string[]) {\n handle.update((prev) => ({ ...prev, failed: paths }))\n },\n select(path: string | null) {\n handle.update((prev) => (prev.selected === path ? prev : { ...prev, selected: path }))\n schedulePersist(handle.getSnapshot())\n },\n })\n ;(store as unknown as Record<symbol, unknown>)[FLUSH_PERSIST] = flushPersist\n return store\n}\n\n// ─── preview store ──────────────────────────────────────────────────────────\n\n/** One preview tab. */\nexport interface PreviewTabState {\n id: string\n title: string\n root: string\n path: string\n contentType: PreviewContentType\n /** Diff tabs (opened from the SCM panel): content is the path's git diff. */\n diff?: { staged: boolean }\n /** URL tabs: bumped by reloadTab to re-navigate the preview frame. */\n reloadNonce?: number\n /** null: content not loaded yet. */\n content: string | null\n /** Image dimensions for image tabs. */\n image?: { width: number; height: number }\n dirty: boolean\n /** mtime the loaded/saved content is based on (write-conflict base). */\n mtime?: number\n /** Disk is newer than the loaded content (refresh affordance). */\n updated: boolean\n loading: boolean\n truncated: boolean\n error: string | null\n savedAt: number\n}\n\n/** Preview panel state. */\nexport interface PreviewState {\n root: string\n open: boolean\n tabs: PreviewTabState[]\n activeTabId: string | null\n /** Bumped on every fs change event (drives staleness checks). */\n version: number\n}\n\n/** The preview store with its async actions. */\nexport interface PreviewStore extends StateHandle<PreviewState> {\n setRoot: (root: string) => void\n openFile: (root: string, path: string) => void\n openDiff: (root: string, path: string, staged: boolean) => void\n switchTab: (id: string) => void\n closeTabs: (ids: string[]) => void\n updateContent: (id: string, content: string) => void\n saveTab: (id: string) => Promise<void>\n reloadTab: (id: string) => Promise<void>\n setOpen: (open: boolean) => void\n handleFsChange: () => void\n handleGitChange: (root: string) => void\n}\n\n/** Persisted tab meta (content is re-fetched on restore). */\ninterface PersistedTab {\n id: string\n title: string\n root: string\n path: string\n contentType: PreviewContentType\n diff?: { staged: boolean }\n savedAt: number\n}\n\n/** Read persisted tabs for a root (guarded, content-less). */\nexport function readPreviewTabs(root: string): PersistedTab[] {\n const stored = readJson<{ savedAt?: unknown; tabs?: unknown }>(`preview-ui:${root}`, {})\n if (!Array.isArray(stored.tabs)) return []\n const out: PersistedTab[] = []\n for (const item of stored.tabs) {\n if (typeof item !== 'object' || item === null) continue\n const record = item as Record<string, unknown>\n if (typeof record.id !== 'string' || typeof record.path !== 'string') continue\n const rawDiff = record.diff\n const diff = typeof rawDiff === 'object' && rawDiff !== null\n && typeof (rawDiff as Record<string, unknown>).staged === 'boolean'\n ? { staged: (rawDiff as { staged: boolean }).staged }\n : undefined\n out.push({\n id: record.id,\n title: typeof record.title === 'string' ? record.title : record.path,\n root: typeof record.root === 'string' ? record.root : root,\n path: record.path,\n contentType: typeof record.contentType === 'string' ? record.contentType as PreviewContentType : 'text',\n diff,\n savedAt: typeof record.savedAt === 'number' ? record.savedAt : 0,\n })\n }\n return out\n}\n\n/** Create the preview store (per-root tab persistence with LRU scopes). */\nexport function createPreviewStore(api: PanelApi): PreviewStore {\n const handle = createState<PreviewState>({\n root: '',\n open: false,\n tabs: [],\n activeTabId: null,\n version: 0,\n })\n\n // handleFsChange single-flight + trailing coalesce (see its guard).\n let previewFsInFlight = false\n let previewFsScheduled: ReturnType<typeof setTimeout> | undefined\n\n const persistDebounced = createDebounced()\n const persistWrite = (): void => {\n const current = handle.getSnapshot()\n if (current.root === '') return\n const meta: PersistedTab[] = current.tabs.map((tab) => ({\n id: tab.id,\n title: tab.title,\n root: tab.root,\n path: tab.path,\n contentType: tab.contentType,\n diff: tab.diff,\n savedAt: tab.savedAt,\n }))\n writeJson(`preview-ui:${current.root}`, { savedAt: Date.now(), tabs: meta })\n evictPreviewScopes(current.root)\n }\n const flushPersist = (): void => { persistDebounced.flush() }\n const schedulePersist = (state: PreviewState): void => {\n if (state.root === '') return\n persistDebounced.schedule(persistWrite)\n }\n\n /** Load content for one tab (text or image data URL, or git diff). */\n const loadContent = async (root: string, id: string): Promise<void> => {\n const tab = handle.getSnapshot().tabs.find((item) => item.id === id)\n if (tab === undefined || tab.content !== null || tab.loading) return\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id ? { ...item, loading: true, error: null } : item)),\n }))\n // Pdf tabs never fetch through /read: the raw route streams the bytes\n // straight into the preview iframe, so the tab content is the route URL.\n if (tab.contentType === 'pdf') {\n handle.update((prev) => {\n if (prev.root !== root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id\n ? { ...item, loading: false, content: pdfPreviewUrl(root, item.path, Date.now()), updated: false }\n : item)),\n }\n })\n return\n }\n const asImage = tab.contentType === 'image'\n const result = tab.diff !== undefined\n ? await api.gitDiff(root, tab.path, tab.diff.staged)\n : await api.read(root, tab.path, asImage)\n handle.update((prev) => {\n if (prev.root !== root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => {\n if (item.id !== id) return item\n if (!result.ok) {\n return { ...item, loading: false, error: result.error.message }\n }\n // The user started typing while the fetch was in flight: their newer\n // content must not be overwritten by this (already stale) disk read.\n if (item.dirty) return { ...item, loading: false }\n // read and gitDiff share the content field; only read carries the\n // rest (image/mtime/truncated), so the union is read as its merge.\n const loaded = result.value as { content: string; image?: FileRead['image']; mtime?: number; truncated?: boolean }\n return {\n ...item,\n loading: false,\n content: loaded.content,\n image: loaded.image,\n mtime: loaded.mtime,\n truncated: loaded.truncated ?? false,\n updated: false,\n }\n }),\n }\n })\n }\n\n /** Touch a tab's savedAt (LRU order within the scope). */\n const touch = (id: string): void => {\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id ? { ...item, savedAt: Date.now() } : item)),\n }))\n }\n\n /**\n * Re-fetch every loaded diff tab of the root in place (fs/git change\n * events). In-flight or not-yet-loaded tabs are skipped — the next load or\n * event covers them; landing guards keep a newer edit from being clobbered.\n */\n const refreshDiffs = async (root: string): Promise<void> => {\n if (handle.getSnapshot().root !== root) return\n const diffs = handle.getSnapshot().tabs\n .filter((tab): tab is PreviewTabState & { diff: { staged: boolean } } => tab.diff !== undefined)\n await Promise.all(diffs.map(async (tab) => {\n if (tab.content === null || tab.loading) return\n const result = await api.gitDiff(root, tab.path, tab.diff.staged)\n handle.update((prev) => {\n if (prev.root !== root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => {\n if (item.id !== tab.id || !result.ok) return item\n if (item.dirty || item.loading) return item\n return { ...item, content: result.value.content, error: null }\n }),\n }\n })\n }))\n }\n\n const store: PreviewStore = Object.assign(handle, {\n setRoot(root: string) {\n handle.update((prev) => {\n if (prev.root === root) return prev\n const persisted = readPreviewTabs(root)\n const tabs: PreviewTabState[] = persisted.map((meta) => ({\n id: meta.id,\n title: meta.title,\n root: meta.root,\n path: meta.path,\n contentType: meta.contentType,\n diff: meta.diff,\n content: null,\n dirty: false,\n updated: false,\n loading: false,\n truncated: false,\n error: null,\n savedAt: meta.savedAt,\n }))\n const activeTabId = tabs.length > 0 ? tabs[tabs.length - 1].id : null\n return { ...prev, root, tabs, activeTabId, open: tabs.length > 0 }\n })\n const state = handle.getSnapshot()\n if (state.activeTabId !== null) void loadContent(root, state.activeTabId)\n },\n openFile(root: string, path: string) {\n const type = detectContentType(path)\n const id = tabIdOf(root, path, type)\n const existing = handle.getSnapshot().tabs.find((tab) => tab.id === id)\n if (existing !== undefined) {\n handle.update((prev) => ({\n ...prev,\n root,\n open: true,\n activeTabId: id,\n tabs: prev.tabs.map((tab) => (tab.id === id ? { ...tab, savedAt: Date.now() } : tab)),\n }))\n void loadContent(root, id)\n schedulePersist(handle.getSnapshot())\n return\n }\n handle.update((prev) => {\n if (prev.root !== root) return prev\n const tab: PreviewTabState = {\n id,\n title: path.split('/').pop() ?? path,\n root,\n path,\n contentType: type,\n content: null,\n dirty: false,\n updated: false,\n loading: false,\n truncated: false,\n error: null,\n savedAt: Date.now(),\n }\n return { ...prev, open: true, tabs: [...prev.tabs, tab], activeTabId: id }\n })\n void loadContent(root, id)\n schedulePersist(handle.getSnapshot())\n },\n openDiff(root: string, path: string, staged: boolean) {\n // A distinct id space (scm-diff: side + root + path) so the same file\n // can carry a diff tab AND a file tab, and staged/unstaged diffs of one\n // path are separate tabs — each reflects the side it was opened from.\n const id = `scm-diff:${staged ? 's' : 'u'}\\u0000${root}\\u0000${path}`\n const existing = handle.getSnapshot().tabs.find((tab) => tab.id === id)\n if (existing !== undefined) {\n handle.update((prev) => ({\n ...prev,\n root,\n open: true,\n activeTabId: id,\n tabs: prev.tabs.map((tab) => (tab.id === id ? { ...tab, savedAt: Date.now() } : tab)),\n }))\n void loadContent(root, id)\n schedulePersist(handle.getSnapshot())\n return\n }\n handle.update((prev) => {\n if (prev.root !== root) return prev\n const tab: PreviewTabState = {\n id,\n title: path.split('/').pop() ?? path,\n root,\n path,\n contentType: 'diff',\n diff: { staged },\n content: null,\n dirty: false,\n updated: false,\n loading: false,\n truncated: false,\n error: null,\n savedAt: Date.now(),\n }\n return { ...prev, open: true, tabs: [...prev.tabs, tab], activeTabId: id }\n })\n void loadContent(root, id)\n schedulePersist(handle.getSnapshot())\n },\n switchTab(id: string) {\n const state = handle.getSnapshot()\n if (state.activeTabId === id) return\n handle.update((prev) => ({ ...prev, activeTabId: id }))\n touch(id)\n const tab = handle.getSnapshot().tabs.find((item) => item.id === id)\n if (tab !== undefined && tab.content === null) void loadContent(state.root, id)\n schedulePersist(handle.getSnapshot())\n },\n closeTabs(ids: string[]) {\n const state = handle.getSnapshot()\n const remaining = state.tabs.filter((tab) => !ids.includes(tab.id))\n const active = remaining.some((tab) => tab.id === state.activeTabId)\n const activeTabId = active\n ? state.activeTabId\n : remaining.length > 0\n ? remaining[Math.min(state.tabs.findIndex((tab) => tab.id === state.activeTabId), remaining.length - 1)]?.id ?? remaining[remaining.length - 1].id\n : null\n handle.update((prev) => ({\n ...prev,\n tabs: remaining,\n activeTabId,\n open: remaining.length > 0 ? prev.open : false,\n }))\n schedulePersist(handle.getSnapshot())\n },\n updateContent(id: string, content: string) {\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((tab) => (tab.id === id ? { ...tab, content, dirty: true, updated: false } : tab)),\n }))\n },\n async saveTab(id: string) {\n const state = handle.getSnapshot()\n const tab = state.tabs.find((item) => item.id === id)\n if (tab === undefined || tab.content === null || !isTextType(tab.contentType) || tab.diff !== undefined) return\n const sentContent = tab.content\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id ? { ...item, loading: true, error: null } : item)),\n }))\n const result = await api.write(state.root, tab.path, tab.content, tab.mtime)\n handle.update((prev) => {\n if (prev.root !== state.root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => {\n if (item.id !== id) return item\n if (!result.ok) {\n return {\n ...item,\n loading: false,\n error: result.error.code === 'write-conflict'\n ? '文件已在磁盘上被修改,保存冲突:请刷新后重试'\n : result.error.message,\n }\n }\n if (item.content !== sentContent) {\n // The user kept typing while the save was in flight: the disk now\n // holds the sent snapshot, but the tab's newer edits are unsaved.\n // Refresh the write base so the next save is conflict-safe and\n // keep the dirty flag so the UI still shows an unsaved edit.\n return { ...item, loading: false, mtime: result.value.mtime, error: null }\n }\n return { ...item, loading: false, dirty: false, mtime: result.value.mtime, error: null }\n }),\n }\n })\n },\n async reloadTab(id: string) {\n const state = handle.getSnapshot()\n const tab = state.tabs.find((item) => item.id === id)\n if (tab === undefined) return\n if (tab.contentType === 'url') {\n // URL tabs own a live document inside the frame; reload bumps the\n // nonce so UrlViewer re-navigates the frame to its address.\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) =>\n item.id === id ? { ...item, reloadNonce: (item.reloadNonce ?? 0) + 1 } : item,\n ),\n }))\n return\n }\n if (tab.contentType === 'pdf') {\n // Streamed tab: re-point the iframe at the raw route with a fresh\n // nonce so the browser re-fetches the bytes (no /read round-trip).\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id\n ? { ...item, content: pdfPreviewUrl(state.root, item.path, Date.now()), updated: false, error: null }\n : item)),\n }))\n return\n }\n handle.update((prev) => ({\n ...prev,\n tabs: prev.tabs.map((item) => (item.id === id ? { ...item, loading: true } : item)),\n }))\n const result = tab.diff !== undefined\n ? await api.gitDiff(state.root, tab.path, tab.diff.staged)\n : await api.read(state.root, tab.path, tab.contentType === 'image')\n handle.update((prev) => {\n if (prev.root !== state.root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((item) => {\n if (item.id !== id) return item\n if (!result.ok) return { ...item, loading: false, error: result.error.message }\n const loaded = result.value as { content: string; image?: FileRead['image']; mtime?: number; truncated?: boolean }\n return {\n ...item,\n loading: false,\n content: loaded.content,\n image: loaded.image,\n mtime: loaded.mtime,\n truncated: loaded.truncated ?? false,\n updated: false,\n dirty: false,\n error: null,\n }\n }),\n }\n })\n },\n setOpen(open: boolean) {\n handle.update((prev) => (prev.open === open ? prev : { ...prev, open }))\n },\n async handleFsChange() {\n const state = handle.getSnapshot()\n if (state.root === '') return\n if (previewFsInFlight) {\n // Collapse a burst of fs events into one trailing pass: each refresh\n // respawns git per diff tab and re-reads the active file, so a write\n // storm must not queue one full round per event.\n if (previewFsScheduled === undefined) {\n previewFsScheduled = setTimeout(() => {\n previewFsScheduled = undefined\n void this.handleFsChange()\n }, FS_COALESCE_MS)\n }\n return\n }\n previewFsInFlight = true\n try {\n handle.update((prev) => ({ ...prev, version: prev.version + 1 }))\n // Diff tabs are derived views: any fs change may alter them, so refresh\n // them in place (never mark \"updated\" — the refresh is automatic).\n await refreshDiffs(state.root)\n // Staleness probe for the ACTIVE file tab only (cheap; the fs watcher\n // debounces bursts). A newer disk mtime flips the tab to \"updated\".\n const active = handle.getSnapshot().tabs.find((tab) => tab.id === handle.getSnapshot().activeTabId)\n if (active === undefined || active.content === null || active.dirty || active.diff !== undefined || !isTextType(active.contentType)) return\n const result = await api.read(state.root, active.path, false)\n handle.update((prev) => {\n if (prev.root !== state.root) return prev\n return {\n ...prev,\n tabs: prev.tabs.map((tab) => {\n if (tab.id !== active.id || tab.dirty) return tab\n if (!result.ok) return tab\n return { ...tab, updated: tab.mtime !== undefined && result.value.mtime > tab.mtime + 1 }\n }),\n }\n })\n } finally {\n previewFsInFlight = false\n }\n },\n async handleGitChange(root: string) {\n // A git push means the index/worktree moved (stage/unstage/discard or\n // external git): every open diff tab is stale by definition.\n await refreshDiffs(root)\n },\n })\n ;(store as unknown as Record<symbol, unknown>)[FLUSH_PERSIST] = flushPersist\n return store\n}\n\n/** Convenience bundle: the four stores wired to one api. */\nexport interface PanelStores {\n layout: LayoutStore\n explorer: ExplorerStore\n scm: ScmStore\n preview: PreviewStore\n}\n\n/** PanelStores plus a pagehide flush hook. */\nexport interface PanelStoresWithFlush extends PanelStores {\n /** Flush every pending debounced persist immediately (pagehide/beforeunload). */\n flushNow: () => void\n}\n\n/** Create the full store bundle. */\nexport function createPanelStores(api: PanelApi): PanelStoresWithFlush {\n const layout = createLayoutStore()\n const explorer = createExplorerStore(api)\n const scm = createScmStore(api)\n const preview = createPreviewStore(api)\n const flushNow = (): void => {\n for (const store of [explorer, scm, preview]) {\n const flush = (store as unknown as Record<symbol, unknown>)[FLUSH_PERSIST]\n if (typeof flush === 'function') (flush as () => void)()\n }\n }\n const stores: PanelStoresWithFlush = { layout, explorer, scm, preview, flushNow }\n return stores\n}\n","/**\n * Maximize-mode geometry (issue #315): when a panel is maximized the layout\n * controller rewrites the frame grid so the target column takes the whole\n * row (sidebar, details, chat and the other panel collapse to 0px tracks —\n * everything stays mounted, nothing unmounts). On narrow viewports the\n * maximized column instead leaves the grid and renders as a fixed\n * full-screen overlay (mobile-friendly full-screen mode), so the shell's\n * own narrow layout stays untouched behind it.\n * @module dsh-filemgr/client/maximize\n */\n\nimport type { MaximizeTarget } from './store.ts'\n\n/** Below this available row width the maximized panel renders as a fixed\n * full-screen overlay instead of a grid takeover. */\nexport const MAXIMIZE_OVERLAY_BREAKPOINT_PX = 640\n\n/**\n * The five grid tracks while one panel is maximized: shell sidebar, chat,\n * shell details and the other panel all collapse to 0px; the target column\n * takes the whole measured frame width. Tracks are the same string shape the\n * shell's own inline style uses (px + fr), so nothing else needs to change.\n */\nexport function maximizedGridTracks(target: MaximizeTarget, frameWidth: number): string {\n const wide = `${Math.max(0, Math.round(frameWidth))}px`\n return target === 'explorer'\n ? `0px 0px 0px 0px ${wide}`\n : `0px 0px 0px ${wide} 0px`\n}\n\n/** Whether the maximized panel should render as a fixed full-screen overlay. */\nexport function maximizedOverlay(availableWidth: number): boolean {\n return availableWidth > 0 && availableWidth < MAXIMIZE_OVERLAY_BREAKPOINT_PX\n}\n","/**\n * The DOM layout controller: extends the web shell's three-column frame\n * (`[data-dsh-frame]`, a grid) with two trailing grid tracks — the preview\n * region and the explorer column — by mirroring the shell's own inline\n * grid-template-columns string and re-appending the two panel tracks on every\n * shell update (MutationObserver, same frame before paint). Also owns the\n * absolute drag handles (12px explorer / 20px preview hit zones), the\n * floating expand button (docked at the top-right corner, just below the\n * shell header's divider — issues #374 / #292), the collapse-as-width-0\n * keep-mounted behavior, and the transient\n * maximize mode (issue #315): while a panel is maximized the target column\n * takes over the whole frame row (or renders as a fixed full-screen overlay\n * on narrow viewports), and Esc / the header button restore the layout.\n *\n * The shell's inline style is the source of truth for the sidebar and details\n * tracks; this controller never guesses their widths. Handles are out-of-flow\n * (absolute), so appending tracks never disturbs the shell's own children.\n *\n * FileManager Layout architecture (Apache-2.0, re-implemented): the explorer\n * column collapses to width 0 while staying mounted; the preview region keeps\n * a 1px left border only (no outer margins — gaps would expose the window\n * background, jarring in dark mode).\n * @module dsh-filemgr/client/layout\n */\n\nimport { handlePointerDragStart } from './drag.ts'\nimport {\n DEFAULT_PREVIEW_REGION_PX, DEFAULT_WORKSPACE_PANEL_PX,\n MAX_PREVIEW_REGION_PX, MAX_WORKSPACE_PANEL_PX,\n MIN_PREVIEW_PANEL_PX, MIN_WORKSPACE_PANEL_PX,\n KEY_EXPLORER_WIDTH, KEY_PREVIEW_WIDTH,\n clampExplorerWidth, clampPreviewWidth,\n type MaximizeTarget,\n} from './store.ts'\nimport { writeStoredNumber } from './persist.ts'\nimport { maximizedGridTracks, maximizedOverlay } from './maximize.ts'\n\nimport type { LayoutStore } from './store.ts'\n\n/** The frame grid element (portals target it). */\nlet frameElement: HTMLElement | null = null\n\n/** Read the current frame element (undefined while the shell is not mounted). */\nexport function getFrameElement(): HTMLElement | null {\n return frameElement\n}\n\n/**\n * Locate the frame grid element the two panel columns append into. The web-ui\n * aggregate's compat shim stamps `data-dsh-frame` onto the grid, but a\n * STANDALONE install of this package has no shim (the attribute never\n * appears), so the panel would wait forever and never mount (issue #56). Fall\n * back to the rc.6-native structure: the frame grid is the parent of the\n * sidebar column, exactly the element the shim would stamp.\n */\nfunction findFrame(): HTMLElement | null {\n const stamped = document.querySelector<HTMLElement>('[data-dsh-frame]')\n if (stamped !== null) return stamped\n return document.querySelector<HTMLElement>('[class*=\"sidebarCol\"]')?.parentElement ?? null\n}\n\n/**\n * Parse an inline grid-template-columns string into its tracks. Handles\n * \"minmax(0, 1fr)\" (spaces inside parens must not split). Empty on failure.\n */\nexport function parseGridTracks(input: string): string[] {\n const tracks: string[] = []\n let depth = 0\n let current = ''\n for (const char of input) {\n if (char === '(') depth += 1\n if (char === ')') depth = Math.max(0, depth - 1)\n if (char === ' ' && depth === 0) {\n if (current !== '') {\n tracks.push(current)\n current = ''\n }\n continue\n }\n current += char\n }\n if (current !== '') tracks.push(current)\n return tracks\n}\n\n/** Extract a px width from one track (0 for fr/minmax/non-px tracks). */\nexport function trackPx(track: string): number {\n const match = /^(-?[\\d.]+)px$/.exec(track.trim())\n return match === null ? 0 : Number(match[1])\n}\n\n/** One drag handle's geometry (hit zone + visual line) — pure CSS in the module. */\nexport const EXPLORER_HANDLE_WIDTH = 12\nexport const PREVIEW_HANDLE_WIDTH = 20\n\n/**\n * Drag target width: apply the hard px bounds (the same min/max the handle\n * always enforced), then the store's ordered container-aware clamp so the\n * grid never re-clamps a width the drag showed.\n */\nexport function dragTargetWidth(\n kind: 'explorer' | 'preview',\n startWidth: number,\n deltaX: number,\n snapshot: { availableWidth: number; previewOpen: boolean; explorerWidth: number },\n): number {\n const requested = startWidth + deltaX\n if (kind === 'explorer') {\n const bounded = Math.min(MAX_WORKSPACE_PANEL_PX, Math.max(MIN_WORKSPACE_PANEL_PX, requested))\n return clampExplorerWidth(bounded, snapshot.availableWidth, snapshot.previewOpen)\n }\n const bounded = Math.min(MAX_PREVIEW_REGION_PX, Math.max(MIN_PREVIEW_PANEL_PX, requested))\n return clampPreviewWidth(bounded, snapshot.availableWidth, snapshot.explorerWidth)\n}\n\n/** The layout controller: frame sync, handles, floating button, width math. */\nexport class PanelLayoutController {\n private frame: HTMLElement | null = null\n private previewCol: HTMLDivElement | null = null\n private explorerCol: HTMLDivElement | null = null\n private explorerHandle: HTMLDivElement | null = null\n private previewHandle: HTMLDivElement | null = null\n\n private styleObserver: MutationObserver | null = null\n private sizeObserver: ResizeObserver | null = null\n private waitObserver: MutationObserver | null = null\n private frameWidth = 0\n /** Cached shell details handle (re-resolved when the shell rebuilds it). */\n private detailsHandle: HTMLElement | null = null\n /** The shell's own 3 tracks (sidebar, center, details) — mirror of its inline style. */\n private shellTracks: string[] = []\n private instantTimer: ReturnType<typeof setTimeout> | undefined\n private disposers: Array<() => void> = []\n constructor(private readonly layout: LayoutStore) {}\n\n /** Start watching for the frame and attach once it appears. */\n mount(): void {\n const tryAttach = (): void => {\n if (this.frame !== null) return\n const frame = findFrame()\n if (frame === null) return\n this.attach(frame)\n }\n this.waitObserver = new MutationObserver(() => { tryAttach() })\n this.waitObserver.observe(document.body, { childList: true, subtree: true })\n tryAttach()\n }\n\n /** Attach to the frame: columns, handles, observers, store subscription. */\n private attach(frame: HTMLElement): void {\n this.frame = frame\n frameElement = frame\n // The wait observer's only job was finding the frame; a document-wide\n // MutationObserver left running would fire on every chat render for the\n // rest of the session.\n this.waitObserver?.disconnect()\n this.waitObserver = null\n this.detailsHandle = null\n\n // The two panel columns: trailing grid items (tracks 4 and 5).\n const previewCol = document.createElement('div')\n previewCol.dataset.filemgrPreviewCol = ''\n previewCol.className = 'filemgr-preview-col'\n previewCol.style.minWidth = '0'\n previewCol.style.overflow = 'hidden'\n previewCol.style.display = 'flex'\n previewCol.style.flexDirection = 'column'\n previewCol.style.borderLeft = '1px solid var(--aion-bg-3, #e5e6eb)'\n\n const explorerCol = document.createElement('div')\n explorerCol.dataset.filemgrExplorerCol = ''\n explorerCol.className = 'filemgr-explorer-col'\n explorerCol.style.minWidth = '0'\n explorerCol.style.overflow = 'hidden'\n explorerCol.style.display = 'flex'\n explorerCol.style.flexDirection = 'column'\n explorerCol.style.borderLeft = '1px solid var(--aion-bg-3, #e5e6eb)'\n\n frame.appendChild(previewCol)\n frame.appendChild(explorerCol)\n this.previewCol = previewCol\n this.explorerCol = explorerCol\n\n // The absolute drag handles (out of the grid flow). Both sit on the left\n // edge of their panel: dragging left widens (reverse).\n this.explorerHandle = this.createHandle('filemgr-explorer-handle', EXPLORER_HANDLE_WIDTH, true, 'explorer')\n this.previewHandle = this.createHandle('filemgr-preview-handle', PREVIEW_HANDLE_WIDTH, true, 'preview')\n frame.appendChild(this.explorerHandle)\n frame.appendChild(this.previewHandle)\n\n\n // Esc restores a maximized panel (issue #315). Editing surfaces own Esc:\n // while an input/textarea/contenteditable is focused, leave it alone.\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return\n const target = event.target instanceof Element ? event.target : null\n if (target !== null && target.closest('input, textarea, [contenteditable=\"true\"]') !== null) return\n this.layout.update((prev) => (prev.maximized === null ? prev : { ...prev, maximized: null }))\n }\n window.addEventListener('keydown', onKeyDown)\n this.disposers.push(() => window.removeEventListener('keydown', onKeyDown))\n\n // Sync the shell's inline grid: any shell write re-appends our tracks.\n const syncGrid = (): void => {\n const el = this.frame\n if (el === null) return\n const inline = el.style.gridTemplateColumns\n if (inline === '') return\n const tracks = parseGridTracks(inline)\n if (tracks.length >= 2 && tracks.length <= 3) {\n // The shell's own write (3 tracks) — remember it and re-append ours.\n this.shellTracks = tracks\n this.applyGrid()\n return\n }\n if (tracks.length === 5 && this.shellTracks.length === 3) {\n // Our own write — keep it (the shell tracks are already mirrored).\n return\n }\n // 6 tracks: dsh-term appended its track after our 5 — re-apply to\n // update handle positions (they must offset left by dsh-term's width).\n if (tracks.length === 6 && tracks.includes('[dsh-term]') && this.shellTracks.length === 3) {\n this.applyGrid()\n return\n }\n }\n this.styleObserver = new MutationObserver(syncGrid)\n this.styleObserver.observe(frame, { attributes: true, attributeFilter: ['style'] })\n\n // Measure the row width: frame minus the shell's sidebar + details tracks.\n const measure = (): void => {\n if (this.frame === null) return\n this.frameWidth = this.frame.getBoundingClientRect().width\n const sidebar = this.shellTracks.length >= 1 ? trackPx(this.shellTracks[0]) : 0\n const details = this.shellTracks.length >= 3 ? trackPx(this.shellTracks[2]) : 0\n const available = Math.max(0, this.frameWidth - sidebar - details)\n const state = this.layout.getSnapshot()\n if (Math.abs(state.availableWidth - available) > 0.5) {\n this.layout.update((prev) => ({ ...prev, availableWidth: available }))\n }\n this.layout.shrinkToFit(this.layout.getSnapshot())\n }\n this.sizeObserver = new ResizeObserver(() => {\n measure()\n this.applyGrid()\n })\n this.sizeObserver.observe(frame)\n\n // Store -> DOM: grid, handles, floating button.\n this.disposers.push(this.layout.subscribe(() => this.applyGrid()))\n\n // Initial sync: read the shell's inline style (it is already applied).\n const initial = frame.style.gridTemplateColumns\n if (initial !== '') {\n const tracks = parseGridTracks(initial)\n if (tracks.length >= 2 && tracks.length <= 3) {\n this.shellTracks = tracks\n } else if (tracks.length === 5 && trackPx(tracks[0]) > 0) {\n // The frame may already carry our own previous 5-track write: the\n // plugin hot-reloads in place (client HMR re-materializes the fiber),\n // and the shell's grid is then the first three tracks. A zero-width\n // first track is never a shell write (the shell collapses to the 56px\n // rail, drags clamp at 280px) — treat it as untrusted and wait for\n // the next shell write instead of mirroring the damage.\n this.shellTracks = tracks.slice(0, 3)\n }\n }\n measure()\n this.applyGrid()\n }\n\n /** Create one drag handle element with its pointer wiring. */\n private createHandle(\n className: string,\n hitWidth: number,\n reverse: boolean,\n kind: 'explorer' | 'preview',\n ): HTMLDivElement {\n const el = document.createElement('div')\n el.className = className\n el.style.position = 'absolute'\n el.style.top = '0'\n el.style.bottom = '0'\n // Same layer as the columns (z 30): the handle strips overlap the\n // column tracks, so anything lower would be painted under the opaque\n // columns and stop receiving pointer events (issue #234 follow-up).\n // Full-screen overlay drawers must render at the ROOT stacking context\n // (z 100~1000) to cover both the columns and the handles — see the\n // columns' stacking-contract note in tokens.module.css.\n el.style.zIndex = '30'\n el.style.cursor = 'col-resize'\n el.style.width = `${hitWidth}px`\n if (reverse) {\n // The preview handle extends LEFT of the preview region's left edge.\n el.style.marginLeft = `-${hitWidth}px`\n }\n el.addEventListener('pointerdown', (event: PointerEvent) => {\n const isExplorer = kind === 'explorer'\n handlePointerDragStart(event, el, {\n reverse,\n getStartWidth: () => {\n const state = this.layout.getSnapshot()\n return isExplorer ? state.explorerWidth : state.previewWidth\n },\n compute: (startWidth, deltaX) => dragTargetWidth(\n isExplorer ? 'explorer' : 'preview',\n startWidth,\n deltaX,\n this.layout.getSnapshot(),\n ),\n onFrame: (width) => {\n // layout.update notifies the subscribers (subscribe -> applyGrid),\n // so no explicit applyGrid here — double-writing every frame.\n this.layout.update((prev) => (\n isExplorer ? { ...prev, explorerWidth: width } : { ...prev, previewWidth: width }\n ))\n },\n onEnd: (width) => {\n writeStoredNumber(isExplorer ? KEY_EXPLORER_WIDTH : KEY_PREVIEW_WIDTH, width)\n },\n })\n })\n // Double-click resets THIS panel to its default width (instant, like\n // every panel width change — the shell's grid transition must not lag).\n el.addEventListener('dblclick', () => {\n this.instant(() => {\n const width = kind === 'explorer' ? DEFAULT_WORKSPACE_PANEL_PX : DEFAULT_PREVIEW_REGION_PX\n this.layout.update((prev) => (\n kind === 'explorer' ? { ...prev, explorerWidth: width } : { ...prev, previewWidth: width }\n ))\n writeStoredNumber(kind === 'explorer' ? KEY_EXPLORER_WIDTH : KEY_PREVIEW_WIDTH, width)\n this.applyGrid()\n })\n })\n // The visual line is drawn by CSS (::after) — the hit zone is transparent.\n return el\n }\n\n /** Toggle explorer collapse (width 0, kept mounted; no transition). */\n toggleExplorer(): void {\n const state = this.layout.getSnapshot()\n const next = !state.explorerCollapsed\n this.instant(() => {\n this.layout.update((prev) => ({ ...prev, explorerCollapsed: next }))\n try {\n localStorage.setItem(`project-panel-collapse:${state.root}`, next ? 'collapsed' : 'expanded')\n } catch {\n // best-effort\n }\n this.applyGrid()\n })\n }\n\n /** Toggle the preview region (open = tabs exist; close keeps tabs). */\n setPreviewOpen(open: boolean): void {\n this.instant(() => {\n this.layout.update((prev) => ({ ...prev, previewOpen: open }))\n this.applyGrid()\n })\n }\n\n /**\n * Locate the shell conversation header: its bottom border is the\n * horizontal divider under the \"Session log\" row the button should\n * sit below. Resolved per call (the shell may mount it late); null when\n * the shell has no header (standalone installs, desktop variants).\n */\n private findHeaderBottom(): number | null {\n const frame = this.frame\n if (frame === null) return null\n const header = frame.querySelector<HTMLElement>(\n '[data-pane=\"conversation\"] header, [class*=\"centerCol\"] header',\n )\n if (header === null) return null\n const bottom = header.getBoundingClientRect().bottom\n return Number.isFinite(bottom) ? bottom : null\n }\n\n\n /** Apply one store update with transitions disabled for exactly one frame. */\n private instant(fn: () => void): void {\n const frame = this.frame\n if (frame === null) {\n fn()\n return\n }\n frame.setAttribute('data-filemgr-instant', '')\n if (this.instantTimer !== undefined) clearTimeout(this.instantTimer)\n this.instantTimer = setTimeout(() => {\n this.instantTimer = undefined\n frame.removeAttribute('data-filemgr-instant')\n }, 0)\n fn()\n }\n\n /** Re-write the frame grid and reposition handles + floating button. */\n private applyGrid(): void {\n const frame = this.frame\n if (frame === null) return\n // Never guess the shell tracks: without a mirrored shell write, the old\n // fallback zeroed the sidebar track (the bug where the left sidebar\n // vanished after a hot reload). Skip the write until syncGrid observes\n // the shell's own 3-track grid.\n if (this.shellTracks.length !== 3) return\n const state = this.layout.getSnapshot()\n const width = this.frameWidth > 0 ? this.frameWidth : frame.getBoundingClientRect().width\n\n if (state.maximized !== null) {\n this.applyMaximized(frame, state.maximized, width)\n return\n }\n this.clearMaximizedChrome()\n\n const explorer = this.layout.explorerWidthPx(state)\n const preview = this.layout.previewWidthPx(state)\n\n // Detect dsh-term column (appended by the dsh-term plugin after our tracks).\n // When present, preserve its track and offset handles left by its width.\n // Check the grid tokens for [dsh-term] — the col element may exist but not\n // have a track yet (initial mount), so display/width alone are unreliable.\n const gridTokens = parseGridTracks(frame.style.gridTemplateColumns)\n const hasDshTermTrack = gridTokens.includes('[dsh-term]')\n const dshTermCol = hasDshTermTrack ? frame.querySelector<HTMLElement>('[data-dsh-term-col]') : null\n const dshTermOpen = dshTermCol !== null\n && dshTermCol.style.display !== 'none'\n && dshTermCol.getBoundingClientRect().width > 0\n const dshTermWidth = dshTermOpen ? Math.round(dshTermCol!.getBoundingClientRect().width) : 0\n\n // Five tracks: shell sidebar, center, shell details, preview, explorer.\n // (Six when dsh-term is open — preserve its track so we don't clobber it.)\n const baseGrid =\n `${this.shellTracks[0]} minmax(0, 1fr) ${this.shellTracks[2]} ${Math.round(preview)}px ${Math.round(explorer)}px`\n frame.style.gridTemplateColumns = dshTermOpen\n ? `${baseGrid} [dsh-term] ${dshTermWidth}px`\n : baseGrid\n\n // Column contents follow the tracks (both columns always mounted).\n if (this.explorerCol !== null) {\n this.explorerCol.style.visibility = explorer > 0 ? 'visible' : 'hidden'\n }\n if (this.previewCol !== null) {\n this.previewCol.style.visibility = preview > 0 ? 'visible' : 'hidden'\n }\n\n // Handles: at the left edge of each panel (offset left by dsh-term if open).\n if (this.explorerHandle !== null) {\n const left = Math.round(width - explorer - dshTermWidth)\n this.explorerHandle.style.left = `${left}px`\n this.explorerHandle.style.marginLeft = `${-EXPLORER_HANDLE_WIDTH / 2}px`\n this.explorerHandle.style.display = explorer > 0 && state.root !== '' ? 'block' : 'none'\n }\n if (this.previewHandle !== null) {\n const left = Math.round(width - explorer - preview - dshTermWidth)\n this.previewHandle.style.left = `${left}px`\n this.previewHandle.style.display = preview > 0 && state.root !== '' ? 'block' : 'none'\n }\n\n // The official shell renders its own details drag handle at\n // `viewport - details` (details treated as the last track). Once this\n // panel extends the grid with preview/explorer tracks, the real\n // center/details boundary shifts left by preview + explorer — re-derive\n // the handle position from the actual tracks so it stays on the details\n // column's left edge (degenerates to the official value when both panels\n // are closed).\n const detailsTrack = trackPx(this.shellTracks[2])\n // applyGrid runs on every drag frame: resolve the shell handle once and\n // cache it instead of scanning the whole frame subtree each call. The\n // cache resets on attach (the shell may rebuild its chrome on HMR).\n if (this.detailsHandle === null || !this.detailsHandle.isConnected) {\n this.detailsHandle = frame.querySelector<HTMLElement>('[data-side=\"details\"]')\n }\n if (this.detailsHandle !== null) {\n this.detailsHandle.style.left = `${Math.round(width - detailsTrack - preview - explorer - dshTermWidth)}px`\n }\n\n }\n\n /**\n * Maximize layout: the target column takes over the whole frame row (the\n * other tracks collapse to 0px). On narrow viewports the takeover grid is\n * skipped and the column renders as a fixed full-screen overlay instead\n * (issue #315). Everything stays mounted — only geometry changes.\n */\n private applyMaximized(frame: HTMLElement, target: MaximizeTarget, width: number): void {\n const overlay = maximizedOverlay(this.layout.getSnapshot().availableWidth)\n if (!overlay) {\n frame.style.gridTemplateColumns = maximizedGridTracks(target, width)\n }\n if (this.explorerCol !== null) {\n this.explorerCol.style.visibility = target === 'explorer' ? 'visible' : 'hidden'\n this.explorerCol.classList.toggle('filemgr-maximized', target === 'explorer' && overlay)\n }\n if (this.previewCol !== null) {\n this.previewCol.style.visibility = target === 'preview' ? 'visible' : 'hidden'\n this.previewCol.classList.toggle('filemgr-maximized', target === 'preview' && overlay)\n }\n // No drag chrome while maximized: nothing to resize.\n if (this.explorerHandle !== null) this.explorerHandle.style.display = 'none'\n if (this.previewHandle !== null) this.previewHandle.style.display = 'none'\n }\n\n /** Remove the narrow-screen overlay class from both columns. */\n private clearMaximizedChrome(): void {\n this.explorerCol?.classList.remove('filemgr-maximized')\n this.previewCol?.classList.remove('filemgr-maximized')\n }\n\n /** Detach everything (plugin unload). */\n dispose(): void {\n this.waitObserver?.disconnect()\n this.styleObserver?.disconnect()\n this.sizeObserver?.disconnect()\n for (const dispose of this.disposers) dispose()\n this.previewCol?.remove()\n this.explorerCol?.remove()\n this.explorerHandle?.remove()\n this.previewHandle?.remove()\n\n if (this.instantTimer !== undefined) clearTimeout(this.instantTimer)\n if (frameElement === this.frame) frameElement = null\n this.frame = null\n }\n}\n","/**\n * Locale strings for the panel surfaces (zh/en). The client registers the\n * dictionary through the locale service like the sibling plugins; copy is\n * deliberately short and technical.\n * @module dsh-filemgr/client/locales\n */\n\nconst zh = {\n 'explorer.tabs.files': '文件',\n 'explorer.tabs.changes': '变更',\n 'explorer.search.placeholder': '按文件名搜索',\n 'explorer.search.searching': '搜索中…',\n 'explorer.search.empty': '没有匹配的文件',\n 'explorer.search.error': '搜索失败',\n 'explorer.search.truncated': '结果过多,仅显示前 {count} 条',\n 'explorer.tree.empty': '项目为空',\n 'explorer.collapse': '收起面板',\n 'explorer.expand': '展开面板',\n 'explorer.maximize': '最大化文件面板',\n 'explorer.restore': '还原面板',\n 'explorer.openPreview': '打开预览',\n 'explorer.drag.dropHint': '松手插入文件路径',\n 'scm.repositories': '存储库',\n 'scm.changes': '变更',\n 'scm.staged': '已暂存',\n 'scm.unstaged': '变更',\n 'scm.untracked': '未跟踪',\n 'scm.conflicted': '冲突',\n 'scm.stage': '暂存',\n 'scm.unstage': '取消暂存',\n 'scm.discard': '放弃更改',\n 'scm.stageAll': '全部暂存',\n 'scm.discardAll': '全部放弃',\n 'scm.empty': '没有更改',\n 'scm.notRepo': '当前目录不是 git 仓库',\n 'scm.gitMissing': '未检测到 git,请先安装 git 后重试',\n 'scm.loading': '读取状态中…',\n 'scm.failed': '操作失败',\n 'scm.viewList': '列表视图',\n 'scm.viewTree': '树视图',\n 'scm.discardConfirmTracked': '放弃对 {count} 个文件的更改?此操作不可恢复。',\n 'scm.discardConfirmUntracked': '删除 {count} 个未跟踪文件?此操作不可恢复。',\n 'preview.noTabs': '没有打开的预览',\n 'preview.newUrlTab': '新建 URL 预览',\n 'preview.collapsePanel': '收起预览面板',\n 'preview.maximize': '最大化预览面板',\n 'preview.restore': '还原面板',\n 'preview.source': '源码',\n 'preview.preview': '预览',\n 'preview.editor': '编辑器',\n 'preview.split': '分屏',\n 'preview.refresh': '刷新',\n 'preview.refresh.updated': '文件已在磁盘更新',\n 'preview.save': '保存',\n 'preview.download': '下载',\n 'preview.copyCode': '复制代码',\n 'preview.copyCodeDone': '已复制',\n 'preview.openExternal': '在系统应用中打开',\n 'preview.dirty': '未保存的更改',\n 'preview.closeLeft': '关闭左侧',\n 'preview.closeRight': '关闭右侧',\n 'preview.closeOthers': '关闭其他',\n 'preview.closeAll': '关闭全部',\n 'preview.closeConfirmTitle': '关闭未保存的标签页',\n 'preview.closeConfirmBody': '{count} 个标签页有未保存的更改,关闭将丢失这些更改。',\n 'preview.saved': '已保存',\n 'preview.saveConflict': '文件已在磁盘上被修改,保存冲突:请刷新后重试',\n 'preview.errorOversized': '文件过大,仅加载前 80,000 字符',\n 'preview.unsupported': '此格式暂不支持预览',\n 'preview.downloadHint': '可在系统应用中打开或下载查看',\n 'preview.url.placeholder': '输入网址,回车打开',\n 'preview.url.hint': '按 Esc 还原',\n 'common.cancel': '取消',\n 'common.confirm': '确定',\n 'common.close': '关闭',\n 'common.delete': '删除',\n 'common.copyPath': '复制路径',\n 'common.copied': '已复制',\n 'explorer.menu.copyPath': '复制路径',\n 'explorer.menu.copyName': '复制名称',\n 'explorer.menu.reveal': '在文件管理器中显示',\n 'explorer.menu.openWithDefault': '用默认应用打开',\n 'explorer.menu.rename': '重命名',\n 'explorer.menu.newFile': '新建文件',\n 'explorer.menu.newFolder': '新建文件夹',\n 'explorer.menu.delete': '删除',\n 'explorer.rename.title': '重命名',\n 'explorer.newFile.title': '新建文件',\n 'explorer.newFolder.title': '新建文件夹',\n 'explorer.deleteConfirmTitle': '删除确认',\n 'explorer.deleteConfirmBody': '确定要删除「{name}」吗?此操作不可恢复。',\n 'explorer.opFailed': '操作失败',\n 'explorer.refToInput': '引用到输入框',\n 'settings.title': '右侧面板',\n 'settings.description': 'Explorer / Preview 与 SCM 变更面板的总开关。',\n 'settings.enabled': '启用右侧面板',\n 'settings.enabledHint': '关闭后不再挂载右侧文件树与预览列、不显示浮动展开按钮、不注册 /filemgr 路由,也不做工作区监视与 git 轮询;聚合包其余插件不受影响。',\n 'settings.overridden': '已覆盖',\n 'settings.reset': '恢复默认',\n 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或为 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES 白名单补充本命名空间后重启。',\n 'settings.readOnly': '当前部署的设置只读。',\n 'settings.inherit': '继承',\n 'settings.on': '开',\n 'settings.off': '关',\n 'settings.expand': '展开设置',\n 'settings.collapse': '收起设置',\n 'settings.save': '保存',\n 'settings.saving': '保存中…',\n 'settings.discard': '放弃',\n 'settings.unsaved': '未保存',\n 'settings.saveFailed': '部署未接受这些值,已保留供你修改。',\n 'settings.invalidNumber': '请输入数字,留空则使用默认值。',\n} as const\n\nconst en: Record<keyof typeof zh, string> = {\n 'explorer.tabs.files': 'Files',\n 'explorer.tabs.changes': 'Changes',\n 'explorer.search.placeholder': 'Search file names',\n 'explorer.search.searching': 'Searching…',\n 'explorer.search.empty': 'No matching files',\n 'explorer.search.error': 'Search failed',\n 'explorer.search.truncated': 'Too many results, showing first {count}',\n 'explorer.tree.empty': 'The project is empty',\n 'explorer.collapse': 'Collapse panel',\n 'explorer.expand': 'Expand panel',\n 'explorer.maximize': 'Maximize files panel',\n 'explorer.restore': 'Restore panel',\n 'explorer.openPreview': 'Open preview',\n 'explorer.drag.dropHint': 'Release to insert the file path',\n 'scm.repositories': 'Repositories',\n 'scm.changes': 'Changes',\n 'scm.staged': 'Staged',\n 'scm.unstaged': 'Changes',\n 'scm.untracked': 'Untracked',\n 'scm.conflicted': 'Conflict',\n 'scm.stage': 'Stage',\n 'scm.unstage': 'Unstage',\n 'scm.discard': 'Discard',\n 'scm.stageAll': 'Stage all',\n 'scm.discardAll': 'Discard all',\n 'scm.empty': 'No changes',\n 'scm.notRepo': 'Not a git repository',\n 'scm.gitMissing': 'Git is not installed. Install git and reload to use the changes panel',\n 'scm.loading': 'Loading status…',\n 'scm.failed': 'Operation failed',\n 'scm.viewList': 'List view',\n 'scm.viewTree': 'Tree view',\n 'scm.discardConfirmTracked': 'Discard changes in {count} files? This cannot be undone.',\n 'scm.discardConfirmUntracked': 'Delete {count} untracked files? This cannot be undone.',\n 'preview.noTabs': 'No open previews',\n 'preview.newUrlTab': 'New URL preview',\n 'preview.collapsePanel': 'Collapse preview panel',\n 'preview.maximize': 'Maximize preview panel',\n 'preview.restore': 'Restore panel',\n 'preview.source': 'Source',\n 'preview.preview': 'Preview',\n 'preview.editor': 'Editor',\n 'preview.split': 'Split',\n 'preview.refresh': 'Refresh',\n 'preview.refresh.updated': 'File updated on disk',\n 'preview.save': 'Save',\n 'preview.download': 'Download',\n 'preview.copyCode': 'Copy code',\n 'preview.copyCodeDone': 'Copied',\n 'preview.openExternal': 'Open in system app',\n 'preview.dirty': 'Unsaved changes',\n 'preview.closeLeft': 'Close left',\n 'preview.closeRight': 'Close right',\n 'preview.closeOthers': 'Close others',\n 'preview.closeAll': 'Close all',\n 'preview.closeConfirmTitle': 'Close unsaved tabs',\n 'preview.closeConfirmBody': '{count} tabs have unsaved changes. Closing will lose them.',\n 'preview.saved': 'Saved',\n 'preview.saveConflict': 'File changed on disk. Save conflict: refresh and retry',\n 'preview.errorOversized': 'File too large, only the first 80,000 characters loaded',\n 'preview.unsupported': 'Preview not supported for this format',\n 'preview.downloadHint': 'Open in a system app or download to view',\n 'preview.url.placeholder': 'Enter a URL and press Enter',\n 'preview.url.hint': 'Press Esc to revert',\n 'common.cancel': 'Cancel',\n 'common.confirm': 'OK',\n 'common.close': 'Close',\n 'common.delete': 'Delete',\n 'common.copyPath': 'Copy path',\n 'common.copied': 'Copied',\n 'explorer.menu.copyPath': 'Copy path',\n 'explorer.menu.copyName': 'Copy name',\n 'explorer.menu.reveal': 'Reveal in file manager',\n 'explorer.menu.openWithDefault': 'Open with default app',\n 'explorer.menu.rename': 'Rename',\n 'explorer.menu.newFile': 'New file',\n 'explorer.menu.newFolder': 'New folder',\n 'explorer.menu.delete': 'Delete',\n 'explorer.rename.title': 'Rename',\n 'explorer.newFile.title': 'New file',\n 'explorer.newFolder.title': 'New folder',\n 'explorer.deleteConfirmTitle': 'Confirm delete',\n 'explorer.deleteConfirmBody': 'Delete \"{name}\"? This cannot be undone.',\n 'explorer.opFailed': 'Operation failed',\n 'explorer.refToInput': 'Reference to input',\n 'settings.title': 'Right panel',\n 'settings.description': 'Master switch for the Explorer / Preview and SCM changes panels.',\n 'settings.enabled': 'Enable the right panel',\n 'settings.enabledHint': 'When off, the Explorer and Preview columns are not mounted, the floating expand button disappears, the /filemgr routes are not registered, and workspace watching and git polling stop. The rest of the family bundle is unaffected.',\n 'settings.overridden': 'Overridden',\n 'settings.reset': 'Reset',\n 'settings.notExposed': 'This DSH version does not expose this plugin\\'s settings namespace; the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to the WEB_SETTINGS_NAMESPACES allowlist of dsh-host-apiproxy and restart.',\n 'settings.readOnly': 'Settings are read-only in this deployment.',\n 'settings.inherit': 'Inherit',\n 'settings.on': 'On',\n 'settings.off': 'Off',\n 'settings.expand': 'Expand settings',\n 'settings.collapse': 'Collapse settings',\n 'settings.save': 'Save',\n 'settings.saving': 'Saving…',\n 'settings.discard': 'Discard',\n 'settings.unsaved': 'Unsaved',\n 'settings.saveFailed': 'The deployment rejected these values; your edits are kept.',\n 'settings.invalidNumber': 'Enter a number, or leave it empty to use the default.',\n}\n\nexport type FileManagerPanelKey = keyof typeof zh\n\n/** The dictionary namespace this plugin owns. */\nexport const NS = 'filemgr'\n\n/** Format one copy string with {name} placeholders. */\nexport function format(template: string, params: Record<string, string | number>): string {\n return template.replace(/\\{(\\w+)\\}/g, (_, key: string) => String(params[key] ?? `{${key}}`))\n}\n\n/** Simple dictionary access (zh/en by a global flag the client sets). */\nexport const dictionaries: Record<'zh' | 'en', Record<FileManagerPanelKey, string>> = { zh, en }\n\nlet currentLanguage: 'zh' | 'en' = 'zh'\n\n/** Set the active language (the client mirrors the locale service). */\nexport function setLanguage(language: string): void {\n currentLanguage = language === 'en' ? 'en' : 'zh'\n}\n\n/** Translate one key with optional params. */\nexport function t(key: FileManagerPanelKey, params?: Record<string, string | number>): string {\n const table = dictionaries[currentLanguage] ?? zh\n const template = table[key] ?? zh[key]\n return params === undefined ? template : format(template, params)\n}\n","/**\n * React bindings for the framework-free stores: useSyncExternalStore with a\n * stable snapshot (the stores return immutable snapshots, so selector-free\n * subscription is safe), plus a stable-callback helper for event handlers.\n * @module dsh-filemgr/client/hooks/useStore\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type { StateHandle } from '../store.ts'\n\n/** Subscribe a component to one store (full snapshot). */\nexport function useStore<S>(store: StateHandle<S>): S {\n return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)\n}\n\n","/**\n * Inline 16px icon set for the panel surfaces (outline style, currentColor).\n * No icon package is introduced; the set covers the explorer tree, SCM rows,\n * and the preview toolbar/tabs with plain geometric shapes.\n * @module dsh-filemgr/client/components/icons\n */\n\nimport type { JSX, SVGProps } from 'react'\n\ninterface IconProps {\n size?: number\n className?: string\n}\n\nconst base = (size: number): SVGProps<SVGSVGElement> => ({\n width: size,\n height: size,\n viewBox: '0 0 16 16',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.3,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': true,\n})\n\nexport function FolderIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2 3.5h4l1.5 2H14a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4.5a1 1 0 0 1 1-1Z\" />\n </svg>\n )\n}\n\nexport function FolderOpenIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2 3.5h4l1.5 2H14a1 1 0 0 1 1 1v1H3.5a1 1 0 0 0-.96.72L1 13.5V4.5a1 1 0 0 1 1-1Z\" />\n <path d=\"M2.8 11.5 4 7.5h11l-1.4 4a1 1 0 0 1-.96.72H3.76a1 1 0 0 1-.96-.72Z\" />\n </svg>\n )\n}\n\nexport function FileIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M4 2h5l3 3v9H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\" />\n <path d=\"M9 2v3h3\" />\n </svg>\n )\n}\n\nexport function FileCodeIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M4 2h5l3 3v9H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\" />\n <path d=\"M9 2v3h3\" />\n <path d=\"m6.2 8.6-1.4 1.4 1.4 1.4M9.8 8.6l1.4 1.4-1.4 1.4\" />\n </svg>\n )\n}\n\nexport function FileImageIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M4 2h5l3 3v9H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\" />\n <path d=\"M9 2v3h3\" />\n <circle cx=\"6.2\" cy=\"6.8\" r=\"1\" />\n <path d=\"m5 11 1.8-1.8 1.4 1.4 1.3-1.3L12 12\" />\n </svg>\n )\n}\n\nexport function FileTextIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M4 2h5l3 3v9H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\" />\n <path d=\"M9 2v3h3\" />\n <path d=\"M6 9h4M6 11.2h4\" />\n </svg>\n )\n}\n\nexport function ChevronRightIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"m6 3.5 4.5 4.5L6 12.5\" />\n </svg>\n )\n}\n\nexport function ChevronDownIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"m3.5 6 4.5 4.5L12.5 6\" />\n </svg>\n )\n}\n\nexport function CloseIcon({ size = 12, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"m3.5 3.5 9 9M12.5 3.5l-9 9\" />\n </svg>\n )\n}\n\nexport function PlusIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M8 3v10M3 8h10\" />\n </svg>\n )\n}\n\nexport function MinusIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M3 8h10\" />\n </svg>\n )\n}\n\nexport function UndoIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M5 3.5 2.5 6 5 8.5\" />\n <path d=\"M2.5 6h8a3.5 3.5 0 0 1 0 7h-3\" />\n </svg>\n )\n}\n\nexport function RefreshIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M13 8a5 5 0 1 1-1.6-3.65\" />\n <path d=\"M13.5 2v2.8h-2.8\" />\n </svg>\n )\n}\n\nexport function SplitIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <rect x=\"2\" y=\"2.5\" width=\"12\" height=\"11\" rx=\"1\" />\n <path d=\"M8 2.5v11\" />\n </svg>\n )\n}\n\nexport function CodeIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"m5.5 4.5-4 3.5 4 3.5M10.5 4.5l4 3.5-4 3.5\" />\n </svg>\n )\n}\n\nexport function EyeIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M1.5 8s2.5-4.5 6.5-4.5S14.5 8 14.5 8 12 12.5 8 12.5 1.5 8 1.5 8Z\" />\n <circle cx=\"8\" cy=\"8\" r=\"2\" />\n </svg>\n )\n}\n\nexport function SaveIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M3 2.5h8l2.5 2.5v8.5a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1Z\" />\n <path d=\"M5 2.5v3.5h4.5V2.5M5 13.5V9.5h6v4\" />\n </svg>\n )\n}\n\nexport function DownloadIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M8 2v7.5M4.5 6.5 8 10l3.5-3.5\" />\n <path d=\"M2.5 13h11\" />\n </svg>\n )\n}\n\nexport function ExternalIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M9 2.5h4.5V7\" />\n <path d=\"M13.5 2.5 7.5 8.5\" />\n <path d=\"M11.5 9v3.5a1 1 0 0 1-1 1H3.5a1 1 0 0 1-1-1V5.5a1 1 0 0 1 1-1H7\" />\n </svg>\n )\n}\n\nexport function SearchIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" />\n <path d=\"m10.5 10.5 3 3\" />\n </svg>\n )\n}\n\nexport function BranchIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <circle cx=\"4\" cy=\"3.5\" r=\"1.5\" />\n <circle cx=\"4\" cy=\"12.5\" r=\"1.5\" />\n <circle cx=\"12\" cy=\"6.5\" r=\"1.5\" />\n <path d=\"M4 5v5M4 10.5c0-2 2-2.5 4-2.5s4-.5 4-1.5\" />\n </svg>\n )\n}\n\nexport function ListIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2.5 4h11M2.5 8h11M2.5 12h11\" />\n </svg>\n )\n}\n\nexport function TreeIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2.5 3.5h6M8.5 8h5M2.5 8h2\" />\n <path d=\"M6 3.5v7\" />\n <path d=\"M11 8v4.5h-2.5\" />\n </svg>\n )\n}\n\nexport function ShrinkIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M14 14 10 10M10 14v-4h4\" />\n <path d=\"M2 2l4 4M6 2v4H2\" />\n </svg>\n )\n}\n\nexport function ExpandRightIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M6 3.5 11.5 8 6 12.5\" />\n </svg>\n )\n}\n\nexport function EmptyFolderIcon({ size = 16, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <path d=\"M2 3.5h4l1.5 2H14a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4.5a1 1 0 0 1 1-1Z\" opacity=\"0.55\" />\n </svg>\n )\n}\n\nexport function MaximizeIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <rect x=\"3\" y=\"3\" width=\"10\" height=\"10\" rx=\"1\" />\n </svg>\n )\n}\n\nexport function RestoreIcon({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg {...base(size)} className={className}>\n <rect x=\"3\" y=\"5\" width=\"8\" height=\"8\" rx=\"1\" />\n <path d=\"M6.5 3.5h5a1 1 0 0 1 1 1V10\" />\n </svg>\n )\n}\n","/**\n * 16x16 file/folder icons for the tree — a small built-in set (folder\n * open/closed, file variants by kind) using the token colors, so both themes\n * stay consistent without pulling in a vscode-icons package.\n * @module dsh-filemgr/client/components/FileIcon\n */\n\nimport type { JSX } from 'react'\nimport { detectContentType } from '../fileType.ts'\nimport {\n FileCodeIcon, FileIcon, FileImageIcon, FileTextIcon, FolderIcon, FolderOpenIcon,\n} from './icons.tsx'\n\n/** The icon for one tree entry (16x16, currentColor). */\nexport function FileTypeIcon({\n name,\n isDir,\n expanded,\n className,\n}: {\n name: string\n isDir: boolean\n expanded: boolean\n className?: string\n}): JSX.Element {\n if (isDir) {\n return expanded\n ? <FolderOpenIcon size={16} className={className} />\n : <FolderIcon size={16} className={className} />\n }\n const type = detectContentType(name)\n switch (type) {\n case 'image':\n return <FileImageIcon size={16} className={className} />\n case 'markdown':\n case 'text':\n return <FileTextIcon size={16} className={className} />\n case 'code':\n case 'diff':\n case 'csv':\n case 'html':\n return <FileCodeIcon size={16} className={className} />\n default:\n return <FileIcon size={16} className={className} />\n }\n}\n","/**\n * Minimal overlay primitives for the panel: a toast and a context menu,\n * rendered through plain DOM + portals so they can live outside the grid\n * columns (fixed positioning, high z-index).\n * @module dsh-filemgr/client/components/overlay\n */\n\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport type { JSX } from 'react'\nimport { t } from '../locales.ts'\nimport type { FileManagerPanelKey } from '../locales.ts'\n\n/** One transient toast message. */\nexport function toast(message: string): void {\n const el = document.createElement('div')\n el.className = 'filemgr-toast'\n el.textContent = message\n document.body.appendChild(el)\n setTimeout(() => {\n el.style.opacity = '0'\n el.style.transition = 'opacity 0.2s ease'\n }, 1800)\n setTimeout(() => el.remove(), 2100)\n}\n\n/** One context-menu entry (separators carry no handler). */\nexport interface MenuEntry {\n key: string\n label: string\n disabled?: boolean\n danger?: boolean\n onSelect?: () => void\n}\n\nexport interface MenuState {\n x: number\n y: number\n entries: MenuEntry[]\n}\n\n/** The shared context-menu portal host (one at a time). */\nexport function ContextMenu({ state, onClose }: { state: MenuState | null; onClose: () => void }): JSX.Element | null {\n const [position, setPosition] = useState<{ x: number; y: number } | null>(null)\n\n useLayoutEffect(() => {\n if (state === null) {\n setPosition(null)\n return\n }\n // Keep the menu inside the viewport.\n const width = 180\n const height = state.entries.length * 28 + 12\n setPosition({\n x: Math.min(state.x, window.innerWidth - width - 8),\n y: Math.min(state.y, window.innerHeight - height - 8),\n })\n }, [state])\n\n useEffect(() => {\n if (state === null) return\n const close = (event: Event): void => {\n // A pointerdown inside the menu must not close it — the menu item's own\n // onClick still needs to run (and microtask-less onClose before onSelect\n // would unmount the item mid-click). Only close on outside clicks.\n if (event.target instanceof Element && event.target.closest('[data-menu-root]') !== null) return\n onClose()\n }\n const key = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') onClose()\n }\n window.addEventListener('pointerdown', close, { capture: true })\n window.addEventListener('blur', onClose)\n window.addEventListener('keydown', key)\n window.addEventListener('contextmenu', onClose)\n return () => {\n window.removeEventListener('pointerdown', close, { capture: true })\n window.removeEventListener('blur', onClose)\n window.removeEventListener('keydown', key)\n window.removeEventListener('contextmenu', onClose)\n }\n }, [state, onClose])\n\n if (state === null || position === null) return null\n return createPortal(\n <div\n className=\"filemgr-menu\"\n data-menu-root=\"\"\n style={{ left: position.x, top: position.y }}\n onPointerDown={(event) => event.stopPropagation()}\n onContextMenu={(event) => event.preventDefault()}\n >\n {state.entries.map((entry) => (\n <div key={entry.key}>\n {entry.label === '---' ? (\n <div className=\"filemgr-menu-sep\" />\n ) : (\n <div\n className={`filemgr-menu-item${entry.disabled === true ? ' filemgr-menu-item-disabled' : ''}`}\n onClick={() => {\n if (entry.disabled === true) return\n onClose()\n entry.onSelect?.()\n }}\n role=\"menuitem\"\n >\n {entry.label}\n </div>\n )}\n </div>\n ))}\n </div>,\n document.body,\n )\n}\n\n/** A single-text-input dialog (rename, new file / new folder). */\nexport function PromptDialog({\n title,\n initialValue,\n confirmLabel,\n onConfirm,\n onCancel,\n}: {\n title: string\n initialValue?: string\n confirmLabel?: string\n onConfirm: (value: string) => void\n onCancel: () => void\n}): JSX.Element {\n const [value, setValue] = useState(initialValue ?? '')\n const inputRef = useRef<HTMLInputElement>(null)\n useLayoutEffect(() => {\n inputRef.current?.focus()\n inputRef.current?.select()\n }, [])\n const commit = (): void => {\n const trimmed = value.trim()\n if (trimmed === '') return\n onConfirm(trimmed)\n }\n useEffect(() => {\n const key = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') onCancel()\n }\n window.addEventListener('keydown', key)\n return () => window.removeEventListener('keydown', key)\n }, [onCancel])\n return createPortal(\n <div className=\"filemgr-overlay\" onPointerDown={onCancel}>\n <div className=\"filemgr-dialog\" onPointerDown={(event) => event.stopPropagation()}>\n <div className=\"filemgr-dialog-title\">{title}</div>\n <div className=\"filemgr-dialog-body\">\n <input\n ref={inputRef}\n className=\"filemgr-input\"\n value={value}\n placeholder={initialValue ?? ''}\n aria-label={title}\n onChange={(event) => setValue(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n />\n </div>\n <div className=\"filemgr-dialog-actions\">\n <button type=\"button\" className=\"filemgr-btn\" onClick={onCancel}>{t('common.cancel')}</button>\n <button\n type=\"button\"\n className=\"filemgr-btn filemgr-btn-primary\"\n disabled={value.trim() === ''}\n onClick={commit}\n >\n {confirmLabel ?? t('common.confirm')}\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n\n/** A confirmation dialog (dirty-close confirm, discard confirm). */\nexport function ConfirmDialog({\n title,\n body,\n confirmLabel,\n danger,\n onConfirm,\n onCancel,\n}: {\n title: string\n body: string\n confirmLabel?: string\n danger?: boolean\n onConfirm: () => void\n onCancel: () => void\n}): JSX.Element {\n useEffect(() => {\n const key = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') onCancel()\n }\n window.addEventListener('keydown', key)\n return () => window.removeEventListener('keydown', key)\n }, [onCancel])\n return createPortal(\n <div className=\"filemgr-overlay\" onPointerDown={onCancel}>\n <div className=\"filemgr-dialog\" onPointerDown={(event) => event.stopPropagation()}>\n <div className=\"filemgr-dialog-title\">{title}</div>\n <div className=\"filemgr-dialog-body\">{body}</div>\n <div className=\"filemgr-dialog-actions\">\n <button type=\"button\" className=\"filemgr-btn\" onClick={onCancel}>{t('common.cancel')}</button>\n <button\n type=\"button\"\n className={`filemgr-btn ${danger === true ? 'filemgr-btn-danger' : 'filemgr-btn-primary'}`}\n onClick={onConfirm}\n >\n {confirmLabel ?? t('common.confirm')}\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n","import type { KeyboardEvent } from 'react'\n\n/**\n * Keyboard activation parity for focusable rows/divs styled as buttons\n * (role=\"button\" + tabIndex={0}): Enter and Space trigger the same action as\n * a click, and events bubbling out of nested interactive elements (a row's\n * inline action buttons, a tab's close control) are ignored so they never\n * double-activate the row.\n * @param handler - the activation handler (the element's click action).\n * @returns a keydown handler for the focusable element.\n */\nexport function activateOnKey(handler: () => void) {\n return (event: KeyboardEvent<HTMLElement>): void => {\n if (event.target !== event.currentTarget) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handler()\n }\n }\n}\n","/**\n * The Changes (SCM) panel: per-repo working-tree status grouped into staged /\n * unstaged / untracked, with stage/unstage/discard actions on every row and\n * bulk actions in the section header. The host status is the only truth — no\n * optimistic rows; a failed batch surfaces its paths and the next refresh\n * clears the flag. Discard confirms with copy split by recoverability\n * (untracked = delete vs tracked = irreversible restore).\n *\n * FileManager ScmPanel behavior (Apache-2.0, re-implemented): window focus\n * refreshes (external editors write without git events), unknown states\n * render as a quiet '?', conflicted rows are visually distinct AND have no\n * actions.\n * @module dsh-filemgr/client/components/ScmPanel\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport type { GitChangeRow } from '../../core/types.ts'\nimport { t, format } from '../locales.ts'\nimport { useStore } from '../hooks/useStore.ts'\nimport type { PanelStores } from '../store.ts'\nimport { ConfirmDialog } from './overlay.tsx'\nimport { activateOnKey } from './a11y.ts'\nimport { FileTypeIcon } from './FileIcon.tsx'\nimport { BranchIcon, ChevronDownIcon, ChevronRightIcon, ListIcon, MinusIcon, PlusIcon, TreeIcon, UndoIcon } from './icons.tsx'\nimport scmCss from '../styles/scm.module.css'\n\n/** Minimum gap between window-focus SCM refreshes (ms). */\nconst FOCUS_REFRESH_MIN_MS = 5_000\n\n/** Badge letter + color class per state. */\nconst BADGE: Record<string, { letter: string; className: string }> = {\n created: { letter: 'A', className: scmCss.badgeCreated },\n modified: { letter: 'M', className: scmCss.badgeModified },\n deleted: { letter: 'D', className: scmCss.badgeDeleted },\n renamed: { letter: 'R', className: scmCss.badgeCreated },\n conflicted: { letter: '!', className: scmCss.badgeConflicted },\n untracked: { letter: '?', className: scmCss.badgeUntracked },\n unknown: { letter: '?', className: scmCss.badgeUntracked },\n}\n\n/** The parent dir of a path ('' for root-level). */\nfunction dirOf(path: string): string {\n const idx = path.lastIndexOf('/')\n return idx > 0 ? path.slice(0, idx) : ''\n}\n\n/** Build a display-only directory tree from rows. */\nfunction buildTree(rows: GitChangeRow[]): Map<string, GitChangeRow[]> {\n const byDir = new Map<string, GitChangeRow[]>()\n for (const row of rows) {\n const dir = dirOf(row.path)\n const list = byDir.get(dir)\n if (list === undefined) byDir.set(dir, [row])\n else list.push(row)\n }\n return byDir\n}\n\n/** The SCM tab body.\n * @param stores - the panel store bundle.\n */\nexport function ScmPanel({ stores }: { stores: PanelStores }): JSX.Element {\n const scm = stores.scm\n const preview = stores.preview\n const state = useStore(scm)\n const [discardTargets, setDiscardTargets] = useState<GitChangeRow[] | null>(null)\n\n // Window focus refreshes (catches external editors writing the tree).\n // Throttled: a focus burst must not spawn a git status per event — the\n // fs watch (host) and the 30s host poll already cover the steady state.\n // -Infinity so the first focus after mount always fires (production\n // Date.now() is enormous anyway; the sentinel makes the throttle explicit\n // and testable at clock 0).\n const lastFocusRefresh = useRef(-Infinity)\n useEffect(() => {\n const onFocus = (): void => {\n const now = Date.now()\n if (now - lastFocusRefresh.current < FOCUS_REFRESH_MIN_MS) return\n lastFocusRefresh.current = now\n void scm.refresh()\n }\n window.addEventListener('focus', onFocus)\n return () => window.removeEventListener('focus', onFocus)\n }, [scm])\n\n const status = state.status\n const changesSectionOpen = state.sectionCollapsed['changes'] !== true\n\n const requestDiscard = (rows: GitChangeRow[]): void => {\n if (rows.length === 0) return\n setDiscardTargets(rows)\n }\n const confirmDiscard = (): void => {\n if (discardTargets === null) return\n void scm.discard(discardTargets.map((row) => row.path))\n setDiscardTargets(null)\n }\n\n if (state.loading && status === null) {\n return <div className={`filemgr-root ${scmCss.panel}`}><div className={scmCss.loading}>{t('scm.loading')}</div></div>\n }\n if (state.gitMissing) {\n return <div className={`filemgr-root ${scmCss.panel}`}><div className={scmCss.notRepo}>{t('scm.gitMissing')}</div></div>\n }\n if (status === null) {\n return <div className={`filemgr-root ${scmCss.panel}`}><div className={scmCss.notRepo}>{t('scm.notRepo')}</div></div>\n }\n\n const staged = status.staged\n const unstaged = status.unstaged\n const untracked = status.untracked\n const hasChanges = staged.length + unstaged.length + untracked.length > 0\n const allUntracked = discardTargets !== null && discardTargets.every((row) => row.state === 'untracked')\n\n return (\n <div className={`filemgr-root ${scmCss.panel}`}>\n {/* Changes section. */}\n <div className={scmCss.section} style={{ flex: changesSectionOpen ? 1 : undefined, maxHeight: changesSectionOpen ? undefined : 24 }}>\n <div\n className={scmCss.sectionHeader}\n onClick={() => scm.setSectionCollapsed('changes', changesSectionOpen)}\n onKeyDown={activateOnKey(() => { scm.setSectionCollapsed('changes', changesSectionOpen) })}\n role=\"button\"\n tabIndex={0}\n aria-expanded={changesSectionOpen}\n >\n <span className={`${scmCss.sectionChevron}${changesSectionOpen ? ` ${scmCss.sectionChevronOpen}` : ''}`}>\n <ChevronRightIcon size={13} />\n </span>\n <span className={scmCss.sectionTitle}>{t('scm.changes')}</span>\n {status.branch !== '' && (\n <span className={scmCss.branchName} style={{ fontSize: 11, color: 'var(--aion-text-tertiary)', display: 'flex', alignItems: 'center', gap: 4 }}>\n <BranchIcon size={12} />\n {status.branch}\n </span>\n )}\n <span\n style={{ display: 'flex', alignItems: 'center', gap: 2, marginLeft: 'auto' }}\n onClick={(event) => event.stopPropagation()}\n >\n <button\n type=\"button\"\n className={scmCss.sectionAction}\n title={t('scm.stageAll')}\n onClick={() => void scm.stage(unstaged.map((row) => row.path))}\n disabled={unstaged.length === 0}\n >\n <PlusIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.sectionAction}\n title={t('scm.discardAll')}\n onClick={() => requestDiscard([...unstaged, ...untracked])}\n disabled={unstaged.length + untracked.length === 0}\n >\n <UndoIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.sectionAction}\n title={t('scm.viewList')}\n style={{ color: state.viewMode === 'list' ? 'var(--aion-brand)' : undefined }}\n onClick={() => scm.setViewMode('list')}\n >\n <ListIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.sectionAction}\n title={t('scm.viewTree')}\n style={{ color: state.viewMode === 'tree' ? 'var(--aion-brand)' : undefined }}\n onClick={() => scm.setViewMode('tree')}\n >\n <TreeIcon size={13} />\n </button>\n </span>\n </div>\n\n {changesSectionOpen && (\n <div className={scmCss.sectionBody}>\n {!hasChanges && <div className={scmCss.empty}>{t('scm.empty')}</div>}\n {hasChanges && (\n <Group\n scm={scm}\n preview={preview}\n title={staged.length > 0 ? t('scm.staged') : undefined}\n rows={staged}\n bulkLabel={t('scm.unstage')}\n onBulk={(rows) => void scm.unstage(rows.map((row) => row.path))}\n onDiscard={requestDiscard}\n />\n )}\n {hasChanges && unstaged.length > 0 && (\n <Group\n scm={scm}\n preview={preview}\n rows={unstaged}\n bulkLabel={t('scm.stage')}\n onBulk={(rows) => void scm.stage(rows.map((row) => row.path))}\n onDiscard={requestDiscard}\n />\n )}\n {untracked.length > 0 && (\n <Group\n scm={scm}\n preview={preview}\n title={t('scm.untracked')}\n rows={untracked}\n bulkLabel={t('scm.stage')}\n onBulk={(rows) => void scm.stage(rows.map((row) => row.path))}\n onDiscard={requestDiscard}\n />\n )}\n </div>\n )}\n </div>\n\n {discardTargets !== null && (\n <ConfirmDialog\n title={t('scm.discard')}\n body={allUntracked\n ? format(t('scm.discardConfirmUntracked'), { count: discardTargets.length })\n : format(t('scm.discardConfirmTracked'), { count: discardTargets.length })}\n confirmLabel={t('common.delete')}\n danger\n onConfirm={confirmDiscard}\n onCancel={() => setDiscardTargets(null)}\n />\n )}\n </div>\n )\n}\n\n/** One change group (staged / unstaged / untracked) with list or tree body. */\nfunction Group({\n scm,\n preview,\n rows,\n title,\n bulkLabel,\n onBulk,\n onDiscard,\n}: {\n scm: PanelStores['scm']\n preview: PanelStores['preview']\n rows: GitChangeRow[]\n title?: string\n bulkLabel: string\n onBulk: (rows: GitChangeRow[]) => void\n onDiscard: (rows: GitChangeRow[]) => void\n}): JSX.Element {\n const state = useStore(scm)\n const tree = useMemo(() => buildTree(rows), [rows])\n const viewTree = state.viewMode === 'tree'\n const allActionable = rows.filter((row) => row.state !== 'conflicted')\n // O(1) lookups for row rendering: an includes() per row per array is\n // O(rows x ops) on every batch operation.\n const busySet = useMemo(() => new Set(state.busy), [state.busy])\n const failedSet = useMemo(() => new Set(state.failed), [state.failed])\n const expandedSet = useMemo(() => new Set(state.treeExpanded), [state.treeExpanded])\n\n return (\n <div>\n {title !== undefined && (\n <div className={scmCss.groupTitle}>\n {title}\n <button\n type=\"button\"\n className={scmCss.groupAction}\n title={bulkLabel}\n onClick={() => onBulk(allActionable)}\n disabled={allActionable.length === 0}\n >\n {bulkLabel === t('scm.unstage') ? <MinusIcon size={12} /> : <PlusIcon size={12} />}\n </button>\n </div>\n )}\n {viewTree ? (\n [...tree.entries()].map(([dir, dirRows]) => (\n <DirNode\n key={dir === '' ? '\\u0000' : dir}\n dir={dir}\n rows={dirRows}\n depth={0}\n state={state}\n expandedSet={expandedSet}\n busySet={busySet}\n failedSet={failedSet}\n scm={scm}\n preview={preview}\n onDiscard={onDiscard}\n />\n ))\n ) : (\n rows.map((row) => (\n <ChangeRow\n key={`${row.staged ? 's' : 'u'}:${row.path}`}\n row={row}\n state={state}\n busy={busySet.has(row.path)}\n failed={failedSet.has(row.path)}\n scm={scm}\n preview={preview}\n onDiscard={onDiscard}\n />\n ))\n )}\n </div>\n )\n}\n\n/** Tree-view directory node (expandable). */\nfunction DirNode({\n dir,\n rows,\n depth,\n state,\n expandedSet,\n busySet,\n failedSet,\n scm,\n preview,\n onDiscard,\n}: {\n dir: string\n rows: GitChangeRow[]\n depth: number\n state: ReturnType<PanelStores['scm']['getSnapshot']>\n expandedSet: ReadonlySet<string>\n busySet: ReadonlySet<string>\n failedSet: ReadonlySet<string>\n scm: PanelStores['scm']\n preview: PanelStores['preview']\n onDiscard: (rows: GitChangeRow[]) => void\n}): JSX.Element {\n const expanded = expandedSet.has(dir)\n const label = dir === '' ? '/' : dir.split('/').pop() ?? dir\n const toggleExpanded = (): void => {\n const next = expanded\n ? state.treeExpanded.filter((item) => item !== dir)\n : [...state.treeExpanded, dir]\n scm.setTreeExpanded(next)\n }\n return (\n <>\n <div\n className={scmCss.dirRow}\n style={{ paddingLeft: 12 + depth * 12 }}\n title={dir}\n role=\"button\"\n tabIndex={0}\n aria-expanded={expanded}\n onClick={toggleExpanded}\n onKeyDown={activateOnKey(toggleExpanded)}\n >\n <span className={`${scmCss.dirArrow}${expanded ? ` ${scmCss.dirArrowOpen}` : ''}`}>\n <ChevronRightIcon size={13} />\n </span>\n <FileTypeIcon name={label} isDir expanded={expanded} />\n <span style={{ fontSize: 13, color: 'var(--aion-text-primary)' }}>{label}</span>\n </div>\n {expanded &&\n rows.map((row) => (\n <ChangeRow\n key={`${row.staged ? 's' : 'u'}:${row.path}`}\n row={row}\n state={state}\n busy={busySet.has(row.path)}\n failed={failedSet.has(row.path)}\n scm={scm}\n preview={preview}\n onDiscard={onDiscard}\n indent={depth + 1}\n hideDir\n />\n ))}\n </>\n )\n}\n\n/** One change row: badge + name + dimmed dir + hover actions.\n * Clicking the row opens the path's diff in the preview panel (every state\n * has a diff — deleted rows show the removal, untracked rows a new-file diff).\n */\nfunction ChangeRow({\n row,\n state,\n busy,\n failed,\n scm,\n preview,\n onDiscard,\n indent = 0,\n hideDir = false,\n}: {\n row: GitChangeRow\n state: ReturnType<PanelStores['scm']['getSnapshot']>\n busy: boolean\n failed: boolean\n scm: PanelStores['scm']\n preview: PanelStores['preview']\n onDiscard: (rows: GitChangeRow[]) => void\n indent?: number\n hideDir?: boolean\n}): JSX.Element {\n const badge = BADGE[row.state] ?? BADGE.unknown\n const conflicted = row.state === 'conflicted'\n const displayName = row.oldPath !== undefined ? `${row.oldPath.split('/').pop()} -> ${row.path.split('/').pop()}` : (row.path.split('/').pop() ?? row.path)\n const dir = dirOf(row.path)\n\n const openInPreview = (): void => {\n scm.select(row.path)\n // Staged rows diff the index against HEAD; unstaged rows the worktree\n // against the index — the side the row was listed under.\n preview.openDiff(state.root, row.path, row.staged)\n }\n\n return (\n <div\n className={`${scmCss.changeRow}${state.selected === row.path ? ` ${scmCss.changeRowSelected}` : ''}${failed ? ` ${scmCss.rowFailed}` : ''}`}\n style={{ paddingLeft: 12 + indent * 12 }}\n title={row.path}\n onClick={openInPreview}\n onKeyDown={activateOnKey(openInPreview)}\n role=\"button\"\n tabIndex={0}\n >\n <span className={`${scmCss.badge} ${badge.className}`}>{badge.letter}</span>\n <span className={scmCss.changeName}>{displayName}</span>\n {!hideDir && dir !== '' && <span className={scmCss.changeDir}>{dir}</span>}\n <span className={`${scmCss.rowActions}${busy || failed ? ` ${scmCss.rowActionsVisible}` : ''}`}>\n {conflicted ? null : row.staged ? (\n <>\n <button\n type=\"button\"\n className={scmCss.rowAction}\n title={t('scm.unstage')}\n disabled={busy}\n onClick={(event) => { event.stopPropagation(); void scm.unstage([row.path]) }}\n >\n <MinusIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.rowAction}\n title={t('scm.discard')}\n disabled={busy}\n onClick={(event) => { event.stopPropagation(); onDiscard([row]) }}\n >\n <UndoIcon size={13} />\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n className={scmCss.rowAction}\n title={t('scm.stage')}\n disabled={busy}\n onClick={(event) => { event.stopPropagation(); void scm.stage([row.path]) }}\n >\n <PlusIcon size={13} />\n </button>\n <button\n type=\"button\"\n className={scmCss.rowAction}\n title={t('scm.discard')}\n disabled={busy}\n onClick={(event) => { event.stopPropagation(); onDiscard([row]) }}\n >\n <UndoIcon size={13} />\n </button>\n </>\n )}\n </span>\n </div>\n )\n}\n","/**\n * Pure drag-to-composer helpers shared by the explorer rows (the drag\n * source) and the composer dock inlay (the drop target): the custom MIME\n * type, the drag-state detector, and the draft-splicing rule. Deliberately\n * framework-free so the splicing math is unit-testable in isolation.\n *\n * The composer host only accepts OS image drops (its document-level drop\n * handler checks `dataTransfer.types` for `Files` and routes through the\n * image pipeline), so a workspace file needs its own MIME. A plain relative\n * path is inserted into the draft — the agent reads the file through its\n * existing tools without any prefix grammar.\n * @module dsh-filemgr/client/drag/file-drag\n */\n\n/** Custom MIME carrying a workspace-relative file path. */\nexport const FILE_DRAG_MIME = 'application/x-dsh-file'\n\n/**\n * Whether a drag event carries our file payload.\n * @param types - the live `dataTransfer.types` list (read-only during drag).\n * @returns true when our MIME is present.\n */\nexport function hasFileDrag(types: readonly string[] | undefined): boolean {\n return types !== undefined && types.includes(FILE_DRAG_MIME)\n}\n\n/**\n * Whether a drop payload is a plausible workspace-relative path. The custom\n * MIME only proves the drag carries *some* string — a foreign page can set it\n * too, so the payload itself is validated before it reaches the draft:\n * relative POSIX shape only; no absolute paths, no '..' segments, no\n * backslashes, no control characters, and a sane length.\n * @param path - the raw payload from dataTransfer.\n * @returns true when the payload is safe to splice into the draft.\n */\nexport function isValidFileDragPayload(path: string): boolean {\n if (path === '' || path.length > 512) return false\n if (path.startsWith('/') || path.includes('\\\\')) return false\n // eslint-disable-next-line no-control-regex\n if (/[\\x00-\\x1f\\x7f]/.test(path)) return false\n if (path.split('/').some(segment => segment === '..')) return false\n return true\n}\n\n/**\n * Splice a workspace-relative path into a composer draft at the caret.\n *\n * Separator rule: one space is added before the path unless the caret sits\n * at the start of the draft or right after whitespace; one space is added\n * after the path unless the caret sits at the end of the draft or right\n * before whitespace. Empty path or an out-of-range caret are no-ops.\n *\n * @param draft - the current draft text.\n * @param path - the relative path to insert.\n * @param caret - insertion offset (default: the end of the draft).\n * @returns the next draft; the caller owns writing it through the input\n * facade.\n */\nexport function insertPathIntoDraft(draft: string, path: string, caret?: number): string {\n if (path === '') return draft\n const at = caret === undefined ? draft.length : Math.min(Math.max(caret, 0), draft.length)\n const before = draft.slice(0, at)\n const after = draft.slice(at)\n const needBefore = before !== '' && !/\\s$/.test(before)\n const needAfter = after !== '' && !/^\\s/.test(after)\n return before + (needBefore ? ' ' : '') + path + (needAfter ? ' ' : '') + after\n}\n","/**\n * The Explorer column: Files/Changes tab bar (37px), the persistent filename\n * search at the top of the Files tab (150ms debounced; a hit click REVEALS\n * the file in the tree — expand ancestors + select — never opens preview),\n * the lazy file tree (34px rows, full-row expand/collapse, 16px icons), and\n * the in-column collapse chevron.\n *\n * FileManager Explorer behavior (Apache-2.0, re-implemented): row click toggles\n * folders (no need to hit the arrow), search results are reveal-only, and\n * clicking a file opens it in the preview panel (dedup focuses the tab).\n * @module dsh-filemgr/client/components/ExplorerPanel\n */\n\nimport { memo, useCallback, useMemo, useRef, useState } from 'react'\nimport type { DragEvent, JSX, MouseEvent as ReactMouseEvent } from 'react'\nimport type { FsEntry } from '../../core/types.ts'\nimport { parentRel } from '../fileType.ts'\nimport { t } from '../locales.ts'\nimport { useStore } from '../hooks/useStore.ts'\nimport type { PanelStores } from '../store.ts'\nimport { FileTypeIcon } from './FileIcon.tsx'\nimport { ChevronRightIcon, CloseIcon, ExpandRightIcon, MaximizeIcon, RestoreIcon, SearchIcon } from './icons.tsx'\nimport { ConfirmDialog, ContextMenu, PromptDialog, toast, type MenuEntry, type MenuState } from './overlay.tsx'\nimport { ScmPanel } from './ScmPanel.tsx'\nimport { activateOnKey } from './a11y.ts'\nimport { FILE_DRAG_MIME } from '../drag/file-drag.ts'\nimport explorerCss from '../styles/explorer.module.css'\nimport '../styles/tokens.module.css'\n\n/** Row indent step per tree depth (px). */\nconst INDENT_STEP = 16\n\n/**\n * The whole explorer column content.\n * @param stores - the panel store bundle.\n * @param onToggleCollapse - collapse the column (host chrome).\n */\nexport function ExplorerPanel({\n stores,\n onToggleCollapse,\n onReference,\n}: {\n stores: PanelStores\n onToggleCollapse: () => void\n onReference: (path: string, isDir: boolean) => void\n}): JSX.Element {\n const state = useStore(stores.explorer)\n const layoutState = useStore(stores.layout)\n const maximizedExplorer = layoutState.maximized === 'explorer'\n const [searchFocus, setSearchFocus] = useState(false)\n const [menu, setMenu] = useState<MenuState | null>(null)\n const [prompt, setPrompt] = useState<{\n kind: 'rename' | 'newFile' | 'newFolder'\n targetRel: string\n initialValue: string\n } | null>(null)\n const [deleteTarget, setDeleteTarget] = useState<FsEntry | null>(null)\n\n /** Absolute path of one entry (root + rel), for copy/reveal. */\n const absolutePath = (entry: FsEntry): string => {\n const basePath = state.root.replace(/[\\\\/]+$/, '')\n const sep = state.root.includes('\\\\') ? '\\\\' : '/'\n return entry.path === '' ? basePath : `${basePath}${sep}${entry.path.split('/').join(sep)}`\n }\n\n const copyText = async (text: string): Promise<void> => {\n try {\n await navigator.clipboard.writeText(text)\n toast(t('common.copied'))\n } catch {\n toast(t('explorer.opFailed'))\n }\n }\n\n /**\n * Open the file-tree context menu. Stable across re-renders (useCallback\n * on root + stores) so the memoized tree rows do not re-render when the\n * panel state changes.\n */\n const openMenu = useCallback((event: ReactMouseEvent, entry: FsEntry): void => {\n event.preventDefault()\n event.stopPropagation()\n const explorerStore = stores.explorer\n explorerStore.select(entry.path)\n const parent = parentRel(entry.path)\n const createTarget = entry.isDir ? entry.path : parent\n const entries: MenuEntry[] = [\n {\n key: 'copy-path',\n label: t('explorer.menu.copyPath'),\n onSelect: () => void copyText(absolutePath(entry)),\n },\n {\n key: 'copy-name',\n label: t('explorer.menu.copyName'),\n onSelect: () => void copyText(entry.name),\n },\n { key: 'sep-1', label: '---' },\n {\n key: 'reveal',\n label: t('explorer.menu.reveal'),\n onSelect: () => {\n void explorerStore.revealInFileManager(entry.path).then((ok) => {\n if (!ok) toast(t('explorer.opFailed'))\n })\n },\n },\n ]\n if (!entry.isDir) {\n entries.push({\n key: 'open-with-default',\n label: t('explorer.menu.openWithDefault'),\n onSelect: () => {\n void explorerStore.openWithDefaultApp(entry.path).then((ok) => {\n if (!ok) toast(t('explorer.opFailed'))\n })\n },\n })\n }\n entries.push(\n { key: 'sep-2', label: '---' },\n {\n key: 'rename',\n label: t('explorer.menu.rename'),\n onSelect: () => setPrompt({ kind: 'rename', targetRel: entry.path, initialValue: entry.name }),\n },\n {\n key: 'new-file',\n label: t('explorer.menu.newFile'),\n onSelect: () => setPrompt({ kind: 'newFile', targetRel: createTarget, initialValue: '' }),\n },\n {\n key: 'new-folder',\n label: t('explorer.menu.newFolder'),\n onSelect: () => setPrompt({ kind: 'newFolder', targetRel: createTarget, initialValue: '' }),\n },\n { key: 'sep-3', label: '---' },\n {\n key: 'delete',\n label: t('explorer.menu.delete'),\n danger: true,\n onSelect: () => setDeleteTarget(entry),\n },\n )\n setMenu({ x: event.clientX, y: event.clientY, entries })\n }, [state.root, stores])\n\n const submitPrompt = (value: string): void => {\n if (prompt === null) return\n const { kind, targetRel } = prompt\n const name = value.trim()\n if (name === '') return\n const op = kind === 'rename'\n ? stores.explorer.renameEntry(prompt.targetRel, name)\n : kind === 'newFolder'\n ? stores.explorer.createDir(targetRel === '' ? name : `${targetRel}/${name}`)\n : stores.explorer.createFile(targetRel === '' ? name : `${targetRel}/${name}`)\n void op.then((ok) => {\n if (!ok) toast(t('explorer.opFailed'))\n })\n setPrompt(null)\n }\n\n return (\n <div className=\"filemgr-root\" style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>\n {/* The Files/Changes tab bar. */}\n <div className={explorerCss.tabBar}>\n <button\n type=\"button\"\n className={state.activeTab === 'files' ? explorerCss.tabBtnActive : explorerCss.tabBtn}\n onClick={() => stores.explorer.setActiveTab('files')}\n >\n {t('explorer.tabs.files')}\n </button>\n <button\n type=\"button\"\n className={state.activeTab === 'changes' ? explorerCss.tabBtnActive : explorerCss.tabBtn}\n onClick={() => stores.explorer.setActiveTab('changes')}\n >\n {t('explorer.tabs.changes')}\n </button>\n {/* Maximize/restore (issue #315): transient — the layout controller\n owns the grid takeover, Esc and the restore path. */}\n <button\n type=\"button\"\n className={explorerCss.tabIconBtn}\n style={{ marginLeft: 'auto' }}\n onClick={() => {\n stores.layout.update((prev) => ({ ...prev, maximized: maximizedExplorer ? null : 'explorer' }))\n }}\n title={t(maximizedExplorer ? 'explorer.restore' : 'explorer.maximize')}\n aria-label={t(maximizedExplorer ? 'explorer.restore' : 'explorer.maximize')}\n >\n {maximizedExplorer ? <RestoreIcon size={14} /> : <MaximizeIcon size={14} />}\n </button>\n <button\n type=\"button\"\n className=\"filemgr-collapse-chevron\"\n onClick={onToggleCollapse}\n title={t('explorer.collapse')}\n aria-label={t('explorer.collapse')}\n >\n <ExpandRightIcon size={16} />\n </button>\n </div>\n\n {/* Files tab: search + tree (kept mounted; hidden when changes is active). */}\n <div style={{ display: state.activeTab === 'files' ? 'flex' : 'none', flexDirection: 'column', flex: 1, minHeight: 0 }}>\n <SearchArea\n stores={stores}\n searchFocus={searchFocus}\n onFocusChange={setSearchFocus}\n />\n <FileTree stores={stores} onContextMenu={openMenu} onReference={onReference} />\n </div>\n\n {/* Changes tab: SCM (mounted on demand; its store outlives the tab). */}\n {state.activeTab === 'changes' && <ScmPanel stores={stores} />}\n\n {/* Right-click menu + dialogs (portaled). */}\n <ContextMenu state={menu} onClose={() => setMenu(null)} />\n {prompt !== null && (\n <PromptDialog\n title={t(prompt.kind === 'rename' ? 'explorer.rename.title' : prompt.kind === 'newFolder' ? 'explorer.newFolder.title' : 'explorer.newFile.title')}\n initialValue={prompt.initialValue}\n onConfirm={submitPrompt}\n onCancel={() => setPrompt(null)}\n />\n )}\n {deleteTarget !== null && (\n <ConfirmDialog\n title={t('explorer.deleteConfirmTitle')}\n body={t('explorer.deleteConfirmBody', { name: deleteTarget.name })}\n danger\n onConfirm={() => {\n const target = deleteTarget\n setDeleteTarget(null)\n void stores.explorer.deleteEntry(target.path).then((ok) => {\n if (!ok) toast(t('explorer.opFailed'))\n })\n }}\n onCancel={() => setDeleteTarget(null)}\n />\n )}\n </div>\n )\n}\n\n/** The search box + results (the tree stays mounted underneath). */\nfunction SearchArea({\n stores,\n searchFocus,\n onFocusChange,\n}: {\n stores: PanelStores\n searchFocus: boolean\n onFocusChange: (focused: boolean) => void\n}): JSX.Element {\n const explorer = stores.explorer\n const state = useStore(explorer)\n const search = state.search\n const active = search.query !== ''\n const inputRef = useRef<HTMLInputElement>(null)\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', minHeight: 0, flex: active ? 1 : undefined }}>\n <div className={explorerCss.searchArea}>\n <div\n className={`${explorerCss.searchBox}${searchFocus ? ` ${explorerCss.searchAreaFocus}` : ''}`}\n style={{ borderColor: searchFocus ? 'var(--aion-primary)' : undefined }}\n >\n <span className={explorerCss.searchIcon}><SearchIcon size={14} /></span>\n <input\n ref={inputRef}\n className={explorerCss.searchInput}\n value={search.query}\n placeholder={t('explorer.search.placeholder')}\n aria-label={t('explorer.search.placeholder')}\n onFocus={() => onFocusChange(true)}\n onBlur={() => onFocusChange(false)}\n onChange={(event) => explorer.setSearchQuery(event.target.value)}\n />\n {search.query !== '' && (\n <button\n type=\"button\"\n className={explorerCss.searchClear}\n onClick={() => { explorer.cancelSearch(); inputRef.current?.focus() }}\n aria-label={t('common.close')}\n >\n <CloseIcon size={12} />\n </button>\n )}\n </div>\n </div>\n\n {/* Result list replaces the tree while the query is active (the tree\n underneath stays mounted — subscriptions never thrash). */}\n {active ? (\n <SearchResults stores={stores} />\n ) : null}\n </div>\n )\n}\n\n/** The flat search-result stream (click = reveal in tree). */\nfunction SearchResults({ stores }: { stores: PanelStores }): JSX.Element {\n const explorer = stores.explorer\n const state = useStore(explorer)\n const search = state.search\n return (\n <div className={explorerCss.scrollArea}>\n {search.status === 'searching' && search.hits.length === 0 && (\n <div className={explorerCss.searchStatus}>{t('explorer.search.searching')}</div>\n )}\n {search.status === 'error' && <div className={explorerCss.searchStatus}>{t('explorer.search.error')}</div>}\n {search.status === 'done' && search.hits.length === 0 && (\n <div className={explorerCss.searchStatus}>{t('explorer.search.empty')}</div>\n )}\n {search.hits.map((hit) => (\n <div\n key={hit.path}\n className={explorerCss.resultRow}\n role=\"button\"\n tabIndex={0}\n title={hit.path}\n onClick={() => {\n // Reveal: expand the ancestor chain and select — not preview.\n explorer.reveal(hit.path)\n }}\n onKeyDown={activateOnKey(() => { explorer.reveal(hit.path) })}\n >\n <FileTypeIcon name={hit.name} isDir={hit.isDir} expanded={false} />\n <span className={explorerCss.resultName}>{hit.name}</span>\n <span className={explorerCss.resultPath}>{parentRel(hit.path)}</span>\n </div>\n ))}\n {search.truncated && search.hits.length > 0 && (\n <div className={explorerCss.searchStatus}>{t('explorer.search.truncated', { count: search.hits.length })}</div>\n )}\n </div>\n )\n}\n\n/** The lazy file tree. */\nfunction FileTree({\n stores,\n onContextMenu,\n onReference,\n}: {\n stores: PanelStores\n onContextMenu: (event: ReactMouseEvent, entry: FsEntry) => void\n onReference: (path: string, isDir: boolean) => void\n}): JSX.Element {\n const explorer = stores.explorer\n const preview = stores.preview\n const state = useStore(explorer)\n const root = state.root\n // One Set per expansion change: O(1) membership for rows, and the memo\n // comparator below can compare membership instead of array identity.\n // (Hooks precede the early returns below.)\n const expandedSet = useMemo(() => new Set(state.expanded), [state.expanded])\n\n if (root === '') return <div className={explorerCss.emptyState}>{t('explorer.tree.empty')}</div>\n const entries = state.dirs['']\n if (entries === undefined) {\n return <div className={explorerCss.searchStatus}>{t('scm.loading')}</div>\n }\n if (entries.length === 0) return <div className={explorerCss.emptyState}>{t('explorer.tree.empty')}</div>\n\n return (\n <div className={`${explorerCss.scrollArea} ${explorerCss.tree}`}>\n {entries.map((entry) => (\n <TreeRow\n key={entry.path}\n entry={entry}\n depth={0}\n expanded={expandedSet}\n selected={state.selected}\n dirs={state.dirs}\n root={state.root}\n stores={stores}\n onContextMenu={onContextMenu}\n onReference={onReference}\n />\n ))}\n </div>\n )\n}\n\n/** One tree row (recursive for children). */\nfunction TreeRowBase({\n entry,\n depth,\n expanded,\n selected,\n dirs,\n root,\n stores,\n onContextMenu,\n onReference,\n}: {\n entry: FsEntry\n depth: number\n expanded: ReadonlySet<string>\n selected: string | null\n dirs: Record<string, FsEntry[]>\n root: string\n stores: PanelStores\n onContextMenu: (event: ReactMouseEvent, entry: FsEntry) => void\n onReference: (path: string, isDir: boolean) => void\n}): JSX.Element {\n const explorer = stores.explorer\n const preview = stores.preview\n const isExpanded = expanded.has(entry.path)\n const isSelected = selected === entry.path\n const children = entry.isDir ? dirs[entry.path] : undefined\n const [draggingRow, setDraggingRow] = useState(false)\n\n const handleClick = (): void => {\n if (entry.isDir) {\n // Full-row expand/collapse toggle.\n explorer.toggleDir(entry.path)\n return\n }\n // A file: select + open in preview (dedup focuses the open tab).\n explorer.select(entry.path)\n preview.openFile(root, entry.path)\n }\n\n // Files are draggable into the composer (the drag MIME carries the\n // workspace-relative path); directory rows stay click-only.\n const onDragStart = (event: DragEvent): void => {\n if (entry.isDir) return\n event.dataTransfer.setData(FILE_DRAG_MIME, entry.path)\n event.dataTransfer.setData('text/plain', entry.path)\n event.dataTransfer.effectAllowed = 'copy'\n setDraggingRow(true)\n }\n const onDragEnd = (): void => {\n setDraggingRow(false)\n }\n\n return (\n <>\n <div\n className={`${explorerCss.treeRow}${isSelected ? ` ${explorerCss.treeRowSelected}` : ''}${draggingRow ? ` ${explorerCss.treeRowDragging}` : ''}`}\n style={{ paddingLeft: 12 + 8 + depth * INDENT_STEP }}\n onClick={handleClick}\n onKeyDown={activateOnKey(handleClick)}\n onContextMenu={(event) => onContextMenu(event, entry)}\n onDoubleClick={(event) => {\n // Double-click on a file: same as click (open). Folders: keep toggle.\n event.stopPropagation()\n }}\n draggable={!entry.isDir}\n onDragStart={onDragStart}\n onDragEnd={onDragEnd}\n role=\"button\"\n tabIndex={0}\n aria-expanded={entry.isDir ? isExpanded : undefined}\n title={entry.path}\n >\n {entry.isDir ? (\n <span className={`${explorerCss.treeArrow}${isExpanded ? ` ${explorerCss.treeArrowOpen}` : ''}`}>\n <ChevronRightIcon size={13} />\n </span>\n ) : (\n <span className={explorerCss.treeArrowEmpty} />\n )}\n <FileTypeIcon name={entry.name} isDir={entry.isDir} expanded={isExpanded} />\n <span className={explorerCss.treeName}>{entry.name}</span>\n <button\n type=\"button\"\n className={explorerCss.refBtn}\n title={t('explorer.refToInput')}\n aria-label={t('explorer.refToInput')}\n onClick={(event) => {\n // Insert a file-reference chip (or plain text for folders).\n event.stopPropagation()\n event.preventDefault()\n onReference(entry.path, entry.isDir)\n }}\n onMouseDown={(event) => event.stopPropagation()}\n >\n @\n </button>\n </div>\n {entry.isDir && isExpanded && children !== undefined && (\n <div>\n {children.map((child) => (\n <TreeRow\n key={child.path}\n entry={child}\n depth={depth + 1}\n expanded={expanded}\n selected={selected}\n dirs={dirs}\n root={root}\n stores={stores}\n onContextMenu={onContextMenu}\n onReference={onReference}\n />\n ))}\n </div>\n )}\n </>\n )\n}\n\n/**\n * A memoized tree row so the whole tree does not re-render on every explorer\n * state change (search keystrokes, tab switches, fs version bumps). The row\n * takes the `state` fields it actually reads as individual props — `expanded`,\n * `selected`, `dirs` — whose references only change when the corresponding\n * data changed, so the default shallow comparison skips rows whose own entry,\n * ancestor, expansion or selection are unaffected. A `dirs` re-fetch (an fs\n * event that relists the expanded dirs) still re-renders the rows under those\n * dirs — the unavoidable O(open-dirs) cost — but transient UI state no longer\n * invalidates the tree.\n */\nconst TreeRow = memo(TreeRowBase, (prev, next) =>\n // The expansion array gets a fresh identity on every toggle; what this row\n // actually reads is its own membership, so compare that instead of the\n // container — plus the other props by identity.\n prev.expanded.has(prev.entry.path) === next.expanded.has(next.entry.path)\n && prev.entry === next.entry\n && prev.depth === next.depth\n && prev.selected === next.selected\n && prev.dirs === next.dirs\n && prev.root === next.root\n && prev.stores === next.stores\n && prev.onContextMenu === next.onContextMenu\n && prev.onReference === next.onReference,\n)\n","/**\n * The preview tab strip: 36px bar, tabs capped at 180px (padding 0 10, gap 6,\n * 12px title), dirty dot (6px, primary), close glyph (16px box, 12px icon),\n * middle-click close, right-click menu (close left/right/others/all), the\n * 32px left/right overflow fade indicators (ResizeObserver + scroll), the\n * new-URL-tab plus, and the panel collapse button.\n * @module dsh-filemgr/client/preview/PreviewTabs\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport type { PreviewTabState } from '../store.ts'\nimport { t } from '../locales.ts'\nimport { CloseIcon, MaximizeIcon, PlusIcon, RestoreIcon, ShrinkIcon } from '../components/icons.tsx'\nimport { activateOnKey } from '../components/a11y.ts'\nimport previewCss from '../styles/preview.module.css'\n\n/** Tab width cap (FileManager measured). */\nexport const MAX_TAB_WIDTH_PX = 180\n/** Fade indicator width. */\nconst FADE_WIDTH = 32\n\n/** Left/right overflow state. */\nexport interface TabFadeState {\n left: boolean\n right: boolean\n}\n\n/** The tab strip. */\nexport function PreviewTabs({\n tabs,\n activeTabId,\n onSwitch,\n onClose,\n onContextMenu,\n onNewUrlTab,\n onClosePanel,\n maximized,\n onMaximize,\n}: {\n tabs: PreviewTabState[]\n activeTabId: string | null\n onSwitch: (id: string) => void\n onClose: (id: string) => void\n onContextMenu: (event: React.MouseEvent, tab: PreviewTabState) => void\n onNewUrlTab: () => void\n onClosePanel: () => void\n maximized: boolean\n onMaximize: () => void\n}): JSX.Element {\n const scrollRef = useRef<HTMLDivElement>(null)\n const [fade, setFade] = useState<TabFadeState>({ left: false, right: false })\n\n // Overflow fades: ResizeObserver + scroll listener, setState only on change.\n useEffect(() => {\n const el = scrollRef.current\n if (el === null) return\n const update = (): void => {\n const next = {\n left: el.scrollLeft > 1,\n right: el.scrollLeft + el.clientWidth < el.scrollWidth - 1,\n }\n setFade((prev) => (prev.left === next.left && prev.right === next.right ? prev : next))\n }\n const observer = new ResizeObserver(update)\n observer.observe(el)\n el.addEventListener('scroll', update, { passive: true })\n window.addEventListener('resize', update)\n update()\n return () => {\n observer.disconnect()\n el.removeEventListener('scroll', update)\n window.removeEventListener('resize', update)\n }\n }, [tabs.length])\n\n return (\n <div className={previewCss.tabBar}>\n <div ref={scrollRef} className={previewCss.tabScroll}>\n {tabs.length === 0 && <div className={previewCss.noTabs}>{t('preview.noTabs')}</div>}\n {tabs.map((tab) => (\n <div\n key={tab.id}\n className={`${previewCss.tab}${tab.id === activeTabId ? ` ${previewCss.tabActive}` : ` ${previewCss.tabInactive}`}`}\n style={{ maxWidth: MAX_TAB_WIDTH_PX }}\n role=\"button\"\n tabIndex={0}\n title={tab.path}\n aria-label={tab.title}\n onClick={() => onSwitch(tab.id)}\n onKeyDown={activateOnKey(() => { onSwitch(tab.id) })}\n onContextMenu={(event) => onContextMenu(event, tab)}\n onAuxClick={(event) => {\n if (event.button !== 1) return\n event.preventDefault()\n event.stopPropagation()\n onClose(tab.id)\n }}\n >\n <span className={previewCss.tabTitle} title={tab.path}>{tab.title}</span>\n {tab.dirty && <span className={previewCss.tabDotDirty} title={t('preview.dirty')} />}\n <span\n className={previewCss.tabClose}\n role=\"button\"\n tabIndex={0}\n title={t('common.close')}\n aria-label={t('common.close')}\n onClick={(event) => {\n event.stopPropagation()\n onClose(tab.id)\n }}\n onKeyDown={activateOnKey(() => { onClose(tab.id) })}\n >\n <CloseIcon size={12} />\n </span>\n </div>\n ))}\n <div\n className={previewCss.tabPlus}\n role=\"button\"\n tabIndex={0}\n onClick={onNewUrlTab}\n onKeyDown={activateOnKey(onNewUrlTab)}\n title={t('preview.newUrlTab')}\n >\n <PlusIcon size={14} />\n </div>\n </div>\n <div className={previewCss.tabBarRight}>\n {/* Maximize/restore (issue #315): the layout controller owns the grid\n takeover, Esc and the restore path. */}\n <div\n className={previewCss.panelMaximize}\n role=\"button\"\n tabIndex={0}\n onClick={onMaximize}\n onKeyDown={activateOnKey(onMaximize)}\n title={t(maximized ? 'preview.restore' : 'preview.maximize')}\n aria-label={t(maximized ? 'preview.restore' : 'preview.maximize')}\n >\n {maximized ? <RestoreIcon size={14} /> : <MaximizeIcon size={14} />}\n </div>\n <div\n className={previewCss.panelCollapse}\n role=\"button\"\n tabIndex={0}\n onClick={onClosePanel}\n onKeyDown={activateOnKey(onClosePanel)}\n title={t('preview.collapsePanel')}\n aria-label={t('preview.collapsePanel')}\n >\n <ShrinkIcon size={14} />\n </div>\n </div>\n {fade.left && <div className={previewCss.tabFadeLeft} style={{ width: FADE_WIDTH }} />}\n {fade.right && <div className={previewCss.tabFadeRight} style={{ width: FADE_WIDTH }} />}\n </div>\n )\n}\n","/**\n * The preview toolbar: 32px bar (padding 0 10). Left: source/preview toggle\n * (markdown/html), split-screen toggle (editable types), download. Right: the\n * refresh button (4-state: hidden/disabled/idle/updated — never a dead\n * button) and save (editable + dirty, Cmd/Ctrl+S too).\n * @module dsh-filemgr/client/preview/PreviewToolbar\n */\n\nimport type { JSX } from 'react'\nimport type { PreviewContentType } from '../../core/types.ts'\nimport { isEditableType } from '../fileType.ts'\nimport { t } from '../locales.ts'\nimport { CodeIcon, DownloadIcon, EyeIcon, RefreshIcon, SaveIcon, SplitIcon } from '../components/icons.tsx'\nimport previewCss from '../styles/preview.module.css'\n\n/** Refresh button states (FileManager's 4-state machine). */\nexport type RefreshState = 'hidden' | 'disabled' | 'idle' | 'updated'\n\n/** Derive the refresh state for one tab. */\nexport function refreshStateFor(\n contentType: PreviewContentType,\n hasContent: boolean,\n loading: boolean,\n updated: boolean,\n): RefreshState {\n // URL tabs reload their frame (cross-origin documents can only be\n // re-navigated to the tab's address, never reloaded in place).\n if (contentType === 'url') return 'idle'\n if (contentType === 'word' || contentType === 'excel'\n || contentType === 'ppt' || contentType === 'unsupported' || contentType === 'image') {\n return 'hidden'\n }\n if (!hasContent || loading) return 'disabled'\n return updated ? 'updated' : 'idle'\n}\n\n/** Download the current tab's content as a file. */\nexport function downloadTab(tab: { title: string; content: string | null; contentType: PreviewContentType }): void {\n if (tab.content === null) return\n const isDataUrl = tab.content.startsWith('data:')\n // Pdf tabs hold a same-origin raw-route URL: anchor it directly (the\n // download attribute forces a save), no blob copy needed.\n const isRouteUrl = tab.content.startsWith('/filemgr/raw')\n const href = isDataUrl || isRouteUrl\n ? tab.content\n : URL.createObjectURL(new Blob([tab.content], { type: 'text/plain;charset=utf-8' }))\n const anchor = document.createElement('a')\n anchor.href = href\n anchor.download = tab.title\n anchor.style.display = 'none'\n document.body.appendChild(anchor)\n anchor.click()\n anchor.remove()\n if (!isDataUrl && !isRouteUrl) setTimeout(() => URL.revokeObjectURL(href), 10_000)\n}\n\n/** The toolbar. */\nexport function PreviewToolbar({\n contentType,\n hasContent,\n loading,\n dirty,\n updated,\n viewMode,\n canToggleView,\n split,\n canSplit,\n onViewModeChange,\n onSplitChange,\n onRefresh,\n onSave,\n onDownload,\n}: {\n contentType: PreviewContentType\n hasContent: boolean\n loading: boolean\n dirty: boolean\n updated: boolean\n viewMode: 'source' | 'preview'\n canToggleView: boolean\n split: boolean\n canSplit: boolean\n onViewModeChange: (mode: 'source' | 'preview') => void\n onSplitChange: (split: boolean) => void\n onRefresh: () => void\n onSave: () => void\n onDownload: () => void\n}): JSX.Element {\n const refreshState = refreshStateFor(contentType, hasContent, loading, updated)\n const editable = isEditableType(contentType)\n\n return (\n <div className={previewCss.toolbar}>\n {canToggleView && (\n <>\n <button\n type=\"button\"\n className={`${previewCss.toolbarBtn}${viewMode === 'source' ? ` ${previewCss.toolbarBtnActive}` : ''}`}\n onClick={() => onViewModeChange('source')}\n >\n <CodeIcon size={13} />\n {t('preview.source')}\n </button>\n <button\n type=\"button\"\n className={`${previewCss.toolbarBtn}${viewMode === 'preview' ? ` ${previewCss.toolbarBtnActive}` : ''}`}\n onClick={() => onViewModeChange('preview')}\n >\n <EyeIcon size={13} />\n {t('preview.preview')}\n </button>\n </>\n )}\n {canSplit && (\n <button\n type=\"button\"\n className={`${previewCss.toolbarBtn}${split ? ` ${previewCss.toolbarBtnActive}` : ''}`}\n title={t('preview.split')}\n onClick={() => onSplitChange(!split)}\n >\n <SplitIcon size={13} />\n {t('preview.split')}\n </button>\n )}\n <button\n type=\"button\"\n className={previewCss.toolbarBtn}\n title={t('preview.download')}\n disabled={!hasContent}\n onClick={onDownload}\n >\n <DownloadIcon size={13} />\n </button>\n <span className={previewCss.toolbarSpacer} />\n {refreshState !== 'hidden' && (\n <button\n type=\"button\"\n className={`${previewCss.toolbarBtn}${refreshState === 'updated' ? ` ${previewCss.toolbarBtnWarn}` : ''}`}\n title={refreshState === 'updated' ? t('preview.refresh.updated') : t('preview.refresh')}\n disabled={refreshState === 'disabled'}\n onClick={onRefresh}\n >\n <RefreshIcon size={13} />\n {t('preview.refresh')}\n </button>\n )}\n {editable && dirty && (\n <button\n type=\"button\"\n className={previewCss.toolbarBtn}\n onClick={onSave}\n disabled={loading}\n >\n <SaveIcon size={13} />\n {t('preview.save')}\n </button>\n )}\n </div>\n )\n}\n","/**\n * The panel system's single drag engine hook — a thin React wrapper over the\n * framework-free machinery in drag.ts (FileManager's useResizableSplit\n * architecture, re-implemented): px or ratio units, range-validated\n * localStorage persistence, double-click reset to the default width.\n * @module dsh-filemgr/client/hooks/useResizableSplit\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PointerEvent as ReactPointerEvent } from 'react'\nimport { handlePointerDragStart } from '../drag.ts'\nimport { readStoredNumber, writeStoredNumber } from '../persist.ts'\n\nexport interface UseResizableSplitOptions {\n /** Default width (px or percent). */\n defaultWidth?: number\n /** Minimum (same unit). */\n minWidth?: number\n /** Maximum (same unit). */\n maxWidth?: number\n /** localStorage key (preference persistence). */\n storageKey?: string\n /** 'px' for fixed pixel widths, 'ratio' for percents (default 'ratio'). */\n unit?: 'px' | 'ratio'\n}\n\nexport interface DragHandleProps {\n onPointerDown: (event: ReactPointerEvent<HTMLDivElement>) => void\n onDoubleClick: () => void\n}\n\n/**\n * Resizable-split engine.\n * @param options - width contract + persistence key.\n * @returns current width, the committed setter, handle props, and the clamp.\n */\nexport function useResizableSplit(options: UseResizableSplitOptions = {}) {\n const {\n defaultWidth = 50,\n minWidth = 20,\n maxWidth = 80,\n storageKey,\n unit = 'ratio',\n } = options\n const isPx = unit === 'px'\n\n const [width, setWidthState] = useState(() =>\n storageKey === undefined\n ? defaultWidth\n : readStoredNumber(storageKey, minWidth, maxWidth, defaultWidth))\n\n // The pointer-down closure reads the width at drag START without rebinding.\n const widthRef = useRef(width)\n useEffect(() => {\n widthRef.current = width\n }, [width])\n\n /** The committed setter: state + storage (validated) + resize event. */\n const setWidth = useCallback((value: number) => {\n setWidthState(value)\n if (storageKey !== undefined) writeStoredNumber(storageKey, value)\n try {\n window.dispatchEvent(new CustomEvent('preview-panel-resize', { detail: { width: value } }))\n } catch {\n // event dispatch is best-effort\n }\n }, [storageKey])\n\n const clamp = useCallback((value: number): number => {\n return Math.min(maxWidth, Math.max(minWidth, value))\n }, [minWidth, maxWidth])\n\n const handlePointerDown = useCallback((event: ReactPointerEvent<HTMLDivElement>) => {\n const el = event.currentTarget as HTMLDivElement\n handlePointerDragStart(event.nativeEvent, el, {\n reverse: el.dataset.reverse === 'true',\n getStartWidth: () => widthRef.current,\n compute: (startWidth, deltaX) => clamp(startWidth + deltaX),\n onFrame: (value) => setWidthState(value),\n onEnd: (value) => setWidth(value),\n })\n }, [clamp, setWidth])\n\n const handleDoubleClick = useCallback(() => {\n setWidth(defaultWidth)\n }, [defaultWidth, setWidth])\n\n const handleProps: DragHandleProps = { onPointerDown: handlePointerDown, onDoubleClick: handleDoubleClick }\n\n return { width, setWidth, handleProps, clamp, isPx }\n}\n","/**\n * A compact markdown renderer for the preview panel: headings, paragraphs,\n * fenced + inline code, bold/italic, links/images, lists, blockquotes, hr,\n * and tables. All HTML is escaped before transformation — the output only\n * ever contains the renderer's own tags. Pure and exported for tests.\n * @module dsh-filemgr/client/preview/markdown\n */\n\n/** Escape HTML special characters. */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\n/** How one image src resolves against the markdown file's location. */\nexport type MarkdownImageResolution =\n /** Scheme URL or fragment: the browser resolves it as-is. */\n | { kind: 'absolute' }\n /** Workspace-relative target: resolved path plus any ?query#fragment suffix. */\n | { kind: 'relative'; path: string; suffix: string }\n /** `..` escaped the project root: the image must be dropped. */\n | { kind: 'escape' }\n\n/** Directory of a workspace-relative file path ('' when at the root). */\nfunction dirOf(filePath: string): string {\n const slash = filePath.lastIndexOf('/')\n return slash === -1 ? '' : filePath.slice(0, slash)\n}\n\n/** Collapse . and .. segments; null when .. escapes the base. */\nfunction normalizeRelPath(rel: string): string | null {\n const out: string[] = []\n for (const part of rel.split('/')) {\n if (part === '' || part === '.') continue\n if (part === '..') {\n if (out.length === 0) return null\n out.pop()\n continue\n }\n out.push(part)\n }\n return out.join('/')\n}\n\n/** Percent-decode a path portion (best effort; never throws). */\nfunction decodePathPart(raw: string): string {\n try {\n return decodeURIComponent(raw)\n } catch {\n return raw\n }\n}\n\n/**\n * Resolve one markdown image src against the markdown file's location:\n * - Absolute URLs (http/https/data:/...) and fragment-only srcs are left to\n * the browser ('absolute').\n * - Root-relative srcs (/img.png) resolve from the project root; other\n * relative srcs resolve against the file's directory. `..` escaping the\n * project root is rejected ('escape').\n * - The path portion is percent-decoded (markdown authors encode spaces in\n * filenames) and any ?query#fragment suffix is preserved verbatim, so\n * cache-busting srcs like ./img.png?v=2 still fetch img.png.\n */\nexport function resolveMarkdownImage(filePath: string, src: string): MarkdownImageResolution {\n const trimmed = src.trim()\n if (trimmed === '' || trimmed.startsWith('#')) return { kind: 'absolute' }\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return { kind: 'absolute' }\n const decoded = decodePathPart(trimmed)\n const q = decoded.indexOf('?')\n const h = decoded.indexOf('#')\n let cut = decoded.length\n if (q !== -1) cut = Math.min(cut, q)\n if (h !== -1) cut = Math.min(cut, h)\n const pathPart = decoded.slice(0, cut)\n const suffix = decoded.slice(cut)\n const base = pathPart.startsWith('/') ? '' : dirOf(filePath)\n const joined = base === '' ? pathPart : `${base}/${pathPart}`\n const normalized = normalizeRelPath(joined)\n if (normalized === null) return { kind: 'escape' }\n return { kind: 'relative', path: normalized, suffix }\n}\n\n/** Options controlling markdown rendering. */\nexport interface MarkdownRenderOptions {\n /**\n * Rewrite image srcs before they are emitted. Return the URL to use, or\n * null to drop the image (alt text only). Relative workspace paths are\n * typically resolved to absolute URLs here.\n */\n resolveImageSrc?: (src: string) => string | null\n}\n\n/**\n * Guard a raw link/image target against dangerous protocols. Returns the\n * (trimmed) raw string when safe, else null. Only these schemes are allowed:\n * http:, https:, mailto: and fragment anchors (#...). Scheme-less relative\n * paths (./ ../ / and plain filenames) pass through unchanged. Anything with\n * a scheme outside the allow-list — javascript:, data:, vbscript:, etc. —\n * is rejected so the value never reaches dangerouslySetInnerHTML.\n */\nexport function safeUrl(raw: string): string | null {\n const trimmed = raw.trim()\n if (trimmed === '') return null\n if (trimmed.startsWith('#')) return trimmed\n const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed)\n if (scheme === null) return trimmed\n const name = scheme[1].toLowerCase()\n return name === 'http' || name === 'https' || name === 'mailto' ? trimmed : null\n}\n\n/** Inline pass: code spans, bold, italic, images, links. */\nexport function renderInline(text: string, options?: MarkdownRenderOptions): string {\n let out = ''\n let i = 0\n const n = text.length\n while (i < n) {\n const char = text[i]\n // Fenced inline code first.\n if (char === '`') {\n const end = text.indexOf('`', i + 1)\n if (end !== -1) {\n out += `<code>${escapeHtml(text.slice(i + 1, end))}</code>`\n i = end + 1\n continue\n }\n }\n // Image ![alt](src)\n if (char === '!' && text[i + 1] === '[') {\n const close = text.indexOf('](', i + 2)\n if (close !== -1) {\n const parenEnd = text.indexOf(')', close + 2)\n if (parenEnd !== -1) {\n const alt = text.slice(i + 2, close)\n const src = text.slice(close + 2, parenEnd)\n const safe = safeUrl(src)\n if (safe === null) {\n // Unsafe image target: drop the img, keep the alt text.\n out += escapeHtml(alt)\n } else {\n let target: string | null = safe\n if (options?.resolveImageSrc !== undefined) {\n target = options.resolveImageSrc(safe)\n }\n if (target === null) {\n // The resolver dropped the image (unresolvable path): alt only.\n out += escapeHtml(alt)\n } else {\n const srcEsc = escapeHtml(target).replace(/\\s+/g, '%20')\n out += `<img alt=\"${escapeHtml(alt)}\" src=\"${srcEsc}\" />`\n }\n }\n i = parenEnd + 1\n continue\n }\n }\n }\n // Link [text](href)\n if (char === '[') {\n const close = text.indexOf('](', i + 1)\n if (close !== -1) {\n const parenEnd = text.indexOf(')', close + 2)\n if (parenEnd !== -1) {\n const label = text.slice(i + 1, close)\n const href = text.slice(close + 2, parenEnd)\n const safe = safeUrl(href)\n if (safe === null) {\n // Unsafe link target: render the label as plain text, no <a>.\n out += renderInline(label, options)\n } else {\n out += `<a href=\"${escapeHtml(safe)}\" target=\"_blank\" rel=\"noopener noreferrer\">${renderInline(label, options)}</a>`\n }\n i = parenEnd + 1\n continue\n }\n }\n }\n // Bold **text**\n if (char === '*' && text[i + 1] === '*') {\n const end = text.indexOf('**', i + 2)\n if (end !== -1) {\n out += `<strong>${renderInline(text.slice(i + 2, end), options)}</strong>`\n i = end + 2\n continue\n }\n }\n // Italic *text*\n if (char === '*' && text[i - 1] !== '*' && text[i + 1] !== '*') {\n const end = text.indexOf('*', i + 1)\n if (end !== -1 && text[end + 1] !== '*') {\n out += `<em>${renderInline(text.slice(i + 1, end), options)}</em>`\n i = end + 1\n continue\n }\n }\n // Strikethrough ~~text~~\n if (char === '~' && text[i + 1] === '~') {\n const end = text.indexOf('~~', i + 2)\n if (end !== -1) {\n out += `<del>${renderInline(text.slice(i + 2, end), options)}</del>`\n i = end + 2\n continue\n }\n }\n out += escapeHtml(char)\n i += 1\n }\n return out\n}\n\n/** Render a markdown document to HTML (block pass). */\nexport function renderMarkdown(source: string, options?: MarkdownRenderOptions): string {\n const lines = source.replace(/\\r\\n/g, '\\n').split('\\n')\n const out: string[] = []\n let i = 0\n const n = lines.length\n\n const flushParagraph = (buffer: string[]): void => {\n if (buffer.length === 0) return\n out.push(`<p>${renderInline(buffer.join(\"\\n\"), options)}</p>`)\n buffer.length = 0\n }\n\n let paragraph: string[] = []\n while (i < n) {\n const line = lines[i]\n\n // Fenced code block.\n const fence = /^```([\\w+-]*)\\s*$/.exec(line)\n if (fence !== null) {\n flushParagraph(paragraph)\n const lang = fence[1] ?? ''\n i += 1\n const code: string[] = []\n while (i < n && !/^```\\s*$/.test(lines[i])) {\n code.push(lines[i])\n i += 1\n }\n i += 1 // closing fence\n const langAttr = lang === '' ? '' : ` class=\"language-${escapeHtml(lang)}\"`\n out.push(`<pre${langAttr}><code>${escapeHtml(code.join('\\n'))}</code></pre>`)\n continue\n }\n\n // Heading.\n const heading = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (heading !== null) {\n flushParagraph(paragraph)\n const level = heading[1].length\n out.push(`<h${level}>${renderInline(heading[2] ?? '', options)}</h${level}>`)\n i += 1\n continue\n }\n\n // Horizontal rule.\n if (/^\\s*(---+|\\*\\*\\*+|___+)\\s*$/.test(line)) {\n flushParagraph(paragraph)\n out.push('<hr />')\n i += 1\n continue\n }\n\n // Table: header row then separator row.\n if (line.includes('|') && i + 1 < n && /^\\s*\\|?[\\s:|-]+\\|?\\s*$/.test(lines[i + 1]) && lines[i + 1].includes('-')) {\n flushParagraph(paragraph)\n const headerCells = splitTableRow(line)\n i += 2\n const rows: string[][] = []\n while (i < n && lines[i].includes('|')) {\n rows.push(splitTableRow(lines[i]))\n i += 1\n }\n out.push('<table>')\n out.push(`<thead><tr>${headerCells.map((cell) => `<th>${renderInline(cell, options)}</th>`).join('')}</tr></thead>`)\n if (rows.length > 0) {\n out.push(`<tbody>${rows.map((row) => `<tr>${row.map((cell) => `<td>${renderInline(cell, options)}</td>`).join('')}</tr>`).join('')}</tbody>`)\n }\n out.push('</table>')\n continue\n }\n\n // Blockquote (one level).\n const quote = /^>\\s?(.*)$/.exec(line)\n if (quote !== null) {\n flushParagraph(paragraph)\n const body: string[] = []\n while (i < n) {\n const q = /^>\\s?(.*)$/.exec(lines[i])\n if (q === null) break\n body.push(q[1] ?? '')\n i += 1\n }\n out.push(`<blockquote><p>${body.map((line) => renderInline(line, options)).join('<br />')}</p></blockquote>`)\n continue\n }\n\n // Unordered list.\n const ul = /^\\s*([-*+])\\s+(.*)$/.exec(line)\n if (ul !== null) {\n flushParagraph(paragraph)\n const items: string[] = []\n while (i < n) {\n const item = /^\\s*([-*+])\\s+(.*)$/.exec(lines[i])\n if (item === null) break\n items.push(`<li>${renderInline(item[2] ?? '', options)}</li>`)\n i += 1\n }\n out.push(`<ul>${items.join('')}</ul>`)\n continue\n }\n\n // Ordered list.\n const ol = /^\\s*\\d+[.)]\\s+(.*)$/.exec(line)\n if (ol !== null) {\n flushParagraph(paragraph)\n const items: string[] = []\n while (i < n) {\n const item = /^\\s*\\d+[.)]\\s+(.*)$/.exec(lines[i])\n if (item === null) break\n items.push(`<li>${renderInline(item[1] ?? '', options)}</li>`)\n i += 1\n }\n out.push(`<ol>${items.join('')}</ol>`)\n continue\n }\n\n // Blank line: flush the paragraph.\n if (line.trim() === '') {\n flushParagraph(paragraph)\n i += 1\n continue\n }\n\n paragraph.push(line)\n i += 1\n }\n flushParagraph(paragraph)\n return out.join('\\n')\n}\n\n/** Split one table row into cells (respecting the leading/trailing pipes). */\nfunction splitTableRow(line: string): string[] {\n const trimmed = line.trim()\n const inner = trimmed.startsWith('|') ? trimmed.slice(1) : trimmed\n const withoutTrailing = inner.endsWith('|') ? inner.slice(0, -1) : inner\n return withoutTrailing.split('|').map((cell) => cell.trim())\n}\n","/**\n * Mermaid diagram enhancement for markdown surfaces: lazily loads the\n * mermaid runtime from the host vendor route (same origin, no CDN), renders\n * every fenced ```mermaid code block in place, and re-renders on theme\n * flips. Framework-free so both the preview panel (React effect) and the\n * chat transcript observer can drive it over disjoint DOM scopes.\n *\n * Failure policy: any load/render failure leaves the original code block\n * untouched (or restores it verbatim); nothing here throws to the caller.\n * @module dsh-filemgr/client/preview/mermaid\n */\n\n/** Minimal structural type of the mermaid runtime this module consumes. */\ninterface MermaidRuntime {\n initialize: (config: Record<string, unknown>) => void\n render: (id: string, text: string, container?: HTMLElement) => Promise<{ svg: string }>\n}\n\n/** Host-served mermaid IIFE bundle (lib/assets/mermaid.min.js behind the route). */\nexport const MERMAID_VENDOR_URL = '/filemgr/vendor/mermaid.js'\n\n/** Lifecycle state stamped on diagram containers (`pending`/`rendering`/`done`). */\nconst DATA_STATE = 'data-mermaid-state'\n\n/** State stamped on a code block once its container exists (`claimed`). */\nconst DATA_CLAIMED = 'data-mermaid-claimed'\n\n/** The verbatim diagram source kept on the container for theme re-renders. */\nconst DATA_SOURCE = 'data-mermaid-source'\n\n/** Marker the preview viewer stamps on its own subtree (chat enhancement skips it). */\nexport const DATA_MD_SCOPE = 'data-filemgr-md-scope'\n\nlet loadPromise: Promise<MermaidRuntime> | undefined\n\n/**\n * Resolve the mermaid global left by the vendor IIFE bundle, or null while\n * absent. Narrow and defensive: the bundle is a third-party artifact.\n */\nfunction mermaidGlobal(): MermaidRuntime | null {\n const candidate = (globalThis as Record<string, unknown>).mermaid\n if (typeof candidate !== 'object' || candidate === null) return null\n const checked = candidate as Record<string, unknown>\n if (typeof checked.initialize !== 'function' || typeof checked.render !== 'function') return null\n return checked as unknown as MermaidRuntime\n}\n\n/**\n * Load the mermaid runtime once per page: injects a <script> for the host\n * vendor route and resolves with the runtime. Concurrent callers share one\n * injection; a failure clears the cache so a later surface can retry.\n */\nexport function loadMermaidLibrary(): Promise<MermaidRuntime> {\n const existing = mermaidGlobal()\n if (existing !== null) return Promise.resolve(existing)\n if (loadPromise !== undefined) return loadPromise\n loadPromise = new Promise<MermaidRuntime>((resolve, reject) => {\n const script = document.createElement('script')\n script.src = MERMAID_VENDOR_URL\n script.async = true\n script.onload = () => {\n const runtime = mermaidGlobal()\n if (runtime === null) {\n loadPromise = undefined\n reject(new Error('mermaid vendor script loaded but window.mermaid is missing'))\n return\n }\n resolve(runtime)\n }\n script.onerror = () => {\n loadPromise = undefined\n reject(new Error(`failed to load ${MERMAID_VENDOR_URL}`))\n }\n document.head.appendChild(script)\n })\n return loadPromise\n}\n\n/** Mermaid theme name for the shell theme marker (`default` or `dark`). */\nexport function mermaidTheme(isDark: boolean): 'default' | 'dark' {\n return isDark ? 'dark' : 'default'\n}\n\n/** Whether the shell currently carries the dark marker attribute. */\nexport function shellIsDark(): boolean {\n return document.body.hasAttribute('data-ds-dark-theme')\n}\n\n/** Monotonic id source for render calls (mermaid keys its <svg> by id). */\nlet renderSeq = 0\n\n/**\n * Configure the mermaid runtime for the current theme. Called once per\n * render batch (enhance or retheme), not per diagram, so a surface with\n * many diagrams initializes the runtime a single time.\n */\nfunction initializeRuntime(runtime: MermaidRuntime, theme: string): void {\n runtime.initialize({\n startOnLoad: false,\n theme,\n securityLevel: 'strict',\n fontFamily: '\"trebuchet ms\", verdana, arial, sans-serif',\n })\n}\n\n/** Render one diagram source to SVG with the already-initialized runtime. */\nasync function renderSvg(runtime: MermaidRuntime, source: string): Promise<string> {\n const { svg } = await runtime.render(`filemgr-mermaid-${(renderSeq += 1)}`, source)\n return svg\n}\n\n/** Disallowed elements removed from mermaid SVG output before innerHTML. */\nconst DISALLOWED_ELEMENTS = ['script', 'foreignObject', 'iframe', 'object', 'embed']\n\n/** Whether an attribute name is an { on* } event-handler (case-insensitive). */\nfunction isEventHandler(name: string): boolean {\n return /^on/i.test(name)\n}\n\n/** Whether an href/xlink:href value carries an executable javascript: URL. */\nfunction isDangerousHref(value: string): boolean {\n return /^javascript:/i.test(value.trim())\n}\n\n/**\n * Application-level defense-in-depth on top of mermaid's own strict-mode\n * escaping: parse the rendered SVG in a detached container, remove disallowed\n * elements and dangerous attributes, and return the serialized cleaned markup.\n * Throws when the input cannot be parsed as markup or still carries dangerous\n * raw tokens, so callers fall back to their failure path.\n */\nexport function sanitizeSvg(svg: string): string {\n const template = document.createElement('template')\n template.innerHTML = svg\n const root = template.content\n\n // Remove disallowed elements; loop because removals can expose nested ones.\n for (let found = true; found; ) {\n found = false\n for (const el of Array.from(root.querySelectorAll('*'))) {\n if (DISALLOWED_ELEMENTS.some((tag) => el.tagName.toLowerCase() === tag.toLowerCase())) {\n el.remove()\n found = true\n }\n }\n }\n\n // Strip event-handler attributes and javascript: hrefs from every element.\n for (const el of Array.from(root.querySelectorAll('*'))) {\n for (const attr of Array.from(el.attributes)) {\n if (isEventHandler(attr.name) || isDangerousHref(attr.value)) el.removeAttribute(attr.name)\n }\n }\n\n const cleaned = template.innerHTML\n const lower = cleaned.toLowerCase()\n if (lower.includes('<script') || lower.includes('javascript:')) {\n throw new Error('mermaid SVG still contains dangerous tokens after sanitization')\n }\n return cleaned\n}\n\n/**\n * Collect the still-unclaimed fenced mermaid code blocks under one scope.\n * Both shapes are found: the panel renderer's `pre.language-mermaid` and\n * the chat renderer's `pre > code.language-mermaid` (the claim always\n * targets the <pre>). Empty blocks and blocks another driver already\n * claimed are skipped. Pure (DOM-read only) so tests can drive it in jsdom.\n */\nexport function findMermaidCodeBlocks(scope: ParentNode): HTMLPreElement[] {\n const found: HTMLPreElement[] = []\n const seen = new Set<Element>()\n for (const el of Array.from(scope.querySelectorAll('pre.language-mermaid, code.language-mermaid'))) {\n const pre = el instanceof HTMLPreElement ? el : el.parentElement\n if (pre === null || !(pre instanceof HTMLPreElement)) continue\n if (seen.has(pre)) continue\n seen.add(pre)\n if (pre.hasAttribute(DATA_CLAIMED)) continue\n if ((pre.textContent ?? '').trim() === '') continue\n found.push(pre)\n }\n return found\n}\n\n/**\n * Swap one code block for a diagram container. The original <pre> stays in\n * the tree (hidden once the render lands) so a failure can restore it\n * verbatim; the container carries the source for theme re-renders.\n */\nfunction claimBlock(pre: HTMLPreElement, className: string): HTMLElement {\n pre.setAttribute(DATA_CLAIMED, '1')\n const container = document.createElement('div')\n container.className = className\n container.setAttribute(DATA_STATE, 'pending')\n container.setAttribute(DATA_SOURCE, pre.textContent ?? '')\n pre.insertAdjacentElement('afterend', container)\n return container\n}\n\n/** Options for {@link enhanceMermaidBlocks}. */\nexport interface EnhanceOptions {\n /** Class for the diagram container (a CSS module export). */\n className: string\n /** Resolved mermaid theme name. */\n theme: string\n /** Optional extra exclusion for scopes another driver owns. */\n skip?: (pre: HTMLPreElement) => boolean\n}\n\n/**\n * Render every unclaimed ```mermaid block under `scope` into an inline SVG\n * diagram. Idempotent per block across drivers (claimed blocks are skipped);\n * failures restore the original code block. Never rejects.\n */\nexport async function enhanceMermaidBlocks(scope: ParentNode, options: EnhanceOptions): Promise<void> {\n let runtime: MermaidRuntime\n try {\n runtime = await loadMermaidLibrary()\n } catch {\n return // no vendor route (asset missing): keep plain code blocks\n }\n initializeRuntime(runtime, options.theme)\n const jobs: Array<Promise<void>> = []\n for (const pre of findMermaidCodeBlocks(scope)) {\n if (options.skip?.(pre) === true) continue\n const container = claimBlock(pre, options.className)\n jobs.push((async () => {\n try {\n container.setAttribute(DATA_STATE, 'rendering')\n const source = container.getAttribute(DATA_SOURCE) ?? ''\n const svg = await renderSvg(runtime, source)\n container.innerHTML = sanitizeSvg(svg)\n container.setAttribute(DATA_STATE, 'done')\n pre.style.display = 'none'\n } catch {\n // Syntax error or render failure: restore the untouched code block.\n container.remove()\n pre.removeAttribute(DATA_CLAIMED)\n }\n })())\n }\n await Promise.all(jobs)\n}\n\n/**\n * Re-render every completed diagram container under `scope` after a theme\n * flip (stored sources re-render with the new theme). Containers not in the\n * `done` state are skipped; a failure keeps the previous render.\n */\nexport async function rethemeMermaidBlocks(scope: ParentNode, options: { theme: string }): Promise<void> {\n const runtime = mermaidGlobal()\n if (runtime === null) return\n initializeRuntime(runtime, options.theme)\n const containers = Array.from(scope.querySelectorAll<HTMLElement>('[data-mermaid-state=\"done\"]'))\n await Promise.all(containers.map(async (container) => {\n const source = container.getAttribute(DATA_SOURCE) ?? ''\n try {\n const svg = await renderSvg(runtime, source)\n container.innerHTML = sanitizeSvg(svg)\n } catch {\n // Keep the previous render; a theme flip must not blank diagrams.\n }\n }))\n}\n\n/**\n * One dark-marker watcher per surface: fires on body attribute flips so the\n * caller can retheme. Returns the disposer.\n */\nexport function watchShellTheme(onChange: (isDark: boolean) => void): () => void {\n const observer = new MutationObserver(() => { onChange(shellIsDark()) })\n observer.observe(document.body, { attributes: true, attributeFilter: ['data-ds-dark-theme'] })\n return () => { observer.disconnect() }\n}\n","/**\n * Preview content routing: the renderers for every content type plus the\n * split-screen editor|preview layout. View mode (source/preview) resets to\n * preview when the displayed FILE changes (keyed on path+type, not tab id —\n * FileManager contract), and the split ratio is persisted under\n * preview-panel-split-ratio with a 20..80 clamp.\n * @module dsh-filemgr/client/preview/content\n */\n\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport { CodeBlock } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PreviewTabState } from '../store.ts'\nimport { useResizableSplit } from '../hooks/useResizableSplit.ts'\nimport { t } from '../locales.ts'\nimport { renderMarkdown, resolveMarkdownImage } from './markdown.ts'\nimport {\n DATA_MD_SCOPE,\n enhanceMermaidBlocks,\n mermaidTheme,\n rethemeMermaidBlocks,\n shellIsDark,\n watchShellTheme,\n} from './mermaid.ts'\nimport previewCss from '../styles/preview.module.css'\n\n/** Split-ratio persistence key (FileManager contract). */\nexport const KEY_SPLIT_RATIO = 'preview-panel-split-ratio'\n\n/** The rendered content of one tab (viewMode/split are controlled by the panel). */\nexport function TabContent({\n tab,\n viewMode,\n split,\n onContentChange,\n onSave,\n}: {\n tab: PreviewTabState\n viewMode: 'source' | 'preview'\n split: boolean\n onContentChange: (content: string) => void\n onSave: () => void\n}): JSX.Element {\n if (tab.error !== null) {\n return <div className={previewCss.placeholder}>\n <div className={previewCss.placeholderTitle}>{tab.title}</div>\n <div className={previewCss.placeholderError}>{tab.error}</div>\n </div>\n }\n\n const editable = tab.contentType === 'markdown' || tab.contentType === 'html'\n || tab.contentType === 'code' || tab.contentType === 'csv' || tab.contentType === 'text'\n\n // Split screen: editable types only; editor | preview with a ratio handle.\n if (split && editable) {\n return (\n <SplitPane\n tab={tab}\n onContentChange={onContentChange}\n onSave={onSave}\n />\n )\n }\n\n return (\n <div className={previewCss.content}>\n {tab.truncated && tab.content !== null && (\n <div className={previewCss.truncatedNote}>{t('preview.errorOversized')}</div>\n )}\n {tab.contentType === 'markdown' && tab.content !== null && (\n <MarkdownViewer\n content={tab.content}\n root={tab.root}\n path={tab.path}\n sourceMode={viewMode === 'source'}\n onContentChange={onContentChange}\n />\n )}\n {tab.contentType === 'html' && tab.content !== null && (\n <HtmlViewer\n content={tab.content}\n sourceMode={viewMode === 'source'}\n onContentChange={onContentChange}\n />\n )}\n {(tab.contentType === 'code' || tab.contentType === 'text') && tab.content !== null && (\n <CodeViewer content={tab.content} language={tab.title.split('.').pop() ?? ''} />\n )}\n {tab.contentType === 'csv' && tab.content !== null && <CsvViewer content={tab.content} />}\n {tab.contentType === 'diff' && tab.content !== null && <DiffViewer content={tab.content} />}\n {tab.contentType === 'image' && tab.content !== null && (\n <ImageViewer src={tab.content} meta={`${tab.image?.width ?? ''}${tab.image ? ' x ' : ''}${tab.image?.height ?? ''}`} />\n )}\n {tab.contentType === 'pdf' && tab.content !== null && <PdfViewer dataUrl={tab.content} title={tab.title} />}\n {tab.contentType === 'url' && <UrlViewer tab={tab} />}\n {(tab.contentType === 'word' || tab.contentType === 'excel' || tab.contentType === 'ppt' || tab.contentType === 'unsupported') && (\n <UnsupportedViewer tab={tab} />\n )}\n {tab.content === null && !tab.loading && (\n <div className={previewCss.placeholder}>\n <div className={previewCss.placeholderTitle}>{tab.title}</div>\n <div className={previewCss.placeholderMeta}>{t('preview.downloadHint')}</div>\n </div>\n )}\n {tab.loading && <div className={previewCss.placeholder}>{t('scm.loading')}</div>}\n </div>\n )\n}\n\n/** Split screen: textarea editor | rendered preview, ratio persisted. */\nfunction SplitPane({\n tab,\n onContentChange,\n onSave,\n}: {\n tab: PreviewTabState\n onContentChange: (content: string) => void\n onSave: () => void\n}): JSX.Element {\n const { width: splitRatio, handleProps } = useResizableSplit({\n unit: 'ratio',\n defaultWidth: 50,\n minWidth: 20,\n maxWidth: 80,\n storageKey: KEY_SPLIT_RATIO,\n })\n const content = tab.content ?? ''\n\n return (\n <div className={previewCss.splitPane}>\n <div className={previewCss.splitPaneLeft} style={{ width: `${splitRatio}%` }}>\n <div className={previewCss.splitHeader}>{t('preview.editor')}</div>\n <div className={previewCss.splitBody}>\n <textarea\n className={previewCss.textEditor}\n value={content}\n spellCheck={false}\n onChange={(event) => onContentChange(event.target.value)}\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 's') {\n event.preventDefault()\n onSave()\n }\n }}\n />\n </div>\n </div>\n <div\n className={previewCss.splitHandle}\n data-reverse=\"false\"\n style={{ left: `calc(${splitRatio}% - 6px)` }}\n {...handleProps}\n />\n <div className={previewCss.splitPaneRight} style={{ width: `${100 - splitRatio}%` }}>\n <div className={previewCss.splitHeader}>{t('preview.preview')}</div>\n <div className={previewCss.splitBody}>\n {tab.contentType === 'markdown' && <MarkdownViewer content={content} root={tab.root} path={tab.path} />}\n {tab.contentType === 'html' && <HtmlViewer content={content} />}\n {tab.contentType === 'csv' && <CsvViewer content={content} />}\n {tab.contentType === 'code' && <CodeViewer content={content} language={tab.title.split('.').pop() ?? ''} />}\n </div>\n </div>\n </div>\n )\n}\n\n/** Markdown viewer with an optional source mode (textarea). */\nfunction MarkdownViewer({\n content,\n root,\n path,\n sourceMode = false,\n onContentChange,\n}: {\n content: string\n /** Project root of the markdown file (image srcs resolve against it). */\n root: string\n /** The markdown file's workspace-relative path (image dir base). */\n path: string\n sourceMode?: boolean\n onContentChange?: (content: string) => void\n}): JSX.Element {\n const resolveImageSrc = useCallback((src: string): string | null => {\n if (root === '' || path === '') return null\n const resolution = resolveMarkdownImage(path, src)\n if (resolution.kind === 'absolute') return src\n if (resolution.kind === 'escape') return null\n // Workspace-relative target: serve the bytes through the host raw route\n // (same origin as the GUI), preserving any ?query#fragment suffix.\n return `/filemgr/raw?root=${encodeURIComponent(root)}&path=${encodeURIComponent(resolution.path)}${resolution.suffix}`\n }, [root, path])\n const html = useMemo(\n () => renderMarkdown(content, { resolveImageSrc }),\n [content, resolveImageSrc],\n )\n if (sourceMode && onContentChange !== undefined) {\n return (\n <div className={previewCss.content}>\n <textarea\n className={previewCss.textEditor}\n value={content}\n spellCheck={false}\n onChange={(event) => onContentChange(event.target.value)}\n />\n </div>\n )\n }\n return <MermaidAwareMarkdown html={html} />\n}\n\n/**\n * Rendered markdown body plus the mermaid enhancement lifecycle: fresh\n * blocks render once per html, completed diagrams re-render on shell theme\n * flips. The scope marker lets the chat-transcript enhancer skip this\n * subtree (each surface owns its blocks).\n */\nfunction MermaidAwareMarkdown({ html }: { html: string }): JSX.Element {\n const ref = useRef<HTMLDivElement | null>(null)\n useEffect(() => {\n const el = ref.current\n if (el === null) return undefined\n void enhanceMermaidBlocks(el, { className: previewCss.mermaidBlock, theme: mermaidTheme(shellIsDark()) })\n return watchShellTheme((isDark) => {\n void rethemeMermaidBlocks(el, { theme: mermaidTheme(isDark) })\n })\n }, [html])\n return (\n <div\n ref={ref}\n className={previewCss.mdViewer}\n {...{ [DATA_MD_SCOPE]: '1' }}\n dangerouslySetInnerHTML={{ __html: html }}\n />\n )\n}\n\n/** HTML viewer: sandboxed iframe (scripts off) or source textarea. */\nfunction HtmlViewer({\n content,\n sourceMode = false,\n onContentChange,\n}: {\n content: string\n sourceMode?: boolean\n onContentChange?: (content: string) => void\n}): JSX.Element {\n const srcDoc = useMemo(() => {\n // Base styles so the embedded page inherits the theme background.\n return `<!doctype html><html><head><meta charset=\"utf-8\"><style>body{margin:0;font-family:-apple-system,\"system-ui\",\"Segoe UI\",Roboto,\"PingFang SC\",sans-serif;color:#1d2129}@media (prefers-color-scheme:dark){body{color:rgba(255,255,255,0.9)}}</style></head><body>${content}</body></html>`\n }, [content])\n if (sourceMode && onContentChange !== undefined) {\n return (\n <div className={previewCss.content}>\n <textarea\n className={previewCss.textEditor}\n value={content}\n spellCheck={false}\n onChange={(event) => onContentChange(event.target.value)}\n />\n </div>\n )\n }\n return <iframe className={previewCss.pdfViewer} srcDoc={srcDoc} sandbox=\"\" title=\"html preview\" />\n}\n\n/**\n * Syntax-highlighted code/text viewer (official shiki core via CodeBlock),\n * wrapped in a line-number gutter.\n *\n * Alignment strategy: instead of trusting CSS to mirror the code block's\n * internal metrics (its language banner, `pre` padding and line-height are\n * owned by the primitives package), the gutter is measured against the live\n * `pre` — its top offset inside the shell (the banner's height) and its\n * computed line-height are read after render and applied as inline styles.\n * This keeps the numbers exactly on their lines regardless of the primitives'\n * internal layout. The trailing newline is not counted (CodeBlock trims it).\n */\nexport function CodeViewer({ content, language }: { content: string; language: string }): JSX.Element {\n const shellRef = useRef<HTMLDivElement | null>(null)\n const [gutterStyle, setGutterStyle] = useState<{ paddingTop: number; lineHeight: number } | null>(null)\n\n const lineCount = useMemo(() => {\n const trimmed = content.endsWith('\\n') ? content.slice(0, -1) : content\n return trimmed === '' ? 1 : trimmed.split('\\n').length\n }, [content])\n const numbers = useMemo(() => {\n const rows: number[] = []\n for (let i = 1; i <= lineCount; i += 1) rows.push(i)\n return rows\n }, [lineCount])\n\n // Measure the live `pre` and align the gutter (banner offset + line height).\n useEffect(() => {\n const shell = shellRef.current\n if (shell === null) return\n const measure = (): void => {\n const pre = shell.querySelector('pre')\n if (pre === null) {\n setGutterStyle(null)\n return\n }\n const shellRect = shell.getBoundingClientRect()\n const preRect = pre.getBoundingClientRect()\n const preStyle = getComputedStyle(pre)\n const lineHeight = parseFloat(preStyle.lineHeight)\n const padTop = parseFloat(preStyle.paddingTop)\n // First code line's top = pre's top offset (banner) + pre's own padding.\n const offsetTop = preRect.top - shellRect.top\n setGutterStyle({\n paddingTop: (Number.isFinite(offsetTop) ? offsetTop : 0) + (Number.isFinite(padTop) ? padTop : 0),\n lineHeight: Number.isFinite(lineHeight) ? lineHeight : 19.2,\n })\n }\n measure()\n // The shiki grammar loads asynchronously and re-renders the pre; watch for\n // structural changes and re-measure (line-height/padding rarely change,\n // but the banner's presence may settle late).\n const observer = new MutationObserver(measure)\n observer.observe(shell, { childList: true, subtree: true })\n return () => observer.disconnect()\n }, [content])\n\n return (\n <div className={previewCss.codeShell} ref={shellRef}>\n <div\n className={previewCss.lineGutter}\n aria-hidden=\"true\"\n style={gutterStyle !== null ? { paddingTop: gutterStyle.paddingTop } : undefined}\n >\n {numbers.map((number) => (\n <div\n key={number}\n className={previewCss.lineNo}\n style={gutterStyle !== null ? { height: gutterStyle.lineHeight, lineHeight: `${gutterStyle.lineHeight}px` } : undefined}\n >\n {number}\n </div>\n ))}\n </div>\n <div className={previewCss.codeBody}>\n <CodeBlock code={content} lang={language === '' ? undefined : language} className={previewCss.codeViewer} copyLabel={t('preview.copyCode')} copiedLabel={t('preview.copyCodeDone')} />\n </div>\n </div>\n )\n}\n\n/**\n * One memoized CSV row. The cells array reference is stable (it comes from the\n * memoized parsed rows), so an untouched row skips re-rendering when a sibling\n * cell changes or the panel re-renders for another reason.\n */\nconst CsvRow = memo(function CsvRow({ cells, isHeader }: { cells: string[]; isHeader: boolean }): JSX.Element {\n return (\n <tr>\n {cells.map((cell, cellIndex) => (\n isHeader ? <th key={cellIndex}>{cell}</th> : <td key={cellIndex}>{cell}</td>\n ))}\n </tr>\n )\n})\n\n/**\n * Stable, content-derived key for a CSV row. Rows have no ids, so the cell\n * content (JSON, occurrence-disambiguated for duplicates) anchors the key\n * instead of the array position — a reordered or shifted table keeps stable\n * React identities instead of reusing DOM nodes by index.\n * @param row - the raw row cells.\n * @param occurrence - how many identical rows were already keyed.\n */\nfunction csvRowKey(row: string[], occurrence: number): string {\n return `${JSON.stringify(row)}\\u0000${occurrence}`\n}\n\n/** CSV table. */\nfunction CsvViewer({ content }: { content: string }): JSX.Element {\n const rows = useMemo(() => parseCsv(content), [content])\n const keyedRows = useMemo(() => {\n const counts = new Map<string, number>()\n return rows.map((row) => {\n const seen = counts.get(JSON.stringify(row)) ?? 0\n counts.set(JSON.stringify(row), seen + 1)\n return { cells: row, key: csvRowKey(row, seen) }\n })\n }, [rows])\n return (\n <div className={previewCss.csvViewer}>\n <table className={previewCss.csvTable}>\n {keyedRows.map((entry, index) => (\n <CsvRow key={entry.key} cells={entry.cells} isHeader={index === 0} />\n ))}\n </table>\n </div>\n )\n}\n\n/** Parse CSV lines (quoted cells with escaped quotes). */\nexport function parseCsv(text: string): string[][] {\n const rows: string[][] = []\n let row: string[] = []\n let cell = ''\n let inQuotes = false\n for (let i = 0; i < text.length; i += 1) {\n const char = text[i]\n if (inQuotes) {\n if (char === '\"') {\n if (text[i + 1] === '\"') {\n cell += '\"'\n i += 1\n } else {\n inQuotes = false\n }\n } else {\n cell += char\n }\n continue\n }\n if (char === '\"') {\n inQuotes = true\n continue\n }\n if (char === ',') {\n row.push(cell)\n cell = ''\n continue\n }\n if (char === '\\n') {\n row.push(cell)\n rows.push(row)\n row = []\n cell = ''\n continue\n }\n if (char !== '\\r') cell += char\n }\n row.push(cell)\n if (row.length > 1 || row[0] !== '') rows.push(row)\n return rows\n}\n\n/** Unified diff viewer. */\nfunction DiffViewer({ content }: { content: string }): JSX.Element {\n const lines = content.split('\\n')\n return (\n <div className={previewCss.diffViewer}>\n {lines.map((line, index) => {\n let className = previewCss.diffLineMeta\n if (line.startsWith('+++') || line.startsWith('---') || line.startsWith('diff ') || line.startsWith('index ')) {\n className = previewCss.diffLineMeta\n } else if (line.startsWith('@@')) {\n className = previewCss.diffLineHunk\n } else if (line.startsWith('+')) {\n className = previewCss.diffLineAdd\n } else if (line.startsWith('-')) {\n className = previewCss.diffLineDel\n }\n return (\n <div key={index} className={className}>\n {line === '' ? ' ' : line}\n </div>\n )\n })}\n </div>\n )\n}\n\n/** Image viewer. */\nfunction ImageViewer({ src, meta }: { src: string; meta: string }): JSX.Element {\n return (\n <div className={previewCss.content}>\n <div className={previewCss.imageViewer}>\n <img src={src} alt=\"\" />\n </div>\n {meta.trim() !== '' && <div className={previewCss.imageMeta}>{meta}</div>}\n </div>\n )\n}\n\n/** PDF viewer: streamed route URL (iframe src) or a legacy data URL (blob). */\nfunction PdfViewer({ dataUrl, title }: { dataUrl: string; title: string }): JSX.Element {\n const [url, setUrl] = useState<string | null>(null)\n useEffect(() => {\n if (!dataUrl.startsWith('data:')) {\n // Same-origin /filemgr/raw URL: the iframe loads the stream\n // directly (mime application/pdf, no size cap, no base64 copy).\n setUrl(dataUrl === '' ? null : dataUrl)\n return\n }\n const blob = dataUrlToBlob(dataUrl)\n if (blob === null) {\n setUrl(null)\n return\n }\n const objectUrl = URL.createObjectURL(blob)\n setUrl(objectUrl)\n return () => URL.revokeObjectURL(objectUrl)\n }, [dataUrl])\n return url === null\n ? <div className={previewCss.placeholder}>{t('preview.unsupported')}</div>\n : <iframe className={previewCss.pdfViewer} src={url} title={title} />\n}\n\n/** Convert a data URL to a Blob (null on failure). */\nexport function dataUrlToBlob(dataUrl: string): Blob | null {\n const comma = dataUrl.indexOf(',')\n if (comma === -1) return null\n const meta = dataUrl.slice(0, comma)\n const mime = /data:([^;]+)/.exec(meta)?.[1] ?? 'application/octet-stream'\n try {\n const binary = atob(dataUrl.slice(comma + 1))\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i)\n return new Blob([bytes], { type: mime })\n } catch {\n return null\n }\n}\n\n/** URL tab: address bar + iframe. */\nfunction UrlViewer({ tab }: { tab: PreviewTabState }): JSX.Element {\n const [input, setInput] = useState(tab.content ?? '')\n const [url, setUrl] = useState(() => normalizeUrl(tab.content ?? ''))\n const frameRef = useRef<HTMLIFrameElement>(null)\n useEffect(() => {\n setInput(tab.content ?? '')\n setUrl(normalizeUrl(tab.content ?? ''))\n }, [tab.id, tab.content])\n\n // The frame is sandboxed WITH allow-popups: sites like bilibili hardcode\n // target=_blank on their nav links, so popups are permitted rather than\n // silently dropped. allow-same-origin is intentionally OMITTED, so the\n // embedded site runs in an OPAQUE origin: it cannot reach window.parent or\n // touch same-origin storage, which also means localStorage access inside\n // the frame throws. The load guard and normalizeUrl's same-origin block\n // remain as defense-in-depth for any frame that still lands on the GUI\n // origin.\n const guardFrameNavigation = (): void => {\n const frame = frameRef.current\n if (frame === null) return\n try {\n const href = frame.contentWindow?.location.href\n if (href !== undefined && !href.startsWith('about:') && new URL(href).origin === window.location.origin) {\n frame.src = 'about:blank'\n }\n } catch {\n // Cross-origin frame: nothing to guard.\n }\n }\n\n return (\n <div className={previewCss.content}>\n <div className={previewCss.urlBar}>\n <input\n className={previewCss.urlInput}\n value={input}\n placeholder={t('preview.url.placeholder')}\n spellCheck={false}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') setUrl(normalizeUrl(input))\n if (event.key === 'Escape') {\n setInput(tab.content ?? '')\n setUrl(normalizeUrl(tab.content ?? ''))\n }\n }}\n onFocus={(event) => event.currentTarget.select()}\n />\n </div>\n <iframe\n // Keyed on url + reloadNonce: a refresh (or a new address) remounts\n // the frame, which re-navigates it — cross-origin documents cannot\n // be reloaded in place from the parent, and re-setting the src\n // attribute does not re-navigate when the value is unchanged.\n key={`${url}\\u0000${tab.reloadNonce ?? 0}`}\n ref={frameRef}\n className={previewCss.urlFrame}\n src={url}\n title={tab.title}\n sandbox=\"allow-scripts allow-forms allow-popups\"\n allow=\"autoplay; fullscreen; picture-in-picture; encrypted-media; clipboard-write\"\n allowFullScreen\n onLoad={guardFrameNavigation}\n />\n </div>\n )\n}\n\n/** Bare domains get https://; whitespace queries go to a search engine. */\nexport function normalizeUrl(input: string): string {\n const trimmed = input.trim()\n if (trimmed === '') return 'about:blank'\n if (/\\s/.test(trimmed)) return `https://www.bing.com/search?q=${encodeURIComponent(trimmed)}`\n const candidate = /^https?:\\/\\//i.test(trimmed) ? trimmed : `https://${trimmed}`\n // Never embed a URL that points back at the harness host: the url frame\n // runs with allow-scripts + allow-same-origin, so a same-origin page there\n // could reach the shell document (the onLoad guard resets indirect\n // same-origin navigations, but a directly typed address must not land at\n // all). Degrade it instead.\n if (typeof window !== 'undefined') {\n try {\n if (new URL(candidate).origin === window.location.origin) return 'about:blank'\n } catch {\n // Malformed URL: fall through and return the best-effort candidate.\n }\n }\n return candidate\n}\n\n/** Office / unsupported placeholder. */\nfunction UnsupportedViewer({ tab }: { tab: PreviewTabState }): JSX.Element {\n return (\n <div className={previewCss.placeholder}>\n <div className={previewCss.placeholderTitle}>{tab.title}</div>\n <div className={previewCss.placeholderMeta}>{t('preview.unsupported')}</div>\n <div className={previewCss.placeholderMeta}>{t('preview.downloadHint')}</div>\n </div>\n )\n}\n","/**\n * Translate a text selection inside the preview into a file reference (path\n * plus start/end line). The selection must live inside a `<pre>` of a file-\n * backed preview (code / text / markdown source / diff); returns null for\n * anything else so the caller can hide the floating action.\n *\n * The reference carries only what the agent needs: the workspace-relative\n * path of the file and the 1-based line range. The selected text itself is\n * not copied into the composer — the agent re-reads the file at the line\n * range when the message is sent.\n * @module dsh-filemgr/client/preview/selection\n */\n\nimport type { PreviewTabState } from '../store.ts'\n\n/** The file-backed reference we surface from a preview selection. */\nexport interface FileReferenceSelection {\n path: string\n startLine: number\n endLine: number\n}\n\n/** Content types that map cleanly to line-based references. */\nconst LINE_BASED_CONTENT_TYPES: ReadonlySet<PreviewTabState['contentType']> = new Set([\n 'code',\n 'text',\n 'markdown', // markdown source-mode selection still maps to text lines\n 'diff',\n])\n\n/** Number the 1-based line of `offset` within `text` (counting newlines before it). */\nfunction lineOf(text: string, offset: number): number {\n const upto = text.length === 0 ? '' : text.slice(0, Math.max(0, Math.min(offset, text.length)))\n let line = 1\n for (let i = 0; i < upto.length; i += 1) {\n if (upto.charCodeAt(i) === 10) line += 1\n }\n return line\n}\n\n/** Return the character offset of (node, offset) measured from the start of `pre`. */\nfunction offsetInPre(pre: HTMLPreElement, node: Node | null, offset: number): number | null {\n if (node === null) return null\n try {\n const range = document.createRange()\n range.setStart(pre, 0)\n range.setEnd(node, offset)\n return range.toString().length\n } catch {\n // Cross-boundary nodes (e.g. detached text) raise; fall through.\n return null\n }\n}\n\n/**\n * Build a FileReferenceSelection from a browser selection if it points to a\n * supported preview's `<pre>`. Returns null otherwise (image / pdf / url /\n * non-line content, or a selection that lives outside any code block).\n */\nexport function findFileReferenceSelection(\n anchorElement: Element | null,\n selection: Selection,\n tab: PreviewTabState | null,\n): FileReferenceSelection | null {\n if (anchorElement === null) return null\n if (tab === null || tab.content === null) return null\n if (!LINE_BASED_CONTENT_TYPES.has(tab.contentType)) return null\n const pre = anchorElement.closest('pre') as HTMLPreElement | null\n if (pre === null) return null\n const startInPre = offsetInPre(pre, selection.anchorNode, selection.anchorOffset)\n const endInPre = offsetInPre(pre, selection.focusNode, selection.focusOffset)\n if (startInPre === null || endInPre === null) return null\n const start = Math.min(startInPre, endInPre)\n const end = Math.max(startInPre, endInPre)\n if (start === end) return null\n const text = pre.textContent ?? ''\n return {\n path: tab.path,\n startLine: lineOf(text, start),\n endLine: lineOf(text, end),\n }\n}\n","/**\n * The preview panel root: tab strip + toolbar + content router, the tab\n * context menu (close left/right/others/all), the dirty-close confirmation\n * (the single entry for every batch close — middle-click included), and the\n * panel collapse button. View mode and split live here so the toolbar and the\n * content share one source; both reset when the displayed file changes.\n * @module dsh-filemgr/client/preview/PreviewPanel\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport { isEditableType } from '../fileType.ts'\nimport { t, format } from '../locales.ts'\nimport { useStore } from '../hooks/useStore.ts'\nimport type { PanelStores, PreviewTabState } from '../store.ts'\nimport { ConfirmDialog, ContextMenu, type MenuState } from '../components/overlay.tsx'\nimport { PreviewTabs } from './PreviewTabs.tsx'\nimport { PreviewToolbar, downloadTab } from './PreviewToolbar.tsx'\nimport { TabContent } from './content.tsx'\nimport { findFileReferenceSelection, type FileReferenceSelection } from './selection.ts'\nimport previewCss from '../styles/preview.module.css'\n\n/** Coords + a fully-resolved file-reference payload (path + line range). */\ninterface AddToChatState {\n x: number\n y: number\n ref: FileReferenceSelection\n}\n\n/** The preview panel (mounted in the preview grid column). */\nexport function PreviewPanel({ stores, onAddFileReference }: { stores: PanelStores; onAddFileReference: (selection: FileReferenceSelection) => boolean }): JSX.Element {\n const preview = stores.preview\n const state = useStore(preview)\n const layoutState = useStore(stores.layout)\n const maximizedPreview = layoutState.maximized === 'preview'\n const [menu, setMenu] = useState<MenuState | null>(null)\n const [closingIds, setClosingIds] = useState<string[] | null>(null)\n const [viewMode, setViewMode] = useState<'source' | 'preview'>('preview')\n const [split, setSplit] = useState(false)\n const lastDirtyCheck = useRef<Set<string>>(new Set())\n const panelRef = useRef<HTMLDivElement | null>(null)\n\n /** The \"add selection to the composer\" floating action. */\n const [addToChat, setAddToChat] = useState<AddToChatState | null>(null)\n\n const activeTab = state.tabs.find((tab) => tab.id === state.activeTabId) ?? null\n\n // View mode resets to preview when the displayed FILE changes (path+type).\n const identity = activeTab === null ? '' : `${activeTab.path}\\u0000${activeTab.contentType}`\n useEffect(() => {\n setViewMode('preview')\n setSplit(false)\n }, [identity])\n\n // Selection → \"添加到对话\" floating action: a non-collapsed selection inside\n // a file-backed (code/text) preview is translated into a file reference\n // (path + start/end line) and surfaces a button under the selection.\n useEffect(() => {\n const onSelectionChange = (): void => {\n const selection = window.getSelection()\n if (selection === null || selection.isCollapsed || selection.rangeCount === 0) {\n setAddToChat(null)\n return\n }\n const node = selection.anchorNode\n const el = node instanceof Element ? node : node?.parentElement\n if (el === undefined || panelRef.current === null || !panelRef.current.contains(el)) {\n setAddToChat(null)\n return\n }\n const ref = findFileReferenceSelection(el, selection, activeTab)\n if (ref === null) {\n setAddToChat(null)\n return\n }\n const rect = selection.getRangeAt(0).getBoundingClientRect()\n setAddToChat({ x: rect.left, y: rect.bottom + 8, ref })\n }\n const onPointerDown = (event: MouseEvent): void => {\n if (addToChat === null) return\n const target = event.target as Element\n if (target.closest(`.${previewCss.addToChat}`) === null) setAddToChat(null)\n }\n document.addEventListener('selectionchange', onSelectionChange)\n document.addEventListener('mousedown', onPointerDown)\n return () => {\n document.removeEventListener('selectionchange', onSelectionChange)\n document.removeEventListener('mousedown', onPointerDown)\n }\n }, [addToChat, activeTab])\n\n const handleAddToChat = (): void => {\n if (addToChat === null) return\n if (onAddFileReference(addToChat.ref)) setAddToChat(null)\n }\n\n /** Close a batch; dirty tabs route through the confirmation first. */\n const requestClose = (ids: string[]): void => {\n const dirty = state.tabs.filter((tab) => ids.includes(tab.id) && tab.dirty)\n if (dirty.length === 0) {\n preview.closeTabs(ids)\n return\n }\n lastDirtyCheck.current = new Set(dirty.map((tab) => tab.id))\n setClosingIds(ids)\n }\n\n const closeMenuFor = (event: React.MouseEvent, tab: PreviewTabState): void => {\n event.preventDefault()\n event.stopPropagation()\n const index = state.tabs.findIndex((item) => item.id === tab.id)\n setMenu({\n x: event.clientX,\n y: event.clientY,\n entries: [\n {\n key: 'close-left',\n label: t('preview.closeLeft'),\n disabled: index <= 0,\n onSelect: () => requestClose(state.tabs.slice(0, index).map((item) => item.id)),\n },\n {\n key: 'close-right',\n label: t('preview.closeRight'),\n disabled: index >= state.tabs.length - 1,\n onSelect: () => requestClose(state.tabs.slice(index + 1).map((item) => item.id)),\n },\n { key: 'sep-1', label: '---', onSelect: () => {} },\n {\n key: 'close-others',\n label: t('preview.closeOthers'),\n disabled: state.tabs.length <= 1,\n onSelect: () => requestClose(state.tabs.filter((item) => item.id !== tab.id).map((item) => item.id)),\n },\n {\n key: 'close-all',\n label: t('preview.closeAll'),\n onSelect: () => requestClose(state.tabs.map((item) => item.id)),\n },\n ],\n })\n }\n\n /** A fresh url tab (empty address; the viewer owns the input). */\n const newUrlTab = (): void => {\n const stamp = Date.now()\n const tab: PreviewTabState = {\n id: `url:${stamp}`,\n title: 'new tab',\n root: state.root,\n path: `url:${stamp}`,\n contentType: 'url',\n content: '',\n dirty: false,\n updated: false,\n loading: false,\n truncated: false,\n error: null,\n savedAt: Date.now(),\n }\n preview.update((prev) => ({ ...prev, open: true, tabs: [...prev.tabs, tab], activeTabId: tab.id }))\n }\n\n return (\n <div ref={panelRef} className={`filemgr-root ${previewCss.panel}`}>\n <PreviewTabs\n tabs={state.tabs}\n activeTabId={state.activeTabId}\n onSwitch={(id) => preview.switchTab(id)}\n onClose={(id) => requestClose([id])}\n onContextMenu={closeMenuFor}\n onNewUrlTab={newUrlTab}\n onClosePanel={() => preview.setOpen(false)}\n maximized={maximizedPreview}\n onMaximize={() => {\n stores.layout.update((prev) => ({ ...prev, maximized: maximizedPreview ? null : 'preview' }))\n }}\n />\n {activeTab !== null && (\n <>\n <PreviewToolbar\n contentType={activeTab.contentType}\n hasContent={activeTab.content !== null}\n loading={activeTab.loading}\n dirty={activeTab.dirty}\n updated={activeTab.updated}\n viewMode={viewMode}\n canToggleView={activeTab.contentType === 'markdown' || activeTab.contentType === 'html'}\n split={split}\n canSplit={isEditableType(activeTab.contentType) && activeTab.content !== null}\n onViewModeChange={setViewMode}\n onSplitChange={setSplit}\n onRefresh={() => void preview.reloadTab(activeTab.id)}\n onSave={() => void preview.saveTab(activeTab.id)}\n onDownload={() => downloadTab(activeTab)}\n />\n <TabContent\n tab={activeTab}\n viewMode={viewMode}\n split={split}\n onContentChange={(content) => preview.updateContent(activeTab.id, content)}\n onSave={() => void preview.saveTab(activeTab.id)}\n />\n </>\n )}\n {menu !== null && <ContextMenu state={menu} onClose={() => setMenu(null)} />}\n {addToChat !== null && (\n <div\n className={previewCss.addToChat}\n style={{ left: addToChat.x, top: addToChat.y }}\n onClick={handleAddToChat}\n role=\"button\"\n tabIndex={-1}\n >\n 添加到对话\n </div>\n )}\n {closingIds !== null && (\n <ConfirmDialog\n title={t('preview.closeConfirmTitle')}\n body={format(t('preview.closeConfirmBody'), { count: lastDirtyCheck.current.size })}\n confirmLabel={t('common.close')}\n danger\n onConfirm={() => {\n preview.closeTabs(closingIds)\n setClosingIds(null)\n }}\n onCancel={() => setClosingIds(null)}\n />\n )}\n </div>\n )\n}\n","/**\n * DOM mounting: two React roots rendered into the panel columns the layout\n * controller appends to the frame grid. The roots wait for their columns\n * (the shell mounts asynchronously), and everything is wrapped so a DOM\n * failure degrades the panels, never the GUI boot.\n * @module dsh-filemgr/client/mount\n */\n\nimport { createRoot, type Root } from 'react-dom/client'\nimport type { PanelStores } from './store.ts'\nimport { ExplorerPanel } from './components/ExplorerPanel.tsx'\nimport { PreviewPanel } from './preview/PreviewPanel.tsx'\nimport type { FileReferenceSelection } from './preview/selection.ts'\n\nconst EXPLORER_COL_SELECTOR = '[data-filemgr-explorer-col]'\nconst PREVIEW_COL_SELECTOR = '[data-filemgr-preview-col]'\n\n/** Wait for one selector (the shell/frame mounts after boot settlement). */\nfunction waitForElement(selector: string, onFound: (el: HTMLElement) => void): () => void {\n let disposed = false\n let observer: MutationObserver | undefined\n const tryFind = (): void => {\n if (disposed) return\n const el = document.querySelector<HTMLElement>(selector)\n if (el !== null) {\n observer?.disconnect()\n onFound(el)\n }\n }\n observer = new MutationObserver(() => { tryFind() })\n observer.observe(document.body, { childList: true, subtree: true })\n tryFind()\n return () => {\n disposed = true\n observer?.disconnect()\n }\n}\n\n/**\n * Mount both panel roots.\n * @param stores - the panel store bundle.\n * @param onToggleExplorer - collapse toggle (owned by the layout controller).\n * @param onReference - insert a file-reference chip into the draft for a file\n * (the Explorer row @-reference button); folders should call a different\n * helper because the chip has no line concept for them.\n * @param onAddFileReference - insert a file-reference chip into the draft for\n * a preview selection (path + start/end line).\n * @returns a disposer unmounting both trees.\n */\nexport function mountPanels(\n stores: PanelStores,\n onToggleExplorer: () => void,\n onReference: (path: string, isDir: boolean) => void,\n onAddFileReference: (selection: FileReferenceSelection) => boolean,\n): () => void {\n let explorerRoot: Root | undefined\n let previewRoot: Root | undefined\n const disposers: Array<() => void> = []\n\n disposers.push(waitForElement(EXPLORER_COL_SELECTOR, (el) => {\n explorerRoot = createRoot(el)\n explorerRoot.render(<ExplorerPanel stores={stores} onToggleCollapse={onToggleExplorer} onReference={onReference} />)\n }))\n disposers.push(waitForElement(PREVIEW_COL_SELECTOR, (el) => {\n previewRoot = createRoot(el)\n previewRoot.render(<PreviewPanel stores={stores} onAddFileReference={onAddFileReference} />)\n }))\n\n return () => {\n for (const dispose of disposers) dispose()\n explorerRoot?.unmount()\n previewRoot?.unmount()\n }\n}\n","/**\n * Composer dock inlay: the drop target for explorer file drags. It mounts\n * in the official `conversation.input.dock` band (a session-scoped list\n * slot declared by the shipped ui-conversation rc.6 shell), so it stacks\n * with the git-graph chip above the composer card. While a file row is\n * dragged over the page it shows a hint strip; on drop it splices the\n * workspace-relative path into the active session's draft through the\n * conversation input facade.\n *\n * The document-level listeners only claim drags carrying our custom MIME —\n * the composer host's own drop handling (OS image files) is untouched. The\n * host's `dragover` refuses every drop it does not claim, so this inlay\n * must `preventDefault` its own drags to make the drop land.\n * @module dsh-filemgr/client/drag/DragFileInlay\n */\n\nimport { useEffect, useRef, useState, type ReactElement } from 'react'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { FILE_DRAG_MIME, hasFileDrag, isValidFileDragPayload } from './file-drag.ts'\nimport { t } from '../locales.ts'\nimport dragCss from '../styles/drag.module.css'\n\n/** Injected business face of the drag inlay (session-routed). */\nexport interface DragFileInjected {\n /** Splice a workspace-relative path into the active session's draft. */\n insertPath: (path: string) => boolean\n}\n\n/** Composed props: the dock's runtime share (sessionId) + the injected verb. */\nexport type DragFileInlayProps =\n PropsRuntime<'conversation.input.dock'>\n & DragFileInjected\n\n/**\n * The composer dock entry: a zero-height anchor that shows a hint strip\n * while a file row is dragged over the page and inserts the path on drop.\n * @param props - the composed dock entry props.\n */\nexport function DragFileInlay(props: DragFileInlayProps): ReactElement {\n const [active, setActive] = useState(false)\n const depth = useRef(0)\n\n useEffect(() => {\n const reset = (): void => {\n depth.current = 0\n setActive(false)\n }\n const onDragOver = (event: DragEvent): void => {\n if (!hasFileDrag(event.dataTransfer?.types)) return\n event.preventDefault()\n depth.current += 1\n setActive(true)\n }\n const onDragLeave = (event: DragEvent): void => {\n if (!hasFileDrag(event.dataTransfer?.types)) return\n depth.current = Math.max(0, depth.current - 1)\n if (depth.current === 0) setActive(false)\n }\n const onDrop = (event: DragEvent): void => {\n if (!hasFileDrag(event.dataTransfer?.types)) return\n event.preventDefault()\n const path = event.dataTransfer?.getData(FILE_DRAG_MIME) ?? ''\n reset()\n if (isValidFileDragPayload(path)) props.insertPath(path)\n }\n const onDragEnd = (): void => reset()\n document.addEventListener('dragover', onDragOver)\n document.addEventListener('dragleave', onDragLeave)\n document.addEventListener('drop', onDrop)\n window.addEventListener('dragend', onDragEnd)\n return () => {\n document.removeEventListener('dragover', onDragOver)\n document.removeEventListener('dragleave', onDragLeave)\n document.removeEventListener('drop', onDrop)\n window.removeEventListener('dragend', onDragEnd)\n }\n }, [props.insertPath])\n\n return (\n <div\n className={active ? `${dragCss.strip} ${dragCss.stripActive}` : dragCss.strip}\n data-testid=\"filemgr-drag-inlay\"\n aria-live=\"polite\"\n >\n {active ? <span className={dragCss.stripText}>{t('explorer.drag.dropHint')}</span> : null}\n </div>\n )\n}\n","/**\n * Chat-transcript mermaid enhancement: the core conversation renderer emits\n * fenced code as `pre > code.language-mermaid`, and the shell has no slot\n * for message-body post-processing — so this component rides the\n * conversation input dock as a zero-render sentinel and observes the\n * document for mermaid blocks the transcript mounts. Blocks inside the\n * preview panel's own subtree are excluded (each surface owns its blocks).\n *\n * Streaming awareness: an assistant message re-renders continuously, so a\n * diagram fence is often incomplete mid-stream. Renders that fail restore\n * the block and the next mutation retries it — once the fence closes the\n * diagram lands. Mutations are debounced to one rAF so long transcripts do\n * not re-scan the whole document: each batch is mapped to the minimal\n * mutated subtrees and scoped per-frame while the first scheduled pass scans\n * the body once. The observer is disconnected on unmount.\n * @module dsh-filemgr/client/chat/mermaid-chat\n */\n\nimport { useEffect } from 'react'\nimport type { JSX } from 'react'\nimport { DATA_MD_SCOPE, enhanceMermaidBlocks, mermaidTheme, rethemeMermaidBlocks, shellIsDark, watchShellTheme } from '../preview/mermaid.ts'\nimport previewCss from '../styles/preview.module.css'\n\n/**\n * Map a mutation batch to the minimal scan scopes that may contain new\n * mermaid fences. Each record contributes its target and its added nodes\n * (an added element directly; otherwise that node's parentElement), deduped\n * by identity. Disconnected nodes and removed-only records yield nothing —\n * removal never introduces a fence. Pure (DOM-read only) so tests can drive\n * it in jsdom.\n */\nexport function enhanceScopesFor(records: MutationRecord[]): Element[] {\n const scopes = new Set<Element>()\n for (const record of records) {\n // Removal-only batches do not introduce a fence: without additions the\n // target scan is wasted, so only records carrying added nodes contribute.\n if (record.addedNodes.length === 0) continue\n if (record.target instanceof Element && record.target.isConnected) {\n scopes.add(record.target)\n }\n for (const node of record.addedNodes) {\n const element = node instanceof Element ? node : node.parentElement\n if (element !== null && element.isConnected) scopes.add(element)\n }\n }\n return Array.from(scopes)\n}\n\n/** Hidden sentinel: renders nothing, owns the transcript observer. */\nexport function MermaidChatEnhancer(): JSX.Element | null {\n useEffect(() => {\n let scheduled = false\n let pendingFrame = 0\n let firstPass = true\n let pendingRecords: MutationRecord[] = []\n const run = (): void => {\n scheduled = false\n const records = pendingRecords\n pendingRecords = []\n const scopes = enhanceScopesFor(records)\n if (firstPass) {\n // First scheduled pass only: scan the whole document exactly once.\n // Later batches (even removal-only ones that yield no scopes) never\n // fall back to a full-body scan.\n firstPass = false\n void enhanceMermaidBlocks(document.body, {\n className: previewCss.mermaidBlock,\n theme: mermaidTheme(shellIsDark()),\n skip: (pre) => pre.closest(`[${DATA_MD_SCOPE}]`) !== null,\n })\n return\n }\n for (const scope of scopes) {\n void enhanceMermaidBlocks(scope, {\n className: previewCss.mermaidBlock,\n theme: mermaidTheme(shellIsDark()),\n skip: (pre) => pre.closest(`[${DATA_MD_SCOPE}]`) !== null,\n })\n }\n }\n const schedule = (): void => {\n if (scheduled) return\n scheduled = true\n pendingFrame = requestAnimationFrame(run)\n }\n const observer = new MutationObserver((records) => {\n pendingRecords = pendingRecords.concat(records)\n schedule()\n })\n observer.observe(document.body, { childList: true, subtree: true })\n schedule()\n const disposeTheme = watchShellTheme((isDark) => {\n void rethemeMermaidBlocks(document.body, { theme: mermaidTheme(isDark) })\n })\n return () => {\n observer.disconnect()\n disposeTheme()\n cancelAnimationFrame(pendingFrame)\n }\n }, [])\n return null\n}\n","/**\n * Composer placeholder hint: the shell owns the input-bar placeholder\n * (\"给智能体发消息\") and exposes no override seam (the composer bar is a\n * single slot owned by ui-conversation, and its locale namespace rejects\n * duplicate registration), so this zero-render sentinel — riding the same\n * `conversation.input.dock` band as the mermaid enhancer — rewrites the\n * placeholder attribute in the DOM. It re-applies on any placeholder\n * attribute change or node insert, which covers React re-renders that\n * reset the attribute to the shell default. English UI is left untouched\n * (exact-match on the Chinese string only).\n * @module dsh-filemgr/client/chat/placeholder-hint\n */\n\nimport { useEffect } from 'react'\nimport type { JSX } from 'react'\n\nconst OLD_PLACEHOLDER = '给智能体发消息'\nconst NEW_PLACEHOLDER = '给智能体发消息。@引用项目文件,/ 调用技能与指令'\n\n/** Rewrite every composer input whose placeholder matches the shell default. */\nfunction apply(): void {\n for (const el of document.querySelectorAll<HTMLTextAreaElement | HTMLInputElement>('textarea, input[type=\"text\"]')) {\n if (el.placeholder === OLD_PLACEHOLDER) el.placeholder = NEW_PLACEHOLDER\n }\n}\n\n/** Hidden sentinel: renders nothing, owns the placeholder rewriting observer. */\nexport function PlaceholderHint(): JSX.Element | null {\n useEffect(() => {\n apply()\n const observer = new MutationObserver((records) => {\n const relevant = records.some(\n (record) => record.type === 'attributes' || record.addedNodes.length > 0,\n )\n if (relevant) apply()\n })\n observer.observe(document.body, {\n attributes: true,\n attributeFilter: ['placeholder'],\n childList: true,\n subtree: true,\n })\n return () => { observer.disconnect() }\n }, [])\n return null\n}\n","/**\n * File-picker bridge: the single channel between the '@' trigger source\n * (which asks for a directory) and the tree-browser modal (which renders it).\n *\n * Why a modal and not the inline trigger menu: the shell's trigger menu is a\n * flat candidate list with no tree affordance — picking a directory cannot\n * expand it (the menu closes on pick, and the shell only re-runs trigger\n * detection on keyboard input, not on programmatic draft writes). The modal\n * is the pi-desktop-style answer: a real directory tree with lazy expansion,\n * a search box, and one-click insertion.\n *\n * The bridge is framework-free (subscribe/getSnapshot/open/close) so the\n * trigger source can open the picker without touching React; the modal host\n * component subscribes and renders. Insertion happens through the\n * conversation input shell, replacing the exact `@` token span the picker\n * was opened from.\n * @module dsh-filemgr/client/picker/file-picker\n */\n\nimport type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'\n\n/** The `@` token span captured when the picker opened (replace-on-insert). */\nexport interface PickSpan {\n /** Start offset of the `@` token in the draft. */\n start: number\n /** End offset (the caret). */\n end: number\n}\n\n/** What the picker is currently anchored to. */\nexport interface PickRequest {\n /** Session whose draft the picker will edit. */\n sessionId: SessionId\n /** Project root (canonical cwd) everything is relative to. */\n root: string\n /** Directory to start browsing at ('' = root). */\n initialDir: string\n /** The `@` token span to replace on insert. */\n span: PickSpan\n}\n\n/** The bridge's public snapshot. */\nexport interface PickState {\n open: boolean\n req: PickRequest | null\n}\n\n/** Minimal listener shape. */\ntype Listener = (state: PickState) => void\n\n/** Framework-free singleton store backing the modal. */\nclass FilePickerBridge {\n private state: PickState = { open: false, req: null }\n private readonly listeners = new Set<Listener>()\n\n /** Current snapshot (stable reference until the next open/close). */\n getSnapshot(): PickState {\n return this.state\n }\n\n /** Subscribe to open/close transitions. */\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n /** Open the picker anchored to one `@` token. */\n open(req: PickRequest): void {\n this.state = { open: true, req }\n this.emit()\n }\n\n /** Close the picker without inserting anything. */\n close(): void {\n if (!this.state.open) return\n this.state = { open: false, req: null }\n this.emit()\n }\n\n private emit(): void {\n for (const listener of this.listeners) listener(this.state)\n }\n}\n\n/** The shared singleton instance. */\nexport const filePicker = new FilePickerBridge()\n","import type { ClientContext, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\n\n/**\n * Composer draft helpers for file references.\n *\n * References ride the shell's native U+FFFC chip pipeline\n * (`slash/input-insert-reference` bail): the composer shows one chip pill in\n * place of the hidden `@path:lines` token, and the model text is serialized\n * on submit through the `file` reference source's codec (registered in\n * file-source.ts). Without that codec the submit attempt fails with\n * `slash: no serializer for reference source \"file\"` — the codec MUST stay\n * registered while any chip is in a draft.\n */\n\n/**\n * Minimal structural view of the conversation input service. Declared locally\n * so this helper has no value import from the conversation package (keeps the\n * client bundle purity gate happy).\n */\ninterface DraftInput {\n state: { getSnapshot(): { draft: string; draftRev: number } }\n setDraft(draft: string): void\n}\nexport interface ConversationService {\n input: { for(actx: ClientContext): DraftInput }\n}\n\n/** The file-backed reference a composer chip stands for. */\nexport interface FileReference {\n /** Workspace-relative path (what the agent will read). */\n path: string\n /** First line of the referenced range (1-based, inclusive). */\n startLine: number\n /** Last line of the referenced range (1-based, inclusive). */\n endLine: number\n}\n\n/** Basename of a `/`-separated relative path ('' when empty). */\nfunction basenameOf(rel: string): string {\n const idx = rel.lastIndexOf('/')\n return idx >= 0 ? rel.slice(idx + 1) : rel\n}\n\n/** Directory of a `/`-separated relative path ('' when none). */\nfunction dirnameOf(rel: string): string {\n const idx = rel.lastIndexOf('/')\n return idx > 0 ? rel.slice(0, idx) : ''\n}\n\n/**\n * The chip label: basename, or `basename - dir` when the basename is\n * ambiguous across the workspace (matches the reference screenshot: a short\n * name plus the line range, never the full path).\n */\nfunction formatRefLabel(ref: FileReference): string {\n const basename = basenameOf(ref.path)\n const dirname = dirnameOf(ref.path)\n const name = dirname === '' ? basename : `${basename} - ${dirname}`\n return ref.endLine > ref.startLine ? `${name} ${ref.startLine}-${ref.endLine}` : `${name} ${ref.startLine}`\n}\n\n/** The `@path:lines` model form (what the codec serializes to on submit). */\nexport function formatFileRefToken(ref: { path: string; startLine: number; endLine: number }): string {\n const range = ref.endLine > ref.startLine ? `${ref.startLine}-${ref.endLine}` : `${ref.startLine}`\n return `@${ref.path}:${range}`\n}\n\n/** Reference shape the conversation machine mints into a chip occurrence. */\ninterface ConversationReference {\n source: string\n ref: string\n label: string\n clipboardText: string\n}\n\n/** The DRAFT-REV+CAS span the conversation machine expects for chip inserts. */\nexport interface RefSpan {\n start: number\n end: number\n draftRev: number\n}\n\n/** Append `text` to the session's composer draft (plain text — no chip). */\nexport function appendToDraft(ctx: ClientContext, sessionId: SessionId | undefined, text: string): boolean {\n try {\n if (sessionId === undefined) return false\n const actx = ctx.sessions.scope(sessionId)\n if (actx === undefined) return false\n const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation\n if (conversation === undefined) return false\n const input = conversation.input.for(actx as unknown as ClientContext)\n const draft = input.state.getSnapshot().draft\n input.setDraft(draft.trim() === '' ? text : `${draft} ${text}`)\n return true\n } catch (error) {\n console.warn('[dsh-filemgr] draft insert failed:', error)\n return false\n }\n}\n\n/**\n * Insert a file-reference chip into the composer draft at `span`, replacing\n * its range with an occurrence the machine renders as a `</> name N-M`\n * pill. The model text (`@path:lines`) is serialized on submit by the `file`\n * source's codec (file-source.ts) — never the clipboard text.\n *\n * @returns true when the bail was accepted (CAS will still reject on\n * stale draftRev — caller can re-read draft after).\n */\nexport function insertFileReference(\n ctx: ClientContext,\n sessionId: SessionId | undefined,\n ref: FileReference,\n span: RefSpan,\n): boolean {\n try {\n if (sessionId === undefined) return false\n const actx = ctx.sessions.scope(sessionId)\n if (actx === undefined) return false\n const reference: ConversationReference = {\n source: 'file',\n ref: formatFileRefToken(ref),\n label: formatRefLabel(ref),\n clipboardText: formatFileRefToken(ref),\n }\n return (actx as unknown as {\n bail(target: unknown, event: string, payload: unknown): boolean\n }).bail(actx, 'slash/input-insert-reference', { reference, span })\n } catch (error) {\n console.warn('[dsh-filemgr] file-reference insert failed:', error)\n return false\n }\n}\n\n/**\n * Append a file-reference chip at the end of the current draft (the explorer\n * `@` button and the preview \"添加到对话\" action path). Reads the latest\n * draft + draftRev from the conversation shell and inserts a zero-length chip\n * there, so the chip lands after whatever the user has already typed.\n *\n * @returns true on success.\n */\nexport function appendFileReferenceChip(\n ctx: ClientContext,\n sessionId: SessionId | undefined,\n ref: FileReference,\n): boolean {\n if (sessionId === undefined) return false\n const actx = ctx.sessions.scope(sessionId)\n if (actx === undefined) return false\n const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation\n if (conversation === undefined) return false\n const shell = conversation.input.for(actx as unknown as ClientContext)\n const snap = shell.state.getSnapshot()\n return insertFileReference(\n ctx,\n sessionId,\n ref,\n { start: snap.draft.length, end: snap.draft.length, draftRev: snap.draftRev },\n )\n}\n","/**\n * File-picker modal: a pi-desktop-style multi-select tree browser for '@'\n * file/folder references.\n *\n * Trigger: typing `@` (with nothing after it) in the composer opens this\n * modal directly — no inline trigger menu (the shell's trigger menu is a\n * flat candidate list that cannot host a tree). The modal owns a recursive\n * tree with lazy expansion, a workspace filename search, per-row checkboxes\n * for multi-selection, and a chip row of the picked paths.\n *\n * Insertion replaces the `@` token the picker was opened from with the\n * picked references joined by spaces (`@a.ts @src/ @b.md`); cancel drops\n * the stray `@`.\n * @module dsh-filemgr/client/picker/FilePickerModal\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport { createPortal } from 'react-dom'\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { FsEntry, SearchHit } from '../../core/types.ts'\nimport type { PanelApi } from '../api.ts'\nimport { filePicker, type PickState } from './file-picker.ts'\nimport { ChevronDownIcon, ChevronRightIcon, CloseIcon, FileIcon, FolderIcon, FolderOpenIcon, SearchIcon } from '../components/icons.tsx'\nimport { appendToDraft, insertFileReference, type RefSpan } from '../reference.ts'\nimport pickerCss from '../styles/picker.module.css'\n\n/** Debounce for the workspace search box. */\nconst SEARCH_DEBOUNCE_MS = 200\n\n/** Split a relative path into its ancestor chain ('' when empty). */\nfunction ancestors(rel: string): string[] {\n const out: string[] = []\n let acc = ''\n for (const part of rel.split('/')) {\n if (part === '') continue\n acc = acc === '' ? part : `${acc}/${part}`\n out.push(acc)\n }\n return out\n}\n\n/** One picked path with its kind (drives the trailing slash on insert). */\nexport interface PickedPath {\n path: string\n isDir: boolean\n}\n\n/** The modal surface (portal target; renders only while open). */\nexport function FilePickerModal({\n state,\n api,\n onInsert,\n onClose,\n}: {\n state: PickState\n api: PanelApi\n onInsert: (paths: PickedPath[]) => void\n onClose: () => void\n}): JSX.Element | null {\n const req = state.req\n const root = req?.root ?? ''\n const [expanded, setExpanded] = useState<Set<string>>(new Set())\n const [dirs, setDirs] = useState<Record<string, FsEntry[]>>({})\n const [loading, setLoading] = useState<Record<string, boolean>>({})\n const [selected, setSelected] = useState<Map<string, boolean>>(new Map())\n const [search, setSearch] = useState('')\n const [searchResults, setSearchResults] = useState<SearchHit[] | null>(null)\n const [searching, setSearching] = useState(false)\n const searchSeq = useRef(0)\n\n /** Load one directory listing into the tree cache (guarded). */\n const loadDir = (dir: string): void => {\n if (dirs[dir] !== undefined || loading[dir]) return\n setLoading((prev) => ({ ...prev, [dir]: true }))\n void api.list(root, dir).then((result) => {\n setLoading((prev) => ({ ...prev, [dir]: false }))\n if (result.ok) setDirs((prev) => ({ ...prev, [dir]: result.value.entries }))\n })\n }\n\n /** Prime the tree: root + the initial directory's ancestor chain. */\n useEffect(() => {\n setExpanded(new Set())\n setDirs({})\n setLoading({})\n setSelected(new Map())\n setSearch('')\n setSearchResults(null)\n if (root === '') return\n loadDir('')\n if (req !== null && req.initialDir !== '') {\n for (const dir of ancestors(req.initialDir)) {\n setExpanded((prev) => new Set(prev).add(dir))\n loadDir(dir)\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [root, req?.initialDir])\n\n // Debounced, seq-guarded workspace filename search.\n useEffect(() => {\n const q = search.trim()\n if (q === '') {\n searchSeq.current += 1\n setSearchResults(null)\n setSearching(false)\n return\n }\n const seq = ++searchSeq.current\n setSearching(true)\n const timer = setTimeout(() => {\n void api.search(root, q).then((result) => {\n if (searchSeq.current !== seq) return\n setSearching(false)\n setSearchResults(result.ok ? result.value.hits : [])\n })\n }, SEARCH_DEBOUNCE_MS)\n return () => { clearTimeout(timer) }\n }, [search, root, api])\n\n const toggleDir = (dir: string): void => {\n setExpanded((prev) => {\n const next = new Set(prev)\n if (next.has(dir)) next.delete(dir)\n else {\n next.add(dir)\n loadDir(dir)\n }\n return next\n })\n }\n\n /** Toggle one path in the multi-selection (checkbox semantics). */\n const toggleSelect = (path: string, isDir: boolean): void => {\n setSelected((prev) => {\n const next = new Map(prev)\n if (next.has(path)) next.delete(path)\n else next.set(path, isDir)\n return next\n })\n }\n\n // Escape closes.\n useEffect(() => {\n if (!state.open) return\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') onClose()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [state.open, onClose])\n\n const tree = useMemo(() => {\n const renderNode = (entry: FsEntry, depth: number): JSX.Element => {\n const isDir = entry.isDir\n const isOpen = expanded.has(entry.path)\n const isSel = selected.has(entry.path)\n const children = dirs[entry.path] ?? []\n const isLoading = loading[entry.path] === true\n return (\n <div key={entry.path}>\n <div\n className={`${pickerCss.row}${isSel ? ` ${pickerCss.rowSelected}` : ''}`}\n style={{ paddingLeft: 8 + depth * 16 }}\n onClick={() => toggleSelect(entry.path, isDir)}\n >\n <span\n className={pickerCss.chev}\n role=\"button\"\n tabIndex={-1}\n onClick={(e) => {\n if (!isDir) return\n e.stopPropagation()\n toggleDir(entry.path)\n }}\n >\n {isDir ? (isOpen ? <ChevronDownIcon size={14} /> : <ChevronRightIcon size={14} />) : <span className={pickerCss.chevSpacer} />}\n </span>\n <span className={pickerCss.icon}>\n {isDir ? (isOpen ? <FolderOpenIcon size={15} /> : <FolderIcon size={15} />) : <FileIcon size={15} />}\n </span>\n <span className={pickerCss.name} title={entry.path}>{entry.name}</span>\n <span\n className={`${pickerCss.check}${isSel ? ` ${pickerCss.checkOn}` : ''}`}\n onClick={(e) => {\n e.stopPropagation()\n toggleSelect(entry.path, isDir)\n }}\n >\n {isSel ? <CheckIcon size={12} /> : null}\n </span>\n </div>\n {isDir && isOpen && (\n <div>\n {isLoading ? (\n <div className={pickerCss.note} style={{ paddingLeft: 8 + (depth + 1) * 16 }}>加载中…</div>\n ) : children.length === 0 ? (\n <div className={pickerCss.note} style={{ paddingLeft: 8 + (depth + 1) * 16 }}>(空目录)</div>\n ) : (\n children.map((child) => renderNode(child, depth + 1))\n )}\n </div>\n )}\n </div>\n )\n }\n return renderNode\n }, [expanded, dirs, loading, selected, toggleDir, toggleSelect])\n\n if (!state.open || req === null) return null\n const rootEntries = dirs[''] ?? []\n const rootLoading = loading[''] === true\n const selectedList: PickedPath[] = Array.from(selected.entries()).map(([path, isDir]) => ({ path, isDir }))\n\n return createPortal(\n <div className={pickerCss.overlay} onMouseDown={(e) => { if (e.target === e.currentTarget) onClose() }}>\n <div className={pickerCss.modal} onClick={(e) => e.stopPropagation()}>\n <div className={pickerCss.header}>\n <div className={pickerCss.titleRow}>\n <span className={pickerCss.title}>引用项目文件</span>\n <button type=\"button\" className={pickerCss.closeBtn} onClick={onClose} aria-label=\"关闭\">\n <CloseIcon size={16} />\n </button>\n </div>\n <div className={pickerCss.searchWrap}>\n <span className={pickerCss.searchIcon}><SearchIcon size={14} /></span>\n <input\n className={pickerCss.searchInput}\n placeholder=\"搜索工作区文件…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n autoFocus\n />\n {search !== '' && (\n <button type=\"button\" className={pickerCss.searchClear} onClick={() => setSearch('')} aria-label=\"清空\">\n <CloseIcon size={13} />\n </button>\n )}\n </div>\n <div className={pickerCss.rootPath} title={root}>{root}</div>\n </div>\n\n <div className={pickerCss.body}>\n {searchResults !== null ? (\n searching ? (\n <div className={pickerCss.note}>搜索中…</div>\n ) : searchResults.length === 0 ? (\n <div className={pickerCss.note}>没有匹配的文件</div>\n ) : (\n searchResults.map((hit) => {\n const isSel = selected.has(hit.path)\n return (\n <div\n key={hit.path}\n className={`${pickerCss.row}${isSel ? ` ${pickerCss.rowSelected}` : ''}`}\n onClick={() => toggleSelect(hit.path, false)}\n >\n <span className={pickerCss.chevSpacer} />\n <span className={pickerCss.icon}><FileIcon size={15} /></span>\n <span className={pickerCss.name} title={hit.path}>\n <span>{hit.name}</span>\n <span className={pickerCss.subpath}>{hit.path}</span>\n </span>\n <span\n className={`${pickerCss.check}${isSel ? ` ${pickerCss.checkOn}` : ''}`}\n onClick={(e) => {\n e.stopPropagation()\n toggleSelect(hit.path, false)\n }}\n >\n {isSel ? <CheckIcon size={12} /> : null}\n </span>\n </div>\n )\n })\n )\n ) : rootLoading ? (\n <div className={pickerCss.note}>加载中…</div>\n ) : rootEntries.length === 0 ? (\n <div className={pickerCss.note}>(空目录)</div>\n ) : (\n rootEntries.map((entry) => tree(entry, 0))\n )}\n </div>\n\n <div className={pickerCss.footer}>\n <div className={pickerCss.chips}>\n {selectedList.length === 0 ? (\n <span className={pickerCss.chipsEmpty}>选择文件或目录(可多选)</span>\n ) : (\n selectedList.map((pick) => (\n <span key={pick.path} className={pickerCss.chip}>\n <span>@{pick.path}{pick.isDir ? '/' : ''}</span>\n <button\n type=\"button\"\n className={pickerCss.chipX}\n onClick={() => toggleSelect(pick.path, pick.isDir)}\n aria-label=\"移除\"\n >\n <CloseIcon size={11} />\n </button>\n </span>\n ))\n )}\n </div>\n <div className={pickerCss.footerActions}>\n <button type=\"button\" className={pickerCss.cancelBtn} onClick={onClose}>取消</button>\n <button\n type=\"button\"\n className={pickerCss.insertBtn}\n disabled={selectedList.length === 0}\n onClick={() => onInsert(selectedList)}\n >\n 插入{selectedList.length > 0 ? ` (${selectedList.length})` : ''}\n </button>\n </div>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n\n/** Minimal inline check glyph (avoids an extra icon import cycle). */\nfunction CheckIcon({ size }: { size: number }): JSX.Element {\n return (\n <svg width={size} height={size} viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2.5 6.2 4.8 8.5 9.5 3.5\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\n/** Minimal structural view of the conversation input service (see reference.ts). */\ninterface DraftInput {\n state: { getSnapshot(): { draft: string; draftRev: number } }\n setDraft(draft: string): void\n}\ninterface ConversationService {\n input: { for(actx: ClientContext): DraftInput }\n}\n\n/** Active `@` mention candidate in the draft (mimics pi-desktop's getActiveMention). */\nexport function findAtMention(value: string, caret: number): { start: number; query: string } | null {\n const before = value.slice(0, caret)\n const at = before.lastIndexOf('@')\n if (at < 0) return null\n // The '@' must sit at a token boundary (start or after whitespace/punctuation).\n if (at > 0 && !/[\\s,;.!?()[\\]{}\"'/\\\\]/.test(before[at - 1])) return null\n return { start: at, query: before.slice(at + 1) }\n}\n\n/**\n * The picker host: watches the composer textarea for a bare `@` (opening the\n * modal directly, pi-desktop style — no inline trigger menu), subscribes to\n * the bridge, and renders the modal. Insertion replaces the `@` token span\n * with the picked references joined by spaces; cancel drops the stray `@`.\n */\nexport function FilePickerHost({ ctx, api }: { ctx: ClientContext; api: PanelApi }): JSX.Element {\n const [state, setState] = useState<PickState>(filePicker.getSnapshot())\n useEffect(() => filePicker.subscribe(setState), [])\n\n // When the modal opens, close the shell's inline trigger menu: the `file`\n // codec source registers under '@' (and any other '@' sources exist), so a\n // bare `@` also pops the flat menu — the modal must be the only surface.\n useEffect(() => {\n if (!state.open || state.req === null) return\n try {\n const actx = ctx.sessions.scope(state.req.sessionId)\n if (actx === undefined) return\n const inputTriggers = (ctx as unknown as {\n get(name: string): unknown\n }).get('inputTriggers') as { sessionOf(a: ClientContext): { dismiss(): void } } | undefined\n inputTriggers?.sessionOf(actx).dismiss()\n } catch {\n // Menu dismissal is best-effort; the modal stands alone regardless.\n }\n }, [state.open, state.req, ctx])\n\n // Composer `@` watcher: open the picker the moment a bare `@` lands.\n useEffect(() => {\n const watched = new WeakSet<HTMLTextAreaElement>()\n const onInput = (e: Event): void => {\n if (filePicker.getSnapshot().open) return\n const ta = e.target as HTMLTextAreaElement\n const caret = ta.selectionStart ?? ta.value.length\n const mention = findAtMention(ta.value, caret)\n if (mention === null || mention.query !== '') return\n const snapshot = ctx.sessions.list.getSnapshot()\n const sessionId = snapshot.current\n if (sessionId === undefined) return\n const cwd = snapshot.byId[sessionId]?.cwd\n const root = typeof cwd === 'string' && cwd !== '' ? cwd : ''\n if (root === '') return\n filePicker.open({\n sessionId,\n root,\n initialDir: '',\n span: { start: mention.start, end: mention.start + 1 },\n })\n }\n const attach = (): void => {\n for (const ta of document.querySelectorAll<HTMLTextAreaElement>('textarea')) {\n if (watched.has(ta)) continue\n watched.add(ta)\n ta.addEventListener('input', onInput)\n }\n }\n attach()\n const observer = new MutationObserver(attach)\n observer.observe(document.body, { childList: true, subtree: true })\n return () => {\n observer.disconnect()\n for (const ta of document.querySelectorAll<HTMLTextAreaElement>('textarea')) {\n ta.removeEventListener('input', onInput)\n }\n }\n }, [ctx])\n\n /**\n * Insert the picked references into the composer draft as file-reference\n * chips (one `slash/input-insert-reference` bail per file; the `file`\n * source codec serializes each to `@path:lines` on submit). Folders fall\n * back to plain `@path/ ` text since the chip has no line concept.\n * Multiple selections land as adjacent chips.\n */\n const insert = async (paths: PickedPath[]): Promise<void> => {\n const current = filePicker.getSnapshot()\n if (!current.open || current.req === null || paths.length === 0) return\n const { sessionId, root, span } = current.req\n try {\n const actx = ctx.sessions.scope(sessionId)\n if (actx === undefined) return\n const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation\n if (conversation === undefined) return\n const shell = conversation.input.for(actx)\n // Pre-fetch every file's line count in parallel (bails are serial so\n // they share the same draft; reads are independent).\n const lineCounts = await Promise.all(paths.map(async (pick) => {\n if (pick.isDir) return { pick, lines: null }\n const result = await api.read(root, pick.path, false)\n if (!result.ok) return { pick, lines: null }\n const text = result.value.content\n const trimmed = text.endsWith('\\n') ? text.slice(0, -1) : text\n const lines = trimmed === '' ? 1 : trimmed.split('\\n').length\n return { pick, lines }\n }))\n // Walk in original order. The first chip replaces the `@` token; the\n // rest insert at the current cursor (0-length span) so the machine\n // appends each one in turn.\n let cursor = span.end\n let firstSpan = true\n for (const { pick, lines } of lineCounts) {\n if (pick.isDir) {\n appendToDraft(ctx, sessionId, `@${pick.path}/ `)\n continue\n }\n if (lines === null) continue\n const snap = shell.state.getSnapshot()\n const currentSpan: RefSpan = firstSpan\n ? { start: span.start, end: span.end, draftRev: snap.draftRev }\n : { start: cursor, end: cursor, draftRev: snap.draftRev }\n const ok = insertFileReference(\n ctx,\n sessionId,\n { path: pick.path, startLine: 1, endLine: lines },\n currentSpan,\n )\n if (ok) {\n firstSpan = false\n // The machine replaces [start,end) with U+FFFC and an optional\n // trailing space; the cursor advances by 2 for the new characters.\n cursor += 2\n }\n }\n filePicker.close()\n } catch (error) {\n console.warn('[dsh-filemgr] picker insert failed:', error)\n }\n }\n\n /** Cancel: drop the stray `@` the picker was opened from. */\n const close = (): void => {\n const current = filePicker.getSnapshot()\n if (current.open && current.req !== null) {\n const { sessionId, span } = current.req\n try {\n const actx = ctx.sessions.scope(sessionId)\n const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation\n if (actx !== undefined && conversation !== undefined) {\n const shell = conversation.input.for(actx)\n const draft = shell.state.getSnapshot().draft\n const token = draft.slice(span.start, span.end)\n if (token.startsWith('@')) {\n shell.setDraft(draft.slice(0, span.start) + draft.slice(span.end))\n }\n }\n } catch {\n // Best-effort cleanup; the picker still closes.\n }\n }\n filePicker.close()\n }\n\n return <FilePickerModal state={state} api={api} onInsert={insert} onClose={close} />\n}\n","/**\n * Chat file-reference click handling (issue #314): the transcript renders\n * workspace file paths as inline code, and clicking one should locate the\n * file in the Explorer (switch to the Files tab, expand the ancestor chain,\n * select the node) and open it in the Preview panel — directories are\n * reveal-only. A document-level click listener (wired in the client apply)\n * recognizes a conservative subset: a single-line `code` element whose text\n * is a workspace-relative path or an absolute path under the project root.\n * Links (`a`), multi-line fences, URLs, escaped (`..`) paths and anything\n * inside the panels' own subtrees keep their existing behavior.\n * @module dsh-filemgr/client/chat/file-ref\n */\n\nimport type { PanelApi } from '../api.ts'\nimport type { PanelStores } from '../store.ts'\nimport { parentRel } from '../fileType.ts'\n\n/** Longest candidate text (arbitrary safety cap against huge code spans). */\nconst MAX_REF_LENGTH = 512\n\n/** Normalize both separators to '/'. */\nfunction normalizeSlashes(value: string): string {\n return value.replace(/\\\\/g, '/')\n}\n\n/**\n * Interpret a code span's text as a workspace path. Returns the workspace\n * RELATIVE path ('' = the root itself), or null when the text is not a\n * recognizable in-workspace path. Never resolves above the root: `..`\n * segments, absolute outside paths, URLs and whitespace/multi-line text all\n * fall back to null so the transcript keeps its normal behavior.\n */\nexport function pathFromText(text: string, root: string): string | null {\n const raw = text.trim()\n if (raw === '' || raw.length > MAX_REF_LENGTH) return null\n if (/[\\r\\n]/.test(raw)) return null\n if (raw.includes('://')) return null\n const normalized = normalizeSlashes(raw)\n const rootNorm = normalizeSlashes(root).replace(/\\/+$/, '')\n if (rootNorm === '') return null\n\n // Absolute path inside the workspace. Posix paths start with '/'\n // (case-sensitive prefix match); Windows drive paths carry a drive\n // letter (case-insensitive prefix match with a separator boundary).\n if (normalized.startsWith('/')) {\n if (normalized === rootNorm) return ''\n if (!normalized.startsWith(rootNorm + '/')) return null\n const rel = normalized.slice(rootNorm.length).replace(/^\\/+/, '')\n return validRelative(rel) ? rel : null\n }\n if (/^[a-zA-Z]:/.test(normalized)) {\n const lower = normalized.toLowerCase()\n const lowerRoot = rootNorm.toLowerCase()\n if (lower === lowerRoot) return ''\n if (!lower.startsWith(lowerRoot + '/')) return null\n const rel = normalized.slice(rootNorm.length).replace(/^\\/+/, '')\n return validRelative(rel) ? rel : null\n }\n\n // Workspace-relative path ('.' prefix stripped).\n const rel = normalized.startsWith('./') ? normalized.slice(2) : normalized\n return validRelative(rel) ? rel : null\n}\n\n/** Validate a relative path: no escapes, no whitespace, looks path-like. */\nfunction validRelative(rel: string): boolean {\n if (rel === '' || rel.length > MAX_REF_LENGTH) return false\n if (/\\s/.test(rel)) return false\n const segments = rel.split('/')\n if (segments.length < 2) {\n // A bare name is accepted only when it looks like a file (dotted), so\n // ordinary words in code spans never trigger a locate.\n return /^[^/]*\\.[^/]+$/.test(rel)\n }\n for (const segment of segments) {\n if (segment === '' || segment === '.' || segment === '..') return false\n }\n return true\n}\n\n/** The `code` element a click targets, when it is a candidate file ref. */\nexport function fileRefElement(target: EventTarget | null): HTMLElement | null {\n if (!(target instanceof Element)) return null\n const code = target.closest('code')\n if (code === null) return null\n // Links keep their own navigation; the panels' own code blocks (preview\n // editors, tree rows) never trigger the transcript locate.\n if (code.closest('a') !== null) return null\n if (code.closest('.filemgr-root') !== null) return null\n if (code.closest('[data-filemgr-preview-col], [data-filemgr-explorer-col]') !== null) return null\n return code\n}\n\n/**\n * Locate a workspace-relative path from the transcript: Files tab + expand\n * ancestors + select; directories stay reveal-only, files also open in the\n * Preview panel (dedup focuses the existing tab). The parent listing is\n * consulted to classify the node; unknown paths keep the reveal and never\n * issue a preview request.\n */\nexport async function locateFileRef(stores: PanelStores, api: PanelApi, rel: string): Promise<void> {\n const explorer = stores.explorer\n explorer.setActiveTab('files')\n if (rel !== '') explorer.reveal(rel)\n\n const root = stores.layout.getSnapshot().root\n if (root === '' || rel === '') return\n\n const name = rel.split('/').pop() ?? ''\n const parent = parentRel(rel)\n let entry = explorer.getSnapshot().dirs[parent]?.find((item) => item.name === name)\n if (entry === undefined) {\n const result = await api.list(root, parent)\n if (result.ok) entry = result.value.entries.find((item) => item.name === name)\n }\n // Known directories: reveal-only (their children list is the tree's job).\n // Known files: open in the preview panel. Unknown: no preview request.\n if (entry !== undefined && !entry.isDir) {\n stores.preview.openFile(root, rel)\n }\n}\n\n/** Document-level click handler: locate recognized chat file references. */\nexport function handleFileRefClick(stores: PanelStores, api: PanelApi, event: MouseEvent): void {\n if (event.defaultPrevented || event.button !== 0) return\n const code = fileRefElement(event.target)\n if (code === null) return\n const root = stores.layout.getSnapshot().root\n if (root === '') return\n const rel = pathFromText(code.textContent ?? '', root)\n if (rel === null) return\n // The explorer must be visible for the reveal to be seen: un-collapse the\n // column (persisted like the chevron toggle does).\n const layout = stores.layout.getSnapshot()\n if (layout.explorerCollapsed) {\n stores.layout.update((prev) => ({ ...prev, explorerCollapsed: false }))\n try {\n localStorage.setItem(`project-panel-collapse:${root}`, 'expanded')\n } catch {\n // best-effort\n }\n }\n void locateFileRef(stores, api, rel)\n}\n","/**\n * The `file` input-trigger source: registers the reference codec the shell's\n * submit pipeline needs to serialize a file chip (`slash: no serializer for\n * reference source \"file\"` disappears once this source is in the roster).\n *\n * The source is deliberately INERT as a menu participant: the file picker is\n * our own pi-desktop-style tree modal (see picker/FilePickerModal.tsx), not\n * the shell's flat trigger menu, so `candidates` returns nothing and `onPick`\n * never fires. Its only jobs are (1) to be findable by\n * `inputTriggers.serializeReference('file', ref)` and (2) to own the model\n * projection of a chip — the `@path:lines` plain-text token.\n *\n * Trigger '@' keeps the chip family visually consistent with the other '@'\n * sources; the menu group this source contributes is empty and is covered by\n * the picker modal the moment a bare `@` lands.\n * @module dsh-filemgr/client/file-source\n */\n\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { InputTriggerSource } from '@deepseek-ai/dsh-client-ui-input-trigger/client'\n\n/** The roster name the chip occurrences address (see reference.ts). */\nexport const FILE_SOURCE_NAME = 'file'\n\n/** Required services: the trigger roster plus the session scope carrier. */\nexport const inject = ['inputTriggers']\n\n/**\n * Register the inert `file` reference source (codec only). Safe to call\n * multiple times (each call returns a disposer; the roster rejects a\n * duplicate (trigger, name) seat, so guard with a module flag).\n */\nexport function registerFileReferenceSource(ctx: ClientContext): () => void {\n // ctx.get — not property access: the caller (index.ts apply) does not\n // declare 'inputTriggers' in its inject list, and property access would\n // throw \"cannot get property without inject\". get() needs no inject.\n const inputTriggers = (ctx.get as (name: string) => unknown)('inputTriggers') as\n | { registerSource(src: InputTriggerSource): () => void }\n | undefined\n if (inputTriggers === undefined) return () => {}\n const source: InputTriggerSource = {\n trigger: '@',\n name: FILE_SOURCE_NAME,\n candidates: async () => [],\n onPick: () => undefined,\n codec: {\n clipboardText: (ref) => ref,\n serialize: (ref, _signal) => Promise.resolve(ref),\n },\n }\n try {\n return inputTriggers.registerSource(source)\n } catch (error) {\n // Duplicate registration (HMR remount) is not a failure.\n console.warn('[dsh-filemgr] file reference source already registered:', error)\n return () => {}\n }\n}\n","/**\r\n * DockItem — a round dock button for the conversation session header.\r\n * Each plugin owns its own DockItem copy (terminal in dsh-term, file-panel in\r\n * dsh-file-manager). Hover scales the button up via pure CSS — no JS event\r\n * coordination, no shared motion value.\r\n * @module dsh-file-manager/client/DockItem\r\n */\r\nimport { type ReactElement, type ReactNode } from 'react'\r\n\r\nconst STYLE_ID = 'dsh-dock-item-style'\r\n\r\nfunction ensureStyle(): void {\r\n if (typeof document === 'undefined') return\r\n if (document.getElementById(STYLE_ID) !== null) return\r\n const tag = document.createElement('style')\r\n tag.id = STYLE_ID\r\n tag.textContent = '.dsh-dock-item{width:32px;height:32px;border:none;border-radius:9999px;background:#000;color:#fff;cursor:pointer;position:relative;transition:transform .15s ease,background .18s ease;display:inline-flex;align-items:center;justify-content:center}.dsh-dock-item:hover{transform:scale(1.15);background:#1a1a1a}.dsh-dock-item-active{background:var(--aion-primary,#6ea0ff)}.dsh-dock-tooltip{position:absolute;top:calc(100% + 6px);left:50%;transform:translateX(-50%);padding:2px 8px;font-size:12px;line-height:1.4;white-space:nowrap;color:#fff;background:rgba(20,20,30,.9);border:1px solid rgba(255,255,255,.12);border-radius:6px;opacity:0;pointer-events:none;transition:opacity .15s}.dsh-dock-item:hover .dsh-dock-tooltip{opacity:1}'\r\n document.head.appendChild(tag)\r\n}\r\n\r\nensureStyle()\r\n\r\nexport function DockItem(props: {\r\n active: boolean\r\n label: string\r\n onClick: () => void\r\n children: ReactNode\r\n}): ReactElement {\r\n return (\r\n <button\r\n type=\"button\"\r\n className={`dsh-dock-item${props.active ? ' dsh-dock-item-active' : ''}`}\r\n onClick={props.onClick}\r\n aria-label={props.label}\r\n aria-pressed={props.active}\r\n title={props.label}\r\n >\r\n <span className=\"dsh-dock-tooltip\">{props.label}</span>\r\n {props.children}\r\n </button>\r\n )\r\n}\r\n","/**\r\n * FilePanelDockItem — the file-panel dock button rendered into the conversation\r\n * session header (the `conversation.session.header.utilities` slot).\r\n *\r\n * This plugin owns its own dock button independently: dsh-term renders its own\r\n * terminal button, dsh-file-manager renders this file-panel button. The two\r\n * are fully decoupled — install either alone and you get just its button;\r\n * install both and both buttons appear side by side with shared magnification.\r\n *\r\n * Clicking broadcasts `dsh-dock:toggle-filepanel` (handled in dsh-file-manager\r\n * index); the open state is mirrored back through `dsh-dock:filepanel-state`.\r\n * @module dsh-file-manager/client/FilePanelDockItem\r\n */\r\nimport { useEffect, useState, type ReactElement } from 'react'\r\nimport { DockItem } from './DockItem.tsx'\r\n\r\nconst EV = {\r\n toggleFile: 'dsh-dock:toggle-filepanel',\r\n fileState: 'dsh-dock:filepanel-state',\r\n} as const\r\n\r\nexport function FilePanelDockItem(): ReactElement {\r\n const [active, setActive] = useState(false)\r\n useEffect(() => {\r\n const onState = (e: Event): void => setActive(Boolean((e as CustomEvent).detail))\r\n window.addEventListener(EV.fileState, onState)\r\n return () => window.removeEventListener(EV.fileState, onState)\r\n }, [])\r\n return (\r\n <DockItem\r\n active={active}\r\n label=\"文件面板\"\r\n onClick={() => window.dispatchEvent(new CustomEvent(EV.toggleFile))}\r\n >\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"m6 14 1.45-2.9a2 2 0 0 1 1.79-1.1h11.76a2 2 0 0 1 1.94 1.5l1.55 6a2 2 0 0 1-1.94 2.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.5a2 2 0 0 1 1.59.79l.91 1.21a2 2 0 0 0 1.59.79H18a2 2 0 0 1 2 2v2\" />\r\n </svg>\r\n </DockItem>\r\n )\r\n}","/**\n * FileManager right-panel system — browser half: mounts the explorer and preview\n * columns into the web shell's frame grid (through the layout controller),\n * binds the four stores to the live client runtime (the active session's cwd\n * is the project root), subscribes to the host change stream (fs + git), and\n * follows the shell's dark marker (body[data-ds-dark-theme]) via CSS only.\n *\n * Failure policy: every DOM/runtime wiring failure is logged, never thrown —\n * the web shell fails the whole boot when a plugin apply throws.\n *\n * FileManager right-panel design (Apache-2.0, iOfficeAI/FileManager) — re-implemented\n * from measured behavior and architecture, not copied code.\n * @module dsh-filemgr/client\n */\n\nimport { createElement } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport type { ClientContext, SessionId, SettingsScope, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the official settings-scope service onto the client Context.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: pulls the ui-conversation SlotMap merge (the input dock entry).\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { PanelApi, subscribePanelEvents } from './api.ts'\nimport { FileManagerSettingsCard, FileManagerSettingsCardController, type FileManagerPanelSettings } from './FileManagerSettingsCard.tsx'\nimport { PanelLayoutController } from './layout.ts'\nimport { createPanelStores, layoutSetRoot } from './store.ts'\nimport { mountPanels } from './mount.tsx'\nimport { NS, dictionaries, setLanguage, type FileManagerPanelKey } from './locales.ts'\nimport { DragFileInlay, type DragFileInjected } from './drag/DragFileInlay.tsx'\nimport { insertPathIntoDraft } from './drag/file-drag.ts'\nimport { MermaidChatEnhancer } from './chat/mermaid-chat.tsx'\nimport { PlaceholderHint } from './chat/placeholder-hint.tsx'\nimport { FilePickerHost } from './picker/FilePickerModal.tsx'\nimport { handleFileRefClick } from './chat/file-ref.ts'\nimport { appendToDraft, appendFileReferenceChip } from './reference.ts'\nimport { registerFileReferenceSource } from './file-source.ts'\nimport type { FileReferenceSelection } from './preview/selection.ts'\nimport './styles/chip.module.css'\nimport { FilePanelDockItem } from './FilePanelDockItem.tsx'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Panel surface copy. */\n 'filemgr': FileManagerPanelKey\n }\n\n interface SlotMap {\n /**\n * One family plugin card inside the Web UI Plugins group. Spelled here\n * with the same shape so this package can register without depending on\n * the sibling web-ui-settings package.\n */\n 'web-ui.plugin.item': { kind: 'list'; scope: 'root'; owner: SettingsPluginItemOwnerProps }\n }\n}\n\n/** Owner share of a plugin card (the section supplies nothing). */\nexport interface SettingsPluginItemOwnerProps {\n /** Marker field: card owner props are intentionally empty. */\n children?: never\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /**\n * Optional rc.6 compatibility binder provided by dsh-web-ui-settings;\n * absent when that group plugin is not installed, so callers fall back to\n * the official settings scope.\n */\n webUiSettings?: { bind<S>(spec: SettingsScopeSpec<S>): SettingsScope<S> }\n }\n}\n\n/** Required services: sessions for the project root, locale for the copy, the settings scope for the master switch, and conversation for the composer draft edits (picker insert / @ button). */\nexport const inject = ['sessions', 'locale', 'settingsScope', 'conversation']\n\n/** Shared, stateless fs client (the PanelApi only wraps fetch calls). */\nconst panelApi = new PanelApi()\n\n/** Apply the browser half. */\nexport function apply(ctx: ClientContext): void {\n // Session header dock button (file-panel): each plugin owns its own button\n // in conversation.session.header.utilities, so file-manager works standalone\n // without dsh-term. Cross-button magnification is coordinated via window\n // events (see DockItem.tsx).\n ctx.inject(['slots'], (scope: ClientContext) => {\n scope.slots.inject('conversation.session.header.utilities', () =>\n scope.slots.register({\n name: 'conversation.session.header.utilities',\n id: 'filemgr-dock-item',\n order: -2,\n inject: () => ({}),\n }, FilePanelDockItem))\n })\n\n ctx.effect(() => ctx.locale.register(NS, dictionaries), 'dsh-filemgr: dictionaries')\n\n // The `file` reference source: registers the codec that serializes file\n // chips on submit (`@path:lines`), which the shell requires before any\n // `slash/input-insert-reference` chip can send. Inert as a menu\n // participant — the '@' tree modal is our own picker, not the shell menu.\n ctx.effect(() => registerFileReferenceSource(ctx), 'dsh-filemgr: file reference source')\n\n // The '@' picker is our own tree modal (pi-desktop style), NOT the shell's\n // flat trigger menu: a bare `@` in the composer opens FilePickerHost\n // directly. The one inputTriggers registration above is codec-only and\n // inert in the menu; the modal covers any residual menu the moment it\n // opens.\n\n // The composer drop target for explorer file drags: mounted in the\n // official `conversation.input.dock` band (declared by the shipped\n // ui-conversation rc.6 shell), session-routed through the conversation\n // input facade. A missing session scope or conversation service degrades\n // to no-op — the panels themselves never depend on the dock entry.\n ctx.inject(['slots', 'conversation', 'sessions'], (scope: ClientContext) => {\n const sessions = scope.sessions\n const conversation = scope.conversation\n scope.slots.inject('conversation.input.dock', () =>\n scope.slots.register({\n name: 'conversation.input.dock',\n id: 'filemgr-drag-file',\n order: 90,\n locale: NS,\n inject: (sessionId: SessionId | undefined): DragFileInjected => ({\n insertPath: (path: string): boolean => {\n if (sessionId === undefined) return false\n const actx = sessions.scope(sessionId)\n if (actx === undefined) return false\n const input = conversation.input\n if (input === undefined) return false\n const shell = input.for(actx)\n const draft = shell.state.getSnapshot().draft\n shell.setDraft(insertPathIntoDraft(draft, path))\n return true\n },\n }),\n }, DragFileInlay))\n })\n\n // Transcript mermaid enhancement rides the same dock as a zero-render\n // sentinel: the shell has no message-body slot, so the sentinel observes\n // the document for the chat renderer's `code.language-mermaid` blocks.\n ctx.inject(['slots'], (scope: ClientContext) => {\n scope.slots.inject('conversation.input.dock', () =>\n scope.slots.register({\n name: 'conversation.input.dock',\n id: 'filemgr-mermaid-chat',\n order: 91,\n }, MermaidChatEnhancer))\n })\n\n // Composer placeholder hint rides the same band: the shell's input bar\n // placeholder (\"给智能体发消息\") has no plugin override seam, so a sentinel\n // rewrites the DOM attribute to advertise the '@' file reference and the\n // '/' command trigger (see placeholder-hint.tsx).\n ctx.inject(['slots'], (scope: ClientContext) => {\n scope.slots.inject('conversation.input.dock', () =>\n scope.slots.register({\n name: 'conversation.input.dock',\n id: 'filemgr-placeholder-hint',\n order: 92,\n }, PlaceholderHint))\n })\n\n // The settings card: one master switch (issue #307) in the Web UI Plugins\n // group, bound to the 'filemgr' namespace through the family bridge\n // (or the official settings scope when the deployment exposes it).\n ctx.inject(['slots', 'settingsScope'], (settingsCtx: ClientContext) => {\n const binder = settingsCtx.get('webUiSettings') ?? settingsCtx.settingsScope\n const panelScope = binder.bind<FileManagerPanelSettings>({ namespace: NS })\n const settingsCard = new FileManagerSettingsCardController(panelScope)\n settingsCtx.slots.inject('web-ui.plugin.item', () => {\n const unregister = settingsCtx.slots.register({\n name: 'web-ui.plugin.item',\n id: 'filemgr',\n order: 110,\n locale: NS,\n inject: () => settingsCard.inject(),\n }, FileManagerSettingsCard)\n return () => {\n settingsCard.dispose()\n unregister()\n }\n })\n })\n\n ctx.effect(() => {\n // Master switch (issue #307): the settings card edits the 'filemgr'\n // namespace through the family settings bridge (or the official scope).\n // While off, the panels, the floating button and the change stream stay\n // unmounted; toggling the switch re-mounts them live (the pet's model).\n let panelScope: SettingsScope<FileManagerPanelSettings> | undefined\n try {\n const binder = ctx.get('webUiSettings') ?? ctx.settingsScope\n if (binder !== undefined) panelScope = binder.bind<FileManagerPanelSettings>({ namespace: NS })\n } catch (error) {\n // A missing settings seam must not break the panel boot: default on.\n panelScope = undefined\n }\n const enabled = (): boolean => panelScope?.getSnapshot().value?.enabled ?? true\n let disposeUi: (() => void) | undefined\n\n /**\n * Mount the whole panel UI (columns, handles, floating button, change\n * stream, persists) and return its teardown. A fresh lifecycle per\n * enable keeps toggling idempotent (the layout controller cannot be\n * reused after dispose).\n */\n const mountUi = (): (() => void) => {\n const stores = createPanelStores(panelApi)\n const layout = new PanelLayoutController(stores.layout)\n const disposers: Array<() => void> = []\n let disposeGitEvents: (() => void) | undefined\n let currentRoot = ''\n let lastPreviewOpen = false\n\n // The Explorer row '@' button: insert a file-reference chip for files\n // (path + 1..N) or plain `@<rel-path>/` text for folders. File lines\n // are fetched from the host so the chip can carry an accurate line\n // range; failures fall back to plain text.\n const onReference = (path: string, isDir: boolean): void => {\n const sessionId = ctx.sessions.list.getSnapshot().current as SessionId | undefined\n if (sessionId === undefined) {\n console.warn('[dsh-filemgr] @ 引用插入失败:没有活动会话')\n return\n }\n if (isDir) {\n appendToDraft(ctx, sessionId, `@${path}/ `)\n return\n }\n void panelApi.read(currentRoot, path, false).then((result) => {\n if (!result.ok) {\n appendToDraft(ctx, sessionId, `@${path} `)\n return\n }\n const text = result.value.content\n const trimmed = text.endsWith('\\n') ? text.slice(0, -1) : text\n const lines = trimmed === '' ? 1 : trimmed.split('\\n').length\n appendFileReferenceChip(ctx, sessionId, { path, startLine: 1, endLine: lines })\n })\n }\n\n // The preview \"添加到对话\" action: insert a file-reference chip\n // carrying the selected line range, appended at the draft end.\n const onAddFileReference = (selection: FileReferenceSelection): boolean => {\n const sessionId = ctx.sessions.list.getSnapshot().current as SessionId | undefined\n return appendFileReferenceChip(ctx, sessionId, selection)\n }\n\n // The project root follows the active session's cwd; switching sessions\n // re-binds every store (widths, collapse, tree, tabs persist per root).\n const bindRoot = (): void => {\n const snapshot = ctx.sessions.list.getSnapshot()\n const sessionId = snapshot.current as SessionId | undefined\n const cwd = sessionId === undefined ? undefined : snapshot.byId[sessionId]?.cwd\n const root = typeof cwd === 'string' && cwd !== '' ? cwd : ''\n if (root === currentRoot) return\n currentRoot = root\n\n // The change stream is git-only and lives exactly as long as the SCM\n // tab is visible (no fs watch — the explorer/preview refresh on user\n // actions, see the host route layer). Drop the old stream on root\n // switches; syncGitSubscription re-evaluates it below.\n disposeGitEvents?.()\n disposeGitEvents = undefined\n const previewOpen = stores.preview.getSnapshot().open\n lastPreviewOpen = previewOpen\n layoutSetRoot(stores.layout, root, previewOpen)\n stores.explorer.setRoot(root)\n stores.scm.setRoot(root)\n stores.preview.setRoot(root)\n\n syncGitSubscription()\n }\n\n /**\n * Keep the git change stream in lockstep with SCM-tab visibility:\n * opening the changes tab starts the subscription (and fetches status\n * once immediately — the host poll only ticks on its own cadence);\n * switching away closes it, so git polling happens only while the SCM\n * panel is actually on screen. Idempotent — explorer state changes\n * (expansion, selection) call it and it no-ops unless the tab flipped.\n */\n const syncGitSubscription = (): void => {\n const root = currentRoot\n const want = root !== '' && stores.explorer.getSnapshot().activeTab === 'changes'\n if (want && disposeGitEvents === undefined) {\n void stores.scm.refresh()\n disposeGitEvents = subscribePanelEvents(root, (event) => {\n if (event.kind === 'git') {\n // The host status is the only truth; land it directly.\n stores.scm.update((prev) => (prev.root !== root ? prev : { ...prev, status: event.status, loading: false }))\n // The index/worktree moved: every open diff tab is stale by now.\n void stores.preview.handleGitChange(root)\n }\n if (event.kind === 'gitUnavailable') {\n // The host could not run git at all: land the friendly\n // unavailable state once instead of a \"not a repository\" view.\n stores.scm.update((prev) => (prev.root !== root ? prev : { ...prev, status: null, loading: false, gitMissing: true }))\n }\n })\n } else if (!want && disposeGitEvents !== undefined) {\n disposeGitEvents()\n disposeGitEvents = undefined\n }\n }\n disposers.push(ctx.sessions.list.subscribe(bindRoot))\n disposers.push(stores.explorer.subscribe(syncGitSubscription))\n bindRoot()\n\n // Header tool-dock bridge (dsh-term's AnimatedDock): the \"file panel\"\n // icon toggles this plugin's explorer through a window event, so the two\n // bundles stay decoupled. We also mirror explorerCollapsed back so the\n // dock icon highlights in lockstep.\n const onToggleFile = (): void => layout.toggleExplorer()\n window.addEventListener('dsh-dock:toggle-filepanel', onToggleFile)\n const unsubFileState = stores.layout.subscribe(() => {\n window.dispatchEvent(new CustomEvent('dsh-dock:filepanel-state', {\n detail: !stores.layout.getSnapshot().explorerCollapsed,\n }))\n })\n window.dispatchEvent(new CustomEvent('dsh-dock:filepanel-state', {\n detail: !stores.layout.getSnapshot().explorerCollapsed,\n }))\n\n // Mirror the preview open state into the layout store (single source: the\n // preview store), and play the enter animation when the region opens.\n const mirrorPreviewOpen = (): void => {\n const open = stores.preview.getSnapshot().open\n if (open === lastPreviewOpen) return\n lastPreviewOpen = open\n stores.layout.update((prev) => ({ ...prev, previewOpen: open }))\n if (open) {\n const col = document.querySelector<HTMLElement>('[data-filemgr-preview-col]')\n col?.classList.add('filemgr-preview-enter')\n setTimeout(() => col?.classList.remove('filemgr-preview-enter'), 300)\n }\n }\n disposers.push(stores.preview.subscribe(mirrorPreviewOpen))\n\n // Language mirroring (the shell owns <html lang>; the dictionary follows).\n let langObserver: MutationObserver | undefined\n const syncLanguage = (): void => {\n setLanguage(document.documentElement.lang?.startsWith('zh') ? 'zh' : 'en')\n }\n langObserver = new MutationObserver(syncLanguage)\n langObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n syncLanguage()\n\n // Mount everything. DOM failures degrade the panels, never the GUI.\n try {\n layout.mount()\n mountPanels(stores, () => layout.toggleExplorer(), onReference, onAddFileReference)\n } catch (error) {\n console.error('[dsh-filemgr] mount failed:', error)\n }\n\n // The '@' tree-browser modal host: a dedicated root appended to body so\n // the modal portals above the shell chrome regardless of panel state.\n const pickerHostEl = document.createElement('div')\n document.body.appendChild(pickerHostEl)\n const pickerRoot = createRoot(pickerHostEl)\n pickerRoot.render(createElement(FilePickerHost, { ctx, api: panelApi }))\n\n // Chat file-reference clicks (issue #314): recognize workspace paths in\n // transcript code spans and locate them in the Explorer / Preview.\n const onFileRefClick = (event: MouseEvent): void => {\n try {\n handleFileRefClick(stores, panelApi, event)\n } catch (error) {\n // A broken locate must never break the transcript's own clicks.\n console.error('[dsh-filemgr] file ref locate failed:', error)\n }\n }\n document.addEventListener('click', onFileRefClick)\n\n // Debounced persists (explorer/scm/preview) may be pending when the page\n // hides; flush them so a close/background never drops the last 150ms.\n const flushOnHide = (): void => stores.flushNow()\n const onVisibilityChange = (): void => {\n if (document.visibilityState === 'hidden') flushOnHide()\n }\n window.addEventListener('pagehide', flushOnHide)\n document.addEventListener('visibilitychange', onVisibilityChange)\n\n return () => {\n flushOnHide()\n window.removeEventListener('pagehide', flushOnHide)\n window.removeEventListener('dsh-dock:toggle-filepanel', onToggleFile)\n unsubFileState()\n document.removeEventListener('visibilitychange', onVisibilityChange)\n document.removeEventListener('click', onFileRefClick)\n disposeGitEvents?.()\n langObserver?.disconnect()\n pickerRoot.unmount()\n pickerHostEl.remove()\n for (const dispose of disposers) dispose()\n layout.dispose()\n }\n }\n const syncUi = (): void => {\n if (enabled() && disposeUi === undefined) {\n disposeUi = mountUi()\n } else if (!enabled() && disposeUi !== undefined) {\n disposeUi()\n disposeUi = undefined\n }\n }\n syncUi()\n const unsubscribeSettings = panelScope?.subscribe(syncUi)\n return () => {\n unsubscribeSettings?.()\n if (disposeUi !== undefined) {\n disposeUi()\n disposeUi = undefined\n }\n }\n }, 'dsh-filemgr: wiring')\n}\n"],"mappings":";;;;;;;;;;;;;;EAYA,MAAM,kBAA8B;GAAE,MAAM;GAAY,SAAS;EAA0B;;EAG3F,eAAe,KAAQ,MAAc,SAA6D;GAChG,IAAI;GACJ,IAAI;IACF,WAAW,MAAM,MAAM,MAAM;KAC3B,QAAQ;KACR,SAAS,EAAE,gBAAgB,mBAAmB;KAC9C,MAAM,KAAK,UAAU,OAAO;IAC9B,CAAC;GACH,QAAQ;IACN,OAAO;KAAE,IAAI;KAAO,OAAO;IAAgB;GAC7C;GACA,IAAI;IACF,MAAM,WAAW,MAAM,SAAS,KAAK;IACrC,IAAI,OAAO,aAAa,YAAY,aAAa,MAAM,OAAO;KAAE,IAAI;KAAO,OAAO;IAAgB;IAClG,MAAM,SAAS;IACf,IAAI,OAAO,OAAO,MAAM,OAAO;KAAE,IAAI;KAAM,OAAO,OAAO;IAAW;IACpE,OAAO;KAAE,IAAI;KAAO,OAAQ,OAAO,SAAoC;IAAgB;GACzF,QAAQ;IACN,OAAO;KAAE,IAAI;KAAO,OAAO;IAAgB;GAC7C;EACF;;EAGA,IAAa,WAAb,MAAsB;;GAEpB,KAAK,MAAc,MAAkD;IACnE,OAAO,KAAK,iBAAiB;KAAE;KAAM;IAAK,CAAC;GAC7C;;GAGA,KAAK,MAAc,MAAc,SAAoD;IACnF,OAAO,KAAK,iBAAiB;KAAE;KAAM;KAAM;IAAQ,CAAC;GACtD;;GAGA,MAAM,MAAc,MAAc,SAAiB,WAA+D;IAChH,OAAO,KAAK,kBAAkB;KAAE;KAAM;KAAM;KAAS;IAAU,CAAC;GAClE;;GAGA,OAAO,MAAc,OAAmD;IACtE,OAAO,KAAK,mBAAmB;KAAE;KAAM;IAAM,CAAC;GAChD;;GAGA,OAAO,MAAc,MAAoD;IACvE,OAAO,KAAK,mBAAmB;KAAE;KAAM;IAAK,CAAC;GAC/C;;GAGA,OAAO,MAAc,MAAoD;IACvE,OAAO,KAAK,mBAAmB;KAAE;KAAM;IAAK,CAAC;GAC/C;;GAGA,gBAAgB,MAAc,MAAoD;IAChF,OAAO,KAAK,8BAA8B;KAAE;KAAM;IAAK,CAAC;GAC1D;;GAGA,OAAO,MAAc,MAAc,SAAuD;IACxF,OAAO,KAAK,mBAAmB;KAAE;KAAM;KAAM;IAAQ,CAAC;GACxD;;GAGA,MAAM,MAAc,MAAoD;IACtE,OAAO,KAAK,kBAAkB;KAAE;KAAM;IAAK,CAAC;GAC9C;;GAGA,QAAQ,MAAc,MAAoD;IACxE,OAAO,KAAK,qBAAqB;KAAE;KAAM;IAAK,CAAC;GACjD;;GAGA,UAAU,MAA4D;IACpE,OAAO,KAAK,uBAAuB,EAAE,KAAK,CAAC;GAC7C;;GAGA,QAAQ,MAAc,MAAc,QAA8D;IAChG,OAAO,KAAK,qBAAqB;KAAE;KAAM;KAAM;IAAO,CAAC;GACzD;;GAGA,SAAS,MAAc,OAAyD;IAC9E,OAAO,KAAK,sBAAsB;KAAE;KAAM;IAAM,CAAC;GACnD;;GAGA,WAAW,MAAc,OAAyD;IAChF,OAAO,KAAK,wBAAwB;KAAE;KAAM;IAAM,CAAC;GACrD;;GAGA,WAAW,MAAc,OAAyD;IAChF,OAAO,KAAK,wBAAwB;KAAE;KAAM;IAAM,CAAC;GACrD;EACF;;;;;;;;;EAgBA,SAAgB,qBAAqB,MAAc,UAAyD;GAC1G,MAAM,SAAS,IAAI,YAAY,wBAAwB,mBAAmB,IAAI,GAAG;GACjF,OAAO,iBAAiB,WAAW,QAAQ;IACzC,IAAI;KAEF,SADc,KAAK,MAAO,IAAqB,IAClC,CAAC;IAChB,QAAQ,CAER;GACF,CAAC;GACD,aAAa;IAAE,OAAO,MAAM;GAAE;EAChC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECzEA,SAAgB,mBAAiD,OAAsC;GACrG,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAoB,MAAM,eAAe,IAAI;GAC1D,MAAM,EAAE,OAAO,eAAe;GAC9B,IAAI,CAAC,MAAM,WAAW,OAAO;GAC7B,MAAM,QAAQ,MAAM,EAAE,MAAM,QAAQ;GACpC,MAAM,cAAc,MAAM,EAAE,MAAM,cAAc;GAChD,MAAM,UAAU,CAAC,MAAM,SAAS,MAAM,WAAW,MAAM;GACvD,MAAM,WAAW,eAAe,QAAQ;GACxC,MAAM,YAAY,WAAW,GAAGA,iCAAI,SAAS,GAAGA,iCAAI,SAASA,iCAAI;GAGjE,MAAM,SAAS,eAAe,OAE1B,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,iCAAI;cAApB,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAWA,iCAAI;eAArB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;MAAa;gBAAQ;KAAY,CAAA,GACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;MAAa,OAAO;gBAAc;KAAkB,CAAA,CACrE;QACL,MAAM,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAWA,iCAAI;KAAS,OAAO,MAAM,EAAE,kBAAkB;eAAI,MAAM,EAAE,kBAAkB;IAAQ,CAAA,IAAI,IACrH;QAGL,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;IACE,MAAK;IACL,WAAWA,iCAAI;IACf,iBAAe;IACf,cAAY,GAAG,MAAM,EAAE,OAAO,sBAAsB,iBAAiB,EAAE,IAAI;IAC3E,eAAe;KAAE,QAAQ,CAAC,IAAI;IAAE;cALlC;KAOE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;gBAArB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,iCAAI;OAAa;iBAAQ;MAAY,CAAA,GACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,iCAAI;OAAa,OAAO;iBAAc;MAAkB,CAAA,CACrE;;KACL,MAAM,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;MAAS,OAAO,MAAM,EAAE,kBAAkB;gBAAI,MAAM,EAAE,kBAAkB;KAAQ,CAAA,IAAI;KACxH,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MACE,OAAM;MACN,QAAO;MACP,SAAQ;MACR,MAAK;MACL,OAAM;MACN,WAAW,OAAO,GAAGA,iCAAI,QAAQ,GAAGA,iCAAI,gBAAgBA,iCAAI;gBAE5D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OACE,GAAE;OACF,MAAK;MACN,CAAA;KACE,CAAA;IACC;;GAMZ,IAAI,CAAC,MAAM,SACT,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAW;cAAf,CACG,QACA,WAEG,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,iCAAI;eAClB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,iCAAI;MAAY,MAAK;gBAAU,MAAM,EAAE,qBAAqB;KAAK,CAAA;IAC5E,CAAA,IAEL,IACF;;GAGR,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAW;cAAf,CACG,QACA,WAEG,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,iCAAI;eAApB;MACG,CAAC,MAAM,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,iCAAI;OAAU,MAAK;iBAAU,MAAM,EAAE,mBAAmB;MAAK,CAAA,IAAI;MACjG,MAAM;MACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,iCAAI;iBAApB;QACG,MAAM,SAEH,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;SAAG,WAAWA,iCAAI;SAAQ,MAAK;mBAA/B,CACG,MAAM,EAAE,qBAAqB,GAAG,MAAM,eAAe,QAAQ,MAAM,eAAe,EAClF;aAEH;QACJ,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,iCAAI;SACf,UAAU,CAAC,MAAM,SAAS,MAAM;SAChC,SAAS,MAAM;mBAEd,MAAM,EAAE,kBAAkB;QACrB,CAAA;QACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,iCAAI;SACf,UAAU;SACV,SAAS,MAAM;mBAEd,MAAM,EAAE,CAAC,MAAM,SAAS,kBAAkB,iBAAiB;QACtD,CAAA;OACL;;KACF;SAEL,IACF;;EAER;;EA4EA,SAAgB,aAAa,OAO1B;GACD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,iCAAI;cAApB;KACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,iCAAI;gBAApB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OAAO,WAAWA,iCAAI;OAAO,SAAS,MAAM;iBAAK,MAAM;MAAa,CAAA,GACnE,MAAM,aAEH,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;OAAM,WAAWA,iCAAI;iBAArB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,iCAAI;kBAAQ,MAAM;OAAsB,CAAA,GACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,iCAAI;QACf,UAAU,MAAM;QAChB,SAAS,MAAM;kBAEd,MAAM;OACD,CAAA,CACJ;WAEN,IACD;;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,IAAI,MAAM;MACV,WAAWA,iCAAI;MACf,OAAO,MAAM;MACb,UAAU,MAAM;MAChB,WAAW,UAAU;OAAE,MAAM,OAAO,MAAM,OAAO,KAAK;MAAE;gBAL1D;OAOE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,OAAM;kBAAI,MAAM;OAAqB,CAAA;OAC7C,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,OAAM;kBAAQ,MAAM;OAAgB,CAAA;OAC5C,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,OAAM;kBAAS,MAAM;OAAiB,CAAA;MACxC;;KACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,iCAAI;gBAAO,MAAM;KAAQ,CAAA;IACpC;;EAET;;;;EC5FA,SAAgB,aAAa,OAA0B;GACrD,OAAO;IACL;IACA,SAAQ,UAAS,OAAO,UAAU,YAAY,OAAO,KAAK,IAAI;IAC9D,QAAQ,SAAS;KACf,MAAM,UAAU,KAAK,KAAK;KAC1B,IAAI,YAAY,IAAI,OAAO,EAAE,MAAM,QAAQ;KAC3C,IAAI,YAAY,QAAQ,OAAO;MAAE,MAAM;MAAO,OAAO;KAAK;KAC1D,IAAI,YAAY,SAAS,OAAO;MAAE,MAAM;MAAO,OAAO;KAAM;IAE9D;GACF;EACF;;;;;;;;;EAsBA,IAAa,WAAb,MAAyB;GAaJ;GAZnB;GACA,yBAA0B,IAAI,IAAwB;GACtD,4BAA6B,IAAI,IAAgB;;GAEjD;GACA,WAAmB;GACnB,SAAiB;GACjB,SAAiB;GACjB;;GAGA,YACE,OACA,OACA;IAFiB,KAAA,QAAA;IAGjB,KAAK,QAAQ,IAAI,IAAI,MAAM,KAAI,SAAQ,CAAC,KAAK,OAAO,IAAI,CAAC,CAAC;IAC1D,KAAK,eAAe,MAAM,gBAAgB;KAAE,KAAK,QAAQ;IAAE,CAAC;GAC9D;;;;;GAMA,UAAgB;IACd,IAAI,KAAK,UAAU;IACnB,KAAK,WAAW;IAChB,KAAK,aAAa;IAClB,KAAK,UAAU,MAAM;GACvB;;GAGA,KAAQ,SAAoC;IAC1C,MAAM,SAAA,GAAA,uCAAA,oBAAA,CAA4B,QAAQ,CAAC;IAC3C,KAAK,UAAU,UAAU;KAAE,MAAM,IAAI,QAAQ,CAAC;IAAE,CAAC;IACjD,OAAO;GACT;;GAGA,QAAmB;IACjB,MAAM,WAAW,KAAK,MAAM,YAAY;IACxC,MAAM,OAAO,KAAK,KAAK;IACvB,OAAO;KACL,WAAW,SAAS,WAAW;KAC/B,SAAS,SAAS,WAAW;KAC7B,UAAU,SAAS;KACnB,OAAO,KAAK,SAAS;KACrB,SAAS,KAAK,MAAK,SAAQ,KAAK,QAAQ,KAAA,CAAS;KACjD,QAAQ,KAAK;KACb,QAAQ,KAAK;KACb,GAAG,KAAK,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,KAAK,aAAa;IAC9E;GACF;;GAGA,MAAM,OAA2B;IAC/B,MAAM,OAAO,KAAK,OAAO,KAAK;IAC9B,MAAM,SAAS,KAAK,OAAO,IAAI,KAAK;IACpC,IAAI,WAAW,KAAA,GACb,OAAO;KAAE,MAAM,KAAK,OAAO,KAAK,aAAa,KAAK,CAAC;KAAG,YAAY,KAAK,OAAO,KAAK;KAAG,SAAS;IAAM;IAEvG,MAAM,QAAQ,OAAO,QAAQ,EAAE,MAAM,QAAiB,IAAI,KAAK,MAAM,OAAO,IAAI;IAChF,OAAO;KACL,MAAM,OAAO;KACb,YAAY,OAAO,SAAS;KAC5B,SAAS,UAAU,KAAA;IACrB;GACF;;GAGA,UAAuB;IACrB,OAAO;KACL,OAAO,OAAO,SAAS;MAAE,KAAK,MAAM,OAAO;OAAE;OAAM,OAAO;MAAM,CAAC;KAAE;KACnE,aAAa,UAAU;MACrB,KAAK,MAAM,OAAO;OAAE,MAAM,KAAK,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,UAAU,KAAK,CAAC;OAAG,OAAO;MAAK,CAAC;KAC3F;KACA,YAAY;MAAE,KAAU,KAAK;KAAE;KAC/B,eAAe;MACb,IAAI,KAAK,OAAO,SAAS,KAAK,CAAC,KAAK,QAAQ;MAC5C,KAAK,OAAO,MAAM;MAClB,KAAK,SAAS;MACd,KAAK,eAAe,KAAA;MACpB,KAAK,QAAQ;KACf;IACF;GACF;;;;;;;;;;;;GAaA,MAAM,OAAsB;IAC1B,MAAM,OAAO,KAAK,KAAK;IACvB,MAAM,QAAQ,KAAK,QAAO,SAAQ,KAAK,QAAQ,KAAA,CAAS;IACxD,IAAI,KAAK,WAAW,KAAK,KAAK,UAAU,MAAM,WAAW,KAAK,QAAQ;IACtE,MAAM,gBAAgB,MAAM,KAAI,SAAQ,KAAK,EAAE;IAG/C,MAAM,SAAS,IAAI,IAAI,KAAK,KAAI,SAAQ,KAAK,KAAK,CAAC;IACnD,KAAK,SAAS;IACd,KAAK,SAAS;IACd,KAAK,eAAe,KAAA;IACpB,KAAK,QAAQ;IACb,MAAM,yBAAS,IAAI,IAAY;IAC/B,MAAM,QAAQ,KAAK,aAAa;IAChC,IAAI,UAAU,KAAA,GAAW;KACvB,MAAM,SAAS,MAAM,MAAM,OAAO,aAAa;KAC/C,IAAI,OAAO;WACJ,MAAM,SAAS,OAAO,QACzB,IAAI,MAAM,QAAQ,OAAO,IAAI,MAAM,KAAK;KAAA,OAG1C,KAAK,eAAe,OAAO;IAE/B,OACE,KAAK,MAAM,QAAQ,OACjB,IAAI,MAAM,KAAK,IAAK,GAAG,OAAO,IAAI,KAAK,KAAK;IAGhD,KAAK,MAAM,SAAS,QAClB,IAAI,OAAO,IAAI,KAAK,GAAG,KAAK,OAAO,OAAO,KAAK;IAEjD,KAAK,SAAS;IACd,KAAK,SAAS,OAAO,SAAS,OAAO;IACrC,KAAK,QAAQ;GACf;;GAGA,eAAyD;IACvD,MAAM,YAAY,KAAK;IACvB,OAAO,OAAO,WAAW,WAAW,aAAa,YAAY,KAAA;GAC/D;;;;;;;;GASA,OAA+B;IAC7B,MAAM,OAAuB,CAAC;IAC9B,KAAK,MAAM,CAAC,OAAO,WAAW,KAAK,QAAQ;KACzC,MAAM,OAAO,KAAK,OAAO,KAAK;KAC9B,IAAI,OAAO,OAAO;MAChB,IAAI,KAAK,OAAO,KAAK,GAAG,KAAK,KAAK;OAAE;OAAO,IAAI;QAAE;QAAO,IAAI;OAAQ;OAAG,WAAW,KAAK,MAAM,KAAK;MAAE,CAAC;MACrG;KACF;KACA,IAAI,OAAO,SAAS,KAAK,OAAO,KAAK,aAAa,KAAK,CAAC,GAAG;KAC3D,MAAM,QAAQ,KAAK,MAAM,OAAO,IAAI;KACpC,IAAI,UAAU,KAAA,GAAW,KAAK,KAAK;MAAE;MAAO,IAAI;OAAE;OAAO,IAAI;MAAQ;MAAG,KAAK,KAAA;KAAU,CAAC;UACnF,IAAI,MAAM,SAAS,SAAS,KAAK,KAAK;MAAE;MAAO,IAAI;OAAE;OAAO,IAAI;MAAQ;MAAG,WAAW,KAAK,MAAM,KAAK;KAAE,CAAC;UACzG,KAAK,KAAK;MAAE;MAAO,IAAI;OAAE;OAAO,IAAI;OAAO,OAAO,MAAM;MAAM;MAAG,WAAW,KAAK,MAAM,OAAO,MAAM,KAAK;KAAE,CAAC;IACnH;IACA,OAAO;GACT;GAEA,MAAc,MAAM,OAAiC;IACnD,MAAM,KAAK,MAAM,MAAM,KAAK;IAC5B,OAAO,CAAC,KAAK,OAAO,KAAK;GAC3B;GAEA,MAAc,MAAM,OAAe,OAAkC;IACnE,MAAM,KAAK,MAAM,IAAI,OAAO,KAAK;IAKjC,IAAI,KAAK,OAAO,KAAK,CAAC,CAAC,QAAQ,OAAO;IACtC,OAAO,KAAK,UAAU,CAAC,GAAG,WAAW;GACvC;GAEA,MAAc,OAAe,MAAwB;IACnD,KAAK,OAAO,IAAI,OAAO,IAAI;IAC3B,KAAK,SAAS;IACd,KAAK,eAAe,KAAA;IACpB,KAAK,QAAQ;GACf;GAEA,OAAe,OAA0B;IACvC,MAAM,OAAO,KAAK,MAAM,IAAI,KAAK;IAGjC,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,8BAA8B,OAAO;IAC7E,OAAO;GACT;GAEA,aAA+C;IAC7C,OAAO,KAAK,MAAM,YAAY;GAChC;GAEA,aAAqB,OAAwB;IAC3C,OAAQ,KAAK,WAAW,CAAC,CAAC,QAAgD;GAC5E;GAEA,UAAkB,OAAwB;IACxC,OAAQ,KAAK,WAAW,CAAC,CAAC,OAA+C;GAC3E;GAEA,YAAyD;IACvD,OAAO,KAAK,WAAW,CAAC,CAAC;GAC3B;GAEA,OAAe,OAAwB;IACrC,MAAM,OAAO,KAAK,UAAU;IAC5B,OAAO,SAAS,KAAA,KAAa,OAAO,OAAO,MAAM,KAAK;GACxD;GAEA,UAAwB;IACtB,KAAK,MAAM,YAAY,KAAK,WAAW,SAAS;GAClD;EACF;;;;EC9ZA,IAAa,oCAAb,MAA+C;GAC7C;GACA;;GAGA,YAAY,OAAgD;IAC1D,KAAK,OAAO,IAAI,SAAS,OAAO,CAC9B,aAAa,SAAS,CACxB,CAAC;IACD,KAAK,QAAQ,KAAK,KAAK,WAAW,KAAK,WAAW,CAAC;GACrD;GAEA,aAAmD;IACjD,OAAO;KACL,GAAG,KAAK,KAAK,MAAM;KACnB,SAAS,KAAK,KAAK,MAAM,SAAS;IACpC;GACF;;;;;GAMA,SAAsC;IACpC,OAAO;KAAE,OAAO,EAAE,qBAAqB,KAAK,MAAM;KAAG,GAAG,KAAK,KAAK,QAAQ;IAAE;GAC9E;;;;;GAMA,UAAgB;IACd,KAAK,KAAK,QAAQ;GACpB;EACF;;;;;;EAaA,SAAgB,wBAAwB,OAAqC;GAC3E,MAAM,EAAE,MAAM;GACd,MAAM,QAAQ,MAAM,wBAAuB,aAAY,QAAQ;GAC/D,MAAM,WAAW,CAAC,MAAM;GACxB,MAAM,aAAa;IACjB,iBAAiB,EAAE,qBAAqB;IACxC,YAAY,EAAE,gBAAgB;IAC9B,cAAc,EAAE,wBAAwB;IACxC;GACF;GACA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,oBAAD;IACK;IACH,UAAS;IACT,gBAAe;IACR;IACP,QAAQ,MAAM;IACd,WAAW,MAAM;cAEjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;KACE,IAAG;KACH,OAAO,EAAE,kBAAkB;KAC3B,MAAM,EAAE,sBAAsB;KAC9B,cAAc,EAAE,kBAAkB;KAClC,SAAS,EAAE,aAAa;KACxB,UAAU,EAAE,cAAc;KAC1B,GAAI;KACJ,GAAI,MAAM;KACV,SAAS,SAAS;MAAE,MAAM,KAAK,WAAW,IAAI;KAAE;KAChD,eAAe;MAAE,MAAM,WAAW,SAAS;KAAE;IAC9C,CAAA;GACiB,CAAA;EAExB;;;;EC7FA,SAAS,iBAAiB,OAA8B;GACtD,OAAO,MAAM,gBAAgB,WAAW,MAAM,WAAW;EAC3D;;;;;;;;;;EAWA,SAAgB,uBAAuB,OAAqB,IAAiB,MAAoC;GAC/G,IAAI,CAAC,iBAAiB,KAAK,GAAG,aAAa,CAAC;GAC5C,MAAM,eAAe;GAErB,MAAM,SAAS,MAAM;GACrB,MAAM,aAAa,KAAK,cAAc;GACtC,MAAM,YAAY,MAAM;GACxB,MAAM,UAAU,KAAK;GAErB,IAAI,QAAuB;GAC3B,IAAI,eAA8B;GAClC,IAAI,cAAc;GAClB,IAAI,aAAa;GACjB,IAAI,UAA+B;GAEnC,MAAM,qBAA2B;IAC/B,IAAI,iBAAiB,MAAM;IAC3B,cAAc;IACd,KAAK,QAAQ,YAAY;GAC3B;GAEA,MAAM,qBACJ,KACA,YACiB;IACjB,OAAO,iBAAiB,KAAK,OAAO;IACpC,aAAa,OAAO,oBAAoB,KAAK,OAAO;GACtD;GAEA,MAAM,gBAAgB,YAA4B;IAChD,MAAM,SAAS,UAAU,SAAS,UAAU,UAAU;IACtD,OAAO,KAAK,QAAQ,YAAY,MAAM;GACxC;GAEA,MAAM,cAAc,MAAqD;IACvE,IAAI,CAAC,YAAY;IACjB,aAAa;IACb,IAAI,UAAU,MAAM;KAClB,qBAAqB,KAAK;KAC1B,QAAQ;IACV;IACA,aAAa;IACb,IAAI,aAAa;IACjB,IAAI,MAAM,KAAA,KAAa,aAAa,KAAK,OAAO,EAAE,YAAY,UAC5D,aAAa,aAAa,EAAE,OAAO;IAErC,KAAK,MAAM,UAAU;IACrB,UAAU;GACZ;GAEA,MAAM,qBAAqB,MAA0B;IACnD,IAAI,CAAC,YAAY;IACjB,IAAI,EAAE,YAAY,GAAG;KAEnB,WAAW,CAAC;KACZ;IACF;IACA,eAAe,aAAa,EAAE,OAAO;IACrC,IAAI,UAAU,MACZ,QAAQ,4BAA4B;KAClC,QAAQ;KACR,aAAa;IACf,CAAC;GAEL;GACA,MAAM,mBAAmB,MAA0B,WAAW,CAAC;GAC/D,MAAM,uBAAuB,MAA0B,WAAW,CAAC;GACnE,MAAM,iBAAiB,MAAwB,WAAW,CAAC;GAC3D,MAAM,0BAAgC,WAAW;GAGjD,MAAM,qBAAqB,SAAS,KAAK,MAAM;GAC/C,MAAM,iBAAiB,SAAS,KAAK,MAAM;GAC3C,SAAS,KAAK,MAAM,aAAa;GACjC,SAAS,KAAK,MAAM,SAAS;GAC7B,MAAM,QAAQ,GAAG,QAAQ,kBAAkB;GAC3C,OAAO,aAAa,wBAAwB,EAAE;GAE9C,MAAM,gBAAsB;IAC1B,SAAS,KAAK,MAAM,aAAa;IACjC,SAAS,KAAK,MAAM,SAAS;IAC7B,OAAO,gBAAgB,sBAAsB;GAC/C;GAEA,IAAI,GAAG,mBACL,IAAI;IACF,GAAG,kBAAkB,SAAS;IAC9B,GAAG,iBAAiB,sBAAsB,iBAAiB;GAC7D,QAAQ,CAER;GAGF,MAAM,uBAA6B;IACjC,IAAI;KACF,IAAI,GAAG,yBAAyB,GAAG,oBAAoB,SAAS,GAC9D,GAAG,sBAAsB,SAAS;IAEtC,QAAQ,CAER;IACA,GAAG,oBAAoB,sBAAsB,iBAAiB;GAChE;GAEA,MAAM,YAAY;IAChB,kBAAkB,eAAe,iBAAiB;IAClD,kBAAkB,aAAa,eAAe;IAC9C,kBAAkB,iBAAiB,mBAAmB;IACtD,kBAAkB,WAAW,aAAa;IAC1C,kBAAkB,cAAc,WAAW,CAAC;GAC9C;GACA,gBAAgB;IACd,QAAQ;IACR,eAAe;IACf,KAAK,MAAM,WAAW,WAAW,QAAQ;GAC3C;GACA,OAAO;EACT;;;;EC/IA,MAAM,+BAAe,IAAI,IAAI;GAAC;GAAM;GAAY;EAAK,CAAC;;EAEtD,MAAM,2BAAW,IAAI,IAAI;GAAC;GAAQ;GAAO;EAAO,CAAC;;EAEjD,MAAM,2BAAW,IAAI,IAAI,CAAC,QAAQ,OAAO,CAAC;;EAE1C,MAAM,0BAAU,IAAI,IAAI,CAAC,KAAK,CAAC;;EAE/B,MAAM,0BAAU,IAAI,IAAI,CAAC,KAAK,CAAC;;EAE/B,MAAM,2BAAW,IAAI,IAAI;GAAC;GAAO;GAAQ;GAAO;EAAK,CAAC;EACtD,MAAM,4BAAY,IAAI,IAAI;GAAC;GAAO;GAAQ;EAAK,CAAC;EAChD,MAAM,0BAAU,IAAI,IAAI;GAAC;GAAO;GAAQ;EAAK,CAAC;;EAE9C,MAAM,4BAAY,IAAI,IAAI;GAAC;GAAO;GAAO;GAAQ;GAAO;GAAQ;GAAO;GAAO;GAAO;EAAM,CAAC;;EAE5F,MAAM,2BAAW,IAAI,IAAI;GACvB;GAAM;GAAO;GAAM;GAAO;GAAO;GAAO;GAAQ;GAAS;GAAO;GAAQ;GACxE;GAAO;GAAQ;GAAQ;GAAO;GAAM;GAAQ;GAAO;GAAQ;GAAM;GAAM;GACvE;GAAQ;GAAK;GAAK;GAAO;GAAO;GAAM;GAAM;GAAO;GAAO;GAAM;GAAS;GACzE;GAAO;GAAU;GAAS;GAAO;GAAO;GAAO;GAAO;GAAQ;GAAO;GACrE;GAAc;GAAY;GAAW;GAAS;GAAU;GAAO;GAAO;GAAK;GAC3E;GAAM;GAAO;GAAO;GAAM;GAAO;GAAS;GAAU;GAAM;GAAO;GAAO;GACxE;GAAM;GAAM;GAAO;GAAO;GAAK;GAAK;GAAO;GAAM;GAAO;GAAM;GAAO;GACrE;GAAY;GAAO;GAAM;GAAO;GAAgB;GAAgB;GAChE;GAAY;GAAW;GAAS;GAAO;GAAQ;EACjD,CAAC;;EAED,MAAM,6BAAa,IAAI,IAAI;GACzB;GAAW;GAAW;GAAU;GAAa;GAAgB;GAAW;GACxE;GAAY;GAAc;GAAY;GAAW;GAAY;EAC/D,CAAC;;;;;;;EAOD,MAAM,qCAAqB,IAAI,IAAI;GACjC;GAAc;GAAkB;GAAe;GAAQ;GACvD;GAAmB;GAAoB;GAAa;GAAU;GAC9D;GAAe;GAAoB;GAAoB;GAAY;GACnE;GAAa;GAAkB;GAAgB;GAAiB;GAChE;GAAiB;GAAmB;GAAoB;EAC1D,CAAC;;EAGD,SAAgB,kBAAkB,MAAkC;GAElE,MAAM,SADO,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,KAAA,CACnB,YAAY;GAC/B,MAAM,MAAM,MAAM,YAAY,GAAG;GAGjC,MAAM,MAAM,MAAM,OAAO,MACpB,MAAM,IAAI,MAAM,MAAM,MAAM,CAAC,IAAI,MAAM,MAAM,CAAC,IAC9C,MAAM,IAAI,MAAM,MAAM,MAAM,CAAC,IAAI;GACtC,MAAM,OAAO,MAAM,IAAI,MAAM,MAAM,GAAG,GAAG,IAAI;GAC7C,IAAI,MAAM,OAAO,OAAO,mBAAmB,IAAI,KAAK,GAAG,OAAO;GAC9D,IAAI,QAAQ,MAAM,WAAW,IAAI,IAAI,GAAG,OAAO;GAC/C,IAAI,QAAQ,IAAI,OAAO;GACvB,IAAI,aAAa,IAAI,GAAG,GAAG,OAAO;GAClC,IAAI,SAAS,IAAI,GAAG,GAAG,OAAO;GAC9B,IAAI,SAAS,IAAI,GAAG,GAAG,OAAO;GAC9B,IAAI,QAAQ,IAAI,GAAG,GAAG,OAAO;GAC7B,IAAI,QAAQ,IAAI,GAAG,GAAG,OAAO;GAC7B,IAAI,SAAS,IAAI,GAAG,GAAG,OAAO;GAC9B,IAAI,UAAU,IAAI,GAAG,GAAG,OAAO;GAC/B,IAAI,QAAQ,IAAI,GAAG,GAAG,OAAO;GAC7B,IAAI,UAAU,IAAI,GAAG,GAAG,OAAO;GAC/B,IAAI,SAAS,IAAI,GAAG,GAAG,OAAO;GAC9B,OAAO;EACT;;EAGA,SAAgB,eAAe,MAAmC;GAChE,OAAO,SAAS,cAAc,SAAS,UAAU,SAAS,UAAU,SAAS,SAAS,SAAS;EACjG;;EAGA,SAAgB,WAAW,MAAmC;GAC5D,OAAO,SAAS,WAAW,SAAS,SAAS,SAAS,UAAU,SAAS,WACpE,SAAS,SAAS,SAAS,iBAAiB,SAAS;EAC5D;;EAGA,SAAgB,QAAQ,MAAc,MAAc,MAAkC;GACpF,OAAO,GAAG,KAAK,QAAQ,KAAK,QAAQ;EACtC;;EAgBA,SAAgB,UAAU,MAAsB;GAC9C,MAAM,MAAM,KAAK,YAAY,GAAG;GAChC,OAAO,MAAM,IAAI,KAAK,MAAM,GAAG,GAAG,IAAI;EACxC;;;;;;;;;EAUA,SAAgB,cAAc,MAAc,MAAc,OAAuB;GAC/E,OAAO,qBAAqB,mBAAmB,IAAI,EAAE,QAAQ,mBAAmB,IAAI,EAAE,KAAK;EAC7F;;;;;;;;;;;;;;;;EClHA,SAAgB,iBAAiB,KAAa,KAAa,KAAa,UAA0B;GAChG,IAAI;IACF,MAAM,MAAM,aAAa,QAAQ,GAAG;IACpC,IAAI,QAAQ,MAAM,OAAO;IACzB,MAAM,QAAQ,OAAO,GAAG;IACxB,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;IACpC,IAAI,QAAQ,OAAO,QAAQ,KAAK,OAAO;IACvC,OAAO;GACT,QAAQ;IACN,OAAO;GACT;EACF;;EAGA,SAAgB,kBAAkB,KAAa,OAAqB;GAClE,IAAI;IACF,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,CAAC;IACpC,IAAI,aAAa,QAAQ,GAAG,MAAM,KAAK;IACvC,aAAa,QAAQ,KAAK,GAAG;GAC/B,QAAQ,CAER;EACF;;EAmBA,SAAgB,gBAAgB,UAAU,KAAgB;GACxD,IAAI;GACJ,IAAI,UAA+B;GACnC,MAAM,cAAoB;IACxB,IAAI,UAAU,KAAA,GAAW,aAAa,KAAK;IAC3C,QAAQ,KAAA;IACR,MAAM,KAAK;IACX,UAAU;IACV,IAAI,OAAO,MAAM,GAAG;GACtB;GACA,OAAO;IACL,SAAS,IAAgB;KACvB,UAAU;KAGV,IAAI,UAAU,KAAA,GAAW,aAAa,KAAK;KAC3C,QAAQ,WAAW,OAAO,OAAO;IACnC;IACA;IACA,UAAU;KACR,IAAI,UAAU,KAAA,GAAW,aAAa,KAAK;KAC3C,QAAQ,KAAA;KACR,UAAU;IACZ;GACF;EACF;;EAGA,MAAa,uBAAuB;;;;;;;EAUpC,SAAS,uBAAuB,QAA0B;GACxD,MAAM,OAAiB,CAAC;GACxB,IAAI;IACF,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK,GAAG;KAC/C,MAAM,MAAM,aAAa,IAAI,CAAC;KAC9B,IAAI,QAAQ,QAAQ,IAAI,WAAW,MAAM,GAAG,KAAK,KAAK,GAAG;IAC3D;GACF,QAAQ;IACN,OAAO,CAAC;GACV;GACA,OAAO;EACT;;EAsBA,SAAgB,oBAA8D;GAC5E,MAAM,MAAgD,CAAC;GACvD,KAAK,MAAM,OAAO,uBAAuB,oBAAoB,GAAG;IAC9D,MAAM,OAAO,IAAI,MAAM,EAA2B;IAClD,IAAI,UAAU;IACd,IAAI;KACF,MAAM,MAAM,aAAa,QAAQ,GAAG;KACpC,IAAI,QAAQ,MAAM;MAChB,MAAM,SAAS,KAAK,MAAM,GAAG;MAC7B,IAAI,OAAO,OAAO,YAAY,UAAU,UAAU,OAAO;KAC3D;IACF,QAAQ;KACN,UAAU;IACZ;IACA,IAAI,KAAK;KAAE;KAAM;IAAQ,CAAC;GAC5B;GACA,IAAI,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO;GACxC,OAAO;EACT;;EAGA,SAAgB,mBAAmB,MAAoB;GAIrD,IAAI,uBAAA,aAA2C,CAAC,CAAC,UAAA,IAA6B;GAC9E,MAAM,SAAS,kBAAkB,CAAC,CAAC,QAAQ,UAAU,MAAM,SAAS,IAAI;GACxE,IAAI,SAAS,OAAO,SAAA;GACpB,KAAK,MAAM,SAAS,QAAQ;IAC1B,IAAI,UAAU,GAAG;IACjB,IAAI;KACF,aAAa,WAAW,GAAG,uBAAuB,MAAM,MAAM;IAChE,QAAQ,CAER;IACA,UAAU;GACZ;EACF;;EAGA,SAAgB,UAAU,KAAa,OAAyB;GAC9D,IAAI;IACF,aAAa,QAAQ,KAAK,KAAK,UAAU,KAAK,CAAC;IAC/C,OAAO;GACT,QAAQ;IACN,IAAI;KACF,aAAa,WAAW,GAAG;IAC7B,QAAQ,CAER;IACA,OAAO;GACT;EACF;;EAGA,SAAgB,SAAY,KAAa,UAAgB;GACvD,IAAI;IACF,MAAM,MAAM,aAAa,QAAQ,GAAG;IACpC,IAAI,QAAQ,MAAM,OAAO;IACzB,MAAM,SAAS,KAAK,MAAM,GAAG;IAG7B,IAAI,WAAW,QAAQ,OAAO,WAAW,UAAU,OAAO;IAC1D,OAAO;GACT,QAAQ;IACN,OAAO;GACT;EACF;;;;EC3KA,MAAM,gBAAgB,OAAO,cAAc;;EAW3C,SAAgB,YAAe,SAA4B;GACzD,IAAI,QAAQ;GACZ,MAAM,4BAAY,IAAI,IAAgB;GACtC,OAAO;IACL,mBAAmB;IACnB,UAAU,UAAU;KAClB,UAAU,IAAI,QAAQ;KACtB,aAAa;MAAE,UAAU,OAAO,QAAQ;KAAE;IAC5C;IACA,OAAO,IAAI;KACT,MAAM,OAAO,GAAG,KAAK;KACrB,IAAI,SAAS,OAAO;KACpB,QAAQ;KACR,KAAK,MAAM,YAAY,WAAW,SAAS;IAC7C;GACF;EACF;EASA,MAAa,wBAAwB;;EASrC,MAAa,qBAAqB;EAClC,MAAa,oBAAoB;EACjC,MAAa,eAAe;EAC5B,MAAa,kBAAkB;EAG/B,MAAa,aAAa;;;;;;;EAQ1B,SAAgB,mBAAmB,WAAmB,WAAmB,aAA8B;GAErG,MAAM,iBAAiB,KAAK,IAAA,KAA4B,aAAA,OADnB,cAAc,MAAkD,GAC1B;GAC3E,OAAO,KAAK,IAAI,WAAW,cAAc;EAC3C;;;;;;EAOA,SAAgB,kBAAkB,WAAmB,WAAmB,eAA+B;GACrG,MAAM,iBAAiB,KAAK,IAAA,KAE1B,YAAA,MAAgC,gBAAA,EAClC;GACA,OAAO,KAAK,IAAI,WAAW,cAAc;EAC3C;;EAyCA,MAAa,eAAe,SAAyB,GAAG,eAAe;;EAGvE,SAAgB,oBAAiC;GAC/C,MAAM,SAAS,YAAyB;IACtC,MAAM;IACN,eAAe,iBAAiB,oBAAA,KAAA,KAAA,GAA8F;IAC9H,cAAc,iBAAiB,mBAAA,KAAyC,uBAAA,GAAgD;IACxH,mBAAmB;IACnB,aAAa;IACb,gBAAgB;IAChB,UAAU;IACV,WAAW;GACb,CAAC;GAwBD,OAvB2B,OAAO,OAAO,QAAQ;IAC/C,gBAAgB,OAA4B;KAC1C,OAAO,MAAM,oBAAoB,IAAI,mBAAmB,MAAM,eAAe,MAAM,gBAAgB,MAAM,WAAW;IACtH;IACA,eAAe,OAA4B;KACzC,IAAI,CAAC,MAAM,aAAa,OAAO;KAC/B,MAAM,WAAW,MAAM,oBAAoB,IAAI,mBAAmB,MAAM,eAAe,MAAM,gBAAgB,IAAI;KACjH,OAAO,kBAAkB,MAAM,cAAc,MAAM,gBAAgB,QAAQ;IAC7E;IACA,YAAY,OAA0B;KACpC,IAAI,MAAM,kBAAkB,GAAG;KAC/B,MAAM,WAAW,mBAAmB,MAAM,eAAe,MAAM,gBAAgB,MAAM,WAAW;KAChG,IAAI,MAAM,gBAAgB,YAAY,CAAC,MAAM,mBAAmB;MAC9D,kBAAkB,oBAAoB,QAAQ;MAC9C,OAAO,QAAQ,UAAU;OAAE,GAAG;OAAM,eAAe;MAAS,EAAE;KAChE;KACA,MAAM,UAAU,kBAAkB,MAAM,cAAc,MAAM,gBAAgB,QAAQ;KACpF,IAAI,MAAM,eAAe,MAAM,eAAe,SAAS;MACrD,kBAAkB,mBAAmB,OAAO;MAC5C,OAAO,QAAQ,UAAU;OAAE,GAAG;OAAM,cAAc;MAAQ,EAAE;KAC9D;IACF;GACF,CACW;EACb;;EAGA,SAAgB,cAAc,OAAoB,MAAc,aAA4B;GAC1F,MAAM,QAAQ,SAAS;IACrB,IAAI,KAAK,SAAS,QAAQ,KAAK,gBAAgB,aAAa,OAAO;IACnE,IAAI,YAAY,KAAK;IACrB,IAAI,KAAK,SAAS,MAChB,IAAI;KACF,YAAY,aAAa,QAAQ,YAAY,IAAI,CAAC,MAAM;IAC1D,QAAQ;KACN,YAAY;IACd;IAIF,OAAO;KAAE,GAAG;KAAM;KAAM,mBAAmB;KAAW;KAAa,WAAW,KAAK,SAAS,OAAO,KAAK,YAAY;IAAK;GAC3H,CAAC;EACH;;EAsDA,SAAgB,eAAe,MAA+D;GAC5F,MAAM,SAAS,SAAqD,GAAG,kBAAkB,QAAQ,CAAC,CAAC;GAKnG,OAAO;IAAE,UAJQ,MAAM,QAAQ,OAAO,QAAQ,IAC1C,OAAO,SAAS,QAAQ,SAAyB,OAAO,SAAS,QAAQ,IACzE,CAAC;IAEc,UADF,OAAO,OAAO,aAAa,WAAW,OAAO,WAAW;GAC7C;EAC9B;EAEA,MAAM,eAAe;GAAE,OAAO;GAAI,QAAQ;GAAiB,MAAM,CAAC;GAAG,WAAW;EAAM;;EAGtF,SAAgB,oBAAoB,KAA8B;GAChE,MAAM,SAAS,YAA2B;IACxC,MAAM;IACN,MAAM,CAAC;IACP,UAAU,CAAC;IACX,UAAU;IACV,SAAS,CAAC;IACV,WAAW;IACX,QAAQ,EAAE,GAAG,aAAa;IAC1B,SAAS;GACX,CAAC;GAED,MAAM,mBAAmB,gBAAgB;GACzC,MAAM,kBAAkB,gBAAgB;GACxC,IAAI,YAAY;GAChB,IAAI,aAAa;GACjB,IAAI;GACJ,IAAI,cAAc;GAClB,IAAI,kBAA4B,CAAC;GACjC,IAAI,kBAAiC;GAErC,MAAM,qBAA2B;IAC/B,IAAI,gBAAgB,IAAI,UAAU,GAAG,kBAAkB,eAAe;KAAE,UAAU;KAAiB,UAAU;IAAgB,CAAC;GAChI;GACA,MAAM,qBAA2B;IAAE,iBAAiB,MAAM;GAAE;GAC5D,MAAM,mBAAmB,MAAc,UAAoB,aAAkC;IAC3F,IAAI,SAAS,IAAI;IACjB,cAAc;IACd,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB,SAAS,YAAY;GACxC;;GAGA,MAAM,YAAY,OAAO,MAAc,QAA+B;IACpE,MAAM,QAAQ,OAAO,YAAY;IACjC,IAAI,MAAM,SAAS,QAAQ,MAAM,KAAK,SAAS,KAAA,KAAa,MAAM,QAAQ,SAAS,GAAG,GAAG;IACzF,OAAO,QAAQ,UAAU;KAAE,GAAG;KAAM,SAAS,CAAC,GAAG,KAAK,SAAS,GAAG;IAAE,EAAE;IACtE,MAAM,SAAS,MAAM,IAAI,KAAK,MAAM,GAAG;IACvC,OAAO,QAAQ,SAAS;KACtB,IAAI,KAAK,SAAS,MAAM,OAAO;KAG/B,IAAI,QAAQ,MAAM,CAAC,KAAK,SAAS,SAAS,GAAG,GAC3C,OAAO;MAAE,GAAG;MAAM,SAAS,KAAK,QAAQ,QAAQ,SAAS,SAAS,GAAG;KAAE;KAEzE,MAAM,OAAO,EAAE,GAAG,KAAK,KAAK;KAC5B,IAAI,OAAO,IAAI,KAAK,OAAO,OAAO,MAAM;UACnC,OAAO,KAAK;KACjB,OAAO;MAAE,GAAG;MAAM;MAAM,SAAS,KAAK,QAAQ,QAAQ,SAAS,SAAS,GAAG;KAAE;IAC/E,CAAC;GACH;;GAGA,MAAM,eAAe,MAAiC,QAA2C;IAC/F,MAAM,SAAS,QAAQ,KAAK,KAAK,GAAG,IAAI;IACxC,MAAM,OAAkC,CAAC;IACzC,KAAK,MAAM,OAAO,OAAO,KAAK,IAAI,GAAG;KACnC,IAAI,QAAQ,OAAO,QAAQ,OAAO,IAAI,WAAW,MAAM,IAAI;KAC3D,KAAK,OAAO,KAAK;IACnB;IACA,OAAO;GACT;;GAGA,MAAM,aAAa,QAA0B;IAC3C,MAAM,MAAgB,CAAC;IACvB,MAAM,QAAQ,IAAI,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO;IAC3C,IAAI,MAAM;IACV,KAAK,MAAM,QAAQ,OAAO;KACxB,MAAM,QAAQ,KAAK,OAAO,GAAG,IAAI,GAAG;KACpC,IAAI,KAAK,GAAG;IACd;IACA,OAAO;GACT;;;;;GAMA,MAAM,eAAe,YAA2B;IAC9C,MAAM,QAAQ,OAAO,YAAY;IACjC,MAAM,OAAO,MAAM;IACnB,IAAI,SAAS,IAAI;IACjB,MAAM,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,IAAI,GAAG,MAAM,QAAQ,CAAC,CAAC;IACjD,MAAM,MAAM,EAAE;IACd,MAAM,UAAU,MAAM,QAAQ,WAAW,KAAK,KAAK,QAAQ,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC;IAC/E,OAAO,QAAQ,SAAS;KACtB,IAAI,KAAK,SAAS,QAAQ,QAAQ,WAAW,OAAO;KACpD,MAAM,WAAW,EAAE,GAAG,KAAK,KAAK;KAChC,QAAQ,SAAS,QAAQ,UAAU;MACjC,MAAM,MAAM,KAAK;MACjB,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM,IAAI;MAGvD,IAAI,QAAQ,MAAM,CAAC,KAAK,SAAS,SAAS,GAAG,GAAG;MAChD,SAAS,OAAO,OAAO,MAAM,MAAM;KACrC,CAAC;KACD,OAAO;MAAE,GAAG;MAAM,MAAM;MAAU,SAAS,KAAK,UAAU;KAAE;IAC9D,CAAC;IACD,IAAI,MAAM,OAAO,UAAU,IACzB,IAAS,OAAO,MAAM,MAAM,OAAO,KAAK,CAAC,CAAC,MAAM,WAAW;KACzD,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,QAAQ,KAAK,OAAO,UAAU,MAAM,OAAO,OAAO,OAAO;MAC3E,OAAO;OACL,GAAG;OACH,QAAQ,OAAO,KACX;QAAE,OAAO,MAAM,OAAO;QAAO,QAAQ;QAAQ,MAAM,OAAO,MAAM;QAAM,WAAW,OAAO,MAAM;OAAU,IACxG,KAAK;MACX;KACF,CAAC;IACH,CAAC;GAEL;GAEA,MAAM,QAAuB,OAAO,OAAO,QAAQ;IACjD,QAAQ,MAAc;KACpB,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,OAAO;MAC/B,MAAM,KAAK,eAAe,IAAI;MAC9B,OAAO;OACL,GAAG;OACH;OACA,MAAM,CAAC;OACP,UAAU,GAAG;OACb,UAAU,GAAG;OACb,SAAS,CAAC;OACV,QAAQ,EAAE,GAAG,aAAa;MAC5B;KACF,CAAC;KACD,UAAe,MAAM,EAAE;IACzB;IACA,aAAa,KAA0B;KACrC,OAAO,QAAQ,SAAU,KAAK,cAAc,MAAM,OAAO;MAAE,GAAG;MAAM,WAAW;KAAI,CAAE;IACvF;IACA,UAAU,KAAa;KACrB,MAAM,QAAQ,OAAO,YAAY;KACjC,MAAM,aAAa,MAAM,SAAS,SAAS,GAAG;KAC9C,IAAI,YACF,OAAO,QAAQ,UAAU;MACvB,GAAG;MACH,UAAU,KAAK,SAAS,QAAQ,SAAS,SAAS,GAAG;MACrD,MAAM,YAAY,KAAK,MAAM,GAAG;KAClC,EAAE;UACG;MACL,OAAO,QAAQ,UAAU;OAAE,GAAG;OAAM,UAAU,CAAC,GAAG,KAAK,UAAU,GAAG;MAAE,EAAE;MACxE,UAAe,MAAM,MAAM,GAAG;KAChC;KACA,gBAAgB,MAAM,MAAM,aAAa,MAAM,SAAS,QAAQ,SAAS,SAAS,GAAG,IAAI,CAAC,GAAG,MAAM,UAAU,GAAG,GAAG,MAAM,QAAQ;IACnI;IACA,OAAO,KAAoB;KACzB,OAAO,QAAQ,SAAU,KAAK,aAAa,MAAM,OAAO;MAAE,GAAG;MAAM,UAAU;KAAI,CAAE;KACnF,MAAM,QAAQ,OAAO,YAAY;KACjC,gBAAgB,MAAM,MAAM,MAAM,UAAU,GAAG;IACjD;IACA,OAAO,KAAa;KAClB,MAAM,QAAQ,OAAO,YAAY;KAEjC,MAAM,UADQ,UAAU,GACJ,CAAC,CAAC,QAAQ,SAAS,CAAC,MAAM,SAAS,SAAS,IAAI,CAAC;KACrE,OAAO,QAAQ,SAAS;MACtB,MAAM,WAAW,CAAC,GAAG,KAAK,QAAQ;MAClC,KAAK,MAAM,QAAQ,SACjB,IAAI,CAAC,SAAS,SAAS,IAAI,GAAG,SAAS,KAAK,IAAI;MAElD,OAAO;OAAE,GAAG;OAAM;OAAU,UAAU;OAAK,QAAQ,EAAE,GAAG,aAAa;MAAE;KACzE,CAAC;KACD,KAAK,MAAM,QAAQ,SAAS,UAAe,MAAM,MAAM,IAAI;KAC3D,gBAAgB,MAAM,MAAM,CAAC,GAAG,MAAM,UAAU,GAAG,OAAO,GAAG,GAAG;IAClE;IACA,eAAe,OAAe;KAC5B,MAAM,UAAU,MAAM,KAAK;KAC3B,OAAO,QAAQ,SAAS;MACtB,IAAI,YAAY,MAAM,KAAK,OAAO,UAAU,IAAI,OAAO;MACvD,OAAO;OACL,GAAG;OACH,QAAQ,YAAY,KAChB,EAAE,GAAG,aAAa,IAClB;QAAE,GAAG,KAAK;QAAQ,OAAO;QAAS,QAAQ;OAAY;MAC5D;KACF,CAAC;KACD,gBAAgB,QAAQ;KACxB,IAAI,YAAY,IAAI;KACpB,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,gBAAgB,eAAe;MAC7B,IAAS,OAAO,MAAM,OAAO,CAAC,CAAC,MAAM,WAAW;OAC9C,OAAO,QAAQ,SAAS;QACtB,IAAI,KAAK,SAAS,QAAQ,KAAK,OAAO,UAAU,SAAS,OAAO;QAChE,OAAO;SACL,GAAG;SACH,QAAQ,OAAO,KACX;UAAE,OAAO;UAAS,QAAQ;UAAQ,MAAM,OAAO,MAAM;UAAM,WAAW,OAAO,MAAM;SAAU,IAC7F;UAAE,GAAG,KAAK;UAAQ,QAAQ;UAAS,MAAM,CAAC;SAAE;QAClD;OACF,CAAC;MACH,CAAC;KACH,CAAC;IACH;IACA,eAAe;KACb,gBAAgB,QAAQ;KACxB,OAAO,QAAQ,SAAU,KAAK,OAAO,UAAU,KAAK,OAAO;MAAE,GAAG;MAAM,QAAQ,EAAE,GAAG,aAAa;KAAE,CAAE;IACtG;IACA,MAAM,oBAAoB,KAAa;KACrC,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,IAAI,OAAO;KAExB,QAAO,MADc,IAAI,OAAO,MAAM,GAAG,EAAA,CAC3B;IAChB;IACA,MAAM,mBAAmB,KAAa;KACpC,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,IAAI,OAAO;KAExB,QAAO,MADc,IAAI,gBAAgB,MAAM,GAAG,EAAA,CACpC;IAChB;IACA,MAAM,YAAY,KAAa,SAAiB;KAC9C,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,MAAM,QAAQ,IAAI,OAAO;KACtC,MAAM,SAAS,MAAM,IAAI,OAAO,MAAM,KAAK,OAAO;KAClD,IAAI,OAAO,IAAI;MAGb,OAAO,QAAQ,SAAS;OACtB,MAAM,SAAS,IAAI,SAAS,GAAG,IAAI,IAAI,MAAM,GAAG,IAAI,YAAY,GAAG,CAAC,IAAI;OACxE,MAAM,SAAS,WAAW,KAAK,UAAU,GAAG,OAAO,GAAG;OACtD,MAAM,OAAsB;QAC1B,GAAG;QACH,MAAM,YAAY,KAAK,MAAM,GAAG;QAChC,UAAU,KAAK,SAAS,QAAQ,SAAS,SAAS,GAAG;OACvD;OACA,IAAI,KAAK,aAAa,KAAK,KAAK,WAAW;OAC3C,OAAO;MACT,CAAC;MACD,KAAU,eAAe;KAC3B;KACA,OAAO,OAAO;IAChB;IACA,MAAM,UAAU,KAAa;KAC3B,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,IAAI,OAAO;KACxB,MAAM,SAAS,MAAM,IAAI,MAAM,MAAM,GAAG;KACxC,IAAI,OAAO,IAAI;MAEb,MAAM,SAAS,IAAI,SAAS,GAAG,IAAI,IAAI,MAAM,GAAG,IAAI,YAAY,GAAG,CAAC,IAAI;MACxE,MAAM,QAAQ,OAAO,YAAY;MACjC,IAAI,WAAW,MAAM,CAAC,MAAM,SAAS,SAAS,MAAM,GAAG,KAAK,UAAU,MAAM;MAC5E,KAAU,eAAe;KAC3B;KACA,OAAO,OAAO;IAChB;IACA,MAAM,WAAW,KAAa;KAC5B,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,IAAI,OAAO;KACxB,MAAM,SAAS,MAAM,IAAI,QAAQ,MAAM,GAAG;KAC1C,IAAI,OAAO,IAAI;MAEb,MAAM,SAAS,IAAI,SAAS,GAAG,IAAI,IAAI,MAAM,GAAG,IAAI,YAAY,GAAG,CAAC,IAAI;MACxE,MAAM,QAAQ,OAAO,YAAY;MACjC,IAAI,WAAW,MAAM,CAAC,MAAM,SAAS,SAAS,MAAM,GAAG,KAAK,UAAU,MAAM;MAC5E,KAAU,eAAe;KAC3B;KACA,OAAO,OAAO;IAChB;IACA,MAAM,YAAY,KAAa;KAC7B,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,MAAM,QAAQ,IAAI,OAAO;KACtC,MAAM,SAAS,MAAM,IAAI,OAAO,MAAM,GAAG;KACzC,IAAI,OAAO,IAAI;MACb,OAAO,QAAQ,UAAU;OACvB,GAAG;OACH,UAAU,KAAK,aAAa,OAAO,KAAK,UAAU,WAAW,MAAM,GAAG,IAAI,OAAO,KAAK;OACtF,MAAM,YAAY,KAAK,MAAM,GAAG;MAClC,EAAE;MACF,KAAU,eAAe;KAC3B;KACA,OAAO,OAAO;IAChB;IACA,MAAM,iBAAiB;KAErB,IADa,OAAO,YAAY,CAAC,CAAC,SACrB,IAAI;KACjB,IAAI,YAAY;MAGd,IAAI,gBAAgB,KAAA,GAClB,cAAc,iBAAiB;OAC7B,cAAc,KAAA;OACd,KAAU,eAAe;MAC3B,GAAA,GAAiB;MAEnB;KACF;KACA,aAAa;KACb,IAAI;MACF,MAAM,aAAa;KACrB,UAAU;MACR,aAAa;KACf;IACF;GACF,CAAC;GACA,MAA8C,iBAAiB;GAChE,OAAO;EACT;;EA0CA,SAAgB,UAAU,MAAyI;GACjK,MAAM,SAAS,SAAyG,GAAG,aAAa,QAAQ,CAAC,CAAC;GASlJ,OAAO;IAAE,UARQ,OAAO,aAAa,SAAS,SAAS;IAQpC,kBAP+B,OAAO,OAAO,qBAAqB,YAAY,OAAO,qBAAqB,OACzH,OAAO,YAAY,OAAO,QAAQ,OAAO,gBAA2C,CAAC,CAAC,QAAQ,GAAG,OAAO,OAAO,MAAM,SAAS,CAAC,IAC/H,CAAC;IAKgC,cAJhB,MAAM,QAAQ,OAAO,YAAY,IAClD,OAAO,aAAa,QAAQ,SAAyB,OAAO,SAAS,QAAQ,IAC7E,CAAC;IAE8C,UADlC,OAAO,OAAO,aAAa,WAAW,OAAO,WAAW;GACb;EAC9D;;EAGA,SAAgB,eAAe,KAAyB;GACtD,MAAM,SAAS,YAAsB;IACnC,MAAM;IACN,QAAQ;IACR,YAAY;IACZ,SAAS;IACT,MAAM,CAAC;IACP,QAAQ,CAAC;IACT,UAAU;IACV,kBAAkB,CAAC;IACnB,cAAc,CAAC;IACf,UAAU;GACZ,CAAC;GAED,MAAM,mBAAmB,gBAAgB;GACzC,IAAI,eAAgC;GACpC,IAAI,UAAU;GACd,MAAM,qBAA2B;IAC/B,IAAI,iBAAiB,QAAQ,aAAa,SAAS,IACjD,UAAU,GAAG,aAAa,aAAa,QAAQ;KAC7C,UAAU,aAAa;KACvB,kBAAkB,aAAa;KAC/B,cAAc,aAAa;KAC3B,UAAU,aAAa;IACzB,CAAC;GAEL;GACA,MAAM,qBAA2B;IAAE,iBAAiB,MAAM;GAAE;GAC5D,MAAM,mBAAmB,UAA0B;IACjD,IAAI,MAAM,SAAS,IAAI;IACvB,eAAe;IACf,iBAAiB,SAAS,YAAY;GACxC;;GAGA,MAAM,OAAO,OAAO,MAAc,WAAqB,CAAC,MAAqB;IAC3E,MAAM,MAAM,EAAE;IACd,OAAO,QAAQ,UAAU;KAAE,GAAG;KAAM,SAAS;IAAK,EAAE;IACpD,MAAM,SAAS,MAAM,IAAI,UAAU,IAAI;IACvC,OAAO,QAAQ,SAAS;KAGtB,IAAI,KAAK,SAAS,QAAQ,QAAQ,SAAS,OAAO;KAClD,OAAO;MACL,GAAG;MACH,QAAQ,OAAO,KAAK,OAAO,QAAQ,KAAK;MAExC,YAAY,OAAO,MAAM,OAAO,UAAU,OAAO,QAAQ,KAAK;MAC9D,SAAS;MACT,MAAM;KACR;IACF,CAAC;GACH;GAEA,MAAM,QAAkB,OAAO,OAAO,QAAQ;IAC5C,QAAQ,MAAc;KACpB,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,OAAO;MAC/B,MAAM,KAAK,UAAU,IAAI;MACzB,OAAO;OACL,GAAG;OACH;OACA,QAAQ;OACR,YAAY;OACZ,SAAS;OACT,MAAM,CAAC;OACP,QAAQ,CAAC;OACT,UAAU,GAAG;OACb,kBAAkB,GAAG;OACrB,cAAc,GAAG;OACjB,UAAU,GAAG;MACf;KACF,CAAC;KACD,KAAU,IAAI;IAChB;IACA,MAAM,UAAU;KACd,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,IAAI,MAAM,KAAK,IAAI;IAClC;IACA,MAAM,MAAM,OAAiB;KAC3B,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,MAAM,MAAM,WAAW,GAAG;KACvC,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG,KAAK;KAAE,EAAE;KACrE,MAAM,SAAS,MAAM,IAAI,SAAS,MAAM,KAAK;KAC7C,OAAO,QAAQ,UAAU;MACvB,GAAG;MACH,QAAQ,OAAO,MAAM,MAAM,QAAQ,OAAO,OAAO,MAAM,IAAI,OAAO,MAAM,SAAU,OAAO,KAAK,CAAC,IAAI;MACnG,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,MAAM,SAAS,IAAI,CAAC;KACxD,EAAE;KACF,MAAM,KAAK,IAAI;IACjB;IACA,MAAM,QAAQ,OAAiB;KAC7B,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,MAAM,MAAM,WAAW,GAAG;KACvC,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG,KAAK;KAAE,EAAE;KACrE,MAAM,SAAS,MAAM,IAAI,WAAW,MAAM,KAAK;KAC/C,OAAO,QAAQ,UAAU;MACvB,GAAG;MACH,QAAQ,OAAO,MAAM,MAAM,QAAQ,OAAO,OAAO,MAAM,IAAI,OAAO,MAAM,SAAU,OAAO,KAAK,CAAC,IAAI;MACnG,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,MAAM,SAAS,IAAI,CAAC;KACxD,EAAE;KACF,MAAM,KAAK,IAAI;IACjB;IACA,MAAM,QAAQ,OAAiB;KAC7B,MAAM,OAAO,OAAO,YAAY,CAAC,CAAC;KAClC,IAAI,SAAS,MAAM,MAAM,WAAW,GAAG;KACvC,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG,KAAK;KAAE,EAAE;KACrE,MAAM,SAAS,MAAM,IAAI,WAAW,MAAM,KAAK;KAC/C,OAAO,QAAQ,UAAU;MACvB,GAAG;MACH,QAAQ,OAAO,MAAM,MAAM,QAAQ,OAAO,OAAO,MAAM,IAAI,OAAO,MAAM,SAAU,OAAO,KAAK,CAAC,IAAI;MACnG,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,MAAM,SAAS,IAAI,CAAC;KACxD,EAAE;KACF,MAAM,KAAK,IAAI;IACjB;IACA,MAAM,aAAa;KACjB,MAAM,QAAQ,OAAO,YAAY;KACjC,MAAM,QAAQ,CACZ,GAAI,MAAM,QAAQ,YAAY,CAAC,GAC/B,GAAI,MAAM,QAAQ,aAAa,CAAC,CAClC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI;KACvB,MAAM,KAAK,QAAQ,KAAK;IAC1B;IACA,YAAY,MAAuB;KACjC,OAAO,QAAQ,SAAU,KAAK,aAAa,OAAO,OAAO;MAAE,GAAG;MAAM,UAAU;KAAK,CAAE;KACrF,gBAAgB,OAAO,YAAY,CAAC;IACtC;IACA,oBAAoB,IAAY,WAAoB;KAClD,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,kBAAkB;OAAE,GAAG,KAAK;QAAmB,KAAK;MAAU;KAAE,EAAE;KACtG,gBAAgB,OAAO,YAAY,CAAC;IACtC;IACA,gBAAgB,MAAgB;KAC9B,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,cAAc;KAAK,EAAE;KACzD,gBAAgB,OAAO,YAAY,CAAC;IACtC;IACA,UAAU,OAAiB;KACzB,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,QAAQ;KAAM,EAAE;IACtD;IACA,OAAO,MAAqB;KAC1B,OAAO,QAAQ,SAAU,KAAK,aAAa,OAAO,OAAO;MAAE,GAAG;MAAM,UAAU;KAAK,CAAE;KACrF,gBAAgB,OAAO,YAAY,CAAC;IACtC;GACF,CAAC;GACA,MAA8C,iBAAiB;GAChE,OAAO;EACT;;EAmEA,SAAgB,gBAAgB,MAA8B;GAC5D,MAAM,SAAS,SAAgD,cAAc,QAAQ,CAAC,CAAC;GACvF,IAAI,CAAC,MAAM,QAAQ,OAAO,IAAI,GAAG,OAAO,CAAC;GACzC,MAAM,MAAsB,CAAC;GAC7B,KAAK,MAAM,QAAQ,OAAO,MAAM;IAC9B,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;IAC/C,MAAM,SAAS;IACf,IAAI,OAAO,OAAO,OAAO,YAAY,OAAO,OAAO,SAAS,UAAU;IACtE,MAAM,UAAU,OAAO;IACvB,MAAM,OAAO,OAAO,YAAY,YAAY,YAAY,QACnD,OAAQ,QAAoC,WAAW,YACxD,EAAE,QAAS,QAAgC,OAAO,IAClD,KAAA;IACJ,IAAI,KAAK;KACP,IAAI,OAAO;KACX,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,OAAO;KAChE,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;KACtD,MAAM,OAAO;KACb,aAAa,OAAO,OAAO,gBAAgB,WAAW,OAAO,cAAoC;KACjG;KACA,SAAS,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;IACjE,CAAC;GACH;GACA,OAAO;EACT;;EAGA,SAAgB,mBAAmB,KAA6B;GAC9D,MAAM,SAAS,YAA0B;IACvC,MAAM;IACN,MAAM;IACN,MAAM,CAAC;IACP,aAAa;IACb,SAAS;GACX,CAAC;GAGD,IAAI,oBAAoB;GACxB,IAAI;GAEJ,MAAM,mBAAmB,gBAAgB;GACzC,MAAM,qBAA2B;IAC/B,MAAM,UAAU,OAAO,YAAY;IACnC,IAAI,QAAQ,SAAS,IAAI;IACzB,MAAM,OAAuB,QAAQ,KAAK,KAAK,SAAS;KACtD,IAAI,IAAI;KACR,OAAO,IAAI;KACX,MAAM,IAAI;KACV,MAAM,IAAI;KACV,aAAa,IAAI;KACjB,MAAM,IAAI;KACV,SAAS,IAAI;IACf,EAAE;IACF,UAAU,cAAc,QAAQ,QAAQ;KAAE,SAAS,KAAK,IAAI;KAAG,MAAM;IAAK,CAAC;IAC3E,mBAAmB,QAAQ,IAAI;GACjC;GACA,MAAM,qBAA2B;IAAE,iBAAiB,MAAM;GAAE;GAC5D,MAAM,mBAAmB,UAA8B;IACrD,IAAI,MAAM,SAAS,IAAI;IACvB,iBAAiB,SAAS,YAAY;GACxC;;GAGA,MAAM,cAAc,OAAO,MAAc,OAA8B;IACrE,MAAM,MAAM,OAAO,YAAY,CAAC,CAAC,KAAK,MAAM,SAAS,KAAK,OAAO,EAAE;IACnE,IAAI,QAAQ,KAAA,KAAa,IAAI,YAAY,QAAQ,IAAI,SAAS;IAC9D,OAAO,QAAQ,UAAU;KACvB,GAAG;KACH,MAAM,KAAK,KAAK,KAAK,SAAU,KAAK,OAAO,KAAK;MAAE,GAAG;MAAM,SAAS;MAAM,OAAO;KAAK,IAAI,IAAK;IACjG,EAAE;IAGF,IAAI,IAAI,gBAAgB,OAAO;KAC7B,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,OAAO;MAC/B,OAAO;OACL,GAAG;OACH,MAAM,KAAK,KAAK,KAAK,SAAU,KAAK,OAAO,KACvC;QAAE,GAAG;QAAM,SAAS;QAAO,SAAS,cAAc,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC;QAAG,SAAS;OAAM,IAC/F,IAAK;MACX;KACF,CAAC;KACD;IACF;IACA,MAAM,UAAU,IAAI,gBAAgB;IACpC,MAAM,SAAS,IAAI,SAAS,KAAA,IACxB,MAAM,IAAI,QAAQ,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,IACjD,MAAM,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO;IAC1C,OAAO,QAAQ,SAAS;KACtB,IAAI,KAAK,SAAS,MAAM,OAAO;KAC/B,OAAO;MACL,GAAG;MACH,MAAM,KAAK,KAAK,KAAK,SAAS;OAC5B,IAAI,KAAK,OAAO,IAAI,OAAO;OAC3B,IAAI,CAAC,OAAO,IACV,OAAO;QAAE,GAAG;QAAM,SAAS;QAAO,OAAO,OAAO,MAAM;OAAQ;OAIhE,IAAI,KAAK,OAAO,OAAO;QAAE,GAAG;QAAM,SAAS;OAAM;OAGjD,MAAM,SAAS,OAAO;OACtB,OAAO;QACL,GAAG;QACH,SAAS;QACT,SAAS,OAAO;QAChB,OAAO,OAAO;QACd,OAAO,OAAO;QACd,WAAW,OAAO,aAAa;QAC/B,SAAS;OACX;MACF,CAAC;KACH;IACF,CAAC;GACH;;GAGA,MAAM,SAAS,OAAqB;IAClC,OAAO,QAAQ,UAAU;KACvB,GAAG;KACH,MAAM,KAAK,KAAK,KAAK,SAAU,KAAK,OAAO,KAAK;MAAE,GAAG;MAAM,SAAS,KAAK,IAAI;KAAE,IAAI,IAAK;IAC1F,EAAE;GACJ;;;;;;GAOA,MAAM,eAAe,OAAO,SAAgC;IAC1D,IAAI,OAAO,YAAY,CAAC,CAAC,SAAS,MAAM;IACxC,MAAM,QAAQ,OAAO,YAAY,CAAC,CAAC,KAChC,QAAQ,QAAgE,IAAI,SAAS,KAAA,CAAS;IACjG,MAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,QAAQ;KACzC,IAAI,IAAI,YAAY,QAAQ,IAAI,SAAS;KACzC,MAAM,SAAS,MAAM,IAAI,QAAQ,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM;KAChE,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,OAAO;MAC/B,OAAO;OACL,GAAG;OACH,MAAM,KAAK,KAAK,KAAK,SAAS;QAC5B,IAAI,KAAK,OAAO,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO;QAC7C,IAAI,KAAK,SAAS,KAAK,SAAS,OAAO;QACvC,OAAO;SAAE,GAAG;SAAM,SAAS,OAAO,MAAM;SAAS,OAAO;QAAK;OAC/D,CAAC;MACH;KACF,CAAC;IACH,CAAC,CAAC;GACJ;GAEA,MAAM,QAAsB,OAAO,OAAO,QAAQ;IAChD,QAAQ,MAAc;KACpB,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,OAAO;MAE/B,MAAM,OADY,gBAAgB,IACM,CAAC,CAAC,KAAK,UAAU;OACvD,IAAI,KAAK;OACT,OAAO,KAAK;OACZ,MAAM,KAAK;OACX,MAAM,KAAK;OACX,aAAa,KAAK;OAClB,MAAM,KAAK;OACX,SAAS;OACT,OAAO;OACP,SAAS;OACT,SAAS;OACT,WAAW;OACX,OAAO;OACP,SAAS,KAAK;MAChB,EAAE;MACF,MAAM,cAAc,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC,KAAK;MACjE,OAAO;OAAE,GAAG;OAAM;OAAM;OAAM;OAAa,MAAM,KAAK,SAAS;MAAE;KACnE,CAAC;KACD,MAAM,QAAQ,OAAO,YAAY;KACjC,IAAI,MAAM,gBAAgB,MAAM,YAAiB,MAAM,MAAM,WAAW;IAC1E;IACA,SAAS,MAAc,MAAc;KACnC,MAAM,OAAO,kBAAkB,IAAI;KACnC,MAAM,KAAK,QAAQ,MAAM,MAAM,IAAI;KAEnC,IADiB,OAAO,YAAY,CAAC,CAAC,KAAK,MAAM,QAAQ,IAAI,OAAO,EACzD,MAAM,KAAA,GAAW;MAC1B,OAAO,QAAQ,UAAU;OACvB,GAAG;OACH;OACA,MAAM;OACN,aAAa;OACb,MAAM,KAAK,KAAK,KAAK,QAAS,IAAI,OAAO,KAAK;QAAE,GAAG;QAAK,SAAS,KAAK,IAAI;OAAE,IAAI,GAAI;MACtF,EAAE;MACF,YAAiB,MAAM,EAAE;MACzB,gBAAgB,OAAO,YAAY,CAAC;MACpC;KACF;KACA,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,OAAO;MAC/B,MAAM,MAAuB;OAC3B;OACA,OAAO,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;OAChC;OACA;OACA,aAAa;OACb,SAAS;OACT,OAAO;OACP,SAAS;OACT,SAAS;OACT,WAAW;OACX,OAAO;OACP,SAAS,KAAK,IAAI;MACpB;MACA,OAAO;OAAE,GAAG;OAAM,MAAM;OAAM,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG;OAAG,aAAa;MAAG;KAC3E,CAAC;KACD,YAAiB,MAAM,EAAE;KACzB,gBAAgB,OAAO,YAAY,CAAC;IACtC;IACA,SAAS,MAAc,MAAc,QAAiB;KAIpD,MAAM,KAAK,YAAY,SAAS,MAAM,IAAI,QAAQ,KAAK,QAAQ;KAE/D,IADiB,OAAO,YAAY,CAAC,CAAC,KAAK,MAAM,QAAQ,IAAI,OAAO,EACzD,MAAM,KAAA,GAAW;MAC1B,OAAO,QAAQ,UAAU;OACvB,GAAG;OACH;OACA,MAAM;OACN,aAAa;OACb,MAAM,KAAK,KAAK,KAAK,QAAS,IAAI,OAAO,KAAK;QAAE,GAAG;QAAK,SAAS,KAAK,IAAI;OAAE,IAAI,GAAI;MACtF,EAAE;MACF,YAAiB,MAAM,EAAE;MACzB,gBAAgB,OAAO,YAAY,CAAC;MACpC;KACF;KACA,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,OAAO;MAC/B,MAAM,MAAuB;OAC3B;OACA,OAAO,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;OAChC;OACA;OACA,aAAa;OACb,MAAM,EAAE,OAAO;OACf,SAAS;OACT,OAAO;OACP,SAAS;OACT,SAAS;OACT,WAAW;OACX,OAAO;OACP,SAAS,KAAK,IAAI;MACpB;MACA,OAAO;OAAE,GAAG;OAAM,MAAM;OAAM,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG;OAAG,aAAa;MAAG;KAC3E,CAAC;KACD,YAAiB,MAAM,EAAE;KACzB,gBAAgB,OAAO,YAAY,CAAC;IACtC;IACA,UAAU,IAAY;KACpB,MAAM,QAAQ,OAAO,YAAY;KACjC,IAAI,MAAM,gBAAgB,IAAI;KAC9B,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,aAAa;KAAG,EAAE;KACtD,MAAM,EAAE;KACR,MAAM,MAAM,OAAO,YAAY,CAAC,CAAC,KAAK,MAAM,SAAS,KAAK,OAAO,EAAE;KACnE,IAAI,QAAQ,KAAA,KAAa,IAAI,YAAY,MAAM,YAAiB,MAAM,MAAM,EAAE;KAC9E,gBAAgB,OAAO,YAAY,CAAC;IACtC;IACA,UAAU,KAAe;KACvB,MAAM,QAAQ,OAAO,YAAY;KACjC,MAAM,YAAY,MAAM,KAAK,QAAQ,QAAQ,CAAC,IAAI,SAAS,IAAI,EAAE,CAAC;KAElE,MAAM,cADS,UAAU,MAAM,QAAQ,IAAI,OAAO,MAAM,WAC/B,IACrB,MAAM,cACN,UAAU,SAAS,IACjB,UAAU,KAAK,IAAI,MAAM,KAAK,WAAW,QAAQ,IAAI,OAAO,MAAM,WAAW,GAAG,UAAU,SAAS,CAAC,EAAE,EAAE,MAAM,UAAU,UAAU,SAAS,EAAE,CAAC,KAC9I;KACN,OAAO,QAAQ,UAAU;MACvB,GAAG;MACH,MAAM;MACN;MACA,MAAM,UAAU,SAAS,IAAI,KAAK,OAAO;KAC3C,EAAE;KACF,gBAAgB,OAAO,YAAY,CAAC;IACtC;IACA,cAAc,IAAY,SAAiB;KACzC,OAAO,QAAQ,UAAU;MACvB,GAAG;MACH,MAAM,KAAK,KAAK,KAAK,QAAS,IAAI,OAAO,KAAK;OAAE,GAAG;OAAK;OAAS,OAAO;OAAM,SAAS;MAAM,IAAI,GAAI;KACvG,EAAE;IACJ;IACA,MAAM,QAAQ,IAAY;KACxB,MAAM,QAAQ,OAAO,YAAY;KACjC,MAAM,MAAM,MAAM,KAAK,MAAM,SAAS,KAAK,OAAO,EAAE;KACpD,IAAI,QAAQ,KAAA,KAAa,IAAI,YAAY,QAAQ,CAAC,WAAW,IAAI,WAAW,KAAK,IAAI,SAAS,KAAA,GAAW;KACzG,MAAM,cAAc,IAAI;KACxB,OAAO,QAAQ,UAAU;MACvB,GAAG;MACH,MAAM,KAAK,KAAK,KAAK,SAAU,KAAK,OAAO,KAAK;OAAE,GAAG;OAAM,SAAS;OAAM,OAAO;MAAK,IAAI,IAAK;KACjG,EAAE;KACF,MAAM,SAAS,MAAM,IAAI,MAAM,MAAM,MAAM,IAAI,MAAM,IAAI,SAAS,IAAI,KAAK;KAC3E,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,MAAM,OAAO;MACrC,OAAO;OACL,GAAG;OACH,MAAM,KAAK,KAAK,KAAK,SAAS;QAC5B,IAAI,KAAK,OAAO,IAAI,OAAO;QAC3B,IAAI,CAAC,OAAO,IACV,OAAO;SACL,GAAG;SACH,SAAS;SACT,OAAO,OAAO,MAAM,SAAS,mBACzB,2BACA,OAAO,MAAM;QACnB;QAEF,IAAI,KAAK,YAAY,aAKnB,OAAO;SAAE,GAAG;SAAM,SAAS;SAAO,OAAO,OAAO,MAAM;SAAO,OAAO;QAAK;QAE3E,OAAO;SAAE,GAAG;SAAM,SAAS;SAAO,OAAO;SAAO,OAAO,OAAO,MAAM;SAAO,OAAO;QAAK;OACzF,CAAC;MACH;KACF,CAAC;IACH;IACA,MAAM,UAAU,IAAY;KAC1B,MAAM,QAAQ,OAAO,YAAY;KACjC,MAAM,MAAM,MAAM,KAAK,MAAM,SAAS,KAAK,OAAO,EAAE;KACpD,IAAI,QAAQ,KAAA,GAAW;KACvB,IAAI,IAAI,gBAAgB,OAAO;MAG7B,OAAO,QAAQ,UAAU;OACvB,GAAG;OACH,MAAM,KAAK,KAAK,KAAK,SACnB,KAAK,OAAO,KAAK;QAAE,GAAG;QAAM,cAAc,KAAK,eAAe,KAAK;OAAE,IAAI,IAC3E;MACF,EAAE;MACF;KACF;KACA,IAAI,IAAI,gBAAgB,OAAO;MAG7B,OAAO,QAAQ,UAAU;OACvB,GAAG;OACH,MAAM,KAAK,KAAK,KAAK,SAAU,KAAK,OAAO,KACvC;QAAE,GAAG;QAAM,SAAS,cAAc,MAAM,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC;QAAG,SAAS;QAAO,OAAO;OAAK,IAClG,IAAK;MACX,EAAE;MACF;KACF;KACA,OAAO,QAAQ,UAAU;MACvB,GAAG;MACH,MAAM,KAAK,KAAK,KAAK,SAAU,KAAK,OAAO,KAAK;OAAE,GAAG;OAAM,SAAS;MAAK,IAAI,IAAK;KACpF,EAAE;KACF,MAAM,SAAS,IAAI,SAAS,KAAA,IACxB,MAAM,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,IACvD,MAAM,IAAI,KAAK,MAAM,MAAM,IAAI,MAAM,IAAI,gBAAgB,OAAO;KACpE,OAAO,QAAQ,SAAS;MACtB,IAAI,KAAK,SAAS,MAAM,MAAM,OAAO;MACrC,OAAO;OACL,GAAG;OACH,MAAM,KAAK,KAAK,KAAK,SAAS;QAC5B,IAAI,KAAK,OAAO,IAAI,OAAO;QAC3B,IAAI,CAAC,OAAO,IAAI,OAAO;SAAE,GAAG;SAAM,SAAS;SAAO,OAAO,OAAO,MAAM;QAAQ;QAC9E,MAAM,SAAS,OAAO;QACtB,OAAO;SACL,GAAG;SACH,SAAS;SACT,SAAS,OAAO;SAChB,OAAO,OAAO;SACd,OAAO,OAAO;SACd,WAAW,OAAO,aAAa;SAC/B,SAAS;SACT,OAAO;SACP,OAAO;QACT;OACF,CAAC;MACH;KACF,CAAC;IACH;IACA,QAAQ,MAAe;KACrB,OAAO,QAAQ,SAAU,KAAK,SAAS,OAAO,OAAO;MAAE,GAAG;MAAM;KAAK,CAAE;IACzE;IACA,MAAM,iBAAiB;KACrB,MAAM,QAAQ,OAAO,YAAY;KACjC,IAAI,MAAM,SAAS,IAAI;KACvB,IAAI,mBAAmB;MAIrB,IAAI,uBAAuB,KAAA,GACzB,qBAAqB,iBAAiB;OACpC,qBAAqB,KAAA;OACrB,KAAU,eAAe;MAC3B,GAAA,GAAiB;MAEnB;KACF;KACA,oBAAoB;KACpB,IAAI;MACF,OAAO,QAAQ,UAAU;OAAE,GAAG;OAAM,SAAS,KAAK,UAAU;MAAE,EAAE;MAGhE,MAAM,aAAa,MAAM,IAAI;MAG7B,MAAM,SAAS,OAAO,YAAY,CAAC,CAAC,KAAK,MAAM,QAAQ,IAAI,OAAO,OAAO,YAAY,CAAC,CAAC,WAAW;MAClG,IAAI,WAAW,KAAA,KAAa,OAAO,YAAY,QAAQ,OAAO,SAAS,OAAO,SAAS,KAAA,KAAa,CAAC,WAAW,OAAO,WAAW,GAAG;MACrI,MAAM,SAAS,MAAM,IAAI,KAAK,MAAM,MAAM,OAAO,MAAM,KAAK;MAC5D,OAAO,QAAQ,SAAS;OACtB,IAAI,KAAK,SAAS,MAAM,MAAM,OAAO;OACrC,OAAO;QACL,GAAG;QACH,MAAM,KAAK,KAAK,KAAK,QAAQ;SAC3B,IAAI,IAAI,OAAO,OAAO,MAAM,IAAI,OAAO,OAAO;SAC9C,IAAI,CAAC,OAAO,IAAI,OAAO;SACvB,OAAO;UAAE,GAAG;UAAK,SAAS,IAAI,UAAU,KAAA,KAAa,OAAO,MAAM,QAAQ,IAAI,QAAQ;SAAE;QAC1F,CAAC;OACH;MACF,CAAC;KACH,UAAU;MACR,oBAAoB;KACtB;IACF;IACA,MAAM,gBAAgB,MAAc;KAGlC,MAAM,aAAa,IAAI;IACzB;GACF,CAAC;GACA,MAA8C,iBAAiB;GAChE,OAAO;EACT;;EAiBA,SAAgB,kBAAkB,KAAqC;GACrE,MAAM,SAAS,kBAAkB;GACjC,MAAM,WAAW,oBAAoB,GAAG;GACxC,MAAM,MAAM,eAAe,GAAG;GAC9B,MAAM,UAAU,mBAAmB,GAAG;GACtC,MAAM,iBAAuB;IAC3B,KAAK,MAAM,SAAS;KAAC;KAAU;KAAK;IAAO,GAAG;KAC5C,MAAM,QAAS,MAA6C;KAC5D,IAAI,OAAO,UAAU,YAAY,MAAsB;IACzD;GACF;GAEA,OAAO;IADgC;IAAQ;IAAU;IAAK;IAAS;GAC3D;EACd;;;;;;;EClvCA,SAAgB,oBAAoB,QAAwB,YAA4B;GACtF,MAAM,OAAO,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,CAAC,EAAE;GACpD,OAAO,WAAW,aACd,mBAAmB,SACnB,eAAe,KAAK;EAC1B;;EAGA,SAAgB,iBAAiB,gBAAiC;GAChE,OAAO,iBAAiB,KAAK,iBAAA;EAC/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECOA,IAAI,eAAmC;;;;;;;;;EAevC,SAAS,YAAgC;GACvC,MAAM,UAAU,SAAS,cAA2B,kBAAkB;GACtE,IAAI,YAAY,MAAM,OAAO;GAC7B,OAAO,SAAS,cAA2B,yBAAuB,CAAC,EAAE,iBAAiB;EACxF;;;;;EAMA,SAAgB,gBAAgB,OAAyB;GACvD,MAAM,SAAmB,CAAC;GAC1B,IAAI,QAAQ;GACZ,IAAI,UAAU;GACd,KAAK,MAAM,QAAQ,OAAO;IACxB,IAAI,SAAS,KAAK,SAAS;IAC3B,IAAI,SAAS,KAAK,QAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;IAC/C,IAAI,SAAS,OAAO,UAAU,GAAG;KAC/B,IAAI,YAAY,IAAI;MAClB,OAAO,KAAK,OAAO;MACnB,UAAU;KACZ;KACA;IACF;IACA,WAAW;GACb;GACA,IAAI,YAAY,IAAI,OAAO,KAAK,OAAO;GACvC,OAAO;EACT;;EAGA,SAAgB,QAAQ,OAAuB;GAC7C,MAAM,QAAQ,iBAAiB,KAAK,MAAM,KAAK,CAAC;GAChD,OAAO,UAAU,OAAO,IAAI,OAAO,MAAM,EAAE;EAC7C;;;;;;EAWA,SAAgB,gBACd,MACA,YACA,QACA,UACQ;GACR,MAAM,YAAY,aAAa;GAC/B,IAAI,SAAS,YAEX,OAAO,mBADS,KAAK,IAAA,KAA4B,KAAK,IAAA,KAA4B,SAAS,CAC3D,GAAG,SAAS,gBAAgB,SAAS,WAAW;GAGlF,OAAO,kBADS,KAAK,IAAI,uBAAuB,KAAK,IAAA,KAA0B,SAAS,CACzD,GAAG,SAAS,gBAAgB,SAAS,aAAa;EACnF;;EAGA,IAAa,wBAAb,MAAmC;GAiBJ;GAhB7B,QAAoC;GACpC,aAA4C;GAC5C,cAA6C;GAC7C,iBAAgD;GAChD,gBAA+C;GAE/C,gBAAiD;GACjD,eAA8C;GAC9C,eAAgD;GAChD,aAAqB;;GAErB,gBAA4C;;GAE5C,cAAgC,CAAC;GACjC;GACA,YAAuC,CAAC;GACxC,YAAY,QAAsC;IAArB,KAAA,SAAA;GAAsB;;GAGnD,QAAc;IACZ,MAAM,kBAAwB;KAC5B,IAAI,KAAK,UAAU,MAAM;KACzB,MAAM,QAAQ,UAAU;KACxB,IAAI,UAAU,MAAM;KACpB,KAAK,OAAO,KAAK;IACnB;IACA,KAAK,eAAe,IAAI,uBAAuB;KAAE,UAAU;IAAE,CAAC;IAC9D,KAAK,aAAa,QAAQ,SAAS,MAAM;KAAE,WAAW;KAAM,SAAS;IAAK,CAAC;IAC3E,UAAU;GACZ;;GAGA,OAAe,OAA0B;IACvC,KAAK,QAAQ;IACb,eAAe;IAIf,KAAK,cAAc,WAAW;IAC9B,KAAK,eAAe;IACpB,KAAK,gBAAgB;IAGrB,MAAM,aAAa,SAAS,cAAc,KAAK;IAC/C,WAAW,QAAQ,oBAAoB;IACvC,WAAW,YAAY;IACvB,WAAW,MAAM,WAAW;IAC5B,WAAW,MAAM,WAAW;IAC5B,WAAW,MAAM,UAAU;IAC3B,WAAW,MAAM,gBAAgB;IACjC,WAAW,MAAM,aAAa;IAE9B,MAAM,cAAc,SAAS,cAAc,KAAK;IAChD,YAAY,QAAQ,qBAAqB;IACzC,YAAY,YAAY;IACxB,YAAY,MAAM,WAAW;IAC7B,YAAY,MAAM,WAAW;IAC7B,YAAY,MAAM,UAAU;IAC5B,YAAY,MAAM,gBAAgB;IAClC,YAAY,MAAM,aAAa;IAE/B,MAAM,YAAY,UAAU;IAC5B,MAAM,YAAY,WAAW;IAC7B,KAAK,aAAa;IAClB,KAAK,cAAc;IAInB,KAAK,iBAAiB,KAAK,aAAa,2BAAA,IAAkD,MAAM,UAAU;IAC1G,KAAK,gBAAgB,KAAK,aAAa,0BAAA,IAAgD,MAAM,SAAS;IACtG,MAAM,YAAY,KAAK,cAAc;IACrC,MAAM,YAAY,KAAK,aAAa;IAKpC,MAAM,aAAa,UAA+B;KAChD,IAAI,MAAM,QAAQ,UAAU;KAC5B,MAAM,SAAS,MAAM,kBAAkB,UAAU,MAAM,SAAS;KAChE,IAAI,WAAW,QAAQ,OAAO,QAAQ,6CAA2C,MAAM,MAAM;KAC7F,KAAK,OAAO,QAAQ,SAAU,KAAK,cAAc,OAAO,OAAO;MAAE,GAAG;MAAM,WAAW;KAAK,CAAE;IAC9F;IACA,OAAO,iBAAiB,WAAW,SAAS;IAC5C,KAAK,UAAU,WAAW,OAAO,oBAAoB,WAAW,SAAS,CAAC;IAG1E,MAAM,iBAAuB;KAC3B,MAAM,KAAK,KAAK;KAChB,IAAI,OAAO,MAAM;KACjB,MAAM,SAAS,GAAG,MAAM;KACxB,IAAI,WAAW,IAAI;KACnB,MAAM,SAAS,gBAAgB,MAAM;KACrC,IAAI,OAAO,UAAU,KAAK,OAAO,UAAU,GAAG;MAE5C,KAAK,cAAc;MACnB,KAAK,UAAU;MACf;KACF;KACA,IAAI,OAAO,WAAW,KAAK,KAAK,YAAY,WAAW,GAErD;KAIF,IAAI,OAAO,WAAW,KAAK,OAAO,SAAS,YAAY,KAAK,KAAK,YAAY,WAAW,GAAG;MACzF,KAAK,UAAU;MACf;KACF;IACF;IACA,KAAK,gBAAgB,IAAI,iBAAiB,QAAQ;IAClD,KAAK,cAAc,QAAQ,OAAO;KAAE,YAAY;KAAM,iBAAiB,CAAC,OAAO;IAAE,CAAC;IAGlF,MAAM,gBAAsB;KAC1B,IAAI,KAAK,UAAU,MAAM;KACzB,KAAK,aAAa,KAAK,MAAM,sBAAsB,CAAC,CAAC;KACrD,MAAM,UAAU,KAAK,YAAY,UAAU,IAAI,QAAQ,KAAK,YAAY,EAAE,IAAI;KAC9E,MAAM,UAAU,KAAK,YAAY,UAAU,IAAI,QAAQ,KAAK,YAAY,EAAE,IAAI;KAC9E,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,aAAa,UAAU,OAAO;KACjE,MAAM,QAAQ,KAAK,OAAO,YAAY;KACtC,IAAI,KAAK,IAAI,MAAM,iBAAiB,SAAS,IAAI,IAC/C,KAAK,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,gBAAgB;KAAU,EAAE;KAEvE,KAAK,OAAO,YAAY,KAAK,OAAO,YAAY,CAAC;IACnD;IACA,KAAK,eAAe,IAAI,qBAAqB;KAC3C,QAAQ;KACR,KAAK,UAAU;IACjB,CAAC;IACD,KAAK,aAAa,QAAQ,KAAK;IAG/B,KAAK,UAAU,KAAK,KAAK,OAAO,gBAAgB,KAAK,UAAU,CAAC,CAAC;IAGjE,MAAM,UAAU,MAAM,MAAM;IAC5B,IAAI,YAAY,IAAI;KAClB,MAAM,SAAS,gBAAgB,OAAO;KACtC,IAAI,OAAO,UAAU,KAAK,OAAO,UAAU,GACzC,KAAK,cAAc;UACd,IAAI,OAAO,WAAW,KAAK,QAAQ,OAAO,EAAE,IAAI,GAOrD,KAAK,cAAc,OAAO,MAAM,GAAG,CAAC;IAExC;IACA,QAAQ;IACR,KAAK,UAAU;GACjB;;GAGA,aACE,WACA,UACA,SACA,MACgB;IAChB,MAAM,KAAK,SAAS,cAAc,KAAK;IACvC,GAAG,YAAY;IACf,GAAG,MAAM,WAAW;IACpB,GAAG,MAAM,MAAM;IACf,GAAG,MAAM,SAAS;IAOlB,GAAG,MAAM,SAAS;IAClB,GAAG,MAAM,SAAS;IAClB,GAAG,MAAM,QAAQ,GAAG,SAAS;IAC7B,IAAI,SAEF,GAAG,MAAM,aAAa,IAAI,SAAS;IAErC,GAAG,iBAAiB,gBAAgB,UAAwB;KAC1D,MAAM,aAAa,SAAS;KAC5B,uBAAuB,OAAO,IAAI;MAChC;MACA,qBAAqB;OACnB,MAAM,QAAQ,KAAK,OAAO,YAAY;OACtC,OAAO,aAAa,MAAM,gBAAgB,MAAM;MAClD;MACA,UAAU,YAAY,WAAW,gBAC/B,aAAa,aAAa,WAC1B,YACA,QACA,KAAK,OAAO,YAAY,CAC1B;MACA,UAAU,UAAU;OAGlB,KAAK,OAAO,QAAQ,SAClB,aAAa;QAAE,GAAG;QAAM,eAAe;OAAM,IAAI;QAAE,GAAG;QAAM,cAAc;OAAM,CACjF;MACH;MACA,QAAQ,UAAU;OAChB,kBAAkB,aAAa,qBAAqB,mBAAmB,KAAK;MAC9E;KACF,CAAC;IACH,CAAC;IAGD,GAAG,iBAAiB,kBAAkB;KACpC,KAAK,cAAc;MACjB,MAAM,QAAQ,SAAS,aAAA,MAAA;MACvB,KAAK,OAAO,QAAQ,SAClB,SAAS,aAAa;OAAE,GAAG;OAAM,eAAe;MAAM,IAAI;OAAE,GAAG;OAAM,cAAc;MAAM,CAC1F;MACD,kBAAkB,SAAS,aAAa,qBAAqB,mBAAmB,KAAK;MACrF,KAAK,UAAU;KACjB,CAAC;IACH,CAAC;IAED,OAAO;GACT;;GAGA,iBAAuB;IACrB,MAAM,QAAQ,KAAK,OAAO,YAAY;IACtC,MAAM,OAAO,CAAC,MAAM;IACpB,KAAK,cAAc;KACjB,KAAK,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,mBAAmB;KAAK,EAAE;KACnE,IAAI;MACF,aAAa,QAAQ,0BAA0B,MAAM,QAAQ,OAAO,cAAc,UAAU;KAC9F,QAAQ,CAER;KACA,KAAK,UAAU;IACjB,CAAC;GACH;;GAGA,eAAe,MAAqB;IAClC,KAAK,cAAc;KACjB,KAAK,OAAO,QAAQ,UAAU;MAAE,GAAG;MAAM,aAAa;KAAK,EAAE;KAC7D,KAAK,UAAU;IACjB,CAAC;GACH;;;;;;;GAQA,mBAA0C;IACxC,MAAM,QAAQ,KAAK;IACnB,IAAI,UAAU,MAAM,OAAO;IAC3B,MAAM,SAAS,MAAM,cACnB,oEACF;IACA,IAAI,WAAW,MAAM,OAAO;IAC5B,MAAM,SAAS,OAAO,sBAAsB,CAAC,CAAC;IAC9C,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS;GAC5C;;GAIA,QAAgB,IAAsB;IACpC,MAAM,QAAQ,KAAK;IACnB,IAAI,UAAU,MAAM;KAClB,GAAG;KACH;IACF;IACA,MAAM,aAAa,wBAAwB,EAAE;IAC7C,IAAI,KAAK,iBAAiB,KAAA,GAAW,aAAa,KAAK,YAAY;IACnE,KAAK,eAAe,iBAAiB;KACnC,KAAK,eAAe,KAAA;KACpB,MAAM,gBAAgB,sBAAsB;IAC9C,GAAG,CAAC;IACJ,GAAG;GACL;;GAGA,YAA0B;IACxB,MAAM,QAAQ,KAAK;IACnB,IAAI,UAAU,MAAM;IAKpB,IAAI,KAAK,YAAY,WAAW,GAAG;IACnC,MAAM,QAAQ,KAAK,OAAO,YAAY;IACtC,MAAM,QAAQ,KAAK,aAAa,IAAI,KAAK,aAAa,MAAM,sBAAsB,CAAC,CAAC;IAEpF,IAAI,MAAM,cAAc,MAAM;KAC5B,KAAK,eAAe,OAAO,MAAM,WAAW,KAAK;KACjD;IACF;IACA,KAAK,qBAAqB;IAE1B,MAAM,WAAW,KAAK,OAAO,gBAAgB,KAAK;IAClD,MAAM,UAAU,KAAK,OAAO,eAAe,KAAK;IAQhD,MAAM,aAFa,gBAAgB,MAAM,MAAM,mBACd,CAAC,CAAC,SAAS,YACX,IAAI,MAAM,cAA2B,qBAAqB,IAAI;IAC/F,MAAM,cAAc,eAAe,QAC9B,WAAW,MAAM,YAAY,UAC7B,WAAW,sBAAsB,CAAC,CAAC,QAAQ;IAChD,MAAM,eAAe,cAAc,KAAK,MAAM,WAAY,sBAAsB,CAAC,CAAC,KAAK,IAAI;IAI3F,MAAM,WACJ,GAAG,KAAK,YAAY,GAAG,kBAAkB,KAAK,YAAY,GAAG,GAAG,KAAK,MAAM,OAAO,EAAE,KAAK,KAAK,MAAM,QAAQ,EAAE;IAChH,MAAM,MAAM,sBAAsB,cAC9B,GAAG,SAAS,cAAc,aAAa,MACvC;IAGJ,IAAI,KAAK,gBAAgB,MACvB,KAAK,YAAY,MAAM,aAAa,WAAW,IAAI,YAAY;IAEjE,IAAI,KAAK,eAAe,MACtB,KAAK,WAAW,MAAM,aAAa,UAAU,IAAI,YAAY;IAI/D,IAAI,KAAK,mBAAmB,MAAM;KAChC,MAAM,OAAO,KAAK,MAAM,QAAQ,WAAW,YAAY;KACvD,KAAK,eAAe,MAAM,OAAO,GAAG,KAAK;KACzC,KAAK,eAAe,MAAM,aAAa,GAAG,MAAyB,EAAE;KACrE,KAAK,eAAe,MAAM,UAAU,WAAW,KAAK,MAAM,SAAS,KAAK,UAAU;IACpF;IACA,IAAI,KAAK,kBAAkB,MAAM;KAC/B,MAAM,OAAO,KAAK,MAAM,QAAQ,WAAW,UAAU,YAAY;KACjE,KAAK,cAAc,MAAM,OAAO,GAAG,KAAK;KACxC,KAAK,cAAc,MAAM,UAAU,UAAU,KAAK,MAAM,SAAS,KAAK,UAAU;IAClF;IASA,MAAM,eAAe,QAAQ,KAAK,YAAY,EAAE;IAIhD,IAAI,KAAK,kBAAkB,QAAQ,CAAC,KAAK,cAAc,aACrD,KAAK,gBAAgB,MAAM,cAA2B,yBAAuB;IAE/E,IAAI,KAAK,kBAAkB,MACzB,KAAK,cAAc,MAAM,OAAO,GAAG,KAAK,MAAM,QAAQ,eAAe,UAAU,WAAW,YAAY,EAAE;GAG5G;;;;;;;GAQA,eAAuB,OAAoB,QAAwB,OAAqB;IACtF,MAAM,UAAU,iBAAiB,KAAK,OAAO,YAAY,CAAC,CAAC,cAAc;IACzE,IAAI,CAAC,SACH,MAAM,MAAM,sBAAsB,oBAAoB,QAAQ,KAAK;IAErE,IAAI,KAAK,gBAAgB,MAAM;KAC7B,KAAK,YAAY,MAAM,aAAa,WAAW,aAAa,YAAY;KACxE,KAAK,YAAY,UAAU,OAAO,qBAAqB,WAAW,cAAc,OAAO;IACzF;IACA,IAAI,KAAK,eAAe,MAAM;KAC5B,KAAK,WAAW,MAAM,aAAa,WAAW,YAAY,YAAY;KACtE,KAAK,WAAW,UAAU,OAAO,qBAAqB,WAAW,aAAa,OAAO;IACvF;IAEA,IAAI,KAAK,mBAAmB,MAAM,KAAK,eAAe,MAAM,UAAU;IACtE,IAAI,KAAK,kBAAkB,MAAM,KAAK,cAAc,MAAM,UAAU;GACtE;;GAGA,uBAAqC;IACnC,KAAK,aAAa,UAAU,OAAO,mBAAmB;IACtD,KAAK,YAAY,UAAU,OAAO,mBAAmB;GACvD;;GAGA,UAAgB;IACd,KAAK,cAAc,WAAW;IAC9B,KAAK,eAAe,WAAW;IAC/B,KAAK,cAAc,WAAW;IAC9B,KAAK,MAAM,WAAW,KAAK,WAAW,QAAQ;IAC9C,KAAK,YAAY,OAAO;IACxB,KAAK,aAAa,OAAO;IACzB,KAAK,gBAAgB,OAAO;IAC5B,KAAK,eAAe,OAAO;IAE3B,IAAI,KAAK,iBAAiB,KAAA,GAAW,aAAa,KAAK,YAAY;IACnE,IAAI,iBAAiB,KAAK,OAAO,eAAe;IAChD,KAAK,QAAQ;GACf;EACF;;;;;;;;;ECngBA,MAAM,KAAK;GACT,uBAAuB;GACvB,yBAAyB;GACzB,+BAA+B;GAC/B,6BAA6B;GAC7B,yBAAyB;GACzB,yBAAyB;GACzB,6BAA6B;GAC7B,uBAAuB;GACvB,qBAAqB;GACrB,mBAAmB;GACnB,qBAAqB;GACrB,oBAAoB;GACpB,wBAAwB;GACxB,0BAA0B;GAC1B,oBAAoB;GACpB,eAAe;GACf,cAAc;GACd,gBAAgB;GAChB,iBAAiB;GACjB,kBAAkB;GAClB,aAAa;GACb,eAAe;GACf,eAAe;GACf,gBAAgB;GAChB,kBAAkB;GAClB,aAAa;GACb,eAAe;GACf,kBAAkB;GAClB,eAAe;GACf,cAAc;GACd,gBAAgB;GAChB,gBAAgB;GAChB,6BAA6B;GAC7B,+BAA+B;GAC/B,kBAAkB;GAClB,qBAAqB;GACrB,yBAAyB;GACzB,oBAAoB;GACpB,mBAAmB;GACnB,kBAAkB;GAClB,mBAAmB;GACnB,kBAAkB;GAClB,iBAAiB;GACjB,mBAAmB;GACnB,2BAA2B;GAC3B,gBAAgB;GAChB,oBAAoB;GACpB,oBAAoB;GACpB,wBAAwB;GACxB,wBAAwB;GACxB,iBAAiB;GACjB,qBAAqB;GACrB,sBAAsB;GACtB,uBAAuB;GACvB,oBAAoB;GACpB,6BAA6B;GAC7B,4BAA4B;GAC5B,iBAAiB;GACjB,wBAAwB;GACxB,0BAA0B;GAC1B,uBAAuB;GACvB,wBAAwB;GACxB,2BAA2B;GAC3B,oBAAoB;GACpB,iBAAiB;GACjB,kBAAkB;GAClB,gBAAgB;GAChB,iBAAiB;GACjB,mBAAmB;GACnB,iBAAiB;GACjB,0BAA0B;GAC1B,0BAA0B;GAC1B,wBAAwB;GACxB,iCAAiC;GACjC,wBAAwB;GACxB,yBAAyB;GACzB,2BAA2B;GAC3B,wBAAwB;GACxB,yBAAyB;GACzB,0BAA0B;GAC1B,4BAA4B;GAC5B,+BAA+B;GAC/B,8BAA8B;GAC9B,qBAAqB;GACrB,uBAAuB;GACvB,kBAAkB;GAClB,wBAAwB;GACxB,oBAAoB;GACpB,wBAAwB;GACxB,uBAAuB;GACvB,kBAAkB;GAClB,uBAAuB;GACvB,qBAAqB;GACrB,oBAAoB;GACpB,eAAe;GACf,gBAAgB;GAChB,mBAAmB;GACnB,qBAAqB;GACrB,iBAAiB;GACjB,mBAAmB;GACnB,oBAAoB;GACpB,oBAAoB;GACpB,uBAAuB;GACvB,0BAA0B;EAC5B;EAEA,MAAM,KAAsC;GAC1C,uBAAuB;GACvB,yBAAyB;GACzB,+BAA+B;GAC/B,6BAA6B;GAC7B,yBAAyB;GACzB,yBAAyB;GACzB,6BAA6B;GAC7B,uBAAuB;GACvB,qBAAqB;GACrB,mBAAmB;GACnB,qBAAqB;GACrB,oBAAoB;GACpB,wBAAwB;GACxB,0BAA0B;GAC1B,oBAAoB;GACpB,eAAe;GACf,cAAc;GACd,gBAAgB;GAChB,iBAAiB;GACjB,kBAAkB;GAClB,aAAa;GACb,eAAe;GACf,eAAe;GACf,gBAAgB;GAChB,kBAAkB;GAClB,aAAa;GACb,eAAe;GACf,kBAAkB;GAClB,eAAe;GACf,cAAc;GACd,gBAAgB;GAChB,gBAAgB;GAChB,6BAA6B;GAC7B,+BAA+B;GAC/B,kBAAkB;GAClB,qBAAqB;GACrB,yBAAyB;GACzB,oBAAoB;GACpB,mBAAmB;GACnB,kBAAkB;GAClB,mBAAmB;GACnB,kBAAkB;GAClB,iBAAiB;GACjB,mBAAmB;GACnB,2BAA2B;GAC3B,gBAAgB;GAChB,oBAAoB;GACpB,oBAAoB;GACpB,wBAAwB;GACxB,wBAAwB;GACxB,iBAAiB;GACjB,qBAAqB;GACrB,sBAAsB;GACtB,uBAAuB;GACvB,oBAAoB;GACpB,6BAA6B;GAC7B,4BAA4B;GAC5B,iBAAiB;GACjB,wBAAwB;GACxB,0BAA0B;GAC1B,uBAAuB;GACvB,wBAAwB;GACxB,2BAA2B;GAC3B,oBAAoB;GACpB,iBAAiB;GACjB,kBAAkB;GAClB,gBAAgB;GAChB,iBAAiB;GACjB,mBAAmB;GACnB,iBAAiB;GACjB,0BAA0B;GAC1B,0BAA0B;GAC1B,wBAAwB;GACxB,iCAAiC;GACjC,wBAAwB;GACxB,yBAAyB;GACzB,2BAA2B;GAC3B,wBAAwB;GACxB,yBAAyB;GACzB,0BAA0B;GAC1B,4BAA4B;GAC5B,+BAA+B;GAC/B,8BAA8B;GAC9B,qBAAqB;GACrB,uBAAuB;GACvB,kBAAkB;GAClB,wBAAwB;GACxB,oBAAoB;GACpB,wBAAwB;GACxB,uBAAuB;GACvB,kBAAkB;GAClB,uBAAuB;GACvB,qBAAqB;GACrB,oBAAoB;GACpB,eAAe;GACf,gBAAgB;GAChB,mBAAmB;GACnB,qBAAqB;GACrB,iBAAiB;GACjB,mBAAmB;GACnB,oBAAoB;GACpB,oBAAoB;GACpB,uBAAuB;GACvB,0BAA0B;EAC5B;;EAKA,MAAa,KAAK;;EAGlB,SAAgB,OAAO,UAAkB,QAAiD;GACxF,OAAO,SAAS,QAAQ,eAAe,GAAG,QAAgB,OAAO,OAAO,QAAQ,IAAI,IAAI,EAAE,CAAC;EAC7F;;EAGA,MAAa,eAAyE;GAAE;GAAI;EAAG;EAE/F,IAAI,kBAA+B;;EAGnC,SAAgB,YAAY,UAAwB;GAClD,kBAAkB,aAAa,OAAO,OAAO;EAC/C;;EAGA,SAAgB,EAAE,KAA0B,QAAkD;GAE5F,MAAM,YADQ,aAAa,oBAAoB,GAAA,CACxB,QAAQ,GAAG;GAClC,OAAO,WAAW,KAAA,IAAY,WAAW,OAAO,UAAU,MAAM;EAClE;;;;;;;;;;EC3OA,SAAgB,SAAY,OAA0B;GACpD,QAAA,GAAA,MAAA,qBAAA,CAA4B,MAAM,WAAW,MAAM,aAAa,MAAM,WAAW;EACnF;;;ECCA,MAAM,QAAQ,UAA2C;GACvD,OAAO;GACP,QAAQ;GACR,SAAS;GACT,MAAM;GACN,QAAQ;GACR,aAAa;GACb,eAAe;GACf,gBAAgB;GAChB,eAAe;EACjB;EAEA,SAAgB,WAAW,EAAE,OAAO,IAAI,aAAqC;GAC3E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,sFAAuF,CAAA;GAC5F,CAAA;EAET;EAEA,SAAgB,eAAe,EAAE,OAAO,IAAI,aAAqC;GAC/E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,mFAAoF,CAAA,GAC5F,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,qEAAsE,CAAA,CAC3E;;EAET;EAEA,SAAgB,SAAS,EAAE,OAAO,IAAI,aAAqC;GACzE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,gDAAiD,CAAA,GACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,WAAY,CAAA,CACjB;;EAET;EAEA,SAAgB,aAAa,EAAE,OAAO,IAAI,aAAqC;GAC7E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,gDAAiD,CAAA;KACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,WAAY,CAAA;KACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,mDAAoD,CAAA;IACzD;;EAET;EAEA,SAAgB,cAAc,EAAE,OAAO,IAAI,aAAqC;GAC9E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,gDAAiD,CAAA;KACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,WAAY,CAAA;KACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAQ,IAAG;MAAM,IAAG;MAAM,GAAE;KAAK,CAAA;KACjC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,sCAAuC,CAAA;IAC5C;;EAET;EAEA,SAAgB,aAAa,EAAE,OAAO,IAAI,aAAqC;GAC7E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,gDAAiD,CAAA;KACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,WAAY,CAAA;KACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,kBAAmB,CAAA;IACxB;;EAET;EAEA,SAAgB,iBAAiB,EAAE,OAAO,IAAI,aAAqC;GACjF,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,wBAAyB,CAAA;GAC9B,CAAA;EAET;EAEA,SAAgB,gBAAgB,EAAE,OAAO,IAAI,aAAqC;GAChF,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,wBAAyB,CAAA;GAC9B,CAAA;EAET;EAEA,SAAgB,UAAU,EAAE,OAAO,IAAI,aAAqC;GAC1E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,6BAA8B,CAAA;GACnC,CAAA;EAET;EAEA,SAAgB,SAAS,EAAE,OAAO,IAAI,aAAqC;GACzE,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,iBAAkB,CAAA;GACvB,CAAA;EAET;EAEA,SAAgB,UAAU,EAAE,OAAO,IAAI,aAAqC;GAC1E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,UAAW,CAAA;GAChB,CAAA;EAET;EAEA,SAAgB,SAAS,EAAE,OAAO,IAAI,aAAqC;GACzE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,qBAAsB,CAAA,GAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,gCAAiC,CAAA,CACtC;;EAET;EAEA,SAAgB,YAAY,EAAE,OAAO,IAAI,aAAqC;GAC5E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,2BAA4B,CAAA,GACpC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,mBAAoB,CAAA,CACzB;;EAET;EAEA,SAAgB,UAAU,EAAE,OAAO,IAAI,aAAqC;GAC1E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,GAAE;KAAI,GAAE;KAAM,OAAM;KAAK,QAAO;KAAK,IAAG;IAAK,CAAA,GACnD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,YAAa,CAAA,CAClB;;EAET;EAEA,SAAgB,SAAS,EAAE,OAAO,IAAI,aAAqC;GACzE,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,4CAA6C,CAAA;GAClD,CAAA;EAET;EAEA,SAAgB,QAAQ,EAAE,OAAO,IAAI,aAAqC;GACxE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,mEAAoE,CAAA,GAC5E,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;KAAQ,IAAG;KAAI,IAAG;KAAI,GAAE;IAAK,CAAA,CAC1B;;EAET;EAEA,SAAgB,SAAS,EAAE,OAAO,IAAI,aAAqC;GACzE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,wEAAyE,CAAA,GACjF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,oCAAqC,CAAA,CAC1C;;EAET;EAEA,SAAgB,aAAa,EAAE,OAAO,IAAI,aAAqC;GAC7E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,gCAAiC,CAAA,GACzC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,aAAc,CAAA,CACnB;;EAET;EAYA,SAAgB,WAAW,EAAE,OAAO,IAAI,aAAqC;GAC3E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;KAAQ,IAAG;KAAI,IAAG;KAAI,GAAE;IAAO,CAAA,GAC/B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,iBAAkB,CAAA,CACvB;;EAET;EAEA,SAAgB,WAAW,EAAE,OAAO,IAAI,aAAqC;GAC3E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAQ,IAAG;MAAI,IAAG;MAAM,GAAE;KAAO,CAAA;KACjC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAQ,IAAG;MAAI,IAAG;MAAO,GAAE;KAAO,CAAA;KAClC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAQ,IAAG;MAAK,IAAG;MAAM,GAAE;KAAO,CAAA;KAClC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,2CAA4C,CAAA;IACjD;;EAET;EAEA,SAAgB,SAAS,EAAE,OAAO,IAAI,aAAqC;GACzE,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,+BAAgC,CAAA;GACrC,CAAA;EAET;EAEA,SAAgB,SAAS,EAAE,OAAO,IAAI,aAAqC;GACzE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,6BAA8B,CAAA;KACtC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,WAAY,CAAA;KACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,iBAAkB,CAAA;IACvB;;EAET;EAEA,SAAgB,WAAW,EAAE,OAAO,IAAI,aAAqC;GAC3E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,0BAA2B,CAAA,GACnC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,mBAAoB,CAAA,CACzB;;EAET;EAEA,SAAgB,gBAAgB,EAAE,OAAO,IAAI,aAAqC;GAChF,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,uBAAwB,CAAA;GAC7B,CAAA;EAET;EAUA,SAAgB,aAAa,EAAE,OAAO,IAAI,aAAqC;GAC7E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,GAAE;KAAI,GAAE;KAAI,OAAM;KAAK,QAAO;KAAK,IAAG;IAAK,CAAA;GAC9C,CAAA;EAET;EAEA,SAAgB,YAAY,EAAE,OAAO,IAAI,aAAqC;GAC5E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,GAAI,KAAK,IAAI;IAAc;cAAhC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,GAAE;KAAI,GAAE;KAAI,OAAM;KAAI,QAAO;KAAI,IAAG;IAAK,CAAA,GAC/C,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,8BAA+B,CAAA,CACpC;;EAET;;;;ECnQA,SAAgB,aAAa,EAC3B,MACA,OACA,UACA,aAMc;GACd,IAAI,OACF,OAAO,WACH,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD;IAAgB,MAAM;IAAe;GAAY,CAAA,IACjD,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;IAAY,MAAM;IAAe;GAAY,CAAA;GAGnD,QADa,kBAAkB,IACpB,GAAX;IACE,KAAK,SACH,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;KAAe,MAAM;KAAe;IAAY,CAAA;IACzD,KAAK;IACL,KAAK,QACH,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;KAAc,MAAM;KAAe;IAAY,CAAA;IACxD,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK,QACH,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;KAAc,MAAM;KAAe;IAAY,CAAA;IACxD,SACE,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;KAAU,MAAM;KAAe;IAAY,CAAA;GACtD;EACF;;;;;;;;;;EC/BA,SAAgB,MAAM,SAAuB;GAC3C,MAAM,KAAK,SAAS,cAAc,KAAK;GACvC,GAAG,YAAY;GACf,GAAG,cAAc;GACjB,SAAS,KAAK,YAAY,EAAE;GAC5B,iBAAiB;IACf,GAAG,MAAM,UAAU;IACnB,GAAG,MAAM,aAAa;GACxB,GAAG,IAAI;GACP,iBAAiB,GAAG,OAAO,GAAG,IAAI;EACpC;;EAkBA,SAAgB,YAAY,EAAE,OAAO,WAAiF;GACpH,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAAyD,IAAI;GAE9E,CAAA,GAAA,MAAA,gBAAA,OAAsB;IACpB,IAAI,UAAU,MAAM;KAClB,YAAY,IAAI;KAChB;IACF;IAEA,MAAM,QAAQ;IACd,MAAM,SAAS,MAAM,QAAQ,SAAS,KAAK;IAC3C,YAAY;KACV,GAAG,KAAK,IAAI,MAAM,GAAG,OAAO,aAAa,QAAQ,CAAC;KAClD,GAAG,KAAK,IAAI,MAAM,GAAG,OAAO,cAAc,SAAS,CAAC;IACtD,CAAC;GACH,GAAG,CAAC,KAAK,CAAC;GAEV,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,UAAU,MAAM;IACpB,MAAM,SAAS,UAAuB;KAIpC,IAAI,MAAM,kBAAkB,WAAW,MAAM,OAAO,QAAQ,kBAAkB,MAAM,MAAM;KAC1F,QAAQ;IACV;IACA,MAAM,OAAO,UAA+B;KAC1C,IAAI,MAAM,QAAQ,UAAU,QAAQ;IACtC;IACA,OAAO,iBAAiB,eAAe,OAAO,EAAE,SAAS,KAAK,CAAC;IAC/D,OAAO,iBAAiB,QAAQ,OAAO;IACvC,OAAO,iBAAiB,WAAW,GAAG;IACtC,OAAO,iBAAiB,eAAe,OAAO;IAC9C,aAAa;KACX,OAAO,oBAAoB,eAAe,OAAO,EAAE,SAAS,KAAK,CAAC;KAClE,OAAO,oBAAoB,QAAQ,OAAO;KAC1C,OAAO,oBAAoB,WAAW,GAAG;KACzC,OAAO,oBAAoB,eAAe,OAAO;IACnD;GACF,GAAG,CAAC,OAAO,OAAO,CAAC;GAEnB,IAAI,UAAU,QAAQ,aAAa,MAAM,OAAO;GAChD,QAAA,GAAA,UAAA,aAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IACE,WAAU;IACV,kBAAe;IACf,OAAO;KAAE,MAAM,SAAS;KAAG,KAAK,SAAS;IAAE;IAC3C,gBAAgB,UAAU,MAAM,gBAAgB;IAChD,gBAAgB,UAAU,MAAM,eAAe;cAE9C,MAAM,QAAQ,KAAK,UAClB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAA,UACG,MAAM,UAAU,QACf,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAK,WAAU,mBAAoB,CAAA,IAEnC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KACE,WAAW,oBAAoB,MAAM,aAAa,OAAO,gCAAgC;KACzF,eAAe;MACb,IAAI,MAAM,aAAa,MAAM;MAC7B,QAAQ;MACR,MAAM,WAAW;KACnB;KACA,MAAK;eAEJ,MAAM;IACJ,CAAA,EAEJ,GAhBK,MAAM,GAgBX,CACN;GACE,CAAA,GACL,SAAS,IACX;EACF;;EAGA,SAAgB,aAAa,EAC3B,OACA,cACA,cACA,WACA,YAOc;GACd,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,gBAAgB,EAAE;GACrD,MAAM,YAAA,GAAA,MAAA,OAAA,CAAoC,IAAI;GAC9C,CAAA,GAAA,MAAA,gBAAA,OAAsB;IACpB,SAAS,SAAS,MAAM;IACxB,SAAS,SAAS,OAAO;GAC3B,GAAG,CAAC,CAAC;GACL,MAAM,eAAqB;IACzB,MAAM,UAAU,MAAM,KAAK;IAC3B,IAAI,YAAY,IAAI;IACpB,UAAU,OAAO;GACnB;GACA,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,OAAO,UAA+B;KAC1C,IAAI,MAAM,QAAQ,UAAU,SAAS;IACvC;IACA,OAAO,iBAAiB,WAAW,GAAG;IACtC,aAAa,OAAO,oBAAoB,WAAW,GAAG;GACxD,GAAG,CAAC,QAAQ,CAAC;GACb,QAAA,GAAA,UAAA,aAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAU;IAAkB,eAAe;cAC9C,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;KAAiB,gBAAgB,UAAU,MAAM,gBAAgB;eAAhF;MACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAU;iBAAwB;MAAW,CAAA;MAClD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAU;iBACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,KAAK;QACL,WAAU;QACH;QACP,aAAa,gBAAgB;QAC7B,cAAY;QACZ,WAAW,UAAU,SAAS,MAAM,OAAO,KAAK;QAChD,YAAY,UAAU;SACpB,IAAI,MAAM,QAAQ,SAAS,OAAO;QACpC;OACD,CAAA;MACE,CAAA;MACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAU;iBAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAU;QAAc,SAAS;kBAAW,EAAE,eAAe;OAAU,CAAA,GAC7F,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAU;QACV,UAAU,MAAM,KAAK,MAAM;QAC3B,SAAS;kBAER,gBAAgB,EAAE,gBAAgB;OAC7B,CAAA,CACL;;KACF;;GACF,CAAA,GACL,SAAS,IACX;EACF;;EAGA,SAAgB,cAAc,EAC5B,OACA,MACA,cACA,QACA,WACA,YAQc;GACd,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,OAAO,UAA+B;KAC1C,IAAI,MAAM,QAAQ,UAAU,SAAS;IACvC;IACA,OAAO,iBAAiB,WAAW,GAAG;IACtC,aAAa,OAAO,oBAAoB,WAAW,GAAG;GACxD,GAAG,CAAC,QAAQ,CAAC;GACb,QAAA,GAAA,UAAA,aAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAU;IAAkB,eAAe;cAC9C,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;KAAiB,gBAAgB,UAAU,MAAM,gBAAgB;eAAhF;MACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAU;iBAAwB;MAAW,CAAA;MAClD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAU;iBAAuB;MAAU,CAAA;MAChD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAU;iBAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAU;QAAc,SAAS;kBAAW,EAAE,eAAe;OAAU,CAAA,GAC7F,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAW,eAAe,WAAW,OAAO,uBAAuB;QACnE,SAAS;kBAER,gBAAgB,EAAE,gBAAgB;OAC7B,CAAA,CACL;;KACF;;GACF,CAAA,GACL,SAAS,IACX;EACF;;;;;;;;;;;;ECrNA,SAAgB,cAAc,SAAqB;GACjD,QAAQ,UAA4C;IAClD,IAAI,MAAM,WAAW,MAAM,eAAe;IAC1C,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;KAC9C,MAAM,eAAe;KACrB,QAAQ;IACV;GACF;EACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECSA,MAAM,uBAAuB;;EAG7B,MAAM,QAA+D;GACnE,SAAS;IAAE,QAAQ;IAAK,WAAWC,uBAAO;GAAa;GACvD,UAAU;IAAE,QAAQ;IAAK,WAAWA,uBAAO;GAAc;GACzD,SAAS;IAAE,QAAQ;IAAK,WAAWA,uBAAO;GAAa;GACvD,SAAS;IAAE,QAAQ;IAAK,WAAWA,uBAAO;GAAa;GACvD,YAAY;IAAE,QAAQ;IAAK,WAAWA,uBAAO;GAAgB;GAC7D,WAAW;IAAE,QAAQ;IAAK,WAAWA,uBAAO;GAAe;GAC3D,SAAS;IAAE,QAAQ;IAAK,WAAWA,uBAAO;GAAe;EAC3D;;EAGA,SAASC,QAAM,MAAsB;GACnC,MAAM,MAAM,KAAK,YAAY,GAAG;GAChC,OAAO,MAAM,IAAI,KAAK,MAAM,GAAG,GAAG,IAAI;EACxC;;EAGA,SAAS,UAAU,MAAmD;GACpE,MAAM,wBAAQ,IAAI,IAA4B;GAC9C,KAAK,MAAM,OAAO,MAAM;IACtB,MAAM,MAAMA,QAAM,IAAI,IAAI;IAC1B,MAAM,OAAO,MAAM,IAAI,GAAG;IAC1B,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC;SACvC,KAAK,KAAK,GAAG;GACpB;GACA,OAAO;EACT;;;;EAKA,SAAgB,SAAS,EAAE,UAAgD;GACzE,MAAM,MAAM,OAAO;GACnB,MAAM,UAAU,OAAO;GACvB,MAAM,QAAQ,SAAS,GAAG;GAC1B,MAAM,CAAC,gBAAgB,sBAAA,GAAA,MAAA,SAAA,CAAqD,IAAI;GAQhF,MAAM,oBAAA,GAAA,MAAA,OAAA,CAA0B,SAAS;GACzC,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,gBAAsB;KAC1B,MAAM,MAAM,KAAK,IAAI;KACrB,IAAI,MAAM,iBAAiB,UAAU,sBAAsB;KAC3D,iBAAiB,UAAU;KAC3B,IAAS,QAAQ;IACnB;IACA,OAAO,iBAAiB,SAAS,OAAO;IACxC,aAAa,OAAO,oBAAoB,SAAS,OAAO;GAC1D,GAAG,CAAC,GAAG,CAAC;GAER,MAAM,SAAS,MAAM;GACrB,MAAM,qBAAqB,MAAM,iBAAiB,eAAe;GAEjE,MAAM,kBAAkB,SAA+B;IACrD,IAAI,KAAK,WAAW,GAAG;IACvB,kBAAkB,IAAI;GACxB;GACA,MAAM,uBAA6B;IACjC,IAAI,mBAAmB,MAAM;IAC7B,IAAS,QAAQ,eAAe,KAAK,QAAQ,IAAI,IAAI,CAAC;IACtD,kBAAkB,IAAI;GACxB;GAEA,IAAI,MAAM,WAAW,WAAW,MAC9B,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAW,gBAAgBD,uBAAO;cAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,uBAAO;eAAU,EAAE,aAAa;IAAO,CAAA;GAAM,CAAA;GAEtH,IAAI,MAAM,YACR,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAW,gBAAgBA,uBAAO;cAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,uBAAO;eAAU,EAAE,gBAAgB;IAAO,CAAA;GAAM,CAAA;GAEzH,IAAI,WAAW,MACb,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAW,gBAAgBA,uBAAO;cAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,uBAAO;eAAU,EAAE,aAAa;IAAO,CAAA;GAAM,CAAA;GAGtH,MAAM,SAAS,OAAO;GACtB,MAAM,WAAW,OAAO;GACxB,MAAM,YAAY,OAAO;GACzB,MAAM,aAAa,OAAO,SAAS,SAAS,SAAS,UAAU,SAAS;GACxE,MAAM,eAAe,mBAAmB,QAAQ,eAAe,OAAO,QAAQ,IAAI,UAAU,WAAW;GAEvG,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAW,gBAAgBA,uBAAO;cAAvC,CAEE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,uBAAO;KAAS,OAAO;MAAE,MAAM,qBAAqB,IAAI,KAAA;MAAW,WAAW,qBAAqB,KAAA,IAAY;KAAG;eAAlI,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MACE,WAAWA,uBAAO;MAClB,eAAe,IAAI,oBAAoB,WAAW,kBAAkB;MACpE,WAAW,oBAAoB;OAAE,IAAI,oBAAoB,WAAW,kBAAkB;MAAE,CAAC;MACzF,MAAK;MACL,UAAU;MACV,iBAAe;gBANjB;OAQE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAW,GAAGA,uBAAO,iBAAiB,qBAAqB,IAAIA,uBAAO,uBAAuB;kBACjG,iBAAA,GAAA,kBAAA,IAAA,CAAC,kBAAD,EAAkB,MAAM,GAAK,CAAA;OACzB,CAAA;OACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,uBAAO;kBAAe,EAAE,aAAa;OAAQ,CAAA;OAC7D,OAAO,WAAW,MACjB,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;QAAM,WAAWA,uBAAO;QAAY,OAAO;SAAE,UAAU;SAAI,OAAO;SAA6B,SAAS;SAAQ,YAAY;SAAU,KAAK;QAAE;kBAA7I,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD,EAAY,MAAM,GAAK,CAAA,GACtB,OAAO,MACJ;;OAER,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;QACE,OAAO;SAAE,SAAS;SAAQ,YAAY;SAAU,KAAK;SAAG,YAAY;QAAO;QAC3E,UAAU,UAAU,MAAM,gBAAgB;kBAF5C;SAIE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,uBAAO;UAClB,OAAO,EAAE,cAAc;UACvB,eAAe,KAAK,IAAI,MAAM,SAAS,KAAK,QAAQ,IAAI,IAAI,CAAC;UAC7D,UAAU,SAAS,WAAW;oBAE9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;SACf,CAAA;SACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,uBAAO;UAClB,OAAO,EAAE,gBAAgB;UACzB,eAAe,eAAe,CAAC,GAAG,UAAU,GAAG,SAAS,CAAC;UACzD,UAAU,SAAS,SAAS,UAAU,WAAW;oBAEjD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;SACf,CAAA;SACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,uBAAO;UAClB,OAAO,EAAE,cAAc;UACvB,OAAO,EAAE,OAAO,MAAM,aAAa,SAAS,sBAAsB,KAAA,EAAU;UAC5E,eAAe,IAAI,YAAY,MAAM;oBAErC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;SACf,CAAA;SACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,uBAAO;UAClB,OAAO,EAAE,cAAc;UACvB,OAAO,EAAE,OAAO,MAAM,aAAa,SAAS,sBAAsB,KAAA,EAAU;UAC5E,eAAe,IAAI,YAAY,MAAM;oBAErC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;SACf,CAAA;QACJ;;MACH;SAEJ,sBACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,uBAAO;gBAAvB;OACG,CAAC,cAAc,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,uBAAO;kBAAQ,EAAE,WAAW;OAAO,CAAA;OAClE,cACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QACO;QACI;QACT,OAAO,OAAO,SAAS,IAAI,EAAE,YAAY,IAAI,KAAA;QAC7C,MAAM;QACN,WAAW,EAAE,aAAa;QAC1B,SAAS,SAAS,KAAK,IAAI,QAAQ,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC;QAC9D,WAAW;OACZ,CAAA;OAEF,cAAc,SAAS,SAAS,KAC/B,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QACO;QACI;QACT,MAAM;QACN,WAAW,EAAE,WAAW;QACxB,SAAS,SAAS,KAAK,IAAI,MAAM,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC;QAC5D,WAAW;OACZ,CAAA;OAEF,UAAU,SAAS,KAClB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QACO;QACI;QACT,OAAO,EAAE,eAAe;QACxB,MAAM;QACN,WAAW,EAAE,WAAW;QACxB,SAAS,SAAS,KAAK,IAAI,MAAM,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC;QAC5D,WAAW;OACZ,CAAA;MAEA;OAEJ;QAEJ,mBAAmB,QAClB,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;KACE,OAAO,EAAE,aAAa;KACtB,MAAM,eACF,OAAO,EAAE,6BAA6B,GAAG,EAAE,OAAO,eAAe,OAAO,CAAC,IACzE,OAAO,EAAE,2BAA2B,GAAG,EAAE,OAAO,eAAe,OAAO,CAAC;KAC3E,cAAc,EAAE,eAAe;KAC/B,QAAA;KACA,WAAW;KACX,gBAAgB,kBAAkB,IAAI;IACvC,CAAA,CAEA;;EAET;;EAGA,SAAS,MAAM,EACb,KACA,SACA,MACA,OACA,WACA,QACA,aASc;GACd,MAAM,QAAQ,SAAS,GAAG;GAC1B,MAAM,QAAA,GAAA,MAAA,QAAA,OAAqB,UAAU,IAAI,GAAG,CAAC,IAAI,CAAC;GAClD,MAAM,WAAW,MAAM,aAAa;GACpC,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,IAAI,UAAU,YAAY;GAGrE,MAAM,WAAA,GAAA,MAAA,QAAA,OAAwB,IAAI,IAAI,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;GAC/D,MAAM,aAAA,GAAA,MAAA,QAAA,OAA0B,IAAI,IAAI,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC;GACrE,MAAM,eAAA,GAAA,MAAA,QAAA,OAA4B,IAAI,IAAI,MAAM,YAAY,GAAG,CAAC,MAAM,YAAY,CAAC;GAEnF,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD,EAAA,UAAA,CACG,UAAU,KAAA,KACT,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,uBAAO;cAAvB,CACG,OACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;KACE,MAAK;KACL,WAAWA,uBAAO;KAClB,OAAO;KACP,eAAe,OAAO,aAAa;KACnC,UAAU,cAAc,WAAW;eAElC,cAAc,EAAE,aAAa,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;IAC3E,CAAA,CACL;OAEN,WACC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,aAC7B,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;IAEO;IACL,MAAM;IACN,OAAO;IACA;IACM;IACJ;IACE;IACN;IACI;IACE;GACZ,GAXM,QAAQ,KAAK,OAAW,GAW9B,CACF,IAED,KAAK,KAAK,QACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;IAEO;IACE;IACP,MAAM,QAAQ,IAAI,IAAI,IAAI;IAC1B,QAAQ,UAAU,IAAI,IAAI,IAAI;IACzB;IACI;IACE;GACZ,GARM,GAAG,IAAI,SAAS,MAAM,IAAI,GAAG,IAAI,MAQvC,CACF,CAEA,EAAA,CAAA;EAET;;EAGA,SAAS,QAAQ,EACf,KACA,MACA,OACA,OACA,aACA,SACA,WACA,KACA,SACA,aAYc;GACd,MAAM,WAAW,YAAY,IAAI,GAAG;GACpC,MAAM,QAAQ,QAAQ,KAAK,MAAM,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;GACzD,MAAM,uBAA6B;IACjC,MAAM,OAAO,WACT,MAAM,aAAa,QAAQ,SAAS,SAAS,GAAG,IAChD,CAAC,GAAG,MAAM,cAAc,GAAG;IAC/B,IAAI,gBAAgB,IAAI;GAC1B;GACA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IACE,WAAWA,uBAAO;IAClB,OAAO,EAAE,aAAa,KAAK,QAAQ,GAAG;IACtC,OAAO;IACP,MAAK;IACL,UAAU;IACV,iBAAe;IACf,SAAS;IACT,WAAW,cAAc,cAAc;cARzC;KAUE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAW,GAAGA,uBAAO,WAAW,WAAW,IAAIA,uBAAO,iBAAiB;gBAC3E,iBAAA,GAAA,kBAAA,IAAA,CAAC,kBAAD,EAAkB,MAAM,GAAK,CAAA;KACzB,CAAA;KACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MAAc,MAAM;MAAO,OAAA;MAAgB;KAAW,CAAA;KACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,OAAO;OAAE,UAAU;OAAI,OAAO;MAA2B;gBAAI;KAAY,CAAA;IAC5E;OACJ,YACC,KAAK,KAAK,QACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;IAEO;IACE;IACP,MAAM,QAAQ,IAAI,IAAI,IAAI;IAC1B,QAAQ,UAAU,IAAI,IAAI,IAAI;IACzB;IACI;IACE;IACX,QAAQ,QAAQ;IAChB,SAAA;GACD,GAVM,GAAG,IAAI,SAAS,MAAM,IAAI,GAAG,IAAI,MAUvC,CACF,CACH,EAAA,CAAA;EAEN;;;;;EAMA,SAAS,UAAU,EACjB,KACA,OACA,MACA,QACA,KACA,SACA,WACA,SAAS,GACT,UAAU,SAWI;GACd,MAAM,QAAQ,MAAM,IAAI,UAAU,MAAM;GACxC,MAAM,aAAa,IAAI,UAAU;GACjC,MAAM,cAAc,IAAI,YAAY,KAAA,IAAY,GAAG,IAAI,QAAQ,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,MAAO,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI;GACtJ,MAAM,MAAMC,QAAM,IAAI,IAAI;GAE1B,MAAM,sBAA4B;IAChC,IAAI,OAAO,IAAI,IAAI;IAGnB,QAAQ,SAAS,MAAM,MAAM,IAAI,MAAM,IAAI,MAAM;GACnD;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IACE,WAAW,GAAGD,uBAAO,YAAY,MAAM,aAAa,IAAI,OAAO,IAAIA,uBAAO,sBAAsB,KAAK,SAAS,IAAIA,uBAAO,cAAc;IACvI,OAAO,EAAE,aAAa,KAAK,SAAS,GAAG;IACvC,OAAO,IAAI;IACX,SAAS;IACT,WAAW,cAAc,aAAa;IACtC,MAAK;IACL,UAAU;cAPZ;KASE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAW,GAAGA,uBAAO,MAAM,GAAG,MAAM;gBAAc,MAAM;KAAa,CAAA;KAC3E,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,uBAAO;gBAAa;KAAkB,CAAA;KACtD,CAAC,WAAW,QAAQ,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,uBAAO;gBAAY;KAAU,CAAA;KACzE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAW,GAAGA,uBAAO,aAAa,QAAQ,SAAS,IAAIA,uBAAO,sBAAsB;gBACvF,aAAa,OAAO,IAAI,SACvB,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OACE,MAAK;OACL,WAAWA,uBAAO;OAClB,OAAO,EAAE,aAAa;OACtB,UAAU;OACV,UAAU,UAAU;QAAE,MAAM,gBAAgB;QAAG,IAAS,QAAQ,CAAC,IAAI,IAAI,CAAC;OAAE;iBAE5E,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA;MAChB,CAAA,GACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OACE,MAAK;OACL,WAAWA,uBAAO;OAClB,OAAO,EAAE,aAAa;OACtB,UAAU;OACV,UAAU,UAAU;QAAE,MAAM,gBAAgB;QAAG,UAAU,CAAC,GAAG,CAAC;OAAE;iBAEhE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;MACf,CAAA,CACR,EAAA,CAAA,IAEF,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OACE,MAAK;OACL,WAAWA,uBAAO;OAClB,OAAO,EAAE,WAAW;OACpB,UAAU;OACV,UAAU,UAAU;QAAE,MAAM,gBAAgB;QAAG,IAAS,MAAM,CAAC,IAAI,IAAI,CAAC;OAAE;iBAE1E,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;MACf,CAAA,GACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OACE,MAAK;OACL,WAAWA,uBAAO;OAClB,OAAO,EAAE,aAAa;OACtB,UAAU;OACV,UAAU,UAAU;QAAE,MAAM,gBAAgB;QAAG,UAAU,CAAC,GAAG,CAAC;OAAE;iBAEhE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;MACf,CAAA,CACR,EAAA,CAAA;KAEA,CAAA;IACH;;EAET;;;;;;;;;;;;;;;;;EChdA,MAAa,iBAAiB;;;;;;EAO9B,SAAgB,YAAY,OAA+C;GACzE,OAAO,UAAU,KAAA,KAAa,MAAM,SAAA,wBAAuB;EAC7D;;;;;;;;;;EAWA,SAAgB,uBAAuB,MAAuB;GAC5D,IAAI,SAAS,MAAM,KAAK,SAAS,KAAK,OAAO;GAC7C,IAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,IAAI,GAAG,OAAO;GAExD,IAAI,kBAAkB,KAAK,IAAI,GAAG,OAAO;GACzC,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,MAAK,YAAW,YAAY,IAAI,GAAG,OAAO;GAC9D,OAAO;EACT;;;;;;;;;;;;;;;EAgBA,SAAgB,oBAAoB,OAAe,MAAc,OAAwB;GACvF,IAAI,SAAS,IAAI,OAAO;GACxB,MAAM,KAAK,UAAU,KAAA,IAAY,MAAM,SAAS,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,MAAM,MAAM;GACzF,MAAM,SAAS,MAAM,MAAM,GAAG,EAAE;GAChC,MAAM,QAAQ,MAAM,MAAM,EAAE;GAC5B,MAAM,aAAa,WAAW,MAAM,CAAC,MAAM,KAAK,MAAM;GACtD,MAAM,YAAY,UAAU,MAAM,CAAC,MAAM,KAAK,KAAK;GACnD,OAAO,UAAU,aAAa,MAAM,MAAM,QAAQ,YAAY,MAAM,MAAM;EAC5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECpCA,MAAM,cAAc;;;;;;EAOpB,SAAgB,cAAc,EAC5B,QACA,kBACA,eAKc;GACd,MAAM,QAAQ,SAAS,OAAO,QAAQ;GAEtC,MAAM,oBADc,SAAS,OAAO,MACA,CAAC,CAAC,cAAc;GACpD,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA2B,KAAK;GACpD,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAsC,IAAI;GACvD,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAIL,IAAI;GACd,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4C,IAAI;;GAGrE,MAAM,gBAAgB,UAA2B;IAC/C,MAAM,WAAW,MAAM,KAAK,QAAQ,WAAW,EAAE;IACjD,MAAM,MAAM,MAAM,KAAK,SAAS,IAAI,IAAI,OAAO;IAC/C,OAAO,MAAM,SAAS,KAAK,WAAW,GAAG,WAAW,MAAM,MAAM,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG;GAC1F;GAEA,MAAM,WAAW,OAAO,SAAgC;IACtD,IAAI;KACF,MAAM,UAAU,UAAU,UAAU,IAAI;KACxC,MAAM,EAAE,eAAe,CAAC;IAC1B,QAAQ;KACN,MAAM,EAAE,mBAAmB,CAAC;IAC9B;GACF;;;;;;GAOA,MAAM,YAAA,GAAA,MAAA,YAAA,EAAwB,OAAwB,UAAyB;IAC7E,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,MAAM,gBAAgB,OAAO;IAC7B,cAAc,OAAO,MAAM,IAAI;IAC/B,MAAM,SAAS,UAAU,MAAM,IAAI;IACnC,MAAM,eAAe,MAAM,QAAQ,MAAM,OAAO;IAChD,MAAM,UAAuB;KAC3B;MACE,KAAK;MACL,OAAO,EAAE,wBAAwB;MACjC,gBAAgB,KAAK,SAAS,aAAa,KAAK,CAAC;KACnD;KACA;MACE,KAAK;MACL,OAAO,EAAE,wBAAwB;MACjC,gBAAgB,KAAK,SAAS,MAAM,IAAI;KAC1C;KACA;MAAE,KAAK;MAAS,OAAO;KAAM;KAC7B;MACE,KAAK;MACL,OAAO,EAAE,sBAAsB;MAC/B,gBAAgB;OACd,cAAmB,oBAAoB,MAAM,IAAI,CAAC,CAAC,MAAM,OAAO;QAC9D,IAAI,CAAC,IAAI,MAAM,EAAE,mBAAmB,CAAC;OACvC,CAAC;MACH;KACF;IACF;IACA,IAAI,CAAC,MAAM,OACT,QAAQ,KAAK;KACX,KAAK;KACL,OAAO,EAAE,+BAA+B;KACxC,gBAAgB;MACd,cAAmB,mBAAmB,MAAM,IAAI,CAAC,CAAC,MAAM,OAAO;OAC7D,IAAI,CAAC,IAAI,MAAM,EAAE,mBAAmB,CAAC;MACvC,CAAC;KACH;IACF,CAAC;IAEH,QAAQ,KACN;KAAE,KAAK;KAAS,OAAO;IAAM,GAC7B;KACE,KAAK;KACL,OAAO,EAAE,sBAAsB;KAC/B,gBAAgB,UAAU;MAAE,MAAM;MAAU,WAAW,MAAM;MAAM,cAAc,MAAM;KAAK,CAAC;IAC/F,GACA;KACE,KAAK;KACL,OAAO,EAAE,uBAAuB;KAChC,gBAAgB,UAAU;MAAE,MAAM;MAAW,WAAW;MAAc,cAAc;KAAG,CAAC;IAC1F,GACA;KACE,KAAK;KACL,OAAO,EAAE,yBAAyB;KAClC,gBAAgB,UAAU;MAAE,MAAM;MAAa,WAAW;MAAc,cAAc;KAAG,CAAC;IAC5F,GACA;KAAE,KAAK;KAAS,OAAO;IAAM,GAC7B;KACE,KAAK;KACL,OAAO,EAAE,sBAAsB;KAC/B,QAAQ;KACR,gBAAgB,gBAAgB,KAAK;IACvC,CACF;IACA,QAAQ;KAAE,GAAG,MAAM;KAAS,GAAG,MAAM;KAAS;IAAQ,CAAC;GACzD,GAAG,CAAC,MAAM,MAAM,MAAM,CAAC;GAEvB,MAAM,gBAAgB,UAAwB;IAC5C,IAAI,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,cAAc;IAC5B,MAAM,OAAO,MAAM,KAAK;IACxB,IAAI,SAAS,IAAI;IAMjB,CALW,SAAS,WAChB,OAAO,SAAS,YAAY,OAAO,WAAW,IAAI,IAClD,SAAS,cACP,OAAO,SAAS,UAAU,cAAc,KAAK,OAAO,GAAG,UAAU,GAAG,MAAM,IAC1E,OAAO,SAAS,WAAW,cAAc,KAAK,OAAO,GAAG,UAAU,GAAG,MAAM,EAAA,CACzE,MAAM,OAAO;KACnB,IAAI,CAAC,IAAI,MAAM,EAAE,mBAAmB,CAAC;IACvC,CAAC;IACD,UAAU,IAAI;GAChB;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;IAAe,OAAO;KAAE,SAAS;KAAQ,eAAe;KAAU,QAAQ;KAAQ,WAAW;IAAE;cAA9G;KAEE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWE,4BAAY;gBAA5B;OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAW,MAAM,cAAc,UAAUA,4BAAY,eAAeA,4BAAY;QAChF,eAAe,OAAO,SAAS,aAAa,OAAO;kBAElD,EAAE,qBAAqB;OAClB,CAAA;OACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAW,MAAM,cAAc,YAAYA,4BAAY,eAAeA,4BAAY;QAClF,eAAe,OAAO,SAAS,aAAa,SAAS;kBAEpD,EAAE,uBAAuB;OACpB,CAAA;OAGR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,4BAAY;QACvB,OAAO,EAAE,YAAY,OAAO;QAC5B,eAAe;SACb,OAAO,OAAO,QAAQ,UAAU;UAAE,GAAG;UAAM,WAAW,oBAAoB,OAAO;SAAW,EAAE;QAChG;QACA,OAAO,EAAE,oBAAoB,qBAAqB,mBAAmB;QACrE,cAAY,EAAE,oBAAoB,qBAAqB,mBAAmB;kBAEzE,oBAAoB,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD,EAAa,MAAM,GAAK,CAAA,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD,EAAc,MAAM,GAAK,CAAA;OACpE,CAAA;OACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAU;QACV,SAAS;QACT,OAAO,EAAE,mBAAmB;QAC5B,cAAY,EAAE,mBAAmB;kBAEjC,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAD,EAAiB,MAAM,GAAK,CAAA;OACtB,CAAA;MACL;;KAGL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,OAAO;OAAE,SAAS,MAAM,cAAc,UAAU,SAAS;OAAQ,eAAe;OAAU,MAAM;OAAG,WAAW;MAAE;gBAArH,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;OACU;OACK;OACb,eAAe;MAChB,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAkB;OAAQ,eAAe;OAAuB;MAAc,CAAA,CAC3E;;KAGJ,MAAM,cAAc,aAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAkB,OAAS,CAAA;KAG7D,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;MAAa,OAAO;MAAM,eAAe,QAAQ,IAAI;KAAI,CAAA;KACxD,WAAW,QACV,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MACE,OAAO,EAAE,OAAO,SAAS,WAAW,0BAA0B,OAAO,SAAS,cAAc,6BAA6B,wBAAwB;MACjJ,cAAc,OAAO;MACrB,WAAW;MACX,gBAAgB,UAAU,IAAI;KAC/B,CAAA;KAEF,iBAAiB,QAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;MACE,OAAO,EAAE,6BAA6B;MACtC,MAAM,EAAE,8BAA8B,EAAE,MAAM,aAAa,KAAK,CAAC;MACjE,QAAA;MACA,iBAAiB;OACf,MAAM,SAAS;OACf,gBAAgB,IAAI;OACpB,OAAY,SAAS,YAAY,OAAO,IAAI,CAAC,CAAC,MAAM,OAAO;QACzD,IAAI,CAAC,IAAI,MAAM,EAAE,mBAAmB,CAAC;OACvC,CAAC;MACH;MACA,gBAAgB,gBAAgB,IAAI;KACrC,CAAA;IAEA;;EAET;;EAGA,SAAS,WAAW,EAClB,QACA,aACA,iBAKc;GACd,MAAM,WAAW,OAAO;GAExB,MAAM,SADQ,SAAS,QACJ,CAAC,CAAC;GACrB,MAAM,SAAS,OAAO,UAAU;GAChC,MAAM,YAAA,GAAA,MAAA,OAAA,CAAoC,IAAI;GAE9C,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,eAAe;KAAU,WAAW;KAAG,MAAM,SAAS,IAAI,KAAA;IAAU;cAAnG,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,4BAAY;eAC1B,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MACE,WAAW,GAAGA,4BAAY,YAAY,cAAc,IAAIA,4BAAY,oBAAoB;MACxF,OAAO,EAAE,aAAa,cAAc,wBAAwB,KAAA,EAAU;gBAFxE;OAIE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,4BAAY;kBAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD,EAAY,MAAM,GAAK,CAAA;OAAO,CAAA;OACvE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,KAAK;QACL,WAAWA,4BAAY;QACvB,OAAO,OAAO;QACd,aAAa,EAAE,6BAA6B;QAC5C,cAAY,EAAE,6BAA6B;QAC3C,eAAe,cAAc,IAAI;QACjC,cAAc,cAAc,KAAK;QACjC,WAAW,UAAU,SAAS,eAAe,MAAM,OAAO,KAAK;OAChE,CAAA;OACA,OAAO,UAAU,MAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,4BAAY;QACvB,eAAe;SAAE,SAAS,aAAa;SAAG,SAAS,SAAS,MAAM;QAAE;QACpE,cAAY,EAAE,cAAc;kBAE5B,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA;OAChB,CAAA;MAEP;;IACF,CAAA,GAIJ,SACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD,EAAuB,OAAS,CAAA,IAC9B,IACD;;EAET;;EAGA,SAAS,cAAc,EAAE,UAAgD;GACvE,MAAM,WAAW,OAAO;GAExB,MAAM,SADQ,SAAS,QACJ,CAAC,CAAC;GACrB,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,4BAAY;cAA5B;KACG,OAAO,WAAW,eAAe,OAAO,KAAK,WAAW,KACvD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,4BAAY;gBAAe,EAAE,2BAA2B;KAAO,CAAA;KAEhF,OAAO,WAAW,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,4BAAY;gBAAe,EAAE,uBAAuB;KAAO,CAAA;KACxG,OAAO,WAAW,UAAU,OAAO,KAAK,WAAW,KAClD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,4BAAY;gBAAe,EAAE,uBAAuB;KAAO,CAAA;KAE5E,OAAO,KAAK,KAAK,QAChB,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAEE,WAAWA,4BAAY;MACvB,MAAK;MACL,UAAU;MACV,OAAO,IAAI;MACX,eAAe;OAEb,SAAS,OAAO,IAAI,IAAI;MAC1B;MACA,WAAW,oBAAoB;OAAE,SAAS,OAAO,IAAI,IAAI;MAAE,CAAC;gBAV9D;OAYE,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;QAAc,MAAM,IAAI;QAAM,OAAO,IAAI;QAAO,UAAU;OAAQ,CAAA;OAClE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,4BAAY;kBAAa,IAAI;OAAW,CAAA;OACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,4BAAY;kBAAa,UAAU,IAAI,IAAI;OAAQ,CAAA;MACjE;QAdE,IAAI,IAcN,CACN;KACA,OAAO,aAAa,OAAO,KAAK,SAAS,KACxC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,4BAAY;gBAAe,EAAE,6BAA6B,EAAE,OAAO,OAAO,KAAK,OAAO,CAAC;KAAO,CAAA;IAE7G;;EAET;;EAGA,SAAS,SAAS,EAChB,QACA,eACA,eAKc;GACd,MAAM,WAAW,OAAO;GACR,OAAO;GACvB,MAAM,QAAQ,SAAS,QAAQ;GAC/B,MAAM,OAAO,MAAM;GAInB,MAAM,eAAA,GAAA,MAAA,QAAA,OAA4B,IAAI,IAAI,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC;GAE3E,IAAI,SAAS,IAAI,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,4BAAY;cAAa,EAAE,qBAAqB;GAAO,CAAA;GAC/F,MAAM,UAAU,MAAM,KAAK;GAC3B,IAAI,YAAY,KAAA,GACd,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,4BAAY;cAAe,EAAE,aAAa;GAAO,CAAA;GAE1E,IAAI,QAAQ,WAAW,GAAG,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,4BAAY;cAAa,EAAE,qBAAqB;GAAO,CAAA;GAExG,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAW,GAAGA,4BAAY,WAAW,GAAGA,4BAAY;cACtD,QAAQ,KAAK,UACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;KAES;KACP,OAAO;KACP,UAAU;KACV,UAAU,MAAM;KAChB,MAAM,MAAM;KACZ,MAAM,MAAM;KACJ;KACO;KACF;IACd,GAVM,MAAM,IAUZ,CACF;GACE,CAAA;EAET;;EAGA,SAAS,YAAY,EACnB,OACA,OACA,UACA,UACA,MACA,MACA,QACA,eACA,eAWc;GACd,MAAM,WAAW,OAAO;GACxB,MAAM,UAAU,OAAO;GACvB,MAAM,aAAa,SAAS,IAAI,MAAM,IAAI;GAC1C,MAAM,aAAa,aAAa,MAAM;GACtC,MAAM,WAAW,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAA;GAClD,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA2B,KAAK;GAEpD,MAAM,oBAA0B;IAC9B,IAAI,MAAM,OAAO;KAEf,SAAS,UAAU,MAAM,IAAI;KAC7B;IACF;IAEA,SAAS,OAAO,MAAM,IAAI;IAC1B,QAAQ,SAAS,MAAM,MAAM,IAAI;GACnC;GAIA,MAAM,eAAe,UAA2B;IAC9C,IAAI,MAAM,OAAO;IACjB,MAAM,aAAa,QAAQ,gBAAgB,MAAM,IAAI;IACrD,MAAM,aAAa,QAAQ,cAAc,MAAM,IAAI;IACnD,MAAM,aAAa,gBAAgB;IACnC,eAAe,IAAI;GACrB;GACA,MAAM,kBAAwB;IAC5B,eAAe,KAAK;GACtB;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IACE,WAAW,GAAGA,4BAAY,UAAU,aAAa,IAAIA,4BAAY,oBAAoB,KAAK,cAAc,IAAIA,4BAAY,oBAAoB;IAC5I,OAAO,EAAE,aAAa,KAAS,QAAQ,YAAY;IACnD,SAAS;IACT,WAAW,cAAc,WAAW;IACpC,gBAAgB,UAAU,cAAc,OAAO,KAAK;IACpD,gBAAgB,UAAU;KAExB,MAAM,gBAAgB;IACxB;IACA,WAAW,CAAC,MAAM;IACL;IACF;IACX,MAAK;IACL,UAAU;IACV,iBAAe,MAAM,QAAQ,aAAa,KAAA;IAC1C,OAAO,MAAM;cAhBf;KAkBG,MAAM,QACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAW,GAAGA,4BAAY,YAAY,aAAa,IAAIA,4BAAY,kBAAkB;gBACzF,iBAAA,GAAA,kBAAA,IAAA,CAAC,kBAAD,EAAkB,MAAM,GAAK,CAAA;KACzB,CAAA,IAEN,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,WAAWA,4BAAY,eAAiB,CAAA;KAEhD,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MAAc,MAAM,MAAM;MAAM,OAAO,MAAM;MAAO,UAAU;KAAa,CAAA;KAC3E,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAY;gBAAW,MAAM;KAAW,CAAA;KACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAWA,4BAAY;MACvB,OAAO,EAAE,qBAAqB;MAC9B,cAAY,EAAE,qBAAqB;MACnC,UAAU,UAAU;OAElB,MAAM,gBAAgB;OACtB,MAAM,eAAe;OACrB,YAAY,MAAM,MAAM,MAAM,KAAK;MACrC;MACA,cAAc,UAAU,MAAM,gBAAgB;gBAC/C;KAEO,CAAA;IACL;OACJ,MAAM,SAAS,cAAc,aAAa,KAAA,KACzC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAA,UACG,SAAS,KAAK,UACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;IAEE,OAAO;IACP,OAAO,QAAQ;IACL;IACA;IACJ;IACA;IACE;IACO;IACF;GACd,GAVM,MAAM,IAUZ,CACF,EACE,CAAA,CAEP,EAAA,CAAA;EAEN;;;;;;;;;;;;EAaA,MAAM,WAAA,GAAA,MAAA,KAAA,CAAe,cAAc,MAAM,SAIvC,KAAK,SAAS,IAAI,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,MAAM,IAAI,KACrE,KAAK,UAAU,KAAK,SACpB,KAAK,UAAU,KAAK,SACpB,KAAK,aAAa,KAAK,YACvB,KAAK,SAAS,KAAK,QACnB,KAAK,SAAS,KAAK,QACnB,KAAK,WAAW,KAAK,UACrB,KAAK,kBAAkB,KAAK,iBAC5B,KAAK,gBAAgB,KAAK,WAC/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECjgBA,MAAM,aAAa;;EASnB,SAAgB,YAAY,EAC1B,MACA,aACA,UACA,SACA,eACA,aACA,cACA,WACA,cAWc;GACd,MAAM,aAAA,GAAA,MAAA,OAAA,CAAmC,IAAI;GAC7C,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAkC;IAAE,MAAM;IAAO,OAAO;GAAM,CAAC;GAG5E,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,KAAK,UAAU;IACrB,IAAI,OAAO,MAAM;IACjB,MAAM,eAAqB;KACzB,MAAM,OAAO;MACX,MAAM,GAAG,aAAa;MACtB,OAAO,GAAG,aAAa,GAAG,cAAc,GAAG,cAAc;KAC3D;KACA,SAAS,SAAU,KAAK,SAAS,KAAK,QAAQ,KAAK,UAAU,KAAK,QAAQ,OAAO,IAAK;IACxF;IACA,MAAM,WAAW,IAAI,eAAe,MAAM;IAC1C,SAAS,QAAQ,EAAE;IACnB,GAAG,iBAAiB,UAAU,QAAQ,EAAE,SAAS,KAAK,CAAC;IACvD,OAAO,iBAAiB,UAAU,MAAM;IACxC,OAAO;IACP,aAAa;KACX,SAAS,WAAW;KACpB,GAAG,oBAAoB,UAAU,MAAM;KACvC,OAAO,oBAAoB,UAAU,MAAM;IAC7C;GACF,GAAG,CAAC,KAAK,MAAM,CAAC;GAEhB,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWC,2BAAW;cAA3B;KACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,KAAK;MAAW,WAAWA,2BAAW;gBAA3C;OACG,KAAK,WAAW,KAAK,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,2BAAW;kBAAS,EAAE,gBAAgB;OAAO,CAAA;OAClF,KAAK,KAAK,QACT,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;QAEE,WAAW,GAAGA,2BAAW,MAAM,IAAI,OAAO,cAAc,IAAIA,2BAAW,cAAc,IAAIA,2BAAW;QACpG,OAAO,EAAE,UAAA,IAA2B;QACpC,MAAK;QACL,UAAU;QACV,OAAO,IAAI;QACX,cAAY,IAAI;QAChB,eAAe,SAAS,IAAI,EAAE;QAC9B,WAAW,oBAAoB;SAAE,SAAS,IAAI,EAAE;QAAE,CAAC;QACnD,gBAAgB,UAAU,cAAc,OAAO,GAAG;QAClD,aAAa,UAAU;SACrB,IAAI,MAAM,WAAW,GAAG;SACxB,MAAM,eAAe;SACrB,MAAM,gBAAgB;SACtB,QAAQ,IAAI,EAAE;QAChB;kBAhBF;SAkBE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,2BAAW;UAAU,OAAO,IAAI;oBAAO,IAAI;SAAY,CAAA;SACvE,IAAI,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,2BAAW;UAAa,OAAO,EAAE,eAAe;SAAI,CAAA;SACnF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UACE,WAAWA,2BAAW;UACtB,MAAK;UACL,UAAU;UACV,OAAO,EAAE,cAAc;UACvB,cAAY,EAAE,cAAc;UAC5B,UAAU,UAAU;WAClB,MAAM,gBAAgB;WACtB,QAAQ,IAAI,EAAE;UAChB;UACA,WAAW,oBAAoB;WAAE,QAAQ,IAAI,EAAE;UAAE,CAAC;oBAElD,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA;SAClB,CAAA;QACH;UAjCE,IAAI,EAiCN,CACN;OACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QACE,WAAWA,2BAAW;QACtB,MAAK;QACL,UAAU;QACV,SAAS;QACT,WAAW,cAAc,WAAW;QACpC,OAAO,EAAE,mBAAmB;kBAE5B,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;OAClB,CAAA;MACF;;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;gBAA3B,CAGE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OACE,WAAWA,2BAAW;OACtB,MAAK;OACL,UAAU;OACV,SAAS;OACT,WAAW,cAAc,UAAU;OACnC,OAAO,EAAE,YAAY,oBAAoB,kBAAkB;OAC3D,cAAY,EAAE,YAAY,oBAAoB,kBAAkB;iBAE/D,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD,EAAa,MAAM,GAAK,CAAA,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD,EAAc,MAAM,GAAK,CAAA;MAC/D,CAAA,GACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OACE,WAAWA,2BAAW;OACtB,MAAK;OACL,UAAU;OACV,SAAS;OACT,WAAW,cAAc,YAAY;OACrC,OAAO,EAAE,uBAAuB;OAChC,cAAY,EAAE,uBAAuB;iBAErC,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD,EAAY,MAAM,GAAK,CAAA;MACpB,CAAA,CACF;;KACJ,KAAK,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;MAAa,OAAO,EAAE,OAAO,WAAW;KAAI,CAAA;KACpF,KAAK,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;MAAc,OAAO,EAAE,OAAO,WAAW;KAAI,CAAA;IACpF;;EAET;;;;EC3IA,SAAgB,gBACd,aACA,YACA,SACA,SACc;GAGd,IAAI,gBAAgB,OAAO,OAAO;GAClC,IAAI,gBAAgB,UAAU,gBAAgB,WACzC,gBAAgB,SAAS,gBAAgB,iBAAiB,gBAAgB,SAC7E,OAAO;GAET,IAAI,CAAC,cAAc,SAAS,OAAO;GACnC,OAAO,UAAU,YAAY;EAC/B;;EAGA,SAAgB,YAAY,KAAuF;GACjH,IAAI,IAAI,YAAY,MAAM;GAC1B,MAAM,YAAY,IAAI,QAAQ,WAAW,OAAO;GAGhD,MAAM,aAAa,IAAI,QAAQ,WAAW,cAAc;GACxD,MAAM,OAAO,aAAa,aACtB,IAAI,UACJ,IAAI,gBAAgB,IAAI,KAAK,CAAC,IAAI,OAAO,GAAG,EAAE,MAAM,2BAA2B,CAAC,CAAC;GACrF,MAAM,SAAS,SAAS,cAAc,GAAG;GACzC,OAAO,OAAO;GACd,OAAO,WAAW,IAAI;GACtB,OAAO,MAAM,UAAU;GACvB,SAAS,KAAK,YAAY,MAAM;GAChC,OAAO,MAAM;GACb,OAAO,OAAO;GACd,IAAI,CAAC,aAAa,CAAC,YAAY,iBAAiB,IAAI,gBAAgB,IAAI,GAAG,GAAM;EACnF;;EAGA,SAAgB,eAAe,EAC7B,aACA,YACA,SACA,OACA,SACA,UACA,eACA,OACA,UACA,kBACA,eACA,WACA,QACA,cAgBc;GACd,MAAM,eAAe,gBAAgB,aAAa,YAAY,SAAS,OAAO;GAC9E,MAAM,WAAW,eAAe,WAAW;GAE3C,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWC,2BAAW;cAA3B;KACG,iBACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAW,GAAGA,2BAAW,aAAa,aAAa,WAAW,IAAIA,2BAAW,qBAAqB;MAClG,eAAe,iBAAiB,QAAQ;gBAH1C,CAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA,GACpB,EAAE,gBAAgB,CACb;SACR,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAW,GAAGA,2BAAW,aAAa,aAAa,YAAY,IAAIA,2BAAW,qBAAqB;MACnG,eAAe,iBAAiB,SAAS;gBAH3C,CAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD,EAAS,MAAM,GAAK,CAAA,GACnB,EAAE,iBAAiB,CACd;OACR,EAAA,CAAA;KAEH,YACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAW,GAAGA,2BAAW,aAAa,QAAQ,IAAIA,2BAAW,qBAAqB;MAClF,OAAO,EAAE,eAAe;MACxB,eAAe,cAAc,CAAC,KAAK;gBAJrC,CAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA,GACrB,EAAE,eAAe,CACZ;;KAEV,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAWA,2BAAW;MACtB,OAAO,EAAE,kBAAkB;MAC3B,UAAU,CAAC;MACX,SAAS;gBAET,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD,EAAc,MAAM,GAAK,CAAA;KACnB,CAAA;KACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,WAAWA,2BAAW,cAAgB,CAAA;KAC3C,iBAAiB,YAChB,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAW,GAAGA,2BAAW,aAAa,iBAAiB,YAAY,IAAIA,2BAAW,mBAAmB;MACrG,OAAO,iBAAiB,YAAY,EAAE,yBAAyB,IAAI,EAAE,iBAAiB;MACtF,UAAU,iBAAiB;MAC3B,SAAS;gBALX,CAOE,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD,EAAa,MAAM,GAAK,CAAA,GACvB,EAAE,iBAAiB,CACd;;KAET,YAAY,SACX,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAWA,2BAAW;MACtB,SAAS;MACT,UAAU;gBAJZ,CAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA,GACpB,EAAE,cAAc,CACX;;IAEP;;EAET;;;;;;;;;;;;;;;EC3HA,SAAgB,kBAAkB,UAAoC,CAAC,GAAG;GACxE,MAAM,EACJ,eAAe,IACf,WAAW,IACX,WAAW,IACX,YACA,OAAO,YACL;GACJ,MAAM,OAAO,SAAS;GAEtB,MAAM,CAAC,OAAO,kBAAA,GAAA,MAAA,SAAA,OACZ,eAAe,KAAA,IACX,eACA,iBAAiB,YAAY,UAAU,UAAU,YAAY,CAAC;GAGpE,MAAM,YAAA,GAAA,MAAA,OAAA,CAAkB,KAAK;GAC7B,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,SAAS,UAAU;GACrB,GAAG,CAAC,KAAK,CAAC;;GAGV,MAAM,YAAA,GAAA,MAAA,YAAA,EAAwB,UAAkB;IAC9C,cAAc,KAAK;IACnB,IAAI,eAAe,KAAA,GAAW,kBAAkB,YAAY,KAAK;IACjE,IAAI;KACF,OAAO,cAAc,IAAI,YAAY,wBAAwB,EAAE,QAAQ,EAAE,OAAO,MAAM,EAAE,CAAC,CAAC;IAC5F,QAAQ,CAER;GACF,GAAG,CAAC,UAAU,CAAC;GAEf,MAAM,SAAA,GAAA,MAAA,YAAA,EAAqB,UAA0B;IACnD,OAAO,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,KAAK,CAAC;GACrD,GAAG,CAAC,UAAU,QAAQ,CAAC;GAmBvB,OAAO;IAAE;IAAO;IAAU,aAAA;KAFa,gBAAA,GAAA,MAAA,YAAA,EAfA,UAA6C;MAClF,MAAM,KAAK,MAAM;MACjB,uBAAuB,MAAM,aAAa,IAAI;OAC5C,SAAS,GAAG,QAAQ,YAAY;OAChC,qBAAqB,SAAS;OAC9B,UAAU,YAAY,WAAW,MAAM,aAAa,MAAM;OAC1D,UAAU,UAAU,cAAc,KAAK;OACvC,QAAQ,UAAU,SAAS,KAAK;MAClC,CAAC;KACH,GAAG,CAAC,OAAO,QAAQ,CAMmD;KAAG,gBAAA,GAAA,MAAA,YAAA,OAJ7B;MAC1C,SAAS,YAAY;KACvB,GAAG,CAAC,cAAc,QAAQ,CAE8E;IAEpE;IAAG;IAAO;GAAK;EACrD;;;;;;;;;;;ECjFA,SAAgB,WAAW,MAAsB;GAC/C,OAAO,KACJ,QAAQ,MAAM,OAAO,CAAC,CACtB,QAAQ,MAAM,MAAM,CAAC,CACrB,QAAQ,MAAM,MAAM,CAAC,CACrB,QAAQ,MAAM,QAAQ,CAAC,CACvB,QAAQ,MAAM,OAAO;EAC1B;;EAYA,SAAS,MAAM,UAA0B;GACvC,MAAM,QAAQ,SAAS,YAAY,GAAG;GACtC,OAAO,UAAU,KAAK,KAAK,SAAS,MAAM,GAAG,KAAK;EACpD;;EAGA,SAAS,iBAAiB,KAA4B;GACpD,MAAM,MAAgB,CAAC;GACvB,KAAK,MAAM,QAAQ,IAAI,MAAM,GAAG,GAAG;IACjC,IAAI,SAAS,MAAM,SAAS,KAAK;IACjC,IAAI,SAAS,MAAM;KACjB,IAAI,IAAI,WAAW,GAAG,OAAO;KAC7B,IAAI,IAAI;KACR;IACF;IACA,IAAI,KAAK,IAAI;GACf;GACA,OAAO,IAAI,KAAK,GAAG;EACrB;;EAGA,SAAS,eAAe,KAAqB;GAC3C,IAAI;IACF,OAAO,mBAAmB,GAAG;GAC/B,QAAQ;IACN,OAAO;GACT;EACF;;;;;;;;;;;;EAaA,SAAgB,qBAAqB,UAAkB,KAAsC;GAC3F,MAAM,UAAU,IAAI,KAAK;GACzB,IAAI,YAAY,MAAM,QAAQ,WAAW,GAAG,GAAG,OAAO,EAAE,MAAM,WAAW;GACzE,IAAI,4BAA4B,KAAK,OAAO,GAAG,OAAO,EAAE,MAAM,WAAW;GACzE,MAAM,UAAU,eAAe,OAAO;GACtC,MAAM,IAAI,QAAQ,QAAQ,GAAG;GAC7B,MAAM,IAAI,QAAQ,QAAQ,GAAG;GAC7B,IAAI,MAAM,QAAQ;GAClB,IAAI,MAAM,IAAI,MAAM,KAAK,IAAI,KAAK,CAAC;GACnC,IAAI,MAAM,IAAI,MAAM,KAAK,IAAI,KAAK,CAAC;GACnC,MAAM,WAAW,QAAQ,MAAM,GAAG,GAAG;GACrC,MAAM,SAAS,QAAQ,MAAM,GAAG;GAChC,MAAM,OAAO,SAAS,WAAW,GAAG,IAAI,KAAK,MAAM,QAAQ;GAE3D,MAAM,aAAa,iBADJ,SAAS,KAAK,WAAW,GAAG,KAAK,GAAG,UACT;GAC1C,IAAI,eAAe,MAAM,OAAO,EAAE,MAAM,SAAS;GACjD,OAAO;IAAE,MAAM;IAAY,MAAM;IAAY;GAAO;EACtD;;;;;;;;;EAoBA,SAAgB,QAAQ,KAA4B;GAClD,MAAM,UAAU,IAAI,KAAK;GACzB,IAAI,YAAY,IAAI,OAAO;GAC3B,IAAI,QAAQ,WAAW,GAAG,GAAG,OAAO;GACpC,MAAM,SAAS,8BAA8B,KAAK,OAAO;GACzD,IAAI,WAAW,MAAM,OAAO;GAC5B,MAAM,OAAO,OAAO,EAAE,CAAC,YAAY;GACnC,OAAO,SAAS,UAAU,SAAS,WAAW,SAAS,WAAW,UAAU;EAC9E;;EAGA,SAAgB,aAAa,MAAc,SAAyC;GAClF,IAAI,MAAM;GACV,IAAI,IAAI;GACR,MAAM,IAAI,KAAK;GACf,OAAO,IAAI,GAAG;IACZ,MAAM,OAAO,KAAK;IAElB,IAAI,SAAS,KAAK;KAChB,MAAM,MAAM,KAAK,QAAQ,KAAK,IAAI,CAAC;KACnC,IAAI,QAAQ,IAAI;MACd,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,GAAG,GAAG,CAAC,EAAE;MACnD,IAAI,MAAM;MACV;KACF;IACF;IAEA,IAAI,SAAS,OAAO,KAAK,IAAI,OAAO,KAAK;KACvC,MAAM,QAAQ,KAAK,QAAQ,MAAM,IAAI,CAAC;KACtC,IAAI,UAAU,IAAI;MAChB,MAAM,WAAW,KAAK,QAAQ,KAAK,QAAQ,CAAC;MAC5C,IAAI,aAAa,IAAI;OACnB,MAAM,MAAM,KAAK,MAAM,IAAI,GAAG,KAAK;OAEnC,MAAM,OAAO,QADD,KAAK,MAAM,QAAQ,GAAG,QACX,CAAC;OACxB,IAAI,SAAS,MAEX,OAAO,WAAW,GAAG;YAChB;QACL,IAAI,SAAwB;QAC5B,IAAI,SAAS,oBAAoB,KAAA,GAC/B,SAAS,QAAQ,gBAAgB,IAAI;QAEvC,IAAI,WAAW,MAEb,OAAO,WAAW,GAAG;aAChB;SACL,MAAM,SAAS,WAAW,MAAM,CAAC,CAAC,QAAQ,QAAQ,KAAK;SACvD,OAAO,aAAa,WAAW,GAAG,EAAE,SAAS,OAAO;QACtD;OACF;OACA,IAAI,WAAW;OACf;MACF;KACF;IACF;IAEA,IAAI,SAAS,KAAK;KAChB,MAAM,QAAQ,KAAK,QAAQ,MAAM,IAAI,CAAC;KACtC,IAAI,UAAU,IAAI;MAChB,MAAM,WAAW,KAAK,QAAQ,KAAK,QAAQ,CAAC;MAC5C,IAAI,aAAa,IAAI;OACnB,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG,KAAK;OAErC,MAAM,OAAO,QADA,KAAK,MAAM,QAAQ,GAAG,QACX,CAAC;OACzB,IAAI,SAAS,MAEX,OAAO,aAAa,OAAO,OAAO;YAElC,OAAO,YAAY,WAAW,IAAI,EAAE,8CAA8C,aAAa,OAAO,OAAO,EAAE;OAEjH,IAAI,WAAW;OACf;MACF;KACF;IACF;IAEA,IAAI,SAAS,OAAO,KAAK,IAAI,OAAO,KAAK;KACvC,MAAM,MAAM,KAAK,QAAQ,MAAM,IAAI,CAAC;KACpC,IAAI,QAAQ,IAAI;MACd,OAAO,WAAW,aAAa,KAAK,MAAM,IAAI,GAAG,GAAG,GAAG,OAAO,EAAE;MAChE,IAAI,MAAM;MACV;KACF;IACF;IAEA,IAAI,SAAS,OAAO,KAAK,IAAI,OAAO,OAAO,KAAK,IAAI,OAAO,KAAK;KAC9D,MAAM,MAAM,KAAK,QAAQ,KAAK,IAAI,CAAC;KACnC,IAAI,QAAQ,MAAM,KAAK,MAAM,OAAO,KAAK;MACvC,OAAO,OAAO,aAAa,KAAK,MAAM,IAAI,GAAG,GAAG,GAAG,OAAO,EAAE;MAC5D,IAAI,MAAM;MACV;KACF;IACF;IAEA,IAAI,SAAS,OAAO,KAAK,IAAI,OAAO,KAAK;KACvC,MAAM,MAAM,KAAK,QAAQ,MAAM,IAAI,CAAC;KACpC,IAAI,QAAQ,IAAI;MACd,OAAO,QAAQ,aAAa,KAAK,MAAM,IAAI,GAAG,GAAG,GAAG,OAAO,EAAE;MAC7D,IAAI,MAAM;MACV;KACF;IACF;IACA,OAAO,WAAW,IAAI;IACtB,KAAK;GACP;GACA,OAAO;EACT;;EAGA,SAAgB,eAAe,QAAgB,SAAyC;GACtF,MAAM,QAAQ,OAAO,QAAQ,SAAS,IAAI,CAAC,CAAC,MAAM,IAAI;GACtD,MAAM,MAAgB,CAAC;GACvB,IAAI,IAAI;GACR,MAAM,IAAI,MAAM;GAEhB,MAAM,kBAAkB,WAA2B;IACjD,IAAI,OAAO,WAAW,GAAG;IACzB,IAAI,KAAK,MAAM,aAAa,OAAO,KAAK,IAAI,GAAG,OAAO,EAAE,KAAK;IAC7D,OAAO,SAAS;GAClB;GAEA,IAAI,YAAsB,CAAC;GAC3B,OAAO,IAAI,GAAG;IACZ,MAAM,OAAO,MAAM;IAGnB,MAAM,QAAQ,oBAAoB,KAAK,IAAI;IAC3C,IAAI,UAAU,MAAM;KAClB,eAAe,SAAS;KACxB,MAAM,OAAO,MAAM,MAAM;KACzB,KAAK;KACL,MAAM,OAAiB,CAAC;KACxB,OAAO,IAAI,KAAK,CAAC,WAAW,KAAK,MAAM,EAAE,GAAG;MAC1C,KAAK,KAAK,MAAM,EAAE;MAClB,KAAK;KACP;KACA,KAAK;KACL,MAAM,WAAW,SAAS,KAAK,KAAK,oBAAoB,WAAW,IAAI,EAAE;KACzE,IAAI,KAAK,OAAO,SAAS,SAAS,WAAW,KAAK,KAAK,IAAI,CAAC,EAAE,cAAc;KAC5E;IACF;IAGA,MAAM,UAAU,oBAAoB,KAAK,IAAI;IAC7C,IAAI,YAAY,MAAM;KACpB,eAAe,SAAS;KACxB,MAAM,QAAQ,QAAQ,EAAE,CAAC;KACzB,IAAI,KAAK,KAAK,MAAM,GAAG,aAAa,QAAQ,MAAM,IAAI,OAAO,EAAE,KAAK,MAAM,EAAE;KAC5E,KAAK;KACL;IACF;IAGA,IAAI,8BAA8B,KAAK,IAAI,GAAG;KAC5C,eAAe,SAAS;KACxB,IAAI,KAAK,QAAQ;KACjB,KAAK;KACL;IACF;IAGA,IAAI,KAAK,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,yBAAyB,KAAK,MAAM,IAAI,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,SAAS,GAAG,GAAG;KAChH,eAAe,SAAS;KACxB,MAAM,cAAc,cAAc,IAAI;KACtC,KAAK;KACL,MAAM,OAAmB,CAAC;KAC1B,OAAO,IAAI,KAAK,MAAM,EAAE,CAAC,SAAS,GAAG,GAAG;MACtC,KAAK,KAAK,cAAc,MAAM,EAAE,CAAC;MACjC,KAAK;KACP;KACA,IAAI,KAAK,SAAS;KAClB,IAAI,KAAK,cAAc,YAAY,KAAK,SAAS,OAAO,aAAa,MAAM,OAAO,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,cAAc;KACnH,IAAI,KAAK,SAAS,GAChB,IAAI,KAAK,UAAU,KAAK,KAAK,QAAQ,OAAO,IAAI,KAAK,SAAS,OAAO,aAAa,MAAM,OAAO,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,SAAS;KAE9I,IAAI,KAAK,UAAU;KACnB;IACF;IAIA,IADc,aAAa,KAAK,IACxB,MAAM,MAAM;KAClB,eAAe,SAAS;KACxB,MAAM,OAAiB,CAAC;KACxB,OAAO,IAAI,GAAG;MACZ,MAAM,IAAI,aAAa,KAAK,MAAM,EAAE;MACpC,IAAI,MAAM,MAAM;MAChB,KAAK,KAAK,EAAE,MAAM,EAAE;MACpB,KAAK;KACP;KACA,IAAI,KAAK,kBAAkB,KAAK,KAAK,SAAS,aAAa,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,kBAAkB;KAC5G;IACF;IAIA,IADW,sBAAsB,KAAK,IACjC,MAAM,MAAM;KACf,eAAe,SAAS;KACxB,MAAM,QAAkB,CAAC;KACzB,OAAO,IAAI,GAAG;MACZ,MAAM,OAAO,sBAAsB,KAAK,MAAM,EAAE;MAChD,IAAI,SAAS,MAAM;MACnB,MAAM,KAAK,OAAO,aAAa,KAAK,MAAM,IAAI,OAAO,EAAE,MAAM;MAC7D,KAAK;KACP;KACA,IAAI,KAAK,OAAO,MAAM,KAAK,EAAE,EAAE,MAAM;KACrC;IACF;IAIA,IADW,sBAAsB,KAAK,IACjC,MAAM,MAAM;KACf,eAAe,SAAS;KACxB,MAAM,QAAkB,CAAC;KACzB,OAAO,IAAI,GAAG;MACZ,MAAM,OAAO,sBAAsB,KAAK,MAAM,EAAE;MAChD,IAAI,SAAS,MAAM;MACnB,MAAM,KAAK,OAAO,aAAa,KAAK,MAAM,IAAI,OAAO,EAAE,MAAM;MAC7D,KAAK;KACP;KACA,IAAI,KAAK,OAAO,MAAM,KAAK,EAAE,EAAE,MAAM;KACrC;IACF;IAGA,IAAI,KAAK,KAAK,MAAM,IAAI;KACtB,eAAe,SAAS;KACxB,KAAK;KACL;IACF;IAEA,UAAU,KAAK,IAAI;IACnB,KAAK;GACP;GACA,eAAe,SAAS;GACxB,OAAO,IAAI,KAAK,IAAI;EACtB;;EAGA,SAAS,cAAc,MAAwB;GAC7C,MAAM,UAAU,KAAK,KAAK;GAC1B,MAAM,QAAQ,QAAQ,WAAW,GAAG,IAAI,QAAQ,MAAM,CAAC,IAAI;GAE3D,QADwB,MAAM,SAAS,GAAG,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,MAAA,CAC5C,MAAM,GAAG,CAAC,CAAC,KAAK,SAAS,KAAK,KAAK,CAAC;EAC7D;;;;EC3UA,MAAa,qBAAqB;;EAGlC,MAAM,aAAa;;EAGnB,MAAM,eAAe;;EAGrB,MAAM,cAAc;;EAGpB,MAAa,gBAAgB;EAE7B,IAAI;;;;;EAMJ,SAAS,gBAAuC;GAC9C,MAAM,YAAa,WAAuC;GAC1D,IAAI,OAAO,cAAc,YAAY,cAAc,MAAM,OAAO;GAChE,MAAM,UAAU;GAChB,IAAI,OAAO,QAAQ,eAAe,cAAc,OAAO,QAAQ,WAAW,YAAY,OAAO;GAC7F,OAAO;EACT;;;;;;EAOA,SAAgB,qBAA8C;GAC5D,MAAM,WAAW,cAAc;GAC/B,IAAI,aAAa,MAAM,OAAO,QAAQ,QAAQ,QAAQ;GACtD,IAAI,gBAAgB,KAAA,GAAW,OAAO;GACtC,cAAc,IAAI,SAAyB,SAAS,WAAW;IAC7D,MAAM,SAAS,SAAS,cAAc,QAAQ;IAC9C,OAAO,MAAM;IACb,OAAO,QAAQ;IACf,OAAO,eAAe;KACpB,MAAM,UAAU,cAAc;KAC9B,IAAI,YAAY,MAAM;MACpB,cAAc,KAAA;MACd,uBAAO,IAAI,MAAM,4DAA4D,CAAC;MAC9E;KACF;KACA,QAAQ,OAAO;IACjB;IACA,OAAO,gBAAgB;KACrB,cAAc,KAAA;KACd,uBAAO,IAAI,MAAM,kBAAkB,oBAAoB,CAAC;IAC1D;IACA,SAAS,KAAK,YAAY,MAAM;GAClC,CAAC;GACD,OAAO;EACT;;EAGA,SAAgB,aAAa,QAAqC;GAChE,OAAO,SAAS,SAAS;EAC3B;;EAGA,SAAgB,cAAuB;GACrC,OAAO,SAAS,KAAK,aAAa,oBAAoB;EACxD;;EAGA,IAAI,YAAY;;;;;;EAOhB,SAAS,kBAAkB,SAAyB,OAAqB;GACvE,QAAQ,WAAW;IACjB,aAAa;IACb;IACA,eAAe;IACf,YAAY;GACd,CAAC;EACH;;EAGA,eAAe,UAAU,SAAyB,QAAiC;GACjF,MAAM,EAAE,QAAQ,MAAM,QAAQ,OAAO,mBAAoB,aAAa,KAAM,MAAM;GAClF,OAAO;EACT;;EAGA,MAAM,sBAAsB;GAAC;GAAU;GAAiB;GAAU;GAAU;EAAO;;EAGnF,SAAS,eAAe,MAAuB;GAC7C,OAAO,OAAO,KAAK,IAAI;EACzB;;EAGA,SAAS,gBAAgB,OAAwB;GAC/C,OAAO,gBAAgB,KAAK,MAAM,KAAK,CAAC;EAC1C;;;;;;;;EASA,SAAgB,YAAY,KAAqB;GAC/C,MAAM,WAAW,SAAS,cAAc,UAAU;GAClD,SAAS,YAAY;GACrB,MAAM,OAAO,SAAS;GAGtB,KAAK,IAAI,QAAQ,MAAM,QAAS;IAC9B,QAAQ;IACR,KAAK,MAAM,MAAM,MAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC,GACpD,IAAI,oBAAoB,MAAM,QAAQ,GAAG,QAAQ,YAAY,MAAM,IAAI,YAAY,CAAC,GAAG;KACrF,GAAG,OAAO;KACV,QAAQ;IACV;GAEJ;GAGA,KAAK,MAAM,MAAM,MAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC,GACpD,KAAK,MAAM,QAAQ,MAAM,KAAK,GAAG,UAAU,GACzC,IAAI,eAAe,KAAK,IAAI,KAAK,gBAAgB,KAAK,KAAK,GAAG,GAAG,gBAAgB,KAAK,IAAI;GAI9F,MAAM,UAAU,SAAS;GACzB,MAAM,QAAQ,QAAQ,YAAY;GAClC,IAAI,MAAM,SAAS,SAAS,KAAK,MAAM,SAAS,aAAa,GAC3D,MAAM,IAAI,MAAM,gEAAgE;GAElF,OAAO;EACT;;;;;;;;EASA,SAAgB,sBAAsB,OAAqC;GACzE,MAAM,QAA0B,CAAC;GACjC,MAAM,uBAAO,IAAI,IAAa;GAC9B,KAAK,MAAM,MAAM,MAAM,KAAK,MAAM,iBAAiB,6CAA6C,CAAC,GAAG;IAClG,MAAM,MAAM,cAAc,iBAAiB,KAAK,GAAG;IACnD,IAAI,QAAQ,QAAQ,EAAE,eAAe,iBAAiB;IACtD,IAAI,KAAK,IAAI,GAAG,GAAG;IACnB,KAAK,IAAI,GAAG;IACZ,IAAI,IAAI,aAAa,YAAY,GAAG;IACpC,KAAK,IAAI,eAAe,GAAA,CAAI,KAAK,MAAM,IAAI;IAC3C,MAAM,KAAK,GAAG;GAChB;GACA,OAAO;EACT;;;;;;EAOA,SAAS,WAAW,KAAqB,WAAgC;GACvE,IAAI,aAAa,cAAc,GAAG;GAClC,MAAM,YAAY,SAAS,cAAc,KAAK;GAC9C,UAAU,YAAY;GACtB,UAAU,aAAa,YAAY,SAAS;GAC5C,UAAU,aAAa,aAAa,IAAI,eAAe,EAAE;GACzD,IAAI,sBAAsB,YAAY,SAAS;GAC/C,OAAO;EACT;;;;;;EAiBA,eAAsB,qBAAqB,OAAmB,SAAwC;GACpG,IAAI;GACJ,IAAI;IACF,UAAU,MAAM,mBAAmB;GACrC,QAAQ;IACN;GACF;GACA,kBAAkB,SAAS,QAAQ,KAAK;GACxC,MAAM,OAA6B,CAAC;GACpC,KAAK,MAAM,OAAO,sBAAsB,KAAK,GAAG;IAC9C,IAAI,QAAQ,OAAO,GAAG,MAAM,MAAM;IAClC,MAAM,YAAY,WAAW,KAAK,QAAQ,SAAS;IACnD,KAAK,MAAM,YAAY;KACrB,IAAI;MACF,UAAU,aAAa,YAAY,WAAW;MAC9C,MAAM,SAAS,UAAU,aAAa,WAAW,KAAK;MACtD,MAAM,MAAM,MAAM,UAAU,SAAS,MAAM;MAC3C,UAAU,YAAY,YAAY,GAAG;MACrC,UAAU,aAAa,YAAY,MAAM;MACzC,IAAI,MAAM,UAAU;KACtB,QAAQ;MAEN,UAAU,OAAO;MACjB,IAAI,gBAAgB,YAAY;KAClC;IACF,EAAA,CAAG,CAAC;GACN;GACA,MAAM,QAAQ,IAAI,IAAI;EACxB;;;;;;EAOA,eAAsB,qBAAqB,OAAmB,SAA2C;GACvG,MAAM,UAAU,cAAc;GAC9B,IAAI,YAAY,MAAM;GACtB,kBAAkB,SAAS,QAAQ,KAAK;GACxC,MAAM,aAAa,MAAM,KAAK,MAAM,iBAA8B,+BAA6B,CAAC;GAChG,MAAM,QAAQ,IAAI,WAAW,IAAI,OAAO,cAAc;IACpD,MAAM,SAAS,UAAU,aAAa,WAAW,KAAK;IACtD,IAAI;KAEF,UAAU,YAAY,YAAY,MADhB,UAAU,SAAS,MAAM,CACN;IACvC,QAAQ,CAER;GACF,CAAC,CAAC;EACJ;;;;;EAMA,SAAgB,gBAAgB,UAAiD;GAC/E,MAAM,WAAW,IAAI,uBAAuB;IAAE,SAAS,YAAY,CAAC;GAAE,CAAC;GACvE,SAAS,QAAQ,SAAS,MAAM;IAAE,YAAY;IAAM,iBAAiB,CAAC,oBAAoB;GAAE,CAAC;GAC7F,aAAa;IAAE,SAAS,WAAW;GAAE;EACvC;;;;;;;;;;;;ECtPA,MAAa,kBAAkB;;EAG/B,SAAgB,WAAW,EACzB,KACA,UACA,OACA,iBACA,UAOc;GACd,IAAI,IAAI,UAAU,MAChB,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWC,2BAAW;cAA3B,CACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,2BAAW;eAAmB,IAAI;IAAW,CAAA,GAC7D,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,2BAAW;eAAmB,IAAI;IAAW,CAAA,CAC1D;;GAGP,MAAM,WAAW,IAAI,gBAAgB,cAAc,IAAI,gBAAgB,UAClE,IAAI,gBAAgB,UAAU,IAAI,gBAAgB,SAAS,IAAI,gBAAgB;GAGpF,IAAI,SAAS,UACX,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;IACO;IACY;IACT;GACT,CAAA;GAIL,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cAA3B;KACG,IAAI,aAAa,IAAI,YAAY,QAChC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;gBAAgB,EAAE,wBAAwB;KAAO,CAAA;KAE7E,IAAI,gBAAgB,cAAc,IAAI,YAAY,QACjD,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD;MACE,SAAS,IAAI;MACb,MAAM,IAAI;MACV,MAAM,IAAI;MACV,YAAY,aAAa;MACR;KAClB,CAAA;KAEF,IAAI,gBAAgB,UAAU,IAAI,YAAY,QAC7C,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;MACE,SAAS,IAAI;MACb,YAAY,aAAa;MACR;KAClB,CAAA;MAED,IAAI,gBAAgB,UAAU,IAAI,gBAAgB,WAAW,IAAI,YAAY,QAC7E,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;MAAY,SAAS,IAAI;MAAS,UAAU,IAAI,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;KAAK,CAAA;KAEhF,IAAI,gBAAgB,SAAS,IAAI,YAAY,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,SAAS,IAAI,QAAU,CAAA;KACvF,IAAI,gBAAgB,UAAU,IAAI,YAAY,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD,EAAY,SAAS,IAAI,QAAU,CAAA;KACzF,IAAI,gBAAgB,WAAW,IAAI,YAAY,QAC9C,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;MAAa,KAAK,IAAI;MAAS,MAAM,GAAG,IAAI,OAAO,SAAS,KAAK,IAAI,QAAQ,QAAQ,KAAK,IAAI,OAAO,UAAU;KAAO,CAAA;KAEvH,IAAI,gBAAgB,SAAS,IAAI,YAAY,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;MAAW,SAAS,IAAI;MAAS,OAAO,IAAI;KAAQ,CAAA;KACzG,IAAI,gBAAgB,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAgB,IAAM,CAAA;MAClD,IAAI,gBAAgB,UAAU,IAAI,gBAAgB,WAAW,IAAI,gBAAgB,SAAS,IAAI,gBAAgB,kBAC9G,iBAAA,GAAA,kBAAA,IAAA,CAAC,mBAAD,EAAwB,IAAM,CAAA;KAE/B,IAAI,YAAY,QAAQ,CAAC,IAAI,WAC5B,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;gBAA3B,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,2BAAW;iBAAmB,IAAI;MAAW,CAAA,GAC7D,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,2BAAW;iBAAkB,EAAE,sBAAsB;MAAO,CAAA,CACzE;;KAEN,IAAI,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;gBAAc,EAAE,aAAa;KAAO,CAAA;IAC5E;;EAET;;EAGA,SAAS,UAAU,EACjB,KACA,iBACA,UAKc;GACd,MAAM,EAAE,OAAO,YAAY,gBAAgB,kBAAkB;IAC3D,MAAM;IACN,cAAc;IACd,UAAU;IACV,UAAU;IACV,YAAY;GACd,CAAC;GACD,MAAM,UAAU,IAAI,WAAW;GAE/B,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cAA3B;KACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;MAAe,OAAO,EAAE,OAAO,GAAG,WAAW,GAAG;gBAA3E,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,2BAAW;iBAAc,EAAE,gBAAgB;MAAO,CAAA,GAClE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,2BAAW;iBACzB,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;QACE,WAAWA,2BAAW;QACtB,OAAO;QACP,YAAY;QACZ,WAAW,UAAU,gBAAgB,MAAM,OAAO,KAAK;QACvD,YAAY,UAAU;SACpB,KAAK,MAAM,WAAW,MAAM,YAAY,MAAM,QAAQ,KAAK;UACzD,MAAM,eAAe;UACrB,OAAO;SACT;QACF;OACD,CAAA;MACE,CAAA,CACF;;KACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MACE,WAAWA,2BAAW;MACtB,gBAAa;MACb,OAAO,EAAE,MAAM,QAAQ,WAAW,UAAU;MAC5C,GAAI;KACL,CAAA;KACD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;MAAgB,OAAO,EAAE,OAAO,GAAG,MAAM,WAAW,GAAG;gBAAlF,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,2BAAW;iBAAc,EAAE,iBAAiB;MAAO,CAAA,GACnE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,2BAAW;iBAA3B;QACG,IAAI,gBAAgB,cAAc,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD;SAAyB;SAAS,MAAM,IAAI;SAAM,MAAM,IAAI;QAAO,CAAA;QACrG,IAAI,gBAAgB,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD,EAAqB,QAAU,CAAA;QAC7D,IAAI,gBAAgB,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAoB,QAAU,CAAA;QAC3D,IAAI,gBAAgB,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;SAAqB;SAAS,UAAU,IAAI,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;QAAK,CAAA;OACvG;QACF;;IACF;;EAET;;EAGA,SAAS,eAAe,EACtB,SACA,MACA,MACA,aAAa,OACb,mBASc;GACd,MAAM,mBAAA,GAAA,MAAA,YAAA,EAA+B,QAA+B;IAClE,IAAI,SAAS,MAAM,SAAS,IAAI,OAAO;IACvC,MAAM,aAAa,qBAAqB,MAAM,GAAG;IACjD,IAAI,WAAW,SAAS,YAAY,OAAO;IAC3C,IAAI,WAAW,SAAS,UAAU,OAAO;IAGzC,OAAO,qBAAqB,mBAAmB,IAAI,EAAE,QAAQ,mBAAmB,WAAW,IAAI,IAAI,WAAW;GAChH,GAAG,CAAC,MAAM,IAAI,CAAC;GACf,MAAM,QAAA,GAAA,MAAA,QAAA,OACE,eAAe,SAAS,EAAE,gBAAgB,CAAC,GACjD,CAAC,SAAS,eAAe,CAC3B;GACA,IAAI,cAAc,oBAAoB,KAAA,GACpC,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cACzB,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;KACE,WAAWA,2BAAW;KACtB,OAAO;KACP,YAAY;KACZ,WAAW,UAAU,gBAAgB,MAAM,OAAO,KAAK;IACxD,CAAA;GACE,CAAA;GAGT,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,sBAAD,EAA4B,KAAO,CAAA;EAC5C;;;;;;;EAQA,SAAS,qBAAqB,EAAE,QAAuC;GACrE,MAAM,OAAA,GAAA,MAAA,OAAA,CAAoC,IAAI;GAC9C,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,KAAK,IAAI;IACf,IAAI,OAAO,MAAM,OAAO,KAAA;IACxB,qBAA0B,IAAI;KAAE,WAAWA,2BAAW;KAAc,OAAO,aAAa,YAAY,CAAC;IAAE,CAAC;IACxG,OAAO,iBAAiB,WAAW;KACjC,qBAA0B,IAAI,EAAE,OAAO,aAAa,MAAM,EAAE,CAAC;IAC/D,CAAC;GACH,GAAG,CAAC,IAAI,CAAC;GACT,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IACO;IACL,WAAWA,2BAAW;KACf,gBAAgB;IACvB,yBAAyB,EAAE,QAAQ,KAAK;GACzC,CAAA;EAEL;;EAGA,SAAS,WAAW,EAClB,SACA,aAAa,OACb,mBAKc;GACd,MAAM,UAAA,GAAA,MAAA,QAAA,OAAuB;IAE3B,OAAO,kQAAkQ,QAAQ;GACnR,GAAG,CAAC,OAAO,CAAC;GACZ,IAAI,cAAc,oBAAoB,KAAA,GACpC,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cACzB,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;KACE,WAAWA,2BAAW;KACtB,OAAO;KACP,YAAY;KACZ,WAAW,UAAU,gBAAgB,MAAM,OAAO,KAAK;IACxD,CAAA;GACE,CAAA;GAGT,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,WAAWA,2BAAW;IAAmB;IAAQ,SAAQ;IAAG,OAAM;GAAgB,CAAA;EACnG;;;;;;;;;;;;;EAcA,SAAgB,WAAW,EAAE,SAAS,YAAgE;GACpG,MAAM,YAAA,GAAA,MAAA,OAAA,CAAyC,IAAI;GACnD,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA8E,IAAI;GAEtG,MAAM,aAAA,GAAA,MAAA,QAAA,OAA0B;IAC9B,MAAM,UAAU,QAAQ,SAAS,IAAI,IAAI,QAAQ,MAAM,GAAG,EAAE,IAAI;IAChE,OAAO,YAAY,KAAK,IAAI,QAAQ,MAAM,IAAI,CAAC,CAAC;GAClD,GAAG,CAAC,OAAO,CAAC;GACZ,MAAM,WAAA,GAAA,MAAA,QAAA,OAAwB;IAC5B,MAAM,OAAiB,CAAC;IACxB,KAAK,IAAI,IAAI,GAAG,KAAK,WAAW,KAAK,GAAG,KAAK,KAAK,CAAC;IACnD,OAAO;GACT,GAAG,CAAC,SAAS,CAAC;GAGd,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,QAAQ,SAAS;IACvB,IAAI,UAAU,MAAM;IACpB,MAAM,gBAAsB;KAC1B,MAAM,MAAM,MAAM,cAAc,KAAK;KACrC,IAAI,QAAQ,MAAM;MAChB,eAAe,IAAI;MACnB;KACF;KACA,MAAM,YAAY,MAAM,sBAAsB;KAC9C,MAAM,UAAU,IAAI,sBAAsB;KAC1C,MAAM,WAAW,iBAAiB,GAAG;KACrC,MAAM,aAAa,WAAW,SAAS,UAAU;KACjD,MAAM,SAAS,WAAW,SAAS,UAAU;KAE7C,MAAM,YAAY,QAAQ,MAAM,UAAU;KAC1C,eAAe;MACb,aAAa,OAAO,SAAS,SAAS,IAAI,YAAY,MAAM,OAAO,SAAS,MAAM,IAAI,SAAS;MAC/F,YAAY,OAAO,SAAS,UAAU,IAAI,aAAa;KACzD,CAAC;IACH;IACA,QAAQ;IAIR,MAAM,WAAW,IAAI,iBAAiB,OAAO;IAC7C,SAAS,QAAQ,OAAO;KAAE,WAAW;KAAM,SAAS;IAAK,CAAC;IAC1D,aAAa,SAAS,WAAW;GACnC,GAAG,CAAC,OAAO,CAAC;GAEZ,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;IAAW,KAAK;cAA3C,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KACE,WAAWA,2BAAW;KACtB,eAAY;KACZ,OAAO,gBAAgB,OAAO,EAAE,YAAY,YAAY,WAAW,IAAI,KAAA;eAEtE,QAAQ,KAAK,WACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAEE,WAAWA,2BAAW;MACtB,OAAO,gBAAgB,OAAO;OAAE,QAAQ,YAAY;OAAY,YAAY,GAAG,YAAY,WAAW;MAAI,IAAI,KAAA;gBAE7G;KACE,GALE,MAKF,CACN;IACE,CAAA,GACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,2BAAW;eACzB,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,WAAD;MAAW,MAAM;MAAS,MAAM,aAAa,KAAK,KAAA,IAAY;MAAU,WAAWD,2BAAW;MAAY,WAAW,EAAE,kBAAkB;MAAG,aAAa,EAAE,sBAAsB;KAAI,CAAA;IAClL,CAAA,CACF;;EAET;;;;;;EAOA,MAAM,UAAA,GAAA,MAAA,KAAA,CAAc,SAAS,OAAO,EAAE,OAAO,YAAiE;GAC5G,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UACG,MAAM,KAAK,MAAM,cAChB,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAqB,KAAS,GAArB,SAAqB,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAqB,KAAS,GAArB,SAAqB,CAC5E,EACC,CAAA;EAER,CAAC;;;;;;;;;EAUD,SAAS,UAAU,KAAe,YAA4B;GAC5D,OAAO,GAAG,KAAK,UAAU,GAAG,EAAE,QAAQ;EACxC;;EAGA,SAAS,UAAU,EAAE,WAA6C;GAChE,MAAM,QAAA,GAAA,MAAA,QAAA,OAAqB,SAAS,OAAO,GAAG,CAAC,OAAO,CAAC;GACvD,MAAM,aAAA,GAAA,MAAA,QAAA,OAA0B;IAC9B,MAAM,yBAAS,IAAI,IAAoB;IACvC,OAAO,KAAK,KAAK,QAAQ;KACvB,MAAM,OAAO,OAAO,IAAI,KAAK,UAAU,GAAG,CAAC,KAAK;KAChD,OAAO,IAAI,KAAK,UAAU,GAAG,GAAG,OAAO,CAAC;KACxC,OAAO;MAAE,OAAO;MAAK,KAAK,UAAU,KAAK,IAAI;KAAE;IACjD,CAAC;GACH,GAAG,CAAC,IAAI,CAAC;GACT,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cACzB,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;KAAO,WAAWA,2BAAW;eAC1B,UAAU,KAAK,OAAO,UACrB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAwB,OAAO,MAAM;MAAO,UAAU,UAAU;KAAI,GAAvD,MAAM,GAAiD,CACrE;IACI,CAAA;GACJ,CAAA;EAET;;EAGA,SAAgB,SAAS,MAA0B;GACjD,MAAM,OAAmB,CAAC;GAC1B,IAAI,MAAgB,CAAC;GACrB,IAAI,OAAO;GACX,IAAI,WAAW;GACf,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;IACvC,MAAM,OAAO,KAAK;IAClB,IAAI,UAAU;KACZ,IAAI,SAAS,MACX,IAAI,KAAK,IAAI,OAAO,MAAK;MACvB,QAAQ;MACR,KAAK;KACP,OACE,WAAW;UAGb,QAAQ;KAEV;IACF;IACA,IAAI,SAAS,MAAK;KAChB,WAAW;KACX;IACF;IACA,IAAI,SAAS,KAAK;KAChB,IAAI,KAAK,IAAI;KACb,OAAO;KACP;IACF;IACA,IAAI,SAAS,MAAM;KACjB,IAAI,KAAK,IAAI;KACb,KAAK,KAAK,GAAG;KACb,MAAM,CAAC;KACP,OAAO;KACP;IACF;IACA,IAAI,SAAS,MAAM,QAAQ;GAC7B;GACA,IAAI,KAAK,IAAI;GACb,IAAI,IAAI,SAAS,KAAK,IAAI,OAAO,IAAI,KAAK,KAAK,GAAG;GAClD,OAAO;EACT;;EAGA,SAAS,WAAW,EAAE,WAA6C;GACjE,MAAM,QAAQ,QAAQ,MAAM,IAAI;GAChC,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cACxB,MAAM,KAAK,MAAM,UAAU;KAC1B,IAAI,YAAYA,2BAAW;KAC3B,IAAI,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,OAAO,KAAK,KAAK,WAAW,QAAQ,GAC1G,YAAYA,2BAAW;UAClB,IAAI,KAAK,WAAW,IAAI,GAC7B,YAAYA,2BAAW;UAClB,IAAI,KAAK,WAAW,GAAG,GAC5B,YAAYA,2BAAW;UAClB,IAAI,KAAK,WAAW,GAAG,GAC5B,YAAYA,2BAAW;KAEzB,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAA4B;gBACzB,SAAS,KAAK,MAAM;KAClB,GAFK,KAEL;IAET,CAAC;GACE,CAAA;EAET;;EAGA,SAAS,YAAY,EAAE,KAAK,QAAoD;GAC9E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cAA3B,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,2BAAW;eACzB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAU;MAAK,KAAI;KAAI,CAAA;IACpB,CAAA,GACJ,KAAK,KAAK,MAAM,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,2BAAW;eAAY;IAAU,CAAA,CACrE;;EAET;;EAGA,SAAS,UAAU,EAAE,SAAS,SAA0D;GACtF,MAAM,CAAC,KAAK,WAAA,GAAA,MAAA,SAAA,CAAkC,IAAI;GAClD,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,CAAC,QAAQ,WAAW,OAAO,GAAG;KAGhC,OAAO,YAAY,KAAK,OAAO,OAAO;KACtC;IACF;IACA,MAAM,OAAO,cAAc,OAAO;IAClC,IAAI,SAAS,MAAM;KACjB,OAAO,IAAI;KACX;IACF;IACA,MAAM,YAAY,IAAI,gBAAgB,IAAI;IAC1C,OAAO,SAAS;IAChB,aAAa,IAAI,gBAAgB,SAAS;GAC5C,GAAG,CAAC,OAAO,CAAC;GACZ,OAAO,QAAQ,OACX,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cAAc,EAAE,qBAAqB;GAAO,CAAA,IACvE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,WAAWA,2BAAW;IAAW,KAAK;IAAY;GAAQ,CAAA;EACxE;;EAGA,SAAgB,cAAc,SAA8B;GAC1D,MAAM,QAAQ,QAAQ,QAAQ,GAAG;GACjC,IAAI,UAAU,IAAI,OAAO;GACzB,MAAM,OAAO,QAAQ,MAAM,GAAG,KAAK;GACnC,MAAM,OAAO,eAAe,KAAK,IAAI,CAAC,GAAG,MAAM;GAC/C,IAAI;IACF,MAAM,SAAS,KAAK,QAAQ,MAAM,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;IAC1C,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,GAAG,MAAM,KAAK,OAAO,WAAW,CAAC;IACzE,OAAO,IAAI,KAAK,CAAC,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;GACzC,QAAQ;IACN,OAAO;GACT;EACF;;EAGA,SAAS,UAAU,EAAE,OAA8C;GACjE,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,IAAI,WAAW,EAAE;GACpD,MAAM,CAAC,KAAK,WAAA,GAAA,MAAA,SAAA,OAAyB,aAAa,IAAI,WAAW,EAAE,CAAC;GACpE,MAAM,YAAA,GAAA,MAAA,OAAA,CAAqC,IAAI;GAC/C,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,SAAS,IAAI,WAAW,EAAE;IAC1B,OAAO,aAAa,IAAI,WAAW,EAAE,CAAC;GACxC,GAAG,CAAC,IAAI,IAAI,IAAI,OAAO,CAAC;GAUxB,MAAM,6BAAmC;IACvC,MAAM,QAAQ,SAAS;IACvB,IAAI,UAAU,MAAM;IACpB,IAAI;KACF,MAAM,OAAO,MAAM,eAAe,SAAS;KAC3C,IAAI,SAAS,KAAA,KAAa,CAAC,KAAK,WAAW,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,WAAW,OAAO,SAAS,QAC/F,MAAM,MAAM;IAEhB,QAAQ,CAER;GACF;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cAA3B,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,2BAAW;eACzB,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;MACE,WAAWA,2BAAW;MACtB,OAAO;MACP,aAAa,EAAE,yBAAyB;MACxC,YAAY;MACZ,WAAW,UAAU,SAAS,MAAM,OAAO,KAAK;MAChD,YAAY,UAAU;OACpB,IAAI,MAAM,QAAQ,SAAS,OAAO,aAAa,KAAK,CAAC;OACrD,IAAI,MAAM,QAAQ,UAAU;QAC1B,SAAS,IAAI,WAAW,EAAE;QAC1B,OAAO,aAAa,IAAI,WAAW,EAAE,CAAC;OACxC;MACF;MACA,UAAU,UAAU,MAAM,cAAc,OAAO;KAChD,CAAA;IACE,CAAA,GACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;KAME,KAAK;KACL,WAAWA,2BAAW;KACtB,KAAK;KACL,OAAO,IAAI;KACX,SAAQ;KACR,OAAM;KACN,iBAAA;KACA,QAAQ;IACT,GATM,GAAG,IAAI,QAAQ,IAAI,eAAe,GASxC,CACE;;EAET;;EAGA,SAAgB,aAAa,OAAuB;GAClD,MAAM,UAAU,MAAM,KAAK;GAC3B,IAAI,YAAY,IAAI,OAAO;GAC3B,IAAI,KAAK,KAAK,OAAO,GAAG,OAAO,iCAAiC,mBAAmB,OAAO;GAC1F,MAAM,YAAY,gBAAgB,KAAK,OAAO,IAAI,UAAU,WAAW;GAMvE,IAAI,OAAO,WAAW,aACpB,IAAI;IACF,IAAI,IAAI,IAAI,SAAS,CAAC,CAAC,WAAW,OAAO,SAAS,QAAQ,OAAO;GACnE,QAAQ,CAER;GAEF,OAAO;EACT;;EAGA,SAAS,kBAAkB,EAAE,OAA8C;GACzE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,2BAAW;cAA3B;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;gBAAmB,IAAI;KAAW,CAAA;KAC7D,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;gBAAkB,EAAE,qBAAqB;KAAO,CAAA;KAC3E,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,2BAAW;gBAAkB,EAAE,sBAAsB;KAAO,CAAA;IACzE;;EAET;;;;ECjlBA,MAAM,2CAAwE,IAAI,IAAI;GACpF;GACA;GACA;GACA;EACF,CAAC;;EAGD,SAAS,OAAO,MAAc,QAAwB;GACpD,MAAM,OAAO,KAAK,WAAW,IAAI,KAAK,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,KAAK,MAAM,CAAC,CAAC;GAC9F,IAAI,OAAO;GACX,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GACpC,IAAI,KAAK,WAAW,CAAC,MAAM,IAAI,QAAQ;GAEzC,OAAO;EACT;;EAGA,SAAS,YAAY,KAAqB,MAAmB,QAA+B;GAC1F,IAAI,SAAS,MAAM,OAAO;GAC1B,IAAI;IACF,MAAM,QAAQ,SAAS,YAAY;IACnC,MAAM,SAAS,KAAK,CAAC;IACrB,MAAM,OAAO,MAAM,MAAM;IACzB,OAAO,MAAM,SAAS,CAAC,CAAC;GAC1B,QAAQ;IAEN,OAAO;GACT;EACF;;;;;;EAOA,SAAgB,2BACd,eACA,WACA,KAC+B;GAC/B,IAAI,kBAAkB,MAAM,OAAO;GACnC,IAAI,QAAQ,QAAQ,IAAI,YAAY,MAAM,OAAO;GACjD,IAAI,CAAC,yBAAyB,IAAI,IAAI,WAAW,GAAG,OAAO;GAC3D,MAAM,MAAM,cAAc,QAAQ,KAAK;GACvC,IAAI,QAAQ,MAAM,OAAO;GACzB,MAAM,aAAa,YAAY,KAAK,UAAU,YAAY,UAAU,YAAY;GAChF,MAAM,WAAW,YAAY,KAAK,UAAU,WAAW,UAAU,WAAW;GAC5E,IAAI,eAAe,QAAQ,aAAa,MAAM,OAAO;GACrD,MAAM,QAAQ,KAAK,IAAI,YAAY,QAAQ;GAC3C,MAAM,MAAM,KAAK,IAAI,YAAY,QAAQ;GACzC,IAAI,UAAU,KAAK,OAAO;GAC1B,MAAM,OAAO,IAAI,eAAe;GAChC,OAAO;IACL,MAAM,IAAI;IACV,WAAW,OAAO,MAAM,KAAK;IAC7B,SAAS,OAAO,MAAM,GAAG;GAC3B;EACF;;;;;;;;;;;;ECnDA,SAAgB,aAAa,EAAE,QAAQ,sBAAgI;GACrK,MAAM,UAAU,OAAO;GACvB,MAAM,QAAQ,SAAS,OAAO;GAE9B,MAAM,mBADc,SAAS,OAAO,MACD,CAAC,CAAC,cAAc;GACnD,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAsC,IAAI;GACvD,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA2C,IAAI;GAClE,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAA8C,SAAS;GACxE,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,KAAK;GACxC,MAAM,kBAAA,GAAA,MAAA,OAAA,iBAAqC,IAAI,IAAI,CAAC;GACpD,MAAM,YAAA,GAAA,MAAA,OAAA,CAAyC,IAAI;;GAGnD,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAAgD,IAAI;GAEtE,MAAM,YAAY,MAAM,KAAK,MAAM,QAAQ,IAAI,OAAO,MAAM,WAAW,KAAK;GAI5E,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,YAAY,SAAS;IACrB,SAAS,KAAK;GAChB,GAAG,CAJc,cAAc,OAAO,KAAK,GAAG,UAAU,KAAK,QAAQ,UAAU,aAInE,CAAC;GAKb,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,0BAAgC;KACpC,MAAM,YAAY,OAAO,aAAa;KACtC,IAAI,cAAc,QAAQ,UAAU,eAAe,UAAU,eAAe,GAAG;MAC7E,aAAa,IAAI;MACjB;KACF;KACA,MAAM,OAAO,UAAU;KACvB,MAAM,KAAK,gBAAgB,UAAU,OAAO,MAAM;KAClD,IAAI,OAAO,KAAA,KAAa,SAAS,YAAY,QAAQ,CAAC,SAAS,QAAQ,SAAS,EAAE,GAAG;MACnF,aAAa,IAAI;MACjB;KACF;KACA,MAAM,MAAM,2BAA2B,IAAI,WAAW,SAAS;KAC/D,IAAI,QAAQ,MAAM;MAChB,aAAa,IAAI;MACjB;KACF;KACA,MAAM,OAAO,UAAU,WAAW,CAAC,CAAC,CAAC,sBAAsB;KAC3D,aAAa;MAAE,GAAG,KAAK;MAAM,GAAG,KAAK,SAAS;MAAG;KAAI,CAAC;IACxD;IACA,MAAM,iBAAiB,UAA4B;KACjD,IAAI,cAAc,MAAM;KAExB,IADe,MAAM,OACV,QAAQ,IAAIE,2BAAW,WAAW,MAAM,MAAM,aAAa,IAAI;IAC5E;IACA,SAAS,iBAAiB,mBAAmB,iBAAiB;IAC9D,SAAS,iBAAiB,aAAa,aAAa;IACpD,aAAa;KACX,SAAS,oBAAoB,mBAAmB,iBAAiB;KACjE,SAAS,oBAAoB,aAAa,aAAa;IACzD;GACF,GAAG,CAAC,WAAW,SAAS,CAAC;GAEzB,MAAM,wBAA8B;IAClC,IAAI,cAAc,MAAM;IACxB,IAAI,mBAAmB,UAAU,GAAG,GAAG,aAAa,IAAI;GAC1D;;GAGA,MAAM,gBAAgB,QAAwB;IAC5C,MAAM,QAAQ,MAAM,KAAK,QAAQ,QAAQ,IAAI,SAAS,IAAI,EAAE,KAAK,IAAI,KAAK;IAC1E,IAAI,MAAM,WAAW,GAAG;KACtB,QAAQ,UAAU,GAAG;KACrB;IACF;IACA,eAAe,UAAU,IAAI,IAAI,MAAM,KAAK,QAAQ,IAAI,EAAE,CAAC;IAC3D,cAAc,GAAG;GACnB;GAEA,MAAM,gBAAgB,OAAyB,QAA+B;IAC5E,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,MAAM,QAAQ,MAAM,KAAK,WAAW,SAAS,KAAK,OAAO,IAAI,EAAE;IAC/D,QAAQ;KACN,GAAG,MAAM;KACT,GAAG,MAAM;KACT,SAAS;MACP;OACE,KAAK;OACL,OAAO,EAAE,mBAAmB;OAC5B,UAAU,SAAS;OACnB,gBAAgB,aAAa,MAAM,KAAK,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,SAAS,KAAK,EAAE,CAAC;MAChF;MACA;OACE,KAAK;OACL,OAAO,EAAE,oBAAoB;OAC7B,UAAU,SAAS,MAAM,KAAK,SAAS;OACvC,gBAAgB,aAAa,MAAM,KAAK,MAAM,QAAQ,CAAC,CAAC,CAAC,KAAK,SAAS,KAAK,EAAE,CAAC;MACjF;MACA;OAAE,KAAK;OAAS,OAAO;OAAO,gBAAgB,CAAC;MAAE;MACjD;OACE,KAAK;OACL,OAAO,EAAE,qBAAqB;OAC9B,UAAU,MAAM,KAAK,UAAU;OAC/B,gBAAgB,aAAa,MAAM,KAAK,QAAQ,SAAS,KAAK,OAAO,IAAI,EAAE,CAAC,CAAC,KAAK,SAAS,KAAK,EAAE,CAAC;MACrG;MACA;OACE,KAAK;OACL,OAAO,EAAE,kBAAkB;OAC3B,gBAAgB,aAAa,MAAM,KAAK,KAAK,SAAS,KAAK,EAAE,CAAC;MAChE;KACF;IACF,CAAC;GACH;;GAGA,MAAM,kBAAwB;IAC5B,MAAM,QAAQ,KAAK,IAAI;IACvB,MAAM,MAAuB;KAC3B,IAAI,OAAO;KACX,OAAO;KACP,MAAM,MAAM;KACZ,MAAM,OAAO;KACb,aAAa;KACb,SAAS;KACT,OAAO;KACP,SAAS;KACT,SAAS;KACT,WAAW;KACX,OAAO;KACP,SAAS,KAAK,IAAI;IACpB;IACA,QAAQ,QAAQ,UAAU;KAAE,GAAG;KAAM,MAAM;KAAM,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG;KAAG,aAAa,IAAI;IAAG,EAAE;GACpG;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,KAAK;IAAU,WAAW,gBAAgBA,2BAAW;cAA1D;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;MACE,MAAM,MAAM;MACZ,aAAa,MAAM;MACnB,WAAW,OAAO,QAAQ,UAAU,EAAE;MACtC,UAAU,OAAO,aAAa,CAAC,EAAE,CAAC;MAClC,eAAe;MACf,aAAa;MACb,oBAAoB,QAAQ,QAAQ,KAAK;MACzC,WAAW;MACX,kBAAkB;OAChB,OAAO,OAAO,QAAQ,UAAU;QAAE,GAAG;QAAM,WAAW,mBAAmB,OAAO;OAAU,EAAE;MAC9F;KACD,CAAA;KACA,cAAc,QACb,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD;MACE,aAAa,UAAU;MACvB,YAAY,UAAU,YAAY;MAClC,SAAS,UAAU;MACnB,OAAO,UAAU;MACjB,SAAS,UAAU;MACT;MACV,eAAe,UAAU,gBAAgB,cAAc,UAAU,gBAAgB;MAC1E;MACP,UAAU,eAAe,UAAU,WAAW,KAAK,UAAU,YAAY;MACzE,kBAAkB;MAClB,eAAe;MACf,iBAAiB,KAAK,QAAQ,UAAU,UAAU,EAAE;MACpD,cAAc,KAAK,QAAQ,QAAQ,UAAU,EAAE;MAC/C,kBAAkB,YAAY,SAAS;KACxC,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;MACE,KAAK;MACK;MACH;MACP,kBAAkB,YAAY,QAAQ,cAAc,UAAU,IAAI,OAAO;MACzE,cAAc,KAAK,QAAQ,QAAQ,UAAU,EAAE;KAChD,CAAA,CACD,EAAA,CAAA;KAEH,SAAS,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;MAAa,OAAO;MAAM,eAAe,QAAQ,IAAI;KAAI,CAAA;KAC1E,cAAc,QACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MACE,WAAWA,2BAAW;MACtB,OAAO;OAAE,MAAM,UAAU;OAAG,KAAK,UAAU;MAAE;MAC7C,SAAS;MACT,MAAK;MACL,UAAU;gBACX;KAEI,CAAA;KAEN,eAAe,QACd,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;MACE,OAAO,EAAE,2BAA2B;MACpC,MAAM,OAAO,EAAE,0BAA0B,GAAG,EAAE,OAAO,eAAe,QAAQ,KAAK,CAAC;MAClF,cAAc,EAAE,cAAc;MAC9B,QAAA;MACA,iBAAiB;OACf,QAAQ,UAAU,UAAU;OAC5B,cAAc,IAAI;MACpB;MACA,gBAAgB,cAAc,IAAI;KACnC,CAAA;IAEA;;EAET;;;;;;;;;;EC1NA,MAAM,wBAAwB;EAC9B,MAAM,uBAAuB;;EAG7B,SAAS,eAAe,UAAkB,SAAgD;GACxF,IAAI,WAAW;GACf,IAAI;GACJ,MAAM,gBAAsB;IAC1B,IAAI,UAAU;IACd,MAAM,KAAK,SAAS,cAA2B,QAAQ;IACvD,IAAI,OAAO,MAAM;KACf,UAAU,WAAW;KACrB,QAAQ,EAAE;IACZ;GACF;GACA,WAAW,IAAI,uBAAuB;IAAE,QAAQ;GAAE,CAAC;GACnD,SAAS,QAAQ,SAAS,MAAM;IAAE,WAAW;IAAM,SAAS;GAAK,CAAC;GAClE,QAAQ;GACR,aAAa;IACX,WAAW;IACX,UAAU,WAAW;GACvB;EACF;;;;;;;;;;;;EAaA,SAAgB,YACd,QACA,kBACA,aACA,oBACY;GACZ,IAAI;GACJ,IAAI;GACJ,MAAM,YAA+B,CAAC;GAEtC,UAAU,KAAK,eAAe,wBAAwB,OAAO;IAC3D,gBAAA,GAAA,iBAAA,WAAA,CAA0B,EAAE;IAC5B,aAAa,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;KAAuB;KAAQ,kBAAkB;KAA+B;IAAc,CAAA,CAAC;GACrH,CAAC,CAAC;GACF,UAAU,KAAK,eAAe,uBAAuB,OAAO;IAC1D,eAAA,GAAA,iBAAA,WAAA,CAAyB,EAAE;IAC3B,YAAY,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;KAAsB;KAA4B;IAAqB,CAAA,CAAC;GAC7F,CAAC,CAAC;GAEF,aAAa;IACX,KAAK,MAAM,WAAW,WAAW,QAAQ;IACzC,cAAc,QAAQ;IACtB,aAAa,QAAQ;GACvB;EACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EClCA,SAAgB,cAAc,OAAyC;GACrE,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,KAAK;GAC1C,MAAM,SAAA,GAAA,MAAA,OAAA,CAAe,CAAC;GAEtB,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,cAAoB;KACxB,MAAM,UAAU;KAChB,UAAU,KAAK;IACjB;IACA,MAAM,cAAc,UAA2B;KAC7C,IAAI,CAAC,YAAY,MAAM,cAAc,KAAK,GAAG;KAC7C,MAAM,eAAe;KACrB,MAAM,WAAW;KACjB,UAAU,IAAI;IAChB;IACA,MAAM,eAAe,UAA2B;KAC9C,IAAI,CAAC,YAAY,MAAM,cAAc,KAAK,GAAG;KAC7C,MAAM,UAAU,KAAK,IAAI,GAAG,MAAM,UAAU,CAAC;KAC7C,IAAI,MAAM,YAAY,GAAG,UAAU,KAAK;IAC1C;IACA,MAAM,UAAU,UAA2B;KACzC,IAAI,CAAC,YAAY,MAAM,cAAc,KAAK,GAAG;KAC7C,MAAM,eAAe;KACrB,MAAM,OAAO,MAAM,cAAc,QAAA,wBAAsB,KAAK;KAC5D,MAAM;KACN,IAAI,uBAAuB,IAAI,GAAG,MAAM,WAAW,IAAI;IACzD;IACA,MAAM,kBAAwB,MAAM;IACpC,SAAS,iBAAiB,YAAY,UAAU;IAChD,SAAS,iBAAiB,aAAa,WAAW;IAClD,SAAS,iBAAiB,QAAQ,MAAM;IACxC,OAAO,iBAAiB,WAAW,SAAS;IAC5C,aAAa;KACX,SAAS,oBAAoB,YAAY,UAAU;KACnD,SAAS,oBAAoB,aAAa,WAAW;KACrD,SAAS,oBAAoB,QAAQ,MAAM;KAC3C,OAAO,oBAAoB,WAAW,SAAS;IACjD;GACF,GAAG,CAAC,MAAM,UAAU,CAAC;GAErB,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IACE,WAAW,SAAS,GAAGC,wBAAQ,MAAM,GAAGA,wBAAQ,gBAAgBA,wBAAQ;IACxE,eAAY;IACZ,aAAU;cAET,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAWA,wBAAQ;eAAY,EAAE,wBAAwB;IAAQ,CAAA,IAAI;GAClF,CAAA;EAET;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECzDA,SAAgB,iBAAiB,SAAsC;GACrE,MAAM,yBAAS,IAAI,IAAa;GAChC,KAAK,MAAM,UAAU,SAAS;IAG5B,IAAI,OAAO,WAAW,WAAW,GAAG;IACpC,IAAI,OAAO,kBAAkB,WAAW,OAAO,OAAO,aACpD,OAAO,IAAI,OAAO,MAAM;IAE1B,KAAK,MAAM,QAAQ,OAAO,YAAY;KACpC,MAAM,UAAU,gBAAgB,UAAU,OAAO,KAAK;KACtD,IAAI,YAAY,QAAQ,QAAQ,aAAa,OAAO,IAAI,OAAO;IACjE;GACF;GACA,OAAO,MAAM,KAAK,MAAM;EAC1B;;EAGA,SAAgB,sBAA0C;GACxD,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,YAAY;IAChB,IAAI,eAAe;IACnB,IAAI,YAAY;IAChB,IAAI,iBAAmC,CAAC;IACxC,MAAM,YAAkB;KACtB,YAAY;KACZ,MAAM,UAAU;KAChB,iBAAiB,CAAC;KAClB,MAAM,SAAS,iBAAiB,OAAO;KACvC,IAAI,WAAW;MAIb,YAAY;MACZ,qBAA0B,SAAS,MAAM;OACvC,WAAWC,2BAAW;OACtB,OAAO,aAAa,YAAY,CAAC;OACjC,OAAO,QAAQ,IAAI,QAAQ,IAAI,cAAc,EAAE,MAAM;MACvD,CAAC;MACD;KACF;KACA,KAAK,MAAM,SAAS,QAClB,qBAA0B,OAAO;MAC/B,WAAWA,2BAAW;MACtB,OAAO,aAAa,YAAY,CAAC;MACjC,OAAO,QAAQ,IAAI,QAAQ,IAAI,cAAc,EAAE,MAAM;KACvD,CAAC;IAEL;IACA,MAAM,iBAAuB;KAC3B,IAAI,WAAW;KACf,YAAY;KACZ,eAAe,sBAAsB,GAAG;IAC1C;IACA,MAAM,WAAW,IAAI,kBAAkB,YAAY;KACjD,iBAAiB,eAAe,OAAO,OAAO;KAC9C,SAAS;IACX,CAAC;IACD,SAAS,QAAQ,SAAS,MAAM;KAAE,WAAW;KAAM,SAAS;IAAK,CAAC;IAClE,SAAS;IACT,MAAM,eAAe,iBAAiB,WAAW;KAC/C,qBAA0B,SAAS,MAAM,EAAE,OAAO,aAAa,MAAM,EAAE,CAAC;IAC1E,CAAC;IACD,aAAa;KACX,SAAS,WAAW;KACpB,aAAa;KACb,qBAAqB,YAAY;IACnC;GACF,GAAG,CAAC,CAAC;GACL,OAAO;EACT;;;;;;;;;;;;;;;ECrFA,MAAM,kBAAkB;EACxB,MAAM,kBAAkB;;EAGxB,SAASC,UAAc;GACrB,KAAK,MAAM,MAAM,SAAS,iBAAyD,gCAA8B,GAC/G,IAAI,GAAG,gBAAgB,iBAAiB,GAAG,cAAc;EAE7D;;EAGA,SAAgB,kBAAsC;GACpD,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,QAAM;IACN,MAAM,WAAW,IAAI,kBAAkB,YAAY;KAIjD,IAHiB,QAAQ,MACtB,WAAW,OAAO,SAAS,gBAAgB,OAAO,WAAW,SAAS,CAE9D,GAAG,QAAM;IACtB,CAAC;IACD,SAAS,QAAQ,SAAS,MAAM;KAC9B,YAAY;KACZ,iBAAiB,CAAC,aAAa;KAC/B,WAAW;KACX,SAAS;IACX,CAAC;IACD,aAAa;KAAE,SAAS,WAAW;IAAE;GACvC,GAAG,CAAC,CAAC;GACL,OAAO;EACT;;;;ECMA,IAAM,mBAAN,MAAuB;GACrB,QAA2B;IAAE,MAAM;IAAO,KAAK;GAAK;GACpD,4BAA6B,IAAI,IAAc;;GAG/C,cAAyB;IACvB,OAAO,KAAK;GACd;;GAGA,UAAU,UAAgC;IACxC,KAAK,UAAU,IAAI,QAAQ;IAC3B,aAAa;KAAE,KAAK,UAAU,OAAO,QAAQ;IAAE;GACjD;;GAGA,KAAK,KAAwB;IAC3B,KAAK,QAAQ;KAAE,MAAM;KAAM;IAAI;IAC/B,KAAK,KAAK;GACZ;;GAGA,QAAc;IACZ,IAAI,CAAC,KAAK,MAAM,MAAM;IACtB,KAAK,QAAQ;KAAE,MAAM;KAAO,KAAK;IAAK;IACtC,KAAK,KAAK;GACZ;GAEA,OAAqB;IACnB,KAAK,MAAM,YAAY,KAAK,WAAW,SAAS,KAAK,KAAK;GAC5D;EACF;;EAGA,MAAa,aAAa,IAAI,iBAAiB;;;;EC/C/C,SAAS,WAAW,KAAqB;GACvC,MAAM,MAAM,IAAI,YAAY,GAAG;GAC/B,OAAO,OAAO,IAAI,IAAI,MAAM,MAAM,CAAC,IAAI;EACzC;;EAGA,SAAS,UAAU,KAAqB;GACtC,MAAM,MAAM,IAAI,YAAY,GAAG;GAC/B,OAAO,MAAM,IAAI,IAAI,MAAM,GAAG,GAAG,IAAI;EACvC;;;;;;EAOA,SAAS,eAAe,KAA4B;GAClD,MAAM,WAAW,WAAW,IAAI,IAAI;GACpC,MAAM,UAAU,UAAU,IAAI,IAAI;GAClC,MAAM,OAAO,YAAY,KAAK,WAAW,GAAG,SAAS,KAAK;GAC1D,OAAO,IAAI,UAAU,IAAI,YAAY,GAAG,KAAK,GAAG,IAAI,UAAU,GAAG,IAAI,YAAY,GAAG,KAAK,GAAG,IAAI;EAClG;;EAGA,SAAgB,mBAAmB,KAAmE;GACpG,MAAM,QAAQ,IAAI,UAAU,IAAI,YAAY,GAAG,IAAI,UAAU,GAAG,IAAI,YAAY,GAAG,IAAI;GACvF,OAAO,IAAI,IAAI,KAAK,GAAG;EACzB;;EAkBA,SAAgB,cAAc,KAAoB,WAAkC,MAAuB;GACzG,IAAI;IACF,IAAI,cAAc,KAAA,GAAW,OAAO;IACpC,MAAM,OAAO,IAAI,SAAS,MAAM,SAAS;IACzC,IAAI,SAAS,KAAA,GAAW,OAAO;IAC/B,MAAM,eAAgB,IAA0D;IAChF,IAAI,iBAAiB,KAAA,GAAW,OAAO;IACvC,MAAM,QAAQ,aAAa,MAAM,IAAI,IAAgC;IACrE,MAAM,QAAQ,MAAM,MAAM,YAAY,CAAC,CAAC;IACxC,MAAM,SAAS,MAAM,KAAK,MAAM,KAAK,OAAO,GAAG,MAAM,GAAG,MAAM;IAC9D,OAAO;GACT,SAAS,OAAO;IACd,QAAQ,KAAK,sCAAsC,KAAK;IACxD,OAAO;GACT;EACF;;;;;;;;;;EAWA,SAAgB,oBACd,KACA,WACA,KACA,MACS;GACT,IAAI;IACF,IAAI,cAAc,KAAA,GAAW,OAAO;IACpC,MAAM,OAAO,IAAI,SAAS,MAAM,SAAS;IACzC,IAAI,SAAS,KAAA,GAAW,OAAO;IAC/B,MAAM,YAAmC;KACvC,QAAQ;KACR,KAAK,mBAAmB,GAAG;KAC3B,OAAO,eAAe,GAAG;KACzB,eAAe,mBAAmB,GAAG;IACvC;IACA,OAAQ,KAEL,KAAK,MAAM,gCAAgC;KAAE;KAAW;IAAK,CAAC;GACnE,SAAS,OAAO;IACd,QAAQ,KAAK,+CAA+C,KAAK;IACjE,OAAO;GACT;EACF;;;;;;;;;EAUA,SAAgB,wBACd,KACA,WACA,KACS;GACT,IAAI,cAAc,KAAA,GAAW,OAAO;GACpC,MAAM,OAAO,IAAI,SAAS,MAAM,SAAS;GACzC,IAAI,SAAS,KAAA,GAAW,OAAO;GAC/B,MAAM,eAAgB,IAA0D;GAChF,IAAI,iBAAiB,KAAA,GAAW,OAAO;GAEvC,MAAM,OADQ,aAAa,MAAM,IAAI,IACpB,CAAC,CAAC,MAAM,YAAY;GACrC,OAAO,oBACL,KACA,WACA,KACA;IAAE,OAAO,KAAK,MAAM;IAAQ,KAAK,KAAK,MAAM;IAAQ,UAAU,KAAK;GAAS,CAC9E;EACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECpIA,MAAM,qBAAqB;;EAG3B,SAAS,UAAU,KAAuB;GACxC,MAAM,MAAgB,CAAC;GACvB,IAAI,MAAM;GACV,KAAK,MAAM,QAAQ,IAAI,MAAM,GAAG,GAAG;IACjC,IAAI,SAAS,IAAI;IACjB,MAAM,QAAQ,KAAK,OAAO,GAAG,IAAI,GAAG;IACpC,IAAI,KAAK,GAAG;GACd;GACA,OAAO;EACT;;EASA,SAAgB,gBAAgB,EAC9B,OACA,KACA,UACA,WAMqB;GACrB,MAAM,MAAM,MAAM;GAClB,MAAM,OAAO,KAAK,QAAQ;GAC1B,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,iBAAqC,IAAI,IAAI,CAAC;GAC/D,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAA+C,CAAC,CAAC;GAC9D,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAgD,CAAC,CAAC;GAClE,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,iBAA8C,IAAI,IAAI,CAAC;GACxE,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,EAAE;GACvC,MAAM,CAAC,eAAe,qBAAA,GAAA,MAAA,SAAA,CAAiD,IAAI;GAC3E,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAAyB,KAAK;GAChD,MAAM,aAAA,GAAA,MAAA,OAAA,CAAmB,CAAC;;GAG1B,MAAM,WAAW,QAAsB;IACrC,IAAI,KAAK,SAAS,KAAA,KAAa,QAAQ,MAAM;IAC7C,YAAY,UAAU;KAAE,GAAG;MAAO,MAAM;IAAK,EAAE;IAC/C,IAAS,KAAK,MAAM,GAAG,CAAC,CAAC,MAAM,WAAW;KACxC,YAAY,UAAU;MAAE,GAAG;OAAO,MAAM;KAAM,EAAE;KAChD,IAAI,OAAO,IAAI,SAAS,UAAU;MAAE,GAAG;OAAO,MAAM,OAAO,MAAM;KAAQ,EAAE;IAC7E,CAAC;GACH;;GAGA,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,4BAAY,IAAI,IAAI,CAAC;IACrB,QAAQ,CAAC,CAAC;IACV,WAAW,CAAC,CAAC;IACb,4BAAY,IAAI,IAAI,CAAC;IACrB,UAAU,EAAE;IACZ,iBAAiB,IAAI;IACrB,IAAI,SAAS,IAAI;IACjB,QAAQ,EAAE;IACV,IAAI,QAAQ,QAAQ,IAAI,eAAe,IACrC,KAAK,MAAM,OAAO,UAAU,IAAI,UAAU,GAAG;KAC3C,aAAa,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC;KAC5C,QAAQ,GAAG;IACb;GAGJ,GAAG,CAAC,MAAM,KAAK,UAAU,CAAC;GAG1B,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,IAAI,OAAO,KAAK;IACtB,IAAI,MAAM,IAAI;KACZ,UAAU,WAAW;KACrB,iBAAiB,IAAI;KACrB,aAAa,KAAK;KAClB;IACF;IACA,MAAM,MAAM,EAAE,UAAU;IACxB,aAAa,IAAI;IACjB,MAAM,QAAQ,iBAAiB;KAC7B,IAAS,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,WAAW;MACxC,IAAI,UAAU,YAAY,KAAK;MAC/B,aAAa,KAAK;MAClB,iBAAiB,OAAO,KAAK,OAAO,MAAM,OAAO,CAAC,CAAC;KACrD,CAAC;IACH,GAAG,kBAAkB;IACrB,aAAa;KAAE,aAAa,KAAK;IAAE;GACrC,GAAG;IAAC;IAAQ;IAAM;GAAG,CAAC;GAEtB,MAAM,aAAa,QAAsB;IACvC,aAAa,SAAS;KACpB,MAAM,OAAO,IAAI,IAAI,IAAI;KACzB,IAAI,KAAK,IAAI,GAAG,GAAG,KAAK,OAAO,GAAG;UAC7B;MACH,KAAK,IAAI,GAAG;MACZ,QAAQ,GAAG;KACb;KACA,OAAO;IACT,CAAC;GACH;;GAGA,MAAM,gBAAgB,MAAc,UAAyB;IAC3D,aAAa,SAAS;KACpB,MAAM,OAAO,IAAI,IAAI,IAAI;KACzB,IAAI,KAAK,IAAI,IAAI,GAAG,KAAK,OAAO,IAAI;UAC/B,KAAK,IAAI,MAAM,KAAK;KACzB,OAAO;IACT,CAAC;GACH;GAGA,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,CAAC,MAAM,MAAM;IACjB,MAAM,SAAS,MAA2B;KACxC,IAAI,EAAE,QAAQ,UAAU,QAAQ;IAClC;IACA,OAAO,iBAAiB,WAAW,KAAK;IACxC,aAAa,OAAO,oBAAoB,WAAW,KAAK;GAC1D,GAAG,CAAC,MAAM,MAAM,OAAO,CAAC;GAExB,MAAM,QAAA,GAAA,MAAA,QAAA,OAAqB;IACzB,MAAM,cAAc,OAAgB,UAA+B;KACjE,MAAM,QAAQ,MAAM;KACpB,MAAM,SAAS,SAAS,IAAI,MAAM,IAAI;KACtC,MAAM,QAAQ,SAAS,IAAI,MAAM,IAAI;KACrC,MAAM,WAAW,KAAK,MAAM,SAAS,CAAC;KACtC,MAAM,YAAY,QAAQ,MAAM,UAAU;KAC1C,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MACE,WAAW,GAAGC,0BAAU,MAAM,QAAQ,IAAIA,0BAAU,gBAAgB;MACpE,OAAO,EAAE,aAAa,IAAI,QAAQ,GAAG;MACrC,eAAe,aAAa,MAAM,MAAM,KAAK;gBAH/C;OAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QACE,WAAWA,0BAAU;QACrB,MAAK;QACL,UAAU;QACV,UAAU,MAAM;SACd,IAAI,CAAC,OAAO;SACZ,EAAE,gBAAgB;SAClB,UAAU,MAAM,IAAI;QACtB;kBAEC,QAAS,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAD,EAAiB,MAAM,GAAK,CAAA,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAAC,kBAAD,EAAkB,MAAM,GAAK,CAAA,IAAK,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,WAAWA,0BAAU,WAAa,CAAA;OACzH,CAAA;OACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,0BAAU;kBACxB,QAAS,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD,EAAgB,MAAM,GAAK,CAAA,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD,EAAY,MAAM,GAAK,CAAA,IAAK,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;OAC/F,CAAA;OACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,0BAAU;QAAM,OAAO,MAAM;kBAAO,MAAM;OAAW,CAAA;OACtE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QACE,WAAW,GAAGA,0BAAU,QAAQ,QAAQ,IAAIA,0BAAU,YAAY;QAClE,UAAU,MAAM;SACd,EAAE,gBAAgB;SAClB,aAAa,MAAM,MAAM,KAAK;QAChC;kBAEC,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA,IAAI;OAC/B,CAAA;MACH;SACJ,SAAS,UACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAA,UACG,YACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,0BAAU;MAAM,OAAO,EAAE,aAAa,KAAK,QAAQ,KAAK,GAAG;gBAAG;KAAS,CAAA,IACrF,SAAS,WAAW,IACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,0BAAU;MAAM,OAAO,EAAE,aAAa,KAAK,QAAQ,KAAK,GAAG;gBAAG;KAAU,CAAA,IAExF,SAAS,KAAK,UAAU,WAAW,OAAO,QAAQ,CAAC,CAAC,EAEnD,CAAA,CAEJ,EAAA,GA3CK,MAAM,IA2CX;IAET;IACA,OAAO;GACT,GAAG;IAAC;IAAU;IAAM;IAAS;IAAU;IAAW;GAAY,CAAC;GAE/D,IAAI,CAAC,MAAM,QAAQ,QAAQ,MAAM,OAAO;GACxC,MAAM,cAAc,KAAK,OAAO,CAAC;GACjC,MAAM,cAAc,QAAQ,QAAQ;GACpC,MAAM,eAA6B,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY;IAAE;IAAM;GAAM,EAAE;GAE1G,QAAA,GAAA,UAAA,aAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWA,0BAAU;IAAS,cAAc,MAAM;KAAE,IAAI,EAAE,WAAW,EAAE,eAAe,QAAQ;IAAE;cACnG,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,0BAAU;KAAO,UAAU,MAAM,EAAE,gBAAgB;eAAnE;MACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,0BAAU;iBAA1B;QACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,0BAAU;mBAA1B,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,0BAAU;oBAAO;SAAY,CAAA,GAC9C,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UAAQ,MAAK;UAAS,WAAWA,0BAAU;UAAU,SAAS;UAAS,cAAW;oBAChF,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA;SAChB,CAAA,CACL;;QACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,0BAAU;mBAA1B;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,0BAAU;qBAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD,EAAY,MAAM,GAAK,CAAA;UAAO,CAAA;UACrE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WACE,WAAWA,0BAAU;WACrB,aAAY;WACZ,OAAO;WACP,WAAW,MAAM,UAAU,EAAE,OAAO,KAAK;WACzC,WAAA;UACD,CAAA;UACA,WAAW,MACV,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,MAAK;WAAS,WAAWA,0BAAU;WAAa,eAAe,UAAU,EAAE;WAAG,cAAW;qBAC/F,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA;UAChB,CAAA;SAEP;;QACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAWA,0BAAU;SAAU,OAAO;mBAAO;QAAU,CAAA;OACzD;;MAEL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,0BAAU;iBACvB,kBAAkB,OACjB,YACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,0BAAU;kBAAM;OAAS,CAAA,IACvC,cAAc,WAAW,IAC3B,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,0BAAU;kBAAM;OAAY,CAAA,IAE5C,cAAc,KAAK,QAAQ;QACzB,MAAM,QAAQ,SAAS,IAAI,IAAI,IAAI;QACnC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAEE,WAAW,GAAGA,0BAAU,MAAM,QAAQ,IAAIA,0BAAU,gBAAgB;SACpE,eAAe,aAAa,IAAI,MAAM,KAAK;mBAH7C;UAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,WAAWA,0BAAU,WAAa,CAAA;UACxC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,0BAAU;qBAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,MAAM,GAAK,CAAA;UAAO,CAAA;UAC7D,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;WAAM,WAAWA,0BAAU;WAAM,OAAO,IAAI;qBAA5C,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,IAAI,KAAW,CAAA,GACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;YAAM,WAAWA,0BAAU;sBAAU,IAAI;WAAW,CAAA,CAChD;;UACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WACE,WAAW,GAAGA,0BAAU,QAAQ,QAAQ,IAAIA,0BAAU,YAAY;WAClE,UAAU,MAAM;YACd,EAAE,gBAAgB;YAClB,aAAa,IAAI,MAAM,KAAK;WAC9B;qBAEC,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA,IAAI;UAC/B,CAAA;SACH;WAnBE,IAAI,IAmBN;OAET,CAAC,IAED,cACF,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,0BAAU;kBAAM;OAAS,CAAA,IACvC,YAAY,WAAW,IACzB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,0BAAU;kBAAM;OAAU,CAAA,IAE1C,YAAY,KAAK,UAAU,KAAK,OAAO,CAAC,CAAC;MAExC,CAAA;MAEL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,0BAAU;iBAA1B,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAWA,0BAAU;kBACvB,aAAa,WAAW,IACvB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,0BAAU;mBAAY;QAAkB,CAAA,IAEzD,aAAa,KAAK,SAChB,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;SAAsB,WAAWA,0BAAU;mBAA3C,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD,EAAA,UAAA;UAAM;UAAE,KAAK;UAAM,KAAK,QAAQ,MAAM;SAAS,EAAA,CAAA,GAC/C,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,0BAAU;UACrB,eAAe,aAAa,KAAK,MAAM,KAAK,KAAK;UACjD,cAAW;oBAEX,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAW,MAAM,GAAK,CAAA;SAChB,CAAA,CACJ;WAVK,KAAK,IAUV,CACP;OAEA,CAAA,GACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;QAAK,WAAWA,0BAAU;kBAA1B,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAWA,0BAAU;SAAW,SAAS;mBAAS;QAAU,CAAA,GAClF,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,0BAAU;SACrB,UAAU,aAAa,WAAW;SAClC,eAAe,SAAS,YAAY;mBAJtC,CAKC,MACI,aAAa,SAAS,IAAI,KAAK,aAAa,OAAO,KAAK,EACrD;UACL;SACF;;KACF;;GACF,CAAA,GACL,SAAS,IACX;EACF;;EAGA,SAAS,UAAU,EAAE,QAAuC;GAC1D,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,OAAO;IAAM,QAAQ;IAAM,SAAQ;IAAY,MAAK;IAAO,eAAY;cAC1E,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,GAAE;KAA2B,QAAO;KAAe,aAAY;KAAM,eAAc;KAAQ,gBAAe;IAAS,CAAA;GACtH,CAAA;EAET;;EAYA,SAAgB,cAAc,OAAe,OAAwD;GACnG,MAAM,SAAS,MAAM,MAAM,GAAG,KAAK;GACnC,MAAM,KAAK,OAAO,YAAY,GAAG;GACjC,IAAI,KAAK,GAAG,OAAO;GAEnB,IAAI,KAAK,KAAK,CAAC,wBAAwB,KAAK,OAAO,KAAK,EAAE,GAAG,OAAO;GACpE,OAAO;IAAE,OAAO;IAAI,OAAO,OAAO,MAAM,KAAK,CAAC;GAAE;EAClD;;;;;;;EAQA,SAAgB,eAAe,EAAE,KAAK,OAA2D;GAC/F,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAgC,WAAW,YAAY,CAAC;GACtE,CAAA,GAAA,MAAA,UAAA,OAAgB,WAAW,UAAU,QAAQ,GAAG,CAAC,CAAC;GAKlD,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,CAAC,MAAM,QAAQ,MAAM,QAAQ,MAAM;IACvC,IAAI;KACF,MAAM,OAAO,IAAI,SAAS,MAAM,MAAM,IAAI,SAAS;KACnD,IAAI,SAAS,KAAA,GAAW;KAIxB,IADG,IAAI,eACK,CAAC,EAAE,UAAU,IAAI,CAAC,CAAC,QAAQ;IACzC,QAAQ,CAER;GACF,GAAG;IAAC,MAAM;IAAM,MAAM;IAAK;GAAG,CAAC;GAG/B,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,0BAAU,IAAI,QAA6B;IACjD,MAAM,WAAW,MAAmB;KAClC,IAAI,WAAW,YAAY,CAAC,CAAC,MAAM;KACnC,MAAM,KAAK,EAAE;KACb,MAAM,QAAQ,GAAG,kBAAkB,GAAG,MAAM;KAC5C,MAAM,UAAU,cAAc,GAAG,OAAO,KAAK;KAC7C,IAAI,YAAY,QAAQ,QAAQ,UAAU,IAAI;KAC9C,MAAM,WAAW,IAAI,SAAS,KAAK,YAAY;KAC/C,MAAM,YAAY,SAAS;KAC3B,IAAI,cAAc,KAAA,GAAW;KAC7B,MAAM,MAAM,SAAS,KAAK,UAAU,EAAE;KACtC,MAAM,OAAO,OAAO,QAAQ,YAAY,QAAQ,KAAK,MAAM;KAC3D,IAAI,SAAS,IAAI;KACjB,WAAW,KAAK;MACd;MACA;MACA,YAAY;MACZ,MAAM;OAAE,OAAO,QAAQ;OAAO,KAAK,QAAQ,QAAQ;MAAE;KACvD,CAAC;IACH;IACA,MAAM,eAAqB;KACzB,KAAK,MAAM,MAAM,SAAS,iBAAsC,UAAU,GAAG;MAC3E,IAAI,QAAQ,IAAI,EAAE,GAAG;MACrB,QAAQ,IAAI,EAAE;MACd,GAAG,iBAAiB,SAAS,OAAO;KACtC;IACF;IACA,OAAO;IACP,MAAM,WAAW,IAAI,iBAAiB,MAAM;IAC5C,SAAS,QAAQ,SAAS,MAAM;KAAE,WAAW;KAAM,SAAS;IAAK,CAAC;IAClE,aAAa;KACX,SAAS,WAAW;KACpB,KAAK,MAAM,MAAM,SAAS,iBAAsC,UAAU,GACxE,GAAG,oBAAoB,SAAS,OAAO;IAE3C;GACF,GAAG,CAAC,GAAG,CAAC;;;;;;;;GASR,MAAM,SAAS,OAAO,UAAuC;IAC3D,MAAM,UAAU,WAAW,YAAY;IACvC,IAAI,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,MAAM,WAAW,GAAG;IACjE,MAAM,EAAE,WAAW,MAAM,SAAS,QAAQ;IAC1C,IAAI;KACF,MAAM,OAAO,IAAI,SAAS,MAAM,SAAS;KACzC,IAAI,SAAS,KAAA,GAAW;KACxB,MAAM,eAAgB,IAA0D;KAChF,IAAI,iBAAiB,KAAA,GAAW;KAChC,MAAM,QAAQ,aAAa,MAAM,IAAI,IAAI;KAGzC,MAAM,aAAa,MAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,SAAS;MAC7D,IAAI,KAAK,OAAO,OAAO;OAAE;OAAM,OAAO;MAAK;MAC3C,MAAM,SAAS,MAAM,IAAI,KAAK,MAAM,KAAK,MAAM,KAAK;MACpD,IAAI,CAAC,OAAO,IAAI,OAAO;OAAE;OAAM,OAAO;MAAK;MAC3C,MAAM,OAAO,OAAO,MAAM;MAC1B,MAAM,UAAU,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;MAE1D,OAAO;OAAE;OAAM,OADD,YAAY,KAAK,IAAI,QAAQ,MAAM,IAAI,CAAC,CAAC;MAClC;KACvB,CAAC,CAAC;KAIF,IAAI,SAAS,KAAK;KAClB,IAAI,YAAY;KAChB,KAAK,MAAM,EAAE,MAAM,WAAW,YAAY;MACxC,IAAI,KAAK,OAAO;OACd,cAAc,KAAK,WAAW,IAAI,KAAK,KAAK,GAAG;OAC/C;MACF;MACA,IAAI,UAAU,MAAM;MACpB,MAAM,OAAO,MAAM,MAAM,YAAY;MACrC,MAAM,cAAuB,YACzB;OAAE,OAAO,KAAK;OAAO,KAAK,KAAK;OAAK,UAAU,KAAK;MAAS,IAC5D;OAAE,OAAO;OAAQ,KAAK;OAAQ,UAAU,KAAK;MAAS;MAO1D,IANW,oBACT,KACA,WACA;OAAE,MAAM,KAAK;OAAM,WAAW;OAAG,SAAS;MAAM,GAChD,WAEG,GAAG;OACN,YAAY;OAGZ,UAAU;MACZ;KACF;KACA,WAAW,MAAM;IACnB,SAAS,OAAO;KACd,QAAQ,KAAK,uCAAuC,KAAK;IAC3D;GACF;;GAGA,MAAM,cAAoB;IACxB,MAAM,UAAU,WAAW,YAAY;IACvC,IAAI,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;KACxC,MAAM,EAAE,WAAW,SAAS,QAAQ;KACpC,IAAI;MACF,MAAM,OAAO,IAAI,SAAS,MAAM,SAAS;MACzC,MAAM,eAAgB,IAA0D;MAChF,IAAI,SAAS,KAAA,KAAa,iBAAiB,KAAA,GAAW;OACpD,MAAM,QAAQ,aAAa,MAAM,IAAI,IAAI;OACzC,MAAM,QAAQ,MAAM,MAAM,YAAY,CAAC,CAAC;OAExC,IADc,MAAM,MAAM,KAAK,OAAO,KAAK,GACnC,CAAC,CAAC,WAAW,GAAG,GACtB,MAAM,SAAS,MAAM,MAAM,GAAG,KAAK,KAAK,IAAI,MAAM,MAAM,KAAK,GAAG,CAAC;MAErE;KACF,QAAQ,CAER;IACF;IACA,WAAW,MAAM;GACnB;GAEA,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAD;IAAwB;IAAY;IAAK,UAAU;IAAQ,SAAS;GAAQ,CAAA;EACrF;;;;ECveA,MAAM,iBAAiB;;EAGvB,SAAS,iBAAiB,OAAuB;GAC/C,OAAO,MAAM,QAAQ,OAAO,GAAG;EACjC;;;;;;;;EASA,SAAgB,aAAa,MAAc,MAA6B;GACtE,MAAM,MAAM,KAAK,KAAK;GACtB,IAAI,QAAQ,MAAM,IAAI,SAAS,gBAAgB,OAAO;GACtD,IAAI,SAAS,KAAK,GAAG,GAAG,OAAO;GAC/B,IAAI,IAAI,SAAS,KAAK,GAAG,OAAO;GAChC,MAAM,aAAa,iBAAiB,GAAG;GACvC,MAAM,WAAW,iBAAiB,IAAI,CAAC,CAAC,QAAQ,QAAQ,EAAE;GAC1D,IAAI,aAAa,IAAI,OAAO;GAK5B,IAAI,WAAW,WAAW,GAAG,GAAG;IAC9B,IAAI,eAAe,UAAU,OAAO;IACpC,IAAI,CAAC,WAAW,WAAW,WAAW,GAAG,GAAG,OAAO;IACnD,MAAM,MAAM,WAAW,MAAM,SAAS,MAAM,CAAC,CAAC,QAAQ,QAAQ,EAAE;IAChE,OAAO,cAAc,GAAG,IAAI,MAAM;GACpC;GACA,IAAI,aAAa,KAAK,UAAU,GAAG;IACjC,MAAM,QAAQ,WAAW,YAAY;IACrC,MAAM,YAAY,SAAS,YAAY;IACvC,IAAI,UAAU,WAAW,OAAO;IAChC,IAAI,CAAC,MAAM,WAAW,YAAY,GAAG,GAAG,OAAO;IAC/C,MAAM,MAAM,WAAW,MAAM,SAAS,MAAM,CAAC,CAAC,QAAQ,QAAQ,EAAE;IAChE,OAAO,cAAc,GAAG,IAAI,MAAM;GACpC;GAGA,MAAM,MAAM,WAAW,WAAW,IAAI,IAAI,WAAW,MAAM,CAAC,IAAI;GAChE,OAAO,cAAc,GAAG,IAAI,MAAM;EACpC;;EAGA,SAAS,cAAc,KAAsB;GAC3C,IAAI,QAAQ,MAAM,IAAI,SAAS,gBAAgB,OAAO;GACtD,IAAI,KAAK,KAAK,GAAG,GAAG,OAAO;GAC3B,MAAM,WAAW,IAAI,MAAM,GAAG;GAC9B,IAAI,SAAS,SAAS,GAGpB,OAAO,iBAAiB,KAAK,GAAG;GAElC,KAAK,MAAM,WAAW,UACpB,IAAI,YAAY,MAAM,YAAY,OAAO,YAAY,MAAM,OAAO;GAEpE,OAAO;EACT;;EAGA,SAAgB,eAAe,QAAgD;GAC7E,IAAI,EAAE,kBAAkB,UAAU,OAAO;GACzC,MAAM,OAAO,OAAO,QAAQ,MAAM;GAClC,IAAI,SAAS,MAAM,OAAO;GAG1B,IAAI,KAAK,QAAQ,GAAG,MAAM,MAAM,OAAO;GACvC,IAAI,KAAK,QAAQ,eAAe,MAAM,MAAM,OAAO;GACnD,IAAI,KAAK,QAAQ,yDAAyD,MAAM,MAAM,OAAO;GAC7F,OAAO;EACT;;;;;;;;EASA,eAAsB,cAAc,QAAqB,KAAe,KAA4B;GAClG,MAAM,WAAW,OAAO;GACxB,SAAS,aAAa,OAAO;GAC7B,IAAI,QAAQ,IAAI,SAAS,OAAO,GAAG;GAEnC,MAAM,OAAO,OAAO,OAAO,YAAY,CAAC,CAAC;GACzC,IAAI,SAAS,MAAM,QAAQ,IAAI;GAE/B,MAAM,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;GACrC,MAAM,SAAS,UAAU,GAAG;GAC5B,IAAI,QAAQ,SAAS,YAAY,CAAC,CAAC,KAAK,OAAO,EAAE,MAAM,SAAS,KAAK,SAAS,IAAI;GAClF,IAAI,UAAU,KAAA,GAAW;IACvB,MAAM,SAAS,MAAM,IAAI,KAAK,MAAM,MAAM;IAC1C,IAAI,OAAO,IAAI,QAAQ,OAAO,MAAM,QAAQ,MAAM,SAAS,KAAK,SAAS,IAAI;GAC/E;GAGA,IAAI,UAAU,KAAA,KAAa,CAAC,MAAM,OAChC,OAAO,QAAQ,SAAS,MAAM,GAAG;EAErC;;EAGA,SAAgB,mBAAmB,QAAqB,KAAe,OAAyB;GAC9F,IAAI,MAAM,oBAAoB,MAAM,WAAW,GAAG;GAClD,MAAM,OAAO,eAAe,MAAM,MAAM;GACxC,IAAI,SAAS,MAAM;GACnB,MAAM,OAAO,OAAO,OAAO,YAAY,CAAC,CAAC;GACzC,IAAI,SAAS,IAAI;GACjB,MAAM,MAAM,aAAa,KAAK,eAAe,IAAI,IAAI;GACrD,IAAI,QAAQ,MAAM;GAIlB,IADe,OAAO,OAAO,YACpB,CAAC,CAAC,mBAAmB;IAC5B,OAAO,OAAO,QAAQ,UAAU;KAAE,GAAG;KAAM,mBAAmB;IAAM,EAAE;IACtE,IAAI;KACF,aAAa,QAAQ,0BAA0B,QAAQ,UAAU;IACnE,QAAQ,CAER;GACF;GACA,cAAmB,QAAQ,KAAK,GAAG;EACrC;;;;ECzHA,MAAa,mBAAmB;;;;;;EAUhC,SAAgB,4BAA4B,KAAgC;GAI1E,MAAM,gBAAiB,IAAI,IAAkC,eAAe;GAG5E,IAAI,kBAAkB,KAAA,GAAW,aAAa,CAAC;GAC/C,MAAM,SAA6B;IACjC,SAAS;IACT,MAAM;IACN,YAAY,YAAY,CAAC;IACzB,cAAc,KAAA;IACd,OAAO;KACL,gBAAgB,QAAQ;KACxB,YAAY,KAAK,YAAY,QAAQ,QAAQ,GAAG;IAClD;GACF;GACA,IAAI;IACF,OAAO,cAAc,eAAe,MAAM;GAC5C,SAAS,OAAO;IAEd,QAAQ,KAAK,2DAA2D,KAAK;IAC7E,aAAa,CAAC;GAChB;EACF;;;;;;;;;;;;;;EChDA,MAAM,WAAW;EAEjB,SAAS,cAAoB;GAC3B,IAAI,OAAO,aAAa,aAAa;GACrC,IAAI,SAAS,eAAe,QAAQ,MAAM,MAAM;GAChD,MAAM,MAAM,SAAS,cAAc,OAAO;GAC1C,IAAI,KAAK;GACT,IAAI,cAAc;GAClB,SAAS,KAAK,YAAY,GAAG;EAC/B;EAEA,YAAY;EAEZ,SAAgB,SAAS,OAKR;GACf,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;IACE,MAAK;IACL,WAAW,gBAAgB,MAAM,SAAS,0BAA0B;IACpE,SAAS,MAAM;IACf,cAAY,MAAM;IAClB,gBAAc,MAAM;IACpB,OAAO,MAAM;cANf,CAQE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;eAAoB,MAAM;IAAY,CAAA,GACrD,MAAM,QACD;;EAEZ;;;;;;;;;;;;;;;;ECzBA,MAAM,KAAK;GACT,YAAY;GACZ,WAAW;EACb;EAEA,SAAgB,oBAAkC;GAChD,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,KAAK;GAC1C,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,WAAW,MAAmB,UAAU,QAAS,EAAkB,MAAM,CAAC;IAChF,OAAO,iBAAiB,GAAG,WAAW,OAAO;IAC7C,aAAa,OAAO,oBAAoB,GAAG,WAAW,OAAO;GAC/D,GAAG,CAAC,CAAC;GACL,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IACU;IACR,OAAM;IACN,eAAe,OAAO,cAAc,IAAI,YAAY,GAAG,UAAU,CAAC;cAElE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,OAAM;KAAK,QAAO;KAAK,SAAQ;KAAY,MAAK;KAAO,QAAO;KAAe,aAAY;KAAI,eAAc;KAAQ,gBAAe;eACrI,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,2LAA4L,CAAA;IACjM,CAAA;GACG,CAAA;EAEd;;;;;;;;;;;;;;;;;;ECqCA,MAAa,SAAS;GAAC;GAAY;GAAU;GAAiB;EAAc;;EAG5E,MAAM,WAAW,IAAI,SAAS;;EAG9B,SAAgB,MAAM,KAA0B;GAK9C,IAAI,OAAO,CAAC,OAAO,IAAI,UAAyB;IAC9C,MAAM,MAAM,OAAO,+CACjB,MAAM,MAAM,SAAS;KACnB,MAAM;KACN,IAAI;KACJ,OAAO;KACP,eAAe,CAAC;IAClB,GAAG,iBAAiB,CAAC;GACzB,CAAC;GAED,IAAI,aAAa,IAAI,OAAO,SAAS,IAAI,YAAY,GAAG,2BAA2B;GAMnF,IAAI,aAAa,4BAA4B,GAAG,GAAG,oCAAoC;GAavF,IAAI,OAAO;IAAC;IAAS;IAAgB;GAAU,IAAI,UAAyB;IAC1E,MAAM,WAAW,MAAM;IACvB,MAAM,eAAe,MAAM;IAC3B,MAAM,MAAM,OAAO,iCACjB,MAAM,MAAM,SAAS;KACnB,MAAM;KACN,IAAI;KACJ,OAAO;KACP,QAAQ;KACR,SAAS,eAAwD,EAC/D,aAAa,SAA0B;MACrC,IAAI,cAAc,KAAA,GAAW,OAAO;MACpC,MAAM,OAAO,SAAS,MAAM,SAAS;MACrC,IAAI,SAAS,KAAA,GAAW,OAAO;MAC/B,MAAM,QAAQ,aAAa;MAC3B,IAAI,UAAU,KAAA,GAAW,OAAO;MAChC,MAAM,QAAQ,MAAM,IAAI,IAAI;MAC5B,MAAM,QAAQ,MAAM,MAAM,YAAY,CAAC,CAAC;MACxC,MAAM,SAAS,oBAAoB,OAAO,IAAI,CAAC;MAC/C,OAAO;KACT,EACF;IACF,GAAG,aAAa,CAAC;GACrB,CAAC;GAKD,IAAI,OAAO,CAAC,OAAO,IAAI,UAAyB;IAC9C,MAAM,MAAM,OAAO,iCACjB,MAAM,MAAM,SAAS;KACnB,MAAM;KACN,IAAI;KACJ,OAAO;IACT,GAAG,mBAAmB,CAAC;GAC3B,CAAC;GAMD,IAAI,OAAO,CAAC,OAAO,IAAI,UAAyB;IAC9C,MAAM,MAAM,OAAO,iCACjB,MAAM,MAAM,SAAS;KACnB,MAAM;KACN,IAAI;KACJ,OAAO;IACT,GAAG,eAAe,CAAC;GACvB,CAAC;GAKD,IAAI,OAAO,CAAC,SAAS,eAAe,IAAI,gBAA+B;IAGrE,MAAM,eAAe,IAAI,mCAFV,YAAY,IAAI,eAAe,KAAK,YAAY,cAAA,CACrC,KAA+B,EAAE,WAAW,GAAG,CACL,CAAC;IACrE,YAAY,MAAM,OAAO,4BAA4B;KACnD,MAAM,aAAa,YAAY,MAAM,SAAS;MAC5C,MAAM;MACN,IAAI;MACJ,OAAO;MACP,QAAQ;MACR,cAAc,aAAa,OAAO;KACpC,GAAG,uBAAuB;KAC1B,aAAa;MACX,aAAa,QAAQ;MACrB,WAAW;KACb;IACF,CAAC;GACH,CAAC;GAED,IAAI,aAAa;IAKf,IAAI;IACJ,IAAI;KACF,MAAM,SAAS,IAAI,IAAI,eAAe,KAAK,IAAI;KAC/C,IAAI,WAAW,KAAA,GAAW,aAAa,OAAO,KAA+B,EAAE,WAAW,GAAG,CAAC;IAChG,SAAS,OAAO;KAEd,aAAa,KAAA;IACf;IACA,MAAM,gBAAyB,YAAY,YAAY,CAAC,CAAC,OAAO,WAAW;IAC3E,IAAI;;;;;;;IAQJ,MAAM,gBAA8B;KAClC,MAAM,SAAS,kBAAkB,QAAQ;KACzC,MAAM,SAAS,IAAI,sBAAsB,OAAO,MAAM;KACtD,MAAM,YAA+B,CAAC;KACtC,IAAI;KACJ,IAAI,cAAc;KAClB,IAAI,kBAAkB;KAMtB,MAAM,eAAe,MAAc,UAAyB;MAC1D,MAAM,YAAY,IAAI,SAAS,KAAK,YAAY,CAAC,CAAC;MAClD,IAAI,cAAc,KAAA,GAAW;OAC3B,QAAQ,KAAK,+BAA+B;OAC5C;MACF;MACA,IAAI,OAAO;OACT,cAAc,KAAK,WAAW,IAAI,KAAK,GAAG;OAC1C;MACF;MACA,SAAc,KAAK,aAAa,MAAM,KAAK,CAAC,CAAC,MAAM,WAAW;OAC5D,IAAI,CAAC,OAAO,IAAI;QACd,cAAc,KAAK,WAAW,IAAI,KAAK,EAAE;QACzC;OACF;OACA,MAAM,OAAO,OAAO,MAAM;OAC1B,MAAM,UAAU,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;OAC1D,MAAM,QAAQ,YAAY,KAAK,IAAI,QAAQ,MAAM,IAAI,CAAC,CAAC;OACvD,wBAAwB,KAAK,WAAW;QAAE;QAAM,WAAW;QAAG,SAAS;OAAM,CAAC;MAChF,CAAC;KACH;KAIA,MAAM,sBAAsB,cAA+C;MACzE,MAAM,YAAY,IAAI,SAAS,KAAK,YAAY,CAAC,CAAC;MAClD,OAAO,wBAAwB,KAAK,WAAW,SAAS;KAC1D;KAIA,MAAM,iBAAuB;MAC3B,MAAM,WAAW,IAAI,SAAS,KAAK,YAAY;MAC/C,MAAM,YAAY,SAAS;MAC3B,MAAM,MAAM,cAAc,KAAA,IAAY,KAAA,IAAY,SAAS,KAAK,UAAU,EAAE;MAC5E,MAAM,OAAO,OAAO,QAAQ,YAAY,QAAQ,KAAK,MAAM;MAC3D,IAAI,SAAS,aAAa;MAC1B,cAAc;MAMd,mBAAmB;MACnB,mBAAmB,KAAA;MACnB,MAAM,cAAc,OAAO,QAAQ,YAAY,CAAC,CAAC;MACjD,kBAAkB;MAClB,cAAc,OAAO,QAAQ,MAAM,WAAW;MAC9C,OAAO,SAAS,QAAQ,IAAI;MAC5B,OAAO,IAAI,QAAQ,IAAI;MACvB,OAAO,QAAQ,QAAQ,IAAI;MAE3B,oBAAoB;KACtB;;;;;;;;;KAUA,MAAM,4BAAkC;MACtC,MAAM,OAAO;MACb,MAAM,OAAO,SAAS,MAAM,OAAO,SAAS,YAAY,CAAC,CAAC,cAAc;MACxE,IAAI,QAAQ,qBAAqB,KAAA,GAAW;OAC1C,OAAY,IAAI,QAAQ;OACxB,mBAAmB,qBAAqB,OAAO,UAAU;QACvD,IAAI,MAAM,SAAS,OAAO;SAExB,OAAO,IAAI,QAAQ,SAAU,KAAK,SAAS,OAAO,OAAO;UAAE,GAAG;UAAM,QAAQ,MAAM;UAAQ,SAAS;SAAM,CAAE;SAE3G,OAAY,QAAQ,gBAAgB,IAAI;QAC1C;QACA,IAAI,MAAM,SAAS,kBAGjB,OAAO,IAAI,QAAQ,SAAU,KAAK,SAAS,OAAO,OAAO;SAAE,GAAG;SAAM,QAAQ;SAAM,SAAS;SAAO,YAAY;QAAK,CAAE;OAEzH,CAAC;MACH,OAAO,IAAI,CAAC,QAAQ,qBAAqB,KAAA,GAAW;OAClD,iBAAiB;OACjB,mBAAmB,KAAA;MACrB;KACF;KACA,UAAU,KAAK,IAAI,SAAS,KAAK,UAAU,QAAQ,CAAC;KACpD,UAAU,KAAK,OAAO,SAAS,UAAU,mBAAmB,CAAC;KAC7D,SAAS;KAMT,MAAM,qBAA2B,OAAO,eAAe;KACvD,OAAO,iBAAiB,6BAA6B,YAAY;KACjE,MAAM,iBAAiB,OAAO,OAAO,gBAAgB;MACnD,OAAO,cAAc,IAAI,YAAY,4BAA4B,EAC/D,QAAQ,CAAC,OAAO,OAAO,YAAY,CAAC,CAAC,kBACvC,CAAC,CAAC;KACJ,CAAC;KACD,OAAO,cAAc,IAAI,YAAY,4BAA4B,EAC/D,QAAQ,CAAC,OAAO,OAAO,YAAY,CAAC,CAAC,kBACvC,CAAC,CAAC;KAIF,MAAM,0BAAgC;MACpC,MAAM,OAAO,OAAO,QAAQ,YAAY,CAAC,CAAC;MAC1C,IAAI,SAAS,iBAAiB;MAC9B,kBAAkB;MAClB,OAAO,OAAO,QAAQ,UAAU;OAAE,GAAG;OAAM,aAAa;MAAK,EAAE;MAC/D,IAAI,MAAM;OACR,MAAM,MAAM,SAAS,cAA2B,4BAA4B;OAC5E,KAAK,UAAU,IAAI,uBAAuB;OAC1C,iBAAiB,KAAK,UAAU,OAAO,uBAAuB,GAAG,GAAG;MACtE;KACF;KACA,UAAU,KAAK,OAAO,QAAQ,UAAU,iBAAiB,CAAC;KAG1D,IAAI;KACJ,MAAM,qBAA2B;MAC/B,YAAY,SAAS,gBAAgB,MAAM,WAAW,IAAI,IAAI,OAAO,IAAI;KAC3E;KACA,eAAe,IAAI,iBAAiB,YAAY;KAChD,aAAa,QAAQ,SAAS,iBAAiB;MAAE,YAAY;MAAM,iBAAiB,CAAC,MAAM;KAAE,CAAC;KAC9F,aAAa;KAGb,IAAI;MACF,OAAO,MAAM;MACb,YAAY,cAAc,OAAO,eAAe,GAAG,aAAa,kBAAkB;KACpF,SAAS,OAAO;MACd,QAAQ,MAAM,+BAA+B,KAAK;KACpD;KAIA,MAAM,eAAe,SAAS,cAAc,KAAK;KACjD,SAAS,KAAK,YAAY,YAAY;KACtC,MAAM,cAAA,GAAA,iBAAA,WAAA,CAAwB,YAAY;KAC1C,WAAW,QAAA,GAAA,MAAA,cAAA,CAAqB,gBAAgB;MAAE;MAAK,KAAK;KAAS,CAAC,CAAC;KAIvE,MAAM,kBAAkB,UAA4B;MAClD,IAAI;OACF,mBAAmB,QAAQ,UAAU,KAAK;MAC5C,SAAS,OAAO;OAEd,QAAQ,MAAM,yCAAyC,KAAK;MAC9D;KACF;KACA,SAAS,iBAAiB,SAAS,cAAc;KAIjD,MAAM,oBAA0B,OAAO,SAAS;KAChD,MAAM,2BAAiC;MACrC,IAAI,SAAS,oBAAoB,UAAU,YAAY;KACzD;KACA,OAAO,iBAAiB,YAAY,WAAW;KAC/C,SAAS,iBAAiB,oBAAoB,kBAAkB;KAEhE,aAAa;MACX,YAAY;MACZ,OAAO,oBAAoB,YAAY,WAAW;MAClD,OAAO,oBAAoB,6BAA6B,YAAY;MACpE,eAAe;MACf,SAAS,oBAAoB,oBAAoB,kBAAkB;MACnE,SAAS,oBAAoB,SAAS,cAAc;MACpD,mBAAmB;MACnB,cAAc,WAAW;MACzB,WAAW,QAAQ;MACnB,aAAa,OAAO;MACpB,KAAK,MAAM,WAAW,WAAW,QAAQ;MACzC,OAAO,QAAQ;KACjB;IACF;IACA,MAAM,eAAqB;KACzB,IAAI,QAAQ,KAAK,cAAc,KAAA,GAC7B,YAAY,QAAQ;UACf,IAAI,CAAC,QAAQ,KAAK,cAAc,KAAA,GAAW;MAChD,UAAU;MACV,YAAY,KAAA;KACd;IACF;IACA,OAAO;IACP,MAAM,sBAAsB,YAAY,UAAU,MAAM;IACxD,aAAa;KACX,sBAAsB;KACtB,IAAI,cAAc,KAAA,GAAW;MAC3B,UAAU;MACV,YAAY,KAAA;KACd;IACF;GACF,GAAG,qBAAqB;EAC1B"}