index.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import "zod-openapi/extend"
  2. import { App } from "./app/app"
  3. import { Server } from "./server/server"
  4. import fs from "fs/promises"
  5. import path from "path"
  6. import { Share } from "./share/share"
  7. import { Global } from "./global"
  8. import yargs from "yargs"
  9. import { hideBin } from "yargs/helpers"
  10. import { RunCommand } from "./cli/cmd/run"
  11. import { GenerateCommand } from "./cli/cmd/generate"
  12. import { ScrapCommand } from "./cli/cmd/scrap"
  13. import { Log } from "./util/log"
  14. import { AuthCommand, AuthLoginCommand } from "./cli/cmd/auth"
  15. import { UpgradeCommand } from "./cli/cmd/upgrade"
  16. import { Provider } from "./provider/provider"
  17. import { UI } from "./cli/ui"
  18. import { GlobalConfig } from "./global/config"
  19. import { Installation } from "./installation"
  20. import { Bus } from "./bus"
  21. const cli = yargs(hideBin(process.argv))
  22. .scriptName("opencode")
  23. .version(Installation.VERSION)
  24. .option("print-logs", {
  25. describe: "Print logs to stderr",
  26. type: "boolean",
  27. })
  28. .middleware(async () => {
  29. await Log.init({ print: process.argv.includes("--print-logs") })
  30. Log.Default.info("opencode", {
  31. version: Installation.VERSION,
  32. args: process.argv.slice(2),
  33. })
  34. })
  35. .usage("\n" + UI.logo())
  36. .command({
  37. command: "$0 [project]",
  38. describe: "Start opencode TUI",
  39. builder: (yargs) =>
  40. yargs.positional("project", {
  41. type: "string",
  42. describe: "path to start opencode in",
  43. }),
  44. handler: async (args) => {
  45. while (true) {
  46. const cwd = args.project ? path.resolve(args.project) : process.cwd()
  47. process.chdir(cwd)
  48. const result = await App.provide({ cwd }, async (app) => {
  49. const providers = await Provider.list()
  50. if (Object.keys(providers).length === 0) {
  51. return "needs_provider"
  52. }
  53. await Share.init()
  54. const server = Server.listen()
  55. let cmd = ["go", "run", "./main.go"]
  56. let cwd = new URL("../../tui/cmd/opencode", import.meta.url).pathname
  57. if (Bun.embeddedFiles.length > 0) {
  58. const blob = Bun.embeddedFiles[0] as File
  59. const binary = path.join(Global.Path.cache, "tui", blob.name)
  60. const file = Bun.file(binary)
  61. if (!(await file.exists())) {
  62. await Bun.write(file, blob, { mode: 0o755 })
  63. await fs.chmod(binary, 0o755)
  64. }
  65. cwd = process.cwd()
  66. cmd = [binary]
  67. }
  68. const proc = Bun.spawn({
  69. cmd: [...cmd, ...process.argv.slice(2)],
  70. cwd,
  71. stdout: "inherit",
  72. stderr: "inherit",
  73. stdin: "inherit",
  74. env: {
  75. ...process.env,
  76. OPENCODE_SERVER: server.url.toString(),
  77. OPENCODE_APP_INFO: JSON.stringify(app),
  78. },
  79. onExit: () => {
  80. server.stop()
  81. },
  82. })
  83. ;(async () => {
  84. if (Installation.VERSION === "dev") return
  85. if (Installation.isSnapshot()) return
  86. const config = await GlobalConfig.get()
  87. if (config.autoupdate === false) return
  88. const latest = await Installation.latest()
  89. if (Installation.VERSION === latest) return
  90. const method = await Installation.method()
  91. if (method === "unknown") return
  92. await Installation.upgrade(method, latest)
  93. .then(() => {
  94. Bus.publish(Installation.Event.Updated, { version: latest })
  95. })
  96. .catch(() => {})
  97. })()
  98. await proc.exited
  99. await server.stop()
  100. return "done"
  101. })
  102. if (result === "done") break
  103. if (result === "needs_provider") {
  104. UI.empty()
  105. UI.println(UI.logo(" "))
  106. UI.empty()
  107. await AuthLoginCommand.handler(args)
  108. }
  109. }
  110. },
  111. })
  112. .command(RunCommand)
  113. .command(GenerateCommand)
  114. .command(ScrapCommand)
  115. .command(AuthCommand)
  116. .command(UpgradeCommand)
  117. .fail((msg) => {
  118. if (
  119. msg.startsWith("Unknown argument") ||
  120. msg.startsWith("Not enough non-option arguments")
  121. ) {
  122. cli.showHelp("log")
  123. }
  124. })
  125. .strict()
  126. try {
  127. await cli.parse()
  128. } catch (e) {
  129. Log.Default.error(e, {
  130. stack: e instanceof Error ? e.stack : undefined,
  131. })
  132. }