@dfosco/storyboard 0.5.0-alpha.9 → 0.5.0-beta.32

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 (166) hide show
  1. package/bin/storyboard-runtime.js +7 -0
  2. package/commandpalette.config.json +5 -4
  3. package/dist/runtime/api-Bbh7Mcv9.d.ts +305 -0
  4. package/dist/runtime/client/index.d.ts +32 -0
  5. package/dist/runtime/client/index.js +281 -0
  6. package/dist/runtime/client/index.js.map +1 -0
  7. package/dist/runtime/index.d.ts +18 -0
  8. package/dist/runtime/index.js +1260 -0
  9. package/dist/runtime/index.js.map +1 -0
  10. package/dist/runtime/schema/index.d.ts +202 -0
  11. package/dist/runtime/schema/index.js +165 -0
  12. package/dist/runtime/schema/index.js.map +1 -0
  13. package/dist/runtime/server/main.d.ts +13 -0
  14. package/dist/runtime/server/main.js +1076 -0
  15. package/dist/runtime/server/main.js.map +1 -0
  16. package/dist/runtime/vite-plugin/index.d.ts +51 -0
  17. package/dist/runtime/vite-plugin/index.js +112 -0
  18. package/dist/runtime/vite-plugin/index.js.map +1 -0
  19. package/dist/runtime/vite-plugin/wrapper.d.ts +17 -0
  20. package/dist/runtime/vite-plugin/wrapper.js +147 -0
  21. package/dist/runtime/vite-plugin/wrapper.js.map +1 -0
  22. package/dist/storyboard-ui.css +1 -1
  23. package/dist/storyboard-ui.js +5062 -5145
  24. package/dist/storyboard-ui.js.map +1 -1
  25. package/dist/tailwind.css +1 -1
  26. package/package.json +38 -9
  27. package/scaffold/gitignore +2 -0
  28. package/src/core/artifact/index.js +15 -0
  29. package/src/core/artifact/operations.js +528 -0
  30. package/src/core/artifact/routes.js +140 -0
  31. package/src/core/artifact/schemas/canvas.schema.json +35 -0
  32. package/src/core/artifact/schemas/component.schema.json +17 -0
  33. package/src/core/artifact/schemas/flow.schema.json +49 -0
  34. package/src/core/artifact/schemas/object.schema.json +26 -0
  35. package/src/core/artifact/schemas/page.schema.json +24 -0
  36. package/src/core/artifact/schemas/prototype.schema.json +60 -0
  37. package/src/core/artifact/schemas/record.schema.json +34 -0
  38. package/src/core/artifact/validate.js +269 -0
  39. package/src/core/canvas/collision.js +150 -0
  40. package/src/core/canvas/materializer.js +25 -0
  41. package/src/core/canvas/materializer.test.js +53 -0
  42. package/src/core/canvas/server.js +202 -31
  43. package/src/core/canvas/terminal-config.js +51 -1
  44. package/src/core/canvas/terminal-server.js +59 -7
  45. package/src/core/cli/agent.js +77 -14
  46. package/src/core/cli/artifact.js +310 -0
  47. package/src/core/cli/branch.js +2 -2
  48. package/src/core/cli/canvasAdd.js +1 -1
  49. package/src/core/cli/canvasBroadcast.js +1 -1
  50. package/src/core/cli/canvasConnector.js +47 -9
  51. package/src/core/cli/create.js +6 -6
  52. package/src/core/cli/dev.js +130 -310
  53. package/src/core/cli/dev.legacy.js +453 -0
  54. package/src/core/cli/index.js +17 -0
  55. package/src/core/cli/proxy.js +184 -279
  56. package/src/core/cli/proxy.legacy.js +319 -0
  57. package/src/core/cli/publish.js +4 -2
  58. package/src/core/cli/pull.js +2 -1
  59. package/src/core/cli/run.js +60 -0
  60. package/src/core/cli/setup.js +101 -44
  61. package/src/core/inspector/highlighter.js +2 -1
  62. package/src/core/messaging/delivery.js +1 -1
  63. package/src/core/messaging/routes.js +14 -3
  64. package/src/core/server/index.js +30 -5
  65. package/src/core/session/localStorage.js +81 -2
  66. package/src/core/session/localStorage.migration.test.js +24 -0
  67. package/src/core/session/localStorage.test.js +24 -9
  68. package/src/core/stores/configSchema.js +4 -0
  69. package/src/core/tools/handlers/agentsReady.js +10 -0
  70. package/src/core/tools/handlers/prototypeFullscreen.js +16 -0
  71. package/src/core/tools/registry.js +1 -0
  72. package/src/core/tools/surfaces/collabBar.js +10 -0
  73. package/src/core/tools/surfaces/registry.js +2 -1
  74. package/src/core/ui/AgentsReadyTrigger.jsx +78 -0
  75. package/src/core/ui/CanvasConnectorStyle.css +27 -0
  76. package/src/core/ui/CanvasConnectorStyle.jsx +53 -0
  77. package/src/core/ui/CanvasCreateMenu.jsx +37 -271
  78. package/src/core/ui/CoreUIBar.css +95 -0
  79. package/src/core/ui/CoreUIBar.jsx +49 -2
  80. package/src/core/vite/server-plugin.js +21 -3
  81. package/src/core/workshop/features/createPrototype/CreatePrototypeForm.jsx +1 -1
  82. package/src/internals/ArtifactForm/ArtifactForm.jsx +262 -0
  83. package/src/internals/ArtifactForm/ArtifactForm.module.css +110 -0
  84. package/src/internals/ArtifactForm/artifactSchemas.js +172 -0
  85. package/src/internals/BranchBar/BranchBar.module.css +4 -1
  86. package/src/internals/CommandPalette/CommandPalette.jsx +106 -6
  87. package/src/internals/CommandPalette/CreateDialog.jsx +79 -195
  88. package/src/internals/CommandPalette/WidgetArtifactDialog.css +132 -0
  89. package/src/internals/CommandPalette/WidgetArtifactDialog.jsx +246 -0
  90. package/src/internals/CommandPalette/command-palette.css +7 -7
  91. package/src/internals/Icon.jsx +15 -0
  92. package/src/internals/PrototypeErrorBoundary.jsx +102 -0
  93. package/src/internals/PrototypeErrorBoundary.module.css +92 -0
  94. package/src/internals/Viewfinder.jsx +63 -50
  95. package/src/internals/canvas/CanvasControls.module.css +5 -0
  96. package/src/internals/canvas/CanvasPage.jsx +279 -2
  97. package/src/internals/canvas/CanvasPage.module.css +9 -0
  98. package/src/internals/canvas/CanvasPage.multiselect.test.jsx +8 -9
  99. package/src/internals/canvas/CanvasToolbar.module.css +5 -0
  100. package/src/internals/canvas/StoryErrorBoundary.jsx +47 -0
  101. package/src/internals/canvas/canvasApi.js +8 -0
  102. package/src/internals/canvas/componentIsolate.jsx +2 -22
  103. package/src/internals/canvas/componentSetIsolate.jsx +49 -28
  104. package/src/internals/canvas/connectorGeometry.js +146 -12
  105. package/src/internals/canvas/connectorRouting.js +294 -0
  106. package/src/internals/canvas/connectorRouting.test.js +134 -0
  107. package/src/internals/canvas/useCanvas.js +3 -1
  108. package/src/internals/canvas/widgets/CodePenEmbed.jsx +5 -2
  109. package/src/internals/canvas/widgets/ExpandedPane.jsx +94 -3
  110. package/src/internals/canvas/widgets/ExpandedPane.module.css +42 -0
  111. package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +8 -1
  112. package/src/internals/canvas/widgets/ExpandedPaneTopBar.module.css +6 -0
  113. package/src/internals/canvas/widgets/FigmaEmbed.jsx +2 -1
  114. package/src/internals/canvas/widgets/ImageWidget.jsx +2 -1
  115. package/src/internals/canvas/widgets/InlineStoryRenderer.jsx +129 -0
  116. package/src/internals/canvas/widgets/InlineStoryRenderer.test.jsx +68 -0
  117. package/src/internals/canvas/widgets/LinkPreview.jsx +2 -1
  118. package/src/internals/canvas/widgets/MarkdownBlock.jsx +12 -9
  119. package/src/internals/canvas/widgets/MarkdownBlock.module.css +15 -3
  120. package/src/internals/canvas/widgets/PromptWidget.jsx +11 -1
  121. package/src/internals/canvas/widgets/PrototypeEmbed.jsx +83 -10
  122. package/src/internals/canvas/widgets/ResizeHandle.jsx +10 -2
  123. package/src/internals/canvas/widgets/StorySetWidget.jsx +68 -13
  124. package/src/internals/canvas/widgets/StoryWidget.jsx +41 -10
  125. package/src/internals/canvas/widgets/TerminalWidget.jsx +34 -3
  126. package/src/internals/canvas/widgets/TerminalWidget.module.css +1 -0
  127. package/src/internals/canvas/widgets/WidgetChrome.jsx +57 -17
  128. package/src/internals/canvas/widgets/WidgetChrome.module.css +27 -23
  129. package/src/internals/canvas/widgets/expandUtils.js +52 -4
  130. package/src/internals/canvas/widgets/useExpandOverride.js +24 -0
  131. package/src/internals/canvas/widgets/widgetProps.js +8 -1
  132. package/src/internals/context.jsx +50 -7
  133. package/src/internals/hashPreserver.foreign-branch.test.js +65 -0
  134. package/src/internals/hashPreserver.js +15 -0
  135. package/src/internals/hooks/useHideMode.test.js +2 -1
  136. package/src/internals/hooks/useLocalStorage.test.js +6 -5
  137. package/src/internals/index.js +3 -0
  138. package/src/internals/story/ComponentSetPage.module.css +39 -17
  139. package/src/internals/vite/data-plugin.js +37 -11
  140. package/src/primer/ThemeSync.jsx +73 -0
  141. package/src/primer/index.js +1 -0
  142. package/src/runtime/client/index.ts +229 -0
  143. package/src/runtime/devserver/index.ts +9 -0
  144. package/src/runtime/devserver/orchestrator.ts +365 -0
  145. package/src/runtime/devserver/port-pool.ts +59 -0
  146. package/src/runtime/index.ts +4 -0
  147. package/src/runtime/pool/hot-pool.ts +103 -0
  148. package/src/runtime/pool/index.ts +2 -0
  149. package/src/runtime/proxy/caddy.ts +154 -0
  150. package/src/runtime/proxy/controller.ts +137 -0
  151. package/src/runtime/proxy/index.ts +3 -0
  152. package/src/runtime/schema/api.ts +100 -0
  153. package/src/runtime/schema/devserver.ts +101 -0
  154. package/src/runtime/schema/identity.ts +68 -0
  155. package/src/runtime/schema/index.ts +3 -0
  156. package/src/runtime/server/constants.ts +54 -0
  157. package/src/runtime/server/http.ts +299 -0
  158. package/src/runtime/server/lock.ts +93 -0
  159. package/src/runtime/server/main.ts +57 -0
  160. package/src/runtime/vite-plugin/index.ts +2 -0
  161. package/src/runtime/vite-plugin/plugin.ts +181 -0
  162. package/src/runtime/vite-plugin/wrapper.ts +54 -0
  163. package/toolbar.config.json +24 -0
  164. package/widgets.config.json +44 -10
  165. package/src/internals/canvas/widgets/embedInteraction.test.jsx +0 -173
  166. package/src/internals/canvas/widgets/snapshotDisplay.test.jsx +0 -211
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { startDaemon } from '../dist/runtime/server/main.js'
3
+
4
+ startDaemon().catch((err) => {
5
+ console.error('[storyboard-runtime] fatal:', err)
6
+ process.exit(1)
7
+ })
@@ -58,14 +58,14 @@
58
58
  "label": "Devtools",
