bin.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #!/usr/bin/env node
  2. /**
  3. * Command-line entry for dsh.
  4. * @module @deepseek-ai/dsh/bin
  5. */
  6. /* v8 ignore file -- built-bin acceptance exercises this self-executing dispatch. */
  7. import { readFileSync } from 'node:fs'
  8. import { fileURLToPath } from 'node:url'
  9. import { loadLayeredEnv, StartupError } from '@deepseek-ai/dsh-app-boot'
  10. import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
  11. import { parseDshArgs } from './args.ts'
  12. import { reportStartupFailure } from './startup-diagnostics.ts'
  13. // Both the source tree (apps/cli/src) and the bundled bin (apps/cli/lib) sit
  14. // one directory under apps/cli, so the checked-in manifest resolves with the
  15. // same relative hop from either artifact.
  16. function readVersion(): string {
  17. const manifest = JSON.parse(
  18. readFileSync(fileURLToPath(new URL('../package.json', import.meta.url)), 'utf8'),
  19. ) as { version?: unknown }
  20. return typeof manifest.version === 'string' ? manifest.version : '0.0.0'
  21. }
  22. /**
  23. * Run the public dsh command-line interface.
  24. * @returns a promise that settles when the selected command mode finishes.
  25. */
  26. export async function runCli(): Promise<void> {
  27. const version = readVersion()
  28. const invocation = parseDshArgs(process.argv.slice(2), version)
  29. switch (invocation.mode) {
  30. case 'profile': {
  31. const { runProfile } = await import('./profile-boot.ts')
  32. try {
  33. await runProfile({
  34. environment: loadLayeredEnv('dsh'),
  35. profile: invocation.profile,
  36. fromDefaultProfile: invocation.fromDefaultProfile,
  37. patchFiles: invocation.patches,
  38. args: invocation.args,
  39. })
  40. } catch (error) {
  41. if (!(error instanceof StartupError)) throw error
  42. await reportStartupFailure(error, { home: resolveDshHome(), version, profile: invocation.profile })
  43. process.exit(1)
  44. }
  45. break
  46. }
  47. case 'plugin': {
  48. const { runPlugin } = await import('./plugin.ts')
  49. process.exit(await runPlugin(invocation.profile, invocation.args))
  50. break
  51. }
  52. case 'dump-config': {
  53. const { runDumpConfig } = await import('./dump-config.ts')
  54. runDumpConfig(
  55. invocation.profile,
  56. invocation.defaultOnly,
  57. invocation.patches,
  58. invocation.fromDefaultProfile,
  59. )
  60. break
  61. }
  62. default:
  63. invocation satisfies never
  64. throw new Error(`dsh: unhandled invocation mode ${JSON.stringify(invocation)}`)
  65. }
  66. }
  67. if (import.meta.main) {
  68. await runCli()
  69. }