soraacode 0.1.0

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 (350) hide show
  1. package/AGENTS.md +131 -0
  2. package/Dockerfile +18 -0
  3. package/README.md +15 -0
  4. package/bin/opencode +199 -0
  5. package/bin/soraacode +199 -0
  6. package/bunfig.toml +7 -0
  7. package/git +0 -0
  8. package/migration/20260511173437_session-metadata/migration.sql +1 -0
  9. package/migration/20260511173437_session-metadata/snapshot.json +1500 -0
  10. package/package.json +107 -0
  11. package/parsers-config.ts +1 -0
  12. package/script/bench-search.ts +94 -0
  13. package/script/bench-test-suite.ts +52 -0
  14. package/script/build-headless.ts +51 -0
  15. package/script/build.ts +245 -0
  16. package/script/generate.ts +14 -0
  17. package/script/httpapi-exercise.ts +1 -0
  18. package/script/postinstall.mjs +189 -0
  19. package/script/profile-test-files.ts +42 -0
  20. package/script/publish.ts +213 -0
  21. package/script/run-workspace-server +106 -0
  22. package/script/schema.ts +77 -0
  23. package/script/time.ts +6 -0
  24. package/script/trace-imports.ts +153 -0
  25. package/specs/effect/error-boundaries-plan.md +235 -0
  26. package/specs/effect/errors.md +207 -0
  27. package/specs/effect/facades.md +218 -0
  28. package/specs/effect/guide.md +247 -0
  29. package/specs/effect/instance-context.md +13 -0
  30. package/specs/effect/loose-ends.md +30 -0
  31. package/specs/effect/migration.md +62 -0
  32. package/specs/effect/routes.md +61 -0
  33. package/specs/effect/schema.md +88 -0
  34. package/specs/effect/server-package.md +58 -0
  35. package/specs/effect/todo.md +241 -0
  36. package/specs/effect/tools.md +88 -0
  37. package/specs/openapi-translation-cleanup.md +204 -0
  38. package/specs/tui-plugins.md +544 -0
  39. package/specs/v2/api.ts +67 -0
  40. package/specs/v2/message-shape.md +136 -0
  41. package/specs/v2/notifications.md +13 -0
  42. package/specs/v2/tui-command-shim.md +67 -0
  43. package/src/account/account.ts +481 -0
  44. package/src/account/repo.ts +171 -0
  45. package/src/account/schema.ts +99 -0
  46. package/src/account/url.ts +8 -0
  47. package/src/acp/agent.ts +95 -0
  48. package/src/acp/config-option.ts +206 -0
  49. package/src/acp/content.ts +269 -0
  50. package/src/acp/directory.ts +212 -0
  51. package/src/acp/error.ts +97 -0
  52. package/src/acp/event.ts +421 -0
  53. package/src/acp/permission.ts +254 -0
  54. package/src/acp/profile.ts +42 -0
  55. package/src/acp/service.ts +1226 -0
  56. package/src/acp/session.ts +232 -0
  57. package/src/acp/tool.ts +364 -0
  58. package/src/acp/usage.ts +243 -0
  59. package/src/agent/agent.ts +450 -0
  60. package/src/agent/generate.txt +75 -0
  61. package/src/agent/prompt/compaction.txt +5 -0
  62. package/src/agent/prompt/explore.txt +18 -0
  63. package/src/agent/prompt/summary.txt +11 -0
  64. package/src/agent/prompt/title.txt +44 -0
  65. package/src/agent/subagent-permissions.ts +27 -0
  66. package/src/audio.d.ts +14 -0
  67. package/src/auth/index.ts +97 -0
  68. package/src/background/job.ts +37 -0
  69. package/src/bus/global.ts +22 -0
  70. package/src/cli/bootstrap.ts +11 -0
  71. package/src/cli/cmd/cmd.ts +7 -0
  72. package/src/cli/cmd/serve.ts +24 -0
  73. package/src/cli/effect/prompt.ts +37 -0
  74. package/src/cli/effect-cmd.ts +96 -0
  75. package/src/cli/error.ts +130 -0
  76. package/src/cli/heap.ts +45 -0
  77. package/src/cli/logo.ts +2 -0
  78. package/src/cli/network.ts +80 -0
  79. package/src/cli/ui.ts +132 -0
  80. package/src/command/index.ts +177 -0
  81. package/src/command/template/initialize.txt +66 -0
  82. package/src/command/template/review.txt +101 -0
  83. package/src/config/agent.ts +59 -0
  84. package/src/config/command.ts +39 -0
  85. package/src/config/config.ts +707 -0
  86. package/src/config/entry-name.ts +19 -0
  87. package/src/config/managed.ts +69 -0
  88. package/src/config/markdown.ts +36 -0
  89. package/src/config/parse.ts +61 -0
  90. package/src/config/paths.ts +45 -0
  91. package/src/config/plugin.ts +79 -0
  92. package/src/config/v2-compat.ts +449 -0
  93. package/src/config/variable.ts +91 -0
  94. package/src/control-plane/adapters/index.ts +41 -0
  95. package/src/control-plane/adapters/worktree.ts +96 -0
  96. package/src/control-plane/dev/README.md +19 -0
  97. package/src/control-plane/dev/debug-workspace-plugin.ts +73 -0
  98. package/src/control-plane/types.ts +59 -0
  99. package/src/control-plane/util.ts +39 -0
  100. package/src/control-plane/workspace-adapter-runtime.ts +51 -0
  101. package/src/control-plane/workspace-context.ts +26 -0
  102. package/src/control-plane/workspace.ts +966 -0
  103. package/src/effect/app-node-builder-v1.ts +12 -0
  104. package/src/effect/app-runtime.ts +135 -0
  105. package/src/effect/bootstrap-runtime.ts +19 -0
  106. package/src/effect/bridge.ts +84 -0
  107. package/src/effect/config-service.ts +67 -0
  108. package/src/effect/instance-ref.ts +11 -0
  109. package/src/effect/instance-registry.ts +12 -0
  110. package/src/effect/instance-state.ts +69 -0
  111. package/src/effect/promise.ts +17 -0
  112. package/src/effect/run-service.ts +47 -0
  113. package/src/effect/runner.ts +217 -0
  114. package/src/effect/runtime-flags.ts +78 -0
  115. package/src/env/index.ts +41 -0
  116. package/src/event-manifest.ts +3 -0
  117. package/src/event-v2-bridge.ts +71 -0
  118. package/src/format/formatter.ts +404 -0
  119. package/src/format/index.ts +203 -0
  120. package/src/git/index.ts +348 -0
  121. package/src/id/id.ts +80 -0
  122. package/src/ide/index.ts +54 -0
  123. package/src/image/image.ts +172 -0
  124. package/src/index-headless.ts +89 -0
  125. package/src/index.ts +93 -0
  126. package/src/installation/index.ts +336 -0
  127. package/src/lsp/client.ts +650 -0
  128. package/src/lsp/diagnostic.ts +29 -0
  129. package/src/lsp/language.ts +121 -0
  130. package/src/lsp/launch.ts +21 -0
  131. package/src/lsp/lsp.ts +507 -0
  132. package/src/lsp/server.ts +1983 -0
  133. package/src/markdown.d.ts +4 -0
  134. package/src/mcp/auth.ts +163 -0
  135. package/src/mcp/browser.ts +37 -0
  136. package/src/mcp/catalog.ts +170 -0
  137. package/src/mcp/index.ts +1004 -0
  138. package/src/mcp/oauth-callback.ts +194 -0
  139. package/src/mcp/oauth-provider.ts +259 -0
  140. package/src/node.ts +4 -0
  141. package/src/patch/index.ts +686 -0
  142. package/src/permission/arity.ts +163 -0
  143. package/src/permission/evaluate.ts +1 -0
  144. package/src/permission/index.ts +223 -0
  145. package/src/plugin/github-copilot/copilot.ts +415 -0
  146. package/src/plugin/github-copilot/models.ts +261 -0
  147. package/src/plugin/index.ts +298 -0
  148. package/src/plugin/install.ts +439 -0
  149. package/src/plugin/loader.ts +237 -0
  150. package/src/plugin/meta.ts +188 -0
  151. package/src/plugin/openai/README.md +31 -0
  152. package/src/plugin/openai/codex.ts +575 -0
  153. package/src/plugin/openai/ws-pool.ts +271 -0
  154. package/src/plugin/openai/ws.ts +383 -0
  155. package/src/plugin/pty-environment.ts +24 -0
  156. package/src/plugin/shared.ts +323 -0
  157. package/src/project/bootstrap-service.ts +9 -0
  158. package/src/project/bootstrap.ts +58 -0
  159. package/src/project/instance-context.ts +24 -0
  160. package/src/project/instance-runtime.ts +16 -0
  161. package/src/project/instance-store.ts +213 -0
  162. package/src/project/project.ts +483 -0
  163. package/src/project/vcs.ts +423 -0
  164. package/src/provider/auth.ts +229 -0
  165. package/src/provider/error.ts +195 -0
  166. package/src/provider/model-status.ts +8 -0
  167. package/src/provider/provider.ts +1955 -0
  168. package/src/provider/transform.ts +1923 -0
  169. package/src/question/index.ts +161 -0
  170. package/src/question/schema.ts +4 -0
  171. package/src/server/auth.ts +48 -0
  172. package/src/server/event.ts +10 -0
  173. package/src/server/global-lifecycle.ts +28 -0
  174. package/src/server/mdns.ts +47 -0
  175. package/src/server/proxy-util.ts +48 -0
  176. package/src/server/routes/instance/httpapi/AGENTS.md +39 -0
  177. package/src/server/routes/instance/httpapi/api.ts +97 -0
  178. package/src/server/routes/instance/httpapi/errors.ts +193 -0
  179. package/src/server/routes/instance/httpapi/groups/config.ts +65 -0
  180. package/src/server/routes/instance/httpapi/groups/control-plane.ts +35 -0
  181. package/src/server/routes/instance/httpapi/groups/control.ts +76 -0
  182. package/src/server/routes/instance/httpapi/groups/event.ts +29 -0
  183. package/src/server/routes/instance/httpapi/groups/experimental.ts +275 -0
  184. package/src/server/routes/instance/httpapi/groups/file.ts +185 -0
  185. package/src/server/routes/instance/httpapi/groups/global.ts +139 -0
  186. package/src/server/routes/instance/httpapi/groups/instance.ts +206 -0
  187. package/src/server/routes/instance/httpapi/groups/mcp.ts +156 -0
  188. package/src/server/routes/instance/httpapi/groups/metadata.ts +18 -0
  189. package/src/server/routes/instance/httpapi/groups/permission.ts +61 -0
  190. package/src/server/routes/instance/httpapi/groups/project-copy.ts +32 -0
  191. package/src/server/routes/instance/httpapi/groups/project.ts +93 -0
  192. package/src/server/routes/instance/httpapi/groups/provider.ts +101 -0
  193. package/src/server/routes/instance/httpapi/groups/pty.ts +172 -0
  194. package/src/server/routes/instance/httpapi/groups/query.ts +12 -0
  195. package/src/server/routes/instance/httpapi/groups/question.ts +74 -0
  196. package/src/server/routes/instance/httpapi/groups/session.ts +462 -0
  197. package/src/server/routes/instance/httpapi/groups/sync.ts +113 -0
  198. package/src/server/routes/instance/httpapi/groups/tui.ts +208 -0
  199. package/src/server/routes/instance/httpapi/groups/workspace.ts +141 -0
  200. package/src/server/routes/instance/httpapi/handlers/config.ts +34 -0
  201. package/src/server/routes/instance/httpapi/handlers/control-plane.ts +37 -0
  202. package/src/server/routes/instance/httpapi/handlers/control.ts +43 -0
  203. package/src/server/routes/instance/httpapi/handlers/event.ts +99 -0
  204. package/src/server/routes/instance/httpapi/handlers/experimental.ts +193 -0
  205. package/src/server/routes/instance/httpapi/handlers/file.ts +139 -0
  206. package/src/server/routes/instance/httpapi/handlers/global.ts +126 -0
  207. package/src/server/routes/instance/httpapi/handlers/instance.ts +110 -0
  208. package/src/server/routes/instance/httpapi/handlers/mcp.ts +111 -0
  209. package/src/server/routes/instance/httpapi/handlers/permission.ts +41 -0
  210. package/src/server/routes/instance/httpapi/handlers/project-copy.ts +83 -0
  211. package/src/server/routes/instance/httpapi/handlers/project.ts +63 -0
  212. package/src/server/routes/instance/httpapi/handlers/provider.ts +116 -0
  213. package/src/server/routes/instance/httpapi/handlers/pty.ts +273 -0
  214. package/src/server/routes/instance/httpapi/handlers/question.ts +54 -0
  215. package/src/server/routes/instance/httpapi/handlers/session-errors.ts +21 -0
  216. package/src/server/routes/instance/httpapi/handlers/session.ts +442 -0
  217. package/src/server/routes/instance/httpapi/handlers/sync.ts +89 -0
  218. package/src/server/routes/instance/httpapi/handlers/tui.ts +131 -0
  219. package/src/server/routes/instance/httpapi/handlers/workspace.ts +102 -0
  220. package/src/server/routes/instance/httpapi/lifecycle.ts +54 -0
  221. package/src/server/routes/instance/httpapi/middleware/authorization.ts +150 -0
  222. package/src/server/routes/instance/httpapi/middleware/compression.ts +64 -0
  223. package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +29 -0
  224. package/src/server/routes/instance/httpapi/middleware/error.ts +44 -0
  225. package/src/server/routes/instance/httpapi/middleware/fence.ts +25 -0
  226. package/src/server/routes/instance/httpapi/middleware/instance-context.ts +43 -0
  227. package/src/server/routes/instance/httpapi/middleware/proxy.ts +131 -0
  228. package/src/server/routes/instance/httpapi/middleware/schema-error.ts +41 -0
  229. package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +250 -0
  230. package/src/server/routes/instance/httpapi/public.ts +537 -0
  231. package/src/server/routes/instance/httpapi/server.ts +325 -0
  232. package/src/server/routes/instance/httpapi/websocket-tracker.ts +60 -0
  233. package/src/server/server.ts +224 -0
  234. package/src/server/shared/fence.ts +60 -0
  235. package/src/server/shared/pty-ticket.ts +15 -0
  236. package/src/server/shared/public-ui.ts +12 -0
  237. package/src/server/shared/tui-control.ts +28 -0
  238. package/src/server/shared/ui.ts +108 -0
  239. package/src/server/shared/workspace-routing.ts +45 -0
  240. package/src/server/tui-event.ts +1 -0
  241. package/src/session/compaction.ts +608 -0
  242. package/src/session/instruction.ts +237 -0
  243. package/src/session/llm/AGENTS.md +90 -0
  244. package/src/session/llm/ai-sdk.ts +291 -0
  245. package/src/session/llm/native-request.ts +196 -0
  246. package/src/session/llm/native-runtime.ts +195 -0
  247. package/src/session/llm/request.ts +226 -0
  248. package/src/session/llm.ts +390 -0
  249. package/src/session/message-error.ts +14 -0
  250. package/src/session/message-v2.ts +742 -0
  251. package/src/session/message.ts +148 -0
  252. package/src/session/overflow.ts +34 -0
  253. package/src/session/processor.ts +732 -0
  254. package/src/session/prompt/build-switch.txt +5 -0
  255. package/src/session/prompt/default.txt +35 -0
  256. package/src/session/prompt/plan-mode.txt +70 -0
  257. package/src/session/prompt/plan.txt +26 -0
  258. package/src/session/prompt.ts +1631 -0
  259. package/src/session/reminders.ts +92 -0
  260. package/src/session/retry.ts +209 -0
  261. package/src/session/revert.ts +136 -0
  262. package/src/session/run-state.ts +151 -0
  263. package/src/session/schema.ts +26 -0
  264. package/src/session/session.ts +1016 -0
  265. package/src/session/status.ts +56 -0
  266. package/src/session/summary.ts +160 -0
  267. package/src/session/system.ts +123 -0
  268. package/src/session/todo.ts +74 -0
  269. package/src/session/tools.ts +590 -0
  270. package/src/share/session.ts +58 -0
  271. package/src/share/share-next.ts +371 -0
  272. package/src/skill/discovery.ts +140 -0
  273. package/src/skill/index.ts +354 -0
  274. package/src/snapshot/index.ts +807 -0
  275. package/src/sql.d.ts +4 -0
  276. package/src/storage/schema.ts +5 -0
  277. package/src/storage/storage.ts +327 -0
  278. package/src/sync/README.md +179 -0
  279. package/src/sync/schema.ts +11 -0
  280. package/src/temporary.ts +31 -0
  281. package/src/tool/apply_patch.ts +313 -0
  282. package/src/tool/apply_patch.txt +14 -0
  283. package/src/tool/code-mode.ts +310 -0
  284. package/src/tool/edit.ts +737 -0
  285. package/src/tool/edit.txt +13 -0
  286. package/src/tool/external-directory.ts +49 -0
  287. package/src/tool/glob.ts +76 -0
  288. package/src/tool/glob.txt +7 -0
  289. package/src/tool/grep.ts +115 -0
  290. package/src/tool/grep.txt +7 -0
  291. package/src/tool/invalid.ts +21 -0
  292. package/src/tool/json-schema.ts +164 -0
  293. package/src/tool/lsp.ts +113 -0
  294. package/src/tool/lsp.txt +1 -0
  295. package/src/tool/mcp-websearch.ts +96 -0
  296. package/src/tool/plan-enter.txt +1 -0
  297. package/src/tool/plan-exit.txt +1 -0
  298. package/src/tool/plan.ts +79 -0
  299. package/src/tool/question.ts +44 -0
  300. package/src/tool/question.txt +1 -0
  301. package/src/tool/read.ts +386 -0
  302. package/src/tool/read.txt +13 -0
  303. package/src/tool/registry.ts +455 -0
  304. package/src/tool/schema.ts +14 -0
  305. package/src/tool/shell/id.ts +19 -0
  306. package/src/tool/shell/prompt.ts +293 -0
  307. package/src/tool/shell/shell.txt +21 -0
  308. package/src/tool/shell.ts +645 -0
  309. package/src/tool/skill.ts +70 -0
  310. package/src/tool/skill.txt +1 -0
  311. package/src/tool/task.ts +371 -0
  312. package/src/tool/task.txt +11 -0
  313. package/src/tool/todo.ts +46 -0
  314. package/src/tool/todowrite.txt +11 -0
  315. package/src/tool/tool.ts +183 -0
  316. package/src/tool/truncate.ts +156 -0
  317. package/src/tool/truncation-dir.ts +4 -0
  318. package/src/tool/webfetch.ts +192 -0
  319. package/src/tool/webfetch.txt +9 -0
  320. package/src/tool/websearch.ts +143 -0
  321. package/src/tool/websearch.txt +9 -0
  322. package/src/tool/write.ts +104 -0
  323. package/src/tool/write.txt +11 -0
  324. package/src/util/archive.ts +17 -0
  325. package/src/util/bom.ts +27 -0
  326. package/src/util/data-url.ts +9 -0
  327. package/src/util/defer.ts +10 -0
  328. package/src/util/effect-http-client.ts +11 -0
  329. package/src/util/error.ts +16 -0
  330. package/src/util/filesystem.ts +251 -0
  331. package/src/util/html.ts +8 -0
  332. package/src/util/iife.ts +3 -0
  333. package/src/util/lazy.ts +20 -0
  334. package/src/util/local-context.ts +25 -0
  335. package/src/util/locale.ts +4 -0
  336. package/src/util/media.ts +26 -0
  337. package/src/util/process.ts +177 -0
  338. package/src/util/proxy-env.ts +72 -0
  339. package/src/util/queue.ts +32 -0
  340. package/src/util/record.ts +3 -0
  341. package/src/util/repository.ts +232 -0
  342. package/src/util/rpc.ts +66 -0
  343. package/src/util/signal.ts +12 -0
  344. package/src/util/timeout.ts +13 -0
  345. package/src/util/token.ts +1 -0
  346. package/src/util/wildcard.ts +59 -0
  347. package/src/worktree/index.ts +623 -0
  348. package/sst-env.d.ts +10 -0
  349. package/tsconfig.headless.json +13 -0
  350. package/tsconfig.json +16 -0
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env node
2
+
3
+ import childProcess from "child_process"
4
+ import fs from "fs"
5
+ import os from "os"
6
+ import path from "path"
7
+ import { createRequire } from "module"
8
+ import { fileURLToPath } from "url"
9
+
10
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
11
+ const require = createRequire(import.meta.url)
12
+ const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"))
13
+
14
+ const platformMap = {
15
+ darwin: "darwin",
16
+ linux: "linux",
17
+ win32: "windows",
18
+ }
19
+ const archMap = {
20
+ x64: "x64",
21
+ arm64: "arm64",
22
+ arm: "arm",
23
+ }
24
+
25
+ const platform = platformMap[os.platform()] ?? os.platform()
26
+ const arch = archMap[os.arch()] ?? os.arch()
27
+ const base = `opencode-${platform}-${arch}`
28
+ const sourceBinary = platform === "windows" ? "opencode.exe" : "opencode"
29
+ const targetBinary = path.join(__dirname, "bin", "opencode.exe")
30
+
31
+ function supportsAvx2() {
32
+ if (arch !== "x64") return false
33
+
34
+ if (platform === "linux") {
35
+ try {
36
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
37
+ } catch {
38
+ return false
39
+ }
40
+ }
41
+
42
+ if (platform === "darwin") {
43
+ try {
44
+ const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
45
+ encoding: "utf8",
46
+ timeout: 1500,
47
+ })
48
+ if (result.status !== 0) return false
49
+ return (result.stdout || "").trim() === "1"
50
+ } catch {
51
+ return false
52
+ }
53
+ }
54
+
55
+ if (platform === "windows") {
56
+ const command =
57
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
58
+
59
+ for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
60
+ try {
61
+ const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
62
+ encoding: "utf8",
63
+ timeout: 3000,
64
+ windowsHide: true,
65
+ })
66
+ if (result.status !== 0) continue
67
+ const output = (result.stdout || "").trim().toLowerCase()
68
+ if (output === "true" || output === "1") return true
69
+ if (output === "false" || output === "0") return false
70
+ } catch {
71
+ continue
72
+ }
73
+ }
74
+ }
75
+
76
+ return false
77
+ }
78
+
79
+ function isMusl() {
80
+ if (platform !== "linux") return false
81
+
82
+ try {
83
+ if (fs.existsSync("/etc/alpine-release")) return true
84
+ } catch {
85
+ // Ignore filesystem probes that are blocked by the host.
86
+ }
87
+
88
+ try {
89
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
90
+ return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
91
+ } catch {
92
+ return false
93
+ }
94
+ }
95
+
96
+ function packageNames() {
97
+ const baseline = arch === "x64" && !supportsAvx2()
98
+
99
+ if (platform === "linux") {
100
+ if (isMusl()) {
101
+ if (arch === "x64")
102
+ return baseline
103
+ ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
104
+ : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
105
+ return [`${base}-musl`, base]
106
+ }
107
+
108
+ if (arch === "x64")
109
+ return baseline
110
+ ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
111
+ : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
112
+ return [base, `${base}-musl`]
113
+ }
114
+
115
+ if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
116
+ return [base]
117
+ }
118
+
119
+ function resolveBinary(name) {
120
+ const packageJsonPath = require.resolve(`${name}/package.json`)
121
+ const binaryPath = path.join(path.dirname(packageJsonPath), "bin", sourceBinary)
122
+ if (!fs.existsSync(binaryPath)) throw new Error(`Binary not found at ${binaryPath}`)
123
+ return binaryPath
124
+ }
125
+
126
+ function installPackage(name) {
127
+ const version = packageJson.optionalDependencies?.[name]
128
+ if (!version) return
129
+
130
+ const temp = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-install-"))
131
+ try {
132
+ const result = childProcess.spawnSync(
133
+ "npm",
134
+ ["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${name}@${version}`],
135
+ { stdio: "inherit", windowsHide: true },
136
+ )
137
+ if (result.status !== 0) return
138
+ const packageDir = path.join(temp, "node_modules", name)
139
+ copyBinary(path.join(packageDir, "bin", sourceBinary), targetBinary)
140
+ return true
141
+ } finally {
142
+ fs.rmSync(temp, { recursive: true, force: true })
143
+ }
144
+ }
145
+
146
+ function copyBinary(source, target) {
147
+ if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
148
+ fs.mkdirSync(path.dirname(target), { recursive: true })
149
+ if (fs.existsSync(target)) fs.unlinkSync(target)
150
+ try {
151
+ fs.linkSync(source, target)
152
+ } catch {
153
+ fs.copyFileSync(source, target)
154
+ }
155
+ fs.chmodSync(target, 0o755)
156
+ }
157
+
158
+ function verifyBinary() {
159
+ const result = childProcess.spawnSync(targetBinary, ["--version"], {
160
+ encoding: "utf8",
161
+ stdio: "ignore",
162
+ windowsHide: true,
163
+ })
164
+ return result.status === 0
165
+ }
166
+
167
+ function main() {
168
+ for (const name of packageNames()) {
169
+ try {
170
+ copyBinary(resolveBinary(name), targetBinary)
171
+ if (verifyBinary()) return
172
+ } catch {
173
+ if (installPackage(name) && verifyBinary()) return
174
+ }
175
+ }
176
+
177
+ throw new Error(
178
+ `It seems your package manager failed to install the right opencode CLI package. Try manually installing ${packageNames()
179
+ .map((name) => JSON.stringify(name))
180
+ .join(" or ")}.`,
181
+ )
182
+ }
183
+
184
+ try {
185
+ main()
186
+ } catch (error) {
187
+ console.error(error.message)
188
+ process.exit(1)
189
+ }
@@ -0,0 +1,42 @@
1
+ // Per-file profiler for finding candidate test-speed work; see ../../perf/test-suite.md
2
+ // for the benchmark notes, kept wins, and discarded experiments.
3
+ // Example: TEST_PROFILE_GLOB='test/server/**/*.test.ts' TEST_PROFILE_TOP=15 bun run profile:test
4
+ const pattern = Bun.env.TEST_PROFILE_GLOB ?? "test/**/*.test.{ts,tsx}"
5
+ const limit = Number(Bun.env.TEST_PROFILE_LIMIT ?? 0)
6
+ const timeout = Bun.env.TEST_PROFILE_TIMEOUT ?? "30000"
7
+ const files = Array.fromAsync(new Bun.Glob(pattern).scan({ cwd: import.meta.dir + "/..", onlyFiles: true }))
8
+ .then((files) => files.toSorted())
9
+ .then((files) => (limit > 0 ? files.slice(0, limit) : files))
10
+
11
+ const results = []
12
+ for (const file of await files) {
13
+ const start = performance.now()
14
+ const proc = Bun.spawn(["bun", "test", "--timeout", timeout, file], {
15
+ cwd: import.meta.dir + "/..",
16
+ stdout: "pipe",
17
+ stderr: "pipe",
18
+ env: Bun.env,
19
+ })
20
+ const [output, error, exitCode] = await Promise.all([
21
+ new Response(proc.stdout).text(),
22
+ new Response(proc.stderr).text(),
23
+ proc.exited,
24
+ ])
25
+ const seconds = (performance.now() - start) / 1000
26
+ results.push({ file, seconds, exitCode })
27
+ console.log(`${exitCode === 0 ? "PASS" : "FAIL"} ${seconds.toFixed(3)}s ${file}`)
28
+ if (exitCode !== 0) console.log((output + error).trim())
29
+ }
30
+
31
+ const sorted = results.toSorted((a, b) => b.seconds - a.seconds)
32
+ console.log("\nSlowest test files:")
33
+ for (const result of sorted.slice(0, Number(Bun.env.TEST_PROFILE_TOP ?? 20))) {
34
+ console.log(`${result.seconds.toFixed(3)}s ${result.exitCode === 0 ? "PASS" : "FAIL"} ${result.file}`)
35
+ }
36
+
37
+ if (sorted[0]) {
38
+ console.log(`METRIC slowest_test_file_seconds=${sorted[0].seconds.toFixed(3)}`)
39
+ console.log(`METRIC profiled_test_files=${results.length}`)
40
+ }
41
+
42
+ if (results.some((result) => result.exitCode !== 0)) process.exit(1)
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env bun
2
+ import { $ } from "bun"
3
+ import pkg from "../package.json"
4
+ import { Script } from "@opencode-ai/script"
5
+ import { fileURLToPath } from "url"
6
+
7
+ const dir = fileURLToPath(new URL("..", import.meta.url))
8
+ process.chdir(dir)
9
+
10
+ async function published(name: string, version: string) {
11
+ return (await $`npm view ${name}@${version} version`.nothrow()).exitCode === 0
12
+ }
13
+
14
+ async function publish(dir: string, name: string, version: string) {
15
+ // GitHub artifact downloads can drop the executable bit, and Docker uses the
16
+ // unpacked dist binaries directly rather than the published tarball.
17
+ if (process.platform !== "win32") await $`chmod -R 755 .`.cwd(dir)
18
+ if (await published(name, version)) {
19
+ console.log(`already published ${name}@${version}`)
20
+ return
21
+ }
22
+ await $`bun pm pack`.cwd(dir)
23
+ await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(dir)
24
+ }
25
+
26
+ const binaries: Record<string, string> = {}
27
+ for (const filepath of new Bun.Glob("*/package.json").scanSync({ cwd: "./dist" })) {
28
+ const pkg = await Bun.file(`./dist/${filepath}`).json()
29
+ binaries[pkg.name] = pkg.version
30
+ }
31
+ console.log("binaries", binaries)
32
+ const version = Object.values(binaries)[0]
33
+
34
+ await $`mkdir -p ./dist/${pkg.name}`
35
+ await $`mkdir -p ./dist/${pkg.name}/bin`
36
+ await $`cp ./script/postinstall.mjs ./dist/${pkg.name}/postinstall.mjs`
37
+ await Bun.file(`./dist/${pkg.name}/LICENSE`).write(await Bun.file("../../LICENSE").text())
38
+ await Bun.file(`./dist/${pkg.name}/bin/${pkg.name}.exe`).write(
39
+ [
40
+ `echo "Error: ${pkg.name}-ai's postinstall script was not run." >&2`,
41
+ 'echo "" >&2',
42
+ 'echo "This occurs when using --ignore-scripts during installation, or when using a" >&2',
43
+ 'echo "package manager like pnpm that does not run postinstall scripts by default." >&2',
44
+ 'echo "" >&2',
45
+ 'echo "To fix this, run the postinstall script manually:" >&2',
46
+ `echo " cd node_modules/${pkg.name}-ai && node postinstall.mjs" >&2`,
47
+ 'echo "" >&2',
48
+ `echo "Or reinstall ${pkg.name}-ai without the --ignore-scripts flag." >&2`,
49
+ "exit 1",
50
+ "",
51
+ ].join("\n"),
52
+ )
53
+
54
+ await Bun.file(`./dist/${pkg.name}/package.json`).write(
55
+ JSON.stringify(
56
+ {
57
+ name: pkg.name + "-ai",
58
+ bin: {
59
+ [pkg.name]: `./bin/${pkg.name}.exe`,
60
+ },
61
+ scripts: {
62
+ postinstall: "node ./postinstall.mjs",
63
+ },
64
+ version: version,
65
+ license: pkg.license,
66
+ os: ["darwin", "linux", "win32"],
67
+ cpu: ["arm64", "x64"],
68
+ optionalDependencies: binaries,
69
+ },
70
+ null,
71
+ 2,
72
+ ),
73
+ )
74
+
75
+ const tasks = Object.entries(binaries).map(async ([name]) => {
76
+ await publish(`./dist/${name}`, name, binaries[name])
77
+ })
78
+ await Promise.all(tasks)
79
+ await publish(`./dist/${pkg.name}`, `${pkg.name}-ai`, version)
80
+
81
+ const image = "ghcr.io/anomalyco/opencode"
82
+ const platforms = "linux/amd64,linux/arm64"
83
+ const tags = [`${image}:${version}`, `${image}:${Script.channel}`]
84
+ const tagFlags = tags.flatMap((t) => ["-t", t])
85
+
86
+ // registries
87
+ if (!Script.preview) {
88
+ await $`docker buildx build --platform ${platforms} ${tagFlags} --push .`
89
+ // Calculate SHA values
90
+ const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
91
+ const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
92
+ const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim())
93
+ const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim())
94
+
95
+ const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2)
96
+
97
+ // arch
98
+ const binaryPkgbuild = [
99
+ "# Maintainer: dax",
100
+ "# Maintainer: adam",
101
+ "",
102
+ "pkgname='opencode-bin'",
103
+ `pkgver=${pkgver}`,
104
+ `_subver=${_subver}`,
105
+ "options=('!debug' '!strip')",
106
+ "pkgrel=1",
107
+ "pkgdesc='The AI coding agent built for the terminal.'",
108
+ "url='https://github.com/anomalyco/opencode'",
109
+ "arch=('aarch64' 'x86_64')",
110
+ "license=('MIT')",
111
+ "provides=('opencode')",
112
+ "conflicts=('opencode')",
113
+ "depends=('ripgrep')",
114
+ "",
115
+ `source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-arm64.tar.gz")`,
116
+ `sha256sums_aarch64=('${arm64Sha}')`,
117
+
118
+ `source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-x64.tar.gz")`,
119
+ `sha256sums_x86_64=('${x64Sha}')`,
120
+ "",
121
+ "package() {",
122
+ ' install -Dm755 ./opencode "${pkgdir}/usr/bin/opencode"',
123
+ "}",
124
+ "",
125
+ ].join("\n")
126
+
127
+ for (const [pkg, pkgbuild] of [["opencode-bin", binaryPkgbuild]]) {
128
+ for (let i = 0; i < 30; i++) {
129
+ try {
130
+ await $`rm -rf ./dist/aur-${pkg}`
131
+ await $`git clone ssh://aur@aur.archlinux.org/${pkg}.git ./dist/aur-${pkg}`
132
+ await $`cd ./dist/aur-${pkg} && git checkout master`
133
+ await Bun.file(`./dist/aur-${pkg}/PKGBUILD`).write(pkgbuild)
134
+ await $`cd ./dist/aur-${pkg} && makepkg --printsrcinfo > .SRCINFO`
135
+ await $`cd ./dist/aur-${pkg} && git add PKGBUILD .SRCINFO`
136
+ if ((await $`cd ./dist/aur-${pkg} && git diff --cached --quiet`.nothrow()).exitCode === 0) break
137
+ await $`cd ./dist/aur-${pkg} && git commit -m "Update to v${Script.version}"`
138
+ await $`cd ./dist/aur-${pkg} && git push`
139
+ break
140
+ } catch {
141
+ continue
142
+ }
143
+ }
144
+ }
145
+
146
+ // Homebrew formula
147
+ const homebrewFormula = [
148
+ "# typed: false",
149
+ "# frozen_string_literal: true",
150
+ "",
151
+ "# This file was generated by GoReleaser. DO NOT EDIT.",
152
+ "class Opencode < Formula",
153
+ ` desc "The AI coding agent built for the terminal."`,
154
+ ` homepage "https://github.com/anomalyco/opencode"`,
155
+ ` version "${Script.version.split("-")[0]}"`,
156
+ "",
157
+ ` depends_on "ripgrep"`,
158
+ "",
159
+ " on_macos do",
160
+ " if Hardware::CPU.intel?",
161
+ ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-x64.zip"`,
162
+ ` sha256 "${macX64Sha}"`,
163
+ "",
164
+ " def install",
165
+ ' bin.install "opencode"',
166
+ " end",
167
+ " end",
168
+ " if Hardware::CPU.arm?",
169
+ ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-arm64.zip"`,
170
+ ` sha256 "${macArm64Sha}"`,
171
+ "",
172
+ " def install",
173
+ ' bin.install "opencode"',
174
+ " end",
175
+ " end",
176
+ " end",
177
+ "",
178
+ " on_linux do",
179
+ " if Hardware::CPU.intel? and Hardware::CPU.is_64_bit?",
180
+ ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-x64.tar.gz"`,
181
+ ` sha256 "${x64Sha}"`,
182
+ " def install",
183
+ ' bin.install "opencode"',
184
+ " end",
185
+ " end",
186
+ " if Hardware::CPU.arm? and Hardware::CPU.is_64_bit?",
187
+ ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-arm64.tar.gz"`,
188
+ ` sha256 "${arm64Sha}"`,
189
+ " def install",
190
+ ' bin.install "opencode"',
191
+ " end",
192
+ " end",
193
+ " end",
194
+ "end",
195
+ "",
196
+ "",
197
+ ].join("\n")
198
+
199
+ const token = process.env.GITHUB_TOKEN
200
+ if (!token) {
201
+ console.error("GITHUB_TOKEN is required to update homebrew tap")
202
+ process.exit(1)
203
+ }
204
+ const tap = `https://x-access-token:${token}@github.com/anomalyco/homebrew-tap.git`
205
+ await $`rm -rf ./dist/homebrew-tap`
206
+ await $`git clone ${tap} ./dist/homebrew-tap`
207
+ await Bun.file("./dist/homebrew-tap/opencode.rb").write(homebrewFormula)
208
+ await $`cd ./dist/homebrew-tap && git add opencode.rb`
209
+ if ((await $`cd ./dist/homebrew-tap && git diff --cached --quiet`.nothrow()).exitCode !== 0) {
210
+ await $`cd ./dist/homebrew-tap && git commit -m "Update to v${Script.version}"`
211
+ await $`cd ./dist/homebrew-tap && git push`
212
+ }
213
+ }
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env bun
2
+
3
+ // This script runs a separate OpenCode server to be used as a remote
4
+ // workspace, simulating a remote environment but all local to make
5
+ // debugger easier
6
+ //
7
+ // *Important*: make sure you add the debug workspace plugin first.
8
+ // In `.opencode/opencode.jsonc` in the root of this project add:
9
+ //
10
+ // "plugin": ["../packages/opencode/src/control-plane/dev/debug-workspace-plugin.ts"]
11
+ //
12
+ // Afterwards, run `./packages/opencode/script/run-workspace-server`
13
+
14
+ import { stat } from "node:fs/promises"
15
+ import { setTimeout as sleep } from "node:timers/promises"
16
+
17
+ const DEV_DATA_FILE = "/tmp/opencode-workspace-dev-data.json"
18
+ const RESTART_POLL_INTERVAL = 250
19
+
20
+ async function readData() {
21
+ return await Bun.file(DEV_DATA_FILE).json()
22
+ }
23
+
24
+ async function readDataMtime() {
25
+ return await stat(DEV_DATA_FILE)
26
+ .then((info) => info.mtimeMs)
27
+ .catch((error) => {
28
+ if (typeof error === "object" && error && "code" in error && error.code === "ENOENT") {
29
+ return undefined
30
+ }
31
+
32
+ throw error
33
+ })
34
+ }
35
+
36
+ async function readSnapshot() {
37
+ while (true) {
38
+ try {
39
+ const before = await readDataMtime()
40
+ if (before === undefined) {
41
+ await sleep(RESTART_POLL_INTERVAL)
42
+ continue
43
+ }
44
+
45
+ const data = await readData()
46
+ const after = await readDataMtime()
47
+
48
+ if (before === after) {
49
+ return { data, mtime: after }
50
+ }
51
+ } catch (error) {
52
+ if (typeof error === "object" && error && "code" in error && error.code === "ENOENT") {
53
+ await sleep(RESTART_POLL_INTERVAL)
54
+ continue
55
+ }
56
+
57
+ throw error
58
+ }
59
+ }
60
+ }
61
+
62
+ function startDevServer(data: any) {
63
+ const env = Object.fromEntries(Object.entries(data.env ?? {}).filter(([, value]) => value !== undefined))
64
+
65
+ return Bun.spawn(["bun", "run", "dev", "serve", "--port", String(data.port), "--print-logs"], {
66
+ env: {
67
+ ...process.env,
68
+ ...env,
69
+ XDG_DATA_HOME: "/tmp/data",
70
+ },
71
+ stdin: "inherit",
72
+ stdout: "inherit",
73
+ stderr: "inherit",
74
+ })
75
+ }
76
+
77
+ async function waitForRestartSignal(mtime: number, signal: AbortSignal) {
78
+ while (!signal.aborted) {
79
+ await sleep(RESTART_POLL_INTERVAL)
80
+ if (signal.aborted) return false
81
+ if ((await readDataMtime()) !== mtime) return true
82
+ }
83
+
84
+ return false
85
+ }
86
+
87
+ while (true) {
88
+ const { data, mtime } = await readSnapshot()
89
+ const proc = startDevServer(data)
90
+ const restartAbort = new AbortController()
91
+
92
+ const result = await Promise.race([
93
+ proc.exited.then((code) => ({ type: "exit" as const, code })),
94
+ waitForRestartSignal(mtime, restartAbort.signal).then((restart) => ({ type: "restart" as const, restart })),
95
+ ])
96
+
97
+ restartAbort.abort()
98
+
99
+ if (result.type === "restart" && result.restart) {
100
+ proc.kill()
101
+ await proc.exited
102
+ continue
103
+ }
104
+
105
+ process.exit(result.code)
106
+ }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Config } from "@/config/config"
4
+ import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
5
+ import { TuiConfig } from "@opencode-ai/tui/config"
6
+ import { Schema } from "effect"
7
+
8
+ type JsonSchema = Record<string, unknown>
9
+ const MODEL_REF = "https://models.dev/model-schema.json#/$defs/Model"
10
+
11
+ function generateEffect(schema: Schema.Top) {
12
+ const document = Schema.toJsonSchemaDocument(schema)
13
+ const normalized = normalize({
14
+ $schema: "https://json-schema.org/draft/2020-12/schema",
15
+ ...document.schema,
16
+ $defs: document.definitions,
17
+ })
18
+ if (!isRecord(normalized)) throw new Error("schema generator produced a non-object schema")
19
+ const restored = restoreModelRefs(normalized)
20
+ if (!isRecord(restored)) throw new Error("schema generator produced a non-object schema")
21
+ restored.allowComments = true
22
+ restored.allowTrailingCommas = true
23
+ return restored
24
+ }
25
+
26
+ function normalize(value: unknown): unknown {
27
+ if (Array.isArray(value)) return value.map(normalize)
28
+ if (!isRecord(value)) return value
29
+
30
+ const schema = Object.fromEntries(Object.entries(value).map(([key, item]) => [key, normalize(item)]))
31
+
32
+ if (Array.isArray(schema.anyOf)) {
33
+ const anyOf = schema.anyOf.filter((item) => !isRecord(item) || item.type !== "null")
34
+ if (anyOf.length !== schema.anyOf.length) {
35
+ const { anyOf: _, ...rest } = schema
36
+ if (anyOf.length === 1 && isRecord(anyOf[0])) return normalize({ ...anyOf[0], ...rest })
37
+ return { ...rest, anyOf }
38
+ }
39
+ }
40
+
41
+ if (Array.isArray(schema.allOf) && schema.allOf.length === 1 && isRecord(schema.allOf[0])) {
42
+ const { allOf: _, ...rest } = schema
43
+ return normalize({ ...schema.allOf[0], ...rest })
44
+ }
45
+
46
+ if (schema.type === "integer" && schema.maximum === undefined) {
47
+ return { ...schema, maximum: Number.MAX_SAFE_INTEGER }
48
+ }
49
+
50
+ return schema
51
+ }
52
+
53
+ function restoreModelRefs(value: unknown, key?: string): unknown {
54
+ if (Array.isArray(value)) return value.map((item) => restoreModelRefs(item))
55
+ if (!isRecord(value)) return value
56
+
57
+ const schema = Object.fromEntries(Object.entries(value).map(([name, item]) => [name, restoreModelRefs(item, name)]))
58
+ if ((key === "model" || key === "small_model") && schema.type === "string") {
59
+ return { ...schema, $ref: MODEL_REF }
60
+ }
61
+ return schema
62
+ }
63
+
64
+ function isRecord(value: unknown): value is JsonSchema {
65
+ return typeof value === "object" && value !== null && !Array.isArray(value)
66
+ }
67
+
68
+ const configFile = process.argv[2]
69
+ const tuiFile = process.argv[3]
70
+
71
+ console.log(configFile)
72
+ await Bun.write(configFile, JSON.stringify(generateEffect(ConfigV1.Info), null, 2))
73
+
74
+ if (tuiFile) {
75
+ console.log(tuiFile)
76
+ await Bun.write(tuiFile, JSON.stringify(generateEffect(TuiConfig.Info), null, 2))
77
+ }
package/script/time.ts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import path from "path"
4
+ const toDynamicallyImport = path.join(process.cwd(), process.argv[2])
5
+ await import(toDynamicallyImport)
6
+ console.log(performance.now())