@nmakarov/cli-toolkit 0.76.0 → 0.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/screen/components.js","../src/screen/scrollbar.js","../src/screen/list-components.js","../src/screen/key-bindings.js","../src/screen/screens.js","../src/screen/ui-elements.js","../src/screen/scrollable-text.js","../src/screen/utils.js","../src/screen/footer-builder.js","../src/screen/index.js","../src/scripts/cli-runner.js","../src/args/index.js","../src/params/index.js","../src/errors.js","../src/params/custom-types.js","../src/logger/index.js","../src/logger/transports.js","../src/init/index.js","../src/db/index.js","../src/db/ensure.js","../src/tasks/index.js","../src/utils/date-utils.js","../src/utils/fs-utils.js","../src/utils/os-utils.js","../src/utils/format-utils.js","../src/utils/core-utils.js","../src/tasks/servicesRegistry.js","../src/tasks/taskUtils.js","../src/tasks/time-matcher.js","../src/tasks/taskLogs.js","../src/filedatabase/index.js","../src/filedatabase/serializers.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/TasksRegistry.js","../src/tasks/serviceTaskAllowlist.js","../src/tasks/taskScriptRunner.js"],"sourcesContent":["/**\n * Core screen layout components\n */\n\nimport { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\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\n return h(Box, {\n flexDirection: \"column\",\n marginTop: 1,\n borderStyle: \"single\",\n borderColor: \"cyan\",\n paddingX: 1,\n width: width // Use the calculated width directly\n }, children);\n}\n\n/**\n * Screen row - just a wrapper for spacing, borders handled by container\n */\nexport function ScreenRow({ children }) {\n return h(Box, { flexDirection: \"column\" }, children);\n}\n\n/**\n * Screen Title - first line inside container (left-aligned, breadcrumb-style)\n */\nexport function ScreenTitle({ text }) {\n return h(ScreenRow, {},\n h(Text, { bold: true, color: \"cyan\" }, 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/**\n * Screen Footer - bottom area with key bindings and status\n * \n * @example\n * <ScreenFooter lines={[\"esc to go back\", \"enter to select\"]} />\n * \n * @example\n * <ScreenFooter \n * lines={[\"esc to go back\", \"enter to select\"]} \n * textStyle={{ color: \"white\" }}\n * />\n * \n * @example\n * <ScreenFooter \n * lines={[\"esc to go back\", \"enter to select\"]} \n * textStyle={{ dimColor: false, color: \"green\" }}\n * />\n */\nexport function ScreenFooter({ lines, textStyle }) {\n const defaultTextStyle = {\n dimColor: true,\n color: \"white\"\n };\n \n const finalTextStyle = { ...defaultTextStyle, ...textStyle };\n\n // Flatten nested arrays and ensure all items are properly wrapped\n const flattenAndWrap = (items, keyPrefix = \"\") => {\n const result = [];\n let keyIndex = 0;\n\n items.forEach((item, index) => {\n if (Array.isArray(item)) {\n // Handle nested arrays\n const nested = flattenAndWrap(item, `${keyPrefix}-${index}`);\n result.push(...nested);\n } else if (typeof item === \"string\") {\n // Wrap strings in Text components\n result.push(\n h(Text, { key: `${keyPrefix}-${keyIndex++}`, ...finalTextStyle }, item)\n );\n } else {\n // JSX elements - add key if missing\n const element = item ;\n if (element.key === null || element.key === undefined) {\n result.push(\n h(Text, { key: `${keyPrefix}-${keyIndex++}`, ...finalTextStyle }, element)\n );\n } else {\n result.push(element);\n }\n }\n });\n\n return result;\n };\n\n const wrappedItems = flattenAndWrap(lines);\n\n return h(Box, { flexDirection: \"column\" },\n h(Box, { flexDirection: \"row\" }, ...wrappedItems)\n );\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 // Create caption that includes sort status\n const sortCaption = () => {\n if (sortOrder === \"none\") {\n return h(Text, {}, \"s to toggle sort\");\n } else {\n const sortLabel = sortOrder === \"asc\" ? \"ASC\" : \"DESC\";\n return h(Text, {}, \n \"s to toggle \",\n h(Text, { color: \"white\", bold: true }, \"sort\"),\n \" \",\n h(Text, highlightStyle, ` ${sortLabel} `)\n );\n }\n };\n\n ctx.setKeyBinding([\n ...navBindings,\n {\n key: \"s\",\n caption: sortCaption,\n action: \"toggleSort\",\n order: 5,\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-${actualIndex}`, color: \"white\" }, arrowPrefix),\n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n h(\n Text,\n {\n key: `name-${actualIndex}`,\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-${actualIndex}`, color: \"white\" }, arrowPrefix),\n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n renderItem(clipped, isSelected, displayIndex),\n );\n\n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: appendBar(row, displayIndex),\n });\n }\n\n return h(ScreenRow, {\n key: `item-${actualIndex}`,\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 // shift is often used with letters; for arrows we still treat omitted as \"any\"\n // only for shift — meta/ctrl are the page-jump modifiers we care about.\n if (!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 * Screen System - Action-based architecture\n */\n\nimport { useState, createElement as h } from \"react\";\nimport { render, useInput, Text } from \"ink\";\nimport { ScreenContainer, ScreenRow, ScreenTitle, ScreenDivider, ScreenFooter } from \"./components.js\";\nimport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\nimport {\n bindingIdentity,\n bindingMatchesInput,\n formatBindingKey,\n} from \"./key-bindings.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 });\n\n return Object.values(groups);\n}\n\n/**\n * Format key bindings for footer (returns array of strings/components)\n */\nexport function formatKeyBindings(bindings, mode = \"long\") {\n // Resolve function captions\n const resolvedBindings = bindings.map(binding => {\n let resolvedCaption = binding.caption;\n\n // If caption is a function, call it\n if (typeof binding.caption === \"function\") {\n resolvedCaption = binding.caption();\n }\n\n return {\n ...binding,\n resolvedCaption\n };\n });\n\n const groups = groupKeyBindings(resolvedBindings.map(b => ({\n ...b,\n caption: typeof b.resolvedCaption === \"string\" ? b.resolvedCaption : \"\"\n })));\n\n // Sort by order\n groups.sort((a, b) => a.order - b.order);\n\n const items = [];\n\n groups.forEach(group => {\n // Check if any binding in this group has a component/custom caption\n const bindingWithCustom = resolvedBindings.find(b =>\n group.keys.includes(b.key) && typeof b.resolvedCaption !== \"string\"\n );\n\n if (bindingWithCustom && bindingWithCustom.resolvedCaption) {\n // Use the full custom display (component or complex structure)\n items.push(bindingWithCustom.resolvedCaption );\n } else {\n // Standard format with string caption\n const keyStr = formatKeys(group.keys);\n\n if (mode === \"long\") {\n items.push(`${keyStr} to ${group.caption}`);\n } else {\n items.push(keyStr);\n }\n }\n });\n\n return items;\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 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 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 // 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 // Build footer\n const footerLines = [];\n\n // Add key bindings (returns array of strings/components)\n const bindingItems = formatKeyBindings(keyBindings, \"long\");\n\n if (bindingItems.length > 0) {\n // Build a single line with all binding items separated by \", \"\n const bindingsLine = [];\n bindingItems.forEach((item, idx) => {\n if (idx > 0) {\n bindingsLine.push(\", \");\n }\n bindingsLine.push(item);\n });\n\n // If all items are strings, join them; otherwise create a Box\n const allStrings = bindingItems.every(item => typeof item === \"string\");\n if (allStrings) {\n footerLines.push(bindingsLine.join(\"\"));\n } else {\n // Mixed strings and components - wrap all strings in Text components\n const wrappedBindingsLine = bindingsLine.map(item => \n typeof item === \"string\" ? h(Text, {}, item) : item\n );\n footerLines.push(wrappedBindingsLine);\n }\n }\n\n // Add custom footer items\n customFooterItems.forEach(item => {\n if (typeof item === \"string\") {\n footerLines.push(item);\n } else {\n footerLines.push(item);\n }\n });\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, { lines: footerLines })\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 });\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 * 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 {\n BAR_THUMB,\n BAR_TRACK,\n PAGE_SCROLL_KEY_BINDINGS,\n scrollbarGlyphs,\n} from \"./scrollbar.js\";\n\nexport { scrollbarGlyphs } from \"./scrollbar.js\";\n\nconst h = createElement;\n\n/**\n * Hard-wrap text to `cols` (keeps empty lines).\n * @param {string} text\n * @param {number} cols\n * @returns {string[]}\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 let rest = raw;\n while (rest.length > w) {\n out.push(rest.slice(0, w));\n rest = rest.slice(w);\n }\n if (rest.length > 0) out.push(rest);\n }\n return out;\n}\n\nfunction padEndVisible(s, w) {\n const t = String(s ?? \"\");\n if (t.length >= w) return t.slice(0, w);\n return t + \" \".repeat(w - t.length);\n}\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 * }} 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}) {\n const [scrollTop, setScrollTop] = useState(0);\n const [, bump] = useState(0);\n\n const termRows = process.stdout.rows || 24;\n const viewportRows = Math.max(\n 4,\n maxHeight != null ? Math.floor(maxHeight) : Math.max(8, termRows - 8),\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 useEffect(() => {\n setScrollTop((s) => Math.min(s, maxScroll));\n }, [maxScroll]);\n\n const maxScrollRef = useRef(maxScroll);\n const pageSizeRef = useRef(viewportRows);\n maxScrollRef.current = maxScroll;\n pageSizeRef.current = viewportRows;\n\n useEffect(() => {\n if (!ctx || !bindKeys) return undefined;\n\n ctx.setKeyBinding(SCROLL_KEYS);\n\n ctx.setAction(\"scrollUp\", () => {\n setScrollTop((s) => Math.max(0, s - 1));\n bump((n) => n + 1);\n ctx.update?.();\n });\n ctx.setAction(\"scrollDown\", () => {\n setScrollTop((s) => Math.min(maxScrollRef.current, s + 1));\n bump((n) => n + 1);\n ctx.update?.();\n });\n ctx.setAction(\"pageUp\", () => {\n setScrollTop((s) => Math.max(0, s - pageSizeRef.current));\n bump((n) => n + 1);\n ctx.update?.();\n });\n ctx.setAction(\"pageDown\", () => {\n setScrollTop((s) => Math.min(maxScrollRef.current, s + pageSizeRef.current));\n bump((n) => n + 1);\n ctx.update?.();\n });\n\n return undefined;\n }, [ctx, bindKeys]);\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\n // Single Text per row (not a row Box): avoids yoga width surprises; ASCII bar is 1 cell.\n const rowNodes = visible.map((line, i) => {\n const body = padEndVisible(line, textWidth);\n const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? \" \" : \"\";\n const isThumb = glyph === BAR_THUMB;\n return h(\n Text,\n { key: `L${clamped + i}` },\n body,\n glyph\n ? h(Text, { color: isThumb ? \"cyan\" : \"gray\" }, glyph)\n : null,\n );\n });\n\n // Pad short final page so the scrollbar track stays full height.\n if (bar && visible.length < viewportRows) {\n for (let i = visible.length; i < viewportRows; i++) {\n const glyph = bar[i] ?? BAR_TRACK;\n rowNodes.push(\n h(\n Text,\n { key: `pad${i}` },\n padEndVisible(\"\", textWidth),\n h(Text, { color: glyph === BAR_THUMB ? \"cyan\" : \"gray\" }, glyph),\n ),\n );\n }\n }\n\n return h(\n Box,\n { flexDirection: \"column\" },\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 * 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} from \"./screens.js\";\n\n// Reusable components\nexport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\nexport { ScreenContainer, ScreenRow, ScreenTitle, ScreenBody, ScreenFooter, ScreenDivider } from \"./components.js\";\nexport { ListItem, TextBlock, Divider, GridCell, InputField } from \"./ui-elements.js\";\nexport { ScrollableText, wrapTextLines, scrollbarGlyphs } from \"./scrollable-text.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\";\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","#!/usr/bin/env node\n\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { init } from \"../init/index.js\";\nimport { Db } from \"../db/index.js\";\nimport { defaultTasksRegistry, TasksManager, TasksRegistry } from \"../tasks/index.js\";\n\n// node subprojects/cli-toolkit/src/scripts/cli-runner.js --dbName=local --table=tasks --target=localRunner --recreateTaskTables=true\n// node subprojects/cli-toolkit/src/scripts/cli-runner.js --dbName=local --table=tasks --target=localRunner --recreateTaskTables=true --pollMs=1000 --maxParallel=1 --scanLimit=100 --tasksModule=./tasks/index.js\n\nconst defs = {\n tasksModule: \"string\",\n};\n\nasync function loadTasksModule(modulePath) {\n const absolute = path.isAbsolute(modulePath) ? modulePath : path.resolve(process.cwd(), modulePath);\n const imported = await import(pathToFileURL(absolute).href);\n if (!imported.tasksRegistry || typeof imported.tasksRegistry !== \"object\") {\n throw new Error(`tasksModule \"${modulePath}\" must export \"tasksRegistry\" object`);\n }\n return imported.tasksRegistry ;\n}\n\nconst flow = async (context) => {\n const { tasksModule } = context.params.getAll(defs);\n\n const db = await Db.init(context);\n context.db = db;\n\n const registry = new TasksRegistry().addMany(defaultTasksRegistry.toObject());\n if (tasksModule) {\n const externalRegistry = await loadTasksModule(tasksModule);\n registry.addMany(externalRegistry);\n }\n\n const tasksManager = TasksManager.init(context, {\n registry,\n });\n await tasksManager.ensureTaskTables();\n await tasksManager.runTasksLoop();\n};\n\nvoid init(flow);\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","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\n\n\n\n\n\n\n\n\n\n\n\n\nexport class Logger {\n context; // Partial context during initialization\n options;\n transport;\n startTimes = {};\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.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 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 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 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 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 this.out({ level: \"debug\", message, chunks });\n }\n\n info(message, ...chunks) {\n this.out({ level: \"info\", message, chunks });\n }\n\n notice(message, ...chunks) {\n this.out({ level: \"notice\", message, chunks });\n }\n\n warn(message, ...chunks) {\n this.out({ level: \"warn\", message, chunks });\n }\n\n error(message, ...chunks) {\n this.out({ level: \"error\", message, chunks });\n }\n\n logic(message, ...chunks) {\n this.out({ level: \"logic\", message, chunks });\n }\n\n silly(message, ...chunks) {\n this.out({ level: \"silly\", message, chunks });\n }\n\n results(results) {\n this.out({ 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 const paddedTotal = String(total).length;\n const paddedCount = String(count).padStart(paddedTotal, \" \");\n const payload = {\n level: \"progress\",\n message,\n count: paddedCount,\n total,\n prefix\n };\n\n if (!this.startTimes[prefix ?? \"\"]) {\n this.startTimes[prefix ?? \"\"] = Date.now();\n }\n const wantTimes = this.options.progressTimes;\n const wantRate = this.options.progressRate;\n if (wantTimes || wantRate) {\n const elapsedSeconds = (Date.now() - this.startTimes[prefix ?? \"\"]) / 1000;\n // Intervals completed = count - 1 (same basis as ETA).\n const intervals = count > 1 ? count - 1 : 0;\n const itemsPerSec = intervals > 0 && elapsedSeconds > 0 ? intervals / elapsedSeconds : -1;\n if (wantTimes) {\n let remaining = -1;\n if (itemsPerSec > 0) {\n remaining = (total - 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 if (count >= total) {\n delete this.startTimes[prefix ?? \"\"];\n delete this.lastProgressTimes[prefix ?? \"\"];\n }\n\n if (this.shouldOutputProgress(prefix ?? \"\", count, total)) {\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.prefix && !struct.prefix) {\n struct.prefix = this.options.prefix;\n }\n\n const output = this.options.mode === \"json\"\n ? struct\n : this.formatLog(struct);\n\n this.transport.write(output);\n }\n\n formatLog(struct) {\n const parts = [];\n const now = new Date();\n\n if (this.options.timestamp) {\n parts.push(now.toISOString());\n }\n\n if (this.options.showLevel) {\n parts.push(struct.level.toUpperCase().padEnd(MAX_LEVEL_LENGTH));\n }\n\n if (struct.level === \"progress\") {\n if (struct.prefix) {\n parts.push(LEVEL_COLORS[struct.level].bold(struct.prefix));\n }\n if (struct.count !== undefined && struct.total !== undefined) {\n parts.push(LEVEL_COLORS[struct.level](`${struct.count}/${struct.total}`));\n }\n } else if (struct.prefix) {\n parts.push(chalk.cyan(`[${struct.prefix}]`));\n }\n\n if (struct.message) {\n const formatter = LEVEL_COLORS[struct.level] ?? chalk.white;\n parts.push(formatter.bold(struct.message));\n }\n\n if (struct.level === \"progress\") {\n const formatter = LEVEL_COLORS[struct.level];\n if (struct.elapsed !== undefined && struct.remaining !== undefined) {\n parts.push(formatter(`${struct.elapsed}/${struct.remaining}`));\n }\n if (struct.rate !== undefined) {\n parts.push(formatter(struct.rate >= 0 ? `${struct.rate}/s` : \"-/s\"));\n }\n }\n\n if (struct.chunks && struct.chunks.length) {\n parts.push(this.inspectChunks(struct.chunks));\n }\n\n if (struct.results) {\n const formatter = LEVEL_COLORS[struct.level] ?? chalk.white;\n parts.push(formatter(JSON.stringify(struct.results, null, 4)));\n }\n\n return parts.join(\" \");\n }\n\n inspectChunks(chunks) {\n return chunks\n .map(chunk => util.inspect(chunk, { colors: true, depth: null }))\n .join(\" \");\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 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 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 for (const fn of fns) {\n try {\n await fn(ctx);\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 }\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","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 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\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.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 this.knexInstance = knex({\n client,\n connection: connectionConfig,\n pool: this.config.pool,\n acquireConnectionTimeout: this.config.acquireConnectionTimeout,\n ...(this.config.ssl && { ssl: this.config.ssl }),\n });\n\n if (this.config.profile) {\n this.attachProfiler();\n }\n\n if (this.config.testConnection) {\n await this.testConnection();\n }\n\n this.isConnected = true;\n this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\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 async disconnect() {\n if (!this.knexInstance) {\n return;\n }\n\n try {\n await this.knexInstance.destroy();\n this.knexInstance = null;\n this.isConnected = false;\n this.queriesLog = [];\n this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);\n throw error;\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 */\n async reconnect() {\n if (this._reconnectPromise) {\n await this._reconnectPromise;\n return;\n }\n\n this._reconnectPromise = (async () => {\n const old = this.knexInstance;\n this.isConnected = false;\n this.knexInstance = null;\n this.queriesLog = [];\n\n if (old) {\n try {\n await old.destroy();\n } catch (error) {\n this.logger.debug?.(\n `[Db] destroy during reconnect: ${this.getErrorMessage(error)}`\n );\n }\n }\n\n await this.connect();\n })();\n\n try {\n await this._reconnectPromise;\n } finally {\n this._reconnectPromise = null;\n }\n }\n\n async reconnectAfterConnectionError(error) {\n this.logger.warn?.(\n `[Db] Connection lost (${this.getErrorMessage(error)}) — reconnecting…`\n );\n await this.reconnect();\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.isConnectionError(error) || attempt >= retries) {\n throw error;\n }\n await this.reconnectAfterConnectionError(error);\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.isConnectionError(error)) {\n throw error;\n }\n await inst.reconnectAfterConnectionError(error);\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","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} 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\";\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\nexport {\n enqueueTask,\n ensureTaskTables,\n queueToTableNames,\n taskHistoryInsertFromQueueRow,\n updateTaskProgress,\n createTaskProgressReporter,\n} from \"./taskUtils.js\";\nexport {\n listServicesRegistry,\n registerInServicesRegistry,\n touchServicesRegistry,\n unregisterServicesRegistry,\n updateServicesRegistryMetadata,\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 flushTaskIpcLogs,\n ipcFileLogsTableNameForSourceResource,\n readTaskIpcLogsSnapshot,\n resolveIpcFileLogsDir,\n} from \"./taskLogs.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 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 */\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 taskInstance = new TaskClass(context, row);\n runningTaskInstances.set(row.id, taskInstance);\n const reportProgress = createTaskProgressReporter(context, 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 =\n results.checkpointParams && typeof results.checkpointParams === \"object\"\n ? results.checkpointParams\n : 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 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 // 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 return { stopRunnerRequested, stopAllowanceMs };\n}\n\n/** Fisher–Yates shuffle so concurrent workers don't all try the same candidate row first. */\nfunction shuffleTaskRowsInPlace(rows) {\n for (let i = rows.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n const t = rows[i];\n rows[i] = rows[j];\n rows[j] = t;\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 .orderByRaw(\"CASE WHEN past_due IS NULL THEN 1 ELSE 0 END ASC\")\n .orderBy([{ column: \"priority\", order: \"asc\" }])\n // Fair rotation for recurring tasks:\n // 1) never-run rows first\n // 2) then least recently completed rows\n // 3) then stable created_at order\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 .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 shuffleTaskRowsInPlace(candidates);\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 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\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 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 * 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 * 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 * 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 * 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 * 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/** Default max concurrent *alive* services per group (0 = unlimited). Override with runnerGroupMaxInstances. */\nconst DEFAULT_GROUP_MAX_INSTANCES = {\n intake: 1,\n harvest: 1,\n harvester: 0,\n loader: 0,\n toolkit: 0,\n photocare: 0,\n /** @deprecated use photocare */\n photos: 0,\n photosprocessor: 0,\n ingest: 0,\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 DEFAULT_GROUP_MAX_INSTANCES[g] ?? 0;\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 = claimed first (see claimNextRunnableTask: ORDER BY priority ASC).\n * Suggested range 0–100: 0 = most urgent, 100 = least; default 50 for normal work.\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 ],\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 * 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 path from \"node:path\";\nimport { FileDatabase } from \"../filedatabase/index.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 * @returns {Promise<{ records: object[], latestTs: string|null }>}\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\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 const latest = versions[versions.length - 1];\n const raw = await fd.read({ version: latest });\n const arr = Array.isArray(raw) ? raw : [];\n\n let filtered = arr;\n if (options.afterTs && String(options.afterTs).trim()) {\n const cut = String(options.afterTs).trim();\n filtered = arr.filter((r) => r && typeof r.ts === \"string\" && String(r.ts) > cut);\n }\n\n /** Watermark for incremental fetches: max `ts` among all matching rows, not only the returned tail. */\n let latestTs = null;\n for (const r of filtered) {\n const ts = typeof r?.ts === \"string\" ? String(r.ts) : null;\n if (ts && (!latestTs || ts > latestTs)) latestTs = ts;\n }\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 ? 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","/**\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\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\n */\n async loadMetadataJson(version) {\n const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n if (fs.existsSync(metadataFile)) {\n try {\n const rawData = await fs.promises.readFile(metadataFile, \"utf8\");\n return JSON.parse(rawData);\n } catch (e) {\n throw new FileDatabaseError(`Failed to read metadata for version \"${version}\": ${(e ).message}`);\n }\n }\n return null;\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 if (this.useMetadata) {\n const metadata = await this.loadMetadataJson(version);\n if (metadata) {\n return metadata;\n }\n }\n \n // Fallback: build from files\n // Use optimized version (only reads first+last) when no synopsis needed\n if (useOptimized && !this.fileSynopsisFunction && !this.versionSynopsisFunction) {\n return await this.buildMetadataOptimized(version);\n }\n \n // Use full version (reads all files) when synopsis calculation needed\n return await this.figureMetadataFromVersionFiles(version);\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 if (version) {\n if (!versions.includes(version)) {\n throw new FileDatabaseError(`[FileDatabase] Version \"${version}\" not found`);\n }\n await this.setCurrentVersion(version);\n } else {\n await this.setCurrentVersion(versions[versions.length - 1]);\n }\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 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 result.push(...recordsFromThisFile);\n recordsRead += recordsFromThisFile.length;\n\n cumulativeRecords += file.recordsCount;\n } catch (error) {\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\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","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 should finish the current unit of work, persist a checkpoint, and\n * return `{ success: true, results: { taskPaused: true, … } }` so the runner\n * keeps the row as `status=paused` instead of deleting it.\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\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];\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 \"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); runner may claim again\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 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 next_run_at: null,\n });\n\n context.logger?.warn?.(`[resumeTask] paused task ${id} (${row.name}) → idle`);\n return {\n success: true,\n results: { taskId: id, status: \"idle\", message: \"Task resumed (idle; will be claimed)\" },\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 */\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 }, 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 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\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 });\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","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\";\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 }\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];\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","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":["Box","Text","h","useState","h","Text","config","resolve","h","Box","Text","useState","useEffect","useRef","createElement","Box","Text","h","path","config","Box","React","Text","createElement","useEffect","useInput","useMemo","useRef","useState","path","config","relativeMatch","defs","path","config","flow","sql","defs","config","os","fs","path","resolve","getDb","path","fs","path","config","defs","path","fs","destPath","state","record","defs","resolve","os","fs","fs","os","out","spawn","getDb","getDb","os","defs","path"]}
1
+ {"version":3,"sources":["../src/screen/components.js","../src/screen/scrollbar.js","../src/screen/list-components.js","../src/screen/key-bindings.js","../src/screen/screens.js","../src/screen/ui-elements.js","../src/screen/scrollable-text.js","../src/screen/utils.js","../src/screen/footer-builder.js","../src/screen/index.js","../src/scripts/cli-runner.js","../src/args/index.js","../src/params/index.js","../src/errors.js","../src/params/custom-types.js","../src/logger/index.js","../src/logger/transports.js","../src/init/index.js","../src/db/index.js","../src/db/ensure.js","../src/tasks/index.js","../src/utils/date-utils.js","../src/utils/fs-utils.js","../src/utils/os-utils.js","../src/utils/format-utils.js","../src/utils/core-utils.js","../src/tasks/servicesRegistry.js","../src/tasks/taskUtils.js","../src/tasks/time-matcher.js","../src/tasks/taskLogs.js","../src/filedatabase/index.js","../src/filedatabase/serializers.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/TasksRegistry.js","../src/tasks/serviceTaskAllowlist.js","../src/tasks/taskScriptRunner.js"],"sourcesContent":["/**\n * Core screen layout components\n */\n\nimport { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\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\n return h(Box, {\n flexDirection: \"column\",\n marginTop: 1,\n borderStyle: \"single\",\n borderColor: \"cyan\",\n paddingX: 1,\n width: width // Use the calculated width directly\n }, children);\n}\n\n/**\n * Screen row - just a wrapper for spacing, borders handled by container\n */\nexport function ScreenRow({ children }) {\n return h(Box, { flexDirection: \"column\" }, children);\n}\n\n/**\n * Screen Title - first line inside container (left-aligned, breadcrumb-style)\n */\nexport function ScreenTitle({ text }) {\n return h(ScreenRow, {},\n h(Text, { bold: true, color: \"cyan\" }, 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/**\n * Screen Footer - bottom area with key bindings and status\n * \n * @example\n * <ScreenFooter lines={[\"esc to go back\", \"enter to select\"]} />\n * \n * @example\n * <ScreenFooter \n * lines={[\"esc to go back\", \"enter to select\"]} \n * textStyle={{ color: \"white\" }}\n * />\n * \n * @example\n * <ScreenFooter \n * lines={[\"esc to go back\", \"enter to select\"]} \n * textStyle={{ dimColor: false, color: \"green\" }}\n * />\n */\nexport function ScreenFooter({ lines, textStyle }) {\n const defaultTextStyle = {\n dimColor: true,\n color: \"white\"\n };\n \n const finalTextStyle = { ...defaultTextStyle, ...textStyle };\n\n // Flatten nested arrays and ensure all items are properly wrapped\n const flattenAndWrap = (items, keyPrefix = \"\") => {\n const result = [];\n let keyIndex = 0;\n\n items.forEach((item, index) => {\n if (Array.isArray(item)) {\n // Handle nested arrays\n const nested = flattenAndWrap(item, `${keyPrefix}-${index}`);\n result.push(...nested);\n } else if (typeof item === \"string\") {\n // Wrap strings in Text components\n result.push(\n h(Text, { key: `${keyPrefix}-${keyIndex++}`, ...finalTextStyle }, item)\n );\n } else {\n // JSX elements - add key if missing\n const element = item ;\n if (element.key === null || element.key === undefined) {\n result.push(\n h(Text, { key: `${keyPrefix}-${keyIndex++}`, ...finalTextStyle }, element)\n );\n } else {\n result.push(element);\n }\n }\n });\n\n return result;\n };\n\n const wrappedItems = flattenAndWrap(lines);\n\n return h(Box, { flexDirection: \"column\" },\n h(Box, { flexDirection: \"row\" }, ...wrappedItems)\n );\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 // Create caption that includes sort status\n const sortCaption = () => {\n if (sortOrder === \"none\") {\n return h(Text, {}, \"s to toggle sort\");\n } else {\n const sortLabel = sortOrder === \"asc\" ? \"ASC\" : \"DESC\";\n return h(Text, {}, \n \"s to toggle \",\n h(Text, { color: \"white\", bold: true }, \"sort\"),\n \" \",\n h(Text, highlightStyle, ` ${sortLabel} `)\n );\n }\n };\n\n ctx.setKeyBinding([\n ...navBindings,\n {\n key: \"s\",\n caption: sortCaption,\n action: \"toggleSort\",\n order: 5,\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-${actualIndex}`, color: \"white\" }, arrowPrefix),\n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n h(\n Text,\n {\n key: `name-${actualIndex}`,\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-${actualIndex}`, color: \"white\" }, arrowPrefix),\n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n renderItem(clipped, isSelected, displayIndex),\n );\n\n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: appendBar(row, displayIndex),\n });\n }\n\n return h(ScreenRow, {\n key: `item-${actualIndex}`,\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 // shift is often used with letters; for arrows we still treat omitted as \"any\"\n // only for shift — meta/ctrl are the page-jump modifiers we care about.\n if (!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 * Screen System - Action-based architecture\n */\n\nimport { useState, createElement as h } from \"react\";\nimport { render, useInput, Text } from \"ink\";\nimport { ScreenContainer, ScreenRow, ScreenTitle, ScreenDivider, ScreenFooter } from \"./components.js\";\nimport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\nimport {\n bindingIdentity,\n bindingMatchesInput,\n formatBindingKey,\n} from \"./key-bindings.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 });\n\n return Object.values(groups);\n}\n\n/**\n * Format key bindings for footer (returns array of strings/components)\n */\nexport function formatKeyBindings(bindings, mode = \"long\") {\n // Resolve function captions\n const resolvedBindings = bindings.map(binding => {\n let resolvedCaption = binding.caption;\n\n // If caption is a function, call it\n if (typeof binding.caption === \"function\") {\n resolvedCaption = binding.caption();\n }\n\n return {\n ...binding,\n resolvedCaption\n };\n });\n\n const groups = groupKeyBindings(resolvedBindings.map(b => ({\n ...b,\n caption: typeof b.resolvedCaption === \"string\" ? b.resolvedCaption : \"\"\n })));\n\n // Sort by order\n groups.sort((a, b) => a.order - b.order);\n\n const items = [];\n\n groups.forEach(group => {\n // Check if any binding in this group has a component/custom caption\n const bindingWithCustom = resolvedBindings.find(b =>\n group.keys.includes(b.key) && typeof b.resolvedCaption !== \"string\"\n );\n\n if (bindingWithCustom && bindingWithCustom.resolvedCaption) {\n // Use the full custom display (component or complex structure)\n items.push(bindingWithCustom.resolvedCaption );\n } else {\n // Standard format with string caption\n const keyStr = formatKeys(group.keys);\n\n if (mode === \"long\") {\n items.push(`${keyStr} to ${group.caption}`);\n } else {\n items.push(keyStr);\n }\n }\n });\n\n return items;\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 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 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 // 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 // Build footer\n const footerLines = [];\n\n // Add key bindings (returns array of strings/components)\n const bindingItems = formatKeyBindings(keyBindings, \"long\");\n\n if (bindingItems.length > 0) {\n // Build a single line with all binding items separated by \", \"\n const bindingsLine = [];\n bindingItems.forEach((item, idx) => {\n if (idx > 0) {\n bindingsLine.push(\", \");\n }\n bindingsLine.push(item);\n });\n\n // If all items are strings, join them; otherwise create a Box\n const allStrings = bindingItems.every(item => typeof item === \"string\");\n if (allStrings) {\n footerLines.push(bindingsLine.join(\"\"));\n } else {\n // Mixed strings and components - wrap all strings in Text components\n const wrappedBindingsLine = bindingsLine.map(item => \n typeof item === \"string\" ? h(Text, {}, item) : item\n );\n footerLines.push(wrappedBindingsLine);\n }\n }\n\n // Add custom footer items\n customFooterItems.forEach(item => {\n if (typeof item === \"string\") {\n footerLines.push(item);\n } else {\n footerLines.push(item);\n }\n });\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, { lines: footerLines })\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 });\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 * 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 {\n BAR_THUMB,\n BAR_TRACK,\n PAGE_SCROLL_KEY_BINDINGS,\n scrollbarGlyphs,\n} from \"./scrollbar.js\";\n\nexport { scrollbarGlyphs } from \"./scrollbar.js\";\n\nconst h = createElement;\n\n/**\n * Hard-wrap text to `cols` (keeps empty lines).\n * @param {string} text\n * @param {number} cols\n * @returns {string[]}\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 let rest = raw;\n while (rest.length > w) {\n out.push(rest.slice(0, w));\n rest = rest.slice(w);\n }\n if (rest.length > 0) out.push(rest);\n }\n return out;\n}\n\nfunction padEndVisible(s, w) {\n const t = String(s ?? \"\");\n if (t.length >= w) return t.slice(0, w);\n return t + \" \".repeat(w - t.length);\n}\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 * }} 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}) {\n const [scrollTop, setScrollTop] = useState(0);\n const [, bump] = useState(0);\n\n const termRows = process.stdout.rows || 24;\n const viewportRows = Math.max(\n 4,\n maxHeight != null ? Math.floor(maxHeight) : Math.max(8, termRows - 8),\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 useEffect(() => {\n setScrollTop((s) => Math.min(s, maxScroll));\n }, [maxScroll]);\n\n const maxScrollRef = useRef(maxScroll);\n const pageSizeRef = useRef(viewportRows);\n maxScrollRef.current = maxScroll;\n pageSizeRef.current = viewportRows;\n\n useEffect(() => {\n if (!ctx || !bindKeys) return undefined;\n\n ctx.setKeyBinding(SCROLL_KEYS);\n\n ctx.setAction(\"scrollUp\", () => {\n setScrollTop((s) => Math.max(0, s - 1));\n bump((n) => n + 1);\n ctx.update?.();\n });\n ctx.setAction(\"scrollDown\", () => {\n setScrollTop((s) => Math.min(maxScrollRef.current, s + 1));\n bump((n) => n + 1);\n ctx.update?.();\n });\n ctx.setAction(\"pageUp\", () => {\n setScrollTop((s) => Math.max(0, s - pageSizeRef.current));\n bump((n) => n + 1);\n ctx.update?.();\n });\n ctx.setAction(\"pageDown\", () => {\n setScrollTop((s) => Math.min(maxScrollRef.current, s + pageSizeRef.current));\n bump((n) => n + 1);\n ctx.update?.();\n });\n\n return undefined;\n }, [ctx, bindKeys]);\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\n // Single Text per row (not a row Box): avoids yoga width surprises; ASCII bar is 1 cell.\n const rowNodes = visible.map((line, i) => {\n const body = padEndVisible(line, textWidth);\n const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? \" \" : \"\";\n const isThumb = glyph === BAR_THUMB;\n return h(\n Text,\n { key: `L${clamped + i}` },\n body,\n glyph\n ? h(Text, { color: isThumb ? \"cyan\" : \"gray\" }, glyph)\n : null,\n );\n });\n\n // Pad short final page so the scrollbar track stays full height.\n if (bar && visible.length < viewportRows) {\n for (let i = visible.length; i < viewportRows; i++) {\n const glyph = bar[i] ?? BAR_TRACK;\n rowNodes.push(\n h(\n Text,\n { key: `pad${i}` },\n padEndVisible(\"\", textWidth),\n h(Text, { color: glyph === BAR_THUMB ? \"cyan\" : \"gray\" }, glyph),\n ),\n );\n }\n }\n\n return h(\n Box,\n { flexDirection: \"column\" },\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 * 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} from \"./screens.js\";\n\n// Reusable components\nexport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\nexport { ScreenContainer, ScreenRow, ScreenTitle, ScreenBody, ScreenFooter, ScreenDivider } from \"./components.js\";\nexport { ListItem, TextBlock, Divider, GridCell, InputField } from \"./ui-elements.js\";\nexport { ScrollableText, wrapTextLines, scrollbarGlyphs } from \"./scrollable-text.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\";\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","#!/usr/bin/env node\n\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { init } from \"../init/index.js\";\nimport { Db } from \"../db/index.js\";\nimport { defaultTasksRegistry, TasksManager, TasksRegistry } from \"../tasks/index.js\";\n\n// node subprojects/cli-toolkit/src/scripts/cli-runner.js --dbName=local --table=tasks --target=localRunner --recreateTaskTables=true\n// node subprojects/cli-toolkit/src/scripts/cli-runner.js --dbName=local --table=tasks --target=localRunner --recreateTaskTables=true --pollMs=1000 --maxParallel=1 --scanLimit=100 --tasksModule=./tasks/index.js\n\nconst defs = {\n tasksModule: \"string\",\n};\n\nasync function loadTasksModule(modulePath) {\n const absolute = path.isAbsolute(modulePath) ? modulePath : path.resolve(process.cwd(), modulePath);\n const imported = await import(pathToFileURL(absolute).href);\n if (!imported.tasksRegistry || typeof imported.tasksRegistry !== \"object\") {\n throw new Error(`tasksModule \"${modulePath}\" must export \"tasksRegistry\" object`);\n }\n return imported.tasksRegistry ;\n}\n\nconst flow = async (context) => {\n const { tasksModule } = context.params.getAll(defs);\n\n const db = await Db.init(context);\n context.db = db;\n\n const registry = new TasksRegistry().addMany(defaultTasksRegistry.toObject());\n if (tasksModule) {\n const externalRegistry = await loadTasksModule(tasksModule);\n registry.addMany(externalRegistry);\n }\n\n const tasksManager = TasksManager.init(context, {\n registry,\n });\n await tasksManager.ensureTaskTables();\n await tasksManager.runTasksLoop();\n};\n\nvoid init(flow);\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","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\n\n\n\n\n\n\n\n\n\n\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.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 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 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 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 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 this.out({ level: \"debug\", message, chunks });\n }\n\n info(message, ...chunks) {\n this.out({ level: \"info\", message, chunks });\n }\n\n notice(message, ...chunks) {\n this.out({ level: \"notice\", message, chunks });\n }\n\n warn(message, ...chunks) {\n this.out({ level: \"warn\", message, chunks });\n }\n\n error(message, ...chunks) {\n this.out({ level: \"error\", message, chunks });\n }\n\n logic(message, ...chunks) {\n this.out({ level: \"logic\", message, chunks });\n }\n\n silly(message, ...chunks) {\n this.out({ level: \"silly\", message, chunks });\n }\n\n results(results) {\n this.out({ 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 const paddedTotal = String(total).length;\n const paddedCount = String(count).padStart(paddedTotal, \" \");\n const payload = {\n level: \"progress\",\n message,\n count: paddedCount,\n total,\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 = (total - 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 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, total)) {\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.prefix && !struct.prefix) {\n struct.prefix = this.options.prefix;\n }\n\n const output = this.options.mode === \"json\"\n ? struct\n : this.formatLog(struct);\n\n this.transport.write(output);\n }\n\n formatLog(struct) {\n const parts = [];\n const now = new Date();\n\n if (this.options.timestamp) {\n parts.push(now.toISOString());\n }\n\n if (this.options.showLevel) {\n parts.push(struct.level.toUpperCase().padEnd(MAX_LEVEL_LENGTH));\n }\n\n if (struct.level === \"progress\") {\n if (struct.prefix) {\n parts.push(LEVEL_COLORS[struct.level].bold(struct.prefix));\n }\n if (struct.count !== undefined && struct.total !== undefined) {\n parts.push(LEVEL_COLORS[struct.level](`${struct.count}/${struct.total}`));\n }\n } else if (struct.prefix) {\n parts.push(chalk.cyan(`[${struct.prefix}]`));\n }\n\n if (struct.message) {\n const formatter = LEVEL_COLORS[struct.level] ?? chalk.white;\n parts.push(formatter.bold(struct.message));\n }\n\n if (struct.level === \"progress\") {\n const formatter = LEVEL_COLORS[struct.level];\n if (struct.elapsed !== undefined && struct.remaining !== undefined) {\n parts.push(formatter(`${struct.elapsed}/${struct.remaining}`));\n }\n if (struct.rate !== undefined) {\n parts.push(formatter(struct.rate >= 0 ? `${struct.rate}/s` : \"-/s\"));\n }\n }\n\n if (struct.chunks && struct.chunks.length) {\n parts.push(this.inspectChunks(struct.chunks));\n }\n\n if (struct.results) {\n const formatter = LEVEL_COLORS[struct.level] ?? chalk.white;\n parts.push(formatter(JSON.stringify(struct.results, null, 4)));\n }\n\n return parts.join(\" \");\n }\n\n inspectChunks(chunks) {\n return chunks\n .map(chunk => util.inspect(chunk, { colors: true, depth: null }))\n .join(\" \");\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 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 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 for (const fn of fns) {\n try {\n await fn(ctx);\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 }\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","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 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\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.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 this.knexInstance = knex({\n client,\n connection: connectionConfig,\n pool: this.config.pool,\n acquireConnectionTimeout: this.config.acquireConnectionTimeout,\n ...(this.config.ssl && { ssl: this.config.ssl }),\n });\n\n if (this.config.profile) {\n this.attachProfiler();\n }\n\n if (this.config.testConnection) {\n await this.testConnection();\n }\n\n this.isConnected = true;\n this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\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 async disconnect() {\n if (!this.knexInstance) {\n return;\n }\n\n try {\n await this.knexInstance.destroy();\n this.knexInstance = null;\n this.isConnected = false;\n this.queriesLog = [];\n this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);\n throw error;\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 */\n async reconnect() {\n if (this._reconnectPromise) {\n await this._reconnectPromise;\n return;\n }\n\n this._reconnectPromise = (async () => {\n const old = this.knexInstance;\n this.isConnected = false;\n this.knexInstance = null;\n this.queriesLog = [];\n\n if (old) {\n try {\n await old.destroy();\n } catch (error) {\n this.logger.debug?.(\n `[Db] destroy during reconnect: ${this.getErrorMessage(error)}`\n );\n }\n }\n\n await this.connect();\n })();\n\n try {\n await this._reconnectPromise;\n } finally {\n this._reconnectPromise = null;\n }\n }\n\n async reconnectAfterConnectionError(error) {\n this.logger.warn?.(\n `[Db] Connection lost (${this.getErrorMessage(error)}) — reconnecting…`\n );\n await this.reconnect();\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.isConnectionError(error) || attempt >= retries) {\n throw error;\n }\n await this.reconnectAfterConnectionError(error);\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.isConnectionError(error)) {\n throw error;\n }\n await inst.reconnectAfterConnectionError(error);\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","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} 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\";\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\nexport {\n enqueueTask,\n ensureTaskTables,\n queueToTableNames,\n taskHistoryInsertFromQueueRow,\n updateTaskProgress,\n createTaskProgressReporter,\n} from \"./taskUtils.js\";\nexport {\n listServicesRegistry,\n registerInServicesRegistry,\n touchServicesRegistry,\n unregisterServicesRegistry,\n updateServicesRegistryMetadata,\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 flushTaskIpcLogs,\n ipcFileLogsTableNameForSourceResource,\n readTaskIpcLogsSnapshot,\n resolveIpcFileLogsDir,\n} from \"./taskLogs.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 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 */\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 taskInstance = new TaskClass(context, row);\n runningTaskInstances.set(row.id, taskInstance);\n const reportProgress = createTaskProgressReporter(context, 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 =\n results.checkpointParams && typeof results.checkpointParams === \"object\"\n ? results.checkpointParams\n : 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 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 // 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 return { stopRunnerRequested, stopAllowanceMs };\n}\n\n/** Fisher–Yates shuffle so concurrent workers don't all try the same candidate row first. */\nfunction shuffleTaskRowsInPlace(rows) {\n for (let i = rows.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n const t = rows[i];\n rows[i] = rows[j];\n rows[j] = t;\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 .orderByRaw(\"CASE WHEN past_due IS NULL THEN 1 ELSE 0 END ASC\")\n .orderBy([{ column: \"priority\", order: \"asc\" }])\n // Fair rotation for recurring tasks:\n // 1) never-run rows first\n // 2) then least recently completed rows\n // 3) then stable created_at order\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 .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 shuffleTaskRowsInPlace(candidates);\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 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\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 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 * 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 * 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 * 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 * 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 * 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/** Default max concurrent *alive* services per group (0 = unlimited). Override with runnerGroupMaxInstances. */\nconst DEFAULT_GROUP_MAX_INSTANCES = {\n intake: 1,\n harvest: 1,\n harvester: 0,\n loader: 0,\n toolkit: 0,\n photocare: 0,\n /** @deprecated use photocare */\n photos: 0,\n photosprocessor: 0,\n ingest: 0,\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 DEFAULT_GROUP_MAX_INSTANCES[g] ?? 0;\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 = claimed first (see claimNextRunnableTask: ORDER BY priority ASC).\n * Suggested range 0–100: 0 = most urgent, 100 = least; default 50 for normal work.\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 ],\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 * 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 path from \"node:path\";\nimport { FileDatabase } from \"../filedatabase/index.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 * @returns {Promise<{ records: object[], latestTs: string|null }>}\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\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 const latest = versions[versions.length - 1];\n const raw = await fd.read({ version: latest });\n const arr = Array.isArray(raw) ? raw : [];\n\n let filtered = arr;\n if (options.afterTs && String(options.afterTs).trim()) {\n const cut = String(options.afterTs).trim();\n filtered = arr.filter((r) => r && typeof r.ts === \"string\" && String(r.ts) > cut);\n }\n\n /** Watermark for incremental fetches: max `ts` among all matching rows, not only the returned tail. */\n let latestTs = null;\n for (const r of filtered) {\n const ts = typeof r?.ts === \"string\" ? String(r.ts) : null;\n if (ts && (!latestTs || ts > latestTs)) latestTs = ts;\n }\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 ? 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","/**\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\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\n */\n async loadMetadataJson(version) {\n const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n if (fs.existsSync(metadataFile)) {\n try {\n const rawData = await fs.promises.readFile(metadataFile, \"utf8\");\n return JSON.parse(rawData);\n } catch (e) {\n throw new FileDatabaseError(`Failed to read metadata for version \"${version}\": ${(e ).message}`);\n }\n }\n return null;\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 if (this.useMetadata) {\n const metadata = await this.loadMetadataJson(version);\n if (metadata) {\n return metadata;\n }\n }\n \n // Fallback: build from files\n // Use optimized version (only reads first+last) when no synopsis needed\n if (useOptimized && !this.fileSynopsisFunction && !this.versionSynopsisFunction) {\n return await this.buildMetadataOptimized(version);\n }\n \n // Use full version (reads all files) when synopsis calculation needed\n return await this.figureMetadataFromVersionFiles(version);\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 if (version) {\n if (!versions.includes(version)) {\n throw new FileDatabaseError(`[FileDatabase] Version \"${version}\" not found`);\n }\n await this.setCurrentVersion(version);\n } else {\n await this.setCurrentVersion(versions[versions.length - 1]);\n }\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 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 result.push(...recordsFromThisFile);\n recordsRead += recordsFromThisFile.length;\n\n cumulativeRecords += file.recordsCount;\n } catch (error) {\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\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","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 should finish the current unit of work, persist a checkpoint, and\n * return `{ success: true, results: { taskPaused: true, … } }` so the runner\n * keeps the row as `status=paused` instead of deleting it.\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\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];\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 \"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); runner may claim again\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 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 next_run_at: null,\n });\n\n context.logger?.warn?.(`[resumeTask] paused task ${id} (${row.name}) → idle`);\n return {\n success: true,\n results: { taskId: id, status: \"idle\", message: \"Task resumed (idle; will be claimed)\" },\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 */\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 }, 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 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\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 });\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","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\";\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 }\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];\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","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":["Box","Text","h","useState","h","Text","config","resolve","h","Box","Text","useState","useEffect","useRef","createElement","Box","Text","h","path","config","Box","React","Text","createElement","useEffect","useInput","useMemo","useRef","useState","path","config","relativeMatch","defs","path","config","flow","sql","defs","config","os","fs","path","resolve","getDb","path","fs","path","config","defs","path","fs","destPath","state","record","defs","resolve","os","fs","fs","os","out","spawn","getDb","getDb","os","defs","path"]}