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,594 @@
1
+ local BRIDGE_VERSION = "1.2.0"
2
+ local live_commands = nil
3
+ local POLL_INTERVAL = 0.10
4
+ local timer = nil
5
+ local bridge_root = nil
6
+ local requests_dir = nil
7
+ local responses_dir = nil
8
+ local auth_path = nil
9
+ local auth_token = nil
10
+
11
+ local function read_file(path)
12
+ local file = io.open(path, "rb")
13
+ if not file then return nil end
14
+ local value = file:read("*a")
15
+ file:close()
16
+ return value
17
+ end
18
+
19
+ local function write_file(path, value)
20
+ local file, err = io.open(path, "wb")
21
+ if not file then error(err or "Unable to open output file", 0) end
22
+ file:write(value)
23
+ file:flush()
24
+ file:close()
25
+ end
26
+
27
+ local function write_json_atomic(path, value)
28
+ local temporary = path .. ".tmp"
29
+ write_file(temporary, json.encode(value))
30
+ os.remove(path)
31
+ local ok, err = os.rename(temporary, path)
32
+ if not ok then
33
+ os.remove(temporary)
34
+ error(err or "Unable to publish bridge response", 0)
35
+ end
36
+ end
37
+
38
+ local function ensure_directories()
39
+ bridge_root = app.fs.joinPath(app.fs.userConfigPath, "auvrynt-bridge")
40
+ requests_dir = app.fs.joinPath(bridge_root, "requests")
41
+ responses_dir = app.fs.joinPath(bridge_root, "responses")
42
+ auth_path = app.fs.joinPath(bridge_root, "auth.json")
43
+ app.fs.makeAllDirectories(requests_dir)
44
+ app.fs.makeAllDirectories(responses_dir)
45
+ end
46
+
47
+ local function is_json_object(value)
48
+ local kind = type(value)
49
+ return kind == "table" or kind == "userdata"
50
+ end
51
+
52
+ local function refresh_auth_token()
53
+ local raw = read_file(auth_path)
54
+ if not raw then auth_token = nil return end
55
+ local ok, value = pcall(json.decode, raw)
56
+ auth_token = ok and is_json_object(value) and value.token or nil
57
+ end
58
+
59
+ local function sequence_length(value)
60
+ if value == nil then return nil end
61
+ local ok, count = pcall(function() return #value end)
62
+ return ok and count or nil
63
+ end
64
+
65
+ local function color_table(color)
66
+ if not color then return nil end
67
+ return { r=color.red, g=color.green, b=color.blue, a=color.alpha }
68
+ end
69
+
70
+ local function color_from_request(value, fallback)
71
+ -- NOTE: this JSON decoder represents decoded objects as either "table" or
72
+ -- "userdata" (see is_json_object below, used elsewhere for the same
73
+ -- reason). The previous type(value) ~= "table" check rejected the
74
+ -- userdata case, silently discarding every color sent by the MCP client
75
+ -- and falling back to fully-transparent black (or the untouched current
76
+ -- foreground), which is why live strokes/pixels/set_colors appeared to
77
+ -- draw nothing.
78
+ if not is_json_object(value) then return fallback or Color() end
79
+ return Color{
80
+ r=math.max(0, math.min(255, tonumber(value.r) or 0)),
81
+ g=math.max(0, math.min(255, tonumber(value.g) or 0)),
82
+ b=math.max(0, math.min(255, tonumber(value.b) or 0)),
83
+ a=math.max(0, math.min(255, tonumber(value.a) or 255)),
84
+ }
85
+ end
86
+
87
+ local function plain_properties(properties)
88
+ local result = {}
89
+ if not properties then return result end
90
+ for key, value in pairs(properties) do
91
+ local value_type = type(value)
92
+ if value_type == "string" or value_type == "number" or value_type == "boolean" then
93
+ result[tostring(key)] = value
94
+ else
95
+ result[tostring(key)] = tostring(value)
96
+ end
97
+ end
98
+ return result
99
+ end
100
+
101
+ local function flatten_layers(items, parent, result)
102
+ for _, layer in ipairs(items) do
103
+ table.insert(result, {
104
+ id=tostring(layer.id),
105
+ name=layer.name,
106
+ parent=parent,
107
+ isGroup=layer.isGroup,
108
+ isTilemap=layer.isTilemap,
109
+ isVisible=layer.isVisible,
110
+ isEditable=layer.isEditable,
111
+ opacity=layer.opacity,
112
+ blendMode=tostring(layer.blendMode),
113
+ celCount=#layer.cels,
114
+ data=layer.data,
115
+ properties=plain_properties(layer.properties),
116
+ })
117
+ if layer.isGroup then flatten_layers(layer.layers, layer.name, result) end
118
+ end
119
+ end
120
+
121
+ local function find_layer(items, name_or_id)
122
+ if name_or_id == nil then return nil end
123
+ for _, layer in ipairs(items) do
124
+ if layer.name == name_or_id or tostring(layer.id) == tostring(name_or_id) then return layer end
125
+ if layer.isGroup then
126
+ local nested = find_layer(layer.layers, name_or_id)
127
+ if nested then return nested end
128
+ end
129
+ end
130
+ return nil
131
+ end
132
+
133
+ local function find_sprite(request)
134
+ local target = request.documentId or request.filename
135
+ if target == nil then return app.activeSprite end
136
+ for _, sprite in ipairs(app.sprites) do
137
+ if tostring(sprite.id) == tostring(target) or sprite.filename == target then return sprite end
138
+ end
139
+ return nil
140
+ end
141
+
142
+ local function normalize_path(path)
143
+ if type(path) ~= "string" or path == "" then return nil end
144
+ return path:gsub("\\", "/"):lower()
145
+ end
146
+
147
+ local function find_open_sprite_by_path(path)
148
+ local normalized = normalize_path(path)
149
+ if not normalized then return nil end
150
+ for _, sprite in ipairs(app.sprites) do
151
+ if normalize_path(sprite.filename) == normalized then return sprite end
152
+ end
153
+ return nil
154
+ end
155
+
156
+ local function palette_rows(sprite)
157
+ local result = {}
158
+ if #sprite.palettes == 0 then return result end
159
+ local palette = sprite.palettes[1]
160
+ for index=0,#palette-1 do
161
+ local color = palette:getColor(index)
162
+ table.insert(result, {
163
+ index=index,
164
+ r=color.red,
165
+ g=color.green,
166
+ b=color.blue,
167
+ a=index == sprite.transparentColor and 0 or color.alpha,
168
+ })
169
+ end
170
+ return result
171
+ end
172
+
173
+ local function sprite_state(sprite)
174
+ if not sprite then return nil end
175
+ local layers = {}
176
+ flatten_layers(sprite.layers, nil, layers)
177
+ local frames = {}
178
+ for _, frame in ipairs(sprite.frames) do
179
+ table.insert(frames, { frame=frame.frameNumber, durationMs=math.floor(frame.duration*1000+0.5) })
180
+ end
181
+ local tags = {}
182
+ for _, tag in ipairs(sprite.tags) do
183
+ table.insert(tags, {
184
+ name=tag.name,
185
+ from=tag.fromFrame.frameNumber,
186
+ to=tag.toFrame.frameNumber,
187
+ direction=tostring(tag.aniDir),
188
+ repeats=tag.repeats,
189
+ data=tag.data,
190
+ properties=plain_properties(tag.properties),
191
+ })
192
+ end
193
+ local selection = sprite.selection
194
+ local selection_bounds = nil
195
+ if selection and not selection.isEmpty then
196
+ selection_bounds = {
197
+ x=selection.bounds.x,
198
+ y=selection.bounds.y,
199
+ width=selection.bounds.width,
200
+ height=selection.bounds.height,
201
+ }
202
+ end
203
+ local onionskin = app.preferences.document(sprite).onionskin
204
+ local editor = app.editor
205
+ local brush = app.activeBrush
206
+ return {
207
+ id=tostring(sprite.id),
208
+ filename=sprite.filename,
209
+ hasAssociatedFile=sprite.hasAssociatedFile,
210
+ isModified=sprite.isModified,
211
+ width=sprite.width,
212
+ height=sprite.height,
213
+ colorMode=tostring(sprite.colorMode),
214
+ colorSpace=sprite.colorSpace and sprite.colorSpace.name or nil,
215
+ transparentColor=sprite.transparentColor,
216
+ pixelRatio={ width=sprite.pixelRatio.width, height=sprite.pixelRatio.height },
217
+ grid={ x=sprite.gridBounds.x, y=sprite.gridBounds.y, width=sprite.gridBounds.width, height=sprite.gridBounds.height },
218
+ frameCount=#sprite.frames,
219
+ activeFrame=app.activeFrame and app.activeFrame.frameNumber or nil,
220
+ activeLayer=app.activeLayer and { id=tostring(app.activeLayer.id), name=app.activeLayer.name } or nil,
221
+ activeTool=app.activeTool and app.activeTool.id or nil,
222
+ activeBrush=brush and { type=tostring(brush.type), size=brush.size, angle=brush.angle } or nil,
223
+ foreground=color_table(app.fgColor),
224
+ background=color_table(app.bgColor),
225
+ editorZoom=editor and editor.zoom or nil,
226
+ selection=selection_bounds,
227
+ onionskin={
228
+ active=onionskin.active,
229
+ prevFrames=onionskin.prev_frames,
230
+ nextFrames=onionskin.next_frames,
231
+ opacityBase=onionskin.opacity_base,
232
+ opacityStep=onionskin.opacity_step,
233
+ loopTag=onionskin.loop_tag,
234
+ currentLayer=onionskin.current_layer,
235
+ type=tostring(onionskin.type),
236
+ position=tostring(onionskin.position),
237
+ },
238
+ layers=layers,
239
+ frames=frames,
240
+ tags=tags,
241
+ palette=palette_rows(sprite),
242
+ data=sprite.data,
243
+ properties=plain_properties(sprite.properties),
244
+ }
245
+ end
246
+
247
+ local function document_list()
248
+ local result = {}
249
+ for _, sprite in ipairs(app.sprites) do
250
+ table.insert(result, {
251
+ id=tostring(sprite.id),
252
+ filename=sprite.filename,
253
+ width=sprite.width,
254
+ height=sprite.height,
255
+ frames=#sprite.frames,
256
+ modified=sprite.isModified,
257
+ active=sprite == app.activeSprite,
258
+ })
259
+ end
260
+ return result
261
+ end
262
+
263
+ local function ensure_canvas_cel(sprite, layer, frame_number)
264
+ local cel = layer:cel(frame_number)
265
+ if cel == nil then
266
+ local image = Image(sprite.spec)
267
+ image:clear()
268
+ cel = sprite:newCel(layer, frame_number, image, Point(0, 0))
269
+ elseif cel.position.x ~= 0 or cel.position.y ~= 0 or cel.image.width ~= sprite.width or cel.image.height ~= sprite.height then
270
+ local image = Image(sprite.spec)
271
+ image:clear()
272
+ image:drawImage(cel.image, cel.position)
273
+ cel.image = image
274
+ cel.position = Point(0, 0)
275
+ end
276
+ return cel
277
+ end
278
+
279
+ local function rgba_pixel(sprite, color)
280
+ if sprite.colorMode == ColorMode.RGB then
281
+ return app.pixelColor.rgba(color.red, color.green, color.blue, color.alpha)
282
+ elseif sprite.colorMode == ColorMode.GRAY then
283
+ local gray = math.floor((color.red*299 + color.green*587 + color.blue*114)/1000)
284
+ return app.pixelColor.graya(gray, color.alpha)
285
+ else
286
+ local palette = sprite.palettes[1]
287
+ local best = 0
288
+ local distance = math.huge
289
+ for index=0,#palette-1 do
290
+ local candidate = palette:getColor(index)
291
+ local dr=candidate.red-color.red
292
+ local dg=candidate.green-color.green
293
+ local db=candidate.blue-color.blue
294
+ local da=(index == sprite.transparentColor and 0 or candidate.alpha)-color.alpha
295
+ local current=dr*dr+dg*dg+db*db+da*da
296
+ if current<distance then best=index distance=current end
297
+ end
298
+ return best
299
+ end
300
+ end
301
+
302
+ local function set_active_target(sprite, request)
303
+ app.activeSprite = sprite
304
+ if request.layer then
305
+ local layer = find_layer(sprite.layers, request.layer)
306
+ if not layer then error("Layer was not found", 0) end
307
+ app.activeLayer = layer
308
+ end
309
+ if request.frame then
310
+ local frame_number = math.floor(tonumber(request.frame) or 0)
311
+ if frame_number < 1 or frame_number > #sprite.frames then error("Frame is outside the sprite", 0) end
312
+ app.activeFrame = sprite.frames[frame_number]
313
+ end
314
+ end
315
+
316
+ local function capture_canvas(sprite, request)
317
+ local frame_number = math.floor(tonumber(request.frame) or (app.activeFrame and app.activeFrame.frameNumber) or 1)
318
+ if frame_number < 1 or frame_number > #sprite.frames then error("Frame is outside the sprite", 0) end
319
+ local output_path = request.outputPath
320
+ if type(output_path) ~= "string" or output_path == "" then error("outputPath is required", 0) end
321
+ local scale = math.max(1, math.min(32, math.floor(tonumber(request.scale) or 1)))
322
+ local render = Image(sprite.spec)
323
+ render:clear()
324
+ render:drawSprite(sprite, frame_number, Point(0, 0))
325
+ if scale == 1 then
326
+ if not render:saveAs(output_path) then error("Unable to save canvas capture", 0) end
327
+ else
328
+ local output = Image(sprite.width*scale, sprite.height*scale, ColorMode.RGB)
329
+ output:clear()
330
+ local palette = #sprite.palettes > 0 and sprite.palettes[1] or nil
331
+ for y=0,sprite.height-1 do
332
+ for x=0,sprite.width-1 do
333
+ local source_pixel = render:getPixel(x,y)
334
+ local color
335
+ if sprite.colorMode == ColorMode.RGB then
336
+ color = Color{
337
+ r=app.pixelColor.rgbaR(source_pixel),
338
+ g=app.pixelColor.rgbaG(source_pixel),
339
+ b=app.pixelColor.rgbaB(source_pixel),
340
+ a=app.pixelColor.rgbaA(source_pixel),
341
+ }
342
+ elseif sprite.colorMode == ColorMode.GRAY then
343
+ local gray=app.pixelColor.grayaV(source_pixel)
344
+ color=Color{r=gray,g=gray,b=gray,a=app.pixelColor.grayaA(source_pixel)}
345
+ else
346
+ local palette_color=palette:getColor(source_pixel)
347
+ color=Color{r=palette_color.red,g=palette_color.green,b=palette_color.blue,a=source_pixel==sprite.transparentColor and 0 or palette_color.alpha}
348
+ end
349
+ local pixel=app.pixelColor.rgba(color.red,color.green,color.blue,color.alpha)
350
+ for dy=0,scale-1 do for dx=0,scale-1 do output:drawPixel(x*scale+dx,y*scale+dy,pixel) end end
351
+ end
352
+ end
353
+ if not output:saveAs(output_path) then error("Unable to save scaled canvas capture", 0) end
354
+ end
355
+ return { outputPath=output_path, frame=frame_number, width=sprite.width*scale, height=sprite.height*scale, scale=scale }
356
+ end
357
+
358
+ local SAFE_COMMANDS = {
359
+ DuplicateLayer=true,
360
+ MergeDownLayer=true,
361
+ FlattenLayers=true,
362
+ BackgroundFromLayer=true,
363
+ LayerFromBackground=true,
364
+ ReverseFrames=true,
365
+ ClearCel=true,
366
+ NewFrame=true,
367
+ RemoveFrame=true,
368
+ NewLayer=true,
369
+ RemoveLayer=true,
370
+ }
371
+
372
+ local function handle_request(request)
373
+ local action = request.action
374
+ if action == "status" then
375
+ return { bridgeVersion=BRIDGE_VERSION, asepriteVersion=tostring(app.version), apiVersion=app.apiVersion, uiAvailable=app.isUIAvailable, documents=#app.sprites, liveCommands=live_commands.names(), active=sprite_state(app.activeSprite) }
376
+ elseif action == "list_documents" then
377
+ return { documents=document_list() }
378
+ elseif action == "new_document" then
379
+ local width=math.max(1,math.min(8192,math.floor(tonumber(request.width) or 1)))
380
+ local height=math.max(1,math.min(8192,math.floor(tonumber(request.height) or 1)))
381
+ local mode=request.colorMode == "indexed" and ColorMode.INDEXED or request.colorMode == "grayscale" and ColorMode.GRAY or ColorMode.RGB
382
+ local sprite=Sprite(width,height,mode)
383
+ app.activeSprite=sprite
384
+ return { document=sprite_state(sprite) }
385
+ elseif action == "open_document" then
386
+ if type(request.path)~="string" or request.path=="" then error("path is required",0) end
387
+ -- Reuse an already-open document for this path instead of calling
388
+ -- app.open() again. This makes the action idempotent: if a caller times
389
+ -- out waiting for a slow open and retries with a new request id, the
390
+ -- retry attaches to the same sprite instead of opening a duplicate tab.
391
+ local sprite=find_open_sprite_by_path(request.path)
392
+ if not sprite then
393
+ sprite=app.open(request.path)
394
+ if not sprite then error("Unable to open document",0) end
395
+ end
396
+ app.activeSprite=sprite
397
+ return { document=sprite_state(sprite) }
398
+ end
399
+
400
+ local sprite = find_sprite(request)
401
+ if not sprite then error("Aseprite document was not found", 0) end
402
+ set_active_target(sprite, request)
403
+
404
+ if action == "inspect" or action == "select_document" or action == "select_layer" or action == "select_frame" then
405
+ return { document=sprite_state(sprite) }
406
+ elseif action == "save" then
407
+ if sprite.filename == "" then error("Document has no associated filename; use save_as", 0) end
408
+ if not sprite:saveAs(sprite.filename) then error("Unable to save document", 0) end
409
+ elseif action == "save_as" then
410
+ if type(request.path)~="string" or request.path=="" then error("path is required",0) end
411
+ if not sprite:saveAs(request.path) then error("Unable to save document",0) end
412
+ elseif action == "close_document" then
413
+ if sprite.isModified and request.discardChanges ~= true then error("Document has unsaved changes; set discardChanges=true to close it",0) end
414
+ sprite:close()
415
+ return { closed=true, documents=document_list() }
416
+ elseif action == "undo" then app.undo()
417
+ elseif action == "redo" then app.redo()
418
+ elseif action == "toggle_playback" then app.command.PlayAnimation()
419
+ elseif action == "set_zoom" then
420
+ if not app.editor then error("No active editor",0) end
421
+ app.editor.zoom=math.max(0.01,math.min(64,tonumber(request.zoom) or 1))
422
+ elseif action == "set_onion_skin" then
423
+ local prefs=app.preferences.document(sprite).onionskin
424
+ if request.active~=nil then prefs.active=request.active==true end
425
+ if request.prevFrames~=nil then prefs.prev_frames=math.max(0,math.floor(request.prevFrames)) end
426
+ if request.nextFrames~=nil then prefs.next_frames=math.max(0,math.floor(request.nextFrames)) end
427
+ if request.opacityBase~=nil then prefs.opacity_base=math.max(0,math.min(255,math.floor(request.opacityBase))) end
428
+ if request.opacityStep~=nil then prefs.opacity_step=math.max(0,math.min(255,math.floor(request.opacityStep))) end
429
+ if request.loopTag~=nil then prefs.loop_tag=request.loopTag==true end
430
+ if request.currentLayer~=nil then prefs.current_layer=request.currentLayer==true end
431
+ elseif action == "set_tool" then
432
+ if type(request.tool)~="string" or request.tool=="" then error("tool is required",0) end
433
+ app.activeTool=request.tool
434
+ elseif action == "set_colors" then
435
+ if request.foreground then app.fgColor=color_from_request(request.foreground,app.fgColor) end
436
+ if request.background then app.bgColor=color_from_request(request.background,app.bgColor) end
437
+ elseif action == "set_brush" then
438
+ local brush_type=request.brushType=="square" and BrushType.SQUARE or request.brushType=="line" and BrushType.LINE or BrushType.CIRCLE
439
+ app.activeBrush=Brush{type=brush_type,size=math.max(1,math.min(256,math.floor(tonumber(request.size) or 1))),angle=math.floor(tonumber(request.angle) or 0)}
440
+ elseif action == "set_selection" then
441
+ local bounds=request.bounds
442
+ if type(bounds)~="table" then error("bounds is required",0) end
443
+ local rectangle=Rectangle(math.floor(bounds.x or 0),math.floor(bounds.y or 0),math.max(1,math.floor(bounds.width or 1)),math.max(1,math.floor(bounds.height or 1)))
444
+ local selection=sprite.selection
445
+ local mode=request.mode or "replace"
446
+ if mode=="replace" then selection:select(rectangle)
447
+ elseif mode=="add" then selection:add(rectangle)
448
+ elseif mode=="subtract" then selection:subtract(rectangle)
449
+ elseif mode=="intersect" then selection:intersect(rectangle)
450
+ else error("Unsupported selection mode",0) end
451
+ elseif action == "clear_selection" then sprite.selection:deselect()
452
+ elseif action == "capture_canvas" then return capture_canvas(sprite,request)
453
+ elseif action == "run_live_command" then
454
+ local result = live_commands.run(sprite, request)
455
+ app.refresh()
456
+ return { command=request.liveCommand, result=result, document=sprite_state(app.activeSprite) }
457
+ elseif action == "set_pixels" then
458
+ local layer=app.activeLayer or sprite.layers[1]
459
+ if layer.isGroup or layer.isTilemap then error("A normal drawable layer is required",0) end
460
+ local frame_number=app.activeFrame and app.activeFrame.frameNumber or 1
461
+ local image=ensure_canvas_cel(sprite,layer,frame_number).image
462
+ local pixels=request.pixels
463
+ local pixel_count=sequence_length(pixels)
464
+ if not pixel_count or pixel_count>8192 then error("pixels must contain at most 8192 entries",0) end
465
+ for index=1,pixel_count do
466
+ local entry=pixels[index]
467
+ local x=math.floor(tonumber(entry.x) or -1) local y=math.floor(tonumber(entry.y) or -1)
468
+ if x<0 or y<0 or x>=sprite.width or y>=sprite.height then error("Pixel is outside the sprite",0) end
469
+ image:drawPixel(x,y,rgba_pixel(sprite,color_from_request(entry.color)))
470
+ end
471
+ elseif action == "draw_stroke" then
472
+ local points={}
473
+ local point_count=sequence_length(request.points)
474
+ if not point_count or point_count<1 or point_count>16384 then error("points must contain 1-16384 entries",0) end
475
+ for index=1,point_count do local entry=request.points[index] table.insert(points,Point(math.floor(entry.x),math.floor(entry.y))) end
476
+ app.useTool{
477
+ tool=request.tool or "pencil",
478
+ color=color_from_request(request.color,app.fgColor),
479
+ opacity=math.max(0,math.min(255,math.floor(tonumber(request.opacity) or 255))),
480
+ brush=Brush{type=BrushType.CIRCLE,size=math.max(1,math.min(256,math.floor(tonumber(request.size) or 1)))},
481
+ freehandAlgorithm=request.pixelPerfect==true and 1 or 0,
482
+ points=points,
483
+ }
484
+ elseif action == "create_layer" then
485
+ local layer=request.group==true and sprite:newGroup() or sprite:newLayer()
486
+ layer.name=request.name or (request.group==true and "Group" or "Layer")
487
+ app.activeLayer=layer
488
+ elseif action == "create_frame" then
489
+ local index=math.max(1,math.min(#sprite.frames+1,math.floor(tonumber(request.frame) or (#sprite.frames+1))))
490
+ local frame=request.duplicate==true and sprite:newFrame(math.min(index,#sprite.frames)) or sprite:newEmptyFrame(index)
491
+ if request.durationMs then frame.duration=math.max(1,math.floor(request.durationMs))/1000 end
492
+ app.activeFrame=frame
493
+ elseif action == "delete_frame" then
494
+ local frame_number=app.activeFrame and app.activeFrame.frameNumber or 1
495
+ if #sprite.frames<=1 then error("Cannot delete the only frame",0) end
496
+ sprite:deleteFrame(frame_number)
497
+ elseif action == "set_frame_duration" then
498
+ local frame=app.activeFrame or sprite.frames[1]
499
+ frame.duration=math.max(1,math.min(60000,math.floor(tonumber(request.durationMs) or 100)))/1000
500
+ elseif action == "safe_command" then
501
+ local command=request.command
502
+ if not SAFE_COMMANDS[command] then error("Command is not allowlisted",0) end
503
+ local fn=app.command[command]
504
+ if type(fn)~="function" then error("Aseprite command is unavailable",0) end
505
+ fn(request.params or {})
506
+ else
507
+ error("Unsupported Auvrynt bridge action: "..tostring(action),0)
508
+ end
509
+ app.refresh()
510
+ return { document=sprite_state(sprite) }
511
+ end
512
+
513
+ local function process_request_file(filename)
514
+ local request_path=app.fs.joinPath(requests_dir,filename)
515
+ local claimed_path=request_path..".processing"
516
+ -- Claim the request file (rename it out of the requests directory) before
517
+ -- doing any work, rather than after. Previously the file was only removed
518
+ -- once handle_request finished, so a slow handler (e.g. open_document on a
519
+ -- large sprite) left it visible to the requests listing for the whole
520
+ -- duration of the call. Claiming it up front closes that window entirely.
521
+ if not os.rename(request_path,claimed_path) then return end
522
+ local raw=read_file(claimed_path)
523
+ if not raw then os.remove(claimed_path) return end
524
+ local response={ok=false}
525
+ local request_id=app.fs.fileTitle(filename)
526
+ local decode_ok,request=pcall(json.decode,raw)
527
+ if not decode_ok or not is_json_object(request) then
528
+ response.error="Invalid request JSON"
529
+ elseif not auth_token or request.token~=auth_token then
530
+ response.error="Invalid bridge token"
531
+ elseif tostring(request.id or "")~=request_id then
532
+ response.error="Request ID mismatch"
533
+ else
534
+ local ok,result=pcall(handle_request,request)
535
+ if ok then response.ok=true response.result=result
536
+ else response.error=tostring(result) end
537
+ end
538
+ response.id=request_id
539
+ response.bridgeVersion=BRIDGE_VERSION
540
+ local response_path=app.fs.joinPath(responses_dir,request_id..".json")
541
+ pcall(write_json_atomic,response_path,response)
542
+ os.remove(claimed_path)
543
+ end
544
+
545
+ local function poll_requests()
546
+ if not auth_token then refresh_auth_token() end
547
+ local files=app.fs.listFiles(requests_dir)
548
+ table.sort(files)
549
+ local processed=0
550
+ for _,filename in ipairs(files) do
551
+ if filename:match("^[%w%-_]+%.json$") then
552
+ process_request_file(filename)
553
+ processed=processed+1
554
+ if processed>=16 then break end
555
+ end
556
+ end
557
+ end
558
+
559
+ function init(plugin)
560
+ -- Aseprite does not guarantee that an extension's directory is in Lua's
561
+ -- module search path. Configure it before loading the bridge's sibling
562
+ -- modules; otherwise the plugin fails during initialization and its timer
563
+ -- never starts polling the request queue.
564
+ local extension_module_path = app.fs.joinPath(plugin.path, "?.lua")
565
+ if not package.path:find(extension_module_path, 1, true) then
566
+ package.path = extension_module_path .. ";" .. package.path
567
+ end
568
+ live_commands = require("live_commands")
569
+ ensure_directories()
570
+ refresh_auth_token()
571
+ timer=Timer{interval=POLL_INTERVAL,ontick=poll_requests}
572
+ timer:start()
573
+ pcall(function()
574
+ plugin:newCommand{
575
+ id="auvrynt_bridge_status",
576
+ title="Auvrynt Bridge Status",
577
+ group="cel_properties",
578
+ onclick=function()
579
+ app.alert{
580
+ title="Auvrynt Bridge",
581
+ text={
582
+ "Bridge version: "..BRIDGE_VERSION,
583
+ auth_token and "Authenticated request queue is ready." or "Waiting for Auvrynt authentication file.",
584
+ bridge_root,
585
+ },
586
+ }
587
+ end,
588
+ }
589
+ end)
590
+ end
591
+
592
+ function exit(plugin)
593
+ if timer then timer:stop() timer=nil end
594
+ end