@kud/gh-ink 0.54.0 → 0.55.1

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
@@ -2,7 +2,7 @@ import React, { ReactNode } from 'react';
2
2
  import { PrComments, PrHealthData, PrCheck, Health } from '@kud/gh';
3
3
  import { StyledLine } from '@kud/ink-ui';
4
4
  import { AnyItem, Section, CiStatus, GHItem, OriginSplit } from '@kud/gh-workflow';
5
- export { AnyItem, CiStatus, GHDetail, GHItem, InboxConfig, Move, OriginSplit, PIN_MARK, RepoHeader, RepoProfile, Section, ShowLess, ShowMore, Standing, SubgroupHeader, TaskRow, checkoutDirs, configureInbox, filterByOrigin, filterByRepos, filterBySearch, impliedLabels, inboxConfig, insertRepoHeaders, labelPriority, layoutGHItems, profileOf, relativeTime, repoPriority, resetInboxConfig, sortByRecency, sortItems, whoseMove } from '@kud/gh-workflow';
5
+ 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';
6
6
 
7
7
  type CommentsPanelProps = {
8
8
  repo: string;
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import { readFileSync, mkdirSync, writeFileSync, existsSync, readdirSync, statSy
9
9
  import { join, dirname, basename } from 'path';
10
10
  import { homedir } from 'os';
11
11
  import { depthOf, checkoutDirs, profileOf, inboxConfig, relativeTime, filterBySearch, filterByRepos, filterByOrigin, PIN_MARK, sizeOf, sizePartsOf, impliedLabels, labelPriority } from '@kud/gh-workflow';
12
- export { PIN_MARK, checkoutDirs, configureInbox, filterByOrigin, filterByRepos, filterBySearch, impliedLabels, inboxConfig, insertRepoHeaders, labelPriority, layoutGHItems, profileOf, relativeTime, repoPriority, resetInboxConfig, sortByRecency, sortItems, whoseMove } from '@kud/gh-workflow';
12
+ 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';
13
13
 
14
14
  // src/components/comments-panel.tsx
15
15
  var ENTITIES = {
@@ -257,7 +257,8 @@ var commentLines = ({ author, body }, width, fileLink, indent = 0) => {
257
257
  { text: author, color: colors.accent, bold: true },
258
258
  { text: " " + "\u2500".repeat(fill), dim: true }
259
259
  ]
260
- }
260
+ },
261
+ { text: "" }
261
262
  ];
262
263
  const bodyLines = renderMarkdown(body, width - indent, fileLink);
263
264
  if (bodyLines.length === 0) lines.push({ text: pad + "(empty)", dim: true });
@@ -934,6 +935,66 @@ var tabsOfMarks = (sections, marks) => {
934
935
  }
935
936
  return out;
936
937
  };
938
+ var HOLD_MS = 5 * 60 * 1e3;
939
+ var anchorIndex = (prevItems, prevIndex, freshItems) => {
940
+ const freshAt = /* @__PURE__ */ new Map();
941
+ freshItems.forEach((item, i) => {
942
+ const key = keyOf(item);
943
+ if (key) freshAt.set(key, i);
944
+ });
945
+ for (let i = prevIndex - 1; i >= 0; i--) {
946
+ const key = keyOf(prevItems[i]);
947
+ const at = key === null ? void 0 : freshAt.get(key);
948
+ if (at !== void 0) return at + 1;
949
+ }
950
+ return Math.min(prevIndex, freshItems.length);
951
+ };
952
+ var reconcile = (prev, fresh, now, holdMs = HOLD_MS) => {
953
+ if (prev.length === 0) return fresh;
954
+ const present = /* @__PURE__ */ new Set();
955
+ for (const section of fresh)
956
+ for (const item of section.items) {
957
+ const key = keyOf(item);
958
+ if (key) present.add(key);
959
+ }
960
+ const bySection = /* @__PURE__ */ new Map();
961
+ const labels = /* @__PURE__ */ new Map();
962
+ prev.forEach((section, at) => {
963
+ if (section.sampled) return;
964
+ section.items.forEach((item, index) => {
965
+ if (item.kind !== "pr" && item.kind !== "issue") return;
966
+ const row = item;
967
+ if (present.has(row.url)) return;
968
+ const heldSince = row.heldSince ?? now;
969
+ if (now - heldSince > holdMs) return;
970
+ const held = { ...row, heldSince };
971
+ const list = bySection.get(section.id);
972
+ if (list) list.push({ item: held, index });
973
+ else bySection.set(section.id, [{ item: held, index }]);
974
+ labels.set(section.id, { label: section.label, at });
975
+ });
976
+ });
977
+ if (bySection.size === 0) return fresh;
978
+ const out = fresh.map((section) => {
979
+ const rows = bySection.get(section.id);
980
+ if (!rows) return section;
981
+ bySection.delete(section.id);
982
+ const prevItems = prev.find((s) => s.id === section.id)?.items ?? [];
983
+ const items = [...section.items];
984
+ for (const row of [...rows].sort((a, b) => a.index - b.index))
985
+ items.splice(anchorIndex(prevItems, row.index, items), 0, row.item);
986
+ return { ...section, items };
987
+ });
988
+ for (const [id, rows] of bySection) {
989
+ const { label, at } = labels.get(id);
990
+ out.splice(Math.min(at, out.length), 0, {
991
+ id,
992
+ label,
993
+ items: rows.sort((a, b) => a.index - b.index).map((r) => r.item)
994
+ });
995
+ }
996
+ return out;
997
+ };
937
998
  var quietly = $({ quiet: true });
