@stackable-labs/cli-app-extension 1.26.4 → 1.27.1

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 +686 -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) {
@@ -1529,6 +1685,7 @@ var scaffold = async (options) => {
1529
1685
  const templateSource = TEMPLATE_SOURCES[flavor];
1530
1686
  const { dir } = await downloadTemplate(templateSource, {
1531
1687
  dir: options.outputDir,
1688
+ forceClean: true,
1532
1689
  force: true
1533
1690
  });
1534
1691
  await replacePlaceholders(dir, {
@@ -1539,7 +1696,7 @@ var scaffold = async (options) => {
1539
1696
  });
1540
1697
  if (flavor === "starter") {
1541
1698
  const selectedTargets = normalizeTargets(options.targets);
1542
- const derivedPermissions = derivePermissions(selectedTargets);
1699
+ const derivedPermissions = deriveScaffoldPermissions(selectedTargets);
1543
1700
  await generateManifest(dir, options.name, selectedTargets, derivedPermissions);
1544
1701
  await generateSurfaceFiles(dir, selectedTargets);
1545
1702
  await rewriteExtensionIndex(dir, options.extensionId || options.name, selectedTargets);
@@ -1557,17 +1714,18 @@ var scaffold = async (options) => {
1557
1714
  appName: options.appName || null,
1558
1715
  extensionName: options.name,
1559
1716
  extensionPort: options.extensionPort,
1560
- previewPort: options.previewPort
1717
+ previewPort: options.previewPort,
1718
+ manifest: null
1561
1719
  });
1562
1720
  return options;
1563
1721
  };
1564
1722
 
1565
1723
  // src/App.tsx
1566
- import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
1724
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
1567
1725
  var STEPS = {
1568
1726
  ["create" /* CREATE */]: ["app", "name", "template", "targets", "settings", "confirm"],
1569
1727
  ["scaffold" /* SCAFFOLD */]: ["app", "extensionSelect", "confirmTargets", "settings", "confirm"],
1570
- ["update" /* UPDATE */]: ["app", "extensionSelect", "updateSettings", "confirm"],
1728
+ ["update" /* UPDATE */]: ["app", "extensionSelect", "updateSettings", "manifestReview", "confirm"],
1571
1729
  ["dev" /* DEV */]: []
1572
1730
  // Dev command has no wizard steps
1573
1731
  };
@@ -1589,8 +1747,7 @@ var PROGRESS_STEPS = {
1589
1747
  ["dev" /* DEV */]: []
1590
1748
  // Dev command has no progress steps
1591
1749
  };
1592
- var toKebabCase2 = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1593
- var derivePermissions2 = (targets) => {
1750
+ var deriveRegistryPermissions = (targets) => {
1594
1751
  const permissions = /* @__PURE__ */ new Set();
1595
1752
  for (const target of targets) {
1596
1753
  const mapped = TARGET_PERMISSION_MAP[target];
@@ -1609,33 +1766,37 @@ var derivePermissions2 = (targets) => {
1609
1766
  };
1610
1767
  var App = ({ command, token, userId, orgId, initialName, initialExtensionId, options }) => {
1611
1768
  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(
1769
+ const [step, setStep] = useState10("app");
1770
+ const [name, setName] = useState10(initialName ?? options?.name ?? "");
1771
+ const [extensionId, setExtensionId] = useState10(initialExtensionId ?? "");
1772
+ const [extensionVersion, setExtensionVersion] = useState10("");
1773
+ const [bundleUrl, setBundleUrl] = useState10(options?.bundleUrl ?? "");
1774
+ const [enabled, setEnabled] = useState10(
1618
1775
  options?.enabled !== void 0 ? options.enabled !== "false" : true
1619
1776
  );
1620
- const [versionOverride, setVersionOverride] = useState9(void 0);
1621
- const [forceMajor, setForceMajor] = useState9(false);
1622
- const [initialExtension, setInitialExtension] = useState9(null);
1623
- const [templateFlavor, setTemplateFlavor] = useState9(
1777
+ const [versionOverride, setVersionOverride] = useState10(void 0);
1778
+ const [forceMajor, setForceMajor] = useState10(false);
1779
+ const [initialExtension, setInitialExtension] = useState10(null);
1780
+ const [templateFlavor, setTemplateFlavor] = useState10(
1624
1781
  options?.template ?? "starter"
1625
1782
  );
1626
- const [targets, setTargets] = useState9(
1783
+ const [targets, setTargets] = useState10(
1627
1784
  options?.targets ? options.targets.split(",").map((t) => t.trim()) : []
1628
1785
  );
1629
- const [selectedApp, setSelectedApp] = useState9(null);
1630
- const [extensionPort, setExtensionPort] = useState9(
1786
+ const [selectedApp, setSelectedApp] = useState10(null);
1787
+ const [extensionPort, setExtensionPort] = useState10(
1631
1788
  options?.extensionPort ? parseInt(options.extensionPort, 10) : 6543
1632
1789
  );
1633
- const [previewPort, setPreviewPort] = useState9(
1790
+ const [previewPort, setPreviewPort] = useState10(
1634
1791
  options?.previewPort ? parseInt(options.previewPort, 10) : 6544
1635
1792
  );
1636
- const [outputDir, setOutputDir] = useState9("");
1637
- const [progressSteps, setProgressSteps] = useState9(PROGRESS_STEPS[command]);
1638
- const [errorMessage, setErrorMessage] = useState9();
1793
+ const [registryManifest, setRegistryManifest] = useState10(null);
1794
+ const [localManifest, setLocalManifest] = useState10(null);
1795
+ const [confirmedPermissions, setConfirmedPermissions] = useState10([]);
1796
+ const [confirmedAllowedDomains, setConfirmedAllowedDomains] = useState10([]);
1797
+ const [outputDir, setOutputDir] = useState10("");
1798
+ const [progressSteps, setProgressSteps] = useState10(PROGRESS_STEPS[command]);
1799
+ const [errorMessage, setErrorMessage] = useState10();
1639
1800
  const updateStep = useCallback((index, status) => {
1640
1801
  setProgressSteps((prev) => prev.map((s, i) => i === index ? { ...s, status } : s));
1641
1802
  }, []);
@@ -1670,8 +1831,47 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1670
1831
  return idx > 0 ? steps[idx - 1] : prev;
1671
1832
  });
1672
1833
  }, [activeSteps]);
1673
- const handleAppSelect = (app) => {
1834
+ const handleAppSelect = async (app) => {
1674
1835
  setSelectedApp(app);
1836
+ if (command === "update" /* UPDATE */ && initialExtensionId) {
1837
+ try {
1838
+ const extensions = await fetchExtensions(token, app.id);
1839
+ const ext = extensions[initialExtensionId];
1840
+ if (!ext) {
1841
+ setErrorMessage(
1842
+ `Extension "${initialExtensionId}" not found or is disabled. If disabled, re-enable it in the admin dashboard before updating.`
1843
+ );
1844
+ setStep("error");
1845
+ return;
1846
+ }
1847
+ setName(ext.manifest.name);
1848
+ setExtensionId(ext.id);
1849
+ setExtensionVersion(ext.manifest.version);
1850
+ setTargets(ext.manifest.targets);
1851
+ setBundleUrl(ext.bundleUrl);
1852
+ setEnabled(ext.enabled ?? true);
1853
+ setInitialExtension({
1854
+ name: ext.manifest.name,
1855
+ targets: ext.manifest.targets,
1856
+ bundleUrl: ext.bundleUrl
1857
+ });
1858
+ setRegistryManifest(ext.manifest);
1859
+ const projectRoot = options?.dir || process.cwd();
1860
+ try {
1861
+ const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
1862
+ const content = await readFile3(manifestPath, "utf8");
1863
+ setLocalManifest(JSON.parse(content));
1864
+ } catch {
1865
+ setLocalManifest(null);
1866
+ }
1867
+ setStep("updateSettings");
1868
+ } catch (err) {
1869
+ const message = err instanceof Error ? err.message : String(err);
1870
+ setErrorMessage(message);
1871
+ setStep("error");
1872
+ }
1873
+ return;
1874
+ }
1675
1875
  if (command === "scaffold" /* SCAFFOLD */ || command === "update" /* UPDATE */) {
1676
1876
  setStep("extensionSelect");
1677
1877
  return;
@@ -1682,7 +1882,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1682
1882
  if (meta.skipTargetStep && meta.defaultTargets) {
1683
1883
  setTargets(meta.defaultTargets);
1684
1884
  if (options?.extensionPort || options?.previewPort) {
1685
- setOutputDir(join3(process.cwd(), toKebabCase2(initialName)));
1885
+ setOutputDir(join3(process.cwd(), toKebabCase(initialName)));
1686
1886
  setStep("confirm");
1687
1887
  } else {
1688
1888
  setStep("settings");
@@ -1697,7 +1897,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1697
1897
  setStep("name");
1698
1898
  }
1699
1899
  };
1700
- const handleExtensionSelect = (ext) => {
1900
+ const handleExtensionSelect = async (ext) => {
1701
1901
  setName(ext.manifest.name);
1702
1902
  setExtensionId(ext.id);
1703
1903
  setExtensionVersion(ext.manifest.version);
@@ -1709,6 +1909,15 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1709
1909
  targets: ext.manifest.targets,
1710
1910
  bundleUrl: ext.bundleUrl
1711
1911
  });
1912
+ setRegistryManifest(ext.manifest);
1913
+ const projectRoot = options?.dir || process.cwd();
1914
+ try {
1915
+ const manifestPath = join3(projectRoot, "packages/extension/public/manifest.json");
1916
+ const content = await readFile3(manifestPath, "utf8");
1917
+ setLocalManifest(JSON.parse(content));
1918
+ } catch {
1919
+ setLocalManifest(null);
1920
+ }
1712
1921
  if (command === "scaffold" /* SCAFFOLD */) {
1713
1922
  setStep("confirmTargets");
1714
1923
  } else if (command === "update" /* UPDATE */) {
@@ -1718,7 +1927,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1718
1927
  const handleConfirmTargets = (value) => {
1719
1928
  setTargets(value);
1720
1929
  if (options?.extensionPort || options?.previewPort) {
1721
- setOutputDir(join3(process.cwd(), toKebabCase2(extensionId || name)));
1930
+ setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
1722
1931
  setStep("confirm");
1723
1932
  } else {
1724
1933
  setStep("settings");
@@ -1726,13 +1935,13 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1726
1935
  };
1727
1936
  const handleName = (value) => {
1728
1937
  setName(value);
1729
- setExtensionId(toKebabCase2(value));
1938
+ setExtensionId(toKebabCase(value));
1730
1939
  if (options?.template) {
1731
1940
  const meta = TEMPLATE_FLAVOR_META[templateFlavor];
1732
1941
  if (meta.skipTargetStep && meta.defaultTargets) {
1733
1942
  setTargets(meta.defaultTargets);
1734
1943
  if (options?.extensionPort || options?.previewPort) {
1735
- setOutputDir(join3(process.cwd(), toKebabCase2(value)));
1944
+ setOutputDir(join3(process.cwd(), toKebabCase(value)));
1736
1945
  setStep("confirm");
1737
1946
  } else {
1738
1947
  setStep("settings");
@@ -1750,7 +1959,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1750
1959
  if (meta.skipTargetStep && meta.defaultTargets) {
1751
1960
  setTargets(meta.defaultTargets);
1752
1961
  if (options?.extensionPort || options?.previewPort) {
1753
- setOutputDir(join3(process.cwd(), toKebabCase2(extensionId || name)));
1962
+ setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
1754
1963
  setStep("confirm");
1755
1964
  } else {
1756
1965
  setStep("settings");
@@ -1762,7 +1971,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1762
1971
  const handleTargets = (value) => {
1763
1972
  setTargets(value);
1764
1973
  if (options?.extensionPort || options?.previewPort) {
1765
- setOutputDir(join3(process.cwd(), toKebabCase2(extensionId || name)));
1974
+ setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
1766
1975
  setStep("confirm");
1767
1976
  } else {
1768
1977
  setStep("settings");
@@ -1784,7 +1993,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1784
1993
  if (targetsChanged) return `${major}.${minor + 1}.0`;
1785
1994
  const nameChanged = newName !== initialExtension.name;
1786
1995
  if (nameChanged) return `${major}.${minor}.${patch + 1}`;
1787
- return currentVersion;
1996
+ return `${major}.${minor}.${patch + 1}`;
1788
1997
  };
1789
1998
  const handleConfirm = async () => {
1790
1999
  if (command === "update" /* UPDATE */) {
@@ -1798,8 +2007,8 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1798
2007
  name,
1799
2008
  version: resolvedVersion,
1800
2009
  targets,
1801
- permissions: derivePermissions2(targets),
1802
- allowedDomains: []
2010
+ permissions: confirmedPermissions,
2011
+ allowedDomains: confirmedAllowedDomains
1803
2012
  },
1804
2013
  bundleUrl: bundleUrl || void 0,
1805
2014
  enabled
@@ -1817,7 +2026,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1817
2026
  setStep("scaffolding");
1818
2027
  setProgressSteps(PROGRESS_STEPS[command]);
1819
2028
  try {
1820
- let resolvedExtensionId = extensionId || toKebabCase2(name);
2029
+ let resolvedExtensionId = extensionId || toKebabCase(name);
1821
2030
  let scaffoldStepOffset = 0;
1822
2031
  if (command === "create" /* CREATE */) {
1823
2032
  scaffoldStepOffset = 1;
@@ -1827,7 +2036,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1827
2036
  name,
1828
2037
  version: "0.0.0",
1829
2038
  targets,
1830
- permissions: derivePermissions2(targets),
2039
+ permissions: deriveRegistryPermissions(targets),
1831
2040
  allowedDomains: []
1832
2041
  },
1833
2042
  bundleUrl: `http://localhost:${extensionPort}`
@@ -1849,6 +2058,17 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1849
2058
  previewPort
1850
2059
  });
1851
2060
  updateStep(scaffoldStepOffset + 0, "done");
2061
+ if (command === "create" /* CREATE */) {
2062
+ const manifestPath = join3(outputDir, "packages/extension/public/manifest.json");
2063
+ try {
2064
+ const manifestContent = await readFile3(manifestPath, "utf8");
2065
+ const manifest = JSON.parse(manifestContent);
2066
+ await updateExtension(token, selectedApp.id, resolvedExtensionId, {
2067
+ manifest: { ...manifest, allowedDomains: [] }
2068
+ });
2069
+ } catch {
2070
+ }
2071
+ }
1852
2072
  updateStep(scaffoldStepOffset + 1, "running");
1853
2073
  await new Promise((r) => setTimeout(r, 200));
1854
2074
  updateStep(scaffoldStepOffset + 1, "done");
@@ -1871,7 +2091,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1871
2091
  };
1872
2092
  switch (step) {
1873
2093
  case "app": {
1874
- return /* @__PURE__ */ jsx14(
2094
+ return /* @__PURE__ */ jsx15(
1875
2095
  AppSelect,
1876
2096
  {
1877
2097
  token,
@@ -1882,7 +2102,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1882
2102
  );
1883
2103
  }
1884
2104
  case "extensionSelect": {
1885
- return /* @__PURE__ */ jsx14(
2105
+ return /* @__PURE__ */ jsx15(
1886
2106
  ExtensionSelect,
1887
2107
  {
1888
2108
  appId: selectedApp.id,
@@ -1894,7 +2114,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1894
2114
  );
1895
2115
  }
1896
2116
  case "confirmTargets": {
1897
- return /* @__PURE__ */ jsx14(
2117
+ return /* @__PURE__ */ jsx15(
1898
2118
  TargetSelect,
1899
2119
  {
1900
2120
  availableTargets: selectedApp?.targets ?? [],
@@ -1905,7 +2125,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1905
2125
  );
1906
2126
  }
1907
2127
  case "name": {
1908
- return /* @__PURE__ */ jsx14(
2128
+ return /* @__PURE__ */ jsx15(
1909
2129
  NamePrompt,
1910
2130
  {
1911
2131
  initialValue: name,
@@ -1915,7 +2135,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1915
2135
  );
1916
2136
  }
1917
2137
  case "template": {
1918
- return /* @__PURE__ */ jsx14(
2138
+ return /* @__PURE__ */ jsx15(
1919
2139
  TemplateSelect,
1920
2140
  {
1921
2141
  onSubmit: handleTemplateSelect,
@@ -1924,7 +2144,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1924
2144
  );
1925
2145
  }
1926
2146
  case "targets": {
1927
- return /* @__PURE__ */ jsx14(
2147
+ return /* @__PURE__ */ jsx15(
1928
2148
  TargetSelect,
1929
2149
  {
1930
2150
  availableTargets: selectedApp?.targets ?? [],
@@ -1934,29 +2154,34 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1934
2154
  );
1935
2155
  }
1936
2156
  case "settings": {
1937
- return /* @__PURE__ */ jsx14(
2157
+ return /* @__PURE__ */ jsx15(
1938
2158
  SettingsPrompt,
1939
2159
  {
1940
- defaultDir: join3(process.cwd(), toKebabCase2(extensionId || name)),
2160
+ defaultDir: join3(process.cwd(), toKebabCase(extensionId || name)),
1941
2161
  onSubmit: handleSettings,
1942
2162
  onBack: goBack
1943
2163
  }
1944
2164
  );
1945
2165
  }
1946
2166
  case "confirm": {
1947
- return /* @__PURE__ */ jsx14(
2167
+ return /* @__PURE__ */ jsx15(
1948
2168
  Confirm,
1949
2169
  {
1950
2170
  command,
1951
2171
  name,
1952
2172
  templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0,
1953
2173
  targets,
2174
+ registryTargets: command === "update" /* UPDATE */ ? registryManifest?.targets : void 0,
1954
2175
  outputDir,
1955
2176
  previewPort,
1956
2177
  extensionPort,
1957
2178
  extensionVersion: command !== "create" /* CREATE */ ? extensionVersion : void 0,
1958
2179
  bundleUrl: command === "update" /* UPDATE */ ? bundleUrl : void 0,
1959
2180
  enabled: command === "update" /* UPDATE */ ? enabled : void 0,
2181
+ permissions: command === "update" /* UPDATE */ ? confirmedPermissions : void 0,
2182
+ allowedDomains: command === "update" /* UPDATE */ ? confirmedAllowedDomains : void 0,
2183
+ registryPermissions: command === "update" /* UPDATE */ ? registryManifest?.permissions : void 0,
2184
+ registryAllowedDomains: command === "update" /* UPDATE */ ? registryManifest?.allowedDomains : void 0,
1960
2185
  newVersion: command === "update" /* UPDATE */ ? options?.setVersion ?? versionOverride ?? computeVersionBump(extensionVersion, name, targets, bundleUrl, forceMajor) : void 0,
1961
2186
  onVersionOverride: command === "update" /* UPDATE */ ? setVersionOverride : void 0,
1962
2187
  onConfirm: handleConfirm,
@@ -1966,10 +2191,10 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1966
2191
  );
1967
2192
  }
1968
2193
  case "scaffolding": {
1969
- return /* @__PURE__ */ jsx14(ScaffoldProgress, { steps: progressSteps });
2194
+ return /* @__PURE__ */ jsx15(ScaffoldProgress, { steps: progressSteps });
1970
2195
  }
1971
2196
  case "updateSettings": {
1972
- return /* @__PURE__ */ jsx14(
2197
+ return /* @__PURE__ */ jsx15(
1973
2198
  UpdateSettingsPrompt,
1974
2199
  {
1975
2200
  name,
@@ -1984,6 +2209,21 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1984
2209
  setEnabled(updated.enabled);
1985
2210
  setForceMajor(updated.forceMajor);
1986
2211
  setVersionOverride(void 0);
2212
+ setStep("manifestReview");
2213
+ },
2214
+ onBack: goBack
2215
+ }
2216
+ );
2217
+ }
2218
+ case "manifestReview": {
2219
+ return /* @__PURE__ */ jsx15(
2220
+ ManifestReviewPrompt,
2221
+ {
2222
+ localManifest,
2223
+ registryManifest,
2224
+ onSubmit: (result) => {
2225
+ setConfirmedPermissions(result.permissions);
2226
+ setConfirmedAllowedDomains(result.allowedDomains);
1987
2227
  setStep("confirm");
1988
2228
  },
1989
2229
  onBack: goBack
@@ -1991,46 +2231,46 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
1991
2231
  );
1992
2232
  }
1993
2233
  case "updating": {
1994
- return /* @__PURE__ */ jsx14(ScaffoldProgress, { steps: progressSteps });
2234
+ return /* @__PURE__ */ jsx15(ScaffoldProgress, { steps: progressSteps });
1995
2235
  }
1996
2236
  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: [
2237
+ return /* @__PURE__ */ jsx15(StepShell, { title: "Extension updated", onBack: goBack, children: /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", gap: 1, children: [
2238
+ /* @__PURE__ */ jsx15(Text15, { color: "green", bold: true, children: "Extension updated successfully!" }),
2239
+ /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
2000
2240
  "Name: ",
2001
2241
  name
2002
2242
  ] }),
2003
- /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2243
+ /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
2004
2244
  "ID: ",
2005
2245
  extensionId
2006
2246
  ] }),
2007
- /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2247
+ /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
2008
2248
  "Version: ",
2009
2249
  extensionVersion
2010
2250
  ] })
2011
2251
  ] }) });
2012
2252
  }
2013
2253
  case "done": {
2014
- return /* @__PURE__ */ jsx14(Done, { name, outputDir, templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0 });
2254
+ return /* @__PURE__ */ jsx15(Done, { name, outputDir, templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0 });
2015
2255
  }
2016
2256
  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 })
2257
+ return /* @__PURE__ */ jsx15(StepShell, { title: "Operation failed", onBack: goBack, children: /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", gap: 1, children: [
2258
+ /* @__PURE__ */ jsx15(Text15, { color: "red", bold: true, children: "An error occurred" }),
2259
+ errorMessage && /* @__PURE__ */ jsx15(Text15, { color: "red", children: errorMessage })
2020
2260
  ] }) });
2021
2261
  }
2022
2262
  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 })
2263
+ return /* @__PURE__ */ jsx15(StepShell, { title: "Scaffold failed", onBack: goBack, children: /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", gap: 1, children: [
2264
+ /* @__PURE__ */ jsx15(Text15, { color: "red", bold: true, children: "An error occurred" }),
2265
+ errorMessage && /* @__PURE__ */ jsx15(Text15, { color: "red", children: errorMessage })
2026
2266
  ] }) });
2027
2267
  }
2028
2268
  }
2029
2269
  };
2030
2270
 
2031
2271
  // 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";
2272
+ import { useRef, useState as useState12, useEffect as useEffect6, useCallback as useCallback2 } from "react";
2273
+ import { useInput as useInput11, Box as Box18, Text as Text18 } from "ink";
2034
2274
 
2035
2275
  // src/lib/tunnel.ts
2036
2276
  import { Tunnel } from "cloudflared";
@@ -2064,12 +2304,12 @@ var startDevServer = (projectRoot) => {
2064
2304
  };
2065
2305
 
2066
2306
  // 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";
2307
+ import { Box as Box16, Text as Text16 } from "ink";
2308
+ import { useState as useState11, useEffect as useEffect4 } from "react";
2309
+ import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
2070
2310
  var DevSetup = ({ initialContext, token, onReady }) => {
2071
- const [step, setStep] = useState10("app");
2072
- const [selectedApp, setSelectedApp] = useState10(null);
2311
+ const [step, setStep] = useState11("app");
2312
+ const [selectedApp, setSelectedApp] = useState11(null);
2073
2313
  useEffect4(() => {
2074
2314
  if (initialContext.appId) {
2075
2315
  setStep("extension");
@@ -2087,9 +2327,9 @@ var DevSetup = ({ initialContext, token, onReady }) => {
2087
2327
  });
2088
2328
  };
2089
2329
  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(
2330
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2331
+ /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { children: "Select the App for your extension:" }) }),
2332
+ /* @__PURE__ */ jsx16(
2093
2333
  AppSelect,
2094
2334
  {
2095
2335
  token,
@@ -2098,9 +2338,9 @@ var DevSetup = ({ initialContext, token, onReady }) => {
2098
2338
  )
2099
2339
  ] });
2100
2340
  }
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(
2341
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2342
+ /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text16, { children: "Select the Extension to develop:" }) }),
2343
+ /* @__PURE__ */ jsx16(
2104
2344
  ExtensionSelect,
2105
2345
  {
2106
2346
  token,
@@ -2112,9 +2352,9 @@ var DevSetup = ({ initialContext, token, onReady }) => {
2112
2352
  };
2113
2353
 
2114
2354
  // src/components/DevDashboard.tsx
2115
- import { Box as Box16, Text as Text16, useInput as useInput9 } from "ink";
2355
+ import { Box as Box17, Text as Text17, useInput as useInput10 } from "ink";
2116
2356
  import { useEffect as useEffect5 } from "react";
2117
- import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
2357
+ import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
2118
2358
  var DevDashboard = ({
2119
2359
  previewTunnelUrl,
2120
2360
  tunnelUrl,
@@ -2126,6 +2366,7 @@ var DevDashboard = ({
2126
2366
  extensionName,
2127
2367
  extensionPort,
2128
2368
  previewPort,
2369
+ manifestWarnings = [],
2129
2370
  onQuit
2130
2371
  }) => {
2131
2372
  useEffect5(() => {
@@ -2137,72 +2378,80 @@ var DevDashboard = ({
2137
2378
  process.off("SIGINT", handler);
2138
2379
  };
2139
2380
  }, [onQuit]);
2140
- useInput9((input, key) => {
2381
+ useInput10((input, key) => {
2141
2382
  if (input === "q" || key.ctrl && input === "c") {
2142
2383
  onQuit();
2143
2384
  }
2144
2385
  });
2145
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
2146
- /* @__PURE__ */ jsx16(Banner, { userId, orgId }),
2147
- /* @__PURE__ */ jsxs16(
2386
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2387
+ /* @__PURE__ */ jsx17(Banner, { userId, orgId }),
2388
+ /* @__PURE__ */ jsxs17(
2148
2389
  StepShell,
2149
2390
  {
2150
2391
  title: "dev",
2151
2392
  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" }) }),
2393
+ footer: /* @__PURE__ */ jsx17(Box17, { flexDirection: "column", gap: 1, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Press q or Ctrl-C to quit" }) }),
2153
2394
  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: [
2395
+ /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2396
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2397
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Extension:" }),
2398
+ /* @__PURE__ */ jsxs17(Text17, { children: [
2158
2399
  extensionName,
2159
2400
  " (",
2160
2401
  extensionId,
2161
2402
  ")"
2162
2403
  ] })
2163
2404
  ] }),
2164
- /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2165
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "App:" }),
2166
- /* @__PURE__ */ jsx16(Text16, { children: `${appName ? `${appName} ` : ""}(${appId})` })
2405
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2406
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "App:" }),
2407
+ /* @__PURE__ */ jsx17(Text17, { children: `${appName ? `${appName} ` : ""}(${appId})` })
2167
2408
  ] }),
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}` })
2409
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2410
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Bundle URL:" }),
2411
+ /* @__PURE__ */ jsx17(Text17, { children: tunnelUrl || `http://localhost:${extensionPort}` })
2171
2412
  ] })
2172
2413
  ] }),
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 })
2414
+ /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2415
+ previewTunnelUrl && /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2416
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Tunnel Dev - Preview:" }),
2417
+ /* @__PURE__ */ jsx17(Text17, { children: previewTunnelUrl })
2177
2418
  ] }),
