@farhanic017/octocode 3.5.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 (716) hide show
  1. package/.swarm_lessons.json +85 -0
  2. package/AGENTS.md +151 -0
  3. package/BUN_SHELL_MIGRATION_PLAN.md +136 -0
  4. package/Dockerfile +18 -0
  5. package/README.md +15 -0
  6. package/bin/octocode +31 -0
  7. package/bunfig.toml +7 -0
  8. package/git +0 -0
  9. package/package.json +151 -0
  10. package/parsers-config.ts +1 -0
  11. package/script/bench-search.ts +115 -0
  12. package/script/bench-test-suite.ts +52 -0
  13. package/script/build.ts +243 -0
  14. package/script/generate.ts +14 -0
  15. package/script/httpapi-exercise.ts +1 -0
  16. package/script/octo-shim.mjs +34 -0
  17. package/script/postinstall.mjs +198 -0
  18. package/script/profile-test-files.ts +42 -0
  19. package/script/publish.ts +211 -0
  20. package/script/run-workspace-server +106 -0
  21. package/script/schema.ts +77 -0
  22. package/script/time.ts +6 -0
  23. package/script/trace-imports.ts +154 -0
  24. package/specs/effect/error-boundaries-plan.md +235 -0
  25. package/specs/effect/errors.md +207 -0
  26. package/specs/effect/facades.md +218 -0
  27. package/specs/effect/guide.md +247 -0
  28. package/specs/effect/instance-context.md +13 -0
  29. package/specs/effect/loose-ends.md +30 -0
  30. package/specs/effect/migration.md +62 -0
  31. package/specs/effect/routes.md +61 -0
  32. package/specs/effect/schema.md +88 -0
  33. package/specs/effect/server-package.md +58 -0
  34. package/specs/effect/todo.md +241 -0
  35. package/specs/effect/tools.md +88 -0
  36. package/specs/openapi-translation-cleanup.md +204 -0
  37. package/specs/tui-plugins.md +544 -0
  38. package/specs/v2/api.ts +67 -0
  39. package/specs/v2/message-shape.md +136 -0
  40. package/specs/v2/notifications.md +13 -0
  41. package/specs/v2/tui-command-shim.md +67 -0
  42. package/src/account/account.ts +459 -0
  43. package/src/account/repo.ts +170 -0
  44. package/src/account/schema.ts +99 -0
  45. package/src/account/url.ts +8 -0
  46. package/src/acp/agent.ts +95 -0
  47. package/src/acp/config-option.ts +203 -0
  48. package/src/acp/content.ts +250 -0
  49. package/src/acp/directory.ts +210 -0
  50. package/src/acp/error.ts +90 -0
  51. package/src/acp/event.ts +345 -0
  52. package/src/acp/permission.ts +145 -0
  53. package/src/acp/profile.ts +42 -0
  54. package/src/acp/service.ts +1062 -0
  55. package/src/acp/tool.ts +321 -0
  56. package/src/acp/usage.ts +239 -0
  57. package/src/agent/agent.ts +451 -0
  58. package/src/agent/generate.txt +75 -0
  59. package/src/agent/prompt/compaction.txt +30 -0
  60. package/src/agent/prompt/explore.txt +18 -0
  61. package/src/agent/prompt/summary.txt +11 -0
  62. package/src/agent/prompt/title.txt +50 -0
  63. package/src/agent/subagent-permissions.ts +35 -0
  64. package/src/audio.d.ts +14 -0
  65. package/src/auth/index.ts +96 -0
  66. package/src/background/job.ts +36 -0
  67. package/src/bus/global.ts +22 -0
  68. package/src/cli/bootstrap.ts +11 -0
  69. package/src/cli/cmd/account.ts +264 -0
  70. package/src/cli/cmd/acp.ts +76 -0
  71. package/src/cli/cmd/agent.ts +259 -0
  72. package/src/cli/cmd/attach.ts +97 -0
  73. package/src/cli/cmd/cmd.ts +7 -0
  74. package/src/cli/cmd/db.ts +62 -0
  75. package/src/cli/cmd/debug/agent.handler.ts +188 -0
  76. package/src/cli/cmd/debug/agent.ts +27 -0
  77. package/src/cli/cmd/debug/config.ts +14 -0
  78. package/src/cli/cmd/debug/file.ts +87 -0
  79. package/src/cli/cmd/debug/index.ts +87 -0
  80. package/src/cli/cmd/debug/lsp.ts +51 -0
  81. package/src/cli/cmd/debug/ripgrep.ts +99 -0
  82. package/src/cli/cmd/debug/scrap.ts +18 -0
  83. package/src/cli/cmd/debug/skill.ts +15 -0
  84. package/src/cli/cmd/debug/snapshot.ts +50 -0
  85. package/src/cli/cmd/debug/startup.ts +11 -0
  86. package/src/cli/cmd/debug/v2.ts +46 -0
  87. package/src/cli/cmd/export.ts +292 -0
  88. package/src/cli/cmd/generate.ts +54 -0
  89. package/src/cli/cmd/github.handler.ts +1594 -0
  90. package/src/cli/cmd/github.shared.ts +30 -0
  91. package/src/cli/cmd/github.ts +42 -0
  92. package/src/cli/cmd/import.ts +224 -0
  93. package/src/cli/cmd/mcp.ts +859 -0
  94. package/src/cli/cmd/models.ts +66 -0
  95. package/src/cli/cmd/plug.ts +230 -0
  96. package/src/cli/cmd/pr.ts +115 -0
  97. package/src/cli/cmd/prompt-display.ts +1 -0
  98. package/src/cli/cmd/providers.ts +550 -0
  99. package/src/cli/cmd/run/demo.ts +1274 -0
  100. package/src/cli/cmd/run/entry.body.ts +205 -0
  101. package/src/cli/cmd/run/footer.command.tsx +1088 -0
  102. package/src/cli/cmd/run/footer.menu.tsx +353 -0
  103. package/src/cli/cmd/run/footer.permission.tsx +482 -0
  104. package/src/cli/cmd/run/footer.prompt.tsx +1351 -0
  105. package/src/cli/cmd/run/footer.question.tsx +580 -0
  106. package/src/cli/cmd/run/footer.subagent.tsx +180 -0
  107. package/src/cli/cmd/run/footer.ts +1153 -0
  108. package/src/cli/cmd/run/footer.view.tsx +992 -0
  109. package/src/cli/cmd/run/footer.width.ts +27 -0
  110. package/src/cli/cmd/run/otel.ts +117 -0
  111. package/src/cli/cmd/run/permission.shared.ts +256 -0
  112. package/src/cli/cmd/run/prompt.editor.ts +157 -0
  113. package/src/cli/cmd/run/prompt.shared.ts +153 -0
  114. package/src/cli/cmd/run/question.shared.ts +340 -0
  115. package/src/cli/cmd/run/runtime.boot.ts +202 -0
  116. package/src/cli/cmd/run/runtime.lifecycle.ts +431 -0
  117. package/src/cli/cmd/run/runtime.queue.ts +349 -0
  118. package/src/cli/cmd/run/runtime.shared.ts +17 -0
  119. package/src/cli/cmd/run/runtime.stdin.ts +37 -0
  120. package/src/cli/cmd/run/runtime.ts +905 -0
  121. package/src/cli/cmd/run/scrollback.shared.ts +92 -0
  122. package/src/cli/cmd/run/scrollback.surface.ts +448 -0
  123. package/src/cli/cmd/run/scrollback.writer.tsx +353 -0
  124. package/src/cli/cmd/run/splash.ts +284 -0
  125. package/src/cli/cmd/run/stream.transport.ts +1465 -0
  126. package/src/cli/cmd/run/stream.ts +175 -0
  127. package/src/cli/cmd/run/subagent-data.ts +876 -0
  128. package/src/cli/cmd/run/theme.ts +690 -0
  129. package/src/cli/cmd/run/tool.ts +1489 -0
  130. package/src/cli/cmd/run/trace.ts +94 -0
  131. package/src/cli/cmd/run/turn-summary.ts +47 -0
  132. package/src/cli/cmd/run/types.ts +350 -0
  133. package/src/cli/cmd/run/variant.shared.ts +215 -0
  134. package/src/cli/cmd/run.ts +897 -0
  135. package/src/cli/cmd/serve.ts +24 -0
  136. package/src/cli/cmd/stats.ts +393 -0
  137. package/src/cli/cmd/tui.ts +264 -0
  138. package/src/cli/cmd/uninstall.ts +353 -0
  139. package/src/cli/cmd/upgrade.ts +74 -0
  140. package/src/cli/cmd/web.ts +84 -0
  141. package/src/cli/effect/prompt.ts +37 -0
  142. package/src/cli/effect-cmd.ts +96 -0
  143. package/src/cli/error.ts +118 -0
  144. package/src/cli/heap.ts +66 -0
  145. package/src/cli/logo.ts +1 -0
  146. package/src/cli/network.ts +64 -0
  147. package/src/cli/tui/layer.ts +7 -0
  148. package/src/cli/tui/photon_rs_bg-bq08arze.wasm +0 -0
  149. package/src/cli/tui/tree-sitter-3jzf13jk.wasm +0 -0
  150. package/src/cli/tui/tree-sitter-bash-hq5s6fxb.wasm +0 -0
  151. package/src/cli/tui/tree-sitter-powershell-ryb2ffqs.wasm +0 -0
  152. package/src/cli/tui/worker.ts +99 -0
  153. package/src/cli/ui.ts +144 -0
  154. package/src/cli/upgrade.ts +53 -0
  155. package/src/command/index.ts +189 -0
  156. package/src/command/template/initialize.txt +66 -0
  157. package/src/command/template/review.txt +101 -0
  158. package/src/command/terminal-ai-commands.ts +567 -0
  159. package/src/config/agent.ts +68 -0
  160. package/src/config/command.ts +45 -0
  161. package/src/config/config.ts +686 -0
  162. package/src/config/entry-name.ts +19 -0
  163. package/src/config/managed.ts +77 -0
  164. package/src/config/markdown.ts +36 -0
  165. package/src/config/parse.ts +79 -0
  166. package/src/config/paths.ts +47 -0
  167. package/src/config/plugin.ts +79 -0
  168. package/src/config/reference.ts +48 -0
  169. package/src/config/tui-cwd.ts +5 -0
  170. package/src/config/tui-host-attention.ts +21 -0
  171. package/src/config/tui-migrate.ts +156 -0
  172. package/src/config/tui.ts +294 -0
  173. package/src/config/variable.ts +91 -0
  174. package/src/control-plane/adapters/index.ts +41 -0
  175. package/src/control-plane/adapters/worktree.ts +96 -0
  176. package/src/control-plane/dev/README.md +19 -0
  177. package/src/control-plane/dev/debug-workspace-plugin.ts +73 -0
  178. package/src/control-plane/types.ts +59 -0
  179. package/src/control-plane/util.ts +39 -0
  180. package/src/control-plane/workspace-adapter-runtime.ts +51 -0
  181. package/src/control-plane/workspace-context.ts +26 -0
  182. package/src/control-plane/workspace.ts +1075 -0
  183. package/src/desktop/agent.ts +147 -0
  184. package/src/desktop/index.ts +247 -0
  185. package/src/desktop/platform.ts +97 -0
  186. package/src/desktop/stream.ts +64 -0
  187. package/src/desktop/vision.ts +52 -0
  188. package/src/desktop/websocket.ts +120 -0
  189. package/src/effect/app-runtime.ts +133 -0
  190. package/src/effect/bootstrap-runtime.ts +23 -0
  191. package/src/effect/bridge.ts +84 -0
  192. package/src/effect/config-service.ts +67 -0
  193. package/src/effect/instance-ref.ts +11 -0
  194. package/src/effect/instance-registry.ts +12 -0
  195. package/src/effect/instance-state.ts +72 -0
  196. package/src/effect/promise.ts +17 -0
  197. package/src/effect/run-service.ts +47 -0
  198. package/src/effect/runner.ts +217 -0
  199. package/src/effect/runtime-flags.ts +76 -0
  200. package/src/env/index.ts +40 -0
  201. package/src/event-v2-bridge.ts +76 -0
  202. package/src/format/formatter.ts +404 -0
  203. package/src/format/index.ts +212 -0
  204. package/src/git/index.ts +347 -0
  205. package/src/id/id.ts +80 -0
  206. package/src/ide/index.ts +70 -0
  207. package/src/image/image.ts +177 -0
  208. package/src/index.ts +208 -0
  209. package/src/installation/index.ts +350 -0
  210. package/src/lsp/client.ts +686 -0
  211. package/src/lsp/diagnostic.ts +29 -0
  212. package/src/lsp/language.ts +121 -0
  213. package/src/lsp/launch.ts +21 -0
  214. package/src/lsp/lsp.ts +517 -0
  215. package/src/lsp/server.ts +2116 -0
  216. package/src/markdown.d.ts +4 -0
  217. package/src/mcp/auth.ts +171 -0
  218. package/src/mcp/builtin.ts +92 -0
  219. package/src/mcp/index.ts +1000 -0
  220. package/src/mcp/oauth-callback.ts +232 -0
  221. package/src/mcp/oauth-provider.ts +217 -0
  222. package/src/node.ts +5 -0
  223. package/src/patch/index.ts +689 -0
  224. package/src/permission/arity.ts +163 -0
  225. package/src/permission/evaluate.ts +1 -0
  226. package/src/permission/index.ts +230 -0
  227. package/src/plugin/azure.ts +26 -0
  228. package/src/plugin/cloudflare.ts +76 -0
  229. package/src/plugin/digitalocean.ts +391 -0
  230. package/src/plugin/github-copilot/copilot.ts +417 -0
  231. package/src/plugin/github-copilot/models.ts +246 -0
  232. package/src/plugin/index.ts +320 -0
  233. package/src/plugin/install.ts +439 -0
  234. package/src/plugin/loader.ts +237 -0
  235. package/src/plugin/meta.ts +188 -0
  236. package/src/plugin/openai/README.md +31 -0
  237. package/src/plugin/openai/codex.ts +647 -0
  238. package/src/plugin/openai/ws-pool.ts +290 -0
  239. package/src/plugin/openai/ws.ts +381 -0
  240. package/src/plugin/shared.ts +323 -0
  241. package/src/plugin/tui/internal.ts +12 -0
  242. package/src/plugin/tui/runtime.ts +1174 -0
  243. package/src/plugin/xai.ts +742 -0
  244. package/src/project/bootstrap-service.ts +9 -0
  245. package/src/project/bootstrap.ts +80 -0
  246. package/src/project/instance-context.ts +24 -0
  247. package/src/project/instance-layer.ts +11 -0
  248. package/src/project/instance-runtime.ts +16 -0
  249. package/src/project/instance-store.ts +207 -0
  250. package/src/project/project.ts +520 -0
  251. package/src/project/vcs.ts +435 -0
  252. package/src/provider/auth.ts +230 -0
  253. package/src/provider/error.ts +188 -0
  254. package/src/provider/model-status.ts +8 -0
  255. package/src/provider/provider.ts +2037 -0
  256. package/src/provider/transform.ts +1367 -0
  257. package/src/pty-preparation.ts +30 -0
  258. package/src/question/index.ts +229 -0
  259. package/src/question/schema.ts +10 -0
  260. package/src/reference/reference.ts +239 -0
  261. package/src/reference/repository-cache.ts +320 -0
  262. package/src/server/auth.ts +48 -0
  263. package/src/server/cors.ts +34 -0
  264. package/src/server/event.ts +13 -0
  265. package/src/server/global-lifecycle.ts +37 -0
  266. package/src/server/init-projectors.ts +3 -0
  267. package/src/server/mdns.ts +60 -0
  268. package/src/server/projectors.ts +1 -0
  269. package/src/server/proxy-util.ts +48 -0
  270. package/src/server/routes/instance/httpapi/AGENTS.md +39 -0
  271. package/src/server/routes/instance/httpapi/api.ts +80 -0
  272. package/src/server/routes/instance/httpapi/errors.ts +193 -0
  273. package/src/server/routes/instance/httpapi/groups/config.ts +65 -0
  274. package/src/server/routes/instance/httpapi/groups/control-plane.ts +35 -0
  275. package/src/server/routes/instance/httpapi/groups/control.ts +76 -0
  276. package/src/server/routes/instance/httpapi/groups/event.ts +29 -0
  277. package/src/server/routes/instance/httpapi/groups/experimental.ts +260 -0
  278. package/src/server/routes/instance/httpapi/groups/file.ts +172 -0
  279. package/src/server/routes/instance/httpapi/groups/global.ts +138 -0
  280. package/src/server/routes/instance/httpapi/groups/instance.ts +206 -0
  281. package/src/server/routes/instance/httpapi/groups/mcp.ts +156 -0
  282. package/src/server/routes/instance/httpapi/groups/metadata.ts +18 -0
  283. package/src/server/routes/instance/httpapi/groups/permission.ts +61 -0
  284. package/src/server/routes/instance/httpapi/groups/project-copy.ts +88 -0
  285. package/src/server/routes/instance/httpapi/groups/project.ts +93 -0
  286. package/src/server/routes/instance/httpapi/groups/provider.ts +101 -0
  287. package/src/server/routes/instance/httpapi/groups/pty.ts +172 -0
  288. package/src/server/routes/instance/httpapi/groups/query.ts +12 -0
  289. package/src/server/routes/instance/httpapi/groups/question.ts +74 -0
  290. package/src/server/routes/instance/httpapi/groups/reference.ts +60 -0
  291. package/src/server/routes/instance/httpapi/groups/sync.ts +113 -0
  292. package/src/server/routes/instance/httpapi/groups/tui.ts +208 -0
  293. package/src/server/routes/instance/httpapi/groups/workspace.ts +141 -0
  294. package/src/server/routes/instance/httpapi/handlers/config.ts +34 -0
  295. package/src/server/routes/instance/httpapi/handlers/control-plane.ts +37 -0
  296. package/src/server/routes/instance/httpapi/handlers/control.ts +37 -0
  297. package/src/server/routes/instance/httpapi/handlers/event.ts +102 -0
  298. package/src/server/routes/instance/httpapi/handlers/experimental.ts +187 -0
  299. package/src/server/routes/instance/httpapi/handlers/file.ts +128 -0
  300. package/src/server/routes/instance/httpapi/handlers/global.ts +157 -0
  301. package/src/server/routes/instance/httpapi/handlers/instance.ts +110 -0
  302. package/src/server/routes/instance/httpapi/handlers/mcp.ts +111 -0
  303. package/src/server/routes/instance/httpapi/handlers/permission.ts +41 -0
  304. package/src/server/routes/instance/httpapi/handlers/project-copy.ts +157 -0
  305. package/src/server/routes/instance/httpapi/handlers/project.ts +63 -0
  306. package/src/server/routes/instance/httpapi/handlers/provider.ts +113 -0
  307. package/src/server/routes/instance/httpapi/handlers/pty.ts +258 -0
  308. package/src/server/routes/instance/httpapi/handlers/question.ts +54 -0
  309. package/src/server/routes/instance/httpapi/handlers/reference.ts +27 -0
  310. package/src/server/routes/instance/httpapi/handlers/sync.ts +95 -0
  311. package/src/server/routes/instance/httpapi/handlers/tui.ts +131 -0
  312. package/src/server/routes/instance/httpapi/handlers/workspace.ts +102 -0
  313. package/src/server/routes/instance/httpapi/lifecycle.ts +57 -0
  314. package/src/server/routes/instance/httpapi/middleware/authorization.ts +150 -0
  315. package/src/server/routes/instance/httpapi/middleware/compression.ts +64 -0
  316. package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +29 -0
  317. package/src/server/routes/instance/httpapi/middleware/error.ts +36 -0
  318. package/src/server/routes/instance/httpapi/middleware/fence.ts +25 -0
  319. package/src/server/routes/instance/httpapi/middleware/instance-context.ts +43 -0
  320. package/src/server/routes/instance/httpapi/middleware/proxy.ts +108 -0
  321. package/src/server/routes/instance/httpapi/middleware/schema-error.ts +42 -0
  322. package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +250 -0
  323. package/src/server/routes/instance/httpapi/public.ts +535 -0
  324. package/src/server/routes/instance/httpapi/server.ts +281 -0
  325. package/src/server/routes/instance/httpapi/websocket-tracker.ts +57 -0
  326. package/src/server/server.ts +218 -0
  327. package/src/server/shared/fence.ts +68 -0
  328. package/src/server/shared/pty-ticket.ts +15 -0
  329. package/src/server/shared/public-ui.ts +12 -0
  330. package/src/server/shared/tui-control.ts +28 -0
  331. package/src/server/shared/ui.ts +108 -0
  332. package/src/server/shared/workspace-routing.ts +38 -0
  333. package/src/server/tui-event.ts +53 -0
  334. package/src/share/share-next.ts +379 -0
  335. package/src/shell/shell.ts +215 -0
  336. package/src/skill/discovery.ts +115 -0
  337. package/src/skill/index.ts +382 -0
  338. package/src/snapshot/index.ts +762 -0
  339. package/src/sql.d.ts +4 -0
  340. package/src/storage/schema.ts +5 -0
  341. package/src/storage/storage.ts +329 -0
  342. package/src/swarm/evolution.ts +304 -0
  343. package/src/swarm/index.ts +7 -0
  344. package/src/swarm/learning.ts +736 -0
  345. package/src/swarm/vision.ts +131 -0
  346. package/src/sync/README.md +179 -0
  347. package/src/sync/schema.ts +11 -0
  348. package/src/temporary.ts +33 -0
  349. package/src/tool/apply_patch.ts +313 -0
  350. package/src/tool/apply_patch.txt +33 -0
  351. package/src/tool/browser_click.ts +51 -0
  352. package/src/tool/browser_drag.ts +76 -0
  353. package/src/tool/browser_evaluate.ts +51 -0
  354. package/src/tool/browser_hover.ts +51 -0
  355. package/src/tool/browser_navigate.ts +45 -0
  356. package/src/tool/browser_screenshot.ts +66 -0
  357. package/src/tool/browser_select.ts +52 -0
  358. package/src/tool/browser_type.ts +52 -0
  359. package/src/tool/browser_wait.ts +60 -0
  360. package/src/tool/desktop_clipboard.ts +82 -0
  361. package/src/tool/desktop_control.ts +160 -0
  362. package/src/tool/desktop_record.ts +93 -0
  363. package/src/tool/desktop_replay.ts +99 -0
  364. package/src/tool/desktop_screen_record.ts +143 -0
  365. package/src/tool/desktop_window.ts +142 -0
  366. package/src/tool/desktop_workflow.ts +81 -0
  367. package/src/tool/edit.ts +737 -0
  368. package/src/tool/edit.txt +10 -0
  369. package/src/tool/external-directory.ts +49 -0
  370. package/src/tool/glob.ts +84 -0
  371. package/src/tool/glob.txt +6 -0
  372. package/src/tool/grep.ts +140 -0
  373. package/src/tool/grep.txt +8 -0
  374. package/src/tool/invalid.ts +21 -0
  375. package/src/tool/json-schema.ts +164 -0
  376. package/src/tool/lsp.ts +113 -0
  377. package/src/tool/lsp.txt +24 -0
  378. package/src/tool/mcp-websearch.ts +96 -0
  379. package/src/tool/open_app.ts +55 -0
  380. package/src/tool/open_terminal.ts +69 -0
  381. package/src/tool/plan-enter.txt +14 -0
  382. package/src/tool/plan-exit.txt +13 -0
  383. package/src/tool/plan.ts +79 -0
  384. package/src/tool/question.ts +44 -0
  385. package/src/tool/question.txt +10 -0
  386. package/src/tool/read.ts +392 -0
  387. package/src/tool/read.txt +14 -0
  388. package/src/tool/registry.ts +527 -0
  389. package/src/tool/schema.ts +14 -0
  390. package/src/tool/screenshot.ts +72 -0
  391. package/src/tool/shell/id.ts +19 -0
  392. package/src/tool/shell/prompt.ts +307 -0
  393. package/src/tool/shell/shell.txt +21 -0
  394. package/src/tool/shell.ts +669 -0
  395. package/src/tool/skill.ts +72 -0
  396. package/src/tool/skill.txt +5 -0
  397. package/src/tool/task.ts +339 -0
  398. package/src/tool/task.txt +19 -0
  399. package/src/tool/todo.ts +57 -0
  400. package/src/tool/todowrite.txt +44 -0
  401. package/src/tool/tool.ts +180 -0
  402. package/src/tool/truncate.ts +160 -0
  403. package/src/tool/truncation-dir.ts +4 -0
  404. package/src/tool/visual_qa.ts +77 -0
  405. package/src/tool/webfetch.ts +192 -0
  406. package/src/tool/webfetch.txt +13 -0
  407. package/src/tool/websearch.ts +143 -0
  408. package/src/tool/websearch.txt +14 -0
  409. package/src/tool/write.ts +104 -0
  410. package/src/tool/write.txt +8 -0
  411. package/src/util/archive.ts +17 -0
  412. package/src/util/bom.ts +27 -0
  413. package/src/util/data-url.ts +9 -0
  414. package/src/util/defer.ts +10 -0
  415. package/src/util/effect-http-client.ts +11 -0
  416. package/src/util/error.ts +1 -0
  417. package/src/util/filesystem.ts +251 -0
  418. package/src/util/iife.ts +3 -0
  419. package/src/util/lazy.ts +20 -0
  420. package/src/util/local-context.ts +25 -0
  421. package/src/util/locale.ts +2 -0
  422. package/src/util/media.ts +26 -0
  423. package/src/util/process.ts +177 -0
  424. package/src/util/proxy-env.ts +72 -0
  425. package/src/util/queue.ts +32 -0
  426. package/src/util/record.ts +1 -0
  427. package/src/util/repository.ts +232 -0
  428. package/src/util/rpc.ts +66 -0
  429. package/src/util/signal.ts +12 -0
  430. package/src/util/sys-monitor.ts +223 -0
  431. package/src/util/timeout.ts +13 -0
  432. package/src/util/wildcard.ts +59 -0
  433. package/src/worktree/index.ts +645 -0
  434. package/sst-env.d.ts +10 -0
  435. package/test/AGENTS.md +204 -0
  436. package/test/EFFECT_TEST_MIGRATION.md +169 -0
  437. package/test/account/repo.test.ts +353 -0
  438. package/test/account/service.test.ts +453 -0
  439. package/test/acp/config-option.test.ts +229 -0
  440. package/test/acp/content.test.ts +201 -0
  441. package/test/acp/directory.test.ts +186 -0
  442. package/test/acp/error.test.ts +67 -0
  443. package/test/acp/event.test.ts +743 -0
  444. package/test/acp/permission.test.ts +273 -0
  445. package/test/acp/tool.test.ts +210 -0
  446. package/test/acp/usage.test.ts +315 -0
  447. package/test/agent/agent.test.ts +711 -0
  448. package/test/agent/plan-mode-subagent-bypass.test.ts +213 -0
  449. package/test/agent/plugin-agent-regression.test.ts +62 -0
  450. package/test/auth/auth.test.ts +77 -0
  451. package/test/background/job.test.ts +243 -0
  452. package/test/cli/account.test.ts +30 -0
  453. package/test/cli/acp/acp-test-client.ts +97 -0
  454. package/test/cli/acp/config-options.test.ts +103 -0
  455. package/test/cli/acp/helpers.ts +96 -0
  456. package/test/cli/acp/initialize-auth.test.ts +61 -0
  457. package/test/cli/acp/lifecycle.test.ts +118 -0
  458. package/test/cli/acp/prompt-content.test.ts +97 -0
  459. package/test/cli/acp/skills.test.ts +38 -0
  460. package/test/cli/cmd/tui/attention.test.ts +484 -0
  461. package/test/cli/effect-cmd-instance-als.test.ts +39 -0
  462. package/test/cli/error.test.ts +95 -0
  463. package/test/cli/github-action.test.ts +199 -0
  464. package/test/cli/github-remote.test.ts +90 -0
  465. package/test/cli/help/__snapshots__/help-snapshots.test.ts.snap +631 -0
  466. package/test/cli/help/help-snapshots.test.ts +137 -0
  467. package/test/cli/import.test.ts +54 -0
  468. package/test/cli/mcp-add.test.ts +74 -0
  469. package/test/cli/plugin-auth-picker.test.ts +120 -0
  470. package/test/cli/run/entry.body.test.ts +536 -0
  471. package/test/cli/run/footer.menu.test.ts +43 -0
  472. package/test/cli/run/footer.view.test.tsx +1336 -0
  473. package/test/cli/run/footer.width.test.ts +35 -0
  474. package/test/cli/run/permission.shared.test.ts +144 -0
  475. package/test/cli/run/prompt.editor.test.ts +101 -0
  476. package/test/cli/run/prompt.shared.test.ts +101 -0
  477. package/test/cli/run/question.shared.test.ts +115 -0
  478. package/test/cli/run/run-process.test.ts +84 -0
  479. package/test/cli/run/runtime.boot.test.ts +283 -0
  480. package/test/cli/run/runtime.queue.test.ts +481 -0
  481. package/test/cli/run/runtime.stdin.test.ts +71 -0
  482. package/test/cli/run/runtime.test.ts +238 -0
  483. package/test/cli/run/scrollback.surface.test.ts +1065 -0
  484. package/test/cli/run/stream.test.ts +56 -0
  485. package/test/cli/run/stream.transport.test.ts +2363 -0
  486. package/test/cli/run/subagent-data.test.ts +547 -0
  487. package/test/cli/run/theme.test.ts +177 -0
  488. package/test/cli/run/variant.shared.test.ts +217 -0
  489. package/test/cli/serve/serve-process.test.ts +61 -0
  490. package/test/cli/smokes/read-only.test.ts +115 -0
  491. package/test/cli/tui/attach.test.ts +11 -0
  492. package/test/cli/tui/editor-context-zed.test.ts +379 -0
  493. package/test/cli/tui/editor-context.test.tsx +297 -0
  494. package/test/cli/tui/plugin-add.test.ts +110 -0
  495. package/test/cli/tui/plugin-install.test.ts +87 -0
  496. package/test/cli/tui/plugin-lifecycle.test.ts +224 -0
  497. package/test/cli/tui/plugin-loader-entrypoint.test.ts +485 -0
  498. package/test/cli/tui/plugin-loader-pure.test.ts +72 -0
  499. package/test/cli/tui/plugin-loader.test.ts +1332 -0
  500. package/test/cli/tui/plugin-toggle.test.ts +264 -0
  501. package/test/cli/tui/thread.test.ts +36 -0
  502. package/test/cli.test.ts +7 -0
  503. package/test/command/acp-slash-detect.test.ts +202 -0
  504. package/test/command/demo-slash.test.ts +213 -0
  505. package/test/command/slash-head.test.ts +232 -0
  506. package/test/command/slash-parsing.test.ts +193 -0
  507. package/test/command/terminal-ai-commands.test.ts +536 -0
  508. package/test/config/agent-color.test.ts +47 -0
  509. package/test/config/config.test.ts +1994 -0
  510. package/test/config/entry-name.test.ts +57 -0
  511. package/test/config/fixtures/empty-frontmatter.md +4 -0
  512. package/test/config/fixtures/frontmatter.md +28 -0
  513. package/test/config/fixtures/markdown-header.md +11 -0
  514. package/test/config/fixtures/no-frontmatter.md +1 -0
  515. package/test/config/fixtures/weird-model-id.md +13 -0
  516. package/test/config/lsp.test.ts +69 -0
  517. package/test/config/markdown.test.ts +228 -0
  518. package/test/config/plugin.test.ts +0 -0
  519. package/test/config/tui.test.ts +886 -0
  520. package/test/control-plane/adapters.test.ts +71 -0
  521. package/test/control-plane/workspace.test.ts +1704 -0
  522. package/test/effect/app-runtime-logger.test.ts +105 -0
  523. package/test/effect/config-service.test.ts +65 -0
  524. package/test/effect/instance-state.test.ts +391 -0
  525. package/test/effect/run-service.test.ts +89 -0
  526. package/test/effect/runner.test.ts +514 -0
  527. package/test/effect/runtime-flags.test.ts +373 -0
  528. package/test/fake/account.ts +9 -0
  529. package/test/fake/auth.ts +8 -0
  530. package/test/fake/npm.ts +8 -0
  531. package/test/fake/provider.ts +82 -0
  532. package/test/fake/skill.ts +8 -0
  533. package/test/filesystem/filesystem.test.ts +319 -0
  534. package/test/fixture/agent-plugin.constants.ts +6 -0
  535. package/test/fixture/agent-plugin.ts +12 -0
  536. package/test/fixture/config.ts +23 -0
  537. package/test/fixture/db.ts +11 -0
  538. package/test/fixture/fixture.test.ts +26 -0
  539. package/test/fixture/fixture.ts +224 -0
  540. package/test/fixture/flag.ts +20 -0
  541. package/test/fixture/flock-worker.ts +72 -0
  542. package/test/fixture/lsp/fake-lsp-server.js +249 -0
  543. package/test/fixture/plug-worker.ts +96 -0
  544. package/test/fixture/plugin-meta-worker.ts +19 -0
  545. package/test/fixture/plugin.ts +10 -0
  546. package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
  547. package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
  548. package/test/fixture/skills/cloudflare/SKILL.md +211 -0
  549. package/test/fixture/skills/index.json +6 -0
  550. package/test/fixture/tui-environment.tsx +32 -0
  551. package/test/fixture/tui-plugin.ts +357 -0
  552. package/test/fixture/tui-runtime.ts +56 -0
  553. package/test/fixture/tui-sdk.ts +82 -0
  554. package/test/fixture/workspace.ts +30 -0
  555. package/test/format/format.test.ts +228 -0
  556. package/test/git/git.test.ts +178 -0
  557. package/test/ide/ide.test.ts +82 -0
  558. package/test/image/fixtures/picture-5mb-base64.png +0 -0
  559. package/test/image/image.test.ts +123 -0
  560. package/test/installation/installation.test.ts +231 -0
  561. package/test/lib/cli-process.ts +459 -0
  562. package/test/lib/effect.ts +177 -0
  563. package/test/lib/filesystem.ts +10 -0
  564. package/test/lib/llm-server.ts +771 -0
  565. package/test/lib/snapshot.ts +73 -0
  566. package/test/lib/test-provider.ts +37 -0
  567. package/test/lib/websocket.ts +46 -0
  568. package/test/lsp/client.test.ts +493 -0
  569. package/test/lsp/index.test.ts +232 -0
  570. package/test/lsp/jdtls-root.test.ts +459 -0
  571. package/test/lsp/launch.test.ts +22 -0
  572. package/test/lsp/lifecycle.test.ts +160 -0
  573. package/test/mcp/auth.test.ts +78 -0
  574. package/test/mcp/builtin.test.ts +95 -0
  575. package/test/mcp/headers.test.ts +126 -0
  576. package/test/mcp/lifecycle.test.ts +999 -0
  577. package/test/mcp/oauth-auto-connect.test.ts +274 -0
  578. package/test/mcp/oauth-browser.test.ts +232 -0
  579. package/test/mcp/oauth-callback.test.ts +34 -0
  580. package/test/mcp/oauth-provider.test.ts +61 -0
  581. package/test/patch/patch.test.ts +383 -0
  582. package/test/permission/arity.test.ts +33 -0
  583. package/test/permission/next.test.ts +1176 -0
  584. package/test/permission-task.test.ts +318 -0
  585. package/test/plugin/auth-override.test.ts +105 -0
  586. package/test/plugin/cloudflare.test.ts +68 -0
  587. package/test/plugin/codex.test.ts +247 -0
  588. package/test/plugin/github-copilot-models.test.ts +332 -0
  589. package/test/plugin/install-concurrency.test.ts +140 -0
  590. package/test/plugin/install.test.ts +573 -0
  591. package/test/plugin/loader-shared.test.ts +1303 -0
  592. package/test/plugin/meta.test.ts +137 -0
  593. package/test/plugin/openai-rollout.test.ts +17 -0
  594. package/test/plugin/openai-ws.test.ts +877 -0
  595. package/test/plugin/shared.test.ts +88 -0
  596. package/test/plugin/trigger.test.ts +120 -0
  597. package/test/plugin/workspace-adapter.test.ts +137 -0
  598. package/test/plugin/xai.test.ts +634 -0
  599. package/test/preload.ts +99 -0
  600. package/test/project/instance-bootstrap.test.ts +110 -0
  601. package/test/project/instance.test.ts +245 -0
  602. package/test/project/migrate-global.test.ts +170 -0
  603. package/test/project/project-directory.test.ts +169 -0
  604. package/test/project/project.test.ts +818 -0
  605. package/test/project/vcs.test.ts +336 -0
  606. package/test/project/worktree-remove.test.ts +126 -0
  607. package/test/project/worktree.test.ts +320 -0
  608. package/test/provider/amazon-bedrock.test.ts +360 -0
  609. package/test/provider/cf-ai-gateway-e2e.test.ts +132 -0
  610. package/test/provider/digitalocean.test.ts +123 -0
  611. package/test/provider/gitlab-duo.test.ts +412 -0
  612. package/test/provider/header-timeout.test.ts +233 -0
  613. package/test/provider/model-status.test.ts +61 -0
  614. package/test/provider/provider.test.ts +1795 -0
  615. package/test/provider/transform.test.ts +3937 -0
  616. package/test/pty/pty-shell.test.ts +102 -0
  617. package/test/question/question.test.ts +465 -0
  618. package/test/reference/reference.test.ts +311 -0
  619. package/test/server/AGENTS.md +15 -0
  620. package/test/server/auth.test.ts +59 -0
  621. package/test/server/global-bus.ts +31 -0
  622. package/test/server/httpapi-authorization.test.ts +174 -0
  623. package/test/server/httpapi-compression.test.ts +154 -0
  624. package/test/server/httpapi-config.test.ts +113 -0
  625. package/test/server/httpapi-control-plane.test.ts +63 -0
  626. package/test/server/httpapi-cors-vary.test.ts +66 -0
  627. package/test/server/httpapi-cors.test.ts +122 -0
  628. package/test/server/httpapi-error-middleware.test.ts +96 -0
  629. package/test/server/httpapi-event.test.ts +97 -0
  630. package/test/server/httpapi-exercise/assertions.ts +64 -0
  631. package/test/server/httpapi-exercise/backend.ts +144 -0
  632. package/test/server/httpapi-exercise/dsl.ts +210 -0
  633. package/test/server/httpapi-exercise/environment.ts +40 -0
  634. package/test/server/httpapi-exercise/index.ts +1538 -0
  635. package/test/server/httpapi-exercise/report.ts +66 -0
  636. package/test/server/httpapi-exercise/routing.ts +96 -0
  637. package/test/server/httpapi-exercise/runner.ts +267 -0
  638. package/test/server/httpapi-exercise/runtime.ts +52 -0
  639. package/test/server/httpapi-exercise/types.ts +123 -0
  640. package/test/server/httpapi-experimental.test.ts +300 -0
  641. package/test/server/httpapi-file.test.ts +76 -0
  642. package/test/server/httpapi-global.test.ts +66 -0
  643. package/test/server/httpapi-instance-context.test.ts +347 -0
  644. package/test/server/httpapi-instance-route-auth.test.ts +84 -0
  645. package/test/server/httpapi-instance.test.ts +265 -0
  646. package/test/server/httpapi-layer.ts +33 -0
  647. package/test/server/httpapi-listen.test.ts +415 -0
  648. package/test/server/httpapi-mcp-oauth.test.ts +73 -0
  649. package/test/server/httpapi-mcp.test.ts +234 -0
  650. package/test/server/httpapi-mdns.test.ts +82 -0
  651. package/test/server/httpapi-promptasync-context.test.ts +222 -0
  652. package/test/server/httpapi-provider.test.ts +403 -0
  653. package/test/server/httpapi-pty.test.ts +275 -0
  654. package/test/server/httpapi-public-openapi.test.ts +297 -0
  655. package/test/server/httpapi-query-schema-drift.test.ts +330 -0
  656. package/test/server/httpapi-reference.test.ts +56 -0
  657. package/test/server/httpapi-schema-error-body.test.ts +165 -0
  658. package/test/server/httpapi-sdk.test.ts +909 -0
  659. package/test/server/httpapi-sync.test.ts +154 -0
  660. package/test/server/httpapi-ui.test.ts +456 -0
  661. package/test/server/httpapi-v2-location.test.ts +85 -0
  662. package/test/server/httpapi-workspace-routing.test.ts +554 -0
  663. package/test/server/httpapi-workspace.test.ts +515 -0
  664. package/test/server/project-copy.test.ts +101 -0
  665. package/test/server/project-init-git.test.ts +117 -0
  666. package/test/server/proxy-util.test.ts +113 -0
  667. package/test/server/sdk-error-shape.test.ts +84 -0
  668. package/test/server/sdk-v1-smoke.test.ts +60 -0
  669. package/test/server/workspace-proxy.test.ts +181 -0
  670. package/test/server/workspace-routing.test.ts +94 -0
  671. package/test/server/worktree-endpoint-repro.test.ts +307 -0
  672. package/test/share/share-next.test.ts +344 -0
  673. package/test/shell/shell.test.ts +99 -0
  674. package/test/skill/discovery.test.ts +139 -0
  675. package/test/skill/skill.test.ts +571 -0
  676. package/test/snapshot/snapshot.test.ts +1121 -0
  677. package/test/storage/storage.test.ts +296 -0
  678. package/test/storage/workspace-time-migration.test.ts +50 -0
  679. package/test/tool/__snapshots__/parameters.test.ts.snap +484 -0
  680. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  681. package/test/tool/apply_patch.test.ts +533 -0
  682. package/test/tool/browser.integration.test.ts +141 -0
  683. package/test/tool/desktop.integration.test.ts +129 -0
  684. package/test/tool/desktop.test.ts +85 -0
  685. package/test/tool/edit.test.ts +578 -0
  686. package/test/tool/external-directory.test.ts +167 -0
  687. package/test/tool/fixtures/large-image.png +0 -0
  688. package/test/tool/fixtures/models-api.json +117299 -0
  689. package/test/tool/glob.test.ts +188 -0
  690. package/test/tool/grep.test.ts +266 -0
  691. package/test/tool/lsp.test.ts +181 -0
  692. package/test/tool/parameters.test.ts +293 -0
  693. package/test/tool/question.test.ts +138 -0
  694. package/test/tool/read.test.ts +659 -0
  695. package/test/tool/registry.test.ts +539 -0
  696. package/test/tool/shell.test.ts +1256 -0
  697. package/test/tool/skill.test.ts +135 -0
  698. package/test/tool/task.test.ts +901 -0
  699. package/test/tool/tool-define.test.ts +153 -0
  700. package/test/tool/truncation.test.ts +266 -0
  701. package/test/tool/webfetch.test.ts +113 -0
  702. package/test/tool/websearch.test.ts +99 -0
  703. package/test/tool/write.test.ts +276 -0
  704. package/test/util/data-url.test.ts +14 -0
  705. package/test/util/error.test.ts +16 -0
  706. package/test/util/filesystem.test.ts +656 -0
  707. package/test/util/glob.test.ts +164 -0
  708. package/test/util/iife.test.ts +36 -0
  709. package/test/util/lazy.test.ts +50 -0
  710. package/test/util/log.test.ts +77 -0
  711. package/test/util/module.test.ts +59 -0
  712. package/test/util/process.test.ts +128 -0
  713. package/test/util/repository.test.ts +93 -0
  714. package/test/util/timeout.test.ts +21 -0
  715. package/test/util/wildcard.test.ts +90 -0
  716. package/tsconfig.json +16 -0
