@bridge-ds/core 0.16.0 → 0.17.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.
@@ -149,12 +149,16 @@ export type ReviewStatusKind = 'merged' | 'closed' | 'draft' | 'ci-failing' | 'c
149
149
  */
150
150
  export declare const REVIEW_STATUS_ORDER: Record<ReviewStatusKind, number>;
151
151
  /**
152
- * One status chip for a pull request, from real data. Same rules and order as the pull request header
153
- * (lib/changes needFromDetail): lifecycle, draft, CI failing, changes requested, merge conflict, CI running, then
154
- * missing approvals (Tier 3 by default), then ready. `mergeable` null means GitHub has not computed it yet: the chip
155
- * reads "Checking" instead of an approval or "Ready to ship", so a list never says something the detail contradicts.
156
- * Undefined means it was not read: no conflict known. `ready` is returned only when mergeGate allows the merge.
157
- * Unknown CI or reviews (null, still loading or failed) never read as ready.
152
+ * The one status of a pull request, from real data: every surface (the Studio list, the branch page, the home, the
153
+ * MCP server and the CLI) derives it here, so the same branch never reads two ways. Same rules and order as the merge
154
+ * gate: lifecycle, draft, CI failing, changes requested, merge conflict, CI running, then missing approvals (Tier 3 by
155
+ * default), then ready.
156
+ *
157
+ * A repo with no automated checks (`ci.state` "none") is a calm state of its own, never "Checking" or unknown: the
158
+ * status comes from the approvals, as for any branch. `mergeable` null means GitHub has not computed whether it merges
159
+ * cleanly yet: that never hides a missing approval (it is missing either way), it only keeps "Ready to merge" back
160
+ * ("checking") until GitHub answers. Undefined means it was not read: no conflict known. `ready` is returned only when
161
+ * mergeGate allows the merge. Unknown CI or reviews (null: the read failed) never read as ready.
158
162
  */