2178
- /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2179
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Local Dev - Preview:" }),
2180
- /* @__PURE__ */ jsxs16(Text16, { children: [
2419
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2420
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Local Dev - Preview:" }),
2421
+ /* @__PURE__ */ jsxs17(Text17, { children: [
2181
2422
  "http://localhost:",
2182
2423
  previewPort
2183
2424
  ] })
2184
2425
  ] })
2185
2426
  ] }),
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 })
2427
+ /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2428
+ tunnelUrl && /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2429
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Tunnel Dev - Extension:" }),
2430
+ /* @__PURE__ */ jsx17(Text17, { children: tunnelUrl })
2190
2431
  ] }),
2191
- /* @__PURE__ */ jsxs16(Box16, { gap: 2, children: [
2192
- /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "Local Dev - Extension:" }),
2193
- /* @__PURE__ */ jsxs16(Text16, { children: [
2432
+ /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2433
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Local Dev - Extension:" }),
2434
+ /* @__PURE__ */ jsxs17(Text17, { children: [
2194
2435
  "http://localhost:",
2195
2436
  extensionPort
2196
2437
  ] })
2197
2438
  ] })
2198
2439
  ] }),
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: [
2440
+ /* @__PURE__ */ jsx17(Box17, { flexDirection: "column", children: tunnelUrl && /* @__PURE__ */ jsxs17(Box17, { gap: 2, children: [
2441
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Host Dev - Query Param:" }),
2442
+ /* @__PURE__ */ jsxs17(Text17, { children: [
2202
2443
  "?_stackable_dev=",
2203
2444
  encodeURIComponent(`${extensionId}:${tunnelUrl}`)
2204
2445
  ] })
2205
- ] }) })
2446
+ ] }) }),
2447
+ manifestWarnings.length > 0 && /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
2448
+ /* @__PURE__ */ jsx17(Text17, { color: "yellow", bold: true, children: "Local manifest differs from registry:" }),
2449
+ manifestWarnings.map((w, i) => /* @__PURE__ */ jsxs17(Text17, { color: "yellow", children: [
2450
+ " ",
2451
+ w
2452
+ ] }, i)),
2453
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " Run `pnpm dlx @stackable-labs/cli-app-extension@latest update` to review and sync." })
2454
+ ] })
2206
2455
  ]
