@thevinci/web 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/README.md +197 -0
  2. package/bin/cli-entry.js +55 -0
  3. package/bin/cli-output.js +145 -0
  4. package/bin/cli.js +4887 -0
  5. package/bin/cli.test.js +64 -0
  6. package/dist/apple-touch-icon-120x120.png +0 -0
  7. package/dist/apple-touch-icon-152x152.png +0 -0
  8. package/dist/apple-touch-icon-167x167.png +0 -0
  9. package/dist/apple-touch-icon-180x180.png +0 -0
  10. package/dist/apple-touch-icon.png +0 -0
  11. package/dist/apple-touch-icon.svg +528 -0
  12. package/dist/assets/JsonTreeView-CSm9OzXG.js +1 -0
  13. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  14. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  15. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  16. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  17. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  18. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  19. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  20. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  21. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  22. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  23. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  24. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  25. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  26. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  27. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  28. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  29. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  30. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  31. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  32. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  33. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  34. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  35. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  36. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  37. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  38. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  39. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  40. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  41. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  42. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  43. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  44. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  45. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  46. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  47. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  48. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  49. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  50. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  51. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  52. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  53. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  54. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  55. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  56. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  57. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  58. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  59. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  60. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  61. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  62. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  63. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  64. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  65. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  66. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  67. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  68. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  69. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  70. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  71. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  72. package/dist/assets/MarkdownRendererImpl-DensKOLc.js +6 -0
  73. package/dist/assets/MultiRunWindow-Bo7THayo.js +1 -0
  74. package/dist/assets/OnboardingScreen-BDqmzTVR.js +2 -0
  75. package/dist/assets/SettingsWindow-coz__Ykw.js +1 -0
  76. package/dist/assets/TerminalView-DrZ-i3Dr.js +1 -0
  77. package/dist/assets/ToolOutputDialog-Eglzslt3.js +16 -0
  78. package/dist/assets/es-4o9ciP61.js +15 -0
  79. package/dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  80. package/dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  81. package/dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  82. package/dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  83. package/dist/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
  84. package/dist/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
  85. package/dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  86. package/dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  87. package/dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  88. package/dist/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  89. package/dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  90. package/dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  91. package/dist/assets/index-DLTDToSP.css +1 -0
  92. package/dist/assets/index-DgiFEKGN.js +1 -0
  93. package/dist/assets/ko-B20imCHE.js +15 -0
  94. package/dist/assets/main-BV3KOtdA.css +1 -0
  95. package/dist/assets/main-CDKJj0sH.js +226 -0
  96. package/dist/assets/main-LC-PSNVM.js +2 -0
  97. package/dist/assets/miniChat-CQUiG_cr.js +2 -0
  98. package/dist/assets/modelPrefsAutoSave-Dm799vzR.js +6986 -0
  99. package/dist/assets/pl-DQJ7LSzj.js +15 -0
  100. package/dist/assets/pt-BR-OmjHUz9y.js +15 -0
  101. package/dist/assets/renderElectronMiniChatApp-CARbeW0G.js +2 -0
  102. package/dist/assets/uk-BNFxOlO4.js +15 -0
  103. package/dist/assets/vendor--DBfsbEis.css +1 -0
  104. package/dist/assets/vendor-.bun-B9l0ZNi2.js +4094 -0
  105. package/dist/assets/wasm-CG6Dc4jp.js +1 -0
  106. package/dist/assets/wasmSttWorker-Dtlxac_K.js +1 -0
  107. package/dist/assets/wasmSttWorker-oo7Dm_jy.js +1806 -0
  108. package/dist/assets/worker-CbT6TVo7.js +155 -0
  109. package/dist/assets/zh-CN-C6T-Ac7F.js +15 -0
  110. package/dist/favicon-16.png +0 -0
  111. package/dist/favicon-32.png +0 -0
  112. package/dist/favicon.png +0 -0
  113. package/dist/favicon.svg +528 -0
  114. package/dist/index.html +607 -0
  115. package/dist/logo-dark-192x192.png +0 -0
  116. package/dist/logo-dark-512x512.png +0 -0
  117. package/dist/logo-dark-512x512.svg +528 -0
  118. package/dist/logo-light-192x192.png +0 -0
  119. package/dist/logo-light-512x512.png +0 -0
  120. package/dist/logo-light-512x512.svg +528 -0
  121. package/dist/mini-chat.html +16 -0
  122. package/dist/pwa-192.png +0 -0
  123. package/dist/pwa-512.png +0 -0
  124. package/dist/pwa-maskable-192.png +0 -0
  125. package/dist/pwa-maskable-512.png +0 -0
  126. package/dist/site.webmanifest +21 -0
  127. package/dist/sw.js +1 -0
  128. package/package.json +118 -0
  129. package/public/apple-touch-icon-120x120.png +0 -0
  130. package/public/apple-touch-icon-152x152.png +0 -0
  131. package/public/apple-touch-icon-167x167.png +0 -0
  132. package/public/apple-touch-icon-180x180.png +0 -0
  133. package/public/apple-touch-icon.png +0 -0
  134. package/public/apple-touch-icon.svg +528 -0
  135. package/public/favicon-16.png +0 -0
  136. package/public/favicon-32.png +0 -0
  137. package/public/favicon.png +0 -0
  138. package/public/favicon.svg +528 -0
  139. package/public/logo-dark-192x192.png +0 -0
  140. package/public/logo-dark-512x512.png +0 -0
  141. package/public/logo-dark-512x512.svg +528 -0
  142. package/public/logo-light-192x192.png +0 -0
  143. package/public/logo-light-512x512.png +0 -0
  144. package/public/logo-light-512x512.svg +528 -0
  145. package/public/pwa-192.png +0 -0
  146. package/public/pwa-512.png +0 -0
  147. package/public/pwa-maskable-192.png +0 -0
  148. package/public/pwa-maskable-512.png +0 -0
  149. package/public/site.webmanifest +21 -0
  150. package/server/TERMINAL_WS_PROTOCOL.md +48 -0
  151. package/server/index.d.ts +39 -0
  152. package/server/index.js +1311 -0
  153. package/server/lib/cloudflare-tunnel.js +650 -0
  154. package/server/lib/event-stream/DOCUMENTATION.md +61 -0
  155. package/server/lib/event-stream/directory-ws-bridge.js +185 -0
  156. package/server/lib/event-stream/global-hub.js +158 -0
  157. package/server/lib/event-stream/global-hub.test.js +140 -0
  158. package/server/lib/event-stream/global-ws-bridge.js +206 -0
  159. package/server/lib/event-stream/index.js +25 -0
  160. package/server/lib/event-stream/protocol.js +131 -0
  161. package/server/lib/event-stream/protocol.test.js +182 -0
  162. package/server/lib/event-stream/runtime.js +180 -0
  163. package/server/lib/event-stream/runtime.test.js +512 -0
  164. package/server/lib/event-stream/upstream-reader.js +226 -0
  165. package/server/lib/event-stream/upstream-reader.test.js +276 -0
  166. package/server/lib/fs/DOCUMENTATION.md +36 -0
  167. package/server/lib/fs/routes.js +1040 -0
  168. package/server/lib/fs/search.js +238 -0
  169. package/server/lib/git/DOCUMENTATION.md +152 -0
  170. package/server/lib/git/credentials.js +74 -0
  171. package/server/lib/git/identity-storage.js +112 -0
  172. package/server/lib/git/index.js +6 -0
  173. package/server/lib/git/routes.js +972 -0
  174. package/server/lib/git/service.js +3432 -0
  175. package/server/lib/git/service.test.js +39 -0
  176. package/server/lib/github/DOCUMENTATION.md +171 -0
  177. package/server/lib/github/auth.js +307 -0
  178. package/server/lib/github/device-flow.js +50 -0
  179. package/server/lib/github/index.js +24 -0
  180. package/server/lib/github/octokit.js +10 -0
  181. package/server/lib/github/pr-status.js +519 -0
  182. package/server/lib/github/repo/fork-detection.js +102 -0
  183. package/server/lib/github/repo/index.js +55 -0
  184. package/server/lib/github/routes.js +1560 -0
  185. package/server/lib/magic-prompts/routes.js +63 -0
  186. package/server/lib/magic-prompts/runtime.js +119 -0
  187. package/server/lib/notifications/DOCUMENTATION.md +122 -0
  188. package/server/lib/notifications/emitter-runtime.js +102 -0
  189. package/server/lib/notifications/index.js +4 -0
  190. package/server/lib/notifications/message.js +52 -0
  191. package/server/lib/notifications/message.test.js +34 -0
  192. package/server/lib/notifications/push-runtime.js +304 -0
  193. package/server/lib/notifications/routes.js +315 -0
  194. package/server/lib/notifications/runtime.js +566 -0
  195. package/server/lib/notifications/template-runtime.js +349 -0
  196. package/server/lib/notifications/template-runtime.test.js +26 -0
  197. package/server/lib/opencode/DOCUMENTATION.md +362 -0
  198. package/server/lib/opencode/agents.js +634 -0
  199. package/server/lib/opencode/auth-state-runtime.js +88 -0
  200. package/server/lib/opencode/auth.js +83 -0
  201. package/server/lib/opencode/bootstrap-runtime.js +131 -0
  202. package/server/lib/opencode/cli-entry-runtime.js +43 -0
  203. package/server/lib/opencode/cli-options.js +128 -0
  204. package/server/lib/opencode/commands.js +339 -0
  205. package/server/lib/opencode/config-entity-routes.js +370 -0
  206. package/server/lib/opencode/core-routes.js +500 -0
  207. package/server/lib/opencode/core-routes.test.js +26 -0
  208. package/server/lib/opencode/env-config.js +74 -0
  209. package/server/lib/opencode/env-keys.js +68 -0
  210. package/server/lib/opencode/env-runtime.js +1162 -0
  211. package/server/lib/opencode/env-runtime.test.js +116 -0
  212. package/server/lib/opencode/feature-routes-runtime.js +244 -0
  213. package/server/lib/opencode/hmr-state-runtime.js +85 -0
  214. package/server/lib/opencode/index.js +66 -0
  215. package/server/lib/opencode/lifecycle.js +1019 -0
  216. package/server/lib/opencode/lifecycle.test.js +240 -0
  217. package/server/lib/opencode/mcp.js +278 -0
  218. package/server/lib/opencode/network-runtime.js +104 -0
  219. package/server/lib/opencode/network-runtime.test.js +37 -0
  220. package/server/lib/opencode/opencode-resolution-runtime.js +71 -0
  221. package/server/lib/opencode/path-utils.js +100 -0
  222. package/server/lib/opencode/path-utils.test.js +71 -0
  223. package/server/lib/opencode/project-directory-runtime.js +124 -0
  224. package/server/lib/opencode/project-icon-routes.js +399 -0
  225. package/server/lib/opencode/project-icon-routes.test.js +107 -0
  226. package/server/lib/opencode/providers.js +96 -0
  227. package/server/lib/opencode/proxy.js +445 -0
  228. package/server/lib/opencode/pwa-manifest-routes.js +257 -0
  229. package/server/lib/opencode/pwa-manifest-routes.test.js +133 -0
  230. package/server/lib/opencode/routes.js +541 -0
  231. package/server/lib/opencode/server-startup-runtime.js +156 -0
  232. package/server/lib/opencode/server-utils-runtime.js +168 -0
  233. package/server/lib/opencode/server-utils-runtime.test.js +135 -0
  234. package/server/lib/opencode/session-runtime.js +356 -0
  235. package/server/lib/opencode/session-runtime.test.js +151 -0
  236. package/server/lib/opencode/settings-helpers.js +770 -0
  237. package/server/lib/opencode/settings-helpers.test.js +109 -0
  238. package/server/lib/opencode/settings-normalization-runtime.js +428 -0
  239. package/server/lib/opencode/settings-runtime.js +826 -0
  240. package/server/lib/opencode/settings-runtime.test.js +85 -0
  241. package/server/lib/opencode/shared.js +615 -0
  242. package/server/lib/opencode/shutdown-runtime.js +139 -0
  243. package/server/lib/opencode/shutdown-runtime.test.js +58 -0
  244. package/server/lib/opencode/skill-routes.js +701 -0
  245. package/server/lib/opencode/skills.js +548 -0
  246. package/server/lib/opencode/startup-pipeline-runtime.js +130 -0
  247. package/server/lib/opencode/static-routes-runtime.js +65 -0
  248. package/server/lib/opencode/theme-runtime.js +167 -0
  249. package/server/lib/opencode/tunnel-auth.js +591 -0
  250. package/server/lib/opencode/tunnel-wiring-runtime.js +94 -0
  251. package/server/lib/opencode/vinci-routes.js +76 -0
  252. package/server/lib/opencode/watcher.js +115 -0
  253. package/server/lib/opencode/watcher.test.js +239 -0
  254. package/server/lib/preview/proxy-runtime.js +1333 -0
  255. package/server/lib/preview/proxy-runtime.test.js +144 -0
  256. package/server/lib/projects/project-config.js +567 -0
  257. package/server/lib/projects/project-config.test.js +175 -0
  258. package/server/lib/projects/project-id.js +13 -0
  259. package/server/lib/quota/DOCUMENTATION.md +58 -0
  260. package/server/lib/quota/index.js +25 -0
  261. package/server/lib/quota/providers/claude.js +107 -0
  262. package/server/lib/quota/providers/codex.js +113 -0
  263. package/server/lib/quota/providers/copilot.js +165 -0
  264. package/server/lib/quota/providers/google/api.js +92 -0
  265. package/server/lib/quota/providers/google/auth.js +108 -0
  266. package/server/lib/quota/providers/google/index.js +124 -0
  267. package/server/lib/quota/providers/google/transforms.js +109 -0
  268. package/server/lib/quota/providers/index.js +168 -0
  269. package/server/lib/quota/providers/interface.js +55 -0
  270. package/server/lib/quota/providers/kimi.js +108 -0
  271. package/server/lib/quota/providers/minimax-cn-coding-plan.js +140 -0
  272. package/server/lib/quota/providers/minimax-coding-plan.js +139 -0
  273. package/server/lib/quota/providers/nanogpt.js +124 -0
  274. package/server/lib/quota/providers/ollama-cloud.js +112 -0
  275. package/server/lib/quota/providers/openai.js +91 -0
  276. package/server/lib/quota/providers/openrouter.js +92 -0
  277. package/server/lib/quota/providers/zai.js +91 -0
  278. package/server/lib/quota/providers/zhipuai-coding-plan.js +133 -0
  279. package/server/lib/quota/providers/zhipuai.js +114 -0
  280. package/server/lib/quota/routes.js +27 -0
  281. package/server/lib/quota/utils/auth.js +50 -0
  282. package/server/lib/quota/utils/formatters.js +85 -0
  283. package/server/lib/quota/utils/formatters.test.js +54 -0
  284. package/server/lib/quota/utils/index.js +10 -0
  285. package/server/lib/quota/utils/transformers.js +55 -0
  286. package/server/lib/scheduled-tasks/DOCUMENTATION.md +44 -0
  287. package/server/lib/scheduled-tasks/routes.js +235 -0
  288. package/server/lib/scheduled-tasks/runtime.js +773 -0
  289. package/server/lib/scheduled-tasks/runtime.test.js +100 -0
  290. package/server/lib/security/request-security.js +115 -0
  291. package/server/lib/session-folders/routes.js +63 -0
  292. package/server/lib/session-folders/routes.test.js +102 -0
  293. package/server/lib/skills-catalog/DOCUMENTATION.md +178 -0
  294. package/server/lib/skills-catalog/cache.js +29 -0
  295. package/server/lib/skills-catalog/clawdhub/api.js +158 -0
  296. package/server/lib/skills-catalog/clawdhub/index.js +30 -0
  297. package/server/lib/skills-catalog/clawdhub/install.js +238 -0
  298. package/server/lib/skills-catalog/clawdhub/scan.js +113 -0
  299. package/server/lib/skills-catalog/curated-sources.js +21 -0
  300. package/server/lib/skills-catalog/git.js +77 -0
  301. package/server/lib/skills-catalog/index.js +42 -0
  302. package/server/lib/skills-catalog/install.js +294 -0
  303. package/server/lib/skills-catalog/scan.js +221 -0
  304. package/server/lib/skills-catalog/source.js +87 -0
  305. package/server/lib/terminal/DOCUMENTATION.md +76 -0
  306. package/server/lib/terminal/index.js +31 -0
  307. package/server/lib/terminal/output-replay-buffer.js +78 -0
  308. package/server/lib/terminal/output-replay-buffer.test.js +75 -0
  309. package/server/lib/terminal/runtime.js +850 -0
  310. package/server/lib/terminal/runtime.test.js +96 -0
  311. package/server/lib/terminal/terminal-ws-protocol.js +68 -0
  312. package/server/lib/terminal/terminal-ws-protocol.test.js +145 -0
  313. package/server/lib/text/DOCUMENTATION.md +35 -0
  314. package/server/lib/text/summarization.js +138 -0
  315. package/server/lib/text/summarization.test.js +34 -0
  316. package/server/lib/tts/DOCUMENTATION.md +146 -0
  317. package/server/lib/tts/base-url.js +62 -0
  318. package/server/lib/tts/capability-runtime.js +31 -0
  319. package/server/lib/tts/index.js +19 -0
  320. package/server/lib/tts/routes.js +261 -0
  321. package/server/lib/tts/routes.test.js +53 -0
  322. package/server/lib/tts/service.js +178 -0
  323. package/server/lib/tts/stt.js +75 -0
  324. package/server/lib/tunnels/DOCUMENTATION.md +18 -0
  325. package/server/lib/tunnels/index.js +166 -0
  326. package/server/lib/tunnels/managed-config.js +201 -0
  327. package/server/lib/tunnels/providers/cloudflare.js +260 -0
  328. package/server/lib/tunnels/registry.js +51 -0
  329. package/server/lib/tunnels/routes.js +605 -0
  330. package/server/lib/tunnels/types.js +219 -0
  331. package/server/lib/ui-auth/DOCUMENTATION.md +38 -0
  332. package/server/lib/ui-auth/ui-auth.js +673 -0
  333. package/server/lib/ui-auth/ui-passkeys.js +545 -0
  334. package/server/opencode-proxy.test.js +151 -0
  335. package/server/proxy-headers.js +61 -0
  336. package/server/proxy-headers.test.js +58 -0
  337. package/server/sse-routes.test.js +152 -0