159
163
  export declare function reviewStatusKind(input: {
160
164
  state?: string;
@@ -165,6 +169,13 @@ export declare function reviewStatusKind(input: {
165
169
  tier: RiskTier | null;
166
170
  mergeable?: boolean | null;
167
171
  }): ReviewStatusKind;
172
+ /**
173
+ * The words of each status, the same in Studio, the MCP server and the CLI. "checking" only ever means GitHub is still
174
+ * working out whether an approved branch merges cleanly; it never stands for missing tests.
175
+ */
176
+ export declare const REVIEW_STATUS_LABEL: Record<ReviewStatusKind, string>;
177
+ /** The words of a CI summary. A repo without automated checks reads as that, calmly, never as pending or unknown. */
178
+ export declare const CI_STATE_LABEL: Record<CiState, string>;
168
179
  export interface QueuePull extends PullStateLike {
169
180
  state: string;
170
181
  labels?: ({
package/dist/rights.d.ts CHANGED
@@ -80,4 +80,23 @@ export interface VisualImpactConfig {
80
80
  export declare const DEFAULT_VISUAL_IMPACT: VisualImpactConfig;
81
81
  /** Label that asks the visual impact workflow to run in on-demand mode. */
82
82
  export declare const VISUAL_CHECK_LABEL = "visual-check";
83
+ /** The workflow that makes the visual before and after (`bridge impact`), as its file is named in .github/workflows. */
84
+ export declare const VISUAL_WORKFLOW_FILES: readonly string[];
85
+ /** Where a team reads how to set up visual checks. */
86
+ export declare const VISUAL_CHECKS_DOCS = "https://github.com/peterbono/ai-design-system-demo/blob/main/docs/GOVERNANCE.md#visual-before-and-after";
87
+ /**
88
+ * Whether the repo has the visual impact workflow, from the files in .github/workflows (paths or names). Without it,
89
+ * neither the visual-check label nor a run "again" means anything, so Bridge offers neither: `visualImpact` in the
90
+ * config only says when the workflow runs, never that it exists.
91
+ */
92
+ export declare function hasVisualWorkflow(files: readonly string[]): boolean;
93
+ /**
94
+ * What a branch offers about visual checks: `run` (the workflow exists: the before and after, the visual-check label
95
+ * on demand, "runs again" after an update), `set-up` (it touches what visual checks capture but the repo has none: a
96
+ * calm link to the docs, never an ask), `none` (nothing visual changes). `workflow` null: not read, the old behaviour.
97
+ */
98
+ export declare function visualOffer(x: {
99
+ touchesVisuals: boolean;
100
+ workflow: boolean | null;
101
+ }): 'run' | 'set-up' | 'none';
83
102
  export declare function visualImpactProblems(raw: unknown): string[];
@@ -2,6 +2,8 @@ import { GitHubClient, type IssueSummary, type PullRequestSummary } from './gith
2
2
  import { type SuggestionAppliedRecord, type SuggestionApprovals, type SuggestionCommentLike, type SuggestionGovernance, type SuggestionReviewEvent } from './suggestion-review';
3
3
  import { type ComposeSuggestionOptions, type ParsedSuggestion, type SuggestionKind, type SuggestionPayloadV1, type SuggestionStatus } from './suggestions';
4
4
  import type { ApprovalRole } from './review-gate';
5
+ import { type BridgeConfig } from './config';
6
+ import { type SuggestionApplyOp, type SuggestionApplyPlan, type SuggestionWorkspace } from './suggestion-apply';
5
7
  export interface CreatedSuggestion {
6
8
  number: number;
7
9
  url: string;
@@ -85,10 +87,51 @@ export declare function getSuggestionOnGitHub(gh: GitHubClient, n: number, gov:
85
87
  outdated?: boolean | undefined;
86
88
  }): Promise<SuggestionDetail>;
87
89
  /**
88
- * Keeps exactly one state label on the issue, the one the status calls for (none once closed or outdated). Best
89
- * effort: returns a warning sentence when the labels could not be changed.
90
+ * Keeps exactly one status label on the issue, the one the status calls for (suggestionLabelChanges): an open state
91
+ * label while open, the final label ("suggestion: applied", "suggestion: declined") once closed, the old ones removed.
92
+ * Best effort: returns a warning sentence when the labels could not be changed.
90
93
  */
91
94
  export declare function syncSuggestionStateLabel(gh: GitHubClient, n: number, labels: readonly string[], status: SuggestionStatus): Promise<string | null>;
95
+ /**
96
+ * After a pull request merged: every Bridge suggestion it closes ("Closes #n") gets its final label, "suggestion:
97
+ * applied", and loses "needs review" and "applying". Issues that are not suggestions are left alone. Best effort: never
98
+ * throws, returns the suggestions it labelled and a warning per one it could not.
99
+ */
100
+ export declare function markSuggestionsAppliedOnGitHub(gh: GitHubClient, pr: {
101
+ body: string | null | undefined;
102
+ }): Promise<{
103
+ applied: number[];
104
+ warnings: string[];
105
+ }>;
106
+ /** The planner's workspace over the GitHub API at a ref or commit: nothing is written. */
107
+ export declare function githubSuggestionWorkspace(gh: GitHubClient, ref: string): SuggestionWorkspace;
108
+ /** Whether a changed repo file can change what a suggestion writes: one of its files, a token file, or the config. */
109
+ export declare function suggestionTouches(payload: SuggestionPayloadV1, config: BridgeConfig, path: string): boolean;
110
+ export interface SuggestionStaleness {
111
+ /** The head of the base branch it was checked against, or null when it could not be read. */
112
+ mainSha: string | null;
113
+ /** Main has commits since the suggestion was made. */
114
+ mainMoved: boolean;
115
+ /** Main moved and part of the change no longer applies: the value it changes is not the one it was suggested from. */
116
+ outdated: boolean;
117
+ /** The changes that conflict with main now (planSuggestionApply), empty when none or not planned. */
118
+ conflicts: SuggestionApplyOp[];
119
+ /** The dry run on main, when it ran (main moved and touched what the suggestion writes). */
120
+ plan: SuggestionApplyPlan | null;
121
+ }
122
+ /**
123
+ * Whether an open suggestion still applies to main (the same staleness rule for Studio, the MCP server and the CLI).
124
+ * Cheap first: nothing to plan when main has not moved since the suggestion's base, or moved without touching what it
125
+ * writes (one compare). Otherwise planSuggestionApply runs on main, nothing written, past the approvals, and any
126
+ * conflict makes it outdated. A read that fails says "not outdated", never a guess.
127
+ */
128
+ export declare function suggestionStalenessOnGitHub(gh: GitHubClient, d: Pick<SuggestionDetail, 'parsed' | 'comments' | 'issue'>, input: {
129
+ config: BridgeConfig;
130
+ governance?: SuggestionGovernance | undefined;
131
+ ref?: string | undefined;
132
+ }): Promise<SuggestionStaleness>;
133
+ /** A suggestion's status once its staleness on main is known (withOutdated). */
134
+ export declare function stalenessStatus(status: SuggestionStatus, staleness: Pick<SuggestionStaleness, 'outdated'> | null | undefined): SuggestionStatus;
92
135
  export interface SuggestionReviewResult {
93
136
  commentUrl: string;
94
137
  payloadSha: string;
@@ -111,8 +154,9 @@ export declare function reviewSuggestionOnGitHub(gh: GitHubClient, n: number, in
111
154
  at?: Date | undefined;
112
155
  }, gov: SuggestionGovernance): Promise<SuggestionReviewResult>;
113
156
  /**
114
- * Records that a suggestion is being applied (the applied marker comment) and sets the `suggestion: applying` label.
115
- * Called after a developer pushed the branch or opened the pull request that says "Closes #n".
157
+ * Records that a suggestion is being applied (the applied marker comment) and sets its status label: "suggestion:
158
+ * applying" while the pull request is open, "suggestion: applied" (the old labels removed) once it merged or the issue
159
+ * is closed as completed. Called after a developer pushed the branch or opened the pull request that says "Closes #n".
116
160
  */
117
161
  export declare function linkSuggestionPrOnGitHub(gh: GitHubClient, n: number, link: {
118
162
  pr?: number | undefined;
@@ -122,9 +166,13 @@ export declare function linkSuggestionPrOnGitHub(gh: GitHubClient, n: number, li
122
166
  payloadSha: string;
123
167
  forced?: boolean | undefined;
124
168
  at?: Date | undefined;
169
+ merged?: boolean | undefined;
125
170
  }): Promise<{
126
171
  warnings: string[];
172
+ status: SuggestionStatus;
127
173
  }>;
174
+ /** Applied once its pull request merged or the issue is closed as completed; being applied before that. */
175
+ export declare function appliedStatus(issue: Pick<IssueSummary, 'state' | 'stateReason'>, merged?: boolean | undefined): 'applied' | 'applying';
128
176
  /** Declines a suggestion like a request (reason comment, closed as not planned), then clears its state label. */
129
177
  export declare function declineSuggestionOnGitHub(gh: GitHubClient, n: number, reason: string, by?: string | null): Promise<{
130
178
  warnings: string[];
@@ -13,6 +13,11 @@ export type SuggestionState = 'needs-review' | 'changes-requested' | 'approved'
13
13
  /** Where a suggestion stands (suggestionStatus). */
14
14
  export type SuggestionStatus = SuggestionState | 'applied' | 'declined' | 'outdated';
15
15
  export declare const SUGGESTION_STATE_LABELS: Record<SuggestionState, string>;
16
+ /**
17
+ * The label a finished suggestion keeps once closed, in place of the open state labels (applied through a merged
18
+ * pull request or closed as completed; declined).
19
+ */
20
+ export declare const SUGGESTION_FINAL_LABELS: Record<'applied' | 'declined', string>;
16
21
  export declare const SUGGESTION_STATUS_LABEL: Record<SuggestionStatus, string>;
17
22
  /** A whole-file result: the git blob sha at `base` (null: a new file), after (null: deleted), and the new content. */
18
23
  export interface SuggestionFile {
@@ -174,8 +179,27 @@ export interface SuggestionStatusInput {
174
179
  * dry run found a conflict; then the review state (changes requested, approved, needs review).
175
180
  */
176
181
  export declare function suggestionStatus(i: SuggestionStatusInput): SuggestionStatus;
177
- /** The state label a status keeps on the issue, or null when none should stay (closed, outdated). */
182
+ /**
183
+ * Outdated wins over the review state once main moved under a suggestion and its change no longer applies (the dry run
184
+ * of planSuggestionApply found a conflict: the value it changes is not the one it was suggested from). Being applied,
185
+ * applied and declined stay as they are.
186
+ */
187
+ export declare function withOutdated(status: SuggestionStatus, outdated: boolean | null | undefined): SuggestionStatus;
188
+ /**
189
+ * The status label a suggestion keeps on the issue: one open state label while it is open, the final label once it is
190
+ * applied or declined, none while it is outdated (the review label then stays as it was).
191
+ */
178
192
  export declare function suggestionStateLabel(status: SuggestionStatus): string | null;
193
+ /** Every status label Bridge manages on a suggestion issue (open states and final ones). */
194
+ export declare const SUGGESTION_STATUS_LABELS: readonly string[];
195
+ /**
196
+ * The status labels to add and remove so the issue carries exactly the one its status calls for: an applied and
197
+ * closed suggestion loses "needs review" and "applying" and gains "applied". Outdated keeps the labels it has.
198
+ */
199
+ export declare function suggestionLabelChanges(labels: readonly string[], status: SuggestionStatus): {
200
+ add: string[];
201
+ remove: string[];
202
+ };
179
203
  export interface SuggestionIssue {
180
204
  title: string;
181
205
  body: string;
@@ -0,0 +1,9 @@
1
+ /** The first letter in lower case, unless the first word is a proper name (properWord). */
2
+ export declare function lowerFirstWord(text: string, names?: readonly string[]): string;
3
+ /**
4
+ * "<subject>: <title>", the title's first letter lowered unless it starts with a proper name. A title that already
5
+ * starts with the subject (any case, with or without a colon) is not prefixed again: "select: keyboard focus" under
6
+ * Select gives "Select: keyboard focus", "Select keeps focus" stays "Select keeps focus", with the subject's own
7
+ * capitals. A trailing period is dropped. `names` lists other proper names to keep (component names).
8
+ */
9
+ export declare function subjectTitle(subject: string, title: string, names?: readonly string[]): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge-ds/core",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "description": "Bridge core: bridge.config.json, DTCG token loading (tiers and layered modes), alias resolution, WCAG contrast, diffs, minimal-diff edits, PR body, the shared risk tier classifier, changesets and a fetch-based GitHub client. No Figma API, no DOM; Node-only helpers (git, reading a product folder) under @bridge-ds/core/node; the adoption audit under @bridge-ds/core/audit.",
6
6
  "license": "MIT",