@stackable-labs/cli-app-extension 1.26.4 → 1.27.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 (2) hide show
  1. package/dist/index.js +685 -410
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6,9 +6,10 @@ import { program } from "commander";
6
6
  import { render } from "ink";
7
7
 
8
8
  // src/App.tsx
9
+ import { readFile as readFile3 } from "fs/promises";
9
10
  import { join as join3 } from "path";
10
- import { Box as Box14, Text as Text14, useApp } from "ink";
11
- import { useCallback, useState as useState9 } from "react";
11
+ import { Box as Box15, Text as Text15, useApp } from "ink";
12
+ import { useCallback, useState as useState10 } from "react";
12
13
 
13
14
  // src/components/Confirm.tsx
14
15
  import { Box as Box2, Text as Text2, useFocus, useFocusManager, useInput as useInput2 } from "ink";
@@ -44,7 +45,7 @@ var TEMPLATE_FLAVOR_META = {
44
45
  };
45
46
  var TARGET_PERMISSION_MAP = {
46
47
  "slot.header": ["context:read"],
47
- "slot.content": ["context:read", "data:query", "actions:toast", "actions:invoke"],
48
+ "slot.content": ["context:read", "data:query", "data:fetch", "actions:toast", "actions:invoke"],
48
49
  "slot.footer": [],
49
50
  "slot.footer-links": []
50
51
  };
@@ -98,11 +99,11 @@ var VersionRow = ({ currentVersion, value, onChange, onFocusChange, onConfirm, o
98
99
  const { focusPrevious, focusNext } = useFocusManager();
99
100
  useInput2((_, key) => {
100
101
  if (!isFocused) return;
101
- if (key.upArrow || key.tab && key.shift) {
102
+ if (key.upArrow) {
102
103
  focusPrevious();
103
104
  return;
104
105
  }
105
- if (key.tab && !key.shift) {
106
+ if (key.downArrow) {
106
107
  focusNext();
107
108
  return;
108
109
  }
@@ -140,9 +141,14 @@ var Confirm = ({
140
141
  extensionPort,
141
142
  previewPort,
142
143
  targets,
144
+ registryTargets,
143
145
  outputDir,
144
146
  bundleUrl,
145
147
  enabled,
148
+ permissions,
149
+ allowedDomains,
150
+ registryPermissions,
151
+ registryAllowedDomains,
146
152
  newVersion,
147
153
  onVersionOverride,
148
154
  onConfirm,
@@ -238,10 +244,57 @@ var Confirm = ({
238
244
  ] }),
239
245
  /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
240
246
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Targets " }),
241
- /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: targets.map((t) => /* @__PURE__ */ jsxs2(Box2, { children: [
242
- /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u2022 " }),
243
- /* @__PURE__ */ jsx2(Text2, { children: t })
244
- ] }, t)) })
247
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
248
+ targets.map((t) => {
249
+ 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)" })
254
+ ] }, t);
255
+ }),
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)" })
260
+ ] }, t))
261
+ ] })
262
+ ] }),
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: [
266
+ permissions.map((p) => {
267
+ 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)" })
272
+ ] }, p);
273
+ }),
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)" })
278
+ ] }, p))
279
+ ] })
280
+ ] }),
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: [
284
+ allowedDomains.map((d) => {
285
+ 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)" })
290
+ ] }, d);
291
+ }),
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)" })
296
+ ] }, d))
297
+ ] })
245
298
  ] })
246
299
  ] })
247
300
  }
@@ -447,24 +500,151 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
447
500
  );
448
501
  };
449
502
 
450
- // src/components/UpdateSettingsPrompt.tsx
451
- import { Box as Box7, Text as Text7, useFocus as useFocus3, useFocusManager as useFocusManager3, useInput as useInput4 } from "ink";
452
- import TextInput4 from "ink-text-input";
503
+ // src/components/ManifestReviewPrompt.tsx
504
+ import { Box as Box7, Text as Text7, useInput as useInput4 } from "ink";
453
505
  import { useState as useState4 } from "react";
506
+
507
+ // src/lib/manifest-diff.ts
508
+ var diffManifestValues = (localValues, registryValues) => {
509
+ const localSet = new Set(localValues ?? []);
510
+ const registrySet = new Set(registryValues);
511
+ const all = /* @__PURE__ */ new Set([...localSet, ...registrySet]);
512
+ return [...all].map((value) => {
513
+ const inLocal = localSet.has(value);
514
+ const inRegistry = registrySet.has(value);
515
+ if (!inLocal) {
516
+ return { value, status: "removed", enabled: false };
517
+ }
518
+ return inRegistry ? { value, status: "unchanged", enabled: true } : { value, status: "new", enabled: false };
519
+ });
520
+ };
521
+
522
+ // src/components/ManifestReviewPrompt.tsx
454
523
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
455
- var FieldRow2 = ({ label, value, onChange, placeholder, autoFocus, isFirst, isLast, onSubmitAll }) => {
456
- const { isFocused } = useFocus3({ autoFocus });
457
- const { focusNext, focusPrevious } = useFocusManager3();
458
- useInput4((_, key) => {
459
- if (!isFocused) return;
524
+ var statusLabel = (status) => {
525
+ switch (status) {
526
+ case "new":
527
+ return "(+ added)";
528
+ case "removed":
529
+ return "(- removed)";
530
+ case "unchanged":
531
+ return void 0;
532
+ }
533
+ };
534
+ var statusColor = (status) => {
535
+ switch (status) {
536
+ case "new":
537
+ return "green";
538
+ case "removed":
539
+ return "red";
540
+ case "unchanged":
541
+ return void 0;
542
+ }
543
+ };
544
+ var ManifestReviewPrompt = ({
545
+ localManifest,
546
+ registryManifest,
547
+ onSubmit,
548
+ onBack
549
+ }) => {
550
+ const [permItems, setPermItems] = useState4(() => diffManifestValues(localManifest?.permissions, registryManifest.permissions));
551
+ const [domainItems, setDomainItems] = useState4(() => diffManifestValues(localManifest?.allowedDomains, registryManifest.allowedDomains));
552
+ const [cursor, setCursor] = useState4(0);
553
+ const totalItems = permItems.length + domainItems.length;
554
+ const cursorInPerms = cursor < permItems.length;
555
+ const cursorInDomains = cursor >= permItems.length;
556
+ const toggle = (index) => {
557
+ if (index < permItems.length) {
558
+ setPermItems((prev) => prev.map((item, i) => i === index ? { ...item, enabled: !item.enabled } : item));
559
+ } else {
560
+ const domainIndex = index - permItems.length;
561
+ setDomainItems((prev) => prev.map((item, i) => i === domainIndex ? { ...item, enabled: !item.enabled } : item));
562
+ }
563
+ };
564
+ const handleSubmit = () => {
565
+ onSubmit({
566
+ permissions: permItems.filter((i) => i.enabled).map((i) => i.value),
567
+ allowedDomains: domainItems.filter((i) => i.enabled).map((i) => i.value)
568
+ });
569
+ };
570
+ const domainSectionStart = permItems.length;
571
+ useInput4((input, key) => {
572
+ if (key.downArrow) {
573
+ setCursor((c) => Math.min(c + 1, totalItems - 1));
574
+ return;
575
+ }
576
+ if (key.upArrow) {
577
+ setCursor((c) => Math.max(c - 1, 0));
578
+ return;
579
+ }
460
580
  if (key.tab && !key.shift) {
461
- if (!isLast) focusNext();
581
+ setCursor((c) => {
582
+ if (c < domainSectionStart && domainItems.length > 0) return domainSectionStart;
583
+ return c;
584
+ });
462
585
  return;
463
586
  }
464
587
  if (key.tab && key.shift) {
465
- if (!isFirst) focusPrevious();
588
+ setCursor((c) => {
589
+ if (c >= domainSectionStart) return 0;
590
+ return c;
591
+ });
592
+ return;
593
+ }
594
+ if (input === " ") {
595
+ toggle(cursor);
466
596
  return;
467
597
  }
598
+ if (key.return) {
599
+ handleSubmit();
600
+ }
601
+ });
602
+ const renderItem = (item, index) => {
603
+ 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) })
609
+ ] }, item.value);
610
+ };
611
+ return /* @__PURE__ */ jsx7(
612
+ StepShell,
613
+ {
614
+ title: "Review Manifest changes",
615
+ hint: "Tab/shift-tab to jump section, \u2191/\u2193 navigate. Enter to submit",
616
+ 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)" })
624
+ ] })
625
+ ] }),
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)" })
631
+ ] })
632
+ ] })
633
+ ] })
634
+ }
635
+ );
636
+ };
637
+
638
+ // src/components/UpdateSettingsPrompt.tsx
639
+ import { Box as Box8, Text as Text8, useFocus as useFocus3, useFocusManager as useFocusManager3, useInput as useInput5 } from "ink";
640
+ import TextInput4 from "ink-text-input";
641
+ import { useState as useState5 } from "react";
642
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
643
+ var FieldRow2 = ({ label, value, onChange, placeholder, autoFocus, isFirst, isLast, onSubmitAll }) => {
644
+ const { isFocused } = useFocus3({ autoFocus });
645
+ const { focusNext, focusPrevious } = useFocusManager3();
646
+ useInput5((_, key) => {
647
+ if (!isFocused) return;
468
648
  if (key.downArrow) {
469
649
  if (!isLast) focusNext();
470
650
  return;
@@ -477,29 +657,17 @@ var FieldRow2 = ({ label, value, onChange, placeholder, autoFocus, isFirst, isLa
477
657
  onSubmitAll();
478
658
  }
479
659
  });
480
- return /* @__PURE__ */ jsxs7(Box7, { gap: 2, children: [
481
- /* @__PURE__ */ jsx7(Text7, { dimColor: !isFocused, bold: isFocused, children: label.padEnd(14) }),
482
- isFocused ? /* @__PURE__ */ jsx7(TextInput4, { value, onChange, placeholder }) : /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: value || placeholder || "" })
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 || "" })
483
663
  ] });
484
664
  };
485
665
  var TargetToggleRow = ({ targets, availableTargets, onToggle, autoFocus, isLast, onSubmitAll }) => {
486
666
  const { isFocused } = useFocus3({ autoFocus });
487
667
  const { focusNext, focusPrevious } = useFocusManager3();
488
- const [cursor, setCursor] = useState4(0);
489
- useInput4((input, key) => {
668
+ const [cursor, setCursor] = useState5(0);
669
+ useInput5((input, key) => {
490
670
  if (!isFocused) return;
491
- if (key.tab && !key.shift) {
492
- focusNext();
493
- return;
494
- }
495
- if (key.tab && key.shift) {
496
- if (cursor > 0) {
497
- setCursor((c) => c - 1);
498
- } else {
499
- focusPrevious();
500
- }
501
- return;
502
- }
503
671
  if (key.downArrow) {
504
672
  if (cursor < availableTargets.length - 1) {
505
673
  setCursor((c) => c + 1);
@@ -524,35 +692,27 @@ var TargetToggleRow = ({ targets, availableTargets, onToggle, autoFocus, isLast,
524
692
  onSubmitAll();
525
693
  }
526
694
  });
527
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
528
- /* @__PURE__ */ jsx7(Text7, { dimColor: !isFocused, bold: isFocused, children: "Targets".padEnd(14) }),
529
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingLeft: 2, children: [
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: [
530
698
  availableTargets.map((t, i) => {
531
699
  const selected = targets.includes(t);
532
700
  const isCursor = isFocused && i === cursor;
533
- return /* @__PURE__ */ jsxs7(Box7, { gap: 1, children: [
534
- /* @__PURE__ */ jsx7(Text7, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
535
- /* @__PURE__ */ jsx7(Text7, { color: selected ? "green" : "gray", children: selected ? "\u25C9" : "\u25CB" }),
536
- /* @__PURE__ */ jsx7(Text7, { bold: isCursor, children: t })
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 })
537
705
  ] }, t);
538
706
  }),
539
- isFocused && /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " (space to toggle)" })
707
+ isFocused && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " (space to toggle)" })
540
708
  ] })
541
709
  ] });
542
710
  };
543
711
  var EnabledToggleRow = ({ enabled, onToggle, autoFocus, isLast, onSubmitAll }) => {
544
712
  const { isFocused } = useFocus3({ autoFocus });
545
713
  const { focusNext, focusPrevious } = useFocusManager3();
546
- useInput4((input, key) => {
714
+ useInput5((input, key) => {
547
715
  if (!isFocused) return;
548
- if (key.tab && !key.shift) {
549
- if (!isLast) focusNext();
550
- return;
551
- }
552
- if (key.tab && key.shift) {
553
- focusPrevious();
554
- return;
555
- }
556
716
  if (key.downArrow) {
557
717
  if (!isLast) focusNext();
558
718
  return;
@@ -569,25 +729,17 @@ var EnabledToggleRow = ({ enabled, onToggle, autoFocus, isLast, onSubmitAll }) =
569
729
  onSubmitAll();
570
730
  }
571
731
  });
572
- return /* @__PURE__ */ jsxs7(Box7, { gap: 2, children: [
573
- /* @__PURE__ */ jsx7(Text7, { dimColor: !isFocused, bold: isFocused, children: "Enabled".padEnd(14) }),
574
- /* @__PURE__ */ jsx7(Text7, { color: enabled ? "green" : "red", bold: isFocused, children: enabled ? "Yes" : "No" }),
575
- isFocused && /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "(space/arrows to toggle)" })
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)" })
576
736
  ] });
