2
0

index.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import yargs from "yargs"
  2. import { hideBin } from "yargs/helpers"
  3. import { RunCommand } from "./cli/cmd/run"
  4. import { GenerateCommand } from "./cli/cmd/generate"
  5. import { Log } from "./util/log"
  6. import { AuthCommand } from "./cli/cmd/auth"
  7. import { AgentCommand } from "./cli/cmd/agent"
  8. import { UpgradeCommand } from "./cli/cmd/upgrade"
  9. import { UninstallCommand } from "./cli/cmd/uninstall"
  10. import { ModelsCommand } from "./cli/cmd/models"
  11. import { UI } from "./cli/ui"
  12. import { Installation } from "./installation"
  13. import { NamedError } from "@opencode-ai/util/error"
  14. import { FormatError } from "./cli/error"
  15. import { ServeCommand } from "./cli/cmd/serve"
  16. import { DebugCommand } from "./cli/cmd/debug"
  17. import { StatsCommand } from "./cli/cmd/stats"
  18. import { McpCommand } from "./cli/cmd/mcp"
  19. import { GithubCommand } from "./cli/cmd/github"
  20. import { ExportCommand } from "./cli/cmd/export"
  21. import { ImportCommand } from "./cli/cmd/import"
  22. import { AttachCommand } from "./cli/cmd/tui/attach"
  23. import { TuiThreadCommand } from "./cli/cmd/tui/thread"
  24. import { TuiSpawnCommand } from "./cli/cmd/tui/spawn"
  25. import { AcpCommand } from "./cli/cmd/acp"
  26. import { EOL } from "os"
  27. import { WebCommand } from "./cli/cmd/web"
  28. import { PrCommand } from "./cli/cmd/pr"
  29. import { SessionCommand } from "./cli/cmd/session"
  30. process.on("unhandledRejection", (e) => {
  31. Log.Default.error("rejection", {
  32. e: e instanceof Error ? e.message : e,
  33. })
  34. })
  35. process.on("uncaughtException", (e) => {
  36. Log.Default.error("exception", {
  37. e: e instanceof Error ? e.message : e,
  38. })
  39. })
  40. const cli = yargs(hideBin(process.argv))
  41. .parserConfiguration({ "populate--": true })
  42. .scriptName("opencode")
  43. .wrap(100)
  44. .help("help", "show help")
  45. .alias("help", "h")
  46. .version("version", "show version number", Installation.VERSION)
  47. .alias("version", "v")
  48. .option("print-logs", {
  49. describe: "print logs to stderr",
  50. type: "boolean",
  51. })
  52. .option("log-level", {
  53. describe: "log level",
  54. type: "string",
  55. choices: ["DEBUG", "INFO", "WARN", "ERROR"],
  56. })
  57. .middleware(async (opts) => {
  58. await Log.init({
  59. print: process.argv.includes("--print-logs"),
  60. dev: Installation.isLocal(),
  61. level: (() => {
  62. if (opts.logLevel) return opts.logLevel as Log.Level
  63. if (Installation.isLocal()) return "DEBUG"
  64. return "INFO"
  65. })(),
  66. })
  67. process.env.AGENT = "1"
  68. process.env.OPENCODE = "1"
  69. Log.Default.info("opencode", {
  70. version: Installation.VERSION,
  71. args: process.argv.slice(2),
  72. })
  73. })
  74. .usage("\n" + UI.logo())
  75. .command(AcpCommand)
  76. .command(McpCommand)
  77. .command(TuiThreadCommand)
  78. .command(TuiSpawnCommand)
  79. .command(AttachCommand)
  80. .command(RunCommand)
  81. .command(GenerateCommand)
  82. .command(DebugCommand)
  83. .command(AuthCommand)
  84. .command(AgentCommand)
  85. .command(UpgradeCommand)
  86. .command(UninstallCommand)
  87. .command(ServeCommand)
  88. .command(WebCommand)
  89. .command(ModelsCommand)
  90. .command(StatsCommand)
  91. .command(ExportCommand)
  92. .command(ImportCommand)
  93. .command(GithubCommand)
  94. .command(PrCommand)
  95. .command(SessionCommand)
  96. .fail((msg) => {
  97. if (
  98. msg.startsWith("Unknown argument") ||
  99. msg.startsWith("Not enough non-option arguments") ||
  100. msg.startsWith("Invalid values:")
  101. ) {
  102. cli.showHelp("log")
  103. }
  104. process.exit(1)
  105. })
  106. .strict()
  107. try {
  108. await cli.parse()
  109. } catch (e) {
  110. let data: Record<string, any> = {}
  111. if (e instanceof NamedError) {
  112. const obj = e.toObject()
  113. Object.assign(data, {
  114. ...obj.data,
  115. })
  116. }
  117. if (e instanceof Error) {
  118. Object.assign(data, {
  119. name: e.name,
  120. message: e.message,
  121. cause: e.cause?.toString(),
  122. stack: e.stack,
  123. })
  124. }
  125. if (e instanceof ResolveMessage) {
  126. Object.assign(data, {
  127. name: e.name,
  128. message: e.message,
  129. code: e.code,
  130. specifier: e.specifier,
  131. referrer: e.referrer,
  132. position: e.position,
  133. importKind: e.importKind,
  134. })
  135. }
  136. Log.Default.error("fatal", data)
  137. const formatted = FormatError(e)
  138. if (formatted) UI.error(formatted)
  139. if (formatted === undefined) {
  140. UI.error("Unexpected error, check log file at " + Log.file() + " for more details" + EOL)
  141. console.error(e)
  142. }
  143. process.exitCode = 1
  144. } finally {
  145. // Some subprocesses don't react properly to SIGTERM and similar signals.
  146. // Most notably, some docker-container-based MCP servers don't handle such signals unless
  147. // run using `docker run --init`.
  148. // Explicitly exit to avoid any hanging subprocesses.
  149. process.exit()
  150. }