@vikasitai/vikasit-code 2.0.3 → 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 +167 -18
  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,998 @@
1
+ import "@opentui/solid/runtime-plugin-support"
2
+ import {
3
+ type TuiDispose,
4
+ type TuiPlugin,
5
+ type TuiPluginApi,
6
+ type TuiPluginInstallResult,
7
+ type TuiPluginModule,
8
+ type TuiPluginMeta,
9
+ type TuiPluginStatus,
10
+ type TuiTheme,
11
+ } from "@vikasit-code/plugin/tui"
12
+ import path from "path"
13
+ import { fileURLToPath } from "url"
14
+
15
+ import { Config } from "@/config/config"
16
+ import { TuiConfig } from "@/config/tui"
17
+ import { Log } from "@/util/log"
18
+ import { errorData, errorMessage } from "@/util/error"
19
+ import { isRecord } from "@/util/record"
20
+ import { Instance } from "@/project/instance"
21
+ import { pluginSource, readPluginId, readV1Plugin, resolvePluginId, type PluginSource } from "@/plugin/shared"
22
+ import { PluginLoader } from "@/plugin/loader"
23
+ import { PluginMeta } from "@/plugin/meta"
24
+ import { installPlugin as installModulePlugin, patchPluginConfig, readPluginManifest } from "@/plugin/install"
25
+ import { hasTheme, upsertTheme } from "../context/theme"
26
+ import { Global } from "@/global"
27
+ import { Filesystem } from "@/util/filesystem"
28
+ import { Process } from "@/util/process"
29
+ import { Flag } from "@/flag/flag"
30
+ import { INTERNAL_TUI_PLUGINS, type InternalTuiPlugin } from "./internal"
31
+ import { setupSlots, Slot as View } from "./slots"
32
+ import type { HostPluginApi, HostSlots } from "./slots"
33
+
34
+ type PluginLoad = {
35
+ options: Config.PluginOptions | undefined
36
+ spec: string
37
+ target: string
38
+ retry: boolean
39
+ source: PluginSource | "internal"
40
+ id: string
41
+ module: TuiPluginModule
42
+ theme_meta: TuiConfig.PluginMeta
43
+ theme_root: string
44
+ }
45
+
46
+ type Api = HostPluginApi
47
+
48
+ type PluginScope = {
49
+ lifecycle: TuiPluginApi["lifecycle"]
50
+ track: (fn: (() => void) | undefined) => () => void
51
+ dispose: () => Promise<void>
52
+ }
53
+
54
+ type PluginEntry = {
55
+ id: string
56
+ load: PluginLoad
57
+ meta: TuiPluginMeta
58
+ themes: Record<string, PluginMeta.Theme>
59
+ plugin: TuiPlugin
60
+ enabled: boolean
61
+ scope?: PluginScope
62
+ }
63
+
64
+ type RuntimeState = {
65
+ directory: string
66
+ api: Api
67
+ slots: HostSlots
68
+ plugins: PluginEntry[]
69
+ plugins_by_id: Map<string, PluginEntry>
70
+ pending: Map<string, TuiConfig.PluginRecord>
71
+ }
72
+
73
+ const log = Log.create({ service: "tui.plugin" })
74
+ const DISPOSE_TIMEOUT_MS = 5000
75
+ const KV_KEY = "plugin_enabled"
76
+
77
+ function fail(message: string, data: Record<string, unknown>) {
78
+ if (!("error" in data)) {
79
+ log.error(message, data)
80
+ console.error(`[tui.plugin] ${message}`, data)
81
+ return
82
+ }
83
+
84
+ const text = `${message}: ${errorMessage(data.error)}`
85
+ const next = { ...data, error: errorData(data.error) }
86
+ log.error(text, next)
87
+ console.error(`[tui.plugin] ${text}`, next)
88
+ }
89
+
90
+ function warn(message: string, data: Record<string, unknown>) {
91
+ log.warn(message, data)
92
+ console.warn(`[tui.plugin] ${message}`, data)
93
+ }
94
+
95
+ type CleanupResult = { type: "ok" } | { type: "error"; error: unknown } | { type: "timeout" }
96
+
97
+ function runCleanup(fn: () => unknown, ms: number): Promise<CleanupResult> {
98
+ return new Promise((resolve) => {
99
+ const timer = setTimeout(() => {
100
+ resolve({ type: "timeout" })
101
+ }, ms)
102
+
103
+ Promise.resolve()
104
+ .then(fn)
105
+ .then(
106
+ () => {
107
+ resolve({ type: "ok" })
108
+ },
109
+ (error) => {
110
+ resolve({ type: "error", error })
111
+ },
112
+ )
113
+ .finally(() => {
114
+ clearTimeout(timer)
115
+ })
116
+ })
117
+ }
118
+
119
+ function isTheme(value: unknown) {
120
+ if (!isRecord(value)) return false
121
+ if (!("theme" in value)) return false
122
+ if (!isRecord(value.theme)) return false
123
+ return true
124
+ }
125
+
126
+ function resolveRoot(root: string) {
127
+ if (root.startsWith("file://")) {
128
+ const file = fileURLToPath(root)
129
+ if (root.endsWith("/")) return file
130
+ return path.dirname(file)
131
+ }
132
+ if (path.isAbsolute(root)) return root
133
+ return path.resolve(process.cwd(), root)
134
+ }
135
+
136
+ function createThemeInstaller(
137
+ meta: TuiConfig.PluginMeta,
138
+ root: string,
139
+ spec: string,
140
+ plugin: PluginEntry,
141
+ ): TuiTheme["install"] {
142
+ return async (file) => {
143
+ const raw = file.startsWith("file://") ? fileURLToPath(file) : file
144
+ const src = path.isAbsolute(raw) ? raw : path.resolve(root, raw)
145
+ const name = path.basename(src, path.extname(src))
146
+ const source_dir = path.dirname(meta.source)
147
+ const local_dir =
148
+ path.basename(source_dir) === ".vikasit"
149
+ ? path.join(source_dir, "themes")
150
+ : path.join(source_dir, ".vikasit", "themes")
151
+ const dest_dir = meta.scope === "local" ? local_dir : path.join(Global.Path.config, "themes")
152
+ const dest = path.join(dest_dir, `${name}.json`)
153
+ const stat = await Filesystem.statAsync(src)
154
+ const mtime = stat ? Math.floor(typeof stat.mtimeMs === "bigint" ? Number(stat.mtimeMs) : stat.mtimeMs) : undefined
155
+ const size = stat ? (typeof stat.size === "bigint" ? Number(stat.size) : stat.size) : undefined
156
+ const exists = hasTheme(name)
157
+ const prev = plugin.themes[name]
158
+
159
+ if (exists) {
160
+ if (plugin.meta.state !== "updated") return
161
+ if (!prev) {
162
+ if (await Filesystem.exists(dest)) {
163
+ plugin.themes[name] = {
164
+ src,
165
+ dest,
166
+ mtime,
167
+ size,
168
+ }
169
+ await PluginMeta.setTheme(plugin.id, name, plugin.themes[name]!).catch((error) => {
170
+ log.warn("failed to track tui plugin theme", {
171
+ path: spec,
172
+ id: plugin.id,
173
+ theme: src,
174
+ dest,
175
+ error,
176
+ })
177
+ })
178
+ }
179
+ return
180
+ }
181
+ if (prev.dest !== dest) return
182
+ if (prev.mtime === mtime && prev.size === size) return
183
+ }
184
+
185
+ const text = await Filesystem.readText(src).catch((error) => {
186
+ log.warn("failed to read tui plugin theme", { path: spec, theme: src, error })
187
+ return
188
+ })
189
+ if (text === undefined) return
190
+
191
+ const fail = Symbol()
192
+ const data = await Promise.resolve(text)
193
+ .then((x) => JSON.parse(x))
194
+ .catch((error) => {
195
+ log.warn("failed to parse tui plugin theme", { path: spec, theme: src, error })
196
+ return fail
197
+ })
198
+ if (data === fail) return
199
+
200
+ if (!isTheme(data)) {
201
+ log.warn("invalid tui plugin theme", { path: spec, theme: src })
202
+ return
203
+ }
204
+
205
+ if (exists || !(await Filesystem.exists(dest))) {
206
+ await Filesystem.write(dest, text).catch((error) => {
207
+ log.warn("failed to persist tui plugin theme", { path: spec, theme: src, dest, error })
208
+ })
209
+ }
210
+
211
+ upsertTheme(name, data)
212
+ plugin.themes[name] = {
213
+ src,
214
+ dest,
215
+ mtime,
216
+ size,
217
+ }
218
+ await PluginMeta.setTheme(plugin.id, name, plugin.themes[name]!).catch((error) => {
219
+ log.warn("failed to track tui plugin theme", {
220
+ path: spec,
221
+ id: plugin.id,
222
+ theme: src,
223
+ dest,
224
+ error,
225
+ })
226
+ })
227
+ }
228
+ }
229
+
230
+ async function loadExternalPlugin(cfg: TuiConfig.PluginRecord, retry = false): Promise<PluginLoad | undefined> {
231
+ const plan = PluginLoader.plan(cfg.item)
232
+ if (plan.deprecated) return
233
+
234
+ log.info("loading tui plugin", { path: plan.spec, retry })
235
+ const resolved = await PluginLoader.resolve(plan, "tui")
236
+ if (!resolved.ok) {
237
+ if (resolved.stage === "missing") {
238
+ warn("tui plugin has no entrypoint", {
239
+ path: plan.spec,
240
+ retry,
241
+ message: resolved.message,
242
+ })
243
+ return
244
+ }
245
+
246
+ if (resolved.stage === "install") {
247
+ fail("failed to resolve tui plugin", { path: plan.spec, retry, error: resolved.error })
248
+ return
249
+ }
250
+ if (resolved.stage === "compatibility") {
251
+ fail("tui plugin incompatible", { path: plan.spec, retry, error: resolved.error })
252
+ return
253
+ }
254
+ fail("failed to resolve tui plugin entry", { path: plan.spec, retry, error: resolved.error })
255
+ return
256
+ }
257
+
258
+ const loaded = await PluginLoader.load(resolved.value)
259
+ if (!loaded.ok) {
260
+ fail("failed to load tui plugin", {
261
+ path: plan.spec,
262
+ target: resolved.value.entry,
263
+ retry,
264
+ error: loaded.error,
265
+ })
266
+ return
267
+ }
268
+
269
+ const mod = await Promise.resolve()
270
+ .then(() => {
271
+ return readV1Plugin(loaded.value.mod as Record<string, unknown>, plan.spec, "tui") as TuiPluginModule
272
+ })
273
+ .catch((error) => {
274
+ fail("failed to load tui plugin", {
275
+ path: plan.spec,
276
+ target: loaded.value.entry,
277
+ retry,
278
+ error,
279
+ })
280
+ return
281
+ })
282
+ if (!mod) return
283
+
284
+ const id = await resolvePluginId(
285
+ loaded.value.source,
286
+ plan.spec,
287
+ loaded.value.target,
288
+ readPluginId(mod.id, plan.spec),
289
+ loaded.value.pkg,
290
+ ).catch((error) => {
291
+ fail("failed to load tui plugin", { path: plan.spec, target: loaded.value.target, retry, error })
292
+ return
293
+ })
294
+ if (!id) return
295
+
296
+ return {
297
+ options: plan.options,
298
+ spec: plan.spec,
299
+ target: loaded.value.target,
300
+ retry,
301
+ source: loaded.value.source,
302
+ id,
303
+ module: mod,
304
+ theme_meta: {
305
+ scope: cfg.scope,
306
+ source: cfg.source,
307
+ },
308
+ theme_root: loaded.value.pkg?.dir ?? resolveRoot(loaded.value.target),
309
+ }
310
+ }
311
+
312
+ function createMeta(
313
+ source: PluginLoad["source"],
314
+ spec: string,
315
+ target: string,
316
+ meta: { state: PluginMeta.State; entry: PluginMeta.Entry } | undefined,
317
+ id?: string,
318
+ ): TuiPluginMeta {
319
+ if (meta) {
320
+ return {
321
+ state: meta.state,
322
+ ...meta.entry,
323
+ }
324
+ }
325
+
326
+ const now = Date.now()
327
+ return {
328
+ state: source === "internal" ? "same" : "first",
329
+ id: id ?? spec,
330
+ source,
331
+ spec,
332
+ target,
333
+ first_time: now,
334
+ last_time: now,
335
+ time_changed: now,
336
+ load_count: 1,
337
+ fingerprint: target,
338
+ }
339
+ }
340
+
341
+ function loadInternalPlugin(item: InternalTuiPlugin): PluginLoad {
342
+ const spec = item.id
343
+ const target = spec
344
+
345
+ return {
346
+ options: undefined,
347
+ spec,
348
+ target,
349
+ retry: false,
350
+ source: "internal",
351
+ id: item.id,
352
+ module: item,
353
+ theme_meta: {
354
+ scope: "global",
355
+ source: target,
356
+ },
357
+ theme_root: process.cwd(),
358
+ }
359
+ }
360
+
361
+ function createPluginScope(load: PluginLoad, id: string) {
362
+ const ctrl = new AbortController()
363
+ let list: { key: symbol; fn: TuiDispose }[] = []
364
+ let done = false
365
+
366
+ const onDispose = (fn: TuiDispose) => {
367
+ if (done) return () => {}
368
+ const key = Symbol()
369
+ list.push({ key, fn })
370
+ let drop = false
371
+ return () => {
372
+ if (drop) return
373
+ drop = true
374
+ list = list.filter((x) => x.key !== key)
375
+ }
376
+ }
377
+
378
+ const track = (fn: (() => void) | undefined) => {
379
+ if (!fn) return () => {}
380
+ const off = onDispose(fn)
381
+ let drop = false
382
+ return () => {
383
+ if (drop) return
384
+ drop = true
385
+ off()
386
+ fn()
387
+ }
388
+ }
389
+
390
+ const lifecycle: TuiPluginApi["lifecycle"] = {
391
+ signal: ctrl.signal,
392
+ onDispose,
393
+ }
394
+
395
+ const dispose = async () => {
396
+ if (done) return
397
+ done = true
398
+ ctrl.abort()
399
+ const queue = [...list].reverse()
400
+ list = []
401
+ const until = Date.now() + DISPOSE_TIMEOUT_MS
402
+ for (const item of queue) {
403
+ const left = until - Date.now()
404
+ if (left <= 0) {
405
+ fail("timed out cleaning up tui plugin", {
406
+ path: load.spec,
407
+ id,
408
+ timeout: DISPOSE_TIMEOUT_MS,
409
+ })
410
+ break
411
+ }
412
+
413
+ const out = await runCleanup(item.fn, left)
414
+ if (out.type === "ok") continue
415
+ if (out.type === "timeout") {
416
+ fail("timed out cleaning up tui plugin", {
417
+ path: load.spec,
418
+ id,
419
+ timeout: DISPOSE_TIMEOUT_MS,
420
+ })
421
+ break
422
+ }
423
+
424
+ if (out.type === "error") {
425
+ fail("failed to clean up tui plugin", {
426
+ path: load.spec,
427
+ id,
428
+ error: out.error,
429
+ })
430
+ }
431
+ }
432
+ }
433
+
434
+ return {
435
+ lifecycle,
436
+ track,
437
+ dispose,
438
+ }
439
+ }
440
+
441
+ function readPluginEnabledMap(value: unknown) {
442
+ if (!isRecord(value)) return {}
443
+ return Object.fromEntries(
444
+ Object.entries(value).filter((item): item is [string, boolean] => typeof item[1] === "boolean"),
445
+ )
446
+ }
447
+
448
+ function pluginEnabledState(state: RuntimeState, config: TuiConfig.Info) {
449
+ return {
450
+ ...readPluginEnabledMap(config.plugin_enabled),
451
+ ...readPluginEnabledMap(state.api.kv.get(KV_KEY, {})),
452
+ }
453
+ }
454
+
455
+ function writePluginEnabledState(api: Api, id: string, enabled: boolean) {
456
+ api.kv.set(KV_KEY, {
457
+ ...readPluginEnabledMap(api.kv.get(KV_KEY, {})),
458
+ [id]: enabled,
459
+ })
460
+ }
461
+
462
+ function listPluginStatus(state: RuntimeState): TuiPluginStatus[] {
463
+ return state.plugins.map((plugin) => ({
464
+ id: plugin.id,
465
+ source: plugin.meta.source,
466
+ spec: plugin.meta.spec,
467
+ target: plugin.meta.target,
468
+ enabled: plugin.enabled,
469
+ active: plugin.scope !== undefined,
470
+ }))
471
+ }
472
+
473
+ async function deactivatePluginEntry(state: RuntimeState, plugin: PluginEntry, persist: boolean) {
474
+ plugin.enabled = false
475
+ if (persist) writePluginEnabledState(state.api, plugin.id, false)
476
+ if (!plugin.scope) return true
477
+ const scope = plugin.scope
478
+ plugin.scope = undefined
479
+ await scope.dispose()
480
+ return true
481
+ }
482
+
483
+ async function activatePluginEntry(state: RuntimeState, plugin: PluginEntry, persist: boolean) {
484
+ plugin.enabled = true
485
+ if (persist) writePluginEnabledState(state.api, plugin.id, true)
486
+ if (plugin.scope) return true
487
+
488
+ const scope = createPluginScope(plugin.load, plugin.id)
489
+ const api = pluginApi(state, plugin, scope, plugin.id)
490
+ const ok = await Promise.resolve()
491
+ .then(async () => {
492
+ await plugin.plugin(api, plugin.load.options, plugin.meta)
493
+ return true
494
+ })
495
+ .catch((error) => {
496
+ fail("failed to initialize tui plugin", {
497
+ path: plugin.load.spec,
498
+ id: plugin.id,
499
+ error,
500
+ })
501
+ return false
502
+ })
503
+
504
+ if (!ok) {
505
+ await scope.dispose()
506
+ return false
507
+ }
508
+
509
+ if (!plugin.enabled) {
510
+ await scope.dispose()
511
+ return true
512
+ }
513
+
514
+ plugin.scope = scope
515
+ return true
516
+ }
517
+
518
+ async function activatePluginById(state: RuntimeState | undefined, id: string, persist: boolean) {
519
+ if (!state) return false
520
+ const plugin = state.plugins_by_id.get(id)
521
+ if (!plugin) return false
522
+ return activatePluginEntry(state, plugin, persist)
523
+ }
524
+
525
+ async function deactivatePluginById(state: RuntimeState | undefined, id: string, persist: boolean) {
526
+ if (!state) return false
527
+ const plugin = state.plugins_by_id.get(id)
528
+ if (!plugin) return false
529
+ return deactivatePluginEntry(state, plugin, persist)
530
+ }
531
+
532
+ function pluginApi(runtime: RuntimeState, plugin: PluginEntry, scope: PluginScope, base: string): TuiPluginApi {
533
+ const api = runtime.api
534
+ const host = runtime.slots
535
+ const load = plugin.load
536
+ const command: TuiPluginApi["command"] = {
537
+ register(cb) {
538
+ return scope.track(api.command.register(cb))
539
+ },
540
+ trigger(value) {
541
+ api.command.trigger(value)
542
+ },
543
+ }
544
+
545
+ const route: TuiPluginApi["route"] = {
546
+ register(list) {
547
+ return scope.track(api.route.register(list))
548
+ },
549
+ navigate(name, params) {
550
+ api.route.navigate(name, params)
551
+ },
552
+ get current() {
553
+ return api.route.current
554
+ },
555
+ }
556
+
557
+ const theme: TuiPluginApi["theme"] = Object.assign(Object.create(api.theme), {
558
+ install: createThemeInstaller(load.theme_meta, load.theme_root, load.spec, plugin),
559
+ })
560
+
561
+ const event: TuiPluginApi["event"] = {
562
+ on(type, handler) {
563
+ return scope.track(api.event.on(type, handler))
564
+ },
565
+ }
566
+
567
+ let count = 0
568
+
569
+ const slots: TuiPluginApi["slots"] = {
570
+ register(plugin) {
571
+ const id = count ? `${base}:${count}` : base
572
+ count += 1
573
+ scope.track(host.register({ ...plugin, id }))
574
+ return id
575
+ },
576
+ }
577
+
578
+ return {
579
+ app: api.app,
580
+ command,
581
+ route,
582
+ ui: api.ui,
583
+ keybind: api.keybind,
584
+ tuiConfig: api.tuiConfig,
585
+ kv: api.kv,
586
+ state: api.state,
587
+ theme,
588
+ get client() {
589
+ return api.client
590
+ },
591
+ scopedClient: api.scopedClient,
592
+ workspace: api.workspace,
593
+ event,
594
+ renderer: api.renderer,
595
+ slots,
596
+ plugins: {
597
+ list() {
598
+ return listPluginStatus(runtime)
599
+ },
600
+ activate(id) {
601
+ return activatePluginById(runtime, id, true)
602
+ },
603
+ deactivate(id) {
604
+ return deactivatePluginById(runtime, id, true)
605
+ },
606
+ add(spec) {
607
+ return addPluginBySpec(runtime, spec)
608
+ },
609
+ install(spec, options) {
610
+ return installPluginBySpec(runtime, spec, options?.global)
611
+ },
612
+ },
613
+ lifecycle: scope.lifecycle,
614
+ }
615
+ }
616
+
617
+ function addPluginEntry(state: RuntimeState, plugin: PluginEntry) {
618
+ if (state.plugins_by_id.has(plugin.id)) {
619
+ fail("duplicate tui plugin id", {
620
+ id: plugin.id,
621
+ path: plugin.load.spec,
622
+ })
623
+ return false
624
+ }
625
+
626
+ state.plugins_by_id.set(plugin.id, plugin)
627
+ state.plugins.push(plugin)
628
+ return true
629
+ }
630
+
631
+ function applyInitialPluginEnabledState(state: RuntimeState, config: TuiConfig.Info) {
632
+ const map = pluginEnabledState(state, config)
633
+ for (const plugin of state.plugins) {
634
+ const enabled = map[plugin.id]
635
+ if (enabled === undefined) continue
636
+ plugin.enabled = enabled
637
+ }
638
+ }
639
+
640
+ async function resolveExternalPlugins(list: TuiConfig.PluginRecord[], wait: () => Promise<void>) {
641
+ const loaded = await Promise.all(list.map((item) => loadExternalPlugin(item)))
642
+ const ready: PluginLoad[] = []
643
+ let deps: Promise<void> | undefined
644
+
645
+ for (let i = 0; i < list.length; i++) {
646
+ let entry = loaded[i]
647
+ if (!entry) {
648
+ const item = list[i]
649
+ if (!item) continue
650
+ if (pluginSource(Config.pluginSpecifier(item.item)) !== "file") continue
651
+ deps ??= wait().catch((error) => {
652
+ log.warn("failed waiting for tui plugin dependencies", { error })
653
+ })
654
+ await deps
655
+ entry = await loadExternalPlugin(item, true)
656
+ }
657
+ if (!entry) continue
658
+ ready.push(entry)
659
+ }
660
+
661
+ return ready
662
+ }
663
+
664
+ async function addExternalPluginEntries(state: RuntimeState, ready: PluginLoad[]) {
665
+ if (!ready.length) return { plugins: [] as PluginEntry[], ok: true }
666
+
667
+ const meta = await PluginMeta.touchMany(
668
+ ready.map((item) => ({
669
+ spec: item.spec,
670
+ target: item.target,
671
+ id: item.id,
672
+ })),
673
+ ).catch((error) => {
674
+ log.warn("failed to track tui plugins", { error })
675
+ return undefined
676
+ })
677
+
678
+ const plugins: PluginEntry[] = []
679
+ let ok = true
680
+ for (let i = 0; i < ready.length; i++) {
681
+ const entry = ready[i]
682
+ if (!entry) continue
683
+ const hit = meta?.[i]
684
+ if (hit && hit.state !== "same") {
685
+ log.info("tui plugin metadata updated", {
686
+ path: entry.spec,
687
+ retry: entry.retry,
688
+ state: hit.state,
689
+ source: hit.entry.source,
690
+ version: hit.entry.version,
691
+ modified: hit.entry.modified,
692
+ })
693
+ }
694
+
695
+ const row = createMeta(entry.source, entry.spec, entry.target, hit, entry.id)
696
+ const themes = hit?.entry.themes ? { ...hit.entry.themes } : {}
697
+ const plugin: PluginEntry = {
698
+ id: entry.id,
699
+ load: entry,
700
+ meta: row,
701
+ themes,
702
+ plugin: entry.module.tui,
703
+ enabled: true,
704
+ }
705
+ if (!addPluginEntry(state, plugin)) {
706
+ ok = false
707
+ continue
708
+ }
709
+ plugins.push(plugin)
710
+ }
711
+
712
+ return { plugins, ok }
713
+ }
714
+
715
+ function defaultPluginRecord(state: RuntimeState, spec: string): TuiConfig.PluginRecord {
716
+ return {
717
+ item: spec,
718
+ scope: "local",
719
+ source: state.api.state.path.config || path.join(state.directory, ".vikasit", "tui.json"),
720
+ }
721
+ }
722
+
723
+ function installCause(err: unknown) {
724
+ if (!err || typeof err !== "object") return
725
+ if (!("cause" in err)) return
726
+ return (err as { cause?: unknown }).cause
727
+ }
728
+
729
+ function installDetail(err: unknown) {
730
+ const hit = installCause(err) ?? err
731
+ if (!(hit instanceof Process.RunFailedError)) {
732
+ return {
733
+ message: errorMessage(hit),
734
+ missing: false,
735
+ }
736
+ }
737
+
738
+ const lines = hit.stderr
739
+ .toString()
740
+ .split(/\r?\n/)
741
+ .map((line) => line.trim())
742
+ .filter(Boolean)
743
+ const errs = lines.filter((line) => line.startsWith("error:")).map((line) => line.replace(/^error:\s*/, ""))
744
+ return {
745
+ message: errs[0] ?? lines.at(-1) ?? errorMessage(hit),
746
+ missing: lines.some((line) => line.includes("No version matching")),
747
+ }
748
+ }
749
+
750
+ async function addPluginBySpec(state: RuntimeState | undefined, raw: string) {
751
+ if (!state) return false
752
+ const spec = raw.trim()
753
+ if (!spec) return false
754
+
755
+ const cfg = state.pending.get(spec) ?? defaultPluginRecord(state, spec)
756
+ const next = Config.pluginSpecifier(cfg.item)
757
+ if (state.plugins.some((plugin) => plugin.load.spec === next)) {
758
+ state.pending.delete(spec)
759
+ return true
760
+ }
761
+
762
+ const ready = await Instance.provide({
763
+ directory: state.directory,
764
+ fn: () => resolveExternalPlugins([cfg], () => TuiConfig.waitForDependencies()),
765
+ }).catch((error) => {
766
+ fail("failed to add tui plugin", { path: next, error })
767
+ return [] as PluginLoad[]
768
+ })
769
+ if (!ready.length) {
770
+ return false
771
+ }
772
+
773
+ const first = ready[0]
774
+ if (!first) {
775
+ fail("failed to add tui plugin", { path: next })
776
+ return false
777
+ }
778
+ if (state.plugins_by_id.has(first.id)) {
779
+ state.pending.delete(spec)
780
+ return true
781
+ }
782
+
783
+ const out = await addExternalPluginEntries(state, [first])
784
+ let ok = out.ok && out.plugins.length > 0
785
+ for (const plugin of out.plugins) {
786
+ const active = await activatePluginEntry(state, plugin, false)
787
+ if (!active) ok = false
788
+ }
789
+
790
+ if (ok) state.pending.delete(spec)
791
+ if (!ok) {
792
+ fail("failed to add tui plugin", { path: next })
793
+ }
794
+ return ok
795
+ }
796
+
797
+ async function installPluginBySpec(
798
+ state: RuntimeState | undefined,
799
+ raw: string,
800
+ global = false,
801
+ ): Promise<TuiPluginInstallResult> {
802
+ if (!state) {
803
+ return {
804
+ ok: false,
805
+ message: "Plugin runtime is not ready.",
806
+ }
807
+ }
808
+
809
+ const spec = raw.trim()
810
+ if (!spec) {
811
+ return {
812
+ ok: false,
813
+ message: "Plugin package name is required",
814
+ }
815
+ }
816
+
817
+ const dir = state.api.state.path
818
+ if (!dir.directory) {
819
+ return {
820
+ ok: false,
821
+ message: "Paths are still syncing. Try again in a moment.",
822
+ }
823
+ }
824
+
825
+ const install = await installModulePlugin(spec)
826
+ if (!install.ok) {
827
+ const out = installDetail(install.error)
828
+ return {
829
+ ok: false,
830
+ message: out.message,
831
+ missing: out.missing,
832
+ }
833
+ }
834
+
835
+ const manifest = await readPluginManifest(install.target)
836
+ if (!manifest.ok) {
837
+ if (manifest.code === "manifest_no_targets") {
838
+ return {
839
+ ok: false,
840
+ message: `"${spec}" does not expose plugin entrypoints in package.json`,
841
+ }
842
+ }
843
+
844
+ return {
845
+ ok: false,
846
+ message: `Installed "${spec}" but failed to read ${manifest.file}`,
847
+ }
848
+ }
849
+
850
+ const patch = await patchPluginConfig({
851
+ spec,
852
+ targets: manifest.targets,
853
+ global,
854
+ vcs: dir.worktree && dir.worktree !== "/" ? "git" : undefined,
855
+ worktree: dir.worktree,
856
+ directory: dir.directory,
857
+ })
858
+ if (!patch.ok) {
859
+ if (patch.code === "invalid_json") {
860
+ return {
861
+ ok: false,
862
+ message: `Invalid JSON in ${patch.file} (${patch.parse} at line ${patch.line}, column ${patch.col})`,
863
+ }
864
+ }
865
+
866
+ return {
867
+ ok: false,
868
+ message: errorMessage(patch.error),
869
+ }
870
+ }
871
+
872
+ const tui = manifest.targets.find((item) => item.kind === "tui")
873
+ if (tui) {
874
+ const file = patch.items.find((item) => item.kind === "tui")?.file
875
+ const item = tui.opts ? ([spec, tui.opts] as Config.PluginSpec) : spec
876
+ state.pending.set(spec, {
877
+ item,
878
+ scope: global ? "global" : "local",
879
+ source: (file ?? dir.config) || path.join(patch.dir, "tui.json"),
880
+ })
881
+ }
882
+
883
+ return {
884
+ ok: true,
885
+ dir: patch.dir,
886
+ tui: Boolean(tui),
887
+ }
888
+ }
889
+
890
+ export namespace TuiPluginRuntime {
891
+ let dir = ""
892
+ let loaded: Promise<void> | undefined
893
+ let runtime: RuntimeState | undefined
894
+ export const Slot = View
895
+
896
+ export async function init(api: HostPluginApi) {
897
+ const cwd = process.cwd()
898
+ if (loaded) {
899
+ if (dir !== cwd) {
900
+ throw new Error(`TuiPluginRuntime.init() called with a different working directory. expected=${dir} got=${cwd}`)
901
+ }
902
+ return loaded
903
+ }
904
+
905
+ dir = cwd
906
+ loaded = load(api)
907
+ return loaded
908
+ }
909
+
910
+ export function list() {
911
+ if (!runtime) return []
912
+ return listPluginStatus(runtime)
913
+ }
914
+
915
+ export async function activatePlugin(id: string) {
916
+ return activatePluginById(runtime, id, true)
917
+ }
918
+
919
+ export async function deactivatePlugin(id: string) {
920
+ return deactivatePluginById(runtime, id, true)
921
+ }
922
+
923
+ export async function addPlugin(spec: string) {
924
+ return addPluginBySpec(runtime, spec)
925
+ }
926
+
927
+ export async function installPlugin(spec: string, options?: { global?: boolean }) {
928
+ return installPluginBySpec(runtime, spec, options?.global)
929
+ }
930
+
931
+ export async function dispose() {
932
+ const task = loaded
933
+ loaded = undefined
934
+ dir = ""
935
+ if (task) await task
936
+ const state = runtime
937
+ runtime = undefined
938
+ if (!state) return
939
+ const queue = [...state.plugins].reverse()
940
+ for (const plugin of queue) {
941
+ await deactivatePluginEntry(state, plugin, false)
942
+ }
943
+ }
944
+
945
+ async function load(api: Api) {
946
+ const cwd = process.cwd()
947
+ const slots = setupSlots(api)
948
+ const next: RuntimeState = {
949
+ directory: cwd,
950
+ api,
951
+ slots,
952
+ plugins: [],
953
+ plugins_by_id: new Map(),
954
+ pending: new Map(),
955
+ }
956
+ runtime = next
957
+
958
+ await Instance.provide({
959
+ directory: cwd,
960
+ fn: async () => {
961
+ const config = await TuiConfig.get()
962
+ const records = Flag.VIKASIT_PURE ? [] : (config.plugin_records ?? [])
963
+ if (Flag.VIKASIT_PURE && config.plugin_records?.length) {
964
+ log.info("skipping external tui plugins in pure mode", { count: config.plugin_records.length })
965
+ }
966
+
967
+ for (const item of INTERNAL_TUI_PLUGINS) {
968
+ log.info("loading internal tui plugin", { id: item.id })
969
+ const entry = loadInternalPlugin(item)
970
+ const meta = createMeta(entry.source, entry.spec, entry.target, undefined, entry.id)
971
+ addPluginEntry(next, {
972
+ id: entry.id,
973
+ load: entry,
974
+ meta,
975
+ themes: {},
976
+ plugin: entry.module.tui,
977
+ enabled: true,
978
+ })
979
+ }
980
+
981
+ const ready = await resolveExternalPlugins(records, () => TuiConfig.waitForDependencies())
982
+ await addExternalPluginEntries(next, ready)
983
+
984
+ applyInitialPluginEnabledState(next, config)
985
+ for (const plugin of next.plugins) {
986
+ if (!plugin.enabled) continue
987
+ // Keep plugin execution sequential for deterministic side effects:
988
+ // command registration order affects keybind/command precedence,
989
+ // route registration is last-wins when ids collide,
990
+ // and hook chains rely on stable plugin ordering.
991
+ await activatePluginEntry(next, plugin, false)
992
+ }
993
+ },
994
+ }).catch((error) => {
995
+ fail("failed to load tui plugins", { directory: cwd, error })
996
+ })
997
+ }
998
+ }