577
737
  };
578
738
  var ForceMajorToggleRow = ({ forceMajor, onToggle, autoFocus, isLast, onSubmitAll }) => {
579
739
  const { isFocused } = useFocus3({ autoFocus });
580
740
  const { focusPrevious, focusNext } = useFocusManager3();
581
- useInput4((input, key) => {
741
+ useInput5((input, key) => {
582
742
  if (!isFocused) return;
583
- if (key.tab && !key.shift) {
584
- if (!isLast) focusNext();
585
- return;
586
- }
587
- if (key.tab && key.shift) {
588
- focusPrevious();
589
- return;
590
- }
591
743
  if (key.downArrow) {
592
744
  if (!isLast) focusNext();
593
745
  return;
@@ -604,10 +756,10 @@ var ForceMajorToggleRow = ({ forceMajor, onToggle, autoFocus, isLast, onSubmitAl
604
756
  onSubmitAll();
605
757
  }
606
758
  });
607
- return /* @__PURE__ */ jsxs7(Box7, { gap: 2, children: [
608
- /* @__PURE__ */ jsx7(Text7, { dimColor: !isFocused, bold: isFocused, children: "Force major".padEnd(14) }),
609
- /* @__PURE__ */ jsx7(Text7, { color: forceMajor ? "yellow" : "gray", bold: isFocused, children: forceMajor ? "Yes" : "No" }),
610
- isFocused && /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "(space/arrows to toggle)" })
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)" })
611
763
  ] });
612
764
  };
613
765
  var UpdateSettingsPrompt = ({
@@ -619,11 +771,11 @@ var UpdateSettingsPrompt = ({
619
771
  onSubmit,
620
772
  onBack
621
773
  }) => {
622
- const [nameValue, setNameValue] = useState4(initialName);
623
- const [targetsValue, setTargetsValue] = useState4(initialTargets);
624
- const [bundleUrlValue, setBundleUrlValue] = useState4(initialBundleUrl);
625
- const [enabledValue, setEnabledValue] = useState4(initialEnabled);
626
- const [forceMajorValue, setForceMajorValue] = useState4(false);
774
+ const [nameValue, setNameValue] = useState5(initialName);
775
+ const [targetsValue, setTargetsValue] = useState5(initialTargets);
776
+ const [bundleUrlValue, setBundleUrlValue] = useState5(initialBundleUrl);
777
+ const [enabledValue, setEnabledValue] = useState5(initialEnabled);
778
+ const [forceMajorValue, setForceMajorValue] = useState5(false);
627
779
  const handleToggleTarget = (target) => {
628
780
  setTargetsValue((prev) => prev.includes(target) ? prev.filter((t) => t !== target) : [...prev, target]);
629
781
  };
@@ -637,14 +789,14 @@ var UpdateSettingsPrompt = ({
637
789
  forceMajor: forceMajorValue
638
790
  });
639
791
  };
640
- return /* @__PURE__ */ jsx7(
792
+ return /* @__PURE__ */ jsx8(
641
793
  StepShell,
642
794
  {
643
795
  title: "Update Extension settings",
644
- hint: "Tab/arrows to navigate, Enter to submit",
796
+ hint: "Tab/shift-tab to jump section, \u2191/\u2193 navigate. Enter to submit",
645
797
  onBack,
646
- children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", gap: 1, children: [
647
- /* @__PURE__ */ jsx7(
798
+ children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
799
+ /* @__PURE__ */ jsx8(
648
800
  FieldRow2,
649
801
  {
650
802
  label: "Name",
@@ -656,7 +808,7 @@ var UpdateSettingsPrompt = ({
656
808
  onSubmitAll: handleSubmitAll
657
809
  }
658
810
  ),
659
- /* @__PURE__ */ jsx7(
811
+ /* @__PURE__ */ jsx8(
660
812
  TargetToggleRow,
661
813
  {
662
814
  targets: targetsValue,
@@ -665,7 +817,7 @@ var UpdateSettingsPrompt = ({
665
817
  onSubmitAll: handleSubmitAll
666
818
  }
667
819
  ),
668
- /* @__PURE__ */ jsx7(
820
+ /* @__PURE__ */ jsx8(
669
821
  FieldRow2,
670
822
  {
671
823
  label: "Bundle URL",
@@ -675,7 +827,7 @@ var UpdateSettingsPrompt = ({
675
827
  onSubmitAll: handleSubmitAll
676
828
  }
677
829
  ),
678
- /* @__PURE__ */ jsx7(
830
+ /* @__PURE__ */ jsx8(
679
831
  EnabledToggleRow,
680
832
  {
681
833
  enabled: enabledValue,
@@ -683,7 +835,7 @@ var UpdateSettingsPrompt = ({
683
835
  onSubmitAll: handleSubmitAll
684
836
  }
685
837
  ),
686
- /* @__PURE__ */ jsx7(
838
+ /* @__PURE__ */ jsx8(
687
839
  ForceMajorToggleRow,
688
840
  {
689
841
  forceMajor: forceMajorValue,
@@ -698,33 +850,33 @@ var UpdateSettingsPrompt = ({
698
850
  };
699
851
 
700
852
  // src/components/ScaffoldProgress.tsx
701
- import { Box as Box8, Text as Text8 } from "ink";
853
+ import { Box as Box9, Text as Text9 } from "ink";
702
854
  import Spinner from "ink-spinner";
703
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
855
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
704
856
  var stepIcon = (status) => {
705
857
  switch (status) {
706
858
  case "running":
707
- return /* @__PURE__ */ jsx8(Spinner, { type: "dots" });
859
+ return /* @__PURE__ */ jsx9(Spinner, { type: "dots" });
708
860
  case "done":
709
- return /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u2714" });
861
+ return /* @__PURE__ */ jsx9(Text9, { color: "green", children: "\u2714" });
710
862
  case "error":
711
- return /* @__PURE__ */ jsx8(Text8, { color: "red", children: "\u2716" });
863
+ return /* @__PURE__ */ jsx9(Text9, { color: "red", children: "\u2716" });
712
864
  default:
713
- return /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\u25CB" });
865
+ return /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u25CB" });
714
866
  }
715
867
  };
716
- var ScaffoldProgress = ({ steps }) => /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
717
- /* @__PURE__ */ jsx8(Text8, { bold: true, children: "Scaffolding your Extension\u2026" }),
718
- /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: steps.map((step) => /* @__PURE__ */ jsxs8(Box8, { gap: 2, children: [
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: [
719
871
  stepIcon(step.status),
720
- /* @__PURE__ */ jsx8(Text8, { dimColor: step.status === "pending", color: step.status === "running" ? "cyan" : void 0, children: step.label })
872
+ /* @__PURE__ */ jsx9(Text9, { dimColor: step.status === "pending", color: step.status === "running" ? "cyan" : void 0, children: step.label })
721
873
  ] }, step.label)) })
722
874
  ] });
723
875
 
724
876
  // src/components/TargetSelect.tsx
725
- import { Box as Box9, Text as Text9, useInput as useInput5 } from "ink";
726
- import { useState as useState5 } from "react";
727
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
877
+ import { Box as Box10, Text as Text10, useInput as useInput6 } from "ink";
878
+ import { useState as useState6 } from "react";
879
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
728
880
  var TARGET_DESCRIPTIONS = {
729
881
  "slot.header": "Renders content in the panel header area",
730
882
  "slot.content": "Renders the main panel body (includes store + navigation state)",
@@ -732,12 +884,12 @@ var TARGET_DESCRIPTIONS = {
732
884
  "slot.footer-links": "Renders a link row in the global footer"
733
885
  };
734
886
  var TargetSelect = ({ availableTargets, preSelected, onSubmit, onBack }) => {
735
- const [cursor, setCursor] = useState5(0);
736
- const [selected, setSelected] = useState5(
887
+ const [cursor, setCursor] = useState6(0);
888
+ const [selected, setSelected] = useState6(
737
889
  new Set(preSelected ?? (availableTargets.includes("slot.content") ? ["slot.content"] : []))
738
890
  );
739
- const [error, setError] = useState5();
740
- useInput5((input, key) => {
891
+ const [error, setError] = useState6();
892
+ useInput6((input, key) => {
741
893
  if (key.upArrow) {
742
894
  setCursor((c) => Math.max(0, c - 1));
743
895
  return;
@@ -768,39 +920,39 @@ var TargetSelect = ({ availableTargets, preSelected, onSubmit, onBack }) => {
768
920
  onSubmit([...selected]);
769
921
  }
770
922
  });
771
- return /* @__PURE__ */ jsxs9(
923
+ return /* @__PURE__ */ jsxs10(
772
924
  StepShell,
773
925
  {
774
926
  title: "Select Surface targets/slots",
775
927
  hint: "Space to toggle, Enter to confirm",
776
928
  onBack,
777
929
  children: [
778
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", gap: 1, children: availableTargets.map((target, i) => {
930
+ /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", gap: 1, children: availableTargets.map((target, i) => {
779
931
  const isSelected = selected.has(target);
780
932
  const isCursor = i === cursor;
781
- return /* @__PURE__ */ jsxs9(Box9, { gap: 1, children: [
782
- /* @__PURE__ */ jsx9(Text9, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
783
- /* @__PURE__ */ jsx9(Text9, { color: isSelected ? "green" : void 0, children: isSelected ? "\u25C9" : "\u25CB" }),
784
- /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
785
- /* @__PURE__ */ jsx9(Text9, { bold: isSelected, children: target }),
786
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: TARGET_DESCRIPTIONS[target] ?? target })
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 })
787
939
  ] })
788
940
  ] }, target);
789
941
  }) }),
790
- error && /* @__PURE__ */ jsx9(Text9, { color: "red", children: error })
942
+ error && /* @__PURE__ */ jsx10(Text10, { color: "red", children: error })
791
943
  ]
792
944
  }
793
945
  );
794
946
  };
795
947
 
796
948
  // src/components/TemplateSelect.tsx
797
- import { Box as Box10, Text as Text10, useInput as useInput6 } from "ink";
798
- import { useState as useState6 } from "react";
799
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
949
+ import { Box as Box11, Text as Text11, useInput as useInput7 } from "ink";
950
+ import { useState as useState7 } from "react";
951
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
800
952
  var FLAVORS = ["minimal", "starter", "kitchen-sink"];
801
953
  var TemplateSelect = ({ onSubmit, onBack }) => {
802
- const [cursor, setCursor] = useState6(1);
803
- useInput6((_input, key) => {
954
+ const [cursor, setCursor] = useState7(1);
955
+ useInput7((_input, key) => {
804
956
  if (key.upArrow) {
805
957
  setCursor((c) => Math.max(0, c - 1));
806
958
  return;
@@ -813,21 +965,21 @@ var TemplateSelect = ({ onSubmit, onBack }) => {
813
965
  onSubmit(FLAVORS[cursor]);
814
966
  }
815
967
  });
816
- return /* @__PURE__ */ jsx10(
968
+ return /* @__PURE__ */ jsx11(
817
969
  StepShell,
818
970
  {
819
971
  title: "Choose a template",
820
972
  hint: "\u2191\u2193 to navigate, Enter to select",
821
973
  onBack,
822
- children: /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", gap: 1, children: FLAVORS.map((flavor, i) => {
974
+ children: /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", gap: 1, children: FLAVORS.map((flavor, i) => {
823
975
  const meta = TEMPLATE_FLAVOR_META[flavor];
824
976
  const isCursor = i === cursor;
825
- return /* @__PURE__ */ jsxs10(Box10, { gap: 1, children: [
826
- /* @__PURE__ */ jsx10(Text10, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
827
- /* @__PURE__ */ jsx10(Text10, { color: isCursor ? "green" : void 0, children: isCursor ? "\u25C9" : "\u25CB" }),
828
- /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
829
- /* @__PURE__ */ jsx10(Text10, { bold: isCursor, children: meta.label }),
830
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: meta.description })
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 })
831
983
  ] })
832
984
  ] }, flavor);
833
985
  }) })
@@ -836,9 +988,9 @@ var TemplateSelect = ({ onSubmit, onBack }) => {
836
988
  };
837
989
 
838
990
  // src/components/AppSelect.tsx
839
- import { Box as Box12, Text as Text12, useInput as useInput7 } from "ink";
991
+ import { Box as Box13, Text as Text13, useInput as useInput8 } from "ink";
840
992
  import Spinner2 from "ink-spinner";
841
- import { useEffect as useEffect2, useState as useState7 } from "react";
993
+ import { useEffect as useEffect2, useState as useState8 } from "react";
842
994
 
843
995
  // src/lib/api.ts
844
996
  var DEFAULT_ADMIN_API_URL = "https://api-use1.stackablelabs.io/admin";
@@ -915,8 +1067,8 @@ var updateExtension = async (token, appId, extensionId, payload) => {
915
1067
  };
916
1068
 
917
1069
  // src/components/Banner.tsx
918
- import { Box as Box11, Text as Text11 } from "ink";
919
- import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1070
+ import { Box as Box12, Text as Text12 } from "ink";
1071
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
920
1072
  var WORDMARK = [
921
1073
  " _ _ _ _ ",
922
1074
  " ___| |_ __ _ ___| | ____ _| |__ | | ___",
@@ -952,18 +1104,18 @@ var gradientColor = (row, col, rows, cols) => {
952
1104
  var Banner = ({ userId, orgId } = {}) => {
953
1105
  const termWidth = process.stdout.columns ?? 80;
954
1106
  const maxLen = Math.max(...WORDMARK.map((l) => l.length));
955
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
956
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u2500".repeat(termWidth) }),
957
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
958
- WORDMARK.map((line, row) => /* @__PURE__ */ jsx11(Box11, { children: line.split("").map((ch, col) => /* @__PURE__ */ jsx11(Text11, { bold: true, color: ch === " " ? void 0 : gradientColor(row, col, WORDMARK.length, maxLen), children: ch }, col)) }, row)),
959
- userId && orgId && /* @__PURE__ */ jsxs11(Box11, { gap: 2, marginTop: 1, children: [
960
- /* @__PURE__ */ jsxs11(Box11, { gap: 1, children: [
961
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "User:" }),
962
- /* @__PURE__ */ jsx11(Text11, { color: "cyan", children: userId })
1107
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
1108
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "\u2500".repeat(termWidth) }),
1109
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
1110
+ 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)),
1111
+ userId && orgId && /* @__PURE__ */ jsxs12(Box12, { gap: 2, marginTop: 1, children: [
1112
+ /* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
1113
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "User:" }),
1114
+ /* @__PURE__ */ jsx12(Text12, { color: "cyan", children: userId })
963
1115
  ] }),
964
- /* @__PURE__ */ jsxs11(Box11, { gap: 1, children: [
965
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "Org:" }),
966
- /* @__PURE__ */ jsx11(Text11, { color: "cyan", children: orgId })
1116
+ /* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
1117
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Org:" }),
1118
+ /* @__PURE__ */ jsx12(Text12, { color: "cyan", children: orgId })
967
1119
  ] })
968
1120
  ] })
969
1121
  ] })
@@ -971,16 +1123,16 @@ var Banner = ({ userId, orgId } = {}) => {
971
1123
  };
972
1124
 
973
1125
  // src/components/AppSelect.tsx
974
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1126
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
975
1127
  var AppSelect = ({ token, userId, orgId, onSubmit }) => {
976
- const [apps, setApps] = useState7([]);
977
- const [loading, setLoading] = useState7(true);
978
- const [error, setError] = useState7();
979
- const [cursor, setCursor] = useState7(0);
1128
+ const [apps, setApps] = useState8([]);
1129
+ const [loading, setLoading] = useState8(true);
1130
+ const [error, setError] = useState8();
1131
+ const [cursor, setCursor] = useState8(0);
980
1132
  useEffect2(() => {
981
1133
  fetchApps(token).then(setApps).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
982
1134
  }, [token]);
983
- useInput7((_, key) => {
1135
+ useInput8((_, key) => {
984
1136
  if (loading || error || apps.length === 0) return;
985
1137
  if (key.upArrow) {
986
1138
  setCursor((c) => Math.max(0, c - 1));
@@ -992,26 +1144,26 @@ var AppSelect = ({ token, userId, orgId, onSubmit }) => {
992
1144
  });
993
1145
  const renderContent = () => {
994
1146
  if (loading) {
995
- return /* @__PURE__ */ jsxs12(Box12, { gap: 2, children: [
996
- /* @__PURE__ */ jsx12(Spinner2, { type: "dots" }),
997
- /* @__PURE__ */ jsx12(Text12, { children: "Loading available Apps\u2026" })
1147
+ return /* @__PURE__ */ jsxs13(Box13, { gap: 2, children: [
1148
+ /* @__PURE__ */ jsx13(Spinner2, { type: "dots" }),
1149
+ /* @__PURE__ */ jsx13(Text13, { children: "Loading available Apps\u2026" })
998
1150
  ] });
999
1151
  }
1000
1152
  if (error) {
1001
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", gap: 1, children: [
1002
- /* @__PURE__ */ jsx12(Text12, { color: "red", bold: true, children: "Failed to load Apps" }),
1003
- /* @__PURE__ */ jsx12(Text12, { color: "red", children: error })
1153
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", gap: 1, children: [
1154
+ /* @__PURE__ */ jsx13(Text13, { color: "red", bold: true, children: "Failed to load Apps" }),
1155
+ /* @__PURE__ */ jsx13(Text13, { color: "red", children: error })
1004
1156
  ] });
1005
1157
  }
1006
1158
  if (apps.length === 0) {
1007
- return /* @__PURE__ */ jsx12(Text12, { color: "yellow", children: "No Apps available. Contact your administrator." });
1159
+ return /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: "No Apps available. Contact your administrator." });
1008
1160
  }
1009
- return /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", children: apps.map((app, i) => {
1161
+ return /* @__PURE__ */ jsx13(Box13, { flexDirection: "column", children: apps.map((app, i) => {
1010
1162
  const isCursor = i === cursor;
1011
- return /* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
1012
- /* @__PURE__ */ jsx12(Text12, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
1013
- /* @__PURE__ */ jsx12(Text12, { bold: isCursor, children: app.name }),
1014
- /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1163
+ return /* @__PURE__ */ jsxs13(Box13, { gap: 1, children: [
1164
+ /* @__PURE__ */ jsx13(Text13, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
1165
+ /* @__PURE__ */ jsx13(Text13, { bold: isCursor, children: app.name }),
1166
+ /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
1015
1167
  "(",
1016
1168
  app.id,
1017
1169
  ")"
@@ -1019,26 +1171,26 @@ var AppSelect = ({ token, userId, orgId, onSubmit }) => {
1019
1171
  ] }, app.id);
1020
1172
  }) });
1021
1173
  };
1022
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
1023
- /* @__PURE__ */ jsx12(Banner, { userId, orgId }),
1024
- /* @__PURE__ */ jsx12(StepShell, { title: "Select the App you are building an Extension for:", children: renderContent() })
1174
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
1175
+ /* @__PURE__ */ jsx13(Banner, { userId, orgId }),
1176
+ /* @__PURE__ */ jsx13(StepShell, { title: "Select the App you are building an Extension for:", children: renderContent() })
1025
1177
  ] });
1026
1178
  };
1027
1179
 
1028
1180
  // src/components/ExtensionSelect.tsx
1029
- import { Box as Box13, Text as Text13, useInput as useInput8 } from "ink";
1181
+ import { Box as Box14, Text as Text14, useInput as useInput9 } from "ink";
1030
1182
  import Spinner3 from "ink-spinner";
1031
- import { useEffect as useEffect3, useState as useState8 } from "react";
1032
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1183
+ import { useEffect as useEffect3, useState as useState9 } from "react";
1184
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
1033
1185
  var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
1034
- const [extensions, setExtensions] = useState8([]);
1035
- const [loading, setLoading] = useState8(true);
1036
- const [error, setError] = useState8();
1037
- const [cursor, setCursor] = useState8(0);
1186
+ const [extensions, setExtensions] = useState9([]);
1187
+ const [loading, setLoading] = useState9(true);
1188
+ const [error, setError] = useState9();
1189
+ const [cursor, setCursor] = useState9(0);
1038
1190
  useEffect3(() => {
1039
1191
  fetchExtensions(token, appId).then((byId) => setExtensions(Object.values(byId))).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
1040
1192
  }, [appId, token]);
1041
- useInput8((_, key) => {
1193
+ useInput9((_, key) => {
1042
1194
  if (key.upArrow) {
1043
1195
  if (!loading && !error && extensions.length > 0) {
1044
1196
  setCursor((c) => Math.max(0, c - 1));
@@ -1059,30 +1211,30 @@ var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
1059
1211
  });
1060
1212
  const renderContent = () => {
1061
1213
  if (loading) {
1062
- return /* @__PURE__ */ jsxs13(Box13, { gap: 2, children: [
1063
- /* @__PURE__ */ jsx13(Spinner3, { type: "dots" }),
1064
- /* @__PURE__ */ jsx13(Text13, { children: "Loading Extensions\u2026" })
1214
+ return /* @__PURE__ */ jsxs14(Box14, { gap: 2, children: [
1215
+ /* @__PURE__ */ jsx14(Spinner3, { type: "dots" }),
1216
+ /* @__PURE__ */ jsx14(Text14, { children: "Loading Extensions\u2026" })
1065
1217
  ] });
1066
1218
  }
1067
1219
  if (error) {
1068
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", gap: 1, children: [
1069
- /* @__PURE__ */ jsx13(Text13, { color: "red", bold: true, children: "Failed to load Extensions" }),
1070
- /* @__PURE__ */ jsx13(Text13, { color: "red", children: error })
1220
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", gap: 1, children: [
1221
+ /* @__PURE__ */ jsx14(Text14, { color: "red", bold: true, children: "Failed to load Extensions" }),
1222
+ /* @__PURE__ */ jsx14(Text14, { color: "red", children: error })
1071
1223
  ] });
1072
1224
  }
1073
1225
  if (extensions.length === 0) {
1074
- return /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: "No Extensions found for this App." });
1226
+ return /* @__PURE__ */ jsx14(Text14, { color: "yellow", children: "No Extensions found for this App." });
1075
1227
  }
1076
- return /* @__PURE__ */ jsx13(Box13, { flexDirection: "column", children: extensions.map((ext, i) => {
1228
+ return /* @__PURE__ */ jsx14(Box14, { flexDirection: "column", children: extensions.map((ext, i) => {
1077
1229
  const isCursor = i === cursor;
1078
- return /* @__PURE__ */ jsxs13(Box13, { gap: 1, children: [
1079
- /* @__PURE__ */ jsx13(Text13, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
1080
- /* @__PURE__ */ jsx13(Text13, { bold: isCursor, children: ext.manifest.name }),
1081
- /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
1230
+ return /* @__PURE__ */ jsxs14(Box14, { gap: 1, children: [
1231
+ /* @__PURE__ */ jsx14(Text14, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
1232
+ /* @__PURE__ */ jsx14(Text14, { bold: isCursor, children: ext.manifest.name }),
1233
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
1082
1234
  "v",
1083
1235
  ext.manifest.version
1084
1236
  ] }),
1085
- /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
1237
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
1086
1238
  "(",
1087
1239
  ext.id,
1088
1240
  ")"
@@ -1090,7 +1242,7 @@ var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
1090
1242
  ] }, ext.id);
1091
1243
  }) });
1092
1244
  };
1093
- return /* @__PURE__ */ jsx13(
1245
+ return /* @__PURE__ */ jsx14(
1094
1246
  StepShell,
1095
1247
  {
1096
1248
  title: command === "update" /* UPDATE */ ? "Select an Extension to update:" : "Select an existing Extension to scaffold:",
@@ -1161,10 +1313,11 @@ var readDevContext = async (projectRoot) => {
1161
1313
  const stackableEnv = await readEnvFile(join(projectRoot, ".env.stackable"));
1162
1314
  const env = await readEnvFile(join(projectRoot, ".env"));
1163
1315
  let extensionName = stackableEnv.EXTENSION_NAME || "Unknown Extension";
1316
+ let manifest = null;
1164
1317
  try {
1165
1318
  const manifestPath = join(projectRoot, "packages/extension/public/manifest.json");
1166
1319
  const manifestContent = await readFile(manifestPath, "utf8");
1167
- const manifest = JSON.parse(manifestContent);
1320
+ manifest = JSON.parse(manifestContent);
1168
1321
  extensionName = manifest.name;
1169
1322
  } catch {
1170
1323
  }
@@ -1179,7 +1332,8 @@ var readDevContext = async (projectRoot) => {
1179
1332
  appName: stackableEnv.APP_NAME || null,
1180
1333
  orgId: stackableEnv.ORG_ID || null,
1181
1334
  extensionPort,
1182
- previewPort
1335
+ previewPort,
1336
+ manifest
1183
1337
  };
1184
1338
  };
1185
1339
  var DEV_LOCAL_ENV = ".env.development.local";
@@ -1209,11 +1363,13 @@ var writeDevContext = async (projectRoot, ctx) => {
1209
1363
  await writeEnvFile(join(projectRoot, ".env.stackable"), env);
1210
1364
  };
1211
1365
 
1212
- // src/lib/scaffold.ts
1366
+ // src/lib/utils.ts
1213
1367
  var toKebabCase = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1368
+
1369
+ // src/lib/scaffold.ts
1214
1370
  var isTextFile = (filePath) => /\.(ts|tsx|js|jsx|json|md|html|yml|yaml|env|gitignore|nvmrc)$/i.test(filePath);
1215
1371
  var normalizeTargets = (targets) => Array.from(new Set(targets));
1216
- var derivePermissions = (targets) => {
1372
+ var deriveScaffoldPermissions = (targets) => {
1217
1373
  const permissions = /* @__PURE__ */ new Set();
1218
1374
  for (const target of targets) {
1219
1375
  for (const permission of TARGET_PERMISSION_MAP[target] ?? DEFAULT_PERMISSIONS) {
@@ -1539,7 +1695,7 @@ var scaffold = async (options) => {
1539
1695
  });
1540
1696
  if (flavor === "starter") {
1541
1697
  const selectedTargets = normalizeTargets(options.targets);
1542
- const derivedPermissions = derivePermissions(selectedTargets);
1698
+ const derivedPermissions = deriveScaffoldPermissions(selectedTargets);
1543
1699
  await generateManifest(dir, options.name, selectedTargets, derivedPermissions);
1544
1700
  await generateSurfaceFiles(dir, selectedTargets);
1545
1701
  await rewriteExtensionIndex(dir, options.extensionId || options.name, selectedTargets);
@@ -1557,17 +1713,18 @@ var scaffold = async (options) => {
1557
1713
  appName: options.appName || null,
1558
1714
  extensionName: options.name,
1559
1715
  extensionPort: options.extensionPort,
1560
- previewPort: options.previewPort
1716
+ previewPort: options.previewPort,
1717
+ manifest: null
1561
1718
  });
1562
1719
  return options;
1563
1720
  };
1564
1721
 
1565
1722
  // src/App.tsx
1566
- import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
1723
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
1567
1724
  var STEPS = {
1568
1725
  ["create" /* CREATE */]: ["app", "name", "template", "targets", "settings", "confirm"],
1569
1726
  ["scaffold" /* SCAFFOLD */]: ["app", "extensionSelect", "confirmTargets", "settings", "confirm"],
1570
- ["update" /* UPDATE */]: ["app", "extensionSelect", "updateSettings", "confirm"],
1727
+ ["update" /* UPDATE */]: ["app", "extensionSelect", "updateSettings", "manifestReview", "confirm"],
1571
1728
  ["dev" /* DEV */]: []
1572
1729
  // Dev command has no wizard steps
1573
1730
  };
@@ -1589,8 +1746,7 @@ var PROGRESS_STEPS = {
1589
1746
  ["dev" /* DEV */]: []
1590
1747
  // Dev command has no progress steps
1591
1748
  };
1592
- var toKebabCase2 = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1593
- var derivePermissions2 = (targets) => {
1749
+ var deriveRegistryPermissions = (targets) => {
1594
1750
  const permissions = /* @__PURE__ */ new Set();
1595
1751
  for (const target of targets) {
1596
1752
  const mapped = TARGET_PERMISSION_MAP[target];
@@ -1609,33 +1765,37 @@ var derivePermissions2 = (targets) => {
1609
1765
  };
1610
1766
  var App = ({ command, token, userId, orgId, initialName, initialExtensionId, options }) => {
1611
1767
  const { exit } = useApp();
1612
- const [step, setStep] = useState9("app");
1613
- const [name, setName] = useState9(initialName ?? options?.name ?? "");
1614
- const [extensionId, setExtensionId] = useState9(initialExtensionId ?? "");
1615
- const [extensionVersion, setExtensionVersion] = useState9("");
1616
- const [bundleUrl, setBundleUrl] = useState9(options?.bundleUrl ?? "");
1617
- const [enabled, setEnabled] = useState9(
1768
+ const [step, setStep] = useState10("app");
1769
+ const [name, setName] = useState10(initialName ?? options?.name ?? "");
1770
+ const [extensionId, setExtensionId] = useState10(initialExtensionId ?? "");
1771
+ const [extensionVersion, setExtensionVersion] = useState10("");
1772
+ const [bundleUrl, setBundleUrl] = useState10(options?.bundleUrl ?? "");
1773
+ const [enabled, setEnabled] = useState10(
1618
1774
  options?.enabled !== void 0 ? options.enabled !== "false" : true
1619
1775
  );
1620
- const [versionOverride, setVersionOverride] = useState9(void 0);
1621
- const [forceMajor, setForceMajor] = useState9(false);
1622
- const [initialExtension, setInitialExtension] = useState9(null);
1623
- const [templateFlavor, setTemplateFlavor] = useState9(
1776
+ const [versionOverride, setVersionOverride] = useState10(void 0);
1777
+ const [forceMajor, setForceMajor] = useState10(false);
1778
+ const [initialExtension, setInitialExtension] = useState10(null);
1779
+ const [templateFlavor, setTemplateFlavor] = useState10(
1624
1780
  options?.template ?? "starter"
1625
1781
  );
1626
- const [targets, setTargets] = useState9(
1782
+ const [targets, setTargets] = useState10(
1627
1783
  options?.targets ? options.targets.split(",").map((t) => t.trim()) : []
1628
1784
  );
1629
- const [selectedApp, setSelectedApp] = useState9(null);
1630
- const [extensionPort, setExtensionPort] = useState9(
1785
+ const [selectedApp, setSelectedApp] = useState10(null);
1786
+ const [extensionPort, setExtensionPort] = useState10(
1631
1787
  options?.extensionPort ? parseInt(options.extensionPort, 10) : 6543
1632
1788
  );
1633
- const [previewPort, setPreviewPort] = useState9(
1789
+ const [previewPort, setPreviewPort] = useState10(
1634
1790
  options?.previewPort ? parseInt(options.previewPort, 10) : 6544
1635
1791
  );
1636
- const [outputDir, setOutputDir] = useState9("");
1637
- const [progressSteps, setProgressSteps] = useState9(PROGRESS_STEPS[command]);
1638
- const [errorMessage, setErrorMessage] = useState9();
1792
+ const [registryManifest, setRegistryManifest] = useState10(null);
1793
+ const [localManifest, setLocalManifest] = useState10(null);
1794
+ const [confirmedPermissions, setConfirmedPermissions] = useState10([]);
1795
+ const [confirmedAllowedDomains, setConfirmedAllowedDomains] = useState10([]);
1796
+ const [outputDir, setOutputDir] = useState10("");
1797
+ const [progressSteps, setProgressSteps] = useState10(PROGRESS_STEPS[command]);
1798
+ const [errorMessage, setErrorMessage] = useState10();
1639
1799
  const updateStep = useCallback((index, status) => {
1640
1800
  setProgressSteps((prev) => prev.map((s, i) => i === index ? { ...s, status } : s));
1641
1801
  }, []);
@@ -1670,8 +1830,47 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1670
1830
  return idx > 0 ? steps[idx - 1] : prev;
1671
1831
  });
1672
1832
  }, [activeSteps]);
1673
- const handleAppSelect = (app) => {
1833
+ const handleAppSelect = async (app) => {
1674
1834
  setSelectedApp(app);
1835
+ if (command === "update" /* UPDATE */ && initialExtensionId) {
1836
+ try {
1837
+ const extensions = await fetchExtensions(token, app.id);
1838
+ const ext = extensions[initialExtensionId];
1839
+ if (!ext) {
1840
+ setErrorMessage(
1841
+ `Extension "${initialExtensionId}" not found or is disabled. If disabled, re-enable it in the admin dashboard before updating.`
1842
+ );
1843
+ setStep("error");
1844
+ return;
1845
+ }
1846
+ setName(ext.manifest.name);
1847
+ setExtensionId(ext.id);
1848
+ setExtensionVersion(ext.manifest.version);
1849
+ setTargets(ext.manifest.targets);
1850
+ setBundleUrl(ext.bundleUrl);
1851
+ setEnabled(ext.enabled ?? true);
1852
+ setInitialExtension({
1853
+ name: ext.manifest.name,
1854
+ targets: ext.manifest.targets,
1855
+ bundleUrl: ext.bundleUrl
1856
+ });
1857
+ setRegistryManifest(ext.manifest);
1858
+ const projectRoot = options?.dir || process.cwd();
1859
+ try {
1860
+ const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
1861
+ const content = await readFile3(manifestPath, "utf8");
1862
+ setLocalManifest(JSON.parse(content));
1863
+ } catch {
1864
+ setLocalManifest(null);
1865
+ }
1866
+ setStep("updateSettings");
1867
+ } catch (err) {
1868
+ const message = err instanceof Error ? err.message : String(err);
1869
+ setErrorMessage(message);
1870
+ setStep("error");
1871
+ }
1872
+ return;
1873
+ }
1675
1874
  if (command === "scaffold" /* SCAFFOLD */ || command === "update" /* UPDATE */) {
1676
1875
  setStep("extensionSelect");
1677
1876
  return;
@@ -1682,7 +1881,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1682
1881
  if (meta.skipTargetStep && meta.defaultTargets) {
1683
1882
  setTargets(meta.defaultTargets);
1684
1883
  if (options?.extensionPort || options?.previewPort) {
1685
- setOutputDir(join3(process.cwd(), toKebabCase2(initialName)));
1884
+ setOutputDir(join3(process.cwd(), toKebabCase(initialName)));
1686
1885
  setStep("confirm");
1687
1886
  } else {
1688
1887
  setStep("settings");
@@ -1697,7 +1896,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1697
1896
  setStep("name");
1698
1897
  }
1699
1898
  };
1700
- const handleExtensionSelect = (ext) => {
1899
+ const handleExtensionSelect = async (ext) => {
1701
1900
  setName(ext.manifest.name);
1702
1901
  setExtensionId(ext.id);
1703
1902
  setExtensionVersion(ext.manifest.version);
@@ -1709,6 +1908,15 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1709
1908
  targets: ext.manifest.targets,
1710
1909
  bundleUrl: ext.bundleUrl
1711
1910
  });
1911
+ setRegistryManifest(ext.manifest);
1912
+ const projectRoot = options?.dir || process.cwd();
1913
+ try {
1914
+ const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
1915
+ const content = await readFile3(manifestPath, "utf8");
1916
+ setLocalManifest(JSON.parse(content));
1917
+ } catch {
1918
+ setLocalManifest(null);
1919
+ }
1712
1920
  if (command === "scaffold" /* SCAFFOLD */) {
1713
1921
  setStep("confirmTargets");
1714
1922
  } else if (command === "update" /* UPDATE */) {
@@ -1718,7 +1926,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1718
1926
  const handleConfirmTargets = (value) => {
1719
1927
  setTargets(value);
1720
1928
  if (options?.extensionPort || options?.previewPort) {
1721
- setOutputDir(join3(process.cwd(), toKebabCase2(extensionId || name)));
1929
+ setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
1722
1930
  setStep("confirm");
1723
1931
  } else {
1724
1932
  setStep("settings");
@@ -1726,13 +1934,13 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1726
1934
  };
1727
1935
  const handleName = (value) => {
1728
1936
  setName(value);
1729
- setExtensionId(toKebabCase2(value));
1937
+ setExtensionId(toKebabCase(value));
1730
1938
  if (options?.template) {
1731
1939
  const meta = TEMPLATE_FLAVOR_META[templateFlavor];
1732
1940
  if (meta.skipTargetStep && meta.defaultTargets) {
1733
1941
  setTargets(meta.defaultTargets);
1734
1942
  if (options?.extensionPort || options?.previewPort) {
1735
- setOutputDir(join3(process.cwd(), toKebabCase2(value)));
1943
+ setOutputDir(join3(process.cwd(), toKebabCase(value)));
1736
1944
  setStep("confirm");
1737
1945
  } else {
1738
1946
  setStep("settings");
@@ -1750,7 +1958,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1750
1958
  if (meta.skipTargetStep && meta.defaultTargets) {
1751
1959
  setTargets(meta.defaultTargets);
1752
1960
  if (options?.extensionPort || options?.previewPort) {
1753
- setOutputDir(join3(process.cwd(), toKebabCase2(extensionId || name)));
1961
+ setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
1754
1962
  setStep("confirm");
1755
1963
  } else {
1756
1964
  setStep("settings");
@@ -1762,7 +1970,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1762
1970
  const handleTargets = (value) => {
1763
1971
  setTargets(value);
1764
1972
  if (options?.extensionPort || options?.previewPort) {
1765
- setOutputDir(join3(process.cwd(), toKebabCase2(extensionId || name)));
1973
+ setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
1766
1974
  setStep("confirm");
1767
1975
  } else {
1768
1976
  setStep("settings");
@@ -1784,7 +1992,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1784
1992
  if (targetsChanged) return `${major}.${minor + 1}.0`;
1785
1993
  const nameChanged = newName !== initialExtension.name;
1786
1994
  if (nameChanged) return `${major}.${minor}.${patch + 1}`;
1787
- return currentVersion;
1995
+ return `${major}.${minor}.${patch + 1}`;
1788
1996
  };
1789
1997
  const handleConfirm = async () => {
1790
1998
  if (command === "update" /* UPDATE */) {
@@ -1798,8 +2006,8 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1798
2006
  name,
1799
2007
  version: resolvedVersion,
1800
2008
  targets,
1801
- permissions: derivePermissions2(targets),
1802
- allowedDomains: []
2009
+ permissions: confirmedPermissions,
2010
+ allowedDomains: confirmedAllowedDomains
1803
2011
  },
1804
2012
  bundleUrl: bundleUrl || void 0,
1805
2013
  enabled
@@ -1817,7 +2025,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1817
2025
  setStep("scaffolding");
1818
2026
  setProgressSteps(PROGRESS_STEPS[command]);
1819
2027
  try {
1820
- let resolvedExtensionId = extensionId || toKebabCase2(name);
2028
+ let resolvedExtensionId = extensionId || toKebabCase(name);
1821
2029
  let scaffoldStepOffset = 0;
1822
2030
  if (command === "create" /* CREATE */) {
1823
2031
  scaffoldStepOffset = 1;
@@ -1827,7 +2035,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1827
2035
  name,
1828
2036
  version: "0.0.0",
1829
2037
  targets,
1830
- permissions: derivePermissions2(targets),
2038
+ permissions: deriveRegistryPermissions(targets),
1831
2039
  allowedDomains: []
1832
2040
  },
1833
2041
  bundleUrl: `http://localhost:${extensionPort}`
@@ -1849,6 +2057,17 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1849
2057
  previewPort
1850
2058
  });
1851
2059
  updateStep(scaffoldStepOffset + 0, "done");
2060
+ if (command === "create" /* CREATE */) {
2061
+ const manifestPath = join3(outputDir, "packages/extension/public/manifest.json");
2062
+ try {
2063
+ const manifestContent = await readFile3(manifestPath, "utf8");
2064
+ const manifest = JSON.parse(manifestContent);
2065
+ await updateExtension(token, selectedApp.id, resolvedExtensionId, {
2066
+ manifest: { ...manifest, allowedDomains: [] }
2067
+ });
2068
+ } catch {
2069
+ }
2070
+ }
1852
2071
  updateStep(scaffoldStepOffset + 1, "running");
1853
2072
  await new Promise((r) => setTimeout(r, 200));
1854
2073
  updateStep(scaffoldStepOffset + 1, "done");
@@ -1871,7 +2090,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1871
2090
  };
1872
2091
  switch (step) {
1873
2092
  case "app": {
1874
- return /* @__PURE__ */ jsx14(
2093
+ return /* @__PURE__ */ jsx15(
1875
2094
  AppSelect,
1876
2095
  {
1877
2096
  token,
@@ -1882,7 +2101,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1882
2101
  );
1883
2102
  }
1884
2103
  case "extensionSelect": {
1885
- return /* @__PURE__ */ jsx14(
2104
+ return /* @__PURE__ */ jsx15(
1886
2105
  ExtensionSelect,
1887
2106
  {
1888
2107
  appId: selectedApp.id,
@@ -1894,7 +2113,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1894
2113
  );
1895
2114
  }
1896
2115
  case "confirmTargets": {
1897
- return /* @__PURE__ */ jsx14(
2116
+ return /* @__PURE__ */ jsx15(
1898
2117
  TargetSelect,
1899
2118
  {
1900
2119
  availableTargets: selectedApp?.targets ?? [],
@@ -1905,7 +2124,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1905
2124
  );
1906
2125
  }
1907
2126
  case "name": {
1908
- return /* @__PURE__ */ jsx14(
2127
+ return /* @__PURE__ */ jsx15(
1909
2128
  NamePrompt,
1910
2129
  {
1911
2130
  initialValue: name,
@@ -1915,7 +2134,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1915
2134
  );
1916
2135
  }
1917
2136
  case "template": {
1918
- return /* @__PURE__ */ jsx14(
2137
+ return /* @__PURE__ */ jsx15(
1919
2138
  TemplateSelect,
1920
2139
  {
1921
2140
  onSubmit: handleTemplateSelect,
@@ -1924,7 +2143,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1924
2143
  );
1925
2144
  }
1926
2145
  case "targets": {
1927
- return /* @__PURE__ */ jsx14(
2146
+ return /* @__PURE__ */ jsx15(
1928
2147
  TargetSelect,
1929
2148
  {
1930
2149
  availableTargets: selectedApp?.targets ?? [],
@@ -1934,29 +2153,34 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1934
2153
  );
1935
2154
  }
1936
2155
  case "settings": {
1937
- return /* @__PURE__ */ jsx14(
2156
+ return /* @__PURE__ */ jsx15(
1938
2157
  SettingsPrompt,
1939
2158
  {
1940
- defaultDir: join3(process.cwd(), toKebabCase2(extensionId || name)),
2159
+ defaultDir: join3(process.cwd(), toKebabCase(extensionId || name)),
1941
2160
  onSubmit: handleSettings,
1942
2161
  onBack: goBack
1943
2162
  }
1944
2163
  );
1945
2164
  }
1946
2165
  case "confirm": {
1947
- return /* @__PURE__ */ jsx14(
2166
+ return /* @__PURE__ */ jsx15(
1948
2167
  Confirm,
1949
2168
  {
1950
2169
  command,
1951
2170
  name,
1952
2171
  templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0,
1953
2172
  targets,
2173
+ registryTargets: command === "update" /* UPDATE */ ? registryManifest?.targets : void 0,
1954
2174
  outputDir,
1955
2175
  previewPort,
1956
2176
  extensionPort,
1957
2177
  extensionVersion: command !== "create" /* CREATE */ ? extensionVersion : void 0,
1958
2178
  bundleUrl: command === "update" /* UPDATE */ ? bundleUrl : void 0,
1959
2179
  enabled: command === "update" /* UPDATE */ ? enabled : void 0,
2180
+ permissions: command === "update" /* UPDATE */ ? confirmedPermissions : void 0,
2181
+ allowedDomains: command === "update" /* UPDATE */ ? confirmedAllowedDomains : void 0,
2182
+ registryPermissions: command === "update" /* UPDATE */ ? registryManifest?.permissions : void 0,
2183
+ registryAllowedDomains: command === "update" /* UPDATE */ ? registryManifest?.allowedDomains : void 0,
1960
2184
  newVersion: command === "update" /* UPDATE */ ? options?.setVersion ?? versionOverride ?? computeVersionBump(extensionVersion, name, targets, bundleUrl, forceMajor) : void 0,
1961
2185
  onVersionOverride: command === "update" /* UPDATE */ ? setVersionOverride : void 0,
1962
2186
  onConfirm: handleConfirm,
@@ -1966,10 +2190,10 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1966
2190
  );
1967
2191
  }
1968
2192
  case "scaffolding": {
1969
- return /* @__PURE__ */ jsx14(ScaffoldProgress, { steps: progressSteps });
2193
+ return /* @__PURE__ */ jsx15(ScaffoldProgress, { steps: progressSteps });
1970
2194
  }
1971
2195
  case "updateSettings": {
1972
- return /* @__PURE__ */ jsx14(
2196
+ return /* @__PURE__ */ jsx15(
1973
2197
  UpdateSettingsPrompt,
1974
2198
  {
1975
2199
  name,
@@ -1984,6 +2208,21 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1984
2208
  setEnabled(updated.enabled);
1985
2209
  setForceMajor(updated.forceMajor);
1986
2210
  setVersionOverride(void 0);
2211
+ setStep("manifestReview");
2212
+ },
2213
+ onBack: goBack
2214
+ }
2215
+ );
2216
+ }
2217
+ case "manifestReview": {
2218
+ return /* @__PURE__ */ jsx15(
2219
+ ManifestReviewPrompt,
2220
+ {
2221
+ localManifest,
2222
+ registryManifest,
2223
+ onSubmit: (result) => {
2224
+ setConfirmedPermissions(result.permissions);
2225
+ setConfirmedAllowedDomains(result.allowedDomains);
1987
2226
  setStep("confirm");
1988
2227
  },
1989
2228
  onBack: goBack
@@ -1991,46 +2230,46 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1991
2230
  );
1992
2231
  }
1993
2232
  case "updating": {
1994
- return /* @__PURE__ */ jsx14(ScaffoldProgress, { steps: progressSteps });
2233
+ return /* @__PURE__ */ jsx15(ScaffoldProgress, { steps: progressSteps });
1995
2234
  }
1996
2235
  case "updateDone": {
1997
- return /* @__PURE__ */ jsx14(StepShell, { title: "Extension updated", onBack: goBack, children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", gap: 1, children: [
1998
- /* @__PURE__ */ jsx14(Text14, { color: "green", bold: true, children: "Extension updated successfully!" }),
1999
- /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2236
+ return /* @__PURE__ */ jsx15(StepShell, { title: "Extension updated", onBack: goBack, children: /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", gap: 1, children: [
2237
+ /* @__PURE__ */ jsx15(Text15, { color: "green", bold: true, children: "Extension updated successfully!" }),
2238
+ /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
2000
2239
  "Name: ",
2001
2240
  name
2002
2241
  ] }),
2003
- /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2242
+ /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
2004
2243
  "ID: ",
2005
2244
  extensionId
2006
2245
  ] }),
2007
- /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2246
+ /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
2008
2247
  "Version: ",
2009
2248
  extensionVersion
2010
2249
  ] })
2011
2250
  ] }) });
2012
2251
  }
2013
2252
  case "done": {
2014
- return /* @__PURE__ */ jsx14(Done, { name, outputDir, templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0 });
2253
+ return /* @__PURE__ */ jsx15(Done, { name, outputDir, templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0 });
2015
2254
  }
2016
2255
  case "error": {
2017
- return /* @__PURE__ */ jsx14(StepShell, { title: "Operation failed", onBack: goBack, children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", gap: 1, children: [
2018
- /* @__PURE__ */ jsx14(Text14, { color: "red", bold: true, children: "An error occurred" }),
2019
- errorMessage && /* @__PURE__ */ jsx14(Text14, { color: "red", children: errorMessage })
2256
+ return /* @__PURE__ */ jsx15(StepShell, { title: "Operation failed", onBack: goBack, children: /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", gap: 1, children: [
2257
+ /* @__PURE__ */ jsx15(Text15, { color: "red", bold: true, children: "An error occurred" }),
2258
+ errorMessage && /* @__PURE__ */ jsx15(Text15, { color: "red", children: errorMessage })
2020
2259
  ] }) });
2021
2260
  }
2022
2261
  default: {
2023
- return /* @__PURE__ */ jsx14(StepShell, { title: "Scaffold failed", onBack: goBack, children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", gap: 1, children: [
2024
- /* @__PURE__ */ jsx14(Text14, { color: "red", bold: true, children: "An error occurred" }),
2025
- errorMessage && /* @__PURE__ */ jsx14(Text14, { color: "red", children: errorMessage })
2262
+ return /* @__PURE__ */ jsx15(StepShell, { title: "Scaffold failed", onBack: goBack, children: /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", gap: 1, children: [
2263
+ /* @__PURE__ */ jsx15(Text15, { color: "red", bold: true, children: "An error occurred" }),
2264
+ errorMessage && /* @__PURE__ */ jsx15(Text15, { color: "red", children: errorMessage })
2026
2265
  ] }) });
2027
2266
  }
2028
2267
  }
2029
2268
  };
2030
2269
 
2031
2270
  // src/components/DevApp.tsx
2032
- import { useRef, useState as useState11, useEffect as useEffect6, useCallback as useCallback2 } from "react";
2033
- import { useInput as useInput10, Box as Box17, Text as Text17 } from "ink";
2271
+ import { useRef, useState as useState12, useEffect as useEffect6, useCallback as useCallback2 } from "react";
2272
+ import { useInput as useInput11, Box as Box18, Text as Text18 } from "ink";
2034
2273
 
2035
2274
  // src/lib/tunnel.ts
2036
2275
  import { Tunnel } from "cloudflared";
@@ -2064,12 +2303,12 @@ var startDevServer = (projectRoot) => {
2064
2303
  };
2065
2304
 
2066
2305
  // src/components/DevSetup.tsx
2067
- import { Box as Box15, Text as Text15 } from "ink";
2068
- import { useState as useState10, useEffect as useEffect4 } from "react";
2069
- import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
2306
+ import { Box as Box16, Text as Text16 } from "ink";
2307
+ import { useState as useState11, useEffect as useEffect4 } from "react";
2308
+ import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
2070
2309
  var DevSetup = ({ initialContext, token, onReady }) => {
2071
- const [step, setStep] = useState10("app");
2072
- const [selectedApp, setSelectedApp] = useState10(null);
2310
+ const [step, setStep] = useState11("app");
2311
+ const [selectedApp, setSelectedApp] = useState11(null);
2073
2312
  useEffect4(() => {
2074
2313
  if (initialContext.appId) {
2075
2314
  setStep("extension");
@@ -2087,9 +2326,9 @@ var DevSetup = ({ initialContext, token, onReady }) => {
2087
2326
  });
2088
2327
  };
2089
2328
  if (step === "app") {
2090
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
2091
- /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsx15(Text15, { children: "Select the App for your extension:" }) }),
2092
- /* @__PURE__ */ jsx15(
2329
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2330
+ /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { children: "Select the App for your extension:" }) }),
2331
+ /* @__PURE__ */ jsx16(
2093
2332
  AppSelect,
2094
2333
  {
2095
2334
  token,
@@ -2098,9 +2337,9 @@ var DevSetup = ({ initialContext, token, onReady }) => {
2098
2337
  )
2099
2338
  ] });
2100
2339
  }
2101
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
2102
- /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsx15(Text15, { children: "Select the Extension to develop:" }) }),
2103
- /* @__PURE__ */ jsx15(
2340
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2341
+ /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { children: "Select the Extension to develop:" }) }),
2342
+ /* @__PURE__ */ jsx16(
2104
2343
  ExtensionSelect,
2105
2344
  {
2106
2345
  token,
@@ -2112,9 +2351,9 @@ var DevSetup = ({ initialContext, token, onReady }) => {
2112
2351
  };
2113
2352
 
2114
2353
  // src/components/DevDashboard.tsx
2115
- import { Box as Box16, Text as Text16, useInput as useInput9 } from "ink";
2354
+ import { Box as Box17, Text as Text17, useInput as useInput10 } from "ink";
2116
2355
  import { useEffect as useEffect5 } from "react";
2117
- import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
2356
+ import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
2118
2357
  var DevDashboard = ({
2119
2358
  previewTunnelUrl,
2120
2359
  tunnelUrl,
@@ -2126,6 +2365,7 @@ var DevDashboard = ({
2126
2365
  extensionName,
2127
2366
  extensionPort,
2128
2367
  previewPort,
2368
+ manifestWarnings = [],
2129
2369
  onQuit
2130
2370
  }) => {
2131
2371
  useEffect5(() => {
@@ -2137,72 +2377,80 @@ var DevDashboard = ({
2137
2377
  process.off("SIGINT", handler);
2138
2378
  };
2139
2379
  }, [onQuit]);
2140
- useInput9((input, key) => {
2380
+ useInput10((input, key) => {
2141
2381
  if (input === "q" || key.ctrl && input === "c") {
2142
2382
  onQuit();
2143
2383
  }
2144
2384
  });
2145
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2146
- /* @__PURE__ */ jsx16(Banner, { userId, orgId }),
2147
- /* @__PURE__ */ jsxs16(
2385
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2386
+ /* @__PURE__ */ jsx17(Banner, { userId, orgId }),
2387
+ /* @__PURE__ */ jsxs17(
2148
2388
  StepShell,
2149
2389
  {
2150
2390
  title: "dev",
2151
2391
  hint: `Live development ${tunnelUrl ? "with" : "w/o"} Tunnel`,
2152
- footer: /* @__PURE__ */ jsx16(Box16, { flexDirection: "column", gap: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Press q or Ctrl-C to quit" }) }),
2392
+ footer: /* @__PURE__ */ jsx17(Box17, { flexDirection: "column", gap: 1, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Press q or Ctrl-C to quit" }) }),
2153
2393
  children: [
2154
- /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2155
- /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2156
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Extension:" }),
2157
- /* @__PURE__ */ jsxs16(Text16, { children: [
2394
+ /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2395
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2396
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Extension:" }),
2397
+ /* @__PURE__ */ jsxs17(Text17, { children: [
2158
2398
  extensionName,
2159
2399
  " (",
2160
2400
  extensionId,
2161
2401
  ")"
2162
2402
  ] })
2163
2403
  ] }),
2164
- /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2165
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "App:" }),
2166
- /* @__PURE__ */ jsx16(Text16, { children: `${appName ? `${appName} ` : ""}(${appId})` })
2404
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2405
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "App:" }),
2406
+ /* @__PURE__ */ jsx17(Text17, { children: `${appName ? `${appName} ` : ""}(${appId})` })
2167
2407
  ] }),
2168
- /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2169
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Bundle URL:" }),
2170
- /* @__PURE__ */ jsx16(Text16, { children: tunnelUrl || `http://localhost:${extensionPort}` })
2408
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2409
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Bundle URL:" }),
2410
+ /* @__PURE__ */ jsx17(Text17, { children: tunnelUrl || `http://localhost:${extensionPort}` })
2171
2411
  ] })
2172
2412
  ] }),
2173
- /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2174
- previewTunnelUrl && /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2175
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Tunnel Dev - Preview:" }),
2176
- /* @__PURE__ */ jsx16(Text16, { children: previewTunnelUrl })
2413
+ /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2414
+ previewTunnelUrl && /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2415
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Tunnel Dev - Preview:" }),
2416
+ /* @__PURE__ */ jsx17(Text17, { children: previewTunnelUrl })
2177
2417
  ] }),
2178
- /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2179
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Local Dev - Preview:" }),
2180
- /* @__PURE__ */ jsxs16(Text16, { children: [
2418
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2419
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Local Dev - Preview:" }),
2420
+ /* @__PURE__ */ jsxs17(Text17, { children: [
2181
2421
  "http://localhost:",
2182
2422
  previewPort
2183
2423
  ] })
2184
2424
  ] })
2185
2425
  ] }),
2186
- /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2187
- tunnelUrl && /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2188
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Tunnel Dev - Extension:" }),
2189
- /* @__PURE__ */ jsx16(Text16, { children: tunnelUrl })
2426
+ /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2427
+ tunnelUrl && /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2428
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Tunnel Dev - Extension:" }),
2429
+ /* @__PURE__ */ jsx17(Text17, { children: tunnelUrl })
2190
2430
  ] }),
2191
- /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2192
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Local Dev - Extension:" }),
2193
- /* @__PURE__ */ jsxs16(Text16, { children: [
2431
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2432
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Local Dev - Extension:" }),
2433
+ /* @__PURE__ */ jsxs17(Text17, { children: [
2194
2434
  "http://localhost:",
2195
2435
  extensionPort
2196
2436
  ] })
2197
2437
  ] })
2198
2438
  ] }),
2199
- /* @__PURE__ */ jsx16(Box16, { flexDirection: "column", children: tunnelUrl && /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2200
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Host Dev - Query Param:" }),
2201
- /* @__PURE__ */ jsxs16(Text16, { children: [
2439
+ /* @__PURE__ */ jsx17(Box17, { flexDirection: "column", children: tunnelUrl && /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2440
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Host Dev - Query Param:" }),
2441
+ /* @__PURE__ */ jsxs17(Text17, { children: [
2202
2442
  "?_stackable_dev=",
2203
2443
  encodeURIComponent(`${extensionId}:${tunnelUrl}`)
2204
2444
  ] })
2205
- ] }) })
2445
+ ] }) }),
2446
+ manifestWarnings.length > 0 && /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
2447
+ /* @__PURE__ */ jsx17(Text17, { color: "yellow", bold: true, children: "Local manifest differs from registry:" }),
2448
+ manifestWarnings.map((w, i) => /* @__PURE__ */ jsxs17(Text17, { color: "yellow", children: [
2449
+ " ",
2450
+ w
2451
+ ] }, i)),
2452
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " Run `stackable-app-extension update` to review and sync." })
2453
+ ] })
2206
2454
  ]
2207
2455
  }
2208
2456
  )
@@ -2210,16 +2458,17 @@ var DevDashboard = ({
2210
2458
  };
2211
2459
 
2212
2460
  // src/components/DevApp.tsx
2213
- import { jsx as jsx17 } from "react/jsx-runtime";
2461
+ import { jsx as jsx18 } from "react/jsx-runtime";
2214
2462
  var DevApp = ({ token, userId, orgId, options = {} }) => {
2215
- const [state, setState] = useState11("setup");
2216
- const [devContext, setDevContext] = useState11(null);
2217
- const [resolvedContext, setResolvedContext] = useState11(null);
2218
- const [tunnelUrl, setTunnelUrl] = useState11(null);
2219
- const [previewTunnelUrl, setPreviewTunnelUrl] = useState11(null);
2220
- const [tunnelHandle, setTunnelHandle] = useState11(null);
2221
- const [previewTunnelHandle, setPreviewTunnelHandle] = useState11(null);
2222
- const [devServerHandle, setDevServerHandle] = useState11(null);
2463
+ const [state, setState] = useState12("setup");
2464
+ const [devContext, setDevContext] = useState12(null);
2465
+ const [resolvedContext, setResolvedContext] = useState12(null);
2466
+ const [tunnelUrl, setTunnelUrl] = useState12(null);
2467
+ const [previewTunnelUrl, setPreviewTunnelUrl] = useState12(null);
2468
+ const [tunnelHandle, setTunnelHandle] = useState12(null);
2469
+ const [previewTunnelHandle, setPreviewTunnelHandle] = useState12(null);
2470
+ const [devServerHandle, setDevServerHandle] = useState12(null);
2471
+ const [manifestWarnings, setManifestWarnings] = useState12([]);
2223
2472
  const shuttingDown = useRef(false);
2224
2473
  const useTunnel = options.tunnel !== false;
2225
2474
  useEffect6(() => {
@@ -2240,6 +2489,31 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2240
2489
  extensionId: resolved.extensionId,
2241
2490
  appName: resolved.appName || null
2242
2491
  });
2492
+ if (devContext.manifest) {
2493
+ try {
2494
+ const extensions = await fetchExtensions(token, resolved.appId);
2495
+ const registryExt = extensions[resolved.extensionId];
2496
+ if (registryExt) {
2497
+ const localPerms = new Set(devContext.manifest.permissions);
2498
+ const registryPerms = new Set(registryExt.manifest.permissions);
2499
+ const missingPerms = [...localPerms].filter((p) => !registryPerms.has(p));
2500
+ const extraPerms = [...registryPerms].filter((p) => !localPerms.has(p));
2501
+ const localDomains = new Set(devContext.manifest.allowedDomains);
2502
+ const registryDomains = new Set(registryExt.manifest.allowedDomains);
2503
+ const missingDomains = [...localDomains].filter((d) => !registryDomains.has(d));
2504
+ const extraDomains = [...registryDomains].filter((d) => !localDomains.has(d));
2505
+ const warnings = [];
2506
+ if (missingPerms.length > 0) warnings.push(`Permissions in local but not registry: ${missingPerms.join(", ")}`);
2507
+ if (extraPerms.length > 0) warnings.push(`Permissions in registry but not local: ${extraPerms.join(", ")}`);
2508
+ if (missingDomains.length > 0) warnings.push(`Domains in local but not registry: ${missingDomains.join(", ")}`);
2509
+ if (extraDomains.length > 0) warnings.push(`Domains in registry but not local: ${extraDomains.join(", ")}`);
2510
+ if (warnings.length > 0) {
2511
+ setManifestWarnings(warnings);
2512
+ }
2513
+ }
2514
+ } catch {
2515
+ }
2516
+ }
2243
2517
  const extensionPort = options.extensionPort ? parseInt(options.extensionPort, 10) : devContext.extensionPort;
2244
2518
  const previewPort = options.previewPort ? parseInt(options.previewPort, 10) : devContext.previewPort;
2245
2519
  await patchViteAllowedHosts(devContext.projectRoot);
@@ -2268,7 +2542,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2268
2542
  setDevServerHandle(serverHandle);
2269
2543
  console.log("[dev] Ready");
2270
2544
  setState("running");
2271
- }, [devContext, options.extensionPort, options.previewPort, useTunnel]);
2545
+ }, [devContext, token, options.extensionPort, options.previewPort, useTunnel]);
2272
2546
  useEffect6(() => {
2273
2547
  if (state === "setup" && devContext && devContext.appId && devContext.extensionId) {
2274
2548
  handleSetupReady({
@@ -2304,7 +2578,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2304
2578
  console.log("[dev] Done");
2305
2579
  process.exit(0);
2306
2580
  };
2307
- useInput10((input, key) => {
2581
+ useInput11((input, key) => {
2308
2582
  if (input === "c" && key.ctrl) {
2309
2583
  if (state === "running") {
2310
2584
  handleQuit();
@@ -2315,7 +2589,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2315
2589
  });
2316
2590
  if (state === "setup" && devContext) {
2317
2591
  if (!devContext.appId || !devContext.extensionId) {
2318
- return /* @__PURE__ */ jsx17(
2592
+ return /* @__PURE__ */ jsx18(
2319
2593
  DevSetup,
2320
2594
  {
2321
2595
  token,
@@ -2327,7 +2601,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2327
2601
  return null;
2328
2602
  }
2329
2603
  if (state === "running" && devContext && resolvedContext) {
2330
- return /* @__PURE__ */ jsx17(
2604
+ return /* @__PURE__ */ jsx18(
2331
2605
  DevDashboard,
2332
2606
  {
2333
2607
  previewTunnelUrl,
@@ -2340,6 +2614,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2340
2614
  extensionId: resolvedContext.extensionId,
2341
2615
  extensionPort: options.extensionPort ? parseInt(options.extensionPort, 10) : devContext.extensionPort,
2342
2616
  previewPort: options.previewPort ? parseInt(options.previewPort, 10) : devContext.previewPort,
2617
+ manifestWarnings,
2343
2618
  onQuit: handleQuit
2344
2619
  }
2345
2620
  );
@@ -2347,13 +2622,13 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2347
2622
  if (state === "stopping") {
2348
2623
  return null;
2349
2624
  }
2350
- return /* @__PURE__ */ jsx17(Box17, { children: /* @__PURE__ */ jsx17(Text17, { children: "Loading..." }) });
2625
+ return /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsx18(Text18, { children: "Loading..." }) });
2351
2626
  };
2352
2627
 
2353
2628
  // src/components/AIScaffold.tsx
2354
- import { Box as Box18, Text as Text18, useApp as useApp2 } from "ink";
2629
+ import { Box as Box19, Text as Text19, useApp as useApp2 } from "ink";
2355
2630
  import Spinner4 from "ink-spinner";
2356
- import { useState as useState12, useEffect as useEffect7 } from "react";
2631
+ import { useState as useState13, useEffect as useEffect7 } from "react";
2357
2632
 
2358
2633
  // src/lib/aiDocs.ts
2359
2634
  import { existsSync, readFileSync } from "fs";
@@ -2406,12 +2681,12 @@ var downloadAndExtractAiDocs = async (targetDir, version2) => {
2406
2681
  };
2407
2682
 
2408
2683
  // src/components/AIScaffold.tsx
2409
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
2684
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
2410
2685
  var AIScaffold = ({ version: version2 }) => {
2411
2686
  const { exit } = useApp2();
2412
- const [state, setState] = useState12("validating");
2413
- const [files, setFiles] = useState12([]);
2414
- const [errorMessage, setErrorMessage] = useState12("");
2687
+ const [state, setState] = useState13("validating");
2688
+ const [files, setFiles] = useState13([]);
2689
+ const [errorMessage, setErrorMessage] = useState13("");
2415
2690
  useEffect7(() => {
2416
2691
  const run = async () => {
2417
2692
  const projectDir = process.cwd();
@@ -2435,35 +2710,35 @@ var AIScaffold = ({ version: version2 }) => {
2435
2710
  };
2436
2711
  run();
2437
2712
  }, []);
2438
- return /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", children: [
2439
- /* @__PURE__ */ jsx18(Banner, {}),
2440
- /* @__PURE__ */ jsxs17(StepShell, { title: "AI Editor Config", children: [
2441
- state === "validating" && /* @__PURE__ */ jsxs17(Box18, { gap: 1, children: [
2442
- /* @__PURE__ */ jsx18(Text18, { color: "cyan", children: /* @__PURE__ */ jsx18(Spinner4, { type: "dots" }) }),
2443
- /* @__PURE__ */ jsx18(Text18, { children: "Checking project..." })
2713
+ return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", children: [
2714
+ /* @__PURE__ */ jsx19(Banner, {}),
2715
+ /* @__PURE__ */ jsxs18(StepShell, { title: "AI Editor Config", children: [
2716
+ state === "validating" && /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2717
+ /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: /* @__PURE__ */ jsx19(Spinner4, { type: "dots" }) }),
2718
+ /* @__PURE__ */ jsx19(Text19, { children: "Checking project..." })
2444
2719
  ] }),
2445
- state === "downloading" && /* @__PURE__ */ jsxs17(Box18, { gap: 1, children: [
2446
- /* @__PURE__ */ jsx18(Text18, { color: "cyan", children: /* @__PURE__ */ jsx18(Spinner4, { type: "dots" }) }),
2447
- /* @__PURE__ */ jsxs17(Text18, { children: [
2720
+ state === "downloading" && /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2721
+ /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: /* @__PURE__ */ jsx19(Spinner4, { type: "dots" }) }),
2722
+ /* @__PURE__ */ jsxs18(Text19, { children: [
2448
2723
  "Downloading AI editor configs (",
2449
2724
  version2,
2450
2725
  ")..."
2451
2726
  ] })
2452
2727
  ] }),
2453
- state === "done" && /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", gap: 1, children: [
2454
- /* @__PURE__ */ jsxs17(Box18, { gap: 1, children: [
2455
- /* @__PURE__ */ jsx18(Text18, { color: "green", bold: true, children: "\u2714" }),
2456
- /* @__PURE__ */ jsxs17(Text18, { bold: true, children: [
2728
+ state === "done" && /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", gap: 1, children: [
2729
+ /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2730
+ /* @__PURE__ */ jsx19(Text19, { color: "green", bold: true, children: "\u2714" }),
2731
+ /* @__PURE__ */ jsxs18(Text19, { bold: true, children: [
2457
2732
  "AI editor configs installed (",
2458
2733
  files.length,
2459
2734
  " files)"
2460
2735
  ] })
2461
2736
  ] }),
2462
- /* @__PURE__ */ jsx18(Box18, { flexDirection: "column", marginLeft: 2, children: files.map((f) => /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: f }, f)) })
2737
+ /* @__PURE__ */ jsx19(Box19, { flexDirection: "column", marginLeft: 2, children: files.map((f) => /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: f }, f)) })
2463
2738
  ] }),
2464
- state === "error" && /* @__PURE__ */ jsxs17(Box18, { gap: 1, children: [
2465
- /* @__PURE__ */ jsx18(Text18, { color: "red", children: "\u2716" }),
2466
- /* @__PURE__ */ jsx18(Text18, { children: errorMessage })
2739
+ state === "error" && /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2740
+ /* @__PURE__ */ jsx19(Text19, { color: "red", children: "\u2716" }),
2741
+ /* @__PURE__ */ jsx19(Text19, { children: errorMessage })
2467
2742
  ] })
2468
2743
  ] })
2469
2744
  ] });
@@ -2471,20 +2746,20 @@ var AIScaffold = ({ version: version2 }) => {
2471
2746
 
2472
2747
  // src/components/AuthLogin.tsx
2473
2748
  import { createServer } from "http";
2474
- import { Box as Box19, Text as Text19, useApp as useApp3 } from "ink";
2749
+ import { Box as Box20, Text as Text20, useApp as useApp3 } from "ink";
2475
2750
  import Spinner5 from "ink-spinner";
2476
2751
  import open from "open";
2477
- import { useState as useState13, useEffect as useEffect8 } from "react";
2752
+ import { useState as useState14, useEffect as useEffect8 } from "react";
2478
2753
 
2479
2754
  // src/lib/auth.ts
2480
- import { readFile as readFile3, writeFile as writeFile4, mkdir as mkdir2, unlink } from "fs/promises";
2755
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir2, unlink } from "fs/promises";
2481
2756
  import { join as join5 } from "path";
2482
2757
  import { homedir } from "os";
2483
2758
  var AUTH_DIR = join5(homedir(), ".stackable");
2484
2759
  var AUTH_FILE = join5(AUTH_DIR, "auth.json");
2485
2760
  var readAuthState = async () => {
2486
2761
  try {
2487
- const content = await readFile3(AUTH_FILE, "utf8");
2762
+ const content = await readFile4(AUTH_FILE, "utf8");
2488
2763
  return JSON.parse(content);
2489
2764
  } catch {
2490
2765
  return null;
@@ -2527,7 +2802,7 @@ var getToken = async () => {
2527
2802
  };
2528
2803
 
2529
2804
  // src/components/AuthLogin.tsx
2530
- import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
2805
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
2531
2806
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
2532
2807
  var callbackPage = (heading, sub, redirectUrl) => `<!DOCTYPE html>
2533
2808
  <html><head><meta charset="utf-8"><title>Stackable CLI</title>
@@ -2538,11 +2813,11 @@ ${redirectUrl ? `<script>(function(){var s=3,el=document.getElementById('h');fun
2538
2813
  </body></html>`;
2539
2814
  var AuthLogin = ({ dashboardUrl }) => {
2540
2815
  const { exit } = useApp3();
2541
- const [state, setState] = useState13("waiting");
2542
- const [loginUrl, setLoginUrl] = useState13("");
2543
- const [userIdLabel, setUserIdLabel] = useState13("");
2544
- const [orgIdLabel, setOrgIdLabel] = useState13("");
2545
- const [errorMessage, setErrorMessage] = useState13("");
2816
+ const [state, setState] = useState14("waiting");
2817
+ const [loginUrl, setLoginUrl] = useState14("");
2818
+ const [userIdLabel, setUserIdLabel] = useState14("");
2819
+ const [orgIdLabel, setOrgIdLabel] = useState14("");
2820
+ const [errorMessage, setErrorMessage] = useState14("");
2546
2821
  useEffect8(() => {
2547
2822
  let server;
2548
2823
  let timeout;
@@ -2618,38 +2893,38 @@ var AuthLogin = ({ dashboardUrl }) => {
2618
2893
  server?.close();
2619
2894
  };
2620
2895
  }, []);
2621
- return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", children: [
2622
- /* @__PURE__ */ jsx19(Banner, {}),
2623
- /* @__PURE__ */ jsxs18(StepShell, { title: "Authenticate with Stackable", children: [
2624
- state === "waiting" && /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", gap: 1, children: [
2625
- /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2626
- /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: /* @__PURE__ */ jsx19(Spinner5, { type: "dots" }) }),
2627
- /* @__PURE__ */ jsx19(Text19, { children: "Waiting for browser authentication..." })
2896
+ return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
2897
+ /* @__PURE__ */ jsx20(Banner, {}),
2898
+ /* @__PURE__ */ jsxs19(StepShell, { title: "Authenticate with Stackable", children: [
2899
+ state === "waiting" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", gap: 1, children: [
2900
+ /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
2901
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner5, { type: "dots" }) }),
2902
+ /* @__PURE__ */ jsx20(Text20, { children: "Waiting for browser authentication..." })
2628
2903
  ] }),
2629
- loginUrl && /* @__PURE__ */ jsxs18(Text19, { dimColor: true, children: [
2904
+ loginUrl && /* @__PURE__ */ jsxs19(Text20, { dimColor: true, children: [
2630
2905
  " ",
2631
2906
  loginUrl
2632
2907
  ] })
2633
2908
  ] }),
2634
- state === "success" && /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", gap: 1, children: [
2635
- /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", children: [
2636
- /* @__PURE__ */ jsxs18(Box19, { gap: 2, children: [
2637
- /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "User:" }),
2638
- /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: userIdLabel })
2909
+ state === "success" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", gap: 1, children: [
2910
+ /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
2911
+ /* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
2912
+ /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "User:" }),
2913
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: userIdLabel })
2639
2914
  ] }),
2640
- /* @__PURE__ */ jsxs18(Box19, { gap: 2, children: [
2641
- /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "Org: " }),
2642
- /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: orgIdLabel })
2915
+ /* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
2916
+ /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "Org: " }),
2917
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: orgIdLabel })
2643
2918
  ] })
2644
2919
  ] }),
2645
- /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2646
- /* @__PURE__ */ jsx19(Text19, { color: "green", bold: true, children: "\u2714" }),
2647
- /* @__PURE__ */ jsx19(Text19, { bold: true, children: "Authenticated" })
2920
+ /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
2921
+ /* @__PURE__ */ jsx20(Text20, { color: "green", bold: true, children: "\u2714" }),
2922
+ /* @__PURE__ */ jsx20(Text20, { bold: true, children: "Authenticated" })
2648
2923
  ] })
2649
2924
  ] }),
2650
- state === "error" && /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2651
- /* @__PURE__ */ jsx19(Text19, { color: "red", children: "\u2716" }),
2652
- /* @__PURE__ */ jsx19(Text19, { children: errorMessage })
2925
+ state === "error" && /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
2926
+ /* @__PURE__ */ jsx20(Text20, { color: "red", children: "\u2716" }),
2927
+ /* @__PURE__ */ jsx20(Text20, { children: errorMessage })
2653
2928
  ] })
2654
2929
  ] })
2655
2930
  ] });
@@ -2657,70 +2932,70 @@ var AuthLogin = ({ dashboardUrl }) => {
2657
2932
 
2658
2933
  // src/components/AuthLogout.tsx
2659
2934
  import { useEffect as useEffect9 } from "react";
2660
- import { Box as Box20, Text as Text20, useApp as useApp4 } from "ink";
2661
- import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
2935
+ import { Box as Box21, Text as Text21, useApp as useApp4 } from "ink";
2936
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
2662
2937
  var AuthLogout = () => {
2663
2938
  const { exit } = useApp4();
2664
2939
  useEffect9(() => {
2665
2940
  exit();
2666
2941
  }, [exit]);
2667
- return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
2668
- /* @__PURE__ */ jsx20(Banner, {}),
2669
- /* @__PURE__ */ jsx20(StepShell, { title: "Authenticate with Stackable", children: /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
2670
- /* @__PURE__ */ jsx20(Text20, { color: "green", bold: true, children: "\u2714" }),
2671
- /* @__PURE__ */ jsx20(Text20, { bold: true, children: "Logged out" })
2942
+ return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", children: [
2943
+ /* @__PURE__ */ jsx21(Banner, {}),
2944
+ /* @__PURE__ */ jsx21(StepShell, { title: "Authenticate with Stackable", children: /* @__PURE__ */ jsxs20(Box21, { gap: 1, children: [
2945
+ /* @__PURE__ */ jsx21(Text21, { color: "green", bold: true, children: "\u2714" }),
2946
+ /* @__PURE__ */ jsx21(Text21, { bold: true, children: "Logged out" })
2672
2947
  ] }) })
2673
2948
  ] });
2674
2949
  };
2675
2950
 
2676
2951
  // src/components/AuthStatus.tsx
2677
2952
  import { useEffect as useEffect10 } from "react";
2678
- import { useApp as useApp5, Box as Box21, Text as Text21 } from "ink";
2679
- import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
2953
+ import { useApp as useApp5, Box as Box22, Text as Text22 } from "ink";
2954
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
2680
2955
  var AuthStatus = ({ state, userId, orgId, expiry }) => {
2681
2956
  const { exit } = useApp5();
2682
2957
  useEffect10(() => {
2683
2958
  exit();
2684
2959
  }, [exit]);
2685
- return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", children: [
2686
- /* @__PURE__ */ jsx21(Banner, {}),
2687
- /* @__PURE__ */ jsxs20(StepShell, { title: "Authenticate with Stackable", children: [
2688
- state === "authenticated" && /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", gap: 1, children: [
2689
- /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", children: [
2690
- /* @__PURE__ */ jsxs20(Box21, { gap: 2, children: [
2691
- /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "User:" }),
2692
- /* @__PURE__ */ jsx21(Text21, { color: "cyan", children: userId })
2960
+ return /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", children: [
2961
+ /* @__PURE__ */ jsx22(Banner, {}),
2962
+ /* @__PURE__ */ jsxs21(StepShell, { title: "Authenticate with Stackable", children: [
2963
+ state === "authenticated" && /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", gap: 1, children: [
2964
+ /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", children: [
2965
+ /* @__PURE__ */ jsxs21(Box22, { gap: 2, children: [
2966
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "User:" }),
2967
+ /* @__PURE__ */ jsx22(Text22, { color: "cyan", children: userId })
2693
2968
  ] }),
2694
- /* @__PURE__ */ jsxs20(Box21, { gap: 2, children: [
2695
- /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Org: " }),
2696
- /* @__PURE__ */ jsx21(Text21, { color: "cyan", children: orgId })
2969
+ /* @__PURE__ */ jsxs21(Box22, { gap: 2, children: [
2970
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "Org: " }),
2971
+ /* @__PURE__ */ jsx22(Text22, { color: "cyan", children: orgId })
2697
2972
  ] }),
2698
- expiry && /* @__PURE__ */ jsxs20(Box21, { gap: 2, children: [
2699
- /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Exp: " }),
2700
- /* @__PURE__ */ jsx21(Text21, { color: "cyan", children: expiry.toLocaleDateString() })
2973
+ expiry && /* @__PURE__ */ jsxs21(Box22, { gap: 2, children: [
2974
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "Exp: " }),
2975
+ /* @__PURE__ */ jsx22(Text22, { color: "cyan", children: expiry.toLocaleDateString() })
2701
2976
  ] })
2702
2977
  ] }),
2703
- /* @__PURE__ */ jsxs20(Box21, { gap: 1, children: [
2704
- /* @__PURE__ */ jsx21(Text21, { color: "green", bold: true, children: "\u2714" }),
2705
- /* @__PURE__ */ jsx21(Text21, { bold: true, children: "Authenticated" })
2978
+ /* @__PURE__ */ jsxs21(Box22, { gap: 1, children: [
2979
+ /* @__PURE__ */ jsx22(Text22, { color: "green", bold: true, children: "\u2714" }),
2980
+ /* @__PURE__ */ jsx22(Text22, { bold: true, children: "Authenticated" })
2706
2981
  ] })
2707
2982
  ] }),
2708
- state === "expired" && /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", gap: 1, children: [
2709
- /* @__PURE__ */ jsxs20(Box21, { gap: 1, children: [
2710
- /* @__PURE__ */ jsx21(Text21, { color: "red", children: "\u2716" }),
2711
- /* @__PURE__ */ jsxs20(Text21, { children: [
2983
+ state === "expired" && /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", gap: 1, children: [
2984
+ /* @__PURE__ */ jsxs21(Box22, { gap: 1, children: [
2985
+ /* @__PURE__ */ jsx22(Text22, { color: "red", children: "\u2716" }),
2986
+ /* @__PURE__ */ jsxs21(Text22, { children: [
2712
2987
  "Session expired",
2713
2988
  expiry ? ` (${expiry.toLocaleDateString()})` : ""
2714
2989
  ] })
2715
2990
  ] }),
2716
- /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Run `stackable-app-extension auth login` to re-authenticate." })
2991
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "Run `stackable-app-extension auth login` to re-authenticate." })
2717
2992
  ] }),
2718
- state === "not-logged-in" && /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", gap: 1, children: [
2719
- /* @__PURE__ */ jsxs20(Box21, { gap: 1, children: [
2720
- /* @__PURE__ */ jsx21(Text21, { color: "red", children: "\u2716" }),
2721
- /* @__PURE__ */ jsx21(Text21, { children: "Not logged in" })
2993
+ state === "not-logged-in" && /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", gap: 1, children: [
2994
+ /* @__PURE__ */ jsxs21(Box22, { gap: 1, children: [
2995
+ /* @__PURE__ */ jsx22(Text22, { color: "red", children: "\u2716" }),
2996
+ /* @__PURE__ */ jsx22(Text22, { children: "Not logged in" })
2722
2997
  ] }),
2723
- /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Run `stackable-app-extension auth login`" })
2998
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "Run `stackable-app-extension auth login`" })
2724
2999
  ] })
2725
3000
  ] })
2726
3001
  ] });
@@ -2774,7 +3049,7 @@ var checkForUpdate = (currentVersion) => {
2774
3049
  };
2775
3050
 
2776
3051
  // src/index.tsx
2777
- import { jsx as jsx22 } from "react/jsx-runtime";
3052
+ import { jsx as jsx23 } from "react/jsx-runtime";
2778
3053
  var require2 = createRequire(import.meta.url);
2779
3054
  var { version } = require2("../package.json");
2780
3055
  checkForUpdate(version);
@@ -2787,7 +3062,7 @@ var ensureToken = async () => {
2787
3062
  const message = err instanceof Error ? err.message : String(err);
2788
3063
  const isExpired = message.toLowerCase().includes("expired");
2789
3064
  render(
2790
- /* @__PURE__ */ jsx22(AuthStatus, { state: isExpired ? "expired" : "not-logged-in" })
3065
+ /* @__PURE__ */ jsx23(AuthStatus, { state: isExpired ? "expired" : "not-logged-in" })
2791
3066
  );
2792
3067
  return null;
2793
3068
  }
@@ -2800,7 +3075,7 @@ program.command("create" /* CREATE */).description("Create a new Extension proje
2800
3075
  }
2801
3076
  const { token, userId, orgId } = auth2;
2802
3077
  render(
2803
- /* @__PURE__ */ jsx22(
3078
+ /* @__PURE__ */ jsx23(
2804
3079
  App,
2805
3080
  {
2806
3081
  command: "create" /* CREATE */,
@@ -2820,7 +3095,7 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
2820
3095
  }
2821
3096
  const { token, userId, orgId } = auth2;
2822
3097
  render(
2823
- /* @__PURE__ */ jsx22(
3098
+ /* @__PURE__ */ jsx23(
2824
3099
  App,
2825
3100
  {
2826
3101
  command: "scaffold" /* SCAFFOLD */,
@@ -2832,14 +3107,14 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
2832
3107
  )
2833
3108
  );
2834
3109
  });
2835
- 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)").action(async (extensionId, options) => {
3110
+ 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) => {
2836
3111
  const auth2 = await ensureToken();
2837
3112
  if (!auth2) {
2838
3113
  return;
2839
3114
  }
2840
3115
  const { token, userId, orgId } = auth2;
2841
3116
  render(
2842
- /* @__PURE__ */ jsx22(
3117
+ /* @__PURE__ */ jsx23(
2843
3118
  App,
2844
3119
  {
2845
3120
  command: "update" /* UPDATE */,
@@ -2859,7 +3134,7 @@ program.command("dev" /* DEV */).description("Start dev servers with a public tu
2859
3134
  }
2860
3135
  const { token, userId, orgId } = auth2;
2861
3136
  render(
2862
- /* @__PURE__ */ jsx22(
3137
+ /* @__PURE__ */ jsx23(
2863
3138
  DevApp,
2864
3139
  {
2865
3140
  options,
@@ -2874,17 +3149,17 @@ program.command("dev" /* DEV */).description("Start dev servers with a public tu
2874
3149
  var DASHBOARD_URL = process.env.ADMIN_DASHBOARD_URL ?? "https://admin.stackablelabs.io";
2875
3150
  var auth = program.command("auth").description("Manage CLI authentication");
2876
3151
  auth.command("login").description("Authenticate with Stackable via browser").action(async () => {
2877
- render(/* @__PURE__ */ jsx22(AuthLogin, { dashboardUrl: DASHBOARD_URL }));
3152
+ render(/* @__PURE__ */ jsx23(AuthLogin, { dashboardUrl: DASHBOARD_URL }));
2878
3153
  });
2879
3154
  auth.command("logout").description("Clear stored CLI credentials").action(async () => {
2880
3155
  await clearAuthState();
2881
- render(/* @__PURE__ */ jsx22(AuthLogout, {}));
3156
+ render(/* @__PURE__ */ jsx23(AuthLogout, {}));
2882
3157
  });
2883
3158
  auth.command("status").description("Show current authentication status").action(async () => {
2884
3159
  const state = await readAuthState();
2885
3160
  if (!state) {
2886
3161
  render(
2887
- /* @__PURE__ */ jsx22(AuthStatus, { state: "not-logged-in" })
3162
+ /* @__PURE__ */ jsx23(AuthStatus, { state: "not-logged-in" })
2888
3163
  );
2889
3164
  return;
2890
3165
  }
@@ -2892,11 +3167,11 @@ auth.command("status").description("Show current authentication status").action(
2892
3167
  const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
2893
3168
  const expiry = payload.exp ? new Date(payload.exp * 1e3) : null;
2894
3169
  if (expiry && Date.now() >= expiry.getTime()) {
2895
- render(/* @__PURE__ */ jsx22(AuthStatus, { state: "expired", expiry }));
3170
+ render(/* @__PURE__ */ jsx23(AuthStatus, { state: "expired", expiry }));
2896
3171
  return;
2897
3172
  }
2898
3173
  render(
2899
- /* @__PURE__ */ jsx22(
3174
+ /* @__PURE__ */ jsx23(
2900
3175
  AuthStatus,
2901
3176
  {
2902
3177
  state: "authenticated",
@@ -2909,6 +3184,6 @@ auth.command("status").description("Show current authentication status").action(
2909
3184
  });
2910
3185
  var ai = program.command("ai").description("AI editor configuration tools");
2911
3186
  ai.command("scaffold").description("Download AI editor config files into your Extension project").option("--version <version>", 'AI docs version (semver or "latest")', "latest").action(async (options) => {
2912
- render(/* @__PURE__ */ jsx22(AIScaffold, { version: options.version }));
3187
+ render(/* @__PURE__ */ jsx23(AIScaffold, { version: options.version }));
2913
3188
  });
2914
3189
  program.parse(process.argv.filter((arg) => arg !== "--"));