@contentful/experience-design-system-cli 2.27.5-dev-build-67ce1cd.0 → 2.27.5-dev-build-99d3b1b.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/index.js CHANGED
@@ -9798,8 +9798,8 @@ function storeCDFComponents(db, sessionId2, components) {
9798
9798
  deleteAllowedValues.run(sessionId2, componentId, propName);
9799
9799
  prop.$values.forEach((v, i) => insertAllowedValue.run(sessionId2, componentId, propName, v, i));
9800
9800
  }
9801
- if (prop["$token.allowed"] !== void 0) {
9802
- writeTokenPaths(componentId, propName, prop["$token.allowed"]);
9801
+ if (prop.$type === "token" && prop.$category === "design") {
9802
+ writeTokenPaths(componentId, propName, prop["$token.allowed"] ?? []);
9803
9803
  }
9804
9804
  }
9805
9805
  const existingDefaults = new Map(
@@ -9852,8 +9852,8 @@ function storeCDFComponents(db, sessionId2, components) {
9852
9852
  if (prop.$values && prop.$values.length > 0) {
9853
9853
  prop.$values.forEach((v, i) => insertAllowedValue.run(sessionId2, componentId, propName, v, i));
9854
9854
  }
9855
- if (prop["$token.allowed"] !== void 0) {
9856
- writeTokenPaths(componentId, propName, prop["$token.allowed"]);
9855
+ if (prop.$type === "token" && prop.$category === "design") {
9856
+ writeTokenPaths(componentId, propName, prop["$token.allowed"] ?? []);
9857
9857
  }
9858
9858
  }
9859
9859
  let slotPos = 0;
@@ -10018,6 +10018,29 @@ function applyScopeDecisions(db, sessionId2, decisions) {
10018
10018
  }
10019
10019
  db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, sessionId2);
10020
10020
  }
10021
+ function storeDTCGTokens(db, sessionId2, groups, tokens) {
10022
+ const now = (/* @__PURE__ */ new Date()).toISOString();
10023
+ db.exec("BEGIN");
10024
+ try {
10025
+ db.prepare("DELETE FROM raw_token_groups WHERE session_id = ?").run(sessionId2);
10026
+ db.prepare("DELETE FROM raw_tokens WHERE session_id = ?").run(sessionId2);
10027
+ const insertGroup = db.prepare(`INSERT INTO raw_token_groups (session_id, path, description) VALUES (?, ?, ?)`);
10028
+ for (const group of groups) {
10029
+ insertGroup.run(sessionId2, group.path, group.$description ?? null);
10030
+ }
10031
+ const insertToken = db.prepare(
10032
+ `INSERT INTO raw_tokens (session_id, path, type, value, description) VALUES (?, ?, ?, ?, ?)`
10033
+ );
10034
+ for (const token of tokens) {
10035
+ insertToken.run(sessionId2, token.path, token.$type, JSON.stringify(token.$value), token.$description ?? null);
10036
+ }
10037
+ db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, sessionId2);
10038
+ db.exec("COMMIT");
10039
+ } catch (e) {
10040
+ db.exec("ROLLBACK");
10041
+ throw e;
10042
+ }
10043
+ }
10021
10044
  function applyTokenToolCalls(db, sessionId2, calls, incomingWarnings) {
10022
10045
  const now = (/* @__PURE__ */ new Date()).toISOString();
10023
10046
  const warnings = [...incomingWarnings];
@@ -22301,6 +22324,7 @@ function parseToState(json) {
22301
22324
  description: typeof p.$description === "string" ? p.$description : "",
22302
22325
  values: Array.isArray(p.$values) ? p.$values.filter((v) => typeof v === "string") : [],
22303
22326
  tokenKind: typeof p["$token.kind"] === "string" ? p["$token.kind"] : "",
22327
+ allowed: Array.isArray(p["$token.allowed"]) ? p["$token.allowed"].filter((v) => typeof v === "string") : [],
22304
22328
  default: defaultValue
22305
22329
  };
22306
22330
  });
@@ -22339,6 +22363,7 @@ function serializeState(state, originalJson) {
22339
22363
  if (p.description) def.$description = p.description;
22340
22364
  if (p.type === "enum" && p.values.length > 0) def.$values = p.values;
22341
22365
  if (p.type === "token" && p.tokenKind) def["$token.kind"] = p.tokenKind;
22366
+ if (p.type === "token" && p.allowed.length > 0) def["$token.allowed"] = p.allowed;
22342
22367
  if (p.default !== null) {
22343
22368
  if (p.type === "boolean" && typeof p.default === "boolean") {
22344
22369
  def.$default = p.default;
@@ -22490,6 +22515,10 @@ function PropRow({
22490
22515
  /* @__PURE__ */ jsx45(Text44, { dimColor: true, children: "desc:" }),
22491
22516
  /* @__PURE__ */ jsx45(Text44, { color: PALETTE.success, children: prop.description || "\u2014" })
22492
22517
  ] }),
22518
+ selected && prop.type === "token" && prop.category === "design" && /* @__PURE__ */ jsxs44(Box42, { paddingLeft: 2, flexDirection: "row", gap: 1, children: [
22519
+ /* @__PURE__ */ jsx45(Text44, { dimColor: true, children: "allowed:" }),
22520
+ activeField === "allowed" ? /* @__PURE__ */ jsx45(Box42, { flexGrow: 1, borderStyle: "round", borderColor: PALETTE.info, paddingX: 1, children: /* @__PURE__ */ jsx45(Text44, { dimColor: true, children: "press [t] to edit allowed tokens" }) }) : /* @__PURE__ */ jsx45(Text44, { color: prop.allowed.length > 0 ? PALETTE.info : void 0, dimColor: prop.allowed.length === 0, children: prop.allowed.length > 0 ? prop.allowed.join(", ") : "(any)" })
22521
+ ] }),
22493
22522
  selected && rationale && rationale.trim().length > 0 && /* @__PURE__ */ jsx45(Box42, { paddingLeft: 2, children: /* @__PURE__ */ jsx45(Text44, { dimColor: true, children: (() => {
22494
22523
  const max = Math.max(8, width - 8);
22495
22524
  const text = `~ ${rationale}`;
@@ -22609,12 +22638,15 @@ function SlotRow({
22609
22638
  }
22610
22639
  function propFields(prop) {
22611
22640
  const fields = ["type", "category", "required"];
22612
- if (prop.type === "token") fields.push("tokenKind");
22641
+ if (prop.type === "token") {
22642
+ fields.push("tokenKind");
22643
+ }
22613
22644
  if (prop.type === "enum") fields.push("values");
22614
22645
  if (prop.type !== "richtext" && prop.type !== "media" && prop.type !== "link") {
22615
22646
  fields.push("default");
22616
22647
  }
22617
22648
  fields.push("description");
22649
+ if (prop.type === "token" && prop.category === "design") fields.push("allowed");
22618
22650
  return fields;
22619
22651
  }
22620
22652
  function simulateGraphWithCandidate(projectSlotGraph, selfName, currentSlots, targetSlotName, candidate) {
@@ -23173,7 +23205,12 @@ function FieldEditor({
23173
23205
  const idx = options.indexOf(currentProp.type);
23174
23206
  const next = key.leftArrow ? options[(idx - 1 + options.length) % options.length] : options[(idx + 1) % options.length];
23175
23207
  const updated = { ...currentProp, type: next };
23176
- if (next !== "token") updated.tokenKind = "";
23208
+ if (next === "token") {
23209
+ updated.category = "design";
23210
+ updated.tokenKind ||= DESIGN_TOKEN_TYPES2[0] ?? "";
23211
+ } else {
23212
+ updated.tokenKind = "";
23213
+ }
23177
23214
  if (next !== "enum") updated.values = [];
23178
23215
  const nextProps = props.map((p, i) => i === propIdx ? updated : p);
23179
23216
  commit({ ...editorState, props: nextProps });
@@ -23914,6 +23951,100 @@ var init_ComponentRationalePanel = __esm({
23914
23951
  }
23915
23952
  });
23916
23953
 
23954
+ // packages/experience-design-system-cli/src/analyze/select/tui/components/TokenReviewPanel.tsx
23955
+ import { Box as Box45, Text as Text47 } from "ink";
23956
+ import { jsx as jsx48, jsxs as jsxs47 } from "react/jsx-runtime";
23957
+ function collectTokenSuggestions(entry, availableTokens = []) {
23958
+ return Object.entries(entry.$properties).filter(([, def]) => {
23959
+ const rawKind = def["$token.kind"];
23960
+ return def.$type === "token" && def.$category === "design" && (typeof rawKind === "string" || Array.isArray(rawKind));
23961
+ }).map(([propName, def]) => {
23962
+ const persistedAllowed = [...def["$token.allowed"] ?? []];
23963
+ const rawKind = def["$token.kind"];
23964
+ const kinds = Array.isArray(rawKind) ? rawKind.filter((kind) => typeof kind === "string") : typeof rawKind === "string" ? rawKind.split(",").map((kind) => kind.trim()).filter(Boolean) : [];
23965
+ const compatible = availableTokens.filter((token) => kinds.includes(token.kind)).map((token) => token.path);
23966
+ const compatiblePaths = new Set(compatible);
23967
+ const allowed = availableTokens.length > 0 ? persistedAllowed.filter((path) => compatiblePaths.has(path)) : persistedAllowed;
23968
+ const paths = availableTokens.length > 0 ? compatible : allowed;
23969
+ return { propName, paths, suggested: [...allowed], allowed };
23970
+ });
23971
+ }
23972
+ function TokenReviewPanel({
23973
+ componentName,
23974
+ suggestions,
23975
+ selectedRow,
23976
+ editing,
23977
+ editCursor,
23978
+ editSelection,
23979
+ width,
23980
+ height,
23981
+ active
23982
+ }) {
23983
+ const current = suggestions[selectedRow];
23984
+ if (editing && current) {
23985
+ const visibleCount = Math.max(1, height - 6);
23986
+ const maxStart = Math.max(0, current.paths.length - visibleCount);
23987
+ const scrollStart = Math.max(0, Math.min(editCursor - Math.floor(visibleCount / 2), maxStart));
23988
+ const visiblePaths = current.paths.slice(scrollStart, scrollStart + visibleCount);
23989
+ const rangeLabel = current.paths.length === 0 ? "no compatible tokens" : `${scrollStart + 1}-${scrollStart + visiblePaths.length} of ${current.paths.length}`;
23990
+ return /* @__PURE__ */ jsxs47(
23991
+ Box45,
23992
+ {
23993
+ flexDirection: "column",
23994
+ width,
23995
+ height: height + 2,
23996
+ borderStyle: "single",
23997
+ borderColor: active ? PALETTE.inverse : void 0,
23998
+ children: [
23999
+ /* @__PURE__ */ jsx48(Text47, { bold: true, dimColor: !active, wrap: "truncate", children: `TOKEN REVIEW \u2014 ${componentName} \xB7 ${current.propName} (edit allowed)` }),
24000
+ /* @__PURE__ */ jsx48(Text47, { dimColor: true, wrap: "truncate", children: `select which tokens are allowed (${rangeLabel})` }),
24001
+ /* @__PURE__ */ jsx48(Text47, { children: " " }),
24002
+ current.paths.length === 0 && /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "(no compatible tokens found for this token kind)" }),
24003
+ visiblePaths.map((path, i) => {
24004
+ const pathIndex = scrollStart + i;
24005
+ const checked = editSelection.has(path);
24006
+ const focused = pathIndex === editCursor;
24007
+ return /* @__PURE__ */ jsx48(Box45, { children: /* @__PURE__ */ jsx48(Text47, { color: focused ? PALETTE.info : void 0, bold: focused, dimColor: !active, wrap: "truncate", children: ` [${checked ? "x" : " "}] ${path}` }) }, path);
24008
+ }),
24009
+ /* @__PURE__ */ jsx48(Text47, { children: " " }),
24010
+ /* @__PURE__ */ jsx48(Text47, { dimColor: true, wrap: "truncate", children: "[\u2191/\u2193] move [Space] toggle" }),
24011
+ /* @__PURE__ */ jsx48(Text47, { dimColor: true, wrap: "truncate", children: "[Ctrl+S] save [Esc] cancel" })
24012
+ ]
24013
+ }
24014
+ );
24015
+ }
24016
+ return /* @__PURE__ */ jsxs47(
24017
+ Box45,
24018
+ {
24019
+ flexDirection: "column",
24020
+ width,
24021
+ height: height + 2,
24022
+ borderStyle: "single",
24023
+ borderColor: active ? PALETTE.inverse : void 0,
24024
+ children: [
24025
+ /* @__PURE__ */ jsx48(Text47, { bold: true, dimColor: !active, children: `TOKEN REVIEW \u2014 ${componentName}` }),
24026
+ suggestions.length === 0 && /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "(no token suggestions for this component)" }),
24027
+ suggestions.map((s, i) => {
24028
+ const focused = i === selectedRow;
24029
+ return /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", children: [
24030
+ /* @__PURE__ */ jsx48(Box45, { children: /* @__PURE__ */ jsx48(Text47, { color: focused ? PALETTE.info : void 0, bold: focused, dimColor: !active, children: `${focused ? "\u25B6" : " "} ${s.propName}` }) }),
24031
+ /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: ` suggested: ${s.suggested.join(", ")}` }),
24032
+ /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: ` allowed: ${s.allowed.join(", ")}` })
24033
+ ] }, s.propName);
24034
+ }),
24035
+ /* @__PURE__ */ jsx48(Text47, { children: " " }),
24036
+ /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "[\u2191/\u2193] move [Enter] edit allowed [Esc] close" })
24037
+ ]
24038
+ }
24039
+ );
24040
+ }
24041
+ var init_TokenReviewPanel = __esm({
24042
+ "packages/experience-design-system-cli/src/analyze/select/tui/components/TokenReviewPanel.tsx"() {
24043
+ "use strict";
24044
+ init_theme();
24045
+ }
24046
+ });
24047
+
23917
24048
  // packages/experience-design-system-cli/src/analyze/select/preview-annotations.ts
