cerebras-cli 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/cerebras-cli-1.0.0.tgz +0 -0
  2. package/package.json +7 -88
  3. package/AGENTS.md +0 -27
  4. package/Dockerfile +0 -10
  5. package/bunfig.toml +0 -4
  6. package/parsers-config.ts +0 -239
  7. package/script/build.ts +0 -151
  8. package/script/postinstall.mjs +0 -122
  9. package/script/publish.ts +0 -256
  10. package/script/schema.ts +0 -47
  11. package/src/acp/README.md +0 -164
  12. package/src/acp/agent.ts +0 -812
  13. package/src/acp/session.ts +0 -70
  14. package/src/acp/types.ts +0 -22
  15. package/src/agent/agent.ts +0 -310
  16. package/src/agent/generate.txt +0 -75
  17. package/src/auth/index.ts +0 -70
  18. package/src/bun/index.ts +0 -152
  19. package/src/bus/global.ts +0 -10
  20. package/src/bus/index.ts +0 -142
  21. package/src/cli/bootstrap.ts +0 -17
  22. package/src/cli/cmd/acp.ts +0 -88
  23. package/src/cli/cmd/agent.ts +0 -165
  24. package/src/cli/cmd/auth.ts +0 -369
  25. package/src/cli/cmd/cmd.ts +0 -7
  26. package/src/cli/cmd/debug/config.ts +0 -15
  27. package/src/cli/cmd/debug/file.ts +0 -91
  28. package/src/cli/cmd/debug/index.ts +0 -41
  29. package/src/cli/cmd/debug/lsp.ts +0 -47
  30. package/src/cli/cmd/debug/ripgrep.ts +0 -83
  31. package/src/cli/cmd/debug/scrap.ts +0 -15
  32. package/src/cli/cmd/debug/snapshot.ts +0 -48
  33. package/src/cli/cmd/export.ts +0 -88
  34. package/src/cli/cmd/generate.ts +0 -38
  35. package/src/cli/cmd/github.ts +0 -1200
  36. package/src/cli/cmd/import.ts +0 -98
  37. package/src/cli/cmd/mcp.ts +0 -400
  38. package/src/cli/cmd/models.ts +0 -77
  39. package/src/cli/cmd/pr.ts +0 -112
  40. package/src/cli/cmd/run.ts +0 -342
  41. package/src/cli/cmd/serve.ts +0 -31
  42. package/src/cli/cmd/session.ts +0 -106
  43. package/src/cli/cmd/stats.ts +0 -298
  44. package/src/cli/cmd/tui/app.tsx +0 -732
  45. package/src/cli/cmd/tui/attach.ts +0 -25
  46. package/src/cli/cmd/tui/component/border.tsx +0 -21
  47. package/src/cli/cmd/tui/component/dialog-agent.tsx +0 -31
  48. package/src/cli/cmd/tui/component/dialog-command.tsx +0 -124
  49. package/src/cli/cmd/tui/component/dialog-feedback.tsx +0 -160
  50. package/src/cli/cmd/tui/component/dialog-mcp.tsx +0 -86
  51. package/src/cli/cmd/tui/component/dialog-model.tsx +0 -223
  52. package/src/cli/cmd/tui/component/dialog-notification.tsx +0 -78
  53. package/src/cli/cmd/tui/component/dialog-provider.tsx +0 -222
  54. package/src/cli/cmd/tui/component/dialog-session-list.tsx +0 -97
  55. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +0 -31
  56. package/src/cli/cmd/tui/component/dialog-status.tsx +0 -114
  57. package/src/cli/cmd/tui/component/dialog-tag.tsx +0 -44
  58. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +0 -50
  59. package/src/cli/cmd/tui/component/logo.tsx +0 -37
  60. package/src/cli/cmd/tui/component/notification-banner.tsx +0 -58
  61. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +0 -530
  62. package/src/cli/cmd/tui/component/prompt/history.tsx +0 -107
  63. package/src/cli/cmd/tui/component/prompt/index.tsx +0 -931
  64. package/src/cli/cmd/tui/context/args.tsx +0 -14
  65. package/src/cli/cmd/tui/context/directory.ts +0 -12
  66. package/src/cli/cmd/tui/context/exit.tsx +0 -23
  67. package/src/cli/cmd/tui/context/helper.tsx +0 -25
  68. package/src/cli/cmd/tui/context/keybind.tsx +0 -111
  69. package/src/cli/cmd/tui/context/kv.tsx +0 -49
  70. package/src/cli/cmd/tui/context/local.tsx +0 -339
  71. package/src/cli/cmd/tui/context/prompt.tsx +0 -18
  72. package/src/cli/cmd/tui/context/route.tsx +0 -45
  73. package/src/cli/cmd/tui/context/sdk.tsx +0 -75
  74. package/src/cli/cmd/tui/context/sync.tsx +0 -374
  75. package/src/cli/cmd/tui/context/theme/aura.json +0 -69
  76. package/src/cli/cmd/tui/context/theme/ayu.json +0 -80
  77. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +0 -233
  78. package/src/cli/cmd/tui/context/theme/catppuccin.json +0 -112
  79. package/src/cli/cmd/tui/context/theme/cobalt2.json +0 -228
  80. package/src/cli/cmd/tui/context/theme/dracula.json +0 -219
  81. package/src/cli/cmd/tui/context/theme/everforest.json +0 -241
  82. package/src/cli/cmd/tui/context/theme/flexoki.json +0 -237
  83. package/src/cli/cmd/tui/context/theme/github.json +0 -233
  84. package/src/cli/cmd/tui/context/theme/gruvbox.json +0 -95
  85. package/src/cli/cmd/tui/context/theme/kanagawa.json +0 -77
  86. package/src/cli/cmd/tui/context/theme/material.json +0 -235
  87. package/src/cli/cmd/tui/context/theme/matrix.json +0 -77
  88. package/src/cli/cmd/tui/context/theme/mercury.json +0 -252
  89. package/src/cli/cmd/tui/context/theme/monokai.json +0 -221
  90. package/src/cli/cmd/tui/context/theme/nightowl.json +0 -221
  91. package/src/cli/cmd/tui/context/theme/nord.json +0 -223
  92. package/src/cli/cmd/tui/context/theme/one-dark.json +0 -84
  93. package/src/cli/cmd/tui/context/theme/orng.json +0 -245
  94. package/src/cli/cmd/tui/context/theme/palenight.json +0 -222
  95. package/src/cli/cmd/tui/context/theme/rosepine.json +0 -234
  96. package/src/cli/cmd/tui/context/theme/solarized.json +0 -223
  97. package/src/cli/cmd/tui/context/theme/synthwave84.json +0 -226
  98. package/src/cli/cmd/tui/context/theme/tokyonight.json +0 -243
  99. package/src/cli/cmd/tui/context/theme/vercel.json +0 -245
  100. package/src/cli/cmd/tui/context/theme/vesper.json +0 -218
  101. package/src/cli/cmd/tui/context/theme/zenburn.json +0 -223
  102. package/src/cli/cmd/tui/context/theme.tsx +0 -1077
  103. package/src/cli/cmd/tui/event.ts +0 -39
  104. package/src/cli/cmd/tui/routes/home.tsx +0 -104
  105. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +0 -93
  106. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +0 -37
  107. package/src/cli/cmd/tui/routes/session/footer.tsx +0 -76
  108. package/src/cli/cmd/tui/routes/session/header.tsx +0 -183
  109. package/src/cli/cmd/tui/routes/session/index.tsx +0 -1703
  110. package/src/cli/cmd/tui/routes/session/sidebar.tsx +0 -586
  111. package/src/cli/cmd/tui/spawn.ts +0 -60
  112. package/src/cli/cmd/tui/thread.ts +0 -120
  113. package/src/cli/cmd/tui/ui/dialog-alert.tsx +0 -55
  114. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +0 -81
  115. package/src/cli/cmd/tui/ui/dialog-help.tsx +0 -36
  116. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +0 -75
  117. package/src/cli/cmd/tui/ui/dialog-select.tsx +0 -317
  118. package/src/cli/cmd/tui/ui/dialog.tsx +0 -170
  119. package/src/cli/cmd/tui/ui/spinner.ts +0 -368
  120. package/src/cli/cmd/tui/ui/toast.tsx +0 -100
  121. package/src/cli/cmd/tui/util/clipboard.ts +0 -127
  122. package/src/cli/cmd/tui/util/editor.ts +0 -32
  123. package/src/cli/cmd/tui/util/terminal.ts +0 -114
  124. package/src/cli/cmd/tui/worker.ts +0 -63
  125. package/src/cli/cmd/uninstall.ts +0 -344
  126. package/src/cli/cmd/upgrade.ts +0 -67
  127. package/src/cli/cmd/web.ts +0 -84
  128. package/src/cli/error.ts +0 -55
  129. package/src/cli/ui.ts +0 -84
  130. package/src/cli/upgrade.ts +0 -25
  131. package/src/command/index.ts +0 -79
  132. package/src/command/template/initialize.txt +0 -10
  133. package/src/command/template/review.txt +0 -73
  134. package/src/config/config.ts +0 -886
  135. package/src/config/markdown.ts +0 -41
  136. package/src/env/index.ts +0 -26
  137. package/src/file/fzf.ts +0 -124
  138. package/src/file/ignore.ts +0 -83
  139. package/src/file/index.ts +0 -326
  140. package/src/file/ripgrep.ts +0 -391
  141. package/src/file/time.ts +0 -38
  142. package/src/file/watcher.ts +0 -89
  143. package/src/flag/flag.ts +0 -28
  144. package/src/format/formatter.ts +0 -277
  145. package/src/format/index.ts +0 -137
  146. package/src/global/index.ts +0 -52
  147. package/src/id/id.ts +0 -73
  148. package/src/ide/index.ts +0 -75
  149. package/src/index.ts +0 -158
  150. package/src/installation/index.ts +0 -194
  151. package/src/lsp/client.ts +0 -215
  152. package/src/lsp/index.ts +0 -370
  153. package/src/lsp/language.ts +0 -111
  154. package/src/lsp/server.ts +0 -1327
  155. package/src/mcp/auth.ts +0 -82
  156. package/src/mcp/index.ts +0 -576
  157. package/src/mcp/oauth-callback.ts +0 -203
  158. package/src/mcp/oauth-provider.ts +0 -132
  159. package/src/notification/index.ts +0 -101
  160. package/src/patch/index.ts +0 -622
  161. package/src/permission/index.ts +0 -198
  162. package/src/plugin/index.ts +0 -95
  163. package/src/project/bootstrap.ts +0 -31
  164. package/src/project/instance.ts +0 -68
  165. package/src/project/project.ts +0 -133
  166. package/src/project/state.ts +0 -65
  167. package/src/project/vcs.ts +0 -77
  168. package/src/provider/auth.ts +0 -143
  169. package/src/provider/models-macro.ts +0 -11
  170. package/src/provider/models.ts +0 -93
  171. package/src/provider/provider.ts +0 -996
  172. package/src/provider/sdk/openai-compatible/src/README.md +0 -5
  173. package/src/provider/sdk/openai-compatible/src/index.ts +0 -2
  174. package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +0 -100
  175. package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +0 -303
  176. package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +0 -27
  177. package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +0 -18
  178. package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +0 -22
  179. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +0 -207
  180. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +0 -1713
  181. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +0 -177
  182. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +0 -1
  183. package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +0 -88
  184. package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +0 -128
  185. package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +0 -115
  186. package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +0 -65
  187. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +0 -104
  188. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +0 -103
  189. package/src/provider/transform.ts +0 -406
  190. package/src/pty/index.ts +0 -226
  191. package/src/ratelimit/index.ts +0 -185
  192. package/src/server/error.ts +0 -36
  193. package/src/server/project.ts +0 -50
  194. package/src/server/server.ts +0 -2463
  195. package/src/server/tui.ts +0 -71
  196. package/src/session/compaction.ts +0 -257
  197. package/src/session/index.ts +0 -470
  198. package/src/session/message-v2.ts +0 -641
  199. package/src/session/message.ts +0 -189
  200. package/src/session/processor.ts +0 -443
  201. package/src/session/prompt/anthropic-20250930.txt +0 -166
  202. package/src/session/prompt/anthropic.txt +0 -105
  203. package/src/session/prompt/anthropic_spoof.txt +0 -1
  204. package/src/session/prompt/beast.txt +0 -147
  205. package/src/session/prompt/build-switch.txt +0 -5
  206. package/src/session/prompt/codex.txt +0 -318
  207. package/src/session/prompt/compaction.txt +0 -12
  208. package/src/session/prompt/copilot-gpt-5.txt +0 -143
  209. package/src/session/prompt/gemini.txt +0 -155
  210. package/src/session/prompt/max-steps.txt +0 -16
  211. package/src/session/prompt/plan-reminder-anthropic.txt +0 -67
  212. package/src/session/prompt/plan.txt +0 -26
  213. package/src/session/prompt/polaris.txt +0 -107
  214. package/src/session/prompt/qwen.txt +0 -109
  215. package/src/session/prompt/summarize.txt +0 -4
  216. package/src/session/prompt/title.txt +0 -36
  217. package/src/session/prompt.ts +0 -1541
  218. package/src/session/retry.ts +0 -82
  219. package/src/session/revert.ts +0 -108
  220. package/src/session/status.ts +0 -75
  221. package/src/session/summary.ts +0 -203
  222. package/src/session/system.ts +0 -148
  223. package/src/session/todo.ts +0 -36
  224. package/src/share/share-next.ts +0 -195
  225. package/src/share/share.ts +0 -87
  226. package/src/snapshot/index.ts +0 -197
  227. package/src/storage/storage.ts +0 -226
  228. package/src/telemetry/index.ts +0 -232
  229. package/src/tool/bash.ts +0 -365
  230. package/src/tool/bash.txt +0 -128
  231. package/src/tool/batch.ts +0 -173
  232. package/src/tool/batch.txt +0 -28
  233. package/src/tool/codesearch.ts +0 -138
  234. package/src/tool/codesearch.txt +0 -12
  235. package/src/tool/edit.ts +0 -674
  236. package/src/tool/edit.txt +0 -10
  237. package/src/tool/glob.ts +0 -65
  238. package/src/tool/glob.txt +0 -6
  239. package/src/tool/grep.ts +0 -120
  240. package/src/tool/grep.txt +0 -8
  241. package/src/tool/invalid.ts +0 -17
  242. package/src/tool/ls.ts +0 -110
  243. package/src/tool/ls.txt +0 -1
  244. package/src/tool/lsp-diagnostics.ts +0 -26
  245. package/src/tool/lsp-diagnostics.txt +0 -1
  246. package/src/tool/lsp-hover.ts +0 -31
  247. package/src/tool/lsp-hover.txt +0 -1
  248. package/src/tool/multiedit.ts +0 -46
  249. package/src/tool/multiedit.txt +0 -41
  250. package/src/tool/patch.ts +0 -233
  251. package/src/tool/patch.txt +0 -1
  252. package/src/tool/read.ts +0 -217
  253. package/src/tool/read.txt +0 -12
  254. package/src/tool/registry.ts +0 -148
  255. package/src/tool/task.ts +0 -135
  256. package/src/tool/task.txt +0 -60
  257. package/src/tool/todo.ts +0 -39
  258. package/src/tool/todoread.txt +0 -14
  259. package/src/tool/todowrite.txt +0 -167
  260. package/src/tool/tool.ts +0 -66
  261. package/src/tool/webfetch.ts +0 -187
  262. package/src/tool/webfetch.txt +0 -14
  263. package/src/tool/websearch.ts +0 -150
  264. package/src/tool/websearch.txt +0 -11
  265. package/src/tool/write.ts +0 -99
  266. package/src/tool/write.txt +0 -8
  267. package/src/types/shims.d.ts +0 -3
  268. package/src/util/color.ts +0 -19
  269. package/src/util/context.ts +0 -25
  270. package/src/util/defer.ts +0 -12
  271. package/src/util/eventloop.ts +0 -20
  272. package/src/util/filesystem.ts +0 -69
  273. package/src/util/fn.ts +0 -11
  274. package/src/util/iife.ts +0 -3
  275. package/src/util/keybind.ts +0 -79
  276. package/src/util/lazy.ts +0 -11
  277. package/src/util/locale.ts +0 -81
  278. package/src/util/lock.ts +0 -98
  279. package/src/util/log.ts +0 -177
  280. package/src/util/queue.ts +0 -32
  281. package/src/util/rpc.ts +0 -42
  282. package/src/util/scrap.ts +0 -10
  283. package/src/util/signal.ts +0 -12
  284. package/src/util/timeout.ts +0 -14
  285. package/src/util/token.ts +0 -7
  286. package/src/util/wildcard.ts +0 -54
  287. package/sst-env.d.ts +0 -9
  288. package/test/bun.test.ts +0 -53
  289. package/test/config/agent-color.test.ts +0 -66
  290. package/test/config/config.test.ts +0 -503
  291. package/test/config/markdown.test.ts +0 -89
  292. package/test/file/ignore.test.ts +0 -10
  293. package/test/fixture/fixture.ts +0 -28
  294. package/test/fixture/lsp/fake-lsp-server.js +0 -77
  295. package/test/ide/ide.test.ts +0 -82
  296. package/test/keybind.test.ts +0 -317
  297. package/test/lsp/client.test.ts +0 -95
  298. package/test/patch/patch.test.ts +0 -348
  299. package/test/preload.ts +0 -38
  300. package/test/project/project.test.ts +0 -42
  301. package/test/provider/provider.test.ts +0 -1809
  302. package/test/provider/transform.test.ts +0 -305
  303. package/test/session/retry.test.ts +0 -61
  304. package/test/session/session.test.ts +0 -71
  305. package/test/snapshot/snapshot.test.ts +0 -939
  306. package/test/tool/__snapshots__/tool.test.ts.snap +0 -9
  307. package/test/tool/bash.test.ts +0 -55
  308. package/test/tool/patch.test.ts +0 -259
  309. package/test/util/iife.test.ts +0 -36
  310. package/test/util/lazy.test.ts +0 -50
  311. package/test/util/timeout.test.ts +0 -21
  312. package/test/util/wildcard.test.ts +0 -55
  313. package/tsconfig.json +0 -17
