@stackable-labs/cli-app-extension 1.36.3 → 1.37.0

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 (3) hide show
  1. package/README.md +73 -14
  2. package/dist/index.js +551 -474
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9,10 +9,67 @@ import { render } from "ink";
9
9
  import { readFile as readFile3 } from "fs/promises";
10
10
  import { join as join3 } from "path";
11
11
  import { Box as Box15, Text as Text15, useApp } from "ink";
12
- import { useCallback, useEffect as useEffect4, useState as useState10 } from "react";
12
+ import Spinner4 from "ink-spinner";
13
+ import { useCallback as useCallback2, useEffect as useEffect4, useState as useState11 } from "react";
14
+
15
+ // src/components/Banner.tsx
16
+ import { Box, Text } from "ink";
17
+ import { jsx, jsxs } from "react/jsx-runtime";
18
+ var WORDMARK = [
19
+ " _ _ _ _ ",
20
+ " ___| |_ __ _ ___| | ____ _| |__ | | ___",
21
+ "/ __| __/ _` |/ __| |/ / _` | '_ \\| |/ _ \\",
22
+ "\\__ \\ || (_| | (__| < (_| | |_) | | __/",
23
+ "|___/\\__\\__,_|\\___|_|\\_\\__,_|_.__/|_|\\___|"
24
+ ];
25
+ var COLORS = [
26
+ [232, 218, 234],
27
+ // Lit Lilac #E8DAEA
28
+ [197, 96, 255],
29
+ // Poppy Purple #C560FF
30
+ [0, 174, 247],
31
+ // Bluetooth Blue #00AEF7
32
+ [70, 224, 177],
33
+ // Tropical Teal #46E0B1
34
+ [252, 248, 161]
35
+ // Not Mellow Yellow #FCF8A1
36
+ ];
37
+ var lerp = (a, b, t) => {
38
+ const r = Math.round(a[0] + (b[0] - a[0]) * t);
39
+ const g = Math.round(a[1] + (b[1] - a[1]) * t);
40
+ const bl = Math.round(a[2] + (b[2] - a[2]) * t);
41
+ return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${bl.toString(16).padStart(2, "0")}`;
42
+ };
43
+ var gradientColor = (row, col, rows, cols) => {
44
+ const t = (row / (rows - 1) + col / (cols - 1)) / 2;
45
+ const idx = t * (COLORS.length - 1);
46
+ const lo = Math.floor(idx);
47
+ const hi = Math.min(lo + 1, COLORS.length - 1);
48
+ return lerp(COLORS[lo], COLORS[hi], idx - lo);
49
+ };
50
+ var Banner = ({ userId, orgId } = {}) => {
51
+ const termWidth = process.stdout.columns ?? 80;
52
+ const maxLen = Math.max(...WORDMARK.map((l) => l.length));
53
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
54
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(termWidth) }),
55
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
56
+ WORDMARK.map((line, row) => /* @__PURE__ */ jsx(Box, { children: line.split("").map((ch, col) => /* @__PURE__ */ jsx(Text, { bold: true, color: ch === " " ? void 0 : gradientColor(row, col, WORDMARK.length, maxLen), children: ch }, col)) }, row)),
57
+ userId && orgId && /* @__PURE__ */ jsxs(Box, { gap: 2, marginTop: 1, children: [
58
+ /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
59
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "User:" }),
60
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: userId })
61
+ ] }),
62
+ /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
63
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Org:" }),
64
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: orgId })
65
+ ] })
66
+ ] })
67
+ ] })
68
+ ] });
69
+ };
13
70
 
14
71
  // src/components/Confirm.tsx
15
- import { Box as Box2, Text as Text2, useFocus, useFocusManager, useInput as useInput2 } from "ink";
72
+ import { Box as Box3, Text as Text3, useFocus, useFocusManager, useInput as useInput2 } from "ink";
16
73
  import TextInput from "ink-text-input";
17
74
  import { useEffect, useState } from "react";
18
75
 
@@ -51,8 +108,8 @@ var TARGET_PERMISSION_MAP = {
51
108
  };
52
109
 
53
110
  // src/components/StepShell.tsx
54
- import { Box, Text, useInput } from "ink";
55
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
111
+ import { Box as Box2, Text as Text2, useInput } from "ink";
112
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
56
113
  var divider = (width) => "\u2500".repeat(width);
57
114
  var INNER_DIVIDER_WIDTH = 40;
58
115
  var StepShell = ({ title, hint, children, footer, onBack }) => {
@@ -62,29 +119,29 @@ var StepShell = ({ title, hint, children, footer, onBack }) => {
62
119
  onBack();
63
120
  }
64
121
  });
65
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 0, children: [
66
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: divider(termWidth) }),
67
- /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, gap: 1, children: [
68
- /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 0, children: [
69
- onBack && /* @__PURE__ */ jsxs(Box, { gap: 1, marginBottom: 1, children: [
70
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2190 Back" }),
71
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(Esc)" })
122
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", gap: 0, children: [
123
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: divider(termWidth) }),
124
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, paddingY: 1, gap: 1, children: [
125
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", gap: 0, children: [
126
+ onBack && /* @__PURE__ */ jsxs2(Box2, { gap: 1, marginBottom: 1, children: [
127
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2190 Back" }),
128
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "(Esc)" })
72
129
  ] }),
73
- /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: title }),
74
- hint && /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint })
130
+ /* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: title }),
131
+ hint && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: hint })
75
132
  ] }),
76
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: divider(INNER_DIVIDER_WIDTH) }),
133
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: divider(INNER_DIVIDER_WIDTH) }),
77
134
  children
78
135
  ] }),
79
- footer && /* @__PURE__ */ jsxs(Fragment, { children: [
80
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: divider(termWidth) }),
81
- /* @__PURE__ */ jsx(Box, { paddingX: 1, paddingTop: 1, children: footer })
136
+ footer && /* @__PURE__ */ jsxs2(Fragment, { children: [
137
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: divider(termWidth) }),
138
+ /* @__PURE__ */ jsx2(Box2, { paddingX: 1, paddingTop: 1, children: footer })
82
139
  ] })
83
140
  ] });
84
141
  };
85
142
 
86
143
  // src/components/Confirm.tsx
87
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
144
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
88
145
  var compareSemver = (a, b) => {
89
146
  const pa = a.split(".").map(Number);
90
147
  const pb = b.split(".").map(Number);
@@ -120,17 +177,17 @@ var VersionRow = ({ currentVersion, value, onChange, onFocusChange, onConfirm, o
120
177
  const isValid = /^\d+\.\d+\.\d+$/.test(value) && compareSemver(value, currentVersion) > 0;
121
178
  const showError = isFocused && value !== "" && !isValid;
122
179
  const hasChange = value !== currentVersion;
123
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
124
- /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
125
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Version " }),
126
- /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
180
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
181
+ /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
182
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Version " }),
183
+ /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
127
184
  currentVersion,
128
185
  hasChange ? " \u2192 " : ""
129
186
  ] }),
130
- isFocused ? /* @__PURE__ */ jsx2(TextInput, { value, onChange, placeholder: value }) : hasChange && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: value }),
131
- isFocused && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "(edit to override)" })
187
+ isFocused ? /* @__PURE__ */ jsx3(TextInput, { value, onChange, placeholder: value }) : hasChange && /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: value }),
188
+ isFocused && /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "(edit to override)" })
132
189
  ] }),
133
- showError && /* @__PURE__ */ jsx2(Text2, { color: "red", children: " Version must be greater than " + currentVersion })
190
+ showError && /* @__PURE__ */ jsx3(Text3, { color: "red", children: " Version must be greater than " + currentVersion })
134
191
  ] });
135
192
  };
136
193
  var Confirm = ({
@@ -181,29 +238,29 @@ var Confirm = ({
181
238
  }
182
239
  }
183
240
  });
184
- return /* @__PURE__ */ jsx2(
241
+ return /* @__PURE__ */ jsx3(
185
242
  StepShell,
186
243
  {
187
244
  title: command === "update" /* UPDATE */ ? "Ready to update" : "Ready to scaffold",
188
245
  hint: "Review your settings before proceeding",
189
246
  onBack,
190
- footer: /* @__PURE__ */ jsxs2(Text2, { children: [
247
+ footer: /* @__PURE__ */ jsxs3(Text3, { children: [
191
248
  "Proceed?",
192
249
  " ",
193
- /* @__PURE__ */ jsx2(Text2, { bold: true, color: "green", inverse: selected === "y", children: "Y" }),
194
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "/" }),
195
- /* @__PURE__ */ jsx2(Text2, { bold: true, color: "red", inverse: selected === "n", children: "n" })
250
+ /* @__PURE__ */ jsx3(Text3, { bold: true, color: "green", inverse: selected === "y", children: "Y" }),
251
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "/" }),
252
+ /* @__PURE__ */ jsx3(Text3, { bold: true, color: "red", inverse: selected === "n", children: "n" })
196
253
  ] }),
197
- children: /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", gap: 1, children: [
198
- /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
199
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Name " }),
200
- /* @__PURE__ */ jsx2(Text2, { dimColor: !!extensionVersion, children: name })
254
+ children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", gap: 1, children: [
255
+ /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
256
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Name " }),
257
+ /* @__PURE__ */ jsx3(Text3, { dimColor: !!extensionVersion, children: name })
201
258
  ] }),
202
- templateFlavor && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
203
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Template " }),
204
- /* @__PURE__ */ jsx2(Text2, { children: TEMPLATE_FLAVOR_META[templateFlavor].label })
259
+ templateFlavor && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
260
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Template " }),
261
+ /* @__PURE__ */ jsx3(Text3, { children: TEMPLATE_FLAVOR_META[templateFlavor].label })
205
262
  ] }),
206
- extensionVersion && command === "update" /* UPDATE */ && newVersion && onVersionOverride && /* @__PURE__ */ jsx2(
263
+ extensionVersion && command === "update" /* UPDATE */ && newVersion && onVersionOverride && /* @__PURE__ */ jsx3(
207
264
  VersionRow,
208
265
  {
209
266
  currentVersion: extensionVersion,
@@ -215,84 +272,84 @@ var Confirm = ({
215
272
  selected
216
273
  }
217
274
  ),
218
- extensionVersion && !(command === "update" /* UPDATE */ && newVersion && onVersionOverride) && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
219
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Version " }),
220
- /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
275
+ extensionVersion && !(command === "update" /* UPDATE */ && newVersion && onVersionOverride) && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
276
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Version " }),
277
+ /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
221
278
  extensionVersion,
222
279
  newVersion && newVersion !== extensionVersion ? ` \u2192 ${newVersion}` : ""
223
280
  ] })
224
281
  ] }),
225
- command !== "update" /* UPDATE */ && outputDir && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
226
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Directory " }),
227
- /* @__PURE__ */ jsx2(Text2, { children: outputDir })
282
+ command !== "update" /* UPDATE */ && outputDir && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
283
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Directory " }),
284
+ /* @__PURE__ */ jsx3(Text3, { children: outputDir })
228
285
  ] }),
229
- command !== "update" /* UPDATE */ && extensionPort !== void 0 && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
230
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Extension port" }),
231
- /* @__PURE__ */ jsx2(Text2, { children: extensionPort })
286
+ command !== "update" /* UPDATE */ && extensionPort !== void 0 && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
287
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Extension port" }),
288
+ /* @__PURE__ */ jsx3(Text3, { children: extensionPort })
232
289
  ] }),
233
- command !== "update" /* UPDATE */ && previewPort !== void 0 && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
234
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Preview port " }),
235
- /* @__PURE__ */ jsx2(Text2, { children: previewPort })
290
+ command !== "update" /* UPDATE */ && previewPort !== void 0 && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
291
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Preview port " }),
292
+ /* @__PURE__ */ jsx3(Text3, { children: previewPort })
236
293
  ] }),
237
- command === "update" /* UPDATE */ && bundleUrl && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
238
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Bundle URL " }),
239
- /* @__PURE__ */ jsx2(Text2, { children: bundleUrl })
294
+ command === "update" /* UPDATE */ && bundleUrl && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
295
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Bundle URL " }),
296
+ /* @__PURE__ */ jsx3(Text3, { children: bundleUrl })
240
297
  ] }),
241
- command === "update" /* UPDATE */ && enabled !== void 0 && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
242
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Enabled " }),
243
- /* @__PURE__ */ jsx2(Text2, { color: enabled ? "green" : "red", children: enabled ? "Yes" : "No" })
298
+ command === "update" /* UPDATE */ && enabled !== void 0 && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
299
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Enabled " }),
300
+ /* @__PURE__ */ jsx3(Text3, { color: enabled ? "green" : "red", children: enabled ? "Yes" : "No" })
244
301
  ] }),
245
- /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
246
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Targets " }),
247
- /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
302
+ /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
303
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Targets " }),
304
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
248
305
  targets.map((t) => {
249
306
  const isAdded = registryTargets && !registryTargets.includes(t);
250
- return /* @__PURE__ */ jsxs2(Box2, { gap: 1, children: [
251
- /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u2022 " }),
252
- /* @__PURE__ */ jsx2(Text2, { children: t }),
253
- isAdded && /* @__PURE__ */ jsx2(Text2, { color: "green", dimColor: true, children: "(+ added)" })
307
+ return /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
308
+ /* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2022 " }),
309
+ /* @__PURE__ */ jsx3(Text3, { children: t }),
310
+ isAdded && /* @__PURE__ */ jsx3(Text3, { color: "green", dimColor: true, children: "(+ added)" })
254
311
  ] }, t);
255
312
  }),
256
- registryTargets?.filter((t) => !targets.includes(t)).map((t) => /* @__PURE__ */ jsxs2(Box2, { gap: 1, children: [
257
- /* @__PURE__ */ jsx2(Text2, { color: "red", children: "\u2022 " }),
258
- /* @__PURE__ */ jsx2(Text2, { color: "red", dimColor: true, strikethrough: true, children: t }),
259
- /* @__PURE__ */ jsx2(Text2, { color: "red", dimColor: true, children: "(- removed)" })
313
+ registryTargets?.filter((t) => !targets.includes(t)).map((t) => /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
314
+ /* @__PURE__ */ jsx3(Text3, { color: "red", children: "\u2022 " }),
315
+ /* @__PURE__ */ jsx3(Text3, { color: "red", dimColor: true, strikethrough: true, children: t }),
316
+ /* @__PURE__ */ jsx3(Text3, { color: "red", dimColor: true, children: "(- removed)" })
260
317
  ] }, t))
261
318
  ] })
262
319
  ] }),
263
- permissions && (permissions.length > 0 || registryPermissions?.some((p) => !permissions.includes(p))) && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
264
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Permissions " }),
265
- /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
320
+ permissions && (permissions.length > 0 || registryPermissions?.some((p) => !permissions.includes(p))) && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
321
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Permissions " }),
322
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
266
323
  permissions.map((p) => {
267
324
  const isAdded = registryPermissions && !registryPermissions.includes(p);
268
- return /* @__PURE__ */ jsxs2(Box2, { gap: 1, children: [
269
- /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u2022 " }),
270
- /* @__PURE__ */ jsx2(Text2, { children: p }),
271
- isAdded && /* @__PURE__ */ jsx2(Text2, { color: "green", dimColor: true, children: "(+ added)" })
325
+ return /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
326
+ /* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2022 " }),
327
+ /* @__PURE__ */ jsx3(Text3, { children: p }),
328
+ isAdded && /* @__PURE__ */ jsx3(Text3, { color: "green", dimColor: true, children: "(+ added)" })
272
329
  ] }, p);
273
330
  }),
274
- registryPermissions?.filter((p) => !permissions.includes(p)).map((p) => /* @__PURE__ */ jsxs2(Box2, { gap: 1, children: [
275
- /* @__PURE__ */ jsx2(Text2, { color: "red", children: "\u2022 " }),
276
- /* @__PURE__ */ jsx2(Text2, { color: "red", dimColor: true, strikethrough: true, children: p }),
277
- /* @__PURE__ */ jsx2(Text2, { color: "red", dimColor: true, children: "(- removed)" })
331
+ registryPermissions?.filter((p) => !permissions.includes(p)).map((p) => /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
332
+ /* @__PURE__ */ jsx3(Text3, { color: "red", children: "\u2022 " }),
333
+ /* @__PURE__ */ jsx3(Text3, { color: "red", dimColor: true, strikethrough: true, children: p }),
334
+ /* @__PURE__ */ jsx3(Text3, { color: "red", dimColor: true, children: "(- removed)" })
278
335
  ] }, p))
279
336
  ] })
280
337
  ] }),
281
- allowedDomains && (allowedDomains.length > 0 || registryAllowedDomains?.some((d) => !allowedDomains.includes(d))) && /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
282
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Domains " }),
283
- /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
338
+ allowedDomains && (allowedDomains.length > 0 || registryAllowedDomains?.some((d) => !allowedDomains.includes(d))) && /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
339
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Domains " }),
340
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
284
341
  allowedDomains.map((d) => {
285
342
  const isAdded = registryAllowedDomains && !registryAllowedDomains.includes(d);
286
- return /* @__PURE__ */ jsxs2(Box2, { gap: 1, children: [
287
- /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u2022 " }),
288
- /* @__PURE__ */ jsx2(Text2, { children: d }),
289
- isAdded && /* @__PURE__ */ jsx2(Text2, { color: "green", dimColor: true, children: "(+ added)" })
343
+ return /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
344
+ /* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2022 " }),
345
+ /* @__PURE__ */ jsx3(Text3, { children: d }),
346
+ isAdded && /* @__PURE__ */ jsx3(Text3, { color: "green", dimColor: true, children: "(+ added)" })
290
347
  ] }, d);
291
348
  }),
292
- registryAllowedDomains?.filter((d) => !allowedDomains.includes(d)).map((d) => /* @__PURE__ */ jsxs2(Box2, { gap: 1, children: [
293
- /* @__PURE__ */ jsx2(Text2, { color: "red", children: "\u2022 " }),
294
- /* @__PURE__ */ jsx2(Text2, { color: "red", dimColor: true, strikethrough: true, children: d }),
295
- /* @__PURE__ */ jsx2(Text2, { color: "red", dimColor: true, children: "(- removed)" })
349
+ registryAllowedDomains?.filter((d) => !allowedDomains.includes(d)).map((d) => /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
350
+ /* @__PURE__ */ jsx3(Text3, { color: "red", children: "\u2022 " }),
351
+ /* @__PURE__ */ jsx3(Text3, { color: "red", dimColor: true, strikethrough: true, children: d }),
352
+ /* @__PURE__ */ jsx3(Text3, { color: "red", dimColor: true, children: "(- removed)" })
296
353
  ] }, d))
297
354
  ] })
298
355
  ] })
@@ -302,70 +359,70 @@ var Confirm = ({
302
359
  };
303
360
 
304
361
  // src/components/Done.tsx
305
- import { Box as Box3, Text as Text3 } from "ink";
306
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
362
+ import { Box as Box4, Text as Text4 } from "ink";
363
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
307
364
  var FLAVOR_HINTS = {
308
365
  minimal: "A clean slate \u2014 add surfaces and capabilities as you need them.",
309
366
  starter: "Common patterns included \u2014 customize and build from here.",
310
367
  "kitchen-sink": "We threw in everything \u2014 including the kitchen sink. Poke around, steal patterns, then delete what you don't need."
311
368
  };
312
- var Done = ({ name, outputDir, templateFlavor }) => /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", gap: 1, children: [
313
- /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
314
- /* @__PURE__ */ jsx3(Text3, { color: "green", bold: true, children: "\u2714" }),
315
- /* @__PURE__ */ jsx3(Text3, { bold: true, children: "Extension scaffolded successfully!" })
369
+ var Done = ({ name, outputDir, templateFlavor }) => /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
370
+ /* @__PURE__ */ jsxs4(Box4, { gap: 1, children: [
371
+ /* @__PURE__ */ jsx4(Text4, { color: "green", bold: true, children: "\u2714" }),
372
+ /* @__PURE__ */ jsx4(Text4, { bold: true, children: "Extension scaffolded successfully!" })
316
373
  ] }),
317
- /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginLeft: 2, children: [
318
- /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
374
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginLeft: 2, children: [
375
+ /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
319
376
  "Created: ",
320
- /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: name })
377
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: name })
321
378
  ] }),
322
- templateFlavor && /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
379
+ templateFlavor && /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
323
380
  "Template: ",
324
- /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: TEMPLATE_FLAVOR_META[templateFlavor].label })
381
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: TEMPLATE_FLAVOR_META[templateFlavor].label })
325
382
  ] }),
326
- /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
383
+ /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
327
384
  "Location: ",
328
- /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: outputDir })
385
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: outputDir })
329
386
  ] })
330
387
  ] }),
331
- templateFlavor && /* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: FLAVOR_HINTS[templateFlavor] }) }),
332
- /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, children: [
333
- /* @__PURE__ */ jsx3(Text3, { bold: true, children: "Next steps:" }),
334
- /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, gap: 1, children: [
335
- /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
336
- /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "1." }),
337
- /* @__PURE__ */ jsxs3(Text3, { children: [
338
- /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "cd " }),
339
- /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: outputDir })
388
+ templateFlavor && /* @__PURE__ */ jsx4(Box4, { marginLeft: 2, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: FLAVOR_HINTS[templateFlavor] }) }),
389
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, children: [
390
+ /* @__PURE__ */ jsx4(Text4, { bold: true, children: "Next steps:" }),
391
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, gap: 1, children: [
392
+ /* @__PURE__ */ jsxs4(Box4, { gap: 1, children: [
393
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "1." }),
394
+ /* @__PURE__ */ jsxs4(Text4, { children: [
395
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "cd " }),
396
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: outputDir })
340
397
  ] })
341
398
  ] }),
342
- /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
343
- /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "2." }),
344
- /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "pnpm install" })
399
+ /* @__PURE__ */ jsxs4(Box4, { gap: 1, children: [
400
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "2." }),
401
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "pnpm install" })
345
402
  ] }),
346
- /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
347
- /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "3." }),
348
- /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "pnpm dev" })
403
+ /* @__PURE__ */ jsxs4(Box4, { gap: 1, children: [
404
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "3." }),
405
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "pnpm dev" })
349
406
  ] })
350
407
  ] })
351
408
  ] })
352
409
  ] });
353
410
 
354
411
  // src/components/NamePrompt.tsx
355
- import { Box as Box5, Text as Text5 } from "ink";
412
+ import { Box as Box6, Text as Text6 } from "ink";
356
413
  import TextInput2 from "ink-text-input";
357
414
  import { useState as useState2 } from "react";
358
415
 
359
416
  // src/components/BackableInput.tsx
360
- import { Box as Box4, Text as Text4 } from "ink";
361
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
362
- var BackableInput = ({ label, hint, onBack, children, error }) => /* @__PURE__ */ jsx4(StepShell, { title: label, hint, onBack, children: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
417
+ import { Box as Box5, Text as Text5 } from "ink";
418
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
419
+ var BackableInput = ({ label, hint, onBack, children, error }) => /* @__PURE__ */ jsx5(StepShell, { title: label, hint, onBack, children: /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, children: [
363
420
  children(true),
364
- error && /* @__PURE__ */ jsx4(Text4, { color: "red", children: error })
421
+ error && /* @__PURE__ */ jsx5(Text5, { color: "red", children: error })
365
422
  ] }) });
366
423
 
367
424
  // src/components/NamePrompt.tsx
368
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
425
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
369
426
  var NamePrompt = ({ initialValue = "", onSubmit, onBack }) => {
370
427
  const [value, setValue] = useState2(initialValue);
371
428
  const [error, setError] = useState2();
@@ -378,17 +435,17 @@ var NamePrompt = ({ initialValue = "", onSubmit, onBack }) => {
378
435
  setError(void 0);
379
436
  onSubmit(trimmed);
380
437
  };
381
- return /* @__PURE__ */ jsx5(BackableInput, { label: "What is your Extension name?", hint: "Press Enter to confirm", onBack, error, children: (isFocused) => /* @__PURE__ */ jsxs5(Box5, { children: [
382
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "> " }),
383
- /* @__PURE__ */ jsx5(TextInput2, { value, onChange: setValue, onSubmit: handleSubmit, focus: isFocused })
438
+ return /* @__PURE__ */ jsx6(BackableInput, { label: "What is your Extension name?", hint: "Press Enter to confirm", onBack, error, children: (isFocused) => /* @__PURE__ */ jsxs6(Box6, { children: [
439
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "> " }),
440
+ /* @__PURE__ */ jsx6(TextInput2, { value, onChange: setValue, onSubmit: handleSubmit, focus: isFocused })
384
441
  ] }) });
385
442
  };
386
443
 
387
444
  // src/components/SettingsPrompt.tsx
388
- import { Box as Box6, Text as Text6, useFocus as useFocus2, useFocusManager as useFocusManager2, useInput as useInput3 } from "ink";
445
+ import { Box as Box7, Text as Text7, useFocus as useFocus2, useFocusManager as useFocusManager2, useInput as useInput3 } from "ink";
389
446
  import TextInput3 from "ink-text-input";
390
447
  import { useState as useState3 } from "react";
391
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
448
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
392
449
  var DEFAULT_EXTENSION_PORT = 6543;
393
450
  var DEFAULT_PREVIEW_PORT = DEFAULT_EXTENSION_PORT + 1;
394
451
  var FieldRow = ({ label, value, onChange, onSubmit, onConfirm, placeholder, autoFocus, isFirst, isLast }) => {
@@ -399,11 +456,11 @@ var FieldRow = ({ label, value, onChange, onSubmit, onConfirm, placeholder, auto
399
456
  if (key.downArrow && !isLast) focusNext();
400
457
  if (key.upArrow && !isFirst) focusPrevious();
401
458
  });
402
- return /* @__PURE__ */ jsxs6(Box6, { gap: 2, children: [
403
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: label }),
404
- isFocused ? /* @__PURE__ */ jsxs6(Box6, { children: [
405
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u2192 " }),
406
- /* @__PURE__ */ jsx6(
459
+ return /* @__PURE__ */ jsxs7(Box7, { gap: 2, children: [
460
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: label }),
461
+ isFocused ? /* @__PURE__ */ jsxs7(Box7, { children: [
462
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "\u2192 " }),
463
+ /* @__PURE__ */ jsx7(
407
464
  TextInput3,
408
465
  {
409
466
  value,
@@ -416,7 +473,7 @@ var FieldRow = ({ label, value, onChange, onSubmit, onConfirm, placeholder, auto
416
473
  focus: isFocused
417
474
  }
418
475
  )
419
- ] }) : /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: value })
476
+ ] }) : /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: value })
420
477
  ] });
421
478
  };
422
479
  var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
@@ -453,14 +510,14 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
453
510
  setOutputDir(trimmed);
454
511
  return [extensionPort, previewPort, trimmed];
455
512
  };
456
- return /* @__PURE__ */ jsx6(
513
+ return /* @__PURE__ */ jsx7(
457
514
  StepShell,
458
515
  {
459
516
  title: "Project settings",
460
517
  hint: "\u2191\u2193 or Tab to move between fields, Enter to confirm",
461
518
  onBack,
462
- children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
463
- /* @__PURE__ */ jsx6(
519
+ children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", gap: 1, children: [
520
+ /* @__PURE__ */ jsx7(
464
521
  FieldRow,
465
522
  {
466
523
  label: "Extension port ",
@@ -473,7 +530,7 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
473
530
  isFirst: true
474
531
  }
475
532
  ),
476
- /* @__PURE__ */ jsx6(
533
+ /* @__PURE__ */ jsx7(
477
534
  FieldRow,
478
535
  {
479
536
  label: "Preview port ",
@@ -484,7 +541,7 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
484
541
  placeholder: String(DEFAULT_PREVIEW_PORT)
485
542
  }
486
543
  ),
487
- /* @__PURE__ */ jsx6(
544
+ /* @__PURE__ */ jsx7(
488
545
  FieldRow,
489
546
  {
490
547
  label: "Output directory",
@@ -501,7 +558,7 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
501
558
  };
502
559
 
503
560
  // src/components/ManifestReviewPrompt.tsx
504
- import { Box as Box7, Text as Text7, useInput as useInput4 } from "ink";
561
+ import { Box as Box8, Text as Text8, useInput as useInput4 } from "ink";
505
562
  import { useState as useState4 } from "react";
506
563
 
507
564
  // src/lib/manifest-diff.ts
@@ -520,7 +577,7 @@ var diffManifestValues = (localValues, registryValues) => {
520
577
  };
521
578
 
522
579
  // src/components/ManifestReviewPrompt.tsx
523
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
580
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
524
581
  var statusLabel = (status) => {
525
582
  switch (status) {
526
583
  case "new":
@@ -601,33 +658,33 @@ var ManifestReviewPrompt = ({
601
658
  });
602
659
  const renderItem = (item, index) => {
603
660
  const isCursor = index === cursor;
604
- return /* @__PURE__ */ jsxs7(Box7, { gap: 1, children: [
605
- /* @__PURE__ */ jsx7(Text7, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
606
- /* @__PURE__ */ jsx7(Text7, { color: item.enabled ? "green" : "gray", children: item.enabled ? "\u25C9" : "\u25CB" }),
607
- /* @__PURE__ */ jsx7(Text7, { bold: isCursor, children: item.value }),
608
- statusLabel(item.status) && /* @__PURE__ */ jsx7(Text7, { color: statusColor(item.status), dimColor: true, children: statusLabel(item.status) })
661
+ return /* @__PURE__ */ jsxs8(Box8, { gap: 1, children: [
662
+ /* @__PURE__ */ jsx8(Text8, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
663
+ /* @__PURE__ */ jsx8(Text8, { color: item.enabled ? "green" : "gray", children: item.enabled ? "\u25C9" : "\u25CB" }),
664
+ /* @__PURE__ */ jsx8(Text8, { bold: isCursor, children: item.value }),
665
+ statusLabel(item.status) && /* @__PURE__ */ jsx8(Text8, { color: statusColor(item.status), dimColor: true, children: statusLabel(item.status) })
609
666
  ] }, item.value);
610
667
  };
611
- return /* @__PURE__ */ jsx7(
668
+ return /* @__PURE__ */ jsx8(
612
669
  StepShell,
613
670
  {
614
671
  title: "Review Manifest changes",
615
672
  hint: "Tab/shift-tab to jump section, \u2191/\u2193 navigate. Enter to submit",
616
673
  onBack,
617
- children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", gap: 1, children: [
618
- !localManifest && /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: "No local manifest.json found \u2014 showing registry values only" }),
619
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
620
- /* @__PURE__ */ jsx7(Text7, { dimColor: !cursorInPerms, bold: cursorInPerms, children: "Permissions".padEnd(14) }),
621
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingLeft: 2, children: [
622
- permItems.length > 0 ? permItems.map((item, i) => renderItem(item, i)) : /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " (none)" }),
623
- cursorInPerms && /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " (space to toggle)" })
674
+ children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
675
+ !localManifest && /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "No local manifest.json found \u2014 showing registry values only" }),
676
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
677
+ /* @__PURE__ */ jsx8(Text8, { dimColor: !cursorInPerms, bold: cursorInPerms, children: "Permissions".padEnd(14) }),
678
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingLeft: 2, children: [
679
+ permItems.length > 0 ? permItems.map((item, i) => renderItem(item, i)) : /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " (none)" }),
680
+ cursorInPerms && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " (space to toggle)" })
624
681
  ] })
625
682
  ] }),
626
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
627
- /* @__PURE__ */ jsx7(Text7, { dimColor: !cursorInDomains, bold: cursorInDomains, children: "Allowed Domains".padEnd(14) }),
628
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingLeft: 2, children: [
629
- domainItems.length > 0 ? domainItems.map((item, i) => renderItem(item, i + permItems.length)) : /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " (none)" }),
630
- cursorInDomains && /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " (space to toggle)" })
683
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
684
+ /* @__PURE__ */ jsx8(Text8, { dimColor: !cursorInDomains, bold: cursorInDomains, children: "Allowed Domains".padEnd(14) }),
685
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingLeft: 2, children: [
686
+ domainItems.length > 0 ? domainItems.map((item, i) => renderItem(item, i + permItems.length)) : /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " (none)" }),
687
+ cursorInDomains && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " (space to toggle)" })
631
688
  ] })
632
689
  ] })
633
690
  ] })
@@ -636,10 +693,10 @@ var ManifestReviewPrompt = ({
636
693
  };
637
694
 
638
695
  // src/components/UpdateSettingsPrompt.tsx
639
- import { Box as Box8, Text as Text8, useFocus as useFocus3, useFocusManager as useFocusManager3, useInput as useInput5 } from "ink";
696
+ import { Box as Box9, Text as Text9, useFocus as useFocus3, useFocusManager as useFocusManager3, useInput as useInput5 } from "ink";
640
697
  import TextInput4 from "ink-text-input";
641
698
  import { useState as useState5 } from "react";
642
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
699
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
643
700
  var FieldRow2 = ({ label, value, onChange, placeholder, autoFocus, isFirst, isLast, onSubmitAll }) => {
644
701
  const { isFocused } = useFocus3({ autoFocus });
645
702
  const { focusNext, focusPrevious } = useFocusManager3();
@@ -657,9 +714,9 @@ var FieldRow2 = ({ label, value, onChange, placeholder, autoFocus, isFirst, isLa
657
714
  onSubmitAll();
658
715
  }
659
716
  });
660
- return /* @__PURE__ */ jsxs8(Box8, { gap: 2, children: [
661
- /* @__PURE__ */ jsx8(Text8, { dimColor: !isFocused, bold: isFocused, children: label.padEnd(14) }),
662
- isFocused ? /* @__PURE__ */ jsx8(TextInput4, { value, onChange, placeholder }) : /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: value || placeholder || "" })
717
+ return /* @__PURE__ */ jsxs9(Box9, { gap: 2, children: [
718
+ /* @__PURE__ */ jsx9(Text9, { dimColor: !isFocused, bold: isFocused, children: label.padEnd(14) }),
719
+ isFocused ? /* @__PURE__ */ jsx9(TextInput4, { value, onChange, placeholder }) : /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: value || placeholder || "" })
663
720
  ] });
664
721
  };
665
722
  var TargetToggleRow = ({ targets, availableTargets, onToggle, autoFocus, isLast, onSubmitAll }) => {
@@ -692,19 +749,19 @@ var TargetToggleRow = ({ targets, availableTargets, onToggle, autoFocus, isLast,
692
749
  onSubmitAll();
693
750
  }
694
751
  });
695
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
696
- /* @__PURE__ */ jsx8(Text8, { dimColor: !isFocused, bold: isFocused, children: "Targets".padEnd(14) }),
697
- /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingLeft: 2, children: [
752
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
753
+ /* @__PURE__ */ jsx9(Text9, { dimColor: !isFocused, bold: isFocused, children: "Targets".padEnd(14) }),
754
+ /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingLeft: 2, children: [
698
755
  availableTargets.map((t, i) => {
699
756
  const selected = targets.includes(t);
700
757
  const isCursor = isFocused && i === cursor;
701
- return /* @__PURE__ */ jsxs8(Box8, { gap: 1, children: [
702
- /* @__PURE__ */ jsx8(Text8, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
703
- /* @__PURE__ */ jsx8(Text8, { color: selected ? "green" : "gray", children: selected ? "\u25C9" : "\u25CB" }),
704
- /* @__PURE__ */ jsx8(Text8, { bold: isCursor, children: t })
758
+ return /* @__PURE__ */ jsxs9(Box9, { gap: 1, children: [
759
+ /* @__PURE__ */ jsx9(Text9, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
760
+ /* @__PURE__ */ jsx9(Text9, { color: selected ? "green" : "gray", children: selected ? "\u25C9" : "\u25CB" }),
761
+ /* @__PURE__ */ jsx9(Text9, { bold: isCursor, children: t })
705
762
  ] }, t);
706
763
  }),
707
- isFocused && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " (space to toggle)" })
764
+ isFocused && /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: " (space to toggle)" })
708
765
  ] })
709
766
  ] });
710
767
  };
@@ -729,10 +786,10 @@ var EnabledToggleRow = ({ enabled, onToggle, autoFocus, isLast, onSubmitAll }) =
729
786
  onSubmitAll();
730
787
  }
731
788
  });
732
- return /* @__PURE__ */ jsxs8(Box8, { gap: 2, children: [
733
- /* @__PURE__ */ jsx8(Text8, { dimColor: !isFocused, bold: isFocused, children: "Enabled".padEnd(14) }),
734
- /* @__PURE__ */ jsx8(Text8, { color: enabled ? "green" : "red", bold: isFocused, children: enabled ? "Yes" : "No" }),
735
- isFocused && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "(space/arrows to toggle)" })
789
+ return /* @__PURE__ */ jsxs9(Box9, { gap: 2, children: [
790
+ /* @__PURE__ */ jsx9(Text9, { dimColor: !isFocused, bold: isFocused, children: "Enabled".padEnd(14) }),
791
+ /* @__PURE__ */ jsx9(Text9, { color: enabled ? "green" : "red", bold: isFocused, children: enabled ? "Yes" : "No" }),
792
+ isFocused && /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "(space/arrows to toggle)" })
736
793
  ] });
737
794
  };
738
795
  var ForceMajorToggleRow = ({ forceMajor, onToggle, autoFocus, isLast, onSubmitAll }) => {
@@ -756,10 +813,10 @@ var ForceMajorToggleRow = ({ forceMajor, onToggle, autoFocus, isLast, onSubmitAl
756
813
  onSubmitAll();
757
814
  }
758
815
  });
759
- return /* @__PURE__ */ jsxs8(Box8, { gap: 2, children: [
760
- /* @__PURE__ */ jsx8(Text8, { dimColor: !isFocused, bold: isFocused, children: "Force major".padEnd(14) }),
761
- /* @__PURE__ */ jsx8(Text8, { color: forceMajor ? "yellow" : "gray", bold: isFocused, children: forceMajor ? "Yes" : "No" }),
762
- isFocused && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "(space/arrows to toggle)" })
816
+ return /* @__PURE__ */ jsxs9(Box9, { gap: 2, children: [
817
+ /* @__PURE__ */ jsx9(Text9, { dimColor: !isFocused, bold: isFocused, children: "Force major".padEnd(14) }),
818
+ /* @__PURE__ */ jsx9(Text9, { color: forceMajor ? "yellow" : "gray", bold: isFocused, children: forceMajor ? "Yes" : "No" }),
819
+ isFocused && /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "(space/arrows to toggle)" })
763
820
  ] });
764
821
  };
765
822
  var UpdateSettingsPrompt = ({
@@ -767,6 +824,7 @@ var UpdateSettingsPrompt = ({
767
824
  targets: initialTargets,
768
825
  availableTargets,
769
826
  bundleUrl: initialBundleUrl,
827
+ allowedDomains: initialAllowedDomains,
770
828
  enabled: initialEnabled,
771
829
  onSubmit,
772
830
  onBack
@@ -774,6 +832,7 @@ var UpdateSettingsPrompt = ({
774
832
  const [nameValue, setNameValue] = useState5(initialName);
775
833
  const [targetsValue, setTargetsValue] = useState5(initialTargets);
776
834
  const [bundleUrlValue, setBundleUrlValue] = useState5(initialBundleUrl);
835
+ const [allowedDomainsValue, setAllowedDomainsValue] = useState5(initialAllowedDomains.join(", "));
777
836
  const [enabledValue, setEnabledValue] = useState5(initialEnabled);
778
837
  const [forceMajorValue, setForceMajorValue] = useState5(false);
779
838
  const handleToggleTarget = (target) => {
@@ -785,18 +844,19 @@ var UpdateSettingsPrompt = ({
785
844
  name: nameValue,
786
845
  targets: targetsValue,
787
846
  bundleUrl: bundleUrlValue,
847
+ allowedDomains: allowedDomainsValue.split(",").map((d) => d.trim()).filter(Boolean),
788
848
  enabled: enabledValue,
789
849
  forceMajor: forceMajorValue
790
850
  });
791
851
  };
792
- return /* @__PURE__ */ jsx8(
852
+ return /* @__PURE__ */ jsx9(
793
853
  StepShell,
794
854
  {
795
855
  title: "Update Extension settings",
796
856
  hint: "Tab/shift-tab to jump section, \u2191/\u2193 navigate. Enter to submit",
797
857
  onBack,
798
- children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
799
- /* @__PURE__ */ jsx8(
858
+ children: /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", gap: 1, children: [
859
+ /* @__PURE__ */ jsx9(
800
860
  FieldRow2,
801
861
  {
802
862
  label: "Name",
@@ -808,7 +868,7 @@ var UpdateSettingsPrompt = ({
808
868
  onSubmitAll: handleSubmitAll
809
869
  }
810
870
  ),
811
- /* @__PURE__ */ jsx8(
871
+ /* @__PURE__ */ jsx9(
812
872
  TargetToggleRow,
813
873
  {
814
874
  targets: targetsValue,
@@ -817,7 +877,7 @@ var UpdateSettingsPrompt = ({
817
877
  onSubmitAll: handleSubmitAll
818
878
  }
819
879
  ),
820
- /* @__PURE__ */ jsx8(
880
+ /* @__PURE__ */ jsx9(
821
881
  FieldRow2,
822
882
  {
823
883
  label: "Bundle URL",
@@ -827,7 +887,17 @@ var UpdateSettingsPrompt = ({
827
887
  onSubmitAll: handleSubmitAll
828
888
  }
829
889
  ),
830
- /* @__PURE__ */ jsx8(
890
+ /* @__PURE__ */ jsx9(
891
+ FieldRow2,
892
+ {
893
+ label: "Allowed Domains",
894
+ value: allowedDomainsValue,
895
+ onChange: setAllowedDomainsValue,
896
+ placeholder: "api.example.com, cdn.example.com",
897
+ onSubmitAll: handleSubmitAll
898
+ }
899
+ ),
900
+ /* @__PURE__ */ jsx9(
831
901
  EnabledToggleRow,
832
902
  {
833
903
  enabled: enabledValue,
@@ -835,7 +905,7 @@ var UpdateSettingsPrompt = ({
835
905
  onSubmitAll: handleSubmitAll
836
906
  }
837
907
  ),
838
- /* @__PURE__ */ jsx8(
908
+ /* @__PURE__ */ jsx9(
839
909
  ForceMajorToggleRow,
840
910
  {
841
911
  forceMajor: forceMajorValue,
@@ -850,33 +920,33 @@ var UpdateSettingsPrompt = ({
850
920
  };
851
921
 
852
922
  // src/components/ScaffoldProgress.tsx
853
- import { Box as Box9, Text as Text9 } from "ink";
923
+ import { Box as Box10, Text as Text10 } from "ink";
854
924
  import Spinner from "ink-spinner";
855
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
925
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
856
926
  var stepIcon = (status) => {
857
927
  switch (status) {
858
928
  case "running":
859
- return /* @__PURE__ */ jsx9(Spinner, { type: "dots" });
929
+ return /* @__PURE__ */ jsx10(Spinner, { type: "dots" });
860
930
  case "done":
861
- return /* @__PURE__ */ jsx9(Text9, { color: "green", children: "\u2714" });
931
+ return /* @__PURE__ */ jsx10(Text10, { color: "green", children: "\u2714" });
862
932
  case "error":
863
- return /* @__PURE__ */ jsx9(Text9, { color: "red", children: "\u2716" });
933
+ return /* @__PURE__ */ jsx10(Text10, { color: "red", children: "\u2716" });
864
934
  default:
865
- return /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u25CB" });
935
+ return /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\u25CB" });
866
936
  }
867
937
  };
868
- var ScaffoldProgress = ({ steps }) => /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", gap: 1, children: [
869
- /* @__PURE__ */ jsx9(Text9, { bold: true, children: "Scaffolding your Extension\u2026" }),
870
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children: steps.map((step) => /* @__PURE__ */ jsxs9(Box9, { gap: 2, children: [
938
+ var ScaffoldProgress = ({ steps }) => /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", gap: 1, children: [
939
+ /* @__PURE__ */ jsx10(Text10, { bold: true, children: "Scaffolding your Extension\u2026" }),
940
+ /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: steps.map((step) => /* @__PURE__ */ jsxs10(Box10, { gap: 2, children: [
871
941
  stepIcon(step.status),
872
- /* @__PURE__ */ jsx9(Text9, { dimColor: step.status === "pending", color: step.status === "running" ? "cyan" : void 0, children: step.label })
942
+ /* @__PURE__ */ jsx10(Text10, { dimColor: step.status === "pending", color: step.status === "running" ? "cyan" : void 0, children: step.label })
873
943
  ] }, step.label)) })
874
944
  ] });
875
945
 
876
946
  // src/components/TargetSelect.tsx
877
- import { Box as Box10, Text as Text10, useInput as useInput6 } from "ink";
947
+ import { Box as Box11, Text as Text11, useInput as useInput6 } from "ink";
878
948
  import { useState as useState6 } from "react";
879
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
949
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
880
950
  var TARGET_DESCRIPTIONS = {
881
951
  "slot.header": "Renders content in the panel header area",
882
952
  "slot.content": "Renders the main panel body (includes store + navigation state)",
@@ -920,35 +990,35 @@ var TargetSelect = ({ availableTargets, preSelected, onSubmit, onBack }) => {
920
990
  onSubmit([...selected]);
921
991
  }
922
992
  });
923
- return /* @__PURE__ */ jsxs10(
993
+ return /* @__PURE__ */ jsxs11(
924
994
  StepShell,
925
995
  {
926
996
  title: "Select Surface targets/slots",
927
997
  hint: "Space to toggle, Enter to confirm",
928
998
  onBack,
929
999
  children: [
930
- /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", gap: 1, children: availableTargets.map((target, i) => {
1000
+ /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", gap: 1, children: availableTargets.map((target, i) => {
931
1001
  const isSelected = selected.has(target);
932
1002
  const isCursor = i === cursor;
933
- return /* @__PURE__ */ jsxs10(Box10, { gap: 1, children: [
934
- /* @__PURE__ */ jsx10(Text10, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
935
- /* @__PURE__ */ jsx10(Text10, { color: isSelected ? "green" : void 0, children: isSelected ? "\u25C9" : "\u25CB" }),
936
- /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
937
- /* @__PURE__ */ jsx10(Text10, { bold: isSelected, children: target }),
938
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: TARGET_DESCRIPTIONS[target] ?? target })
1003
+ return /* @__PURE__ */ jsxs11(Box11, { gap: 1, children: [
1004
+ /* @__PURE__ */ jsx11(Text11, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
1005
+ /* @__PURE__ */ jsx11(Text11, { color: isSelected ? "green" : void 0, children: isSelected ? "\u25C9" : "\u25CB" }),
1006
+ /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
1007
+ /* @__PURE__ */ jsx11(Text11, { bold: isSelected, children: target }),
1008
+ /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: TARGET_DESCRIPTIONS[target] ?? target })
939
1009
  ] })
940
1010
  ] }, target);
941
1011
  }) }),
942
- error && /* @__PURE__ */ jsx10(Text10, { color: "red", children: error })
1012
+ error && /* @__PURE__ */ jsx11(Text11, { color: "red", children: error })
943
1013
  ]
944
1014
  }
945
1015
  );
946
1016
  };
947
1017
 
948
1018
  // src/components/TemplateSelect.tsx
949
- import { Box as Box11, Text as Text11, useInput as useInput7 } from "ink";
1019
+ import { Box as Box12, Text as Text12, useInput as useInput7 } from "ink";
950
1020
  import { useState as useState7 } from "react";
951
- import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1021
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
952
1022
  var FLAVORS = ["minimal", "starter", "kitchen-sink"];
953
1023
  var TemplateSelect = ({ onSubmit, onBack }) => {
954
1024
  const [cursor, setCursor] = useState7(1);
@@ -965,21 +1035,21 @@ var TemplateSelect = ({ onSubmit, onBack }) => {
965
1035
  onSubmit(FLAVORS[cursor]);
966
1036
  }
967
1037
  });
968
- return /* @__PURE__ */ jsx11(
1038
+ return /* @__PURE__ */ jsx12(
969
1039
  StepShell,
970
1040
  {
971
1041
  title: "Choose a template",
972
1042
  hint: "\u2191\u2193 to navigate, Enter to select",
973
1043
  onBack,
974
- children: /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", gap: 1, children: FLAVORS.map((flavor, i) => {
1044
+ children: /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", gap: 1, children: FLAVORS.map((flavor, i) => {
975
1045
  const meta = TEMPLATE_FLAVOR_META[flavor];
976
1046
  const isCursor = i === cursor;
977
- return /* @__PURE__ */ jsxs11(Box11, { gap: 1, children: [
978
- /* @__PURE__ */ jsx11(Text11, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
979
- /* @__PURE__ */ jsx11(Text11, { color: isCursor ? "green" : void 0, children: isCursor ? "\u25C9" : "\u25CB" }),
980
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
981
- /* @__PURE__ */ jsx11(Text11, { bold: isCursor, children: meta.label }),
982
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: meta.description })
1047
+ return /* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
1048
+ /* @__PURE__ */ jsx12(Text12, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
1049
+ /* @__PURE__ */ jsx12(Text12, { color: isCursor ? "green" : void 0, children: isCursor ? "\u25C9" : "\u25CB" }),
1050
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
1051
+ /* @__PURE__ */ jsx12(Text12, { bold: isCursor, children: meta.label }),
1052
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: meta.description })
983
1053
  ] })
984
1054
  ] }, flavor);
985
1055
  }) })
@@ -994,7 +1064,9 @@ import { useEffect as useEffect2, useState as useState8 } from "react";
994
1064
 
995
1065
  // src/lib/api.ts
996
1066
  var DEFAULT_ADMIN_API_URL = "https://api-use1.stackablelabs.io/admin";
1067
+ var DEFAULT_PUBLIC_API_URL = "https://api.stackablelabs.io/app-extension/v1";
997
1068
  var getAdminApiBaseUrl = () => process.env.ADMIN_API_BASE_URL ?? DEFAULT_ADMIN_API_URL;
1069
+ var getPublicApiBaseUrl = () => process.env.APP_EXTENSION_API_BASE_URL ?? DEFAULT_PUBLIC_API_URL;
998
1070
  var CLI_CLIENT_NAME = "@stackable-labs/cli-app-extension";
999
1071
  var authHeaders = (token) => ({
1000
1072
  authorization: `Bearer ${token}`,
@@ -1053,6 +1125,26 @@ var fetchExtensions = async (token, appId) => {
1053
1125
  ])
1054
1126
  );
1055
1127
  };
1128
+ var resolveAppForExtension = async (token, extensionId) => {
1129
+ const apps = await fetchApps(token);
1130
+ const publicBaseUrl = getPublicApiBaseUrl();
1131
+ for (const app of apps) {
1132
+ try {
1133
+ const res = await fetch(`${publicBaseUrl}/extensions/${app.id}`, {
1134
+ headers: authHeaders(token)
1135
+ });
1136
+ if (!res.ok) continue;
1137
+ const extensions = await res.json();
1138
+ const ext = extensions[extensionId];
1139
+ if (ext) {
1140
+ return { app, extension: ext };
1141
+ }
1142
+ } catch {
1143
+ continue;
1144
+ }
1145
+ }
1146
+ return null;
1147
+ };
1056
1148
  var fetchProject = async (token, appId, projectId) => {
1057
1149
  const baseUrl = getAdminApiBaseUrl();
1058
1150
  const res = await fetch(`${baseUrl}/app-extension/${appId}/projects/${projectId}`, {
@@ -1102,62 +1194,6 @@ var updateExtension = async (token, appId, extensionId, payload) => {
1102
1194
  }
1103
1195
  };
1104
1196
 
1105
- // src/components/Banner.tsx
1106
- import { Box as Box12, Text as Text12 } from "ink";
1107
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1108
- var WORDMARK = [
1109
- " _ _ _ _ ",
1110
- " ___| |_ __ _ ___| | ____ _| |__ | | ___",
1111
- "/ __| __/ _` |/ __| |/ / _` | '_ \\| |/ _ \\",
1112
- "\\__ \\ || (_| | (__| < (_| | |_) | | __/",
1113
- "|___/\\__\\__,_|\\___|_|\\_\\__,_|_.__/|_|\\___|"
1114
- ];
1115
- var COLORS = [
1116
- [232, 218, 234],
1117
- // Lit Lilac #E8DAEA
1118
- [197, 96, 255],
1119
- // Poppy Purple #C560FF
1120
- [0, 174, 247],
1121
- // Bluetooth Blue #00AEF7
1122
- [70, 224, 177],
1123
- // Tropical Teal #46E0B1
1124
- [252, 248, 161]
1125
- // Not Mellow Yellow #FCF8A1
1126
- ];
1127
- var lerp = (a, b, t) => {
1128
- const r = Math.round(a[0] + (b[0] - a[0]) * t);
1129
- const g = Math.round(a[1] + (b[1] - a[1]) * t);
1130
- const bl = Math.round(a[2] + (b[2] - a[2]) * t);
1131
- return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${bl.toString(16).padStart(2, "0")}`;
1132
- };
1133
- var gradientColor = (row, col, rows, cols) => {
1134
- const t = (row / (rows - 1) + col / (cols - 1)) / 2;
1135
- const idx = t * (COLORS.length - 1);
1136
- const lo = Math.floor(idx);
1137
- const hi = Math.min(lo + 1, COLORS.length - 1);
1138
- return lerp(COLORS[lo], COLORS[hi], idx - lo);
1139
- };
1140
- var Banner = ({ userId, orgId } = {}) => {
1141
- const termWidth = process.stdout.columns ?? 80;
1142
- const maxLen = Math.max(...WORDMARK.map((l) => l.length));
1143
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
1144
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "\u2500".repeat(termWidth) }),
1145
- /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
1146
- WORDMARK.map((line, row) => /* @__PURE__ */ jsx12(Box12, { children: line.split("").map((ch, col) => /* @__PURE__ */ jsx12(Text12, { bold: true, color: ch === " " ? void 0 : gradientColor(row, col, WORDMARK.length, maxLen), children: ch }, col)) }, row)),
1147
- userId && orgId && /* @__PURE__ */ jsxs12(Box12, { gap: 2, marginTop: 1, children: [
1148
- /* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
1149
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "User:" }),
1150
- /* @__PURE__ */ jsx12(Text12, { color: "cyan", children: userId })
1151
- ] }),
1152
- /* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
1153
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Org:" }),
1154
- /* @__PURE__ */ jsx12(Text12, { color: "cyan", children: orgId })
1155
- ] })
1156
- ] })
1157
- ] })
1158
- ] });
1159
- };
1160
-
1161
1197
  // src/components/AppSelect.tsx
