@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,71 @@
1
+ export const createOpenCodeResolutionRuntime = (dependencies) => {
2
+ const {
3
+ path,
4
+ resolveOpencodeCliPath,
5
+ applyOpencodeBinaryFromSettings,
6
+ ensureOpencodeCliEnv,
7
+ resolveManagedOpenCodeLaunchSpec,
8
+ getResolvedState,
9
+ setResolvedOpencodeBinarySource,
10
+ } = dependencies;
11
+
12
+ const getOpenCodeResolutionSnapshot = async (settings) => {
13
+ const configured = typeof settings?.opencodeBinary === 'string' ? settings.opencodeBinary : null;
14
+
15
+ const { resolvedOpencodeBinarySource: previousSource } = getResolvedState();
16
+ const detectedNow = resolveOpencodeCliPath();
17
+ const { resolvedOpencodeBinarySource: rawDetectedSourceNow } = getResolvedState();
18
+ setResolvedOpencodeBinarySource(previousSource);
19
+
20
+ await applyOpencodeBinaryFromSettings();
21
+ ensureOpencodeCliEnv();
22
+
23
+ const {
24
+ resolvedOpencodeBinary,
25
+ resolvedOpencodeBinarySource,
26
+ useWslForOpencode,
27
+ resolvedWslBinary,
28
+ resolvedWslOpencodePath,
29
+ resolvedWslDistro,
30
+ resolvedNodeBinary,
31
+ resolvedBunBinary,
32
+ } = getResolvedState();
33
+
34
+ const resolved = resolvedOpencodeBinary || null;
35
+ const source = resolvedOpencodeBinarySource || null;
36
+ const detectedSourceNow =
37
+ detectedNow &&
38
+ resolved &&
39
+ detectedNow === resolved &&
40
+ rawDetectedSourceNow === 'env' &&
41
+ source &&
42
+ source !== 'env'
43
+ ? source
44
+ : rawDetectedSourceNow;
45
+ const launchSpec = resolved && !useWslForOpencode
46
+ ? resolveManagedOpenCodeLaunchSpec(resolved)
47
+ : null;
48
+
49
+ return {
50
+ configured,
51
+ resolved,
52
+ resolvedDir: resolved ? path.dirname(resolved) : null,
53
+ source,
54
+ detectedNow,
55
+ detectedSourceNow,
56
+ launchBinary: launchSpec?.binary || null,
57
+ launchArgs: launchSpec?.args || [],
58
+ launchWrapperType: launchSpec?.wrapperType || null,
59
+ viaWsl: useWslForOpencode,
60
+ wslBinary: resolvedWslBinary || null,
61
+ wslPath: resolvedWslOpencodePath || null,
62
+ wslDistro: resolvedWslDistro || null,
63
+ node: resolvedNodeBinary || null,
64
+ bun: resolvedBunBinary || null,
65
+ };
66
+ };
67
+
68
+ return {
69
+ getOpenCodeResolutionSnapshot,
70
+ };
71
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Shared PATH heuristics and merge utilities for server and Electron runtimes.
3
+ *
4
+ * The heuristic decides whether the current process.env.PATH looks like it was
5
+ * configured by the user (or their session manager) vs. a minimal system default.
6
+ * When the PATH looks user-configured we keep it; otherwise we prefer the login
7
+ * shell PATH which typically has the full toolchain.
8
+ */
9
+
10
+ const TOOLCHAIN_SEGMENTS = [
11
+ '/opt/homebrew/',
12
+ '/opt/pkg/',
13
+ '/opt/pmk/',
14
+ '/snap/',
15
+ ];
16
+
17
+ const TOOLCHAIN_BASENAMES = new Set([
18
+ '.cargo',
19
+ '.bun',
20
+ '.nvm',
21
+ '.pyenv',
22
+ '.rbenv',
23
+ '.sdkman',
24
+ '.asdf',
25
+ '.volta',
26
+ '.fnm',
27
+ '.local',
28
+ '.opencode',
29
+ 'node_modules',
30
+ ]);
31
+
32
+ /**
33
+ * Returns true when `value` (a PATH string) contains at least one segment that
34
+ * suggests the PATH was configured by the user or their session manager rather
35
+ * than being a bare system default.
36
+ *
37
+ * @param {string} value - The PATH string to inspect.
38
+ * @param {string} home - The user's home directory (os.homedir()).
39
+ * @param {string} delim - The PATH delimiter (':' on POSIX, ';' on Windows).
40
+ */
41
+ export function pathLooksUserConfigured(value, home, delim) {
42
+ if (typeof value !== 'string' || !value) {
43
+ return false;
44
+ }
45
+
46
+ const normalizedHome = typeof home === 'string' ? home.replaceAll('\\', '/') : '';
47
+ const homeWithSep = normalizedHome ? normalizedHome + '/' : '';
48
+
49
+ return value.split(delim).some((segment) => {
50
+ if (!segment) return false;
51
+ const normalizedSegment = segment.replaceAll('\\', '/');
52
+
53
+ // Any path under the user's home directory.
54
+ if (normalizedHome && (normalizedSegment === normalizedHome || normalizedSegment.startsWith(homeWithSep))) {
55
+ return true;
56
+ }
57
+
58
+ // Well-known package-manager / toolchain prefixes.
59
+ if (TOOLCHAIN_SEGMENTS.some((prefix) => normalizedSegment.startsWith(prefix))) {
60
+ return true;
61
+ }
62
+
63
+ // Well-known dot-directories inside home (e.g. ~/.cargo/bin).
64
+ const parts = normalizedSegment.split('/').filter(Boolean);
65
+ if (parts.some((part) => TOOLCHAIN_BASENAMES.has(part))) {
66
+ return true;
67
+ }
68
+
69
+ return false;
70
+ });
71
+ }
72
+
73
+ /**
74
+ * Merges two PATH strings, deduplicating segments while preserving the order of
75
+ * `primary` and appending any segments from `fallback` that are not already
76
+ * present.
77
+ *
78
+ * @param {string} primary - The preferred PATH (e.g. user-configured or login shell).
79
+ * @param {string} fallback - The secondary PATH to fill gaps from.
80
+ * @param {string} delim - The PATH delimiter.
81
+ */
82
+ export function mergePathValues(primary, fallback, delim) {
83
+ const seen = new Set();
84
+ const result = [];
85
+
86
+ const addSegments = (value) => {
87
+ if (typeof value !== 'string' || !value) return;
88
+ for (const segment of value.split(delim)) {
89
+ if (segment && !seen.has(segment)) {
90
+ seen.add(segment);
91
+ result.push(segment);
92
+ }
93
+ }
94
+ };
95
+
96
+ addSegments(primary);
97
+ addSegments(fallback);
98
+
99
+ return result.join(delim);
100
+ }
@@ -0,0 +1,71 @@
1
+ import path from 'node:path';
2
+ import os from 'node:os';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ import { pathLooksUserConfigured, mergePathValues } from './path-utils.js';
6
+
7
+ const home = os.homedir();
8
+ const delim = path.delimiter;
9
+
10
+ describe('pathLooksUserConfigured', () => {
11
+ it('returns false for empty or non-string values', () => {
12
+ expect(pathLooksUserConfigured('', home, delim)).toBe(false);
13
+ expect(pathLooksUserConfigured(null, home, delim)).toBe(false);
14
+ expect(pathLooksUserConfigured(undefined, home, delim)).toBe(false);
15
+ expect(pathLooksUserConfigured(42, home, delim)).toBe(false);
16
+ });
17
+
18
+ it('returns false for minimal system PATH', () => {
19
+ expect(pathLooksUserConfigured('/usr/local/bin:/usr/bin:/bin', home, delim)).toBe(false);
20
+ });
21
+
22
+ it('detects paths under home directory', () => {
23
+ expect(pathLooksUserConfigured(`${home}/.bun/bin:/usr/bin`, home, delim)).toBe(true);
24
+ expect(pathLooksUserConfigured(`${home}/.local/bin:/usr/bin`, home, delim)).toBe(true);
25
+ });
26
+
27
+ it('detects home directory itself', () => {
28
+ expect(pathLooksUserConfigured(`${home}:/usr/bin`, home, delim)).toBe(true);
29
+ });
30
+
31
+ it('detects well-known package manager prefixes', () => {
32
+ expect(pathLooksUserConfigured('/opt/homebrew/bin:/usr/bin', home, delim)).toBe(true);
33
+ expect(pathLooksUserConfigured('/opt/pkg/bin:/usr/bin', home, delim)).toBe(true);
34
+ expect(pathLooksUserConfigured('/snap/bin:/usr/bin', home, delim)).toBe(true);
35
+ });
36
+
37
+ it('detects well-known dot-directory basenames', () => {
38
+ expect(pathLooksUserConfigured('/some/path/.cargo/bin:/usr/bin', home, delim)).toBe(true);
39
+ expect(pathLooksUserConfigured('/some/path/.nvm/versions/node/v20/bin:/usr/bin', home, delim)).toBe(true);
40
+ expect(pathLooksUserConfigured('/some/path/.pyenv/shims:/usr/bin', home, delim)).toBe(true);
41
+ expect(pathLooksUserConfigured('/some/path/.opencode/bin:/usr/bin', home, delim)).toBe(true);
42
+ });
43
+
44
+ it('detects Windows home and toolchain paths', () => {
45
+ const windowsHome = 'C:\\Users\\agent';
46
+ expect(pathLooksUserConfigured('C:\\Users\\agent\\.bun\\bin;C:\\Windows\\System32', windowsHome, ';')).toBe(true);
47
+ expect(pathLooksUserConfigured('C:\\tools\\.cargo\\bin;C:\\Windows\\System32', windowsHome, ';')).toBe(true);
48
+ });
49
+ });
50
+
51
+ describe('mergePathValues', () => {
52
+ it('returns empty string for empty inputs', () => {
53
+ expect(mergePathValues('', '', delim)).toBe('');
54
+ });
55
+
56
+ it('returns primary when fallback is empty', () => {
57
+ expect(mergePathValues('/a:/b', '', delim)).toBe('/a:/b');
58
+ });
59
+
60
+ it('returns fallback when primary is empty', () => {
61
+ expect(mergePathValues('', '/a:/b', delim)).toBe('/a:/b');
62
+ });
63
+
64
+ it('deduplicates segments, preserving primary order', () => {
65
+ expect(mergePathValues('/a:/b:/c', '/b:/d:/a', delim)).toBe('/a:/b:/c:/d');
66
+ });
67
+
68
+ it('appends all fallback segments when no overlap', () => {
69
+ expect(mergePathValues('/a:/b', '/c:/d', delim)).toBe('/a:/b:/c:/d');
70
+ });
71
+ });
@@ -0,0 +1,124 @@
1
+ export const createProjectDirectoryRuntime = (dependencies) => {
2
+ const {
3
+ fsPromises,
4
+ path,
5
+ normalizeDirectoryPath,
6
+ readSettingsFromDiskMigrated,
7
+ getReadSettingsFromDiskMigrated,
8
+ sanitizeProjects,
9
+ } = dependencies;
10
+
11
+ const resolveDirectoryCandidate = (value) => {
12
+ if (typeof value !== 'string') {
13
+ return null;
14
+ }
15
+ const trimmed = value.trim();
16
+ if (!trimmed) {
17
+ return null;
18
+ }
19
+ const normalized = normalizeDirectoryPath(trimmed);
20
+ return path.resolve(normalized);
21
+ };
22
+
23
+ const validateDirectoryPath = async (candidate) => {
24
+ const resolved = resolveDirectoryCandidate(candidate);
25
+ if (!resolved) {
26
+ return { ok: false, error: 'Directory parameter is required' };
27
+ }
28
+ try {
29
+ const stats = await fsPromises.stat(resolved);
30
+ if (!stats.isDirectory()) {
31
+ return { ok: false, error: 'Specified path is not a directory' };
32
+ }
33
+ return { ok: true, directory: resolved };
34
+ } catch (error) {
35
+ const err = error;
36
+ if (err && typeof err === 'object' && err.code === 'ENOENT') {
37
+ return { ok: false, error: 'Directory not found' };
38
+ }
39
+ if (err && typeof err === 'object' && err.code === 'EACCES') {
40
+ return { ok: false, error: 'Access to directory denied' };
41
+ }
42
+ return { ok: false, error: 'Failed to validate directory' };
43
+ }
44
+ };
45
+
46
+ const resolveProjectDirectory = async (req) => {
47
+ const headerDirectory = typeof req.get === 'function' ? req.get('x-opencode-directory') : null;
48
+ const queryDirectory = Array.isArray(req.query?.directory)
49
+ ? req.query.directory[0]
50
+ : req.query?.directory;
51
+ const requested = headerDirectory || queryDirectory || null;
52
+
53
+ if (requested) {
54
+ const validated = await validateDirectoryPath(requested);
55
+ if (!validated.ok) {
56
+ return { directory: null, error: validated.error };
57
+ }
58
+ return { directory: validated.directory, error: null };
59
+ }
60
+
61
+ const readSettings = typeof getReadSettingsFromDiskMigrated === 'function'
62
+ ? getReadSettingsFromDiskMigrated()
63
+ : readSettingsFromDiskMigrated;
64
+ const settings = await readSettings();
65
+
66
+ // `lastDirectory` reflects the directory the UI is currently browsing —
67
+ // useDirectoryStore.setDirectory() persists it on every navigation.
68
+ // Prefer it over activeProjectId, because the user may have navigated
69
+ // away from the project that was last "clicked" in the sidebar (e.g. via
70
+ // `go to parent`, directory picker, or a deep link), leaving
71
+ // activeProjectId stale. Fetches scoped to the stale project would 400
72
+ // with "Path is outside of active workspace".
73
+ if (typeof settings.lastDirectory === 'string' && settings.lastDirectory.trim()) {
74
+ const validated = await validateDirectoryPath(settings.lastDirectory);
75
+ if (validated.ok) {
76
+ return { directory: validated.directory, error: null };
77
+ }
78
+ }
79
+
80
+ const projects = sanitizeProjects(settings.projects) || [];
81
+ if (projects.length === 0) {
82
+ return { directory: null, error: 'Directory parameter or active project is required' };
83
+ }
84
+
85
+ const activeId = typeof settings.activeProjectId === 'string' ? settings.activeProjectId : '';
86
+ const active = projects.find((project) => project.id === activeId) || projects[0];
87
+ if (!active || !active.path) {
88
+ return { directory: null, error: 'Directory parameter or active project is required' };
89
+ }
90
+
91
+ const validated = await validateDirectoryPath(active.path);
92
+ if (!validated.ok) {
93
+ return { directory: null, error: validated.error };
94
+ }
95
+
96
+ return { directory: validated.directory, error: null };
97
+ };
98
+
99
+ const resolveOptionalProjectDirectory = async (req) => {
100
+ const headerDirectory = typeof req.get === 'function' ? req.get('x-opencode-directory') : null;
101
+ const queryDirectory = Array.isArray(req.query?.directory)
102
+ ? req.query.directory[0]
103
+ : req.query?.directory;
104
+ const requested = headerDirectory || queryDirectory || null;
105
+
106
+ if (!requested) {
107
+ return { directory: null, error: null };
108
+ }
109
+
110
+ const validated = await validateDirectoryPath(requested);
111
+ if (!validated.ok) {
112
+ return { directory: null, error: validated.error };
113
+ }
114
+
115
+ return { directory: validated.directory, error: null };
116
+ };
117
+
118
+ return {
119
+ resolveDirectoryCandidate,
120
+ validateDirectoryPath,
121
+ resolveProjectDirectory,
122
+ resolveOptionalProjectDirectory,
123
+ };
124
+ };