@kidd-cli/core 0.1.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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +214 -0
  3. package/dist/config-BvGapuFJ.js +282 -0
  4. package/dist/config-BvGapuFJ.js.map +1 -0
  5. package/dist/create-store-BQUX0tAn.js +197 -0
  6. package/dist/create-store-BQUX0tAn.js.map +1 -0
  7. package/dist/index.d.ts +73 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +1034 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/lib/config.d.ts +64 -0
  12. package/dist/lib/config.d.ts.map +1 -0
  13. package/dist/lib/config.js +4 -0
  14. package/dist/lib/logger.d.ts +2 -0
  15. package/dist/lib/logger.js +55 -0
  16. package/dist/lib/logger.js.map +1 -0
  17. package/dist/lib/output.d.ts +62 -0
  18. package/dist/lib/output.d.ts.map +1 -0
  19. package/dist/lib/output.js +276 -0
  20. package/dist/lib/output.js.map +1 -0
  21. package/dist/lib/project.d.ts +59 -0
  22. package/dist/lib/project.d.ts.map +1 -0
  23. package/dist/lib/project.js +3 -0
  24. package/dist/lib/prompts.d.ts +24 -0
  25. package/dist/lib/prompts.d.ts.map +1 -0
  26. package/dist/lib/prompts.js +3 -0
  27. package/dist/lib/store.d.ts +56 -0
  28. package/dist/lib/store.d.ts.map +1 -0
  29. package/dist/lib/store.js +4 -0
  30. package/dist/logger-BkQQej8h.d.ts +76 -0
  31. package/dist/logger-BkQQej8h.d.ts.map +1 -0
  32. package/dist/middleware/auth.d.ts +22 -0
  33. package/dist/middleware/auth.d.ts.map +1 -0
  34. package/dist/middleware/auth.js +759 -0
  35. package/dist/middleware/auth.js.map +1 -0
  36. package/dist/middleware/http.d.ts +87 -0
  37. package/dist/middleware/http.d.ts.map +1 -0
  38. package/dist/middleware/http.js +255 -0
  39. package/dist/middleware/http.js.map +1 -0
  40. package/dist/middleware-D3psyhYo.js +54 -0
  41. package/dist/middleware-D3psyhYo.js.map +1 -0
  42. package/dist/project-NPtYX2ZX.js +181 -0
  43. package/dist/project-NPtYX2ZX.js.map +1 -0
  44. package/dist/prompts-lLfUSgd6.js +63 -0
  45. package/dist/prompts-lLfUSgd6.js.map +1 -0
  46. package/dist/types-CqKJhsYk.d.ts +135 -0
  47. package/dist/types-CqKJhsYk.d.ts.map +1 -0
  48. package/dist/types-Cz9h927W.d.ts +23 -0
  49. package/dist/types-Cz9h927W.d.ts.map +1 -0
  50. package/dist/types-DFtYg5uZ.d.ts +26 -0
  51. package/dist/types-DFtYg5uZ.d.ts.map +1 -0
  52. package/dist/types-kjpRau0U.d.ts +382 -0
  53. package/dist/types-kjpRau0U.d.ts.map +1 -0
  54. package/package.json +94 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["match"],"sources":["../src/context/error.ts","../src/context/output.ts","../src/context/prompts.ts","../src/context/store.ts","../src/context/create-context.ts","../src/autoloader.ts","../src/runtime/args/zod.ts","../src/runtime/args/parser.ts","../src/runtime/args/register.ts","../src/runtime/register.ts","../src/runtime/runner.ts","../src/runtime/runtime.ts","../src/cli.ts","../src/command.ts"],"sourcesContent":["import type { Tagged } from '@kidd-cli/utils/tag'\nimport { TAG, hasTag, withTag } from '@kidd-cli/utils/tag'\n\nimport { DEFAULT_EXIT_CODE } from '@/utils/constants.js'\n\nexport { DEFAULT_EXIT_CODE }\n\n/**\n * Plain data representation of a ContextError (no Error prototype).\n *\n * Useful for serializing error data without carrying the Error prototype chain,\n * for example when logging or forwarding errors across process boundaries.\n */\nexport type ContextErrorData = Tagged<\n {\n readonly code: string | undefined\n readonly exitCode: number\n readonly message: string\n },\n 'ContextError'\n>\n\n/**\n * An Error subtype carrying an exit code and optional error code.\n *\n * Created by {@link createContextError} and thrown by `ctx.fail()`.\n * The CLI boundary catches these to produce clean, user-facing error output\n * with the correct process exit code.\n */\nexport type ContextError = Error &\n Tagged<\n {\n readonly code: string | undefined\n readonly exitCode: number\n },\n 'ContextError'\n >\n\n/**\n * Create a ContextError with an exit code and optional error code.\n *\n * Used to surface user-facing CLI errors with clean messages.\n * The error carries a Symbol-based tag for reliable type-narrowing\n * via {@link isContextError}.\n *\n * @param message - Human-readable error message.\n * @param options - Optional error code and exit code overrides.\n * @returns A ContextError instance.\n */\nexport function createContextError(\n message: string,\n options?: { code?: string; exitCode?: number }\n): ContextError {\n const data = createContextErrorData(message, options)\n const error = new Error(data.message) as ContextError\n error.name = 'ContextError'\n Object.defineProperty(error, TAG, { enumerable: false, value: 'ContextError', writable: false })\n Object.defineProperty(error, 'code', { enumerable: true, value: data.code, writable: false })\n Object.defineProperty(error, 'exitCode', {\n enumerable: true,\n value: data.exitCode,\n writable: false,\n })\n return error\n}\n\n/**\n * Type guard that narrows an unknown value to {@link ContextError}.\n *\n * Checks that the value is an Error instance whose `[TAG]` property\n * equals `'ContextError'`, which distinguishes CLI-layer errors from\n * unexpected exceptions.\n *\n * @param error - The value to check.\n * @returns `true` when the value is a ContextError.\n */\nexport function isContextError(error: unknown): error is ContextError {\n if (error instanceof Error) {\n return hasTag(error, 'ContextError')\n }\n return false\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nfunction resolveExitCode(options: { code?: string; exitCode?: number } | undefined): number {\n if (options && options.exitCode !== undefined) {\n return options.exitCode\n }\n return DEFAULT_EXIT_CODE\n}\n\nfunction resolveCode(\n options: { code?: string; exitCode?: number } | undefined\n): string | undefined {\n if (options && options.code !== undefined) {\n return options.code\n }\n return undefined\n}\n\nfunction createContextErrorData(\n message: string,\n options?: { code?: string; exitCode?: number }\n): ContextErrorData {\n return withTag(\n {\n code: resolveCode(options),\n exitCode: resolveExitCode(options),\n message,\n },\n 'ContextError'\n )\n}\n","import { jsonStringify } from '@kidd-cli/utils/json'\n\nimport type { Output, OutputOptions } from './types.js'\n\n/**\n * Create the structured output methods for a context.\n *\n * @private\n * @param stream - The writable stream to write output to.\n * @returns An Output instance backed by the given stream.\n */\nexport function createContextOutput(stream: NodeJS.WriteStream): Output {\n return {\n markdown(content: string): void {\n stream.write(`${content}\\n`)\n },\n raw(content: string): void {\n stream.write(content)\n },\n table(rows: Record<string, unknown>[], options?: OutputOptions): void {\n if (options && options.json) {\n const [, json] = jsonStringify(rows, { pretty: true })\n stream.write(`${json}\\n`)\n return\n }\n if (rows.length === 0) {\n return\n }\n const [firstRow] = rows\n if (!firstRow) {\n return\n }\n writeTableToStream(stream, rows, Object.keys(firstRow))\n },\n write(data: unknown, options?: OutputOptions): void {\n if ((options && options.json) || (typeof data === 'object' && data !== null)) {\n const [, json] = jsonStringify(data, { pretty: true })\n stream.write(`${json}\\n`)\n } else {\n stream.write(`${String(data)}\\n`)\n }\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Format an unknown value as a string for table cell display.\n *\n * @private\n * @param val - The value to format.\n * @returns The stringified value, or empty string for undefined.\n */\nfunction formatStringValue(val: unknown): string {\n if (val === undefined) {\n return ''\n }\n return String(val)\n}\n\n/**\n * Options for creating a table header string.\n */\ninterface TableHeaderOptions {\n keys: string[]\n widths: (number | undefined)[]\n}\n\n/**\n * Create a padded header row string from column keys and widths.\n *\n * @private\n * @param options - The keys and column widths.\n * @returns A formatted header string.\n */\nfunction createTableHeader(options: TableHeaderOptions): string {\n const { keys, widths } = options\n return keys\n .map((key, idx) => {\n const width = widths[idx]\n if (width === undefined) {\n return key\n }\n return key.padEnd(width)\n })\n .join(' ')\n}\n\n/**\n * Options for creating a table row string.\n */\ninterface TableRowOptions {\n row: Record<string, unknown>\n keys: string[]\n widths: (number | undefined)[]\n}\n\n/**\n * Create a padded row string from a data record, column keys, and widths.\n *\n * @private\n * @param options - The row data, keys, and column widths.\n * @returns A formatted row string.\n */\nfunction createTableRow(options: TableRowOptions): string {\n const { row, keys, widths } = options\n return keys\n .map((key, idx) => {\n const width = widths[idx]\n const val = formatStringValue(row[key])\n if (width === undefined) {\n return val\n }\n return val.padEnd(width)\n })\n .join(' ')\n}\n\n/**\n * Compute the maximum column width for each key across all rows.\n *\n * @private\n * @param rows - The data rows.\n * @param keys - The column keys.\n * @returns An array of column widths.\n */\nfunction computeColumnWidths(rows: Record<string, unknown>[], keys: string[]): number[] {\n return keys.map((key) => {\n const values = rows.map((row) => formatStringValue(row[key]))\n return Math.max(key.length, ...values.map((val) => val.length))\n })\n}\n\n/**\n * Write a formatted table (header, separator, rows) to a writable stream.\n *\n * @private\n * @param stream - The writable stream.\n * @param rows - The data rows.\n * @param keys - The column keys.\n */\nfunction writeTableToStream(\n stream: NodeJS.WriteStream,\n rows: Record<string, unknown>[],\n keys: string[]\n): void {\n const widths = computeColumnWidths(rows, keys)\n const header = createTableHeader({ keys, widths })\n const separator = widths.map((width) => '-'.repeat(width)).join(' ')\n const dataRows = rows.map((row) => createTableRow({ keys, row, widths }))\n const content = [header, separator, ...dataRows].join('\\n')\n stream.write(`${content}\\n`)\n}\n","import { createPromptUtils } from '@/lib/prompts/index.js'\n\nimport { DEFAULT_EXIT_CODE, createContextError } from './error.js'\nimport type { Prompts } from './types.js'\n\n/**\n * Create the interactive prompt methods for a context.\n *\n * @private\n * @returns A Prompts instance backed by clack.\n */\nexport function createContextPrompts(): Prompts {\n const utils = createPromptUtils()\n\n return {\n async confirm(opts): Promise<boolean> {\n const result = await utils.confirm(opts)\n return unwrapCancelSignal(utils, result)\n },\n async multiselect<Type>(opts: Parameters<Prompts['multiselect']>[0]): Promise<Type[]> {\n const result = await utils.multiselect<Type>(\n opts as Parameters<typeof utils.multiselect<Type>>[0]\n )\n return unwrapCancelSignal(utils, result)\n },\n async password(opts): Promise<string> {\n const result = await utils.password(opts)\n return unwrapCancelSignal(utils, result)\n },\n async select<Type>(opts: Parameters<Prompts['select']>[0]): Promise<Type> {\n const result = await utils.select<Type>(opts as Parameters<typeof utils.select<Type>>[0])\n return unwrapCancelSignal(utils, result)\n },\n async text(opts): Promise<string> {\n const result = await utils.text(opts)\n return unwrapCancelSignal(utils, result)\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Unwrap a prompt result that may be a cancel symbol.\n *\n * If the user cancelled (Ctrl-C), throws a ContextError. Otherwise returns\n * the typed result value.\n *\n * @private\n * @param utils - The prompt utils instance (for isCancel and cancel).\n * @param result - The raw prompt result (value or cancel symbol).\n * @returns The unwrapped typed value.\n */\nfunction unwrapCancelSignal<Type>(\n utils: ReturnType<typeof createPromptUtils>,\n result: Type | symbol\n): Type {\n if (utils.isCancel(result)) {\n utils.cancel('Operation cancelled.')\n throw createContextError('Prompt cancelled by user', {\n code: 'PROMPT_CANCELLED',\n exitCode: DEFAULT_EXIT_CODE,\n })\n }\n return result as Type\n}\n","import type { Store } from './types.js'\n\n/**\n * Create an in-memory key-value store.\n *\n * @private\n * @returns A Store instance backed by a Map.\n */\nexport function createMemoryStore<TMap extends Record<string, unknown>>(): Store<TMap> {\n const map = new Map<string, unknown>()\n\n return {\n clear(): void {\n map.clear()\n },\n delete(key: string): boolean {\n return map.delete(key)\n },\n get<Key extends Extract<keyof TMap, string>>(key: Key): TMap[Key] | undefined {\n return map.get(key) as TMap[Key] | undefined\n },\n has(key: string): boolean {\n return map.has(key)\n },\n set<Key extends Extract<keyof TMap, string>>(key: Key, value: TMap[Key]): void {\n map.set(key, value)\n },\n }\n}\n","import { createCliLogger } from '@/lib/logger.js'\nimport type { CliLogger } from '@/lib/logger.js'\nimport { createSpinner } from '@/lib/prompts/index.js'\nimport type { AnyRecord, KiddStore, Merge } from '@/types.js'\n\nimport { createContextError } from './error.js'\nimport { createContextOutput } from './output.js'\nimport { createContextPrompts } from './prompts.js'\nimport { createMemoryStore } from './store.js'\nimport type { Context, Meta, Output, Prompts, Spinner, Store, StoreMap } from './types.js'\n\n/**\n * Options for creating a {@link Context} instance via {@link createContext}.\n *\n * Carries the parsed args, validated config, and CLI metadata needed to\n * assemble a fully-wired context. An optional `logger` override allows\n * callers to inject a custom {@link CliLogger}; when omitted a default\n * @clack/prompts-backed instance is used.\n */\nexport interface CreateContextOptions<TArgs extends AnyRecord, TConfig extends AnyRecord> {\n readonly args: TArgs\n readonly config: TConfig\n readonly meta: { readonly name: string; readonly version: string; readonly command: string[] }\n readonly logger?: CliLogger\n readonly output?: NodeJS.WriteStream\n}\n\n/**\n * Create the {@link Context} object threaded through middleware and command handlers.\n *\n * Assembles logger, spinner, output, store, prompts, and meta from\n * the provided options into a single immutable context. Each sub-system is\n * constructed via its own factory so this function remains a lean orchestrator.\n *\n * @param options - Args, config, and meta for the current invocation.\n * @returns A fully constructed Context.\n */\nexport function createContext<TArgs extends AnyRecord, TConfig extends AnyRecord>(\n options: CreateContextOptions<TArgs, TConfig>\n): Context<TArgs, TConfig> {\n const ctxLogger: CliLogger = options.logger ?? createCliLogger()\n const ctxSpinner: Spinner = createSpinner()\n const ctxOutput: Output = createContextOutput(options.output ?? process.stdout)\n const ctxStore: Store<Merge<KiddStore, StoreMap>> = createMemoryStore()\n const ctxPrompts: Prompts = createContextPrompts()\n const ctxMeta: Meta = {\n command: options.meta.command,\n name: options.meta.name,\n version: options.meta.version,\n }\n\n // Middleware-augmented properties (e.g. `auth`) are added at runtime.\n // See `decorateContext` — they are intentionally absent here.\n return {\n args: options.args as Context<TArgs, TConfig>['args'],\n config: options.config as Context<TArgs, TConfig>['config'],\n fail(message: string, failOptions?: { code?: string; exitCode?: number }): never {\n throw createContextError(message, failOptions)\n },\n logger: ctxLogger,\n meta: ctxMeta as Context<TArgs, TConfig>['meta'],\n output: ctxOutput,\n prompts: ctxPrompts,\n spinner: ctxSpinner,\n store: ctxStore,\n } as Context<TArgs, TConfig>\n}\n","import type { Dirent } from 'node:fs'\nimport { readdir } from 'node:fs/promises'\nimport { basename, extname, join, resolve } from 'node:path'\n\nimport { isPlainObject, isString } from '@kidd-cli/utils/fp'\nimport { hasTag, withTag } from '@kidd-cli/utils/tag'\n\nimport type { AutoloadOptions, Command, CommandMap } from './types.js'\n\nconst VALID_EXTENSIONS = new Set(['.ts', '.js', '.mjs'])\nconst INDEX_NAME = 'index'\n\n/**\n * Scan a directory for command files and produce a CommandMap.\n *\n * @param options - Autoload configuration (directory override, etc.).\n * @returns A promise resolving to a CommandMap built from the directory tree.\n */\nexport async function autoload(options?: AutoloadOptions): Promise<CommandMap> {\n const dir = resolveDir(options)\n const entries = await readdir(dir, { withFileTypes: true })\n\n const fileEntries = entries.filter(isCommandFile)\n const dirEntries = entries.filter(isCommandDir)\n\n const fileResults = await Promise.all(\n fileEntries.map(async (entry): Promise<[string, Command] | undefined> => {\n const cmd = await importCommand(join(dir, entry.name))\n if (!cmd) {\n return undefined\n }\n return [deriveCommandName(entry), cmd]\n })\n )\n\n const dirResults = await Promise.all(\n dirEntries.map((entry) => buildDirCommand(join(dir, entry.name)))\n )\n\n const allResults = [...fileResults, ...dirResults]\n const validPairs = allResults.filter((pair): pair is [string, Command] => pair !== undefined)\n\n return Object.fromEntries(validPairs) as CommandMap\n}\n\n// ---------------------------------------------------------------------------\n// Private\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the target directory from autoload options.\n *\n * @private\n * @param options - Optional autoload configuration.\n * @returns The resolved absolute directory path.\n */\nfunction resolveDir(options?: AutoloadOptions): string {\n if (options && isString(options.dir)) {\n return resolve(options.dir)\n }\n return resolve('./commands')\n}\n\n/**\n * Scan a subdirectory and assemble it as a parent command with subcommands.\n *\n * If the directory contains an `index.ts`/`index.js`, that becomes the parent\n * handler. Otherwise a handler-less group command is created that demands a\n * subcommand.\n *\n * @private\n * @param dir - Absolute path to the subdirectory.\n * @returns A tuple of [name, Command] or undefined if the directory is empty.\n */\nasync function buildDirCommand(dir: string): Promise<[string, Command] | undefined> {\n const name = basename(dir)\n const dirEntries = await readdir(dir, { withFileTypes: true })\n const subCommands = await buildSubCommands(dir, dirEntries)\n const indexFile = findIndexInEntries(dirEntries)\n\n if (indexFile) {\n const parentCommand = await importCommand(join(dir, indexFile.name))\n if (parentCommand) {\n return [name, withTag({ ...parentCommand, commands: subCommands }, 'Command')]\n }\n }\n\n if (Object.keys(subCommands).length === 0) {\n return undefined\n }\n\n return [name, withTag({ commands: subCommands }, 'Command')]\n}\n\n/**\n * Build subcommands from already-read directory entries, avoiding a redundant readdir call.\n *\n * @private\n * @param dir - Absolute path to the directory.\n * @param entries - Pre-read directory entries.\n * @returns A CommandMap built from the entries.\n */\nasync function buildSubCommands(dir: string, entries: Dirent[]): Promise<CommandMap> {\n const fileEntries = entries.filter(isCommandFile)\n const dirEntries = entries.filter(isCommandDir)\n\n const fileResults = await Promise.all(\n fileEntries.map(async (entry): Promise<[string, Command] | undefined> => {\n const cmd = await importCommand(join(dir, entry.name))\n if (!cmd) {\n return undefined\n }\n return [deriveCommandName(entry), cmd]\n })\n )\n\n const dirResults = await Promise.all(\n dirEntries.map((entry) => buildDirCommand(join(dir, entry.name)))\n )\n\n const allResults = [...fileResults, ...dirResults]\n const validPairs = allResults.filter((pair): pair is [string, Command] => pair !== undefined)\n\n return Object.fromEntries(validPairs) as CommandMap\n}\n\n/**\n * Find the index file (index.ts or index.js) in pre-read directory entries.\n *\n * @private\n * @param entries - Pre-read directory entries.\n * @returns The index file's Dirent or undefined.\n */\nfunction findIndexInEntries(entries: Dirent[]): Dirent | undefined {\n return entries.find(\n (entry) =>\n entry.isFile() &&\n VALID_EXTENSIONS.has(extname(entry.name)) &&\n basename(entry.name, extname(entry.name)) === INDEX_NAME\n )\n}\n\n/**\n * Dynamically import a file and validate that its default export is a Command.\n *\n * @private\n * @param filePath - Absolute path to the file to import.\n * @returns The Command if valid, or undefined.\n */\nasync function importCommand(filePath: string): Promise<Command | undefined> {\n const mod: unknown = await import(filePath)\n if (isCommandExport(mod)) {\n return mod.default\n }\n return undefined\n}\n\n/**\n * Check whether a module's default export is a Command object.\n *\n * ES module namespace objects have a null prototype, so isPlainObject\n * rejects them. We only need to verify the namespace is a non-null\n * object with a default export that is a plain Command object.\n *\n * @private\n * @param mod - The imported module to inspect.\n * @returns True when the module has a Command as its default export.\n */\nfunction isCommandExport(mod: unknown): mod is { default: Command } {\n if (typeof mod !== 'object' || mod === null) {\n return false\n }\n const def = (mod as Record<string, unknown>)['default']\n if (!isPlainObject(def)) {\n return false\n }\n return hasTag(def, 'Command')\n}\n\n/**\n * Derive a command name from a directory entry by stripping its extension.\n *\n * @private\n * @param entry - The directory entry to derive the name from.\n * @returns The file name without its extension.\n */\nfunction deriveCommandName(entry: Dirent): string {\n return basename(entry.name, extname(entry.name))\n}\n\n/**\n * Predicate: entry is a command file (.ts/.js, not index, not _/. prefixed).\n *\n * @private\n * @param entry - The directory entry to check.\n * @returns True when the entry is a valid command file.\n */\nfunction isCommandFile(entry: Dirent): boolean {\n if (!entry.isFile()) {\n return false\n }\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) {\n return false\n }\n if (!VALID_EXTENSIONS.has(extname(entry.name))) {\n return false\n }\n return deriveCommandName(entry) !== INDEX_NAME\n}\n\n/**\n * Predicate: entry is a scannable command directory (not _/. prefixed).\n *\n * @private\n * @param entry - The directory entry to check.\n * @returns True when the entry is a valid command directory.\n */\nfunction isCommandDir(entry: Dirent): boolean {\n if (!entry.isDirectory()) {\n return false\n }\n return !entry.name.startsWith('_') && !entry.name.startsWith('.')\n}\n","import { match } from 'ts-pattern'\nimport type { Options as YargsOptions } from 'yargs'\nimport type { z } from 'zod'\n\n/**\n * Type guard that checks whether a value is a zod object schema.\n *\n * @param args - The value to check.\n * @returns True when args is a ZodObject.\n */\nexport function isZodSchema(args: unknown): args is z.ZodObject<z.ZodRawShape> {\n return (\n typeof args === 'object' &&\n args !== null &&\n '_def' in args &&\n typeof (args as { _def: unknown })._def === 'object' &&\n (args as { _def: { type?: string } })._def !== null &&\n (args as { _def: { type?: string } })._def.type === 'object'\n )\n}\n\n/**\n * Convert an entire zod object schema into a record of yargs options.\n *\n * @param schema - The zod object schema.\n * @returns A record mapping field names to yargs option definitions.\n */\nexport function zodSchemaToYargsOptions(\n schema: z.ZodObject<z.ZodRawShape>\n): Record<string, YargsOptions> {\n const shape = schema.shape as Record<string, z.ZodTypeAny>\n return Object.fromEntries(\n Object.entries(shape).map(([key, fieldSchema]): [string, YargsOptions] => [\n key,\n getZodTypeOption(fieldSchema),\n ])\n )\n}\n\n// ---------------------------------------------------------------------------\n// Private\n// ---------------------------------------------------------------------------\n\ninterface ZodDef {\n type?: string\n innerType?: z.ZodTypeAny\n defaultValue?: unknown\n}\n\ninterface ZodTypeInfo {\n defaultValue: unknown\n inner: z.ZodTypeAny\n isOptional: boolean\n}\n\ninterface UnwrapOptions {\n def: ZodDef\n current: z.ZodTypeAny\n defaultValue: unknown\n}\n\ninterface UnwrapRecursiveOptions {\n current: z.ZodTypeAny\n isOptional: boolean\n defaultValue: unknown\n}\n\n/**\n * Extract a default value from a zod definition, falling back to the provided value.\n *\n * @private\n * @param def - The zod definition to inspect.\n * @param fallback - Value to return when no default is defined.\n * @returns The resolved default value.\n */\nfunction resolveDefaultValue(def: ZodDef, fallback: unknown): unknown {\n if (def.defaultValue !== undefined) {\n return def.defaultValue\n }\n return fallback\n}\n\n/**\n * Unwrap a ZodOptional type, recursing into the inner type.\n *\n * @private\n * @param options - The unwrap options containing def, current type, and default value.\n * @returns Unwrapped type information.\n */\nfunction unwrapOptional(options: UnwrapOptions): ZodTypeInfo {\n const { def, current, defaultValue } = options\n if (def.innerType) {\n return unwrapZodTypeRecursive({ current: def.innerType, defaultValue, isOptional: true })\n }\n return { defaultValue, inner: current, isOptional: true }\n}\n\n/**\n * Unwrap a ZodDefault type, resolving its default value and recursing.\n *\n * @private\n * @param options - The unwrap options containing def, current type, and default value.\n * @returns Unwrapped type information with the resolved default.\n */\nfunction unwrapDefault(options: UnwrapOptions): ZodTypeInfo {\n const { def, current, defaultValue } = options\n const newDefault = resolveDefaultValue(def, defaultValue)\n if (def.innerType) {\n return unwrapZodTypeRecursive({\n current: def.innerType,\n defaultValue: newDefault,\n isOptional: true,\n })\n }\n return { defaultValue: newDefault, inner: current, isOptional: true }\n}\n\n/**\n * Recursively unwrap optional and default wrappers from a zod type.\n *\n * @private\n * @param options - The recursive unwrap options containing current type, optionality flag, and default value.\n * @returns The fully unwrapped type information.\n */\nfunction unwrapZodTypeRecursive(options: UnwrapRecursiveOptions): ZodTypeInfo {\n const { current, isOptional, defaultValue } = options\n const def = (current as { _def: ZodDef })._def\n if (def.type === 'optional') {\n return unwrapOptional({ current, def, defaultValue })\n }\n if (def.type === 'default') {\n return unwrapDefault({ current, def, defaultValue })\n }\n return { defaultValue, inner: current, isOptional }\n}\n\n/**\n * Unwrap a zod schema to extract its base type, optionality, and default value.\n *\n * @private\n * @param schema - The zod type to unwrap.\n * @returns The unwrapped type information.\n */\nfunction unwrapZodType(schema: z.ZodTypeAny): ZodTypeInfo {\n return unwrapZodTypeRecursive({ current: schema, defaultValue: undefined, isOptional: false })\n}\n\n/**\n * Map a zod type name to a yargs option type string.\n *\n * @private\n * @param typeName - The zod type name (e.g. 'string', 'number').\n * @returns The corresponding yargs type.\n */\nfunction resolveZodYargsType(\n typeName: string | undefined\n): 'string' | 'number' | 'boolean' | 'array' {\n return match(typeName)\n .with('string', () => 'string' as const)\n .with('number', () => 'number' as const)\n .with('boolean', () => 'boolean' as const)\n .with('array', () => 'array' as const)\n .otherwise(() => 'string' as const)\n}\n\n/**\n * Build a base yargs option from a zod schema's description and default.\n *\n * @private\n * @param inner - The unwrapped zod schema instance.\n * @param defaultValue - The resolved default value.\n * @returns A partial yargs option object.\n */\nfunction buildBaseOption(inner: z.ZodTypeAny, defaultValue: unknown): YargsOptions {\n const base: YargsOptions = {}\n const { description } = inner as { description?: string }\n if (description) {\n base.describe = description\n }\n if (defaultValue !== undefined) {\n base.default = defaultValue\n }\n return base\n}\n\n/**\n * Convert a single zod field schema into a complete yargs option definition.\n *\n * @private\n * @param schema - A single zod field type.\n * @returns A complete yargs option object.\n */\nfunction getZodTypeOption(schema: z.ZodTypeAny): YargsOptions {\n const { inner, isOptional, defaultValue } = unwrapZodType(schema)\n const innerDef = (inner as { _def: ZodDef })._def\n const base = {\n ...buildBaseOption(inner, defaultValue),\n type: resolveZodYargsType(innerDef.type),\n }\n if (!isOptional) {\n return { ...base, demandOption: true }\n }\n return base\n}\n","import { err, ok } from '@kidd-cli/utils/fp'\nimport type { Result } from '@kidd-cli/utils/fp'\nimport { formatZodIssues } from '@kidd-cli/utils/validate'\n\nimport type { Command } from '@/types.js'\n\nimport type { ArgsParser } from '../types.js'\nimport { isZodSchema } from './zod.js'\n\n/**\n * Create an args parser that cleans and validates raw parsed arguments.\n *\n * Captures the argument definition in a closure and returns an ArgsParser\n * whose `parse` method strips yargs-internal keys and validates against\n * a zod schema when one is defined.\n *\n * @param argsDef - The argument definition from the command.\n * @returns An ArgsParser with a parse method.\n */\nexport function createArgsParser(argsDef: Command['args']): ArgsParser {\n return {\n parse(rawArgs: Record<string, unknown>): Result<Record<string, unknown>, Error> {\n const cleaned = cleanParsedArgs(rawArgs)\n return validateArgs(argsDef, cleaned)\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Private\n// ---------------------------------------------------------------------------\n\n/**\n * Strip yargs-internal keys (`_`, `$0`) and camelCase-duplicated hyphenated keys\n * from a parsed argv record, returning only user-defined arguments.\n *\n * @private\n * @param argv - Raw parsed argv from yargs.\n * @returns A cleaned record containing only user-defined arguments.\n */\nfunction cleanParsedArgs(argv: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(argv).filter(([key]) => key !== '_' && key !== '$0' && !key.includes('-'))\n )\n}\n\n/**\n * Validate parsed arguments against a zod schema when one is defined.\n *\n * If the command uses yargs-native args (no zod schema), the parsed args are\n * returned as-is. When a zod schema is present, validation is performed and\n * a Result error is returned on failure.\n *\n * @private\n * @param argsDef - The argument definition from the command.\n * @param parsedArgs - The cleaned parsed arguments.\n * @returns A Result containing validated arguments (zod-parsed when applicable).\n */\nfunction validateArgs(\n argsDef: Command['args'],\n parsedArgs: Record<string, unknown>\n): Result<Record<string, unknown>, Error> {\n if (!argsDef || !isZodSchema(argsDef)) {\n return ok(parsedArgs)\n }\n const result = argsDef.safeParse(parsedArgs)\n if (!result.success) {\n return err(new Error(`Invalid arguments:\\n ${formatZodIssues(result.error.issues).message}`))\n }\n return ok(result.data as Record<string, unknown>)\n}\n","import type { Argv, Options as YargsOptions } from 'yargs'\n\nimport type { Command, YargsArgDef } from '@/types.js'\n\nimport { isZodSchema, zodSchemaToYargsOptions } from './zod.js'\n\n/**\n * Register argument definitions on a yargs builder.\n *\n * Accepts either a zod object schema or a record of yargs-native arg definitions\n * and wires them as yargs options on the given builder instance.\n *\n * @param builder - The yargs Argv instance to register options on.\n * @param args - Argument definitions from a Command.\n */\nexport function registerCommandArgs(builder: Argv, args: Command['args']): void {\n if (!args) {\n return\n }\n if (isZodSchema(args)) {\n const options = zodSchemaToYargsOptions(args)\n for (const [key, opt] of Object.entries(options)) {\n builder.option(key, opt)\n }\n } else {\n const argsDef = args as Record<string, YargsArgDef>\n for (const [key, def] of Object.entries(argsDef)) {\n builder.option(key, yargsArgDefToOption(def))\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Private\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a yargs-native arg definition into a yargs option object.\n *\n * @private\n * @param def - The yargs arg definition.\n * @returns A yargs option object.\n */\nfunction yargsArgDefToOption(def: YargsArgDef): YargsOptions {\n return {\n alias: def.alias,\n choices: def.choices as string[],\n default: def.default,\n demandOption: def.required ?? false,\n describe: def.description,\n type: def.type,\n }\n}\n","import { hasTag } from '@kidd-cli/utils/tag'\nimport type { Argv } from 'yargs'\n\nimport type { Context } from '@/context/types.js'\nimport type { Command, CommandMap, Middleware } from '@/types.js'\n\nimport { registerCommandArgs } from './args/index.js'\nimport type { ResolvedCommand, ResolvedRef } from './types.js'\n\n/**\n * Type guard that checks whether a value is a Command object.\n *\n * @param value - The value to test.\n * @returns True when the value has `[TAG] === 'Command'`.\n */\nexport function isCommand(value: unknown): value is Command {\n return hasTag(value, 'Command')\n}\n\n/**\n * Register all commands from a CommandMap on a yargs instance.\n *\n * Iterates over the command map, filters for valid Command objects,\n * and recursively registers each command (including subcommands) on\n * the provided yargs Argv instance.\n *\n * @param options - Registration options including the command map, yargs instance, and resolution ref.\n */\nexport function registerCommands(options: RegisterCommandsOptions): void {\n const { instance, commands, resolved, parentPath } = options\n const commandEntries = Object.entries(commands).filter(([, entry]) => isCommand(entry))\n\n for (const [name, entry] of commandEntries) {\n registerResolvedCommand({\n builder: instance,\n cmd: entry as Command,\n instance,\n name,\n parentPath,\n resolved,\n })\n }\n}\n\nexport type { ResolvedCommand, ResolvedRef } from './types.js'\n\n// ---------------------------------------------------------------------------\n// Private\n// ---------------------------------------------------------------------------\n\ninterface RegisterResolvedCommandOptions {\n builder: Argv\n cmd: Command\n instance: Argv\n name: string\n parentPath: string[]\n resolved: ResolvedRef\n}\n\ninterface RegisterCommandsOptions {\n commands: CommandMap\n instance: Argv\n parentPath: string[]\n resolved: ResolvedRef\n}\n\n/**\n * Register a single resolved command (and its subcommands) with yargs.\n *\n * Sets up the yargs command handler, wires argument definitions, and\n * recursively registers any nested subcommands. On match, stores the\n * resolved handler and command path in the shared ref.\n *\n * @private\n * @param options - Command registration context.\n */\nfunction registerResolvedCommand(options: RegisterResolvedCommandOptions): void {\n const { instance, name, cmd, resolved, parentPath } = options\n const description = cmd.description ?? ''\n\n instance.command(\n name,\n description,\n (builder: Argv) => {\n registerCommandArgs(builder, cmd.args)\n\n if (cmd.commands) {\n const subCommands = Object.entries(cmd.commands).filter(([, entry]) => isCommand(entry))\n\n for (const [subName, subEntry] of subCommands) {\n registerResolvedCommand({\n builder,\n cmd: subEntry as Command,\n instance: builder,\n name: subName,\n parentPath: [...parentPath, name],\n resolved,\n })\n }\n\n if (cmd.handler) {\n builder.demandCommand(0)\n } else {\n builder.demandCommand(1, 'You must specify a subcommand.')\n }\n }\n\n return builder\n },\n () => {\n resolved.ref = {\n args: cmd.args,\n commandPath: [...parentPath, name],\n handler: cmd.handler as ((ctx: Context) => Promise<void> | void) | undefined,\n middleware: (cmd.middleware ?? []) as Middleware[],\n }\n }\n )\n}\n","import type { Context } from '@/context/types.js'\nimport type { Middleware } from '@/types.js'\n\nimport type { Runner } from './types.js'\n\n/**\n * Create a runner that executes root and command middleware chains.\n *\n * Root middleware wraps the command middleware chain, which in turn wraps\n * the command handler — producing a nested onion lifecycle:\n *\n * ```\n * root middleware start →\n * command middleware start →\n * handler\n * command middleware end\n * root middleware end\n * ```\n *\n * @param rootMiddleware - Root-level middleware from `cli({ middleware })`.\n * @returns A Runner with an execute method.\n */\nexport function createRunner(rootMiddleware: Middleware[]): Runner {\n return {\n async execute({ ctx, handler, middleware }): Promise<void> {\n const commandHandler = async (innerCtx: Context): Promise<void> => {\n await runMiddlewareChain(middleware, innerCtx, handler)\n }\n await runMiddlewareChain(rootMiddleware, ctx, commandHandler)\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Private\n// ---------------------------------------------------------------------------\n\n/**\n * Execute a middleware chain followed by a final handler.\n *\n * Runs each middleware in order, passing `ctx` and a `next` callback.\n * When all middleware have called `next()`, the final handler is invoked.\n * A middleware can short-circuit by not calling `next()`.\n *\n * @private\n * @param middlewares - Ordered array of middleware to execute.\n * @param ctx - The context object threaded through middleware and handler.\n * @param finalHandler - The command handler to invoke after all middleware.\n */\nasync function runMiddlewareChain(\n middlewares: Middleware[],\n ctx: Context,\n finalHandler: (ctx: Context) => Promise<void> | void\n): Promise<void> {\n async function executeChain(index: number): Promise<void> {\n if (index >= middlewares.length) {\n await finalHandler(ctx)\n return\n }\n const mw = middlewares[index]\n if (mw) {\n await mw.handler(ctx, () => executeChain(index + 1))\n }\n }\n\n await executeChain(0)\n}\n","import { attemptAsync, err, ok } from '@kidd-cli/utils/fp'\nimport type { AsyncResult } from '@kidd-cli/utils/fp'\nimport type { z } from 'zod'\n\nimport { createContext } from '@/context/index.js'\nimport type { Context } from '@/context/types.js'\nimport { createConfigClient } from '@/lib/config/index.js'\nimport type { CliConfigOptions, Middleware } from '@/types.js'\n\nimport { createArgsParser } from './args/index.js'\nimport { createRunner } from './runner.js'\nimport type { Runtime, RuntimeOptions } from './types.js'\n\n/**\n * Create a runtime that orchestrates config loading and middleware execution.\n *\n * Loads config up front, then captures it in a closure alongside a runner.\n * The returned `runtime.execute` method handles arg parsing, context creation,\n * and middleware chain execution for each command invocation.\n *\n * @param options - Runtime configuration including name, version, config, and middleware.\n * @returns An AsyncResult containing the runtime or an error.\n */\nexport async function createRuntime<TSchema extends z.ZodType>(\n options: RuntimeOptions<TSchema>\n): AsyncResult<Runtime, Error> {\n const config = await resolveConfig(options.config, options.name)\n\n const runner = createRunner((options.middleware ?? []) as Middleware[])\n\n const runtime: Runtime = {\n async execute(command): AsyncResult<void, Error> {\n const parser = createArgsParser(command.args)\n const [argsError, validatedArgs] = parser.parse(command.rawArgs)\n if (argsError) {\n return err(argsError)\n }\n\n const ctx = createContext({\n args: validatedArgs,\n config,\n meta: {\n command: command.commandPath as string[],\n name: options.name,\n version: options.version,\n },\n })\n\n const finalHandler = command.handler ?? (async () => {})\n\n const [execError] = await attemptAsync(() =>\n runner.execute({\n ctx: ctx as Context,\n handler: finalHandler as (ctx: Context) => Promise<void> | void,\n middleware: command.middleware,\n })\n )\n if (execError) {\n return err(execError)\n }\n\n return ok()\n },\n }\n\n return ok(runtime)\n}\n\n// ---------------------------------------------------------------------------\n// Private\n// ---------------------------------------------------------------------------\n\n/**\n * Load and validate a config file via the config client.\n *\n * Returns the validated config record or an empty object when no config\n * options are provided or when loading fails.\n *\n * @private\n * @param configOptions - Config loading options with schema and optional name override.\n * @param defaultName - Fallback config file name derived from the CLI name.\n * @returns The loaded config record or an empty object.\n */\nasync function resolveConfig<TSchema extends z.ZodType>(\n configOptions: CliConfigOptions<TSchema> | undefined,\n defaultName: string\n): Promise<Record<string, unknown>> {\n if (!configOptions || !configOptions.schema) {\n return {}\n }\n const client = createConfigClient({\n name: configOptions.name ?? defaultName,\n schema: configOptions.schema,\n })\n const [configError, configResult] = await client.load()\n if (configError || !configResult) {\n return {}\n }\n return configResult.config as Record<string, unknown>\n}\n","import { resolve } from 'node:path'\n\nimport { loadConfig } from '@kidd-cli/config/loader'\nimport { attemptAsync, isPlainObject, isString } from '@kidd-cli/utils/fp'\nimport yargs from 'yargs'\nimport type { z } from 'zod'\n\nimport { DEFAULT_EXIT_CODE, isContextError } from '@/context/index.js'\nimport { createCliLogger } from '@/lib/logger.js'\nimport type { CliOptions, CommandMap } from '@/types.js'\n\nimport { autoload } from './autoloader.js'\nimport { createRuntime, registerCommands } from './runtime/index.js'\nimport type { ResolvedRef } from './runtime/index.js'\n\nconst ARGV_SLICE_START = 2\n\n/**\n * Bootstrap and run the CLI application.\n *\n * Parses argv, resolves the matched command, loads config, runs the\n * middleware chain, and invokes the command handler.\n *\n * @param options - CLI configuration including name, version, commands, and middleware.\n */\nexport async function cli<TSchema extends z.ZodType = z.ZodType>(\n options: CliOptions<TSchema>\n): Promise<void> {\n const logger = createCliLogger()\n\n const [uncaughtError, result] = await attemptAsync(async () => {\n const program = yargs(process.argv.slice(ARGV_SLICE_START))\n .scriptName(options.name)\n .version(options.version)\n .strict()\n .help()\n .option('cwd', {\n describe: 'Set the working directory',\n global: true,\n type: 'string',\n })\n\n if (options.description) {\n program.usage(options.description)\n }\n\n const resolved: ResolvedRef = { ref: undefined }\n\n const commands = await resolveCommands(options.commands)\n\n if (commands) {\n registerCommands({ commands, instance: program, parentPath: [], resolved })\n program.demandCommand(1, 'You must specify a command.')\n }\n\n const argv = await program.parseAsync()\n\n applyCwd(argv as Record<string, unknown>)\n\n if (!resolved.ref) {\n return undefined\n }\n\n const [runtimeError, runtime] = await createRuntime({\n config: options.config,\n middleware: options.middleware,\n name: options.name,\n version: options.version,\n })\n\n if (runtimeError) {\n return runtimeError\n }\n\n const [executeError] = await runtime.execute({\n args: resolved.ref.args,\n commandPath: resolved.ref.commandPath,\n handler: resolved.ref.handler,\n middleware: resolved.ref.middleware,\n rawArgs: argv as Record<string, unknown>,\n })\n\n return executeError\n })\n\n if (uncaughtError) {\n exitOnError(uncaughtError, logger)\n return\n }\n\n if (result) {\n exitOnError(result, logger)\n }\n}\n\nexport default cli\n\n// ---------------------------------------------------------------------------\n// Private\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the commands option to a CommandMap.\n *\n * Accepts a directory string (triggers autoload), a static CommandMap,\n * a Promise<CommandMap> (from autoload() called at the call site),\n * or undefined (loads `kidd.config.ts` and autoloads from its `commands` field,\n * falling back to `'./commands'`).\n *\n * @private\n * @param commands - The commands option from CliOptions.\n * @returns A CommandMap or undefined.\n */\nasync function resolveCommands(\n commands: string | CommandMap | Promise<CommandMap> | undefined\n): Promise<CommandMap | undefined> {\n if (isString(commands)) {\n return autoload({ dir: commands })\n }\n if (commands instanceof Promise) {\n return commands\n }\n if (isPlainObject(commands)) {\n return commands as CommandMap\n }\n return resolveCommandsFromConfig()\n}\n\n/**\n * Load `kidd.config.ts` and autoload commands from its `commands` field.\n *\n * Falls back to `'./commands'` when the config file is missing, fails to load,\n * or does not specify a `commands` field.\n *\n * @private\n * @returns A CommandMap autoloaded from the configured commands directory.\n */\nasync function resolveCommandsFromConfig(): Promise<CommandMap> {\n const DEFAULT_COMMANDS_DIR = './commands'\n\n const [configError, configResult] = await loadConfig()\n if (configError || !configResult) {\n return autoload({ dir: DEFAULT_COMMANDS_DIR })\n }\n\n const dir = configResult.config.commands ?? DEFAULT_COMMANDS_DIR\n return autoload({ dir })\n}\n\n/**\n * Change the process working directory when `--cwd` is provided.\n *\n * Resolves the value to an absolute path and calls `process.chdir()` so\n * that all downstream `process.cwd()` calls reflect the override.\n *\n * @private\n * @param argv - The parsed argv record from yargs.\n */\nfunction applyCwd(argv: Record<string, unknown>): void {\n if (isString(argv.cwd)) {\n process.chdir(resolve(argv.cwd))\n }\n}\n\n/**\n * Handle a CLI error by logging the message and exiting with the appropriate code.\n *\n * ContextErrors carry a custom exit code; all other errors exit with code 1.\n *\n * @private\n * @param error - The caught error value.\n * @param logger - Logger with an error method for output.\n */\nfunction exitOnError(error: unknown, logger: { error(msg: string): void }): void {\n if (isContextError(error)) {\n logger.error(error.message)\n process.exit(error.exitCode)\n } else if (error instanceof Error) {\n logger.error(error.message)\n process.exit(DEFAULT_EXIT_CODE)\n } else {\n logger.error(String(error))\n process.exit(DEFAULT_EXIT_CODE)\n }\n}\n","import { withTag } from '@kidd-cli/utils/tag'\n\nimport type { ArgsDef, CommandDef, Command as CommandType } from './types.js'\n\n/**\n * Define a CLI command with typed args, config, and handler.\n *\n * @param def - Command definition including description, args schema, and handler.\n * @returns A resolved Command object for registration in the command map.\n */\nexport function command<\n TArgsDef extends ArgsDef = ArgsDef,\n TConfig extends Record<string, unknown> = Record<string, unknown>,\n>(def: CommandDef<TArgsDef, TConfig>): CommandType<TArgsDef, TConfig> {\n return withTag({ ...def }, 'Command')\n}\n"],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import { ZodTypeAny, output } from "zod";
