@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,294 @@
1
+ export * as TuiConfig from "./tui"
2
+
3
+ import path from "path"
4
+ import { mergeDeep, unique } from "remeda"
5
+ import { Cause, Context, Effect, Fiber, Layer } from "effect"
6
+ import { ConfigParse } from "@/config/parse"
7
+ import * as ConfigPaths from "@/config/paths"
8
+ import { migrateTuiConfig } from "./tui-migrate"
9
+ import { resolveHostAttentionSoundPaths } from "./tui-host-attention"
10
+ import { Flag } from "@octocode-ai/core/flag/flag"
11
+ import { isRecord } from "@octocode-ai/tui/util/record"
12
+ import { Global } from "@octocode-ai/core/global"
13
+ import { FSUtil } from "@octocode-ai/core/fs-util"
14
+ import { CurrentWorkingDirectory } from "./tui-cwd"
15
+ import { ConfigPlugin } from "@/config/plugin"
16
+ import { TuiKeybind } from "@octocode-ai/tui/config/keybind"
17
+ import { InstallationLocal, InstallationVersion } from "@octocode-ai/core/installation/version"
18
+ import { makeRuntime } from "@octocode-ai/core/effect/runtime"
19
+ import { Filesystem } from "@/util/filesystem"
20
+ import * as Log from "@octocode-ai/core/util/log"
21
+ import { ConfigVariable } from "@/config/variable"
22
+ import { Npm } from "@octocode-ai/core/npm"
23
+ import { FormatError, FormatUnknownError } from "@/cli/error"
24
+ import { TuiConfig } from "@octocode-ai/tui/config"
25
+
26
+ const log = Log.create({ service: "tui.config" })
27
+
28
+ export const Info = TuiConfig.Info
29
+ export type Info = TuiConfig.Info
30
+
31
+ type Acc = {
32
+ result: Info
33
+ plugin_origins: ConfigPlugin.Origin[]
34
+ }
35
+
36
+ export type Resolved = TuiConfig.Resolved
37
+
38
+ export type HostMetadata = {
39
+ plugin_origins?: ConfigPlugin.Origin[]
40
+ }
41
+
42
+ export interface Interface {
43
+ readonly get: () => Effect.Effect<Resolved>
44
+ readonly pluginOrigins: () => Effect.Effect<ConfigPlugin.Origin[]>
45
+ readonly waitForDependencies: () => Effect.Effect<void>
46
+ }
47
+
48
+ export class Service extends Context.Service<Service, Interface>()("@octocode/TuiConfig") {}
49
+
50
+ function pluginScope(file: string, ctx: { directory: string }): ConfigPlugin.Scope {
51
+ if (Filesystem.contains(ctx.directory, file)) return "local"
52
+ // if (ctx.worktree !== "/" && Filesystem.contains(ctx.worktree, file)) return "local"
53
+ return "global"
54
+ }
55
+
56
+ function normalize(raw: Record<string, unknown>) {
57
+ const data = { ...raw }
58
+ if (!("tui" in data)) return data
59
+ if (!isRecord(data.tui)) {
60
+ delete data.tui
61
+ return data
62
+ }
63
+
64
+ const tui = data.tui
65
+ delete data.tui
66
+ return {
67
+ ...tui,
68
+ ...data,
69
+ }
70
+ }
71
+
72
+ function dropUnknownKeybinds(input: Record<string, unknown>, configFilepath: string) {
73
+ if (!isRecord(input.keybinds)) return input
74
+
75
+ const invalid = TuiKeybind.unknownKeys(input.keybinds)
76
+ if (!invalid.length) return input
77
+
78
+ log.warn("ignored unknown tui keybinds", {
79
+ path: configFilepath,
80
+ keybinds: invalid,
81
+ hint: "Remove these entries or rename them to keys from the tui.json schema.",
82
+ })
83
+ return {
84
+ ...input,
85
+ keybinds: Object.fromEntries(Object.entries(input.keybinds).filter(([key]) => !invalid.includes(key))),
86
+ }
87
+ }
88
+
89
+ const loadState = Effect.fn("TuiConfig.loadState")(function* (ctx: { directory: string }) {
90
+ const afs = yield* FSUtil.Service
91
+ let appliedOrder = 0
92
+
93
+ const resolvePlugins = (config: Info, configFilepath: string): Effect.Effect<Info> =>
94
+ Effect.gen(function* () {
95
+ const plugins = config.plugin
96
+ if (!plugins) return config
97
+ return {
98
+ ...config,
99
+ plugin: yield* Effect.forEach(plugins, (plugin) =>
100
+ Effect.promise(() => ConfigPlugin.resolvePluginSpec(plugin as ConfigPlugin.Origin["spec"], configFilepath)),
101
+ ),
102
+ }
103
+ })
104
+
105
+ const load = (text: string, configFilepath: string): Effect.Effect<Info> =>
106
+ Effect.gen(function* () {
107
+ const expanded = yield* Effect.promise(() =>
108
+ ConfigVariable.substitute({ text, type: "path", path: configFilepath, missing: "empty" }),
109
+ )
110
+ const data = ConfigParse.jsonc(expanded, configFilepath)
111
+ if (!isRecord(data)) return {} as Info
112
+ // Flatten a nested "tui" key so users who wrote `{ "tui": { ... } }` inside tui.json
113
+ // (mirroring the old octo/octocode config shape) still get their settings applied.
114
+ const normalized = dropUnknownKeybinds(normalize(data), configFilepath)
115
+ const parsed = ConfigParse.schema(Info, normalized, configFilepath)
116
+ const validated = parsed.attention?.sounds
117
+ ? {
118
+ ...parsed,
119
+ attention: {
120
+ ...parsed.attention,
121
+ sounds: resolveHostAttentionSoundPaths(path.dirname(configFilepath), parsed.attention.sounds),
122
+ },
123
+ }
124
+ : parsed
125
+ return yield* resolvePlugins(validated, configFilepath)
126
+ }).pipe(
127
+ // catchCause (not tapErrorCause + orElseSucceed) because JSONC parsing and validation
128
+ // can sync-throw — those become defects, which orElseSucceed wouldn't catch.
129
+ Effect.catchCause((cause) =>
130
+ Effect.sync(() => {
131
+ const error = Cause.squash(cause)
132
+ const reason = FormatError(error) ?? FormatUnknownError(error)
133
+ log.warn("skipping invalid tui config", {
134
+ path: configFilepath,
135
+ reason,
136
+ })
137
+ return {} as Info
138
+ }),
139
+ ),
140
+ )
141
+
142
+ const loadFile = (filepath: string): Effect.Effect<Info> =>
143
+ Effect.gen(function* () {
144
+ // Silent-swallow non-NotFound read errors (perms, EISDIR, IO) → log + skip.
145
+ // Matches how parse/schema/plugin failures in load() are handled — every
146
+ // broken-config path degrades gracefully rather than crashing TUI startup.
147
+ const text = yield* afs.readFileStringSafe(filepath).pipe(
148
+ Effect.catchCause((cause) =>
149
+ Effect.sync(() => {
150
+ const error = Cause.squash(cause)
151
+ const reason = FormatError(error) ?? FormatUnknownError(error)
152
+ log.warn("failed to read tui config", {
153
+ path: filepath,
154
+ reason,
155
+ })
156
+ return undefined
157
+ }),
158
+ ),
159
+ )
160
+ if (!text) return {} as Info
161
+ log.info("loading tui config", { path: filepath })
162
+ return yield* load(text, filepath)
163
+ })
164
+
165
+ const mergeFile = (acc: Acc, file: string) =>
166
+ Effect.gen(function* () {
167
+ const data = yield* loadFile(file)
168
+ if (Object.keys(data).length) {
169
+ appliedOrder += 1
170
+ log.info("applying tui config", { path: file, order: appliedOrder })
171
+ }
172
+ acc.result = mergeDeep(acc.result, data)
173
+ if (!data.plugin?.length) return
174
+
175
+ const scope = pluginScope(file, ctx)
176
+ const plugins = ConfigPlugin.deduplicatePluginOrigins([
177
+ ...acc.plugin_origins,
178
+ ...data.plugin.map((spec) => ({ spec: spec as ConfigPlugin.Origin["spec"], scope, source: file })),
179
+ ])
180
+ acc.result = {
181
+ ...acc.result,
182
+ plugin: plugins.map((item) => item.spec),
183
+ }
184
+ acc.plugin_origins = plugins
185
+ })
186
+
187
+ // Every config dir we may read from: global config dir, any `.octo`/`.octocode`
188
+ // folders between cwd and home, and OCTOCODE_CONFIG_DIR.
189
+ const directories = yield* ConfigPaths.directories(ctx.directory)
190
+ yield* Effect.promise(() => migrateTuiConfig({ directories, cwd: ctx.directory }))
191
+
192
+ const projectFiles = Flag.OCTOCODE_DISABLE_PROJECT_CONFIG ? [] : yield* ConfigPaths.files("tui", ctx.directory)
193
+
194
+ const acc: Acc = {
195
+ result: {},
196
+ plugin_origins: [],
197
+ }
198
+
199
+ // 1. Global tui config (lowest precedence).
200
+ for (const file of ConfigPaths.fileInDirectory(Global.Path.config, "tui")) {
201
+ yield* mergeFile(acc, file)
202
+ }
203
+
204
+ // 2. Explicit OCTOCODE_TUI_CONFIG override, if set.
205
+ if (Flag.OCTOCODE_TUI_CONFIG) {
206
+ const configFile = Flag.OCTOCODE_TUI_CONFIG
207
+ yield* mergeFile(acc, configFile)
208
+ log.debug("loaded custom tui config", { path: configFile })
209
+ }
210
+
211
+ // 3. Project tui files, applied root-first so the closest file wins.
212
+ for (const file of projectFiles) {
213
+ yield* mergeFile(acc, file)
214
+ }
215
+
216
+ // 4. `.octo`/`.octocode` directories (and OCTOCODE_CONFIG_DIR) discovered while
217
+ // walking up the tree. Also returned below so callers can install plugin
218
+ // dependencies from each location.
219
+ const dirs = unique(directories).filter(
220
+ (dir) => dir.endsWith(".octo") || dir.endsWith(".octocode") || dir === Flag.OCTOCODE_CONFIG_DIR,
221
+ )
222
+
223
+ for (const dir of dirs) {
224
+ if (!dir.endsWith(".octo") && !dir.endsWith(".octocode") && dir !== Flag.OCTOCODE_CONFIG_DIR) continue
225
+ for (const file of ConfigPaths.fileInDirectory(dir, "tui")) {
226
+ yield* mergeFile(acc, file)
227
+ }
228
+ }
229
+
230
+ const result = TuiConfig.resolve(
231
+ {
232
+ ...acc.result,
233
+ },
234
+ {
235
+ terminalSuspend: process.platform !== "win32",
236
+ },
237
+ )
238
+
239
+ return {
240
+ config: result,
241
+ pluginOrigins: acc.plugin_origins,
242
+ dirs: result.plugin?.length ? dirs : [],
243
+ }
244
+ })
245
+
246
+ export const layer = Layer.effect(
247
+ Service,
248
+ Effect.gen(function* () {
249
+ const directory = yield* CurrentWorkingDirectory
250
+ const npm = yield* Npm.Service
251
+ const data = yield* loadState({ directory })
252
+ const deps = yield* Effect.forEach(
253
+ data.dirs,
254
+ (dir) =>
255
+ npm
256
+ .install(dir, {
257
+ add: [
258
+ {
259
+ name: "@octocode-ai/plugin",
260
+ version: InstallationLocal ? undefined : InstallationVersion,
261
+ },
262
+ ],
263
+ })
264
+ .pipe(Effect.forkScoped),
265
+ {
266
+ concurrency: "unbounded",
267
+ },
268
+ )
269
+
270
+ const get = Effect.fn("TuiConfig.get")(() => Effect.succeed(data.config))
271
+ const pluginOrigins = Effect.fn("TuiConfig.pluginOrigins")(() => Effect.succeed(data.pluginOrigins))
272
+
273
+ const waitForDependencies = Effect.fn("TuiConfig.waitForDependencies")(() =>
274
+ Effect.forEach(deps, Fiber.join, { concurrency: "unbounded" }).pipe(Effect.ignore(), Effect.asVoid),
275
+ )
276
+ return Service.of({ get, pluginOrigins, waitForDependencies })
277
+ }).pipe(Effect.withSpan("TuiConfig.layer")),
278
+ )
279
+
280
+ export const defaultLayer = layer.pipe(Layer.provide(Npm.defaultLayer), Layer.provide(FSUtil.defaultLayer))
281
+
282
+ const { runPromise } = makeRuntime(Service, defaultLayer)
283
+
284
+ export async function waitForDependencies() {
285
+ await runPromise((svc) => svc.waitForDependencies())
286
+ }
287
+
288
+ export async function get() {
289
+ return runPromise((svc) => svc.get())
290
+ }
291
+
292
+ export async function pluginOrigins() {
293
+ return runPromise((svc) => svc.pluginOrigins())
294
+ }
@@ -0,0 +1,91 @@
1
+ export * as ConfigVariable from "./variable"
2
+
3
+ import path from "path"
4
+ import os from "os"
5
+ import { Filesystem } from "@/util/filesystem"
6
+ import { InvalidError } from "@octocode-ai/core/v1/config/error"
7
+
8
+ type ParseSource =
9
+ | {
10
+ type: "path"
11
+ path: string
12
+ }
13
+ | {
14
+ type: "virtual"
15
+ source: string
16
+ dir: string
17
+ }
18
+
19
+ type SubstituteInput = ParseSource & {
20
+ text: string
21
+ missing?: "error" | "empty"
22
+ env?: Record<string, string>
23
+ }
24
+
25
+ function source(input: ParseSource) {
26
+ return input.type === "path" ? input.path : input.source
27
+ }
28
+
29
+ function dir(input: ParseSource) {
30
+ return input.type === "path" ? path.dirname(input.path) : input.dir
31
+ }
32
+
33
+ /** Apply {env:VAR} and {file:path} substitutions to config text. */
34
+ export async function substitute(input: SubstituteInput) {
35
+ const missing = input.missing ?? "error"
36
+ let text = input.text.replace(/\{env:([^}]+)\}/g, (_, varName) => {
37
+ return (input.env?.[varName] ?? process.env[varName]) || ""
38
+ })
39
+
40
+ const fileMatches = Array.from(text.matchAll(/\{file:[^}]+\}/g))
41
+ if (!fileMatches.length) return text
42
+
43
+ const configDir = dir(input)
44
+ const configSource = source(input)
45
+ let out = ""
46
+ let cursor = 0
47
+
48
+ for (const match of fileMatches) {
49
+ const token = match[0]
50
+ const index = match.index
51
+ out += text.slice(cursor, index)
52
+
53
+ const lineStart = text.lastIndexOf("\n", index - 1) + 1
54
+ const prefix = text.slice(lineStart, index).trimStart()
55
+ if (prefix.startsWith("//")) {
56
+ out += token
57
+ cursor = index + token.length
58
+ continue
59
+ }
60
+
61
+ let filePath = token.replace(/^\{file:/, "").replace(/\}$/, "")
62
+ if (filePath.startsWith("~/")) {
63
+ filePath = path.join(os.homedir(), filePath.slice(2))
64
+ }
65
+
66
+ const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath)
67
+ const fileContent = (
68
+ await Filesystem.readText(resolvedPath).catch((error: NodeJS.ErrnoException) => {
69
+ if (missing === "empty") return ""
70
+
71
+ const errMsg = `bad file reference: "${token}"`
72
+ if (error.code === "ENOENT") {
73
+ throw new InvalidError(
74
+ {
75
+ path: configSource,
76
+ message: errMsg + ` ${resolvedPath} does not exist`,
77
+ },
78
+ { cause: error },
79
+ )
80
+ }
81
+ throw new InvalidError({ path: configSource, message: errMsg }, { cause: error })
82
+ })
83
+ ).trim()
84
+
85
+ out += JSON.stringify(fileContent).slice(1, -1)
86
+ cursor = index + token.length
87
+ }
88
+
89
+ out += text.slice(cursor)
90
+ return out
91
+ }
@@ -0,0 +1,41 @@
1
+ import type { ProjectV2 } from "@octocode-ai/core/project"
2
+ import type { WorkspaceAdapter, WorkspaceAdapterEntry } from "../types"
3
+ import { WorktreeAdapter } from "./worktree"
4
+
5
+ const BUILTIN: Record<string, WorkspaceAdapter> = {
6
+ worktree: WorktreeAdapter,
7
+ }
8
+
9
+ const state = new Map<ProjectV2.ID, Map<string, WorkspaceAdapter>>()
10
+
11
+ export function getAdapter(projectID: ProjectV2.ID, type: string): WorkspaceAdapter {
12
+ const custom = state.get(projectID)?.get(type)
13
+ if (custom) return custom
14
+
15
+ const builtin = BUILTIN[type]
16
+ if (builtin) return builtin
17
+
18
+ throw new Error(`Unknown workspace adapter: ${type}`)
19
+ }
20
+
21
+ export function listAdapters(projectID: ProjectV2.ID): WorkspaceAdapterEntry[] {
22
+ return registeredAdapters(projectID).map(([type, adapter]) => ({
23
+ type,
24
+ name: adapter.name,
25
+ description: adapter.description,
26
+ }))
27
+ }
28
+
29
+ export function registeredAdapters(projectID: ProjectV2.ID): [string, WorkspaceAdapter][] {
30
+ const adapters = new Map(Object.entries(BUILTIN))
31
+ for (const [type, adapter] of state.get(projectID)?.entries() ?? []) adapters.set(type, adapter)
32
+ return [...adapters.entries()]
33
+ }
34
+
35
+ // Plugins can be loaded per-project so we need to scope them. If you
36
+ // want to install a global one pass `ProjectV2.ID.global`
37
+ export function registerAdapter(projectID: ProjectV2.ID, type: string, adapter: WorkspaceAdapter) {
38
+ const adapters = state.get(projectID) ?? new Map<string, WorkspaceAdapter>()
39
+ adapters.set(type, adapter)
40
+ state.set(projectID, adapters)
41
+ }
@@ -0,0 +1,96 @@
1
+ import { Effect, Schema } from "effect"
2
+ import { InstanceRef, WorkspaceRef } from "@/effect/instance-ref"
3
+ import { type WorkspaceAdapter, type WorkspaceAdapterContext, WorkspaceInfo } from "../types"
4
+
5
+ const WorktreeConfig = Schema.Struct({
6
+ name: WorkspaceInfo.fields.name,
7
+ branch: Schema.optional(Schema.NullOr(Schema.String)),
8
+ directory: Schema.String,
9
+ })
10
+ const decodeWorktreeConfig = Schema.decodeUnknownSync(WorktreeConfig)
11
+
12
+ async function loadWorktree() {
13
+ const [{ AppRuntime }, { Worktree }] = await Promise.all([import("@/effect/app-runtime"), import("@/worktree")])
14
+ return { AppRuntime, Worktree }
15
+ }
16
+
17
+ function requireInstance(context: WorkspaceAdapterContext | undefined) {
18
+ if (!context?.instance) throw new Error("Worktree adapter requires an instance context")
19
+ return context.instance
20
+ }
21
+
22
+ const provideContext = <A, E, R>(effect: Effect.Effect<A, E, R>, context: WorkspaceAdapterContext | undefined) =>
23
+ effect.pipe(
24
+ Effect.provideService(InstanceRef, requireInstance(context)),
25
+ Effect.provideService(WorkspaceRef, context?.workspaceID),
26
+ )
27
+
28
+ export const WorktreeAdapter: WorkspaceAdapter = {
29
+ name: "Worktree",
30
+ description: "Create a git worktree",
31
+ async configure(info, context) {
32
+ const { AppRuntime, Worktree } = await loadWorktree()
33
+ const next = await AppRuntime.runPromise(
34
+ provideContext(
35
+ Worktree.Service.use((svc) => svc.makeWorktreeInfo({ detached: true })),
36
+ context,
37
+ ),
38
+ )
39
+ return {
40
+ ...info,
41
+ name: next.name,
42
+ directory: next.directory,
43
+ }
44
+ },
45
+ async create(info, _env, _from, context) {
46
+ const { AppRuntime, Worktree } = await loadWorktree()
47
+ const config = decodeWorktreeConfig(info)
48
+ await AppRuntime.runPromise(
49
+ provideContext(
50
+ Worktree.Service.use((svc) =>
51
+ svc.createFromInfo({
52
+ name: config.name,
53
+ directory: config.directory,
54
+ ...(config.branch ? { branch: config.branch } : {}),
55
+ }),
56
+ ),
57
+ context,
58
+ ),
59
+ )
60
+ },
61
+ async list(context) {
62
+ const { AppRuntime, Worktree } = await loadWorktree()
63
+ const ctx = requireInstance(context)
64
+ return (
65
+ await AppRuntime.runPromise(
66
+ provideContext(
67
+ Worktree.Service.use((svc) => svc.list()),
68
+ context,
69
+ ),
70
+ )
71
+ ).map((info) => ({
72
+ type: "worktree",
73
+ name: info.name,
74
+ branch: info.branch,
75
+ directory: info.directory,
76
+ projectID: ctx.project.id,
77
+ }))
78
+ },
79
+ async remove(info, context) {
80
+ const { AppRuntime, Worktree } = await loadWorktree()
81
+ const config = decodeWorktreeConfig(info)
82
+ await AppRuntime.runPromise(
83
+ provideContext(
84
+ Worktree.Service.use((svc) => svc.remove({ directory: config.directory })),
85
+ context,
86
+ ),
87
+ )
88
+ },
89
+ target(info) {
90
+ const config = decodeWorktreeConfig(info)
91
+ return {
92
+ type: "local",
93
+ directory: config.directory,
94
+ }
95
+ },
96
+ }
@@ -0,0 +1,19 @@
1
+ This is a plugin to simulate a remote environment locally. Add this to `.octo/octo.jsonc`:
2
+
3
+ ```json
4
+ "plugin": ["../packages/octocode/src/control-plane/dev/debug-workspace-plugin.ts"],
5
+ ```
6
+
7
+ In a separate terminal, run a separate octo code server. This will act like a remote server and the local instance will proxy all requests to it:
8
+
9
+ ```
10
+ ./packages/octocode/script/run-workspace-server
11
+ ```
12
+
13
+ With the plugin install, you can now run octo code and create a `debug` workspace type. This will create a "remote" workspace which talks to the second workspace server started above.
14
+
15
+ How this works:
16
+
17
+ - The workspace server needs to know the workspace id and port to run. It waits for this information to be written to a file and starts the server when the data is written.
18
+ - The debug plugin writes this information in the `create` call to the workspace. So create a `debug` workspace will always kick off a new external server.
19
+ - The server script watches for file changes, so whenver you create a new `debug` workspace it will restart with the new information. This means that there is only ever one working `debug` workspace at a time; when you create a new one all previous sessions will show that it can't connect because previous debug workspaces do not exist.
@@ -0,0 +1,73 @@
1
+ import type { Plugin } from "@octocode-ai/plugin"
2
+ import { rename, writeFile } from "node:fs/promises"
3
+ import { randomInt } from "node:crypto"
4
+ import { setTimeout as sleep } from "node:timers/promises"
5
+
6
+ const DEV_DATA_FILE = "/tmp/octocode-workspace-dev-data.json"
7
+ const DEV_DATA_TEMP_FILE = `${DEV_DATA_FILE}.tmp`
8
+
9
+ async function waitForHealth(port: number) {
10
+ const url = `http://127.0.0.1:${port}/global/health`
11
+ const started = Date.now()
12
+
13
+ while (Date.now() - started < 30_000) {
14
+ try {
15
+ const response = await fetch(url)
16
+ if (response.ok) {
17
+ return
18
+ }
19
+ } catch {}
20
+
21
+ await sleep(250)
22
+ }
23
+
24
+ throw new Error(`Timed out waiting for debug server health check at ${url}`)
25
+ }
26
+
27
+ let PORT: number | undefined
28
+
29
+ async function writeDebugData(port: number, id: string, env: Record<string, string | undefined>) {
30
+ await writeFile(
31
+ DEV_DATA_TEMP_FILE,
32
+ JSON.stringify(
33
+ {
34
+ port,
35
+ id,
36
+ env,
37
+ },
38
+ null,
39
+ 2,
40
+ ),
41
+ )
42
+
43
+ await rename(DEV_DATA_TEMP_FILE, DEV_DATA_FILE)
44
+ }
45
+
46
+ export const DebugWorkspacePlugin: Plugin = async ({ experimental_workspace }) => {
47
+ experimental_workspace.register("debug", {
48
+ name: "Debug",
49
+ description: "Create a debugging server",
50
+ configure(config) {
51
+ return config
52
+ },
53
+ async create(config, env) {
54
+ const port = randomInt(5000, 9001)
55
+ PORT = port
56
+
57
+ await writeDebugData(port, config.id, env)
58
+
59
+ await waitForHealth(port)
60
+ },
61
+ async remove(_config) {},
62
+ target(_config) {
63
+ return {
64
+ type: "remote",
65
+ url: `http://localhost:${PORT!}/`,
66
+ }
67
+ },
68
+ })
69
+
70
+ return {}
71
+ }
72
+
73
+ export default DebugWorkspacePlugin
@@ -0,0 +1,59 @@
1
+ import { Schema, Struct } from "effect"
2
+ import { ProjectV2 } from "@octocode-ai/core/project"
3
+ import type { InstanceContext } from "@/project/instance-context"
4
+ import { WorkspaceV2 } from "@octocode-ai/core/workspace"
5
+ import type { DeepMutable } from "@octocode-ai/core/schema"
6
+
7
+ export const WorkspaceInfo = Schema.Struct({
8
+ id: WorkspaceV2.ID,
9
+ type: Schema.String,
10
+ name: Schema.String,
11
+ branch: Schema.optional(Schema.NullOr(Schema.String)),
12
+ directory: Schema.optional(Schema.NullOr(Schema.String)),
13
+ extra: Schema.optional(Schema.NullOr(Schema.Unknown)),
14
+ projectID: ProjectV2.ID,
15
+ }).annotate({ identifier: "Workspace" })
16
+ export type WorkspaceInfo = DeepMutable<Schema.Schema.Type<typeof WorkspaceInfo>>
17
+
18
+ export const WorkspaceListedInfo = Schema.Struct(Struct.omit(WorkspaceInfo.fields, ["id"])).annotate({
19
+ identifier: "WorkspaceListedInfo",
20
+ })
21
+ export type WorkspaceListedInfo = DeepMutable<Schema.Schema.Type<typeof WorkspaceListedInfo>>
22
+
23
+ export const WorkspaceAdapterEntry = Schema.Struct({
24
+ type: Schema.String,
25
+ name: Schema.String,
26
+ description: Schema.String,
27
+ })
28
+ export type WorkspaceAdapterEntry = Schema.Schema.Type<typeof WorkspaceAdapterEntry>
29
+
30
+ export type Target =
31
+ | {
32
+ type: "local"
33
+ directory: string
34
+ }
35
+ | {
36
+ type: "remote"
37
+ url: string | URL
38
+ headers?: HeadersInit
39
+ }
40
+
41
+ export type WorkspaceAdapterContext = {
42
+ readonly instance?: InstanceContext
43
+ readonly workspaceID?: WorkspaceV2.ID
44
+ }
45
+
46
+ export type WorkspaceAdapter = {
47
+ name: string
48
+ description: string
49
+ configure(info: WorkspaceInfo, context?: WorkspaceAdapterContext): WorkspaceInfo | Promise<WorkspaceInfo>
50
+ create(
51
+ info: WorkspaceInfo,
52
+ env: Record<string, string | undefined>,
53
+ from?: WorkspaceInfo,
54
+ context?: WorkspaceAdapterContext,
55
+ ): Promise<void>
56
+ list?(context?: WorkspaceAdapterContext): WorkspaceListedInfo[] | Promise<WorkspaceListedInfo[]>
57
+ remove(info: WorkspaceInfo, context?: WorkspaceAdapterContext): Promise<void>
58
+ target(info: WorkspaceInfo, context?: WorkspaceAdapterContext): Target | Promise<Target>
59
+ }