@bridge-ds/cli 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +406 -157
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -3336,25 +3336,25 @@ var GitHubClient = class _GitHubClient {
3336
3336
  return pr ? { number: pr.number, url: pr.html_url, title: pr.title, draft: !!pr.draft, headRef: pr.head.ref } : void 0;
3337
3337
  }
3338
3338
  /** Best effort: labels need the repo to allow it; failure is not fatal. */
3339
- async addLabels(issueNumber2, labels) {
3339
+ async addLabels(issueNumber3, labels) {
3340
3340
  try {
3341
- await this.request("POST", `${this.repoPath}/issues/${issueNumber2}/labels`, { labels });
3341
+ await this.request("POST", `${this.repoPath}/issues/${issueNumber3}/labels`, { labels });
3342
3342
  return true;
3343
3343
  } catch {
3344
3344
  return false;
3345
3345
  }
3346
3346
  }
3347
- async addComment(issueNumber2, body) {
3348
- await this.request("POST", `${this.repoPath}/issues/${issueNumber2}/comments`, { body });
3347
+ async addComment(issueNumber3, body) {
3348
+ await this.request("POST", `${this.repoPath}/issues/${issueNumber3}/comments`, { body });
3349
3349
  }
3350
3350
  /**
3351
3351
  * Comments on an issue or pull request, oldest first (first 100: the sticky preview comment is posted early).
3352
3352
  * `authorAssociation` is GitHub's OWNER, MEMBER, COLLABORATOR, CONTRIBUTOR, NONE... (suggestion approvals read it).
3353
3353
  */
3354
- async listIssueComments(issueNumber2) {
3354
+ async listIssueComments(issueNumber3) {
3355
3355
  const r = await this.request(
3356
3356
  "GET",
3357
- `${this.repoPath}/issues/${issueNumber2}/comments?per_page=100`
3357
+ `${this.repoPath}/issues/${issueNumber3}/comments?per_page=100`
3358
3358
  );
3359
3359
  return r.map((c) => ({ id: c.id, body: c.body ?? "", author: c.user?.login ?? "unknown", updatedAt: c.updated_at, createdAt: c.created_at ?? c.updated_at, authorAssociation: c.author_association ?? "NONE" }));
3360
3360
  }
@@ -3671,8 +3671,8 @@ var GitHubClient = class _GitHubClient {
3671
3671
  });
3672
3672
  return { id: r.id, name: r.name, status: r.status, conclusion: r.conclusion, url: r.html_url };
3673
3673
  }
3674
- async removeLabel(issueNumber2, label) {
3675
- await this.request("DELETE", `${this.repoPath}/issues/${issueNumber2}/labels/${encodeURIComponent(label)}`);
3674
+ async removeLabel(issueNumber3, label) {
3675
+ await this.request("DELETE", `${this.repoPath}/issues/${issueNumber3}/labels/${encodeURIComponent(label)}`);
3676
3676
  }
3677
3677
  // --- branch actions shared by Studio, the MCP server and the CLI (branch-actions.ts) ---
3678
3678
  /** The account the token belongs to (GET /user). Needs a token. */
@@ -3901,6 +3901,27 @@ function jiraIssueFields(r, jira, issueUrl) {
3901
3901
  };
3902
3902
  }
3903
3903
 
3904
+ // ../core/src/suggestions.ts
3905
+ var SUGGESTION_STATUS_LABEL = {
3906
+ "needs-review": "Needs review",
3907
+ "changes-requested": "Changes requested",
3908
+ approved: "Approved, ready to apply",
3909
+ applying: "Being applied",
3910
+ applied: "Applied",
3911
+ declined: "Declined",
3912
+ outdated: "Outdated"
3913
+ };
3914
+
3915
+ // ../core/src/suggestion-apply.ts
3916
+ var SUGGESTION_APPLY_EXIT = {
3917
+ ready: 0,
3918
+ "already-applied": 0,
3919
+ conflict: 3,
3920
+ "not-approved": 1,
3921
+ blocked: 1,
3922
+ refused: 1
3923
+ };
3924
+
3904
3925
  // src/index.ts
3905
3926
  import { fileURLToPath } from "node:url";
3906
3927
 
@@ -5710,7 +5731,195 @@ ${EXPLORE_HELP}`);
5710
5731
  // src/branch.ts
5711
5732
  import { readFile as readFile6 } from "node:fs/promises";
5712
5733
  import { resolve as resolve3 } from "node:path";
5713
- import { BridgeContext as BridgeContext4, branches, studio } from "@bridge-ds/mcp";
5734
+ import { BridgeContext as BridgeContext5, branches, studio } from "@bridge-ds/mcp";
5735
+
5736
+ // src/suggest.ts
5737
+ import { BridgeContext as BridgeContext4, suggestions } from "@bridge-ds/mcp";
5738
+ var SuggestUsageError = class extends Error {
5739
+ };
5740
+ var SUGGESTIONS_HELP = `bridge suggestions: changes filed as GitHub issues (label bridge-suggestion), applied by a developer
5741
+
5742
+ Usage:
5743
+ bridge suggestions [list] [--status needs-review|changes-requested|approved|applying|applied|declined|outdated|all]
5744
+ [--kind token-change|docs|component-spec|brand|revert|config] [--json]
5745
+ bridge suggestions show <n> [--json]
5746
+ the change, the checks, its version, who approved it and what is missing
5747
+ bridge suggestions link <n> --pr <m> | --branch <name>
5748
+ record the pull request that applies it (it must say "Closes #<n>")
5749
+ bridge apply <n> [--write | --patch] [--dry-run] [--accept-edited] [--force-unapproved] [--branch name] [--json]
5750
+ apply it on today's code: a new local branch by default (working tree untouched, nothing
5751
+ pushed), --write into the working tree, --patch prints a patch for git am. --dry-run shows
5752
+ the plan and the diff and writes nothing
5753
+ bridge review <n> --approve | --request-changes --message "..." | --decline --message "..." [--version <sha>]
5754
+ as the owner your GitHub token belongs to; counts only for owners in bridge.config.json
5755
+
5756
+ GitHub token: GITHUB_TOKEN or BRIDGE_GITHUB_TOKEN, else \`gh auth token\`. Reading a public repo works without one.
5757
+ Exit codes (apply): 0 applied, already applied or a clean dry run; 1 not approved, blocked by a check or refused;
5758
+ 2 usage or setup error; 3 conflict with today's code.`;
5759
+ var flag3 = (a, k) => a.flags[k]?.[a.flags[k].length - 1];
5760
+ var has3 = (a, k) => Boolean(a.flags[k]);
5761
+ function changesFlag(a) {
5762
+ if (has3(a, "suggest") && has3(a, "direct")) throw new SuggestUsageError("Pass --suggest or --direct, not both.");
5763
+ return has3(a, "direct") ? "direct" : has3(a, "suggest") ? "suggest" : void 0;
5764
+ }
5765
+ function tokenFrom2(io) {
5766
+ return io.env.BRIDGE_GITHUB_TOKEN || io.env.GITHUB_TOKEN || io.ghToken();
5767
+ }
5768
+ async function context3(root, io) {
5769
+ const token = tokenFrom2(io);
5770
+ return BridgeContext4.create({ root, ...token ? { token } : {}, ...io.fetch ? { fetch: io.fetch } : {} });
5771
+ }
5772
+ function issueNumber2(raw, usage) {
5773
+ const n = Number((raw ?? "").replace(/^#/, ""));
5774
+ if (!raw || !Number.isInteger(n) || n <= 0) throw new SuggestUsageError(`Usage: ${usage}`);
5775
+ return n;
5776
+ }
5777
+ var STATUSES = ["needs-review", "changes-requested", "approved", "applying", "applied", "declined", "outdated", "all"];
5778
+ var KINDS = ["token-change", "docs", "component-spec", "brand", "revert", "config"];
5779
+ async function runSuggestions(a, root, io = defaultIO()) {
5780
+ const sub = a._[1] ?? "list";
5781
+ if (sub === "help" || has3(a, "help")) return io.print(SUGGESTIONS_HELP), 0;
5782
+ switch (sub) {
5783
+ case "list": {
5784
+ const status = flag3(a, "status") ?? "all";
5785
+ if (!STATUSES.includes(status)) throw new SuggestUsageError(`--status takes ${STATUSES.join(", ")}, got "${status}"`);
5786
+ const kind = flag3(a, "kind");
5787
+ if (kind && !KINDS.includes(kind)) throw new SuggestUsageError(`--kind takes ${KINDS.join(", ")}, got "${kind}"`);
5788
+ const ctx = await context3(root, io);
5789
+ const r = await suggestions.listSuggestionsOp(ctx, { status, ...kind ? { kind } : {} });
5790
+ if (has3(a, "json")) return io.print(JSON.stringify(r, null, 2)), 0;
5791
+ if (!r.suggestions.length) return io.print(`No ${status === "all" ? "open " : `${status} `}suggestion in ${r.repo}.`), 0;
5792
+ for (const x of r.suggestions) {
5793
+ const prs = x.linkedPrs.length ? ` PR ${x.linkedPrs.map((p) => `#${p.number}${p.merged ? " merged" : ` ${p.state}`}`).join(", ")}` : "";
5794
+ io.print(`#${String(x.number).padEnd(5)} ${x.said.padEnd(25)} ${(x.kind ?? "").padEnd(14)} ${x.tier ? `tier ${x.tier}` : " "} ${x.title}${prs}`);
5795
+ }
5796
+ io.print(`
5797
+ ${r.next}`);
5798
+ return 0;
5799
+ }
5800
+ case "show": {
5801
+ const n = issueNumber2(a._[2], "bridge suggestions show <number>");
5802
+ const ctx = await context3(root, io);
5803
+ const r = await suggestions.getSuggestionOp(ctx, { number: n });
5804
+ if (has3(a, "json")) return io.print(JSON.stringify(r, null, 2)), 0;
5805
+ io.print(`#${r.number} ${r.title}`);
5806
+ io.print(`${r.said}${r.kind ? `, ${r.kind}` : ""}${r.tier ? `, tier ${r.tier} (${r.bump})` : ""}${r.source ? `, from ${r.source}` : ""}${r.suggestedBy ? ` by @${r.suggestedBy}` : ""}`);
5807
+ io.print(r.url);
5808
+ if (r.problem) {
5809
+ io.print(`
5810
+ ${r.problem}`);
5811
+ return 1;
5812
+ }
5813
+ if (r.summary) io.print(`
5814
+ ${r.summary}`);
5815
+ const c = r.change ?? {};
5816
+ if (c.tokens?.length) {
5817
+ io.print("\nTokens:");
5818
+ for (const t of c.tokens) io.print(` ${t.kind ?? t.op} ${t.path}${t.before !== void 0 || t.after !== void 0 ? `: ${fmt(t.before)} -> ${fmt(t.after)}` : ""}`);
5819
+ }
5820
+ for (const d of c.docs ?? []) io.print(`Docs: ${d.component} (${d.path})`);
5821
+ if (c.componentSpec) io.print(`Component spec: ${c.componentSpec.component} (${c.componentSpec.specPath})`);
5822
+ for (const f of c.files ?? []) io.print(`File: ${f.change} ${f.path}`);
5823
+ io.print(`
5824
+ Version ${r.version}${r.edited ? ` (${r.edited})` : ""}`);
5825
+ io.print(`Approved by: ${r.approvals.approvedBy.map((l) => `@${l}`).join(", ") || "nobody yet"}`);
5826
+ if (r.approvals.missing.length) io.print(`Missing: ${r.approvals.missing.join(" and ")}`);
5827
+ if (r.approvals.changesRequestedBy.length) io.print(`Changes requested by: ${r.approvals.changesRequestedBy.map((l) => `@${l}`).join(", ")}`);
5828
+ for (const p of r.linkedPrs ?? []) io.print(`Pull request: #${p.number} ${p.merged ? "merged" : p.state} ${p.url}`);
5829
+ io.print(`
5830
+ Next: ${r.next}`);
5831
+ return 0;
5832
+ }
5833
+ case "link": {
5834
+ const n = issueNumber2(a._[2], "bridge suggestions link <number> --pr <m>");
5835
+ const prRaw = flag3(a, "pr");
5836
+ const pr = prRaw ? issueNumber2(prRaw, "bridge suggestions link <number> --pr <m>") : void 0;
5837
+ const branch = flag3(a, "branch");
5838
+ if (!pr && !branch) throw new SuggestUsageError("Usage: bridge suggestions link <number> --pr <m> (or --branch <name>)");
5839
+ const ctx = await context3(root, io);
5840
+ const r = await suggestions.linkSuggestionOp(ctx, { number: n, ...pr ? { pr } : {}, ...branch ? { branch } : {} });
5841
+ if (has3(a, "json")) return io.print(JSON.stringify(r, null, 2)), 0;
5842
+ io.print(`#${n} is being applied${pr ? ` in #${pr}` : branch ? ` on ${branch}` : ""}.`);
5843
+ for (const w of r.warnings ?? []) io.error(`warning: ${w}`);
5844
+ return 0;
5845
+ }
5846
+ default:
5847
+ throw new SuggestUsageError(`Unknown suggestions command "${sub}".
5848
+
5849
+ ${SUGGESTIONS_HELP}`);
5850
+ }
5851
+ }
5852
+ var fmt = (v) => v === void 0 ? "(none)" : typeof v === "string" ? v : JSON.stringify(v);
5853
+ async function runApply(a, root, io = defaultIO()) {
5854
+ if (has3(a, "help") || a._[1] === "help") return io.print(SUGGESTIONS_HELP), 0;
5855
+ const n = issueNumber2(a._[1], "bridge apply <number> [--write | --patch] [--dry-run]");
5856
+ if (has3(a, "write") && has3(a, "patch")) throw new SuggestUsageError("Pass --write or --patch, not both.");
5857
+ const mode2 = has3(a, "write") ? "write" : has3(a, "patch") ? "patch" : "branch";
5858
+ const ctx = await context3(root, io);
5859
+ if (ctx.mode !== "local" || !ctx.isGit) throw new SuggestUsageError("bridge apply runs in a git checkout of the design system: cd into it, or pass --root.");
5860
+ const branch = flag3(a, "branch");
5861
+ const r = await suggestions.applySuggestionOp(ctx, {
5862
+ number: n,
5863
+ mode: has3(a, "dry-run") ? "dry-run" : mode2,
5864
+ acceptEdited: has3(a, "accept-edited"),
5865
+ forceUnapproved: has3(a, "force-unapproved"),
5866
+ ...branch ? { branch } : {}
5867
+ });
5868
+ const code = typeof r.exitCode === "number" ? r.exitCode : SUGGESTION_APPLY_EXIT[r.outcome] ?? 1;
5869
+ if (has3(a, "json")) return io.print(JSON.stringify(r, null, 2)), code;
5870
+ if (mode2 === "patch" && r.patch && !has3(a, "dry-run")) {
5871
+ io.print(r.patch.trimEnd());
5872
+ io.error(r.message);
5873
+ for (const w of r.warnings ?? []) io.error(`warning: ${w}`);
5874
+ return code;
5875
+ }
5876
+ io.print(`#${n}: ${r.message}`);
5877
+ if (r.table) io.print(`
5878
+ ${r.table}`);
5879
+ for (const p of r.problems ?? []) io.print(` ${p}`);
5880
+ for (const note of r.notes ?? []) io.print(` note: ${note}`);
5881
+ if (r.diff) io.print(`
5882
+ ${r.diff.trimEnd()}`);
5883
+ if (r.brief) io.print(`
5884
+ Brief to implement it:
5885
+ ${r.brief}`);
5886
+ if (r.branch) io.print(`
5887
+ branch: ${r.branch}${r.commit ? ` (${String(r.commit).slice(0, 7)})` : ""}`);
5888
+ for (const w of r.warnings ?? []) io.error(`warning: ${w}`);
5889
+ if (r.next && r.next !== r.message) io.print(`
5890
+ Next: ${r.next}`);
5891
+ return code;
5892
+ }
5893
+ async function runReview(a, root, io = defaultIO()) {
5894
+ if (has3(a, "help") || a._[1] === "help") return io.print(SUGGESTIONS_HELP), 0;
5895
+ const usage = 'bridge review <number> --approve | --request-changes --message "..." | --decline --message "..."';
5896
+ const n = issueNumber2(a._[1], usage);
5897
+ const events = ["approve", "request-changes", "decline", "comment"].filter((e) => has3(a, e));
5898
+ if (events.length !== 1) throw new SuggestUsageError(`Usage: ${usage}`);
5899
+ const event = events[0];
5900
+ const inline = flag3(a, event);
5901
+ const message = flag3(a, "message") ?? (inline && inline !== "true" ? inline : void 0);
5902
+ if ((event === "request-changes" || event === "decline" || event === "comment") && !message?.trim()) throw new SuggestUsageError(`--${event} needs --message "..." (the author reads it).`);
5903
+ const role = flag3(a, "role");
5904
+ if (role && !["design", "tech", "approval"].includes(role)) throw new SuggestUsageError(`--role takes design, tech or approval, got "${role}"`);
5905
+ const ctx = await context3(root, io);
5906
+ const version = flag3(a, "version");
5907
+ const r = await suggestions.reviewSuggestionOp(ctx, {
5908
+ number: n,
5909
+ event,
5910
+ ...message ? { message } : {},
5911
+ ...role ? { role } : {},
5912
+ ...version ? { payloadSha: version } : {}
5913
+ });
5914
+ if (has3(a, "json")) return io.print(JSON.stringify(r, null, 2)), 0;
5915
+ const done = event === "approve" ? "Approved" : event === "request-changes" ? "Changes requested on" : event === "decline" ? "Declined" : "Commented on";
5916
+ io.print(`${done} #${n}${r.version ? ` (version ${r.version})` : ""}. Now: ${SUGGESTION_STATUS_LABEL[r.status] ?? r.status}.`);
5917
+ for (const w of r.warnings ?? []) io.error(`warning: ${w}`);
5918
+ if (r.next) io.print(`Next: ${r.next}`);
5919
+ return r.counts === false ? 1 : 0;
5920
+ }
5921
+
5922
+ // src/branch.ts
5714
5923
  var BRANCH_HELP = `bridge branch: branches in review, the same actions as Bridge Studio
5715
5924
 
5716
5925
  Usage:
@@ -5740,11 +5949,11 @@ Usage:
5740
5949
 
5741
5950
  Start work for a product: bridge propose|explore start|request create ... --product <key> [--jira DS-42].
5742
5951
  GitHub token: GITHUB_TOKEN or BRIDGE_GITHUB_TOKEN, else \`gh auth token\`. Exit codes: 0 ok, 2 usage or setup error.`;
5743
- var flag3 = (a, k) => a.flags[k]?.[a.flags[k].length - 1];
5744
- var has3 = (a, k) => Boolean(a.flags[k]);
5745
- async function context3(root, io) {
5952
+ var flag4 = (a, k) => a.flags[k]?.[a.flags[k].length - 1];
5953
+ var has4 = (a, k) => Boolean(a.flags[k]);
5954
+ async function context4(root, io) {
5746
5955
  const token = io.env.BRIDGE_GITHUB_TOKEN || io.env.GITHUB_TOKEN || io.ghToken();
5747
- return BridgeContext4.create({ root, ...token ? { token } : {}, ...io.fetch ? { fetch: io.fetch } : {} });
5956
+ return BridgeContext5.create({ root, ...token ? { token } : {}, ...io.fetch ? { fetch: io.fetch } : {} });
5748
5957
  }
5749
5958
  function number(a, at, usage) {
5750
5959
  const raw = a._[at];
@@ -5763,16 +5972,16 @@ function pairs(list2, what) {
5763
5972
  var said = (r) => String(r.said ?? r.summary ?? r.status ?? "Done.");
5764
5973
  async function runBranch(a, root, io = defaultIO()) {
5765
5974
  const sub = a._[1];
5766
- if (!sub || sub === "help" || has3(a, "help")) {
5975
+ if (!sub || sub === "help" || has4(a, "help")) {
5767
5976
  io.print(BRANCH_HELP);
5768
- return sub || has3(a, "help") ? 0 : 2;
5977
+ return sub || has4(a, "help") ? 0 : 2;
5769
5978
  }
5770
- const json = has3(a, "json");
5771
- const ctx = await context3(root, io);
5979
+ const json = has4(a, "json");
5980
+ const ctx = await context4(root, io);
5772
5981
  const out = (r, text) => (json ? io.print(JSON.stringify(r, null, 2)) : text(), 0);
5773
5982
  switch (sub) {
5774
5983
  case "list": {
5775
- const limit = flag3(a, "limit");
5984
+ const limit = flag4(a, "limit");
5776
5985
  const r = await branches.whatNeedsMe(ctx, limit ? { limit: Number(limit) } : {});
5777
5986
  return out(r, () => {
5778
5987
  io.print(r.summary);
@@ -5806,28 +6015,28 @@ async function runBranch(a, root, io = defaultIO()) {
5806
6015
  }
5807
6016
  case "review": {
5808
6017
  const n = number(a, 2, 'bridge branch review <n> --approve | --request-changes "..." | --comment "..."');
5809
- const decision = has3(a, "approve") ? "approve" : has3(a, "request-changes") ? "request_changes" : has3(a, "comment") ? "comment" : null;
6018
+ const decision = has4(a, "approve") ? "approve" : has4(a, "request-changes") ? "request_changes" : has4(a, "comment") ? "comment" : null;
5810
6019
  if (!decision) throw new RequestUsageError('Say what you decide: --approve, --request-changes "what to change" or --comment "text".');
5811
- const body = decision === "approve" ? flag3(a, "body") : flag3(a, decision === "request_changes" ? "request-changes" : "comment");
6020
+ const body = decision === "approve" ? flag4(a, "body") : flag4(a, decision === "request_changes" ? "request-changes" : "comment");
5812
6021
  const r = await branches.reviewBranch(ctx, { pr: n, decision, ...body && body !== "true" ? { body } : {} });
5813
6022
  return out(r, () => io.print(r.said));
5814
6023
  }
5815
6024
  case "ask": {
5816
- const r = await branches.askSomeoneElse(ctx, { pr: number(a, 2, "bridge branch ask <n>"), dryRun: has3(a, "dry-run") });
6025
+ const r = await branches.askSomeoneElse(ctx, { pr: number(a, 2, "bridge branch ask <n>"), dryRun: has4(a, "dry-run") });
5817
6026
  return out(r, () => io.print(r.said));
5818
6027
  }
5819
6028
  case "comment": {
5820
6029
  const n = number(a, 2, 'bridge branch comment <n> "text"');
5821
- const body = a._.slice(3).join(" ") || flag3(a, "body");
6030
+ const body = a._.slice(3).join(" ") || flag4(a, "body");
5822
6031
  if (!body) throw new RequestUsageError('Usage: bridge branch comment <n> "text" [--reply-to <id>]');
5823
- const reply = flag3(a, "reply-to");
6032
+ const reply = flag4(a, "reply-to");
5824
6033
  const r = await branches.commentOnBranch(ctx, { pr: n, body, ...reply ? { replyTo: Number(reply) } : {} });
5825
6034
  return out(r, () => io.print(r.said));
5826
6035
  }
5827
6036
  case "merge": {
5828
6037
  const n = number(a, 2, 'bridge branch merge <n> [--override "reason"] [--dry-run]');
5829
- const reason = flag3(a, "override");
5830
- const r = await branches.mergeBranch(ctx, { pr: n, ...reason ? { overrideReason: reason } : {}, dryRun: has3(a, "dry-run") });
6038
+ const reason = flag4(a, "override");
6039
+ const r = await branches.mergeBranch(ctx, { pr: n, ...reason ? { overrideReason: reason } : {}, dryRun: has4(a, "dry-run") });
5831
6040
  return out(r, () => io.print(r.said));
5832
6041
  }
5833
6042
  case "close": {
@@ -5842,7 +6051,7 @@ async function runBranch(a, root, io = defaultIO()) {
5842
6051
  const n = number(a, 2, "bridge branch update <n> [--choice key=mine|theirs] [--dry-run]");
5843
6052
  const choices = pairs(a.flags.choice, "choice");
5844
6053
  for (const [k, v] of Object.entries(choices)) if (v !== "mine" && v !== "theirs") throw new RequestUsageError(`--choice ${k}= takes mine or theirs, got "${v}".`);
5845
- const r = await branches.updateFromMain(ctx, { pr: n, ...Object.keys(choices).length ? { choices } : {}, dryRun: has3(a, "dry-run") });
6054
+ const r = await branches.updateFromMain(ctx, { pr: n, ...Object.keys(choices).length ? { choices } : {}, dryRun: has4(a, "dry-run") });
5846
6055
  return out(r, () => {
5847
6056
  io.print(said(r));
5848
6057
  for (const c of r.conflicts ?? []) io.print(` ${c.key} (${c.token}, default ${c.default ?? "none: pick one"})`);
@@ -5874,8 +6083,8 @@ ${BRANCH_HELP}`);
5874
6083
  }
5875
6084
  }
5876
6085
  async function runStudioRead(cmd, a, root, io = defaultIO()) {
5877
- const ctx = await context3(root, io);
5878
- const json = has3(a, "json");
6086
+ const ctx = await context4(root, io);
6087
+ const json = has4(a, "json");
5879
6088
  if (cmd === "products") {
5880
6089
  const r2 = await branches.listProducts(ctx);
5881
6090
  if (json) return io.print(JSON.stringify(r2, null, 2)), 0;
@@ -5904,7 +6113,7 @@ This folder: ${r2.current.name}. Pick another with --product <key>.`);
5904
6113
  }
5905
6114
  async function runDocsSave(a, root, io = defaultIO()) {
5906
6115
  const component = a._[2];
5907
- const file = flag3(a, "file");
6116
+ const file = flag4(a, "file");
5908
6117
  if (!component || !file) throw new RequestUsageError('Usage: bridge docs save <Component> --file docs.json [--pr <n>] [--title "..."] [--jira DS-42] [--product admin] [--dry-run]');
5909
6118
  let docs;
5910
6119
  try {
@@ -5912,28 +6121,32 @@ async function runDocsSave(a, root, io = defaultIO()) {
5912
6121
  } catch (e) {
5913
6122
  throw new RequestUsageError(`${file} is not a readable JSON file: ${e.message}`);
5914
6123
  }
5915
- const ctx = await context3(root, io);
5916
- const pr = flag3(a, "pr");
6124
+ const ctx = await context4(root, io);
6125
+ const pr = flag4(a, "pr");
6126
+ const changes = changesFlag(a);
5917
6127
  const r = await studio.saveDocs(ctx, {
5918
6128
  component,
5919
6129
  docs,
5920
6130
  ...pr ? { pr } : {},
5921
- ...flag3(a, "title") ? { title: flag3(a, "title") } : {},
5922
- ...flag3(a, "notes") ? { notes: flag3(a, "notes") } : {},
5923
- ...flag3(a, "jira") ? { jira: flag3(a, "jira") } : {},
5924
- ...flag3(a, "product") ? { product: flag3(a, "product") } : {},
5925
- dryRun: has3(a, "dry-run")
6131
+ ...flag4(a, "title") ? { title: flag4(a, "title") } : {},
6132
+ ...flag4(a, "notes") ? { notes: flag4(a, "notes") } : {},
6133
+ ...flag4(a, "jira") ? { jira: flag4(a, "jira") } : {},
6134
+ ...flag4(a, "product") ? { product: flag4(a, "product") } : {},
6135
+ ...changes ? { changes } : {},
6136
+ source: "cli",
6137
+ dryRun: has4(a, "dry-run")
5926
6138
  });
5927
- if (has3(a, "json")) io.print(JSON.stringify(r, null, 2));
6139
+ if (has4(a, "json")) io.print(JSON.stringify(r, null, 2));
5928
6140
  else io.print(r.status === "dry-run" || r.status === "preview" ? `${r.said ?? "Dry run, nothing written."}
5929
6141
 
5930
6142
  ${r.path}:
5931
- ${r.content}` : String(r.said));
6143
+ ${r.content}` : `${String(r.said)}${r.next ? `
6144
+ ${String(r.next)}` : ""}`);
5932
6145
  return 0;
5933
6146
  }
5934
6147
 
5935
6148
  // src/pieces.ts
5936
- import { BridgeContext as BridgeContext5, branches as branches2, pieces } from "@bridge-ds/mcp";
6149
+ import { BridgeContext as BridgeContext6, branches as branches2, pieces } from "@bridge-ds/mcp";
5937
6150
  var PIECES_HELP = `bridge pieces: a product branch and the library
5938
6151
 
5939
6152
  Usage:
@@ -5948,10 +6161,10 @@ Usage:
5948
6161
  bridge pieces switch <n> once the library shipped: main into the product branch
5949
6162
 
5950
6163
  GitHub token: GITHUB_TOKEN or BRIDGE_GITHUB_TOKEN, else \`gh auth token\`. Exit codes: 0 ok, 2 usage or setup error.`;
5951
- var has4 = (a, k) => Boolean(a.flags[k]);
5952
- async function context4(root, io) {
6164
+ var has5 = (a, k) => Boolean(a.flags[k]);
6165
+ async function context5(root, io) {
5953
6166
  const token = io.env.BRIDGE_GITHUB_TOKEN || io.env.GITHUB_TOKEN || io.ghToken();
5954
- return BridgeContext5.create({ root, ...token ? { token } : {}, ...io.fetch ? { fetch: io.fetch } : {} });
6167
+ return BridgeContext6.create({ root, ...token ? { token } : {}, ...io.fetch ? { fetch: io.fetch } : {} });
5955
6168
  }
5956
6169
  function number2(a, at, usage) {
5957
6170
  const raw = a._[at];
@@ -5965,12 +6178,12 @@ function piece(a, at, usage) {
5965
6178
  }
5966
6179
  async function runPieces(a, root, io = defaultIO()) {
5967
6180
  const sub = a._[1];
5968
- if (!sub || sub === "help" || has4(a, "help")) {
6181
+ if (!sub || sub === "help" || has5(a, "help")) {
5969
6182
  io.print(PIECES_HELP);
5970
- return sub || has4(a, "help") ? 0 : 2;
6183
+ return sub || has5(a, "help") ? 0 : 2;
5971
6184
  }
5972
- const json = has4(a, "json");
5973
- const ctx = await context4(root, io);
6185
+ const json = has5(a, "json");
6186
+ const ctx = await context5(root, io);
5974
6187
  const out = (r, text) => (json ? io.print(JSON.stringify(r, null, 2)) : text(), 0);
5975
6188
  switch (sub) {
5976
6189
  case "status": {
@@ -5985,9 +6198,10 @@ async function runPieces(a, root, io = defaultIO()) {
5985
6198
  }
5986
6199
  case "open": {
5987
6200
  const usage = "bridge pieces open <n> <piece>";
5988
- const r = await pieces.openLibraryBranchOp(ctx, { pr: number2(a, 2, usage), piece: piece(a, 3, usage), usePreview: !has4(a, "no-preview"), dryRun: has4(a, "dry-run"), source: "cli" });
6201
+ const changes = changesFlag(a);
6202
+ const r = await pieces.openLibraryBranchOp(ctx, { pr: number2(a, 2, usage), piece: piece(a, 3, usage), usePreview: !has5(a, "no-preview"), dryRun: has5(a, "dry-run"), source: "cli", ...changes ? { changes } : {} });
5989
6203
  return out(r, () => {
5990
- io.print(`${r.status === "dry-run" ? "Would open" : r.status === "already-linked" ? "Already linked" : "Opened"} a ${r.opens}: ${r.title}, needed by ${r.neededBy}.`);
6204
+ io.print(`${r.status === "dry-run" ? "Would open" : r.status === "already-linked" ? "Already linked" : r.status === "suggested" ? "Suggested" : "Opened"} a ${r.opens}: ${r.title}, needed by ${r.neededBy}.`);
5991
6205
  if (r.library) io.print(` #${r.library.number} ${r.library.url}`);
5992
6206
  if (r.preview) io.print(` ${r.preview.said}`);
5993
6207
  for (const w of r.warnings ?? []) io.print(` ${w}`);
@@ -6004,7 +6218,7 @@ async function runPieces(a, root, io = defaultIO()) {
6004
6218
  return out(r, () => io.print(r.said));
6005
6219
  }
6006
6220
  default: {
6007
- const r = await pieces.missingPiecesOp(ctx, { pr: number2(a, 1, "bridge pieces <n> [--record]"), record: has4(a, "record") });
6221
+ const r = await pieces.missingPiecesOp(ctx, { pr: number2(a, 1, "bridge pieces <n> [--record]"), record: has5(a, "record") });
6008
6222
  return out(r, () => {
6009
6223
  io.print(`#${r.pr} ${r.branch} (${r.product}): ${r.pieces.length ? `${r.pieces.length} ${r.pieces.length === 1 ? "piece is" : "pieces are"} missing from the library` : "nothing is missing from the library"}, ${r.files} files read.`);
6010
6224
  for (const p of r.pieces) io.print(` ${p.id} ${p.title}: ${p.summary} Opens ${p.opens}.${"linked" in p ? ` Linked: #${p.linked}.` : ""}`);
@@ -6020,7 +6234,7 @@ ${r.fixes.sample.map((s) => ` ${s}`).join("\n")}`);
6020
6234
  // src/figma.ts
6021
6235
  import { readFileSync as readFileSync2 } from "node:fs";
6022
6236
  import { resolve as resolve4 } from "node:path";
6023
- import { BridgeContext as BridgeContext6, branches as branches3, figma } from "@bridge-ds/mcp";
6237
+ import { BridgeContext as BridgeContext7, branches as branches3, figma } from "@bridge-ds/mcp";
6024
6238
  var FIGMA_HELP = `bridge figma: component changes sent from Figma
6025
6239
 
6026
6240
  Usage:
@@ -6034,10 +6248,10 @@ Usage:
6034
6248
  token change, or a branch with the spec for Claude AI
6035
6249
 
6036
6250
  GitHub token: GITHUB_TOKEN or BRIDGE_GITHUB_TOKEN, else \`gh auth token\`. Exit codes: 0 ok, 2 usage or setup error.`;
6037
- var has5 = (a, k) => Boolean(a.flags[k]);
6038
- async function context5(root, io) {
6251
+ var has6 = (a, k) => Boolean(a.flags[k]);
6252
+ async function context6(root, io) {
6039
6253
  const token = io.env.BRIDGE_GITHUB_TOKEN || io.env.GITHUB_TOKEN || io.ghToken();
6040
- return BridgeContext6.create({ root, ...token ? { token } : {}, ...io.fetch ? { fetch: io.fetch } : {} });
6254
+ return BridgeContext7.create({ root, ...token ? { token } : {}, ...io.fetch ? { fetch: io.fetch } : {} });
6041
6255
  }
6042
6256
  function number3(a, usage) {
6043
6257
  const raw = a._[2];
@@ -6046,17 +6260,17 @@ function number3(a, usage) {
6046
6260
  }
6047
6261
  async function runFigma(a, root, io = defaultIO()) {
6048
6262
  const sub = a._[1];
6049
- if (sub === "help" || has5(a, "help")) {
6263
+ if (sub === "help" || has6(a, "help")) {
6050
6264
  io.print(FIGMA_HELP);
6051
6265
  return 0;
6052
6266
  }
6053
- const json = has5(a, "json");
6054
- const ctx = await context5(root, io);
6267
+ const json = has6(a, "json");
6268
+ const ctx = await context6(root, io);
6055
6269
  const out = (r, text) => (json ? io.print(JSON.stringify(r, null, 2)) : text(), 0);
6056
6270
  switch (sub) {
6057
6271
  case void 0:
6058
6272
  case "list": {
6059
- const r = await figma.figmaChangesOp(ctx, { state: has5(a, "all") ? "all" : "open" });
6273
+ const r = await figma.figmaChangesOp(ctx, { state: has6(a, "all") ? "all" : "open" });
6060
6274
  return out(r, () => {
6061
6275
  for (const c of r.changes) io.print(`#${c.pr} ${c.title} (${c.route}): ${c.status}. ${c.said}`);
6062
6276
  io.print(`Next: ${r.next}`);
@@ -6064,7 +6278,7 @@ async function runFigma(a, root, io = defaultIO()) {
6064
6278
  }
6065
6279
  case "show": {
6066
6280
  const r = await figma.getFigmaChangeOp(ctx, { pr: number3(a, "bridge figma show <n>") });
6067
- if (has5(a, "draft")) {
6281
+ if (has6(a, "draft")) {
6068
6282
  if (!r.brief) throw new RequestUsageError(`#${r.pr} is an exact token change: there is no code to draft.`);
6069
6283
  if (!io.hasClaude()) throw new RequestUsageError("`claude` is not on PATH: install Claude Code, or paste the brief from `bridge figma show <n>` into Claude.");
6070
6284
  return io.runClaude(r.brief, root);
@@ -6089,12 +6303,14 @@ ${r.brief}`);
6089
6303
  } catch (err) {
6090
6304
  throw new RequestUsageError(`${file} could not be read as JSON: ${err.message}`);
6091
6305
  }
6092
- const r = await figma.pushFigmaComponentOp(ctx, { diff: diff2, dryRun: has5(a, "dry-run"), source: "cli" });
6306
+ const changes = changesFlag(a);
6307
+ const r = await figma.pushFigmaComponentOp(ctx, { diff: diff2, dryRun: has6(a, "dry-run"), source: "cli", ...changes ? { changes } : {} });
6093
6308
  return out(r, () => {
6094
6309
  io.print(`${r.component}: ${r.route}. ${r.said}`);
6095
6310
  for (const x of r.reasons ?? []) io.print(` ${x}`);
6096
6311
  for (const x of r.fixInFigma ?? []) io.print(` Fix in Figma: ${x.what} ${x.todo}`);
6097
6312
  if (r.library) io.print(` #${r.library.number} ${r.library.url}`);
6313
+ if (r.suggestion) io.print(` suggestion #${r.suggestion.number} ${r.suggestion.url}`);
6098
6314
  io.print(`Next: ${r.next}`);
6099
6315
  });
6100
6316
  }
@@ -6135,7 +6351,7 @@ async function rolesReport(opts) {
6135
6351
  }
6136
6352
 
6137
6353
  // src/index.ts
6138
- import { brand, BridgeContext as BridgeContext7, CONFIG_FILE as CONFIG_FILE2, core, detectConfig, GitRefSource, history as hist, LocalSource, ops, optionsFromArgv, serveStdio, toConfigJson, VERSION } from "@bridge-ds/mcp";
6354
+ import { brand, BridgeContext as BridgeContext8, CONFIG_FILE as CONFIG_FILE2, core, detectConfig, GitRefSource, history as hist, LocalSource, ops, optionsFromArgv, serveStdio, toConfigJson, VERSION } from "@bridge-ds/mcp";
6139
6355
  var MCP_PACKAGE = "@bridge-ds/mcp";
6140
6356
  var HELP = `bridge ${VERSION}: design system as code, for you and your Claude
6141
6357
 
@@ -6151,8 +6367,10 @@ Usage:
6151
6367
  bridge diff <base> [--json|--md] designer-readable token diff: working tree vs <base> (git ref)
6152
6368
  bridge propose --title "..." --set path=value [--set ...] [--file f | --mode theme=dark]
6153
6369
  [--edits edits.json] [--summary "..."] [--branch explore/<name>] [--pr <n>]
6154
- [--product <key>] [--jira DS-42] [--dry-run]
6155
- validate + contrast + new local bridge/* branch (never pushes).
6370
+ [--product <key>] [--jira DS-42] [--suggest | --direct] [--dry-run]
6371
+ validate + contrast, then a suggestion (a GitHub issue a developer
6372
+ applies with bridge apply) or, with "changes": "direct" in
6373
+ bridge.config.json or --direct, a new local bridge/* branch (never pushes).
6156
6374
  --branch: write the edits to the checked-out exploration instead.
6157
6375
  --pr: add them to that branch in review (GitHub token).
6158
6376
  --product: the product it is for (bridge products); --jira: the
@@ -6160,9 +6378,10 @@ Usage:
6160
6378
  bridge brand list [--json] brands: slug, name, default, primary action color, theme overrides
6161
6379
  bridge brand create <slug> --from bridge --primary <hex|hue> --neutral <hex|hue>
6162
6380
  [--name "Acme"] [--accent x] [--link x] [--radius soft|balanced|crisp|i,c,co,o]
6163
- [--heading font] [--text font] [--notes "..."] [--dry-run] [--json]
6164
- new brand: generated ramps, contrast gate for every theme,
6165
- new local bridge/brand-<slug> branch (never pushes, never main).
6381
+ [--heading font] [--text font] [--notes "..."] [--suggest | --direct] [--dry-run] [--json]
6382
+ new brand: generated ramps, contrast gate for every theme, then a
6383
+ suggestion, or in direct mode a new local bridge/brand-<slug> branch
6384
+ (never pushes, never main).
6166
6385
  Exit 1 when blocked
6167
6386
  bridge impact [--base main] [--head HEAD] [--out dir] [--only stories|app] [--threshold 0.03]
6168
6387
  [--plan] [--json] [--image-base url] [--artifact-url url] [--keep-unchanged]
@@ -6176,9 +6395,9 @@ Usage:
6176
6395
  Needs Chrome installed
6177
6396
  bridge history [token] [--json] [--limit n] [--author a] [--tier n] [--version v]
6178
6397
  token history: versions, merged changes, who, when, why
6179
- bridge revert <pr|commit|id> [--dry-run] [--restore-conflicts] [--use-before path@file] [--json]
6180
- undo a merged token change against HEAD: conflicts shown,
6181
- new local bridge/* branch (never pushes, never main)
6398
+ bridge revert <pr|commit|id> [--dry-run] [--restore-conflicts] [--use-before path@file] [--suggest | --direct] [--json]
6399
+ undo a merged token change against HEAD: conflicts shown, then a
6400
+ suggestion, or in direct mode a new local bridge/* branch (never pushes)
6182
6401
  bridge audit <path> [--json [out.json]] [--md [out.md]] [--fail-under 80] [--baseline prev.json]
6183
6402
  [--label "..."] [--ds dir] [--no-regress] [--allowlist known.json]
6184
6403
  design system adoption in a product folder: token and component
@@ -6221,6 +6440,17 @@ Usage:
6221
6440
  a product branch and the library (\`bridge pieces help\`): what it adds
6222
6441
  that the library lacks, the library branch each piece opens (linked
6223
6442
  both ways), its preview in the product branch, the published version
6443
+ bridge suggestions [list | show <n> | link <n> --pr <m>] [--status approved] [--json]
6444
+ suggestions: changes filed as GitHub issues (label bridge-suggestion)
6445
+ that the owners approve and a developer applies (\`bridge suggestions help\`)
6446
+ bridge apply <n> [--write | --patch] [--dry-run] [--accept-edited] [--force-unapproved] [--json]
6447
+ apply suggestion #n on today's code: a new local branch (working tree
6448
+ untouched, nothing pushed), --write into the working tree, --patch for
6449
+ git am. Exit 0 applied or already applied, 1 not approved or blocked,
6450
+ 2 usage, 3 conflict
6451
+ bridge review <n> --approve | --request-changes --message "..." | --decline --message "..."
6452
+ review a suggestion as its owner (counts only for owners in
6453
+ bridge.config.json, on the version you saw)
6224
6454
  bridge figma [show <n> | drafted <n> | push <diff.json>]
6225
6455
  component changes sent from Figma (\`bridge figma help\`): exact token
6226
6456
  changes and branches Claude AI drafts from the spec
@@ -6234,8 +6464,11 @@ Usage:
6234
6464
  Options:
6235
6465
  --root <dir> repo root (default: current directory)
6236
6466
  --ds <dir> audit: design system repo with bridge.config.json (default: --root, or the nearest one above)
6237
- GITHUB_TOKEN env, optional: lets the MCP server open PRs on a remote repo, and bridge request create
6238
- file issues (else \`gh auth token\`). Never needed for local token work.
6467
+ GITHUB_TOKEN env, optional: lets bridge file suggestions and requests (Issues: read and write) and the
6468
+ MCP server open PRs on a remote repo in direct mode (else \`gh auth token\`). Never needed for
6469
+ local token work in direct mode.
6470
+ --suggest | --direct how a change reaches the code for this command (propose, brand create, revert,
6471
+ docs save, pieces open, figma push). Default: "changes" in bridge.config.json, else suggest.
6239
6472
  `;
6240
6473
  function parse(argv) {
6241
6474
  const out = { _: [], flags: {} };
@@ -6245,23 +6478,32 @@ function parse(argv) {
6245
6478
  const [k, inline] = a.slice(2).split(/=(.*)/s, 2);
6246
6479
  const next = argv[i + 1];
6247
6480
  const fileArg = k === "json" && /\.json$/i.test(next ?? "") || k === "md" && /\.(md|markdown)$/i.test(next ?? "");
6248
- const takesValue = inline === void 0 && next !== void 0 && !next.startsWith("--") && (fileArg || !["force", "json", "md", "strict", "dry-run", "help", "fix", "write", "no-regress", "plan", "keep-unchanged", "restore-conflicts", "breaking", "claude", "all", "offline", "approve"].includes(k));
6481
+ const takesValue = inline === void 0 && next !== void 0 && !next.startsWith("--") && (fileArg || !["force", "json", "md", "strict", "dry-run", "help", "fix", "write", "no-regress", "plan", "keep-unchanged", "restore-conflicts", "breaking", "claude", "all", "offline", "approve", "patch", "accept-edited", "force-unapproved", "suggest", "direct"].includes(k));
6249
6482
  (out.flags[k] ??= []).push(inline ?? (takesValue ? argv[++i] : "true"));
6250
6483
  } else out._.push(a);
6251
6484
  }
6252
6485
  return out;
6253
6486
  }
6254
- var flag4 = (a, k) => a.flags[k]?.[a.flags[k].length - 1];
6255
- var has6 = (a, k) => Boolean(a.flags[k]);
6487
+ var flag5 = (a, k) => a.flags[k]?.[a.flags[k].length - 1];
6488
+ var has7 = (a, k) => Boolean(a.flags[k]);
6256
6489
  var print = (s) => process.stdout.write(`${s}
6257
6490
  `);
6258
6491
  var modeArg = (s) => s ? Object.fromEntries(s.split(",").map((kv) => kv.split("="))) : void 0;
6492
+ var githubToken = () => process.env.BRIDGE_GITHUB_TOKEN || process.env.GITHUB_TOKEN || defaultIO().ghToken();
6493
+ function printSent(r) {
6494
+ if (r.status === "suggested") print(`suggestion: #${r.number} ${r.url}`);
6495
+ if (r.message) print(String(r.message));
6496
+ if (r.branch && r.status !== "suggested") print(`branch: ${r.branch}`);
6497
+ for (const w of r.warnings ?? []) print(`warning: ${w}`);
6498
+ if (r.next) print(String(r.next));
6499
+ if (r.hint) print(String(r.hint));
6500
+ }
6259
6501
  async function init(a, root) {
6260
6502
  const cfgPath = join6(root, CONFIG_FILE2);
6261
6503
  let config;
6262
- if (existsSync6(cfgPath) && !has6(a, "force")) {
6504
+ if (existsSync6(cfgPath) && !has7(a, "force")) {
6263
6505
  print(`${CONFIG_FILE2} exists, keeping it (--force to regenerate).`);
6264
- config = (await (await BridgeContext7.create({ root })).config()).config;
6506
+ config = (await (await BridgeContext8.create({ root })).config()).config;
6265
6507
  } else {
6266
6508
  const src = new LocalSource(root);
6267
6509
  const files = await src.list("");
@@ -6289,14 +6531,14 @@ async function init(a, root) {
6289
6531
  print(` claude mcp add bridge -- ${desktop.command} ${desktop.args.join(" ")}`);
6290
6532
  }
6291
6533
  async function check(a, root) {
6292
- const ctx = await BridgeContext7.create({ root });
6534
+ const ctx = await BridgeContext8.create({ root });
6293
6535
  const v = await ops.validateTokens(ctx, { includeWarnings: true });
6294
6536
  const c = await ops.checkContrast(ctx, {});
6295
6537
  const warnings = "warnings" in v ? v.warnings ?? [] : [];
6296
- const failed = !v.valid || "failing" in c && (c.failing ?? 0) > 0 || has6(a, "strict") && warnings.length > 0;
6538
+ const failed = !v.valid || "failing" in c && (c.failing ?? 0) > 0 || has7(a, "strict") && warnings.length > 0;
6297
6539
  const protection = await protectionOf(a, root, ctx);
6298
6540
  const roles = await rolesOf(a, root, ctx);
6299
- if (has6(a, "json")) {
6541
+ if (has7(a, "json")) {
6300
6542
  print(JSON.stringify({ ok: !failed, validation: v, contrast: c, ...protection ? { protection: protection.state } : {}, ...roles?.teams.length ? { teams: roles.teams } : {} }, null, 2));
6301
6543
  return failed ? 1 : 0;
6302
6544
  }
@@ -6315,7 +6557,7 @@ async function check(a, root) {
6315
6557
  return failed ? 1 : 0;
6316
6558
  }
6317
6559
  async function protectionOf(a, root, ctx) {
6318
- if (has6(a, "offline") || process.env.BRIDGE_OFFLINE === "1") return void 0;
6560
+ if (has7(a, "offline") || process.env.BRIDGE_OFFLINE === "1") return void 0;
6319
6561
  const { config } = await ctx.config();
6320
6562
  const repo = config.repo ? `${config.repo.owner}/${config.repo.name}` : await originRepo(root);
6321
6563
  if (!repo) return void 0;
@@ -6323,7 +6565,7 @@ async function protectionOf(a, root, ctx) {
6323
6565
  return protectionReport({ repo, defaultBranch: config.repo?.defaultBranch ?? "main", token });
6324
6566
  }
6325
6567
  async function rolesOf(a, root, ctx) {
6326
- if (has6(a, "offline") || process.env.BRIDGE_OFFLINE === "1") return void 0;
6568
+ if (has7(a, "offline") || process.env.BRIDGE_OFFLINE === "1") return void 0;
6327
6569
  const { config } = await ctx.config();
6328
6570
  const repo = config.repo ? `${config.repo.owner}/${config.repo.name}` : await originRepo(root);
6329
6571
  if (!repo) return void 0;
@@ -6333,9 +6575,9 @@ async function rolesOf(a, root, ctx) {
6333
6575
  async function tokens(a, root) {
6334
6576
  const q = a._.slice(1).join(" ");
6335
6577
  if (!q) throw new UsageError("bridge tokens <query>");
6336
- const ctx = await BridgeContext7.create({ root });
6337
- const r = await ops.searchTokens(ctx, { query: q, limit: Number(flag4(a, "limit") ?? 20) });
6338
- if (has6(a, "json")) return print(JSON.stringify(r, null, 2));
6578
+ const ctx = await BridgeContext8.create({ root });
6579
+ const r = await ops.searchTokens(ctx, { query: q, limit: Number(flag5(a, "limit") ?? 20) });
6580
+ if (has7(a, "json")) return print(JSON.stringify(r, null, 2));
6339
6581
  if (!r.results.length) return print(`No token matches "${q}".`);
6340
6582
  const w = Math.max(...r.results.map((x) => x.path.length));
6341
6583
  for (const t of r.results) print(`${t.path.padEnd(w)} ${String(t.value).padEnd(10)} ${(t.tier ?? "").padEnd(9)} ${t.description ?? ""}`);
@@ -6343,7 +6585,7 @@ async function tokens(a, root) {
6343
6585
  async function diff(a, root) {
6344
6586
  const base = a._[1];
6345
6587
  if (!base) throw new UsageError("bridge diff <base> (a git ref: main, HEAD~1, a sha)");
6346
- const ctx = await BridgeContext7.create({ root });
6588
+ const ctx = await BridgeContext8.create({ root });
6347
6589
  const { config } = await ctx.config();
6348
6590
  const before = await core.loadTokenSet(new GitRefSource(root, base), config);
6349
6591
  const after = await ctx.tokens();
@@ -6352,11 +6594,11 @@ async function diff(a, root) {
6352
6594
  const delta2 = pairs2.length ? core.contrastDelta(core.runContrast(before, pairs2, config.contrast?.modes), core.runContrast(after, pairs2, config.contrast?.modes)) : [];
6353
6595
  const tier = core.classify(changes, [], config);
6354
6596
  const imp = core.impact(before, after, changes, 30);
6355
- if (has6(a, "json")) {
6597
+ if (has7(a, "json")) {
6356
6598
  print(JSON.stringify({ base, changes, contrast: delta2, tier, impact: imp }, null, 2));
6357
6599
  return 0;
6358
6600
  }
6359
- if (has6(a, "md")) {
6601
+ if (has7(a, "md")) {
6360
6602
  print(`## Token changes since \`${base}\`
6361
6603
 
6362
6604
  ${core.tokenTable(changes)}
@@ -6391,26 +6633,27 @@ ${imp.total} other token(s) change value through aliases:`);
6391
6633
  return delta2.some((d) => d.passBefore && !d.passAfter) ? 1 : 0;
6392
6634
  }
6393
6635
  async function propose(a, root) {
6394
- const title = flag4(a, "title");
6636
+ const title = flag5(a, "title");
6395
6637
  if (!title) throw new UsageError('bridge propose --title "Darken muted text" --set color.text.muted={palette.neutral.700} --mode theme=light');
6396
6638
  const edits = [];
6397
- const file = flag4(a, "file");
6398
- const mode2 = modeArg(flag4(a, "mode"));
6639
+ const file = flag5(a, "file");
6640
+ const mode2 = modeArg(flag5(a, "mode"));
6399
6641
  for (const s of a.flags.set ?? []) {
6400
6642
  const i = s.indexOf("=");
6401
6643
  if (i < 0) throw new UsageError(`--set needs path=value, got "${s}"`);
6402
6644
  edits.push({ op: "set", path: s.slice(0, i), value: s.slice(i + 1), ...file ? { file } : {}, ...mode2 ? { mode: mode2 } : {} });
6403
6645
  }
6404
- const editsFile = flag4(a, "edits");
6646
+ const editsFile = flag5(a, "edits");
6405
6647
  if (editsFile) edits.push(...JSON.parse(await readFile7(resolve5(editsFile), "utf8")));
6406
6648
  if (!edits.length) throw new UsageError("Give at least one --set path=value or --edits file.json");
6407
- const pr = flag4(a, "pr");
6408
- const token = pr ? process.env.BRIDGE_GITHUB_TOKEN || process.env.GITHUB_TOKEN || defaultIO().ghToken() : void 0;
6409
- const ctx = await BridgeContext7.create({ root, ...token ? { token } : {} });
6410
- const summary = flag4(a, "summary");
6411
- const branch = flag4(a, "branch");
6412
- const jira = flag4(a, "jira");
6413
- const product = flag4(a, "product");
6649
+ const pr = flag5(a, "pr");
6650
+ const changes = changesFlag(a);
6651
+ const token = pr || changes !== "direct" ? githubToken() : void 0;
6652
+ const ctx = await BridgeContext8.create({ root, ...token ? { token } : {} });
6653
+ const summary = flag5(a, "summary");
6654
+ const branch = flag5(a, "branch");
6655
+ const jira = flag5(a, "jira");
6656
+ const product = flag5(a, "product");
6414
6657
  const r = await ops.proposeTokenChange(ctx, {
6415
6658
  title,
6416
6659
  edits,
@@ -6419,34 +6662,36 @@ async function propose(a, root) {
6419
6662
  ...pr ? { pr } : {},
6420
6663
  ...jira ? { jira } : {},
6421
6664
  ...product ? { product } : {},
6422
- dryRun: has6(a, "dry-run")
6665
+ ...changes ? { changes } : {},
6666
+ source: "cli",
6667
+ dryRun: has7(a, "dry-run")
6423
6668
  });
6424
- if (has6(a, "json")) print(JSON.stringify(r, null, 2));
6669
+ if (has7(a, "json")) print(JSON.stringify(r, null, 2));
6425
6670
  else {
6426
6671
  print(`status: ${r.status}${r.why ? ` (${r.why})` : ""}`);
6427
6672
  if (r.tier) print(`tier ${r.tier}, ${r.bump}`);
6428
6673
  for (const c of r.changes ?? []) print(` ${c.kind} ${c.path}: ${c.before ?? ""} -> ${c.after ?? ""}`);
6429
- if (r.branch) print(`branch: ${r.branch}`);
6430
- if (r.next) print(String(r.next));
6431
- if (r.hint) print(String(r.hint));
6674
+ printSent(r);
6432
6675
  if (r.status === "dry-run") print(`
6433
- ${r.prBody}`);
6676
+ ${r.suggestion?.body ?? r.prBody}`);
6434
6677
  }
6435
6678
  return r.status === "blocked" ? 1 : 0;
6436
6679
  }
6437
6680
  async function brandCmd(a, root) {
6438
6681
  const sub = a._[1];
6439
- const ctx = await BridgeContext7.create({ root });
6682
+ const changes = changesFlag(a);
6683
+ const token = sub === "create" && changes !== "direct" ? githubToken() : void 0;
6684
+ const ctx = await BridgeContext8.create({ root, ...token ? { token } : {} });
6440
6685
  if (sub === "list") {
6441
6686
  const r2 = await brand.listBrands(ctx);
6442
- if (has6(a, "json")) print(JSON.stringify(r2.brands, null, 2));
6687
+ if (has7(a, "json")) print(JSON.stringify(r2.brands, null, 2));
6443
6688
  else for (const b of r2.brands) print(`${b.default ? "*" : " "} ${b.slug.padEnd(14)} ${b.name.padEnd(18)} ${b.primary ?? ""}${b.overrides.length ? ` overrides: ${b.overrides.join(", ")}` : ""}`);
6444
6689
  return 0;
6445
6690
  }
6446
6691
  if (sub !== "create") throw new UsageError('bridge brand list | bridge brand create <slug> --from bridge --primary "#1F5F3A" --neutral "#2A2F2C"');
6447
6692
  const slug = a._[2];
6448
6693
  if (!slug) throw new UsageError('bridge brand create <slug> --from bridge --primary "#1F5F3A" --neutral "#2A2F2C"');
6449
- const opt = (k) => flag4(a, k);
6694
+ const opt = (k) => flag5(a, k);
6450
6695
  const fonts = { ...opt("heading") ? { heading: opt("heading") } : {}, ...opt("text") ? { text: opt("text") } : {} };
6451
6696
  const r = await brand.proposeBrand(ctx, {
6452
6697
  slug,
@@ -6459,9 +6704,11 @@ async function brandCmd(a, root) {
6459
6704
  ...opt("radius") ? { radius: opt("radius") } : {},
6460
6705
  ...Object.keys(fonts).length ? { fonts } : {},
6461
6706
  ...opt("notes") ? { notes: opt("notes") } : {},
6462
- dryRun: has6(a, "dry-run")
6707
+ ...changes ? { changes } : {},
6708
+ source: "cli",
6709
+ dryRun: has7(a, "dry-run")
6463
6710
  });
6464
- if (has6(a, "json")) {
6711
+ if (has7(a, "json")) {
6465
6712
  const { fileContents: _f, ...rest } = r;
6466
6713
  print(JSON.stringify(rest, null, 2));
6467
6714
  return r.status === "blocked" ? 1 : 0;
@@ -6476,13 +6723,11 @@ async function brandCmd(a, root) {
6476
6723
  for (const i of r.issues) print(` ${i.level}: ${i.message}`);
6477
6724
  print("files:");
6478
6725
  for (const f of r.files) print(` ${f.action} ${f.path}`);
6479
- if (r.branch) print(`branch: ${r.branch}`);
6480
- if (r.next) print(String(r.next));
6481
- if (r.hint) print(String(r.hint));
6726
+ printSent(r);
6482
6727
  return r.status === "blocked" ? 1 : 0;
6483
6728
  }
6484
6729
  async function figmaReferences(a, root) {
6485
- let sha = flag4(a, "sha");
6730
+ let sha = flag5(a, "sha");
6486
6731
  if (!sha) {
6487
6732
  try {
6488
6733
  sha = execFileSync2("git", ["rev-parse", "HEAD"], { cwd: root, encoding: "utf8" }).trim();
@@ -6490,33 +6735,33 @@ async function figmaReferences(a, root) {
6490
6735
  sha = "unknown";
6491
6736
  }
6492
6737
  }
6493
- const only = (flag4(a, "only") ?? "").split(",").filter(Boolean);
6738
+ const only = (flag5(a, "only") ?? "").split(",").filter(Boolean);
6494
6739
  const r = await captureFigmaReferences({
6495
- storybook: resolve5(root, flag4(a, "storybook") ?? "storybook-static"),
6496
- specs: resolve5(root, flag4(a, "specs") ?? "packages/react/component-specs.json"),
6497
- out: resolve5(root, flag4(a, "out") ?? "figma-references"),
6740
+ storybook: resolve5(root, flag5(a, "storybook") ?? "storybook-static"),
6741
+ specs: resolve5(root, flag5(a, "specs") ?? "packages/react/component-specs.json"),
6742
+ out: resolve5(root, flag5(a, "out") ?? "figma-references"),
6498
6743
  sha,
6499
6744
  ...only.length ? { only } : {},
6500
- log: has6(a, "json") ? void 0 : (line) => print(line)
6745
+ log: has7(a, "json") ? void 0 : (line) => print(line)
6501
6746
  });
6502
- if (has6(a, "json")) print(JSON.stringify({ manifest: r.manifestPath, captured: r.captured, skipped: r.skipped }, null, 2));
6747
+ if (has7(a, "json")) print(JSON.stringify({ manifest: r.manifestPath, captured: r.captured, skipped: r.skipped }, null, 2));
6503
6748
  return 0;
6504
6749
  }
6505
6750
  async function impact(a, root) {
6506
- const only = (flag4(a, "only") ?? "").split(",").filter(Boolean);
6751
+ const only = (flag5(a, "only") ?? "").split(",").filter(Boolean);
6507
6752
  for (const x of only) if (x !== "stories" && x !== "app") throw new UsageError(`--only takes stories or app, got "${x}"`);
6508
- const num2 = (k) => flag4(a, k) !== void 0 ? Number(flag4(a, k)) : void 0;
6753
+ const num2 = (k) => flag5(a, k) !== void 0 ? Number(flag5(a, k)) : void 0;
6509
6754
  const threshold = num2("threshold");
6510
6755
  if (threshold !== void 0 && !(threshold >= 0 && threshold <= 1)) throw new UsageError("--threshold is between 0 and 1 (pixelmatch color distance)");
6511
- const imageBase = flag4(a, "image-base");
6512
- const artifactUrl = flag4(a, "artifact-url");
6513
- const out = flag4(a, "out");
6514
- const cacheDir = flag4(a, "cache");
6756
+ const imageBase = flag5(a, "image-base");
6757
+ const artifactUrl = flag5(a, "artifact-url");
6758
+ const out = flag5(a, "out");
6759
+ const cacheDir = flag5(a, "cache");
6515
6760
  const maxStories = num2("max-stories");
6516
6761
  const r = await runImpact({
6517
6762
  root,
6518
- base: flag4(a, "base") ?? "main",
6519
- head: flag4(a, "head") ?? "HEAD",
6763
+ base: flag5(a, "base") ?? "main",
6764
+ head: flag5(a, "head") ?? "HEAD",
6520
6765
  ...out ? { out: resolve5(out) } : {},
6521
6766
  ...only.length ? { only } : {},
6522
6767
  ...threshold !== void 0 ? { threshold } : {},
@@ -6524,15 +6769,15 @@ async function impact(a, root) {
6524
6769
  ...maxStories ? { maxStoriesPerComponent: maxStories } : {},
6525
6770
  ...imageBase !== void 0 ? { imageBase } : {},
6526
6771
  ...artifactUrl ? { artifactUrl } : {},
6527
- plan: has6(a, "plan"),
6528
- keepUnchanged: has6(a, "keep-unchanged")
6772
+ plan: has7(a, "plan"),
6773
+ keepUnchanged: has7(a, "keep-unchanged")
6529
6774
  });
6530
- if (has6(a, "json")) {
6775
+ if (has7(a, "json")) {
6531
6776
  print(JSON.stringify({ summary: r.summary, manifest: r.manifestPath, comment: r.commentPath ?? null, ...r.manifest.summary, selection: r.manifest.selection }, null, 2));
6532
6777
  return 0;
6533
6778
  }
6534
6779
  const sel = r.manifest.selection;
6535
- if (has6(a, "plan")) {
6780
+ if (has7(a, "plan")) {
6536
6781
  print(`Plan ${r.manifest.base.ref} (${r.manifest.base.sha.slice(0, 7)}) -> ${r.manifest.head.ref} (${r.manifest.head.sha.slice(0, 7)})`);
6537
6782
  print(` tokens changing value: ${sel.tokens.length}${sel.tokens.length ? ` (${sel.tokens.filter((t) => t.kind === "direct").map((t) => t.path).slice(0, 6).join(", ")})` : ""}`);
6538
6783
  print(` components: ${sel.components.map((c) => c.id).join(", ") || "none"}`);
@@ -6548,12 +6793,12 @@ async function impact(a, root) {
6548
6793
  }
6549
6794
  var day = (iso) => iso.slice(0, 10);
6550
6795
  async function historyCmd(a, root) {
6551
- const ctx = await BridgeContext7.create({ root });
6796
+ const ctx = await BridgeContext8.create({ root });
6552
6797
  const token = a._[1];
6553
- const limit = Number(flag4(a, "limit") ?? 20);
6798
+ const limit = Number(flag5(a, "limit") ?? 20);
6554
6799
  if (token) {
6555
6800
  const r2 = await hist.getTokenHistory(ctx, { path: token, limit });
6556
- if (has6(a, "json")) return print(JSON.stringify(r2, null, 2)), 0;
6801
+ if (has7(a, "json")) return print(JSON.stringify(r2, null, 2)), 0;
6557
6802
  if (!r2.total) return print(`No recorded change of ${r2.path} in ${r2.source}.`), 0;
6558
6803
  print(`${r2.path}: ${r2.total} change(s) (${r2.source})
6559
6804
  `);
@@ -6564,9 +6809,9 @@ async function historyCmd(a, root) {
6564
6809
  }
6565
6810
  return 0;
6566
6811
  }
6567
- const tier = flag4(a, "tier");
6568
- const r = await hist.getHistory(ctx, { limit, ...flag4(a, "author") ? { author: flag4(a, "author") } : {}, ...tier ? { tier: Number(tier) } : {}, ...flag4(a, "version") ? { version: flag4(a, "version") } : {}, ...has6(a, "breaking") ? { breaking: true } : {} });
6569
- if (has6(a, "json")) return print(JSON.stringify(r, null, 2)), 0;
6812
+ const tier = flag5(a, "tier");
6813
+ const r = await hist.getHistory(ctx, { limit, ...flag5(a, "author") ? { author: flag5(a, "author") } : {}, ...tier ? { tier: Number(tier) } : {}, ...flag5(a, "version") ? { version: flag5(a, "version") } : {}, ...has7(a, "breaking") ? { breaking: true } : {} });
6814
+ if (has7(a, "json")) return print(JSON.stringify(r, null, 2)), 0;
6570
6815
  print(`${r.source}${r.currentVersion ? `, package version ${r.currentVersion}` : ""}`);
6571
6816
  if (!r.total) return print(r.note ?? "No token change matches."), 0;
6572
6817
  for (const v of r.versions) print(` ${v.version.padEnd(11)} ${day(v.date)} ${v.entries} change(s), ${v.tokenChanges} token edit(s)${v.breaking ? ", breaking" : ""}`);
@@ -6584,10 +6829,12 @@ ${r.truncated}`);
6584
6829
  async function revertCmd(a, root) {
6585
6830
  const target = a._[1];
6586
6831
  if (!target) throw new UsageError("bridge revert <pr|commit|id> [--dry-run] (ids from `bridge history`)");
6587
- const ctx = await BridgeContext7.create({ root });
6832
+ const changes = changesFlag(a);
6833
+ const token = changes !== "direct" ? githubToken() : void 0;
6834
+ const ctx = await BridgeContext8.create({ root, ...token ? { token } : {} });
6588
6835
  const resolutions = Object.fromEntries((a.flags["use-before"] ?? []).map((k) => [k, "use-before"]));
6589
- const r = await hist.proposeRevert(ctx, { target, resolutions, restoreConflicts: has6(a, "restore-conflicts"), dryRun: has6(a, "dry-run") });
6590
- if (has6(a, "json")) {
6836
+ const r = await hist.proposeRevert(ctx, { target, resolutions, restoreConflicts: has7(a, "restore-conflicts"), dryRun: has7(a, "dry-run"), ...changes ? { changes } : {}, source: "cli" });
6837
+ if (has7(a, "json")) {
6591
6838
  print(JSON.stringify(r, null, 2));
6592
6839
  return r.status === "blocked" ? 1 : 0;
6593
6840
  }
@@ -6602,35 +6849,34 @@ async function revertCmd(a, root) {
6602
6849
  }
6603
6850
  for (const s of r.skipped ?? []) print(` skipped ${s}`);
6604
6851
  if (r.contrast?.moved) print(`contrast: ${r.contrast.moved} pair(s) move, ${r.contrast.newFailures.length} new failure(s)`);
6605
- if (r.branch) print(`branch: ${r.branch}`);
6606
- if (r.next) print(String(r.next));
6852
+ printSent(r);
6607
6853
  if (r.status === "dry-run") print(`
6608
- ${r.prBody}`);
6854
+ ${r.suggestion?.body ?? r.prBody}`);
6609
6855
  return r.status === "blocked" ? 1 : 0;
6610
6856
  }
6611
6857
  async function audit(a, root) {
6612
6858
  const target = a._[1];
6613
6859
  if (!target) throw new UsageError("bridge audit <path> (a product folder or file that uses the design system)");
6614
6860
  if (!existsSync6(target)) throw new UsageError(`No such file or folder: ${target}`);
6615
- const dsRoot = flag4(a, "ds") ? resolve5(flag4(a, "ds")) : existsSync6(join6(root, CONFIG_FILE2)) ? root : findDesignSystemRoot(root);
6861
+ const dsRoot = flag5(a, "ds") ? resolve5(flag5(a, "ds")) : existsSync6(join6(root, CONFIG_FILE2)) ? root : findDesignSystemRoot(root);
6616
6862
  if (!dsRoot) throw new UsageError(`No ${CONFIG_FILE2} found: run bridge audit from the design system repo or pass --ds <dir>.`);
6617
6863
  const ds = loadDesignSystem(dsRoot);
6618
- if (has6(a, "fix")) {
6619
- const write = has6(a, "write");
6864
+ if (has7(a, "fix")) {
6865
+ const write = has7(a, "write");
6620
6866
  const changes = fixCss(target, ds.index, write);
6621
6867
  const n = changes.reduce((acc, c) => acc + c.edits.length, 0);
6622
6868
  for (const c of changes) for (const e of c.edits) print(`${c.file}:${e.line}:${e.column} ${e.from} -> ${e.to}`);
6623
6869
  print(n ? `${write ? "Replaced" : "Would replace"} ${n} value(s) in ${changes.length} file(s) with exact token matches.${write ? "" : " Run again with --write to apply."}` : "Nothing to fix: no CSS value equals a token exactly.");
6624
6870
  return 0;
6625
6871
  }
6626
- const baselinePath = flag4(a, "baseline");
6872
+ const baselinePath = flag5(a, "baseline");
6627
6873
  let baseline;
6628
6874
  if (baselinePath) {
6629
6875
  if (!existsSync6(baselinePath)) throw new UsageError(`Baseline not found: ${baselinePath}`);
6630
6876
  baseline = JSON.parse(await readFile7(baselinePath, "utf8"));
6631
6877
  }
6632
- const label = flag4(a, "label");
6633
- const allowlistPath = flag4(a, "allowlist");
6878
+ const label = flag5(a, "label");
6879
+ const allowlistPath = flag5(a, "allowlist");
6634
6880
  if (allowlistPath && !existsSync6(allowlistPath)) throw new UsageError(`Allowlist not found: ${allowlistPath}`);
6635
6881
  let allowlist;
6636
6882
  try {
@@ -6640,8 +6886,8 @@ async function audit(a, root) {
6640
6886
  }
6641
6887
  const report = runAudit(target, { ds: dsRoot, version: VERSION, ...label ? { label } : {}, ...baseline ? { baseline } : {}, ...allowlist ? { allowlist } : {} });
6642
6888
  const md = auditMarkdown(report);
6643
- const jsonOut = flag4(a, "json");
6644
- const mdOut = flag4(a, "md");
6889
+ const jsonOut = flag5(a, "json");
6890
+ const mdOut = flag5(a, "md");
6645
6891
  if (jsonOut && jsonOut !== "true") await writeFile5(jsonOut, `${JSON.stringify(report, null, 2)}
6646
6892
  `);
6647
6893
  if (mdOut && mdOut !== "true") await writeFile5(mdOut, `${md}
@@ -6681,7 +6927,7 @@ async function audit(a, root) {
6681
6927
  for (const f of report.files) for (const e of f.ignoreErrors ?? []) process.stderr.write(`${report.target.path}/${f.path}:${e.line}: ${e.message}
6682
6928
  `);
6683
6929
  let code = 0;
6684
- const failUnder = flag4(a, "fail-under");
6930
+ const failUnder = flag5(a, "fail-under");
6685
6931
  if (failUnder !== void 0) {
6686
6932
  const min = Number(failUnder);
6687
6933
  if (!Number.isFinite(min)) throw new UsageError("--fail-under needs a number, e.g. --fail-under 80");
@@ -6692,7 +6938,7 @@ async function audit(a, root) {
6692
6938
  code = 1;
6693
6939
  }
6694
6940
  }
6695
- if (has6(a, "no-regress") && report.baseline) {
6941
+ if (has7(a, "no-regress") && report.baseline) {
6696
6942
  const b = report.baseline;
6697
6943
  if ((b.tokenAdoption.delta ?? 0) < 0 || (b.componentAdoption.delta ?? 0) < 0 || b.hardcoded.delta > 0) {
6698
6944
  process.stderr.write("bridge audit: adoption regressed since the baseline\n");
@@ -6704,9 +6950,9 @@ async function audit(a, root) {
6704
6950
  async function docsCmd(a, root) {
6705
6951
  const [, sub, name] = a._;
6706
6952
  if (sub !== "draft" || !name) throw new UsageError("Usage: bridge docs draft <Component> [--json]");
6707
- const ctx = await BridgeContext7.create({ root });
6953
+ const ctx = await BridgeContext8.create({ root });
6708
6954
  const d = await ops.draftDocsOp(ctx, { name });
6709
- if (has6(a, "json")) {
6955
+ if (has7(a, "json")) {
6710
6956
  print(JSON.stringify({ component: d.component, path: d.path, exists: d.exists, prefill: d.prefill, prompt: d.prompt }, null, 2));
6711
6957
  return 0;
6712
6958
  }
@@ -6737,17 +6983,20 @@ async function main() {
6737
6983
  const argv = process.argv.slice(2);
6738
6984
  const a = parse(argv);
6739
6985
  const cmd = a._[0];
6740
- const root = resolve5(flag4(a, "root") ?? process.cwd());
6986
+ const root = resolve5(flag5(a, "root") ?? process.cwd());
6741
6987
  if (cmd === "request") return runRequest(a, root);
6742
6988
  if (cmd === "explore") return runExplore(a, root);
6743
6989
  if (cmd === "branch") return runBranch(a, root);
6744
6990
  if (cmd === "pieces") return runPieces(a, root);
6745
6991
  if (cmd === "figma") return runFigma(a, root);
6992
+ if (cmd === "suggestions" || cmd === "suggest") return runSuggestions(a, root);
6993
+ if (cmd === "apply") return runApply(a, root);
6994
+ if (cmd === "review") return runReview(a, root);
6746
6995
  if (cmd === "products" || cmd === "settings" || cmd === "coverage") return runStudioRead(cmd, a, root);
6747
6996
  if (cmd === "docs" && a._[1] === "save") return runDocsSave(a, root);
6748
- if (!cmd || has6(a, "help") || cmd === "help") {
6997
+ if (!cmd || has7(a, "help") || cmd === "help") {
6749
6998
  print(HELP);
6750
- return cmd || has6(a, "help") ? 0 : 2;
6999
+ return cmd || has7(a, "help") ? 0 : 2;
6751
7000
  }
6752
7001
  if (cmd === "--version" || cmd === "version") return print(VERSION), 0;
6753
7002
  switch (cmd) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge-ds/cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "description": "bridge CLI: set up Bridge in a design system repo, check tokens in CI, search and diff tokens, propose changes, start the MCP server.",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  "build:package": "node ../../scripts/build-packages.mjs cli"
44
44
  },
45
45
  "dependencies": {
46
- "@bridge-ds/mcp": "^0.6.0",
46
+ "@bridge-ds/mcp": "^0.7.0",
47
47
  "@bridge-ds/visual": "^0.3.4",
48
48
  "typescript": "5.9.3"
49
49
  },