@maltty/cli 1.0.0-rc.0 → 1.0.0-rc.2

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 (107) hide show
  1. package/dist/{_format-CeQhQTl5.js → _format-XTN-U4H5.js} +4 -2
  2. package/dist/{_format-CeQhQTl5.js.map → _format-XTN-U4H5.js.map} +1 -1
  3. package/dist/attemptAsync-D_oWcKfe.js +74 -0
  4. package/dist/attemptAsync-D_oWcKfe.js.map +1 -0
  5. package/dist/commands/add/command.d.ts +0 -1
  6. package/dist/commands/add/command.d.ts.map +1 -1
  7. package/dist/commands/add/command.js +4 -4
  8. package/dist/commands/add/command.js.map +1 -1
  9. package/dist/commands/add/config.d.ts +0 -1
  10. package/dist/commands/add/config.d.ts.map +1 -1
  11. package/dist/commands/add/config.js +3 -3
  12. package/dist/commands/add/config.js.map +1 -1
  13. package/dist/commands/add/index.d.ts +0 -1
  14. package/dist/commands/add/index.d.ts.map +1 -1
  15. package/dist/commands/add/index.js.map +1 -1
  16. package/dist/commands/add/middleware.d.ts +0 -1
  17. package/dist/commands/add/middleware.d.ts.map +1 -1
  18. package/dist/commands/add/middleware.js +3 -3
  19. package/dist/commands/add/middleware.js.map +1 -1
  20. package/dist/commands/build.d.ts +7 -8
  21. package/dist/commands/build.d.ts.map +1 -1
  22. package/dist/commands/build.js +3 -3
  23. package/dist/commands/build.js.map +1 -1
  24. package/dist/commands/commands.d.ts +6 -7
  25. package/dist/commands/commands.d.ts.map +1 -1
  26. package/dist/commands/commands.js +5 -5
  27. package/dist/commands/commands.js.map +1 -1
  28. package/dist/commands/dev.d.ts +5 -6
  29. package/dist/commands/dev.d.ts.map +1 -1
  30. package/dist/commands/dev.js +3 -3
  31. package/dist/commands/dev.js.map +1 -1
  32. package/dist/commands/doctor.d.ts +5 -6
  33. package/dist/commands/doctor.d.ts.map +1 -1
  34. package/dist/commands/doctor.js +7 -6
  35. package/dist/commands/doctor.js.map +1 -1
  36. package/dist/commands/init.d.ts +0 -1
  37. package/dist/commands/init.d.ts.map +1 -1
  38. package/dist/commands/init.js +5 -5
  39. package/dist/commands/init.js.map +1 -1
  40. package/dist/commands/run.d.ts +11 -12
  41. package/dist/commands/run.d.ts.map +1 -1
  42. package/dist/commands/run.js +6 -6
  43. package/dist/commands/run.js.map +1 -1
  44. package/dist/commands/stories.d.ts +3 -4
  45. package/dist/commands/stories.d.ts.map +1 -1
  46. package/dist/commands/stories.js.map +1 -1
  47. package/dist/{config-helpers-pv_2Spux.js → config-helpers-DAy-Arox.js} +1 -1
  48. package/dist/{config-helpers-pv_2Spux.js.map → config-helpers-DAy-Arox.js.map} +1 -1
  49. package/dist/{defu-BBwssjW3.js → defu-BOMYL43b.js} +1 -13
  50. package/dist/{defu-BBwssjW3.js.map → defu-BOMYL43b.js.map} +1 -1
  51. package/dist/{detect-AOq1ehTE.js → detect-Gdceq3rh.js} +4 -4
  52. package/dist/{detect-AOq1ehTE.js.map → detect-Gdceq3rh.js.map} +1 -1
  53. package/dist/{dist-Xa07jNxS.js → dist-BGEDDbkB.js} +1430 -859
  54. package/dist/dist-BGEDDbkB.js.map +1 -0
  55. package/dist/{dist-DW_gRP7_.js → dist-FY8K5na4.js} +37 -8
  56. package/dist/dist-FY8K5na4.js.map +1 -0
  57. package/dist/fs-Uxhr-pvi-AfTuGWmD.js +98 -0
  58. package/dist/fs-Uxhr-pvi-AfTuGWmD.js.map +1 -0
  59. package/dist/index.d.ts +1 -1
  60. package/dist/index.js +2 -2
  61. package/dist/index.js.map +1 -1
  62. package/dist/{jiti-CxWlVmZ_.js → jiti-DLiXBetA.js} +15 -10
  63. package/dist/{jiti-CxWlVmZ_.js.map → jiti-DLiXBetA.js.map} +1 -1
  64. package/dist/json-DjLTvRvF.js +82 -0
  65. package/dist/json-DjLTvRvF.js.map +1 -0
  66. package/dist/{json5-z-PGDMyy.js → json5-Dgws4cj9.js} +22 -8
  67. package/dist/{json5-z-PGDMyy.js.map → json5-Dgws4cj9.js.map} +1 -1
  68. package/dist/{jsonc-DqZkfC3S.js → jsonc-B3DUZTiW.js} +9 -15
  69. package/dist/jsonc-B3DUZTiW.js.map +1 -0
  70. package/dist/jsonc-BjIiMOLf.js +2 -0
  71. package/dist/{main-C_8x2aB3.js → main-CMmTVJ4V.js} +2 -2
  72. package/dist/{main-C_8x2aB3.js.map → main-CMmTVJ4V.js.map} +1 -1
  73. package/dist/{manifest-BIKVDJML.js → manifest-C192Fk9X.js} +3 -3
  74. package/dist/{manifest-BIKVDJML.js.map → manifest-C192Fk9X.js.map} +1 -1
  75. package/dist/{multipart-parser-MNkxNO83.js → multipart-parser-XnJOfY8C.js} +14 -4
  76. package/dist/{multipart-parser-MNkxNO83.js.map → multipart-parser-XnJOfY8C.js.map} +1 -1
  77. package/dist/{node-C91xGGqn.js → node-Bbe24r0m.js} +28 -105
  78. package/dist/node-Bbe24r0m.js.map +1 -0
  79. package/dist/{node-Drmc03fL.js → node-lkjrm0W1.js} +95 -33
  80. package/dist/{node-Drmc03fL.js.map → node-lkjrm0W1.js.map} +1 -1
  81. package/dist/{ohash-BPoV4zBH.js → ohash-Cgvv31gH.js} +5 -3
  82. package/dist/ohash-Cgvv31gH.js.map +1 -0
  83. package/dist/pnpm-workspace.yaml +10 -10
  84. package/dist/{chunk-DsIazq42.js → rolldown-runtime-C7HZzL1F.js} +2 -2
  85. package/dist/{toml-LuHsHQtV.js → toml-BrfNstp2.js} +34 -3
  86. package/dist/{toml-LuHsHQtV.js.map → toml-BrfNstp2.js.map} +1 -1
  87. package/dist/{utils-DlIJNGLQ.js → utils-ioeFEbm4.js} +208 -236
  88. package/dist/utils-ioeFEbm4.js.map +1 -0
  89. package/dist/{validate-C_SXBoLq.js → validate-CX8axBK6.js} +1 -1
  90. package/dist/{validate-C_SXBoLq.js.map → validate-CX8axBK6.js.map} +1 -1
  91. package/dist/{write-CSwG4Stj.js → write-C6VsyUuc.js} +6 -4
  92. package/dist/{write-CSwG4Stj.js.map → write-C6VsyUuc.js.map} +1 -1
  93. package/dist/{yaml-BS9RDuUr.js → yaml-Cp5SldPx.js} +78 -18
  94. package/dist/yaml-Cp5SldPx.js.map +1 -0
  95. package/package.json +14 -14
  96. package/dist/attemptAsync-BdXzRSIT.js +0 -42
  97. package/dist/attemptAsync-BdXzRSIT.js.map +0 -1
  98. package/dist/dist-DW_gRP7_.js.map +0 -1
  99. package/dist/dist-Xa07jNxS.js.map +0 -1
  100. package/dist/json-D7WbuVK1.js +0 -43
  101. package/dist/json-D7WbuVK1.js.map +0 -1
  102. package/dist/jsonc-DqZkfC3S.js.map +0 -1
  103. package/dist/jsonc-KADMdSjU.js +0 -2
  104. package/dist/node-C91xGGqn.js.map +0 -1
  105. package/dist/ohash-BPoV4zBH.js.map +0 -1
  106. package/dist/utils-DlIJNGLQ.js.map +0 -1
  107. package/dist/yaml-BS9RDuUr.js.map +0 -1
