auvrynt 1.0.2 → 1.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 (550) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +366 -233
  3. package/addons/auvrynt_bridge/auvrynt_bridge.gd +500 -0
  4. package/addons/auvrynt_bridge/plugin.cfg +7 -0
  5. package/bin/auvrynt-launcher.cjs +77 -0
  6. package/dist/artifact-registry.js +1 -0
  7. package/dist/aseprite-tools.js +1 -0
  8. package/dist/auth/connection-registry.js +145 -0
  9. package/dist/auth/connection-status.js +176 -0
  10. package/dist/auth/oauth-provider.js +617 -0
  11. package/dist/auth/room-registry.js +131 -0
  12. package/dist/auth/session-registry.js +531 -0
  13. package/dist/background-lifecycle.js +1 -0
  14. package/dist/blender-client.js +1 -109
  15. package/dist/blender-tools.js +1 -930
  16. package/dist/browser-stability.js +1 -0
  17. package/dist/cli/commands/help-command.js +10 -0
  18. package/dist/cli/commands/init-command.js +190 -0
  19. package/dist/cli/commands/integration-commands.js +88 -0
  20. package/dist/cli/commands/serve-command.js +83 -0
  21. package/dist/cli/commands/setup-command.js +81 -0
  22. package/dist/cli/commands/status-commands.js +166 -0
  23. package/dist/cli/commands/tunnel-command.js +127 -0
  24. package/dist/cli/commands/user-config-commands.js +105 -0
  25. package/dist/cli/dashboard-actions.js +516 -0
  26. package/dist/cli/dashboard-native-actions.js +282 -0
  27. package/dist/cli/foreground-server.js +270 -0
  28. package/dist/cli/instance-control.js +21 -0
  29. package/dist/cli/instance-lock.js +123 -0
  30. package/dist/cli/integration-bootstrap.js +206 -0
  31. package/dist/cli/lifecycle-manager.js +493 -0
  32. package/dist/cli/runtime-support.js +74 -0
  33. package/dist/cli/serena-detected-default.js +27 -0
  34. package/dist/cli/tunnel-health-monitor.js +182 -0
  35. package/dist/cli.js +82 -739
  36. package/dist/config.js +1 -243
  37. package/dist/connection-registry.js +1 -73
  38. package/dist/connection-status.js +1 -139
  39. package/dist/control-retry.js +1 -0
  40. package/dist/crash-recovery.js +1 -0
  41. package/dist/db/client.js +16 -3
  42. package/dist/db/schema.js +30 -0
  43. package/dist/dotnet-tools.js +1 -223
  44. package/dist/git-worktrees.js +1 -134
  45. package/dist/git.js +1 -41
  46. package/dist/godot-animation-tilemap.js +1 -82
  47. package/dist/godot-csharp-build.js +1 -93
  48. package/dist/godot-csharp-project.js +1 -157
  49. package/dist/godot-csharp-runner.js +1 -146
  50. package/dist/godot-csharp-semantic.js +1 -161
  51. package/dist/godot-csharp-validate.js +1 -71
  52. package/dist/godot-dotnet-env.js +1 -169
  53. package/dist/godot-editor-bridge.js +1 -140
  54. package/dist/godot-gdscript.js +1 -824
  55. package/dist/godot-project-settings.js +1 -223
  56. package/dist/godot-runtime-testing.js +1 -249
  57. package/dist/godot-tools.js +1 -183
  58. package/dist/http-rate-limit.js +1 -0
  59. package/dist/http-server-hardening.js +1 -0
  60. package/dist/image-tools.js +1 -157
  61. package/dist/infrastructure/command-reference.js +32 -0
  62. package/dist/infrastructure/config.js +424 -0
  63. package/dist/infrastructure/context7-auth.js +55 -0
  64. package/dist/infrastructure/http-rate-limit.js +42 -0
  65. package/dist/infrastructure/http-server-hardening.js +23 -0
  66. package/dist/infrastructure/integration-queue.js +46 -0
  67. package/dist/infrastructure/logger.js +129 -0
  68. package/dist/infrastructure/mcp-event-store.js +103 -0
  69. package/dist/infrastructure/ngrok-auth-pool.js +208 -0
  70. package/dist/infrastructure/request-context.js +14 -0
  71. package/dist/infrastructure/shutdown.js +37 -0
  72. package/dist/infrastructure/sse-heartbeat.js +47 -0
  73. package/dist/infrastructure/tool-capabilities.js +67 -0
  74. package/dist/infrastructure/tool-result-budget.js +175 -0
  75. package/dist/infrastructure/user-config.js +167 -0
  76. package/dist/integration-discovery.js +1 -98
  77. package/dist/integration-queue.js +1 -0
  78. package/dist/integrations/agent-reach/agent-reach-tools.js +196 -0
  79. package/dist/integrations/agent-reach/native-channels.js +468 -0
  80. package/dist/integrations/aseprite/aseprite-analysis-tools.js +368 -0
  81. package/dist/integrations/aseprite/aseprite-editing-tools.js +647 -0
  82. package/dist/integrations/aseprite/aseprite-live-tools.js +297 -0
  83. package/dist/integrations/aseprite/aseprite-safety-tools.js +594 -0
  84. package/dist/integrations/aseprite/aseprite-specialized-tools.js +289 -0
  85. package/dist/integrations/aseprite/aseprite-tools.js +837 -0
  86. package/dist/integrations/blender/blender-catalog-mesh.js +593 -0
  87. package/dist/integrations/blender/blender-catalog-object.js +906 -0
  88. package/dist/integrations/blender/blender-catalog-scene.js +266 -0
  89. package/dist/integrations/blender/blender-catalog-select.js +581 -0
  90. package/dist/integrations/blender/blender-catalog-stubs.js +7512 -0
  91. package/dist/integrations/blender/blender-catalog.js +165 -0
  92. package/dist/integrations/blender/blender-client.js +105 -0
  93. package/dist/integrations/blender/blender-tools.js +2243 -0
  94. package/dist/integrations/context7/context7-tools.js +106 -0
  95. package/dist/integrations/dotnet/dotnet-tools.js +195 -0
  96. package/dist/integrations/godot/godot-animation-tilemap.js +74 -0
  97. package/dist/integrations/godot/godot-csharp-build.js +91 -0
  98. package/dist/integrations/godot/godot-csharp-project.js +155 -0
  99. package/dist/integrations/godot/godot-csharp-runner.js +118 -0
  100. package/dist/integrations/godot/godot-csharp-semantic.js +146 -0
  101. package/dist/integrations/godot/godot-csharp-validate.js +71 -0
  102. package/dist/integrations/godot/godot-dotnet-env.js +134 -0
  103. package/dist/integrations/godot/godot-editor-bridge.js +328 -0
  104. package/dist/integrations/godot/godot-gdscript.js +536 -0
  105. package/dist/integrations/godot/godot-project-settings.js +178 -0
  106. package/dist/integrations/godot/godot-runtime-testing.js +263 -0
  107. package/dist/integrations/godot/godot-tools.js +193 -0
  108. package/dist/integrations/images/image-tools.js +414 -0
  109. package/dist/integrations/images/png-codec.js +251 -0
  110. package/dist/integrations/images/view-image.js +99 -0
  111. package/dist/integrations/images/window-capture.js +148 -0
  112. package/dist/integrations/integration-discovery.js +185 -0
  113. package/dist/integrations/obsidian/obsidian-tools.js +205 -0
  114. package/dist/integrations/playwright/browser-session.js +516 -0
  115. package/dist/integrations/playwright/browser-stability.js +36 -0
  116. package/dist/integrations/playwright/playwright-runtime.js +105 -0
  117. package/dist/integrations/playwright/web-tools.js +504 -0
  118. package/dist/integrations/roblox/roblox-helpers.js +381 -0
  119. package/dist/integrations/roblox/roblox-studio-client.js +112 -0
  120. package/dist/integrations/roblox/roblox-tools.js +106 -0
  121. package/dist/integrations/serena/serena-manager.js +464 -0
  122. package/dist/integrations/serena/serena-tools.js +411 -0
  123. package/dist/logger.js +1 -76
  124. package/dist/mcp-event-store.js +1 -0
  125. package/dist/oauth-provider.js +1 -377
  126. package/dist/pi-tools.js +1 -81
  127. package/dist/playwright-runtime.js +1 -0
  128. package/dist/process/background-lifecycle.js +189 -0
  129. package/dist/process/control-retry.js +42 -0
  130. package/dist/process/crash-recovery.js +23 -0
  131. package/dist/process/processes.js +456 -0
  132. package/dist/processes.js +1 -218
  133. package/dist/request-context.js +1 -0
  134. package/dist/review-checkpoints.js +1 -142
  135. package/dist/room-registry.js +1 -0
  136. package/dist/roots.js +1 -53
  137. package/dist/search-discovery.js +1 -271
  138. package/dist/serena-manager.js +1 -443
  139. package/dist/serena-tools.js +1 -411
  140. package/dist/server/dashboard-page-styles.js +331 -0
  141. package/dist/server/dashboard-page.js +1509 -0
  142. package/dist/server/dashboard-routes.js +46 -0
  143. package/dist/server/dashboard.js +240 -0
  144. package/dist/server/http-helpers.js +30 -0
  145. package/dist/server/integration-profile-update.js +37 -0
  146. package/dist/server/mcp-policy.js +169 -0
  147. package/dist/server/mcp-server-factory.js +127 -0
  148. package/dist/server/mcp-tool-registrar.js +182 -0
  149. package/dist/server/openai-session-hint.js +14 -0
  150. package/dist/server/tool-groups.js +29 -0
  151. package/dist/server/tool-logging.js +33 -0
  152. package/dist/server/tool-registration-shared.js +59 -0
  153. package/dist/server/tools/aseprite-advanced-tools-registration.js +547 -0
  154. package/dist/server/tools/aseprite-tools-registration.js +213 -0
  155. package/dist/server/tools/blender-tools-registration.js +690 -0
  156. package/dist/server/tools/core-file-tools-registration.js +459 -0
  157. package/dist/server/tools/dotnet-godot-window-tools-registration.js +120 -0
  158. package/dist/server/tools/godot-csharp-tools-registration.js +252 -0
  159. package/dist/server/tools/godot-gdscript-tools-registration.js +189 -0
  160. package/dist/server/tools/process-project-tools-registration.js +155 -0
  161. package/dist/server/tools/roblox-tools-registration.js +514 -0
  162. package/dist/server/tools/web-image-tools-registration.js +326 -0
  163. package/dist/server/tools/workspace-lifecycle-tools-registration.js +130 -0
  164. package/dist/server/ui-assets.js +97 -0
  165. package/dist/server/workspace-analytics.js +92 -0
  166. package/dist/server.js +453 -2713
  167. package/dist/session-registry.js +1 -0
  168. package/dist/shutdown.js +1 -0
  169. package/dist/skills.js +1 -45
  170. package/dist/sse-heartbeat.js +1 -0
  171. package/dist/tool-capabilities.js +1 -0
  172. package/dist/tool-result-budget.js +1 -0
  173. package/dist/tools/pi-tools.js +81 -0
  174. package/dist/tunnels/cloudflare-tunnel.js +217 -0
  175. package/dist/tunnels/cloudflared-service.js +174 -0
  176. package/dist/tunnels/ngrok-tunnel.js +220 -0
  177. package/dist/tunnels/tunnel-manager.js +186 -0
  178. package/dist/tunnels/tunnel-types.js +1 -0
  179. package/dist/tunnels/tunnel-utils.js +62 -0
  180. package/dist/ui/.vite/manifest.json +9 -2487
  181. package/dist/ui/assets/heavy-payload-D42A9ceL.js +1 -0
  182. package/dist/ui/assets/lightweight-diff-Cv4g9Hdr.js +13 -0
  183. package/dist/ui/assets/review-payload-DKIg1cKF.js +1 -0
  184. package/dist/ui/assets/workspace-app-CeK3NhmB.css +1 -0
  185. package/dist/ui/assets/{workspace-app-C5QsE314.js → workspace-app-CkUXnpl4.js} +6 -6
  186. package/dist/ui/brand-theme.js +23 -0
  187. package/dist/ui/workspace-app.html +15 -15
  188. package/dist/user-config.js +1 -57
  189. package/dist/view-image.js +1 -104
  190. package/dist/web-tools.js +1 -200
  191. package/dist/window-capture.js +1 -74
  192. package/dist/workspace/artifact-registry.js +69 -0
  193. package/dist/workspace/git-worktrees.js +141 -0
  194. package/dist/workspace/git.js +42 -0
  195. package/dist/workspace/review-checkpoints.js +142 -0
  196. package/dist/workspace/roots.js +56 -0
  197. package/dist/workspace/search-discovery.js +264 -0
  198. package/dist/workspace/skills.js +45 -0
  199. package/dist/workspace/workspace-store.js +219 -0
  200. package/dist/workspace/workspaces.js +314 -0
  201. package/dist/workspace-store.js +1 -125
  202. package/dist/workspaces.js +1 -226
  203. package/docs/CREATOR_STORE_FREE_ASSETS.md +162 -0
  204. package/docs/DEVELOPMENT_TOOLS.md +136 -93
  205. package/docs/assets/auvrynt-icon.png +0 -0
  206. package/docs/assets/auvrynt-icon.svg +20 -0
  207. package/docs/chatgpt-coding-workflow.md +143 -143
  208. package/docs/configuration.md +156 -124
  209. package/docs/diagnostics.md +79 -0
  210. package/docs/gotchas.md +244 -202
  211. package/docs/multi-agent-and-long-projects.md +91 -0
  212. package/docs/security.md +138 -100
  213. package/docs/setup.md +171 -131
  214. package/docs/source-layout.md +60 -0
  215. package/extensions/auvrynt_bridge/auvrynt_bridge.lua +594 -0
  216. package/extensions/auvrynt_bridge/live_analysis.lua +181 -0
  217. package/extensions/auvrynt_bridge/live_animation.lua +134 -0
  218. package/extensions/auvrynt_bridge/live_commands.lua +24 -0
  219. package/extensions/auvrynt_bridge/live_common.lua +130 -0
  220. package/extensions/auvrynt_bridge/live_document.lua +78 -0
  221. package/extensions/auvrynt_bridge/live_drawing.lua +125 -0
  222. package/extensions/auvrynt_bridge/live_effects.lua +91 -0
  223. package/extensions/auvrynt_bridge/live_palette_template.lua +167 -0
  224. package/extensions/auvrynt_bridge/live_selection.lua +110 -0
  225. package/extensions/auvrynt_bridge/live_structure.lua +129 -0
  226. package/extensions/auvrynt_bridge/package.json +17 -0
  227. package/guides/ASEPRITE_AGENT_GUIDE.md +133 -0
  228. package/guides/BLENDER_AGENT_GUIDE.md +472 -0
  229. package/guides/GODOT_AGENT_GUIDE.md +298 -0
  230. package/guides/PROJECT_ROUTER.md +165 -0
  231. package/guides/ROBLOX_AGENT_GUIDE.md +75 -0
  232. package/guides/SOFTWARE_AGENT_GUIDE.md +104 -0
  233. package/guides/WEB_AGENT_GUIDE.md +287 -0
  234. package/package.json +78 -70
  235. package/scripts/dev-server.mjs +121 -120
  236. package/scripts/live-tunnel-smoke.mjs +538 -0
  237. package/scripts/repo-hygiene.mjs +74 -0
  238. package/scripts/restart-after-crash.mjs +49 -0
  239. package/scripts/run-tests.mjs +166 -0
  240. package/dist/ui/assets/abap-CLvhMVsD.js +0 -1
  241. package/dist/ui/assets/actionscript-3--17pq3dv.js +0 -1
  242. package/dist/ui/assets/ada-C5qYipkI.js +0 -1
  243. package/dist/ui/assets/andromeeda-vGVdxbeo.js +0 -1
  244. package/dist/ui/assets/angular-html-BJqQFYI6.js +0 -1
  245. package/dist/ui/assets/angular-ts-CMJECO0Y.js +0 -1
  246. package/dist/ui/assets/apache-U0d_L8uA.js +0 -1
  247. package/dist/ui/assets/apex-CGTLDQj6.js +0 -1
  248. package/dist/ui/assets/apl-DWeXpBBr.js +0 -1
  249. package/dist/ui/assets/applescript-CCn79oCD.js +0 -1
  250. package/dist/ui/assets/ara-4CJ0cIlV.js +0 -1
  251. package/dist/ui/assets/asciidoc-DE70LPWp.js +0 -1
  252. package/dist/ui/assets/asm-Cmm7eHzH.js +0 -1
  253. package/dist/ui/assets/astro-CLbttLOq.js +0 -1
  254. package/dist/ui/assets/aurora-x-CDeNXAV0.js +0 -1
  255. package/dist/ui/assets/awk-BWXHIvNe.js +0 -1
  256. package/dist/ui/assets/ayu-dark-DluEY0Gj.js +0 -1
  257. package/dist/ui/assets/ayu-light-C3h-C4tm.js +0 -1
  258. package/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +0 -1
  259. package/dist/ui/assets/ballerina-B7ZEbQpA.js +0 -1
  260. package/dist/ui/assets/bat-Bo4NYOV-.js +0 -1
  261. package/dist/ui/assets/beancount-D-usSTwE.js +0 -1
  262. package/dist/ui/assets/berry-DKpUyyne.js +0 -1
  263. package/dist/ui/assets/bibtex-Ci_nEsc7.js +0 -1
  264. package/dist/ui/assets/bicep-CUHmPFLl.js +0 -1
  265. package/dist/ui/assets/bird2-C2hNVINV.js +0 -1
  266. package/dist/ui/assets/blade-BOzY0P2V.js +0 -1
  267. package/dist/ui/assets/bsl-BkkzgIyY.js +0 -1
  268. package/dist/ui/assets/c-BG-8uJvh.js +0 -1
  269. package/dist/ui/assets/c3-CnJL0r0V.js +0 -1
  270. package/dist/ui/assets/cadence-CQ2zXKGN.js +0 -1
  271. package/dist/ui/assets/cairo-DLTphjLi.js +0 -1
  272. package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +0 -1
  273. package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +0 -1
  274. package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +0 -1
  275. package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +0 -1
  276. package/dist/ui/assets/clarity-SemFz856.js +0 -1
  277. package/dist/ui/assets/clojure-DqKBuwfJ.js +0 -1
  278. package/dist/ui/assets/cmake-Bj61d0ZC.js +0 -1
  279. package/dist/ui/assets/cobol-I_17IuGe.js +0 -1
  280. package/dist/ui/assets/codeowners-C8r90Shi.js +0 -1
  281. package/dist/ui/assets/codeql-oeQT6MSM.js +0 -1
  282. package/dist/ui/assets/coffee-C0B8hmok.js +0 -1
  283. package/dist/ui/assets/common-lisp-Cv5bFMCO.js +0 -1
  284. package/dist/ui/assets/coq-BrsZFFmf.js +0 -1
  285. package/dist/ui/assets/cpp-DDJXt6Vs.js +0 -1
  286. package/dist/ui/assets/crystal-Bexqace6.js +0 -1
  287. package/dist/ui/assets/csharp-Ct8U2NOr.js +0 -1
  288. package/dist/ui/assets/css-DSQhw_9R.js +0 -1
  289. package/dist/ui/assets/csv-Dx-8-gkx.js +0 -1
  290. package/dist/ui/assets/cue-CE9AQfxI.js +0 -1
  291. package/dist/ui/assets/cypher-ClKdZ_lG.js +0 -1
  292. package/dist/ui/assets/d-qD-0Kul2.js +0 -1
  293. package/dist/ui/assets/dark-plus-Cs2F2srj.js +0 -1
  294. package/dist/ui/assets/dart-DkHntEIa.js +0 -1
  295. package/dist/ui/assets/dax-BkyTk9wS.js +0 -1
  296. package/dist/ui/assets/desktop-Dlh5hvp9.js +0 -1
  297. package/dist/ui/assets/diff-woXpYk--.js +0 -1
  298. package/dist/ui/assets/docker-IyjqRm3v.js +0 -1
  299. package/dist/ui/assets/dotenv-_5a1GRtc.js +0 -1
  300. package/dist/ui/assets/dracula-BHWKrbxM.js +0 -1
  301. package/dist/ui/assets/dracula-soft-5eyTD99u.js +0 -1
  302. package/dist/ui/assets/dream-maker-DW3nJb8Q.js +0 -1
  303. package/dist/ui/assets/edge-Z8YYkHOr.js +0 -1
  304. package/dist/ui/assets/elixir-CG9uKtAF.js +0 -1
  305. package/dist/ui/assets/elm-GfWG2IfT.js +0 -1
  306. package/dist/ui/assets/emacs-lisp-C9PiwqqW.js +0 -1
  307. package/dist/ui/assets/erb-xe89e73J.js +0 -1
  308. package/dist/ui/assets/erlang-Cphh6RMH.js +0 -1
  309. package/dist/ui/assets/everforest-dark-sB-x3p7T.js +0 -1
  310. package/dist/ui/assets/everforest-light-Df2xbC6M.js +0 -1
  311. package/dist/ui/assets/fennel-DQxkIbk2.js +0 -1
  312. package/dist/ui/assets/fish-BJitypiv.js +0 -1
  313. package/dist/ui/assets/fluent-C03EYrpw.js +0 -1
  314. package/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +0 -1
  315. package/dist/ui/assets/fortran-free-form-CYNrtFtB.js +0 -1
  316. package/dist/ui/assets/fsharp-D13ZGOAj.js +0 -1
  317. package/dist/ui/assets/gdresource-C0sCabJj.js +0 -1
  318. package/dist/ui/assets/gdscript-Cp2uCuqX.js +0 -1
  319. package/dist/ui/assets/gdshader-CBce3t8t.js +0 -1
  320. package/dist/ui/assets/genie-CV2tkWYe.js +0 -1
  321. package/dist/ui/assets/gherkin-DExj1W_8.js +0 -1
  322. package/dist/ui/assets/git-commit-BSykSTBG.js +0 -1
  323. package/dist/ui/assets/git-rebase-CoTL_uSE.js +0 -1
  324. package/dist/ui/assets/github-dark-C-LZuMrd.js +0 -1
  325. package/dist/ui/assets/github-dark-default-DXG-b-1a.js +0 -1
  326. package/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +0 -1
  327. package/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +0 -1
  328. package/dist/ui/assets/github-light-EUqPIrTm.js +0 -1
  329. package/dist/ui/assets/github-light-default-BXViO-2h.js +0 -1
  330. package/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +0 -1
  331. package/dist/ui/assets/gleam-CSRkHgEL.js +0 -1
  332. package/dist/ui/assets/glimmer-js-DAn4UCSu.js +0 -1
  333. package/dist/ui/assets/glimmer-ts-Tjyi6Gh5.js +0 -1
  334. package/dist/ui/assets/glsl-CtTDZoqR.js +0 -1
  335. package/dist/ui/assets/gn-ilITqXS6.js +0 -1
  336. package/dist/ui/assets/gnuplot-7GGW24-e.js +0 -1
  337. package/dist/ui/assets/go-BJwz_mda.js +0 -1
  338. package/dist/ui/assets/graphql-D5gcC_Jk.js +0 -1
  339. package/dist/ui/assets/groovy-CacY0gHj.js +0 -1
  340. package/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +0 -1
  341. package/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +0 -1
  342. package/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +0 -1
  343. package/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +0 -1
  344. package/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +0 -1
  345. package/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +0 -1
  346. package/dist/ui/assets/hack-BJXY27dt.js +0 -1
  347. package/dist/ui/assets/haml-BLfFoZf7.js +0 -1
  348. package/dist/ui/assets/handlebars-Dw6CWkvN.js +0 -1
  349. package/dist/ui/assets/haskell-D8IpX4py.js +0 -1
  350. package/dist/ui/assets/haxe-OTjmBuCE.js +0 -1
  351. package/dist/ui/assets/hcl-Dh228itO.js +0 -1
  352. package/dist/ui/assets/heavy-payload-Dcg0-F-S.js +0 -4
  353. package/dist/ui/assets/hjson-CxZEssPk.js +0 -1
  354. package/dist/ui/assets/hlsl-Cvrh5tZx.js +0 -1
  355. package/dist/ui/assets/horizon-CE9ld1lL.js +0 -1
  356. package/dist/ui/assets/horizon-bright-Br1oVSNq.js +0 -1
  357. package/dist/ui/assets/houston-CsvMBhTu.js +0 -1
  358. package/dist/ui/assets/html-CAcAWvoN.js +0 -1
  359. package/dist/ui/assets/html-derivative-8aSW2E_7.js +0 -1
  360. package/dist/ui/assets/http-B2YR_3V1.js +0 -1
  361. package/dist/ui/assets/hurl-BnDJ9Zhf.js +0 -1
  362. package/dist/ui/assets/hxml-B0Qn7Nwc.js +0 -1
  363. package/dist/ui/assets/hy-CZbG8q4J.js +0 -1
  364. package/dist/ui/assets/imba-DsUTQ-LC.js +0 -1
  365. package/dist/ui/assets/ini-B5eOa1yu.js +0 -1
  366. package/dist/ui/assets/java-Doxi4W8u.js +0 -1
  367. package/dist/ui/assets/javascript-BbRdEqti.js +0 -1
  368. package/dist/ui/assets/jinja-CS3Tpv_Q.js +0 -1
  369. package/dist/ui/assets/jison-BkPGYVHR.js +0 -1
  370. package/dist/ui/assets/json-BMt1m3m8.js +0 -1
  371. package/dist/ui/assets/json5-BR5RXkoi.js +0 -1
  372. package/dist/ui/assets/jsonc-CYpm1nAK.js +0 -1
  373. package/dist/ui/assets/jsonl-CmCQp5Yx.js +0 -1
  374. package/dist/ui/assets/jsonnet-CJTPZ8u_.js +0 -1
  375. package/dist/ui/assets/jssm-DXw9l8Rf.js +0 -1
  376. package/dist/ui/assets/jsx-CQKrJXXY.js +0 -1
  377. package/dist/ui/assets/julia-BuN7i2du.js +0 -1
  378. package/dist/ui/assets/just-BswEPFPu.js +0 -1
  379. package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +0 -1
  380. package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +0 -1
  381. package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +0 -1
  382. package/dist/ui/assets/kdl-CsD5j6eV.js +0 -1
  383. package/dist/ui/assets/kotlin-DhhofPvG.js +0 -1
  384. package/dist/ui/assets/kusto-BUv0MjJC.js +0 -1
  385. package/dist/ui/assets/laserwave-C_8bwKvT.js +0 -1
  386. package/dist/ui/assets/latex-DU2VyFfA.js +0 -1
  387. package/dist/ui/assets/lean-CewbzKMR.js +0 -1
  388. package/dist/ui/assets/less-DVTAwKKz.js +0 -1
  389. package/dist/ui/assets/light-plus-DVQuIRkW.js +0 -1
  390. package/dist/ui/assets/liquid-Cmz1L3dq.js +0 -1
  391. package/dist/ui/assets/llvm-Cm23YOpf.js +0 -1
  392. package/dist/ui/assets/log-BNLmms1o.js +0 -1
  393. package/dist/ui/assets/logo-Cluzi2Zq.js +0 -1
  394. package/dist/ui/assets/lua-CfVXhkaJ.js +0 -1
  395. package/dist/ui/assets/luau-CNKltnaQ.js +0 -1
  396. package/dist/ui/assets/make-Dixweg8N.js +0 -1
  397. package/dist/ui/assets/markdown-BYOwaDjH.js +0 -1
  398. package/dist/ui/assets/marko-C5bfqGiA.js +0 -1
  399. package/dist/ui/assets/material-theme-Bm3Qr25_.js +0 -1
  400. package/dist/ui/assets/material-theme-darker-2IIEA8gg.js +0 -1
  401. package/dist/ui/assets/material-theme-lighter-uhdI0v04.js +0 -1
  402. package/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +0 -1
  403. package/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +0 -1
  404. package/dist/ui/assets/matlab-D7qyCx1q.js +0 -1
  405. package/dist/ui/assets/mdc-CVBXYfyq.js +0 -1
  406. package/dist/ui/assets/mdx-DQZ5AkYe.js +0 -1
  407. package/dist/ui/assets/mermaid-Bk4SNUv9.js +0 -1
  408. package/dist/ui/assets/min-dark-BSWPekZh.js +0 -1
  409. package/dist/ui/assets/min-light-DDpmG2fV.js +0 -1
  410. package/dist/ui/assets/mipsasm-BMqwQI7S.js +0 -1
  411. package/dist/ui/assets/mojo-BgCJLMeH.js +0 -1
  412. package/dist/ui/assets/monokai-CdkpiU2Y.js +0 -1
  413. package/dist/ui/assets/moonbit-CaWjb8XO.js +0 -1
  414. package/dist/ui/assets/move-B1IS1UjX.js +0 -1
  415. package/dist/ui/assets/narrat-_X_XdTYD.js +0 -1
  416. package/dist/ui/assets/nextflow-Bbiyy34d.js +0 -1
  417. package/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +0 -1
  418. package/dist/ui/assets/nginx-CzJafxLa.js +0 -1
  419. package/dist/ui/assets/night-owl-DhmEMT88.js +0 -1
  420. package/dist/ui/assets/night-owl-light-eJ-hLW7d.js +0 -1
  421. package/dist/ui/assets/nim-DABKtHtM.js +0 -1
  422. package/dist/ui/assets/nix-IvuFDN5E.js +0 -1
  423. package/dist/ui/assets/nord-Cb4Vim4T.js +0 -1
  424. package/dist/ui/assets/nushell-DcLAeLz5.js +0 -1
  425. package/dist/ui/assets/objective-c-D1A_Heim.js +0 -1
  426. package/dist/ui/assets/objective-cpp-BsSzOQcm.js +0 -1
  427. package/dist/ui/assets/ocaml-O90oeIOV.js +0 -1
  428. package/dist/ui/assets/odin-B1RWQWA5.js +0 -1
  429. package/dist/ui/assets/one-dark-pro-CLwyXe_n.js +0 -1
  430. package/dist/ui/assets/one-light-D7Lr4KcI.js +0 -1
  431. package/dist/ui/assets/openscad-BUDT5pXO.js +0 -1
  432. package/dist/ui/assets/pascal-4ZHwLPI5.js +0 -1
  433. package/dist/ui/assets/perl-CBh7L3lZ.js +0 -1
  434. package/dist/ui/assets/php-DFbI9q5p.js +0 -1
  435. package/dist/ui/assets/pierre-dark-sU4Zdns8.js +0 -1
  436. package/dist/ui/assets/pierre-dark-soft-HXgun5vs.js +0 -1
  437. package/dist/ui/assets/pierre-light-DWBk51d8.js +0 -1
  438. package/dist/ui/assets/pierre-light-soft-CodEzPxf.js +0 -1
  439. package/dist/ui/assets/pkl-ot-7Btpt.js +0 -1
  440. package/dist/ui/assets/plastic-DQwYfKfQ.js +0 -1
  441. package/dist/ui/assets/plsql-DGHpHOYJ.js +0 -1
  442. package/dist/ui/assets/po-BiJDBrnU.js +0 -1
  443. package/dist/ui/assets/poimandres-DRFjx7u4.js +0 -1
  444. package/dist/ui/assets/polar-C7UOKdEL.js +0 -1
  445. package/dist/ui/assets/postcss-BXeXVLqQ.js +0 -1
  446. package/dist/ui/assets/powerquery-DNMTfnFr.js +0 -1
  447. package/dist/ui/assets/powershell-DshXNtvi.js +0 -1
  448. package/dist/ui/assets/prisma-BsRQq5mF.js +0 -1
  449. package/dist/ui/assets/prolog-iXnhIJG7.js +0 -1
  450. package/dist/ui/assets/proto-DB4EqR-F.js +0 -1
  451. package/dist/ui/assets/pug-C_PxC7gO.js +0 -1
  452. package/dist/ui/assets/puppet-CDv2pdJW.js +0 -1
  453. package/dist/ui/assets/purescript-9MfHhQsQ.js +0 -1
  454. package/dist/ui/assets/python-gzcpVVnB.js +0 -1
  455. package/dist/ui/assets/qml-DtngoFFK.js +0 -1
  456. package/dist/ui/assets/qmldir-DCQb3MpD.js +0 -1
  457. package/dist/ui/assets/qss-Fe1Jh2GI.js +0 -1
  458. package/dist/ui/assets/r-DohkcevW.js +0 -1
  459. package/dist/ui/assets/racket-DcIDlBhZ.js +0 -1
  460. package/dist/ui/assets/raku-B3gFvitq.js +0 -1
  461. package/dist/ui/assets/razor-C4t8J0_E.js +0 -1
  462. package/dist/ui/assets/red-CJ3rzSJv.js +0 -1
  463. package/dist/ui/assets/reg-CRGYupPL.js +0 -1
  464. package/dist/ui/assets/regexp-OGbTbjgY.js +0 -1
  465. package/dist/ui/assets/rel-BtDbiS_P.js +0 -1
  466. package/dist/ui/assets/review-payload-C5Qz60Kq.js +0 -1
  467. package/dist/ui/assets/riscv-Ckw8ddFX.js +0 -1
  468. package/dist/ui/assets/ron-VUp2lXgN.js +0 -1
  469. package/dist/ui/assets/rose-pine-BthvhNj6.js +0 -1
  470. package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +0 -1
  471. package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +0 -1
  472. package/dist/ui/assets/rosmsg-CAekHB0j.js +0 -1
  473. package/dist/ui/assets/rst-CfBbbcvC.js +0 -1
  474. package/dist/ui/assets/ruby-Bw0mpxHY.js +0 -1
  475. package/dist/ui/assets/rust-Cfkwpbl8.js +0 -1
  476. package/dist/ui/assets/sas-Cs3s9JOf.js +0 -1
  477. package/dist/ui/assets/sass-DXrisJhu.js +0 -1
  478. package/dist/ui/assets/scala-DKOlJaKm.js +0 -1
  479. package/dist/ui/assets/scheme-DQCgrYNe.js +0 -1
  480. package/dist/ui/assets/scss-sRxNJS54.js +0 -1
  481. package/dist/ui/assets/sdbl-bTVj8UrX.js +0 -1
  482. package/dist/ui/assets/shaderlab-TOUzSsQk.js +0 -1
  483. package/dist/ui/assets/shellscript-B0X6wh0R.js +0 -1
  484. package/dist/ui/assets/shellsession-D2FdOioR.js +0 -1
  485. package/dist/ui/assets/slack-dark-DnToyrRv.js +0 -1
  486. package/dist/ui/assets/slack-ochin-B2OO5cIa.js +0 -1
  487. package/dist/ui/assets/smalltalk-B16xEiuN.js +0 -1
  488. package/dist/ui/assets/snazzy-light-4G7pJPwS.js +0 -1
  489. package/dist/ui/assets/solarized-dark-DV17i1UV.js +0 -1
  490. package/dist/ui/assets/solarized-light-DSh2HLQt.js +0 -1
  491. package/dist/ui/assets/solidity-CKzVLygQ.js +0 -1
  492. package/dist/ui/assets/soy-s6g9OjJ1.js +0 -1
  493. package/dist/ui/assets/sparql-D_iOobhT.js +0 -1
  494. package/dist/ui/assets/splunk-BC2Px7Mm.js +0 -1
  495. package/dist/ui/assets/sql-DVTnh5V-.js +0 -1
  496. package/dist/ui/assets/ssh-config-BgfXC-Er.js +0 -1
  497. package/dist/ui/assets/stata-DFIDiXF9.js +0 -1
  498. package/dist/ui/assets/stylus-B6D30XZt.js +0 -1
  499. package/dist/ui/assets/surrealql-DVfrsLyg.js +0 -1
  500. package/dist/ui/assets/svelte-D5GsxESq.js +0 -1
  501. package/dist/ui/assets/swift-DonLKvLd.js +0 -1
  502. package/dist/ui/assets/synthwave-84-nFMaYfgc.js +0 -1
  503. package/dist/ui/assets/system-verilog-DJ5XKQeo.js +0 -1
  504. package/dist/ui/assets/systemd-BxMlprV5.js +0 -1
  505. package/dist/ui/assets/talonscript-CohzipZa.js +0 -1
  506. package/dist/ui/assets/tasl-DMoTqEGO.js +0 -1
  507. package/dist/ui/assets/tcl-CZd0xW_V.js +0 -1
  508. package/dist/ui/assets/templ-DI-Zyqzd.js +0 -1
  509. package/dist/ui/assets/terraform-DswuEJGm.js +0 -1
  510. package/dist/ui/assets/tex-WHHmlbJI.js +0 -1
  511. package/dist/ui/assets/tokyo-night-oM2G3aXe.js +0 -1
  512. package/dist/ui/assets/toml-CcmNWLt0.js +0 -1
  513. package/dist/ui/assets/ts-tags-Dwpo2RFJ.js +0 -1
  514. package/dist/ui/assets/tsv-sltzmVWM.js +0 -1
  515. package/dist/ui/assets/tsx-ph_idaAW.js +0 -1
  516. package/dist/ui/assets/turtle-ByJddavk.js +0 -1
  517. package/dist/ui/assets/twig-YO17jFjR.js +0 -1
  518. package/dist/ui/assets/typescript-CbAxjhkl.js +0 -1
  519. package/dist/ui/assets/typespec-B88KGewJ.js +0 -1
  520. package/dist/ui/assets/typst-DI99ib-x.js +0 -1
  521. package/dist/ui/assets/useFileDiffInstance-B2DLX3Vg.js +0 -244
  522. package/dist/ui/assets/v-DETTlOr0.js +0 -1
  523. package/dist/ui/assets/vala-zf12oZj6.js +0 -1
  524. package/dist/ui/assets/vb-Djn5o6TS.js +0 -1
  525. package/dist/ui/assets/verilog-CiiDBU1e.js +0 -1
  526. package/dist/ui/assets/vesper-D5bVUKB1.js +0 -1
  527. package/dist/ui/assets/vhdl-BroJfC0k.js +0 -1
  528. package/dist/ui/assets/viml-DvXPmvsu.js +0 -1
  529. package/dist/ui/assets/vitesse-black-fwtXNY1n.js +0 -1
  530. package/dist/ui/assets/vitesse-dark-BZCL-v6S.js +0 -1
  531. package/dist/ui/assets/vitesse-light-VbXTXTou.js +0 -1
  532. package/dist/ui/assets/vue-CraHL-Ps.js +0 -1
  533. package/dist/ui/assets/vue-html-e9tyZNtS.js +0 -1
  534. package/dist/ui/assets/vue-vine-CofmxaUb.js +0 -1
  535. package/dist/ui/assets/vyper-CgoNMtux.js +0 -1
  536. package/dist/ui/assets/wasm-BnjxR4X6.js +0 -1
  537. package/dist/ui/assets/wasm-ByWQv1Qj.js +0 -1
  538. package/dist/ui/assets/wenyan-C8pVoKbM.js +0 -1
  539. package/dist/ui/assets/wgsl-BsKzXJz4.js +0 -1
  540. package/dist/ui/assets/wikitext-ClFFjSW2.js +0 -1
  541. package/dist/ui/assets/wit-DdvCle-K.js +0 -1
  542. package/dist/ui/assets/wolfram-DLL8P-h_.js +0 -1
  543. package/dist/ui/assets/workspace-app-8--oTbCd.css +0 -1
  544. package/dist/ui/assets/xml-BWSdPZHm.js +0 -1
  545. package/dist/ui/assets/xsl-BtCt7Hx8.js +0 -1
  546. package/dist/ui/assets/yaml-BZiTw7cQ.js +0 -1
  547. package/dist/ui/assets/zenscript-BnlCZFoB.js +0 -1
  548. package/dist/ui/assets/zig-CMLA9XwU.js +0 -1
  549. package/docs/assets/auvrynt-logo-light.png +0 -0
  550. package/docs/assets/auvrynt-screenshot.png +0 -0
