@maltty/cli 1.0.0-rc.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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/bin/maltty.js +3 -0
  4. package/dist/_format-CeQhQTl5.js +23 -0
  5. package/dist/_format-CeQhQTl5.js.map +1 -0
  6. package/dist/attemptAsync-BdXzRSIT.js +42 -0
  7. package/dist/attemptAsync-BdXzRSIT.js.map +1 -0
  8. package/dist/chunk-DsIazq42.js +26 -0
  9. package/dist/commands/add/command.d.ts +7 -0
  10. package/dist/commands/add/command.d.ts.map +1 -0
  11. package/dist/commands/add/command.js +123 -0
  12. package/dist/commands/add/command.js.map +1 -0
  13. package/dist/commands/add/config.d.ts +7 -0
  14. package/dist/commands/add/config.d.ts.map +1 -0
  15. package/dist/commands/add/config.js +57 -0
  16. package/dist/commands/add/config.js.map +1 -0
  17. package/dist/commands/add/index.d.ts +7 -0
  18. package/dist/commands/add/index.d.ts.map +1 -0
  19. package/dist/commands/add/index.js +7 -0
  20. package/dist/commands/add/index.js.map +1 -0
  21. package/dist/commands/add/middleware.d.ts +7 -0
  22. package/dist/commands/add/middleware.d.ts.map +1 -0
  23. package/dist/commands/add/middleware.js +88 -0
  24. package/dist/commands/add/middleware.js.map +1 -0
  25. package/dist/commands/build.d.ts +15 -0
  26. package/dist/commands/build.d.ts.map +1 -0
  27. package/dist/commands/build.js +246 -0
  28. package/dist/commands/build.js.map +1 -0
  29. package/dist/commands/commands.d.ts +14 -0
  30. package/dist/commands/commands.d.ts.map +1 -0
  31. package/dist/commands/commands.js +189 -0
  32. package/dist/commands/commands.js.map +1 -0
  33. package/dist/commands/dev.d.ts +13 -0
  34. package/dist/commands/dev.d.ts.map +1 -0
  35. package/dist/commands/dev.js +58 -0
  36. package/dist/commands/dev.js.map +1 -0
  37. package/dist/commands/doctor.d.ts +13 -0
  38. package/dist/commands/doctor.d.ts.map +1 -0
  39. package/dist/commands/doctor.js +658 -0
  40. package/dist/commands/doctor.js.map +1 -0
  41. package/dist/commands/init.d.ts +7 -0
  42. package/dist/commands/init.d.ts.map +1 -0
  43. package/dist/commands/init.js +305 -0
  44. package/dist/commands/init.js.map +1 -0
  45. package/dist/commands/run.d.ts +19 -0
  46. package/dist/commands/run.d.ts.map +1 -0
  47. package/dist/commands/run.js +478 -0
  48. package/dist/commands/run.js.map +1 -0
  49. package/dist/commands/stories.d.ts +11 -0
  50. package/dist/commands/stories.d.ts.map +1 -0
  51. package/dist/commands/stories.js +22 -0
  52. package/dist/commands/stories.js.map +1 -0
  53. package/dist/config-helpers-pv_2Spux.js +15 -0
  54. package/dist/config-helpers-pv_2Spux.js.map +1 -0
  55. package/dist/defu-BBwssjW3.js +192 -0
  56. package/dist/defu-BBwssjW3.js.map +1 -0
  57. package/dist/detect-AOq1ehTE.js +61 -0
  58. package/dist/detect-AOq1ehTE.js.map +1 -0
  59. package/dist/dist-DW_gRP7_.js +1119 -0
  60. package/dist/dist-DW_gRP7_.js.map +1 -0
  61. package/dist/dist-Xa07jNxS.js +15617 -0
  62. package/dist/dist-Xa07jNxS.js.map +1 -0
  63. package/dist/index.d.ts +1 -0
  64. package/dist/index.js +46 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/jiti-CxWlVmZ_.js +5458 -0
  67. package/dist/jiti-CxWlVmZ_.js.map +1 -0
  68. package/dist/json-D7WbuVK1.js +43 -0
  69. package/dist/json-D7WbuVK1.js.map +1 -0
  70. package/dist/json5-z-PGDMyy.js +777 -0
  71. package/dist/json5-z-PGDMyy.js.map +1 -0
  72. package/dist/jsonc-DqZkfC3S.js +401 -0
  73. package/dist/jsonc-DqZkfC3S.js.map +1 -0
  74. package/dist/jsonc-KADMdSjU.js +2 -0
  75. package/dist/lib/templates/command/command.ts.liquid +12 -0
  76. package/dist/lib/templates/config/config.ts.liquid +16 -0
  77. package/dist/lib/templates/middleware/middleware.ts.liquid +9 -0
  78. package/dist/lib/templates/project/gitignore.liquid +3 -0
  79. package/dist/lib/templates/project/maltty.config.ts.liquid +6 -0
  80. package/dist/lib/templates/project/package.json.liquid +30 -0
  81. package/dist/lib/templates/project/src/commands/hello.ts.liquid +12 -0
  82. package/dist/lib/templates/project/src/config.ts.liquid +16 -0
  83. package/dist/lib/templates/project/src/index.ts.liquid +13 -0
  84. package/dist/lib/templates/project/tsconfig.json.liquid +19 -0
  85. package/dist/lib/templates/project/vitest.config.ts.liquid +8 -0
  86. package/dist/main-C_8x2aB3.js +274 -0
  87. package/dist/main-C_8x2aB3.js.map +1 -0
  88. package/dist/manifest-BIKVDJML.js +112 -0
  89. package/dist/manifest-BIKVDJML.js.map +1 -0
  90. package/dist/multipart-parser-MNkxNO83.js +174 -0
  91. package/dist/multipart-parser-MNkxNO83.js.map +1 -0
  92. package/dist/node-C91xGGqn.js +644 -0
  93. package/dist/node-C91xGGqn.js.map +1 -0
  94. package/dist/node-Drmc03fL.js +3973 -0
  95. package/dist/node-Drmc03fL.js.map +1 -0
  96. package/dist/ohash-BPoV4zBH.js +185 -0
  97. package/dist/ohash-BPoV4zBH.js.map +1 -0
  98. package/dist/pnpm-workspace.yaml +26 -0
  99. package/dist/toml-LuHsHQtV.js +646 -0
  100. package/dist/toml-LuHsHQtV.js.map +1 -0
  101. package/dist/utils-DlIJNGLQ.js +1905 -0
  102. package/dist/utils-DlIJNGLQ.js.map +1 -0
  103. package/dist/validate-C_SXBoLq.js +18 -0
  104. package/dist/validate-C_SXBoLq.js.map +1 -0
  105. package/dist/write-CSwG4Stj.js +152 -0
  106. package/dist/write-CSwG4Stj.js.map +1 -0
  107. package/dist/yaml-BS9RDuUr.js +1067 -0
  108. package/dist/yaml-BS9RDuUr.js.map +1 -0
  109. package/package.json +65 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","names":["fs","match"],"sources":["../../src/lib/checks.ts","../../src/commands/doctor.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path'\n\nimport { DEFAULT_COMMANDS, DEFAULT_ENTRY } from '@maltty/bundler'\nimport type { LoadConfigResult } from '@maltty/config/utils'\nimport { err, ok } from '@maltty/utils/fp'\nimport type { ResultAsync } from '@maltty/utils/fp'\nimport { jsonParse, jsonStringify } from '@maltty/utils/json'\nimport type { Manifest } from '@maltty/utils/manifest'\nimport { fs } from '@maltty/utils/node'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Outcome status for a single diagnostic check.\n */\nexport type CheckStatus = 'fail' | 'pass' | 'warn'\n\n/**\n * The result of running a single diagnostic check.\n */\nexport interface CheckResult {\n readonly name: string\n readonly status: CheckStatus\n readonly message: string\n readonly hint: string | null\n}\n\n/**\n * The result of running an auto-fix for a diagnostic check.\n */\nexport interface FixResult {\n readonly name: string\n readonly fixed: boolean\n readonly message: string\n}\n\n/**\n * A named diagnostic check with an async runner and optional fix.\n */\nexport interface DiagnosticCheck {\n readonly name: string\n readonly run: (context: CheckContext) => Promise<CheckResult>\n readonly fix?: (context: CheckContext) => Promise<FixResult>\n}\n\n/**\n * Context shared across all diagnostic checks.\n */\nexport interface CheckContext {\n readonly cwd: string\n readonly configResult: LoadConfigResult | null\n readonly configError: Error | null\n readonly manifest: Manifest | null\n readonly rawPackageJson: RawPackageJson | null\n}\n\n/**\n * Minimal package.json shape for fields not exposed by Manifest.\n */\nexport interface RawPackageJson {\n readonly type?: string\n readonly dependencies?: Readonly<Record<string, string>>\n readonly devDependencies?: Readonly<Record<string, string>>\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a CheckContext from the gathered project data.\n *\n * @param params - The context parameters.\n * @returns A frozen CheckContext.\n */\nexport function createCheckContext(params: {\n readonly cwd: string\n readonly configResult: LoadConfigResult | null\n readonly configError: Error | null\n readonly manifest: Manifest | null\n readonly rawPackageJson: RawPackageJson | null\n}): CheckContext {\n return {\n configError: params.configError,\n configResult: params.configResult,\n cwd: params.cwd,\n manifest: params.manifest,\n rawPackageJson: params.rawPackageJson,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Result helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Create a CheckResult with the given status.\n *\n * @private\n * @param params - The check result parameters.\n * @returns A CheckResult.\n */\nfunction checkResult(params: {\n readonly name: string\n readonly status: CheckStatus\n readonly message: string\n readonly hint?: string | null\n}): CheckResult {\n return {\n hint: params.hint ?? null,\n message: params.message,\n name: params.name,\n status: params.status,\n }\n}\n\n/**\n * Create a FixResult.\n *\n * @private\n * @param params - The fix result parameters.\n * @returns A FixResult.\n */\nfunction fixResult(params: {\n readonly name: string\n readonly fixed: boolean\n readonly message: string\n}): FixResult {\n return {\n fixed: params.fixed,\n message: params.message,\n name: params.name,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Checks\n// ---------------------------------------------------------------------------\n\n/**\n * Check whether a maltty config file exists.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass or fail.\n */\nasync function checkMalttyConfig(context: CheckContext): Promise<CheckResult> {\n if (context.configResult && context.configResult.configFile) {\n const rel = relative(context.cwd, context.configResult.configFile)\n return checkResult({\n message: `Config file found at ./${rel}`,\n name: 'maltty.config',\n status: 'pass',\n })\n }\n\n return checkResult({\n hint: 'Run \"maltty init\" to scaffold a config file',\n message: 'No config file found',\n name: 'maltty.config',\n status: 'fail',\n })\n}\n\n/**\n * Check whether the loaded config schema is valid.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass, warn, or fail.\n */\nasync function checkConfigSchema(context: CheckContext): Promise<CheckResult> {\n if (context.configResult) {\n return checkResult({ message: 'Config is valid', name: 'config schema', status: 'pass' })\n }\n\n if (context.configError) {\n return checkResult({\n hint: 'Check your maltty.config.ts for syntax or schema errors',\n message: `Config validation failed: ${context.configError.message}`,\n name: 'config schema',\n status: 'fail',\n })\n }\n\n return checkResult({\n message: 'No config file, using defaults',\n name: 'config schema',\n status: 'warn',\n })\n}\n\n/**\n * Check whether package.json exists in the project.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass or fail.\n */\nasync function checkPackageJson(context: CheckContext): Promise<CheckResult> {\n if (context.rawPackageJson) {\n return checkResult({ message: 'Found', name: 'package.json', status: 'pass' })\n }\n\n return checkResult({\n hint: 'Run \"pnpm init\" to create a package.json',\n message: 'Not found',\n name: 'package.json',\n status: 'fail',\n })\n}\n\n/**\n * Check whether the package.json has a version field.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass or warn.\n */\nasync function checkPackageVersion(context: CheckContext): Promise<CheckResult> {\n if (context.manifest && context.manifest.version) {\n return checkResult({\n message: context.manifest.version,\n name: 'package version',\n status: 'pass',\n })\n }\n\n return checkResult({\n hint: 'Add a \"version\" field to package.json',\n message: 'No version field',\n name: 'package version',\n status: 'warn',\n })\n}\n\n/**\n * Check whether the package.json declares ESM via `\"type\": \"module\"`.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass or fail.\n */\nasync function checkModuleType(context: CheckContext): Promise<CheckResult> {\n if (context.rawPackageJson && context.rawPackageJson.type === 'module') {\n return checkResult({ message: 'ESM (\"type\": \"module\")', name: 'module type', status: 'pass' })\n }\n\n return checkResult({\n hint: 'Add \"type\": \"module\" to package.json (fixable with --fix)',\n message: 'Missing or wrong \"type\" field (expected \"module\")',\n name: 'module type',\n status: 'fail',\n })\n}\n\n/**\n * Check whether maltty is listed as a dependency or devDependency.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass or fail.\n */\nasync function checkMalttyDependency(context: CheckContext): Promise<CheckResult> {\n if (!context.rawPackageJson) {\n return checkResult({\n hint: 'Run \"pnpm init\" to create a package.json first',\n message: 'No package.json found',\n name: 'maltty dependency',\n status: 'fail',\n })\n }\n\n const deps = context.rawPackageJson.dependencies ?? {}\n const devDeps = context.rawPackageJson.devDependencies ?? {}\n\n if ('maltty' in deps) {\n return checkResult({\n message: 'Found in dependencies',\n name: 'maltty dependency',\n status: 'pass',\n })\n }\n\n if ('maltty' in devDeps) {\n return checkResult({\n message: 'Found in devDependencies',\n name: 'maltty dependency',\n status: 'pass',\n })\n }\n\n return checkResult({\n hint: 'Run \"pnpm add maltty\" or use --fix to add it (fixable with --fix)',\n message: 'Not found in dependencies or devDependencies',\n name: 'maltty dependency',\n status: 'fail',\n })\n}\n\n/**\n * Check whether the CLI entry point file exists on disk.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass, warn, or fail.\n */\nasync function checkEntryPoint(context: CheckContext): Promise<CheckResult> {\n const config = extractConfig(context.configResult)\n const entryPath = resolveEntryPath(config)\n\n const absolutePath = join(context.cwd, entryPath)\n const exists = await fs.exists(absolutePath)\n\n if (exists) {\n return checkResult({ message: `Found: ${entryPath}`, name: 'entry point', status: 'pass' })\n }\n\n if (!config) {\n return checkResult({\n hint: 'Create the entry file or update \"entry\" in maltty.config.ts (fixable with --fix)',\n message: `No config, default not found: ${entryPath}`,\n name: 'entry point',\n status: 'warn',\n })\n }\n\n return checkResult({\n hint: 'Create the entry file or update \"entry\" in maltty.config.ts (fixable with --fix)',\n message: `Not found: ${entryPath}`,\n name: 'entry point',\n status: 'fail',\n })\n}\n\n/**\n * Check whether the commands directory exists on disk.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass, warn, or fail.\n */\nasync function checkCommandsDirectory(context: CheckContext): Promise<CheckResult> {\n const config = extractConfig(context.configResult)\n const commandsPath = resolveCommandsPath(config)\n\n const absolutePath = join(context.cwd, commandsPath)\n const exists = await fs.exists(absolutePath)\n\n if (exists) {\n return checkResult({\n message: `Found: ${commandsPath}`,\n name: 'commands directory',\n status: 'pass',\n })\n }\n\n if (!config) {\n return checkResult({\n hint: 'Create the directory or update \"commands\" in maltty.config.ts (fixable with --fix)',\n message: `No config, default not found: ${commandsPath}`,\n name: 'commands directory',\n status: 'warn',\n })\n }\n\n return checkResult({\n hint: 'Create the directory or update \"commands\" in maltty.config.ts (fixable with --fix)',\n message: `Not found: ${commandsPath}`,\n name: 'commands directory',\n status: 'fail',\n })\n}\n\n/**\n * Check whether a tsconfig.json exists in the project root.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A CheckResult indicating pass or warn.\n */\nasync function checkTsconfig(context: CheckContext): Promise<CheckResult> {\n const exists = await fs.exists(join(context.cwd, 'tsconfig.json'))\n\n if (exists) {\n return checkResult({ message: 'Found', name: 'tsconfig.json', status: 'pass' })\n }\n\n return checkResult({\n hint: 'Run \"tsc --init\" to create a tsconfig.json',\n message: 'Not found (recommended)',\n name: 'tsconfig.json',\n status: 'warn',\n })\n}\n\n// ---------------------------------------------------------------------------\n// Fix functions\n// ---------------------------------------------------------------------------\n\n/**\n * Fix the module type by adding \"type\": \"module\" to package.json.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A FixResult indicating whether the fix was applied.\n */\nasync function fixModuleType(context: CheckContext): Promise<FixResult> {\n const [updateError] = await updatePackageJson(context.cwd, (pkg) => ({ ...pkg, type: 'module' }))\n\n if (updateError) {\n return fixResult({ fixed: false, message: updateError.message, name: 'module type' })\n }\n\n return fixResult({\n fixed: true,\n message: 'Added \"type\": \"module\" to package.json',\n name: 'module type',\n })\n}\n\n/**\n * Fix the maltty dependency by adding it to package.json dependencies.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A FixResult indicating whether the fix was applied.\n */\nasync function fixMalttyDependency(context: CheckContext): Promise<FixResult> {\n const [updateError] = await updatePackageJson(context.cwd, (pkg) => {\n const deps = pkg.dependencies ?? {}\n return {\n ...pkg,\n dependencies: { ...deps, maltty: 'latest' },\n }\n })\n\n if (updateError) {\n return fixResult({\n fixed: false,\n message: updateError.message,\n name: 'maltty dependency',\n })\n }\n\n return fixResult({\n fixed: true,\n message: 'Added \"maltty\": \"latest\" to dependencies',\n name: 'maltty dependency',\n })\n}\n\n/**\n * Fix the entry point by creating the entry file with a minimal scaffold.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A FixResult indicating whether the fix was applied.\n */\nasync function fixEntryPoint(context: CheckContext): Promise<FixResult> {\n const config = extractConfig(context.configResult)\n const entryPath = resolveEntryPath(config)\n const absolutePath = join(context.cwd, entryPath)\n\n const [mkdirError] = await fs.mkdir(dirname(absolutePath))\n if (mkdirError) {\n return fixResult({\n fixed: false,\n message: `Failed to create directory: ${mkdirError.message}`,\n name: 'entry point',\n })\n }\n\n const content = `import { create } from 'maltty'\\n`\n const [writeError] = await fs.write(absolutePath, content)\n if (writeError) {\n return fixResult({\n fixed: false,\n message: `Failed to create file: ${writeError.message}`,\n name: 'entry point',\n })\n }\n\n return fixResult({ fixed: true, message: `Created ${entryPath}`, name: 'entry point' })\n}\n\n/**\n * Fix the commands directory by creating it.\n *\n * @private\n * @param context - The diagnostic check context.\n * @returns A FixResult indicating whether the fix was applied.\n */\nasync function fixCommandsDirectory(context: CheckContext): Promise<FixResult> {\n const config = extractConfig(context.configResult)\n const commandsPath = resolveCommandsPath(config)\n const absolutePath = join(context.cwd, commandsPath)\n\n const [mkdirError] = await fs.mkdir(absolutePath)\n if (mkdirError) {\n return fixResult({\n fixed: false,\n message: `Failed to create directory: ${mkdirError.message}`,\n name: 'commands directory',\n })\n }\n\n return fixResult({ fixed: true, message: `Created ${commandsPath}`, name: 'commands directory' })\n}\n\n/**\n * All diagnostic checks to run in order.\n */\nexport const CHECKS: readonly DiagnosticCheck[] = [\n { name: 'maltty.config', run: checkMalttyConfig },\n { name: 'config schema', run: checkConfigSchema },\n { name: 'package.json', run: checkPackageJson },\n { name: 'package version', run: checkPackageVersion },\n { fix: fixModuleType, name: 'module type', run: checkModuleType },\n { fix: fixMalttyDependency, name: 'maltty dependency', run: checkMalttyDependency },\n { fix: fixEntryPoint, name: 'entry point', run: checkEntryPoint },\n { fix: fixCommandsDirectory, name: 'commands directory', run: checkCommandsDirectory },\n { name: 'tsconfig.json', run: checkTsconfig },\n]\n\n// ---------------------------------------------------------------------------\n// Raw package.json loader\n// ---------------------------------------------------------------------------\n\n/**\n * Read and parse the raw package.json from a directory.\n *\n * Only extracts the fields needed by diagnostic checks that Manifest does not expose.\n *\n * @param cwd - The directory to read from.\n * @returns A Result tuple with the raw package.json data or an error message.\n */\nexport async function readRawPackageJson(cwd: string): ResultAsync<RawPackageJson> {\n const filePath = join(cwd, 'package.json')\n const [readError, content] = await fs.read(filePath)\n if (readError) {\n return err(`Failed to read package.json: ${readError.message}`)\n }\n\n const [parseError, data] = jsonParse(content)\n\n if (parseError) {\n return err(parseError)\n }\n\n return ok(data as RawPackageJson)\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extract a MalttyConfig from a load result, returning null when absent.\n *\n * @private\n * @param result - The config load result, or null.\n * @returns The config object or null.\n */\nfunction extractConfig(result: LoadConfigResult | null): LoadConfigResult['config'] | null {\n if (result) {\n return result.config\n }\n\n return null\n}\n\n/**\n * Resolve the entry path from config, falling back to the default.\n *\n * @private\n * @param config - The loaded config or null.\n * @returns The entry path string.\n */\nfunction resolveEntryPath(config: LoadConfigResult['config'] | null): string {\n if (config && config.entry) {\n return config.entry\n }\n\n return DEFAULT_ENTRY\n}\n\n/**\n * Resolve the commands directory path from config, falling back to the default.\n *\n * @private\n * @param config - The loaded config or null.\n * @returns The commands directory path string.\n */\nfunction resolveCommandsPath(config: LoadConfigResult['config'] | null): string {\n if (config && config.commands) {\n return config.commands\n }\n\n return DEFAULT_COMMANDS\n}\n\n/**\n * Read, transform, and write back a package.json file.\n *\n * @private\n * @param cwd - The directory containing the package.json.\n * @param transform - A pure function that returns the updated package data.\n * @returns A Result tuple indicating success or failure.\n */\nasync function updatePackageJson(\n cwd: string,\n transform: (data: Record<string, unknown>) => Record<string, unknown>\n): ResultAsync<void> {\n const filePath = join(cwd, 'package.json')\n\n const [readError, content] = await fs.read(filePath)\n if (readError) {\n return err(`Failed to read package.json: ${readError.message}`)\n }\n\n const [parseError, data] = jsonParse(content)\n if (parseError) {\n return err(parseError)\n }\n\n const updated = transform(data as Record<string, unknown>)\n\n const [stringifyError, json] = jsonStringify(updated, { pretty: true })\n if (stringifyError) {\n return err(stringifyError)\n }\n\n const [writeError] = await fs.write(filePath, `${json}\\n`)\n if (writeError) {\n return err(`Failed to write package.json: ${writeError.message}`)\n }\n\n return ok()\n}\n","import { loadConfig } from '@maltty/config/utils'\nimport { match } from '@maltty/utils/fp'\nimport { readManifest } from '@maltty/utils/manifest'\nimport { command } from 'maltty'\nimport type { Command, CommandContext } from 'maltty'\nimport pc from 'picocolors'\nimport { z } from 'zod'\n\nimport type { CheckContext, CheckResult, CheckStatus, FixResult } from '../lib/checks.js'\nimport { CHECKS, createCheckContext, readRawPackageJson } from '../lib/checks.js'\n\nconst options = z.object({\n fix: z.boolean().describe('Auto-fix issues where possible').optional(),\n})\n\ntype DoctorArgs = z.infer<typeof options>\n\n/**\n * Diagnose common maltty project issues.\n *\n * Validates config, checks package.json setup, verifies entry points exist,\n * and catches anything that could cause build or runtime failures.\n */\nconst doctorCommand: Command = command({\n options,\n description: 'Diagnose common maltty project issues',\n handler: async (ctx: CommandContext<DoctorArgs>) => {\n const cwd = process.cwd()\n const shouldFix = ctx.args.fix === true\n\n const [configError, configResult] = await loadConfig({ cwd })\n const [, manifest] = await readManifest(cwd)\n const [, rawPackageJson] = await readRawPackageJson(cwd)\n\n const context = createCheckContext({\n configError,\n configResult,\n cwd,\n manifest,\n rawPackageJson,\n })\n\n ctx.status.spinner.start('Running diagnostics...')\n\n const initialResults = await Promise.all(CHECKS.map((check) => check.run(context)))\n\n const fixResults = await resolveFixResults(shouldFix, initialResults, context)\n const fixed = fixResults.filter((r) => r.fixed).length\n const results = await resolveResults({ cwd, fixed, initialResults, shouldFix })\n\n ctx.status.spinner.stop('Diagnostics complete')\n\n displayResults(ctx, results, fixResults)\n\n const passed = results.filter((r) => r.status === 'pass').length\n const warnings = results.filter((r) => r.status === 'warn').length\n const failed = results.filter((r) => r.status === 'fail').length\n\n const summary = formatSummary({ failed, fixed, passed, total: results.length, warnings })\n\n ctx.log.raw(summary)\n\n if (failed > 0) {\n ctx.fail(`${failed} ${pluralizeCheck(failed)} failed`)\n }\n },\n})\n\nexport default doctorCommand\n\n// ---------------------------------------------------------------------------\n// Fix orchestration\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve fix results based on whether --fix is enabled.\n *\n * @private\n * @param shouldFix - Whether the --fix flag was set.\n * @param results - The initial check results.\n * @param context - The diagnostic check context.\n * @returns Fix results when --fix is enabled, empty array otherwise.\n */\nasync function resolveFixResults(\n shouldFix: boolean,\n results: readonly CheckResult[],\n context: CheckContext\n): Promise<readonly FixResult[]> {\n if (!shouldFix) {\n return []\n }\n\n return applyFixes(results, context)\n}\n\n/**\n * Resolve the final check results, re-running after fixes when needed.\n *\n * Rebuilds the context from disk so that fixes to package.json are reflected.\n *\n * @private\n * @param params - The resolution parameters.\n * @returns Updated check results if fixes were applied, otherwise the initial results.\n */\nasync function resolveResults(params: {\n readonly cwd: string\n readonly fixed: number\n readonly initialResults: readonly CheckResult[]\n readonly shouldFix: boolean\n}): Promise<readonly CheckResult[]> {\n if (!params.shouldFix || params.fixed === 0) {\n return params.initialResults\n }\n\n const [configError, configResult] = await loadConfig({ cwd: params.cwd })\n const [, manifest] = await readManifest(params.cwd)\n const [, rawPackageJson] = await readRawPackageJson(params.cwd)\n\n const freshContext = createCheckContext({\n configError,\n configResult,\n cwd: params.cwd,\n manifest,\n rawPackageJson,\n })\n\n return Promise.all(CHECKS.map((check) => check.run(freshContext)))\n}\n\n/**\n * Apply fixes for all non-passing checks that have a fix function.\n *\n * @private\n * @param results - The initial check results.\n * @param context - The diagnostic check context.\n * @returns An array of FixResults for checks that were attempted.\n */\nasync function applyFixes(\n results: readonly CheckResult[],\n context: CheckContext\n): Promise<readonly FixResult[]> {\n const fixable = CHECKS.filter((check) => {\n if (!check.fix) {\n return false\n }\n\n const result = results.find((r) => r.name === check.name)\n return result !== undefined && result.status !== 'pass'\n }).flatMap((check) => {\n if (check.fix) {\n return [check.fix]\n }\n return []\n })\n\n return Promise.all(fixable.map((fix) => fix(context)))\n}\n\n// ---------------------------------------------------------------------------\n// Display\n// ---------------------------------------------------------------------------\n\n/**\n * Display check results with hints and fix indicators.\n *\n * @private\n * @param ctx - The command context for logging.\n * @param results - The check results to display.\n * @param fixResults - The fix results (empty when --fix was not used).\n */\nfunction displayResults(\n ctx: CommandContext,\n results: readonly CheckResult[],\n fixResults: readonly FixResult[]\n): void {\n const lines = results.map((result) => formatResultLine(result, fixResults))\n const output = lines.join('')\n if (output.length > 0) {\n ctx.log.raw(output)\n }\n}\n\n/**\n * Format a single check result line with optional hint.\n *\n * @private\n * @param result - The check result to format.\n * @param fixResults - The fix results to check for applied fixes.\n * @returns The formatted result line string.\n */\nfunction formatResultLine(result: CheckResult, fixResults: readonly FixResult[]): string {\n const appliedFix = fixResults.find((f) => f.name === result.name && f.fixed)\n\n if (appliedFix) {\n return ` ${formatDisplayStatus('fix')} ${result.name} - ${appliedFix.message}\\n`\n }\n\n const line = ` ${formatDisplayStatus(result.status)} ${result.name} - ${result.message}\\n`\n\n if (result.hint && result.status !== 'pass') {\n return `${line} ${pc.dim(`→ ${result.hint}`)}\\n`\n }\n\n return line\n}\n\n/**\n * Format a display status with color.\n *\n * Accepts both CheckStatus values and the 'fix' display status.\n *\n * @private\n * @param status - The status to format.\n * @returns A colored string representation of the status.\n */\nfunction formatDisplayStatus(status: CheckStatus | 'fix'): string {\n return match(status)\n .with('pass', () => pc.green('pass'))\n .with('warn', () => pc.yellow('warn'))\n .with('fix', () => pc.blue('fix '))\n .with('fail', () => pc.red('fail'))\n .exhaustive()\n}\n\n/**\n * Format the summary line with counts.\n *\n * @private\n * @param params - The count parameters.\n * @returns A formatted summary string.\n */\nfunction formatSummary(params: {\n readonly total: number\n readonly passed: number\n readonly warnings: number\n readonly failed: number\n readonly fixed: number\n}): string {\n const base = `\\n${params.total} checks, ${params.passed} passed, ${params.warnings} warnings, ${params.failed} failed`\n\n if (params.fixed > 0) {\n return `${base}, ${params.fixed} fixed\\n`\n }\n\n return `${base}\\n`\n}\n\n/**\n * Pluralize the word \"check\" based on count.\n *\n * @private\n * @param count - The number of checks.\n * @returns \"check\" or \"checks\".\n */\nfunction pluralizeCheck(count: number): string {\n if (count === 1) {\n return 'check'\n }\n\n return 'checks'\n}\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Command } from "maltty";
2
+
3
+ //#region src/commands/init.d.ts
4
+ declare const initCommand: Command;
5
+ //#endregion
6
+ export { initCommand as default };
7
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","names":[],"sources":["../../src/commands/init.ts"],"mappings":";;;cAyBM,WAAA,EAAa,OAAA"}
@@ -0,0 +1,305 @@
1
+ import { n as err, r as ok } from "../attemptAsync-BdXzRSIT.js";
2
+ import { r as attempt } from "../json-D7WbuVK1.js";
3
+ import { t as readManifest } from "../manifest-BIKVDJML.js";
4
+ import { n as renderTemplate, t as writeFiles } from "../write-CSwG4Stj.js";
5
+ import { t as isKebabCase } from "../validate-C_SXBoLq.js";
6
+ import { createRequire } from "node:module";
7
+ import { command } from "maltty";
8
+ import { dirname, join } from "node:path";
9
+ import { z } from "zod";
10
+ import { existsSync, readFileSync } from "node:fs";
11
+ import { parse } from "yaml";
12
+ //#region src/lib/template-versions.ts
13
+ /**
14
+ * Zod schema for the `catalog` field in `pnpm-workspace.yaml`.
15
+ *
16
+ * @private
17
+ */
18
+ const catalogSchema = z.object({ catalog: z.object({
19
+ tsdown: z.string(),
20
+ typescript: z.string(),
21
+ vitest: z.string(),
22
+ zod: z.string()
23
+ }) });
24
+ /**
25
+ * Known locations for `pnpm-workspace.yaml` relative to this module.
26
+ *
27
+ * - First path covers the built `dist/` layout (yaml copied to `dist/`).
28
+ * - Second path covers running from source `src/lib/` during development.
29
+ *
30
+ * @private
31
+ */
32
+ const CANDIDATE_PATHS = [join(import.meta.dirname, "..", "pnpm-workspace.yaml"), join(import.meta.dirname, "..", "..", "..", "..", "pnpm-workspace.yaml")];
33
+ /**
34
+ * Locate `pnpm-workspace.yaml` by checking known candidate paths.
35
+ *
36
+ * @returns The resolved path, or `null` when no candidate exists.
37
+ * @private
38
+ */
39
+ function findWorkspaceYaml() {
40
+ return CANDIDATE_PATHS.find(existsSync) ?? null;
41
+ }
42
+ /**
43
+ * Range operator prefixes recognized in version strings.
44
+ *
45
+ * @private
46
+ */
47
+ const RANGE_PREFIXES = [
48
+ "^",
49
+ "~",
50
+ ">",
51
+ "<",
52
+ "="
53
+ ];
54
+ /**
55
+ * Normalize a version string to always include a caret range prefix.
56
+ *
57
+ * If the version already starts with a range operator (`^`, `~`, `>`, `<`, `=`)
58
+ * it is returned as-is. Otherwise a `^` prefix is added.
59
+ *
60
+ * @param version - The raw version string from the catalog.
61
+ * @returns The version prefixed with `^` when no range operator is present.
62
+ */
63
+ function normalizeVersion(version) {
64
+ if (RANGE_PREFIXES.some((prefix) => version.startsWith(prefix))) return version;
65
+ return `^${version}`;
66
+ }
67
+ /**
68
+ * Read template dependency versions from the workspace catalog (`pnpm-workspace.yaml`).
69
+ *
70
+ * Resolves the workspace file from known relative locations, parses the YAML,
71
+ * validates the structure with Zod, and returns normalized version strings
72
+ * suitable for scaffolding `package.json` files in new projects.
73
+ *
74
+ * @returns A `Result` tuple with the resolved versions or an error.
75
+ */
76
+ function readTemplateVersions() {
77
+ const yamlPath = findWorkspaceYaml();
78
+ if (yamlPath === null) return err(/* @__PURE__ */ new Error("Could not locate pnpm-workspace.yaml"));
79
+ const [readError, content] = attempt(() => readFileSync(yamlPath, "utf8"));
80
+ if (readError) return err(readError);
81
+ const [parseError, rawParsed] = attempt(() => parse(content));
82
+ if (parseError) return err(parseError);
83
+ const validation = catalogSchema.safeParse(rawParsed);
84
+ if (!validation.success) return err(/* @__PURE__ */ new Error(`Invalid pnpm-workspace.yaml catalog: ${validation.error.message}`));
85
+ const { catalog } = validation.data;
86
+ return ok(Object.freeze({
87
+ tsdownVersion: normalizeVersion(catalog.tsdown),
88
+ typescriptVersion: normalizeVersion(catalog.typescript),
89
+ vitestVersion: normalizeVersion(catalog.vitest),
90
+ zodVersion: normalizeVersion(catalog.zod)
91
+ }));
92
+ }
93
+ //#endregion
94
+ //#region src/commands/init.ts
95
+ const initCommand = command({
96
+ options: z.object({
97
+ config: z.boolean().describe("Include config schema setup").optional(),
98
+ description: z.string().describe("Project description").optional(),
99
+ example: z.boolean().describe("Include example command").optional(),
100
+ name: z.string().describe("Project name (kebab-case)").optional(),
101
+ pm: z.enum([
102
+ "pnpm",
103
+ "yarn",
104
+ "npm"
105
+ ]).describe("Package manager").optional()
106
+ }),
107
+ description: "Scaffold a new maltty CLI project",
108
+ handler: async (ctx) => {
109
+ const projectName = await resolveProjectName(ctx);
110
+ const projectDescription = await resolveDescription(ctx);
111
+ const packageManager = await resolvePackageManager(ctx);
112
+ const includeExample = await resolveIncludeExample(ctx);
113
+ const includeConfig = await resolveIncludeConfig(ctx);
114
+ ctx.status.spinner.start("Scaffolding project...");
115
+ const [versionsError, templateVersions] = readTemplateVersions();
116
+ if (versionsError) {
117
+ ctx.status.spinner.stop("Failed");
118
+ return ctx.fail(versionsError.message);
119
+ }
120
+ const coreVersion = await resolveDependencyVersion("maltty");
121
+ const cliVersion = await resolveSelfVersion();
122
+ const [renderError, rendered] = await renderTemplate({
123
+ templateDir: join(import.meta.dirname, "..", "lib", "templates", "project"),
124
+ variables: {
125
+ cliVersion,
126
+ coreVersion,
127
+ description: projectDescription,
128
+ includeConfig,
129
+ name: projectName,
130
+ packageManager,
131
+ ...templateVersions
132
+ }
133
+ });
134
+ if (renderError) {
135
+ ctx.status.spinner.stop("Failed");
136
+ return ctx.fail(renderError.message);
137
+ }
138
+ const [writeError] = await writeFiles({
139
+ files: selectFiles({
140
+ includeConfig,
141
+ includeExample
142
+ }, rendered),
143
+ outputDir: join(process.cwd(), projectName),
144
+ overwrite: false
145
+ });
146
+ if (writeError) {
147
+ ctx.status.spinner.stop("Failed");
148
+ return ctx.fail(writeError.message);
149
+ }
150
+ ctx.status.spinner.stop("Project created!");
151
+ ctx.log.newline();
152
+ ctx.log.raw("Next steps:");
153
+ ctx.log.raw(` cd ${projectName}`);
154
+ ctx.log.raw(` ${packageManager} install`);
155
+ }
156
+ });
157
+ /**
158
+ * Resolve the project name from args or prompt.
159
+ *
160
+ * @param ctx - Command context.
161
+ * @returns The validated project name.
162
+ * @private
163
+ */
164
+ async function resolveProjectName(ctx) {
165
+ if (ctx.args.name) {
166
+ if (!isKebabCase(ctx.args.name)) return ctx.fail("Project name must be kebab-case (e.g. my-cli)");
167
+ return ctx.args.name;
168
+ }
169
+ return ctx.prompts.text({
170
+ message: "Project name",
171
+ placeholder: "my-cli",
172
+ validate: (value) => {
173
+ if (value === void 0 || !isKebabCase(value)) return "Must be kebab-case (e.g. my-cli)";
174
+ }
175
+ });
176
+ }
177
+ /**
178
+ * Resolve the project description from args or prompt.
179
+ *
180
+ * @param ctx - Command context.
181
+ * @returns The project description string.
182
+ * @private
183
+ */
184
+ async function resolveDescription(ctx) {
185
+ if (ctx.args.description) return ctx.args.description;
186
+ return ctx.prompts.text({
187
+ defaultValue: "A CLI built with maltty",
188
+ message: "Description",
189
+ placeholder: "A CLI built with maltty"
190
+ });
191
+ }
192
+ /**
193
+ * Resolve the package manager from args or prompt.
194
+ *
195
+ * @param ctx - Command context.
196
+ * @returns The selected package manager.
197
+ * @private
198
+ */
199
+ async function resolvePackageManager(ctx) {
200
+ if (ctx.args.pm) return ctx.args.pm;
201
+ return ctx.prompts.select({
202
+ message: "Package manager",
203
+ options: [
204
+ {
205
+ label: "pnpm",
206
+ value: "pnpm"
207
+ },
208
+ {
209
+ label: "yarn",
210
+ value: "yarn"
211
+ },
212
+ {
213
+ label: "npm",
214
+ value: "npm"
215
+ }
216
+ ]
217
+ });
218
+ }
219
+ /**
220
+ * Resolve whether to include the example command from args or prompt.
221
+ *
222
+ * @param ctx - Command context.
223
+ * @returns True when the example hello command should be included.
224
+ * @private
225
+ */
226
+ async function resolveIncludeExample(ctx) {
227
+ if (ctx.args.example !== void 0) return ctx.args.example;
228
+ return ctx.prompts.confirm({
229
+ initialValue: true,
230
+ message: "Include example command?"
231
+ });
232
+ }
233
+ /**
234
+ * Resolve whether to include config schema setup from args or prompt.
235
+ *
236
+ * @param ctx - Command context.
237
+ * @returns True when the config schema file should be included.
238
+ * @private
239
+ */
240
+ async function resolveIncludeConfig(ctx) {
241
+ if (ctx.args.config !== void 0) return ctx.args.config;
242
+ return ctx.prompts.confirm({
243
+ initialValue: false,
244
+ message: "Include config schema?"
245
+ });
246
+ }
247
+ /**
248
+ * Select the rendered files to write, optionally excluding the example command and config.
249
+ *
250
+ * @param options - Flags controlling which optional files to include.
251
+ * @param rendered - The full set of rendered files.
252
+ * @returns The filtered file list.
253
+ * @private
254
+ */
255
+ function selectFiles(selectionOptions, rendered) {
256
+ return rendered.filter((file) => selectionOptions.includeExample || !file.relativePath.includes("commands/hello.ts")).filter((file) => selectionOptions.includeConfig || !file.relativePath.includes("config.ts"));
257
+ }
258
+ const DEFAULT_VERSION = "0.0.0";
259
+ /**
260
+ * Resolve the version of the running CLI package.
261
+ *
262
+ * Reads the CLI's own `package.json` by navigating up from the current
263
+ * command file directory. Returns `'0.0.0'` when the manifest cannot be
264
+ * read or is missing a version field.
265
+ *
266
+ * @returns The CLI package version string, or `'0.0.0'` on failure.
267
+ * @private
268
+ */
269
+ async function resolveSelfVersion() {
270
+ const [error, manifest] = await readManifest(join(import.meta.dirname, "..", ".."));
271
+ if (error || !manifest.version) {
272
+ console.warn("Warning: Could not resolve CLI version, using fallback 0.0.0");
273
+ return DEFAULT_VERSION;
274
+ }
275
+ return manifest.version;
276
+ }
277
+ /**
278
+ * Resolve the installed version of a dependency package.
279
+ *
280
+ * Uses `createRequire` to locate the package entry point, derives the
281
+ * package root from the resolved path, and reads its `package.json`.
282
+ * Returns `'0.0.0'` when resolution fails for any reason.
283
+ *
284
+ * @param packageName - The npm package name to resolve (e.g. `'maltty'`).
285
+ * @returns The package version string, or `'0.0.0'` on failure.
286
+ * @private
287
+ */
288
+ async function resolveDependencyVersion(packageName) {
289
+ const require = createRequire(import.meta.url);
290
+ const [resolveError, entryPath] = attempt(() => require.resolve(packageName));
291
+ if (resolveError || entryPath === null) {
292
+ console.warn(`Warning: Could not resolve version for ${packageName}, using fallback 0.0.0`);
293
+ return DEFAULT_VERSION;
294
+ }
295
+ const [manifestError, manifest] = await readManifest(join(dirname(entryPath), ".."));
296
+ if (manifestError || !manifest.version) {
297
+ console.warn(`Warning: Could not resolve version for ${packageName}, using fallback 0.0.0`);
298
+ return DEFAULT_VERSION;
299
+ }
300
+ return manifest.version;
301
+ }
302
+ //#endregion
303
+ export { initCommand as default };
304
+
305
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","names":[],"sources":["../../src/lib/template-versions.ts","../../src/commands/init.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { attempt, err, ok } from '@maltty/utils/fp'\nimport type { Result } from '@maltty/utils/fp'\nimport { parse } from 'yaml'\nimport { z } from 'zod'\n\n/**\n * Zod schema for the `catalog` field in `pnpm-workspace.yaml`.\n *\n * @private\n */\nconst catalogSchema = z.object({\n catalog: z.object({\n tsdown: z.string(),\n typescript: z.string(),\n vitest: z.string(),\n zod: z.string(),\n }),\n})\n\n/**\n * Resolved template dependency versions read from the workspace catalog.\n */\nexport interface TemplateVersions {\n readonly tsdownVersion: string\n readonly typescriptVersion: string\n readonly vitestVersion: string\n readonly zodVersion: string\n}\n\n/**\n * Known locations for `pnpm-workspace.yaml` relative to this module.\n *\n * - First path covers the built `dist/` layout (yaml copied to `dist/`).\n * - Second path covers running from source `src/lib/` during development.\n *\n * @private\n */\nconst CANDIDATE_PATHS: readonly string[] = [\n join(import.meta.dirname, '..', 'pnpm-workspace.yaml'),\n join(import.meta.dirname, '..', '..', '..', '..', 'pnpm-workspace.yaml'),\n]\n\n/**\n * Locate `pnpm-workspace.yaml` by checking known candidate paths.\n *\n * @returns The resolved path, or `null` when no candidate exists.\n * @private\n */\nfunction findWorkspaceYaml(): string | null {\n return CANDIDATE_PATHS.find(existsSync) ?? null\n}\n\n/**\n * Range operator prefixes recognized in version strings.\n *\n * @private\n */\nconst RANGE_PREFIXES = ['^', '~', '>', '<', '='] as const\n\n/**\n * Normalize a version string to always include a caret range prefix.\n *\n * If the version already starts with a range operator (`^`, `~`, `>`, `<`, `=`)\n * it is returned as-is. Otherwise a `^` prefix is added.\n *\n * @param version - The raw version string from the catalog.\n * @returns The version prefixed with `^` when no range operator is present.\n */\nexport function normalizeVersion(version: string): string {\n const hasRange = RANGE_PREFIXES.some((prefix) => version.startsWith(prefix))\n if (hasRange) {\n return version\n }\n return `^${version}`\n}\n\n/**\n * Read template dependency versions from the workspace catalog (`pnpm-workspace.yaml`).\n *\n * Resolves the workspace file from known relative locations, parses the YAML,\n * validates the structure with Zod, and returns normalized version strings\n * suitable for scaffolding `package.json` files in new projects.\n *\n * @returns A `Result` tuple with the resolved versions or an error.\n */\nexport function readTemplateVersions(): Result<TemplateVersions> {\n const yamlPath = findWorkspaceYaml()\n if (yamlPath === null) {\n return err(new Error('Could not locate pnpm-workspace.yaml'))\n }\n\n const [readError, content] = attempt(() => readFileSync(yamlPath, 'utf8'))\n if (readError) {\n return err(readError)\n }\n\n const [parseError, rawParsed] = attempt(() => parse(content as string) as unknown)\n if (parseError) {\n return err(parseError)\n }\n\n const validation = catalogSchema.safeParse(rawParsed)\n if (!validation.success) {\n return err(new Error(`Invalid pnpm-workspace.yaml catalog: ${validation.error.message}`))\n }\n\n const { catalog } = validation.data\n\n return ok(\n Object.freeze({\n tsdownVersion: normalizeVersion(catalog.tsdown),\n typescriptVersion: normalizeVersion(catalog.typescript),\n vitestVersion: normalizeVersion(catalog.vitest),\n zodVersion: normalizeVersion(catalog.zod),\n })\n )\n}\n","import { createRequire } from 'node:module'\nimport { dirname, join } from 'node:path'\n\nimport { attempt } from '@maltty/utils/fp'\nimport { readManifest } from '@maltty/utils/manifest'\nimport { command } from 'maltty'\nimport type { Command, CommandContext } from 'maltty'\nimport { z } from 'zod'\n\nimport { renderTemplate } from '../lib/render.js'\nimport { readTemplateVersions } from '../lib/template-versions.js'\nimport type { RenderedFile } from '../lib/types.js'\nimport { isKebabCase } from '../lib/validate.js'\nimport { writeFiles } from '../lib/write.js'\n\nconst options = z.object({\n config: z.boolean().describe('Include config schema setup').optional(),\n description: z.string().describe('Project description').optional(),\n example: z.boolean().describe('Include example command').optional(),\n name: z.string().describe('Project name (kebab-case)').optional(),\n pm: z.enum(['pnpm', 'yarn', 'npm']).describe('Package manager').optional(),\n})\n\ntype InitArgs = z.infer<typeof options>\n\nconst initCommand: Command = command({\n options,\n description: 'Scaffold a new maltty CLI project',\n handler: async (ctx: CommandContext<InitArgs>) => {\n const projectName = await resolveProjectName(ctx)\n const projectDescription = await resolveDescription(ctx)\n const packageManager = await resolvePackageManager(ctx)\n const includeExample = await resolveIncludeExample(ctx)\n const includeConfig = await resolveIncludeConfig(ctx)\n\n ctx.status.spinner.start('Scaffolding project...')\n\n const [versionsError, templateVersions] = readTemplateVersions()\n if (versionsError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(versionsError.message)\n }\n\n const coreVersion = await resolveDependencyVersion('maltty')\n const cliVersion = await resolveSelfVersion()\n\n const templateDir = join(import.meta.dirname, '..', 'lib', 'templates', 'project')\n const [renderError, rendered] = await renderTemplate({\n templateDir,\n variables: {\n cliVersion,\n coreVersion,\n description: projectDescription,\n includeConfig,\n name: projectName,\n packageManager,\n ...templateVersions,\n },\n })\n\n if (renderError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(renderError.message)\n }\n\n const files = selectFiles({ includeConfig, includeExample }, rendered)\n\n const outputDir = join(process.cwd(), projectName)\n const [writeError] = await writeFiles({ files, outputDir, overwrite: false })\n\n if (writeError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(writeError.message)\n }\n\n ctx.status.spinner.stop('Project created!')\n\n ctx.log.newline()\n ctx.log.raw('Next steps:')\n ctx.log.raw(` cd ${projectName}`)\n ctx.log.raw(` ${packageManager} install`)\n },\n})\n\nexport default initCommand\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the project name from args or prompt.\n *\n * @param ctx - Command context.\n * @returns The validated project name.\n * @private\n */\nasync function resolveProjectName(ctx: CommandContext<InitArgs>): Promise<string> {\n if (ctx.args.name) {\n if (!isKebabCase(ctx.args.name)) {\n return ctx.fail('Project name must be kebab-case (e.g. my-cli)')\n }\n return ctx.args.name\n }\n return ctx.prompts.text({\n message: 'Project name',\n placeholder: 'my-cli',\n validate: (value: string | undefined) => {\n if (value === undefined || !isKebabCase(value)) {\n return 'Must be kebab-case (e.g. my-cli)'\n }\n return undefined\n },\n })\n}\n\n/**\n * Resolve the project description from args or prompt.\n *\n * @param ctx - Command context.\n * @returns The project description string.\n * @private\n */\nasync function resolveDescription(ctx: CommandContext<InitArgs>): Promise<string> {\n if (ctx.args.description) {\n return ctx.args.description\n }\n return ctx.prompts.text({\n defaultValue: 'A CLI built with maltty',\n message: 'Description',\n placeholder: 'A CLI built with maltty',\n })\n}\n\n/**\n * Resolve the package manager from args or prompt.\n *\n * @param ctx - Command context.\n * @returns The selected package manager.\n * @private\n */\nasync function resolvePackageManager(ctx: CommandContext<InitArgs>): Promise<string> {\n if (ctx.args.pm) {\n return ctx.args.pm\n }\n return ctx.prompts.select({\n message: 'Package manager',\n options: [\n { label: 'pnpm', value: 'pnpm' },\n { label: 'yarn', value: 'yarn' },\n { label: 'npm', value: 'npm' },\n ],\n })\n}\n\n/**\n * Resolve whether to include the example command from args or prompt.\n *\n * @param ctx - Command context.\n * @returns True when the example hello command should be included.\n * @private\n */\nasync function resolveIncludeExample(ctx: CommandContext<InitArgs>): Promise<boolean> {\n if (ctx.args.example !== undefined) {\n return ctx.args.example\n }\n return ctx.prompts.confirm({\n initialValue: true,\n message: 'Include example command?',\n })\n}\n\n/**\n * Resolve whether to include config schema setup from args or prompt.\n *\n * @param ctx - Command context.\n * @returns True when the config schema file should be included.\n * @private\n */\nasync function resolveIncludeConfig(ctx: CommandContext<InitArgs>): Promise<boolean> {\n if (ctx.args.config !== undefined) {\n return ctx.args.config\n }\n return ctx.prompts.confirm({\n initialValue: false,\n message: 'Include config schema?',\n })\n}\n\n/**\n * Options for filtering the rendered file set.\n *\n * @private\n */\ninterface SelectFilesOptions {\n readonly includeConfig: boolean\n readonly includeExample: boolean\n}\n\n/**\n * Select the rendered files to write, optionally excluding the example command and config.\n *\n * @param options - Flags controlling which optional files to include.\n * @param rendered - The full set of rendered files.\n * @returns The filtered file list.\n * @private\n */\nfunction selectFiles(\n selectionOptions: SelectFilesOptions,\n rendered: readonly RenderedFile[]\n): readonly RenderedFile[] {\n return rendered\n .filter(\n (file) => selectionOptions.includeExample || !file.relativePath.includes('commands/hello.ts')\n )\n .filter((file) => selectionOptions.includeConfig || !file.relativePath.includes('config.ts'))\n}\n\nconst DEFAULT_VERSION = '0.0.0'\n\n/**\n * Resolve the version of the running CLI package.\n *\n * Reads the CLI's own `package.json` by navigating up from the current\n * command file directory. Returns `'0.0.0'` when the manifest cannot be\n * read or is missing a version field.\n *\n * @returns The CLI package version string, or `'0.0.0'` on failure.\n * @private\n */\nasync function resolveSelfVersion(): Promise<string> {\n const packageDir = join(import.meta.dirname, '..', '..')\n const [error, manifest] = await readManifest(packageDir)\n if (error || !manifest.version) {\n console.warn('Warning: Could not resolve CLI version, using fallback 0.0.0')\n return DEFAULT_VERSION\n }\n return manifest.version\n}\n\n/**\n * Resolve the installed version of a dependency package.\n *\n * Uses `createRequire` to locate the package entry point, derives the\n * package root from the resolved path, and reads its `package.json`.\n * Returns `'0.0.0'` when resolution fails for any reason.\n *\n * @param packageName - The npm package name to resolve (e.g. `'maltty'`).\n * @returns The package version string, or `'0.0.0'` on failure.\n * @private\n */\nasync function resolveDependencyVersion(packageName: string): Promise<string> {\n const require = createRequire(import.meta.url)\n const [resolveError, entryPath] = attempt(() => require.resolve(packageName))\n if (resolveError || entryPath === null) {\n console.warn(`Warning: Could not resolve version for ${packageName}, using fallback 0.0.0`)\n return DEFAULT_VERSION\n }\n\n const packageDir = join(dirname(entryPath), '..')\n const [manifestError, manifest] = await readManifest(packageDir)\n if (manifestError || !manifest.version) {\n console.warn(`Warning: Could not resolve version for ${packageName}, using fallback 0.0.0`)\n return DEFAULT_VERSION\n }\n\n return manifest.version\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAaA,MAAM,gBAAgB,EAAE,OAAO,EAC7B,SAAS,EAAE,OAAO;CAChB,QAAQ,EAAE,QAAQ;CAClB,YAAY,EAAE,QAAQ;CACtB,QAAQ,EAAE,QAAQ;CAClB,KAAK,EAAE,QAAQ;CAChB,CAAC,EACH,CAAC;;;;;;;;;AAoBF,MAAM,kBAAqC,CACzC,KAAK,OAAO,KAAK,SAAS,MAAM,sBAAsB,EACtD,KAAK,OAAO,KAAK,SAAS,MAAM,MAAM,MAAM,MAAM,sBAAsB,CACzE;;;;;;;AAQD,SAAS,oBAAmC;AAC1C,QAAO,gBAAgB,KAAK,WAAW,IAAI;;;;;;;AAQ7C,MAAM,iBAAiB;CAAC;CAAK;CAAK;CAAK;CAAK;CAAI;;;;;;;;;;AAWhD,SAAgB,iBAAiB,SAAyB;AAExD,KADiB,eAAe,MAAM,WAAW,QAAQ,WAAW,OAAO,CAAC,CAE1E,QAAO;AAET,QAAO,IAAI;;;;;;;;;;;AAYb,SAAgB,uBAAiD;CAC/D,MAAM,WAAW,mBAAmB;AACpC,KAAI,aAAa,KACf,QAAO,oBAAI,IAAI,MAAM,uCAAuC,CAAC;CAG/D,MAAM,CAAC,WAAW,WAAW,cAAc,aAAa,UAAU,OAAO,CAAC;AAC1E,KAAI,UACF,QAAO,IAAI,UAAU;CAGvB,MAAM,CAAC,YAAY,aAAa,cAAc,MAAM,QAAkB,CAAY;AAClF,KAAI,WACF,QAAO,IAAI,WAAW;CAGxB,MAAM,aAAa,cAAc,UAAU,UAAU;AACrD,KAAI,CAAC,WAAW,QACd,QAAO,oBAAI,IAAI,MAAM,wCAAwC,WAAW,MAAM,UAAU,CAAC;CAG3F,MAAM,EAAE,YAAY,WAAW;AAE/B,QAAO,GACL,OAAO,OAAO;EACZ,eAAe,iBAAiB,QAAQ,OAAO;EAC/C,mBAAmB,iBAAiB,QAAQ,WAAW;EACvD,eAAe,iBAAiB,QAAQ,OAAO;EAC/C,YAAY,iBAAiB,QAAQ,IAAI;EAC1C,CAAC,CACH;;;;AC7FH,MAAM,cAAuB,QAAQ;CACnC,SAXc,EAAE,OAAO;EACvB,QAAQ,EAAE,SAAS,CAAC,SAAS,8BAA8B,CAAC,UAAU;EACtE,aAAa,EAAE,QAAQ,CAAC,SAAS,sBAAsB,CAAC,UAAU;EAClE,SAAS,EAAE,SAAS,CAAC,SAAS,0BAA0B,CAAC,UAAU;EACnE,MAAM,EAAE,QAAQ,CAAC,SAAS,4BAA4B,CAAC,UAAU;EACjE,IAAI,EAAE,KAAK;GAAC;GAAQ;GAAQ;GAAM,CAAC,CAAC,SAAS,kBAAkB,CAAC,UAAU;EAC3E,CAAC;CAMA,aAAa;CACb,SAAS,OAAO,QAAkC;EAChD,MAAM,cAAc,MAAM,mBAAmB,IAAI;EACjD,MAAM,qBAAqB,MAAM,mBAAmB,IAAI;EACxD,MAAM,iBAAiB,MAAM,sBAAsB,IAAI;EACvD,MAAM,iBAAiB,MAAM,sBAAsB,IAAI;EACvD,MAAM,gBAAgB,MAAM,qBAAqB,IAAI;AAErD,MAAI,OAAO,QAAQ,MAAM,yBAAyB;EAElD,MAAM,CAAC,eAAe,oBAAoB,sBAAsB;AAChE,MAAI,eAAe;AACjB,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,cAAc,QAAQ;;EAGxC,MAAM,cAAc,MAAM,yBAAyB,SAAS;EAC5D,MAAM,aAAa,MAAM,oBAAoB;EAG7C,MAAM,CAAC,aAAa,YAAY,MAAM,eAAe;GACnD,aAFkB,KAAK,OAAO,KAAK,SAAS,MAAM,OAAO,aAAa,UAAU;GAGhF,WAAW;IACT;IACA;IACA,aAAa;IACb;IACA,MAAM;IACN;IACA,GAAG;IACJ;GACF,CAAC;AAEF,MAAI,aAAa;AACf,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,YAAY,QAAQ;;EAMtC,MAAM,CAAC,cAAc,MAAM,WAAW;GAAE,OAH1B,YAAY;IAAE;IAAe;IAAgB,EAAE,SAAS;GAGvB,WAD7B,KAAK,QAAQ,KAAK,EAAE,YAAY;GACQ,WAAW;GAAO,CAAC;AAE7E,MAAI,YAAY;AACd,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,WAAW,QAAQ;;AAGrC,MAAI,OAAO,QAAQ,KAAK,mBAAmB;AAE3C,MAAI,IAAI,SAAS;AACjB,MAAI,IAAI,IAAI,cAAc;AAC1B,MAAI,IAAI,IAAI,QAAQ,cAAc;AAClC,MAAI,IAAI,IAAI,KAAK,eAAe,UAAU;;CAE7C,CAAC;;;;;;;;AAeF,eAAe,mBAAmB,KAAgD;AAChF,KAAI,IAAI,KAAK,MAAM;AACjB,MAAI,CAAC,YAAY,IAAI,KAAK,KAAK,CAC7B,QAAO,IAAI,KAAK,gDAAgD;AAElE,SAAO,IAAI,KAAK;;AAElB,QAAO,IAAI,QAAQ,KAAK;EACtB,SAAS;EACT,aAAa;EACb,WAAW,UAA8B;AACvC,OAAI,UAAU,KAAA,KAAa,CAAC,YAAY,MAAM,CAC5C,QAAO;;EAIZ,CAAC;;;;;;;;;AAUJ,eAAe,mBAAmB,KAAgD;AAChF,KAAI,IAAI,KAAK,YACX,QAAO,IAAI,KAAK;AAElB,QAAO,IAAI,QAAQ,KAAK;EACtB,cAAc;EACd,SAAS;EACT,aAAa;EACd,CAAC;;;;;;;;;AAUJ,eAAe,sBAAsB,KAAgD;AACnF,KAAI,IAAI,KAAK,GACX,QAAO,IAAI,KAAK;AAElB,QAAO,IAAI,QAAQ,OAAO;EACxB,SAAS;EACT,SAAS;GACP;IAAE,OAAO;IAAQ,OAAO;IAAQ;GAChC;IAAE,OAAO;IAAQ,OAAO;IAAQ;GAChC;IAAE,OAAO;IAAO,OAAO;IAAO;GAC/B;EACF,CAAC;;;;;;;;;AAUJ,eAAe,sBAAsB,KAAiD;AACpF,KAAI,IAAI,KAAK,YAAY,KAAA,EACvB,QAAO,IAAI,KAAK;AAElB,QAAO,IAAI,QAAQ,QAAQ;EACzB,cAAc;EACd,SAAS;EACV,CAAC;;;;;;;;;AAUJ,eAAe,qBAAqB,KAAiD;AACnF,KAAI,IAAI,KAAK,WAAW,KAAA,EACtB,QAAO,IAAI,KAAK;AAElB,QAAO,IAAI,QAAQ,QAAQ;EACzB,cAAc;EACd,SAAS;EACV,CAAC;;;;;;;;;;AAqBJ,SAAS,YACP,kBACA,UACyB;AACzB,QAAO,SACJ,QACE,SAAS,iBAAiB,kBAAkB,CAAC,KAAK,aAAa,SAAS,oBAAoB,CAC9F,CACA,QAAQ,SAAS,iBAAiB,iBAAiB,CAAC,KAAK,aAAa,SAAS,YAAY,CAAC;;AAGjG,MAAM,kBAAkB;;;;;;;;;;;AAYxB,eAAe,qBAAsC;CAEnD,MAAM,CAAC,OAAO,YAAY,MAAM,aADb,KAAK,OAAO,KAAK,SAAS,MAAM,KAAK,CACA;AACxD,KAAI,SAAS,CAAC,SAAS,SAAS;AAC9B,UAAQ,KAAK,+DAA+D;AAC5E,SAAO;;AAET,QAAO,SAAS;;;;;;;;;;;;;AAclB,eAAe,yBAAyB,aAAsC;CAC5E,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;CAC9C,MAAM,CAAC,cAAc,aAAa,cAAc,QAAQ,QAAQ,YAAY,CAAC;AAC7E,KAAI,gBAAgB,cAAc,MAAM;AACtC,UAAQ,KAAK,0CAA0C,YAAY,wBAAwB;AAC3F,SAAO;;CAIT,MAAM,CAAC,eAAe,YAAY,MAAM,aADrB,KAAK,QAAQ,UAAU,EAAE,KAAK,CACe;AAChE,KAAI,iBAAiB,CAAC,SAAS,SAAS;AACtC,UAAQ,KAAK,0CAA0C,YAAY,wBAAwB;AAC3F,SAAO;;AAGT,QAAO,SAAS"}
@@ -0,0 +1,19 @@
1
+ import { Command } from "maltty";
2
+
3
+ //#region src/commands/run.d.ts
4
+ /**
5
+ * Run the current maltty CLI project.
6
+ *
7
+ * Supports three engines:
8
+ * - `node` (default) — builds first, then runs `node dist/index.js`
9
+ * - `tsx` — runs the source entry file directly via `tsx`
10
+ * - `binary` — builds and compiles, then executes the compiled binary
11
+ *
12
+ * All unknown flags are forwarded to the executed CLI. Supports
13
+ * `--inspect`, `--inspect-brk`, `--inspect-wait`, and `--inspect-port`
14
+ * for attaching a debugger (node and tsx engines only).
15
+ */
16
+ declare const runCommand: Command;
17
+ //#endregion
18
+ export { runCommand as default };
19
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","names":[],"sources":["../../src/commands/run.ts"],"mappings":";;;;;AAQ6C;;;;;;;;;;cA6CvC,UAAA,EAAY,OAAA"}