bonecode 1.0.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 (605) hide show
  1. package/ARCHITECTURE.md +183 -0
  2. package/README.md +71 -0
  3. package/bin/bonecode +62 -0
  4. package/bone/migrations/rag_vectors.sql +258 -0
  5. package/bone/output/agent/.dockerignore +7 -0
  6. package/bone/output/agent/.env.example +36 -0
  7. package/bone/output/agent/.github/workflows/ci.yaml +58 -0
  8. package/bone/output/agent/AgentDomain.bone.map +350 -0
  9. package/bone/output/agent/AgentDomain.postman_collection.json +958 -0
  10. package/bone/output/agent/Dockerfile +22 -0
  11. package/bone/output/agent/README.md +47 -0
  12. package/bone/output/agent/admin/index.html +740 -0
  13. package/bone/output/agent/docker-compose.yaml +22 -0
  14. package/bone/output/agent/k8s/deployment.yaml +75 -0
  15. package/bone/output/agent/migrations/agent.sql +36 -0
  16. package/bone/output/agent/migrations/agent_instance.sql +36 -0
  17. package/bone/output/agent/migrations/audit_log.sql +18 -0
  18. package/bone/output/agent/migrations/build_step.sql +34 -0
  19. package/bone/output/agent/migrations/event_outbox.sql +31 -0
  20. package/bone/output/agent/migrations/plan.sql +30 -0
  21. package/bone/output/agent/migrations/task.sql +30 -0
  22. package/bone/output/agent/migrations/tool_call.sql +33 -0
  23. package/bone/output/agent/openapi.yaml +1116 -0
  24. package/bone/output/agent/package.json +36 -0
  25. package/bone/output/agent/schema.graphql +233 -0
  26. package/bone/output/agent/sdk/client.ts +231 -0
  27. package/bone/output/agent/src/algorithms.ts +2 -0
  28. package/bone/output/agent/src/audit.ts +44 -0
  29. package/bone/output/agent/src/auth.ts +57 -0
  30. package/bone/output/agent/src/cron.ts +12 -0
  31. package/bone/output/agent/src/db.ts +32 -0
  32. package/bone/output/agent/src/debug.ts +66 -0
  33. package/bone/output/agent/src/events.ts +243 -0
  34. package/bone/output/agent/src/extensions.ts +54 -0
  35. package/bone/output/agent/src/failure_rules.ts +323 -0
  36. package/bone/output/agent/src/flows.ts +168 -0
  37. package/bone/output/agent/src/health.ts +43 -0
  38. package/bone/output/agent/src/index.ts +100 -0
  39. package/bone/output/agent/src/logger.ts +66 -0
  40. package/bone/output/agent/src/metrics.ts +75 -0
  41. package/bone/output/agent/src/migrate.ts +352 -0
  42. package/bone/output/agent/src/migration_diff.ts +108 -0
  43. package/bone/output/agent/src/notify.ts +125 -0
  44. package/bone/output/agent/src/routes/agent_instance.ts +234 -0
  45. package/bone/output/agent/src/routes/build_step.ts +105 -0
  46. package/bone/output/agent/src/routes/plan.ts +91 -0
  47. package/bone/output/agent/src/routes/task.ts +105 -0
  48. package/bone/output/agent/src/routes/tool_call.ts +166 -0
  49. package/bone/output/agent/src/schemas.ts +384 -0
  50. package/bone/output/agent/src/state_machines/agent_instance.ts +24 -0
  51. package/bone/output/agent/src/state_machines/build_step.ts +22 -0
  52. package/bone/output/agent/src/state_machines/plan.ts +22 -0
  53. package/bone/output/agent/src/state_machines/task.ts +22 -0
  54. package/bone/output/agent/src/state_machines/tool_call.ts +22 -0
  55. package/bone/output/agent/src/tests.ts +362 -0
  56. package/bone/output/agent/src/websocket.ts +201 -0
  57. package/bone/output/agent/tsconfig.json +25 -0
  58. package/bone/output/rag/.dockerignore +7 -0
  59. package/bone/output/rag/.env.example +36 -0
  60. package/bone/output/rag/.github/workflows/ci.yaml +58 -0
  61. package/bone/output/rag/Dockerfile +22 -0
  62. package/bone/output/rag/RAGDomain.bone.map +287 -0
  63. package/bone/output/rag/RAGDomain.postman_collection.json +923 -0
  64. package/bone/output/rag/README.md +47 -0
  65. package/bone/output/rag/admin/index.html +818 -0
  66. package/bone/output/rag/docker-compose.yaml +22 -0
  67. package/bone/output/rag/k8s/deployment.yaml +75 -0
  68. package/bone/output/rag/migrations/audit_log.sql +18 -0
  69. package/bone/output/rag/migrations/code_chunk.sql +34 -0
  70. package/bone/output/rag/migrations/code_file.sql +33 -0
  71. package/bone/output/rag/migrations/event_outbox.sql +31 -0
  72. package/bone/output/rag/migrations/indexing_job.sql +33 -0
  73. package/bone/output/rag/migrations/knowledge_base.sql +35 -0
  74. package/bone/output/rag/migrations/memory_entry.sql +34 -0
  75. package/bone/output/rag/openapi.yaml +1097 -0
  76. package/bone/output/rag/package.json +36 -0
  77. package/bone/output/rag/schema.graphql +245 -0
  78. package/bone/output/rag/sdk/client.ts +234 -0
  79. package/bone/output/rag/src/algorithms.ts +2 -0
  80. package/bone/output/rag/src/audit.ts +37 -0
  81. package/bone/output/rag/src/auth.ts +57 -0
  82. package/bone/output/rag/src/cron.ts +12 -0
  83. package/bone/output/rag/src/db.ts +32 -0
  84. package/bone/output/rag/src/debug.ts +66 -0
  85. package/bone/output/rag/src/events.ts +243 -0
  86. package/bone/output/rag/src/extensions.ts +350 -0
  87. package/bone/output/rag/src/failure_rules.ts +315 -0
  88. package/bone/output/rag/src/flows.ts +239 -0
  89. package/bone/output/rag/src/health.ts +43 -0
  90. package/bone/output/rag/src/index.ts +95 -0
  91. package/bone/output/rag/src/logger.ts +66 -0
  92. package/bone/output/rag/src/metrics.ts +75 -0
  93. package/bone/output/rag/src/migrate.ts +364 -0
  94. package/bone/output/rag/src/migration_diff.ts +108 -0
  95. package/bone/output/rag/src/notify.ts +99 -0
  96. package/bone/output/rag/src/routes/code_chunk.ts +75 -0
  97. package/bone/output/rag/src/routes/code_file.ts +101 -0
  98. package/bone/output/rag/src/routes/indexing_job.ts +87 -0
  99. package/bone/output/rag/src/routes/knowledge_base.ts +230 -0
  100. package/bone/output/rag/src/routes/memory_entry.ts +87 -0
  101. package/bone/output/rag/src/schemas.ts +394 -0
  102. package/bone/output/rag/src/state_machines/code_file.ts +23 -0
  103. package/bone/output/rag/src/state_machines/indexing_job.ts +22 -0
  104. package/bone/output/rag/src/state_machines/knowledge_base.ts +23 -0
  105. package/bone/output/rag/src/state_machines/memory_entry.ts +20 -0
  106. package/bone/output/rag/src/tests.ts +340 -0
  107. package/bone/output/rag/tsconfig.json +25 -0
  108. package/bone/output/session/.dockerignore +7 -0
  109. package/bone/output/session/.env.example +36 -0
  110. package/bone/output/session/.github/workflows/ci.yaml +58 -0
  111. package/bone/output/session/Dockerfile +22 -0
  112. package/bone/output/session/README.md +47 -0
  113. package/bone/output/session/SessionDomain.bone.map +350 -0
  114. package/bone/output/session/SessionDomain.postman_collection.json +958 -0
  115. package/bone/output/session/admin/index.html +667 -0
  116. package/bone/output/session/docker-compose.yaml +22 -0
  117. package/bone/output/session/k8s/deployment.yaml +75 -0
  118. package/bone/output/session/migrations/audit_log.sql +18 -0
  119. package/bone/output/session/migrations/event_outbox.sql +31 -0
  120. package/bone/output/session/migrations/message.sql +31 -0
  121. package/bone/output/session/migrations/part.sql +28 -0
  122. package/bone/output/session/migrations/permission.sql +28 -0
  123. package/bone/output/session/migrations/project.sql +28 -0
  124. package/bone/output/session/migrations/session.sql +38 -0
  125. package/bone/output/session/openapi.yaml +1101 -0
  126. package/bone/output/session/package.json +36 -0
  127. package/bone/output/session/schema.graphql +222 -0
  128. package/bone/output/session/sdk/client.ts +225 -0
  129. package/bone/output/session/src/algorithms.ts +2 -0
  130. package/bone/output/session/src/audit.ts +44 -0
  131. package/bone/output/session/src/auth.ts +57 -0
  132. package/bone/output/session/src/cron.ts +12 -0
  133. package/bone/output/session/src/db.ts +32 -0
  134. package/bone/output/session/src/debug.ts +66 -0
  135. package/bone/output/session/src/events.ts +270 -0
  136. package/bone/output/session/src/extensions.ts +215 -0
  137. package/bone/output/session/src/failure_rules.ts +284 -0
  138. package/bone/output/session/src/flows.ts +168 -0
  139. package/bone/output/session/src/health.ts +43 -0
  140. package/bone/output/session/src/index.ts +100 -0
  141. package/bone/output/session/src/logger.ts +66 -0
  142. package/bone/output/session/src/metrics.ts +75 -0
  143. package/bone/output/session/src/migrate.ts +332 -0
  144. package/bone/output/session/src/migration_diff.ts +108 -0
  145. package/bone/output/session/src/notify.ts +112 -0
  146. package/bone/output/session/src/routes/message.ts +93 -0
  147. package/bone/output/session/src/routes/part.ts +79 -0
  148. package/bone/output/session/src/routes/permission.ts +79 -0
  149. package/bone/output/session/src/routes/project.ts +79 -0
  150. package/bone/output/session/src/routes/session.ts +294 -0
  151. package/bone/output/session/src/schemas.ts +357 -0
  152. package/bone/output/session/src/state_machines/session.ts +23 -0
  153. package/bone/output/session/src/tests.ts +326 -0
  154. package/bone/output/session/src/websocket.ts +201 -0
  155. package/bone/output/session/tsconfig.json +25 -0
  156. package/bone/output/workspace/.dockerignore +7 -0
  157. package/bone/output/workspace/.env.example +36 -0
  158. package/bone/output/workspace/.github/workflows/ci.yaml +58 -0
  159. package/bone/output/workspace/Dockerfile +22 -0
  160. package/bone/output/workspace/README.md +45 -0
  161. package/bone/output/workspace/WorkspaceDomain.bone.map +189 -0
  162. package/bone/output/workspace/WorkspaceDomain.postman_collection.json +621 -0
  163. package/bone/output/workspace/admin/index.html +485 -0
  164. package/bone/output/workspace/docker-compose.yaml +22 -0
  165. package/bone/output/workspace/k8s/deployment.yaml +75 -0
  166. package/bone/output/workspace/migrations/audit_log.sql +18 -0
  167. package/bone/output/workspace/migrations/codebase.sql +34 -0
  168. package/bone/output/workspace/migrations/event_outbox.sql +31 -0
  169. package/bone/output/workspace/migrations/snapshot.sql +32 -0
  170. package/bone/output/workspace/migrations/workspace.sql +33 -0
  171. package/bone/output/workspace/openapi.yaml +721 -0
  172. package/bone/output/workspace/package.json +36 -0
  173. package/bone/output/workspace/schema.graphql +153 -0
  174. package/bone/output/workspace/sdk/client.ts +155 -0
  175. package/bone/output/workspace/src/algorithms.ts +2 -0
  176. package/bone/output/workspace/src/audit.ts +37 -0
  177. package/bone/output/workspace/src/auth.ts +57 -0
  178. package/bone/output/workspace/src/cron.ts +12 -0
  179. package/bone/output/workspace/src/db.ts +32 -0
  180. package/bone/output/workspace/src/debug.ts +66 -0
  181. package/bone/output/workspace/src/events.ts +243 -0
  182. package/bone/output/workspace/src/extensions.ts +44 -0
  183. package/bone/output/workspace/src/failure_rules.ts +153 -0
  184. package/bone/output/workspace/src/health.ts +43 -0
  185. package/bone/output/workspace/src/index.ts +89 -0
  186. package/bone/output/workspace/src/logger.ts +66 -0
  187. package/bone/output/workspace/src/metrics.ts +75 -0
  188. package/bone/output/workspace/src/migrate.ts +220 -0
  189. package/bone/output/workspace/src/migration_diff.ts +108 -0
  190. package/bone/output/workspace/src/notify.ts +73 -0
  191. package/bone/output/workspace/src/routes/codebase.ts +87 -0
  192. package/bone/output/workspace/src/routes/snapshot.ts +127 -0
  193. package/bone/output/workspace/src/routes/workspace.ts +190 -0
  194. package/bone/output/workspace/src/schemas.ts +231 -0
  195. package/bone/output/workspace/src/state_machines/codebase.ts +21 -0
  196. package/bone/output/workspace/src/state_machines/snapshot.ts +20 -0
  197. package/bone/output/workspace/src/state_machines/workspace.ts +21 -0
  198. package/bone/output/workspace/src/tests.ts +249 -0
  199. package/bone/output/workspace/tsconfig.json +25 -0
  200. package/compat/opencode_adapter.ts +410 -0
  201. package/package.json +69 -0
  202. package/scripts/check_benchmark_session.js +34 -0
  203. package/scripts/check_finish_event.js +24 -0
  204. package/scripts/check_parts.js +15 -0
  205. package/scripts/compile.js +79 -0
  206. package/scripts/copy_opencode.ps1 +53 -0
  207. package/scripts/create_functions.sql +129 -0
  208. package/scripts/migrate.js +85 -0
  209. package/scripts/migrate_from_opencode.ts +218 -0
  210. package/scripts/test_agent_loop.js +101 -0
  211. package/scripts/test_api.ps1 +116 -0
  212. package/scripts/test_context_builder.js +136 -0
  213. package/scripts/test_context_builder.ts +97 -0
  214. package/scripts/test_rag.js +189 -0
  215. package/scripts/test_stream_events.js +36 -0
  216. package/scripts/test_websocket_and_saga.js +216 -0
  217. package/src/cli.ts +475 -0
  218. package/src/config.ts +162 -0
  219. package/src/context_builder.ts +598 -0
  220. package/src/engine/account/account.sql.ts +39 -0
  221. package/src/engine/account/account.ts +456 -0
  222. package/src/engine/account/repo.ts +166 -0
  223. package/src/engine/account/schema.ts +99 -0
  224. package/src/engine/account/url.ts +8 -0
  225. package/src/engine/acp/README.md +174 -0
  226. package/src/engine/acp/agent.ts +1968 -0
  227. package/src/engine/acp/runtime.ts +22 -0
  228. package/src/engine/acp/session.ts +122 -0
  229. package/src/engine/acp/types.ts +24 -0
  230. package/src/engine/agent/agent.ts +463 -0
  231. package/src/engine/agent/generate.txt +75 -0
  232. package/src/engine/agent/prompt/compaction.txt +9 -0
  233. package/src/engine/agent/prompt/explore.txt +18 -0
  234. package/src/engine/agent/prompt/scout.txt +36 -0
  235. package/src/engine/agent/prompt/summary.txt +11 -0
  236. package/src/engine/agent/prompt/title.txt +44 -0
  237. package/src/engine/agent/subagent-permissions.ts +34 -0
  238. package/src/engine/auth/index.ts +96 -0
  239. package/src/engine/background/background/job.ts +200 -0
  240. package/src/engine/background/job.ts +200 -0
  241. package/src/engine/bus/bus-event.ts +45 -0
  242. package/src/engine/bus/global.ts +22 -0
  243. package/src/engine/bus/index.ts +203 -0
  244. package/src/engine/command/command/index.ts +181 -0
  245. package/src/engine/command/command/template/initialize.txt +66 -0
  246. package/src/engine/command/command/template/review.txt +101 -0
  247. package/src/engine/command/index.ts +181 -0
  248. package/src/engine/command/template/initialize.txt +66 -0
  249. package/src/engine/command/template/review.txt +101 -0
  250. package/src/engine/config/agent.ts +172 -0
  251. package/src/engine/config/attachment.ts +25 -0
  252. package/src/engine/config/command.ts +62 -0
  253. package/src/engine/config/config.ts +833 -0
  254. package/src/engine/config/console-state.ts +14 -0
  255. package/src/engine/config/entry-name.ts +16 -0
  256. package/src/engine/config/error.ts +23 -0
  257. package/src/engine/config/formatter.ts +13 -0
  258. package/src/engine/config/layout.ts +6 -0
  259. package/src/engine/config/lsp.ts +43 -0
  260. package/src/engine/config/managed.ts +71 -0
  261. package/src/engine/config/markdown.ts +96 -0
  262. package/src/engine/config/mcp.ts +56 -0
  263. package/src/engine/config/model-id.ts +5 -0
  264. package/src/engine/config/parse.ts +79 -0
  265. package/src/engine/config/paths.ts +45 -0
  266. package/src/engine/config/permission.ts +58 -0
  267. package/src/engine/config/plugin.ts +84 -0
  268. package/src/engine/config/provider.ts +111 -0
  269. package/src/engine/config/reference.ts +23 -0
  270. package/src/engine/config/server.ts +19 -0
  271. package/src/engine/config/skills.ts +14 -0
  272. package/src/engine/config/variable.ts +90 -0
  273. package/src/engine/control-plane/adapters/index.ts +41 -0
  274. package/src/engine/control-plane/adapters/worktree.ts +96 -0
  275. package/src/engine/control-plane/dev/README.md +19 -0
  276. package/src/engine/control-plane/dev/debug-workspace-plugin.ts +73 -0
  277. package/src/engine/control-plane/schema.ts +14 -0
  278. package/src/engine/control-plane/types.ts +59 -0
  279. package/src/engine/control-plane/util.ts +39 -0
  280. package/src/engine/control-plane/workspace-adapter-runtime.ts +51 -0
  281. package/src/engine/control-plane/workspace-context.ts +26 -0
  282. package/src/engine/control-plane/workspace.sql.ts +20 -0
  283. package/src/engine/control-plane/workspace.ts +1072 -0
  284. package/src/engine/data-migration.ts +161 -0
  285. package/src/engine/effect/app-runtime.ts +143 -0
  286. package/src/engine/effect/bootstrap-runtime.ts +29 -0
  287. package/src/engine/effect/bridge.ts +84 -0
  288. package/src/engine/effect/config-service.ts +67 -0
  289. package/src/engine/effect/instance-ref.ts +11 -0
  290. package/src/engine/effect/instance-registry.ts +12 -0
  291. package/src/engine/effect/instance-state.ts +72 -0
  292. package/src/engine/effect/promise.ts +17 -0
  293. package/src/engine/effect/run-service.ts +47 -0
  294. package/src/engine/effect/runner.ts +217 -0
  295. package/src/engine/effect/runtime-flags.ts +74 -0
  296. package/src/engine/effect/service-use.ts +38 -0
  297. package/src/engine/env/index.ts +37 -0
  298. package/src/engine/event-v2-bridge.ts +89 -0
  299. package/src/engine/file/file/ignore.ts +81 -0
  300. package/src/engine/file/file/index.ts +651 -0
  301. package/src/engine/file/file/protected.ts +59 -0
  302. package/src/engine/file/file/ripgrep.ts +481 -0
  303. package/src/engine/file/file/watcher.ts +167 -0
  304. package/src/engine/file/ignore.ts +81 -0
  305. package/src/engine/file/index.ts +651 -0
  306. package/src/engine/file/protected.ts +59 -0
  307. package/src/engine/file/ripgrep.ts +481 -0
  308. package/src/engine/file/watcher.ts +167 -0
  309. package/src/engine/format/format/formatter.ts +404 -0
  310. package/src/engine/format/format/index.ts +209 -0
  311. package/src/engine/format/formatter.ts +404 -0
  312. package/src/engine/format/index.ts +209 -0
  313. package/src/engine/git/git/index.ts +347 -0
  314. package/src/engine/git/index.ts +347 -0
  315. package/src/engine/id/id.ts +80 -0
  316. package/src/engine/ide/index.ts +70 -0
  317. package/src/engine/image/image/image.ts +176 -0
  318. package/src/engine/image/image.ts +176 -0
  319. package/src/engine/index.ts +251 -0
  320. package/src/engine/installation/index.ts +327 -0
  321. package/src/engine/lsp/client.ts +707 -0
  322. package/src/engine/lsp/diagnostic.ts +29 -0
  323. package/src/engine/lsp/language.ts +121 -0
  324. package/src/engine/lsp/launch.ts +21 -0
  325. package/src/engine/lsp/lsp/client.ts +707 -0
  326. package/src/engine/lsp/lsp/diagnostic.ts +29 -0
  327. package/src/engine/lsp/lsp/language.ts +121 -0
  328. package/src/engine/lsp/lsp/launch.ts +21 -0
  329. package/src/engine/lsp/lsp/lsp.ts +507 -0
  330. package/src/engine/lsp/lsp/server.ts +2064 -0
  331. package/src/engine/lsp/lsp.ts +507 -0
  332. package/src/engine/lsp/server.ts +2064 -0
  333. package/src/engine/mcp/auth.ts +146 -0
  334. package/src/engine/mcp/index.ts +958 -0
  335. package/src/engine/mcp/mcp/auth.ts +146 -0
  336. package/src/engine/mcp/mcp/index.ts +958 -0
  337. package/src/engine/mcp/mcp/oauth-callback.ts +232 -0
  338. package/src/engine/mcp/mcp/oauth-provider.ts +214 -0
  339. package/src/engine/mcp/oauth-callback.ts +232 -0
  340. package/src/engine/mcp/oauth-provider.ts +214 -0
  341. package/src/engine/node.ts +6 -0
  342. package/src/engine/patch/index.ts +689 -0
  343. package/src/engine/patch/patch/index.ts +689 -0
  344. package/src/engine/permission/arity.ts +163 -0
  345. package/src/engine/permission/evaluate.ts +15 -0
  346. package/src/engine/permission/index.ts +306 -0
  347. package/src/engine/permission/permission/arity.ts +163 -0
  348. package/src/engine/permission/permission/evaluate.ts +15 -0
  349. package/src/engine/permission/permission/index.ts +306 -0
  350. package/src/engine/permission/permission/schema.ts +13 -0
  351. package/src/engine/permission/schema.ts +13 -0
  352. package/src/engine/plugin/azure.ts +26 -0
  353. package/src/engine/plugin/cloudflare.ts +76 -0
  354. package/src/engine/plugin/codex.ts +622 -0
  355. package/src/engine/plugin/digitalocean.ts +411 -0
  356. package/src/engine/plugin/github-copilot/copilot.ts +394 -0
  357. package/src/engine/plugin/github-copilot/models.ts +196 -0
  358. package/src/engine/plugin/index.ts +295 -0
  359. package/src/engine/plugin/install.ts +439 -0
  360. package/src/engine/plugin/loader.ts +216 -0
  361. package/src/engine/plugin/meta.ts +188 -0
  362. package/src/engine/plugin/shared.ts +323 -0
  363. package/src/engine/project/bootstrap-service.ts +9 -0
  364. package/src/engine/project/bootstrap.ts +75 -0
  365. package/src/engine/project/instance-context.ts +24 -0
  366. package/src/engine/project/instance-layer.ts +11 -0
  367. package/src/engine/project/instance-runtime.ts +16 -0
  368. package/src/engine/project/instance-store.ts +193 -0
  369. package/src/engine/project/project.sql.ts +17 -0
  370. package/src/engine/project/project.ts +537 -0
  371. package/src/engine/project/schema.ts +13 -0
  372. package/src/engine/project/vcs.ts +405 -0
  373. package/src/engine/provider/auth.ts +225 -0
  374. package/src/engine/provider/error.ts +204 -0
  375. package/src/engine/provider/model-status.ts +8 -0
  376. package/src/engine/provider/provider.ts +1843 -0
  377. package/src/engine/provider/schema.ts +30 -0
  378. package/src/engine/provider/sdk/copilot/AGENTS.md +1 -0
  379. package/src/engine/provider/transform.ts +1376 -0
  380. package/src/engine/pty/index.ts +365 -0
  381. package/src/engine/pty/input.ts +24 -0
  382. package/src/engine/pty/pty/index.ts +365 -0
  383. package/src/engine/pty/pty/input.ts +24 -0
  384. package/src/engine/pty/pty/pty.bun.ts +26 -0
  385. package/src/engine/pty/pty/pty.node.ts +27 -0
  386. package/src/engine/pty/pty/pty.ts +25 -0
  387. package/src/engine/pty/pty/schema.ts +14 -0
  388. package/src/engine/pty/pty/ticket.ts +68 -0
  389. package/src/engine/pty/pty.bun.ts +26 -0
  390. package/src/engine/pty/pty.node.ts +27 -0
  391. package/src/engine/pty/pty.ts +25 -0
  392. package/src/engine/pty/schema.ts +14 -0
  393. package/src/engine/pty/ticket.ts +68 -0
  394. package/src/engine/question/index.ts +213 -0
  395. package/src/engine/question/question/index.ts +213 -0
  396. package/src/engine/question/question/schema.ts +10 -0
  397. package/src/engine/question/schema.ts +10 -0
  398. package/src/engine/reference/reference/reference.ts +241 -0
  399. package/src/engine/reference/reference/repository-cache.ts +147 -0
  400. package/src/engine/reference/reference.ts +241 -0
  401. package/src/engine/reference/repository-cache.ts +147 -0
  402. package/src/engine/session/compaction.ts +651 -0
  403. package/src/engine/session/compaction_logic.ts +120 -0
  404. package/src/engine/session/instruction.ts +238 -0
  405. package/src/engine/session/instruction_loader.ts +54 -0
  406. package/src/engine/session/llm.ts +459 -0
  407. package/src/engine/session/message-error.ts +14 -0
  408. package/src/engine/session/message-v2.ts +1202 -0
  409. package/src/engine/session/message.ts +146 -0
  410. package/src/engine/session/overflow.ts +32 -0
  411. package/src/engine/session/overflow_check.ts +46 -0
  412. package/src/engine/session/processor.ts +823 -0
  413. package/src/engine/session/prompt/anthropic.txt +105 -0
  414. package/src/engine/session/prompt/beast.txt +147 -0
  415. package/src/engine/session/prompt/build-switch.txt +5 -0
  416. package/src/engine/session/prompt/codex.txt +79 -0
  417. package/src/engine/session/prompt/copilot-gpt-5.txt +143 -0
  418. package/src/engine/session/prompt/default.txt +105 -0
  419. package/src/engine/session/prompt/gemini.txt +155 -0
  420. package/src/engine/session/prompt/gpt.txt +107 -0
  421. package/src/engine/session/prompt/kimi.txt +95 -0
  422. package/src/engine/session/prompt/max-steps.txt +16 -0
  423. package/src/engine/session/prompt/plan-reminder-anthropic.txt +67 -0
  424. package/src/engine/session/prompt/plan.txt +26 -0
  425. package/src/engine/session/prompt/trinity.txt +97 -0
  426. package/src/engine/session/prompt.ts +671 -0
  427. package/src/engine/session/provider_transform.ts +187 -0
  428. package/src/engine/session/retry.ts +200 -0
  429. package/src/engine/session/retry_logic.ts +65 -0
  430. package/src/engine/session/revert.ts +162 -0
  431. package/src/engine/session/run-state.ts +153 -0
  432. package/src/engine/session/schema.ts +26 -0
  433. package/src/engine/session/session.sql.ts +137 -0
  434. package/src/engine/session/session.ts +1011 -0
  435. package/src/engine/session/status.ts +94 -0
  436. package/src/engine/session/summary.ts +164 -0
  437. package/src/engine/session/system.ts +84 -0
  438. package/src/engine/session/system_prompt.ts +65 -0
  439. package/src/engine/session/todo.ts +81 -0
  440. package/src/engine/session/tool_registry.ts +162 -0
  441. package/src/engine/share/session.ts +61 -0
  442. package/src/engine/share/share-next.ts +376 -0
  443. package/src/engine/share/share.sql.ts +13 -0
  444. package/src/engine/shell/shell/shell.ts +215 -0
  445. package/src/engine/shell/shell.ts +215 -0
  446. package/src/engine/skill/discovery.ts +116 -0
  447. package/src/engine/skill/index.ts +336 -0
  448. package/src/engine/skill/prompt/customize-opencode.md +377 -0
  449. package/src/engine/skill/skill/discovery.ts +116 -0
  450. package/src/engine/skill/skill/index.ts +336 -0
  451. package/src/engine/skill/skill/prompt/customize-opencode.md +377 -0
  452. package/src/engine/snapshot/index.ts +762 -0
  453. package/src/engine/snapshot/snapshot/index.ts +762 -0
  454. package/src/engine/sync/README.md +179 -0
  455. package/src/engine/sync/event.sql.ts +17 -0
  456. package/src/engine/sync/index.ts +410 -0
  457. package/src/engine/sync/schema.ts +11 -0
  458. package/src/engine/temporary.ts +33 -0
  459. package/src/engine/tool/apply_patch.ts +313 -0
  460. package/src/engine/tool/apply_patch.txt +33 -0
  461. package/src/engine/tool/edit.ts +711 -0
  462. package/src/engine/tool/edit.txt +10 -0
  463. package/src/engine/tool/external-directory.ts +49 -0
  464. package/src/engine/tool/glob.ts +103 -0
  465. package/src/engine/tool/glob.txt +6 -0
  466. package/src/engine/tool/grep.ts +156 -0
  467. package/src/engine/tool/grep.txt +8 -0
  468. package/src/engine/tool/invalid.ts +21 -0
  469. package/src/engine/tool/json-schema.ts +164 -0
  470. package/src/engine/tool/lsp.ts +113 -0
  471. package/src/engine/tool/lsp.txt +24 -0
  472. package/src/engine/tool/mcp-websearch.ts +96 -0
  473. package/src/engine/tool/plan-enter.txt +14 -0
  474. package/src/engine/tool/plan-exit.txt +13 -0
  475. package/src/engine/tool/plan.ts +78 -0
  476. package/src/engine/tool/question.ts +44 -0
  477. package/src/engine/tool/question.txt +10 -0
  478. package/src/engine/tool/read.ts +337 -0
  479. package/src/engine/tool/read.txt +14 -0
  480. package/src/engine/tool/registry.ts +472 -0
  481. package/src/engine/tool/repo_clone.ts +80 -0
  482. package/src/engine/tool/repo_clone.txt +5 -0
  483. package/src/engine/tool/repo_overview.ts +279 -0
  484. package/src/engine/tool/repo_overview.txt +4 -0
  485. package/src/engine/tool/schema.ts +14 -0
  486. package/src/engine/tool/shell/id.ts +19 -0
  487. package/src/engine/tool/shell/prompt.ts +295 -0
  488. package/src/engine/tool/shell/shell.txt +77 -0
  489. package/src/engine/tool/shell.ts +647 -0
  490. package/src/engine/tool/skill.ts +75 -0
  491. package/src/engine/tool/skill.txt +5 -0
  492. package/src/engine/tool/task.ts +337 -0
  493. package/src/engine/tool/task.txt +58 -0
  494. package/src/engine/tool/task_status.ts +179 -0
  495. package/src/engine/tool/task_status.txt +13 -0
  496. package/src/engine/tool/todo.ts +57 -0
  497. package/src/engine/tool/todowrite.txt +167 -0
  498. package/src/engine/tool/tool/apply_patch.ts +313 -0
  499. package/src/engine/tool/tool/apply_patch.txt +33 -0
  500. package/src/engine/tool/tool/edit.ts +711 -0
  501. package/src/engine/tool/tool/edit.txt +10 -0
  502. package/src/engine/tool/tool/external-directory.ts +49 -0
  503. package/src/engine/tool/tool/glob.ts +103 -0
  504. package/src/engine/tool/tool/glob.txt +6 -0
  505. package/src/engine/tool/tool/grep.ts +156 -0
  506. package/src/engine/tool/tool/grep.txt +8 -0
  507. package/src/engine/tool/tool/invalid.ts +21 -0
  508. package/src/engine/tool/tool/json-schema.ts +164 -0
  509. package/src/engine/tool/tool/lsp.ts +113 -0
  510. package/src/engine/tool/tool/lsp.txt +24 -0
  511. package/src/engine/tool/tool/mcp-websearch.ts +96 -0
  512. package/src/engine/tool/tool/plan-enter.txt +14 -0
  513. package/src/engine/tool/tool/plan-exit.txt +13 -0
  514. package/src/engine/tool/tool/plan.ts +78 -0
  515. package/src/engine/tool/tool/question.ts +44 -0
  516. package/src/engine/tool/tool/question.txt +10 -0
  517. package/src/engine/tool/tool/read.ts +337 -0
  518. package/src/engine/tool/tool/read.txt +14 -0
  519. package/src/engine/tool/tool/registry.ts +472 -0
  520. package/src/engine/tool/tool/repo_clone.ts +80 -0
  521. package/src/engine/tool/tool/repo_clone.txt +5 -0
  522. package/src/engine/tool/tool/repo_overview.ts +279 -0
  523. package/src/engine/tool/tool/repo_overview.txt +4 -0
  524. package/src/engine/tool/tool/schema.ts +14 -0
  525. package/src/engine/tool/tool/shell/id.ts +19 -0
  526. package/src/engine/tool/tool/shell/prompt.ts +295 -0
  527. package/src/engine/tool/tool/shell/shell.txt +77 -0
  528. package/src/engine/tool/tool/shell.ts +647 -0
  529. package/src/engine/tool/tool/skill.ts +75 -0
  530. package/src/engine/tool/tool/skill.txt +5 -0
  531. package/src/engine/tool/tool/task.ts +337 -0
  532. package/src/engine/tool/tool/task.txt +58 -0
  533. package/src/engine/tool/tool/task_status.ts +179 -0
  534. package/src/engine/tool/tool/task_status.txt +13 -0
  535. package/src/engine/tool/tool/todo.ts +57 -0
  536. package/src/engine/tool/tool/todowrite.txt +167 -0
  537. package/src/engine/tool/tool/tool.ts +164 -0
  538. package/src/engine/tool/tool/truncate.ts +160 -0
  539. package/src/engine/tool/tool/truncation-dir.ts +4 -0
  540. package/src/engine/tool/tool/webfetch.ts +192 -0
  541. package/src/engine/tool/tool/webfetch.txt +13 -0
  542. package/src/engine/tool/tool/websearch.ts +143 -0
  543. package/src/engine/tool/tool/websearch.txt +14 -0
  544. package/src/engine/tool/tool/write.ts +104 -0
  545. package/src/engine/tool/tool/write.txt +8 -0
  546. package/src/engine/tool/tool.ts +164 -0
  547. package/src/engine/tool/truncate.ts +160 -0
  548. package/src/engine/tool/truncation-dir.ts +4 -0
  549. package/src/engine/tool/webfetch.ts +192 -0
  550. package/src/engine/tool/webfetch.txt +13 -0
  551. package/src/engine/tool/websearch.ts +143 -0
  552. package/src/engine/tool/websearch.txt +14 -0
  553. package/src/engine/tool/write.ts +104 -0
  554. package/src/engine/tool/write.txt +8 -0
  555. package/src/engine/util/archive.ts +17 -0
  556. package/src/engine/util/bom.ts +31 -0
  557. package/src/engine/util/data-url.ts +9 -0
  558. package/src/engine/util/defer.ts +10 -0
  559. package/src/engine/util/effect-http-client.ts +11 -0
  560. package/src/engine/util/error.ts +88 -0
  561. package/src/engine/util/filesystem.ts +252 -0
  562. package/src/engine/util/format.ts +20 -0
  563. package/src/engine/util/iife.ts +3 -0
  564. package/src/engine/util/lazy.ts +20 -0
  565. package/src/engine/util/local-context.ts +25 -0
  566. package/src/engine/util/locale.ts +86 -0
  567. package/src/engine/util/media.ts +26 -0
  568. package/src/engine/util/process.ts +176 -0
  569. package/src/engine/util/queue.ts +32 -0
  570. package/src/engine/util/record.ts +3 -0
  571. package/src/engine/util/repository.ts +158 -0
  572. package/src/engine/util/rpc.ts +66 -0
  573. package/src/engine/util/signal.ts +12 -0
  574. package/src/engine/util/timeout.ts +13 -0
  575. package/src/engine/util/token.ts +7 -0
  576. package/src/engine/util/util/archive.ts +17 -0
  577. package/src/engine/util/util/bom.ts +31 -0
  578. package/src/engine/util/util/data-url.ts +9 -0
  579. package/src/engine/util/util/defer.ts +10 -0
  580. package/src/engine/util/util/effect-http-client.ts +11 -0
  581. package/src/engine/util/util/error.ts +88 -0
  582. package/src/engine/util/util/filesystem.ts +252 -0
  583. package/src/engine/util/util/format.ts +20 -0
  584. package/src/engine/util/util/iife.ts +3 -0
  585. package/src/engine/util/util/lazy.ts +20 -0
  586. package/src/engine/util/util/local-context.ts +25 -0
  587. package/src/engine/util/util/locale.ts +86 -0
  588. package/src/engine/util/util/media.ts +26 -0
  589. package/src/engine/util/util/process.ts +176 -0
  590. package/src/engine/util/util/queue.ts +32 -0
  591. package/src/engine/util/util/record.ts +3 -0
  592. package/src/engine/util/util/repository.ts +158 -0
  593. package/src/engine/util/util/rpc.ts +66 -0
  594. package/src/engine/util/util/signal.ts +12 -0
  595. package/src/engine/util/util/timeout.ts +13 -0
  596. package/src/engine/util/util/token.ts +7 -0
  597. package/src/engine/util/util/which.ts +14 -0
  598. package/src/engine/util/util/wildcard.ts +59 -0
  599. package/src/engine/util/which.ts +14 -0
  600. package/src/engine/util/wildcard.ts +59 -0
  601. package/src/engine/worktree/index.ts +621 -0
  602. package/src/rag_worker.ts +519 -0
  603. package/src/server.ts +201 -0
  604. package/src/tui.ts +637 -0
  605. package/tsconfig.json +24 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Provider message transforms — thin re-export wrapper.
