skybridge 0.0.0-dev.f283a28 → 0.0.0-dev.f2911c3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/README.md +123 -124
  2. package/dist/cli/detect-port.js.map +1 -1
  3. package/dist/cli/header.js.map +1 -1
  4. package/dist/cli/run-command.js.map +1 -1
  5. package/dist/cli/telemetry.js.map +1 -1
  6. package/dist/cli/tunnel-control-server.js.map +1 -1
  7. package/dist/cli/tunnel-control-server.test.js.map +1 -1
  8. package/dist/cli/tunnel-handler.js.map +1 -1
  9. package/dist/cli/tunnel-handler.test.js.map +1 -1
  10. package/dist/cli/tunnel.js +2 -2
  11. package/dist/cli/tunnel.js.map +1 -1
  12. package/dist/cli/tunnel.test.js.map +1 -1
  13. package/dist/cli/types.js.map +1 -1
  14. package/dist/cli/use-execute-steps.js.map +1 -1
  15. package/dist/cli/use-messages.js.map +1 -1
  16. package/dist/cli/use-nodemon.js +11 -2
  17. package/dist/cli/use-nodemon.js.map +1 -1
  18. package/dist/cli/use-open-browser.d.ts +1 -0
  19. package/dist/cli/use-open-browser.js +44 -0
  20. package/dist/cli/use-open-browser.js.map +1 -0
  21. package/dist/cli/use-tunnel.js.map +1 -1
  22. package/dist/cli/use-typescript-check.js +1 -1
  23. package/dist/cli/use-typescript-check.js.map +1 -1
  24. package/dist/commands/build.js +36 -1
  25. package/dist/commands/build.js.map +1 -1
  26. package/dist/commands/create.d.ts +9 -0
  27. package/dist/commands/create.js +30 -0
  28. package/dist/commands/create.js.map +1 -0
  29. package/dist/commands/dev.d.ts +1 -0
  30. package/dist/commands/dev.js +7 -0
  31. package/dist/commands/dev.js.map +1 -1
  32. package/dist/commands/start.js.map +1 -1
  33. package/dist/commands/telemetry/disable.js.map +1 -1
  34. package/dist/commands/telemetry/enable.js.map +1 -1
  35. package/dist/commands/telemetry/status.js.map +1 -1
  36. package/dist/server/asset-base-url-transform-plugin.d.ts +1 -0
  37. package/dist/server/asset-base-url-transform-plugin.js +16 -1
  38. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  39. package/dist/server/asset-base-url-transform-plugin.test.js +51 -1
  40. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  41. package/dist/server/auth.d.ts +20 -0
  42. package/dist/server/auth.js +28 -0
  43. package/dist/server/auth.js.map +1 -0
  44. package/dist/server/content-helpers.d.ts +40 -0
  45. package/dist/server/content-helpers.js +33 -0
  46. package/dist/server/content-helpers.js.map +1 -1
  47. package/dist/server/content-helpers.test.js.map +1 -1
  48. package/dist/server/express.d.ts +1 -5
  49. package/dist/server/express.js +13 -7
  50. package/dist/server/express.js.map +1 -1
  51. package/dist/server/express.test.js +153 -71
  52. package/dist/server/express.test.js.map +1 -1
  53. package/dist/server/file-ref.d.ts +28 -0
  54. package/dist/server/file-ref.js +27 -0
  55. package/dist/server/file-ref.js.map +1 -0
  56. package/dist/server/index.d.ts +3 -1
  57. package/dist/server/index.js +2 -0
  58. package/dist/server/index.js.map +1 -1
  59. package/dist/server/inferUtilityTypes.js.map +1 -1
  60. package/dist/server/metric.js.map +1 -1
  61. package/dist/server/middleware.d.ts +16 -3
  62. package/dist/server/middleware.js.map +1 -1
  63. package/dist/server/middleware.test-d.js.map +1 -1
  64. package/dist/server/middleware.test.js.map +1 -1
  65. package/dist/server/server.d.ts +231 -6
  66. package/dist/server/server.js +201 -76
  67. package/dist/server/server.js.map +1 -1
  68. package/dist/server/templateHelper.d.ts +0 -2
  69. package/dist/server/templateHelper.js +3 -22
  70. package/dist/server/templateHelper.js.map +1 -1
  71. package/dist/server/templates.generated.d.ts +4 -0
  72. package/dist/server/templates.generated.js +47 -0
  73. package/dist/server/templates.generated.js.map +1 -0
  74. package/dist/server/tunnel-proxy-router.js.map +1 -1
  75. package/dist/server/tunnel-proxy-router.test.js.map +1 -1
  76. package/dist/server/viewsDevServer.js.map +1 -1
  77. package/dist/test/utils.js.map +1 -1
  78. package/dist/test/view.test.js +45 -0
  79. package/dist/test/view.test.js.map +1 -1
  80. package/dist/version.js +1 -3
  81. package/dist/version.js.map +1 -1
  82. package/dist/web/bridges/apps-sdk/adaptor.d.ts +6 -2
  83. package/dist/web/bridges/apps-sdk/adaptor.js +23 -3
  84. package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -1
  85. package/dist/web/bridges/apps-sdk/bridge.d.ts +1 -0
  86. package/dist/web/bridges/apps-sdk/bridge.js +1 -0
  87. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  88. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  89. package/dist/web/bridges/apps-sdk/types.d.ts +8 -1
  90. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  91. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  92. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  93. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  94. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  95. package/dist/web/bridges/get-adaptor.js +7 -0
  96. package/dist/web/bridges/get-adaptor.js.map +1 -1
  97. package/dist/web/bridges/index.js.map +1 -1
  98. package/dist/web/bridges/mcp-app/adaptor.d.ts +6 -2
  99. package/dist/web/bridges/mcp-app/adaptor.js +18 -6
  100. package/dist/web/bridges/mcp-app/adaptor.js.map +1 -1
  101. package/dist/web/bridges/mcp-app/bridge.d.ts +1 -0
  102. package/dist/web/bridges/mcp-app/bridge.js +1 -0
  103. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  104. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  105. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  106. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +12 -0
  107. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +12 -0
  108. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  109. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  110. package/dist/web/bridges/types.d.ts +65 -3
  111. package/dist/web/bridges/types.js.map +1 -1
  112. package/dist/web/bridges/use-host-context.d.ts +5 -0
  113. package/dist/web/bridges/use-host-context.js +5 -0
  114. package/dist/web/bridges/use-host-context.js.map +1 -1
  115. package/dist/web/components/modal-provider.js.map +1 -1
  116. package/dist/web/create-store.d.ts +26 -0
  117. package/dist/web/create-store.js +26 -0
  118. package/dist/web/create-store.js.map +1 -1
  119. package/dist/web/create-store.test.js.map +1 -1
  120. package/dist/web/data-llm.d.ts +33 -0
  121. package/dist/web/data-llm.js +28 -0
  122. package/dist/web/data-llm.js.map +1 -1
  123. package/dist/web/data-llm.test.js.map +1 -1
  124. package/dist/web/generate-helpers.d.ts +2 -0
  125. package/dist/web/generate-helpers.js +2 -0
  126. package/dist/web/generate-helpers.js.map +1 -1
  127. package/dist/web/generate-helpers.test-d.js.map +1 -1
  128. package/dist/web/generate-helpers.test.js.map +1 -1
  129. package/dist/web/helpers/state.js.map +1 -1
  130. package/dist/web/helpers/state.test.js.map +1 -1
  131. package/dist/web/hooks/index.d.ts +3 -0
  132. package/dist/web/hooks/index.js +3 -0
  133. package/dist/web/hooks/index.js.map +1 -1
  134. package/dist/web/hooks/test/utils.d.ts +6 -2
  135. package/dist/web/hooks/test/utils.js +13 -2
  136. package/dist/web/hooks/test/utils.js.map +1 -1
  137. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  138. package/dist/web/hooks/use-call-tool.js +28 -0
  139. package/dist/web/hooks/use-call-tool.js.map +1 -1
  140. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  141. package/dist/web/hooks/use-call-tool.test.js +27 -6
  142. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  143. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  144. package/dist/web/hooks/use-display-mode.js +20 -0
  145. package/dist/web/hooks/use-display-mode.js.map +1 -1
  146. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -1
  147. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  148. package/dist/web/hooks/use-download.d.ts +5 -0
  149. package/dist/web/hooks/use-download.js +8 -0
  150. package/dist/web/hooks/use-download.js.map +1 -0
  151. package/dist/web/hooks/use-download.test.d.ts +1 -0
  152. package/dist/web/hooks/use-download.test.js +95 -0
  153. package/dist/web/hooks/use-download.test.js.map +1 -0
  154. package/dist/web/hooks/use-files.d.ts +32 -0
  155. package/dist/web/hooks/use-files.js +32 -0
  156. package/dist/web/hooks/use-files.js.map +1 -1
  157. package/dist/web/hooks/use-files.test.js.map +1 -1
  158. package/dist/web/hooks/use-layout.d.ts +2 -0
  159. package/dist/web/hooks/use-layout.js +2 -0
  160. package/dist/web/hooks/use-layout.js.map +1 -1
  161. package/dist/web/hooks/use-layout.test.js.map +1 -1
  162. package/dist/web/hooks/use-open-external.d.ts +17 -0
  163. package/dist/web/hooks/use-open-external.js +16 -0
  164. package/dist/web/hooks/use-open-external.js.map +1 -1
  165. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  166. package/dist/web/hooks/use-request-close.d.ts +16 -0
  167. package/dist/web/hooks/use-request-close.js +21 -0
  168. package/dist/web/hooks/use-request-close.js.map +1 -0
  169. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  170. package/dist/web/hooks/use-request-close.test.js +52 -0
  171. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  172. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  173. package/dist/web/hooks/use-request-modal.js +16 -1
  174. package/dist/web/hooks/use-request-modal.js.map +1 -1
  175. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  176. package/dist/web/hooks/use-request-size.d.ts +20 -0
  177. package/dist/web/hooks/use-request-size.js +24 -0
  178. package/dist/web/hooks/use-request-size.js.map +1 -0
  179. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  180. package/dist/web/hooks/use-request-size.test.js +65 -0
  181. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  182. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  183. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  184. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  185. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  186. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  187. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  188. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  189. package/dist/web/hooks/use-tool-info.d.ts +33 -0
  190. package/dist/web/hooks/use-tool-info.js +26 -0
  191. package/dist/web/hooks/use-tool-info.js.map +1 -1
  192. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  193. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  194. package/dist/web/hooks/use-user.d.ts +2 -0
  195. package/dist/web/hooks/use-user.js +2 -0
  196. package/dist/web/hooks/use-user.js.map +1 -1
  197. package/dist/web/hooks/use-user.test.js.map +1 -1
  198. package/dist/web/hooks/use-view-state.d.ts +21 -0
  199. package/dist/web/hooks/use-view-state.js.map +1 -1
  200. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  201. package/dist/web/index.js.map +1 -1
  202. package/dist/web/mount-view.d.ts +19 -0
  203. package/dist/web/mount-view.js +19 -0
  204. package/dist/web/mount-view.js.map +1 -1
  205. package/dist/web/plugin/data-llm.test.js.map +1 -1
  206. package/dist/web/plugin/plugin.d.ts +28 -0
  207. package/dist/web/plugin/plugin.js +35 -9
  208. package/dist/web/plugin/plugin.js.map +1 -1
  209. package/dist/web/plugin/scan-views.js.map +1 -1
  210. package/dist/web/plugin/scan-views.test.js.map +1 -1
  211. package/dist/web/plugin/transform-data-llm.js.map +1 -1
  212. package/dist/web/plugin/transform-data-llm.test.js.map +1 -1
  213. package/dist/web/plugin/validate-view.js.map +1 -1
  214. package/dist/web/plugin/validate-view.test.js.map +1 -1
  215. package/dist/web/proxy.js.map +1 -1
  216. package/dist/web/types.d.ts +4 -0
  217. package/dist/web/types.js.map +1 -1
  218. package/package.json +24 -17
  219. package/dist/server/templates/development.hbs +0 -12
  220. package/dist/server/templates/production.hbs +0 -6
