@stackable-labs/cli-app-extension 1.36.2 → 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 -480
  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,121 +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("name");
1871
- skipped.add("template");
1872
- skipped.add("targets");
1873
- }
1874
- if (command === "scaffold" /* SCAFFOLD */ && studioProject.extensionId) {
1875
- skipped.add("extensionSelect");
1876
- }
1877
- }
1878
- return base.filter((s) => !skipped.has(s));
1879
- }, [
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({
1880
1963
  command,
1881
1964
  initialName,
1882
1965
  initialExtensionId,
1883
1966
  templateFlavor,
1884
1967
  studioProject,
1885
- options?.template,
1886
- options?.extensionPort,
1887
- options?.previewPort,
1888
- options?.appId
1889
- ]);
1890
- const goBack = useCallback(() => {
1891
- setStep((prev) => {
1892
- const steps = activeSteps();
1893
- const idx = steps.indexOf(prev);
1894
- return idx > 0 ? steps[idx - 1] : prev;
1895
- });
1896
- }, [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
+ }, []);
1897
1974
  const handleAppSelect = async (app) => {
1898
1975
  setSelectedApp(app);
1899
- if (options?.project && (command === "create" /* CREATE */ || command === "scaffold" /* SCAFFOLD */)) {
1976
+ if (options?.projectId && (command === "create" /* CREATE */ || command === "scaffold" /* SCAFFOLD */)) {
1900
1977
  try {
1901
- const project = await fetchProject(token, app.id, options.project);
1978
+ const project = await fetchProject(token, app.id, options.projectId);
1902
1979
  setStudioProject(project);
1903
1980
  setName(project.name);
1904
1981
  setTargets(project.manifest.targets);
1905
1982
  if (project.extensionId) {
1906
1983
  setExtensionId(project.extensionId);
1907
1984
  }
1908
- if (command === "create" /* CREATE */) {
1909
- if (options?.extensionPort || options?.previewPort) {
1910
- setOutputDir(join3(process.cwd(), toKebabCase(project.name)));
1911
- setStep("confirm");
1912
- } else {
1913
- setStep("settings");
1914
- }
1915
- } else if (command === "scaffold" /* SCAFFOLD */) {
1916
- if (project.extensionId) {
1917
- setStep("confirmTargets");
1918
- } else {
1919
- setStep("extensionSelect");
1920
- }
1921
- }
1985
+ goForward({ studioProject: project });
1922
1986
  return;
1923
1987
  } catch (err) {
1924
1988
  const message = err instanceof Error ? err.message : String(err);
1925
1989
  setErrorMessage(`Failed to fetch Studio project: ${message}`);
1926
- setStep("error");
1990
+ goTo("error");
1927
1991
  return;
1928
1992
  }
1929
1993
  }
1930
- if (command === "update" /* UPDATE */ && initialExtensionId) {
1994
+ if ((command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */) && initialExtensionId) {
1931
1995
  try {
1932
1996
  const extensions = await fetchExtensions(token, app.id);
1933
1997
  const ext = extensions[initialExtensionId];
@@ -1935,7 +1999,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1935
1999
  setErrorMessage(
1936
2000
  `Extension "${initialExtensionId}" not found or is disabled. If disabled, re-enable it in the admin dashboard before updating.`
1937
2001
  );
1938
- setStep("error");
2002
+ goTo("error");
1939
2003
  return;
1940
2004
  }
1941
2005
  setName(ext.manifest.name);
@@ -1950,46 +2014,37 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1950
2014
  bundleUrl: ext.bundleUrl
1951
2015
  });
1952
2016
  setRegistryManifest(ext.manifest);
1953
- const projectRoot = options?.dir || process.cwd();
1954
- try {
1955
- const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
1956
- const content = await readFile3(manifestPath, "utf8");
1957
- setLocalManifest(JSON.parse(content));
1958
- } catch {
1959
- 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
+ }
1960
2029
  }
1961
- setStep("updateSettings");
2030
+ goForward({ hasLocalProject: localProjectFound });
1962
2031
  } catch (err) {
1963
2032
  const message = err instanceof Error ? err.message : String(err);
1964
2033
  setErrorMessage(message);
1965
- setStep("error");
2034
+ goTo("error");
1966
2035
  }
1967
2036
  return;
1968
2037
  }