3
+ *
4
+ * The full transform logic lives in the copied OpenCode file at
5
+ * src/engine/provider/transform.ts. However, that file uses Effect.js
6
+ * types and imports. This wrapper extracts the pure functions we need
7
+ * (message normalization, temperature, topP, topK) and re-exports them
8
+ * with plain TypeScript signatures.
9
+ *
10
+ * For the full provider-specific transforms (Anthropic tool ID scrubbing,
11
+ * Mistral 9-char IDs, DeepSeek reasoning injection, prompt caching, etc.)
12
+ * we call the copied functions directly where possible, or inline the
13
+ * critical transforms here.
14
+ */
15
+
16
+
17
+ // ─── Temperature / sampling defaults (from OpenCode's transform.ts) ───────────
18
+
19
+ export function temperature(model: { id: string; providerID?: string }): number | undefined {
20
+ const id = model.id.toLowerCase();
21
+ if (id.includes("qwen")) return 0.55;
22
+ if (id.includes("claude")) return undefined;
23
+ if (id.includes("gemini")) return 1.0;
24
+ if (id.includes("glm-4.6") || id.includes("glm-4.7")) return 1.0;
25
+ if (id.includes("minimax-m2")) return 1.0;
26
+ if (id.includes("kimi-k2")) {
27
+ if (["thinking", "k2.", "k2p", "k2-5"].some(s => id.includes(s))) return 1.0;
28
+ return 0.6;
29
+ }
30
+ return undefined;
31
+ }
32
+
33
+ export function topP(model: { id: string }): number | undefined {
34
+ const id = model.id.toLowerCase();
35
+ if (id.includes("qwen")) return 1;
36
+ if (["minimax-m2", "gemini", "kimi-k2.5", "kimi-k2p5", "kimi-k2-5"].some(s => id.includes(s))) return 0.95;
37
+ return undefined;
38
+ }
39
+
40
+ export function topK(model: { id: string }): number | undefined {
41
+ const id = model.id.toLowerCase();
42
+ if (id.includes("minimax-m2")) return id.includes("m2.") || id.includes("m25") || id.includes("m21") ? 40 : 20;
43
+ if (id.includes("gemini")) return 64;
44
+ return undefined;
45
+ }
46
+
47
+ export const OUTPUT_TOKEN_MAX = 32_000;
48
+
49
+ export function maxOutputTokens(model: { id: string; limit?: { output?: number } }, outputTokenMax?: number): number {
50
+ const cap = outputTokenMax ?? OUTPUT_TOKEN_MAX;
51
+ return model.limit?.output ? Math.min(model.limit.output, cap) : cap;
52
+ }
53
+
54
+ // ─── Message normalization ────────────────────────────────────────────────────
55
+ // Critical transforms ported from OpenCode's transform.ts normalizeMessages()
56
+
57
+ function sanitizeSurrogates(content: string): string {
58
+ return content.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD");
59
+ }
60
+
61
+ export function message(
62
+ msgs: any[],
63
+ model: { id: string; providerID: string; api?: { npm?: string } },
64
+ _options: Record<string, unknown>
65
+ ): any[] {
66
+ const npm = model.api?.npm || "";
67
+ const id = model.id.toLowerCase();
68
+
69
+ // 1. Sanitize surrogates in all text content
70
+ msgs = msgs.map((msg: any) => {
71
+ if (msg.role === "system") {
72
+ return { ...msg, content: sanitizeSurrogates(msg.content) };
73
+ }
74
+ if (msg.role === "user") {
75
+ if (typeof msg.content === "string") return { ...msg, content: sanitizeSurrogates(msg.content) };
76
+ return { ...msg, content: (msg.content as any[]).map(p => p.type === "text" ? { ...p, text: sanitizeSurrogates(p.text) } : p) };
77
+ }
78
+ if (msg.role === "assistant") {
79
+ if (typeof msg.content === "string") return { ...msg, content: sanitizeSurrogates(msg.content) };
80
+ return { ...msg, content: (msg.content as any[]).map(p => (p.type === "text" || p.type === "reasoning") ? { ...p, text: sanitizeSurrogates(p.text) } : p) };
81
+ }
82
+ return msg;
83
+ });
84
+
85
+ // 2. Anthropic: filter empty content, scrub tool IDs to [a-zA-Z0-9_-]
86
+ if (npm === "@ai-sdk/anthropic" || id.includes("claude")) {
87
+ const scrub = (id: string) => id.replace(/[^a-zA-Z0-9_-]/g, "_");
88
+ msgs = msgs
89
+ .map(msg => {
90
+ if (typeof msg.content === "string") {
91
+ return msg.content === "" ? undefined : msg;
92
+ }
93
+ if (!Array.isArray(msg.content)) return msg;
94
+ const filtered = (msg.content as any[]).filter(p => {
95
+ if (p.type === "text") return p.text !== "";
96
+ if (p.type === "reasoning") return p.text?.trim().length > 0 || p.providerOptions?.anthropic?.signature != null;
97
+ return true;
98
+ });
99
+ return filtered.length === 0 ? undefined : { ...msg, content: filtered };
100
+ })
101
+ .filter((m: any): m is any => m !== undefined);
102
+
103
+ // Scrub tool call IDs
104
+ msgs = msgs.map((msg: any) => {
105
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
106
+ return { ...msg, content: (msg.content as any[]).map(p => (p.type === "tool-call" || p.type === "tool-result") ? { ...p, toolCallId: scrub(p.toolCallId) } : p) };
107
+ }
108
+ if (msg.role === "tool" && Array.isArray(msg.content)) {
109
+ return { ...msg, content: (msg.content as any[]).map(p => p.type === "tool-result" ? { ...p, toolCallId: scrub(p.toolCallId) } : p) };
110
+ }
111
+ return msg;
112
+ });
113
+
114
+ // Reorder: tool_use blocks must not be followed by text in same assistant message
115
+ msgs = msgs.flatMap((msg: any) => {
116
+ if (msg.role !== "assistant" || !Array.isArray(msg.content)) return [msg];
117
+ const parts = msg.content as any[];
118
+ const first = parts.findIndex(p => p.type === "tool-call");
119
+ if (first === -1) return [msg];
120
+ if (!parts.slice(first).some(p => p.type !== "tool-call")) return [msg];
121
+ return [
122
+ { ...msg, content: parts.filter(p => p.type !== "tool-call") },
123
+ { ...msg, content: parts.filter(p => p.type === "tool-call") },
124
+ ];
125
+ });
126
+ }
127
+
128
+ // 3. Mistral: 9-char alphanumeric tool IDs, fix tool→user sequence
129
+ if (model.providerID === "mistral" || id.includes("mistral") || id.includes("devstral")) {
130
+ const scrub = (id: string) => id.replace(/[^a-zA-Z0-9]/g, "").substring(0, 9).padEnd(9, "0");
131
+ const result: any[] = [];
132
+ for (let i = 0; i < msgs.length; i++) {
133
+ const msg = msgs[i];
134
+ const next = msgs[i + 1];
135
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
136
+ (msg as any).content = (msg.content as any[]).map(p => (p.type === "tool-call" || p.type === "tool-result") ? { ...p, toolCallId: scrub(p.toolCallId) } : p);
137
+ }
138
+ if (msg.role === "tool" && Array.isArray(msg.content)) {
139
+ (msg as any).content = (msg.content as any[]).map(p => p.type === "tool-result" ? { ...p, toolCallId: scrub(p.toolCallId) } : p);
140
+ }
141
+ result.push(msg);
142
+ if (msg.role === "tool" && next?.role === "user") {
143
+ result.push({ role: "assistant", content: [{ type: "text", text: "Done." }] });
144
+ }
145
+ }
146
+ return result;
147
+ }
148
+
149
+ // 4. DeepSeek: inject empty reasoning on all assistant messages
150
+ if (id.includes("deepseek")) {
151
+ msgs = msgs.map((msg: any) => {
152
+ if (msg.role !== "assistant") return msg;
153
+ if (Array.isArray(msg.content)) {
154
+ if ((msg.content as any[]).some(p => p.type === "reasoning")) return msg;
155
+ return { ...msg, content: [...(msg.content as any[]), { type: "reasoning", text: "" }] };
156
+ }
157
+ return { ...msg, content: [{ type: "text", text: msg.content || "" }, { type: "reasoning", text: "" }] };
158
+ });
159
+ }
160
+
161
+ return msgs;
162
+ }
163
+
164
+ // ─── Provider options (prompt caching, etc.) ──────────────────────────────────
165
+
166
+ export function providerOptions(model: { id: string; providerID: string; api?: { npm?: string } }, options: Record<string, any>): Record<string, any> {
167
+ const npm = model.api?.npm || "";
168
+ const id = model.id.toLowerCase();
169
+
170
+ // Anthropic prompt caching
171
+ if (npm === "@ai-sdk/anthropic" || id.includes("claude")) {
172
+ return { ...options, anthropic: { ...options.anthropic } };
173
+ }
174
+ return options;
175
+ }
176
+
177
+ export function smallOptions(model: { id: string }): Record<string, any> {
178
+ return {};
179
+ }
180
+
181
+ export function options(input: { model: { id: string; providerID: string }; sessionID: string; providerOptions?: Record<string, any> }): Record<string, any> {
182
+ return input.providerOptions || {};
183
+ }
184
+
185
+ export function schema(model: { id: string }, jsonSchema: any): any {
186
+ return jsonSchema;
187
+ }
@@ -0,0 +1,200 @@
1
+ import type { NamedError } from "@opencode-ai/core/util/error"
2
+ import { Cause, Clock, Duration, Effect, Schedule } from "effect"
3
+ import { MessageV2 } from "./message-v2"
4
+ import { iife } from "@/util/iife"
5
+ import { isRecord } from "@/util/record"
6
+
7
+ export type Err = ReturnType<NamedError["toObject"]>
8
+
9
+ export const GO_UPSELL_MESSAGE = "Free usage exceeded, subscribe to Go"
10
+ export const GO_UPSELL_URL = "https://opencode.ai/go"
11
+ export type RetryReason = "free_tier_limit" | "account_rate_limit" | (string & {})
12
+
13
+ export type Retryable = {
14
+ message: string
15
+ action?: {
16
+ reason: RetryReason
17
+ provider: string
18
+ title: string
19
+ message: string
20
+ label: string
21
+ link?: string
22
+ }
23
+ }
24
+
25
+ export const RETRY_INITIAL_DELAY = 2000
26
+ export const RETRY_BACKOFF_FACTOR = 2
27
+ export const RETRY_MAX_DELAY_NO_HEADERS = 30_000 // 30 seconds
28
+ export const RETRY_MAX_DELAY = 2_147_483_647 // max 32-bit signed integer for setTimeout
29
+
30
+ function cap(ms: number) {
31
+ return Math.min(ms, RETRY_MAX_DELAY)
32
+ }
33
+
34
+ export function delay(attempt: number, error?: MessageV2.APIError) {
35
+ if (error) {
36
+ const headers = error.data.responseHeaders
37
+ if (headers) {
38
+ const retryAfterMs = headers["retry-after-ms"]
39
+ if (retryAfterMs) {
40
+ const parsedMs = Number.parseFloat(retryAfterMs)
41
+ if (!Number.isNaN(parsedMs)) {
42
+ return cap(parsedMs)
43
+ }
44
+ }
45
+
46
+ const retryAfter = headers["retry-after"]
47
+ if (retryAfter) {
48
+ const parsedSeconds = Number.parseFloat(retryAfter)
49
+ if (!Number.isNaN(parsedSeconds)) {
50
+ // convert seconds to milliseconds
51
+ return cap(Math.ceil(parsedSeconds * 1000))
52
+ }
53
+ // Try parsing as HTTP date format
54
+ const parsed = Date.parse(retryAfter) - Date.now()
55
+ if (!Number.isNaN(parsed) && parsed > 0) {
56
+ return cap(Math.ceil(parsed))
57
+ }
58
+ }
59
+
60
+ return cap(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1))
61
+ }
62
+ }
63
+
64
+ return cap(Math.min(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1), RETRY_MAX_DELAY_NO_HEADERS))
65
+ }
66
+
67
+ export function retryable(error: Err, provider: string) {
68
+ // context overflow errors should not be retried
69
+ if (MessageV2.ContextOverflowError.isInstance(error)) return undefined
70
+ if (MessageV2.APIError.isInstance(error)) {
71
+ const status = error.data.statusCode
72
+ // 5xx errors are transient server failures and should always be retried,
73
+ // even when the provider SDK doesn't explicitly mark them as retryable.
74
+ if (!error.data.isRetryable && !(status !== undefined && status >= 500)) return undefined
75
+ if (error.data.responseBody?.includes("FreeUsageLimitError")) {
76
+ return {
77
+ message: GO_UPSELL_MESSAGE,
78
+ action: {
79
+ reason: "free_tier_limit",
80
+ provider,
81
+ title: "Free limit reached",
82
+ message: "Subscribe to OpenCode Go for reliable access to the best open-source models, starting at $5/month.",
83
+ label: "subscribe",
84
+ link: GO_UPSELL_URL,
85
+ },
86
+ }
87
+ }
88
+ if (error.data.responseBody?.includes("GoUsageLimitError")) {
89
+ const body = parseJSON(error.data.responseBody)
90
+ const workspace = str(body?.metadata?.workspace)
91
+ const limitName = str(body?.metadata?.limitName)
92
+ const retryAfter = num(error.data.responseHeaders?.["retry-after"])
93
+ const resetIn = iife(() => {
94
+ if (retryAfter === undefined) return ""
95
+ const seconds = Math.max(0, Math.ceil(retryAfter))
96
+ const days = Math.floor(seconds / 86_400)
97
+ const hours = Math.floor((seconds % 86_400) / 3_600)
98
+ const minutes = Math.ceil((seconds % 3_600) / 60)
99
+ const unit = (value: number, name: string) => `${value} ${name}${value === 1 ? "" : "s"}`
100
+
101
+ if (days > 0) return hours > 0 ? `${unit(days, "day")} ${unit(hours, "hour")}` : unit(days, "day")
102
+ if (hours > 0) return minutes > 0 ? `${unit(hours, "hour")} ${unit(minutes, "minute")}` : unit(hours, "hour")
103
+ return minutes > 0 ? unit(minutes, "minute") : "less than a minute"
104
+ })
105
+
106
+ const message = `${limitName ? `${limitName} usage limit` : "Usage limit"} reached. It will reset in ${resetIn}. To continue using this model now, enable usage from your available balance`
107
+
108
+ const link = `https://opencode.ai/workspace/${workspace}/go`
109
+ return {
110
+ message: `${message} - ${link}`,
111
+ action: {
112
+ reason: "account_rate_limit",
113
+ provider,
114
+ title: "Go limit reached",
115
+ message,
116
+ label: "open settings",
117
+ link,
118
+ },
119
+ }
120
+ }
121
+ return { message: error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message }
122
+ }
123
+
124
+ // Check for rate limit patterns in plain text error messages
125
+ const msg = isRecord(error.data) ? error.data.message : undefined
126
+ if (typeof msg === "string") {
127
+ const lower = msg.toLowerCase()
128
+ if (
129
+ lower.includes("rate increased too quickly") ||
130
+ lower.includes("rate limit") ||
131
+ lower.includes("too many requests")
132
+ ) {
133
+ return { message: msg }
134
+ }
135
+ }
136
+
137
+ const json = parseJSON(msg)
138
+ if (!json || typeof json !== "object") return undefined
139
+ const code = typeof json.code === "string" ? json.code : ""
140
+
141
+ if (json.type === "error" && json.error?.type === "too_many_requests") {
142
+ return { message: "Too Many Requests" }
143
+ }
144
+ if (code.includes("exhausted") || code.includes("unavailable")) {
145
+ return { message: "Provider is overloaded" }
146
+ }
147
+ if (json.type === "error" && typeof json.error?.code === "string" && json.error.code.includes("rate_limit")) {
148
+ return { message: "Rate Limited" }
149
+ }
150
+ return undefined
151
+ }
152
+
153
+ function str(value: unknown) {
154
+ if (value === undefined || value === null) return ""
155
+ return String(value)
156
+ }
157
+
158
+ function num(value: unknown) {
159
+ const parsed = Number.parseFloat(str(value))
160
+ if (Number.isNaN(parsed)) return undefined
161
+ return parsed
162
+ }
163
+
164
+ function parseJSON(value: unknown) {
165
+ return iife(() => {
166
+ try {
167
+ if (typeof value !== "string") return undefined
168
+ return JSON.parse(value)
169
+ } catch {
170
+ return undefined
171
+ }
172
+ })
173
+ }
174
+
175
+ export function policy(opts: {
176
+ provider: string
177
+ parse: (error: unknown) => Err
178
+ set: (input: { attempt: number; message: string; action?: Retryable["action"]; next: number }) => Effect.Effect<void>
179
+ }) {
180
+ return Schedule.fromStepWithMetadata(
181
+ Effect.succeed((meta: Schedule.InputMetadata<unknown>) => {
182
+ const error = opts.parse(meta.input)
183
+ const retry = retryable(error, opts.provider)
184
+ if (!retry) return Cause.done(meta.attempt)
185
+ return Effect.gen(function* () {
186
+ const wait = delay(meta.attempt, MessageV2.APIError.isInstance(error) ? error : undefined)
187
+ const now = yield* Clock.currentTimeMillis
188
+ yield* opts.set({
189
+ attempt: meta.attempt,
190
+ message: retry.message,
191
+ action: retry.action,
192
+ next: now + wait,
193
+ })
194
+ return [meta.attempt, Duration.millis(wait)] as [number, Duration.Duration]
195
+ })
196
+ }),
197
+ )
198
+ }
199
+
200
+ export * as SessionRetry from "./retry"
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Retry logic — pure port from OpenCode's session/retry.ts
3
+ * No Effect.js dependency. Same algorithm, plain TypeScript.
4
+ */
5
+
6
+ export const RETRY_INITIAL_DELAY = 2000;
7
+ export const RETRY_BACKOFF_FACTOR = 2;
8
+ export const RETRY_MAX_DELAY_NO_HEADERS = 30_000;
9
+ export const RETRY_MAX_DELAY = 2_147_483_647;
10
+
11
+ function cap(ms: number) {
12
+ return Math.min(ms, RETRY_MAX_DELAY);
13
+ }
14
+
15
+ export function delay(attempt: number, error?: any): number {
16
+ if (error) {
17
+ const headers = error?.data?.responseHeaders || error?.responseHeaders;
18
+ if (headers) {
19
+ const retryAfterMs = headers["retry-after-ms"];
20
+ if (retryAfterMs) {
21
+ const parsed = Number.parseFloat(retryAfterMs);
22
+ if (!Number.isNaN(parsed)) return cap(parsed);
23
+ }
24
+ const retryAfter = headers["retry-after"];
25
+ if (retryAfter) {
26
+ const parsedSeconds = Number.parseFloat(retryAfter);
27
+ if (!Number.isNaN(parsedSeconds)) return cap(Math.ceil(parsedSeconds * 1000));
28
+ const parsed = Date.parse(retryAfter) - Date.now();
29
+ if (!Number.isNaN(parsed) && parsed > 0) return cap(Math.ceil(parsed));
30
+ }
31
+ return cap(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1));
32
+ }
33
+ }
34
+ return cap(Math.min(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1), RETRY_MAX_DELAY_NO_HEADERS));
35
+ }
36
+
37
+ export function retryable(error: any, provider: string): { message: string } | undefined {
38
+ // Context overflow — never retry, triggers compaction instead
39
+ if (error?.name === "ContextOverflowError" || error?.message?.includes("context_length_exceeded")) return undefined;
40
+
41
+ const status = error?.status || error?.statusCode || error?.data?.statusCode;
42
+ const isRetryable = error?.data?.isRetryable;
43
+
44
+ // 5xx always retried
45
+ if (status !== undefined && status >= 500) return { message: `Server error ${status}` };
46
+ if (!isRetryable && status !== undefined && status < 500) return undefined;
47
+
48
+ const msg = error?.message || error?.data?.message || "";
49
+ const lower = msg.toLowerCase();
50
+
51
+ if (lower.includes("rate limit") || lower.includes("too many requests") || lower.includes("rate increased too quickly")) {
52
+ return { message: msg };
53
+ }
54
+ if (lower.includes("overloaded")) return { message: "Provider is overloaded" };
55
+ if (lower.includes("exhausted") || lower.includes("unavailable")) return { message: "Provider is overloaded" };
56
+
57
+ // Check JSON body
58
+ try {
59
+ const body = typeof error?.data?.responseBody === "string" ? JSON.parse(error.data.responseBody) : null;
60
+ if (body?.type === "error" && body?.error?.type === "too_many_requests") return { message: "Too Many Requests" };
61
+ if (body?.error?.code?.includes("rate_limit")) return { message: "Rate Limited" };
62
+ } catch {}
63
+
64
+ return undefined;
65
+ }
@@ -0,0 +1,162 @@
1
+ import { Effect, Layer, Context, Schema } from "effect"
2
+ import { Bus } from "../bus"
3
+ import { Snapshot } from "../snapshot"
4
+ import { Storage } from "@/storage/storage"
5
+ import { SyncEvent } from "../sync"
6
+ import * as Log from "@opencode-ai/core/util/log"
7
+ import * as Session from "./session"
8
+ import { MessageV2 } from "./message-v2"
9
+ import { SessionID, MessageID, PartID } from "./schema"
10
+ import { SessionRunState } from "./run-state"
11
+ import { SessionSummary } from "./summary"
12
+
13
+ const log = Log.create({ service: "session.revert" })
14
+
15
+ export const RevertInput = Schema.Struct({
16
+ sessionID: SessionID,
17
+ messageID: MessageID,
18
+ partID: Schema.optional(PartID),
19
+ })
20
+ export type RevertInput = Schema.Schema.Type<typeof RevertInput>
21
+
22
+ export interface Interface {
23
+ readonly revert: (input: RevertInput) => Effect.Effect<Session.Info, Session.BusyError>
24
+ readonly unrevert: (input: { sessionID: SessionID }) => Effect.Effect<Session.Info, Session.BusyError>
25
+ readonly cleanup: (session: Session.Info) => Effect.Effect<void>
26
+ }
27
+
28
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionRevert") {}
29
+
30
+ export const layer = Layer.effect(
31
+ Service,
32
+ Effect.gen(function* () {
33
+ const sessions = yield* Session.Service
34
+ const snap = yield* Snapshot.Service
35
+ const storage = yield* Storage.Service
36
+ const bus = yield* Bus.Service
37
+ const summary = yield* SessionSummary.Service
38
+ const state = yield* SessionRunState.Service
39
+ const sync = yield* SyncEvent.Service
40
+
41
+ const revert = Effect.fn("SessionRevert.revert")(function* (input: RevertInput) {
42
+ yield* state.assertNotBusy(input.sessionID)
43
+ const all = yield* sessions.messages({ sessionID: input.sessionID }).pipe(Effect.orDie)
44
+ let lastUser: MessageV2.User | undefined
45
+ const session = yield* sessions.get(input.sessionID).pipe(Effect.orDie)
46
+
47
+ let rev: Session.Info["revert"]
48
+ const patches: Snapshot.Patch[] = []
49
+ for (const msg of all) {
50
+ if (msg.info.role === "user") lastUser = msg.info
51
+ const remaining = []
52
+ for (const part of msg.parts) {
53
+ if (rev) {
54
+ if (part.type === "patch") patches.push(part)
55
+ continue
56
+ }
57
+
58
+ if (!rev) {
59
+ if ((msg.info.id === input.messageID && !input.partID) || part.id === input.partID) {
60
+ const partID = remaining.some((item) => ["text", "tool"].includes(item.type)) ? input.partID : undefined
61
+ rev = {
62
+ messageID: !partID && lastUser ? lastUser.id : msg.info.id,
63
+ partID,
64
+ }
65
+ }
66
+ remaining.push(part)
67
+ }
68
+ }
69
+ }
70
+
71
+ if (!rev) return session
72
+
73
+ rev.snapshot = session.revert?.snapshot ?? (yield* snap.track())
74
+ if (session.revert?.snapshot) yield* snap.restore(session.revert.snapshot)
75
+ yield* snap.revert(patches)
76
+ if (rev.snapshot) rev.diff = yield* snap.diff(rev.snapshot)
77
+ const range = all.filter((msg) => msg.info.id >= rev.messageID)
78
+ const diffs = yield* summary.computeDiff({ messages: range })
79
+ yield* storage.write(["session_diff", input.sessionID], diffs).pipe(Effect.ignore)
80
+ yield* bus.publish(Session.Event.Diff, { sessionID: input.sessionID, diff: diffs })
81
+ yield* sessions.setRevert({
82
+ sessionID: input.sessionID,
83
+ revert: rev,
84
+ summary: {
85
+ additions: diffs.reduce((sum, x) => sum + x.additions, 0),
86
+ deletions: diffs.reduce((sum, x) => sum + x.deletions, 0),
87
+ files: diffs.length,
88
+ },
89
+ })
90
+ return yield* sessions.get(input.sessionID).pipe(Effect.orDie)
91
+ })
92
+
93
+ const unrevert = Effect.fn("SessionRevert.unrevert")(function* (input: { sessionID: SessionID }) {
94
+ log.info("unreverting", input)
95
+ yield* state.assertNotBusy(input.sessionID)
96
+ const session = yield* sessions.get(input.sessionID).pipe(Effect.orDie)
97
+ if (!session.revert) return session
98
+ if (session.revert.snapshot) yield* snap.restore(session.revert.snapshot)
99
+ yield* sessions.clearRevert(input.sessionID)
100
+ return yield* sessions.get(input.sessionID).pipe(Effect.orDie)
101
+ })
102
+
103
+ const cleanup = Effect.fn("SessionRevert.cleanup")(function* (session: Session.Info) {
104
+ if (!session.revert) return
105
+ const sessionID = session.id
106
+ const msgs = yield* sessions.messages({ sessionID }).pipe(Effect.orDie)
107
+ const messageID = session.revert.messageID
108
+ const remove = [] as MessageV2.WithParts[]
109
+ let target: MessageV2.WithParts | undefined
110
+ for (const msg of msgs) {
111
+ if (msg.info.id < messageID) continue
112
+ if (msg.info.id > messageID) {
113
+ remove.push(msg)
114
+ continue
115
+ }
116
+ if (session.revert.partID) {
117
+ target = msg
118
+ continue
119
+ }
120
+ remove.push(msg)
121
+ }
122
+ for (const msg of remove) {
123
+ yield* sync.run(MessageV2.Event.Removed, {
124
+ sessionID,
125
+ messageID: msg.info.id,
126
+ })
127
+ }
128
+ if (session.revert.partID && target) {
129
+ const partID = session.revert.partID
130
+ const idx = target.parts.findIndex((part) => part.id === partID)
131
+ if (idx >= 0) {
132
+ const removeParts = target.parts.slice(idx)
133
+ target.parts = target.parts.slice(0, idx)
134
+ for (const part of removeParts) {
135
+ yield* sync.run(MessageV2.Event.PartRemoved, {
136
+ sessionID,
137
+ messageID: target.info.id,
138
+ partID: part.id,
139
+ })
140
+ }
141
+ }
142
+ }
143
+ yield* sessions.clearRevert(sessionID)
144
+ })
145
+
146
+ return Service.of({ revert, unrevert, cleanup })
147
+ }),
148
+ )
149
+
150
+ export const defaultLayer = Layer.suspend(() =>
151
+ layer.pipe(
152
+ Layer.provide(SessionRunState.defaultLayer),
153
+ Layer.provide(Session.defaultLayer),
154
+ Layer.provide(Snapshot.defaultLayer),
155
+ Layer.provide(Storage.defaultLayer),
156
+ Layer.provide(Bus.layer),
157
+ Layer.provide(SessionSummary.defaultLayer),
158
+ Layer.provide(SyncEvent.defaultLayer),
159
+ ),
160
+ )
161
+
162
+ export * as SessionRevert from "./revert"