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.
- package/LICENSE +21 -21
- package/README.md +366 -233
- package/addons/auvrynt_bridge/auvrynt_bridge.gd +500 -0
- package/addons/auvrynt_bridge/plugin.cfg +7 -0
- package/bin/auvrynt-launcher.cjs +77 -0
- package/dist/artifact-registry.js +1 -0
- package/dist/aseprite-tools.js +1 -0
- package/dist/auth/connection-registry.js +145 -0
- package/dist/auth/connection-status.js +176 -0
- package/dist/auth/oauth-provider.js +617 -0
- package/dist/auth/room-registry.js +131 -0
- package/dist/auth/session-registry.js +531 -0
- package/dist/background-lifecycle.js +1 -0
- package/dist/blender-client.js +1 -109
- package/dist/blender-tools.js +1 -930
- package/dist/browser-stability.js +1 -0
- package/dist/cli/commands/help-command.js +10 -0
- package/dist/cli/commands/init-command.js +190 -0
- package/dist/cli/commands/integration-commands.js +88 -0
- package/dist/cli/commands/serve-command.js +83 -0
- package/dist/cli/commands/setup-command.js +81 -0
- package/dist/cli/commands/status-commands.js +166 -0
- package/dist/cli/commands/tunnel-command.js +127 -0
- package/dist/cli/commands/user-config-commands.js +105 -0
- package/dist/cli/dashboard-actions.js +516 -0
- package/dist/cli/dashboard-native-actions.js +282 -0
- package/dist/cli/foreground-server.js +270 -0
- package/dist/cli/instance-control.js +21 -0
- package/dist/cli/instance-lock.js +123 -0
- package/dist/cli/integration-bootstrap.js +206 -0
- package/dist/cli/lifecycle-manager.js +493 -0
- package/dist/cli/runtime-support.js +74 -0
- package/dist/cli/serena-detected-default.js +27 -0
- package/dist/cli/tunnel-health-monitor.js +182 -0
- package/dist/cli.js +82 -739
- package/dist/config.js +1 -243
- package/dist/connection-registry.js +1 -73
- package/dist/connection-status.js +1 -139
- package/dist/control-retry.js +1 -0
- package/dist/crash-recovery.js +1 -0
- package/dist/db/client.js +16 -3
- package/dist/db/schema.js +30 -0
- package/dist/dotnet-tools.js +1 -223
- package/dist/git-worktrees.js +1 -134
- package/dist/git.js +1 -41
- package/dist/godot-animation-tilemap.js +1 -82
- package/dist/godot-csharp-build.js +1 -93
- package/dist/godot-csharp-project.js +1 -157
- package/dist/godot-csharp-runner.js +1 -146
- package/dist/godot-csharp-semantic.js +1 -161
- package/dist/godot-csharp-validate.js +1 -71
- package/dist/godot-dotnet-env.js +1 -169
- package/dist/godot-editor-bridge.js +1 -140
- package/dist/godot-gdscript.js +1 -824
- package/dist/godot-project-settings.js +1 -223
- package/dist/godot-runtime-testing.js +1 -249
- package/dist/godot-tools.js +1 -183
- package/dist/http-rate-limit.js +1 -0
- package/dist/http-server-hardening.js +1 -0
- package/dist/image-tools.js +1 -157
- package/dist/infrastructure/command-reference.js +32 -0
- package/dist/infrastructure/config.js +424 -0
- package/dist/infrastructure/context7-auth.js +55 -0
- package/dist/infrastructure/http-rate-limit.js +42 -0
- package/dist/infrastructure/http-server-hardening.js +23 -0
- package/dist/infrastructure/integration-queue.js +46 -0
- package/dist/infrastructure/logger.js +129 -0
- package/dist/infrastructure/mcp-event-store.js +103 -0
- package/dist/infrastructure/ngrok-auth-pool.js +208 -0
- package/dist/infrastructure/request-context.js +14 -0
- package/dist/infrastructure/shutdown.js +37 -0
- package/dist/infrastructure/sse-heartbeat.js +47 -0
- package/dist/infrastructure/tool-capabilities.js +67 -0
- package/dist/infrastructure/tool-result-budget.js +175 -0
- package/dist/infrastructure/user-config.js +167 -0
- package/dist/integration-discovery.js +1 -98
- package/dist/integration-queue.js +1 -0
- package/dist/integrations/agent-reach/agent-reach-tools.js +196 -0
- package/dist/integrations/agent-reach/native-channels.js +468 -0
- package/dist/integrations/aseprite/aseprite-analysis-tools.js +368 -0
- package/dist/integrations/aseprite/aseprite-editing-tools.js +647 -0
- package/dist/integrations/aseprite/aseprite-live-tools.js +297 -0
- package/dist/integrations/aseprite/aseprite-safety-tools.js +594 -0
- package/dist/integrations/aseprite/aseprite-specialized-tools.js +289 -0
- package/dist/integrations/aseprite/aseprite-tools.js +837 -0
- package/dist/integrations/blender/blender-catalog-mesh.js +593 -0
- package/dist/integrations/blender/blender-catalog-object.js +906 -0
- package/dist/integrations/blender/blender-catalog-scene.js +266 -0
- package/dist/integrations/blender/blender-catalog-select.js +581 -0
- package/dist/integrations/blender/blender-catalog-stubs.js +7512 -0
- package/dist/integrations/blender/blender-catalog.js +165 -0
- package/dist/integrations/blender/blender-client.js +105 -0
- package/dist/integrations/blender/blender-tools.js +2243 -0
- package/dist/integrations/context7/context7-tools.js +106 -0
- package/dist/integrations/dotnet/dotnet-tools.js +195 -0
- package/dist/integrations/godot/godot-animation-tilemap.js +74 -0
- package/dist/integrations/godot/godot-csharp-build.js +91 -0
- package/dist/integrations/godot/godot-csharp-project.js +155 -0
- package/dist/integrations/godot/godot-csharp-runner.js +118 -0
- package/dist/integrations/godot/godot-csharp-semantic.js +146 -0
- package/dist/integrations/godot/godot-csharp-validate.js +71 -0
- package/dist/integrations/godot/godot-dotnet-env.js +134 -0
- package/dist/integrations/godot/godot-editor-bridge.js +328 -0
- package/dist/integrations/godot/godot-gdscript.js +536 -0
- package/dist/integrations/godot/godot-project-settings.js +178 -0
- package/dist/integrations/godot/godot-runtime-testing.js +263 -0
- package/dist/integrations/godot/godot-tools.js +193 -0
- package/dist/integrations/images/image-tools.js +414 -0
- package/dist/integrations/images/png-codec.js +251 -0
- package/dist/integrations/images/view-image.js +99 -0
- package/dist/integrations/images/window-capture.js +148 -0
- package/dist/integrations/integration-discovery.js +185 -0
- package/dist/integrations/obsidian/obsidian-tools.js +205 -0
- package/dist/integrations/playwright/browser-session.js +516 -0
- package/dist/integrations/playwright/browser-stability.js +36 -0
- package/dist/integrations/playwright/playwright-runtime.js +105 -0
- package/dist/integrations/playwright/web-tools.js +504 -0
- package/dist/integrations/roblox/roblox-helpers.js +381 -0
- package/dist/integrations/roblox/roblox-studio-client.js +112 -0
- package/dist/integrations/roblox/roblox-tools.js +106 -0
- package/dist/integrations/serena/serena-manager.js +464 -0
- package/dist/integrations/serena/serena-tools.js +411 -0
- package/dist/logger.js +1 -76
- package/dist/mcp-event-store.js +1 -0
- package/dist/oauth-provider.js +1 -377
- package/dist/pi-tools.js +1 -81
- package/dist/playwright-runtime.js +1 -0
- package/dist/process/background-lifecycle.js +189 -0
- package/dist/process/control-retry.js +42 -0
- package/dist/process/crash-recovery.js +23 -0
- package/dist/process/processes.js +456 -0
- package/dist/processes.js +1 -218
- package/dist/request-context.js +1 -0
- package/dist/review-checkpoints.js +1 -142
- package/dist/room-registry.js +1 -0
- package/dist/roots.js +1 -53
- package/dist/search-discovery.js +1 -271
- package/dist/serena-manager.js +1 -443
- package/dist/serena-tools.js +1 -411
- package/dist/server/dashboard-page-styles.js +331 -0
- package/dist/server/dashboard-page.js +1509 -0
- package/dist/server/dashboard-routes.js +46 -0
- package/dist/server/dashboard.js +240 -0
- package/dist/server/http-helpers.js +30 -0
- package/dist/server/integration-profile-update.js +37 -0
- package/dist/server/mcp-policy.js +169 -0
- package/dist/server/mcp-server-factory.js +127 -0
- package/dist/server/mcp-tool-registrar.js +182 -0
- package/dist/server/openai-session-hint.js +14 -0
- package/dist/server/tool-groups.js +29 -0
- package/dist/server/tool-logging.js +33 -0
- package/dist/server/tool-registration-shared.js +59 -0
- package/dist/server/tools/aseprite-advanced-tools-registration.js +547 -0
- package/dist/server/tools/aseprite-tools-registration.js +213 -0
- package/dist/server/tools/blender-tools-registration.js +690 -0
- package/dist/server/tools/core-file-tools-registration.js +459 -0
- package/dist/server/tools/dotnet-godot-window-tools-registration.js +120 -0
- package/dist/server/tools/godot-csharp-tools-registration.js +252 -0
- package/dist/server/tools/godot-gdscript-tools-registration.js +189 -0
- package/dist/server/tools/process-project-tools-registration.js +155 -0
- package/dist/server/tools/roblox-tools-registration.js +514 -0
- package/dist/server/tools/web-image-tools-registration.js +326 -0
- package/dist/server/tools/workspace-lifecycle-tools-registration.js +130 -0
- package/dist/server/ui-assets.js +97 -0
- package/dist/server/workspace-analytics.js +92 -0
- package/dist/server.js +453 -2713
- package/dist/session-registry.js +1 -0
- package/dist/shutdown.js +1 -0
- package/dist/skills.js +1 -45
- package/dist/sse-heartbeat.js +1 -0
- package/dist/tool-capabilities.js +1 -0
- package/dist/tool-result-budget.js +1 -0
- package/dist/tools/pi-tools.js +81 -0
- package/dist/tunnels/cloudflare-tunnel.js +217 -0
- package/dist/tunnels/cloudflared-service.js +174 -0
- package/dist/tunnels/ngrok-tunnel.js +220 -0
- package/dist/tunnels/tunnel-manager.js +186 -0
- package/dist/tunnels/tunnel-types.js +1 -0
- package/dist/tunnels/tunnel-utils.js +62 -0
- package/dist/ui/.vite/manifest.json +9 -2487
- package/dist/ui/assets/heavy-payload-D42A9ceL.js +1 -0
- package/dist/ui/assets/lightweight-diff-Cv4g9Hdr.js +13 -0
- package/dist/ui/assets/review-payload-DKIg1cKF.js +1 -0
- package/dist/ui/assets/workspace-app-CeK3NhmB.css +1 -0
- package/dist/ui/assets/{workspace-app-C5QsE314.js → workspace-app-CkUXnpl4.js} +6 -6
- package/dist/ui/brand-theme.js +23 -0
- package/dist/ui/workspace-app.html +15 -15
- package/dist/user-config.js +1 -57
- package/dist/view-image.js +1 -104
- package/dist/web-tools.js +1 -200
- package/dist/window-capture.js +1 -74
- package/dist/workspace/artifact-registry.js +69 -0
- package/dist/workspace/git-worktrees.js +141 -0
- package/dist/workspace/git.js +42 -0
- package/dist/workspace/review-checkpoints.js +142 -0
- package/dist/workspace/roots.js +56 -0
- package/dist/workspace/search-discovery.js +264 -0
- package/dist/workspace/skills.js +45 -0
- package/dist/workspace/workspace-store.js +219 -0
- package/dist/workspace/workspaces.js +314 -0
- package/dist/workspace-store.js +1 -125
- package/dist/workspaces.js +1 -226
- package/docs/CREATOR_STORE_FREE_ASSETS.md +162 -0
- package/docs/DEVELOPMENT_TOOLS.md +136 -93
- package/docs/assets/auvrynt-icon.png +0 -0
- package/docs/assets/auvrynt-icon.svg +20 -0
- package/docs/chatgpt-coding-workflow.md +143 -143
- package/docs/configuration.md +156 -124
- package/docs/diagnostics.md +79 -0
- package/docs/gotchas.md +244 -202
- package/docs/multi-agent-and-long-projects.md +91 -0
- package/docs/security.md +138 -100
- package/docs/setup.md +171 -131
- package/docs/source-layout.md +60 -0
- package/extensions/auvrynt_bridge/auvrynt_bridge.lua +594 -0
- package/extensions/auvrynt_bridge/live_analysis.lua +181 -0
- package/extensions/auvrynt_bridge/live_animation.lua +134 -0
- package/extensions/auvrynt_bridge/live_commands.lua +24 -0
- package/extensions/auvrynt_bridge/live_common.lua +130 -0
- package/extensions/auvrynt_bridge/live_document.lua +78 -0
- package/extensions/auvrynt_bridge/live_drawing.lua +125 -0
- package/extensions/auvrynt_bridge/live_effects.lua +91 -0
- package/extensions/auvrynt_bridge/live_palette_template.lua +167 -0
- package/extensions/auvrynt_bridge/live_selection.lua +110 -0
- package/extensions/auvrynt_bridge/live_structure.lua +129 -0
- package/extensions/auvrynt_bridge/package.json +17 -0
- package/guides/ASEPRITE_AGENT_GUIDE.md +133 -0
- package/guides/BLENDER_AGENT_GUIDE.md +472 -0
- package/guides/GODOT_AGENT_GUIDE.md +298 -0
- package/guides/PROJECT_ROUTER.md +165 -0
- package/guides/ROBLOX_AGENT_GUIDE.md +75 -0
- package/guides/SOFTWARE_AGENT_GUIDE.md +104 -0
- package/guides/WEB_AGENT_GUIDE.md +287 -0
- package/package.json +78 -70
- package/scripts/dev-server.mjs +121 -120
- package/scripts/live-tunnel-smoke.mjs +538 -0
- package/scripts/repo-hygiene.mjs +74 -0
- package/scripts/restart-after-crash.mjs +49 -0
- package/scripts/run-tests.mjs +166 -0
- package/dist/ui/assets/abap-CLvhMVsD.js +0 -1
- package/dist/ui/assets/actionscript-3--17pq3dv.js +0 -1
- package/dist/ui/assets/ada-C5qYipkI.js +0 -1
- package/dist/ui/assets/andromeeda-vGVdxbeo.js +0 -1
- package/dist/ui/assets/angular-html-BJqQFYI6.js +0 -1
- package/dist/ui/assets/angular-ts-CMJECO0Y.js +0 -1
- package/dist/ui/assets/apache-U0d_L8uA.js +0 -1
- package/dist/ui/assets/apex-CGTLDQj6.js +0 -1
- package/dist/ui/assets/apl-DWeXpBBr.js +0 -1
- package/dist/ui/assets/applescript-CCn79oCD.js +0 -1
- package/dist/ui/assets/ara-4CJ0cIlV.js +0 -1
- package/dist/ui/assets/asciidoc-DE70LPWp.js +0 -1
- package/dist/ui/assets/asm-Cmm7eHzH.js +0 -1
- package/dist/ui/assets/astro-CLbttLOq.js +0 -1
- package/dist/ui/assets/aurora-x-CDeNXAV0.js +0 -1
- package/dist/ui/assets/awk-BWXHIvNe.js +0 -1
- package/dist/ui/assets/ayu-dark-DluEY0Gj.js +0 -1
- package/dist/ui/assets/ayu-light-C3h-C4tm.js +0 -1
- package/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +0 -1
- package/dist/ui/assets/ballerina-B7ZEbQpA.js +0 -1
- package/dist/ui/assets/bat-Bo4NYOV-.js +0 -1
- package/dist/ui/assets/beancount-D-usSTwE.js +0 -1
- package/dist/ui/assets/berry-DKpUyyne.js +0 -1
- package/dist/ui/assets/bibtex-Ci_nEsc7.js +0 -1
- package/dist/ui/assets/bicep-CUHmPFLl.js +0 -1
- package/dist/ui/assets/bird2-C2hNVINV.js +0 -1
- package/dist/ui/assets/blade-BOzY0P2V.js +0 -1
- package/dist/ui/assets/bsl-BkkzgIyY.js +0 -1
- package/dist/ui/assets/c-BG-8uJvh.js +0 -1
- package/dist/ui/assets/c3-CnJL0r0V.js +0 -1
- package/dist/ui/assets/cadence-CQ2zXKGN.js +0 -1
- package/dist/ui/assets/cairo-DLTphjLi.js +0 -1
- package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +0 -1
- package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +0 -1
- package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +0 -1
- package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +0 -1
- package/dist/ui/assets/clarity-SemFz856.js +0 -1
- package/dist/ui/assets/clojure-DqKBuwfJ.js +0 -1
- package/dist/ui/assets/cmake-Bj61d0ZC.js +0 -1
- package/dist/ui/assets/cobol-I_17IuGe.js +0 -1
- package/dist/ui/assets/codeowners-C8r90Shi.js +0 -1
- package/dist/ui/assets/codeql-oeQT6MSM.js +0 -1
- package/dist/ui/assets/coffee-C0B8hmok.js +0 -1
- package/dist/ui/assets/common-lisp-Cv5bFMCO.js +0 -1
- package/dist/ui/assets/coq-BrsZFFmf.js +0 -1
- package/dist/ui/assets/cpp-DDJXt6Vs.js +0 -1
- package/dist/ui/assets/crystal-Bexqace6.js +0 -1
- package/dist/ui/assets/csharp-Ct8U2NOr.js +0 -1
- package/dist/ui/assets/css-DSQhw_9R.js +0 -1
- package/dist/ui/assets/csv-Dx-8-gkx.js +0 -1
- package/dist/ui/assets/cue-CE9AQfxI.js +0 -1
- package/dist/ui/assets/cypher-ClKdZ_lG.js +0 -1
- package/dist/ui/assets/d-qD-0Kul2.js +0 -1
- package/dist/ui/assets/dark-plus-Cs2F2srj.js +0 -1
- package/dist/ui/assets/dart-DkHntEIa.js +0 -1
- package/dist/ui/assets/dax-BkyTk9wS.js +0 -1
- package/dist/ui/assets/desktop-Dlh5hvp9.js +0 -1
- package/dist/ui/assets/diff-woXpYk--.js +0 -1
- package/dist/ui/assets/docker-IyjqRm3v.js +0 -1
- package/dist/ui/assets/dotenv-_5a1GRtc.js +0 -1
- package/dist/ui/assets/dracula-BHWKrbxM.js +0 -1
- package/dist/ui/assets/dracula-soft-5eyTD99u.js +0 -1
- package/dist/ui/assets/dream-maker-DW3nJb8Q.js +0 -1
- package/dist/ui/assets/edge-Z8YYkHOr.js +0 -1
- package/dist/ui/assets/elixir-CG9uKtAF.js +0 -1
- package/dist/ui/assets/elm-GfWG2IfT.js +0 -1
- package/dist/ui/assets/emacs-lisp-C9PiwqqW.js +0 -1
- package/dist/ui/assets/erb-xe89e73J.js +0 -1
- package/dist/ui/assets/erlang-Cphh6RMH.js +0 -1
- package/dist/ui/assets/everforest-dark-sB-x3p7T.js +0 -1
- package/dist/ui/assets/everforest-light-Df2xbC6M.js +0 -1
- package/dist/ui/assets/fennel-DQxkIbk2.js +0 -1
- package/dist/ui/assets/fish-BJitypiv.js +0 -1
- package/dist/ui/assets/fluent-C03EYrpw.js +0 -1
- package/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +0 -1
- package/dist/ui/assets/fortran-free-form-CYNrtFtB.js +0 -1
- package/dist/ui/assets/fsharp-D13ZGOAj.js +0 -1
- package/dist/ui/assets/gdresource-C0sCabJj.js +0 -1
- package/dist/ui/assets/gdscript-Cp2uCuqX.js +0 -1
- package/dist/ui/assets/gdshader-CBce3t8t.js +0 -1
- package/dist/ui/assets/genie-CV2tkWYe.js +0 -1
- package/dist/ui/assets/gherkin-DExj1W_8.js +0 -1
- package/dist/ui/assets/git-commit-BSykSTBG.js +0 -1
- package/dist/ui/assets/git-rebase-CoTL_uSE.js +0 -1
- package/dist/ui/assets/github-dark-C-LZuMrd.js +0 -1
- package/dist/ui/assets/github-dark-default-DXG-b-1a.js +0 -1
- package/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +0 -1
- package/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +0 -1
- package/dist/ui/assets/github-light-EUqPIrTm.js +0 -1
- package/dist/ui/assets/github-light-default-BXViO-2h.js +0 -1
- package/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +0 -1
- package/dist/ui/assets/gleam-CSRkHgEL.js +0 -1
- package/dist/ui/assets/glimmer-js-DAn4UCSu.js +0 -1
- package/dist/ui/assets/glimmer-ts-Tjyi6Gh5.js +0 -1
- package/dist/ui/assets/glsl-CtTDZoqR.js +0 -1
- package/dist/ui/assets/gn-ilITqXS6.js +0 -1
- package/dist/ui/assets/gnuplot-7GGW24-e.js +0 -1
- package/dist/ui/assets/go-BJwz_mda.js +0 -1
- package/dist/ui/assets/graphql-D5gcC_Jk.js +0 -1
- package/dist/ui/assets/groovy-CacY0gHj.js +0 -1
- package/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +0 -1
- package/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +0 -1
- package/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +0 -1
- package/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +0 -1
- package/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +0 -1
- package/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +0 -1
- package/dist/ui/assets/hack-BJXY27dt.js +0 -1
- package/dist/ui/assets/haml-BLfFoZf7.js +0 -1
- package/dist/ui/assets/handlebars-Dw6CWkvN.js +0 -1
- package/dist/ui/assets/haskell-D8IpX4py.js +0 -1
- package/dist/ui/assets/haxe-OTjmBuCE.js +0 -1
- package/dist/ui/assets/hcl-Dh228itO.js +0 -1
- package/dist/ui/assets/heavy-payload-Dcg0-F-S.js +0 -4
- package/dist/ui/assets/hjson-CxZEssPk.js +0 -1
- package/dist/ui/assets/hlsl-Cvrh5tZx.js +0 -1
- package/dist/ui/assets/horizon-CE9ld1lL.js +0 -1
- package/dist/ui/assets/horizon-bright-Br1oVSNq.js +0 -1
- package/dist/ui/assets/houston-CsvMBhTu.js +0 -1
- package/dist/ui/assets/html-CAcAWvoN.js +0 -1
- package/dist/ui/assets/html-derivative-8aSW2E_7.js +0 -1
- package/dist/ui/assets/http-B2YR_3V1.js +0 -1
- package/dist/ui/assets/hurl-BnDJ9Zhf.js +0 -1
- package/dist/ui/assets/hxml-B0Qn7Nwc.js +0 -1
- package/dist/ui/assets/hy-CZbG8q4J.js +0 -1
- package/dist/ui/assets/imba-DsUTQ-LC.js +0 -1
- package/dist/ui/assets/ini-B5eOa1yu.js +0 -1
- package/dist/ui/assets/java-Doxi4W8u.js +0 -1
- package/dist/ui/assets/javascript-BbRdEqti.js +0 -1
- package/dist/ui/assets/jinja-CS3Tpv_Q.js +0 -1
- package/dist/ui/assets/jison-BkPGYVHR.js +0 -1
- package/dist/ui/assets/json-BMt1m3m8.js +0 -1
- package/dist/ui/assets/json5-BR5RXkoi.js +0 -1
- package/dist/ui/assets/jsonc-CYpm1nAK.js +0 -1
- package/dist/ui/assets/jsonl-CmCQp5Yx.js +0 -1
- package/dist/ui/assets/jsonnet-CJTPZ8u_.js +0 -1
- package/dist/ui/assets/jssm-DXw9l8Rf.js +0 -1
- package/dist/ui/assets/jsx-CQKrJXXY.js +0 -1
- package/dist/ui/assets/julia-BuN7i2du.js +0 -1
- package/dist/ui/assets/just-BswEPFPu.js +0 -1
- package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +0 -1
- package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +0 -1
- package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +0 -1
- package/dist/ui/assets/kdl-CsD5j6eV.js +0 -1
- package/dist/ui/assets/kotlin-DhhofPvG.js +0 -1
- package/dist/ui/assets/kusto-BUv0MjJC.js +0 -1
- package/dist/ui/assets/laserwave-C_8bwKvT.js +0 -1
- package/dist/ui/assets/latex-DU2VyFfA.js +0 -1
- package/dist/ui/assets/lean-CewbzKMR.js +0 -1
- package/dist/ui/assets/less-DVTAwKKz.js +0 -1
- package/dist/ui/assets/light-plus-DVQuIRkW.js +0 -1
- package/dist/ui/assets/liquid-Cmz1L3dq.js +0 -1
- package/dist/ui/assets/llvm-Cm23YOpf.js +0 -1
- package/dist/ui/assets/log-BNLmms1o.js +0 -1
- package/dist/ui/assets/logo-Cluzi2Zq.js +0 -1
- package/dist/ui/assets/lua-CfVXhkaJ.js +0 -1
- package/dist/ui/assets/luau-CNKltnaQ.js +0 -1
- package/dist/ui/assets/make-Dixweg8N.js +0 -1
- package/dist/ui/assets/markdown-BYOwaDjH.js +0 -1
- package/dist/ui/assets/marko-C5bfqGiA.js +0 -1
- package/dist/ui/assets/material-theme-Bm3Qr25_.js +0 -1
- package/dist/ui/assets/material-theme-darker-2IIEA8gg.js +0 -1
- package/dist/ui/assets/material-theme-lighter-uhdI0v04.js +0 -1
- package/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +0 -1
- package/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +0 -1
- package/dist/ui/assets/matlab-D7qyCx1q.js +0 -1
- package/dist/ui/assets/mdc-CVBXYfyq.js +0 -1
- package/dist/ui/assets/mdx-DQZ5AkYe.js +0 -1
- package/dist/ui/assets/mermaid-Bk4SNUv9.js +0 -1
- package/dist/ui/assets/min-dark-BSWPekZh.js +0 -1
- package/dist/ui/assets/min-light-DDpmG2fV.js +0 -1
- package/dist/ui/assets/mipsasm-BMqwQI7S.js +0 -1
- package/dist/ui/assets/mojo-BgCJLMeH.js +0 -1
- package/dist/ui/assets/monokai-CdkpiU2Y.js +0 -1
- package/dist/ui/assets/moonbit-CaWjb8XO.js +0 -1
- package/dist/ui/assets/move-B1IS1UjX.js +0 -1
- package/dist/ui/assets/narrat-_X_XdTYD.js +0 -1
- package/dist/ui/assets/nextflow-Bbiyy34d.js +0 -1
- package/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +0 -1
- package/dist/ui/assets/nginx-CzJafxLa.js +0 -1
- package/dist/ui/assets/night-owl-DhmEMT88.js +0 -1
- package/dist/ui/assets/night-owl-light-eJ-hLW7d.js +0 -1
- package/dist/ui/assets/nim-DABKtHtM.js +0 -1
- package/dist/ui/assets/nix-IvuFDN5E.js +0 -1
- package/dist/ui/assets/nord-Cb4Vim4T.js +0 -1
- package/dist/ui/assets/nushell-DcLAeLz5.js +0 -1
- package/dist/ui/assets/objective-c-D1A_Heim.js +0 -1
- package/dist/ui/assets/objective-cpp-BsSzOQcm.js +0 -1
- package/dist/ui/assets/ocaml-O90oeIOV.js +0 -1
- package/dist/ui/assets/odin-B1RWQWA5.js +0 -1
- package/dist/ui/assets/one-dark-pro-CLwyXe_n.js +0 -1
- package/dist/ui/assets/one-light-D7Lr4KcI.js +0 -1
- package/dist/ui/assets/openscad-BUDT5pXO.js +0 -1
- package/dist/ui/assets/pascal-4ZHwLPI5.js +0 -1
- package/dist/ui/assets/perl-CBh7L3lZ.js +0 -1
- package/dist/ui/assets/php-DFbI9q5p.js +0 -1
- package/dist/ui/assets/pierre-dark-sU4Zdns8.js +0 -1
- package/dist/ui/assets/pierre-dark-soft-HXgun5vs.js +0 -1
- package/dist/ui/assets/pierre-light-DWBk51d8.js +0 -1
- package/dist/ui/assets/pierre-light-soft-CodEzPxf.js +0 -1
- package/dist/ui/assets/pkl-ot-7Btpt.js +0 -1
- package/dist/ui/assets/plastic-DQwYfKfQ.js +0 -1
- package/dist/ui/assets/plsql-DGHpHOYJ.js +0 -1
- package/dist/ui/assets/po-BiJDBrnU.js +0 -1
- package/dist/ui/assets/poimandres-DRFjx7u4.js +0 -1
- package/dist/ui/assets/polar-C7UOKdEL.js +0 -1
- package/dist/ui/assets/postcss-BXeXVLqQ.js +0 -1
- package/dist/ui/assets/powerquery-DNMTfnFr.js +0 -1
- package/dist/ui/assets/powershell-DshXNtvi.js +0 -1
- package/dist/ui/assets/prisma-BsRQq5mF.js +0 -1
- package/dist/ui/assets/prolog-iXnhIJG7.js +0 -1
- package/dist/ui/assets/proto-DB4EqR-F.js +0 -1
- package/dist/ui/assets/pug-C_PxC7gO.js +0 -1
- package/dist/ui/assets/puppet-CDv2pdJW.js +0 -1
- package/dist/ui/assets/purescript-9MfHhQsQ.js +0 -1
- package/dist/ui/assets/python-gzcpVVnB.js +0 -1
- package/dist/ui/assets/qml-DtngoFFK.js +0 -1
- package/dist/ui/assets/qmldir-DCQb3MpD.js +0 -1
- package/dist/ui/assets/qss-Fe1Jh2GI.js +0 -1
- package/dist/ui/assets/r-DohkcevW.js +0 -1
- package/dist/ui/assets/racket-DcIDlBhZ.js +0 -1
- package/dist/ui/assets/raku-B3gFvitq.js +0 -1
- package/dist/ui/assets/razor-C4t8J0_E.js +0 -1
- package/dist/ui/assets/red-CJ3rzSJv.js +0 -1
- package/dist/ui/assets/reg-CRGYupPL.js +0 -1
- package/dist/ui/assets/regexp-OGbTbjgY.js +0 -1
- package/dist/ui/assets/rel-BtDbiS_P.js +0 -1
- package/dist/ui/assets/review-payload-C5Qz60Kq.js +0 -1
- package/dist/ui/assets/riscv-Ckw8ddFX.js +0 -1
- package/dist/ui/assets/ron-VUp2lXgN.js +0 -1
- package/dist/ui/assets/rose-pine-BthvhNj6.js +0 -1
- package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +0 -1
- package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +0 -1
- package/dist/ui/assets/rosmsg-CAekHB0j.js +0 -1
- package/dist/ui/assets/rst-CfBbbcvC.js +0 -1
- package/dist/ui/assets/ruby-Bw0mpxHY.js +0 -1
- package/dist/ui/assets/rust-Cfkwpbl8.js +0 -1
- package/dist/ui/assets/sas-Cs3s9JOf.js +0 -1
- package/dist/ui/assets/sass-DXrisJhu.js +0 -1
- package/dist/ui/assets/scala-DKOlJaKm.js +0 -1
- package/dist/ui/assets/scheme-DQCgrYNe.js +0 -1
- package/dist/ui/assets/scss-sRxNJS54.js +0 -1
- package/dist/ui/assets/sdbl-bTVj8UrX.js +0 -1
- package/dist/ui/assets/shaderlab-TOUzSsQk.js +0 -1
- package/dist/ui/assets/shellscript-B0X6wh0R.js +0 -1
- package/dist/ui/assets/shellsession-D2FdOioR.js +0 -1
- package/dist/ui/assets/slack-dark-DnToyrRv.js +0 -1
- package/dist/ui/assets/slack-ochin-B2OO5cIa.js +0 -1
- package/dist/ui/assets/smalltalk-B16xEiuN.js +0 -1
- package/dist/ui/assets/snazzy-light-4G7pJPwS.js +0 -1
- package/dist/ui/assets/solarized-dark-DV17i1UV.js +0 -1
- package/dist/ui/assets/solarized-light-DSh2HLQt.js +0 -1
- package/dist/ui/assets/solidity-CKzVLygQ.js +0 -1
- package/dist/ui/assets/soy-s6g9OjJ1.js +0 -1
- package/dist/ui/assets/sparql-D_iOobhT.js +0 -1
- package/dist/ui/assets/splunk-BC2Px7Mm.js +0 -1
- package/dist/ui/assets/sql-DVTnh5V-.js +0 -1
- package/dist/ui/assets/ssh-config-BgfXC-Er.js +0 -1
- package/dist/ui/assets/stata-DFIDiXF9.js +0 -1
- package/dist/ui/assets/stylus-B6D30XZt.js +0 -1
- package/dist/ui/assets/surrealql-DVfrsLyg.js +0 -1
- package/dist/ui/assets/svelte-D5GsxESq.js +0 -1
- package/dist/ui/assets/swift-DonLKvLd.js +0 -1
- package/dist/ui/assets/synthwave-84-nFMaYfgc.js +0 -1
- package/dist/ui/assets/system-verilog-DJ5XKQeo.js +0 -1
- package/dist/ui/assets/systemd-BxMlprV5.js +0 -1
- package/dist/ui/assets/talonscript-CohzipZa.js +0 -1
- package/dist/ui/assets/tasl-DMoTqEGO.js +0 -1
- package/dist/ui/assets/tcl-CZd0xW_V.js +0 -1
- package/dist/ui/assets/templ-DI-Zyqzd.js +0 -1
- package/dist/ui/assets/terraform-DswuEJGm.js +0 -1
- package/dist/ui/assets/tex-WHHmlbJI.js +0 -1
- package/dist/ui/assets/tokyo-night-oM2G3aXe.js +0 -1
- package/dist/ui/assets/toml-CcmNWLt0.js +0 -1
- package/dist/ui/assets/ts-tags-Dwpo2RFJ.js +0 -1
- package/dist/ui/assets/tsv-sltzmVWM.js +0 -1
- package/dist/ui/assets/tsx-ph_idaAW.js +0 -1
- package/dist/ui/assets/turtle-ByJddavk.js +0 -1
- package/dist/ui/assets/twig-YO17jFjR.js +0 -1
- package/dist/ui/assets/typescript-CbAxjhkl.js +0 -1
- package/dist/ui/assets/typespec-B88KGewJ.js +0 -1
- package/dist/ui/assets/typst-DI99ib-x.js +0 -1
- package/dist/ui/assets/useFileDiffInstance-B2DLX3Vg.js +0 -244
- package/dist/ui/assets/v-DETTlOr0.js +0 -1
- package/dist/ui/assets/vala-zf12oZj6.js +0 -1
- package/dist/ui/assets/vb-Djn5o6TS.js +0 -1
- package/dist/ui/assets/verilog-CiiDBU1e.js +0 -1
- package/dist/ui/assets/vesper-D5bVUKB1.js +0 -1
- package/dist/ui/assets/vhdl-BroJfC0k.js +0 -1
- package/dist/ui/assets/viml-DvXPmvsu.js +0 -1
- package/dist/ui/assets/vitesse-black-fwtXNY1n.js +0 -1
- package/dist/ui/assets/vitesse-dark-BZCL-v6S.js +0 -1
- package/dist/ui/assets/vitesse-light-VbXTXTou.js +0 -1
- package/dist/ui/assets/vue-CraHL-Ps.js +0 -1
- package/dist/ui/assets/vue-html-e9tyZNtS.js +0 -1
- package/dist/ui/assets/vue-vine-CofmxaUb.js +0 -1
- package/dist/ui/assets/vyper-CgoNMtux.js +0 -1
- package/dist/ui/assets/wasm-BnjxR4X6.js +0 -1
- package/dist/ui/assets/wasm-ByWQv1Qj.js +0 -1
- package/dist/ui/assets/wenyan-C8pVoKbM.js +0 -1
- package/dist/ui/assets/wgsl-BsKzXJz4.js +0 -1
- package/dist/ui/assets/wikitext-ClFFjSW2.js +0 -1
- package/dist/ui/assets/wit-DdvCle-K.js +0 -1
- package/dist/ui/assets/wolfram-DLL8P-h_.js +0 -1
- package/dist/ui/assets/workspace-app-8--oTbCd.css +0 -1
- package/dist/ui/assets/xml-BWSdPZHm.js +0 -1
- package/dist/ui/assets/xsl-BtCt7Hx8.js +0 -1
- package/dist/ui/assets/yaml-BZiTw7cQ.js +0 -1
- package/dist/ui/assets/zenscript-BnlCZFoB.js +0 -1
- package/dist/ui/assets/zig-CMLA9XwU.js +0 -1
- package/docs/assets/auvrynt-logo-light.png +0 -0
- package/docs/assets/auvrynt-screenshot.png +0 -0
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { copyFile, cp, lstat, mkdir, readFile, readdir, rename, rm, stat, writeFile, } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { basename, dirname, extname, join } from "node:path";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
import { asepriteConvertFile, asepriteExportSpriteSheet, errorResponse, luaString, openSpriteScript, resolveAsepriteExecutable, runLua, sanitizeCliOutput, textResponse, workspacePath, } from "./aseprite-tools.js";
|
|
9
|
+
import { asepriteAuditSprite, asepriteCompareDocuments } from "./aseprite-analysis-tools.js";
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
const MAX_BATCH_FILES = 128;
|
|
12
|
+
function safeSegment(value) {
|
|
13
|
+
const normalized = value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
14
|
+
return normalized.slice(0, 120) || "sprite";
|
|
15
|
+
}
|
|
16
|
+
async function sha256(path) {
|
|
17
|
+
return createHash("sha256").update(await readFile(path)).digest("hex");
|
|
18
|
+
}
|
|
19
|
+
function checkpointRoot(registry, workspaceId, filePath) {
|
|
20
|
+
const workspace = registry.getWorkspace(workspaceId);
|
|
21
|
+
return registry.resolveArtifactPath(workspace, `checkpoints/${safeSegment(filePath)}`, "aseprite");
|
|
22
|
+
}
|
|
23
|
+
function asepriteUserDataRoot() {
|
|
24
|
+
if (process.env.ASEPRITE_USER_DATA_DIR?.trim())
|
|
25
|
+
return process.env.ASEPRITE_USER_DATA_DIR.trim();
|
|
26
|
+
if (process.platform === "win32" && process.env.APPDATA)
|
|
27
|
+
return join(process.env.APPDATA, "Aseprite");
|
|
28
|
+
if (process.platform === "darwin")
|
|
29
|
+
return join(homedir(), "Library", "Application Support", "Aseprite");
|
|
30
|
+
return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "aseprite");
|
|
31
|
+
}
|
|
32
|
+
async function assertTreeContainsNoSymlinks(path) {
|
|
33
|
+
const info = await lstat(path);
|
|
34
|
+
if (info.isSymbolicLink())
|
|
35
|
+
throw new Error(`Symbolic links are not allowed in extension packages: ${path}`);
|
|
36
|
+
if (!info.isDirectory())
|
|
37
|
+
return;
|
|
38
|
+
for (const entry of await readdir(path, { withFileTypes: true })) {
|
|
39
|
+
await assertTreeContainsNoSymlinks(join(path, entry.name));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function directorySize(path) {
|
|
43
|
+
let total = 0;
|
|
44
|
+
for (const entry of await readdir(path, { withFileTypes: true }).catch(() => [])) {
|
|
45
|
+
const child = join(path, entry.name);
|
|
46
|
+
if (entry.isDirectory())
|
|
47
|
+
total += await directorySize(child);
|
|
48
|
+
else if (entry.isFile())
|
|
49
|
+
total += (await stat(child)).size;
|
|
50
|
+
}
|
|
51
|
+
return total;
|
|
52
|
+
}
|
|
53
|
+
export async function assertAsepriteExpectedVersion(registry, workspaceId, filePath, expectedVersion) {
|
|
54
|
+
const file = workspacePath(registry, workspaceId, filePath);
|
|
55
|
+
const actual = await sha256(file.absolute);
|
|
56
|
+
if (expectedVersion && expectedVersion !== actual) {
|
|
57
|
+
throw new Error(`Aseprite file changed since it was inspected. Expected ${expectedVersion}, current ${actual}.`);
|
|
58
|
+
}
|
|
59
|
+
return actual;
|
|
60
|
+
}
|
|
61
|
+
export async function asepriteFileSafety(config, registry, input) {
|
|
62
|
+
try {
|
|
63
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
64
|
+
const root = checkpointRoot(registry, input.workspaceId, file.relative);
|
|
65
|
+
await mkdir(root, { recursive: true });
|
|
66
|
+
if (input.action === "status" || input.action === "assert_version") {
|
|
67
|
+
const info = await stat(file.absolute);
|
|
68
|
+
const version = await assertAsepriteExpectedVersion(registry, input.workspaceId, input.filePath, input.action === "assert_version" ? input.expectedVersion : undefined);
|
|
69
|
+
return textResponse({
|
|
70
|
+
file: file.relative,
|
|
71
|
+
version,
|
|
72
|
+
size: info.size,
|
|
73
|
+
modifiedAt: info.mtime.toISOString(),
|
|
74
|
+
asepriteRunning: (await import("../integration-discovery.js")).processDetected(await (await import("../integration-discovery.js")).discoverLocalIntegrations({ forceRefresh: true }), "aseprite"),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (input.action === "checkpoint") {
|
|
78
|
+
const version = await assertAsepriteExpectedVersion(registry, input.workspaceId, input.filePath, input.expectedVersion);
|
|
79
|
+
const id = `${new Date().toISOString().replace(/[:.]/g, "-")}-${version.slice(0, 12)}`;
|
|
80
|
+
const extension = extname(file.absolute) || ".aseprite";
|
|
81
|
+
const copyPath = join(root, `${id}${extension}`);
|
|
82
|
+
const metadataPath = join(root, `${id}.json`);
|
|
83
|
+
await copyFile(file.absolute, copyPath);
|
|
84
|
+
await writeFile(metadataPath, JSON.stringify({
|
|
85
|
+
id,
|
|
86
|
+
file: file.relative,
|
|
87
|
+
version,
|
|
88
|
+
label: input.label?.trim() || undefined,
|
|
89
|
+
createdAt: new Date().toISOString(),
|
|
90
|
+
copyFile: basename(copyPath),
|
|
91
|
+
}, null, 2), "utf8");
|
|
92
|
+
return textResponse({ checkpointId: id, file: file.relative, version });
|
|
93
|
+
}
|
|
94
|
+
const metadataFiles = (await readdir(root)).filter((name) => name.endsWith(".json")).sort().reverse();
|
|
95
|
+
const checkpoints = [];
|
|
96
|
+
for (const name of metadataFiles) {
|
|
97
|
+
try {
|
|
98
|
+
checkpoints.push(JSON.parse(await readFile(join(root, name), "utf8")));
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
checkpoints.push({ id: name.slice(0, -5), invalidMetadata: true });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (input.action === "list_checkpoints")
|
|
105
|
+
return textResponse({ file: file.relative, checkpoints });
|
|
106
|
+
const id = input.checkpointId?.trim();
|
|
107
|
+
if (!id || !/^[a-zA-Z0-9._-]+$/.test(id))
|
|
108
|
+
throw new Error("A valid checkpointId is required.");
|
|
109
|
+
const metadata = checkpoints.find((item) => item.id === id);
|
|
110
|
+
if (!metadata)
|
|
111
|
+
throw new Error(`Checkpoint ${id} was not found.`);
|
|
112
|
+
const copyPath = join(root, metadata.copyFile);
|
|
113
|
+
if (input.action === "delete_checkpoint") {
|
|
114
|
+
await rm(copyPath, { force: true });
|
|
115
|
+
await rm(join(root, `${id}.json`), { force: true });
|
|
116
|
+
return textResponse({ deleted: id });
|
|
117
|
+
}
|
|
118
|
+
await assertAsepriteExpectedVersion(registry, input.workspaceId, input.filePath, input.expectedVersion);
|
|
119
|
+
const temporary = `${file.absolute}.auvrynt-rollback-${Date.now()}`;
|
|
120
|
+
await copyFile(copyPath, temporary);
|
|
121
|
+
await rename(temporary, file.absolute);
|
|
122
|
+
return textResponse({
|
|
123
|
+
restored: id,
|
|
124
|
+
file: file.relative,
|
|
125
|
+
version: await sha256(file.absolute),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function presetDirectory(registry, workspaceId) {
|
|
133
|
+
const workspace = registry.getWorkspace(workspaceId);
|
|
134
|
+
return registry.resolvePath(workspace, ".auvrynt/aseprite-export-presets");
|
|
135
|
+
}
|
|
136
|
+
async function runExtendedExport(config, registry, workspaceId, preset) {
|
|
137
|
+
const workspace = registry.getWorkspace(workspaceId);
|
|
138
|
+
const executable = await resolveAsepriteExecutable(config);
|
|
139
|
+
const source = workspacePath(registry, workspaceId, preset.filePath);
|
|
140
|
+
const sheet = workspacePath(registry, workspaceId, preset.sheetPath);
|
|
141
|
+
const data = preset.dataPath ? workspacePath(registry, workspaceId, preset.dataPath) : undefined;
|
|
142
|
+
await mkdir(dirname(sheet.absolute), { recursive: true });
|
|
143
|
+
if (data)
|
|
144
|
+
await mkdir(dirname(data.absolute), { recursive: true });
|
|
145
|
+
const args = ["-b", source.absolute, "--sheet", sheet.absolute, "--sheet-type", preset.sheetType ?? "horizontal"];
|
|
146
|
+
if (data)
|
|
147
|
+
args.push("--data", data.absolute, "--format", preset.dataFormat ?? "json-array");
|
|
148
|
+
if (preset.columns)
|
|
149
|
+
args.push("--sheet-columns", String(preset.columns));
|
|
150
|
+
if (preset.rows)
|
|
151
|
+
args.push("--sheet-rows", String(preset.rows));
|
|
152
|
+
if (preset.sheetWidth)
|
|
153
|
+
args.push("--sheet-width", String(preset.sheetWidth));
|
|
154
|
+
if (preset.sheetHeight)
|
|
155
|
+
args.push("--sheet-height", String(preset.sheetHeight));
|
|
156
|
+
if (preset.tag)
|
|
157
|
+
args.push("--tag", preset.tag);
|
|
158
|
+
if (preset.layer)
|
|
159
|
+
args.push("--layer", preset.layer);
|
|
160
|
+
for (const ignored of preset.ignoreLayers ?? [])
|
|
161
|
+
args.push("--ignore-layer", ignored);
|
|
162
|
+
if (preset.allLayers)
|
|
163
|
+
args.push("--all-layers");
|
|
164
|
+
if (preset.splitLayers)
|
|
165
|
+
args.push("--split-layers");
|
|
166
|
+
if (preset.splitTags)
|
|
167
|
+
args.push("--split-tags");
|
|
168
|
+
if (preset.splitSlices)
|
|
169
|
+
args.push("--split-slices");
|
|
170
|
+
if (preset.splitGrid)
|
|
171
|
+
args.push("--split-grid");
|
|
172
|
+
if (preset.playSubtags)
|
|
173
|
+
args.push("--play-subtags");
|
|
174
|
+
if (preset.ignoreEmpty)
|
|
175
|
+
args.push("--ignore-empty");
|
|
176
|
+
if (preset.trim)
|
|
177
|
+
args.push("--trim");
|
|
178
|
+
if (preset.trimSprite)
|
|
179
|
+
args.push("--trim-sprite");
|
|
180
|
+
if (preset.trimByGrid)
|
|
181
|
+
args.push("--trim-by-grid");
|
|
182
|
+
if (preset.extrude)
|
|
183
|
+
args.push("--extrude");
|
|
184
|
+
if (preset.mergeDuplicates)
|
|
185
|
+
args.push("--merge-duplicates");
|
|
186
|
+
if (preset.borderPadding !== undefined)
|
|
187
|
+
args.push("--border-padding", String(preset.borderPadding));
|
|
188
|
+
if (preset.shapePadding !== undefined)
|
|
189
|
+
args.push("--shape-padding", String(preset.shapePadding));
|
|
190
|
+
if (preset.innerPadding !== undefined)
|
|
191
|
+
args.push("--inner-padding", String(preset.innerPadding));
|
|
192
|
+
if (preset.filenameFormat)
|
|
193
|
+
args.push("--filename-format", preset.filenameFormat);
|
|
194
|
+
if (preset.tagnameFormat)
|
|
195
|
+
args.push("--tagname-format", preset.tagnameFormat);
|
|
196
|
+
const { stdout, stderr } = await execFileAsync(executable, args, {
|
|
197
|
+
cwd: workspace.root,
|
|
198
|
+
timeout: 120_000,
|
|
199
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
200
|
+
windowsHide: true,
|
|
201
|
+
});
|
|
202
|
+
return {
|
|
203
|
+
source: source.relative,
|
|
204
|
+
sheet: sheet.relative,
|
|
205
|
+
data: data?.relative,
|
|
206
|
+
output: sanitizeCliOutput([stdout.trim(), stderr.trim()].filter(Boolean).join("\n")).slice(-4000),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function validateExportData(config, registry, workspaceId, preset) {
|
|
210
|
+
const source = workspacePath(registry, workspaceId, preset.filePath);
|
|
211
|
+
const sheet = workspacePath(registry, workspaceId, preset.sheetPath);
|
|
212
|
+
const data = preset.dataPath ? workspacePath(registry, workspaceId, preset.dataPath) : undefined;
|
|
213
|
+
const problems = [];
|
|
214
|
+
if (!existsSync(sheet.absolute))
|
|
215
|
+
problems.push({ code: "missing_sheet", path: sheet.relative });
|
|
216
|
+
let metadataFrames = [];
|
|
217
|
+
if (data) {
|
|
218
|
+
if (!existsSync(data.absolute))
|
|
219
|
+
problems.push({ code: "missing_metadata", path: data.relative });
|
|
220
|
+
else {
|
|
221
|
+
const parsed = JSON.parse(await readFile(data.absolute, "utf8"));
|
|
222
|
+
const frames = parsed.frames ?? parsed;
|
|
223
|
+
metadataFrames = Array.isArray(frames)
|
|
224
|
+
? frames
|
|
225
|
+
: frames && typeof frames === "object"
|
|
226
|
+
? Object.values(frames)
|
|
227
|
+
: [];
|
|
228
|
+
const rectangles = metadataFrames.map((entry, index) => ({
|
|
229
|
+
index,
|
|
230
|
+
x: entry.frame?.x,
|
|
231
|
+
y: entry.frame?.y,
|
|
232
|
+
width: entry.frame?.w ?? entry.frame?.width,
|
|
233
|
+
height: entry.frame?.h ?? entry.frame?.height,
|
|
234
|
+
})).filter((rect) => [rect.x, rect.y, rect.width, rect.height].every(Number.isFinite));
|
|
235
|
+
for (let i = 0; i < rectangles.length; i++) {
|
|
236
|
+
for (let j = i + 1; j < rectangles.length; j++) {
|
|
237
|
+
const a = rectangles[i];
|
|
238
|
+
const b = rectangles[j];
|
|
239
|
+
const overlap = a.x < b.x + b.width && a.x + a.width > b.x
|
|
240
|
+
&& a.y < b.y + b.height && a.y + a.height > b.y;
|
|
241
|
+
if (overlap)
|
|
242
|
+
problems.push({ code: "overlapping_frames", first: a.index, second: b.index });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const sourceInfo = await runLua(config, registry, workspaceId, `
|
|
248
|
+
${openSpriteScript(source.absolute)}
|
|
249
|
+
local count=#sprite.frames
|
|
250
|
+
if ${preset.tag ? "true" : "false"} then
|
|
251
|
+
local found=nil
|
|
252
|
+
for _,tag in ipairs(sprite.tags) do if tag.name==${luaString(preset.tag ?? "")} then found=tag break end end
|
|
253
|
+
if found==nil then fail("Configured export tag was not found") end
|
|
254
|
+
count=found.toFrame.frameNumber-found.fromFrame.frameNumber+1
|
|
255
|
+
end
|
|
256
|
+
emit_result({expected_frames=count,summary=sprite_summary(sprite)})
|
|
257
|
+
sprite:close()
|
|
258
|
+
`);
|
|
259
|
+
if (data && !preset.mergeDuplicates && metadataFrames.length !== sourceInfo.expected_frames) {
|
|
260
|
+
problems.push({ code: "frame_count_mismatch", expected: sourceInfo.expected_frames, actual: metadataFrames.length });
|
|
261
|
+
}
|
|
262
|
+
return { valid: problems.length === 0, problems, source: sourceInfo.summary, metadataFrames: metadataFrames.length };
|
|
263
|
+
}
|
|
264
|
+
export async function asepriteManageExportPreset(config, registry, input) {
|
|
265
|
+
try {
|
|
266
|
+
const directory = presetDirectory(registry, input.workspaceId);
|
|
267
|
+
await mkdir(directory, { recursive: true });
|
|
268
|
+
const lastPath = join(directory, "_last-export.json");
|
|
269
|
+
if (input.action === "list") {
|
|
270
|
+
const names = (await readdir(directory)).filter((name) => name.endsWith(".json") && name !== "_last-export.json").map((name) => name.slice(0, -5));
|
|
271
|
+
return textResponse({ presets: names.sort() });
|
|
272
|
+
}
|
|
273
|
+
const name = input.name?.trim();
|
|
274
|
+
if (input.action !== "repeat" && (!name || !/^[a-zA-Z0-9._-]+$/.test(name)))
|
|
275
|
+
throw new Error("A valid preset name is required.");
|
|
276
|
+
const path = name ? join(directory, `${name}.json`) : lastPath;
|
|
277
|
+
if (input.action === "save") {
|
|
278
|
+
if (!input.preset)
|
|
279
|
+
throw new Error("preset is required.");
|
|
280
|
+
await writeFile(path, JSON.stringify(input.preset, null, 2), "utf8");
|
|
281
|
+
return textResponse({ saved: name });
|
|
282
|
+
}
|
|
283
|
+
if (input.action === "delete") {
|
|
284
|
+
await rm(path, { force: true });
|
|
285
|
+
return textResponse({ deleted: name });
|
|
286
|
+
}
|
|
287
|
+
const preset = input.action === "repeat"
|
|
288
|
+
? JSON.parse(await readFile(lastPath, "utf8"))
|
|
289
|
+
: JSON.parse(await readFile(path, "utf8"));
|
|
290
|
+
if (input.action === "validate")
|
|
291
|
+
return textResponse(await validateExportData(config, registry, input.workspaceId, preset));
|
|
292
|
+
const result = await runExtendedExport(config, registry, input.workspaceId, preset);
|
|
293
|
+
await writeFile(lastPath, JSON.stringify(preset, null, 2), "utf8");
|
|
294
|
+
return textResponse({ ...result, validation: await validateExportData(config, registry, input.workspaceId, preset) });
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
export async function asepriteBatchProcess(config, registry, input) {
|
|
301
|
+
try {
|
|
302
|
+
if (!Array.isArray(input.filePaths) || input.filePaths.length === 0)
|
|
303
|
+
throw new Error("filePaths must not be empty.");
|
|
304
|
+
if (input.filePaths.length > MAX_BATCH_FILES)
|
|
305
|
+
throw new Error(`A maximum of ${MAX_BATCH_FILES} files is supported.`);
|
|
306
|
+
if (!input.inPlace && input.operation !== "audit" && !input.outputDirectory)
|
|
307
|
+
throw new Error("outputDirectory is required unless inPlace is true.");
|
|
308
|
+
const plan = input.filePaths.map((filePath) => ({ filePath, operation: input.operation }));
|
|
309
|
+
if (input.dryRun)
|
|
310
|
+
return textResponse({ dryRun: true, plan });
|
|
311
|
+
const results = [];
|
|
312
|
+
for (const filePath of input.filePaths) {
|
|
313
|
+
const source = workspacePath(registry, input.workspaceId, filePath);
|
|
314
|
+
if (input.operation === "audit") {
|
|
315
|
+
const response = await asepriteAuditSprite(config, registry, { workspaceId: input.workspaceId, filePath });
|
|
316
|
+
results.push({ filePath, response: response.content[0]?.type === "text" ? response.content[0].text : response });
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (input.inPlace) {
|
|
320
|
+
await asepriteFileSafety(config, registry, {
|
|
321
|
+
workspaceId: input.workspaceId,
|
|
322
|
+
filePath,
|
|
323
|
+
action: "checkpoint",
|
|
324
|
+
label: `batch-${input.operation}`,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
const outputPath = input.inPlace
|
|
328
|
+
? filePath
|
|
329
|
+
: `${input.outputDirectory.replace(/[\\/]$/, "")}/${basename(filePath)}`;
|
|
330
|
+
if (input.operation === "convert") {
|
|
331
|
+
const response = await asepriteConvertFile(config, registry, {
|
|
332
|
+
workspaceId: input.workspaceId,
|
|
333
|
+
filePath,
|
|
334
|
+
outputPath,
|
|
335
|
+
scale: input.scale,
|
|
336
|
+
colorMode: input.colorMode,
|
|
337
|
+
palettePath: input.palettePath,
|
|
338
|
+
trim: input.trim,
|
|
339
|
+
});
|
|
340
|
+
results.push({ filePath, outputPath, response: response.content[0]?.type === "text" ? response.content[0].text : response });
|
|
341
|
+
}
|
|
342
|
+
else if (input.operation === "export") {
|
|
343
|
+
const base = basename(filePath, extname(filePath));
|
|
344
|
+
const sheetPath = `${input.outputDirectory.replace(/[\\/]$/, "")}/${base}.png`;
|
|
345
|
+
const dataPath = `${input.outputDirectory.replace(/[\\/]$/, "")}/${base}.json`;
|
|
346
|
+
const response = await asepriteExportSpriteSheet(config, registry, {
|
|
347
|
+
workspaceId: input.workspaceId,
|
|
348
|
+
filePath,
|
|
349
|
+
sheetPath,
|
|
350
|
+
dataPath,
|
|
351
|
+
sheetType: input.sheetType,
|
|
352
|
+
trim: input.trim,
|
|
353
|
+
});
|
|
354
|
+
results.push({ filePath, sheetPath, dataPath, response: response.content[0]?.type === "text" ? response.content[0].text : response });
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
const response = await asepriteMaintenance(config, registry, {
|
|
358
|
+
workspaceId: input.workspaceId,
|
|
359
|
+
action: "repair",
|
|
360
|
+
filePath,
|
|
361
|
+
outputPath,
|
|
362
|
+
});
|
|
363
|
+
results.push({ filePath, outputPath, response: response.content[0]?.type === "text" ? response.content[0].text : response });
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return textResponse({ processed: results.length, results });
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
export async function asepriteMaintenance(config, registry, input) {
|
|
373
|
+
try {
|
|
374
|
+
const source = workspacePath(registry, input.workspaceId, input.filePath);
|
|
375
|
+
if (input.action === "validate") {
|
|
376
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
377
|
+
${openSpriteScript(source.absolute)}
|
|
378
|
+
emit_result({valid=true,summary=sprite_summary(sprite),modified=sprite.isModified})
|
|
379
|
+
sprite:close()
|
|
380
|
+
`);
|
|
381
|
+
return textResponse(result);
|
|
382
|
+
}
|
|
383
|
+
if (!input.outputPath)
|
|
384
|
+
throw new Error("outputPath is required.");
|
|
385
|
+
const output = workspacePath(registry, input.workspaceId, input.outputPath);
|
|
386
|
+
await mkdir(dirname(output.absolute), { recursive: true });
|
|
387
|
+
if (input.action === "repair") {
|
|
388
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
389
|
+
${openSpriteScript(source.absolute)}
|
|
390
|
+
if not sprite:saveCopyAs(${luaString(output.absolute)}) then fail("Unable to save repaired copy") end
|
|
391
|
+
local reopened=app.open(${luaString(output.absolute)})
|
|
392
|
+
if reopened==nil then fail("Repaired copy could not be reopened") end
|
|
393
|
+
emit_result({source=${luaString(source.relative)},output=${luaString(output.relative)},summary=sprite_summary(reopened)})
|
|
394
|
+
reopened:close() sprite:close()
|
|
395
|
+
`);
|
|
396
|
+
return textResponse(result);
|
|
397
|
+
}
|
|
398
|
+
const workspace = registry.getWorkspace(input.workspaceId);
|
|
399
|
+
const executable = await resolveAsepriteExecutable(config);
|
|
400
|
+
const format = input.intermediateFormat ?? "png";
|
|
401
|
+
const intermediate = registry.resolveArtifactPath(workspace, `roundtrip/${Date.now()}.${format}`, "aseprite");
|
|
402
|
+
await mkdir(dirname(intermediate), { recursive: true });
|
|
403
|
+
await execFileAsync(executable, ["-b", source.absolute, "--save-as", intermediate], { cwd: workspace.root, timeout: 120_000, windowsHide: true });
|
|
404
|
+
await execFileAsync(executable, ["-b", intermediate, "--save-as", output.absolute], { cwd: workspace.root, timeout: 120_000, windowsHide: true });
|
|
405
|
+
const comparison = await asepriteCompareDocuments(config, registry, {
|
|
406
|
+
workspaceId: input.workspaceId,
|
|
407
|
+
referencePath: input.filePath,
|
|
408
|
+
candidatePath: input.outputPath,
|
|
409
|
+
comparePixels: true,
|
|
410
|
+
});
|
|
411
|
+
return textResponse({
|
|
412
|
+
source: source.relative,
|
|
413
|
+
output: output.relative,
|
|
414
|
+
intermediateFormat: format,
|
|
415
|
+
comparison: comparison.content[0]?.type === "text" ? JSON.parse(comparison.content[0].text) : comparison,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
async function listRecoverySessions() {
|
|
423
|
+
const sessionsRoot = join(asepriteUserDataRoot(), "sessions");
|
|
424
|
+
const entries = await readdir(sessionsRoot, { withFileTypes: true }).catch(() => []);
|
|
425
|
+
const sessions = [];
|
|
426
|
+
for (const entry of entries) {
|
|
427
|
+
if (!entry.isDirectory())
|
|
428
|
+
continue;
|
|
429
|
+
const path = join(sessionsRoot, entry.name);
|
|
430
|
+
const info = await stat(path);
|
|
431
|
+
const documents = (await readdir(path, { withFileTypes: true }).catch(() => [])).filter((child) => child.isDirectory()).map((child) => child.name);
|
|
432
|
+
sessions.push({
|
|
433
|
+
id: entry.name,
|
|
434
|
+
modifiedAt: info.mtime.toISOString(),
|
|
435
|
+
bytes: await directorySize(path),
|
|
436
|
+
documents,
|
|
437
|
+
activePidFile: existsSync(join(path, "pid")),
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return sessions.sort((a, b) => String(b.modifiedAt).localeCompare(String(a.modifiedAt)));
|
|
441
|
+
}
|
|
442
|
+
export async function asepriteRecovery(config, registry, processManager, input) {
|
|
443
|
+
try {
|
|
444
|
+
const sessionsRoot = join(asepriteUserDataRoot(), "sessions");
|
|
445
|
+
if (input.action === "list")
|
|
446
|
+
return textResponse({ sessions: await listRecoverySessions() });
|
|
447
|
+
if (input.action === "open_recovery_ui") {
|
|
448
|
+
const executable = await resolveAsepriteExecutable(config);
|
|
449
|
+
const command = `"${executable.replace(/"/g, '\\"')}"`;
|
|
450
|
+
return textResponse(processManager.startProcess({
|
|
451
|
+
workspaceId: input.workspaceId,
|
|
452
|
+
command,
|
|
453
|
+
useShell: false,
|
|
454
|
+
}));
|
|
455
|
+
}
|
|
456
|
+
const id = input.sessionId?.trim();
|
|
457
|
+
if (!id || !/^[a-zA-Z0-9._-]+$/.test(id))
|
|
458
|
+
throw new Error("A valid sessionId is required.");
|
|
459
|
+
const source = join(sessionsRoot, id);
|
|
460
|
+
if (!existsSync(source))
|
|
461
|
+
throw new Error(`Recovery session ${id} was not found.`);
|
|
462
|
+
const sourceInfo = await lstat(source);
|
|
463
|
+
if (!sourceInfo.isDirectory() || sourceInfo.isSymbolicLink())
|
|
464
|
+
throw new Error("Recovery session is not a real directory.");
|
|
465
|
+
if (input.action === "archive") {
|
|
466
|
+
if (!input.outputDirectory)
|
|
467
|
+
throw new Error("outputDirectory is required.");
|
|
468
|
+
const target = workspacePath(registry, input.workspaceId, `${input.outputDirectory.replace(/[\\/]$/, "")}/${id}`);
|
|
469
|
+
await cp(source, target.absolute, { recursive: true, force: true });
|
|
470
|
+
return textResponse({ archived: id, output: target.relative, note: "Open Aseprite's Recovery UI to reconstruct the archived native session." });
|
|
471
|
+
}
|
|
472
|
+
if (!input.allowGlobalWrite)
|
|
473
|
+
throw new Error("allowGlobalWrite=true is required to discard an Aseprite recovery session.");
|
|
474
|
+
await rm(source, { recursive: true, force: true });
|
|
475
|
+
return textResponse({ discarded: id });
|
|
476
|
+
}
|
|
477
|
+
catch (error) {
|
|
478
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
async function readExtensionManifests() {
|
|
482
|
+
const root = join(asepriteUserDataRoot(), "extensions");
|
|
483
|
+
const iniPath = join(asepriteUserDataRoot(), "aseprite.ini");
|
|
484
|
+
const ini = await readFile(iniPath, "utf8").catch(() => "");
|
|
485
|
+
const enabledMap = new Map();
|
|
486
|
+
const section = ini.match(/(?:^|\r?\n)\[extensions\]\r?\n([\s\S]*?)(?=\r?\n\[|$)/i)?.[1] ?? "";
|
|
487
|
+
for (const line of section.split(/\r?\n/)) {
|
|
488
|
+
const match = line.match(/^([^=]+)=(true|false|yes|no|1|0)$/i);
|
|
489
|
+
if (match)
|
|
490
|
+
enabledMap.set(match[1].trim(), /^(true|yes|1)$/i.test(match[2]));
|
|
491
|
+
}
|
|
492
|
+
const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
|
|
493
|
+
const extensions = [];
|
|
494
|
+
for (const entry of entries) {
|
|
495
|
+
if (!entry.isDirectory())
|
|
496
|
+
continue;
|
|
497
|
+
const manifestPath = join(root, entry.name, "package.json");
|
|
498
|
+
let manifest = {};
|
|
499
|
+
try {
|
|
500
|
+
manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
501
|
+
}
|
|
502
|
+
catch {
|
|
503
|
+
manifest = { invalidManifest: true };
|
|
504
|
+
}
|
|
505
|
+
const name = String(manifest.name ?? entry.name);
|
|
506
|
+
extensions.push({
|
|
507
|
+
directory: entry.name,
|
|
508
|
+
name,
|
|
509
|
+
displayName: manifest.displayName,
|
|
510
|
+
version: manifest.version,
|
|
511
|
+
description: manifest.description,
|
|
512
|
+
enabled: enabledMap.get(name) ?? true,
|
|
513
|
+
contributes: manifest.contributes,
|
|
514
|
+
invalidManifest: manifest.invalidManifest,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
return extensions;
|
|
518
|
+
}
|
|
519
|
+
async function setExtensionEnabled(name, enabled) {
|
|
520
|
+
const iniPath = join(asepriteUserDataRoot(), "aseprite.ini");
|
|
521
|
+
let ini = await readFile(iniPath, "utf8").catch(() => "");
|
|
522
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
523
|
+
const sectionPattern = /(^|\r?\n)\[extensions\]\r?\n([\s\S]*?)(?=\r?\n\[|$)/i;
|
|
524
|
+
const match = ini.match(sectionPattern);
|
|
525
|
+
const value = `${name}=${enabled ? "true" : "false"}`;
|
|
526
|
+
if (match) {
|
|
527
|
+
let body = match[2];
|
|
528
|
+
const keyPattern = new RegExp(`^${escaped}=.*$`, "mi");
|
|
529
|
+
body = keyPattern.test(body) ? body.replace(keyPattern, value) : `${body.trimEnd()}\r\n${value}\r\n`;
|
|
530
|
+
ini = ini.replace(sectionPattern, `${match[1]}[extensions]\r\n${body}`);
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
ini = `${ini.trimEnd()}\r\n\r\n[extensions]\r\n${value}\r\n`;
|
|
534
|
+
}
|
|
535
|
+
await writeFile(iniPath, ini, "utf8");
|
|
536
|
+
}
|
|
537
|
+
export async function asepriteExtensions(registry, input) {
|
|
538
|
+
try {
|
|
539
|
+
registry.getWorkspace(input.workspaceId);
|
|
540
|
+
const root = asepriteUserDataRoot();
|
|
541
|
+
if (input.action === "list_extensions")
|
|
542
|
+
return textResponse({ root, extensions: await readExtensionManifests() });
|
|
543
|
+
if (input.action === "list_resources") {
|
|
544
|
+
const resources = {};
|
|
545
|
+
for (const name of ["extensions", "palettes", "scripts", "themes", "brushes", "files", "sessions"]) {
|
|
546
|
+
const path = join(root, name);
|
|
547
|
+
resources[name] = (await readdir(path).catch(() => [])).sort();
|
|
548
|
+
}
|
|
549
|
+
const standalone = (await readdir(root).catch(() => [])).filter((name) => /\.(aseprite-brushes|aseprite-layouts|ini)$/i.test(name));
|
|
550
|
+
return textResponse({ root, resources, standalone });
|
|
551
|
+
}
|
|
552
|
+
if (input.action === "startup_errors") {
|
|
553
|
+
const logPath = join(root, "Aseprite.log");
|
|
554
|
+
const lines = (await readFile(logPath, "utf8").catch(() => "")).split(/\r?\n/);
|
|
555
|
+
return textResponse({ logPath, errors: lines.filter((line) => /error|failed|exception/i.test(line)).slice(-200) });
|
|
556
|
+
}
|
|
557
|
+
if (!input.allowGlobalWrite)
|
|
558
|
+
throw new Error("allowGlobalWrite=true is required for extension changes.");
|
|
559
|
+
const extensionsRoot = join(root, "extensions");
|
|
560
|
+
await mkdir(extensionsRoot, { recursive: true });
|
|
561
|
+
if (input.action === "install") {
|
|
562
|
+
if (!input.sourceDirectoryPath)
|
|
563
|
+
throw new Error("sourceDirectoryPath is required.");
|
|
564
|
+
const source = workspacePath(registry, input.workspaceId, input.sourceDirectoryPath);
|
|
565
|
+
const info = await lstat(source.absolute);
|
|
566
|
+
if (!info.isDirectory() || info.isSymbolicLink())
|
|
567
|
+
throw new Error("Extension source must be a real workspace directory.");
|
|
568
|
+
await assertTreeContainsNoSymlinks(source.absolute);
|
|
569
|
+
const manifest = JSON.parse(await readFile(join(source.absolute, "package.json"), "utf8"));
|
|
570
|
+
const name = safeSegment(String(manifest.name ?? basename(source.absolute)));
|
|
571
|
+
const target = join(extensionsRoot, name);
|
|
572
|
+
await cp(source.absolute, target, { recursive: true, force: true, dereference: false });
|
|
573
|
+
await setExtensionEnabled(String(manifest.name ?? name), true);
|
|
574
|
+
return textResponse({ installed: manifest.name ?? name, target, restartRequired: true });
|
|
575
|
+
}
|
|
576
|
+
const name = input.extensionName?.trim();
|
|
577
|
+
if (!name)
|
|
578
|
+
throw new Error("extensionName is required.");
|
|
579
|
+
const extensions = await readExtensionManifests();
|
|
580
|
+
const extension = extensions.find((item) => item.name === name || item.directory === name);
|
|
581
|
+
if (!extension)
|
|
582
|
+
throw new Error(`Extension ${name} was not found.`);
|
|
583
|
+
if (input.action === "enable" || input.action === "disable") {
|
|
584
|
+
await setExtensionEnabled(extension.name, input.action === "enable");
|
|
585
|
+
return textResponse({ extension: extension.name, enabled: input.action === "enable", restartRequired: true });
|
|
586
|
+
}
|
|
587
|
+
await rm(join(extensionsRoot, extension.directory), { recursive: true, force: true });
|
|
588
|
+
await setExtensionEnabled(extension.name, false);
|
|
589
|
+
return textResponse({ removed: extension.name, restartRequired: true });
|
|
590
|
+
}
|
|
591
|
+
catch (error) {
|
|
592
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
593
|
+
}
|
|
594
|
+
}
|