1969
- if (command === "scaffold" /* SCAFFOLD */ || command === "update" /* UPDATE */) {
1970
- setStep("extensionSelect");
1971
- return;
1972
- }
1973
- if (initialName) {
1974
- if (options?.template) {
1975
- const meta = TEMPLATE_FLAVOR_META[templateFlavor];
1976
- if (meta.skipTargetStep && meta.defaultTargets) {
1977
- setTargets(meta.defaultTargets);
1978
- if (options?.extensionPort || options?.previewPort) {
1979
- setOutputDir(join3(process.cwd(), toKebabCase(initialName)));
1980
- setStep("confirm");
1981
- } else {
1982
- setStep("settings");
1983
- }
1984
- 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)));
1985
2044
  }
1986
- setStep("targets");
1987
- } else {
1988
- setStep("template");
1989
2045
  }
1990
- } else {
1991
- setStep("name");
1992
2046
  }
2047
+ goForward();
1993
2048
  };
1994
2049
  useEffect4(() => {
1995
2050
  if (!options?.appId) return;
@@ -1999,11 +2054,28 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1999
2054
  handleAppSelect(app);
2000
2055
  } else {
2001
2056
  setErrorMessage(`App "${options.appId}" not found or is disabled.`);
2002
- setStep("error");
2057
+ goTo("error");
2003
2058
  }
2004
2059
  }).catch((err) => {
2005
2060
  setErrorMessage(err instanceof Error ? err.message : String(err));
2006
- setStep("error");
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");
2075
+ }
2076
+ }).catch((err) => {
2077
+ setErrorMessage(err instanceof Error ? err.message : String(err));
2078
+ goTo("error");
2007
2079
  });
2008
2080
  }, []);
2009
2081
  const handleExtensionSelect = async (ext) => {
@@ -2019,28 +2091,25 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2019
2091
  bundleUrl: ext.bundleUrl
2020
2092
  });
2021
2093
  setRegistryManifest(ext.manifest);
2094
+ let localProjectFound = false;
2022
2095
  const projectRoot = options?.dir || process.cwd();
2023
2096
  try {
2024
2097
  const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
2025
2098
  const content = await readFile3(manifestPath, "utf8");
2026
2099
  setLocalManifest(JSON.parse(content));
2100
+ setHasLocalProject(true);
2101
+ localProjectFound = true;
2027
2102
  } catch {
2028
2103
  setLocalManifest(null);
2029
2104
  }
2030
- if (command === "scaffold" /* SCAFFOLD */) {
2031
- setStep("confirmTargets");
2032
- } else if (command === "update" /* UPDATE */) {
2033
- setStep("updateSettings");
2034
- }
2105
+ goForward({ hasLocalProject: localProjectFound });
2035
2106
  };
2036
2107
  const handleConfirmTargets = (value) => {
2037
2108
  setTargets(value);
2038
2109
  if (options?.extensionPort || options?.previewPort) {
2039
- setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
2040
- setStep("confirm");
2041
- } else {
2042
- setStep("settings");
2110
+ setOutputDir(join3(process.cwd(), toKebabCase(name || extensionId)));
2043
2111
  }
2112
+ goForward();
2044
2113
  };
2045
2114
  const handleName = (value) => {
2046
2115
  setName(value);
@@ -2049,48 +2118,36 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2049
2118
  const meta = TEMPLATE_FLAVOR_META[templateFlavor];
2050
2119
  if (meta.skipTargetStep && meta.defaultTargets) {
2051
2120
  setTargets(meta.defaultTargets);
2052
- if (options?.extensionPort || options?.previewPort) {
2053
- setOutputDir(join3(process.cwd(), toKebabCase(value)));
2054
- setStep("confirm");
2055
- } else {
2056
- setStep("settings");
2057
- }
2058
- return;
2059
2121
  }
2060
- setStep("targets");
2061
- } else {
2062
- setStep("template");
2063
2122
  }
2123
+ if (options?.extensionPort || options?.previewPort) {
2124
+ setOutputDir(join3(process.cwd(), toKebabCase(value)));
2125
+ }
2126
+ goForward();
2064
2127
  };
