@kud/gh-ink 0.63.0 → 0.65.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/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import React, { ReactNode } from 'react';
2
2
  import { PrComments, PrHealthData, PrCheck, Health } from '@kud/gh';
3
3
  import { GHItem, AnyItem, Section, CiStatus, OriginSplit } from '@kud/gh-workflow';
4
- export { AnyItem, Band, CiStatus, GHDetail, GHItem, InboxConfig, Move, OriginSplit, PIN_MARK, RepoHeader, RepoProfile, Section, ShowLess, ShowMore, Standing, SubgroupHeader, TaskRow, bandOf, checkoutDirs, configureInbox, filterByOrigin, filterByRepos, filterBySearch, impliedLabels, inboxConfig, insertRepoHeaders, labelPriority, layoutGHItems, profileOf, relativeTime, repoPriority, resetInboxConfig, sortByRecency, sortItems, whoseMove } from '@kud/gh-workflow';
4
+ export { AnyItem, Band, CiStatus, GHDetail, GHItem, InboxConfig, Move, NEEDS_YOU_SECTION, NeedsYou, OriginSplit, PIN_MARK, RepoHeader, RepoProfile, Section, ShowLess, ShowMore, Standing, SubgroupHeader, TaskRow, bandOf, checkoutDirs, configureInbox, filterByOrigin, filterByRepos, filterBySearch, impliedLabels, inboxConfig, insertRepoHeaders, labelPriority, layoutGHItems, profileOf, relativeTime, repoPriority, resetInboxConfig, sortByRecency, sortItems, whoseMove } from '@kud/gh-workflow';
5
5
  import { StyledLine } from '@kud/ink-ui';
6
6
 