23918
24049
  function applyPreviewAnnotations(preview, localNames) {
23919
24050
  const out = /* @__PURE__ */ new Map();
@@ -24366,8 +24497,8 @@ var init_history = __esm({
24366
24497
 
24367
24498
  // packages/experience-design-system-cli/src/import/tui/steps/GenerateReviewStep.tsx
24368
24499
  import { useEffect as useEffect13, useMemo as useMemo7, useRef as useRef7, useState as useState26 } from "react";
24369
- import { Box as Box45, Text as Text47, useStdout as useStdout6 } from "ink";
24370
- import { Fragment as Fragment14, jsx as jsx48, jsxs as jsxs47 } from "react/jsx-runtime";
24500
+ import { Box as Box46, Text as Text48, useStdout as useStdout6 } from "ink";
24501
+ import { Fragment as Fragment14, jsx as jsx49, jsxs as jsxs48 } from "react/jsx-runtime";
24371
24502
  function sortComponentsForSidebar2(components, cycleParticipants) {
24372
24503
  const isEmpty2 = (entry) => Object.keys(entry.$properties ?? {}).length === 0 && Object.keys(entry.$slots ?? {}).length === 0;
24373
24504
  const tier = (c2) => {
@@ -24425,6 +24556,7 @@ function deriveBreakingChanges(response) {
24425
24556
  }
24426
24557
  function GenerateReviewStep({
24427
24558
  extractSessionId,
24559
+ tokenSessionId,
24428
24560
  onFinalize,
24429
24561
  onQuit,
24430
24562
  livePreview = true,
@@ -24465,6 +24597,12 @@ function GenerateReviewStep({
24465
24597
  const [panelScrollOffset, setPanelScrollOffset] = useState26(0);
24466
24598
  const [textEntryActive, setTextEntryActive] = useState26(false);
24467
24599
  const [componentRationale, setComponentRationale] = useState26(null);
24600
+ const [tokenReviewRow, setTokenReviewRow] = useState26(0);
24601
+ const [tokenReviewEditing, setTokenReviewEditing] = useState26(false);
24602
+ const [tokenReviewEditCursor, setTokenReviewEditCursor] = useState26(0);
24603
+ const [tokenReviewEditSelection, setTokenReviewEditSelection] = useState26(/* @__PURE__ */ new Set());
24604
+ const [availableTokens, setAvailableTokens] = useState26([]);
24605
+ const tokenReviewSuggestedRef = useRef7(/* @__PURE__ */ new Map());
24468
24606
  const pendingGRef = useRef7(false);
24469
24607
  const [slotCycles, setSlotCycles] = useState26([]);
24470
24608
  const [cyclePanelScroll, setCyclePanelScroll] = useState26(0);
@@ -24552,9 +24690,14 @@ function GenerateReviewStep({
24552
24690
  const db = openPipelineDb();
24553
24691
  let cdfComponents = [];
24554
24692
  let cycles = [];
24693
+ let tokens = [];
24555
24694
  try {
24556
24695
  cdfComponents = loadCDFComponents(db, extractSessionId);
24557
24696
  cycles = loadSlotCycles(db, extractSessionId);
24697
+ tokens = loadDTCGTokens(db, tokenSessionId ?? extractSessionId).tokens.map((token) => ({
24698
+ path: token.path,
24699
+ kind: token.$type
24700
+ }));
24558
24701
  } finally {
24559
24702
  db.close();
24560
24703
  }
@@ -24562,6 +24705,7 @@ function GenerateReviewStep({
24562
24705
  return {
24563
24706
  entries: [],
24564
24707
  cycles: [],
24708
+ tokens: [],
24565
24709
  error: "No generated definitions found for this session. Try re-running generate."
24566
24710
  };
24567
24711
  }
@@ -24575,25 +24719,34 @@ function GenerateReviewStep({
24575
24719
  return {
24576
24720
  entries: sortComponentsForSidebar2(reviewEntries, cycleParticipants),
24577
24721
  cycles,
24722
+ tokens,
24578
24723
  error: null
24579
24724
  };
24580
24725
  };
24581
24726
  useEffect13(() => {
24582
- try {
24583
- const { entries, cycles, error } = loadSessionState();
24584
- if (error) {
24585
- setLoadError(error);
24586
- setLoading(false);
24587
- return;
24727
+ let disposed = false;
24728
+ void (async () => {
24729
+ try {
24730
+ const { entries, cycles, tokens, error } = loadSessionState();
24731
+ if (error) {
24732
+ if (!disposed) setLoadError(error);
24733
+ return;
24734
+ }
24735
+ const catalog = tokensPath ? (await readTokensFromPath("tokens", tokensPath)).map((token) => ({ path: token.path, kind: token.$type })) : tokens;
24736
+ if (disposed) return;
24737
+ setSlotCycles(cycles);
24738
+ setAvailableTokens(catalog);
24739
+ setComponents(entries);
24740
+ } catch (e) {
24741
+ if (!disposed) setLoadError(String(e));
24742
+ } finally {
24743
+ if (!disposed) setLoading(false);
24588
24744
  }
24589
- setSlotCycles(cycles);
24590
- setComponents(entries);
24591
- setLoading(false);
24592
- } catch (e) {
24593
- setLoadError(String(e));
24594
- setLoading(false);
24595
- }
24596
- }, []);
24745
+ })();
24746
+ return () => {
24747
+ disposed = true;
24748
+ };
24749
+ }, [extractSessionId, tokenSessionId, tokensPath]);
24597
24750
  useEffect13(() => {
24598
24751
  if (loading) return;
24599
24752
  if (!livePreview) return;
@@ -24759,12 +24912,13 @@ function GenerateReviewStep({
24759
24912
  };
24760
24913
  const reloadFromSave = () => {
24761
24914
  try {
24762
- const { entries, cycles, error } = loadSessionState();
24915
+ const { entries, cycles, tokens, error } = loadSessionState();
24763
24916
  if (error) {
24764
24917
  setLoadError(error);
24765
24918
  return;
24766
24919
  }
24767
24920
  setSlotCycles(cycles);
24921
+ setAvailableTokens(tokens);
24768
24922
  setComponents(entries);
24769
24923
  const reloadGraph = buildComponentGraph(entries);
24770
24924
  const reloadClosures = computeAllClosures(reloadGraph);
@@ -24874,6 +25028,12 @@ function GenerateReviewStep({
24874
25028
  db.close();
24875
25029
  }
24876
25030
  }, [selectedIdx, components, extractSessionId]);
25031
+ useEffect13(() => {
25032
+ setTokenReviewRow(0);
25033
+ setTokenReviewEditing(false);
25034
+ setTokenReviewEditCursor(0);
25035
+ setTokenReviewEditSelection(/* @__PURE__ */ new Set());
25036
+ }, [selectedIdx]);
24877
25037
  useEffect13(() => {
24878
25038
  const current = components[selectedIdx];
24879
25039
  if (!current) {
@@ -25045,6 +25205,44 @@ function GenerateReviewStep({
25045
25205
  recomputeCycles(next);
25046
25206
  pushHistorySnapshot(next, autoRejected, undoSnapshot, "reject-cascade");
25047
25207
  };
25208
+ const currentTokenSuggestions = () => {
25209
+ const current = components[selectedIdx];
25210
+ if (!current) return [];
25211
+ return collectTokenSuggestions(current.entry, availableTokens).map((suggestion) => {
25212
+ const snapshotKey = `${current.key}::${suggestion.propName}`;
25213
+ const suggested = tokenReviewSuggestedRef.current.get(snapshotKey) ?? [...suggestion.suggested];
25214
+ tokenReviewSuggestedRef.current.set(snapshotKey, suggested);
25215
+ return { ...suggestion, suggested };
25216
+ });
25217
+ };
25218
+ const persistTokenFields = (propName, allowed) => {
25219
+ const current = components[selectedIdx];
25220
+ if (!current) return;
25221
+ const prop = current.entry.$properties[propName];
25222
+ if (!prop) return;
25223
+ const nextProp = { ...prop };
25224
+ nextProp["$token.allowed"] = allowed;
25225
+ const nextEntry = {
25226
+ ...current.entry,
25227
+ $properties: { ...current.entry.$properties, [propName]: nextProp }
25228
+ };
25229
+ const next = components.map((c2, i) => i === selectedIdx ? { ...c2, entry: nextEntry } : c2);
25230
+ setComponents(next);
25231
+ const db = openPipelineDb();
25232
+ try {
25233
+ storeCDFComponents(db, extractSessionId, [{ key: current.key, entry: nextEntry }]);
25234
+ } finally {
25235
+ db.close();
25236
+ }
25237
+ livePreviewHook.trigger();
25238
+ pushHistorySnapshot(next, autoRejected, undoSnapshot, `token-review:${propName}`);
25239
+ };
25240
+ const handleTokenEditSave = (s) => {
25241
+ const allowed = s.paths.filter((p) => tokenReviewEditSelection.has(p));
25242
+ if (allowed.length === 0) return;
25243
+ persistTokenFields(s.propName, allowed);
25244
+ setTokenReviewEditing(false);
25245
+ };
25048
25246
  const dialogOpen = showFinalize || showQuit;
25049
25247
  useImmediateInput((input, key) => {
25050
25248
  if (loading) return;
@@ -25315,6 +25513,65 @@ function GenerateReviewStep({
25315
25513
  setJumpFilterTarget((prev) => prev === t ? null : t);
25316
25514
  return;
25317
25515
  }
25516
+ if (panelOpen === "token-review") {
25517
+ const suggestions = currentTokenSuggestions();
25518
+ const row = suggestions[tokenReviewRow];
25519
+ if (tokenReviewEditing) {
25520
+ if (row && row.paths.length > 0) {
25521
+ if (key.upArrow || input === "k") {
25522
+ setTokenReviewEditCursor((c2) => Math.max(0, c2 - 1));
25523
+ return;
25524
+ }
25525
+ if (key.downArrow || input === "j") {
25526
+ setTokenReviewEditCursor((c2) => Math.min(row.paths.length - 1, c2 + 1));
25527
+ return;
25528
+ }
25529
+ if (input === " " || key.return) {
25530
+ const path = row.paths[tokenReviewEditCursor];
25531
+ setTokenReviewEditSelection((prev) => {
25532
+ const next = new Set(prev);
25533
+ if (next.has(path) && next.size === 1) return next;
25534
+ if (next.has(path)) next.delete(path);
25535
+ else next.add(path);
25536
+ return next;
25537
+ });
25538
+ return;
25539
+ }
25540
+ if (key.ctrl && input === "s") {
25541
+ handleTokenEditSave(row);
25542
+ return;
25543
+ }
25544
+ }
25545
+ if (key.escape) {
25546
+ setTokenReviewEditing(false);
25547
+ return;
25548
+ }
25549
+ return;
25550
+ }
25551
+ if (key.upArrow || input === "k") {
25552
+ setTokenReviewRow((r) => Math.max(0, r - 1));
25553
+ return;
25554
+ }
25555
+ if (key.downArrow || input === "j") {
25556
+ setTokenReviewRow((r) => Math.min(Math.max(0, suggestions.length - 1), r + 1));
25557
+ return;
25558
+ }
25559
+ if (key.return && row) {
25560
+ setTokenReviewEditCursor(0);
25561
+ setTokenReviewEditSelection(new Set(row.allowed));
25562
+ setTokenReviewEditing(true);
25563
+ return;
25564
+ }
25565
+ if (key.escape) {
25566
+ setPanelOpen("none");
25567
+ return;
25568
+ }
25569
+ if (input === "t") {
25570
+ setPanelOpen("none");
25571
+ return;
25572
+ }
25573
+ return;
25574
+ }
25318
25575
  if (panelOpen !== "none") {
25319
25576
  const PANEL_HEIGHT_LOCAL = 12;
25320
25577
  const next = computeNextScrollOffset(panelScrollOffset, input, key, 9999, PANEL_HEIGHT_LOCAL);
@@ -25377,6 +25634,11 @@ function GenerateReviewStep({
25377
25634
  setPanelScrollOffset(() => 0);
25378
25635
  return;
25379
25636
  }
25637
+ if (input === "t" && currentTokenSuggestions().length > 0) {
25638
+ setPanelOpen("token-review");
25639
+ setTokenReviewRow(0);
25640
+ return;
25641
+ }
25380
25642
  }
25381
25643
  if (key.tab) {
25382
25644
  if (!sidebarFocused && editorDirty) {
@@ -25598,42 +25860,42 @@ function GenerateReviewStep({
25598
25860
  }
25599
25861
  });
25600
25862
  if (loading) {
25601
- return /* @__PURE__ */ jsx48(Box45, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "Loading generated definitions..." }) });
25863
+ return /* @__PURE__ */ jsx49(Box46, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "Loading generated definitions..." }) });
25602
25864
  }
25603
25865
  if (loadError) {
25604
- return /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
25605
- /* @__PURE__ */ jsx48(Text47, { color: PALETTE.error, children: loadError }),
25606
- /* @__PURE__ */ jsx48(Text47, { children: " " }),
25607
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "[q / Enter / Esc] Quit" })
25866
+ return /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
25867
+ /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, children: loadError }),
25868
+ /* @__PURE__ */ jsx49(Text48, { children: " " }),
25869
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "[q / Enter / Esc] Quit" })
25608
25870
  ] });
25609
25871
  }
25610
25872
  if (showHelp) {
25611
- return /* @__PURE__ */ jsx48(HelpOverlay, { sections: HELP_SECTIONS2, onClose: () => setShowHelp(false) });
25873
+ return /* @__PURE__ */ jsx49(HelpOverlay, { sections: HELP_SECTIONS2, onClose: () => setShowHelp(false) });
25612
25874
  }
25613
25875
  const renderBreakOverlay = (width) => {
25614
25876
  const highlightedCycle = slotCycles[cyclesCursor];
25615
- return /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, width, children: [
25616
- /* @__PURE__ */ jsx48(Text47, { bold: true, color: PALETTE.warning, children: `BREAK CYCLE ${cyclesCursor + 1} \u2014 remove a slot edge or reject a member` }),
25877
+ return /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, width, children: [
25878
+ /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.warning, children: `BREAK CYCLE ${cyclesCursor + 1} \u2014 remove a slot edge or reject a member` }),
25617
25879
  highlightedCycle && (() => {
25618
25880
  const segs = formatCyclePathSegments(highlightedCycle);
25619
- return /* @__PURE__ */ jsxs47(Text47, { children: [
25881
+ return /* @__PURE__ */ jsxs48(Text48, { children: [
25620
25882
  " ",
25621
25883
  segs.map(
25622
- (seg, si) => seg.kind === "slot" ? /* @__PURE__ */ jsx48(Text47, { color: PALETTE.info, children: seg.text }, si) : seg.kind === "arrow" ? /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: seg.text }, si) : /* @__PURE__ */ jsx48(Text47, { color: PALETTE.warning, children: seg.text }, si)
25884
+ (seg, si) => seg.kind === "slot" ? /* @__PURE__ */ jsx49(Text48, { color: PALETTE.info, children: seg.text }, si) : seg.kind === "arrow" ? /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: seg.text }, si) : /* @__PURE__ */ jsx49(Text48, { color: PALETTE.warning, children: seg.text }, si)
25623
25885
  )
25624
25886
  ] });
25625
25887
  })(),
25626
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: highlightedCycle ? "Deleting an edge removes it from $allowedComponents (undo with Ctrl+Z)." : "No cycle highlighted." }),
25627
- /* @__PURE__ */ jsx48(Text47, { children: " " }),
25628
- breakEdges.length > 0 && /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "remove slot edge:" }),
25888
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: highlightedCycle ? "Deleting an edge removes it from $allowedComponents (undo with Ctrl+Z)." : "No cycle highlighted." }),
25889
+ /* @__PURE__ */ jsx49(Text48, { children: " " }),
25890
+ breakEdges.length > 0 && /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "remove slot edge:" }),
25629
25891
  breakEdges.map((edge, idx) => {
25630
25892
  const isCursor = idx === breakCursor;
25631
- return /* @__PURE__ */ jsx48(Text47, { inverse: isCursor, children: `${isCursor ? "\u25B6" : " "} remove '${edge.toComponent}' from ${edge.fromComponent}.$slots.${edge.slotName}.$allowedComponents` }, `break-${idx}`);
25893
+ return /* @__PURE__ */ jsx49(Text48, { inverse: isCursor, children: `${isCursor ? "\u25B6" : " "} remove '${edge.toComponent}' from ${edge.fromComponent}.$slots.${edge.slotName}.$allowedComponents` }, `break-${idx}`);
25632
25894
  }),
25633
- breakConfirm ? /* @__PURE__ */ jsxs47(Fragment14, { children: [
25634
- /* @__PURE__ */ jsx48(Text47, { children: " " }),
25635
- /* @__PURE__ */ jsx48(Text47, { bold: true, color: PALETTE.warning, children: "Delete this slot edge? [y] confirm [n] cancel" })
25636
- ] }) : /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "[\u2191\u2193/j/k] move [Enter] delete [x/Esc] close" })
25895
+ breakConfirm ? /* @__PURE__ */ jsxs48(Fragment14, { children: [
25896
+ /* @__PURE__ */ jsx49(Text48, { children: " " }),
25897
+ /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.warning, children: "Delete this slot edge? [y] confirm [n] cancel" })
25898
+ ] }) : /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "[\u2191\u2193/j/k] move [Enter] delete [x/Esc] close" })
25637
25899
  ] });
25638
25900
  };