2065
2128
  const handleTemplateSelect = (flavor) => {
2066
2129
  setTemplateFlavor(flavor);
2067
2130
  const meta = TEMPLATE_FLAVOR_META[flavor];
2068
2131
  if (meta.skipTargetStep && meta.defaultTargets) {
2069
2132
  setTargets(meta.defaultTargets);
2070
- if (options?.extensionPort || options?.previewPort) {
2071
- setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
2072
- setStep("confirm");
2073
- } else {
2074
- setStep("settings");
2075
- }
2076
- return;
2077
2133
  }
2078
- setStep("targets");
2134
+ if (options?.extensionPort || options?.previewPort) {
2135
+ setOutputDir(join3(process.cwd(), toKebabCase(name || extensionId)));
2136
+ }
2137
+ goForward({ templateFlavor: flavor });
2079
2138
  };
2080
2139
  const handleTargets = (value) => {
2081
2140
  setTargets(value);
2082
2141
  if (options?.extensionPort || options?.previewPort) {
2083
- setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
2084
- setStep("confirm");
2085
- } else {
2086
- setStep("settings");
2142
+ setOutputDir(join3(process.cwd(), toKebabCase(name || extensionId)));
2087
2143
  }
2144
+ goForward();
2088
2145
  };
2089
2146
  const handleSettings = (extPort, prevPort, dir) => {
2090
2147
  setExtensionPort(extPort);
2091
2148
  setPreviewPort(prevPort);
2092
2149
  setOutputDir(dir);
2093
- setStep("confirm");
2150
+ goForward();
2094
2151
  };
2095
2152
  const computeVersionBump = (currentVersion, newName, newTargets, newBundleUrl, isForceMajor) => {
2096
2153
  const [major, minor, patch] = currentVersion.split(".").map(Number);
@@ -2106,7 +2163,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2106
2163
  };
2107
2164
  const handleConfirm = async () => {
2108
2165
  if (command === "update" /* UPDATE */) {
2109
- setStep("updating");
2166
+ goTo("updating");
2110
2167
  setProgressSteps(PROGRESS_STEPS[command]);
2111
2168
  try {
2112
2169
  updateStep(0, "running");
@@ -2124,15 +2181,15 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2124
2181
  });
2125
2182
  updateStep(0, "done");
2126
2183
  setExtensionVersion(resolvedVersion);
2127
- setStep("updateDone");
2184
+ goTo("updateDone");
2128
2185
  } catch (err) {
2129
2186
  const message = err instanceof Error ? err.message : String(err);
2130
2187
  setErrorMessage(message);
2131
- setStep("error");
2188
+ goTo("error");
2132
2189
  }
2133
2190
  return;
2134
2191
  }
2135
- setStep("scaffolding");
2192
+ goTo("scaffolding");
2136
2193
  setProgressSteps(PROGRESS_STEPS[command]);
2137
2194
  try {
2138
2195
  let resolvedExtensionId = extensionId || toKebabCase(name);
@@ -2161,7 +2218,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2161
2218
  name,
2162
2219
  extensionId: resolvedExtensionId,
2163
2220
  targets,
2164
- templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0,
2221
+ templateFlavor: command === "create" /* CREATE */ || command === "scaffold" /* SCAFFOLD */ ? templateFlavor : void 0,
2165
2222
  outputDir,
2166
2223
  extensionPort,
2167
2224
  previewPort,
@@ -2200,11 +2257,11 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2200
2257
  } else {
2201
2258
  updateStep(scaffoldStepOffset + 2, "done");
2202
2259
  }
2203
- setStep("done");
2260
+ goTo("done");
2204
2261
  } catch (err) {
2205
2262
  const message = err instanceof Error ? err.message : String(err);
2206
2263
  setErrorMessage(message);
2207
- setStep("error");
2264
+ goTo("error");
2208
2265
  }
2209
2266
  };
2210
2267
  const handleCancel = () => {
@@ -2212,6 +2269,15 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2212
2269
  };