package/README.md CHANGED
@@ -1,153 +1,152 @@
1
- <div align="center">
2
-
3
- <img alt="Skybridge" src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/github-banner.png" width="100%">
4
-
5
- <br />
6
-
7
- **Build ChatGPT & MCP Apps. The Modern TypeScript Way.**
8
-
9
- The fullstack TypeScript framework for AI-embedded views.<br />
10
- **Type-safe. React-powered. Platform-agnostic.**
11
-
12
- <br />
13
-
14
- [![NPM Version](https://img.shields.io/npm/v/skybridge?color=e90060&style=for-the-badge)](https://www.npmjs.com/package/skybridge)
15
- [![NPM Downloads](https://img.shields.io/npm/dm/skybridge?color=e90060&style=for-the-badge)](https://www.npmjs.com/package/skybridge)
16
- [![GitHub License](https://img.shields.io/github/license/alpic-ai/skybridge?color=e90060&style=for-the-badge)](https://github.com/alpic-ai/skybridge/blob/main/LICENSE)
17
-
18
- <br />
19
-
20
- [Documentation](https://docs.skybridge.tech) · [Quick Start](https://docs.skybridge.tech/quickstart/create-new-app) · [Showcase](https://docs.skybridge.tech/showcase)
21
-
22
- </div>
23
-
24
- <br />
25
-
26
- ## Why Skybridge?
27
-
28
- ChatGPT Apps and MCP Apps let you embed **rich, interactive UIs** directly in AI conversations. But the raw SDKs are low-level—no hooks, no type safety, no dev tools, and no HMR.
29
-
30
- **Skybridge fixes that.**
31
-
32
- | | |
33
- |:--|:--|
34
- | 🌐 **Write once, run everywhere** Skybridge works seamlessly with ChatGPT (Apps SDK) and MCP-compatible clients. | **End-to-End Type Safety** — tRPC-style inference from server to view. Autocomplete everywhere. |
35
- | 🔄 **View-to-Model Sync** — Keep the model aware of UI state with `data-llm`. Dual surfaces, one source of truth. | ⚒️ **React Query-style Hooks** — `isPending`, `isError`, callbacks. State management you already know. |
36
- | 👨‍💻 **Full dev environment** — HMR, debug traces, and local devtools. | 📦 **Showcase Examples** — Production-ready examples to learn from and build upon. |
37
-
38
- <br />
39
-
40
- ## 🚀 Get Started
41
-
42
- **Create a new app:**
43
-
1
+ # Skybridge - the MCP Apps framework
2
+
3
+ <p align="center">
4
+ <a href="https://docs.skybridge.tech">
5
+ <picture>
6
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/skybridge-readme-banner-dark.png" />
7
+ <img alt="Skybridge, the full-stack React framework for MCP apps and MCP servers" src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/skybridge-readme-banner-light.png" width="100%" />
8
+ </picture>
9
+ </a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <strong>The full-stack React framework for MCP Apps and MCP Servers.</strong>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="https://docs.skybridge.tech">Documentation</a> ·
18
+ <a href="https://docs.skybridge.tech/quickstart/create-new-app">Quickstart</a> ·
19
+ <a href="https://github.com/alpic-ai/skybridge/tree/main/examples">Examples</a>
20
+ </p>
21
+
22
+ <p align="center">
23
+ <a href="https://www.npmjs.com/package/skybridge"><picture><source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/v/skybridge?color=77F5EE&amp;labelColor=161B22&amp;style=for-the-badge"><img alt="npm version" src="https://img.shields.io/npm/v/skybridge?color=E3FAF7&amp;labelColor=F6F8FA&amp;style=for-the-badge"></picture></a>
24
+ <a href="https://www.npmjs.com/package/skybridge"><picture><source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/dm/skybridge?color=D7FFC8&amp;labelColor=161B22&amp;style=for-the-badge"><img alt="npm downloads" src="https://img.shields.io/npm/dm/skybridge?color=E8FBD9&amp;labelColor=F6F8FA&amp;style=for-the-badge"></picture></a>
25
+ <a href="https://discord.com/invite/gNAazGueab"><picture><source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/Discord-community-77F5EE?style=for-the-badge&amp;logo=discord&amp;logoColor=77F5EE&amp;labelColor=161B22"><img alt="Discord community" src="https://img.shields.io/badge/Discord-community-E3FAF7?style=for-the-badge&amp;logo=discord&amp;logoColor=5865F2&amp;labelColor=F6F8FA"></picture></a>
26
+ <a href="https://github.com/alpic-ai/skybridge/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/license/alpic-ai/skybridge?color=D7FFC8&amp;labelColor=161B22&amp;style=for-the-badge"><img alt="License: MIT" src="https://img.shields.io/github/license/alpic-ai/skybridge?color=E8FBD9&amp;labelColor=F6F8FA&amp;style=for-the-badge"></picture></a>
27
+ </p>
28
+
29
+ ## About Skybridge
30
+
31
+ Skybridge helps developers build type-safe MCP apps for Claude, ChatGPT and other UI-enabled MCP clients, with a complete set of tooling designed for both humans and agents.
32
+
33
+ Why? MCP apps extend the [Model Context Protocol](https://modelcontextprotocol.io/docs/getting-started/intro) with **rich, interactive UI views** rendered from MCP servers. Conversational apps need seamless interaction between the user, the UI, and the model. This means new UX patterns, developer tooling, and abstractions.
34
+ Plus, the raw SDKs are low-level: no hooks, type safety, HMR, etc.
35
+
36
+ That's why we built *Skybridge*.
37
+
38
+ Features include:
39
+
40
+ - **Delightful dev environment**: Skybridge provides a dev server with a local emulator, hot module reload, and a permanent tunnel to connect your local app to Claude and ChatGPT.
41
+ - **Write once, run everywhere**: the framework abstracts implementation differences between MCP clients, so your app runs seamlessly in Claude, ChatGPT, VSCode, and any other MCP apps compatible client.
42
+ - **Agent-ready**: powerful skills, CLI, and programmatic dev tool APIs, everything your coding agent needs to build MCP apps end-to-end.
43
+ - **Type-safe end-to-end**: tRPC-style inference from MCP server tool definition to React view for type safety from server to frontend.
44
+ - **React-first**: Intuitive React Query-style hooks, with advanced state management.
45
+ - **Example library**: get started quickly with ChatGPT- and Claude-ready app examples for ecommerce, travel, SaaS, and more.
46
+
47
+ They chose to build their MCP apps with Skybridge:
48
+
49
+ <p align="center">
50
+ <a href="https://www.datadoghq.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/datadog-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/datadog-light.svg" alt="Datadog" height="24"></picture></a>
51
+ &nbsp;&nbsp;
52
+ <a href="https://bitmovin.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/bitmovin-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/bitmovin-light.svg" alt="Bitmovin" height="22"></picture></a>
53
+ &nbsp;&nbsp;
54
+ <a href="https://www.evaneos.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/evaneos-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/evaneos-light.svg" alt="Evaneos" height="18"></picture></a>
55
+ &nbsp;&nbsp;
56
+ <a href="https://www.touchstream.media"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/touchstream-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/touchstream-light.svg" alt="Touchstream" height="24"></picture></a>
57
+ &nbsp;&nbsp;
58
+ <a href="https://www.cottages.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/cottages-dark.svg"><img src="https://raw.githubusercontent.com/alpic-ai/skybridge/main/docs/images/user-logos/cottages-light.svg" alt="Cottages.com" height="24"></picture></a>
59
+ </p>
60
+
61
+ ## Get started
62
+
63
+ **For agents**
64
+
65
+ Install our [skill](https://docs.skybridge.tech/devtools/skills) for building MCP apps and ChatGPT apps:
44
66
  ```bash
45
- npm create skybridge@latest
67
+ npx skills add alpic-ai/skybridge -s skybridge
46
68
  ```
69
+ Once installed, ask your agent "What skills do you have?" to confirm, then try:
47
70
 
48
- **Or add to an existing project:**
71
+ - _Create a new MCP app_
72
+ - _Migrate my MCP server to the Skybridge framework_
73
+ - _Add a new view to my MCP app_
49
74
 
75
+ **For humans**
76
+
77
+ Bootstrap a new project with:
50
78
  ```bash
51
- npm i skybridge
52
- yarn add skybridge
53
- pnpm add skybridge
54
- bun add skybridge
55
- deno add skybridge
79
+ npm create skybridge@latest my-app
56
80
  ```
81
+ For full install instructions, read our [**Quickstart guide**](https://docs.skybridge.tech/quickstart/create-new-app).
57
82
 
58
- <div align="center">
59
-
60
- **👉 [Read the Docs](https://docs.skybridge.tech) 👈**
61
-
62
- </div>
83
+ ## Documentation
63
84
 
64
- <br />
85
+ The [Skybridge documentation](https://docs.skybridge.tech) covers the full lifecycle of building MCP Apps:
65
86
 
66
- ## 📦 Architecture
87
+ - [Fundamentals](https://docs.skybridge.tech/fundamentals): understand MCP Apps, ChatGPT Apps, and how Skybridge bridges both runtimes.
88
+ - [Core concepts](https://docs.skybridge.tech/concepts): learn about server <> model <> UI data flows, LLM context sync, type safety, and instant local iteration with our devtools.
89
+ - [Guides](https://docs.skybridge.tech/guides/fetching-data): build real app behavior with tools, views, state, and model communication.
90
+ - [API Reference](https://docs.skybridge.tech/api-reference): browse our MCP server APIs, React hooks, CLI commands, and runtime compatibility.
67
91
 
68
- Skybridge is a fullstack framework with unified server and client modules:
92
+ ## Deploy
69
93
 
70
- - **`skybridge/server`** Define tools and views with full type inference. Extends the MCP SDK.
71
- - **`skybridge/web`** — React hooks that consume your server types. Works with Apps SDK (ChatGPT) and MCP Apps.
72
- - **Dev Environment** — Vite plugin with HMR, DevTools emulator, and optimized builds.
94
+ Deploy Skybridge apps instantly on [Alpic](https://alpic.ai) for scalable hosting, MCP-specific analytics, permanent tunneling, app store compliance auditing and submission help. You can also self-host on any Node.js-compatible platform.
73
95
 
74
- ### Server
96
+ See our [deployment guide](https://docs.skybridge.tech/quickstart/deploy) for the full production path.
75
97
 
76
- ```ts
77
- import { McpServer } from "skybridge/server";
98
+ ## Community & Contributing
78
99
 
79
- server.registerView("flights", {}, {
80
- inputSchema: { destination: z.string() },
81
- }, async ({ destination }) => {
82
- const flights = await searchFlights(destination);
83
- return { structuredContent: { flights } };
84
- });
85
- ```
86
-
87
- ### View
88
-
89
- ```tsx
90
- import { useToolInfo } from "skybridge/web";
91
-
92
- function FlightsView() {
93
- const { output } = useToolInfo();
94
-
95
- return output.structuredContent.flights.map(flight =>
96
- <FlightCard key={flight.id} flight={flight} />
97
- );
98
- }
99
- ```
100
+ We'd love your help improving Skybridge. Here are a few ways to get involved:
100
101
 
101
- <br />
102
+ - **Bugs**: If you run into a bug or unexpected behavior, open a [GitHub Issue](https://github.com/alpic-ai/skybridge/issues) with a clear reproduction.
103
+ - **Questions and ideas**: Need help building with Skybridge or have ideas to improve the framework, docs, examples, or developer experience? [Open an issue](https://github.com/alpic-ai/skybridge/issues) or share them on our [Discord](https://discord.com/invite/gNAazGueab).
104
+ - **Pull requests**: For code or documentation changes, read the [Contributing Guide](https://github.com/alpic-ai/skybridge/blob/main/CONTRIBUTING.md) before opening a PR.
102
105
 
103
- ## 🎯 Features at a Glance
106
+ Skybridge is released under the [MIT License](https://github.com/alpic-ai/skybridge/blob/main/LICENSE).
104
107
 
105
- - **Live Reload** — Vite HMR. See changes instantly without reinstalling.
106
- - **Typed Hooks** — Full autocomplete for tools, inputs, outputs.
107
- - **View → Tool Calls** — Trigger server actions from UI.
108
- - **Dual Surface Sync** — Keep model aware of what users see with `data-llm`.
109
- - **React Query-style API** — `isPending`, `isError`, callbacks.
110
- - **Platform Agnostic** — Works with ChatGPT (Apps SDK) and MCP Apps clients (Goose, VSCode, etc.).
111
- - **MCP Compatible** — Extends the official SDK. Works with any MCP client.
108
+ ### Contributors
112
109
 
113
- <br />
110
+ Built and maintained with ❤️ by [Harijoe](https://github.com/harijoe), [Fred Barthelet](https://github.com/fredericbarthelet), and the [Alpic](https://alpic.ai) team.
114
111
 
115
- ## 📖 Showcase
112
+ <a href="https://github.com/alpic-ai/skybridge/graphs/contributors">
113
+ <img src="https://contrib.rocks/image?repo=alpic-ai/skybridge" alt="Skybridge contributors">
114
+ </a>
116
115
 
117
- Explore production-ready examples:
116
+ ## Example templates
118
117
 
119
- | Example | Description | Demo | Code |
120
- |------------------------|----------------------------------------------------------------------------------|-----------------------------------------------------|-------------------------------------------------------------------------------------|
121
- | **Awaze — Cottage Search** | Holiday cottage search and booking experience — browse properties, filter by location, and explore availability | [Try Demo](https://mcp.cottages.com/try) | — |
122
- | **Capitals Explorer** | Interactive world map with geolocation and Wikipedia integration | [Try Demo](https://capitals.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/capitals) |
123
- | **Ecommerce Carousel** | Product carousel with cart, localization, and modals | [Try Demo](https://ecommerce.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/ecom-carousel) |
124
- | **Everything** | Comprehensive playground showcasing all hooks and features | [Try Demo](https://everything.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/everything) |
125
- | **Investigation Game** | Interactive murder mystery game with multi-screen gameplay and dynamic story progression | [Try Demo](https://investigation-game.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/investigation-game) |
126
- | **Productivity** | Data visualization dashboard demonstrating Skybridge capabilities for MCP Apps | [Try Demo](https://productivity.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/productivity) |
127
- | **Time's Up** | Word-guessing party game where the user gives hints and the AI tries to guess the secret word | [Try Demo](https://times-up.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/times-up) |
128
- | **Lumo — Interactive AI Tutor** | Adaptive educational tutor with Mermaid.js diagrams, mind maps, quizzes, and fill-in-the-blank exercises | [Try Demo](https://lumo-mcp-app-39519fdd.alpic.live/try) | [View Code](https://github.com/connorads/lumo-mcp-app) |
129
- | **Auth — Auth0** | Full OAuth authentication with Auth0 and personalized coffee shop search | — | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-auth0) |
130
- | **Auth — Clerk** | Full OAuth authentication with Clerk and personalized coffee shop search | — | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-clerk) |
131
- | **Auth — Stytch** | Full OAuth authentication with Stytch and personalized coffee shop search | — | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-stytch) |
132
- | **Auth — WorkOS AuthKit** | Full OAuth authentication with WorkOS AuthKit and personalized coffee shop search | — | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-workos) |
133
- | **Flight Booking** | Flight booking carousel with dynamic search and booking flow | [Try Demo](https://flight-booking.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/flight-booking) |
134
- | **Generative UI** | Dynamic UI generation using json-render and Skybridge | [Try Demo](https://generative-ui.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/generative-ui) |
135
- | **Manifest Starter** | Starter app with Manifest UI agentic components out-of-the-box | [Try Demo](https://manifest-ui.skybridge.tech/try) | [View Code](https://github.com/alpic-ai/skybridge/tree/main/examples/manifest-ui) |
118
+ Explore all our example templates in the [Examples](https://docs.skybridge.tech/examples) section of the documentation.
136
119
 
137
- See all examples in the [Showcase](https://docs.skybridge.tech/showcase) or browse the [examples/](examples/) directory.
120
+ ### Basic
138
121
 
139
- <br />
122
+ | Preview | App | Description | Demo | Code |
123
+ | --- | --- | --- | --- | --- |
124
+ | <img src="docs/images/showcase-example.png" alt="Everything" width="160" /> | Everything | Comprehensive playground app showcasing all Skybridge hooks and features. | [Try Demo](https://everything.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/everything) |
140
125
 
141
- <div align="center">
126
+ ### Use cases
142
127
 
143
- [![GitHub Discussions](https://img.shields.io/badge/Discussions-Ask%20Questions-blue?style=flat-square&logo=github)](https://github.com/alpic-ai/skybridge/discussions)
144
- [![GitHub Issues](https://img.shields.io/badge/Issues-Report%20Bugs-red?style=flat-square&logo=github)](https://github.com/alpic-ai/skybridge/issues)
145
- [![Discord](https://img.shields.io/badge/Discord-Chat-5865F2?style=flat-square&logo=discord&logoColor=white)](https://discord.com/invite/gNAazGueab)
128
+ | Preview | App | Description | Demo | Code |
129
+ | --- | --- | --- | --- | --- |
130
+ | <img src="docs/images/showcase-capitals.png" alt="Capitals Explorer" width="160" /> | Capitals Explorer | Interactive world map with geolocation, country information, and dynamic capital exploration. | [Try Demo](https://capitals.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/capitals) |
131
+ | <img src="docs/images/showcase-flight-booking.png" alt="Flight Booking" width="160" /> | Flight Booking | Flight search carousel with route details, pricing comparison, and external booking. | [Try Demo](https://flight-booking.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/flight-booking) |
132
+ | <img src="docs/images/showcase-ecommerce.png" alt="Ecommerce Carousel" width="160" /> | Ecommerce Carousel | Product carousel with persistent cart, localization, theme switching, and modal dialogs. | [Try Demo](https://ecommerce.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/ecom-carousel) |
133
+ | <img src="docs/images/showcase-investigation-game.png" alt="Investigation Game" width="160" /> | Investigation Game | Multi-screen mystery game with fullscreen mode, dynamic story progression and context asynchronicity demonstration | [Try Demo](https://investigation-game.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/investigation-game) |
134
+ | <img src="docs/images/showcase-productivity.png" alt="Productivity" width="160" /> | Productivity | Interactive analytics dashboard with charts, theme adaptation, localization, fullscreen mode, and bidirectional tool calls. | [Try Demo](https://productivity.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/productivity) |
135
+ | <img src="docs/images/showcase-times-up.png" alt="Time's Up" width="160" /> | Time's Up | Word-guessing party game where the user gives hints and the AI tries to guess. | [Try Demo](https://times-up.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/times-up) |
136
+ | <img src="docs/images/showcase-lumo.png" alt="Lumo Interactive AI Tutor" width="160" /> | Lumo — Interactive AI Tutor | Adaptive tutor with Mermaid diagrams, mind maps, quizzes, and fill-in-the-blank exercises. | [Try Demo](https://lumo-mcp-app-39519fdd.alpic.live/try) | [View code](https://github.com/connorads/lumo-mcp-app) |
146
137
 
147
- See [CONTRIBUTING.md](CONTRIBUTING.md) for setup instructions
138
+ ### Auth
148
139
 
149
- <br />
140
+ | Preview | Provider | Description | Code |
141
+ | --- | --- | --- | --- |
142
+ | <img src="docs/images/showcase-clerk.png" alt="Auth Clerk" width="160" /> | Clerk | Full OAuth authentication with Clerk and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-clerk) |
143
+ | <img src="docs/images/showcase-workos.png" alt="Auth WorkOS AuthKit" width="160" /> | WorkOS AuthKit | Full OAuth authentication with WorkOS AuthKit and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-workos) |
144
+ | <img src="docs/images/showcase-stytch.png" alt="Auth Stytch" width="160" /> | Stytch | Full OAuth authentication with Stytch and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-stytch) |
145
+ | <img src="docs/images/showcase-auth0.png" alt="Auth Auth0" width="160" /> | Auth0 | Full OAuth authentication with Auth0 and personalized coffee shop search. | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/auth-auth0) |
150
146
 
151
- **[MIT License](LICENSE)** · Made with ❤️ by **[Alpic](https://alpic.ai)**
147
+ ### UI and component libraries
152
148
 
153
- </div>
149
+ | Preview | App | Description | Demo | Code |
150
+ | --- | --- | --- | --- | --- |
151
+ | <img src="docs/images/showcase-manifest-ui.png" alt="Manifest UI" width="160" /> | Manifest UI | Agentic component library example for rich AI-powered experiences. | [Try Demo](https://manifest-ui.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/manifest-ui) |
152
+ | <img src="docs/images/showcase-generative-ui.png" alt="Generative UI" width="160" /> | Generative UI | LLM-generated dynamic UIs with json-render and 36 pre-built shadcn/ui components. | [Try Demo](https://generative-ui.skybridge.tech/try) | [View code](https://github.com/alpic-ai/skybridge/tree/main/examples/generative-ui) |
@@ -1 +1 @@
1
- {"version":3,"file":"detect-port.js","sourceRoot":"","sources":["../../src/cli/detect-port.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAiB;IACjD,IAAI,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC3C,CAAC;QACD,OAAO;YACL,IAAI,EAAE,MAAM,mBAAmB,CAAC,YAAY,CAAC;YAC7C,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,iBAAiB,MAAM,+BAA+B;SACnE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACrD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,SAAiB,EACjB,IAAa;IAEb,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAElC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;gBACtB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAChB,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CACrD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,IAAa;IAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAElC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"detect-port.js","sourceRoot":"","sources":["../../src/cli/detect-port.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAiB;IACjD,IAAI,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC3C,CAAC;QACD,OAAO;YACL,IAAI,EAAE,MAAM,mBAAmB,CAAC,YAAY,CAAC;YAC7C,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,iBAAiB,MAAM,+BAA+B;SACnE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACrD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,SAAiB,EACjB,IAAa;IAEb,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAElC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;gBACtB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAChB,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CACrD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,IAAa;IAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAElC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import net from \"node:net\";\n\nconst DEFAULT_PORT = 3000;\n\nexport async function resolvePort(flagPort?: number) {\n if (flagPort && flagPort > 1) {\n return { port: flagPort, fallback: false };\n }\n\n const rawEnv = process.env.PORT;\n if (rawEnv) {\n const parsed = Number(rawEnv);\n if (Number.isInteger(parsed) && parsed > 0) {\n return { port: parsed, fallback: false };\n }\n return {\n port: await detectAvailablePort(DEFAULT_PORT),\n fallback: false,\n envWarning: `Invalid PORT=\"${rawEnv}\", ignoring and using default`,\n };\n }\n\n const port = await detectAvailablePort(DEFAULT_PORT);\n return { port, fallback: port !== DEFAULT_PORT };\n}\n\n/**\n * Returns the given port if available, otherwise lets the OS\n * pick a free port via `listen(0)`.\n *\n * @param host - Bind address for the check. Pass `\"localhost\"` for\n * services that bind to 127.0.0.1 (e.g. Vite HMR). Omit for\n * services that bind to all interfaces (e.g. the HTTP server).\n */\nexport async function detectAvailablePort(\n startPort: number,\n host?: string,\n): Promise<number> {\n const available = await isPortAvailable(startPort, host);\n if (available) {\n return startPort;\n }\n\n return new Promise((resolve, reject) => {\n const server = net.createServer();\n\n server.once(\"error\", reject);\n server.once(\"listening\", () => {\n const addr = server.address();\n if (addr && typeof addr === \"object\") {\n const { port } = addr;\n server.close(() => resolve(port));\n } else {\n server.close(() =>\n reject(new Error(\"Failed to detect available port\")),\n );\n }\n });\n\n server.listen(0, host);\n });\n}\n\nfunction isPortAvailable(port: number, host?: string): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", () => resolve(false));\n server.once(\"listening\", () => {\n server.close(() => resolve(true));\n });\n\n server.listen(port, host);\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/cli/header.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,OAAO,EACP,QAAQ,GAIT,EAAE,EAAE;IACH,OAAO,CACL,MAAC,GAAG,IAAC,YAAY,EAAE,CAAC,aAClB,MAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,6BACnB,IAAI,iBACD,EACP,MAAC,IAAI,IAAC,KAAK,EAAC,MAAM,mBAAI,OAAO,IAAQ,EACpC,QAAQ,IACL,CACP,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/cli/header.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,OAAO,EACP,QAAQ,GAIT,EAAE,EAAE;IACH,OAAO,CACL,MAAC,GAAG,IAAC,YAAY,EAAE,CAAC,aAClB,MAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,6BACnB,IAAI,iBACD,EACP,MAAC,IAAI,IAAC,KAAK,EAAC,MAAM,mBAAI,OAAO,IAAQ,EACpC,QAAQ,IACL,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { Box, Text } from \"ink\";\n\nexport const Header = ({\n version,\n children,\n}: {\n version: string;\n children?: React.ReactNode;\n}) => {\n return (\n <Box marginBottom={1}>\n <Text color=\"cyan\" bold>\n ⛰{\" \"}Skybridge\n </Text>\n <Text color=\"cyan\"> v{version}</Text>\n {children}\n </Box>\n );\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"run-command.js","sourceRoot":"","sources":["../../src/cli/run-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE9D,MAAM,UAAU,UAAU,CACxB,OAAe,EACf,UAAwB;IACtB,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;CACxC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE;YAC1B,GAAG,OAAO;YACV,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC/B,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC/B,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC5D,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC5D,MAAM,SAAS,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;qBAC3C,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;qBACjC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,MAAM,YAAY,GAAG,SAAS;oBAC5B,CAAC,CAAC,iCAAiC,IAAI,KAAK,SAAS,EAAE;oBACvD,CAAC,CAAC,iCAAiC,IAAI,EAAE,CAAC;gBAC5C,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;YAClC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACzB,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"run-command.js","sourceRoot":"","sources":["../../src/cli/run-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE9D,MAAM,UAAU,UAAU,CACxB,OAAe,EACf,UAAwB;IACtB,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;CACxC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE;YAC1B,GAAG,OAAO;YACV,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC/B,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC/B,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC5D,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC5D,MAAM,SAAS,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;qBAC3C,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;qBACjC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,MAAM,YAAY,GAAG,SAAS;oBAC5B,CAAC,CAAC,iCAAiC,IAAI,KAAK,SAAS,EAAE;oBACvD,CAAC,CAAC,iCAAiC,IAAI,EAAE,CAAC;gBAC5C,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;YAClC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACzB,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { type SpawnOptions, spawn } from \"node:child_process\";\n\nexport function runCommand(\n command: string,\n options: SpawnOptions = {\n stdio: [\"ignore\", \"inherit\", \"inherit\"],\n },\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n const proc = spawn(command, {\n ...options,\n shell: true,\n });\n\n if (proc.stdout) {\n proc.stdout.on(\"data\", (chunk) => {\n stdoutChunks.push(chunk);\n });\n }\n\n if (proc.stderr) {\n proc.stderr.on(\"data\", (chunk) => {\n stderrChunks.push(chunk);\n });\n }\n\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n const stdoutOutput = Buffer.concat(stdoutChunks).toString();\n const stderrOutput = Buffer.concat(stderrChunks).toString();\n const allOutput = [stdoutOutput, stderrOutput]\n .filter((output) => output.trim())\n .join(\"\\n\");\n const errorMessage = allOutput\n ? `Command failed with exit code ${code}\\n${allOutput}`\n : `Command failed with exit code ${code}`;\n reject(new Error(errorMessage));\n }\n });\n\n proc.on(\"error\", (error) => {\n reject(error);\n });\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/cli/telemetry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/cli/telemetry.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Hook } from \"@oclif/core\";\nimport ci from \"ci-info\";\nimport { PostHog } from \"posthog-node\";\n\nconst POSTHOG_API_KEY = \"phc_rQdkCYr0DO4NcZBQXZnUwsHAbau9zuNwKIpil9FQP6v\";\nconst POSTHOG_HOST = \"https://us.i.posthog.com\";\n\nconst ENV_TELEMETRY_DISABLED = \"SKYBRIDGE_TELEMETRY_DISABLED\";\nconst ENV_TELEMETRY_DEBUG = \"SKYBRIDGE_TELEMETRY_DEBUG\";\nconst ENV_DO_NOT_TRACK = \"DO_NOT_TRACK\";\n\nconst GLOBAL_CONFIG_DIR = join(homedir(), \".skybridge\");\nconst GLOBAL_CONFIG_FILE = join(GLOBAL_CONFIG_DIR, \"config.json\");\n\ninterface GlobalConfig {\n machineId: string;\n telemetry: {\n enabled: boolean;\n };\n}\n\ninterface TelemetryEvent {\n version: string;\n machineId: string;\n sessionId: string;\n isCI: boolean;\n nodeVersion: string;\n platform: NodeJS.Platform;\n outcome: \"success\" | \"failure\";\n error?: string;\n}\n\nlet posthogClient: PostHog | null = null;\n\nfunction getPostHogClient(): PostHog {\n if (!posthogClient) {\n posthogClient = new PostHog(POSTHOG_API_KEY, {\n host: POSTHOG_HOST,\n flushAt: 1,\n flushInterval: 0,\n });\n }\n\n return posthogClient;\n}\n\nfunction readJsonFile<T>(filePath: string): T | null {\n try {\n if (existsSync(filePath)) {\n const content = readFileSync(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n }\n } catch {\n // Ignore errors reading config\n }\n return null;\n}\n\nfunction writeJsonFile(filePath: string, data: unknown): void {\n try {\n const dir = join(filePath, \"..\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(filePath, JSON.stringify(data, null, 2), \"utf-8\");\n } catch {\n // Ignore errors writing config\n }\n}\n\nfunction getGlobalConfig(): GlobalConfig {\n const existing = readJsonFile<GlobalConfig>(GLOBAL_CONFIG_FILE);\n if (existing?.machineId && existing?.telemetry !== undefined) {\n return existing;\n }\n\n const config: GlobalConfig = {\n machineId: existing?.machineId || crypto.randomUUID(),\n telemetry: {\n enabled: existing?.telemetry?.enabled ?? true,\n },\n };\n\n writeJsonFile(GLOBAL_CONFIG_FILE, config);\n return config;\n}\n\nexport function isEnabled(): boolean {\n if (\n process.env[ENV_TELEMETRY_DISABLED] === \"1\" ||\n process.env[ENV_TELEMETRY_DISABLED]?.toLowerCase() === \"true\"\n ) {\n return false;\n }\n\n if (\n process.env[ENV_DO_NOT_TRACK] === \"1\" ||\n process.env[ENV_DO_NOT_TRACK]?.toLowerCase() === \"true\"\n ) {\n return false;\n }\n\n if (ci.isCI) {\n return true;\n }\n\n const config = getGlobalConfig();\n return config.telemetry.enabled;\n}\n\nexport function isDebugMode(): boolean {\n return (\n process.env[ENV_TELEMETRY_DEBUG] === \"1\" ||\n process.env[ENV_TELEMETRY_DEBUG]?.toLowerCase() === \"true\"\n );\n}\n\nexport function setEnabled(enabled: boolean): void {\n const config = getGlobalConfig();\n config.telemetry.enabled = enabled;\n writeJsonFile(GLOBAL_CONFIG_FILE, config);\n}\n\nexport function getMachineId(): string {\n if (ci.isCI) {\n return ci.name ?? \"unknown-ci\";\n }\n\n return getGlobalConfig().machineId;\n}\n\nconst hook: Hook<\"finally\"> = async ({\n id: command,\n config: { version },\n error,\n}) => {\n if (!isEnabled()) {\n return;\n }\n\n const event: TelemetryEvent = {\n version,\n machineId: getMachineId(),\n sessionId: crypto.randomUUID(),\n isCI: ci.isCI,\n nodeVersion: process.version,\n platform: process.platform,\n outcome: error ? \"failure\" : \"success\",\n error: error?.message,\n };\n\n if (isDebugMode()) {\n console.error(\n \"[Telemetry Debug] Would send event:\",\n JSON.stringify(event, null, 2),\n );\n return;\n }\n\n try {\n const client = getPostHogClient();\n client.capture({\n distinctId: event.machineId,\n event: command,\n properties: event,\n });\n } catch {\n // Silently ignore telemetry errors - never block CLI operation\n }\n};\n\nexport default hook;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel-control-server.js","sourceRoot":"","sources":["../../src/cli/tunnel-control-server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAgB,aAAa,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAQ1D,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAqB,EACrB,OAA6B;IAE7B,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC5B,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IACjC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACpD,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,OAAO;QACP,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACpC,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,gEAAgE;YAChE,wEAAwE;YACxE,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC,CAAC;KACL,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"tunnel-control-server.js","sourceRoot":"","sources":["../../src/cli/tunnel-control-server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAgB,aAAa,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAQ1D,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAqB,EACrB,OAA6B;IAE7B,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC5B,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IACjC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACpD,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,OAAO;QACP,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACpC,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,gEAAgE;YAChE,wEAAwE;YACxE,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC,CAAC;KACL,CAAC;AACJ,CAAC","sourcesContent":["import http from \"node:http\";\nimport { type SpawnFn, TunnelManager } from \"./tunnel.js\";\nimport { createTunnelHandler } from \"./tunnel-handler.js\";\n\nexport type TunnelControlServer = {\n port: number;\n manager: TunnelManager;\n close: () => Promise<void>;\n};\n\nexport async function startTunnelControlServer(\n getPort: () => number,\n options?: { spawn?: SpawnFn },\n): Promise<TunnelControlServer> {\n const manager = new TunnelManager({ getPort, spawn: options?.spawn });\n const server = http.createServer(createTunnelHandler(manager));\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(0, \"127.0.0.1\", () => {\n server.off(\"error\", reject);\n resolve();\n });\n });\n const address = server.address();\n if (typeof address === \"string\" || address === null) {\n server.close();\n throw new Error(\"tunnel control server has no address\");\n }\n return {\n port: address.port,\n manager,\n close: () =>\n new Promise<void>((resolve, reject) => {\n manager.stop();\n // Force any in-flight SSE connections to drop so server.close()\n // doesn't hang indefinitely on subscribers that never end on their own.\n server.closeAllConnections();\n server.close((err) => (err ? reject(err) : resolve()));\n }),\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel-control-server.test.js","sourceRoot":"","sources":["../../src/cli/tunnel-control-server.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,IAAI,WAAuD,CAAC;AAC5D,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,WAAW,EAAE,KAAK,EAAE,CAAC;IAC3B,WAAW,GAAG,SAAS,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3D,WAAW,GAAG,OAAO,CAAC;QAEtB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,oBAAoB,OAAO,CAAC,IAAI,4BAA4B,CAC7D,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAEtE,MAAM,MAAM,GAAI,GAAG,CAAC,IAAmC,CAAC,SAAS,EAAE,CAAC;QACpE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC3C,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,CAAC,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC;YACH,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,MAAM,CACV,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,4BAA4B,CAAC,CACpE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"tunnel-control-server.test.js","sourceRoot":"","sources":["../../src/cli/tunnel-control-server.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,IAAI,WAAuD,CAAC;AAC5D,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,WAAW,EAAE,KAAK,EAAE,CAAC;IAC3B,WAAW,GAAG,SAAS,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3D,WAAW,GAAG,OAAO,CAAC;QAEtB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,oBAAoB,OAAO,CAAC,IAAI,4BAA4B,CAC7D,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAEtE,MAAM,MAAM,GAAI,GAAG,CAAC,IAAmC,CAAC,SAAS,EAAE,CAAC;QACpE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC3C,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,CAAC,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC;YACH,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,MAAM,CACV,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,4BAA4B,CAAC,CACpE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { afterEach, describe, expect, it } from \"vitest\";\nimport { startTunnelControlServer } from \"./tunnel-control-server.js\";\n\nlet openControl: { close: () => Promise<void> } | undefined;\nafterEach(async () => {\n await openControl?.close();\n openControl = undefined;\n});\n\ndescribe(\"startTunnelControlServer\", () => {\n it(\"listens on a random loopback port and serves /__skybridge/tunnel/events\", async () => {\n const control = await startTunnelControlServer(() => 3000);\n openControl = control;\n\n expect(control.port).toBeGreaterThan(0);\n\n const res = await fetch(\n `http://127.0.0.1:${control.port}/__skybridge/tunnel/events`,\n );\n expect(res.headers.get(\"content-type\")).toMatch(/text\\/event-stream/);\n\n const reader = (res.body as ReadableStream<Uint8Array>).getReader();\n const { value } = await reader.read();\n const chunk = new TextDecoder().decode(value);\n expect(chunk).toContain(\"event: state\");\n expect(chunk).toContain('\"status\":\"idle\"');\n await reader.cancel();\n });\n\n it(\"two concurrent control servers get different ports\", async () => {\n const a = await startTunnelControlServer(() => 3000);\n const b = await startTunnelControlServer(() => 4000);\n try {\n expect(a.port).not.toBe(b.port);\n } finally {\n await a.close();\n await b.close();\n }\n });\n\n it(\"close() shuts the listener\", async () => {\n const control = await startTunnelControlServer(() => 3000);\n await control.close();\n await expect(\n fetch(`http://127.0.0.1:${control.port}/__skybridge/tunnel/events`),\n ).rejects.toThrow();\n });\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel-handler.js","sourceRoot":"","sources":["../../src/cli/tunnel-handler.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,mBAAmB,CAAC,OAAsB;IACxD,OAAO,CAAC,GAAoB,EAAE,GAAmB,EAAQ,EAAE;QACzD,IAAI,GAAG,CAAC,GAAG,KAAK,qBAAqB,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC/D,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,GAAG,KAAK,qBAAqB,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACjE,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,GAAG,KAAK,4BAA4B,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YACrE,YAAY,CAAC,GAAG,CAAC,CAAC;YAClB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC3C,MAAM,OAAO,GAAG,CAAC,CAAc,EAAE,EAAE;gBACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAC5B,CAAC,CAAC;YACF,MAAM,UAAU,GAAG,CAAC,CAAiB,EAAE,EAAE;gBACvC,QAAQ,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;YAC/B,CAAC,CAAC;YACF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7B,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACnC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBACnB,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAClE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,YAAY,CAAC,GAAmB;IACvC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,cAAc,EAAE,mBAAmB;QACnC,eAAe,EAAE,wBAAwB;QACzC,UAAU,EAAE,YAAY;KACzB,CAAC,CAAC;IACH,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;AACvB,CAAC;AAED,SAAS,QAAQ,CAAC,GAAmB,EAAE,KAAa,EAAE,IAAa;IACjE,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAClE,CAAC"}
1
+ {"version":3,"file":"tunnel-handler.js","sourceRoot":"","sources":["../../src/cli/tunnel-handler.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,mBAAmB,CAAC,OAAsB;IACxD,OAAO,CAAC,GAAoB,EAAE,GAAmB,EAAQ,EAAE;QACzD,IAAI,GAAG,CAAC,GAAG,KAAK,qBAAqB,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC/D,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,GAAG,KAAK,qBAAqB,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACjE,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,GAAG,KAAK,4BAA4B,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YACrE,YAAY,CAAC,GAAG,CAAC,CAAC;YAClB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC3C,MAAM,OAAO,GAAG,CAAC,CAAc,EAAE,EAAE;gBACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAC5B,CAAC,CAAC;YACF,MAAM,UAAU,GAAG,CAAC,CAAiB,EAAE,EAAE;gBACvC,QAAQ,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;YAC/B,CAAC,CAAC;YACF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7B,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACnC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBACnB,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAClE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,YAAY,CAAC,GAAmB;IACvC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,cAAc,EAAE,mBAAmB;QACnC,eAAe,EAAE,wBAAwB;QACzC,UAAU,EAAE,YAAY;KACzB,CAAC,CAAC;IACH,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;AACvB,CAAC;AAED,SAAS,QAAQ,CAAC,GAAmB,EAAE,KAAa,EAAE,IAAa;IACjE,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { TunnelActivity, TunnelManager, TunnelState } from \"./tunnel.js\";\n\nexport function createTunnelHandler(manager: TunnelManager) {\n return (req: IncomingMessage, res: ServerResponse): void => {\n if (req.url === \"/__skybridge/tunnel\" && req.method === \"POST\") {\n manager.start();\n sendJson(res, 200, manager.getState());\n return;\n }\n if (req.url === \"/__skybridge/tunnel\" && req.method === \"DELETE\") {\n manager.stop();\n sendJson(res, 200, manager.getState());\n return;\n }\n if (req.url === \"/__skybridge/tunnel/events\" && req.method === \"GET\") {\n writeSseHead(res);\n writeSse(res, \"state\", manager.getState());\n const onState = (s: TunnelState) => {\n writeSse(res, \"state\", s);\n };\n const onActivity = (a: TunnelActivity) => {\n writeSse(res, \"activity\", a);\n };\n manager.on(\"state\", onState);\n manager.on(\"activity\", onActivity);\n req.on(\"close\", () => {\n manager.off(\"state\", onState);\n manager.off(\"activity\", onActivity);\n });\n return;\n }\n res.writeHead(404).end();\n };\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(data));\n}\n\nfunction writeSseHead(res: ServerResponse): void {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n });\n res.flushHeaders?.();\n}\n\nfunction writeSse(res: ServerResponse, event: string, data: unknown): void {\n res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel-handler.test.js","sourceRoot":"","sources":["../../src/cli/tunnel-handler.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tunnel-handler.test.js","sourceRoot":"","sources":["../../src/cli/tunnel-handler.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"node:events\";\nimport http from \"node:http\";\nimport { Readable } from \"node:stream\";\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { TunnelManager } from \"./tunnel.js\";\nimport { createTunnelHandler } from \"./tunnel-handler.js\";\n\nlet openServer: http.Server | undefined;\nafterEach(() => openServer?.close());\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\nasync function listen(handler: http.RequestListener) {\n const server = http.createServer(handler);\n await new Promise<void>((resolve) => server.listen(0, resolve));\n const port = (server.address() as { port: number }).port;\n return { port, server };\n}\n\nasync function listenWithHandler() {\n const child = makeFakeChild();\n const manager = new TunnelManager({\n getPort: () => 3000,\n spawn: () => child,\n });\n const { port, server } = await listen(createTunnelHandler(manager));\n openServer = server;\n return { port, child, manager };\n}\n\ndescribe(\"createTunnelHandler\", () => {\n it(\"POST /__skybridge/tunnel starts the tunnel and returns the current state\", async () => {\n const { port, child } = await listenWithHandler();\n\n const res = await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"POST\",\n });\n expect(res.status).toBe(200);\n expect(await res.json()).toEqual({\n status: \"starting\",\n message: \"Starting tunnel…\",\n });\n expect(child.kill).not.toHaveBeenCalled();\n });\n\n it(\"POST /__skybridge/tunnel is idempotent — second call does not respawn\", async () => {\n const { port, manager } = await listenWithHandler();\n const startSpy = vi.spyOn(manager, \"start\");\n\n await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"POST\",\n });\n await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"POST\",\n });\n\n expect(startSpy).toHaveBeenCalledTimes(2);\n // Manager.start() is internally idempotent (verified in tunnel.test.ts).\n });\n\n it(\"DELETE /__skybridge/tunnel stops the tunnel\", async () => {\n const { port, child } = await listenWithHandler();\n await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"POST\",\n });\n\n const res = await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"DELETE\",\n });\n expect(res.status).toBe(200);\n expect(await res.json()).toEqual({ status: \"idle\" });\n expect(child.kill).toHaveBeenCalled();\n });\n\n it(\"GET /__skybridge/tunnel/events streams the current state on connect\", async () => {\n const { port, child } = await listenWithHandler();\n await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"POST\",\n });\n child.stdout.emit(\n \"data\",\n Buffer.from(\n \"Forwarding: https://abc.tunnel.example -> http://localhost:3000\\n\",\n ),\n );\n\n const res = await fetch(\n `http://localhost:${port}/__skybridge/tunnel/events`,\n );\n expect(res.headers.get(\"content-type\")).toMatch(/text\\/event-stream/);\n expect(res.body).toBeTruthy();\n\n const reader = (res.body as ReadableStream<Uint8Array>).getReader();\n const { value } = await reader.read();\n const chunk = new TextDecoder().decode(value);\n\n expect(chunk).toContain(\"event: state\");\n expect(chunk).toContain('\"status\":\"connected\"');\n expect(chunk).toContain('\"url\":\"https://abc.tunnel.example\"');\n\n await reader.cancel();\n });\n\n it(\"GET /__skybridge/tunnel/events sends the current error state on connect\", async () => {\n const { port, child } = await listenWithHandler();\n await fetch(`http://localhost:${port}/__skybridge/tunnel`, {\n method: \"POST\",\n });\n child.stderr.emit(\"data\", Buffer.from(\"boom: tunnel auth failed\\n\"));\n child.emit(\"close\", 1);\n\n const res = await fetch(\n `http://localhost:${port}/__skybridge/tunnel/events`,\n );\n expect(res.headers.get(\"content-type\")).toMatch(/text\\/event-stream/);\n expect(res.body).toBeTruthy();\n\n const reader = (res.body as ReadableStream<Uint8Array>).getReader();\n const { value } = await reader.read();\n const chunk = new TextDecoder().decode(value);\n\n expect(chunk).toContain(\"event: state\");\n expect(chunk).toContain('\"status\":\"error\"');\n expect(chunk).toContain(\"boom: tunnel auth failed\");\n\n await reader.cancel();\n });\n});\n"]}
@@ -1,5 +1,5 @@
1
- import { spawn as nodeSpawn } from "node:child_process";
2
1
  import { EventEmitter } from "node:events";
2
+ import spawn from "cross-spawn";
3
3
  const FORWARDING_RE = /Forwarding:\s+(https?:\/\/\S+)\s*->\s*(\S+)/;
4
4
  export function parseStdoutLine(line) {
5
5
  const trimmed = line.trim();
@@ -14,7 +14,7 @@ export function parseStdoutLine(line) {
14
14
  }
15
15
  const CONNECT_TIMEOUT_MS = 60_000;
16
16
  const STDERR_BUFFER_BYTES = 1024;
17
- const defaultSpawn = (port) => nodeSpawn("npx", ["--yes", "alpic", "tunnel", "--port", String(port), "--plain"], {
17
+ const defaultSpawn = (port) => spawn("npx", ["--yes", "alpic", "tunnel", "--port", String(port), "--plain"], {
18
18
  stdio: ["ignore", "pipe", "pipe"],
19
19
  });
20
20
  export class TunnelManager extends EventEmitter {
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../../src/cli/tunnel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../../src/cli/tunnel.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"node:events\";\nimport type { Readable } from \"node:stream\";\nimport spawn from \"cross-spawn\";\n\nexport type TunnelState =\n | { status: \"idle\" }\n | { status: \"starting\"; message: string }\n | { status: \"connected\"; url: string }\n | { status: \"error\"; message: string };\n\nexport type ParsedStdoutEvent =\n | { kind: \"connected\"; url: string }\n | { kind: \"starting\"; message: string };\n\nconst FORWARDING_RE = /Forwarding:\\s+(https?:\\/\\/\\S+)\\s*->\\s*(\\S+)/;\n\nexport function parseStdoutLine(line: string): ParsedStdoutEvent | null {\n const trimmed = line.trim();\n if (!trimmed) {\n return null;\n }\n\n const match = trimmed.match(FORWARDING_RE);\n if (match?.[1]) {\n return { kind: \"connected\", url: match[1].replace(/\\/$/, \"\") };\n }\n return { kind: \"starting\", message: trimmed };\n}\n\nconst CONNECT_TIMEOUT_MS = 60_000;\nconst STDERR_BUFFER_BYTES = 1024;\n\nexport type TunnelActivity = {\n time: string;\n text: string;\n level: \"log\" | \"error\";\n};\n\nexport type TunnelChildProcess = {\n stdout: Pick<Readable, \"on\"> | null;\n stderr: Pick<Readable, \"on\"> | null;\n kill: (signal?: NodeJS.Signals | number) => boolean;\n on(event: \"error\", listener: (err: Error) => void): unknown;\n on(event: \"close\", listener: (code: number | null) => void): unknown;\n};\n\nexport type SpawnFn = (port: number) => TunnelChildProcess;\n\nconst defaultSpawn: SpawnFn = (port) =>\n spawn(\n \"npx\",\n [\"--yes\", \"alpic\", \"tunnel\", \"--port\", String(port), \"--plain\"],\n {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n },\n );\n\nexport class TunnelManager extends EventEmitter {\n private state: TunnelState = { status: \"idle\" };\n private child: ReturnType<SpawnFn> | null = null;\n private timeout: NodeJS.Timeout | null = null;\n private stderrBuffer = \"\";\n private connected = false;\n private readonly getPort: () => number;\n private readonly spawnFn: SpawnFn;\n\n constructor(opts: { getPort: () => number; spawn?: SpawnFn }) {\n super();\n this.getPort = opts.getPort;\n this.spawnFn = opts.spawn ?? defaultSpawn;\n // Multiple SSE subscribers (CLI, devtools, ad-hoc curl) can each register\n // state + activity listeners; the default cap of 10 is easy to hit.\n this.setMaxListeners(0);\n }\n\n getState(): TunnelState {\n return this.state;\n }\n\n subscribe(listener: (state: TunnelState) => void): () => void {\n listener(this.state);\n this.on(\"state\", listener);\n return () => {\n this.off(\"state\", listener);\n };\n }\n\n start(): void {\n if (this.state.status === \"starting\" || this.state.status === \"connected\") {\n return;\n }\n\n this.connected = false;\n this.stderrBuffer = \"\";\n this.setState({ status: \"starting\", message: \"Starting tunnel…\" });\n\n const child = this.spawnFn(this.getPort());\n this.child = child;\n\n this.timeout = setTimeout(() => {\n if (!this.connected) {\n this.setState({\n status: \"error\",\n message: \"Tunnel connection timed out after one minute\",\n });\n // Detach before killing so the imminent `close` event is treated as\n // stale and does not overwrite the timeout error message.\n this.child = null;\n child.kill();\n }\n }, CONNECT_TIMEOUT_MS);\n\n child.stdout?.on(\"data\", (data: Buffer) => {\n this.handleStdout(data);\n });\n child.stderr?.on(\"data\", (data: Buffer) => {\n this.handleStderr(data);\n });\n\n child.on(\"error\", (err: Error) => {\n // Stale event from a child we've already replaced via stop()+start().\n if (child !== this.child) {\n return;\n }\n this.clearConnectTimeout();\n this.setState({ status: \"error\", message: err.message });\n });\n\n child.on(\"close\", (code: number | null) => {\n // Stale event from a child we've already replaced via stop()+start().\n if (child !== this.child) {\n return;\n }\n this.clearConnectTimeout();\n if (code !== 0 && code !== null) {\n const detail = this.stderrBuffer.trim() || `exited with code ${code}`;\n this.setState({ status: \"error\", message: detail });\n } else {\n this.setState({ status: \"idle\" });\n }\n this.child = null;\n });\n }\n\n stop(): void {\n this.clearConnectTimeout();\n if (this.child) {\n this.child.kill();\n this.child = null;\n }\n this.setState({ status: \"idle\" });\n }\n\n private handleStdout(data: Buffer): void {\n const lines = data.toString().split(\"\\n\");\n for (const raw of lines) {\n const parsed = parseStdoutLine(raw);\n if (!parsed) {\n continue;\n }\n if (parsed.kind === \"connected\") {\n this.connected = true;\n this.clearConnectTimeout();\n this.setState({ status: \"connected\", url: parsed.url });\n } else if (this.connected) {\n this.emitActivity(parsed.message, \"log\");\n } else {\n this.setState({ status: \"starting\", message: parsed.message });\n }\n }\n }\n\n private handleStderr(data: Buffer): void {\n const text = data.toString().trim();\n if (!text) {\n return;\n }\n this.stderrBuffer = (this.stderrBuffer + text).slice(-STDERR_BUFFER_BYTES);\n for (const line of text.split(\"\\n\").filter(Boolean)) {\n this.emitActivity(line, \"error\");\n }\n }\n\n private setState(next: TunnelState): void {\n this.state = next;\n this.emit(\"state\", next);\n }\n\n private emitActivity(text: string, level: \"log\" | \"error\"): void {\n const activity: TunnelActivity = {\n time: new Date().toISOString(),\n text,\n level,\n };\n this.emit(\"activity\", activity);\n }\n\n private clearConnectTimeout(): void {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel.test.js","sourceRoot":"","sources":["../../src/cli/tunnel.test.ts"],"names":[],"mappings":"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"}
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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":""}
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"]}
@@ -1 +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"}
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"]}