@bridge-ds/mcp 0.11.0 → 0.11.2

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.
@@ -559,7 +559,7 @@ function productOfRepo(products, repo, designSystemRepo) {
559
559
  }
560
560
  var KEY = /^[a-z0-9][a-z0-9-]*$/;
561
561
  var REPO = /^[\w.-]+\/[\w.-]+$/;
562
- var FIELDS = ["key", "name", "repo", "path", "preview", "framework", "default"];
562
+ var FIELDS = ["key", "name", "repo", "path", "preview", "production", "framework", "default"];
563
563
  function productProblems(raw) {
564
564
  if (raw === void 0) return [];
565
565
  if (!Array.isArray(raw)) return ['"products" must be a list of { "key", "name" } objects'];
@@ -585,6 +585,7 @@ function productProblems(raw) {
585
585
  if (bad) problems.push(`${at}.path" must be a folder relative to the repository root, without a leading "/" or "..", such as "apps/admin"`);
586
586
  }
587
587
  if (o.preview !== void 0 && (typeof o.preview !== "string" || !/^https?:\/\//.test(o.preview))) problems.push(`${at}.preview" must be an http(s) URL template, such as "https://app-git-{branch}.vercel.app"`);
588
+ if (o.production !== void 0 && (typeof o.production !== "string" || !/^https?:\/\/[^{}\s]+$/.test(o.production))) problems.push(`${at}.production" must be the product's production URL, without placeholders, such as "https://shop.example.com"`);
588
589
  if (o.framework !== void 0 && (typeof o.framework !== "string" || !o.framework.trim())) problems.push(`${at}.framework" must be a name such as "react", "vue" or "other"`);
589
590
  if (o.default !== void 0 && typeof o.default !== "boolean") problems.push(`${at}.default" must be true or false`);
590
591
  if (o.default === true) defaults++;
@@ -89,7 +89,7 @@ import {
89
89
  validateLayered,
90
90
  variantKeyOf,
91
91
  whoCanShipSentence
92
- } from "./chunk-WSNJYGA5.js";
92
+ } from "./chunk-HNGVASTJ.js";
93
93
 
94
94
  // src/lib.ts
95
95
  import { execFileSync } from "node:child_process";
@@ -4018,13 +4018,21 @@ var labelNames = (labels) => labels.map((l) => typeof l === "string" ? l : l.nam
4018
4018
  function isExplorationPull(p) {
4019
4019
  return isExplorationBranch(p.headRef) || labelNames(p.labels).includes(EXPLORATION_LABEL) || Boolean(parseExplorationBody(p.body));
4020
4020
  }
4021
+ function isUnlabeledExploration(p) {
4022
+ if (p.state !== "open" || p.draft !== true) return false;
4023
+ const names4 = labelNames(p.labels ?? []);
4024
+ if (names4.includes(EXPLORATION_LABEL) || names4.includes(EXPLORATION_ARCHIVED_LABEL) || names4.includes(EXPLORATION_READY_LABEL)) return false;
4025
+ const block = parseExplorationBody(p.body);
4026
+ if (block?.doneAt) return false;
4027
+ return isExplorationBranch(p.headRef) || Boolean(block);
4028
+ }
4021
4029
  function isHandedOff(p) {
4022
4030
  return labelNames(p.labels).includes(EXPLORATION_READY_LABEL) || Boolean(parseExplorationBody(p.body)?.doneAt);
4023
4031
  }
4024
4032
  function explorationStatus(p) {
4025
4033
  const merged = Boolean(p.merged || p.merged_at || p.state === "merged");
4026
4034
  if (p.state !== "open" && !merged) return "closed";
4027
- if (p.state === "open" && labelNames(p.labels).includes(EXPLORATION_LABEL)) return "active";
4035
+ if (p.state === "open" && (labelNames(p.labels).includes(EXPLORATION_LABEL) || isUnlabeledExploration(p))) return "active";
4028
4036
  if (!isHandedOff(p)) return "promoted";
4029
4037
  if (merged) return "shipped";
4030
4038
  if (p.draft === false) return "building";
@@ -4038,6 +4046,7 @@ function isHeldExploration(p) {
4038
4046
  if (p.state !== void 0 && p.state !== "open") return false;
4039
4047
  const names4 = labelNames(p.labels ?? []);
4040
4048
  if (names4.includes(EXPLORATION_LABEL) || names4.includes(EXPLORATION_ARCHIVED_LABEL)) return true;
4049
+ if (isUnlabeledExploration({ state: "open", draft: p.draft, labels: p.labels, headRef: p.headRef ?? p.head?.ref, body: p.body })) return true;
4041
4050
  return names4.includes(EXPLORATION_READY_LABEL) && p.draft !== false;
4042
4051
  }
4043
4052
  var explorationTakeCommands = (branch) => ["git fetch origin", `git checkout ${branch}`];
@@ -4570,7 +4579,7 @@ async function startExplorationOnGitHub(gh, e, s) {
4570
4579
  const ctx = { owner: gh.owner, repo: gh.name, packages: s.packages, apps: s.apps, ...s.requests?.length ? { requests: s.requests } : {}, ...s.inProduct ? { inProduct: s.inProduct } : {} };
4571
4580
  const title = full.jira ? `${full.jira.trim().toUpperCase()} ${explorationPrTitle(full)}` : explorationPrTitle(full);
4572
4581
  const pr = await x.createPullRequest({ title, head: branch, base: s.base, body: explorationPrBody(full, ctx), draft: true });
4573
- await x.addLabels(pr.number, [EXPLORATION_LABEL, ...s.labels ?? []]);
4582
+ const labelsMissing = await labelExploration(x, pr.number, s.labels ?? [], s.retryMs);
4574
4583
  await x.updatePullRequest(pr.number, { body: explorationPrBody(full, { ...ctx, pr: pr.number }) }).catch(() => void 0);
4575
4584
  return {
4576
4585
  branch,
@@ -4579,9 +4588,21 @@ async function startExplorationOnGitHub(gh, e, s) {
4579
4588
  url: pr.url,
4580
4589
  commit: commit.sha,
4581
4590
  tryIt: { state: "building" },
4582
- previews: previewLinks(s.apps, { branch, pr: pr.number, sha: commit.sha })
4591
+ previews: previewLinks(s.apps, { branch, pr: pr.number, sha: commit.sha }),
4592
+ ...labelsMissing.length ? { labelsMissing } : {}
4583
4593
  };
4584
4594
  }
4595
+ var wait = (ms) => new Promise((r) => setTimeout(r, ms));
4596
+ async function labelExploration(gh, pr, extra, retryMs = 600) {
4597
+ let labeled = false;
4598
+ for (let i = 0; i < 3 && !labeled; i++) {
4599
+ if (i) await wait(retryMs * i);
4600
+ labeled = await gh.addLabels(pr, [EXPLORATION_LABEL]);
4601
+ }
4602
+ const more = extra.filter((l) => l !== EXPLORATION_LABEL);
4603
+ const moreOk = more.length ? await gh.addLabels(pr, more) : true;
4604
+ return [...labeled ? [] : [EXPLORATION_LABEL], ...moreOk ? [] : more];
4605
+ }
4585
4606
  async function productRepoAccess(gh) {
4586
4607
  try {
4587
4608
  const r = await gh.getRepo();
@@ -9858,6 +9879,7 @@ async function markFigmaChangeDraftedOnGitHub(gh, n) {
9858
9879
  var BUILD_REQUEST_LABEL = "bridge-build";
9859
9880
  var SOURCE_FIGMA_LABEL = "source: figma";
9860
9881
  var BUILD_STALE_DAYS = 7;
9882
+ var BUILD_DECLINED_DAYS = 7;
9861
9883
  var names3 = (labels) => (labels ?? []).map((l) => (typeof l === "string" ? l : l.name ?? "").toLowerCase());
9862
9884
  function isFigmaPush(p) {
9863
9885
  const l = names3(p.labels);
@@ -10069,7 +10091,8 @@ function buildRequestStatus(x, now = Date.now(), nameOf = (l) => l) {
10069
10091
  if (s === "shipped") return { status: s, ...shippedAt ? { at: shippedAt } : {} };
10070
10092
  return { status: s };
10071
10093
  });
10072
- if (status === "not-planned") timeline.push({ status: "not-planned", ...x.issue?.closedAt ? { at: x.issue.closedAt } : {} });
10094
+ const closedOn = x.issue ? x.issue.closedAt : own?.closedAt ?? own?.updatedAt;
10095
+ if (status === "not-planned") timeline.push({ status: "not-planned", ...closedOn ? { at: closedOn } : {} });
10073
10096
  return {
10074
10097
  status,
10075
10098
  label: status === "requested" && stale ? `Requested ${ageDays} days ago` : BUILD_STATUS_LABEL[status],
@@ -10147,9 +10170,10 @@ var BUILD_FILTER_LABEL = {
10147
10170
  "in-progress": "In progress",
10148
10171
  "shipped-this-week": "Shipped this week"
10149
10172
  };
10173
+ var declinedAt = (v) => v.status === "not-planned" ? v.timeline.find((e) => e.status === "not-planned")?.at ?? null : null;
10150
10174
  function matchesBuildFilter(v, f, now = Date.now()) {
10151
10175
  const nowMs = typeof now === "number" ? now : now.getTime();
10152
- const recent = (iso) => Boolean(iso) && nowMs - Date.parse(iso) <= 7 * DAY;
10176
+ const recent = (iso, days = 7) => Boolean(iso) && nowMs - Date.parse(iso) <= days * DAY;
10153
10177
  switch (f) {
10154
10178
  case "waiting":
10155
10179
  return v.status === "requested";
@@ -10158,7 +10182,7 @@ function matchesBuildFilter(v, f, now = Date.now()) {
10158
10182
  case "shipped-this-week":
10159
10183
  return v.status === "shipped" && recent(v.shippedAt);
10160
10184
  default:
10161
- return v.status === "not-planned" ? recent(v.timeline.find((e) => e.status === "not-planned")?.at) : true;
10185
+ return v.status === "not-planned" ? recent(declinedAt(v), BUILD_DECLINED_DAYS) : true;
10162
10186
  }
10163
10187
  }
10164
10188
  var openBuildRequests = (views) => views.filter((v) => v.status !== "shipped" && v.status !== "not-planned");
@@ -15731,7 +15755,7 @@ async function visualImpact(ctx, a, run2) {
15731
15755
  if (ctx.mode !== "local" || !ctx.root) throw new Error("Visual impact needs a local checkout (start Bridge with --root): it builds Storybook and the app at both refs.");
15732
15756
  if (!ctx.isGit) throw new Error(`${ctx.root} is not a git repository.`);
15733
15757
  const out = a.out ? resolve3(ctx.root, a.out) : join5(ctx.root, "visual-impact");
15734
- const runImpact = run2 ?? (await import("./src-P6G5JWLN.js")).runImpact;
15758
+ const runImpact = run2 ?? (await import("./src-P42KWNHQ.js")).runImpact;
15735
15759
  const r = await runImpact({
15736
15760
  root: ctx.root,
15737
15761
  base: a.base ?? "main",
@@ -17130,7 +17154,7 @@ async function proposeFigmaFixesOp(ctx, a) {
17130
17154
  }
17131
17155
 
17132
17156
  // src/server.ts
17133
- var VERSION = true ? "0.11.0" : "dev";
17157
+ var VERSION = true ? "0.11.2" : "dev";
17134
17158
  var BRIDGE_SITE = "https://bridge.floriangouloubi.com";
17135
17159
  var SERVER_INFO = {
17136
17160
  name: "bridge",
package/dist/index.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  VERSION,
4
4
  optionsFromArgv,
5
5
  serveStdio
6
- } from "./chunk-LI4FNPYK.js";
7
- import "./chunk-WSNJYGA5.js";
6
+ } from "./chunk-P2UU6IKZ.js";
7
+ import "./chunk-HNGVASTJ.js";
8
8
 
9
9
  // src/index.ts
10
10
  var argv = process.argv.slice(2);
package/dist/lib.js CHANGED
@@ -42,12 +42,12 @@ import {
42
42
  studio_exports,
43
43
  suggestions_exports,
44
44
  tokenNote
45
- } from "./chunk-LI4FNPYK.js";
45
+ } from "./chunk-P2UU6IKZ.js";
46
46
  import {
47
47
  CONFIG_FILE,
48
48
  loadConfig,
49
49
  toConfigJson
50
- } from "./chunk-WSNJYGA5.js";
50
+ } from "./chunk-HNGVASTJ.js";
51
51
  export {
52
52
  BlockedError,
53
53
  BridgeContext,
@@ -11,7 +11,7 @@ import {
11
11
  referenceImagePath,
12
12
  selectTokenFiles,
13
13
  showFile
14
- } from "./chunk-WSNJYGA5.js";
14
+ } from "./chunk-HNGVASTJ.js";
15
15
 
16
16
  // ../visual/src/run.ts
17
17
  import { existsSync as existsSync3 } from "node:fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge-ds/mcp",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "type": "module",
5
5
  "description": "Bridge MCP server: lets Claude (Claude Code, Claude Desktop or any MCP client) read, check and propose changes to a DTCG design system repo through pull requests.",
6
6
  "license": "FSL-1.1-MIT",
@@ -55,8 +55,8 @@
55
55
  "build:package": "node ../../scripts/build-packages.mjs mcp"
56
56
  },
57
57
  "dependencies": {
58
- "@bridge-ds/core": "^0.21.0",
59
- "@bridge-ds/visual": "^0.3.15",
58
+ "@bridge-ds/core": "^0.23.0",
59
+ "@bridge-ds/visual": "^0.3.17",
60
60
  "@modelcontextprotocol/sdk": "1.31.0",
61
61
  "typescript": "5.9.3",
62
62
  "zod": "3.25.76"