2213
2270
  switch (step) {
2214
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
+ }
2215
2281
  return /* @__PURE__ */ jsx15(
2216
2282
  AppSelect,
2217
2283
  {
@@ -2269,6 +2335,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2269
2335
  TargetSelect,
2270
2336
  {
2271
2337
  availableTargets: selectedApp?.targets ?? [],
2338
+ preSelected: targets,
2272
2339
  onSubmit: handleTargets,
2273
2340
  onBack: goBack
2274
2341
  }
@@ -2278,7 +2345,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2278
2345
  return /* @__PURE__ */ jsx15(
2279
2346
  SettingsPrompt,
2280
2347
  {
2281
- defaultDir: join3(process.cwd(), toKebabCase(extensionId || name)),
2348
+ defaultDir: join3(process.cwd(), toKebabCase(name || extensionId)),
2282
2349
  onSubmit: handleSettings,
2283
2350
  onBack: goBack
2284
2351
  }
@@ -2322,30 +2389,33 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2322
2389
  targets,
2323
2390
  enabled,
2324
2391
  bundleUrl,
2392
+ allowedDomains: registryManifest?.allowedDomains ?? [],
2325
2393
  availableTargets: selectedApp?.targets ?? [],
2326
2394
  onSubmit: (updated) => {
2327
2395
  setName(updated.name);
2328
2396
  setTargets(updated.targets);
2329
2397
  setBundleUrl(updated.bundleUrl);
2398
+ setUserEditedAllowedDomains(updated.allowedDomains);
2330
2399
  setEnabled(updated.enabled);
2331
2400
  setForceMajor(updated.forceMajor);
2332
2401
  setVersionOverride(void 0);
2333
- setStep("manifestReview");
2402
+ goForward();
2334
2403
  },
2335
2404
  onBack: goBack
2336
2405
  }
2337
2406
  );
2338
2407
  }