25639
25901
  const breakOverlayFullScreen = breakPanel.isOpen && shouldBreakOverlayGoFullScreen({
@@ -25680,8 +25942,8 @@ function GenerateReviewStep({
25680
25942
  const needsReview = components.filter((c2) => c2.status === "needs-review").length;
25681
25943
  const propCount = selected ? Object.keys(selected.entry.$properties).length : 0;
25682
25944
  const slotCount = selected?.entry.$slots ? Object.keys(selected.entry.$slots).length : 0;
25683
- return /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", children: [
25684
- showFinalize && /* @__PURE__ */ jsx48(
25945
+ return /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", children: [
25946
+ showFinalize && /* @__PURE__ */ jsx49(
25685
25947
  FinalizeDialog,
25686
25948
  {
25687
25949
  accepted,
@@ -25694,31 +25956,31 @@ function GenerateReviewStep({
25694
25956
  onCancel: () => setShowFinalize(false)
25695
25957
  }
25696
25958
  ),
25697
- showQuit && /* @__PURE__ */ jsx48(QuitDialog, { hasUnsavedDrafts: false, onConfirm: onQuit, onCancel: () => setShowQuit(false) }),
25698
- showUnsavedWarning && !dialogOpen && /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
25699
- /* @__PURE__ */ jsx48(Text47, { bold: true, color: PALETTE.warning, children: "Unsaved changes" }),
25700
- /* @__PURE__ */ jsx48(Text47, { children: "You have unsaved edits in the current field editor." }),
25701
- /* @__PURE__ */ jsx48(Text47, { children: " " }),
25702
- /* @__PURE__ */ jsx48(Text47, { children: " [Enter] Save and continue" }),
25703
- /* @__PURE__ */ jsx48(Text47, { children: " [Esc] Discard changes and continue" }),
25704
- /* @__PURE__ */ jsx48(Text47, { children: " [Tab] Stay in the panel" })
25959
+ showQuit && /* @__PURE__ */ jsx49(QuitDialog, { hasUnsavedDrafts: false, onConfirm: onQuit, onCancel: () => setShowQuit(false) }),
25960
+ showUnsavedWarning && !dialogOpen && /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
25961
+ /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.warning, children: "Unsaved changes" }),
25962
+ /* @__PURE__ */ jsx49(Text48, { children: "You have unsaved edits in the current field editor." }),
25963
+ /* @__PURE__ */ jsx49(Text48, { children: " " }),
25964
+ /* @__PURE__ */ jsx49(Text48, { children: " [Enter] Save and continue" }),
25965
+ /* @__PURE__ */ jsx49(Text48, { children: " [Esc] Discard changes and continue" }),
25966
+ /* @__PURE__ */ jsx49(Text48, { children: " [Tab] Stay in the panel" })
25705
25967
  ] }),
25706
- showReloadDialog && !dialogOpen && /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
25707
- /* @__PURE__ */ jsx48(Text47, { bold: true, color: PALETTE.warning, children: "Reload from saved state?" }),
25708
- /* @__PURE__ */ jsx48(Text47, { children: "Unsaved in-memory changes will be lost." }),
25709
- /* @__PURE__ */ jsx48(Text47, { children: " " }),
25710
- /* @__PURE__ */ jsx48(Text47, { children: " [Enter] Confirm" }),
25711
- /* @__PURE__ */ jsx48(Text47, { children: " [Esc] Cancel" })
25968
+ showReloadDialog && !dialogOpen && /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
25969
+ /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.warning, children: "Reload from saved state?" }),
25970
+ /* @__PURE__ */ jsx49(Text48, { children: "Unsaved in-memory changes will be lost." }),
25971
+ /* @__PURE__ */ jsx49(Text48, { children: " " }),
25972
+ /* @__PURE__ */ jsx49(Text48, { children: " [Enter] Confirm" }),
25973
+ /* @__PURE__ */ jsx49(Text48, { children: " [Esc] Cancel" })
25712
25974
  ] }),
25713
- removedComponents.length > 0 && !dialogOpen && /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.error, paddingX: 1, children: [
25714
- /* @__PURE__ */ jsx48(Text47, { bold: true, color: PALETTE.error, children: removedComponentsHeader(removedComponents.length, true) }),
25715
- !removedBannerCollapsed && /* @__PURE__ */ jsxs47(Fragment14, { children: [
25716
- /* @__PURE__ */ jsx48(Text47, { children: " " }),
25717
- removedComponents.map((rc) => /* @__PURE__ */ jsx48(Text47, { children: removedComponentLine(rc) }, rc.id))
25975
+ removedComponents.length > 0 && !dialogOpen && /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.error, paddingX: 1, children: [
25976
+ /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.error, children: removedComponentsHeader(removedComponents.length, true) }),
25977
+ !removedBannerCollapsed && /* @__PURE__ */ jsxs48(Fragment14, { children: [
25978
+ /* @__PURE__ */ jsx49(Text48, { children: " " }),
25979
+ removedComponents.map((rc) => /* @__PURE__ */ jsx49(Text48, { children: removedComponentLine(rc) }, rc.id))
25718
25980
  ] })
25719
25981
  ] }),
25720
- breakingChanges.length > 0 && !dialogOpen && /* @__PURE__ */ jsx48(Box45, { paddingX: 1, children: /* @__PURE__ */ jsx48(
25721
- Text47,
25982
+ breakingChanges.length > 0 && !dialogOpen && /* @__PURE__ */ jsx49(Box46, { paddingX: 1, children: /* @__PURE__ */ jsx49(
25983
+ Text48,
25722
25984
  {
25723
25985
  color: PALETTE.warning,
25724
25986
  children: `[b] ${breakingChanges.length} breaking change${breakingChanges.length === 1 ? "" : "s"}`
@@ -25728,32 +25990,32 @@ function GenerateReviewStep({
25728
25990
  const row = breakingRows[breakingCursor];
25729
25991
  const comp = row ? breakingChanges.find((b) => b.componentName === row.componentName) : void 0;
25730
25992
  if (!comp) return null;
25731
- return /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
25732
- /* @__PURE__ */ jsx48(Text47, { bold: true, color: PALETTE.warning, children: `Breaking changes \u2014 ${comp.componentName}` }),
25733
- comp.impact && /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: ` affects ${comp.impact.affectedExperiences} experience${comp.impact.affectedExperiences === 1 ? "" : "s"}, ${comp.impact.affectedFragments} fragment${comp.impact.affectedFragments === 1 ? "" : "s"}` }),
25734
- comp.changes.length === 0 ? /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: " (no enumerated changes)" }) : comp.changes.map((change, ci) => /* @__PURE__ */ jsx48(Text47, { children: ` \u2022 ${formatBreakingChange(change, comp.current)}` }, `bd-detail-${ci}`)),
25735
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "[D/Esc] close detail" })
25993
+ return /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
25994
+ /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.warning, children: `Breaking changes \u2014 ${comp.componentName}` }),
25995
+ comp.impact && /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: ` affects ${comp.impact.affectedExperiences} experience${comp.impact.affectedExperiences === 1 ? "" : "s"}, ${comp.impact.affectedFragments} fragment${comp.impact.affectedFragments === 1 ? "" : "s"}` }),
25996
+ comp.changes.length === 0 ? /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: " (no enumerated changes)" }) : comp.changes.map((change, ci) => /* @__PURE__ */ jsx49(Text48, { children: ` \u2022 ${formatBreakingChange(change, comp.current)}` }, `bd-detail-${ci}`)),
25997
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "[D/Esc] close detail" })
25736
25998
  ] });
25737
25999
  })(),
25738
26000
  cyclePanel.isOpen && !dialogOpen && (() => {
25739
26001
  const PANEL_H = 20;
25740
26002
  const lines = [];
25741
26003
  lines.push(
25742
- /* @__PURE__ */ jsx48(Text47, { bold: true, color: PALETTE.warning, children: `SLOT DEPENDENCY CYCLES (${slotCycles.length})` }, "cyc-title")
26004
+ /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.warning, children: `SLOT DEPENDENCY CYCLES (${slotCycles.length})` }, "cyc-title")
25743
26005
  );
25744
26006
  lines.push(
25745
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "push will fail until these are resolved" }, "cyc-sub")
26007
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "push will fail until these are resolved" }, "cyc-sub")
25746
26008
  );
25747
26009
  lines.push(
25748
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "To fix: reject a cycle member, or break the cycle by removing a slot edge." }, "cyc-guide")
26010
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "To fix: reject a cycle member, or break the cycle by removing a slot edge." }, "cyc-guide")
25749
26011
  );
25750
- lines.push(/* @__PURE__ */ jsx48(Text47, { children: " " }, "cyc-space"));
26012
+ lines.push(/* @__PURE__ */ jsx49(Text48, { children: " " }, "cyc-space"));
25751
26013
  slotCycles.forEach((cycle, idx) => {
25752
26014
  const nodeCount = new Set(cycle.path).size;
25753
26015
  const isCursor = idx === cyclesCursor;
25754
26016
  lines.push(
25755
- /* @__PURE__ */ jsx48(
25756
- Text47,
26017
+ /* @__PURE__ */ jsx49(
26018
+ Text48,
25757
26019
  {
25758
26020
  bold: true,
25759
26021
  inverse: isCursor,
@@ -25764,25 +26026,25 @@ function GenerateReviewStep({
25764
26026
  );
25765
26027
  const segs = formatCyclePathSegments(cycle, 16);
25766
26028
  lines.push(
25767
- /* @__PURE__ */ jsxs47(Text47, { children: [
26029
+ /* @__PURE__ */ jsxs48(Text48, { children: [
25768
26030
  " ",
25769
26031
  segs.map(
25770
- (seg, si) => seg.kind === "slot" ? /* @__PURE__ */ jsx48(Text47, { color: PALETTE.info, children: seg.text }, si) : seg.kind === "arrow" ? /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: seg.text }, si) : /* @__PURE__ */ jsx48(Text47, { children: seg.text }, si)
26032
+ (seg, si) => seg.kind === "slot" ? /* @__PURE__ */ jsx49(Text48, { color: PALETTE.info, children: seg.text }, si) : seg.kind === "arrow" ? /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: seg.text }, si) : /* @__PURE__ */ jsx49(Text48, { children: seg.text }, si)
25771
26033
  )
25772
26034
  ] }, `cyc-p-${idx}`)
25773
26035
  );
25774
26036
  if (cycle.suggestedBreak) {
25775
26037
  const b = cycle.suggestedBreak;
25776
26038
  lines.push(
25777
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: ` Suggested fix: remove '${b.toComponent}' from ${b.fromComponent}.$slots.${b.slotName}.$allowedComponents` }, `cyc-f-${idx}`)
26039
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: ` Suggested fix: remove '${b.toComponent}' from ${b.fromComponent}.$slots.${b.slotName}.$allowedComponents` }, `cyc-f-${idx}`)
25778
26040
  );
25779
26041
  }
25780
- lines.push(/* @__PURE__ */ jsx48(Text47, { children: " " }, `cyc-s-${idx}`));
26042
+ lines.push(/* @__PURE__ */ jsx49(Text48, { children: " " }, `cyc-s-${idx}`));
25781
26043
  });
25782
26044
  const visible = lines.slice(cyclePanelScroll, cyclePanelScroll + PANEL_H);
25783
- return /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
26045
+ return /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
25784
26046
  visible,
25785
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "[\u2191\u2193/j/k] move [Enter] jump [x] break cycle [c/q/Esc] close" })
26047
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "[\u2191\u2193/j/k] move [Enter] jump [x] break cycle [c/q/Esc] close" })
25786
26048
  ] });
25787
26049
  })(),
25788
26050
  !dialogOpen && livePreview && (() => {
@@ -25792,21 +26054,21 @@ function GenerateReviewStep({
25792
26054
  }
25793
26055
  const hasCounts = counts.new + counts.changed + counts.removed + counts.breaking > 0;
25794
26056
  if (livePreviewHook.disabled) {
25795
- return /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "Preview: disabled (creds rejected)" });
26057
+ return /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "Preview: disabled (creds rejected)" });
25796
26058
  }
25797
26059
  if (livePreviewHook.status === "running" && !hasCounts) {
25798
- return /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: `Preview: ${livePreviewSpinner} running...` });
26060
+ return /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: `Preview: ${livePreviewSpinner} running...` });
25799
26061
  }
25800
26062
  if (!hasCounts) return null;
25801
- return /* @__PURE__ */ jsxs47(Box45, { children: [
25802
- /* @__PURE__ */ jsx48(Text47, { children: "Preview: " }),
25803
- /* @__PURE__ */ jsx48(Text47, { color: PALETTE.success, children: `${counts.new} new` }),
25804
- /* @__PURE__ */ jsx48(Text47, { children: " \xB7 " }),
25805
- /* @__PURE__ */ jsx48(Text47, { color: PALETTE.warning, children: `${counts.changed} changed` }),
25806
- /* @__PURE__ */ jsx48(Text47, { children: " \xB7 " }),
25807
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: `${counts.removed} removed` }),
25808
- /* @__PURE__ */ jsx48(Text47, { children: " \xB7 " }),
25809
- /* @__PURE__ */ jsx48(Text47, { color: PALETTE.error, bold: true, children: `${counts.breaking} breaking` })
26063
+ return /* @__PURE__ */ jsxs48(Box46, { children: [
26064
+ /* @__PURE__ */ jsx49(Text48, { children: "Preview: " }),
26065
+ /* @__PURE__ */ jsx49(Text48, { color: PALETTE.success, children: `${counts.new} new` }),
26066
+ /* @__PURE__ */ jsx49(Text48, { children: " \xB7 " }),
26067
+ /* @__PURE__ */ jsx49(Text48, { color: PALETTE.warning, children: `${counts.changed} changed` }),
26068
+ /* @__PURE__ */ jsx49(Text48, { children: " \xB7 " }),
26069
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: `${counts.removed} removed` }),
26070
+ /* @__PURE__ */ jsx49(Text48, { children: " \xB7 " }),
26071
+ /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, bold: true, children: `${counts.breaking} breaking` })
25810
26072
  ] });
25811
26073
  })(),
25812
26074
  !dialogOpen && autoRejected.length > 0 && (() => {
@@ -25818,17 +26080,17 @@ function GenerateReviewStep({
25818
26080
  const participantSet = cycleView.structural;
25819
26081
  const members = stillRejected.filter((n) => participantSet.has(n)).sort();
25820
26082
  const ancestors = stillRejected.filter((n) => !participantSet.has(n)).sort();
25821
- return /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", borderStyle: "single", borderColor: PALETTE.error, paddingX: 1, children: [
25822
- /* @__PURE__ */ jsx48(Text47, { color: PALETTE.error, bold: true, children: `Cyclic manifest \u2014 auto-rejected ${stillRejected.length} component${stillRejected.length === 1 ? "" : "s"}:` }),
25823
- members.length > 0 && /* @__PURE__ */ jsx48(Text47, { color: PALETTE.error, children: ` Cycle members: ${members.join(", ")}` }),
25824
- ancestors.length > 0 && /* @__PURE__ */ jsx48(Text47, { color: PALETTE.error, children: ` Ancestors: ${ancestors.join(", ")}` }),
25825
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: undoSnapshot ? " [Ctrl+Z] undo \xB7 [r]/[a] manually toggle \xB7 [F] continue" : " [r]/[a] manually toggle \xB7 [F] continue" })
26083
+ return /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "single", borderColor: PALETTE.error, paddingX: 1, children: [
26084
+ /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, bold: true, children: `Cyclic manifest \u2014 auto-rejected ${stillRejected.length} component${stillRejected.length === 1 ? "" : "s"}:` }),
26085
+ members.length > 0 && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, children: ` Cycle members: ${members.join(", ")}` }),
26086
+ ancestors.length > 0 && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, children: ` Ancestors: ${ancestors.join(", ")}` }),
26087
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: undoSnapshot ? " [Ctrl+Z] undo \xB7 [r]/[a] manually toggle \xB7 [F] continue" : " [r]/[a] manually toggle \xB7 [F] continue" })
25826
26088
  ] });
25827
26089
  })(),
