@kud/gh-ink 0.57.1 → 0.59.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +126 -16
  2. package/dist/index.js +460 -166
  3. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -136,32 +136,112 @@ declare const counts: (row: SidebarRow, liveLabel?: LiveLabel) => string;
136
136
  */
137
137
  declare const railCapacity: (height: number, rows: number) => number;
138
138
  /**
139
- * A right-hand rail of initiatives, standing beside the list.
140
- *
141
- * Label first, facts beneath, because a roadmap is read by name: nobody thinks
142
- * "ACC-11312", they think "the OpenSearch migration". So the label is the
143
- * bright line and the key drops to the facts line as what it is — a reference
144
- * you follow, in the secondary tier. Two lines rather than one because both are
145
- * load-bearing and neither survives the other being cut: words with no key
146
- * cannot be opened, and a key with no words cannot be read at a glance.
139
+ * One rail, or several stacked in one column. A host with one thing to rail —
140
+ * initiatives — passes the one; a host with two kinds of container passes both,
141
+ * and the panel draws them in order under one rule, each with its own heading.
142
+ * A stack rather than a second prop because the second rail needs everything
143
+ * the first has — a heading, a window, a cursor — and nothing more.
144
+ */
145
+ type Rails = Sidebar | Sidebar[];
146
+ /** The stack as an array, whichever shape the host chose. */
147
+ declare const railsOf: (rails: Rails | undefined) => Sidebar[];
148
+ /** Every row of every section in order — the space the rail's cursor moves in. */
149
+ declare const railRowsOf: (rails: Rails | undefined) => SidebarRow[];
150
+ /**
151
+ * How the rail's height is shared out down a stack. Each section takes what it
152
+ * needs while that fits inside an even share of what is left, so a short
153
+ * section hands its surplus down rather than sitting beside a stripe of blank
154
+ * lines while the section under it says `+4 more`. Even shares rather than
155
+ * first-come, because the FIRST section is the one most likely to be long, and
156
+ * letting it fill the column would leave the second with a heading and nothing
157
+ * under it — a section that is visibly there and unreadable.
158
+ */
159
+ declare const railHeights: (height: number, rowCounts: number[]) => number[];
160
+ /**
161
+ * A right-hand rail standing beside the list: one section, or a stack of them.
147
162
  *
148
163
  * Presentational, like every other row renderer here: it DRAWS a cursor but does
149
164
  * not own one, and it never calls `useInput`. Where the cursor is, and whether
150
165
  * the arrows are pointed at this rail at all, are the host's state — which is
151
- * what lets a screen with two focus regions have exactly one of them lit.
166
+ * what lets a screen with two focus regions have exactly one of them lit. The
167
+ * cursor counts across the whole stack, in `railRowsOf` order, so the host
168
+ * moves one number and never learns where a section boundary falls.
152
169
  */
153
170
  declare const SidePanel: ({ sidebar, liveLabel, width, height, focused, cursor, }: {
154
- sidebar: Sidebar;
171
+ sidebar: Rails;
155
172
  liveLabel?: LiveLabel;
156
173
  /** From `railWidth`, so the list beside it can subtract the same number. */
157
174
  width?: number;
158
175
  height?: number;
159
176
  /** The arrows are pointed here, so this rail draws the cursor. */
160
177
  focused?: boolean;
161
- /** Which row the cursor is on. Only drawn while `focused`. */
178
+ /** Which row the cursor is on, counted across every section. Only drawn while `focused`. */
162
179
  cursor?: number;
163
180
  }) => React.JSX.Element;
164
181
 