1162
1198
  import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1163
1199
  var AppSelect = ({ token, userId, orgId, onSubmit }) => {
@@ -1288,6 +1324,90 @@ var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
1288
1324
  );
1289
1325
  };
1290
1326
 
1327
+ // src/hooks/useWizardSteps.ts
1328
+ import { useCallback, useMemo, useState as useState10 } from "react";
1329
+ var STEPS = {
1330
+ ["create" /* CREATE */]: ["app", "name", "template", "targets", "settings", "confirm"],
1331
+ ["scaffold" /* SCAFFOLD */]: ["app", "extensionSelect", "template", "confirmTargets", "settings", "confirm"],
1332
+ ["update" /* UPDATE */]: ["app", "extensionSelect", "updateSettings", "manifestReview", "confirm"],
1333
+ ["dev" /* DEV */]: []
1334
+ };
1335
+ var computeActiveSteps = (conditions) => {
1336
+ const { command, initialName, initialExtensionId, templateFlavor, studioProject, options } = conditions;
1337
+ const base = STEPS[command];
1338
+ const skipped = /* @__PURE__ */ new Set();
1339
+ if (command === "create" /* CREATE */ && initialName) skipped.add("name");
1340
+ if (command === "create" /* CREATE */ && options?.template) skipped.add("template");
1341
+ if (command === "create" /* CREATE */ && TEMPLATE_FLAVOR_META[templateFlavor].skipTargetStep) {
1342
+ skipped.add("targets");
1343
+ }
1344
+ if (options?.extensionPort || options?.previewPort) skipped.add("settings");
1345
+ if (options?.appId) skipped.add("app");
1346
+ if (initialExtensionId && (command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */)) {
1347
+ skipped.add("app");
1348
+ skipped.add("extensionSelect");
1349
+ }
1350
+ if (studioProject) {
1351
+ if (command === "create" /* CREATE */) {
1352
+ skipped.add("template");
1353
+ }
1354
+ if (command === "scaffold" /* SCAFFOLD */) {
1355
+ skipped.add("template");
1356
+ if (studioProject.extensionId) {
1357
+ skipped.add("extensionSelect");
1358
+ }
1359
+ }
1360
+ }
1361
+ if (command === "scaffold" /* SCAFFOLD */ && (options?.template || conditions.hasLocalProject)) {
1362
+ skipped.add("template");
1363
+ }
1364
+ return base.filter((s) => !skipped.has(s));
1365
+ };
1366
+ var useWizardSteps = (opts) => {
1367
+ const [step, setStep] = useState10("app");
1368
+ const activeSteps = useMemo(
1369
+ () => computeActiveSteps(opts),
1370
+ [
1371
+ opts.command,
1372
+ opts.initialName,
1373
+ opts.initialExtensionId,
1374
+ opts.templateFlavor,
1375
+ opts.studioProject,
1376
+ opts.hasLocalProject,
1377
+ opts.options?.template,
1378
+ opts.options?.extensionPort,
1379
+ opts.options?.previewPort,
1380
+ opts.options?.appId
1381
+ ]
1382
+ );
1383
+ const goForward = useCallback(
1384
+ (overrides) => {
1385
+ setStep((prev) => {
1386
+ const steps = computeActiveSteps({ ...opts, ...overrides });
1387
+ const idx = steps.indexOf(prev);
1388
+ if (idx >= 0 && idx < steps.length - 1) {
1389
+ return steps[idx + 1];
1390
+ }
1391
+ if (idx === -1 && steps.length > 0) {
1392
+ return steps[0];
1393
+ }
1394
+ return prev;
1395
+ });
1396
+ },
1397
+ [opts]
1398
+ );
1399
+ const goBack = useCallback(() => {
1400
+ setStep((prev) => {
1401
+ const idx = activeSteps.indexOf(prev);
1402
+ return idx > 0 ? activeSteps[idx - 1] : prev;
1403
+ });
1404
+ }, [activeSteps]);
1405
+ const goTo = useCallback((target) => {
1406
+ setStep(target);
1407
+ }, []);
1408
+ return { step, activeSteps, goForward, goBack, goTo };
1409
+ };
1410
+
1291
1411
  // src/lib/postScaffold.ts