25828
- !dialogOpen && emptyCount > 0 && /* @__PURE__ */ jsx48(Text47, { color: PALETTE.warning, children: `\u26A0 ${emptyCount} component${emptyCount === 1 ? "" : "s"} had no classifiable props \u2014 review with care` }),
25829
- !dialogOpen && finalizeError && /* @__PURE__ */ jsx48(Text47, { color: PALETTE.error, children: `\u26A0 ${finalizeError}` }),
25830
- !dialogOpen && /* @__PURE__ */ jsxs47(Box45, { children: [
25831
- breakingPanel.isOpen ? /* @__PURE__ */ jsx48(
26090
+ !dialogOpen && emptyCount > 0 && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.warning, children: `\u26A0 ${emptyCount} component${emptyCount === 1 ? "" : "s"} had no classifiable props \u2014 review with care` }),
26091
+ !dialogOpen && finalizeError && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, children: `\u26A0 ${finalizeError}` }),
26092
+ !dialogOpen && /* @__PURE__ */ jsxs48(Box46, { children: [
26093
+ breakingPanel.isOpen ? /* @__PURE__ */ jsx49(
25832
26094
  GotoBanner,
25833
26095
  {
25834
26096
  title: "Breaking changes",
@@ -25841,7 +26103,7 @@ function GenerateReviewStep({
25841
26103
  width: sidebarWidth,
25842
26104
  footerHint: "[\u2191/\u2193] move \xB7 [Enter] jump \xB7 [D] detail \xB7 [Esc] close"
25843
26105
  }
25844
- ) : lineagePanel.isOpen && focusedComponentKey ? /* @__PURE__ */ jsx48(
26106
+ ) : lineagePanel.isOpen && focusedComponentKey ? /* @__PURE__ */ jsx49(
25845
26107
  LineagePanel,
25846
26108
  {
25847
26109
  focusedComponentKey,
@@ -25851,7 +26113,7 @@ function GenerateReviewStep({
25851
26113
  maxRows: panelMaxRows,
25852
26114
  width: sidebarWidth
25853
26115
  }
25854
- ) : /* @__PURE__ */ jsx48(
26116
+ ) : /* @__PURE__ */ jsx49(
25855
26117
  GroupedSidebar,
25856
26118
  {
25857
26119
  items: groupedItems,
@@ -25889,11 +26151,11 @@ function GenerateReviewStep({
25889
26151
  graph: sidebarGraph
25890
26152
  }
25891
26153
  ),
25892
- /* @__PURE__ */ jsx48(Box45, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: selected ? /* @__PURE__ */ jsxs47(Fragment14, { children: [
25893
- /* @__PURE__ */ jsxs47(Box45, { children: [
25894
- /* @__PURE__ */ jsx48(Text47, { bold: true, children: selected.key }),
25895
- /* @__PURE__ */ jsx48(Box45, { flexGrow: 1 }),
25896
- /* @__PURE__ */ jsxs47(Text47, { dimColor: true, children: [
26154
+ /* @__PURE__ */ jsx49(Box46, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: selected ? /* @__PURE__ */ jsxs48(Fragment14, { children: [
26155
+ /* @__PURE__ */ jsxs48(Box46, { children: [
26156
+ /* @__PURE__ */ jsx49(Text48, { bold: true, children: selected.key }),
26157
+ /* @__PURE__ */ jsx49(Box46, { flexGrow: 1 }),
26158
+ /* @__PURE__ */ jsxs48(Text48, { dimColor: true, children: [
25897
26159
  propCount,
25898
26160
  " prop",
25899
26161
  propCount !== 1 ? "s" : "",
@@ -25915,7 +26177,7 @@ function GenerateReviewStep({
25915
26177
  rationale: s.rationale ?? ""
25916
26178
  }))
25917
26179
  ];
25918
- return /* @__PURE__ */ jsx48(
26180
+ return /* @__PURE__ */ jsx49(
25919
26181
  RationalePanel,
25920
26182
  {
25921
26183
  componentName: componentRationale?.name ?? selected.key,
@@ -25926,7 +26188,7 @@ function GenerateReviewStep({
25926
26188
  active: true
25927
26189
  }
25928
26190
  );
25929
- })() : panelOpen === "component-rationale" ? /* @__PURE__ */ jsx48(
26191
+ })() : panelOpen === "component-rationale" ? /* @__PURE__ */ jsx49(
25930
26192
  ComponentRationalePanel,
25931
26193
  {
25932
26194
  data: componentRationale ?? {
@@ -25948,8 +26210,8 @@ function GenerateReviewStep({
25948
26210
  const src = reviewMetadata?.componentSource ?? null;
25949
26211
  const headerPath = path ?? "<unknown source path>";
25950
26212
  const lines = src ? src.split("\n").slice(panelScrollOffset, panelScrollOffset + PANEL_HEIGHT) : [];
25951
- return /* @__PURE__ */ jsxs47(
25952
- Box45,
26213
+ return /* @__PURE__ */ jsxs48(
26214
+ Box46,
25953
26215
  {
25954
26216
  flexDirection: "column",
25955
26217
  width: panelWidth,
@@ -25957,13 +26219,26 @@ function GenerateReviewStep({
25957
26219
  borderColor: "gray",
25958
26220
  paddingX: 1,
25959
26221
  children: [
25960
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, bold: true, children: `source: ${headerPath}` }),
25961
- src ? lines.map((ln, i) => /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: ln }, `source-line-${i}`)) : /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "(no source captured)" }),
25962
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "[s/Esc] close" })
26222
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, bold: true, children: `source: ${headerPath}` }),
26223
+ src ? lines.map((ln, i) => /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: ln }, `source-line-${i}`)) : /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "(no source captured)" }),
26224
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "[s/Esc] close" })
25963
26225
  ]
25964
26226
  }
25965
26227
  );
25966
- })() : showJson ? /* @__PURE__ */ jsx48(
26228
+ })() : panelOpen === "token-review" ? /* @__PURE__ */ jsx49(
26229
+ TokenReviewPanel,
26230
+ {
26231
+ componentName: selected.key,
26232
+ suggestions: currentTokenSuggestions(),
26233
+ selectedRow: tokenReviewRow,
26234
+ editing: tokenReviewEditing,
26235
+ editCursor: tokenReviewEditCursor,
26236
+ editSelection: tokenReviewEditSelection,
26237
+ width: panelWidth,
26238
+ height: PANEL_HEIGHT,
26239
+ active: true
26240
+ }
26241
+ ) : showJson ? /* @__PURE__ */ jsx49(
25967
26242
  JsonPanel,
25968
26243
  {
25969
26244
  label: "GENERATED DEFINITION (read-only)",
@@ -25973,7 +26248,7 @@ function GenerateReviewStep({
25973
26248
  height: PANEL_HEIGHT,
25974
26249
  active: !sidebarFocused
25975
26250
  }
25976
- ) : /* @__PURE__ */ jsx48(
26251
+ ) : /* @__PURE__ */ jsx49(
25977
26252
  FieldEditor,
25978
26253
  {
25979
26254
  value: draftValue || selectedJson,
@@ -26013,39 +26288,43 @@ function GenerateReviewStep({
26013
26288
  },
26014
26289
  pendingEditorFocus && pendingEditorFocus.componentName === selected.key ? `${selected.key}::${pendingEditorFocus.target.kind}:${pendingEditorFocus.target.name}` : selected.key
26015
26290
  ),
26016
- saveError && /* @__PURE__ */ jsx48(Text47, { color: PALETTE.error, children: "\u2717 " + saveError }),
26017
- /* @__PURE__ */ jsxs47(Text47, { dimColor: true, children: [
26018
- sidebarFocused ? hasGroupRoots ? " [Space] expand/collapse group [E/C] expand/collapse all" : "" : showJson ? " [j/k] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list (edit fields)",
26019
- livePreviewHook.status === "running" && /* @__PURE__ */ jsx48(Text47, { children: ` ${livePreviewSpinner} live preview` }),
26020
- livePreviewHook.disabled && /* @__PURE__ */ jsx48(Text47, { children: " \xB7 live preview disabled" })
26291
+ saveError && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, children: "\u2717 " + saveError }),
26292
+ /* @__PURE__ */ jsxs48(Text48, { dimColor: true, children: [
26293
+ panelOpen === "token-review" ? " [\u2191/\u2193] move [Enter] edit allowed [Esc] close" : sidebarFocused ? hasGroupRoots ? " [Space] expand/collapse group [E/C] expand/collapse all" : "" : showJson ? " [j/k] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list (edit fields)" + (currentTokenSuggestions().length > 0 ? " [t] token review" : ""),
26294
+ livePreviewHook.status === "running" && /* @__PURE__ */ jsx49(Text48, { children: ` ${livePreviewSpinner} live preview` }),
26295
+ livePreviewHook.disabled && /* @__PURE__ */ jsx49(Text48, { children: " \xB7 live preview disabled" })
26021
26296
  ] })
26022
- ] }) : /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: "No component selected" }) })
26297
+ ] }) : /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "No component selected" }) })
26023
26298
  ] }),
26024
26299
  breakPanel.isOpen && !breakOverlayFullScreen && !dialogOpen && renderBreakOverlay(),
26025
- !dialogOpen && slotCycles.length > 0 && !cyclePanel.isOpen && !breakPanel.isOpen && /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", children: [
26026
- /* @__PURE__ */ jsx48(Text47, { color: PALETTE.warning, children: `\u26A0 ${slotCycles.length} slot dependency cycle${slotCycles.length === 1 ? "" : "s"} detected \u2014 push will fail` }),
26300
+ !dialogOpen && slotCycles.length > 0 && !cyclePanel.isOpen && !breakPanel.isOpen && /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", children: [
26301
+ /* @__PURE__ */ jsx49(Text48, { color: PALETTE.warning, children: `\u26A0 ${slotCycles.length} slot dependency cycle${slotCycles.length === 1 ? "" : "s"} detected \u2014 push will fail` }),
26027
26302
  slotCycles.slice(0, 3).map((cycle, idx) => {
26028
26303
  const segs = formatCyclePathSegments(cycle);
26029
- return /* @__PURE__ */ jsxs47(Text47, { color: PALETTE.warning, children: [
26304
+ return /* @__PURE__ */ jsxs48(Text48, { color: PALETTE.warning, children: [
26030
26305
  " Cycle: ",
26031
26306
  segs.map(
26032
- (seg, si) => seg.kind === "slot" ? /* @__PURE__ */ jsx48(Text47, { color: PALETTE.info, children: seg.text }, si) : seg.kind === "arrow" ? /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: seg.text }, si) : /* @__PURE__ */ jsx48(Text47, { color: PALETTE.warning, children: seg.text }, si)
26307
+ (seg, si) => seg.kind === "slot" ? /* @__PURE__ */ jsx49(Text48, { color: PALETTE.info, children: seg.text }, si) : seg.kind === "arrow" ? /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: seg.text }, si) : /* @__PURE__ */ jsx49(Text48, { color: PALETTE.warning, children: seg.text }, si)
26033
26308
  )
26034
26309
  ] }, `cyc-banner-${idx}`);
26035
26310
  }),
26036
- slotCycles.length > 3 && /* @__PURE__ */ jsx48(Text47, { color: PALETTE.warning, children: ` \u2026${slotCycles.length - 3} more` }),
26037
- /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: " press [c] for detail" })
26311
+ slotCycles.length > 3 && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.warning, children: ` \u2026${slotCycles.length - 3} more` }),
26312
+ /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: " press [c] for detail" })
26038
26313
  ] }),
26039
- !dialogOpen && searchOpen && /* @__PURE__ */ jsxs47(Box45, { flexDirection: "column", children: [
26040
- /* @__PURE__ */ jsxs47(Text47, { children: [
26314
+ !dialogOpen && searchOpen && /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", children: [
26315
+ /* @__PURE__ */ jsxs48(Text48, { children: [
26041
26316
  `/${searchQuery}`,
26042
- /* @__PURE__ */ jsx48(Text47, { color: PALETTE.info, children: "\u258E" }),
26043
- searchQuery && /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: ` (${searchMatchCount}/${components.length} matches)` })
26317
+ /* @__PURE__ */ jsx49(Text48, { color: PALETTE.info, children: "\u258E" }),
26318
+ searchQuery && /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: ` (${searchMatchCount}/${components.length} matches)` })
26044
26319
  ] }),
26045
- autocompleteCandidates.length > 1 && /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: ` possibilities: ${autocompleteCandidates.join(" \xB7 ").slice(0, 120)}` })
26320
+ autocompleteCandidates.length > 1 && /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: ` possibilities: ${autocompleteCandidates.join(" \xB7 ").slice(0, 120)}` })
26046
26321
  ] }),
