{"version":3,"sources":["../src/screen/screen-layout.js","../src/screen/visible-text.js","../src/screen/components.js","../src/screen/scrollbar.js","../src/screen/list-components.js","../src/screen/key-bindings.js","../src/screen/flicker-free-stdout.js","../src/screen/screens.js","../src/screen/ui-elements.js","../src/screen/follow-scroll.js","../src/screen/scrollable-text.js","../src/screen/text-input.js","../src/screen/utils.js","../src/screen/footer-builder.js","../src/screen/index.js","../src/index.js","../src/args/index.js","../src/params/index.js","../src/errors.js","../src/params/custom-types.js","../src/filedatabase/index.js","../src/utils/os-utils.js","../src/utils/fs-utils.js","../src/utils/format-utils.js","../src/utils/date-utils.js","../src/filedatabase/serializers.js","../src/filedatabase/synopsis-functions.js","../src/db/index.js","../src/db/ensure.js","../src/s3/index.js","../src/aws/index.js","../src/logger/index.js","../src/logger/transports.js","../src/init/index.js","../src/deploy/service.js","../src/deploy/paths.js","../src/deploy/run.js","../src/deploy/log.js","../src/deploy/git.js","../src/deploy/release.js","../src/deploy/activate.js","../src/deploy/deps.js","../src/deploy/test.js","../src/deploy/prune.js","../src/deploy/pm2.js","../src/deploy/nginx.js","../src/deploy/sync-env.js","../src/deploy/build-info.js","../src/deploy/init-structure.js","../src/deploy/bootstrap-host.js","../src/deploy/deploy-service.js","../src/deploy/provision-service.js","../src/deploy/rollback-service.js","../src/deploy/ssh-remote.js","../src/deploy/manifests.js","../src/tasks/index.js","../src/utils/core-utils.js","../src/tasks/servicesRegistry.js","../src/tasks/taskUtils.js","../src/tasks/time-matcher.js","../src/tasks/taskLogs.js","../src/tasks/AbstractTask.js","../src/tasks/coreTasks/TaskPing.js","../src/tasks/coreTasks/TaskSampleProcess.js","../src/tasks/coreTasks/TaskShellCommand.js","../src/tasks/coreTasks/TaskSystemInfo.js","../src/tasks/coreTasks/TaskSumAB.js","../src/tasks/coreTasks/TaskStopRunner.js","../src/tasks/runtimeParams.js","../src/tasks/coreTasks/TaskPauseRunner.js","../src/tasks/coreTasks/TaskPauseTask.js","../src/tasks/coreTasks/TaskGetLogs.js","../src/tasks/coreTasks/TaskSetRuntimeParam.js","../src/tasks/taskRetentionNameRules.js","../src/tasks/taskRetention.js","../src/tasks/coreTasks/TaskPruneTaskRetention.js","../src/tasks/TasksRegistry.js","../src/tasks/serviceTaskAllowlist.js","../src/tasks/claimOrder.js","../src/tasks/taskScriptRunner.js"],"sourcesContent":["/**\n * showScreen chrome (must match screens.js + ScreenContainer):\n *   1 marginTop\n *   1 border top + 1 border bottom\n *   1 title\n *   1 divider\n *   1 blank spacer\n *   1 blank spacer\n *   1 divider\n *   N footer lines (default 1)\n *\n * Ink’s log-update does clearTerminal when outputHeight >= stdout.rows.\n * That wipe is the “everything flickers, title scrolled off” failure mode.\n * Keep one unused row so the frame always fits.\n */\n\nexport const SCREEN_MARGIN_TOP = 1;\nexport const SCREEN_CHROME_WITHOUT_FOOTER = 8;\nexport const INK_HEIGHT_SLACK = 1;\n\nexport function getScreenChromeRows({ footerLines = 1 } = {}) {\n    return SCREEN_CHROME_WITHOUT_FOOTER + Math.max(0, Number(footerLines) || 0);\n}\n\n/**\n * Rows left for a scroll viewport (log lines, list rows) after chrome +\n * any extra header/status lines the body renders.\n */\nexport function getScreenBodyRows({\n    extraRows = 0,\n    footerLines = 1,\n    minRows = 4,\n    termRows = process.stdout.rows || 24,\n} = {}) {\n    const rows = Number(termRows) || 24;\n    const reserved =\n        getScreenChromeRows({ footerLines }) +\n        Math.max(0, Number(extraRows) || 0) +\n        INK_HEIGHT_SLACK;\n    return Math.max(minRows, rows - reserved);\n}\n\n/**\n * ScreenContainer Box maxHeight (margin is outside). margin + this <= termRows - slack.\n */\nexport function getScreenFrameBoxHeight({ termRows = process.stdout.rows || 24 } = {}) {\n    const rows = Number(termRows) || 24;\n    return Math.max(8, rows - SCREEN_MARGIN_TOP - INK_HEIGHT_SLACK);\n}\n","/**\n * Terminal-visible width: ignore ANSI, count code points as one cell.\n * Keeps scrollbar / pad math aligned when log lines carry chalk codes.\n */\n\nconst ANSI_RE = /\\u001b(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g;\n\nexport function stripAnsi(text) {\n    return String(text ?? \"\").replace(ANSI_RE, \"\");\n}\n\nexport function visibleWidth(text) {\n    return [...stripAnsi(text)].length;\n}\n\n/**\n * First `cols` visible cells, preserving ANSI in that span.\n */\nexport function sliceVisible(text, cols) {\n    const w = Math.max(0, Math.floor(Number(cols) || 0));\n    const s = String(text ?? \"\");\n    if (w === 0) return \"\";\n    let vis = 0;\n    let out = \"\";\n    let i = 0;\n    while (i < s.length && vis < w) {\n        ANSI_RE.lastIndex = i;\n        const m = ANSI_RE.exec(s);\n        if (m && m.index === i) {\n            out += m[0];\n            i += m[0].length;\n            continue;\n        }\n        const cp = s.codePointAt(i);\n        const ch = String.fromCodePoint(cp);\n        out += ch;\n        i += ch.length;\n        vis += 1;\n    }\n    return out;\n}\n\nexport function padEndVisible(text, cols) {\n    const w = Math.max(0, Math.floor(Number(cols) || 0));\n    const s = String(text ?? \"\");\n    const vis = visibleWidth(s);\n    if (vis === w) return s;\n    if (vis > w) return sliceVisible(s, w);\n    return s + \" \".repeat(w - vis);\n}\n\n/**\n * Hard-wrap on visible columns (keeps empty lines). ANSI stays with its text.\n */\nexport function wrapTextLines(text, cols) {\n    const w = Math.max(1, Math.floor(Number(cols) || 1));\n    const out = [];\n    for (const raw of String(text ?? \"\").split(\"\\n\")) {\n        if (raw.length === 0) {\n            out.push(\"\");\n            continue;\n        }\n        if (visibleWidth(raw) <= w) {\n            out.push(raw);\n            continue;\n        }\n        let rest = raw;\n        while (visibleWidth(rest) > w) {\n            const head = sliceVisible(rest, w);\n            out.push(head);\n            rest = rest.slice(head.length);\n        }\n        if (rest.length > 0) out.push(rest);\n    }\n    return out;\n}\n","/**\n * Core screen layout components\n */\n\nimport React, { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getScreenFrameBoxHeight } from \"./screen-layout.js\";\nimport { stripAnsi } from \"./visible-text.js\";\n\n/**\n * Get screen width for borders\n * @param maxWidth - Optional max width (null = no limit)\n */\nexport function getScreenWidth(maxWidth = null) {\n    const terminalWidth = process.stdout.columns || 80;\n    // Leave some margin for borders and padding\n    const availableWidth = Math.max(20, terminalWidth - 4);\n    return maxWidth ? Math.min(availableWidth, maxWidth) : availableWidth;\n}\n\n// Types\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Screen Container - uses Ink's built-in borderStyle for proper text wrapping\n */\nexport function ScreenContainer({ children }) {\n    const width = getScreenWidth();\n    const maxHeight = getScreenFrameBoxHeight();\n\n    return h(Box, {\n        flexDirection: \"column\",\n        marginTop: 1,\n        borderStyle: \"single\",\n        borderColor: \"cyan\",\n        paddingX: 1,\n        width,\n        maxHeight,\n        overflow: \"hidden\",\n    }, children);\n}\n\n/**\n * Screen row - just a wrapper for spacing, borders handled by container\n */\nexport function ScreenRow({ children, ...boxProps }) {\n    return h(Box, { flexDirection: \"column\", ...boxProps }, children);\n}\n\n/**\n * Screen Title - first line inside container (left-aligned, breadcrumb-style)\n */\nexport function ScreenTitle({ text }) {\n    return h(ScreenRow, { flexShrink: 0 },\n        h(Text, { bold: true, color: \"cyan\", wrap: \"truncate\" }, text)\n    );\n}\n\n/**\n * Horizontal divider line\n */\nexport function ScreenDivider({ width }) {\n    const dividerWidth = width || (getScreenWidth() - 4); // Account for border and padding\n    return h(Text, { color: \"cyan\", dimColor: true }, \"─\".repeat(dividerWidth));\n}\n\n/**\n * Screen Body - main content area\n */\nexport function ScreenBody({ children, alignItems = \"flex-start\" }) {\n    return h(Box, { flexDirection: \"column\", alignItems }, children);\n}\n\n/** Bold key label. Do not use dimColor here — dim and bold share SGR 22. */\nexport const FOOTER_HOTKEY_STYLE = { bold: true };\n\n/** Caption / separator. Gray, not dim, so later keys stay bold. */\nexport const FOOTER_MUTED_STYLE = { color: \"gray\" };\n\n/**\n * Normalize one footer item: `{ hotkey, caption }` (aliases: key, title, text).\n * `hotkey` may be a string (`\"esc/←\"`) or an array of labels.\n */\nexport function normalizeFooterHotkey(item) {\n    if (item == null) return null;\n    if (typeof item === \"string\") {\n        return { hotkey: [item], caption: \"\" };\n    }\n    const raw = item.hotkey ?? item.key;\n    const hotkey = Array.isArray(raw)\n        ? raw.map(String)\n        : String(raw ?? \"\").split(\"/\").map((s) => s.trim()).filter(Boolean);\n    return {\n        ...item,\n        hotkey,\n        caption: item.caption ?? item.title ?? item.text ?? \"\",\n    };\n}\n\nfunction renderHotkeyPieces(item, reactKey) {\n    const normalized = normalizeFooterHotkey(item);\n    if (!normalized) return [];\n    if (normalized.node && React.isValidElement(normalized.node)) {\n        return [\n            normalized.node.key == null\n                ? React.cloneElement(normalized.node, { key: reactKey })\n                : normalized.node,\n        ];\n    }\n\n    const pieces = [];\n    normalized.hotkey.forEach((label, i) => {\n        if (i > 0) {\n            pieces.push(h(Text, { key: `${reactKey}-sep${i}`, ...FOOTER_MUTED_STYLE }, \"/\"));\n        }\n        pieces.push(h(Text, { key: `${reactKey}-k${i}`, ...FOOTER_HOTKEY_STYLE }, label));\n    });\n\n    if (normalized.caption) {\n        pieces.push(h(Text, { key: `${reactKey}-cap`, ...FOOTER_MUTED_STYLE }, ` to ${normalized.caption}`));\n    }\n\n    if (normalized.kind === \"toggle\" && normalized.value) {\n        pieces.push(h(Text, { key: `${reactKey}-sp`, ...FOOTER_MUTED_STYLE }, \" \"));\n        pieces.push(h(\n            Text,\n            { key: `${reactKey}-val`, ...(normalized.valueStyle || FOOTER_HOTKEY_STYLE) },\n            ` ${normalized.value} `,\n        ));\n    }\n\n    return pieces;\n}\n\n/**\n * Screen Footer — hotkeys are structured items, styled here (not parsed from a string).\n *\n * @example\n * <ScreenFooter hotkeys={[\n *   { hotkey: [\"esc\", \"←\"], caption: \"go back\" },\n *   { hotkey: \"enter\", caption: \"select\" },\n *   { hotkey: \"s\", caption: \"sort\", kind: \"toggle\", value: \"ASC\" },\n * ]} />\n *\n * Extra status lines (not hotkeys) still go in `lines`.\n */\nexport function ScreenFooter({ hotkeys, lines, textStyle }) {\n    const defaultTextStyle = {\n        dimColor: true,\n        color: \"white\"\n    };\n    \n    const finalTextStyle = { ...defaultTextStyle, ...textStyle };\n\n    const flattenAndWrap = (items, keyPrefix = \"\") => {\n        const result = [];\n        let keyIndex = 0;\n\n        (items || []).forEach((item, index) => {\n            if (Array.isArray(item)) {\n                const nested = flattenAndWrap(item, `${keyPrefix}-${index}`);\n                result.push(...nested);\n            } else if (typeof item === \"string\") {\n                const preStyled = stripAnsi(item) !== item;\n                result.push(\n                    h(Text, {\n                        key: `${keyPrefix}-${keyIndex++}`,\n                        ...(preStyled ? {} : finalTextStyle),\n                    }, item)\n                );\n            } else if (React.isValidElement(item)) {\n                result.push(\n                    item.key == null\n                        ? React.cloneElement(item, { key: `${keyPrefix}-${keyIndex++}` })\n                        : item\n                );\n            } else if (item != null) {\n                result.push(item);\n            }\n        });\n\n        return result;\n    };\n\n    const hotkeyPieces = [];\n    (hotkeys || []).forEach((item, idx) => {\n        if (idx > 0) {\n            hotkeyPieces.push(h(Text, { key: `hk-join-${idx}`, ...FOOTER_MUTED_STYLE }, \", \"));\n        }\n        hotkeyPieces.push(...renderHotkeyPieces(item, `hk-${idx}`));\n    });\n\n    const extraRows = (lines && lines.length)\n        ? flattenAndWrap(lines, \"line\")\n        : [];\n\n    const rows = [];\n    if (hotkeyPieces.length) {\n        rows.push(h(Box, { key: \"hotkeys\", flexDirection: \"row\" }, ...hotkeyPieces));\n    }\n    if (extraRows.length) {\n        rows.push(h(Box, { key: \"lines\", flexDirection: \"row\" }, ...extraRows));\n    }\n\n    return h(Box, { flexDirection: \"column\" }, ...rows);\n}","/**\n * Shared proportional scrollbar (ASCII — block glyphs are often double-width).\n */\n\nexport const BAR_THUMB = \"#\";\nexport const BAR_TRACK = \"|\";\n\n/**\n * Proportional scrollbar glyphs for a viewport.\n * @returns {string[]|null} one glyph per viewport row, or null when no overflow\n */\nexport function scrollbarGlyphs(viewportRows, totalLines, scrollTop) {\n    const view = Math.max(1, Math.floor(viewportRows));\n    const total = Math.max(0, Math.floor(totalLines));\n    if (total <= view) return null;\n\n    const maxScroll = total - view;\n    const thumbSize = Math.max(1, Math.round((view / total) * view));\n    const travel = Math.max(0, view - thumbSize);\n    const s = Math.min(Math.max(0, Math.floor(scrollTop)), maxScroll);\n    const thumbStart = maxScroll === 0 ? 0 : Math.round((s / maxScroll) * travel);\n\n    const glyphs = [];\n    for (let i = 0; i < view; i++) {\n        glyphs.push(i >= thumbStart && i < thumbStart + thumbSize ? BAR_THUMB : BAR_TRACK);\n    }\n    return glyphs;\n}\n\n/** ⌥/Ctrl + arrows and PgUp/PgDn → pageUp / pageDown actions. */\nexport const PAGE_SCROLL_KEY_BINDINGS = [\n    { key: \"upArrow\", meta: true, caption: \"page\", action: \"pageUp\", order: 0 },\n    { key: \"downArrow\", meta: true, caption: \"page\", action: \"pageDown\", order: 0 },\n    { key: \"upArrow\", ctrl: true, caption: \"page\", action: \"pageUp\", order: 0 },\n    { key: \"downArrow\", ctrl: true, caption: \"page\", action: \"pageDown\", order: 0 },\n    { key: \"pageUp\", caption: \"page\", action: \"pageUp\", order: 0 },\n    { key: \"pageDown\", caption: \"page\", action: \"pageDown\", order: 0 },\n];\n","/**\n * Reusable screen components for V2 architecture\n */\n\nimport React, { useState, useEffect, useRef, createElement } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { ScreenRow, ScreenDivider } from \"./components.js\";\nimport {\n    BAR_THUMB,\n    BAR_TRACK,\n    PAGE_SCROLL_KEY_BINDINGS,\n    scrollbarGlyphs,\n} from \"./scrollbar.js\";\n\nconst h = createElement;\n\n/**\n * Make room for a 1-cell scrollbar. Full-width table rows are padEnd'd (trailing\n * space) — trim one cell. Short labels are left alone (bar just appends).\n */\nfunction clipNameForScrollbar(name, needsBar) {\n    if (!needsBar || name == null) return name;\n    const s = String(name);\n    if (s.length <= 1) return s;\n    if (/\\s$/.test(s)) return s.slice(0, -1);\n    return s;\n}\n\n// TODO: Define proper context type interface\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Multi-column list component\n * Handles its own navigation, actions, and key bindings\n */\nexport function MultiColumnListComponent({ items, ctx, selectedIndexRef }) {\n    const [, forceUpdate] = useState({});\n\n    // Calculate layout\n    const termWidth = (process.stdout.columns || 80) - 8;\n    const maxItemLength = Math.max(...items.map(w => w.length));\n    const columnWidth = maxItemLength + 3;\n    const columns = Math.max(1, Math.floor(termWidth / columnWidth));\n    const itemsPerColumn = Math.ceil(items.length / columns);\n\n    // Set up actions in useEffect (runs once)\n    useEffect(() => {\n        ctx.setAction(\"moveUp\", () => {\n            selectedIndexRef.current = Math.max(0, selectedIndexRef.current - 1);\n            forceUpdate({});\n        });\n\n        ctx.setAction(\"moveDown\", () => {\n            selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + 1);\n            forceUpdate({});\n        });\n\n        ctx.setAction(\"moveLeft\", () => {\n            if (selectedIndexRef.current === 0) {\n                ctx.goBack();\n            } else {\n                selectedIndexRef.current = Math.max(0, selectedIndexRef.current - itemsPerColumn);\n                forceUpdate({});\n            }\n        });\n\n        ctx.setAction(\"moveRight\", () => {\n            selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + itemsPerColumn);\n            forceUpdate({});\n        });\n\n        // Set up key bindings\n        ctx.setKeyBinding([\n            { key: \"leftArrow\", caption: \"navigate\", action: \"moveLeft\", order: 0 },\n            { key: \"rightArrow\", caption: \"navigate\", action: \"moveRight\", order: 0 },\n            { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n            { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n        ]);\n\n        // Add footer\n        ctx.addFooter(`Total: ${items.length} items`);\n    }, []);\n\n    const selectedIndex = selectedIndexRef.current;\n\n    // Build grid\n    const rows = [];\n    for (let row = 0; row < itemsPerColumn; row++) {\n        const cols = [];\n        for (let col = 0; col < columns; col++) {\n            const index = col * itemsPerColumn + row;\n            if (index < items.length) {\n                const isSelected = index === selectedIndex;\n                cols.push(\n                    h(Box, { key: index, width: columnWidth },\n                        h(Text, {\n                            color: isSelected ? \"black\" : \"white\",\n                            backgroundColor: isSelected ? \"cyan\" : undefined,\n                            bold: isSelected\n                        }, items[index].padEnd(maxItemLength))\n                    )\n                );\n            }\n        }\n        rows.push(\n            h(ScreenRow, { key: row, children: h(Box, { flexDirection: \"row\" }, ...cols) })\n        );\n    }\n\n    return h(Box, { flexDirection: \"column\" }, ...rows);\n}\n\n/**\n * Multi-column list with preview panel component\n * Shows selected item details below the list\n */\nexport function MultiColumnListWithPreviewComponent({\n    items,\n    getPreviewContent,\n    ctx,\n    selectedIndexRef\n}) {\n    const [, forceUpdate] = useState({});\n\n    // Calculate layout\n    const termWidth = (process.stdout.columns || 80) - 8;\n    const maxItemLength = Math.max(...items.map(w => w.length));\n    const columnWidth = maxItemLength + 3;\n    const columns = Math.max(1, Math.floor(termWidth / columnWidth));\n    const itemsPerColumn = Math.ceil(items.length / columns);\n\n    // Set up actions in useEffect (runs once)\n    useEffect(() => {\n        ctx.setAction(\"moveUp\", () => {\n            selectedIndexRef.current = Math.max(0, selectedIndexRef.current - 1);\n            forceUpdate({});\n        });\n\n        ctx.setAction(\"moveDown\", () => {\n            selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + 1);\n            forceUpdate({});\n        });\n\n        ctx.setAction(\"moveLeft\", () => {\n            if (selectedIndexRef.current === 0) {\n                ctx.goBack();\n            } else {\n                selectedIndexRef.current = Math.max(0, selectedIndexRef.current - itemsPerColumn);\n                forceUpdate({});\n            }\n        });\n\n        ctx.setAction(\"moveRight\", () => {\n            selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + itemsPerColumn);\n            forceUpdate({});\n        });\n\n        // Set up key bindings\n        ctx.setKeyBinding([\n            { key: \"leftArrow\", caption: \"navigate\", action: \"moveLeft\", order: 0 },\n            { key: \"rightArrow\", caption: \"navigate\", action: \"moveRight\", order: 0 },\n            { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n            { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n        ]);\n\n        // Add footer\n        ctx.addFooter(`Total: ${items.length} items`);\n    }, []);\n\n    const selectedIndex = selectedIndexRef.current;\n    const selectedItem = items[selectedIndex];\n\n    // Build grid\n    const rows = [];\n    for (let row = 0; row < itemsPerColumn; row++) {\n        const cols = [];\n        for (let col = 0; col < columns; col++) {\n            const index = col * itemsPerColumn + row;\n            if (index < items.length) {\n                const isSelected = index === selectedIndex;\n                cols.push(\n                    h(Box, { key: index, width: columnWidth },\n                        h(Text, {\n                            color: isSelected ? \"black\" : \"white\",\n                            backgroundColor: isSelected ? \"cyan\" : undefined,\n                            bold: isSelected\n                        }, items[index].padEnd(maxItemLength))\n                    )\n                );\n            }\n        }\n        rows.push(\n            h(ScreenRow, { key: row, children: h(Box, { flexDirection: \"row\" }, ...cols) })\n        );\n    }\n\n    // Get preview content for selected item\n    const previewContent = getPreviewContent ? getPreviewContent(selectedItem) : selectedItem;\n\n    const previewRows = [];\n    if (typeof previewContent === \"string\") {\n        previewRows.push(h(ScreenRow, { key: \"preview-string\", children: h(Text, { bold: true }, previewContent) }));\n    } else if (typeof previewContent === \"object\" && !React.isValidElement(previewContent) && previewContent !== null) {\n        Object.entries(previewContent).forEach(([key, value], idx) => {\n            previewRows.push(h(ScreenRow, { key: `preview-${key}-${idx}`, children: h(Text, {}, `${key}: ${value}`) }));\n        });\n    } else if (React.isValidElement(previewContent)) {\n        previewRows.push(h(ScreenRow, { key: \"preview-element\", children: previewContent }));\n    }\n\n    return h(Box, { flexDirection: \"column\" },\n        ...rows,\n        h(ScreenRow, { key: \"spacer-1\", children: h(Text, {}, \" \") }),\n        h(ScreenDivider, { key: \"divider\" }),\n        h(ScreenRow, { key: \"spacer-2\", children: h(Text, {}, \" \") }),\n        ...previewRows\n    );\n}\n\n/**\n * Single-column list component\n * Simple vertical menu with optional sorting\n */\nexport function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sortable = false, maxHeight, sortHighlightStyle, selectionMarker = \" \", onSelectionChange }) {\n    const [, forceUpdate] = useState({});\n    const [sortOrder, setSortOrder] = useState(\"none\");\n    const [scrollOffset, setScrollOffset] = useState(0);\n    \n    // Use refs to store current scroll values to avoid stale closures\n    const scrollStateRef = useRef({ scrollOffset: 0, maxHeight: 0, totalItems: 0 });\n    const itemsRef = useRef(items);\n    itemsRef.current = items;\n\n    // Default getTitle - returns item if string, otherwise item.title\n    const defaultGetTitle = (item) => {\n        return getTitle ? getTitle(item) : (typeof item.value === \"string\" ? item.value : (item.value?.title || item.name));\n    };\n\n    // Get title for sorting\n    const titleGetter = getTitle || defaultGetTitle;\n\n    // Apply sorting if enabled\n    const displayItems = sortable && sortOrder !== \"none\" ? [...items].sort((a, b) => {\n        const titleA = titleGetter(a).toLowerCase();\n        const titleB = titleGetter(b).toLowerCase();\n        if (sortOrder === \"asc\") {\n            return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;\n        } else {\n            return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;\n        }\n    }) : items;\n\n    const displayItemsRef = useRef(displayItems);\n    displayItemsRef.current = displayItems;\n\n    // Calculate scrolling\n    const effectiveMaxHeight = maxHeight || displayItems.length;\n    const _canScroll = displayItems.length > effectiveMaxHeight;\n    const maxScrollOffset = Math.max(0, displayItems.length - effectiveMaxHeight);\n    \n    // Ensure scroll offset is within bounds\n    const clampedScrollOffset = Math.min(Math.max(0, scrollOffset), maxScrollOffset);\n    \n    // Get visible items\n    const visibleItems = displayItems.slice(clampedScrollOffset, clampedScrollOffset + effectiveMaxHeight);\n    \n    // Check if we can scroll up/down\n    const canScrollUp = clampedScrollOffset > 0;\n    const canScrollDown = clampedScrollOffset < maxScrollOffset;\n    \n    // Update scroll state ref with current values\n    scrollStateRef.current = { scrollOffset, maxHeight: effectiveMaxHeight, totalItems: displayItems.length };\n    \n\n    const onSelectionChangeRef = useRef(onSelectionChange);\n    onSelectionChangeRef.current = onSelectionChange;\n\n    // Set up actions in useEffect (runs once)\n    useEffect(() => {\n        ctx.setAction(\"moveUp\", () => {\n            const newIndex = Math.max(0, selectedIndexRef.current - 1);\n            selectedIndexRef.current = newIndex;\n            const list = displayItemsRef.current;\n            onSelectionChangeRef.current?.(newIndex, list[newIndex]);\n\n            // Auto-scroll to keep selected item visible\n            const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n            const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n            const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);\n\n            if (newIndex < currentClampedScrollOffset) {\n                setScrollOffset(newIndex);\n            }\n\n            forceUpdate({});\n        });\n\n        ctx.setAction(\"moveDown\", () => {\n            const currentItems = displayItemsRef.current;\n            const maxIndex = Math.max(0, currentItems.length - 1);\n            const newIndex = Math.min(maxIndex, selectedIndexRef.current + 1);\n            selectedIndexRef.current = newIndex;\n            onSelectionChangeRef.current?.(newIndex, currentItems[newIndex]);\n\n            // Auto-scroll to keep selected item visible\n            const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n            const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n            const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);\n\n            if (newIndex >= currentClampedScrollOffset + currentMaxHeight) {\n                setScrollOffset(newIndex - currentMaxHeight + 1);\n            }\n\n            forceUpdate({});\n        });\n\n        // Viewport scroll (without moving selection)\n        ctx.setAction(\"scrollUp\", () => {\n            const { scrollOffset: currentScrollOffset } = scrollStateRef.current;\n            setScrollOffset(Math.max(0, currentScrollOffset - 1));\n            forceUpdate({});\n        });\n\n        ctx.setAction(\"scrollDown\", () => {\n            const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } =\n                scrollStateRef.current;\n            const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n            setScrollOffset(Math.min(currentMaxScrollOffset, currentScrollOffset + 1));\n            forceUpdate({});\n        });\n\n        // Page: move selection by one viewport, keep it visible (⌥/Ctrl+↑↓, PgUp/PgDn)\n        ctx.setAction(\"pageUp\", () => {\n            const { maxHeight: vh } = scrollStateRef.current;\n            const page = Math.max(1, vh || 1);\n            const newIndex = Math.max(0, selectedIndexRef.current - page);\n            selectedIndexRef.current = newIndex;\n            const list = displayItemsRef.current;\n            onSelectionChangeRef.current?.(newIndex, list[newIndex]);\n            setScrollOffset(newIndex);\n            forceUpdate({});\n        });\n\n        ctx.setAction(\"pageDown\", () => {\n            const { maxHeight: vh, totalItems } = scrollStateRef.current;\n            const page = Math.max(1, vh || 1);\n            const maxIndex = Math.max(0, totalItems - 1);\n            const newIndex = Math.min(maxIndex, selectedIndexRef.current + page);\n            selectedIndexRef.current = newIndex;\n            const list = displayItemsRef.current;\n            onSelectionChangeRef.current?.(newIndex, list[newIndex]);\n            const maxScroll = Math.max(0, totalItems - page);\n            setScrollOffset(Math.min(maxScroll, Math.max(0, newIndex - page + 1)));\n            forceUpdate({});\n        });\n\n        const navBindings = [\n            { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n            { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 },\n            ...PAGE_SCROLL_KEY_BINDINGS,\n        ];\n\n        // Set up sort action if sortable\n        if (sortable) {\n            ctx.setAction(\"toggleSort\", () => {\n                const nextSort = \n                    sortOrder === \"none\" ? \"asc\" : \n                        sortOrder === \"asc\" ? \"desc\" : \"none\";\n                \n                // Store the currently selected item from the current display items\n                const currentSelectedItem = displayItemsRef.current[selectedIndexRef.current];\n                \n                setSortOrder(nextSort);\n                \n                // Calculate the new sorted items\n                const newSortedItems = nextSort !== \"none\" ? [...itemsRef.current].sort((a, b) => {\n                    const titleA = titleGetter(a).toLowerCase();\n                    const titleB = titleGetter(b).toLowerCase();\n                    if (nextSort === \"asc\") {\n                        return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;\n                    } else {\n                        return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;\n                    }\n                }) : itemsRef.current;\n                \n                // Find the new index of the selected item in the new sorted list\n                const newIndex = newSortedItems.findIndex(item => item === currentSelectedItem);\n                if (newIndex !== -1) {\n                    selectedIndexRef.current = newIndex;\n                    // Set scroll position to show the selected item at the top\n                    setScrollOffset(newIndex);\n                } else {\n                    // Fallback: if item not found, select first item\n                    selectedIndexRef.current = 0;\n                    setScrollOffset(0);\n                }\n                \n                forceUpdate({});\n            });\n\n            // Default highlight style (green background, black text, bold)\n            const defaultHighlightStyle = {\n                color: \"black\",\n                backgroundColor: \"green\", \n                bold: true\n            };\n            const highlightStyle = { ...defaultHighlightStyle, ...sortHighlightStyle };\n\n            ctx.setKeyBinding([\n                ...navBindings,\n                {\n                    key: \"s\",\n                    caption: \"toggle sort\",\n                    action: \"toggleSort\",\n                    order: 5,\n                    kind: \"toggle\",\n                    value: sortOrder === \"none\" ? undefined : sortOrder === \"asc\" ? \"ASC\" : \"DESC\",\n                    valueStyle: highlightStyle,\n                },\n            ]);\n\n            // Force update to show the new caption in footer\n            ctx.update();\n        } else {\n            ctx.setKeyBinding(navBindings);\n        }\n    }, [sortOrder, sortable]);\n\n    const selectedIndex = selectedIndexRef.current;\n    const needsBar = displayItems.length > effectiveMaxHeight;\n    const barGlyphs = needsBar\n        ? scrollbarGlyphs(effectiveMaxHeight, displayItems.length, clampedScrollOffset)\n        : null;\n\n    const appendBar = (rowContent, displayIndex) => {\n        if (!barGlyphs) return rowContent;\n        const glyph = barGlyphs[displayIndex] ?? BAR_TRACK;\n        return h(\n            Box,\n            { flexDirection: \"row\" },\n            rowContent,\n            h(Text, { color: glyph === BAR_THUMB ? \"cyan\" : \"gray\" }, glyph),\n        );\n    };\n\n    // Default renderer — edge ↑/↓ only when there is no scrollbar (bar replaces them).\n    const defaultRenderItem = (item, isSelected, displayIndex, actualIndex) => {\n        const isFirstVisible = displayIndex === 0;\n        const isLastVisible = displayIndex === visibleItems.length - 1;\n\n        let arrowPrefix = \"  \";\n        if (!needsBar) {\n            if (isFirstVisible && canScrollUp) arrowPrefix = \"↑ \";\n            else if (isLastVisible && canScrollDown) arrowPrefix = \"↓ \";\n        }\n\n        const selectionPrefix = isSelected\n            ? selectionMarker\n            : \" \".repeat(selectionMarker.length);\n\n        const label = clipNameForScrollbar(item.name, needsBar);\n\n        return h(\n            Box,\n            { flexDirection: \"row\" },\n            h(Text, { key: \"arrow\", color: \"white\" }, arrowPrefix),\n            h(Text, { key: \"marker\", color: \"white\" }, selectionPrefix),\n            h(\n                Text,\n                {\n                    key: \"name\",\n                    color: isSelected ? \"black\" : \"white\",\n                    backgroundColor: isSelected ? \"cyan\" : undefined,\n                    bold: isSelected,\n                },\n                label,\n            ),\n        );\n    };\n\n    const itemRenderer = renderItem || defaultRenderItem;\n\n    return h(\n        Box,\n        { flexDirection: \"column\" },\n        ...visibleItems.map((item, displayIndex) => {\n            const actualIndex = clampedScrollOffset + displayIndex;\n            const isSelected = actualIndex === selectedIndex;\n\n            if (renderItem) {\n                const isFirstVisible = displayIndex === 0;\n                const isLastVisible = displayIndex === visibleItems.length - 1;\n\n                let arrowPrefix = \"  \";\n                if (!needsBar) {\n                    if (isFirstVisible && canScrollUp) arrowPrefix = \"↑ \";\n                    else if (isLastVisible && canScrollDown) arrowPrefix = \"↓ \";\n                }\n\n                const selectionPrefix = isSelected\n                    ? selectionMarker\n                    : \" \".repeat(selectionMarker.length);\n\n                const clipped = needsBar\n                    ? { ...item, name: clipNameForScrollbar(item.name, true) }\n                    : item;\n\n                const row = h(\n                    Box,\n                    { flexDirection: \"row\" },\n                    h(Text, { key: \"arrow\", color: \"white\" }, arrowPrefix),\n                    h(Text, { key: \"marker\", color: \"white\" }, selectionPrefix),\n                    renderItem(clipped, isSelected, displayIndex),\n                );\n\n                return h(ScreenRow, {\n                    key: `slot-${displayIndex}`,\n                    children: appendBar(row, displayIndex),\n                });\n            }\n\n            return h(ScreenRow, {\n                key: `slot-${displayIndex}`,\n                children: appendBar(\n                    itemRenderer(item, isSelected, displayIndex, actualIndex),\n                    displayIndex,\n                ),\n            });\n        }),\n    );\n}\n","/**\n * Key-binding helpers for showScreen (matching + footer labels).\n *\n * Bindings may set `meta` / `ctrl` / `shift` booleans. Plain bindings (flags\n * omitted) do not match when that modifier is held, so `↑` and `⌥↑` can coexist.\n */\n\n/**\n * Stable identity for replace/remove (key + modifiers).\n * @param {{ key: string, meta?: boolean, ctrl?: boolean, shift?: boolean }} b\n */\nexport function bindingIdentity(b) {\n    return [\n        String(b?.key ?? \"\"),\n        b?.meta ? \"m\" : \"\",\n        b?.ctrl ? \"c\" : \"\",\n        b?.shift ? \"s\" : \"\",\n    ].join(\"|\");\n}\n\n/**\n * @param {{ key: string, meta?: boolean, ctrl?: boolean, shift?: boolean }} binding\n * @param {string} input\n * @param {import(\"ink\").Key} key\n */\nexport function bindingMatchesInput(binding, input, key) {\n    if (!binding?.key) return false;\n\n    let keyMatches = false;\n    if (key?.[binding.key]) {\n        keyMatches = true;\n    } else if (input === binding.key) {\n        keyMatches = true;\n    } else if (key?.name === binding.key) {\n        keyMatches = true;\n    }\n    if (!keyMatches) return false;\n\n    // Explicit true → require; explicit false → forbid; omitted → forbid if pressed\n    // (so plain upArrow does not fire for meta+up).\n    const modOk = (flag, pressed) => {\n        if (flag === true) return !!pressed;\n        if (flag === false) return !pressed;\n        return !pressed;\n    };\n\n    // Ink's useInput sets `meta: true` whenever `name === \"escape\"` (Escape is\n    // the terminal meta prefix). Treat that as a lone Esc, not Option+key.\n    const inkEscapeMeta = binding.key === \"escape\" && key?.escape;\n    if (!inkEscapeMeta && !modOk(binding.meta, key?.meta)) return false;\n    if (!modOk(binding.ctrl, key?.ctrl)) return false;\n    if (binding.shift !== undefined && !!key?.shift !== !!binding.shift) return false;\n\n    return true;\n}\n\nconst KEY_LABELS = {\n    escape: \"esc\",\n    leftArrow: \"←\",\n    rightArrow: \"→\",\n    upArrow: \"↑\",\n    downArrow: \"↓\",\n    return: \"enter\",\n    pageUp: \"PgUp\",\n    pageDown: \"PgDn\",\n};\n\n/**\n * Human label for one binding (modifiers + key), e.g. `⌥↑`, `^↓`, `PgUp`.\n * @param {{ key: string, meta?: boolean, ctrl?: boolean, shift?: boolean }} binding\n */\nexport function formatBindingKey(binding) {\n    let label = KEY_LABELS[binding.key] || binding.key;\n    if (binding.shift) label = `⇧${label}`;\n    if (binding.ctrl) label = `^${label}`;\n    // ink `meta` is Option/Alt on macOS (⌘ is usually eaten by the terminal).\n    if (binding.meta) label = `⌥${label}`;\n    return label;\n}\n","/**\n * Ink's log-update always does eraseLines(whole frame) + reprint. That blank\n * intermediate is the flicker. We intercept those writes and update only\n * changed lines in place (like less).\n *\n * Ink writes `yogaOutput + \"\\n\"`. After that, the cursor sits on a new empty\n * line — not on a trailing content row. split(\"\\n\") includes a final \"\" for\n * that newline; CUU must use the content-row count, not the split length.\n */\n\nconst ESC = \"\\u001b[\";\nconst ERASE_LINE = `${ESC}2K`;\nconst CURSOR_UP = `${ESC}1A`;\nconst CURSOR_LEFT = `${ESC}G`;\n\n/** Same formula as ansi-escapes `eraseLines(count)`. */\nexport function inkEraseLines(count) {\n    let clear = \"\";\n    for (let i = 0; i < count; i++) {\n        clear += ERASE_LINE + (i < count - 1 ? CURSOR_UP : \"\");\n    }\n    if (count) clear += CURSOR_LEFT;\n    return clear;\n}\n\nconst ERASE_LINES_RE = /^(?:\\u001b\\[2K\\u001b\\[1A)*\\u001b\\[2K\\u001b\\[G/;\nconst CLEAR_TERMINAL_RE = /^\\u001b\\[2J(?:\\u001b\\[3J)?(?:\\u001b\\[H|\\u001b\\[0f)?/;\n\nexport function splitInkLogWrite(str) {\n    const s = String(str ?? \"\");\n    if (CLEAR_TERMINAL_RE.test(s)) {\n        return { kind: \"clear\", body: s };\n    }\n    const m = s.match(ERASE_LINES_RE);\n    if (m) {\n        return { kind: \"frame\", body: s.slice(m[0].length) };\n    }\n    return { kind: \"raw\", body: s };\n}\n\nexport function splitFrameLines(body) {\n    return String(body ?? \"\").split(\"\\n\");\n}\n\n/** Drop the trailing \"\" that split() adds for Ink's final newline. */\nexport function contentRows(lines) {\n    const rows = Array.isArray(lines) ? lines.slice() : [];\n    if (rows.length > 0 && rows[rows.length - 1] === \"\") rows.pop();\n    return rows;\n}\n\n/**\n * Cursor is on the empty line after the previous frame. Move to the first\n * content row and rewrite only diffs, then park on the line after the new\n * last content row (Ink's convention).\n */\nexport function paintFrameDiff(prevLines, nextLines) {\n    const prev = contentRows(prevLines);\n    const next = contentRows(nextLines);\n    if (prev.length === 0 && next.length === 0) return \"\";\n\n    let out = \"\";\n    if (prev.length > 0) {\n        out += `${ESC}${prev.length}A`;\n    }\n\n    for (let i = 0; i < next.length; i++) {\n        if (prev[i] !== next[i]) {\n            out += ERASE_LINE + CURSOR_LEFT + next[i];\n        }\n        out += \"\\n\";\n    }\n\n    const leftovers = prev.length - next.length;\n    if (leftovers > 0) {\n        for (let i = 0; i < leftovers; i++) {\n            out += ERASE_LINE;\n            if (i < leftovers - 1) out += \"\\n\";\n        }\n        if (leftovers > 1) {\n            out += `${ESC}${leftovers - 1}A`;\n        }\n        out += CURSOR_LEFT;\n    }\n\n    return out;\n}\n\nfunction finishWrite(stdout, payload, enc, done) {\n    const ok = stdout.write(payload, enc);\n    if (typeof done === \"function\") done();\n    return ok;\n}\n\n/**\n * @param {NodeJS.WriteStream} [stdout]\n * @returns {NodeJS.WriteStream}\n */\nexport function createFlickerFreeStdout(stdout = process.stdout) {\n    let prevLines = [];\n\n    const write = (chunk, encoding, cb) => {\n        const done = typeof encoding === \"function\" ? encoding : cb;\n        const enc = typeof encoding === \"function\" ? undefined : encoding;\n        const str = typeof chunk === \"string\" ? chunk : Buffer.from(chunk).toString();\n        const parsed = splitInkLogWrite(str);\n\n        if (parsed.kind === \"clear\") {\n            const after = str.replace(CLEAR_TERMINAL_RE, \"\");\n            prevLines = after ? splitFrameLines(after) : [];\n            return finishWrite(stdout, str, enc, done);\n        }\n\n        if (parsed.kind === \"frame\") {\n            if (parsed.body === \"\") {\n                prevLines = [];\n                return finishWrite(stdout, str, enc, done);\n            }\n            const nextLines = splitFrameLines(parsed.body);\n            if (prevLines.length === 0) {\n                prevLines = nextLines;\n                return finishWrite(stdout, parsed.body, enc, done);\n            }\n            const painted = paintFrameDiff(prevLines, nextLines);\n            prevLines = nextLines;\n            return finishWrite(stdout, painted, enc, done);\n        }\n\n        if (prevLines.length === 0 && parsed.body.includes(\"\\n\")) {\n            prevLines = splitFrameLines(parsed.body);\n        }\n        return stdout.write(chunk, encoding, cb);\n    };\n\n    return new Proxy(stdout, {\n        get(target, prop) {\n            if (prop === \"write\") return write;\n            const value = Reflect.get(target, prop, target);\n            return typeof value === \"function\" ? value.bind(target) : value;\n        },\n    });\n}\n","/**\n * Screen System - Action-based architecture\n */\n\nimport { useState, createElement as h } from \"react\";\nimport { render, useInput, Box, Text } from \"ink\";\nimport chalk from \"chalk\";\nimport { ScreenContainer, ScreenRow, ScreenTitle, ScreenDivider, ScreenFooter, normalizeFooterHotkey } from \"./components.js\";\nimport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\nimport {\n    bindingIdentity,\n    bindingMatchesInput,\n    formatBindingKey,\n} from \"./key-bindings.js\";\nimport { createFlickerFreeStdout } from \"./flicker-free-stdout.js\";\n\n// Types\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Group key bindings by caption for footer display\n */\nexport function groupKeyBindings(bindings) {\n    const groups = {};\n\n    // Filter out disabled bindings\n    const enabledBindings = bindings.filter(b => b.enabled !== false);\n\n    enabledBindings.forEach(binding => {\n        const caption = typeof binding.caption === \"string\" ? binding.caption : \"\";\n        if (!groups[caption]) {\n            groups[caption] = {\n                keys: [],\n                caption: caption,\n                order: binding.order || 999\n            };\n        }\n        groups[caption].keys.push(formatBindingKey(binding));\n        if (binding.kind) groups[caption].kind = binding.kind;\n        if (binding.value !== undefined) groups[caption].value = binding.value;\n        if (binding.valueStyle) groups[caption].valueStyle = binding.valueStyle;\n    });\n\n    return Object.values(groups);\n}\n\n/**\n * Turn key bindings into `{ hotkey, caption }` items for ScreenFooter.\n * Does not style anything — ScreenFooter paints each hotkey.\n *\n * @param {object[]} bindings\n * @param {\"long\"|\"short\"} [mode]\n */\nexport function bindingsToFooterHotkeys(bindings, mode = \"long\") {\n    const customItems = [];\n    const stringBindings = [];\n\n    (bindings || []).forEach((binding) => {\n        if (binding.enabled === false) return;\n        let caption = binding.caption;\n        if (typeof caption === \"function\") {\n            caption = caption();\n        }\n        if (caption != null && typeof caption !== \"string\") {\n            customItems.push({\n                hotkey: [formatBindingKey(binding)],\n                caption: \"\",\n                node: caption,\n                order: binding.order || 999,\n                kind: binding.kind,\n                value: binding.value,\n                valueStyle: binding.valueStyle,\n            });\n            return;\n        }\n        stringBindings.push({ ...binding, caption: caption || \"\" });\n    });\n\n    const groups = groupKeyBindings(stringBindings);\n    groups.sort((a, b) => a.order - b.order);\n\n    const items = groups.map((group) => {\n        const item = {\n            hotkey: group.keys,\n            caption: mode === \"short\" ? \"\" : group.caption,\n            order: group.order,\n        };\n        if (group.kind) item.kind = group.kind;\n        if (group.value !== undefined) item.value = group.value;\n        if (group.valueStyle) item.valueStyle = group.valueStyle;\n        return item;\n    });\n\n    customItems.forEach((item) => items.push(item));\n    items.sort((a, b) => (a.order || 999) - (b.order || 999));\n    return items;\n}\n\n/** @deprecated Use bindingsToFooterHotkeys — returns structured footer items. */\nexport function formatKeyBindings(bindings, mode = \"long\") {\n    return bindingsToFooterHotkeys(bindings, mode);\n}\n\nexport { FOOTER_HOTKEY_STYLE, FOOTER_MUTED_STYLE, normalizeFooterHotkey } from \"./components.js\";\n\n/** Bold default-fg key; `reset` clears a prior dim so later keys stay bright. */\nexport function styleFooterHotkey(label) {\n    return chalk.reset.bold(String(label));\n}\n\n/** Dim caption / separator; `reset` clears bold from the preceding key. */\nexport function styleFooterMuted(text) {\n    return chalk.reset.dim(String(text));\n}\n\n/**\n * One footer binding: highlighted keys, dim \"to …\" caption.\n * Returns a chalk string (not Ink nodes) so every key is independently bright.\n * @param {string} keyStr\n * @param {string} [caption]\n * @param {\"long\"|\"short\"} [mode]\n */\nexport function formatFooterHotkey(keyStr, caption = \"\", mode = \"long\") {\n    const keys = String(keyStr)\n        .split(\"/\")\n        .map((part) => styleFooterHotkey(part))\n        .join(styleFooterMuted(\"/\"));\n    if (mode === \"long\" && caption) {\n        return keys + styleFooterMuted(` to ${caption}`);\n    }\n    return keys;\n}\n\n/**\n * Format keys for display\n */\nexport function formatKeys(keys) {\n    // `keys` may already be display labels (from groupKeyBindings) or raw key names.\n    const keyMap = {\n        escape: \"esc\",\n        leftArrow: \"←\",\n        rightArrow: \"→\",\n        upArrow: \"↑\",\n        downArrow: \"↓\",\n        return: \"enter\",\n        pageUp: \"PgUp\",\n        pageDown: \"PgDn\",\n    };\n\n    return keys.map((k) => keyMap[k] || k).join(\"/\");\n}\n\n/**\n * Show screen with action-based architecture\n */\nexport async function showScreen(config) {\n    const {\n        title,\n        onRender,\n        parentData = {}\n    } = config;\n\n\n    return new Promise((resolve) => {\n        // eslint-disable-next-line prefer-const\n        let instance;\n\n        // Persistent collections (closure variables survive re-renders)\n        const keyBindings = [];\n        const actions = {};\n        const customFooterItems = [];\n        let smartFooterHotkeys = null;\n        let renderResult = null;\n        let initialized = false;\n\n        const Screen = () => {\n            const [, setUpdateCounter] = useState(0);\n\n            // Initialize defaults only once\n            if (!initialized) {\n                const defaultBindings = [\n                    { key: \"escape\", caption: \"go back\", action: \"back\", protected: true, order: 1 },\n                    { key: \"leftArrow\", caption: \"go back\", action: \"back\", protected: false, order: 1 }\n                    // Note: 'select' is not a default - components add it if needed\n                ];\n\n                // Add defaults\n                defaultBindings.forEach(binding => {\n                    keyBindings.push(binding);\n                });\n\n                // Default actions\n                actions.back = () => {\n                    cleanup(null);\n                };\n\n                initialized = true;\n            }\n\n            // Context for onRender\n            const context = {\n                setAction: (actionName, handlerFn) => {\n                    actions[actionName] = handlerFn;\n                },\n\n                setKeyBinding: (bindingOrBindings) => {\n                    // Support both single object and array\n                    const bindingsToSet = Array.isArray(bindingOrBindings) ? bindingOrBindings : [bindingOrBindings];\n\n                    bindingsToSet.forEach(binding => {\n                        const id = bindingIdentity(binding);\n                        const existingIndex = keyBindings.findIndex(\n                            (b) => bindingIdentity(b) === id,\n                        );\n\n                        if (existingIndex >= 0) {\n                            const existing = keyBindings[existingIndex];\n\n                            // Can't override protected keys\n                            if (existing.protected) {\n                                console.warn(`Cannot override protected key: ${binding.key}`);\n                                return;\n                            }\n\n                            // Replace binding (keep original order if not specified)\n                            keyBindings[existingIndex] = {\n                                ...existing,\n                                ...binding,\n                                order: binding.order !== undefined ? binding.order : existing.order,\n                                enabled: binding.enabled !== undefined ? binding.enabled : (existing.enabled !== undefined ? existing.enabled : true)\n                            };\n                        } else {\n                            // Add new binding\n                            keyBindings.push({\n                                protected: false,\n                                order: 999,\n                                enabled: true,\n                                ...binding\n                            });\n                        }\n                    });\n                },\n\n                updateKeyBinding: (keyName, updates) => {\n                    // Prefer identity match when updates carry modifiers; else first key name.\n                    const id =\n                        updates && (updates.meta != null || updates.ctrl != null || updates.shift != null)\n                            ? bindingIdentity({ key: keyName, ...updates })\n                            : null;\n                    const index = keyBindings.findIndex((b) =>\n                        id ? bindingIdentity(b) === id : b.key === keyName,\n                    );\n                    if (index >= 0) {\n                        // Update only specified properties\n                        keyBindings[index] = {\n                            ...keyBindings[index],\n                            ...updates\n                        };\n                    }\n                },\n\n                removeKeyBinding: (keyNameOrBinding) => {\n                    const index =\n                        typeof keyNameOrBinding === \"object\" && keyNameOrBinding\n                            ? keyBindings.findIndex(\n                                  (b) => bindingIdentity(b) === bindingIdentity(keyNameOrBinding),\n                              )\n                            : keyBindings.findIndex((b) => b.key === keyNameOrBinding);\n                    if (index >= 0) {\n                        if (keyBindings[index].protected) {\n                            console.warn(`Cannot remove protected key: ${keyNameOrBinding}`);\n                            return;\n                        }\n                        keyBindings.splice(index, 1);\n                    }\n                },\n\n                addFooter: (item) => {\n                    customFooterItems.push(item);\n                },\n\n                clearFooter: () => {\n                    customFooterItems.length = 0;\n                },\n\n                setFooter: (items) => {\n                    customFooterItems.length = 0;\n                    const itemsArray = Array.isArray(items) ? items : [items];\n                    customFooterItems.push(...itemsArray);\n                },\n\n                /**\n                 * Structured hotkey footer. With no args, rebuild from current\n                 * key bindings. With an array, use those `{ hotkey, caption }`\n                 * items (and optional `kind: \"toggle\", value`) instead.\n                 */\n                setSmartFooter: (items) => {\n                    if (items == null) {\n                        smartFooterHotkeys = null;\n                    } else {\n                        const arr = Array.isArray(items) ? items : [items];\n                        smartFooterHotkeys = arr.map(normalizeFooterHotkey).filter(Boolean);\n                    }\n                },\n\n                update: () => {\n                    setUpdateCounter(c => c + 1);\n                },\n\n                goBack: () => {\n                    if (actions.back) {\n                        actions.back();\n                    }\n                },\n\n                close: (result) => {\n                    cleanup(result);\n                },\n\n                parentData\n            };\n\n            // Call onRender once to let component set up\n            if (!renderResult) {\n                renderResult = onRender(context);\n            }\n\n            // Handle input - dispatch to actions\n            useInput((input, key) => {\n                // Check Ctrl+C for exit\n                if (key.ctrl && input === \"c\") {\n                    cleanup(null);\n                    process.exit(0);\n                    return;\n                }\n\n                // Paste is a multi-char string; Ink leaves only shift/meta/ctrl\n                // on `key`. Do not treat that as a hotkey (`s`, `r`, …).\n                const keyFlags = Object.entries(key || {})\n                    .filter(([, v]) => v === true)\n                    .map(([k]) => k);\n                const pasteLike = keyFlags.every((k) => k === \"shift\" || k === \"meta\" || k === \"ctrl\");\n                if (typeof input === \"string\" && input.length > 1 && pasteLike) {\n                    return;\n                }\n\n                // Find matching key binding\n                let matchedBinding = null;\n\n                for (const binding of keyBindings) {\n                    if (binding.enabled === false) continue;\n                    if (!bindingMatchesInput(binding, input, key)) continue;\n                    if (binding.condition && !binding.condition(context)) continue;\n\n                    matchedBinding = binding;\n                    break;\n                }\n\n                if (matchedBinding && actions[matchedBinding.action]) {\n                    // Execute action\n                    actions[matchedBinding.action]({\n                        input,\n                        key,\n                        binding: matchedBinding\n                    });\n\n                    // If action returns a value, might be used for something\n                    // For now, actions manage their own state via closures\n                }\n            });\n\n            const footerHotkeys = smartFooterHotkeys\n                ?? bindingsToFooterHotkeys(keyBindings, \"long\");\n\n            return h(ScreenContainer, {},\n                h(ScreenTitle, { text: title }),\n                h(ScreenDivider),\n                h(ScreenRow, {}, h(Text, {}, \" \")),\n                renderResult,\n                h(ScreenRow, {}, h(Text, {}, \" \")),\n                h(ScreenDivider),\n                h(ScreenFooter, {\n                    hotkeys: footerHotkeys,\n                    lines: customFooterItems,\n                })\n            );\n        };\n\n        const cleanup = (result) => {\n            if (instance) instance.unmount();\n            setTimeout(() => resolve(result), 50);\n        };\n\n        instance = render(h(Screen), {\n            patchConsole: false,\n            stdout: createFlickerFreeStdout(process.stdout),\n        });\n    });\n}\n\n/**\n * Helper: Show list screen (single column menu)\n */\nexport async function showListScreen(config) {\n    const { title, items, onSelect, onEscape, parentData, initialSelectedIndex = 0, renderItem, getTitle, sortable, maxHeight, sortHighlightStyle, selectionMarker } = config;\n\n    return showScreen({\n        title,\n        parentData,\n        onRender: (ctx) => {\n            // Shared state ref\n            const selectedIndexRef = { current: initialSelectedIndex };\n\n            // Set up select action at screen level\n            ctx.setAction(\"select\", () => {\n                const selected = items[selectedIndexRef.current];\n                if (onSelect) {\n                    const result = onSelect(selected.value, selectedIndexRef.current);\n                    ctx.close(result);\n                }\n            });\n\n            // Set up back action if provided\n            if (onEscape) {\n                ctx.setAction(\"back\", () => {\n                    const result = onEscape(selectedIndexRef.current);\n                    ctx.close(result);\n                });\n            }\n\n            // Add select key binding\n            ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n            // Return the component (it will set up its own navigation actions and bindings)\n            return h(ListComponent, { items, ctx, selectedIndexRef, renderItem, getTitle, sortable, maxHeight, sortHighlightStyle, selectionMarker });\n        }\n    });\n}\n\n/**\n * Helper: Show multi-column list screen (grid layout)\n */\nexport async function showMultiColumnListScreen(config) {\n    const { title, items, onSelect, onEscape, parentData, initialSelectedIndex = 0 } = config;\n\n    return showScreen({\n        title,\n        parentData,\n        onRender: (ctx) => {\n            // Shared state ref\n            const selectedIndexRef = { current: initialSelectedIndex };\n\n            // Set up select action at screen level\n            ctx.setAction(\"select\", () => {\n                const selected = items[selectedIndexRef.current];\n                if (onSelect) {\n                    const result = onSelect(selected, selectedIndexRef.current);\n                    ctx.close(result);\n                }\n            });\n\n            // Set up back action if provided\n            if (onEscape) {\n                ctx.setAction(\"back\", () => {\n                    const result = onEscape(selectedIndexRef.current);\n                    ctx.close(result);\n                });\n            }\n\n            // Add select key binding\n            ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n            // Return the component (it will set up its own navigation actions and bindings)\n            return h(MultiColumnListComponent, { items, ctx, selectedIndexRef });\n        }\n    });\n}\n\n/**\n * Helper: Show multi-column list with preview panel below\n */\nexport async function showMultiColumnListWithPreviewScreen(config) {\n    const { title, items, getPreviewContent, onSelect, onEscape, parentData, initialSelectedIndex = 0 } = config;\n\n    return showScreen({\n        title,\n        parentData,\n        onRender: (ctx) => {\n            // Shared state ref\n            const selectedIndexRef = { current: initialSelectedIndex };\n\n            // Set up select action at screen level\n            ctx.setAction(\"select\", () => {\n                const selected = items[selectedIndexRef.current];\n                if (onSelect) {\n                    const result = onSelect(selected, selectedIndexRef.current);\n                    ctx.close(result);\n                }\n            });\n\n            // Set up back action if provided\n            if (onEscape) {\n                ctx.setAction(\"back\", () => {\n                    const result = onEscape(selectedIndexRef.current);\n                    ctx.close(result);\n                });\n            }\n\n            // Add select key binding\n            ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n            // Return the component (it will set up its own navigation actions and bindings)\n            return h(MultiColumnListWithPreviewComponent, { items, getPreviewContent, ctx, selectedIndexRef });\n        }\n    });\n}\n\n// Backward compatibility aliases\nexport const showMenuScreen = showListScreen;\nexport const showWordGridScreen = showMultiColumnListScreen;\n","/**\n * Reusable UI elements for the screen system\n */\n\nimport { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\n\n// Types\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * List item component\n */\nexport function ListItem({ \n    children, \n    isSelected = false, \n    color = \"white\", \n    backgroundColor, \n    bold = false, \n    dimColor = false \n}) {\n    return h(Box, {},\n        h(Text, {\n            color: isSelected ? backgroundColor || \"green\" : color,\n            backgroundColor: isSelected ? color : backgroundColor,\n            bold: isSelected || bold,\n            dimColor: !isSelected && dimColor\n        }, children)\n    );\n}\n\n/**\n * Text block component with customizable styling\n */\nexport function TextBlock({ \n    text, \n    color = \"white\", \n    dimmed = false, \n    bold = false, \n    maxWidth: _maxWidth \n}) {\n    return h(Box, {},\n        h(Text, { \n            color, \n            dimColor: dimmed, \n            bold \n        }, text)\n    );\n}\n\n/**\n * Horizontal divider\n */\nexport function Divider({ character = \"─\", width = 80 }) {\n    return h(Box, { marginY: 1 },\n        h(Text, { dimColor: true }, character.repeat(width))\n    );\n}\n\n/**\n * Grid cell component\n */\nexport function GridCell({ \n    children, \n    width, \n    color = \"white\", \n    backgroundColor, \n    bold = false, \n    dimColor = false, \n    align = \"left\" \n}) {\n    return h(Box, { width },\n        h(Text, {\n            color,\n            backgroundColor,\n            bold,\n            dimColor,\n            textAlign: align\n        }, children)\n    );\n}\n\n/**\n * Input field component\n */\nexport function InputField({ prompt, value, onChange: _onChange, onSubmit: _onSubmit }) {\n    return h(Box, { flexDirection: \"column\" },\n        h(Text, {}, prompt),\n        h(Box, { marginTop: 1 },\n            h(Text, { color: \"cyan\" }, \" > \", value, \"_\")\n        )\n    );\n}","/**\n * Tail-follow helpers for ScrollableText.\n * Follow while the viewport is pinned to the last line; leave follow on\n * scroll-up; resume when the user scrolls back to the bottom.\n */\n\nexport function clampScroll(scrollTop, maxScroll) {\n    const max = Math.max(0, Number(maxScroll) || 0);\n    const top = Number(scrollTop) || 0;\n    return Math.min(Math.max(0, top), max);\n}\n\nexport function isScrolledToBottom(scrollTop, maxScroll) {\n    return clampScroll(scrollTop, maxScroll) >= Math.max(0, Number(maxScroll) || 0);\n}\n\nexport function nextScrollAfterUserMove(scrollTop, maxScroll, delta) {\n    const next = clampScroll((Number(scrollTop) || 0) + (Number(delta) || 0), maxScroll);\n    return { scrollTop: next, following: isScrolledToBottom(next, maxScroll) };\n}\n\nexport function nextScrollAfterContentChange({ following, scrollTop, maxScroll }) {\n    const max = Math.max(0, Number(maxScroll) || 0);\n    if (following) return { scrollTop: max, following: true };\n    const next = clampScroll(scrollTop, max);\n    return { scrollTop: next, following: isScrolledToBottom(next, max) };\n}\n","/**\n * ScrollableText — wrap long text, line/page scroll, proportional scrollbar.\n *\n *   h(ScrollableText, { ctx, text: json, bindKeys: true })\n *\n * Keys (when bindKeys):\n *   ↑/↓         — one line\n *   ⌥↑/↓ ^↑/↓   — one page (ink `meta` ≈ Option/Alt; ⌘ often never reaches the TTY)\n *   PgUp/PgDn   — one page\n */\n\nimport { useState, useEffect, useMemo, useRef, createElement } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getScreenWidth } from \"./components.js\";\nimport { getScreenBodyRows } from \"./screen-layout.js\";\nimport {\n    BAR_THUMB,\n    BAR_TRACK,\n    PAGE_SCROLL_KEY_BINDINGS,\n    scrollbarGlyphs,\n} from \"./scrollbar.js\";\nimport { nextScrollAfterContentChange, nextScrollAfterUserMove } from \"./follow-scroll.js\";\nimport { padEndVisible, wrapTextLines } from \"./visible-text.js\";\n\nexport { scrollbarGlyphs } from \"./scrollbar.js\";\nexport { wrapTextLines } from \"./visible-text.js\";\n\nconst h = createElement;\n\nconst SCROLL_KEYS = [\n    { key: \"upArrow\", caption: \"scroll\", action: \"scrollUp\", order: 0 },\n    { key: \"downArrow\", caption: \"scroll\", action: \"scrollDown\", order: 0 },\n    ...PAGE_SCROLL_KEY_BINDINGS,\n];\n/**\n * @param {{\n *   ctx: object,\n *   text?: string,\n *   lines?: string[],\n *   maxHeight?: number,\n *   wrap?: boolean,\n *   showScrollbar?: boolean,\n *   showStatus?: boolean,\n *   bindKeys?: boolean,\n *   header?: unknown,\n *   followBottom?: boolean,\n *   reserveRows?: number,\n * }} props\n */\nexport function ScrollableText({\n    ctx,\n    text = \"\",\n    lines: linesProp,\n    maxHeight,\n    wrap = true,\n    showScrollbar = true,\n    showStatus = true,\n    bindKeys = true,\n    header = null,\n    followBottom = false,\n    reserveRows = 0,\n}) {\n    const [scrollTop, setScrollTop] = useState(0);\n    const [following, setFollowing] = useState(() => !!followBottom);\n\n    const extraRows = (header == null ? 0 : 1) + (showStatus ? 1 : 0) + (Number(reserveRows) || 0);\n    const viewportRows = Math.max(\n        4,\n        maxHeight != null ? Math.floor(maxHeight) : getScreenBodyRows({ extraRows }),\n    );\n\n    // Match ScreenContainer inner width: container is term-4, minus border+paddingX → term-8\n    // (same heuristic as ListComponent / ScreenDivider).\n    const contentCols = Math.max(20, getScreenWidth() - 4);\n    // Always reserve the bar column when enabled so wrap width does not jump when overflow starts.\n    const barCols = showScrollbar ? 1 : 0;\n    const textWidth = Math.max(8, contentCols - barCols);\n\n    const allLines = useMemo(() => {\n        if (Array.isArray(linesProp)) return linesProp.map((l) => String(l ?? \"\"));\n        return wrap ? wrapTextLines(text, textWidth) : String(text ?? \"\").split(\"\\n\");\n    }, [linesProp, text, wrap, textWidth]);\n\n    const needsBar = showScrollbar && allLines.length > viewportRows;\n    const maxScroll = Math.max(0, allLines.length - viewportRows);\n    const clamped = Math.min(Math.max(0, scrollTop), maxScroll);\n    const visible = allLines.slice(clamped, clamped + viewportRows);\n    const bar = needsBar ? scrollbarGlyphs(viewportRows, allLines.length, clamped) : null;\n\n    const maxScrollRef = useRef(maxScroll);\n    const pageSizeRef = useRef(viewportRows);\n    const scrollTopRef = useRef(scrollTop);\n    const followingRef = useRef(following);\n    maxScrollRef.current = maxScroll;\n    pageSizeRef.current = viewportRows;\n    scrollTopRef.current = scrollTop;\n    followingRef.current = following;\n\n    useEffect(() => {\n        const next = nextScrollAfterContentChange({\n            following: followBottom && followingRef.current,\n            scrollTop: scrollTopRef.current,\n            maxScroll,\n        });\n        if (next.scrollTop !== scrollTopRef.current) setScrollTop(next.scrollTop);\n        if (followBottom && next.following !== followingRef.current) setFollowing(next.following);\n    }, [maxScroll, followBottom]);\n\n    const applyUserScroll = (delta) => {\n        const next = nextScrollAfterUserMove(scrollTopRef.current, maxScrollRef.current, delta);\n        setScrollTop(next.scrollTop);\n        if (followBottom) setFollowing(next.following);\n        // Do not ctx.update() — that remounts the bordered Screen and flashes.\n        // Slot keys stay `slot-i` so Ink patches line text in place (like less).\n    };\n\n    useEffect(() => {\n        if (!ctx || !bindKeys) return undefined;\n\n        ctx.setKeyBinding(SCROLL_KEYS);\n\n        ctx.setAction(\"scrollUp\", () => applyUserScroll(-1));\n        ctx.setAction(\"scrollDown\", () => applyUserScroll(1));\n        ctx.setAction(\"pageUp\", () => applyUserScroll(-pageSizeRef.current));\n        ctx.setAction(\"pageDown\", () => applyUserScroll(pageSizeRef.current));\n\n        return undefined;\n    }, [ctx, bindKeys, followBottom]);\n\n    const status =\n        allLines.length === 0\n            ? \"empty\"\n            : `lines ${clamped + 1}-${Math.min(clamped + visible.length, allLines.length)} of ${allLines.length}` +\n              (needsBar ? \" · ⌥↑/↓ or PgUp/Dn page\" : \"\") +\n              (followBottom && following ? \" · follow\" : followBottom ? \" · follow off\" : \"\");\n\n    // Fixed-width rows + stable slot keys: scrolling updates text, does not remount.\n    // Always emit `viewportRows` slots so the pane height (and Screen border) stay put.\n    const rowNodes = [];\n    for (let i = 0; i < viewportRows; i++) {\n        const line = visible[i] ?? \"\";\n        const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? \" \" : \"\";\n        const isThumb = glyph === BAR_THUMB;\n        rowNodes.push(\n            h(\n                Box,\n                { key: `slot-${i}`, flexDirection: \"row\", width: contentCols, flexShrink: 0 },\n                h(\n                    Box,\n                    { width: textWidth, flexShrink: 0 },\n                    h(Text, { wrap: \"truncate\" }, padEndVisible(line, textWidth)),\n                ),\n                showScrollbar\n                    ? h(Box, { width: 1, flexShrink: 0 }, h(Text, { color: isThumb ? \"cyan\" : \"gray\" }, glyph))\n                    : null,\n            ),\n        );\n    }\n\n    return h(\n        Box,\n        { flexDirection: \"column\", overflow: \"hidden\" },\n        header == null\n            ? null\n            : typeof header === \"string\"\n              ? h(Text, { color: \"gray\" }, header)\n              : header,\n        showStatus ? h(Text, { color: \"gray\" }, status) : null,\n        ...rowNodes,\n    );\n}\n","/**\n * Typed + pasted text for Ink `useInput`.\n *\n * Ink calls the handler once with the full string when the user pastes more\n * than one character. Terminals also wrap paste in CSI 200~/201~ (bracketed\n * paste); those markers must not land in the field.\n */\n\nconst BRACKETED_PASTE_RE = /\\u001b\\[200~|\\u001b\\[201~|\\[200~|\\[201~/g;\nconst CONTROL_RE = /[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/g;\n\nexport function sanitizeTextInput(input, { allowNewlines = false } = {}) {\n    let s = String(input ?? \"\").replace(BRACKETED_PASTE_RE, \"\");\n    if (!allowNewlines) s = s.replace(/[\\r\\n]+/g, \"\");\n    else s = s.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n    return s.replace(CONTROL_RE, \"\");\n}\n\nfunction isTextInsertKey(key) {\n    if (!key) return true;\n    if (key.return || key.escape || key.tab) return false;\n    if (key.backspace || key.delete) return false;\n    if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) return false;\n    if (key.pageUp || key.pageDown) return false;\n    if (key.ctrl) return false;\n    return true;\n}\n\n/**\n * @param {string} current\n * @param {string} input\n * @param {object} key\n * @param {{ allowNewlines?: boolean, accept?: RegExp }} [opts]\n * @returns {string|null} next value, or null if this key is not text\n */\nexport function nextTextInputValue(current, input, key, opts = {}) {\n    const cur = String(current ?? \"\");\n    if (key?.backspace || key?.delete) return cur.slice(0, -1);\n    if (!isTextInsertKey(key)) return null;\n\n    let chunk = sanitizeTextInput(input, opts);\n    if (opts.accept instanceof RegExp) {\n        chunk = [...chunk].filter((ch) => opts.accept.test(ch)).join(\"\");\n    }\n    if (!chunk) return null;\n    return cur + chunk;\n}\n","/**\n * Utility functions for Screen System\n */\n\n/**\n * Build breadcrumb-style title\n * @param parts - Parts of the breadcrumb path\n * @returns Formatted breadcrumb\n *\n * Examples:\n *   buildBreadcrumb(['Menu']) → 'Menu'\n *   buildBreadcrumb(['Menu', 'Info']) → '←  Info'\n *   buildBreadcrumb(['Menu', 'Words', 'nefarious']) → '←  Words  ←  nefarious'\n */\nexport function buildBreadcrumb(parts) {\n    if (parts.length === 0) return \"\";\n    if (parts.length === 1) return parts[0];\n\n    // Skip first part (root), add arrows with spaces to rest\n    return parts.slice(1).map(part => `←  ${part}`).join(\"  \");\n}\n\n/**\n * Create multi-line breadcrumb with details\n * @param path - Navigation path\n * @param suffix - Additional suffix (e.g., 'Details')\n * @returns Formatted breadcrumb with suffix\n *\n * Example:\n *   buildDetailBreadcrumb(['Menu', 'Words', 'nefarious'], 'Details')\n *   → '←  Words  ←  nefarious Details'\n */\nexport function buildDetailBreadcrumb(path, suffix = \"\") {\n    if (path.length <= 1) {\n        return suffix ? `←  ${suffix}` : path[0] || \"\";\n    }\n\n    const breadcrumb = buildBreadcrumb(path);\n    return suffix ? `${breadcrumb} ${suffix}` : breadcrumb;\n}\n","/**\n * Footer builder - composes footer messages from multiple sources\n */\n\n\n\n\n\n\n\n\n\n/**\n * Build footer lines from multiple message sources\n *\n * @param config - Footer configuration object\n * @returns Array of footer lines\n */\nexport function buildFooter(config = {}) {\n    const {\n        navigation = null,\n        actions = null,\n        info = null,\n        escape = \"Esc to go back\",\n        custom = null\n    } = config;\n\n    const lines = [];\n\n    // Build main help line (navigation + actions + escape)\n    const mainParts = [];\n\n    if (navigation) {\n        mainParts.push(navigation);\n    }\n\n    if (actions) {\n        mainParts.push(actions);\n    }\n\n    if (escape) {\n        mainParts.push(escape);\n    }\n\n    if (mainParts.length > 0) {\n        lines.push(mainParts.join(\", \"));\n    }\n\n    // Add info line if present\n    if (info) {\n        const infoLines = Array.isArray(info) ? info : [info];\n        lines.push(...infoLines);\n    }\n\n    // Add custom lines if present\n    if (custom) {\n        const customLines = Array.isArray(custom) ? custom : [custom];\n        lines.push(...customLines);\n    }\n\n    return lines;\n}\n\n/**\n * Predefined footer configurations for common screen types\n */\nexport const FooterPresets = {\n    /**\n     * Menu screen footer\n     */\n    menu: (customInfo = null) => buildFooter({\n        navigation: \"↑/↓ to navigate\",\n        actions: \"Enter to select\",\n        escape: \"Esc to go back\",\n        info: customInfo\n    }),\n\n    /**\n     * Word grid footer\n     */\n    wordGrid: (totalWords) => buildFooter({\n        navigation: \"↑↓←→ to navigate\",\n        actions: \"Enter to select\",\n        escape: \"Esc to go back\",\n        info: `Total: ${totalWords} words`\n    }),\n\n    /**\n     * Text input footer\n     */\n    textInput: () => buildFooter({\n        actions: \"Type and press Enter to submit\",\n        escape: \"Esc to cancel\"\n    }),\n\n    /**\n     * Info/static screen footer\n     */\n    info: () => buildFooter({\n        escape: \"Esc to continue\"\n    }),\n\n    /**\n     * Main menu footer (escape exits)\n     */\n    mainMenu: () => buildFooter({\n        navigation: \"↑/↓ to navigate\",\n        actions: \"Enter to select\",\n        escape: \"Esc to exit\"\n    }),\n\n    /**\n     * Action menu footer (for word cards, etc.)\n     */\n    actionMenu: (hasAudio = false) => {\n        const parts = buildFooter({\n            navigation: \"↑/↓ to navigate\",\n            actions: \"Enter to select\",\n            escape: \"Esc to go back\"\n        });\n\n        if (hasAudio) {\n            parts.push(\"Audio available\");\n        }\n\n        return parts;\n    }\n};\n\n/**\n * Combine multiple footer messages into organized lines\n * Smart grouping of related messages\n *\n * @param messages - Individual footer messages\n * @returns Organized footer lines\n */\nexport function organizeFooterMessages(messages) {\n    if (!messages || messages.length === 0) {\n        return [\"Esc to go back\"];\n    }\n\n    // Group similar messages\n    const navigation = messages.filter(m => m.includes(\"↑\") || m.includes(\"↓\") || m.includes(\"←\") || m.includes(\"→\"));\n    const actions = messages.filter(m => m.includes(\"Enter\") || m.includes(\"select\") || m.includes(\"submit\"));\n    const escape = messages.filter(m => m.includes(\"Esc\"));\n    const others = messages.filter(m =>\n        !navigation.includes(m) &&\n        !actions.includes(m) &&\n        !escape.includes(m)\n    );\n\n    const lines = [];\n\n    // Combine navigation, actions, and escape on one line\n    const mainLine = [...navigation, ...actions, ...escape].join(\", \");\n    if (mainLine) lines.push(mainLine);\n\n    // Add other messages as separate lines\n    lines.push(...others);\n\n    return lines;\n}\n","/**\n * Screen System - Action-based architecture\n * Converted from legacy/screenSystem/src\n */\n\n// Re-export React and React hooks (encapsulated)\nimport React, { useState, useEffect, useLayoutEffect, useRef, useMemo, useCallback, memo, createElement } from \"react\";\nexport { React, useState, useEffect, useLayoutEffect, useRef, useMemo, useCallback, memo };\nexport { createElement as h };\n\n// Re-export Ink components (encapsulated)\nexport { Box, Text, useInput } from \"ink\";\n\n// Screen functions\nexport {\n    showScreen,\n    showListScreen,\n    showMultiColumnListScreen,\n    showMultiColumnListWithPreviewScreen,\n    // Backward compatibility aliases\n    showMenuScreen,\n    showWordGridScreen,\n    formatFooterHotkey,\n    formatKeyBindings,\n    bindingsToFooterHotkeys,\n    FOOTER_HOTKEY_STYLE,\n    FOOTER_MUTED_STYLE,\n    styleFooterHotkey,\n    styleFooterMuted,\n} from \"./screens.js\";\n\n// Reusable components\nexport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\nexport { ScreenContainer, ScreenRow, ScreenTitle, ScreenBody, ScreenFooter, ScreenDivider, normalizeFooterHotkey } from \"./components.js\";\nexport {\n    getScreenBodyRows,\n    getScreenChromeRows,\n    getScreenFrameBoxHeight,\n} from \"./screen-layout.js\";\nexport { ListItem, TextBlock, Divider, GridCell, InputField } from \"./ui-elements.js\";\nexport { ScrollableText, wrapTextLines, scrollbarGlyphs } from \"./scrollable-text.js\";\nexport { createFlickerFreeStdout } from \"./flicker-free-stdout.js\";\nexport { stripAnsi, visibleWidth, padEndVisible, sliceVisible } from \"./visible-text.js\";\nexport {\n    clampScroll,\n    isScrolledToBottom,\n    nextScrollAfterUserMove,\n    nextScrollAfterContentChange,\n} from \"./follow-scroll.js\";\nexport {\n    PAGE_SCROLL_KEY_BINDINGS,\n    BAR_THUMB,\n    BAR_TRACK,\n} from \"./scrollbar.js\";\nexport {\n    bindingIdentity,\n    bindingMatchesInput,\n    formatBindingKey,\n} from \"./key-bindings.js\";\nexport { nextTextInputValue, sanitizeTextInput } from \"./text-input.js\";\n\n// Utilities\nexport { buildBreadcrumb, buildDetailBreadcrumb } from \"./utils.js\";\nexport { buildFooter, FooterPresets, organizeFooterMessages } from \"./footer-builder.js\";\n\n// For CommonJS compatibility: pre-load ESM dependencies\nlet loadPromise = null;\nexport async function load() {\n    if (loadPromise) return loadPromise;\n    loadPromise = Promise.all([\n        import(\"react\"),\n        import(\"ink\")\n    ]).then(() => {}) ;\n    return loadPromise;\n}\n// Auto-load in ESM, but CJS users should call load() explicitly\nif (typeof window === \"undefined\") {\n    load().catch(() => {\n    // Ignore errors during auto-load, user can call load() explicitly\n    });\n}\n","// Main exports for @nmakarov/cli-toolkit\nexport * from \"./args/index.js\";\nexport * from \"./params/index.js\";\nexport * from \"./screen/index.js\";\nexport * from \"./filedatabase/index.js\";\nexport * from \"./db/index.js\";\nexport * from \"./s3/index.js\";\nexport * from \"./aws/index.js\";\nexport * from \"./init/index.js\";\nexport * from \"./deploy/index.js\";\nexport * from \"./tasks/index.js\";\n","// Arguments discovery and parsing module\n// This module provides utilities for parsing CLI arguments and detecting flags\n\nimport { readFileSync, existsSync } from \"fs\";\nimport { resolve, dirname, basename, extname, join, isAbsolute } from \"path\";\nimport { config } from \"dotenv\";\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Parse command line arguments with support for aliases, overrides, and defaults\n *\n * Precedence order (highest to lowest):\n * 1. Overrides (constructor config)\n * 2. CLI args (command line)\n * 3. Config files (loaded from files)\n * 4. Environment variables (process.env)\n * 5. Defaults (constructor config)\n */\nexport class Args {\n    args = {};\n    flags = {};\n    options = {};\n    commands = [];\n    usedKeys = new Set();\n    aliases = {};\n    overrides = {};\n    defaults = {};\n    prefixes = [];\n    nots = [];\n    configValues = {};\n    configsLoaded = [];\n    env = \"local\";\n\n    constructor(contextOrConfig = {}, config) {\n        // Support (context, config) or (config) for backward compatibility\n        const hasContext = config !== undefined;\n        const configToUse = hasContext ? (config ?? {}) : (contextOrConfig ?? {});\n        const context = hasContext ? contextOrConfig : undefined;\n\n        // Set defaults first\n        this.aliases = {};\n        this.overrides = {};\n        this.defaults = {};\n        this.prefixes = [\"not\", \"no\"];\n\n        // Apply configuration\n        if (Object.keys(configToUse).length > 0) {\n            this.configure(configToUse);\n        }\n\n        // Parse arguments first to get environment\n        const args = configToUse.args || process.argv.slice(2);\n        this.parseArgs(args);\n\n        // Runtime environment selector (--env / ENV / NODE_ENV). Default \"local\".\n        // Prefer process env before .env (pm2 ecosystem / ensure-env.cjs). After\n        // loadDotEnv, re-resolve so a late ENV (or .env ENV=) still applies —\n        // pm2 has been observed to omit ecosystem env on the first start after\n        // a kill_timeout SIGKILL.\n        this.env = this.get(\"env\")?.toLowerCase() || \"local\";\n\n        // Load .env file (single file with LOCAL / PRODUCTION / STAGE variants)\n        this.loadDotEnv();\n\n        const envAfterDotEnv = this.get(\"env\")?.toLowerCase();\n        if (envAfterDotEnv) {\n            this.env = envAfterDotEnv;\n        }\n\n        // Load configuration files\n        this.loadConfigFiles();\n\n        // Check for conflicts (short + long form of same option)\n        this.checkConflicts();\n\n        // Register cleanup to warn about unused CLI args on exit (when context has registerCleanup)\n        if (context && typeof context.registerCleanup === \"function\") {\n            context.registerCleanup((ctx) => {\n                const unusedArgs = ctx.args.getUnused();\n                if (unusedArgs.length > 0) {\n                    ctx.logger.warn(\"Unused CLI args:\", unusedArgs.join(\", \"));\n                }\n            });\n        }\n    }\n\n    /**\n     * Configure Args options\n     * Only parameters present in config are updated\n     * Note: Args is special - it's initialized first, so it can't take context\n     */\n    configure(config) {\n        if (config.aliases !== undefined) {\n            this.aliases = config.aliases;\n        }\n        if (config.overrides !== undefined) {\n            this.overrides = config.overrides;\n        }\n        if (config.defaults !== undefined) {\n            this.defaults = config.defaults;\n        }\n        if (config.prefixes !== undefined) {\n            this.prefixes = config.prefixes;\n        }\n        // Note: args array can't be reconfigured after construction\n    }\n\n    /**\n     * Initialize Args instance.\n     * Args.init(context, config) when used from init/setup: context has registerCleanup, Args registers unused-args cleanup.\n     * Args.init(config) for standalone use (no cleanup).\n     */\n    static init(contextOrConfig, config) {\n        if (config !== undefined) {\n            return new Args(contextOrConfig, config);\n        }\n        return new Args(contextOrConfig ?? {});\n    }\n\n    /**\n     * Parse command line arguments\n     */\n    parseArgs(args) {\n        let i = 0;\n        while (i < args.length) {\n            const arg = args[i];\n\n            if (arg.startsWith(\"--\")) {\n                // Long option: --key=value or --key\n                const [key, value] = this.parseLongOption(arg);\n                this.setValue(key, value);\n                i++;\n            } else if (arg.startsWith(\"-\")) {\n                // Short option: -k=value, -k, or bundled -vsd\n                const result = this.parseShortOption(arg, args, i);\n                if (result.consumed > 0) {\n                    i += result.consumed;\n                } else {\n                    i++;\n                }\n            } else {\n                // Command (no prefix)\n                this.commands.push(arg);\n                i++;\n            }\n        }\n    }\n\n    /**\n     * Parse long option (--key=value or --key)\n     */\n    parseLongOption(arg) {\n        const key = arg.slice(2); // Remove '--'\n\n        // Check for negative flags (--no-debug, --not-verbose)\n        const prefix = this.prefixes.find((p) => key.startsWith(p));\n        if (prefix) {\n            let strippedKey = key.slice(prefix.length);\n            // Remove leading dash if present\n            if (strippedKey.startsWith(\"-\")) {\n                strippedKey = strippedKey.slice(1);\n            }\n            this.nots.push(key);\n            return [strippedKey, false];\n        }\n\n        if (key.includes(\"=\")) {\n            // --key=value - need to handle quoted values properly\n            const eqIndex = key.indexOf(\"=\");\n            const optionKey = key.slice(0, eqIndex);\n            const value = key.slice(eqIndex + 1);\n            return [optionKey, this.parseValue(value)];\n        } else {\n            // --key (boolean flag)\n            return [key, true];\n        }\n    }\n\n    /**\n     * Parse short option (-k=value, -k, or bundled -vsd)\n     */\n    parseShortOption(arg, args, index) {\n        const key = arg.slice(1); // Remove '-'\n\n        // Check if it's a single short flag with value (like -vo file.txt)\n        if (key.length === 1 && index + 1 < args.length && !args[index + 1].startsWith(\"-\")) {\n            // Single short flag with separate value\n            const value = args[index + 1];\n            this.setValue(key, this.parseValue(value));\n            return { consumed: 2 }; // Consumed this flag and the next argument\n        }\n\n        // Check if it's a bundled short flags (like -vsd)\n        if (key.length > 1 && !key.includes(\"=\")) {\n            // Handle bundled flags: -vsd = -v -s -d\n            // Process each character, valid ones become flags, invalid ones become unused\n            for (let i = 0; i < key.length; i++) {\n                const shortKey = key[i];\n                if (shortKey in this.aliases) {\n                    this.setValue(shortKey, true);\n                } else {\n                    // Invalid short flag - add to unused keys\n                    this.args[shortKey] = true;\n                }\n            }\n            return { consumed: 1 };\n        }\n\n        if (key.includes(\"=\")) {\n            // -k=value or -vsdk=4 - need to handle quoted values properly\n            const eqIndex = key.indexOf(\"=\");\n            const optionKey = key.slice(0, eqIndex);\n            const value = key.slice(eqIndex + 1);\n\n            // Check if this is a bundled flag with value on the last one (like -vsdk=4)\n            if (optionKey.length > 1) {\n                // Handle bundled flags with value on the last one: -vsdk=4 = -v -s -d -k=4\n                for (let i = 0; i < optionKey.length - 1; i++) {\n                    const shortKey = optionKey[i];\n                    if (shortKey in this.aliases) {\n                        this.setValue(shortKey, true);\n                    } else {\n                        this.args[shortKey] = true;\n                    }\n                }\n                // Handle the last flag with value\n                const lastKey = optionKey[optionKey.length - 1];\n                if (lastKey in this.aliases) {\n                    this.setValue(lastKey, this.parseValue(value));\n                } else {\n                    this.args[lastKey] = this.parseValue(value);\n                }\n            } else {\n                // Single flag with value: -k=value\n                this.setValue(optionKey, this.parseValue(value));\n            }\n            return { consumed: 1 };\n        } else {\n            // -k (boolean flag)\n            this.setValue(key, true);\n            return { consumed: 1 };\n        }\n    }\n\n    /**\n     * Parse value (handle quotes)\n     */\n    parseValue(value) {\n        // Remove surrounding quotes if present\n        if (\n            (value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")) ||\n            (value.startsWith(\"'\") && value.endsWith(\"'\"))\n        ) {\n            return value.slice(1, -1);\n        }\n        return value;\n    }\n\n    /**\n     * Set a value with proper categorization\n     */\n    setValue(key, value) {\n        // Resolve alias if it's a short form\n        const resolvedKey = this.aliases[key] || key;\n\n        if (typeof value === \"boolean\") {\n            this.flags[resolvedKey] = value;\n        } else {\n            this.options[resolvedKey] = value;\n        }\n\n        // Always set the value in lowercase (for case-insensitive lookup, like legacy)\n        this.args[resolvedKey.toLowerCase()] = value;\n    }\n\n    /**\n     * Check for conflicts (short + long form of same option)\n     */\n    checkConflicts() {\n        const conflicts = [];\n\n        for (const [shortKey, longKey] of Object.entries(this.aliases)) {\n            const hasShort = this.args[shortKey] !== undefined;\n            const hasLong = this.args[longKey] !== undefined;\n\n            if (hasShort && hasLong) {\n                conflicts.push(`Both -${shortKey} and --${longKey} specified`);\n            }\n        }\n\n        if (conflicts.length > 0) {\n            throw new Error(`Argument conflicts: ${conflicts.join(\", \")}`);\n        }\n    }\n\n    /**\n     * Get a value with precedence order\n     */\n    get(key) {\n        const resolvedKey = this.aliases[key] || key;\n        // Normalize key to lowercase for case-insensitive lookups\n        // This ensures that params.get(\"showAuthRequest\") works regardless of how\n        // the key was provided (CLI: --showAuthRequest, --showauthrequest, env: SHOW_AUTH_REQUEST)\n        const lcKey = resolvedKey.toLowerCase();\n        this.usedKeys.add(lcKey);\n\n        // Precedence order: overrides > CLI args > config files > env vars > defaults\n        // All lookups are case-insensitive using lcKey\n        \n        // Case-insensitive lookup for overrides\n        const overrideKey = Object.keys(this.overrides).find(k => k.toLowerCase() === lcKey);\n        if (overrideKey !== undefined) {\n            return this.overrides[overrideKey];\n        }\n\n        // Case-insensitive lookup for CLI args\n        // Try environment-specific CLI args first (e.g., --silent_local, --debug_production)\n        const lcKeyWithEnv = `${lcKey}${this.env ? `_${this.env.toLowerCase()}` : \"\"}`;\n        if (this.env && this.args[lcKeyWithEnv] !== undefined) {\n            return this.args[lcKeyWithEnv];\n        } else if (this.args[lcKey] !== undefined) {\n            return this.args[lcKey];\n        }\n\n        // Case-insensitive lookup for config file values\n        const configKey = Object.keys(this.configValues).find(k => k.toLowerCase() === lcKey);\n        if (configKey !== undefined) {\n            return this.configValues[configKey];\n        }\n\n        // Environment variable (convert key to ENV_VAR format)\n        // Use resolvedKey (original case) for env var conversion to preserve camelCase -> SNAKE_CASE\n        const envKey = this.toEnvKey(resolvedKey);\n        const envKeyWithEnv = `${envKey}${this.env ? `_${this.env.toUpperCase()}` : \"\"}`;\n\n        // Try environment-specific env vars first (e.g., SILENT_LOCAL, DEBUG_PRODUCTION)\n        const envSpecificKey = Object.keys(process.env).find(\n            (k) => this.env && k.toUpperCase() === envKeyWithEnv\n        );\n        \n        // Try exact match first (case-insensitive)\n        const envKeyFound = Object.keys(process.env).find((k) => k.toUpperCase() === envKey);\n        \n        // If not found, try alternative formats (e.g., TRESTLE_IDXPLUS_2_ID -> TRESTLE_IDXPLUS2_ID)\n        // This handles cases where env var names don't follow standard camelCase->SNAKE_CASE conversion\n        const envKeyAlt = envKey.replace(/_([0-9])/g, \"$1\"); // Remove underscore before numbers\n        const envKeyAltFound = !envKeyFound ? Object.keys(process.env).find((k) => k.toUpperCase() === envKeyAlt) : null;\n\n        if (envSpecificKey) {\n            return process.env[envSpecificKey];\n        } else if (envKeyFound) {\n            return process.env[envKeyFound];\n        } else if (envKeyAltFound) {\n            return process.env[envKeyAltFound];\n        }\n\n        // Case-insensitive lookup for defaults\n        const defaultKey = Object.keys(this.defaults).find(k => k.toLowerCase() === lcKey);\n        if (defaultKey !== undefined) {\n            return this.defaults[defaultKey];\n        }\n\n        // NODE_ENV fallback for 'env' key (like legacy)\n        if (lcKey === \"env\" && process.env.NODE_ENV !== undefined) {\n            return process.env.NODE_ENV;\n        }\n\n        return undefined;\n    }\n\n    /**\n     * Return which layer provided the value for get(key): overrides, cli, config, env, or default.\n     * Does not add key to usedKeys. Use after get(key) when you need the origin.\n     */\n    getSource(key) {\n        const resolvedKey = this.aliases[key] || key;\n        const lcKey = resolvedKey.toLowerCase();\n\n        const overrideKey = Object.keys(this.overrides).find(k => k.toLowerCase() === lcKey);\n        if (overrideKey !== undefined) return \"overrides\";\n\n        const lcKeyWithEnv = `${lcKey}${this.env ? `_${this.env.toLowerCase()}` : \"\"}`;\n        if (this.env && this.args[lcKeyWithEnv] !== undefined) return \"cli\";\n        if (this.args[lcKey] !== undefined) return \"cli\";\n\n        const configKey = Object.keys(this.configValues).find(k => k.toLowerCase() === lcKey);\n        if (configKey !== undefined) return \"config\";\n\n        const envKey = this.toEnvKey(resolvedKey);\n        const envKeyWithEnv = `${envKey}${this.env ? `_${this.env.toUpperCase()}` : \"\"}`;\n        const envSpecificKey = Object.keys(process.env).find(k => this.env && k.toUpperCase() === envKeyWithEnv);\n        const envKeyFound = Object.keys(process.env).find(k => k.toUpperCase() === envKey);\n        const envKeyAlt = envKey.replace(/_([0-9])/g, \"$1\");\n        const envKeyAltFound = !envKeyFound ? Object.keys(process.env).find(k => k.toUpperCase() === envKeyAlt) : null;\n        if (envSpecificKey || envKeyFound || envKeyAltFound) return \"env\";\n\n        const defaultKey = Object.keys(this.defaults).find(k => k.toLowerCase() === lcKey);\n        if (defaultKey !== undefined) return \"default\";\n        if (lcKey === \"env\" && process.env.NODE_ENV !== undefined) return \"env\";\n\n        return undefined;\n    }\n\n    /**\n     * Set a value (for testing/internal use)\n     */\n    set(key, value) {\n        this.args[key] = value;\n    }\n\n    /**\n     * Check if a command exists (case-insensitive)\n     */\n    hasCommand(cmd) {\n        return this.commands.some((command) => command.toLowerCase() === cmd.toLowerCase());\n    }\n\n    /**\n     * Get all commands\n     */\n    getCommands() {\n        return [...this.commands];\n    }\n\n    /**\n     * Get used keys (as array)\n     */\n    getUsed() {\n        return Array.from(this.usedKeys);\n    }\n\n    /**\n     * Get unused keys (as array)\n     */\n    getUnused() {\n        const unused = [];\n\n        for (const key of Object.keys(this.args)) {\n            if (!this.usedKeys.has(key) && !this.nots.includes(key)) {\n                unused.push(key);\n            }\n        }\n\n        return unused;\n    }\n\n    /**\n     * Convert key to environment variable format\n     * Converts camelCase to SNAKE_CASE\n     */\n    toEnvKey(key) {\n        // If already in SNAKE_CASE (contains underscores and is uppercase), return as-is\n        if (key.includes(\"_\") && key === key.toUpperCase()) {\n            return key;\n        }\n\n        // Convert camelCase to SNAKE_CASE\n        // Standard conversion: add underscore before capitals and numbers\n        return key\n            .replace(/[A-Z0-9]/g, (match, offset) =>\n                offset === 0 ? match : \"_\" + match.toLowerCase()\n            )\n            .toUpperCase();\n    }\n\n    /**\n     * Load .env file\n     */\n    loadDotEnv() {\n        const dotEnvPath = this.get(\"dotEnvPath\") || process.cwd();\n        const dotEnvFile = this.get(\"dotEnvFile\") || \".env\";\n\n        // If custom dotEnvFile is specified, use it as-is\n        if (this.get(\"dotEnvFile\")) {\n            const customPath = resolve(dotEnvPath, dotEnvFile);\n            if (existsSync(customPath)) {\n                config({ path: customPath, quiet: true });\n            }\n            return;\n        }\n\n        // Prefer a single .env that holds all env-suffixed keys (KEY_LOCAL,\n        // KEY_PRODUCTION, …). Optional `.env.<env>` overlay is still supported\n        // for examples / one-off overrides, but only after the base .env.\n        let dotEnvPathFile = resolve(dotEnvPath, dotEnvFile);\n\n        if (!existsSync(dotEnvPathFile) && !this.get(\"dotEnvPath\")) {\n            const examplesPath = resolve(dotEnvPath, \"examples\");\n            const examplesEnvFile = resolve(examplesPath, dotEnvFile);\n            if (existsSync(examplesEnvFile)) {\n                dotEnvPathFile = examplesEnvFile;\n            } else {\n                dotEnvPathFile = resolve(dotEnvPath, \"..\", dotEnvFile);\n            }\n        }\n\n        if (dotEnvPathFile && existsSync(dotEnvPathFile)) {\n            config({ path: dotEnvPathFile, quiet: true });\n        }\n\n        // Optional overlay: .env.production / .env.local (does not replace base .env)\n        const envSpecificFile = `.env.${this.env}`;\n        const envSpecificPath = resolve(dotEnvPath, envSpecificFile);\n        if (existsSync(envSpecificPath) && envSpecificPath !== dotEnvPathFile) {\n            config({ path: envSpecificPath, quiet: true });\n        } else if (!this.get(\"dotEnvPath\")) {\n            const examplesOverlay = resolve(dotEnvPath, \"examples\", envSpecificFile);\n            if (existsSync(examplesOverlay)) {\n                config({ path: examplesOverlay, quiet: true });\n            }\n        }\n    }\n\n    /**\n     * Load configuration files\n     */\n    loadConfigFiles() {\n        this.configsLoaded = [];\n        this.configValues = {};\n\n        const _defaultConfigExtension = this.get(\"defaultConfigExtension\") || \"js\";\n        const optConfigFiles = this.get(\"config\") || this.get(\"configs\") || \"\";\n        const configFiles = optConfigFiles ? optConfigFiles.split(/,\\s*/) : [];\n        const optConfigFilePath = this.get(\"configPath\");\n\n        if (configFiles.length > 0) {\n            for (const cfgFile of configFiles) {\n                let notLoaded = false;\n                let notLoadedEnvSpecific = false;\n\n                const cfgFileWithPath = this.resolveFileWithPath(optConfigFilePath, cfgFile);\n                try {\n                    const cfgContents = this.requireConfigFile(cfgFileWithPath);\n                    this.configValues = { ...this.configValues, ...cfgContents };\n                    this.configsLoaded.push(cfgFileWithPath);\n                } catch {\n                    notLoaded = true;\n                }\n\n                const cfgEnvFileWithPath = this.resolveFileWithPath(\n                    optConfigFilePath,\n                    cfgFile,\n                    this.env\n                );\n                if (cfgEnvFileWithPath !== cfgFileWithPath) {\n                    try {\n                        const cfgContents = this.requireConfigFile(cfgEnvFileWithPath);\n                        this.configValues = { ...this.configValues, ...cfgContents };\n                        this.configsLoaded.push(cfgEnvFileWithPath);\n                    } catch {\n                        notLoadedEnvSpecific = true;\n                    }\n                } else {\n                    notLoadedEnvSpecific = true;\n                }\n\n                if (notLoaded && notLoadedEnvSpecific) {\n                    throw new Error(`can't load config file \"${cfgFileWithPath}\"`);\n                }\n            }\n        }\n    }\n\n    /**\n     * Resolve file path with environment-specific naming\n     */\n    resolveFileWithPath(\n        optConfigFilePath,\n        cfgFile,\n        env\n    ) {\n        let cfgFileWithPath = optConfigFilePath\n            ? isAbsolute(optConfigFilePath)\n                ? resolve(optConfigFilePath, cfgFile)\n                : resolve(process.cwd(), optConfigFilePath, cfgFile)\n            : isAbsolute(cfgFile)\n                ? cfgFile\n                : resolve(process.cwd(), cfgFile);\n\n        const { basePathWithName, extension } = this.splitPath(cfgFileWithPath);\n        if (env) {\n            cfgFileWithPath = `${basePathWithName}.${env}.${extension || \"js\"}`;\n        } else {\n            cfgFileWithPath = `${basePathWithName}.${extension || \"js\"}`;\n        }\n        return cfgFileWithPath;\n    }\n\n    /**\n     * Split file path into base path and extension\n     */\n    splitPath(filePath) {\n        const basePathWithName = join(dirname(filePath), basename(filePath, extname(filePath)));\n        const extension = extname(filePath).slice(1);\n        return { basePathWithName, extension };\n    }\n\n    /**\n     * Require a configuration file (supports .js and .json)\n     */\n    requireConfigFile(filePath) {\n        if (!existsSync(filePath)) {\n            throw new Error(`Config file not found: ${filePath}`);\n        }\n\n        const ext = extname(filePath).toLowerCase();\n        if (ext === \".json\") {\n            const content = readFileSync(filePath, \"utf8\");\n            return JSON.parse(content);\n        } else if (ext === \".js\") {\n            // For .js files, use require() which is safer than eval\n            try {\n                // Clear require cache to ensure fresh load\n                delete require.cache[require.resolve(filePath)];\n                return require(filePath);\n            } catch (error) {\n                throw new Error(`Failed to load JS config file: ${error instanceof Error ? error.message : String(error)}`);\n            }\n        } else {\n            throw new Error(`Unsupported file extension: ${ext}`);\n        }\n    }\n\n    /**\n     * Get all parsed data\n     */\n    getParsed() {\n        return {\n            command: this.commands[0] || \"\",\n            flags: { ...this.flags },\n            options: { ...this.options },\n            usedKeys: Array.from(this.usedKeys)\n        };\n    }\n\n    /**\n     * Set prefixes dynamically and re-parse arguments (like legacy)\n     */\n    setPrefixes(prefixes) {\n        const arr = Array.isArray(prefixes) ? prefixes : prefixes.split(/,\\s*/);\n        const sortedArr = arr.sort((a, b) =>\n            a.length < b.length ? 1 : a.length > b.length ? -1 : 0\n        );\n        this.prefixes = sortedArr.map((el) => el.toLowerCase());\n        // Re-parse arguments with new prefixes\n        const args = process.argv.slice(2);\n        this.parseArgs(args);\n    }\n}\n\n// Singleton pattern (like legacy)\nlet instance = null;\n\n/**\n * Initialize Args instance (singleton pattern)\n */\nexport function init(args) {\n    instance = new Args({ args });\n    return instance;\n}\n\n/**\n * Get the current Args instance (singleton pattern)\n */\nexport function getArgsInstance() {\n    return instance;\n}\n\n\n","import Joi from \"joi\";\nimport { ParamError } from \"../errors.js\";\nimport { joiEdateType, joiStringArrayType } from \"./custom-types.js\";\n\n/**\n * Parameter definition types\n */\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Params class for parameter validation and type checking\n * Built on top of Args library with Joi validation\n */\nexport class Params {\n    context; // Partial context during initialization\n    params = {};\n    paramSources = {};\n    definitions = {};\n    args;\n    paramSetters = [];\n    paramGetters = [];\n    trackedParams = [];\n    _currentModule = \"script\";\n    /**\n     * Resolved early in constructor so cleanup does not read params lazily.\n     * One of: false (off) | \"end\" (print at exit) | \"top\" (print after init,\n     * via context.showUsedParamsIfNeeded()) | \"stop\" (print after init, then\n     * exit the process — also via context.showUsedParamsIfNeeded()).\n     */\n    _showUsedParamsMode = false;\n    /** Guard so the dump prints at most once (top OR end, never both). */\n    _usedParamsPrinted = false;\n\n    constructor(context, options = {}) {\n        // Context might be partial during initialization\n        this.context = context;\n        this.args = context.args;\n\n        // Apply initial configuration\n        if (Object.keys(options).length > 0) {\n            this.configure(options);\n        }\n\n        // Resolve showUsedParams early (fail fast, consistent with \"params figured in init\")\n        this._resolveShowUsedParams();\n\n        if (context && typeof context.registerCleanup === \"function\") {\n            context.registerCleanup((ctx) => {\n                // Print at exit unless it was already printed at the top\n                // (--showUsedParams=top via context.showUsedParamsIfNeeded()).\n                // printUsedParams is idempotent, so \"top\" runs here are no-ops;\n                // it also acts as a fallback if a \"top\" script never called\n                // showUsedParamsIfNeeded().\n                if (!ctx.params.getShowUsedParamsMode()) return;\n                ctx.params.printUsedParams(ctx.logger);\n            });\n        }\n    }\n\n    /**\n     * Resolve the --showUsedParams mode. The flag is intentionally dual-typed:\n     *   (absent) / --no-showUsedParams / =false   -> false  (off)\n     *   --showUsedParams / =true                   -> \"end\"  (print at exit)\n     *   --showUsedParams=top                       -> \"top\"  (print after init)\n     *   --showUsedParams=stop                      -> \"stop\" (print after init, then exit)\n     * Read raw (uncoerced) from args so the string \"top\"/\"stop\" isn't forced to\n     * a boolean, then track it under the \"script\" module for the dump itself.\n     */\n    _resolveShowUsedParams() {\n        const raw = this.args.get(\"showUsedParams\"); // also marks the key as used\n        const source = this.args.getSource?.(\"showUsedParams\") ?? \"default\";\n\n        let mode = false;\n        if (raw === undefined || raw === null) {\n            mode = false;\n        } else if (typeof raw === \"string\" && raw.trim().toLowerCase() === \"top\") {\n            mode = \"top\";\n        } else if (typeof raw === \"string\" && raw.trim().toLowerCase() === \"stop\") {\n            mode = \"stop\";\n        } else {\n            const s = typeof raw === \"string\" ? raw.trim().toLowerCase() : raw;\n            const falsey = s === false || s === \"false\" || s === \"0\" || s === \"no\" || s === \"off\";\n            mode = falsey ? false : \"end\";\n        }\n\n        this._showUsedParamsMode = mode;\n        this.trackParam(\"showUsedParams\", \"string\", mode, raw === undefined ? \"default\" : source, \"script\");\n        return mode;\n    }\n\n    /** Whether --showUsedParams was requested in any mode (truthy = on). */\n    getShowUsedParams() {\n        return this._showUsedParamsMode !== false;\n    }\n\n    /** Resolved mode: false | \"end\" | \"top\" | \"stop\". */\n    getShowUsedParamsMode() {\n        return this._showUsedParamsMode;\n    }\n\n    /**\n     * Print the module-grouped list of figured params (the --showUsedParams\n     * dump). Idempotent: only the first call prints, so callers can invoke it\n     * at the top (long-running services) without double-printing at exit.\n     */\n    printUsedParams(logger) {\n        if (this._usedParamsPrinted) return;\n        const byModule = this.getFiguredByModule();\n        const modules = Object.keys(byModule).sort();\n        if (modules.length === 0) return;\n        this._usedParamsPrinted = true;\n\n        logger = logger ?? this.context?.logger ?? console;\n        const hasHighlight = typeof logger.highlight === \"function\";\n        logger.debug(\"[Params]: list of used params:\");\n        for (const mod of modules) {\n            logger.debug(`  [${mod}]`);\n            for (const [key, entry] of Object.entries(byModule[mod])) {\n                const valueStr = JSON.stringify(entry.value);\n                const display = (hasHighlight && entry.source !== \"default\")\n                    ? logger.highlight(valueStr)\n                    : valueStr;\n                logger.debug(`    ${key}: ${display} (${entry.source})`);\n            }\n        }\n    }\n\n    /**\n     * Configure parameters\n     * Only parameters present in options are updated\n     */\n    configure(options) {\n        for (const [k, v] of Object.entries(options)) {\n            // TODO: opt values might be an object with definitions in it, so perhaps `this.set` should be used\n            this.params[k] = v;\n        }\n    }\n\n    /**\n     * Initialize Params from context and CLI parameters\n     * Note: Params is special - it's initialized early with partial context\n     */\n    static init(context, options) {\n        return new Params(context, options || {});\n    }\n\n    /**\n     * Track a parameter request for --stopAfter=init and --showUsedParams\n     */\n    trackParam(key, definition, value, source, moduleName) {\n        this.trackedParams.push({\n            key,\n            definition,\n            value,\n            source,\n            module: moduleName ?? this._currentModule,\n        });\n    }\n\n    /**\n     * Report a param value that a component RESOLVED ON ITS OWN — outside\n     * Params.get() — e.g. discovered by combining its config files (the way\n     * blueprints merge defaults/aggregator/feed data). Without this, every\n     * key such a component probed for an override shows up in the\n     * --showUsedParams dump as \"undefined (default)\"; reporting upgrades the\n     * entry to the value the component actually works with.\n     *\n     * Attribution rules:\n     *   - entries figured from an explicit input (cli/env/options/…) are left\n     *     untouched — the component merely confirmed them, the origin stands;\n     *   - \"default\" entries (Params had nothing) and earlier reports are\n     *     replaced by the report;\n     *   - keys never seen by Params are appended as new entries.\n     * The LATEST report wins — a component may resolve the same key several\n     * times with increasing specificity (e.g. a blueprint re-merged for a\n     * concrete resource) and the dump should show what it settled on.\n     * Later params.get() probes that find nothing (\"default\") never shadow a\n     * reported value — see {@link getFiguredByModule}.\n     *\n     * @param {string} key\n     * @param {*} value - the value the component actually uses\n     * @param {string} [source=\"discovered\"] - short origin label, e.g. \"blueprint\"\n     * @param {string} [moduleName] - dump section; defaults to the current module\n     */\n    reportResolved(key, value, source = \"discovered\", moduleName) {\n        const mod = moduleName ?? this._currentModule;\n        const mine = this.trackedParams.filter((e) => e.key === key && e.module === mod);\n        if (mine.some((e) => e.source !== \"default\" && !e.reported)) {\n            return; // explicitly figured (cli/env/options/…) — that origin stands\n        }\n        // Replace default probes and earlier reports with this report.\n        this.trackedParams = this.trackedParams.filter(\n            (e) => !(e.key === key && e.module === mod)\n        );\n        this.trackedParams.push({\n            key,\n            definition: \"reported\",\n            value,\n            source,\n            module: mod,\n            reported: true,\n        });\n    }\n\n    /**\n     * Get all tracked parameters (for --stopAfter=init)\n     */\n    getTrackedParams() {\n        return [...this.trackedParams];\n    }\n\n    /**\n     * Get all figured parameters as a record (flat, last occurrence per key)\n     * Returns all parameters that were collected during initialization,\n     * whether from CLI args, options, or defaults\n     */\n    getAllFigured() {\n        const result = {};\n        for (const param of this.trackedParams) {\n            result[param.key] = {\n                value: param.value,\n                source: param.source,\n            };\n        }\n        return result;\n    }\n\n    /**\n     * Get figured parameters grouped by module name.\n     * Same param can appear in multiple modules (e.g. source, resource).\n     * Last occurrence per key wins, EXCEPT that an empty probe — a\n     * params.get() that found nothing (\"default\", undefined) — never shadows\n     * a value reported via {@link reportResolved}: components probe for\n     * overrides on every resolution cycle, and those misses say nothing about\n     * the value the component actually uses.\n     */\n    getFiguredByModule() {\n        const reported = new Set();\n        for (const param of this.trackedParams) {\n            if (param.reported) reported.add(`${param.module}\\u0000${param.key}`);\n        }\n        const byModule = {};\n        for (const param of this.trackedParams) {\n            const mod = param.module;\n            if (!byModule[mod]) byModule[mod] = {};\n            if (\n                !param.reported &&\n                param.source === \"default\" &&\n                reported.has(`${mod}\\u0000${param.key}`)\n            ) {\n                continue;\n            }\n            byModule[mod][param.key] = { value: param.value, source: param.source };\n        }\n        return byModule;\n    }\n\n    /**\n     * Clear tracked parameters\n     */\n    clearTrackedParams() {\n        this.trackedParams = [];\n    }\n\n    /**\n     * Assign a parameter definition\n     */\n    assignDefinition(key, definition) {\n        if (this.definitions[key] && !definition) {\n            return this.definitions[key];\n        }\n\n        let type;\n        if (!definition) {\n            type = Joi.string();\n        } else if (Joi.isSchema(definition)) {\n            type = definition;\n        } else if (Joi.isSchema(definition.type)) {\n            type = definition.type;\n        } else if (typeof definition === \"string\") {\n            type = this.toJoi(definition);\n        } else if (typeof definition.type === \"string\") {\n            type = this.toJoi(definition.type);\n        } else if (!definition.type) {\n            type = Joi.string();\n        } else {\n            type = Joi.string();\n        }\n\n        if (!this.definitions[key]) {\n            this.definitions[key] = {};\n        }\n        this.definitions[key].type = type;\n\n        if (definition && definition.values) {\n            if (Array.isArray(definition.values)) {\n                this.definitions[key].values = definition.values;\n            }\n        }\n        return this.definitions[key];\n    }\n\n    /**\n     * Convert string definition to Joi schema\n     */\n    toJoi(str) {\n        let type;\n        \n        if (str.match(/^string|^text/i)) {\n            type = Joi.string();\n        } else if (str.match(/^number|^integer|^int/i)) {\n            type = Joi.number();\n        } else if (str.match(/^boolean|^bool/i)) {\n            type = Joi.boolean();\n        } else if (str.match(/^date/i)) {\n            type = Joi.custom(joiEdateType);\n        } else if (str.match(/^duration/i)) {\n            type = Joi.string().isoDuration();\n        } else if (str.match(/^array/i)) {\n            let elementTypes = \"string\";\n            const tmp = str.match(/\\((.*)\\)/);\n            if (tmp && tmp[1].match(/string/i)) {\n                elementTypes = \"string\";\n            } else if (tmp && tmp[1].match(/number|integer|int/i)) {\n                elementTypes = \"number\";\n            } else if (tmp && tmp[1].match(/boolean|bool/i)) {\n                elementTypes = \"boolean\";\n            }\n            type = Joi.custom(joiStringArrayType(elementTypes));\n        } else {\n            type = Joi.string();\n        }\n\n        // Handle default values\n        const regexForDefault = /\\bdefault\\s+([^\\s]+)/;\n        const matchForDefault = str.match(regexForDefault);\n        if (matchForDefault) {\n            const defValObj = type.validate(matchForDefault[1]);\n            if (defValObj.error) {\n                throw new ParamError(`default value \"${defValObj.value}\" type mismatch`);\n            }\n            // Joi's default() automatically allows undefined and applies the default\n            type = type.default(defValObj.value);\n        } else if (str.match(/\\s*required\\s*/)) {\n            type = type.required();\n        } else {\n            // If not required and no default, make it optional\n            type = type.optional();\n        }\n\n        return type;\n    }\n\n    /**\n     * Validate a value against a definition\n     */\n    validate(key, val, def) {\n        // Convert null to undefined so Joi defaults can be applied\n        // Joi's .default() only works with undefined, not null\n        const normalizedVal = val === null ? undefined : val;\n        \n        // Pass current params as context to support cross-parameter references (e.g., @startTime+2h)\n        // Use abortEarly: false to get all errors, and allowUnknown: false for strict validation\n        const { value, error } = def.type.validate(normalizedVal, { \n            context: { params: this.params },\n            abortEarly: false,\n            allowUnknown: false,\n        });\n        if (error) {\n            const errs = error.details.map((el) => el.message).join(\", \");\n            throw new ParamError(`\"${key}\" validation error: ${errs}`);\n        }\n        return value;\n    }\n\n    /**\n     * Get a parameter value with validation\n     */\n    get(key, definition) {\n        const def = this.assignDefinition(key, definition);\n        let valFromGetters = undefined;\n        \n        // eslint-disable-next-line no-constant-condition\n        if (def.volatile || true) {\n            valFromGetters = this.runAllRegisteredGetters(key);\n        }\n        \n        // Always call args.get() to mark the key as used, even if it doesn't exist\n        const valFromArgs = this.args.get(key);\n        const valFromParams = this.params[key];\n\n        let source = \"default\";\n        let value;\n\n        if (valFromGetters !== undefined && valFromGetters !== null) {\n            value = this.validate(key, valFromGetters, def);\n            source = \"options\";\n        } else if (valFromArgs !== undefined && valFromArgs !== null) {\n            value = this.validate(key, valFromArgs, def);\n            const argsSource = (this.args ).getSource?.(key);\n            if (argsSource === \"overrides\") source = \"options\";\n            else if (argsSource === \"cli\" || argsSource === \"env\" || argsSource === \"config\") source = argsSource;\n            else if (argsSource === \"default\") source = \"default\";\n            else source = \"cli\";\n        } else if (valFromParams !== undefined && valFromParams !== null) {\n            value = this.validate(key, valFromParams, def);\n            source = this.paramSources[key] ?? \"options\";\n        } else {\n            value = this.validate(key, undefined, def);\n            source = \"default\";\n        }\n\n        this.paramSources[key] = source;\n        // Track parameter for --stopAfter=init and --showUsedParams\n        this.trackParam(key, definition || \"string\", value, source);\n\n        if (value !== undefined && def.values && !def.values.includes(value)) {\n            throw new ParamError(`key ${key} should be one of ${def.values}`);\n        }\n        return value;\n    }\n\n    /**\n     * Set a parameter value with validation\n     */\n    set(key, val, definition) {\n        // TODO: check if there's a test for this:\n        if (val && val.type && val.value) {\n            definition = val;\n            val = val.value;\n        }\n        this.assignDefinition(key, definition);\n\n        if (!this.runAllRegisteredSetters(key, val)) {\n            this.params[key] = val;\n        }\n    }\n\n    /**\n     * Get all parameters from definitions (main script).\n     * Same as getAllForModule(\"script\", defs). Processes left-to-right for cross-parameter references.\n     * Libraries should use {@link getAllForModule} with an explicit module name (or {@link runWithModule}\n     * around {@link get}) so --showUsedParams groups usage correctly.\n     */\n    getAll(defs) {\n        return this.getAllForModule(\"script\", defs);\n    }\n\n    /**\n     * Get all parameters from definitions for a given module name.\n     * Figured params are grouped by module when using --showUsedParams.\n     * Processes parameters left-to-right to support cross-parameter references.\n     * If moduleName is omitted, it is inferred from the caller's file path (directory name under src/).\n     */\n    getAllForModule(moduleNameOrDefs, defs) {\n        let moduleName;\n        let definitions;\n        if (defs !== undefined) {\n            moduleName = moduleNameOrDefs ;\n            definitions = defs;\n        } else {\n            definitions = moduleNameOrDefs ;\n            moduleName = this._inferModuleNameFromStack();\n        }\n        const prev = this._currentModule;\n        this._currentModule = moduleName;\n        try {\n            const res = {};\n            for (const [k, def] of Object.entries(definitions)) {\n                const value = this.get(k, def);\n                res[k] = value;\n                if (value !== undefined) {\n                    this.params[k] = value;\n                }\n            }\n            return res;\n        } finally {\n            this._currentModule = prev;\n        }\n    }\n\n    /**\n     * Run a callback with {@link _currentModule} set so single {@link get} calls are tracked\n     * under the same module (for --showUsedParams / getFiguredByModule).\n     */\n    runWithModule(moduleName, fn) {\n        const prev = this._currentModule;\n        this._currentModule = moduleName;\n        try {\n            return fn();\n        } finally {\n            this._currentModule = prev;\n        }\n    }\n\n    /**\n     * Async variant of {@link runWithModule} for modules that await params.get().\n     */\n    async runWithModuleAsync(moduleName, fn) {\n        const prev = this._currentModule;\n        this._currentModule = moduleName;\n        try {\n            return await fn();\n        } finally {\n            this._currentModule = prev;\n        }\n    }\n\n    /**\n     * Infer module name from call stack: first caller outside params/index gives path like .../src/<moduleName>/...\n     */\n    _inferModuleNameFromStack() {\n        const stack = new Error().stack;\n        if (!stack) return \"script\";\n        const lines = stack.split(\"\\n\");\n        const paramsIndexPath = \"params\" + (typeof process !== \"undefined\" && process.platform === \"win32\" ? \"\\\\\" : \"/\") + \"index.\";\n        for (const line of lines) {\n            const parenMatch = line.match(/\\(([^)]+)\\)/);\n            if (!parenMatch) continue;\n            const parts = parenMatch[1].split(\":\");\n            if (parts.length < 3) continue;\n            const path = parts.slice(0, -2).join(\":\").replace(/^file:\\/\\//, \"\");\n            if (!path || path.includes(paramsIndexPath)) continue;\n            const srcMatch = path.match(/[/\\\\]src[/\\\\]([^/\\\\]+)(?:[/\\\\]|$)/);\n            if (srcMatch) return srcMatch[1];\n        }\n        return \"script\";\n    }\n\n    /**\n     * Run all registered getters for a key\n     */\n    runAllRegisteredGetters(key) {\n        let val = undefined;\n        for (const getter of this.paramGetters) {\n            val = getter(key, this.definitions[key]);\n            if (val !== undefined && val !== null) {\n                break;\n            }\n        }\n        return val;\n    }\n\n    /**\n     * Run all registered setters for a key\n     */\n    runAllRegisteredSetters(key, value) {\n        let setterUsed = false;\n        for (const setter of this.paramSetters) {\n            setterUsed = setter(key, value);\n            if (setterUsed) {\n                break;\n            }\n        }\n        return setterUsed;\n    }\n\n    /**\n     * Register a parameter getter\n     */\n    registerParamGetter(fn) {\n        this.paramGetters.push(fn);\n    }\n\n    /**\n     * Register a parameter setter\n     */\n    registerParamSetter(fn) {\n        this.paramSetters.push(fn);\n    }\n}\n\n// Export custom types for external use\nexport { joiEdateType, joiStringArrayType };\n\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n    constructor(message) {\n        super(message);\n        this.name = \"FrameworkError\";\n    }\n}\n\nexport class ParamError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"ParamError\";\n    }\n}\n\nexport class InitError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"InitError\";\n    }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"CriticalRequestError\";\n    }\n}\n\nexport class ControlFlowError extends Error {\n    constructor(message) {\n        super(message);\n        this.name = \"ControlFlowError\";\n    }\n}\n\nexport class HttpClientError extends FrameworkError {\n    constructor(message,   cause) {\n        super(message);this.cause = cause;;\n        this.name = \"HttpClientError\";\n    }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"FileDatabaseError\";\n    }\n}\n\n","\nimport { ParamError } from \"../errors.js\";\n\n/**\n * Custom Joi type for enhanced date parsing with relative time support\n * Supports:\n * - ISO8601 strings: \"2025-01-01T01:01:01Z\"\n * - Relative time: \"-2h\", \"+1d\", \"now\"\n * - Cross-parameter references: \"@startTime+2h\", \"@endDate-30m\"\n * \n * Internal representation: UTC ISO8601 string (YYYY-MM-DDTHH:mm:ssZ)\n * \n * @param value - Date value to parse\n * @param helpers - Joi helpers (includes context with other params)\n * @returns ISO8601 string in UTC timezone\n */\nexport const joiEdateType = (value, helpers) => {\n    // If value is already a string in ISO format, validate and return\n    if (typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/.test(value)) {\n        const testDate = new Date(value);\n        if (!isNaN(testDate.getTime())) {\n            return value;\n        }\n    }\n\n    // If value is a Date object, convert to ISO string\n    if (value instanceof Date) {\n        return value.toISOString();\n    }\n\n    // If value is not a string, try to convert it\n    if (typeof value !== \"string\") {\n        value = String(value);\n    }\n\n    // Handle special keyword \"now\"\n    if (value.toLowerCase() === \"now\") {\n        return new Date().toISOString();\n    }\n\n    // Check for cross-parameter reference with relative time: @paramName+2h, @paramName-30m\n    const referenceRegex = /^@(\\w+)([+-]\\d+[smhdwy])$/i;\n    const referenceMatch = value.match(referenceRegex);\n    \n    if (referenceMatch) {\n        const [, paramName, relativeExpr] = referenceMatch;\n        \n        // Get the referenced parameter from context (if available via helpers.state.ancestors)\n        // For now, we'll use helpers.prefs.context which Joi provides\n        const context = (helpers ).prefs?.context;\n        \n        if (!context || !context.params) {\n            throw new ParamError(`Cannot resolve cross-parameter reference @${paramName}: context not available. Ensure parameters are processed with proper context.`);\n        }\n\n        const referencedValue = context.params[paramName];\n        \n        if (referencedValue === undefined || referencedValue === null) {\n            throw new ParamError(`Cannot resolve @${paramName}: parameter \"${paramName}\" is not defined or has no value. Parameters are evaluated left-to-right.`);\n        }\n\n        // Referenced value should be an ISO string or Date\n        let referenceDate;\n        if (referencedValue instanceof Date) {\n            referenceDate = referencedValue;\n        } else if (typeof referencedValue === \"string\") {\n            referenceDate = new Date(referencedValue);\n            if (isNaN(referenceDate.getTime())) {\n                throw new ParamError(`Referenced parameter @${paramName} has invalid date value: ${referencedValue}`);\n            }\n        } else {\n            throw new ParamError(`Referenced parameter @${paramName} is not a valid date type (found: ${typeof referencedValue})`);\n        }\n\n        // Parse the relative expression and apply to reference date\n        const relativeMatch = relativeExpr.match(/^([+-])(\\d+)([smhdwy])$/i);\n        if (!relativeMatch) {\n            throw new ParamError(`Invalid relative time expression in @${paramName}${relativeExpr}`);\n        }\n\n        const [, sign, amount, unit] = relativeMatch;\n        const offset = calculateTimeOffset(parseInt(amount, 10), unit, sign);\n        const resultDate = new Date(referenceDate.getTime() + offset);\n        \n        return resultDate.toISOString();\n    }\n\n    // Check for relative time expressions like \"-2h\", \"+1d\", \"-30m\", etc.\n    const relativeTimeRegex = /^([+-])(\\d+)([smhdwy])$/i;\n    const relativeMatch = value.match(relativeTimeRegex);\n    \n    if (relativeMatch) {\n        const [, sign, amount, unit] = relativeMatch;\n        const numAmount = parseInt(amount, 10);\n        \n        if (isNaN(numAmount)) {\n            throw new ParamError(`Invalid relative time amount: ${amount}`);\n        }\n\n        const offset = calculateTimeOffset(numAmount, unit, sign);\n        const resultDate = new Date(Date.now() + offset);\n        \n        return resultDate.toISOString();\n    }\n\n    // Try to parse as a regular date string\n    const parsedDate = new Date(value);\n    \n    // Check if the parsed date is valid\n    if (isNaN(parsedDate.getTime())) {\n        throw new ParamError(`Invalid date format: ${value}. Expected a valid date string, \"now\", relative time expression (e.g., \"-2h\", \"+1d\"), or cross-parameter reference (e.g., \"@startTime+2h\")`);\n    }\n\n    return parsedDate.toISOString();\n};\n\n/**\n * Calculate time offset in milliseconds\n */\nfunction calculateTimeOffset(amount, unit, sign) {\n    let multiplier = 1;\n    \n    // Convert to milliseconds based on unit\n    switch (unit.toLowerCase()) {\n        case \"s\": // seconds\n            multiplier = 1000;\n            break;\n        case \"m\": // minutes\n            multiplier = 60 * 1000;\n            break;\n        case \"h\": // hours\n            multiplier = 60 * 60 * 1000;\n            break;\n        case \"d\": // days\n            multiplier = 24 * 60 * 60 * 1000;\n            break;\n        case \"w\": // weeks\n            multiplier = 7 * 24 * 60 * 60 * 1000;\n            break;\n        case \"y\": // years (approximate)\n            multiplier = 365 * 24 * 60 * 60 * 1000;\n            break;\n        default:\n            throw new ParamError(`Invalid time unit: ${unit}. Supported units: s, m, h, d, w, y`);\n    }\n\n    return sign === \"+\" ? amount * multiplier : -amount * multiplier;\n}\n\n/**\n * Custom Joi type for string array parsing\n * Converts comma-separated strings to typed arrays\n */\nexport const joiStringArrayType = (type) => (value, _helpers) => {\n    if (value === undefined || typeof value === \"function\") {\n        return [];\n    }\n    \n    const arr = value.split(/,\\s*/).map((el) => {\n        if (type === \"number\") {\n            const v = parseInt(el, 10);\n            if (isNaN(v)) {\n                throw new ParamError(`array element \"${el}\" should be numeric`);\n            }\n            return v;\n        } else if (type === \"boolean\") {\n            const v = el.match(/true|t|yes|1/i) ? true :\n                el.match(/false|f|no|0/i) ? false : null;\n            if (v === null) {\n                throw new ParamError(`array element \"${el}\" should be boolean`);\n            }\n            return v;\n        } else if (type === \"string\") {\n            return el;\n        } else {\n            throw new ParamError(`unknown type \"${type}\" for array elements`);\n        }\n    });\n    \n    return arr;\n};\n\n","/**\n * FileDatabase - Versioned, file-based data storage system\n * \n * Provides organized file storage with:\n * - Timestamp-based versioning\n * - Chunked/paginated file writes for large datasets\n * - Metadata tracking\n * - Backward compatibility with legacy structures\n * - Multiple storage modes (versioned, catalog, logs)\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { ensurePath, getFileExtension, getFreeDiskSpace, bytesToHumanReadable, isTimestampFolder } from \"./utils.js\";\nimport { detectDataType, serializeData, deserializeData } from \"./serializers.js\";\nimport { ParamError, FileDatabaseError } from \"../errors.js\";\n\nexport { FileDatabaseError };\n\nexport class FileDatabase {\n    basePath;\n    namespace;\n    tableName = null;\n    versioned;\n    maxVersions;\n    pageSize;\n    useMetadata;\n    freeSpaceThreshold;\n    logger;\n\n    // Current operation state\n    currentVersion = null;\n    currentVersionFolder = null;\n    currentFileNumber = 0;\n    currentRecord = 0;\n    hasReadFirstPage = false;\n    lastFileData = null;\n    /** Cache of the last JSON file parsed during paginated reads (avoid re-parse per page). */\n    readFileCache = null; // { filePath: string, data: any[] } | null\n    metadata;\n\n    // Synopsis calculation functions\n    fileSynopsisFunction = null;\n    versionSynopsisFunction = null;\n\n    /**\n     * Constructor - accepts context as first parameter (new pattern)\n     * or config object (legacy pattern for backward compatibility)\n     */\n    constructor(contextOrConfig, options) {\n        let config;\n        \n        // Check if first parameter is Context (has params property)\n        if (contextOrConfig && typeof contextOrConfig === \"object\" && \"params\" in contextOrConfig) {\n            // New pattern: context is first parameter\n            const context = contextOrConfig ;\n            const opts = options || {};\n            \n            // Get configuration from context.params (module \"filedatabase\" for --showUsedParams grouping)\n            const defs = {\n                basePath: \"string default ./data\",\n                namespace: \"string default default\",\n                tableName: \"string\",\n                maxVersions: \"number default 5\",\n                pageSize: \"number default 5000\",\n            };\n            const discovered = context.params.getAllForModule(defs);\n            config = { ...discovered, ...opts, logger: context.logger } ;\n        } else {\n            // Legacy pattern: config object\n            config = contextOrConfig ;\n        }\n        \n        // Validate required configuration\n        if (!config.basePath) {\n            throw new ParamError(\"[FileDatabase] basePath is required\");\n        }\n\n        this.basePath = config.basePath;\n        this.namespace = config.namespace || \"default\";\n        this.tableName = config.tableName || null;\n        this.versioned = config.versioned ?? true; // Default true for backward compatibility\n        this.maxVersions = config.maxVersions || 5;\n        this.pageSize = config.pageSize || 5000;\n        this.useMetadata = config.useMetadata !== false; // Default true\n        this.freeSpaceThreshold = config.freeSpaceThreshold || 100 * 1024 * 1024; // 100MB\n        this.logger = config.logger || console;\n        this.lastReadMissingFiles = [];\n\n        // Initialize metadata\n        this.metadata = this.getDefaultMetadata();\n    }\n\n    /**\n     * Initialize FileDatabase from context and options.\n     * Params are read via getAllForModule(\"filedatabase\", defs) for --showUsedParams grouping.\n     */\n    static init(context, options) {\n        return new FileDatabase(context, options ?? {});\n    }\n\n    /**\n     * Get default metadata structure\n     */\n    getDefaultMetadata() {\n        return {\n            version: this.currentVersion || null,\n            files: [],\n            createdAt: new Date().toISOString(),\n            modifiedAt: new Date().toISOString(),\n            totalRecords: 0,\n            synopsis: null,\n            dataType: null,\n        };\n    }\n\n    /**\n     * Get the destination path (basePath/namespace/tableName[/version])\n     */\n    getDestinationPath(version) {\n        const errors = [\"basePath\", \"namespace\", \"tableName\"]\n            .filter(prop => !this[prop ])\n            .map(prop => `${prop} is not set`);\n        if (errors.length) {\n            throw new FileDatabaseError(`[FileDatabase] ${errors.join(\"; \")}`);\n        }\n\n        const parts = [this.basePath, this.namespace];\n        if (this.tableName) {\n            parts.push(...this.tableName.split(\"/\"));\n        }\n\n        // Only add version folder if in versioned mode and version is specified\n        if (this.versioned && version) {\n            parts.push(version);\n        }\n\n        return path.resolve(...parts);\n    }\n\n    /**\n     * Set current version and version folder\n     */\n    async setCurrentVersion(version) {\n        this.currentVersion = version;\n        this.currentVersionFolder = await ensurePath(this.getDestinationPath(), version);\n    }\n\n    /**\n     * Create a new version folder named with the current UTC second.\n     * Only works in versioned mode.\n     *\n     * Clash protection: if that name already exists (two writers in the same\n     * second, or wall clock behind the latest version), advance +1s until free.\n     * Do NOT always derive from max(existing)+1s — that made successive harvests\n     * hours apart still land one second apart on disk.\n     */\n    async makeNewVersion() {\n        if (!this.versioned) {\n            throw new FileDatabaseError(\"makeNewVersion() only works in versioned mode\");\n        }\n\n        // Reset in-memory metadata when creating a new version\n        this.metadata = this.getDefaultMetadata();\n\n        const existingVersions = await this.getVersions();\n        const existingSet = new Set(existingVersions);\n\n        let candidateMs = Date.now();\n        if (existingVersions.length > 0) {\n            let maxMs = 0;\n            for (const version of existingVersions) {\n                const ms = new Date(version).getTime();\n                if (Number.isFinite(ms) && ms > maxMs) maxMs = ms;\n            }\n            // Same-second clash or clock behind latest folder — start just after it.\n            if (candidateMs <= maxMs) {\n                candidateMs = maxMs + 1000;\n            }\n        }\n\n        let versionName = new Date(candidateMs).toISOString().split(\".\")[0] + \"Z\";\n        while (existingSet.has(versionName)) {\n            candidateMs += 1000;\n            versionName = new Date(candidateMs).toISOString().split(\".\")[0] + \"Z\";\n        }\n\n        await this.setCurrentVersion(versionName);\n\n        // Reset file numbering for new version\n        this.currentFileNumber = 0;\n\n        // Delete old versions if we exceed maxVersions\n        const versions = await this.getVersions();\n        while (versions.length > this.maxVersions) {\n            const versionToDelete = path.resolve(this.getDestinationPath(), versions.shift());\n            this.logger.silly?.(`[FileDatabase] Deleting old version: ${versionToDelete}`);\n            await fs.promises.rm(versionToDelete, { recursive: true, force: true });\n        }\n\n        return versionName;\n    }\n\n    /**\n     * Get list of all versions (sorted chronologically)\n     * Only works in versioned mode\n     */\n    async getVersions() {\n        if (!this.versioned) {\n            return []; // No versions in non-versioned mode\n        }\n\n        const destPath = this.getDestinationPath();\n\n        try {\n            await ensurePath(destPath);\n            const items = await fs.promises.readdir(destPath);\n            const versions = items.filter(item => {\n                const itemPath = path.join(destPath, item);\n                const stat = fs.statSync(itemPath);\n                return stat.isDirectory() && isTimestampFolder(item);\n            });\n\n            return versions.sort();\n        } catch (error) {\n            return [];\n        }\n    }\n\n    /**\n     * Get the latest version (most recent timestamp)\n     * Only works in versioned mode\n     * @returns Latest version string or null if no versions\n     */\n    async getLatestVersion() {\n        if (!this.versioned) {\n            throw new FileDatabaseError(\"getLatestVersion() only works in versioned mode\");\n        }\n\n        const versions = await this.getVersions();\n        if (versions.length === 0) {\n            return null;\n        }\n\n        return versions[versions.length - 1];\n    }\n\n    /**\n     * Check if any data exists in this table\n     * Works for both versioned and non-versioned modes\n     * @returns true if data exists\n     */\n    async hasData() {\n        const tablePath = this.getDestinationPath();\n\n        if (!fs.existsSync(tablePath)) {\n            return false;\n        }\n\n        if (this.versioned) {\n            // Check for version folders\n            const versions = await this.getVersions();\n            return versions.length > 0;\n        } else {\n            // Check for any data files or metadata\n            const items = await fs.promises.readdir(tablePath);\n            return items.some(item =>\n                item === \"metadata.json\" ||\n                item.match(/^\\d{6}\\.(json|txt|xml)$/) ||\n                item.endsWith(\".json\")\n            );\n        }\n    }\n\n    /**\n     * Auto-detect the data format in this table\n     * Used when reading existing data\n     * @returns Format detection result\n     */\n    async detectDataFormat()\n\n\n\n    {\n        const tablePath = this.getDestinationPath();\n\n        if (!fs.existsSync(tablePath)) {\n            return { versioned: false, hasMetadata: false, dataType: null };\n        }\n\n        const items = await fs.promises.readdir(tablePath);\n\n        // Check for metadata.json in root (non-versioned with metadata)\n        if (items.includes(\"metadata.json\")) {\n            const metadata = JSON.parse(\n                await fs.promises.readFile(path.join(tablePath, \"metadata.json\"), \"utf8\")\n            );\n            return {\n                versioned: false,\n                hasMetadata: true,\n                dataType: metadata.dataType || null\n            };\n        }\n\n        // Check for version folders\n        const versionFolders = items.filter(item => {\n            const itemPath = path.join(tablePath, item);\n            const stat = fs.statSync(itemPath);\n            return stat.isDirectory() && isTimestampFolder(item);\n        });\n\n        if (versionFolders.length > 0) {\n            // Check if latest version has metadata\n            const latestVersion = versionFolders.sort().pop();\n            const versionMetadataPath = path.join(tablePath, latestVersion, \"metadata.json\");\n\n            return {\n                versioned: true,\n                hasMetadata: fs.existsSync(versionMetadataPath),\n                dataType: null\n            };\n        }\n\n        // Check for sequential files (legacy non-versioned)\n        const dataFiles = items.filter(f => f.match(/^\\d{6}\\.(json|txt|xml)$/));\n        if (dataFiles.length > 0) {\n            return {\n                versioned: false,\n                hasMetadata: false,\n                dataType: null\n            };\n        }\n\n        return { versioned: false, hasMetadata: false, dataType: null };\n    }\n\n    /**\n     * Load metadata from JSON file. Distinguishes missing vs unreadable so\n     * callers can rewrite a truncated file once instead of warning on every read.\n     */\n    async loadMetadataJson(version) {\n        const loaded = await this.readMetadataJsonFile(version);\n        return loaded.metadata;\n    }\n\n    async readMetadataJsonFile(version) {\n        const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n        if (!fs.existsSync(metadataFile)) {\n            return { metadata: null, unreadable: false };\n        }\n        try {\n            const rawData = await fs.promises.readFile(metadataFile, \"utf8\");\n            return { metadata: JSON.parse(rawData), unreadable: false };\n        } catch {\n            return { metadata: null, unreadable: true };\n        }\n    }\n\n    async persistMetadataJson(version, metadata) {\n        if (!this.useMetadata || !metadata) {\n            return;\n        }\n        const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n        try {\n            await fs.promises.writeFile(metadataFile, JSON.stringify(metadata, null, 4), \"utf8\");\n        } catch (e) {\n            this.logger.silly?.(`[FileDatabase] Could not rewrite metadata for \"${version}\": ${e.message}`);\n        }\n    }\n\n    /**\n     * Build metadata by scanning files in a version folder (backward compatibility)\n     * Reads all files to get accurate counts - used when synopsis calculation is needed\n     */\n    async figureMetadataFromVersionFiles(version) {\n        const versionPath = path.join(this.getDestinationPath(), version);\n\n        if (!fs.existsSync(versionPath)) {\n            return this.getDefaultMetadata();\n        }\n\n        const files = (await fs.promises.readdir(versionPath))\n            .filter(file => file !== \"metadata.json\" && !file.startsWith(\".\"))\n            .sort();\n\n        const metadata = this.getDefaultMetadata();\n        metadata.version = version;\n        metadata.files = [];\n\n        let totalRecords = 0;\n        let detectedDataType = null;\n\n        for (let i = 0; i < files.length; i++) {\n            const fileName = files[i];\n            const filePath = path.join(versionPath, fileName);\n\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                const extension = path.extname(fileName).toLowerCase();\n                let dataType = \"text\";\n\n                if (extension === \".json\") {\n                    dataType = \"json-array\";\n                } else if (extension === \".xml\") {\n                    dataType = \"xml\";\n                }\n\n                const fileData = deserializeData(rawData, dataType);\n                const recordsCount = Array.isArray(fileData) ? fileData.length : 1;\n\n                if (detectedDataType === null) {\n                    detectedDataType = detectDataType(fileData);\n                }\n\n                const fileInfo = {\n                    number: i + 1,\n                    recordsCount,\n                    fileName,\n                };\n\n                metadata.files.push(fileInfo);\n                totalRecords += recordsCount;\n            } catch (error) {\n                this.logger.error?.(`[FileDatabase] Failed to read file ${fileName}: ${(error ).message}`);\n            }\n        }\n\n        metadata.totalRecords = totalRecords;\n        metadata.dataType = detectedDataType;\n\n        return metadata;\n    }\n\n    /**\n     * Build metadata optimized - only reads first and last files\n     * Assumes all middle files have the same record count as the first file\n     * Much faster for large datasets with many files\n     */\n    async buildMetadataOptimized(version) {\n        const versionPath = path.join(this.getDestinationPath(), version);\n\n        if (!fs.existsSync(versionPath)) {\n            return this.getDefaultMetadata();\n        }\n\n        const files = (await fs.promises.readdir(versionPath))\n            .filter(file => file !== \"metadata.json\" && !file.startsWith(\".\"))\n            .sort();\n\n        if (files.length === 0) {\n            return this.getDefaultMetadata();\n        }\n\n        const metadata = this.getDefaultMetadata();\n        metadata.version = version;\n        metadata.files = files.map((fileName, index) => ({\n            number: index + 1,\n            recordsCount: 0,\n            fileName,\n        }));\n\n        // Read first file to determine data type and standard record count\n        const firstFile = metadata.files[0];\n        const firstFilePath = path.join(versionPath, firstFile.fileName);\n        const firstFileRaw = await fs.promises.readFile(firstFilePath, \"utf8\");\n\n        let firstFileData;\n        try {\n            firstFileData = JSON.parse(firstFileRaw);\n        } catch (e) {\n            firstFileData = firstFileRaw;\n        }\n\n        metadata.dataType = detectDataType(firstFileData);\n\n        // Only proceed with optimization for json-array data\n        if (metadata.dataType === \"json-array\") {\n            const firstFileCount = Array.isArray(firstFileData) ? firstFileData.length : 1;\n            firstFile.recordsCount = firstFileCount;\n\n            // Assume all middle files have the same count as the first\n            for (let i = 1; i < metadata.files.length - 1; i++) {\n                metadata.files[i].recordsCount = firstFileCount;\n            }\n\n            // Read last file to get its actual count (might be partial)\n            if (files.length > 1) {\n                const lastFile = metadata.files[metadata.files.length - 1];\n                const lastFilePath = path.join(versionPath, lastFile.fileName);\n                const lastFileRaw = await fs.promises.readFile(lastFilePath, \"utf8\");\n                const lastFileData = deserializeData(lastFileRaw, metadata.dataType);\n                lastFile.recordsCount = Array.isArray(lastFileData) ? lastFileData.length : 1;\n            }\n\n            // Calculate total records\n            metadata.totalRecords = metadata.files.reduce((sum, file) => sum + file.recordsCount, 0);\n        } else {\n            // For non-array data, count each file as 1 record\n            metadata.files.forEach(file => {\n                file.recordsCount = 1;\n            });\n            metadata.totalRecords = files.length;\n        }\n\n        return metadata;\n    }\n\n    /**\n     * Figure out metadata - tries JSON first, then builds from files\n     * Uses optimized building when no synopsis calculation is needed\n     */\n    async figureMetadata(version, useOptimized = true) {\n        let unreadable = false;\n        if (this.useMetadata) {\n            const loaded = await this.readMetadataJsonFile(version);\n            if (loaded.metadata) {\n                return loaded.metadata;\n            }\n            unreadable = loaded.unreadable;\n        }\n\n        // Fallback: build from files\n        // Use optimized version (only reads first+last) when no synopsis needed\n        const rebuilt = (useOptimized && !this.fileSynopsisFunction && !this.versionSynopsisFunction)\n            ? await this.buildMetadataOptimized(version)\n            : await this.figureMetadataFromVersionFiles(version);\n\n        if (unreadable) {\n            await this.persistMetadataJson(version, rebuilt);\n        }\n        return rebuilt;\n    }\n\n    /**\n     * Load version metadata (main entry point for loading)\n     */\n    async loadVersionMetadata(version) {\n        const metadata = await this.figureMetadata(version);\n        this.metadata = metadata;\n        return metadata;\n    }\n\n    /**\n     * Save version metadata to file\n     */\n    async saveVersionMetadata(metadata) {\n        if (!this.useMetadata) {\n            return;\n        }\n\n        const metadataToSave = metadata || this.metadata;\n        let metadataFile;\n\n        if (this.versioned) {\n            // Versioned mode: metadata in version folder\n            if (!this.currentVersion) {\n                return;\n            }\n            metadataFile = path.join(this.getDestinationPath(), this.currentVersion, \"metadata.json\");\n        } else {\n            // Non-versioned mode: metadata in root table folder\n            metadataFile = path.join(this.getDestinationPath(), \"metadata.json\");\n        }\n\n        await fs.promises.writeFile(metadataFile, JSON.stringify(metadataToSave, null, 4), \"utf8\");\n    }\n\n    /**\n     * Create a new file entry in metadata\n     */\n    makeNewFile() {\n        this.currentFileNumber = (this.currentFileNumber || 0) + 1;\n\n        const dataType = this.metadata.dataType || \"json-array\";\n        const fileEntry = {\n            number: this.currentFileNumber,\n            recordsCount: 0,\n            fileName: `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(dataType)}`,\n        };\n\n        this.metadata.files.push(fileEntry);\n        this.lastFileData = null;\n\n        this.logger.silly?.(`[FileDatabase] Created new file: ${fileEntry.fileName}, fileNumber: ${this.currentFileNumber}`);\n    }\n\n    /**\n     * Figure out what data to write and which file to use (for pagination)\n     * @param data - Data to write\n     * @param targetFileIndex - Optional index of existing file to overwrite (when customMetadata matches)\n     * @param forceNewFile - If true, always create a new file (when customMetadata provided but no match)\n     */\n    figureOutDataAndFileToWrite(data, targetFileIndex = null, forceNewFile = false) {\n        let dataToWrite;\n        let dataLeftOver;\n\n        // Detect data type from incoming data\n        // Always use the incoming data's type to ensure correct file extension\n        const incomingDataType = detectDataType(data);\n        if (this.metadata.dataType !== incomingDataType) {\n            this.metadata.dataType = incomingDataType;\n        }\n\n        // If targetFileIndex is provided, use that file (overwrite existing file with matching customMetadata)\n        if (targetFileIndex !== null && targetFileIndex < this.metadata.files.length) {\n            const targetFile = this.metadata.files[targetFileIndex];\n            // For non-array data, overwrite the file\n            if (!Array.isArray(data)) {\n                dataToWrite = data;\n                dataLeftOver = null;\n                return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };\n            } else {\n                // For arrays, start fresh in the target file (don't append)\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n                return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };\n            }\n        }\n\n        // If forceNewFile is true (customMetadata provided but no match), create a new file\n        // Skip the initial file creation if forceNewFile is true to avoid creating an extra empty file\n        let newlyCreatedFileIndex = null;\n        if (forceNewFile) {\n            const filesBeforeCreate = this.metadata.files.length;\n            this.makeNewFile();\n            newlyCreatedFileIndex = filesBeforeCreate; // Index of the newly created file\n            this.logger.silly?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);\n        } else if (this.metadata.files.length === 0) {\n            // If no files exist yet and we're not forcing a new file, create the first file\n            this.makeNewFile();\n        }\n\n        // Get the last file (which might be the one we just created)\n        const lastFile = this.metadata.files[this.metadata.files.length - 1];\n        const lastFileRecordsCount = lastFile.recordsCount;\n        \n        // Verify that if we created a new file, we're using it\n        if (forceNewFile && newlyCreatedFileIndex !== null) {\n            const newlyCreatedFile = this.metadata.files[newlyCreatedFileIndex];\n            if (newlyCreatedFile && newlyCreatedFile.fileName !== lastFile.fileName) {\n                this.logger.warn?.(`[FileDatabase] Warning: Newly created file ${newlyCreatedFile.fileName} doesn't match last file ${lastFile.fileName}`);\n            }\n        }\n        \n        // For non-array data (text/xml/object), check if we need a new file with correct extension\n        // But skip this check if forceNewFile is true - we already created the file we need\n        if (!Array.isArray(data) && !forceNewFile) {\n            const lastFileExtension = path.extname(lastFile.fileName);\n            const expectedExtension = `.${getFileExtension(incomingDataType)}`;\n            // If the last file has wrong extension, create a new file with correct extension\n            // Check even if recordsCount is 0 (empty file) - we want correct extension for new writes\n            if (lastFileExtension !== expectedExtension) {\n                // Only create new file if the existing one has content, otherwise we'll use it\n                if (lastFileRecordsCount > 0) {\n                    this.makeNewFile();\n                } else {\n                    // File is empty, update its name to have correct extension\n                    lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(incomingDataType)}`;\n                }\n            }\n        } else if (!Array.isArray(data) && forceNewFile) {\n            // If forceNewFile is true, ensure the newly created file has the correct extension\n            const lastFileExtension = path.extname(lastFile.fileName);\n            const expectedExtension = `.${getFileExtension(incomingDataType)}`;\n            if (lastFileExtension !== expectedExtension) {\n                lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(incomingDataType)}`;\n            }\n        }\n\n        if (Array.isArray(data)) {\n            // For arrays, handle pagination\n            // If forceNewFile is true, write fresh data to the new file (don't append)\n            if (forceNewFile) {\n                // Write fresh data to the newly created file\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n            } else if (lastFileRecordsCount < this.pageSize) {\n                // Try to append to existing file if there's space\n                dataToWrite = [...(this.lastFileData || []), ...data.slice(0, this.pageSize - lastFileRecordsCount)];\n                dataLeftOver = data.slice(this.pageSize - lastFileRecordsCount);\n                this.lastFileData = dataToWrite;\n            } else {\n                // Last file is full, create a new file\n                this.makeNewFile();\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n            }\n        } else {\n            // For non-arrays, write as-is\n            dataToWrite = data;\n            dataLeftOver = null;\n        }\n\n        // Get the file name - if forceNewFile is true, we just created a new file, so use that one\n        // Otherwise, use the last file (which might have been created earlier or is being reused)\n        const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;\n\n        this.logger.silly?.(\n            `[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, forceNewFile=${forceNewFile}, targetFileIndex=${targetFileIndex}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : \"N/A\"}, lastFileRecordsCount=${lastFileRecordsCount}`\n        );\n\n        return { dataToWrite, dataLeftOver, fileName };\n    }\n\n    /**\n     * Calculate file-level synopsis if function is set\n     */\n    calculateFileSynopsis(data, fileIndex = this.metadata.files.length - 1) {\n        if (!this.fileSynopsisFunction) {\n            return;\n        }\n        const fileInfo = this.metadata.files[fileIndex];\n        const enhancedFileInfo = this.fileSynopsisFunction(fileInfo, data);\n        this.metadata.files[fileIndex] = enhancedFileInfo;\n    }\n\n    /**\n     * Calculate version-level synopsis if function is set\n     */\n    calculateVersionSynopsis() {\n        if (!this.versionSynopsisFunction) {\n            return;\n        }\n        const enhancedMetadata = this.versionSynopsisFunction(this.metadata);\n        this.metadata = enhancedMetadata;\n    }\n\n    /**\n     * Update metadata after writing data\n     */\n    updateMetadata(dataToWrite, fileName, customMetadata) {\n        let currentFile;\n\n        if (fileName) {\n            // Find the specific file by filename\n            const foundFile = this.metadata.files.find(file => file.fileName === fileName);\n            if (!foundFile) {\n                this.logger.warn?.(`[FileDatabase] File ${fileName} not found in metadata, using last file`);\n                currentFile = this.metadata.files[this.metadata.files.length - 1];\n            } else {\n                currentFile = foundFile;\n            }\n        } else {\n            // Get the current file info from metadata (always the last file)\n            currentFile = this.metadata.files[this.metadata.files.length - 1];\n        }\n\n        // Calculate the actual records count for the data being written\n        const recordsCount = Array.isArray(dataToWrite) ? dataToWrite.length : 1;\n\n        // Update existing file entry with the correct records count\n        currentFile.recordsCount = recordsCount;\n\n        // Add custom metadata fields if provided\n        if (customMetadata) {\n            Object.assign(currentFile, customMetadata);\n        }\n\n        // Find the file index for synopsis calculation\n        const fileIndex = this.metadata.files.indexOf(currentFile);\n        if (fileIndex !== -1) {\n            this.calculateFileSynopsis(dataToWrite, fileIndex);\n        }\n\n        // Update version metadata\n        this.metadata.version = this.currentVersion;\n        this.metadata.modifiedAt = new Date().toISOString();\n        this.metadata.dataType = detectDataType(dataToWrite);\n\n        // Recalculate total records by summing all file records counts\n        this.metadata.totalRecords = this.metadata.files.reduce((sum, file) => sum + (file.recordsCount || 0), 0);\n\n        this.logger.silly?.(\n            `[FileDatabase] Updated metadata for file ${currentFile.fileName}: recordsCount=${recordsCount}, totalRecords=${this.metadata.totalRecords}`\n        );\n    }\n\n    /**\n     * Safe write with disk space check\n     */\n    async safeWrite(filePath, data) {\n        const serializedData = serializeData(data);\n        const dir = path.dirname(filePath);\n        const requiredBytes = Buffer.byteLength(serializedData, \"utf8\");\n\n        // Check disk space\n        const freeBytes = getFreeDiskSpace(dir);\n        if (freeBytes !== null) {\n            if (freeBytes < requiredBytes) {\n                throw new FileDatabaseError(\n                    `Not enough disk space. Required: ${bytesToHumanReadable(requiredBytes)}, Free: ${bytesToHumanReadable(freeBytes)}`\n                );\n            }\n\n            if (freeBytes < this.freeSpaceThreshold) {\n                this.logger.warn?.(`Low disk space warning: only ${bytesToHumanReadable(freeBytes)} left`);\n            }\n        }\n\n        try {\n            await fs.promises.writeFile(filePath, serializedData, \"utf8\");\n            this.logger.silly?.(`[FileDatabase] Wrote ${bytesToHumanReadable(requiredBytes)} to ${filePath}`);\n        } catch (error) {\n            throw new FileDatabaseError(`Failed to write file ${filePath}: ${(error ).message}`);\n        }\n    }\n\n    /**\n     * Prepare the instance for read or write operations\n     * This discovers state and sets up internal members based on mode and current data\n     */\n    async prepare(options\n\n\n\n\n\n\n\n\n\n    ) {\n        const { write, read, version, deferInitialVersion } = options;\n        if (write) {\n            if (this.versioned) {\n                // Versioned mode\n                if (this.currentVersion === null) {\n                    if (!deferInitialVersion) {\n                        await this.makeNewVersion();\n                        this.metadata = this.getDefaultMetadata();\n                        this.metadata.version = this.currentVersion;\n                        this.makeNewFile();\n                    }\n                } else {\n                    // For existing versions, load the metadata if not already loaded\n                    if (!this.metadata.files.length) {\n                        this.metadata = await this.figureMetadata(this.currentVersion);\n                        // Initialize currentFileNumber from existing files\n                        if (this.metadata.files && this.metadata.files.length > 0) {\n                            this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                        } else {\n                            this.currentFileNumber = 0;\n                        }\n                    }\n                }\n            } else {\n                // Non-versioned mode - ensure table directory exists\n                await ensurePath(this.getDestinationPath());\n\n                // Non-versioned mode - auto-detect useMetadata if not set\n                if (this.useMetadata === true) {\n                    // Try to load existing metadata, create new if doesn't exist\n                    const metadataPath = path.join(this.getDestinationPath(), \"metadata.json\");\n                    if (fs.existsSync(metadataPath)) {\n                        try {\n                            const rawData = await fs.promises.readFile(metadataPath, \"utf8\");\n                            this.metadata = JSON.parse(rawData);\n                            // Initialize currentFileNumber from existing files\n                            if (this.metadata.files && this.metadata.files.length > 0) {\n                                this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                            } else {\n                                this.currentFileNumber = 0;\n                            }\n                        } catch (e) {\n                            this.metadata = this.getDefaultMetadata();\n                            this.currentFileNumber = 0;\n                        }\n                    } else {\n                        // Don't create a file here - let the write logic handle it\n                        // This prevents creating an empty file when customMetadata is provided\n                        this.metadata = this.getDefaultMetadata();\n                        this.currentFileNumber = 0;\n                    }\n                } else {\n                    // No metadata mode - just create default metadata\n                    // Don't create a file here either - let the write logic handle it\n                    this.metadata = this.getDefaultMetadata();\n                    this.currentFileNumber = 0;\n                }\n            }\n        } else if (read) {\n            if (this.versioned) {\n                // Versioned mode\n                const versions = await this.getVersions();\n                if (versions.length === 0) {\n                    throw new FileDatabaseError(\"[FileDatabase] No versions found, cannot read\");\n                }\n\n                const targetVersion = version || versions[versions.length - 1];\n                if (version && !versions.includes(version)) {\n                    throw new FileDatabaseError(`[FileDatabase] Version \"${version}\" not found`);\n                }\n                if (this.metadata.version !== targetVersion) {\n                    this.metadata = this.getDefaultMetadata();\n                    this.currentRecord = 0;\n                    this.hasReadFirstPage = false;\n                }\n                await this.setCurrentVersion(targetVersion);\n\n                if (!this.metadata.files.length) {\n                    this.metadata = await this.figureMetadata(this.currentVersion);\n                    // Initialize currentFileNumber from existing files\n                    if (this.metadata.files && this.metadata.files.length > 0) {\n                        this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                    } else {\n                        this.currentFileNumber = 0;\n                    }\n                }\n            } else {\n                // Non-versioned mode\n                this.currentVersion = null; // No version concept\n\n                // Auto-detect useMetadata if not explicitly set\n                if (this.useMetadata === undefined) {\n                    const format = await this.detectDataFormat();\n                    this.useMetadata = format.hasMetadata;\n                }\n\n                if (this.useMetadata) {\n                    // Load metadata from root\n                    const destPath = this.getDestinationPath();\n                    const metadataPath = path.join(destPath, \"metadata.json\");\n                    if (fs.existsSync(metadataPath)) {\n                        try {\n                            const rawData = await fs.promises.readFile(metadataPath, \"utf8\");\n                            this.metadata = JSON.parse(rawData);\n                            // Initialize currentFileNumber from existing files\n                            if (this.metadata.files && this.metadata.files.length > 0) {\n                                this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                            } else {\n                                this.currentFileNumber = 0;\n                            }\n                        } catch (e) {\n                            throw new FileDatabaseError(`Failed to read metadata: ${(e ).message}`);\n                        }\n                    } else {\n                        throw new FileDatabaseError(\n                            `[FileDatabase] No metadata found in non-versioned mode. Looked for: ${metadataPath} (table path: ${destPath})`\n                        );\n                    }\n                } else {\n                    // Figure metadata from files\n                    this.metadata = await this.figureMetadataFromVersionFiles(\"\");\n                    // Initialize currentFileNumber from existing files\n                    if (this.metadata.files && this.metadata.files.length > 0) {\n                        this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                    } else {\n                        this.currentFileNumber = 0;\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Write data to the file database\n     */\n    async write(data, options = {}) {\n        // Catalog mode: write to specific filename in destination path\n        if (options.filename) {\n            const destPath = this.getDestinationPath();\n            await ensurePath(destPath);\n            const filePath = path.join(destPath, options.filename);\n            await this.safeWrite(filePath, data);\n            return;\n        }\n\n        // Check for forceNewVersion in non-versioned mode\n        if (options.forceNewVersion && !this.versioned) {\n            throw new FileDatabaseError(\"Cannot use forceNewVersion in non-versioned mode\");\n        }\n\n        // Prepare for writing (this may load existing metadata).\n        // If this write will force a new version on an empty store, defer the initial version in\n        // prepare so we only call makeNewVersion() once (in the forceNewVersion block below).\n        await this.prepare({ write: true, deferInitialVersion: !!(options.forceNewVersion && this.versioned) });\n\n        // Always detect data type from incoming data AFTER prepare()\n        // This ensures we use the correct type even if existing metadata has a different type\n        const incomingDataType = detectDataType(data);\n        this.metadata.dataType = incomingDataType;\n\n        // Force new version if requested (versioned mode only)\n        if (options.forceNewVersion) {\n            await this.makeNewVersion();\n            this.metadata = this.getDefaultMetadata();\n            this.metadata.version = this.currentVersion;\n            // Set data type from incoming data\n            this.metadata.dataType = incomingDataType;\n            this.makeNewFile();\n        }\n\n        // Check if customMetadata is provided and find existing file with matching metadata\n        let targetFileIndex = null;\n        const hasCustomMetadata = options.customMetadata && Object.keys(options.customMetadata).length > 0;\n        \n        if (hasCustomMetadata) {\n            // Search through existing files for matching custom metadata\n            for (let i = 0; i < this.metadata.files.length; i++) {\n                const fileEntry = this.metadata.files[i];\n                // Check if all customMetadata fields match\n                // A file matches if it has all the customMetadata keys and their values match\n                const matches = Object.keys(options.customMetadata).every(key => {\n                    // File must have the key and the value must match\n                    return key in fileEntry && fileEntry[key] === options.customMetadata[key];\n                });\n                if (matches) {\n                    targetFileIndex = i;\n                    this.logger.silly?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);\n                    break;\n                } else {\n                    this.logger.silly?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);\n                }\n            }\n            if (targetFileIndex === null) {\n                this.logger.silly?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);\n            }\n        } else {\n            this.logger.silly?.(`[FileDatabase] No custom metadata provided, will create new file`);\n        }\n\n        // If we found a matching file, prepare to overwrite it\n        if (targetFileIndex !== null) {\n            const targetFile = this.metadata.files[targetFileIndex];\n            // Set current file number to match the target file\n            this.currentFileNumber = targetFile.number;\n            // Reset pagination state since we're overwriting\n            this.lastFileData = null;\n            this.currentRecord = 0;\n            this.hasReadFirstPage = false;\n        }\n\n        // Pass flag indicating if we should force a new file (when customMetadata provided but no match)\n        const forceNewFile = hasCustomMetadata && targetFileIndex === null;\n        // eslint-disable-next-line prefer-const\n        let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data, targetFileIndex, forceNewFile);\n\n        // Write first batch\n        const destPath = this.getDestinationPath(this.currentVersion || undefined);\n        await this.safeWrite(path.join(destPath, fileName), dataToWrite);\n        this.updateMetadata(dataToWrite, fileName, options.customMetadata);\n\n        // Handle pagination for remaining data (arrays only)\n        // Note: For customMetadata matches, we only write to the target file, so no pagination needed\n        while (dataLeftOver && dataLeftOver.length > 0 && targetFileIndex === null) {\n            const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);\n            await this.safeWrite(path.join(destPath, writeContext.fileName), writeContext.dataToWrite);\n            this.updateMetadata(writeContext.dataToWrite, writeContext.fileName, options.customMetadata);\n            dataLeftOver = writeContext.dataLeftOver;\n        }\n\n        // Calculate version synopsis\n        this.calculateVersionSynopsis();\n\n        // Save metadata to file\n        if (this.useMetadata) {\n            await this.saveVersionMetadata(this.metadata);\n        }\n    }\n\n    /**\n     * Read data from the file database\n     */\n    async read(options = {}) {\n        const { version, nextPage = false, pageSize, filename } = options;\n\n        // Catalog mode: read specific file by name\n        if (filename) {\n            const destPath = this.getDestinationPath(version);\n            const filePath = path.join(destPath, filename);\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                return JSON.parse(rawData);\n            } catch (error) {\n                throw new FileDatabaseError(`Failed to read file ${filename}: ${(error ).message}`);\n            }\n        }\n\n        // Prepare for reading\n        await this.prepare({ read: true, version });\n\n        // Check for non-paginated data types\n        const isNonPaginatedData =\n            this.metadata.dataType === \"text\" || this.metadata.dataType === \"xml\" || this.metadata.dataType === \"json-object\";\n\n        if (isNonPaginatedData) {\n            // For text/xml/object data, return all content\n            const file = this.metadata.files[0];\n            const filePath = path.join(this.getDestinationPath(this.currentVersion || undefined), file.fileName);\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                return deserializeData(rawData, this.metadata.dataType);\n            } catch (error) {\n                throw new FileDatabaseError(`Failed to read file ${file.fileName}: ${(error ).message}`);\n            }\n        }\n\n        // Handle paginated data (JSON arrays)\n        let effectivePageSize;\n\n        if (nextPage && this.hasReadFirstPage) {\n            // currentRecord was already advanced by records actually returned\n            // at the end of the previous read (not by requested pageSize — that\n            // skipped records when a read ended mid-file / short final page).\n            effectivePageSize = pageSize || this.pageSize;\n        } else if (!nextPage) {\n            // If not paginating, read all records (unless pageSize is explicitly provided)\n            effectivePageSize = pageSize !== undefined ? pageSize : this.metadata.totalRecords;\n            this.currentRecord = 0;\n        } else {\n            // First call with nextPage=true (no previous page read)\n            effectivePageSize = pageSize || this.pageSize;\n        }\n\n        // If beyond total records, return empty array\n        if (this.currentRecord >= this.metadata.totalRecords) {\n            return [];\n        }\n\n        const result = [];\n        this.lastReadMissingFiles = [];\n        let recordsRead = 0;\n        let currentFileIndex = 0;\n        let currentFileOffset = 0;\n\n        // Calculate which file and offset to start from\n        let totalRecords = 0;\n        for (let i = 0; i < this.metadata.files.length; i++) {\n            const file = this.metadata.files[i];\n            if (this.currentRecord < totalRecords + file.recordsCount) {\n                currentFileIndex = i;\n                currentFileOffset = totalRecords;\n                break;\n            }\n            totalRecords += file.recordsCount;\n        }\n\n        // Read from files (cache parsed JSON — harvest chunks are often 50–60MB;\n        // re-parsing on every nextPage with pageSize=200 is catastrophic).\n        let cumulativeRecords = currentFileOffset;\n        for (let i = currentFileIndex; i < this.metadata.files.length && recordsRead < effectivePageSize; i++) {\n            const file = this.metadata.files[i];\n            const filePath = path.join(this.getDestinationPath(this.currentVersion || undefined), file.fileName);\n\n            try {\n                let fileData;\n                if (this.readFileCache?.filePath === filePath && Array.isArray(this.readFileCache.data)) {\n                    fileData = this.readFileCache.data;\n                } else {\n                    const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                    fileData = deserializeData(rawData, this.metadata.dataType);\n                    this.readFileCache = { filePath, data: fileData };\n                }\n\n                let startIndex = 0;\n                if (i === currentFileIndex) {\n                    startIndex = this.currentRecord - cumulativeRecords;\n                }\n\n                const endIndex = Math.min(startIndex + (effectivePageSize - recordsRead), fileData.length);\n                const recordsFromThisFile = fileData.slice(startIndex, endIndex);\n\n                for (let r = 0; r < recordsFromThisFile.length; r++) {\n                    result.push(recordsFromThisFile[r]);\n                }\n                recordsRead += recordsFromThisFile.length;\n\n                cumulativeRecords += file.recordsCount;\n            } catch (error) {\n                if (error?.code === \"ENOENT\") {\n                    if (!this.lastReadMissingFiles) this.lastReadMissingFiles = [];\n                    this.lastReadMissingFiles.push(file.fileName);\n                    cumulativeRecords += file.recordsCount;\n                    continue;\n                }\n                throw new FileDatabaseError(`Failed to read file ${file.fileName}: ${(error ).message}`);\n            }\n        }\n\n        // Advance by what we actually returned so mid-file seeks + short pages\n        // don't skip records on the next nextPage call.\n        this.currentRecord += recordsRead;\n\n        // Mark page as read for pagination tracking\n        // When nextPage=true, we're explicitly paginating\n        // When nextPage=false with explicit pageSize, we're also paginating (starting from beginning)\n        if (result.length > 0) {\n            if (nextPage || (pageSize !== undefined && pageSize < this.metadata.totalRecords)) {\n                this.hasReadFirstPage = true;\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * Set the starting record for pagination (1-based index)\n     */\n    setStartRecord(startRecord) {\n        this.currentRecord = startRecord - 1;\n        this.hasReadFirstPage = false;\n        this.readFileCache = null;\n    }\n\n    /**\n     * Reset read pagination state\n     */\n    resetPagination() {\n        this.currentRecord = 0;\n        this.hasReadFirstPage = false;\n        this.readFileCache = null;\n    }\n\n    /**\n     * List filenames in the table directory.\n     * For catalog/key-value usage (files written with { filename }).\n     * Returns data file names (.json, .txt, .xml) excluding metadata.json.\n     */\n    async listFilenames() {\n        const destPath = this.versioned && this.currentVersion\n            ? path.join(this.getDestinationPath(), this.currentVersion)\n            : this.getDestinationPath();\n        try {\n            const entries = await fs.promises.readdir(destPath, { withFileTypes: true });\n            return entries\n                .filter((e) => e.isFile() && e.name !== \"metadata.json\" && /\\.(json|txt|xml)$/i.test(e.name))\n                .map((e) => e.name);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") return [];\n            throw new FileDatabaseError(`Failed to list files: ${(err ).message}`);\n        }\n    }\n\n    /**\n     * Remove a file from the table directory (catalog mode).\n     * Use with listFilenames() to manage individual files.\n     */\n    async removeFile(filename) {\n        const destPath = this.versioned && this.currentVersion\n            ? path.join(this.getDestinationPath(), this.currentVersion)\n            : this.getDestinationPath();\n        const filePath = path.join(destPath, filename);\n        try {\n            await fs.promises.unlink(filePath);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") return;\n            throw new FileDatabaseError(`Failed to remove file ${filename}: ${(err ).message}`);\n        }\n    }\n\n    /**\n     * Remove a file and its metadata entry (non-versioned mode with useMetadata).\n     * Use with findData() to get fileName, then call removeFileEntry to delete.\n     */\n    async removeFileEntry(filename) {\n        if (this.versioned) {\n            throw new FileDatabaseError(\"removeFileEntry is only supported in non-versioned mode\");\n        }\n        await this.prepare({ read: true });\n        const idx = this.metadata.files.findIndex((f) => f.fileName === filename);\n        if (idx === -1) {\n            throw new FileDatabaseError(`File entry ${filename} not found in metadata`);\n        }\n        const entry = this.metadata.files[idx];\n        const recordsCount = entry.recordsCount || 0;\n        this.metadata.files.splice(idx, 1);\n        this.metadata.totalRecords = Math.max(0, (this.metadata.totalRecords || 0) - recordsCount);\n        const destPath = this.getDestinationPath();\n        const filePath = path.join(destPath, filename);\n        try {\n            await fs.promises.unlink(filePath);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") {\n                this.logger.warn?.(`[FileDatabase] File ${filename} already missing on disk`);\n            } else {\n                throw new FileDatabaseError(`Failed to remove file ${filename}: ${(err ).message}`);\n            }\n        }\n        if (this.useMetadata) {\n            await this.saveVersionMetadata(this.metadata);\n        }\n    }\n\n    /**\n     * Set file-level synopsis calculation function\n     */\n    setFileSynopsisFunction(fn) {\n        this.fileSynopsisFunction = fn;\n    }\n\n    /**\n     * Set version-level synopsis calculation function\n     */\n    setVersionSynopsisFunction(fn) {\n        this.versionSynopsisFunction = fn;\n    }\n\n    /**\n     * Get current version name\n     */\n    getCurrentVersion() {\n        return this.currentVersion;\n    }\n\n    /**\n     * Max retained version folders (used by harvest_sync.loaded_versions cap, etc.).\n     */\n    getMaxVersions() {\n        return this.maxVersions;\n    }\n\n    /**\n     * Get current metadata\n     */\n    getMetadata() {\n        return { ...this.metadata };\n    }\n\n    /**\n     * Find data by custom metadata fields\n     * Searches through all versions and files to find entries matching the search criteria\n     * \n     * @param searchCriteria - Object with field names and values to search for (e.g., { ListingKey: \"123\", id: \"456\" })\n     * @returns Array of found entries with their file paths and metadata\n     */\n    async findData(searchCriteria)\n\n\n\n\n\n    {\n        const results\n\n\n\n\n\n = [];\n\n        // Handle non-versioned mode separately\n        if (!this.versioned) {\n            // Load metadata for non-versioned mode\n            await this.prepare({ read: true });\n            const metadata = this.getMetadata();\n            \n            // Search through files\n            for (const fileEntry of metadata.files) {\n                // Check if file entry matches search criteria\n                const matches = Object.keys(searchCriteria).every(key => {\n                    return fileEntry[key] === searchCriteria[key];\n                });\n\n                if (matches) {\n                    // Read the file data\n                    const destPath = this.getDestinationPath();\n                    const filePath = path.join(destPath, fileEntry.fileName);\n                    const fileData = await fs.promises.readFile(filePath, \"utf8\");\n                    const data = deserializeData(fileData, metadata.dataType || \"json-object\");\n\n                    results.push({\n                        filePath,\n                        fileName: fileEntry.fileName,\n                        version: null,\n                        metadata: fileEntry,\n                        data,\n                    });\n                }\n            }\n        } else {\n            // Versioned mode: search through all versions\n            const versions = await this.getVersions();\n            \n            for (const version of versions) {\n                // Load metadata for this version\n                await this.prepare({ read: true, version });\n                const metadata = this.getMetadata();\n\n                // Search through files in this version\n                for (const fileEntry of metadata.files) {\n                    // Check if file entry matches search criteria\n                    const matches = Object.keys(searchCriteria).every(key => {\n                        return fileEntry[key] === searchCriteria[key];\n                    });\n\n                    if (matches) {\n                        // Read the file data\n                        const destPath = this.getDestinationPath(version);\n                        const filePath = path.join(destPath, fileEntry.fileName);\n                        const fileData = await fs.promises.readFile(filePath, \"utf8\");\n                        const data = deserializeData(fileData, metadata.dataType || \"json-object\");\n\n                        results.push({\n                            filePath,\n                            fileName: fileEntry.fileName,\n                            version,\n                            metadata: fileEntry,\n                            data,\n                        });\n                    }\n                }\n            }\n        }\n\n        return results;\n    }\n}\n\n// Export types\n\n\n\n\n\n\n\n\n\n\n\n;\n\n// Export synopsis functions\nexport { defaultFileSynopsisFunction, defaultVersionSynopsisFunction } from \"./synopsis-functions.js\";\n\n/**\n * Initialize FileDatabase from context\n * Similar to MlsClient.init pattern\n * \n * @param context - Context from init()\n * @param options - Optional configuration (takes precedence over context.params)\n * @returns Initialized FileDatabase instance\n */\n/**\n * List all table names in a given namespace\n * Scans the filesystem to find all table directories\n *\n * @param basePath - Base path for file storage\n * @param namespace - Namespace to scan (e.g., \"harvested\", \"fromMLS\")\n * @returns Array of table names (directory names)\n */\nexport function listTables(basePath, namespace) {\n    const namespacePath = path.join(basePath, namespace);\n\n    if (!fs.existsSync(namespacePath)) {\n        return [];\n    }\n\n    try {\n        return fs.readdirSync(namespacePath, { withFileTypes: true })\n            .filter(dirent => dirent.isDirectory())\n            .map(dirent => dirent.name);\n    } catch (error) {\n        // Return empty array if can't read directory\n        return [];\n    }\n}\n\n/**\n * List all sources (namespaces) in a given base path\n * Scans the filesystem to find all namespace directories\n *\n * @param basePath - Base path for file storage\n * @returns Array of source names (directory names)\n */\nexport function listSources(basePath) {\n    if (!fs.existsSync(basePath)) {\n        return [];\n    }\n\n    try {\n        return fs.readdirSync(basePath, { withFileTypes: true })\n            .filter(dirent => dirent.isDirectory())\n            .map(dirent => dirent.name);\n    } catch (error) {\n        // Return empty array if can't read directory\n        return [];\n    }\n}\n","/**\n * Operating System Utilities\n * \n * Helper functions for interacting with the operating system\n * to get system statistics and information\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { execSync } from \"child_process\";\n\n/**\n * Get free disk space for a given path (in bytes)\n * Returns null if unable to determine\n * Uses `df` command on Unix-like systems\n */\nexport function getFreeDiskSpace(targetPath) {\n    try {\n        // If the target path doesn't exist, use its parent directory\n        let pathToCheck = targetPath;\n        if (!fs.existsSync(targetPath)) {\n            const parentDir = path.dirname(targetPath);\n            if (fs.existsSync(parentDir)) {\n                pathToCheck = parentDir;\n            } else {\n                // If parent doesn't exist either, use the root directory\n                pathToCheck = process.platform === \"win32\" ? \"C:\\\\\" : \"/\";\n            }\n        }\n\n        if (process.platform === \"win32\") {\n            // Windows: use wmic command\n            // Note: This is a simplified implementation, may need adjustments\n            return null; // TODO: Implement robust Windows support\n        } else {\n            // Unix-like systems: use df command\n            const stdout = execSync(`df -k \"${pathToCheck}\"`, { encoding: \"utf8\" });\n            const lines = stdout.trim().split(\"\\n\");\n            const parts = lines[1].split(/\\s+/); // second line, split on whitespace\n            const freeKb = parseInt(parts[3], 10); // 4th column is \"Available\"\n            return freeKb * 1024; // Convert to bytes\n        }\n    } catch (error) {\n        // Silently fail and return null\n        return null;\n    }\n}\n\n/**\n * Free / total bytes for the volume that holds `targetPath` (Node `fs.statfs`).\n * Returns null when the call is unavailable or fails.\n *\n * @param {string} targetPath\n * @returns {Promise<{ free: number, total: number, freeRatio: number } | null>}\n */\nexport async function getDiskUsage(targetPath) {\n    const fsPromises = await import(\"node:fs/promises\");\n    try {\n        let pathToCheck = targetPath;\n        if (!fs.existsSync(pathToCheck)) {\n            const parentDir = path.dirname(pathToCheck);\n            pathToCheck = fs.existsSync(parentDir)\n                ? parentDir\n                : process.platform === \"win32\"\n                  ? \"C:\\\\\"\n                  : \"/\";\n        }\n        if (typeof fsPromises.statfs !== \"function\") return null;\n        const stats = await fsPromises.statfs(pathToCheck);\n        const total = Number(stats.bsize) * Number(stats.blocks);\n        const free = Number(stats.bsize) * Number(stats.bavail);\n        if (!Number.isFinite(total) || total <= 0) return null;\n        return { free, total, freeRatio: free / total };\n    } catch {\n        return null;\n    }\n}\n\n","/**\n * File System Utilities\n * \n * Helper functions for file system operations like path management,\n * directory creation, and file type detection\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * Ensure a directory path exists, creating it if necessary\n * Returns the absolute path\n */\nexport async function ensurePath(...pathParts) {\n    const fullPath = path.resolve(...pathParts);\n    \n    if (!fs.existsSync(fullPath)) {\n        await fs.promises.mkdir(fullPath, { recursive: true });\n    }\n    \n    return fullPath;\n}\n\n/**\n * Synchronous version of ensurePath\n */\nexport function ensurePathSync(...pathParts) {\n    const fullPath = path.resolve(...pathParts);\n    \n    if (!fs.existsSync(fullPath)) {\n        fs.mkdirSync(fullPath, { recursive: true });\n    }\n    \n    return fullPath;\n}\n\n/**\n * Get file extension for a given data type\n */\nexport function getFileExtension(dataType) {\n    switch (dataType) {\n        case \"json-array\":\n        case \"json-object\":\n            return \"json\";\n        case \"text\":\n            return \"txt\";\n        case \"xml\":\n            return \"xml\";\n        default:\n            return \"json\";\n    }\n}\n\n/**\n * Get __dirname equivalent for ES modules\n * \n * Returns the directory path of the module file\n * Useful for resolving relative paths in ES modules where __dirname is not available\n * \n * @param metaUrl - The import.meta.url from the calling module (must be passed from calling module)\n * @returns The directory path of the module\n * \n * @example\n * ```typescript\n * import { getDirname } from \"@nmakarov/cli-toolkit/utils\";\n * const __dirname = getDirname(import.meta.url);\n * ```\n */\nexport function getDirname(metaUrl) {\n    return path.dirname(fileURLToPath(metaUrl));\n}\n\n","/**\n * Formatting Utilities\n * \n * Helper functions for converting between different data formats\n * and human-readable representations\n */\n\n/**\n * Convert bytes to human-readable format (e.g., \"1.5 MB\")\n */\nexport function bytesToHumanReadable(bytes) {\n    if (bytes === 0) return \"0 B\";\n    \n    const k = 1024;\n    const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"];\n    const i = Math.floor(Math.log(bytes) / Math.log(k));\n    \n    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n}\n\n/**\n * Convert human-readable format to bytes (e.g., \"1.5 MB\" -> 1572864)\n */\nexport function humanReadableToBytes(humanString) {\n    const units = {\n        \"B\": 1,\n        \"KB\": 1024,\n        \"MB\": 1024 * 1024,\n        \"GB\": 1024 * 1024 * 1024,\n        \"TB\": 1024 * 1024 * 1024 * 1024,\n        \"PB\": 1024 * 1024 * 1024 * 1024 * 1024,\n    };\n    \n    const match = humanString.trim().match(/^([\\d.]+)\\s*([A-Z]+)$/i);\n    if (!match) {\n        throw new Error(`Invalid format: ${humanString}. Expected format like \"2MB\" or \"1.5 GB\"`);\n    }\n    \n    const value = parseFloat(match[1]);\n    const unit = match[2].toUpperCase();\n    \n    if (!units[unit]) {\n        throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(\", \")}`);\n    }\n    \n    return Math.round(value * units[unit]);\n}\n\n","/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\n\n\n\n\n\n/**\n * Format a date string or Date object to ISO8601 format in specified timezone\n * Always returns UTC-based ISO strings (YYYY-MM-DDTHH:mm:ssZ) as internal representation\n * \n * @param value - Date object, ISO string, or timestamp\n * @param options - Formatting options\n * @returns ISO8601 formatted string\n */\nexport function formatDate(value, options = {}) {\n    if (value === undefined || value === null) {\n        return \"\";\n    }\n\n    const { timezone = \"UTC\", format = \"iso\" } = options;\n    \n    let date;\n    if (value instanceof Date) {\n        date = value;\n    } else if (typeof value === \"string\") {\n        date = new Date(value);\n    } else if (typeof value === \"number\") {\n        date = new Date(value);\n    } else {\n        return \"\";\n    }\n\n    if (isNaN(date.getTime())) {\n        return \"\";\n    }\n\n    // Format based on requested format\n    switch (format) {\n        case \"iso\":\n            // Full ISO8601: 2025-01-01T01:01:01Z\n            return date.toISOString();\n        \n        case \"iso-date\":\n            // Date only: 2025-01-01\n            return date.toISOString().split(\"T\")[0];\n        \n        case \"iso-time\":\n            // Time only: 01:01:01Z\n            return date.toISOString().split(\"T\")[1];\n        \n        case \"human\":\n            // Human-readable: Jan 1, 2025 01:01:01 UTC\n            if (timezone === \"user\") {\n                return date.toLocaleString();\n            }\n            return date.toUTCString();\n        \n        default:\n            return date.toISOString();\n    }\n}\n\n/**\n * Parse a date value and return ISO8601 string in UTC\n * This is the canonical format for internal storage\n * \n * @param value - Date object or string\n * @returns ISO8601 string in UTC timezone\n */\nexport function toISOString(value) {\n    return formatDate(value, { timezone: \"UTC\", format: \"iso\" });\n}\n\n/**\n * Get current timestamp as ISO8601 string in UTC\n * @returns Current time as ISO8601 string\n */\nexport function nowISO() {\n    return new Date().toISOString();\n}\n\n/**\n * Parse ISO8601 string to Date object\n * @param isoString - ISO8601 formatted string\n * @returns Date object\n */\nexport function fromISOString(isoString) {\n    return new Date(isoString);\n}\n\n/**\n * Calculate difference between two dates in various units\n * @param start - Start date (ISO string or Date)\n * @param end - End date (ISO string or Date)\n * @returns Object with duration in multiple units\n */\nexport function dateDiff(\n    start,\n    end\n)\n\n\n\n\n\n{\n    const startDate = start instanceof Date ? start : new Date(start);\n    const endDate = end instanceof Date ? end : new Date(end);\n    \n    const diffMs = endDate.getTime() - startDate.getTime();\n    \n    return {\n        milliseconds: diffMs,\n        seconds: Math.floor(diffMs / 1000),\n        minutes: Math.floor(diffMs / (1000 * 60)),\n        hours: Math.floor(diffMs / (1000 * 60 * 60)),\n        days: Math.floor(diffMs / (1000 * 60 * 60 * 24))\n    };\n}\n\n/**\n * Check if a folder name looks like an ISO8601 timestamp\n * Used to identify version folders vs regular folders\n * @param folderName - Folder name to check\n * @returns true if the folder name is a valid ISO8601 timestamp\n */\nexport function isTimestampFolder(folderName) {\n    // Match ISO8601 format: YYYY-MM-DDTHH:mm:ssZ\n    const isoRegex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|\\.\\d{3}Z)$/;\n    \n    if (!isoRegex.test(folderName)) {\n        return false;\n    }\n    \n    const date = new Date(folderName);\n    return !isNaN(date.getTime()) && date.getTime() > 0;\n}\n\n/**\n * Generate a new version name (ISO8601 timestamp)\n * If existingVersions provided, ensures the new version is later than all existing ones\n * @param existingVersions - Array of existing version timestamps\n * @returns New version timestamp that is unique and later than existing ones\n */\nexport function generateVersionName(existingVersions = []) {\n    if (existingVersions.length === 0) {\n        // No existing versions, use current timestamp\n        const now = new Date();\n        return now.toISOString().split(\".\")[0] + \"Z\";\n    }\n    \n    // Find the maximum timestamp among all existing versions\n    const maxTimestamp = existingVersions.reduce((max, version) => {\n        const versionDate = new Date(version);\n        const maxDate = new Date(max);\n        return versionDate > maxDate ? version : max;\n    });\n    \n    // Increment by 1 second to ensure uniqueness\n    const maxDate = new Date(maxTimestamp);\n    const nextDate = new Date(maxDate.getTime() + 1000);\n    \n    return nextDate.toISOString().split(\".\")[0] + \"Z\";\n}\n\n","\n\n\n\n\n\n\n\n/**\n * Detect the data type of a given value\n */\nexport function detectDataType(data) {\n    if (Array.isArray(data)) {\n        return \"json-array\";\n    } else if (typeof data === \"object\" && data !== null) {\n        return \"json-object\";\n    } else if (typeof data === \"string\") {\n        // Try to detect if it's XML\n        const trimmed = data.trim();\n        if (trimmed.startsWith(\"<?xml\") || trimmed.startsWith(\"<\")) {\n            return \"xml\";\n        }\n        return \"text\";\n    } else {\n        return \"text\";\n    }\n}\n\n/**\n * Serialize data to a string for file storage\n */\nexport function serializeData(data) {\n    const dataType = detectDataType(data);\n    \n    if (dataType === \"json-array\" || dataType === \"json-object\") {\n        return JSON.stringify(data, null, 4);\n    } else {\n        // For text and XML, return as-is\n        return String(data);\n    }\n}\n\n/**\n * Deserialize data from a string based on data type\n */\nexport function deserializeData(rawData, dataType) {\n    if (dataType === \"json-array\" || dataType === \"json-object\") {\n        return JSON.parse(rawData);\n    } else {\n        // For text and XML, return as-is\n        return rawData;\n    }\n}\n\n","/**\n * Legacy MLS-oriented synopsis helpers.\n *\n * @deprecated MLS harvest digests (ModificationTimestamp min/max + StandardStatus\n * counts) live in mlsfarm `v2/mls-toolkit/src/harvest/synopsis.js`\n * (`attachHarvestSynopsis`). FileDatabase stays domain-agnostic — attach a\n * synopsis plugin from the app layer. These exports remain for older callers /\n * tests; prefer mls-toolkit for new harvest code.\n */\n\n/**\n * Default file-level synopsis function\n * Extracts min/max *ModificationTimestamp and StandardStatus counts from records.\n * Matches ModificationTimestamp and MediaModificationTimestamp (any key ending\n * with \"modificationtimestamp\", case-insensitive).\n */\nexport function defaultFileSynopsisFunction(fileEntry, data) {\n    if (!Array.isArray(data) || data.length === 0) {\n        return { ...fileEntry };\n    }\n\n    const timestamps = [];\n    const statusCounts = {};\n\n    for (const item of data) {\n        if (!item || typeof item !== \"object\") continue;\n\n        for (const [key, value] of Object.entries(item)) {\n            const k = key.toLowerCase();\n            if (k.endsWith(\"modificationtimestamp\") && value != null && value !== \"\") {\n                const ts = new Date(value).getTime();\n                if (!Number.isNaN(ts)) timestamps.push(ts);\n            }\n            if (k === \"standardstatus\" && value != null && value !== \"\") {\n                const status = String(value);\n                statusCounts[status] = (statusCounts[status] || 0) + 1;\n            }\n        }\n    }\n\n    const result = { ...fileEntry };\n\n    if (timestamps.length) {\n        result.minModificationTimestamp = new Date(Math.min(...timestamps)).toISOString();\n        result.maxModificationTimestamp = new Date(Math.max(...timestamps)).toISOString();\n    }\n\n    if (Object.keys(statusCounts).length) {\n        result.StandardStatuses = statusCounts;\n    }\n\n    return result;\n}\n\n/**\n * Default version-level synopsis function\n * Aggregates min/max timestamps and status counts across all files in a version\n */\nexport function defaultVersionSynopsisFunction(metadata) {\n    if (!metadata?.files || !Array.isArray(metadata.files)) {\n        return metadata;\n    }\n\n    const timestamps = [];\n    const statusCounts = {};\n\n    for (const file of metadata.files) {\n        if (file?.minModificationTimestamp) {\n            const minTs = new Date(file.minModificationTimestamp).getTime();\n            if (!Number.isNaN(minTs)) timestamps.push(minTs);\n        }\n        if (file?.maxModificationTimestamp) {\n            const maxTs = new Date(file.maxModificationTimestamp).getTime();\n            if (!Number.isNaN(maxTs)) timestamps.push(maxTs);\n        }\n\n        if (file?.StandardStatuses && typeof file.StandardStatuses === \"object\") {\n            for (const [status, count] of Object.entries(file.StandardStatuses)) {\n                statusCounts[status] = (statusCounts[status] || 0) + Number(count || 0);\n            }\n        }\n    }\n\n    const result = { ...metadata };\n    const synopsis = {\n        ...(metadata.synopsis && typeof metadata.synopsis === \"object\" ? metadata.synopsis : {}),\n    };\n\n    if (timestamps.length) {\n        const minIso = new Date(Math.min(...timestamps)).toISOString();\n        const maxIso = new Date(Math.max(...timestamps)).toISOString();\n        result.minModificationTimestamp = minIso;\n        result.maxModificationTimestamp = maxIso;\n        synopsis.minModificationTimestamp = minIso;\n        synopsis.maxModificationTimestamp = maxIso;\n    }\n\n    if (Object.keys(statusCounts).length > 0) {\n        result.StandardStatuses = statusCounts;\n        synopsis.StandardStatuses = statusCounts;\n    }\n\n    if (Object.keys(synopsis).length) {\n        result.synopsis = synopsis;\n    }\n    return result;\n}\n","import knex from \"knex\";\nimport { ParamError } from \"../errors.js\";\n\nexport {\n    ensureExtension,\n    ensureTable,\n    ensureIndex,\n    ensureSchema,\n    ensureSchemaEverywhere,\n} from \"./ensure.js\";\n\nconst KNEX_DEFAULTS = {\n    testConnection: true,\n    // min: 0 avoids holding idle sockets that go stale during long-running CLIs\n    pool: { min: 0, max: 10, idleTimeoutMillis: 30_000 },\n    acquireConnectionTimeout: 10000,\n    ssl: { rejectUnauthorized: false },\n};\n\n/** Node / pg / knex signals that the socket or pool is dead and a reconnect may help. */\nconst CONNECTION_ERROR_CODES = new Set([\n    \"ECONNRESET\",\n    \"ECONNREFUSED\",\n    \"EPIPE\",\n    \"ETIMEDOUT\",\n    \"ENOTFOUND\",\n    \"EHOSTUNREACH\",\n    \"ENETUNREACH\",\n    \"ECONNABORTED\",\n    \"CONNECTION_ENDED\",\n    \"CONNECTION_CLOSED\",\n    // PostgreSQL SQLSTATE class 08xxx (connection exception) + admin shutdowns\n    \"08000\",\n    \"08001\",\n    \"08003\",\n    \"08004\",\n    \"08006\",\n    \"08007\",\n    \"08P01\",\n    \"57P01\",\n    \"57P02\",\n    \"57P03\",\n]);\n\n// Note: \"Timeout acquiring a connection\" is pool contention (all slots busy),\n// not a dead socket — reconnecting destroys healthy clients and makes it worse.\nconst CONNECTION_ERROR_MESSAGE_RE =\n    /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection (terminated|ended) unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET/i;\n\nexport class Db {\n    static async init(context, options = {}) {\n        const buildConfig = async () => {\n            const defs = {\n                dbName: \"string\",\n                dbProfile: \"boolean default false\",\n                /** Cap knex pool size (default 10). Size ≈ expected concurrency + headroom. */\n                dbPoolMax: \"number\",\n            };\n            const discovered = context?.params?.getAllForModule?.(\"db\", defs) ?? {};\n            const merged = { ...discovered, ...options };\n\n            let { dbName, dbProfile } = merged;\n            let dbConnectionString = options.dbConnectionString ?? options.connectionString;\n            let connectionParam = dbConnectionString ? \"options\" : null;\n\n            if (!dbConnectionString) {\n                const src = context?.args?.getSource?.(\"dbConnectionString\");\n                if (src === \"cli\" || src === \"overrides\" || src === \"config\") {\n                    dbConnectionString = await context.params.get(\"dbConnectionString\", \"string\");\n                    connectionParam = \"dbConnectionString\";\n                }\n            }\n\n            if (!dbConnectionString && dbName && /^(postgresql|mysql):\\/\\//.test(dbName)) {\n                dbConnectionString = dbName;\n                dbName = undefined;\n            }\n\n            if (!dbConnectionString && dbName) {\n                const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n                dbConnectionString = await context.params.get(paramName, \"string\");\n                connectionParam = paramName;\n                if (!dbConnectionString) {\n                    throw new ParamError(\n                        `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n                    );\n                }\n            }\n\n            if (!dbConnectionString) {\n                dbConnectionString = await context.params.get(\"dbConnectionString\", \"string\");\n                if (dbConnectionString) {\n                    connectionParam = \"dbConnectionString\";\n                }\n            }\n\n            if (!dbConnectionString) {\n                if (!dbName) {\n                    const env = context?.args?.env;\n                    // Never silently fall back to \"local\" on production/stage — that\n                    // masked missing DB_NAME_* / --dbName as a localhost:6032 connect.\n                    if (env && String(env).toLowerCase() !== \"local\") {\n                        throw new ParamError(\n                            `Db: dbName not set for env=\"${env}\" (set --dbName or DB_NAME_${String(env).toUpperCase()})`\n                        );\n                    }\n                    dbName = \"local\";\n                }\n                const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n                dbConnectionString = await context.params.get(paramName, \"string\");\n                connectionParam = paramName;\n                if (!dbConnectionString) {\n                    throw new ParamError(\n                        `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n                    );\n                }\n            }\n\n            const displayName = resolveDbDisplayName(\n                dbName,\n                connectionParam,\n                context?.args?.env,\n                merged.name\n            );\n\n            const poolMaxRaw = merged.dbPoolMax ?? merged.pool?.max;\n            const poolMax = Number(poolMaxRaw);\n            const pool = {\n                ...KNEX_DEFAULTS.pool,\n                ...(merged.pool && typeof merged.pool === \"object\" ? merged.pool : {}),\n            };\n            if (Number.isFinite(poolMax) && poolMax >= 1) {\n                pool.max = Math.floor(poolMax);\n            }\n\n            return {\n                ...KNEX_DEFAULTS,\n                connectionString: dbConnectionString,\n                name: displayName,\n                profile: !!dbProfile,\n                logger: context.logger,\n                pool,\n                ...(merged.acquireConnectionTimeout != null\n                    ? { acquireConnectionTimeout: merged.acquireConnectionTimeout }\n                    : {}),\n            };\n        };\n\n        const config = context?.params?.runWithModuleAsync\n            ? await context.params.runWithModuleAsync(\"db\", buildConfig)\n            : await buildConfig();\n\n        return dbConnect(context, config);\n    }\n\n    /**\n     * Initialize a SIBLING database handler: a database that lives on the same\n     * server with the same credentials/options as an existing (\"base\") one, and\n     * differs only by its database name. Typical use: a per-tenant / per-subject\n     * database alongside a main database that keeps the shared tables.\n     *\n     *   context.db = await Db.init(context);                       // main\n     *   const sub  = await Db.initSibling(context, \"src_bright\");  // sibling\n     *\n     * LOCATION-AGNOSTIC BY DESIGN — the call gracefully falls back to the main\n     * database, so callers can use it for all subject data without knowing what\n     * has been migrated where:\n     *   - empty `siblingName`            → the main handler (same as Db.init)\n     *   - sibling DB does not exist yet  → the main handler (data not migrated;\n     *     it still lives in the main database)\n     * Callers that must not fall back can check `handler === context.db`.\n     *\n     * Connection string resolution for an actual sibling, in order:\n     *   1. Explicit override — param `dbConnectionStringSib<SiblingName>` (env\n     *      `DB_CONNECTION_STRING_SIB_<SIBLING_NAME>`, e.g. `src_bright` →\n     *      `DB_CONNECTION_STRING_SIB_SRC_BRIGHT`). Nobody needs this on day\n     *      one; it is the escape hatch for when a sibling later moves to its\n     *      own server — one env var, no code changes (the `SIB_` namespace\n     *      both overrides the connection and declares that the sibling\n     *      exists, so it never falls back to main).\n     *   2. Derived — take the base connection string and swap the database\n     *      name (after confirming the database exists on that server). The\n     *      base is `options.baseDb` (a Db handler), then\n     *      `options.baseConnectionString`, then `context.db`.\n     *\n     * Handlers are cached per name on the context (`context.siblingDbs`), so\n     * any number of components asking for the same sibling share one pool —\n     * including the \"falls back to main\" answer, which is remembered for the\n     * lifetime of the process (a mid-run migration is picked up on restart).\n     * Disconnect is registered via `context.registerCleanup`, same as the\n     * main handler.\n     *\n     * @param {object} context - context with params/logger (and usually .db)\n     * @param {string} [siblingName] - the sibling's database name (e.g. \"src_bright\")\n     * @param {object} [options] - { baseDb, baseConnectionString, dbProfile }\n     * @returns {Promise<Db>} connected handler (same proxy shape as Db.init)\n     */\n    static async initSibling(context, siblingName, options = {}) {\n        // Empty name → the main database, so call sites stay location-agnostic.\n        if (!siblingName) {\n            return resolveMainHandler(context, options);\n        }\n        if (!/^[a-zA-Z0-9_]+$/.test(siblingName)) {\n            throw new ParamError(\n                `Db.initSibling: invalid sibling database name \"${siblingName}\" (letters, digits and _ only)`\n            );\n        }\n\n        if (!context.siblingDbs) {\n            context.siblingDbs = new Map();\n        }\n        const cached = context.siblingDbs.get(siblingName);\n        if (cached) {\n            return cached;\n        }\n\n        // 1. explicit override: dbConnectionStringSib<SiblingName> param / env var.\n        // Its presence also DECLARES the sibling (it may live on another server),\n        // so the existence check below is skipped.\n        const overrideParam = `dbConnectionStringSib${camelizeDbName(siblingName)}`;\n        let connectionString = await context?.params?.get?.(overrideParam, \"string\");\n        if (connectionString) {\n            context.logger?.debug?.(\n                `[Db] sibling \"${siblingName}\": using override param \"${overrideParam}\"`\n            );\n        } else {\n            // 2. derive from the base connection string\n            const baseHandle = options.baseDb ?? context.db;\n            const base =\n                baseHandle?.config?.connectionString ?? options.baseConnectionString;\n            if (!base) {\n                throw new ParamError(\n                    `Db.initSibling: no base connection to derive \"${siblingName}\" from — ` +\n                        `init the main Db first (context.db = await Db.init(context)), ` +\n                        `or pass options.baseDb / options.baseConnectionString, ` +\n                        `or set the ${overrideParam} param (env ${toEnvKey(overrideParam)})`\n                );\n            }\n\n            // Not migrated yet? Fall back to the main database so the caller's\n            // code works the same before and after the split.\n            const exists = await databaseExistsOnServer(baseHandle, base, siblingName);\n            if (!exists) {\n                context.logger?.debug?.(\n                    `[Db] sibling \"${siblingName}\" does not exist — falling back to the main database`\n                );\n                const main = await resolveMainHandler(context, options);\n                context.siblingDbs.set(siblingName, main);\n                return main;\n            }\n\n            connectionString = replaceDatabaseName(base, siblingName);\n            context.logger?.debug?.(\n                `[Db] sibling \"${siblingName}\": derived from base (${formatConnectionEndpoint(base) ?? \"?\"})`\n            );\n        }\n\n        const config = {\n            ...KNEX_DEFAULTS,\n            connectionString,\n            name: siblingName,\n            profile: !!options.dbProfile,\n            logger: context.logger,\n        };\n\n        const handler = await dbConnect(context, config);\n        context.siblingDbs.set(siblingName, handler);\n        return handler;\n    }\n\n    /**\n     * Discover the sibling databases that are \"currently in use\", by name.\n     * Two sources, merged (env wins on duplicates):\n     *\n     *   1. ENV-DECLARED — every `DB_CONNECTION_STRING_SIB_<NAME>` env var\n     *      (the dedicated `SIB_` namespace) whose decoded name matches. This\n     *      covers siblings that moved to their own server: the same var that\n     *      overrides the connection also *registers* the database, so `.env`\n     *      stays the single convenient list.\n     *   2. SAME-SERVER SCAN — `SELECT datname FROM pg_database` on the base\n     *      server (PostgreSQL only), filtered the same way.\n     *\n     * The caller says what \"matches\": `{ prefix: \"src_\" }` or\n     * `{ match: /^src_/ }` — the toolkit does not guess a naming convention.\n     *\n     * @param {object} context - needs context.db (or options.baseDb) for the server scan\n     * @param {{ prefix?: string, match?: RegExp, baseDb?: object, env?: object }} options\n     * @returns {Promise<Array<{ name: string, origin: \"env\"|\"server\" }>>} sorted by name\n     */\n    static async discoverSiblings(context, options = {}) {\n        const { prefix, match, env = process.env } = options;\n        if (!prefix && !match) {\n            throw new ParamError(`Db.discoverSiblings: pass { prefix: \"...\" } or { match: /.../ }`);\n        }\n        const matches = match instanceof RegExp ? (n) => match.test(n) : (n) => n.startsWith(prefix);\n\n        const found = new Map();\n\n        // 1. env-declared siblings (possibly on other servers) — SIB_ namespace\n        for (const key of Object.keys(env)) {\n            const m = /^DB_CONNECTION_STRING_SIB_(.+)$/.exec(key);\n            if (!m || !env[key]) continue;\n            const name = m[1].toLowerCase();\n            if (matches(name)) {\n                found.set(name, \"env\");\n            }\n        }\n\n        // 2. same-server scan (PostgreSQL)\n        const base = options.baseDb ?? context?.db;\n        if (base) {\n            const connectionString = String(base.config?.connectionString ?? \"\");\n            if (connectionString.startsWith(\"postgresql\")) {\n                const { rows } = await base.raw(\n                    \"SELECT datname FROM pg_database WHERE datistemplate = false\",\n                );\n                for (const { datname } of rows) {\n                    if (matches(datname) && !found.has(datname)) {\n                        found.set(datname, \"server\");\n                    }\n                }\n            } else {\n                context?.logger?.warn?.(\n                    \"[Db] discoverSiblings: server scan supported for PostgreSQL only; using env-declared siblings\",\n                );\n            }\n        }\n\n        return [...found]\n            .map(([name, origin]) => ({ name, origin }))\n            .sort((a, b) => a.name.localeCompare(b.name));\n    }\n\n    /**\n     * Discover + connect: one handler per active sibling (cached, pooled —\n     * see initSibling). Pass `includeMain: true` to get `[context.db, ...]`,\n     * which is the usual shape for \"apply this DDL everywhere\" loops:\n     *\n     *   const dbs = await Db.initAllSiblings(context, { prefix: \"src_\", includeMain: true });\n     *   await ensureSchemaEverywhere(dbs, spec, { logger: context.logger });\n     *\n     * @param {object} context\n     * @param {{ prefix?: string, match?: RegExp, includeMain?: boolean, baseDb?: object, env?: object }} options\n     * @returns {Promise<Function[]>} connected handlers\n     */\n    static async initAllSiblings(context, options = {}) {\n        const discovered = await Db.discoverSiblings(context, options);\n        const handlers = [];\n        for (const { name } of discovered) {\n            handlers.push(await Db.initSibling(context, name, options));\n        }\n        return options.includeMain && context.db ? [context.db, ...handlers] : handlers;\n    }\n\n    constructor(config) {\n        if (!config || !config.connectionString) {\n            throw new ParamError(\"Db: connectionString is required\");\n        }\n\n        this.knexInstance = null;\n        this.isConnected = false;\n        this.queriesLog = [];\n        this._reconnectPromise = null;\n        /** Set by disconnect(); blocks reconnect and connect so exit does not hang. */\n        this._closed = false;\n        /** Every knex client we created — reconnect can leave extras that disconnect must kill. */\n        this._liveKnex = new Set();\n        /** After a failed reconnect, skip further attempts until this timestamp. */\n        this._reconnectCooldownUntil = 0;\n        /** Shorter acquire timeout used only while reconnecting. */\n        this._reconnectAcquireTimeoutMs = null;\n\n        this.config = {\n            testConnection: true,\n            profile: false,\n            pool: { min: 0, max: 10, idleTimeoutMillis: 30_000 },\n            acquireConnectionTimeout: 10000,\n            ssl: { rejectUnauthorized: false },\n            logger: console,\n            ...config,\n        };\n\n        this.logger = this.config.logger;\n\n        const instance = this;\n        const callableWrapper = function () {\n            throw new Error(\"This should never be called directly\");\n        };\n        callableWrapper._instance = instance;\n\n        return new Proxy(callableWrapper, {\n            apply: (target, _thisArg, argumentsList) => {\n                const inst = target._instance;\n                if (!inst.knexInstance) {\n                    throw new Error(\"Db: Not connected. Call connect() first.\");\n                }\n                return inst.wrapQueryBuilder(inst.knexInstance(...argumentsList));\n            },\n            get: (target, prop) => {\n                if (prop === \"_instance\") {\n                    return target._instance;\n                }\n\n                const inst = target._instance;\n\n                const ownMethods = [\n                    \"connect\",\n                    \"disconnect\",\n                    \"reconnect\",\n                    \"testConnection\",\n                    \"tableExists\",\n                    \"raw\",\n                    \"withConnectionRetry\",\n                    \"isConnectionError\",\n                    \"getQueryLog\",\n                    \"getKnex\",\n                    \"isConnectedToDb\",\n                    \"getErrorMessage\",\n                    \"detectClient\",\n                    \"attachProfiler\",\n                ];\n\n                if (prop in inst) {\n                    const value = inst[prop];\n                    if (typeof value === \"function\" && ownMethods.includes(prop)) {\n                        return value.bind(inst);\n                    }\n                    if (typeof value !== \"function\") {\n                        return value;\n                    }\n                }\n\n                if (inst.knexInstance) {\n                    const knexProp = inst.knexInstance[prop];\n                    if (typeof knexProp === \"function\") {\n                        if (prop === \"raw\") {\n                            return (...args) => inst.raw(...args);\n                        }\n                        return knexProp.bind(inst.knexInstance);\n                    }\n                    return knexProp;\n                }\n\n                if (prop in inst) {\n                    const method = inst[prop];\n                    if (typeof method === \"function\") {\n                        return method.bind(inst);\n                    }\n                    return method;\n                }\n\n                return undefined;\n            },\n        });\n    }\n\n    detectClient(connectionString) {\n        if (connectionString.match(/^postgresql/)) {\n            return \"pg\";\n        }\n        if (connectionString.match(/^mysql/)) {\n            return \"mysql2\";\n        }\n        return null;\n    }\n\n    async connect() {\n        if (this._closed) {\n            throw new ParamError(\"Db: Connection closed\");\n        }\n        if (this.isConnected && this.knexInstance) {\n            this.logger.warn?.(\"[Db] Already connected\");\n            return;\n        }\n\n        const client = this.detectClient(this.config.connectionString);\n        if (!client) {\n            throw new ParamError(\n                \"Db: Cannot determine client type from connection string. Expected postgresql:// or mysql://\"\n            );\n        }\n\n        try {\n            const connectionConfig = {\n                connectionString: this.config.connectionString,\n                family: 4,\n            };\n\n            const acquireTimeout = this._reconnectAcquireTimeoutMs\n                ?? this.config.acquireConnectionTimeout;\n            this.knexInstance = knex({\n                client,\n                connection: connectionConfig,\n                pool: this.config.pool,\n                acquireConnectionTimeout: acquireTimeout,\n                ...(this.config.ssl && { ssl: this.config.ssl }),\n            });\n            this._liveKnex.add(this.knexInstance);\n            this.knexInstance.on?.(\"error\", (err) => {\n                if (this._closed) return;\n                this.logger.warn?.(\n                    `[Db] Connection error (${this.getErrorMessage(err)})`\n                );\n            });\n\n            if (this._closed) {\n                await this._destroyKnex(this.knexInstance, \"connect aborted (closed)\");\n                this.knexInstance = null;\n                throw new ParamError(\"Db: Connection closed\");\n            }\n\n            if (this.config.profile) {\n                this.attachProfiler();\n            }\n\n            if (this.config.testConnection) {\n                await this.testConnection();\n            }\n\n            if (this._closed) {\n                await this._destroyKnex(this.knexInstance, \"connect aborted (closed)\");\n                this.knexInstance = null;\n                throw new ParamError(\"Db: Connection closed\");\n            }\n\n            this.isConnected = true;\n            this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));\n        } catch (error) {\n            // Always tear down a half-open pool (e.g. testConnection ENOTFOUND),\n            // otherwise the next reconnect/disconnect waits on a dead knex forever.\n            const failed = this.knexInstance;\n            this.knexInstance = null;\n            this.isConnected = false;\n            if (failed) {\n                await this._destroyKnex(failed, \"connect failed\");\n            }\n            if (error instanceof ParamError) {\n                throw error;\n            }\n            const errorMsg = this.getErrorMessage(error);\n            throw new ParamError(`Db: Connection failed - ${errorMsg}`);\n        }\n    }\n\n    /**\n     * Destroy a knex pool without hanging exit on stuck TCP sockets (ETIMEDOUT).\n     * @param {import(\"knex\").Knex | null | undefined} knexInst\n     * @param {string} [reason]\n     * @param {number} [timeoutMs]\n     */\n    async _destroyKnex(knexInst, reason = \"destroy\", timeoutMs = 3_000) {\n        if (!knexInst || typeof knexInst.destroy !== \"function\") return;\n        this._liveKnex.delete(knexInst);\n        try {\n            await Promise.race([\n                knexInst.destroy(),\n                new Promise((_, reject) => {\n                    const t = setTimeout(\n                        () => reject(new Error(`Db: ${reason} timed out after ${timeoutMs}ms`)),\n                        timeoutMs,\n                    );\n                    t.unref?.();\n                }),\n            ]);\n        } catch (error) {\n            this.logger.debug?.(\n                `[Db] ${reason}: ${this.getErrorMessage(error)}`\n            );\n        }\n    }\n\n    async disconnect() {\n        this._closed = true;\n        this.isConnected = false;\n        this.knexInstance = null;\n        this.queriesLog = [];\n\n        // Do not await an in-flight reconnect — connect() may be stuck in\n        // testConnection / DNS for acquireConnectionTimeout (often 60s).\n        // Tear down every knex we created, including ones spawned mid-reconnect.\n        const all = [...this._liveKnex];\n        this._liveKnex.clear();\n        await Promise.all(all.map((inst) => this._destroyKnex(inst, \"disconnect\")));\n        if (all.length > 0) {\n            this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));\n        }\n    }\n\n    /**\n     * True when the error indicates a dead socket / pool that a fresh connect may fix.\n     * Safe to call as `Db.prototype.isConnectionError(err)` or via a connected handle.\n     */\n    isConnectionError(error) {\n        if (!error) {\n            return false;\n        }\n\n        if (error instanceof AggregateError && Array.isArray(error.errors)) {\n            return error.errors.some((e) => this.isConnectionError(e));\n        }\n\n        const code = error.code ?? error.errno;\n        if (code != null && CONNECTION_ERROR_CODES.has(String(code))) {\n            return true;\n        }\n\n        const msg = error instanceof Error ? error.message : String(error);\n        return CONNECTION_ERROR_MESSAGE_RE.test(msg);\n    }\n\n    /**\n     * Destroy the current knex pool and open a new one. Concurrent callers share one attempt.\n     * No-ops once disconnect() has closed the handle.\n     */\n    async reconnect() {\n        if (this._closed) {\n            return;\n        }\n        if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {\n            return;\n        }\n        if (this._reconnectPromise) {\n            await this._reconnectPromise;\n            return;\n        }\n\n        this._reconnectPromise = (async () => {\n            if (this._closed) return;\n\n            const old = this.knexInstance;\n            this.isConnected = false;\n            this.knexInstance = null;\n            this.queriesLog = [];\n\n            if (old) {\n                await this._destroyKnex(old, \"destroy during reconnect\");\n            }\n\n            if (this._closed) return;\n            // Don't inherit the caller's 60s acquire timeout while the host is down.\n            this._reconnectAcquireTimeoutMs = 3_000;\n            try {\n                await this.connect();\n                this._reconnectCooldownUntil = 0;\n            } catch (error) {\n                this._reconnectCooldownUntil = Date.now() + 5_000;\n                throw error;\n            } finally {\n                this._reconnectAcquireTimeoutMs = null;\n            }\n        })();\n\n        try {\n            await this._reconnectPromise;\n        } finally {\n            this._reconnectPromise = null;\n        }\n    }\n\n    async reconnectAfterConnectionError(error) {\n        if (this._closed) {\n            return;\n        }\n        if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {\n            return;\n        }\n        this.logger.warn?.(\n            `[Db] Connection lost (${this.getErrorMessage(error)}) — reconnecting…`\n        );\n        try {\n            await this.reconnect();\n        } catch {\n            // connect() already logged the test failure; caller retries or throws.\n        }\n    }\n\n    /**\n     * Run `fn`; on a connection error, reconnect once (by default) and retry `fn`.\n     * `fn` should look up `this.knexInstance` each call so the retry uses the new client.\n     */\n    async withConnectionRetry(fn, { retries = 1 } = {}) {\n        let lastError;\n        for (let attempt = 0; attempt <= retries; attempt++) {\n            try {\n                return await fn();\n            } catch (error) {\n                lastError = error;\n                if (this._closed || !this.isConnectionError(error) || attempt >= retries) {\n                    throw error;\n                }\n                await this.reconnectAfterConnectionError(error);\n                if (this._closed) {\n                    throw error;\n                }\n            }\n        }\n        throw lastError;\n    }\n\n    /**\n     * Wrap a knex QueryBuilder / Raw so that awaiting it retries once after reconnect\n     * when the first attempt dies with a connection error.\n     */\n    wrapQueryBuilder(builder) {\n        if (!builder || typeof builder.then !== \"function\" || builder.__dbReconnectWrapped) {\n            return builder;\n        }\n\n        builder.__dbReconnectWrapped = true;\n        const inst = this;\n        const protoThen = Object.getPrototypeOf(builder)?.then;\n        if (typeof protoThen !== \"function\") {\n            return builder;\n        }\n\n        builder.then = function (onFulfilled, onRejected) {\n            const run = async () => {\n                try {\n                    return await protoThen.call(builder);\n                } catch (error) {\n                    if (inst._closed || !inst.isConnectionError(error)) {\n                        throw error;\n                    }\n                    await inst.reconnectAfterConnectionError(error);\n                    if (inst._closed || !inst.knexInstance) {\n                        throw error;\n                    }\n\n                    if (typeof builder.clone === \"function\") {\n                        const retry = builder.clone();\n                        retry.client = inst.knexInstance.client;\n                        return await protoThen.call(retry);\n                    }\n\n                    if (typeof builder.toSQL === \"function\" && inst.knexInstance) {\n                        const sql = builder.toSQL();\n                        const statements = Array.isArray(sql) ? sql : [sql];\n                        let last;\n                        for (const stmt of statements) {\n                            last = await inst.knexInstance.raw(stmt.sql, stmt.bindings);\n                        }\n                        return last;\n                    }\n\n                    throw error;\n                }\n            };\n            return run().then(onFulfilled, onRejected);\n        };\n\n        return builder;\n    }\n\n    /** knex.raw with auto-reconnect on dead connections. */\n    raw(...args) {\n        if (!this.knexInstance) {\n            throw new Error(\"Db: Not connected. Call connect() first.\");\n        }\n        return this.wrapQueryBuilder(this.knexInstance.raw(...args));\n    }\n\n    getErrorMessage(error) {\n        if (error instanceof AggregateError) {\n            const errors = error.errors || [];\n\n            if (errors.length > 0) {\n                const firstError = errors[0];\n                const firstErrorMsg =\n                    firstError instanceof Error ? firstError.message : String(firstError);\n\n                const allSimilar = errors.every((e) => {\n                    const msg = e instanceof Error ? e.message : String(e);\n                    const codeMatch = msg.match(/^(\\w+)\\s/);\n                    const firstCodeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n                    return codeMatch && firstCodeMatch && codeMatch[1] === firstCodeMatch[1];\n                });\n\n                if (allSimilar && errors.length > 1) {\n                    const addresses = errors\n                        .map((e) => {\n                            const msg = e instanceof Error ? e.message : String(e);\n                            const addrMatch = msg.match(/([:\\d.]+:\\d+)/);\n                            return addrMatch ? addrMatch[1] : null;\n                        })\n                        .filter(Boolean);\n\n                    if (addresses.length > 0) {\n                        const codeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n                        const code = codeMatch ? codeMatch[1] : \"Connection error\";\n                        return `${code} (tried: ${addresses.join(\", \")})`;\n                    }\n                }\n\n                const uniqueMessages = [\n                    ...new Set(\n                        errors.map((e) => (e instanceof Error ? e.message : String(e)))\n                    ),\n                ];\n\n                if (uniqueMessages.length === 1) {\n                    return uniqueMessages[0];\n                }\n\n                return uniqueMessages.join(\"; \");\n            }\n\n            return error.message || \"Multiple errors occurred\";\n        }\n\n        if (error instanceof Error) {\n            const code = error.code;\n            if (code) {\n                return `${code}: ${error.message || String(error)}`;\n            }\n            return error.message || String(error);\n        }\n\n        if (typeof error === \"string\") {\n            return error;\n        }\n\n        if (error && typeof error === \"object\" && \"message\" in error) {\n            const msg = String(error.message);\n            const code = error.code;\n            if (code) {\n                return `${code}: ${msg}`;\n            }\n            return msg;\n        }\n\n        return String(error) || \"Unknown error\";\n    }\n\n    async testConnection() {\n        if (!this.knexInstance) {\n            throw new Error(\"Db: Not connected. Call connect() first.\");\n        }\n\n        try {\n            const result = await this.knexInstance.raw(\"SELECT 2+3 AS result\");\n            const isOk = result.rows?.[0]?.result === 5 || result[0]?.[0]?.result === 5;\n            this.logger.debug?.(`[Db] Connection test: ${isOk ? \"OK\" : \"FAILED\"}`);\n            return isOk;\n        } catch (error) {\n            const errorMsg = this.getErrorMessage(error);\n            this.logger.error?.(`[Db] Connection test failed: ${errorMsg}`);\n            throw new ParamError(`Db: Connection test failed - ${errorMsg}`);\n        }\n    }\n\n    attachProfiler() {\n        if (!this.knexInstance) {\n            return;\n        }\n\n        this.queriesLog = [];\n        this.knexInstance.queriesLog = this.queriesLog;\n\n        // Knex emits fresh Object.assign(...) copies on \"query\" and \"query-response\",\n        // so __startTime on the query object does not survive — track per-connection FIFO.\n        const startsByConnection = new Map();\n\n        const pushStart = (query) => {\n            const uid = query?.__knexUid ?? \"\";\n            if (!startsByConnection.has(uid)) {\n                startsByConnection.set(uid, []);\n            }\n            startsByConnection.get(uid).push(process.hrtime());\n        };\n\n        const popStart = (query) => {\n            const uid = query?.__knexUid ?? \"\";\n            const stack = startsByConnection.get(uid);\n            if (!stack?.length) {\n                return null;\n            }\n            return stack.pop();\n        };\n\n        const isTimeoutError = (error) =>\n            error?.name === \"KnexTimeoutError\" ||\n            /query timeout|timeout exceeded/i.test(String(error?.message ?? \"\"));\n\n        const logQueryEntry = (query, start, { error } = {}) => {\n            let executionTimeMs;\n            if (start) {\n                const [seconds, nanoseconds] = process.hrtime(start);\n                executionTimeMs = (seconds * 1000 + nanoseconds / 1e6).toFixed(2);\n            } else if (error?.timeout != null) {\n                executionTimeMs = Number(error.timeout).toFixed(2);\n            } else {\n                executionTimeMs = \"?\";\n            }\n\n            let status = \"ok\";\n            if (error) {\n                status = isTimeoutError(error) ? \"timeout\" : \"error\";\n            }\n\n            const logEntry = {\n                sql: query?.sql,\n                bindings: query?.bindings || [],\n                executionTimeMs,\n                status,\n            };\n            if (error) {\n                logEntry.error = error.message ?? String(error);\n            }\n\n            this.queriesLog.push(logEntry);\n            const suffix = error ? ` | ${status}: ${logEntry.error}` : \"\";\n            this.logger.debug?.(\n                `[Db] Query: ${query?.sql} | Duration: ${executionTimeMs}ms${suffix}`,\n            );\n        };\n\n        const handleQueryError = (error, query) => {\n            const start = popStart(query);\n            logQueryEntry(query, start, { error });\n            this.logger.error?.(`[Db] Query failed: ${query?.sql}`, error);\n        };\n\n        this.knexInstance.on(\"query\", (query) => {\n            pushStart(query);\n        });\n\n        this.knexInstance.on(\"query-response\", (_response, query) => {\n            const start = popStart(query);\n            if (!start) {\n                return;\n            }\n            logQueryEntry(query, start);\n        });\n\n        this.knexInstance.on(\"query-error\", (error, query) => {\n            handleQueryError(error, query);\n        });\n\n        // Builder queries emit \"query\" / \"query-error\" on the builder, not always on client.\n        const hookBuilder = (builder) => {\n            if (!builder || builder.__dbProfilerHooked) {\n                return;\n            }\n            builder.__dbProfilerHooked = true;\n            builder.on(\"query\", pushStart);\n            builder.on(\"query-error\", handleQueryError);\n        };\n\n        const client = this.knexInstance.client;\n        if (client && !client.__dbProfilerPatched) {\n            client.__dbProfilerPatched = true;\n            if (typeof client.queryBuilder === \"function\") {\n                const origQueryBuilder = client.queryBuilder.bind(client);\n                client.queryBuilder = (...args) => {\n                    const builder = origQueryBuilder(...args);\n                    hookBuilder(builder);\n                    return builder;\n                };\n            }\n        }\n    }\n\n    getQueryLog() {\n        return [...this.queriesLog];\n    }\n\n    async tableExists(tableName) {\n        if (!this.knexInstance) {\n            throw new Error(\"Db: Not connected. Call connect() first.\");\n        }\n\n        try {\n            return await this.withConnectionRetry(() =>\n                this.knexInstance.schema.hasTable(tableName)\n            );\n        } catch (error) {\n            this.logger.error?.(`[Db] Error checking table existence: ${error.message}`);\n            throw error;\n        }\n    }\n\n    getKnex() {\n        if (!this.knexInstance) {\n            throw new Error(\"Db: Not connected. Call connect() first.\");\n        }\n        return this.knexInstance;\n    }\n\n    isConnectedToDb() {\n        return this.isConnected && this.knexInstance !== null;\n    }\n}\n\nfunction capitalizeFirstLetter(str) {\n    return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * The main database handler, for initSibling's fallbacks: the base handle when\n * one was passed, otherwise `context.db` (initialized on demand, so an\n * initSibling-only script still works).\n */\nasync function resolveMainHandler(context, options = {}) {\n    if (options.baseDb) {\n        return options.baseDb;\n    }\n    if (!context.db) {\n        context.db = await Db.init(context);\n    }\n    return context.db;\n}\n\n/**\n * Does `databaseName` exist on the base server? Checked via an existing handle\n * when available (no extra connection), else a short-lived one. Non-PostgreSQL\n * bases skip the check (returns true — connection will tell).\n */\nasync function databaseExistsOnServer(baseHandle, baseConnectionString, databaseName) {\n    if (!String(baseConnectionString).startsWith(\"postgresql\")) {\n        return true;\n    }\n    const query = \"SELECT 1 FROM pg_database WHERE datname = ?\";\n    if (baseHandle) {\n        const { rows } = await baseHandle.raw(query, [databaseName]);\n        return rows.length > 0;\n    }\n    const shortLived = knex({\n        client: \"pg\",\n        connection: { connectionString: baseConnectionString },\n        pool: { min: 0, max: 1 },\n    });\n    try {\n        const { rows } = await shortLived.raw(query, [databaseName]);\n        return rows.length > 0;\n    } finally {\n        await shortLived.destroy();\n    }\n}\n\n/**\n * Database name → camelCase param suffix: \"src_bright\" → \"SrcBright\",\n * so the override param becomes dbConnectionStringSibSrcBright\n * (env DB_CONNECTION_STRING_SIB_SRC_BRIGHT).\n */\nfunction camelizeDbName(name) {\n    return name\n        .split(/[_-]+/)\n        .filter(Boolean)\n        .map(capitalizeFirstLetter)\n        .join(\"\");\n}\n\n/** camelCase param name → its SNAKE_CASE env var (for error messages only). */\nfunction toEnvKey(key) {\n    return key.replace(/([A-Z])/g, \"_$1\").toUpperCase();\n}\n\n/**\n * Replace the database name in a connection string, keeping everything else\n * (credentials, host, port, query options like sslmode) intact.\n * Exported for reuse (e.g. database-splitting tools) and tests.\n */\nexport function replaceDatabaseName(connectionString, databaseName) {\n    let url;\n    try {\n        url = new URL(connectionString);\n    } catch {\n        throw new ParamError(\n            `Db: cannot parse connection string to derive a sibling database from it`\n        );\n    }\n    url.pathname = `/${databaseName}`;\n    return url.toString();\n}\n\nfunction resolveDbDisplayName(dbName, connectionParam, argsEnv, mergedName) {\n    if (dbName) {\n        return dbName;\n    }\n    if (mergedName) {\n        return mergedName;\n    }\n    if (\n        connectionParam?.startsWith(\"dbConnectionString\") &&\n        connectionParam.length > \"dbConnectionString\".length\n    ) {\n        return connectionParam.slice(\"dbConnectionString\".length).toLowerCase();\n    }\n    if (connectionParam === \"dbConnectionString\" && argsEnv) {\n        return argsEnv;\n    }\n    return undefined;\n}\n\nfunction formatDbConnectMessage(name, connectionString) {\n    const endpointSuffix = formatConnectionEndpointSuffix(connectionString);\n    if (name) {\n        return `[Db] Connected to database \"${name}\"${endpointSuffix}`;\n    }\n    return `[Db] Connected${endpointSuffix}`;\n}\n\nfunction formatDbDisconnectMessage(name, connectionString) {\n    const endpointSuffix = formatConnectionEndpointSuffix(connectionString);\n    if (name) {\n        return `[Db] Disconnected from database \"${name}\"${endpointSuffix}`;\n    }\n    return `[Db] Disconnected${endpointSuffix}`;\n}\n\nfunction formatDbInstanceMessage(action, name) {\n    if (name) {\n        return `[Db] instance \"${name}\" ${action}`;\n    }\n    return `[Db] instance ${action}`;\n}\n\nfunction formatConnectionEndpointSuffix(connectionString) {\n    const endpoint = formatConnectionEndpoint(connectionString);\n    return endpoint ? ` (${endpoint})` : \"\";\n}\n\nfunction formatConnectionEndpoint(connectionString) {\n    try {\n        const url = new URL(connectionString);\n        const host = url.hostname;\n        if (!host) {\n            return null;\n        }\n\n        let port = url.port;\n        if (!port) {\n            if (url.protocol === \"postgresql:\") {\n                port = \"5432\";\n            } else if (url.protocol === \"mysql:\") {\n                port = \"3306\";\n            }\n        }\n\n        return port ? `${host}:${port}` : host;\n    } catch {\n        return null;\n    }\n}\n\nasync function dbConnect(context, config) {\n    try {\n        const db = new Db(config);\n\n        context.registerCleanup(async () => {\n            await db.disconnect();\n            context.logger.debug?.(formatDbInstanceMessage(\"disconnected\", config.name));\n        });\n\n        await db.connect();\n\n        context.logger.debug?.(formatDbInstanceMessage(\"initialized\", config.name));\n\n        return db;\n    } catch (error) {\n        if (error instanceof ParamError) {\n            throw error;\n        }\n        const errorMsg = error instanceof Error ? error.message : String(error);\n        throw new ParamError(`[Db] connect error: ${errorMsg}`);\n    }\n}\n","/**\n * Declarative, idempotent DDL — \"make sure this schema exists\" helpers.\n *\n * Components describe the schema they need (tables, columns, indexes,\n * extensions) once, as data; `ensureSchema` diffs that spec against a live\n * database and applies only what's missing:\n *\n *   - table missing            → CREATE TABLE with all columns + indexes\n *   - table there, column not  → ALTER TABLE ADD COLUMN (never drops/changes)\n *   - index/unique missing     → CREATE [UNIQUE] INDEX IF NOT EXISTS\n *   - extension missing        → CREATE EXTENSION IF NOT EXISTS\n *\n * Because the input is a spec (not imperative code), the same call can be\n * repeated over any number of databases — the main one and every sibling —\n * and each gets exactly the DDL it lacks. See Db.initSibling /\n * Db.discoverSiblings for getting those handles.\n *\n * Spec shape:\n *\n *   {\n *       extensions: [\"uuid-ossp\"],\n *       tables: {\n *           my_table: {\n *               columns: {\n *                   id:   (t, db) => t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\")),\n *                   name: (t) => t.text(\"name\").notNullable(),\n *               },\n *               indexes: [\n *                   { columns: [\"name\"], name: \"my_table_name_idx\" },\n *                   { columns: [\"a\", \"b\"], name: \"my_table_ab_uniq\", unique: true },\n *               ],\n *           },\n *       },\n *   }\n *\n * Every function accepts `{ dryRun: true }` and then only *reports* what it\n * would do (returned in the report, logged when a logger is given) without\n * touching the database.\n */\n\n/** @typedef {{ columns: Record<string, Function>, indexes?: Array<{ columns: string[], name: string, unique?: boolean }> }} TableSpec */\n/** @typedef {{ extensions?: string[], tables?: Record<string, TableSpec> }} SchemaSpec */\n\nconst dbLabel = (db) => db?.config?.name ?? \"db\";\n\n/**\n * CREATE EXTENSION IF NOT EXISTS (PostgreSQL). No-op report entry on dryRun.\n *\n * @param {Function} db - a connected Db/knex handle\n * @param {string} name - extension name, e.g. \"uuid-ossp\"\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<{ action: string }>}\n */\nexport async function ensureExtension(db, name, options = {}) {\n    const action = `CREATE EXTENSION IF NOT EXISTS \"${name}\"`;\n    if (!options.dryRun) {\n        await db.raw(action);\n    }\n    options.logger?.silly?.(`[ensure] ${dbLabel(db)}: ${action}${options.dryRun ? \" (dryRun)\" : \"\"}`);\n    return { action };\n}\n\n/**\n * Create a table when missing; when it exists, add any missing columns and\n * indexes from the spec. Never drops or alters existing columns.\n *\n * @param {Function} db\n * @param {string} tableName\n * @param {TableSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<string[]>} human-readable list of applied (or planned) DDL\n */\nexport async function ensureTable(db, tableName, spec, options = {}) {\n    const { dryRun = false, logger } = options;\n    const actions = [];\n    const exists = await db.tableExists(tableName);\n\n    if (!exists) {\n        actions.push(`CREATE TABLE ${tableName} (${Object.keys(spec.columns).length} columns)`);\n        if (!dryRun) {\n            await db.schema.createTable(tableName, (t) => {\n                for (const define of Object.values(spec.columns)) {\n                    define(t, db);\n                }\n            });\n        }\n    } else {\n        // Column-level ensure: add whatever the spec has that the table lacks.\n        const missing = [];\n        for (const column of Object.keys(spec.columns)) {\n            if (!(await db.schema.hasColumn(tableName, column))) {\n                missing.push(column);\n            }\n        }\n        if (missing.length > 0) {\n            actions.push(`ALTER TABLE ${tableName} ADD COLUMN ${missing.join(\", \")}`);\n            if (!dryRun) {\n                await db.schema.alterTable(tableName, (t) => {\n                    for (const column of missing) {\n                        spec.columns[column](t, db);\n                    }\n                });\n            }\n        }\n    }\n\n    for (const index of spec.indexes ?? []) {\n        const indexActions = await ensureIndex(db, tableName, index, options);\n        actions.push(...indexActions);\n    }\n\n    for (const action of actions) {\n        logger?.silly?.(`[ensure] ${dbLabel(db)}: ${action}${dryRun ? \" (dryRun)\" : \"\"}`);\n    }\n    return actions;\n}\n\n/**\n * Ensure a (unique) index exists. On PostgreSQL this is a real existence check\n * (`CREATE [UNIQUE] INDEX IF NOT EXISTS`); other dialects fall back to\n * attempt-and-tolerate-\"already exists\".\n *\n * @param {Function} db\n * @param {string} tableName\n * @param {{ columns: string[], name: string, unique?: boolean }} index\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<string[]>}\n */\nexport async function ensureIndex(db, tableName, index, options = {}) {\n    const { dryRun = false } = options;\n    const kind = index.unique ? \"UNIQUE INDEX\" : \"INDEX\";\n    const cols = index.columns.map((c) => `\"${c}\"`).join(\", \");\n    const isPg = String(db?.config?.connectionString ?? \"\").startsWith(\"postgresql\");\n\n    if (isPg) {\n        const sql = `CREATE ${kind} IF NOT EXISTS \"${index.name}\" ON \"${tableName}\" (${cols})`;\n        const { rows } = await db.raw(`SELECT 1 FROM pg_indexes WHERE indexname = ?`, [index.name]);\n        if (rows.length > 0) return [];\n        if (!dryRun) await db.raw(sql);\n        return [sql];\n    }\n\n    // Non-pg fallback: try, and treat \"already exists\" as success.\n    const sql = `CREATE ${kind} ${index.name} ON ${tableName} (${cols})`;\n    if (!dryRun) {\n        try {\n            await db.raw(sql);\n        } catch (error) {\n            if (!/already exists|duplicate/i.test(error?.message ?? \"\")) throw error;\n            return [];\n        }\n    }\n    return [sql];\n}\n\n/**\n * Apply a full schema spec to ONE database. Returns the list of applied\n * (or, with dryRun, planned) DDL statements — empty when everything is\n * already in place.\n *\n * @param {Function} db\n * @param {SchemaSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<{ database: string, actions: string[] }>}\n */\nexport async function ensureSchema(db, spec, options = {}) {\n    const actions = [];\n    for (const extension of spec.extensions ?? []) {\n        // Extensions are cheap no-ops when present; report only in dryRun.\n        const { action } = await ensureExtension(db, extension, options);\n        if (options.dryRun) actions.push(action);\n    }\n    for (const [tableName, tableSpec] of Object.entries(spec.tables ?? {})) {\n        actions.push(...(await ensureTable(db, tableName, tableSpec, options)));\n    }\n    return { database: dbLabel(db), actions };\n}\n\n/**\n * Apply a schema spec to MANY databases (e.g. the main DB plus every sibling).\n * Convenience loop over {@link ensureSchema} with a combined report and\n * per-database info logging.\n *\n * @param {Function[]} dbs - connected handles (see Db.initAllSiblings)\n * @param {SchemaSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<Array<{ database: string, actions: string[] }>>}\n */\nexport async function ensureSchemaEverywhere(dbs, spec, options = {}) {\n    const reports = [];\n    for (const db of dbs) {\n        const report = await ensureSchema(db, spec, options);\n        if (report.actions.length > 0) {\n            options.logger?.info?.(\n                `[ensure] ${report.database}: ${options.dryRun ? \"would apply\" : \"applied\"} ${report.actions.length} DDL statement(s)`,\n            );\n        }\n        reports.push(report);\n    }\n    return reports;\n}\n","/**\n * S3 component\n *\n * Thin async wrapper over @aws-sdk/client-s3 v3 with the cli-toolkit conventions:\n *   const s3 = await S3.init(context);\n *\n * Supports multiple \"profiles\" (local, production, stage, …) selected at runtime\n * via `--bucket=<profile>` (or `BUCKET` / env-suffixed `BUCKET_LOCAL`,\n * `BUCKET_PRODUCTION`). Each profile has its own set of parameters resolved by\n * the framework, mirroring how `Db.init` uses `dbName` → `dbConnectionString${Name}`.\n *\n * Profile selector (often driven by `--env` / `ENV` via Args env-suffixes):\n *   --bucket=local         (default when env=local)\n *   --bucket=production    (default when ENV=production and BUCKET_PRODUCTION=production)\n *   --bucket=stage\n *\n * Per-profile parameters (CLI / env / .env — see @nmakarov/cli-toolkit/params):\n *   s3Bucket{Profile}            string   required  (S3_BUCKET_LOCAL, S3_BUCKET_PRODUCTION, …)\n *   s3Region{Profile}            string   default us-east-1\n *   s3Endpoint{Profile}          string   optional (MinIO/local; unset = real AWS)\n *   s3ForcePathStyle{Profile}    boolean  default false (true for MinIO)\n *   s3AccessKeyId{Profile}       string   optional (omit on EC2 for instance profile)\n *   s3SecretAccessKey{Profile}   string   optional\n *\n * Example (.env — all profiles in one file):\n *   BUCKET_LOCAL=local\n *   BUCKET_PRODUCTION=production\n *   S3_BUCKET_LOCAL=photos-local\n *   S3_REGION_LOCAL=us-east-1\n *   S3_ENDPOINT_LOCAL=http://localhost:9000\n *   S3_FORCE_PATH_STYLE_LOCAL=true\n *   S3_ACCESS_KEY_ID_LOCAL=dev\n *   S3_SECRET_ACCESS_KEY_LOCAL=devdevdev\n *   S3_BUCKET_PRODUCTION=photos-everystate-prod\n *   S3_REGION_PRODUCTION=ca-central-1\n *   …\n */\n\nimport {\n    S3Client,\n    HeadBucketCommand,\n    HeadObjectCommand,\n    GetObjectCommand,\n    PutObjectCommand,\n    DeleteObjectCommand,\n    CopyObjectCommand,\n    ListObjectsV2Command,\n    PutObjectTaggingCommand,\n    GetObjectTaggingCommand,\n} from \"@aws-sdk/client-s3\";\n\nimport { ParamError } from \"../errors.js\";\n\nconst DEFAULT_PROFILE = \"local\";\n\nfunction capitalize(str) {\n    if (!str) return str;\n    return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nexport class S3 {\n    /**\n     * Build an S3 instance. Reads bucket profile from --bucket (default \"local\"),\n     * then resolves per-profile params, builds the SDK client, and returns the\n     * instance. Optionally pings the bucket once to verify reachability.\n     */\n    static async init(context, options = {}) {\n        const profileDef = { bucket: \"string\" };\n        const discovered = context?.params?.getAllForModule?.(\"s3\", profileDef) ?? {};\n        const profile = options.bucket ?? discovered.bucket ?? DEFAULT_PROFILE;\n        const cap = capitalize(profile);\n\n        const config = {\n            profile,\n            bucketName: options.bucketName\n                ?? await context.params.get(`s3Bucket${cap}`, \"string\"),\n            region: options.region\n                ?? await context.params.get(`s3Region${cap}`, \"string default us-east-1\"),\n            endpoint: options.endpoint\n                ?? await context.params.get(`s3Endpoint${cap}`, \"string\"),\n            forcePathStyle: options.forcePathStyle\n                ?? await context.params.get(`s3ForcePathStyle${cap}`, \"boolean default false\"),\n            accessKeyId: options.accessKeyId\n                ?? await context.params.get(`s3AccessKeyId${cap}`, \"string\"),\n            secretAccessKey: options.secretAccessKey\n                ?? await context.params.get(`s3SecretAccessKey${cap}`, \"string\"),\n        };\n\n        if (!config.bucketName) {\n            throw new ParamError(\n                `S3: bucket name not configured for profile \"${profile}\" `\n                + `(set s3Bucket${cap} or S3_BUCKET_${profile.toUpperCase()})`\n            );\n        }\n\n        const s3 = new S3(context, config);\n\n        if (options.testBucket !== false) {\n            try {\n                await s3.bucketExists();\n                context.logger?.debug?.(\n                    `[S3] profile=\"${profile}\" bucket=\"${config.bucketName}\" reachable`\n                );\n            } catch (err) {\n                context.logger?.warn?.(\n                    `[S3] profile=\"${profile}\" bucket=\"${config.bucketName}\" `\n                    + `reachability test failed: ${err?.message ?? err}`\n                );\n            }\n        }\n\n        return s3;\n    }\n\n    constructor(context, config) {\n        this.logger = context?.logger ?? console;\n        this.profile = config.profile;\n        this.bucketName = config.bucketName;\n        this.region = config.region;\n        this.endpoint = config.endpoint || null;\n\n        const clientConfig = { region: config.region };\n        if (config.endpoint) clientConfig.endpoint = config.endpoint;\n        if (config.forcePathStyle) clientConfig.forcePathStyle = true;\n        if (config.accessKeyId && config.secretAccessKey) {\n            clientConfig.credentials = {\n                accessKeyId: config.accessKeyId,\n                secretAccessKey: config.secretAccessKey,\n            };\n        }\n\n        // Silence the AWS SDK v3 \"node >=22 required after Jan 2027\" notice on\n        // older Node. Honors an explicit env value if the user already set one.\n        process.env.AWS_SDK_JS_NODE_VERSION_SUPPORT_WARNING_DISABLED ??= \"true\";\n\n        this.client = new S3Client(clientConfig);\n    }\n\n    // ── info ────────────────────────────────────────────────────────────────\n    getBucketName() { return this.bucketName; }\n    getProfile()    { return this.profile; }\n    getRegion()     { return this.region; }\n    getEndpoint()   { return this.endpoint; }\n\n    // ── reachability ────────────────────────────────────────────────────────\n    async bucketExists() {\n        await this.client.send(new HeadBucketCommand({ Bucket: this.bucketName }));\n        return true;\n    }\n\n    // ── HEAD / GET ──────────────────────────────────────────────────────────\n    /** Returns null on 404; never throws for \"missing\". Other errors throw. */\n    async headObject(key) {\n        try {\n            const out = await this.client.send(new HeadObjectCommand({\n                Bucket: this.bucketName,\n                Key: key,\n            }));\n            return {\n                etag: out.ETag,\n                size: out.ContentLength,\n                contentType: out.ContentType,\n                lastModified: out.LastModified,\n                metadata: out.Metadata,\n                storageClass: out.StorageClass,\n            };\n        } catch (err) {\n            if (this._isNotFound(err)) return null;\n            throw err;\n        }\n    }\n\n    /** Returns { body: Readable, contentType, contentLength, etag, ... } or null on 404. */\n    async getObject(key) {\n        try {\n            const out = await this.client.send(new GetObjectCommand({\n                Bucket: this.bucketName,\n                Key: key,\n            }));\n            return {\n                body: out.Body,\n                contentType: out.ContentType,\n                contentLength: out.ContentLength,\n                etag: out.ETag,\n                lastModified: out.LastModified,\n                metadata: out.Metadata,\n            };\n        } catch (err) {\n            if (this._isNotFound(err)) return null;\n            throw err;\n        }\n    }\n\n    /** Buffers the whole object. Use only for small objects (manifests, JSON). */\n    async getObjectBytes(key) {\n        const obj = await this.getObject(key);\n        if (!obj) return null;\n        const chunks = [];\n        for await (const chunk of obj.body) chunks.push(chunk);\n        return { ...obj, body: Buffer.concat(chunks) };\n    }\n\n    /** Convenience for JSON manifests. Returns parsed object or null on 404. */\n    async getJson(key) {\n        const obj = await this.getObjectBytes(key);\n        if (!obj) return null;\n        return JSON.parse(obj.body.toString(\"utf8\"));\n    }\n\n    // ── PUT ─────────────────────────────────────────────────────────────────\n    async putObject({ key, body, contentType, contentLength, tags, metadata }) {\n        const cmd = new PutObjectCommand({\n            Bucket: this.bucketName,\n            Key: key,\n            Body: body,\n            ...(contentType && { ContentType: contentType }),\n            ...(contentLength != null && { ContentLength: contentLength }),\n            ...(metadata && { Metadata: metadata }),\n            ...(tags && { Tagging: this._tagsToQuery(tags) }),\n        });\n        return this.client.send(cmd);\n    }\n\n    /** Convenience for JSON manifests. */\n    async putJson(key, value, opts = {}) {\n        const json = JSON.stringify(value, null, opts.pretty ? 2 : 0);\n        const body = Buffer.from(json, \"utf8\");\n        return this.putObject({\n            key,\n            body,\n            contentType: \"application/json\",\n            contentLength: body.length,\n            tags: opts.tags,\n            metadata: opts.metadata,\n        });\n    }\n\n    // ── DELETE ──────────────────────────────────────────────────────────────\n    async deleteObject(key) {\n        return this.client.send(new DeleteObjectCommand({\n            Bucket: this.bucketName,\n            Key: key,\n        }));\n    }\n\n    // ── COPY (for migration: legacy → new bucket, or intra-bucket \"rename\") ─\n    async copyObject({ sourceBucket, sourceKey, key, contentType, metadata, tags }) {\n        const src = sourceBucket || this.bucketName;\n        const cmd = new CopyObjectCommand({\n            Bucket: this.bucketName,\n            Key: key,\n            CopySource: encodeURIComponent(`${src}/${sourceKey}`),\n            ...(contentType && {\n                ContentType: contentType,\n                MetadataDirective: \"REPLACE\",\n            }),\n            ...(metadata && {\n                Metadata: metadata,\n                MetadataDirective: \"REPLACE\",\n            }),\n            ...(tags && {\n                Tagging: this._tagsToQuery(tags),\n                TaggingDirective: \"REPLACE\",\n            }),\n        });\n        return this.client.send(cmd);\n    }\n\n    // ── LIST ────────────────────────────────────────────────────────────────\n    async listObjects(prefix, { keysOnly = false, maxKeys = 1000, continuationToken } = {}) {\n        const out = await this.client.send(new ListObjectsV2Command({\n            Bucket: this.bucketName,\n            Prefix: prefix,\n            MaxKeys: maxKeys,\n            ContinuationToken: continuationToken,\n        }));\n        const items = (out.Contents ?? []).map(o => ({\n            key: o.Key,\n            size: o.Size,\n            etag: o.ETag,\n            lastModified: o.LastModified,\n            storageClass: o.StorageClass,\n        }));\n        return {\n            items: keysOnly ? items.map(i => i.key) : items,\n            isTruncated: !!out.IsTruncated,\n            nextContinuationToken: out.NextContinuationToken,\n        };\n    }\n\n    // ── TAGS (used for lifecycle rules, e.g. status=closed → Glacier IR) ────\n    async putObjectTagging(key, tags) {\n        return this.client.send(new PutObjectTaggingCommand({\n            Bucket: this.bucketName,\n            Key: key,\n            Tagging: { TagSet: this._tagsToTagSet(tags) },\n        }));\n    }\n\n    async getObjectTagging(key) {\n        const out = await this.client.send(new GetObjectTaggingCommand({\n            Bucket: this.bucketName,\n            Key: key,\n        }));\n        const tags = {};\n        for (const t of out.TagSet ?? []) tags[t.Key] = t.Value;\n        return tags;\n    }\n\n    // ── internals ───────────────────────────────────────────────────────────\n    _isNotFound(err) {\n        const status = err?.$metadata?.httpStatusCode;\n        return status === 404\n            || err?.name === \"NotFound\"\n            || err?.name === \"NoSuchKey\"\n            || err?.Code === \"NoSuchKey\";\n    }\n\n    _tagsToQuery(tags) {\n        return Object.entries(tags)\n            .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)\n            .join(\"&\");\n    }\n\n    _tagsToTagSet(tags) {\n        return Object.entries(tags).map(([Key, Value]) => ({ Key, Value: String(Value) }));\n    }\n}\n","/**\n * AWS discovery component\n *\n * A thin, read-only wrapper over a few AWS SDK v3 clients (STS, EC2, Route53)\n * with cli-toolkit conventions:\n *\n *   const aws = await Aws.init(context);\n *   const me  = await aws.whoAmI();\n *   const zones = await aws.listHostedZones();\n *\n * The whole point: given just an access key + secret (usually from .env), it can\n * *discover* the boring-to-look-up bits of an AWS account (account id, regions,\n * VPCs, subnets, security groups, key pairs, Route53 hosted zones, the latest\n * Ubuntu AMI) so scripts can pre-fill config (e.g. a terraform.tfvars) instead of\n * making you hunt through the console.\n *\n * Credentials + region are resolved via context.params, so they come from CLI,\n * env, or .env transparently:\n *   awsAccessKeyId      -> AWS_ACCESS_KEY_ID\n *   awsSecretAccessKey  -> AWS_SECRET_ACCESS_KEY\n *   awsSessionToken     -> AWS_SESSION_TOKEN      (optional, for temp creds)\n *   awsRegion           -> AWS_REGION             (default us-east-1)\n *\n * If no explicit keys are found, the SDK's default credential chain is used\n * (shared config/profile, instance role, etc.) — so AWS_PROFILE also works.\n *\n * Everything here is read-only (Describe / List / Get calls). It never mutates AWS.\n */\n\nimport {\n    STSClient,\n    GetCallerIdentityCommand,\n} from \"@aws-sdk/client-sts\";\nimport {\n    EC2Client,\n    DescribeRegionsCommand,\n    DescribeAvailabilityZonesCommand,\n    DescribeVpcsCommand,\n    DescribeSubnetsCommand,\n    DescribeSecurityGroupsCommand,\n    DescribeKeyPairsCommand,\n    DescribeImagesCommand,\n} from \"@aws-sdk/client-ec2\";\nimport {\n    Route53Client,\n    ListHostedZonesCommand,\n} from \"@aws-sdk/client-route-53\";\n\nconst DEFAULT_REGION = \"us-east-1\";\nconst CANONICAL_OWNER_ID = \"099720109477\"; // Ubuntu images\nconst DEFAULT_UBUNTU_PATTERN = \"ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*\";\n\nfunction nameTag(tags) {\n    const t = (tags ?? []).find(x => x.Key === \"Name\");\n    return t?.Value ?? null;\n}\n\nexport class Aws {\n    /**\n     * Resolve credentials/region from params and return an Aws instance.\n     * Does not call AWS until you invoke a method (clients are lazy).\n     */\n    static async init(context, options = {}) {\n        // Tolerate blank/missing values (e.g. an env var present but empty, like\n        // a half-filled .env): treat them as \"not set\" rather than failing param\n        // validation, so we fall back cleanly to the SDK default credential chain.\n        const getOpt = async (k) => {\n            try {\n                const v = await context?.params?.get?.(k, \"string\");\n                return v != null && String(v).trim() !== \"\" ? v : undefined;\n            } catch {\n                return undefined;\n            }\n        };\n\n        const config = {\n            region: options.region ?? (await getOpt(\"awsRegion\")) ?? DEFAULT_REGION,\n            accessKeyId: options.accessKeyId ?? (await getOpt(\"awsAccessKeyId\")),\n            secretAccessKey: options.secretAccessKey ?? (await getOpt(\"awsSecretAccessKey\")),\n            sessionToken: options.sessionToken ?? (await getOpt(\"awsSessionToken\")),\n        };\n\n        const aws = new Aws(context, config);\n        context?.logger?.debug?.(\n            `[aws] region=${config.region} credentials=${config.accessKeyId ? \"explicit\" : \"default-chain\"}`,\n        );\n        return aws;\n    }\n\n    constructor(context, config) {\n        this.logger = context?.logger ?? console;\n        this.region = config.region || DEFAULT_REGION;\n\n        // Build an explicit credentials object only when keys were supplied;\n        // otherwise leave undefined so the SDK uses its default chain (profile,\n        // instance role, env, …).\n        this._credentials = config.accessKeyId && config.secretAccessKey\n            ? {\n                accessKeyId: config.accessKeyId,\n                secretAccessKey: config.secretAccessKey,\n                ...(config.sessionToken ? { sessionToken: config.sessionToken } : {}),\n            }\n            : undefined;\n\n        /** True when explicit access key + secret were supplied (env/.env/CLI). */\n        this.hasExplicitCredentials = !!this._credentials;\n\n        // Quiet the AWS SDK v3 \"node >=22 required after Jan 2027\" notice.\n        process.env.AWS_SDK_JS_NODE_VERSION_SUPPORT_WARNING_DISABLED ??= \"true\";\n\n        this._clients = {};\n    }\n\n    // ── clients (lazy, optionally region-scoped) ──────────────────────────────\n    _clientConfig(region) {\n        const cfg = { region: region || this.region };\n        if (this._credentials) cfg.credentials = this._credentials;\n        return cfg;\n    }\n\n    _sts() {\n        return (this._clients.sts ??= new STSClient(this._clientConfig()));\n    }\n\n    _ec2(region) {\n        const key = `ec2:${region || this.region}`;\n        return (this._clients[key] ??= new EC2Client(this._clientConfig(region)));\n    }\n\n    _route53() {\n        // Route53 is global; region is irrelevant but the client still wants one.\n        return (this._clients.route53 ??= new Route53Client(this._clientConfig()));\n    }\n\n    getRegion() { return this.region; }\n\n    // ── credentials ─────────────────────────────────────────────────────────────\n    /**\n     * Are any credentials available *before* hitting AWS? Returns\n     * { ok, source } — explicit keys, or a resolvable default chain (profile/SSO/\n     * instance role). { ok:false } means there's nothing to even try with.\n     * Note: \"ok\" only means creds were *found*, not that AWS will accept them.\n     */\n    async checkCredentials() {\n        if (this.hasExplicitCredentials) {\n            return { ok: true, source: \"explicit keys (env/.env/CLI)\" };\n        }\n        try {\n            const provider = this._sts().config.credentials;\n            const resolved = typeof provider === \"function\" ? await provider() : provider;\n            if (resolved?.accessKeyId) {\n                return { ok: true, source: \"default credential chain (profile/SSO/role)\" };\n            }\n        } catch {\n            // nothing resolvable\n        }\n        return { ok: false };\n    }\n\n    /** True for \"bad/missing credentials\" style errors (vs. real failures). */\n    static isAuthError(err) {\n        const name = err?.name || err?.Code || err?.__type || \"\";\n        return [\n            \"CredentialsProviderError\",\n            \"InvalidClientTokenId\",\n            \"UnrecognizedClientException\",\n            \"AuthFailure\",\n            \"AccessDenied\",\n            \"AccessDeniedException\",\n            \"ExpiredToken\",\n            \"ExpiredTokenException\",\n            \"SignatureDoesNotMatch\",\n            \"MissingAuthenticationToken\",\n        ].includes(name);\n    }\n\n    /** Short, precise instructions for getting AWS credentials into .env. */\n    static credentialsHelp(region = DEFAULT_REGION) {\n        return [\n            \"No usable AWS credentials were found (or AWS rejected them).\",\n            \"\",\n            \"Put a read-only access key in the project's .env:\",\n            \"\",\n            \"  AWS_ACCESS_KEY_ID=AKIA...\",\n            \"  AWS_SECRET_ACCESS_KEY=...\",\n            `  AWS_REGION=${region}        # optional (default ${DEFAULT_REGION})`,\n            \"\",\n            \"Get a key from the AWS console (~2 min):\",\n            \"  1. IAM → Users → create or pick a user (console sign-in not needed).\",\n            '  2. Attach a policy — \"ReadOnlyAccess\" (AWS managed) is enough for discovery.',\n            '  3. The user → \"Security credentials\" → \"Create access key\" → \"CLI\".',\n            \"  4. Copy the Access key ID + Secret access key (the secret shows only once).\",\n            \"  5. Paste both into .env, then re-run.\",\n            \"     Direct link: https://console.aws.amazon.com/iam/home#/users\",\n            \"\",\n            \"Prefer a named profile or an EC2 instance role? Re-run with AWS_PROFILE=<name>\",\n            \"set (or on the instance) and credentials resolve automatically.\",\n        ].join(\"\\n\");\n    }\n\n    // ── identity ──────────────────────────────────────────────────────────────\n    /** { account, arn, userId } — confirm which account/identity the keys belong to. */\n    async whoAmI() {\n        const out = await this._sts().send(new GetCallerIdentityCommand({}));\n        return { account: out.Account, arn: out.Arn, userId: out.UserId };\n    }\n\n    // ── regions / AZs ──────────────────────────────────────────────────────────\n    /** Enabled region names, sorted. */\n    async listRegions({ allRegions = false } = {}) {\n        const out = await this._ec2().send(new DescribeRegionsCommand({ AllRegions: allRegions }));\n        return (out.Regions ?? []).map(r => r.RegionName).sort();\n    }\n\n    /** Availability zone names for a region (defaults to the instance region). */\n    async listAvailabilityZones(region) {\n        const out = await this._ec2(region).send(new DescribeAvailabilityZonesCommand({}));\n        return (out.AvailabilityZones ?? [])\n            .filter(z => z.State === \"available\")\n            .map(z => z.ZoneName)\n            .sort();\n    }\n\n    // ── VPC / subnets / SGs / key pairs ────────────────────────────────────────\n    /** [{ id, cidr, isDefault, name }] in a region. */\n    async listVpcs(region) {\n        const out = await this._ec2(region).send(new DescribeVpcsCommand({}));\n        return (out.Vpcs ?? []).map(v => ({\n            id: v.VpcId,\n            cidr: v.CidrBlock,\n            isDefault: !!v.IsDefault,\n            name: nameTag(v.Tags),\n        }));\n    }\n\n    /** [{ id, vpcId, az, cidr, public, name }]; pass vpcId to scope. */\n    async listSubnets({ vpcId, region } = {}) {\n        const Filters = vpcId ? [{ Name: \"vpc-id\", Values: [vpcId] }] : undefined;\n        const out = await this._ec2(region).send(new DescribeSubnetsCommand({ Filters }));\n        return (out.Subnets ?? []).map(s => ({\n            id: s.SubnetId,\n            vpcId: s.VpcId,\n            az: s.AvailabilityZone,\n            cidr: s.CidrBlock,\n            public: !!s.MapPublicIpOnLaunch,\n            name: nameTag(s.Tags),\n        }));\n    }\n\n    /** [{ id, name, vpcId, description }]; pass vpcId to scope. */\n    async listSecurityGroups({ vpcId, region } = {}) {\n        const Filters = vpcId ? [{ Name: \"vpc-id\", Values: [vpcId] }] : undefined;\n        const out = await this._ec2(region).send(new DescribeSecurityGroupsCommand({ Filters }));\n        return (out.SecurityGroups ?? []).map(g => ({\n            id: g.GroupId,\n            name: g.GroupName,\n            vpcId: g.VpcId,\n            description: g.Description,\n        }));\n    }\n\n    /** [{ name, fingerprint }] EC2 key pairs in a region. */\n    async listKeyPairs(region) {\n        const out = await this._ec2(region).send(new DescribeKeyPairsCommand({}));\n        return (out.KeyPairs ?? []).map(k => ({ name: k.KeyName, fingerprint: k.KeyFingerprint }));\n    }\n\n    // ── Route53 ────────────────────────────────────────────────────────────────\n    /** [{ id, name, private, recordCount }] — id is the bare zone id (no /hostedzone/). */\n    async listHostedZones() {\n        const zones = [];\n        let marker;\n        do {\n            const out = await this._route53().send(new ListHostedZonesCommand({ Marker: marker }));\n            for (const z of out.HostedZones ?? []) {\n                zones.push({\n                    id: (z.Id ?? \"\").replace(\"/hostedzone/\", \"\"),\n                    name: (z.Name ?? \"\").replace(/\\.$/, \"\"), // strip trailing dot\n                    private: !!z.Config?.PrivateZone,\n                    recordCount: z.ResourceRecordSetCount,\n                });\n            }\n            marker = out.IsTruncated ? out.NextMarker : undefined;\n        } while (marker);\n        return zones;\n    }\n\n    /**\n     * Best hosted zone for a domain: exact match, else the longest zone name that\n     * is a suffix of the domain (so \"api.foo.com\" matches the \"foo.com\" zone).\n     * Returns the zone object or null.\n     */\n    async findHostedZoneForDomain(domain) {\n        const target = String(domain ?? \"\").replace(/\\.$/, \"\").toLowerCase();\n        if (!target) return null;\n        const zones = await this.listHostedZones();\n        const exact = zones.find(z => z.name.toLowerCase() === target);\n        if (exact) return exact;\n        return zones\n            .filter(z => target.endsWith(`.${z.name.toLowerCase()}`))\n            .sort((a, b) => b.name.length - a.name.length)[0] ?? null;\n    }\n\n    // ── AMI lookup ──────────────────────────────────────────────────────────────\n    /**\n     * Latest Ubuntu AMI matching a name pattern in a region.\n     * Returns { id, name, creationDate, architecture } or null.\n     */\n    async findLatestUbuntuAmi({ region, pattern = DEFAULT_UBUNTU_PATTERN, architecture = \"x86_64\" } = {}) {\n        const out = await this._ec2(region).send(new DescribeImagesCommand({\n            Owners: [CANONICAL_OWNER_ID],\n            Filters: [\n                { Name: \"name\", Values: [pattern] },\n                { Name: \"virtualization-type\", Values: [\"hvm\"] },\n                { Name: \"state\", Values: [\"available\"] },\n                ...(architecture ? [{ Name: \"architecture\", Values: [architecture] }] : []),\n            ],\n        }));\n        const newest = (out.Images ?? [])\n            .sort((a, b) => String(b.CreationDate).localeCompare(String(a.CreationDate)))[0];\n        if (!newest) return null;\n        return {\n            id: newest.ImageId,\n            name: newest.Name,\n            creationDate: newest.CreationDate,\n            architecture: newest.Architecture,\n        };\n    }\n}\n","import chalk from \"chalk\";\nimport util from \"util\";\n\n\n\n\n\n\n\n\n\n\nimport { ConsoleTransport, ParentProcessTransport } from \"./transports.js\";\n\n\nconst ALL_LEVELS = [\n    \"silly\",\n    \"debug\",\n    \"logic\",\n    \"info\",\n    \"notice\",\n    \"warn\",\n    \"error\",\n    \"results\",\n    \"request\",\n    \"response\",\n    \"progress\"\n];\nconst DEFAULT_LEVELS = ALL_LEVELS.filter((l) => l !== \"silly\");\n\n// Calculate maximum level name length for alignment\nconst MAX_LEVEL_LENGTH = Math.max(...ALL_LEVELS.map(level => level.toUpperCase().length));\n\nconst LEVEL_COLORS = {\n    error: chalk.red.bold,\n    warn: chalk.rgb(255, 165, 0),\n    notice: chalk.cyan,\n    info: chalk.white.bold,\n    logic: chalk.gray,\n    debug: chalk.gray,\n    silly: chalk.gray,\n    request: chalk.green,\n    response: chalk.yellow,\n    // Magenta stands out from white info / green request lines.\n    progress: chalk.magentaBright,\n    results: chalk.magenta\n};\n\nfunction paint(level, text, { color = true, bold = false } = {}) {\n    if (!color || text == null || text === \"\") return text == null ? \"\" : String(text);\n    const formatter = LEVEL_COLORS[level] ?? chalk.white;\n    return bold ? formatter.bold(text) : formatter(text);\n}\n\nfunction inspectChunks(chunks, color = true) {\n    return (chunks ?? [])\n        .map((chunk) => util.inspect(chunk, { colors: color, depth: null }))\n        .join(\" \");\n}\n\n/**\n * Format a log struct for a terminal. Used by Logger and by UIs (tasksmm)\n * that persist structs and render them later.\n *\n * @param {{ level?: string, message?: string, name?: string, task?: string, prefix?: string, count?: unknown, total?: unknown,\n *           elapsed?: number, remaining?: number, rate?: number, chunks?: unknown[], results?: unknown }} struct\n * @param {{ timestamp?: boolean, showLevel?: boolean, color?: boolean, now?: Date|string|number }} [options]\n */\nexport function formatLog(struct = {}, options = {}) {\n    const level = String(struct.level || \"info\").toLowerCase();\n    const color = options.color !== false;\n    const parts = [];\n    const now = options.now != null ? new Date(options.now) : new Date();\n\n    if (options.timestamp) {\n        const d = Number.isNaN(now.getTime()) ? new Date() : now;\n        parts.push(d.toISOString());\n    }\n\n    if (options.showLevel) {\n        parts.push(level.toUpperCase().padEnd(MAX_LEVEL_LENGTH));\n    }\n\n    const taskName = struct.task != null ? String(struct.task).trim() : \"\";\n    if (taskName) {\n        parts.push(color ? chalk.cyan(`[${taskName}]`) : `[${taskName}]`);\n    }\n\n    if (level === \"progress\") {\n        if (struct.prefix) {\n            parts.push(paint(level, struct.prefix, { color, bold: true }));\n        }\n        if (struct.count !== undefined && struct.total !== undefined) {\n            parts.push(paint(level, `${struct.count}/${struct.total}`, { color }));\n        }\n    } else if (struct.prefix) {\n        parts.push(color ? chalk.cyan(`[${struct.prefix}]`) : `[${struct.prefix}]`);\n    }\n\n    if (struct.message) {\n        parts.push(paint(level, struct.message, { color, bold: true }));\n    }\n\n    if (level === \"progress\") {\n        if (struct.elapsed !== undefined && struct.remaining !== undefined) {\n            parts.push(paint(level, `${struct.elapsed}/${struct.remaining}`, { color }));\n        }\n        if (struct.rate !== undefined) {\n            parts.push(paint(level, Number(struct.rate) >= 0 ? `${struct.rate}/s` : \"-/s\", { color }));\n        }\n    }\n\n    if (struct.chunks && struct.chunks.length) {\n        parts.push(inspectChunks(struct.chunks, color));\n    }\n\n    if (struct.results) {\n        parts.push(paint(level, JSON.stringify(struct.results, null, 4), { color }));\n    }\n\n    return parts.join(\" \");\n}\n\nexport class Logger  {\n    context; // Partial context during initialization\n    options;\n    transport;\n    startTimes = {};\n    /** Count at the first progress sample for each prefix (rate baseline). */\n    startCounts = {};\n    lastProgressTimes = {};\n\n    constructor(context, options = {}) {\n        this.context = context;\n        // Set defaults first\n        this.options = this.getDefaultOptions();\n        // Apply configuration\n        if (options) {\n            this.configure(options);\n        }\n        // Initialize transport\n        this.updateTransport();\n    }\n\n    /**\n     * Configure logger options. Accepts both LoggerOptions shape and flat param names\n     * (levels string, progressWithTimes, progressWithRate, progressThrottleMs).\n     */\n    configure(options) {\n        if (options.mode !== undefined) {\n            this.options.mode = this.isValidMode(options.mode) ? options.mode : \"text\";\n        }\n        if (options.route !== undefined) {\n            this.options.route = options.route;\n            this.updateTransport();\n        }\n        if (options.prefix !== undefined) this.options.prefix = options.prefix;\n        if (options.name !== undefined) this.options.name = options.name;\n        if (options.logName !== undefined) this.options.name = options.logName;\n        if (options.task !== undefined) this.options.task = options.task;\n        if (options.silent !== undefined) this.options.silent = options.silent;\n        if (options.showLevel !== undefined) this.options.showLevel = options.showLevel;\n        if (options.timestamp !== undefined) this.options.timestamp = options.timestamp;\n        if (options.levels !== undefined) {\n            const levels = typeof options.levels === \"string\" ? options.levels.split(\",\") : options.levels;\n            this.options.levels = this.normalizeLevels(levels);\n        }\n        if (options.progress !== undefined) {\n            if (options.progress.withTimes !== undefined) this.options.progressTimes = options.progress.withTimes;\n            if (options.progress.withRate !== undefined) this.options.progressRate = options.progress.withRate;\n            if (options.progress.throttleMs !== undefined) this.options.progressThrottle = options.progress.throttleMs;\n        }\n        const flat = options ;\n        if (flat.progressWithTimes !== undefined) this.options.progressTimes = flat.progressWithTimes;\n        if (flat.progressWithRate !== undefined) this.options.progressRate = flat.progressWithRate;\n        if (flat.progressThrottleMs !== undefined) this.options.progressThrottle = flat.progressThrottleMs;\n    }\n\n    /**\n     * Initialize logger from context and CLI parameters. Whatever is in options goes (after discovered params).\n     * Params are tracked under the `logger` module for --showUsedParams.\n     */\n    static init(context, options) {\n        const paramDefs = {\n            mode: \"string default text\",\n            route: \"string default console\",\n            prefix: \"string\",\n            logName: \"string\",\n            silent: \"boolean default false\",\n            showLevel: \"boolean default true\",\n            timestamp: \"boolean default false\",\n            levels: \"string\",\n            progressWithTimes: \"boolean default false\",\n            progressWithRate: \"boolean default false\",\n            progressThrottleMs: \"number\",\n        };\n        const discovered = context.params.getAllForModule(\"logger\", paramDefs);\n        const config = { ...discovered, ...options } ;\n        if (!config.name && !config.logName) {\n            const fromEnv = process.env.name || process.env.SERVICE_NAME;\n            if (fromEnv) config.name = fromEnv;\n        }\n        const logger = new Logger(context, config);\n        context.logger = logger;\n        return logger;\n    }\n\n    getDefaultOptions() {\n        return {\n            mode: \"text\",\n            route: this.shouldUseIpcRoute() ? \"ipc\" : \"console\",\n            prefix: undefined,\n            name: undefined,\n            task: undefined,\n            silent: false,\n            showLevel: false,\n            timestamp: false,\n            levels: DEFAULT_LEVELS,\n            progressTimes: false,\n            progressRate: false,\n            progressThrottle: undefined,\n        };\n    }\n\n    updateTransport() {\n        this.transport = this.options.route === \"ipc\"\n            ? new ParentProcessTransport()\n            : new ConsoleTransport();\n    }\n\n    /**\n     * Same transport, tagged with a task name on every line. Does not mutate\n     * this instance — safe when maxParallel > 1.\n     *\n     * @param {string} task\n     * @returns {Logger}\n     */\n    child(task) {\n        const next = Object.create(this);\n        next.options = { ...this.options, task: task ? String(task) : this.options.task };\n        return next;\n    }\n\n    setMode(mode) {\n        if (!this.isValidMode(mode)) {\n            throw new Error(`Unsupported logger mode: ${mode}`);\n        }\n        this.options.mode = mode;\n    }\n\n    /** Returns a styled string (bright white) for highlighting; keeps chalk inside logger. */\n    highlight(text) {\n        return chalk.whiteBright(text);\n    }\n\n    debug(message, ...chunks) {\n        const out = this?.out;\n        if (typeof out === \"function\") out.call(this, { level: \"debug\", message, chunks });\n    }\n\n    info(message, ...chunks) {\n        const out = this?.out;\n        if (typeof out === \"function\") out.call(this, { level: \"info\", message, chunks });\n    }\n\n    notice(message, ...chunks) {\n        const out = this?.out;\n        if (typeof out === \"function\") out.call(this, { level: \"notice\", message, chunks });\n    }\n\n    warn(message, ...chunks) {\n        const out = this?.out;\n        if (typeof out === \"function\") out.call(this, { level: \"warn\", message, chunks });\n    }\n\n    error(message, ...chunks) {\n        const out = this?.out;\n        if (typeof out === \"function\") out.call(this, { level: \"error\", message, chunks });\n    }\n\n    logic(message, ...chunks) {\n        const out = this?.out;\n        if (typeof out === \"function\") out.call(this, { level: \"logic\", message, chunks });\n    }\n\n    silly(message, ...chunks) {\n        const out = this?.out;\n        if (typeof out === \"function\") out.call(this, { level: \"silly\", message, chunks });\n    }\n\n    results(results) {\n        const out = this?.out;\n        if (typeof out === \"function\") out.call(this, { level: \"results\", message: \"results\", results });\n    }\n\n    request(operation, ...chunks) {\n        const message = this.inspectChunks([operation, ...chunks]);\n        this.out({ level: \"request\", message });\n    }\n\n    response(operation, ...chunks) {\n        const message = this.inspectChunks([operation, ...chunks]);\n        this.out({ level: \"response\", message });\n    }\n\n    /**\n     * @returns {boolean} true when the progress line was emitted (not throttled)\n     */\n    progress(message, opts) {\n        const { prefix, count, total } = opts;\n        // If count briefly overshoots a stale total, display without negative ETA;\n        // callers should raise `total` when the feed revises @odata.count.\n        const displayTotal = Math.max(Number(total) || 0, Number(count) || 0);\n        const paddedTotal = String(displayTotal).length;\n        const paddedCount = String(count).padStart(paddedTotal, \" \");\n        const payload = {\n            level: \"progress\",\n            message,\n            count: paddedCount,\n            total: displayTotal,\n            prefix\n        };\n\n        const key = prefix ?? \"\";\n        // First sample for this prefix: establish baseline only (no rate yet).\n        // Rate/ETA use items completed since that sample, so batched reporters\n        // (e.g. every 500 records) don't inflate early /s from a late start clock.\n        if (this.startTimes[key] === undefined) {\n            this.startTimes[key] = Date.now();\n            this.startCounts[key] = count;\n        }\n        const wantTimes = this.options.progressTimes;\n        const wantRate = this.options.progressRate;\n        if (wantTimes || wantRate) {\n            const elapsedSeconds = (Date.now() - this.startTimes[key]) / 1000;\n            const done = count - (this.startCounts[key] ?? count);\n            const itemsPerSec = done > 0 && elapsedSeconds > 0 ? done / elapsedSeconds : -1;\n            if (wantTimes) {\n                let remaining = -1;\n                if (itemsPerSec > 0) {\n                    remaining = Math.max(0, (displayTotal - count) / itemsPerSec);\n                }\n                payload.elapsed = this.round(elapsedSeconds, 2);\n                payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;\n            }\n            if (wantRate) {\n                payload.rate = itemsPerSec >= 0 ? this.round(itemsPerSec, 2) : itemsPerSec;\n            }\n        }\n\n        // Clear rate baseline on exact completion so the next job with the same\n        // prefix re-baselines. Do not clear on overrun (count > total) — that\n        // would zero the rate until total is corrected.\n        if (count === total) {\n            delete this.startTimes[key];\n            delete this.startCounts[key];\n            delete this.lastProgressTimes[key];\n        }\n\n        if (this.shouldOutputProgress(prefix ?? \"\", count, displayTotal)) {\n            this.out(payload);\n            if (this.options.progressThrottle && prefix) {\n                this.lastProgressTimes[prefix] = Date.now();\n            }\n            return true;\n        }\n        return false;\n    }\n\n    shouldOutputProgress(prefix, count, total) {\n        if (!this.options.progressThrottle) {\n            return true;\n        }\n        if (count === 1 || count === total || !prefix) {\n            return true;\n        }\n        const lastTime = this.lastProgressTimes[prefix];\n        if (!lastTime) {\n            return true;\n        }\n        return Date.now() - lastTime >= this.options.progressThrottle;\n    }\n\n    out(struct) {\n        if (this.options.silent) {\n            return;\n        }\n        if (!this.options.levels.includes(struct.level)) {\n            return;\n        }\n\n        if (this.options.task && !struct.task) {\n            struct.task = this.options.task;\n        }\n        if (this.options.prefix && !struct.prefix) {\n            struct.prefix = this.options.prefix;\n        }\n\n        const output = this.options.mode === \"json\"\n            ? JSON.stringify(struct)\n            : this.formatLog(struct);\n\n        this.transport.write(output);\n    }\n\n    formatLog(struct) {\n        return formatLog(struct, {\n            timestamp: this.options.timestamp,\n            showLevel: this.options.showLevel,\n            color: true,\n        });\n    }\n\n    inspectChunks(chunks) {\n        return inspectChunks(chunks, true);\n    }\n\n    shouldUseIpcRoute() {\n        // Don't use IPC in test environments (Vitest workers interfere with process.send)\n        if (process.env.VITEST || process.env.NODE_ENV === \"test\") {\n            return false;\n        }\n        // Only use IPC if process.send exists AND we're connected to a parent\n        // In Vitest workers, process.send exists but process.connected is undefined/false\n        // process.connected is only true in actual child processes created with fork()\n        return typeof process.send === \"function\" && process.connected === true;\n    }\n\n    normalizeLevels(levels) {\n        if (!levels || !levels.length) {\n            return DEFAULT_LEVELS;\n        }\n\n        const tokens = levels.map((t) => String(t).trim()).filter(Boolean);\n        const explicitIncludes = tokens\n            .filter((t) => !t.startsWith(\"+\") && !t.startsWith(\"-\"))\n            .map((t) => t );\n        const addIncludes = tokens\n            .filter((t) => t.startsWith(\"+\"))\n            .map((t) => t.slice(1) );\n        const excludes = tokens\n            .filter((t) => t.startsWith(\"-\"))\n            .map((t) => t.slice(1) );\n\n        const unknown = [...explicitIncludes, ...addIncludes, ...excludes].filter(level => !ALL_LEVELS.includes(level));\n        if (unknown.length) {\n            console.warn(`[Logger] Unknown level(s): ${unknown.join(\", \")}`);\n        }\n\n        const base = explicitIncludes.length\n            ? explicitIncludes\n            : Array.from(new Set([...DEFAULT_LEVELS, ...addIncludes]));\n        return base.filter(level => !excludes.includes(level));\n    }\n\n    isValidMode(mode) {\n        return mode === undefined || mode === null || mode === \"text\" || mode === \"json\";\n    }\n\n    round(value, places) {\n        const factor = Math.pow(10, places);\n        return Math.round(value * factor) / factor;\n    }\n}\n\n","\n\nexport class ConsoleTransport  {\n    write(payload) {\n        console.info(payload);\n    }\n}\n\nexport class ParentProcessTransport  {\n    write(payload) {\n        // Don't use IPC in test environments (Vitest workers interfere with process.send)\n        if (process.env.VITEST || process.env.NODE_ENV === \"test\") {\n            console.info(payload);\n            return;\n        }\n        // Only use process.send if we're actually connected to a parent process\n        // In Vitest workers, process.send exists but shouldn't be used\n        if (typeof process.send === \"function\" && process.connected === true) {\n            process.send(payload);\n        } else {\n            console.info(payload);\n        }\n    }\n}\n\n\n","/**\n * Init component - Framework initialization and flow execution\n * \n * Provides a standardized way to initialize CLI scripts with Args, Params, Logger,\n * and other dependencies, then execute the main flow function.\n */\n\nimport { Args } from \"../args/index.js\";\nimport { Params } from \"../params/index.js\";\nimport { Logger } from \"../logger/index.js\";\nimport { ParamError, InitError } from \"../errors.js\";\n\nimport { EventEmitter } from \"events\";\n\n/**\n * Partial context used during initialization\n * Components are added as they're created\n */\n\n\n\n\n\n\n\n\n\n\n/**\n * Extract component-specific options from InitOptions\n * Removes reserved keys (overrides, defaults, modules) and returns component options\n */\nfunction extractComponentOptions(opts, _componentName) {\n    const reservedKeys = [\"overrides\", \"defaults\", \"modules\"];\n    const componentOptions = {};\n    \n    for (const [key, value] of Object.entries(opts)) {\n        if (!reservedKeys.includes(key)) {\n            componentOptions[key] = value;\n        }\n    }\n    \n    return componentOptions;\n}\n\n/**\n * Setup initial context with Args, Params, and Logger\n * Uses staged initialization to handle circular dependencies\n */\nfunction setup(opts = {}) {\n    // Stage 1: Create partial context first (Args will register its cleanup on it)\n    const partialContext = {\n        emitter: new EventEmitter(),\n        isStop: () => false,\n        isKill: () => false,\n        cleanupFunctions: [],\n        registerCleanup: (fn) => {\n            partialContext.cleanupFunctions.push(fn);\n        },\n    };\n\n    // Stage 2: Initialize Args with partial context so it can register unused-args cleanup\n    const args = Args.init(partialContext , {\n        overrides: opts.overrides || {},\n        defaults: opts.defaults || {},\n    });\n    partialContext.args = args;\n\n    // Stage 3: Initialize Params with partial context\n    const params = Params.init(partialContext , opts.overrides || {});\n    partialContext.params = params;\n\n    // Stage 4: Initialize Logger with partial context (now has Args and Params)\n    // Extract logger options from top-level opts (mode, route, prefix, etc.)\n    const loggerOptions = extractComponentOptions(opts, \"logger\");\n    const logger = Logger.init(partialContext , loggerOptions);\n    partialContext.logger = logger;\n\n    // Stage 5: Create complete context\n    const context = {\n        args,\n        params,\n        logger,\n        emitter: partialContext.emitter,\n        isStop: partialContext.isStop,\n        isKill: partialContext.isKill,\n        cleanupFunctions: partialContext.cleanupFunctions,\n        registerCleanup: partialContext.registerCleanup,\n        // For long-running scripts (servers): with --showUsedParams=top, print\n        // the used-params list now (after the script has initialized all its\n        // own components), instead of at exit. No-op for the default mode,\n        // which prints at exit via the cleanup registered by Params.\n        //\n        // --showUsedParams=stop behaves like \"top\" but then exits immediately —\n        // a quick \"show me the figured params and quit\" that skips the flow's\n        // actual work. Like --stopAfter=init, this is a hard exit(0) (registered\n        // cleanups are skipped); call it once components/params are resolved.\n        _requestExitCode: null,\n        requestExit: null,\n        showUsedParamsIfNeeded: () => {\n            const mode = params.getShowUsedParamsMode?.();\n            if (mode !== \"top\" && mode !== \"stop\") return;\n            params.printUsedParams(logger);\n            if (mode === \"stop\") {\n                logger.debug?.(\"[showUsedParams=stop] params printed — exiting\");\n                process.exit(0);\n            }\n        },\n    };\n\n    // Interactive CLIs (tasksmm) call this before returning so leftover\n    // knex/DNS handles cannot keep the process alive after cleanup.\n    context.requestExit = (code = 0) => {\n        context._requestExitCode = code;\n    };\n\n    logger.debug(\"[setup] completed successfully\");\n    return context;\n}\n\n/**\n * Setup modules (future feature - placeholder for now)\n */\nasync function setupModules(context, opts = {}) {\n    // TODO: Implement module initialization\n    // For now, just log that modules would be initialized\n    if (opts.modules && opts.modules.length > 0) {\n        context.logger.debug(`[setupModules] modules specified: ${opts.modules.join(\", \")} (not yet implemented)`);\n    }\n    context.logger.debug(\"[setupModules] completed successfully\");\n    return context;\n}\n\n/**\n * Print all figured parameters for --stopAfter=init\n */\nfunction printAllParameters(context) {\n    const trackedParams = context.params.getTrackedParams();\n    \n    console.log(\"\\n=== All Figured Parameters ===\");\n    console.log(\"\\nComponent: Logger\");\n    const loggerParams = trackedParams.filter(p => \n        [\"mode\", \"route\", \"prefix\", \"silent\", \"showLevel\", \"timestamp\", \"levels\"].includes(p.key)\n    );\n    if (loggerParams.length > 0) {\n        loggerParams.forEach(p => {\n            console.log(`  ${p.key}: ${JSON.stringify(p.value)} (from ${p.source})`);\n        });\n    } else {\n        console.log(\"  (no parameters requested)\");\n    }\n\n    // Add other components as they're initialized\n    console.log(\"\\n=== End Parameters ===\\n\");\n}\n\n/**\n * Initialize framework and execute flow function\n * \n * Automatically handles async module loading (e.g., ESM dependencies for screen module)\n * so users don't need to call load() manually.\n * \n * @param flow - Main function that receives context and executes the script logic\n * @param opts - Configuration options for initialization\n */\nexport async function init(flow, opts = {}) {\n    let stop = false;\n    let kill = false;\n    let context = null;\n    let cleanupRan = false;\n\n    const runRegisteredCleanups = async (ctx) => {\n        if (cleanupRan) return;\n        cleanupRan = true;\n        const fns = [...ctx.cleanupFunctions].reverse();\n        const budgetMs = 5_000;\n        const started = Date.now();\n        for (const fn of fns) {\n            const left = budgetMs - (Date.now() - started);\n            if (left <= 0) {\n                ctx.logger.warn(\"[cleanup] budget exhausted — skipping remaining cleanup\");\n                break;\n            }\n            try {\n                await Promise.race([\n                    Promise.resolve(fn(ctx)),\n                    new Promise((_, reject) => {\n                        const t = setTimeout(\n                            () => reject(new Error(`cleanup timed out after ${left}ms`)),\n                            left,\n                        );\n                        t.unref?.();\n                    }),\n                ]);\n            } catch (error) {\n                ctx.logger.warn(\"[cleanup] error in cleanup function:\", error);\n            }\n        }\n    };\n\n    try {\n        // Pre-load ESM dependencies (ink, react) for CommonJS compatibility\n        // This ensures screen-related functionality works in CommonJS environments\n        // The load() function is available from the screen module or main package\n        try {\n            // Try to import screen module and call its load function\n            // This works in both ESM and CommonJS (via dynamic import)\n            const screenModule = await import(\"../screen/index.js\");\n            if (screenModule && typeof screenModule.load === \"function\") {\n                await screenModule.load();\n            }\n        } catch {\n            // If screen module load fails, try accessing via main package (CommonJS)\n            if (typeof require !== \"undefined\") {\n                try {\n                    // In CommonJS, the main package may have been required and exports load()\n                    // We can't use require() here as it would be synchronous, so we skip it\n                    // The screen module import above should work in both cases\n                } catch {\n                    // Ignore - screen functionality may not be needed\n                }\n            }\n        }\n\n        // Setup context with Args, Params, Logger\n        context = setup(opts);\n        \n        // Cooperative stop (SIGINT/SIGTERM) vs urgent kill (SIGUSR2).\n        // Kill also sets stop so existing `isStop()` loops exit promptly.\n        context.isStop = () => stop;\n        context.isKill = () => kill;\n\n        // Setup modules (future feature)\n        context = await setupModules(context, opts);\n\n        // Resolve params used by init (stopAfter, stopAllowance) early.\n        // `stopAllowance` is seconds (CLI/env); runners and pm2 kill_timeout use ms.\n        const stopAfter = context.args.get(\"stopAfter\");\n        const stopAllowanceSec = Number(context.params.get(\"stopAllowance\", \"number default 60\"));\n        const stopAllowanceMs = (Number.isFinite(stopAllowanceSec) && stopAllowanceSec >= 0\n            ? stopAllowanceSec\n            : 60) * 1000;\n        context.stopAllowanceSec = stopAllowanceSec;\n        context.stopAllowanceMs = stopAllowanceMs;\n\n        if (stopAfter === \"init\") {\n            printAllParameters(context);\n            process.exit(0);\n        }\n\n        // Graceful shutdown: first Ctrl+C sets stop + emits; second runs registered cleanups then exits.\n        // (Previously, process.exit(2) on second SIGINT skipped try/finally, so registerCleanup never ran.)\n        let sigintCount = 0;\n        let firstSigintAt = 0;\n        process.on(\"SIGINT\", async () => {\n            if (!context) return;\n            const now = Date.now();\n            if (sigintCount === 0) {\n                sigintCount = 1;\n                firstSigintAt = now;\n                stop = true;\n                context.logger.info(\n                    `>> emitting stop with allowance ${stopAllowanceSec}s (${stopAllowanceMs}ms)`\n                );\n                context.emitter.emit(\"stop\", stopAllowanceMs);\n                return;\n            }\n            // A single Ctrl+C can reach Node as TWO SIGINTs (e.g. under\n            // `npm run`: the terminal signals the whole process group AND npm\n            // forwards the signal). Those duplicates land within a few ms, so\n            // ignore a second SIGINT that arrives shortly after the first —\n            // otherwise we'd force-exit (below) before the graceful cleanup\n            // chain finishes, skipping late cleanups like --showUsedParams.\n            if (now - firstSigintAt < 250) return;\n            context.logger.warn(\"[process] second SIGINT: running cleanup then exit\");\n            await runRegisteredCleanups(context);\n            process.exit(2);\n        });\n\n        process.on(\"SIGTERM\", () => {\n            if (!context || stop) return;\n            stop = true;\n            context.logger.info(\n                `>> SIGTERM: emitting stop with allowance ${stopAllowanceSec}s (${stopAllowanceMs}ms)`\n            );\n            context.emitter.emit(\"stop\", stopAllowanceMs);\n        });\n\n        // Urgent abort (e.g. `pm2 sendSignal SIGUSR2 <app>`). Parents that spawn\n        // children (retro loops) should forward SIGUSR2 on the \"kill\" event so the\n        // child init flips isKill() and breaks its own loops cooperatively.\n        process.on(\"SIGUSR2\", () => {\n            if (!context || kill) return;\n            kill = true;\n            stop = true;\n            context.logger.warn(\">> SIGUSR2: emitting kill (urgent stop)\");\n            context.emitter.emit(\"kill\");\n            context.emitter.emit(\"stop\", stopAllowanceMs);\n        });\n\n        // Execute the flow function\n        await flow(context);\n\n    } catch (error) {\n        // Error handling with proper error types\n        const errorLocation = error instanceof Error && error.stack\n            ? error.stack.split(\"\\n\")[1]?.trim() || \"Unknown location\"\n            : \"Unknown location\";\n\n        // Use logger if available, otherwise fall back to console.error\n        const logError = (msg, ...args) => {\n            if (context?.logger) {\n                context.logger.error(msg, ...args);\n            } else {\n                console.error(msg, ...args);\n            }\n        };\n\n        if (error instanceof ParamError) {\n            logError(`[params]: ${error.message} (${errorLocation})`);\n            process.exitCode = 3;\n        } else if (error instanceof InitError) {\n            logError(`[init]: ${error.message} (${errorLocation})`);\n            process.exitCode = 4;\n        } else {\n            logError(`[other] error:`, error, errorLocation);\n            process.exitCode = 5;\n        }\n    } finally {\n        if (context) {\n            await runRegisteredCleanups(context);\n        }\n        // Open handles (logger, SDK agents, signal listeners, …) can keep Node\n        // alive after the flow returns. Under pm2 that becomes a zombie: the\n        // runner has unregistered and disconnected, but pm2 waits kill_timeout\n        // then SIGKILL. Force-exit on errors and on cooperative/signal stop.\n        if (process.exitCode && process.exitCode !== 0) {\n            process.exit(process.exitCode);\n        } else if (stop || kill) {\n            process.exit(0);\n        } else if (context._requestExitCode != null) {\n            process.exit(context._requestExitCode);\n        }\n    }\n}\n\n/**\n * Setup function - can be used independently to get context without executing flow\n * Useful for testing or advanced use cases\n */\nexport function setupContext(opts = {}) {\n    return setup(opts);\n}\n\n","/**\n * A \"service\" is a plain manifest object describing how to deploy one app onto a\n * host. Projects define these; the engine is otherwise project-agnostic.\n *\n * Required:\n *   name        unique id, also the default pm2 app + nginx site name\n *   appsRoot    base dir on the host, e.g. /apps/<name>\n *   repoUrl     git url to clone (ssh git@… or https://…)\n *   pm2.script  entry script (relative to the release/cwd)\n *\n * Optional (sensible defaults applied by defineService):\n *   repoDirName     default: repo name derived from repoUrl\n *   repoSubdir      default: \"\" (release = repo root). Set \"v2\" for a monorepo subdir.\n *   keepReleases    default: 3\n *   testCommand     default: null  (shell run in the release before activating; null = skip)\n *   envScrubPatterns default: []   (regex source strings; matching .env lines are dropped)\n *   legacyRepoEnv   default: null  (fallback .env path on a pre-migration host)\n *   buildInfoPath   default: \"build-info.json\"  (written into each release, relative to release root)\n *   deployKey       default: null  (path to a git deploy key; only needed for ssh repoUrl)\n *   requireEnv      default: false (true = fail if no .env found; false = continue with empty)\n *   pm2: {\n *     appName=name, script, args=\"\", port,\n *     stopAllowance=60,   // seconds → injected as --stopAllowance=N on the process\n *     killTimeout=65000,  // ms; pm2 kill_timeout (default: stopAllowance*1000+5000)\n *     killRetryTime=10000, // ms; pm2 kill_retry_time (default 10s; pm2's own default is 100ms)\n *   }\n *   nginx: { siteName=name, fqdn }   (omit nginx entirely to skip the nginx step)\n */\nexport function deriveRepoDirName(repoUrl) {\n    const tail = String(repoUrl ?? \"\").split(\"/\").pop() ?? \"repo\";\n    return tail.replace(/\\.git$/, \"\") || \"repo\";\n}\n\nexport function defineService(service) {\n    if (!service?.name) throw new Error(\"service manifest needs a `name`\");\n    if (!service.appsRoot) throw new Error(`service \"${service.name}\" needs an appsRoot`);\n    if (!service.repoUrl) throw new Error(`service \"${service.name}\" needs a repoUrl`);\n    if (!service.pm2?.script) throw new Error(`service \"${service.name}\" needs pm2.script`);\n\n    const pm2 = {\n        appName: service.name,\n        args: \"\",\n        stopAllowance: 60,\n        ...service.pm2,\n    };\n    if (pm2.killTimeout == null) {\n        const stopSec = Number(pm2.stopAllowance);\n        pm2.killTimeout = Number.isFinite(stopSec) && stopSec > 0\n            ? Math.floor(stopSec * 1000) + 5000\n            : 65_000;\n    }\n    const nginx = service.nginx\n        ? { siteName: service.name, ...service.nginx }\n        : null;\n\n    return {\n        repoDirName: deriveRepoDirName(service.repoUrl),\n        repoSubdir: \"\",\n        keepReleases: 3,\n        testCommand: null,\n        envScrubPatterns: [],\n        legacyRepoEnv: null,\n        buildInfoPath: \"build-info.json\",\n        deployKey: null,\n        requireEnv: false,\n        ...service,\n        pm2,\n        nginx,\n    };\n}\n","import { join } from \"node:path\";\n\n/**\n * Resolve on-disk paths for a service under <appsRoot>/.\n *\n *   <appsRoot>/\n *     <repoDirName>/[<repoSubdir>/]   git checkout (build source only)\n *     releases/<stamp>/               one release = contents of the run dir\n *     shared/.env, ecosystem.config.cjs\n *     logs/deploy.log\n *     current -> releases/<stamp>\n */\nexport function servicePaths(service) {\n    const root = service.appsRoot;\n    const repoDirName = service.repoDirName ?? \"repo\";\n    const repoSubdir = service.repoSubdir ?? \"\";\n\n    const repo = join(root, repoDirName);\n    const repoRun = repoSubdir ? join(repo, repoSubdir) : repo;\n\n    return {\n        root,\n        repo,\n        repoRun,\n        repoEnv: join(repoRun, \".env\"),\n        releases: join(root, \"releases\"),\n        shared: join(root, \"shared\"),\n        logs: join(root, \"logs\"),\n        current: join(root, \"current\"),\n        sharedEnv: join(root, \"shared\", \".env\"),\n        ecosystem: join(root, \"shared\", \"ecosystem.config.cjs\"),\n        /** Preloaded by pm2 `node_args --require` so ENV survives flaky restarts. */\n        ensureEnv: join(root, \"shared\", \"ensure-env.cjs\"),\n        deployLog: join(root, \"logs\", \"deploy.log\"),\n        lockHashFile: join(root, \"shared\", \".package-lock.sha256\"),\n    };\n}\n\n/** ISO-8601 release stamp with `:` (safe on Linux ext4). */\nexport function releaseStamp(date = new Date()) {\n    return date.toISOString().replace(/\\.\\d{3}Z$/, \"Z\");\n}\n\nexport function releaseDir(releasesRoot, stamp) {\n    return join(releasesRoot, stamp);\n}\n","import { spawn } from \"node:child_process\";\n\n/** npm omits devDependencies when NODE_ENV=production — unset it for ci + tests. */\nexport function npmEnv(baseEnv = process.env) {\n    const env = { ...baseEnv };\n    delete env.NODE_ENV;\n    return env;\n}\n\n/** Env for npm ci/install so devDependencies are always installed. */\nexport function npmInstallEnv(baseEnv = process.env) {\n    return {\n        ...npmEnv(baseEnv),\n        NPM_CONFIG_PRODUCTION: \"false\",\n        npm_config_production: \"false\",\n    };\n}\n\n/** Run a command with inherited stdio. Rejects on non-zero exit. */\nexport function run(cmd, args, options = {}) {\n    const { cwd, env, logger } = options;\n\n    return new Promise((resolve, reject) => {\n        logger?.info?.(`$ ${cmd} ${args.join(\" \")}${cwd ? `  (cwd=${cwd})` : \"\"}`);\n        const child = spawn(cmd, args, {\n            cwd,\n            env: env ?? process.env,\n            stdio: \"inherit\",\n        });\n        child.on(\"error\", reject);\n        child.on(\"close\", (code) => {\n            if (code === 0) resolve();\n            else reject(new Error(`${cmd} exited with code ${code}`));\n        });\n    });\n}\n\n/** Run a shell one-liner via bash -lc. */\nexport function runShell(command, options = {}) {\n    return run(\"bash\", [\"-lc\", command], options);\n}\n\n/**\n * Run a command capturing stdout/stderr (for `pm2 jlist`, etc.).\n * Rejects on non-zero exit unless `allowFail` is set.\n *\n * @returns {Promise<{ stdout: string, stderr: string, code: number|null }>}\n */\nexport function runCapture(cmd, args, options = {}) {\n    const { cwd, env, logger, allowFail = false } = options;\n\n    return new Promise((resolve, reject) => {\n        logger?.info?.(`$ ${cmd} ${args.join(\" \")}${cwd ? `  (cwd=${cwd})` : \"\"}`);\n        const child = spawn(cmd, args, {\n            cwd,\n            env: env ?? process.env,\n            stdio: [\"ignore\", \"pipe\", \"pipe\"],\n        });\n        let stdout = \"\";\n        let stderr = \"\";\n        child.stdout?.on(\"data\", (chunk) => {\n            stdout += chunk.toString();\n        });\n        child.stderr?.on(\"data\", (chunk) => {\n            stderr += chunk.toString();\n        });\n        child.on(\"error\", reject);\n        child.on(\"close\", (code) => {\n            if (code === 0 || allowFail) resolve({ stdout, stderr, code });\n            else reject(new Error(`${cmd} exited with code ${code}${stderr ? `: ${stderr.trim()}` : \"\"}`));\n        });\n    });\n}\n","import { appendFile, mkdir } from \"node:fs/promises\";\n\n/** Section header: what is about to happen. Falls back to info (e.g. `console`). */\nexport function deployNotice(logger, message) {\n    if (typeof logger?.notice === \"function\") logger.notice(message);\n    else logger?.info?.(message);\n}\n\nexport async function appendDeployLog(deployLogPath, message) {\n    await mkdir(deployLogPath.replace(/\\/[^/]+$/, \"\"), { recursive: true });\n    const line = `[${new Date().toISOString()}] ${message}\\n`;\n    await appendFile(deployLogPath, line);\n}\n","import { access } from \"node:fs/promises\";\n\nimport { servicePaths } from \"./paths.js\";\nimport { run } from \"./run.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nexport async function cloneRepo(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n\n    if (await pathExists(paths.repo)) {\n        throw new Error(`Repo already exists at ${paths.repo} — use git pull instead`);\n    }\n    if (dryRun) {\n        logger.info(`[dryRun] would git clone ${service.repoUrl} ${paths.repo}`);\n        return;\n    }\n\n    await run(\"git\", [\"clone\", service.repoUrl, paths.repo], { logger });\n    logger.info(`cloned ${service.repoUrl} → ${paths.repo}`);\n}\n\nexport async function pullRepo(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n\n    if (!(await pathExists(paths.repo))) {\n        throw new Error(`Repo missing at ${paths.repo} — run provision first`);\n    }\n    if (dryRun) {\n        logger.info(`[dryRun] would git -C ${paths.repo} pull --ff-only`);\n        return;\n    }\n\n    await run(\"git\", [\"-C\", paths.repo, \"pull\", \"--ff-only\"], { logger });\n    logger.info(`pulled ${paths.repo}`);\n}\n","import { cp, mkdir, readlink, readdir, stat } from \"node:fs/promises\";\nimport { join, dirname as pathDirname, sep } from \"node:path\";\n\nimport { releaseDir, releaseStamp, servicePaths } from \"./paths.js\";\n\nconst SKIP_TOP = new Set([\"node_modules\", \".git\"]);\n\nfunction shouldCopyEntry(srcPath) {\n    const parts = srcPath.split(sep);\n    if (parts.some((p) => p === \"node_modules\" || p === \".git\")) return false;\n    const top = parts.at(-1);\n    if (parts.length === 1 && SKIP_TOP.has(top)) return false;\n    return true;\n}\n\n/** Copy the run dir into releases/<stamp>/ (excluding node_modules and .git). */\nexport async function createRelease(service, options = {}) {\n    const { stamp = releaseStamp(), dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n    const dest = releaseDir(paths.releases, stamp);\n\n    if (dryRun) {\n        logger.info(`[dryRun] would copy ${paths.repoRun} → ${dest}`);\n        return { stamp, path: dest };\n    }\n\n    await mkdir(paths.releases, { recursive: true });\n    await cp(paths.repoRun, dest, {\n        recursive: true,\n        filter: (src) => shouldCopyEntry(src),\n    });\n\n    logger.info(`release ${stamp} created at ${dest}`);\n    return { stamp, path: dest };\n}\n\n/** Resolve current release path if symlink exists. */\nexport async function readCurrentRelease(paths) {\n    try {\n        const target = await readlink(paths.current);\n        return target.startsWith(\"/\") ? target : join(pathDirname(paths.current), target);\n    } catch {\n        return null;\n    }\n}\n\nexport async function listReleases(paths) {\n    let names;\n    try {\n        names = await readdir(paths.releases);\n    } catch {\n        return [];\n    }\n\n    const entries = [];\n    for (const name of names) {\n        const full = releaseDir(paths.releases, name);\n        const s = await stat(full);\n        if (s.isDirectory()) entries.push({ name, path: full, mtime: s.mtime });\n    }\n\n    entries.sort((a, b) => b.name.localeCompare(a.name));\n    return entries;\n}\n","import { symlink, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n/** Point current → release and link shared/.env inside the release. */\nexport async function activateRelease(releasePath, paths, options = {}) {\n    const { dryRun = false, logger = console } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would activate ${releasePath} → ${paths.current}`);\n        return;\n    }\n\n    try {\n        await unlink(paths.current);\n    } catch {\n        // first deploy\n    }\n    await symlink(releasePath, paths.current);\n\n    const envLink = join(releasePath, \".env\");\n    try {\n        await unlink(envLink);\n    } catch {\n        // ok\n    }\n    await symlink(paths.sharedEnv, envLink);\n\n    logger.info(`active release: ${releasePath}`);\n}\n","import { createHash } from \"node:crypto\";\nimport { access, cp, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { readCurrentRelease } from \"./release.js\";\nimport { npmInstallEnv, run } from \"./run.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nasync function lockfileHash(releasePath) {\n    const lockPath = join(releasePath, \"package-lock.json\");\n    try {\n        const buf = await readFile(lockPath);\n        return createHash(\"sha256\").update(buf).digest(\"hex\");\n    } catch {\n        return null; // no lockfile → can't fingerprint; always (re)install\n    }\n}\n\nasync function readHashFile(path) {\n    try {\n        return (await readFile(path, \"utf8\")).trim();\n    } catch {\n        return null;\n    }\n}\n\nasync function npmInstall(releasePath, hasLock, logger) {\n    await rm(join(releasePath, \"node_modules\"), { recursive: true, force: true });\n    const cmd = hasLock ? [\"ci\", \"--include=dev\"] : [\"install\", \"--include=dev\", \"--no-audit\", \"--no-fund\"];\n    logger.info(`running npm ${cmd.join(\" \")} in ${releasePath}`);\n    await run(\"npm\", cmd, { cwd: releasePath, logger, env: npmInstallEnv() });\n}\n\n/**\n * Install deps in the release. If the lockfile is unchanged from the active\n * release and its node_modules exists, copy it (fast path); otherwise npm ci.\n */\nexport async function installDeps(service, releasePath, paths, options = {}) {\n    const { dryRun = false, logger = console } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would install deps in ${releasePath}`);\n        return { hash: null, copied: false };\n    }\n\n    const hash = await lockfileHash(releasePath);\n    const hasLock = hash !== null;\n    const hashMarker = join(releasePath, \".deploy-package-lock.sha256\");\n\n    const currentPath = await readCurrentRelease(paths);\n    let copied = false;\n\n    if (hasLock && currentPath && (await pathExists(join(currentPath, \"node_modules\")))) {\n        const currentHash = await readHashFile(join(currentPath, \".deploy-package-lock.sha256\"));\n        if (currentHash === hash) {\n            logger.info(\"lockfile unchanged — copying node_modules from current release\");\n            await cp(join(currentPath, \"node_modules\"), join(releasePath, \"node_modules\"), {\n                recursive: true,\n                force: true,\n            });\n            copied = true;\n        }\n    }\n\n    if (!copied) {\n        await npmInstall(releasePath, hasLock, logger);\n    }\n\n    if (hasLock) {\n        await writeFile(hashMarker, `${hash}\\n`, \"utf8\");\n        await mkdir(paths.shared, { recursive: true });\n        await writeFile(paths.lockHashFile, `${hash}\\n`, \"utf8\");\n    }\n\n    return { hash, copied };\n}\n","import { symlink, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { npmInstallEnv, runShell } from \"./run.js\";\n\n/**\n * Symlink shared/.env into the release and run the service's testCommand (a shell\n * one-liner, e.g. \"npm run test:ci\"). No-op when the service defines no command.\n */\nexport async function runReleaseTests(service, releasePath, paths, options = {}) {\n    const { dryRun = false, logger = console } = options;\n\n    if (!service.testCommand) {\n        logger.info(\"no testCommand configured — skipping tests\");\n        return;\n    }\n\n    if (dryRun) {\n        logger.info(`[dryRun] would run \"${service.testCommand}\" in ${releasePath}`);\n        return;\n    }\n\n    const envLink = join(releasePath, \".env\");\n    try {\n        await unlink(envLink);\n    } catch {\n        // no existing link\n    }\n    await symlink(paths.sharedEnv, envLink);\n\n    logger.info(`running \"${service.testCommand}\" in ${releasePath}`);\n    await runShell(service.testCommand, { cwd: releasePath, logger, env: npmInstallEnv() });\n}\n","import { rm, readlink } from \"node:fs/promises\";\n\nimport { listReleases } from \"./release.js\";\n\n/**\n * Remove old releases, keeping the newest N (always keeps the active one).\n *\n * @param {object} service\n * @param {object} paths\n * @param {{ dryRun?: boolean, logger?: object, protect?: string[] }} [options]\n *   `protect` — release stamp names that must not be deleted (e.g. still-running\n *   previous release during a rolling deploy).\n */\nexport async function pruneReleases(service, paths, options = {}) {\n    const { dryRun = false, logger = console, protect = [] } = options;\n    const keep = service.keepReleases ?? 3;\n    const releases = await listReleases(paths);\n\n    let activeName = null;\n    try {\n        const target = await readlink(paths.current);\n        activeName = target.split(\"/\").pop();\n    } catch {\n        // no current\n    }\n\n    const keepSet = new Set();\n    for (const rel of releases) {\n        if (keepSet.size < keep) keepSet.add(rel.name);\n    }\n    if (activeName) keepSet.add(activeName);\n    for (const name of protect) {\n        if (name) keepSet.add(name);\n    }\n\n    const toRemove = releases.filter((rel) => !keepSet.has(rel.name));\n    for (const rel of toRemove) {\n        if (dryRun) {\n            logger.info(`[dryRun] would rm -rf ${rel.path}`);\n        } else {\n            await rm(rel.path, { recursive: true, force: true });\n            logger.info(`pruned ${rel.path}`);\n        }\n    }\n\n    return { removed: toRemove.map((r) => r.name) };\n}\n","import { runShell, runCapture } from \"./run.js\";\n\nfunction sleep(ms) {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** True if `pid` still exists (same host). */\nexport function isPidAlive(pid) {\n    const n = Number(pid);\n    if (!Number.isFinite(n) || n <= 0) return false;\n    try {\n        process.kill(n, 0);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\n/**\n * Parse `pm2 jlist` stdout. When the daemon was not running, pm2 prints\n * \"[PM2] Spawning PM2 daemon…\" on stdout before the JSON array.\n *\n * @param {string} stdout\n * @returns {unknown[]}\n */\nexport function parsePm2Jlist(stdout) {\n    const raw = String(stdout ?? \"\");\n    // Drop \"[PM2] Spawning…\" banners (stdout when the daemon was not running).\n    const text = raw\n        .split(\"\\n\")\n        .filter((line) => !line.startsWith(\"[PM2]\"))\n        .join(\"\\n\")\n        .trim();\n    if (!text) return [];\n    try {\n        const parsed = JSON.parse(text);\n        return Array.isArray(parsed) ? parsed : [];\n    } catch (err) {\n        throw new Error(`pm2 jlist: invalid JSON (${err?.message ?? err})`);\n    }\n}\n\n/**\n * Parse `pm2 jlist` and return the process entry for `appName`, or null.\n *\n * @param {string} appName\n * @param {{ logger?: { info?: Function, warn?: Function } }} [options]\n * @returns {Promise<object|null>}\n */\nexport async function getPm2Process(appName, options = {}) {\n    const { logger } = options;\n    // Warm the daemon so spawn banners do not race the next jlist (best-effort).\n    await runCapture(\"bash\", [\"-lc\", \"pm2 ping >/dev/null 2>&1 || true\"], { logger }).catch(() => {});\n    const { stdout } = await runCapture(\"bash\", [\"-lc\", \"pm2 jlist\"], { logger });\n    let list;\n    try {\n        list = parsePm2Jlist(stdout);\n    } catch (err) {\n        throw new Error(`pm2 jlist: invalid JSON (${err?.message ?? err})`);\n    }\n    return list.find((p) => p?.name === appName) ?? null;\n}\n\n/**\n * Poll pm2 until `predicate(proc)` is true (proc may be null if missing), or timeout.\n *\n * @param {string} appName\n * @param {(proc: object|null) => boolean} predicate\n * @param {{ timeoutMs?: number, pollMs?: number, dryRun?: boolean, logger?: object, label?: string }} [options]\n */\nexport async function waitPm2(appName, predicate, options = {}) {\n    const {\n        timeoutMs = 65_000,\n        pollMs = 500,\n        dryRun = false,\n        logger = console,\n        label = \"condition\",\n    } = options;\n\n    if (dryRun) {\n        logger.info?.(`[dryRun] would wait pm2 ${appName} for ${label}`);\n        return null;\n    }\n\n    const deadline = Date.now() + timeoutMs;\n    let lastStatus = \"(unknown)\";\n    while (Date.now() < deadline) {\n        const proc = await getPm2Process(appName, { logger });\n        lastStatus = proc?.pm2_env?.status ?? \"(missing)\";\n        if (predicate(proc)) return proc;\n        await sleep(pollMs);\n    }\n    throw new Error(\n        `pm2 wait timed out after ${timeoutMs}ms for ${appName} (${label}); last status=${lastStatus}`\n    );\n}\n\n/**\n * True when pm2 reports the app online on a *new* pid (old process fully gone).\n * Avoids treating a not-yet-dead pre-reload process as a successful restart.\n */\nexport function isFreshOnline(proc, oldPid) {\n    if (proc?.pm2_env?.status !== \"online\") return false;\n    const pid = Number(proc.pid);\n    if (!Number.isFinite(pid) || pid <= 0) return false;\n    if (oldPid != null) {\n        if (pid === oldPid) return false;\n        if (isPidAlive(oldPid)) return false;\n    }\n    return true;\n}\n\n/**\n * Remove app from pm2 (SIGINT + kill_timeout drain) and wait until gone.\n * No-op if the app is not present.\n */\nasync function deletePm2App(appName, options = {}) {\n    const { dryRun = false, logger = console, waitTimeoutMs = 65_000, oldPid = null } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would pm2 delete ${appName}`);\n        return;\n    }\n\n    const before = await getPm2Process(appName, { logger });\n    if (!before) {\n        logger.info(`pm2 ${appName}: not present (skip delete)`);\n        return;\n    }\n\n    await runShell(`pm2 delete \"${appName}\"`, { logger });\n    await waitPm2(\n        appName,\n        (proc) => {\n            if (proc) return false;\n            if (oldPid != null && isPidAlive(oldPid)) return false;\n            return true;\n        },\n        { timeoutMs: waitTimeoutMs, logger, label: \"deleted (process gone)\" }\n    );\n    logger.info(`pm2 ${appName} deleted`);\n}\n\n/** Fresh `pm2 start <ecosystem> --update-env` with production ENV on the CLI. */\nasync function startFromEcosystem(paths, options = {}) {\n    const { dryRun = false, logger = console } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would pm2 start ${paths.ecosystem} --update-env`);\n        return;\n    }\n\n    // Prefix ENV on the pm2 CLI: --update-env copies the invoking shell env.\n    await runShell(\n        `ENV=production NODE_ENV=production pm2 start \"${paths.ecosystem}\" --update-env`,\n        { logger }\n    );\n    logger.info(\"pm2 started from ecosystem\");\n}\n\n/**\n * Rolling restart: `pm2 delete` then `pm2 start <ecosystem> --update-env`.\n *\n * Prefer delete+start over `startOrReload --update-env`: reload can leave a first\n * spawn with a stale/wrong ENV (e.g. S3 profile=local) and does not refresh\n * immutable fields like `script` / `node_args`. Delete honors kill_timeout so the\n * old process can drain, then start applies the full ecosystem.\n */\nexport async function reloadPm2(paths, options = {}) {\n    const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65_000 } = options;\n\n    if (dryRun) {\n        logger.info(\n            `[dryRun] would pm2 delete${appName ? ` ${appName}` : \"\"} + start ${paths.ecosystem} --update-env`\n        );\n        return;\n    }\n\n    let oldPid = null;\n    if (appName) {\n        const before = await getPm2Process(appName, { logger });\n        const n = Number(before?.pid);\n        if (Number.isFinite(n) && n > 0 && before?.pm2_env?.status === \"online\") {\n            oldPid = n;\n            logger.info(`pm2 ${appName}: recreate (old pid=${oldPid})`);\n        }\n        await deletePm2App(appName, { dryRun, logger, waitTimeoutMs, oldPid });\n    } else {\n        logger.warn?.(\n            \"reloadPm2: appName missing; starting ecosystem without delete \" +\n                \"(pass appName so script/env always recreate cleanly)\"\n        );\n    }\n\n    await startFromEcosystem(paths, { dryRun, logger });\n\n    if (appName) {\n        const proc = await waitPm2(\n            appName,\n            (p) => isFreshOnline(p, oldPid),\n            {\n                timeoutMs: waitTimeoutMs,\n                logger,\n                label: oldPid\n                    ? `online on new pid (old ${oldPid} gone)`\n                    : \"online after recreate\",\n            }\n        );\n        logger.info(`pm2 ${appName} online pid=${proc?.pid ?? \"?\"}`);\n    }\n}\n\n/** `pm2 stop <app>` and wait until status is stopped (or process missing). */\nexport async function stopPm2(appName, options = {}) {\n    const { dryRun = false, logger = console, waitTimeoutMs = 65_000 } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would pm2 stop ${appName}`);\n        return;\n    }\n\n    const before = await getPm2Process(appName, { logger });\n    if (!before) {\n        logger.info(`pm2 ${appName}: not present (already stopped)`);\n        return;\n    }\n    if (before.pm2_env?.status === \"stopped\") {\n        logger.info(`pm2 ${appName}: already stopped`);\n        return;\n    }\n\n    const oldPid = Number(before.pid);\n    await runShell(`pm2 stop \"${appName}\"`, { logger });\n    await waitPm2(\n        appName,\n        (proc) => {\n            if (proc && proc.pm2_env?.status !== \"stopped\") return false;\n            if (Number.isFinite(oldPid) && oldPid > 0 && isPidAlive(oldPid)) return false;\n            return true;\n        },\n        { timeoutMs: waitTimeoutMs, logger, label: \"stopped\" }\n    );\n    logger.info(`pm2 ${appName} stopped`);\n}\n\n/**\n * `pm2 start <ecosystem> --update-env` after deleting any existing registration\n * so immutable fields (script, node_args) and env always come from the ecosystem.\n */\nexport async function startPm2(paths, options = {}) {\n    const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65_000 } = options;\n\n    if (dryRun) {\n        logger.info(\n            `[dryRun] would pm2 delete${appName ? ` ${appName}` : \"\"} + start ${paths.ecosystem} --update-env`\n        );\n        return;\n    }\n\n    if (appName) {\n        // stopFirst leaves a stopped registration; delete so start is a full recreate.\n        await deletePm2App(appName, { dryRun, logger, waitTimeoutMs });\n    }\n\n    await startFromEcosystem(paths, { dryRun, logger });\n\n    if (appName) {\n        const proc = await waitPm2(\n            appName,\n            (p) => isFreshOnline(p, null),\n            { timeoutMs: waitTimeoutMs, logger, label: \"online after start\" }\n        );\n        logger.info(`pm2 ${appName} online pid=${proc?.pid ?? \"?\"}`);\n    }\n}\n","import { writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { runShell } from \"./run.js\";\n\nasync function hasTlsCert(certPath) {\n    try {\n        await runShell(`sudo test -f '${certPath}'`, {});\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nfunction proxyBlock(port) {\n    return `  location / {\n    proxy_pass http://127.0.0.1:${port};\n    proxy_http_version 1.1;\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header X-Forwarded-Proto $scheme;\n    proxy_read_timeout 120s;\n  }`;\n}\n\nfunction buildNginxConfig(service) {\n    const { nginx, pm2 } = service;\n    const certDir = `/etc/letsencrypt/live/${nginx.fqdn}`;\n\n    return `# ${nginx.siteName} — managed by cli-toolkit deploy (proxy mode)\n# ${nginx.fqdn} → 127.0.0.1:${pm2.port}\n\nserver {\n  listen 80;\n  listen [::]:80;\n  server_name ${nginx.fqdn};\n  location / { return 301 https://$host$request_uri; }\n}\n\nserver {\n  listen 443 ssl;\n  listen [::]:443 ssl;\n  server_name ${nginx.fqdn};\n\n  ssl_certificate ${certDir}/fullchain.pem;\n  ssl_certificate_key ${certDir}/privkey.pem;\n  include /etc/letsencrypt/options-ssl-nginx.conf;\n  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;\n\n  client_max_body_size 25m;\n\n${proxyBlock(pm2.port)}\n}\n`;\n}\n\nfunction buildNginxConfigHttpOnly(service) {\n    const { nginx, pm2 } = service;\n    return `# ${nginx.siteName} — managed by cli-toolkit deploy (HTTP proxy, no TLS cert yet)\n\nserver {\n  listen 80;\n  listen [::]:80;\n  server_name ${nginx.fqdn};\n\n  client_max_body_size 25m;\n\n${proxyBlock(pm2.port)}\n}\n`;\n}\n\n/** Replace the stub nginx site with a reverse-proxy to the app. */\nexport async function enableNginxUpstream(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const { nginx } = service;\n    if (!nginx) {\n        logger.info(\"no nginx config on service — skipping nginx step\");\n        return { skipped: true };\n    }\n\n    const siteAvailable = `/etc/nginx/sites-available/${nginx.siteName}`;\n    const siteEnabled = `/etc/nginx/sites-enabled/${nginx.siteName}`;\n    const cert = `/etc/letsencrypt/live/${nginx.fqdn}/fullchain.pem`;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would write ${siteAvailable} (proxy → 127.0.0.1:${service.pm2.port}) and reload nginx`);\n        return { hasCert: null };\n    }\n\n    const hasCert = await hasTlsCert(cert);\n    const config = hasCert ? buildNginxConfig(service) : buildNginxConfigHttpOnly(service);\n\n    const tmp = join(tmpdir(), `${service.name}-nginx.conf`);\n    await writeFile(tmp, config);\n    await runShell(\n        `sudo cp '${tmp}' '${siteAvailable}' && sudo ln -sf '${siteAvailable}' '${siteEnabled}' && sudo nginx -t && sudo systemctl reload nginx`,\n        { logger },\n    );\n\n    logger.info(`nginx upstream enabled for ${nginx.fqdn} → 127.0.0.1:${service.pm2.port} (tls=${hasCert})`);\n    return { hasCert };\n}\n","import { access, mkdir, readFile, writeFile } from \"node:fs/promises\";\n\nimport { servicePaths } from \"./paths.js\";\n\n/**\n * Drop .env lines matching any of the service's envScrubPatterns (regex source\n * strings). Useful to strip empty keys that would crash strict param validation.\n */\nexport function scrubEnvContent(content, patterns = []) {\n    const regexes = patterns.map((p) => (p instanceof RegExp ? p : new RegExp(p)));\n    if (regexes.length === 0) return content;\n    return content\n        .split(\"\\n\")\n        .filter((line) => !regexes.some((re) => re.test(line.trim())))\n        .join(\"\\n\");\n}\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\n/** Copy <repoRun>/.env → shared/.env (with optional legacy fallback + scrubbing). */\nexport async function syncEnv(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n    const patterns = service.envScrubPatterns ?? [];\n\n    if (dryRun) {\n        logger.info(`[dryRun] would sync ${paths.repoEnv} → ${paths.sharedEnv}`);\n        return { source: paths.repoEnv, dest: paths.sharedEnv };\n    }\n\n    let source = paths.repoEnv;\n    if (!(await pathExists(source)) && service.legacyRepoEnv && (await pathExists(service.legacyRepoEnv))) {\n        logger.info(`using legacy env: ${service.legacyRepoEnv}`);\n        source = service.legacyRepoEnv;\n    }\n\n    await mkdir(paths.shared, { recursive: true });\n\n    if (!(await pathExists(source))) {\n        if (service.requireEnv) {\n            throw new Error(\n                `No .env found at ${paths.repoEnv}` +\n                    (service.legacyRepoEnv ? ` or ${service.legacyRepoEnv}` : \"\") +\n                    \" — place .env on the host or run the remote deploy from a laptop with a local .env (auto-scp)\",\n            );\n        }\n        // Optional env: ensure shared/.env exists so the per-release symlink is valid.\n        if (!(await pathExists(paths.sharedEnv))) {\n            await writeFile(paths.sharedEnv, \"\", { mode: 0o600 });\n        }\n        logger.warn(`no .env found (source ${source}) — using empty ${paths.sharedEnv}`);\n        return { source: null, dest: paths.sharedEnv };\n    }\n\n    const raw = await readFile(source, \"utf8\");\n    await writeFile(paths.sharedEnv, scrubEnvContent(raw, patterns), { mode: 0o600 });\n    logger.info(`synced ${source} → ${paths.sharedEnv}`);\n    return { source, dest: paths.sharedEnv };\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nimport { readCurrentRelease } from \"./release.js\";\nimport { servicePaths } from \"./paths.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Bump semver patch (0.1.0 → 0.1.1). */\nexport function bumpPatchVersion(version) {\n    const parts = String(version).trim().split(\".\");\n    const major = Number.parseInt(parts[0], 10) || 0;\n    const minor = Number.parseInt(parts[1], 10) || 0;\n    const patch = Number.parseInt(parts[2], 10) || 0;\n    return `${major}.${minor}.${patch + 1}`;\n}\n\nasync function readJson(path) {\n    try {\n        return JSON.parse(await readFile(path, \"utf8\"));\n    } catch {\n        return null;\n    }\n}\n\nasync function gitShortCommit(repoPath) {\n    try {\n        const { stdout } = await execFileAsync(\"git\", [\"-C\", repoPath, \"rev-parse\", \"--short\", \"HEAD\"], {\n            encoding: \"utf8\",\n        });\n        return stdout.trim() || null;\n    } catch {\n        return null;\n    }\n}\n\n/**\n * Next semver: bump patch from the **currently active** release's build-info,\n * else seed from package.json. Each release carries its own build-info.json so a\n * rollback restores that release's label.\n */\nexport async function resolveNextVersion(service, paths, pkgPath) {\n    const pkg = (await readJson(pkgPath)) ?? {};\n    const baseVersion = pkg.version || \"0.1.0\";\n\n    const currentPath = await readCurrentRelease(paths);\n    if (currentPath) {\n        const active = await readJson(join(currentPath, service.buildInfoPath));\n        if (active?.version) return bumpPatchVersion(active.version);\n    }\n    return baseVersion;\n}\n\n/** Read build-info from a release directory (for rollback logs / status). */\nexport async function readReleaseBuildInfo(service, releasePath) {\n    return readJson(join(releasePath, service.buildInfoPath));\n}\n\n/** Write build-info.json into the new release directory. */\nexport async function writeReleaseBuildInfo(service, releasePath, { stamp, dryRun = false, logger = console }) {\n    const paths = servicePaths(service);\n    const pkgPath = join(paths.repoRun, \"package.json\");\n\n    const version = await resolveNextVersion(service, paths, pkgPath);\n    const gitCommit = await gitShortCommit(paths.repo);\n\n    const buildInfo = {\n        version,\n        release: stamp,\n        deployedAt: new Date().toISOString(),\n        gitCommit,\n        service: service.name,\n    };\n\n    const dest = join(releasePath, service.buildInfoPath);\n\n    if (dryRun) {\n        logger.info(`[dryRun] would write ${dest} (${JSON.stringify(buildInfo)})`);\n        return buildInfo;\n    }\n\n    await mkdir(dirname(dest), { recursive: true });\n    await writeFile(dest, `${JSON.stringify(buildInfo, null, 2)}\\n`, { mode: 0o644 });\n\n    const gitSuffix = gitCommit ? ` git=${gitCommit}` : \"\";\n    logger.info(`build info: v${version} release=${stamp}${gitSuffix}`);\n    return buildInfo;\n}\n","import { access, appendFile, mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { servicePaths } from \"./paths.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\n/** Fail fast with a useful message when not on a provisioned host. */\nasync function requireDeployRoot(parentDir, serviceRoot) {\n    if (await pathExists(parentDir)) return;\n    throw new Error(\n        `Cannot create ${serviceRoot}: parent directory ${parentDir} does not exist.\\n` +\n            `This is meant to run on the target host (where ${parentDir} exists). ` +\n            `For a local dry run use --appsRoot=/tmp/<service>.`,\n    );\n}\n\nfunction resolveKillTimeoutMs(pm2) {\n    const explicit = Number(pm2?.killTimeout);\n    if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);\n    const stopSec = Number(pm2?.stopAllowance);\n    if (Number.isFinite(stopSec) && stopSec > 0) return Math.floor(stopSec * 1000) + 5000;\n    return 65_000;\n}\n\n/** How often pm2 re-sends SIGINT / logs \"failed to kill - retrying in …\" (ms). */\nconst DEFAULT_KILL_RETRY_TIME_MS = 10_000;\n\nfunction resolveKillRetryTimeMs(pm2) {\n    const explicit = Number(pm2?.killRetryTime);\n    if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);\n    return DEFAULT_KILL_RETRY_TIME_MS;\n}\n\n/** Append `--stopAllowance=<sec>` to pm2 args when manifest sets pm2.stopAllowance. */\nfunction resolvePm2Args(pm2) {\n    const base = String(pm2?.args ?? \"\").trim();\n    const stopSec = Number(pm2?.stopAllowance);\n    if (!Number.isFinite(stopSec) || stopSec <= 0) return base;\n    if (/(?:^|\\s)--stopAllowance=/.test(base)) return base;\n    return `${base}${base ? \" \" : \"\"}--stopAllowance=${Math.floor(stopSec)}`.trim();\n}\n\n/** CJS snippet required before the app — always force production on deployed hosts. */\nfunction buildEnsureEnvScript() {\n    return `/**\n * Written by cli-toolkit deploy (init-structure). Do not hand-edit.\n * Preloaded via pm2 node_args --require. Always set (do not only fill when unset):\n * \\`pm2 start … --update-env\\` can inject a non-production ENV from the\n * deploy shell / prior dump, and a conditional assign would leave it in place.\n */\nprocess.env.ENV = \"production\";\nprocess.env.NODE_ENV = \"production\";\n`;\n}\n\nfunction buildEcosystemConfig(service, paths) {\n    const { pm2 } = service;\n    const outLog = join(paths.logs, `${pm2.appName}.out.log`);\n    const errLog = join(paths.logs, `${pm2.appName}.err.log`);\n    const killTimeoutMs = resolveKillTimeoutMs(pm2);\n    const killRetryTimeMs = resolveKillRetryTimeMs(pm2);\n    const args = resolvePm2Args(pm2);\n    const ensureEnv = paths.ensureEnv;\n\n    return `/**\n * pm2 ecosystem for ${service.name} — written by cli-toolkit deploy from the\n * service manifest (init/deploy). Do not hand-edit; change pm2.* in the\n * manifest and redeploy. cwd → \\`current\\` symlink.\n */\nmodule.exports = {\n    apps: [\n        {\n            name: \"${pm2.appName}\",\n            script: \"${pm2.script}\",\n            cwd: \"${paths.current}\",\n            args: ${JSON.stringify(args)},\n            // Absolute --require so ENV is set before Args constructs (see shared/ensure-env.cjs).\n            node_args: ${JSON.stringify(`--require ${ensureEnv}`)},\n            instances: 1,\n            exec_mode: \"fork\",\n            autorestart: true,\n            min_uptime: \"10s\",\n            max_restarts: 10,\n            restart_delay: 2000,\n            max_memory_restart: \"1500M\",\n            // Grace window after SIGINT/SIGTERM before SIGKILL (ms). Align with --stopAllowance.\n            kill_timeout: ${killTimeoutMs},\n            // How often pm2 re-checks / logs \"failed to kill - retrying in …\"\n            // while waiting for graceful exit (pm2 default 100ms → noisy logs).\n            kill_retry_time: ${killRetryTimeMs},\n            out_file: \"${outLog}\",\n            error_file: \"${errLog}\",\n            merge_logs: true,\n            time: true,\n            env: {\n                // cli-toolkit Args: ENV selects env-suffixed defaults (DB_NAME_PRODUCTION, BUCKET_PRODUCTION, …)\n                ENV: \"production\",\n                NODE_ENV: \"production\",\n            },\n        },\n    ],\n};\n`;\n}\n\n/** Create <appsRoot>/{releases,shared,logs} and sync shared/ecosystem.config.cjs from the manifest. */\nexport async function initServiceStructure(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n    const dirs = [paths.releases, paths.shared, paths.logs];\n    const created = [];\n    const skipped = [];\n\n    if (!dryRun) {\n        await requireDeployRoot(dirname(paths.root), paths.root);\n    }\n\n    for (const dir of dirs) {\n        if (await pathExists(dir)) {\n            skipped.push(dir);\n            continue;\n        }\n        if (!dryRun) await mkdir(dir, { recursive: true });\n        created.push(dir);\n    }\n\n    const ecosystemExisted = await pathExists(paths.ecosystem);\n    const ensureEnvExisted = await pathExists(paths.ensureEnv);\n    if (!dryRun) {\n        await writeFile(paths.ensureEnv, buildEnsureEnvScript(), { mode: 0o644 });\n        await writeFile(paths.ecosystem, buildEcosystemConfig(service, paths), { mode: 0o644 });\n    }\n    if (ensureEnvExisted) {\n        logger.info(`synced ${paths.ensureEnv}`);\n    } else {\n        created.push(paths.ensureEnv);\n        logger.info(`seeded ${paths.ensureEnv}`);\n    }\n    if (ecosystemExisted) {\n        logger.info(`synced ${paths.ecosystem} from manifest`);\n    } else {\n        created.push(paths.ecosystem);\n        logger.info(`seeded ${paths.ecosystem}`);\n    }\n\n    const line = `[${new Date().toISOString()}] init-structure service=${service.name} dryRun=${dryRun} created=${created.length} skipped=${skipped.length} ecosystem=synced\\n`;\n    if (!dryRun) {\n        await mkdir(paths.logs, { recursive: true });\n        await appendFile(paths.deployLog, line);\n    }\n\n    logger.info(`service=${service.name} appsRoot=${paths.root}`);\n    logger.info(`created: ${created.length ? created.join(\", \") : \"(none)\"}`);\n    logger.info(`already present: ${skipped.length ? skipped.join(\", \") : \"(none)\"}`);\n\n    return { paths, created, skipped, ecosystemCreated: !ecosystemExisted, ecosystemSynced: true };\n}\n","import { execSync } from \"node:child_process\";\nimport { access, chmod, copyFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\n\nimport { runShell } from \"./run.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nfunction expandHome(path) {\n    return path.startsWith(\"~/\") ? join(homedir(), path.slice(2)) : path;\n}\n\nasync function ensurePm2Startup(options = {}) {\n    const { user = \"ubuntu\", dryRun = false, logger = console } = options;\n\n    if (dryRun) {\n        logger.info(\"[dryRun] would configure pm2 startup systemd\");\n        return;\n    }\n\n    try {\n        execSync(\"pm2 ping\", { stdio: \"ignore\" });\n    } catch {\n        // pm2 daemon may not be up yet\n    }\n\n    try {\n        const out = execSync(`pm2 startup systemd -u ${user} --hp /home/${user}`, { encoding: \"utf8\" });\n        const sudoLine = out.split(\"\\n\").find((l) => l.trim().startsWith(\"sudo\"));\n        if (sudoLine) {\n            execSync(sudoLine.trim(), { stdio: \"inherit\" });\n            logger.info(\"pm2 startup systemd configured\");\n        }\n    } catch (err) {\n        logger.warn(`pm2 startup skipped or already configured: ${err.message}`);\n    }\n}\n\nasync function installDeployKey(deployKeyPath, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const keyPath = expandHome(deployKeyPath);\n\n    if (!(await pathExists(keyPath))) {\n        logger.warn(`deploy key not found at ${keyPath} — skipping git ssh setup`);\n        return;\n    }\n\n    const keyBase = basename(keyPath);\n    const sshDir = join(homedir(), \".ssh\");\n    const destKey = join(sshDir, keyBase);\n    const configPath = join(sshDir, \"config\");\n    const block = `\nHost github.com\n  HostName github.com\n  User git\n  IdentityFile ${destKey}\n  IdentitiesOnly yes\n`;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would install deploy key ${keyPath} → ${destKey}`);\n        return;\n    }\n\n    await mkdir(sshDir, { recursive: true, mode: 0o700 });\n    await copyFile(keyPath, destKey);\n    await chmod(destKey, 0o600);\n\n    let config = \"\";\n    if (await pathExists(configPath)) config = await readFile(configPath, \"utf8\");\n    if (!config.includes(\"Host github.com\")) {\n        await writeFile(configPath, `${config.trimEnd()}\\n${block}\\n`, { mode: 0o600 });\n        logger.info(\"updated ~/.ssh/config for github.com\");\n    }\n    logger.info(`deploy key installed at ${destKey}`);\n}\n\nasync function installLogrotate(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const conf = `/etc/logrotate.d/${service.name}`;\n    const body = `${service.appsRoot}/logs/*.log {\n  daily\n  rotate 14\n  compress\n  delaycompress\n  missingok\n  notifempty\n  copytruncate\n}\n`;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would write ${conf}`);\n        return;\n    }\n\n    const tmp = join(\"/tmp\", `${service.name}-logrotate.conf`);\n    await writeFile(tmp, body);\n    await runShell(`sudo cp '${tmp}' '${conf}'`, { logger });\n    logger.info(`logrotate config written: ${conf}`);\n}\n\nconst OPERATOR_SHELL_BEGIN = \"# >>> mlsfarm-operator >>>\";\nconst OPERATOR_SHELL_END = \"# <<< mlsfarm-operator <<<\";\n\n/**\n * Idempotent ~/.bashrc block: ENV=production + cd into /apps/<service>/current\n * on interactive login. Safe to re-run; replaces any prior managed block.\n */\nexport async function installOperatorShell(service, options = {}) {\n    const { user = \"ubuntu\", dryRun = false, logger = console } = options;\n    const appsRoot = service.appsRoot;\n    if (!appsRoot) {\n        logger.warn(\"installOperatorShell: service.appsRoot missing — skipped\");\n        return;\n    }\n\n    const home = user === \"ubuntu\" || user === process.env.USER\n        ? join(homedir(), \".bashrc\")\n        : `/home/${user}/.bashrc`;\n    const currentDir = join(appsRoot, \"current\");\n    const block = [\n        OPERATOR_SHELL_BEGIN,\n        \"# Managed by cli-toolkit deploy bootstrap — do not edit by hand.\",\n        'export ENV=production',\n        `if [ -d \"${currentDir}\" ]; then`,\n        `  cd \"${currentDir}\" || true`,\n        \"fi\",\n        OPERATOR_SHELL_END,\n        \"\",\n    ].join(\"\\n\");\n\n    if (dryRun) {\n        logger.info(`[dryRun] would update ${home} (ENV=production, cd ${currentDir})`);\n        return;\n    }\n\n    let existing = \"\";\n    if (await pathExists(home)) {\n        existing = await readFile(home, \"utf8\");\n    }\n\n    const begin = existing.indexOf(OPERATOR_SHELL_BEGIN);\n    const end = existing.indexOf(OPERATOR_SHELL_END);\n    let next;\n    if (begin !== -1 && end !== -1 && end > begin) {\n        const afterEnd = end + OPERATOR_SHELL_END.length;\n        const rest = existing.slice(afterEnd).replace(/^\\n/, \"\");\n        next = `${existing.slice(0, begin).replace(/\\s*$/, \"\\n\")}${block}${rest}`;\n    } else {\n        next = `${existing.replace(/\\s*$/, \"\\n\")}\\n${block}`;\n    }\n\n    await writeFile(home, next, { mode: 0o644 });\n    logger.info(`operator shell: ${home} → ENV=production, cd ${currentDir}`);\n}\n\n/** One-time host prep: pm2 systemd, optional git deploy key, logrotate, operator shell. */\nexport async function bootstrapHost(service, options = {}) {\n    const { deployKey = service.deployKey, user = \"ubuntu\", dryRun = false, logger = console } = options;\n\n    await ensurePm2Startup({ user, dryRun, logger });\n    if (deployKey) await installDeployKey(deployKey, { dryRun, logger });\n    await installLogrotate(service, { dryRun, logger });\n    await installOperatorShell(service, { user, dryRun, logger });\n    logger.info(\"bootstrap-host complete\");\n}\n","import { readlink } from \"node:fs/promises\";\n\nimport { initServiceStructure } from \"./init-structure.js\";\nimport { appendDeployLog, deployNotice } from \"./log.js\";\nimport { pullRepo } from \"./git.js\";\nimport { createRelease } from \"./release.js\";\nimport { installDeps } from \"./deps.js\";\nimport { runReleaseTests } from \"./test.js\";\nimport { activateRelease } from \"./activate.js\";\nimport { pruneReleases } from \"./prune.js\";\nimport { reloadPm2, stopPm2, startPm2 } from \"./pm2.js\";\nimport { enableNginxUpstream } from \"./nginx.js\";\nimport { syncEnv } from \"./sync-env.js\";\nimport { writeReleaseBuildInfo } from \"./build-info.js\";\nimport { servicePaths } from \"./paths.js\";\n\n/**\n * Resolve pm2 kill_timeout (ms). Prefer manifest `pm2.killTimeout`, else\n * stopAllowance seconds × 1000 + 5s buffer, else 65s.\n */\nfunction resolveKillTimeoutMs(service) {\n    const explicit = Number(service.pm2?.killTimeout);\n    if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);\n    const stopSec = Number(service.pm2?.stopAllowance);\n    if (Number.isFinite(stopSec) && stopSec > 0) return Math.floor(stopSec * 1000) + 5000;\n    return 65_000;\n}\n\n/**\n * Full deploy: pull → env → release → deps → test → activate → pm2 → prune → nginx.\n *\n * Default (**rolling**): keep the process running while the new release is built and\n * `current` is flipped; then `pm2 delete` + `pm2 start` (SIGINT + kill_timeout drain,\n * then full ecosystem recreate) so script/node_args/env always apply. Previous\n * release is not pruned until after that restart.\n *\n * **`--stopFirst`**: `pm2 stop` + wait → activate/prune → delete + `pm2 start`.\n * Use when a runner is wedged and will not honor graceful stop.\n */\nexport async function deployService(service, options = {}) {\n    const {\n        dryRun = false,\n        skipPull = false,\n        skipTests = false,\n        skipNginx = false,\n        stopFirst = false,\n        logger = console,\n    } = options;\n\n    const paths = servicePaths(service);\n    const appName = service.pm2.appName;\n    const killTimeoutMs = resolveKillTimeoutMs(service);\n    const waitTimeoutMs = killTimeoutMs + 10_000;\n\n    deployNotice(logger, `Prepare ${service.name} directories`);\n    await initServiceStructure(service, { dryRun, logger });\n\n    if (!skipPull) {\n        deployNotice(logger, \"Pull latest repository\");\n        await pullRepo(service, { dryRun, logger });\n    }\n\n    deployNotice(logger, \"Sync environment\");\n    await syncEnv(service, { dryRun, logger });\n\n    deployNotice(logger, \"Create release\");\n    const { stamp, path: releasePath } = await createRelease(service, { dryRun, logger });\n    await writeReleaseBuildInfo(service, releasePath, { stamp, dryRun, logger });\n\n    deployNotice(logger, \"Install dependencies\");\n    await installDeps(service, releasePath, paths, { dryRun, logger });\n\n    if (!skipTests) {\n        deployNotice(logger, \"Run release tests\");\n        await runReleaseTests(service, releasePath, paths, { dryRun, logger });\n    }\n\n    let previousReleaseName = null;\n    try {\n        const prev = await readlink(paths.current);\n        previousReleaseName = prev.split(\"/\").pop() || null;\n    } catch {\n        // first deploy\n    }\n\n    if (stopFirst) {\n        logger.info(`deploy mode=stopFirst app=${appName} killTimeoutMs=${killTimeoutMs}`);\n        deployNotice(logger, `Stop ${appName}`);\n        await stopPm2(appName, { dryRun, logger, waitTimeoutMs });\n        deployNotice(logger, \"Activate release\");\n        await activateRelease(releasePath, paths, { dryRun, logger });\n        deployNotice(logger, \"Prune old releases\");\n        await pruneReleases(service, paths, { dryRun, logger });\n        deployNotice(logger, \"Start pm2\");\n        await startPm2(paths, { dryRun, logger, appName, waitTimeoutMs });\n    } else {\n        logger.info(\n            `deploy mode=rolling app=${appName} killTimeoutMs=${killTimeoutMs}` +\n                (previousReleaseName ? ` previous=${previousReleaseName}` : \"\")\n        );\n        deployNotice(logger, \"Activate release\");\n        await activateRelease(releasePath, paths, { dryRun, logger });\n        // Restart into new `current` before pruning the previous tree (still in use by the old process).\n        deployNotice(logger, \"Reload pm2\");\n        await reloadPm2(paths, { dryRun, logger, appName, waitTimeoutMs });\n        deployNotice(logger, \"Prune old releases\");\n        await pruneReleases(service, paths, { dryRun, logger });\n    }\n\n    if (!skipNginx) {\n        deployNotice(logger, \"Update nginx upstream\");\n        await enableNginxUpstream(service, { dryRun, logger });\n    }\n\n    const summary = `deploy complete stamp=${stamp} mode=${stopFirst ? \"stopFirst\" : \"rolling\"} dryRun=${dryRun}`;\n    deployNotice(logger, `Deploy complete (${stamp})`);\n    logger.info(summary);\n    if (!dryRun) await appendDeployLog(paths.deployLog, summary);\n\n    return { stamp, releasePath, mode: stopFirst ? \"stopFirst\" : \"rolling\" };\n}\n","import { access } from \"node:fs/promises\";\n\nimport { bootstrapHost } from \"./bootstrap-host.js\";\nimport { initServiceStructure } from \"./init-structure.js\";\nimport { cloneRepo, pullRepo } from \"./git.js\";\nimport { deployService } from \"./deploy-service.js\";\nimport { deployNotice } from \"./log.js\";\nimport { syncEnv } from \"./sync-env.js\";\nimport { servicePaths } from \"./paths.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\n/** First-time setup: optional bootstrap, init dirs, clone/pull, sync .env, first deploy. */\nexport async function provisionService(service, options = {}) {\n    const {\n        dryRun = false,\n        deploy = true,\n        skipBootstrap = true,\n        deployKey,\n        logger = console,\n    } = options;\n\n    if (!skipBootstrap) {\n        deployNotice(logger, \"Bootstrap host (pm2, deploy key, operator shell)\");\n        await bootstrapHost(service, { deployKey, dryRun, logger });\n    }\n\n    deployNotice(logger, `Prepare ${service.name} directories`);\n    await initServiceStructure(service, { dryRun, logger });\n    const paths = servicePaths(service);\n\n    if (await pathExists(paths.repo)) {\n        deployNotice(logger, \"Pull existing repository\");\n        logger.info(`repo exists at ${paths.repo} — pulling`);\n        await pullRepo(service, { dryRun, logger });\n    } else {\n        deployNotice(logger, \"Clone repository\");\n        await cloneRepo(service, { dryRun, logger });\n    }\n\n    deployNotice(logger, \"Sync environment\");\n    await syncEnv(service, { dryRun, logger });\n\n    if (deploy) {\n        deployNotice(logger, \"Run first deploy\");\n        await deployService(service, { dryRun, logger, skipPull: true });\n    } else {\n        deployNotice(logger, \"Provision complete (deploy skipped)\");\n        logger.info(\"provision complete (deploy skipped)\");\n    }\n}\n","import { readlink } from \"node:fs/promises\";\n\nimport { activateRelease } from \"./activate.js\";\nimport { readReleaseBuildInfo } from \"./build-info.js\";\nimport { appendDeployLog, deployNotice } from \"./log.js\";\nimport { listReleases } from \"./release.js\";\nimport { reloadPm2 } from \"./pm2.js\";\nimport { servicePaths } from \"./paths.js\";\n\n/** Flip current to a named release or the previous one. */\nexport async function rollbackService(service, options = {}) {\n    const { release: targetName, dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n    const releases = await listReleases(paths);\n\n    if (releases.length === 0) throw new Error(\"No releases to roll back to\");\n\n    let activeName = null;\n    try {\n        const target = await readlink(paths.current);\n        activeName = target.split(\"/\").pop();\n    } catch {\n        throw new Error(\"No active release (current symlink missing)\");\n    }\n\n    let rollbackTarget;\n    if (targetName) {\n        rollbackTarget = releases.find((r) => r.name === targetName);\n        if (!rollbackTarget) throw new Error(`Release not found: ${targetName}`);\n    } else {\n        rollbackTarget = releases.find((r) => r.name !== activeName);\n        if (!rollbackTarget) throw new Error(\"No previous release to roll back to\");\n    }\n\n    if (rollbackTarget.name === activeName) throw new Error(`Already on release ${activeName}`);\n\n    deployNotice(logger, `Rollback ${activeName} → ${rollbackTarget.name}`);\n    logger.info(`rollback ${activeName} → ${rollbackTarget.name}`);\n    const buildInfo = await readReleaseBuildInfo(service, rollbackTarget.path);\n    if (buildInfo?.version) {\n        logger.info(`rollback target: v${buildInfo.version} release=${buildInfo.release ?? rollbackTarget.name}`);\n    }\n    deployNotice(logger, \"Activate previous release\");\n    await activateRelease(rollbackTarget.path, paths, { dryRun, logger });\n    const appName = service.pm2?.appName ?? null;\n    const waitTimeoutMs = 65_000;\n    deployNotice(logger, \"Reload pm2\");\n    await reloadPm2(paths, { dryRun, logger, appName, waitTimeoutMs });\n\n    const summary = `rollback ${activeName} → ${rollbackTarget.name} dryRun=${dryRun}`;\n    deployNotice(logger, `Rollback complete (${rollbackTarget.name})`);\n    if (!dryRun) await appendDeployLog(paths.deployLog, summary);\n\n    return { from: activeName, to: rollbackTarget.name, path: rollbackTarget.path };\n}\n","import { access, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\nimport { spawn } from \"node:child_process\";\n\nimport { scrubEnvContent } from \"./sync-env.js\";\nimport { servicePaths } from \"./paths.js\";\nimport { deployNotice } from \"./log.js\";\n\n/** Path (relative to the run dir on the server) of the toolkit deploy CLI. */\nexport const REMOTE_CLI_REL = \"node_modules/@nmakarov/cli-toolkit/scripts/deploy/cli.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nfunction expandHome(path) {\n    return path.startsWith(\"~/\") ? join(homedir(), path.slice(2)) : path;\n}\n\nfunction resolveLocalEnvPath(envFile) {\n    if (envFile) {\n        const expanded = expandHome(envFile);\n        return expanded.startsWith(\"/\") ? expanded : join(process.cwd(), expanded);\n    }\n    return join(process.cwd(), \".env\");\n}\n\n/** Parse the ssh host out of a git url (git@host:..., ssh://git@host/...). null for https. */\nexport function parseGitHost(repoUrl) {\n    const u = String(repoUrl ?? \"\");\n    let m = u.match(/^[^@]+@([^:]+):/); // git@github.com:org/repo.git\n    if (m) return m[1];\n    m = u.match(/^ssh:\\/\\/[^@]+@([^/:]+)/); // ssh://git@github.com/org/repo.git\n    if (m) return m[1];\n    return null;\n}\n\nexport function shellQuote(value) {\n    return `'${String(value).replace(/'/g, `'\\\\''`)}'`;\n}\n\nexport function sshRun(host, remoteCommand, options = {}) {\n    const { logger } = options;\n    return new Promise((resolve, reject) => {\n        logger?.info?.(`ssh ${host} ${remoteCommand.slice(0, 120)}${remoteCommand.length > 120 ? \"…\" : \"\"}`);\n        const child = spawn(\"ssh\", [host, remoteCommand], { stdio: \"inherit\" });\n        child.on(\"error\", reject);\n        child.on(\"close\", (code) => (code === 0 ? resolve() : reject(new Error(`ssh ${host} exited with code ${code}`))));\n    });\n}\n\nfunction scp(localPath, remoteSpec) {\n    return new Promise((resolve, reject) => {\n        const child = spawn(\"scp\", [localPath, remoteSpec], { stdio: \"inherit\" });\n        child.on(\"error\", reject);\n        child.on(\"close\", (code) => (code === 0 ? resolve() : reject(new Error(`scp exited with code ${code}`))));\n    });\n}\n\n/** Copy a git deploy key from the laptop to the server (no-op if not present locally). */\nexport async function ensureDeployKeyOnRemote(host, deployKeyPath, options = {}) {\n    const { logger = console } = options;\n    if (!deployKeyPath) return false;\n    const localPath = expandHome(deployKeyPath);\n    if (!(await pathExists(localPath))) return false;\n\n    const keyBase = basename(localPath);\n    deployNotice(logger, `Copy deploy key to ${host}`);\n    logger.info(`copying deploy key ${localPath} → ${host}:~/.ssh/${keyBase}`);\n    await sshRun(host, \"mkdir -p ~/.ssh && chmod 700 ~/.ssh\", { logger });\n    await scp(localPath, `${host}:.ssh/${keyBase}`, { logger });\n    await sshRun(host, `chmod 600 ~/.ssh/${keyBase}`, { logger });\n    return true;\n}\n\n/** known_hosts for the git host + (optional) ~/.ssh/config IdentityFile for the deploy key. */\nexport async function prepareGitHost(host, options = {}) {\n    const { logger = console, gitHost, keyBasename } = options;\n    if (!gitHost) return;\n\n    const configBlock = keyBasename\n        ? `if ! grep -q 'Host ${gitHost}' ~/.ssh/config 2>/dev/null; then\n  printf '%s\\\\n' '' 'Host ${gitHost}' '  HostName ${gitHost}' '  User git' '  IdentityFile ~/.ssh/${keyBasename}' '  IdentitiesOnly yes' >> ~/.ssh/config\n  chmod 600 ~/.ssh/config\n  echo \"configured ~/.ssh/config for ${gitHost}\"\nfi`\n        : `:`;\n\n    const script = `\nset -euo pipefail\nmkdir -p ~/.ssh\nchmod 700 ~/.ssh\nif ! grep -q '^${gitHost}' ~/.ssh/known_hosts 2>/dev/null; then\n  ssh-keyscan -t ed25519,rsa ${gitHost} >> ~/.ssh/known_hosts 2>/dev/null\n  echo \"added ${gitHost} to known_hosts\"\nfi\n${configBlock}\n`.trim();\n\n    await sshRun(host, script, { logger });\n}\n\n/** Install the run-dir workspace deps so the toolkit CLI is available on the server. */\nexport async function ensureRepoDependencies(host, service, options = {}) {\n    const { logger = console } = options;\n    const paths = servicePaths(service);\n    const run = shellQuote(paths.repoRun);\n    await sshRun(\n        host,\n        `cd ${run} && if [ ! -d node_modules/@nmakarov/cli-toolkit ] || [ package-lock.json -nt node_modules/.package-lock.json ]; then npm ci; fi`,\n        { logger },\n    );\n}\n\n/** Copy laptop .env → server run-dir .env (scrubbed). sync-env then copies it to shared/. */\nexport async function ensureEnvOnRemote(host, service, options = {}) {\n    const { logger = console, envFile } = options;\n    const paths = servicePaths(service);\n    const localPath = resolveLocalEnvPath(envFile);\n    if (!(await pathExists(localPath))) return false;\n\n    deployNotice(logger, `Copy environment to ${host}`);\n    logger.info(`copying .env ${localPath} → ${host}:${paths.repoEnv}`);\n    await sshRun(host, `mkdir -p ${shellQuote(dirname(paths.repoEnv))}`, { logger });\n\n    const scrubbed = scrubEnvContent(await readFile(localPath, \"utf8\"), service.envScrubPatterns ?? []);\n    const tmp = join(tmpdir(), `deploy-env-${Date.now()}`);\n    await writeFile(tmp, scrubbed, { mode: 0o600 });\n    await scp(tmp, `${host}:${paths.repoEnv}`, { logger });\n    await sshRun(host, `chmod 600 ${shellQuote(paths.repoEnv)}`, { logger });\n    return true;\n}\n\n/** Ensure a checkout exists on the server, then pull latest + deps + env. */\nexport async function ensureRemoteRepo(host, service, options = {}) {\n    const { logger = console, deployKey = service.deployKey, envFile } = options;\n    const paths = servicePaths(service);\n    const repo = shellQuote(paths.repo);\n    const repoUrl = shellQuote(service.repoUrl);\n    const root = shellQuote(paths.root);\n\n    const localKeyBase = deployKey ? basename(expandHome(deployKey)) : null;\n    await ensureDeployKeyOnRemote(host, deployKey, { logger });\n    await prepareGitHost(host, { logger, gitHost: parseGitHost(service.repoUrl), keyBasename: localKeyBase });\n\n    await sshRun(\n        host,\n        `mkdir -p ${root} && if [ -d ${repo}/.git ]; then git -C ${repo} pull --ff-only; else git clone ${repoUrl} ${repo}; fi`,\n        { logger },\n    );\n\n    await ensureRepoDependencies(host, service, { logger });\n    await ensureEnvOnRemote(host, service, { logger, envFile });\n}\n\n/**\n * Invoke the toolkit deploy CLI on the server in local mode (no --host), passing\n * the same --service/--manifests + extra flags. Run after ensureRemoteRepo.\n */\nexport async function runRemoteCli(host, service, command, args = [], options = {}) {\n    const { logger = console, manifests, skipPull = false, deployKey = service.deployKey, envFile } = options;\n    const paths = servicePaths(service);\n    const run = shellQuote(paths.repoRun);\n    const cli = shellQuote(REMOTE_CLI_REL);\n\n    if (!skipPull) {\n        deployNotice(logger, `Prepare checkout and dependencies on ${host}`);\n        await ensureRemoteRepo(host, service, { logger, deployKey, envFile });\n    } else {\n        deployNotice(logger, `Install host CLI dependencies on ${host}`);\n        await ensureRepoDependencies(host, service, { logger });\n        await ensureEnvOnRemote(host, service, { logger, envFile });\n    }\n\n    deployNotice(logger, `Run ${command} on ${host}`);\n\n    const passthrough = [\n        `--service=${service.name}`,\n        ...(manifests ? [`--manifests=${manifests}`] : []),\n        ...args,\n    ].map(shellQuote).join(\" \");\n\n    await sshRun(host, `cd ${run} && node ${cli} ${shellQuote(command)} ${passthrough}`.trim(), { logger });\n}\n\nexport async function runRemoteStatus(host, service, options = {}) {\n    const { logger = console } = options;\n    const paths = servicePaths(service);\n    const port = service.pm2.port;\n    const app = service.pm2.appName;\n\n    const script = `\necho \"=== apps root ===\"\nls -la ${shellQuote(paths.root)} 2>/dev/null || echo \"(missing)\"\necho \"\"\necho \"=== current ===\"\nreadlink ${shellQuote(paths.current)} 2>/dev/null || echo \"(not set)\"\necho \"\"\necho \"=== releases ===\"\nls -1 ${shellQuote(paths.releases)} 2>/dev/null || echo \"(none)\"\necho \"\"\necho \"=== pm2 ===\"\npm2 describe ${app} 2>/dev/null | head -20 || pm2 status ${app} 2>/dev/null || echo \"(not running)\"\n${port ? `echo \"\"\necho \"=== app health (localhost) ===\"\ncurl -sf http://127.0.0.1:${port}/healthz 2>/dev/null || echo \"(no /healthz on :${port})\"` : \"\"}\n`.trim();\n\n    await sshRun(host, script, { logger });\n}\n","import { isAbsolute, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport { defineService } from \"./service.js\";\n\n/**\n * Load a project's service manifests module. The module may export:\n *   export const services = { \"my-svc\": { … }, … }   // map\n *   export default { \"my-svc\": { … } }                // map as default\n *   export const services = [ { name: \"my-svc\", … } ] // array\n * Every entry is normalized through defineService().\n *\n * @param {{ manifests?: string, cwd?: string }} opts  manifests = path to the module\n * @returns {Promise<Record<string, object>>} name → normalized service\n */\nexport async function loadServices({ manifests = \"deploy/services.js\", cwd = process.cwd() } = {}) {\n    const abs = isAbsolute(manifests) ? manifests : resolve(cwd, manifests);\n    let mod;\n    try {\n        mod = await import(pathToFileURL(abs).href);\n    } catch (err) {\n        throw new Error(`Could not load deploy manifests from ${abs}: ${err.message}`);\n    }\n\n    const raw = mod.services ?? mod.default;\n    if (!raw) {\n        throw new Error(`Manifests module ${abs} must export \\`services\\` (or default): a map or array of service manifests`);\n    }\n\n    const list = Array.isArray(raw) ? raw : Object.values(raw);\n    const out = {};\n    for (const entry of list) {\n        const svc = defineService(entry);\n        out[svc.name] = svc;\n    }\n    return out;\n}\n\n/** Resolve one normalized service by name (optionally overriding appsRoot). */\nexport function resolveServiceFrom(serviceMap, name, { appsRoot } = {}) {\n    const svc = serviceMap[name];\n    if (!svc) {\n        throw new Error(`Unknown service \"${name}\". Known: ${Object.keys(serviceMap).join(\", \") || \"(none)\"}`);\n    }\n    return appsRoot ? { ...svc, appsRoot } : svc;\n}\n","import os from \"node:os\";\nimport { sleepMs, toJsonColumn } from \"../utils/index.js\";\nimport {\n    registerInServicesRegistry,\n    touchServicesRegistry,\n    unregisterServicesRegistry,\n} from \"./servicesRegistry.js\";\nimport {\n    enqueueTask,\n    ensureTaskTables,\n    queueToTableNames,\n    taskHistoryInsertFromQueueRow,\n    createTaskProgressReporter,\n    loggerTaskLabel,\n} from \"./taskUtils.js\";\nimport { appendTaskIpcLog } from \"./taskLogs.js\";\nimport { nextTimeMatch, timeMatcher } from \"./time-matcher.js\";\nexport {\n    timeMatcher,\n    nextTimeMatch,\n    matchesParsedPattern,\n    convertPattern,\n    resolveAsterisks,\n    resolveRanges,\n    resolveSteps,\n} from \"./time-matcher.js\";\nimport { TasksRegistry } from \"./TasksRegistry.js\";\nimport { normalizeAllowedTasks } from \"./serviceTaskAllowlist.js\";\nimport {\n    controlLaneTaskNames,\n    ensureTasksRuntime,\n    readLoopRuntime,\n    mergeRuntimeParamSpecs,\n    runtimeValuesForSpecs,\n} from \"./runtimeParams.js\";\nimport { maybePruneTaskRetention, seedTaskRetentionRuntime } from \"./taskRetention.js\";\nimport { applyClaimOrder, compareClaimCandidates } from \"./claimOrder.js\";\n\n/** Sentinel value stored in the `progress` column when a task is paused due to error. */\nconst LOCKED_BY_ERROR_MESSAGE = \"locked by error\";\n\n/**\n * Next `params` to persist on the queue row. Long-running tasks return\n * `results.checkpointParams` so pause, hard stop, and the next scheduled\n * tick resume from the same cursor (offset / pending unit) instead of\n * starting the next window.\n *\n * @param {object|null|undefined} results\n * @returns {object|null}\n */\nexport function checkpointParamsFromResults(results) {\n    if (!results || typeof results !== \"object\") return null;\n    const next = results.checkpointParams;\n    return next && typeof next === \"object\" && !Array.isArray(next) ? next : null;\n}\n\nexport {\n    enqueueTask,\n    ensureTaskTables,\n    queueToTableNames,\n    taskHistoryInsertFromQueueRow,\n    updateTaskProgress,\n    createTaskProgressReporter,\n    loggerTaskLabel,\n    setLoggerTaskLabelResolver,\n} from \"./taskUtils.js\";\nexport {\n    listServicesRegistry,\n    registerInServicesRegistry,\n    touchServicesRegistry,\n    unregisterServicesRegistry,\n    updateServicesRegistryMetadata,\n    setGroupMaxInstancesDefaults,\n    resolveGroupMaxInstances,\n} from \"./servicesRegistry.js\";\n/** @deprecated Use registerInServicesRegistry */\nexport { registerInServicesRegistry as registerRunnerHeartbeat } from \"./servicesRegistry.js\";\n/** @deprecated Use touchServicesRegistry */\nexport { touchServicesRegistry as touchRunnerHeartbeat } from \"./servicesRegistry.js\";\n/** @deprecated Use unregisterServicesRegistry */\nexport { unregisterServicesRegistry as unregisterRunnerHeartbeat } from \"./servicesRegistry.js\";\n/** @deprecated Use listServicesRegistry */\nexport { listServicesRegistry as listAliveRunnerHeartbeats } from \"./servicesRegistry.js\";\nexport {\n    appendTaskIpcLog,\n    filterIpcLogRecords,\n    flushTaskIpcLogs,\n    ipcFileLogsTableNameForSourceResource,\n    readTaskIpcLogsSnapshot,\n    resolveIpcFileLogsDir,\n    pruneIpcLogsOlderThan,\n    planIpcLogPrune,\n    tasksLogsRoot,\n} from \"./taskLogs.js\";\nexport {\n    maybePruneTaskRetention,\n    pruneTaskRetention,\n    seedTaskRetentionRuntime,\n    readRetentionConfig,\n    effectiveRetentionDays,\n    retentionCutoffIso,\n    retentionCutoffFromHours,\n    deleteHistoryOlderThan,\n} from \"./taskRetention.js\";\nexport {\n    setTaskRetentionNameRulesDefaults,\n    resolveRetentionNameRules,\n    parseRetentionNameRulesRaw,\n} from \"./taskRetentionNameRules.js\";\nexport { TaskPruneTaskRetention } from \"./coreTasks/TaskPruneTaskRetention.js\";\nexport { runNodeTaskScript } from \"./taskScriptRunner.js\";\nexport { AbstractTask } from \"./AbstractTask.js\";\nexport { TasksRegistry } from \"./TasksRegistry.js\";\nexport { TaskPing } from \"./coreTasks/TaskPing.js\";\nexport { TaskSampleProcess } from \"./coreTasks/TaskSampleProcess.js\";\nexport { TaskShellCommand } from \"./coreTasks/TaskShellCommand.js\";\nexport { TaskSystemInfo } from \"./coreTasks/TaskSystemInfo.js\";\nexport { TaskSumAB } from \"./coreTasks/TaskSumAB.js\";\nexport { TaskStopRunner } from \"./coreTasks/TaskStopRunner.js\";\nexport {\n    TaskPauseRunner,\n    TaskUnpauseRunner,\n    applyRunnerPaused,\n} from \"./coreTasks/TaskPauseRunner.js\";\nexport {\n    TaskPauseTask,\n    TaskResumeTask,\n    applyPauseTask,\n    applyResumeTask,\n} from \"./coreTasks/TaskPauseTask.js\";\nexport { TaskGetLogs } from \"./coreTasks/TaskGetLogs.js\";\nexport { TaskSetRuntimeParam } from \"./coreTasks/TaskSetRuntimeParam.js\";\nexport {\n    normalizeAllowedTasks,\n    mergeAllowedTasksWithServiceTasks,\n    SERVICE_TASK_NAMES,\n} from \"./serviceTaskAllowlist.js\";\nexport {\n    applyClaimOrder,\n    claimDueInstantMs,\n    compareClaimCandidates,\n    isClaimDue,\n} from \"./claimOrder.js\";\nexport {\n    applyRuntimeParam,\n    applyRuntimePatch,\n    coerceRuntimeValue,\n    controlLaneTaskNames,\n    ensureTasksRuntime,\n    readLoopRuntime,\n    mergeRuntimeParamSpecs,\n    runtimeValuesForSpecs,\n    runtimeParamSpecsFromMetadata,\n    LOOP_RUNTIME_KEYS,\n    LOGGER_RUNTIME_KEYS,\n    DEFAULT_RUNTIME_PARAM_SPECS,\n} from \"./runtimeParams.js\";\n\n/** Shared default registry preloaded with every core task (including legacy aliases). */\nexport const defaultTasksRegistry = TasksRegistry.withCoreTasks();\n\n/**\n * Fail-fast accessor for `context.db` with a tasks-specific error message.\n *\n * @param {object} context\n * @returns {Function}\n */\nfunction getDb(context) {\n    const db = context.db;\n    if (!db) {\n        throw new Error(\"Tasks component requires context.db. Initialize DB first and attach to context.\");\n    }\n    return db;\n}\n\n/**\n * Coerce whatever the caller passed as `registry` into a `TasksRegistry` instance:\n *\n *   - `undefined` / missing → {@link defaultTasksRegistry} (every core task)\n *   - already a `TasksRegistry` → returned as-is\n *   - plain `{ name: Class }` map → wrapped in a fresh registry\n *\n * @param {TasksRegistry | Record<string, Function> | undefined} registry\n * @returns {TasksRegistry}\n */\nfunction normalizeRegistry(registry) {\n    if (!registry) return defaultTasksRegistry;\n    if (registry instanceof TasksRegistry) return registry;\n    return new TasksRegistry().addMany(registry);\n}\n\n/**\n * Convenience for enqueuing a targeted `stopRunner` task so a specific service\n * group exits cleanly on its next tick. Intended for operator tooling — the\n * runner itself also accepts in-process stop signals via `context.isStop()`.\n *\n * @param {object} context\n * @param {string} serviceGroup\n * @param {string} [queueName]\n * @param {number} [allowanceMs]\n * @returns {Promise<string>} UUID of the enqueued stop task.\n */\nexport async function enqueueStopTask(context, serviceGroup, queueName = \"tasks\", allowanceMs = 60_000) {\n    return enqueueTask(context, {\n        queueName,\n        name: \"stopRunner\",\n        params: { allowanceMs },\n        priority: 0,\n        serviceGroup,\n    });\n}\n\n/**\n * Broadcast a cooperative stop signal to every currently-running task instance.\n * Tasks decide per-call how much of `allowanceMs` to honor; we also emit on\n * `context.emitter` so other subscribers (e.g. fetchers) can wind down.\n *\n * @param {object} context\n * @param {Map<string, { requestStop?: Function }>} runningTaskInstances\n * @param {number} allowanceMs\n * @returns {Promise<void>}\n */\n/**\n * If an operator deleted a queue row while the task is still running, ask that\n * instance to stop. Delete is a different process (tasksmm) and cannot call\n * requestStop itself.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {Map<string, { requestStop?: Function }>} runningTaskInstances\n */\nexport async function signalStopForDeletedQueueRows(context, tasksTable, runningTaskInstances) {\n    if (!runningTaskInstances?.size) return;\n    const db = context?.db;\n    if (!db) return;\n    const ids = [...runningTaskInstances.keys()];\n    let alive;\n    try {\n        const rows = await db(tasksTable).whereIn(\"id\", ids).select(\"id\");\n        alive = new Set((Array.isArray(rows) ? rows : []).map((r) => r.id));\n    } catch {\n        return;\n    }\n    for (const [id, inst] of runningTaskInstances) {\n        if (alive.has(id)) continue;\n        context.logger?.warn?.(`[tasks] queue row ${id} deleted — requesting stop`);\n        if (typeof inst.requestStop === \"function\") {\n            try {\n                await inst.requestStop(0);\n            } catch (error) {\n                context.logger?.warn?.(\"[tasks] task requestStop failed:\", error);\n            }\n        }\n    }\n}\n\nasync function signalRunningTasksStop(context, runningTaskInstances, allowanceMs) {\n    context.logger.warn?.(`[tasks] signaling ${runningTaskInstances.size} running task(s) to stop`);\n    for (const [, taskInstance] of runningTaskInstances) {\n        if (typeof taskInstance.requestStop === \"function\") {\n            try {\n                await taskInstance.requestStop(allowanceMs);\n            } catch (error) {\n                context.logger.warn?.(\"[tasks] task requestStop failed:\", error);\n            }\n        }\n    }\n    context.emitter.emit(\"stop\", allowanceMs);\n}\n\n/**\n * Run a single claimed task row end-to-end:\n *\n *   1. Resolve its class from the registry (unknown name → record failure + remove/pause).\n *   2. Construct an instance, stash it in `runningTaskInstances` so stop signals can reach it.\n *   3. `await instance.run(reportProgress)`; capture thrown errors into a structured `results` payload.\n *   4. Append a row to the history table, update/delete/pause the queue row depending on schedule/success.\n *   5. Return a summary telling the loop whether a `stopRunner` was requested.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {string} historyTable\n * @param {object} row              The claimed queue row.\n * @param {TasksRegistry} registry\n * @param {Map<string, object>} runningTaskInstances\n * @returns {Promise<{ stopRunnerRequested: boolean, stopAllowanceMs: number }>}\n */\nasync function executeClaimedTask(context, tasksTable, historyTable, row, registry, runningTaskInstances) {\n    const db = getDb(context);\n    const taskName = row.name;\n    const TaskClass = registry.get(taskName);\n    if (!TaskClass) {\n        const err = { message: `Unknown task \"${taskName}\"` };\n        await db(historyTable).insert(\n            taskHistoryInsertFromQueueRow(row, {\n                completed_at: new Date(),\n                success: false,\n                status: \"failed\",\n                status_changed_at: db.fn.now(),\n                params: toJsonColumn(row.params),\n                results: toJsonColumn(err),\n            })\n        );\n        if (row.schedule) {\n            await db(tasksTable).where({ id: row.id }).update({\n                started_at: null,\n                completed_at: new Date(),\n                success: false,\n                results: toJsonColumn(err),\n                past_due: null,\n                status: \"paused\",\n                status_changed_at: db.fn.now(),\n                progress: LOCKED_BY_ERROR_MESSAGE,\n            });\n        } else {\n            await db(tasksTable).where({ id: row.id }).delete();\n        }\n        return { stopRunnerRequested: false, stopAllowanceMs: 0 };\n    }\n\n    let success = false;\n    let results = null;\n    let taskInstance = null;\n    try {\n        const taskLogger =\n            typeof context.logger?.child === \"function\"\n                ? context.logger.child(loggerTaskLabel(row))\n                : context.logger;\n        const taskContext =\n            taskLogger && taskLogger !== context.logger ? { ...context, logger: taskLogger } : context;\n        taskInstance = new TaskClass(taskContext, row);\n        runningTaskInstances.set(row.id, taskInstance);\n        const reportProgress = createTaskProgressReporter(taskContext, tasksTable, row.id);\n        const runResult = await taskInstance.run(reportProgress);\n        success = !!runResult?.success;\n        results = runResult?.results ?? null;\n    } catch (error) {\n        success = false;\n        results = {\n            message: error?.message ?? String(error),\n            name: error?.name ?? \"Error\",\n            stack: error?.stack ?? null,\n        };\n    } finally {\n        runningTaskInstances.delete(row.id);\n    }\n\n    const taskPaused =\n        success && results && typeof results === \"object\" && results.taskPaused === true;\n\n    await db(historyTable).insert(\n        taskHistoryInsertFromQueueRow(row, {\n            completed_at: new Date(),\n            success,\n            status: taskPaused ? \"paused\" : success ? \"completed\" : \"failed\",\n            status_changed_at: db.fn.now(),\n            params: toJsonColumn(row.params),\n            results: toJsonColumn(results),\n        })\n    );\n    if (!success) {\n        const dbName = String(context?.params?.get?.(\"dbName\") || \"local\");\n        const tableName = String(context?.params?.get?.(\"table\") || \"tasks\");\n        const fallbackRecoverCommand = [\n            \"node\",\n            \"examples/tasks/recover-task.js\",\n            `--dbName='${dbName.replace(/'/g, `'\\\\''`)}'`,\n            `--table='${tableName.replace(/'/g, `'\\\\''`)}'`,\n            `--id='${String(row.id).replace(/'/g, `'\\\\''`)}'`,\n        ].join(\" \");\n        const rerunCommand = results && typeof results === \"object\" && results.rerunCommand\n            ? results.rerunCommand\n            : fallbackRecoverCommand;\n        appendTaskIpcLog(context, row, {\n            level: \"error\",\n            message: `[tasks] task failed: ${row.name} id=${row.id}. Once problem is fixed, re-run: ${rerunCommand}`,\n            details: results,\n        });\n    }\n\n    // Cooperative pause: keep the queue row as paused with optional checkpoint params.\n    // Survives runner restart — resumeTask (or manual status→idle) continues later.\n    if (taskPaused) {\n        const checkpointParams = checkpointParamsFromResults(results) ?? row.params;\n        const progressPayload =\n            results.progress != null\n                ? results.progress\n                : { paused: true, pausedAt: new Date().toISOString(), message: \"paused\" };\n        await db(tasksTable).where({ id: row.id }).update({\n            started_at: null,\n            completed_at: new Date(),\n            success: true,\n            results: toJsonColumn(results),\n            params: toJsonColumn(checkpointParams),\n            progress: toJsonColumn(progressPayload),\n            status: \"paused\",\n            status_changed_at: db.fn.now(),\n            past_due: null,\n            service_name: null,\n            server_name: null,\n            instance_number: null,\n        });\n    } else if (row.schedule) {\n        if (success) {\n            let nextRunAt = null;\n            try {\n                nextRunAt = nextTimeMatch(row.schedule, new Date());\n            } catch (e) {\n                context.logger?.warn?.(`[tasks] nextTimeMatch after success for task ${row.id}: ${e?.message ?? String(e)}`);\n            }\n            const checkpointParams = checkpointParamsFromResults(results);\n            await db(tasksTable).where({ id: row.id }).update({\n                started_at: null,\n                completed_at: new Date(),\n                success,\n                results: toJsonColumn(results),\n                progress: null,\n                past_due: null,\n                status: \"idle\",\n                status_changed_at: db.fn.now(),\n                next_run_at: nextRunAt,\n                ...(checkpointParams ? { params: toJsonColumn(checkpointParams) } : {}),\n                // Claim overwrites these; clear so idle rows stay “any worker” (see claimNextRunnableTask).\n                service_name: null,\n                server_name: null,\n                instance_number: null,\n            });\n        } else {\n            await db(tasksTable).where({ id: row.id }).update({\n                started_at: null,\n                completed_at: new Date(),\n                success,\n                results: toJsonColumn(results),\n                status: \"paused\",\n                status_changed_at: db.fn.now(),\n                progress: LOCKED_BY_ERROR_MESSAGE,\n                past_due: null,\n            });\n        }\n    } else {\n        await db(tasksTable).where({ id: row.id }).delete();\n    }\n\n    const stopRunnerRequested = !!(results && typeof results === \"object\" && results.stopRunner === true);\n    const stopAllowanceMs = stopRunnerRequested ? Number(results.allowanceMs ?? 60_000) : 0;\n    scheduleTaskRetentionPass(context, historyTable);\n    return { stopRunnerRequested, stopAllowanceMs };\n}\n\nfunction scheduleTaskRetentionPass(context, historyTable) {\n    void maybePruneTaskRetention(context, {\n        historyTable,\n        queueName: context.tasksQueueName,\n    }).catch((err) => {\n        context.logger?.warn?.(`[tasks-retention] ${err?.message ?? String(err)}`);\n    });\n}\n\n/**\n * Atomically claim one runnable task row matching the caller's service group /\n * identity / allowlist, and return the (now-`running`) row — or `null` when none\n * are ready.\n *\n * Targeting rules for task columns (`service_group`, `service_name`, `server_name`,\n * `instance_number`): NULL on the task row means \"any\" for that field; a value\n * means \"this runner must match exactly\". This lets operators enqueue a task for\n * a specific host/instance while letting other rows fan out to whoever is free.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {string} serviceGroup\n * @param {TasksRegistry} registry\n * @param {number} scanLimit How many candidate rows to pull before attempting claim.\n * @param {string[]|undefined} taskNames When set, only claim rows with `name IN taskNames`.\n * @param {{ service_name: string, server_name: string, instance_number: number }|null} runnerIdentity\n * @returns {Promise<object|null>} The claimed row, or `null` when nothing is ready.\n */\nasync function claimNextRunnableTask(\n    context,\n    tasksTable,\n    serviceGroup,\n    registry,\n    scanLimit,\n    taskNames,\n    runnerIdentity\n) {\n    const db = getDb(context);\n\n    // Targeting: NULL on the task row means \"any\" for that field. Rows must match the runner's\n    // service_group and identity (when provided) for each non-null task column.\n    let query = db(tasksTable)\n        .where({ status: \"idle\" })\n        .where(function () {\n            this.whereNull(\"service_group\").orWhere({ service_group: serviceGroup });\n        })\n        // Honor next_run_at as a \"not before\" gate. NULL = no delay (claim now).\n        // This makes delayed one-off retries (next_run_at set, no schedule) wait\n        // their turn; scheduled rows already set next_run_at to their next fire\n        // time on enqueue/completion, so this stays consistent with timeMatcher.\n        .where(function () {\n            this.whereNull(\"next_run_at\").orWhere(\"next_run_at\", \"<=\", db.fn.now());\n        });\n    query = applyClaimOrder(query).limit(scanLimit);\n    if (taskNames && taskNames.length > 0) {\n        query = query.whereIn(\"name\", taskNames);\n    }\n    if (runnerIdentity) {\n        query = query\n            .where(function () {\n                this.whereNull(\"service_name\").orWhere({ service_name: runnerIdentity.service_name });\n            })\n            .where(function () {\n                this.whereNull(\"instance_number\").orWhere({ instance_number: runnerIdentity.instance_number });\n            })\n            .where(function () {\n                this.whereNull(\"server_name\").orWhere({ server_name: runnerIdentity.server_name });\n            });\n    } else {\n        // Without registry identity we cannot match a specific instance; only rows with no per-instance targeting.\n        query = query\n            .whereNull(\"service_name\")\n            .whereNull(\"instance_number\")\n            .whereNull(\"server_name\");\n    }\n    const candidates = await query;\n    candidates.sort(compareClaimCandidates);\n\n    for (const row of candidates) {\n        if (!row.past_due && row.schedule && !timeMatcher(row.schedule)) {\n            continue;\n        }\n\n        const TaskClass = registry.get(row.name);\n        if (!TaskClass) {\n            // Not registered on this runner — skip without claiming so another worker can run it.\n            continue;\n        }\n\n        const taskInstance = new TaskClass(context, row);\n        const reason = taskInstance.cantRunReason ? await taskInstance.cantRunReason() : null;\n        if (reason) {\n            if (!row.past_due) {\n                await db(tasksTable).where({ id: row.id }).update({\n                    past_due: db.fn.now(),\n                    progress: String(reason),\n                });\n            }\n            continue;\n        }\n\n        const claimPatch = {\n            started_at: db.fn.now(),\n            status: \"running\",\n            status_changed_at: db.fn.now(),\n        };\n        if (runnerIdentity) {\n            claimPatch.service_name = runnerIdentity.service_name;\n            claimPatch.server_name = runnerIdentity.server_name;\n            claimPatch.instance_number = runnerIdentity.instance_number;\n        }\n\n        const updated = await db(tasksTable)\n            .where({ id: row.id, status: \"idle\" })\n            .update(claimPatch)\n            .returning(\"*\");\n\n        const claimed = Array.isArray(updated) ? updated[0] : null;\n        if (claimed) return claimed;\n    }\n\n    return null;\n}\n\n/**\n * Main runner loop. Registers in the services registry (optional), then polls\n * the queue, claiming up to `maxParallel` tasks at a time plus one extra\n * \"control lane\" for `stop` / `pause` / `unpause` / `setRuntimeParam` (and\n * optional `controlLaneTasks`) so those can run even when workers are saturated.\n * When `context.tasksRuntime.paused` is true, in-flight worker tasks finish but\n * no new worker-lane claims are made until unpause.\n *\n * Loop knobs (`maxParallel`, `pollMs`, `claimJitterMs`, `scanLimit`) live on\n * `context.tasksRuntime` and are re-read every tick — change them live with the\n * `setRuntimeParam` core task (no restart).\n *\n * Exits when any of the following become true:\n *   - `context.isStop()` flips to `true` (external shutdown signal).\n *   - A `stopRunner` task completes successfully.\n *   - `context.tasksRunnerStop === true` (manual flag, mostly for tests).\n *\n * @param {object} context\n * @param {{\n *   queueName?: string,\n *   target: string,\n *   pollMs?: number,\n *   claimJitterMs?: number,\n *   maxParallel?: number,\n *   scanLimit?: number,\n *   allowedTasks?: string | string[],\n *   controlLaneTasks?: string | string[],\n *   registry?: TasksRegistry | Record<string, Function>,\n *   runnerServiceGroup?: string,\n *   runnerServiceName?: string,\n *   runnerInstanceNumber?: number,\n *   runnerHeartbeatIntervalMs?: number,\n *   runnerHeartbeatStaleMs?: number,\n *   runnerGroupMaxInstances?: number,\n *   runnerEnforceMaxInstances?: boolean,\n *   runnerMetadata?: Record<string, unknown>,\n *   runnerRuntimeParams?: import(\"./runtimeParams.js\").RuntimeParamSpec[],\n *   onRuntimeParam?: (key: string, value: unknown, runtime: object, context: object) => unknown,\n * }} options\n * @returns {Promise<void>}\n */\nexport async function runTasksLoop(context, options) {\n    const queueName = options.queueName ?? \"tasks\";\n    const target = options.target;\n    const allowedTasks = normalizeAllowedTasks(options.allowedTasks);\n    const controlLaneNames = controlLaneTaskNames(options.controlLaneTasks);\n    const registry = normalizeRegistry(options.registry);\n    const { tasksTable, historyTable } = queueToTableNames(queueName);\n\n    if (!target) throw new Error(\"runTasksLoop: target is required\");\n\n    context.tasksQueueName = queueName;\n    ensureTasksRuntime(context, {\n        maxParallel: options.maxParallel ?? 32,\n        pollMs: options.pollMs ?? 1000,\n        claimJitterMs: options.claimJitterMs ?? 0,\n        scanLimit: options.scanLimit ?? 100,\n    });\n    seedTaskRetentionRuntime(context);\n    if (typeof options.onRuntimeParam === \"function\") {\n        context.tasksRuntimeOnParam = options.onRuntimeParam;\n    }\n\n    const runningPromises = new Set();\n    const runningTaskInstances = new Map();\n    // Expose so control-lane pauseTask can signal in-process workers.\n    context.runningTaskInstances = runningTaskInstances;\n    let runningControlPromise = null;\n    let stopRequested = false;\n    let stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : 60_000;\n    context.tasksRunnerStop = false;\n\n    let registryReg = null;\n    let registryInterval = null;\n    let runnerIdentity = null;\n    const hbGroup = options.runnerServiceGroup?.trim();\n    if (hbGroup) {\n        const hbIntervalMs = options.runnerHeartbeatIntervalMs ?? 10_000;\n        const staleMs = options.runnerHeartbeatStaleMs ?? 45_000;\n        const runtimeParamSpecs = mergeRuntimeParamSpecs(options.runnerRuntimeParams);\n        context.tasksRuntimeParamSpecs = runtimeParamSpecs;\n        const defaultMeta = {\n            component: \"tasks-runner\",\n            allowedTasks: allowedTasks?.length ? allowedTasks.join(\",\") : \"all\",\n            paused: false,\n            runtimeParams: runtimeParamSpecs,\n            runtime: runtimeValuesForSpecs(context, runtimeParamSpecs),\n        };\n        const metadata = {\n            ...defaultMeta,\n            ...(options.runnerMetadata && typeof options.runnerMetadata === \"object\"\n                ? options.runnerMetadata\n                : {}),\n        };\n        if (!Array.isArray(metadata.runtimeParams) || metadata.runtimeParams.length === 0) {\n            metadata.runtimeParams = defaultMeta.runtimeParams;\n        }\n        if (!metadata.runtime || typeof metadata.runtime !== \"object\") {\n            metadata.runtime = defaultMeta.runtime;\n        }\n        registryReg = await registerInServicesRegistry(context, {\n            queueName,\n            target,\n            serviceGroup: hbGroup,\n            serviceName: options.runnerServiceName,\n            instanceNumber: options.runnerInstanceNumber,\n            staleMs,\n            groupMaxInstances: options.runnerGroupMaxInstances,\n            enforceMaxInstances: options.runnerEnforceMaxInstances ?? true,\n            metadata,\n        });\n        // Expose registration so setRuntimeParam can patch metadata.\n        context.servicesRegistry = registryReg;\n        runnerIdentity = {\n            service_name: registryReg.serviceName,\n            server_name: os.hostname(),\n            instance_number: registryReg.instanceNumber,\n        };\n        registryInterval = setInterval(() => {\n            void touchServicesRegistry(context, registryReg).catch((err) => {\n                context.logger.warn?.(`[services-registry] touch failed: ${err?.message ?? String(err)}`);\n            });\n        }, hbIntervalMs);\n    }\n\n    try {\n        while (!context.isStop() && !stopRequested && context.tasksRunnerStop !== true) {\n            const { maxParallel, pollMs, claimJitterMs, scanLimit } = readLoopRuntime(context);\n            await signalStopForDeletedQueueRows(context, tasksTable, runningTaskInstances);\n\n            // Control lane: stop / setRuntimeParam / extras even when workers are saturated.\n            if (!runningControlPromise) {\n                const claimedControlTask = await claimNextRunnableTask(\n                    context,\n                    tasksTable,\n                    target,\n                    registry,\n                    10,\n                    controlLaneNames,\n                    runnerIdentity\n                );\n                if (claimedControlTask) {\n                    runningControlPromise = executeClaimedTask(\n                        context,\n                        tasksTable,\n                        historyTable,\n                        claimedControlTask,\n                        registry,\n                        runningTaskInstances\n                    )\n                        .then(async (outcome) => {\n                            if (outcome.stopRunnerRequested && !stopRequested) {\n                                stopRequested = true;\n                                stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;\n                                context.tasksRunnerStop = true;\n                                await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);\n                            }\n                        })\n                        .finally(() => {\n                            runningControlPromise = null;\n                        });\n                }\n            }\n\n            if (claimJitterMs > 0) {\n                await sleepMs(Math.floor(Math.random() * (claimJitterMs + 1)));\n            }\n\n            // Worker lane: skip new claims while paused (in-flight work still drains).\n            const paused = context.tasksRuntime?.paused === true;\n            if (!paused) {\n                while (runningPromises.size < maxParallel) {\n                    const claimed = await claimNextRunnableTask(\n                        context,\n                        tasksTable,\n                        target,\n                        registry,\n                        scanLimit,\n                        allowedTasks,\n                        runnerIdentity\n                    );\n                    if (!claimed) break;\n\n                    const p = executeClaimedTask(\n                        context,\n                        tasksTable,\n                        historyTable,\n                        claimed,\n                        registry,\n                        runningTaskInstances\n                    )\n                        .then(async (outcome) => {\n                            if (outcome.stopRunnerRequested && !stopRequested) {\n                                stopRequested = true;\n                                stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;\n                                context.tasksRunnerStop = true;\n                                await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);\n                            }\n                        })\n                        .finally(() => {\n                            runningPromises.delete(p);\n                        });\n                    runningPromises.add(p);\n                }\n            }\n\n            const wakePromises = [...runningPromises];\n            if (runningControlPromise) {\n                wakePromises.push(runningControlPromise);\n            }\n            if (wakePromises.length === 0) {\n                scheduleTaskRetentionPass(context, historyTable);\n                await sleepMs(pollMs);\n            } else {\n                const safe = wakePromises.map((p) => p.catch(() => undefined));\n                await Promise.race([sleepMs(pollMs), Promise.race(safe)]);\n            }\n        }\n\n        if (context.isStop() && !stopRequested) {\n            stopRequested = true;\n            stopAllowanceMs = Number(context.stopAllowanceMs) > 0\n                ? Number(context.stopAllowanceMs)\n                : stopAllowanceMs;\n            await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);\n        }\n\n        if (runningPromises.size > 0) {\n            if (stopRequested) {\n                await Promise.race([\n                    Promise.allSettled(Array.from(runningPromises)),\n                    sleepMs(stopAllowanceMs).then(() => {\n                        context.logger.warn?.(\n                            `[tasks] stop allowance (${stopAllowanceMs}ms) reached; ${runningPromises.size} task(s) still running`\n                        );\n                    }),\n                ]);\n            } else {\n                await Promise.allSettled(Array.from(runningPromises));\n            }\n        }\n    } finally {\n        if (registryInterval) {\n            clearInterval(registryInterval);\n            registryInterval = null;\n        }\n        if (registryReg) {\n            await unregisterServicesRegistry(context, registryReg).catch((err) => {\n                context.logger.warn?.(`[services-registry] unregister failed: ${err?.message ?? String(err)}`);\n            });\n            registryReg = null;\n            delete context.servicesRegistry;\n            delete context.runnerHeartbeat;\n        }\n    }\n}\n\n/**\n * Poll for the outcome of a task by id. Returns the matching `_history` row when\n * the task completes, or `null` when the wait times out.\n *\n * Resolves any of:\n *   - Legacy: history row whose `id` equals the queue task id.\n *   - `opid` equals the queue task id (stamped when enqueue had no opid — see\n *     {@link taskHistoryInsertFromQueueRow}).\n *   - Same `name`+`opid` with `completed_at` ≥ wait start (optional `name`/`opid`\n *     hints help when the queue row is already gone on the first poll).\n *\n * Fast one-shot tasks (e.g. hostInfo) often finish before the first poll sees the\n * queue row — we keep polling until `timeoutMs` rather than treating “row gone”\n * as failure.\n *\n * @param {object} context\n * @param {string} taskId\n * @param {{\n *   queueName?: string,\n *   timeoutMs?: number,\n *   pollMs?: number,\n *   name?: string,\n *   opid?: string|null,\n * }} [options]\n * @returns {Promise<object|null>}\n */\nexport async function waitForTaskResult(context, taskId, options = {}) {\n    const db = getDb(context);\n    const queueName = options.queueName ?? \"tasks\";\n    const timeoutMs = options.timeoutMs ?? 60000;\n    const pollMs = options.pollMs ?? 500;\n    const { tasksTable, historyTable } = queueToTableNames(queueName);\n    const deadline = Date.now() + timeoutMs;\n    // Small skew grace so a fast complete on a slightly-behind DB clock still matches.\n    const waitStartedAt = new Date(Date.now() - 5_000);\n    let cachedNameOpid =\n        options.name != null && String(options.name).trim() !== \"\"\n            ? {\n                  name: String(options.name).trim(),\n                  opid: options.opid !== undefined ? options.opid : null,\n              }\n            : null;\n\n    /**\n     * @param {string} name\n     * @param {string|null|undefined} opid\n     * @returns {Promise<object|undefined>}\n     */\n    async function findHistory(name, opid) {\n        const base = () =>\n            db(historyTable).where({ name }).where(\"completed_at\", \">=\", waitStartedAt);\n\n        if (opid != null && String(opid).trim() !== \"\") {\n            const byOpid = await base().where({ opid }).orderBy(\"completed_at\", \"desc\").first();\n            if (byOpid) return byOpid;\n        }\n\n        // Queue id stamped into history.opid when the task had no opid.\n        const byQueueId = await base().where({ opid: taskId }).orderBy(\"completed_at\", \"desc\").first();\n        if (byQueueId) return byQueueId;\n\n        // Also try without the time gate for the unique queue-id opid (clock skew).\n        const byQueueIdAny = await db(historyTable)\n            .where({ name, opid: taskId })\n            .orderBy(\"completed_at\", \"desc\")\n            .first();\n        if (byQueueIdAny) return byQueueIdAny;\n\n        if (opid == null || opid === \"\") {\n            const byNull = await base().whereNull(\"opid\").orderBy(\"completed_at\", \"desc\").first();\n            if (byNull) return byNull;\n        }\n\n        return undefined;\n    }\n\n    while (Date.now() <= deadline) {\n        const legacy = await db(historyTable).where({ id: taskId }).orderBy(\"created_at\", \"desc\").first();\n        if (legacy) {\n            return legacy;\n        }\n\n        const pending = await db(tasksTable).where({ id: taskId }).first();\n        if (pending) {\n            cachedNameOpid = { name: pending.name, opid: pending.opid };\n        }\n\n        if (cachedNameOpid) {\n            const done = await findHistory(cachedNameOpid.name, cachedNameOpid.opid);\n            if (done) {\n                return done;\n            }\n        } else {\n            // Name unknown yet — still try correlation by stamped opid=taskId across names.\n            const byQueueId = await db(historyTable)\n                .where({ opid: taskId })\n                .orderBy(\"completed_at\", \"desc\")\n                .first();\n            if (byQueueId) {\n                return byQueueId;\n            }\n        }\n\n        await sleepMs(pollMs);\n    }\n    return null;\n}\n\n/**\n * Higher-level wrapper over {@link runTasksLoop}: captures defaults / params-driven\n * config at construction, then exposes them as methods (`ensureTaskTables`,\n * `runTasksLoop`) so callers don't have to plumb the same options through twice.\n *\n * Prefer `TasksManager.init(context)` over the bare constructor — `init` pulls\n * sensible defaults from `context.params` using the `tasks` module namespace.\n */\nexport class TasksManager {\n    /**\n     * @param {object} context\n     * @param {{\n     *   queueName?: string,\n     *   target?: string,\n     *   recreateTaskTables?: boolean,\n     *   pollMs?: number,\n     *   claimJitterMs?: number,\n     *   maxParallel?: number,\n     *   scanLimit?: number,\n     *   allowedTasks?: string | string[],\n     *   registry?: TasksRegistry | Record<string, Function>,\n     *   runnerServiceGroup?: string,\n     *   runnerServiceName?: string,\n     *   runnerInstanceNumber?: number,\n     *   runnerHeartbeatIntervalMs?: number,\n     *   runnerHeartbeatStaleMs?: number,\n     *   runnerGroupMaxInstances?: number,\n     *   runnerEnforceMaxInstances?: boolean,\n     *   runnerMetadata?: Record<string, unknown>,\n     * }} [options]\n     */\n    constructor(context, options = {}) {\n        this.context = context;\n        this.queueName = options.queueName ?? \"tasks\";\n        this.target = options.target ?? \"localRunner\";\n        this.recreateTaskTables = options.recreateTaskTables ?? false;\n        this.pollMs = options.pollMs ?? 1000;\n        this.claimJitterMs = options.claimJitterMs ?? 0;\n        this.maxParallel = options.maxParallel ?? 1;\n        this.scanLimit = options.scanLimit ?? 100;\n        this.allowedTasks = normalizeAllowedTasks(options.allowedTasks);\n        this.registry = normalizeRegistry(options.registry);\n        this.runnerServiceGroup = options.runnerServiceGroup;\n        this.runnerServiceName = options.runnerServiceName;\n        this.runnerInstanceNumber = options.runnerInstanceNumber;\n        this.runnerHeartbeatIntervalMs = options.runnerHeartbeatIntervalMs;\n        this.runnerHeartbeatStaleMs = options.runnerHeartbeatStaleMs;\n        this.runnerGroupMaxInstances = options.runnerGroupMaxInstances;\n        this.runnerEnforceMaxInstances = options.runnerEnforceMaxInstances;\n        this.runnerMetadata = options.runnerMetadata;\n    }\n\n    /**\n     * Preferred factory: reads defaults from `context.params` (module namespace\n     * `\"tasks\"`), then overlays explicit `options`. Keeps CLI flags, env vars,\n     * and inline options in one consistent resolver.\n     *\n     * @param {object} context\n     * @param {ConstructorParameters<typeof TasksManager>[1]} [options]\n     * @returns {TasksManager}\n     */\n    static init(context, options = {}) {\n        const defs = {\n            table: \"string default tasks\",\n            target: \"string default localRunner\",\n            recreateTaskTables: \"boolean default false\",\n            pollMs: \"number default 1000\",\n            claimJitterMs: \"number default 0\",\n            maxParallel: \"number default 1\",\n            scanLimit: \"number default 100\",\n            allowedTasks: \"string\",\n            runnerServiceGroup: \"string\",\n            runnerServiceName: \"string\",\n            runnerInstanceNumber: \"number\",\n            runnerHeartbeatIntervalMs: \"number default 10000\",\n            runnerHeartbeatStaleMs: \"number default 45000\",\n            runnerGroupMaxInstances: \"number\",\n            runnerEnforceMaxInstances: \"boolean default true\",\n        };\n\n        const discovered = context.params.getAllForModule(\"tasks\", defs);\n        const resolved = {\n            queueName: discovered.table,\n            target: discovered.target,\n            recreateTaskTables: discovered.recreateTaskTables,\n            pollMs: discovered.pollMs,\n            claimJitterMs: discovered.claimJitterMs,\n            maxParallel: discovered.maxParallel,\n            scanLimit: discovered.scanLimit,\n            allowedTasks: discovered.allowedTasks,\n            runnerServiceGroup: discovered.runnerServiceGroup,\n            runnerServiceName: discovered.runnerServiceName,\n            runnerInstanceNumber: discovered.runnerInstanceNumber,\n            runnerHeartbeatIntervalMs: discovered.runnerHeartbeatIntervalMs,\n            runnerHeartbeatStaleMs: discovered.runnerHeartbeatStaleMs,\n            runnerGroupMaxInstances: discovered.runnerGroupMaxInstances,\n            runnerEnforceMaxInstances: discovered.runnerEnforceMaxInstances,\n            ...options,\n        };\n        return new TasksManager(context, resolved);\n    }\n\n    /**\n     * Idempotently ensure the three backing tables exist for this queue.\n     *\n     * @param {{ recreate?: boolean }} [options]\n     * @returns {Promise<void>}\n     */\n    async ensureTaskTables(options = {}) {\n        await ensureTaskTables(this.context, {\n            queueName: this.queueName,\n            recreate: options.recreate ?? this.recreateTaskTables,\n        });\n    }\n\n    /**\n     * Start the runner loop using this manager's resolved config. Per-call\n     * options override the stored defaults, but `runnerMetadata` still falls\n     * through when omitted.\n     *\n     * @param {Partial<ConstructorParameters<typeof TasksManager>[1]>} [options]\n     * @returns {Promise<void>}\n     */\n    async runTasksLoop(options = {}) {\n        await runTasksLoop(this.context, {\n            queueName: options.queueName ?? this.queueName,\n            target: options.target ?? this.target,\n            pollMs: options.pollMs ?? this.pollMs,\n            claimJitterMs: options.claimJitterMs ?? this.claimJitterMs,\n            maxParallel: options.maxParallel ?? this.maxParallel,\n            scanLimit: options.scanLimit ?? this.scanLimit,\n            allowedTasks: options.allowedTasks ?? this.allowedTasks,\n            registry: options.registry ?? this.registry,\n            runnerServiceGroup: options.runnerServiceGroup ?? this.runnerServiceGroup,\n            runnerServiceName: options.runnerServiceName ?? this.runnerServiceName,\n            runnerInstanceNumber: options.runnerInstanceNumber ?? this.runnerInstanceNumber,\n            runnerHeartbeatIntervalMs: options.runnerHeartbeatIntervalMs ?? this.runnerHeartbeatIntervalMs,\n            runnerHeartbeatStaleMs: options.runnerHeartbeatStaleMs ?? this.runnerHeartbeatStaleMs,\n            runnerGroupMaxInstances: options.runnerGroupMaxInstances ?? this.runnerGroupMaxInstances,\n            runnerEnforceMaxInstances: options.runnerEnforceMaxInstances ?? this.runnerEnforceMaxInstances,\n            runnerMetadata: options.runnerMetadata ?? this.runnerMetadata,\n        });\n    }\n}\n","/**\n * Core lightweight utilities\n */\n\nexport function sleepMs(ms) {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function toJsonColumn(value) {\n    if (value === undefined || value === null) return null;\n    return JSON.stringify(value);\n}\n","import os from \"node:os\";\nimport { toJsonColumn } from \"../utils/index.js\";\nimport { queueToTableNames } from \"./taskUtils.js\";\n\n/**\n * Fail-fast accessor for `context.db`. The services-registry never lazy-inits the DB;\n * if it's missing, that's a caller wiring mistake.\n *\n * @param {object} context\n * @returns {Function}\n */\nfunction getDb(context) {\n    const db = context.db;\n    if (!db) {\n        throw new Error(\"Services registry requires context.db\");\n    }\n    return db;\n}\n\n/**\n * Decode a JSON column value into a plain object. Returns `{}` for nulls,\n * arrays, parse errors — callers never get `null`/`undefined` back so they can\n * safely spread the result.\n *\n * @param {unknown} value\n * @returns {Record<string, unknown>}\n */\nfunction parseMetadataColumn(value) {\n    if (!value) return {};\n    if (typeof value === \"object\" && !Array.isArray(value)) return value;\n    if (typeof value === \"string\") {\n        try {\n            const p = JSON.parse(value);\n            return p && typeof p === \"object\" && !Array.isArray(value) ? p : {};\n        } catch {\n            return {};\n        }\n    }\n    return {};\n}\n\n/**\n * Per-group max alive instances (0 = unlimited). Empty by default — product\n * apps inject their map via {@link setGroupMaxInstancesDefaults}.\n * An explicit `runnerGroupMaxInstances` override still wins.\n *\n * @type {Record<string, number>}\n */\nlet groupMaxInstancesDefaults = Object.create(null);\n\n/**\n * Replace the per-group instance-cap map. Keys are lowercased group names.\n * Pass `null` / omit to clear (every group unlimited unless overridden).\n *\n * @param {Record<string, number>|null|undefined} map\n */\nexport function setGroupMaxInstancesDefaults(map) {\n    const next = Object.create(null);\n    if (map && typeof map === \"object\") {\n        for (const [key, value] of Object.entries(map)) {\n            const g = String(key).trim().toLowerCase();\n            if (!g || !Number.isFinite(Number(value))) continue;\n            next[g] = Math.max(0, Math.floor(Number(value)));\n        }\n    }\n    groupMaxInstancesDefaults = next;\n}\n\n/**\n * Produce a DB-safe, human-readable name part: letters / digits / `._-` only,\n * trimmed and capped at 80 chars. Empty inputs fall back to `\"runner\"`.\n *\n * @param {unknown} raw\n * @returns {string}\n */\nfunction sanitizeNamePart(raw) {\n    const s = String(raw || \"\")\n        .trim()\n        .replace(/[^a-zA-Z0-9._-]+/g, \"-\")\n        .replace(/^-+|-+$/g, \"\");\n    return s.slice(0, 80) || \"runner\";\n}\n\n/**\n * How many alive instances are allowed in this group? Explicit `override` wins;\n * otherwise use the per-group default (lowercased group name). `0` = unlimited.\n *\n * @param {string} serviceGroup\n * @param {number|undefined} override\n * @returns {number}\n */\nfunction resolveMaxInstances(serviceGroup, override) {\n    if (override !== undefined && Number.isFinite(override)) {\n        return Math.max(0, Math.floor(Number(override)));\n    }\n    const g = serviceGroup.trim().toLowerCase();\n    return groupMaxInstancesDefaults[g] ?? 0;\n}\n\n/** @internal exported for tests */\nexport function resolveGroupMaxInstances(serviceGroup, override) {\n    return resolveMaxInstances(serviceGroup, override);\n}\n\n/**\n * Count rows in a group that have heartbeat'd within `staleMs`. Used to gate\n * `groupMaxInstances` at registration time.\n *\n * @param {Function} db knex instance.\n * @param {string} registryTable\n * @param {string} queueName\n * @param {string} serviceGroup\n * @param {number} staleMs\n * @param {string|undefined} excludeRowId When retrying, skip the row we're about to reuse.\n * @returns {Promise<number>}\n */\nasync function countAliveInGroup(\n    db,\n    registryTable,\n    queueName,\n    serviceGroup,\n    staleMs,\n    excludeRowId\n) {\n    const cutoff = new Date(Date.now() - staleMs);\n    let q = db(registryTable)\n        .where({ queue_name: queueName, service_group: serviceGroup })\n        .where(\"last_seen_at\", \">\", cutoff);\n    if (excludeRowId) {\n        q = q.whereNot(\"id\", excludeRowId);\n    }\n    const row = await q.count(\"id as count\").first();\n    return Number(row?.count ?? 0);\n}\n\n/**\n * Instance numbers currently held by *alive* rows (fresh last_seen).\n *\n * @param {Function} db\n * @param {string} registryTable\n * @param {string} queueName\n * @param {string} serviceGroup\n * @param {number} staleMs\n * @returns {Promise<Set<number>>}\n */\nasync function getOccupiedInstanceSlots(\n    db,\n    registryTable,\n    queueName,\n    serviceGroup,\n    staleMs\n) {\n    const cutoff = new Date(Date.now() - staleMs);\n    const rows = await db(registryTable)\n        .where({ queue_name: queueName, service_group: serviceGroup })\n        .where(\"last_seen_at\", \">\", cutoff)\n        .select(\"instance_number\");\n    const set = new Set();\n    for (const r of rows) {\n        const n = Number(r.instance_number);\n        if (Number.isFinite(n) && n >= 1) set.add(Math.floor(n));\n    }\n    return set;\n}\n\n/**\n * Best-effort detection of Postgres unique-constraint violations. Covers both\n * pg's `23505` SQLSTATE and drivers that only surface the error message.\n *\n * @param {unknown} error\n * @returns {boolean}\n */\nfunction isUniqueViolation(error) {\n    const code = error?.code ?? error?.errno;\n    return code === \"23505\" || String(error?.message || \"\").includes(\"duplicate key\");\n}\n\n/**\n * Package the `metadata` JSON column payload for a new/updated registry row.\n * Always carries `runnerTarget` when provided so read-side filters can see it\n * without decoding the whole blob.\n *\n * @param {{ metadata?: Record<string, unknown>, target?: string }} options\n * @returns {string|null}\n */\nfunction buildMetadata(options) {\n    const base = options.metadata && typeof options.metadata === \"object\" ? { ...options.metadata } : {};\n    if (options.target) {\n        base.runnerTarget = options.target;\n    }\n    return toJsonColumn(Object.keys(base).length ? base : null);\n}\n\n/**\n * Pick first free instance number: smallest n >= 1 with n ∉ occupied.\n * If explicit is set, use it only if not in occupied and within maxSlots (when > 0).\n *\n * @param {Set<number>} occupied\n * @param {number|undefined|null} explicit\n * @param {number|undefined} maxSlots\n * @returns {number}\n */\nfunction allocateInstanceNumber(occupied, explicit, maxSlots) {\n    if (explicit !== undefined && explicit !== null && Number.isFinite(Number(explicit))) {\n        const e = Math.max(1, Math.floor(Number(explicit)));\n        if (occupied.has(e)) {\n            throw new Error(`[services-registry] instance slot ${e} is already occupied by an alive peer`);\n        }\n        if (maxSlots !== undefined && maxSlots > 0 && e > maxSlots) {\n            throw new Error(`[services-registry] instance ${e} exceeds configured max slots ${maxSlots} for this group`);\n        }\n        return e;\n    }\n    const cap = maxSlots !== undefined && maxSlots > 0 ? maxSlots : 10_000;\n    for (let n = 1; n <= cap; n++) {\n        if (!occupied.has(n)) return n;\n    }\n    throw new Error(`[services-registry] no free instance slot (searched 1..${cap})`);\n}\n\n/**\n * Build a conventional `service_name` when the caller didn't pick one:\n * `<group>-<host>-<instance>`.\n *\n * @param {string} groupBase\n * @param {string} hostBase\n * @param {number} instanceNumber\n * @returns {string}\n */\nfunction defaultServiceName(groupBase, hostBase, instanceNumber) {\n    return `${groupBase}-${hostBase}-${instanceNumber}`;\n}\n\n/**\n * Register this process in `{queue}_services_registry` (no local identity files).\n * Allocates the first free instance number among *alive* peers, then inserts or takes over a stale row\n * with the same `service_name` when restarting on the same host/name pattern.\n *\n * @param {object} context\n * @param {{\n *   queueName: string,\n *   target?: string,\n *   serviceGroup: string,\n *   serviceName?: string,\n *   instanceNumber?: number|null,\n *   staleMs: number,\n *   groupMaxInstances?: number,\n *   enforceMaxInstances?: boolean,\n *   metadata?: Record<string, unknown>,\n * }} options\n * @returns {Promise<{\n *   serviceName: string,\n *   serviceGroup: string,\n *   queueName: string,\n *   target?: string,\n *   rowId: string,\n *   registryTable: string,\n *   instanceNumber: number,\n * }>}\n */\nexport async function registerInServicesRegistry(context, options) {\n    const db = getDb(context);\n    const registryTable = queueToTableNames(options.queueName).registryTable;\n    const serviceGroup = options.serviceGroup.trim();\n    if (!serviceGroup) {\n        throw new Error(\"registerInServicesRegistry: serviceGroup is required\");\n    }\n\n    const serverName = os.hostname();\n    const pid = typeof process.pid === \"number\" ? process.pid : null;\n    const meta = buildMetadata(options);\n    const groupBase = sanitizeNamePart(serviceGroup);\n    const hostBase = sanitizeNamePart(serverName);\n\n    const maxAllowed = resolveMaxInstances(serviceGroup, options.groupMaxInstances);\n    const aliveCount = await countAliveInGroup(db, registryTable, options.queueName, serviceGroup, options.staleMs, undefined);\n\n    if (maxAllowed > 0 && aliveCount >= maxAllowed) {\n        const msg = `[services-registry] group limit reached for \"${serviceGroup}\": ${aliveCount} alive (max ${maxAllowed}, queue=${options.queueName}).`;\n        if (options.enforceMaxInstances) {\n            throw new Error(msg);\n        }\n        context.logger.warn?.(`${msg} Starting anyway (runnerEnforceMaxInstances=false).`);\n    }\n\n    const maxSlots = maxAllowed > 0 ? maxAllowed : undefined;\n    const cutoff = new Date(Date.now() - options.staleMs);\n\n    const MAX_ATTEMPTS = 8;\n    for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {\n        const occupied = await getOccupiedInstanceSlots(db, registryTable, options.queueName, serviceGroup, options.staleMs);\n        const instanceNumber = allocateInstanceNumber(occupied, options.instanceNumber, maxSlots);\n\n        const serviceNameRaw = options.serviceName?.trim()\n            ? sanitizeNamePart(options.serviceName.trim())\n            : defaultServiceName(groupBase, hostBase, instanceNumber);\n\n        const existing = await db(registryTable)\n            .where({ queue_name: options.queueName, service_name: serviceNameRaw })\n            .first();\n\n        if (existing) {\n            const lastSeen = new Date(existing.last_seen_at);\n            const isAlive = !Number.isNaN(lastSeen.getTime()) && lastSeen > cutoff;\n\n            if (isAlive) {\n                if (options.serviceName?.trim()) {\n                    throw new Error(\n                        `[services-registry] service_name \"${serviceNameRaw}\" is already registered by an alive peer`\n                    );\n                }\n                context.logger.warn?.(\n                    `[services-registry] service_name \"${serviceNameRaw}\" already alive; retrying allocation (attempt ${attempt + 1})`\n                );\n                if (options.instanceNumber !== undefined && options.instanceNumber !== null) {\n                    throw new Error(\n                        `[services-registry] instance slot ${instanceNumber} / name \"${serviceNameRaw}\" is already held by an alive peer`\n                    );\n                }\n                await new Promise((r) => setTimeout(r, 50 + attempt * 30));\n                continue;\n            }\n\n            await db(registryTable)\n                .where({ id: existing.id })\n                .update({\n                    server_name: serverName,\n                    pid,\n                    metadata: meta,\n                    service_group: serviceGroup,\n                    instance_number: instanceNumber,\n                    last_seen_at: db.fn.now(),\n                });\n\n            const reg = {\n                serviceName: serviceNameRaw,\n                serviceGroup,\n                queueName: options.queueName,\n                target: options.target,\n                rowId: String(existing.id),\n                registryTable,\n                instanceNumber,\n            };\n            context.servicesRegistry = reg;\n            context.runnerHeartbeat = reg;\n\n            context.logger.info?.(\n                `[services-registry] took over stale row name=${serviceNameRaw} instance=${instanceNumber} group=${serviceGroup} queue=${options.queueName}`\n            );\n            return reg;\n        }\n\n        try {\n            const rows = await db(registryTable)\n                .insert({\n                    queue_name: options.queueName,\n                    service_group: serviceGroup,\n                    instance_number: instanceNumber,\n                    service_name: serviceNameRaw,\n                    server_name: serverName,\n                    pid,\n                    metadata: meta,\n                    last_seen_at: db.fn.now(),\n                    created_at: db.fn.now(),\n                })\n                .returning([\"id\", \"service_name\"]);\n\n            const row = Array.isArray(rows) ? rows[0] : rows;\n            let rowId = row && typeof row === \"object\" ? String(row.id ?? \"\") : \"\";\n            if (!rowId) {\n                const again = await db(registryTable)\n                    .where({ queue_name: options.queueName, service_name: serviceNameRaw })\n                    .first();\n                rowId = again?.id != null ? String(again.id) : \"\";\n            }\n            if (!rowId) continue;\n\n            const regNew = {\n                serviceName: String(row?.service_name ?? serviceNameRaw),\n                serviceGroup,\n                queueName: options.queueName,\n                target: options.target,\n                rowId,\n                registryTable,\n                instanceNumber,\n            };\n            context.servicesRegistry = regNew;\n            context.runnerHeartbeat = regNew;\n\n            context.logger.info?.(\n                `[services-registry] registered name=${regNew.serviceName} instance=${instanceNumber} group=${serviceGroup} queue=${options.queueName}`\n            );\n            return regNew;\n        } catch (error) {\n            if (!isUniqueViolation(error)) {\n                throw error;\n            }\n            context.logger.warn?.(`[services-registry] insert race on \"${serviceNameRaw}\", retrying (attempt ${attempt + 1})`);\n        }\n    }\n\n    throw new Error(\n        `[services-registry] could not allocate a registry row for group=${serviceGroup} queue=${options.queueName} after ${MAX_ATTEMPTS} attempts`\n    );\n}\n\n/**\n * Heartbeat: bump `last_seen_at`, refresh `server_name` / `pid` in case the\n * hostname rotates or the process PID changes (container restart in place).\n *\n * @param {object} context\n * @param {{ registryTable: string, rowId: string }} registration\n * @returns {Promise<void>}\n */\nexport async function touchServicesRegistry(context, registration) {\n    const db = getDb(context);\n    const serverName = os.hostname();\n    const pid = typeof process.pid === \"number\" ? process.pid : null;\n    await db(registration.registryTable)\n        .where({ id: registration.rowId })\n        .update({\n            last_seen_at: db.fn.now(),\n            server_name: serverName,\n            pid,\n        });\n}\n\n/**\n * Merge metadata (e.g. new allowedTasks / role) for this service row. Bumps last_seen_at.\n * Use when a service changes what it handles without restarting the process.\n *\n * @param {object} context\n * @param {{ registryTable: string, rowId: string, serviceName: string }} registration\n * @param {Record<string, unknown>} patch\n * @returns {Promise<void>}\n */\nexport async function updateServicesRegistryMetadata(context, registration, patch) {\n    const db = getDb(context);\n    const row = await db(registration.registryTable).where({ id: registration.rowId }).first();\n    const prev = parseMetadataColumn(row?.metadata);\n    const merged = { ...prev, ...patch };\n    await db(registration.registryTable)\n        .where({ id: registration.rowId })\n        .update({\n            metadata: toJsonColumn(merged),\n            last_seen_at: db.fn.now(),\n        });\n    context.logger.info?.(`[services-registry] metadata updated for ${registration.serviceName}`);\n}\n\n/**\n * Drop this process's registry row. Call on graceful shutdown so peers don't\n * have to wait for `staleMs` to reclaim the slot.\n *\n * @param {object} context\n * @param {{ registryTable: string, rowId: string, serviceName: string }} registration\n * @returns {Promise<void>}\n */\nexport async function unregisterServicesRegistry(context, registration) {\n    const db = getDb(context);\n    await db(registration.registryTable).where({ id: registration.rowId }).delete();\n    context.logger.info?.(`[services-registry] unregistered name=${registration.serviceName} id=${registration.rowId}`);\n}\n\n/**\n * List registry rows (optionally filter by queue / group). Rows with last_seen older than staleMs are excluded.\n *\n * @param {object} context\n * @param {{ queueName: string, staleMs?: number, serviceGroup?: string }} [options]\n * @returns {Promise<object[]>}\n */\nexport async function listServicesRegistry(context, options = { queueName: \"tasks\" }) {\n    const db = getDb(context);\n    const staleMs = options.staleMs ?? 60_000;\n    const cutoff = new Date(Date.now() - staleMs);\n    const table = queueToTableNames(options.queueName).registryTable;\n    let q = db(table).where(\"last_seen_at\", \">\", cutoff).orderBy([{ column: \"service_group\", order: \"asc\" }, { column: \"service_name\", order: \"asc\" }]);\n    if (options.serviceGroup?.trim()) {\n        q = q.where({ service_group: options.serviceGroup.trim() });\n    }\n    return await q;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { toJsonColumn } from \"../utils/index.js\";\nimport { ensureSchema } from \"../db/ensure.js\";\nimport { nextTimeMatch } from \"./time-matcher.js\";\n\n/**\n * Fail-fast accessor for the knex instance on `context.db`. The tasks component\n * assumes the DB is already initialized by the caller — we don't lazy-init here,\n * so a missing `db` is a programming error, not a runtime condition.\n *\n * @param {object} context\n * @returns {Function} knex instance\n */\nfunction getDb(context) {\n    const db = context.db;\n    if (!db) {\n        throw new Error(\"Tasks component requires context.db. Initialize DB first and attach to context.\");\n    }\n    return db;\n}\n\n/**\n * Given a queue name, derive the three related table names the runtime uses:\n *\n *   - `tasksTable`     — active queue (rows that may still run)\n *   - `historyTable`   — append-only audit of completed attempts\n *   - `registryTable`  — live service/runner heartbeats for the queue\n *\n * @param {string} queueName\n * @returns {{ tasksTable: string, historyTable: string, registryTable: string }}\n */\nexport function queueToTableNames(queueName) {\n    return {\n        tasksTable: queueName,\n        historyTable: `${queueName}_history`,\n        registryTable: `${queueName}_services_registry`,\n    };\n}\n\n/**\n * Column set shared by the active queue and its history mirror, expressed as a\n * declarative spec (see db/ensure.js): each entry is one column, so\n * `ensureSchema` can create the whole table OR add just the columns an older\n * installation is missing — adding a field here is all a migration takes.\n *\n * @param {string} tableNameForIndex Used to name indexes uniquely per table.\n * @returns {import(\"../db/ensure.js\").TableSpec}\n */\nfunction tasksTableSpec(tableNameForIndex) {\n    return {\n        columns: {\n            id: (t, db) => t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\")),\n            created_at: (t, db) => t.timestamp(\"created_at\").notNullable().defaultTo(db.fn.now()),\n            started_at: (t) => t.timestamp(\"started_at\"),\n            completed_at: (t) => t.timestamp(\"completed_at\"),\n            /*\n             * Priority: lower number = more urgent (0 first, default 50). Used when no\n             * row is due (`next_run_at` / `past_due`); due rows claim by earliest due.\n             */\n            priority: (t) => t.integer(\"priority\").notNullable().defaultTo(50),\n\n            schedule: (t) => t.text(\"schedule\"),\n            next_run_at: (t) => t.timestamp(\"next_run_at\").defaultTo(null),\n            past_due: (t) => t.timestamp(\"past_due\").defaultTo(null),\n\n            name: (t) => t.text(\"name\").notNullable(),\n            opid: (t) => t.text(\"opid\"),\n            params: (t) => t.jsonb(\"params\"),\n\n            // those are target identifiers, kind of who is going to run a task.\n            service_group: (t) => t.text(\"service_group\"), // harvester, loader, photos, ...\n            instance_number: (t) => t.integer(\"instance_number\"),\n            service_name: (t) => t.text(\"service_name\"), // that's a \"<server_name>_<service_group>_<instance_number>\"\n            server_name: (t) => t.text(\"server_name\"), // filled by runner when registering, auto.\n\n            status: (t) => t.text(\"status\").notNullable().defaultTo(\"idle\"), // idle, running, completed, failed, paused\n            status_changed_at: (t) => t.timestamp(\"status_changed_at\").defaultTo(null),\n\n            progress: (t) => t.text(\"progress\"),\n            success: (t) => t.boolean(\"success\"),\n            results: (t) => t.jsonb(\"results\"),\n        },\n        indexes: [\n            {\n                columns: [\"service_group\", \"status\", \"priority\", \"created_at\"],\n                name: `${tableNameForIndex}_claim_idx`,\n            },\n            { columns: [\"service_group\", \"name\"], name: `${tableNameForIndex}_group_name_idx` },\n            { columns: [\"completed_at\"], name: `${tableNameForIndex}_completed_at_idx` },\n            { columns: [\"name\", \"completed_at\"], name: `${tableNameForIndex}_name_completed_at_idx` },\n        ],\n    };\n}\n\n/**\n * Spec for the services registry table of a queue.\n *\n * @param {string} registryTable\n * @returns {import(\"../db/ensure.js\").TableSpec}\n */\nfunction registryTableSpec(registryTable) {\n    return {\n        columns: {\n            id: (t, db) => t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\")),\n\n            queue_name: (t) => t.text(\"queue_name\").notNullable(),\n            service_group: (t) => t.text(\"service_group\").notNullable(), // harvester, loader, photos, ...\n            instance_number: (t) => t.integer(\"instance_number\").notNullable().defaultTo(1),\n            service_name: (t) => t.text(\"service_name\").notNullable(), // that's a \"<server_name>_<service_group>_<instance_number>\"\n            server_name: (t) => t.text(\"server_name\").notNullable(), // filled by runner when registering, auto.\n            pid: (t) => t.integer(\"pid\"),\n\n            metadata: (t) => t.json(\"metadata\"),\n\n            created_at: (t, db) => t.timestamp(\"created_at\").notNullable().defaultTo(db.fn.now()),\n            last_seen_at: (t, db) => t.timestamp(\"last_seen_at\").notNullable().defaultTo(db.fn.now()),\n        },\n        indexes: [\n            {\n                columns: [\"queue_name\", \"service_name\"],\n                name: `${registryTable}_queue_name_service_name_uniq`,\n                unique: true,\n            },\n            {\n                columns: [\"queue_name\", \"service_group\", \"last_seen_at\"],\n                name: `${registryTable}_queue_group_seen_idx`,\n            },\n            { columns: [\"queue_name\", \"last_seen_at\"], name: `${registryTable}_queue_seen_idx` },\n        ],\n        // TODO: a reference is needed - task_history entry should reference the registry entry, so that we can easily find all executed tasks for a given service and calculate the average workload or identify if there's a bottleneck. Also may be used for the load balancing.\n    };\n}\n\n/**\n * Full schema spec for one queue: active table + history mirror + registry.\n * Exported so callers (and tests) can feed it to `ensureSchema` /\n * `ensureSchemaEverywhere` directly.\n *\n * @param {string} [queueName]\n * @returns {import(\"../db/ensure.js\").SchemaSpec}\n */\nexport function tasksSchemaSpec(queueName = \"tasks\") {\n    const { tasksTable, historyTable, registryTable } = queueToTableNames(queueName);\n    return {\n        extensions: [\"uuid-ossp\"],\n        tables: {\n            [tasksTable]: tasksTableSpec(tasksTable),\n            [historyTable]: tasksTableSpec(historyTable),\n            [registryTable]: registryTableSpec(registryTable),\n        },\n    };\n}\n\n/**\n * Build an insert payload for `*_history`: never copies the queue row `id` as the history PK — PostgreSQL default\n * generates a new `id`. The snapshot still carries `name`, `opid`, `params`, etc. for auditing and ad hoc queries.\n *\n * When the queue row has no `opid`, we stamp `opid` with the queue row id so\n * {@link waitForTaskResult} can correlate history after the queue row is deleted\n * (history PK ≠ queue id). Explicit `opid` on the row or in `overrides` wins.\n *\n * @param {object} row      Original queue row.\n * @param {object} overrides Fields to override on the snapshot (e.g. `completed_at`, `success`).\n * @returns {object}\n */\nexport function taskHistoryInsertFromQueueRow(row, overrides = {}) {\n    const { id, ...snapshot } = row;\n    const opid =\n        overrides.opid !== undefined\n            ? overrides.opid\n            : snapshot.opid != null && String(snapshot.opid).trim() !== \"\"\n              ? snapshot.opid\n              : id;\n    return {\n        ...snapshot,\n        ...overrides,\n        opid,\n    };\n}\n\n/**\n * Idempotently make the three tables backing a queue (tasks / history /\n * registry) match the current spec — on one database or on many.\n *\n * Spec-driven (see {@link tasksSchemaSpec} + db/ensure.js), so this covers\n * BOTH cases: a missing table is created whole, and a table created by an\n * older version gets its missing columns/indexes added (never dropped or\n * altered in place).\n *\n * Multi-database: pass `databases: [handle, handle, ...]` (e.g. from\n * `Db.initAllSiblings(context, { prefix: \"src_\", includeMain: true })`) to\n * apply the same ensure to every database currently in use. Default stays\n * `context.db` only.\n *\n * Other options:\n *   - `recreate: true` — drop-and-recreate (dev/test only).\n *   - `dryRun: true`   — report the DDL it *would* run, change nothing.\n *\n * Requires the `uuid-ossp` extension; created on the fly if missing.\n *\n * @param {object} context\n * @param {{ queueName?: string, recreate?: boolean, dryRun?: boolean, databases?: Function[] }} [options]\n * @returns {Promise<void>}\n */\nexport async function ensureTaskTables(context, options = {}) {\n    const queueName = options.queueName ?? \"tasks\";\n    const recreate = options.recreate ?? false;\n    const dryRun = options.dryRun ?? false;\n    const databases = options.databases ?? [getDb(context)];\n    const log = context.logger ?? console;\n    const { tasksTable, historyTable, registryTable } = queueToTableNames(queueName);\n    const spec = tasksSchemaSpec(queueName);\n\n    for (const db of databases) {\n        const label = db?.config?.name ?? \"db\";\n\n        if (recreate) {\n            if (dryRun) {\n                log.info?.(\n                    `[tasks-schema] dryRun — ${label}: DROP TABLE IF EXISTS ${historyTable}, ${tasksTable}, ${registryTable}`,\n                );\n            } else {\n                await db.schema.dropTableIfExists(historyTable);\n                await db.schema.dropTableIfExists(tasksTable);\n                await db.schema.dropTableIfExists(registryTable);\n            }\n        }\n\n        const { actions } = await ensureSchema(db, spec, { dryRun, logger: context.logger });\n\n        // Older schemas had NOT NULL \"task\" (renamed to \"name\"). ensureSchema only\n        // adds columns, so a hybrid table breaks enqueueTask inserts into \"name\".\n        const legacyDrops = await dropLegacyTaskNameColumn(db, [tasksTable, historyTable], {\n            dryRun,\n            log,\n            label,\n        });\n\n        const allActions = [...actions, ...legacyDrops];\n        if (dryRun) {\n            if (allActions.length === 0) {\n                log.info?.(`[tasks-schema] dryRun — ${label}: queue \"${queueName}\" already up to date; no DDL`);\n            } else {\n                log.info?.(\n                    `[tasks-schema] dryRun — ${label}: would run ${allActions.length} statement(s) for queue \"${queueName}\":`,\n                );\n                for (const s of allActions) log.info?.(`  - ${s}`);\n            }\n        } else if (allActions.length > 0) {\n            log.info?.(\n                `[tasks-schema] ${label}: applied ${allActions.length} DDL statement(s) for queue \"${queueName}\"`,\n            );\n        }\n    }\n}\n\n/**\n * Drop legacy `task` text column when modern `name` is already present.\n * @returns {Promise<string[]>}\n */\nasync function dropLegacyTaskNameColumn(db, tableNames, { dryRun, log, label }) {\n    const actions = [];\n    for (const table of tableNames) {\n        if (!(await db.tableExists(table).catch(() => false))) continue;\n        const hasTask = await db.schema.hasColumn(table, \"task\");\n        const hasName = await db.schema.hasColumn(table, \"name\");\n        if (!hasTask || !hasName) continue;\n        const sql = `ALTER TABLE \"${table}\" DROP COLUMN IF EXISTS \"task\"`;\n        actions.push(sql);\n        if (dryRun) {\n            log?.info?.(`[tasks-schema] dryRun — ${label}: ${sql}`);\n        } else {\n            await db.raw(sql);\n            log?.info?.(`[tasks-schema] ${label}: dropped legacy column ${table}.task`);\n        }\n    }\n    return actions;\n}\n\n/**\n * Insert one task row into the queue. Supports targeting (service_group + optional\n * instance/server), recurring schedules (cron-like 6-field string, see `time-matcher.js`),\n * and explicit `nextRunAt` overrides.\n *\n * @param {object} context\n * @param {{\n *   queueName?: string,\n *   name?: string,\n *   task?: string,\n *   params?: unknown,\n *   opid?: string|null,\n *   priority?: number,\n *   schedule?: string|null,\n *   nextRunAt?: Date|string|number|null,\n *   serviceGroup?: string|null,\n *   instanceNumber?: number|null,\n *   serviceName?: string|null,\n *   serverName?: string|null,\n * }} options\n * @returns {Promise<string>} The new task's UUID.\n */\nexport async function enqueueTask(context, options) {\n    const db = getDb(context);\n    const queueName = options.queueName ?? \"tasks\";\n    const { tasksTable } = queueToTableNames(queueName);\n    const id = randomUUID();\n\n    const name = options.name ?? options.task;\n    if (!name) {\n        throw new Error(\"enqueueTask: name (or task) is required\");\n    }\n\n    const schedule = options.schedule?.trim() ? options.schedule : null;\n    let nextRunAt = null;\n    if (options.nextRunAt !== undefined) {\n        nextRunAt = options.nextRunAt == null ? null : new Date(options.nextRunAt);\n    } else if (schedule) {\n        nextRunAt = nextTimeMatch(schedule, new Date());\n    }\n\n    const row = {\n        id,\n        name,\n        params: toJsonColumn(options.params ?? null),\n        opid: options.opid ?? null,\n        priority: options.priority ?? 50,\n        schedule,\n        next_run_at: nextRunAt,\n        service_group: options.serviceGroup ?? null,\n        instance_number: options.instanceNumber ?? null,\n        service_name: options.serviceName ?? null,\n        server_name: options.serverName ?? null,\n        status: \"idle\",\n        status_changed_at: db.fn.now(),\n    };\n\n    // Hybrid DBs may still have legacy NOT NULL \"task\" until ensureTaskTables drops it.\n    if (await tableHasLegacyTaskColumn(db, tasksTable)) {\n        row.task = name;\n    }\n\n    await db(tasksTable).insert(row);\n    return id;\n}\n\n/** @type {Map<string, boolean>} */\nconst legacyTaskColumnCache = new Map();\n\nasync function tableHasLegacyTaskColumn(db, tableName) {\n    const key = `${db?.config?.name ?? \"db\"}:${tableName}`;\n    if (!legacyTaskColumnCache.has(key)) {\n        legacyTaskColumnCache.set(key, await db.schema.hasColumn(tableName, \"task\"));\n    }\n    return legacyTaskColumnCache.get(key);\n}\n\n/**\n * Update the `progress` column for one task. Strings go in verbatim; anything\n * else gets JSON-stringified so the column stays text-friendly.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {string} taskId\n * @param {unknown} progress\n * @returns {Promise<void>}\n */\nexport async function updateTaskProgress(context, tasksTable, taskId, progress) {\n    const db = getDb(context);\n    await db(tasksTable).where({ id: taskId }).update({\n        progress: typeof progress === \"string\" ? progress : JSON.stringify(progress),\n    });\n}\n\n/**\n * Progress reporter for one running task: at most one in-flight UPDATE, with\n * the latest value coalesced. Prevents fire-and-forget per-photo writes from\n * saturating the Knex pool under high `maxParallel`.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {string} taskId\n * @returns {(progress: unknown) => Promise<void>}\n */\nexport function createTaskProgressReporter(context, tasksTable, taskId) {\n    let pump = null;\n    let pending = undefined;\n    let hasPending = false;\n\n    return (progress) => {\n        pending = progress;\n        hasPending = true;\n        if (pump) return pump;\n\n        pump = (async () => {\n            try {\n                while (hasPending) {\n                    hasPending = false;\n                    const value = pending;\n                    try {\n                        await updateTaskProgress(context, tasksTable, taskId, value);\n                    } catch (err) {\n                        context.logger?.warn?.(\n                            `[tasks] progress update failed for ${taskId}: ${err?.message ?? err}`\n                        );\n                    }\n                }\n            } finally {\n                pump = null;\n            }\n        })();\n\n        return pump;\n    };\n}\n\n/** Optional product hook: `(row, { name, params }) => string|null`. */\nlet loggerTaskLabelResolver = null;\n\n/**\n * Inject a product-specific log-tag resolver (MLS leaf names, opid shapes, …).\n * The toolkit default is `params.logTask`, then `name:source`, then `name`.\n * Pass `null` to clear.\n *\n * @param {((row: object, parsed: { name: string, params: object|null }) => string|null|undefined)|null} fn\n */\nexport function setLoggerTaskLabelResolver(fn) {\n    loggerTaskLabelResolver = typeof fn === \"function\" ? fn : null;\n}\n\nfunction parseTaskParams(raw) {\n    if (raw && typeof raw === \"object\" && !Array.isArray(raw)) return raw;\n    if (typeof raw === \"string\") {\n        try {\n            const parsed = JSON.parse(raw);\n            if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n        } catch {\n            /* ignore */\n        }\n    }\n    return null;\n}\n\n/**\n * Top-level task tag for logger lines (`name:source`).\n * Prefer `params.logTask` when a parent stamped the child row.\n * Product-specific leaf/opid mapping is an injected resolver, not toolkit logic.\n *\n * @param {object} [row]\n * @returns {string}\n */\nexport function loggerTaskLabel(row) {\n    const name = String(row?.name || \"task\").trim() || \"task\";\n    const params = parseTaskParams(row?.params);\n    const explicit = params?.logTask != null ? String(params.logTask).trim() : \"\";\n    if (explicit) return explicit;\n    if (loggerTaskLabelResolver) {\n        const extra = loggerTaskLabelResolver(row, { name, params });\n        if (extra != null && String(extra).trim()) return String(extra).trim();\n    }\n    const source = params?.source != null ? String(params.source).trim() : \"\";\n    if (source) return `${name}:${source}`;\n    return name;\n}\n","/**\n * 6-field cron-like matcher: `sec min hour day month weekday`.\n * Fields support `*`, numeric literals, ranges (`1-5`), comma lists (`0,15,30,45`),\n * and step expressions (`*\\/10`, `0-30/5`). No named months/weekdays, no\n * `L`/`#`/`?` magic — keep patterns explicit.\n */\n\n/** Field index → `\"lo-hi\"` range that `*` expands into. Order: sec, min, hour, day, month, weekday. */\nconst RANGES = [\"0-59\", \"0-59\", \"0-23\", \"1-31\", \"1-12\", \"0-6\"];\n\n/**\n * Replace `*` with a concrete `lo-hi` range so the rest of the pipeline only\n * has to deal with numeric forms.\n *\n * @param {string} field\n * @param {string} range e.g. `\"0-59\"`\n * @returns {string}\n */\nexport function resolveAsterisks(field, range) {\n    return field.includes(\"*\") ? field.replace(\"*\", range) : field;\n}\n\n/**\n * Expand every `lo-hi` run in `field` to the comma-separated list of integers it\n * covers. Handles reversed bounds (`5-2` → `2,3,4,5`). Does not handle steps;\n * run {@link resolveSteps} after this.\n *\n * @param {string} field\n * @returns {string}\n */\nexport function resolveRanges(field) {\n    const regex = /(\\d+)-(\\d+)/;\n    let current = field;\n    while (true) {\n        const match = regex.exec(current);\n        if (!match) break;\n        const raw = match[0];\n        let first = Number(match[1]);\n        let last = Number(match[2]);\n        if (last < first) {\n            [first, last] = [last, first];\n        }\n        const values = [];\n        for (let i = first; i <= last; i += 1) {\n            values.push(i);\n        }\n        current = current.replace(raw, values.join(\",\"));\n    }\n    return current;\n}\n\n/**\n * Apply a `.../step` suffix, keeping only values divisible by `step`.\n * Expects ranges to already be expanded to comma-lists. No-op when the suffix is missing.\n *\n * @param {string} field e.g. `\"0,1,2,...,59/10\"` → `\"0,10,20,30,40,50\"`\n * @returns {string}\n */\nexport function resolveSteps(field) {\n    const match = /^(.+)\\/(\\d+)$/.exec(field);\n    if (!match) return field;\n    const base = match[1];\n    const step = Number(match[2]);\n    if (!Number.isFinite(step) || step <= 0) return field;\n    return base\n        .split(\",\")\n        .map((v) => Number(v))\n        .filter((v) => Number.isFinite(v) && v % step === 0)\n        .join(\",\");\n}\n\n/**\n * Normalize a raw 6-field schedule string into an array of comma-separated integer\n * lists — one per field, ready for {@link matchesParsedPattern}.\n *\n * @param {string} pattern\n * @returns {string[]}\n * @throws If `pattern` does not contain exactly six whitespace-separated fields.\n */\nexport function convertPattern(pattern) {\n    const parts = pattern.trim().split(/\\s+/);\n    if (parts.length !== 6) {\n        throw new Error(`Invalid schedule \"${pattern}\". Expected 6 fields: sec min hour day month weekday`);\n    }\n    return parts\n        .map((field, idx) => resolveAsterisks(field, RANGES[idx]))\n        .map((field) => resolveRanges(field))\n        .map((field) => resolveSteps(field));\n}\n\n/**\n * Does `value` appear in the comma-list `field`?\n *\n * @param {string} field\n * @param {number} value\n * @returns {boolean}\n */\nfunction fieldMatches(field, value) {\n    const allowed = field.split(\",\").map((v) => Number(v));\n    return allowed.includes(value);\n}\n\n/**\n * Check an already-parsed pattern against a `Date`. All six fields must match\n * (month is 1-indexed here; weekday follows `Date#getDay`, 0 = Sunday).\n *\n * @param {string[]} parsed Output of {@link convertPattern}.\n * @param {Date} date\n * @returns {boolean}\n */\nexport function matchesParsedPattern(parsed, date) {\n    return (\n        fieldMatches(parsed[0], date.getSeconds()) &&\n        fieldMatches(parsed[1], date.getMinutes()) &&\n        fieldMatches(parsed[2], date.getHours()) &&\n        fieldMatches(parsed[3], date.getDate()) &&\n        fieldMatches(parsed[4], date.getMonth() + 1) &&\n        fieldMatches(parsed[5], date.getDay())\n    );\n}\n\n/**\n * One-shot check: does `pattern` match `date`? Parses the pattern each call —\n * fine for the runner loop where we only test one date per tick; use\n * {@link convertPattern} + {@link matchesParsedPattern} if you need to test\n * many dates against the same schedule.\n *\n * @param {string} pattern\n * @param {Date} [date]\n * @returns {boolean}\n */\nexport function timeMatcher(pattern, date = new Date()) {\n    const parsed = convertPattern(pattern);\n    return matchesParsedPattern(parsed, date);\n}\n\nconst MS_PER_SECOND = 1000;\nconst DEFAULT_SEARCH_HORIZON_MS = 10 * 365 * 24 * 60 * 60 * MS_PER_SECOND;\n\n/**\n * Earliest calendar second strictly after `from` where the schedule matches.\n * Use this to sleep until the next run instead of polling `timeMatcher` and risking missed seconds.\n *\n * @param {string} pattern Same 6-field format as `timeMatcher`: `sec min hour day month weekday`\n * @param {Date} [from=new Date()] Reference instant. Matching is second-granularity; search starts at the next second after `from`.\n * @param {number} [maxSearchMs] Abort if no match within this window (default ~10 years).\n * @returns {Date}\n */\nexport function nextTimeMatch(\n    pattern,\n    from = new Date(),\n    maxSearchMs = DEFAULT_SEARCH_HORIZON_MS\n) {\n    const parsed = convertPattern(pattern);\n    let t = Math.ceil((from.getTime() + 1) / MS_PER_SECOND) * MS_PER_SECOND;\n    const end = t + maxSearchMs;\n    while (t <= end) {\n        const date = new Date(t);\n        if (matchesParsedPattern(parsed, date)) {\n            return date;\n        }\n        t += MS_PER_SECOND;\n    }\n    throw new Error(\n        `nextTimeMatch: no match for \"${pattern}\" within ${maxSearchMs}ms after ${from.toISOString()}`\n    );\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { FileDatabase } from \"../filedatabase/index.js\";\nimport { isTimestampFolder } from \"../utils/date-utils.js\";\n\n/**\n * Gets or lazily builds the default IPC-logs FileDatabase state, cached on\n * `context.__tasksLogsState`. Reads `tasksLogs*` params (basePath, namespace,\n * table, errorTable, enabled, maxVersions, pageSize). When `tasksLogsEnabled=false`\n * the main `db` is null but `errorDb` still captures error payloads.\n *\n * @param {object} context\n * @returns {object} `{ db, errorDb, queue, initialized, errorInitialized }`\n */\nfunction getLogsState(context) {\n    const holder = context;\n    if (holder.__tasksLogsState) return holder.__tasksLogsState;\n\n    const basePath = holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\";\n    const namespace = holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\";\n    const tableName = holder.params?.get?.(\"tasksLogsTable\") || \"runner\";\n    const errorTableName = holder.params?.get?.(\"tasksErrorLogsTable\") || `${tableName}-errors`;\n    const maxVersionsRaw = Number(holder.params?.get?.(\"tasksLogsMaxVersions\"));\n    const pageSizeRaw = Number(holder.params?.get?.(\"tasksLogsPageSize\"));\n\n    const errorDb = new FileDatabase({\n        basePath,\n        namespace,\n        tableName: errorTableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: Number.isFinite(maxVersionsRaw) && maxVersionsRaw > 0 ? maxVersionsRaw : 20,\n        pageSize: Number.isFinite(pageSizeRaw) && pageSizeRaw > 0 ? pageSizeRaw : 2000,\n        logger: holder.logger,\n    });\n\n    const enabledRaw = holder.params?.get?.(\"tasksLogsEnabled\");\n    const enabled = enabledRaw === undefined ? true : !!enabledRaw;\n    if (!enabled) {\n        const disabledState = {\n            db: null,\n            errorDb,\n            queue: Promise.resolve(),\n            initialized: true,\n            errorInitialized: false,\n        };\n        holder.__tasksLogsState = disabledState;\n        return disabledState;\n    }\n\n    const db = new FileDatabase({\n        basePath,\n        namespace,\n        tableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: Number.isFinite(maxVersionsRaw) && maxVersionsRaw > 0 ? maxVersionsRaw : 20,\n        pageSize: Number.isFinite(pageSizeRaw) && pageSizeRaw > 0 ? pageSizeRaw : 2000,\n        logger: holder.logger,\n    });\n    const state = {\n        db,\n        errorDb,\n        queue: Promise.resolve(),\n        initialized: false,\n        errorInitialized: false,\n    };\n    holder.__tasksLogsState = state;\n    return state;\n}\n\n/**\n * Cache key for a target so multiple writers sharing the same\n * `basePath`/`namespace`/`tableName` reuse one FileDatabase state\n * (see `getLogsStateForTarget`).\n *\n * @param {object} target `{ basePath?, namespace?, tableName }`\n * @returns {string}\n */\nfunction ipcLogTargetKey(target) {\n    const bp = target.basePath ?? \"\";\n    const ns = target.namespace ?? \"\";\n    return `${bp}::${ns}::${target.tableName}`;\n}\n\n/**\n * Produce a FileDatabase `tableName` of the form `source/resource`, sanitizing each\n * segment so only `[a-zA-Z0-9._-]` survive. Empty segments fall back to `\"x\"`.\n *\n * @param {string} source\n * @param {string} resource\n * @returns {string} e.g. `\"actris/properties\"`\n */\nexport function ipcFileLogsTableNameForSourceResource(source, resource) {\n    const seg = (s) => {\n        const t = String(s).trim().replace(/[^a-zA-Z0-9._-]+/g, \"_\").replace(/^_+|_+$/g, \"\");\n        return t.length ? t : \"x\";\n    };\n    return `${seg(source)}/${seg(resource)}`;\n}\n\n/**\n * Read IPC log records from the latest FileDatabase version for `source/resource`.\n * Intended for tailing / incremental polling — use the returned `latestTs` as the\n * next call's `afterTs`.\n *\n * @param {object} context\n * @param {object} options\n * @param {string} options.source\n * @param {string} options.resource\n * @param {number} [options.tail=100]     Max records returned after filtering (clamped 1..10000).\n * @param {string|null} [options.afterTs] ISO timestamp watermark; keeps rows with `ts > afterTs`.\n * @param {string|null} [options.fromTs]  Inclusive lower bound (`ts >= fromTs`).\n * @param {string|null} [options.toTs]    Inclusive upper bound (`ts <= toTs`).\n * @param {string|null} [options.taskId]  Keep only rows stamped with this task id.\n * @returns {Promise<{ records: object[], latestTs: string|null }>}\n */\nexport function filterIpcLogRecords(records, { afterTs, fromTs, toTs, taskId } = {}) {\n    const after = afterTs && String(afterTs).trim() ? String(afterTs).trim() : \"\";\n    const from = fromTs && String(fromTs).trim() ? String(fromTs).trim() : \"\";\n    const to = toTs && String(toTs).trim() ? String(toTs).trim() : \"\";\n    const id = taskId != null && String(taskId).trim() ? String(taskId).trim() : \"\";\n    return (Array.isArray(records) ? records : []).filter((r) => {\n        if (!r || typeof r.ts !== \"string\") return false;\n        const ts = String(r.ts);\n        if (after && !(ts > after)) return false;\n        if (from && ts < from) return false;\n        if (to && ts > to) return false;\n        if (id && String(r.taskId ?? \"\") !== id) return false;\n        return true;\n    });\n}\n\nfunction latestIpcRecordTs(records) {\n    let latestTs = null;\n    for (const r of records ?? []) {\n        const ts = typeof r?.ts === \"string\" ? String(r.ts) : null;\n        if (ts && (!latestTs || ts > latestTs)) latestTs = ts;\n    }\n    return latestTs;\n}\n\nexport async function readTaskIpcLogsSnapshot(context, options) {\n    const holder = context;\n    const basePath = holder.params?.get?.(\"tasksLogsBasePath\") ?? \"./data\";\n    const namespace = holder.params?.get?.(\"tasksLogsNamespace\") ?? \"tasks-logs\";\n    const tableName = ipcFileLogsTableNameForSourceResource(options.source, options.resource);\n    const tail = Math.max(1, Math.min(10_000, Number(options.tail) > 0 ? Number(options.tail) : 100));\n    const fromTs = options.fromTs && String(options.fromTs).trim() ? String(options.fromTs).trim() : \"\";\n    const toTs = options.toTs && String(options.toTs).trim() ? String(options.toTs).trim() : \"\";\n    const wantsWindow = !!(fromTs || toTs);\n\n    const fd = new FileDatabase({\n        basePath,\n        namespace,\n        tableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: 30,\n        pageSize: 2000,\n        logger: holder.logger,\n    });\n\n    const versions = await fd.getVersions();\n    if (versions.length === 0) {\n        return { records: [], latestTs: null };\n    }\n\n    const versionsToRead = wantsWindow ? [...versions].reverse() : [versions[versions.length - 1]];\n    const collected = [];\n    for (const version of versionsToRead) {\n        const { records: arr } = await readIpcLogVersion(fd, version, holder.logger, tableName);\n        appendItems(collected, arr);\n        if (!wantsWindow) break;\n        if (fromTs) {\n            let minTs = null;\n            for (const r of arr) {\n                const ts = typeof r?.ts === \"string\" ? r.ts : null;\n                if (ts && (!minTs || ts < minTs)) minTs = ts;\n            }\n            if (minTs && minTs <= fromTs) break;\n        }\n    }\n\n    const filtered = filterIpcLogRecords(collected, {\n        afterTs: options.afterTs,\n        fromTs,\n        toTs,\n        taskId: options.taskId,\n    });\n    filtered.sort((a, b) => String(a?.ts ?? \"\").localeCompare(String(b?.ts ?? \"\")));\n\n    /** Watermark for incremental fetches: max `ts` among all matching rows, not only the returned tail. */\n    const latestTs = latestIpcRecordTs(filtered);\n\n    const incremental = !!(options.afterTs && String(options.afterTs).trim());\n    /** Incremental polls may return many lines between ticks — cap at 10k so we do not drop rows then advance `latestTs` past them. */\n    const maxReturn = incremental || wantsWindow ? 10_000 : tail;\n    const sliced = filtered.length > maxReturn ? filtered.slice(-maxReturn) : filtered;\n\n    return { records: sliced, latestTs };\n}\n\n/**\n * Absolute path to the FileDatabase table directory for a given target (matches the\n * FileDatabase on-disk layout). Versioned writes create timestamp subfolders inside.\n *\n * @param {object} context\n * @param {object} target `{ basePath?, namespace?, tableName }`\n * @returns {string}\n */\nexport function resolveIpcFileLogsDir(context, target) {\n    const holder = context;\n    const basePath = target.basePath ?? (holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\");\n    const namespace = target.namespace ?? (holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\");\n    const segments = target.tableName.split(\"/\").filter(Boolean);\n    return path.resolve(basePath, namespace, ...segments);\n}\n\n/**\n * Lazily build a FileDatabase state for the given target, memoized on\n * `context.__tasksLogsTargetStates` (Map keyed by `ipcLogTargetKey`).\n * Returns `null` when `tasksLogsEnabled=false`.\n *\n * @param {object} context\n * @param {object} target `{ basePath?, namespace?, tableName }`\n * @returns {object|null} same shape as `getLogsState`, but `errorDb` is always null.\n */\nfunction getLogsStateForTarget(context, target) {\n    const holder = context;\n    const enabledRaw = holder.params?.get?.(\"tasksLogsEnabled\");\n    const enabled = enabledRaw === undefined ? true : !!enabledRaw;\n    if (!enabled) return null;\n\n    if (!holder.__tasksLogsTargetStates) holder.__tasksLogsTargetStates = new Map();\n    const map = holder.__tasksLogsTargetStates;\n    const key = ipcLogTargetKey(target);\n    if (map.has(key)) return map.get(key);\n\n    const basePath = target.basePath ?? (holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\");\n    const namespace = target.namespace ?? (holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\");\n    const maxVersionsRaw = Number(holder.params?.get?.(\"tasksLogsMaxVersions\"));\n    const pageSizeRaw = Number(holder.params?.get?.(\"tasksLogsPageSize\"));\n\n    const db = new FileDatabase({\n        basePath,\n        namespace,\n        tableName: target.tableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: Number.isFinite(maxVersionsRaw) && maxVersionsRaw > 0 ? maxVersionsRaw : 20,\n        pageSize: Number.isFinite(pageSizeRaw) && pageSizeRaw > 0 ? pageSizeRaw : 2000,\n        logger: holder.logger,\n    });\n    const state = {\n        db,\n        errorDb: null,\n        queue: Promise.resolve(),\n        initialized: false,\n        errorInitialized: false,\n    };\n    map.set(key, state);\n    return state;\n}\n\n/**\n * Heuristic: does this IPC payload represent an error?\n *   - object with `level` of `\"error\"`/`\"fatal\"`, OR\n *   - object with a `message` string containing the word \"error\", OR\n *   - plain string containing \"error\" (case-insensitive).\n *\n * @param {unknown} payload\n * @returns {boolean}\n */\nfunction isErrorPayload(payload) {\n    if (!payload) return false;\n    if (typeof payload === \"object\") {\n        const level = typeof payload.level === \"string\" ? payload.level.toLowerCase() : \"\";\n        if (level === \"error\" || level === \"fatal\") return true;\n        if (typeof payload.message === \"string\" && /\\berror\\b/i.test(payload.message)) return true;\n        return false;\n    }\n    if (typeof payload === \"string\") {\n        return /\\berror\\b/i.test(payload);\n    }\n    return false;\n}\n\n/**\n * Build the persisted log record for an IPC payload. Copies `source`/`resource` from\n * `task.params` when present so logs stay queryable by them later.\n *\n * @param {object} task\n * @param {unknown} payload\n * @returns {object} `{ ts, opid, taskId, taskName, target, source, resource, payload }`\n */\nfunction buildLogRecord(task, payload) {\n    const params = task.params && typeof task.params === \"object\" ? task.params : {};\n    return {\n        ts: new Date().toISOString(),\n        opid: task.opid ?? null,\n        taskId: task.id,\n        taskName: task.name,\n        target: task.service_group,\n        source: typeof params.source === \"string\" ? params.source : null,\n        resource: typeof params.resource === \"string\" ? params.resource : null,\n        payload,\n    };\n}\n\n/**\n * Append one IPC log line from a child worker. Never throws; writes are serialized\n * per-state on a promise queue (drain with `flushTaskIpcLogs`).\n *\n *   - Without `target`: writes to the default store (`tasksLogsTable`, usually `runner`)\n *     and, when the payload looks like an error, also to `tasksErrorLogsTable`.\n *   - With `target`: writes only to that target's store (e.g. per source/resource,\n *     later read by `readTaskIpcLogsSnapshot`).\n *\n * @param {object} context\n * @param {object} task\n * @param {unknown} payload\n * @param {object} [target] `{ basePath?, namespace?, tableName }`\n * @returns {void}\n */\nexport function appendTaskIpcLog(context, task, payload, target) {\n    if (target) {\n        const state = getLogsStateForTarget(context, target);\n        if (!state?.db) return;\n        const record = buildLogRecord(task, payload);\n        state.queue = state.queue\n            .then(async () => {\n                await state.db.write([record], { forceNewVersion: !state.initialized });\n                state.initialized = true;\n            })\n            .catch((error) => {\n                context.logger.warn?.(\"[tasks] failed to persist IPC log entry (targeted):\", error);\n            });\n        return;\n    }\n\n    const state = getLogsState(context);\n    if (!state.db && !state.errorDb) return;\n\n    const record = buildLogRecord(task, payload);\n    state.queue = state.queue\n        .then(async () => {\n            if (state.db) {\n                await state.db.write([record], { forceNewVersion: !state.initialized });\n                state.initialized = true;\n            }\n            if (state.errorDb && isErrorPayload(payload)) {\n                await state.errorDb.write([record], { forceNewVersion: !state.errorInitialized });\n                state.errorInitialized = true;\n            }\n        })\n        .catch((error) => {\n            context.logger.warn?.(\"[tasks] failed to persist IPC log entry:\", error);\n        });\n}\n\n/**\n * Await pending FileDatabase writes from task IPC logging (default store + every\n * per-target store). Does not close anything; subsequent appends continue to work.\n *\n * @param {object} context\n * @returns {Promise<void>}\n */\nexport async function flushTaskIpcLogs(context) {\n    const holder = context;\n    const promises = [];\n    if (holder.__tasksLogsState?.queue) promises.push(holder.__tasksLogsState.queue);\n    const map = holder.__tasksLogsTargetStates;\n    if (map) {\n        for (const s of map.values()) {\n            if (s.queue) promises.push(s.queue);\n        }\n    }\n    await Promise.all(promises);\n}\n\nexport function tasksLogsRoot(context) {\n    const holder = context ?? {};\n    const basePath = holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\";\n    const namespace = holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\";\n    return path.resolve(basePath, namespace);\n}\n\n/**\n * `arr.push(...items)` throws Maximum call stack size exceeded on large items.\n * @param {unknown[]} target\n * @param {unknown[]} items\n */\nexport function appendItems(target, items) {\n    if (!items?.length) return target;\n    for (let i = 0; i < items.length; i++) target.push(items[i]);\n    return target;\n}\n\n/**\n * Decide what to drop / rewrite for one IPC table.\n * @param {{ version: string, records: object[], missingChunks?: number }[]} versions\n * @param {string} cutoff ISO\n */\nexport function planIpcLogPrune(versions, cutoff) {\n    const cut = String(cutoff);\n    const kept = [];\n    const deleteVersions = [];\n    let dropped = 0;\n    let needsRewrite = false;\n    for (const { version, records, missingChunks } of versions ?? []) {\n        const arr = Array.isArray(records) ? records : [];\n        const live = arr.filter((r) => typeof r?.ts === \"string\" && r.ts >= cut);\n        dropped += arr.length - live.length;\n        appendItems(kept, live);\n        if (live.length === 0) deleteVersions.push(version);\n        else if (live.length < arr.length || Number(missingChunks) > 0) needsRewrite = true;\n    }\n    return {\n        kept,\n        dropped,\n        deleteVersions,\n        rewrite: needsRewrite,\n        deleteAll: kept.length === 0 && (versions?.length ?? 0) > 0,\n    };\n}\n\nasync function listIpcLogTableNames(root) {\n    const tables = [];\n    const walk = async (dir, prefix) => {\n        let entries;\n        try {\n            entries = await fs.readdir(dir, { withFileTypes: true });\n        } catch {\n            return;\n        }\n        const versionDirs = entries.filter((e) => e.isDirectory() && isTimestampFolder(e.name));\n        if (versionDirs.length && prefix) {\n            tables.push(prefix);\n            return;\n        }\n        for (const e of entries) {\n            if (!e.isDirectory() || isTimestampFolder(e.name)) continue;\n            const next = prefix ? `${prefix}/${e.name}` : e.name;\n            await walk(path.join(dir, e.name), next);\n        }\n    };\n    await walk(root, \"\");\n    return tables;\n}\n\nasync function removeVersionDir(tableDir, version) {\n    await fs.rm(path.join(tableDir, version), { recursive: true, force: true });\n}\n\n/** Live writes are in-place; do not delete a file that may still be flushing. */\nconst UNREADABLE_IPC_LOG_GRACE_MS = 10_000;\n\nfunction ipcLogBrokenFileName(message) {\n    const m = String(message ?? \"\").match(/Failed to read file ([^:]+):/i);\n    const name = m?.[1]?.trim() ?? \"\";\n    if (!name || name.includes(\"/\") || name.includes(\"\\\\\") || name.includes(\"..\")) return null;\n    return name;\n}\n\n/**\n * Drop a truncated / unparseable IPC chunk (or the whole version if we cannot\n * name the file). Returns what was removed, or null when the file is too new.\n */\nasync function removeUnreadableIpcLog(fd, version, message) {\n    const dest = fd.getDestinationPath(version);\n    const fileName = ipcLogBrokenFileName(message);\n    const target = fileName ? path.join(dest, fileName) : dest;\n    try {\n        const st = await fs.stat(target);\n        if (Date.now() - Number(st.mtimeMs) < UNREADABLE_IPC_LOG_GRACE_MS) return null;\n    } catch {\n        return null;\n    }\n    if (fileName) {\n        await fs.rm(target, { force: true });\n        let leftover = [];\n        try {\n            leftover = (await fs.readdir(dest)).filter((n) => n !== \"metadata.json\" && !n.startsWith(\".\"));\n        } catch {\n            leftover = [];\n        }\n        if (leftover.length === 0) {\n            await fs.rm(dest, { recursive: true, force: true });\n            return `${version}/${fileName}`;\n        }\n        return fileName;\n    }\n    await fs.rm(dest, { recursive: true, force: true });\n    return version;\n}\n\nasync function readIpcLogVersion(fd, version, logger, tableName) {\n    try {\n        fd.lastReadMissingFiles = [];\n        const raw = await fd.read({ version });\n        const missingChunks = Array.isArray(fd.lastReadMissingFiles) ? fd.lastReadMissingFiles.length : 0;\n        return { version, records: Array.isArray(raw) ? raw : [], missingChunks };\n    } catch (err) {\n        const msg = err?.message ?? String(err);\n        let removed = null;\n        try {\n            removed = await removeUnreadableIpcLog(fd, version, msg);\n        } catch {\n            /* still skip this poll */\n        }\n        logger?.warn?.(\n            `[tasks-logs] ${removed ? \"deleted\" : \"skipping\"} unreadable IPC log ${tableName}/${version}: ${msg}`,\n        );\n        return { version, records: [], missingChunks: 0 };\n    }\n}\n\nasync function compactIpcLogTable(context, tableName, cutoff) {\n    const holder = context;\n    const basePath = holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\";\n    const namespace = holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\";\n    const fd = new FileDatabase({\n        basePath,\n        namespace,\n        tableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: 30,\n        pageSize: 2000,\n        logger: holder.logger,\n    });\n    const versions = await fd.getVersions();\n    if (versions.length === 0) return { table: tableName, dropped: 0, deletedVersions: 0 };\n\n    const loaded = [];\n    for (const version of versions) {\n        loaded.push(await readIpcLogVersion(fd, version, holder.logger, tableName));\n    }\n    const plan = planIpcLogPrune(loaded, cutoff);\n    const tableDir = resolveIpcFileLogsDir(context, { tableName, basePath, namespace });\n\n    if (plan.deleteAll) {\n        for (const version of versions) await removeVersionDir(tableDir, version);\n        return { table: tableName, dropped: plan.dropped, deletedVersions: versions.length };\n    }\n\n    if (plan.rewrite) {\n        await fd.write(plan.kept, { forceNewVersion: true });\n        const keep = fd.currentVersion;\n        for (const version of await fd.getVersions()) {\n            if (version !== keep) await removeVersionDir(tableDir, version);\n        }\n        return { table: tableName, dropped: plan.dropped, deletedVersions: versions.length, rewritten: true };\n    }\n\n    for (const version of plan.deleteVersions) await removeVersionDir(tableDir, version);\n    return { table: tableName, dropped: plan.dropped, deletedVersions: plan.deleteVersions.length };\n}\n\nfunction invalidateIpcLogWriter(context, tableName) {\n    const holder = context;\n    holder.__tasksLogsTargetStates?.delete(ipcLogTargetKey({ tableName }));\n    const defaultTable = holder.params?.get?.(\"tasksLogsTable\") || \"runner\";\n    if (tableName === defaultTable) holder.__tasksLogsState = undefined;\n}\n\nfunction enqueueOnLogQueue(context, tableName, work) {\n    const state = getLogsStateForTarget(context, { tableName });\n    if (!state) return work();\n    const done = state.queue.then(work, work);\n    state.queue = done.catch(() => {});\n    return done;\n}\n\n/**\n * Drop IPC FileDatabase records older than `cutoff` (all tables under the logs namespace).\n *\n * @param {object} context\n * @param {string} cutoff ISO\n * @param {{ isStop?: () => boolean }} [opts]\n * @returns {Promise<{ tables: number, dropped: number, details: object[] }>}\n */\nexport async function pruneIpcLogsOlderThan(context, cutoff, opts = {}) {\n    const isStop = typeof opts.isStop === \"function\" ? opts.isStop : () => false;\n    const root = tasksLogsRoot(context);\n    const tables = await listIpcLogTableNames(root);\n    const details = [];\n    let dropped = 0;\n    for (const tableName of tables) {\n        if (isStop()) break;\n        try {\n            const out = await enqueueOnLogQueue(context, tableName, () =>\n                compactIpcLogTable(context, tableName, cutoff),\n            );\n            invalidateIpcLogWriter(context, tableName);\n            details.push(out);\n            dropped += Number(out?.dropped) || 0;\n        } catch (err) {\n            context?.logger?.warn?.(\n                `[tasks-retention] prune table ${tableName} failed: ${err?.message ?? err}`,\n            );\n            details.push({ table: tableName, dropped: 0, error: err?.message ?? String(err) });\n        }\n    }\n    return { tables: details.length, dropped, details };\n}\n","import { ParamError } from \"../errors.js\";\n\n/**\n * Base class every task handler extends. Holds the runner `context` and the\n * claimed task row, and defines the contract the runner calls into:\n *\n *   - {@link AbstractTask#cantRunReason}: synchronous / async precondition check.\n *     Returning a truthy string tells the runner \"skip for now, stash the reason\n *     into `progress`\" without burning a retry; returning `false` means \"go\".\n *   - {@link AbstractTask#run}: the actual work, handed a `reportProgress`\n *     callback that updates the DB `progress` column.\n *   - {@link AbstractTask#requestStop}: cooperative shutdown signal from the runner\n *     (noop by default; long-running tasks override to honor it).\n *\n * Static enqueue-time hooks (write-time validation):\n *\n *   - {@link AbstractTask.resolveParams}: build a full row payload (envelope +\n *     inner `params` blob) for {@link enqueueTask}. Subclasses normally do not\n *     override this — they override {@link AbstractTask.resolveCustomParams}\n *     instead. Override here only for envelope-level cross-field rules\n *     (e.g. \"stop tasks must target a specific service_name\").\n *   - {@link AbstractTask.resolveCustomParams}: validate / default the typed\n *     fields that go into the `params` JSON column. Default returns a\n *     `--paramsJson` passthrough; subclasses override.\n *\n * Both static methods are async and accept `(context, overrides)`. `overrides`\n * is a partial that wins over CLI/env values — the typical caller is the\n * {@link TasksRegistry#resolveTaskParams} dispatcher, which seeds it with\n * `{ name }`. Programmatic enqueuers can pass any envelope field plus\n * `overrides.params` to inject inner-blob values.\n */\nexport class AbstractTask {\n    /**\n     * Whether `send-task` should wait for completion (and print a result\n     * report) when no explicit `--wait` / `--noWait` flag is given. Defaults\n     * to false; short-lived probe tasks (e.g. `ping`) override to true.\n     *\n     * @type {boolean}\n     */\n    static defaultWaitForResult = false;\n\n    /**\n     * @param {object} context Runner context (db, logger, params, emitter...).\n     * @param {object} task    Task row as claimed from the queue.\n     */\n    constructor(context, task) {\n        this.context = context;\n        this.task = task;\n        /** @type {boolean} */\n        this._stopRequested = false;\n        /** @type {boolean} */\n        this._pauseRequested = false;\n    }\n\n    /**\n     * Return a short reason string when the task should be deferred (e.g. \"locked\n     * by source\"), or `false`/falsy when it is free to run. Default: always `false`.\n     *\n     * @returns {string | false | Promise<string | false>}\n     */\n    cantRunReason() {\n        return false;\n    }\n\n    /**\n     * Called by the runner when a stop has been requested. Subclasses running\n     * long loops should flip a flag here and check it between iterations.\n     *\n     * @param {number} [_allowanceMs] Grace period the runner promises before hard exit.\n     */\n    requestStop(_allowanceMs) {\n        this._stopRequested = true;\n    }\n\n    /**\n     * Cooperative pause signal (from `pauseTask` control-lane task). Long-running\n     * tasks must persist the resume cursor in `results.checkpointParams` and\n     * return `{ success: true, results: { taskPaused: true, checkpointParams } }`\n     * so the runner keeps the row as `status=paused` and the next claim continues\n     * from that point (not the next window). Hard stop of a scheduled task must\n     * do the same (`checkpointParams` is written on scheduled finalize).\n     *\n     * @param {number} [_allowanceMs]\n     */\n    requestPause(_allowanceMs) {\n        this._pauseRequested = true;\n    }\n\n    /** @returns {boolean} */\n    isStopRequested() {\n        return this._stopRequested === true;\n    }\n\n    /** @returns {boolean} */\n    isPauseRequested() {\n        return this._pauseRequested === true;\n    }\n\n    /**\n     * Perform the task. Must be implemented by subclasses.\n     *\n     * @param {(progress: unknown) => Promise<void>} _reportProgress\n     *        Updates the DB `progress` column. Accepts any serializable value;\n     *        strings are stored verbatim, objects are JSON-stringified.\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run(_reportProgress) {\n        throw new Error(\"AbstractTask.run must be implemented by subclass\");\n    }\n\n    /**\n     * Resolve a complete row payload for this task — envelope fields (queue,\n     * priority, targeting, schedule…) plus the inner `params` blob produced by\n     * {@link AbstractTask.resolveCustomParams}. Output shape matches\n     * {@link enqueueTask}'s `options` argument, so the typical call is:\n     *\n     *   const payload = await TaskClass.resolveParams(context, { name });\n     *   await enqueueTask(context, payload);\n     *\n     * Validation failures throw {@link ParamError} so the script aborts before\n     * a malformed row hits the DB.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides] Partial overrides; takes precedence over CLI/env.\n     *   Recognised keys: `name`, `queueName`, `priority`, `serviceGroup`,\n     *   `serviceName`, `instanceNumber`, `serverName`, `opid`, `schedule`,\n     *   `nextRunAt`, plus `params` (object — overlay onto inner blob).\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = AbstractTask._resolveMainFields(context, overrides);\n        const params = await this.resolveCustomParams(context, overrides);\n        return { ...main, params };\n    }\n\n    /**\n     * Resolve the inner JSON blob stored in the `params` column. Default\n     * implementation passes through `--paramsJson` (parsed as a JSON object)\n     * overlaid with `overrides.params` when supplied; returns `null` when\n     * neither is provided.\n     *\n     * Subclasses with typed fields should override and call\n     * {@link AbstractTask._mergeTypedParams} for layered CLI/env/JSON/override\n     * resolution, then validate and throw {@link ParamError} on bad input.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object|null>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        return AbstractTask._defaultParamsBlob(context, overrides);\n    }\n\n    /**\n     * Read main task envelope fields from `context.params` (CLI/env), with\n     * any matching key on `overrides` taking precedence. Internal; called by\n     * {@link AbstractTask.resolveParams}.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {object}\n     */\n    static _resolveMainFields(context, overrides = {}) {\n        const defs = {\n            queueName: \"string default tasks\",\n            priority: \"number default 50\",\n            serviceGroup: \"string\",\n            serviceName: \"string\",\n            instanceNumber: \"number\",\n            serverName: \"string\",\n            opid: \"string\",\n            schedule: \"string\",\n        };\n        const cli = context.params.getAllForModule(\"task-envelope\", defs);\n\n        const name = emptyToUndef(overrides.name) ?? emptyToUndef(context.params.get(\"name\", \"string\"));\n        if (!name) {\n            throw new ParamError(\"Task --name is required (e.g. ping, stop, dummyHarvest)\");\n        }\n\n        let instanceNumber;\n        const rawInstance = overrides.instanceNumber ?? cli.instanceNumber;\n        if (rawInstance !== undefined && rawInstance !== null && String(rawInstance).trim() !== \"\") {\n            const n = Number(rawInstance);\n            if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {\n                throw new ParamError(\"--instanceNumber must be a positive integer when set\");\n            }\n            instanceNumber = n;\n        } else {\n            instanceNumber = null;\n        }\n\n        const priorityRaw = overrides.priority ?? cli.priority ?? 50;\n        const priority = Number(priorityRaw);\n        if (!Number.isFinite(priority)) {\n            throw new ParamError(`--priority must be a number (got ${JSON.stringify(priorityRaw)})`);\n        }\n\n        return {\n            name,\n            queueName: overrides.queueName ?? emptyToUndef(cli.queueName) ?? \"tasks\",\n            priority,\n            serviceGroup: emptyToUndef(overrides.serviceGroup) ?? emptyToUndef(cli.serviceGroup) ?? null,\n            serviceName: emptyToUndef(overrides.serviceName) ?? emptyToUndef(cli.serviceName) ?? null,\n            instanceNumber,\n            serverName: emptyToUndef(overrides.serverName) ?? emptyToUndef(cli.serverName) ?? null,\n            opid: emptyToUndef(overrides.opid) ?? emptyToUndef(cli.opid) ?? null,\n            schedule: emptyToUndef(overrides.schedule) ?? emptyToUndef(cli.schedule) ?? null,\n            nextRunAt: overrides.nextRunAt ?? null,\n        };\n    }\n\n    /**\n     * Default inner-params resolver: parses `--paramsJson` (must be a JSON\n     * object), then overlays `overrides.params` on top. Returns `null` when\n     * neither is provided.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {object|null}\n     */\n    static _defaultParamsBlob(context, overrides = {}) {\n        const cli = context.params.getAllForModule(\"task-params\", { paramsJson: \"string\" });\n        const fromJson = parseParamsJson(cli.paramsJson);\n        const fromOverride = pickParamsObject(overrides);\n        if (!fromJson && !fromOverride) return null;\n        return { ...(fromJson ?? {}), ...(fromOverride ?? {}) };\n    }\n\n    /**\n     * Helper for subclass `resolveCustomParams` overrides. Reads typed CLI\n     * params (per `defs`) plus `--paramsJson` under a module namespace, then\n     * merges them with explicit `overrides.params` in increasing priority:\n     *\n     *   typed CLI flags → --paramsJson → overrides.params\n     *\n     * Undefined values are dropped so defaults declared in `defs` aren't\n     * overwritten by missing-flag noise. Returns the merged object; the\n     * caller is responsible for validation and throwing `ParamError`.\n     *\n     * @param {object} context\n     * @param {string} moduleName Namespace for `--showUsedParams` grouping.\n     * @param {Record<string, string>} defs Param defs in `getAllForModule` syntax.\n     * @param {Record<string, unknown>} [overrides] As passed to `resolveCustomParams`.\n     * @returns {Record<string, unknown>}\n     */\n    static _mergeTypedParams(context, moduleName, defs, overrides = {}) {\n        const fullDefs = { ...defs, paramsJson: \"string\" };\n        const cliRaw = context.params.getAllForModule(moduleName, fullDefs);\n        const fromJson = parseParamsJson(cliRaw.paramsJson) ?? {};\n        const fromCli = {};\n        for (const [k, v] of Object.entries(cliRaw)) {\n            if (k === \"paramsJson\") continue;\n            if (v !== undefined && v !== null) fromCli[k] = v;\n        }\n        const fromOverride = pickParamsObject(overrides) ?? {};\n        return { ...fromCli, ...fromJson, ...fromOverride };\n    }\n}\n\n/** Trim a string-ish to a non-empty string, or return undefined. Non-strings pass through. */\nfunction emptyToUndef(s) {\n    if (s === undefined || s === null) return undefined;\n    if (typeof s !== \"string\") return s;\n    const t = s.trim();\n    return t.length ? t : undefined;\n}\n\n/**\n * Parse a `--paramsJson` value. Returns `null` for empty/missing input.\n * Throws `ParamError` for non-JSON or non-object payloads.\n *\n * @param {unknown} raw\n * @returns {object|null}\n */\nfunction parseParamsJson(raw) {\n    if (raw == null) return null;\n    const t = String(raw).trim();\n    if (!t) return null;\n    let parsed;\n    try {\n        parsed = JSON.parse(t);\n    } catch (e) {\n        throw new ParamError(`--paramsJson: not valid JSON: ${e?.message ?? String(e)}`);\n    }\n    if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n        throw new ParamError(\"--paramsJson must be a JSON object\");\n    }\n    return parsed;\n}\n\n/** Extract `overrides.params` when it is a plain object, else undefined. */\nfunction pickParamsObject(overrides) {\n    const p = overrides?.params;\n    if (p && typeof p === \"object\" && !Array.isArray(p)) return p;\n    return undefined;\n}\n","import { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Trivial health-check task: used by `registryMaintenance` to probe runners and\n * by operators to confirm a runner is picking up work. Emits a log line and\n * returns `{ success: true, results: \"pong\" }`.\n */\nexport class TaskPing extends AbstractTask {\n    /** Default-wait so `send-task --name=ping` prints a result without `--wait`. */\n    static defaultWaitForResult = true;\n\n    /** Ping takes no params. */\n    static async resolveCustomParams() {\n        return null;\n    }\n\n    /**\n     * @returns {Promise<{ success: true, results: \"pong\" }>}\n     */\n    async run() {\n        this.context.logger.info?.(`[TaskPing] pong (${this.task.id})`);\n        return { success: true, results: \"pong\" };\n    }\n}\n","import { sleepMs } from \"../../utils/index.js\";\nimport { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Long-running demo task used for exercising the runner's progress/stop paths.\n *\n * Ticks `total` times with `delay` ms between iterations, calling `reportProgress`\n * each tick. Honors cooperative stop (`requestStop`) by completing the current\n * iteration and deciding whether to finish the run or abort based on the\n * remaining work vs. the allowance window.\n */\nexport class TaskSampleProcess extends AbstractTask {\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ total: number, delay: number, name?: string }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-sample-process\", {\n            total: \"number default 10\",\n            delay: \"number default 1000\",\n            name: \"string\",\n        }, overrides);\n        const total = Number(merged.total);\n        const delay = Number(merged.delay);\n        if (!Number.isInteger(total) || total <= 0) {\n            throw new ParamError(`sampleProcess: param \"total\" must be a positive integer (got ${JSON.stringify(merged.total)})`);\n        }\n        if (!Number.isInteger(delay) || delay < 0) {\n            throw new ParamError(`sampleProcess: param \"delay\" must be an integer >= 0 (got ${JSON.stringify(merged.delay)})`);\n        }\n        const out = { total, delay };\n        if (typeof merged.name === \"string\" && merged.name.trim()) {\n            out.name = merged.name.trim();\n        }\n        return out;\n    }\n\n    /**\n     * @param {object} context\n     * @param {object} task\n     */\n    constructor(context, task) {\n        super(context, task);\n        this.stopRequested = false;\n        this.stopAllowanceMs = 0;\n        this.stopDecisionLogged = false;\n    }\n\n    /**\n     * Runner-facing stop signal. Records the allowance window so the main loop\n     * can decide per-iteration whether to finish or abort early.\n     *\n     * @param {number} allowanceMs\n     */\n    requestStop(allowanceMs) {\n        this.stopRequested = true;\n        this.stopAllowanceMs = Number.isFinite(allowanceMs) && allowanceMs > 0 ? allowanceMs : 0;\n        this.context.logger.warn?.(\n            `[TaskSampleProcess] stop signal received (${this.task.id}), allowanceMs=${this.stopAllowanceMs}`\n        );\n    }\n\n    /**\n     * Iterate `total` times, sleeping `delay` ms between ticks and reporting\n     * progress every iteration. Validates params up front; invalid values short-\n     * circuit to a structured failure without starting the loop.\n     *\n     * @param {(progress: object) => Promise<void>} reportProgress\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run(reportProgress) {\n        const totalRaw = this.task?.params?.total ?? 10;\n        const delayRaw = this.task?.params?.delay ?? 1000;\n        const nameRaw = this.task?.params?.name;\n\n        const total = Number(totalRaw);\n        const delay = Number(delayRaw);\n        const name = typeof nameRaw === \"string\" && nameRaw.trim() ? nameRaw.trim() : \"sampleProcess\";\n\n        const errors = [];\n        if (!Number.isInteger(total) || total <= 0) {\n            errors.push('param \"total\" must be a positive integer');\n        }\n        if (!Number.isInteger(delay) || delay < 0) {\n            errors.push('param \"delay\" must be an integer >= 0');\n        }\n\n        if (errors.length > 0) {\n            return {\n                success: false,\n                results: {\n                    error: `Validation failed: ${errors.join(\", \")}`,\n                    received: { total: totalRaw, delay: delayRaw, name: nameRaw },\n                },\n            };\n        }\n\n        const startedAt = Date.now();\n        for (let i = 1; i <= total; i += 1) {\n            if (this.stopRequested) {\n                const remainingMs = Math.max(0, (total - i + 1) * delay);\n                if (remainingMs <= this.stopAllowanceMs) {\n                    if (!this.stopDecisionLogged) {\n                        this.stopDecisionLogged = true;\n                        this.context.logger.warn?.(\n                            `[TaskSampleProcess] continue to finish (${this.task.id}): remainingMs=${remainingMs} <= allowanceMs=${this.stopAllowanceMs}`\n                        );\n                    }\n                } else {\n                    this.context.logger.warn?.(\n                        `[TaskSampleProcess] stopping gracefully at iteration ${i}/${total} (${this.task.id}), remainingMs=${remainingMs} > allowanceMs=${this.stopAllowanceMs}`\n                    );\n                    return {\n                        success: false,\n                        results: {\n                            message: `Stopped before completion at iteration ${i}/${total}`,\n                            completed: i - 1,\n                            total,\n                            name,\n                            remainingMs,\n                            allowanceMs: this.stopAllowanceMs,\n                        },\n                    };\n                }\n            }\n\n            const elapsed = Date.now() - startedAt;\n            const remaining = Math.max(0, (total - i) * delay);\n            const progress = {\n                name,\n                count: i,\n                total,\n                elapsedMs: elapsed,\n                remainingMs: remaining,\n                status: `running ${name}: ${i}/${total}`,\n            };\n\n            this.context.logger.progress(\"running\", {\n                prefix: name,\n                count: i,\n                total,\n            });\n            await reportProgress(progress);\n            await sleepMs(delay);\n        }\n\n        return {\n            success: true,\n            results: {\n                message: `Completed ${total} iterations`,\n                total,\n                delay,\n                name,\n            },\n        };\n    }\n}\n","import { spawn } from \"node:child_process\";\nimport { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Run a shell string, buffering stdout/stderr until exit. Use for short commands\n * only — everything accumulates in memory; long-running / high-throughput work\n * should spawn its own worker instead (see `taskScriptRunner.js`).\n *\n * @param {string} command\n * @param {string} [cwd]\n * @returns {Promise<{ exitCode: number|null, output: string, stderr: string, signal: NodeJS.Signals|null }>}\n */\nfunction runShellCommand(command, cwd) {\n    return new Promise((resolve, reject) => {\n        const child = spawn(command, {\n            shell: true,\n            cwd: cwd || process.cwd(),\n            stdio: [\"ignore\", \"pipe\", \"pipe\"],\n        });\n\n        let output = \"\";\n        let stderr = \"\";\n\n        child.stdout.on(\"data\", (chunk) => {\n            output += String(chunk);\n        });\n        child.stderr.on(\"data\", (chunk) => {\n            stderr += String(chunk);\n        });\n\n        child.on(\"error\", (error) => {\n            reject(error);\n        });\n\n        child.on(\"close\", (exitCode, signal) => {\n            resolve({\n                exitCode,\n                output: output.trim(),\n                stderr: stderr.trim(),\n                signal,\n            });\n        });\n    });\n}\n\n/**\n * Task wrapper for {@link runShellCommand}. Accepts either:\n *\n *   - `params: \"echo hi\"` (string shortcut), or\n *   - `params: { command: string, cwd?: string }`.\n *\n * Success is defined as `exitCode === 0`. Non-zero / spawn errors come back as\n * `{ success: false, results: { ... } }` — never a thrown exception.\n */\nexport class TaskShellCommand extends AbstractTask {\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ command: string, cwd?: string }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-shell\", {\n            command: \"string\",\n            cwd: \"string\",\n        }, overrides);\n        const command = typeof merged.command === \"string\" ? merged.command.trim() : \"\";\n        if (!command) {\n            throw new ParamError('shellCommand: param \"command\" must be a non-empty string');\n        }\n        const cwd = typeof merged.cwd === \"string\" && merged.cwd.trim() ? merged.cwd.trim() : null;\n        return cwd ? { command, cwd } : { command };\n    }\n\n    /**\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run() {\n        const params = this.task?.params;\n        const commandRaw = typeof params === \"string\" ? params : params?.command;\n        const cwdRaw = typeof params === \"string\" ? undefined : params?.cwd;\n        const command = typeof commandRaw === \"string\" ? commandRaw.trim() : \"\";\n        const cwd = typeof cwdRaw === \"string\" && cwdRaw.trim() ? cwdRaw.trim() : undefined;\n\n        if (!command) {\n            return {\n                success: false,\n                results: {\n                    error: 'Validation failed: param \"command\" must be a non-empty string',\n                    received: this.task?.params ?? null,\n                },\n            };\n        }\n\n        try {\n            const result = await runShellCommand(command, cwd);\n            const success = result.exitCode === 0;\n\n            this.context.logger.info?.(\n                `[TaskShellCommand] command=\"${command}\" exitCode=${String(result.exitCode)} (${this.task.id})`\n            );\n\n            return {\n                success,\n                results: {\n                    command,\n                    cwd: cwd ?? process.cwd(),\n                    output: result.output,\n                    stderr: result.stderr,\n                    exitCode: result.exitCode,\n                    signal: result.signal,\n                },\n            };\n        } catch (error) {\n            return {\n                success: false,\n                results: {\n                    command,\n                    cwd: cwd ?? process.cwd(),\n                    output: \"\",\n                    stderr: \"\",\n                    exitCode: null,\n                    error: error?.message ?? String(error),\n                },\n            };\n        }\n    }\n}\n","import os from \"node:os\";\nimport fs from \"node:fs/promises\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Format bytes as a human-readable gigabyte string, e.g. `\"3.25 GB\"`.\n *\n * @param {number} valueBytes\n * @returns {string}\n */\nfunction toGb(valueBytes) {\n    return `${(valueBytes / (1024 ** 3)).toFixed(2)} GB`;\n}\n\n/**\n * Format bytes as a human-readable megabyte string, e.g. `\"128.00 MB\"`.\n *\n * @param {number} valueBytes\n * @returns {string}\n */\nfunction toMb(valueBytes) {\n    return `${(valueBytes / (1024 ** 2)).toFixed(2)} MB`;\n}\n\n/**\n * Disk usage for `/` as `{ total, used, free }` strings. Uses `fs.statfs`\n * (Node 20+); for host-level signal we probe the root mount rather than the cwd.\n *\n * @returns {Promise<{ total: string, used: string, free: string }>}\n */\nasync function getDiskStats() {\n    // Node 20+ statfs; use root path for host-level signal.\n    const stats = await fs.statfs(\"/\");\n    const total = Number(stats.bsize) * Number(stats.blocks);\n    const free = Number(stats.bsize) * Number(stats.bavail);\n    const used = total - free;\n    return {\n        total: toGb(total),\n        used: toGb(used),\n        free: toGb(free),\n    };\n}\n\n/**\n * Snapshot of host + process stats (memory, CPU utilization, disk, runtime info).\n * Useful for ops dashboards and cluster-wide \"ping with telemetry\".\n */\nexport class TaskSystemInfo extends AbstractTask {\n    /** Same UX expectation as `ping` — short probe, print the result. */\n    static defaultWaitForResult = true;\n\n    /** systemInfo takes no params. */\n    static async resolveCustomParams() {\n        return null;\n    }\n\n    /**\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run() {\n        try {\n            const totalMemory = os.totalmem();\n            const freeMemory = os.freemem();\n            const usedMemory = totalMemory - freeMemory;\n\n            const cpus = os.cpus();\n            const cpuUtilization = cpus.map((cpu) => {\n                const total = Object.values(cpu.times).reduce((acc, time) => acc + time, 0);\n                const usage = ((total - cpu.times.idle) / total) * 100;\n                return Number(usage.toFixed(2));\n            });\n\n            const processMemory = process.memoryUsage();\n            const disk = await getDiskStats();\n\n            const results = {\n                memory: {\n                    total: toGb(totalMemory),\n                    used: toGb(usedMemory),\n                    free: toGb(freeMemory),\n                },\n                processMemory: {\n                    rss: toMb(processMemory.rss),\n                    heapTotal: toMb(processMemory.heapTotal),\n                    heapUsed: toMb(processMemory.heapUsed),\n                    external: toMb(processMemory.external),\n                },\n                disk,\n                cpu: {\n                    cores: cpuUtilization.length,\n                    utilization: cpuUtilization,\n                },\n                runtime: {\n                    platform: os.platform(),\n                    arch: os.arch(),\n                    uptimeSec: os.uptime(),\n                    hostname: os.hostname(),\n                },\n            };\n\n            this.context.logger.info?.(`[TaskSystemInfo] collected system metrics (${this.task.id})`);\n            return { success: true, results };\n        } catch (error) {\n            return {\n                success: false,\n                results: {\n                    error: \"Can't collect system stats\",\n                    message: error?.message ?? String(error),\n                },\n            };\n        }\n    }\n}\n","import { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Sanity-check task for wiring: reads `params.a` and `params.b` (both numbers),\n * returns `{ a, b, sum }`. Any non-numeric input short-circuits to a structured\n * validation failure, not an exception.\n */\nexport class TaskSumAB extends AbstractTask {\n    /** Short, deterministic — wait by default so callers see the sum. */\n    static defaultWaitForResult = true;\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ a: number, b: number }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-sumab\", {\n            a: \"number\",\n            b: \"number\",\n        }, overrides);\n        if (typeof merged.a !== \"number\" || Number.isNaN(merged.a)) {\n            throw new ParamError(`taskSumAB: param \"a\" must be a valid number (got ${JSON.stringify(merged.a)})`);\n        }\n        if (typeof merged.b !== \"number\" || Number.isNaN(merged.b)) {\n            throw new ParamError(`taskSumAB: param \"b\" must be a valid number (got ${JSON.stringify(merged.b)})`);\n        }\n        return { a: merged.a, b: merged.b };\n    }\n\n    /**\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run() {\n        const a = this.task?.params?.a;\n        const b = this.task?.params?.b;\n\n        if (typeof a !== \"number\" || Number.isNaN(a)) {\n            return {\n                success: false,\n                results: {\n                    error: 'Validation failed: param \"a\" must be a valid number',\n                    received: { a, b },\n                },\n            };\n        }\n\n        if (typeof b !== \"number\" || Number.isNaN(b)) {\n            return {\n                success: false,\n                results: {\n                    error: 'Validation failed: param \"b\" must be a valid number',\n                    received: { a, b },\n                },\n            };\n        }\n\n        const sum = a + b;\n        this.context.logger.info?.(`[TaskSumAB] ${a} + ${b} = ${sum} (${this.task.id})`);\n        return {\n            success: true,\n            results: { a, b, sum },\n        };\n    }\n}\n","import { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Cooperative stop signal for the runner that claims it. Returns a result with\n * `stopRunner: true`; `runTasksLoop` sees that flag in `executeClaimedTask`'s\n * outcome and flips its own stop state, propagating `requestStop(allowanceMs)`\n * to every currently-running task.\n *\n * `params.allowanceMs` controls the grace window (default 60000 ms).\n */\nexport class TaskStopRunner extends AbstractTask {\n    /**\n     * Stop tasks must target a concrete instance — without `serviceName` the\n     * row would race against any worker on the queue. Layered on top of the\n     * envelope built by {@link AbstractTask.resolveParams}.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = await super.resolveParams(context, overrides);\n        if (!main.serviceName) {\n            throw new ParamError(\n                \"stop/stopRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)\"\n            );\n        }\n        return main;\n    }\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ allowanceMs: number }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-stop\", {\n            allowanceMs: \"number default 60000\",\n        }, overrides);\n        const allowanceMs = Number(merged.allowanceMs);\n        if (!Number.isFinite(allowanceMs) || allowanceMs < 0) {\n            throw new ParamError(\n                `stopRunner: allowanceMs must be a non-negative number (got ${JSON.stringify(merged.allowanceMs)})`\n            );\n        }\n        return { allowanceMs };\n    }\n\n    /**\n     * @returns {Promise<{ success: true, results: { stopRunner: true, allowanceMs: number, message: string } }>}\n     */\n    async run() {\n        const allowanceMs = Number(this.task?.params?.allowanceMs ?? 60_000);\n        this.context.logger.warn?.(`[TaskStopRunner] stop requested (allowanceMs=${allowanceMs})`);\n        return {\n            success: true,\n            results: {\n                stopRunner: true,\n                allowanceMs,\n                message: \"Runner stop requested\",\n            },\n        };\n    }\n}\n","import { ParamError } from \"../errors.js\";\nimport { updateServicesRegistryMetadata } from \"./servicesRegistry.js\";\n\n/** Keys the tasks loop re-reads every tick from `context.tasksRuntime`. */\nexport const LOOP_RUNTIME_KEYS = [\"maxParallel\", \"pollMs\", \"claimJitterMs\", \"scanLimit\"];\n\n/** Keys applied via `context.logger.configure(...)`. */\nexport const LOGGER_RUNTIME_KEYS = [\n    \"levels\",\n    \"silent\",\n    \"showLevel\",\n    \"timestamp\",\n    \"mode\",\n    \"route\",\n    \"prefix\",\n    \"progressWithTimes\",\n    \"progressWithRate\",\n    \"progressThrottleMs\",\n];\n\n/**\n * Declared knobs operators may edit via setRuntimeParam / tasksmm \"Change param(s)\".\n * Written into services_registry `metadata.runtimeParams` at registration.\n *\n * @typedef {{\n *   key: string,\n *   type: \"number\" | \"boolean\" | \"string\",\n *   label: string,\n *   description?: string,\n * }} RuntimeParamSpec\n */\n\n/** @type {RuntimeParamSpec[]} */\nexport const DEFAULT_RUNTIME_PARAM_SPECS = [\n    {\n        key: \"maxParallel\",\n        type: \"number\",\n        label: \"Max parallel\",\n        description: \"Worker-lane concurrency (how many tasks claim at once)\",\n    },\n    {\n        key: \"pollMs\",\n        type: \"number\",\n        label: \"Poll ms\",\n        description: \"Idle poll interval between claim attempts\",\n    },\n    {\n        key: \"claimJitterMs\",\n        type: \"number\",\n        label: \"Claim jitter ms\",\n        description: \"Random delay before worker claims (0 = off)\",\n    },\n    {\n        key: \"scanLimit\",\n        type: \"number\",\n        label: \"Scan limit\",\n        description: \"Max idle rows scanned per claim attempt\",\n    },\n    {\n        key: \"tasksRetentionEnabled\",\n        type: \"boolean\",\n        label: \"Retention enabled\",\n        description: \"Prune tasks_history + IPC logs together\",\n    },\n    {\n        key: \"tasksRetentionDays\",\n        type: \"number\",\n        label: \"Retention days\",\n        description: \"Keep history and IPC logs this many days (0 = off)\",\n    },\n    {\n        key: \"tasksRetentionIntervalMs\",\n        type: \"number\",\n        label: \"Retention interval ms\",\n        description: \"How often the runner checks for stale history/logs\",\n    },\n    {\n        key: \"tasksRetentionMinFreeRatio\",\n        type: \"number\",\n        label: \"Min free disk ratio\",\n        description: \"If free/total on the logs volume is below this, prune earlier\",\n    },\n    {\n        key: \"tasksRetentionMinHours\",\n        type: \"number\",\n        label: \"Min retention hours\",\n        description: \"Floor when disk is low (never prune newer than this)\",\n    },\n    {\n        key: \"tasksRetentionNameRules\",\n        type: \"string\",\n        label: \"Per-task retention (JSON)\",\n        description: 'Shorter windows by task name, e.g. {\"processListingPhotos\":12} (hours)',\n    },\n];\n\n/**\n * Normalize / merge runner-supplied specs with defaults (by key; extras append).\n *\n * @param {RuntimeParamSpec[] | undefined | null} [extra]\n * @returns {RuntimeParamSpec[]}\n */\nexport function mergeRuntimeParamSpecs(extra) {\n    const byKey = new Map(DEFAULT_RUNTIME_PARAM_SPECS.map((s) => [s.key, { ...s }]));\n    if (Array.isArray(extra)) {\n        for (const raw of extra) {\n            if (!raw || typeof raw !== \"object\") continue;\n            const key = String(raw.key ?? \"\").trim();\n            if (!key) continue;\n            const prev = byKey.get(key) ?? {};\n            const type = [\"number\", \"boolean\", \"string\"].includes(raw.type) ? raw.type : prev.type ?? \"string\";\n            byKey.set(key, {\n                key,\n                type,\n                label: String(raw.label ?? prev.label ?? key),\n                description:\n                    raw.description != null\n                        ? String(raw.description)\n                        : prev.description != null\n                          ? String(prev.description)\n                          : undefined,\n            });\n        }\n    }\n    return Array.from(byKey.values());\n}\n\n/**\n * Snapshot current values for the given specs from `context.tasksRuntime`.\n *\n * @param {object} context\n * @param {RuntimeParamSpec[]} [specs]\n * @returns {Record<string, unknown>}\n */\nexport function runtimeValuesForSpecs(context, specs = DEFAULT_RUNTIME_PARAM_SPECS) {\n    const rt = ensureTasksRuntime(context);\n    const out = {};\n    for (const s of specs) {\n        if (rt[s.key] !== undefined) out[s.key] = rt[s.key];\n    }\n    return out;\n}\n\n/**\n * Parse specs from registry metadata (tolerant of older runners).\n *\n * @param {unknown} metadata\n * @returns {RuntimeParamSpec[]}\n */\nexport function runtimeParamSpecsFromMetadata(metadata) {\n    const meta = metadata && typeof metadata === \"object\" ? metadata : null;\n    const raw = meta?.runtimeParams;\n    if (!Array.isArray(raw) || raw.length === 0) {\n        return mergeRuntimeParamSpecs();\n    }\n    return mergeRuntimeParamSpecs(raw);\n}\n\nconst CONTROL_LANE_TASK_NAMES = [\n    \"stopRunner\",\n    \"stop\",\n    \"pauseRunner\",\n    \"pause\",\n    \"unpauseRunner\",\n    \"unpause\",\n    \"pauseTask\",\n    \"resumeTask\",\n    \"setRuntimeParam\",\n    \"setRunnerParam\",\n    \"pruneTaskRetention\",\n];\n\n/**\n * Task names claimed on the dedicated control lane (even when workers are saturated).\n * Pass `extra` from `runTasksLoop({ controlLaneTasks })` for app-specific ops\n * probes (e.g. v2 `hostInfo`) that must run while regular workers are full.\n *\n * @param {string|string[]|undefined|null} [extra]\n * @returns {string[]}\n */\nexport function controlLaneTaskNames(extra) {\n    const names = [...CONTROL_LANE_TASK_NAMES];\n    if (extra == null || extra === \"\") return names;\n    const more = Array.isArray(extra) ? extra : String(extra).split(\",\");\n    const seen = new Set(names);\n    for (const raw of more) {\n        const n = String(raw ?? \"\").trim();\n        if (!n || seen.has(n)) continue;\n        seen.add(n);\n        names.push(n);\n    }\n    return names;\n}\n\n/**\n * @param {unknown} value\n * @param {string} key\n * @returns {number}\n */\nfunction asPositiveInt(value, key, { min = 1 } = {}) {\n    const n = Number(value);\n    if (!Number.isFinite(n) || n < min) {\n        throw new ParamError(\n            `setRuntimeParam: ${key} must be a number >= ${min} (got ${JSON.stringify(value)})`\n        );\n    }\n    return Math.floor(n);\n}\n\n/**\n * Coerce / validate a single runtime value for a known key.\n * Unknown keys pass through unchanged (apps may handle via onRuntimeParam).\n *\n * @param {string} key\n * @param {unknown} value\n * @returns {unknown}\n */\nexport function coerceRuntimeValue(key, value) {\n    switch (key) {\n        case \"maxParallel\":\n            return asPositiveInt(value, key, { min: 1 });\n        case \"pollMs\":\n            return asPositiveInt(value, key, { min: 50 });\n        case \"claimJitterMs\":\n            return asPositiveInt(value, key, { min: 0 });\n        case \"scanLimit\":\n            return asPositiveInt(value, key, { min: 1 });\n        case \"tasksRetentionDays\":\n            return asPositiveInt(value, key, { min: 0 });\n        case \"tasksRetentionIntervalMs\":\n            return asPositiveInt(value, key, { min: 10_000 });\n        case \"tasksRetentionMinHours\":\n            return asPositiveInt(value, key, { min: 1 });\n        case \"tasksRetentionMinFreeRatio\": {\n            const n = Number(value);\n            if (!Number.isFinite(n) || n <= 0 || n >= 1) {\n                throw new ParamError(\n                    `setRuntimeParam: ${key} must be a number between 0 and 1 (got ${JSON.stringify(value)})`,\n                );\n            }\n            return n;\n        }\n        case \"tasksRetentionEnabled\":\n            if (typeof value === \"boolean\") return value;\n            if (value === \"true\" || value === \"1\") return true;\n            if (value === \"false\" || value === \"0\") return false;\n            throw new ParamError(\n                `setRuntimeParam: ${key} must be boolean (got ${JSON.stringify(value)})`,\n            );\n        case \"silent\":\n        case \"showLevel\":\n        case \"timestamp\":\n        case \"progressWithTimes\":\n        case \"progressWithRate\":\n            if (typeof value === \"boolean\") return value;\n            if (value === \"true\" || value === \"1\") return true;\n            if (value === \"false\" || value === \"0\") return false;\n            throw new ParamError(\n                `setRuntimeParam: ${key} must be boolean (got ${JSON.stringify(value)})`\n            );\n        case \"progressThrottleMs\":\n            return asPositiveInt(value, key, { min: 0 });\n        case \"levels\":\n        case \"mode\":\n        case \"route\":\n        case \"prefix\":\n            return value;\n        default:\n            return value;\n    }\n}\n\n/**\n * Ensure `context.tasksRuntime` exists (used by the loop and by setRuntimeParam).\n *\n * @param {object} context\n * @param {Partial<{ maxParallel: number, pollMs: number, claimJitterMs: number, scanLimit: number, paused: boolean }>} [seed]\n * @returns {Record<string, unknown>}\n */\nexport function ensureTasksRuntime(context, seed = {}) {\n    if (!context.tasksRuntime || typeof context.tasksRuntime !== \"object\") {\n        context.tasksRuntime = {};\n    }\n    const rt = context.tasksRuntime;\n    if (rt.maxParallel === undefined) rt.maxParallel = seed.maxParallel ?? 32;\n    if (rt.pollMs === undefined) rt.pollMs = seed.pollMs ?? 1000;\n    if (rt.claimJitterMs === undefined) rt.claimJitterMs = seed.claimJitterMs ?? 0;\n    if (rt.scanLimit === undefined) rt.scanLimit = seed.scanLimit ?? 100;\n    if (rt.paused === undefined) rt.paused = seed.paused === true;\n    return rt;\n}\n\n/**\n * Apply one key/value to the running process. Mutates `context.tasksRuntime`,\n * updates logger when relevant, invokes optional `context.tasksRuntimeOnParam`.\n *\n * @param {object} context\n * @param {string} key\n * @param {unknown} value\n * @returns {Promise<{ key: string, previous: unknown, next: unknown, applied: string[] }>}\n */\nexport async function applyRuntimeParam(context, key, value) {\n    const k = String(key ?? \"\").trim();\n    if (!k) throw new ParamError(\"setRuntimeParam: key is required\");\n\n    const runtime = ensureTasksRuntime(context);\n    const next = coerceRuntimeValue(k, value);\n    const previous = runtime[k];\n    const applied = [];\n\n    runtime[k] = next;\n    applied.push(\"tasksRuntime\");\n\n    if (LOGGER_RUNTIME_KEYS.includes(k) && context.logger?.configure) {\n        context.logger.configure({ [k]: next });\n        applied.push(\"logger\");\n    }\n\n    const hook = context.tasksRuntimeOnParam;\n    if (typeof hook === \"function\") {\n        await hook(k, next, runtime, context);\n        applied.push(\"onRuntimeParam\");\n    }\n\n    const reg = context.servicesRegistry;\n    if (reg?.rowId && reg?.registryTable) {\n        try {\n            // Prefer specs declared at loop start (also in registry metadata.runtimeParams).\n            const specs = Array.isArray(context.tasksRuntimeParamSpecs)\n                ? context.tasksRuntimeParamSpecs\n                : DEFAULT_RUNTIME_PARAM_SPECS;\n            const runtimeSnapshot = runtimeValuesForSpecs(context, specs);\n            for (const lk of LOOP_RUNTIME_KEYS) {\n                if (runtime[lk] !== undefined && runtimeSnapshot[lk] === undefined) {\n                    runtimeSnapshot[lk] = runtime[lk];\n                }\n            }\n            await updateServicesRegistryMetadata(context, reg, {\n                runtime: runtimeSnapshot,\n                runtimeUpdatedAt: new Date().toISOString(),\n            });\n            applied.push(\"servicesRegistry\");\n        } catch (err) {\n            context.logger?.warn?.(\n                `[setRuntimeParam] registry metadata update failed: ${err?.message ?? String(err)}`\n            );\n        }\n    }\n\n    return { key: k, previous, next, applied };\n}\n\n/**\n * Apply a patch object `{ key: value, ... }` sequentially.\n *\n * @param {object} context\n * @param {Record<string, unknown>} patch\n * @returns {Promise<Array<{ key: string, previous: unknown, next: unknown, applied: string[] }>>}\n */\nexport async function applyRuntimePatch(context, patch) {\n    if (!patch || typeof patch !== \"object\" || Array.isArray(patch)) {\n        throw new ParamError(\"setRuntimeParam: patch must be a plain object\");\n    }\n    const entries = Object.entries(patch);\n    if (entries.length === 0) {\n        throw new ParamError(\"setRuntimeParam: patch is empty\");\n    }\n    const out = [];\n    for (const [key, value] of entries) {\n        out.push(await applyRuntimeParam(context, key, value));\n    }\n    return out;\n}\n\n/**\n * Read loop knobs from `context.tasksRuntime` with sane clamps.\n *\n * @param {object} context\n * @returns {{ maxParallel: number, pollMs: number, claimJitterMs: number, scanLimit: number }}\n */\nexport function readLoopRuntime(context) {\n    const rt = ensureTasksRuntime(context);\n    return {\n        maxParallel: Math.max(1, Number(rt.maxParallel) || 1),\n        pollMs: Math.max(50, Number(rt.pollMs) || 1000),\n        claimJitterMs: Math.max(0, Number(rt.claimJitterMs) || 0),\n        scanLimit: Math.max(1, Number(rt.scanLimit) || 100),\n    };\n}\n","/**\n * Pause / unpause a task runner service.\n *\n * When paused, the runner finishes in-flight worker tasks and does not claim new\n * worker-lane work until unpaused. Control-lane tasks (stop, pause, unpause,\n * setRuntimeParam, …) still run.\n *\n * Target a service via `--serviceName` (same shape as stopRunner). Persists\n * `metadata.paused` on services_registry for operators / TUI status.\n *\n * Aliases: `pause` / `unpause`.\n */\n\nimport { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\nimport { updateServicesRegistryMetadata } from \"../servicesRegistry.js\";\nimport { ensureTasksRuntime } from \"../runtimeParams.js\";\n\n/**\n * @param {object} context\n * @param {boolean} paused\n * @returns {Promise<{ success: true, results: { paused: boolean, message: string } }>}\n */\nexport async function applyRunnerPaused(context, paused) {\n    const runtime = ensureTasksRuntime(context);\n    const was = runtime.paused === true;\n    runtime.paused = paused === true;\n\n    const registry = context.servicesRegistry;\n    if (registry && typeof registry === \"object\") {\n        await updateServicesRegistryMetadata(context, registry, {\n            paused: runtime.paused,\n            pausedAt: runtime.paused ? new Date().toISOString() : null,\n        });\n    }\n\n    const message = runtime.paused\n        ? was\n            ? \"Runner already paused (no new worker tasks).\"\n            : \"Runner paused: finishing in-flight work; no new worker tasks until unpause.\"\n        : was\n          ? \"Runner unpaused: claiming worker tasks again.\"\n          : \"Runner already running (not paused).\";\n\n    context.logger?.warn?.(\n        runtime.paused ? `[TaskPauseRunner] ${message}` : `[TaskUnpauseRunner] ${message}`\n    );\n\n    return {\n        success: true,\n        results: {\n            paused: runtime.paused,\n            message,\n        },\n    };\n}\n\n/**\n * Pause worker claiming on the targeted service.\n */\nexport class TaskPauseRunner extends AbstractTask {\n    static taskName = \"pauseRunner\";\n    static description =\n        \"Pause a runner: finish in-flight tasks, claim no new worker tasks until unpaused\";\n    static aliases = [\"pause\"];\n    static defaultWaitForResult = true;\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = await super.resolveParams(context, overrides);\n        if (!main.serviceName) {\n            throw new ParamError(\n                \"pause/pauseRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)\"\n            );\n        }\n        return main;\n    }\n\n    async run() {\n        return applyRunnerPaused(this.context, true);\n    }\n}\n\n/**\n * Resume worker claiming on the targeted service.\n */\nexport class TaskUnpauseRunner extends AbstractTask {\n    static taskName = \"unpauseRunner\";\n    static description = \"Unpause a runner: resume claiming worker tasks\";\n    static aliases = [\"unpause\"];\n    static defaultWaitForResult = true;\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = await super.resolveParams(context, overrides);\n        if (!main.serviceName) {\n            throw new ParamError(\n                \"unpause/unpauseRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)\"\n            );\n        }\n        return main;\n    }\n\n    async run() {\n        return applyRunnerPaused(this.context, false);\n    }\n}\n","/**\n * Pause / resume a single queue task (not the runner).\n *\n * pauseTask:\n *   - idle → status=paused (persists across runner restart/redeploy)\n *   - running → stamp progress.pauseRequested + call requestPause() on the\n *     in-process instance when this runner owns it; the task cooperatively\n *     finishes its current unit and returns `{ taskPaused: true }`\n *   - already paused → no-op success\n *\n * resumeTask:\n *   - paused → status=idle (clears pauseRequested)\n *   - stamps `past_due` + `next_run_at` so a scheduled row is claimed on the\n *     next poll (does not wait for the next cron slot)\n *\n * Both are control-lane tasks so they run even when workers are saturated or\n * the runner itself is paused.\n */\n\nimport { ParamError } from \"../../errors.js\";\nimport { toJsonColumn } from \"../../utils/index.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\nimport { queueToTableNames } from \"../taskUtils.js\";\n\n/**\n * @param {unknown} progress\n * @returns {Record<string, unknown>}\n */\nfunction parseProgressObject(progress) {\n    if (progress == null || progress === \"\") return {};\n    if (typeof progress === \"object\" && !Array.isArray(progress)) {\n        return { ...progress };\n    }\n    if (typeof progress === \"string\") {\n        const t = progress.trim();\n        if (t.startsWith(\"{\") || t.startsWith(\"[\")) {\n            try {\n                const parsed = JSON.parse(t);\n                if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return { ...parsed };\n            } catch {\n                /* keep as message */\n            }\n        }\n        return { message: progress };\n    }\n    return { message: String(progress) };\n}\n\n/**\n * @param {object} context\n * @param {string} taskId\n * @returns {Promise<{ success: boolean, results: object }>}\n */\nexport async function applyPauseTask(context, taskId) {\n    const db = context.db;\n    if (!db) throw new Error(\"pauseTask: context.db is required\");\n    const id = String(taskId ?? \"\").trim();\n    if (!id) throw new ParamError('pauseTask: param \"taskId\" is required');\n\n    const { tasksTable } = queueToTableNames(context.tasksQueueName ?? \"tasks\");\n    const row = await db(tasksTable).where({ id }).first();\n    if (!row) {\n        return { success: false, results: { error: `Task ${id} not found`, taskId: id } };\n    }\n\n    if (row.status === \"paused\") {\n        return {\n            success: true,\n            results: { taskId: id, status: \"paused\", message: \"Task already paused\" },\n        };\n    }\n\n    if (row.status === \"idle\") {\n        const progress = parseProgressObject(row.progress);\n        progress.pauseRequested = true;\n        progress.pausedAt = new Date().toISOString();\n        await db(tasksTable).where({ id }).update({\n            status: \"paused\",\n            status_changed_at: db.fn.now(),\n            progress: toJsonColumn(progress),\n        });\n        context.logger?.warn?.(`[pauseTask] idle task ${id} (${row.name}) → paused`);\n        return {\n            success: true,\n            results: { taskId: id, status: \"paused\", message: \"Idle task paused\" },\n        };\n    }\n\n    if (row.status === \"running\") {\n        const progress = parseProgressObject(row.progress);\n        progress.pauseRequested = true;\n        progress.pauseRequestedAt = new Date().toISOString();\n        await db(tasksTable).where({ id }).update({\n            progress: toJsonColumn(progress),\n        });\n\n        const inst = context.runningTaskInstances?.get?.(id);\n        if (inst && typeof inst.requestPause === \"function\") {\n            await inst.requestPause();\n            context.logger?.warn?.(\n                `[pauseTask] signaled running task ${id} (${row.name}) to pause after current unit`,\n            );\n            return {\n                success: true,\n                results: {\n                    taskId: id,\n                    status: \"running\",\n                    signaled: true,\n                    message: \"Pause requested; task will finish current unit then park as paused\",\n                },\n            };\n        }\n\n        context.logger?.warn?.(\n            `[pauseTask] stamped pauseRequested on ${id} (${row.name}) — not running in this process`,\n        );\n        return {\n            success: true,\n            results: {\n                taskId: id,\n                status: \"running\",\n                signaled: false,\n                message:\n                    \"pauseRequested stamped on task row; target runner must observe it (enqueue pauseTask on that service)\",\n            },\n        };\n    }\n\n    return {\n        success: false,\n        results: {\n            error: `Cannot pause task in status \"${row.status}\"`,\n            taskId: id,\n            status: row.status,\n        },\n    };\n}\n\n/**\n * @param {object} context\n * @param {string} taskId\n * @returns {Promise<{ success: boolean, results: object }>}\n */\nexport async function applyResumeTask(context, taskId) {\n    const db = context.db;\n    if (!db) throw new Error(\"resumeTask: context.db is required\");\n    const id = String(taskId ?? \"\").trim();\n    if (!id) throw new ParamError('resumeTask: param \"taskId\" is required');\n\n    const { tasksTable } = queueToTableNames(context.tasksQueueName ?? \"tasks\");\n    const row = await db(tasksTable).where({ id }).first();\n    if (!row) {\n        return { success: false, results: { error: `Task ${id} not found`, taskId: id } };\n    }\n\n    if (row.status === \"idle\") {\n        return {\n            success: true,\n            results: { taskId: id, status: \"idle\", message: \"Task already idle (runnable)\" },\n        };\n    }\n\n    if (row.status !== \"paused\") {\n        return {\n            success: false,\n            results: {\n                error: `Cannot resume task in status \"${row.status}\" (expected paused)`,\n                taskId: id,\n                status: row.status,\n            },\n        };\n    }\n\n    const progress = parseProgressObject(row.progress);\n    delete progress.pauseRequested;\n    delete progress.pauseRequestedAt;\n    delete progress.pausedAt;\n    progress.resumedAt = new Date().toISOString();\n\n    const now = new Date();\n    await db(tasksTable).where({ id }).update({\n        status: \"idle\",\n        status_changed_at: db.fn.now(),\n        started_at: null,\n        completed_at: null,\n        success: null,\n        progress: toJsonColumn(progress),\n        // Clear claim binding so any matching worker can pick it up.\n        service_name: null,\n        server_name: null,\n        instance_number: null,\n        // Claim skips scheduled rows until cron matches unless past_due is set.\n        next_run_at: now,\n        past_due: now,\n    });\n\n    context.logger?.warn?.(`[resumeTask] paused task ${id} (${row.name}) → idle (run now)`);\n    return {\n        success: true,\n        results: { taskId: id, status: \"idle\", message: \"Task resumed (idle; will be claimed now)\" },\n    };\n}\n\nexport class TaskPauseTask extends AbstractTask {\n    static taskName = \"pauseTask\";\n    static description = \"Pause a specific task: finish current unit, persist status=paused\";\n    static defaultWaitForResult = true;\n\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(\n            context,\n            \"task-pause-task\",\n            { taskId: \"string\" },\n            overrides,\n        );\n        const taskId = typeof merged.taskId === \"string\" ? merged.taskId.trim() : \"\";\n        if (!taskId) throw new ParamError('pauseTask: param \"taskId\" is required');\n        return { taskId };\n    }\n\n    async run() {\n        return applyPauseTask(this.context, this.task?.params?.taskId);\n    }\n}\n\nexport class TaskResumeTask extends AbstractTask {\n    static taskName = \"resumeTask\";\n    static description = \"Resume a paused task (status paused → idle)\";\n    static defaultWaitForResult = true;\n\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(\n            context,\n            \"task-resume-task\",\n            { taskId: \"string\" },\n            overrides,\n        );\n        const taskId = typeof merged.taskId === \"string\" ? merged.taskId.trim() : \"\";\n        if (!taskId) throw new ParamError('resumeTask: param \"taskId\" is required');\n        return { taskId };\n    }\n\n    async run() {\n        return applyResumeTask(this.context, this.task?.params?.taskId);\n    }\n}\n","import { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\nimport { readTaskIpcLogsSnapshot } from \"../taskLogs.js\";\n\n/**\n * Fetches IPC FileDatabase rows for `dummyHarvest` (and similar) logs keyed by params.source / params.resource.\n * Intended for machine-targeted enqueue (`server_name` set, `service_group` null) so any runner on that host can execute.\n *\n * Params:\n *   - `source`   (required) — logical source name, e.g. `\"actris\"`\n *   - `resource` (required) — resource slug, e.g. `\"properties\"`\n *   - `tail`     — max records to return (clamped 1..10000; default 100)\n *   - `afterTs`  — ISO timestamp watermark; keeps only rows with `ts > afterTs`\n *   - `fromTs`   — inclusive lower bound (`ts >= fromTs`); scans older versions\n *   - `toTs`     — inclusive upper bound (`ts <= toTs`)\n *   - `taskId`   — keep only rows stamped with this task id\n */\nexport class TaskGetLogs extends AbstractTask {\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ source: string, resource: string, tail: number, afterTs?: string }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-get-logs\", {\n            source: \"string\",\n            resource: \"string\",\n            tail: \"number default 100\",\n            afterTs: \"string\",\n            fromTs: \"string\",\n            toTs: \"string\",\n            taskId: \"string\",\n        }, overrides);\n        const source = typeof merged.source === \"string\" ? merged.source.trim() : \"\";\n        const resource = typeof merged.resource === \"string\" ? merged.resource.trim() : \"\";\n        if (!source) throw new ParamError('getLogs: param \"source\" is required');\n        if (!resource) throw new ParamError('getLogs: param \"resource\" is required');\n        let tail = Number(merged.tail);\n        if (!Number.isFinite(tail) || tail < 1) tail = 100;\n        tail = Math.min(10_000, Math.max(1, Math.floor(tail)));\n        const out = { source, resource, tail };\n        if (typeof merged.afterTs === \"string\" && merged.afterTs.trim()) {\n            out.afterTs = merged.afterTs.trim();\n        }\n        if (typeof merged.fromTs === \"string\" && merged.fromTs.trim()) {\n            out.fromTs = merged.fromTs.trim();\n        }\n        if (typeof merged.toTs === \"string\" && merged.toTs.trim()) {\n            out.toTs = merged.toTs.trim();\n        }\n        if (typeof merged.taskId === \"string\" && merged.taskId.trim()) {\n            out.taskId = merged.taskId.trim();\n        }\n        return out;\n    }\n\n    /**\n     * @param {unknown} _reportProgress Unused (single-shot read, no progress events).\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run(_reportProgress) {\n        const p = this.task.params ?? {};\n        const source = String(p.source ?? \"\").trim();\n        const resource = String(p.resource ?? \"\").trim();\n        const tail = Math.max(1, Math.min(10_000, Number(p.tail) > 0 ? Number(p.tail) : 100));\n        const afterTs = p.afterTs != null && String(p.afterTs).trim() ? String(p.afterTs).trim() : null;\n        const fromTs = p.fromTs != null && String(p.fromTs).trim() ? String(p.fromTs).trim() : null;\n        const toTs = p.toTs != null && String(p.toTs).trim() ? String(p.toTs).trim() : null;\n        const taskId = p.taskId != null && String(p.taskId).trim() ? String(p.taskId).trim() : null;\n\n        if (!source || !resource) {\n            return {\n                success: false,\n                results: { error: 'getLogs requires params \"source\" and \"resource\"' },\n            };\n        }\n\n        try {\n            const { records, latestTs } = await readTaskIpcLogsSnapshot(this.context, {\n                source,\n                resource,\n                tail,\n                afterTs,\n                fromTs,\n                toTs,\n                taskId,\n            });\n            return {\n                success: true,\n                results: { records, latestTs, source, resource },\n            };\n        } catch (e) {\n            return {\n                success: false,\n                results: { error: e?.message ?? String(e) },\n            };\n        }\n    }\n}\n","import { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\nimport { applyRuntimeParam, applyRuntimePatch } from \"../runtimeParams.js\";\nimport { listServicesRegistry } from \"../servicesRegistry.js\";\nimport { enqueueTask } from \"../taskUtils.js\";\n\n/**\n * Hot-update runner knobs without restarting the process.\n *\n * Apply to `context.tasksRuntime` (loop re-reads `maxParallel` / `pollMs` /\n * `claimJitterMs` / `scanLimit` every tick) and to the logger for level-related\n * keys (`levels`, `silent`, …).\n *\n * Targeting (same idea as stop):\n *   - `--serviceName=<registry name>` → one instance\n *   - `--serviceGroup=photos` without serviceName → broadcast to every alive\n *     instance in that group (via {@link TaskSetRuntimeParam.enqueue})\n *\n * Params (any of):\n *   - `--paramKey=maxParallel --paramValue=16`\n *   - `--paramsJson='{\"key\":\"maxParallel\",\"value\":16}'`\n *   - `--paramsJson='{\"patch\":{\"maxParallel\":16,\"levels\":\"+debug\"}}'`\n */\nexport class TaskSetRuntimeParam extends AbstractTask {\n    static defaultWaitForResult = true;\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = await super.resolveParams(context, overrides);\n        if (!main.serviceName && !main.serviceGroup) {\n            throw new ParamError(\n                \"setRuntimeParam requires --serviceName (one instance) or --serviceGroup (broadcast to alive instances)\"\n            );\n        }\n        return main;\n    }\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ key?: string, value?: unknown, patch?: Record<string, unknown> }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(\n            context,\n            \"task-set-runtime-param\",\n            {\n                paramKey: \"string\",\n                paramValue: \"string\",\n                key: \"string\",\n                value: \"string\",\n            },\n            overrides\n        );\n\n        if (merged.patch && typeof merged.patch === \"object\" && !Array.isArray(merged.patch)) {\n            if (Object.keys(merged.patch).length === 0) {\n                throw new ParamError(\"setRuntimeParam: patch is empty\");\n            }\n            return { patch: { ...merged.patch } };\n        }\n\n        const key = merged.paramKey || merged.key;\n        const value = merged.paramValue !== undefined ? merged.paramValue : merged.value;\n\n        if (!key) {\n            throw new ParamError(\n                'setRuntimeParam requires --paramKey/--paramValue, or --paramsJson \\'{\"key\":\"maxParallel\",\"value\":16}\\' / \\'{\"patch\":{...}}\\''\n            );\n        }\n\n        // CLI strings: try JSON parse for numbers/bools/objects; else keep string\n        let parsed = value;\n        if (typeof value === \"string\") {\n            const t = value.trim();\n            if (t === \"true\") parsed = true;\n            else if (t === \"false\") parsed = false;\n            else if (t !== \"\" && !Number.isNaN(Number(t)) && /^-?\\d+(\\.\\d+)?$/.test(t)) {\n                parsed = Number(t);\n            } else if (\n                (t.startsWith(\"{\") && t.endsWith(\"}\")) ||\n                (t.startsWith(\"[\") && t.endsWith(\"]\")) ||\n                (t.startsWith('\"') && t.endsWith('\"'))\n            ) {\n                try {\n                    parsed = JSON.parse(t);\n                } catch {\n                    parsed = value;\n                }\n            }\n        }\n\n        return { key: String(key), value: parsed };\n    }\n\n    /**\n     * Enqueue one or many setRuntimeParam tasks. Prefer this over a bare\n     * `enqueueTask` when broadcasting to a service group.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ ids: string[], targets: string[] }>}\n     */\n    static async enqueue(context, overrides = {}) {\n        const payload = await this.resolveParams(context, { ...overrides, name: \"setRuntimeParam\" });\n        const queueName = payload.queueName ?? \"tasks\";\n\n        if (payload.serviceName) {\n            const id = await enqueueTask(context, payload);\n            return { ids: [id], targets: [payload.serviceName] };\n        }\n\n        const group = String(payload.serviceGroup || \"\").trim();\n        if (!group) {\n            throw new ParamError(\"setRuntimeParam.enqueue: serviceGroup required for broadcast\");\n        }\n\n        const alive = await listServicesRegistry(context, {\n            queueName,\n            serviceGroup: group,\n            staleMs: overrides.staleMs ?? 45_000,\n        });\n        if (!alive.length) {\n            throw new ParamError(\n                `setRuntimeParam: no alive services in group=\"${group}\" queue=\"${queueName}\"`\n            );\n        }\n\n        const ids = [];\n        const targets = [];\n        for (const reg of alive) {\n            const id = await enqueueTask(context, {\n                ...payload,\n                serviceGroup: group,\n                serviceName: reg.service_name,\n                serverName: reg.server_name ?? null,\n                instanceNumber: reg.instance_number ?? null,\n            });\n            ids.push(id);\n            targets.push(reg.service_name);\n        }\n        context.logger?.info?.(\n            `[setRuntimeParam] broadcast to ${targets.length} instance(s) in group=${group}: ${targets.join(\", \")}`\n        );\n        return { ids, targets };\n    }\n\n    /**\n     * @returns {Promise<{ success: true, results: object }>}\n     */\n    async run() {\n        const params = this.task?.params ?? {};\n        let changes;\n        if (params.patch && typeof params.patch === \"object\") {\n            changes = await applyRuntimePatch(this.context, params.patch);\n        } else {\n            changes = [await applyRuntimeParam(this.context, params.key, params.value)];\n        }\n\n        const summary = changes.map((c) => `${c.key}: ${JSON.stringify(c.previous)} → ${JSON.stringify(c.next)}`);\n        this.context.logger.warn?.(\n            `[TaskSetRuntimeParam] applied on ${this.context.servicesRegistry?.serviceName ?? \"runner\"}: ${summary.join(\"; \")}`\n        );\n\n        return {\n            success: true,\n            results: {\n                runtimeParamApplied: true,\n                changes,\n                runtime: { ...(this.context.tasksRuntime ?? {}) },\n            },\n        };\n    }\n}\n","/**\n * Shorter retention windows for high-volume ephemeral task names.\n * Apps inject defaults via {@link setTaskRetentionNameRulesDefaults}; runtime\n * may override with `tasksRetentionNameRules` (JSON object name → hours).\n */\n\n/** @type {Record<string, number> | null} */\nlet injectedDefaults = null;\n\n/**\n * @param {Record<string, number>|null|undefined} map  task name → retention hours\n */\nexport function setTaskRetentionNameRulesDefaults(map) {\n    if (map == null) {\n        injectedDefaults = null;\n        return;\n    }\n    injectedDefaults = { ...map };\n}\n\n/**\n * @param {unknown} raw JSON string or object from runtime / params\n * @returns {Record<string, number>}\n */\nexport function parseRetentionNameRulesRaw(raw) {\n    if (raw == null || raw === \"\") return {};\n    let obj = raw;\n    if (typeof raw === \"string\") {\n        const t = raw.trim();\n        if (!t) return {};\n        try {\n            obj = JSON.parse(t);\n        } catch {\n            return {};\n        }\n    }\n    if (!obj || typeof obj !== \"object\" || Array.isArray(obj)) return {};\n    const out = {};\n    for (const [name, hours] of Object.entries(obj)) {\n        const h = Number(hours);\n        if (String(name ?? \"\").trim() && Number.isFinite(h) && h > 0) {\n            out[String(name).trim()] = h;\n        }\n    }\n    return out;\n}\n\n/**\n * Merged name → hours map (runtime wins over injected defaults per name).\n *\n * @param {object} [runtime] context.tasksRuntime\n * @returns {{ name: string, hours: number }[]}\n */\nexport function resolveRetentionNameRules(runtime = {}) {\n    const merged = { ...(injectedDefaults ?? {}), ...parseRetentionNameRulesRaw(runtime.tasksRetentionNameRules) };\n    return Object.entries(merged)\n        .map(([name, hours]) => ({ name, hours: Number(hours) }))\n        .filter((r) => r.name && Number.isFinite(r.hours) && r.hours > 0)\n        .sort((a, b) => a.name.localeCompare(b.name));\n}\n","/**\n * Unified retention for `*_history` rows and IPC FileDatabase logs.\n *\n * The same cutoff is applied to both stores so Inspect history and `l` logs stay\n * aligned. FileDatabase `maxVersions` remains a process-restart backstop only.\n *\n * Config (CLI / env / getAllForModule, then hot-update via setRuntimeParam):\n *   tasksRetentionEnabled        default true\n *   tasksRetentionDays           default 7 (0 = disable time prune)\n *   tasksRetentionIntervalMs     default 1h between automatic passes\n *   tasksRetentionMinFreeRatio   default 0.10 — shrink the window if free/total is below this\n *   tasksRetentionMinHours       default 6 — floor when disk is tight\n */\n\nimport { getDiskUsage } from \"../utils/os-utils.js\";\nimport { queueToTableNames } from \"./taskUtils.js\";\nimport { ensureTasksRuntime } from \"./runtimeParams.js\";\nimport { pruneIpcLogsOlderThan, tasksLogsRoot } from \"./taskLogs.js\";\nimport { parseRetentionNameRulesRaw, resolveRetentionNameRules } from \"./taskRetentionNameRules.js\";\n\nexport const HISTORY_PRUNE_CHUNK = 2000;\n\nexport const DEFAULT_RETENTION_DAYS = 7;\nexport const DEFAULT_RETENTION_INTERVAL_MS = 60 * 60 * 1000;\nexport const DEFAULT_MIN_FREE_RATIO = 0.1;\nexport const DEFAULT_MIN_RETENTION_HOURS = 6;\n\nconst RETENTION_PARAM_DEFS = {\n    tasksRetentionEnabled: \"boolean default true\",\n    tasksRetentionDays: \"number default 7\",\n    tasksRetentionIntervalMs: \"number default 3600000\",\n    tasksRetentionMinFreeRatio: \"number default 0.1\",\n    tasksRetentionMinHours: \"number default 6\",\n    tasksRetentionNameRules: \"string\",\n};\n\n/**\n * Register CLI/env knobs and seed `context.tasksRuntime` once per process.\n *\n * @param {object} context\n * @returns {Record<string, unknown>}\n */\nexport function seedTaskRetentionRuntime(context) {\n    const fromParams =\n        typeof context.params?.getAllForModule === \"function\"\n            ? context.params.getAllForModule(\"tasks-retention\", RETENTION_PARAM_DEFS)\n            : {};\n    const rt = ensureTasksRuntime(context);\n    if (rt.tasksRetentionEnabled === undefined) {\n        rt.tasksRetentionEnabled = fromParams.tasksRetentionEnabled !== false;\n    }\n    if (rt.tasksRetentionDays === undefined) {\n        rt.tasksRetentionDays = Number(fromParams.tasksRetentionDays ?? DEFAULT_RETENTION_DAYS);\n    }\n    if (rt.tasksRetentionIntervalMs === undefined) {\n        rt.tasksRetentionIntervalMs = Number(\n            fromParams.tasksRetentionIntervalMs ?? DEFAULT_RETENTION_INTERVAL_MS,\n        );\n    }\n    if (rt.tasksRetentionMinFreeRatio === undefined) {\n        rt.tasksRetentionMinFreeRatio = Number(\n            fromParams.tasksRetentionMinFreeRatio ?? DEFAULT_MIN_FREE_RATIO,\n        );\n    }\n    if (rt.tasksRetentionMinHours === undefined) {\n        rt.tasksRetentionMinHours = Number(fromParams.tasksRetentionMinHours ?? DEFAULT_MIN_RETENTION_HOURS);\n    }\n    if (rt.tasksRetentionNameRules === undefined && fromParams.tasksRetentionNameRules != null) {\n        rt.tasksRetentionNameRules = fromParams.tasksRetentionNameRules;\n    }\n    return rt;\n}\n\n/**\n * @param {object} [runtime]\n * @returns {{\n *   enabled: boolean,\n *   days: number,\n *   intervalMs: number,\n *   minFreeRatio: number,\n *   minHours: number,\n * }}\n */\nexport function readRetentionConfig(runtime = {}) {\n    const days = Number(runtime.tasksRetentionDays);\n    const intervalMs = Number(runtime.tasksRetentionIntervalMs);\n    const minFreeRatio = Number(runtime.tasksRetentionMinFreeRatio);\n    const minHours = Number(runtime.tasksRetentionMinHours);\n    return {\n        enabled: runtime.tasksRetentionEnabled !== false && Number.isFinite(days) && days > 0,\n        days: Number.isFinite(days) && days > 0 ? days : 0,\n        intervalMs: Number.isFinite(intervalMs) && intervalMs >= 10_000 ? intervalMs : DEFAULT_RETENTION_INTERVAL_MS,\n        minFreeRatio:\n            Number.isFinite(minFreeRatio) && minFreeRatio > 0 && minFreeRatio < 1\n                ? minFreeRatio\n                : DEFAULT_MIN_FREE_RATIO,\n        minHours: Number.isFinite(minHours) && minHours >= 1 ? minHours : DEFAULT_MIN_RETENTION_HOURS,\n    };\n}\n\n/**\n * Scale the configured window down when the logs volume is short on free space.\n * At/above `minFreeRatio` keep `days`. As free → 0, approach `minHours`.\n *\n * @param {{ days: number, minFreeRatio: number, minHours: number }} cfg\n * @param {{ free: number, total: number, freeRatio: number } | null} disk\n * @returns {{ days: number, diskAdjusted: boolean, freeRatio: number | null }}\n */\nexport function effectiveRetentionDays(cfg, disk) {\n    const minDays = cfg.minHours / 24;\n    if (!disk || !Number.isFinite(disk.freeRatio) || disk.freeRatio >= cfg.minFreeRatio) {\n        return { days: cfg.days, diskAdjusted: false, freeRatio: disk?.freeRatio ?? null };\n    }\n    const scaled = cfg.days * (disk.freeRatio / cfg.minFreeRatio);\n    const days = Math.max(minDays, scaled);\n    return { days, diskAdjusted: true, freeRatio: disk.freeRatio };\n}\n\n/**\n * @param {number} days\n * @param {Date} [now]\n * @returns {string} ISO cutoff\n */\nexport function retentionCutoffIso(days, now = new Date()) {\n    const ms = Math.max(0, Number(days) || 0) * 24 * 60 * 60 * 1000;\n    return new Date(now.getTime() - ms).toISOString();\n}\n\n/**\n * @param {number} hours\n * @param {Date} [now]\n * @returns {string} ISO cutoff\n */\nexport function retentionCutoffFromHours(hours, now = new Date()) {\n    const ms = Math.max(0, Number(hours) || 0) * 60 * 60 * 1000;\n    return new Date(now.getTime() - ms).toISOString();\n}\n\nexport { parseRetentionNameRulesRaw, resolveRetentionNameRules };\n\nexport { getDiskUsage as readDiskUsage };\n\n/**\n * Delete history rows older than `cutoff` in chunks (re-run safe).\n *\n * @param {Function} db\n * @param {string} historyTable\n * @param {string|Date} cutoff\n * @param {{ chunkSize?: number, isStop?: () => boolean }} [opts]\n * @returns {Promise<number>}\n */\nexport async function deleteHistoryOlderThan(db, historyTable, cutoff, opts = {}) {\n    const chunkSize = Math.max(1, Number(opts.chunkSize) || HISTORY_PRUNE_CHUNK);\n    const isStop = typeof opts.isStop === \"function\" ? opts.isStop : () => false;\n    const name =\n        opts.name != null && String(opts.name).trim() ? String(opts.name).trim() : null;\n    let total = 0;\n    for (;;) {\n        if (isStop()) break;\n        let q = db(historyTable).where(\"completed_at\", \"<\", cutoff);\n        if (name) q = q.where({ name });\n        const rows = await q.select(\"id\").limit(chunkSize);\n        if (!Array.isArray(rows) || rows.length === 0) break;\n        const ids = rows.map((r) => r.id).filter(Boolean);\n        if (!ids.length) break;\n        const deleted = await db(historyTable).whereIn(\"id\", ids).delete();\n        total += Number(deleted) || ids.length;\n        if (rows.length < chunkSize) break;\n    }\n    return total;\n}\n\n/**\n * Run one prune pass: disk-aware cutoff → IPC logs → tasks_history.\n *\n * @param {object} context\n * @param {{\n *   queueName?: string,\n *   historyTable?: string,\n *   force?: boolean,\n *   now?: Date,\n *   readDisk?: (p: string) => Promise<{ free: number, total: number, freeRatio: number } | null>,\n *   pruneLogs?: typeof pruneIpcLogsOlderThan,\n * }} [options]\n * @returns {Promise<object>}\n */\nexport async function pruneTaskRetention(context, options = {}) {\n    seedTaskRetentionRuntime(context);\n    const cfg = readRetentionConfig(context.tasksRuntime);\n    if (!cfg.enabled) {\n        return { skipped: true, reason: \"disabled\" };\n    }\n\n    const queueName = options.queueName ?? context.tasksQueueName ?? \"tasks\";\n    const historyTable = options.historyTable ?? queueToTableNames(queueName).historyTable;\n    const now = options.now ?? new Date();\n    const logsRoot = tasksLogsRoot(context);\n    const readDisk = options.readDisk ?? getDiskUsage;\n    const disk = await readDisk(logsRoot);\n    const effective = effectiveRetentionDays(cfg, disk);\n    const cutoff = retentionCutoffIso(effective.days, now);\n\n    const pruneLogs = options.pruneLogs ?? pruneIpcLogsOlderThan;\n    const logs = await pruneLogs(context, cutoff, {\n        isStop: () => context.isStop?.() === true,\n    });\n\n    let historyDeleted = 0;\n    if (context.db && typeof context.db === \"function\") {\n        historyDeleted = await deleteHistoryOlderThan(context.db, historyTable, cutoff, {\n            isStop: () => context.isStop?.() === true,\n        });\n    }\n\n    const nameRules = resolveRetentionNameRules(context.tasksRuntime);\n    const nameRuleResults = [];\n    if (context.db && typeof context.db === \"function\") {\n        for (const rule of nameRules) {\n            const ruleCutoff = retentionCutoffFromHours(rule.hours, now);\n            const deleted = await deleteHistoryOlderThan(context.db, historyTable, ruleCutoff, {\n                name: rule.name,\n                isStop: () => context.isStop?.() === true,\n            });\n            if (deleted > 0) {\n                nameRuleResults.push({ name: rule.name, hours: rule.hours, cutoff: ruleCutoff, deleted });\n            }\n            historyDeleted += deleted;\n        }\n    }\n\n    const summary = {\n        skipped: false,\n        cutoff,\n        days: effective.days,\n        configuredDays: cfg.days,\n        diskAdjusted: effective.diskAdjusted,\n        freeRatio: effective.freeRatio,\n        historyTable,\n        historyDeleted,\n        nameRules: nameRuleResults,\n        logs,\n    };\n    context.logger?.info?.(\n        `[tasks-retention] cutoff=${cutoff} days=${effective.days.toFixed(2)}` +\n            `${effective.diskAdjusted ? ` (disk ${(effective.freeRatio * 100).toFixed(1)}% free)` : \"\"}` +\n            ` history=${historyDeleted}` +\n            (nameRuleResults.length\n                ? ` nameRules=${nameRuleResults.map((r) => `${r.name}:${r.deleted}@${r.hours}h`).join(\",\")}`\n                : \"\") +\n            ` logTables=${logs?.tables ?? 0} logDropped=${logs?.dropped ?? 0}`,\n    );\n    return summary;\n}\n\n/**\n * Throttled prune for the runner loop / after each handler. Overlapping calls no-op.\n *\n * @param {object} context\n * @param {{ queueName?: string, historyTable?: string, force?: boolean }} [options]\n * @returns {Promise<object|null>}\n */\nexport async function maybePruneTaskRetention(context, options = {}) {\n    seedTaskRetentionRuntime(context);\n    const cfg = readRetentionConfig(context.tasksRuntime);\n    if (!cfg.enabled) return null;\n\n    const now = Date.now();\n    const last = Number(context.__tasksRetentionLastAt) || 0;\n    if (!options.force && last && now - last < cfg.intervalMs) return null;\n    if (context.__tasksRetentionInFlight) return null;\n\n    context.__tasksRetentionLastAt = now;\n    context.__tasksRetentionInFlight = true;\n    try {\n        return await pruneTaskRetention(context, options);\n    } catch (err) {\n        context.logger?.warn?.(`[tasks-retention] prune failed: ${err?.message ?? String(err)}`);\n        return { skipped: true, reason: \"error\", error: err?.message ?? String(err) };\n    } finally {\n        context.__tasksRetentionInFlight = false;\n    }\n}\n","import { AbstractTask } from \"../AbstractTask.js\";\nimport { pruneTaskRetention, seedTaskRetentionRuntime } from \"../taskRetention.js\";\n\n/**\n * Run one history + IPC log retention pass on this host (same cutoff both stores).\n * Also runs automatically from the tasks loop; this task is the \"do it now\" hook.\n */\nexport class TaskPruneTaskRetention extends AbstractTask {\n    static defaultWaitForResult = true;\n\n    /**\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run() {\n        seedTaskRetentionRuntime(this.context);\n        const results = await pruneTaskRetention(this.context, { force: true });\n        return { success: true, results };\n    }\n}\n","import { ParamError } from \"../errors.js\";\nimport { TaskPing } from \"./coreTasks/TaskPing.js\";\nimport { TaskSampleProcess } from \"./coreTasks/TaskSampleProcess.js\";\nimport { TaskShellCommand } from \"./coreTasks/TaskShellCommand.js\";\nimport { TaskSystemInfo } from \"./coreTasks/TaskSystemInfo.js\";\nimport { TaskSumAB } from \"./coreTasks/TaskSumAB.js\";\nimport { TaskStopRunner } from \"./coreTasks/TaskStopRunner.js\";\nimport { TaskPauseRunner, TaskUnpauseRunner } from \"./coreTasks/TaskPauseRunner.js\";\nimport { TaskPauseTask, TaskResumeTask } from \"./coreTasks/TaskPauseTask.js\";\nimport { TaskGetLogs } from \"./coreTasks/TaskGetLogs.js\";\nimport { TaskSetRuntimeParam } from \"./coreTasks/TaskSetRuntimeParam.js\";\nimport { TaskPruneTaskRetention } from \"./coreTasks/TaskPruneTaskRetention.js\";\n\n/**\n * Name → task class map. Runners look up the class by `task.name` when claiming\n * a row. Keep names stable across versions: the DB queue references them as strings.\n *\n * Backward-compat aliases (e.g. `stop` → `TaskStopRunner`, `info` → `TaskSystemInfo`)\n * are seeded by {@link TasksRegistry.withCoreTasks}.\n */\nexport class TasksRegistry {\n    /**\n     * @param {Record<string, Function>} [initial] Optional seed entries to copy in.\n     */\n    constructor(initial) {\n        this.map = {};\n        if (initial) {\n            this.addMany(initial);\n        }\n    }\n\n    /**\n     * Build a registry pre-populated with every core task plus legacy aliases.\n     * Prefer this over `new TasksRegistry()` for anything that wants `ping`/`stop`/etc.\n     *\n     * @returns {TasksRegistry}\n     */\n    static withCoreTasks() {\n        return new TasksRegistry()\n            .add(\"ping\", TaskPing)\n            .add(\"sampleProcess\", TaskSampleProcess)\n            .add(\"shellCommand\", TaskShellCommand)\n            .add(\"systemInfo\", TaskSystemInfo)\n            .add(\"info\", TaskSystemInfo)\n            .add(\"taskSumAB\", TaskSumAB)\n            .add(\"stopRunner\", TaskStopRunner)\n            // Backward-compat alias\n            .add(\"stop\", TaskStopRunner)\n            .add(\"pauseRunner\", TaskPauseRunner)\n            .add(\"pause\", TaskPauseRunner)\n            .add(\"unpauseRunner\", TaskUnpauseRunner)\n            .add(\"unpause\", TaskUnpauseRunner)\n            .add(\"pauseTask\", TaskPauseTask)\n            .add(\"resumeTask\", TaskResumeTask)\n            .add(\"getLogs\", TaskGetLogs)\n            .add(\"setRuntimeParam\", TaskSetRuntimeParam)\n            .add(\"setRunnerParam\", TaskSetRuntimeParam)\n            .add(\"pruneTaskRetention\", TaskPruneTaskRetention);\n    }\n\n    /**\n     * Register a single task class under a name. Overwrites any previous entry.\n     *\n     * @param {string} taskName\n     * @param {Function} taskClass Subclass of `AbstractTask`.\n     * @returns {this}\n     */\n    add(taskName, taskClass) {\n        this.map[taskName] = taskClass;\n        return this;\n    }\n\n    /**\n     * Bulk-register a name → class map. Later calls override earlier ones.\n     *\n     * @param {Record<string, Function>} entries\n     * @returns {this}\n     */\n    addMany(entries) {\n        for (const [name, klass] of Object.entries(entries)) {\n            this.add(name, klass);\n        }\n        return this;\n    }\n\n    /**\n     * Look up a task class by name. Returns `undefined` when the name is unknown;\n     * the runner treats that as \"some other worker may handle this\" and skips.\n     *\n     * @param {string} taskName\n     * @returns {Function | undefined}\n     */\n    get(taskName) {\n        return this.map[taskName];\n    }\n\n    /**\n     * Strict variant of {@link get}: throws {@link ParamError} (with the list\n     * of supported names) when `taskName` is unknown. Use from enqueuer code\n     * paths where an unknown name is a hard CLI/programmer error.\n     *\n     * @param {string} taskName\n     * @returns {Function}\n     */\n    requireClass(taskName) {\n        const TaskClass = taskName ? this.map[taskName] : undefined;\n        if (!TaskClass) {\n            const supported = this.listSupportedTasks().join(\", \") || \"(none)\";\n            throw new ParamError(\n                `Unknown task \"${taskName ?? \"\"}\". Supported on this registry: ${supported}`\n            );\n        }\n        return TaskClass;\n    }\n\n    /**\n     * Dispatcher used by `send-task` / programmatic enqueuers: pick `name`\n     * from `overrides` or `context.params`, look up the class, and delegate\n     * to its static {@link AbstractTask.resolveParams} with `name` seeded into\n     * the overrides. The returned object is shaped for {@link enqueueTask}.\n     *\n     * Validation failures (unknown task, missing required custom params, etc.)\n     * surface as {@link ParamError} so the caller aborts cleanly before any\n     * row is inserted.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    async resolveTaskParams(context, overrides = {}) {\n        const overrideName = typeof overrides.name === \"string\" ? overrides.name.trim() : overrides.name;\n        const fromCli = context.params.get(\"name\", \"string\");\n        const cliName = typeof fromCli === \"string\" ? fromCli.trim() : fromCli;\n        const name = overrideName || cliName;\n        if (!name) {\n            throw new ParamError(\"Task --name is required (e.g. ping, stop, dummyHarvest)\");\n        }\n        const TaskClass = this.requireClass(name);\n        return TaskClass.resolveParams(context, { ...overrides, name });\n    }\n\n    /**\n     * Names of every registered task, sorted alphabetically (useful for CLI output\n     * and allowlist sanity checks).\n     *\n     * @returns {string[]}\n     */\n    listSupportedTasks() {\n        return Object.keys(this.map).sort();\n    }\n\n    /**\n     * Shallow copy of the internal map, for handing to `addMany` on another registry\n     * or for serialization.\n     *\n     * @returns {Record<string, Function>}\n     */\n    toObject() {\n        return { ...this.map };\n    }\n}\n","/**\n * Shared allowlist helpers for task runners: normalize CLI strings, merge with service (control) tasks.\n */\n\n/**\n * Task names every runner should be willing to claim (in addition to `--allowedTasks` or\n * service-group config). These map to core `TasksRegistry.withCoreTasks` handlers.\n */\nexport const SERVICE_TASK_NAMES = [\n    \"ping\",\n    \"stop\",\n    \"stopRunner\",\n    \"pause\",\n    \"pauseRunner\",\n    \"unpause\",\n    \"unpauseRunner\",\n    \"pauseTask\",\n    \"resumeTask\",\n    \"shellCommand\",\n    \"systemInfo\",\n    \"info\",\n    \"getLogs\",\n    \"setRuntimeParam\",\n    \"setRunnerParam\",\n    \"pruneTaskRetention\",\n];\n\n/**\n * Coerce a caller-supplied allowlist value (CLI string, array, or undefined) into\n * a clean string array, or `undefined` when nothing was provided / only blanks.\n *\n *   - `\"a,b\"`  → `[\"a\", \"b\"]`\n *   - `[\"a \", \"\", \" b\"]` → `[\"a\", \"b\"]`\n *   - `\"  \"` / `undefined` / `null` → `undefined`\n *\n * @param {unknown} value\n * @returns {string[] | undefined}\n */\nexport function normalizeAllowedTasks(value) {\n    if (!value) return undefined;\n    if (Array.isArray(value)) {\n        const out = value.map((v) => String(v).trim()).filter(Boolean);\n        return out.length ? out : undefined;\n    }\n    const out = String(value)\n        .split(\",\")\n        .map((v) => v.trim())\n        .filter(Boolean);\n    return out.length ? out : undefined;\n}\n\n/**\n * Union of `SERVICE_TASK_NAMES` and caller-provided names (deduped, sorted).\n * Use when building the allowlist for `runTasksLoop` / `claimNextRunnableTask`.\n *\n * @param {string[]} [names]\n * @returns {string[]}\n */\nexport function mergeAllowedTasksWithServiceTasks(names) {\n    const set = new Set([...SERVICE_TASK_NAMES, ...(names ?? [])]);\n    return Array.from(set).sort();\n}\n","/**\n * Claim order for idle queue rows:\n *   1. Due tasks first, earliest due instant wins\n *   2. If none are due, highest priority (lowest `priority` number)\n *\n * A row is due when `past_due` or `next_run_at` is set. The claim query already\n * gates `next_run_at` (NULL or <= now), so a stored next_run_at here means\n * \"ready / overdue\". The due instant is the earlier of the two timestamps.\n *\n * Tie-breakers (same due instant, or several non-due rows): priority, then\n * never-run first / oldest `completed_at`, then `created_at`.\n */\n\nfunction toMs(value) {\n    if (value == null || value === \"\") return null;\n    const t = value instanceof Date ? value.getTime() : new Date(value).getTime();\n    return Number.isFinite(t) ? t : null;\n}\n\n/** Earlier of `next_run_at` and `past_due`, or null when neither is set. */\nexport function claimDueInstantMs(row) {\n    const nextRun = toMs(row?.next_run_at);\n    const pastDue = toMs(row?.past_due);\n    if (nextRun == null) return pastDue;\n    if (pastDue == null) return nextRun;\n    return Math.min(nextRun, pastDue);\n}\n\nexport function isClaimDue(row) {\n    return claimDueInstantMs(row) != null;\n}\n\n/**\n * Sort comparator matching {@link applyClaimOrder}. Negative => `a` is claimed first.\n *\n * @param {object} a\n * @param {object} b\n * @returns {number}\n */\nexport function compareClaimCandidates(a, b) {\n    const dueA = claimDueInstantMs(a);\n    const dueB = claimDueInstantMs(b);\n    const aDue = dueA != null;\n    const bDue = dueB != null;\n    if (aDue !== bDue) return aDue ? -1 : 1;\n    if (aDue && dueA !== dueB) return dueA - dueB;\n\n    const priA = Number(a?.priority);\n    const priB = Number(b?.priority);\n    const pA = Number.isFinite(priA) ? priA : 50;\n    const pB = Number.isFinite(priB) ? priB : 50;\n    if (pA !== pB) return pA - pB;\n\n    const doneA = toMs(a?.completed_at);\n    const doneB = toMs(b?.completed_at);\n    if ((doneA == null) !== (doneB == null)) return doneA == null ? -1 : 1;\n    if (doneA != null && doneB != null && doneA !== doneB) return doneA - doneB;\n\n    const createdA = toMs(a?.created_at) ?? 0;\n    const createdB = toMs(b?.created_at) ?? 0;\n    if (createdA !== createdB) return createdA - createdB;\n    return 0;\n}\n\n/**\n * Knex ORDER BY matching {@link compareClaimCandidates} (must stay in sync so\n * `scanLimit` keeps the rows that should actually be claimed first).\n *\n * @param {import(\"knex\").Knex.QueryBuilder} query\n * @returns {import(\"knex\").Knex.QueryBuilder}\n */\nexport function applyClaimOrder(query) {\n    return query\n        .orderByRaw(\n            \"CASE WHEN past_due IS NOT NULL OR next_run_at IS NOT NULL THEN 0 ELSE 1 END ASC\"\n        )\n        .orderByRaw(\n            \"LEAST(COALESCE(next_run_at, past_due), COALESCE(past_due, next_run_at)) ASC NULLS LAST\"\n        )\n        .orderBy([{ column: \"priority\", order: \"asc\" }])\n        .orderByRaw(\"CASE WHEN completed_at IS NULL THEN 0 ELSE 1 END ASC\")\n        .orderBy([{ column: \"completed_at\", order: \"asc\" }, { column: \"created_at\", order: \"asc\" }]);\n}\n","import { spawn } from \"node:child_process\";\nimport {\n    appendTaskIpcLog,\n    flushTaskIpcLogs,\n    resolveIpcFileLogsDir,\n} from \"./taskLogs.js\";\n\n/** Upper bound on the `progress` column write; keeps a runaway child from bloating the row. */\nconst MAX_PROGRESS_TEXT_LEN = 4000;\n\n/**\n * Remove empty / non-string entries from a CLI args array.\n *\n * @param {unknown[]} [args]\n * @returns {string[]}\n */\nfunction toCliArgs(args = []) {\n    return args.filter((a) => typeof a === \"string\" && a.length > 0);\n}\n\n/**\n * Short prefix for child-side log lines: `<taskName>:<id8>[:<opid>]`.\n *\n * @param {{ name: string, id: string, opid?: string|null }} task\n * @returns {string}\n */\nfunction formatChildLogPrefix(task) {\n    return `${task.name}:${task.id.slice(0, 8)}${task.opid ? `:${task.opid}` : \"\"}`;\n}\n\n/**\n * True progress event: must carry `level === \"progress\"` and numeric `count`/`total`.\n * Anything else (debug, info, error, worker-result sentinel...) is treated as a regular log.\n *\n * @param {unknown} payload\n * @returns {boolean}\n */\nfunction isProgressPayload(payload) {\n    if (!payload || typeof payload !== \"object\") return false;\n    if (payload.level !== \"progress\") return false;\n    const count = Number(payload.count);\n    const total = Number(payload.total);\n    return Number.isFinite(count) && Number.isFinite(total) && total > 0;\n}\n\n/**\n * Render a progress payload as `\"[prefix ][message ]count/total\"` for the DB `progress` column.\n *\n * @param {{ prefix?: string, message?: string, count: number, total: number }} payload\n * @param {string} fallbackPrefix Used when `payload.prefix` is missing.\n * @returns {string}\n */\nfunction formatProgressText(payload, fallbackPrefix) {\n    const pfx = payload.prefix ? `${payload.prefix} ` : (fallbackPrefix ? `${fallbackPrefix} ` : \"\");\n    const label = typeof payload.message === \"string\" && payload.message ? `${payload.message} ` : \"\";\n    return `${pfx}${label}${payload.count}/${payload.total}`;\n}\n\n/**\n * Forward a structured IPC log line from the child to the parent's logger at the\n * matching level. `stdout`/`stderr` go through a different path (raw forwarding);\n * this only handles `{ level, message, ... }` payloads.\n *\n * @param {object} context\n * @param {string} prefix\n * @param {unknown} message\n * @returns {void}\n */\nfunction forwardChildLogToParent(context, prefix, message) {\n    if (!message || typeof message !== \"object\") return;\n    const text = typeof message.message === \"string\" ? message.message : null;\n    if (!text) return;\n    const level = typeof message.level === \"string\" ? message.level.toLowerCase() : \"\";\n    const line = `[child:${prefix}] ${text}`;\n    const logger = context.logger;\n    switch (level) {\n        case \"error\":\n        case \"fatal\":\n            logger.error?.(line);\n            return;\n        case \"warn\":\n        case \"warning\":\n            logger.warn?.(line);\n            return;\n        case \"debug\":\n            logger.debug?.(line);\n            return;\n        case \"info\":\n        default:\n            logger.info?.(line);\n    }\n}\n\n/**\n * Build the `node` argv for `spawn`. Workers are plain `.js` (ESM), so we just\n * run them with `node`. Any exec flags the parent was started with (e.g.\n * `--inspect`) are inherited so child workers behave consistently.\n *\n * @param {string} scriptPath\n * @param {string[]} cliArgs\n * @returns {string[]}\n */\nfunction buildNodeArgs(scriptPath, cliArgs) {\n    const inheritedExecArgs = Array.isArray(process.execArgv) ? [...process.execArgv] : [];\n    return [...inheritedExecArgs, scriptPath, ...cliArgs];\n}\n\n/**\n * Where progress writes land: `context.tasksQueueName` > `params.get(\"table\")` > `\"tasks\"`.\n *\n * @param {object} context\n * @returns {string}\n */\nfunction resolveTasksTableName(context) {\n    return context.tasksQueueName || context.params?.get?.(\"table\") || \"tasks\";\n}\n\n/**\n * Announce the IPC-file-logs target once at spawn time. Emits a single info line\n * with the resolved directory and notes when `tasksLogsEnabled=false` keeps logs in-memory only.\n *\n * @param {object} context\n * @param {{ ipcFileLogs?: { basePath?: string, namespace?: string, tableName: string } }} options\n * @returns {void}\n */\nfunction announceIpcFileLogsTarget(context, options) {\n    if (!options.ipcFileLogs) return;\n    const logsDir = resolveIpcFileLogsDir(context, options.ipcFileLogs);\n    const enabledRaw = context.params?.get?.(\"tasksLogsEnabled\");\n    const logsEnabled = enabledRaw === undefined ? true : !!enabledRaw;\n    context.logger.info?.(\n        `[tasks] IPC file logs: ${logsDir}` +\n            (logsEnabled ? \"\" : \" (tasksLogsEnabled=false; not persisted)\")\n    );\n}\n\n/**\n * Single-consumer FIFO for async work: each `push` runs after the previous one\n * finishes (success or failure). Thrown errors are swallowed by the chain so one\n * bad task never wedges the rest; callers handle errors inside their own `fn`.\n *\n * @returns {{ push: (fn: () => Promise<void>) => Promise<void>, drain: () => Promise<void> }}\n */\nfunction createSerializedQueue() {\n    let chain = Promise.resolve();\n    return {\n        push(fn) {\n            chain = chain.then(fn, () => {}).catch(() => {});\n            return chain;\n        },\n        drain() {\n            return chain.catch(() => {});\n        },\n    };\n}\n\n/**\n * Fork `scriptPath` as a Node child with IPC, forward its stdio + IPC logs to the\n * parent logger, update the task row's `progress` column on `{ level: \"progress\" }`\n * payloads, and resolve with a summary once the child closes.\n *\n * Contract:\n *   - **Only** IPC payloads matching {@link isProgressPayload} touch the `progress` column.\n *     stdout/stderr are diagnostic — accumulated and forwarded to logger but never\n *     persisted to `progress`.\n *   - The worker returns its final value via `process.send({ __taskWorkerResult: ... })`;\n *     that sentinel is captured and exposed as `workerResult`.\n *   - DB write and `onProgress` callback for a given payload run sequentially on a shared\n *     queue so ordering is preserved across rapid updates.\n *\n * @param {object} context\n * @param {{\n *   scriptPath: string,\n *   task: { id: string, name: string, opid?: string|null },\n *   args?: string[],\n *   cwd?: string,\n *   onProgress?: (progressText: string) => unknown | Promise<unknown>,\n *   onChildIpcMessage?: (message: unknown) => void,\n *   ipcFileLogs?: { basePath?: string, namespace?: string, tableName: string },\n * }} options\n * @returns {Promise<{\n *   exitCode: number | null,\n *   signal: NodeJS.Signals | null,\n *   stdout: string,\n *   stderr: string,\n *   workerResult: unknown,\n *   hadErrorMessage: boolean,\n * }>}\n */\nexport async function runNodeTaskScript(context, options) {\n    const cliArgs = toCliArgs([\"--route=ipc\", \"--mode=json\", ...(options.args || [])]);\n    const nodeArgs = buildNodeArgs(options.scriptPath, cliArgs);\n    const child = spawn(process.execPath, nodeArgs, {\n        cwd: options.cwd || process.cwd(),\n        stdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n        env: {\n            ...process.env,\n            TASK_ID: options.task.id,\n            TASK_NAME: options.task.name,\n            TASK_OPID: options.task.opid || \"\",\n        },\n    });\n\n    announceIpcFileLogsTarget(context, options);\n\n    const prefix = formatChildLogPrefix(options.task);\n    const tasksTable = resolveTasksTableName(context);\n    const progressQueue = createSerializedQueue();\n\n    const state = {\n        stdout: \"\",\n        stderr: \"\",\n        workerResult: null,\n        hadErrorMessage: false,\n    };\n\n    /**\n     * Serialize a progress update: write to DB, then invoke the optional callback.\n     * Each half is independently try/caught so one failure doesn't skip the other.\n     *\n     * @param {string} text\n     */\n    const writeProgress = (text) => {\n        const trimmed = typeof text === \"string\" ? text.slice(0, MAX_PROGRESS_TEXT_LEN) : \"\";\n        if (!trimmed) return;\n        progressQueue.push(async () => {\n            const db = context.db;\n            if (db) {\n                try {\n                    await db(tasksTable).where({ id: options.task.id }).update({ progress: trimmed });\n                } catch (error) {\n                    context.logger.warn?.(\n                        `[tasks] failed to update progress for task=${options.task.id}: ${error?.message ?? String(error)}`\n                    );\n                }\n            }\n            if (options.onProgress) {\n                try {\n                    await options.onProgress(trimmed);\n                } catch (error) {\n                    context.logger.warn?.(\n                        `[tasks] reportProgress callback failed for task=${options.task.id}: ${error?.message ?? String(error)}`\n                    );\n                }\n            }\n        });\n    };\n\n    child.stdout?.on(\"data\", (chunk) => {\n        const text = String(chunk);\n        state.stdout += text;\n        if (text.trim()) {\n            context.logger.info?.(`[child:${prefix}] ${text.trimEnd()}`);\n        }\n    });\n    child.stderr?.on(\"data\", (chunk) => {\n        const text = String(chunk);\n        state.stderr += text;\n        if (text.trim()) {\n            context.logger.warn?.(`[child:${prefix}] ${text.trimEnd()}`);\n        }\n    });\n\n    child.on(\"message\", (message) => {\n        if (message && typeof message === \"object\" && \"__taskWorkerResult\" in message) {\n            state.workerResult = message.__taskWorkerResult;\n            return;\n        }\n\n        if (message && typeof message === \"object\") {\n            const level = typeof message.level === \"string\" ? message.level.toLowerCase() : \"\";\n            if (level === \"error\" || level === \"fatal\") {\n                state.hadErrorMessage = true;\n            }\n        }\n\n        appendTaskIpcLog(context, options.task, message, options.ipcFileLogs);\n\n        try {\n            options.onChildIpcMessage?.(message);\n        } catch (e) {\n            context.logger.warn?.(`[tasks] onChildIpcMessage failed: ${e?.message ?? String(e)}`);\n        }\n\n        if (isProgressPayload(message)) {\n            context.logger.progress(message.message || \"progress\", {\n                prefix: message.prefix || prefix,\n                count: Number(message.count),\n                total: Number(message.total),\n            });\n            writeProgress(formatProgressText(message, prefix));\n            return;\n        }\n\n        forwardChildLogToParent(context, prefix, message);\n    });\n\n    return await new Promise((resolve, reject) => {\n        child.on(\"error\", (error) => reject(error));\n        child.on(\"close\", (exitCode, signal) => {\n            void (async () => {\n                await flushTaskIpcLogs(context);\n                await progressQueue.drain();\n                resolve({\n                    exitCode,\n                    signal,\n                    stdout: state.stdout.trim(),\n                    stderr: state.stderr.trim(),\n                    workerResult: state.workerResult,\n                    hadErrorMessage: state.hadErrorMessage,\n                });\n            })();\n        });\n    });\n}\n"],"mappings":"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","names":["cp","h","React","h","React","import_react","import_ink","chalk","config","resolve","instance","h","import_react","import_ink","h","import_react","import_ink","h","import_react","import_ink","path","config","import_react","import_ink","React","config","relativeMatch","Joi","path","import_fs","import_path","import_fs","import_path","fs","path","import_fs","import_path","path","fs","config","path","fs","stat","destPath","path","fs","sql","config","instance","knex","run","config","config","import_chalk","chalk","util","config","resolve","import_promises","path","import_promises","import_node_path","pathDirname","import_promises","import_node_path","import_promises","import_node_path","pathExists","path","import_promises","import_node_path","import_promises","resolve","import_promises","import_node_path","config","import_promises","pathExists","path","import_promises","import_node_path","import_node_child_process","path","import_promises","import_node_path","pathExists","path","import_node_child_process","import_promises","import_node_os","import_node_path","pathExists","path","config","import_promises","resolveKillTimeoutMs","import_promises","pathExists","path","import_promises","import_promises","import_node_os","import_node_path","import_node_child_process","pathExists","path","expandHome","resolve","run","import_node_path","import_node_os","resolve","import_node_os","import_node_crypto","getDb","os","import_promises","import_node_path","path","state","record","fs","import_node_child_process","resolve","import_node_os","import_promises","fs","os","h","out","import_node_child_process","resolve","getDb","os"]}