skybridge 0.0.0-dev.feb36b5 → 0.0.0-dev.febcf34
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 -674
- package/README.md +124 -97
- package/bin/run.js +5 -0
- package/dist/cli/build-helpers.d.ts +10 -0
- package/dist/cli/build-helpers.js +93 -0
- package/dist/cli/build-helpers.js.map +1 -0
- package/dist/cli/build-helpers.test.js +89 -0
- package/dist/cli/build-helpers.test.js.map +1 -0
- package/dist/cli/build-steps.d.ts +2 -0
- package/dist/cli/build-steps.js +68 -0
- package/dist/cli/build-steps.js.map +1 -0
- package/dist/cli/build-steps.test.js +52 -0
- package/dist/cli/build-steps.test.js.map +1 -0
- package/dist/cli/detect-port.d.ts +18 -0
- package/dist/cli/detect-port.js +50 -0
- package/dist/cli/detect-port.js.map +1 -0
- package/dist/cli/header.d.ts +4 -0
- package/dist/cli/header.js +6 -0
- package/dist/cli/header.js.map +1 -0
- package/dist/cli/resolve-views-dir.d.ts +1 -0
- package/dist/cli/resolve-views-dir.js +17 -0
- package/dist/cli/resolve-views-dir.js.map +1 -0
- package/dist/cli/run-command.d.ts +2 -0
- package/dist/cli/run-command.js +43 -0
- package/dist/cli/run-command.js.map +1 -0
- package/dist/cli/run-plain.d.ts +18 -0
- package/dist/cli/run-plain.js +89 -0
- package/dist/cli/run-plain.js.map +1 -0
- package/dist/cli/telemetry.d.ts +7 -0
- package/dist/cli/telemetry.js +123 -0
- package/dist/cli/telemetry.js.map +1 -0
- package/dist/cli/tunnel-control-server.d.ts +9 -0
- package/dist/cli/tunnel-control-server.js +31 -0
- package/dist/cli/tunnel-control-server.js.map +1 -0
- package/dist/cli/tunnel-control-server.test.d.ts +1 -0
- package/dist/cli/tunnel-control-server.test.js +39 -0
- package/dist/cli/tunnel-control-server.test.js.map +1 -0
- package/dist/cli/tunnel-handler.d.ts +3 -0
- package/dist/cli/tunnel-handler.js +48 -0
- package/dist/cli/tunnel-handler.js.map +1 -0
- package/dist/cli/tunnel-handler.test.d.ts +1 -0
- package/dist/cli/tunnel-handler.test.js +105 -0
- package/dist/cli/tunnel-handler.test.js.map +1 -0
- package/dist/cli/tunnel.d.ts +57 -0
- package/dist/cli/tunnel.js +154 -0
- package/dist/cli/tunnel.js.map +1 -0
- package/dist/cli/tunnel.test.d.ts +1 -0
- package/dist/cli/tunnel.test.js +190 -0
- package/dist/cli/tunnel.test.js.map +1 -0
- package/dist/cli/types.d.ts +5 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/use-execute-steps.d.ts +11 -0
- package/dist/cli/use-execute-steps.js +36 -0
- package/dist/cli/use-execute-steps.js.map +1 -0
- package/dist/cli/use-messages.d.ts +3 -0
- package/dist/cli/use-messages.js +11 -0
- package/dist/cli/use-messages.js.map +1 -0
- package/dist/cli/use-nodemon.d.ts +16 -0
- package/dist/cli/use-nodemon.js +84 -0
- package/dist/cli/use-nodemon.js.map +1 -0
- package/dist/cli/use-open-browser.d.ts +1 -0
- package/dist/cli/use-open-browser.js +44 -0
- package/dist/cli/use-open-browser.js.map +1 -0
- package/dist/cli/use-tunnel.d.ts +14 -0
- package/dist/cli/use-tunnel.js +131 -0
- package/dist/cli/use-tunnel.js.map +1 -0
- package/dist/cli/use-typescript-check.d.ts +15 -0
- package/dist/cli/use-typescript-check.js +97 -0
- package/dist/cli/use-typescript-check.js.map +1 -0
- package/dist/commands/build.d.ts +6 -0
- package/dist/commands/build.js +31 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/create.d.ts +9 -0
- package/dist/commands/create.js +30 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +13 -0
- package/dist/commands/dev.js +128 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/start.d.ts +9 -0
- package/dist/commands/start.js +55 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/telemetry/disable.d.ts +5 -0
- package/dist/commands/telemetry/disable.js +14 -0
- package/dist/commands/telemetry/disable.js.map +1 -0
- package/dist/commands/telemetry/enable.d.ts +5 -0
- package/dist/commands/telemetry/enable.js +14 -0
- package/dist/commands/telemetry/enable.js.map +1 -0
- package/dist/commands/telemetry/status.d.ts +5 -0
- package/dist/commands/telemetry/status.js +14 -0
- package/dist/commands/telemetry/status.js.map +1 -0
- package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
- package/dist/server/asset-base-url-transform-plugin.js +48 -0
- package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
- package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
- package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
- package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
- package/dist/server/auth/discovery.d.ts +32 -0
- package/dist/server/auth/discovery.js +56 -0
- package/dist/server/auth/discovery.js.map +1 -0
- package/dist/server/auth/discovery.test.d.ts +1 -0
- package/dist/server/auth/discovery.test.js +93 -0
- package/dist/server/auth/discovery.test.js.map +1 -0
- package/dist/server/auth/index.d.ts +18 -0
- package/dist/server/auth/index.js +2 -0
- package/dist/server/auth/index.js.map +1 -0
- package/dist/server/auth/providers/auth0.d.ts +18 -0
- package/dist/server/auth/providers/auth0.js +31 -0
- package/dist/server/auth/providers/auth0.js.map +1 -0
- package/dist/server/auth/providers/auth0.test.d.ts +1 -0
- package/dist/server/auth/providers/auth0.test.js +48 -0
- package/dist/server/auth/providers/auth0.test.js.map +1 -0
- package/dist/server/auth/providers/clerk.d.ts +14 -0
- package/dist/server/auth/providers/clerk.js +16 -0
- package/dist/server/auth/providers/clerk.js.map +1 -0
- package/dist/server/auth/providers/clerk.test.d.ts +1 -0
- package/dist/server/auth/providers/clerk.test.js +28 -0
- package/dist/server/auth/providers/clerk.test.js.map +1 -0
- package/dist/server/auth/providers/custom.d.ts +24 -0
- package/dist/server/auth/providers/custom.js +37 -0
- package/dist/server/auth/providers/custom.js.map +1 -0
- package/dist/server/auth/providers/custom.test.d.ts +1 -0
- package/dist/server/auth/providers/custom.test.js +107 -0
- package/dist/server/auth/providers/custom.test.js.map +1 -0
- package/dist/server/auth/providers/descope.d.ts +15 -0
- package/dist/server/auth/providers/descope.js +34 -0
- package/dist/server/auth/providers/descope.js.map +1 -0
- package/dist/server/auth/providers/descope.test.d.ts +1 -0
- package/dist/server/auth/providers/descope.test.js +38 -0
- package/dist/server/auth/providers/descope.test.js.map +1 -0
- package/dist/server/auth/providers/shared.d.ts +2 -0
- package/dist/server/auth/providers/shared.js +6 -0
- package/dist/server/auth/providers/shared.js.map +1 -0
- package/dist/server/auth/providers/shared.test.d.ts +1 -0
- package/dist/server/auth/providers/shared.test.js +10 -0
- package/dist/server/auth/providers/shared.test.js.map +1 -0
- package/dist/server/auth/providers/stytch.d.ts +12 -0
- package/dist/server/auth/providers/stytch.js +13 -0
- package/dist/server/auth/providers/stytch.js.map +1 -0
- package/dist/server/auth/providers/workos.d.ts +11 -0
- package/dist/server/auth/providers/workos.js +12 -0
- package/dist/server/auth/providers/workos.js.map +1 -0
- package/dist/server/auth/setup.d.ts +4 -0
- package/dist/server/auth/setup.js +51 -0
- package/dist/server/auth/setup.js.map +1 -0
- package/dist/server/auth/setup.test.d.ts +1 -0
- package/dist/server/auth/setup.test.js +185 -0
- package/dist/server/auth/setup.test.js.map +1 -0
- package/dist/server/auth/verify.d.ts +12 -0
- package/dist/server/auth/verify.js +38 -0
- package/dist/server/auth/verify.js.map +1 -0
- package/dist/server/auth/verify.test.d.ts +1 -0
- package/dist/server/auth/verify.test.js +100 -0
- package/dist/server/auth/verify.test.js.map +1 -0
- package/dist/server/auth.d.ts +20 -0
- package/dist/server/auth.js +28 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/build-manifest.test.d.ts +1 -0
- package/dist/server/build-manifest.test.js +27 -0
- package/dist/server/build-manifest.test.js.map +1 -0
- package/dist/server/content-helpers.d.ts +67 -0
- package/dist/server/content-helpers.js +79 -0
- package/dist/server/content-helpers.js.map +1 -0
- package/dist/server/content-helpers.test.d.ts +1 -0
- package/dist/server/content-helpers.test.js +70 -0
- package/dist/server/content-helpers.test.js.map +1 -0
- package/dist/server/express.d.ts +11 -0
- package/dist/server/express.js +101 -0
- package/dist/server/express.js.map +1 -0
- package/dist/server/express.test.d.ts +1 -0
- package/dist/server/express.test.js +491 -0
- package/dist/server/express.test.js.map +1 -0
- package/dist/server/file-ref.d.ts +28 -0
- package/dist/server/file-ref.js +27 -0
- package/dist/server/file-ref.js.map +1 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.js +12 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/inferUtilityTypes.d.ts +64 -0
- package/dist/server/inferUtilityTypes.js +2 -0
- package/dist/server/inferUtilityTypes.js.map +1 -0
- package/dist/server/metric.d.ts +14 -0
- package/dist/server/metric.js +62 -0
- package/dist/server/metric.js.map +1 -0
- package/dist/server/middleware.d.ts +137 -0
- package/dist/server/middleware.js +93 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/middleware.test-d.d.ts +1 -0
- package/dist/server/middleware.test-d.js +75 -0
- package/dist/server/middleware.test-d.js.map +1 -0
- package/dist/server/middleware.test.d.ts +1 -0
- package/dist/server/middleware.test.js +493 -0
- package/dist/server/middleware.test.js.map +1 -0
- package/dist/server/requestOrigin.d.ts +7 -0
- package/dist/server/requestOrigin.js +25 -0
- package/dist/server/requestOrigin.js.map +1 -0
- package/dist/server/server.d.ts +419 -0
- package/dist/server/server.js +632 -0
- package/dist/server/server.js.map +1 -0
- package/dist/{src/server → server}/templateHelper.d.ts +5 -4
- package/dist/server/templateHelper.js +11 -0
- package/dist/server/templateHelper.js.map +1 -0
- package/dist/server/templates.generated.d.ts +4 -0
- package/dist/server/templates.generated.js +47 -0
- package/dist/server/templates.generated.js.map +1 -0
- package/dist/server/tunnel-proxy-router.d.ts +7 -0
- package/dist/server/tunnel-proxy-router.js +110 -0
- package/dist/server/tunnel-proxy-router.js.map +1 -0
- package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
- package/dist/server/tunnel-proxy-router.test.js +229 -0
- package/dist/server/tunnel-proxy-router.test.js.map +1 -0
- package/dist/server/view-name.test-d.d.ts +1 -0
- package/dist/server/view-name.test-d.js +8 -0
- package/dist/server/view-name.test-d.js.map +1 -0
- package/dist/server/view-resource-resolution.test.d.ts +6 -0
- package/dist/server/view-resource-resolution.test.js +171 -0
- package/dist/server/view-resource-resolution.test.js.map +1 -0
- package/dist/server/viewsDevServer.d.ts +14 -0
- package/dist/server/viewsDevServer.js +45 -0
- package/dist/server/viewsDevServer.js.map +1 -0
- package/dist/test/utils.d.ts +127 -0
- package/dist/test/utils.js +247 -0
- package/dist/test/utils.js.map +1 -0
- package/dist/test/view.test.d.ts +1 -0
- package/dist/test/view.test.js +536 -0
- package/dist/test/view.test.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/web/bridges/adaptor.d.ts +51 -0
- package/dist/web/bridges/adaptor.js +330 -0
- package/dist/web/bridges/adaptor.js.map +1 -0
- package/dist/web/bridges/adaptor.test.d.ts +1 -0
- package/dist/web/bridges/adaptor.test.js +208 -0
- package/dist/web/bridges/adaptor.test.js.map +1 -0
- package/dist/web/bridges/apps-sdk/bridge.d.ts +15 -0
- package/dist/web/bridges/apps-sdk/bridge.js +58 -0
- package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
- package/dist/web/bridges/apps-sdk/index.d.ts +4 -0
- package/dist/web/bridges/apps-sdk/index.js +4 -0
- package/dist/web/bridges/apps-sdk/index.js.map +1 -0
- package/dist/web/bridges/apps-sdk/types.d.ts +133 -0
- package/dist/web/bridges/apps-sdk/types.js.map +1 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +13 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +18 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
- package/dist/web/bridges/get-adaptor.d.ts +9 -0
- package/dist/web/bridges/get-adaptor.js +10 -0
- package/dist/web/bridges/get-adaptor.js.map +1 -0
- package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
- package/dist/web/bridges/get-adaptor.test.js +32 -0
- package/dist/web/bridges/get-adaptor.test.js.map +1 -0
- package/dist/web/bridges/index.d.ts +5 -0
- package/dist/web/bridges/index.js +6 -0
- package/dist/web/bridges/index.js.map +1 -0
- package/dist/web/bridges/mcp-app/bridge.d.ts +39 -0
- package/dist/web/bridges/mcp-app/bridge.js +166 -0
- package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
- package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
- package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
- package/dist/web/bridges/mcp-app/index.d.ts +3 -0
- package/dist/web/bridges/mcp-app/index.js +3 -0
- package/dist/web/bridges/mcp-app/index.js.map +1 -0
- package/dist/web/bridges/mcp-app/types.d.ts +8 -0
- package/dist/web/bridges/mcp-app/types.js +2 -0
- package/dist/web/bridges/mcp-app/types.js.map +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +19 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js +19 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
- package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
- package/dist/web/bridges/types.d.ts +214 -0
- package/dist/web/bridges/types.js +15 -0
- package/dist/web/bridges/types.js.map +1 -0
- package/dist/web/bridges/types.test.d.ts +1 -0
- package/dist/web/bridges/types.test.js +19 -0
- package/dist/web/bridges/types.test.js.map +1 -0
- package/dist/web/bridges/use-host-context.d.ts +7 -0
- package/dist/web/bridges/use-host-context.js +13 -0
- package/dist/web/bridges/use-host-context.js.map +1 -0
- package/dist/web/components/modal-provider.d.ts +4 -0
- package/dist/web/components/modal-provider.js +46 -0
- package/dist/web/components/modal-provider.js.map +1 -0
- package/dist/web/create-store.d.ts +29 -0
- package/dist/web/create-store.js +64 -0
- package/dist/web/create-store.js.map +1 -0
- package/dist/web/create-store.test.d.ts +1 -0
- package/dist/web/create-store.test.js +132 -0
- package/dist/web/create-store.test.js.map +1 -0
- package/dist/web/data-llm.d.ts +47 -0
- package/dist/web/data-llm.js +100 -0
- package/dist/web/data-llm.js.map +1 -0
- package/dist/web/data-llm.test.d.ts +1 -0
- package/dist/web/data-llm.test.js +154 -0
- package/dist/web/data-llm.test.js.map +1 -0
- package/dist/web/generate-helpers.d.ts +120 -0
- package/dist/web/generate-helpers.js +115 -0
- package/dist/web/generate-helpers.js.map +1 -0
- package/dist/web/generate-helpers.test-d.d.ts +1 -0
- package/dist/web/generate-helpers.test-d.js +211 -0
- package/dist/web/generate-helpers.test-d.js.map +1 -0
- package/dist/web/generate-helpers.test.d.ts +1 -0
- package/dist/web/generate-helpers.test.js +17 -0
- package/dist/web/generate-helpers.test.js.map +1 -0
- package/dist/web/helpers/state.d.ts +7 -0
- package/dist/web/helpers/state.js +45 -0
- package/dist/web/helpers/state.js.map +1 -0
- package/dist/web/helpers/state.test.d.ts +1 -0
- package/dist/web/helpers/state.test.js +53 -0
- package/dist/web/helpers/state.test.js.map +1 -0
- package/dist/web/hooks/index.d.ts +15 -0
- package/dist/web/hooks/index.js +16 -0
- package/dist/web/hooks/index.js.map +1 -0
- package/dist/web/hooks/test/utils.d.ts +20 -0
- package/dist/web/hooks/test/utils.js +75 -0
- package/dist/web/hooks/test/utils.js.map +1 -0
- package/dist/web/hooks/use-call-tool.d.ts +146 -0
- package/dist/web/hooks/use-call-tool.js +96 -0
- package/dist/web/hooks/use-call-tool.js.map +1 -0
- package/dist/web/hooks/use-call-tool.test-d.d.ts +1 -0
- package/dist/web/hooks/use-call-tool.test-d.js +104 -0
- package/dist/web/hooks/use-call-tool.test-d.js.map +1 -0
- package/dist/web/hooks/use-call-tool.test.d.ts +1 -0
- package/dist/web/hooks/use-call-tool.test.js +225 -0
- package/dist/web/hooks/use-call-tool.test.js.map +1 -0
- package/dist/web/hooks/use-display-mode.d.ts +24 -0
- package/dist/web/hooks/use-display-mode.js +29 -0
- package/dist/web/hooks/use-display-mode.js.map +1 -0
- package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
- package/dist/web/hooks/use-display-mode.test-d.js +8 -0
- package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
- package/dist/web/hooks/use-display-mode.test.d.ts +1 -0
- package/dist/web/hooks/use-display-mode.test.js +77 -0
- package/dist/web/hooks/use-display-mode.test.js.map +1 -0
- package/dist/web/hooks/use-download.d.ts +5 -0
- package/dist/web/hooks/use-download.js +8 -0
- package/dist/web/hooks/use-download.js.map +1 -0
- package/dist/web/hooks/use-download.test.d.ts +1 -0
- package/dist/web/hooks/use-download.test.js +103 -0
- package/dist/web/hooks/use-download.test.js.map +1 -0
- package/dist/web/hooks/use-files.d.ts +39 -0
- package/dist/web/hooks/use-files.js +42 -0
- package/dist/web/hooks/use-files.js.map +1 -0
- package/dist/web/hooks/use-files.test.d.ts +1 -0
- package/dist/web/hooks/use-files.test.js +62 -0
- package/dist/web/hooks/use-files.test.js.map +1 -0
- package/dist/web/hooks/use-layout.d.ts +24 -0
- package/dist/web/hooks/use-layout.js +25 -0
- package/dist/web/hooks/use-layout.js.map +1 -0
- package/dist/web/hooks/use-layout.test.d.ts +1 -0
- package/dist/web/hooks/use-layout.test.js +129 -0
- package/dist/web/hooks/use-layout.test.js.map +1 -0
- package/dist/web/hooks/use-open-external.d.ts +20 -0
- package/dist/web/hooks/use-open-external.js +24 -0
- package/dist/web/hooks/use-open-external.js.map +1 -0
- package/dist/web/hooks/use-open-external.test.d.ts +1 -0
- package/dist/web/hooks/use-open-external.test.js +75 -0
- package/dist/web/hooks/use-open-external.test.js.map +1 -0
- package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
- package/dist/web/hooks/use-register-view-tool.js +50 -0
- package/dist/web/hooks/use-register-view-tool.js.map +1 -0
- package/dist/web/hooks/use-request-close.d.ts +16 -0
- package/dist/web/hooks/use-request-close.js +21 -0
- package/dist/web/hooks/use-request-close.js.map +1 -0
- package/dist/web/hooks/use-request-close.test.d.ts +1 -0
- package/dist/web/hooks/use-request-close.test.js +47 -0
- package/dist/web/hooks/use-request-close.test.js.map +1 -0
- package/dist/web/hooks/use-request-modal.d.ts +24 -0
- package/dist/web/hooks/use-request-modal.js +31 -0
- package/dist/web/hooks/use-request-modal.js.map +1 -0
- package/dist/web/hooks/use-request-modal.test.d.ts +1 -0
- package/dist/web/hooks/use-request-modal.test.js +71 -0
- package/dist/web/hooks/use-request-modal.test.js.map +1 -0
- package/dist/web/hooks/use-request-size.d.ts +20 -0
- package/dist/web/hooks/use-request-size.js +24 -0
- package/dist/web/hooks/use-request-size.js.map +1 -0
- package/dist/web/hooks/use-request-size.test.d.ts +1 -0
- package/dist/web/hooks/use-request-size.test.js +47 -0
- package/dist/web/hooks/use-request-size.test.js.map +1 -0
- package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -0
- package/dist/web/hooks/use-send-follow-up-message.js +25 -0
- package/dist/web/hooks/use-send-follow-up-message.js.map +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
- package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
- package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.js +63 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
- package/dist/web/hooks/use-tool-info.d.ts +87 -0
- package/dist/web/hooks/use-tool-info.js +49 -0
- package/dist/web/hooks/use-tool-info.js.map +1 -0
- package/dist/web/hooks/use-tool-info.test-d.d.ts +1 -0
- package/dist/web/hooks/use-tool-info.test-d.js +91 -0
- package/dist/web/hooks/use-tool-info.test-d.js.map +1 -0
- package/dist/web/hooks/use-tool-info.test.d.ts +1 -0
- package/dist/web/hooks/use-tool-info.test.js +140 -0
- package/dist/web/hooks/use-tool-info.test.js.map +1 -0
- package/dist/web/hooks/use-user.d.ts +20 -0
- package/dist/web/hooks/use-user.js +37 -0
- package/dist/web/hooks/use-user.js.map +1 -0
- package/dist/web/hooks/use-user.test.d.ts +1 -0
- package/dist/web/hooks/use-user.test.js +168 -0
- package/dist/web/hooks/use-user.test.js.map +1 -0
- package/dist/web/hooks/use-view-state.d.ts +25 -0
- package/dist/web/hooks/use-view-state.js +32 -0
- package/dist/web/hooks/use-view-state.js.map +1 -0
- package/dist/web/hooks/use-view-state.test.d.ts +1 -0
- package/dist/web/hooks/use-view-state.test.js +181 -0
- package/dist/web/hooks/use-view-state.test.js.map +1 -0
- package/dist/web/index.d.ts +7 -0
- package/dist/web/index.js +8 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/mount-view.d.ts +20 -0
- package/dist/web/mount-view.js +46 -0
- package/dist/web/mount-view.js.map +1 -0
- package/dist/web/plugin/data-llm.test.d.ts +1 -0
- package/dist/web/plugin/data-llm.test.js +81 -0
- package/dist/web/plugin/data-llm.test.js.map +1 -0
- package/dist/web/plugin/plugin.d.ts +33 -0
- package/dist/web/plugin/plugin.js +188 -0
- package/dist/web/plugin/plugin.js.map +1 -0
- package/dist/web/plugin/scan-views.d.ts +16 -0
- package/dist/web/plugin/scan-views.js +88 -0
- package/dist/web/plugin/scan-views.js.map +1 -0
- package/dist/web/plugin/scan-views.test.d.ts +1 -0
- package/dist/web/plugin/scan-views.test.js +99 -0
- package/dist/web/plugin/scan-views.test.js.map +1 -0
- package/dist/web/plugin/transform-data-llm.d.ts +12 -0
- package/dist/web/plugin/transform-data-llm.js +96 -0
- package/dist/web/plugin/transform-data-llm.js.map +1 -0
- package/dist/web/plugin/transform-data-llm.test.d.ts +1 -0
- package/dist/web/plugin/transform-data-llm.test.js +81 -0
- package/dist/web/plugin/transform-data-llm.test.js.map +1 -0
- package/dist/web/plugin/validate-view.d.ts +1 -0
- package/dist/web/plugin/validate-view.js +9 -0
- package/dist/web/plugin/validate-view.js.map +1 -0
- package/dist/web/plugin/validate-view.test.d.ts +1 -0
- package/dist/web/plugin/validate-view.test.js +24 -0
- package/dist/web/plugin/validate-view.test.js.map +1 -0
- package/dist/web/proxy.d.ts +1 -0
- package/dist/web/proxy.js +52 -0
- package/dist/web/proxy.js.map +1 -0
- package/dist/web/types.d.ts +20 -0
- package/dist/web/types.js +2 -0
- package/dist/web/types.js.map +1 -0
- package/package.json +90 -31
- package/tsconfig.base.json +33 -0
- package/dist/src/server/index.d.ts +0 -2
- package/dist/src/server/index.js +0 -3
- package/dist/src/server/index.js.map +0 -1
- package/dist/src/server/server.d.ts +0 -13
- package/dist/src/server/server.js +0 -54
- package/dist/src/server/server.js.map +0 -1
- package/dist/src/server/templateHelper.js +0 -29
- package/dist/src/server/templateHelper.js.map +0 -1
- package/dist/src/server/templates/development.hbs +0 -12
- package/dist/src/server/templates/production.hbs +0 -6
- package/dist/src/server/widgetsDevServer.d.ts +0 -12
- package/dist/src/server/widgetsDevServer.js +0 -39
- package/dist/src/server/widgetsDevServer.js.map +0 -1
- package/dist/src/test/setup.js +0 -9
- package/dist/src/test/setup.js.map +0 -1
- package/dist/src/test/utils.d.ts +0 -28
- package/dist/src/test/utils.js +0 -43
- package/dist/src/test/utils.js.map +0 -1
- package/dist/src/test/widget.test.js +0 -76
- package/dist/src/test/widget.test.js.map +0 -1
- package/dist/src/web/index.d.ts +0 -5
- package/dist/src/web/index.js +0 -6
- package/dist/src/web/index.js.map +0 -1
- package/dist/src/web/mount-widget.d.ts +0 -1
- package/dist/src/web/mount-widget.js +0 -14
- package/dist/src/web/mount-widget.js.map +0 -1
- package/dist/src/web/plugin.d.ts +0 -2
- package/dist/src/web/plugin.js +0 -28
- package/dist/src/web/plugin.js.map +0 -1
- package/dist/src/web/types.d.ts +0 -95
- package/dist/src/web/types.js.map +0 -1
- package/dist/src/web/use-openai-global.d.ts +0 -2
- package/dist/src/web/use-openai-global.js +0 -21
- package/dist/src/web/use-openai-global.js.map +0 -1
- package/dist/src/web/use-tool-output.d.ts +0 -3
- package/dist/src/web/use-tool-output.js +0 -5
- package/dist/src/web/use-tool-output.js.map +0 -1
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -9
- package/dist/vitest.config.js.map +0 -1
- /package/dist/{src/test/setup.d.ts → cli/build-helpers.test.d.ts} +0 -0
- /package/dist/{src/test/widget.test.d.ts → cli/build-steps.test.d.ts} +0 -0
- /package/dist/{src/web → web/bridges/apps-sdk}/types.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel.test.js","sourceRoot":"","sources":["../../src/cli/tunnel.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"node:events\";\nimport { Readable } from \"node:stream\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { parseStdoutLine, TunnelManager, type TunnelState } from \"./tunnel.js\";\n\ndescribe(\"parseStdoutLine\", () => {\n it(\"returns a connected event when the forwarding line is seen\", () => {\n const result = parseStdoutLine(\n \"Forwarding: https://abc.tunnel.example -> http://localhost:3000\",\n );\n expect(result).toEqual({\n kind: \"connected\",\n url: \"https://abc.tunnel.example\",\n });\n });\n\n it(\"strips a trailing slash from the forwarded URL\", () => {\n const result = parseStdoutLine(\n \"Forwarding: https://abc.tunnel.example/ -> http://localhost:3000\",\n );\n expect(result).toEqual({\n kind: \"connected\",\n url: \"https://abc.tunnel.example\",\n });\n });\n\n it(\"returns a starting event for any other non-empty line\", () => {\n expect(parseStdoutLine(\"Opening tunnel...\")).toEqual({\n kind: \"starting\",\n message: \"Opening tunnel...\",\n });\n });\n\n it(\"returns null for empty lines\", () => {\n expect(parseStdoutLine(\"\")).toBeNull();\n expect(parseStdoutLine(\" \")).toBeNull();\n });\n});\n\ntype FakeChild = EventEmitter & {\n stdout: Readable;\n stderr: Readable;\n kill: ReturnType<typeof vi.fn<() => boolean>>;\n};\n\nfunction makeFakeChild(): FakeChild {\n const child = new EventEmitter() as FakeChild;\n child.stdout = new Readable({ read() {} });\n child.stderr = new Readable({ read() {} });\n child.kill = vi.fn<() => boolean>(() => true);\n return child;\n}\n\ndescribe(\"TunnelManager\", () => {\n beforeEach(() => {\n vi.useFakeTimers();\n });\n afterEach(() => {\n vi.useRealTimers();\n });\n\n it(\"starts idle\", () => {\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => makeFakeChild(),\n });\n expect(manager.getState()).toEqual({ status: \"idle\" });\n });\n\n it(\"transitions idle -> starting -> connected as stdout reports progress\", () => {\n const child = makeFakeChild();\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => child,\n });\n const states: string[] = [];\n manager.on(\"state\", (s: TunnelState) => states.push(s.status));\n\n manager.start();\n child.stdout.emit(\"data\", Buffer.from(\"Opening tunnel...\\n\"));\n child.stdout.emit(\n \"data\",\n Buffer.from(\n \"Forwarding: https://abc.tunnel.example -> http://localhost:3000\\n\",\n ),\n );\n\n expect(states).toEqual([\"starting\", \"starting\", \"connected\"]);\n expect(manager.getState()).toEqual({\n status: \"connected\",\n url: \"https://abc.tunnel.example\",\n });\n });\n\n it(\"emits activity events for stdout lines after connect\", () => {\n const child = makeFakeChild();\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => child,\n });\n const activity: Array<{ text: string; level: string }> = [];\n manager.on(\"activity\", (a: { text: string; level: string }) =>\n activity.push({ text: a.text, level: a.level }),\n );\n\n manager.start();\n child.stdout.emit(\n \"data\",\n Buffer.from(\n \"Forwarding: https://abc.tunnel.example -> http://localhost:3000\\n\",\n ),\n );\n child.stdout.emit(\"data\", Buffer.from(\"GET /widgets/foo\\n\"));\n child.stderr.emit(\"data\", Buffer.from(\"connection wobble\\n\"));\n\n expect(activity).toEqual([\n { text: \"GET /widgets/foo\", level: \"log\" },\n { text: \"connection wobble\", level: \"error\" },\n ]);\n });\n\n it(\"calling start twice does not spawn twice\", () => {\n const spawn = vi.fn(() => makeFakeChild());\n const manager = new TunnelManager({ getPort: () => 3000, spawn });\n manager.start();\n manager.start();\n expect(spawn).toHaveBeenCalledTimes(1);\n });\n\n it(\"transitions to error when the connection times out\", () => {\n const child = makeFakeChild();\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => child,\n });\n manager.start();\n\n vi.advanceTimersByTime(60_000);\n\n expect(manager.getState().status).toBe(\"error\");\n expect(child.kill).toHaveBeenCalled();\n });\n\n it(\"preserves the timeout error message when the killed child later emits close\", () => {\n const child = makeFakeChild();\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => child,\n });\n manager.start();\n\n vi.advanceTimersByTime(60_000);\n // The killed child emits a non-zero close after the timeout fired.\n child.emit(\"close\", 1);\n\n expect(manager.getState()).toEqual({\n status: \"error\",\n message: \"Tunnel connection timed out after one minute\",\n });\n });\n\n it(\"stop() kills the subprocess and goes idle\", () => {\n const child = makeFakeChild();\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => child,\n });\n manager.start();\n manager.stop();\n expect(child.kill).toHaveBeenCalled();\n expect(manager.getState()).toEqual({ status: \"idle\" });\n });\n\n it(\"subscribers get the current state on subscribe\", () => {\n const child = makeFakeChild();\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => child,\n });\n manager.start();\n child.stdout.emit(\n \"data\",\n Buffer.from(\n \"Forwarding: https://abc.tunnel.example -> http://localhost:3000\\n\",\n ),\n );\n\n let received: TunnelState | undefined;\n const unsubscribe = manager.subscribe((s) => {\n received = s;\n });\n expect(received).toEqual({\n status: \"connected\",\n url: \"https://abc.tunnel.example\",\n });\n unsubscribe();\n });\n\n it(\"ignores deferred close from a child that was replaced via stop()+start()\", () => {\n const childA = makeFakeChild();\n const childB = makeFakeChild();\n let spawnCount = 0;\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => (spawnCount++ === 0 ? childA : childB),\n });\n\n manager.start();\n manager.stop();\n manager.start();\n childB.stdout.emit(\n \"data\",\n Buffer.from(\n \"Forwarding: https://abc.tunnel.example -> http://localhost:3000\\n\",\n ),\n );\n expect(manager.getState()).toEqual({\n status: \"connected\",\n url: \"https://abc.tunnel.example\",\n });\n\n // Stale close from childA arrives only now — must not clobber state.\n childA.emit(\"close\", null);\n expect(manager.getState()).toEqual({\n status: \"connected\",\n url: \"https://abc.tunnel.example\",\n });\n });\n\n it(\"ignores deferred error from a child that was replaced via stop()+start()\", () => {\n const childA = makeFakeChild();\n const childB = makeFakeChild();\n let spawnCount = 0;\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => (spawnCount++ === 0 ? childA : childB),\n });\n\n manager.start();\n manager.stop();\n manager.start();\n childB.stdout.emit(\n \"data\",\n Buffer.from(\n \"Forwarding: https://abc.tunnel.example -> http://localhost:3000\\n\",\n ),\n );\n\n childA.emit(\"error\", new Error(\"late spawn failure\"));\n expect(manager.getState()).toEqual({\n status: \"connected\",\n url: \"https://abc.tunnel.example\",\n });\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"","sourcesContent":["export type Message = {\n id: string;\n text: string;\n type: \"log\" | \"restart\" | \"error\";\n};\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CommandStep {
|
|
2
|
+
label: string;
|
|
3
|
+
command?: string;
|
|
4
|
+
run?: () => void | Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare const useExecuteSteps: (steps: CommandStep[]) => {
|
|
7
|
+
currentStep: number;
|
|
8
|
+
status: "error" | "running" | "success";
|
|
9
|
+
error: string | null;
|
|
10
|
+
execute: () => Promise<void>;
|
|
11
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
import { runCommand } from "./run-command.js";
|
|
3
|
+
export const useExecuteSteps = (steps) => {
|
|
4
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
5
|
+
const [status, setStatus] = useState("running");
|
|
6
|
+
const [error, setError] = useState(null);
|
|
7
|
+
const execute = useCallback(async () => {
|
|
8
|
+
try {
|
|
9
|
+
for (let i = 0; i < steps.length; i++) {
|
|
10
|
+
const step = steps[i];
|
|
11
|
+
if (step) {
|
|
12
|
+
setCurrentStep(i);
|
|
13
|
+
if (step.run) {
|
|
14
|
+
await step.run();
|
|
15
|
+
}
|
|
16
|
+
if (step.command) {
|
|
17
|
+
await runCommand(step.command);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
setStatus("success");
|
|
22
|
+
setImmediate(() => {
|
|
23
|
+
process.exit(0);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
setStatus("error");
|
|
28
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
29
|
+
setImmediate(() => {
|
|
30
|
+
process.exit(1);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}, [steps]);
|
|
34
|
+
return { currentStep, status, error, execute };
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=use-execute-steps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-execute-steps.js","sourceRoot":"","sources":["../../src/cli/use-execute-steps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAQ9C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAoB,EAAE,EAAE;IACtD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAS,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAClC,SAAS,CACV,CAAC;IACF,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAExD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACrC,IAAI,CAAC;YACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,IAAI,IAAI,EAAE,CAAC;oBACT,cAAc,CAAC,CAAC,CAAC,CAAC;oBAClB,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;wBACb,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;oBACnB,CAAC;oBACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;wBACjB,MAAM,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACjC,CAAC;gBACH,CAAC;YACH,CAAC;YACD,SAAS,CAAC,SAAS,CAAC,CAAC;YACrB,YAAY,CAAC,GAAG,EAAE;gBAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,CAAC,OAAO,CAAC,CAAC;YACnB,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3D,YAAY,CAAC,GAAG,EAAE;gBAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACjD,CAAC,CAAC","sourcesContent":["import { useCallback, useState } from \"react\";\nimport { runCommand } from \"./run-command.js\";\n\nexport interface CommandStep {\n label: string;\n command?: string;\n run?: () => void | Promise<void>;\n}\n\nexport const useExecuteSteps = (steps: CommandStep[]) => {\n const [currentStep, setCurrentStep] = useState<number>(0);\n const [status, setStatus] = useState<\"running\" | \"success\" | \"error\">(\n \"running\",\n );\n const [error, setError] = useState<string | null>(null);\n\n const execute = useCallback(async () => {\n try {\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i];\n if (step) {\n setCurrentStep(i);\n if (step.run) {\n await step.run();\n }\n if (step.command) {\n await runCommand(step.command);\n }\n }\n }\n setStatus(\"success\");\n setImmediate(() => {\n process.exit(0);\n });\n } catch (err) {\n setStatus(\"error\");\n setError(err instanceof Error ? err.message : String(err));\n setImmediate(() => {\n process.exit(1);\n });\n }\n }, [steps]);\n\n return { currentStep, status, error, execute };\n};\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { useCallback, useState } from "react";
|
|
3
|
+
const MAX_MESSAGES = 10;
|
|
4
|
+
export function useMessages() {
|
|
5
|
+
const [messages, setMessages] = useState([]);
|
|
6
|
+
const push = useCallback((text, type) => {
|
|
7
|
+
setMessages((prev) => [...prev, { id: randomUUID(), text, type }].slice(-MAX_MESSAGES));
|
|
8
|
+
}, []);
|
|
9
|
+
return [messages, push];
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=use-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-messages.js","sourceRoot":"","sources":["../../src/cli/use-messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG9C,MAAM,YAAY,GAAG,EAAE,CAAC;AAIxB,MAAM,UAAU,WAAW;IACzB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAiB,EAAE,CAAC,CAAC;IAE7D,MAAM,IAAI,GAAG,WAAW,CAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACnD,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CACnB,CAAC,GAAG,IAAI,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CACjE,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { useCallback, useState } from \"react\";\nimport type { Message } from \"./types.js\";\n\nconst MAX_MESSAGES = 10;\n\nexport type PushMessage = (text: string, type: Message[\"type\"]) => void;\n\nexport function useMessages(): [Array<Message>, PushMessage] {\n const [messages, setMessages] = useState<Array<Message>>([]);\n\n const push = useCallback<PushMessage>((text, type) => {\n setMessages((prev) =>\n [...prev, { id: randomUUID(), text, type }].slice(-MAX_MESSAGES),\n );\n }, []);\n\n return [messages, push];\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PushMessage } from "./use-messages.js";
|
|
2
|
+
export interface NodemonHandlers {
|
|
3
|
+
/** A raw chunk of server stdout, forwarded untouched. */
|
|
4
|
+
onStdout: (chunk: Buffer) => void;
|
|
5
|
+
/** A (filtered) chunk of server stderr. */
|
|
6
|
+
onStderr: (message: string) => void;
|
|
7
|
+
/** The server restarted because the listed files changed. */
|
|
8
|
+
onRestart: (files: string[]) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Boot nodemon and wire its stdout/stderr to the provided handlers. Returns a
|
|
12
|
+
* cleanup function that detaches the listeners and quits nodemon. Shared by the
|
|
13
|
+
* Ink-based dev UI (via {@link useNodemon}) and the `--plain` runner.
|
|
14
|
+
*/
|
|
15
|
+
export declare function startNodemon(env: NodeJS.ProcessEnv, handlers: NodemonHandlers): () => void;
|
|
16
|
+
export declare function useNodemon(env: NodeJS.ProcessEnv, pushMessage: PushMessage): void;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import nodemonOriginal from "nodemon";
|
|
4
|
+
import { useEffect } from "react";
|
|
5
|
+
const nodemon = nodemonOriginal;
|
|
6
|
+
const SOURCEMAP_WARNING = /^Sourcemap for ".*" points to missing source files$/;
|
|
7
|
+
/**
|
|
8
|
+
* Boot nodemon and wire its stdout/stderr to the provided handlers. Returns a
|
|
9
|
+
* cleanup function that detaches the listeners and quits nodemon. Shared by the
|
|
10
|
+
* Ink-based dev UI (via {@link useNodemon}) and the `--plain` runner.
|
|
11
|
+
*/
|
|
12
|
+
export function startNodemon(env, handlers) {
|
|
13
|
+
const configFile = resolve(process.cwd(), "nodemon.json");
|
|
14
|
+
const config = existsSync(configFile)
|
|
15
|
+
? {
|
|
16
|
+
configFile,
|
|
17
|
+
}
|
|
18
|
+
: {
|
|
19
|
+
watch: ["src"],
|
|
20
|
+
ext: "ts,json",
|
|
21
|
+
exec: "tsx src/server.ts",
|
|
22
|
+
};
|
|
23
|
+
nodemon({ ...config, env, stdout: false });
|
|
24
|
+
const handleStdoutData = (chunk) => {
|
|
25
|
+
handlers.onStdout(chunk);
|
|
26
|
+
};
|
|
27
|
+
const handleStderrData = (chunk) => {
|
|
28
|
+
const message = chunk.toString().trim();
|
|
29
|
+
if (!message) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Node's source-map warnings for third-party deps (superjson, @mcp/sdk, …) — not actionable.
|
|
33
|
+
const filtered = message
|
|
34
|
+
.split("\n")
|
|
35
|
+
.filter((line) => !SOURCEMAP_WARNING.test(line))
|
|
36
|
+
.join("\n");
|
|
37
|
+
if (filtered) {
|
|
38
|
+
handlers.onStderr(filtered);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const setupStdoutListener = () => {
|
|
42
|
+
if (nodemon.stdout) {
|
|
43
|
+
nodemon.stdout.off("data", handleStdoutData);
|
|
44
|
+
nodemon.stdout.on("data", handleStdoutData);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const setupStderrListener = () => {
|
|
48
|
+
if (nodemon.stderr) {
|
|
49
|
+
nodemon.stderr.off("data", handleStderrData);
|
|
50
|
+
nodemon.stderr.on("data", handleStderrData);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
nodemon.on("readable", () => {
|
|
54
|
+
setupStdoutListener();
|
|
55
|
+
setupStderrListener();
|
|
56
|
+
});
|
|
57
|
+
nodemon.on("restart", (files) => {
|
|
58
|
+
handlers.onRestart(files);
|
|
59
|
+
setupStdoutListener();
|
|
60
|
+
setupStderrListener();
|
|
61
|
+
});
|
|
62
|
+
return () => {
|
|
63
|
+
if (nodemon.stdout) {
|
|
64
|
+
nodemon.stdout.off("data", handleStdoutData);
|
|
65
|
+
}
|
|
66
|
+
if (nodemon.stderr) {
|
|
67
|
+
nodemon.stderr.off("data", handleStderrData);
|
|
68
|
+
}
|
|
69
|
+
nodemon.emit("quit");
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function useNodemon(env, pushMessage) {
|
|
73
|
+
useEffect(() => startNodemon(env, {
|
|
74
|
+
onStdout: (chunk) => {
|
|
75
|
+
const message = chunk.toString().trim();
|
|
76
|
+
if (message) {
|
|
77
|
+
pushMessage(message, "log");
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
onStderr: (message) => pushMessage(message, "error"),
|
|
81
|
+
onRestart: (files) => pushMessage(`Server restarted due to file changes: ${files.join(", ")}`, "restart"),
|
|
82
|
+
}), [env, pushMessage]);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=use-nodemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-nodemon.js","sourceRoot":"","sources":["../../src/cli/use-nodemon.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport nodemonOriginal from \"nodemon\";\nimport { useEffect } from \"react\";\nimport type { ExtendedNodemon } from \"./nodemon.d.ts\";\nimport type { PushMessage } from \"./use-messages.js\";\n\nconst nodemon = nodemonOriginal as ExtendedNodemon;\n\nconst SOURCEMAP_WARNING = /^Sourcemap for \".*\" points to missing source files$/;\n\nexport interface NodemonHandlers {\n /** A raw chunk of server stdout, forwarded untouched. */\n onStdout: (chunk: Buffer) => void;\n /** A (filtered) chunk of server stderr. */\n onStderr: (message: string) => void;\n /** The server restarted because the listed files changed. */\n onRestart: (files: string[]) => void;\n}\n\n/**\n * Boot nodemon and wire its stdout/stderr to the provided handlers. Returns a\n * cleanup function that detaches the listeners and quits nodemon. Shared by the\n * Ink-based dev UI (via {@link useNodemon}) and the `--plain` runner.\n */\nexport function startNodemon(\n env: NodeJS.ProcessEnv,\n handlers: NodemonHandlers,\n): () => void {\n const configFile = resolve(process.cwd(), \"nodemon.json\");\n\n const config = existsSync(configFile)\n ? {\n configFile,\n }\n : {\n watch: [\"src\"],\n ext: \"ts,json\",\n exec: \"tsx src/server.ts\",\n };\n\n nodemon({ ...config, env, stdout: false });\n\n const handleStdoutData = (chunk: Buffer) => {\n handlers.onStdout(chunk);\n };\n\n const handleStderrData = (chunk: Buffer) => {\n const message = chunk.toString().trim();\n if (!message) {\n return;\n }\n // Node's source-map warnings for third-party deps (superjson, @mcp/sdk, …) — not actionable.\n const filtered = message\n .split(\"\\n\")\n .filter((line) => !SOURCEMAP_WARNING.test(line))\n .join(\"\\n\");\n if (filtered) {\n handlers.onStderr(filtered);\n }\n };\n\n const setupStdoutListener = () => {\n if (nodemon.stdout) {\n nodemon.stdout.off(\"data\", handleStdoutData);\n nodemon.stdout.on(\"data\", handleStdoutData);\n }\n };\n\n const setupStderrListener = () => {\n if (nodemon.stderr) {\n nodemon.stderr.off(\"data\", handleStderrData);\n nodemon.stderr.on(\"data\", handleStderrData);\n }\n };\n\n nodemon.on(\"readable\", () => {\n setupStdoutListener();\n setupStderrListener();\n });\n\n nodemon.on(\"restart\", (files: string[]) => {\n handlers.onRestart(files);\n setupStdoutListener();\n setupStderrListener();\n });\n\n return () => {\n if (nodemon.stdout) {\n nodemon.stdout.off(\"data\", handleStdoutData);\n }\n if (nodemon.stderr) {\n nodemon.stderr.off(\"data\", handleStderrData);\n }\n nodemon.emit(\"quit\");\n };\n}\n\nexport function useNodemon(\n env: NodeJS.ProcessEnv,\n pushMessage: PushMessage,\n): void {\n useEffect(\n () =>\n startNodemon(env, {\n onStdout: (chunk) => {\n const message = chunk.toString().trim();\n if (message) {\n pushMessage(message, \"log\");\n }\n },\n onStderr: (message) => pushMessage(message, \"error\"),\n onRestart: (files) =>\n pushMessage(\n `Server restarted due to file changes: ${files.join(\", \")}`,\n \"restart\",\n ),\n }),\n [env, pushMessage],\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useOpenBrowser(port: number, enabled: boolean): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import net from "node:net";
|
|
2
|
+
import open from "open";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
const POLL_INTERVAL_MS = 200;
|
|
5
|
+
const POLL_TIMEOUT_MS = 5_000;
|
|
6
|
+
const isPortListening = (port) => new Promise((resolve) => {
|
|
7
|
+
const socket = net.createConnection({ port, host: "127.0.0.1" });
|
|
8
|
+
socket.once("connect", () => {
|
|
9
|
+
socket.end();
|
|
10
|
+
resolve(true);
|
|
11
|
+
});
|
|
12
|
+
socket.once("error", () => {
|
|
13
|
+
socket.destroy();
|
|
14
|
+
resolve(false);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
export function useOpenBrowser(port, enabled) {
|
|
18
|
+
const opened = useRef(false);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!enabled || opened.current) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
let cancelled = false;
|
|
24
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
25
|
+
const tick = async () => {
|
|
26
|
+
while (!cancelled && Date.now() < deadline) {
|
|
27
|
+
if (await isPortListening(port)) {
|
|
28
|
+
if (cancelled || opened.current) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
opened.current = true;
|
|
32
|
+
await open(`http://localhost:${port}/`).catch(() => { });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
void tick();
|
|
39
|
+
return () => {
|
|
40
|
+
cancelled = true;
|
|
41
|
+
};
|
|
42
|
+
}, [port, enabled]);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=use-open-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-open-browser.js","sourceRoot":"","sources":["../../src/cli/use-open-browser.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE1C,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B,MAAM,eAAe,GAAG,CAAC,IAAY,EAAoB,EAAE,CACzD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;IACtB,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IACjE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;QAC1B,MAAM,CAAC,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,OAAgB;IAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE7B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe,CAAC;QAE9C,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;YACtB,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;gBAC3C,IAAI,MAAM,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;oBAChC,IAAI,SAAS,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;wBAChC,OAAO;oBACT,CAAC;oBACD,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;oBACtB,MAAM,IAAI,CAAC,oBAAoB,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBACxD,OAAO;gBACT,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC,CAAC;QAEF,KAAK,IAAI,EAAE,CAAC;QAEZ,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AACtB,CAAC","sourcesContent":["import net from \"node:net\";\nimport open from \"open\";\nimport { useEffect, useRef } from \"react\";\n\nconst POLL_INTERVAL_MS = 200;\nconst POLL_TIMEOUT_MS = 5_000;\n\nconst isPortListening = (port: number): Promise<boolean> =>\n new Promise((resolve) => {\n const socket = net.createConnection({ port, host: \"127.0.0.1\" });\n socket.once(\"connect\", () => {\n socket.end();\n resolve(true);\n });\n socket.once(\"error\", () => {\n socket.destroy();\n resolve(false);\n });\n });\n\nexport function useOpenBrowser(port: number, enabled: boolean): void {\n const opened = useRef(false);\n\n useEffect(() => {\n if (!enabled || opened.current) {\n return;\n }\n\n let cancelled = false;\n const deadline = Date.now() + POLL_TIMEOUT_MS;\n\n const tick = async () => {\n while (!cancelled && Date.now() < deadline) {\n if (await isPortListening(port)) {\n if (cancelled || opened.current) {\n return;\n }\n opened.current = true;\n await open(`http://localhost:${port}/`).catch(() => {});\n return;\n }\n await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));\n }\n };\n\n void tick();\n\n return () => {\n cancelled = true;\n };\n }, [port, enabled]);\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PushMessage } from "./use-messages.js";
|
|
2
|
+
export type TunnelState = {
|
|
3
|
+
status: "idle";
|
|
4
|
+
} | {
|
|
5
|
+
status: "starting";
|
|
6
|
+
message: string;
|
|
7
|
+
} | {
|
|
8
|
+
status: "connected";
|
|
9
|
+
url: string;
|
|
10
|
+
} | {
|
|
11
|
+
status: "error";
|
|
12
|
+
message: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function useTunnel(port: number | null, pushMessage: PushMessage, verbose: boolean, autoStart: boolean): TunnelState;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
const POST_RETRY_DELAY_MS = 250;
|
|
3
|
+
export function useTunnel(port, pushMessage, verbose, autoStart) {
|
|
4
|
+
const [state, setState] = useState(port !== null && autoStart
|
|
5
|
+
? { status: "starting", message: "Starting tunnel…" }
|
|
6
|
+
: { status: "idle" });
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (port === null) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const baseUrl = `http://localhost:${port}`;
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
let cancelled = false;
|
|
14
|
+
const pushLog = (text, type) => {
|
|
15
|
+
const time = new Date().toLocaleTimeString("en-US", {
|
|
16
|
+
hour: "numeric",
|
|
17
|
+
minute: "2-digit",
|
|
18
|
+
second: "2-digit",
|
|
19
|
+
hour12: true,
|
|
20
|
+
});
|
|
21
|
+
pushMessage(`${time} [tunnel] ${text}`, type);
|
|
22
|
+
};
|
|
23
|
+
const handleEvent = (event, data) => {
|
|
24
|
+
if (event === "state") {
|
|
25
|
+
const next = JSON.parse(data);
|
|
26
|
+
setState(next);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (event === "activity") {
|
|
30
|
+
if (!verbose) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const activity = JSON.parse(data);
|
|
34
|
+
pushLog(activity.text, activity.level);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const consumeSse = async () => {
|
|
38
|
+
const res = await fetch(`${baseUrl}/__skybridge/tunnel/events`, {
|
|
39
|
+
signal: controller.signal,
|
|
40
|
+
headers: { Accept: "text/event-stream" },
|
|
41
|
+
});
|
|
42
|
+
if (!res.ok || !res.body) {
|
|
43
|
+
throw new Error(`SSE connection failed (${res.status})`);
|
|
44
|
+
}
|
|
45
|
+
const reader = res.body.getReader();
|
|
46
|
+
const decoder = new TextDecoder();
|
|
47
|
+
let buffer = "";
|
|
48
|
+
while (!cancelled) {
|
|
49
|
+
const { value, done } = await reader.read();
|
|
50
|
+
if (done) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
buffer += decoder.decode(value, { stream: true });
|
|
54
|
+
// SSE frames are separated by a blank line ("\n\n").
|
|
55
|
+
let sep = buffer.indexOf("\n\n");
|
|
56
|
+
while (sep !== -1) {
|
|
57
|
+
const frame = buffer.slice(0, sep);
|
|
58
|
+
buffer = buffer.slice(sep + 2);
|
|
59
|
+
let eventName = "message";
|
|
60
|
+
const dataLines = [];
|
|
61
|
+
for (const rawLine of frame.split("\n")) {
|
|
62
|
+
const line = rawLine.replace(/\r$/, "");
|
|
63
|
+
if (line.startsWith("event:")) {
|
|
64
|
+
eventName = line.slice(6).trim();
|
|
65
|
+
}
|
|
66
|
+
else if (line.startsWith("data:")) {
|
|
67
|
+
dataLines.push(line.slice(5).trimStart());
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (dataLines.length > 0) {
|
|
71
|
+
handleEvent(eventName, dataLines.join("\n"));
|
|
72
|
+
}
|
|
73
|
+
sep = buffer.indexOf("\n\n");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const postUntilStarted = async () => {
|
|
78
|
+
// Retry indefinitely until POST lands once. Bounded by the effect
|
|
79
|
+
// lifetime via controller.abort() on unmount. Once the manager has
|
|
80
|
+
// been started, this returns and never POSTs again — a user-driven
|
|
81
|
+
// DELETE /tunnel won't be auto-undone.
|
|
82
|
+
while (!cancelled) {
|
|
83
|
+
try {
|
|
84
|
+
const res = await fetch(`${baseUrl}/__skybridge/tunnel`, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
signal: controller.signal,
|
|
87
|
+
});
|
|
88
|
+
if (res.ok) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// dev server not up yet (or restarting under nodemon) — wait, retry
|
|
94
|
+
}
|
|
95
|
+
await new Promise((r) => setTimeout(r, POST_RETRY_DELAY_MS));
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
// Always observe the tunnel state so external triggers (curl, future
|
|
99
|
+
// devtools UI) update the cli UI. `autoStart` only decides whether we
|
|
100
|
+
// also POST /tunnel on mount. Reconnects indefinitely so we survive
|
|
101
|
+
// dev-server boot delay and nodemon restarts; the cli owns the actual
|
|
102
|
+
// subprocess so a temporarily-unreachable dev server is fine.
|
|
103
|
+
const observe = async () => {
|
|
104
|
+
while (!cancelled) {
|
|
105
|
+
try {
|
|
106
|
+
await consumeSse();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// network error or stream ended abnormally — fall through to retry
|
|
110
|
+
}
|
|
111
|
+
if (cancelled) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
await new Promise((r) => setTimeout(r, POST_RETRY_DELAY_MS));
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
// observe() always runs — it owns the cli's view of tunnel state. POST is
|
|
118
|
+
// a fire-and-forget side-effect that nudges the manager into starting and
|
|
119
|
+
// retries until it lands at least once.
|
|
120
|
+
if (autoStart) {
|
|
121
|
+
void postUntilStarted();
|
|
122
|
+
}
|
|
123
|
+
void observe();
|
|
124
|
+
return () => {
|
|
125
|
+
cancelled = true;
|
|
126
|
+
controller.abort();
|
|
127
|
+
};
|
|
128
|
+
}, [port, pushMessage, verbose, autoStart]);
|
|
129
|
+
return state;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=use-tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tunnel.js","sourceRoot":"","sources":["../../src/cli/use-tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAe5C,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,UAAU,SAAS,CACvB,IAAmB,EACnB,WAAwB,EACxB,OAAgB,EAChB,SAAkB;IAElB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAChC,IAAI,KAAK,IAAI,IAAI,SAAS;QACxB,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,kBAAkB,EAAE;QACrD,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CACvB,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,oBAAoB,IAAI,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,IAAqB,EAAE,EAAE;YACtD,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE;gBAClD,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;YACH,WAAW,CAAC,GAAG,IAAI,aAAa,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC;QAEF,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,IAAY,EAAE,EAAE;YAClD,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBACtB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAgB,CAAC;gBAC7C,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACf,OAAO;YACT,CAAC;YACD,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;gBACzB,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO;gBACT,CAAC;gBACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;gBACpD,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;YACzC,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE;YAC5B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,4BAA4B,EAAE;gBAC9D,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,OAAO,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAE;aACzC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;YAC3D,CAAC;YAED,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;YAClC,IAAI,MAAM,GAAG,EAAE,CAAC;YAEhB,OAAO,CAAC,SAAS,EAAE,CAAC;gBAClB,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,IAAI,EAAE,CAAC;oBACT,OAAO;gBACT,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;gBAElD,qDAAqD;gBACrD,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBACjC,OAAO,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;oBAClB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;oBACnC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;oBAC/B,IAAI,SAAS,GAAG,SAAS,CAAC;oBAC1B,MAAM,SAAS,GAAa,EAAE,CAAC;oBAC/B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;wBACxC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;wBACxC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;4BAC9B,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;wBACnC,CAAC;6BAAM,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;4BACpC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;wBAC5C,CAAC;oBACH,CAAC;oBACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACzB,WAAW,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;oBAC/C,CAAC;oBACD,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;YAClC,kEAAkE;YAClE,mEAAmE;YACnE,mEAAmE;YACnE,uCAAuC;YACvC,OAAO,CAAC,SAAS,EAAE,CAAC;gBAClB,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,qBAAqB,EAAE;wBACvD,MAAM,EAAE,MAAM;wBACd,MAAM,EAAE,UAAU,CAAC,MAAM;qBAC1B,CAAC,CAAC;oBACH,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;wBACX,OAAO;oBACT,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,oEAAoE;gBACtE,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC,CAAC;QAEF,qEAAqE;QACrE,sEAAsE;QACtE,oEAAoE;QACpE,sEAAsE;QACtE,8DAA8D;QAC9D,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,OAAO,CAAC,SAAS,EAAE,CAAC;gBAClB,IAAI,CAAC;oBACH,MAAM,UAAU,EAAE,CAAC;gBACrB,CAAC;gBAAC,MAAM,CAAC;oBACP,mEAAmE;gBACrE,CAAC;gBACD,IAAI,SAAS,EAAE,CAAC;oBACd,OAAO;gBACT,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC,CAAC;QAEF,0EAA0E;QAC1E,0EAA0E;QAC1E,wCAAwC;QACxC,IAAI,SAAS,EAAE,CAAC;YACd,KAAK,gBAAgB,EAAE,CAAC;QAC1B,CAAC;QACD,KAAK,OAAO,EAAE,CAAC;QAEf,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,UAAU,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;IAE5C,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { PushMessage } from \"./use-messages.js\";\n\nexport type TunnelState =\n | { status: \"idle\" }\n | { status: \"starting\"; message: string }\n | { status: \"connected\"; url: string }\n | { status: \"error\"; message: string };\n\ntype TunnelActivity = {\n time: string;\n text: string;\n level: \"log\" | \"error\";\n};\n\nconst POST_RETRY_DELAY_MS = 250;\n\nexport function useTunnel(\n port: number | null,\n pushMessage: PushMessage,\n verbose: boolean,\n autoStart: boolean,\n): TunnelState {\n const [state, setState] = useState<TunnelState>(\n port !== null && autoStart\n ? { status: \"starting\", message: \"Starting tunnel…\" }\n : { status: \"idle\" },\n );\n\n useEffect(() => {\n if (port === null) {\n return;\n }\n\n const baseUrl = `http://localhost:${port}`;\n const controller = new AbortController();\n let cancelled = false;\n\n const pushLog = (text: string, type: \"log\" | \"error\") => {\n const time = new Date().toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: true,\n });\n pushMessage(`${time} [tunnel] ${text}`, type);\n };\n\n const handleEvent = (event: string, data: string) => {\n if (event === \"state\") {\n const next = JSON.parse(data) as TunnelState;\n setState(next);\n return;\n }\n if (event === \"activity\") {\n if (!verbose) {\n return;\n }\n const activity = JSON.parse(data) as TunnelActivity;\n pushLog(activity.text, activity.level);\n }\n };\n\n const consumeSse = async () => {\n const res = await fetch(`${baseUrl}/__skybridge/tunnel/events`, {\n signal: controller.signal,\n headers: { Accept: \"text/event-stream\" },\n });\n if (!res.ok || !res.body) {\n throw new Error(`SSE connection failed (${res.status})`);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (!cancelled) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n buffer += decoder.decode(value, { stream: true });\n\n // SSE frames are separated by a blank line (\"\\n\\n\").\n let sep = buffer.indexOf(\"\\n\\n\");\n while (sep !== -1) {\n const frame = buffer.slice(0, sep);\n buffer = buffer.slice(sep + 2);\n let eventName = \"message\";\n const dataLines: string[] = [];\n for (const rawLine of frame.split(\"\\n\")) {\n const line = rawLine.replace(/\\r$/, \"\");\n if (line.startsWith(\"event:\")) {\n eventName = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n dataLines.push(line.slice(5).trimStart());\n }\n }\n if (dataLines.length > 0) {\n handleEvent(eventName, dataLines.join(\"\\n\"));\n }\n sep = buffer.indexOf(\"\\n\\n\");\n }\n }\n };\n\n const postUntilStarted = async () => {\n // Retry indefinitely until POST lands once. Bounded by the effect\n // lifetime via controller.abort() on unmount. Once the manager has\n // been started, this returns and never POSTs again — a user-driven\n // DELETE /tunnel won't be auto-undone.\n while (!cancelled) {\n try {\n const res = await fetch(`${baseUrl}/__skybridge/tunnel`, {\n method: \"POST\",\n signal: controller.signal,\n });\n if (res.ok) {\n return;\n }\n } catch {\n // dev server not up yet (or restarting under nodemon) — wait, retry\n }\n await new Promise((r) => setTimeout(r, POST_RETRY_DELAY_MS));\n }\n };\n\n // Always observe the tunnel state so external triggers (curl, future\n // devtools UI) update the cli UI. `autoStart` only decides whether we\n // also POST /tunnel on mount. Reconnects indefinitely so we survive\n // dev-server boot delay and nodemon restarts; the cli owns the actual\n // subprocess so a temporarily-unreachable dev server is fine.\n const observe = async () => {\n while (!cancelled) {\n try {\n await consumeSse();\n } catch {\n // network error or stream ended abnormally — fall through to retry\n }\n if (cancelled) {\n return;\n }\n await new Promise((r) => setTimeout(r, POST_RETRY_DELAY_MS));\n }\n };\n\n // observe() always runs — it owns the cli's view of tunnel state. POST is\n // a fire-and-forget side-effect that nudges the manager into starting and\n // retries until it lands at least once.\n if (autoStart) {\n void postUntilStarted();\n }\n void observe();\n\n return () => {\n cancelled = true;\n controller.abort();\n };\n }, [port, pushMessage, verbose, autoStart]);\n\n return state;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type TsError = {
|
|
2
|
+
file: string;
|
|
3
|
+
line: number;
|
|
4
|
+
col: number;
|
|
5
|
+
code: string;
|
|
6
|
+
message: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Spawn `tsc --noEmit --watch` and report each completed check via `onErrors`
|
|
10
|
+
* (empty array when the check is clean). Returns a cleanup function that kills
|
|
11
|
+
* the watcher. Shared by the Ink-based dev UI (via {@link useTypeScriptCheck})
|
|
12
|
+
* and the `--plain` runner.
|
|
13
|
+
*/
|
|
14
|
+
export declare function startTypeScriptCheck(onErrors: (errors: Array<TsError>) => void): () => void;
|
|
15
|
+
export declare function useTypeScriptCheck(): Array<TsError>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { isAbsolute, relative } from "node:path";
|
|
2
|
+
import spawn from "cross-spawn";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
// TypeScript nests from general to specific — the deepest line is the root cause.
|
|
5
|
+
function extractBestMessage(message, continuationLines) {
|
|
6
|
+
if (!continuationLines.length) {
|
|
7
|
+
return message;
|
|
8
|
+
}
|
|
9
|
+
let maxIndent = 0;
|
|
10
|
+
for (const line of continuationLines) {
|
|
11
|
+
const indent = line.length - line.trimStart().length;
|
|
12
|
+
if (indent > maxIndent) {
|
|
13
|
+
maxIndent = indent;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const deepest = continuationLines
|
|
17
|
+
.filter((l) => l.length - l.trimStart().length === maxIndent)
|
|
18
|
+
.map((l) => l.trim())
|
|
19
|
+
.filter(Boolean)[0];
|
|
20
|
+
return deepest ?? message;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Spawn `tsc --noEmit --watch` and report each completed check via `onErrors`
|
|
24
|
+
* (empty array when the check is clean). Returns a cleanup function that kills
|
|
25
|
+
* the watcher. Shared by the Ink-based dev UI (via {@link useTypeScriptCheck})
|
|
26
|
+
* and the `--plain` runner.
|
|
27
|
+
*/
|
|
28
|
+
export function startTypeScriptCheck(onErrors) {
|
|
29
|
+
const tsProcess = spawn("npx", ["tsc", "--noEmit", "--watch", "--pretty", "false"], {
|
|
30
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
31
|
+
shell: true,
|
|
32
|
+
});
|
|
33
|
+
let outputBuffer = "";
|
|
34
|
+
let currentErrors = [];
|
|
35
|
+
let pendingError = null;
|
|
36
|
+
let continuationLines = [];
|
|
37
|
+
const flushPending = () => {
|
|
38
|
+
if (!pendingError) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
pendingError.message = extractBestMessage(pendingError.message, continuationLines);
|
|
42
|
+
currentErrors.push(pendingError);
|
|
43
|
+
pendingError = null;
|
|
44
|
+
continuationLines = [];
|
|
45
|
+
};
|
|
46
|
+
const processOutput = (data) => {
|
|
47
|
+
outputBuffer += data.toString();
|
|
48
|
+
const lines = outputBuffer.split("\n");
|
|
49
|
+
outputBuffer = lines.pop() || "";
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
const trimmed = line.trim();
|
|
52
|
+
const errorMatch = trimmed.match(/^(.+?)\((\d+),(\d+)\):\s+error\s+(TS\d+)?\s*:?\s*(.+)$/);
|
|
53
|
+
if (errorMatch) {
|
|
54
|
+
flushPending();
|
|
55
|
+
const [, file, lineStr, colStr, code, message] = errorMatch;
|
|
56
|
+
if (file && lineStr && colStr && message) {
|
|
57
|
+
let cleanFile = file.trim();
|
|
58
|
+
if (isAbsolute(cleanFile)) {
|
|
59
|
+
cleanFile = relative(process.cwd(), cleanFile);
|
|
60
|
+
}
|
|
61
|
+
pendingError = {
|
|
62
|
+
file: cleanFile,
|
|
63
|
+
line: Number.parseInt(lineStr, 10),
|
|
64
|
+
col: Number.parseInt(colStr, 10),
|
|
65
|
+
code: code ?? "",
|
|
66
|
+
message: message.trim(),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (pendingError && line.startsWith(" ")) {
|
|
72
|
+
continuationLines.push(line);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (trimmed.includes("Found") && trimmed.includes("error")) {
|
|
76
|
+
flushPending();
|
|
77
|
+
onErrors(trimmed.match(/Found 0 error/) ? [] : [...currentErrors]);
|
|
78
|
+
currentErrors = [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
if (tsProcess.stdout) {
|
|
83
|
+
tsProcess.stdout.on("data", processOutput);
|
|
84
|
+
}
|
|
85
|
+
if (tsProcess.stderr) {
|
|
86
|
+
tsProcess.stderr.on("data", processOutput);
|
|
87
|
+
}
|
|
88
|
+
return () => {
|
|
89
|
+
tsProcess.kill();
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export function useTypeScriptCheck() {
|
|
93
|
+
const [tsErrors, setTsErrors] = useState([]);
|
|
94
|
+
useEffect(() => startTypeScriptCheck(setTsErrors), []);
|
|
95
|
+
return tsErrors;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=use-typescript-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-typescript-check.js","sourceRoot":"","sources":["../../src/cli/use-typescript-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAbsolute, relative } from \"node:path\";\nimport spawn from \"cross-spawn\";\nimport { useEffect, useState } from \"react\";\n\nexport type TsError = {\n file: string;\n line: number;\n col: number;\n code: string;\n message: string;\n};\n\n// TypeScript nests from general to specific — the deepest line is the root cause.\nfunction extractBestMessage(\n message: string,\n continuationLines: Array<string>,\n): string {\n if (!continuationLines.length) {\n return message;\n }\n let maxIndent = 0;\n for (const line of continuationLines) {\n const indent = line.length - line.trimStart().length;\n if (indent > maxIndent) {\n maxIndent = indent;\n }\n }\n const deepest = continuationLines\n .filter((l) => l.length - l.trimStart().length === maxIndent)\n .map((l) => l.trim())\n .filter(Boolean)[0];\n return deepest ?? message;\n}\n\n/**\n * Spawn `tsc --noEmit --watch` and report each completed check via `onErrors`\n * (empty array when the check is clean). Returns a cleanup function that kills\n * the watcher. Shared by the Ink-based dev UI (via {@link useTypeScriptCheck})\n * and the `--plain` runner.\n */\nexport function startTypeScriptCheck(\n onErrors: (errors: Array<TsError>) => void,\n): () => void {\n const tsProcess = spawn(\n \"npx\",\n [\"tsc\", \"--noEmit\", \"--watch\", \"--pretty\", \"false\"],\n {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: true,\n },\n );\n\n let outputBuffer = \"\";\n let currentErrors: Array<TsError> = [];\n let pendingError: TsError | null = null;\n let continuationLines: Array<string> = [];\n\n const flushPending = () => {\n if (!pendingError) {\n return;\n }\n pendingError.message = extractBestMessage(\n pendingError.message,\n continuationLines,\n );\n currentErrors.push(pendingError);\n pendingError = null;\n continuationLines = [];\n };\n\n const processOutput = (data: Buffer) => {\n outputBuffer += data.toString();\n const lines = outputBuffer.split(\"\\n\");\n outputBuffer = lines.pop() || \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n const errorMatch = trimmed.match(\n /^(.+?)\\((\\d+),(\\d+)\\):\\s+error\\s+(TS\\d+)?\\s*:?\\s*(.+)$/,\n );\n if (errorMatch) {\n flushPending();\n const [, file, lineStr, colStr, code, message] = errorMatch;\n if (file && lineStr && colStr && message) {\n let cleanFile = file.trim();\n if (isAbsolute(cleanFile)) {\n cleanFile = relative(process.cwd(), cleanFile);\n }\n pendingError = {\n file: cleanFile,\n line: Number.parseInt(lineStr, 10),\n col: Number.parseInt(colStr, 10),\n code: code ?? \"\",\n message: message.trim(),\n };\n }\n continue;\n }\n\n if (pendingError && line.startsWith(\" \")) {\n continuationLines.push(line);\n continue;\n }\n\n if (trimmed.includes(\"Found\") && trimmed.includes(\"error\")) {\n flushPending();\n onErrors(trimmed.match(/Found 0 error/) ? [] : [...currentErrors]);\n currentErrors = [];\n }\n }\n };\n\n if (tsProcess.stdout) {\n tsProcess.stdout.on(\"data\", processOutput);\n }\n if (tsProcess.stderr) {\n tsProcess.stderr.on(\"data\", processOutput);\n }\n\n return () => {\n tsProcess.kill();\n };\n}\n\nexport function useTypeScriptCheck(): Array<TsError> {\n const [tsErrors, setTsErrors] = useState<Array<TsError>>([]);\n\n useEffect(() => startTypeScriptCheck(setTsErrors), []);\n\n return tsErrors;\n}\n"]}
|