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,538 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Live tunnel smoke test.
|
|
5
|
+
*
|
|
6
|
+
* This script actually connects to ngrok and/or Cloudflare if those tools
|
|
7
|
+
* are installed on the local machine. It cannot pass without at least one
|
|
8
|
+
* tunnel provider executable available.
|
|
9
|
+
*
|
|
10
|
+
* Use:
|
|
11
|
+
* node scripts/live-tunnel-smoke.mjs
|
|
12
|
+
*
|
|
13
|
+
* Environment:
|
|
14
|
+
* AUVRYNT_LIVE_TUNNEL_PORT port for the local listener (default 49321)
|
|
15
|
+
* AUVRYNT_NGROK_AUTHTOKEN optional, forwarded to ngrok
|
|
16
|
+
* AUVRYNT_NGROK_URL optional stable origin, verified if provided
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import assert from "node:assert/strict";
|
|
20
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
21
|
+
import { mkdtempSync, openSync, closeSync, rmSync } from "node:fs";
|
|
22
|
+
import { mkdir, readFile, writeFile, unlink } from "node:fs/promises";
|
|
23
|
+
import { createServer } from "node:http";
|
|
24
|
+
import { tmpdir } from "node:os";
|
|
25
|
+
import { join } from "node:path";
|
|
26
|
+
|
|
27
|
+
// ── Reproduce the tunnel-utils helpers inline so the smoke test does not
|
|
28
|
+
// depend on compiled TypeScript output.
|
|
29
|
+
|
|
30
|
+
function findCommand(command) {
|
|
31
|
+
try {
|
|
32
|
+
return execFileSync(
|
|
33
|
+
process.platform === "win32" ? "where.exe" : "which",
|
|
34
|
+
[command],
|
|
35
|
+
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], windowsHide: true },
|
|
36
|
+
).split(/\r?\n/)[0]?.trim() || undefined;
|
|
37
|
+
} catch { return undefined; }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function normalizeUrl(value) {
|
|
41
|
+
if (!value?.trim()) return undefined;
|
|
42
|
+
const trimmed = value.trim();
|
|
43
|
+
const parsed = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
|
|
44
|
+
if (parsed.protocol !== "https:") throw new Error("URL must use HTTPS.");
|
|
45
|
+
if (parsed.username || parsed.password) throw new Error("URL must not contain credentials.");
|
|
46
|
+
if (parsed.port) throw new Error("URL must not contain a custom port.");
|
|
47
|
+
if ((parsed.pathname && parsed.pathname !== "/") || parsed.search || parsed.hash) {
|
|
48
|
+
throw new Error("URL must be an origin without path, query, or fragment.");
|
|
49
|
+
}
|
|
50
|
+
return parsed.origin;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isGeneratedNgrokUrl(value) {
|
|
54
|
+
try {
|
|
55
|
+
const parsed = new URL(value);
|
|
56
|
+
return parsed.protocol === "https:" && !parsed.username && !parsed.password
|
|
57
|
+
&& !parsed.port && (parsed.pathname === "/" || parsed.pathname === "")
|
|
58
|
+
&& !parsed.search && !parsed.hash
|
|
59
|
+
&& /(^|\.)ngrok(?:-free)?\.(?:app|dev|io)$/i.test(parsed.hostname);
|
|
60
|
+
} catch { return false; }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function tunnelUrlMatchesProvider(url, provider, expectedNgrokUrl) {
|
|
64
|
+
if (provider === "ngrok") {
|
|
65
|
+
const expected = normalizeUrl(expectedNgrokUrl);
|
|
66
|
+
if (expected) return url === expected;
|
|
67
|
+
return isGeneratedNgrokUrl(url);
|
|
68
|
+
}
|
|
69
|
+
return /^https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com$/.test(url);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ── Test result counters
|
|
73
|
+
|
|
74
|
+
let passed = 0;
|
|
75
|
+
let failed = 0;
|
|
76
|
+
let skipped = 0;
|
|
77
|
+
const failures = [];
|
|
78
|
+
|
|
79
|
+
function test(name, fn) {
|
|
80
|
+
try {
|
|
81
|
+
fn();
|
|
82
|
+
passed++;
|
|
83
|
+
console.log(` ✓ ${name}`);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
failed++;
|
|
86
|
+
failures.push({ name, error });
|
|
87
|
+
console.error(` ✗ ${name}`);
|
|
88
|
+
console.error(` ${error.message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function testAsync(name, fn) {
|
|
93
|
+
try {
|
|
94
|
+
await fn();
|
|
95
|
+
passed++;
|
|
96
|
+
console.log(` ✓ ${name}`);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
failed++;
|
|
99
|
+
failures.push({ name: `${name} (async)`, error });
|
|
100
|
+
console.error(` ✗ ${name}`);
|
|
101
|
+
console.error(` ${error.message}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── Temporary directories
|
|
106
|
+
|
|
107
|
+
const tempDir = mkdtempSync(join(tmpdir(), "auvrynt-tunnel-smoke-"));
|
|
108
|
+
const stateDir = join(tempDir, "state");
|
|
109
|
+
|
|
110
|
+
function tunnelJsonPath() {
|
|
111
|
+
return join(stateDir, "tunnel.json");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ── Helpers (reproduce the production logic inline)
|
|
115
|
+
|
|
116
|
+
async function readJson(path) {
|
|
117
|
+
try {
|
|
118
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
119
|
+
} catch { return undefined; }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function writeTunnelRecord(path, record) {
|
|
123
|
+
await writeFile(path, JSON.stringify(record), { mode: 0o600 });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function makeTunnelRecord(pid, url, port, provider) {
|
|
127
|
+
return { pid, url, port, provider, processPath: "smoke-test", processStartedAt: new Date().toISOString() };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Wait for a URL to appear in a log file, with timeout
|
|
131
|
+
async function waitForUrlInLog(logPath, checkUrl, timeoutMs, pollMs = 100) {
|
|
132
|
+
const deadline = Date.now() + timeoutMs;
|
|
133
|
+
while (Date.now() < deadline) {
|
|
134
|
+
const output = await readFile(logPath, "utf8").catch(() => "");
|
|
135
|
+
const result = checkUrl(output);
|
|
136
|
+
if (result) return result;
|
|
137
|
+
await new Promise(r => setTimeout(r, pollMs));
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ── Smoke test suite
|
|
143
|
+
|
|
144
|
+
async function main() {
|
|
145
|
+
const PORT = Number(process.env.AUVRYNT_LIVE_TUNNEL_PORT || "49321");
|
|
146
|
+
const EXPECTED_NGROK_URL = normalizeUrl(process.env.AUVRYNT_NGROK_URL);
|
|
147
|
+
|
|
148
|
+
console.log(`\n=== Auvrynt Live Tunnel Smoke Test ===`);
|
|
149
|
+
console.log(`Port: ${PORT}`);
|
|
150
|
+
console.log(`Temp: ${tempDir}`);
|
|
151
|
+
console.log(`Expected ngrok URL: ${EXPECTED_NGROK_URL ?? "(none, use assigned)"}\n`);
|
|
152
|
+
|
|
153
|
+
// ── 1. Provider detection
|
|
154
|
+
console.log(`\n── Provider detection ──`);
|
|
155
|
+
|
|
156
|
+
const ngrokExe = findCommand("ngrok");
|
|
157
|
+
const hasNgrok = Boolean(ngrokExe);
|
|
158
|
+
test("ngrok installed", () => {
|
|
159
|
+
if (!hasNgrok) throw new Error("ngrok not found on PATH. Install from https://ngrok.com/download");
|
|
160
|
+
});
|
|
161
|
+
if (!hasNgrok) { skipped++; console.log(" → ngrok tests will be skipped"); }
|
|
162
|
+
|
|
163
|
+
const cfExe = findCommand("cloudflared");
|
|
164
|
+
const hasCloudflared = Boolean(cfExe);
|
|
165
|
+
test("cloudflared installed", () => {
|
|
166
|
+
if (!hasCloudflared) throw new Error("cloudflared not found on PATH. Install from https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/");
|
|
167
|
+
});
|
|
168
|
+
if (!hasCloudflared) { skipped++; console.log(" → Cloudflare tests will be skipped"); }
|
|
169
|
+
|
|
170
|
+
if (!hasNgrok && !hasCloudflared) {
|
|
171
|
+
console.log("\n⚠ No tunnel provider found. At least one of ngrok or cloudflared must be installed.");
|
|
172
|
+
console.log(" Install one and re-run.");
|
|
173
|
+
process.exitCode = 0;
|
|
174
|
+
console.log(`\nResults: 0 passed, 0 failed, 2 skipped (no tunnel provider)`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Start a minimal local HTTP server to tunnel to
|
|
179
|
+
const server = createServer((_req, res) => {
|
|
180
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
181
|
+
res.end(JSON.stringify({ ok: true }));
|
|
182
|
+
});
|
|
183
|
+
await new Promise(resolve => server.listen(PORT, "127.0.0.1", resolve));
|
|
184
|
+
console.log(`\n Local HTTP server listening on 127.0.0.1:${PORT}`);
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
await mkdir(stateDir, { recursive: true });
|
|
188
|
+
|
|
189
|
+
// ── 2. URL format helpers
|
|
190
|
+
console.log(`\n── URL format helpers ──`);
|
|
191
|
+
|
|
192
|
+
test("normalizeUrl: prepends https", () => {
|
|
193
|
+
assert.equal(normalizeUrl("demo.ngrok.app"), "https://demo.ngrok.app");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("normalizeUrl: strips trailing slash", () => {
|
|
197
|
+
assert.equal(normalizeUrl("https://demo.ngrok.app/"), "https://demo.ngrok.app");
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("normalizeUrl: rejects path", () => {
|
|
201
|
+
assert.throws(() => normalizeUrl("https://demo.ngrok.app/path"), /origin/);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("normalizeUrl: rejects HTTP", () => {
|
|
205
|
+
assert.throws(() => normalizeUrl("http://demo.ngrok.app"), /HTTPS/);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("isGeneratedNgrokUrl: recognizes ngrok-free.app", () => {
|
|
209
|
+
assert.equal(isGeneratedNgrokUrl("https://abc123.ngrok-free.app"), true);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("isGeneratedNgrokUrl: recognizes ngrok.app", () => {
|
|
213
|
+
assert.equal(isGeneratedNgrokUrl("https://abc123.ngrok.app"), true);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("isGeneratedNgrokUrl: rejects custom domain", () => {
|
|
217
|
+
assert.equal(isGeneratedNgrokUrl("https://api.example.com"), false);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// ── 3. ngrok live tests
|
|
221
|
+
if (hasNgrok) {
|
|
222
|
+
console.log(`\n── ngrok live tunnel ──`);
|
|
223
|
+
|
|
224
|
+
// 3a. Start an assigned (generated) tunnel
|
|
225
|
+
let ngrokChild;
|
|
226
|
+
try {
|
|
227
|
+
const ngrokLog = join(tempDir, "ngrok-assigned.log");
|
|
228
|
+
await writeFile(ngrokLog, "", { mode: 0o600 });
|
|
229
|
+
const logHandle = openSync(ngrokLog, "a");
|
|
230
|
+
|
|
231
|
+
const args = ["http", String(PORT), "--log=stdout", "--log-format=json"];
|
|
232
|
+
const spawnEnv = { ...process.env };
|
|
233
|
+
if (process.env.AUVRYNT_NGROK_AUTHTOKEN) {
|
|
234
|
+
spawnEnv.NGROK_AUTHTOKEN = process.env.AUVRYNT_NGROK_AUTHTOKEN;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
ngrokChild = spawn(ngrokExe, args, {
|
|
238
|
+
stdio: ["ignore", logHandle, logHandle],
|
|
239
|
+
windowsHide: true,
|
|
240
|
+
env: spawnEnv,
|
|
241
|
+
});
|
|
242
|
+
closeSync(logHandle);
|
|
243
|
+
let ngrokSpawnErr;
|
|
244
|
+
ngrokChild.once("error", (err) => { ngrokSpawnErr = err; });
|
|
245
|
+
|
|
246
|
+
// Wait for URL with 90s timeout
|
|
247
|
+
const ngrokAssignedUrl = await waitForUrlInLog(
|
|
248
|
+
ngrokLog,
|
|
249
|
+
(output) => {
|
|
250
|
+
const candidates = output.match(/https:\/\/[^\s"'\\]+/g) ?? [];
|
|
251
|
+
for (const raw of candidates) {
|
|
252
|
+
const cleaned = raw.replace(/[),.;]+$/, "");
|
|
253
|
+
try {
|
|
254
|
+
const n = normalizeUrl(cleaned);
|
|
255
|
+
if (n && isGeneratedNgrokUrl(n)) return n;
|
|
256
|
+
} catch {}
|
|
257
|
+
}
|
|
258
|
+
return undefined;
|
|
259
|
+
},
|
|
260
|
+
90_000,
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
if (!ngrokAssignedUrl) throw new Error("ngrok did not provide a generated URL within 90 seconds.");
|
|
264
|
+
|
|
265
|
+
await testAsync("ngrok: assigned URL discovered", async () => {
|
|
266
|
+
assert.ok(ngrokAssignedUrl.startsWith("https://"), `Expected HTTPS URL, got: ${ngrokAssignedUrl}`);
|
|
267
|
+
assert.ok(isGeneratedNgrokUrl(ngrokAssignedUrl), `Expected generated ngrok URL, got: ${ngrokAssignedUrl}`);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("ngrok: URL matches provider", () => {
|
|
271
|
+
assert.ok(tunnelUrlMatchesProvider(ngrokAssignedUrl, "ngrok"));
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// 3b. Tunnel record persistence
|
|
275
|
+
const recordPath = tunnelJsonPath();
|
|
276
|
+
const record = makeTunnelRecord(ngrokChild.pid, ngrokAssignedUrl, PORT, "ngrok");
|
|
277
|
+
await writeTunnelRecord(recordPath, record);
|
|
278
|
+
|
|
279
|
+
await testAsync("ngrok: tunnel record persisted", async () => {
|
|
280
|
+
const saved = await readJson(recordPath);
|
|
281
|
+
assert.ok(saved, "tunnel.json should exist");
|
|
282
|
+
assert.equal(saved.url, ngrokAssignedUrl);
|
|
283
|
+
assert.equal(saved.port, PORT);
|
|
284
|
+
assert.equal(saved.provider, "ngrok");
|
|
285
|
+
assert.equal(saved.pid, ngrokChild.pid);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// 3c. Verify actual HTTP reachability through the tunnel
|
|
289
|
+
await testAsync("ngrok: HTTP reachable through tunnel", async () => {
|
|
290
|
+
const response = await fetch(`${ngrokAssignedUrl}/healthz`, { signal: AbortSignal.timeout(15_000) });
|
|
291
|
+
assert.equal(response.status, 200);
|
|
292
|
+
const body = await response.json();
|
|
293
|
+
assert.ok(body.ok);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// 3d. Stop tunnel and verify cleanup
|
|
297
|
+
const killedPid = ngrokChild.pid;
|
|
298
|
+
ngrokChild.kill();
|
|
299
|
+
await new Promise(resolve => ngrokChild.once("exit", resolve));
|
|
300
|
+
ngrokChild = undefined;
|
|
301
|
+
|
|
302
|
+
await testAsync("ngrok: cleanup after kill", async () => {
|
|
303
|
+
try { process.kill(killedPid, 0); throw new Error("process still running"); }
|
|
304
|
+
catch (e) { if (e.code !== "ESRCH") throw e; }
|
|
305
|
+
await unlink(recordPath);
|
|
306
|
+
const gone = await readJson(recordPath);
|
|
307
|
+
assert.equal(gone, undefined);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
console.log(" → Assigned ngrok tunnel verified.");
|
|
311
|
+
} catch (error) {
|
|
312
|
+
failed++;
|
|
313
|
+
failures.push({ name: "ngrok assigned tunnel", error });
|
|
314
|
+
console.error(` ✗ ngrok assigned tunnel failed: ${error.message}`);
|
|
315
|
+
if (ngrokChild) {
|
|
316
|
+
ngrokChild.kill();
|
|
317
|
+
ngrokChild = undefined;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// ── 3e. Stable (reserved) URL test
|
|
322
|
+
if (hasNgrok && EXPECTED_NGROK_URL) {
|
|
323
|
+
let stableChild;
|
|
324
|
+
try {
|
|
325
|
+
const ngrokLog = join(tempDir, "ngrok-stable.log");
|
|
326
|
+
await writeFile(ngrokLog, "", { mode: 0o600 });
|
|
327
|
+
const logHandle = openSync(ngrokLog, "a");
|
|
328
|
+
|
|
329
|
+
const args = ["http", String(PORT), "--log=stdout", "--log-format=json", "--url", EXPECTED_NGROK_URL];
|
|
330
|
+
const spawnEnv = { ...process.env };
|
|
331
|
+
if (process.env.AUVRYNT_NGROK_AUTHTOKEN) {
|
|
332
|
+
spawnEnv.NGROK_AUTHTOKEN = process.env.AUVRYNT_NGROK_AUTHTOKEN;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
stableChild = spawn(ngrokExe, args, {
|
|
336
|
+
stdio: ["ignore", logHandle, logHandle],
|
|
337
|
+
windowsHide: true,
|
|
338
|
+
env: spawnEnv,
|
|
339
|
+
});
|
|
340
|
+
closeSync(logHandle);
|
|
341
|
+
let stableSpawnErr;
|
|
342
|
+
stableChild.once("error", (err) => { stableSpawnErr = err; });
|
|
343
|
+
|
|
344
|
+
const stableUrl = await waitForUrlInLog(
|
|
345
|
+
ngrokLog,
|
|
346
|
+
(output) => {
|
|
347
|
+
const candidates = output.match(/https:\/\/[^\s"'\\]+/g) ?? [];
|
|
348
|
+
for (const raw of candidates) {
|
|
349
|
+
const cleaned = raw.replace(/[),.;]+$/, "");
|
|
350
|
+
try {
|
|
351
|
+
const n = normalizeUrl(cleaned);
|
|
352
|
+
if (n && n === EXPECTED_NGROK_URL) return n;
|
|
353
|
+
} catch {}
|
|
354
|
+
}
|
|
355
|
+
return undefined;
|
|
356
|
+
},
|
|
357
|
+
90_000,
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
if (!stableUrl) throw new Error(`ngrok did not provide the stable URL ${EXPECTED_NGROK_URL} within 90 seconds.`);
|
|
361
|
+
|
|
362
|
+
await testAsync("ngrok: stable URL matches expected", async () => {
|
|
363
|
+
assert.equal(stableUrl, EXPECTED_NGROK_URL);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
await testAsync("ngrok: stable URL HTTP reachable", async () => {
|
|
367
|
+
const response = await fetch(`${stableUrl}/healthz`, { signal: AbortSignal.timeout(15_000) });
|
|
368
|
+
assert.equal(response.status, 200);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
test("ngrok: stable URL matches provider", () => {
|
|
372
|
+
assert.ok(tunnelUrlMatchesProvider(stableUrl, "ngrok", EXPECTED_NGROK_URL));
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
stableChild.kill();
|
|
376
|
+
await new Promise(resolve => stableChild.once("exit", resolve));
|
|
377
|
+
stableChild = undefined;
|
|
378
|
+
console.log(" → Stable ngrok tunnel verified.");
|
|
379
|
+
} catch (error) {
|
|
380
|
+
failed++;
|
|
381
|
+
failures.push({ name: "ngrok stable URL test", error });
|
|
382
|
+
console.error(` ✗ ngrok stable URL test failed: ${error.message}`);
|
|
383
|
+
if (stableChild) {
|
|
384
|
+
stableChild.kill();
|
|
385
|
+
stableChild = undefined;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
} else if (hasNgrok) {
|
|
389
|
+
skipped++;
|
|
390
|
+
console.log(" → Skipping stable URL test (set AUVRYNT_NGROK_URL to test)");
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// ── 4. Cloudflare live test
|
|
395
|
+
if (hasCloudflared) {
|
|
396
|
+
console.log(`\n── Cloudflare live tunnel ──`);
|
|
397
|
+
|
|
398
|
+
let cfChild;
|
|
399
|
+
try {
|
|
400
|
+
const cfLog = join(tempDir, "cloudflared.log");
|
|
401
|
+
await writeFile(cfLog, "", { mode: 0o600 });
|
|
402
|
+
const logHandle = openSync(cfLog, "a");
|
|
403
|
+
|
|
404
|
+
const args = ["tunnel", "--no-autoupdate", "--url", `http://127.0.0.1:${PORT}`];
|
|
405
|
+
cfChild = spawn(cfExe, args, {
|
|
406
|
+
stdio: ["ignore", logHandle, logHandle],
|
|
407
|
+
windowsHide: true,
|
|
408
|
+
});
|
|
409
|
+
closeSync(logHandle);
|
|
410
|
+
let cfSpawnErr;
|
|
411
|
+
cfChild.once("error", (err) => { cfSpawnErr = err; });
|
|
412
|
+
|
|
413
|
+
const cfUrl = await waitForUrlInLog(
|
|
414
|
+
cfLog,
|
|
415
|
+
(output) => {
|
|
416
|
+
const match = output.match(/https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com/);
|
|
417
|
+
return match ? match[0] : undefined;
|
|
418
|
+
},
|
|
419
|
+
120_000,
|
|
420
|
+
250,
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
if (!cfUrl) throw new Error("cloudflared did not provide a URL within 120 seconds.");
|
|
424
|
+
|
|
425
|
+
await testAsync("cloudflared: URL discovered", async () => {
|
|
426
|
+
assert.ok(cfUrl.startsWith("https://"), `Expected HTTPS URL, got: ${cfUrl}`);
|
|
427
|
+
assert.ok(cfUrl.includes(".trycloudflare.com"), `Expected trycloudflare.com URL, got: ${cfUrl}`);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test("cloudflared: URL matches provider", () => {
|
|
431
|
+
assert.ok(tunnelUrlMatchesProvider(cfUrl, "cloudflare"));
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Tunnel record persistence
|
|
435
|
+
const recordPath = tunnelJsonPath();
|
|
436
|
+
const record = makeTunnelRecord(cfChild.pid, cfUrl, PORT, "cloudflare");
|
|
437
|
+
await writeTunnelRecord(recordPath, record);
|
|
438
|
+
|
|
439
|
+
await testAsync("cloudflared: tunnel record persisted", async () => {
|
|
440
|
+
const saved = await readJson(recordPath);
|
|
441
|
+
assert.ok(saved);
|
|
442
|
+
assert.equal(saved.url, cfUrl);
|
|
443
|
+
assert.equal(saved.port, PORT);
|
|
444
|
+
assert.equal(saved.provider, "cloudflare");
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// HTTP reachability through tunnel
|
|
448
|
+
await testAsync("cloudflared: HTTP reachable through tunnel", async () => {
|
|
449
|
+
const response = await fetch(`${cfUrl}/healthz`, { signal: AbortSignal.timeout(15_000) });
|
|
450
|
+
assert.equal(response.status, 200);
|
|
451
|
+
const body = await response.json();
|
|
452
|
+
assert.ok(body.ok);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// Stop and cleanup
|
|
456
|
+
const killedCfPid = cfChild.pid;
|
|
457
|
+
cfChild.kill();
|
|
458
|
+
await new Promise(resolve => cfChild.once("exit", resolve));
|
|
459
|
+
cfChild = undefined;
|
|
460
|
+
|
|
461
|
+
await testAsync("cloudflared: cleanup after kill", async () => {
|
|
462
|
+
try { process.kill(killedCfPid, 0); throw new Error("process still running"); }
|
|
463
|
+
catch (e) { if (e.code !== "ESRCH") throw e; }
|
|
464
|
+
await unlink(recordPath);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
console.log(" → Cloudflare tunnel verified.");
|
|
468
|
+
} catch (error) {
|
|
469
|
+
failed++;
|
|
470
|
+
failures.push({ name: "Cloudflare tunnel", error });
|
|
471
|
+
console.error(` ✗ Cloudflare tunnel test failed: ${error.message}`);
|
|
472
|
+
if (cfChild) {
|
|
473
|
+
cfChild.kill();
|
|
474
|
+
cfChild = undefined;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// ── 5. Tunnel manager simulation
|
|
480
|
+
console.log(`\n── Tunnel manager simulation ──`);
|
|
481
|
+
|
|
482
|
+
test("tunnelUrlMatchesProvider: rejects wrong provider", () => {
|
|
483
|
+
const url = "https://abc123.ngrok-free.app";
|
|
484
|
+
assert.equal(tunnelUrlMatchesProvider(url, "cloudflare"), false);
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
test("tunnelUrlMatchesProvider: accepts correct ngrok", () => {
|
|
488
|
+
const url = "https://abc123.ngrok-free.app";
|
|
489
|
+
assert.equal(tunnelUrlMatchesProvider(url, "ngrok"), true);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
test("tunnelUrlMatchesProvider: stable URL matching", () => {
|
|
493
|
+
const url = "https://custom.ngrok.app";
|
|
494
|
+
assert.equal(tunnelUrlMatchesProvider(url, "ngrok", "https://custom.ngrok.app"), true);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// Simulate read-managed-tunnel behavior
|
|
498
|
+
await testAsync("readManagedTunnel simulation: missing file returns undefined", async () => {
|
|
499
|
+
const data = await readJson(join(tempDir, "nonexistent.json"));
|
|
500
|
+
assert.equal(data, undefined);
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
await testAsync("readManagedTunnel simulation: valid record parsed", async () => {
|
|
504
|
+
const path = join(tempDir, "valid-record.json");
|
|
505
|
+
const record = makeTunnelRecord(99999, "https://test.ngrok-free.app", PORT, "ngrok");
|
|
506
|
+
await writeTunnelRecord(path, record);
|
|
507
|
+
const saved = await readJson(path);
|
|
508
|
+
assert.ok(saved);
|
|
509
|
+
assert.equal(saved.url, "https://test.ngrok-free.app");
|
|
510
|
+
assert.equal(saved.provider, "ngrok");
|
|
511
|
+
await unlink(path);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
} finally {
|
|
515
|
+
// Cleanup — kill any orphaned child processes and remove temp dir
|
|
516
|
+
server.close();
|
|
517
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// ── Results
|
|
521
|
+
const total = passed + failed + skipped;
|
|
522
|
+
console.log(`\n── Results ──`);
|
|
523
|
+
console.log(` ${passed} passed, ${failed} failed, ${skipped} skipped (${total} total)`);
|
|
524
|
+
|
|
525
|
+
if (failed > 0) {
|
|
526
|
+
console.log(`\nFailures:`);
|
|
527
|
+
for (const f of failures) {
|
|
528
|
+
console.log(` - ${f.name}: ${f.error.message}`);
|
|
529
|
+
}
|
|
530
|
+
process.exitCode = 1;
|
|
531
|
+
}
|
|
532
|
+
console.log(`\n${failed === 0 ? "✓ All tunnel smoke tests passed." : "✗ Some tunnel smoke tests failed."}`);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
main().catch(error => {
|
|
536
|
+
console.error(`Fatal error: ${error.stack ?? error.message}`);
|
|
537
|
+
process.exitCode = 1;
|
|
538
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
7
|
+
const checkOnly = process.argv.includes("--check") || !process.argv.includes("--fix");
|
|
8
|
+
const binaryExtensions = new Set([
|
|
9
|
+
".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico",
|
|
10
|
+
".blend", ".glb", ".wasm", ".sqlite", ".db", ".zip", ".tgz",
|
|
11
|
+
]);
|
|
12
|
+
const knownNulArtifact = "INFO: Could not find files for the given pattern(s).";
|
|
13
|
+
|
|
14
|
+
const git = spawnSync("git", ["ls-files", "-z"], {
|
|
15
|
+
cwd: root,
|
|
16
|
+
encoding: "utf8",
|
|
17
|
+
windowsHide: true,
|
|
18
|
+
});
|
|
19
|
+
if (git.status !== 0) {
|
|
20
|
+
process.stderr.write(git.stderr || "Could not list tracked files.\n");
|
|
21
|
+
process.exit(2);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const trackedFiles = git.stdout.split("\0").filter(Boolean);
|
|
25
|
+
const crlfFiles = [];
|
|
26
|
+
|
|
27
|
+
for (const relativePath of trackedFiles) {
|
|
28
|
+
if (binaryExtensions.has(extname(relativePath).toLowerCase())) continue;
|
|
29
|
+
const absolutePath = join(root, relativePath);
|
|
30
|
+
if (!existsSync(absolutePath)) continue;
|
|
31
|
+
|
|
32
|
+
const buffer = readFileSync(absolutePath);
|
|
33
|
+
if (buffer.includes(0)) continue;
|
|
34
|
+
const text = buffer.toString("utf8");
|
|
35
|
+
if (!text.includes("\r\n")) continue;
|
|
36
|
+
|
|
37
|
+
crlfFiles.push(relativePath);
|
|
38
|
+
if (!checkOnly) writeFileSync(absolutePath, text.replace(/\r\n/g, "\n"), "utf8");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let nulArtifact = false;
|
|
42
|
+
let unsafeNulArtifact = false;
|
|
43
|
+
if (process.platform === "win32") {
|
|
44
|
+
const normalPath = join(root, "NUL");
|
|
45
|
+
const extendedPath = `\\\\?\\${normalPath}`;
|
|
46
|
+
if (existsSync(extendedPath)) {
|
|
47
|
+
const content = readFileSync(extendedPath, "utf8").trim();
|
|
48
|
+
if (content === knownNulArtifact) {
|
|
49
|
+
nulArtifact = true;
|
|
50
|
+
if (!checkOnly) unlinkSync(extendedPath);
|
|
51
|
+
} else {
|
|
52
|
+
unsafeNulArtifact = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (checkOnly) {
|
|
58
|
+
if (crlfFiles.length > 0) {
|
|
59
|
+
console.error(`CRLF normalization required in ${crlfFiles.length} tracked file(s):`);
|
|
60
|
+
for (const path of crlfFiles.slice(0, 20)) console.error(` ${path}`);
|
|
61
|
+
if (crlfFiles.length > 20) console.error(` ...and ${crlfFiles.length - 20} more`);
|
|
62
|
+
}
|
|
63
|
+
if (nulArtifact) console.error("Known accidental Windows NUL artifact is present at repository root.");
|
|
64
|
+
if (unsafeNulArtifact) console.error("A repository-root NUL file exists but does not match the known disposable artifact; it was not touched.");
|
|
65
|
+
if (crlfFiles.length > 0 || nulArtifact || unsafeNulArtifact) process.exit(1);
|
|
66
|
+
console.log("Repository hygiene check passed.");
|
|
67
|
+
} else {
|
|
68
|
+
console.log(`Normalized ${crlfFiles.length} tracked file(s) to LF.`);
|
|
69
|
+
console.log(nulArtifact ? "Removed the known accidental Windows NUL artifact." : "No known Windows NUL artifact needed removal.");
|
|
70
|
+
if (unsafeNulArtifact) {
|
|
71
|
+
console.warn("A repository-root NUL file exists but did not match the known disposable artifact; it was left untouched.");
|
|
72
|
+
process.exitCode = 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
const [, , parentPidText, cliPath, encodedArgs] = process.argv;
|
|
4
|
+
const parentPid = Number(parentPidText);
|
|
5
|
+
|
|
6
|
+
if (!Number.isInteger(parentPid) || parentPid <= 0 || !cliPath || !encodedArgs) {
|
|
7
|
+
process.exitCode = 2;
|
|
8
|
+
} else {
|
|
9
|
+
const originalArgs = JSON.parse(Buffer.from(encodedArgs, "base64url").toString("utf8"));
|
|
10
|
+
if (!Array.isArray(originalArgs) || originalArgs.some((value) => typeof value !== "string")) {
|
|
11
|
+
process.exitCode = 2;
|
|
12
|
+
} else {
|
|
13
|
+
const deadline = Date.now() + 30_000;
|
|
14
|
+
while (Date.now() < deadline && isRunning(parentPid)) {
|
|
15
|
+
await delay(250);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (isRunning(parentPid)) {
|
|
19
|
+
console.error(`[auvrynt] Crash recovery abandoned because process ${parentPid} did not exit.`);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
} else {
|
|
22
|
+
await delay(500);
|
|
23
|
+
const child = spawn(process.execPath, [cliPath, ...originalArgs], {
|
|
24
|
+
cwd: process.cwd(),
|
|
25
|
+
detached: true,
|
|
26
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
27
|
+
windowsHide: true,
|
|
28
|
+
env: process.env,
|
|
29
|
+
});
|
|
30
|
+
child.once("error", (error) => {
|
|
31
|
+
console.error(`[auvrynt] Crash recovery restart failed: ${error.message}`);
|
|
32
|
+
});
|
|
33
|
+
child.unref();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isRunning(pid) {
|
|
39
|
+
try {
|
|
40
|
+
process.kill(pid, 0);
|
|
41
|
+
return true;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function delay(ms) {
|
|
48
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
49
|
+
}
|