@bridge-ds/core 0.11.0 → 0.13.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/README.md CHANGED
@@ -275,7 +275,7 @@ parseSuggestionIssue(body, { comments?, author? }): { ok: true; payload; sha; ma
275
275
  suggestionPayloadSha(payload); canonicalJson(value); sha256Hex(text); gitBlobSha(text);
276
276
  suggestionLabels(payload, { state?, labels? }); suggestionIssueTitle(payload); suggestionStatus({ state, stateReason?, linkedPrs?, review?, applied?, outdated? });
277
277
  suggestionPathProblems(payload, config): string[]; unsafePathProblem(path): string | null;
278
- summarizeSuggestionApprovals(comments, { owners, rights?, teams? }, { payloadSha, author? }); suggestionReviewState(tier, approvals);
278
+ summarizeSuggestionApprovals(comments, { owners, rights?, teams?, soloOwnerCanApproveBoth? }, { payloadSha, author? }); suggestionReviewState(tier, approvals);
279
279
  composeSuggestionReviewComment(record); parseSuggestionReviewComment(body); composeSuggestionAppliedComment(record); parseSuggestionAppliedComment(body);
280
280
  // GitHub (Issues read and write only)
281
281
  createSuggestionOnGitHub(gh, payload, opts); listSuggestionsOnGitHub(gh, { state? }); getSuggestionOnGitHub(gh, n, gov, { outdated? });
@@ -283,6 +283,22 @@ reviewSuggestionOnGitHub(gh, n, { event, role?, message?, payloadSha? }, gov); l
283
283
  declineSuggestionOnGitHub(gh, n, reason, by?); syncSuggestionStateLabel(gh, n, labels, status);
284
284
  ```
285
285
 
286
+ ## storybook (storybook.ts)
287
+
288
+ Reads a deployed or built Storybook without the repo: `index.json` (v4 for Storybook 7, v5 for 8 and later), else
289
+ `stories.json` (v3). Entries are grouped by title into components (name = last title segment); test entries stay out
290
+ of `stories`. A 404, an HTML answer from a host that falls back to `index.html`, or a body with no entries moves on to
291
+ the next file. Errors carry a code: `invalid-url`, `not-found`, `not-json`, `private` (sign-in wall, Chromatic login
292
+ answer, 401/403), `empty`, `http`, `network`. Pure, with an injected `fetch`; `@bridge-ds/visual` uses the parser for
293
+ `storybook-static/index.json` and the iframe URL builder for its captures.
294
+
295
+ ```ts
296
+ fetchStorybookIndex(base, { fetch?, signal? }): Promise<{ version; source: 'index.json' | 'stories.json'; entries; components }>;
297
+ parseStorybookIndex(json, source?); groupStorybookComponents(entries): { title; name; group; stories; docs; tags }[];
298
+ normalizeStorybookUrl(pasted): string; // https only (http on localhost), drops ?path=, /index.html, /iframe.html
299
+ storybookIframeUrl(base, id, { viewMode?, globals?, args? }); storybookManagerUrl(base, id, viewMode?); storybookIndexUrls(base);
300
+ ```
301
+
286
302
  ## history (history.ts, history-github.ts, history-demo.ts)
287
303
 
288
304
  What changed in the tokens, when, who changed it and why, and how to undo it safely.
@@ -437,6 +437,11 @@
437
437
  }
438
438
  }
439
439
  },
440
+ "soloOwnerCanApproveBoth": {
441
+ "type": "boolean",
442
+ "description": "For a design system run by one person. When true and the owners resolve to exactly one person who holds both roles, that person's approval counts as the design and the tech approval, so Tier 2 and Tier 3 changes can be approved. The author of a change still never approves it. Default false: one person never covers both approvals alone.",
443
+ "default": false
444
+ },
440
445
  "rights": {
441
446
  "type": "object",
442
447
  "additionalProperties": false,
@@ -1,6 +1,6 @@
1
- import { i as isAuditable, a as auditFile } from "../report-DOnKUw8G.js";
2
- import { A, b, c, C, D, d, F, I, L, e, M, N, f, g, h, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, B, E, G, H, J, K, O, P, Q, R, S, T, U, V, W, X, Y, Z } from "../report-DOnKUw8G.js";
3
- import { p as pieceId, a as proposedTokenPath, t as tokenLabel } from "../prod-branch-BdMPKffE.js";
1
+ import { i as isAuditable, a as auditFile } from "../report-BeWNSjPk.js";
2
+ import { A, b, c, C, D, d, F, I, L, e, M, N, f, g, h, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, B, E, G, H, J, K, O, P, Q, R, S, T, U, V, W, X, Y, Z } from "../report-BeWNSjPk.js";
3
+ import { p as pieceId, a as proposedTokenPath, t as tokenLabel } from "../prod-branch-6ftQWwdu.js";
4
4
  const lines = (text) => text.split(/\r?\n/);
5
5
  function lineBag(text) {
6
6
  const bag = /* @__PURE__ */ new Map();
package/dist/config.d.ts CHANGED
@@ -114,6 +114,11 @@ export interface GovernanceConfig {
114
114
  * and anyone with write access may ship, as before the field existed.
115
115
  */
116
116
  rights?: Rights | undefined;
117
+ /**
118
+ * A design system run by one person: when the owners resolve to exactly one person holding both roles, that
119
+ * person's approval counts for design and tech. Default false: one person never covers both approvals alone.
120
+ */
121
+ soloOwnerCanApproveBoth?: boolean | undefined;
117
122
  }
118
123
  /** `bridge audit` settings: how product code that consumes the design system is measured. */
119
124
  export interface AuditConfig {
package/dist/index.d.ts CHANGED
@@ -63,3 +63,4 @@ export * from './suggestions';
63
63
  export * from './suggestion-review';
64
64
  export * from './suggestions-github';
65
65
  export * from './suggestion-apply';
66
+ export * from './storybook';
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { m as modeDisplayName, b as modesOf$1, i as isMultiMode, T as TIER_NAMES, c as TIER_AXIS, d as collectRefs, f as findReferenceProblems, e as evaluatePairs, g as contrastScope, h as contextLabel, S as SINGLE_MODE, j as isAlias, k as aliasTarget, l as pathId, v as valuesEqual, n as flattenTokens, s as serializeTokenFile, r as removeToken, u as upsertToken, o as threeWayDiff, q as emptyTokenFile, w as parseTokenFile, E as EXT_ID, x as EXT_SCOPES, y as parseColor, z as rgbaToHex, A as formatValue, B as resolve, C as moveToken, D as effectiveScopes, F as sameScopes, G as defaultScopes, H as readTokenAt, I as modeFile, J as defaultFile, K as selectTokenFiles, L as LayeredTokenSet, M as resolveBranchPreviews, N as loadConfig, O as tokensPath, P as toConfigJson, Q as validateLayered, R as parseContrastChecks, U as classifyRisk, V as CONFIG_FILE, W as RISK_LABELS, X as previewLinks, Y as findPreviewComment, Z as previewsSettled, _ as DEFAULT_TOKEN_PATHS, $ as layoutOptions, a0 as buildTokenSet, a1 as readPreviewComment, a2 as linkStatus, a3 as libraryPreviewState, a4 as parsePiecesRecord, a5 as libraryBranchPlan, a6 as NEEDED_BY_LABEL, a7 as withNeededBy, a8 as withLink, a9 as withPiecesRecord, aa as productBranchSentence, ab as mergePiecesRecord, ac as productOfBranch, ad as defaultProduct, ae as slugify } from "./prod-branch-BdMPKffE.js";
2
- import { af, ag, ah, ai, aj, ak, al, am, an, ao, ap, aq, ar, as, at, au, av, aw, ax, ay, az, aA, aB, aC, aD, aE, aF, aG, aH, aI, aJ, aK, aL, aM, aN, aO, aP, aQ, aR, aS, aT, aU, aV, aW, aX, aY, aZ, a_, a$, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz, bA, bB, bC, bD, bE, bF, bG, bH, bI, bJ, bK, bL, p, bM, bN, bO, bP, bQ, bR, bS, bT, bU, bV, bW, a, bX, bY, bZ, b_, b$, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf, cg, t, ch, ci, cj, ck, cl, cm, cn, co } from "./prod-branch-BdMPKffE.js";
3
- import { G as GitHubError, c as collectHistory, p as packageDirCandidates, a as parseChangelog, r as releasesFromTags, m as mergeReleases, b as buildReport, d as applyTokenEdits, e as buildHistoryEntry, f as coerceValue, g as checkLayeredPair, h as formatChangeset, P as PROSE_KEYS, i as markClaudeDraft, j as cleanDraftText, k as docsPrompt, D as DRAFT_LINE_MAX, R as REQUESTS_BRANCH, l as REQUEST_KINDS, s as sanitizeDraftLine, n as parseExplorationBody, E as EXPLORATION_PREFIX, o as explorationSlug, q as explorationStatus, t as explorationTryIt, u as isExplorationPull, v as promotionPlan, w as EXPLORATION_LABEL, x as explorationProblems, y as explorationNote, z as explorationNotePath, A as explorationPrTitle, B as explorationPrBody, C as variantKeyOf, F as overrideComment, O as OVERRIDE_HEADING, H as overrideRefusedComment, I as suggestionStateFromLabels, J as suggestionStatus, K as composeRequestIssue, L as EXPLORATION_NOTES_DIR, M as isExplorationBranch, N as diffLayered, Q as contrastDelta, S as runLayeredContrast, T as layeredImpact, U as classifyLayered, V as composeProposalBody, W as createSuggestionOnGitHub, X as gitBlobSha, Y as SUGGESTION_SCHEMA, Z as branchWithJiraKey, _ as titleWithJiraKey, $ as figmaSpecPath, a0 as formatFigmaSpec, a1 as figmaDraftBrief, a2 as parseFigmaOrigin, a3 as figmaPushStatus, a4 as parseFigmaSpec, a5 as FIGMA_SPEC_DIR, a6 as FROM_FIGMA_LABEL, a7 as withFigmaOrigin, a8 as WAITING_FOR_CLAUDE_LABEL, a9 as DRAFTED_BY_CLAUDE_LABEL, aa as planComponentPush, ab as figmaOriginSection, ac as figmaBranchTitle, ad as figmaSpecSlug, ae as figmaDraftBody, af as REQUEST_LABEL, ag as figmaNodeUrl } from "./suggestion-apply-DxXRGQrO.js";
4
- import { ah as ah2, ai as ai2, aj as aj2, ak as ak2, al as al2, am as am2, an as an2, ao as ao2, ap as ap2, aq as aq2, ar as ar2, as as as2, at as at2, au as au2, av as av2, aw as aw2, ax as ax2, ay as ay2, az as az2, aA as aA2, aB as aB2, aC as aC2, aD as aD2, aE as aE2, aF as aF2, aG as aG2, aH as aH2, aI as aI2, aJ as aJ2, aK as aK2, aL as aL2, aM as aM2, aN as aN2, aO as aO2, aP as aP2, aQ as aQ2, aR as aR2, aS as aS2, aT as aT2, aU as aU2, aV as aV2, aW as aW2, aX as aX2, aY as aY2, aZ as aZ2, a_ as a_2, a$ as a$2, b0 as b02, b1 as b12, b2 as b22, b3 as b32, b4 as b42, b5 as b52, b6 as b62, b7 as b72, b8 as b82, b9 as b92, ba as ba2, bb as bb2, bc as bc2, bd as bd2, be as be2, bf as bf2, bg as bg2, bh as bh2, bi as bi2, bj as bj2, bk as bk2, bl as bl2, bm as bm2, bn as bn2, bo as bo2, bp as bp2, bq as bq2, br as br2, bs as bs2, bt as bt2, bu as bu2, bv as bv2, bw as bw2, bx as bx2, by as by2, bz as bz2, bA as bA2, bB as bB2, bC as bC2, bD as bD2, bE as bE2, bF as bF2, bG as bG2, bH as bH2, bI as bI2, bJ as bJ2, bK as bK2, bL as bL2, bM as bM2, bN as bN2, bO as bO2, bP as bP2, bQ as bQ2, bR as bR2, bS as bS2, bT as bT2, bU as bU2, bV as bV2, bW as bW2, bX as bX2, bY as bY2, bZ as bZ2, b_ as b_2, b$ as b$2, c0 as c02, c1 as c12, c2 as c22, c3 as c32, c4 as c42, c5 as c52, c6 as c62, c7 as c72, c8 as c82, c9 as c92, ca as ca2, cb as cb2, cc as cc2, cd as cd2, ce as ce2, cf as cf2, cg as cg2, ch as ch2, ci as ci2, cj as cj2, ck as ck2, cl as cl2, cm as cm2, cn as cn2, co as co2, cp, cq, cr, cs, ct, cu, cv, cw, cx, cy, cz, cA, cB, cC, cD, cE, cF, cG, cH, cI, cJ, cK, cL, cM, cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ, c_, c$, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df, dg, dh } from "./suggestion-apply-DxXRGQrO.js";
1
+ import { m as modeDisplayName, b as modesOf$1, i as isMultiMode, T as TIER_NAMES, c as TIER_AXIS, d as collectRefs, f as findReferenceProblems, e as evaluatePairs, g as contrastScope, h as contextLabel, S as SINGLE_MODE, j as isAlias, k as aliasTarget, l as pathId, v as valuesEqual, n as flattenTokens, s as serializeTokenFile, r as removeToken, u as upsertToken, o as threeWayDiff, q as emptyTokenFile, w as parseTokenFile, E as EXT_ID, x as EXT_SCOPES, y as parseColor, z as rgbaToHex, A as formatValue, B as resolve, C as moveToken, D as effectiveScopes, F as sameScopes, G as defaultScopes, H as readTokenAt, I as modeFile, J as defaultFile, K as selectTokenFiles, L as LayeredTokenSet, M as resolveBranchPreviews, N as loadConfig, O as tokensPath, P as toConfigJson, Q as validateLayered, R as parseContrastChecks, U as classifyRisk, V as CONFIG_FILE, W as RISK_LABELS, X as previewLinks, Y as findPreviewComment, Z as previewsSettled, _ as DEFAULT_TOKEN_PATHS, $ as layoutOptions, a0 as buildTokenSet, a1 as readPreviewComment, a2 as linkStatus, a3 as libraryPreviewState, a4 as parsePiecesRecord, a5 as libraryBranchPlan, a6 as NEEDED_BY_LABEL, a7 as withNeededBy, a8 as withLink, a9 as withPiecesRecord, aa as productBranchSentence, ab as mergePiecesRecord, ac as productOfBranch, ad as defaultProduct, ae as slugify } from "./prod-branch-6ftQWwdu.js";
2
+ import { af, ag, ah, ai, aj, ak, al, am, an, ao, ap, aq, ar, as, at, au, av, aw, ax, ay, az, aA, aB, aC, aD, aE, aF, aG, aH, aI, aJ, aK, aL, aM, aN, aO, aP, aQ, aR, aS, aT, aU, aV, aW, aX, aY, aZ, a_, a$, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz, bA, bB, bC, bD, bE, bF, bG, bH, bI, bJ, bK, bL, p, bM, bN, bO, bP, bQ, bR, bS, bT, bU, bV, bW, a, bX, bY, bZ, b_, b$, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, t, ck, cl, cm, cn, co, cp, cq, cr } from "./prod-branch-6ftQWwdu.js";
3
+ import { G as GitHubError, c as collectHistory, p as packageDirCandidates, a as parseChangelog, r as releasesFromTags, m as mergeReleases, b as buildReport, d as applyTokenEdits, e as buildHistoryEntry, f as coerceValue, g as checkLayeredPair, h as formatChangeset, P as PROSE_KEYS, i as markClaudeDraft, j as cleanDraftText, k as docsPrompt, D as DRAFT_LINE_MAX, R as REQUESTS_BRANCH, l as REQUEST_KINDS, s as sanitizeDraftLine, n as parseExplorationBody, E as EXPLORATION_PREFIX, o as explorationSlug, q as explorationStatus, t as explorationTryIt, u as isExplorationPull, v as promotionPlan, w as EXPLORATION_LABEL, x as explorationProblems, y as explorationNote, z as explorationNotePath, A as explorationPrTitle, B as explorationPrBody, C as variantKeyOf, F as overrideComment, O as OVERRIDE_HEADING, H as overrideRefusedComment, I as suggestionStateFromLabels, J as suggestionStatus, K as composeRequestIssue, L as EXPLORATION_NOTES_DIR, M as isExplorationBranch, N as diffLayered, Q as contrastDelta, S as runLayeredContrast, T as layeredImpact, U as classifyLayered, V as composeProposalBody, W as createSuggestionOnGitHub, X as gitBlobSha, Y as SUGGESTION_SCHEMA, Z as branchWithJiraKey, _ as titleWithJiraKey, $ as figmaSpecPath, a0 as formatFigmaSpec, a1 as figmaDraftBrief, a2 as parseFigmaOrigin, a3 as figmaPushStatus, a4 as parseFigmaSpec, a5 as FIGMA_SPEC_DIR, a6 as FROM_FIGMA_LABEL, a7 as withFigmaOrigin, a8 as WAITING_FOR_CLAUDE_LABEL, a9 as DRAFTED_BY_CLAUDE_LABEL, aa as planComponentPush, ab as figmaOriginSection, ac as figmaBranchTitle, ad as figmaSpecSlug, ae as figmaDraftBody, af as REQUEST_LABEL, ag as figmaNodeUrl } from "./suggestion-apply-bH6-gZrE.js";
4
+ import { ah as ah2, ai as ai2, aj as aj2, ak as ak2, al as al2, am as am2, an as an2, ao as ao2, ap as ap2, aq as aq2, ar as ar2, as as as2, at as at2, au as au2, av as av2, aw as aw2, ax as ax2, ay as ay2, az as az2, aA as aA2, aB as aB2, aC as aC2, aD as aD2, aE as aE2, aF as aF2, aG as aG2, aH as aH2, aI as aI2, aJ as aJ2, aK as aK2, aL as aL2, aM as aM2, aN as aN2, aO as aO2, aP as aP2, aQ as aQ2, aR as aR2, aS as aS2, aT as aT2, aU as aU2, aV as aV2, aW as aW2, aX as aX2, aY as aY2, aZ as aZ2, a_ as a_2, a$ as a$2, b0 as b02, b1 as b12, b2 as b22, b3 as b32, b4 as b42, b5 as b52, b6 as b62, b7 as b72, b8 as b82, b9 as b92, ba as ba2, bb as bb2, bc as bc2, bd as bd2, be as be2, bf as bf2, bg as bg2, bh as bh2, bi as bi2, bj as bj2, bk as bk2, bl as bl2, bm as bm2, bn as bn2, bo as bo2, bp as bp2, bq as bq2, br as br2, bs as bs2, bt as bt2, bu as bu2, bv as bv2, bw as bw2, bx as bx2, by as by2, bz as bz2, bA as bA2, bB as bB2, bC as bC2, bD as bD2, bE as bE2, bF as bF2, bG as bG2, bH as bH2, bI as bI2, bJ as bJ2, bK as bK2, bL as bL2, bM as bM2, bN as bN2, bO as bO2, bP as bP2, bQ as bQ2, bR as bR2, bS as bS2, bT as bT2, bU as bU2, bV as bV2, bW as bW2, bX as bX2, bY as bY2, bZ as bZ2, b_ as b_2, b$ as b$2, c0 as c02, c1 as c12, c2 as c22, c3 as c32, c4 as c42, c5 as c52, c6 as c62, c7 as c72, c8 as c82, c9 as c92, ca as ca2, cb as cb2, cc as cc2, cd as cd2, ce as ce2, cf as cf2, cg as cg2, ch as ch2, ci as ci2, cj as cj2, ck as ck2, cl as cl2, cm as cm2, cn as cn2, co as co2, cp as cp2, cq as cq2, cr as cr2, cs, ct, cu, cv, cw, cx, cy, cz, cA, cB, cC, cD, cE, cF, cG, cH, cI, cJ, cK, cL, cM, cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ, c_, c$, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df, dg, dh } from "./suggestion-apply-bH6-gZrE.js";
5
5
  const issueKey$1 = (i) => `${i.code}|${i.path ?? ""}|${i.mode ?? ""}|${i.code === "file-problem" ? i.message : ""}`;
6
6
  const modeName = (mode) => mode === SINGLE_MODE ? "all modes" : modeDisplayName(mode);
7
7
  const isPalette = (t2) => t2.tier === "brand" && t2.path.startsWith("palette.");
@@ -52,7 +52,7 @@ function checkValue(set, owner, value, mode, where, issues) {
52
52
  });
53
53
  }
54
54
  }
55
- function validateSet(set, pairs) {
55
+ function validateSet(set, pairs2) {
56
56
  const issues = [];
57
57
  for (const p2 of set.problems) issues.push({ code: "file-problem", severity: "error", message: p2 });
58
58
  for (const t2 of set.tokens.values()) {
@@ -119,7 +119,7 @@ function validateSet(set, pairs) {
119
119
  }
120
120
  );
121
121
  }
122
- const contrast = evaluatePairs(set.byPath, pairs, contrastScope(set));
122
+ const contrast = evaluatePairs(set.byPath, pairs2, contrastScope(set));
123
123
  for (const r of contrast) {
124
124
  const path = `${r.pair.foreground} on ${r.pair.background}`;
125
125
  const mode = `${r.brand ?? ""}.${r.theme}`;
@@ -154,9 +154,9 @@ function shadowedEdits(set, edits) {
154
154
  }
155
155
  return out;
156
156
  }
157
- function validateProposal(proposed, head, pairs, typeChanges = []) {
158
- const after = validateSet(proposed, pairs);
159
- const before = validateSet(head, pairs);
157
+ function validateProposal(proposed, head, pairs2, typeChanges = []) {
158
+ const after = validateSet(proposed, pairs2);
159
+ const before = validateSet(head, pairs2);
160
160
  const existing = new Set(before.issues.map(issueKey$1));
161
161
  const blocking = [];
162
162
  const warnings = [];
@@ -1112,7 +1112,7 @@ const RADIUS_ROLES = ["inset", "control", "container", "overlay"];
1112
1112
  const RESERVED = /* @__PURE__ */ new Set(["default", "base", "all", "none", "new", "blank", "primitives", "semantic", "components", "density"]);
1113
1113
  const BRAND_SLUG_RE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
1114
1114
  const DEFAULT_PRIMARY_CHROMA = 0.14;
1115
- const isObj = (x) => !!x && typeof x === "object" && !Array.isArray(x);
1115
+ const isObj$1 = (x) => !!x && typeof x === "object" && !Array.isArray(x);
1116
1116
  const fileMap = (f) => f instanceof Map ? new Map(f) : new Map(Object.entries(f));
1117
1117
  const brandDisplayName = (slug) => slug.split("-").filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
1118
1118
  function brandLayers(config) {
@@ -1133,27 +1133,27 @@ function setAt(doc, path, node) {
1133
1133
  const keys = path.split(".");
1134
1134
  let cur = doc;
1135
1135
  for (const k of keys.slice(0, -1)) {
1136
- if (!isObj(cur[k])) cur[k] = {};
1136
+ if (!isObj$1(cur[k])) cur[k] = {};
1137
1137
  cur = cur[k];
1138
1138
  }
1139
1139
  const last = keys[keys.length - 1];
1140
- const prev = isObj(cur[last]) ? cur[last] : {};
1140
+ const prev = isObj$1(cur[last]) ? cur[last] : {};
1141
1141
  cur[last] = { ...prev, ...node };
1142
1142
  }
1143
1143
  function getAt(doc, path) {
1144
1144
  let cur = doc;
1145
- for (const k of path.split(".")) cur = isObj(cur) ? cur[k] : void 0;
1146
- return isObj(cur) ? cur : void 0;
1145
+ for (const k of path.split(".")) cur = isObj$1(cur) ? cur[k] : void 0;
1146
+ return isObj$1(cur) ? cur : void 0;
1147
1147
  }
1148
1148
  function typeAt(doc, path) {
1149
1149
  let cur = doc;
1150
1150
  let type;
1151
1151
  for (const k of path.split(".")) {
1152
- if (!isObj(cur)) return type;
1152
+ if (!isObj$1(cur)) return type;
1153
1153
  if (typeof cur.$type === "string") type = cur.$type;
1154
1154
  cur = cur[k];
1155
1155
  }
1156
- return isObj(cur) && typeof cur.$type === "string" ? cur.$type : type;
1156
+ return isObj$1(cur) && typeof cur.$type === "string" ? cur.$type : type;
1157
1157
  }
1158
1158
  function rampFor(input, pinStep, kind) {
1159
1159
  if (typeof input === "number" || typeof input === "string" && /^\d+(\.\d+)?$/.test(input.trim())) {
@@ -1210,7 +1210,7 @@ function listBrands(source) {
1210
1210
  doc = JSON.parse(files.get(file) ?? "{}");
1211
1211
  } catch {
1212
1212
  }
1213
- const meta = isObj(doc.$extensions) && isObj(doc.$extensions["dev.bridge.brand"]) ? doc.$extensions["dev.bridge.brand"] : {};
1213
+ const meta = isObj$1(doc.$extensions) && isObj$1(doc.$extensions["dev.bridge.brand"]) ? doc.$extensions["dev.bridge.brand"] : {};
1214
1214
  const combo = set.normalizeCombo({ brand: slug });
1215
1215
  const primary = set.resolve("color.action.primary.bg", combo);
1216
1216
  const overrides = layers.override ? (config.axes[layers.overrideAxis]?.values ?? []).map((v) => fill(layers.override, { brand: slug, [layers.overrideAxis]: v })).filter((f) => files.has(f)) : [];
@@ -1300,7 +1300,7 @@ function planNewBrand(source, input) {
1300
1300
  for (const [path, defs] of before.view(before.defaultCombo)) {
1301
1301
  const m = /^radius\.([\w-]+)$/.exec(path);
1302
1302
  const v = defs[defs.length - 1].value;
1303
- if (m && isObj(v) && typeof v.value === "number" && v.unit === "px" && !getAt(doc, path)) scale.set(v.value, m[1]);
1303
+ if (m && isObj$1(v) && typeof v.value === "number" && v.unit === "px" && !getAt(doc, path)) scale.set(v.value, m[1]);
1304
1304
  }
1305
1305
  const radius = input.radius ?? (blank ? RADIUS_PRESETS[0].radius : void 0);
1306
1306
  if (radius) {
@@ -1339,9 +1339,9 @@ function planNewBrand(source, input) {
1339
1339
  }
1340
1340
  const palette = getAt(doc, "palette");
1341
1341
  for (const [role, group] of Object.entries(palette ?? {})) {
1342
- if (role.startsWith("$") || !isObj(group)) continue;
1342
+ if (role.startsWith("$") || !isObj$1(group)) continue;
1343
1343
  for (const [step, node] of Object.entries(group)) {
1344
- if (step.startsWith("$") || !isObj(node) || !("$value" in node) || typeof node.$value === "string") continue;
1344
+ if (step.startsWith("$") || !isObj$1(node) || !("$value" in node) || typeof node.$value === "string") continue;
1345
1345
  const ramp = `${slug}-${role}`;
1346
1346
  const entry = prims.get(ramp) ?? { description: `${name} ${role}. Exact values set when the brand was created.`, steps: /* @__PURE__ */ new Map() };
1347
1347
  entry.steps.set(Number(step), node.$value);
@@ -1354,7 +1354,7 @@ function planNewBrand(source, input) {
1354
1354
  if (prims.size && files.has(primFile)) issues.push({ level: "error", code: "slug-file-exists", message: `${tokensPath(config, primFile)} already exists. Pick another name.` });
1355
1355
  for (const r of prims.keys()) if (before.allPaths().some((p2) => p2.startsWith(`color.${r}.`))) issues.push({ level: "error", code: "ramp-exists", message: `A primitive ramp color.${r} already exists. Pick another name.` });
1356
1356
  doc.$description = `${name}: created with Bridge, started from ${blank ? "a blank brand" : brandDisplayName(from)}.`;
1357
- doc.$extensions = { ...isObj(doc.$extensions) ? doc.$extensions : {}, "dev.bridge.brand": { name, from, ...Object.keys(anchors).length ? { anchors } : {} } };
1357
+ doc.$extensions = { ...isObj$1(doc.$extensions) ? doc.$extensions : {}, "dev.bridge.brand": { name, from, ...Object.keys(anchors).length ? { anchors } : {} } };
1358
1358
  const { $description, $extensions, ...rest } = doc;
1359
1359
  const brandFile = fill(layers.brand, { brand: slug });
1360
1360
  const nextFiles = new Map(files);
@@ -1406,10 +1406,10 @@ function planNewBrand(source, input) {
1406
1406
  if (i.modes && !i.modes.some((m) => m.split(",").includes(brandKey)) && !created.includes(i.file ?? "")) continue;
1407
1407
  issues.push({ level: i.level, code: i.code, message: i.message, ...i.path ? { path: i.path } : {}, ...i.file ? { file: tokensPath(config, i.file) } : {} });
1408
1408
  }
1409
- const pairs = parseContrastChecks(source.contrastText);
1409
+ const pairs2 = parseContrastChecks(source.contrastText);
1410
1410
  const inGate = nextConfig.axes.brand?.values.includes(slug);
1411
1411
  const combos = inGate ? after.combos(nextConfig.contrast?.modes).filter((c) => c.brand === slug) : [];
1412
- const results = combos.flatMap((c) => pairs.map((p2) => checkLayeredPair(after, p2, c)));
1412
+ const results = combos.flatMap((c) => pairs2.map((p2) => checkLayeredPair(after, p2, c)));
1413
1413
  const failing = results.filter((r) => !r.pass);
1414
1414
  const themes = [...new Set(combos.map((c) => c.theme).filter((t2) => !!t2))];
1415
1415
  const ramps = {};
@@ -1780,7 +1780,7 @@ function composePendingDrafts(input) {
1780
1780
  return p2;
1781
1781
  }
1782
1782
  const KINDS = new Set(REQUEST_KINDS.map((k) => k.value));
1783
- const str = (x) => typeof x === "string";
1783
+ const str$1 = (x) => typeof x === "string";
1784
1784
  const optStr = (x) => x === void 0 || typeof x === "string";
1785
1785
  function validatePendingDrafts(x) {
1786
1786
  const out = [];
@@ -1788,7 +1788,7 @@ function validatePendingDrafts(x) {
1788
1788
  const p2 = x;
1789
1789
  if (p2.version !== DRAFT_EXCHANGE_VERSION) out.push(`Unsupported draft session version ${String(p2.version)}: update Bridge.`);
1790
1790
  if (!isDraftSessionId(p2.sessionId)) out.push("The session id is missing or invalid.");
1791
- if (!str(p2.createdAt) || Number.isNaN(Date.parse(p2.createdAt))) out.push("createdAt must be an ISO date.");
1791
+ if (!str$1(p2.createdAt) || Number.isNaN(Date.parse(p2.createdAt))) out.push("createdAt must be an ISO date.");
1792
1792
  if (p2.status !== "pending" && p2.status !== "drafted") out.push('status must be "pending" or "drafted".');
1793
1793
  if (p2.source !== "figma" && p2.source !== "studio") out.push('source must be "figma" or "studio".');
1794
1794
  if (!Array.isArray(p2.items) || !p2.items.length) out.push("A draft session needs at least one item.");
@@ -1799,32 +1799,32 @@ function validatePendingDrafts(x) {
1799
1799
  out.push(`${at3} is not an object.`);
1800
1800
  continue;
1801
1801
  }
1802
- if (!str(i.id) || !i.id) out.push(`${at3} has no id.`);
1802
+ if (!str$1(i.id) || !i.id) out.push(`${at3} has no id.`);
1803
1803
  else if (ids.has(i.id)) out.push(`${at3} repeats the id "${i.id}".`);
1804
1804
  else ids.add(i.id);
1805
1805
  if (i.scope !== "request" && i.scope !== "push" && i.scope !== "docs") out.push(`${at3}: scope must be "request", "push" or "docs".`);
1806
1806
  if (i.scope === "docs") {
1807
1807
  const d = i.docs;
1808
- if (!d || typeof d !== "object" || !str(d.slug) || !d.slug || !str(d.prompt) || !d.prompt || !optStr(d.path)) out.push(`${at3}: a docs item needs docs {slug, task, prompt}.`);
1808
+ if (!d || typeof d !== "object" || !str$1(d.slug) || !d.slug || !str$1(d.prompt) || !d.prompt || !optStr(d.path)) out.push(`${at3}: a docs item needs docs {slug, task, prompt}.`);
1809
1809
  else out.push(...validateDocsTask(d.task).map((m) => `${at3}: ${m}`));
1810
1810
  } else if (i.docs !== void 0) out.push(`${at3}: only a docs item has docs.`);
1811
1811
  if (!optStr(i.component)) out.push(`${at3}: component must be text.`);
1812
1812
  if (i.kind !== void 0 && !KINDS.has(i.kind)) out.push(`${at3}: unknown kind "${String(i.kind)}".`);
1813
- if (!Array.isArray(i.changes) || i.changes.some((c) => !c || !str(c.field) || !optStr(c.before) || !optStr(c.after))) out.push(`${at3}: changes must be a list of {field, before, after}.`);
1814
- if (i.variables !== void 0 && (!Array.isArray(i.variables) || i.variables.some((v) => !v || !str(v.path)))) out.push(`${at3}: variables must be a list of {path, before, after}.`);
1813
+ if (!Array.isArray(i.changes) || i.changes.some((c) => !c || !str$1(c.field) || !optStr(c.before) || !optStr(c.after))) out.push(`${at3}: changes must be a list of {field, before, after}.`);
1814
+ if (i.variables !== void 0 && (!Array.isArray(i.variables) || i.variables.some((v) => !v || !str$1(v.path)))) out.push(`${at3}: variables must be a list of {path, before, after}.`);
1815
1815
  if (i.variables !== void 0 && i.scope !== "push") out.push(`${at3}: only a push item has variables.`);
1816
- if (i.images !== void 0 && (!Array.isArray(i.images) || i.images.some((m) => !m || m.label !== "before" && m.label !== "after" || !str(m.url)))) out.push(`${at3}: images must be a list of {label: before or after, url}.`);
1817
- if (!i.draft || !str(i.draft.title) || !str(i.draft.summary)) out.push(`${at3}: draft must hold a title and a summary.`);
1818
- if (i.lines !== void 0 && (!Array.isArray(i.lines) || i.lines.some((l) => !l || !str(l.id) || !l.id || !str(l.line) || !optStr(l.title) || !Array.isArray(l.changes)))) out.push(`${at3}: lines must be a list of {id, changes, line, title}.`);
1816
+ if (i.images !== void 0 && (!Array.isArray(i.images) || i.images.some((m) => !m || m.label !== "before" && m.label !== "after" || !str$1(m.url)))) out.push(`${at3}: images must be a list of {label: before or after, url}.`);
1817
+ if (!i.draft || !str$1(i.draft.title) || !str$1(i.draft.summary)) out.push(`${at3}: draft must hold a title and a summary.`);
1818
+ if (i.lines !== void 0 && (!Array.isArray(i.lines) || i.lines.some((l) => !l || !str$1(l.id) || !l.id || !str$1(l.line) || !optStr(l.title) || !Array.isArray(l.changes)))) out.push(`${at3}: lines must be a list of {id, changes, line, title}.`);
1819
1819
  }
1820
1820
  if (p2.results !== void 0) {
1821
1821
  if (!Array.isArray(p2.results)) out.push("results must be a list.");
1822
1822
  else
1823
1823
  for (const r of p2.results) {
1824
- if (!r || !str(r.id) || !str(r.title) || !str(r.summary)) out.push("Each result needs an id, a title and a summary.");
1824
+ if (!r || !str$1(r.id) || !str$1(r.title) || !str$1(r.summary)) out.push("Each result needs an id, a title and a summary.");
1825
1825
  else if (r.docs !== void 0 && (!r.docs || typeof r.docs !== "object" || Array.isArray(r.docs))) out.push("Result docs must be an object of sections.");
1826
1826
  else if (!optStr(r.replacement)) out.push("A result replacement must be text.");
1827
- else if (r.lines !== void 0 && (!Array.isArray(r.lines) || r.lines.some((l) => !l || !str(l.id) || !str(l.line) || !optStr(l.title)))) out.push("Result lines must be a list of {id, line, title}.");
1827
+ else if (r.lines !== void 0 && (!Array.isArray(r.lines) || r.lines.some((l) => !l || !str$1(l.id) || !str$1(l.line) || !optStr(l.title)))) out.push("Result lines must be a list of {id, line, title}.");
1828
1828
  }
1829
1829
  }
1830
1830
  return out;
@@ -3210,6 +3210,149 @@ async function figmaPushStatusesOnGitHub(gh, numbers) {
3210
3210
  );
3211
3211
  return out;
3212
3212
  }
3213
+ class StorybookIndexError extends Error {
3214
+ constructor(code2, message, status) {
3215
+ super(message);
3216
+ this.code = code2;
3217
+ this.status = status;
3218
+ this.name = "StorybookIndexError";
3219
+ }
3220
+ code;
3221
+ status;
3222
+ }
3223
+ const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
3224
+ const str = (v) => typeof v === "string" && v.trim() ? v : void 0;
3225
+ function entryFrom(key, raw, v3) {
3226
+ if (!isObj(raw)) return null;
3227
+ const id = str(raw.id) ?? key;
3228
+ const title = str(raw.title) ?? str(raw.kind);
3229
+ const name = str(raw.name) ?? str(raw.story);
3230
+ if (!id || !title || !name) return null;
3231
+ const params = isObj(raw.parameters) ? raw.parameters : {};
3232
+ const type = raw.type === "docs" || raw.type === "story" ? raw.type : v3 && params.docsOnly === true ? "docs" : "story";
3233
+ const e = {
3234
+ id,
3235
+ title,
3236
+ name,
3237
+ type,
3238
+ importPath: str(raw.importPath) ?? str(params.fileName) ?? "",
3239
+ tags: Array.isArray(raw.tags) ? raw.tags.filter((t2) => typeof t2 === "string") : []
3240
+ };
3241
+ const subtype = str(raw.subtype);
3242
+ if (subtype) e.subtype = subtype;
3243
+ const exportName2 = str(raw.exportName);
3244
+ if (exportName2) e.exportName = exportName2;
3245
+ const componentPath = str(raw.componentPath);
3246
+ if (componentPath) e.componentPath = componentPath;
3247
+ return e;
3248
+ }
3249
+ function groupStorybookComponents(entries) {
3250
+ const byTitle = /* @__PURE__ */ new Map();
3251
+ for (const e of entries) {
3252
+ let c = byTitle.get(e.title);
3253
+ if (!c) {
3254
+ const parts = e.title.split("/").map((p2) => p2.trim()).filter(Boolean);
3255
+ c = { title: e.title, name: parts[parts.length - 1] ?? e.title, group: parts.slice(0, -1), stories: [], docs: [], tags: [] };
3256
+ byTitle.set(e.title, c);
3257
+ }
3258
+ if (e.type === "docs") c.docs.push(e);
3259
+ else if (e.subtype !== "test") c.stories.push(e);
3260
+ for (const t2 of e.tags) if (!c.tags.includes(t2)) c.tags.push(t2);
3261
+ }
3262
+ const out = [...byTitle.values()].filter((c) => c.stories.length || c.docs.length);
3263
+ for (const c of out) c.tags.sort();
3264
+ return out.sort((a2, b) => a2.title.localeCompare(b.title));
3265
+ }
3266
+ function parseStorybookIndex(json, source) {
3267
+ if (!isObj(json)) throw new StorybookIndexError("not-json", "The Storybook index is not a JSON object.");
3268
+ if (typeof json.loginUrl === "string" && !("entries" in json) && !("stories" in json)) {
3269
+ throw new StorybookIndexError("private", "This Storybook is private: it asks for a sign-in before showing its index.");
3270
+ }
3271
+ const map = isObj(json.entries) ? json.entries : isObj(json.stories) ? json.stories : null;
3272
+ if (!map) throw new StorybookIndexError("empty", "This file has no Storybook entries.");
3273
+ const v3 = !isObj(json.entries);
3274
+ const entries = Object.entries(map).map(([k, raw]) => entryFrom(k, raw, v3)).filter((e) => e !== null);
3275
+ if (!entries.length) throw new StorybookIndexError("empty", "This Storybook index lists no stories or docs.");
3276
+ const version = typeof json.v === "number" ? json.v : v3 ? 3 : 4;
3277
+ return { version, source: source ?? (v3 ? "stories.json" : "index.json"), entries, components: groupStorybookComponents(entries) };
3278
+ }
3279
+ function normalizeStorybookUrl(input) {
3280
+ let u;
3281
+ try {
3282
+ u = new URL(input.trim());
3283
+ } catch {
3284
+ throw new StorybookIndexError("invalid-url", "Enter the full Storybook address, for example https://storybook.example.com");
3285
+ }
3286
+ const local = u.hostname === "localhost" || u.hostname === "127.0.0.1" || u.hostname === "[::1]";
3287
+ if (u.protocol !== "https:" && !(u.protocol === "http:" && local)) {
3288
+ throw new StorybookIndexError("invalid-url", "The Storybook address must start with https://");
3289
+ }
3290
+ if (u.username || u.password) throw new StorybookIndexError("invalid-url", "Remove the user name and password from the address.");
3291
+ const path = u.pathname.replace(/\/(index\.html|iframe\.html|index\.json|stories\.json)$/i, "/").replace(/\/+$/, "");
3292
+ return `${u.protocol}//${u.host}${path}`;
3293
+ }
3294
+ const storybookIndexUrls = (base) => {
3295
+ const b = base.replace(/\/+$/, "");
3296
+ return [
3297
+ { url: `${b}/index.json`, source: "index.json" },
3298
+ { url: `${b}/stories.json`, source: "stories.json" }
3299
+ ];
3300
+ };
3301
+ const pairs = (o) => Object.entries(o).map(([k, v]) => `${encodeURIComponent(k)}:${encodeURIComponent(v)}`).join(";");
3302
+ function storybookIframeUrl(base, id, o = {}) {
3303
+ let url = `${base.replace(/\/+$/, "")}/iframe.html?id=${encodeURIComponent(id)}&viewMode=${o.viewMode ?? "story"}`;
3304
+ if (o.globals && Object.keys(o.globals).length) url += `&globals=${pairs(o.globals)}`;
3305
+ if (o.args && Object.keys(o.args).length) url += `&args=${pairs(o.args)}`;
3306
+ return url;
3307
+ }
3308
+ function storybookManagerUrl(base, id, viewMode = "story") {
3309
+ return `${base.replace(/\/+$/, "")}/?path=/${viewMode}/${encodeURIComponent(id)}`;
3310
+ }
3311
+ async function fetchStorybookIndex(base, o = {}) {
3312
+ const doFetch = o.fetch ?? ((url, init) => fetch(url, init));
3313
+ const rank = { private: 6, http: 5, network: 4, empty: 3, "not-json": 2, "not-found": 1, "invalid-url": 0 };
3314
+ let worst = null;
3315
+ const keep = (e) => {
3316
+ if (!worst || rank[e.code] > rank[worst.code]) worst = e;
3317
+ };
3318
+ for (const { url, source } of storybookIndexUrls(base)) {
3319
+ let res;
3320
+ try {
3321
+ res = await doFetch(url, { headers: { accept: "application/json" }, ...o.signal ? { signal: o.signal } : {} });
3322
+ } catch (err) {
3323
+ if (o.signal?.aborted) throw err;
3324
+ keep(new StorybookIndexError("network", `Could not reach ${url}. The host may be down or may not allow reading from another site.`));
3325
+ continue;
3326
+ }
3327
+ if (res.status === 404 || res.status === 410) {
3328
+ keep(new StorybookIndexError("not-found", `No Storybook index at ${base}: neither index.json nor stories.json was found.`, res.status));
3329
+ continue;
3330
+ }
3331
+ if (res.status === 401 || res.status === 403) {
3332
+ keep(new StorybookIndexError("private", "This Storybook is private: it asks for a sign-in before showing its index.", res.status));
3333
+ continue;
3334
+ }
3335
+ if (!res.ok) {
3336
+ keep(new StorybookIndexError("http", `The Storybook host answered ${res.status} for ${url}.`, res.status));
3337
+ continue;
3338
+ }
3339
+ const text = await res.text();
3340
+ let json;
3341
+ try {
3342
+ json = JSON.parse(text);
3343
+ } catch {
3344
+ keep(new StorybookIndexError("not-json", `${url} is not a Storybook index (the host answered with a web page).`));
3345
+ continue;
3346
+ }
3347
+ try {
3348
+ return parseStorybookIndex(json, source);
3349
+ } catch (err) {
3350
+ if (err instanceof StorybookIndexError) keep(err);
3351
+ else throw err;
3352
+ }
3353
+ }
3354
+ throw worst ?? new StorybookIndexError("not-found", `No Storybook index at ${base}.`);
3355
+ }
3213
3356
  export {
3214
3357
  af as AAA_MIN,
3215
3358
  ag as AA_MIN,
@@ -3326,6 +3469,7 @@ export {
3326
3469
  aI2 as SUGGESTION_STATE_LABELS,
3327
3470
  aJ2 as SUGGESTION_STATUS_LABEL,
3328
3471
  aK2 as SUGGESTION_TOO_LARGE,
3472
+ StorybookIndexError,
3329
3473
  aL2 as SuggestionError,
3330
3474
  TIER_AXIS,
3331
3475
  TIER_NAMES,
@@ -3515,6 +3659,7 @@ export {
3515
3659
  explorationTestBuildOnGitHub,
3516
3660
  explorationTryIt,
3517
3661
  explorationTryItOnGitHub,
3662
+ fetchStorybookIndex,
3518
3663
  fidelityComponentLine,
3519
3664
  fidelityVerdict,
3520
3665
  bb as fieldChanges,
@@ -3560,6 +3705,7 @@ export {
3560
3705
  gitBlobSha,
3561
3706
  gitHubHistoryBackend,
3562
3707
  bl as globToRegExp,
3708
+ groupStorybookComponents,
3563
3709
  bm as groupsPhrase,
3564
3710
  bL2 as hasSuggestionBlock,
3565
3711
  bM2 as hasWriteAccess,
@@ -3647,6 +3793,7 @@ export {
3647
3793
  newDraftSessionId,
3648
3794
  bC as nodesEqual,
3649
3795
  bD as normalizeRights,
3796
+ normalizeStorybookUrl,
3650
3797
  oklch,
3651
3798
  oklchToLinear,
3652
3799
  onlyTokens,
@@ -3683,6 +3830,7 @@ export {
3683
3830
  parsePiecesRecord,
3684
3831
  cd2 as parseRepo,
3685
3832
  ce2 as parseRequestIssue,
3833
+ parseStorybookIndex,
3686
3834
  cf2 as parseStructureChange,
3687
3835
  cg2 as parseSuggestionAppliedComment,
3688
3836
  ch2 as parseSuggestionIssue,
@@ -3705,11 +3853,11 @@ export {
3705
3853
  planReferences,
3706
3854
  cn2 as planRestore,
3707
3855
  co2 as planRevert,
3708
- cp as planSuggestionApply,
3709
- cq as planToJson,
3856
+ cp2 as planSuggestionApply,
3857
+ cq2 as planToJson,
3710
3858
  planTokenMerge,
3711
3859
  planTokenProposal,
3712
- cr as prNumberFromSubject,
3860
+ cr2 as prNumberFromSubject,
3713
3861
  cs as prefillDocs,
3714
3862
  bO as previewComment,
3715
3863
  previewLinks,
@@ -3808,13 +3956,19 @@ export {
3808
3956
  showShare,
3809
3957
  slugify,
3810
3958
  c3 as snapshotUrl,
3959
+ c4 as soloApprover,
3960
+ c5 as soloOwnerOf,
3961
+ c6 as soloOwnerSentence,
3811
3962
  cO as specHash,
3812
3963
  cP as specsUsage,
3813
3964
  stableCommand,
3814
3965
  startExplorationOnGitHub,
3815
3966
  stateSentence,
3816
- c4 as storybookUrl,
3817
- c5 as suggestNearestComment,
3967
+ storybookIframeUrl,
3968
+ storybookIndexUrls,
3969
+ storybookManagerUrl,
3970
+ c7 as storybookUrl,
3971
+ c8 as suggestNearestComment,
3818
3972
  suggestTokenProposalOnGitHub,
3819
3973
  cQ as suggestionAllowedRoots,
3820
3974
  cR as suggestionAppliedComment,
@@ -3834,33 +3988,33 @@ export {
3834
3988
  d1 as summarizeCi,
3835
3989
  summarizeComponent,
3836
3990
  d2 as summarizeSuggestionApprovals,
3837
- c6 as summarizeTokenChange,
3991
+ c9 as summarizeTokenChange,
3838
3992
  switchToPublishedOnGitHub,
3839
3993
  d3 as syncSuggestionStateLabel,
3840
3994
  takeMine,
3841
- c7 as tarballAssetName,
3842
- c8 as tarballUrl,
3843
- c9 as teamKey,
3844
- ca as teamKeyOf,
3845
- cb as teamUnreadableMessage,
3846
- cc as teamsIn,
3995
+ ca as tarballAssetName,
3996
+ cb as tarballUrl,
3997
+ cc as teamKey,
3998
+ cd as teamKeyOf,
3999
+ ce as teamUnreadableMessage,
4000
+ cf as teamsIn,
3847
4001
  threeWayDiff,
3848
4002
  tintedNeutral,
3849
4003
  d4 as titleOf,
3850
4004
  titleWithJiraKey,
3851
- cd as toAlias,
4005
+ cg as toAlias,
3852
4006
  d5 as toChangeSummary,
3853
4007
  toConfigJson,
3854
4008
  toHex,
3855
- ce as toMap,
4009
+ ch as toMap,
3856
4010
  toOklch,
3857
- cf as toPlain,
3858
- cg as tokenBump,
4011
+ ci as toPlain,
4012
+ cj as tokenBump,
3859
4013
  d6 as tokenCssVar,
3860
4014
  tokenFilesOf,
3861
4015
  d7 as tokenHistory,
3862
4016
  t as tokenLabel,
3863
- ch as tokenNode,
4017
+ ck as tokenNode,
3864
4018
  tokenSuggestionPayload,
3865
4019
  tokenUsage,
3866
4020
  tokensPath,
@@ -3868,8 +4022,8 @@ export {
3868
4022
  tryInProductUrl,
3869
4023
  tryTogetherUrl,
3870
4024
  unpicked,
3871
- ci as unreadableShipTeams,
3872
- cj as unreadableTeams,
4025
+ cl as unreadableShipTeams,
4026
+ cm as unreadableTeams,
3873
4027
  d8 as unsafePathProblem,
3874
4028
  updatePendingDrafts,
3875
4029
  upsertToken,
@@ -3883,15 +4037,15 @@ export {
3883
4037
  validatePendingDrafts,
3884
4038
  validateProposal,
3885
4039
  validateSet,
3886
- ck as valueIn,
3887
- cl as valueToCss,
4040
+ cn as valueIn,
4041
+ co as valueToCss,
3888
4042
  valuesEqual,
3889
4043
  variantKeyOf,
3890
4044
  dd as variantName,
3891
4045
  de as versionTimeline,
3892
- cm as visualImpactProblems,
3893
- cn as whoCanShipSentence,
3894
- co as whyItExists,
4046
+ cp as visualImpactProblems,
4047
+ cq as whoCanShipSentence,
4048
+ cr as whyItExists,
3895
4049
  df as withAuthorLine,
3896
4050
  withFigmaOrigin,
3897
4051
  withLink,