@@ -1,2463 +0,0 @@
1
- import { Log } from "../util/log"
2
- import { Bus } from "../bus"
3
- import { describeRoute, generateSpecs, validator, resolver, openAPIRouteHandler } from "hono-openapi"
4
- import { Hono } from "hono"
5
- import { cors } from "hono/cors"
6
- import { stream, streamSSE } from "hono/streaming"
7
- import { proxy } from "hono/proxy"
8
- import { Session } from "../session"
9
- import z from "zod"
10
- import { Provider } from "../provider/provider"
11
- import { mapValues, pipe } from "remeda"
12
- import { NamedError } from "@opencode-ai/util/error"
13
- import { ModelsDev } from "../provider/models"
14
- import { Ripgrep } from "../file/ripgrep"
15
- import { Config } from "../config/config"
16
- import { File } from "../file"
17
- import { LSP } from "../lsp"
18
- import { Format } from "../format"
19
- import { MessageV2 } from "../session/message-v2"
20
- import { TuiRoute } from "./tui"
21
- import { Permission } from "../permission"
22
- import { Instance } from "../project/instance"
23
- import { Vcs } from "../project/vcs"
24
- import { Agent } from "../agent/agent"
25
- import { Auth } from "../auth"
26
- import { Command } from "../command"
27
- import { ProviderAuth } from "../provider/auth"
28
- import { Global } from "../global"
29
- import { ProjectRoute } from "./project"
30
- import { ToolRegistry } from "../tool/registry"
31
- import { zodToJsonSchema } from "zod-to-json-schema"
32
- import { SessionPrompt } from "../session/prompt"
33
- import { SessionCompaction } from "../session/compaction"
34
- import { SessionRevert } from "../session/revert"
35
- import { lazy } from "../util/lazy"
36
- import { Todo } from "../session/todo"
37
- import { InstanceBootstrap } from "../project/bootstrap"
38
- import { MCP } from "../mcp"
39
- import { Storage } from "../storage/storage"
40
- import type { ContentfulStatusCode } from "hono/utils/http-status"
41
- import { TuiEvent } from "@/cli/cmd/tui/event"
42
- import { Snapshot } from "@/snapshot"
43
- import { SessionSummary } from "@/session/summary"
44
- import { GlobalBus } from "@/bus/global"
45
- import { SessionStatus } from "@/session/status"
46
- import { upgradeWebSocket, websocket } from "hono/bun"
47
- import { errors } from "./error"
48
- import { Pty } from "@/pty"
49
-
50
- // @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85
51
- globalThis.AI_SDK_LOG_WARNINGS = false
52
-
53
- export namespace Server {
54
- const log = Log.create({ service: "server" })
55
-
56
- export const Event = {
57
- Connected: Bus.event("server.connected", z.object({})),
58
- }
59
-
60
- const app = new Hono()
61
- export const App = lazy(() =>
62
- app
63
- .onError((err, c) => {
64
- log.error("failed", {
65
- error: err,
66
- })
67
- if (err instanceof NamedError) {
68
- let status: ContentfulStatusCode
69
- if (err instanceof Storage.NotFoundError) status = 404
70
- else if (err instanceof Provider.ModelNotFoundError) status = 400
71
- else status = 500
72
- return c.json(err.toObject(), { status })
73
- }
74
- const message = err instanceof Error && err.stack ? err.stack : err.toString()
75
- return c.json(new NamedError.Unknown({ message }).toObject(), {
76
- status: 500,
77
- })
78
- })
79
- .use(async (c, next) => {
80
- const skipLogging = c.req.path === "/log"
81
- if (!skipLogging) {
82
- log.info("request", {
83
- method: c.req.method,
84
- path: c.req.path,
85
- })
86
- }
87
- const timer = log.time("request", {
88
- method: c.req.method,
89
- path: c.req.path,
90
- })
91
- await next()
92
- if (!skipLogging) {
93
- timer.stop()
94
- }
95
- })
96
- .use(cors())
97
- .get(
98
- "/global/event",
99
- describeRoute({
100
- summary: "Get global events",
101
- description: "Subscribe to global events from the OpenCode system using server-sent events.",
102
- operationId: "global.event",
103
- responses: {
104
- 200: {
105
- description: "Event stream",
106
- content: {
107
- "text/event-stream": {
108
- schema: resolver(
109
- z
110
- .object({
111
- directory: z.string(),
112
- payload: Bus.payloads(),
113
- })
114
- .meta({
115
- ref: "GlobalEvent",
116
- }),
117
- ),
118
- },
119
- },
120
- },
121
- },
122
- }),
123
- async (c) => {
124
- log.info("global event connected")
125
- return streamSSE(c, async (stream) => {
126
- async function handler(event: any) {
127
- await stream.writeSSE({
128
- data: JSON.stringify(event),
129
- })
130
- }
131
- GlobalBus.on("event", handler)
132
- await new Promise<void>((resolve) => {
133
- stream.onAbort(() => {
134
- GlobalBus.off("event", handler)
135
- resolve()
136
- log.info("global event disconnected")
137
- })
138
- })
139
- })
140
- },
141
- )
142
- .use(async (c, next) => {
143
- const directory = c.req.query("directory") ?? c.req.header("x-opencode-directory") ?? process.cwd()
144
- return Instance.provide({
145
- directory,
146
- init: InstanceBootstrap,
147
- async fn() {
148
- return next()
149
- },
150
- })
151
- })
152
- .get(
153
- "/doc",
154
- openAPIRouteHandler(app, {
155
- documentation: {
156
- info: {
157
- title: "opencode",
158
- version: "0.0.3",
159
- description: "opencode api",
160
- },
161
- openapi: "3.1.1",
162
- },
163
- }),
164
- )
165
- .use(validator("query", z.object({ directory: z.string().optional() })))
166
-
167
- .route("/project", ProjectRoute)
168
-
169
- .get(
170
- "/pty",
171
- describeRoute({
172
- summary: "List PTY sessions",
173
- description: "Get a list of all active pseudo-terminal (PTY) sessions managed by OpenCode.",
174
- operationId: "pty.list",
175
- responses: {
176
- 200: {
177
- description: "List of sessions",
178
- content: {
179
- "application/json": {
180
- schema: resolver(Pty.Info.array()),
181
- },
182
- },
183
- },
184
- },
185
- }),
186
- async (c) => {
187
- return c.json(Pty.list())
188
- },
189
- )
190
- .post(
191
- "/pty",
192
- describeRoute({
193
- summary: "Create PTY session",
194
- description: "Create a new pseudo-terminal (PTY) session for running shell commands and processes.",
195
- operationId: "pty.create",
196
- responses: {
197
- 200: {
198
- description: "Created session",
199
- content: {
200
- "application/json": {
201
- schema: resolver(Pty.Info),
202
- },
203
- },
204
- },
205
- ...errors(400),
206
- },
207
- }),
208
- validator("json", Pty.CreateInput),
209
- async (c) => {
210
- const info = await Pty.create(c.req.valid("json"))
211
- return c.json(info)
212
- },
213
- )
214
- .get(
215
- "/pty/:ptyID",
216
- describeRoute({
217
- summary: "Get PTY session",
218
- description: "Retrieve detailed information about a specific pseudo-terminal (PTY) session.",
219
- operationId: "pty.get",
220
- responses: {
221
- 200: {
222
- description: "Session info",
223
- content: {
224
- "application/json": {
225
- schema: resolver(Pty.Info),
226
- },
227
- },
228
- },
229
- ...errors(404),
230
- },
231
- }),
232
- validator("param", z.object({ ptyID: z.string() })),
233
- async (c) => {
234
- const info = Pty.get(c.req.valid("param").ptyID)
235
- if (!info) {
236
- throw new Storage.NotFoundError({ message: "Session not found" })
237
- }
238
- return c.json(info)
239
- },
240
- )
241
- .put(
242
- "/pty/:ptyID",
243
- describeRoute({
244
- summary: "Update PTY session",
245
- description: "Update properties of an existing pseudo-terminal (PTY) session.",
246
- operationId: "pty.update",
247
- responses: {
248
- 200: {
249
- description: "Updated session",
250
- content: {
251
- "application/json": {
252
- schema: resolver(Pty.Info),
253
- },
254
- },
255
- },
256
- ...errors(400),
257
- },
258
- }),
259
- validator("param", z.object({ ptyID: z.string() })),
260
- validator("json", Pty.UpdateInput),
261
- async (c) => {
262
- const info = await Pty.update(c.req.valid("param").ptyID, c.req.valid("json"))
263
- return c.json(info)
264
- },
265
- )
266
- .delete(
267
- "/pty/:ptyID",
268
- describeRoute({
269
- summary: "Remove PTY session",
270
- description: "Remove and terminate a specific pseudo-terminal (PTY) session.",
271
- operationId: "pty.remove",
272
- responses: {
273
- 200: {
274
- description: "Session removed",
275
- content: {
276
- "application/json": {
277
- schema: resolver(z.boolean()),
278
- },
279
- },
280
- },
281
- ...errors(404),
282
- },
283
- }),
284
- validator("param", z.object({ ptyID: z.string() })),
285
- async (c) => {
286
- await Pty.remove(c.req.valid("param").ptyID)
287
- return c.json(true)
288
- },
289
- )
290
- .get(
291
- "/pty/:ptyID/connect",
292
- describeRoute({
293
- summary: "Connect to PTY session",
294
- description:
295
- "Establish a WebSocket connection to interact with a pseudo-terminal (PTY) session in real-time.",
296
- operationId: "pty.connect",
297
- responses: {
298
- 200: {
299
- description: "Connected session",
300
- content: {
301
- "application/json": {
302
- schema: resolver(z.boolean()),
303
- },
304
- },
305
- },
306
- ...errors(404),
307
- },
308
- }),
309
- validator("param", z.object({ ptyID: z.string() })),
310
- upgradeWebSocket((c) => {
311
- const id = c.req.param("ptyID")
312
- let handler: ReturnType<typeof Pty.connect>
313
- if (!Pty.get(id)) throw new Error("Session not found")
314
- return {
315
- onOpen(_event, ws) {
316
- handler = Pty.connect(id, ws)
317
- },
318
- onMessage(event) {
319
- handler?.onMessage(String(event.data))
320
- },
321
- onClose() {
322
- handler?.onClose()
323
- },
324
- }
325
- }),
326
- )
327
-
328
- .get(
329
- "/config",
330
- describeRoute({
331
- summary: "Get configuration",
332
- description: "Retrieve the current OpenCode configuration settings and preferences.",
333
- operationId: "config.get",
334
- responses: {
335
- 200: {
336
- description: "Get config info",
337
- content: {
338
- "application/json": {
339
- schema: resolver(Config.Info),
340
- },
341
- },
342
- },
343
- },
344
- }),
345
- async (c) => {
346
- return c.json(await Config.get())
347
- },
348
- )
349
-
350
- .patch(
351
- "/config",
352
- describeRoute({
353
- summary: "Update configuration",
354
- description: "Update OpenCode configuration settings and preferences.",
355
- operationId: "config.update",
356
- responses: {
357
- 200: {
358
- description: "Successfully updated config",
359
- content: {
360
- "application/json": {
361
- schema: resolver(Config.Info),
362
- },
363
- },
364
- },
365
- ...errors(400),
366
- },
367
- }),
368
- validator("json", Config.Info),
369
- async (c) => {
370
- const config = c.req.valid("json")
371
- await Config.update(config)
372
- return c.json(config)
373
- },
374
- )
375
- .get(
376
- "/experimental/tool/ids",
377
- describeRoute({
378
- summary: "List tool IDs",
379
- description:
380
- "Get a list of all available tool IDs, including both built-in tools and dynamically registered tools.",
381
- operationId: "tool.ids",
382
- responses: {
383
- 200: {
384
- description: "Tool IDs",
385
- content: {
386
- "application/json": {
387
- schema: resolver(z.array(z.string()).meta({ ref: "ToolIDs" })),
388
- },
389
- },
390
- },
391
- ...errors(400),
392
- },
393
- }),
394
- async (c) => {
395
- return c.json(await ToolRegistry.ids())
396
- },
397
- )
398
- .get(
399
- "/experimental/tool",
400
- describeRoute({
401
- summary: "List tools",
402
- description:
403
- "Get a list of available tools with their JSON schema parameters for a specific provider and model combination.",
404
- operationId: "tool.list",
405
- responses: {
406
- 200: {
407
- description: "Tools",
408
- content: {
409
- "application/json": {
410
- schema: resolver(
411
- z
412
- .array(
413
- z
414
- .object({
415
- id: z.string(),
416
- description: z.string(),
417
- parameters: z.any(),
418
- })
419
- .meta({ ref: "ToolListItem" }),
420
- )
421
- .meta({ ref: "ToolList" }),
422
- ),
423
- },
424
- },
425
- },
426
- ...errors(400),
427
- },
428
- }),
429
- validator(
430
- "query",
431
- z.object({
432
- provider: z.string(),
433
- model: z.string(),
434
- }),
435
- ),
436
- async (c) => {
437
- const { provider } = c.req.valid("query")
438
- const tools = await ToolRegistry.tools(provider)
439
- return c.json(
440
- tools.map((t) => ({
441
- id: t.id,
442
- description: t.description,
443
- // Handle both Zod schemas and plain JSON schemas
444
- parameters: (t.parameters as any)?._def ? zodToJsonSchema(t.parameters as any) : t.parameters,
445
- })),
446
- )
447
- },
448
- )
449
- .post(
450
- "/instance/dispose",
451
- describeRoute({
452
- summary: "Dispose instance",
453
- description: "Clean up and dispose the current OpenCode instance, releasing all resources.",
454
- operationId: "instance.dispose",
455
- responses: {
456
- 200: {
457
- description: "Instance disposed",
458
- content: {
459
- "application/json": {
460
- schema: resolver(z.boolean()),
461
- },
462
- },
463
- },
464
- },
465
- }),
466
- async (c) => {
467
- await Instance.dispose()
468
- return c.json(true)
469
- },
470
- )
471
- .get(
472
- "/path",
473
- describeRoute({
474
- summary: "Get paths",
475
- description: "Retrieve the current working directory and related path information for the OpenCode instance.",
476
- operationId: "path.get",
477
- responses: {
478
- 200: {
479
- description: "Path",
480
- content: {
481
- "application/json": {
482
- schema: resolver(
483
- z
484
- .object({
485
- state: z.string(),
486
- config: z.string(),
487
- worktree: z.string(),
488
- directory: z.string(),
489
- })
490
- .meta({
491
- ref: "Path",
492
- }),
493
- ),
494
- },
495
- },
496
- },
497
- },
498
- }),
499
- async (c) => {
500
- return c.json({
501
- state: Global.Path.state,
502
- config: Global.Path.config,
503
- worktree: Instance.worktree,
504
- directory: Instance.directory,
505
- })
506
- },
507
- )
508
- .get(
509
- "/vcs",
510
- describeRoute({
511
- summary: "Get VCS info",
512
- description: "Retrieve version control system (VCS) information for the current project, such as git branch.",
513
- operationId: "vcs.get",
514
- responses: {
515
- 200: {
516
- description: "VCS info",
517
- content: {
518
- "application/json": {
519
- schema: resolver(Vcs.Info),
520
- },
521
- },
522
- },
523
- },
524
- }),
525
- async (c) => {
526
- const branch = await Vcs.branch()
527
- return c.json({
528
- branch,
529
- })
530
- },
531
- )
532
- .get(
533
- "/session",
534
- describeRoute({
535
- summary: "List sessions",
536
- description: "Get a list of all OpenCode sessions, sorted by most recently updated.",
537
- operationId: "session.list",
538
- responses: {
539
- 200: {
540
- description: "List of sessions",
541
- content: {
542
- "application/json": {
543
- schema: resolver(Session.Info.array()),
544
- },
545
- },
546
- },
547
- },
548
- }),
549
- async (c) => {
550
- const sessions = await Array.fromAsync(Session.list())
551
- sessions.sort((a, b) => b.time.updated - a.time.updated)
552
- return c.json(sessions)
553
- },
554
- )
555
- .get(
556
- "/session/status",
557
- describeRoute({
558
- summary: "Get session status",
559
- description: "Retrieve the current status of all sessions, including active, idle, and completed states.",
560
- operationId: "session.status",
561
- responses: {
562
- 200: {
563
- description: "Get session status",
564
- content: {
565
- "application/json": {
566
- schema: resolver(z.record(z.string(), SessionStatus.Info)),
567
- },
568
- },
569
- },
570
- ...errors(400),
571
- },
572
- }),
573
- async (c) => {
574
- const result = SessionStatus.list()
575
- return c.json(result)
576
- },
577
- )
578
- .get(
579
- "/session/:sessionID",
580
- describeRoute({
581
- summary: "Get session",
582
- description: "Retrieve detailed information about a specific OpenCode session.",
583
- tags: ["Session"],
584
- operationId: "session.get",
585
- responses: {
586
- 200: {
587
- description: "Get session",
588
- content: {
589
- "application/json": {
590
- schema: resolver(Session.Info),
591
- },
592
- },
593
- },
594
- ...errors(400, 404),
595
- },
596
- }),
597
- validator(
598
- "param",
599
- z.object({
600
- sessionID: Session.get.schema,
601
- }),
602
- ),
603
- async (c) => {
604
- const sessionID = c.req.valid("param").sessionID
605
- log.info("SEARCH", { url: c.req.url })
606
- const session = await Session.get(sessionID)
607
- return c.json(session)
608
- },
609
- )
610
- .get(
611
- "/session/:sessionID/children",
612
- describeRoute({
613
- summary: "Get session children",
614
- tags: ["Session"],
615
- description: "Retrieve all child sessions that were forked from the specified parent session.",
616
- operationId: "session.children",
617
- responses: {
618
- 200: {
619
- description: "List of children",
620
- content: {
621
- "application/json": {
622
- schema: resolver(Session.Info.array()),
623
- },
624
- },
625
- },
626
- ...errors(400, 404),
627
- },
628
- }),
629
- validator(
630
- "param",
631
- z.object({
632
- sessionID: Session.children.schema,
633
- }),
634
- ),
635
- async (c) => {
636
- const sessionID = c.req.valid("param").sessionID
637
- const session = await Session.children(sessionID)
638
- return c.json(session)
639
- },
640
- )
641
- .get(
642
- "/session/:sessionID/todo",
643
- describeRoute({
644
- summary: "Get session todos",
645
- description: "Retrieve the todo list associated with a specific session, showing tasks and action items.",
646
- operationId: "session.todo",
647
- responses: {
648
- 200: {
649
- description: "Todo list",
650
- content: {
651
- "application/json": {
652
- schema: resolver(Todo.Info.array()),
653
- },
654
- },
655
- },
656
- ...errors(400, 404),
657
- },
658
- }),
659
- validator(
660
- "param",
661
- z.object({
662
- sessionID: z.string().meta({ description: "Session ID" }),
663
- }),
664
- ),
665
- async (c) => {
666
- const sessionID = c.req.valid("param").sessionID
667
- const todos = await Todo.get(sessionID)
668
- return c.json(todos)
669
- },
670
- )
671
- .post(
672
- "/session",
673
- describeRoute({
674
- summary: "Create session",
675
- description: "Create a new OpenCode session for interacting with AI assistants and managing conversations.",
676
- operationId: "session.create",
677
- responses: {
678
- ...errors(400),
679
- 200: {
680
- description: "Successfully created session",
681
- content: {
682
- "application/json": {
683
- schema: resolver(Session.Info),
684
- },
685
- },
686
- },
687
- },
688
- }),
689
- validator("json", Session.create.schema.optional()),
690
- async (c) => {
691
- const body = c.req.valid("json") ?? {}
692
- const session = await Session.create(body)
693
- return c.json(session)
694
- },
695
- )
696
- .delete(
697
- "/session/:sessionID",
698
- describeRoute({
699
- summary: "Delete session",
700
- description: "Delete a session and permanently remove all associated data, including messages and history.",
701
- operationId: "session.delete",
702
- responses: {
703
- 200: {
704
- description: "Successfully deleted session",
705
- content: {
706
- "application/json": {
707
- schema: resolver(z.boolean()),
708
- },
709
- },
710
- },
711
- ...errors(400, 404),
712
- },
713
- }),
714
- validator(
715
- "param",
716
- z.object({
717
- sessionID: Session.remove.schema,
718
- }),
719
- ),
720
- async (c) => {
721
- const sessionID = c.req.valid("param").sessionID
722
- await Session.remove(sessionID)
723
- await Bus.publish(TuiEvent.CommandExecute, {
724
- command: "session.list",
725
- })
726
- return c.json(true)
727
- },
728
- )
729
- .patch(
730
- "/session/:sessionID",
731
- describeRoute({
732
- summary: "Update session",
733
- description: "Update properties of an existing session, such as title or other metadata.",
734
- operationId: "session.update",
735
- responses: {
736
- 200: {
737
- description: "Successfully updated session",
738
- content: {
739
- "application/json": {
740
- schema: resolver(Session.Info),
741
- },
742
- },
743
- },
744
- ...errors(400, 404),
745
- },
746
- }),
747
- validator(
748
- "param",
749
- z.object({
750
- sessionID: z.string(),
751
- }),
752
- ),
753
- validator(
754
- "json",
755
- z.object({
756
- title: z.string().optional(),
757
- }),
758
- ),
759
- async (c) => {
760
- const sessionID = c.req.valid("param").sessionID
761
- const updates = c.req.valid("json")
762
-
763
- const updatedSession = await Session.update(sessionID, (session) => {
764
- if (updates.title !== undefined) {
765
- session.title = updates.title
766
- }
767
- })
768
-
769
- return c.json(updatedSession)
770
- },
771
- )
772
- .post(
773
- "/session/:sessionID/init",
774
- describeRoute({
775
- summary: "Initialize session",
776
- description:
777
- "Analyze the current application and create an AGENTS.md file with project-specific agent configurations.",
778
- operationId: "session.init",
779
- responses: {
780
- 200: {
781
- description: "200",
782
- content: {
783
- "application/json": {
784
- schema: resolver(z.boolean()),
785
- },
786
- },
787
- },
788
- ...errors(400, 404),
789
- },
790
- }),
791
- validator(
792
- "param",
793
- z.object({
794
- sessionID: z.string().meta({ description: "Session ID" }),
795
- }),
796
- ),
797
- validator("json", Session.initialize.schema.omit({ sessionID: true })),
798
- async (c) => {
799
- const sessionID = c.req.valid("param").sessionID
800
- const body = c.req.valid("json")
801
- await Session.initialize({ ...body, sessionID })
802
- return c.json(true)
803
- },
804
- )
805
- .post(
806
- "/session/:sessionID/fork",
807
- describeRoute({
808
- summary: "Fork session",
809
- description: "Create a new session by forking an existing session at a specific message point.",
810
- operationId: "session.fork",
811
- responses: {
812
- 200: {
813
- description: "200",
814
- content: {
815
- "application/json": {
816
- schema: resolver(Session.Info),
817
- },
818
- },
819
- },
820
- },
821
- }),
822
- validator(
823
- "param",
824
- z.object({
825
- sessionID: Session.fork.schema.shape.sessionID,
826
- }),
827
- ),
828
- validator("json", Session.fork.schema.omit({ sessionID: true })),
829
- async (c) => {
830
- const sessionID = c.req.valid("param").sessionID
831
- const body = c.req.valid("json")
832
- const result = await Session.fork({ ...body, sessionID })
833
- return c.json(result)
834
- },
835
- )
836
- .post(
837
- "/session/:sessionID/abort",
838
- describeRoute({
839
- summary: "Abort session",
840
- description: "Abort an active session and stop any ongoing AI processing or command execution.",
841
- operationId: "session.abort",
842
- responses: {
843
- 200: {
844
- description: "Aborted session",
845
- content: {
846
- "application/json": {
847
- schema: resolver(z.boolean()),
848
- },
849
- },
850
- },
851
- ...errors(400, 404),
852
- },
853
- }),
854
- validator(
855
- "param",
856
- z.object({
857
- sessionID: z.string(),
858
- }),
859
- ),
860
- async (c) => {
861
- SessionPrompt.cancel(c.req.valid("param").sessionID)
862
- return c.json(true)
863
- },
864
- )
865
- .post(
866
- "/session/:sessionID/share",
867
- describeRoute({
868
- summary: "Share session",
869
- description: "Create a shareable link for a session, allowing others to view the conversation.",
870
- operationId: "session.share",
871
- responses: {
872
- 200: {
873
- description: "Successfully shared session",
874
- content: {
875
- "application/json": {
876
- schema: resolver(Session.Info),
877
- },
878
- },
879
- },
880
- ...errors(400, 404),
881
- },
882
- }),
883
- validator(
884
- "param",
885
- z.object({
886
- sessionID: z.string(),
887
- }),
888
- ),
889
- async (c) => {
890
- const sessionID = c.req.valid("param").sessionID
891
- await Session.share(sessionID)
892
- const session = await Session.get(sessionID)
893
- return c.json(session)
894
- },
895
- )
896
- .get(
897
- "/session/:sessionID/diff",
898
- describeRoute({
899
- summary: "Get message diff",
900
- description: "Get the file changes (diff) that resulted from a specific user message in the session.",
901
- operationId: "session.diff",
902
- responses: {
903
- 200: {
904
- description: "Successfully retrieved diff",
905
- content: {
906
- "application/json": {
907
- schema: resolver(Snapshot.FileDiff.array()),
908
- },
909
- },
910
- },
911
- },
912
- }),
913
- validator(
914
- "param",
915
- z.object({
916
- sessionID: SessionSummary.diff.schema.shape.sessionID,
917
- }),
918
- ),
919
- validator(
920
- "query",
921
- z.object({
922
- messageID: SessionSummary.diff.schema.shape.messageID,
923
- }),
924
- ),
925
- async (c) => {
926
- const query = c.req.valid("query")
927
- const params = c.req.valid("param")
928
- const result = await SessionSummary.diff({
929
- sessionID: params.sessionID,
930
- messageID: query.messageID,
931
- })
932
- return c.json(result)
933
- },
934
- )
935
- .delete(
936
- "/session/:sessionID/share",
937
- describeRoute({
938
- summary: "Unshare session",
939
- description: "Remove the shareable link for a session, making it private again.",
940
- operationId: "session.unshare",
941
- responses: {
942
- 200: {
943
- description: "Successfully unshared session",
944
- content: {
945
- "application/json": {
946
- schema: resolver(Session.Info),
947
- },
948
- },
949
- },
950
- ...errors(400, 404),
951
- },
952
- }),
953
- validator(
954
- "param",
955
- z.object({
956
- sessionID: Session.unshare.schema,
957
- }),
958
- ),
959
- async (c) => {
960
- const sessionID = c.req.valid("param").sessionID
961
- await Session.unshare(sessionID)
962
- const session = await Session.get(sessionID)
963
- return c.json(session)
964
- },
965
- )
966
- .post(
967
- "/session/:sessionID/summarize",
968
- describeRoute({
969
- summary: "Summarize session",
970
- description: "Generate a concise summary of the session using AI compaction to preserve key information.",
971
- operationId: "session.summarize",
972
- responses: {
973
- 200: {
974
- description: "Summarized session",
975
- content: {
976
- "application/json": {
977
- schema: resolver(z.boolean()),
978
- },
979
- },
980
- },
981
- ...errors(400, 404),
982
- },
983
- }),
984
- validator(
985
- "param",
986
- z.object({
987
- sessionID: z.string().meta({ description: "Session ID" }),
988
- }),
989
- ),
990
- validator(
991
- "json",
992
- z.object({
993
- providerID: z.string(),
994
- modelID: z.string(),
995
- }),
996
- ),
997
- async (c) => {
998
- const sessionID = c.req.valid("param").sessionID
999
- const body = c.req.valid("json")
1000
- const msgs = await Session.messages({ sessionID })
1001
- let currentAgent = "build"
1002
- for (let i = msgs.length - 1; i >= 0; i--) {
1003
- const info = msgs[i].info
1004
- if (info.role === "user") {
1005
- currentAgent = info.agent || "build"
1006
- break
1007
- }
1008
- }
1009
- await SessionCompaction.create({
1010
- sessionID,
1011
- agent: currentAgent,
1012
- model: {
1013
- providerID: body.providerID,
1014
- modelID: body.modelID,
1015
- },
1016
- auto: false,
1017
- })
1018
- await SessionPrompt.loop(sessionID)
1019
- return c.json(true)
1020
- },
1021
- )
1022
- .get(
1023
- "/session/:sessionID/message",
1024
- describeRoute({
1025
- summary: "Get session messages",
1026
- description: "Retrieve all messages in a session, including user prompts and AI responses.",
1027
- operationId: "session.messages",
1028
- responses: {
1029
- 200: {
1030
- description: "List of messages",
1031
- content: {
1032
- "application/json": {
1033
- schema: resolver(MessageV2.WithParts.array()),
1034
- },
1035
- },
1036
- },
1037
- ...errors(400, 404),
1038
- },
1039
- }),
1040
- validator(
1041
- "param",
1042
- z.object({
1043
- sessionID: z.string().meta({ description: "Session ID" }),
1044
- }),
1045
- ),
1046
- validator(
1047
- "query",
1048
- z.object({
1049
- limit: z.coerce.number().optional(),
1050
- }),
1051
- ),
1052
- async (c) => {
1053
- const query = c.req.valid("query")
1054
- const messages = await Session.messages({
1055
- sessionID: c.req.valid("param").sessionID,
1056
- limit: query.limit,
1057
- })
1058
- return c.json(messages)
1059
- },
1060
- )
1061
- .get(
1062
- "/session/:sessionID/diff",
1063
- describeRoute({
1064
- summary: "Get session diff",
1065
- description: "Get all file changes (diffs) made during this session.",
1066
- operationId: "session.diff",
1067
- responses: {
1068
- 200: {
1069
- description: "List of diffs",
1070
- content: {
1071
- "application/json": {
1072
- schema: resolver(Snapshot.FileDiff.array()),
1073
- },
1074
- },
1075
- },
1076
- ...errors(400, 404),
1077
- },
1078
- }),
1079
- validator(
1080
- "param",
1081
- z.object({
1082
- sessionID: z.string().meta({ description: "Session ID" }),
1083
- }),
1084
- ),
1085
- async (c) => {
1086
- const diff = await Session.diff(c.req.valid("param").sessionID)
1087
- return c.json(diff)
1088
- },
1089
- )
1090
- .get(
1091
- "/session/:sessionID/message/:messageID",
1092
- describeRoute({
1093
- summary: "Get message",
1094
- description: "Retrieve a specific message from a session by its message ID.",
1095
- operationId: "session.message",
1096
- responses: {
1097
- 200: {
1098
- description: "Message",
1099
- content: {
1100
- "application/json": {
1101
- schema: resolver(
1102
- z.object({
1103
- info: MessageV2.Info,
1104
- parts: MessageV2.Part.array(),
1105
- }),
1106
- ),
1107
- },
1108
- },
1109
- },
1110
- ...errors(400, 404),
1111
- },
1112
- }),
1113
- validator(
1114
- "param",
1115
- z.object({
1116
- sessionID: z.string().meta({ description: "Session ID" }),
1117
- messageID: z.string().meta({ description: "Message ID" }),
1118
- }),
1119
- ),
1120
- async (c) => {
1121
- const params = c.req.valid("param")
1122
- const message = await MessageV2.get({
1123
- sessionID: params.sessionID,
1124
- messageID: params.messageID,
1125
- })
1126
- return c.json(message)
1127
- },
1128
- )
1129
- .post(
1130
- "/session/:sessionID/message",
1131
- describeRoute({
1132
- summary: "Send message",
1133
- description: "Create and send a new message to a session, streaming the AI response.",
1134
- operationId: "session.prompt",
1135
- responses: {
1136
- 200: {
1137
- description: "Created message",
1138
- content: {
1139
- "application/json": {
1140
- schema: resolver(
1141
- z.object({
1142
- info: MessageV2.Assistant,
1143
- parts: MessageV2.Part.array(),
1144
- }),
1145
- ),
1146
- },
1147
- },
1148
- },
1149
- ...errors(400, 404),
1150
- },
1151
- }),
1152
- validator(
1153
- "param",
1154
- z.object({
1155
- sessionID: z.string().meta({ description: "Session ID" }),
1156
- }),
1157
- ),
1158
- validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })),
1159
- async (c) => {
1160
- c.status(200)
1161
- c.header("Content-Type", "application/json")
1162
- return stream(c, async (stream) => {
1163
- const sessionID = c.req.valid("param").sessionID
1164
- const body = c.req.valid("json")
1165
- const msg = await SessionPrompt.prompt({ ...body, sessionID })
1166
- stream.write(JSON.stringify(msg))
1167
- })
1168
- },
1169
- )
1170
- .post(
1171
- "/session/:sessionID/prompt_async",
1172
- describeRoute({
1173
- summary: "Send async message",
1174
- description:
1175
- "Create and send a new message to a session asynchronously, starting the session if needed and returning immediately.",
1176
- operationId: "session.prompt_async",
1177
- responses: {
1178
- 204: {
1179
- description: "Prompt accepted",
1180
- },
1181
- ...errors(400, 404),
1182
- },
1183
- }),
1184
- validator(
1185
- "param",
1186
- z.object({
1187
- sessionID: z.string().meta({ description: "Session ID" }),
1188
- }),
1189
- ),
1190
- validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })),
1191
- async (c) => {
1192
- c.status(204)
1193
- c.header("Content-Type", "application/json")
1194
- return stream(c, async () => {
1195
- const sessionID = c.req.valid("param").sessionID
1196
- const body = c.req.valid("json")
1197
- SessionPrompt.prompt({ ...body, sessionID })
1198
- })
1199
- },
1200
- )
1201
- .post(
1202
- "/session/:sessionID/command",
1203
- describeRoute({
1204
- summary: "Send command",
1205
- description: "Send a new command to a session for execution by the AI assistant.",
1206
- operationId: "session.command",
1207
- responses: {
1208
- 200: {
1209
- description: "Created message",
1210
- content: {
1211
- "application/json": {
1212
- schema: resolver(
1213
- z.object({
1214
- info: MessageV2.Assistant,
1215
- parts: MessageV2.Part.array(),
1216
- }),
1217
- ),
1218
- },
1219
- },
1220
- },
1221
- ...errors(400, 404),
1222
- },
1223
- }),
1224
- validator(
1225
- "param",
1226
- z.object({
1227
- sessionID: z.string().meta({ description: "Session ID" }),
1228
- }),
1229
- ),
1230
- validator("json", SessionPrompt.CommandInput.omit({ sessionID: true })),
1231
- async (c) => {
1232
- const sessionID = c.req.valid("param").sessionID
1233
- const body = c.req.valid("json")
1234
- const msg = await SessionPrompt.command({ ...body, sessionID })
1235
- return c.json(msg)
1236
- },
1237
- )
1238
- .post(
1239
- "/session/:sessionID/shell",
1240
- describeRoute({
1241
- summary: "Run shell command",
1242
- description: "Execute a shell command within the session context and return the AI's response.",
1243
- operationId: "session.shell",
1244
- responses: {
1245
- 200: {
1246
- description: "Created message",
1247
- content: {
1248
- "application/json": {
1249
- schema: resolver(MessageV2.Assistant),
1250
- },
1251
- },
1252
- },
1253
- ...errors(400, 404),
1254
- },
1255
- }),
1256
- validator(
1257
- "param",
1258
- z.object({
1259
- sessionID: z.string().meta({ description: "Session ID" }),
1260
- }),
1261
- ),
1262
- validator("json", SessionPrompt.ShellInput.omit({ sessionID: true })),
1263
- async (c) => {
1264
- const sessionID = c.req.valid("param").sessionID
1265
- const body = c.req.valid("json")
1266
- const msg = await SessionPrompt.shell({ ...body, sessionID })
1267
- return c.json(msg)
1268
- },
1269
- )
1270
- .post(
1271
- "/session/:sessionID/revert",
1272
- describeRoute({
1273
- summary: "Revert message",
1274
- description: "Revert a specific message in a session, undoing its effects and restoring the previous state.",
1275
- operationId: "session.revert",
1276
- responses: {
1277
- 200: {
1278
- description: "Updated session",
1279
- content: {
1280
- "application/json": {
1281
- schema: resolver(Session.Info),
1282
- },
1283
- },
1284
- },
1285
- ...errors(400, 404),
1286
- },
1287
- }),
1288
- validator(
1289
- "param",
1290
- z.object({
1291
- sessionID: z.string(),
1292
- }),
1293
- ),
1294
- validator("json", SessionRevert.RevertInput.omit({ sessionID: true })),
1295
- async (c) => {
1296
- const sessionID = c.req.valid("param").sessionID
1297
- log.info("revert", c.req.valid("json"))
1298
- const session = await SessionRevert.revert({
1299
- sessionID,
1300
- ...c.req.valid("json"),
1301
- })
1302
- return c.json(session)
1303
- },
1304
- )
1305
- .post(
1306
- "/session/:sessionID/unrevert",
1307
- describeRoute({
1308
- summary: "Restore reverted messages",
1309
- description: "Restore all previously reverted messages in a session.",
1310
- operationId: "session.unrevert",
1311
- responses: {
1312
- 200: {
1313
- description: "Updated session",
1314
- content: {
1315
- "application/json": {
1316
- schema: resolver(Session.Info),
1317
- },
1318
- },
1319
- },
1320
- ...errors(400, 404),
1321
- },
1322
- }),
1323
- validator(
1324
- "param",
1325
- z.object({
1326
- sessionID: z.string(),
1327
- }),
1328
- ),
1329
- async (c) => {
1330
- const sessionID = c.req.valid("param").sessionID
1331
- const session = await SessionRevert.unrevert({ sessionID })
1332
- return c.json(session)
1333
- },
1334
- )
1335
- .post(
1336
- "/session/:sessionID/permissions/:permissionID",
1337
- describeRoute({
1338
- summary: "Respond to permission",
1339
- description: "Approve or deny a permission request from the AI assistant.",
1340
- operationId: "permission.respond",
1341
- responses: {
1342
- 200: {
1343
- description: "Permission processed successfully",
1344
- content: {
1345
- "application/json": {
1346
- schema: resolver(z.boolean()),
1347
- },
1348
- },
1349
- },
1350
- ...errors(400, 404),
1351
- },
1352
- }),
1353
- validator(
1354
- "param",
1355
- z.object({
1356
- sessionID: z.string(),
1357
- permissionID: z.string(),
1358
- }),
1359
- ),
1360
- validator("json", z.object({ response: Permission.Response })),
1361
- async (c) => {
1362
- const params = c.req.valid("param")
1363
- const sessionID = params.sessionID
1364
- const permissionID = params.permissionID
1365
- Permission.respond({
1366
- sessionID,
1367
- permissionID,
1368
- response: c.req.valid("json").response,
1369
- })
1370
- return c.json(true)
1371
- },
1372
- )
1373
- .get(
1374
- "/command",
1375
- describeRoute({
1376
- summary: "List commands",
1377
- description: "Get a list of all available commands in the OpenCode system.",
1378
- operationId: "command.list",
1379
- responses: {
1380
- 200: {
1381
- description: "List of commands",
1382
- content: {
1383
- "application/json": {
1384
- schema: resolver(Command.Info.array()),
1385
- },
1386
- },
1387
- },
1388
- },
1389
- }),
1390
- async (c) => {
1391
- const commands = await Command.list()
1392
- return c.json(commands)
1393
- },
1394
- )
1395
- .get(
1396
- "/config/providers",
1397
- describeRoute({
1398
- summary: "List config providers",
1399
- description: "Get a list of all configured AI providers and their default models.",
1400
- operationId: "config.providers",
1401
- responses: {
1402
- 200: {
1403
- description: "List of providers",
1404
- content: {
1405
- "application/json": {
1406
- schema: resolver(
1407
- z.object({
1408
- providers: Provider.Info.array(),
1409
- default: z.record(z.string(), z.string()),
1410
- }),
1411
- ),
1412
- },
1413
- },
1414
- },
1415
- },
1416
- }),
1417
- async (c) => {
1418
- using _ = log.time("providers")
1419
- const providers = await Provider.list().then((x) => mapValues(x, (item) => item))
1420
- return c.json({
1421
- providers: Object.values(providers),
1422
- default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
1423
- })
1424
- },
1425
- )
1426
- .get(
1427
- "/provider",
1428
- describeRoute({
1429
- summary: "List providers",
1430
- description: "Get a list of all available AI providers, including both available and connected ones.",
1431
- operationId: "provider.list",
1432
- responses: {
1433
- 200: {
1434
- description: "List of providers",
1435
- content: {
1436
- "application/json": {
1437
- schema: resolver(
1438
- z.object({
1439
- all: ModelsDev.Provider.array(),
1440
- default: z.record(z.string(), z.string()),
1441
- connected: z.array(z.string()),
1442
- }),
1443
- ),
1444
- },
1445
- },
1446
- },
1447
- },
1448
- }),
1449
- async (c) => {
1450
- const config = await Config.get()
1451
- const disabled = new Set(config.disabled_providers ?? [])
1452
- const enabled = config.enabled_providers ? new Set(config.enabled_providers) : undefined
1453
-
1454
- const allProviders = await ModelsDev.get()
1455
- const filteredProviders: Record<string, (typeof allProviders)[string]> = {}
1456
- for (const [key, value] of Object.entries(allProviders)) {
1457
- if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) {
1458
- filteredProviders[key] = value
1459
- }
1460
- }
1461
-
1462
- const providers = mapValues(filteredProviders, (x) => Provider.fromModelsDevProvider(x))
1463
- const connected = await Provider.list().then((x) => Object.keys(x))
1464
- return c.json({
1465
- all: Object.values(providers),
1466
- default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
1467
- connected,
1468
- })
1469
- },
1470
- )
1471
- .get(
1472
- "/provider/auth",
1473
- describeRoute({
1474
- summary: "Get provider auth methods",
1475
- description: "Retrieve available authentication methods for all AI providers.",
1476
- operationId: "provider.auth",
1477
- responses: {
1478
- 200: {
1479
- description: "Provider auth methods",
1480
- content: {
1481
- "application/json": {
1482
- schema: resolver(z.record(z.string(), z.array(ProviderAuth.Method))),
1483
- },
1484
- },
1485
- },
1486
- },
1487
- }),
1488
- async (c) => {
1489
- return c.json(await ProviderAuth.methods())
1490
- },
1491
- )
1492
- .post(
1493
- "/provider/:providerID/oauth/authorize",
1494
- describeRoute({
1495
- summary: "OAuth authorize",
1496
- description: "Initiate OAuth authorization for a specific AI provider to get an authorization URL.",
1497
- operationId: "provider.oauth.authorize",
1498
- responses: {
1499
- 200: {
1500
- description: "Authorization URL and method",
1501
- content: {
1502
- "application/json": {
1503
- schema: resolver(ProviderAuth.Authorization.optional()),
1504
- },
1505
- },
1506
- },
1507
- ...errors(400),
1508
- },
1509
- }),
1510
- validator(
1511
- "param",
1512
- z.object({
1513
- providerID: z.string().meta({ description: "Provider ID" }),
1514
- }),
1515
- ),
1516
- validator(
1517
- "json",
1518
- z.object({
1519
- method: z.number().meta({ description: "Auth method index" }),
1520
- }),
1521
- ),
1522
- async (c) => {
1523
- const providerID = c.req.valid("param").providerID
1524
- const { method } = c.req.valid("json")
1525
- const result = await ProviderAuth.authorize({
1526
- providerID,
1527
- method,
1528
- })
1529
- return c.json(result)
1530
- },
1531
- )
1532
- .post(
1533
- "/provider/:providerID/oauth/callback",
1534
- describeRoute({
1535
- summary: "OAuth callback",
1536
- description: "Handle the OAuth callback from a provider after user authorization.",
1537
- operationId: "provider.oauth.callback",
1538
- responses: {
1539
- 200: {
1540
- description: "OAuth callback processed successfully",
1541
- content: {
1542
- "application/json": {
1543
- schema: resolver(z.boolean()),
1544
- },
1545
- },
1546
- },
1547
- ...errors(400),
1548
- },
1549
- }),
1550
- validator(
1551
- "param",
1552
- z.object({
1553
- providerID: z.string().meta({ description: "Provider ID" }),
1554
- }),
1555
- ),
1556
- validator(
1557
- "json",
1558
- z.object({
1559
- method: z.number().meta({ description: "Auth method index" }),
1560
- code: z.string().optional().meta({ description: "OAuth authorization code" }),
1561
- }),
1562
- ),
1563
- async (c) => {
1564
- const providerID = c.req.valid("param").providerID
1565
- const { method, code } = c.req.valid("json")
1566
- await ProviderAuth.callback({
1567
- providerID,
1568
- method,
1569
- code,
1570
- })
1571
- return c.json(true)
1572
- },
1573
- )
1574
- .get(
1575
- "/find",
1576
- describeRoute({
1577
- summary: "Find text",
1578
- description: "Search for text patterns across files in the project using ripgrep.",
1579
- operationId: "find.text",
1580
- responses: {
1581
- 200: {
1582
- description: "Matches",
1583
- content: {
1584
- "application/json": {
1585
- schema: resolver(Ripgrep.Match.shape.data.array()),
1586
- },
1587
- },
1588
- },
1589
- },
1590
- }),
1591
- validator(
1592
- "query",
1593
- z.object({
1594
- pattern: z.string(),
1595
- }),
1596
- ),
1597
- async (c) => {
1598
- const pattern = c.req.valid("query").pattern
1599
- const result = await Ripgrep.search({
1600
- cwd: Instance.directory,
1601
- pattern,
1602
- limit: 10,
1603
- })
1604
- return c.json(result)
1605
- },
1606
- )
1607
- .get(
1608
- "/find/file",
1609
- describeRoute({
1610
- summary: "Find files",
1611
- description: "Search for files by name or pattern in the project directory.",
1612
- operationId: "find.files",
1613
- responses: {
1614
- 200: {
1615
- description: "File paths",
1616
- content: {
1617
- "application/json": {
1618
- schema: resolver(z.string().array()),
1619
- },
1620
- },
1621
- },
1622
- },
1623
- }),
1624
- validator(
1625
- "query",
1626
- z.object({
1627
- query: z.string(),
1628
- dirs: z.enum(["true", "false"]).optional(),
1629
- }),
1630
- ),
1631
- async (c) => {
1632
- const query = c.req.valid("query").query
1633
- const dirs = c.req.valid("query").dirs
1634
- const results = await File.search({
1635
- query,
1636
- limit: 10,
1637
- dirs: dirs !== "false",
1638
- })
1639
- return c.json(results)
1640
- },
1641
- )
1642
- .get(
1643
- "/find/symbol",
1644
- describeRoute({
1645
- summary: "Find symbols",
1646
- description: "Search for workspace symbols like functions, classes, and variables using LSP.",
1647
- operationId: "find.symbols",
1648
- responses: {
1649
- 200: {
1650
- description: "Symbols",
1651
- content: {
1652
- "application/json": {
1653
- schema: resolver(LSP.Symbol.array()),
1654
- },
1655
- },
1656
- },
1657
- },
1658
- }),
1659
- validator(
1660
- "query",
1661
- z.object({
1662
- query: z.string(),
1663
- }),
1664
- ),
1665
- async (c) => {
1666
- /*
1667
- const query = c.req.valid("query").query
1668
- const result = await LSP.workspaceSymbol(query)
1669
- return c.json(result)
1670
- */
1671
- return c.json([])
1672
- },
1673
- )
1674
- .get(
1675
- "/file",
1676
- describeRoute({
1677
- summary: "List files",
1678
- description: "List files and directories in a specified path.",
1679
- operationId: "file.list",
1680
- responses: {
1681
- 200: {
1682
- description: "Files and directories",
1683
- content: {
1684
- "application/json": {
1685
- schema: resolver(File.Node.array()),
1686
- },
1687
- },
1688
- },
1689
- },
1690
- }),
1691
- validator(
1692
- "query",
1693
- z.object({
1694
- path: z.string(),
1695
- }),
1696
- ),
1697
- async (c) => {
1698
- const path = c.req.valid("query").path
1699
- const content = await File.list(path)
1700
- return c.json(content)
1701
- },
1702
- )
1703
- .get(
1704
- "/file/content",
1705
- describeRoute({
1706
- summary: "Read file",
1707
- description: "Read the content of a specified file.",
1708
- operationId: "file.read",
1709
- responses: {
1710
- 200: {
1711
- description: "File content",
1712
- content: {
1713
- "application/json": {
1714
- schema: resolver(File.Content),
1715
- },
1716
- },
1717
- },
1718
- },
1719
- }),
1720
- validator(
1721
- "query",
1722
- z.object({
1723
- path: z.string(),
1724
- }),
1725
- ),
1726
- async (c) => {
1727
- const path = c.req.valid("query").path
1728
- const content = await File.read(path)
1729
- return c.json(content)
1730
- },
1731
- )
1732
- .get(
1733
- "/file/status",
1734
- describeRoute({
1735
- summary: "Get file status",
1736
- description: "Get the git status of all files in the project.",
1737
- operationId: "file.status",
1738
- responses: {
1739
- 200: {
1740
- description: "File status",
1741
- content: {
1742
- "application/json": {
1743
- schema: resolver(File.Info.array()),
1744
- },
1745
- },
1746
- },
1747
- },
1748
- }),
1749
- async (c) => {
1750
- const content = await File.status()
1751
- return c.json(content)
1752
- },
1753
- )
1754
- .post(
1755
- "/log",
1756
- describeRoute({
1757
- summary: "Write log",
1758
- description: "Write a log entry to the server logs with specified level and metadata.",
1759
- operationId: "app.log",
1760
- responses: {
1761
- 200: {
1762
- description: "Log entry written successfully",
1763
- content: {
1764
- "application/json": {
1765
- schema: resolver(z.boolean()),
1766
- },
1767
- },
1768
- },
1769
- ...errors(400),
1770
- },
1771
- }),
1772
- validator(
1773
- "json",
1774
- z.object({
1775
- service: z.string().meta({ description: "Service name for the log entry" }),
1776
- level: z.enum(["debug", "info", "error", "warn"]).meta({ description: "Log level" }),
1777
- message: z.string().meta({ description: "Log message" }),
1778
- extra: z
1779
- .record(z.string(), z.any())
1780
- .optional()
1781
- .meta({ description: "Additional metadata for the log entry" }),
1782
- }),
1783
- ),
1784
- async (c) => {
1785
- const { service, level, message, extra } = c.req.valid("json")
1786
- const logger = Log.create({ service })
1787
-
1788
- switch (level) {
1789
- case "debug":
1790
- logger.debug(message, extra)
1791
- break
1792
- case "info":
1793
- logger.info(message, extra)
1794
- break
1795
- case "error":
1796
- logger.error(message, extra)
1797
- break
1798
- case "warn":
1799
- logger.warn(message, extra)
1800
- break
1801
- }
1802
-
1803
- return c.json(true)
1804
- },
1805
- )
1806
- .get(
1807
- "/agent",
1808
- describeRoute({
1809
- summary: "List agents",
1810
- description: "Get a list of all available AI agents in the OpenCode system.",
1811
- operationId: "app.agents",
1812
- responses: {
1813
- 200: {
1814
- description: "List of agents",
1815
- content: {
1816
- "application/json": {
1817
- schema: resolver(Agent.Info.array()),
1818
- },
1819
- },
1820
- },
1821
- },
1822
- }),
1823
- async (c) => {
1824
- const modes = await Agent.list()
1825
- return c.json(modes)
1826
- },
1827
- )
1828
- .get(
1829
- "/mcp",
1830
- describeRoute({
1831
- summary: "Get MCP status",
1832
- description: "Get the status of all Model Context Protocol (MCP) servers.",
1833
- operationId: "mcp.status",
1834
- responses: {
1835
- 200: {
1836
- description: "MCP server status",
1837
- content: {
1838
- "application/json": {
1839
- schema: resolver(z.record(z.string(), MCP.Status)),
1840
- },
1841
- },
1842
- },
1843
- },
1844
- }),
1845
- async (c) => {
1846
- return c.json(await MCP.status())
1847
- },
1848
- )
1849
- .post(
1850
- "/mcp",
1851
- describeRoute({
1852
- summary: "Add MCP server",
1853
- description: "Dynamically add a new Model Context Protocol (MCP) server to the system.",
1854
- operationId: "mcp.add",
1855
- responses: {
1856
- 200: {
1857
- description: "MCP server added successfully",
1858
- content: {
1859
- "application/json": {
1860
- schema: resolver(z.record(z.string(), MCP.Status)),
1861
- },
1862
- },
1863
- },
1864
- ...errors(400),
1865
- },
1866
- }),
1867
- validator(
1868
- "json",
1869
- z.object({
1870
- name: z.string(),
1871
- config: Config.Mcp,
1872
- }),
1873
- ),
1874
- async (c) => {
1875
- const { name, config } = c.req.valid("json")
1876
- const result = await MCP.add(name, config)
1877
- return c.json(result.status)
1878
- },
1879
- )
1880
- .post(
1881
- "/mcp/:name/auth",
1882
- describeRoute({
1883
- summary: "Start MCP OAuth",
1884
- description: "Start OAuth authentication flow for a Model Context Protocol (MCP) server.",
1885
- operationId: "mcp.auth.start",
1886
- responses: {
1887
- 200: {
1888
- description: "OAuth flow started",
1889
- content: {
1890
- "application/json": {
1891
- schema: resolver(
1892
- z.object({
1893
- authorizationUrl: z.string().describe("URL to open in browser for authorization"),
1894
- }),
1895
- ),
1896
- },
1897
- },
1898
- },
1899
- ...errors(400, 404),
1900
- },
1901
- }),
1902
- async (c) => {
1903
- const name = c.req.param("name")
1904
- const supportsOAuth = await MCP.supportsOAuth(name)
1905
- if (!supportsOAuth) {
1906
- return c.json({ error: `MCP server ${name} does not support OAuth` }, 400)
1907
- }
1908
- const result = await MCP.startAuth(name)
1909
- return c.json(result)
1910
- },
1911
- )
1912
- .post(
1913
- "/mcp/:name/auth/callback",
1914
- describeRoute({
1915
- summary: "Complete MCP OAuth",
1916
- description:
1917
- "Complete OAuth authentication for a Model Context Protocol (MCP) server using the authorization code.",
1918
- operationId: "mcp.auth.callback",
1919
- responses: {
1920
- 200: {
1921
- description: "OAuth authentication completed",
1922
- content: {
1923
- "application/json": {
1924
- schema: resolver(MCP.Status),
1925
- },
1926
- },
1927
- },
1928
- ...errors(400, 404),
1929
- },
1930
- }),
1931
- validator(
1932
- "json",
1933
- z.object({
1934
- code: z.string().describe("Authorization code from OAuth callback"),
1935
- }),
1936
- ),
1937
- async (c) => {
1938
- const name = c.req.param("name")
1939
- const { code } = c.req.valid("json")
1940
- const status = await MCP.finishAuth(name, code)
1941
- return c.json(status)
1942
- },
1943
- )
1944
- .post(
1945
- "/mcp/:name/auth/authenticate",
1946
- describeRoute({
1947
- summary: "Authenticate MCP OAuth",
1948
- description: "Start OAuth flow and wait for callback (opens browser)",
1949
- operationId: "mcp.auth.authenticate",
1950
- responses: {
1951
- 200: {
1952
- description: "OAuth authentication completed",
1953
- content: {
1954
- "application/json": {
1955
- schema: resolver(MCP.Status),
1956
- },
1957
- },
1958
- },
1959
- ...errors(400, 404),
1960
- },
1961
- }),
1962
- async (c) => {
1963
- const name = c.req.param("name")
1964
- const supportsOAuth = await MCP.supportsOAuth(name)
1965
- if (!supportsOAuth) {
1966
- return c.json({ error: `MCP server ${name} does not support OAuth` }, 400)
1967
- }
1968
- const status = await MCP.authenticate(name)
1969
- return c.json(status)
1970
- },
1971
- )
1972
- .delete(
1973
- "/mcp/:name/auth",
1974
- describeRoute({
1975
- summary: "Remove MCP OAuth",
1976
- description: "Remove OAuth credentials for an MCP server",
1977
- operationId: "mcp.auth.remove",
1978
- responses: {
1979
- 200: {
1980
- description: "OAuth credentials removed",
1981
- content: {
1982
- "application/json": {
1983
- schema: resolver(z.object({ success: z.literal(true) })),
1984
- },
1985
- },
1986
- },
1987
- ...errors(404),
1988
- },
1989
- }),
1990
- async (c) => {
1991
- const name = c.req.param("name")
1992
- await MCP.removeAuth(name)
1993
- return c.json({ success: true as const })
1994
- },
1995
- )
1996
- .post(
1997
- "/mcp/:name/connect",
1998
- describeRoute({
1999
- description: "Connect an MCP server",
2000
- operationId: "mcp.connect",
2001
- responses: {
2002
- 200: {
2003
- description: "MCP server connected successfully",
2004
- content: {
2005
- "application/json": {
2006
- schema: resolver(z.boolean()),
2007
- },
2008
- },
2009
- },
2010
- },
2011
- }),
2012
- validator("param", z.object({ name: z.string() })),
2013
- async (c) => {
2014
- const { name } = c.req.valid("param")
2015
- await MCP.connect(name)
2016
- return c.json(true)
2017
- },
2018
- )
2019
- .post(
2020
- "/mcp/:name/disconnect",
2021
- describeRoute({
2022
- description: "Disconnect an MCP server",
2023
- operationId: "mcp.disconnect",
2024
- responses: {
2025
- 200: {
2026
- description: "MCP server disconnected successfully",
2027
- content: {
2028
- "application/json": {
2029
- schema: resolver(z.boolean()),
2030
- },
2031
- },
2032
- },
2033
- },
2034
- }),
2035
- validator("param", z.object({ name: z.string() })),
2036
- async (c) => {
2037
- const { name } = c.req.valid("param")
2038
- await MCP.disconnect(name)
2039
- return c.json(true)
2040
- },
2041
- )
2042
- .get(
2043
- "/lsp",
2044
- describeRoute({
2045
- summary: "Get LSP status",
2046
- description: "Get LSP server status",
2047
- operationId: "lsp.status",
2048
- responses: {
2049
- 200: {
2050
- description: "LSP server status",
2051
- content: {
2052
- "application/json": {
2053
- schema: resolver(LSP.Status.array()),
2054
- },
2055
- },
2056
- },
2057
- },
2058
- }),
2059
- async (c) => {
2060
- return c.json(await LSP.status())
2061
- },
2062
- )
2063
- .get(
2064
- "/formatter",
2065
- describeRoute({
2066
- summary: "Get formatter status",
2067
- description: "Get formatter status",
2068
- operationId: "formatter.status",
2069
- responses: {
2070
- 200: {
2071
- description: "Formatter status",
2072
- content: {
2073
- "application/json": {
2074
- schema: resolver(Format.Status.array()),
2075
- },
2076
- },
2077
- },
2078
- },
2079
- }),
2080
- async (c) => {
2081
- return c.json(await Format.status())
2082
- },
2083
- )
2084
- .post(
2085
- "/tui/append-prompt",
2086
- describeRoute({
2087
- summary: "Append TUI prompt",
2088
- description: "Append prompt to the TUI",
2089
- operationId: "tui.appendPrompt",
2090
- responses: {
2091
- 200: {
2092
- description: "Prompt processed successfully",
2093
- content: {
2094
- "application/json": {
2095
- schema: resolver(z.boolean()),
2096
- },
2097
- },
2098
- },
2099
- ...errors(400),
2100
- },
2101
- }),
2102
- validator("json", TuiEvent.PromptAppend.properties),
2103
- async (c) => {
2104
- await Bus.publish(TuiEvent.PromptAppend, c.req.valid("json"))
2105
- return c.json(true)
2106
- },
2107
- )
2108
- .post(
2109
- "/tui/open-help",
2110
- describeRoute({
2111
- summary: "Open help dialog",
2112
- description: "Open the help dialog in the TUI to display user assistance information.",
2113
- operationId: "tui.openHelp",
2114
- responses: {
2115
- 200: {
2116
- description: "Help dialog opened successfully",
2117
- content: {
2118
- "application/json": {
2119
- schema: resolver(z.boolean()),
2120
- },
2121
- },
2122
- },
2123
- },
2124
- }),
2125
- async (c) => {
2126
- // TODO: open dialog
2127
- return c.json(true)
2128
- },
2129
- )
2130
- .post(
2131
- "/tui/open-sessions",
2132
- describeRoute({
2133
- summary: "Open sessions dialog",
2134
- description: "Open the session dialog",
2135
- operationId: "tui.openSessions",
2136
- responses: {
2137
- 200: {
2138
- description: "Session dialog opened successfully",
2139
- content: {
2140
- "application/json": {
2141
- schema: resolver(z.boolean()),
2142
- },
2143
- },
2144
- },
2145
- },
2146
- }),
2147
- async (c) => {
2148
- await Bus.publish(TuiEvent.CommandExecute, {
2149
- command: "session.list",
2150
- })
2151
- return c.json(true)
2152
- },
2153
- )
2154
- .post(
2155
- "/tui/open-themes",
2156
- describeRoute({
2157
- summary: "Open themes dialog",
2158
- description: "Open the theme dialog",
2159
- operationId: "tui.openThemes",
2160
- responses: {
2161
- 200: {
2162
- description: "Theme dialog opened successfully",
2163
- content: {
2164
- "application/json": {
2165
- schema: resolver(z.boolean()),
2166
- },
2167
- },
2168
- },
2169
- },
2170
- }),
2171
- async (c) => {
2172
- await Bus.publish(TuiEvent.CommandExecute, {
2173
- command: "session.list",
2174
- })
2175
- return c.json(true)
2176
- },
2177
- )
2178
- .post(
2179
- "/tui/open-models",
2180
- describeRoute({
2181
- summary: "Open models dialog",
2182
- description: "Open the model dialog",
2183
- operationId: "tui.openModels",
2184
- responses: {
2185
- 200: {
2186
- description: "Model dialog opened successfully",
2187
- content: {
2188
- "application/json": {
2189
- schema: resolver(z.boolean()),
2190
- },
2191
- },
2192
- },
2193
- },
2194
- }),
2195
- async (c) => {
2196
- await Bus.publish(TuiEvent.CommandExecute, {
2197
- command: "model.list",
2198
- })
2199
- return c.json(true)
2200
- },
2201
- )
2202
- .post(
2203
- "/tui/submit-prompt",
2204
- describeRoute({
2205
- summary: "Submit TUI prompt",
2206
- description: "Submit the prompt",
2207
- operationId: "tui.submitPrompt",
2208
- responses: {
2209
- 200: {
2210
- description: "Prompt submitted successfully",
2211
- content: {
2212
- "application/json": {
2213
- schema: resolver(z.boolean()),
2214
- },
2215
- },
2216
- },
2217
- },
2218
- }),
2219
- async (c) => {
2220
- await Bus.publish(TuiEvent.CommandExecute, {
2221
- command: "prompt.submit",
2222
- })
2223
- return c.json(true)
2224
- },
2225
- )
2226
- .post(
2227
- "/tui/clear-prompt",
2228
- describeRoute({
2229
- summary: "Clear TUI prompt",
2230
- description: "Clear the prompt",
2231
- operationId: "tui.clearPrompt",
2232
- responses: {
2233
- 200: {
2234
- description: "Prompt cleared successfully",
2235
- content: {
2236
- "application/json": {
2237
- schema: resolver(z.boolean()),
2238
- },
2239
- },
2240
- },
2241
- },
2242
- }),
2243
- async (c) => {
2244
- await Bus.publish(TuiEvent.CommandExecute, {
2245
- command: "prompt.clear",
2246
- })
2247
- return c.json(true)
2248
- },
2249
- )
2250
- .post(
2251
- "/tui/execute-command",
2252
- describeRoute({
2253
- summary: "Execute TUI command",
2254
- description: "Execute a TUI command (e.g. agent_cycle)",
2255
- operationId: "tui.executeCommand",
2256
- responses: {
2257
- 200: {
2258
- description: "Command executed successfully",
2259
- content: {
2260
- "application/json": {
2261
- schema: resolver(z.boolean()),
2262
- },
2263
- },
2264
- },
2265
- ...errors(400),
2266
- },
2267
- }),
2268
- validator("json", z.object({ command: z.string() })),
2269
- async (c) => {
2270
- const command = c.req.valid("json").command
2271
- await Bus.publish(TuiEvent.CommandExecute, {
2272
- // @ts-expect-error
2273
- command: {
2274
- session_new: "session.new",
2275
- session_share: "session.share",
2276
- session_interrupt: "session.interrupt",
2277
- session_compact: "session.compact",
2278
- messages_page_up: "session.page.up",
2279
- messages_page_down: "session.page.down",
2280
- messages_half_page_up: "session.half.page.up",
2281
- messages_half_page_down: "session.half.page.down",
2282
- messages_first: "session.first",
2283
- messages_last: "session.last",
2284
- agent_cycle: "agent.cycle",
2285
- }[command],
2286
- })
2287
- return c.json(true)
2288
- },
2289
- )
2290
- .post(
2291
- "/tui/show-toast",
2292
- describeRoute({
2293
- summary: "Show TUI toast",
2294
- description: "Show a toast notification in the TUI",
2295
- operationId: "tui.showToast",
2296
- responses: {
2297
- 200: {
2298
- description: "Toast notification shown successfully",
2299
- content: {
2300
- "application/json": {
2301
- schema: resolver(z.boolean()),
2302
- },
2303
- },
2304
- },
2305
- },
2306
- }),
2307
- validator("json", TuiEvent.ToastShow.properties),
2308
- async (c) => {
2309
- await Bus.publish(TuiEvent.ToastShow, c.req.valid("json"))
2310
- return c.json(true)
2311
- },
2312
- )
2313
- .post(
2314
- "/tui/publish",
2315
- describeRoute({
2316
- summary: "Publish TUI event",
2317
- description: "Publish a TUI event",
2318
- operationId: "tui.publish",
2319
- responses: {
2320
- 200: {
2321
- description: "Event published successfully",
2322
- content: {
2323
- "application/json": {
2324
- schema: resolver(z.boolean()),
2325
- },
2326
- },
2327
- },
2328
- ...errors(400),
2329
- },
2330
- }),
2331
- validator(
2332
- "json",
2333
- z.union(
2334
- Object.values(TuiEvent).map((def) => {
2335
- return z
2336
- .object({
2337
- type: z.literal(def.type),
2338
- properties: def.properties,
2339
- })
2340
- .meta({
2341
- ref: "Event" + "." + def.type,
2342
- })
2343
- }),
2344
- ),
2345
- ),
2346
- async (c) => {
2347
- const evt = c.req.valid("json")
2348
- await Bus.publish(Object.values(TuiEvent).find((def) => def.type === evt.type)!, evt.properties)
2349
- return c.json(true)
2350
- },
2351
- )
2352
- .route("/tui/control", TuiRoute)
2353
- .put(
2354
- "/auth/:providerID",
2355
- describeRoute({
2356
- summary: "Set auth credentials",
2357
- description: "Set authentication credentials",
2358
- operationId: "auth.set",
2359
- responses: {
2360
- 200: {
2361
- description: "Successfully set authentication credentials",
2362
- content: {
2363
- "application/json": {
2364
- schema: resolver(z.boolean()),
2365
- },
2366
- },
2367
- },
2368
- ...errors(400),
2369
- },
2370
- }),
2371
- validator(
2372
- "param",
2373
- z.object({
2374
- providerID: z.string(),
2375
- }),
2376
- ),
2377
- validator("json", Auth.Info),
2378
- async (c) => {
2379
- const providerID = c.req.valid("param").providerID
2380
- const info = c.req.valid("json")
2381
- await Auth.set(providerID, info)
2382
- return c.json(true)
2383
- },
2384
- )
2385
- .get(
2386
- "/event",
2387
- describeRoute({
2388
- summary: "Subscribe to events",
2389
- description: "Get events",
2390
- operationId: "event.subscribe",
2391
- responses: {
2392
- 200: {
2393
- description: "Event stream",
2394
- content: {
2395
- "text/event-stream": {
2396
- schema: resolver(Bus.payloads()),
2397
- },
2398
- },
2399
- },
2400
- },
2401
- }),
2402
- async (c) => {
2403
- log.info("event connected")
2404
- return streamSSE(c, async (stream) => {
2405
- stream.writeSSE({
2406
- data: JSON.stringify({
2407
- type: "server.connected",
2408
- properties: {},
2409
- }),
2410
- })
2411
- const unsub = Bus.subscribeAll(async (event) => {
2412
- await stream.writeSSE({
2413
- data: JSON.stringify(event),
2414
- })
2415
- if (event.type === Bus.InstanceDisposed.type) {
2416
- stream.close()
2417
- }
2418
- })
2419
- await new Promise<void>((resolve) => {
2420
- stream.onAbort(() => {
2421
- unsub()
2422
- resolve()
2423
- log.info("event disconnected")
2424
- })
2425
- })
2426
- })
2427
- },
2428
- )
2429
- .all("/*", async (c) => {
2430
- return proxy(`https://desktop.opencode.ai${c.req.path}`, {
2431
- ...c.req,
2432
- headers: {
2433
- host: "desktop.opencode.ai",
2434
- },
2435
- })
2436
- }),
2437
- )
2438
-
2439
- export async function openapi() {
2440
- const result = await generateSpecs(App(), {
2441
- documentation: {
2442
- info: {
2443
- title: "opencode",
2444
- version: "1.0.0",
2445
- description: "opencode api",
2446
- },
2447
- openapi: "3.1.1",
2448
- },
2449
- })
2450
- return result
2451
- }
2452
-
2453
- export function listen(opts: { port: number; hostname: string }) {
2454
- const server = Bun.serve({
2455
- port: opts.port,
2456
- hostname: opts.hostname,
2457
- idleTimeout: 0,
2458
- fetch: App().fetch,
2459
- websocket: websocket,
2460
- })
2461
- return server
2462
- }
2463
- }