@@ -0,0 +1,131 @@
1
+ import { Effect, Context, Layer, Schema } from "effect"
2
+
3
+ const VISION_DETAIL_AREAS = [
4
+ "objects, people, characters, products, and text",
5
+ "layout, spacing, alignment, hierarchy, and composition",
6
+ "colors, materials, lighting, shadows, camera angle, and style",
7
+ "UI states, controls, navigation, responsiveness, and accessibility hints",
8
+ "animation timing, motion paths, transitions, cuts, and scene changes",
9
+ "risks, ambiguities, edge cases, and what must be verified by the next agent",
10
+ ] as const
11
+
12
+ export const VisionPlan = Schema.Struct({
13
+ agentName: Schema.String,
14
+ agentModel: Schema.String,
15
+ task: Schema.String,
16
+ route: Schema.Literals([
17
+ "use_agent_native_vision",
18
+ "delegate_to_temporary_vision_model",
19
+ "ask_user_visual_questions",
20
+ "continue_without_annoying_user",
21
+ ]),
22
+ questions: Schema.Array(Schema.String),
23
+ detailAreas: Schema.Array(Schema.String),
24
+ handoffPolicy: Schema.String,
25
+ })
26
+ export type VisionPlan = Schema.Schema.Type<typeof VisionPlan>
27
+
28
+ export interface Interface {
29
+ readonly planTemporaryVision: (input: {
30
+ agentName: string
31
+ agentModel: string
32
+ task: string
33
+ mode?: string
34
+ }) => Effect.Effect<VisionPlan>
35
+ readonly isVisionModel: (modelId: string) => Effect.Effect<boolean>
36
+ readonly needsVisualDetail: (task: string) => Effect.Effect<boolean>
37
+ readonly formatVisionBrief: (plan: VisionPlan) => Effect.Effect<string>
38
+ }
39
+
40
+ export class Service extends Context.Service<Service, Interface>()("@octocode/SwarmVision") {}
41
+
42
+ export const layer = Layer.succeed(Service, {
43
+ planTemporaryVision: (input) =>
44
+ Effect.sync(() => {
45
+ const agentHasVision = isVisionModelSync(input.agentModel)
46
+ const needsDetail = needsVisualDetailSync(input.task)
47
+ const isPlanMode = (input.mode ?? "").toLowerCase() === "plan"
48
+
49
+ let route: VisionPlan["route"]
50
+ let questions: string[] = []
51
+
52
+ if (agentHasVision) {
53
+ route = "use_agent_native_vision"
54
+ } else if (isPlanMode && needsDetail) {
55
+ route = "ask_user_visual_questions"
56
+ questions = buildPlanModeVisualQuestions(input.task)
57
+ } else {
58
+ route = "continue_without_annoying_user"
59
+ }
60
+
61
+ return {
62
+ agentName: input.agentName,
63
+ agentModel: input.agentModel,
64
+ task: input.task,
65
+ route,
66
+ questions,
67
+ detailAreas: [...VISION_DETAIL_AREAS],
68
+ handoffPolicy:
69
+ "Vision model returns a full structured visual brief once; the requesting agent continues from that brief without repeatedly rereading the media.",
70
+ }
71
+ }),
72
+
73
+ isVisionModel: (modelId) => Effect.succeed(isVisionModelSync(modelId)),
74
+
75
+ needsVisualDetail: (task) => Effect.succeed(needsVisualDetailSync(task)),
76
+
77
+ formatVisionBrief: (plan) =>
78
+ Effect.sync(() => {
79
+ if (plan.route === "use_agent_native_vision") {
80
+ return [
81
+ `<vision_routing agent="${plan.agentName}" route="native_vision" />`,
82
+ "This agent has native vision capabilities. Inspect visual assets directly.",
83
+ ].join("\n")
84
+ }
85
+
86
+ if (plan.route === "ask_user_visual_questions") {
87
+ const questionList = plan.questions.map((q, i) => ` ${i + 1}. ${q}`).join("\n")
88
+ return [
89
+ `<vision_routing agent="${plan.agentName}" route="ask_user" />`,
90
+ "No vision model available. Ask the user these visual questions before proceeding:",
91
+ questionList,
92
+ ].join("\n")
93
+ }
94
+
95
+ return [
96
+ `<vision_routing agent="${plan.agentName}" route="skip" />`,
97
+ "No vision model available and task does not require visual inspection. Proceed with reasonable assumptions.",
98
+ ].join("\n")
99
+ }),
100
+ })
101
+
102
+ function isVisionModelSync(model: string): boolean {
103
+ const lower = model.toLowerCase()
104
+ return /vision|multimodal|gpt-4o|gemini|claude|image|video|scout|flash/.test(lower)
105
+ }
106
+
107
+ function needsVisualDetailSync(task: string): boolean {
108
+ const lower = task.toLowerCase()
109
+ return /image|video|design|layout|animation|visual|photo|screenshot|figma|ui|ux|css|style/.test(lower)
110
+ }
111
+
112
+ function isSimpleVisualTask(task: string): boolean {
113
+ const lower = task.toLowerCase()
114
+ const simple = /simple|basic|quick|plain/.test(lower)
115
+ const complex = /full app|dashboard|animation|exact|detailed|responsive/.test(lower)
116
+ return simple && !complex
117
+ }
118
+
119
+ function buildPlanModeVisualQuestions(task: string): string[] {
120
+ if (isSimpleVisualTask(task)) return []
121
+ return [
122
+ "What exact visual style should the final result follow?",
123
+ "What are the main objects, layout, proportions, colors, and materials?",
124
+ "What text, branding, icons, UI controls, or labels must be preserved?",
125
+ "What animations, transitions, timing, or interactions are required?",
126
+ "What functions or user flows are tied to the visual design?",
127
+ "What details are forbidden, optional, or lower priority?",
128
+ ]
129
+ }
130
+
131
+ export * as SwarmVision from "./vision"
@@ -0,0 +1,179 @@
1
+ tl;dr All of these APIs work, are properly type-checked, and are sync events are backwards compatible with `Bus`:
2
+
3
+ ```ts
4
+ // The schema from `Updated` typechecks the object correctly
5
+ SyncEvent.run(Updated, { sessionID: id, info: { title: "foo" } })
6
+
7
+ // `subscribeAll` passes a generic sync event
8
+ SyncEvent.subscribeAll((event) => {
9
+ // These will be type-checked correctly
10
+ event.id
11
+ event.seq
12
+ // This will be unknown because we are listening for all events,
13
+ // and this API is only used to record them
14
+ event.data
15
+ })
16
+
17
+ // This works, but you shouldn't publish sync event like this (should fail in the future)
18
+ Bus.publish(Updated, { sessionID: id, info: { title: "foo" } })
19
+
20
+ // Update event is fully type-checked
21
+ Bus.subscribe(Updated, (event) => event.properties.info.title)
22
+
23
+ // Update event is fully type-checked
24
+ client.subscribe("session.updated", (evt) => evt.properties.info.title)
25
+ ```
26
+
27
+ # Goal
28
+
29
+ ## Syncing with only one writer
30
+
31
+ This system defines a basic event sourcing system for session replayability. The goal is to allow for one device to control and modify the session, and allow multiple other devices to "sync" session data. The sync works by getting a log of events to replay and replaying them locally.
32
+
33
+ Because only one device is allowed to write, we don't need any kind of sophisticated distributed system clocks or causal ordering. We implement total ordering with a simple sequence id (a number) and increment it by one every time we generate an event.
34
+
35
+ ## Bus event integration and backwards compatibility
36
+
37
+ This initial implementation aims to be fully backwards compatible. We should be able to land this without any visible changes to the user.
38
+
39
+ An existing `Bus` abstraction to send events already exists. We already send events like `session.created` through the system. We should not duplicate this.
40
+
41
+ The difference in event sourcing is events are sent _before_ the mutation happens, and "projectors" handle the effects and perform the mutations. This difference is subtle, and a necessary change for syncing to work.
42
+
43
+ So the goal is:
44
+
45
+ - Introduce a new syncing abstraction to handle event sourcing and projectors
46
+ - Seamlessly integrate these new events into the same existing `Bus` abstraction
47
+ - Maintain full backwards compatibility to reduce risk
48
+
49
+ ## My approach
50
+
51
+ This directory introduces a new abstraction: `SyncEvent`. This handles all of the event sourcing.
52
+
53
+ There are now "sync events" which are different than "bus events". Bus events are defined like this:
54
+
55
+ ```ts
56
+ const Diff = BusEvent.define(
57
+ "session.diff",
58
+ Schema.Struct({
59
+ sessionID: SessionID,
60
+ diff: Schema.Array(Snapshot.FileDiff),
61
+ }),
62
+ )
63
+ ```
64
+
65
+ You can do `Bus.publish(Diff, { ... })` to push these events, and `Bus.subscribe(Diff, handler)` to listen to them.
66
+
67
+ Sync events are a lower-level abstraction which are similar, but also handle the requirements for recording and replaying. Defining them looks like this:
68
+
69
+ ```ts
70
+ const Created = SyncEvent.define({
71
+ type: "session.created",
72
+ version: 1,
73
+ aggregate: "sessionID",
74
+ schema: Schema.Struct({
75
+ sessionID: SessionID,
76
+ info: Info,
77
+ }),
78
+ })
79
+ ```
80
+
81
+ Not too different, except they track a version and an "aggregate" field (will explain that later).
82
+
83
+ You do this to run an event, which is kind of like `Bus.publish` except that it runs through the event sourcing system:
84
+
85
+ ```
86
+ SyncEvent.run(Created, { ... })
87
+ ```
88
+
89
+ The data passed as the second argument is properly type-checked based on the schema defined in `Created`.
90
+
91
+ Importantly, **sync events automatically re-publish as bus events**. This makes them backwards compatible, and allows the `Bus` to still be the single abstraction that the system uses to listen for individual events.
92
+
93
+ **We have upgraded many of the session events to be sync events** (all of the ones that mutate the db). Sync and bus events are largely compatible. Here are the differences:
94
+
95
+ ### Event shape
96
+
97
+ - The shape of the events are slightly different. A sync event has the `type`, `id`, `seq`, `aggregateID`, and `data` fields. A bus event has the `type` and `properties` fields. `data` and `properties` are largely the same thing. This conversion is automatically handled when the sync system re-published the event through the bus.
98
+
99
+ The reason for this is because sync events need to track more information. I chose not to copy the `properties` naming to more clearly disambiguate the event types.
100
+
101
+ ### Event flow
102
+
103
+ There is no way to subscribe to individual sync events in `SyncEvent`. You can use `subscribeAll` to receive _all_ of the events, which is needed for clients that want to record them.
104
+
105
+ To listen for individual events, use `Bus.subscribe`. You can pass in a sync event definition to it: `Bus.subscribe(Created, handler)`. This is fully supported.
106
+
107
+ You should never "publish" a sync event however: `Bus.publish(Created, ...)`. I would like to force this to be a type error in the future. You should never be touching the db directly, and should not be manually handling these events.
108
+
109
+ ### Backwards compatibility
110
+
111
+ The system install projectors in `server/projectors.js`. It calls `SyncEvent.init` to do this. It also installs a hook for dynamically converting an event at runtime (`convertEvent`).
112
+
113
+ This allows you to "reshape" an event from the sync system before it's published to the bus. This should be avoided, but might be necessary for temporary backwards compat.
114
+
115
+ The only time we use this is the `session.updated` event. Previously this event contained the entire session object. The sync event only contains the fields updated. We convert the event to contain the full object for backwards compatibility (but ideally we'd remove this).
116
+
117
+ It's very important that types are correct when working with events. Event definitions have a `schema` which carries the definition of the event shape. Examples:
118
+
119
+ ```ts
120
+ // The schema from `Updated` typechecks the object correctly
121
+ SyncEvent.run(Updated, { sessionID: id, info: { title: "foo" } })
122
+
123
+ // `subscribeAll` passes a generic sync event
124
+ SyncEvent.subscribeAll((event) => {
125
+ // These will be type-checked correctly
126
+ event.id
127
+ event.seq
128
+ // This will be unknown because we are listening for all events,
129
+ // and this API is only used to record them
130
+ event.data
131
+ })
132
+
133
+ // This works, but you shouldn't publish sync event like this (should fail in the future)
134
+ Bus.publish(Updated, { sessionID: id, info: { title: "foo" } })
135
+
136
+ // Update event is fully type-checked
137
+ Bus.subscribe(Updated, (event) => event.properties.info.title)
138
+
139
+ // Update event is fully type-checked
140
+ client.subscribe("session.updated", (evt) => evt.properties.info.title)
141
+ ```
142
+
143
+ The last two examples look similar to `SyncEvent.run`, but they were the cause of a lot of grief. Those are existing APIs that we can't break, but we are passing in the new sync event definitions to these APIs, which sometimes have a different event shape.
144
+
145
+ I previously mentioned the runtime conversion of events, but we still need to the types to work! To do that, the `define` API supports an optional `busSchema` prop to give it the schema for backwards compatibility. For example this is the full definition of `Session.Update`:
146
+
147
+ ```ts
148
+ const Update = SyncEvent.define({
149
+ type: "session.updated",
150
+ version: 1,
151
+ aggregate: "sessionID",
152
+ schema: Schema.Struct({
153
+ sessionID: SessionID,
154
+ info: partialSchema(Info),
155
+ }),
156
+ busSchema: Schema.Struct({
157
+ sessionID: SessionID,
158
+ info: Info,
159
+ }),
160
+ })
161
+ ```
162
+
163
+ _Important_: the conversion done in `convertEvent` is not automatically type-checked with `busSchema`. It's very important they match, but because we need this at type-checking time this needs to live here.
164
+
165
+ Internally, the way this works is `busSchema` is stored on a `properties` field which is what the bus system expects. Doing this made everything with `Bus` "just work". This is why you can pass a sync event to the bus APIs.
166
+
167
+ _Alternatives_
168
+
169
+ These are some other paths I explored:
170
+
171
+ - Providing a way to subscribe to individual sync events, and change all the instances of `Bus.subscribe` in our code to it. Then you are directly only working with sync events always.
172
+ - Two big problems. First, `Bus` is instance-scoped, and we'd need to make the sync event system instance-scoped too for backwards compat. If we didn't, those listeners would get calls for events they weren't expecting.
173
+ - Second, we can't change consumers of our SDK. So they still have to use the old events, and we might as well stick with them for consistency
174
+ - Directly add sync event support to bus system
175
+ - I explored adding sync events to the bus, but due to backwards compat, it only made it more complicated (still need to support both shapes)
176
+ - I explored a `convertSchema` function to convert the event schema at runtime so we didn't need `busSchema`
177
+ - Fatal flaw: we need type-checking done earlier. We can't do this at run-time. This worked for consumers of our SDK (because it gets generated TS types from the converted schema) but breaks for our internal usage of `Bus.subscribe` calls
178
+
179
+ I explored many other permutations of the above solutions. What we have today I think is the best balance of backwards compatibility while opening a path forward for the new events.
@@ -0,0 +1,11 @@
1
+ import { Schema } from "effect"
2
+
3
+ import { Identifier } from "@/id/id"
4
+ import { withStatics } from "@octocode-ai/core/schema"
5
+
6
+ export const EventID = Schema.String.check(Schema.isStartsWith("evt")).pipe(
7
+ Schema.brand("EventID"),
8
+ withStatics((s) => ({
9
+ ascending: (id?: string) => s.make(Identifier.ascending("event", id)),
10
+ })),
11
+ )
@@ -0,0 +1,33 @@
1
+ import yargs from "yargs"
2
+ import { TuiThreadCommand } from "./cli/cmd/tui"
3
+ import { InstallationVersion } from "@octocode-ai/core/installation/version"
4
+ import { hideBin } from "yargs/helpers"
5
+ import { Log } from "./node"
6
+
7
+ Log.init({
8
+ print: false,
9
+ })
10
+
11
+ const cli = yargs(hideBin(process.argv))
12
+ .parserConfiguration({ "populate--": true })
13
+ .scriptName("octo")
14
+ .wrap(100)
15
+ .help("help", "show help")
16
+ .alias("help", "h")
17
+ .version("version", "show version number", InstallationVersion)
18
+ .alias("version", "v")
19
+ .option("print-logs", {
20
+ describe: "print logs to stderr",
21
+ type: "boolean",
22
+ })
23
+ .option("log-level", {
24
+ describe: "log level",
25
+ type: "string",
26
+ choices: ["DEBUG", "INFO", "WARN", "ERROR"],
27
+ })
28
+ .option("pure", {
29
+ describe: "run without external plugins",
30
+ type: "boolean",
31
+ })
32
+ .command(TuiThreadCommand)
33
+ .parse()
@@ -0,0 +1,313 @@
1
+ import * as path from "path"
2
+ import { Effect, Schema } from "effect"
3
+ import * as Tool from "./tool"
4
+ import { EventV2Bridge } from "@/event-v2-bridge"
5
+ import { Watcher } from "@octocode-ai/core/filesystem/watcher"
6
+ import { InstanceState } from "@/effect/instance-state"
7
+ import { Patch } from "../patch"
8
+ import { createTwoFilesPatch, diffLines } from "diff"
9
+ import { assertExternalDirectoryEffect } from "./external-directory"
10
+ import { trimDiff } from "./edit"
11
+ import { LSP } from "@/lsp/lsp"
12
+ import { FSUtil } from "@octocode-ai/core/fs-util"
13
+ import DESCRIPTION from "./apply_patch.txt"
14
+ import { FileSystem } from "@octocode-ai/core/filesystem"
15
+ import { Format } from "../format"
16
+ import * as Bom from "@/util/bom"
17
+
18
+ export const Parameters = Schema.Struct({
19
+ patchText: Schema.String.annotate({ description: "The full patch text that describes all changes to be made" }),
20
+ })
21
+
22
+ export const ApplyPatchTool = Tool.define(
23
+ "apply_patch",
24
+ Effect.gen(function* () {
25
+ const lsp = yield* LSP.Service
26
+ const afs = yield* FSUtil.Service
27
+ const format = yield* Format.Service
28
+ const events = yield* EventV2Bridge.Service
29
+
30
+ const run = Effect.fn("ApplyPatchTool.execute")(function* (
31
+ params: Schema.Schema.Type<typeof Parameters>,
32
+ ctx: Tool.Context,
33
+ ) {
34
+ if (!params.patchText) {
35
+ return yield* Effect.fail(new Error("patchText is required"))
36
+ }
37
+
38
+ // Parse the patch to get hunks
39
+ let hunks: Patch.Hunk[]
40
+ try {
41
+ const parseResult = Patch.parsePatch(params.patchText)
42
+ hunks = parseResult.hunks
43
+ } catch (error) {
44
+ return yield* Effect.fail(new Error(`apply_patch verification failed: ${error}`))
45
+ }
46
+
47
+ if (hunks.length === 0) {
48
+ const normalized = params.patchText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim()
49
+ if (normalized === "*** Begin Patch\n*** End Patch") {
50
+ return yield* Effect.fail(new Error("patch rejected: empty patch"))
51
+ }
52
+ return yield* Effect.fail(new Error("apply_patch verification failed: no hunks found"))
53
+ }
54
+
55
+ const instance = yield* InstanceState.context
56
+
57
+ // Validate file paths and check permissions
58
+ const fileChanges: Array<{
59
+ filePath: string
60
+ oldContent: string
61
+ newContent: string
62
+ type: "add" | "update" | "delete" | "move"
63
+ movePath?: string
64
+ diff: string
65
+ additions: number
66
+ deletions: number
67
+ bom: boolean
68
+ }> = []
69
+
70
+ let totalDiff = ""
71
+
72
+ for (const hunk of hunks) {
73
+ const filePath = path.resolve(instance.directory, hunk.path)
74
+ yield* assertExternalDirectoryEffect(ctx, filePath)
75
+
76
+ switch (hunk.type) {
77
+ case "add": {
78
+ const oldContent = ""
79
+ const newContent =
80
+ hunk.contents.length === 0 || hunk.contents.endsWith("\n") ? hunk.contents : `${hunk.contents}\n`
81
+ const next = Bom.split(newContent)
82
+ const diff = trimDiff(createTwoFilesPatch(filePath, filePath, oldContent, next.text))
83
+
84
+ let additions = 0
85
+ let deletions = 0
86
+ for (const change of diffLines(oldContent, next.text)) {
87
+ if (change.added) additions += change.count || 0
88
+ if (change.removed) deletions += change.count || 0
89
+ }
90
+
91
+ fileChanges.push({
92
+ filePath,
93
+ oldContent,
94
+ newContent: next.text,
95
+ type: "add",
96
+ diff,
97
+ additions,
98
+ deletions,
99
+ bom: next.bom,
100
+ })
101
+
102
+ totalDiff += diff + "\n"
103
+ break
104
+ }
105
+
106
+ case "update": {
107
+ // Check if file exists for update
108
+ const stats = yield* afs.stat(filePath).pipe(Effect.catch(() => Effect.succeed(undefined)))
109
+ if (!stats || stats.type === "Directory") {
110
+ return yield* Effect.fail(
111
+ new Error(`apply_patch verification failed: Failed to read file to update: ${filePath}`),
112
+ )
113
+ }
114
+
115
+ const source = yield* Bom.readFile(afs, filePath)
116
+ const oldContent = source.text
117
+ let newContent = oldContent
118
+ let bom = source.bom
119
+
120
+ // Apply the update chunks to get new content
121
+ try {
122
+ const fileUpdate = Patch.deriveNewContentsFromChunks(
123
+ filePath,
124
+ hunk.chunks,
125
+ Bom.join(source.text, source.bom),
126
+ )
127
+ newContent = fileUpdate.content
128
+ bom = fileUpdate.bom
129
+ } catch (error) {
130
+ return yield* Effect.fail(new Error(`apply_patch verification failed: ${error}`))
131
+ }
132
+
133
+ const diff = trimDiff(createTwoFilesPatch(filePath, filePath, oldContent, newContent))
134
+
135
+ let additions = 0
136
+ let deletions = 0
137
+ for (const change of diffLines(oldContent, newContent)) {
138
+ if (change.added) additions += change.count || 0
139
+ if (change.removed) deletions += change.count || 0
140
+ }
141
+
142
+ const movePath = hunk.move_path ? path.resolve(instance.directory, hunk.move_path) : undefined
143
+ yield* assertExternalDirectoryEffect(ctx, movePath)
144
+
145
+ fileChanges.push({
146
+ filePath,
147
+ oldContent,
148
+ newContent,
149
+ type: hunk.move_path ? "move" : "update",
150
+ movePath,
151
+ diff,
152
+ additions,
153
+ deletions,
154
+ bom,
155
+ })
156
+
157
+ totalDiff += diff + "\n"
158
+ break
159
+ }
160
+
161
+ case "delete": {
162
+ const source = yield* Bom.readFile(afs, filePath).pipe(
163
+ Effect.catch((error) =>
164
+ Effect.fail(
165
+ new Error(
166
+ `apply_patch verification failed: ${error instanceof Error ? error.message : String(error)}`,
167
+ ),
168
+ ),
169
+ ),
170
+ )
171
+ const contentToDelete = source.text
172
+ const deleteDiff = trimDiff(createTwoFilesPatch(filePath, filePath, contentToDelete, ""))
173
+
174
+ const deletions = contentToDelete.split("\n").length
175
+
176
+ fileChanges.push({
177
+ filePath,
178
+ oldContent: contentToDelete,
179
+ newContent: "",
180
+ type: "delete",
181
+ diff: deleteDiff,
182
+ additions: 0,
183
+ deletions,
184
+ bom: source.bom,
185
+ })
186
+
187
+ totalDiff += deleteDiff + "\n"
188
+ break
189
+ }
190
+ }
191
+ }
192
+
193
+ // Build per-file metadata for UI rendering (used for both permission and result)
194
+ const files = fileChanges.map((change) => ({
195
+ filePath: change.filePath,
196
+ relativePath: path.relative(instance.worktree, change.movePath ?? change.filePath).replaceAll("\\", "/"),
197
+ type: change.type,
198
+ patch: change.diff,
199
+ additions: change.additions,
200
+ deletions: change.deletions,
201
+ movePath: change.movePath,
202
+ }))
203
+
204
+ // Check permissions if needed
205
+ const relativePaths = fileChanges.map((c) => path.relative(instance.worktree, c.filePath).replaceAll("\\", "/"))
206
+ yield* ctx.ask({
207
+ permission: "edit",
208
+ patterns: relativePaths,
209
+ always: ["*"],
210
+ metadata: {
211
+ filepath: relativePaths.join(", "),
212
+ diff: totalDiff,
213
+ files,
214
+ },
215
+ })
216
+
217
+ // Apply the changes
218
+ const updates: Array<{ file: string; event: "add" | "change" | "unlink" }> = []
219
+
220
+ for (const change of fileChanges) {
221
+ const edited = change.type === "delete" ? undefined : (change.movePath ?? change.filePath)
222
+ switch (change.type) {
223
+ case "add":
224
+ // Create parent directories (recursive: true is safe on existing/root dirs)
225
+
226
+ yield* afs.writeWithDirs(change.filePath, Bom.join(change.newContent, change.bom))
227
+ updates.push({ file: change.filePath, event: "add" })
228
+ break
229
+
230
+ case "update":
231
+ yield* afs.writeWithDirs(change.filePath, Bom.join(change.newContent, change.bom))
232
+ updates.push({ file: change.filePath, event: "change" })
233
+ break
234
+
235
+ case "move":
236
+ if (change.movePath) {
237
+ // Create parent directories (recursive: true is safe on existing/root dirs)
238
+
239
+ yield* afs.writeWithDirs(change.movePath!, Bom.join(change.newContent, change.bom))
240
+ yield* afs.remove(change.filePath)
241
+ updates.push({ file: change.filePath, event: "unlink" })
242
+ updates.push({ file: change.movePath, event: "add" })
243
+ }
244
+ break
245
+
246
+ case "delete":
247
+ yield* afs.remove(change.filePath)
248
+ updates.push({ file: change.filePath, event: "unlink" })
249
+ break
250
+ }
251
+
252
+ if (edited) {
253
+ if (yield* format.file(edited)) {
254
+ yield* Bom.syncFile(afs, edited, change.bom)
255
+ }
256
+ yield* events.publish(FileSystem.Event.Edited, { file: edited })
257
+ }
258
+ }
259
+
260
+ // Publish file change events
261
+ for (const update of updates) {
262
+ yield* events.publish(Watcher.Event.Updated, update)
263
+ }
264
+
265
+ // Notify LSP of file changes and collect diagnostics
266
+ for (const change of fileChanges) {
267
+ if (change.type === "delete") continue
268
+ const target = change.movePath ?? change.filePath
269
+ yield* lsp.touchFile(target, "document")
270
+ }
271
+ const diagnostics = yield* lsp.diagnostics()
272
+
273
+ // Generate output summary
274
+ const summaryLines = fileChanges.map((change) => {
275
+ if (change.type === "add") {
276
+ return `A ${path.relative(instance.worktree, change.filePath).replaceAll("\\", "/")}`
277
+ }
278
+ if (change.type === "delete") {
279
+ return `D ${path.relative(instance.worktree, change.filePath).replaceAll("\\", "/")}`
280
+ }
281
+ const target = change.movePath ?? change.filePath
282
+ return `M ${path.relative(instance.worktree, target).replaceAll("\\", "/")}`
283
+ })
284
+ let output = `Success. Updated the following files:\n${summaryLines.join("\n")}`
285
+
286
+ for (const change of fileChanges) {
287
+ if (change.type === "delete") continue
288
+ const target = change.movePath ?? change.filePath
289
+ const block = LSP.Diagnostic.report(target, diagnostics[FSUtil.normalizePath(target)] ?? [])
290
+ if (!block) continue
291
+ const rel = path.relative(instance.worktree, target).replaceAll("\\", "/")
292
+ output += `\n\nLSP errors detected in ${rel}, please fix:\n${block}`
293
+ }
294
+
295
+ return {
296
+ title: output,
297
+ metadata: {
298
+ diff: totalDiff,
299
+ files,
300
+ diagnostics,
301
+ },
302
+ output,
303
+ }
304
+ })
305
+
306
+ return {
307
+ description: DESCRIPTION,
308
+ parameters: Parameters,
309
+ execute: (params: Schema.Schema.Type<typeof Parameters>, ctx: Tool.Context) =>
310
+ run(params, ctx).pipe(Effect.orDie),
311
+ }
312
+ }),
313
+ )