26047
- !dialogOpen && !searchOpen && searchQuery && /* @__PURE__ */ jsx48(Box45, { children: /* @__PURE__ */ jsx48(Text47, { dimColor: true, children: `/${searchQuery} (${searchMatchCount}/${components.length} matches) \xB7 [Esc] clear` }) }),
26048
- !dialogOpen && sidebarFocused && /* @__PURE__ */ jsxs47(Box45, { columnGap: 2, flexWrap: "wrap", children: [
26322
+ !dialogOpen && !searchOpen && searchQuery && /* @__PURE__ */ jsx49(Box46, { children: /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: `/${searchQuery} (${searchMatchCount}/${components.length} matches) \xB7 [Esc] clear` }) }),
26323
+ !dialogOpen && sidebarFocused && /* @__PURE__ */ jsx49(Box46, { columnGap: 2, flexWrap: "wrap", children: panelOpen === "token-review" ? /* @__PURE__ */ jsxs48(Fragment14, { children: [
26324
+ legendEntry("[\u2191/\u2193]", "move"),
26325
+ legendEntry("[Enter]", "edit allowed"),
26326
+ legendEntry("[Esc]", "close")
26327
+ ] }) : /* @__PURE__ */ jsxs48(Fragment14, { children: [
26049
26328
  legendEntry("[j/k]", "move"),
26050
26329
  legendEntry("[a]", "accept"),
26051
26330
  legendEntry("[r]", "reject"),
@@ -26060,6 +26339,7 @@ function GenerateReviewStep({
26060
26339
  legendEntry("[p]", "prop rationale", panelOpen === "prop-rationale"),
26061
26340
  legendEntry("[P]", "component rationale", panelOpen === "component-rationale"),
26062
26341
  legendEntry("[s]", "source", panelOpen === "source"),
26342
+ currentTokenSuggestions().length > 0 && legendEntry("[t]", "token review"),
26063
26343
  legendEntry("[J]", showJson ? "hide JSON" : "show JSON", showJson),
26064
26344
  legendEntry("[H]", showHiddenProps ? "hide state/unattached" : "show state/unattached", showHiddenProps),
26065
26345
  breakingChanges.length > 0 && legendEntry("[b]", "see breaking changes", breakingPanel.isOpen),
@@ -26071,8 +26351,8 @@ function GenerateReviewStep({
26071
26351
  legendEntry("[Ctrl+R]", "reload"),
26072
26352
  legendEntry("[?]", "help"),
26073
26353
  legendEntry("[q]", "quit")
26074
- ] }),
26075
- !dialogOpen && /* @__PURE__ */ jsx48(
26354
+ ] }) }),
26355
+ !dialogOpen && /* @__PURE__ */ jsx49(
26076
26356
  StatusBar,
26077
26357
  {
26078
26358
  accepted,
@@ -26105,11 +26385,13 @@ var init_GenerateReviewStep = __esm({
26105
26385
  init_removed_components_text();
26106
26386
  init_QuitDialog();
26107
26387
  init_useImmediateInput();
26388
+ init_manifest();
26108
26389
  init_db();
26109
26390
  init_cycle_detection();
26110
26391
  init_cycle_panel_scroll();
26111
26392
  init_RationalePanel();
26112
26393
  init_ComponentRationalePanel();
26394
+ init_TokenReviewPanel();
26113
26395
  init_preview_annotations();
26114
26396
  init_useLivePreview();
26115
26397
  init_useFinalizePreview();
@@ -26209,8 +26491,8 @@ var init_GenerateReviewStep = __esm({
26209
26491
 
26210
26492
  // packages/experience-design-system-cli/src/import/tui/steps/AtomicGenerateReviewStep.tsx
26211
26493
  import { useEffect as useEffect14, useRef as useRef8, useState as useState27 } from "react";
26212
- import { Box as Box46, Text as Text48, useStdout as useStdout7 } from "ink";
26213
- import { Fragment as Fragment15, jsx as jsx49, jsxs as jsxs48 } from "react/jsx-runtime";
26494
+ import { Box as Box47, Text as Text49, useStdout as useStdout7 } from "ink";
26495
+ import { Fragment as Fragment15, jsx as jsx50, jsxs as jsxs49 } from "react/jsx-runtime";
26214
26496
  function sortComponentsForSidebar3(components) {
26215
26497
  return [...components].sort((a, b) => {
26216
26498
  const aEmpty = Object.keys(a.entry.$properties ?? {}).length === 0;
@@ -26221,6 +26503,7 @@ function sortComponentsForSidebar3(components) {
26221
26503
  }
26222
26504
  function AtomicGenerateReviewStep({
26223
26505
  extractSessionId,
26506
+ tokenSessionId,
26224
26507
  onFinalize,
26225
26508
  onQuit,
26226
26509
  livePreview = true,
@@ -26255,6 +26538,12 @@ function AtomicGenerateReviewStep({
26255
26538
  const [panelScrollOffset, setPanelScrollOffset] = useState27(0);
26256
26539
  const [textEntryActive, setTextEntryActive] = useState27(false);
26257
26540
  const [componentRationale, setComponentRationale] = useState27(null);
26541
+ const [tokenReviewRow, setTokenReviewRow] = useState27(0);
26542
+ const [tokenReviewEditing, setTokenReviewEditing] = useState27(false);
26543
+ const [tokenReviewEditCursor, setTokenReviewEditCursor] = useState27(0);
26544
+ const [tokenReviewEditSelection, setTokenReviewEditSelection] = useState27(/* @__PURE__ */ new Set());
26545
+ const [availableTokens, setAvailableTokens] = useState27([]);
26546
+ const tokenReviewSuggestedRef = useRef8(/* @__PURE__ */ new Map());
26258
26547
  const pendingGRef = useRef8(false);
26259
26548
  const [showReloadDialog, setShowReloadDialog] = useState27(false);
26260
26549
  const historyRef = useRef8(null);
@@ -26290,35 +26579,53 @@ function AtomicGenerateReviewStep({
26290
26579
  const loadEntries = () => {
26291
26580
  const db = openPipelineDb();
26292
26581
  let cdfComponents;
26582
+ let tokens = [];
26293
26583
  try {
26294
26584
  cdfComponents = loadCDFComponents(db, extractSessionId);
26585
+ tokens = loadDTCGTokens(db, tokenSessionId ?? extractSessionId).tokens.map((token) => ({
26586
+ path: token.path,
26587
+ kind: token.$type
26588
+ }));
26295
26589
  } finally {
26296
26590
  db.close();
26297
26591
  }
26298
26592
  if (cdfComponents.length === 0) {
26299
- return { entries: [], error: "No generated definitions found for this session. Try re-running generate." };
26593
+ return {
26594
+ entries: [],
26595
+ tokens: [],
26596
+ error: "No generated definitions found for this session. Try re-running generate."
26597
+ };
26300
26598
  }
26301
26599
  const reviewEntries = cdfComponents.map(({ key, entry }) => ({
26302
26600
  key,
26303
26601
  entry,
26304
26602
  status: "needs-review"
26305
26603
  }));
26306
- return { entries: sortComponentsForSidebar3(reviewEntries), error: null };
26604
+ return { entries: sortComponentsForSidebar3(reviewEntries), tokens, error: null };
26307
26605
  };
26308
26606
  useEffect14(() => {
26309
- try {
26310
- const { entries, error } = loadEntries();
26311
- if (error) {
26312
- setLoadError(error);
26313
- } else {
26607
+ let disposed = false;
26608
+ void (async () => {
26609
+ try {
26610
+ const { entries, tokens, error } = loadEntries();
26611
+ if (error) {
26612
+ if (!disposed) setLoadError(error);
26613
+ return;
26614
+ }
26615
+ const catalog = tokensPath ? (await readTokensFromPath("tokens", tokensPath)).map((token) => ({ path: token.path, kind: token.$type })) : tokens;
26616
+ if (disposed) return;
26314
26617
  setComponents(entries);
26618
+ setAvailableTokens(catalog);
26619
+ } catch (e) {
26620
+ if (!disposed) setLoadError(String(e));
26621
+ } finally {
26622
+ if (!disposed) setLoading(false);
26315
26623
  }
26316
- } catch (e) {
26317
- setLoadError(String(e));
26318
- } finally {
26319
- setLoading(false);
26320
- }
26321
- }, []);
26624
+ })();
26625
+ return () => {
26626
+ disposed = true;
26627
+ };
26628
+ }, [extractSessionId, tokenSessionId, tokensPath]);
26322
26629
  useEffect14(() => {
26323
26630
  if (loading) return;
26324
26631
  if (historySeededRef.current) return;
@@ -26353,12 +26660,13 @@ function AtomicGenerateReviewStep({
26353
26660
  };
26354
26661
  const reloadFromSave = () => {
26355
26662
  try {
26356
- const { entries, error } = loadEntries();
26663
+ const { entries, tokens, error } = loadEntries();
26357
26664
  if (error) {
26358
26665
  setLoadError(error);
26359
26666
  return;
26360
26667
  }
26361
26668
  setComponents(entries);
26669
+ setAvailableTokens(tokens);
26362
26670
  historyRef.current?.reset({
26363
26671
  components: entries.map((c2) => ({ key: c2.key, entry: c2.entry, status: c2.status })),
26364
26672
  autoRejected: [],
@@ -26389,6 +26697,12 @@ function AtomicGenerateReviewStep({
26389
26697
  db.close();
26390
26698
  }
26391
26699
  }, [selectedIdx, components, extractSessionId]);
26700
+ useEffect14(() => {
26701
+ setTokenReviewRow(0);
26702
+ setTokenReviewEditing(false);
26703
+ setTokenReviewEditCursor(0);
26704
+ setTokenReviewEditSelection(/* @__PURE__ */ new Set());
26705
+ }, [selectedIdx]);
26392
26706
  useEffect14(() => {
26393
26707
  const current = components[selectedIdx];
26394
26708
  if (!current) {
@@ -26481,6 +26795,46 @@ function AtomicGenerateReviewStep({
26481
26795
  setDraftValue("");
26482
26796
  setSaveError(null);
26483
26797
  };
26798
+ const currentTokenSuggestions = () => {
26799
+ const current = components[selectedIdx];
26800
+ if (!current) return [];
26801
+ return collectTokenSuggestions(current.entry, availableTokens).map((suggestion) => {
26802
+ const snapshotKey = `${current.key}::${suggestion.propName}`;
26803
+ const suggested = tokenReviewSuggestedRef.current.get(snapshotKey) ?? [...suggestion.suggested];
26804
+ tokenReviewSuggestedRef.current.set(snapshotKey, suggested);
26805
+ return { ...suggestion, suggested };
26806
+ });
26807
+ };
26808
+ const persistTokenFields = (propName, allowed) => {
26809
+ const current = components[selectedIdx];
26810
+ if (!current) return;
26811
+ const prop = current.entry.$properties[propName];
26812
+ if (!prop) return;
26813
+ const nextProp = { ...prop };
26814
+ nextProp["$token.allowed"] = allowed;
26815
+ const nextEntry = {
26816
+ ...current.entry,
26817
+ $properties: { ...current.entry.$properties, [propName]: nextProp }
26818
+ };
26819
+ setComponents((prev) => {
26820
+ const next = prev.map((c2, i) => i === selectedIdx ? { ...c2, entry: nextEntry } : c2);
26821
+ pushHistorySnapshot(next, `token-review:${propName}`);
26822
+ return next;
26823
+ });
26824
+ const db = openPipelineDb();
26825
+ try {
26826
+ storeCDFComponents(db, extractSessionId, [{ key: current.key, entry: nextEntry }]);
26827
+ } finally {
26828
+ db.close();
26829
+ }
26830
+ livePreviewHook.trigger();
26831
+ };
26832
+ const handleTokenEditSave = (s) => {
26833
+ const allowed = s.paths.filter((p) => tokenReviewEditSelection.has(p));
26834
+ if (allowed.length === 0) return;
26835
+ persistTokenFields(s.propName, allowed);
26836
+ setTokenReviewEditing(false);
26837
+ };
26484
26838
  const dialogOpen = showFinalize || showQuit;
26485
26839
  useImmediateInput((input, key) => {
26486
26840
  if (loading) return;
@@ -26534,6 +26888,65 @@ function AtomicGenerateReviewStep({
26534
26888
  setShowRemovedPanel(true);
26535
26889
  return;
26536
26890
  }
26891
+ if (panelOpen === "token-review") {
26892
+ const suggestions = currentTokenSuggestions();
26893
+ const row = suggestions[tokenReviewRow];
26894
+ if (tokenReviewEditing) {
26895
+ if (row && row.paths.length > 0) {
26896
+ if (key.upArrow || input === "k") {
26897
+ setTokenReviewEditCursor((c2) => Math.max(0, c2 - 1));
26898
+ return;
26899
+ }
26900
+ if (key.downArrow || input === "j") {
26901
+ setTokenReviewEditCursor((c2) => Math.min(row.paths.length - 1, c2 + 1));
26902
+ return;
26903
+ }
26904
+ if (input === " " || key.return) {
26905
+ const path = row.paths[tokenReviewEditCursor];
26906
+ setTokenReviewEditSelection((prev) => {
26907
+ const next = new Set(prev);
26908
+ if (next.has(path) && next.size === 1) return next;
26909
+ if (next.has(path)) next.delete(path);
26910
+ else next.add(path);
26911
+ return next;
26912
+ });
26913
+ return;
26914
+ }
26915
+ if (key.ctrl && input === "s") {
26916
+ handleTokenEditSave(row);
26917
+ return;
26918
+ }
26919
+ }
26920
+ if (key.escape) {
26921
+ setTokenReviewEditing(false);
26922
+ return;
26923
+ }
26924
+ return;
26925
+ }
26926
+ if (key.upArrow || input === "k") {
26927
+ setTokenReviewRow((r) => Math.max(0, r - 1));
26928
+ return;
26929
+ }
26930
+ if (key.downArrow || input === "j") {
26931
+ setTokenReviewRow((r) => Math.min(Math.max(0, suggestions.length - 1), r + 1));
26932
+ return;
26933
+ }
26934
+ if (key.return && row) {
26935
+ setTokenReviewEditCursor(0);
26936
+ setTokenReviewEditSelection(new Set(row.allowed));
26937
+ setTokenReviewEditing(true);
26938
+ return;
26939
+ }
26940
+ if (key.escape) {
26941
+ setPanelOpen("none");
26942
+ return;
26943
+ }
26944
+ if (input === "t") {
26945
+ setPanelOpen("none");
26946
+ return;
26947
+ }
26948
+ return;
26949
+ }
26537
26950
  if (panelOpen !== "none") {
26538
26951
  const PANEL_HEIGHT_LOCAL = 12;
26539
26952
  const next = computeNextScrollOffset(panelScrollOffset, input, key, 9999, PANEL_HEIGHT_LOCAL);
@@ -26596,6 +27009,11 @@ function AtomicGenerateReviewStep({
26596
27009
  setPanelScrollOffset(() => 0);
26597
27010
  return;
26598
27011
  }
27012
+ if (input === "t" && currentTokenSuggestions().length > 0) {
27013
+ setPanelOpen("token-review");
27014
+ setTokenReviewRow(0);
27015
+ return;
27016
+ }
26599
27017
  }
26600
27018
  if (key.tab) {
26601
27019
  setSidebarFocused((prev) => !prev);
@@ -26690,13 +27108,13 @@ function AtomicGenerateReviewStep({
26690
27108
  }
26691
27109
  });
26692
27110
  if (loading) {
26693
- return /* @__PURE__ */ jsx49(Box46, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "Loading generated definitions..." }) });
27111
+ return /* @__PURE__ */ jsx50(Box47, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: "Loading generated definitions..." }) });
26694
27112
  }
26695
27113
  if (loadError) {
26696
- return /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
26697
- /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, children: loadError }),
26698
- /* @__PURE__ */ jsx49(Text48, { children: " " }),
26699
- /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "[q / Enter / Esc] Quit" })
27114
+ return /* @__PURE__ */ jsxs49(Box47, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
27115
+ /* @__PURE__ */ jsx50(Text49, { color: PALETTE.error, children: loadError }),
27116
+ /* @__PURE__ */ jsx50(Text49, { children: " " }),
27117
+ /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: "[q / Enter / Esc] Quit" })
26700
27118
  ] });
26701
27119
  }
26702
27120
  const selected = components[selectedIdx] ?? null;
@@ -26722,8 +27140,8 @@ function AtomicGenerateReviewStep({
26722
27140
  const needsReview = components.filter((c2) => c2.status === "needs-review").length;
26723
27141
  const propCount = selected ? Object.keys(selected.entry.$properties).length : 0;
26724
27142
  const slotCount = selected?.entry.$slots ? Object.keys(selected.entry.$slots).length : 0;
26725
- return /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", children: [
26726
- showFinalize && /* @__PURE__ */ jsx49(
27143
+ return /* @__PURE__ */ jsxs49(Box47, { flexDirection: "column", children: [
27144
+ showFinalize && /* @__PURE__ */ jsx50(
26727
27145
  FinalizeDialog,
26728
27146
  {
26729
27147
  accepted,
@@ -26736,21 +27154,21 @@ function AtomicGenerateReviewStep({
26736
27154
  onCancel: () => setShowFinalize(false)
26737
27155
  }
26738
27156
  ),
26739
- showQuit && /* @__PURE__ */ jsx49(QuitDialog, { hasUnsavedDrafts: false, onConfirm: onQuit, onCancel: () => setShowQuit(false) }),
26740
- showReloadDialog && !dialogOpen && /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
26741
- /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.warning, children: "Reload from saved state?" }),
26742
- /* @__PURE__ */ jsx49(Text48, { children: "Unsaved in-memory changes will be lost." }),
26743
- /* @__PURE__ */ jsx49(Text48, { children: " " }),
26744
- /* @__PURE__ */ jsx49(Text48, { children: " [Enter] Confirm" }),
26745
- /* @__PURE__ */ jsx49(Text48, { children: " [Esc] Cancel" })
27157
+ showQuit && /* @__PURE__ */ jsx50(QuitDialog, { hasUnsavedDrafts: false, onConfirm: onQuit, onCancel: () => setShowQuit(false) }),
27158
+ showReloadDialog && !dialogOpen && /* @__PURE__ */ jsxs49(Box47, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.warning, paddingX: 1, children: [
27159
+ /* @__PURE__ */ jsx50(Text49, { bold: true, color: PALETTE.warning, children: "Reload from saved state?" }),
27160
+ /* @__PURE__ */ jsx50(Text49, { children: "Unsaved in-memory changes will be lost." }),
27161
+ /* @__PURE__ */ jsx50(Text49, { children: " " }),
27162
+ /* @__PURE__ */ jsx50(Text49, { children: " [Enter] Confirm" }),
27163
+ /* @__PURE__ */ jsx50(Text49, { children: " [Esc] Cancel" })
26746
27164
  ] }),
26747
- showRemovedPanel && !dialogOpen && /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.info, paddingX: 1, children: [
26748
- /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.info, children: `Removed components (${removedComponents.length})` }),
26749
- /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "these will be DELETED from the target space" }),
26750
- /* @__PURE__ */ jsx49(Text48, { children: " " }),
26751
- removedComponents.map((rc) => /* @__PURE__ */ jsx49(Text48, { children: `- ${rc.name}${rc.id ? ` (${rc.id})` : ""}` }, rc.id)),
26752
- /* @__PURE__ */ jsx49(Text48, { children: " " }),
26753
- /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "press d or Esc to close" })
27165
+ showRemovedPanel && !dialogOpen && /* @__PURE__ */ jsxs49(Box47, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.info, paddingX: 1, children: [
27166
+ /* @__PURE__ */ jsx50(Text49, { bold: true, color: PALETTE.info, children: `Removed components (${removedComponents.length})` }),
27167
+ /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: "these will be DELETED from the target space" }),
27168
+ /* @__PURE__ */ jsx50(Text49, { children: " " }),
27169
+ removedComponents.map((rc) => /* @__PURE__ */ jsx50(Text49, { children: `- ${rc.name}${rc.id ? ` (${rc.id})` : ""}` }, rc.id)),
27170
+ /* @__PURE__ */ jsx50(Text49, { children: " " }),
27171
+ /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: "press d or Esc to close" })
26754
27172
  ] }),
26755
27173
  !dialogOpen && livePreview && (() => {
26756
27174
  const counts = { new: 0, changed: 0, removed: 0, breaking: 0 };
@@ -26759,28 +27177,28 @@ function AtomicGenerateReviewStep({
26759
27177
  }
26760
27178
  const hasCounts = counts.new + counts.changed + counts.removed + counts.breaking > 0;
26761
27179
  if (livePreviewHook.disabled) {
26762
- return /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "Preview: disabled (creds rejected)" });
27180
+ return /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: "Preview: disabled (creds rejected)" });
26763
27181
  }
26764
27182
  if (livePreviewHook.status === "running" && !hasCounts) {
26765
- return /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: `Preview: ${livePreviewSpinner} running...` });
27183
+ return /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: `Preview: ${livePreviewSpinner} running...` });
26766
27184
  }
26767
27185
  if (!hasCounts) return null;
26768
- return /* @__PURE__ */ jsxs48(Box46, { children: [
26769
- /* @__PURE__ */ jsx49(Text48, { children: "Preview: " }),
26770
- /* @__PURE__ */ jsx49(Text48, { color: PALETTE.success, children: `${counts.new} new` }),
26771
- /* @__PURE__ */ jsx49(Text48, { children: " \xB7 " }),
26772
- /* @__PURE__ */ jsx49(Text48, { color: PALETTE.warning, children: `${counts.changed} changed` }),
26773
- /* @__PURE__ */ jsx49(Text48, { children: " \xB7 " }),
26774
- /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: `${counts.removed} removed` }),
26775
- removedComponents.length > 0 && /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: " ([d] removed list)" }),
26776
- /* @__PURE__ */ jsx49(Text48, { children: " \xB7 " }),
26777
- /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, bold: true, children: `${counts.breaking} breaking` })
27186
+ return /* @__PURE__ */ jsxs49(Box47, { children: [
27187
+ /* @__PURE__ */ jsx50(Text49, { children: "Preview: " }),
27188
+ /* @__PURE__ */ jsx50(Text49, { color: PALETTE.success, children: `${counts.new} new` }),
27189
+ /* @__PURE__ */ jsx50(Text49, { children: " \xB7 " }),
27190
+ /* @__PURE__ */ jsx50(Text49, { color: PALETTE.warning, children: `${counts.changed} changed` }),
27191
+ /* @__PURE__ */ jsx50(Text49, { children: " \xB7 " }),
27192
+ /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: `${counts.removed} removed` }),
27193
+ removedComponents.length > 0 && /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: " ([d] removed list)" }),
27194
+ /* @__PURE__ */ jsx50(Text49, { children: " \xB7 " }),
27195
+ /* @__PURE__ */ jsx50(Text49, { color: PALETTE.error, bold: true, children: `${counts.breaking} breaking` })
26778
27196
  ] });