182
+ /**
183
+ * One state per thing, from a closed set the strip knows how to draw. The host
184
+ * decides what "warn" means — an error-rate edge, a stale feed, a flaky build —
185
+ * and the strip only ever says it with a shape.
186
+ *
187
+ * `unknown` is a state and not the absence of one: "nothing heard from it" is
188
+ * a fact about the feed that a green tick would paper over, and a strip that
189
+ * draws an unmeasured thing as fine is the one failure it cannot afford.
190
+ */
191
+ type StripState = "ok" | "warn" | "fail" | "unknown";
192
+ type StripItem = {
193
+ /** The name on screen. Short — it is drawn once per item across one line. */
194
+ key: string;
195
+ state: StripState;
196
+ /**
197
+ * A second, independent alarm beside the state — a build on fire next to a
198
+ * service that is serving fine, say. Drawn as its own mark rather than folded
199
+ * into `state`, because the two answer different questions and a reader
200
+ * needs to see when they disagree.
201
+ */
202
+ alarm?: boolean;
203
+ /** Where `o` goes when this item is opened from a rail row. Unused here. */
204
+ url?: string;
205
+ };
206
+ type StatusStrip = {
207
+ /** What the row is a strip OF, in the host's words: `services`, say. */
208
+ title: string;
209
+ items: StripItem[];
210
+ /** When this snapshot was taken (ms). Drawn as an age at the end of the row. */
211
+ at?: number;
212
+ };
213
+ declare const stripGlyph: (state: StripState) => [string, string];
214
+ declare const ageLabel: (at: number | undefined, now?: number) => string;
215
+ /**
216
+ * The strip as plain text, at the width it has to fit. Exported so a test — or a
217
+ * host laying out its own row — can ask the same question the renderer asks.
218
+ *
219
+ * Wide: every item named with its mark, so the row reads as a roll call. Narrow:
220
+ * counts for what is fine, and names ONLY for what is not — the reader of a
221
+ * narrow terminal loses the roll call, never the failures. When even the
222
+ * failures do not fit, the worst few are named and the rest counted, so the
223
+ * row still says "and N more" rather than silently dropping the fourth fire.
224
+ */
225
+ declare const stripLayout: (strip: StatusStrip, width: number, now?: number) => {
226
+ parts: StripItem[] | null;
227
+ summary: string;
228
+ age: string;
229
+ };
230
+ /**
231
+ * A standing single-line row, the same height across loading / absent / ready
232
+ * so the content below it never jumps — the same contract `CiStatusLine` keeps,
233
+ * and drawn in the same place, because a reader learns one row of glances.
234
+ */
235
+ declare const StatusStripLine: ({ strip, label, width, now, }: {
236
+ /** `undefined` while the first poll is out; `null` when the host has nothing. */
237
+ strip: StatusStrip | null | undefined;
238
+ /** What to call the row before the data arrives with its own title. */
239
+ label?: string;
240
+ /** Columns the row may use. */
241
+ width: number;
242
+ now?: number;
243
+ }) => React.JSX.Element;
244
+
165
245
  declare const renderMarkdown: (raw: string, width: number, fileLink?: (path: string, line?: number) => string) => StyledLine[];
166
246
 