2207
2456
  }
2208
2457
  )
@@ -2210,16 +2459,17 @@ var DevDashboard = ({
2210
2459
  };
2211
2460
 
2212
2461
  // src/components/DevApp.tsx
2213
- import { jsx as jsx17 } from "react/jsx-runtime";
2462
+ import { jsx as jsx18 } from "react/jsx-runtime";
2214
2463
  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);
2464
+ const [state, setState] = useState12("setup");
2465
+ const [devContext, setDevContext] = useState12(null);
2466
+ const [resolvedContext, setResolvedContext] = useState12(null);
2467
+ const [tunnelUrl, setTunnelUrl] = useState12(null);
2468
+ const [previewTunnelUrl, setPreviewTunnelUrl] = useState12(null);
2469
+ const [tunnelHandle, setTunnelHandle] = useState12(null);
2470
+ const [previewTunnelHandle, setPreviewTunnelHandle] = useState12(null);
2471
+ const [devServerHandle, setDevServerHandle] = useState12(null);
2472
+ const [manifestWarnings, setManifestWarnings] = useState12([]);
2223
2473
  const shuttingDown = useRef(false);
2224
2474
  const useTunnel = options.tunnel !== false;
2225
2475
  useEffect6(() => {
@@ -2240,6 +2490,31 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2240
2490
  extensionId: resolved.extensionId,
2241
2491
  appName: resolved.appName || null
2242
2492
  });