@@ -1,9 +1,10 @@
1
- import { n as err, r as ok } from "../attemptAsync-BdXzRSIT.js";
2
- import { i as M, r as fs_exports } from "../node-C91xGGqn.js";
3
- import { n as DEFAULT_ENTRY, t as DEFAULT_COMMANDS } from "../dist-DW_gRP7_.js";
4
- import { n as jsonStringify, t as jsonParse } from "../json-D7WbuVK1.js";
5
- import { t as readManifest } from "../manifest-BIKVDJML.js";
6
- import { n as loadConfig } from "../utils-DlIJNGLQ.js";
1
+ import { n as err, r as ok } from "../attemptAsync-D_oWcKfe.js";
2
+ import { r as M } from "../node-Bbe24r0m.js";
3
+ import { n as DEFAULT_ENTRY, t as DEFAULT_COMMANDS } from "../dist-FY8K5na4.js";
4
+ import { n as jsonStringify, t as jsonParse } from "../json-DjLTvRvF.js";
5
+ import { t as readManifest } from "../manifest-C192Fk9X.js";
6
+ import { t as fs_exports } from "../fs-Uxhr-pvi-AfTuGWmD.js";
7
+ import { n as loadConfig } from "../utils-ioeFEbm4.js";
7
8
  import { command } from "maltty";
8
9
  import { dirname, join, relative } from "node:path";
9
10
  import { z } from "zod";
@@ -1 +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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"}
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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"}
@@ -1,5 +1,4 @@
1
1
  import { Command } from "maltty";
2
-
3
2
  //#region src/commands/init.d.ts
4
3
  declare const initCommand: Command;
5
4
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","names":[],"sources":["../../src/commands/init.ts"],"mappings":";;;cAyBM,WAAA,EAAa,OAAA"}
1
+ {"version":3,"file":"init.d.ts","names":[],"sources":["../../src/commands/init.ts"],"mappings":";;cAyBM,aAAa"}
@@ -1,8 +1,8 @@
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";
1
+ import { n as err, r as ok } from "../attemptAsync-D_oWcKfe.js";
2
+ import { r as attempt } from "../json-DjLTvRvF.js";
3
+ import { t as readManifest } from "../manifest-C192Fk9X.js";
4
+ import { n as renderTemplate, t as writeFiles } from "../write-C6VsyUuc.js";
5
+ import { t as isKebabCase } from "../validate-CX8axBK6.js";
6
6
  import { createRequire } from "node:module";
7
7
  import { command } from "maltty";
8
8
  import { dirname, join } from "node:path";
@@ -1 +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":"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"}
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":"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"}
@@ -1,18 +1,17 @@
1
1
  import { Command } from "maltty";
2
-
3
2
  //#region src/commands/run.d.ts
4
3
  /**
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
- */
4
+ * Run the current maltty CLI project.
5
+ *
6
+ * Supports three engines:
7
+ * - `node` (default) — builds first, then runs `node dist/index.js`
8
+ * - `tsx` — runs the source entry file directly via `tsx`
9
+ * - `binary` — builds and compiles, then executes the compiled binary
10
+ *
11
+ * All unknown flags are forwarded to the executed CLI. Supports
12
+ * `--inspect`, `--inspect-brk`, `--inspect-wait`, and `--inspect-port`
13
+ * for attaching a debugger (node and tsx engines only).
14
+ */
16
15
  declare const runCommand: Command;
17
16
  //#endregion
18
17
  export { runCommand as default };
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","names":[],"sources":["../../src/commands/run.ts"],"mappings":";;;;;AAQ6C;;;;;;;;;;cA6CvC,UAAA,EAAY,OAAA"}
1
+ {"version":3,"file":"run.d.ts","names":[],"sources":["../../src/commands/run.ts"],"mappings":";;;;;;;;;;;;;;cAqDM,YAAY"}
@@ -1,7 +1,7 @@
1
- import { i as M, n as process_exports } from "../node-C91xGGqn.js";
2
- import { i as normalizeCompileOptions, r as createBundler } from "../dist-DW_gRP7_.js";
3
- import { n as loadConfig, t as compileTargets } from "../utils-DlIJNGLQ.js";
4
- import { t as extractConfig } from "../config-helpers-pv_2Spux.js";
1
+ import { n as process_exports, r as M } from "../node-Bbe24r0m.js";
2
+ import { i as normalizeCompileOptions, r as createBundler } from "../dist-FY8K5na4.js";
3
+ import { n as loadConfig, t as compileTargets } from "../utils-ioeFEbm4.js";
4
+ import { t as extractConfig } from "../config-helpers-DAy-Arox.js";
5
5
  import { command } from "maltty";
6
6
  import { resolve } from "node:path";
7
7
  import { z } from "zod";
