@kud/gh-ink 0.19.0 → 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.
package/dist/index.d.ts CHANGED
@@ -311,4 +311,59 @@ declare const writeCache: (key: string, data: {
311
311
  login: string;
312
312
  }) => void;
313
313
 
314
- export { type Action, ActionMenu, type AnyItem, App, COLS, type CiStatus, CiStatusLine, type CiStatusState, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, type GHDetail, type GHItem, HealthPanel, type HealthPanelProps, type InboxExtension, type JiraTransition, type RepoHeader, type Section, type ShowLess, type ShowMore, type Standing, type SubgroupHeader, type TaskRow, buildActions, buildCheckoutCmd, clipboard, drillCmd, explainItem, filterByOrigin, filterByRepos, filterBySearch, fitCount, healthColor, healthDisplay, healthGlyph, healthLegend, insertRepoHeaders, itermRun, jumpToRepo, jumpToRepoPane, layoutGHItems, maxViewStart, moveCursor, openInTab, readCache, relativeTime, renderMarkdown, repoPriority, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sortByRecency, sortItems, toCiStatusState, topLevelCount, truncate, useActionMenu, whoseMove, windowCount, withHeaders, withoutItem, writeCache };
314
+ /**
315
+ * A named slice of the reader's repos. Two or more turn on the in-app toggle;
316
+ * one or none means an undivided set and no toggle at all.
317
+ *
318
+ * Named rather than boolean because the distinction was never a property of a
319
+ * repo — it is whatever separation the reader actually keeps, and a boolean
320
+ * leaves a third slice nowhere to go.
321
+ */
322
+ type RepoProfile = {
323
+ /** Stable id — what `--profile=<name>` selects. */
324
+ name: string;
325
+ /** Shown on the toggle. Defaults to `name`. */
326
+ label?: string;
327
+ /** Which repos belong to this profile. */
328
+ match: (repo: string) => boolean;
329
+ /** Where this profile's checkouts live, if it keeps its own directory. */
330
+ checkoutDir?: string;
331
+ };
332
+ type InboxConfig = {
333
+ /**
334
+ * Repo ranking, best first. An entry ending in `/` matches by owner prefix,
335
+ * anything else must equal `owner/name` exactly — so a single repo can outrank
336
+ * the owner that contains it. Repos matching nothing sort last, together.
337
+ */
338
+ repoPriority: readonly string[];
339
+ profiles: readonly RepoProfile[];
340
+ /**
341
+ * Fallback directory holding checkouts, for repos in no profile that names one
342
+ * of its own. Unset means local checkouts are not resolved at all, which is
343
+ * correct for a host that only ever opens things in a browser.
344
+ */
345
+ checkoutDir?: string;
346
+ /**
347
+ * Directory name the on-disk cache lives under, inside the platform cache
348
+ * root. Defaults to this package's name — a library has no business claiming a
349
+ * directory named after whichever tool happens to embed it, and two hosts on
350
+ * one machine would otherwise share a cache keyed only by section name.
351
+ */
352
+ cacheNamespace: string;
353
+ };
354
+ /** Supply the host's opinions. Call once, before rendering. */
355
+ declare const configureInbox: (config: Partial<InboxConfig>) => void;
356
+ declare const inboxConfig: () => InboxConfig;
357
+ /** Test seam — restores the empty defaults. */
358
+ declare const resetInboxConfig: () => void;
359
+ /** The profile a repo belongs to, or null when none claims it. */
360
+ declare const profileOf: (repo: string) => RepoProfile | null;
361
+ /**
362
+ * Where checkouts are searched, in order: every profile that names its own
363
+ * directory, then the fallback. Deduped, since the ordinary single-directory
364
+ * case points them all at the same place. Empty when nothing is configured —
365
+ * callers treat that as "not checked out locally", which it truthfully is.
366
+ */
367
+ declare const checkoutDirs: () => string[];
368
+
369
+ export { type Action, ActionMenu, type AnyItem, App, COLS, type CiStatus, CiStatusLine, type CiStatusState, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, type GHDetail, type GHItem, HealthPanel, type HealthPanelProps, type InboxConfig, type InboxExtension, type JiraTransition, type RepoHeader, type RepoProfile, type Section, type ShowLess, type ShowMore, type Standing, type SubgroupHeader, type TaskRow, buildActions, buildCheckoutCmd, checkoutDirs, clipboard, configureInbox, drillCmd, explainItem, filterByOrigin, filterByRepos, filterBySearch, fitCount, healthColor, healthDisplay, healthGlyph, healthLegend, inboxConfig, insertRepoHeaders, itermRun, jumpToRepo, jumpToRepoPane, layoutGHItems, maxViewStart, moveCursor, openInTab, profileOf, readCache, relativeTime, renderMarkdown, repoPriority, reposInSections, resetInboxConfig, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sortByRecency, sortItems, toCiStatusState, topLevelCount, truncate, useActionMenu, whoseMove, windowCount, withHeaders, withoutItem, writeCache };
package/dist/index.js CHANGED
@@ -606,9 +606,36 @@ var healthLegend = [
606
606
  ["merged", "Merged"],
607
607
  ["closed", "Closed"]
608
608
  ];