2493
+ if (devContext.manifest) {
2494
+ try {
2495
+ const extensions = await fetchExtensions(token, resolved.appId);
2496
+ const registryExt = extensions[resolved.extensionId];
2497
+ if (registryExt) {
2498
+ const localPerms = new Set(devContext.manifest.permissions);
2499
+ const registryPerms = new Set(registryExt.manifest.permissions);
2500
+ const missingPerms = [...localPerms].filter((p) => !registryPerms.has(p));
2501
+ const extraPerms = [...registryPerms].filter((p) => !localPerms.has(p));
2502
+ const localDomains = new Set(devContext.manifest.allowedDomains);
2503
+ const registryDomains = new Set(registryExt.manifest.allowedDomains);
2504
+ const missingDomains = [...localDomains].filter((d) => !registryDomains.has(d));
2505
+ const extraDomains = [...registryDomains].filter((d) => !localDomains.has(d));
2506
+ const warnings = [];
2507
+ if (missingPerms.length > 0) warnings.push(`Permissions in local but not registry: ${missingPerms.join(", ")}`);
2508
+ if (extraPerms.length > 0) warnings.push(`Permissions in registry but not local: ${extraPerms.join(", ")}`);
2509
+ if (missingDomains.length > 0) warnings.push(`Domains in local but not registry: ${missingDomains.join(", ")}`);
2510
+ if (extraDomains.length > 0) warnings.push(`Domains in registry but not local: ${extraDomains.join(", ")}`);
2511
+ if (warnings.length > 0) {
2512
+ setManifestWarnings(warnings);
2513
+ }
2514
+ }
2515
+ } catch {
2516
+ }
2517
+ }
2243
2518
  const extensionPort = options.extensionPort ? parseInt(options.extensionPort, 10) : devContext.extensionPort;
