1
0

startup.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /**
  2. * The web app's command-line provider: it parses the `dsh --profile web` flag
  3. * family (`--host`, `--port`, `--trusted-host`) and its `--help`
  4. * text, then provides the immutable values as {@link WEB_STARTUP_SERVICE}.
  5. * Ordinary rows inject that service before reading it from lazy config.
  6. * @module @deepseek-ai/dsh-web-app/startup
  7. */
  8. import { Command } from 'commander'
  9. import type { Context } from '@deepseek-ai/cordis'
  10. import { parseCmdline } from '@deepseek-ai/dsh-cmdline'
  11. /** Stable Cordis plugin name. */
  12. export const name = 'web-startup'
  13. /** Services required before the flags can be resolved. */
  14. export const inject = ['cmdlineArgs']
  15. /** Service provided by this ordinary plugin and injected by flag-configured rows. */
  16. export const WEB_STARTUP_SERVICE = 'webStartup'
  17. /** What the web rows read from {@link WEB_STARTUP_SERVICE}. */
  18. export interface WebStartupValues {
  19. /** `--host`, absent when the invocation did not name one. */
  20. host?: string
  21. /** `--port`, absent when the invocation did not name one. */
  22. port?: number
  23. /** Explicit `--trusted-host` authorities, in argument order. */
  24. trustedHosts: string[]
  25. }
  26. /** The web flag family, as commander parsed it. */
  27. interface WebOptions {
  28. host?: string
  29. port?: string
  30. trustedHost?: string[]
  31. }
  32. /**
  33. * This app's command: its flags, its description, and its help text.
  34. * @returns a fresh program, so one process can parse more than once (tests).
  35. */
  36. function webCommand(): Command {
  37. return new Command()
  38. .name('dsh --profile web')
  39. .description('Serve the DeepSeek Harness browser UI.')
  40. .helpOption('-h, --help', 'show this help')
  41. .option('--host <host>', 'bind host; pass 0.0.0.0 to reach it from another machine')
  42. .option('--port <port>', 'listen port; pass 0 to let the OS pick a free one')
  43. .option('--trusted-host <authority...>', 'extra authority the /api browser-trust fence accepts (host or host:port; repeatable)')
  44. .addHelpText('after', `
  45. Examples:
  46. dsh --profile web serve on the composed host and port
  47. dsh --profile web --port 8080 serve on another port
  48. dsh --profile web --host 0.0.0.0 reach it from another machine on the LAN
  49. `)
  50. }
  51. /**
  52. * Turn the parsed flags into the value injected rows read.
  53. * @param program - the parsed web command.
  54. * @returns this invocation's immutable Web options.
  55. */
  56. function planWebStartup(program: Command): WebStartupValues {
  57. const options = program.opts<WebOptions>()
  58. if (options.port !== undefined && !/^\d+$/.test(options.port)) {
  59. program.error(`error: --port must be a number, got ${JSON.stringify(options.port)}`)
  60. }
  61. return {
  62. ...options.host !== undefined && { host: options.host },
  63. ...options.port !== undefined && { port: Number(options.port) },
  64. trustedHosts: options.trustedHost ?? [],
  65. }
  66. }
  67. /**
  68. * Parse and provide the Web invocation as an ordinary Cordis service.
  69. * @param ctx - plugin context carrying the command line.
  70. * @returns nothing once values are provided, or when the command requested exit.
  71. */
  72. export function apply(ctx: Context): void {
  73. const values = parseCmdline(ctx, webCommand(), planWebStartup)
  74. if (values !== undefined) ctx.provide(WEB_STARTUP_SERVICE, values)
  75. }