609
+
610
+ // src/inbox/config.ts
611
+ var EMPTY = {
612
+ repoPriority: [],
613
+ profiles: [],
614
+ cacheNamespace: "gh-ink"
615
+ };
616
+ var current = EMPTY;
617
+ var configureInbox = (config) => {
618
+ current = { ...EMPTY, ...config };
619
+ };
620
+ var inboxConfig = () => current;
621
+ var resetInboxConfig = () => {
622
+ current = EMPTY;
623
+ };
624
+ var profileOf = (repo) => current.profiles.find((p) => p.match(repo)) ?? null;
625
+ var checkoutDirs = () => [
626
+ .../* @__PURE__ */ new Set([
627
+ ...current.profiles.flatMap((p) => p.checkoutDir ?? []),
628
+ ...current.checkoutDir ? [current.checkoutDir] : []
629
+ ])
630
+ ];
631
+
632
+ // src/inbox/cache.ts
609
633
  var CACHE_TTL_MS = 12e4;
610
634
  var CACHE_VERSION = 2;
611
- var cacheDir = () => join(process.env.XDG_CACHE_HOME || join(homedir(), ".cache"), "ambre");
635
+ var cacheDir = () => join(
636
+ process.env.XDG_CACHE_HOME || join(homedir(), ".cache"),
637
+ inboxConfig().cacheNamespace
638
+ );
612
639
  var cacheFile = (key) => join(cacheDir(), `${key.replace(/[^a-z0-9._-]/gi, "-")}.json`);
