index.ts 3.9 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 { Bus } from "./bus"
  7. import { Session } from "./session"
  8. import cac from "cac"
  9. import { Share } from "./share/share"
  10. import { Message } from "./session/message"
  11. import { Global } from "./global"
  12. import { Provider } from "./provider/provider"
  13. declare global {
  14. const OPENCODE_VERSION: string
  15. }
  16. const cli = cac("opencode")
  17. const version = typeof OPENCODE_VERSION === "string" ? OPENCODE_VERSION : "dev"
  18. cli.command("", "Start the opencode in interactive mode").action(async () => {
  19. await App.provide({ cwd: process.cwd(), version }, async () => {
  20. await Share.init()
  21. const server = Server.listen()
  22. let cmd = ["go", "run", "./main.go"]
  23. let cwd = new URL("../../tui/cmd/opencode", import.meta.url).pathname
  24. if (Bun.embeddedFiles.length > 0) {
  25. const blob = Bun.embeddedFiles[0] as File
  26. const binary = path.join(Global.Path.cache, "tui", blob.name)
  27. const file = Bun.file(binary)
  28. if (!(await file.exists())) {
  29. console.log("installing tui binary...")
  30. await Bun.write(file, blob, { mode: 0o755 })
  31. await fs.chmod(binary, 0o755)
  32. }
  33. cwd = process.cwd()
  34. cmd = [binary]
  35. }
  36. const proc = Bun.spawn({
  37. cmd,
  38. cwd,
  39. stdout: "inherit",
  40. stderr: "inherit",
  41. stdin: "inherit",
  42. env: {
  43. ...process.env,
  44. OPENCODE_SERVER: server.url.toString(),
  45. },
  46. onExit: () => {
  47. server.stop()
  48. },
  49. })
  50. await proc.exited
  51. await server.stop()
  52. })
  53. })
  54. cli.command("generate", "Generate OpenAPI and event specs").action(async () => {
  55. const specs = await Server.openapi()
  56. const dir = "gen"
  57. await fs.rmdir(dir, { recursive: true }).catch(() => {})
  58. await fs.mkdir(dir, { recursive: true })
  59. await Bun.write(
  60. path.join(dir, "openapi.json"),
  61. JSON.stringify(specs, null, 2),
  62. )
  63. })
  64. cli
  65. .command("run [...message]", "Run a chat message")
  66. .option("--session <id>", "Session ID")
  67. .action(async (message: string[], options) => {
  68. await App.provide({ cwd: process.cwd(), version }, async () => {
  69. await Share.init()
  70. const session = options.session
  71. ? await Session.get(options.session)
  72. : await Session.create()
  73. console.log("Session:", session.id)
  74. Bus.subscribe(Message.Event.Updated, async () => {
  75. console.log("Thinking...")
  76. })
  77. const unsub = Bus.subscribe(Session.Event.Updated, async (message) => {
  78. if (message.properties.info.share?.url)
  79. console.log("Share:", message.properties.info.share.url)
  80. unsub()
  81. })
  82. const { providerID, modelID } = await Provider.defaultModel()
  83. const result = await Session.chat({
  84. sessionID: session.id,
  85. providerID,
  86. modelID,
  87. parts: [
  88. {
  89. type: "text",
  90. text: message.join(" "),
  91. },
  92. ],
  93. })
  94. for (const part of result.parts) {
  95. if (part.type === "text") {
  96. console.log("opencode:", part.text)
  97. }
  98. }
  99. console.log({
  100. cost: result.metadata.assistant?.cost,
  101. tokens: result.metadata.assistant?.tokens,
  102. })
  103. })
  104. })
  105. cli.command("init", "Run a chat message").action(async () => {
  106. await App.provide({ cwd: process.cwd(), version }, async () => {
  107. const { modelID, providerID } = await Provider.defaultModel()
  108. console.log("Initializing...")
  109. const session = await Session.create()
  110. const unsub = Bus.subscribe(Session.Event.Updated, async (message) => {
  111. if (message.properties.info.share?.url)
  112. console.log("Share:", message.properties.info.share.url)
  113. unsub()
  114. })
  115. await Session.initialize({
  116. sessionID: session.id,
  117. modelID,
  118. providerID,
  119. })
  120. })
  121. })
  122. cli.version(typeof OPENCODE_VERSION === "string" ? OPENCODE_VERSION : "dev")
  123. cli.help()
  124. cli.parse()