2339
2408
  case "manifestReview": {
2409
+ const effectiveLocalManifest = localManifest ? { ...localManifest, allowedDomains: userEditedAllowedDomains } : userEditedAllowedDomains.length > 0 ? { name, version: "0.0.0", targets, permissions: [], allowedDomains: userEditedAllowedDomains } : localManifest;
2340
2410
  return /* @__PURE__ */ jsx15(
2341
2411
  ManifestReviewPrompt,
2342
2412
  {
2343
- localManifest,
2413
+ localManifest: effectiveLocalManifest,
2344
2414
  registryManifest,
2345
2415
  onSubmit: (result) => {
2346
2416
  setConfirmedPermissions(result.permissions);
2347
2417
  setConfirmedAllowedDomains(result.allowedDomains);
2348
- setStep("confirm");
2418
+ goForward();
2349
2419
  },
2350
2420
  onBack: goBack
2351
2421
  }
@@ -2390,7 +2460,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
2390
2460
  };
2391
2461
 
2392
2462
  // src/components/DevApp.tsx
2393
- 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";
2394
2464
  import { useInput as useInput12, Box as Box19, Text as Text19 } from "ink";
2395
2465
 
2396
2466
  // src/lib/devServer.ts
@@ -2464,11 +2534,11 @@ var startTunnel = async (port) => {
2464
2534
 
2465
2535
  // src/components/DevSetup.tsx
2466
2536
  import { Box as Box16, Text as Text16 } from "ink";
2467
- import { useState as useState11, useEffect as useEffect5 } from "react";
2537
+ import { useState as useState12, useEffect as useEffect5 } from "react";
2468
2538
  import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
2469
2539
  var DevSetup = ({ initialContext, token, onReady }) => {
2470
- const [step, setStep] = useState11("app");
2471
- const [selectedApp, setSelectedApp] = useState11(null);
2540
+ const [step, setStep] = useState12("app");
2541
+ const [selectedApp, setSelectedApp] = useState12(null);
2472
2542
  useEffect5(() => {
2473
2543
  if (initialContext.appId) {
2474
2544
  setStep("extension");
@@ -2512,10 +2582,10 @@ var DevSetup = ({ initialContext, token, onReady }) => {
2512
2582
 
2513
2583
  // src/components/DevDashboard.tsx
2514
2584
  import { Box as Box18, Text as Text18, useInput as useInput11 } from "ink";
2515
- import { useEffect as useEffect6, useMemo } from "react";
2585
+ import { useEffect as useEffect6, useMemo as useMemo2 } from "react";
2516
2586
 
2517
2587
  // src/components/CopyableField.tsx
2518
- import { useState as useState12, useCallback as useCallback2 } from "react";
2588
+ import { useState as useState13, useCallback as useCallback3 } from "react";
2519
2589
  import { useInput as useInput10, Box as Box17, Text as Text17 } from "ink";
2520
2590
  import clipboard from "clipboardy";
2521
2591
  import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
@@ -2528,9 +2598,9 @@ var CopyableField = ({
2528
2598
  labelColor,
2529
2599
  children
2530
2600
  }) => {
2531
- const [expanded, setExpanded] = useState12(false);
2532
- const [copied, setCopied] = useState12(false);
2533
- const handleCopy = useCallback2(async () => {
2601
+ const [expanded, setExpanded] = useState13(false);
2602
+ const [copied, setCopied] = useState13(false);
2603
+ const handleCopy = useCallback3(async () => {
2534
2604
  if (expanded) {
2535
2605
  setExpanded(false);
2536
2606
  setCopied(false);
@@ -2600,7 +2670,7 @@ var DevDashboard = ({
2600
2670
  process.off("SIGINT", handler);
2601
2671
  };
2602
2672
  }, [onQuit]);
2603
- const devParamBlob = useMemo(() => {
2673
+ const devParamBlob = useMemo2(() => {
2604
2674
  if (!tunnelUrl || !devSessionToken) return "";
2605
2675
  return toBase64Url(JSON.stringify({ url: tunnelUrl, token: devSessionToken }));
2606
2676
  }, [tunnelUrl, devSessionToken]);
@@ -2736,16 +2806,16 @@ var DevDashboard = ({
2736
2806
  // src/components/DevApp.tsx
2737
2807
  import { jsx as jsx19 } from "react/jsx-runtime";
2738
2808
  var DevApp = ({ token, userId, orgId, options = {} }) => {
2739
- const [state, setState] = useState13("setup");
2740
- const [devContext, setDevContext] = useState13(null);
2741
- const [resolvedContext, setResolvedContext] = useState13(null);
2742
- const [tunnelUrl, setTunnelUrl] = useState13(null);
2743
- const [previewTunnelUrl, setPreviewTunnelUrl] = useState13(null);
2744
- const [tunnelHandle, setTunnelHandle] = useState13(null);
2745
- const [previewTunnelHandle, setPreviewTunnelHandle] = useState13(null);
2746
- const [devServerHandle, setDevServerHandle] = useState13(null);
2747
- const [manifestWarnings, setManifestWarnings] = useState13([]);
2748
- 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);
2749
2819
  const shuttingDown = useRef(false);
2750
2820
  const useTunnel = options.tunnel !== false;
2751
2821
  useEffect7(() => {
@@ -2756,7 +2826,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2756
2826
  setDevContext(ctx);
2757
2827
  });
2758
2828
  }, [options.dir]);
2759
- const handleSetupReady = useCallback3(async (resolved) => {
2829
+ const handleSetupReady = useCallback4(async (resolved) => {
2760
2830
  if (!devContext) return;
2761
2831
  setResolvedContext(resolved);
2762
2832
  console.log(`[dev] Saving context: appId=${resolved.appId} extensionId=${resolved.extensionId}`);
@@ -2913,8 +2983,8 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2913
2983
 
2914
2984
  // src/components/AIScaffold.tsx
2915
2985
  import { Box as Box20, Text as Text20, useApp as useApp2 } from "ink";
2916
- import Spinner4 from "ink-spinner";
2917
- 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";
2918
2988
 
2919
2989
  // src/lib/aiDocs.ts
2920
2990
  import { existsSync, readFileSync } from "fs";
@@ -2970,9 +3040,9 @@ var downloadAndExtractAiDocs = async (targetDir, version2) => {
2970
3040
  import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
2971
3041
  var AIScaffold = ({ version: version2 }) => {
2972
3042
  const { exit } = useApp2();
2973
- const [state, setState] = useState14("validating");
2974
- const [files, setFiles] = useState14([]);
2975
- const [errorMessage, setErrorMessage] = useState14("");
3043
+ const [state, setState] = useState15("validating");
3044
+ const [files, setFiles] = useState15([]);
3045
+ const [errorMessage, setErrorMessage] = useState15("");
2976
3046
  useEffect8(() => {
2977
3047
  const run = async () => {
2978
3048
  const projectDir = process.cwd();
@@ -3000,11 +3070,11 @@ var AIScaffold = ({ version: version2 }) => {
3000
3070
  /* @__PURE__ */ jsx20(Banner, {}),
3001
3071
  /* @__PURE__ */ jsxs19(StepShell, { title: "AI Editor Config", children: [
3002
3072
  state === "validating" && /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
3003
- /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner4, { type: "dots" }) }),
3073
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner5, { type: "dots" }) }),
3004
3074
  /* @__PURE__ */ jsx20(Text20, { children: "Checking project..." })
3005
3075
  ] }),
3006
3076
  state === "downloading" && /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
3007
- /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner4, { type: "dots" }) }),
3077
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner5, { type: "dots" }) }),
3008
3078
  /* @__PURE__ */ jsxs19(Text20, { children: [
3009
3079
  "Downloading AI editor configs (",
3010
3080
  version2,
@@ -3033,9 +3103,9 @@ var AIScaffold = ({ version: version2 }) => {
3033
3103
  // src/components/AuthLogin.tsx
3034
3104
  import { createServer } from "http";
3035
3105
  import { Box as Box21, Text as Text21, useApp as useApp3 } from "ink";
3036
- import Spinner5 from "ink-spinner";
3106
+ import Spinner6 from "ink-spinner";
3037
3107
  import open from "open";
3038
- import { useState as useState15, useEffect as useEffect9 } from "react";
3108
+ import { useState as useState16, useEffect as useEffect9 } from "react";
3039
3109
 
3040
3110
  // src/lib/auth.ts
3041
3111
  import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir2, unlink } from "fs/promises";
@@ -3099,11 +3169,11 @@ ${redirectUrl ? `<script>(function(){var s=3,el=document.getElementById('h');fun
3099
3169
  </body></html>`;
3100
3170
  var AuthLogin = ({ dashboardUrl }) => {
3101
3171
  const { exit } = useApp3();
3102
- const [state, setState] = useState15("waiting");
3103
- const [loginUrl, setLoginUrl] = useState15("");
3104
- const [userIdLabel, setUserIdLabel] = useState15("");
3105
- const [orgIdLabel, setOrgIdLabel] = useState15("");
3106
- 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("");
3107
3177
  useEffect9(() => {
3108
3178
  let server;
3109
3179
  let timeout;
@@ -3184,7 +3254,7 @@ var AuthLogin = ({ dashboardUrl }) => {
3184
3254
  /* @__PURE__ */ jsxs20(StepShell, { title: "Authenticate with Stackable", children: [
3185
3255
  state === "waiting" && /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", gap: 1, children: [
3186
3256
  /* @__PURE__ */ jsxs20(Box21, { gap: 1, children: [
3187
- /* @__PURE__ */ jsx21(Text21, { color: "cyan", children: /* @__PURE__ */ jsx21(Spinner5, { type: "dots" }) }),
3257
+ /* @__PURE__ */ jsx21(Text21, { color: "cyan", children: /* @__PURE__ */ jsx21(Spinner6, { type: "dots" }) }),
3188
3258
  /* @__PURE__ */ jsx21(Text21, { children: "Waiting for browser authentication..." })
3189
3259
  ] }),
3190
3260
  loginUrl && /* @__PURE__ */ jsxs20(Text21, { dimColor: true, children: [
@@ -3354,7 +3424,7 @@ var ensureToken = async () => {
3354
3424
  }
3355
3425
  };
3356
3426
  program.name("stackable-app-extension").description("Stackable Labs - App Extension developer CLI").version(version);
3357
- 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) => {
3358
3428
  const auth2 = await ensureToken();
3359
3429
  if (!auth2) {
3360
3430
  return;
@@ -3374,7 +3444,7 @@ program.command("create" /* CREATE */).description("Create a new Extension proje
3374
3444
  )
3375
3445
  );
3376
3446
  });
3377
- 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) => {
3378
3448
  const auth2 = await ensureToken();
3379
3449
  if (!auth2) {
3380
3450
  return;
@@ -3385,6 +3455,7 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
3385
3455
  App,
3386
3456
  {
3387
3457
  command: "scaffold" /* SCAFFOLD */,
3458
+ initialExtensionId: extensionId,
3388
3459
  options,
3389
3460
  token,
3390
3461
  orgId,
@@ -3393,7 +3464,7 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
3393
3464
  )
3394
3465
  );
3395
3466
  });
3396
- 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) => {
3397
3468
  const auth2 = await ensureToken();
3398
3469
  if (!auth2) {
3399
3470
  return;