@bridge-ds/mcp 0.10.0 → 0.11.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.
@@ -119,7 +119,7 @@ var STATE_OF = {
119
119
  deployed: "ready",
120
120
  ready: "ready",
121
121
  ignored: "ready",
122
- // Vercel skipped the build (nothing changed for this app): the branch alias serves the last one.
122
+ // Vercel skipped the build: nothing to wait for. BranchPreview.skipped says the branch has no build of its own.
123
123
  pending: "building",
124
124
  queued: "building",
125
125
  in_progress: "building",
@@ -131,13 +131,15 @@ var STATE_OF = {
131
131
  canceled: "failed"
132
132
  };
133
133
  var stateOf = (s) => STATE_OF[(s ?? "").toLowerCase()] ?? "unknown";
134
+ var IGNORED_BUILD = /ignored build step/i;
134
135
  var isInspectorUrl = (u) => /^https:\/\/(?:www\.)?vercel\.com\//i.test(u);
135
136
  function resolveBranchPreviews(apps, ctx, sources = {}) {
136
137
  const seen = /* @__PURE__ */ new Map();
137
138
  const at = (app) => seen.get(app) ?? (seen.set(app, {}), seen.get(app));
138
- const offer = (app, url, urlSource, state, stateRank) => {
139
+ const offer = (app, url, urlSource, state, stateRank, skipped) => {
139
140
  if (!app) return;
140
141
  const s = at(app);
142
+ if (skipped !== void 0 && (s.skipRank === void 0 || stateRank < s.skipRank)) Object.assign(s, { skipped, skipRank: stateRank });
141
143
  if (url && !s.url) Object.assign(s, { url, urlSource });
142
144
  if (state !== "unknown" && (s.stateRank === void 0 || stateRank < s.stateRank)) Object.assign(s, { state, stateRank });
143
145
  };
@@ -148,7 +150,7 @@ function resolveBranchPreviews(apps, ctx, sources = {}) {
148
150
  const project = projectOfLabel(st.context);
149
151
  if (!project) continue;
150
152
  const url = httpsUrl(st.target_url);
151
- offer(appForProject(project, apps), url && !isInspectorUrl(url) ? url : null, "status", stateOf(st.state), 0);
153
+ offer(appForProject(project, apps), url && !isInspectorUrl(url) ? url : null, "status", stateOf(st.state), 0, IGNORED_BUILD.test(st.description ?? ""));
152
154
  }
153
155
  for (const d of sources.deployments ?? []) {
154
156
  const project = projectOfLabel(d.environment);
@@ -160,17 +162,18 @@ function resolveBranchPreviews(apps, ctx, sources = {}) {
160
162
  const state = stateOf(d.state);
161
163
  if (state !== "unknown" && (s.stateRank === void 0 || 1 < s.stateRank)) Object.assign(s, { state, stateRank: 1 });
162
164
  }
163
- for (const p of parseVercelComment(findVercelComment(sources.comments ?? [])?.body) ?? []) offer(appForProject(p.name, apps), p.previewUrl, "vercel-comment", stateOf(p.status), 2);
165
+ for (const p of parseVercelComment(findVercelComment(sources.comments ?? [])?.body) ?? []) offer(appForProject(p.name, apps), p.previewUrl, "vercel-comment", stateOf(p.status), 2, p.status ? p.status.toUpperCase() === "IGNORED" : void 0);
164
166
  const out = [];
165
167
  for (const app of Object.keys(PREVIEW_APP_LABELS)) {
166
168
  if (!apps[app]) continue;
167
169
  const s = seen.get(app) ?? {};
168
170
  const url = s.url ?? previewUrl(apps[app], ctx);
169
171
  const source = s.url ? s.urlSource : url ? "template" : null;
170
- out.push({ app, label: PREVIEW_APP_LABELS[app], url, state: s.state ?? "unknown", source });
172
+ out.push({ app, label: PREVIEW_APP_LABELS[app], url, state: s.state ?? "unknown", source, ...s.skipped ? { skipped: true } : {} });
171
173
  }
172
174
  return out;
173
175
  }
176
+ var previewLinksOf = (previews) => previews.filter((p) => !!p.url && !p.skipped).map((p) => ({ app: p.app, label: p.label, url: p.url }));
174
177
  var previewsSettled = (previews) => previews.every((p) => p.state === "failed" || !!p.url && p.state === "ready");
175
178
 
176
179
  // ../core/src/teams.ts
@@ -533,6 +536,27 @@ function productForPlace(products, place) {
533
536
  }
534
537
  return { product: defaultProduct(products), how: "default" };
535
538
  }
539
+ function productRepoOf(p, designSystemRepo) {
540
+ const repo = p?.repo?.trim();
541
+ if (!repo || !REPO.test(repo)) return null;
542
+ return repo.toLowerCase() === (designSystemRepo ?? "").trim().toLowerCase() ? null : repo;
543
+ }
544
+ function productRepos(products, designSystemRepo) {
545
+ const seen = /* @__PURE__ */ new Set();
546
+ const out = [];
547
+ for (const p of products) {
548
+ const repo = productRepoOf(p, designSystemRepo);
549
+ if (!repo || seen.has(repo.toLowerCase())) continue;
550
+ seen.add(repo.toLowerCase());
551
+ out.push({ product: p, repo });
552
+ }
553
+ return out;
554
+ }
555
+ function productOfRepo(products, repo, designSystemRepo) {
556
+ const r = (repo ?? "").trim().toLowerCase();
557
+ if (!r) return void 0;
558
+ return productRepos(products, designSystemRepo).find((x) => x.repo.toLowerCase() === r)?.product;
559
+ }
536
560
  var KEY = /^[a-z0-9][a-z0-9-]*$/;
537
561
  var REPO = /^[\w.-]+\/[\w.-]+$/;
538
562
  var FIELDS = ["key", "name", "repo", "path", "preview", "framework", "default"];
@@ -1832,6 +1856,23 @@ function hashSpec(spec) {
1832
1856
  return specHash(JSON.stringify(rest));
1833
1857
  }
1834
1858
  var variantKeyOf = (props) => Object.keys(props).sort().map((k) => `${k}=${props[k]}`).join(", ") || "Default";
1859
+ function matchVariant(spec, props) {
1860
+ if (!spec) return void 0;
1861
+ const key = variantKeyOf(props);
1862
+ const exact = spec.variants.find((v) => variantKeyOf(v.props) === key);
1863
+ if (exact) return exact;
1864
+ const asked = Object.entries(props);
1865
+ const fits = spec.variants.filter((v) => Object.keys(v.props).length > asked.length && asked.every(([k, val]) => v.props[k] === val));
1866
+ if (fits.length <= 1) return fits[0];
1867
+ const atDefault = (name, value) => {
1868
+ const axis = spec.axes?.find((a) => a.name === name);
1869
+ if (axis) return value === axis.default;
1870
+ const v = value.toLowerCase();
1871
+ return v === "false" || v === "default";
1872
+ };
1873
+ const best = fits.filter((v) => Object.entries(v.props).every(([k, val]) => k in props || atDefault(k, val)));
1874
+ return best.length === 1 ? best[0] : void 0;
1875
+ }
1835
1876
  function parseComponentSpecs(text) {
1836
1877
  let data;
1837
1878
  try {
@@ -2124,6 +2165,7 @@ export {
2124
2165
  readPreviewComment,
2125
2166
  findPreviewComment,
2126
2167
  resolveBranchPreviews,
2168
+ previewLinksOf,
2127
2169
  previewsSettled,
2128
2170
  expandOwners,
2129
2171
  entryLabel,
@@ -2145,6 +2187,9 @@ export {
2145
2187
  findProduct,
2146
2188
  productOfBranch,
2147
2189
  productForPlace,
2190
+ productRepoOf,
2191
+ productRepos,
2192
+ productOfRepo,
2148
2193
  CONFIG_FILE,
2149
2194
  DEFAULT_OVERRIDE,
2150
2195
  DEFAULT_TOKEN_PATHS,
@@ -2190,6 +2235,7 @@ export {
2190
2235
  coverageSummary,
2191
2236
  hashSpec,
2192
2237
  variantKeyOf,
2238
+ matchVariant,
2193
2239
  parseComponentSpecs,
2194
2240
  figmaCell,
2195
2241
  FIGMA_REFERENCES_BRANCH,
package/dist/context.d.ts CHANGED
@@ -23,6 +23,13 @@ export interface ContextOptions {
23
23
  surface?: 'mcp' | 'cli';
24
24
  /** How a person adds a token where Bridge runs, for the rate-limit message. Default: the MCP server's environment. */
25
25
  tokenHint?: string;
26
+ /**
27
+ * Remote mode run inside a connected product repository (`.bridge/product.json`, product-link.ts): that checkout,
28
+ * which continuing one of its explorations switches to the branch when safe.
29
+ */
30
+ workTree?: string;
31
+ /** The product key of that repository: new work and a bare reference (#12) default to it. */
32
+ product?: string;
26
33
  }
27
34
  /** Whether a request only reads: GET and HEAD, and GraphQL queries (POST /graphql without a mutation). */
28
35
  export declare function isReadRequest(url: string, init?: {
@@ -52,6 +59,18 @@ export declare class BridgeContext {
52
59
  * branch are refused, new branches need the agent prefix. Local mode uses config.repo or the origin remote.
53
60
  */
54
61
  github(): Promise<GitHubClient | null>;
62
+ /**
63
+ * A client for another repository (a product's own one) with the same token, fetch and hosts. Its default branch
64
+ * and the protected ones are refused, new branches need `branchPrefix`.
65
+ */
66
+ githubFor(repo: string, rules: {
67
+ protectedBranches: string[];
68
+ branchPrefix: string;
69
+ }): GitHubClient;
70
+ /** The local checkout Bridge may switch branches in: the repo root in local mode, the connected product checkout in remote mode. */
71
+ get checkout(): string | undefined;
72
+ /** The product of the connected product repository Bridge runs in (`.bridge/product.json`), if any. */
73
+ get product(): string | undefined;
55
74
  get canWriteRemote(): boolean;
56
75
  /** Who reads the messages: 'mcp' (tool names and arguments, the default) or 'cli' (commands and flags). */
57
76
  get surface(): 'mcp' | 'cli';
@@ -9,7 +9,8 @@ export declare const settingsOf: (config: BridgeConfig) => {
9
9
  export declare function toExplorationBranch(ref: string): string;
10
10
  export interface StartExplorationInput {
11
11
  name: string;
12
- purpose: string;
12
+ /** What the designer wants to learn. Optional: nobody is asked for a brief; Claude passes their first sentence when it has one. */
13
+ purpose?: string | undefined;
13
14
  useCase?: string | undefined;
14
15
  experimental?: string[] | undefined;
15
16
  author?: string | undefined;
@@ -18,16 +19,61 @@ export interface StartExplorationInput {
18
19
  agent?: string | undefined;
19
20
  /** The product it is tried in (key or name, bridge.config.json "products"). Default: the product of the current folder or repo. */
20
21
  product?: string | undefined;
22
+ /**
23
+ * Where the branch is created. `product` (the default): in the product's own repository when the team connected one
24
+ * (bridge.config.json products[].repo), else in the design system repository. `library`: always in the design system
25
+ * repository, the fallback when the person chooses it because Bridge cannot reach the product repository.
26
+ */
27
+ where?: 'product' | 'library' | undefined;
21
28
  dryRun?: boolean | undefined;
22
29
  }
30
+ /** What Claude says when Bridge cannot reach a product's own repository: the admin action first, the fallback on request. */
31
+ export declare function productRepoBlocked(ctx: BridgeContext, product: string, repo: string, reason: 'not-connected' | 'read-only' | 'no-token'): string;
23
32
  /**
24
33
  * bridge_start_exploration / `bridge explore start`. With a GitHub token: the branch on GitHub from the default branch
25
34
  * and a draft pull request labeled exploration. Without one, in a local git repo: a local branch with the note,
26
35
  * nothing pushed, and the commands to push it and open the draft pull request.
27
36
  */
28
37
  export declare function startExploration(ctx: BridgeContext, a: StartExplorationInput): Promise<{
38
+ blocked?: string | undefined;
29
39
  branch: string;
30
40
  product: string;
41
+ repo: string;
42
+ inProductRepo: boolean;
43
+ slug: string;
44
+ base: string;
45
+ title: string;
46
+ label: string;
47
+ note: {
48
+ path: string;
49
+ content: string;
50
+ };
51
+ prBody: string;
52
+ status: "dry-run";
53
+ } | {
54
+ pr: number;
55
+ url: string;
56
+ commit: string;
57
+ next: string;
58
+ branch: string;
59
+ product: string;
60
+ repo: string;
61
+ inProductRepo: boolean;
62
+ slug: string;
63
+ base: string;
64
+ title: string;
65
+ label: string;
66
+ note: {
67
+ path: string;
68
+ content: string;
69
+ };
70
+ prBody: string;
71
+ status: "started";
72
+ } | {
73
+ branch: string;
74
+ product: string;
75
+ repo: string | null;
76
+ inProductRepo: boolean;
31
77
  slug: string;
32
78
  base: string;
33
79
  title: string;
@@ -55,6 +101,8 @@ export declare function startExploration(ctx: BridgeContext, a: StartExploration
55
101
  next: string;
56
102
  branch: string;
57
103
  product: string;
104
+ repo: string | null;
105
+ inProductRepo: boolean;
58
106
  slug: string;
59
107
  base: string;
60
108
  title: string;
@@ -70,6 +118,8 @@ export declare function startExploration(ctx: BridgeContext, a: StartExploration
70
118
  next: string;
71
119
  branch: string;
72
120
  product: string;
121
+ repo: string | null;
122
+ inProductRepo: boolean;
73
123
  slug: string;
74
124
  base: string;
75
125
  title: string;
@@ -93,6 +143,8 @@ export declare function installOf(t: ExplorationTryIt): {
93
143
  /** bridge_list_explorations / `bridge explore list`. */
94
144
  export declare function listExplorations(ctx: BridgeContext, a?: {
95
145
  state?: 'open' | 'closed' | 'all';
146
+ archived?: boolean | undefined;
147
+ mine?: boolean | undefined;
96
148
  }): Promise<{
97
149
  localBranches?: string[] | undefined;
98
150
  localHint?: string | undefined;
@@ -109,6 +161,7 @@ export declare function listExplorations(ctx: BridgeContext, a?: {
109
161
  url: string;
110
162
  state: string;
111
163
  }[];
164
+ ref: string;
112
165
  number: number;
113
166
  url: string;
114
167
  branch: string;
@@ -117,6 +170,7 @@ export declare function listExplorations(ctx: BridgeContext, a?: {
117
170
  purpose: string;
118
171
  useCase?: string | undefined;
119
172
  status: import("@bridge-ds/core").ExplorationStatus;
173
+ archived: boolean;
120
174
  draft: boolean;
121
175
  author: string;
122
176
  source?: ExplorationSource | undefined;
@@ -128,6 +182,8 @@ export declare function listExplorations(ctx: BridgeContext, a?: {
128
182
  label: string;
129
183
  url: string;
130
184
  }[];
185
+ repo?: string | undefined;
186
+ product?: string | undefined;
131
187
  } | {
132
188
  install: {
133
189
  state: ExplorationTryIt["state"];
@@ -140,6 +196,7 @@ export declare function listExplorations(ctx: BridgeContext, a?: {
140
196
  url: string;
141
197
  state: string;
142
198
  }[];
199
+ ref: string;
143
200
  number: number;
144
201
  url: string;
145
202
  branch: string;
@@ -148,6 +205,7 @@ export declare function listExplorations(ctx: BridgeContext, a?: {
148
205
  purpose: string;
149
206
  useCase?: string | undefined;
150
207
  status: import("@bridge-ds/core").ExplorationStatus;
208
+ archived: boolean;
151
209
  draft: boolean;
152
210
  author: string;
153
211
  source?: ExplorationSource | undefined;
@@ -159,6 +217,8 @@ export declare function listExplorations(ctx: BridgeContext, a?: {
159
217
  label: string;
160
218
  url: string;
161
219
  }[];
220
+ repo?: string | undefined;
221
+ product?: string | undefined;
162
222
  } | {
163
223
  previews: {
164
224
  app: keyof import("@bridge-ds/core").PreviewApps;
@@ -177,6 +237,7 @@ export declare function listExplorations(ctx: BridgeContext, a?: {
177
237
  url: string;
178
238
  state: string;
179
239
  }[];
240
+ ref: string;
180
241
  number: number;
181
242
  url: string;
182
243
  branch: string;
@@ -185,37 +246,137 @@ export declare function listExplorations(ctx: BridgeContext, a?: {
185
246
  purpose: string;
186
247
  useCase?: string | undefined;
187
248
  status: import("@bridge-ds/core").ExplorationStatus;
249
+ archived: boolean;
188
250
  draft: boolean;
189
251
  author: string;
190
252
  source?: ExplorationSource | undefined;
191
253
  agent?: string | undefined;
192
254
  updatedAt: string;
193
255
  headSha: string;
256
+ repo?: string | undefined;
257
+ product?: string | undefined;
194
258
  })[];
195
259
  }>;
196
- /** `bridge explore promote`: ready for review, tier labels, exploration label and note removed, linked requests closed on merge. */
197
- export declare function promoteExploration(ctx: BridgeContext, a: {
260
+ /**
261
+ * bridge_promote_exploration (kept name) / `bridge explore done` (`promote` is an alias): "Done exploring". The pieces
262
+ * named in `pieces` (ids from bridge_missing_pieces) go to the DS lead as requests with the preview link; the
263
+ * exploration label and note go, `ready-for-devs` comes, and developers take the branch from there. Nothing is closed,
264
+ * merged or marked ready for review, so the preview link stays alive. Without `pieces`, the result lists the pieces
265
+ * still unsent so the person can pick.
266
+ */
267
+ export declare function doneExploring(ctx: BridgeContext, a: {
198
268
  ref: string;
269
+ pieces?: string[] | undefined;
199
270
  dryRun?: boolean | undefined;
271
+ source?: ExplorationSource | undefined;
272
+ agent?: string | undefined;
200
273
  }): Promise<{
201
- closes: number[];
202
- number: number;
274
+ notProposed: {
275
+ id: string;
276
+ title: string;
277
+ summary: string;
278
+ }[];
279
+ checked: boolean;
280
+ forDevelopers: {
281
+ take: [string, string];
282
+ note: string;
283
+ };
284
+ warnings: string[];
285
+ next: string;
286
+ unknownPieces?: string[] | undefined;
203
287
  url: string;
204
288
  branch: string;
205
- warnings: string[];
206
- tier: import("@bridge-ds/core").RiskTier;
207
- reasons: string[];
208
- removeLabels: string[];
209
- addLabels: string[];
289
+ exploration: import("@bridge-ds/core").ExplorationStatus;
290
+ labels: {
291
+ add: string[];
292
+ remove: string[];
293
+ } | null;
210
294
  removeFiles: string[];
211
- body: string;
212
- title: string;
213
- markReady: true;
214
- status: "promoted" | "dry-run";
295
+ requests: {
296
+ piece: string;
297
+ title: string;
298
+ number: number;
299
+ url: string;
300
+ }[];
301
+ alreadySent: {
302
+ piece: string;
303
+ number: number;
304
+ }[];
305
+ repo?: string | undefined;
306
+ product?: string | undefined;
307
+ requestsIn?: string | undefined;
308
+ status: "dry-run" | "done-exploring" | "already-done";
309
+ number: number;
310
+ ref: string;
311
+ }>;
312
+ /**
313
+ * bridge_continue_exploration / "Continue Bridge exploration #12" (or shop#12): resolves the exploration, switches the
314
+ * local checkout of its repository to its branch when that is safe, and returns where it stands in plain words (what
315
+ * changed, the last activity) for Claude to say first, with the previews and the missing pieces when recorded.
316
+ * One read of the pull request, its files and its commits.
317
+ */
318
+ export declare function continueExploration(ctx: BridgeContext, a: {
319
+ ref: string;
320
+ checkout?: boolean | undefined;
321
+ }): Promise<{
322
+ checkout: {
323
+ status: "already-on-it" | "switched" | "not-switched";
324
+ note: string;
325
+ };
326
+ continueLines: {
327
+ app: string;
328
+ terminal: string;
329
+ };
330
+ next: string;
331
+ missingPieces?: {
332
+ id: string;
333
+ title: string;
334
+ }[] | undefined;
335
+ ref: string;
336
+ number: number;
337
+ name: string;
338
+ product: string;
339
+ repo: string;
340
+ branch: string;
341
+ url: string;
342
+ status: import("@bridge-ds/core").ExplorationStatus;
343
+ statusLabel: string;
344
+ archived: boolean;
345
+ stage: "exploring" | "not-started" | "handed";
346
+ whereItStands: string;
347
+ activity: {
348
+ who: string;
349
+ what: string;
350
+ when: string;
351
+ }[];
352
+ changedFiles: string[] | null;
353
+ previews: {
354
+ app: keyof import("@bridge-ds/core").PreviewApps;
355
+ label: string;
356
+ url: string;
357
+ }[];
358
+ }>;
359
+ /** @deprecated The old name: "Promote to review" became "Done exploring" (doneExploring). */
360
+ export declare const promoteExploration: typeof doneExploring;
361
+ /** bridge_archive_exploration / `bridge explore archive|unarchive`: the archived label on the still open pull request. */
362
+ export declare function archiveExploration(ctx: BridgeContext, a: {
363
+ ref: string;
364
+ archived?: boolean | undefined;
365
+ }): Promise<{
366
+ next: string;
367
+ repo?: string | undefined;
368
+ ref: string;
369
+ number: number;
370
+ url: string;
371
+ branch: string;
372
+ archived: boolean;
373
+ status: "archived" | "unarchived";
215
374
  }>;
216
375
  export declare function closeExploration(ctx: BridgeContext, a: {
217
376
  ref: string;
218
377
  }): Promise<{
378
+ note: string;
379
+ repo?: string | undefined;
219
380
  number: number;
220
381
  url: string;
221
382
  branch: string;
package/dist/figma.d.ts CHANGED
@@ -84,7 +84,7 @@ export declare function pushFigmaComponentOp(ctx: BridgeContext, a: {
84
84
  fixInFigma?: import("@bridge-ds/core").PushIssue[] | undefined;
85
85
  reasons?: string[] | undefined;
86
86
  edits?: import("@bridge-ds/core").TokenEdit[] | undefined;
87
- status: "opened" | "suggested" | "dry-run" | "not-sent";
87
+ status: "suggested" | "opened" | "dry-run" | "not-sent";
88
88
  component: string;
89
89
  route: string;
90
90
  said: string;
package/dist/index.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  VERSION,
4
4
  optionsFromArgv,
5
5
  serveStdio
6
- } from "./chunk-E5V42VCS.js";
7
- import "./chunk-BZEPCY42.js";
6
+ } from "./chunk-LI4FNPYK.js";
7
+ import "./chunk-WSNJYGA5.js";
8
8
 
9
9
  // src/index.ts
10
10
  var argv = process.argv.slice(2);
package/dist/lib.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BridgeContext, type ContextOptions } from './context.js';
2
2
  import { type ServerOptions } from './server.js';
3
3
  export { BridgeContext, type ContextOptions } from './context.js';
4
+ export { findProductLink, GIT_CONFIG_KEYS, linkedOptions, parseProductPointer, PRODUCT_POINTER, type ProductLink, type ProductPointer } from './product-link.js';
4
5
  export { BlockedError, isBlocked, say } from './say.js';
5
6
  export { createServer, SERVER_INFO, VERSION, type ServerOptions } from './server.js';
6
7
  export { CONFIG_FILE, detectConfig, parseConfig, toConfigJson, type BridgeConfig } from './config.js';
package/dist/lib.js CHANGED
@@ -2,9 +2,11 @@ import {
2
2
  BlockedError,
3
3
  BridgeContext,
4
4
  DOCS_DRAFT_MODEL,
5
+ GIT_CONFIG_KEYS,
5
6
  GitHubSource,
6
7
  GitRefSource,
7
8
  LocalSource,
9
+ PRODUCT_POINTER,
8
10
  SERVER_INFO,
9
11
  VERSION,
10
12
  anthropicReplyText,
@@ -20,16 +22,19 @@ import {
20
22
  explorations_exports,
21
23
  figma_exports,
22
24
  figma_fixes_exports,
25
+ findProductLink,
23
26
  formatDocsJson,
24
27
  ghAuthToken,
25
28
  handleHttp,
26
29
  history_exports,
27
30
  isBlocked,
31
+ linkedOptions,
28
32
  mergeDocsDraft,
29
33
  missingProse,
30
34
  ops_exports,
31
35
  optionsFromArgv,
32
36
  parseDocsReply,
37
+ parseProductPointer,
33
38
  pieces_exports,
34
39
  requests_exports,
35
40
  say,
@@ -37,20 +42,22 @@ import {
37
42
  studio_exports,
38
43
  suggestions_exports,
39
44
  tokenNote
40
- } from "./chunk-E5V42VCS.js";
45
+ } from "./chunk-LI4FNPYK.js";
41
46
  import {
42
47
  CONFIG_FILE,
43
48
  loadConfig,
44
49
  toConfigJson
45
- } from "./chunk-BZEPCY42.js";
50
+ } from "./chunk-WSNJYGA5.js";
46
51
  export {
47
52
  BlockedError,
48
53
  BridgeContext,
49
54
  CONFIG_FILE,
50
55
  DOCS_DRAFT_MODEL,
56
+ GIT_CONFIG_KEYS,
51
57
  GitHubSource,
52
58
  GitRefSource,
53
59
  LocalSource,
60
+ PRODUCT_POINTER,
54
61
  SERVER_INFO,
55
62
  VERSION,
56
63
  anthropicReplyText,
@@ -66,17 +73,20 @@ export {
66
73
  explorations_exports as explorations,
67
74
  figma_exports as figma,
68
75
  figma_fixes_exports as figmaFixes,
76
+ findProductLink,
69
77
  formatDocsJson,
70
78
  ghAuthToken,
71
79
  handleHttp,
72
80
  history_exports as history,
73
81
  isBlocked,
82
+ linkedOptions,
74
83
  mergeDocsDraft,
75
84
  missingProse,
76
85
  ops_exports as ops,
77
86
  optionsFromArgv,
78
87
  loadConfig as parseConfig,
79
88
  parseDocsReply,
89
+ parseProductPointer,
80
90
  pieces_exports as pieces,
81
91
  requests_exports as requests,
82
92
  say,
package/dist/pieces.d.ts CHANGED
@@ -30,10 +30,12 @@ export declare function missingPiecesOp(ctx: BridgeContext, a: {
30
30
  recorded: boolean;
31
31
  next: string;
32
32
  skipped?: string | undefined;
33
- pr: number;
34
33
  branch: string;
35
34
  product: string;
36
35
  files: number;
36
+ repo?: string | undefined;
37
+ pr: number;
38
+ ref: string;
37
39
  }>;
38
40
  /**
39
41
  * bridge_open_library_branch / `bridge pieces open <n> <piece>`: the library side of one recorded piece, linked both
@@ -57,13 +59,15 @@ export declare function openLibraryBranchOp(ctx: BridgeContext, a: {
57
59
  number: number;
58
60
  url: string;
59
61
  } | undefined;
60
- changesMode: ChangesMode;
61
62
  neededBy: string;
63
+ ref?: string | undefined;
64
+ repo?: string | undefined;
65
+ changesMode: ChangesMode;
62
66
  request?: string | undefined;
63
67
  exploration?: string | undefined;
64
68
  brief?: string | undefined;
65
69
  edits?: import("@bridge-ds/core").TokenEdit[] | undefined;
66
- status: "opened" | "suggested" | "already-linked" | "dry-run";
70
+ status: "suggested" | "opened" | "already-linked" | "dry-run";
67
71
  pr: number;
68
72
  piece: string;
69
73
  opens: string;
@@ -74,7 +78,6 @@ export declare function productBranchOp(ctx: BridgeContext, a: {
74
78
  pr: number | string;
75
79
  }): Promise<{
76
80
  next?: string | undefined;
77
- pr: number;
78
81
  title: string;
79
82
  product: string;
80
83
  said: string;
@@ -102,6 +105,10 @@ export declare function productBranchOp(ctx: BridgeContext, a: {
102
105
  title: string;
103
106
  summary: string;
104
107
  }[];
108
+ ref?: string | undefined;
109
+ repo?: string | undefined;
110
+ library?: string | undefined;
111
+ pr: number;
105
112
  }>;
106
113
  /** bridge_use_library_preview: the product branch takes (again) the library branch of a piece, merged in. */
107
114
  export declare function useLibraryPreviewOp(ctx: BridgeContext, a: {
@@ -0,0 +1,42 @@
1
+ import type { ContextOptions } from './context.js';
2
+ /** Where the pointer lives, relative to the product repository root. */
3
+ export declare const PRODUCT_POINTER = ".bridge/product.json";
4
+ export interface ProductPointer {
5
+ version: 1;
6
+ /** The team's design system repository, `owner/name`, where bridge.config.json lives. */
7
+ designSystem: string;
8
+ /** The product key in that bridge.config.json `products[]`. */
9
+ product: string;
10
+ }
11
+ export interface ProductLink extends ProductPointer {
12
+ /** The product repository root: the folder holding `.bridge/product.json`. */
13
+ root: string;
14
+ }
15
+ /**
16
+ * The same link kept in the clone's own git config (`bridge.designSystem`, `bridge.product`, set by `bridge connect`):
17
+ * it survives switching to a branch made before the setup was committed, where `.bridge/product.json` is not.
18
+ */
19
+ export declare const GIT_CONFIG_KEYS: {
20
+ readonly designSystem: "bridge.designSystem";
21
+ readonly product: "bridge.product";
22
+ };
23
+ /** The pointer from its JSON text, or why it cannot be read, in plain words. */
24
+ export declare function parseProductPointer(text: string): ProductPointer;
25
+ /**
26
+ * The connected product repository `dir` is in: the nearest folder at or above it with `.bridge/product.json`. A
27
+ * folder with its own bridge.config.json met first wins (it is a design system repository, not a product), and so
28
+ * does the end of the git repository (the folder holding `.git`): there the clone's git config may still keep the link
29
+ * (GIT_CONFIG_KEYS), else null.
30
+ */
31
+ export declare function findProductLink(dir: string): Promise<ProductLink | null>;
32
+ /**
33
+ * Context options for a command run in `dir`. In a connected product repository: the design system repository on
34
+ * GitHub (`repo`), this checkout (`workTree`) and its product key (`product`). Elsewhere `base` unchanged with `root`.
35
+ * An explicit `repo` (the MCP server's `--repo`) keeps it, and takes the checkout and product only when the pointer
36
+ * names that same repository.
37
+ */
38
+ export declare function linkedOptions(dir: string, base?: Omit<ContextOptions, 'root'> & {
39
+ root?: string | undefined;
40
+ }): Promise<ContextOptions & {
41
+ link?: ProductLink;
42
+ }>;