thread.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { cmd } from "@/cli/cmd/cmd"
  2. import { tui } from "./app"
  3. import { Rpc } from "@/util/rpc"
  4. import { type rpc } from "./worker"
  5. import { upgrade } from "@/cli/upgrade"
  6. import { Session } from "@/session"
  7. import { bootstrap } from "@/cli/bootstrap"
  8. import path from "path"
  9. import { UI } from "@/cli/ui"
  10. export const TuiThreadCommand = cmd({
  11. command: "$0 [project]",
  12. describe: "start opencode tui",
  13. builder: (yargs) =>
  14. yargs
  15. .positional("project", {
  16. type: "string",
  17. describe: "path to start opencode in",
  18. })
  19. .option("model", {
  20. type: "string",
  21. alias: ["m"],
  22. describe: "model to use in the format of provider/model",
  23. })
  24. .option("continue", {
  25. alias: ["c"],
  26. describe: "continue the last session",
  27. type: "boolean",
  28. })
  29. .option("session", {
  30. alias: ["s"],
  31. describe: "session id to continue",
  32. type: "string",
  33. })
  34. .option("agent", {
  35. type: "string",
  36. describe: "agent to use",
  37. })
  38. .option("port", {
  39. type: "number",
  40. describe: "port to listen on",
  41. default: 0,
  42. })
  43. .option("hostname", {
  44. alias: ["h"],
  45. type: "string",
  46. describe: "hostname to listen on",
  47. default: "127.0.0.1",
  48. }),
  49. handler: async (args) => {
  50. const cwd = args.project ? path.resolve(args.project) : process.cwd()
  51. try {
  52. process.chdir(cwd)
  53. } catch (e) {
  54. UI.error("Failed to change directory to " + cwd)
  55. return
  56. }
  57. await bootstrap(cwd, async () => {
  58. upgrade()
  59. const sessionID = await (async () => {
  60. if (args.continue) {
  61. const it = Session.list()
  62. try {
  63. for await (const s of it) {
  64. if (s.parentID === undefined) {
  65. return s.id
  66. }
  67. }
  68. return
  69. } finally {
  70. await it.return()
  71. }
  72. }
  73. if (args.session) {
  74. return args.session
  75. }
  76. return undefined
  77. })()
  78. const worker = new Worker("./src/cli/cmd/tui/worker.ts")
  79. worker.onerror = console.error
  80. const client = Rpc.client<typeof rpc>(worker)
  81. process.on("uncaughtException", (e) => {
  82. console.error(e)
  83. })
  84. process.on("unhandledRejection", (e) => {
  85. console.error(e)
  86. })
  87. const server = await client.call("server", {
  88. port: args.port,
  89. hostname: args.hostname,
  90. })
  91. await tui({
  92. url: server.url,
  93. sessionID,
  94. model: args.model,
  95. agent: args.agent,
  96. onExit: async () => {
  97. await client.call("shutdown", undefined)
  98. },
  99. })
  100. })
  101. },
  102. })