59
59
  "meta": { "strokeWeight": 1.6, "scale": 1.1 }
60
60
  },
61
+ {
62
+ "id": "see-deployed-branch",
63
+ "label": "See deployed branch"
64
+ },
61
65
  {
62
66
  "id": "feature-flags",
63
67
  "label": "Feature Flags",
64
68
  "meta": { "strokeWeight": 1.6, "scale": 1.1 }
65
- },
66
- {
67
- "id": "autosync",
68
- "label": "Auto Sync"
69
69
  }
70
70
  ]
71
71
  },
@@ -144,6 +144,7 @@
144
144
  "repository": "primer/mark-github",
145
145
  "docs": "primer/book",
146
146
  "devtools": "iconoir/wrench",
147
+ "see-deployed-branch": "primer/globe",
147
148
  "feature-flags": "iconoir/white-flag",
148
149
  "agent": "agents",
149
150
  "prompt": "primer/zap",
@@ -0,0 +1,305 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * `POST /devserver/acquire` — request a devserver for a `(devDomain, worktree)` slot.
5
+ *
6
+ * If a devserver already exists for the slot, the runtime returns its existing
7
+ * lease (renewed). Otherwise it either rents a hot-pool member or spawns a new
8
+ * Vite process. The slot is locked for the duration of the call.
9
+ */
10
+ declare const AcquireRequest: z.ZodObject<{
11
+ slot: z.ZodObject<{
12
+ devDomain: z.ZodBranded<z.ZodString, "DevDomain">;
13
+ worktree: z.ZodBranded<z.ZodString, "WorktreeName">;
14
+ }, "strip", z.ZodTypeAny, {
15
+ devDomain?: string & z.BRAND<"DevDomain">;
16
+ worktree?: string & z.BRAND<"WorktreeName">;
17
+ }, {
18
+ devDomain?: string;
19
+ worktree?: string;
20
+ }>;
21
+ /** Absolute path of the worktree directory; the runtime spawns Vite with `cwd: targetCwd`. */
22
+ targetCwd: z.ZodString;
23
+ /** Lease TTL in seconds. Defaults to 5 min; CLI clients renew on each command. */
24
+ ttlSeconds: z.ZodDefault<z.ZodNumber>;
25
+ /**
26
+ * Escape hatch for the deprecated default devDomain `"storyboard"`. CI and
27
+ * one-off scripts may pass true; the CLI never does.
28
+ */
29
+ allowDefaultDomain: z.ZodDefault<z.ZodBoolean>;
30
+ }, "strip", z.ZodTypeAny, {
31
+ slot?: {
32
+ devDomain?: string & z.BRAND<"DevDomain">;
33
+ worktree?: string & z.BRAND<"WorktreeName">;
34
+ };
35
+ targetCwd?: string;
36
+ ttlSeconds?: number;
37
+ allowDefaultDomain?: boolean;
38
+ }, {
39
+ slot?: {
40
+ devDomain?: string;
41
+ worktree?: string;
42
+ };
43
+ targetCwd?: string;
44
+ ttlSeconds?: number;
45
+ allowDefaultDomain?: boolean;
46
+ }>;
47
+ type AcquireRequest = z.infer<typeof AcquireRequest>;
48
+ declare const AcquireResponse: z.ZodObject<{
49
+ lease: z.ZodObject<{
50
+ id: z.ZodString;
51
+ devServerId: z.ZodString;
52
+ slot: z.ZodObject<{
53
+ devDomain: z.ZodBranded<z.ZodString, "DevDomain">;
54
+ worktree: z.ZodBranded<z.ZodString, "WorktreeName">;
55
+ }, "strip", z.ZodTypeAny, {
56
+ devDomain?: string & z.BRAND<"DevDomain">;
57
+ worktree?: string & z.BRAND<"WorktreeName">;
58
+ }, {
59
+ devDomain?: string;
60
+ worktree?: string;
61
+ }>;
62
+ url: z.ZodString;
63
+ expiresAt: z.ZodString;
64
+ }, "strip", z.ZodTypeAny, {
65
+ id?: string;
66
+ slot?: {
67
+ devDomain?: string & z.BRAND<"DevDomain">;
68
+ worktree?: string & z.BRAND<"WorktreeName">;
69
+ };
70
+ devServerId?: string;
71
+ url?: string;
72
+ expiresAt?: string;
73
+ }, {
74
+ id?: string;
75
+ slot?: {
76
+ devDomain?: string;
77
+ worktree?: string;
78
+ };
79
+ devServerId?: string;
80
+ url?: string;
81
+ expiresAt?: string;
82
+ }>;
83
+ devServer: z.ZodObject<{
84
+ id: z.ZodString;
85
+ pid: z.ZodNumber;
86
+ port: z.ZodBranded<z.ZodNumber, "Port">;
87
+ status: z.ZodEnum<["idle", "spawning", "ready", "draining", "stopped"]>;
88
+ slot: z.ZodNullable<z.ZodObject<{
89
+ devDomain: z.ZodBranded<z.ZodString, "DevDomain">;
90
+ worktree: z.ZodBranded<z.ZodString, "WorktreeName">;
91
+ }, "strip", z.ZodTypeAny, {
92
+ devDomain?: string & z.BRAND<"DevDomain">;
93
+ worktree?: string & z.BRAND<"WorktreeName">;
94
+ }, {
95
+ devDomain?: string;
96
+ worktree?: string;
97
+ }>>;
98
+ cwd: z.ZodNullable<z.ZodString>;
99
+ spawnedAt: z.ZodString;
100
+ updatedAt: z.ZodString;
101
+ }, "strip", z.ZodTypeAny, {
102
+ status?: "idle" | "spawning" | "ready" | "draining" | "stopped";
103
+ id?: string;
104
+ pid?: number;
105
+ port?: number & z.BRAND<"Port">;
106
+ slot?: {
107
+ devDomain?: string & z.BRAND<"DevDomain">;
108
+ worktree?: string & z.BRAND<"WorktreeName">;
109
+ };
110
+ cwd?: string;
111
+ spawnedAt?: string;
112
+ updatedAt?: string;
113
+ }, {
114
+ status?: "idle" | "spawning" | "ready" | "draining" | "stopped";
115
+ id?: string;
116
+ pid?: number;
117
+ port?: number;
118
+ slot?: {
119
+ devDomain?: string;
120
+ worktree?: string;
121
+ };
122
+ cwd?: string;
123
+ spawnedAt?: string;
124
+ updatedAt?: string;
125
+ }>;
126
+ }, "strip", z.ZodTypeAny, {
127
+ lease?: {
128
+ id?: string;
129
+ slot?: {
130
+ devDomain?: string & z.BRAND<"DevDomain">;
131
+ worktree?: string & z.BRAND<"WorktreeName">;
132
+ };
133
+ devServerId?: string;
134
+ url?: string;
135
+ expiresAt?: string;
136
+ };
137
+ devServer?: {
138
+ status?: "idle" | "spawning" | "ready" | "draining" | "stopped";
139
+ id?: string;
140
+ pid?: number;
141
+ port?: number & z.BRAND<"Port">;
142
+ slot?: {
143
+ devDomain?: string & z.BRAND<"DevDomain">;
144
+ worktree?: string & z.BRAND<"WorktreeName">;
145
+ };
146
+ cwd?: string;
147
+ spawnedAt?: string;
148
+ updatedAt?: string;
149
+ };
150
+ }, {
151
+ lease?: {
152
+ id?: string;
153
+ slot?: {
154
+ devDomain?: string;
155
+ worktree?: string;
156
+ };
157
+ devServerId?: string;
158
+ url?: string;
159
+ expiresAt?: string;
160
+ };
161
+ devServer?: {
162
+ status?: "idle" | "spawning" | "ready" | "draining" | "stopped";
163
+ id?: string;
164
+ pid?: number;
165
+ port?: number;
166
+ slot?: {
167
+ devDomain?: string;
168
+ worktree?: string;
169
+ };
170
+ cwd?: string;
171
+ spawnedAt?: string;
172
+ updatedAt?: string;
173
+ };
174
+ }>;
175
+ type AcquireResponse = z.infer<typeof AcquireResponse>;
176
+ /** `POST /devserver/release` — relinquish the lease and trigger draining. */
177
+ declare const ReleaseRequest: z.ZodObject<{
178
+ leaseId: z.ZodString;
179
+ }, "strip", z.ZodTypeAny, {
180
+ leaseId?: string;
181
+ }, {
182
+ leaseId?: string;
183
+ }>;
184
+ type ReleaseRequest = z.infer<typeof ReleaseRequest>;
185
+ /** `POST /devserver/renew` — extend the lease without changing devserver state. */
186
+ declare const RenewRequest: z.ZodObject<{
187
+ leaseId: z.ZodString;
188
+ ttlSeconds: z.ZodDefault<z.ZodNumber>;
189
+ }, "strip", z.ZodTypeAny, {
190
+ ttlSeconds?: number;
191
+ leaseId?: string;
192
+ }, {
193
+ ttlSeconds?: number;
194
+ leaseId?: string;
195
+ }>;
196
+ type RenewRequest = z.infer<typeof RenewRequest>;
197
+ /** `GET /proxy/state` — current routing table the runtime believes Caddy holds. */
198
+ declare const ProxyState: z.ZodObject<{
199
+ routes: z.ZodArray<z.ZodObject<{
200
+ devDomain: z.ZodBranded<z.ZodString, "DevDomain">;
201
+ host: z.ZodString;
202
+ upstreams: z.ZodRecord<z.ZodString, z.ZodBranded<z.ZodNumber, "Port">>;
203
+ }, "strip", z.ZodTypeAny, {
204
+ devDomain?: string & z.BRAND<"DevDomain">;
205
+ host?: string;
206
+ upstreams?: Record<string, number & z.BRAND<"Port">>;
207
+ }, {
208
+ devDomain?: string;
209
+ host?: string;
210
+ upstreams?: Record<string, number>;
211
+ }>, "many">;
212
+ caddyReachable: z.ZodBoolean;
213
+ }, "strip", z.ZodTypeAny, {
214
+ routes?: {
215
+ devDomain?: string & z.BRAND<"DevDomain">;
216
+ host?: string;
217
+ upstreams?: Record<string, number & z.BRAND<"Port">>;
218
+ }[];
219
+ caddyReachable?: boolean;
220
+ }, {
221
+ routes?: {
222
+ devDomain?: string;
223
+ host?: string;
224
+ upstreams?: Record<string, number>;
225
+ }[];
226
+ caddyReachable?: boolean;
227
+ }>;
228
+ type ProxyState = z.infer<typeof ProxyState>;
229
+ /** `GET /pool/status` — hot-pool inventory. */
230
+ declare const PoolStatus: z.ZodObject<{
231
+ warm: z.ZodNumber;
232
+ bound: z.ZodNumber;
233
+ capacity: z.ZodNumber;
234
+ }, "strip", z.ZodTypeAny, {
235
+ warm?: number;
236
+ bound?: number;
237
+ capacity?: number;
238
+ }, {
239
+ warm?: number;
240
+ bound?: number;
241
+ capacity?: number;
242
+ }>;
243
+ type PoolStatus = z.infer<typeof PoolStatus>;
244
+ /** `POST /proxy/upsert` — bind (devDomain, worktree) → port in the proxy. */
245
+ declare const ProxyUpsertRequest: z.ZodObject<{
246
+ devDomain: z.ZodString;
247
+ worktree: z.ZodString;
248
+ port: z.ZodNumber;
249
+ }, "strip", z.ZodTypeAny, {
250
+ devDomain?: string;
251
+ worktree?: string;
252
+ port?: number;
253
+ }, {
254
+ devDomain?: string;
255
+ worktree?: string;
256
+ port?: number;
257
+ }>;
258
+ type ProxyUpsertRequest = z.infer<typeof ProxyUpsertRequest>;
259
+ /** `POST /proxy/remove` — drop a worktree's route from the proxy. */
260
+ declare const ProxyRemoveRequest: z.ZodObject<{
261
+ devDomain: z.ZodString;
262
+ worktree: z.ZodString;
263
+ }, "strip", z.ZodTypeAny, {
264
+ devDomain?: string;
265
+ worktree?: string;
266
+ }, {
267
+ devDomain?: string;
268
+ worktree?: string;
269
+ }>;
270
+ type ProxyRemoveRequest = z.infer<typeof ProxyRemoveRequest>;
271
+ /** `GET /health` — daemon liveness probe. */
272
+ declare const Health: z.ZodObject<{
273
+ ok: z.ZodLiteral<true>;
274
+ version: z.ZodString;
275
+ uptimeSeconds: z.ZodNumber;
276
+ port: z.ZodBranded<z.ZodNumber, "Port">;
277
+ }, "strip", z.ZodTypeAny, {
278
+ port?: number & z.BRAND<"Port">;
279
+ ok?: true;
280
+ version?: string;
281
+ uptimeSeconds?: number;
282
+ }, {
283
+ port?: number;
284
+ ok?: true;
285
+ version?: string;
286
+ uptimeSeconds?: number;
287
+ }>;
288
+ type Health = z.infer<typeof Health>;
289
+ /** Runtime error envelope. All non-2xx responses share this shape. */
290
+ declare const RuntimeError: z.ZodObject<{
291
+ error: z.ZodString;
292
+ code: z.ZodEnum<["NOT_IMPLEMENTED", "BAD_REQUEST", "CONFLICT", "NOT_FOUND", "FORBIDDEN_DEFAULT_DOMAIN", "INTERNAL", "CADDY_UNREACHABLE", "PORT_EXHAUSTED", "TIMEOUT"]>;
293
+ details: z.ZodOptional<z.ZodUnknown>;
294
+ }, "strip", z.ZodTypeAny, {
295
+ code?: "NOT_IMPLEMENTED" | "BAD_REQUEST" | "CONFLICT" | "NOT_FOUND" | "FORBIDDEN_DEFAULT_DOMAIN" | "INTERNAL" | "CADDY_UNREACHABLE" | "PORT_EXHAUSTED" | "TIMEOUT";
296
+ error?: string;
297
+ details?: unknown;
298
+ }, {
299
+ code?: "NOT_IMPLEMENTED" | "BAD_REQUEST" | "CONFLICT" | "NOT_FOUND" | "FORBIDDEN_DEFAULT_DOMAIN" | "INTERNAL" | "CADDY_UNREACHABLE" | "PORT_EXHAUSTED" | "TIMEOUT";
300
+ error?: string;
301
+ details?: unknown;
302
+ }>;
303
+ type RuntimeError = z.infer<typeof RuntimeError>;
304
+
305
+ export { AcquireRequest as A, Health as H, ProxyState as P, ReleaseRequest as R, AcquireResponse as a, RenewRequest as b, PoolStatus as c, ProxyUpsertRequest as d, ProxyRemoveRequest as e, RuntimeError as f };
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ import { H as Health, A as AcquireRequest, a as AcquireResponse, R as ReleaseRequest, b as RenewRequest, P as ProxyState, d as ProxyUpsertRequest, e as ProxyRemoveRequest, c as PoolStatus, f as RuntimeError } from '../api-Bbh7Mcv9.js';
3
+
4
+ interface RuntimeClientOptions {
5
+ /** Override base URL (mostly for tests). */
6
+ baseUrl?: string;
7
+ /** Auto-start the daemon if it isn't running. Default: true. */
8
+ autoStart?: boolean;
9
+ }
10
+ declare class RuntimeRequestError extends Error {
11
+ readonly status: number;
12
+ readonly code: z.infer<typeof RuntimeError>['code'];
13
+ readonly details?: unknown;
14
+ constructor(message: string, status: number, code: z.infer<typeof RuntimeError>['code'], details?: unknown);
15
+ }
16
+ declare class RuntimeClient {
17
+ readonly baseUrl: string;
18
+ readonly autoStart: boolean;
19
+ constructor(opts?: RuntimeClientOptions);
20
+ health(): Promise<Health>;
21
+ acquire(input: z.input<typeof AcquireRequest>): Promise<AcquireResponse>;
22
+ release(input: z.input<typeof ReleaseRequest>): Promise<void>;
23
+ renew(input: z.input<typeof RenewRequest>): Promise<void>;
24
+ proxyState(): Promise<ProxyState>;
25
+ proxyUpsert(input: z.input<typeof ProxyUpsertRequest>): Promise<ProxyState>;
26
+ proxyRemove(input: z.input<typeof ProxyRemoveRequest>): Promise<ProxyState>;
27
+ poolStatus(): Promise<PoolStatus>;
28
+ }
29
+ /** Default singleton client for casual callers. */
30
+ declare const runtime: RuntimeClient;
31
+
32
+ export { RuntimeClient, type RuntimeClientOptions, RuntimeRequestError, runtime };
@@ -0,0 +1,281 @@
1
+ // src/runtime/client/index.ts
2
+ import { spawn } from "child_process";
3
+ import { fileURLToPath } from "url";
4
+ import { dirname, resolve } from "path";
5
+ import { existsSync, readFileSync } from "fs";
6
+
7
+ // src/runtime/schema/identity.ts
8
+ import { z } from "zod";
9
+ var DevDomain = z.string().min(1).max(32).regex(/^[a-z][a-z0-9-]*$/, "devDomain must match /^[a-z][a-z0-9-]*$/").brand();
10
+ var WorktreeName = z.string().min(1).max(64).regex(/^[a-z0-9][a-z0-9._-]*$/i, "worktree name must be URL-safe").brand();
11
+ var Port = z.number().int().min(1024).max(65535).brand();
12
+ var DevServerSlot = z.object({
13
+ devDomain: DevDomain,
14
+ worktree: WorktreeName
15
+ });
16
+
17
+ // src/runtime/schema/devserver.ts
18
+ import { z as z2 } from "zod";
19
+ var DevServerStatus = z2.enum([
20
+ "idle",
21
+ // pre-warmed in the hot pool, no project bound yet
22
+ "spawning",
23
+ // process started, waiting for `ready in …` from Vite stdout
24
+ "ready",
25
+ // bound to a slot, accepting traffic via Caddy
26
+ "draining",
27
+ // releasing — finishing in-flight requests before kill
28
+ "stopped"
29
+ // process exited, slot freed, port returned to the pool
30
+ ]);
31
+ var DevServer = z2.object({
32
+ id: z2.string().uuid(),
33
+ pid: z2.number().int().positive(),
34
+ port: Port,
35
+ status: DevServerStatus,
36
+ slot: DevServerSlot.nullable(),
37
+ /** Absolute path of the worktree directory once bound; null while in the pool. */
38
+ cwd: z2.string().nullable(),
39
+ /** ISO timestamp; immutable after spawn. */
40
+ spawnedAt: z2.string().datetime(),
41
+ /** ISO timestamp of last status change. */
42
+ updatedAt: z2.string().datetime()
43
+ });
44
+ var Lease = z2.object({
45
+ id: z2.string().uuid(),
46
+ devServerId: z2.string().uuid(),
47
+ slot: DevServerSlot,
48
+ /** Public proxy URL the client should print to the user. Authoritative. */
49
+ url: z2.string().url(),
50
+ /** Renew before this timestamp or the lease expires and the devserver drains. */
51
+ expiresAt: z2.string().datetime()
52
+ });
53
+ var ProxyRoute = z2.object({
54
+ devDomain: DevDomain,
55
+ host: z2.string(),
56
+ /** worktree name → upstream port. `main` is the host's catch-all. */
57
+ upstreams: z2.record(z2.string(), Port)
58
+ });
59
+
60
+ // src/runtime/schema/api.ts
61
+ import { z as z3 } from "zod";
62
+ var AcquireRequest = z3.object({
63
+ slot: DevServerSlot,
64
+ /** Absolute path of the worktree directory; the runtime spawns Vite with `cwd: targetCwd`. */
65
+ targetCwd: z3.string().min(1),
66
+ /** Lease TTL in seconds. Defaults to 5 min; CLI clients renew on each command. */
67
+ ttlSeconds: z3.number().int().min(30).max(60 * 60).default(300),
68
+ /**
69
+ * Escape hatch for the deprecated default devDomain `"storyboard"`. CI and
70
+ * one-off scripts may pass true; the CLI never does.
71
+ */
72
+ allowDefaultDomain: z3.boolean().default(false)
73
+ });
74
+ var AcquireResponse = z3.object({
75
+ lease: Lease,
76
+ devServer: DevServer
77
+ });
78
+ var ReleaseRequest = z3.object({
79
+ leaseId: z3.string().uuid()
80
+ });
81
+ var RenewRequest = z3.object({
82
+ leaseId: z3.string().uuid(),
83
+ ttlSeconds: z3.number().int().min(30).max(60 * 60).default(300)
84
+ });
85
+ var ProxyState = z3.object({
86
+ routes: z3.array(ProxyRoute),
87
+ caddyReachable: z3.boolean()
88
+ });
89
+ var PoolStatus = z3.object({
90
+ warm: z3.number().int().nonnegative(),
91
+ bound: z3.number().int().nonnegative(),
92
+ capacity: z3.number().int().nonnegative()
93
+ });
94
+ var ProxyUpsertRequest = z3.object({
95
+ devDomain: z3.string(),
96
+ worktree: z3.string(),
97
+ port: z3.number()
98
+ });
99
+ var ProxyRemoveRequest = z3.object({
100
+ devDomain: z3.string(),
101
+ worktree: z3.string()
102
+ });
103
+ var Health = z3.object({
104
+ ok: z3.literal(true),
105
+ version: z3.string(),
106
+ uptimeSeconds: z3.number().nonnegative(),
107
+ port: Port
108
+ });
109
+ var RuntimeError = z3.object({
110
+ error: z3.string(),
111
+ code: z3.enum([
112
+ "NOT_IMPLEMENTED",
113
+ "BAD_REQUEST",
114
+ "CONFLICT",
115
+ "NOT_FOUND",
116
+ "FORBIDDEN_DEFAULT_DOMAIN",
117
+ "INTERNAL",
118
+ "CADDY_UNREACHABLE",
119
+ "PORT_EXHAUSTED",
120
+ "TIMEOUT"
121
+ ]),
122
+ details: z3.unknown().optional()
123
+ });
124
+
125
+ // src/runtime/client/index.ts
126
+ var RUNTIME_BASE = "http://127.0.0.1:4321";
127
+ var RuntimeRequestError = class extends Error {
128
+ constructor(message, status, code, details) {
129
+ super(message);
130
+ this.status = status;
131
+ this.code = code;
132
+ this.details = details;
133
+ this.name = "RuntimeRequestError";
134
+ }
135
+ };
136
+ async function request(baseUrl, method, path, body, responseSchema) {
137
+ const init = {
138
+ method,
139
+ headers: body !== void 0 ? { "Content-Type": "application/json" } : void 0,
140
+ body: body !== void 0 ? JSON.stringify(body) : void 0
141
+ };
142
+ let res;
143
+ try {
144
+ res = await fetch(`${baseUrl}${path}`, init);
145
+ } catch (err) {
146
+ throw new RuntimeRequestError(
147
+ `Cannot reach Storyboard Runtime at ${baseUrl} \u2014 is the daemon running? (${err.message})`,
148
+ 0,
149
+ "INTERNAL"
150
+ );
151
+ }
152
+ const text = await res.text();
153
+ let parsed;
154
+ try {
155
+ parsed = text ? JSON.parse(text) : {};
156
+ } catch {
157
+ parsed = { error: text, code: "INTERNAL" };
158
+ }
159
+ if (!res.ok) {
160
+ const err = RuntimeError.safeParse(parsed);
161
+ if (err.success) {
162
+ throw new RuntimeRequestError(err.data.error, res.status, err.data.code, err.data.details);
163
+ }
164
+ throw new RuntimeRequestError(`HTTP ${res.status}`, res.status, "INTERNAL", parsed);
165
+ }
166
+ if (responseSchema === null) return void 0;
167
+ return responseSchema.parse(parsed);
168
+ }
169
+ async function spawnDaemon(baseUrl) {
170
+ const here = dirname(fileURLToPath(import.meta.url));
171
+ const binPath = resolve(here, "..", "..", "..", "bin", "storyboard-runtime.js");
172
+ const child = spawn(process.execPath, [binPath], {
173
+ detached: true,
174
+ stdio: "ignore",
175
+ env: process.env
176
+ });
177
+ child.unref();
178
+ const deadline = Date.now() + 5e3;
179
+ while (Date.now() < deadline) {
180
+ try {
181
+ const r = await fetch(`${baseUrl}/health`);
182
+ if (r.ok) return;
183
+ } catch {
184
+ }
185
+ await new Promise((r) => setTimeout(r, 100));
186
+ }
187
+ throw new Error(
188
+ `Storyboard Runtime did not become ready within 5s (tried to spawn ${binPath})`
189
+ );
190
+ }
191
+ function readClientVersion() {
192
+ try {
193
+ const here = dirname(fileURLToPath(import.meta.url));
194
+ const candidates = [
195
+ resolve(here, "..", "..", "..", "package.json"),
196
+ resolve(here, "..", "..", "package.json")
197
+ ];
198
+ for (const p of candidates) {
199
+ if (existsSync(p)) {
200
+ const pkg = JSON.parse(readFileSync(p, "utf8"));
201
+ if (typeof pkg.version === "string") return pkg.version;
202
+ }
203
+ }
204
+ } catch {
205
+ }
206
+ return "0.0.0";
207
+ }
208
+ var CLIENT_VERSION = readClientVersion();
209
+ function killExistingDaemon() {
210
+ try {
211
+ const pidPath = resolve(process.env.HOME || "", ".storyboard", "runtime.pid");
212
+ if (!existsSync(pidPath)) return;
213
+ const pid = Number(readFileSync(pidPath, "utf8").trim());
214
+ if (Number.isFinite(pid) && pid > 0) {
215
+ try {
216
+ process.kill(pid, "SIGTERM");
217
+ } catch {
218
+ }
219
+ }
220
+ } catch {
221
+ }
222
+ }
223
+ var RuntimeClient = class {
224
+ baseUrl;
225
+ autoStart;
226
+ constructor(opts = {}) {
227
+ this.baseUrl = opts.baseUrl ?? RUNTIME_BASE;
228
+ this.autoStart = opts.autoStart !== false;
229
+ }
230
+ async health() {
231
+ try {
232
+ const result = await request(this.baseUrl, "GET", "/health", void 0, Health);
233
+ if (this.autoStart && CLIENT_VERSION !== "0.0.0" && result.version !== "0.0.0" && result.version !== CLIENT_VERSION) {
234
+ killExistingDaemon();
235
+ await new Promise((r) => setTimeout(r, 250));
236
+ await spawnDaemon(this.baseUrl);
237
+ return request(this.baseUrl, "GET", "/health", void 0, Health);
238
+ }
239
+ return result;
240
+ } catch (err) {
241
+ if (this.autoStart && err instanceof RuntimeRequestError && err.status === 0) {
242
+ await spawnDaemon(this.baseUrl);
243
+ return request(this.baseUrl, "GET", "/health", void 0, Health);
244
+ }
245
+ throw err;
246
+ }
247
+ }
248
+ async acquire(input) {
249
+ const body = AcquireRequest.parse(input);
250
+ return request(this.baseUrl, "POST", "/devserver/acquire", body, AcquireResponse);
251
+ }
252
+ async release(input) {
253
+ const body = ReleaseRequest.parse(input);
254
+ await request(this.baseUrl, "POST", "/devserver/release", body, null);
255
+ }
256
+ async renew(input) {
257
+ const body = RenewRequest.parse(input);
258
+ await request(this.baseUrl, "POST", "/devserver/renew", body, null);
259
+ }
260
+ async proxyState() {
261
+ return request(this.baseUrl, "GET", "/proxy/state", void 0, ProxyState);
262
+ }
263
+ async proxyUpsert(input) {
264
+ const body = ProxyUpsertRequest.parse(input);
265
+ return request(this.baseUrl, "POST", "/proxy/upsert", body, ProxyState);
266
+ }
267
+ async proxyRemove(input) {
268
+ const body = ProxyRemoveRequest.parse(input);
269
+ return request(this.baseUrl, "POST", "/proxy/remove", body, ProxyState);
270
+ }
271
+ async poolStatus() {
272
+ return request(this.baseUrl, "GET", "/pool/status", void 0, PoolStatus);
273
+ }
274
+ };
275
+ var runtime = new RuntimeClient();
276
+ export {
277
+ RuntimeClient,
278
+ RuntimeRequestError,
279
+ runtime
280
+ };
281
+ //# sourceMappingURL=index.js.map