command.ts 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. /**
  2. * Internal dsh-sdk command composition used by the package bin.
  3. *
  4. * @module @deepseek-ai/dsh-scripts/command
  5. */
  6. import { parseDshSdkArgs } from './args.ts'
  7. import { runProjectBuild } from './build.ts'
  8. import { runConfigCommand, type ConfigCommandContext } from './config.ts'
  9. import { runCreatePluginCommand } from './create-plugin.ts'
  10. import { runSDK } from './runtime.ts'
  11. import { reportCommandTelemetry, type CommandTelemetryEvent } from './telemetry.ts'
  12. import { DSH_SDK_TEMPLATES } from './templates/dsh-sdk-templates.ts'
  13. /** Injectable process and command boundaries used by the dsh-sdk bin. */
  14. export interface DshSdkCommandContext extends ConfigCommandContext {
  15. cwd: string
  16. stdin: NodeJS.ReadStream
  17. stdout: NodeJS.WriteStream
  18. stderr: NodeJS.WriteStream
  19. run?: typeof runSDK
  20. build?: typeof runProjectBuild
  21. config?: typeof runConfigCommand
  22. createPlugin?: typeof runCreatePluginCommand
  23. telemetry?: (event: CommandTelemetryEvent) => Promise<void>
  24. }
  25. /** Run one parsed dsh-sdk command and return its process exit code. */
  26. export async function runDshSdkCommand(
  27. argv: readonly string[] = process.argv.slice(2),
  28. context: DshSdkCommandContext = {
  29. cwd: process.cwd(),
  30. stdin: process.stdin,
  31. stdout: process.stdout,
  32. stderr: process.stderr,
  33. },
  34. ): Promise<number> {
  35. const startedAt = Date.now()
  36. let command: string | undefined
  37. let success = true
  38. try {
  39. const args = parseDshSdkArgs(argv)
  40. if (args.help || !args.command) {
  41. context.stdout.write(DSH_SDK_TEMPLATES.usage.render({}))
  42. return 0
  43. }
  44. command = args.command
  45. const run = context.run ?? runSDK
  46. const build = context.build ?? runProjectBuild
  47. const config = context.config ?? runConfigCommand
  48. const createPlugin = context.createPlugin ?? runCreatePluginCommand
  49. switch (args.command) {
  50. case 'start': await run(args.target, { cwd: context.cwd, argv: args.forwarded }); break
  51. case 'dev': await run(args.target, { cwd: context.cwd, dev: true, argv: args.forwarded }); break
  52. case 'build': await build(args.forwarded, context.cwd); break
  53. case 'config': {
  54. const result = await config(context)
  55. if (result.installError) { success = false; return 1 }
  56. break
  57. }
  58. /* v8 ignore next -- Commander requires <source>, so create never dispatches without it */
  59. case 'create': await createPlugin(args.source ?? '', context); break
  60. }
  61. return 0
  62. } catch (error) {
  63. success = false
  64. context.stderr.write(`dsh-sdk: ${error instanceof Error ? error.message : String(error)}\n`)
  65. return 1
  66. } finally {
  67. if (command !== undefined) {
  68. /* v8 ignore next -- production telemetry wiring is exercised by the built-bin smoke */
  69. const telemetry = context.telemetry ?? reportCommandTelemetry
  70. await telemetry({ command, cwd: context.cwd, durationMs: Date.now() - startedAt, success })
  71. }
  72. }
  73. }