@@ -0,0 +1,617 @@
1
+ import { timingSafeEqual, randomBytes, randomUUID, createHash } from "node:crypto";
2
+ import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { AccessDeniedError, InvalidGrantError, InvalidRequestError, InvalidTokenError } from "@modelcontextprotocol/sdk/server/auth/errors.js";
5
+ import { checkResourceAllowed, resourceUrlFromServerUrl } from "@modelcontextprotocol/sdk/shared/auth-utils.js";
6
+ import { logEvent } from "../logger.js";
7
+ import { AUVRYNT_THEME_CSS } from "../ui/brand-theme.js";
8
+ const CODE_TTL_MS = 5 * 60 * 1000;
9
+ const MAX_DYNAMIC_CLIENTS = 1024;
10
+ const MAX_AUTHORIZATION_CODES = 1024;
11
+ const MAX_ACCESS_TOKENS = 4096;
12
+ const MAX_REFRESH_TOKENS = 4096;
13
+ function randomToken() {
14
+ return randomBytes(32).toString("base64url");
15
+ }
16
+ function safeEquals(a, b) {
17
+ const left = Buffer.from(a);
18
+ const right = Buffer.from(b);
19
+ if (left.byteLength !== right.byteLength)
20
+ return false;
21
+ return timingSafeEqual(left, right);
22
+ }
23
+ function htmlEscape(value) {
24
+ return value
25
+ .replaceAll("&", "&")
26
+ .replaceAll("<", "&lt;")
27
+ .replaceAll(">", "&gt;")
28
+ .replaceAll('"', "&quot;")
29
+ .replaceAll("'", "&#39;");
30
+ }
31
+ function formHtml(params) {
32
+ const scopeDescriptions = {
33
+ "auvrynt:read": "Inspect files, search, and perform read-only project analysis",
34
+ "auvrynt:write": "Edit and create files",
35
+ "auvrynt:process": "Run local commands and processes with the current OS user's privileges",
36
+ "auvrynt:web": "Use browser and web-development tools",
37
+ "auvrynt:software": "Use software and .NET tools",
38
+ "auvrynt:godot": "Use Godot project and editor tools",
39
+ "auvrynt:blender": "Use workspace-bound Blender 3D tools",
40
+ "auvrynt:blender-python": "Execute arbitrary Python inside Blender (host-level capability)",
41
+ "auvrynt:serena": "Use local Serena semantic code tools",
42
+ };
43
+ const scopeItems = params.scopes.length > 0
44
+ ? params.scopes.map((s) => {
45
+ const desc = scopeDescriptions[s];
46
+ return `<li><strong>${htmlEscape(s)}</strong>${desc ? ` <span>${htmlEscape(desc)}</span>` : ""}</li>`;
47
+ }).join("\n ")
48
+ : "<li><strong>auvrynt</strong><span>General access</span></li>";
49
+ const error = params.error
50
+ ? `<output role="alert" class="error">${htmlEscape(params.error)}</output>`
51
+ : "";
52
+ const privilegedScopes = params.scopes.filter((scope) => scope === "auvrynt:process" || scope === "auvrynt:blender-python");
53
+ const privilegeNote = privilegedScopes.length > 0
54
+ ? `<p class="privilege-note"><strong>Local execution requested.</strong> These permissions can run code with your OS user privileges. Approve only for a web agent you trust.</p>`
55
+ : "";
56
+ const hiddenFields = Object.entries(params.fields)
57
+ .filter((entry) => entry[1] !== undefined)
58
+ .map(([name, value]) => ` <input type="hidden" name="${htmlEscape(name)}" value="${htmlEscape(value)}" />`)
59
+ .join("\n");
60
+ return `<!doctype html>
61
+ <html lang="en">
62
+ <head>
63
+ <meta charset="utf-8" />
64
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
65
+ <title>Auvrynt: Webkit Arsenal</title>
66
+ <style nonce="${htmlEscape(params.nonce)}">
67
+ ${AUVRYNT_THEME_CSS}
68
+ *, *::before, *::after { box-sizing: border-box; }
69
+ :root { font-family: var(--auvrynt-font-sans); }
70
+ html, body { height: 100%; }
71
+ body { margin: 0; height: 100dvh; overflow: hidden; background: radial-gradient(circle at 20% 0%, rgba(168,85,247,.20), transparent 36%), linear-gradient(135deg, var(--auvrynt-bg), var(--auvrynt-surface) 52%, var(--auvrynt-bg-deep)); color: var(--auvrynt-text); display: flex; align-items: center; justify-content: center; }
72
+ main { width: min(100%, 760px); max-height: 100dvh; overflow: hidden; }
73
+ .form-panel { padding: clamp(18px, 4vh, 42px) clamp(20px, 5vw, 52px); }
74
+ .brand-icon { width: 52px; height: 52px; display: block; margin: 0 0 14px; border-radius: 12px; object-fit: cover; }
75
+ .eyebrow { margin: 0 0 7px; color: var(--auvrynt-accent-soft); font-size: 10px; font-weight: 750; letter-spacing: .14em; text-transform: uppercase; }
76
+ .form-panel h2 { margin: 0 0 7px; font-size: clamp(26px, 4vh, 34px); line-height: 1.05; letter-spacing: -.045em; }
77
+ .intro { max-width: 660px; margin: 0 0 12px; color: var(--auvrynt-text-secondary); font-size: 14px; line-height: 1.45; }
78
+ .client-badge { display: inline-flex; align-items: center; gap: 8px; margin-bottom: 12px; color: #f3e8ff; font-size: 13px; font-weight: 650; }
79
+ .client-badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--auvrynt-accent); }
80
+ .section-label { margin: 0 0 5px; color: var(--auvrynt-text-muted); font-size: 10px; font-weight: 750; letter-spacing: .12em; text-transform: uppercase; }
81
+ .scope-list { list-style: none; padding: 0; margin: 0 0 12px; display: flex; flex-wrap: wrap; column-gap: 22px; row-gap: 3px; }
82
+ .scope-list li { flex: 1 1 46%; min-width: 260px; padding: 2px 0; color: #c4b5fd; font-size: 11px; line-height: 1.3; }
83
+ .scope-list li strong { color: #fff7ff; font-size: 11px; font-weight: 700; }
84
+ .token-group { margin-bottom: 12px; }
85
+ .token-group label { display: block; margin-bottom: 5px; color: #dce6f1; font-size: 12px; font-weight: 650; }
86
+ .input-wrapper { position: relative; }
87
+ .input-wrapper input { width: 100%; padding: 11px 12px; border: 1px solid var(--auvrynt-border); border-radius: var(--auvrynt-radius); background: var(--auvrynt-code); color: var(--auvrynt-text); font: inherit; font-size: 14px; outline: none; }
88
+ .input-wrapper input:focus { border-color: var(--auvrynt-accent); box-shadow: 0 0 0 2px rgba(192,132,252,.20); }
89
+ .input-wrapper input::placeholder { color: #657388; }
90
+ .button-group { display: flex; gap: 8px; }
91
+ .button-group button { flex: 1; min-height: 42px; border-radius: 7px; padding: 10px 12px; font: inherit; font-size: 13px; font-weight: 750; cursor: pointer; }
92
+ .button-group button:focus-visible { outline: 2px solid var(--auvrynt-accent); outline-offset: 2px; }
93
+ .btn-approve { border: 1px solid var(--auvrynt-accent); color: var(--auvrynt-surface); background: linear-gradient(135deg, var(--auvrynt-accent-soft), var(--auvrynt-accent)); }
94
+ .btn-deny { border: 1px solid rgba(216,180,254,.35); color: #f3e8ff; background: transparent; }
95
+ .error { display: block; margin: 0 0 10px; color: var(--auvrynt-danger); font-size: 12px; line-height: 1.35; }
96
+ .privilege-note { margin: -2px 0 10px; color: #e9d5ff; font-size: 11px; line-height: 1.35; }
97
+ .privilege-note strong { color: #f5d0fe; }
98
+ .security-note { display: flex; gap: 7px; margin: 10px 0 0; color: #a78bfa; font-size: 11px; line-height: 1.35; }
99
+ .submit-status { min-height: 16px; margin: 8px 0 0; color: #c4b5fd; font-size: 11px; line-height: 1.35; }
100
+ .security-note::before { content: "✓"; color: var(--auvrynt-accent); font-weight: 800; }
101
+ @media (max-width: 620px) { body { align-items: flex-start; } .form-panel { padding: 14px 18px; } .scope-list li { min-width: 100%; } }
102
+ @media (max-height: 680px) { .brand-icon { width: 40px; height: 40px; margin-bottom: 8px; } .intro, .client-badge, .scope-list { margin-bottom: 8px; } .scope-list li { font-size: 10px; padding: 0; } .form-panel h2 { font-size: 26px; } }
103
+ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
104
+ </style>
105
+ </head>
106
+ <body>
107
+ <main role="main" aria-labelledby="authorize-title">
108
+ <section class="form-panel">
109
+ <img class="brand-icon" src="/brand-assets/auvrynt-icon.png" alt="Auvrynt" width="64" height="64" />
110
+ <p class="eyebrow">Secure handshake</p>
111
+ <h2 id="authorize-title">Approve this connection</h2>
112
+ <p class="intro">Review what the web agent can do in your workspace, then confirm with your local owner token.</p>
113
+ ${error}
114
+ <div class="client-badge">${htmlEscape(params.clientName)}</div>
115
+ <p class="section-label">Requested permissions</p>
116
+ <ul class="scope-list" aria-label="Requested permissions">
117
+ ${scopeItems}
118
+ </ul>
119
+ ${privilegeNote}
120
+ <form id="authorization-form" method="post" action="/authorize" aria-describedby="token-desc">
121
+ <div class="token-group">
122
+ <label for="owner_token">Local owner token</label>
123
+ <p id="token-desc" class="sr-only">Enter your Auvrynt owner token to authorize this connection. This token stays on this page and is never shared with the web agent.</p>
124
+ <div class="input-wrapper">
125
+ <input id="owner_token" name="owner_token" type="password" placeholder="Enter your owner token" autocomplete="off" autofocus required aria-required="true" />
126
+ </div>
127
+ </div>
128
+ ${hiddenFields}
129
+ <div class="button-group">
130
+ <button type="submit" name="denied" value="true" class="btn-deny" formnovalidate>Deny request</button>
131
+ <button type="submit" class="btn-approve">Approve connection</button>
132
+ </div>
133
+ <p id="approval-status" class="submit-status" role="status" aria-live="polite"></p>
134
+ </form>
135
+ <p class="security-note">Your owner token is validated locally. It is never sent to the web agent, stored in cookies, or written to logs.</p>
136
+ </section>
137
+ </main>
138
+ <script nonce="${htmlEscape(params.nonce)}">
139
+ (function() {
140
+ var form = document.getElementById('authorization-form');
141
+ var status = document.getElementById('approval-status');
142
+ if (form && status) {
143
+ form.addEventListener('submit', function(event) {
144
+ if (event.submitter && event.submitter.name === 'denied') return;
145
+ var approve = form.querySelector('.btn-approve');
146
+ if (approve) {
147
+ approve.textContent = 'Approving...';
148
+ approve.setAttribute('aria-busy', 'true');
149
+ }
150
+ status.textContent = 'Approval submitted. Returning to your web agent...';
151
+ var dashboardUrl = 'http://127.0.0.1:49321/dashboard';
152
+ var dashboard = window.open(dashboardUrl, '_blank', 'noopener,noreferrer');
153
+ if (!dashboard) status.textContent = 'Approved. Your browser blocked the dashboard tab; open ' + dashboardUrl + ' manually.';
154
+ window.setTimeout(function() {
155
+ if (!approve || approve.textContent !== 'Approving...') return;
156
+ approve.textContent = 'Approve connection';
157
+ approve.removeAttribute('aria-busy');
158
+ status.textContent = 'Still waiting for the web agent callback. Keep this page open, then retry if the web agent does not finish connecting.';
159
+ }, 8000);
160
+ });
161
+ }
162
+ })();
163
+ </script>
164
+ </body>
165
+ </html>`;
166
+ }
167
+ function requestedScopesAllowed(requested, supported) {
168
+ return requested.every((scope) => supported.includes(scope));
169
+ }
170
+ function redirectHostAllowed(redirectUri, allowedHosts) {
171
+ let parsed;
172
+ try {
173
+ parsed = new URL(redirectUri);
174
+ }
175
+ catch {
176
+ return false;
177
+ }
178
+ const hostname = parsed.hostname.toLowerCase();
179
+ const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(hostname);
180
+ if (loopback)
181
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
182
+ if (parsed.protocol !== "https:")
183
+ return false;
184
+ return allowedHosts.some((allowed) => {
185
+ const h = allowed.toLowerCase();
186
+ return h === "*" || hostname === h || hostname.endsWith(`.${h}`);
187
+ });
188
+ }
189
+ function redirectHostDescription(redirectUri) {
190
+ try {
191
+ const parsed = new URL(redirectUri);
192
+ return `${parsed.protocol}//${parsed.hostname}`;
193
+ }
194
+ catch {
195
+ return "invalid-uri";
196
+ }
197
+ }
198
+ function authorizationNonce() {
199
+ return randomBytes(18).toString("base64url");
200
+ }
201
+ function setAuthorizationSecurityHeaders(res, nonce, redirectUri) {
202
+ let redirectOrigin;
203
+ try {
204
+ redirectOrigin = redirectUri ? new URL(redirectUri).origin : undefined;
205
+ }
206
+ catch {
207
+ redirectOrigin = undefined;
208
+ }
209
+ const formAction = ["'self'", redirectOrigin].filter(Boolean).join(" ");
210
+ res.setHeader("Cache-Control", "no-store");
211
+ res.setHeader("Pragma", "no-cache");
212
+ res.setHeader("X-Content-Type-Options", "nosniff");
213
+ res.setHeader("X-Frame-Options", "DENY");
214
+ res.setHeader("Referrer-Policy", "no-referrer");
215
+ res.setHeader("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=(), usb=()");
216
+ res.setHeader("Content-Security-Policy", `default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; img-src 'self'; form-action ${formAction}; frame-ancestors 'none'; base-uri 'none'`);
217
+ }
218
+ function sendAuthorizationForm(res, params, status) {
219
+ const nonce = authorizationNonce();
220
+ setAuthorizationSecurityHeaders(res, nonce, params.fields.redirect_uri);
221
+ res.status(status).setHeader("Content-Type", "text/html; charset=utf-8");
222
+ res.send(formHtml({ ...params, nonce }));
223
+ }
224
+ export class InMemoryOAuthClientsStore {
225
+ allowedRedirectHosts;
226
+ onChange;
227
+ isClientInUse;
228
+ onEvictClient;
229
+ clients = new Map();
230
+ constructor(allowedRedirectHosts, initialClients = [], onChange, isClientInUse = () => false, onEvictClient) {
231
+ this.allowedRedirectHosts = allowedRedirectHosts;
232
+ this.onChange = onChange;
233
+ this.isClientInUse = isClientInUse;
234
+ this.onEvictClient = onEvictClient;
235
+ for (const client of initialClients) {
236
+ if (client.client_id)
237
+ this.clients.set(client.client_id, client);
238
+ }
239
+ }
240
+ getClient(clientId) {
241
+ return this.clients.get(clientId);
242
+ }
243
+ registerClient(client) {
244
+ if (this.clients.size >= MAX_DYNAMIC_CLIENTS && !this.evictOldestInactiveClient()) {
245
+ throw new InvalidRequestError("Dynamic OAuth client capacity reached while all registered clients are active.");
246
+ }
247
+ const rejectedRedirectHosts = client.redirect_uris
248
+ .filter((uri) => !redirectHostAllowed(uri, this.allowedRedirectHosts))
249
+ .map(redirectHostDescription);
250
+ if (rejectedRedirectHosts.length > 0) {
251
+ throw new InvalidRequestError(`Client redirect_uri is not allowed for this Auvrynt server (rejected host(s): ${rejectedRedirectHosts.join(", ")})`);
252
+ }
253
+ const now = Math.floor(Date.now() / 1000);
254
+ const registered = {
255
+ ...client,
256
+ client_id: `auvrynt-${randomUUID()}`,
257
+ client_id_issued_at: now,
258
+ token_endpoint_auth_method: client.token_endpoint_auth_method ?? "none",
259
+ grant_types: client.grant_types ?? ["authorization_code", "refresh_token"],
260
+ response_types: client.response_types ?? ["code"],
261
+ };
262
+ this.clients.set(registered.client_id, registered);
263
+ this.onChange?.();
264
+ return registered;
265
+ }
266
+ allClients() {
267
+ return [...this.clients.values()];
268
+ }
269
+ evictOldestInactiveClient() {
270
+ const candidates = [...this.clients.values()].sort((left, right) => (left.client_id_issued_at ?? 0) - (right.client_id_issued_at ?? 0));
271
+ const inactive = candidates.find((registered) => !this.isClientInUse(registered.client_id));
272
+ if (inactive) {
273
+ this.onEvictClient?.(inactive.client_id);
274
+ return this.clients.delete(inactive.client_id);
275
+ }
276
+ const oldest = candidates[0];
277
+ if (!oldest)
278
+ return false;
279
+ this.onEvictClient?.(oldest.client_id);
280
+ return this.clients.delete(oldest.client_id);
281
+ }
282
+ }
283
+ export class SingleUserOAuthProvider {
284
+ config;
285
+ clientsStore;
286
+ codes = new Map();
287
+ accessTokens = new Map();
288
+ refreshTokens = new Map();
289
+ resourceServerUrl;
290
+ stateFile;
291
+ constructor(config, resourceServerUrl, stateFile) {
292
+ this.config = config;
293
+ this.resourceServerUrl = resourceUrlFromServerUrl(resourceServerUrl);
294
+ this.stateFile = stateFile;
295
+ const persisted = this.loadState();
296
+ this.clientsStore = new InMemoryOAuthClientsStore(config.allowedRedirectHosts, persisted?.clients, () => this.persistState(), (clientId) => this.clientHasActiveGrant(clientId), (clientId) => this.revokeClientGrants(clientId));
297
+ for (const [code, record] of persisted?.codes ?? []) {
298
+ this.codes.set(code, {
299
+ ...record,
300
+ params: {
301
+ ...record.params,
302
+ resource: record.params.resource ? new URL(record.params.resource) : undefined,
303
+ },
304
+ });
305
+ }
306
+ for (const [tokenHash, record] of persisted?.accessTokens ?? []) {
307
+ this.accessTokens.set(tokenHash, {
308
+ ...record,
309
+ resource: record.resource ? new URL(record.resource) : undefined,
310
+ });
311
+ }
312
+ for (const [tokenHash, record] of persisted?.refreshTokens ?? []) {
313
+ this.refreshTokens.set(tokenHash, {
314
+ ...record,
315
+ resource: record.resource ? new URL(record.resource) : undefined,
316
+ });
317
+ }
318
+ this.pruneExpired();
319
+ this.persistState();
320
+ }
321
+ async authorize(client, params, res) {
322
+ // Some hosted MCP clients (including Bolt) omit the RFC 8707 resource
323
+ // parameter even after discovering the protected-resource metadata. Bind
324
+ // an omitted value to this server; never accept a different resource.
325
+ const requestedResource = params.resource ?? this.resourceServerUrl;
326
+ if (!checkResourceAllowed({ requestedResource, configuredResource: this.resourceServerUrl })) {
327
+ throw new InvalidRequestError("Invalid or missing OAuth resource");
328
+ }
329
+ params = { ...params, resource: requestedResource };
330
+ if (!requestedScopesAllowed(params.scopes ?? [], this.config.scopes)) {
331
+ throw new InvalidRequestError("Requested scope is not supported");
332
+ }
333
+ const req = res.req;
334
+ const queryError = req.query?.error;
335
+ if (queryError === "access_denied") {
336
+ throw new AccessDeniedError("Authorization denied by user");
337
+ }
338
+ if (req.method !== "POST") {
339
+ sendAuthorizationForm(res, {
340
+ clientName: client.client_name ?? client.client_id,
341
+ scopes: params.scopes ?? this.config.scopes,
342
+ resource: params.resource,
343
+ fields: authorizationFormFields(client, params),
344
+ }, 200);
345
+ return;
346
+ }
347
+ if (req.body?.denied === "true") {
348
+ throw new AccessDeniedError("Authorization denied by user");
349
+ }
350
+ const providedToken = String(req.body?.owner_token ?? "");
351
+ if (!safeEquals(providedToken, this.config.ownerToken)) {
352
+ sendAuthorizationForm(res, {
353
+ error: "The owner token was not accepted.",
354
+ clientName: client.client_name ?? client.client_id,
355
+ scopes: params.scopes ?? this.config.scopes,
356
+ resource: params.resource,
357
+ fields: authorizationFormFields(client, params),
358
+ }, 401);
359
+ return;
360
+ }
361
+ this.pruneExpired();
362
+ if (this.codes.size >= MAX_AUTHORIZATION_CODES) {
363
+ throw new InvalidRequestError("Too many pending authorization requests. Try again after older requests expire.");
364
+ }
365
+ const code = `code-${randomUUID()}`;
366
+ this.codes.set(code, {
367
+ clientId: client.client_id,
368
+ params,
369
+ expiresAtMs: Date.now() + CODE_TTL_MS,
370
+ });
371
+ this.persistState();
372
+ if (this.config.logging) {
373
+ logEvent(this.config.logging, "info", "oauth_authorization_approved", {
374
+ clientId: client.client_id,
375
+ clientName: client.client_name ?? client.client_id,
376
+ scopes: params.scopes ?? this.config.scopes,
377
+ });
378
+ }
379
+ const redirectUrl = new URL(params.redirectUri);
380
+ redirectUrl.searchParams.set("code", code);
381
+ if (params.state !== undefined)
382
+ redirectUrl.searchParams.set("state", params.state);
383
+ res.redirect(302, redirectUrl.href);
384
+ }
385
+ async challengeForAuthorizationCode(client, authorizationCode) {
386
+ const record = this.validCodeRecord(client, authorizationCode);
387
+ return record.params.codeChallenge;
388
+ }
389
+ async exchangeAuthorizationCode(client, authorizationCode, _codeVerifier, redirectUri, resource) {
390
+ const record = this.validCodeRecord(client, authorizationCode);
391
+ if (redirectUri && redirectUri !== record.params.redirectUri) {
392
+ throw new InvalidGrantError("redirect_uri does not match the authorization request");
393
+ }
394
+ if (resource && !checkResourceAllowed({ requestedResource: resource, configuredResource: this.resourceServerUrl })) {
395
+ throw new InvalidGrantError("Invalid resource");
396
+ }
397
+ this.codes.delete(authorizationCode);
398
+ const tokens = this.issueTokens(client.client_id, record.params.scopes ?? this.config.scopes, record.params.resource);
399
+ this.persistState();
400
+ return tokens;
401
+ }
402
+ async exchangeRefreshToken(client, refreshToken, scopes, resource) {
403
+ const record = this.refreshTokens.get(hashToken(refreshToken));
404
+ if (!record || record.clientId !== client.client_id || record.expiresAt < Math.floor(Date.now() / 1000)) {
405
+ throw new InvalidGrantError("Invalid refresh token");
406
+ }
407
+ if (resource && !checkResourceAllowed({ requestedResource: resource, configuredResource: this.resourceServerUrl })) {
408
+ throw new InvalidGrantError("Invalid resource");
409
+ }
410
+ const requestedScopes = scopes ?? record.scopes;
411
+ if (!requestedScopes.every((scope) => record.scopes.includes(scope))) {
412
+ throw new AccessDeniedError("Refresh token cannot grant requested scopes");
413
+ }
414
+ this.refreshTokens.delete(hashToken(refreshToken));
415
+ const tokens = this.issueTokens(client.client_id, requestedScopes, resource ?? record.resource);
416
+ this.persistState();
417
+ return tokens;
418
+ }
419
+ async verifyAccessToken(token) {
420
+ this.pruneExpired();
421
+ // Header-only MCP clients (e.g. Clusy) cannot run the browser /authorize
422
+ // flow. Accept the Owner token as a long-lived Bearer credential that
423
+ // grants the configured OAuth scopes. OAuth access tokens still take
424
+ // precedence when present.
425
+ if (safeEquals(token, this.config.ownerToken)) {
426
+ return {
427
+ token,
428
+ clientId: "auvrynt-owner-bearer",
429
+ scopes: [...this.config.scopes],
430
+ expiresAt: Math.floor(Date.now() / 1000) + this.config.accessTokenTtlSeconds,
431
+ resource: this.resourceServerUrl,
432
+ };
433
+ }
434
+ const record = this.accessTokens.get(hashToken(token));
435
+ if (!record || record.expiresAt < Math.floor(Date.now() / 1000)) {
436
+ throw new InvalidTokenError("Invalid or expired access token");
437
+ }
438
+ return {
439
+ token,
440
+ clientId: record.clientId,
441
+ scopes: record.scopes,
442
+ expiresAt: record.expiresAt,
443
+ resource: record.resource,
444
+ };
445
+ }
446
+ /**
447
+ * A local profile change is an explicit owner action. Extend existing grants
448
+ * only with scopes already allowed by server configuration so connected web
449
+ * agents can use the newly enabled profile without a forced OAuth reconnect.
450
+ */
451
+ grantScopesToExistingTokens(scopes) {
452
+ const allowed = scopes.filter((scope) => this.config.scopes.includes(scope));
453
+ if (allowed.length === 0)
454
+ return 0;
455
+ let updated = 0;
456
+ const extend = (record) => {
457
+ const next = Array.from(new Set([...record.scopes, ...allowed]));
458
+ if (next.length === record.scopes.length)
459
+ return;
460
+ record.scopes = next;
461
+ updated++;
462
+ };
463
+ for (const record of this.accessTokens.values())
464
+ extend(record);
465
+ for (const record of this.refreshTokens.values())
466
+ extend(record);
467
+ if (updated > 0)
468
+ this.persistState();
469
+ return updated;
470
+ }
471
+ async revokeToken(_client, request) {
472
+ const hashed = hashToken(request.token);
473
+ this.accessTokens.delete(hashed);
474
+ this.refreshTokens.delete(hashed);
475
+ this.persistState();
476
+ }
477
+ validCodeRecord(client, authorizationCode) {
478
+ const record = this.codes.get(authorizationCode);
479
+ if (!record || record.clientId !== client.client_id || record.expiresAtMs < Date.now()) {
480
+ throw new InvalidGrantError("Invalid authorization code");
481
+ }
482
+ return record;
483
+ }
484
+ revokeClientGrants(clientId) {
485
+ for (const [code, record] of this.codes) {
486
+ if (record.clientId === clientId)
487
+ this.codes.delete(code);
488
+ }
489
+ for (const [hash, record] of this.accessTokens) {
490
+ if (record.clientId === clientId)
491
+ this.accessTokens.delete(hash);
492
+ }
493
+ for (const [hash, record] of this.refreshTokens) {
494
+ if (record.clientId === clientId)
495
+ this.refreshTokens.delete(hash);
496
+ }
497
+ }
498
+ clientHasActiveGrant(clientId) {
499
+ this.pruneExpired();
500
+ for (const record of this.codes.values()) {
501
+ if (record.clientId === clientId)
502
+ return true;
503
+ }
504
+ for (const record of this.accessTokens.values()) {
505
+ if (record.clientId === clientId)
506
+ return true;
507
+ }
508
+ for (const record of this.refreshTokens.values()) {
509
+ if (record.clientId === clientId)
510
+ return true;
511
+ }
512
+ return false;
513
+ }
514
+ issueTokens(clientId, scopes, resource) {
515
+ this.pruneExpired();
516
+ if (this.accessTokens.size >= MAX_ACCESS_TOKENS || this.refreshTokens.size >= MAX_REFRESH_TOKENS) {
517
+ throw new InvalidGrantError("OAuth token capacity reached. Revoke stale clients or restart Auvrynt.");
518
+ }
519
+ const now = Math.floor(Date.now() / 1000);
520
+ const accessToken = randomToken();
521
+ const refreshToken = randomToken();
522
+ const accessExpiresAt = now + this.config.accessTokenTtlSeconds;
523
+ const refreshExpiresAt = now + this.config.refreshTokenTtlSeconds;
524
+ this.accessTokens.set(hashToken(accessToken), {
525
+ clientId,
526
+ scopes,
527
+ expiresAt: accessExpiresAt,
528
+ resource,
529
+ });
530
+ this.refreshTokens.set(hashToken(refreshToken), {
531
+ clientId,
532
+ scopes,
533
+ expiresAt: refreshExpiresAt,
534
+ resource,
535
+ });
536
+ return {
537
+ access_token: accessToken,
538
+ token_type: "bearer",
539
+ expires_in: this.config.accessTokenTtlSeconds,
540
+ refresh_token: refreshToken,
541
+ scope: scopes.join(" "),
542
+ };
543
+ }
544
+ pruneExpired() {
545
+ const nowSeconds = Math.floor(Date.now() / 1000);
546
+ const nowMs = Date.now();
547
+ for (const [code, record] of this.codes) {
548
+ if (record.expiresAtMs < nowMs)
549
+ this.codes.delete(code);
550
+ }
551
+ for (const [tokenHash, record] of this.accessTokens) {
552
+ if (record.expiresAt < nowSeconds)
553
+ this.accessTokens.delete(tokenHash);
554
+ }
555
+ for (const [tokenHash, record] of this.refreshTokens) {
556
+ if (record.expiresAt < nowSeconds)
557
+ this.refreshTokens.delete(tokenHash);
558
+ }
559
+ }
560
+ loadState() {
561
+ if (!this.stateFile)
562
+ return undefined;
563
+ try {
564
+ const state = JSON.parse(readFileSync(this.stateFile, "utf8"));
565
+ if (state.version !== 1 || state.resourceServerUrl !== this.resourceServerUrl.href)
566
+ return undefined;
567
+ return state;
568
+ }
569
+ catch {
570
+ return undefined;
571
+ }
572
+ }
573
+ persistState() {
574
+ if (!this.stateFile || !(this.clientsStore instanceof InMemoryOAuthClientsStore))
575
+ return;
576
+ const state = {
577
+ version: 1,
578
+ resourceServerUrl: this.resourceServerUrl.href,
579
+ clients: this.clientsStore.allClients(),
580
+ codes: [...this.codes.entries()].map(([code, record]) => [code, {
581
+ ...record,
582
+ params: {
583
+ ...record.params,
584
+ resource: record.params.resource?.href,
585
+ },
586
+ }]),
587
+ accessTokens: [...this.accessTokens.entries()].map(([tokenHash, record]) => [tokenHash, {
588
+ ...record,
589
+ resource: record.resource?.href,
590
+ }]),
591
+ refreshTokens: [...this.refreshTokens.entries()].map(([tokenHash, record]) => [tokenHash, {
592
+ ...record,
593
+ resource: record.resource?.href,
594
+ }]),
595
+ };
596
+ mkdirSync(dirname(this.stateFile), { recursive: true, mode: 0o700 });
597
+ const temporary = `${this.stateFile}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
598
+ writeFileSync(temporary, JSON.stringify(state), { encoding: "utf8", mode: 0o600, flag: "wx" });
599
+ renameSync(temporary, this.stateFile);
600
+ chmodSync(this.stateFile, 0o600);
601
+ }
602
+ }
603
+ function authorizationFormFields(client, params) {
604
+ return {
605
+ response_type: "code",
606
+ client_id: client.client_id,
607
+ redirect_uri: params.redirectUri,
608
+ code_challenge: params.codeChallenge,
609
+ code_challenge_method: "S256",
610
+ scope: params.scopes?.join(" "),
611
+ state: params.state,
612
+ resource: params.resource?.href,
613
+ };
614
+ }
615
+ function hashToken(token) {
616
+ return createHash("sha256").update(token).digest("base64url");
617
+ }