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,326 @@
1
+ import * as z from "zod/v4";
2
+ import { getRequestContext } from "../../request-context.js";
3
+ import { startDevServer, capturePageScreenshot, inspectPage, testResponsivePage } from "../../web-tools.js";
4
+ import { browserOpen, browserClose, browserListSessions, browserNavigate, browserReload, browserGoBack, browserGoForward, browserSnapshot, browserClick, browserType, browserSelectOption, browserHover, browserPressKey, browserWaitFor, browserGetText, browserGetAttribute, browserIsVisible, browserScroll, browserConsole, browserNetwork, browserEvaluate, browserScreenshot, } from "../../integrations/playwright/browser-session.js";
5
+ import { compareImages, inspectImage, inspectSprite, splitSpriteSheet } from "../../image-tools.js";
6
+ import { registerAppTool } from "../mcp-tool-registrar.js";
7
+ import { MUTATING_ANNOTATIONS, READ_ONLY_ANNOTATIONS, WEB_READ_ANNOTATIONS, WEB_WRITE_ANNOTATIONS, WORKSPACE_ID_SCHEMA, PROCESS_ANNOTATIONS, toolWidgetDescriptorMeta, } from "../tool-registration-shared.js";
8
+ export function registerWebImageTools(server, config, workspaces, processManager) {
9
+ registerAppTool(server, "start_dev_server", {
10
+ title: "Start dev server",
11
+ description: "Launch a local web development server as a persistent process. Auto-detects the dev script from the project. Returns a processId for use with get_process_logs and stop_process.",
12
+ inputSchema: {
13
+ workspaceId: WORKSPACE_ID_SCHEMA,
14
+ command: z.string().optional().describe("Override command to run (e.g. 'npm run dev'). Auto-detected if omitted."),
15
+ workingDirectory: z.string().optional().describe("Working directory relative to workspace root."),
16
+ port: z.number().int().optional().describe("Expected port for the dev server."),
17
+ },
18
+ ...toolWidgetDescriptorMeta(config, "shell"), annotations: PROCESS_ANNOTATIONS,
19
+ }, async ({ workspaceId, command, workingDirectory, port }) => {
20
+ try {
21
+ const result = await startDevServer(workspaces, processManager, { workspaceId, command, workingDirectory, port }, getRequestContext()?.ownerClientId);
22
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
23
+ }
24
+ catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ return { content: [{ type: "text", text: `start_dev_server failed: ${message}` }], isError: true };
27
+ }
28
+ });
29
+ registerAppTool(server, "capture_page_screenshot", {
30
+ title: "Capture page screenshot",
31
+ description: "Screenshot a local or remote web page using Playwright. Saves to workspace and returns as MCP image content. Blocks unsafe schemes and SSRF addresses.",
32
+ inputSchema: {
33
+ workspaceId: WORKSPACE_ID_SCHEMA,
34
+ url: z.string().describe("Page URL (http/https only). Local dev URLs like localhost:3000 are allowed."),
35
+ outputPath: z.string().describe("Workspace-relative path to save the screenshot PNG."),
36
+ fullPage: z.boolean().optional().describe("Capture full scrollable page (default false)."),
37
+ viewportWidth: z.number().int().optional().describe("Viewport width in pixels (default 1280, max 3840)."),
38
+ viewportHeight: z.number().int().optional().describe("Viewport height in pixels (default 800, max 2160)."),
39
+ waitUntil: z.enum(["load", "domcontentloaded", "networkidle"]).optional().describe("Page load event to wait for."),
40
+ delayMs: z.number().int().optional().describe("Additional delay in ms after load (max 5000)."),
41
+ },
42
+ ...toolWidgetDescriptorMeta(config, "write"), annotations: WEB_WRITE_ANNOTATIONS,
43
+ }, ({ workspaceId, url, outputPath, fullPage, viewportWidth, viewportHeight, waitUntil, delayMs }) => capturePageScreenshot(workspaces, { workspaceId, url, outputPath, fullPage, viewportWidth, viewportHeight, waitUntil, delayMs }));
44
+ registerAppTool(server, "inspect_page", {
45
+ title: "Inspect page",
46
+ description: "Inspect DOM structure, headings, buttons, links, and console errors of a web page using Playwright.",
47
+ inputSchema: {
48
+ workspaceId: WORKSPACE_ID_SCHEMA,
49
+ url: z.string().describe("Page URL to inspect."),
50
+ includeAccessibilityTree: z.boolean().optional().describe("Include accessibility tree."),
51
+ includeComputedStyles: z.boolean().optional().describe("Include key computed styles."),
52
+ maxElements: z.number().int().optional().describe("Max elements per category (default 20)."),
53
+ },
54
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
55
+ }, ({ workspaceId, url, includeAccessibilityTree, includeComputedStyles, maxElements }) => inspectPage(workspaces, { workspaceId, url, includeAccessibilityTree, includeComputedStyles, maxElements }));
56
+ registerAppTool(server, "test_responsive_page", {
57
+ title: "Test responsive page",
58
+ description: "Capture the same web page across 1–6 bounded viewports using Playwright. Saves PNGs inside the workspace and returns each screenshot for visual comparison.",
59
+ inputSchema: {
60
+ workspaceId: WORKSPACE_ID_SCHEMA,
61
+ url: z.string().describe("Page URL to test."),
62
+ outputDirectory: z.string().describe("Workspace-relative directory for viewport screenshots."),
63
+ viewports: z.array(z.object({ name: z.string(), width: z.number().int(), height: z.number().int() })).max(6).optional().describe("Optional viewport set. Defaults to mobile, tablet, and desktop."),
64
+ fullPage: z.boolean().optional().describe("Capture the full scrollable page (default true)."),
65
+ },
66
+ ...toolWidgetDescriptorMeta(config, "write"), annotations: WEB_WRITE_ANNOTATIONS,
67
+ }, ({ workspaceId, url, outputDirectory, viewports, fullPage }) => testResponsivePage(workspaces, { workspaceId, url, outputDirectory, viewports, fullPage }));
68
+ const sessionIdSchema = z.string().describe("Browser session id from browser_open.");
69
+ const selectorSchema = z.string().describe("CSS selector, text=, or Playwright locator string.");
70
+ registerAppTool(server, "browser_open", {
71
+ title: "Open browser session",
72
+ description: "Open a persistent Playwright Chromium session for interactive automation. Returns sessionId for subsequent browser_* tools. Max 4 concurrent sessions; idle sessions expire after 15 minutes.",
73
+ inputSchema: {
74
+ workspaceId: WORKSPACE_ID_SCHEMA,
75
+ url: z.string().optional().describe("Optional initial page URL (http/https)."),
76
+ viewportWidth: z.number().int().optional().describe("Viewport width (default 1280, max 3840)."),
77
+ viewportHeight: z.number().int().optional().describe("Viewport height (default 800, max 2160)."),
78
+ userAgent: z.string().optional().describe("Optional custom user agent."),
79
+ },
80
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
81
+ }, ({ workspaceId, url, viewportWidth, viewportHeight, userAgent }) => browserOpen(workspaces, { workspaceId, url, viewportWidth, viewportHeight, userAgent }));
82
+ registerAppTool(server, "browser_close", {
83
+ title: "Close browser session",
84
+ description: "Close a Playwright browser session and free capacity.",
85
+ inputSchema: { sessionId: sessionIdSchema },
86
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
87
+ }, ({ sessionId }) => browserClose({ sessionId }));
88
+ registerAppTool(server, "browser_list_sessions", {
89
+ title: "List browser sessions",
90
+ description: "List active Playwright browser sessions, optionally filtered by workspace.",
91
+ inputSchema: { workspaceId: WORKSPACE_ID_SCHEMA.optional() },
92
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
93
+ }, ({ workspaceId }) => browserListSessions({ workspaceId }));
94
+ registerAppTool(server, "browser_navigate", {
95
+ title: "Browser navigate",
96
+ description: "Navigate an open browser session to a URL with SSRF protection.",
97
+ inputSchema: {
98
+ sessionId: sessionIdSchema,
99
+ url: z.string().describe("Target page URL (http/https)."),
100
+ waitUntil: z.enum(["load", "domcontentloaded", "networkidle"]).optional(),
101
+ },
102
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
103
+ }, ({ sessionId, url, waitUntil }) => browserNavigate({ sessionId, url, waitUntil }));
104
+ registerAppTool(server, "browser_reload", {
105
+ title: "Browser reload",
106
+ description: "Reload the current page in a browser session.",
107
+ inputSchema: { sessionId: sessionIdSchema },
108
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
109
+ }, ({ sessionId }) => browserReload({ sessionId }));
110
+ registerAppTool(server, "browser_go_back", {
111
+ title: "Browser go back",
112
+ description: "Navigate back in browser history.",
113
+ inputSchema: { sessionId: sessionIdSchema },
114
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
115
+ }, ({ sessionId }) => browserGoBack({ sessionId }));
116
+ registerAppTool(server, "browser_go_forward", {
117
+ title: "Browser go forward",
118
+ description: "Navigate forward in browser history.",
119
+ inputSchema: { sessionId: sessionIdSchema },
120
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
121
+ }, ({ sessionId }) => browserGoForward({ sessionId }));
122
+ registerAppTool(server, "browser_snapshot", {
123
+ title: "Browser snapshot",
124
+ description: "Capture a structured page snapshot: headings, buttons, links, inputs, and optional accessibility tree.",
125
+ inputSchema: {
126
+ sessionId: sessionIdSchema,
127
+ interestingOnly: z.boolean().optional().describe("Accessibility snapshot interesting-only mode (default true)."),
128
+ maxChars: z.number().int().optional().describe("Truncate response text length."),
129
+ },
130
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
131
+ }, ({ sessionId, interestingOnly, maxChars }) => browserSnapshot({ sessionId, interestingOnly, maxChars }));
132
+ registerAppTool(server, "browser_click", {
133
+ title: "Browser click",
134
+ description: "Click an element in an open browser session.",
135
+ inputSchema: {
136
+ sessionId: sessionIdSchema,
137
+ selector: selectorSchema,
138
+ button: z.enum(["left", "right", "middle"]).optional(),
139
+ clickCount: z.number().int().optional(),
140
+ timeoutMs: z.number().int().optional(),
141
+ },
142
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
143
+ }, ({ sessionId, selector, button, clickCount, timeoutMs }) => browserClick({ sessionId, selector, button, clickCount, timeoutMs }));
144
+ registerAppTool(server, "browser_type", {
145
+ title: "Browser type",
146
+ description: "Type or fill text into an input/textarea in an open browser session.",
147
+ inputSchema: {
148
+ sessionId: sessionIdSchema,
149
+ selector: selectorSchema,
150
+ text: z.string().describe("Text to type or fill."),
151
+ clear: z.boolean().optional().describe("Clear existing value first (default true)."),
152
+ delayMs: z.number().int().optional().describe("Per-key delay when clear=false."),
153
+ timeoutMs: z.number().int().optional(),
154
+ },
155
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
156
+ }, ({ sessionId, selector, text, clear, delayMs, timeoutMs }) => browserType({ sessionId, selector, text, clear, delayMs, timeoutMs }));
157
+ registerAppTool(server, "browser_select_option", {
158
+ title: "Browser select option",
159
+ description: "Select one or more options in a <select> element.",
160
+ inputSchema: {
161
+ sessionId: sessionIdSchema,
162
+ selector: selectorSchema,
163
+ values: z.union([z.string(), z.array(z.string())]).describe("Option value(s) to select."),
164
+ timeoutMs: z.number().int().optional(),
165
+ },
166
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
167
+ }, ({ sessionId, selector, values, timeoutMs }) => browserSelectOption({ sessionId, selector, values, timeoutMs }));
168
+ registerAppTool(server, "browser_hover", {
169
+ title: "Browser hover",
170
+ description: "Hover over an element in an open browser session.",
171
+ inputSchema: {
172
+ sessionId: sessionIdSchema,
173
+ selector: selectorSchema,
174
+ timeoutMs: z.number().int().optional(),
175
+ },
176
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
177
+ }, ({ sessionId, selector, timeoutMs }) => browserHover({ sessionId, selector, timeoutMs }));
178
+ registerAppTool(server, "browser_press_key", {
179
+ title: "Browser press key",
180
+ description: "Press a keyboard key, optionally focused on a selector.",
181
+ inputSchema: {
182
+ sessionId: sessionIdSchema,
183
+ key: z.string().describe("Key name, e.g. Enter, Tab, Escape, ArrowDown."),
184
+ selector: z.string().optional().describe("Optional element to focus before keypress."),
185
+ timeoutMs: z.number().int().optional(),
186
+ },
187
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
188
+ }, ({ sessionId, key, selector, timeoutMs }) => browserPressKey({ sessionId, key, selector, timeoutMs }));
189
+ registerAppTool(server, "browser_wait_for", {
190
+ title: "Browser wait",
191
+ description: "Wait for a selector, URL, load state, or a short timeout.",
192
+ inputSchema: {
193
+ sessionId: sessionIdSchema,
194
+ selector: z.string().optional(),
195
+ url: z.string().optional().describe("URL substring or pattern to wait for."),
196
+ loadState: z.enum(["load", "domcontentloaded", "networkidle"]).optional(),
197
+ state: z.enum(["attached", "detached", "visible", "hidden"]).optional(),
198
+ timeoutMs: z.number().int().optional(),
199
+ },
200
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
201
+ }, ({ sessionId, selector, url, loadState, state, timeoutMs }) => browserWaitFor({ sessionId, selector, url, loadState, state, timeoutMs }));
202
+ registerAppTool(server, "browser_get_text", {
203
+ title: "Browser get text",
204
+ description: "Read textContent of an element.",
205
+ inputSchema: {
206
+ sessionId: sessionIdSchema,
207
+ selector: selectorSchema,
208
+ timeoutMs: z.number().int().optional(),
209
+ },
210
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
211
+ }, ({ sessionId, selector, timeoutMs }) => browserGetText({ sessionId, selector, timeoutMs }));
212
+ registerAppTool(server, "browser_get_attribute", {
213
+ title: "Browser get attribute",
214
+ description: "Read an element attribute value.",
215
+ inputSchema: {
216
+ sessionId: sessionIdSchema,
217
+ selector: selectorSchema,
218
+ name: z.string().describe("Attribute name, e.g. href, value, aria-label."),
219
+ timeoutMs: z.number().int().optional(),
220
+ },
221
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
222
+ }, ({ sessionId, selector, name, timeoutMs }) => browserGetAttribute({ sessionId, selector, name, timeoutMs }));
223
+ registerAppTool(server, "browser_is_visible", {
224
+ title: "Browser is visible",
225
+ description: "Check whether an element is visible.",
226
+ inputSchema: {
227
+ sessionId: sessionIdSchema,
228
+ selector: selectorSchema,
229
+ timeoutMs: z.number().int().optional(),
230
+ },
231
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
232
+ }, ({ sessionId, selector, timeoutMs }) => browserIsVisible({ sessionId, selector, timeoutMs }));
233
+ registerAppTool(server, "browser_scroll", {
234
+ title: "Browser scroll",
235
+ description: "Scroll an element into view, or wheel-scroll the page.",
236
+ inputSchema: {
237
+ sessionId: sessionIdSchema,
238
+ selector: z.string().optional().describe("If set, scroll this element into view."),
239
+ deltaX: z.number().optional(),
240
+ deltaY: z.number().optional().describe("Wheel delta Y when no selector (default 600)."),
241
+ },
242
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
243
+ }, ({ sessionId, selector, deltaX, deltaY }) => browserScroll({ sessionId, selector, deltaX, deltaY }));
244
+ registerAppTool(server, "browser_console", {
245
+ title: "Browser console",
246
+ description: "Read console messages captured by the browser session.",
247
+ inputSchema: {
248
+ sessionId: sessionIdSchema,
249
+ clear: z.boolean().optional().describe("Clear stored console logs after reading."),
250
+ types: z.array(z.string()).optional().describe("Filter by console types, e.g. error, warning."),
251
+ },
252
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
253
+ }, ({ sessionId, clear, types }) => browserConsole({ sessionId, clear, types }));
254
+ registerAppTool(server, "browser_network", {
255
+ title: "Browser network",
256
+ description: "Read network requests/responses captured by the browser session, including policy-blocked URLs.",
257
+ inputSchema: {
258
+ sessionId: sessionIdSchema,
259
+ clear: z.boolean().optional().describe("Clear stored network entries after reading."),
260
+ onlyFailed: z.boolean().optional().describe("Only failed or HTTP 4xx/5xx requests."),
261
+ },
262
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
263
+ }, ({ sessionId, clear, onlyFailed }) => browserNetwork({ sessionId, clear, onlyFailed }));
264
+ registerAppTool(server, "browser_evaluate", {
265
+ title: "Browser evaluate",
266
+ description: "Evaluate a short JavaScript expression in the page context. Network/module side effects are blocked.",
267
+ inputSchema: {
268
+ sessionId: sessionIdSchema,
269
+ expression: z.string().describe("Expression to evaluate, e.g. document.title or location.href."),
270
+ },
271
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: WEB_READ_ANNOTATIONS,
272
+ }, ({ sessionId, expression }) => browserEvaluate({ sessionId, expression }));
273
+ registerAppTool(server, "browser_screenshot", {
274
+ title: "Browser screenshot",
275
+ description: "Screenshot the current page of an open browser session into the workspace artifact directory.",
276
+ inputSchema: {
277
+ sessionId: sessionIdSchema,
278
+ outputPath: z.string().describe("Workspace-relative PNG path."),
279
+ fullPage: z.boolean().optional(),
280
+ },
281
+ ...toolWidgetDescriptorMeta(config, "write"), annotations: WEB_WRITE_ANNOTATIONS,
282
+ }, ({ sessionId, outputPath, fullPage }) => browserScreenshot(workspaces, { sessionId, outputPath, fullPage }));
283
+ registerAppTool(server, "inspect_image", {
284
+ title: "Inspect image",
285
+ description: "Return format, dimensions, file size, alpha capability, and pixel-art likelihood for a local image. Does not resize or recompress.",
286
+ inputSchema: { workspaceId: WORKSPACE_ID_SCHEMA, path: z.string().describe("Workspace-relative image path.") },
287
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: READ_ONLY_ANNOTATIONS,
288
+ }, ({ workspaceId, path }) => inspectImage(workspaces, { workspaceId, path }));
289
+ registerAppTool(server, "compare_images", {
290
+ title: "Compare images",
291
+ description: "Pixel-level comparison of two workspace PNG images. Returns exact and tolerance-based match percentages, changed pixel count, and an optional real diff PNG.",
292
+ inputSchema: {
293
+ workspaceId: WORKSPACE_ID_SCHEMA,
294
+ referencePath: z.string().describe("Reference image path (workspace-relative)."),
295
+ candidatePath: z.string().describe("Candidate image path to compare (workspace-relative)."),
296
+ diffOutputPath: z.string().optional().describe("Workspace-relative path to save the diff image."),
297
+ threshold: z.number().optional().describe("Per-channel tolerance (0–255, default 0)."),
298
+ ignoreTransparentPixels: z.boolean().optional().describe("Skip fully transparent pixels in comparison."),
299
+ },
300
+ ...toolWidgetDescriptorMeta(config, "write"), annotations: MUTATING_ANNOTATIONS,
301
+ }, ({ workspaceId, referencePath, candidatePath, diffOutputPath, threshold, ignoreTransparentPixels }) => compareImages(workspaces, { workspaceId, referencePath, candidatePath, diffOutputPath, threshold, ignoreTransparentPixels }));
302
+ registerAppTool(server, "inspect_sprite", {
303
+ title: "Inspect sprite",
304
+ description: "Analyze image dimensions against an expected sprite-cell size and report the resulting grid and divisibility.",
305
+ inputSchema: {
306
+ workspaceId: WORKSPACE_ID_SCHEMA,
307
+ path: z.string().describe("Workspace-relative image path."),
308
+ expectedCellWidth: z.number().int().optional().describe("Expected cell width for grid detection."),
309
+ expectedCellHeight: z.number().int().optional().describe("Expected cell height for grid detection."),
310
+ },
311
+ ...toolWidgetDescriptorMeta(config, "read"), annotations: READ_ONLY_ANNOTATIONS,
312
+ }, ({ workspaceId, path, expectedCellWidth, expectedCellHeight }) => inspectSprite(workspaces, { workspaceId, path, expectedCellWidth, expectedCellHeight }));
313
+ registerAppTool(server, "split_sprite_sheet", {
314
+ title: "Split sprite sheet",
315
+ description: "Split a PNG sprite sheet into real cropped frame PNGs inside the managed artifact directory. Rejects unsafe filenames and does not overwrite existing files.",
316
+ inputSchema: {
317
+ workspaceId: WORKSPACE_ID_SCHEMA,
318
+ path: z.string().describe("Workspace-relative sprite sheet path."),
319
+ columns: z.number().int().describe("Number of columns."),
320
+ rows: z.number().int().describe("Number of rows."),
321
+ outputDirectory: z.string().describe("Workspace-relative output directory."),
322
+ namingPattern: z.string().optional().describe("Frame filename pattern with {col} and {row} placeholders."),
323
+ },
324
+ ...toolWidgetDescriptorMeta(config, "write"), annotations: MUTATING_ANNOTATIONS,
325
+ }, ({ workspaceId, path, columns, rows, outputDirectory, namingPattern }) => splitSpriteSheet(workspaces, { workspaceId, path, columns, rows, outputDirectory, namingPattern }));
326
+ }
@@ -0,0 +1,130 @@
1
+ import * as z from "zod/v4";
2
+ import { logEvent } from "../../logger.js";
3
+ import { getRequestContext, requireRequestContext } from "../../request-context.js";
4
+ import { formatPathForPrompt } from "../../skills.js";
5
+ import { formatAgentsPath } from "../../workspaces.js";
6
+ import { registerAppTool } from "../mcp-tool-registrar.js";
7
+ import { MUTATING_ANNOTATIONS, PROCESS_ANNOTATIONS, toolWidgetDescriptorMeta } from "../tool-registration-shared.js";
8
+ const workspaceSkillOutputSchema = z.object({
9
+ name: z.string(),
10
+ description: z.string(),
11
+ path: z.string(),
12
+ });
13
+ const workspaceAgentsFileOutputSchema = z.object({ path: z.string(), content: z.string() });
14
+ const workspaceAvailableAgentsFileOutputSchema = z.object({ path: z.string() });
15
+ export function registerWorkspaceLifecycleTools(server, config, workspaces, reviewCheckpoints, processManager, roomRegistry, sessionRegistry, workspaceChanges, logToolCall) {
16
+ registerAppTool(server, "open_workspace", {
17
+ title: "Open workspace",
18
+ description: "Open a local project directory as a coding workspace. Call this once per project folder or worktree before reading, editing, searching, writing, showing changes, or running commands. Reuse the returned workspaceId for later calls in the same folder; do not call open_workspace again unless switching folders/worktrees, changing checkout/worktree mode, the workspaceId is rejected as unknown, or the user explicitly asks to reopen. By default this opens the actual checkout; set mode=\"worktree\" when the user asks for an isolated or parallel coding session. Returns a workspaceId, loaded root project instructions, and nested instruction file paths the model should read before working in those directories.",
19
+ inputSchema: {
20
+ path: z.string().describe("Absolute path, or a leading-tilde home path such as ~/project, to a local project directory inside an allowed root."),
21
+ mode: z.enum(["checkout", "worktree"]).optional().describe("Defaults to checkout. Use checkout to work in the actual directory. Use worktree to create an isolated managed Git worktree for parallel work."),
22
+ baseRef: z.string().optional().describe("Git ref to base a worktree on. Only used with mode=\"worktree\". Defaults to HEAD."),
23
+ },
24
+ outputSchema: {
25
+ workspaceId: z.string(),
26
+ root: z.string(),
27
+ mode: z.enum(["checkout", "worktree"]),
28
+ sourceRoot: z.string().optional(),
29
+ worktree: z.object({
30
+ path: z.string(), baseRef: z.string(), baseSha: z.string(), dirtySource: z.boolean(),
31
+ detached: z.boolean(), managed: z.boolean(),
32
+ }).optional(),
33
+ agentsFiles: z.array(workspaceAgentsFileOutputSchema),
34
+ availableAgentsFiles: z.array(workspaceAvailableAgentsFileOutputSchema),
35
+ skills: z.array(workspaceSkillOutputSchema),
36
+ skillDiagnostics: z.array(z.unknown()),
37
+ instruction: z.string(),
38
+ },
39
+ ...toolWidgetDescriptorMeta(config, "workspace"),
40
+ annotations: PROCESS_ANNOTATIONS,
41
+ }, async ({ path, mode, baseRef }) => {
42
+ const startedAt = performance.now();
43
+ const { workspace, agentsFiles, availableAgentsFiles } = await workspaces.openWorkspace({ path, mode, baseRef });
44
+ workspaceChanges.activateWorkspace(workspace.id, workspace.root);
45
+ const ctx = getRequestContext();
46
+ if (ctx) {
47
+ const room = roomRegistry.create(ctx.ownerClientId, workspace.id);
48
+ sessionRegistry.bindWorkspace(ctx.sessionId, room.roomId, workspace.id);
49
+ }
50
+ if (config.widgets === "changes") {
51
+ void reviewCheckpoints.initializeWorkspace({ workspaceId: workspace.id, root: workspace.root }).catch((error) => {
52
+ logEvent(config.logging, "warn", "review_checkpoint_init_failed", {
53
+ workspaceId: workspace.id,
54
+ error: error instanceof Error ? error.message : String(error),
55
+ });
56
+ });
57
+ }
58
+ const visibleSkills = workspace.skills
59
+ .filter((skill) => !skill.disableModelInvocation)
60
+ .map((skill) => ({ name: skill.name, description: skill.description, path: formatPathForPrompt(skill.filePath) }));
61
+ const loadedAgentsFiles = agentsFiles.map((file) => ({
62
+ path: formatAgentsPath(file.path, workspace.root), content: file.content,
63
+ }));
64
+ const availableAgentsFileOutputs = availableAgentsFiles.map((file) => ({ path: formatAgentsPath(file.path, workspace.root) }));
65
+ const instruction = config.skillsEnabled
66
+ ? "Use this workspaceId in all subsequent tool calls for this project. Do not call open_workspace again for this same folder unless this workspaceId stops working, the user asks to reopen, or you switch to a different folder/worktree. Follow loaded agentsFiles instructions. Before working under a path listed in availableAgentsFiles, read that instruction file. When a task matches an available skill in skills, read its path before proceeding."
67
+ : "Use this workspaceId in all subsequent tool calls for this project. Do not call open_workspace again for this same folder unless this workspaceId stops working, the user asks to reopen, or you switch to a different folder/worktree. Follow loaded agentsFiles instructions. Before working under a path listed in availableAgentsFiles, read that instruction file.";
68
+ const content = [{
69
+ type: "text",
70
+ text: [
71
+ `Opened workspace ${workspace.id}`,
72
+ `Root: ${workspace.root}`,
73
+ `Mode: ${workspace.mode}`,
74
+ loadedAgentsFiles.length > 0 ? `Loaded project instructions: ${loadedAgentsFiles.map((file) => file.path).join(", ")}` : undefined,
75
+ availableAgentsFileOutputs.length > 0 ? `Available nested instructions: ${availableAgentsFileOutputs.map((file) => file.path).join(", ")}` : undefined,
76
+ visibleSkills.length > 0 ? `Available skills: ${visibleSkills.map((skill) => skill.name).join(", ")}` : undefined,
77
+ instruction,
78
+ ].filter(Boolean).join("\n"),
79
+ }];
80
+ logToolCall(config, {
81
+ tool: "open_workspace", workspaceId: workspace.id, path: workspace.root, success: true,
82
+ durationMs: Math.round(performance.now() - startedAt),
83
+ });
84
+ return {
85
+ content,
86
+ _meta: {
87
+ tool: "open_workspace",
88
+ card: {
89
+ workspaceId: workspace.id, root: workspace.root, path: workspace.root,
90
+ summary: {
91
+ agentsFiles: loadedAgentsFiles.length,
92
+ availableAgentsFiles: availableAgentsFileOutputs.length,
93
+ skills: visibleSkills.length,
94
+ skillDiagnostics: workspace.skillDiagnostics.length,
95
+ },
96
+ },
97
+ },
98
+ structuredContent: {
99
+ workspaceId: workspace.id,
100
+ root: workspace.root,
101
+ mode: workspace.mode,
102
+ sourceRoot: workspace.sourceRoot,
103
+ worktree: workspace.worktree,
104
+ agentsFiles: loadedAgentsFiles,
105
+ availableAgentsFiles: availableAgentsFileOutputs,
106
+ skills: visibleSkills,
107
+ skillDiagnostics: workspace.skillDiagnostics,
108
+ instruction,
109
+ },
110
+ };
111
+ });
112
+ registerAppTool(server, "close_workspace", {
113
+ title: "Close workspace",
114
+ description: "Explicitly close an open workspace, stopping its processes and releasing resources. Use this when done working in a workspace to ensure proper cleanup. The workspaceId will no longer be valid after this call.",
115
+ inputSchema: { workspaceId: z.string().describe("Workspace identifier returned by open_workspace.") },
116
+ ...toolWidgetDescriptorMeta(config, "workspace"),
117
+ annotations: MUTATING_ANNOTATIONS,
118
+ }, async ({ workspaceId }) => {
119
+ const startedAt = performance.now();
120
+ const ctx = requireRequestContext();
121
+ roomRegistry.closeOwned(ctx.ownerClientId, workspaceId);
122
+ const stopped = await processManager.stopAllProcessesForWorkspace(workspaceId);
123
+ workspaces.markClosed(workspaceId);
124
+ logToolCall(config, {
125
+ tool: "close_workspace", workspaceId, success: true,
126
+ durationMs: Math.round(performance.now() - startedAt),
127
+ });
128
+ return { content: [{ type: "text", text: `Workspace ${workspaceId} closed. ${stopped} processes stopped.` }] };
129
+ });
130
+ }
@@ -0,0 +1,97 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { access } from "node:fs/promises";
3
+ import { fileURLToPath } from "node:url";
4
+ const WORKSPACE_APP_MANIFEST_ENTRY = "workspace-app.html";
5
+ export function workspaceAppAssetInfo(config) {
6
+ const baseUrl = assetBaseUrl(config);
7
+ const entry = getWorkspaceAppManifestEntry();
8
+ return {
9
+ resourceBaseUrl: baseUrl,
10
+ scriptUrl: assetUrl(baseUrl, entry.file),
11
+ stylesheetUrls: (entry.css ?? []).map((stylesheet) => assetUrl(baseUrl, stylesheet)),
12
+ };
13
+ }
14
+ export function workspaceAppHtml(config, baseUrlOverride) {
15
+ const baseUrl = baseUrlOverride?.replace(/\/+$/, "") ?? assetBaseUrl(config);
16
+ const entry = getWorkspaceAppManifestEntry();
17
+ const stylesheets = (entry.css ?? [])
18
+ .map((stylesheet) => ` <link rel="stylesheet" crossorigin href="${assetUrl(baseUrl, stylesheet)}" />`)
19
+ .join("\n");
20
+ return `<!doctype html>
21
+ <html lang="en">
22
+ <head>
23
+ <meta charset="UTF-8" />
24
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
25
+ <title>Auvrynt Workspace</title>
26
+ <script type="module" crossorigin src="${assetUrl(baseUrl, entry.file)}"></script>
27
+ ${stylesheets}
28
+ </head>
29
+ <body>
30
+ <main id="app" class="shell">
31
+ <section class="empty loading" role="status" aria-live="polite">
32
+ <span class="empty-indicator" aria-hidden="true"></span>
33
+ <span class="empty-copy">
34
+ <span class="empty-title">Connecting to Auvrynt</span>
35
+ <span class="empty-detail">Establishing a secure link with the host.</span>
36
+ </span>
37
+ </section>
38
+ </main>
39
+ </body>
40
+ </html>`;
41
+ }
42
+ export function appCsp(config) {
43
+ const publicBaseUrl = config.publicBaseUrl.replace(/\/+$/, "");
44
+ return {
45
+ resourceDomains: [publicBaseUrl],
46
+ connectDomains: [publicBaseUrl],
47
+ };
48
+ }
49
+ export function uiBuildDirectory() {
50
+ return fileURLToPath(new URL("../../dist/ui", import.meta.url));
51
+ }
52
+ export function brandAssetDirectory() {
53
+ return fileURLToPath(new URL("../../docs/assets", import.meta.url));
54
+ }
55
+ export function setAssetHeaders(res) {
56
+ res.setHeader("Access-Control-Allow-Origin", "*");
57
+ res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
58
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Range");
59
+ res.setHeader("Cross-Origin-Resource-Policy", "cross-origin");
60
+ }
61
+ export async function assertWorkspaceAppAssets() {
62
+ const entry = getWorkspaceAppManifestEntry();
63
+ const candidates = [entry.file, ...(entry.css ?? [])].map((assetPath) => new URL(`../../dist/ui/${assetPath}`, import.meta.url));
64
+ for (const candidate of candidates)
65
+ await access(candidate);
66
+ }
67
+ export function packageVersion() {
68
+ try {
69
+ const packageJson = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
70
+ return typeof packageJson.version === "string"
71
+ ? packageJson.version
72
+ : "unknown";
73
+ }
74
+ catch {
75
+ return "unknown";
76
+ }
77
+ }
78
+ function assetBaseUrl(config) {
79
+ return `${config.publicBaseUrl.replace(/\/+$/, "")}/mcp-app-assets`;
80
+ }
81
+ function uiManifestUrl() {
82
+ return new URL("../../dist/ui/.vite/manifest.json", import.meta.url);
83
+ }
84
+ function readWorkspaceAppManifest() {
85
+ return JSON.parse(readFileSync(uiManifestUrl(), "utf8"));
86
+ }
87
+ function getWorkspaceAppManifestEntry() {
88
+ const manifest = readWorkspaceAppManifest();
89
+ const entry = manifest[WORKSPACE_APP_MANIFEST_ENTRY];
90
+ if (!entry?.file) {
91
+ throw new Error(`Missing ${WORKSPACE_APP_MANIFEST_ENTRY} in UI manifest.`);
92
+ }
93
+ return entry;
94
+ }
95
+ function assetUrl(baseUrl, assetPath) {
96
+ return `${baseUrl}/${assetPath.replace(/^\/+/, "")}`;
97
+ }
@@ -0,0 +1,92 @@
1
+ export function createWorkspaceChangeTracker(now = () => new Date()) {
2
+ const workspaces = new Map();
3
+ let activeWorkspaceKey;
4
+ const ensureWorkspace = (workspaceId, workspaceRoot) => {
5
+ const key = workspaceKey(workspaceRoot);
6
+ const existing = workspaces.get(key);
7
+ if (existing) {
8
+ existing.workspaceId = workspaceId;
9
+ existing.workspaceRoot = workspaceRoot;
10
+ return [key, existing];
11
+ }
12
+ const timestamp = now().toISOString();
13
+ const activity = {
14
+ workspaceId,
15
+ workspaceRoot,
16
+ startedAt: timestamp,
17
+ updatedAt: timestamp,
18
+ createdPaths: new Set(),
19
+ modifiedPaths: new Set(),
20
+ deletedPaths: new Set(),
21
+ additions: 0,
22
+ removals: 0,
23
+ };
24
+ workspaces.set(key, activity);
25
+ return [key, activity];
26
+ };
27
+ return {
28
+ activateWorkspace(workspaceId, workspaceRoot) {
29
+ const [key] = ensureWorkspace(workspaceId, workspaceRoot);
30
+ activeWorkspaceKey = key;
31
+ },
32
+ recordMutation(mutation) {
33
+ const [key, activity] = ensureWorkspace(mutation.workspaceId, mutation.workspaceRoot);
34
+ const path = normalizePath(mutation.path);
35
+ activeWorkspaceKey = key;
36
+ activity.updatedAt = now().toISOString();
37
+ activity.additions += normalizeCount(mutation.additions);
38
+ activity.removals += normalizeCount(mutation.removals);
39
+ if (mutation.kind === "created")
40
+ activity.createdPaths.add(path);
41
+ if (mutation.kind === "modified")
42
+ activity.modifiedPaths.add(path);
43
+ if (mutation.kind === "deleted")
44
+ activity.deletedPaths.add(path);
45
+ },
46
+ snapshot() {
47
+ const activity = activeWorkspaceKey ? workspaces.get(activeWorkspaceKey) : undefined;
48
+ if (!activity)
49
+ return emptyWorkspaceAnalytics(now().toISOString());
50
+ return {
51
+ workspaceId: activity.workspaceId,
52
+ workspaceRoot: activity.workspaceRoot,
53
+ filesCreated: activity.createdPaths.size,
54
+ filesDeleted: activity.deletedPaths.size,
55
+ filesModified: activity.modifiedPaths.size,
56
+ additions: activity.additions,
57
+ removals: activity.removals,
58
+ startedAt: activity.startedAt,
59
+ sampledAt: activity.updatedAt,
60
+ };
61
+ },
62
+ };
63
+ }
64
+ export function countTextLines(content) {
65
+ if (content.length === 0)
66
+ return 0;
67
+ const lines = content.replace(/\r\n/g, "\n").split("\n");
68
+ if (lines.at(-1) === "")
69
+ lines.pop();
70
+ return lines.length;
71
+ }
72
+ function normalizeCount(value) {
73
+ return Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
74
+ }
75
+ function normalizePath(path) {
76
+ return path.replace(/\\/g, "/").replace(/^\.\//, "");
77
+ }
78
+ function workspaceKey(workspaceRoot) {
79
+ const normalized = workspaceRoot.replace(/\\/g, "/").replace(/\/+$/, "");
80
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
81
+ }
82
+ function emptyWorkspaceAnalytics(timestamp) {
83
+ return {
84
+ filesCreated: 0,
85
+ filesDeleted: 0,
86
+ filesModified: 0,
87
+ additions: 0,
88
+ removals: 0,
89
+ startedAt: timestamp,
90
+ sampledAt: timestamp,
91
+ };
92
+ }