envprism 0.1.0-dev.8-eaeab9f → 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.
@@ -1 +0,0 @@
1
- {"version":3,"file":"app-d_wGTwvJ.mjs","sources":["../../src/tui/app.ts"],"sourcesContent":["import {\n BoxRenderable,\n type CliRenderer,\n createCliRenderer,\n RGBA,\n ScrollBoxRenderable,\n TextRenderable\n} from '@opentui/core';\nimport { writeFile } from 'node:fs/promises';\nimport { basename, dirname, join } from 'pathe';\nimport { isSecretKey, maskValue } from '../core/mask.ts';\nimport { buildMatrix, type CellState, type Matrix } from '../core/matrix.ts';\nimport { rebuildKvLine, serializeEnv } from '../core/serialize.ts';\nimport type { EnvFile, KvEntry } from '../core/types.ts';\n\ntype Mode = 'browse' | 'filter' | 'prompt';\n\ntype Prompt =\n | { kind: 'edit'; key: string; file: EnvFile }\n | { kind: 'add-key'; file: EnvFile }\n | { kind: 'add-value'; key: string; file: EnvFile }\n | { kind: 'new-file' };\n\ntype Grouping = 'banner' | 'prefix';\n\ntype UndoEntry =\n | {\n kind: 'edit';\n file: EnvFile;\n entry: KvEntry;\n prevValue: string;\n prevRaw: string;\n }\n | { kind: 'add-kv'; file: EnvFile; entry: KvEntry }\n | { kind: 'delete-kv'; file: EnvFile; entry: KvEntry; idx: number };\n\nconst UNDO_LIMIT = 50;\n\ntype Pane = 'matrix' | 'sidebar';\n\ntype ItemKind = 'key' | 'divider';\ninterface MatrixItem {\n kind: ItemKind;\n // For 'key': the variable name; for 'divider': the section's lookup name\n // (or '__other__'). Holding the raw key/section here keeps focus stable\n // across rebuilds.\n ref: string;\n}\n\ninterface State {\n mode: Mode;\n filter: string;\n rowIdx: number;\n colIdx: number;\n prompt: Prompt | null;\n dirty: Set<EnvFile>;\n visibleKeys: string[]; // kept for callers that just want the keys\n visibleItems: MatrixItem[];\n message: string | null;\n driftOnly: boolean;\n confirmQuit: boolean;\n grouping: Grouping;\n helpOpen: boolean;\n undo: UndoEntry[];\n pane: Pane;\n sidebarIdx: number;\n enabled: Set<EnvFile>;\n showSecrets: boolean;\n collapsed: Set<string>;\n // (key + \"|\" + file.path) of cells the user has touched in this session.\n // Drives a green ● marker so unsaved local changes are visually distinct\n // from \"this file disagrees with base\", which uses the diff icons.\n modified: Set<string>;\n // Current value of the prompt input. We accumulate characters ourselves\n // in the global key handler instead of relying on opentui's InputRenderable,\n // because the InputRenderable swallows Esc (it interprets it as \"blur\").\n promptInput: string;\n}\n\n// Three semantic colours only. Everything else is grayscale so the eye\n// doesn't get pulled in five directions.\nconst COLORS = {\n fg: RGBA.fromHex('#cccccc'),\n fgDim: RGBA.fromHex('#666666'),\n fgHeader: RGBA.fromHex('#ffffff'),\n // accent — base file + section names (blue/purple, single accent for\n // navigational anchors).\n fgBase: RGBA.fromHex('#82aaff'),\n fgSection: RGBA.fromHex('#82aaff'),\n // drift/extra/placeholder — same yellow. They describe disagreement with\n // the base file, all one semantic.\n differs: RGBA.fromHex('#ffd866'),\n extra: RGBA.fromHex('#ffd866'),\n placeholder: RGBA.fromHex('#ffd866'),\n // user-made changes (modified cells, dirty files, unsaved counter) — green.\n // Different colour from drift on purpose: \"I just touched this\" is a\n // different signal from \"this disagrees with the base\".\n modified: RGBA.fromHex('#7fce6a'),\n fgDirty: RGBA.fromHex('#7fce6a'),\n // problem — value-is-missing red. Reserved exclusively for missing.\n missing: RGBA.fromHex('#ff6b6b'),\n focusBg: RGBA.fromHex('#3a3f4b')\n};\n\nconst PLACEHOLDER_RE =\n /^(todo|fixme|changeme|placeholder|tbd|x{3,}|your[_-]?(secret|key|token|password|api[_-]?key)(_here)?|replace[_-]?me)$/i;\n\nfunction isPlaceholderValue(value: string): boolean {\n const v = value.trim();\n if (v.length === 0) return false;\n return PLACEHOLDER_RE.test(v);\n}\n\nconst KEY_COL_WIDTH = 22;\nconst VALUE_COL_MIN = 18;\nconst SIDEBAR_WIDTH = 30;\nconst ROW_GAP = 0;\nconst CELL_PAD_X = 1;\nconst KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\ntype HelpLine =\n | { kind: 'header'; text: string }\n | { kind: 'entry'; text: string }\n | { kind: 'legend'; symbol: string; color: RGBA; description: string }\n | { kind: 'blank' };\n\nfunction buildHelpLines(): HelpLine[] {\n return [\n { kind: 'header', text: 'Panes' },\n {\n kind: 'entry',\n text: ' Tab Switch matrix ↔ files sidebar'\n },\n {\n kind: 'entry',\n text: ' ← (leftmost col) Hop from matrix into the sidebar'\n },\n { kind: 'blank' },\n { kind: 'header', text: 'Matrix navigation' },\n { kind: 'entry', text: ' ↑ ↓ ← → Move focused cell' },\n { kind: 'entry', text: ' Mouse wheel Scroll (both axes)' },\n { kind: 'blank' },\n { kind: 'header', text: 'Files sidebar' },\n { kind: 'entry', text: ' ↑ ↓ Move selection' },\n { kind: 'entry', text: ' Space Enable / disable file' },\n { kind: 'entry', text: ' b Make selected file the base' },\n { kind: 'entry', text: ' Tab / → Back to matrix' },\n { kind: 'blank' },\n { kind: 'header', text: 'Editing' },\n { kind: 'entry', text: ' e / Enter Edit focused cell value' },\n { kind: 'entry', text: ' a Add a new variable here' },\n {\n kind: 'entry',\n text: ' d Delete the variable from this file'\n },\n { kind: 'entry', text: ' n Create a new .env* file' },\n {\n kind: 'entry',\n text: ' = Sync focused value to every file'\n },\n {\n kind: 'entry',\n text: ' Ctrl-A (in edit) Apply typed value to every file'\n },\n { kind: 'entry', text: ' Ctrl-Z Undo last edit/add/delete' },\n { kind: 'entry', text: ' Ctrl-S Write all dirty files' },\n {\n kind: 'entry',\n text: ' c Collapse / expand focused section'\n },\n {\n kind: 'entry',\n text: ' Shift-C Expand every collapsed section'\n },\n { kind: 'blank' },\n { kind: 'header', text: 'View' },\n { kind: 'entry', text: ' / Filter keys' },\n { kind: 'entry', text: ' v All keys ↔ drift-only' },\n { kind: 'entry', text: ' g Group by prefix ↔ banner' },\n { kind: 'entry', text: ' Ctrl-T Show / mask secret values' },\n { kind: 'blank' },\n { kind: 'header', text: 'Help & exit' },\n { kind: 'entry', text: ' ? / ß Toggle this overlay' },\n { kind: 'entry', text: ' q Quit (twice if dirty)' },\n { kind: 'entry', text: ' Ctrl-C Force quit' },\n { kind: 'blank' },\n { kind: 'header', text: 'Cell icons' },\n {\n kind: 'legend',\n symbol: '≠ value',\n color: RGBA.fromHex('#ffd866'),\n description: 'value differs from base'\n },\n {\n kind: 'legend',\n symbol: '✗ missing',\n color: RGBA.fromHex('#ff6b6b'),\n description: 'this file has no value for the key'\n },\n {\n kind: 'legend',\n symbol: '★ value',\n color: RGBA.fromHex('#ffd866'),\n description: 'key is not in the base'\n },\n {\n kind: 'legend',\n symbol: '•••• (N)',\n color: RGBA.fromHex('#cccccc'),\n description: 'secret-suspect value masked by length'\n },\n {\n kind: 'legend',\n symbol: '⚠ TODO',\n color: RGBA.fromHex('#ffd866'),\n description: 'placeholder value (TODO, CHANGEME, xxx, …)'\n },\n {\n kind: 'legend',\n symbol: 'value ●',\n color: RGBA.fromHex('#7fce6a'),\n description: 'modified in this session — Ctrl-S to persist'\n }\n ];\n}\n\nexport async function runMatrixTui(initialMatrix: Matrix): Promise<void> {\n const renderer = await createCliRenderer({ useMouse: true });\n // The full discovered file list never changes; the matrix is rebuilt from\n // the currently *enabled* subset whenever the user toggles a file.\n const allFiles = initialMatrix.files.slice();\n let currentBase = initialMatrix.base;\n let matrix = initialMatrix;\n\n // Prefer banner grouping when the base file actually has section banners;\n // otherwise prefix grouping is more useful out of the box.\n const hasBanners = initialMatrix.keys.some(\n (k) => initialMatrix.sectionOf(k) !== undefined\n );\n const state: State = {\n mode: 'browse',\n filter: '',\n rowIdx: 0,\n colIdx: 0,\n prompt: null,\n dirty: new Set(),\n visibleKeys: matrix.keys.slice(),\n visibleItems: [],\n message: null,\n driftOnly: false,\n confirmQuit: false,\n grouping: hasBanners ? 'banner' : 'prefix',\n helpOpen: false,\n undo: [],\n pane: 'matrix',\n sidebarIdx: 0,\n enabled: new Set(allFiles),\n showSecrets: false,\n collapsed: new Set(),\n modified: new Set(),\n promptInput: ''\n };\n\n const cellKey = (key: string, file: EnvFile) => `${key}|${file.path}`;\n const markModified = (key: string, file: EnvFile) =>\n state.modified.add(cellKey(key, file));\n\n const SECTION_COLLAPSE_KEY = (name: string | undefined) =>\n name ?? '__other__';\n\n const pushUndo = (entry: UndoEntry) => {\n state.undo.push(entry);\n if (state.undo.length > UNDO_LIMIT) state.undo.shift();\n };\n\n // --- Layout ---\n const root = new BoxRenderable(renderer, {\n id: 'root',\n flexDirection: 'column',\n width: '100%',\n height: '100%'\n });\n renderer.root.add(root);\n\n const body = new BoxRenderable(renderer, {\n id: 'body',\n flexDirection: 'row',\n flexGrow: 1\n });\n root.add(body);\n\n const sidebar = new BoxRenderable(renderer, {\n id: 'sidebar',\n border: true,\n borderStyle: 'rounded',\n title: '',\n flexDirection: 'column',\n width: SIDEBAR_WIDTH,\n flexShrink: 0,\n paddingX: 1\n });\n body.add(sidebar);\n\n const matrixBox = new BoxRenderable(renderer, {\n id: 'matrix',\n border: true,\n borderStyle: 'rounded',\n title: '',\n flexDirection: 'column',\n flexGrow: 1,\n paddingX: 1,\n // Reserve a row at the bottom so the ScrollBox's horizontal scrollbar\n // does not overlap the matrix box's bottom border.\n paddingBottom: 1\n });\n body.add(matrixBox);\n\n // Header sits above the scrollable region so it doesn't scroll out of view.\n const headerHost = new BoxRenderable(renderer, {\n id: 'header-host',\n flexDirection: 'column',\n flexShrink: 0,\n // Match the ScrollBox viewport padding so the header column boundaries\n // line up with the data rows below.\n paddingRight: 1\n });\n matrixBox.add(headerHost);\n\n const scrollBox = new ScrollBoxRenderable(renderer, {\n id: 'matrix-scroll',\n flexGrow: 1,\n scrollX: true,\n scrollY: true,\n // Reserve a column on the right so the vertical scrollbar doesn't sit on\n // top of cell content, and a row at the bottom for the horizontal one.\n viewportOptions: { paddingRight: 1, paddingBottom: 1 },\n contentOptions: { flexDirection: 'column', rowGap: ROW_GAP }\n });\n matrixBox.add(scrollBox);\n\n const footer = new BoxRenderable(renderer, {\n id: 'footer',\n flexDirection: 'column',\n flexShrink: 0,\n paddingX: 1\n });\n root.add(footer);\n\n const hintA = new BoxRenderable(renderer, {\n id: 'hint-a',\n flexDirection: 'row',\n height: 1,\n flexShrink: 0\n });\n footer.add(hintA);\n\n const hintB = new BoxRenderable(renderer, {\n id: 'hint-b',\n flexDirection: 'row',\n height: 1,\n flexShrink: 0\n });\n footer.add(hintB);\n\n const status = new TextRenderable(renderer, {\n id: 'status',\n content: '',\n fg: COLORS.fgDim,\n wrapMode: 'none',\n height: 1\n });\n footer.add(status);\n\n // Filter has its own popover so we don't fight opentui's input-focus\n // behaviour. state.filter is the source of truth; characters are\n // accumulated by the global keypress handler when state.mode === 'filter'.\n const filterBox = new BoxRenderable(renderer, {\n id: 'filter-box',\n position: 'absolute',\n top: '15%',\n left: '20%',\n right: '20%',\n height: 'auto',\n zIndex: 60,\n border: true,\n borderStyle: 'rounded',\n title: ' Filter keys ',\n paddingX: 2,\n paddingY: 1,\n visible: false,\n backgroundColor: RGBA.fromHex('#1a1a1a'),\n flexDirection: 'column'\n });\n const filterField = new TextRenderable(renderer, {\n id: 'filter-field',\n content: '',\n fg: COLORS.fg,\n height: 1,\n wrapMode: 'none'\n });\n const filterStatus = new TextRenderable(renderer, {\n id: 'filter-status',\n content: '',\n fg: COLORS.fgDim,\n height: 1,\n marginTop: 1,\n wrapMode: 'none'\n });\n const filterHint = new TextRenderable(renderer, {\n id: 'filter-hint',\n content: 'Enter · keep filter Esc · clear & close',\n fg: COLORS.fg,\n height: 1,\n marginTop: 1,\n wrapMode: 'none'\n });\n filterBox.add(filterField);\n filterBox.add(filterStatus);\n filterBox.add(filterHint);\n renderer.root.add(filterBox);\n\n // --- Prompt modal (used for edit / add / new-file) ---\n const promptBox = new BoxRenderable(renderer, {\n id: 'prompt-box',\n position: 'absolute',\n top: '20%',\n left: '15%',\n right: '15%',\n height: 'auto',\n zIndex: 50,\n border: true,\n borderStyle: 'rounded',\n title: '',\n paddingX: 2,\n paddingY: 1,\n visible: false,\n backgroundColor: RGBA.fromHex('#1a1a1a'),\n flexDirection: 'column'\n });\n // Body of the modal is rebuilt on every refresh — either the context table\n // (edit / add-value) or just a single input row (add-key / new-file).\n const promptBody = new BoxRenderable(renderer, {\n id: 'prompt-body',\n flexDirection: 'column',\n flexGrow: 1\n });\n const promptHint = new TextRenderable(renderer, {\n id: 'prompt-hint',\n content: '',\n fg: COLORS.fg,\n height: 1,\n marginTop: 2,\n wrapMode: 'none'\n });\n promptBox.add(promptBody);\n promptBox.add(promptHint);\n renderer.root.add(promptBox);\n\n // Full-screen dim layer drawn below the prompt and help overlays so the\n // matrix fades back when a modal is active. Solid dark backgroundColor at\n // reduced opacity feels like a real dim/scrim.\n const dimOverlay = new BoxRenderable(renderer, {\n id: 'dim-overlay',\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 40,\n backgroundColor: RGBA.fromHex('#000000'),\n opacity: 0.6,\n visible: false\n });\n renderer.root.add(dimOverlay);\n\n // Floating help overlay. Hidden until '?' / 'ß' opens it. Two-column grid\n // so the overlay stays compact vertically and doesn't run off the bottom\n // on small terminals.\n // Help overlay — outer Box stays absolute-positioned; the body is rebuilt\n // every time it opens so we can switch between a one-column scrollable\n // layout (small terminals) and a two-column grid (wide terminals).\n const helpBox = new BoxRenderable(renderer, {\n id: 'help-overlay',\n position: 'absolute',\n top: 2,\n bottom: 2,\n left: '8%',\n right: '8%',\n zIndex: 100,\n border: true,\n borderStyle: 'rounded',\n title: ' Keybindings — press ? or Esc to close ',\n paddingX: 2,\n paddingY: 1,\n visible: false,\n backgroundColor: RGBA.fromHex('#1a1a1a'),\n flexDirection: 'column'\n });\n renderer.root.add(helpBox);\n\n // --- State helpers ---\n const sectionOf = (key: string): string | undefined =>\n state.grouping === 'banner' ? matrix.sectionOf(key) : prefixSection(key);\n\n const recomputeVisibleKeys = () => {\n // Two parallel structures:\n // visibleKeys — just the key names (used by editing helpers)\n // visibleItems — dividers + visible keys, in render order\n // Dividers stay in the item list even when their section is collapsed,\n // so the user can navigate onto one and expand it with 'c'.\n const visibleKeys: string[] = [];\n const items: MatrixItem[] = [];\n const orderedAll = orderedKeys(matrix, state, sectionOf);\n const seen = new Set<string>();\n const focusedRef = state.visibleItems[state.rowIdx]?.ref;\n for (const k of orderedAll) {\n if (!matchesFilter(k, state.filter)) continue;\n if (state.driftOnly && !keyDrifts(matrix, k)) continue;\n const sec = sectionOf(k);\n const secKey = SECTION_COLLAPSE_KEY(sec);\n if (!seen.has(secKey)) {\n seen.add(secKey);\n items.push({ kind: 'divider', ref: secKey });\n }\n if (state.collapsed.has(secKey)) continue;\n items.push({ kind: 'key', ref: k });\n visibleKeys.push(k);\n }\n state.visibleKeys = visibleKeys;\n state.visibleItems = items;\n // Try to keep focus on the same item across rebuilds.\n if (focusedRef) {\n const i = items.findIndex((it) => it.ref === focusedRef);\n if (i >= 0) state.rowIdx = i;\n }\n if (state.rowIdx >= items.length) {\n state.rowIdx = Math.max(0, items.length - 1);\n }\n // Make sure we don't land on an expanded divider after a rebuild.\n if (\n items[state.rowIdx]?.kind === 'divider' &&\n !state.collapsed.has(items[state.rowIdx]!.ref)\n ) {\n const next = stepRow(state, 1);\n const prev = stepRow(state, -1);\n state.rowIdx = next !== state.rowIdx ? next : prev;\n }\n };\n\n const rebuildMatrix = () => {\n const enabledList = allFiles.filter((f) => state.enabled.has(f));\n if (!state.enabled.has(currentBase)) {\n // Base got disabled — promote the first enabled file.\n const next = enabledList[0];\n if (next) currentBase = next;\n }\n matrix = buildMatrix(enabledList, currentBase);\n if (state.colIdx >= matrix.files.length) {\n state.colIdx = Math.max(0, matrix.files.length - 1);\n }\n if (state.sidebarIdx >= allFiles.length) {\n state.sidebarIdx = Math.max(0, allFiles.length - 1);\n }\n recomputeVisibleKeys();\n };\n\n const focusKey = (key: string) => {\n const idx = state.visibleKeys.indexOf(key);\n if (idx >= 0) state.rowIdx = idx;\n };\n\n const computeValueColWidth = (): number => {\n // Available width inside the matrix box (subtract sidebar, both borders\n // and the matrix's horizontal padding). If columns would have to shrink\n // below VALUE_COL_MIN to fit the viewport, keep them at the minimum and\n // let the ScrollBox handle the horizontal overflow.\n const available = Math.max(\n 0,\n renderer.terminalWidth - SIDEBAR_WIDTH - 6 - KEY_COL_WIDTH\n );\n const fair = matrix.files.length\n ? Math.floor(available / matrix.files.length)\n : VALUE_COL_MIN;\n return Math.max(VALUE_COL_MIN, fair);\n };\n\n const refreshNow = () => {\n const valueColWidth = computeValueColWidth();\n refreshSidebar(sidebar, renderer, matrix, allFiles, state);\n refreshMatrix(\n matrixBox,\n headerHost,\n scrollBox,\n renderer,\n matrix,\n state,\n valueColWidth,\n sectionOf\n );\n refreshFooter(hintA, hintB, status, renderer, state);\n refreshPrompt(promptBox, promptBody, promptHint, renderer, matrix, state);\n refreshHelp(helpBox, renderer, state);\n refreshFilter(filterBox, filterField, filterStatus, matrix, state);\n dimOverlay.visible =\n state.helpOpen || state.mode === 'prompt' || state.mode === 'filter';\n };\n\n // Coalesce burst-y refreshes (held arrow keys, fast filter typing) into\n // one render per microtask flush. The full refreshNow rebuilds every\n // matrix row, which is expensive when called for every keystroke; with\n // batching, holding an arrow key spends most of the time in opentui's\n // own redraw loop instead of in our re-render.\n let refreshScheduled = false;\n const refresh = () => {\n if (refreshScheduled) return;\n refreshScheduled = true;\n queueMicrotask(() => {\n refreshScheduled = false;\n refreshNow();\n });\n };\n\n recomputeVisibleKeys();\n refreshNow();\n\n // --- Interaction ---\n return new Promise<void>((resolve) => {\n const cleanup = () => {\n renderer._internalKeyInput.offInternal('keypress', onKey);\n renderer.destroy?.();\n resolve();\n };\n\n const openPrompt = (prompt: Prompt, value = '', placeholder = '') => {\n void placeholder; // input is rendered as plain text now, no placeholder slot\n state.prompt = prompt;\n state.mode = 'prompt';\n state.message = null;\n state.promptInput = value;\n refresh();\n };\n\n const closePrompt = (msg: string | null = null) => {\n state.prompt = null;\n state.mode = 'browse';\n state.promptInput = '';\n state.message = msg;\n refresh();\n };\n\n const focusedKey = (): string | null => {\n const item = state.visibleItems[state.rowIdx];\n return item && item.kind === 'key' ? item.ref : null;\n };\n\n const startEdit = () => {\n const key = focusedKey();\n const file = matrix.files[state.colIdx];\n if (!key || !file) {\n state.message = 'Move onto a variable row to edit.';\n refresh();\n return;\n }\n // Edit works on missing cells too — on commit we either update the\n // existing entry or append a new one.\n const entry = findKvEntry(file, key);\n openPrompt({ kind: 'edit', key, file }, entry?.value ?? '', 'value');\n };\n\n const startAdd = () => {\n const file = matrix.files[state.colIdx];\n if (!file) return;\n openPrompt({ kind: 'add-key', file }, '', 'NEW_KEY');\n };\n\n const startNewFile = () => {\n openPrompt({ kind: 'new-file' }, '', '.env.local');\n };\n\n const startDelete = () => {\n const key = focusedKey();\n const file = matrix.files[state.colIdx];\n if (!key || !file) {\n state.message = 'Move onto a variable row to delete.';\n refresh();\n return;\n }\n const entry = findKvEntry(file, key);\n if (!entry) {\n state.message = `${key} is not present in ${basename(file.path)}.`;\n refresh();\n return;\n }\n const idx = file.entries.indexOf(entry);\n if (idx >= 0) {\n pushUndo({ kind: 'delete-kv', file, entry, idx });\n file.entries.splice(idx, 1);\n }\n state.dirty.add(file);\n markModified(key, file);\n rebuildMatrix();\n state.message = `Deleted ${key} from ${basename(file.path)}. Ctrl-S to save.`;\n refresh();\n };\n\n const toggleEnabled = () => {\n const file = allFiles[state.sidebarIdx];\n if (!file) return;\n if (state.enabled.has(file)) {\n if (state.enabled.size === 1) {\n state.message = 'At least one file must stay enabled.';\n refresh();\n return;\n }\n state.enabled.delete(file);\n state.message = `Hidden ${basename(file.path)} from the matrix.`;\n } else {\n state.enabled.add(file);\n state.message = `Showing ${basename(file.path)} in the matrix.`;\n }\n rebuildMatrix();\n refresh();\n };\n\n const setBase = () => {\n const file = allFiles[state.sidebarIdx];\n if (!file) return;\n if (file === currentBase) {\n state.message = `${basename(file.path)} is already the base.`;\n refresh();\n return;\n }\n const wasDisabled = !state.enabled.has(file);\n if (wasDisabled) state.enabled.add(file);\n currentBase = file;\n rebuildMatrix();\n state.message = wasDisabled\n ? `${basename(file.path)} is now the base (re-enabled).`\n : `${basename(file.path)} is now the base.`;\n refresh();\n };\n\n const applyToAllFiles = (key: string, value: string): number => {\n // Set key=value in every enabled file. Used by '=' in the matrix and\n // Ctrl-A from the edit prompt. Each per-file mutation is undone\n // individually (one Ctrl-Z per file) — not perfect but predictable.\n let touched = 0;\n for (const file of matrix.files) {\n const existing = findKvEntry(file, key);\n if (existing) {\n if (existing.value === value) continue;\n pushUndo({\n kind: 'edit',\n file,\n entry: existing,\n prevValue: existing.value,\n prevRaw: existing.raw\n });\n existing.value = value;\n rebuildKvLine(existing);\n } else {\n const added = appendKv(file, key, value);\n pushUndo({ kind: 'add-kv', file, entry: added });\n }\n state.dirty.add(file);\n markModified(key, file);\n touched++;\n }\n return touched;\n };\n\n const syncToAll = () => {\n const key = focusedKey();\n const file = matrix.files[state.colIdx];\n if (!key || !file) {\n state.message = 'Move onto a variable row to sync.';\n refresh();\n return;\n }\n const entry = findKvEntry(file, key);\n if (!entry) {\n state.message = `${key} has no value in ${basename(file.path)} to sync.`;\n refresh();\n return;\n }\n const touched = applyToAllFiles(key, entry.value);\n rebuildMatrix();\n state.message =\n touched > 0\n ? `Synced ${key} to ${touched} file(s). Ctrl-S to save.`\n : `${key} is already in sync.`;\n refresh();\n };\n\n const undo = () => {\n const last = state.undo.pop();\n if (!last) {\n state.message = 'Nothing to undo.';\n refresh();\n return;\n }\n switch (last.kind) {\n case 'edit':\n last.entry.value = last.prevValue;\n last.entry.raw = last.prevRaw;\n state.dirty.add(last.file);\n state.message = `Undid edit on ${last.entry.key} in ${basename(last.file.path)}.`;\n break;\n case 'add-kv': {\n const i = last.file.entries.indexOf(last.entry);\n if (i >= 0) last.file.entries.splice(i, 1);\n state.dirty.add(last.file);\n state.message = `Undid add of ${last.entry.key} in ${basename(last.file.path)}.`;\n break;\n }\n case 'delete-kv':\n last.file.entries.splice(last.idx, 0, last.entry);\n state.dirty.add(last.file);\n state.message = `Undid delete of ${last.entry.key} in ${basename(last.file.path)}.`;\n break;\n }\n rebuildMatrix();\n refresh();\n };\n\n const commitPrompt = () => {\n if (!state.prompt) return;\n const p = state.prompt;\n const raw = state.promptInput;\n\n if (p.kind === 'edit') {\n const existing = findKvEntry(p.file, p.key);\n if (existing) {\n pushUndo({\n kind: 'edit',\n file: p.file,\n entry: existing,\n prevValue: existing.value,\n prevRaw: existing.raw\n });\n existing.value = raw;\n rebuildKvLine(existing);\n state.dirty.add(p.file);\n markModified(p.key, p.file);\n rebuildMatrix();\n closePrompt(\n `Edited ${p.key} in ${basename(p.file.path)}. Ctrl-S to save.`\n );\n } else {\n // Missing cell: add the key with the typed value.\n const added = appendKv(p.file, p.key, raw);\n pushUndo({ kind: 'add-kv', file: p.file, entry: added });\n state.dirty.add(p.file);\n markModified(p.key, p.file);\n rebuildMatrix();\n closePrompt(\n `Added ${p.key} to ${basename(p.file.path)}. Ctrl-S to save.`\n );\n }\n return;\n }\n\n if (p.kind === 'add-key') {\n const key = raw.trim();\n if (!KEY_RE.test(key)) {\n state.message = `Invalid key \"${key}\". Must match ${KEY_RE.source}.`;\n refresh();\n return;\n }\n if (findKvEntry(p.file, key)) {\n state.message = `${key} already exists in ${basename(p.file.path)}. Use edit instead.`;\n refresh();\n return;\n }\n openPrompt({ kind: 'add-value', key, file: p.file }, '', 'value');\n return;\n }\n\n if (p.kind === 'add-value') {\n const added = appendKv(p.file, p.key, raw);\n pushUndo({ kind: 'add-kv', file: p.file, entry: added });\n state.dirty.add(p.file);\n markModified(p.key, p.file);\n rebuildMatrix();\n focusKey(p.key);\n state.colIdx = matrix.files.indexOf(p.file);\n closePrompt(\n `Added ${p.key} to ${basename(p.file.path)}. Ctrl-S to save.`\n );\n return;\n }\n\n if (p.kind === 'new-file') {\n const name = raw.trim();\n if (!isValidEnvFileName(name)) {\n state.message =\n name.length === 0\n ? 'Filename cannot be empty.'\n : !name.startsWith('.env')\n ? `Filename must start with \".env\" (got \"${name}\").`\n : `\"${name}\" is not a valid env filename.`;\n refresh();\n return;\n }\n const newPath = join(dirname(currentBase.path), name);\n if (allFiles.some((f) => f.path === newPath)) {\n state.message = `${name} already exists.`;\n refresh();\n return;\n }\n const newFile = createEmptyEnvFile(newPath);\n allFiles.push(newFile);\n state.enabled.add(newFile);\n state.dirty.add(newFile);\n rebuildMatrix();\n state.colIdx = matrix.files.indexOf(newFile);\n closePrompt(`Created ${name}. Ctrl-S to write to disk.`);\n return;\n }\n };\n\n const cancelPrompt = () => {\n closePrompt('Cancelled.');\n };\n\n const saveDirty = async () => {\n if (state.dirty.size === 0) {\n state.message = 'Nothing to save.';\n refresh();\n return;\n }\n const count = state.dirty.size;\n const errors: string[] = [];\n for (const file of state.dirty) {\n try {\n await writeFile(file.path, serializeEnv(file), 'utf8');\n } catch (err) {\n errors.push(\n `${basename(file.path)}: ${(err as Error).message ?? String(err)}`\n );\n }\n }\n if (errors.length === 0) {\n state.dirty.clear();\n state.modified.clear();\n state.message = `Saved ${count} file${count === 1 ? '' : 's'}.`;\n } else {\n state.message = `Save failed: ${errors.join('; ')}`;\n }\n refresh();\n };\n\n const onKey = (key: {\n name: string;\n ctrl?: boolean;\n shift?: boolean;\n sequence?: string;\n preventDefault?: () => void;\n }) => {\n if (state.helpOpen) {\n if (\n key.name === 'escape' ||\n key.sequence === '?' ||\n key.sequence === 'ß' ||\n key.name === 'q'\n ) {\n state.helpOpen = false;\n refresh();\n }\n return;\n }\n\n if (state.mode === 'prompt') {\n if (key.name === 'escape') {\n cancelPrompt();\n return;\n }\n if (key.name === 'return') {\n commitPrompt();\n return;\n }\n if (key.name === 'backspace') {\n if (state.promptInput.length > 0) {\n state.promptInput = state.promptInput.slice(0, -1);\n refresh();\n }\n return;\n }\n if (key.ctrl && key.name === 't') {\n state.showSecrets = !state.showSecrets;\n refresh();\n return;\n }\n if (key.ctrl && key.name === 'a' && state.prompt) {\n const p = state.prompt;\n if (p.kind === 'edit' || p.kind === 'add-value') {\n const touched = applyToAllFiles(p.key, state.promptInput);\n rebuildMatrix();\n closePrompt(\n touched > 0\n ? `Set ${p.key} in ${touched} file(s). Ctrl-S to save.`\n : `${p.key} already had that value everywhere.`\n );\n }\n return;\n }\n const seq = key.sequence ?? '';\n if (!key.ctrl && seq.length === 1 && seq >= ' ' && seq !== '\\x7f') {\n state.promptInput += seq;\n refresh();\n }\n return;\n }\n\n if (state.mode === 'filter') {\n if (key.name === 'escape') {\n state.filter = '';\n state.mode = 'browse';\n recomputeVisibleKeys();\n refresh();\n return;\n }\n if (key.name === 'return') {\n state.mode = 'browse';\n refresh();\n return;\n }\n if (key.name === 'backspace') {\n if (state.filter.length > 0) {\n state.filter = state.filter.slice(0, -1);\n recomputeVisibleKeys();\n refresh();\n }\n return;\n }\n // Append any printable character. opentui's KeyEvent puts the actual\n // char into `sequence` for normal keystrokes.\n const seq = key.sequence ?? '';\n if (seq.length === 1 && seq >= ' ' && seq !== '\\x7f') {\n state.filter += seq;\n recomputeVisibleKeys();\n refresh();\n }\n return;\n }\n\n // Browse mode.\n if (key.ctrl && key.name === 'c') return cleanup();\n if (key.ctrl && key.name === 's') {\n state.confirmQuit = false;\n return void saveDirty();\n }\n if (key.ctrl && key.name === 'z') {\n state.confirmQuit = false;\n return undo();\n }\n if (key.ctrl && key.name === 't') {\n state.showSecrets = !state.showSecrets;\n state.message = state.showSecrets\n ? 'Showing secret values in plain text.'\n : 'Masking secret values.';\n return refresh();\n }\n\n const tryQuit = () => {\n if (state.dirty.size > 0 && !state.confirmQuit) {\n state.confirmQuit = true;\n state.message = `${state.dirty.size} unsaved file(s). Press 'q' again to quit without saving, or Ctrl-S to save first.`;\n refresh();\n return;\n }\n cleanup();\n };\n // Any key other than q clears a pending quit confirmation.\n if (state.confirmQuit && key.name !== 'q') {\n state.confirmQuit = false;\n state.message = null;\n }\n\n if (state.pane === 'sidebar') {\n switch (key.name) {\n case 'q':\n return tryQuit();\n case 'tab':\n state.pane = 'matrix';\n return refresh();\n case 'right':\n state.pane = 'matrix';\n return refresh();\n case 'up':\n state.sidebarIdx = Math.max(0, state.sidebarIdx - 1);\n return refresh();\n case 'down':\n state.sidebarIdx = Math.min(\n allFiles.length - 1,\n state.sidebarIdx + 1\n );\n return refresh();\n case 'space':\n return toggleEnabled();\n case 'b':\n return setBase();\n }\n if (key.sequence === ' ') return toggleEnabled();\n if (key.sequence === '?' || key.sequence === 'ß') {\n state.helpOpen = true;\n return refresh();\n }\n return;\n }\n\n switch (key.name) {\n case 'q':\n return tryQuit();\n case 'tab':\n state.pane = 'sidebar';\n return refresh();\n case 'up':\n state.rowIdx = stepRow(state, -1);\n return refresh();\n case 'down':\n state.rowIdx = stepRow(state, 1);\n return refresh();\n case 'left':\n if (state.colIdx === 0) {\n // Already at the leftmost matrix column — hand focus to the sidebar.\n state.pane = 'sidebar';\n return refresh();\n }\n state.colIdx = Math.max(0, state.colIdx - 1);\n return refresh();\n case 'right':\n state.colIdx = Math.min(matrix.files.length - 1, state.colIdx + 1);\n return refresh();\n case 'e':\n case 'return':\n return startEdit();\n case 'a':\n return startAdd();\n case 'd':\n return startDelete();\n case 'n':\n return startNewFile();\n case 'v':\n state.driftOnly = !state.driftOnly;\n state.message = state.driftOnly\n ? 'Drift-only view (only keys with differences).'\n : 'Full view.';\n recomputeVisibleKeys();\n return refresh();\n case 'c': {\n if (key.shift) {\n // Capital C — expand every collapsed section. Use this when all\n // keys you'd navigate to are hidden behind a fold.\n if (state.collapsed.size === 0) {\n state.message = 'Nothing collapsed.';\n return refresh();\n }\n const count = state.collapsed.size;\n state.collapsed.clear();\n state.message = `Expanded ${count} section(s).`;\n recomputeVisibleKeys();\n return refresh();\n }\n // Collapse / expand the section of the focused item. Works on\n // both key rows and section dividers; on a divider this is the\n // only way back into a collapsed section.\n const item = state.visibleItems[state.rowIdx];\n if (!item) return;\n const sectionKey =\n item.kind === 'divider'\n ? item.ref\n : (sectionOf(item.ref) ?? '__other__');\n if (state.collapsed.has(sectionKey)) {\n state.collapsed.delete(sectionKey);\n state.message = `Expanded \"${sectionKey === '__other__' ? '(other)' : sectionKey}\".`;\n } else {\n state.collapsed.add(sectionKey);\n state.message = `Collapsed \"${sectionKey === '__other__' ? '(other)' : sectionKey}\". Press Shift-C to expand all.`;\n }\n recomputeVisibleKeys();\n return refresh();\n }\n case 'g': {\n // Preserve focus across the rebuild — focusedRef in\n // recomputeVisibleKeys finds the same item by ref.\n state.grouping = state.grouping === 'banner' ? 'prefix' : 'banner';\n recomputeVisibleKeys();\n state.message =\n state.grouping === 'banner'\n ? 'Group by comment banners.'\n : 'Group by key prefix (first underscore segment).';\n return refresh();\n }\n }\n\n if (key.sequence === '/' || key.name === 'slash') {\n state.mode = 'filter';\n state.message = null;\n refresh();\n return;\n }\n\n // = sync-to-all. opentui's key.name for \"=\" is inconsistent across\n // platforms so we check the sequence directly.\n if (key.sequence === '=') return syncToAll();\n\n if (key.sequence === '?' || key.sequence === 'ß') {\n state.helpOpen = true;\n refresh();\n }\n };\n\n // Use the internal channel so our handler runs *before* the focused\n // renderable processes the event. That lets us intercept Esc / Enter\n // before opentui's InputRenderable swallows them (Esc would otherwise\n // just blur the input instead of closing the modal).\n renderer._internalKeyInput.onInternal('keypress', onKey);\n renderer.on('resize', refresh);\n });\n}\n\n// --- Refreshers ---\n\nfunction refreshSidebar(\n sidebar: BoxRenderable,\n renderer: CliRenderer,\n matrix: Matrix,\n allFiles: EnvFile[],\n state: State\n): void {\n const total = allFiles.length;\n const enabled = state.enabled.size;\n sidebar.title =\n state.pane === 'sidebar'\n ? ` Files ${enabled}/${total} • focused `\n : ` Files ${enabled}/${total} `;\n removeAllChildren(sidebar);\n for (let i = 0; i < allFiles.length; i++) {\n const file = allFiles[i]!;\n const isBase = file === matrix.base;\n const isDirty = state.dirty.has(file);\n const isEnabled = state.enabled.has(file);\n const matrixIdx = matrix.files.indexOf(file);\n const isFocusCol = isEnabled && matrixIdx === state.colIdx;\n const isPaneFocus = state.pane === 'sidebar' && i === state.sidebarIdx;\n const nameFg = !isEnabled\n ? COLORS.fgDim\n : isBase\n ? COLORS.fgBase\n : COLORS.fg;\n\n const row = new BoxRenderable(renderer, {\n id: `file-${file.path}`,\n flexDirection: 'row',\n height: 1,\n flexShrink: 0,\n ...(isPaneFocus ? { backgroundColor: COLORS.focusBg } : {})\n });\n const span = (id: string, text: string, fg: RGBA) =>\n new TextRenderable(renderer, {\n id: `${row.id}-${id}`,\n content: text,\n fg,\n height: 1,\n wrapMode: 'none'\n });\n row.add(span('focus', `${isPaneFocus ? '▶' : ' '} `, COLORS.fg));\n row.add(\n span(\n 'dirty',\n `${isDirty ? '●' : ' '} `,\n isDirty ? COLORS.fgDirty : COLORS.fgDim\n )\n );\n row.add(\n span(\n 'base',\n `${isBase ? '★' : ' '} `,\n isBase ? COLORS.fgBase : COLORS.fgDim\n )\n );\n row.add(span('col', `${isFocusCol ? '▸' : ' '} `, COLORS.fgDim));\n row.add(span('enabled', `${isEnabled ? '✓' : '☐'} `, COLORS.fgDim));\n row.add(span('name', basename(file.path), nameFg));\n sidebar.add(row);\n }\n}\n\nfunction refreshMatrix(\n matrixBox: BoxRenderable,\n headerHost: BoxRenderable,\n scrollBox: ScrollBoxRenderable,\n renderer: CliRenderer,\n matrix: Matrix,\n state: State,\n valueColWidth: number,\n sectionOf: (key: string) => string | undefined\n): void {\n matrixBox.title = matrixTitle(matrix, state);\n removeAllChildren(headerHost);\n removeAllChildren(scrollBox.content);\n\n headerHost.add(\n buildRow(renderer, 'header', [\n { text: 'KEY', fg: COLORS.fgHeader, width: KEY_COL_WIDTH },\n ...matrix.files.map((f) => ({\n text: basename(f.path),\n fg: COLORS.fgHeader,\n width: valueColWidth\n }))\n ])\n );\n\n // Walk every key (including those hidden by a collapsed section) so we can\n // render section dividers for collapsed groups too. Within an expanded\n // group we render the cell rows; within a collapsed one we render nothing\n // beyond the header.\n const totalWidth = KEY_COL_WIDTH + valueColWidth * matrix.files.length;\n const sectionStats = sectionMetadata(matrix, sectionOf, state);\n\n for (let r = 0; r < state.visibleItems.length; r++) {\n const item = state.visibleItems[r]!;\n if (item.kind === 'divider') {\n const sectionKey = item.ref;\n const sectionName = sectionKey === '__other__' ? undefined : sectionKey;\n const meta = sectionStats.get(sectionKey) ?? {\n drift: 0,\n missing: 0,\n total: 0\n };\n const focused = state.mode === 'browse' && r === state.rowIdx;\n scrollBox.content.add(\n buildSectionDivider(renderer, `row-${r}`, sectionName, totalWidth, {\n ...meta,\n collapsed: state.collapsed.has(sectionKey),\n focused\n })\n );\n continue;\n }\n const key = item.ref;\n const secret = isSecretKey(key) && !state.showSecrets;\n const cells: CellSpec[] = [\n { text: key, fg: COLORS.fg, width: KEY_COL_WIDTH }\n ];\n for (let c = 0; c < matrix.files.length; c++) {\n const file = matrix.files[c]!;\n const cell = matrix.cell(key, file);\n const focused =\n state.mode === 'browse' && r === state.rowIdx && c === state.colIdx;\n const isModified = state.modified.has(`${key}|${file.path}`);\n cells.push(\n buildValueCell(cell, secret, valueColWidth, focused, isModified)\n );\n }\n scrollBox.content.add(buildRow(renderer, `row-${r}`, cells));\n }\n\n // Keep the focused row in view. Single deferred call so layout has been\n // computed before we ask for a scroll target; doing it twice (sync +\n // deferred) was causing visible \"jumps\" because the two calls landed on\n // slightly different layouts.\n if (state.mode === 'browse' && state.visibleItems.length > 0) {\n const target = `row-${state.rowIdx}`;\n setImmediate(() => {\n try {\n scrollBox.scrollChildIntoView(target);\n } catch {\n /* row not laid out yet — next refresh will retry */\n }\n });\n }\n}\n\ninterface FooterSeg {\n text: string;\n fg: RGBA;\n}\n\nfunction bindings(specs: { key: string; label: string }[]): FooterSeg[] {\n // \"[key] label\" with the brackets dim and the key + label in normal fg.\n // Segments separated by dim \" · \".\n const out: FooterSeg[] = [];\n specs.forEach((spec, i) => {\n if (i > 0) out.push({ text: ' · ', fg: COLORS.fgDim });\n out.push({ text: '[', fg: COLORS.fgDim });\n out.push({ text: spec.key, fg: COLORS.fg });\n out.push({ text: '] ', fg: COLORS.fgDim });\n out.push({ text: spec.label, fg: COLORS.fg });\n });\n return out;\n}\n\nfunction renderHintBox(\n box: BoxRenderable,\n renderer: CliRenderer,\n segs: FooterSeg[]\n): void {\n removeAllChildren(box);\n segs.forEach((seg, i) => {\n box.add(\n new TextRenderable(renderer, {\n id: `${box.id}-seg-${i}`,\n content: seg.text,\n fg: seg.fg,\n height: 1,\n wrapMode: 'none'\n })\n );\n });\n}\n\nfunction refreshHelp(\n helpBox: BoxRenderable,\n renderer: CliRenderer,\n state: State\n): void {\n helpBox.visible = state.helpOpen;\n if (!state.helpOpen) return;\n removeAllChildren(helpBox);\n const lines = buildHelpLines();\n // Use one scrollable column when the terminal is narrow or short.\n const narrow = renderer.terminalWidth < 100;\n const short = renderer.terminalHeight < 36;\n const oneColumn = narrow || short;\n if (oneColumn) {\n const scroll = new ScrollBoxRenderable(renderer, {\n id: 'help-scroll',\n flexGrow: 1,\n scrollX: false,\n scrollY: true,\n viewportOptions: { paddingRight: 1 },\n contentOptions: { flexDirection: 'column' }\n });\n helpBox.add(scroll);\n lines.forEach((line, i) => {\n scroll.content.add(buildHelpRow(renderer, `help-${i}`, line));\n });\n return;\n }\n // Two-column grid.\n const grid = new BoxRenderable(renderer, {\n id: 'help-grid',\n flexDirection: 'row',\n flexGrow: 1,\n columnGap: 3\n });\n const left = new BoxRenderable(renderer, {\n id: 'help-left',\n flexDirection: 'column',\n flexGrow: 1,\n flexBasis: 0\n });\n const right = new BoxRenderable(renderer, {\n id: 'help-right',\n flexDirection: 'column',\n flexGrow: 1,\n flexBasis: 0\n });\n const half = Math.floor(lines.length / 2);\n let splitIdx = half;\n for (let i = half; i < lines.length; i++) {\n if (lines[i]?.kind === 'blank') {\n splitIdx = i + 1;\n break;\n }\n }\n lines\n .slice(0, splitIdx)\n .forEach((line, i) =>\n left.add(buildHelpRow(renderer, `help-l-${i}`, line))\n );\n lines\n .slice(splitIdx)\n .forEach((line, i) =>\n right.add(buildHelpRow(renderer, `help-r-${i}`, line))\n );\n grid.add(left);\n grid.add(right);\n helpBox.add(grid);\n}\n\nfunction refreshFilter(\n filterBox: BoxRenderable,\n filterField: TextRenderable,\n filterStatus: TextRenderable,\n matrix: Matrix,\n state: State\n): void {\n const open = state.mode === 'filter';\n filterBox.visible = open;\n if (!open) return;\n // Show the current filter with a fake cursor at the end. visibleKeys is\n // already filtered, so its length is the live match count.\n filterField.content = `▸ ${state.filter}▏`;\n const matches = state.visibleKeys.length;\n const total = matrix.keys.length;\n filterStatus.content =\n state.filter.length === 0\n ? 'Type to filter the keys list.'\n : `Matching ${matches} of ${total} keys.`;\n}\n\nfunction refreshFooter(\n hintA: BoxRenderable,\n hintB: BoxRenderable,\n status: TextRenderable,\n renderer: CliRenderer,\n state: State\n): void {\n const dirty = state.dirty.size;\n const dirtyTail: FooterSeg[] =\n dirty > 0\n ? [\n { text: ' ', fg: COLORS.fgDim },\n { text: '●', fg: COLORS.modified },\n { text: ` ${dirty} unsaved`, fg: COLORS.fg }\n ]\n : [];\n\n if (state.mode === 'filter') {\n renderHintBox(hintA, renderer, [\n ...bindings([\n { key: 'Enter', label: 'keep filter' },\n { key: 'Esc', label: 'clear' }\n ]),\n ...dirtyTail\n ]);\n renderHintBox(hintB, renderer, [{ text: ' Filter:', fg: COLORS.fgDim }]);\n } else if (state.mode === 'prompt') {\n renderHintBox(hintA, renderer, []);\n renderHintBox(hintB, renderer, []);\n } else if (state.pane === 'sidebar') {\n renderHintBox(hintA, renderer, [\n ...bindings([\n { key: '↑↓', label: 'move' },\n { key: 'Space', label: 'toggle' },\n { key: 'b', label: 'set base' },\n { key: 'Tab/→', label: 'matrix' },\n { key: '^S', label: 'save' },\n { key: '?', label: 'help' },\n { key: 'q', label: 'quit' }\n ]),\n ...dirtyTail\n ]);\n renderHintBox(hintB, renderer, [{ text: 'Files pane', fg: COLORS.fgDim }]);\n } else {\n renderHintBox(hintA, renderer, [\n ...bindings([\n { key: '↑↓←→', label: 'move' },\n { key: 'Tab', label: 'files' },\n { key: 'e', label: 'edit' },\n { key: 'a', label: 'add var' },\n { key: 'd', label: 'del var' },\n { key: 'n', label: 'new file' },\n { key: '=', label: 'sync to all' },\n { key: 'c', label: 'collapse' },\n { key: '^T', label: 'secrets' },\n { key: '^Z', label: 'undo' },\n { key: '^S', label: 'save' },\n { key: '/', label: 'filter' },\n { key: '?/ß', label: 'help' },\n { key: 'q', label: 'quit' }\n ]),\n ...dirtyTail\n ]);\n renderHintBox(hintB, renderer, [\n { text: 'view: ', fg: COLORS.fgDim },\n { text: state.driftOnly ? 'drift' : 'all', fg: COLORS.fg },\n { text: ' · group: ', fg: COLORS.fgDim },\n { text: state.grouping, fg: COLORS.fg },\n { text: ' · secrets: ', fg: COLORS.fgDim },\n { text: state.showSecrets ? 'shown' : 'masked', fg: COLORS.fg }\n ]);\n }\n status.content = state.message ?? '';\n}\n\nfunction refreshPrompt(\n promptBox: BoxRenderable,\n promptBody: BoxRenderable,\n promptHint: TextRenderable,\n renderer: CliRenderer,\n matrix: Matrix,\n state: State\n): void {\n const open = state.mode === 'prompt' && state.prompt !== null;\n promptBox.visible = open;\n if (!open || !state.prompt) return;\n\n promptBox.title = promptLabelText(state.prompt);\n // Hint depends on which prompt is active — only edit/add-value support\n // the apply-to-all + show-secrets shortcuts.\n const p = state.prompt;\n if (p.kind === 'edit' || p.kind === 'add-value') {\n promptHint.content =\n 'Enter · confirm Ctrl-A · apply to all ' +\n 'Ctrl-T · show/mask secrets Esc · cancel';\n } else {\n promptHint.content = 'Enter · confirm Esc · cancel';\n }\n\n // Body layout: full-width input on top, then a context table of every file\n // and its current value (read-only). For add-key / new-file there's no\n // context to show — just the input.\n removeAllChildren(promptBody);\n // Input is rendered as plain text so we can guarantee char + Esc handling\n // ourselves (opentui's InputRenderable swallows Esc as \"blur\").\n promptBody.add(\n new TextRenderable(renderer, {\n id: 'prompt-input-text',\n content: `▸ ${state.promptInput}▏`,\n fg: COLORS.fg,\n height: 1,\n wrapMode: 'none'\n })\n );\n // Show validation errors inside the modal so they aren't hidden behind\n // the dim overlay. state.message is set by commitPrompt when input is\n // invalid (and cleared on each fresh openPrompt).\n if (state.message) {\n promptBody.add(\n new TextRenderable(renderer, {\n id: 'prompt-error',\n content: `! ${state.message}`,\n fg: COLORS.missing,\n height: 1,\n marginTop: 1,\n wrapMode: 'none'\n })\n );\n }\n\n if (p.kind === 'edit' || p.kind === 'add-value') {\n const secret = isSecretKey(p.key) && !state.showSecrets;\n const nameWidth = Math.min(\n 26,\n Math.max(...matrix.files.map((f) => basename(f.path).length + 2))\n );\n\n promptBody.add(\n new TextRenderable(renderer, {\n id: 'prompt-table-header',\n content: 'Current values',\n fg: COLORS.fgSection,\n wrapMode: 'none',\n height: 1,\n marginTop: 1\n })\n );\n\n for (const file of matrix.files) {\n const isTarget = file === p.file;\n const row = new BoxRenderable(renderer, {\n id: `prompt-row-${file.path}`,\n flexDirection: 'row',\n height: 1,\n flexShrink: 0\n });\n row.add(\n new TextRenderable(renderer, {\n id: `prompt-row-${file.path}-name`,\n content: `${isTarget ? '▸' : ' '} ${basename(file.path)}`.padEnd(\n nameWidth\n ),\n fg: isTarget ? COLORS.fgBase : COLORS.fgDim,\n height: 1,\n wrapMode: 'none'\n })\n );\n const entry = findKvEntry(file, p.key);\n const current = entry ? formatValue(entry.value, secret) : '✗ missing';\n row.add(\n new TextRenderable(renderer, {\n id: `prompt-row-${file.path}-value`,\n content: current,\n fg: !entry ? COLORS.missing : isTarget ? COLORS.fg : COLORS.fgDim,\n height: 1,\n wrapMode: 'none'\n })\n );\n promptBody.add(row);\n }\n }\n}\n\nfunction promptLabelText(p: Prompt): string {\n switch (p.kind) {\n case 'edit':\n return ` Edit ${p.key} in ${basename(p.file.path)}:`;\n case 'add-key':\n return ` Add new key to ${basename(p.file.path)}:`;\n case 'add-value':\n return ` Value for ${p.key} in ${basename(p.file.path)}:`;\n case 'new-file':\n return ' New env file name (e.g. .env.local):';\n }\n}\n\n// --- Helpers ---\n\nfunction prefixSection(key: string): string | undefined {\n const idx = key.indexOf('_');\n if (idx <= 0) return undefined;\n return key.slice(0, idx);\n}\n\n/**\n * Sort by first-underscore-prefix while preserving the relative order each\n * prefix first appeared in. Keys without an underscore land in a trailing\n * \"Other\" group keeping their authored order.\n */\nfunction groupByPrefix(keys: string[]): string[] {\n const groups = new Map<string, string[]>();\n const order: string[] = [];\n const OTHER = '__other__';\n for (const k of keys) {\n const p = prefixSection(k) ?? OTHER;\n let bucket = groups.get(p);\n if (!bucket) {\n bucket = [];\n groups.set(p, bucket);\n if (p !== OTHER) order.push(p);\n }\n bucket.push(k);\n }\n if (groups.has(OTHER)) order.push(OTHER);\n return order.flatMap((p) => groups.get(p)!);\n}\n\n/**\n * Move row focus by `delta` while skipping section dividers that are not\n * collapsed. The user only needs to land on a divider when its section is\n * folded — that's the only context in which 'c' on the divider does work\n * the focused-key path doesn't already cover.\n */\nfunction stepRow(state: State, delta: number): number {\n const items = state.visibleItems;\n if (items.length === 0) return 0;\n const canFocus = (i: number) => {\n const it = items[i];\n if (!it) return false;\n if (it.kind === 'key') return true;\n // divider — focusable only when collapsed\n return state.collapsed.has(it.ref);\n };\n let i = state.rowIdx + delta;\n while (i >= 0 && i < items.length) {\n if (canFocus(i)) return i;\n i += delta;\n }\n // No focusable item further along — clamp to current.\n return state.rowIdx;\n}\n\nfunction orderedKeys(\n matrix: Matrix,\n state: State,\n sectionOf: (key: string) => string | undefined\n): string[] {\n void sectionOf;\n const filtered = matrix.keys.filter((k) => {\n if (!matchesFilter(k, state.filter)) return false;\n if (state.driftOnly && !keyDrifts(matrix, k)) return false;\n return true;\n });\n return state.grouping === 'prefix' ? groupByPrefix(filtered) : filtered;\n}\n\ninterface SectionStats {\n drift: number;\n missing: number;\n total: number;\n}\n\nfunction sectionMetadata(\n matrix: Matrix,\n sectionOf: (key: string) => string | undefined,\n state: State\n): Map<string, SectionStats> {\n const out = new Map<string, SectionStats>();\n for (const key of orderedKeys(matrix, state, sectionOf)) {\n const k = sectionOf(key) ?? '__other__';\n const bucket = out.get(k) ?? { drift: 0, missing: 0, total: 0 };\n bucket.total += 1;\n let drifts = false;\n let missing = false;\n for (const file of matrix.files) {\n if (file === matrix.base) continue;\n const s = matrix.cell(key, file).state;\n if (s === 'missing') missing = true;\n if (s === 'differs' || s === 'missing' || s === 'extra') drifts = true;\n }\n if (drifts) bucket.drift += 1;\n if (missing) bucket.missing += 1;\n out.set(k, bucket);\n }\n return out;\n}\n\nfunction buildValueCell(\n cell: { state: CellState; value: string | undefined },\n secret: boolean,\n width: number,\n focused: boolean,\n modified: boolean\n): CellSpec {\n const bg = focused ? COLORS.focusBg : undefined;\n const trailing = modified ? { char: '●', fg: COLORS.modified } : undefined;\n if (cell.state === 'missing') {\n return {\n text: 'missing',\n fg: COLORS.fgDim,\n width,\n bg,\n icon: { char: '✗', fg: COLORS.missing },\n trailing\n };\n }\n const value = cell.value ?? '';\n if (value !== '' && isPlaceholderValue(value)) {\n return {\n text: value,\n fg: COLORS.fg,\n width,\n bg,\n icon: { char: '⚠', fg: COLORS.placeholder },\n trailing\n };\n }\n const isEmpty = value === '' && !secret;\n const displayText = isEmpty ? '(empty)' : formatValue(value, secret);\n const displayFg = isEmpty ? COLORS.fgDim : COLORS.fg;\n if (cell.state === 'differs') {\n return {\n text: displayText,\n fg: displayFg,\n width,\n bg,\n icon: { char: '≠', fg: COLORS.differs },\n trailing\n };\n }\n if (cell.state === 'extra') {\n return {\n text: displayText,\n fg: displayFg,\n width,\n bg,\n icon: { char: '★', fg: COLORS.extra },\n trailing\n };\n }\n return { text: displayText, fg: displayFg, width, bg, trailing };\n}\n\nfunction keyDrifts(matrix: Matrix, key: string): boolean {\n for (const file of matrix.files) {\n if (file === matrix.base) continue;\n const s = matrix.cell(key, file).state;\n if (s === 'differs' || s === 'missing' || s === 'extra') return true;\n }\n return false;\n}\n\nfunction isValidEnvFileName(name: string): boolean {\n if (!name.startsWith('.env')) return false;\n if (name.includes('/') || name.includes('\\\\')) return false;\n if (name.endsWith('.swp') || name.endsWith('~') || name.endsWith('.bak'))\n return false;\n return true;\n}\n\nfunction createEmptyEnvFile(path: string): EnvFile {\n return {\n path,\n entries: [{ kind: 'comment', raw: `# ${basename(path)}` }],\n trailingNewline: true\n };\n}\n\nfunction appendKv(file: EnvFile, key: string, value: string): KvEntry {\n const entry: KvEntry = {\n kind: 'kv',\n key,\n rawValue: '',\n value,\n quoting: 'none',\n exportPrefix: false,\n inlineComment: '',\n raw: ''\n };\n rebuildKvLine(entry);\n file.entries.push(entry);\n // Round-trip semantics: serializeEnv joins with \\n and appends a trailing\n // newline if trailingNewline is set. Push alone gives us \"...\\nKEY=val\" when\n // trailingNewline=false, or \"...\\nKEY=val\\n\" when true. Either case is\n // sane; we make sure the file ends with a newline so editors don't complain.\n file.trailingNewline = true;\n return entry;\n}\n\nfunction buildHelpRow(\n renderer: CliRenderer,\n id: string,\n line: HelpLine\n): BoxRenderable {\n const row = new BoxRenderable(renderer, {\n id,\n flexDirection: 'row',\n height: 1,\n flexShrink: 0\n });\n if (line.kind === 'header') {\n row.add(\n new TextRenderable(renderer, {\n id: `${id}-t`,\n content: line.text,\n fg: COLORS.fgSection,\n wrapMode: 'none',\n height: 1\n })\n );\n } else if (line.kind === 'entry') {\n row.add(\n new TextRenderable(renderer, {\n id: `${id}-t`,\n content: line.text,\n fg: COLORS.fg,\n wrapMode: 'none',\n height: 1\n })\n );\n } else if (line.kind === 'legend') {\n row.add(\n new TextRenderable(renderer, {\n id: `${id}-sym`,\n content: ` ${line.symbol.padEnd(12)}`,\n fg: line.color,\n wrapMode: 'none',\n height: 1\n })\n );\n row.add(\n new TextRenderable(renderer, {\n id: `${id}-desc`,\n content: line.description,\n fg: COLORS.fgDim,\n wrapMode: 'none',\n height: 1\n })\n );\n }\n return row;\n}\n\nfunction buildSectionDivider(\n renderer: CliRenderer,\n id: string,\n name: string | undefined,\n width: number,\n meta: SectionStats & { collapsed: boolean; focused?: boolean }\n): BoxRenderable {\n // Multi-segment divider so colours can encode meaning:\n // gray ─── blue ▾ Name dim · stats gray ───\n // Drift counts go yellow; if any key in the section is missing in any\n // non-base file we surface that explicitly in red (\"✗ N missing\"), even\n // when the section also has plain differs.\n const baseName = name ?? '(other)';\n const indicator = meta.collapsed ? '▸' : '▾';\n // Icons + numbers carry colour (red for missing, yellow for drift). Name\n // and descriptive words render in the normal foreground; the \"/\" and\n // trailing whitespace stay dim.\n type Seg = { text: string; fg: RGBA };\n const segs: Seg[] = [\n { text: ` ${indicator} `, fg: COLORS.fgDim },\n { text: baseName, fg: COLORS.fg },\n { text: ' ', fg: COLORS.fgDim }\n ];\n if (meta.missing > 0) {\n segs.push({ text: '✗ ', fg: COLORS.missing });\n segs.push({ text: `${meta.missing}`, fg: COLORS.missing });\n segs.push({ text: ' missing ', fg: COLORS.fg });\n }\n if (meta.drift > 0) {\n segs.push({ text: '≠ ', fg: COLORS.differs });\n segs.push({ text: `${meta.drift}`, fg: COLORS.differs });\n segs.push({ text: '/', fg: COLORS.fgDim });\n segs.push({ text: `${meta.total}`, fg: COLORS.differs });\n segs.push({ text: ' drift ', fg: COLORS.fg });\n }\n if (meta.missing === 0 && meta.drift === 0) {\n segs.push({ text: `${meta.total}`, fg: COLORS.fgDim });\n segs.push({ text: ' keys ', fg: COLORS.fg });\n }\n segs.push({ text: ' ', fg: COLORS.fgDim });\n\n const labelLength = segs.reduce((sum, s) => sum + s.text.length, 0);\n const rule = '─';\n const visible = Math.max(0, width - 2);\n const beforeLen = Math.max(2, Math.floor((visible - labelLength) / 2));\n const afterLen = Math.max(0, visible - beforeLen - labelLength);\n\n const box = new BoxRenderable(renderer, {\n id,\n flexDirection: 'row',\n flexShrink: 0,\n height: 1,\n paddingX: 1,\n ...(meta.focused ? { backgroundColor: COLORS.focusBg } : {})\n });\n box.add(\n new TextRenderable(renderer, {\n id: `${id}-lead`,\n content: rule.repeat(beforeLen),\n fg: COLORS.fgDim,\n height: 1,\n wrapMode: 'none'\n })\n );\n segs.forEach((seg, i) => {\n box.add(\n new TextRenderable(renderer, {\n id: `${id}-seg-${i}`,\n content: seg.text,\n fg: seg.fg,\n height: 1,\n wrapMode: 'none'\n })\n );\n });\n box.add(\n new TextRenderable(renderer, {\n id: `${id}-trail`,\n content: rule.repeat(afterLen),\n fg: COLORS.fgDim,\n height: 1,\n wrapMode: 'none'\n })\n );\n return box;\n}\n\ninterface CellSpec {\n text: string;\n fg: RGBA;\n width: number;\n bg?: RGBA;\n // Optional coloured prefix — rendered in its own Text span so only the\n // icon carries the state colour, the text stays neutral.\n icon?: { char: string; fg: RGBA };\n // Optional coloured marker that sits at the right edge of the cell.\n // Used for the modified-since-load indicator.\n trailing?: { char: string; fg: RGBA };\n}\n\nfunction buildRow(\n renderer: CliRenderer,\n idPrefix: string,\n cells: CellSpec[]\n): BoxRenderable {\n const row = new BoxRenderable(renderer, {\n id: idPrefix,\n flexDirection: 'row',\n flexShrink: 0,\n height: 1\n });\n cells.forEach((cell, i) => {\n const cellOpts: ConstructorParameters<typeof BoxRenderable>[1] = {\n id: `${idPrefix}-c${i}`,\n width: cell.width,\n height: 1,\n flexDirection: 'row',\n flexShrink: 0,\n paddingX: CELL_PAD_X\n };\n if (cell.bg) cellOpts.backgroundColor = cell.bg;\n const cellBox = new BoxRenderable(renderer, cellOpts);\n const innerWidth = Math.max(0, cell.width - CELL_PAD_X * 2);\n const iconLen = cell.icon ? cell.icon.char.length + 1 : 0;\n const trailingLen = cell.trailing ? cell.trailing.char.length + 1 : 0;\n const textWidth = Math.max(0, innerWidth - iconLen - trailingLen);\n if (cell.icon) {\n cellBox.add(\n new TextRenderable(renderer, {\n id: `${idPrefix}-c${i}-icon`,\n content: `${cell.icon.char} `,\n fg: cell.icon.fg,\n height: 1,\n wrapMode: 'none'\n })\n );\n }\n cellBox.add(\n new TextRenderable(renderer, {\n id: `${idPrefix}-c${i}-t`,\n content: truncate(cell.text, textWidth),\n fg: cell.fg,\n height: 1,\n flexGrow: 1,\n wrapMode: 'none'\n })\n );\n if (cell.trailing) {\n cellBox.add(\n new TextRenderable(renderer, {\n id: `${idPrefix}-c${i}-trail`,\n content: ` ${cell.trailing.char}`,\n fg: cell.trailing.fg,\n height: 1,\n wrapMode: 'none'\n })\n );\n }\n row.add(cellBox);\n });\n return row;\n}\n\nfunction removeAllChildren(node: BoxRenderable): void {\n const ids = node.getChildren().map((c) => c.id);\n for (const id of ids) node.remove(id);\n}\n\nfunction matrixTitle(matrix: Matrix, state: State): string {\n const visible = state.visibleKeys.length;\n const total = matrix.keys.length;\n const parts: string[] = [`${total} keys`];\n if (state.driftOnly) parts.push(`drift ${visible}/${total}`);\n else if (state.filter && visible !== total) {\n parts.push(`\"${state.filter}\" ${visible}/${total}`);\n }\n return ` Matrix · ${parts.join(' · ')} `;\n}\n\nfunction formatValue(value: string | undefined, secret: boolean): string {\n if (value === undefined) return '';\n if (secret) return maskValue(value);\n return value;\n}\n\nfunction matchesFilter(key: string, filter: string): boolean {\n if (!filter) return true;\n return key.toLowerCase().includes(filter.toLowerCase());\n}\n\nfunction truncate(text: string, width: number): string {\n if (width <= 0) return '';\n if (text.length <= width) return text;\n if (width <= 1) return '…';\n return `${text.slice(0, width - 1)}…`;\n}\n\nfunction findKvEntry(file: EnvFile, key: string): KvEntry | undefined {\n for (const e of file.entries) {\n if (e.kind === 'kv' && e.key === key) return e;\n }\n return undefined;\n}\n"],"names":["i"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"mask-Bv9W6Ei8.mjs","sources":["../../src/core/serialize.ts","../../src/core/mask.ts"],"sourcesContent":["import type { EnvFile, KvEntry, Quoting } from './types.ts';\n\n/**\n * Serialize an {@link EnvFile} back to a string. Unchanged entries are emitted\n * from their captured `raw` line so round-trip is byte-exact; modified entries\n * must have their `raw` field re-built via {@link rebuildKvLine} first.\n */\nexport function serializeEnv(file: EnvFile): string {\n const body = file.entries.map((e) => e.raw).join('\\n');\n return file.trailingNewline ? `${body}\\n` : body;\n}\n\n/**\n * Rebuild the `raw` line of a kv entry from its structured fields. Call this\n * after mutating `key`, `value`, `quoting`, or `exportPrefix` so the next\n * serialize emits the new line.\n */\nexport function rebuildKvLine(entry: KvEntry): void {\n const prefix = entry.exportPrefix ? 'export ' : '';\n const encoded = encodeValue(entry.value, entry.quoting);\n // Update rawValue to match the (possibly new) encoded inner form.\n entry.rawValue = encoded.inner;\n entry.raw = `${prefix}${entry.key}=${encoded.full}${entry.inlineComment}`;\n}\n\ninterface EncodedValue {\n /** Inner string without surrounding quotes (for `rawValue`). */\n inner: string;\n /** Fully formed value including surrounding quotes if any. */\n full: string;\n}\n\nfunction encodeValue(value: string, quoting: Quoting): EncodedValue {\n // Auto-promote to double quotes when an unquoted value would be ambiguous\n // (contains whitespace, `#`, or characters that require escaping). Single\n // quotes are preserved as authored but can't represent embedded `'`.\n const effective: Quoting = needsQuoting(value, quoting) ? 'double' : quoting;\n\n switch (effective) {\n case 'none':\n return { inner: value, full: value };\n case 'single': {\n if (value.includes(\"'\")) {\n // Fall back to double-quoting if a single quote sneaks in.\n const escaped = escapeDoubleQuoted(value);\n return { inner: escaped, full: `\"${escaped}\"` };\n }\n return { inner: value, full: `'${value}'` };\n }\n case 'double': {\n const escaped = escapeDoubleQuoted(value);\n return { inner: escaped, full: `\"${escaped}\"` };\n }\n }\n}\n\nfunction needsQuoting(value: string, current: Quoting): boolean {\n if (current !== 'none') return false;\n return /[\\s#\"'\\\\]/.test(value);\n}\n\nfunction escapeDoubleQuoted(value: string): string {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\t/g, '\\\\t');\n}\n","const SECRET_TOKENS = [\n 'SECRET',\n 'TOKEN',\n 'PASSWORD',\n 'PASSWD',\n 'PWD',\n 'KEY',\n 'PRIVATE',\n 'CREDENTIAL',\n 'AUTH',\n 'DSN'\n] as const;\n\n/**\n * Heuristic: should a value with this key be masked by default? Matches any\n * underscore-separated segment of {@link SECRET_TOKENS} (case-insensitive),\n * with carve-outs for false positives like `*_PUBLIC_KEY`, `PUBLIC_*`, and\n * keys whose final segment is `ID` (e.g. `API_KEY_ID` is an identifier, not\n * a secret).\n */\nexport function isSecretKey(key: string): boolean {\n const upper = key.toUpperCase();\n const segments = upper.split('_').filter(Boolean);\n if (segments.length === 0) return false;\n if (segments[segments.length - 1] === 'ID') return false;\n if (segments[0] === 'PUBLIC') return false;\n if (segments.includes('PUBLIC')) return false;\n\n return segments.some((seg) =>\n SECRET_TOKENS.some((token) => seg === token || seg.endsWith(token))\n );\n}\n\n/**\n * Render a masked placeholder that hints at the original value's length\n * without leaking content. Returns `••••` when the input is empty.\n */\nexport function maskValue(value: string): string {\n if (value.length === 0) return '••••';\n const dots = '•'.repeat(Math.min(value.length, 8));\n return value.length > 8 ? `${dots} (${value.length})` : dots;\n}\n"],"names":[],"mappings":"AAOO,SAAS,aAAa,MAAuB;AAClD,QAAM,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,IAAI;AACrD,SAAO,KAAK,kBAAkB,GAAG,IAAI;AAAA,IAAO;AAC9C;AAOO,SAAS,cAAc,OAAsB;AAClD,QAAM,SAAS,MAAM,eAAe,YAAY;AAChD,QAAM,UAAU,YAAY,MAAM,OAAO,MAAM,OAAO;AAEtD,QAAM,WAAW,QAAQ;AACzB,QAAM,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,QAAQ,IAAI,GAAG,MAAM,aAAa;AACzE;AASA,SAAS,YAAY,OAAe,SAAgC;AAIlE,QAAM,YAAqB,aAAa,OAAO,OAAO,IAAI,WAAW;AAErE,UAAQ,WAAA;AAAA,IACN,KAAK;AACH,aAAO,EAAE,OAAO,OAAO,MAAM,MAAA;AAAA,IAC/B,KAAK,UAAU;AACb,UAAI,MAAM,SAAS,GAAG,GAAG;AAEvB,cAAM,UAAU,mBAAmB,KAAK;AACxC,eAAO,EAAE,OAAO,SAAS,MAAM,IAAI,OAAO,IAAA;AAAA,MAC5C;AACA,aAAO,EAAE,OAAO,OAAO,MAAM,IAAI,KAAK,IAAA;AAAA,IACxC;AAAA,IACA,KAAK,UAAU;AACb,YAAM,UAAU,mBAAmB,KAAK;AACxC,aAAO,EAAE,OAAO,SAAS,MAAM,IAAI,OAAO,IAAA;AAAA,IAC5C;AAAA,EAAA;AAEJ;AAEA,SAAS,aAAa,OAAe,SAA2B;AAC9D,MAAI,YAAY,OAAQ,QAAO;AAC/B,SAAO,YAAY,KAAK,KAAK;AAC/B;AAEA,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MACJ,QAAQ,OAAO,MAAM,EACrB,QAAQ,MAAM,KAAK,EACnB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK;AACzB;ACpEA,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASO,SAAS,YAAY,KAAsB;AAChD,QAAM,QAAQ,IAAI,YAAA;AAClB,QAAM,WAAW,MAAM,MAAM,GAAG,EAAE,OAAO,OAAO;AAChD,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,MAAI,SAAS,SAAS,SAAS,CAAC,MAAM,KAAM,QAAO;AACnD,MAAI,SAAS,CAAC,MAAM,SAAU,QAAO;AACrC,MAAI,SAAS,SAAS,QAAQ,EAAG,QAAO;AAExC,SAAO,SAAS;AAAA,IAAK,CAAC,QACpB,cAAc,KAAK,CAAC,UAAU,QAAQ,SAAS,IAAI,SAAS,KAAK,CAAC;AAAA,EAAA;AAEtE;AAMO,SAAS,UAAU,OAAuB;AAC/C,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,OAAO,IAAI,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC,CAAC;AACjD,SAAO,MAAM,SAAS,IAAI,GAAG,IAAI,KAAK,MAAM,MAAM,MAAM;AAC1D;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"matrix-nBq_GY2v.mjs","sources":["../../src/core/base.ts","../../src/core/diff.ts","../../src/core/parse.ts","../../src/core/discover.ts","../../src/core/sections.ts","../../src/core/matrix.ts"],"sourcesContent":["import { basename } from 'pathe';\nimport type { EnvFile } from './types.ts';\n\n/**\n * Resolve which {@link EnvFile} acts as the base (reference) for diff. Order:\n *\n * 1. `override` path argument, matched by full path or basename.\n * 2. `.env.example` if present.\n * 3. The first file (already sorted by {@link discoverEnvFiles}).\n *\n * Returns `null` if `files` is empty.\n */\nexport function resolveBase(\n files: EnvFile[],\n override?: string\n): EnvFile | null {\n if (files.length === 0) return null;\n\n if (override) {\n const match = files.find(\n (f) => f.path === override || basename(f.path) === override\n );\n if (!match) {\n throw new Error(\n `--base ${override} did not match any discovered env file`\n );\n }\n return match;\n }\n\n const example = files.find((f) => basename(f.path) === '.env.example');\n if (example) return example;\n\n return files[0] ?? null;\n}\n","import { basename } from 'pathe';\nimport type { Matrix, CellState } from './matrix.ts';\nimport type { EnvFile } from './types.ts';\n\nexport interface DiffReport {\n base: string;\n /** Compared files, excluding the base. */\n files: DiffFileReport[];\n /** True when no non-base cell is `differs`, `missing`, or `extra`. */\n inSync: boolean;\n}\n\nexport interface DiffFileReport {\n path: string;\n keys: Record<string, CellState>;\n /** Number of keys with state !== 'same'. */\n drift: number;\n}\n\nconst DRIFT_STATES: ReadonlySet<CellState> = new Set([\n 'differs',\n 'missing',\n 'extra'\n]);\n\nexport function computeDiff(matrix: Matrix): DiffReport {\n const others = matrix.files.filter((f) => f !== matrix.base);\n const files = others.map((f) => buildFileReport(matrix, f));\n return {\n base: matrix.base.path,\n files,\n inSync: files.every((f) => f.drift === 0)\n };\n}\n\nfunction buildFileReport(matrix: Matrix, file: EnvFile): DiffFileReport {\n const keys: Record<string, CellState> = {};\n let drift = 0;\n for (const key of matrix.keys) {\n const { state } = matrix.cell(key, file);\n keys[key] = state;\n if (DRIFT_STATES.has(state)) drift++;\n }\n return { path: file.path, keys, drift };\n}\n\nexport function formatDiffText(report: DiffReport): string {\n const baseName = basename(report.base);\n const otherNames = report.files.map((f) => basename(f.path));\n const lines: string[] = [];\n lines.push(`Base: ${baseName} (vs. ${otherNames.join(', ')})`);\n lines.push('');\n\n if (report.files.length === 0) {\n lines.push('No other env files to compare.');\n return lines.join('\\n') + '\\n';\n }\n\n const driftKeys = new Set<string>();\n for (const f of report.files) {\n for (const [k, s] of Object.entries(f.keys)) {\n if (DRIFT_STATES.has(s)) driftKeys.add(k);\n }\n }\n\n if (driftKeys.size === 0) {\n lines.push('All env files are in sync with the base.');\n return lines.join('\\n') + '\\n';\n }\n\n const keyWidth = Math.max(3, ...[...driftKeys].map((k) => k.length));\n const colWidth = Math.max(12, ...otherNames.map((n) => n.length));\n\n lines.push(\n formatRow('KEY', otherNames, keyWidth, colWidth, (n) => n.padEnd(colWidth))\n );\n for (const key of [...driftKeys].sort()) {\n const cells = report.files.map((f) => stateLabel(f.keys[key] ?? 'missing'));\n lines.push(\n formatRow(key, cells, keyWidth, colWidth, (n) => n.padEnd(colWidth))\n );\n }\n\n lines.push('');\n const totalDrift = report.files.reduce((sum, f) => sum + f.drift, 0);\n lines.push(\n `${driftKeys.size} key(s) differ across ${report.files.length} file(s) (${totalDrift} cell drift).`\n );\n\n return lines.join('\\n') + '\\n';\n}\n\nfunction formatRow(\n key: string,\n cells: string[],\n keyWidth: number,\n colWidth: number,\n pad: (s: string) => string\n): string {\n return [key.padEnd(keyWidth), ...cells.map(pad)].join(' ');\n}\n\nfunction stateLabel(state: CellState): string {\n switch (state) {\n case 'same':\n return '— same';\n case 'differs':\n return '≠ differs';\n case 'missing':\n return '✗ missing';\n case 'extra':\n return '★ extra';\n case 'base':\n return '· base';\n }\n}\n","import type { EnvEntry, EnvFile, KvEntry, Quoting } from './types.ts';\n\nconst KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\n/**\n * Parse a `.env` file into a structured, round-trippable representation.\n * Each entry stores its original raw line so the serializer can emit it\n * byte-for-byte when nothing changes.\n */\nexport function parseEnv(source: string, path = ''): EnvFile {\n const trailingNewline = source.endsWith('\\n');\n const body = trailingNewline ? source.slice(0, -1) : source;\n const lines = body.length === 0 ? [] : body.split('\\n');\n\n const entries: EnvEntry[] = [];\n for (const raw of lines) {\n entries.push(parseLine(raw));\n }\n\n return { path, entries, trailingNewline };\n}\n\nfunction parseLine(raw: string): EnvEntry {\n if (raw.trim().length === 0) {\n return { kind: 'blank', raw };\n }\n\n // Comment line: leading whitespace then `#`.\n const trimmedStart = raw.replace(/^\\s+/, '');\n if (trimmedStart.startsWith('#')) {\n return { kind: 'comment', raw };\n }\n\n const kv = tryParseKv(raw);\n if (kv) return kv;\n\n // Unrecognised line — treat as a comment-like passthrough so round-trip\n // still works. Diff/matrix code ignores non-kv entries.\n return { kind: 'comment', raw };\n}\n\nfunction tryParseKv(raw: string): KvEntry | null {\n let rest = raw;\n // Optional leading whitespace is preserved in `raw`; the structured key\n // identifier itself is captured separately so we can rebuild the line.\n const leadingWs = rest.match(/^[ \\t]*/)?.[0] ?? '';\n rest = rest.slice(leadingWs.length);\n\n let exportPrefix = false;\n if (rest.startsWith('export ')) {\n exportPrefix = true;\n rest = rest.slice('export '.length).replace(/^[ \\t]*/, '');\n }\n\n const eqIdx = rest.indexOf('=');\n if (eqIdx < 0) return null;\n\n const key = rest.slice(0, eqIdx).trimEnd();\n if (!KEY_RE.test(key)) return null;\n\n const after = rest.slice(eqIdx + 1);\n const valueStart = after.replace(/^[ \\t]*/, '');\n const valueLeadingWs = after.slice(0, after.length - valueStart.length);\n\n const parsed = parseValue(valueStart);\n if (!parsed) return null;\n\n // Preserve trailing whitespace before any inline comment so round-trip\n // matches the source exactly (we don't need to model it separately — `raw`\n // is what gets emitted).\n void leadingWs;\n void valueLeadingWs;\n\n return {\n kind: 'kv',\n key,\n rawValue: parsed.rawValue,\n value: parsed.value,\n quoting: parsed.quoting,\n exportPrefix,\n inlineComment: parsed.inlineComment,\n raw\n };\n}\n\ninterface ParsedValue {\n rawValue: string;\n value: string;\n quoting: Quoting;\n inlineComment: string;\n}\n\nfunction parseValue(input: string): ParsedValue | null {\n if (input.length === 0) {\n return { rawValue: '', value: '', quoting: 'none', inlineComment: '' };\n }\n\n const first = input[0];\n if (first === '\"' || first === \"'\") {\n const close = findClosingQuote(input, first);\n if (close < 0) return null;\n const rawValue = input.slice(1, close);\n const value = first === '\"' ? decodeDoubleQuoted(rawValue) : rawValue;\n const tail = input.slice(close + 1);\n const inlineComment = extractInlineComment(tail);\n return {\n rawValue,\n value,\n quoting: first === '\"' ? 'double' : 'single',\n inlineComment\n };\n }\n\n // Unquoted: value runs until ` #` or end-of-line, trailing whitespace\n // belongs to the inline-comment slot (so round-trip is preserved via `raw`).\n const hashIdx = findUnquotedCommentStart(input);\n const valuePart = (hashIdx < 0 ? input : input.slice(0, hashIdx)).trimEnd();\n const inlineComment = hashIdx < 0 ? '' : input.slice(valuePart.length);\n return {\n rawValue: valuePart,\n value: valuePart,\n quoting: 'none',\n inlineComment\n };\n}\n\nfunction findClosingQuote(input: string, quote: '\"' | \"'\"): number {\n for (let i = 1; i < input.length; i++) {\n const ch = input[i];\n if (quote === '\"' && ch === '\\\\') {\n i++;\n continue;\n }\n if (ch === quote) return i;\n }\n return -1;\n}\n\nfunction findUnquotedCommentStart(input: string): number {\n for (let i = 0; i < input.length; i++) {\n if (input[i] !== '#') continue;\n if (i === 0) return i;\n const prev = input[i - 1];\n if (prev === ' ' || prev === '\\t') return i;\n }\n return -1;\n}\n\nfunction extractInlineComment(tail: string): string {\n // Tail is everything after the closing quote. It is either empty, pure\n // whitespace, or whitespace + `#...`. Preserve it verbatim.\n return tail;\n}\n\nfunction decodeDoubleQuoted(raw: string): string {\n return raw.replace(/\\\\(.)/g, (_, ch: string) => {\n switch (ch) {\n case 'n':\n return '\\n';\n case 'r':\n return '\\r';\n case 't':\n return '\\t';\n case '\\\\':\n return '\\\\';\n case '\"':\n return '\"';\n default:\n return `\\\\${ch}`;\n }\n });\n}\n","import { readdir, readFile, stat } from 'node:fs/promises';\nimport { basename, join } from 'pathe';\nimport { parseEnv } from './parse.ts';\nimport type { EnvFile } from './types.ts';\n\nconst SKIP_SUFFIXES = ['.swp', '~', '.bak'];\n\n/**\n * Discover `.env*` files in the given path(s). Each path may be a directory\n * (glob-like discovery happens at its top level) or an explicit file. Editor\n * and backup files are skipped.\n *\n * Files are returned sorted: `.env.example` first if present, then the rest\n * alphabetically. Base-resolution lives in `base.ts` and depends on this order.\n */\nexport async function discoverEnvFiles(paths: string[]): Promise<EnvFile[]> {\n const filePaths = new Set<string>();\n\n for (const p of paths) {\n const info = await stat(p);\n if (info.isDirectory()) {\n const entries = await readdir(p);\n for (const name of entries) {\n if (!looksLikeEnvFile(name)) continue;\n filePaths.add(join(p, name));\n }\n } else {\n filePaths.add(p);\n }\n }\n\n const sorted = [...filePaths].sort(envPathOrder);\n const files: EnvFile[] = [];\n for (const filePath of sorted) {\n const source = await readFile(filePath, 'utf8');\n files.push(parseEnv(source, filePath));\n }\n return files;\n}\n\nfunction looksLikeEnvFile(name: string): boolean {\n if (!name.startsWith('.env')) return false;\n if (SKIP_SUFFIXES.some((s) => name.endsWith(s))) return false;\n return true;\n}\n\nfunction envPathOrder(a: string, b: string): number {\n const an = basename(a);\n const bn = basename(b);\n if (an === '.env.example') return -1;\n if (bn === '.env.example') return 1;\n return an.localeCompare(bn);\n}\n","import type { EnvEntry, EnvFile } from './types.ts';\n\nconst SEP_CHARS = new Set(['=', '-', '#', '~', '*']);\nconst SPACE_CHARS = new Set([' ', '\\t']);\n\n/**\n * Walk the base file in source order and decide which section each kv entry\n * belongs to. Returns a `key → section` map; keys with no inferred section\n * are absent from the map.\n *\n * A \"section header\" is one of:\n * 1. An inline banner: `# === Section name ===` (or `---`, `~~~`, `***`).\n * 2. A block banner — a single comment line `# Section name` whose\n * immediately preceding or following comment line is purely decorative\n * (e.g. `# ===========================`).\n *\n * The detected name applies to every subsequent kv entry until the next\n * detected section header.\n */\nexport function computeSections(base: EnvFile): Map<string, string> {\n const out = new Map<string, string>();\n let current: string | null = null;\n for (let i = 0; i < base.entries.length; i++) {\n const name = detectSectionName(base.entries, i);\n if (name !== null) current = name;\n const e = base.entries[i]!;\n if (e.kind === 'kv' && current) out.set(e.key, current);\n }\n return out;\n}\n\nfunction detectSectionName(entries: EnvEntry[], idx: number): string | null {\n const e = entries[idx];\n if (!e || e.kind !== 'comment') return null;\n if (isDecorativeLine(e.raw)) return null;\n\n const inline = parseInlineBanner(e.raw);\n if (inline !== null) return inline;\n\n const text = stripCommentPrefix(e.raw);\n if (!text) return null;\n\n if (isDecorative(entries[idx - 1]) || isDecorative(entries[idx + 1])) {\n return text;\n }\n return null;\n}\n\nfunction isDecorative(e: EnvEntry | undefined): boolean {\n if (!e || e.kind !== 'comment') return false;\n return isDecorativeLine(e.raw);\n}\n\n/**\n * True for comment lines whose body is nothing but separator chars and\n * whitespace (e.g. \"# ======\", \"###\", \"# -=-=-=-\").\n *\n * Implemented with a manual scan rather than a regex with overlapping\n * `\\s*` / `[\\s…]+` groups, which CodeQL flags as ReDoS-prone.\n */\nfunction isDecorativeLine(raw: string): boolean {\n const start = skipSpaces(raw, 0);\n if (start >= raw.length || raw[start] !== '#') return false;\n let i = start + 1;\n let sawSeparator = false;\n while (i < raw.length) {\n const ch = raw[i]!;\n if (SEP_CHARS.has(ch)) sawSeparator = true;\n else if (!SPACE_CHARS.has(ch)) return false;\n i++;\n }\n return sawSeparator;\n}\n\n/**\n * Parse a single-line inline banner like `# === Name ===` (also `---`,\n * `~~~`, `***`) and return the inner name, or null if the line isn't an\n * inline banner.\n *\n * Manual scan, again to avoid the overlapping `\\s*` regex backtracking\n * CodeQL warned about.\n */\nfunction parseInlineBanner(raw: string): string | null {\n const start = skipSpaces(raw, 0);\n if (start >= raw.length || raw[start] !== '#') return null;\n\n // After '#', skip spaces, then read 2+ separator chars (single char repeated).\n let i = skipSpaces(raw, start + 1);\n if (i >= raw.length || !SEP_CHARS.has(raw[i]!)) return null;\n let leadCount = 0;\n while (i < raw.length && SEP_CHARS.has(raw[i]!)) {\n leadCount++;\n i++;\n }\n if (leadCount < 2) return null;\n\n // Walk from the end inward to find the trailing separator run.\n let j = raw.length;\n while (j > i && SPACE_CHARS.has(raw[j - 1]!)) j--;\n if (j <= i || !SEP_CHARS.has(raw[j - 1]!)) return null;\n let trailCount = 0;\n while (j > i && SEP_CHARS.has(raw[j - 1]!)) {\n trailCount++;\n j--;\n }\n if (trailCount < 2) return null;\n\n // Between the two separator runs lives the name (after stripping spaces).\n const inner = raw.slice(i, j).trim();\n return inner.length > 0 ? inner : null;\n}\n\nfunction stripCommentPrefix(raw: string): string {\n // Leading whitespace, then one or more '#', then whitespace, then content.\n let i = skipSpaces(raw, 0);\n while (i < raw.length && raw[i] === '#') i++;\n i = skipSpaces(raw, i);\n // Trim trailing whitespace and decorative chars.\n let j = raw.length;\n while (\n j > i &&\n (SPACE_CHARS.has(raw[j - 1]!) || SEP_CHARS.has(raw[j - 1]!))\n ) {\n j--;\n }\n return raw.slice(i, j);\n}\n\nfunction skipSpaces(raw: string, from: number): number {\n let i = from;\n while (i < raw.length && SPACE_CHARS.has(raw[i]!)) i++;\n return i;\n}\n","import { computeSections } from './sections.ts';\nimport type { EnvFile, KvEntry } from './types.ts';\n\nexport type CellState = 'same' | 'differs' | 'missing' | 'extra' | 'base';\n\nexport interface Cell {\n state: CellState;\n /** Decoded value if present in this file, else `undefined`. */\n value: string | undefined;\n}\n\nexport interface Matrix {\n /** Union of all keys across all files, base keys first (in source order). */\n keys: string[];\n /** Files in display order; base is included. */\n files: EnvFile[];\n base: EnvFile;\n cell(key: string, file: EnvFile): Cell;\n /**\n * Section name inferred from the base file's comment banners, or\n * `undefined` for keys outside any section (and for keys only present in\n * non-base files).\n */\n sectionOf(key: string): string | undefined;\n}\n\nexport function buildMatrix(files: EnvFile[], base: EnvFile): Matrix {\n const keys = collectKeys(files, base);\n const lookups = new Map<EnvFile, Map<string, KvEntry>>();\n for (const file of files) {\n lookups.set(file, indexKv(file));\n }\n const baseIndex = lookups.get(base);\n if (!baseIndex) {\n throw new Error('base file is not in the files list');\n }\n const sections = computeSections(base);\n\n return {\n keys,\n files,\n base,\n sectionOf(key) {\n return sections.get(key);\n },\n cell(key, file) {\n const ownIndex = lookups.get(file);\n if (!ownIndex) {\n throw new Error(`file not in matrix: ${file.path}`);\n }\n const own = ownIndex.get(key);\n const baseEntry = baseIndex.get(key);\n\n if (file === base) {\n return {\n state: own ? 'base' : 'missing',\n value: own?.value\n };\n }\n\n if (!own && !baseEntry) {\n return { state: 'missing', value: undefined };\n }\n if (!own) {\n return { state: 'missing', value: undefined };\n }\n if (!baseEntry) {\n return { state: 'extra', value: own.value };\n }\n return {\n state: own.value === baseEntry.value ? 'same' : 'differs',\n value: own.value\n };\n }\n };\n}\n\nfunction collectKeys(files: EnvFile[], base: EnvFile): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n\n // Base file keys first in their authored order so the matrix view tracks\n // the .env.example layout most users curate.\n for (const e of base.entries) {\n if (e.kind === 'kv' && !seen.has(e.key)) {\n seen.add(e.key);\n out.push(e.key);\n }\n }\n // Then any extras only present in non-base files, in alpha order so the\n // result is deterministic.\n const extras = new Set<string>();\n for (const file of files) {\n if (file === base) continue;\n for (const e of file.entries) {\n if (e.kind === 'kv' && !seen.has(e.key)) {\n extras.add(e.key);\n }\n }\n }\n for (const k of [...extras].sort()) out.push(k);\n return out;\n}\n\nfunction indexKv(file: EnvFile): Map<string, KvEntry> {\n const m = new Map<string, KvEntry>();\n for (const e of file.entries) {\n if (e.kind === 'kv') m.set(e.key, e);\n }\n return m;\n}\n"],"names":["inlineComment"],"mappings":";;AAYO,SAAS,YACd,OACA,UACgB;AAChB,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,MAAI,UAAU;AACZ,UAAM,QAAQ,MAAM;AAAA,MAClB,CAAC,MAAM,EAAE,SAAS,YAAY,SAAS,EAAE,IAAI,MAAM;AAAA,IAAA;AAErD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR,UAAU,QAAQ;AAAA,MAAA;AAAA,IAEtB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM,KAAK,CAAC,MAAM,SAAS,EAAE,IAAI,MAAM,cAAc;AACrE,MAAI,QAAS,QAAO;AAEpB,SAAO,MAAM,CAAC,KAAK;AACrB;ACfA,MAAM,mCAA2C,IAAI;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,YAAY,QAA4B;AACtD,QAAM,SAAS,OAAO,MAAM,OAAO,CAAC,MAAM,MAAM,OAAO,IAAI;AAC3D,QAAM,QAAQ,OAAO,IAAI,CAAC,MAAM,gBAAgB,QAAQ,CAAC,CAAC;AAC1D,SAAO;AAAA,IACL,MAAM,OAAO,KAAK;AAAA,IAClB;AAAA,IACA,QAAQ,MAAM,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;AAAA,EAAA;AAE5C;AAEA,SAAS,gBAAgB,QAAgB,MAA+B;AACtE,QAAM,OAAkC,CAAA;AACxC,MAAI,QAAQ;AACZ,aAAW,OAAO,OAAO,MAAM;AAC7B,UAAM,EAAE,MAAA,IAAU,OAAO,KAAK,KAAK,IAAI;AACvC,SAAK,GAAG,IAAI;AACZ,QAAI,aAAa,IAAI,KAAK,EAAG;AAAA,EAC/B;AACA,SAAO,EAAE,MAAM,KAAK,MAAM,MAAM,MAAA;AAClC;AAEO,SAAS,eAAe,QAA4B;AACzD,QAAM,WAAW,SAAS,OAAO,IAAI;AACrC,QAAM,aAAa,OAAO,MAAM,IAAI,CAAC,MAAM,SAAS,EAAE,IAAI,CAAC;AAC3D,QAAM,QAAkB,CAAA;AACxB,QAAM,KAAK,SAAS,QAAQ,UAAU,WAAW,KAAK,IAAI,CAAC,GAAG;AAC9D,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,MAAM,WAAW,GAAG;AAC7B,UAAM,KAAK,gCAAgC;AAC3C,WAAO,MAAM,KAAK,IAAI,IAAI;AAAA,EAC5B;AAEA,QAAM,gCAAgB,IAAA;AACtB,aAAW,KAAK,OAAO,OAAO;AAC5B,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,EAAE,IAAI,GAAG;AAC3C,UAAI,aAAa,IAAI,CAAC,EAAG,WAAU,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AAEA,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,KAAK,0CAA0C;AACrD,WAAO,MAAM,KAAK,IAAI,IAAI;AAAA,EAC5B;AAEA,QAAM,WAAW,KAAK,IAAI,GAAG,GAAG,CAAC,GAAG,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AACnE,QAAM,WAAW,KAAK,IAAI,IAAI,GAAG,WAAW,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AAEhE,QAAM;AAAA,IACJ,UAAU,OAAO,YAAY,UAAU,UAAU,CAAC,MAAM,EAAE,OAAO,QAAQ,CAAC;AAAA,EAAA;AAE5E,aAAW,OAAO,CAAC,GAAG,SAAS,EAAE,QAAQ;AACvC,UAAM,QAAQ,OAAO,MAAM,IAAI,CAAC,MAAM,WAAW,EAAE,KAAK,GAAG,KAAK,SAAS,CAAC;AAC1E,UAAM;AAAA,MACJ,UAAU,KAAK,OAAO,UAAU,UAAU,CAAC,MAAM,EAAE,OAAO,QAAQ,CAAC;AAAA,IAAA;AAAA,EAEvE;AAEA,QAAM,KAAK,EAAE;AACb,QAAM,aAAa,OAAO,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AACnE,QAAM;AAAA,IACJ,GAAG,UAAU,IAAI,yBAAyB,OAAO,MAAM,MAAM,aAAa,UAAU;AAAA,EAAA;AAGtF,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;AAEA,SAAS,UACP,KACA,OACA,UACA,UACA,KACQ;AACR,SAAO,CAAC,IAAI,OAAO,QAAQ,GAAG,GAAG,MAAM,IAAI,GAAG,CAAC,EAAE,KAAK,IAAI;AAC5D;AAEA,SAAS,WAAW,OAA0B;AAC5C,UAAQ,OAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EAAA;AAEb;ACjHA,MAAM,SAAS;AAOR,SAAS,SAAS,QAAgB,OAAO,IAAa;AAC3D,QAAM,kBAAkB,OAAO,SAAS,IAAI;AAC5C,QAAM,OAAO,kBAAkB,OAAO,MAAM,GAAG,EAAE,IAAI;AACrD,QAAM,QAAQ,KAAK,WAAW,IAAI,CAAA,IAAK,KAAK,MAAM,IAAI;AAEtD,QAAM,UAAsB,CAAA;AAC5B,aAAW,OAAO,OAAO;AACvB,YAAQ,KAAK,UAAU,GAAG,CAAC;AAAA,EAC7B;AAEA,SAAO,EAAE,MAAM,SAAS,gBAAA;AAC1B;AAEA,SAAS,UAAU,KAAuB;AACxC,MAAI,IAAI,OAAO,WAAW,GAAG;AAC3B,WAAO,EAAE,MAAM,SAAS,IAAA;AAAA,EAC1B;AAGA,QAAM,eAAe,IAAI,QAAQ,QAAQ,EAAE;AAC3C,MAAI,aAAa,WAAW,GAAG,GAAG;AAChC,WAAO,EAAE,MAAM,WAAW,IAAA;AAAA,EAC5B;AAEA,QAAM,KAAK,WAAW,GAAG;AACzB,MAAI,GAAI,QAAO;AAIf,SAAO,EAAE,MAAM,WAAW,IAAA;AAC5B;AAEA,SAAS,WAAW,KAA6B;AAC/C,MAAI,OAAO;AAGX,QAAM,YAAY,KAAK,MAAM,SAAS,IAAI,CAAC,KAAK;AAChD,SAAO,KAAK,MAAM,UAAU,MAAM;AAElC,MAAI,eAAe;AACnB,MAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,mBAAe;AACf,WAAO,KAAK,MAAM,UAAU,MAAM,EAAE,QAAQ,WAAW,EAAE;AAAA,EAC3D;AAEA,QAAM,QAAQ,KAAK,QAAQ,GAAG;AAC9B,MAAI,QAAQ,EAAG,QAAO;AAEtB,QAAM,MAAM,KAAK,MAAM,GAAG,KAAK,EAAE,QAAA;AACjC,MAAI,CAAC,OAAO,KAAK,GAAG,EAAG,QAAO;AAE9B,QAAM,QAAQ,KAAK,MAAM,QAAQ,CAAC;AAClC,QAAM,aAAa,MAAM,QAAQ,WAAW,EAAE;AACvB,QAAM,MAAM,GAAG,MAAM,SAAS,WAAW,MAAM;AAEtE,QAAM,SAAS,WAAW,UAAU;AACpC,MAAI,CAAC,OAAQ,QAAO;AAQpB,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,UAAU,OAAO;AAAA,IACjB,OAAO,OAAO;AAAA,IACd,SAAS,OAAO;AAAA,IAChB;AAAA,IACA,eAAe,OAAO;AAAA,IACtB;AAAA,EAAA;AAEJ;AASA,SAAS,WAAW,OAAmC;AACrD,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,EAAE,UAAU,IAAI,OAAO,IAAI,SAAS,QAAQ,eAAe,GAAA;AAAA,EACpE;AAEA,QAAM,QAAQ,MAAM,CAAC;AACrB,MAAI,UAAU,OAAO,UAAU,KAAK;AAClC,UAAM,QAAQ,iBAAiB,OAAO,KAAK;AAC3C,QAAI,QAAQ,EAAG,QAAO;AACtB,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK;AACrC,UAAM,QAAQ,UAAU,MAAM,mBAAmB,QAAQ,IAAI;AAC7D,UAAM,OAAO,MAAM,MAAM,QAAQ,CAAC;AAClC,UAAMA,iBAAgB,qBAAqB,IAAI;AAC/C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,SAAS,UAAU,MAAM,WAAW;AAAA,MACpC,eAAAA;AAAAA,IAAA;AAAA,EAEJ;AAIA,QAAM,UAAU,yBAAyB,KAAK;AAC9C,QAAM,aAAa,UAAU,IAAI,QAAQ,MAAM,MAAM,GAAG,OAAO,GAAG,QAAA;AAClE,QAAM,gBAAgB,UAAU,IAAI,KAAK,MAAM,MAAM,UAAU,MAAM;AACrE,SAAO;AAAA,IACL,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT;AAAA,EAAA;AAEJ;AAEA,SAAS,iBAAiB,OAAe,OAA0B;AACjE,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,KAAK,MAAM,CAAC;AAClB,QAAI,UAAU,OAAO,OAAO,MAAM;AAChC;AACA;AAAA,IACF;AACA,QAAI,OAAO,MAAO,QAAO;AAAA,EAC3B;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,OAAuB;AACvD,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAI,MAAM,CAAC,MAAM,IAAK;AACtB,QAAI,MAAM,EAAG,QAAO;AACpB,UAAM,OAAO,MAAM,IAAI,CAAC;AACxB,QAAI,SAAS,OAAO,SAAS,IAAM,QAAO;AAAA,EAC5C;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,MAAsB;AAGlD,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAqB;AAC/C,SAAO,IAAI,QAAQ,UAAU,CAAC,GAAG,OAAe;AAC9C,YAAQ,IAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO,KAAK,EAAE;AAAA,IAAA;AAAA,EAEpB,CAAC;AACH;ACtKA,MAAM,gBAAgB,CAAC,QAAQ,KAAK,MAAM;AAU1C,eAAsB,iBAAiB,OAAqC;AAC1E,QAAM,gCAAgB,IAAA;AAEtB,aAAW,KAAK,OAAO;AACrB,UAAM,OAAO,MAAM,KAAK,CAAC;AACzB,QAAI,KAAK,eAAe;AACtB,YAAM,UAAU,MAAM,QAAQ,CAAC;AAC/B,iBAAW,QAAQ,SAAS;AAC1B,YAAI,CAAC,iBAAiB,IAAI,EAAG;AAC7B,kBAAU,IAAI,KAAK,GAAG,IAAI,CAAC;AAAA,MAC7B;AAAA,IACF,OAAO;AACL,gBAAU,IAAI,CAAC;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,SAAS,CAAC,GAAG,SAAS,EAAE,KAAK,YAAY;AAC/C,QAAM,QAAmB,CAAA;AACzB,aAAW,YAAY,QAAQ;AAC7B,UAAM,SAAS,MAAM,SAAS,UAAU,MAAM;AAC9C,UAAM,KAAK,SAAS,QAAQ,QAAQ,CAAC;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,MAAuB;AAC/C,MAAI,CAAC,KAAK,WAAW,MAAM,EAAG,QAAO;AACrC,MAAI,cAAc,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,EAAG,QAAO;AACxD,SAAO;AACT;AAEA,SAAS,aAAa,GAAW,GAAmB;AAClD,QAAM,KAAK,SAAS,CAAC;AACrB,QAAM,KAAK,SAAS,CAAC;AACrB,MAAI,OAAO,eAAgB,QAAO;AAClC,MAAI,OAAO,eAAgB,QAAO;AAClC,SAAO,GAAG,cAAc,EAAE;AAC5B;AClDA,MAAM,gCAAgB,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AACnD,MAAM,cAAc,oBAAI,IAAI,CAAC,KAAK,GAAI,CAAC;AAgBhC,SAAS,gBAAgB,MAAoC;AAClE,QAAM,0BAAU,IAAA;AAChB,MAAI,UAAyB;AAC7B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,QAAQ,KAAK;AAC5C,UAAM,OAAO,kBAAkB,KAAK,SAAS,CAAC;AAC9C,QAAI,SAAS,KAAM,WAAU;AAC7B,UAAM,IAAI,KAAK,QAAQ,CAAC;AACxB,QAAI,EAAE,SAAS,QAAQ,aAAa,IAAI,EAAE,KAAK,OAAO;AAAA,EACxD;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,SAAqB,KAA4B;AAC1E,QAAM,IAAI,QAAQ,GAAG;AACrB,MAAI,CAAC,KAAK,EAAE,SAAS,UAAW,QAAO;AACvC,MAAI,iBAAiB,EAAE,GAAG,EAAG,QAAO;AAEpC,QAAM,SAAS,kBAAkB,EAAE,GAAG;AACtC,MAAI,WAAW,KAAM,QAAO;AAE5B,QAAM,OAAO,mBAAmB,EAAE,GAAG;AACrC,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI,aAAa,QAAQ,MAAM,CAAC,CAAC,KAAK,aAAa,QAAQ,MAAM,CAAC,CAAC,GAAG;AACpE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,aAAa,GAAkC;AACtD,MAAI,CAAC,KAAK,EAAE,SAAS,UAAW,QAAO;AACvC,SAAO,iBAAiB,EAAE,GAAG;AAC/B;AASA,SAAS,iBAAiB,KAAsB;AAC9C,QAAM,QAAQ,WAAW,KAAK,CAAC;AAC/B,MAAI,SAAS,IAAI,UAAU,IAAI,KAAK,MAAM,IAAK,QAAO;AACtD,MAAI,IAAI,QAAQ;AAChB,MAAI,eAAe;AACnB,SAAO,IAAI,IAAI,QAAQ;AACrB,UAAM,KAAK,IAAI,CAAC;AAChB,QAAI,UAAU,IAAI,EAAE,EAAG,gBAAe;AAAA,aAC7B,CAAC,YAAY,IAAI,EAAE,EAAG,QAAO;AACtC;AAAA,EACF;AACA,SAAO;AACT;AAUA,SAAS,kBAAkB,KAA4B;AACrD,QAAM,QAAQ,WAAW,KAAK,CAAC;AAC/B,MAAI,SAAS,IAAI,UAAU,IAAI,KAAK,MAAM,IAAK,QAAO;AAGtD,MAAI,IAAI,WAAW,KAAK,QAAQ,CAAC;AACjC,MAAI,KAAK,IAAI,UAAU,CAAC,UAAU,IAAI,IAAI,CAAC,CAAE,EAAG,QAAO;AACvD,MAAI,YAAY;AAChB,SAAO,IAAI,IAAI,UAAU,UAAU,IAAI,IAAI,CAAC,CAAE,GAAG;AAC/C;AACA;AAAA,EACF;AACA,MAAI,YAAY,EAAG,QAAO;AAG1B,MAAI,IAAI,IAAI;AACZ,SAAO,IAAI,KAAK,YAAY,IAAI,IAAI,IAAI,CAAC,CAAE,EAAG;AAC9C,MAAI,KAAK,KAAK,CAAC,UAAU,IAAI,IAAI,IAAI,CAAC,CAAE,EAAG,QAAO;AAClD,MAAI,aAAa;AACjB,SAAO,IAAI,KAAK,UAAU,IAAI,IAAI,IAAI,CAAC,CAAE,GAAG;AAC1C;AACA;AAAA,EACF;AACA,MAAI,aAAa,EAAG,QAAO;AAG3B,QAAM,QAAQ,IAAI,MAAM,GAAG,CAAC,EAAE,KAAA;AAC9B,SAAO,MAAM,SAAS,IAAI,QAAQ;AACpC;AAEA,SAAS,mBAAmB,KAAqB;AAE/C,MAAI,IAAI,WAAW,KAAK,CAAC;AACzB,SAAO,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,IAAK;AACzC,MAAI,WAAW,KAAK,CAAC;AAErB,MAAI,IAAI,IAAI;AACZ,SACE,IAAI,MACH,YAAY,IAAI,IAAI,IAAI,CAAC,CAAE,KAAK,UAAU,IAAI,IAAI,IAAI,CAAC,CAAE,IAC1D;AACA;AAAA,EACF;AACA,SAAO,IAAI,MAAM,GAAG,CAAC;AACvB;AAEA,SAAS,WAAW,KAAa,MAAsB;AACrD,MAAI,IAAI;AACR,SAAO,IAAI,IAAI,UAAU,YAAY,IAAI,IAAI,CAAC,CAAE,EAAG;AACnD,SAAO;AACT;AC1GO,SAAS,YAAY,OAAkB,MAAuB;AACnE,QAAM,OAAO,YAAY,OAAO,IAAI;AACpC,QAAM,8BAAc,IAAA;AACpB,aAAW,QAAQ,OAAO;AACxB,YAAQ,IAAI,MAAM,QAAQ,IAAI,CAAC;AAAA,EACjC;AACA,QAAM,YAAY,QAAQ,IAAI,IAAI;AAClC,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,QAAM,WAAW,gBAAgB,IAAI;AAErC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,KAAK;AACb,aAAO,SAAS,IAAI,GAAG;AAAA,IACzB;AAAA,IACA,KAAK,KAAK,MAAM;AACd,YAAM,WAAW,QAAQ,IAAI,IAAI;AACjC,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,uBAAuB,KAAK,IAAI,EAAE;AAAA,MACpD;AACA,YAAM,MAAM,SAAS,IAAI,GAAG;AAC5B,YAAM,YAAY,UAAU,IAAI,GAAG;AAEnC,UAAI,SAAS,MAAM;AACjB,eAAO;AAAA,UACL,OAAO,MAAM,SAAS;AAAA,UACtB,OAAO,KAAK;AAAA,QAAA;AAAA,MAEhB;AAEA,UAAI,CAAC,OAAO,CAAC,WAAW;AACtB,eAAO,EAAE,OAAO,WAAW,OAAO,OAAA;AAAA,MACpC;AACA,UAAI,CAAC,KAAK;AACR,eAAO,EAAE,OAAO,WAAW,OAAO,OAAA;AAAA,MACpC;AACA,UAAI,CAAC,WAAW;AACd,eAAO,EAAE,OAAO,SAAS,OAAO,IAAI,MAAA;AAAA,MACtC;AACA,aAAO;AAAA,QACL,OAAO,IAAI,UAAU,UAAU,QAAQ,SAAS;AAAA,QAChD,OAAO,IAAI;AAAA,MAAA;AAAA,IAEf;AAAA,EAAA;AAEJ;AAEA,SAAS,YAAY,OAAkB,MAAyB;AAC9D,QAAM,2BAAW,IAAA;AACjB,QAAM,MAAgB,CAAA;AAItB,aAAW,KAAK,KAAK,SAAS;AAC5B,QAAI,EAAE,SAAS,QAAQ,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG;AACvC,WAAK,IAAI,EAAE,GAAG;AACd,UAAI,KAAK,EAAE,GAAG;AAAA,IAChB;AAAA,EACF;AAGA,QAAM,6BAAa,IAAA;AACnB,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS,KAAM;AACnB,eAAW,KAAK,KAAK,SAAS;AAC5B,UAAI,EAAE,SAAS,QAAQ,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG;AACvC,eAAO,IAAI,EAAE,GAAG;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,aAAW,KAAK,CAAC,GAAG,MAAM,EAAE,OAAQ,KAAI,KAAK,CAAC;AAC9C,SAAO;AACT;AAEA,SAAS,QAAQ,MAAqC;AACpD,QAAM,wBAAQ,IAAA;AACd,aAAW,KAAK,KAAK,SAAS;AAC5B,QAAI,EAAE,SAAS,QAAQ,IAAI,EAAE,KAAK,CAAC;AAAA,EACrC;AACA,SAAO;AACT;"}