938
999
  var healthSentence = (item) => {
939
1000
  const glyph = displayFor(item.health).glyph.trim();
@@ -1895,7 +1956,8 @@ var ItemRow = ({
1895
1956
  prefix = "",
1896
1957
  parent,
1897
1958
  sparkFrame = 0,
1898
- cols = COLS
1959
+ cols = COLS,
1960
+ markerCols = 0
1899
1961
  }) => {
1900
1962
  const backdropped = useBackdropped();
1901
1963
  const transient = leaving ? "out" : refreshMark;
@@ -1928,13 +1990,14 @@ var ItemRow = ({
1928
1990
  const transitIcon = !transient ? " " : isDeparture(transient) ? TRANSIT_OUT_FRAMES[rampAt(TRANSIT_OUT_FRAMES.length)] : isArrival(transient) ? TRANSIT_IN_FRAMES[rampAt(TRANSIT_IN_FRAMES.length)] : "\u25C9";
1929
1991
  const titleMax2 = Math.max(
1930
1992
  1,
1931
- cols - item.key.length - note.length - (item.pill ? pillWidth(item.pill) + 1 : 0) - (farewellLabel ? pillWidth(farewellLabel) + 2 : 0) - prefix.length - 12
1993
+ cols - item.key.length - note.length - (item.pill ? pillWidth(item.pill) + 1 : 0) - (farewellLabel ? pillWidth(farewellLabel) + 2 : 0) - prefix.length - (markerCols > 0 ? markerCols + 1 : 0) - 12
1932
1994
  );
1933
1995
  return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
1934
1996
  /* @__PURE__ */ jsx(Text3, { color: "cyan", children: active ? "\u276F " : " " }),
1935
1997
  /* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
1936
1998
  /* @__PURE__ */ jsx(Text3, { dimColor: true, children: parent ? "\u252C " : " " }),
1937
1999
  /* @__PURE__ */ jsx(Text3, { bold: true, color: transient ? TRANSIT_COLOUR[transient] : void 0, children: transitIcon + " " }),
2000
+ markerCols > 0 ? /* @__PURE__ */ jsx(Text3, { color: item.markerColor, children: (item.marker ?? "").padEnd(markerCols) + " " }) : null,
1938
2001
  /* @__PURE__ */ jsx(Text3, { color: colors.accent, bold: active, children: item.key + " " }),
1939
2002
  /* @__PURE__ */ jsx(
1940
2003
  Text3,
@@ -2511,6 +2574,10 @@ var BrowseScreen = ({
2511
2574
  const viewStart = viewStarts[activeId] ?? 0;
2512
2575
  const visibleCount = windowCount(section.items, viewStart, listHeight);
2513
2576
  const visibleItems = section.items.slice(viewStart, viewStart + visibleCount);
2577
+ const markerCols = section.items.reduce(
2578
+ (w, i) => i.kind === "task" ? Math.max(w, [...i.marker ?? ""].length) : w,
2579
+ 0
2580
+ );
2514
2581
  const hasMore = viewStart + visibleCount < section.items.length;
2515
2582
  const activeItem = section.items[cursor];
2516
2583
  const showFlash = (msg) => {
@@ -3130,6 +3197,7 @@ var BrowseScreen = ({
3130
3197
  parent: item.kind === "task" && depthOf(section.items[viewStart + i + 1]) > depthOf(item),
3131
3198
  sparkFrame,
3132
3199
  cols: listCols,
3200
+ markerCols,
3133
3201
  gap: i > 0 && gapsAbove(section.items, viewStart + i)
3134
3202
  },
3135
3203
  `${viewStart + i}:${rowKey(item)}`
@@ -3351,7 +3419,15 @@ var App = ({
3351
3419
  }
3352
3420
  setSkippedForBudget(false);
3353
3421
  if (manual) setRefreshing(true);
3354
- fetcher().then((fresh) => {
3422
+ fetcher().then((fetched) => {
3423
+ const fresh = {
3424
+ ...fetched,
3425
+ sections: reconcile(
3426
+ displayedSections.current,
3427
+ fetched.sections,
3428
+ Date.now()
3429
+ )
3430
+ };
3355
3431
  if (fresh.budget) setBudget(fresh.budget);
3356
3432
  if (fresh.sidebar !== void 0) setSidebar(fresh.sidebar);
3357
3433
  if (cacheKey) writeCache(cacheKey, fresh);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/gh-ink",
3
- "version": "0.54.0",
3
+ "version": "0.55.1",
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",
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@kud/gh": "0.16.0",
52
- "@kud/gh-workflow": "0.11.0",
52
+ "@kud/gh-workflow": "0.12.0",
53
53
  "@kud/ink-ui": "0.29.0",
54
54
  "zx": "8.8.5"
55
55
  },