2244
2519
  const previewPort = options.previewPort ? parseInt(options.previewPort, 10) : devContext.previewPort;
2245
2520
  await patchViteAllowedHosts(devContext.projectRoot);
@@ -2268,7 +2543,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2268
2543
  setDevServerHandle(serverHandle);
2269
2544
  console.log("[dev] Ready");
2270
2545
  setState("running");
2271
- }, [devContext, options.extensionPort, options.previewPort, useTunnel]);
2546
+ }, [devContext, token, options.extensionPort, options.previewPort, useTunnel]);
2272
2547
  useEffect6(() => {
2273
2548
  if (state === "setup" && devContext && devContext.appId && devContext.extensionId) {
2274
2549
  handleSetupReady({
@@ -2304,7 +2579,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2304
2579
  console.log("[dev] Done");
2305
2580
  process.exit(0);
2306
2581
  };
2307
- useInput10((input, key) => {
2582
+ useInput11((input, key) => {
2308
2583
  if (input === "c" && key.ctrl) {
2309
2584
  if (state === "running") {
2310
2585
  handleQuit();
@@ -2315,7 +2590,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2315
2590
  });
2316
2591
  if (state === "setup" && devContext) {
2317
2592
  if (!devContext.appId || !devContext.extensionId) {
2318
- return /* @__PURE__ */ jsx17(
2593
+ return /* @__PURE__ */ jsx18(
2319
2594
  DevSetup,
2320
2595
  {
2321
2596
  token,
@@ -2327,7 +2602,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2327
2602
  return null;
2328
2603
  }
2329
2604
  if (state === "running" && devContext && resolvedContext) {
2330
- return /* @__PURE__ */ jsx17(
2605
+ return /* @__PURE__ */ jsx18(
2331
2606
  DevDashboard,
2332
2607
  {
2333
2608
  previewTunnelUrl,
@@ -2340,6 +2615,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2340
2615
  extensionId: resolvedContext.extensionId,
2341
2616
  extensionPort: options.extensionPort ? parseInt(options.extensionPort, 10) : devContext.extensionPort,
2342
2617
  previewPort: options.previewPort ? parseInt(options.previewPort, 10) : devContext.previewPort,
2618
+ manifestWarnings,
2343
2619
  onQuit: handleQuit
2344
2620
  }
2345
2621
  );
@@ -2347,13 +2623,13 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
2347
2623
  if (state === "stopping") {
2348
2624
  return null;
2349
2625
  }
2350
- return /* @__PURE__ */ jsx17(Box17, { children: /* @__PURE__ */ jsx17(Text17, { children: "Loading..." }) });
2626
+ return /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsx18(Text18, { children: "Loading..." }) });
2351
2627
  };
2352
2628
 
2353
2629
  // src/components/AIScaffold.tsx
2354
- import { Box as Box18, Text as Text18, useApp as useApp2 } from "ink";
2630
+ import { Box as Box19, Text as Text19, useApp as useApp2 } from "ink";
2355
2631
  import Spinner4 from "ink-spinner";
2356
- import { useState as useState12, useEffect as useEffect7 } from "react";
2632
+ import { useState as useState13, useEffect as useEffect7 } from "react";
2357
2633
 
2358
2634
  // src/lib/aiDocs.ts
2359
2635
  import { existsSync, readFileSync } from "fs";
@@ -2406,12 +2682,12 @@ var downloadAndExtractAiDocs = async (targetDir, version2) => {
2406
2682
  };
2407
2683
 
2408
2684
  // src/components/AIScaffold.tsx
2409
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
2685
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
2410
2686
  var AIScaffold = ({ version: version2 }) => {
2411
2687
  const { exit } = useApp2();
2412
- const [state, setState] = useState12("validating");
2413
- const [files, setFiles] = useState12([]);
2414
- const [errorMessage, setErrorMessage] = useState12("");
2688
+ const [state, setState] = useState13("validating");
2689
+ const [files, setFiles] = useState13([]);
2690
+ const [errorMessage, setErrorMessage] = useState13("");
2415
2691
  useEffect7(() => {
2416
2692
  const run = async () => {
2417
2693
  const projectDir = process.cwd();
@@ -2435,35 +2711,35 @@ var AIScaffold = ({ version: version2 }) => {
2435
2711
  };
2436
2712
  run();
2437
2713
  }, []);
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..." })
2714
+ return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", children: [
2715
+ /* @__PURE__ */ jsx19(Banner, {}),
2716
+ /* @__PURE__ */ jsxs18(StepShell, { title: "AI Editor Config", children: [
2717
+ state === "validating" && /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2718
+ /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: /* @__PURE__ */ jsx19(Spinner4, { type: "dots" }) }),
2719
+ /* @__PURE__ */ jsx19(Text19, { children: "Checking project..." })
2444
2720
  ] }),
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: [
2721
+ state === "downloading" && /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2722
+ /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: /* @__PURE__ */ jsx19(Spinner4, { type: "dots" }) }),
2723
+ /* @__PURE__ */ jsxs18(Text19, { children: [
2448
2724
  "Downloading AI editor configs (",
2449
2725
  version2,
2450
2726
  ")..."
2451
2727
  ] })
2452
2728
  ] }),
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: [
2729
+ state === "done" && /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", gap: 1, children: [
2730
+ /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2731
+ /* @__PURE__ */ jsx19(Text19, { color: "green", bold: true, children: "\u2714" }),
2732
+ /* @__PURE__ */ jsxs18(Text19, { bold: true, children: [
2457
2733
  "AI editor configs installed (",
2458
2734
  files.length,
2459
2735
  " files)"
2460
2736
  ] })
2461
2737
  ] }),
2462
- /* @__PURE__ */ jsx18(Box18, { flexDirection: "column", marginLeft: 2, children: files.map((f) => /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: f }, f)) })
2738
+ /* @__PURE__ */ jsx19(Box19, { flexDirection: "column", marginLeft: 2, children: files.map((f) => /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: f }, f)) })
2463
2739
  ] }),
