merge-steward 0.17.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/db/schema.js CHANGED
@@ -75,6 +75,7 @@ export function ensureSchema(connection) {
75
75
  ensureColumn(connection, "queue_entries", "post_merge_summary", "TEXT");
76
76
  ensureColumn(connection, "queue_entries", "post_merge_checked_at", "TEXT");
77
77
  ensureColumn(connection, "queue_entries", "wait_detail", "TEXT");
78
+ ensureColumn(connection, "queue_entries", "pr_title", "TEXT");
78
79
  connection.exec(`
79
80
  UPDATE queue_entries
80
81
  SET post_merge_status = 'pending'
@@ -29,6 +29,7 @@ function mapEntry(row) {
29
29
  postMergeSha: row.post_merge_sha === null || row.post_merge_sha === undefined ? null : String(row.post_merge_sha),
30
30
  postMergeSummary: row.post_merge_summary === null || row.post_merge_summary === undefined ? null : String(row.post_merge_summary),
31
31
  postMergeCheckedAt: row.post_merge_checked_at === null || row.post_merge_checked_at === undefined ? null : String(row.post_merge_checked_at),
32
+ prTitle: row.pr_title === null || row.pr_title === undefined ? null : String(row.pr_title),
32
33
  enqueuedAt: String(row.enqueued_at),
33
34
  updatedAt: String(row.updated_at),
34
35
  };
@@ -125,8 +126,9 @@ export class SqliteStore {
125
126
  priority, generation, ci_run_id, ci_retries, retry_attempts,
126
127
  max_retries, last_failed_base_sha, issue_key, wait_detail,
127
128
  post_merge_status, post_merge_sha, post_merge_summary, post_merge_checked_at,
129
+ pr_title,
128
130
  enqueued_at, updated_at)
129
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(entry.id, entry.repoId, entry.prNumber, entry.branch, entry.headSha, entry.baseSha, entry.status, entry.position, entry.priority, entry.generation, entry.ciRunId, entry.ciRetries, entry.retryAttempts, entry.maxRetries, entry.lastFailedBaseSha, entry.issueKey ?? null, entry.waitDetail ?? null, entry.postMergeStatus ?? null, entry.postMergeSha ?? null, entry.postMergeSummary ?? null, entry.postMergeCheckedAt ?? null, entry.enqueuedAt, entry.updatedAt);
131
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(entry.id, entry.repoId, entry.prNumber, entry.branch, entry.headSha, entry.baseSha, entry.status, entry.position, entry.priority, entry.generation, entry.ciRunId, entry.ciRetries, entry.retryAttempts, entry.maxRetries, entry.lastFailedBaseSha, entry.issueKey ?? null, entry.waitDetail ?? null, entry.postMergeStatus ?? null, entry.postMergeSha ?? null, entry.postMergeSummary ?? null, entry.postMergeCheckedAt ?? null, entry.prTitle ?? null, entry.enqueuedAt, entry.updatedAt);
130
132
  this.writeEvent(entry.id, null, entry.status);
131
133
  })();
132
134
  }
@@ -24,13 +24,14 @@ export class GitHubPRClient {
24
24
  const result = await exec("gh", [
25
25
  "pr", "view", String(prNumber),
26
26
  "--repo", this.repoFullName,
27
- "--json", "number,headRefName,headRefOid,reviewDecision,state,mergeStateStatus",
27
+ "--json", "number,title,headRefName,headRefOid,reviewDecision,state,mergeStateStatus",
28
28
  ], { githubRepoFullName: this.repoFullName });
29
29
  const data = JSON.parse(result.stdout);
30
30
  return {
31
31
  number: data.number,
32
32
  branch: data.headRefName,
33
33
  headSha: data.headRefOid,
34
+ ...(data.title ? { title: data.title } : {}),
34
35
  mergeable: data.state === "OPEN",
35
36
  mergeStateStatus: data.mergeStateStatus,
36
37
  reviewDecision: data.reviewDecision,
@@ -18,6 +18,7 @@ export declare class MergeStewardQueueCommands {
18
18
  headSha: string;
19
19
  issueKey?: string;
20
20
  priority?: number;
21
+ prTitle?: string;
21
22
  }): QueueEntry | undefined;
22
23
  scanStartupAdmissions(): Promise<void>;
23
24
  scanEligibleOpenPrs(): Promise<{
@@ -63,6 +63,7 @@ export class MergeStewardQueueCommands {
63
63
  postMergeSha: null,
64
64
  postMergeSummary: null,
65
65
  postMergeCheckedAt: null,
66
+ prTitle: params.prTitle ?? null,
66
67
  enqueuedAt: new Date().toISOString(),
67
68
  updatedAt: new Date().toISOString(),
68
69
  };
@@ -161,7 +162,7 @@ export class MergeStewardQueueCommands {
161
162
  return false;
162
163
  }
163
164
  }
164
- this.enqueue({ prNumber, branch, headSha });
165
+ this.enqueue({ prNumber, branch, headSha, ...(status.title ? { prTitle: status.title } : {}) });
165
166
  return true;
166
167
  }
167
168
  catch (error) {
package/dist/types.d.ts CHANGED
@@ -42,6 +42,8 @@ export interface QueueEntry {
42
42
  waitDetail?: string | null;
43
43
  /** Post-merge verification status for the landed commit on main. */
44
44
  postMergeStatus: PostMergeStatus | null;
45
+ /** PR title captured at admission. Falls back to branch name in the UI. */
46
+ prTitle?: string | null;
45
47
  /** Commit SHA used when checking post-merge status. */
46
48
  postMergeSha: string | null;
47
49
  /** Optional one-line summary of post-merge checks. */
@@ -180,6 +182,7 @@ export interface PRStatus {
180
182
  number: number;
181
183
  branch: string;
182
184
  headSha: string;
185
+ title?: string | undefined;
183
186
  mergeable: boolean;
184
187
  mergeStateStatus?: string | undefined;
185
188
  reviewDecision?: string | undefined;
@@ -3,13 +3,26 @@ import { Box, Text, useStdout } from "ink";
3
3
  import { RepoRow } from "./OverviewView.js";
4
4
  import { clipSummary } from "./dashboard-model.js";
5
5
  const PR_ID_WIDTH = 7;
6
+ const PR_PHRASE_WIDTH = 20;
6
7
  const SUMMARY_INDENT = 9;
7
8
  function PrEntryRow({ entry, width, includeSummary, }) {
8
9
  const idText = `#${entry.prNumber}`.padEnd(PR_ID_WIDTH, " ");
10
+ const paddedPhrase = entry.phrase.padEnd(PR_PHRASE_WIDTH, " ");
9
11
  const summaryText = includeSummary
10
12
  ? clipSummary(entry.summary, { maxLines: 3, width: Math.max(20, width - SUMMARY_INDENT) })
11
13
  : "";
12
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: entry.color, children: idText }), _jsx(Text, { color: entry.color, children: entry.glyph }), _jsx(Text, { children: ` ${entry.phrase}` })] }), summaryText ? (_jsxs(Box, { children: [_jsx(Text, { children: " ".repeat(SUMMARY_INDENT) }), _jsx(Text, { dimColor: true, children: summaryText })] })) : null] }));
14
+ const titleSpace = Math.max(0, width - (PR_ID_WIDTH + 3 + PR_PHRASE_WIDTH + 1));
15
+ const title = entry.title && entry.title !== entry.phrase && titleSpace >= 8
16
+ ? truncate(entry.title, titleSpace)
17
+ : "";
18
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: entry.color, children: idText }), _jsx(Text, { color: entry.color, children: entry.glyph }), _jsx(Text, { children: ` ${paddedPhrase}` }), title ? _jsx(Text, { dimColor: true, children: ` ${title}` }) : null] }), summaryText ? (_jsxs(Box, { children: [_jsx(Text, { children: " ".repeat(SUMMARY_INDENT) }), _jsx(Text, { dimColor: true, children: summaryText })] })) : null] }));
19
+ }
20
+ function truncate(value, maxWidth) {
21
+ if (value.length <= maxWidth)
22
+ return value;
23
+ if (maxWidth <= 1)
24
+ return value.slice(0, maxWidth);
25
+ return `${value.slice(0, Math.max(0, maxWidth - 1))}\u2026`;
13
26
  }
14
27
  export function ProjectDetailView({ model, selectedRepoId }) {
15
28
  const { stdout } = useStdout();
@@ -23,6 +23,7 @@ export interface DashboardToken {
23
23
  export interface DashboardPrEntry extends DashboardToken {
24
24
  phrase: string;
25
25
  summary?: string;
26
+ title?: string;
26
27
  eventAt: number;
27
28
  }
28
29
  export interface DashboardRepo {
@@ -151,6 +151,9 @@ function repoEntriesFromSnapshot(snapshot, cutoff) {
151
151
  const summary = entrySummary(entry);
152
152
  if (summary)
153
153
  item.summary = summary;
154
+ const title = entry.prTitle?.trim() || entry.branch;
155
+ if (title)
156
+ item.title = title;
154
157
  byPr.set(entry.prNumber, item);
155
158
  }
156
159
  return [...byPr.values()].sort((left, right) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "merge-steward",
3
- "version": "0.17.1",
3
+ "version": "0.18.0",
4
4
  "description": "Serial merge queue for GitHub — rebase, CI-gate, and merge PRs one at a time",
5
5
  "type": "module",
6
6
  "repository": {