@@ -0,0 +1,55 @@
1
+ export const asObject = (value) => (value && typeof value === 'object' ? value : null);
2
+
3
+ export const asNonEmptyString = (value) => {
4
+ if (typeof value !== 'string') return null;
5
+ const trimmed = value.trim();
6
+ return trimmed ? trimmed : null;
7
+ };
8
+
9
+ export const toNumber = (value) => {
10
+ if (typeof value === 'number' && Number.isFinite(value)) {
11
+ return value;
12
+ }
13
+ if (typeof value === 'string') {
14
+ const parsed = Number(value);
15
+ return Number.isFinite(parsed) ? parsed : null;
16
+ }
17
+ return null;
18
+ };
19
+
20
+ export const toTimestamp = (value) => {
21
+ if (!value) return null;
22
+ if (typeof value === 'number') {
23
+ return value < 1_000_000_000_000 ? value * 1000 : value;
24
+ }
25
+ if (typeof value === 'string') {
26
+ const parsed = Date.parse(value);
27
+ return Number.isNaN(parsed) ? null : parsed;
28
+ }
29
+ return null;
30
+ };
31
+
32
+ export const normalizeTimestamp = (value) => {
33
+ if (typeof value !== 'number') return null;
34
+ return value < 1_000_000_000_000 ? value * 1000 : value;
35
+ };
36
+
37
+ export const resolveWindowSeconds = (limit) => {
38
+ const ZAI_TOKEN_WINDOW_SECONDS = { 3: 3600 };
39
+ if (!limit || !limit.number) return null;
40
+ const unitSeconds = ZAI_TOKEN_WINDOW_SECONDS[limit.unit];
41
+ if (!unitSeconds) return null;
42
+ return unitSeconds * limit.number;
43
+ };
44
+
45
+ export const resolveWindowLabel = (windowSeconds) => {
46
+ if (!windowSeconds) return 'tokens';
47
+ if (windowSeconds % 86400 === 0) {
48
+ const days = windowSeconds / 86400;
49
+ return days === 7 ? 'weekly' : `${days}d`;
50
+ }
51
+ if (windowSeconds % 3600 === 0) {
52
+ return `${windowSeconds / 3600}h`;
53
+ }
54
+ return `${windowSeconds}s`;
55
+ };
@@ -0,0 +1,44 @@
1
+ # Scheduled Tasks module
2
+
3
+ Server-owned scheduled task runtime and routes for Vinci-only automation.
4
+
5
+ ## Scope
6
+
7
+ - Per-project scheduled task persistence is owned by `packages/web/server/lib/projects/project-config.js`.
8
+ - Runtime orchestration and execution is owned by this module.
9
+ - This module is Vinci feature logic; it is intentionally separate from OpenCode proxy/runtime internals.
10
+
11
+ ## Files
12
+
13
+ - `packages/web/server/lib/scheduled-tasks/runtime.js`
14
+ - Next-run computation (daily/weekly/cron compatibility)
15
+ - Timer scheduling and queueing
16
+ - Concurrency controls
17
+ - Session create + prompt_async execution
18
+ - Emits Vinci task-run events
19
+
20
+ - `packages/web/server/lib/scheduled-tasks/routes.js`
21
+ - Scheduled task CRUD endpoints
22
+ - Manual run endpoint
23
+ - Vinci events SSE stream endpoint
24
+
25
+ ## Public exports (runtime.js)
26
+
27
+ - `createScheduledTasksRuntime(dependencies)`
28
+ - Returned API:
29
+ - `start()`
30
+ - `stop()`
31
+ - `syncAllProjects()`
32
+ - `syncProject(projectId)`
33
+ - `runNow(projectId, taskId)`
34
+
35
+ ## Public exports (routes.js)
36
+
37
+ - `registerScheduledTaskRoutes(app, dependencies)`
38
+ - Registers:
39
+ - `GET /api/projects/:projectId/scheduled-tasks`
40
+ - `PUT /api/projects/:projectId/scheduled-tasks`
41
+ - `DELETE /api/projects/:projectId/scheduled-tasks/:taskId`
42
+ - `POST /api/projects/:projectId/scheduled-tasks/:taskId/run`
43
+ - `GET /api/vinci/scheduled-tasks/status`
44
+ - `GET /api/vinci/events`
@@ -0,0 +1,235 @@
1
+ const asNonEmptyString = (value) => {
2
+ if (typeof value !== 'string') {
3
+ return null;
4
+ }
5
+ const trimmed = value.trim();
6
+ return trimmed.length > 0 ? trimmed : null;
7
+ };
8
+
9
+ const parseProjectID = (req) => asNonEmptyString(req?.params?.projectId);
10
+ const parseTaskID = (req) => asNonEmptyString(req?.params?.taskId);
11
+
12
+ export const registerScheduledTaskRoutes = (app, dependencies) => {
13
+ const {
14
+ readSettingsFromDiskMigrated,
15
+ sanitizeProjects,
16
+ projectConfigRuntime,
17
+ scheduledTasksRuntime,
18
+ getVinciEventClients,
19
+ writeSseEvent,
20
+ } = dependencies;
21
+
22
+ const findProjectByID = async (projectID) => {
23
+ const settings = await readSettingsFromDiskMigrated();
24
+ const projects = sanitizeProjects(settings?.projects || []);
25
+ return projects.find((project) => project.id === projectID) || null;
26
+ };
27
+
28
+ app.get('/api/projects/:projectId/scheduled-tasks', async (req, res) => {
29
+ const projectID = parseProjectID(req);
30
+ if (!projectID) {
31
+ return res.status(400).json({ error: 'projectId is required' });
32
+ }
33
+
34
+ try {
35
+ const project = await findProjectByID(projectID);
36
+ if (!project) {
37
+ return res.status(404).json({ error: 'Project not found' });
38
+ }
39
+
40
+ const tasks = await projectConfigRuntime.listScheduledTasks(projectID);
41
+ return res.json({ tasks });
42
+ } catch (error) {
43
+ console.error('[ScheduledTasks] failed to load tasks:', error);
44
+ return res.status(500).json({ error: 'Failed to load scheduled tasks' });
45
+ }
46
+ });
47
+
48
+ app.put('/api/projects/:projectId/scheduled-tasks', async (req, res) => {
49
+ const projectID = parseProjectID(req);
50
+ if (!projectID) {
51
+ return res.status(400).json({ error: 'projectId is required' });
52
+ }
53
+
54
+ const taskInput = req.body && typeof req.body === 'object' ? req.body.task : null;
55
+ if (!taskInput || typeof taskInput !== 'object') {
56
+ return res.status(400).json({ error: 'task payload is required' });
57
+ }
58
+
59
+ try {
60
+ const project = await findProjectByID(projectID);
61
+ if (!project) {
62
+ return res.status(404).json({ error: 'Project not found' });
63
+ }
64
+
65
+ const upserted = await projectConfigRuntime.upsertScheduledTask(projectID, taskInput);
66
+ await scheduledTasksRuntime.syncProject(projectID);
67
+ const freshTasks = await projectConfigRuntime.listScheduledTasks(projectID);
68
+ const freshTask = freshTasks.find((task) => task.id === upserted.task.id) || upserted.task;
69
+
70
+ return res.json({
71
+ tasks: freshTasks,
72
+ task: freshTask,
73
+ created: upserted.created,
74
+ });
75
+ } catch (error) {
76
+ const message = error instanceof Error ? error.message : 'Failed to save scheduled task';
77
+ const statusCode = message.toLowerCase().includes('required') || message.toLowerCase().includes('invalid')
78
+ ? 400
79
+ : 500;
80
+ if (statusCode === 500) {
81
+ console.error('[ScheduledTasks] failed to save task:', error);
82
+ }
83
+ return res.status(statusCode).json({ error: message });
84
+ }
85
+ });
86
+
87
+ app.delete('/api/projects/:projectId/scheduled-tasks/:taskId', async (req, res) => {
88
+ const projectID = parseProjectID(req);
89
+ const taskID = parseTaskID(req);
90
+ if (!projectID) {
91
+ return res.status(400).json({ error: 'projectId is required' });
92
+ }
93
+ if (!taskID) {
94
+ return res.status(400).json({ error: 'taskId is required' });
95
+ }
96
+
97
+ try {
98
+ const project = await findProjectByID(projectID);
99
+ if (!project) {
100
+ return res.status(404).json({ error: 'Project not found' });
101
+ }
102
+
103
+ const result = await projectConfigRuntime.deleteScheduledTask(projectID, taskID);
104
+ if (!result.deleted) {
105
+ return res.status(404).json({ error: 'Task not found' });
106
+ }
107
+ await scheduledTasksRuntime.syncProject(projectID);
108
+ const freshTasks = await projectConfigRuntime.listScheduledTasks(projectID);
109
+ return res.json({ tasks: freshTasks });
110
+ } catch (error) {
111
+ console.error('[ScheduledTasks] failed to delete task:', error);
112
+ return res.status(500).json({ error: 'Failed to delete scheduled task' });
113
+ }
114
+ });
115
+
116
+ app.post('/api/projects/:projectId/scheduled-tasks/:taskId/run', async (req, res) => {
117
+ const projectID = parseProjectID(req);
118
+ const taskID = parseTaskID(req);
119
+ if (!projectID) {
120
+ return res.status(400).json({ error: 'projectId is required' });
121
+ }
122
+ if (!taskID) {
123
+ return res.status(400).json({ error: 'taskId is required' });
124
+ }
125
+
126
+ try {
127
+ const project = await findProjectByID(projectID);
128
+ if (!project) {
129
+ return res.status(404).json({ error: 'Project not found' });
130
+ }
131
+
132
+ const result = await scheduledTasksRuntime.runNow(projectID, taskID);
133
+ if (result.running || result.queued) {
134
+ return res.status(409).json({ error: result.error || 'Task already running' });
135
+ }
136
+ if (result.skipped) {
137
+ return res.status(404).json({ error: 'Task not found or disabled' });
138
+ }
139
+ if (!result.ok) {
140
+ return res.status(500).json({
141
+ error: result.error || 'Task run failed',
142
+ task: result.task,
143
+ });
144
+ }
145
+
146
+ return res.json({
147
+ ok: true,
148
+ task: result.task,
149
+ sessionId: result.sessionID,
150
+ });
151
+ } catch (error) {
152
+ console.error('[ScheduledTasks] failed to run task:', error);
153
+ return res.status(500).json({ error: 'Failed to run scheduled task' });
154
+ }
155
+ });
156
+
157
+ app.get('/api/vinci/scheduled-tasks/status', async (_req, res) => {
158
+ try {
159
+ if (typeof scheduledTasksRuntime.getStatus === 'function') {
160
+ return res.json(scheduledTasksRuntime.getStatus());
161
+ }
162
+
163
+ const settings = await readSettingsFromDiskMigrated();
164
+ const projects = sanitizeProjects(settings?.projects || []);
165
+
166
+ let enabledCount = 0;
167
+ let runningCount = 0;
168
+
169
+ for (const project of projects) {
170
+ try {
171
+ const tasks = await projectConfigRuntime.listScheduledTasks(project.id);
172
+ for (const task of tasks) {
173
+ if (task?.enabled) {
174
+ enabledCount += 1;
175
+ }
176
+ if (task?.state?.lastStatus === 'running') {
177
+ runningCount += 1;
178
+ }
179
+ }
180
+ } catch {
181
+ }
182
+ }
183
+
184
+ return res.json({
185
+ hasEnabledScheduledTasks: enabledCount > 0,
186
+ hasRunningScheduledTasks: runningCount > 0,
187
+ enabledScheduledTasksCount: enabledCount,
188
+ runningScheduledTasksCount: runningCount,
189
+ });
190
+ } catch (error) {
191
+ console.error('[ScheduledTasks] failed to resolve scheduled task status:', error);
192
+ return res.status(500).json({ error: 'Failed to resolve scheduled task status' });
193
+ }
194
+ });
195
+
196
+ app.get('/api/vinci/events', (req, res) => {
197
+ res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
198
+ res.setHeader('Cache-Control', 'no-cache, no-transform');
199
+ res.setHeader('Connection', 'keep-alive');
200
+ res.setHeader('X-Accel-Buffering', 'no');
201
+ res.flushHeaders?.();
202
+
203
+ const clients = getVinciEventClients();
204
+ clients.add(res);
205
+
206
+ try {
207
+ writeSseEvent(res, {
208
+ type: 'vinci:event-stream-ready',
209
+ properties: {
210
+ connectedAt: Date.now(),
211
+ },
212
+ });
213
+ } catch {
214
+ }
215
+
216
+ const heartbeat = setInterval(() => {
217
+ try {
218
+ writeSseEvent(res, {
219
+ type: 'vinci:heartbeat',
220
+ properties: {
221
+ timestamp: Date.now(),
222
+ },
223
+ });
224
+ } catch {
225
+ clearInterval(heartbeat);
226
+ clients.delete(res);
227
+ }
228
+ }, 25_000);
229
+
230
+ req.on('close', () => {
231
+ clearInterval(heartbeat);
232
+ clients.delete(res);
233
+ });
234
+ });
235
+ };