merge-steward 0.19.2 → 0.20.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.
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text, useStdout } from "ink";
3
+ import { formatRepoTokenText } from "./format.js";
3
4
  function RepoTokens({ tokens, width }) {
4
5
  if (tokens.length === 0 || width < 6)
5
6
  return null;
6
7
  const parts = [];
7
8
  let used = 0;
8
9
  for (const token of tokens) {
9
- const text = `#${token.prNumber} ${token.glyph}`;
10
+ const text = formatRepoTokenText(token);
10
11
  const separatorWidth = parts.length === 0 ? 0 : 2;
11
12
  if (used + separatorWidth + text.length > width)
12
13
  break;
@@ -2,9 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text, useStdout } from "ink";
3
3
  import { RepoRow } from "./OverviewView.js";
4
4
  import { clipSummary } from "./dashboard-model.js";
5
+ import { formatTokenAge } from "./format.js";
5
6
  const PR_ID_WIDTH = 7;
6
7
  const PR_PHRASE_WIDTH = 20;
7
8
  const SUMMARY_INDENT = 9;
9
+ const AGE_WIDTH = 4;
8
10
  function truncate(value, maxWidth) {
9
11
  if (value.length <= maxWidth)
10
12
  return value;
@@ -33,11 +35,12 @@ export function buildContentLines(repo, width) {
33
35
  function EntryHeaderRow({ entry, width }) {
34
36
  const idText = `#${entry.prNumber}`.padEnd(PR_ID_WIDTH, " ");
35
37
  const paddedPhrase = entry.phrase.padEnd(PR_PHRASE_WIDTH, " ");
36
- const titleSpace = Math.max(0, width - (PR_ID_WIDTH + 3 + PR_PHRASE_WIDTH + 1));
38
+ const age = formatTokenAge(entry.eventAt);
39
+ const titleSpace = Math.max(0, width - (PR_ID_WIDTH + 3 + PR_PHRASE_WIDTH + 3 + AGE_WIDTH));
37
40
  const title = entry.title && entry.title !== entry.phrase && titleSpace >= 8
38
41
  ? truncate(entry.title, titleSpace)
39
42
  : "";
40
- return (_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] }));
43
+ return (_jsxs(Box, { children: [_jsx(Text, { color: entry.color, children: idText }), _jsx(Text, { color: entry.color, children: entry.glyph }), _jsx(Text, { children: ` ${paddedPhrase}` }), _jsx(Text, { dimColor: true, children: ` ${age}` }), title ? _jsx(Text, { dimColor: true, children: ` ${title}` }) : null] }));
41
44
  }
42
45
  function renderLine(line, key, width) {
43
46
  if (line.kind === "blank")
@@ -19,6 +19,7 @@ export interface DashboardToken {
19
19
  glyph: string;
20
20
  color: DashboardTokenColor;
21
21
  kind: DashboardTokenKind;
22
+ eventAt: number;
22
23
  }
23
24
  export interface DashboardPrEntry extends DashboardToken {
24
25
  phrase: string;
@@ -193,7 +193,7 @@ export function buildDashboard(repos, opts = {}) {
193
193
  return {
194
194
  repoId: repo.repoId,
195
195
  repoFullName: repo.repoFullName,
196
- tokens: entries.map(({ prNumber, glyph, color, kind }) => ({ prNumber, glyph, color, kind })),
196
+ tokens: entries.map(({ prNumber, glyph, color, kind, eventAt }) => ({ prNumber, glyph, color, kind, eventAt })),
197
197
  entries,
198
198
  latestActivityAt,
199
199
  hasActivity: entries.length > 0,
@@ -1,7 +1,13 @@
1
1
  import type { CheckResult, PostMergeStatus, QueueBlockState, QueueEntryStatus, QueueEventRecord, QueueEventSummary, QueueRuntimeStatus } from "../types.ts";
2
2
  export declare function isPendingMainVerification(block: QueueBlockState | null | undefined): boolean;
3
3
  export declare function shortSha(value: string | null | undefined): string;
4
- export declare function relativeTime(iso: string | null | undefined): string;
4
+ export declare function relativeTime(iso: string | number | null | undefined): string;
5
+ export declare function formatTokenAge(eventAt: number): string;
6
+ export declare function formatRepoTokenText(token: {
7
+ prNumber: number;
8
+ glyph: string;
9
+ eventAt: number;
10
+ }): string;
5
11
  export declare function mergeWaitState(entry: {
6
12
  status: QueueEntryStatus;
7
13
  waitDetail?: string | null | undefined;
@@ -21,7 +21,8 @@ export function relativeTime(iso) {
21
21
  if (!iso) {
22
22
  return "-";
23
23
  }
24
- const seconds = Math.max(0, Math.floor((Date.now() - new Date(iso).getTime()) / 1000));
24
+ const timestamp = typeof iso === "number" ? iso : new Date(iso).getTime();
25
+ const seconds = Math.max(0, Math.floor((Date.now() - timestamp) / 1000));
25
26
  if (seconds < 5)
26
27
  return "now";
27
28
  if (seconds < 60)
@@ -35,6 +36,12 @@ export function relativeTime(iso) {
35
36
  const days = Math.floor(hours / 24);
36
37
  return `${days}d`;
37
38
  }
39
+ export function formatTokenAge(eventAt) {
40
+ return relativeTime(eventAt).padStart(4, " ");
41
+ }
42
+ export function formatRepoTokenText(token) {
43
+ return `#${token.prNumber} ${token.glyph} ${relativeTime(token.eventAt)}`;
44
+ }
38
45
  export function mergeWaitState(entry) {
39
46
  if (!entry || entry.status !== "merging" || !entry.waitDetail) {
40
47
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "merge-steward",
3
- "version": "0.19.2",
3
+ "version": "0.20.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": {