167
247
  declare const healthDisplay: Record<Health, {
@@ -178,6 +258,14 @@ type ExtensionTarget = {
178
258
  login: string;
179
259
  onRemove?: (item: AnyItem) => void;
180
260
  showFlash?: (msg: string) => void;
261
+ query?: string;
262
+ ticketKey?: string;
263
+ };
264
+ type Command = {
265
+ id: string;
266
+ title: string;
267
+ group?: string;
268
+ run: () => void | Promise<void>;
181
269
  };
182
270
  interface InboxExtension {
183
271
  id: string;
@@ -187,6 +275,7 @@ interface InboxExtension {
187
275
  scope?: "item" | "global";
188
276
  drills?: AnyItem["kind"][];
189
277
  body: (onExit: () => void, target?: ExtensionTarget) => ReactNode;
278
+ commands?: (target: ExtensionTarget) => Command[];
190
279
  }
191
280
 
192
281
  /**
@@ -225,14 +314,14 @@ type CachedCockpit = {
225
314
  * rail left out of the file is a rail that does not exist until the next
226
315
  * refresh — `i` did nothing and the footer did not even offer it.
227
316
  */
228
- sidebar?: Sidebar;
317
+ sidebar?: Rails;
229
318
  };
230
319
  declare const readCache: (key: string) => CachedCockpit | null;
231
320
  declare const writeCache: (key: string, data: {
232
321
  sections: Section[];
233
322
  login: string;
234
323
  budget?: InboxBudget;
235
- sidebar?: Sidebar;
324
+ sidebar?: Rails;
236
325
  }) => void;
237
326
 
238
327
  type DetailContext = {
@@ -413,6 +502,14 @@ type CiStatusState = {
413
502
  kind: "ready";
414
503
  status: CiStatus;
415
504
  };
505
+ type StripStatusState = {
506
+ kind: "loading";
507
+ } | {
508
+ kind: "ready";
509
+ strip: StatusStrip | null;
510
+ };
511
+ /** What the strip SAYS, ignoring when it said it. */
512
+ declare const stripSignature: (strip: StatusStrip | null) => string;
416
513
  declare const toCiStatusState: (status: CiStatus | null) => CiStatusState;
417
514
  declare const sameCiStatusState: (a: CiStatusState, b: CiStatusState) => boolean;
418
515
  declare const CiStatusLine: ({ state, job, }: {
@@ -437,7 +534,7 @@ declare const ActionMenu: ({ item, actions, cursor, }: {
437
534
  cursor: number;
438
535
  }) => React.JSX.Element;
439
536
  declare const signatureOf: (sections: Section[]) => string;
440
- declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraTransitions, hasCiStatus, ciJob, ciFetcher, ciPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, }: {
537
+ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraSetupHint, jiraTransitions, hasCiStatus, ciJob, ciFetcher, ciPollMs, stripFetcher, stripLabel, stripPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, }: {
441
538
  fetcher: () => Promise<{
442
539
  sections: Section[];
443
540
  login: string;
@@ -457,7 +554,7 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
457
554
  * Part of the fetch result rather than a static prop because it is data, and
458
555
  * data that goes stale the same way the rows do.
459
556
  */
460
- sidebar?: Sidebar;
557
+ sidebar?: Rails;
461
558
  }>;
462
559
  cacheKey?: string;
463
560
  /**
@@ -475,11 +572,24 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
475
572
  emptyHint?: string;
476
573
  jiraBase?: string;
477
574
  jiraKeyRe?: RegExp;
575
+ jiraSetupHint?: string;
478
576
  jiraTransitions?: JiraTransition[];
479
577
  hasCiStatus?: boolean;
480
578
  ciJob?: string;
481
579
  ciFetcher?: () => Promise<CiStatus | null>;
482
580
  ciPollMs?: number;
581
+ /**
582
+ * A standing status strip under the CI line — one row of things and the
583
+ * state each is in, polled on its own timer like the CI line and for the
584
+ * same reason: it is a glance at something that moves on its own schedule.
585
+ * Wiring a fetcher reserves the row; leaving it out draws nothing. `null`
586
+ * from the fetcher means "nothing configured" and is drawn as such, while a
587
+ * rejected poll keeps the last strip up.
588
+ */
589
+ stripFetcher?: () => Promise<StatusStrip | null>;
590
+ /** What to call the row before its first answer arrives with a title. */
591
+ stripLabel?: string;
592
+ stripPollMs?: number;
483
593
  /**
484
594
  * A file something else touches when it has changed GitHub on your behalf —
485
595
  * a Claude session closing an issue, a script merging a PR. Touching it makes
@@ -519,4 +629,4 @@ declare const matchesFilter: (repo: string, filter: RepoFilter) => boolean;
519
629
  */
520
630
  declare const parsePatterns: (value: string) => string[];
521
631
 
522
- export { type Action, ActionMenu, App, COLS, CiStatusLine, type CiStatusState, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraTransition, type LiveLabel, MIN_SIDEBAR_COLS, type RepoFilter, SIDEBAR_COLS, SidePanel, type Sidebar, type SidebarRow, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, railWidth, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, toCiStatusState, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
632
+ 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, type Rails, type RepoFilter, SIDEBAR_COLS, SidePanel, type Sidebar, type SidebarRow, type StatusStrip, StatusStripLine, type StripItem, type StripState, type StripStatusState, 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, signatureOf, stripGlyph, stripLayout, stripSignature, toCiStatusState, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };