@vikasitai/vikasit-code 2.0.4 → 2.0.5

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 (711) hide show
  1. package/AGENTS.md +69 -0
  2. package/BUN_SHELL_MIGRATION_PLAN.md +136 -0
  3. package/Dockerfile +18 -0
  4. package/README.md +15 -0
  5. package/bunfig.toml +7 -0
  6. package/drizzle.config.ts +10 -0
  7. package/git +0 -0
  8. package/migration/20260127222353_familiar_lady_ursula/migration.sql +90 -0
  9. package/migration/20260127222353_familiar_lady_ursula/snapshot.json +796 -0
  10. package/migration/20260211171708_add_project_commands/migration.sql +1 -0
  11. package/migration/20260211171708_add_project_commands/snapshot.json +806 -0
  12. package/migration/20260213144116_wakeful_the_professor/migration.sql +11 -0
  13. package/migration/20260213144116_wakeful_the_professor/snapshot.json +897 -0
  14. package/migration/20260225215848_workspace/migration.sql +7 -0
  15. package/migration/20260225215848_workspace/snapshot.json +959 -0
  16. package/migration/20260227213759_add_session_workspace_id/migration.sql +2 -0
  17. package/migration/20260227213759_add_session_workspace_id/snapshot.json +983 -0
  18. package/migration/20260228203230_blue_harpoon/migration.sql +17 -0
  19. package/migration/20260228203230_blue_harpoon/snapshot.json +1102 -0
  20. package/migration/20260303231226_add_workspace_fields/migration.sql +5 -0
  21. package/migration/20260303231226_add_workspace_fields/snapshot.json +1013 -0
  22. package/migration/20260309230000_move_org_to_state/migration.sql +3 -0
  23. package/migration/20260309230000_move_org_to_state/snapshot.json +1156 -0
  24. package/migration/20260312043431_session_message_cursor/migration.sql +4 -0
  25. package/migration/20260312043431_session_message_cursor/snapshot.json +1168 -0
  26. package/migration/20260323234822_events/migration.sql +13 -0
  27. package/migration/20260323234822_events/snapshot.json +1271 -0
  28. package/package.json +170 -17
  29. package/parsers-config.ts +290 -0
  30. package/script/build-all.sh +40 -0
  31. package/script/build-node.ts +54 -0
  32. package/script/build.ts +281 -0
  33. package/script/check-migrations.ts +16 -0
  34. package/script/fetch-models.ts +101 -0
  35. package/script/publish.ts +184 -0
  36. package/script/schema.ts +63 -0
  37. package/script/seed-e2e.ts +75 -0
  38. package/script/upgrade-opentui.ts +64 -0
  39. package/specs/claude-code-integration.md +563 -0
  40. package/specs/effect-migration.md +291 -0
  41. package/specs/tui-plugins.md +410 -0
  42. package/src/account/account.sql.ts +39 -0
  43. package/src/account/index.ts +397 -0
  44. package/src/account/repo.ts +163 -0
  45. package/src/account/schema.ts +91 -0
  46. package/src/acp/README.md +174 -0
  47. package/src/acp/agent.ts +1743 -0
  48. package/src/acp/session.ts +116 -0
  49. package/src/acp/types.ts +24 -0
  50. package/src/agent/agent-display.ts +82 -0
  51. package/src/agent/agent.ts +475 -0
  52. package/src/agent/extract-names.cjs +42 -0
  53. package/src/agent/generate.txt +75 -0
  54. package/src/agent/mailbox.ts +124 -0
  55. package/src/agent/orchestrator.ts +170 -0
  56. package/src/agent/prompt/code-reviewer.txt +11 -0
  57. package/src/agent/prompt/compaction.txt +14 -0
  58. package/src/agent/prompt/explore.txt +18 -0
  59. package/src/agent/prompt/general.txt +17 -0
  60. package/src/agent/prompt/summary.txt +11 -0
  61. package/src/agent/prompt/title.txt +44 -0
  62. package/src/agent/prompt/verification.txt +11 -0
  63. package/src/auth/index.ts +109 -0
  64. package/src/bun/index.ts +129 -0
  65. package/src/bun/registry.ts +50 -0
  66. package/src/bus/bus-event.ts +40 -0
  67. package/src/bus/global.ts +10 -0
  68. package/src/bus/index.ts +184 -0
  69. package/src/cli/bootstrap.ts +17 -0
  70. package/src/cli/cmd/account.ts +257 -0
  71. package/src/cli/cmd/acp.ts +70 -0
  72. package/src/cli/cmd/agent.ts +245 -0
  73. package/src/cli/cmd/auto-updater.ts +71 -0
  74. package/src/cli/cmd/cmd.ts +7 -0
  75. package/src/cli/cmd/db.ts +119 -0
  76. package/src/cli/cmd/debug/agent.ts +167 -0
  77. package/src/cli/cmd/debug/config.ts +16 -0
  78. package/src/cli/cmd/debug/file.ts +97 -0
  79. package/src/cli/cmd/debug/index.ts +48 -0
  80. package/src/cli/cmd/debug/lsp.ts +53 -0
  81. package/src/cli/cmd/debug/ripgrep.ts +87 -0
  82. package/src/cli/cmd/debug/scrap.ts +16 -0
  83. package/src/cli/cmd/debug/skill.ts +16 -0
  84. package/src/cli/cmd/debug/snapshot.ts +52 -0
  85. package/src/cli/cmd/export.ts +89 -0
  86. package/src/cli/cmd/generate.ts +38 -0
  87. package/src/cli/cmd/github.ts +1646 -0
  88. package/src/cli/cmd/import.ts +207 -0
  89. package/src/cli/cmd/mcp.ts +754 -0
  90. package/src/cli/cmd/models.ts +78 -0
  91. package/src/cli/cmd/plug.ts +231 -0
  92. package/src/cli/cmd/pr.ts +127 -0
  93. package/src/cli/cmd/providers.ts +484 -0
  94. package/src/cli/cmd/run.ts +676 -0
  95. package/src/cli/cmd/search.ts +137 -0
  96. package/src/cli/cmd/serve.ts +24 -0
  97. package/src/cli/cmd/session.ts +159 -0
  98. package/src/cli/cmd/stats.ts +405 -0
  99. package/src/cli/cmd/tui/app.tsx +996 -0
  100. package/src/cli/cmd/tui/attach.ts +88 -0
  101. package/src/cli/cmd/tui/component/border.tsx +21 -0
  102. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  103. package/src/cli/cmd/tui/component/dialog-command.tsx +171 -0
  104. package/src/cli/cmd/tui/component/dialog-login.tsx +156 -0
  105. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  106. package/src/cli/cmd/tui/component/dialog-model.tsx +179 -0
  107. package/src/cli/cmd/tui/component/dialog-provider.tsx +329 -0
  108. package/src/cli/cmd/tui/component/dialog-session-list.tsx +108 -0
  109. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  110. package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
  111. package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
  112. package/src/cli/cmd/tui/component/dialog-status.tsx +168 -0
  113. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  114. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  115. package/src/cli/cmd/tui/component/dialog-variant.tsx +39 -0
  116. package/src/cli/cmd/tui/component/dialog-workspace-list.tsx +320 -0
  117. package/src/cli/cmd/tui/component/error-component.tsx +91 -0
  118. package/src/cli/cmd/tui/component/login-gate.tsx +125 -0
  119. package/src/cli/cmd/tui/component/logo.tsx +85 -0
  120. package/src/cli/cmd/tui/component/plugin-route-missing.tsx +14 -0
  121. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +667 -0
  122. package/src/cli/cmd/tui/component/prompt/frecency.tsx +90 -0
  123. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  124. package/src/cli/cmd/tui/component/prompt/index.tsx +1224 -0
  125. package/src/cli/cmd/tui/component/prompt/part.ts +16 -0
  126. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  127. package/src/cli/cmd/tui/component/spinner.tsx +24 -0
  128. package/src/cli/cmd/tui/component/startup-loading.tsx +63 -0
  129. package/src/cli/cmd/tui/component/status-bar.ts +54 -0
  130. package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
  131. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  132. package/src/cli/cmd/tui/component/workspace/dialog-session-list.tsx +151 -0
  133. package/src/cli/cmd/tui/context/args.tsx +15 -0
  134. package/src/cli/cmd/tui/context/directory.ts +13 -0
  135. package/src/cli/cmd/tui/context/exit.tsx +60 -0
  136. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  137. package/src/cli/cmd/tui/context/keybind.tsx +105 -0
  138. package/src/cli/cmd/tui/context/kv.tsx +52 -0
  139. package/src/cli/cmd/tui/context/local.tsx +412 -0
  140. package/src/cli/cmd/tui/context/plugin-keybinds.ts +41 -0
  141. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  142. package/src/cli/cmd/tui/context/route.tsx +52 -0
  143. package/src/cli/cmd/tui/context/sdk.tsx +128 -0
  144. package/src/cli/cmd/tui/context/sync.tsx +504 -0
  145. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  146. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  147. package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
  148. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  149. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  150. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  151. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  152. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  153. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  154. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  155. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  156. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  157. package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
  158. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  159. package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
  160. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  161. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  162. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  163. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  164. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  165. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  166. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  167. package/src/cli/cmd/tui/context/theme/orng.json +249 -0
  168. package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
  169. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  170. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  171. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  172. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  173. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  174. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  175. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  176. package/src/cli/cmd/tui/context/theme/vikasit.json +245 -0
  177. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  178. package/src/cli/cmd/tui/context/theme.tsx +1236 -0
  179. package/src/cli/cmd/tui/context/tui-config.tsx +9 -0
  180. package/src/cli/cmd/tui/event.ts +52 -0
  181. package/src/cli/cmd/tui/feature-plugins/home/footer.tsx +93 -0
  182. package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +152 -0
  183. package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +50 -0
  184. package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +63 -0
  185. package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +62 -0
  186. package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +99 -0
  187. package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +66 -0
  188. package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +96 -0
  189. package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +48 -0
  190. package/src/cli/cmd/tui/feature-plugins/system/invite.tsx +148 -0
  191. package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +270 -0
  192. package/src/cli/cmd/tui/plugin/api.tsx +420 -0
  193. package/src/cli/cmd/tui/plugin/index.ts +3 -0
  194. package/src/cli/cmd/tui/plugin/internal.ts +29 -0
  195. package/src/cli/cmd/tui/plugin/runtime.ts +998 -0
  196. package/src/cli/cmd/tui/plugin/slots.tsx +61 -0
  197. package/src/cli/cmd/tui/routes/home.tsx +84 -0
  198. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +65 -0
  199. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +110 -0
  200. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  201. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  202. package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
  203. package/src/cli/cmd/tui/routes/session/index.tsx +2259 -0
  204. package/src/cli/cmd/tui/routes/session/permission.tsx +685 -0
  205. package/src/cli/cmd/tui/routes/session/question.tsx +467 -0
  206. package/src/cli/cmd/tui/routes/session/sidebar.tsx +68 -0
  207. package/src/cli/cmd/tui/routes/session/subagent-footer.tsx +124 -0
  208. package/src/cli/cmd/tui/thread.ts +232 -0
  209. package/src/cli/cmd/tui/ui/dialog-alert.tsx +59 -0
  210. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +89 -0
  211. package/src/cli/cmd/tui/ui/dialog-export-options.tsx +208 -0
  212. package/src/cli/cmd/tui/ui/dialog-help.tsx +40 -0
  213. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +106 -0
  214. package/src/cli/cmd/tui/ui/dialog-select.tsx +402 -0
  215. package/src/cli/cmd/tui/ui/dialog.tsx +192 -0
  216. package/src/cli/cmd/tui/ui/link.tsx +28 -0
  217. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  218. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  219. package/src/cli/cmd/tui/util/clipboard.ts +192 -0
  220. package/src/cli/cmd/tui/util/editor.ts +37 -0
  221. package/src/cli/cmd/tui/util/selection.ts +25 -0
  222. package/src/cli/cmd/tui/util/signal.ts +7 -0
  223. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  224. package/src/cli/cmd/tui/util/transcript.ts +98 -0
  225. package/src/cli/cmd/tui/win32.ts +129 -0
  226. package/src/cli/cmd/tui/worker.ts +172 -0
  227. package/src/cli/cmd/uninstall.ts +353 -0
  228. package/src/cli/cmd/upgrade.ts +73 -0
  229. package/src/cli/cmd/web.ts +81 -0
  230. package/src/cli/effect/prompt.ts +25 -0
  231. package/src/cli/error.ts +46 -0
  232. package/src/cli/logo.ts +20 -0
  233. package/src/cli/network.ts +60 -0
  234. package/src/cli/ui.ts +116 -0
  235. package/src/cli/upgrade.ts +31 -0
  236. package/src/command/index.ts +251 -0
  237. package/src/command/template/branch.txt +1 -0
  238. package/src/command/template/commit.txt +7 -0
  239. package/src/command/template/diff.txt +1 -0
  240. package/src/command/template/initialize.txt +10 -0
  241. package/src/command/template/memory.txt +1 -0
  242. package/src/command/template/review.txt +101 -0
  243. package/src/command/template/summary.txt +1 -0
  244. package/src/config/config.ts +1619 -0
  245. package/src/config/markdown.ts +99 -0
  246. package/src/config/migrate-tui-config.ts +155 -0
  247. package/src/config/paths.ts +174 -0
  248. package/src/config/tui-schema.ts +36 -0
  249. package/src/config/tui.ts +222 -0
  250. package/src/context/contextOptimizer.ts +277 -0
  251. package/src/control-plane/adaptors/index.ts +20 -0
  252. package/src/control-plane/adaptors/worktree.ts +38 -0
  253. package/src/control-plane/schema.ts +17 -0
  254. package/src/control-plane/sse.ts +66 -0
  255. package/src/control-plane/types.ts +21 -0
  256. package/src/control-plane/workspace.sql.ts +17 -0
  257. package/src/control-plane/workspace.ts +154 -0
  258. package/src/cost/index.ts +173 -0
  259. package/src/cost/schema.ts +43 -0
  260. package/src/cron/index.ts +200 -0
  261. package/src/effect/cross-spawn-spawner.ts +479 -0
  262. package/src/effect/instance-registry.ts +12 -0
  263. package/src/effect/instance-state.ts +47 -0
  264. package/src/effect/run-service.ts +19 -0
  265. package/src/effect/runner.ts +216 -0
  266. package/src/env/index.ts +28 -0
  267. package/src/file/ignore.ts +82 -0
  268. package/src/file/index.ts +698 -0
  269. package/src/file/protected.ts +59 -0
  270. package/src/file/ripgrep.ts +376 -0
  271. package/src/file/time.ts +128 -0
  272. package/src/file/watcher.ts +171 -0
  273. package/src/filesystem/index.ts +226 -0
  274. package/src/flag/flag.ts +175 -0
  275. package/src/format/formatter.ts +396 -0
  276. package/src/format/index.ts +199 -0
  277. package/src/global/index.ts +54 -0
  278. package/src/hook/index.ts +132 -0
  279. package/src/hook/schema.ts +31 -0
  280. package/src/id/id.ts +85 -0
  281. package/src/ide/index.ts +74 -0
  282. package/src/index.ts +249 -0
  283. package/src/installation/index.ts +363 -0
  284. package/src/lsp/client.ts +252 -0
  285. package/src/lsp/index.ts +558 -0
  286. package/src/lsp/language.ts +120 -0
  287. package/src/lsp/launch.ts +21 -0
  288. package/src/lsp/server.ts +2093 -0
  289. package/src/mcp/auth.ts +181 -0
  290. package/src/mcp/index.ts +926 -0
  291. package/src/mcp/oauth-callback.ts +215 -0
  292. package/src/mcp/oauth-provider.ts +185 -0
  293. package/src/memory/memory.ts +140 -0
  294. package/src/node.ts +1 -0
  295. package/src/patch/index.ts +680 -0
  296. package/src/permission/arity.ts +163 -0
  297. package/src/permission/auto-classify.ts +114 -0
  298. package/src/permission/evaluate.ts +15 -0
  299. package/src/permission/index.ts +322 -0
  300. package/src/permission/schema.ts +17 -0
  301. package/src/plugin/codex.ts +596 -0
  302. package/src/plugin/copilot.ts +343 -0
  303. package/src/plugin/index.ts +322 -0
  304. package/src/plugin/install.ts +417 -0
  305. package/src/plugin/loader.ts +137 -0
  306. package/src/plugin/meta.ts +188 -0
  307. package/src/plugin/shared.ts +272 -0
  308. package/src/project/bootstrap.ts +31 -0
  309. package/src/project/instance.ts +167 -0
  310. package/src/project/project.sql.ts +16 -0
  311. package/src/project/project.ts +519 -0
  312. package/src/project/schema.ts +16 -0
  313. package/src/project/state.ts +70 -0
  314. package/src/project/vcs.ts +124 -0
  315. package/src/provider/auth.ts +252 -0
  316. package/src/provider/error.ts +197 -0
  317. package/src/provider/github-models.ts +53 -0
  318. package/src/provider/models.ts +139 -0
  319. package/src/provider/provider.ts +1650 -0
  320. package/src/provider/schema.ts +38 -0
  321. package/src/provider/sdk/copilot/README.md +5 -0
  322. package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +170 -0
  323. package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
  324. package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
  325. package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
  326. package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +815 -0
  327. package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
  328. package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
  329. package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +83 -0
  330. package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
  331. package/src/provider/sdk/copilot/index.ts +2 -0
  332. package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
  333. package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +335 -0
  334. package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
  335. package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
  336. package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
  337. package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +214 -0
  338. package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1769 -0
  339. package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +173 -0
  340. package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
  341. package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +87 -0
  342. package/src/provider/sdk/copilot/responses/tool/file-search.ts +127 -0
  343. package/src/provider/sdk/copilot/responses/tool/image-generation.ts +114 -0
  344. package/src/provider/sdk/copilot/responses/tool/local-shell.ts +64 -0
  345. package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +103 -0
  346. package/src/provider/sdk/copilot/responses/tool/web-search.ts +102 -0
  347. package/src/provider/transform.ts +1045 -0
  348. package/src/pty/index.ts +397 -0
  349. package/src/pty/schema.ts +17 -0
  350. package/src/question/index.ts +221 -0
  351. package/src/question/schema.ts +17 -0
  352. package/src/server/error.ts +36 -0
  353. package/src/server/event.ts +7 -0
  354. package/src/server/instance.ts +285 -0
  355. package/src/server/mdns.ts +60 -0
  356. package/src/server/middleware.ts +33 -0
  357. package/src/server/projectors.ts +28 -0
  358. package/src/server/router.ts +99 -0
  359. package/src/server/routes/config.ts +92 -0
  360. package/src/server/routes/event.ts +83 -0
  361. package/src/server/routes/experimental.ts +271 -0
  362. package/src/server/routes/file.ts +197 -0
  363. package/src/server/routes/global.ts +312 -0
  364. package/src/server/routes/instance/httpapi/app.ts +21 -0
  365. package/src/server/routes/mcp.ts +225 -0
  366. package/src/server/routes/permission.ts +69 -0
  367. package/src/server/routes/project.ts +118 -0
  368. package/src/server/routes/provider.ts +171 -0
  369. package/src/server/routes/pty.ts +211 -0
  370. package/src/server/routes/question.ts +99 -0
  371. package/src/server/routes/session.ts +1031 -0
  372. package/src/server/routes/tui.ts +379 -0
  373. package/src/server/routes/workspace.ts +94 -0
  374. package/src/server/server.ts +314 -0
  375. package/src/session/compaction.ts +432 -0
  376. package/src/session/index.ts +885 -0
  377. package/src/session/instruction.ts +192 -0
  378. package/src/session/llm.ts +365 -0
  379. package/src/session/memory.ts +126 -0
  380. package/src/session/message-v2.ts +1030 -0
  381. package/src/session/message.ts +191 -0
  382. package/src/session/overflow.ts +22 -0
  383. package/src/session/processor.ts +697 -0
  384. package/src/session/projectors.ts +135 -0
  385. package/src/session/prompt/anthropic.txt +125 -0
  386. package/src/session/prompt/beast.txt +161 -0
  387. package/src/session/prompt/build-switch.txt +5 -0
  388. package/src/session/prompt/codex.txt +90 -0
  389. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  390. package/src/session/prompt/default.txt +116 -0
  391. package/src/session/prompt/gemini.txt +173 -0
  392. package/src/session/prompt/gpt.txt +120 -0
  393. package/src/session/prompt/kimi.txt +131 -0
  394. package/src/session/prompt/max-steps.txt +16 -0
  395. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  396. package/src/session/prompt/plan.txt +26 -0
  397. package/src/session/prompt/trinity.txt +109 -0
  398. package/src/session/prompt.ts +1898 -0
  399. package/src/session/rate-limit.ts +176 -0
  400. package/src/session/retry.ts +107 -0
  401. package/src/session/revert.ts +135 -0
  402. package/src/session/schema.ts +38 -0
  403. package/src/session/session.sql.ts +103 -0
  404. package/src/session/status.ts +102 -0
  405. package/src/session/summary.ts +169 -0
  406. package/src/session/system.ts +76 -0
  407. package/src/session/todo.ts +57 -0
  408. package/src/share/share-next.ts +287 -0
  409. package/src/share/share.sql.ts +13 -0
  410. package/src/shell/shell.ts +110 -0
  411. package/src/skill/discovery.ts +116 -0
  412. package/src/skill/index.ts +277 -0
  413. package/src/snapshot/index.ts +489 -0
  414. package/src/sql.d.ts +4 -0
  415. package/src/storage/db.bun.ts +8 -0
  416. package/src/storage/db.node.ts +8 -0
  417. package/src/storage/db.ts +177 -0
  418. package/src/storage/json-migration.ts +425 -0
  419. package/src/storage/schema.sql.ts +10 -0
  420. package/src/storage/schema.ts +5 -0
  421. package/src/storage/storage.ts +353 -0
  422. package/src/sync/README.md +179 -0
  423. package/src/sync/event.sql.ts +16 -0
  424. package/src/sync/index.ts +263 -0
  425. package/src/sync/schema.ts +14 -0
  426. package/src/task/index.ts +89 -0
  427. package/src/task/schema.ts +39 -0
  428. package/src/tool/apply_patch.ts +281 -0
  429. package/src/tool/apply_patch.txt +33 -0
  430. package/src/tool/bash-security.ts +214 -0
  431. package/src/tool/bash.ts +526 -0
  432. package/src/tool/bash.txt +129 -0
  433. package/src/tool/batch.ts +183 -0
  434. package/src/tool/batch.txt +24 -0
  435. package/src/tool/codesearch.ts +132 -0
  436. package/src/tool/codesearch.txt +12 -0
  437. package/src/tool/cron-create.ts +38 -0
  438. package/src/tool/cron-create.txt +10 -0
  439. package/src/tool/cron-delete.ts +29 -0
  440. package/src/tool/cron-delete.txt +1 -0
  441. package/src/tool/cron-list.ts +37 -0
  442. package/src/tool/cron-list.txt +1 -0
  443. package/src/tool/edit.ts +667 -0
  444. package/src/tool/edit.txt +10 -0
  445. package/src/tool/external-directory.ts +37 -0
  446. package/src/tool/glob.ts +78 -0
  447. package/src/tool/glob.txt +6 -0
  448. package/src/tool/grep.ts +156 -0
  449. package/src/tool/grep.txt +8 -0
  450. package/src/tool/invalid.ts +17 -0
  451. package/src/tool/ls.ts +121 -0
  452. package/src/tool/ls.txt +1 -0
  453. package/src/tool/lsp.ts +97 -0
  454. package/src/tool/lsp.txt +19 -0
  455. package/src/tool/multiedit.ts +46 -0
  456. package/src/tool/multiedit.txt +41 -0
  457. package/src/tool/notebook-edit.ts +136 -0
  458. package/src/tool/notebook-edit.txt +10 -0
  459. package/src/tool/plan-enter.txt +14 -0
  460. package/src/tool/plan-exit.txt +13 -0
  461. package/src/tool/plan.ts +130 -0
  462. package/src/tool/question.ts +33 -0
  463. package/src/tool/question.txt +10 -0
  464. package/src/tool/read.ts +296 -0
  465. package/src/tool/read.txt +14 -0
  466. package/src/tool/registry.ts +333 -0
  467. package/src/tool/schema.ts +17 -0
  468. package/src/tool/sendmessage.ts +57 -0
  469. package/src/tool/sendmessage.txt +6 -0
  470. package/src/tool/skill.ts +105 -0
  471. package/src/tool/task-create.ts +25 -0
  472. package/src/tool/task-create.txt +1 -0
  473. package/src/tool/task-get.ts +27 -0
  474. package/src/tool/task-get.txt +1 -0
  475. package/src/tool/task-list.ts +45 -0
  476. package/src/tool/task-list.txt +1 -0
  477. package/src/tool/task-output.ts +28 -0
  478. package/src/tool/task-output.txt +1 -0
  479. package/src/tool/task-stop.ts +27 -0
  480. package/src/tool/task-stop.txt +1 -0
  481. package/src/tool/task-update.ts +38 -0
  482. package/src/tool/task-update.txt +1 -0
  483. package/src/tool/task.ts +246 -0
  484. package/src/tool/task.txt +65 -0
  485. package/src/tool/todo.ts +31 -0
  486. package/src/tool/todowrite.txt +167 -0
  487. package/src/tool/tool.ts +98 -0
  488. package/src/tool/toolsearch.ts +117 -0
  489. package/src/tool/toolsearch.txt +10 -0
  490. package/src/tool/truncate.ts +144 -0
  491. package/src/tool/truncation-dir.ts +4 -0
  492. package/src/tool/webfetch.ts +206 -0
  493. package/src/tool/webfetch.txt +13 -0
  494. package/src/tool/websearch.ts +150 -0
  495. package/src/tool/websearch.txt +14 -0
  496. package/src/tool/worktree-enter.ts +38 -0
  497. package/src/tool/worktree-enter.txt +8 -0
  498. package/src/tool/worktree-exit.ts +43 -0
  499. package/src/tool/worktree-exit.txt +3 -0
  500. package/src/tool/write.ts +84 -0
  501. package/src/tool/write.txt +8 -0
  502. package/src/util/abort.ts +35 -0
  503. package/src/util/archive.ts +17 -0
  504. package/src/util/color.ts +19 -0
  505. package/src/util/context.ts +25 -0
  506. package/src/util/data-url.ts +9 -0
  507. package/src/util/defer.ts +12 -0
  508. package/src/util/effect-http-client.ts +11 -0
  509. package/src/util/effect-zod.ts +98 -0
  510. package/src/util/error.ts +77 -0
  511. package/src/util/filesystem.ts +220 -0
  512. package/src/util/flock.ts +333 -0
  513. package/src/util/fn.ts +21 -0
  514. package/src/util/format.ts +20 -0
  515. package/src/util/git.ts +35 -0
  516. package/src/util/glob.ts +34 -0
  517. package/src/util/hash.ts +7 -0
  518. package/src/util/iife.ts +3 -0
  519. package/src/util/keybind.ts +103 -0
  520. package/src/util/lazy.ts +23 -0
  521. package/src/util/locale.ts +81 -0
  522. package/src/util/lock.ts +98 -0
  523. package/src/util/log.ts +182 -0
  524. package/src/util/network.ts +9 -0
  525. package/src/util/process.ts +172 -0
  526. package/src/util/queue.ts +32 -0
  527. package/src/util/record.ts +3 -0
  528. package/src/util/rpc.ts +66 -0
  529. package/src/util/schema.ts +53 -0
  530. package/src/util/scrap.ts +10 -0
  531. package/src/util/signal.ts +12 -0
  532. package/src/util/timeout.ts +14 -0
  533. package/src/util/token.ts +7 -0
  534. package/src/util/update-schema.ts +13 -0
  535. package/src/util/which.ts +14 -0
  536. package/src/util/wildcard.ts +59 -0
  537. package/src/vim/agent-namer.ts +86 -0
  538. package/src/vim/types.ts +29 -0
  539. package/src/worktree/index.ts +638 -0
  540. package/sst-env.d.ts +10 -0
  541. package/test/AGENTS.md +81 -0
  542. package/test/account/repo.test.ts +326 -0
  543. package/test/account/service.test.ts +282 -0
  544. package/test/acp/agent-interface.test.ts +51 -0
  545. package/test/acp/event-subscription.test.ts +685 -0
  546. package/test/agent/agent.test.ts +717 -0
  547. package/test/auth/auth.test.ts +58 -0
  548. package/test/bun.test.ts +137 -0
  549. package/test/bus/bus-effect.test.ts +164 -0
  550. package/test/bus/bus-integration.test.ts +87 -0
  551. package/test/bus/bus.test.ts +219 -0
  552. package/test/cli/account.test.ts +26 -0
  553. package/test/cli/cmd/tui/prompt-part.test.ts +47 -0
  554. package/test/cli/github-action.test.ts +198 -0
  555. package/test/cli/github-remote.test.ts +80 -0
  556. package/test/cli/import.test.ts +54 -0
  557. package/test/cli/plugin-auth-picker.test.ts +120 -0
  558. package/test/cli/tui/keybind-plugin.test.ts +90 -0
  559. package/test/cli/tui/plugin-add.test.ts +61 -0
  560. package/test/cli/tui/plugin-install.test.ts +89 -0
  561. package/test/cli/tui/plugin-lifecycle.test.ts +225 -0
  562. package/test/cli/tui/plugin-loader-entrypoint.test.ts +492 -0
  563. package/test/cli/tui/plugin-loader-pure.test.ts +72 -0
  564. package/test/cli/tui/plugin-loader.test.ts +752 -0
  565. package/test/cli/tui/plugin-toggle.test.ts +159 -0
  566. package/test/cli/tui/theme-store.test.ts +51 -0
  567. package/test/cli/tui/thread.test.ts +128 -0
  568. package/test/cli/tui/transcript.test.ts +322 -0
  569. package/test/config/agent-color.test.ts +71 -0
  570. package/test/config/config.test.ts +2218 -0
  571. package/test/config/fixtures/empty-frontmatter.md +4 -0
  572. package/test/config/fixtures/frontmatter.md +28 -0
  573. package/test/config/fixtures/markdown-header.md +11 -0
  574. package/test/config/fixtures/no-frontmatter.md +1 -0
  575. package/test/config/fixtures/weird-model-id.md +13 -0
  576. package/test/config/markdown.test.ts +228 -0
  577. package/test/config/tui.test.ts +673 -0
  578. package/test/control-plane/sse.test.ts +56 -0
  579. package/test/effect/cross-spawn-spawner.test.ts +402 -0
  580. package/test/effect/instance-state.test.ts +384 -0
  581. package/test/effect/run-service.test.ts +46 -0
  582. package/test/effect/runner.test.ts +523 -0
  583. package/test/file/fsmonitor.test.ts +62 -0
  584. package/test/file/ignore.test.ts +10 -0
  585. package/test/file/index.test.ts +946 -0
  586. package/test/file/path-traversal.test.ts +198 -0
  587. package/test/file/ripgrep.test.ts +54 -0
  588. package/test/file/time.test.ts +354 -0
  589. package/test/file/watcher.test.ts +247 -0
  590. package/test/filesystem/filesystem.test.ts +319 -0
  591. package/test/fixture/db.ts +11 -0
  592. package/test/fixture/fixture.test.ts +26 -0
  593. package/test/fixture/fixture.ts +141 -0
  594. package/test/fixture/flock-worker.ts +72 -0
  595. package/test/fixture/lsp/fake-lsp-server.js +77 -0
  596. package/test/fixture/plug-worker.ts +93 -0
  597. package/test/fixture/plugin-meta-worker.ts +26 -0
  598. package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
  599. package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
  600. package/test/fixture/skills/cloudflare/SKILL.md +211 -0
  601. package/test/fixture/skills/index.json +6 -0
  602. package/test/fixture/tui-plugin.ts +335 -0
  603. package/test/fixture/tui-runtime.ts +27 -0
  604. package/test/format/format.test.ts +179 -0
  605. package/test/ide/ide.test.ts +82 -0
  606. package/test/installation/installation.test.ts +151 -0
  607. package/test/keybind.test.ts +421 -0
  608. package/test/lib/effect.ts +37 -0
  609. package/test/lib/filesystem.ts +10 -0
  610. package/test/lsp/client.test.ts +95 -0
  611. package/test/lsp/index.test.ts +55 -0
  612. package/test/lsp/launch.test.ts +22 -0
  613. package/test/lsp/lifecycle.test.ts +147 -0
  614. package/test/mcp/headers.test.ts +153 -0
  615. package/test/mcp/lifecycle.test.ts +750 -0
  616. package/test/mcp/oauth-auto-connect.test.ts +199 -0
  617. package/test/mcp/oauth-browser.test.ts +249 -0
  618. package/test/memory/abort-leak.test.ts +137 -0
  619. package/test/patch/patch.test.ts +348 -0
  620. package/test/permission/arity.test.ts +33 -0
  621. package/test/permission/next.test.ts +1148 -0
  622. package/test/permission-task.test.ts +323 -0
  623. package/test/plugin/auth-override.test.ts +74 -0
  624. package/test/plugin/codex.test.ts +123 -0
  625. package/test/plugin/install-concurrency.test.ts +140 -0
  626. package/test/plugin/install.test.ts +531 -0
  627. package/test/plugin/loader-shared.test.ts +836 -0
  628. package/test/plugin/meta.test.ts +137 -0
  629. package/test/plugin/trigger.test.ts +111 -0
  630. package/test/preload.ts +90 -0
  631. package/test/project/migrate-global.test.ts +140 -0
  632. package/test/project/project.test.ts +459 -0
  633. package/test/project/state.test.ts +115 -0
  634. package/test/project/vcs.test.ts +116 -0
  635. package/test/project/worktree-remove.test.ts +96 -0
  636. package/test/project/worktree.test.ts +173 -0
  637. package/test/provider/amazon-bedrock.test.ts +447 -0
  638. package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
  639. package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
  640. package/test/provider/gitlab-duo.test.ts +412 -0
  641. package/test/provider/provider.test.ts +2284 -0
  642. package/test/provider/transform.test.ts +2758 -0
  643. package/test/pty/pty-output-isolation.test.ts +141 -0
  644. package/test/pty/pty-session.test.ts +92 -0
  645. package/test/pty/pty-shell.test.ts +59 -0
  646. package/test/question/question.test.ts +453 -0
  647. package/test/server/global-session-list.test.ts +89 -0
  648. package/test/server/project-init-git.test.ts +121 -0
  649. package/test/server/session-actions.test.ts +83 -0
  650. package/test/server/session-list.test.ts +98 -0
  651. package/test/server/session-messages.test.ts +159 -0
  652. package/test/server/session-select.test.ts +84 -0
  653. package/test/session/compaction.test.ts +1202 -0
  654. package/test/session/instruction.test.ts +170 -0
  655. package/test/session/llm.test.ts +1098 -0
  656. package/test/session/message-v2.test.ts +957 -0
  657. package/test/session/messages-pagination.test.ts +115 -0
  658. package/test/session/processor-effect.test.ts +872 -0
  659. package/test/session/prompt-concurrency.test.ts +247 -0
  660. package/test/session/prompt-effect.test.ts +1206 -0
  661. package/test/session/prompt.test.ts +518 -0
  662. package/test/session/retry.test.ts +232 -0
  663. package/test/session/revert-compact.test.ts +286 -0
  664. package/test/session/session.test.ts +142 -0
  665. package/test/session/structured-output-integration.test.ts +233 -0
  666. package/test/session/structured-output.test.ts +391 -0
  667. package/test/session/system.test.ts +59 -0
  668. package/test/share/share-next.test.ts +76 -0
  669. package/test/shell/shell.test.ts +73 -0
  670. package/test/skill/discovery.test.ts +116 -0
  671. package/test/skill/skill.test.ts +392 -0
  672. package/test/snapshot/snapshot.test.ts +1235 -0
  673. package/test/storage/db.test.ts +14 -0
  674. package/test/storage/json-migration.test.ts +849 -0
  675. package/test/storage/storage.test.ts +295 -0
  676. package/test/sync/index.test.ts +191 -0
  677. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  678. package/test/tool/apply_patch.test.ts +567 -0
  679. package/test/tool/bash.test.ts +984 -0
  680. package/test/tool/edit.test.ts +681 -0
  681. package/test/tool/external-directory.test.ts +198 -0
  682. package/test/tool/fixtures/large-image.png +0 -0
  683. package/test/tool/fixtures/models-api.json +65179 -0
  684. package/test/tool/grep.test.ts +111 -0
  685. package/test/tool/question.test.ts +108 -0
  686. package/test/tool/read.test.ts +546 -0
  687. package/test/tool/registry.test.ts +126 -0
  688. package/test/tool/skill.test.ts +167 -0
  689. package/test/tool/task.test.ts +49 -0
  690. package/test/tool/truncation.test.ts +161 -0
  691. package/test/tool/webfetch.test.ts +101 -0
  692. package/test/tool/write.test.ts +353 -0
  693. package/test/util/data-url.test.ts +14 -0
  694. package/test/util/effect-zod.test.ts +61 -0
  695. package/test/util/error.test.ts +38 -0
  696. package/test/util/filesystem.test.ts +567 -0
  697. package/test/util/flock.test.ts +383 -0
  698. package/test/util/format.test.ts +59 -0
  699. package/test/util/glob.test.ts +164 -0
  700. package/test/util/iife.test.ts +36 -0
  701. package/test/util/lazy.test.ts +50 -0
  702. package/test/util/lock.test.ts +72 -0
  703. package/test/util/module.test.ts +59 -0
  704. package/test/util/process.test.ts +128 -0
  705. package/test/util/timeout.test.ts +21 -0
  706. package/test/util/which.test.ts +100 -0
  707. package/test/util/wildcard.test.ts +90 -0
  708. package/tsconfig.json +23 -0
  709. package/vikasitai-vikasit-code-2.0.5.tgz +0 -0
  710. package/LICENSE +0 -21
  711. /package/{postinstall.mjs → script/postinstall.mjs} +0 -0