613
640
  var readCache = (key) => {
614
641
  try {
@@ -840,14 +867,11 @@ var explainItem = (item, login) => {
840
867
  ];
841
868
  };
842
869
  var repoPriority = (repo) => {
843
- const profile = process.env.OS_PROFILE ?? "";
844
- if (profile === "work") {
845
- if (repo === "theorchard/orchardgo") return 0;
846
- if (repo.startsWith("theorchard/")) return 1;
847
- if (repo.startsWith("kud/")) return 2;
848
- return 3;
849
- }
850
- return repo.startsWith("kud/") ? 0 : 1;
870
+ const order = inboxConfig().repoPriority;
871
+ const i = order.findIndex(
872
+ (p) => p.endsWith("/") ? repo.startsWith(p) : repo === p
873
+ );
874
+ return i === -1 ? order.length : i;
851
875
  };
852
876
  var sortItems = (items) => [...items].sort((a, b) => {
853
877
  const pd = repoPriority(a.repo) - repoPriority(b.repo);
@@ -996,11 +1020,11 @@ var reposInSections = (sections) => [
996
1020
  sections.flatMap((s) => s.items).filter((i) => i.kind === "pr" || i.kind === "issue").map((i) => i.repo)
997
1021
  )
998
1022
  ].sort();
999
- var moveCursor = (items, current, dir) => {
1000
- let next = current + dir;
1023
+ var moveCursor = (items, current2, dir) => {
1024
+ let next = current2 + dir;
1001
1025
  while (next >= 0 && next < items.length && (items[next].kind === "repo-header" || items[next].kind === "subgroup-header"))
1002
1026
  next += dir;
1003
- if (next < 0 || next >= items.length) return current;
1027
+ if (next < 0 || next >= items.length) return current2;
1004
1028
  return next;
1005
1029
  };
1006
1030
  var itemLines = (item, isFirst) => (item.kind === "repo-header" || item.kind === "subgroup-header") && !isFirst ? 2 : 1;
@@ -1049,11 +1073,8 @@ var clipboard = (text) => {
1049
1073
  };
1050
1074
  var buildCheckoutCmd = async (repoFull, branch, login) => {
1051
1075
  const [repoOwner, repoName] = repoFull.split("/");
1052
- const projects = process.env.PROJECTS_DIR ?? `${process.env.HOME}/Projects`;
1053
- const profile = process.env.OS_PROFILE ?? "";
1054
- const isWorkRepo = profile === "work" && (repoFull.startsWith("theorchard/") || repoFull.startsWith("kud/") && (repoName ?? "").startsWith("theorchard-"));
1055
- const cloneBase = profile === "work" ? `${projects}/${isWorkRepo ? "work" : "home"}` : projects;
1056
- const searchDirs = profile === "work" ? [`${projects}/work`, `${projects}/home`] : [projects];
1076
+ const searchDirs = checkoutDirs();
1077
+ const cloneBase = profileOf(repoFull)?.checkoutDir ?? inboxConfig().checkoutDir ?? "";
1057
1078
  let repoPath = "";
1058
1079
  outer: for (const searchDir of searchDirs) {
1059
1080
  if (!existsSync(searchDir)) continue;
@@ -1108,9 +1129,7 @@ var buildCheckoutCmd = async (repoFull, branch, login) => {
1108
1129
  return cmd;
1109
1130
  };
1110
1131
  var resolveRepoPath = async (repoFull) => {
1111
- const projects = process.env.PROJECTS_DIR ?? `${process.env.HOME}/Projects`;
1112
- const profile = process.env.OS_PROFILE ?? "";
1113
- const searchDirs = profile === "work" ? [`${projects}/work`, `${projects}/home`] : [projects];
1132
+ const searchDirs = checkoutDirs();
1114
1133
  for (const searchDir of searchDirs) {
1115
1134
  if (!existsSync(searchDir)) continue;
1116
1135
  let entries;
@@ -2936,4 +2955,4 @@ var App = ({
2936
2955
  ] });
2937
2956
  };
2938
2957
 
2939
- export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, buildActions, buildCheckoutCmd, clipboard, drillCmd, explainItem, filterByOrigin, filterByRepos, filterBySearch, fitCount, healthColor, healthDisplay, healthGlyph, healthLegend, insertRepoHeaders, itermRun, jumpToRepo, jumpToRepoPane, layoutGHItems, maxViewStart, moveCursor, openInTab, readCache, relativeTime, renderMarkdown, repoPriority, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sortByRecency, sortItems, toCiStatusState, topLevelCount, truncate, useActionMenu, whoseMove, windowCount, withHeaders, withoutItem, writeCache };
2958
+ export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, buildActions, buildCheckoutCmd, checkoutDirs, clipboard, configureInbox, drillCmd, explainItem, filterByOrigin, filterByRepos, filterBySearch, fitCount, healthColor, healthDisplay, healthGlyph, healthLegend, inboxConfig, insertRepoHeaders, itermRun, jumpToRepo, jumpToRepoPane, layoutGHItems, maxViewStart, moveCursor, openInTab, profileOf, readCache, relativeTime, renderMarkdown, repoPriority, reposInSections, resetInboxConfig, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sortByRecency, sortItems, toCiStatusState, topLevelCount, truncate, useActionMenu, whoseMove, windowCount, withHeaders, withoutItem, writeCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/gh-ink",
3
- "version": "0.19.0",
3
+ "version": "0.20.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",