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,141 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { mkdir, readdir, realpath, rm, stat } from "node:fs/promises";
|
|
5
|
+
import { basename, join, relative, resolve } from "node:path";
|
|
6
|
+
import { assertAllowedPath, isPathInsideRoot } from "../roots.js";
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
const MAX_MANAGED_WORKTREES = 16;
|
|
9
|
+
export class GitWorktreeError extends Error {
|
|
10
|
+
code;
|
|
11
|
+
constructor(code, message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.name = "GitWorktreeError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export async function createManagedWorktree(input) {
|
|
18
|
+
const sourcePath = assertAllowedPath(input.sourcePath, input.config.allowedRoots);
|
|
19
|
+
try {
|
|
20
|
+
const sourceStats = await stat(sourcePath);
|
|
21
|
+
if (!sourceStats.isDirectory()) {
|
|
22
|
+
throw new GitWorktreeError("GIT_REPOSITORY_NOT_FOUND", `Cannot open workspace in worktree mode because the source path is not a directory: ${input.sourcePath}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof GitWorktreeError)
|
|
27
|
+
throw error;
|
|
28
|
+
throw new GitWorktreeError("GIT_REPOSITORY_NOT_FOUND", `Cannot open workspace in worktree mode because the source path does not exist: ${input.sourcePath}`);
|
|
29
|
+
}
|
|
30
|
+
const sourceRoot = await resolveGitRoot(sourcePath, input.config.allowedRoots);
|
|
31
|
+
const baseRef = input.baseRef ?? "HEAD";
|
|
32
|
+
const baseSha = await resolveBaseCommit(sourceRoot, baseRef);
|
|
33
|
+
const dirtySource = (await git(["status", "--porcelain=v1"], sourceRoot)).trim().length > 0;
|
|
34
|
+
const worktreePath = managedWorktreePath({
|
|
35
|
+
worktreeRoot: input.config.worktreeRoot,
|
|
36
|
+
repoRoot: sourceRoot,
|
|
37
|
+
});
|
|
38
|
+
await mkdir(input.config.worktreeRoot, { recursive: true });
|
|
39
|
+
assertAllowedPath(worktreePath, [input.config.worktreeRoot]);
|
|
40
|
+
const existing = await readdir(input.config.worktreeRoot).catch(() => []);
|
|
41
|
+
const managedCount = existing.filter((e) => /^[a-zA-Z0-9._-]+-[a-f0-9]{8}$/.test(e)).length;
|
|
42
|
+
if (managedCount >= MAX_MANAGED_WORKTREES) {
|
|
43
|
+
throw new GitWorktreeError("GIT_WORKTREE_CREATE_FAILED", `Cannot create managed worktree: limit of ${MAX_MANAGED_WORKTREES} concurrent managed worktrees reached. Remove unused worktrees and retry.`);
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
await git(["worktree", "add", "--detach", worktreePath, baseSha], sourceRoot);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
await rm(worktreePath, { recursive: true, force: true });
|
|
50
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
51
|
+
throw new GitWorktreeError("GIT_WORKTREE_CREATE_FAILED", `Git failed to create the managed worktree. ${message}`);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
sourceRoot,
|
|
55
|
+
path: worktreePath,
|
|
56
|
+
baseRef,
|
|
57
|
+
baseSha,
|
|
58
|
+
dirtySource,
|
|
59
|
+
detached: true,
|
|
60
|
+
managed: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function resolveGitRoot(path, allowedRoots) {
|
|
64
|
+
try {
|
|
65
|
+
const output = await git(["rev-parse", "--show-toplevel"], path);
|
|
66
|
+
return await assertGitRootAllowed(output.trim(), allowedRoots);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (isGitUnavailable(error)) {
|
|
70
|
+
throw new GitWorktreeError("GIT_NOT_AVAILABLE", "Cannot open workspace in worktree mode because Git is not available on this machine.");
|
|
71
|
+
}
|
|
72
|
+
throw new GitWorktreeError("GIT_REPOSITORY_NOT_FOUND", `Cannot open workspace in worktree mode because this path is not inside a Git repository: ${path}. Use mode=\"checkout\" to work directly in this directory, or initialize Git and create an initial commit first.`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function assertGitRootAllowed(gitRoot, allowedRoots) {
|
|
76
|
+
try {
|
|
77
|
+
return assertAllowedPath(gitRoot, allowedRoots);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
const canonicalGitRoot = await realpath(gitRoot);
|
|
81
|
+
for (const allowedRoot of allowedRoots) {
|
|
82
|
+
const canonicalAllowedRoot = await realpath(allowedRoot).catch(() => undefined);
|
|
83
|
+
if (!canonicalAllowedRoot || !isPathInsideRoot(canonicalGitRoot, canonicalAllowedRoot)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const logicalGitRoot = resolve(allowedRoot, relative(canonicalAllowedRoot, canonicalGitRoot));
|
|
87
|
+
return assertAllowedPath(logicalGitRoot, allowedRoots);
|
|
88
|
+
}
|
|
89
|
+
return assertAllowedPath(canonicalGitRoot, allowedRoots);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async function resolveBaseCommit(sourceRoot, baseRef) {
|
|
93
|
+
try {
|
|
94
|
+
return (await git(["rev-parse", "--verify", `${baseRef}^{commit}`], sourceRoot)).trim();
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (baseRef === "HEAD") {
|
|
98
|
+
throw new GitWorktreeError("GIT_REPOSITORY_HAS_NO_COMMITS", "Cannot open workspace in worktree mode because the repository has no commits yet. Create an initial commit first, or use mode=\"checkout\".");
|
|
99
|
+
}
|
|
100
|
+
throw new GitWorktreeError("GIT_INVALID_BASE_REF", `Cannot open workspace in worktree mode because baseRef ${JSON.stringify(baseRef)} does not resolve to a commit.`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function managedWorktreePath(input) {
|
|
104
|
+
const repoName = sanitizePathSegment(basename(input.repoRoot)) || "repo";
|
|
105
|
+
const worktreeId = randomBytes(4).toString("hex");
|
|
106
|
+
return join(input.worktreeRoot, `${repoName}-${worktreeId}`);
|
|
107
|
+
}
|
|
108
|
+
function sanitizePathSegment(value) {
|
|
109
|
+
return value
|
|
110
|
+
.replace(/[^a-zA-Z0-9._-]+/g, "-")
|
|
111
|
+
.replace(/^-+|-+$/g, "")
|
|
112
|
+
.slice(0, 80);
|
|
113
|
+
}
|
|
114
|
+
async function git(args, cwd) {
|
|
115
|
+
try {
|
|
116
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
117
|
+
cwd,
|
|
118
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
119
|
+
windowsHide: true,
|
|
120
|
+
});
|
|
121
|
+
return stdout;
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (isGitUnavailable(error))
|
|
125
|
+
throw error;
|
|
126
|
+
const stderr = typeof error === "object" && error && "stderr" in error
|
|
127
|
+
? String(error.stderr ?? "").trim()
|
|
128
|
+
: "";
|
|
129
|
+
const stdout = typeof error === "object" && error && "stdout" in error
|
|
130
|
+
? String(error.stdout ?? "").trim()
|
|
131
|
+
: "";
|
|
132
|
+
const details = stderr || stdout || (error instanceof Error ? error.message : String(error));
|
|
133
|
+
throw new Error(details);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function isGitUnavailable(error) {
|
|
137
|
+
return Boolean(typeof error === "object" &&
|
|
138
|
+
error &&
|
|
139
|
+
"code" in error &&
|
|
140
|
+
error.code === "ENOENT");
|
|
141
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
export async function git(cwd, args, options = {}) {
|
|
6
|
+
const { stdout, stderr } = await execFileAsync("git", args, {
|
|
7
|
+
cwd,
|
|
8
|
+
env: options.env ? { ...process.env, ...options.env } : process.env,
|
|
9
|
+
maxBuffer: options.maxBuffer ?? 10 * 1024 * 1024,
|
|
10
|
+
windowsHide: true,
|
|
11
|
+
});
|
|
12
|
+
return { stdout, stderr };
|
|
13
|
+
}
|
|
14
|
+
export async function getGitEligibility(cwd) {
|
|
15
|
+
try {
|
|
16
|
+
await git(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return {
|
|
20
|
+
ok: false,
|
|
21
|
+
reason: "not_git",
|
|
22
|
+
message: "workspace is not inside a git repository",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const gitRoot = (await git(cwd, ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
26
|
+
try {
|
|
27
|
+
await git(gitRoot, ["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
gitRoot,
|
|
33
|
+
reason: "no_head",
|
|
34
|
+
message: "repository has no HEAD commit",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return { ok: true, gitRoot };
|
|
38
|
+
}
|
|
39
|
+
export function safeWorkspaceRefSegment(workspaceId) {
|
|
40
|
+
const safe = workspaceId.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
41
|
+
return safe.length > 0 ? safe : createHash("sha256").update(workspaceId).digest("hex").slice(0, 16);
|
|
42
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { git, getGitEligibility, safeWorkspaceRefSegment } from "./git.js";
|
|
5
|
+
const REVIEW_REF_PREFIX = "refs/auvrynt/review";
|
|
6
|
+
export function createReviewCheckpointManager() {
|
|
7
|
+
const states = new Map();
|
|
8
|
+
return {
|
|
9
|
+
async initializeWorkspace({ workspaceId, root }) {
|
|
10
|
+
const refs = reviewRefs(workspaceId);
|
|
11
|
+
const state = { root, ...refs };
|
|
12
|
+
states.set(workspaceId, state);
|
|
13
|
+
try {
|
|
14
|
+
const eligibility = await getGitEligibility(root);
|
|
15
|
+
if (!eligibility.ok || !eligibility.gitRoot) {
|
|
16
|
+
state.diagnostic = eligibility.message ?? "show_changes requires a Git workspace in this version.";
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
state.gitRoot = eligibility.gitRoot;
|
|
20
|
+
const commit = await createWorkingTreeSnapshot(eligibility.gitRoot);
|
|
21
|
+
await git(eligibility.gitRoot, ["update-ref", state.openRef, commit]);
|
|
22
|
+
await git(eligibility.gitRoot, ["update-ref", state.baselineRef, commit]);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
state.diagnostic = error instanceof Error ? error.message : String(error);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
async reviewChanges({ workspaceId, root, since = "last_shown", markReviewed = true }) {
|
|
29
|
+
let state = states.get(workspaceId);
|
|
30
|
+
if (!state) {
|
|
31
|
+
await this.initializeWorkspace({ workspaceId, root });
|
|
32
|
+
state = states.get(workspaceId);
|
|
33
|
+
}
|
|
34
|
+
if (!state?.gitRoot) {
|
|
35
|
+
throw new Error(state?.diagnostic ?? "show_changes requires a Git workspace in this version.");
|
|
36
|
+
}
|
|
37
|
+
const baselineRef = since === "workspace_open" ? state.openRef : state.baselineRef;
|
|
38
|
+
const baseline = (await git(state.gitRoot, ["rev-parse", "--verify", `${baselineRef}^{commit}`])).stdout.trim();
|
|
39
|
+
const current = await createWorkingTreeSnapshot(state.gitRoot);
|
|
40
|
+
const patch = (await git(state.gitRoot, ["diff", "--binary", "--no-color", baseline, current], {
|
|
41
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
42
|
+
})).stdout;
|
|
43
|
+
const numstat = (await git(state.gitRoot, ["diff", "--numstat", "-z", baseline, current], {
|
|
44
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
45
|
+
})).stdout;
|
|
46
|
+
const files = parseNumstat(numstat);
|
|
47
|
+
const summary = summarizeFiles(files);
|
|
48
|
+
if (markReviewed) {
|
|
49
|
+
await git(state.gitRoot, ["update-ref", state.baselineRef, current]);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
result: summary.files === 0
|
|
53
|
+
? `No changes since ${since === "workspace_open" ? "workspace open" : "last shown changes"}.`
|
|
54
|
+
: `Changed ${summary.files} ${summary.files === 1 ? "file" : "files"} (+${summary.additions} -${summary.removals}).`,
|
|
55
|
+
summary,
|
|
56
|
+
files,
|
|
57
|
+
patch,
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function reviewRefs(workspaceId) {
|
|
63
|
+
const segment = safeWorkspaceRefSegment(workspaceId);
|
|
64
|
+
return {
|
|
65
|
+
openRef: `${REVIEW_REF_PREFIX}/${segment}/open`,
|
|
66
|
+
baselineRef: `${REVIEW_REF_PREFIX}/${segment}/baseline`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function createWorkingTreeSnapshot(gitRoot) {
|
|
70
|
+
const tempDir = await mkdtemp(join(tmpdir(), "auvrynt-review-index-"));
|
|
71
|
+
const indexPath = join(tempDir, "index");
|
|
72
|
+
const env = checkpointEnv(indexPath);
|
|
73
|
+
try {
|
|
74
|
+
await git(gitRoot, ["read-tree", "HEAD"], { env });
|
|
75
|
+
await git(gitRoot, ["add", "-A", "--", "."], { env });
|
|
76
|
+
const tree = (await git(gitRoot, ["write-tree"], { env })).stdout.trim();
|
|
77
|
+
const parent = (await git(gitRoot, ["rev-parse", "--verify", "HEAD^{commit}"])).stdout.trim();
|
|
78
|
+
return (await git(gitRoot, ["commit-tree", tree, "-p", parent, "-m", "Auvrynt review snapshot"], { env })).stdout.trim();
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function checkpointEnv(indexPath) {
|
|
85
|
+
return {
|
|
86
|
+
GIT_INDEX_FILE: indexPath,
|
|
87
|
+
GIT_AUTHOR_NAME: "Auvrynt",
|
|
88
|
+
GIT_AUTHOR_EMAIL: "auvrynt@users.noreply.local",
|
|
89
|
+
GIT_COMMITTER_NAME: "Auvrynt",
|
|
90
|
+
GIT_COMMITTER_EMAIL: "auvrynt@users.noreply.local",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function parseNumstat(output) {
|
|
94
|
+
const fields = output.split("\0").filter((field) => field.length > 0);
|
|
95
|
+
const files = [];
|
|
96
|
+
for (let index = 0; index < fields.length;) {
|
|
97
|
+
const header = fields[index++] ?? "";
|
|
98
|
+
const parts = header.split("\t");
|
|
99
|
+
const additions = parseStatNumber(parts[0]);
|
|
100
|
+
const removals = parseStatNumber(parts[1]);
|
|
101
|
+
if (parts.length >= 3) {
|
|
102
|
+
const path = parts[2] ?? "";
|
|
103
|
+
if (path)
|
|
104
|
+
files.push({ path, type: fileType(path, undefined, additions, removals), additions, removals });
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const previousPath = fields[index++];
|
|
108
|
+
const path = fields[index++];
|
|
109
|
+
if (!path)
|
|
110
|
+
continue;
|
|
111
|
+
files.push({
|
|
112
|
+
path,
|
|
113
|
+
previousPath,
|
|
114
|
+
type: fileType(path, previousPath, additions, removals),
|
|
115
|
+
additions,
|
|
116
|
+
removals,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return files;
|
|
120
|
+
}
|
|
121
|
+
function parseStatNumber(value) {
|
|
122
|
+
if (!value || value === "-")
|
|
123
|
+
return 0;
|
|
124
|
+
const parsed = Number(value);
|
|
125
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
126
|
+
}
|
|
127
|
+
function fileType(path, previousPath, additions, removals) {
|
|
128
|
+
if (previousPath)
|
|
129
|
+
return additions === 0 && removals === 0 ? "rename-pure" : "rename-changed";
|
|
130
|
+
if (additions > 0 && removals === 0)
|
|
131
|
+
return "new";
|
|
132
|
+
if (additions === 0 && removals > 0)
|
|
133
|
+
return "deleted";
|
|
134
|
+
return "change";
|
|
135
|
+
}
|
|
136
|
+
function summarizeFiles(files) {
|
|
137
|
+
return files.reduce((summary, file) => ({
|
|
138
|
+
files: summary.files + 1,
|
|
139
|
+
additions: summary.additions + file.additions,
|
|
140
|
+
removals: summary.removals + file.removals,
|
|
141
|
+
}), { files: 0, additions: 0, removals: 0 });
|
|
142
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { basename, dirname, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
4
|
+
export class AccessDeniedError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "AccessDeniedError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function expandHomePath(path) {
|
|
11
|
+
if (path === "~")
|
|
12
|
+
return homedir();
|
|
13
|
+
if (path.startsWith("~/") || path.startsWith("~\\")) {
|
|
14
|
+
return resolve(homedir(), path.slice(2));
|
|
15
|
+
}
|
|
16
|
+
return path;
|
|
17
|
+
}
|
|
18
|
+
export function isPathInsideRoot(path, root) {
|
|
19
|
+
const resolvedPath = canonicalizePath(path);
|
|
20
|
+
const resolvedRoot = canonicalizePath(root);
|
|
21
|
+
const relationship = relative(resolvedRoot, resolvedPath);
|
|
22
|
+
return (relationship === "" ||
|
|
23
|
+
(!relationship.startsWith("..") && relationship !== ".." && !relationship.includes(`..${sep}`)));
|
|
24
|
+
}
|
|
25
|
+
export function assertAllowedPath(path, allowedRoots) {
|
|
26
|
+
const resolvedPath = canonicalizePath(path);
|
|
27
|
+
if (allowedRoots.some((root) => isPathInsideRoot(resolvedPath, root))) {
|
|
28
|
+
// Return the canonical path that was actually authorized rather than the
|
|
29
|
+
// original symlink/junction spelling. This narrows the time-of-check /
|
|
30
|
+
// time-of-use window for callers that subsequently open or mutate it.
|
|
31
|
+
return resolvedPath;
|
|
32
|
+
}
|
|
33
|
+
throw new AccessDeniedError(`Path is outside allowed roots: ${path}`);
|
|
34
|
+
}
|
|
35
|
+
export function resolveAllowedPath(inputPath, cwd, allowedRoots) {
|
|
36
|
+
const absolutePath = resolve(cwd, inputPath);
|
|
37
|
+
return assertAllowedPath(absolutePath, allowedRoots);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the existing portion of a path through symlinks/junctions before
|
|
41
|
+
* applying workspace boundaries. This also handles new files whose parent
|
|
42
|
+
* directory already exists behind a link.
|
|
43
|
+
*/
|
|
44
|
+
function canonicalizePath(path) {
|
|
45
|
+
const resolved = resolve(expandHomePath(path));
|
|
46
|
+
const missing = [];
|
|
47
|
+
let existing = resolved;
|
|
48
|
+
while (!existsSync(existing)) {
|
|
49
|
+
const parent = dirname(existing);
|
|
50
|
+
if (parent === existing)
|
|
51
|
+
return resolved;
|
|
52
|
+
missing.unshift(basename(existing));
|
|
53
|
+
existing = parent;
|
|
54
|
+
}
|
|
55
|
+
return resolve(realpathSync.native(existing), ...missing);
|
|
56
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
const DEFAULT_IGNORED_DIRS = new Set([
|
|
4
|
+
".git",
|
|
5
|
+
".auvrynt-run",
|
|
6
|
+
"node_modules",
|
|
7
|
+
"dist",
|
|
8
|
+
"build",
|
|
9
|
+
"bin",
|
|
10
|
+
"obj",
|
|
11
|
+
".next",
|
|
12
|
+
".godot",
|
|
13
|
+
"__pycache__",
|
|
14
|
+
]);
|
|
15
|
+
export async function globFiles(registry, input) {
|
|
16
|
+
const workspace = registry.getWorkspace(input.workspaceId);
|
|
17
|
+
const baseDir = input.basePath
|
|
18
|
+
? registry.resolvePath(workspace, input.basePath)
|
|
19
|
+
: workspace.root;
|
|
20
|
+
const maxResults = Math.min(Math.max(input.maxResults ?? 100, 1), 1000);
|
|
21
|
+
const matchedFiles = [];
|
|
22
|
+
let truncated = false;
|
|
23
|
+
const regexPattern = input.pattern
|
|
24
|
+
.replace(/\./g, "\\.")
|
|
25
|
+
.replace(/\*\*/g, ".*")
|
|
26
|
+
.replace(/\*/g, "[^/\\\\]*")
|
|
27
|
+
.replace(/\?/g, ".");
|
|
28
|
+
const patternRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
29
|
+
async function walk(dir) {
|
|
30
|
+
if (matchedFiles.length >= maxResults) {
|
|
31
|
+
truncated = true;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
let entries;
|
|
35
|
+
try {
|
|
36
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
if (matchedFiles.length >= maxResults) {
|
|
43
|
+
truncated = true;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (entry.isDirectory()) {
|
|
47
|
+
if (DEFAULT_IGNORED_DIRS.has(entry.name))
|
|
48
|
+
continue;
|
|
49
|
+
await walk(join(dir, entry.name));
|
|
50
|
+
}
|
|
51
|
+
else if (entry.isFile()) {
|
|
52
|
+
const fullPath = join(dir, entry.name);
|
|
53
|
+
const relPath = relative(workspace.root, fullPath).replace(/\\/g, "/");
|
|
54
|
+
if (patternRegex.test(entry.name) || patternRegex.test(relPath)) {
|
|
55
|
+
matchedFiles.push(relPath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
await walk(baseDir);
|
|
61
|
+
return {
|
|
62
|
+
files: matchedFiles,
|
|
63
|
+
total: matchedFiles.length,
|
|
64
|
+
truncated,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export async function searchText(registry, input) {
|
|
68
|
+
const workspace = registry.getWorkspace(input.workspaceId);
|
|
69
|
+
const searchRoot = workspace.root;
|
|
70
|
+
const maxResults = Math.min(Math.max(input.maxResults ?? 50, 1), 500);
|
|
71
|
+
const caseSensitive = input.caseSensitive ?? false;
|
|
72
|
+
const flags = caseSensitive ? "g" : "gi";
|
|
73
|
+
const searchRegex = new RegExp(input.query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), flags);
|
|
74
|
+
const fileFilterRegex = input.filePattern
|
|
75
|
+
? new RegExp(input.filePattern
|
|
76
|
+
.replace(/\./g, "\\.")
|
|
77
|
+
.replace(/\*/g, ".*"), "i")
|
|
78
|
+
: null;
|
|
79
|
+
const matches = [];
|
|
80
|
+
let truncated = false;
|
|
81
|
+
async function searchInFile(fullPath) {
|
|
82
|
+
if (matches.length >= maxResults) {
|
|
83
|
+
truncated = true;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
let text;
|
|
87
|
+
try {
|
|
88
|
+
const stats = await stat(fullPath);
|
|
89
|
+
if (stats.size > 2 * 1024 * 1024)
|
|
90
|
+
return;
|
|
91
|
+
text = await readFile(fullPath, "utf8");
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const lines = text.split(/\r?\n/);
|
|
97
|
+
const relPath = relative(workspace.root, fullPath).replace(/\\/g, "/");
|
|
98
|
+
for (let i = 0; i < lines.length; i++) {
|
|
99
|
+
if (matches.length >= maxResults) {
|
|
100
|
+
truncated = true;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const lineText = lines[i];
|
|
104
|
+
searchRegex.lastIndex = 0;
|
|
105
|
+
const matchExec = searchRegex.exec(lineText);
|
|
106
|
+
if (matchExec) {
|
|
107
|
+
const startCtx = Math.max(0, i - 1);
|
|
108
|
+
const endCtx = Math.min(lines.length - 1, i + 1);
|
|
109
|
+
const context = lines.slice(startCtx, endCtx + 1);
|
|
110
|
+
matches.push({
|
|
111
|
+
path: relPath,
|
|
112
|
+
line: i + 1,
|
|
113
|
+
column: matchExec.index + 1,
|
|
114
|
+
match: lineText.trim(),
|
|
115
|
+
context,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async function walk(dir) {
|
|
121
|
+
if (matches.length >= maxResults) {
|
|
122
|
+
truncated = true;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let entries;
|
|
126
|
+
try {
|
|
127
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
for (const entry of entries) {
|
|
133
|
+
if (matches.length >= maxResults) {
|
|
134
|
+
truncated = true;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (entry.isDirectory()) {
|
|
138
|
+
if (DEFAULT_IGNORED_DIRS.has(entry.name))
|
|
139
|
+
continue;
|
|
140
|
+
await walk(join(dir, entry.name));
|
|
141
|
+
}
|
|
142
|
+
else if (entry.isFile()) {
|
|
143
|
+
if (fileFilterRegex && !fileFilterRegex.test(entry.name))
|
|
144
|
+
continue;
|
|
145
|
+
await searchInFile(join(dir, entry.name));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const targetDirs = input.paths?.length
|
|
150
|
+
? input.paths.map((p) => registry.resolvePath(workspace, p))
|
|
151
|
+
: [searchRoot];
|
|
152
|
+
for (const dir of targetDirs) {
|
|
153
|
+
const s = await stat(dir).catch(() => null);
|
|
154
|
+
if (s?.isDirectory()) {
|
|
155
|
+
await walk(dir);
|
|
156
|
+
}
|
|
157
|
+
else if (s?.isFile()) {
|
|
158
|
+
await searchInFile(dir);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
matches,
|
|
163
|
+
total: matches.length,
|
|
164
|
+
truncated,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export async function inspectProject(registry, input) {
|
|
168
|
+
const workspace = registry.getWorkspace(input.workspaceId);
|
|
169
|
+
const targetDir = input.path
|
|
170
|
+
? registry.resolvePath(workspace, input.path)
|
|
171
|
+
: workspace.root;
|
|
172
|
+
const projectTypes = [];
|
|
173
|
+
const packageManagers = [];
|
|
174
|
+
const frameworks = [];
|
|
175
|
+
const configFiles = [];
|
|
176
|
+
const recommendedCommands = {};
|
|
177
|
+
const details = {};
|
|
178
|
+
let entries = [];
|
|
179
|
+
try {
|
|
180
|
+
entries = await readdir(targetDir);
|
|
181
|
+
}
|
|
182
|
+
catch { }
|
|
183
|
+
const entrySet = new Set(entries);
|
|
184
|
+
if (entrySet.has("package.json")) {
|
|
185
|
+
projectTypes.push("nodejs");
|
|
186
|
+
configFiles.push("package.json");
|
|
187
|
+
try {
|
|
188
|
+
const pkgContent = await readFile(join(targetDir, "package.json"), "utf8");
|
|
189
|
+
const pkgJson = JSON.parse(pkgContent);
|
|
190
|
+
details.packageName = pkgJson.name;
|
|
191
|
+
details.scripts = pkgJson.scripts ?? {};
|
|
192
|
+
if (pkgJson.scripts?.build)
|
|
193
|
+
recommendedCommands.build = "npm run build";
|
|
194
|
+
if (pkgJson.scripts?.dev)
|
|
195
|
+
recommendedCommands.run = "npm run dev";
|
|
196
|
+
else if (pkgJson.scripts?.start)
|
|
197
|
+
recommendedCommands.run = "npm start";
|
|
198
|
+
if (pkgJson.scripts?.test)
|
|
199
|
+
recommendedCommands.test = "npm test";
|
|
200
|
+
if (pkgJson.scripts?.lint)
|
|
201
|
+
recommendedCommands.lint = "npm run lint";
|
|
202
|
+
const allDeps = { ...(pkgJson.dependencies ?? {}), ...(pkgJson.devDependencies ?? {}) };
|
|
203
|
+
if (allDeps.next)
|
|
204
|
+
frameworks.push("nextjs");
|
|
205
|
+
if (allDeps.vite)
|
|
206
|
+
frameworks.push("vite");
|
|
207
|
+
if (allDeps.react)
|
|
208
|
+
frameworks.push("react");
|
|
209
|
+
if (allDeps.express)
|
|
210
|
+
frameworks.push("express");
|
|
211
|
+
}
|
|
212
|
+
catch { }
|
|
213
|
+
}
|
|
214
|
+
if (entrySet.has("package-lock.json"))
|
|
215
|
+
packageManagers.push("npm");
|
|
216
|
+
if (entrySet.has("pnpm-lock.yaml"))
|
|
217
|
+
packageManagers.push("pnpm");
|
|
218
|
+
if (entrySet.has("yarn.lock"))
|
|
219
|
+
packageManagers.push("yarn");
|
|
220
|
+
if (entrySet.has("bun.lockb") || entrySet.has("bun.lock"))
|
|
221
|
+
packageManagers.push("bun");
|
|
222
|
+
if (entrySet.has("tsconfig.json")) {
|
|
223
|
+
projectTypes.push("typescript");
|
|
224
|
+
configFiles.push("tsconfig.json");
|
|
225
|
+
}
|
|
226
|
+
const dotnetFiles = entries.filter((e) => e.endsWith(".csproj") || e.endsWith(".fsproj") || e.endsWith(".sln"));
|
|
227
|
+
if (dotnetFiles.length > 0) {
|
|
228
|
+
projectTypes.push("dotnet");
|
|
229
|
+
configFiles.push(...dotnetFiles);
|
|
230
|
+
recommendedCommands.build = recommendedCommands.build ?? "dotnet build";
|
|
231
|
+
recommendedCommands.run = recommendedCommands.run ?? "dotnet run";
|
|
232
|
+
recommendedCommands.test = recommendedCommands.test ?? "dotnet test";
|
|
233
|
+
recommendedCommands.format = recommendedCommands.format ?? "dotnet format";
|
|
234
|
+
details.dotnetFiles = dotnetFiles;
|
|
235
|
+
}
|
|
236
|
+
if (entrySet.has("project.godot")) {
|
|
237
|
+
projectTypes.push("godot");
|
|
238
|
+
configFiles.push("project.godot");
|
|
239
|
+
recommendedCommands.run = recommendedCommands.run ?? "godot --path .";
|
|
240
|
+
details.godotProject = true;
|
|
241
|
+
}
|
|
242
|
+
if (entrySet.has("pyproject.toml") || entrySet.has("requirements.txt") || entrySet.has("setup.py")) {
|
|
243
|
+
projectTypes.push("python");
|
|
244
|
+
if (entrySet.has("pyproject.toml"))
|
|
245
|
+
configFiles.push("pyproject.toml");
|
|
246
|
+
if (entrySet.has("requirements.txt"))
|
|
247
|
+
configFiles.push("requirements.txt");
|
|
248
|
+
recommendedCommands.run = recommendedCommands.run ?? "python main.py";
|
|
249
|
+
}
|
|
250
|
+
if (entrySet.has(".git")) {
|
|
251
|
+
configFiles.push(".git");
|
|
252
|
+
details.gitRepository = true;
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
workspaceId: input.workspaceId,
|
|
256
|
+
root: targetDir,
|
|
257
|
+
projectTypes,
|
|
258
|
+
packageManagers,
|
|
259
|
+
frameworks,
|
|
260
|
+
configFiles,
|
|
261
|
+
recommendedCommands,
|
|
262
|
+
details,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { resolve, sep } from "node:path";
|
|
3
|
+
import { loadSkills, } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { expandHomePath, isPathInsideRoot } from "../roots.js";
|
|
5
|
+
export function loadWorkspaceSkills(config, cwd) {
|
|
6
|
+
if (!config.skillsEnabled)
|
|
7
|
+
return { skills: [], diagnostics: [] };
|
|
8
|
+
return loadSkills({
|
|
9
|
+
cwd,
|
|
10
|
+
agentDir: config.agentDir,
|
|
11
|
+
skillPaths: config.skillPaths,
|
|
12
|
+
includeDefaults: true,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export function resolveSkillReadPath(skills, activatedSkillDirs, inputPath) {
|
|
16
|
+
const absolutePath = resolve(expandHomePath(inputPath));
|
|
17
|
+
for (const skill of skills) {
|
|
18
|
+
const skillFilePath = resolve(skill.filePath);
|
|
19
|
+
if (absolutePath === skillFilePath) {
|
|
20
|
+
return { absolutePath, skill, isSkillFile: true };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
for (const skill of skills) {
|
|
24
|
+
const baseDir = resolve(skill.baseDir);
|
|
25
|
+
if (!activatedSkillDirs.has(baseDir))
|
|
26
|
+
continue;
|
|
27
|
+
if (!isPathInsideRoot(absolutePath, baseDir))
|
|
28
|
+
continue;
|
|
29
|
+
return { absolutePath, skill, isSkillFile: false };
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
export function markSkillActivated(activatedSkillDirs, skill) {
|
|
34
|
+
activatedSkillDirs.add(resolve(skill.baseDir));
|
|
35
|
+
}
|
|
36
|
+
export function formatPathForPrompt(path) {
|
|
37
|
+
const home = resolve(homedir());
|
|
38
|
+
const resolvedPath = resolve(path);
|
|
39
|
+
if (resolvedPath === home)
|
|
40
|
+
return "~";
|
|
41
|
+
if (resolvedPath.startsWith(`${home}${sep}`)) {
|
|
42
|
+
return `~/${resolvedPath.slice(home.length + 1).split(sep).join("/")}`;
|
|
43
|
+
}
|
|
44
|
+
return resolvedPath.split(sep).join("/");
|
|
45
|
+
}
|