@kud/gh-ink 0.74.0 → 0.75.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/README.md +25 -0
- package/dist/index.d.ts +133 -4
- package/dist/index.js +167 -11
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -61,6 +61,31 @@ codepoints; sibling host verbs should match them rather than invent neighbours:
|
|
|
61
61
|
| Unsubscribe / Mute / Remove reviewer | U+F478 / U+F466 / U+F468 |
|
|
62
62
|
| Close PR / and delete / issue | U+F4DC / U+F48E / U+F41D |
|
|
63
63
|
|
|
64
|
+
## Inbox focus slot and tab icons
|
|
65
|
+
|
|
66
|
+
`App` draws one standing row directly above the tab strip for whatever the
|
|
67
|
+
reader should look at next. The fetch result carries it as
|
|
68
|
+
`focus?: FocusSlot | null`: absent means the host has no focus feature and no
|
|
69
|
+
row is drawn; `null` means nothing to point at and draws the dim empty line.
|
|
70
|
+
It rides the fetch (and the cache beside the rows) because it goes stale the
|
|
71
|
+
same way they do.
|
|
72
|
+
|
|
73
|
+
| Prop / field | What |
|
|
74
|
+
| ------------------ | --------------------------------------------------------------------------------------------------- |
|
|
75
|
+
| `focusLabel` | What to call the row (default `focus`). Passing this or `focusEmpty` reserves the row from first paint. |
|
|
76
|
+
| `focusEmpty` | The empty sentence, drawn dim after the label when focus comes back `null`. |
|
|
77
|
+
| `FocusSlot` | `label`, `ref` (a ticket key, or a PR-style `#427`), `title`, `reason`, optional `marker` (the host's priority glyph), `mark`/`markColor`/`refColor` overrides, and `target: { tab, url }`. |
|
|
78
|
+
| `g` | Jumps to `focus.target`: switches to that tab and lands the cursor on that row, opening a collapsed tail it is folded into. Listed in the `?` legend only while a focus is on screen. |
|
|
79
|
+
|
|
80
|
+
A row whose url matches the target draws the mark in a fixed gutter between
|
|
81
|
+
the tree glyph and the marker cell; every other row holds two blanks there, so
|
|
82
|
+
the mark moves nothing sideways. Without a focus the rows draw what they
|
|
83
|
+
always drew.
|
|
84
|
+
|
|
85
|
+
Tabs take an optional `Section.icon`, passed through to ink-ui's
|
|
86
|
+
`TabItem.icon`: one glyph naming the tab beside its label, which is also what
|
|
87
|
+
an inactive tab folds down to when the strip does not fit its width.
|
|
88
|
+
|
|
64
89
|
## Development
|
|
65
90
|
|
|
66
91
|
```sh
|
package/dist/index.d.ts
CHANGED
|
@@ -179,6 +179,94 @@ declare const SidePanel: ({ sidebar, liveLabel, width, height, focused, cursor,
|
|
|
179
179
|
cursor?: number;
|
|
180
180
|
}) => React.JSX.Element;
|
|
181
181
|
|
|
182
|
+
/**
|
|
183
|
+
* The one thing the reader should look at next, in the host's words.
|
|
184
|
+
*
|
|
185
|
+
* Data, not vocabulary: `label` is the host's word for the row ("focus"), but
|
|
186
|
+
* everything else arrived over the wire — which ticket, what it says, where it
|
|
187
|
+
* lives — and goes stale the same way the rows do. That is why it rides the
|
|
188
|
+
* fetch result (and the cache beside the rows) rather than arriving as props.
|
|
189
|
+
*
|
|
190
|
+
* `undefined` (the field absent) means the host has no focus feature and draws
|
|
191
|
+
* no row at all; `null` means there is one and it currently has nothing to
|
|
192
|
+
* point at, which draws the dim empty line. The distinction matters because a
|
|
193
|
+
* host that never wired the feature must keep byte-identical output, while a
|
|
194
|
+
* host whose feature came back empty still owes the reader one line saying so.
|
|
195
|
+
*/
|
|
196
|
+
type FocusSlot = {
|
|
197
|
+
/** The mark in front of the row, accent by default. */
|
|
198
|
+
mark?: string;
|
|
199
|
+
/** The mark's colour. Defaults to the accent. */
|
|
200
|
+
markColor?: string;
|
|
201
|
+
/** What the row is a slot OF, in the host's words: `focus`, say. */
|
|
202
|
+
label: string;
|
|
203
|
+
/** The thing to look at: a ticket key, or a PR-style `#427`. */
|
|
204
|
+
ref: string;
|
|
205
|
+
/** The ref's colour. A `#` ref takes the accent, anything else the ticket. */
|
|
206
|
+
refColor?: string;
|
|
207
|
+
/** The row's own title, bold. Truncated to keep the line to one row. */
|
|
208
|
+
title: string;
|
|
209
|
+
/** Why this is the focus, dim, three spaces after the title. */
|
|
210
|
+
reason: string;
|
|
211
|
+
/** The host's priority glyph for the row, drawn in the default foreground. */
|
|
212
|
+
marker?: string;
|
|
213
|
+
/** Where `g` goes: the tab id and the row url. */
|
|
214
|
+
target: {
|
|
215
|
+
tab: string;
|
|
216
|
+
url: string;
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
declare const FOCUS_MARK = "\uDB81\uDCFE";
|
|
220
|
+
declare const DEFAULT_FOCUS_LABEL = "focus";
|
|
221
|
+
declare const DEFAULT_FOCUS_EMPTY = "nothing to focus on";
|
|
222
|
+
/**
|
|
223
|
+
* What one row draws in the focus gutter, resolved by the list. `undefined`
|
|
224
|
+
* means no focus is on screen and the row draws nothing — the branch is
|
|
225
|
+
* absent, not blank, so output without the feature is byte-identical. `null`
|
|
226
|
+
* holds two blank columns on a row the focus is not pointing at, so the one
|
|
227
|
+
* row that carries the mark does not shift its neighbours.
|
|
228
|
+
*/
|
|
229
|
+
type FocusGutter = {
|
|
230
|
+
mark: string;
|
|
231
|
+
color?: string;
|
|
232
|
+
} | null;
|
|
233
|
+
/**
|
|
234
|
+
* The gutter cell for a row url: the mark when this is the row `g` would land
|
|
235
|
+
* on, a blank holder on every other row while a focus is on screen, nothing at
|
|
236
|
+
* all without one. One function so the task rows and the PR rows cannot
|
|
237
|
+
* disagree about which row is marked.
|
|
238
|
+
*/
|
|
239
|
+
declare const focusCellFor: (focus: FocusSlot | null | undefined, url: string | undefined) => FocusGutter | undefined;
|
|
240
|
+
/**
|
|
241
|
+
* The ref's colour, for the one decision the frame cannot show. A `#427` is a
|
|
242
|
+
* pull request and takes the accent — the same orange the PR rows number
|
|
243
|
+
* themselves in — while a ticket key takes the ticket yellow. An explicit
|
|
244
|
+
* `refColor` wins over both, for a host whose refs follow another vocabulary.
|
|
245
|
+
*
|
|
246
|
+
* Exported pure because the test frame carries no escape codes: a colour that
|
|
247
|
+
* lived only in a tint would be a colour nobody can test for.
|
|
248
|
+
*/
|
|
249
|
+
declare const focusRefColor: (focus: Pick<FocusSlot, "ref" | "refColor">) => string;
|
|
250
|
+
/**
|
|
251
|
+
* One standing single-line row, the same height across loading / ready / empty
|
|
252
|
+
* so the tab strip below it never jumps — the same contract `StatusStripLine`
|
|
253
|
+
* keeps, and drawn in the same place, directly above the tabs.
|
|
254
|
+
*
|
|
255
|
+
* `undefined` while the first answer is out; `null` when the host answered
|
|
256
|
+
* with nothing to point at. Either prop (`label`/`empty`) reserves the row;
|
|
257
|
+
* with neither and no focus value the caller draws nothing at all.
|
|
258
|
+
*/
|
|
259
|
+
declare const FocusSlotLine: ({ focus, label, empty, width, }: {
|
|
260
|
+
/** `undefined` while the first answer is out; `null` when it came back empty. */
|
|
261
|
+
focus: FocusSlot | null | undefined;
|
|
262
|
+
/** What to call the row. The host's word; defaults to `focus`. */
|
|
263
|
+
label?: string;
|
|
264
|
+
/** The empty sentence, drawn dim after the label when focus is null. */
|
|
265
|
+
empty?: string;
|
|
266
|
+
/** Columns the row may use. */
|
|
267
|
+
width: number;
|
|
268
|
+
}) => React.JSX.Element;
|
|
269
|
+
|
|
182
270
|
/**
|
|
183
271
|
* How this row is moving through the list right now.
|
|
184
272
|
*
|
|
@@ -270,6 +358,15 @@ type PrRowProps = {
|
|
|
270
358
|
* to the title rather than standing empty.
|
|
271
359
|
*/
|
|
272
360
|
gutter?: boolean;
|
|
361
|
+
/**
|
|
362
|
+
* The focus gutter, resolved by the list — see `focusCellFor`. `undefined`
|
|
363
|
+
* draws nothing at all (no focus feature, byte-identical to before); `null`
|
|
364
|
+
* holds two blank columns so the marked row does not shift its neighbours;
|
|
365
|
+
* a mark draws the focus glyph there in its colour. A fixed cell either way,
|
|
366
|
+
* for the same reason the cursor gutter is one: a mark that moved the title
|
|
367
|
+
* of exactly the row being watched would defeat its own purpose.
|
|
368
|
+
*/
|
|
369
|
+
focusCell?: FocusGutter;
|
|
273
370
|
};
|
|
274
371
|
/**
|
|
275
372
|
* The trailing block, in reading order: whose, how contested, how big, how
|
|
@@ -313,7 +410,9 @@ declare const trailingColumnsOf: (items: readonly GHItem[]) => TrailingColumns;
|
|
|
313
410
|
* three, and a six-digit number would have run straight into its title.
|
|
314
411
|
*/
|
|
315
412
|
declare const numberColumnsOf: (items: readonly GHItem[]) => number;
|
|
316
|
-
type LayoutInput = Pick<PrRowProps, "item" | "login" | "cols" | "prefix" | "uniformLabels" | "announcements" | "columns" | "shed" | "numberCols" | "gutter"
|
|
413
|
+
type LayoutInput = Pick<PrRowProps, "item" | "login" | "cols" | "prefix" | "uniformLabels" | "announcements" | "columns" | "shed" | "numberCols" | "gutter"> & {
|
|
414
|
+
focusGutter?: boolean;
|
|
415
|
+
};
|
|
317
416
|
/**
|
|
318
417
|
* Which trailing columns the section has to give up, so that every row gives up
|
|
319
418
|
* the same ones. Each row is laid out alone and the drops are unioned: if any
|
|
@@ -339,7 +438,7 @@ declare const sectionShedOf: (rows: readonly Pick<LayoutInput, "item" | "prefix"
|
|
|
339
438
|
* arrival, merge and departure belongs to whoever owns the list, and reaches
|
|
340
439
|
* the row as `icon`, `motion` and `announcements` after the decisions are made.
|
|
341
440
|
*/
|
|
342
|
-
declare const PrRow: ({ item, active, login, cols, selectionBg, icon: iconOverride, prefix, uniformLabels, motion, announcements, columns, shed, numberCols, gutter, }: PrRowProps) => React.JSX.Element;
|
|
441
|
+
declare const PrRow: ({ item, active, login, cols, selectionBg, icon: iconOverride, prefix, uniformLabels, motion, announcements, columns, shed, numberCols, gutter, focusCell, }: PrRowProps) => React.JSX.Element;
|
|
343
442
|
|
|
344
443
|
/**
|
|
345
444
|
* One state per thing, from a closed set the strip knows how to draw. The host
|
|
@@ -517,6 +616,16 @@ type CachedCockpit = {
|
|
|
517
616
|
* refresh — `i` did nothing and the footer did not even offer it.
|
|
518
617
|
*/
|
|
519
618
|
sidebar?: Rails;
|
|
619
|
+
/**
|
|
620
|
+
* The focus slot, when the host supplied one. Cached beside the rows because
|
|
621
|
+
* it is painted beside them: a launch that trusts the cache never refetches,
|
|
622
|
+
* so a focus left out of the file is a slot that stays on `loading…` until
|
|
623
|
+
* the next refresh — or never fills in at all.
|
|
624
|
+
*
|
|
625
|
+
* Absent reads as `undefined`: no focus feature, no row. `null` is a real
|
|
626
|
+
* answer ("nothing to focus on") and round-trips as one.
|
|
627
|
+
*/
|
|
628
|
+
focus?: FocusSlot | null;
|
|
520
629
|
};
|
|
521
630
|
declare const readCache: (key: string) => CachedCockpit | null;
|
|
522
631
|
declare const writeCache: (key: string, data: {
|
|
@@ -524,6 +633,7 @@ declare const writeCache: (key: string, data: {
|
|
|
524
633
|
login: string;
|
|
525
634
|
budget?: InboxBudget;
|
|
526
635
|
sidebar?: Rails;
|
|
636
|
+
focus?: FocusSlot | null;
|
|
527
637
|
}) => void;
|
|
528
638
|
|
|
529
639
|
/**
|
|
@@ -880,7 +990,7 @@ declare const ActionMenu: ({ item, actions, cursor, cols, }: {
|
|
|
880
990
|
cols?: number;
|
|
881
991
|
}) => React.JSX.Element;
|
|
882
992
|
declare const signatureOf: (sections: Section[]) => string;
|
|
883
|
-
declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraSetupHint, jiraTransitions, jiraTransitionsFor, tabForStatus, hasCiStatus, ciJob, ciFetcher, ciPollMs, stripFetcher, stripLabel, stripPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, onSettled, }: {
|
|
993
|
+
declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraSetupHint, jiraTransitions, jiraTransitionsFor, tabForStatus, hasCiStatus, ciJob, ciFetcher, ciPollMs, stripFetcher, stripLabel, stripPollMs, focusLabel, focusEmpty, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, onSettled, }: {
|
|
884
994
|
fetcher: () => Promise<{
|
|
885
995
|
sections: Section[];
|
|
886
996
|
login: string;
|
|
@@ -901,6 +1011,15 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
|
|
|
901
1011
|
* data that goes stale the same way the rows do.
|
|
902
1012
|
*/
|
|
903
1013
|
sidebar?: Rails;
|
|
1014
|
+
/**
|
|
1015
|
+
* What the reader should look at next, in the host's words — see
|
|
1016
|
+
* `FocusSlot`. Part of the fetch result for the same reason the rail is:
|
|
1017
|
+
* it goes stale with the rows, and the cache paints it beside them.
|
|
1018
|
+
*
|
|
1019
|
+
* Absent means the host has no focus feature and no row is drawn; `null`
|
|
1020
|
+
* means nothing to point at and draws the dim empty line.
|
|
1021
|
+
*/
|
|
1022
|
+
focus?: FocusSlot | null;
|
|
904
1023
|
}>;
|
|
905
1024
|
cacheKey?: string;
|
|
906
1025
|
/**
|
|
@@ -943,6 +1062,16 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
|
|
|
943
1062
|
/** What to call the row before its first answer arrives with a title. */
|
|
944
1063
|
stripLabel?: string;
|
|
945
1064
|
stripPollMs?: number;
|
|
1065
|
+
/**
|
|
1066
|
+
* What to call the focus row. Passing this (or `focusEmpty`) reserves the
|
|
1067
|
+
* row from the first paint — `loading…` until the fetch lands — while a
|
|
1068
|
+
* host that never wires the feature passes neither and draws nothing.
|
|
1069
|
+
* Vocabulary, not data: it never goes stale, so it is a prop rather than
|
|
1070
|
+
* part of the fetch result.
|
|
1071
|
+
*/
|
|
1072
|
+
focusLabel?: string;
|
|
1073
|
+
/** The empty sentence, drawn dim after the label when focus comes back null. */
|
|
1074
|
+
focusEmpty?: string;
|
|
946
1075
|
/**
|
|
947
1076
|
* A file something else touches when it has changed GitHub on your behalf —
|
|
948
1077
|
* a Claude session closing an issue, a script merging a PR. Touching it makes
|
|
@@ -995,4 +1124,4 @@ declare const matchesFilter: (repo: string, filter: RepoFilter) => boolean;
|
|
|
995
1124
|
*/
|
|
996
1125
|
declare const parsePatterns: (value: string) => string[];
|
|
997
1126
|
|
|
998
|
-
export { type Action, type ActionGroup, ActionMenu, App, COLS, type ChromeHints, type ChromeSpec, type ChromeState, CiStatusLine, type CiStatusState, type Command, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraAvailableTransition, type JiraTransition, type JiraTransitionsFor, type LiveLabel, LookupMiss, MIN_SIDEBAR_COLS, type MenuGap, type MenuRow, 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 TabForStatus, type TrailingColumns, type TrailingShed, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, isMenuGap, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, menuRowsOf, menuTone, 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, useChrome, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
|
1127
|
+
export { type Action, type ActionGroup, ActionMenu, App, COLS, type ChromeHints, type ChromeSpec, type ChromeState, CiStatusLine, type CiStatusState, type Command, CommentsPanel, type CommentsPanelProps, DEFAULT_FOCUS_EMPTY, DEFAULT_FOCUS_LABEL, type DetailContext, type ExplainSection, type ExtensionTarget, FOCUS_MARK, type FocusGutter, type FocusSlot, FocusSlotLine, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraAvailableTransition, type JiraTransition, type JiraTransitionsFor, type LiveLabel, LookupMiss, MIN_SIDEBAR_COLS, type MenuGap, type MenuRow, 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 TabForStatus, type TrailingColumns, type TrailingShed, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, focusCellFor, focusRefColor, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, isMenuGap, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, menuRowsOf, menuTone, 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, useChrome, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
package/dist/index.js
CHANGED
|
@@ -876,7 +876,8 @@ var layoutOf = ({
|
|
|
876
876
|
columns,
|
|
877
877
|
shed = {},
|
|
878
878
|
numberCols,
|
|
879
|
-
gutter = true
|
|
879
|
+
gutter = true,
|
|
880
|
+
focusGutter = false
|
|
880
881
|
}) => {
|
|
881
882
|
const numCols = numberCols ?? numberColumnsOf([item]);
|
|
882
883
|
const numStr = `#${item.number}`.padEnd(numCols);
|
|
@@ -923,7 +924,7 @@ var layoutOf = ({
|
|
|
923
924
|
);
|
|
924
925
|
const pills = announcements.reduce((w, a) => w + 2 + a.label.length, 0);
|
|
925
926
|
const cell = labelCell();
|
|
926
|
-
return (gutter ? 2 : 0) + prefix.length + 2 + 2 + numCols + (cell ? 2 + cell.length + 1 : 0) + (givingUp.repo ? 0 : repoLabel.length) + block + pills + pillCaps + 4;
|
|
927
|
+
return (gutter ? 2 : 0) + prefix.length + (focusGutter ? 2 : 0) + 2 + 2 + numCols + (cell ? 2 + cell.length + 1 : 0) + (givingUp.repo ? 0 : repoLabel.length) + block + pills + pillCaps + 4;
|
|
927
928
|
};
|
|
928
929
|
const MIN_TITLE = 24;
|
|
929
930
|
for (const give of [
|
|
@@ -969,7 +970,8 @@ var PrRow = ({
|
|
|
969
970
|
columns,
|
|
970
971
|
shed,
|
|
971
972
|
numberCols,
|
|
972
|
-
gutter = true
|
|
973
|
+
gutter = true,
|
|
974
|
+
focusCell
|
|
973
975
|
}) => {
|
|
974
976
|
const backdropped = useBackdropped();
|
|
975
977
|
const { glyph: healthIcon, color: healthColor2 } = displayFor(item.health);
|
|
@@ -1002,7 +1004,8 @@ var PrRow = ({
|
|
|
1002
1004
|
columns,
|
|
1003
1005
|
shed,
|
|
1004
1006
|
numberCols,
|
|
1005
|
-
gutter
|
|
1007
|
+
gutter,
|
|
1008
|
+
focusGutter: focusCell !== void 0
|
|
1006
1009
|
});
|
|
1007
1010
|
return (
|
|
1008
1011
|
// The wash paints every cell of the fixed-width row — an Ink Box's
|
|
@@ -1010,6 +1013,7 @@ var PrRow = ({
|
|
|
1010
1013
|
/* @__PURE__ */ jsxs(Box, { width: cols, backgroundColor: selectionBg, children: [
|
|
1011
1014
|
gutter ? /* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }) : null,
|
|
1012
1015
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
1016
|
+
focusCell !== void 0 ? focusCell ? /* @__PURE__ */ jsx(Text3, { color: focusCell.color, bold: true, children: `${focusCell.mark} ` }) : /* @__PURE__ */ jsx(Text3, { children: " " }) : null,
|
|
1013
1017
|
/* @__PURE__ */ jsx(Text3, { color, bold: true, children: icon + " " }),
|
|
1014
1018
|
/* @__PURE__ */ jsx(Text3, { color: turnColor, bold: turnIcon === "\u2190", children: turnIcon + " " }),
|
|
1015
1019
|
/* @__PURE__ */ jsx(Text3, { color: colors.accent, children: numStr }),
|
|
@@ -1372,7 +1376,7 @@ var lookupRows = (claim, lookup, query, start, openUrl) => {
|
|
|
1372
1376
|
|
|
1373
1377
|
// src/inbox/cache.ts
|
|
1374
1378
|
var cacheTtlMs = () => inboxConfig().cacheTtlMs;
|
|
1375
|
-
var CACHE_VERSION =
|
|
1379
|
+
var CACHE_VERSION = 6;
|
|
1376
1380
|
var cacheDir = () => join(
|
|
1377
1381
|
process.env.XDG_CACHE_HOME || join(homedir(), ".cache"),
|
|
1378
1382
|
inboxConfig().cacheNamespace
|
|
@@ -1383,11 +1387,14 @@ var readCache = (key) => {
|
|
|
1383
1387
|
const raw = JSON.parse(readFileSync(cacheFile(key), "utf8"));
|
|
1384
1388
|
if (raw?.version !== CACHE_VERSION) return null;
|
|
1385
1389
|
if (!Array.isArray(raw?.sections)) return null;
|
|
1390
|
+
const focusOk = raw.focus === void 0 || raw.focus === null || typeof raw.focus?.target?.tab === "string" && typeof raw.focus?.target?.url === "string";
|
|
1391
|
+
if (!focusOk) return null;
|
|
1386
1392
|
return {
|
|
1387
1393
|
sections: raw.sections,
|
|
1388
1394
|
login: raw.login ?? "",
|
|
1389
1395
|
at: raw.at ?? 0,
|
|
1390
1396
|
budget: raw.budget,
|
|
1397
|
+
...raw.focus !== void 0 ? { focus: raw.focus } : {},
|
|
1391
1398
|
...railsOf(raw.sidebar).every((s) => Array.isArray(s?.rows)) && raw.sidebar !== void 0 ? { sidebar: raw.sidebar } : {}
|
|
1392
1399
|
};
|
|
1393
1400
|
} catch {
|
|
@@ -1686,6 +1693,56 @@ var failureNotice = (failed) => {
|
|
|
1686
1693
|
const more = failed.length > 1 ? ` +${failed.length - 1} more` : "";
|
|
1687
1694
|
return `\u2717 Couldn't ${newest.action} ${newest.label}: ${newest.failure?.reason ?? "no reason reported"}${more} w restore`;
|
|
1688
1695
|
};
|
|
1696
|
+
var FOCUS_MARK = "\u{F04FE}";
|
|
1697
|
+
var DEFAULT_FOCUS_LABEL = "focus";
|
|
1698
|
+
var DEFAULT_FOCUS_EMPTY = "nothing to focus on";
|
|
1699
|
+
var focusCellFor = (focus, url) => {
|
|
1700
|
+
if (focus === void 0) return void 0;
|
|
1701
|
+
if (!focus || url !== focus.target.url) return null;
|
|
1702
|
+
return { mark: focus.mark ?? FOCUS_MARK, color: focus.markColor ?? colors.accent };
|
|
1703
|
+
};
|
|
1704
|
+
var focusRefColor = (focus) => focus.refColor ?? (focus.ref.startsWith("#") ? colors.accent : colors.ticket);
|
|
1705
|
+
var cells = (s) => [...s].length;
|
|
1706
|
+
var titleBudgetOf = (focus, label, width) => {
|
|
1707
|
+
const mark = focus.mark ?? FOCUS_MARK;
|
|
1708
|
+
const head = 2 + cells(mark) + 1 + cells(label) + 2 + (focus.marker ? cells(focus.marker) + 1 : 0) + cells(focus.ref) + 2;
|
|
1709
|
+
const tail = 3 + cells(focus.reason);
|
|
1710
|
+
const titleMax = width - head - tail;
|
|
1711
|
+
if (titleMax >= 1)
|
|
1712
|
+
return { title: truncate(focus.title, titleMax), reason: focus.reason };
|
|
1713
|
+
return {
|
|
1714
|
+
title: "",
|
|
1715
|
+
reason: truncate(focus.reason, Math.max(0, width - head - 3 - 1))
|
|
1716
|
+
};
|
|
1717
|
+
};
|
|
1718
|
+
var FocusSlotLine = ({
|
|
1719
|
+
focus,
|
|
1720
|
+
label = DEFAULT_FOCUS_LABEL,
|
|
1721
|
+
empty = DEFAULT_FOCUS_EMPTY,
|
|
1722
|
+
width
|
|
1723
|
+
}) => {
|
|
1724
|
+
if (focus === void 0)
|
|
1725
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1726
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
1727
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${label} loading\u2026` })
|
|
1728
|
+
] });
|
|
1729
|
+
if (focus === null)
|
|
1730
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1731
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${FOCUS_MARK} ` }),
|
|
1732
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${label} ${empty}` })
|
|
1733
|
+
] });
|
|
1734
|
+
const mark = focus.mark ?? FOCUS_MARK;
|
|
1735
|
+
const { title, reason } = titleBudgetOf(focus, label, width);
|
|
1736
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1737
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
1738
|
+
/* @__PURE__ */ jsx(Text, { color: focus.markColor ?? colors.accent, bold: true, children: `${mark} ` }),
|
|
1739
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${label} ` }),
|
|
1740
|
+
focus.marker ? /* @__PURE__ */ jsx(Text, { children: `${focus.marker} ` }) : null,
|
|
1741
|
+
/* @__PURE__ */ jsx(Text, { color: focusRefColor(focus), bold: true, children: `${focus.ref} ` }),
|
|
1742
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: title }),
|
|
1743
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${reason}` })
|
|
1744
|
+
] });
|
|
1745
|
+
};
|
|
1689
1746
|
var quietly = $({ quiet: true });
|
|
1690
1747
|
var isMenuGap = (row) => "gap" in row;
|
|
1691
1748
|
var rowLabelOf = (item) => item.kind === "task" ? item.ticket ?? item.key : item.kind === "pr" || item.kind === "issue" ? `#${item.number}` : "";
|
|
@@ -2911,7 +2968,8 @@ var ItemRow = ({
|
|
|
2911
2968
|
uniformLabels = [],
|
|
2912
2969
|
columns,
|
|
2913
2970
|
shed,
|
|
2914
|
-
numberCols
|
|
2971
|
+
numberCols,
|
|
2972
|
+
focus
|
|
2915
2973
|
}) => {
|
|
2916
2974
|
const backdropped = useBackdropped();
|
|
2917
2975
|
const selBg = selectionBackground(active, backdropped);
|
|
@@ -2955,12 +3013,16 @@ var ItemRow = ({
|
|
|
2955
3013
|
const transitIcon = pending ? PENDING_GLYPH : !transient ? " " : isDeparture(transient) ? TRANSIT_OUT_FRAMES[rampAt(TRANSIT_OUT_FRAMES.length)] : isArrival(transient) ? TRANSIT_IN_FRAMES[rampAt(TRANSIT_IN_FRAMES.length)] : "\u25C9";
|
|
2956
3014
|
const titleMax = Math.max(
|
|
2957
3015
|
1,
|
|
2958
|
-
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) -
|
|
3016
|
+
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) - // The focus gutter, priced only when it is drawn: two columns on every
|
|
3017
|
+
// url-bearing row while a focus is on screen, none at all without one.
|
|
3018
|
+
(focus !== void 0 ? 2 : 0) - 12
|
|
2959
3019
|
);
|
|
3020
|
+
const focusCell = focusCellFor(focus, item.url);
|
|
2960
3021
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, width: cols, backgroundColor: selBg, children: [
|
|
2961
3022
|
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2962
3023
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
2963
3024
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: parent ? "\u252C " : " " }),
|
|
3025
|
+
focusCell !== void 0 ? focusCell ? /* @__PURE__ */ jsx(Text3, { color: focusCell.color, bold: true, children: `${focusCell.mark} ` }) : /* @__PURE__ */ jsx(Text3, { children: " " }) : null,
|
|
2964
3026
|
pending ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: transitIcon + " " }) : /* @__PURE__ */ jsx(Text3, { bold: true, color: transient ? TRANSIT_COLOUR[transient] : void 0, children: transitIcon + " " }),
|
|
2965
3027
|
markerCols > 0 ? /* @__PURE__ */ jsx(Text3, { color: item.markerColor, children: (item.marker ?? "").padEnd(markerCols) + " " }) : null,
|
|
2966
3028
|
/* @__PURE__ */ jsx(Text3, { ...taskKeyStyle(), children: item.key + " " }),
|
|
@@ -3019,7 +3081,11 @@ var ItemRow = ({
|
|
|
3019
3081
|
numberCols,
|
|
3020
3082
|
icon,
|
|
3021
3083
|
motion,
|
|
3022
|
-
announcements
|
|
3084
|
+
announcements,
|
|
3085
|
+
focusCell: focusCellFor(
|
|
3086
|
+
focus,
|
|
3087
|
+
"url" in item ? item.url : void 0
|
|
3088
|
+
)
|
|
3023
3089
|
}
|
|
3024
3090
|
);
|
|
3025
3091
|
};
|
|
@@ -3223,6 +3289,7 @@ var LEGEND_FOOTNOTE = "Each item lands in the FIRST tab that claims it, so count
|
|
|
3223
3289
|
var HelpModal = ({
|
|
3224
3290
|
extensions,
|
|
3225
3291
|
hasJira,
|
|
3292
|
+
hasFocus,
|
|
3226
3293
|
tabHelp,
|
|
3227
3294
|
maxRows,
|
|
3228
3295
|
scroll = 0,
|
|
@@ -3257,6 +3324,7 @@ var HelpModal = ({
|
|
|
3257
3324
|
["f", "filter by repo"],
|
|
3258
3325
|
["r", "refresh"],
|
|
3259
3326
|
["w", "restore a change that failed"],
|
|
3327
|
+
...hasFocus ? [["g", "jump to focus"]] : [],
|
|
3260
3328
|
...extensionLegend(extensions),
|
|
3261
3329
|
["?", "this help"],
|
|
3262
3330
|
["q", "quit"]
|
|
@@ -3452,6 +3520,9 @@ var BrowseScreen = ({
|
|
|
3452
3520
|
ciJob,
|
|
3453
3521
|
stripState,
|
|
3454
3522
|
stripLabel,
|
|
3523
|
+
focus,
|
|
3524
|
+
focusLabel,
|
|
3525
|
+
focusEmpty,
|
|
3455
3526
|
tabHelp,
|
|
3456
3527
|
origin,
|
|
3457
3528
|
budget,
|
|
@@ -3503,12 +3574,13 @@ var BrowseScreen = ({
|
|
|
3503
3574
|
const filterActive = search != null || repoFilter.size > 0;
|
|
3504
3575
|
const reserveCiRow = ciStatusState != null;
|
|
3505
3576
|
const reserveStripRow = stripState != null;
|
|
3577
|
+
const reserveFocusRow = focusLabel !== void 0 || focusEmpty !== void 0 || focus !== void 0;
|
|
3506
3578
|
const ciStatus = ciStatusState?.kind === "ready" ? ciStatusState.status : null;
|
|
3507
3579
|
const listHeight = Math.max(
|
|
3508
3580
|
5,
|
|
3509
3581
|
// -10 rather than -8: the extra 2 are the frame's top and bottom border
|
|
3510
3582
|
// rows, so the tree never grows taller than the terminal inside the frame.
|
|
3511
|
-
rows - 10 - (filterActive ? 2 : 0) - (reserveCiRow ? 2 : 0) - (reserveStripRow ? 2 : 0)
|
|
3583
|
+
rows - 10 - (filterActive ? 2 : 0) - (reserveCiRow ? 2 : 0) - (reserveStripRow ? 2 : 0) - (reserveFocusRow ? 2 : 0)
|
|
3512
3584
|
);
|
|
3513
3585
|
useEffect(() => {
|
|
3514
3586
|
setLocalSections(applyWork(sections));
|
|
@@ -3654,7 +3726,10 @@ var BrowseScreen = ({
|
|
|
3654
3726
|
cols: rowCols,
|
|
3655
3727
|
uniformLabels,
|
|
3656
3728
|
columns: trailingColumns,
|
|
3657
|
-
numberCols
|
|
3729
|
+
numberCols,
|
|
3730
|
+
// Presence only: every row holds the same two gutter columns while a
|
|
3731
|
+
// focus is on screen, so the shed ladder prices the cost once for all.
|
|
3732
|
+
focusGutter: focus !== void 0
|
|
3658
3733
|
}
|
|
3659
3734
|
);
|
|
3660
3735
|
const [sparkFrame, setSparkFrame] = useState(0);
|
|
@@ -3894,6 +3969,56 @@ var BrowseScreen = ({
|
|
|
3894
3969
|
onRefresh?.();
|
|
3895
3970
|
return;
|
|
3896
3971
|
}
|
|
3972
|
+
if (input === "g" && focus) {
|
|
3973
|
+
const tabId = focus.target.tab;
|
|
3974
|
+
const at = localSections.findIndex((s) => s.id === tabId);
|
|
3975
|
+
if (at === -1) return;
|
|
3976
|
+
const drawn = (s) => {
|
|
3977
|
+
const one = search != null ? filterBySearch([s], search, login) : [s];
|
|
3978
|
+
const two = repoFilter.size > 0 ? filterByRepos(one, repoFilter, login) : one;
|
|
3979
|
+
return filterActive ? two[0]?.items ?? [] : s.items;
|
|
3980
|
+
};
|
|
3981
|
+
const urlOf = (i) => "url" in i ? i.url : void 0;
|
|
3982
|
+
let items = localSections[at].items;
|
|
3983
|
+
if (!items.some((i) => urlOf(i) === focus.target.url)) {
|
|
3984
|
+
const tail = items.find(
|
|
3985
|
+
(i) => i.kind === "show-more" && i.hidden.some((h) => h.url === focus.target.url)
|
|
3986
|
+
);
|
|
3987
|
+
if (!tail) {
|
|
3988
|
+
setTabIdx(at);
|
|
3989
|
+
return;
|
|
3990
|
+
}
|
|
3991
|
+
items = [
|
|
3992
|
+
...items.slice(0, items.indexOf(tail)),
|
|
3993
|
+
...tail.hidden,
|
|
3994
|
+
{
|
|
3995
|
+
kind: "show-less",
|
|
3996
|
+
toHide: tail.hidden,
|
|
3997
|
+
// The depth of the row it replaces, never a constant — a collapsed
|
|
3998
|
+
// row under a story sits deeper than 1, and pinning it breaks the
|
|
3999
|
+
// `treeUrls` walk exactly as the comment there warns.
|
|
4000
|
+
depth: depthOf(tail)
|
|
4001
|
+
},
|
|
4002
|
+
...items.slice(items.indexOf(tail) + 1)
|
|
4003
|
+
];
|
|
4004
|
+
const expanded = items;
|
|
4005
|
+
setLocalSections(
|
|
4006
|
+
(prev) => prev.map((s) => s.id === tabId ? { ...s, items: expanded } : s)
|
|
4007
|
+
);
|
|
4008
|
+
prevItems.current = { ...prevItems.current, [tabId]: expanded };
|
|
4009
|
+
}
|
|
4010
|
+
setTabIdx(at);
|
|
4011
|
+
const shown = drawn({ ...localSections[at], items });
|
|
4012
|
+
const dit = shown.findIndex((i) => urlOf(i) === focus.target.url);
|
|
4013
|
+
if (dit === -1) return;
|
|
4014
|
+
setCursors((p) => ({ ...p, [tabId]: dit }));
|
|
4015
|
+
setViewStarts((p) => {
|
|
4016
|
+
let vs = Math.min(p[tabId] ?? 0, withHeaders(shown, dit));
|
|
4017
|
+
while (dit >= vs + windowCount(shown, vs, listHeight)) vs++;
|
|
4018
|
+
return { ...p, [tabId]: vs };
|
|
4019
|
+
});
|
|
4020
|
+
return;
|
|
4021
|
+
}
|
|
3897
4022
|
const ext = extensionFor(input, extensions);
|
|
3898
4023
|
if (ext) {
|
|
3899
4024
|
onOpenExt?.(ext.id, extensionTargetFor(activeItem));
|
|
@@ -4309,6 +4434,7 @@ var BrowseScreen = ({
|
|
|
4309
4434
|
{
|
|
4310
4435
|
extensions,
|
|
4311
4436
|
hasJira: !!jiraBase,
|
|
4437
|
+
hasFocus: focus != null,
|
|
4312
4438
|
tabHelp,
|
|
4313
4439
|
maxRows: listHeight,
|
|
4314
4440
|
scroll: helpScroll,
|
|
@@ -4365,6 +4491,15 @@ var BrowseScreen = ({
|
|
|
4365
4491
|
width: COLS
|
|
4366
4492
|
}
|
|
4367
4493
|
) : null,
|
|
4494
|
+
reserveFocusRow ? /* @__PURE__ */ jsx(
|
|
4495
|
+
FocusSlotLine,
|
|
4496
|
+
{
|
|
4497
|
+
focus,
|
|
4498
|
+
label: focusLabel,
|
|
4499
|
+
empty: focusEmpty,
|
|
4500
|
+
width: COLS
|
|
4501
|
+
}
|
|
4502
|
+
) : null,
|
|
4368
4503
|
skippedForBudget ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
4369
4504
|
/* @__PURE__ */ jsx(Text3, { bold: true, color: colors.accent, children: " \u26A1 auto-refresh paused to save API budget" }),
|
|
4370
4505
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: " r refreshes anyway" })
|
|
@@ -4373,9 +4508,11 @@ var BrowseScreen = ({
|
|
|
4373
4508
|
Tabs,
|
|
4374
4509
|
{
|
|
4375
4510
|
active: section.id,
|
|
4511
|
+
width: COLS,
|
|
4376
4512
|
items: localSections.map((s) => ({
|
|
4377
4513
|
value: s.id,
|
|
4378
4514
|
label: s.label,
|
|
4515
|
+
icon: s.icon,
|
|
4379
4516
|
count: countOf(s.id),
|
|
4380
4517
|
/*
|
|
4381
4518
|
* The denominator, and only where it can still be true.
|
|
@@ -4461,6 +4598,7 @@ var BrowseScreen = ({
|
|
|
4461
4598
|
columns: trailingColumns,
|
|
4462
4599
|
shed: trailingShed,
|
|
4463
4600
|
numberCols,
|
|
4601
|
+
focus,
|
|
4464
4602
|
gap: i > 0 && gapsAbove(section.items, viewStart + i)
|
|
4465
4603
|
},
|
|
4466
4604
|
`${viewStart + i}:${rowKey(item)}`
|
|
@@ -4556,6 +4694,8 @@ var App = ({
|
|
|
4556
4694
|
stripFetcher,
|
|
4557
4695
|
stripLabel,
|
|
4558
4696
|
stripPollMs = 3e5,
|
|
4697
|
+
focusLabel,
|
|
4698
|
+
focusEmpty,
|
|
4559
4699
|
watchPath,
|
|
4560
4700
|
watchDebounceMs = 400,
|
|
4561
4701
|
// Zero by default, deliberately. A package that adds randomness to its own
|
|
@@ -4738,6 +4878,7 @@ var App = ({
|
|
|
4738
4878
|
)
|
|
4739
4879
|
};
|
|
4740
4880
|
if (fresh.budget) setBudget(fresh.budget);
|
|
4881
|
+
if (fresh.focus !== void 0) setFocus(fresh.focus);
|
|
4741
4882
|
if (fresh.sidebar !== void 0) setSidebar(fresh.sidebar);
|
|
4742
4883
|
if (cacheKey) writeCache(cacheKey, fresh);
|
|
4743
4884
|
setRefreshing(false);
|
|
@@ -4890,6 +5031,7 @@ var App = ({
|
|
|
4890
5031
|
displayedSections.current = cached.sections;
|
|
4891
5032
|
setFetchedAt(cached.at);
|
|
4892
5033
|
if (cached.sidebar) setSidebar(cached.sidebar);
|
|
5034
|
+
if (cached.focus !== void 0) setFocus(cached.focus);
|
|
4893
5035
|
setState({
|
|
4894
5036
|
phase: "browse",
|
|
4895
5037
|
sections: cached.sections,
|
|
@@ -4952,6 +5094,7 @@ var App = ({
|
|
|
4952
5094
|
if (shared && shared.at > firedAt) {
|
|
4953
5095
|
receive({ sections: shared.sections, login: shared.login });
|
|
4954
5096
|
if (shared.sidebar) setSidebar(shared.sidebar);
|
|
5097
|
+
if (shared.focus !== void 0) setFocus(shared.focus);
|
|
4955
5098
|
setFetchedAt(shared.at);
|
|
4956
5099
|
return;
|
|
4957
5100
|
}
|
|
@@ -4972,6 +5115,7 @@ var App = ({
|
|
|
4972
5115
|
);
|
|
4973
5116
|
const [appliedSummary, setAppliedSummary] = useState("");
|
|
4974
5117
|
const [sidebar, setSidebar] = useState(void 0);
|
|
5118
|
+
const [focus, setFocus] = useState(void 0);
|
|
4975
5119
|
const [skippedForBudget, setSkippedForBudget] = useState(false);
|
|
4976
5120
|
const [mergedUrls, setMergedUrls] = useState([]);
|
|
4977
5121
|
const [leavingUrls, setLeavingUrls] = useState([]);
|
|
@@ -5024,6 +5168,15 @@ var App = ({
|
|
|
5024
5168
|
width: COLS
|
|
5025
5169
|
}
|
|
5026
5170
|
) : null,
|
|
5171
|
+
focusLabel !== void 0 || focusEmpty !== void 0 ? /* @__PURE__ */ jsx(
|
|
5172
|
+
FocusSlotLine,
|
|
5173
|
+
{
|
|
5174
|
+
focus: void 0,
|
|
5175
|
+
label: focusLabel,
|
|
5176
|
+
empty: focusEmpty,
|
|
5177
|
+
width: COLS
|
|
5178
|
+
}
|
|
5179
|
+
) : null,
|
|
5027
5180
|
/* @__PURE__ */ jsx(
|
|
5028
5181
|
Box,
|
|
5029
5182
|
{
|
|
@@ -5136,6 +5289,9 @@ var App = ({
|
|
|
5136
5289
|
ciJob,
|
|
5137
5290
|
stripState: hasStrip ? stripState : void 0,
|
|
5138
5291
|
stripLabel,
|
|
5292
|
+
focus,
|
|
5293
|
+
focusLabel,
|
|
5294
|
+
focusEmpty,
|
|
5139
5295
|
tabHelp,
|
|
5140
5296
|
onOpenPr: (item) => {
|
|
5141
5297
|
setChromeSpec({});
|
|
@@ -5184,4 +5340,4 @@ var matchesFilter = (repo, filter) => {
|
|
|
5184
5340
|
};
|
|
5185
5341
|
var parsePatterns = (value) => value.split(",").map((p) => p.trim()).filter(Boolean);
|
|
5186
5342
|
|
|
5187
|
-
export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, LookupMiss, MIN_SIDEBAR_COLS, PrRow, SIDEBAR_COLS, SidePanel, StatusStripLine, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, isMenuGap, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, menuRowsOf, menuTone, 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, useChrome, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
|
5343
|
+
export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, DEFAULT_FOCUS_EMPTY, DEFAULT_FOCUS_LABEL, FOCUS_MARK, FocusSlotLine, HealthPanel, LookupMiss, MIN_SIDEBAR_COLS, PrRow, SIDEBAR_COLS, SidePanel, StatusStripLine, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, focusCellFor, focusRefColor, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, isMenuGap, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, menuRowsOf, menuTone, 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, useChrome, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/gh-ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.75.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",
|
|
@@ -44,17 +44,17 @@
|
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@kud/ink-ui": ">=0.
|
|
47
|
+
"@kud/ink-ui": ">=0.39.0 <1",
|
|
48
48
|
"ink": ">=7",
|
|
49
49
|
"react": ">=19"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@kud/gh": "0.21.0",
|
|
53
|
-
"@kud/gh-workflow": "0.
|
|
53
|
+
"@kud/gh-workflow": "0.17.0",
|
|
54
54
|
"zx": "8.8.5"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@kud/ink-ui": "0.
|
|
57
|
+
"@kud/ink-ui": "0.39.0",
|
|
58
58
|
"@types/node": "22.20.1",
|
|
59
59
|
"@types/react": "19.2.17",
|
|
60
60
|
"ink": "7.1.0",
|