index.ts 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. /**
  2. * Shared no-shell `execFile` runner for host-native OS integrations (the
  3. * native directory chooser, the open-with-default-application hand-off):
  4. * utf8 stdio capture, abort propagation, Windows console hide. A library,
  5. * not a plugin — no ctx, no state, no events.
  6. * @module @deepseek-ai/dsh-native-command
  7. */
  8. import { execFile } from 'node:child_process'
  9. /** Testable command boundary; native implementations never invoke a shell. */
  10. export type NativeCommandRunner = (
  11. command: string,
  12. args: readonly string[],
  13. signal: AbortSignal,
  14. ) => Promise<{ stdout: string; stderr: string }>
  15. /**
  16. * Run a host command with utf8 stdio, abort propagation, and Windows hide.
  17. * @param command - executable path or PATH name.
  18. * @param args - argv (never a shell string).
  19. * @param signal - caller/connection lifetime; abort terminates the child.
  20. * @returns captured stdout/stderr on exit 0.
  21. */
  22. export const runNativeCommand: NativeCommandRunner = (command, args, signal) =>
  23. new Promise((resolve, reject) => {
  24. execFile(
  25. command,
  26. [...args],
  27. { encoding: 'utf8', signal, windowsHide: true },
  28. (error, stdout, stderr) => {
  29. if (error !== null) {
  30. const failure = Object.assign(new Error(error.message, { cause: error }), {
  31. code: error.code,
  32. stdout,
  33. stderr,
  34. })
  35. reject(failure)
  36. return
  37. }
  38. resolve({ stdout, stderr })
  39. },
  40. )
  41. })