2464
- state === "error" && /* @__PURE__ */ jsxs17(Box18, { gap: 1, children: [
2465
- /* @__PURE__ */ jsx18(Text18, { color: "red", children: "\u2716" }),
2466
- /* @__PURE__ */ jsx18(Text18, { children: errorMessage })
2740
+ state === "error" && /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2741
+ /* @__PURE__ */ jsx19(Text19, { color: "red", children: "\u2716" }),
2742
+ /* @__PURE__ */ jsx19(Text19, { children: errorMessage })
2467
2743
  ] })
2468
2744
  ] })
2469
2745
  ] });
@@ -2471,20 +2747,20 @@ var AIScaffold = ({ version: version2 }) => {
2471
2747
 
2472
2748
  // src/components/AuthLogin.tsx
2473
2749
  import { createServer } from "http";
2474
- import { Box as Box19, Text as Text19, useApp as useApp3 } from "ink";
2750
+ import { Box as Box20, Text as Text20, useApp as useApp3 } from "ink";
2475
2751
  import Spinner5 from "ink-spinner";
2476
2752
  import open from "open";
2477
- import { useState as useState13, useEffect as useEffect8 } from "react";
2753
+ import { useState as useState14, useEffect as useEffect8 } from "react";
2478
2754
 
2479
2755
  // src/lib/auth.ts
2480
- import { readFile as readFile3, writeFile as writeFile4, mkdir as mkdir2, unlink } from "fs/promises";
2756
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir2, unlink } from "fs/promises";
2481
2757
  import { join as join5 } from "path";
2482
2758
  import { homedir } from "os";
2483
2759
  var AUTH_DIR = join5(homedir(), ".stackable");
2484
2760
  var AUTH_FILE = join5(AUTH_DIR, "auth.json");