26779
27197
  })(),
26780
- !dialogOpen && emptyCount > 0 && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.warning, children: `\u26A0 ${emptyCount} component${emptyCount === 1 ? "" : "s"} had no classifiable props \u2014 review with care` }),
26781
- !dialogOpen && finalizeError && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, children: `\u26A0 ${finalizeError}` }),
26782
- !dialogOpen && /* @__PURE__ */ jsxs48(Box46, { children: [
26783
- /* @__PURE__ */ jsx49(
27198
+ !dialogOpen && emptyCount > 0 && /* @__PURE__ */ jsx50(Text49, { color: PALETTE.warning, children: `\u26A0 ${emptyCount} component${emptyCount === 1 ? "" : "s"} had no classifiable props \u2014 review with care` }),
27199
+ !dialogOpen && finalizeError && /* @__PURE__ */ jsx50(Text49, { color: PALETTE.error, children: `\u26A0 ${finalizeError}` }),
27200
+ !dialogOpen && /* @__PURE__ */ jsxs49(Box47, { children: [
27201
+ /* @__PURE__ */ jsx50(
26784
27202
  Sidebar,
26785
27203
  {
26786
27204
  components: sidebarItems,
@@ -26799,11 +27217,11 @@ function AtomicGenerateReviewStep({
26799
27217
  width: sidebarWidth
26800
27218
  }
26801
27219
  ),
26802
- /* @__PURE__ */ jsx49(Box46, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: selected ? /* @__PURE__ */ jsxs48(Fragment15, { children: [
26803
- /* @__PURE__ */ jsxs48(Box46, { children: [
26804
- /* @__PURE__ */ jsx49(Text48, { bold: true, children: selected.key }),
26805
- /* @__PURE__ */ jsx49(Box46, { flexGrow: 1 }),
26806
- /* @__PURE__ */ jsxs48(Text48, { dimColor: true, children: [
27220
+ /* @__PURE__ */ jsx50(Box47, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: selected ? /* @__PURE__ */ jsxs49(Fragment15, { children: [
27221
+ /* @__PURE__ */ jsxs49(Box47, { children: [
27222
+ /* @__PURE__ */ jsx50(Text49, { bold: true, children: selected.key }),
27223
+ /* @__PURE__ */ jsx50(Box47, { flexGrow: 1 }),
27224
+ /* @__PURE__ */ jsxs49(Text49, { dimColor: true, children: [
26807
27225
  propCount,
26808
27226
  " prop",
26809
27227
  propCount !== 1 ? "s" : "",
@@ -26825,7 +27243,7 @@ function AtomicGenerateReviewStep({
26825
27243
  rationale: s.rationale ?? ""
26826
27244
  }))
26827
27245
  ];
26828
- return /* @__PURE__ */ jsx49(
27246
+ return /* @__PURE__ */ jsx50(
26829
27247
  RationalePanel,
26830
27248
  {
26831
27249
  componentName: componentRationale?.name ?? selected.key,
@@ -26836,7 +27254,7 @@ function AtomicGenerateReviewStep({
26836
27254
  active: true
26837
27255
  }
26838
27256
  );
26839
- })() : panelOpen === "component-rationale" ? /* @__PURE__ */ jsx49(
27257
+ })() : panelOpen === "component-rationale" ? /* @__PURE__ */ jsx50(
26840
27258
  ComponentRationalePanel,
26841
27259
  {
26842
27260
  data: componentRationale ?? {
@@ -26858,8 +27276,8 @@ function AtomicGenerateReviewStep({
26858
27276
  const src = reviewMetadata?.componentSource ?? null;
26859
27277
  const headerPath = path ?? "<unknown source path>";
26860
27278
  const lines = src ? src.split("\n").slice(panelScrollOffset, panelScrollOffset + PANEL_HEIGHT2) : [];
26861
- return /* @__PURE__ */ jsxs48(
26862
- Box46,
27279
+ return /* @__PURE__ */ jsxs49(
27280
+ Box47,
26863
27281
  {
26864
27282
  flexDirection: "column",
26865
27283
  width: panelWidth,
@@ -26867,13 +27285,26 @@ function AtomicGenerateReviewStep({
26867
27285
  borderColor: PALETTE.border,
26868
27286
  paddingX: 1,
26869
27287
  children: [
26870
- /* @__PURE__ */ jsx49(Text48, { dimColor: true, bold: true, children: `source: ${headerPath}` }),
26871
- src ? lines.map((ln, i) => /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: ln }, `source-line-${i}`)) : /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "(no source captured)" }),
26872
- /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "[s/Esc] close" })
27288
+ /* @__PURE__ */ jsx50(Text49, { dimColor: true, bold: true, children: `source: ${headerPath}` }),
27289
+ src ? lines.map((ln, i) => /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: ln }, `source-line-${i}`)) : /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: "(no source captured)" }),
27290
+ /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: "[s/Esc] close" })
26873
27291
  ]
26874
27292
  }
26875
27293
  );
26876
- })() : showJson ? /* @__PURE__ */ jsx49(
27294
+ })() : panelOpen === "token-review" ? /* @__PURE__ */ jsx50(
27295
+ TokenReviewPanel,
27296
+ {
27297
+ componentName: selected.key,
27298
+ suggestions: currentTokenSuggestions(),
27299
+ selectedRow: tokenReviewRow,
27300
+ editing: tokenReviewEditing,
27301
+ editCursor: tokenReviewEditCursor,
27302
+ editSelection: tokenReviewEditSelection,
27303
+ width: panelWidth,
27304
+ height: PANEL_HEIGHT2,
27305
+ active: true
27306
+ }
27307
+ ) : showJson ? /* @__PURE__ */ jsx50(
26877
27308
  JsonPanel,
26878
27309
  {
26879
27310
  label: "GENERATED DEFINITION (read-only)",
@@ -26883,7 +27314,7 @@ function AtomicGenerateReviewStep({
26883
27314
  height: PANEL_HEIGHT2,
26884
27315
  active: !sidebarFocused
26885
27316
  }
26886
- ) : /* @__PURE__ */ jsx49(
27317
+ ) : /* @__PURE__ */ jsx50(
26887
27318
  FieldEditor,
26888
27319
  {
26889
27320
  value: draftValue || selectedJson,
@@ -26917,15 +27348,15 @@ function AtomicGenerateReviewStep({
26917
27348
  },
26918
27349
  selected.key
26919
27350
  ),
26920
- saveError && /* @__PURE__ */ jsx49(Text48, { color: PALETTE.error, children: "\u2717 " + saveError }),
26921
- /* @__PURE__ */ jsxs48(Text48, { dimColor: true, children: [
26922
- sidebarFocused ? " [a] accept [r] reject [A] accept all [i] prop rationale [I] component rationale [s] source [J] " + (showJson ? "hide JSON" : "show JSON") + " [H] " + (showHiddenProps ? "hide state/unattached" : "show state/unattached") + " [^z] undo [^y] redo [^r] reload [F] finalize [e/Tab] focus panel" + (livePreview && removedComponents.length > 0 ? " [d] removed list" : "") + " [q] quit" : showJson ? " [j/k] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list (edit fields)",
26923
- livePreviewHook.status === "running" && /* @__PURE__ */ jsx49(Text48, { children: ` ${livePreviewSpinner} live preview` }),
26924
- livePreviewHook.disabled && /* @__PURE__ */ jsx49(Text48, { children: " \xB7 live preview disabled" })
27351
+ saveError && /* @__PURE__ */ jsx50(Text49, { color: PALETTE.error, children: "\u2717 " + saveError }),
27352
+ /* @__PURE__ */ jsxs49(Text49, { dimColor: true, children: [
27353
+ panelOpen === "token-review" ? " [\u2191/\u2193] move [Enter] edit allowed [Esc] close" : sidebarFocused ? " [a] accept [r] reject [A] accept all [i] prop rationale [I] component rationale [s] source [J] " + (showJson ? "hide JSON" : "show JSON") + " [H] " + (showHiddenProps ? "hide state/unattached" : "show state/unattached") + (currentTokenSuggestions().length > 0 ? " [t] token review" : "") + " [^z] undo [^y] redo [^r] reload [F] finalize [e/Tab] focus panel" + (livePreview && removedComponents.length > 0 ? " [d] removed list" : "") + " [q] quit" : showJson ? " [j/k] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list (edit fields)" + (currentTokenSuggestions().length > 0 ? " [t] token review" : ""),
27354
+ livePreviewHook.status === "running" && /* @__PURE__ */ jsx50(Text49, { children: ` ${livePreviewSpinner} live preview` }),
27355
+ livePreviewHook.disabled && /* @__PURE__ */ jsx50(Text49, { children: " \xB7 live preview disabled" })
26925
27356
  ] })
26926
- ] }) : /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "No component selected" }) })
27357
+ ] }) : /* @__PURE__ */ jsx50(Text49, { dimColor: true, children: "No component selected" }) })
26927
27358
  ] }),
26928
- !dialogOpen && /* @__PURE__ */ jsx49(
27359
+ !dialogOpen && /* @__PURE__ */ jsx50(
26929
27360
  StatusBar,
26930
27361
  {
26931
27362
  accepted,
@@ -26957,9 +27388,11 @@ var init_AtomicGenerateReviewStep = __esm({
26957
27388
  init_FinalizeDialog();
26958
27389
  init_QuitDialog();
26959
27390
  init_useImmediateInput();
27391
+ init_manifest();
26960
27392
  init_db();
26961
27393
  init_RationalePanel();
26962
27394
  init_ComponentRationalePanel();
27395
+ init_TokenReviewPanel();
26963
27396
  init_preview_annotations();
26964
27397
  init_history();
26965
27398
  init_useLivePreview();
@@ -26973,11 +27406,12 @@ var init_AtomicGenerateReviewStep = __esm({
26973
27406
  });
26974
27407
 
26975
27408
  // packages/experience-design-system-cli/src/import/tui/final-review-host.tsx
26976
- import { Box as Box47, Text as Text49 } from "ink";
27409
+ import { Box as Box48, Text as Text50 } from "ink";
26977
27410
  import React27 from "react";
26978
- import { jsx as jsx50, jsxs as jsxs49 } from "react/jsx-runtime";
27411
+ import { jsx as jsx51, jsxs as jsxs50 } from "react/jsx-runtime";
26979
27412
  function FinalReviewHost({
26980
27413
  extractSessionId,
27414
+ tokenSessionId,
26981
27415
  generatedCount,
26982
27416
  autoAccept,
26983
27417
  compositionMode = "atomic",
@@ -26993,16 +27427,17 @@ function FinalReviewHost({
26993
27427
  allowDeletions
26994
27428
  }) {
26995
27429
  if (!extractSessionId) {
26996
- return /* @__PURE__ */ jsx50(Box47, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx50(Text49, { color: PALETTE.error, children: "Error: no session ID \u2014 cannot load generated definitions." }) });
27430
+ return /* @__PURE__ */ jsx51(Box48, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx51(Text50, { color: PALETTE.error, children: "Error: no session ID \u2014 cannot load generated definitions." }) });
26997
27431
  }
26998
27432
  if (autoAccept) {
26999
- return /* @__PURE__ */ jsx50(FinalReviewAutoAccept, { generatedCount, onFinalize });
27433
+ return /* @__PURE__ */ jsx51(FinalReviewAutoAccept, { generatedCount, onFinalize });
27000
27434
  }
27001
27435
  const StepComponent = compositionMode === "atomic" ? AtomicGenerateReviewStep : GenerateReviewStep;
27002
- return /* @__PURE__ */ jsx50(
27436
+ return /* @__PURE__ */ jsx51(
27003
27437
  StepComponent,
27004
27438
  {
27005
27439
  extractSessionId,
27440
+ tokenSessionId,
27006
27441
  onFinalize,
27007
27442
  onQuit,
27008
27443
  livePreview,
@@ -27023,7 +27458,7 @@ function FinalReviewAutoAccept({
27023
27458
  React27.useEffect(() => {
27024
27459
  onFinalize(generatedCount, 0, 0);
27025
27460
  }, []);
27026
- return /* @__PURE__ */ jsx50(Box47, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsxs49(Text49, { dimColor: true, children: [
27461
+ return /* @__PURE__ */ jsx51(Box48, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsxs50(Text50, { dimColor: true, children: [
27027
27462
  "Auto-accepting ",
27028
27463
  generatedCount,
27029
27464
  " generated components..."
@@ -27128,13 +27563,15 @@ var WizardApp_exports = {};
27128
27563
  __export(WizardApp_exports, {
27129
27564
  WizardApp: () => WizardApp,
27130
27565
  buildGenerateComponentsArgs: () => buildGenerateComponentsArgs,
27566
+ buildMapTokensArgs: () => buildMapTokensArgs,
27131
27567
  buildSelectAgentArgs: () => buildSelectAgentArgs,
27132
27568
  formatAcceptanceSummary: () => formatAcceptanceSummary,
27133
27569
  parseAutoFilterProgressLine: () => parseAutoFilterProgressLine,
27134
- parsePrintTokensCount: () => parsePrintTokensCount
27570
+ parsePrintTokensCount: () => parsePrintTokensCount,
27571
+ shouldRunMapTokens: () => shouldRunMapTokens
27135
27572
  });
27136
27573
  import { useEffect as useEffect15, useRef as useRef9, useState as useState28 } from "react";
27137
- import { Box as Box48, Text as Text50, useStdout as useStdout8 } from "ink";
27574
+ import { Box as Box49, Text as Text51, useStdout as useStdout8 } from "ink";
27138
27575
  import { join as join23, resolve as resolve23 } from "node:path";
27139
27576
  import { appendFileSync as appendFileSync2, writeFileSync } from "node:fs";
27140
27577
  import { access as access9, readFile as readFile24, stat as stat6 } from "node:fs/promises";
@@ -27142,7 +27579,7 @@ import { tmpdir } from "node:os";
27142
27579
  import { execFile as execFile4, spawn as spawn4 } from "node:child_process";
27143
27580
  import { mkdir as mkdir7 } from "node:fs/promises";
27144
27581
  import { buildManifest as buildManifest4 } from "@contentful/experience-design-system-types";
27145
- import { jsx as jsx51, jsxs as jsxs50 } from "react/jsx-runtime";
27582
+ import { jsx as jsx52, jsxs as jsxs51 } from "react/jsx-runtime";
27146
27583
  function buildSelectAgentArgs(opts) {
27147
27584
  const args = ["analyze", "select-agent", "--agent", opts.agent, "--session", opts.sessionId, "--exclude-invalid"];
27148
27585
  if (opts.model) args.push("--model", opts.model);
@@ -27185,6 +27622,16 @@ function buildGenerateComponentsArgs(opts) {
27185
27622
  if (opts.generatePromptPath) args.push("--generate-prompt-path", opts.generatePromptPath);
27186
27623
  return args;
27187
27624
  }
27625
+ function buildMapTokensArgs(opts) {
27626
+ const args = ["map", "tokens", "--session", opts.sessionId, "--agent", opts.agent];
27627
+ if (opts.model) args.push("--model", opts.model);
27628
+ if (opts.noCache) args.push("--no-cache");
27629
+ if (opts.skipAgent) args.push("--skip-agent");
27630
+ return args;
27631
+ }
27632
+ function shouldRunMapTokens(opts) {
27633
+ return opts.mappablePropCount > 0 && opts.rawTokenCount > 0;
27634
+ }
27188
27635
  function formatAcceptanceSummary(opts) {
27189
27636
  const acceptedClause = `${opts.accepted} component${opts.accepted === 1 ? "" : "s"} accepted`;
27190
27637
  if (opts.autoRejected === 0) return `${acceptedClause}.`;
@@ -27233,6 +27680,7 @@ function WizardApp({
27233
27680
  onConflictMode,
27234
27681
  selectPromptPath,
27235
27682
  generatePromptPath,
27683
+ skipMapTokens = false,
27236
27684
  seedExtractSessionId,
27237
27685
  seedGenerateSessionId,
27238
27686
  seedTokenSessionId,
@@ -27318,6 +27766,7 @@ function WizardApp({
27318
27766
  credentialsValidating: false,
27319
27767
  generatePrefetchStatus: "idle",
27320
27768
  generatePrefetchError: null,
27769
+ mapTokensEligible: null,
27321
27770
  credentialsSkipped: false,
27322
27771
  lastRunId: null,
27323
27772
  finalizeErrorBanner: null,
@@ -27463,6 +27912,60 @@ If you are using AWS Bedrock, run:
27463
27912
  }
27464
27913
  update({ step: "path-validation", tokensPath, tokenSessionId, tokenCount });
27465
27914
  };
27915
+ const runMapTokens2 = async (sessionId2) => {
27916
+ let mappablePropCount = 0;
27917
+ let rawTokenCount = 0;
27918
+ try {
27919
+ const db = openPipelineDb();
27920
+ try {
27921
+ if (state.tokenSessionId && state.tokenSessionId !== sessionId2) {
27922
+ copyTokensFromCache(db, state.tokenSessionId, sessionId2);
27923
+ } else if (!state.tokenSessionId && state.tokensPath) {
27924
+ const tokens = await readTokensFromPath("tokens", state.tokensPath);
27925
+ storeDTCGTokens(db, sessionId2, [], tokens);
27926
+ }
27927
+ const cdfEntries = loadCDFComponents(db, sessionId2);
27928
+ mappablePropCount = cdfEntries.reduce(
27929
+ (count, { entry }) => count + Object.values(entry.$properties ?? {}).filter(
27930
+ (prop) => prop.$type === "token" && prop.$category === "design"
27931
+ ).length,
27932
+ 0
27933
+ );
27934
+ rawTokenCount = loadDTCGTokens(db, sessionId2).tokens.length;
27935
+ } finally {
27936
+ db.close();
27937
+ }
27938
+ } catch (error) {
27939
+ update({
27940
+ step: "error",
27941
+ errorStep: "map tokens",
27942
+ errorMessage: error instanceof Error ? error.message : String(error)
27943
+ });
27944
+ return false;
27945
+ }
27946
+ if (!shouldRunMapTokens({ mappablePropCount, rawTokenCount })) {
27947
+ update({ mapTokensEligible: false });
27948
+ return true;
27949
+ }
27950
+ update({ step: "mapping-tokens", mapTokensEligible: true });
27951
+ const args = buildMapTokensArgs({
27952
+ sessionId: sessionId2,
27953
+ agent: state.agent,
27954
+ ...state.agentModel ? { model: state.agentModel } : {},
27955
+ noCache: effectiveNoCache,
27956
+ skipAgent: skipMapTokens
27957
+ });
27958
+ const result = await runCli2(args);
27959
+ if (result.exitCode !== 0) {
27960
+ update({
27961
+ step: "error",
27962
+ errorStep: "map tokens",
27963
+ errorMessage: result.stderr.trim() || "Unknown error"
27964
+ });
27965
+ return false;
27966
+ }
27967
+ return true;
27968
+ };
27466
27969
  const runExtract = async (projectPath) => {
27467
27970
  const outDir = join23(resolve23(projectPath), ".contentful");
27468
27971
  update({ step: "extracting", outDir, extractProgress: null, compositionPhase: null });
@@ -27766,13 +28269,14 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27766
28269
  const generatedCount = countMatch ? Number(countMatch[1]) : acceptedCount;
27767
28270
  const renamedMatch = /^renamed-slots:\s*(\d+)$/m.exec(result.stdout);
27768
28271
  const renamedSlotsCount = renamedMatch ? Number(renamedMatch[1]) : 0;
28272
+ const mappedSessionId = generateSessionId2 ?? extractSessionId;
27769
28273
  update({
27770
- step: "final-review",
27771
- generateSessionId: generateSessionId2,
28274
+ generateSessionId: mappedSessionId,
27772
28275
  generatedCount,
27773
28276
  renamedSlotsCount,
27774
28277
  generateProgress: null
27775
28278
  });
28279
+ if (await runMapTokens2(mappedSessionId)) update({ step: "final-review" });
27776
28280
  };
27777
28281
  const advanceToPushFlow = (generatedAcceptedCount) => {
27778
28282
  update({ generatedAcceptedCount, step: "credentials" });
@@ -27867,7 +28371,10 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27867
28371
  const result = await inflight;
27868
28372
  generatePromiseRef.current = null;
27869
28373
  if (result.exitCode === 0 && result.signal !== "SIGTERM") {
27870
- setState((prev) => ({ ...prev, step: "final-review" }));
28374
+ const sessionMatch = /^session=(.+)$/m.exec(result.stdout);
28375
+ const generatedSessionId = sessionMatch ? sessionMatch[1].trim() : sid;
28376
+ update({ generateSessionId: generatedSessionId });
28377
+ if (await runMapTokens2(generatedSessionId)) update({ step: "final-review" });
27871
28378
  return;
27872
28379
  }
27873
28380
  }
@@ -28386,6 +28893,7 @@ If using a custom --host, make sure the space exists on that host.`
28386
28893
  "generating-tokens",
28387
28894
  "extracting",
28388
28895
  "generating",
28896
+ "mapping-tokens",
28389
28897
  "printing",
28390
28898
  "previewing",
28391
28899
  "push-from-picker",
@@ -28394,11 +28902,11 @@ If using a custom --host, make sure the space exists on that host.`
28394
28902
  const hints = noQuitSteps.includes(state.step) ? [] : [{ key: "q", label: "quit" }];
28395
28903
  const hasTokens = !!state.tokensPath;
28396
28904
  const hasComponents = !state.skipComponents;
28397
- const totalSteps = 3 + (hasTokens ? 1 : 0) + (hasComponents ? 2 : 0);
28905
+ const totalSteps = 3 + (hasTokens ? 1 : 0) + (hasComponents ? 2 : 0) + (state.mapTokensEligible === true ? 1 : 0);
28398
28906
  const stepContent = (() => {
28399
28907
  switch (state.step) {
28400
28908
  case "run-picker":
28401
- return /* @__PURE__ */ jsx51(
28909
+ return /* @__PURE__ */ jsx52(
28402
28910
  RunPicker,
28403
28911
  {
28404
28912
  runs: initialRuns ?? [],
@@ -28413,7 +28921,7 @@ If using a custom --host, make sure the space exists on that host.`
28413
28921
  }
28414
28922
  );
28415
28923
  case "welcome":
28416
- return /* @__PURE__ */ jsx51(
28924
+ return /* @__PURE__ */ jsx52(
28417
28925
  WelcomeStep,
28418
28926
  {
28419
28927
  onContinue: (path) => {
@@ -28425,7 +28933,7 @@ If using a custom --host, make sure the space exists on that host.`
28425
28933
  }
28426
28934
  );
28427
28935
  case "token-input":
28428
- return /* @__PURE__ */ jsx51(
28936
+ return /* @__PURE__ */ jsx52(
28429
28937
  TokenInputStep,
28430
28938
  {
28431
28939
  onConfirm: (rawTokensPath) => {
@@ -28436,7 +28944,7 @@ If using a custom --host, make sure the space exists on that host.`
28436
28944
  }
28437
28945
  );
28438
28946
  case "token-reuse-gate":
28439
- return /* @__PURE__ */ jsx51(
28947
+ return /* @__PURE__ */ jsx52(
28440
28948
  GateStep,
28441
28949
  {
28442
28950
  successMessage: "Existing tokens.json found",
@@ -28458,7 +28966,7 @@ If using a custom --host, make sure the space exists on that host.`
28458
28966
  }
28459
28967
  );
28460
28968
  case "checking-claude-auth":
28461
- return /* @__PURE__ */ jsx51(
28969
+ return /* @__PURE__ */ jsx52(
28462
28970
  RunningStep,
28463
28971
  {
28464
28972
  stepNumber: state.authCheckStepNumber,
@@ -28468,7 +28976,7 @@ If using a custom --host, make sure the space exists on that host.`
28468
28976
  }
28469
28977
  );
28470
28978
  case "generating-tokens":
28471
- return /* @__PURE__ */ jsx51(
28979
+ return /* @__PURE__ */ jsx52(
28472
28980
  RunningStep,
28473
28981
  {
28474
28982
  stepNumber: 1,
@@ -28478,7 +28986,7 @@ If using a custom --host, make sure the space exists on that host.`
28478
28986
  }
28479
28987
  );
28480
28988
  case "path-validation":
28481
- return /* @__PURE__ */ jsx51(
28989
+ return /* @__PURE__ */ jsx52(
28482
28990
  PathValidationStep,
28483
28991
  {
28484
28992
  projectPath: state.projectPath,
@@ -28518,7 +29026,7 @@ If using a custom --host, make sure the space exists on that host.`
28518
29026
  if (phase === "done") return "Composition mapping resolved \u2713";
28519
29027
  return `Composition: ${phase}`;
28520
29028
  })();
28521
- return /* @__PURE__ */ jsx51(
29029
+ return /* @__PURE__ */ jsx52(
28522
29030
  RunningStep,
28523
29031
  {
28524
29032
  stepNumber: hasTokens ? 2 : 1,
@@ -28532,7 +29040,7 @@ If using a custom --host, make sure the space exists on that host.`
28532
29040
  }
28533
29041
  case "scope-gate": {
28534
29042
  if (!state.extractSessionId) {
28535
- return /* @__PURE__ */ jsx51(Box48, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx51(Text50, { color: PALETTE.error, children: "Error: extract session ID missing \u2014 please re-run." }) });
29043
+ return /* @__PURE__ */ jsx52(Box49, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx52(Text51, { color: PALETTE.error, children: "Error: extract session ID missing \u2014 please re-run." }) });
28536
29044
  }
28537
29045
  const sessionId2 = state.extractSessionId;
28538
29046
  const db = openPipelineDb();
@@ -28543,7 +29051,7 @@ If using a custom --host, make sure the space exists on that host.`
28543
29051
  db.close();
28544
29052
  }
28545
29053
  components = mergeAiDecisions(components, state.aiDecisions);
28546
- return /* @__PURE__ */ jsx51(
29054
+ return /* @__PURE__ */ jsx52(
28547
29055
  ScopeGateHost,
28548
29056
  {
28549
29057
  components,
@@ -28593,7 +29101,7 @@ If using a custom --host, make sure the space exists on that host.`
28593
29101
  const p = state.generateProgress;
28594
29102
  const stepNum = hasTokens ? 4 : 3;
28595
29103
  const progressDetail = p ? `[${p.done}/${p.total}] ${p.current} \u2014 this can take 10\u201330 minutes for large libraries` : `Starting up ${state.agent}... (this can take 10\u201330 minutes for large libraries \u2014 grab a coffee)`;
28596
- return /* @__PURE__ */ jsx51(
29104
+ return /* @__PURE__ */ jsx52(
28597
29105
  RunningStep,
28598
29106
  {
28599
29107
  stepNumber: stepNum,
@@ -28604,11 +29112,25 @@ If using a custom --host, make sure the space exists on that host.`
28604
29112
  }
28605
29113
  );
28606
29114
  }
29115
+ case "mapping-tokens": {
29116
+ const stepNum = hasTokens ? 5 : 4;
29117
+ return /* @__PURE__ */ jsx52(
29118
+ RunningStep,
29119
+ {
29120
+ stepNumber: stepNum,
29121
+ totalSteps,
29122
+ title: "Mapping design tokens",
29123
+ description: "Finding the design tokens that are valid for each generated token property.",
29124
+ detail: skipMapTokens ? "Resolving token defaults..." : `Running ${state.agent}...`
29125
+ }
29126
+ );
29127
+ }
28607
29128
  case "final-review": {
28608
- return /* @__PURE__ */ jsx51(
29129
+ return /* @__PURE__ */ jsx52(
28609
29130
  FinalReviewHost,
28610
29131
  {
28611
29132
  extractSessionId: state.extractSessionId,
29133
+ tokenSessionId: state.tokenSessionId,
28612
29134
  generatedCount: state.generatedCount,
28613
29135
  autoAccept: autoAcceptScope,
28614
29136
  compositionMode,
@@ -28752,7 +29274,7 @@ If using a custom --host, make sure the space exists on that host.`
28752
29274
  const files = [tokenDesc, compDesc].filter(Boolean).join(" and ");
28753
29275
  const count = state.generatedAcceptedCount > 0 ? state.generatedAcceptedCount : state.generatedCount;
28754
29276
  const summary = hasComponents ? `${count} component definition${count !== 1 ? "s" : ""} ready${hasTokens ? ", design tokens ready" : ""}.` : hasTokens ? "Design tokens ready." : "Ready to continue.";
28755
- return /* @__PURE__ */ jsx51(
29277
+ return /* @__PURE__ */ jsx52(
28756
29278
  PushDecisionGateStep,
28757
29279
  {
28758
29280
  summary,
@@ -28784,7 +29306,7 @@ If using a custom --host, make sure the space exists on that host.`
28784
29306
  );
28785
29307
  }
28786
29308
  case "credentials":
28787
- return /* @__PURE__ */ jsx51(
29309
+ return /* @__PURE__ */ jsx52(
28788
29310
  CredentialsStep,
28789
29311
  {
28790
29312
  initialSpaceId: state.spaceId,
@@ -28817,7 +29339,7 @@ If using a custom --host, make sure the space exists on that host.`
28817
29339
  );
28818
29340
  case "push-from-picker":
28819
29341
  case "previewing":
28820
- return /* @__PURE__ */ jsx51(
29342
+ return /* @__PURE__ */ jsx52(
28821
29343
  RunningStep,
28822
29344
  {
28823
29345
  stepNumber: totalSteps,
@@ -28830,7 +29352,7 @@ If using a custom --host, make sure the space exists on that host.`
28830
29352
  const editableComponentCount = Object.keys(state.manifest?.componentsManifest ?? {}).filter(
28831
29353
  (k) => k !== "$schema"
28832
29354
  ).length;
28833
- return /* @__PURE__ */ jsx51(
29355
+ return /* @__PURE__ */ jsx52(
28834
29356
  WizardPreviewStep,
28835
29357
  {
28836
29358
  preview: state.serverPreview,
@@ -28860,9 +29382,9 @@ If using a custom --host, make sure the space exists on that host.`
28860
29382
  );
28861
29383
  }
28862
29384
  case "pushing":
28863
- return /* @__PURE__ */ jsx51(PushingStep, { stepNumber: totalSteps, totalSteps, progress: state.pushProgress });
29385
+ return /* @__PURE__ */ jsx52(PushingStep, { stepNumber: totalSteps, totalSteps, progress: state.pushProgress });
28864
29386
  case "path-prompt":
28865
- return /* @__PURE__ */ jsx51(
29387
+ return /* @__PURE__ */ jsx52(
28866
29388
  PathPrompt,
28867
29389
  {
28868
29390
  defaultPath: state.outDir,
@@ -28881,7 +29403,7 @@ If using a custom --host, make sure the space exists on that host.`
28881
29403
  }
28882
29404
  );
28883
29405
  case "save-conflict-gate":
28884
- return /* @__PURE__ */ jsx51(
29406
+ return /* @__PURE__ */ jsx52(
28885
29407
  SaveConflictGate,
28886
29408
  {
28887
29409
  path: state.outDir,
@@ -28899,7 +29421,7 @@ If using a custom --host, make sure the space exists on that host.`
28899
29421
  }
28900
29422
  );
28901
29423
  case "printing":
28902
- return /* @__PURE__ */ jsx51(
29424
+ return /* @__PURE__ */ jsx52(
28903
29425
  RunningStep,
28904
29426
  {
28905
29427
  stepNumber: totalSteps,
@@ -28910,7 +29432,7 @@ If using a custom --host, make sure the space exists on that host.`
28910
29432
  );
28911
29433
  case "print-gate": {
28912
29434
  const teaser = buildRunTeaserLine(state.lastRunId);
28913
- return /* @__PURE__ */ jsx51(
29435
+ return /* @__PURE__ */ jsx52(
28914
29436
  GateStep,
28915
29437
  {
28916
29438
  successMessage: "Files saved",
@@ -28929,7 +29451,7 @@ If using a custom --host, make sure the space exists on that host.`
28929
29451
  case "done": {
28930
29452
  const totalFailed = state.pushResult.componentTypes.failed + state.pushResult.designTokens.failed;
28931
29453
  const teaser = buildRunTeaserLine(state.lastRunId);
28932
- return /* @__PURE__ */ jsx51(
29454
+ return /* @__PURE__ */ jsx52(
28933
29455
  DoneStep,
28934
29456
  {
28935
29457
  componentTypes: state.pushResult.componentTypes,
@@ -28945,7 +29467,7 @@ If using a custom --host, make sure the space exists on that host.`
28945
29467
  );
28946
29468
  }
28947
29469
  case "preview-validation-error": {
28948
- return /* @__PURE__ */ jsx51(
29470
+ return /* @__PURE__ */ jsx52(
28949
29471
  PreviewValidationErrorStep,
28950
29472
  {
28951
29473
  errors: state.previewValidationErrors,
@@ -28961,7 +29483,7 @@ If using a custom --host, make sure the space exists on that host.`
28961
29483
  );
28962
29484
  }
28963
29485
  case "error":
28964
- return /* @__PURE__ */ jsx51(
29486
+ return /* @__PURE__ */ jsx52(
28965
29487
  ErrorStep,
28966
29488
  {
28967
29489
  stepName: state.errorStep,
@@ -28974,9 +29496,9 @@ If using a custom --host, make sure the space exists on that host.`
28974
29496
  return null;
28975
29497
  }
28976
29498
  })();
28977
- return /* @__PURE__ */ jsxs50(Box48, { flexDirection: "column", width: terminalWidth, children: [
28978
- /* @__PURE__ */ jsx51(TopBar, { subcommand: "import", hints }),
28979
- /* @__PURE__ */ jsx51(CustomPromptBanner, { selectPromptPath, generatePromptPath }),
29499
+ return /* @__PURE__ */ jsxs51(Box49, { flexDirection: "column", width: terminalWidth, children: [
29500
+ /* @__PURE__ */ jsx52(TopBar, { subcommand: "import", hints }),
29501
+ /* @__PURE__ */ jsx52(CustomPromptBanner, { selectPromptPath, generatePromptPath }),
28980
29502
  stepContent
28981
29503
  ] });
28982
29504
  }
@@ -29165,7 +29687,7 @@ __export(push_creds_prompt_exports, {
29165
29687
  });
29166
29688
  import React29 from "react";
29167
29689
  async function promptForPushCredentials(opts = {}) {
29168
- const { render: render7, Box: Box49, Text: Text51 } = await import("ink");
29690
+ const { render: render7, Box: Box50, Text: Text52 } = await import("ink");
29169
29691
  const { useState: useState29 } = await import("react");
29170
29692
  const { CredentialsStep: CredentialsStep2 } = await Promise.resolve().then(() => (init_CredentialsStep(), CredentialsStep_exports));
29171
29693
  return new Promise((resolve27, reject) => {
@@ -29181,7 +29703,7 @@ async function promptForPushCredentials(opts = {}) {
29181
29703
  });
29182
29704
  };
29183
29705
  if (done) {
29184
- return React29.createElement(Box49, null, React29.createElement(Text51, null, ""));
29706
+ return React29.createElement(Box50, null, React29.createElement(Text52, null, ""));
29185
29707
  }
29186
29708
  return React29.createElement(CredentialsStep2, {
29187
29709
  summary: opts.summary ?? "Enter Contentful credentials to push this run. Press Enter on each field to advance.",
@@ -33776,6 +34298,7 @@ import { resolve as resolve25, join as join25 } from "node:path";
33776
34298
  // packages/experience-design-system-cli/src/import/orchestrator.ts
33777
34299
  init_db();
33778
34300
  init_command();
34301
+ init_manifest();
33779
34302
  init_api_client();
33780
34303
  init_contentful_urls();
33781
34304
  init_debug_logger();
@@ -33892,7 +34415,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
33892
34415
  await mkdir5(outDir, { recursive: true });
33893
34416
  const steps = [];
33894
34417
  let stepNum = 0;
33895
- const totalSteps = 4 + (opts.print ? 1 : 0);
34418
+ const totalSteps = 5 + (opts.print ? 1 : 0);
33896
34419
  function stepLabel(name) {
33897
34420
  stepNum++;
33898
34421
  return ` Step ${stepNum}/${totalSteps} ${name} `;
@@ -34073,6 +34596,88 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34073
34596
  progressWriter(`${generateLabel}\u2713 components stored locally (${(durationMs / 1e3).toFixed(1)}s)`);
34074
34597
  steps.push({ step: "generate components", status: "complete", durationMs });
34075
34598
  }
34599
+ if (extractSessionId && opts.tokens) {
34600
+ const tokens = await readTokensFromPath("--tokens", opts.tokens);
34601
+ storeDTCGTokens(db, extractSessionId, [], tokens);
34602
+ }
34603
+ const mapTokensLabel = stepLabel("Mapping design tokens");
34604
+ const hasGeneratedComponents = extractSessionId !== null && loadCDFComponents(db, extractSessionId).length > 0;
34605
+ if (!extractSessionId || opts.skipGenerate && !hasGeneratedComponents) {
34606
+ const reason = extractSessionId ? "no generated components" : "no extract session";
34607
+ progressWriter(`${mapTokensLabel}\u2013 skipped (${reason})`);
34608
+ steps.push({
34609
+ step: "map tokens",
34610
+ status: "skipped",
34611
+ reason
34612
+ });
34613
+ } else {
34614
+ const mapTokensArgs = ["map", "tokens", "--session", extractSessionId, "--agent", opts.agent];
34615
+ if (opts.model) mapTokensArgs.push("--model", opts.model);
34616
+ if (opts.noCache) mapTokensArgs.push("--no-cache");
34617
+ if (opts.skipMapTokens) mapTokensArgs.push("--skip-agent");
34618
+ const mapTokensStepId = createStep(db, sessionId2, "map tokens", {
34619
+ extractSession: extractSessionId,
34620
+ skipAgent: String(opts.skipMapTokens === true)
34621
+ });
34622
+ const t0MapTokens = Date.now();
34623
+ const rMapTokens = await runStep(mapTokensArgs, cliPath, sessionId2);
34624
+ const mapTokensDurationMs = Date.now() - t0MapTokens;
34625
+ if (rMapTokens.exitCode !== 0) {
34626
+ if (rMapTokens.stderr) process.stderr.write(rMapTokens.stderr);
34627
+ updateStep(db, mapTokensStepId, "failed", {}, rMapTokens.stderr);
34628
+ progressWriter(`${mapTokensLabel}\u2717 failed (${(mapTokensDurationMs / 1e3).toFixed(1)}s)`);
34629
+ steps.push({
34630
+ step: "map tokens",
34631
+ status: "failed",
34632
+ durationMs: mapTokensDurationMs,
34633
+ error: rMapTokens.stderr
34634
+ });
34635
+ db.close();
34636
+ return { session: sessionId2, project: projectRoot, steps };
34637
+ }
34638
+ if (opts.skipMapTokens) {
34639
+ updateStep(db, mapTokensStepId, "complete", { deterministicOnly: "true" });
34640
+ progressWriter(
34641
+ `${mapTokensLabel}\u2713 defaults resolved (agent skipped) (${(mapTokensDurationMs / 1e3).toFixed(1)}s)`
34642
+ );
34643
+ steps.push({
34644
+ step: "map tokens",
34645
+ status: "complete",
34646
+ durationMs: mapTokensDurationMs,
34647
+ detail: { deterministicOnly: true }
34648
+ });
34649
+ } else if (rMapTokens.stdout.includes("Nothing to map")) {
34650
+ updateStep(db, mapTokensStepId, "complete", { applied: "0" });
34651
+ progressWriter(`${mapTokensLabel}\u2013 skipped (no tokens in session)`);
34652
+ steps.push({
34653
+ step: "map tokens",
34654
+ status: "skipped",
34655
+ reason: "no tokens in session"
34656
+ });
34657
+ } else if (rMapTokens.stdout.includes("cached")) {
34658
+ updateStep(db, mapTokensStepId, "complete", { cached: "true" });
34659
+ progressWriter(`${mapTokensLabel}\u2713 cached (${(mapTokensDurationMs / 1e3).toFixed(1)}s)`);
34660
+ steps.push({
34661
+ step: "map tokens",
34662
+ status: "complete",
34663
+ durationMs: mapTokensDurationMs,
34664
+ detail: { cached: true }
34665
+ });
34666
+ } else {
34667
+ const appliedMatch = /(\d+) mapping\(s\) applied/.exec(rMapTokens.stdout);
34668
+ const applied = appliedMatch ? Number(appliedMatch[1]) : 0;
34669
+ updateStep(db, mapTokensStepId, "complete", { applied: String(applied) });
34670
+ progressWriter(
34671
+ `${mapTokensLabel}\u2713 ${applied} mapping${applied === 1 ? "" : "s"} applied (${(mapTokensDurationMs / 1e3).toFixed(1)}s)`
34672
+ );
34673
+ steps.push({
34674
+ step: "map tokens",
34675
+ status: "complete",
34676
+ durationMs: mapTokensDurationMs,
34677
+ detail: { applied }
34678
+ });
34679
+ }
34680
+ }
34076
34681
  if (extractSessionId && !opts.autoRejectCycles) {
34077
34682
  const acceptedCycles = (() => {
34078
34683
  try {
@@ -34436,6 +35041,7 @@ async function launchModifyWizard(input) {
34436
35041
  };
34437
35042
  if (input.generateSessionId) props.seedGenerateSessionId = input.generateSessionId;
34438
35043
  if (input.tokenSessionId) props.seedTokenSessionId = input.tokenSessionId;
35044
+ if (input.tokensPath) props.seedTokensPath = input.tokensPath;
34439
35045
  if (input.compositionMode) props.compositionMode = input.compositionMode;
34440
35046
  if (input.saveMode === "overwrite") props.outDirOverride = input.savePath;
34441
35047
  if (input.outDirOverride) props.outDirOverride = input.outDirOverride;
@@ -34554,6 +35160,7 @@ async function modifyRun(opts) {
34554
35160
  extractSessionId: run.extractSessionId,
34555
35161
  generateSessionId: run.generateSessionId,
34556
35162
  tokenSessionId: run.tokenSessionId,
35163
+ tokensPath: run.tokensPath,
34557
35164
  projectPath: run.projectPath,
34558
35165
  savePath: run.savePath,
34559
35166
  entryStep: "final-review",
@@ -34735,7 +35342,10 @@ function registerImportCommand(program) {
34735
35342
  "Deselect components matching pattern (repeatable)",
34736
35343
  (v, a) => [...a, v],
34737
35344
  []
34738
- ).option("--skip-analyze", "Skip the analyze step (uses most recent extract session)").option("--skip-generate", "Skip the generate step (uses most recent generate session)").option("--print", "Write components.json to --out after generation").option("--skip-apply", "(deprecated alias for --no-push) Skip pushing to Contentful").option("--no-cache", "Re-run all steps even if output already exists").option("--yes", "Skip interactive confirmation in apply push").option("--verbose", "Show full agent output and all entity progress").option("--exclude-invalid", "Automatically reject components with validation errors (empty names, collisions)").option("--viewports <path>", "JSON file with viewport array (passed to apply push)").option("--host <url>", "Override API base URL (passed to apply push)").option(
35345
+ ).option("--skip-analyze", "Skip the analyze step (uses most recent extract session)").option("--skip-generate", "Skip the generate step (uses most recent generate session)").option("--print", "Write components.json to --out after generation").option("--skip-apply", "(deprecated alias for --no-push) Skip pushing to Contentful").option(
35346
+ "--skip-map-tokens",
35347
+ "Skip agentic token restrictions while still resolving deterministic token-default paths"
35348
+ ).option("--no-cache", "Re-run all steps even if output already exists").option("--yes", "Skip interactive confirmation in apply push").option("--verbose", "Show full agent output and all entity progress").option("--exclude-invalid", "Automatically reject components with validation errors (empty names, collisions)").option("--viewports <path>", "JSON file with viewport array (passed to apply push)").option("--host <url>", "Override API base URL (passed to apply push)").option(
34739
35349
  "--dry-run",
34740
35350
  "(deprecated, will change semantics in a future release) Print generate components prompt without invoking the agent. Use --print-prompt for the same behaviour explicitly, or '--dry-run --no-push' for the upcoming manifest-preview semantics."
34741
35351
  ).option(
@@ -35018,6 +35628,7 @@ function registerImportCommand(program) {
35018
35628
  ...opts.generateMap ? { generateMap: opts.generateMap } : {},
35019
35629
  ...opts.prompt && opts.prompt.length > 0 ? { promptOverrides: opts.prompt } : {},
35020
35630
  noCache: opts.cache === false,
35631
+ skipMapTokens: opts.skipMapTokens ?? false,
35021
35632
  autoFilter: resolveAutoFilter({ autoFilter: opts.autoFilter }, creds.autoFilter),
35022
35633
  livePreview: opts.livePreview !== false,
35023
35634
  noPush: noPushRequested,
@@ -35083,6 +35694,7 @@ function registerImportCommand(program) {
35083
35694
  deselect: opts.deselect.length > 0 ? opts.deselect : void 0,
35084
35695
  skipAnalyze: opts.skipAnalyze ?? false,
35085
35696
  skipGenerate: opts.skipGenerate ?? false,
35697
+ skipMapTokens: opts.skipMapTokens ?? false,
35086
35698
  print: opts.print ?? false,
35087
35699
  skipApply,
35088
35700
  noCache: opts.cache === false,