2
+
3
+ //#region src/lib/config/constants.d.ts
4
+ /**
5
+ * Supported configuration file formats.
6
+ */
7
+ type ConfigFormat = "json" | "jsonc" | "yaml";
8
+ //#endregion
9
+ //#region src/lib/config/types.d.ts
10
+ /**
11
+ * Options for creating a config client.
12
+ */
13
+ interface ConfigOptions<TSchema extends ZodTypeAny> {
14
+ name: string;
15
+ schema: TSchema;
16
+ searchPaths?: string[];
17
+ }
18
+ /**
19
+ * Result of loading a config file: the parsed config, its path, and format.
20
+ */
21
+ interface ConfigResult<TConfig> {
22
+ config: TConfig;
23
+ filePath: string;
24
+ format: ConfigFormat;
25
+ }
26
+ /**
27
+ * Options for writing a config file.
28
+ */
29
+ interface ConfigWriteOptions {
30
+ dir?: string;
31
+ format?: ConfigFormat;
32
+ filePath?: string;
33
+ }
34
+ /**
35
+ * Result of writing a config file.
36
+ */
37
+ interface ConfigWriteResult {
38
+ filePath: string;
39
+ format: ConfigFormat;
40
+ }
41
+ /**
42
+ * Result type for config operations.
43
+ */
44
+ type ConfigOperationResult<TResult> = readonly [Error, null] | readonly [null, TResult];
45
+ /**
46
+ * Config client for loading, finding, and writing config files.
47
+ */
48
+ interface Config<TConfig> {
49
+ load(cwd?: string): Promise<ConfigOperationResult<ConfigResult<TConfig>> | readonly [null, null]>;
50
+ find(cwd?: string): Promise<string | null>;
51
+ write(data: TConfig, options?: ConfigWriteOptions): Promise<ConfigOperationResult<ConfigWriteResult>>;
52
+ }
53
+ //#endregion
54
+ //#region src/lib/config/create-config.d.ts
55
+ /**
56
+ * Create a typed config client that loads, validates, and writes config files.
57
+ *
58
+ * @param options - Config client options including name and Zod schema.
59
+ * @returns A {@link Config} client instance.
60
+ */
61
+ declare function createConfigClient<TSchema extends ZodTypeAny>(options: ConfigOptions<TSchema>): Config<output<TSchema>>;
62
+ //#endregion
63
+ export { type Config, type ConfigFormat, type ConfigOperationResult, type ConfigOptions, type ConfigResult, type ConfigWriteOptions, type ConfigWriteResult, createConfigClient };
64
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","names":[],"sources":["../../src/lib/config/constants.ts","../../src/lib/config/types.ts","../../src/lib/config/create-config.ts"],"mappings":";;;;;;KAGY,YAAA;;;;AAAZ;;UCIiB,aAAA,iBAA8B,UAAA;EAC7C,IAAA;EACA,MAAA,EAAQ,OAAA;EACR,WAAA;AAAA;;AAHF;;UASiB,YAAA;EACf,MAAA,EAAQ,OAAA;EACR,QAAA;EACA,MAAA,EAAQ,YAAA;AAAA;;;;UAMO,kBAAA;EACf,GAAA;EACA,MAAA,GAAS,YAAA;EACT,QAAA;AAAA;;;;UAMe,iBAAA;EACf,QAAA;EACA,MAAA,EAAQ,YAAA;AAAA;;;AAXV;KAiBY,qBAAA,sBAA2C,KAAA,0BAA+B,OAAA;;;;UAKrE,MAAA;EACf,IAAA,CAAK,GAAA,YAAe,OAAA,CAAQ,qBAAA,CAAsB,YAAA,CAAa,OAAA;EAC/D,IAAA,CAAK,GAAA,YAAe,OAAA;EACpB,KAAA,CACE,IAAA,EAAM,OAAA,EACN,OAAA,GAAU,kBAAA,GACT,OAAA,CAAQ,qBAAA,CAAsB,iBAAA;AAAA;;;;ADlDnC;;;;;iBEqBgB,kBAAA,iBAAmC,UAAA,CAAA,CACjD,OAAA,EAAS,aAAA,CAAc,OAAA,IACtB,MAAA,CAAO,MAAA,CAAO,OAAA"}
@@ -0,0 +1,4 @@
1
+ import { t as createConfigClient } from "../config-BvGapuFJ.js";
2
+ import "../project-NPtYX2ZX.js";
3
+
4
+ export { createConfigClient };
@@ -0,0 +1,2 @@
1
+ import { i as createCliLogger, n as CliLoggerOptions, r as cliLogger, t as CliLogger } from "../logger-BkQQej8h.js";
2
+ export { CliLogger, CliLoggerOptions, cliLogger, createCliLogger };
@@ -0,0 +1,55 @@
1
+ import * as clack from "@clack/prompts";
2
+
3
+ //#region src/lib/logger.ts
4
+ /**
5
+ * Create a new {@link CliLogger} instance.
6
+ *
7
+ * @param options - Logger configuration.
8
+ * @returns A CliLogger wired to the given output stream.
9
+ */
10
+ function createCliLogger(options = {}) {
11
+ const output = options.output ?? process.stderr;
12
+ return {
13
+ error(message) {
14
+ clack.log.error(message);
15
+ },
16
+ info(message) {
17
+ clack.log.info(message);
18
+ },
19
+ intro(title) {
20
+ clack.intro(title);
21
+ },
22
+ message(message, opts) {
23
+ clack.log.message(message, opts);
24
+ },
25
+ newline() {
26
+ output.write("\n");
27
+ },
28
+ note(message, title) {
29
+ clack.note(message, title);
30
+ },
31
+ outro(message) {
32
+ clack.outro(message);
33
+ },
34
+ print(text) {
35
+ output.write(`${text}\n`);
36
+ },
37
+ step(message) {
38
+ clack.log.step(message);
39
+ },
40
+ success(message) {
41
+ clack.log.success(message);
42
+ },
43
+ warn(message) {
44
+ clack.log.warn(message);
45
+ }
46
+ };
47
+ }
48
+ /**
49
+ * Default logger instance writing to stderr.
50
+ */
51
+ const cliLogger = createCliLogger();
52
+
53
+ //#endregion
54
+ export { cliLogger, createCliLogger };
55
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../../src/lib/logger.ts"],"sourcesContent":["import * as clack from '@clack/prompts'\n\n/**\n * Options for creating a logger instance.\n */\nexport interface CliLoggerOptions {\n /**\n * Writable stream for raw output methods like {@link CliLogger.print} and {@link CliLogger.newline}.\n * Defaults to `process.stderr`.\n */\n readonly output?: NodeJS.WriteStream\n}\n\n/**\n * Structured logger backed by @clack/prompts for terminal UI output.\n */\nexport interface CliLogger {\n /**\n * Log an informational message.\n */\n info(message: string): void\n /**\n * Log a success message.\n */\n success(message: string): void\n /**\n * Log an error message.\n */\n error(message: string): void\n /**\n * Log a warning message.\n */\n warn(message: string): void\n /**\n * Log a step indicator message.\n */\n step(message: string): void\n /**\n * Log a message with an optional custom symbol prefix.\n */\n message(message: string, opts?: { symbol?: string }): void\n /**\n * Print an intro banner with an optional title.\n */\n intro(title?: string): void\n /**\n * Print an outro banner with an optional closing message.\n */\n outro(message?: string): void\n /**\n * Display a boxed note with an optional title.\n */\n note(message?: string, title?: string): void\n /**\n * Write a blank line to the output stream.\n */\n newline(): void\n /**\n * Write raw text followed by a newline to the output stream.\n */\n print(text: string): void\n}\n\n/**\n * Create a new {@link CliLogger} instance.\n *\n * @param options - Logger configuration.\n * @returns A CliLogger wired to the given output stream.\n */\nexport function createCliLogger(options: CliLoggerOptions = {}): CliLogger {\n const output = options.output ?? process.stderr\n\n return {\n error(message: string): void {\n clack.log.error(message)\n },\n info(message: string): void {\n clack.log.info(message)\n },\n intro(title?: string): void {\n clack.intro(title)\n },\n message(message: string, opts?: { symbol?: string }): void {\n clack.log.message(message, opts)\n },\n newline(): void {\n output.write('\\n')\n },\n note(message?: string, title?: string): void {\n clack.note(message, title)\n },\n outro(message?: string): void {\n clack.outro(message)\n },\n print(text: string): void {\n output.write(`${text}\\n`)\n },\n step(message: string): void {\n clack.log.step(message)\n },\n success(message: string): void {\n clack.log.success(message)\n },\n warn(message: string): void {\n clack.log.warn(message)\n },\n }\n}\n\n/**\n * Default logger instance writing to stderr.\n */\nexport const cliLogger: CliLogger = createCliLogger()\n"],"mappings":";;;;;;;;;AAqEA,SAAgB,gBAAgB,UAA4B,EAAE,EAAa;CACzE,MAAM,SAAS,QAAQ,UAAU,QAAQ;AAEzC,QAAO;EACL,MAAM,SAAuB;AAC3B,SAAM,IAAI,MAAM,QAAQ;;EAE1B,KAAK,SAAuB;AAC1B,SAAM,IAAI,KAAK,QAAQ;;EAEzB,MAAM,OAAsB;AAC1B,SAAM,MAAM,MAAM;;EAEpB,QAAQ,SAAiB,MAAkC;AACzD,SAAM,IAAI,QAAQ,SAAS,KAAK;;EAElC,UAAgB;AACd,UAAO,MAAM,KAAK;;EAEpB,KAAK,SAAkB,OAAsB;AAC3C,SAAM,KAAK,SAAS,MAAM;;EAE5B,MAAM,SAAwB;AAC5B,SAAM,MAAM,QAAQ;;EAEtB,MAAM,MAAoB;AACxB,UAAO,MAAM,GAAG,KAAK,IAAI;;EAE3B,KAAK,SAAuB;AAC1B,SAAM,IAAI,KAAK,QAAQ;;EAEzB,QAAQ,SAAuB;AAC7B,SAAM,IAAI,QAAQ,QAAQ;;EAE5B,KAAK,SAAuB;AAC1B,SAAM,IAAI,KAAK,QAAQ;;EAE1B;;;;;AAMH,MAAa,YAAuB,iBAAiB"}
@@ -0,0 +1,62 @@
1
+ import { Result } from "@kidd-cli/utils/fp";
2
+ import { Liquid } from "liquidjs";
3
+
4
+ //#region src/lib/output/types.d.ts
5
+ /**
6
+ * Options for JSON serialization output.
7
+ */
8
+ interface JsonOutputOptions {
9
+ pretty?: boolean;
10
+ redact?: boolean;
11
+ }
12
+ /**
13
+ * Parameters for writing content to a file.
14
+ */
15
+ interface WriteParams {
16
+ path: string;
17
+ content: string;
18
+ }
19
+ /**
20
+ * Parameters for rendering data to markdown via a Liquid template.
21
+ */
22
+ interface ToMarkdownParams {
23
+ data: unknown;
24
+ type: string;
25
+ }
26
+ /**
27
+ * Options for creating an output instance.
28
+ */
29
+ interface CreateOutputOptions {
30
+ output?: NodeJS.WriteStream;
31
+ templates?: string;
32
+ filters?: Record<string, (...args: unknown[]) => unknown>;
33
+ context?: (params: ToMarkdownParams) => Record<string, unknown>;
34
+ }
35
+ /**
36
+ * Structured output utilities for JSON, markdown, and file writing.
37
+ */
38
+ interface CliOutput {
39
+ toJson(data: unknown, options?: JsonOutputOptions): string;
40
+ toMarkdown(params: ToMarkdownParams): Result<string, Error>;
41
+ json(data: unknown, options?: JsonOutputOptions): void;
42
+ write(params: WriteParams): Result<void, Error>;
43
+ print(content: string): void;
44
+ }
45
+ //#endregion
46
+ //#region src/lib/output/create-output.d.ts
47
+ /**
48
+ * Create a new {@link CliOutput} instance for structured CLI output.
49
+ *
50
+ * @param options - Output configuration.
51
+ * @returns A CliOutput instance.
52
+ */
53
+ declare function createOutput(options?: CreateOutputOptions): CliOutput;
54
+ //#endregion
55
+ //#region src/lib/output/defaults.d.ts
56
+ /**
57
+ * Default output instance writing to stdout.
58
+ */
59
+ declare const output: CliOutput;
60
+ //#endregion
61
+ export { type CliOutput, type CreateOutputOptions, type JsonOutputOptions, type ToMarkdownParams, type WriteParams, createOutput, output };
62
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","names":[],"sources":["../../src/lib/output/types.ts","../../src/lib/output/create-output.ts","../../src/lib/output/defaults.ts"],"mappings":";;;;;;AAMA;UAAiB,iBAAA;EACf,MAAA;EACA,MAAA;AAAA;AAMF;;;AAAA,UAAiB,WAAA;EACf,IAAA;EACA,OAAA;AAAA;;;;UAMe,gBAAA;EACf,IAAA;EACA,IAAA;AAAA;;;;UAMe,mBAAA;EACf,MAAA,GAAS,MAAA,CAAO,WAAA;EAChB,SAAA;EACA,OAAA,GAAU,MAAA,aAAmB,IAAA;EAC7B,OAAA,IAAW,MAAA,EAAQ,gBAAA,KAAqB,MAAA;AAAA;;;;UAMzB,SAAA;EACf,MAAA,CAAO,IAAA,WAAe,OAAA,GAAU,iBAAA;EAChC,UAAA,CAAW,MAAA,EAAQ,gBAAA,GAAmB,MAAA,SAAe,KAAA;EACrD,IAAA,CAAK,IAAA,WAAe,OAAA,GAAU,iBAAA;EAC9B,KAAA,CAAM,MAAA,EAAQ,WAAA,GAAc,MAAA,OAAa,KAAA;EACzC,KAAA,CAAM,OAAA;AAAA;;;;;;AAvCR;;;iBCegB,YAAA,CAAa,OAAA,GAAS,mBAAA,GAA2B,SAAA;;;;;;cCfpD,MAAA,EAAQ,SAAA"}
@@ -0,0 +1,276 @@
1
+ import { createCliLogger } from "./logger.js";
2
+ import path from "node:path";
3
+ import { attempt, err, ok } from "@kidd-cli/utils/fp";
4
+ import { jsonStringify } from "@kidd-cli/utils/json";
5
+ import fs from "node:fs";
6
+ import pinoRedact from "@pinojs/redact";
7
+ import { Liquid } from "liquidjs";
8
+
9
+ //#region src/context/redact.ts
10
+ const CENSOR = "[REDACTED]";
11
+ /**
12
+ * Keys that are always redacted regardless of their depth in the object tree.
13
+ */
14
+ const SENSITIVE_KEYS = new Set([
15
+ "password",
16
+ "secret",
17
+ "token",
18
+ "apiKey",
19
+ "api_key",
20
+ "apiSecret",
21
+ "api_secret",
22
+ "authorization",
23
+ "auth",
24
+ "credentials",
25
+ "private_key",
26
+ "privateKey"
27
+ ]);
28
+ const redactPaths = pinoRedact({
29
+ censor: resolveCensor,
30
+ paths: [...[
31
+ "headers.Authorization",
32
+ "env.GITHUB_TOKEN",
33
+ "env.LINEAR_API_KEY"
34
+ ]],
35
+ serialize: false
36
+ });
37
+ /**
38
+ * Censor function for `@pinojs/redact` that preserves null/undefined values.
39
+ *
40
+ * @private
41
+ * @param value - The original value at a redacted path.
42
+ * @returns The censor string or the original null/undefined.
43
+ */
44
+ function resolveCensor(value) {
45
+ if (value === null || value === void 0) return value;
46
+ return CENSOR;
47
+ }
48
+ /**
49
+ * Deep-clone an object and replace values at sensitive key paths with `[REDACTED]`.
50
+ *
51
+ * Uses `@pinojs/redact` for specific fixed paths and a recursive walk for
52
+ * any-depth key-name matching against {@link SENSITIVE_KEYS}.
53
+ *
54
+ * @param obj - The object to redact.
55
+ * @returns A deep clone with sensitive values replaced.
56
+ */
57
+ function redactObject(obj) {
58
+ return redactSensitiveKeys(redactPaths(obj));
59
+ }
60
+ /**
61
+ * Recursively walk an object and redact values whose key is in {@link SENSITIVE_KEYS}.
62
+ * Returns a new object — does not mutate the input.
63
+ *
64
+ * @private
65
+ * @param target - The record to walk.
66
+ * @returns A new record with sensitive values replaced.
67
+ */
68
+ function redactSensitiveKeys(target) {
69
+ return Object.fromEntries(Object.entries(target).filter(([key]) => key !== "restore").map(([key, value]) => redactEntry(key, value)));
70
+ }
71
+ /**
72
+ * Process a single key-value entry for sensitive-key redaction.
73
+ *
74
+ * @private
75
+ * @param key - The property key.
76
+ * @param value - The property value.
77
+ * @returns A [key, value] tuple with the value potentially redacted.
78
+ */
79
+ function redactEntry(key, value) {
80
+ if (SENSITIVE_KEYS.has(key) && value !== void 0 && value !== null) return [key, CENSOR];
81
+ if (Array.isArray(value)) return [key, value.map(redactArrayItem)];
82
+ if (value && typeof value === "object") return [key, redactSensitiveKeys(value)];
83
+ return [key, value];
84
+ }
85
+ /**
86
+ * Redact sensitive keys within an array item if it is an object.
87
+ *
88
+ * @private
89
+ * @param item - The array element.
90
+ * @returns The element with sensitive keys redacted, or the original primitive.
91
+ */
92
+ function redactArrayItem(item) {
93
+ if (item && typeof item === "object") return redactSensitiveKeys(item);
94
+ return item;
95
+ }
96
+
97
+ //#endregion
98
+ //#region src/lib/output/renderer.ts
99
+ /**
100
+ * Resolve an unknown error to a string message.
101
+ *
102
+ * @param error - The error to resolve.
103
+ * @returns A string error message.
104
+ */
105
+ function resolveRenderError(error) {
106
+ if (error instanceof Error) return error.message;
107
+ return "Unknown error";
108
+ }
109
+ /**
110
+ * Create a Liquid template {@link Renderer}.
111
+ *
112
+ * @param options - Renderer configuration.
113
+ * @returns A Renderer instance.
114
+ */
115
+ function createRenderer(options) {
116
+ const { templates: templatesDir, filters = {}, context } = options;
117
+ const liquid = new Liquid();
118
+ const templateCache = /* @__PURE__ */ new Map();
119
+ for (const [name, fn] of Object.entries(filters)) liquid.registerFilter(name, fn);
120
+ return { render(params) {
121
+ const [templateError, template] = loadTemplateFromDisk({
122
+ cache: templateCache,
123
+ templatesDir,
124
+ type: params.type
125
+ });
126
+ if (templateError) return [templateError, null];
127
+ return renderTemplate({
128
+ extraContext: resolveExtraContext(context, params),
129
+ liquid,
130
+ params,
131
+ template
132
+ });
133
+ } };
134
+ }
135
+ /**
136
+ * Resolve the full filesystem path to a Liquid template file.
137
+ *
138
+ * @private
139
+ */
140
+ function resolveTemplatePath(templatesDir, type) {
141
+ const segments = type.split(":");
142
+ return `${path.join(templatesDir, ...segments)}.liquid`;
143
+ }
144
+ /**
145
+ * Load a Liquid template from disk, using a cache to avoid redundant reads.
146
+ *
147
+ * @private
148
+ */
149
+ function loadTemplateFromDisk(options) {
150
+ const { templatesDir, type, cache } = options;
151
+ const cached = cache.get(type);
152
+ if (cached !== void 0) return ok(cached);
153
+ const templatePath = resolveTemplatePath(templatesDir, type);
154
+ const [error, content] = attempt(() => fs.readFileSync(templatePath, "utf8"));
155
+ if (error || content === null) return err(/* @__PURE__ */ new Error(`Template not found for type '${type}': ${templatePath}`));
156
+ cache.set(type, content);
157
+ return ok(content);
158
+ }
159
+ /**
160
+ * Resolve additional template context from the user-provided context function.
161
+ *
162
+ * @private
163
+ */
164
+ function resolveExtraContext(context, params) {
165
+ if (context) return context(params);
166
+ return {};
167
+ }
168
+ /**
169
+ * Render a Liquid template with the given parameters and context.
170
+ *
171
+ * @private
172
+ */
173
+ function renderTemplate(options) {
174
+ const { liquid, template, params, extraContext } = options;
175
+ const [error, result] = attempt(() => liquid.parseAndRenderSync(template, {
176
+ ...params.data,
177
+ ...extraContext
178
+ }));
179
+ if (error || result === void 0) {
180
+ const errorMessage = resolveRenderError(error);
181
+ return err(/* @__PURE__ */ new Error(`Failed to render template for ${params.type}: ${errorMessage}`));
182
+ }
183
+ return ok(result);
184
+ }
185
+
186
+ //#endregion
187
+ //#region src/lib/output/format.ts
188
+ /**
189
+ * Serialize data to a JSON string.
190
+ *
191
+ * @param data - The data to serialize.
192
+ * @param opts - JSON output options.
193
+ * @returns The JSON string.
194
+ */
195
+ function formatJson(data, opts = {}) {
196
+ const { pretty = true, redact = false } = opts;
197
+ const [, json] = jsonStringify(resolveProcessed(data, redact), { pretty });
198
+ return json || "";
199
+ }
200
+ /**
201
+ * Write content to a file on disk, creating parent directories as needed.
202
+ *
203
+ * @param params - Write parameters (path and content).
204
+ * @returns A Result indicating success or failure.
205
+ */
206
+ function writeToFile(params) {
207
+ const [error] = attempt(() => {
208
+ fs.mkdirSync(path.dirname(params.path), { recursive: true });
209
+ fs.writeFileSync(params.path, params.content, "utf8");
210
+ });
211
+ if (error) {
212
+ const errorMessage = resolveRenderError(error);
213
+ return err(/* @__PURE__ */ new Error(`Failed to write file ${params.path}: ${errorMessage}`));
214
+ }
215
+ return ok();
216
+ }
217
+ /**
218
+ * Resolve the processed data, optionally redacting sensitive fields.
219
+ *
220
+ * @private
221
+ */
222
+ function resolveProcessed(data, redact) {
223
+ if (redact && data && typeof data === "object") return redactObject(data);
224
+ return data;
225
+ }
226
+
227
+ //#endregion
228
+ //#region src/lib/output/create-output.ts
229
+ /**
230
+ * Create a new {@link CliOutput} instance for structured CLI output.
231
+ *
232
+ * @param options - Output configuration.
233
+ * @returns A CliOutput instance.
234
+ */
235
+ function createOutput(options = {}) {
236
+ const logger = createCliLogger({ output: options.output ?? process.stdout });
237
+ const renderer = resolveRenderer(options);
238
+ function toMarkdown(params) {
239
+ if (!renderer) return err(/* @__PURE__ */ new Error("Templates directory not configured. Pass `templates` to createOutput()."));
240
+ return renderer.render(params);
241
+ }
242
+ return {
243
+ json(data, jsonOptions = {}) {
244
+ logger.print(formatJson(data, jsonOptions));
245
+ },
246
+ print(content) {
247
+ logger.print(content);
248
+ },
249
+ toJson: formatJson,
250
+ toMarkdown,
251
+ write: writeToFile
252
+ };
253
+ }
254
+ /**
255
+ * Resolve a Renderer from the output options, if templates are configured.
256
+ *
257
+ * @private
258
+ */
259
+ function resolveRenderer(options) {
260
+ if (options.templates) return createRenderer({
261
+ context: options.context,
262
+ filters: options.filters,
263
+ templates: options.templates
264
+ });
265
+ }
266
+
267
+ //#endregion
268
+ //#region src/lib/output/defaults.ts
269
+ /**
270
+ * Default output instance writing to stdout.
271
+ */
272
+ const output = createOutput();
273
+
274
+ //#endregion
275
+ export { createOutput, output };
276
+ //# sourceMappingURL=output.js.map