@nmakarov/cli-toolkit 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db.cjs +351 -0
- package/dist/db.cjs.map +1 -0
- package/dist/db.js +314 -0
- package/dist/db.js.map +1 -0
- package/dist/index.cjs +297 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +296 -0
- package/dist/index.js.map +1 -1
- package/package.json +22 -3
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/args/index.ts","../src/params/index.ts","../src/errors.ts","../src/params/custom-types.ts","../src/screen/screens.ts","../src/screen/components.ts","../src/screen/list-components.ts","../src/screen/ui-elements.ts","../src/screen/utils.ts","../src/screen/footer-builder.ts","../src/filedatabase/index.ts","../src/utils/os-utils.ts","../src/utils/fs-utils.ts","../src/utils/format-utils.ts","../src/utils/date-utils.ts","../src/filedatabase/serializers.ts","../src/filedatabase/synopsis-functions.ts"],"sourcesContent":["// Main exports for @nmakarov/cli-toolkit\nexport * from \"./args.js\";\nexport * from \"./params.js\";\nexport * from \"./screen.js\";\nexport * from \"./filedatabase.js\";\n","// Arguments discovery and parsing module\n// This module provides utilities for parsing CLI arguments and detecting flags\n\nimport { readFileSync, existsSync } from \"fs\";\nimport { resolve, dirname, basename, extname, join, isAbsolute } from \"path\";\nimport { config } from \"dotenv\";\n\nexport interface ArgsConfig {\n args?: string[]; // Default: process.argv.slice(2)\n aliases?: Record<string, string>; // Short → long mapping\n overrides?: Record<string, any>; // Highest precedence\n defaults?: Record<string, any>; // Lowest precedence\n prefixes?: string[]; // Negative flag prefixes (default: [\"not\", \"no\"])\n}\n\nexport interface ParsedArgs {\n command: string;\n flags: Record<string, boolean>;\n options: Record<string, string>;\n usedKeys: string[];\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 private args: Record<string, any> = {};\n private flags: Record<string, boolean> = {};\n private options: Record<string, string> = {};\n private commands: string[] = [];\n private usedKeys: Set<string> = new Set();\n private aliases: Record<string, string> = {};\n private overrides: Record<string, any> = {};\n private defaults: Record<string, any> = {};\n private prefixes: string[] = [];\n private nots: string[] = [];\n private configValues: Record<string, any> = {};\n private configsLoaded: string[] = [];\n private env: string = \"local\";\n\n constructor(config: ArgsConfig = {}) {\n // Set up configuration\n this.aliases = config.aliases || {};\n this.overrides = config.overrides || {};\n this.defaults = config.defaults || {};\n this.prefixes = config.prefixes || [\"not\", \"no\"];\n\n // Parse arguments first to get environment\n const args = config.args || process.argv.slice(2);\n this.parseArgs(args);\n\n // Set environment from parsed args\n this.env = this.get(\"env\")?.toLowerCase() || \"local\";\n\n // Load .env file\n this.loadDotEnv();\n\n // Load configuration files\n this.loadConfigFiles();\n\n // Check for conflicts (short + long form of same option)\n this.checkConflicts();\n }\n\n /**\n * Parse command line arguments\n */\n private parseArgs(args: string[]): void {\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 private parseLongOption(arg: string): [string, string | boolean] {\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 private parseShortOption(arg: string, args: string[], index: number): { consumed: number } {\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 private parseValue(value: string): string {\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 private setValue(key: string, value: string | boolean): void {\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 private checkConflicts(): void {\n const conflicts: string[] = [];\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: string): any {\n const resolvedKey = this.aliases[key] || key;\n this.usedKeys.add(resolvedKey);\n\n // Precedence order: overrides > CLI args > config files > env vars > defaults\n if (this.overrides[resolvedKey] !== undefined) {\n return this.overrides[resolvedKey];\n }\n\n // Case-insensitive lookup for CLI args (like legacy)\n const lcKey = resolvedKey.toLowerCase();\n\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 // Config file values (case-sensitive)\n if (this.configValues[resolvedKey] !== undefined) {\n return this.configValues[resolvedKey];\n }\n\n // Environment variable (convert key to ENV_VAR format)\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 const envKeyFound = Object.keys(process.env).find((k) => k.toUpperCase() === envKey);\n\n if (envSpecificKey) {\n return process.env[envSpecificKey];\n } else if (envKeyFound) {\n return process.env[envKeyFound];\n }\n\n // Default value\n if (this.defaults[resolvedKey] !== undefined) {\n return this.defaults[resolvedKey];\n }\n\n // NODE_ENV fallback for 'env' key (like legacy)\n if (resolvedKey === \"env\" && process.env.NODE_ENV !== undefined) {\n return process.env.NODE_ENV;\n }\n\n return undefined;\n }\n\n /**\n * Set a value (for testing/internal use)\n */\n set(key: string, value: any): void {\n this.args[key] = value;\n }\n\n /**\n * Check if a command exists (case-insensitive)\n */\n hasCommand(cmd: string): boolean {\n return this.commands.some((command) => command.toLowerCase() === cmd.toLowerCase());\n }\n\n /**\n * Get all commands\n */\n getCommands(): string[] {\n return [...this.commands];\n }\n\n /**\n * Get used keys (as array)\n */\n getUsed(): string[] {\n return Array.from(this.usedKeys);\n }\n\n /**\n * Get unused keys (as array)\n */\n getUnused(): string[] {\n const unused: string[] = [];\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 */\n private toEnvKey(key: string): string {\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 private loadDotEnv(): void {\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 // Try environment-specific .env file first (e.g., .env.local, .env.production)\n let dotEnvPathFile: string | null = null;\n\n const envSpecificFile = `.env.${this.env}`;\n const envSpecificPath = resolve(dotEnvPath, envSpecificFile);\n if (existsSync(envSpecificPath)) {\n dotEnvPathFile = envSpecificPath;\n }\n\n // If no environment-specific file found in current directory, try examples folder\n if (!dotEnvPathFile && !this.get(\"dotEnvPath\")) {\n const examplesPath = resolve(dotEnvPath, \"examples\");\n const examplesEnvSpecificPath = resolve(examplesPath, envSpecificFile);\n if (existsSync(examplesEnvSpecificPath)) {\n dotEnvPathFile = examplesEnvSpecificPath;\n }\n }\n\n // If no environment-specific file found, try default .env\n if (!dotEnvPathFile) {\n dotEnvPathFile = resolve(dotEnvPath, dotEnvFile);\n\n // If .env file doesn't exist in current directory, try examples folder (for our examples)\n if (!existsSync(dotEnvPathFile)) {\n if (!this.get(\"dotEnvPath\")) {\n // Try examples folder first (for our examples)\n const examplesPath = resolve(dotEnvPath, \"examples\");\n const examplesEnvFile = resolve(examplesPath, dotEnvFile);\n if (existsSync(examplesEnvFile)) {\n dotEnvPathFile = examplesEnvFile;\n } else {\n // Try parent directory (like legacy)\n dotEnvPathFile = resolve(dotEnvPath, \"..\", dotEnvFile);\n }\n }\n }\n }\n\n // Load .env file if it exists\n if (dotEnvPathFile && existsSync(dotEnvPathFile)) {\n config({ path: dotEnvPathFile, quiet: true });\n }\n }\n\n /**\n * Load configuration files\n */\n private loadConfigFiles(): void {\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 private resolveFileWithPath(\n optConfigFilePath: string | undefined,\n cfgFile: string,\n env?: string\n ): string {\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 private splitPath(filePath: string): { basePathWithName: string; extension: string } {\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 private requireConfigFile(filePath: string): any {\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(): ParsedArgs {\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: string | string[]): void {\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: Args | null = null;\n\n/**\n * Initialize Args instance (singleton pattern)\n */\nexport function init(args?: string[]): Args {\n instance = new Args({ args });\n return instance;\n}\n\n/**\n * Get the current Args instance (singleton pattern)\n */\nexport function getArgsInstance(): Args | null {\n return instance;\n}\n\n\n","import Joi from \"joi\";\nimport { ParamError } from \"../errors\";\nimport { joiEdateType, joiStringArrayType } from \"./custom-types\";\n\n/**\n * Parameter definition types\n */\nexport type ParamDefinition = \n | string \n | Joi.Schema \n | { \n type?: string | Joi.Schema; \n values?: any[]; \n [key: string]: any; \n };\n\nexport type ParamGetter = (key: string, definition?: any) => any;\nexport type ParamSetter = (key: string, value: any) => boolean;\n\n/**\n * Args instance interface\n */\nexport interface ArgsInstance {\n get(key: string): any;\n}\n\n/**\n * Params constructor options\n */\nexport interface ParamsOptions {\n [key: string]: any;\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 private params: Record<string, any> = {};\n private definitions: Record<string, any> = {};\n private args: ArgsInstance;\n private paramSetters: ParamSetter[] = [];\n private paramGetters: ParamGetter[] = [];\n\n constructor({ args }: { args: ArgsInstance }, opts: ParamsOptions = {}) {\n this.args = args;\n\n for (const [k, v] of Object.entries(opts)) {\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 * Assign a parameter definition\n */\n assignDefinition(key: string, definition?: ParamDefinition): any {\n if (this.definitions[key] && !definition) {\n return this.definitions[key];\n }\n\n let type: Joi.Schema;\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: string): Joi.Schema {\n let type: Joi.Schema;\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 type = type.default(defValObj.value);\n } else if (str.match(/required/)) {\n type = type.required();\n }\n\n return type;\n }\n\n /**\n * Validate a value against a definition\n */\n validate(key: string, val: any, def: any): any {\n // Pass current params as context to support cross-parameter references (e.g., @startTime+2h)\n const { value, error } = def.type.validate(val, { context: { params: this.params } });\n if (error) {\n const errs = error.details.map((el: any) => 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: string, definition?: ParamDefinition): any {\n const def = this.assignDefinition(key, definition);\n let valFromGetters: any = undefined;\n \n if (def.volatile || true) {\n valFromGetters = this.runAllRegisteredGetters(key);\n }\n \n const valFromArgs = this.args.get(key);\n const valFromParams = this.params[key];\n\n const res = valFromGetters ? this.validate(key, valFromGetters, def) :\n valFromArgs ? this.validate(key, valFromArgs, def) :\n this.validate(key, valFromParams, def);\n\n if (res !== undefined && def.values && !def.values.includes(res)) {\n throw new ParamError(`key ${key} should be one of ${def.values}`);\n }\n return res;\n }\n\n /**\n * Set a parameter value with validation\n */\n set(key: string, val: any, definition?: ParamDefinition): void {\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 const def = 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\n * Processes parameters left-to-right to support cross-parameter references\n */\n getAll(defs: Record<string, ParamDefinition>): Record<string, any> {\n const res: Record<string, any> = {};\n for (const [k, def] of Object.entries(defs)) {\n const value = this.get(k, def);\n res[k] = value;\n // Store validated value in params so subsequent params can reference it\n if (value !== undefined) {\n this.params[k] = value;\n }\n }\n return res;\n }\n\n /**\n * Run all registered getters for a key\n */\n runAllRegisteredGetters(key: string): any {\n let val: any = null;\n for (const getter of this.paramGetters) {\n val = getter(key, this.definitions[key]);\n if (val !== undefined) {\n break;\n }\n }\n return val;\n }\n\n /**\n * Run all registered setters for a key\n */\n runAllRegisteredSetters(key: string, value: any): boolean {\n let setterUsed: boolean = 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: ParamGetter): void {\n this.paramGetters.push(fn);\n }\n\n /**\n * Register a parameter setter\n */\n registerParamSetter(fn: ParamSetter): void {\n this.paramSetters.push(fn);\n }\n}\n\n// Singleton instance\nlet paramsInstance: Params | null = null;\n\n/**\n * Initialize the singleton Params instance\n */\nexport const init = (fns: { args: ArgsInstance }, opts: ParamsOptions = {}): Params => {\n paramsInstance = new Params(fns, opts);\n return paramsInstance;\n};\n\n/**\n * Get the current singleton Params instance\n */\nexport const getParamsInstance = (): Params | null => paramsInstance;\n\n// Export custom types for external use\nexport { joiEdateType, joiStringArrayType };\n\n\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\n","import Joi from \"joi\";\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: any, helpers: Joi.CustomHelpers): string => {\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 as any).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: Date;\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: number, unit: string, sign: string): number {\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: string) => (value: any, helpers: Joi.CustomHelpers): any[] => {\n if (value === undefined || typeof value === \"function\") {\n return [];\n }\n \n const arr = value.split(/,\\s*/).map((el: string) => {\n if (type === \"number\") {\n const v = parseInt(el, 10);\n if (isNaN(v)) {\n throw new ParamError(`array element \"${el}\" should be numeric`);\n }\n return v;\n } else if (type === \"boolean\") {\n const v = el.match(/true|t|yes|1/i) ? true :\n el.match(/false|f|no|0/i) ? false : null;\n if (v === null) {\n throw new ParamError(`array element \"${el}\" should be boolean`);\n }\n return v;\n } else if (type === \"string\") {\n return el;\n } else {\n throw new ParamError(`unknown type \"${type}\" for array elements`);\n }\n });\n \n return arr;\n};\n\n","/**\n * Screen System - Action-based architecture\n */\n\nimport React, { useState, useRef, useEffect, createElement as h } from \"react\";\nimport { render, useInput, Box, Text } from \"ink\";\nimport { ScreenContainer, ScreenRow, ScreenTitle, ScreenDivider, ScreenFooter } from \"./components.js\";\nimport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\n\n// Types\ninterface KeyBinding {\n key: string;\n caption: string | (() => string | JSX.Element);\n action: string;\n order?: number;\n protected?: boolean;\n enabled?: boolean;\n condition?: (ctx: ScreenContext) => boolean;\n}\n\ninterface BindingGroup {\n keys: string[];\n caption: string;\n order: number;\n}\n\ninterface ActionPayload {\n input: string;\n key: any;\n binding: KeyBinding;\n}\n\ninterface ScreenContext {\n setAction: (actionName: string, handlerFn: (payload?: ActionPayload) => void | any) => void;\n setKeyBinding: (bindingOrBindings: KeyBinding | KeyBinding[]) => void;\n updateKeyBinding: (keyName: string, updates: Partial<KeyBinding>) => void;\n removeKeyBinding: (keyName: string) => void;\n addFooter: (item: string | JSX.Element) => void;\n clearFooter: () => void;\n setFooter: (items: string | string[] | JSX.Element | JSX.Element[]) => void;\n update: () => void;\n goBack: () => void;\n close: (result: any) => void;\n parentData: any;\n}\n\ninterface ShowScreenConfig {\n title: string;\n onRender: (ctx: ScreenContext) => JSX.Element;\n parentData?: any;\n}\n\ninterface ShowListScreenConfig {\n title: string;\n items: Array<{ name: string; value: any }>;\n onSelect?: (value: any, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n renderItem?: (item: { name: string; value: any }, isSelected: boolean, displayIndex: number) => JSX.Element;\n getTitle?: (item: { name: string; value: any }) => string;\n sortable?: boolean;\n maxHeight?: number;\n sortHighlightStyle?: {\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n };\n selectionMarker?: string; // Customizable selection marker, default: \" \"\n}\n\ninterface ShowMultiColumnListScreenConfig {\n title: string;\n items: string[];\n onSelect?: (item: string, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n}\n\ninterface ShowMultiColumnListWithPreviewScreenConfig {\n title: string;\n items: string[];\n getPreviewContent?: (item: string) => string | JSX.Element | Record<string, any>;\n onSelect?: (item: string, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n}\n\n/**\n * Group key bindings by caption for footer display\n */\nexport function groupKeyBindings(bindings: KeyBinding[]): BindingGroup[] {\n const groups: Record<string, BindingGroup> = {};\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(binding.key);\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: KeyBinding[], mode: string = \"long\"): (string | JSX.Element)[] {\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: (string | JSX.Element)[] = [];\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 as JSX.Element);\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: string[]): string {\n const keyMap: Record<string, string> = {\n \"escape\": \"esc\",\n \"leftArrow\": \"←\",\n \"rightArrow\": \"→\",\n \"upArrow\": \"↑\",\n \"downArrow\": \"↓\",\n \"return\": \"enter\"\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: ShowScreenConfig): Promise<any> {\n const {\n title,\n onRender,\n parentData = {}\n } = config;\n\n\n return new Promise((resolve) => {\n let instance: any;\n\n // Persistent collections (closure variables survive re-renders)\n const keyBindings: KeyBinding[] = [];\n const actions: Record<string, (payload?: ActionPayload) => void | any> = {};\n const customFooterItems: (string | JSX.Element)[] = [];\n let renderResult: JSX.Element | null = null;\n let initialized = false;\n\n const Screen = (): JSX.Element => {\n const [updateCounter, setUpdateCounter] = useState(0);\n\n // Initialize defaults only once\n if (!initialized) {\n const defaultBindings: KeyBinding[] = [\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: ScreenContext = {\n setAction: (actionName: string, handlerFn: (payload?: ActionPayload) => void | any) => {\n actions[actionName] = handlerFn;\n },\n\n setKeyBinding: (bindingOrBindings: KeyBinding | KeyBinding[]) => {\n // Support both single object and array\n const bindingsToSet = Array.isArray(bindingOrBindings) ? bindingOrBindings : [bindingOrBindings];\n\n bindingsToSet.forEach(binding => {\n // Check if key already exists\n const existingIndex = keyBindings.findIndex(b => b.key === binding.key);\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: string, updates: Partial<KeyBinding>) => {\n const index = keyBindings.findIndex(b => b.key === keyName);\n if (index >= 0) {\n // Update only specified properties\n keyBindings[index] = {\n ...keyBindings[index],\n ...updates\n };\n }\n },\n\n removeKeyBinding: (keyName: string) => {\n const index = keyBindings.findIndex(b => b.key === keyName);\n if (index >= 0) {\n if (keyBindings[index].protected) {\n console.warn(`Cannot remove protected key: ${keyName}`);\n return;\n }\n keyBindings.splice(index, 1);\n }\n },\n\n addFooter: (item: string | JSX.Element) => {\n customFooterItems.push(item);\n },\n\n clearFooter: () => {\n customFooterItems.length = 0;\n },\n\n setFooter: (items: string | string[] | JSX.Element | JSX.Element[]) => {\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: any) => {\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: string, key: any) => {\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: KeyBinding | null = null;\n\n for (const binding of keyBindings) {\n let keyMatches = false;\n\n // Check key match\n if (key[binding.key]) {\n keyMatches = true;\n } else if (input === binding.key) {\n keyMatches = true;\n }\n\n if (keyMatches) {\n // Check if binding is enabled\n if (binding.enabled === false) {\n continue;\n }\n\n // Check condition if present\n if (binding.condition && !binding.condition(context)) {\n continue;\n }\n\n matchedBinding = binding;\n break;\n }\n }\n\n if (matchedBinding && actions[matchedBinding.action]) {\n // Execute action\n const actionResult = 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: (string | JSX.Element | (string | JSX.Element)[])[] = [];\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: (string | JSX.Element)[] = [];\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: any) => {\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: ShowListScreenConfig): Promise<any> {\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: ShowMultiColumnListScreenConfig): Promise<any> {\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: ShowMultiColumnListWithPreviewScreenConfig): Promise<any> {\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 * Core screen layout components\n */\n\nimport React, { 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: number | null = null): number {\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\nexport interface ScreenContainerProps {\n children: React.ReactNode;\n}\n\nexport interface ScreenRowProps {\n children: React.ReactNode;\n}\n\nexport interface ScreenTitleProps {\n text: string;\n}\n\nexport interface ScreenDividerProps {\n width?: number;\n}\n\nexport interface ScreenBodyProps {\n children: React.ReactNode;\n alignItems?: \"flex-start\" | \"center\" | \"flex-end\";\n}\n\nexport interface ScreenFooterProps {\n lines: (string | JSX.Element)[];\n textStyle?: {\n color?: string;\n dimColor?: boolean;\n bold?: boolean;\n };\n}\n\n/**\n * Screen Container - uses Ink's built-in borderStyle for proper text wrapping\n */\nexport function ScreenContainer({ children }: ScreenContainerProps): JSX.Element {\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 }: ScreenRowProps): JSX.Element {\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 }: ScreenTitleProps): JSX.Element {\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 }: ScreenDividerProps): JSX.Element {\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\" }: ScreenBodyProps): JSX.Element {\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 }: ScreenFooterProps): JSX.Element {\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: (string | JSX.Element | (string | JSX.Element)[])[], keyPrefix: string = \"\"): JSX.Element[] => {\n const result: JSX.Element[] = [];\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 as JSX.Element;\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 * 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\";\n\nconst h = createElement;\n\n// TODO: Define proper context type interface\ninterface ScreenContext {\n setAction: (name: string, handler: () => void) => void;\n setKeyBinding: (bindings: KeyBinding | KeyBinding[]) => void;\n addFooter: (message: string) => void;\n setFooter: (items: string | string[]) => void;\n goBack: () => void;\n update: () => void;\n}\n\ninterface KeyBinding {\n key: string;\n caption: string;\n action: string;\n order: number;\n}\n\ninterface ListItem {\n name: string;\n value: any;\n}\n\ninterface MultiColumnListComponentProps {\n items: string[];\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n}\n\ninterface MultiColumnListWithPreviewComponentProps {\n items: string[];\n getPreviewContent?: (item: string) => string | JSX.Element | Record<string, any>;\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n}\n\ninterface ListComponentProps {\n items: ListItem[];\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n renderItem?: (item: ListItem, isSelected: boolean, displayIndex: number) => JSX.Element;\n getTitle?: (item: ListItem) => string;\n sortable?: boolean;\n maxHeight?: number;\n sortHighlightStyle?: {\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n };\n selectionMarker?: string; // Customizable selection marker, default: \" \"\n}\n\n/**\n * Multi-column list component\n * Handles its own navigation, actions, and key bindings\n */\nexport function MultiColumnListComponent({ items, ctx, selectedIndexRef }: MultiColumnListComponentProps): JSX.Element {\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: JSX.Element[] = [];\n for (let row = 0; row < itemsPerColumn; row++) {\n const cols: JSX.Element[] = [];\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}: MultiColumnListWithPreviewComponentProps): JSX.Element {\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: JSX.Element[] = [];\n for (let row = 0; row < itemsPerColumn; row++) {\n const cols: JSX.Element[] = [];\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: JSX.Element[] = [];\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 = \" \" }: ListComponentProps): JSX.Element {\n const [, forceUpdate] = useState({});\n const [sortOrder, setSortOrder] = useState<\"none\" | \"asc\" | \"desc\">(\"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\n // Default getTitle - returns item if string, otherwise item.title\n const defaultGetTitle = (item: ListItem): string => {\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 // 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 // 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 \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 // Force update to trigger re-render with new selected index\n forceUpdate({});\n });\n\n ctx.setAction(\"moveDown\", () => {\n const currentItems = 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 maxIndex = currentItems.length - 1;\n const newIndex = Math.min(maxIndex, selectedIndexRef.current + 1);\n selectedIndexRef.current = 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 // Force update to trigger re-render with new selected index\n forceUpdate({});\n });\n\n // Add scroll actions for arrow clicks\n ctx.setAction(\"scrollUp\", () => {\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const newScrollOffset = Math.max(0, currentScrollOffset - 1);\n setScrollOffset(newScrollOffset);\n forceUpdate({});\n });\n\n ctx.setAction(\"scrollDown\", () => {\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const newScrollOffset = Math.min(currentMaxScrollOffset, currentScrollOffset + 1);\n setScrollOffset(newScrollOffset);\n forceUpdate({});\n });\n\n // Set up sort action if sortable\n if (sortable) {\n ctx.setAction(\"toggleSort\", () => {\n const nextSort: \"none\" | \"asc\" | \"desc\" = \n sortOrder === \"none\" ? \"asc\" : \n sortOrder === \"asc\" ? \"desc\" : \"none\";\n \n // Store the currently selected item from the current display items\n const currentSelectedItem = displayItems[selectedIndexRef.current];\n \n setSortOrder(nextSort);\n \n // Calculate the new sorted items\n const newSortedItems = nextSort !== \"none\" ? [...items].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 }) : items;\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 // Update key bindings with sort\n ctx.setKeyBinding([\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 },\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 // No sorting\n ctx.setKeyBinding([\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n ]);\n }\n }, [sortOrder, sortable]);\n\n const selectedIndex = selectedIndexRef.current;\n \n\n // Default renderer with static scroll indicators for debugging\n const defaultRenderItem = (item: ListItem, isSelected: boolean, displayIndex: number, actualIndex: number) => {\n const isFirstVisible = displayIndex === 0;\n const isLastVisible = displayIndex === visibleItems.length - 1;\n \n // Build prefix with arrows and selection marker\n let arrowPrefix = \"\";\n let selectionPrefix = \"\";\n \n // Only show arrows when scrolling is actually needed and available\n if (isFirstVisible && canScrollUp) {\n arrowPrefix = \"↑ \";\n } else if (isLastVisible && canScrollDown) {\n arrowPrefix = \"↓ \";\n } else {\n // No arrow, but reserve the same space\n arrowPrefix = \" \";\n }\n \n // Always reserve space for selection marker (pad with spaces if not selected)\n if (isSelected) {\n selectionPrefix = selectionMarker;\n } else {\n // Pad with spaces to match the length of the selection marker\n selectionPrefix = \" \".repeat(selectionMarker.length);\n }\n \n return h(Box, { flexDirection: \"row\" },\n // Arrow (clickable if functional, not highlighted)\n h(Text, { \n key: `arrow-${actualIndex}`,\n color: \"white\"\n }, arrowPrefix),\n // Selection marker space (always same width, not highlighted) \n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n // Item name (highlighted if selected)\n h(Text, {\n key: `name-${actualIndex}`,\n color: isSelected ? \"black\" : \"white\",\n backgroundColor: isSelected ? \"cyan\" : undefined,\n bold: isSelected\n }, item.name)\n );\n };\n\n // Use custom renderer if provided, otherwise use default\n const itemRenderer = renderItem || defaultRenderItem;\n\n // Render visible menu items with scroll indicators\n return h(Box, { flexDirection: \"column\" },\n ...visibleItems.map((item, displayIndex) => {\n const actualIndex = clampedScrollOffset + displayIndex;\n const isSelected = actualIndex === selectedIndex;\n \n // If using custom renderer, wrap it with scroll indicators\n if (renderItem) {\n const isFirstVisible = displayIndex === 0;\n const isLastVisible = displayIndex === visibleItems.length - 1;\n \n // Build prefix with arrows and selection marker\n let arrowPrefix = \"\";\n let selectionPrefix = \"\";\n \n // Only show arrows when scrolling is actually needed and available\n if (isFirstVisible && canScrollUp) {\n arrowPrefix = \"↑ \";\n } else if (isLastVisible && canScrollDown) {\n arrowPrefix = \"↓ \";\n } else {\n // No arrow, but reserve the same space\n arrowPrefix = \" \";\n }\n \n // Always reserve space for selection marker (pad with spaces if not selected)\n if (isSelected) {\n selectionPrefix = selectionMarker;\n } else {\n // Pad with spaces to match the length of the selection marker\n selectionPrefix = \" \".repeat(selectionMarker.length);\n }\n \n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: h(Box, { flexDirection: \"row\" },\n // Arrow (clickable if functional, not highlighted)\n h(Text, { \n key: `arrow-${actualIndex}`,\n color: \"white\"\n }, arrowPrefix),\n // Selection marker space (always same width, not highlighted) \n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n // Custom rendered content\n renderItem(item, isSelected, displayIndex)\n )\n });\n } else {\n // Use default renderer (which already includes scroll indicators)\n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: itemRenderer(item, isSelected, displayIndex, actualIndex)\n });\n }\n })\n );\n}\n","/**\n * Reusable UI elements for the screen system\n */\n\nimport React, { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\n\n// Types\nexport interface ListItemProps {\n children: React.ReactNode;\n isSelected?: boolean;\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n dimColor?: boolean;\n}\n\nexport interface TextBlockProps {\n text: string;\n color?: string;\n dimmed?: boolean;\n bold?: boolean;\n maxWidth?: number;\n}\n\nexport interface DividerProps {\n character?: string;\n width?: number;\n}\n\nexport interface GridCellProps {\n children: React.ReactNode;\n width?: number;\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n dimColor?: boolean;\n align?: \"left\" | \"center\" | \"right\";\n}\n\nexport interface InputFieldProps {\n prompt: string;\n value: string;\n onChange?: (value: string) => void;\n onSubmit?: (value: string) => void;\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}: ListItemProps): JSX.Element {\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 \n}: TextBlockProps): JSX.Element {\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 }: DividerProps): JSX.Element {\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}: GridCellProps): JSX.Element {\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, onSubmit }: InputFieldProps): JSX.Element {\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 * 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: string[]): string {\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: string[], suffix: string = \"\"): string {\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\ninterface FooterConfig {\n navigation?: string | string[];\n actions?: string | string[];\n info?: string | string[];\n escape?: string | string[];\n custom?: string | string[];\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: FooterConfig = {}): string[] {\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: string[] = [];\n\n // Build main help line (navigation + actions + escape)\n const mainParts: (string | string[])[] = [];\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: string | string[] | null = null): string[] => 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: number): string[] => 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: (): string[] => 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: (): string[] => buildFooter({\n escape: \"Esc to continue\"\n }),\n\n /**\n * Main menu footer (escape exits)\n */\n mainMenu: (): string[] => 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: boolean = false): string[] => {\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: string[] | null | undefined): string[] {\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: string[] = [];\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 * 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\";\nimport type {\n FileDatabaseConfig,\n VersionMetadata,\n FileEntry,\n ReadOptions,\n WriteOptions,\n WriteContext,\n FileSynopsisFunction,\n VersionSynopsisFunction,\n DataType,\n} from \"./types.js\";\nimport { ensurePath, generateVersionName, getFileExtension, getFreeDiskSpace, bytesToHumanReadable, isTimestampFolder } from \"./utils.js\";\nimport { detectDataType, serializeData, deserializeData } from \"./serializers.js\";\nimport { ParamError } from \"../errors.js\";\n\n/**\n * FileDatabase Error class\n */\nexport class FileDatabaseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\nexport class FileDatabase {\n private basePath: string;\n private namespace: string;\n private tableName: string | null = null;\n private versioned: boolean;\n private maxVersions: number;\n private pageSize: number;\n private useMetadata: boolean;\n private freeSpaceThreshold: number;\n private logger: any;\n\n // Current operation state\n private currentVersion: string | null = null;\n private currentVersionFolder: string | null = null;\n private currentFileNumber: number = 0;\n private currentRecord: number = 0;\n private hasReadFirstPage: boolean = false;\n private lastFileData: any = null;\n private metadata: VersionMetadata;\n\n // Synopsis calculation functions\n private fileSynopsisFunction: FileSynopsisFunction | null = null;\n private versionSynopsisFunction: VersionSynopsisFunction | null = null;\n\n constructor(config: FileDatabaseConfig) {\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 * Get default metadata structure\n */\n private getDefaultMetadata(): VersionMetadata {\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 private getDestinationPath(version?: string): string {\n const errors = [\"basePath\", \"namespace\", \"tableName\"]\n .filter(prop => !this[prop as keyof this])\n .map(prop => `${prop} is not set`);\n if (errors.length) {\n throw new FileDatabaseError(`[FileDatabase] ${errors.join(\"; \")}`);\n }\n\n let 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 private async setCurrentVersion(version: string): Promise<void> {\n this.currentVersion = version;\n this.currentVersionFolder = await ensurePath(this.getDestinationPath(), version);\n }\n\n /**\n * Create a new version folder with comprehensive timestamp logic\n * Only works in versioned mode\n */\n private async makeNewVersion(): Promise<string> {\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 let versionName: string;\n\n if (existingVersions.length > 0) {\n // Find the maximum timestamp among all existing versions\n const maxTimestamp = existingVersions.reduce((max, version) => {\n const versionDate = new Date(version.replace(\"Z\", \"\"));\n const maxDate = new Date(max.replace(\"Z\", \"\"));\n return versionDate > maxDate ? version : max;\n });\n\n // Increment the maximum timestamp by 1 second\n const maxDate = new Date(maxTimestamp.replace(\"Z\", \"\"));\n const nextDate = new Date(maxDate.getTime() + 1000);\n versionName = nextDate.toISOString().split(\".\")[0] + \"Z\";\n } else {\n // No existing versions, use current timestamp\n const now = new Date();\n versionName = now.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.debug?.(`[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(): Promise<string[]> {\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(): Promise<string | null> {\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(): Promise<boolean> {\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(): Promise<{\n versioned: boolean;\n hasMetadata: boolean;\n dataType: DataType | null;\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 private async loadMetadataJson(version: string): Promise<VersionMetadata | null> {\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 as Error).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 private async figureMetadataFromVersionFiles(version: string): Promise<VersionMetadata> {\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: DataType | null = 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: 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: FileEntry = {\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 as 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 private async buildMetadataOptimized(version: string): Promise<VersionMetadata> {\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: any;\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 private async figureMetadata(version: string, useOptimized: boolean = true): Promise<VersionMetadata> {\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 private async loadVersionMetadata(version: string): Promise<VersionMetadata> {\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 private async saveVersionMetadata(metadata?: VersionMetadata): Promise<void> {\n if (!this.useMetadata) {\n return;\n }\n\n const metadataToSave = metadata || this.metadata;\n let metadataFile: string;\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 private makeNewFile(): void {\n this.currentFileNumber = (this.currentFileNumber || 0) + 1;\n\n const dataType = this.metadata.dataType || \"json-array\";\n const fileEntry: 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.debug?.(`[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 */\n private figureOutDataAndFileToWrite(data: any): WriteContext {\n let dataToWrite: any;\n let dataLeftOver: any[] | null;\n\n const lastFile = this.metadata.files[this.metadata.files.length - 1];\n const lastFileRecordsCount = lastFile.recordsCount;\n\n if (Array.isArray(data)) {\n // For arrays, handle pagination\n 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 } 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 }\n this.lastFileData = dataToWrite;\n } else {\n // For non-arrays, write as-is\n dataToWrite = data;\n dataLeftOver = null;\n }\n\n const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;\n\n this.logger.debug?.(\n `[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, 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 private calculateFileSynopsis(data: any, fileIndex: number = this.metadata.files.length - 1): void {\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 private calculateVersionSynopsis(): void {\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 private updateMetadata(dataToWrite: any, fileName?: string): void {\n let currentFile: FileEntry;\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 // 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.debug?.(\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 private async safeWrite(filePath: string, data: any): Promise<void> {\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.debug?.(`[FileDatabase] Wrote ${bytesToHumanReadable(requiredBytes)} to ${filePath}`);\n } catch (error) {\n throw new FileDatabaseError(`Failed to write file ${filePath}: ${(error as 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 private async prepare({ write, read, version }: { write?: boolean; read?: boolean; version?: string }): Promise<void> {\n if (write) {\n if (this.versioned) {\n // Versioned mode\n if (this.currentVersion === null) {\n await this.makeNewVersion();\n this.metadata = this.getDefaultMetadata();\n this.metadata.version = this.currentVersion;\n this.makeNewFile();\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 }\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 } catch (e) {\n this.metadata = this.getDefaultMetadata();\n }\n } else {\n this.metadata = this.getDefaultMetadata();\n this.makeNewFile();\n }\n } else {\n // No metadata mode - just create default metadata\n this.metadata = this.getDefaultMetadata();\n this.makeNewFile();\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 }\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 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 } catch (e) {\n throw new FileDatabaseError(`Failed to read metadata: ${(e as Error).message}`);\n }\n } else {\n throw new FileDatabaseError(\"[FileDatabase] No metadata found in non-versioned mode\");\n }\n } else {\n // Figure metadata from files\n this.metadata = await this.figureMetadataFromVersionFiles('');\n }\n }\n }\n }\n\n /**\n * Write data to the file database\n */\n async write(data: any, options: WriteOptions = {}): Promise<void> {\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\n await this.prepare({ write: true });\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 this.makeNewFile();\n }\n\n let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data);\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);\n\n // Handle pagination for remaining data (arrays only)\n while (dataLeftOver && dataLeftOver.length > 0) {\n const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);\n await this.safeWrite(path.join(destPath, writeContext.fileName), writeContext.dataToWrite);\n this.updateMetadata(writeContext.dataToWrite, writeContext.fileName);\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: ReadOptions = {}): Promise<any> {\n const { version, nextPage = false, pageSize } = options;\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 as Error).message}`);\n }\n }\n\n // Handle paginated data (JSON arrays)\n let effectivePageSize: number;\n\n if (nextPage && this.hasReadFirstPage) {\n // Move to next page\n effectivePageSize = pageSize || this.pageSize;\n this.currentRecord += effectivePageSize;\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: any[] = [];\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\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 const rawData = await fs.promises.readFile(filePath, \"utf8\");\n const fileData = deserializeData(rawData, this.metadata.dataType!);\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 as Error).message}`);\n }\n }\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: number): void {\n this.currentRecord = startRecord - 1;\n this.hasReadFirstPage = false;\n }\n\n /**\n * Reset read pagination state\n */\n resetPagination(): void {\n this.currentRecord = 0;\n this.hasReadFirstPage = false;\n }\n\n /**\n * Set file-level synopsis calculation function\n */\n setFileSynopsisFunction(fn: FileSynopsisFunction): void {\n this.fileSynopsisFunction = fn;\n }\n\n /**\n * Set version-level synopsis calculation function\n */\n setVersionSynopsisFunction(fn: VersionSynopsisFunction): void {\n this.versionSynopsisFunction = fn;\n }\n\n /**\n * Get current version name\n */\n getCurrentVersion(): string | null {\n return this.currentVersion;\n }\n\n /**\n * Get current metadata\n */\n getMetadata(): VersionMetadata {\n return { ...this.metadata };\n }\n}\n\n// Export types\nexport type {\n FileDatabaseConfig,\n VersionMetadata,\n FileEntry,\n ReadOptions,\n WriteOptions,\n FileSynopsisFunction,\n VersionSynopsisFunction,\n DataType,\n StorageMode,\n CatalogEntry,\n} from \"./types.js\";\n\n// Export synopsis functions\nexport { defaultFileSynopsisFunction, defaultVersionSynopsisFunction } from \"./synopsis-functions.js\";\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: string): number | null {\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 * 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\";\n\n/**\n * Ensure a directory path exists, creating it if necessary\n * Returns the absolute path\n */\nexport async function ensurePath(...pathParts: string[]): Promise<string> {\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: string[]): string {\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: string): string {\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 * 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: number): string {\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: string): number {\n const units: Record<string, number> = {\n \"B\": 1,\n \"KB\": 1024,\n \"MB\": 1024 * 1024,\n \"GB\": 1024 * 1024 * 1024,\n \"TB\": 1024 * 1024 * 1024 * 1024,\n \"PB\": 1024 * 1024 * 1024 * 1024 * 1024,\n };\n \n const match = humanString.trim().match(/^([\\d.]+)\\s*([A-Z]+)$/i);\n if (!match) {\n throw new Error(`Invalid format: ${humanString}. Expected format like \"2MB\" or \"1.5 GB\"`);\n }\n \n const value = parseFloat(match[1]);\n const unit = match[2].toUpperCase();\n \n if (!units[unit]) {\n throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(\", \")}`);\n }\n \n return Math.round(value * units[unit]);\n}\n\n","/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\nexport interface DateFormatOptions {\n timezone?: \"UTC\" | \"user\";\n format?: \"iso\" | \"iso-date\" | \"iso-time\" | \"human\";\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: Date | string | number | undefined, options: DateFormatOptions = {}): string {\n if (value === undefined || value === null) {\n return \"\";\n }\n\n const { timezone = \"UTC\", format = \"iso\" } = options;\n \n let date: 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: Date | string | number | undefined): string {\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(): string {\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: string): Date {\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: Date | string,\n end: Date | string\n): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\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: string): boolean {\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: string[] = []): string {\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 * FileStore Serializers\n * \n * Data type detection and serialization/deserialization utilities\n */\n\nimport type { DataType } from \"./types.js\";\n\n/**\n * Detect the data type of a given value\n */\nexport function detectDataType(data: any): DataType {\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: any): string {\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: string, dataType: DataType): any {\n if (dataType === \"json-array\" || dataType === \"json-object\") {\n return JSON.parse(rawData);\n } else {\n // For text and XML, return as-is\n return rawData;\n }\n}\n\n","/**\n * Synopsis Functions - Predefined synopsis calculations for FileDatabase\n * \n * These functions analyze file and version data to generate useful summaries\n * and statistics that can be stored in metadata.\n */\n\nimport type { FileEntry, VersionMetadata } from \"./types.js\";\n\n/**\n * Default file-level synopsis function\n * Extracts min/max ModificationTimestamp and StandardStatus counts from records\n */\nexport function defaultFileSynopsisFunction(fileEntry: FileEntry, data: any): FileEntry {\n if (!Array.isArray(data) || data.length === 0) {\n return { ...fileEntry };\n }\n\n const timestamps: number[] = [];\n const statusCounts: Record<string, number> = {};\n\n for (const item of data) {\n let ts: number | null = null;\n let status: string | null = null;\n\n for (const [key, value] of Object.entries(item)) {\n const k = key.toLowerCase();\n if (k === \"modificationtimestamp\") {\n ts = new Date(value as string).getTime();\n }\n if (k === \"standardstatus\") {\n status = value as string;\n }\n }\n\n if (ts && !isNaN(ts)) {\n timestamps.push(ts);\n }\n\n if (status !== null && status !== undefined) {\n statusCounts[status] = (statusCounts[status] || 0) + 1;\n }\n }\n\n const result: FileEntry = { ...fileEntry };\n\n if (timestamps.length) {\n result.minModificationTimestamp = new Date(Math.min(...timestamps)).toISOString();\n result.maxModificationTimestamp = new Date(Math.max(...timestamps)).toISOString();\n }\n\n if (Object.keys(statusCounts).length) {\n result.StandardStatuses = statusCounts;\n }\n\n return result;\n}\n\n/**\n * Default version-level synopsis function\n * Aggregates min/max timestamps and status counts across all files in a version\n */\nexport function defaultVersionSynopsisFunction(metadata: VersionMetadata): VersionMetadata {\n if (!metadata?.files || !Array.isArray(metadata.files)) {\n return metadata;\n }\n\n const timestamps: number[] = [];\n const statusCounts: Record<string, number> = {};\n\n for (const file of metadata.files) {\n // Collect timestamps\n if ((file as any).minModificationTimestamp) {\n const minTs = new Date((file as any).minModificationTimestamp).getTime();\n if (!isNaN(minTs)) timestamps.push(minTs);\n }\n if ((file as any).maxModificationTimestamp) {\n const maxTs = new Date((file as any).maxModificationTimestamp).getTime();\n if (!isNaN(maxTs)) timestamps.push(maxTs);\n }\n\n // Aggregate statuses\n if ((file as any).StandardStatuses && typeof (file as any).StandardStatuses === \"object\") {\n for (const [status, count] of Object.entries((file as any).StandardStatuses)) {\n statusCounts[status] = (statusCounts[status] || 0) + (count as number);\n }\n }\n }\n\n const result = { ...metadata };\n\n if (timestamps.length) {\n (result as any).minModificationTimestamp = new Date(Math.min(...timestamps)).toISOString();\n (result as any).maxModificationTimestamp = new Date(Math.max(...timestamps)).toISOString();\n }\n\n if (Object.keys(statusCounts).length > 0) {\n (result as any).StandardStatuses = statusCounts;\n }\n\n return result;\n}\n\n"],"mappings":"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","names":["config","relativeMatch","Joi","import_react","import_ink","h","import_react","import_ink","h","React","config","resolve","instance","h","import_react","import_ink","h","path","config","import_fs","import_path","import_fs","import_path","fs","path","import_fs","import_path","path","fs","config","path","maxDate","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/args/index.ts","../src/params/index.ts","../src/errors.ts","../src/params/custom-types.ts","../src/screen/screens.ts","../src/screen/components.ts","../src/screen/list-components.ts","../src/screen/ui-elements.ts","../src/screen/utils.ts","../src/screen/footer-builder.ts","../src/filedatabase/index.ts","../src/utils/os-utils.ts","../src/utils/fs-utils.ts","../src/utils/format-utils.ts","../src/utils/date-utils.ts","../src/filedatabase/serializers.ts","../src/filedatabase/synopsis-functions.ts","../src/db/index.ts"],"sourcesContent":["// Main exports for @nmakarov/cli-toolkit\nexport * from \"./args.js\";\nexport * from \"./params.js\";\nexport * from \"./screen.js\";\nexport * from \"./filedatabase.js\";\nexport * from \"./db.js\";\n","// Arguments discovery and parsing module\n// This module provides utilities for parsing CLI arguments and detecting flags\n\nimport { readFileSync, existsSync } from \"fs\";\nimport { resolve, dirname, basename, extname, join, isAbsolute } from \"path\";\nimport { config } from \"dotenv\";\n\nexport interface ArgsConfig {\n args?: string[]; // Default: process.argv.slice(2)\n aliases?: Record<string, string>; // Short → long mapping\n overrides?: Record<string, any>; // Highest precedence\n defaults?: Record<string, any>; // Lowest precedence\n prefixes?: string[]; // Negative flag prefixes (default: [\"not\", \"no\"])\n}\n\nexport interface ParsedArgs {\n command: string;\n flags: Record<string, boolean>;\n options: Record<string, string>;\n usedKeys: string[];\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 private args: Record<string, any> = {};\n private flags: Record<string, boolean> = {};\n private options: Record<string, string> = {};\n private commands: string[] = [];\n private usedKeys: Set<string> = new Set();\n private aliases: Record<string, string> = {};\n private overrides: Record<string, any> = {};\n private defaults: Record<string, any> = {};\n private prefixes: string[] = [];\n private nots: string[] = [];\n private configValues: Record<string, any> = {};\n private configsLoaded: string[] = [];\n private env: string = \"local\";\n\n constructor(config: ArgsConfig = {}) {\n // Set up configuration\n this.aliases = config.aliases || {};\n this.overrides = config.overrides || {};\n this.defaults = config.defaults || {};\n this.prefixes = config.prefixes || [\"not\", \"no\"];\n\n // Parse arguments first to get environment\n const args = config.args || process.argv.slice(2);\n this.parseArgs(args);\n\n // Set environment from parsed args\n this.env = this.get(\"env\")?.toLowerCase() || \"local\";\n\n // Load .env file\n this.loadDotEnv();\n\n // Load configuration files\n this.loadConfigFiles();\n\n // Check for conflicts (short + long form of same option)\n this.checkConflicts();\n }\n\n /**\n * Parse command line arguments\n */\n private parseArgs(args: string[]): void {\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 private parseLongOption(arg: string): [string, string | boolean] {\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 private parseShortOption(arg: string, args: string[], index: number): { consumed: number } {\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 private parseValue(value: string): string {\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 private setValue(key: string, value: string | boolean): void {\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 private checkConflicts(): void {\n const conflicts: string[] = [];\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: string): any {\n const resolvedKey = this.aliases[key] || key;\n this.usedKeys.add(resolvedKey);\n\n // Precedence order: overrides > CLI args > config files > env vars > defaults\n if (this.overrides[resolvedKey] !== undefined) {\n return this.overrides[resolvedKey];\n }\n\n // Case-insensitive lookup for CLI args (like legacy)\n const lcKey = resolvedKey.toLowerCase();\n\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 // Config file values (case-sensitive)\n if (this.configValues[resolvedKey] !== undefined) {\n return this.configValues[resolvedKey];\n }\n\n // Environment variable (convert key to ENV_VAR format)\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 const envKeyFound = Object.keys(process.env).find((k) => k.toUpperCase() === envKey);\n\n if (envSpecificKey) {\n return process.env[envSpecificKey];\n } else if (envKeyFound) {\n return process.env[envKeyFound];\n }\n\n // Default value\n if (this.defaults[resolvedKey] !== undefined) {\n return this.defaults[resolvedKey];\n }\n\n // NODE_ENV fallback for 'env' key (like legacy)\n if (resolvedKey === \"env\" && process.env.NODE_ENV !== undefined) {\n return process.env.NODE_ENV;\n }\n\n return undefined;\n }\n\n /**\n * Set a value (for testing/internal use)\n */\n set(key: string, value: any): void {\n this.args[key] = value;\n }\n\n /**\n * Check if a command exists (case-insensitive)\n */\n hasCommand(cmd: string): boolean {\n return this.commands.some((command) => command.toLowerCase() === cmd.toLowerCase());\n }\n\n /**\n * Get all commands\n */\n getCommands(): string[] {\n return [...this.commands];\n }\n\n /**\n * Get used keys (as array)\n */\n getUsed(): string[] {\n return Array.from(this.usedKeys);\n }\n\n /**\n * Get unused keys (as array)\n */\n getUnused(): string[] {\n const unused: string[] = [];\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 */\n private toEnvKey(key: string): string {\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 private loadDotEnv(): void {\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 // Try environment-specific .env file first (e.g., .env.local, .env.production)\n let dotEnvPathFile: string | null = null;\n\n const envSpecificFile = `.env.${this.env}`;\n const envSpecificPath = resolve(dotEnvPath, envSpecificFile);\n if (existsSync(envSpecificPath)) {\n dotEnvPathFile = envSpecificPath;\n }\n\n // If no environment-specific file found in current directory, try examples folder\n if (!dotEnvPathFile && !this.get(\"dotEnvPath\")) {\n const examplesPath = resolve(dotEnvPath, \"examples\");\n const examplesEnvSpecificPath = resolve(examplesPath, envSpecificFile);\n if (existsSync(examplesEnvSpecificPath)) {\n dotEnvPathFile = examplesEnvSpecificPath;\n }\n }\n\n // If no environment-specific file found, try default .env\n if (!dotEnvPathFile) {\n dotEnvPathFile = resolve(dotEnvPath, dotEnvFile);\n\n // If .env file doesn't exist in current directory, try examples folder (for our examples)\n if (!existsSync(dotEnvPathFile)) {\n if (!this.get(\"dotEnvPath\")) {\n // Try examples folder first (for our examples)\n const examplesPath = resolve(dotEnvPath, \"examples\");\n const examplesEnvFile = resolve(examplesPath, dotEnvFile);\n if (existsSync(examplesEnvFile)) {\n dotEnvPathFile = examplesEnvFile;\n } else {\n // Try parent directory (like legacy)\n dotEnvPathFile = resolve(dotEnvPath, \"..\", dotEnvFile);\n }\n }\n }\n }\n\n // Load .env file if it exists\n if (dotEnvPathFile && existsSync(dotEnvPathFile)) {\n config({ path: dotEnvPathFile, quiet: true });\n }\n }\n\n /**\n * Load configuration files\n */\n private loadConfigFiles(): void {\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 private resolveFileWithPath(\n optConfigFilePath: string | undefined,\n cfgFile: string,\n env?: string\n ): string {\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 private splitPath(filePath: string): { basePathWithName: string; extension: string } {\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 private requireConfigFile(filePath: string): any {\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(): ParsedArgs {\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: string | string[]): void {\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: Args | null = null;\n\n/**\n * Initialize Args instance (singleton pattern)\n */\nexport function init(args?: string[]): Args {\n instance = new Args({ args });\n return instance;\n}\n\n/**\n * Get the current Args instance (singleton pattern)\n */\nexport function getArgsInstance(): Args | null {\n return instance;\n}\n\n\n","import Joi from \"joi\";\nimport { ParamError } from \"../errors\";\nimport { joiEdateType, joiStringArrayType } from \"./custom-types\";\n\n/**\n * Parameter definition types\n */\nexport type ParamDefinition = \n | string \n | Joi.Schema \n | { \n type?: string | Joi.Schema; \n values?: any[]; \n [key: string]: any; \n };\n\nexport type ParamGetter = (key: string, definition?: any) => any;\nexport type ParamSetter = (key: string, value: any) => boolean;\n\n/**\n * Args instance interface\n */\nexport interface ArgsInstance {\n get(key: string): any;\n}\n\n/**\n * Params constructor options\n */\nexport interface ParamsOptions {\n [key: string]: any;\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 private params: Record<string, any> = {};\n private definitions: Record<string, any> = {};\n private args: ArgsInstance;\n private paramSetters: ParamSetter[] = [];\n private paramGetters: ParamGetter[] = [];\n\n constructor({ args }: { args: ArgsInstance }, opts: ParamsOptions = {}) {\n this.args = args;\n\n for (const [k, v] of Object.entries(opts)) {\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 * Assign a parameter definition\n */\n assignDefinition(key: string, definition?: ParamDefinition): any {\n if (this.definitions[key] && !definition) {\n return this.definitions[key];\n }\n\n let type: Joi.Schema;\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: string): Joi.Schema {\n let type: Joi.Schema;\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 type = type.default(defValObj.value);\n } else if (str.match(/required/)) {\n type = type.required();\n }\n\n return type;\n }\n\n /**\n * Validate a value against a definition\n */\n validate(key: string, val: any, def: any): any {\n // Pass current params as context to support cross-parameter references (e.g., @startTime+2h)\n const { value, error } = def.type.validate(val, { context: { params: this.params } });\n if (error) {\n const errs = error.details.map((el: any) => 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: string, definition?: ParamDefinition): any {\n const def = this.assignDefinition(key, definition);\n let valFromGetters: any = undefined;\n \n if (def.volatile || true) {\n valFromGetters = this.runAllRegisteredGetters(key);\n }\n \n const valFromArgs = this.args.get(key);\n const valFromParams = this.params[key];\n\n const res = valFromGetters ? this.validate(key, valFromGetters, def) :\n valFromArgs ? this.validate(key, valFromArgs, def) :\n this.validate(key, valFromParams, def);\n\n if (res !== undefined && def.values && !def.values.includes(res)) {\n throw new ParamError(`key ${key} should be one of ${def.values}`);\n }\n return res;\n }\n\n /**\n * Set a parameter value with validation\n */\n set(key: string, val: any, definition?: ParamDefinition): void {\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 const def = 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\n * Processes parameters left-to-right to support cross-parameter references\n */\n getAll(defs: Record<string, ParamDefinition>): Record<string, any> {\n const res: Record<string, any> = {};\n for (const [k, def] of Object.entries(defs)) {\n const value = this.get(k, def);\n res[k] = value;\n // Store validated value in params so subsequent params can reference it\n if (value !== undefined) {\n this.params[k] = value;\n }\n }\n return res;\n }\n\n /**\n * Run all registered getters for a key\n */\n runAllRegisteredGetters(key: string): any {\n let val: any = null;\n for (const getter of this.paramGetters) {\n val = getter(key, this.definitions[key]);\n if (val !== undefined) {\n break;\n }\n }\n return val;\n }\n\n /**\n * Run all registered setters for a key\n */\n runAllRegisteredSetters(key: string, value: any): boolean {\n let setterUsed: boolean = 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: ParamGetter): void {\n this.paramGetters.push(fn);\n }\n\n /**\n * Register a parameter setter\n */\n registerParamSetter(fn: ParamSetter): void {\n this.paramSetters.push(fn);\n }\n}\n\n// Singleton instance\nlet paramsInstance: Params | null = null;\n\n/**\n * Initialize the singleton Params instance\n */\nexport const init = (fns: { args: ArgsInstance }, opts: ParamsOptions = {}): Params => {\n paramsInstance = new Params(fns, opts);\n return paramsInstance;\n};\n\n/**\n * Get the current singleton Params instance\n */\nexport const getParamsInstance = (): Params | null => paramsInstance;\n\n// Export custom types for external use\nexport { joiEdateType, joiStringArrayType };\n\n\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\n","import Joi from \"joi\";\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: any, helpers: Joi.CustomHelpers): string => {\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 as any).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: Date;\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: number, unit: string, sign: string): number {\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: string) => (value: any, helpers: Joi.CustomHelpers): any[] => {\n if (value === undefined || typeof value === \"function\") {\n return [];\n }\n \n const arr = value.split(/,\\s*/).map((el: string) => {\n if (type === \"number\") {\n const v = parseInt(el, 10);\n if (isNaN(v)) {\n throw new ParamError(`array element \"${el}\" should be numeric`);\n }\n return v;\n } else if (type === \"boolean\") {\n const v = el.match(/true|t|yes|1/i) ? true :\n el.match(/false|f|no|0/i) ? false : null;\n if (v === null) {\n throw new ParamError(`array element \"${el}\" should be boolean`);\n }\n return v;\n } else if (type === \"string\") {\n return el;\n } else {\n throw new ParamError(`unknown type \"${type}\" for array elements`);\n }\n });\n \n return arr;\n};\n\n","/**\n * Screen System - Action-based architecture\n */\n\nimport React, { useState, useRef, useEffect, createElement as h } from \"react\";\nimport { render, useInput, Box, Text } from \"ink\";\nimport { ScreenContainer, ScreenRow, ScreenTitle, ScreenDivider, ScreenFooter } from \"./components.js\";\nimport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\n\n// Types\ninterface KeyBinding {\n key: string;\n caption: string | (() => string | JSX.Element);\n action: string;\n order?: number;\n protected?: boolean;\n enabled?: boolean;\n condition?: (ctx: ScreenContext) => boolean;\n}\n\ninterface BindingGroup {\n keys: string[];\n caption: string;\n order: number;\n}\n\ninterface ActionPayload {\n input: string;\n key: any;\n binding: KeyBinding;\n}\n\ninterface ScreenContext {\n setAction: (actionName: string, handlerFn: (payload?: ActionPayload) => void | any) => void;\n setKeyBinding: (bindingOrBindings: KeyBinding | KeyBinding[]) => void;\n updateKeyBinding: (keyName: string, updates: Partial<KeyBinding>) => void;\n removeKeyBinding: (keyName: string) => void;\n addFooter: (item: string | JSX.Element) => void;\n clearFooter: () => void;\n setFooter: (items: string | string[] | JSX.Element | JSX.Element[]) => void;\n update: () => void;\n goBack: () => void;\n close: (result: any) => void;\n parentData: any;\n}\n\ninterface ShowScreenConfig {\n title: string;\n onRender: (ctx: ScreenContext) => JSX.Element;\n parentData?: any;\n}\n\ninterface ShowListScreenConfig {\n title: string;\n items: Array<{ name: string; value: any }>;\n onSelect?: (value: any, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n renderItem?: (item: { name: string; value: any }, isSelected: boolean, displayIndex: number) => JSX.Element;\n getTitle?: (item: { name: string; value: any }) => string;\n sortable?: boolean;\n maxHeight?: number;\n sortHighlightStyle?: {\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n };\n selectionMarker?: string; // Customizable selection marker, default: \" \"\n}\n\ninterface ShowMultiColumnListScreenConfig {\n title: string;\n items: string[];\n onSelect?: (item: string, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n}\n\ninterface ShowMultiColumnListWithPreviewScreenConfig {\n title: string;\n items: string[];\n getPreviewContent?: (item: string) => string | JSX.Element | Record<string, any>;\n onSelect?: (item: string, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n}\n\n/**\n * Group key bindings by caption for footer display\n */\nexport function groupKeyBindings(bindings: KeyBinding[]): BindingGroup[] {\n const groups: Record<string, BindingGroup> = {};\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(binding.key);\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: KeyBinding[], mode: string = \"long\"): (string | JSX.Element)[] {\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: (string | JSX.Element)[] = [];\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 as JSX.Element);\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: string[]): string {\n const keyMap: Record<string, string> = {\n \"escape\": \"esc\",\n \"leftArrow\": \"←\",\n \"rightArrow\": \"→\",\n \"upArrow\": \"↑\",\n \"downArrow\": \"↓\",\n \"return\": \"enter\"\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: ShowScreenConfig): Promise<any> {\n const {\n title,\n onRender,\n parentData = {}\n } = config;\n\n\n return new Promise((resolve) => {\n let instance: any;\n\n // Persistent collections (closure variables survive re-renders)\n const keyBindings: KeyBinding[] = [];\n const actions: Record<string, (payload?: ActionPayload) => void | any> = {};\n const customFooterItems: (string | JSX.Element)[] = [];\n let renderResult: JSX.Element | null = null;\n let initialized = false;\n\n const Screen = (): JSX.Element => {\n const [updateCounter, setUpdateCounter] = useState(0);\n\n // Initialize defaults only once\n if (!initialized) {\n const defaultBindings: KeyBinding[] = [\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: ScreenContext = {\n setAction: (actionName: string, handlerFn: (payload?: ActionPayload) => void | any) => {\n actions[actionName] = handlerFn;\n },\n\n setKeyBinding: (bindingOrBindings: KeyBinding | KeyBinding[]) => {\n // Support both single object and array\n const bindingsToSet = Array.isArray(bindingOrBindings) ? bindingOrBindings : [bindingOrBindings];\n\n bindingsToSet.forEach(binding => {\n // Check if key already exists\n const existingIndex = keyBindings.findIndex(b => b.key === binding.key);\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: string, updates: Partial<KeyBinding>) => {\n const index = keyBindings.findIndex(b => b.key === keyName);\n if (index >= 0) {\n // Update only specified properties\n keyBindings[index] = {\n ...keyBindings[index],\n ...updates\n };\n }\n },\n\n removeKeyBinding: (keyName: string) => {\n const index = keyBindings.findIndex(b => b.key === keyName);\n if (index >= 0) {\n if (keyBindings[index].protected) {\n console.warn(`Cannot remove protected key: ${keyName}`);\n return;\n }\n keyBindings.splice(index, 1);\n }\n },\n\n addFooter: (item: string | JSX.Element) => {\n customFooterItems.push(item);\n },\n\n clearFooter: () => {\n customFooterItems.length = 0;\n },\n\n setFooter: (items: string | string[] | JSX.Element | JSX.Element[]) => {\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: any) => {\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: string, key: any) => {\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: KeyBinding | null = null;\n\n for (const binding of keyBindings) {\n let keyMatches = false;\n\n // Check key match\n if (key[binding.key]) {\n keyMatches = true;\n } else if (input === binding.key) {\n keyMatches = true;\n }\n\n if (keyMatches) {\n // Check if binding is enabled\n if (binding.enabled === false) {\n continue;\n }\n\n // Check condition if present\n if (binding.condition && !binding.condition(context)) {\n continue;\n }\n\n matchedBinding = binding;\n break;\n }\n }\n\n if (matchedBinding && actions[matchedBinding.action]) {\n // Execute action\n const actionResult = 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: (string | JSX.Element | (string | JSX.Element)[])[] = [];\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: (string | JSX.Element)[] = [];\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: any) => {\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: ShowListScreenConfig): Promise<any> {\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: ShowMultiColumnListScreenConfig): Promise<any> {\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: ShowMultiColumnListWithPreviewScreenConfig): Promise<any> {\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 * Core screen layout components\n */\n\nimport React, { 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: number | null = null): number {\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\nexport interface ScreenContainerProps {\n children: React.ReactNode;\n}\n\nexport interface ScreenRowProps {\n children: React.ReactNode;\n}\n\nexport interface ScreenTitleProps {\n text: string;\n}\n\nexport interface ScreenDividerProps {\n width?: number;\n}\n\nexport interface ScreenBodyProps {\n children: React.ReactNode;\n alignItems?: \"flex-start\" | \"center\" | \"flex-end\";\n}\n\nexport interface ScreenFooterProps {\n lines: (string | JSX.Element)[];\n textStyle?: {\n color?: string;\n dimColor?: boolean;\n bold?: boolean;\n };\n}\n\n/**\n * Screen Container - uses Ink's built-in borderStyle for proper text wrapping\n */\nexport function ScreenContainer({ children }: ScreenContainerProps): JSX.Element {\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 }: ScreenRowProps): JSX.Element {\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 }: ScreenTitleProps): JSX.Element {\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 }: ScreenDividerProps): JSX.Element {\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\" }: ScreenBodyProps): JSX.Element {\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 }: ScreenFooterProps): JSX.Element {\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: (string | JSX.Element | (string | JSX.Element)[])[], keyPrefix: string = \"\"): JSX.Element[] => {\n const result: JSX.Element[] = [];\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 as JSX.Element;\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 * 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\";\n\nconst h = createElement;\n\n// TODO: Define proper context type interface\ninterface ScreenContext {\n setAction: (name: string, handler: () => void) => void;\n setKeyBinding: (bindings: KeyBinding | KeyBinding[]) => void;\n addFooter: (message: string) => void;\n setFooter: (items: string | string[]) => void;\n goBack: () => void;\n update: () => void;\n}\n\ninterface KeyBinding {\n key: string;\n caption: string;\n action: string;\n order: number;\n}\n\ninterface ListItem {\n name: string;\n value: any;\n}\n\ninterface MultiColumnListComponentProps {\n items: string[];\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n}\n\ninterface MultiColumnListWithPreviewComponentProps {\n items: string[];\n getPreviewContent?: (item: string) => string | JSX.Element | Record<string, any>;\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n}\n\ninterface ListComponentProps {\n items: ListItem[];\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n renderItem?: (item: ListItem, isSelected: boolean, displayIndex: number) => JSX.Element;\n getTitle?: (item: ListItem) => string;\n sortable?: boolean;\n maxHeight?: number;\n sortHighlightStyle?: {\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n };\n selectionMarker?: string; // Customizable selection marker, default: \" \"\n}\n\n/**\n * Multi-column list component\n * Handles its own navigation, actions, and key bindings\n */\nexport function MultiColumnListComponent({ items, ctx, selectedIndexRef }: MultiColumnListComponentProps): JSX.Element {\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: JSX.Element[] = [];\n for (let row = 0; row < itemsPerColumn; row++) {\n const cols: JSX.Element[] = [];\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}: MultiColumnListWithPreviewComponentProps): JSX.Element {\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: JSX.Element[] = [];\n for (let row = 0; row < itemsPerColumn; row++) {\n const cols: JSX.Element[] = [];\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: JSX.Element[] = [];\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 = \" \" }: ListComponentProps): JSX.Element {\n const [, forceUpdate] = useState({});\n const [sortOrder, setSortOrder] = useState<\"none\" | \"asc\" | \"desc\">(\"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\n // Default getTitle - returns item if string, otherwise item.title\n const defaultGetTitle = (item: ListItem): string => {\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 // 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 // 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 \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 // Force update to trigger re-render with new selected index\n forceUpdate({});\n });\n\n ctx.setAction(\"moveDown\", () => {\n const currentItems = 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 maxIndex = currentItems.length - 1;\n const newIndex = Math.min(maxIndex, selectedIndexRef.current + 1);\n selectedIndexRef.current = 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 // Force update to trigger re-render with new selected index\n forceUpdate({});\n });\n\n // Add scroll actions for arrow clicks\n ctx.setAction(\"scrollUp\", () => {\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const newScrollOffset = Math.max(0, currentScrollOffset - 1);\n setScrollOffset(newScrollOffset);\n forceUpdate({});\n });\n\n ctx.setAction(\"scrollDown\", () => {\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const newScrollOffset = Math.min(currentMaxScrollOffset, currentScrollOffset + 1);\n setScrollOffset(newScrollOffset);\n forceUpdate({});\n });\n\n // Set up sort action if sortable\n if (sortable) {\n ctx.setAction(\"toggleSort\", () => {\n const nextSort: \"none\" | \"asc\" | \"desc\" = \n sortOrder === \"none\" ? \"asc\" : \n sortOrder === \"asc\" ? \"desc\" : \"none\";\n \n // Store the currently selected item from the current display items\n const currentSelectedItem = displayItems[selectedIndexRef.current];\n \n setSortOrder(nextSort);\n \n // Calculate the new sorted items\n const newSortedItems = nextSort !== \"none\" ? [...items].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 }) : items;\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 // Update key bindings with sort\n ctx.setKeyBinding([\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 },\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 // No sorting\n ctx.setKeyBinding([\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n ]);\n }\n }, [sortOrder, sortable]);\n\n const selectedIndex = selectedIndexRef.current;\n \n\n // Default renderer with static scroll indicators for debugging\n const defaultRenderItem = (item: ListItem, isSelected: boolean, displayIndex: number, actualIndex: number) => {\n const isFirstVisible = displayIndex === 0;\n const isLastVisible = displayIndex === visibleItems.length - 1;\n \n // Build prefix with arrows and selection marker\n let arrowPrefix = \"\";\n let selectionPrefix = \"\";\n \n // Only show arrows when scrolling is actually needed and available\n if (isFirstVisible && canScrollUp) {\n arrowPrefix = \"↑ \";\n } else if (isLastVisible && canScrollDown) {\n arrowPrefix = \"↓ \";\n } else {\n // No arrow, but reserve the same space\n arrowPrefix = \" \";\n }\n \n // Always reserve space for selection marker (pad with spaces if not selected)\n if (isSelected) {\n selectionPrefix = selectionMarker;\n } else {\n // Pad with spaces to match the length of the selection marker\n selectionPrefix = \" \".repeat(selectionMarker.length);\n }\n \n return h(Box, { flexDirection: \"row\" },\n // Arrow (clickable if functional, not highlighted)\n h(Text, { \n key: `arrow-${actualIndex}`,\n color: \"white\"\n }, arrowPrefix),\n // Selection marker space (always same width, not highlighted) \n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n // Item name (highlighted if selected)\n h(Text, {\n key: `name-${actualIndex}`,\n color: isSelected ? \"black\" : \"white\",\n backgroundColor: isSelected ? \"cyan\" : undefined,\n bold: isSelected\n }, item.name)\n );\n };\n\n // Use custom renderer if provided, otherwise use default\n const itemRenderer = renderItem || defaultRenderItem;\n\n // Render visible menu items with scroll indicators\n return h(Box, { flexDirection: \"column\" },\n ...visibleItems.map((item, displayIndex) => {\n const actualIndex = clampedScrollOffset + displayIndex;\n const isSelected = actualIndex === selectedIndex;\n \n // If using custom renderer, wrap it with scroll indicators\n if (renderItem) {\n const isFirstVisible = displayIndex === 0;\n const isLastVisible = displayIndex === visibleItems.length - 1;\n \n // Build prefix with arrows and selection marker\n let arrowPrefix = \"\";\n let selectionPrefix = \"\";\n \n // Only show arrows when scrolling is actually needed and available\n if (isFirstVisible && canScrollUp) {\n arrowPrefix = \"↑ \";\n } else if (isLastVisible && canScrollDown) {\n arrowPrefix = \"↓ \";\n } else {\n // No arrow, but reserve the same space\n arrowPrefix = \" \";\n }\n \n // Always reserve space for selection marker (pad with spaces if not selected)\n if (isSelected) {\n selectionPrefix = selectionMarker;\n } else {\n // Pad with spaces to match the length of the selection marker\n selectionPrefix = \" \".repeat(selectionMarker.length);\n }\n \n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: h(Box, { flexDirection: \"row\" },\n // Arrow (clickable if functional, not highlighted)\n h(Text, { \n key: `arrow-${actualIndex}`,\n color: \"white\"\n }, arrowPrefix),\n // Selection marker space (always same width, not highlighted) \n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n // Custom rendered content\n renderItem(item, isSelected, displayIndex)\n )\n });\n } else {\n // Use default renderer (which already includes scroll indicators)\n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: itemRenderer(item, isSelected, displayIndex, actualIndex)\n });\n }\n })\n );\n}\n","/**\n * Reusable UI elements for the screen system\n */\n\nimport React, { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\n\n// Types\nexport interface ListItemProps {\n children: React.ReactNode;\n isSelected?: boolean;\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n dimColor?: boolean;\n}\n\nexport interface TextBlockProps {\n text: string;\n color?: string;\n dimmed?: boolean;\n bold?: boolean;\n maxWidth?: number;\n}\n\nexport interface DividerProps {\n character?: string;\n width?: number;\n}\n\nexport interface GridCellProps {\n children: React.ReactNode;\n width?: number;\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n dimColor?: boolean;\n align?: \"left\" | \"center\" | \"right\";\n}\n\nexport interface InputFieldProps {\n prompt: string;\n value: string;\n onChange?: (value: string) => void;\n onSubmit?: (value: string) => void;\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}: ListItemProps): JSX.Element {\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 \n}: TextBlockProps): JSX.Element {\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 }: DividerProps): JSX.Element {\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}: GridCellProps): JSX.Element {\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, onSubmit }: InputFieldProps): JSX.Element {\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 * 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: string[]): string {\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: string[], suffix: string = \"\"): string {\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\ninterface FooterConfig {\n navigation?: string | string[];\n actions?: string | string[];\n info?: string | string[];\n escape?: string | string[];\n custom?: string | string[];\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: FooterConfig = {}): string[] {\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: string[] = [];\n\n // Build main help line (navigation + actions + escape)\n const mainParts: (string | string[])[] = [];\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: string | string[] | null = null): string[] => 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: number): string[] => 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: (): string[] => 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: (): string[] => buildFooter({\n escape: \"Esc to continue\"\n }),\n\n /**\n * Main menu footer (escape exits)\n */\n mainMenu: (): string[] => 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: boolean = false): string[] => {\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: string[] | null | undefined): string[] {\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: string[] = [];\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 * 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\";\nimport type {\n FileDatabaseConfig,\n VersionMetadata,\n FileEntry,\n ReadOptions,\n WriteOptions,\n WriteContext,\n FileSynopsisFunction,\n VersionSynopsisFunction,\n DataType,\n} from \"./types.js\";\nimport { ensurePath, generateVersionName, getFileExtension, getFreeDiskSpace, bytesToHumanReadable, isTimestampFolder } from \"./utils.js\";\nimport { detectDataType, serializeData, deserializeData } from \"./serializers.js\";\nimport { ParamError } from \"../errors.js\";\n\n/**\n * FileDatabase Error class\n */\nexport class FileDatabaseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\nexport class FileDatabase {\n private basePath: string;\n private namespace: string;\n private tableName: string | null = null;\n private versioned: boolean;\n private maxVersions: number;\n private pageSize: number;\n private useMetadata: boolean;\n private freeSpaceThreshold: number;\n private logger: any;\n\n // Current operation state\n private currentVersion: string | null = null;\n private currentVersionFolder: string | null = null;\n private currentFileNumber: number = 0;\n private currentRecord: number = 0;\n private hasReadFirstPage: boolean = false;\n private lastFileData: any = null;\n private metadata: VersionMetadata;\n\n // Synopsis calculation functions\n private fileSynopsisFunction: FileSynopsisFunction | null = null;\n private versionSynopsisFunction: VersionSynopsisFunction | null = null;\n\n constructor(config: FileDatabaseConfig) {\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 * Get default metadata structure\n */\n private getDefaultMetadata(): VersionMetadata {\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 private getDestinationPath(version?: string): string {\n const errors = [\"basePath\", \"namespace\", \"tableName\"]\n .filter(prop => !this[prop as keyof this])\n .map(prop => `${prop} is not set`);\n if (errors.length) {\n throw new FileDatabaseError(`[FileDatabase] ${errors.join(\"; \")}`);\n }\n\n let 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 private async setCurrentVersion(version: string): Promise<void> {\n this.currentVersion = version;\n this.currentVersionFolder = await ensurePath(this.getDestinationPath(), version);\n }\n\n /**\n * Create a new version folder with comprehensive timestamp logic\n * Only works in versioned mode\n */\n private async makeNewVersion(): Promise<string> {\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 let versionName: string;\n\n if (existingVersions.length > 0) {\n // Find the maximum timestamp among all existing versions\n const maxTimestamp = existingVersions.reduce((max, version) => {\n const versionDate = new Date(version.replace(\"Z\", \"\"));\n const maxDate = new Date(max.replace(\"Z\", \"\"));\n return versionDate > maxDate ? version : max;\n });\n\n // Increment the maximum timestamp by 1 second\n const maxDate = new Date(maxTimestamp.replace(\"Z\", \"\"));\n const nextDate = new Date(maxDate.getTime() + 1000);\n versionName = nextDate.toISOString().split(\".\")[0] + \"Z\";\n } else {\n // No existing versions, use current timestamp\n const now = new Date();\n versionName = now.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.debug?.(`[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(): Promise<string[]> {\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(): Promise<string | null> {\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(): Promise<boolean> {\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(): Promise<{\n versioned: boolean;\n hasMetadata: boolean;\n dataType: DataType | null;\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 private async loadMetadataJson(version: string): Promise<VersionMetadata | null> {\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 as Error).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 private async figureMetadataFromVersionFiles(version: string): Promise<VersionMetadata> {\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: DataType | null = 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: 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: FileEntry = {\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 as 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 private async buildMetadataOptimized(version: string): Promise<VersionMetadata> {\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: any;\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 private async figureMetadata(version: string, useOptimized: boolean = true): Promise<VersionMetadata> {\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 private async loadVersionMetadata(version: string): Promise<VersionMetadata> {\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 private async saveVersionMetadata(metadata?: VersionMetadata): Promise<void> {\n if (!this.useMetadata) {\n return;\n }\n\n const metadataToSave = metadata || this.metadata;\n let metadataFile: string;\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 private makeNewFile(): void {\n this.currentFileNumber = (this.currentFileNumber || 0) + 1;\n\n const dataType = this.metadata.dataType || \"json-array\";\n const fileEntry: 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.debug?.(`[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 */\n private figureOutDataAndFileToWrite(data: any): WriteContext {\n let dataToWrite: any;\n let dataLeftOver: any[] | null;\n\n const lastFile = this.metadata.files[this.metadata.files.length - 1];\n const lastFileRecordsCount = lastFile.recordsCount;\n\n if (Array.isArray(data)) {\n // For arrays, handle pagination\n 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 } 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 }\n this.lastFileData = dataToWrite;\n } else {\n // For non-arrays, write as-is\n dataToWrite = data;\n dataLeftOver = null;\n }\n\n const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;\n\n this.logger.debug?.(\n `[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, 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 private calculateFileSynopsis(data: any, fileIndex: number = this.metadata.files.length - 1): void {\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 private calculateVersionSynopsis(): void {\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 private updateMetadata(dataToWrite: any, fileName?: string): void {\n let currentFile: FileEntry;\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 // 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.debug?.(\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 private async safeWrite(filePath: string, data: any): Promise<void> {\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.debug?.(`[FileDatabase] Wrote ${bytesToHumanReadable(requiredBytes)} to ${filePath}`);\n } catch (error) {\n throw new FileDatabaseError(`Failed to write file ${filePath}: ${(error as 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 private async prepare({ write, read, version }: { write?: boolean; read?: boolean; version?: string }): Promise<void> {\n if (write) {\n if (this.versioned) {\n // Versioned mode\n if (this.currentVersion === null) {\n await this.makeNewVersion();\n this.metadata = this.getDefaultMetadata();\n this.metadata.version = this.currentVersion;\n this.makeNewFile();\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 }\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 } catch (e) {\n this.metadata = this.getDefaultMetadata();\n }\n } else {\n this.metadata = this.getDefaultMetadata();\n this.makeNewFile();\n }\n } else {\n // No metadata mode - just create default metadata\n this.metadata = this.getDefaultMetadata();\n this.makeNewFile();\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 }\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 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 } catch (e) {\n throw new FileDatabaseError(`Failed to read metadata: ${(e as Error).message}`);\n }\n } else {\n throw new FileDatabaseError(\"[FileDatabase] No metadata found in non-versioned mode\");\n }\n } else {\n // Figure metadata from files\n this.metadata = await this.figureMetadataFromVersionFiles('');\n }\n }\n }\n }\n\n /**\n * Write data to the file database\n */\n async write(data: any, options: WriteOptions = {}): Promise<void> {\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\n await this.prepare({ write: true });\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 this.makeNewFile();\n }\n\n let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data);\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);\n\n // Handle pagination for remaining data (arrays only)\n while (dataLeftOver && dataLeftOver.length > 0) {\n const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);\n await this.safeWrite(path.join(destPath, writeContext.fileName), writeContext.dataToWrite);\n this.updateMetadata(writeContext.dataToWrite, writeContext.fileName);\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: ReadOptions = {}): Promise<any> {\n const { version, nextPage = false, pageSize } = options;\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 as Error).message}`);\n }\n }\n\n // Handle paginated data (JSON arrays)\n let effectivePageSize: number;\n\n if (nextPage && this.hasReadFirstPage) {\n // Move to next page\n effectivePageSize = pageSize || this.pageSize;\n this.currentRecord += effectivePageSize;\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: any[] = [];\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\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 const rawData = await fs.promises.readFile(filePath, \"utf8\");\n const fileData = deserializeData(rawData, this.metadata.dataType!);\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 as Error).message}`);\n }\n }\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: number): void {\n this.currentRecord = startRecord - 1;\n this.hasReadFirstPage = false;\n }\n\n /**\n * Reset read pagination state\n */\n resetPagination(): void {\n this.currentRecord = 0;\n this.hasReadFirstPage = false;\n }\n\n /**\n * Set file-level synopsis calculation function\n */\n setFileSynopsisFunction(fn: FileSynopsisFunction): void {\n this.fileSynopsisFunction = fn;\n }\n\n /**\n * Set version-level synopsis calculation function\n */\n setVersionSynopsisFunction(fn: VersionSynopsisFunction): void {\n this.versionSynopsisFunction = fn;\n }\n\n /**\n * Get current version name\n */\n getCurrentVersion(): string | null {\n return this.currentVersion;\n }\n\n /**\n * Get current metadata\n */\n getMetadata(): VersionMetadata {\n return { ...this.metadata };\n }\n}\n\n// Export types\nexport type {\n FileDatabaseConfig,\n VersionMetadata,\n FileEntry,\n ReadOptions,\n WriteOptions,\n FileSynopsisFunction,\n VersionSynopsisFunction,\n DataType,\n StorageMode,\n CatalogEntry,\n} from \"./types.js\";\n\n// Export synopsis functions\nexport { defaultFileSynopsisFunction, defaultVersionSynopsisFunction } from \"./synopsis-functions.js\";\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: string): number | null {\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 * 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\";\n\n/**\n * Ensure a directory path exists, creating it if necessary\n * Returns the absolute path\n */\nexport async function ensurePath(...pathParts: string[]): Promise<string> {\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: string[]): string {\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: string): string {\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 * 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: number): string {\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: string): number {\n const units: Record<string, number> = {\n \"B\": 1,\n \"KB\": 1024,\n \"MB\": 1024 * 1024,\n \"GB\": 1024 * 1024 * 1024,\n \"TB\": 1024 * 1024 * 1024 * 1024,\n \"PB\": 1024 * 1024 * 1024 * 1024 * 1024,\n };\n \n const match = humanString.trim().match(/^([\\d.]+)\\s*([A-Z]+)$/i);\n if (!match) {\n throw new Error(`Invalid format: ${humanString}. Expected format like \"2MB\" or \"1.5 GB\"`);\n }\n \n const value = parseFloat(match[1]);\n const unit = match[2].toUpperCase();\n \n if (!units[unit]) {\n throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(\", \")}`);\n }\n \n return Math.round(value * units[unit]);\n}\n\n","/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\nexport interface DateFormatOptions {\n timezone?: \"UTC\" | \"user\";\n format?: \"iso\" | \"iso-date\" | \"iso-time\" | \"human\";\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: Date | string | number | undefined, options: DateFormatOptions = {}): string {\n if (value === undefined || value === null) {\n return \"\";\n }\n\n const { timezone = \"UTC\", format = \"iso\" } = options;\n \n let date: 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: Date | string | number | undefined): string {\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(): string {\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: string): Date {\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: Date | string,\n end: Date | string\n): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\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: string): boolean {\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: string[] = []): string {\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 * FileStore Serializers\n * \n * Data type detection and serialization/deserialization utilities\n */\n\nimport type { DataType } from \"./types.js\";\n\n/**\n * Detect the data type of a given value\n */\nexport function detectDataType(data: any): DataType {\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: any): string {\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: string, dataType: DataType): any {\n if (dataType === \"json-array\" || dataType === \"json-object\") {\n return JSON.parse(rawData);\n } else {\n // For text and XML, return as-is\n return rawData;\n }\n}\n\n","/**\n * Synopsis Functions - Predefined synopsis calculations for FileDatabase\n * \n * These functions analyze file and version data to generate useful summaries\n * and statistics that can be stored in metadata.\n */\n\nimport type { FileEntry, VersionMetadata } from \"./types.js\";\n\n/**\n * Default file-level synopsis function\n * Extracts min/max ModificationTimestamp and StandardStatus counts from records\n */\nexport function defaultFileSynopsisFunction(fileEntry: FileEntry, data: any): FileEntry {\n if (!Array.isArray(data) || data.length === 0) {\n return { ...fileEntry };\n }\n\n const timestamps: number[] = [];\n const statusCounts: Record<string, number> = {};\n\n for (const item of data) {\n let ts: number | null = null;\n let status: string | null = null;\n\n for (const [key, value] of Object.entries(item)) {\n const k = key.toLowerCase();\n if (k === \"modificationtimestamp\") {\n ts = new Date(value as string).getTime();\n }\n if (k === \"standardstatus\") {\n status = value as string;\n }\n }\n\n if (ts && !isNaN(ts)) {\n timestamps.push(ts);\n }\n\n if (status !== null && status !== undefined) {\n statusCounts[status] = (statusCounts[status] || 0) + 1;\n }\n }\n\n const result: FileEntry = { ...fileEntry };\n\n if (timestamps.length) {\n result.minModificationTimestamp = new Date(Math.min(...timestamps)).toISOString();\n result.maxModificationTimestamp = new Date(Math.max(...timestamps)).toISOString();\n }\n\n if (Object.keys(statusCounts).length) {\n result.StandardStatuses = statusCounts;\n }\n\n return result;\n}\n\n/**\n * Default version-level synopsis function\n * Aggregates min/max timestamps and status counts across all files in a version\n */\nexport function defaultVersionSynopsisFunction(metadata: VersionMetadata): VersionMetadata {\n if (!metadata?.files || !Array.isArray(metadata.files)) {\n return metadata;\n }\n\n const timestamps: number[] = [];\n const statusCounts: Record<string, number> = {};\n\n for (const file of metadata.files) {\n // Collect timestamps\n if ((file as any).minModificationTimestamp) {\n const minTs = new Date((file as any).minModificationTimestamp).getTime();\n if (!isNaN(minTs)) timestamps.push(minTs);\n }\n if ((file as any).maxModificationTimestamp) {\n const maxTs = new Date((file as any).maxModificationTimestamp).getTime();\n if (!isNaN(maxTs)) timestamps.push(maxTs);\n }\n\n // Aggregate statuses\n if ((file as any).StandardStatuses && typeof (file as any).StandardStatuses === \"object\") {\n for (const [status, count] of Object.entries((file as any).StandardStatuses)) {\n statusCounts[status] = (statusCounts[status] || 0) + (count as number);\n }\n }\n }\n\n const result = { ...metadata };\n\n if (timestamps.length) {\n (result as any).minModificationTimestamp = new Date(Math.min(...timestamps)).toISOString();\n (result as any).maxModificationTimestamp = new Date(Math.max(...timestamps)).toISOString();\n }\n\n if (Object.keys(statusCounts).length > 0) {\n (result as any).StandardStatuses = statusCounts;\n }\n\n return result;\n}\n\n","/**\n * Database Client - Low-level SQL database operations\n *\n * Wraps Knex.js with connection management, profiling, and utility functions.\n * The instance can be used directly like a Knex instance: db('table').select()\n */\n\nimport knex, { Knex } from 'knex';\nimport { ParamError } from '../errors.js';\nimport type { DbConfig, DatabaseClient, QueryLogEntry, DbInstance } from './types.js';\n\n/**\n * Database client wrapper around Knex\n * \n * Usage:\n * ```typescript\n * const db = new Db({\n * connectionString: 'postgresql://user:pass@host:5432/dbname',\n * testConnection: true,\n * profile: false\n * });\n * await db.connect();\n * \n * // Use like Knex:\n * const users = await db('users').select('*');\n * await db('posts').insert({ title: 'Hello' });\n * ```\n */\nexport class Db {\n private knexInstance: Knex | null = null;\n private config: Required<DbConfig>;\n private logger: any;\n private queriesLog: QueryLogEntry[] = [];\n private isConnected: boolean = false;\n\n constructor(config: DbConfig) {\n if (!config.connectionString) {\n throw new ParamError('Db: connectionString is required');\n }\n\n this.config = {\n testConnection: true,\n profile: false,\n pool: { min: 2, max: 10 },\n acquireConnectionTimeout: 10000,\n ssl: { rejectUnauthorized: false },\n logger: console,\n name: 'default',\n ...config,\n };\n\n this.logger = this.config.logger;\n\n // Create a callable function wrapper that forwards to the instance\n // This allows db('table') to work like Knex\n const instance = this;\n const callableWrapper = function(...args: any[]) {\n // This function body is never executed - the Proxy apply trap handles calls\n // But we need a function to make the Proxy apply trap work\n throw new Error('This should never be called directly');\n };\n \n // Store instance reference on the wrapper for Proxy access\n (callableWrapper as any)._instance = instance;\n\n // Create a Proxy that makes the wrapper callable and forwards property access\n return new Proxy(callableWrapper, {\n // Intercept function calls: db('table')\n apply: (target, thisArg, argumentsList) => {\n const inst = (target as any)._instance;\n if (!inst.knexInstance) {\n throw new Error('Db: Not connected. Call connect() first.');\n }\n // Forward the call to the Knex instance (Knex instances are callable)\n return (inst.knexInstance as any)(...argumentsList);\n },\n // Intercept property access: db.schema, db.raw, etc.\n get: (target, prop) => {\n // Allow access to _instance for internal use\n if (prop === '_instance') {\n return (target as any)._instance;\n }\n \n const instance = (target as any)._instance;\n \n // List of our own methods that should NOT be forwarded to Knex\n const ownMethods = [\n 'connect',\n 'disconnect',\n 'testConnection',\n 'tableExists',\n 'getQueryLog',\n 'getKnex',\n 'isConnectedToDb',\n 'getErrorMessage',\n 'detectClient',\n 'attachProfiler',\n ];\n \n // Always return our own methods first (before checking Knex)\n if (prop in instance) {\n const value = (instance as any)[prop];\n // If it's one of our own methods, return it bound to instance\n if (typeof value === 'function' && ownMethods.includes(prop as string)) {\n return value.bind(instance);\n }\n // If it's a non-function property, return it\n if (typeof value !== 'function') {\n return value;\n }\n }\n \n // If we have a Knex instance, forward to it for everything else\n if (instance.knexInstance) {\n const knexProp = (instance.knexInstance as any)[prop];\n if (typeof knexProp === 'function') {\n // Bind methods to the Knex instance\n return knexProp.bind(instance.knexInstance);\n }\n return knexProp;\n }\n \n // Return our own methods that aren't in the ownMethods list (shouldn't happen, but fallback)\n if (prop in instance) {\n const method = (instance as any)[prop];\n if (typeof method === 'function') {\n return method.bind(instance);\n }\n return method;\n }\n \n // Property doesn't exist\n return undefined;\n },\n }) as any;\n }\n\n /**\n * Detect database client type from connection string\n */\n private detectClient(connectionString: string): DatabaseClient | null {\n if (connectionString.match(/^postgresql/)) {\n return 'pg';\n }\n if (connectionString.match(/^mysql/)) {\n return 'mysql2';\n }\n return null;\n }\n\n /**\n * Connect to the database\n */\n async connect(): Promise<void> {\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 // Force IPv4 only (disable IPv6) by setting family: 4 in connection config\n // Knex accepts connection as string or object; we wrap string to add family option\n const connectionConfig = {\n connectionString: this.config.connectionString,\n family: 4, // Force IPv4 only (disable IPv6)\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 } as any);\n\n // Attach profiler if enabled\n if (this.config.profile) {\n this.attachProfiler();\n }\n\n // Test connection if requested\n if (this.config.testConnection) {\n await this.testConnection();\n }\n\n this.isConnected = true;\n this.logger.debug?.(`[Db] Connected to database \"${this.config.name || this.config.connectionString}\"`);\n } catch (error: any) {\n // If testConnection already threw a ParamError, preserve its message\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = this.getErrorMessage(error);\n throw new ParamError(`Db: Connection failed - ${errorMsg}`);\n }\n }\n\n /**\n * Disconnect from the database\n */\n async disconnect(): Promise<void> {\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?.(`[Db] Disconnected from database \"${this.config.name || this.config.connectionString}\"`);\n } catch (error: any) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);\n throw error;\n }\n }\n\n /**\n * Extract error message from various error types\n */\n private getErrorMessage(error: any): string {\n // Handle AggregateError (can contain multiple errors)\n if (error instanceof AggregateError) {\n const errors = error.errors || [];\n \n // If all errors are the same type (e.g., ECONNREFUSED for different IPs), show a consolidated message\n if (errors.length > 0) {\n const firstError = errors[0];\n const firstErrorMsg = firstError instanceof Error ? firstError.message : String(firstError);\n \n // Check if all errors are similar (same error code/type, different addresses)\n const allSimilar = errors.every((e: any) => {\n const msg = e instanceof Error ? e.message : String(e);\n // Extract error code (e.g., \"ECONNREFUSED\") from message\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 // Extract addresses/IPs from error messages\n const addresses = errors.map((e: any) => {\n const msg = e instanceof Error ? e.message : String(e);\n // Try to extract address (e.g., \"::1:5432\" or \"127.0.0.1:5432\")\n const addrMatch = msg.match(/([:\\d.]+:\\d+)/);\n return addrMatch ? addrMatch[1] : null;\n }).filter(Boolean);\n \n if (addresses.length > 0) {\n // Show consolidated message with all addresses\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 // Fallback: show all errors but deduplicate identical messages\n const uniqueMessages = [...new Set(errors.map((e: any) => {\n return e instanceof Error ? e.message : String(e);\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 // Handle standard Error objects\n if (error instanceof Error) {\n // Check for common database error properties (code is often present on Node.js errors)\n const errorWithCode = error as Error & { code?: string };\n if (errorWithCode.code) {\n return `${errorWithCode.code}: ${error.message || String(error)}`;\n }\n return error.message || String(error);\n }\n \n // Handle string errors\n if (typeof error === 'string') {\n return error;\n }\n \n // Handle objects with message property\n if (error?.message) {\n const msg = String(error.message);\n const errorWithCode = error as { code?: string };\n if (errorWithCode.code) {\n return `${errorWithCode.code}: ${msg}`;\n }\n return msg;\n }\n \n // Fallback: try to stringify the error\n return String(error) || 'Unknown error';\n }\n\n /**\n * Test database connection\n */\n async testConnection(): Promise<boolean> {\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: any) {\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 /**\n * Attach query profiler to log all queries\n */\n private attachProfiler(): void {\n if (!this.knexInstance) {\n return;\n }\n\n this.queriesLog = [];\n (this.knexInstance as any).queriesLog = this.queriesLog;\n\n this.knexInstance.on('query', (query: any) => {\n query.__startTime = process.hrtime();\n });\n\n this.knexInstance.on('query-response', (response: any, query: any) => {\n const [seconds, nanoseconds] = process.hrtime(query.__startTime);\n const executionTimeMs = ((seconds * 1000) + (nanoseconds / 1e6)).toFixed(2);\n\n const logEntry: QueryLogEntry = {\n sql: query.sql,\n bindings: query.bindings || [],\n executionTimeMs,\n };\n\n this.queriesLog.push(logEntry);\n this.logger.debug?.(`[Db] Query: ${query.sql} | Duration: ${executionTimeMs}ms`);\n });\n\n this.knexInstance.on('query-error', (error: Error, query: any) => {\n this.logger.error?.(`[Db] Query failed: ${query.sql}`, error);\n });\n }\n\n /**\n * Get query log (only available if profiling is enabled)\n */\n getQueryLog(): QueryLogEntry[] {\n return [...this.queriesLog];\n }\n\n /**\n * Check if a table exists\n */\n async tableExists(tableName: string): Promise<boolean> {\n if (!this.knexInstance) {\n throw new Error('Db: Not connected. Call connect() first.');\n }\n\n try {\n return await this.knexInstance.schema.hasTable(tableName);\n } catch (error: any) {\n this.logger.error?.(`[Db] Error checking table existence: ${error.message}`);\n throw error;\n }\n }\n\n /**\n * Get the underlying Knex instance (for advanced usage)\n */\n getKnex(): Knex {\n if (!this.knexInstance) {\n throw new Error('Db: Not connected. Call connect() first.');\n }\n return this.knexInstance;\n }\n\n /**\n * Get connection status\n */\n isConnectedToDb(): boolean {\n return this.isConnected && this.knexInstance !== null;\n }\n}\n\n"],"mappings":"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","names":["config","relativeMatch","Joi","import_react","import_ink","h","import_react","import_ink","h","React","config","resolve","instance","h","import_react","import_ink","h","path","config","import_fs","import_path","import_fs","import_path","fs","path","import_fs","import_path","path","fs","config","path","maxDate","fs","config","instance","knex"]}
|