@@ -0,0 +1,99 @@
1
+ import { NamedError } from "@vikasit-code/util/error"
2
+ import matter from "gray-matter"
3
+ import { z } from "zod"
4
+ import { Filesystem } from "../util/filesystem"
5
+
6
+ export namespace ConfigMarkdown {
7
+ export const FILE_REGEX = /(?<![\w`])@(\.?[^\s`,.]*(?:\.[^\s`,.]+)*)/g
8
+ export const SHELL_REGEX = /!`([^`]+)`/g
9
+
10
+ export function files(template: string) {
11
+ return Array.from(template.matchAll(FILE_REGEX))
12
+ }
13
+
14
+ export function shell(template: string) {
15
+ return Array.from(template.matchAll(SHELL_REGEX))
16
+ }
17
+
18
+ // other coding agents like claude code allow invalid yaml in their
19
+ // frontmatter, we need to fallback to a more permissive parser for those cases
20
+ export function fallbackSanitization(content: string): string {
21
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
22
+ if (!match) return content
23
+
24
+ const frontmatter = match[1]
25
+ const lines = frontmatter.split(/\r?\n/)
26
+ const result: string[] = []
27
+
28
+ for (const line of lines) {
29
+ // skip comments and empty lines
30
+ if (line.trim().startsWith("#") || line.trim() === "") {
31
+ result.push(line)
32
+ continue
33
+ }
34
+
35
+ // skip lines that are continuations (indented)
36
+ if (line.match(/^\s+/)) {
37
+ result.push(line)
38
+ continue
39
+ }
40
+
41
+ // match key: value pattern
42
+ const kvMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.*)$/)
43
+ if (!kvMatch) {
44
+ result.push(line)
45
+ continue
46
+ }
47
+
48
+ const key = kvMatch[1]
49
+ const value = kvMatch[2].trim()
50
+
51
+ // skip if value is empty, already quoted, or uses block scalar
52
+ if (value === "" || value === ">" || value === "|" || value.startsWith('"') || value.startsWith("'")) {
53
+ result.push(line)
54
+ continue
55
+ }
56
+
57
+ // if value contains a colon, convert to block scalar
58
+ if (value.includes(":")) {
59
+ result.push(`${key}: |-`)
60
+ result.push(` ${value}`)
61
+ continue
62
+ }
63
+
64
+ result.push(line)
65
+ }
66
+
67
+ const processed = result.join("\n")
68
+ return content.replace(frontmatter, () => processed)
69
+ }
70
+
71
+ export async function parse(filePath: string) {
72
+ const template = await Filesystem.readText(filePath)
73
+
74
+ try {
75
+ const md = matter(template)
76
+ return md
77
+ } catch {
78
+ try {
79
+ return matter(fallbackSanitization(template))
80
+ } catch (err) {
81
+ throw new FrontmatterError(
82
+ {
83
+ path: filePath,
84
+ message: `${filePath}: Failed to parse YAML frontmatter: ${err instanceof Error ? err.message : String(err)}`,
85
+ },
86
+ { cause: err },
87
+ )
88
+ }
89
+ }
90
+ }
91
+
92
+ export const FrontmatterError = NamedError.create(
93
+ "ConfigFrontmatterError",
94
+ z.object({
95
+ path: z.string(),
96
+ message: z.string(),
97
+ }),
98
+ )
99
+ }
@@ -0,0 +1,155 @@
1
+ import path from "path"
2
+ import { type ParseError as JsoncParseError, applyEdits, modify, parse as parseJsonc } from "jsonc-parser"
3
+ import { unique } from "remeda"
4
+ import z from "zod"
5
+ import { ConfigPaths } from "./paths"
6
+ import { TuiInfo, TuiOptions } from "./tui-schema"
7
+ import { Instance } from "@/project/instance"
8
+ import { Flag } from "@/flag/flag"
9
+ import { Log } from "@/util/log"
10
+ import { Filesystem } from "@/util/filesystem"
11
+ import { Global } from "@/global"
12
+
13
+ const log = Log.create({ service: "tui.migrate" })
14
+
15
+ const TUI_SCHEMA_URL = "https://vikasit.ai/tui.json"
16
+
17
+ const LegacyTheme = TuiInfo.shape.theme.optional()
18
+ const LegacyRecord = z.record(z.string(), z.unknown()).optional()
19
+
20
+ const TuiLegacy = z
21
+ .object({
22
+ scroll_speed: TuiOptions.shape.scroll_speed.catch(undefined),
23
+ scroll_acceleration: TuiOptions.shape.scroll_acceleration.catch(undefined),
24
+ diff_style: TuiOptions.shape.diff_style.catch(undefined),
25
+ })
26
+ .strip()
27
+
28
+ interface MigrateInput {
29
+ directories: string[]
30
+ custom?: string
31
+ managed: string
32
+ }
33
+
34
+ /**
35
+ * Migrates tui-specific keys (theme, keybinds, tui) from vikasit.json files
36
+ * into dedicated tui.json files. Migration is performed per-directory and
37
+ * skips only locations where a tui.json already exists.
38
+ */
39
+ export async function migrateTuiConfig(input: MigrateInput) {
40
+ const opencode = await opencodeFiles(input)
41
+ for (const file of opencode) {
42
+ const source = await Filesystem.readText(file).catch((error) => {
43
+ log.warn("failed to read config for tui migration", { path: file, error })
44
+ return undefined
45
+ })
46
+ if (!source) continue
47
+ const errors: JsoncParseError[] = []
48
+ const data = parseJsonc(source, errors, { allowTrailingComma: true })
49
+ if (errors.length || !data || typeof data !== "object" || Array.isArray(data)) continue
50
+
51
+ const theme = LegacyTheme.safeParse("theme" in data ? data.theme : undefined)
52
+ const keybinds = LegacyRecord.safeParse("keybinds" in data ? data.keybinds : undefined)
53
+ const legacyTui = LegacyRecord.safeParse("tui" in data ? data.tui : undefined)
54
+ const extracted = {
55
+ theme: theme.success ? theme.data : undefined,
56
+ keybinds: keybinds.success ? keybinds.data : undefined,
57
+ tui: legacyTui.success ? legacyTui.data : undefined,
58
+ }
59
+ const tui = extracted.tui ? normalizeTui(extracted.tui) : undefined
60
+ if (extracted.theme === undefined && extracted.keybinds === undefined && !tui) continue
61
+
62
+ const target = path.join(path.dirname(file), "tui.json")
63
+ const targetExists = await Filesystem.exists(target)
64
+ if (targetExists) continue
65
+
66
+ const payload: Record<string, unknown> = {
67
+ $schema: TUI_SCHEMA_URL,
68
+ }
69
+ if (extracted.theme !== undefined) payload.theme = extracted.theme
70
+ if (extracted.keybinds !== undefined) payload.keybinds = extracted.keybinds
71
+ if (tui) Object.assign(payload, tui)
72
+
73
+ const wrote = await Filesystem.write(target, JSON.stringify(payload, null, 2))
74
+ .then(() => true)
75
+ .catch((error) => {
76
+ log.warn("failed to write tui migration target", { from: file, to: target, error })
77
+ return false
78
+ })
79
+ if (!wrote) continue
80
+
81
+ const stripped = await backupAndStripLegacy(file, source)
82
+ if (!stripped) {
83
+ log.warn("tui config migrated but source file was not stripped", { from: file, to: target })
84
+ continue
85
+ }
86
+ log.info("migrated tui config", { from: file, to: target })
87
+ }
88
+ }
89
+
90
+ function normalizeTui(data: Record<string, unknown>) {
91
+ const parsed = TuiLegacy.parse(data)
92
+ if (
93
+ parsed.scroll_speed === undefined &&
94
+ parsed.diff_style === undefined &&
95
+ parsed.scroll_acceleration === undefined
96
+ ) {
97
+ return
98
+ }
99
+ return parsed
100
+ }
101
+
102
+ async function backupAndStripLegacy(file: string, source: string) {
103
+ const backup = file + ".tui-migration.bak"
104
+ const hasBackup = await Filesystem.exists(backup)
105
+ const backed = hasBackup
106
+ ? true
107
+ : await Filesystem.write(backup, source)
108
+ .then(() => true)
109
+ .catch((error) => {
110
+ log.warn("failed to backup source config during tui migration", { path: file, backup, error })
111
+ return false
112
+ })
113
+ if (!backed) return false
114
+
115
+ const text = ["theme", "keybinds", "tui"].reduce((acc, key) => {
116
+ const edits = modify(acc, [key], undefined, {
117
+ formattingOptions: {
118
+ insertSpaces: true,
119
+ tabSize: 2,
120
+ },
121
+ })
122
+ if (!edits.length) return acc
123
+ return applyEdits(acc, edits)
124
+ }, source)
125
+
126
+ return Filesystem.write(file, text)
127
+ .then(() => {
128
+ log.info("stripped tui keys from server config", { path: file, backup })
129
+ return true
130
+ })
131
+ .catch((error) => {
132
+ log.warn("failed to strip legacy tui keys from server config", { path: file, backup, error })
133
+ return false
134
+ })
135
+ }
136
+
137
+ async function opencodeFiles(input: { directories: string[]; managed: string }) {
138
+ const project = Flag.VIKASIT_DISABLE_PROJECT_CONFIG
139
+ ? []
140
+ : await ConfigPaths.projectFiles("vikasit", Instance.directory, Instance.worktree)
141
+ const files = [...project, ...ConfigPaths.fileInDirectory(Global.Path.config, "vikasit")]
142
+ for (const dir of unique(input.directories)) {
143
+ files.push(...ConfigPaths.fileInDirectory(dir, "vikasit"))
144
+ }
145
+ if (Flag.VIKASIT_CONFIG) files.push(Flag.VIKASIT_CONFIG)
146
+ files.push(...ConfigPaths.fileInDirectory(input.managed, "vikasit"))
147
+
148
+ const existing = await Promise.all(
149
+ unique(files).map(async (file) => {
150
+ const ok = await Filesystem.exists(file)
151
+ return ok ? file : undefined
152
+ }),
153
+ )
154
+ return existing.filter((file): file is string => !!file)
155
+ }
@@ -0,0 +1,174 @@
1
+ import path from "path"
2
+ import os from "os"
3
+ import z from "zod"
4
+ import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser"
5
+ import { NamedError } from "@vikasit-code/util/error"
6
+ import { Filesystem } from "@/util/filesystem"
7
+ import { Flag } from "@/flag/flag"
8
+ import { Global } from "@/global"
9
+
10
+ export namespace ConfigPaths {
11
+ export async function projectFiles(name: string, directory: string, worktree: string) {
12
+ const files: string[] = []
13
+ for (const file of [`${name}.jsonc`, `${name}.json`]) {
14
+ const found = await Filesystem.findUp(file, directory, worktree)
15
+ for (const resolved of found.toReversed()) {
16
+ files.push(resolved)
17
+ }
18
+ }
19
+ return files
20
+ }
21
+
22
+ export async function directories(directory: string, worktree: string) {
23
+ return [
24
+ Global.Path.config,
25
+ ...(!Flag.VIKASIT_DISABLE_PROJECT_CONFIG
26
+ ? await Array.fromAsync(
27
+ Filesystem.up({
28
+ targets: [".vikasit"],
29
+ start: directory,
30
+ stop: worktree,
31
+ }),
32
+ )
33
+ : []),
34
+ ...(await Array.fromAsync(
35
+ Filesystem.up({
36
+ targets: [".vikasit"],
37
+ start: Global.Path.home,
38
+ stop: Global.Path.home,
39
+ }),
40
+ )),
41
+ ...(Flag.VIKASIT_CONFIG_DIR ? [Flag.VIKASIT_CONFIG_DIR] : []),
42
+ ]
43
+ }
44
+
45
+ export function fileInDirectory(dir: string, name: string) {
46
+ return [path.join(dir, `${name}.jsonc`), path.join(dir, `${name}.json`)]
47
+ }
48
+
49
+ export const JsonError = NamedError.create(
50
+ "ConfigJsonError",
51
+ z.object({
52
+ path: z.string(),
53
+ message: z.string().optional(),
54
+ }),
55
+ )
56
+
57
+ export const InvalidError = NamedError.create(
58
+ "ConfigInvalidError",
59
+ z.object({
60
+ path: z.string(),
61
+ issues: z.custom<z.core.$ZodIssue[]>().optional(),
62
+ message: z.string().optional(),
63
+ }),
64
+ )
65
+
66
+ /** Read a config file, returning undefined for missing files and throwing JsonError for other failures. */
67
+ export async function readFile(filepath: string) {
68
+ return Filesystem.readText(filepath).catch((err: NodeJS.ErrnoException) => {
69
+ if (err.code === "ENOENT") return
70
+ throw new JsonError({ path: filepath }, { cause: err })
71
+ })
72
+ }
73
+
74
+ type ParseSource = string | { source: string; dir: string }
75
+
76
+ function source(input: ParseSource) {
77
+ return typeof input === "string" ? input : input.source
78
+ }
79
+
80
+ function dir(input: ParseSource) {
81
+ return typeof input === "string" ? path.dirname(input) : input.dir
82
+ }
83
+
84
+ /** Apply {env:VAR} and {file:path} substitutions to config text. */
85
+ async function substitute(text: string, input: ParseSource, missing: "error" | "empty" = "error") {
86
+ text = text.replace(/\{env:([^}]+)\}/g, (_, varName) => {
87
+ return process.env[varName] || ""
88
+ })
89
+
90
+ const fileMatches = Array.from(text.matchAll(/\{file:[^}]+\}/g))
91
+ if (!fileMatches.length) return text
92
+
93
+ const configDir = dir(input)
94
+ const configSource = source(input)
95
+ let out = ""
96
+ let cursor = 0
97
+
98
+ for (const match of fileMatches) {
99
+ const token = match[0]
100
+ const index = match.index!
101
+ out += text.slice(cursor, index)
102
+
103
+ const lineStart = text.lastIndexOf("\n", index - 1) + 1
104
+ const prefix = text.slice(lineStart, index).trimStart()
105
+ if (prefix.startsWith("//")) {
106
+ out += token
107
+ cursor = index + token.length
108
+ continue
109
+ }
110
+
111
+ let filePath = token.replace(/^\{file:/, "").replace(/\}$/, "")
112
+ if (filePath.startsWith("~/")) {
113
+ filePath = path.join(os.homedir(), filePath.slice(2))
114
+ }
115
+
116
+ const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath)
117
+ const fileContent = (
118
+ await Filesystem.readText(resolvedPath).catch((error: NodeJS.ErrnoException) => {
119
+ if (missing === "empty") return ""
120
+
121
+ const errMsg = `bad file reference: "${token}"`
122
+ if (error.code === "ENOENT") {
123
+ throw new InvalidError(
124
+ {
125
+ path: configSource,
126
+ message: errMsg + ` ${resolvedPath} does not exist`,
127
+ },
128
+ { cause: error },
129
+ )
130
+ }
131
+ throw new InvalidError({ path: configSource, message: errMsg }, { cause: error })
132
+ })
133
+ ).trim()
134
+
135
+ out += JSON.stringify(fileContent).slice(1, -1)
136
+ cursor = index + token.length
137
+ }
138
+
139
+ out += text.slice(cursor)
140
+ return out
141
+ }
142
+
143
+ /** Substitute and parse JSONC text, throwing JsonError on syntax errors. */
144
+ export async function parseText(text: string, input: ParseSource, missing: "error" | "empty" = "error") {
145
+ const configSource = source(input)
146
+ text = await substitute(text, input, missing)
147
+
148
+ const errors: JsoncParseError[] = []
149
+ const data = parseJsonc(text, errors, { allowTrailingComma: true })
150
+ if (errors.length) {
151
+ const lines = text.split("\n")
152
+ const errorDetails = errors
153
+ .map((e) => {
154
+ const beforeOffset = text.substring(0, e.offset).split("\n")
155
+ const line = beforeOffset.length
156
+ const column = beforeOffset[beforeOffset.length - 1].length + 1
157
+ const problemLine = lines[line - 1]
158
+
159
+ const error = `${printParseErrorCode(e.error)} at line ${line}, column ${column}`
160
+ if (!problemLine) return error
161
+
162
+ return `${error}\n Line ${line}: ${problemLine}\n${"".padStart(column + 9)}^`
163
+ })
164
+ .join("\n")
165
+
166
+ throw new JsonError({
167
+ path: configSource,
168
+ message: `\n--- JSONC Input ---\n${text}\n--- Errors ---\n${errorDetails}\n--- End ---`,
169
+ })
170
+ }
171
+
172
+ return data
173
+ }
174
+ }
@@ -0,0 +1,36 @@
1
+ import z from "zod"
2
+ import { Config } from "./config"
3
+
4
+ const KeybindOverride = z
5
+ .object(
6
+ Object.fromEntries(Object.keys(Config.Keybinds.shape).map((key) => [key, z.string().optional()])) as Record<
7
+ string,
8
+ z.ZodOptional<z.ZodString>
9
+ >,
10
+ )
11
+ .strict()
12
+
13
+ export const TuiOptions = z.object({
14
+ scroll_speed: z.number().min(0.001).optional().describe("TUI scroll speed"),
15
+ scroll_acceleration: z
16
+ .object({
17
+ enabled: z.boolean().describe("Enable scroll acceleration"),
18
+ })
19
+ .optional()
20
+ .describe("Scroll acceleration settings"),
21
+ diff_style: z
22
+ .enum(["auto", "stacked"])
23
+ .optional()
24
+ .describe("Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column"),
25
+ })
26
+
27
+ export const TuiInfo = z
28
+ .object({
29
+ $schema: z.string().optional(),
30
+ theme: z.string().optional(),
31
+ keybinds: KeybindOverride.optional(),
32
+ plugin: Config.PluginSpec.array().optional(),
33
+ plugin_enabled: z.record(z.string(), z.boolean()).optional(),
34
+ })
35
+ .extend(TuiOptions.shape)
36
+ .strict()
@@ -0,0 +1,222 @@
1
+ import { existsSync } from "fs"
2
+ import z from "zod"
3
+ import { mergeDeep, unique } from "remeda"
4
+ import { Config } from "./config"
5
+ import { ConfigPaths } from "./paths"
6
+ import { migrateTuiConfig } from "./migrate-tui-config"
7
+ import { TuiInfo } from "./tui-schema"
8
+ import { Instance } from "@/project/instance"
9
+ import { Flag } from "@/flag/flag"
10
+ import { Log } from "@/util/log"
11
+ import { isRecord } from "@/util/record"
12
+ import { Global } from "@/global"
13
+ import { parsePluginSpecifier } from "@/plugin/shared"
14
+
15
+ export namespace TuiConfig {
16
+ const log = Log.create({ service: "tui.config" })
17
+
18
+ export const Info = TuiInfo
19
+
20
+ export type PluginMeta = {
21
+ scope: "global" | "local"
22
+ source: string
23
+ }
24
+
25
+ export type PluginRecord = {
26
+ item: Config.PluginSpec
27
+ scope: PluginMeta["scope"]
28
+ source: string
29
+ }
30
+
31
+ type PluginEntry = {
32
+ item: Config.PluginSpec
33
+ meta: PluginMeta
34
+ }
35
+
36
+ type Acc = {
37
+ result: Info
38
+ entries: PluginEntry[]
39
+ }
40
+
41
+ export type Info = z.output<typeof Info> & {
42
+ // Internal resolved plugin list used by runtime loading.
43
+ plugin_records?: PluginRecord[]
44
+ }
45
+
46
+ function pluginScope(file: string): PluginMeta["scope"] {
47
+ if (Instance.containsPath(file)) return "local"
48
+ return "global"
49
+ }
50
+
51
+ function dedupePlugins(list: PluginEntry[]) {
52
+ const seen = new Set<string>()
53
+ const result: PluginEntry[] = []
54
+ for (const item of list.toReversed()) {
55
+ const spec = Config.pluginSpecifier(item.item)
56
+ const name = spec.startsWith("file://") ? spec : parsePluginSpecifier(spec).pkg
57
+ if (seen.has(name)) continue
58
+ seen.add(name)
59
+ result.push(item)
60
+ }
61
+ return result.toReversed()
62
+ }
63
+
64
+ function mergeInfo(target: Info, source: Info): Info {
65
+ const merged = mergeDeep(target, source)
66
+ if (target.plugin && source.plugin) {
67
+ merged.plugin = [...target.plugin, ...source.plugin]
68
+ }
69
+ return merged
70
+ }
71
+
72
+ function customPath() {
73
+ return Flag.VIKASIT_TUI_CONFIG
74
+ }
75
+
76
+ function normalize(raw: Record<string, unknown>) {
77
+ const data = { ...raw }
78
+ if (!("tui" in data)) return data
79
+ if (!isRecord(data.tui)) {
80
+ delete data.tui
81
+ return data
82
+ }
83
+
84
+ const tui = data.tui
85
+ delete data.tui
86
+ return {
87
+ ...tui,
88
+ ...data,
89
+ }
90
+ }
91
+
92
+ function installDeps(dir: string): Promise<void> {
93
+ return Config.installDependencies(dir)
94
+ }
95
+
96
+ async function mergeFile(acc: Acc, file: string) {
97
+ const data = await loadFile(file)
98
+ acc.result = mergeInfo(acc.result, data)
99
+ if (!data.plugin?.length) return
100
+
101
+ const scope = pluginScope(file)
102
+ for (const item of data.plugin) {
103
+ acc.entries.push({
104
+ item,
105
+ meta: {
106
+ scope,
107
+ source: file,
108
+ },
109
+ })
110
+ }
111
+ }
112
+
113
+ const state = Instance.state(async () => {
114
+ let projectFiles = Flag.VIKASIT_DISABLE_PROJECT_CONFIG
115
+ ? []
116
+ : await ConfigPaths.projectFiles("tui", Instance.directory, Instance.worktree)
117
+ const directories = await ConfigPaths.directories(Instance.directory, Instance.worktree)
118
+ const custom = customPath()
119
+ const managed = Config.managedConfigDir()
120
+ await migrateTuiConfig({ directories, custom, managed })
121
+ // Re-compute after migration since migrateTuiConfig may have created new tui.json files
122
+ projectFiles = Flag.VIKASIT_DISABLE_PROJECT_CONFIG
123
+ ? []
124
+ : await ConfigPaths.projectFiles("tui", Instance.directory, Instance.worktree)
125
+
126
+ const acc: Acc = {
127
+ result: {},
128
+ entries: [],
129
+ }
130
+
131
+ for (const file of ConfigPaths.fileInDirectory(Global.Path.config, "tui")) {
132
+ await mergeFile(acc, file)
133
+ }
134
+
135
+ if (custom) {
136
+ await mergeFile(acc, custom)
137
+ log.debug("loaded custom tui config", { path: custom })
138
+ }
139
+
140
+ for (const file of projectFiles) {
141
+ await mergeFile(acc, file)
142
+ }
143
+
144
+ for (const dir of unique(directories)) {
145
+ if (!dir.endsWith(".vikasit") && dir !== Flag.VIKASIT_CONFIG_DIR) continue
146
+ for (const file of ConfigPaths.fileInDirectory(dir, "tui")) {
147
+ await mergeFile(acc, file)
148
+ }
149
+ }
150
+
151
+ if (existsSync(managed)) {
152
+ for (const file of ConfigPaths.fileInDirectory(managed, "tui")) {
153
+ await mergeFile(acc, file)
154
+ }
155
+ }
156
+
157
+ const merged = dedupePlugins(acc.entries)
158
+ acc.result.keybinds = Config.Keybinds.parse(acc.result.keybinds ?? {})
159
+ const list = merged.map((item) => ({
160
+ item: item.item,
161
+ scope: item.meta.scope,
162
+ source: item.meta.source,
163
+ }))
164
+ acc.result.plugin = list.map((item) => item.item)
165
+ acc.result.plugin_records = list.length ? list : undefined
166
+
167
+ const deps: Promise<void>[] = []
168
+ if (acc.result.plugin?.length) {
169
+ for (const dir of unique(directories)) {
170
+ if (!dir.endsWith(".vikasit") && dir !== Flag.VIKASIT_CONFIG_DIR) continue
171
+ deps.push(installDeps(dir))
172
+ }
173
+ }
174
+
175
+ return {
176
+ config: acc.result,
177
+ deps,
178
+ }
179
+ })
180
+
181
+ export async function get() {
182
+ return state().then((x) => x.config)
183
+ }
184
+
185
+ export async function waitForDependencies() {
186
+ const deps = await state().then((x) => x.deps)
187
+ await Promise.all(deps)
188
+ }
189
+
190
+ async function loadFile(filepath: string): Promise<Info> {
191
+ const text = await ConfigPaths.readFile(filepath)
192
+ if (!text) return {}
193
+ return load(text, filepath).catch((error) => {
194
+ log.warn("failed to load tui config", { path: filepath, error })
195
+ return {}
196
+ })
197
+ }
198
+
199
+ async function load(text: string, configFilepath: string): Promise<Info> {
200
+ const raw = await ConfigPaths.parseText(text, configFilepath, "empty")
201
+ if (!isRecord(raw)) return {}
202
+
203
+ // Flatten a nested "tui" key so users who wrote `{ "tui": { ... } }` inside tui.json
204
+ // (mirroring the old vikasit.json shape) still get their settings applied.
205
+ const normalized = normalize(raw)
206
+
207
+ const parsed = Info.safeParse(normalized)
208
+ if (!parsed.success) {
209
+ log.warn("invalid tui config", { path: configFilepath, issues: parsed.error.issues })
210
+ return {}
211
+ }
212
+
213
+ const data = parsed.data
214
+ if (data.plugin) {
215
+ for (let i = 0; i < data.plugin.length; i++) {
216
+ data.plugin[i] = await Config.resolvePluginSpec(data.plugin[i], configFilepath)
217
+ }
218
+ }
219
+
220
+ return data
221
+ }
222
+ }