2485
2761
  var readAuthState = async () => {
2486
2762
  try {
2487
- const content = await readFile3(AUTH_FILE, "utf8");
2763
+ const content = await readFile4(AUTH_FILE, "utf8");
2488
2764
  return JSON.parse(content);
2489
2765
  } catch {
2490
2766
  return null;
@@ -2527,7 +2803,7 @@ var getToken = async () => {
2527
2803
  };
2528
2804
 
2529
2805
  // src/components/AuthLogin.tsx
2530
- import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
2806
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
2531
2807
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
2532
2808
  var callbackPage = (heading, sub, redirectUrl) => `<!DOCTYPE html>
2533
2809
  <html><head><meta charset="utf-8"><title>Stackable CLI</title>
@@ -2538,11 +2814,11 @@ ${redirectUrl ? `<script>(function(){var s=3,el=document.getElementById('h');fun
2538
2814
  </body></html>`;
2539
2815
  var AuthLogin = ({ dashboardUrl }) => {
2540
2816
  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("");
2817
+ const [state, setState] = useState14("waiting");
2818
+ const [loginUrl, setLoginUrl] = useState14("");
2819
+ const [userIdLabel, setUserIdLabel] = useState14("");
2820
+ const [orgIdLabel, setOrgIdLabel] = useState14("");
2821
+ const [errorMessage, setErrorMessage] = useState14("");
2546
2822
  useEffect8(() => {
2547
2823
  let server;
2548
2824
  let timeout;
@@ -2618,38 +2894,38 @@ var AuthLogin = ({ dashboardUrl }) => {
2618
2894
  server?.close();
2619
2895
  };
2620
2896
  }, []);
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..." })
2897
+ return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
2898
+ /* @__PURE__ */ jsx20(Banner, {}),
2899
+ /* @__PURE__ */ jsxs19(StepShell, { title: "Authenticate with Stackable", children: [
2900
+ state === "waiting" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", gap: 1, children: [
2901
+ /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
2902
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(Spinner5, { type: "dots" }) }),
2903
+ /* @__PURE__ */ jsx20(Text20, { children: "Waiting for browser authentication..." })
2628
2904
  ] }),
2629
- loginUrl && /* @__PURE__ */ jsxs18(Text19, { dimColor: true, children: [
2905
+ loginUrl && /* @__PURE__ */ jsxs19(Text20, { dimColor: true, children: [
2630
2906
  " ",
2631
2907
  loginUrl
2632
2908
  ] })
2633
2909
  ] }),
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 })
2910
+ state === "success" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", gap: 1, children: [
2911
+ /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
2912
+ /* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
2913
+ /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "User:" }),
2914
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: userIdLabel })
2639
2915
  ] }),
2640
- /* @__PURE__ */ jsxs18(Box19, { gap: 2, children: [
2641
- /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "Org: " }),
2642
- /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: orgIdLabel })
2916
+ /* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
2917
+ /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "Org: " }),
2918
+ /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: orgIdLabel })
2643
2919
  ] })
2644
2920
  ] }),
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" })
2921
+ /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
2922
+ /* @__PURE__ */ jsx20(Text20, { color: "green", bold: true, children: "\u2714" }),
2923
+ /* @__PURE__ */ jsx20(Text20, { bold: true, children: "Authenticated" })
2648
2924
  ] })
2649
2925
  ] }),
2650
- state === "error" && /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
2651
- /* @__PURE__ */ jsx19(Text19, { color: "red", children: "\u2716" }),
2652
- /* @__PURE__ */ jsx19(Text19, { children: errorMessage })
2926
+ state === "error" && /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
2927
+ /* @__PURE__ */ jsx20(Text20, { color: "red", children: "\u2716" }),
2928
+ /* @__PURE__ */ jsx20(Text20, { children: errorMessage })
2653
2929
  ] })
2654
2930
  ] })
2655
2931
  ] });
@@ -2657,70 +2933,70 @@ var AuthLogin = ({ dashboardUrl }) => {
2657
2933
 
2658
2934
  // src/components/AuthLogout.tsx
2659
2935
  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";
2936
+ import { Box as Box21, Text as Text21, useApp as useApp4 } from "ink";
2937
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
2662
2938
  var AuthLogout = () => {
2663
2939
  const { exit } = useApp4();
2664
2940
  useEffect9(() => {
2665
2941
  exit();
2666
2942
  }, [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" })
2943
+ return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", children: [
2944
+ /* @__PURE__ */ jsx21(Banner, {}),
2945
+ /* @__PURE__ */ jsx21(StepShell, { title: "Authenticate with Stackable", children: /* @__PURE__ */ jsxs20(Box21, { gap: 1, children: [
2946
+ /* @__PURE__ */ jsx21(Text21, { color: "green", bold: true, children: "\u2714" }),
2947
+ /* @__PURE__ */ jsx21(Text21, { bold: true, children: "Logged out" })
2672
2948
  ] }) })
2673
2949
  ] });
2674
2950
  };
2675
2951
 
2676
2952
  // src/components/AuthStatus.tsx
2677
2953
  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";
2954
+ import { useApp as useApp5, Box as Box22, Text as Text22 } from "ink";
2955
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
2680
2956
  var AuthStatus = ({ state, userId, orgId, expiry }) => {
2681
2957
  const { exit } = useApp5();
2682
2958
  useEffect10(() => {
2683
2959
  exit();
2684
2960
  }, [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 })
2961
+ return /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", children: [
2962
+ /* @__PURE__ */ jsx22(Banner, {}),
2963
+ /* @__PURE__ */ jsxs21(StepShell, { title: "Authenticate with Stackable", children: [
2964
+ state === "authenticated" && /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", gap: 1, children: [
2965
+ /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", children: [
2966
+ /* @__PURE__ */ jsxs21(Box22, { gap: 2, children: [
2967
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "User:" }),
2968
+ /* @__PURE__ */ jsx22(Text22, { color: "cyan", children: userId })
2693
2969
  ] }),
2694
- /* @__PURE__ */ jsxs20(Box21, { gap: 2, children: [
2695
- /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Org: " }),
2696
- /* @__PURE__ */ jsx21(Text21, { color: "cyan", children: orgId })
2970
+ /* @__PURE__ */ jsxs21(Box22, { gap: 2, children: [
2971
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "Org: " }),
2972
+ /* @__PURE__ */ jsx22(Text22, { color: "cyan", children: orgId })
2697
2973
  ] }),
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() })
2974
+ expiry && /* @__PURE__ */ jsxs21(Box22, { gap: 2, children: [
2975
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "Exp: " }),
2976
+ /* @__PURE__ */ jsx22(Text22, { color: "cyan", children: expiry.toLocaleDateString() })
2701
2977
  ] })
2702
2978
  ] }),
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" })
2979
+ /* @__PURE__ */ jsxs21(Box22, { gap: 1, children: [
2980
+ /* @__PURE__ */ jsx22(Text22, { color: "green", bold: true, children: "\u2714" }),
2981
+ /* @__PURE__ */ jsx22(Text22, { bold: true, children: "Authenticated" })
2706
2982
  ] })
2707
2983
  ] }),
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: [
2984
+ state === "expired" && /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", gap: 1, children: [
2985
+ /* @__PURE__ */ jsxs21(Box22, { gap: 1, children: [
2986
+ /* @__PURE__ */ jsx22(Text22, { color: "red", children: "\u2716" }),
2987
+ /* @__PURE__ */ jsxs21(Text22, { children: [
2712
2988
  "Session expired",
2713
2989
  expiry ? ` (${expiry.toLocaleDateString()})` : ""
2714
2990
  ] })
2715
2991
  ] }),
2716
- /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Run `stackable-app-extension auth login` to re-authenticate." })
2992
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "Run `stackable-app-extension auth login` to re-authenticate." })
2717
2993
  ] }),
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" })
2994
+ state === "not-logged-in" && /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", gap: 1, children: [
2995
+ /* @__PURE__ */ jsxs21(Box22, { gap: 1, children: [
2996
+ /* @__PURE__ */ jsx22(Text22, { color: "red", children: "\u2716" }),
2997
+ /* @__PURE__ */ jsx22(Text22, { children: "Not logged in" })
2722
2998
  ] }),
2723
- /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "Run `stackable-app-extension auth login`" })
2999
+ /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "Run `stackable-app-extension auth login`" })
2724
3000
  ] })
2725
3001
  ] })
2726
3002
  ] });
@@ -2774,7 +3050,7 @@ var checkForUpdate = (currentVersion) => {
2774
3050
  };
2775
3051
 
2776
3052
  // src/index.tsx
2777
- import { jsx as jsx22 } from "react/jsx-runtime";
3053
+ import { jsx as jsx23 } from "react/jsx-runtime";
2778
3054
  var require2 = createRequire(import.meta.url);
2779
3055
  var { version } = require2("../package.json");
2780
3056
  checkForUpdate(version);
@@ -2787,7 +3063,7 @@ var ensureToken = async () => {
2787
3063
  const message = err instanceof Error ? err.message : String(err);
2788
3064
  const isExpired = message.toLowerCase().includes("expired");
2789
3065
  render(
2790
- /* @__PURE__ */ jsx22(AuthStatus, { state: isExpired ? "expired" : "not-logged-in" })
3066
+ /* @__PURE__ */ jsx23(AuthStatus, { state: isExpired ? "expired" : "not-logged-in" })
2791
3067
  );
2792
3068
  return null;
2793
3069
  }
@@ -2800,7 +3076,7 @@ program.command("create" /* CREATE */).description("Create a new Extension proje
2800
3076
  }
2801
3077
  const { token, userId, orgId } = auth2;
2802
3078
  render(
2803
- /* @__PURE__ */ jsx22(
3079
+ /* @__PURE__ */ jsx23(
2804
3080
  App,
2805
3081
  {
2806
3082
  command: "create" /* CREATE */,
@@ -2820,7 +3096,7 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
2820
3096
  }
2821
3097
  const { token, userId, orgId } = auth2;
2822
3098
  render(
2823
- /* @__PURE__ */ jsx22(
3099
+ /* @__PURE__ */ jsx23(
2824
3100
  App,
2825
3101
  {
2826
3102
  command: "scaffold" /* SCAFFOLD */,
@@ -2832,14 +3108,14 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
2832
3108
  )
2833
3109
  );
2834
3110
  });
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) => {
3111
+ 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
3112
  const auth2 = await ensureToken();
2837
3113
  if (!auth2) {
2838
3114
  return;
2839
3115
  }
2840
3116
  const { token, userId, orgId } = auth2;
2841
3117
  render(
2842
- /* @__PURE__ */ jsx22(
3118
+ /* @__PURE__ */ jsx23(
2843
3119
  App,
2844
3120
  {
2845
3121
  command: "update" /* UPDATE */,
@@ -2859,7 +3135,7 @@ program.command("dev" /* DEV */).description("Start dev servers with a public tu
2859
3135
  }
2860
3136
  const { token, userId, orgId } = auth2;
2861
3137
  render(
2862
- /* @__PURE__ */ jsx22(
3138
+ /* @__PURE__ */ jsx23(
2863
3139
  DevApp,
2864
3140
  {
2865
3141
  options,
@@ -2874,17 +3150,17 @@ program.command("dev" /* DEV */).description("Start dev servers with a public tu
2874
3150
  var DASHBOARD_URL = process.env.ADMIN_DASHBOARD_URL ?? "https://admin.stackablelabs.io";
2875
3151
  var auth = program.command("auth").description("Manage CLI authentication");
2876
3152
  auth.command("login").description("Authenticate with Stackable via browser").action(async () => {
2877
- render(/* @__PURE__ */ jsx22(AuthLogin, { dashboardUrl: DASHBOARD_URL }));
3153
+ render(/* @__PURE__ */ jsx23(AuthLogin, { dashboardUrl: DASHBOARD_URL }));
2878
3154
  });
2879
3155
  auth.command("logout").description("Clear stored CLI credentials").action(async () => {
2880
3156
  await clearAuthState();
2881
- render(/* @__PURE__ */ jsx22(AuthLogout, {}));
3157
+ render(/* @__PURE__ */ jsx23(AuthLogout, {}));
2882
3158
  });
2883
3159
  auth.command("status").description("Show current authentication status").action(async () => {
2884
3160
  const state = await readAuthState();
2885
3161
  if (!state) {
2886
3162
  render(
2887
- /* @__PURE__ */ jsx22(AuthStatus, { state: "not-logged-in" })
3163
+ /* @__PURE__ */ jsx23(AuthStatus, { state: "not-logged-in" })
2888
3164
  );
2889
3165
  return;
2890
3166
  }
@@ -2892,11 +3168,11 @@ auth.command("status").description("Show current authentication status").action(
2892
3168
  const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
2893
3169
  const expiry = payload.exp ? new Date(payload.exp * 1e3) : null;
2894
3170
  if (expiry && Date.now() >= expiry.getTime()) {
2895
- render(/* @__PURE__ */ jsx22(AuthStatus, { state: "expired", expiry }));
3171
+ render(/* @__PURE__ */ jsx23(AuthStatus, { state: "expired", expiry }));
2896
3172
  return;
2897
3173
  }
2898
3174
  render(
2899
- /* @__PURE__ */ jsx22(
3175
+ /* @__PURE__ */ jsx23(
2900
3176
  AuthStatus,
2901
3177
  {
2902
3178
  state: "authenticated",
@@ -2909,6 +3185,6 @@ auth.command("status").description("Show current authentication status").action(
2909
3185
  });
2910
3186
  var ai = program.command("ai").description("AI editor configuration tools");
2911
3187
  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 }));
3188
+ render(/* @__PURE__ */ jsx23(AIScaffold, { version: options.version }));
2913
3189
  });
2914
3190
  program.parse(process.argv.filter((arg) => arg !== "--"));