1292
1412
  import { execFile } from "child_process";
1293
1413
  import { promisify } from "util";
@@ -1769,13 +1889,6 @@ var scaffold = async (options) => {
1769
1889
 
1770
1890
  // src/App.tsx
1771
1891
  import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
1772
- var STEPS = {
1773
- ["create" /* CREATE */]: ["app", "name", "template", "targets", "settings", "confirm"],
1774
- ["scaffold" /* SCAFFOLD */]: ["app", "extensionSelect", "confirmTargets", "settings", "confirm"],
1775
- ["update" /* UPDATE */]: ["app", "extensionSelect", "updateSettings", "manifestReview", "confirm"],
1776
- ["dev" /* DEV */]: []
1777
- // Dev command has no wizard steps
1778
- };
1779
1892
  var PROGRESS_STEPS = {
1780
1893
  ["create" /* CREATE */]: [
1781
1894
  { label: "Registering Extension", status: "pending" },
@@ -1813,115 +1926,72 @@ var deriveRegistryPermissions = (targets) => {
1813
1926
  };
1814
1927
  var App = ({ command, token, userId, orgId, initialName, initialExtensionId, options }) => {
1815
1928
  const { exit } = useApp();
1816
- const [step, setStep] = useState10(() => {
1817
- if (options?.appId) {
1818
- const base = STEPS[command];
1819
- return base.find((s) => s !== "app") ?? "app";
1820
- }
1821
- return "app";
1822
- });
1823
- const [name, setName] = useState10(initialName ?? options?.name ?? "");
1824
- const [extensionId, setExtensionId] = useState10(initialExtensionId ?? "");
1825
- const [extensionVersion, setExtensionVersion] = useState10("");
1826
- const [bundleUrl, setBundleUrl] = useState10(options?.bundleUrl ?? "");
1827
- const [enabled, setEnabled] = useState10(
1929
+ const [name, setName] = useState11(initialName ?? options?.name ?? "");
1930
+ const [extensionId, setExtensionId] = useState11(initialExtensionId ?? "");
1931
+ const [extensionVersion, setExtensionVersion] = useState11("");
1932
+ const [bundleUrl, setBundleUrl] = useState11(options?.bundleUrl ?? "");
1933
+ const [enabled, setEnabled] = useState11(
1828
1934
  options?.enabled !== void 0 ? options.enabled !== "false" : true
1829
1935
  );
1830
- const [versionOverride, setVersionOverride] = useState10(void 0);
1831
- const [forceMajor, setForceMajor] = useState10(false);
1832
- const [initialExtension, setInitialExtension] = useState10(null);
1833
- const [templateFlavor, setTemplateFlavor] = useState10(
1936
+ const [versionOverride, setVersionOverride] = useState11(void 0);
1937
+ const [forceMajor, setForceMajor] = useState11(false);
1938
+ const [initialExtension, setInitialExtension] = useState11(null);
1939
+ const [templateFlavor, setTemplateFlavor] = useState11(
1834
1940
  options?.template ?? "starter"
1835
1941
  );
1836
- const [targets, setTargets] = useState10(
1942
+ const [targets, setTargets] = useState11(
1837
1943
  options?.targets ? options.targets.split(",").map((t) => t.trim()) : []
1838
1944
  );
1839
- const [selectedApp, setSelectedApp] = useState10(null);
1840
- const [extensionPort, setExtensionPort] = useState10(
1945
+ const [selectedApp, setSelectedApp] = useState11(null);
1946
+ const [extensionPort, setExtensionPort] = useState11(
1841
1947
  options?.extensionPort ? parseInt(options.extensionPort, 10) : 6543
1842
1948
  );
1843
- const [previewPort, setPreviewPort] = useState10(
1949
+ const [previewPort, setPreviewPort] = useState11(
1844
1950
  options?.previewPort ? parseInt(options.previewPort, 10) : 6544
1845
1951
  );
1846
- const [registryManifest, setRegistryManifest] = useState10(null);
1847
- const [localManifest, setLocalManifest] = useState10(null);
1848
- const [confirmedPermissions, setConfirmedPermissions] = useState10([]);
1849
- const [confirmedAllowedDomains, setConfirmedAllowedDomains] = useState10([]);
1850
- const [outputDir, setOutputDir] = useState10("");
1851
- const [studioProject, setStudioProject] = useState10(null);
1852
- const [progressSteps, setProgressSteps] = useState10(PROGRESS_STEPS[command]);
1853
- const [errorMessage, setErrorMessage] = useState10();
1854
- const updateStep = useCallback((index, status) => {
1855
- setProgressSteps((prev) => prev.map((s, i) => i === index ? { ...s, status } : s));
1856
- }, []);
1857
- const activeSteps = useCallback(() => {
1858
- const base = STEPS[command];
1859
- const skipped = /* @__PURE__ */ new Set();
1860
- if (command === "create" /* CREATE */ && initialName) skipped.add("name");
1861
- if (command === "create" /* CREATE */ && options?.template) skipped.add("template");
1862
- if (command === "create" /* CREATE */ && TEMPLATE_FLAVOR_META[templateFlavor].skipTargetStep) {
1863
- skipped.add("targets");
1864
- }
1865
- if (options?.extensionPort || options?.previewPort) skipped.add("settings");
1866
- if (options?.appId) skipped.add("app");
1867
- if (command === "update" /* UPDATE */ && initialExtensionId) skipped.add("extensionSelect");
1868
- if (studioProject) {
1869
- if (command === "create" /* CREATE */) {
1870
- skipped.add("template");
1871
- skipped.add("targets");
1872
- }
1873
- if (command === "scaffold" /* SCAFFOLD */ && studioProject.extensionId) {
1874
- skipped.add("extensionSelect");
1875
- }
1876
- }
1877
- return base.filter((s) => !skipped.has(s));
1878
- }, [
1952
+ const [registryManifest, setRegistryManifest] = useState11(null);
1953
+ const [localManifest, setLocalManifest] = useState11(null);
1954
+ const [confirmedPermissions, setConfirmedPermissions] = useState11([]);
1955
+ const [confirmedAllowedDomains, setConfirmedAllowedDomains] = useState11([]);
1956
+ const [userEditedAllowedDomains, setUserEditedAllowedDomains] = useState11([]);
1957
+ const [outputDir, setOutputDir] = useState11("");
1958
+ const [studioProject, setStudioProject] = useState11(null);
1959
+ const [hasLocalProject, setHasLocalProject] = useState11(false);
1960
+ const [progressSteps, setProgressSteps] = useState11(PROGRESS_STEPS[command]);
1961
+ const [errorMessage, setErrorMessage] = useState11();
1962
+ const { step, goForward, goBack, goTo } = useWizardSteps({
1879
1963
  command,
1880
1964
  initialName,
1881
1965
  initialExtensionId,
1882
1966
  templateFlavor,
1883
1967
  studioProject,
1884
- options?.template,
1885
- options?.extensionPort,
1886
- options?.previewPort,
1887
- options?.appId
1888
- ]);
1889
- const goBack = useCallback(() => {
1890
- setStep((prev) => {
1891
- const steps = activeSteps();
1892
- const idx = steps.indexOf(prev);
1893
- return idx > 0 ? steps[idx - 1] : prev;
1894
- });
1895
- }, [activeSteps]);
1968
+ hasLocalProject,
1969
+ options
1970
+ });
1971
+ const updateStep = useCallback2((index, status) => {
1972
+ setProgressSteps((prev) => prev.map((s, i) => i === index ? { ...s, status } : s));
1973
+ }, []);
1896
1974
  const handleAppSelect = async (app) => {
1897
1975
  setSelectedApp(app);
1898
- if (options?.project && (command === "create" /* CREATE */ || command === "scaffold" /* SCAFFOLD */)) {
1976
+ if (options?.projectId && (command === "create" /* CREATE */ || command === "scaffold" /* SCAFFOLD */)) {
1899
1977
  try {
1900
- const project = await fetchProject(token, app.id, options.project);
1978
+ const project = await fetchProject(token, app.id, options.projectId);
1901
1979
  setStudioProject(project);
1902
1980
  setName(project.name);
1903
1981
  setTargets(project.manifest.targets);
1904
1982
  if (project.extensionId) {
1905
1983
  setExtensionId(project.extensionId);
1906
1984
  }
1907
- if (command === "create" /* CREATE */) {
1908
- setStep("name");
1909
- } else if (command === "scaffold" /* SCAFFOLD */) {
1910
- if (project.extensionId) {
1911
- setStep("confirmTargets");
1912
- } else {
1913
- setStep("extensionSelect");
1914
- }
1915
- }
1985
+ goForward({ studioProject: project });
1916
1986
  return;
1917
1987
  } catch (err) {
1918
1988
  const message = err instanceof Error ? err.message : String(err);
1919
1989
  setErrorMessage(`Failed to fetch Studio project: ${message}`);
1920
- setStep("error");
1990
+ goTo("error");
1921
1991
  return;
1922
1992
  }
1923
1993
  }
1924
- if (command === "update" /* UPDATE */ && initialExtensionId) {
1994
+ if ((command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */) && initialExtensionId) {
1925
1995
  try {
1926
1996
  const extensions = await fetchExtensions(token, app.id);
1927
1997
  const ext = extensions[initialExtensionId];
@@ -1929,7 +1999,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1929
1999
  setErrorMessage(
1930
2000
  `Extension "${initialExtensionId}" not found or is disabled. If disabled, re-enable it in the admin dashboard before updating.`
1931
2001
  );
1932
- setStep("error");
2002
+ goTo("error");
1933
2003
  return;
1934
2004
  }
1935
2005
  setName(ext.manifest.name);
@@ -1944,46 +2014,37 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1944
2014
  bundleUrl: ext.bundleUrl
1945
2015
  });
1946
2016
  setRegistryManifest(ext.manifest);
1947
- const projectRoot = options?.dir || process.cwd();
1948
- try {
1949
- const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
1950
- const content = await readFile3(manifestPath, "utf8");
1951
- setLocalManifest(JSON.parse(content));
1952
- } catch {
1953
- setLocalManifest(null);
2017
+ let localProjectFound = false;
2018
+ if (command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */) {
2019
+ const projectRoot = options?.dir || process.cwd();
2020
+ try {
2021
+ const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
2022
+ const content = await readFile3(manifestPath, "utf8");
2023
+ setLocalManifest(JSON.parse(content));
2024
+ setHasLocalProject(true);
2025
+ localProjectFound = true;
2026
+ } catch {
2027
+ setLocalManifest(null);
2028
+ }
1954
2029
  }
1955
- setStep("updateSettings");
2030
+ goForward({ hasLocalProject: localProjectFound });
1956
2031
  } catch (err) {
1957
2032
  const message = err instanceof Error ? err.message : String(err);
1958
2033
  setErrorMessage(message);
1959
- setStep("error");
2034
+ goTo("error");
1960
2035
  }
1961
2036
  return;
1962
2037
  }
1963
- if (command === "scaffold" /* SCAFFOLD */ || command === "update" /* UPDATE */) {
1964
- setStep("extensionSelect");
1965
- return;
1966
- }
1967
- if (initialName) {
1968
- if (options?.template) {
1969
- const meta = TEMPLATE_FLAVOR_META[templateFlavor];
1970
- if (meta.skipTargetStep && meta.defaultTargets) {
1971
- setTargets(meta.defaultTargets);
1972
- if (options?.extensionPort || options?.previewPort) {
1973
- setOutputDir(join3(process.cwd(), toKebabCase(initialName)));
1974
- setStep("confirm");
1975
- } else {
1976
- setStep("settings");
1977
- }
1978
- return;
2038
+ if (initialName && options?.template) {
2039
+ const meta = TEMPLATE_FLAVOR_META[templateFlavor];
2040
+ if (meta.skipTargetStep && meta.defaultTargets) {
2041
+ setTargets(meta.defaultTargets);
2042
+ if (options?.extensionPort || options?.previewPort) {
2043
+ setOutputDir(join3(process.cwd(), toKebabCase(initialName)));
1979
2044
  }
1980
- setStep("targets");
1981
- } else {
1982
- setStep("template");
1983
2045
  }
1984
- } else {
1985
- setStep("name");
1986
2046
  }
2047
+ goForward();
1987
2048
  };
1988
2049
  useEffect4(() => {
1989
2050
  if (!options?.appId) return;
@@ -1993,11 +2054,28 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1993
2054
  handleAppSelect(app);
1994
2055
  } else {
1995
2056
  setErrorMessage(`App "${options.appId}" not found or is disabled.`);
1996
- setStep("error");
2057
+ goTo("error");
2058
+ }
2059
+ }).catch((err) => {
2060
+ setErrorMessage(err instanceof Error ? err.message : String(err));
2061
+ goTo("error");
2062
+ });
2063
+ }, []);
2064
+ useEffect4(() => {
2065
+ if (options?.appId || !initialExtensionId) return;
2066
+ if (command !== "update" /* UPDATE */ && command !== "scaffold" /* SCAFFOLD */) return;
2067
+ resolveAppForExtension(token, initialExtensionId).then((result) => {
2068
+ if (result) {
2069
+ handleAppSelect(result.app);
2070
+ } else {
2071
+ setErrorMessage(
2072
+ `Extension "${initialExtensionId}" not found across your apps. Verify the extension ID or provide --app-id explicitly.`
2073
+ );
2074
+ goTo("error");
1997
2075
  }
1998
2076
  }).catch((err) => {
1999
2077
  setErrorMessage(err instanceof Error ? err.message : String(err));
2000
- setStep("error");
2078
+ goTo("error");
2001
2079
  });
2002
2080
  }, []);
2003
2081
  const handleExtensionSelect = async (ext) => {
@@ -2013,28 +2091,25 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2013
2091
  bundleUrl: ext.bundleUrl
2014
2092
  });
2015
2093
  setRegistryManifest(ext.manifest);
2094
+ let localProjectFound = false;
2016
2095
  const projectRoot = options?.dir || process.cwd();
2017
2096
  try {
2018
2097
  const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
2019
2098
  const content = await readFile3(manifestPath, "utf8");
2020
2099
  setLocalManifest(JSON.parse(content));
2100
+ setHasLocalProject(true);
2101
+ localProjectFound = true;
2021
2102
  } catch {
2022
2103
  setLocalManifest(null);
2023
2104
  }
2024
- if (command === "scaffold" /* SCAFFOLD */) {
2025
- setStep("confirmTargets");
2026
- } else if (command === "update" /* UPDATE */) {
2027
- setStep("updateSettings");
2028
- }
2105
+ goForward({ hasLocalProject: localProjectFound });
2029
2106
  };
2030
2107
  const handleConfirmTargets = (value) => {
2031
2108
  setTargets(value);
2032
2109
  if (options?.extensionPort || options?.previewPort) {
2033
- setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
2034
- setStep("confirm");
2035
- } else {
2036
- setStep("settings");
2110
+ setOutputDir(join3(process.cwd(), toKebabCase(name || extensionId)));
2037
2111
  }
2112
+ goForward();
2038
2113
  };
2039
2114
  const handleName = (value) => {
2040
2115
  setName(value);
@@ -2043,48 +2118,36 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2043
2118
  const meta = TEMPLATE_FLAVOR_META[templateFlavor];
2044
2119
  if (meta.skipTargetStep && meta.defaultTargets) {
2045
2120
  setTargets(meta.defaultTargets);
2046
- if (options?.extensionPort || options?.previewPort) {
2047
- setOutputDir(join3(process.cwd(), toKebabCase(value)));
2048
- setStep("confirm");
2049
- } else {
2050
- setStep("settings");
2051
- }
2052
- return;
2053
2121
  }
2054
- setStep("targets");
2055
- } else {
2056
- setStep("template");
2057
2122
  }
2123
+ if (options?.extensionPort || options?.previewPort) {
2124
+ setOutputDir(join3(process.cwd(), toKebabCase(value)));
2125
+ }
2126
+ goForward();
2058
2127
  };
2059
2128
  const handleTemplateSelect = (flavor) => {
2060
2129
  setTemplateFlavor(flavor);
2061
2130
  const meta = TEMPLATE_FLAVOR_META[flavor];
2062
2131
  if (meta.skipTargetStep && meta.defaultTargets) {
2063
2132
  setTargets(meta.defaultTargets);
2064
- if (options?.extensionPort || options?.previewPort) {
2065
- setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
2066
- setStep("confirm");
2067
- } else {
2068
- setStep("settings");
2069
- }
2070
- return;
2071
2133
  }
2072
- setStep("targets");
2134
+ if (options?.extensionPort || options?.previewPort) {
2135
+ setOutputDir(join3(process.cwd(), toKebabCase(name || extensionId)));
2136
+ }
2137
+ goForward({ templateFlavor: flavor });
2073
2138
  };
2074
2139
  const handleTargets = (value) => {
2075
2140
  setTargets(value);
2076
2141
  if (options?.extensionPort || options?.previewPort) {
2077
- setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
2078
- setStep("confirm");
2079
- } else {
2080
- setStep("settings");
2142
+ setOutputDir(join3(process.cwd(), toKebabCase(name || extensionId)));
2081
2143
  }
2144
+ goForward();
2082
2145
  };
2083
2146
  const handleSettings = (extPort, prevPort, dir) => {
2084
2147
  setExtensionPort(extPort);
2085
2148
  setPreviewPort(prevPort);
2086
2149
  setOutputDir(dir);
2087
- setStep("confirm");
2150
+ goForward();
2088
2151
  };
2089
2152
  const computeVersionBump = (currentVersion, newName, newTargets, newBundleUrl, isForceMajor) => {
2090
2153
  const [major, minor, patch] = currentVersion.split(".").map(Number);
@@ -2100,7 +2163,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2100
2163
  };
2101
2164
  const handleConfirm = async () => {
2102
2165
  if (command === "update" /* UPDATE */) {
2103
- setStep("updating");
2166
+ goTo("updating");
2104
2167
  setProgressSteps(PROGRESS_STEPS[command]);
2105
2168
  try {
2106
2169
  updateStep(0, "running");
@@ -2118,15 +2181,15 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2118
2181
  });
2119
2182
  updateStep(0, "done");
2120
2183
  setExtensionVersion(resolvedVersion);
2121
- setStep("updateDone");
2184
+ goTo("updateDone");
2122
2185
  } catch (err) {
2123
2186
  const message = err instanceof Error ? err.message : String(err);
2124
2187
  setErrorMessage(message);
2125
- setStep("error");
2188
+ goTo("error");
2126
2189
  }
2127
2190
  return;
2128
2191
  }
2129
- setStep("scaffolding");
2192
+ goTo("scaffolding");
2130
2193
  setProgressSteps(PROGRESS_STEPS[command]);
2131
2194
  try {
2132
2195
  let resolvedExtensionId = extensionId || toKebabCase(name);
@@ -2155,7 +2218,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2155
2218
  name,
2156
2219
  extensionId: resolvedExtensionId,
2157
2220
  targets,
2158
- templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0,
2221
+ templateFlavor: command === "create" /* CREATE */ || command === "scaffold" /* SCAFFOLD */ ? templateFlavor : void 0,
2159
2222
  outputDir,
2160
2223
  extensionPort,
2161
2224
  previewPort,
@@ -2194,11 +2257,11 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2194
2257
  } else {
2195
2258
  updateStep(scaffoldStepOffset + 2, "done");
2196
2259
  }
2197
- setStep("done");
2260
+ goTo("done");
2198
2261
  } catch (err) {
2199
2262
  const message = err instanceof Error ? err.message : String(err);
2200
2263
  setErrorMessage(message);
2201
- setStep("error");
2264
+ goTo("error");
2202
2265
  }
2203
2266
  };
2204
2267
  const handleCancel = () => {
@@ -2206,6 +2269,15 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2206
2269
  };
2207
2270
  switch (step) {
2208
2271
  case "app": {
2272
+ if (options?.appId || initialExtensionId && (command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */)) {
2273
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
2274
+ /* @__PURE__ */ jsx15(Banner, { userId, orgId }),
2275
+ /* @__PURE__ */ jsx15(StepShell, { title: "Loading App\u2026", children: /* @__PURE__ */ jsxs15(Box15, { gap: 2, children: [
2276
+ /* @__PURE__ */ jsx15(Spinner4, { type: "dots" }),
2277
+ /* @__PURE__ */ jsx15(Text15, { children: options?.appId ? "Fetching app details\u2026" : "Resolving app from extension\u2026" })
2278
+ ] }) })
2279
+ ] });
2280
+ }
2209
2281
  return /* @__PURE__ */ jsx15(
2210
2282
  AppSelect,
2211
2283
  {
@@ -2263,6 +2335,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2263
2335
  TargetSelect,
2264
2336
  {
2265
2337
  availableTargets: selectedApp?.targets ?? [],
2338
+ preSelected: targets,
2266
2339
  onSubmit: handleTargets,
2267
2340
  onBack: goBack
2268
2341
  }
@@ -2272,7 +2345,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2272
2345
  return /* @__PURE__ */ jsx15(
2273
2346
  SettingsPrompt,
2274
2347
  {
2275
- defaultDir: join3(process.cwd(), toKebabCase(extensionId || name)),
2348
+ defaultDir: join3(process.cwd(), toKebabCase(name || extensionId)),
2276
2349
  onSubmit: handleSettings,
2277
2350
  onBack: goBack
2278
2351
  }
@@ -2316,30 +2389,33 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2316
2389
  targets,
2317
2390
  enabled,
2318
2391
  bundleUrl,
2392
+ allowedDomains: registryManifest?.allowedDomains ?? [],
2319
2393
  availableTargets: selectedApp?.targets ?? [],
2320
2394
  onSubmit: (updated) => {
2321
2395
  setName(updated.name);
2322
2396
  setTargets(updated.targets);
2323
2397
  setBundleUrl(updated.bundleUrl);
2398
+ setUserEditedAllowedDomains(updated.allowedDomains);
2324
2399
  setEnabled(updated.enabled);
2325
2400
  setForceMajor(updated.forceMajor);
2326
2401
  setVersionOverride(void 0);
2327
- setStep("manifestReview");
2402
+ goForward();
2328
2403
  },
2329
2404
  onBack: goBack
2330
2405
  }
2331
2406
  );
2332
2407
  }
2333
2408
  case "manifestReview": {
2409
+ const effectiveLocalManifest = localManifest ? { ...localManifest, allowedDomains: userEditedAllowedDomains } : userEditedAllowedDomains.length > 0 ? { name, version: "0.0.0", targets, permissions: [], allowedDomains: userEditedAllowedDomains } : localManifest;
2334
2410
  return /* @__PURE__ */ jsx15(
2335
2411
  ManifestReviewPrompt,
2336
2412
  {
2337
- localManifest,
2413
+ localManifest: effectiveLocalManifest,
2338
2414
  registryManifest,
2339
2415
  onSubmit: (result) => {
2340
2416
  setConfirmedPermissions(result.permissions);
2341
2417
  setConfirmedAllowedDomains(result.allowedDomains);
2342
- setStep("confirm");
2418
+ goForward();
2343
2419
  },
2344
2420
  onBack: goBack
2345
2421
  }
@@ -2384,7 +2460,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2384
2460
  };
2385
2461
 
2386
2462
  // src/components/DevApp.tsx
2387
- import { useRef, useState as useState13, useEffect as useEffect7, useCallback as useCallback3 } from "react";
2463
+ import { useRef, useState as useState14, useEffect as useEffect7, useCallback as useCallback4 } from "react";
2388
2464
  import { useInput as useInput12, Box as Box19, Text as Text19 } from "ink";
2389
2465
 
2390
2466
  // src/lib/devServer.ts
@@ -2458,11 +2534,11 @@ var startTunnel = async (port) => {
2458
2534
 
2459
2535
  // src/components/DevSetup.tsx
2460
2536
  import { Box as Box16, Text as Text16 } from "ink";
2461
- import { useState as useState11, useEffect as useEffect5 } from "react";
2537
+ import { useState as useState12, useEffect as useEffect5 } from "react";
2462
2538
  import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
2463
2539
  var DevSetup = ({ initialContext, token, onReady }) => {
2464
- const [step, setStep] = useState11("app");
2465
- const [selectedApp, setSelectedApp] = useState11(null);
2540
+ const [step, setStep] = useState12("app");
2541
+ const [selectedApp, setSelectedApp] = useState12(null);
2466
2542
  useEffect5(() => {
2467
2543
  if (initialContext.appId) {
2468
2544
  setStep("extension");
@@ -2506,10 +2582,10 @@ var DevSetup = ({ initialContext, token, onReady }) => {
2506
2582
 
2507
2583
  // src/components/DevDashboard.tsx
2508
2584
  import { Box as Box18, Text as Text18, useInput as useInput11 } from "ink";
2509
- import { useEffect as useEffect6, useMemo } from "react";
2585
+ import { useEffect as useEffect6, useMemo as useMemo2 } from "react";
2510
2586
 
2511
2587
  // src/components/CopyableField.tsx
2512
- import { useState as useState12, useCallback as useCallback2 } from "react";
2588
+ import { useState as useState13, useCallback as useCallback3 } from "react";
2513
2589
  import { useInput as useInput10, Box as Box17, Text as Text17 } from "ink";
2514
2590
  import clipboard from "clipboardy";
2515
2591
  import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
@@ -2522,9 +2598,9 @@ var CopyableField = ({
2522
2598
  labelColor,
2523
2599
  children
2524
2600
  }) => {
2525
- const [expanded, setExpanded] = useState12(false);
2526
- const [copied, setCopied] = useState12(false);
2527
- const handleCopy = useCallback2(async () => {
2601
+ const [expanded, setExpanded] = useState13(false);
2602
+ const [copied, setCopied] = useState13(false);
2603
+ const handleCopy = useCallback3(async () => {
2528
2604
  if (expanded) {
2529
2605
  setExpanded(false);
2530
2606
  setCopied(false);
@@ -2594,7 +2670,7 @@ var DevDashboard = ({
2594
2670
  process.off("SIGINT", handler);
2595
2671
  };
2596
2672
  }, [onQuit]);
2597
- const devParamBlob = useMemo(() => {
2673
+ const devParamBlob = useMemo2(() => {
2598
2674
  if (!tunnelUrl || !devSessionToken) return "";
2599
2675
  return toBase64Url(JSON.stringify({ url: tunnelUrl, token: devSessionToken }));
2600
2676
  }, [tunnelUrl, devSessionToken]);
@@ -2730,16 +2806,16 @@ var DevDashboard = ({
2730
2806
  // src/components/DevApp.tsx
2731
2807
  import { jsx as jsx19 } from "react/jsx-runtime";
2732
2808
  var DevApp = ({ token, userId, orgId, options = {} }) => {
2733
- const [state, setState] = useState13("setup");
2734
- const [devContext, setDevContext] = useState13(null);
2735
- const [resolvedContext, setResolvedContext] = useState13(null);
2736
- const [tunnelUrl, setTunnelUrl] = useState13(null);
2737
- const [previewTunnelUrl, setPreviewTunnelUrl] = useState13(null);
2738
- const [tunnelHandle, setTunnelHandle] = useState13(null);
2739
- const [previewTunnelHandle, setPreviewTunnelHandle] = useState13(null);
2740
- const [devServerHandle, setDevServerHandle] = useState13(null);
2741
- const [manifestWarnings, setManifestWarnings] = useState13([]);
2742
- const [devSessionToken, setDevSessionToken] = useState13(null);
2809
+ const [state, setState] = useState14("setup");
2810
+ const [devContext, setDevContext] = useState14(null);
2811
+ const [resolvedContext, setResolvedContext] = useState14(null);
2812
+ const [tunnelUrl, setTunnelUrl] = useState14(null);
2813
+ const [previewTunnelUrl, setPreviewTunnelUrl] = useState14(null);
2814
+ const [tunnelHandle, setTunnelHandle] = useState14(null);
2815
+ const [previewTunnelHandle, setPreviewTunnelHandle] = useState14(null);
2816
+ const [devServerHandle, setDevServerHandle] = useState14(null);
2817
+ const [manifestWarnings, setManifestWarnings] = useState14([]);
2818
+ const [devSessionToken, setDevSessionToken] = useState14(null);
2743
2819
  const shuttingDown = useRef(false);
2744
2820
  const useTunnel = options.tunnel !== false;
2745
2821
  useEffect7(() => {
@@ -2750,7 +2826,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2750
2826
  setDevContext(ctx);
2751
2827
  });
2752
2828
  }, [options.dir]);
2753
- const handleSetupReady = useCallback3(async (resolved) => {
2829
+ const handleSetupReady = useCallback4(async (resolved) => {
2754
2830
  if (!devContext) return;
2755
2831
  setResolvedContext(resolved);
2756
2832
  console.log(`[dev] Saving context: appId=${resolved.appId} extensionId=${resolved.extensionId}`);
@@ -2907,8 +2983,8 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2907
2983
 
2908
2984
  // src/components/AIScaffold.tsx
2909
2985
  import { Box as Box20, Text as Text20, useApp as useApp2 } from "ink";
2910
- import Spinner4 from "ink-spinner";
2911
- import { useState as useState14, useEffect as useEffect8 } from "react";
2986
+ import Spinner5 from "ink-spinner";
2987
+ import { useState as useState15, useEffect as useEffect8 } from "react";
2912
2988
 
2913
2989
  // src/lib/aiDocs.ts
2914
2990
  import { existsSync, readFileSync } from "fs";
@@ -2964,9 +3040,9 @@ var downloadAndExtractAiDocs = async (targetDir, version2) => {
2964
3040
  import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
2965
3041
  var AIScaffold = ({ version: version2 }) => {
2966
3042
  const { exit } = useApp2();
2967
- const [state, setState] = useState14("validating");
2968
- const [files, setFiles] = useState14([]);
2969
- const [errorMessage, setErrorMessage] = useState14("");
3043
+ const [state, setState] = useState15("validating");
3044
+ const [files, setFiles] = useState15([]);
3045
+ const [errorMessage, setErrorMessage] = useState15("");
2970
3046
  useEffect8(() => {
2971
3047
  const run = async () => {
2972
3048
  const projectDir = process.cwd();
@@ -2994,11 +3070,11 @@ var AIScaffold = ({ version: version2 }) => {
2994
3070
  /* @__PURE__ */ jsx20(Banner, {}),
2995
3071
  /* @__PURE__ */ jsxs19(StepShell, { title: "AI Editor Config", children: [
2996
3072
  state === "validating" && /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
2997
- /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner4, { type: "dots" }) }),
3073
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner5, { type: "dots" }) }),
2998
3074
  /* @__PURE__ */ jsx20(Text20, { children: "Checking project..." })
2999
3075
  ] }),
3000
3076
  state === "downloading" && /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
3001
- /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner4, { type: "dots" }) }),
3077
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner5, { type: "dots" }) }),
3002
3078
  /* @__PURE__ */ jsxs19(Text20, { children: [
3003
3079
  "Downloading AI editor configs (",
3004
3080
  version2,
@@ -3027,9 +3103,9 @@ var AIScaffold = ({ version: version2 }) => {
3027
3103
  // src/components/AuthLogin.tsx
3028
3104
  import { createServer } from "http";
3029
3105
  import { Box as Box21, Text as Text21, useApp as useApp3 } from "ink";
3030
- import Spinner5 from "ink-spinner";
3106
+ import Spinner6 from "ink-spinner";
3031
3107
  import open from "open";
3032
- import { useState as useState15, useEffect as useEffect9 } from "react";
3108
+ import { useState as useState16, useEffect as useEffect9 } from "react";
3033
3109
 
3034
3110
  // src/lib/auth.ts
3035
3111
  import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir2, unlink } from "fs/promises";
@@ -3093,11 +3169,11 @@ ${redirectUrl ? `<script>(function(){var s=3,el=document.getElementById('h');fun
3093
3169
  </body></html>`;
3094
3170
  var AuthLogin = ({ dashboardUrl }) => {
3095
3171
  const { exit } = useApp3();
3096
- const [state, setState] = useState15("waiting");
3097
- const [loginUrl, setLoginUrl] = useState15("");
3098
- const [userIdLabel, setUserIdLabel] = useState15("");
3099
- const [orgIdLabel, setOrgIdLabel] = useState15("");
3100
- const [errorMessage, setErrorMessage] = useState15("");
3172
+ const [state, setState] = useState16("waiting");
3173
+ const [loginUrl, setLoginUrl] = useState16("");
3174
+ const [userIdLabel, setUserIdLabel] = useState16("");
3175
+ const [orgIdLabel, setOrgIdLabel] = useState16("");
3176
+ const [errorMessage, setErrorMessage] = useState16("");
3101
3177
  useEffect9(() => {
3102
3178
  let server;
3103
3179
  let timeout;
@@ -3178,7 +3254,7 @@ var AuthLogin = ({ dashboardUrl }) => {
3178
3254
  /* @__PURE__ */ jsxs20(StepShell, { title: "Authenticate with Stackable", children: [
3179
3255
  state === "waiting" && /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", gap: 1, children: [
3180
3256
  /* @__PURE__ */ jsxs20(Box21, { gap: 1, children: [
3181
- /* @__PURE__ */ jsx21(Text21, { color: "cyan", children: /* @__PURE__ */ jsx21(Spinner5, { type: "dots" }) }),
3257
+ /* @__PURE__ */ jsx21(Text21, { color: "cyan", children: /* @__PURE__ */ jsx21(Spinner6, { type: "dots" }) }),
3182
3258
  /* @__PURE__ */ jsx21(Text21, { children: "Waiting for browser authentication..." })
3183
3259
  ] }),
3184
3260
  loginUrl && /* @__PURE__ */ jsxs20(Text21, { dimColor: true, children: [
@@ -3348,7 +3424,7 @@ var ensureToken = async () => {
3348
3424
  }
3349
3425
  };
3350
3426
  program.name("stackable-app-extension").description("Stackable Labs - App Extension developer CLI").version(version);
3351
- program.command("create" /* CREATE */).description("Create a new Extension project").argument("[name]", "Extension project name").option("--app-id <id>", "Skip App selection").option("--project <id>", "Studio project ID (fetches files/manifest from Studio)").option("--template <flavor>", "Template flavor: minimal, starter, kitchen-sink").option("--extension-port <port>", "Extension dev server port (default: 6543)").option("--preview-port <port>", "Preview dev server port").option("--skip-install", "Skip package manager install").option("--skip-git", "Skip git initialization").action(async (name, options) => {
3427
+ program.command("create" /* CREATE */).description("Create a new Extension project").argument("[name]", "Extension project name").option("--app-id <id>", "Skip App selection").option("--project-id <id>", "Studio project ID (fetches files/manifest from Studio)").option("--template <flavor>", "Template flavor: minimal, starter, kitchen-sink").option("--extension-port <port>", "Extension dev server port (default: 6543)").option("--preview-port <port>", "Preview dev server port").option("--skip-install", "Skip package manager install").option("--skip-git", "Skip git initialization").action(async (name, options) => {
3352
3428
  const auth2 = await ensureToken();
3353
3429
  if (!auth2) {
3354
3430
  return;
@@ -3368,7 +3444,7 @@ program.command("create" /* CREATE */).description("Create a new Extension proje
3368
3444
  )
3369
3445
  );
3370
3446
  });
3371
- program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project from an existing Extension").option("--app-id <id>", "Skip App selection").option("--project <id>", "Studio project ID (fetches files/manifest from Studio)").option("--extension-port <port>", "Extension dev server port (default: 6543)").option("--preview-port <port>", "Preview dev server port").option("--skip-install", "Skip package manager install").option("--skip-git", "Skip git initialization").action(async (options) => {
3447
+ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project from an existing Extension").argument("[extensionId]", "Extension ID to scaffold from").option("--app-id <id>", "App ID (auto-resolved from extensionId if omitted)").option("--project-id <id>", "Studio project ID (fetches files/manifest from Studio)").option("--template <flavor>", "Template flavor: minimal, starter, kitchen-sink").option("--extension-port <port>", "Extension dev server port (default: 6543)").option("--preview-port <port>", "Preview dev server port").option("--skip-install", "Skip package manager install").option("--skip-git", "Skip git initialization").action(async (extensionId, options) => {
3372
3448
  const auth2 = await ensureToken();
3373
3449
  if (!auth2) {
3374
3450
  return;
@@ -3379,6 +3455,7 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
3379
3455
  App,
3380
3456
  {
3381
3457
  command: "scaffold" /* SCAFFOLD */,
3458
+ initialExtensionId: extensionId,
3382
3459
  options,
3383
3460
  token,
3384
3461
  orgId,
@@ -3387,7 +3464,7 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
3387
3464
  )
3388
3465
  );
3389
3466
  });
3390
- program.command("update" /* UPDATE */).description("Update an existing Extension").argument("[extensionId]", "Extension ID to update").option("--app-id <id>", "Skip App selection").option("--name <name>", "New Extension name").option("--targets <targets>", "Comma-separated target slots (validated against app)").option("--bundle-url <url>", "New bundle URL").option("--enabled <bool>", "Enable/disable Extension").option("--set-version <version>", "Explicit version (skips auto-compute)").option("--dir <path>", "Project root (default: cwd)").action(async (extensionId, options) => {
3467
+ program.command("update" /* UPDATE */).description("Update an existing Extension").argument("[extensionId]", "Extension ID to update").option("--app-id <id>", "App ID (auto-resolved from extensionId if omitted)").option("--name <name>", "New Extension name").option("--targets <targets>", "Comma-separated target slots (validated against app)").option("--bundle-url <url>", "New bundle URL").option("--enabled <bool>", "Enable/disable Extension").option("--set-version <version>", "Explicit version (skips auto-compute)").option("--dir <path>", "Project root (default: cwd)").action(async (extensionId, options) => {
3391
3468
  const auth2 = await ensureToken();
3392
3469
  if (!auth2) {
3393
3470
  return;