7
7
  type CommentsPanelProps = {
@@ -250,6 +250,12 @@ type PrRowProps = {
250
250
  columns?: TrailingColumns;
251
251
  /** Trailing columns the section has given up — see `sectionShedOf`. */
252
252
  shed?: TrailingShed;
253
+ /**
254
+ * Width of the number cell across the section — see `numberColumnsOf`.
255
+ * Absent, the row measures itself, which aligns nothing but never runs the
256
+ * number into the title.
257
+ */
258
+ numberCols?: number;
253
259
  };
254
260
  /**
255
261
  * The trailing block, in reading order: how contested, how big, how recent.
@@ -274,7 +280,19 @@ type TrailingShed = Partial<Record<(typeof TRAILING)[number], boolean>>;
274
280
  * would not.
275
281
  */
276
282
  declare const trailingColumnsOf: (items: readonly GHItem[]) => TrailingColumns;
277
- type LayoutInput = Pick<PrRowProps, "item" | "login" | "cols" | "prefix" | "uniformLabels" | "announcements" | "columns" | "shed">;
283
+ /**
284
+ * Width of the `#n` cell across these rows: the widest number plus a two-cell
285
+ * gutter, left-aligned. Measured once by the list over the whole section, the
286
+ * same move as `markerCols` and `trailingColumnsOf`, so the titles start on one
287
+ * column and that column does not move as you scroll.
288
+ *
289
+ * It replaced `padEnd(7)`, a constant that fitted the repos it was written
290
+ * against and nothing else: `#31805` left a one-cell gutter where `#172` left
291
+ * three, and a six-digit number would have run straight into its title. A
292
+ * section of short numbers no longer pays for a long one it does not hold.
293
+ */
294
+ declare const numberColumnsOf: (items: readonly GHItem[]) => number;
295
+ type LayoutInput = Pick<PrRowProps, "item" | "login" | "cols" | "prefix" | "uniformLabels" | "announcements" | "columns" | "shed" | "numberCols">;
278
296
  /**
279
297
  * Which trailing columns the section has to give up, so that every row gives up
280
298
  * the same ones. Each row is laid out alone and the drops are unioned: if any
@@ -300,7 +318,7 @@ declare const sectionShedOf: (rows: readonly Pick<LayoutInput, "item" | "prefix"
300
318
  * arrival, merge and departure belongs to whoever owns the list, and reaches
301
319
  * the row as `icon`, `motion` and `announcements` after the decisions are made.
302
320
  */
303
- declare const PrRow: ({ item, active, login, cols, icon: iconOverride, prefix, uniformLabels, motion, announcements, columns, shed, }: PrRowProps) => React.JSX.Element;
321
+ declare const PrRow: ({ item, active, login, cols, icon: iconOverride, prefix, uniformLabels, motion, announcements, columns, shed, numberCols, }: PrRowProps) => React.JSX.Element;
304
322
 
305
323
  /**
306
324
  * One state per thing, from a closed set the strip knows how to draw. The host
@@ -525,18 +543,20 @@ declare const reposInSections: (sections: Section[]) => string[];
525
543
  /**
526
544
  * The next selectable row in `dir`, or `current` when there is none.
527
545
  *
528
- * A repo-header is a STOP, and a subgroup-header is not. The two look alike and
529
- * are not: the fence names a thing you can act on — open the checkout, copy every
530
- * URL under it — where a band label ("Your move") names an arrangement of rows
531
- * and has nothing behind it to open. Landing on the second would be a keystroke
532
- * spent on a row whose every key is inert.
546
+ * Both header kinds are STOPS. A repo-header names a thing you can act on —
547
+ * open the checkout, copy every URL under it — and a band header
548
+ * ("» Your move") does now too: `c` copies the whole band. Landing on one
549
+ * used to be a keystroke spent on a row whose every key was inert, which is
550
+ * why `moveCursor` stepped over subgroup-headers; now that the key does
551
+ * something there, skipping it would hide the row that says how many links
552
+ * the key will take.
533
553
  *
534
- * Unconditional in both directions, deliberately. Skipping the fence going down
535
- * and landing on it going up would make ↓ then ↑ end somewhere other than where
536
- * it started, and an arrow pair that is not its own inverse reads as the list
537
- * drifting rather than as a shortcut. The cost is one press per repo group; the
538
- * fence is also the "you have crossed into another repo" beat the eye takes
539
- * anyway, so the press buys orientation as well as position.
554
+ * Unconditional in both directions, deliberately. Skipping a header going
555
+ * down and landing on it going up would make ↓ then ↑ end somewhere other
556
+ * than where it started, and an arrow pair that is not its own inverse reads
557
+ * as the list drifting rather than as a shortcut. The cost is one press per
558
+ * header; each is also the "you have crossed into another group" beat the eye
559
+ * takes anyway, so the press buys orientation as well as position.
540
560
  */
541
561
  declare const moveCursor: (items: AnyItem[], current: number, dir: 1 | -1) => number;
542
562
  /**
@@ -792,4 +812,4 @@ declare const matchesFilter: (repo: string, filter: RepoFilter) => boolean;
792
812
  */
793
813
  declare const parsePatterns: (value: string) => string[];
794
814
 
795
- export { type Action, ActionMenu, App, COLS, CiStatusLine, type CiStatusState, type Command, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraTransition, type LiveLabel, MIN_SIDEBAR_COLS, PrRow, type PrRowProps, type Rails, type RepoFilter, type RowAnnouncement, type RowMotion, SIDEBAR_COLS, type SettledResult, SidePanel, type Sidebar, type SidebarRow, type StatusStrip, StatusStripLine, type StripItem, type StripState, type StripStatusState, type TrailingColumns, type TrailingShed, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, railHeights, railRowsOf, railWidth, railsOf, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sectionShedOf, signatureOf, stripGlyph, stripLayout, stripSignature, toCiStatusState, trailingColumnsOf, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
815
+ export { type Action, ActionMenu, App, COLS, CiStatusLine, type CiStatusState, type Command, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraTransition, type LiveLabel, MIN_SIDEBAR_COLS, PrRow, type PrRowProps, type Rails, type RepoFilter, type RowAnnouncement, type RowMotion, SIDEBAR_COLS, type SettledResult, SidePanel, type Sidebar, type SidebarRow, type StatusStrip, StatusStripLine, type StripItem, type StripState, type StripStatusState, type TrailingColumns, type TrailingShed, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, numberColumnsOf, openInTab, parsePatterns, railCapacity, railHeights, railRowsOf, railWidth, railsOf, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sectionShedOf, signatureOf, stripGlyph, stripLayout, stripSignature, toCiStatusState, trailingColumnsOf, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { colors, ScrollView, TextInput, Pill, useAppKeys, LoadingScreen, StatusM
4
4
  import { isPassCheck, isFailCheck, isInconclusiveCheck, resolveThread, unresolveThread, replyToThread, rerunFailedRun, mergePr, reRequestReviewer } from '@kud/gh';
5
5
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
6
  import { PIN_MARK, sizeOf, sizePartsOf, depthOf, impliedLabels, labelPriority, checkoutDirs, profileOf, inboxConfig, relativeTime, filterBySearch, filterByRepos, filterByOrigin } from '@kud/gh-workflow';
7
- export { PIN_MARK, bandOf, checkoutDirs, configureInbox, filterByOrigin, filterByRepos, filterBySearch, impliedLabels, inboxConfig, insertRepoHeaders, labelPriority, layoutGHItems, profileOf, relativeTime, repoPriority, resetInboxConfig, sortByRecency, sortItems, whoseMove } from '@kud/gh-workflow';
7
+ export { NEEDS_YOU_SECTION, PIN_MARK, bandOf, checkoutDirs, configureInbox, filterByOrigin, filterByRepos, filterBySearch, impliedLabels, inboxConfig, insertRepoHeaders, labelPriority, layoutGHItems, profileOf, relativeTime, repoPriority, resetInboxConfig, sortByRecency, sortItems, whoseMove } from '@kud/gh-workflow';
8
8
  import { $ } from 'zx';
9
9
  import { spawn } from 'child_process';
10
10
  import { readFileSync, mkdirSync, writeFileSync, existsSync, readdirSync, statSync, watch, rmSync } from 'fs';
@@ -849,6 +849,7 @@ var trailingColumnsOf = (items) => items.reduce(
849
849
  }),
850
850
  { threads: 0, size: 0, age: 0 }
851
851
  );
852
+ var numberColumnsOf = (items) => items.reduce((w, item) => Math.max(w, cellsOf(`#${item.number}`)), 0) + 2;
852
853
  var sectionShedOf = (rows, context) => rows.reduce((shed, row) => {
853
854
  const { givingUp } = layoutOf({ ...context, ...row });
854
855
  return {
@@ -865,9 +866,11 @@ var layoutOf = ({
865
866
  uniformLabels = [],
866
867
  announcements = [],
867
868
  columns,
868
- shed = {}
869
+ shed = {},
870
+ numberCols
869
871
  }) => {
870
- const numStr = `#${item.number}`.padEnd(7);
872
+ const numCols = numberCols ?? numberColumnsOf([item]);
873
+ const numStr = `#${item.number}`.padEnd(numCols);
871
874
  const showAuthor = !!item.author && item.author !== login;
872
875
  const sizeParts = sizePartsOf(item);
873
876
  const unresolvedLabel = threadsLabelOf(item);
@@ -911,7 +914,7 @@ var layoutOf = ({
911
914
  const author = showAuthor && !givingUp.author ? ` by ${item.author}`.length : 0;
912
915
  const pills = announcements.reduce((w, a) => w + 2 + a.label.length, 0);
913
916
  const cell = labelCell();
914
- return 2 + prefix.length + 2 + 2 + 7 + (cell ? 2 + cell.length + 1 : 0) + (givingUp.repo ? 0 : repoLabel.length) + author + block + pills + pillCaps + 4;
917
+ return 2 + prefix.length + 2 + 2 + numCols + (cell ? 2 + cell.length + 1 : 0) + (givingUp.repo ? 0 : repoLabel.length) + author + block + pills + pillCaps + 4;
915
918
  };
916
919
  const MIN_TITLE = 24;
917
920
  for (const give of [
@@ -953,7 +956,8 @@ var PrRow = ({
953
956
  motion,
954
957
  announcements = [],
955
958
  columns,
956
- shed
959
+ shed,
960
+ numberCols
957
961
  }) => {
958
962
  const backdropped = useBackdropped();
959
963
  const { glyph: healthIcon, color: healthColor2 } = displayFor(item.health);
@@ -983,7 +987,8 @@ var PrRow = ({
983
987
  uniformLabels,
984
988
  announcements,
985
989
  columns,
986
- shed
990
+ shed,
991
+ numberCols
987
992
  });
988
993
  return /* @__PURE__ */ jsxs(Box, { width: cols, children: [
989
994
  /* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
@@ -997,7 +1002,10 @@ var PrRow = ({
997
1002
  bold: active || motion === "arriving",
998
1003
  dimColor: motion === "departing" || motion === "withdrawn",
999
1004
  strikethrough: motion === "withdrawn",
1000
- children: truncate(item.title, titleMax) + " "
1005
+ children: truncate(
1006
+ item.needsYou?.decision ? item.needsYou.decision : item.title,
1007
+ titleMax
1008
+ ) + " "
1001
1009
  }
1002
1010
  ),
1003
1011
  labelLabel ? /* @__PURE__ */ jsx(Text3, { color: colors.secondary, children: labelLabel + " " }) : null,
@@ -1516,9 +1524,7 @@ var reposInSections = (sections) => [
1516
1524
  )
1517
1525
  ].sort();
1518
1526
  var moveCursor = (items, current, dir) => {
1519
- let next = current + dir;
1520
- while (next >= 0 && next < items.length && items[next].kind === "subgroup-header")
1521
- next += dir;
1527
+ const next = current + dir;
1522
1528
  if (next < 0 || next >= items.length) return current;
1523
1529
  return next;
1524
1530
  };
@@ -1594,6 +1600,28 @@ var treeUrls = (items, i) => {
1594
1600
  }
1595
1601
  return urls;
1596
1602
  };
1603
+ var bandUrls = (items, i) => {
1604
+ const urls = [];
1605
+ for (let j = i + 1; j < items.length; j += 1) {
1606
+ const item = items[j];
1607
+ if (item.kind === "subgroup-header") break;
1608
+ if (item.kind === "show-more") {
1609
+ for (const child of item.hidden) if (child.url) urls.push(child.url);
1610
+ continue;
1611
+ }
1612
+ const url = item.url;
1613
+ if (url) urls.push(url);
1614
+ }
1615
+ return urls;
1616
+ };
1617
+ var copyUrls = (items, i) => {
1618
+ const item = items[i];
1619
+ if (!item) return [];
1620
+ if (item.kind === "repo-header") return groupUrls(items, i);
1621
+ if (item.kind === "subgroup-header") return bandUrls(items, i);
1622
+ const url = item.url;
1623
+ return url ? [url] : [];
1624
+ };
1597
1625
  var gapsAbove = (items, i) => {
1598
1626
  const item = items[i];
1599
1627
  if (!item || i === 0) return false;
@@ -1820,6 +1848,7 @@ var FRAME_PAD_X = 1;
1820
1848
  var FRAME_CHROME_COLS = 2 + FRAME_PAD_X * 2;
1821
1849
  var COLS = (process.stdout.columns ?? 120) - FRAME_CHROME_COLS;
1822
1850
  var MODAL_CHROME_COLS = 2 + 1 * 2;
1851
+ var ROW_MAX_COLS = 140;
1823
1852
  var OVERLAY_BG = "#22222e";
1824
1853
  var workCount = (s) => {
1825
1854
  let n = 0;
@@ -1994,7 +2023,10 @@ var buildActions = (item, login, showFlash, jiraBase, jiraKeyRe, jiraTransitions
1994
2023
  (e) => {
1995
2024
  showFlash(`\u2717 #${item.number}: ${explainGhAction(e)}`);
1996
2025
  onRefresh?.();
1997
- ext?.onSettled?.(item, { ok: false, reason: firstLine(e) });
2026
+ ext?.onSettled?.(item, {
2027
+ ok: false,
2028
+ reason: firstLine(e)
2029
+ });
1998
2030
  }
1999
2031
  );
2000
2032
  }
@@ -2076,7 +2108,10 @@ var buildActions = (item, login, showFlash, jiraBase, jiraKeyRe, jiraTransitions
2076
2108
  (e) => {
2077
2109
  showFlash(`\u2717 Close failed \u2014 restoring #${item.number}`);
2078
2110
  onRefresh?.();
2079
- ext?.onSettled?.(item, { ok: false, reason: firstLine(e) });
2111
+ ext?.onSettled?.(item, {
2112
+ ok: false,
2113
+ reason: firstLine(e)
2114
+ });
2080
2115
  }
2081
2116
  );
2082
2117
  }
@@ -2132,7 +2167,10 @@ var buildActions = (item, login, showFlash, jiraBase, jiraKeyRe, jiraTransitions
2132
2167
  (e) => {
2133
2168
  showFlash(`\u2717 Close failed \u2014 restoring #${item.number}`);
2134
2169
  onRefresh?.();
2135
- ext?.onSettled?.(item, { ok: false, reason: firstLine(e) });
2170
+ ext?.onSettled?.(item, {
2171
+ ok: false,
2172
+ reason: firstLine(e)
2173
+ });
2136
2174
  }
2137
2175
  );
2138
2176
  }
@@ -2351,7 +2389,8 @@ var ItemRow = ({
2351
2389
  markerCols = 0,
2352
2390
  uniformLabels = [],
2353
2391
  columns,
2354
- shed
2392
+ shed,
2393
+ numberCols
2355
2394
  }) => {
2356
2395
  const backdropped = useBackdropped();
2357
2396
  const transient = leaving ? "out" : refreshMark;
@@ -2362,7 +2401,8 @@ var ItemRow = ({
2362
2401
  return /* @__PURE__ */ jsx(RepoHeaderRow, { repo: item.repo, gap: gap ?? false, active });
2363
2402
  if (item.kind === "subgroup-header")
2364
2403
  return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
2365
- /* @__PURE__ */ jsx(Text3, { color: colors.accent, bold: true, children: " \xBB " }),
2404
+ /* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
2405
+ /* @__PURE__ */ jsx(Text3, { color: colors.accent, bold: true, children: "\xBB " }),
2366
2406
  /* @__PURE__ */ jsx(Text3, { bold: true, children: item.label })
2367
2407
  ] });
2368
2408
  if (item.kind === "show-more")
@@ -2444,6 +2484,7 @@ var ItemRow = ({
2444
2484
  uniformLabels,
2445
2485
  columns,
2446
2486
  shed,
2487
+ numberCols,
2447
2488
  icon,
2448
2489
  motion,
2449
2490
  announcements
@@ -2859,17 +2900,7 @@ var BrowseScreen = ({
2859
2900
  s.items.length - 1
2860
2901
  );
2861
2902
  if (c < 0) return [s.id, 0];
2862
- return [
2863
- s.id,
2864
- // Only `subgroup-header`, which is the one kind the arrows refuse to
2865
- // stand on — `moveCursor` skips it and nothing else. A REPO header is
2866
- // selectable on purpose: it opens the repo and `C` copies the group,
2867
- // and the footer advertises both. Stepping off it here meant that
2868
- // standing on a repo and pressing `r` moved you onto an issue, every
2869
- // single time, and the rule predated repo headers being selectable
2870
- // at all.
2871
- s.items[c]?.kind === "subgroup-header" ? moveCursor(s.items, c, 1) : c
2872
- ];
2903
+ return [s.id, c];
2873
2904
  })
2874
2905
  )
2875
2906
  );
@@ -2967,11 +2998,19 @@ var BrowseScreen = ({
2967
2998
  const railCols = railWidth(COLS);
2968
2999
  const listCols = showRail ? COLS - railCols : COLS;
2969
3000
  const trailingColumns = trailingColumnsOf(labelBearing);
3001
+ const numberCols = numberColumnsOf(labelBearing);
3002
+ const rowCols = Math.min(listCols, ROW_MAX_COLS);
2970
3003
  const trailingShed = sectionShedOf(
2971
3004
  section.items.flatMap(
2972
3005
  (item, i) => item.kind === "pr" || item.kind === "issue" ? [{ item, prefix: treePrefix(section.items, i) }] : []
2973
3006
  ),
2974
- { login, cols: listCols, uniformLabels, columns: trailingColumns }
3007
+ {
3008
+ login,
3009
+ cols: rowCols,
3010
+ uniformLabels,
3011
+ columns: trailingColumns,
3012
+ numberCols
3013
+ }
2975
3014
  );
2976
3015
  const [sparkFrame, setSparkFrame] = useState(0);
2977
3016
  const sparkling = (mergedUrls?.length ?? 0) > 0 || (leavingUrls?.length ?? 0) > 0 || // Any MARKED TAB, not just rows on screen. The scope used to be this tab's
@@ -3198,8 +3237,10 @@ var BrowseScreen = ({
3198
3237
  return;
3199
3238
  }
3200
3239
  if (input === "c") {
3201
- clipboard(repoUrl);
3202
- showFlash(`\u2713 Copied URL for ${repo}`);
3240
+ const urls = copyUrls(section.items, cursor);
3241
+ if (urls.length === 0) return;
3242
+ clipboard(urls.join("\n"));
3243
+ showFlash(`\u2713 Copied ${urls.length} link${urls.length === 1 ? "" : "s"}`);
3203
3244
  return;
3204
3245
  }
3205
3246
  if (input === "C" || input === "O") {
@@ -3218,7 +3259,16 @@ var BrowseScreen = ({
3218
3259
  }
3219
3260
  return;
3220
3261
  }
3221
- if (!activeItem || activeItem.kind === "subgroup-header") return;
3262
+ if (activeItem?.kind === "subgroup-header") {
3263
+ if (input === "c") {
3264
+ const urls = copyUrls(section.items, cursor);
3265
+ if (urls.length === 0) return;
3266
+ clipboard(urls.join("\n"));
3267
+ showFlash(`\u2713 Copied ${urls.length} link${urls.length === 1 ? "" : "s"}`);
3268
+ }
3269
+ return;
3270
+ }
3271
+ if (!activeItem) return;
3222
3272
  if (key.return && activeItem.kind === "show-more") {
3223
3273
  setLocalSections(
3224
3274
  (prev) => prev.map((s) => ({
@@ -3410,6 +3460,11 @@ var BrowseScreen = ({
3410
3460
  menu.open(actions);
3411
3461
  }
3412
3462
  });
3463
+ const headerLinks = activeItem?.kind === "repo-header" || activeItem?.kind === "subgroup-header" ? copyUrls(section.items, cursor).length : 0;
3464
+ const headerHint = [
3465
+ "c",
3466
+ `copy ${headerLinks} link${headerLinks === 1 ? "" : "s"}`
3467
+ ];
3413
3468
  const hints = railActive ? (
3414
3469
  // The rail's own keymap while it holds focus, not the list's with a line
3415
3470
  // bolted on. A footer advertising `m actions` beside a cursor that cannot
@@ -3429,7 +3484,13 @@ var BrowseScreen = ({
3429
3484
  ["\u2190\u2192", "tab"],
3430
3485
  ["\u21B5", "open repo"],
3431
3486
  ["o", "browser"],
3432
- ["C", "copy group"],
3487
+ headerHint,
3488
+ ["?", "help"],
3489
+ ["q", "quit"]
3490
+ ] : activeItem?.kind === "subgroup-header" ? [
3491
+ ["\u2191\u2193", "nav"],
3492
+ ["\u2190\u2192", "tab"],
3493
+ headerHint,
3433
3494
  ["?", "help"],
3434
3495
  ["q", "quit"]
3435
3496
  ] : [
@@ -3667,11 +3728,12 @@ var BrowseScreen = ({
3667
3728
  prefix: treePrefix(section.items, viewStart + i),
3668
3729
  parent: item.kind === "task" && depthOf(section.items[viewStart + i + 1]) > depthOf(item),
3669
3730
  sparkFrame,
3670
- cols: listCols,
3731
+ cols: item.kind === "pr" || item.kind === "issue" ? rowCols : listCols,
3671
3732
  markerCols,
3672
3733
  uniformLabels,
3673
3734
  columns: trailingColumns,
3674
3735
  shed: trailingShed,
3736
+ numberCols,
3675
3737
  gap: i > 0 && gapsAbove(section.items, viewStart + i)
3676
3738
  },
3677
3739
  `${viewStart + i}:${rowKey(item)}`
@@ -4260,4 +4322,4 @@ var matchesFilter = (repo, filter) => {
4260
4322
  };
4261
4323
  var parsePatterns = (value) => value.split(",").map((p) => p.trim()).filter(Boolean);
4262
4324
 
4263
- export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, MIN_SIDEBAR_COLS, PrRow, SIDEBAR_COLS, SidePanel, StatusStripLine, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, railHeights, railRowsOf, railWidth, railsOf, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sectionShedOf, signatureOf, stripGlyph, stripLayout, stripSignature, toCiStatusState, trailingColumnsOf, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
4325
+ export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, MIN_SIDEBAR_COLS, PrRow, SIDEBAR_COLS, SidePanel, StatusStripLine, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, numberColumnsOf, openInTab, parsePatterns, railCapacity, railHeights, railRowsOf, railWidth, railsOf, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sectionShedOf, signatureOf, stripGlyph, stripLayout, stripSignature, toCiStatusState, trailingColumnsOf, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/gh-ink",
3
- "version": "0.63.0",
3
+ "version": "0.65.0",
4
4
  "description": "Ink components for rendering GitHub PR review comments and health — controlled, presentation-only, built on @kud/ink-ui and fed by @kud/gh.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -48,8 +48,8 @@
48
48
  "react": ">=19"
49
49
  },
50
50
  "dependencies": {
51
- "@kud/gh": "0.18.0",
52
- "@kud/gh-workflow": "0.13.1",
51
+ "@kud/gh": "0.19.0",
52
+ "@kud/gh-workflow": "0.14.0",
53
53
  "@kud/ink-ui": "0.31.0",
54
54
  "zx": "8.8.5"
55
55
  },