@@ -344,7 +344,7 @@ function extractPassthroughArgs() {
344
344
  *
345
345
  * @private
346
346
  */
347
- const KNOWN_BOOLEAN_FLAGS = new Set([
347
+ const KNOWN_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
348
348
  "--inspect",
349
349
  "--inspect-brk",
350
350
  "--inspect-wait"
@@ -354,7 +354,7 @@ const KNOWN_BOOLEAN_FLAGS = new Set([
354
354
  *
355
355
  * @private
356
356
  */
357
- const KNOWN_VALUE_FLAGS = new Set([
357
+ const KNOWN_VALUE_FLAGS = /* @__PURE__ */ new Set([
358
358
  "--engine",
359
359
  "--inspect-port",
360
360
  "--target"
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","names":["match","proc"],"sources":["../../src/commands/run.ts"],"sourcesContent":["import { resolve } from 'node:path'\n\nimport { createBundler, DEFAULT_ENTRY, normalizeCompileOptions } from '@maltty/bundler'\nimport type { BuildOutput, Bundler, CompileOutput, CompiledBinary } from '@maltty/bundler'\nimport type { CompileTarget, MalttyConfig } from '@maltty/config'\nimport { compileTargets, loadConfig } from '@maltty/config/utils'\nimport { process as proc } from '@maltty/utils/node'\nimport { command } from 'maltty'\nimport type { Command, CommandContext } from 'maltty'\nimport { match } from 'ts-pattern'\nimport { z } from 'zod'\n\nimport { extractConfig } from '../lib/config-helpers.js'\n\nconst EngineSchema = z.enum(['node', 'tsx', 'binary'])\n\nconst compileTargetValues = compileTargets.map((entry) => entry.target) as [\n CompileTarget,\n ...CompileTarget[],\n]\nconst TargetSchema = z.enum(compileTargetValues)\n\nconst options = z.object({\n engine: EngineSchema.default('node').describe(\n 'Runtime engine: node (built), tsx (source), or binary (compiled)'\n ),\n inspect: z.boolean().optional().describe('Enable the Node.js inspector (--inspect)'),\n 'inspect-brk': z\n .boolean()\n .optional()\n .describe('Enable the Node.js inspector and break before user code starts (--inspect-brk)'),\n 'inspect-port': z.number().optional().describe('Set the inspector port'),\n 'inspect-wait': z\n .boolean()\n .optional()\n .describe('Enable the Node.js inspector and wait for debugger to attach (--inspect-wait)'),\n target: z.string().optional().describe('Compile target for binary engine (e.g. darwin-arm64)'),\n})\n\ntype RunArgs = z.infer<typeof options>\n\n/**\n * Run the current maltty CLI project.\n *\n * Supports three engines:\n * - `node` (default) — builds first, then runs `node dist/index.js`\n * - `tsx` — runs the source entry file directly via `tsx`\n * - `binary` — builds and compiles, then executes the compiled binary\n *\n * All unknown flags are forwarded to the executed CLI. Supports\n * `--inspect`, `--inspect-brk`, `--inspect-wait`, and `--inspect-port`\n * for attaching a debugger (node and tsx engines only).\n */\nconst runCommand: Command = command({\n options,\n strict: false,\n description: 'Run the current maltty CLI project',\n handler: async (ctx: CommandContext<RunArgs>) => {\n const cwd = process.cwd()\n\n const [configError, configResult] = await loadConfig({ cwd })\n\n if (configError) {\n return ctx.fail(configError.message)\n }\n\n const config = extractConfig(configResult)\n\n if (ctx.args.engine === 'binary' && hasInspectFlag(ctx.args)) {\n return ctx.fail(\n 'Inspector flags are not supported with the binary engine. Use --engine=node or --engine=tsx instead.'\n )\n }\n\n const passthroughArgs = extractPassthroughArgs()\n\n const exitCode = await match(ctx.args.engine)\n .with('node', () => runWithNode({ args: ctx.args, config, cwd, passthroughArgs, ctx }))\n .with('tsx', () => runWithTsx({ args: ctx.args, config, cwd, passthroughArgs, ctx }))\n .with('binary', () => runWithBinary({ args: ctx.args, config, cwd, passthroughArgs, ctx }))\n .exhaustive()\n\n if (exitCode !== 0) {\n return ctx.fail(`Process exited with code ${exitCode}`)\n }\n },\n})\n\nexport default runCommand\n\n// ---------------------------------------------------------------------------\n\n/**\n * Build the project and run the bundled entry file with `node`.\n *\n * @private\n * @param params - Engine execution parameters.\n * @returns The exit code of the spawned process.\n */\nasync function runWithNode(params: EngineParams): Promise<number> {\n const bundler = await createBundler({ config: params.config, cwd: params.cwd })\n const buildOutput = await buildProject({ bundler, ctx: params.ctx })\n const inspectFlags = buildInspectFlags(params.args)\n\n return spawnProcess({\n args: [...inspectFlags, buildOutput.entryFile, ...params.passthroughArgs],\n cmd: 'node',\n cwd: params.cwd,\n })\n}\n\n/**\n * Run the source entry file directly with `tsx`.\n *\n * @private\n * @param params - Engine execution parameters.\n * @returns The exit code of the spawned process.\n */\nasync function runWithTsx(params: EngineParams): Promise<number> {\n const entryFile = resolve(params.cwd, params.config.entry ?? DEFAULT_ENTRY)\n const inspectFlags = buildInspectFlags(params.args)\n\n return spawnProcess({\n args: [...inspectFlags, entryFile, ...params.passthroughArgs],\n cmd: 'tsx',\n cwd: params.cwd,\n })\n}\n\n/**\n * Build and compile the project, then execute the compiled binary.\n *\n * Requires compile targets to be configured in `maltty.config.ts` or\n * provided via `--target`. Resolves the current platform's binary\n * from the compile output.\n *\n * @private\n * @param params - Engine execution parameters.\n * @returns The exit code of the spawned process.\n */\nasync function runWithBinary(params: EngineParams): Promise<number> {\n const validatedTarget = validateTarget({ ctx: params.ctx, target: params.args.target })\n\n const configWithTarget = applyTargetOverride({\n config: params.config,\n target: validatedTarget,\n })\n\n if (!hasCompileTargets(configWithTarget)) {\n return params.ctx.fail(\n 'No compile targets configured. Set targets in maltty.config.ts or use --target.'\n )\n }\n\n const bundler = await createBundler({ config: configWithTarget, cwd: params.cwd })\n\n await buildProject({ bundler, ctx: params.ctx })\n\n params.ctx.status.spinner.message('Compiling binary...')\n\n const compileOutput = await compileProject({ bundler, ctx: params.ctx })\n\n const binary = resolveBinary({\n compileOutput,\n ctx: params.ctx,\n target: params.args.target,\n })\n\n params.ctx.status.spinner.stop('Build complete')\n\n return spawnProcess({\n args: params.passthroughArgs,\n cmd: binary.path,\n cwd: params.cwd,\n })\n}\n\n/**\n * Parameters shared across all engine execution functions.\n *\n * @private\n */\ninterface EngineParams {\n readonly args: RunArgs\n readonly config: MalttyConfig\n readonly ctx: CommandContext<RunArgs>\n readonly cwd: string\n readonly passthroughArgs: readonly string[]\n}\n\n/**\n * Build the project using the bundler and return the build output.\n *\n * Starts a spinner, invokes the build, and fails the command on error.\n *\n * @private\n * @param params - The bundler instance and command context.\n * @returns The successful build output.\n */\nasync function buildProject(params: {\n readonly bundler: Bundler\n readonly ctx: CommandContext<RunArgs>\n}): Promise<BuildOutput> {\n params.ctx.status.spinner.start('Building...')\n\n const [buildError, buildOutput] = await params.bundler.build()\n\n if (buildError) {\n params.ctx.status.spinner.stop('Build failed')\n return params.ctx.fail(buildError.message)\n }\n\n params.ctx.status.spinner.stop('Built')\n\n return buildOutput\n}\n\n/**\n * Compile the project into standalone binaries.\n *\n * @private\n * @param params - The bundler instance and command context.\n * @returns The successful compile output.\n */\nasync function compileProject(params: {\n readonly bundler: Bundler\n readonly ctx: CommandContext<RunArgs>\n}): Promise<CompileOutput> {\n const [compileError, compileOutput] = await params.bundler.compile()\n\n if (compileError) {\n params.ctx.status.spinner.stop('Compile failed')\n return params.ctx.fail(compileError.message)\n }\n\n return compileOutput\n}\n\n/**\n * Resolve the binary to execute from compile output.\n *\n * When `--target` is provided, finds the matching binary. Otherwise\n * detects the host platform and architecture to find the correct binary.\n *\n * @private\n * @param params - The compile output, optional target, and command context.\n * @returns The resolved compiled binary.\n */\nfunction resolveBinary(params: {\n readonly compileOutput: CompileOutput\n readonly ctx: CommandContext<RunArgs>\n readonly target: string | undefined\n}): CompiledBinary {\n if (params.target) {\n const binary = params.compileOutput.binaries.find((b) => b.target === params.target)\n\n if (!binary) {\n return params.ctx.fail(`No binary found for target \"${params.target}\"`)\n }\n\n return binary\n }\n\n const hostTarget = resolveHostTarget()\n const candidates = resolveHostTargetCandidates(hostTarget)\n const binary = findFirstMatchingBinary(params.compileOutput.binaries, candidates)\n\n if (!binary) {\n return params.ctx.fail(`No binary found for target \"${hostTarget}\"`)\n }\n\n return binary\n}\n\n/**\n * Build an ordered list of candidate targets for the current host.\n *\n * On Linux x64, includes both the musl variant (`linux-x64-musl`) and the\n * glibc variant (`linux-x64`) so the correct binary is found on Alpine-like\n * hosts. The musl variant is preferred when available.\n *\n * @private\n * @param hostTarget - The base host target string (e.g. `linux-x64`).\n * @returns An ordered list of candidate target strings to try.\n */\nfunction resolveHostTargetCandidates(hostTarget: string): readonly string[] {\n if (hostTarget === 'linux-x64') {\n return [`${hostTarget}-musl`, hostTarget]\n }\n\n return [hostTarget]\n}\n\n/**\n * Find the first binary matching any of the candidate targets.\n *\n * @private\n * @param binaries - The compiled binaries to search.\n * @param candidates - Ordered candidate target strings.\n * @returns The first matching binary, or `undefined`.\n */\nfunction findFirstMatchingBinary(\n binaries: readonly CompiledBinary[],\n candidates: readonly string[]\n): CompiledBinary | undefined {\n return candidates.reduce<CompiledBinary | undefined>(\n (found, candidate) => found ?? binaries.find((b) => b.target === candidate),\n undefined\n )\n}\n\n/**\n * Map from Node.js `process.platform` to compile target OS prefix.\n *\n * @private\n */\nconst PLATFORM_MAP: Readonly<Record<string, string>> = {\n darwin: 'darwin',\n linux: 'linux',\n win32: 'windows',\n}\n\n/**\n * Map from Node.js `process.arch` to compile target architecture suffix.\n *\n * @private\n */\nconst ARCH_MAP: Readonly<Record<string, string>> = {\n arm64: 'arm64',\n x64: 'x64',\n}\n\n/**\n * Detect the host platform and architecture, returning a compile target string.\n *\n * Combines `process.platform` and `process.arch` into a target like `darwin-arm64`.\n *\n * @private\n * @returns The compile target string for the current host.\n */\nfunction resolveHostTarget(): string {\n const os = PLATFORM_MAP[process.platform] ?? process.platform\n const arch = ARCH_MAP[process.arch] ?? process.arch\n return `${os}-${arch}`\n}\n\n/**\n * Check whether a config has compilation enabled.\n *\n * Returns `true` for `compile: true` (boolean shorthand), for object configs\n * that omit `targets` (the bundler fills in defaults), and for object configs\n * with a non-empty `targets` array. Only returns `false` when compile is\n * `false`, `undefined`, or an object with an explicitly empty `targets` array.\n *\n * @private\n * @param config - The maltty config to check.\n * @returns `true` when compilation is enabled.\n */\nfunction hasCompileTargets(config: MalttyConfig): boolean {\n if (config.compile === true) {\n return true\n }\n\n if (typeof config.compile !== 'object') {\n return false\n }\n\n if (config.compile.targets === undefined) {\n return true\n }\n\n return config.compile.targets.length > 0\n}\n\n/**\n * Validate a `--target` string against known compile targets.\n *\n * Returns the validated target when provided, or `undefined` when no target\n * was specified. Fails the command with a descriptive error for invalid values.\n *\n * @private\n * @param params - The target string and command context.\n * @returns The validated compile target, or `undefined`.\n */\nfunction validateTarget(params: {\n readonly ctx: CommandContext<RunArgs>\n readonly target: string | undefined\n}): CompileTarget | undefined {\n if (!params.target) {\n return undefined\n }\n\n const parsed = TargetSchema.safeParse(params.target)\n\n if (!parsed.success) {\n const validTargets = TargetSchema.options.join(', ')\n return params.ctx.fail(\n `Invalid compile target \"${params.target}\". Must be one of: ${validTargets}`\n )\n }\n\n return parsed.data\n}\n\n/**\n * Apply a `--target` CLI override to the config's compile targets.\n *\n * @private\n * @param params - The config and optional validated target override.\n * @returns A config with the target override applied.\n */\nfunction applyTargetOverride(params: {\n readonly config: MalttyConfig\n readonly target: CompileTarget | undefined\n}): MalttyConfig {\n if (!params.target) {\n return params.config\n }\n\n const existingCompile = normalizeCompileOptions(params.config.compile)\n\n return {\n ...params.config,\n compile: {\n ...existingCompile,\n targets: [params.target],\n },\n }\n}\n\n/**\n * Extract passthrough arguments by sequentially walking argv tokens\n * and skipping known `maltty run` flags and their values.\n *\n * Uses positional parsing: when a known flag that takes a value is\n * encountered (e.g. `--engine`), the next token is also skipped.\n * This avoids the fragile value-based matching that could accidentally\n * consume user CLI arguments that happen to match a known flag's value.\n *\n * @private\n * @returns An array of arguments to forward to the user's CLI.\n */\nfunction extractPassthroughArgs(): readonly string[] {\n const argv = process.argv.slice(2)\n const runIndex = argv.indexOf('run')\n\n if (runIndex === -1) {\n return []\n }\n\n const afterRun = argv.slice(runIndex + 1)\n\n return collectPassthroughTokens(afterRun)\n}\n\n/**\n * Known boolean flags for the `maltty run` command (no value follows).\n *\n * @private\n */\nconst KNOWN_BOOLEAN_FLAGS: ReadonlySet<string> = new Set([\n '--inspect',\n '--inspect-brk',\n '--inspect-wait',\n])\n\n/**\n * Known value flags for the `maltty run` command (next token is consumed as value).\n *\n * @private\n */\nconst KNOWN_VALUE_FLAGS: ReadonlySet<string> = new Set(['--engine', '--inspect-port', '--target'])\n\n/**\n * Walk an array of CLI tokens sequentially and collect only passthrough args.\n *\n * Skips known boolean flags, known value flags (and their following value token),\n * and `--flag=value` forms. All other tokens are collected as passthrough.\n *\n * @private\n * @param tokens - The CLI tokens after the `run` subcommand.\n * @returns The filtered passthrough arguments.\n */\nfunction collectPassthroughTokens(tokens: readonly string[]): readonly string[] {\n return tokens.reduce<{ readonly result: readonly string[]; readonly skip: boolean }>(\n (acc, token) => {\n if (acc.skip) {\n return { result: acc.result, skip: false }\n }\n\n if (KNOWN_BOOLEAN_FLAGS.has(token)) {\n return { result: acc.result, skip: false }\n }\n\n if (KNOWN_VALUE_FLAGS.has(token)) {\n return { result: acc.result, skip: true }\n }\n\n if (isKnownEqualsSyntax(token)) {\n return { result: acc.result, skip: false }\n }\n\n return { result: [...acc.result, token], skip: false }\n },\n { result: [], skip: false }\n ).result\n}\n\n/**\n * Check whether a token uses `--flag=value` syntax for a known flag.\n *\n * @private\n * @param token - The CLI token to check.\n * @returns `true` when the token is a known flag in `--flag=value` form.\n */\nfunction isKnownEqualsSyntax(token: string): boolean {\n const eqIndex = token.indexOf('=')\n if (eqIndex <= 0) {\n return false\n }\n\n const flagPart = token.slice(0, eqIndex)\n return KNOWN_BOOLEAN_FLAGS.has(flagPart) || KNOWN_VALUE_FLAGS.has(flagPart)\n}\n\n/**\n * Check whether any inspector flag is set, including `--inspect-port`.\n *\n * @private\n * @param args - The parsed CLI args.\n * @returns `true` when any inspector flag is enabled.\n */\nfunction hasInspectFlag(args: RunArgs): boolean {\n return (\n args.inspect === true ||\n args['inspect-brk'] === true ||\n args['inspect-wait'] === true ||\n args['inspect-port'] !== undefined\n )\n}\n\n/**\n * Build inspector-related Node.js flags from parsed CLI args.\n *\n * Only one inspector mode is active at a time, with `inspect-brk` taking\n * precedence over `inspect-wait`, which takes precedence over `inspect`.\n *\n * @private\n * @param args - The parsed CLI args.\n * @returns An array of inspector flags.\n */\nfunction buildInspectFlags(args: RunArgs): readonly string[] {\n const flag = resolveInspectMode(args)\n\n if (!flag) {\n return []\n }\n\n return [formatInspectFlag(flag, args['inspect-port'])]\n}\n\n/**\n * Determine which inspector mode to use based on parsed CLI args.\n *\n * When only `--inspect-port` is provided without an explicit mode,\n * defaults to `'inspect'` so the port is not silently ignored.\n *\n * @private\n * @param args - The parsed CLI args.\n * @returns The inspector flag name, or `undefined` if none is active.\n */\nfunction resolveInspectMode(args: RunArgs): string | undefined {\n if (args['inspect-brk']) {\n return 'inspect-brk'\n }\n\n if (args['inspect-wait']) {\n return 'inspect-wait'\n }\n\n if (args.inspect) {\n return 'inspect'\n }\n\n if (args['inspect-port'] !== undefined) {\n return 'inspect'\n }\n\n return undefined\n}\n\n/**\n * Format an inspector flag with an optional port.\n *\n * @private\n * @param flag - The inspector flag name (e.g. 'inspect', 'inspect-brk').\n * @param port - Optional port number.\n * @returns The formatted flag string.\n */\nfunction formatInspectFlag(flag: string, port: number | undefined): string {\n if (port !== undefined) {\n return `--${flag}=${port}`\n }\n\n return `--${flag}`\n}\n\n/**\n * Spawn a process with the given command and arguments, inheriting stdio.\n *\n * @private\n * @param params - The command, arguments, and working directory.\n * @returns The exit code of the spawned process.\n */\nfunction spawnProcess(params: {\n readonly cmd: string\n readonly args: readonly string[]\n readonly cwd: string\n}): Promise<number> {\n return proc.spawn(params)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run.js","names":["match","proc"],"sources":["../../src/commands/run.ts"],"sourcesContent":["import { resolve } from 'node:path'\n\nimport { createBundler, DEFAULT_ENTRY, normalizeCompileOptions } from '@maltty/bundler'\nimport type { BuildOutput, Bundler, CompileOutput, CompiledBinary } from '@maltty/bundler'\nimport type { CompileTarget, MalttyConfig } from '@maltty/config'\nimport { compileTargets, loadConfig } from '@maltty/config/utils'\nimport { process as proc } from '@maltty/utils/node'\nimport { command } from 'maltty'\nimport type { Command, CommandContext } from 'maltty'\nimport { match } from 'ts-pattern'\nimport { z } from 'zod'\n\nimport { extractConfig } from '../lib/config-helpers.js'\n\nconst EngineSchema = z.enum(['node', 'tsx', 'binary'])\n\nconst compileTargetValues = compileTargets.map((entry) => entry.target) as [\n CompileTarget,\n ...CompileTarget[],\n]\nconst TargetSchema = z.enum(compileTargetValues)\n\nconst options = z.object({\n engine: EngineSchema.default('node').describe(\n 'Runtime engine: node (built), tsx (source), or binary (compiled)'\n ),\n inspect: z.boolean().optional().describe('Enable the Node.js inspector (--inspect)'),\n 'inspect-brk': z\n .boolean()\n .optional()\n .describe('Enable the Node.js inspector and break before user code starts (--inspect-brk)'),\n 'inspect-port': z.number().optional().describe('Set the inspector port'),\n 'inspect-wait': z\n .boolean()\n .optional()\n .describe('Enable the Node.js inspector and wait for debugger to attach (--inspect-wait)'),\n target: z.string().optional().describe('Compile target for binary engine (e.g. darwin-arm64)'),\n})\n\ntype RunArgs = z.infer<typeof options>\n\n/**\n * Run the current maltty CLI project.\n *\n * Supports three engines:\n * - `node` (default) — builds first, then runs `node dist/index.js`\n * - `tsx` — runs the source entry file directly via `tsx`\n * - `binary` — builds and compiles, then executes the compiled binary\n *\n * All unknown flags are forwarded to the executed CLI. Supports\n * `--inspect`, `--inspect-brk`, `--inspect-wait`, and `--inspect-port`\n * for attaching a debugger (node and tsx engines only).\n */\nconst runCommand: Command = command({\n options,\n strict: false,\n description: 'Run the current maltty CLI project',\n handler: async (ctx: CommandContext<RunArgs>) => {\n const cwd = process.cwd()\n\n const [configError, configResult] = await loadConfig({ cwd })\n\n if (configError) {\n return ctx.fail(configError.message)\n }\n\n const config = extractConfig(configResult)\n\n if (ctx.args.engine === 'binary' && hasInspectFlag(ctx.args)) {\n return ctx.fail(\n 'Inspector flags are not supported with the binary engine. Use --engine=node or --engine=tsx instead.'\n )\n }\n\n const passthroughArgs = extractPassthroughArgs()\n\n const exitCode = await match(ctx.args.engine)\n .with('node', () => runWithNode({ args: ctx.args, config, cwd, passthroughArgs, ctx }))\n .with('tsx', () => runWithTsx({ args: ctx.args, config, cwd, passthroughArgs, ctx }))\n .with('binary', () => runWithBinary({ args: ctx.args, config, cwd, passthroughArgs, ctx }))\n .exhaustive()\n\n if (exitCode !== 0) {\n return ctx.fail(`Process exited with code ${exitCode}`)\n }\n },\n})\n\nexport default runCommand\n\n// ---------------------------------------------------------------------------\n\n/**\n * Build the project and run the bundled entry file with `node`.\n *\n * @private\n * @param params - Engine execution parameters.\n * @returns The exit code of the spawned process.\n */\nasync function runWithNode(params: EngineParams): Promise<number> {\n const bundler = await createBundler({ config: params.config, cwd: params.cwd })\n const buildOutput = await buildProject({ bundler, ctx: params.ctx })\n const inspectFlags = buildInspectFlags(params.args)\n\n return spawnProcess({\n args: [...inspectFlags, buildOutput.entryFile, ...params.passthroughArgs],\n cmd: 'node',\n cwd: params.cwd,\n })\n}\n\n/**\n * Run the source entry file directly with `tsx`.\n *\n * @private\n * @param params - Engine execution parameters.\n * @returns The exit code of the spawned process.\n */\nasync function runWithTsx(params: EngineParams): Promise<number> {\n const entryFile = resolve(params.cwd, params.config.entry ?? DEFAULT_ENTRY)\n const inspectFlags = buildInspectFlags(params.args)\n\n return spawnProcess({\n args: [...inspectFlags, entryFile, ...params.passthroughArgs],\n cmd: 'tsx',\n cwd: params.cwd,\n })\n}\n\n/**\n * Build and compile the project, then execute the compiled binary.\n *\n * Requires compile targets to be configured in `maltty.config.ts` or\n * provided via `--target`. Resolves the current platform's binary\n * from the compile output.\n *\n * @private\n * @param params - Engine execution parameters.\n * @returns The exit code of the spawned process.\n */\nasync function runWithBinary(params: EngineParams): Promise<number> {\n const validatedTarget = validateTarget({ ctx: params.ctx, target: params.args.target })\n\n const configWithTarget = applyTargetOverride({\n config: params.config,\n target: validatedTarget,\n })\n\n if (!hasCompileTargets(configWithTarget)) {\n return params.ctx.fail(\n 'No compile targets configured. Set targets in maltty.config.ts or use --target.'\n )\n }\n\n const bundler = await createBundler({ config: configWithTarget, cwd: params.cwd })\n\n await buildProject({ bundler, ctx: params.ctx })\n\n params.ctx.status.spinner.message('Compiling binary...')\n\n const compileOutput = await compileProject({ bundler, ctx: params.ctx })\n\n const binary = resolveBinary({\n compileOutput,\n ctx: params.ctx,\n target: params.args.target,\n })\n\n params.ctx.status.spinner.stop('Build complete')\n\n return spawnProcess({\n args: params.passthroughArgs,\n cmd: binary.path,\n cwd: params.cwd,\n })\n}\n\n/**\n * Parameters shared across all engine execution functions.\n *\n * @private\n */\ninterface EngineParams {\n readonly args: RunArgs\n readonly config: MalttyConfig\n readonly ctx: CommandContext<RunArgs>\n readonly cwd: string\n readonly passthroughArgs: readonly string[]\n}\n\n/**\n * Build the project using the bundler and return the build output.\n *\n * Starts a spinner, invokes the build, and fails the command on error.\n *\n * @private\n * @param params - The bundler instance and command context.\n * @returns The successful build output.\n */\nasync function buildProject(params: {\n readonly bundler: Bundler\n readonly ctx: CommandContext<RunArgs>\n}): Promise<BuildOutput> {\n params.ctx.status.spinner.start('Building...')\n\n const [buildError, buildOutput] = await params.bundler.build()\n\n if (buildError) {\n params.ctx.status.spinner.stop('Build failed')\n return params.ctx.fail(buildError.message)\n }\n\n params.ctx.status.spinner.stop('Built')\n\n return buildOutput\n}\n\n/**\n * Compile the project into standalone binaries.\n *\n * @private\n * @param params - The bundler instance and command context.\n * @returns The successful compile output.\n */\nasync function compileProject(params: {\n readonly bundler: Bundler\n readonly ctx: CommandContext<RunArgs>\n}): Promise<CompileOutput> {\n const [compileError, compileOutput] = await params.bundler.compile()\n\n if (compileError) {\n params.ctx.status.spinner.stop('Compile failed')\n return params.ctx.fail(compileError.message)\n }\n\n return compileOutput\n}\n\n/**\n * Resolve the binary to execute from compile output.\n *\n * When `--target` is provided, finds the matching binary. Otherwise\n * detects the host platform and architecture to find the correct binary.\n *\n * @private\n * @param params - The compile output, optional target, and command context.\n * @returns The resolved compiled binary.\n */\nfunction resolveBinary(params: {\n readonly compileOutput: CompileOutput\n readonly ctx: CommandContext<RunArgs>\n readonly target: string | undefined\n}): CompiledBinary {\n if (params.target) {\n const binary = params.compileOutput.binaries.find((b) => b.target === params.target)\n\n if (!binary) {\n return params.ctx.fail(`No binary found for target \"${params.target}\"`)\n }\n\n return binary\n }\n\n const hostTarget = resolveHostTarget()\n const candidates = resolveHostTargetCandidates(hostTarget)\n const binary = findFirstMatchingBinary(params.compileOutput.binaries, candidates)\n\n if (!binary) {\n return params.ctx.fail(`No binary found for target \"${hostTarget}\"`)\n }\n\n return binary\n}\n\n/**\n * Build an ordered list of candidate targets for the current host.\n *\n * On Linux x64, includes both the musl variant (`linux-x64-musl`) and the\n * glibc variant (`linux-x64`) so the correct binary is found on Alpine-like\n * hosts. The musl variant is preferred when available.\n *\n * @private\n * @param hostTarget - The base host target string (e.g. `linux-x64`).\n * @returns An ordered list of candidate target strings to try.\n */\nfunction resolveHostTargetCandidates(hostTarget: string): readonly string[] {\n if (hostTarget === 'linux-x64') {\n return [`${hostTarget}-musl`, hostTarget]\n }\n\n return [hostTarget]\n}\n\n/**\n * Find the first binary matching any of the candidate targets.\n *\n * @private\n * @param binaries - The compiled binaries to search.\n * @param candidates - Ordered candidate target strings.\n * @returns The first matching binary, or `undefined`.\n */\nfunction findFirstMatchingBinary(\n binaries: readonly CompiledBinary[],\n candidates: readonly string[]\n): CompiledBinary | undefined {\n return candidates.reduce<CompiledBinary | undefined>(\n (found, candidate) => found ?? binaries.find((b) => b.target === candidate),\n undefined\n )\n}\n\n/**\n * Map from Node.js `process.platform` to compile target OS prefix.\n *\n * @private\n */\nconst PLATFORM_MAP: Readonly<Record<string, string>> = {\n darwin: 'darwin',\n linux: 'linux',\n win32: 'windows',\n}\n\n/**\n * Map from Node.js `process.arch` to compile target architecture suffix.\n *\n * @private\n */\nconst ARCH_MAP: Readonly<Record<string, string>> = {\n arm64: 'arm64',\n x64: 'x64',\n}\n\n/**\n * Detect the host platform and architecture, returning a compile target string.\n *\n * Combines `process.platform` and `process.arch` into a target like `darwin-arm64`.\n *\n * @private\n * @returns The compile target string for the current host.\n */\nfunction resolveHostTarget(): string {\n const os = PLATFORM_MAP[process.platform] ?? process.platform\n const arch = ARCH_MAP[process.arch] ?? process.arch\n return `${os}-${arch}`\n}\n\n/**\n * Check whether a config has compilation enabled.\n *\n * Returns `true` for `compile: true` (boolean shorthand), for object configs\n * that omit `targets` (the bundler fills in defaults), and for object configs\n * with a non-empty `targets` array. Only returns `false` when compile is\n * `false`, `undefined`, or an object with an explicitly empty `targets` array.\n *\n * @private\n * @param config - The maltty config to check.\n * @returns `true` when compilation is enabled.\n */\nfunction hasCompileTargets(config: MalttyConfig): boolean {\n if (config.compile === true) {\n return true\n }\n\n if (typeof config.compile !== 'object') {\n return false\n }\n\n if (config.compile.targets === undefined) {\n return true\n }\n\n return config.compile.targets.length > 0\n}\n\n/**\n * Validate a `--target` string against known compile targets.\n *\n * Returns the validated target when provided, or `undefined` when no target\n * was specified. Fails the command with a descriptive error for invalid values.\n *\n * @private\n * @param params - The target string and command context.\n * @returns The validated compile target, or `undefined`.\n */\nfunction validateTarget(params: {\n readonly ctx: CommandContext<RunArgs>\n readonly target: string | undefined\n}): CompileTarget | undefined {\n if (!params.target) {\n return undefined\n }\n\n const parsed = TargetSchema.safeParse(params.target)\n\n if (!parsed.success) {\n const validTargets = TargetSchema.options.join(', ')\n return params.ctx.fail(\n `Invalid compile target \"${params.target}\". Must be one of: ${validTargets}`\n )\n }\n\n return parsed.data\n}\n\n/**\n * Apply a `--target` CLI override to the config's compile targets.\n *\n * @private\n * @param params - The config and optional validated target override.\n * @returns A config with the target override applied.\n */\nfunction applyTargetOverride(params: {\n readonly config: MalttyConfig\n readonly target: CompileTarget | undefined\n}): MalttyConfig {\n if (!params.target) {\n return params.config\n }\n\n const existingCompile = normalizeCompileOptions(params.config.compile)\n\n return {\n ...params.config,\n compile: {\n ...existingCompile,\n targets: [params.target],\n },\n }\n}\n\n/**\n * Extract passthrough arguments by sequentially walking argv tokens\n * and skipping known `maltty run` flags and their values.\n *\n * Uses positional parsing: when a known flag that takes a value is\n * encountered (e.g. `--engine`), the next token is also skipped.\n * This avoids the fragile value-based matching that could accidentally\n * consume user CLI arguments that happen to match a known flag's value.\n *\n * @private\n * @returns An array of arguments to forward to the user's CLI.\n */\nfunction extractPassthroughArgs(): readonly string[] {\n const argv = process.argv.slice(2)\n const runIndex = argv.indexOf('run')\n\n if (runIndex === -1) {\n return []\n }\n\n const afterRun = argv.slice(runIndex + 1)\n\n return collectPassthroughTokens(afterRun)\n}\n\n/**\n * Known boolean flags for the `maltty run` command (no value follows).\n *\n * @private\n */\nconst KNOWN_BOOLEAN_FLAGS: ReadonlySet<string> = new Set([\n '--inspect',\n '--inspect-brk',\n '--inspect-wait',\n])\n\n/**\n * Known value flags for the `maltty run` command (next token is consumed as value).\n *\n * @private\n */\nconst KNOWN_VALUE_FLAGS: ReadonlySet<string> = new Set(['--engine', '--inspect-port', '--target'])\n\n/**\n * Walk an array of CLI tokens sequentially and collect only passthrough args.\n *\n * Skips known boolean flags, known value flags (and their following value token),\n * and `--flag=value` forms. All other tokens are collected as passthrough.\n *\n * @private\n * @param tokens - The CLI tokens after the `run` subcommand.\n * @returns The filtered passthrough arguments.\n */\nfunction collectPassthroughTokens(tokens: readonly string[]): readonly string[] {\n return tokens.reduce<{ readonly result: readonly string[]; readonly skip: boolean }>(\n (acc, token) => {\n if (acc.skip) {\n return { result: acc.result, skip: false }\n }\n\n if (KNOWN_BOOLEAN_FLAGS.has(token)) {\n return { result: acc.result, skip: false }\n }\n\n if (KNOWN_VALUE_FLAGS.has(token)) {\n return { result: acc.result, skip: true }\n }\n\n if (isKnownEqualsSyntax(token)) {\n return { result: acc.result, skip: false }\n }\n\n return { result: [...acc.result, token], skip: false }\n },\n { result: [], skip: false }\n ).result\n}\n\n/**\n * Check whether a token uses `--flag=value` syntax for a known flag.\n *\n * @private\n * @param token - The CLI token to check.\n * @returns `true` when the token is a known flag in `--flag=value` form.\n */\nfunction isKnownEqualsSyntax(token: string): boolean {\n const eqIndex = token.indexOf('=')\n if (eqIndex <= 0) {\n return false\n }\n\n const flagPart = token.slice(0, eqIndex)\n return KNOWN_BOOLEAN_FLAGS.has(flagPart) || KNOWN_VALUE_FLAGS.has(flagPart)\n}\n\n/**\n * Check whether any inspector flag is set, including `--inspect-port`.\n *\n * @private\n * @param args - The parsed CLI args.\n * @returns `true` when any inspector flag is enabled.\n */\nfunction hasInspectFlag(args: RunArgs): boolean {\n return (\n args.inspect === true ||\n args['inspect-brk'] === true ||\n args['inspect-wait'] === true ||\n args['inspect-port'] !== undefined\n )\n}\n\n/**\n * Build inspector-related Node.js flags from parsed CLI args.\n *\n * Only one inspector mode is active at a time, with `inspect-brk` taking\n * precedence over `inspect-wait`, which takes precedence over `inspect`.\n *\n * @private\n * @param args - The parsed CLI args.\n * @returns An array of inspector flags.\n */\nfunction buildInspectFlags(args: RunArgs): readonly string[] {\n const flag = resolveInspectMode(args)\n\n if (!flag) {\n return []\n }\n\n return [formatInspectFlag(flag, args['inspect-port'])]\n}\n\n/**\n * Determine which inspector mode to use based on parsed CLI args.\n *\n * When only `--inspect-port` is provided without an explicit mode,\n * defaults to `'inspect'` so the port is not silently ignored.\n *\n * @private\n * @param args - The parsed CLI args.\n * @returns The inspector flag name, or `undefined` if none is active.\n */\nfunction resolveInspectMode(args: RunArgs): string | undefined {\n if (args['inspect-brk']) {\n return 'inspect-brk'\n }\n\n if (args['inspect-wait']) {\n return 'inspect-wait'\n }\n\n if (args.inspect) {\n return 'inspect'\n }\n\n if (args['inspect-port'] !== undefined) {\n return 'inspect'\n }\n\n return undefined\n}\n\n/**\n * Format an inspector flag with an optional port.\n *\n * @private\n * @param flag - The inspector flag name (e.g. 'inspect', 'inspect-brk').\n * @param port - Optional port number.\n * @returns The formatted flag string.\n */\nfunction formatInspectFlag(flag: string, port: number | undefined): string {\n if (port !== undefined) {\n return `--${flag}=${port}`\n }\n\n return `--${flag}`\n}\n\n/**\n * Spawn a process with the given command and arguments, inheriting stdio.\n *\n * @private\n * @param params - The command, arguments, and working directory.\n * @returns The exit code of the spawned process.\n */\nfunction spawnProcess(params: {\n readonly cmd: string\n readonly args: readonly string[]\n readonly cwd: string\n}): Promise<number> {\n return proc.spawn(params)\n}\n"],"mappings":"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"}
@@ -1,10 +1,9 @@
1
1
  import { Command } from "maltty";
2
-
3
2
  //#region src/commands/stories.d.ts
4
3
  /**
5
- * Launch the stories viewer TUI for browsing and editing
6
- * component stories in the terminal.
7
- */
4
+ * Launch the stories viewer TUI for browsing and editing
5
+ * component stories in the terminal.
6
+ */
8
7
  declare const storiesCommand: Command;
9
8
  //#endregion
10
9
  export { storiesCommand as default };
@@ -1 +1 @@
1
- {"version":3,"file":"stories.d.ts","names":[],"sources":["../../src/commands/stories.ts"],"mappings":";;;;;AAA6B;;cAkBvB,cAAA,EAAgB,OAAA"}
1
+ {"version":3,"file":"stories.d.ts","names":[],"sources":["../../src/commands/stories.ts"],"mappings":";;;;;;cAkBM,gBAAgB"}
@@ -1 +1 @@
1
- {"version":3,"file":"stories.js","names":[],"sources":["../../src/commands/stories.ts"],"sourcesContent":["import type { Command } from 'maltty'\nimport { StoriesScreen } from 'maltty/stories'\nimport { screen } from 'maltty/ui'\nimport { z } from 'zod'\n\n/**\n * Options schema for the `maltty stories` command.\n */\nconst options = z.object({\n include: z.string().describe('Glob pattern for story files').optional(),\n out: z.string().describe('Render story to stdout (pass story name, or omit for all)').optional(),\n check: z.boolean().describe('Validate stories for common issues').default(false),\n})\n\n/**\n * Launch the stories viewer TUI for browsing and editing\n * component stories in the terminal.\n */\nconst storiesCommand: Command = screen({\n description: 'Browse and preview component stories in the terminal',\n options,\n exit: 'manual',\n render: StoriesScreen,\n})\n\nexport default storiesCommand\n"],"mappings":";;;;;;;;AAkBA,MAAM,iBAA0B,OAAO;CACrC,aAAa;CACb,SAZc,EAAE,OAAO;EACvB,SAAS,EAAE,QAAQ,CAAC,SAAS,+BAA+B,CAAC,UAAU;EACvE,KAAK,EAAE,QAAQ,CAAC,SAAS,4DAA4D,CAAC,UAAU;EAChG,OAAO,EAAE,SAAS,CAAC,SAAS,qCAAqC,CAAC,QAAQ,MAAM;EACjF,CAAC;CASA,MAAM;CACN,QAAQ;CACT,CAAC"}
1
+ {"version":3,"file":"stories.js","names":[],"sources":["../../src/commands/stories.ts"],"sourcesContent":["import type { Command } from 'maltty'\nimport { StoriesScreen } from 'maltty/stories'\nimport { screen } from 'maltty/ui'\nimport { z } from 'zod'\n\n/**\n * Options schema for the `maltty stories` command.\n */\nconst options = z.object({\n include: z.string().describe('Glob pattern for story files').optional(),\n out: z.string().describe('Render story to stdout (pass story name, or omit for all)').optional(),\n check: z.boolean().describe('Validate stories for common issues').default(false),\n})\n\n/**\n * Launch the stories viewer TUI for browsing and editing\n * component stories in the terminal.\n */\nconst storiesCommand: Command = screen({\n description: 'Browse and preview component stories in the terminal',\n options,\n exit: 'manual',\n render: StoriesScreen,\n})\n\nexport default storiesCommand\n"],"mappings":";;;;;;;;AAkBA,MAAM,iBAA0B,OAAO;CACrC,aAAa;CACb,SAZc,EAAE,OAAO;EACvB,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS,8BAA8B,CAAC,CAAC,SAAS;EACtE,KAAK,EAAE,OAAO,CAAC,CAAC,SAAS,2DAA2D,CAAC,CAAC,SAAS;EAC/F,OAAO,EAAE,QAAQ,CAAC,CAAC,SAAS,oCAAoC,CAAC,CAAC,QAAQ,KAAK;CACjF,CAQQ;CACN,MAAM;CACN,QAAQ;AACV,CAAC"}
@@ -12,4 +12,4 @@ function extractConfig(result) {
12
12
  //#endregion
13
13
  export { extractConfig as t };
14
14
 
15
- //# sourceMappingURL=config-helpers-pv_2Spux.js.map
15
+ //# sourceMappingURL=config-helpers-DAy-Arox.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-helpers-pv_2Spux.js","names":[],"sources":["../src/lib/config-helpers.ts"],"sourcesContent":["import type { MalttyConfig } from '@maltty/config'\nimport type { LoadConfigResult } from '@maltty/config/utils'\n\n/**\n * Extract a MalttyConfig from a load result, falling back to empty defaults.\n *\n * @param result - The result from loadConfig, or null when loading failed.\n * @returns The loaded config or an empty object (all MalttyConfig fields are optional).\n */\nexport function extractConfig(result: LoadConfigResult | null): MalttyConfig {\n if (result) {\n return result.config\n }\n\n return {}\n}\n"],"mappings":";;;;;;;AASA,SAAgB,cAAc,QAA+C;AAC3E,KAAI,OACF,QAAO,OAAO;AAGhB,QAAO,EAAE"}
1
+ {"version":3,"file":"config-helpers-DAy-Arox.js","names":[],"sources":["../src/lib/config-helpers.ts"],"sourcesContent":["import type { MalttyConfig } from '@maltty/config'\nimport type { LoadConfigResult } from '@maltty/config/utils'\n\n/**\n * Extract a MalttyConfig from a load result, falling back to empty defaults.\n *\n * @param result - The result from loadConfig, or null when loading failed.\n * @returns The loaded config or an empty object (all MalttyConfig fields are optional).\n */\nexport function extractConfig(result: LoadConfigResult | null): MalttyConfig {\n if (result) {\n return result.config\n }\n\n return {}\n}\n"],"mappings":";;;;;;;AASA,SAAgB,cAAc,QAA+C;CAC3E,IAAI,QACF,OAAO,OAAO;CAGhB,OAAO,CAAC;AACV"}
@@ -174,19 +174,7 @@ function createDefu(merger) {
174
174
  return (...arguments_) => arguments_.reduce((p, c) => _defu(p, c, "", merger), {});
175
175
  }
176
176
  const defu = createDefu();
177
- createDefu((object, key, currentValue) => {
178
- if (object[key] !== void 0 && typeof currentValue === "function") {
179
- object[key] = currentValue(object[key]);
180
- return true;
181
- }
182
- });
183
- createDefu((object, key, currentValue) => {
184
- if (Array.isArray(object[key]) && typeof currentValue === "function") {
185
- object[key] = currentValue(object[key]);
186
- return true;
187
- }
188
- });
189
177
  //#endregion
190
178
  export { isAbsolute as a, relative as c, extname as i, resolve as l, basename as n, join as o, dirname as r, normalize as s, defu as t };
191
179
 
192
- //# sourceMappingURL=defu-BBwssjW3.js.map
180
+ //# sourceMappingURL=defu-BOMYL43b.js.map