@opensip-cli/cli-ui 0.1.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 (80) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/banner.d.ts +70 -0
  5. package/dist/banner.d.ts.map +1 -0
  6. package/dist/banner.js +203 -0
  7. package/dist/banner.js.map +1 -0
  8. package/dist/clock.d.ts +28 -0
  9. package/dist/clock.d.ts.map +1 -0
  10. package/dist/clock.js +45 -0
  11. package/dist/clock.js.map +1 -0
  12. package/dist/error-message.d.ts +12 -0
  13. package/dist/error-message.d.ts.map +1 -0
  14. package/dist/error-message.js +13 -0
  15. package/dist/error-message.js.map +1 -0
  16. package/dist/fit-table-format.d.ts +35 -0
  17. package/dist/fit-table-format.d.ts.map +1 -0
  18. package/dist/fit-table-format.js +48 -0
  19. package/dist/fit-table-format.js.map +1 -0
  20. package/dist/format-duration.d.ts +13 -0
  21. package/dist/format-duration.d.ts.map +1 -0
  22. package/dist/format-duration.js +23 -0
  23. package/dist/format-duration.js.map +1 -0
  24. package/dist/index.d.ts +33 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +32 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/live-progress.d.ts +57 -0
  29. package/dist/live-progress.d.ts.map +1 -0
  30. package/dist/live-progress.js +106 -0
  31. package/dist/live-progress.js.map +1 -0
  32. package/dist/progress-event.d.ts +66 -0
  33. package/dist/progress-event.d.ts.map +1 -0
  34. package/dist/progress-event.js +21 -0
  35. package/dist/progress-event.js.map +1 -0
  36. package/dist/project-header.d.ts +31 -0
  37. package/dist/project-header.d.ts.map +1 -0
  38. package/dist/project-header.js +38 -0
  39. package/dist/project-header.js.map +1 -0
  40. package/dist/render-to-ink.d.ts +15 -0
  41. package/dist/render-to-ink.d.ts.map +1 -0
  42. package/dist/render-to-ink.js +104 -0
  43. package/dist/render-to-ink.js.map +1 -0
  44. package/dist/render-to-text.d.ts +24 -0
  45. package/dist/render-to-text.d.ts.map +1 -0
  46. package/dist/render-to-text.js +86 -0
  47. package/dist/render-to-text.js.map +1 -0
  48. package/dist/run-footer-hints.d.ts +32 -0
  49. package/dist/run-footer-hints.d.ts.map +1 -0
  50. package/dist/run-footer-hints.js +33 -0
  51. package/dist/run-footer-hints.js.map +1 -0
  52. package/dist/run-header.d.ts +25 -0
  53. package/dist/run-header.d.ts.map +1 -0
  54. package/dist/run-header.js +19 -0
  55. package/dist/run-header.js.map +1 -0
  56. package/dist/run-summary.d.ts +48 -0
  57. package/dist/run-summary.d.ts.map +1 -0
  58. package/dist/run-summary.js +56 -0
  59. package/dist/run-summary.js.map +1 -0
  60. package/dist/run-timing-provider.d.ts +59 -0
  61. package/dist/run-timing-provider.d.ts.map +1 -0
  62. package/dist/run-timing-provider.js +52 -0
  63. package/dist/run-timing-provider.js.map +1 -0
  64. package/dist/spinner.d.ts +29 -0
  65. package/dist/spinner.d.ts.map +1 -0
  66. package/dist/spinner.js +44 -0
  67. package/dist/spinner.js.map +1 -0
  68. package/dist/theme.d.ts +42 -0
  69. package/dist/theme.d.ts.map +1 -0
  70. package/dist/theme.js +96 -0
  71. package/dist/theme.js.map +1 -0
  72. package/dist/verbose-detail.d.ts +43 -0
  73. package/dist/verbose-detail.d.ts.map +1 -0
  74. package/dist/verbose-detail.js +104 -0
  75. package/dist/verbose-detail.js.map +1 -0
  76. package/dist/view-model.d.ts +132 -0
  77. package/dist/view-model.d.ts.map +1 -0
  78. package/dist/view-model.js +71 -0
  79. package/dist/view-model.js.map +1 -0
  80. package/package.json +52 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-message.js","sourceRoot":"","sources":["../src/error-message.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAGhC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAOtC,MAAM,UAAU,YAAY,CAAC,EAAE,OAAO,EAAE,UAAU,EAAqB;IACrE,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IAEzB,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,YAAG,GAAG,GAAQ,OAAE,OAAO,IAC1C,EACN,UAAU,KAAK,SAAS,IAAI,CAC3B,MAAC,IAAI,IAAC,QAAQ,mBACX,MAAM,EACN,UAAU,IACN,CACR,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared, renderer-agnostic helpers for the fitness results table.
3
+ *
4
+ * Used by BOTH the cli static view-model builder (`fit-done-view.ts`) and the
5
+ * fitness live Ink view (`fit-runner-views.tsx`), which previously each kept a
6
+ * byte-identical copy (flagged by graph:duplicated-function-body). Pure
7
+ * functions with structural parameter types so cli-ui stays free of any
8
+ * @opensip-cli dependency — contracts' `TableRow` structurally satisfies
9
+ * `FitRowSortKey`, so callers pass a `TableRow` directly.
10
+ */
11
+ /** The fields {@link sortFitRowPriority} reads off a fit results row. */
12
+ export interface FitRowSortKey {
13
+ readonly status: 'PASS' | 'FAIL' | 'TIMEOUT' | 'ERROR';
14
+ readonly warnings: number;
15
+ }
16
+ /**
17
+ * Sort priority for the fit results table: timed-out / errored checks first,
18
+ * then failures, then checks carrying warnings, then clean checks. Lower sorts
19
+ * earlier. (ERROR is the envelope-table status for a unit that threw — it sorts
20
+ * with TIMEOUT, the prior plain-table's "couldn't complete" rung.)
21
+ */
22
+ export declare function sortFitRowPriority(r: FitRowSortKey): number;
23
+ /**
24
+ * Parse the leading integer out of a "Validated" cell — e.g. `"171 files"` →
25
+ * `171`, `"—"` → `0`. Used to compute the ignored-ratio tone/colour.
26
+ */
27
+ export declare function parseValidatedCount(validated: string): number;
28
+ /**
29
+ * Render a "Validated" table cell: item count with a singular/plural noun
30
+ * (e.g. `450 → "450 files"`, `1 → "1 file"`, `0`/undefined → `"—"`). Shared by
31
+ * the fit static view-model and live Ink view so both render the column
32
+ * identically. `itemType` defaults to `"items"`.
33
+ */
34
+ export declare function formatValidatedColumn(totalItems: number | undefined, itemType?: string): string;
35
+ //# sourceMappingURL=fit-table-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fit-table-format.d.ts","sourceRoot":"","sources":["../src/fit-table-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACvD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAK3D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,SAAU,GAAG,MAAM,CAIhG"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Shared, renderer-agnostic helpers for the fitness results table.
3
+ *
4
+ * Used by BOTH the cli static view-model builder (`fit-done-view.ts`) and the
5
+ * fitness live Ink view (`fit-runner-views.tsx`), which previously each kept a
6
+ * byte-identical copy (flagged by graph:duplicated-function-body). Pure
7
+ * functions with structural parameter types so cli-ui stays free of any
8
+ * @opensip-cli dependency — contracts' `TableRow` structurally satisfies
9
+ * `FitRowSortKey`, so callers pass a `TableRow` directly.
10
+ */
11
+ /**
12
+ * Sort priority for the fit results table: timed-out / errored checks first,
13
+ * then failures, then checks carrying warnings, then clean checks. Lower sorts
14
+ * earlier. (ERROR is the envelope-table status for a unit that threw — it sorts
15
+ * with TIMEOUT, the prior plain-table's "couldn't complete" rung.)
16
+ */
17
+ export function sortFitRowPriority(r) {
18
+ if (r.status === 'TIMEOUT' || r.status === 'ERROR')
19
+ return 0;
20
+ if (r.status === 'FAIL')
21
+ return 1;
22
+ if (r.warnings > 0)
23
+ return 2;
24
+ return 3;
25
+ }
26
+ /**
27
+ * Parse the leading integer out of a "Validated" cell — e.g. `"171 files"` →
28
+ * `171`, `"—"` → `0`. Used to compute the ignored-ratio tone/colour.
29
+ */
30
+ export function parseValidatedCount(validated) {
31
+ if (validated === '—')
32
+ return 0;
33
+ const match = /^(\d+)/.exec(validated);
34
+ return match ? Number.parseInt(match[1], 10) : 0;
35
+ }
36
+ /**
37
+ * Render a "Validated" table cell: item count with a singular/plural noun
38
+ * (e.g. `450 → "450 files"`, `1 → "1 file"`, `0`/undefined → `"—"`). Shared by
39
+ * the fit static view-model and live Ink view so both render the column
40
+ * identically. `itemType` defaults to `"items"`.
41
+ */
42
+ export function formatValidatedColumn(totalItems, itemType = 'items') {
43
+ if (!totalItems)
44
+ return '—';
45
+ const singular = itemType.endsWith('s') ? itemType.slice(0, -1) : itemType;
46
+ return totalItems === 1 ? `${totalItems} ${singular}` : `${totalItems} ${itemType}`;
47
+ }
48
+ //# sourceMappingURL=fit-table-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fit-table-format.js","sourceRoot":"","sources":["../src/fit-table-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAgB;IACjD,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,CAAC,CAAC;IAC7D,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACnD,IAAI,SAAS,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAA8B,EAAE,QAAQ,GAAG,OAAO;IACtF,IAAI,CAAC,UAAU;QAAE,OAAO,GAAG,CAAC;IAC5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC3E,OAAO,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC;AACtF,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * formatDuration — compact ms→human duration used by the shared run-summary and
3
+ * live-progress renderers. Extracted from run-summary.tsx so both consumers share
4
+ * one definition (cli-ui cannot import `@opensip-cli/core`'s formatDuration —
5
+ * the package depends on ink/react only).
6
+ *
7
+ * Format: `<1000ms → "Nms"`, sub-minute durations as `"N.Ys"` (one decimal),
8
+ * and minute-scale durations as `"Nm Y.Ys"`. Long stages render as e.g.
9
+ * "24m 31.6s" so graph runs that spend many minutes in a stage remain easy to
10
+ * scan.
11
+ */
12
+ export declare function formatDuration(ms: number): string;
13
+ //# sourceMappingURL=format-duration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-duration.d.ts","sourceRoot":"","sources":["../src/format-duration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CASjD"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * formatDuration — compact ms→human duration used by the shared run-summary and
3
+ * live-progress renderers. Extracted from run-summary.tsx so both consumers share
4
+ * one definition (cli-ui cannot import `@opensip-cli/core`'s formatDuration —
5
+ * the package depends on ink/react only).
6
+ *
7
+ * Format: `<1000ms → "Nms"`, sub-minute durations as `"N.Ys"` (one decimal),
8
+ * and minute-scale durations as `"Nm Y.Ys"`. Long stages render as e.g.
9
+ * "24m 31.6s" so graph runs that spend many minutes in a stage remain easy to
10
+ * scan.
11
+ */
12
+ // @fitness-ignore-file duplicate-utility-functions -- intentional: cli-ui is deliberately ink/react-only (see docstring above) and must not depend on @opensip-cli/core, so this small formatter is duplicated by design rather than shared across the layer boundary.
13
+ export function formatDuration(ms) {
14
+ if (ms < 1000)
15
+ return `${ms}ms`;
16
+ const totalTenths = Math.round(ms / 100);
17
+ if (totalTenths < 600)
18
+ return `${(totalTenths / 10).toFixed(1)}s`;
19
+ const minutes = Math.floor(totalTenths / 600);
20
+ const remainingTenths = totalTenths % 600;
21
+ return `${minutes}m ${(remainingTenths / 10).toFixed(1)}s`;
22
+ }
23
+ //# sourceMappingURL=format-duration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-duration.js","sourceRoot":"","sources":["../src/format-duration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,uQAAuQ;AACvQ,MAAM,UAAU,cAAc,CAAC,EAAU;IACvC,IAAI,EAAE,GAAG,IAAI;QAAE,OAAO,GAAG,EAAE,IAAI,CAAC;IAEhC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC;IACzC,IAAI,WAAW,GAAG,GAAG;QAAE,OAAO,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAElE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC;IAC9C,MAAM,eAAe,GAAG,WAAW,GAAG,GAAG,CAAC;IAC1C,OAAO,GAAG,OAAO,KAAK,CAAC,eAAe,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @opensip-cli/cli-ui — shared Ink/React presentational primitives for
3
+ * OpenSIP CLI CLI tools.
4
+ *
5
+ * Tools that ship an Ink live view (fitness, graph, future audit/lint/etc.)
6
+ * import from this package instead of duplicating banner/spinner/header
7
+ * code in their own runner files. The CLI's static-render path (App.tsx)
8
+ * imports the same primitives so the live view and the post-run summary
9
+ * look consistent.
10
+ *
11
+ * This package depends on `ink` and `react` only; no opensip-cli deps,
12
+ * no Node-runtime side-effects beyond the theme's terminal-capability
13
+ * detection. Safe to import from any Layer 3 tool package.
14
+ */
15
+ export { Banner, UpdateHint, normalizeBannerSize, type BannerSize, type BannerProps, } from './banner.js';
16
+ export { ErrorMessage, type ErrorMessageProps } from './error-message.js';
17
+ export { ProjectHeader, formatProjectHeader, viewProjectHeader, type ProjectHeaderInput, } from './project-header.js';
18
+ export { RunHeader, type RunHeaderProps, type RunHeaderMeta } from './run-header.js';
19
+ export { RunSummary, viewRunSummary, type RunSummaryProps } from './run-summary.js';
20
+ export { RunTimingProvider, useRunTiming, useRunDuration, type RunTimingProviderProps, } from './run-timing-provider.js';
21
+ export { RunFooterHints, viewFooterHints, type RunFooterHint, type RunFooterHintsProps, } from './run-footer-hints.js';
22
+ export { sortFitRowPriority, parseValidatedCount, formatValidatedColumn, type FitRowSortKey, } from './fit-table-format.js';
23
+ export { Spinner, type SpinnerProps, useSpinner, useStandaloneSpinner } from './spinner.js';
24
+ export { ClockProvider, type ClockProviderProps, useClock, useTick } from './clock.js';
25
+ export { formatDuration } from './format-duration.js';
26
+ export { LiveProgress, useProgressState, type LiveProgressProps } from './live-progress.js';
27
+ export type { ProgressEvent, ProgressCallback, ProgressShape, ProgressStageDescriptor, ProgressSurface, } from './progress-event.js';
28
+ export { type ViewNode, type Span, type Tone, type HintItem, type TableColumnSpec, text, line, group, viewTable, } from './view-model.js';
29
+ export { viewVerboseLines, viewFindingsGroups, viewVerboseHint, VERBOSE_DETAIL_HINT, type FindingLineView, type FindingGroupView, } from './verbose-detail.js';
30
+ export { renderToText } from './render-to-text.js';
31
+ export { renderToInk } from './render-to-ink.js';
32
+ export { DEFAULT_THEME, ThemeContext, ThemeProvider, type Theme, type ThemeProviderProps, type TerminalCapabilities, detectTerminalCapabilities, useTheme, } from './theme.js';
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,KAAK,sBAAsB,GAC5B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,aAAa,EAClB,KAAK,mBAAmB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,aAAa,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5F,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,uBAAuB,EACvB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,IAAI,EACT,KAAK,IAAI,EACT,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,SAAS,GACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EACL,aAAa,EACb,YAAY,EACZ,aAAa,EACb,KAAK,KAAK,EACV,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,0BAA0B,EAC1B,QAAQ,GACT,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @opensip-cli/cli-ui — shared Ink/React presentational primitives for
3
+ * OpenSIP CLI CLI tools.
4
+ *
5
+ * Tools that ship an Ink live view (fitness, graph, future audit/lint/etc.)
6
+ * import from this package instead of duplicating banner/spinner/header
7
+ * code in their own runner files. The CLI's static-render path (App.tsx)
8
+ * imports the same primitives so the live view and the post-run summary
9
+ * look consistent.
10
+ *
11
+ * This package depends on `ink` and `react` only; no opensip-cli deps,
12
+ * no Node-runtime side-effects beyond the theme's terminal-capability
13
+ * detection. Safe to import from any Layer 3 tool package.
14
+ */
15
+ export { Banner, UpdateHint, normalizeBannerSize, } from './banner.js';
16
+ export { ErrorMessage } from './error-message.js';
17
+ export { ProjectHeader, formatProjectHeader, viewProjectHeader, } from './project-header.js';
18
+ export { RunHeader } from './run-header.js';
19
+ export { RunSummary, viewRunSummary } from './run-summary.js';
20
+ export { RunTimingProvider, useRunTiming, useRunDuration, } from './run-timing-provider.js';
21
+ export { RunFooterHints, viewFooterHints, } from './run-footer-hints.js';
22
+ export { sortFitRowPriority, parseValidatedCount, formatValidatedColumn, } from './fit-table-format.js';
23
+ export { Spinner, useSpinner, useStandaloneSpinner } from './spinner.js';
24
+ export { ClockProvider, useClock, useTick } from './clock.js';
25
+ export { formatDuration } from './format-duration.js';
26
+ export { LiveProgress, useProgressState } from './live-progress.js';
27
+ export { text, line, group, viewTable, } from './view-model.js';
28
+ export { viewVerboseLines, viewFindingsGroups, viewVerboseHint, VERBOSE_DETAIL_HINT, } from './verbose-detail.js';
29
+ export { renderToText } from './render-to-text.js';
30
+ export { renderToInk } from './render-to-ink.js';
31
+ export { DEFAULT_THEME, ThemeContext, ThemeProvider, detectTerminalCapabilities, useTheme, } from './theme.js';
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,MAAM,EACN,UAAU,EACV,mBAAmB,GAGpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAA0B,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,iBAAiB,GAElB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAA2C,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAwB,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,cAAc,GAEf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,cAAc,EACd,eAAe,GAGhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,GAEtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAqB,UAAU,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,aAAa,EAA2B,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAA0B,MAAM,oBAAoB,CAAC;AAQ5F,OAAO,EAML,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,SAAS,GACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,GAGpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EACL,aAAa,EACb,YAAY,EACZ,aAAa,EAIb,0BAA0B,EAC1B,QAAQ,GACT,MAAM,YAAY,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * LiveProgress — the single live-run renderer shared by fit, graph, and sim
3
+ * (ADR-0016). Replaces graph's bespoke StageChecklist/StageLine/RunningStageLine
4
+ * and fit's inline Spinner wiring with one component driven by the
5
+ * {@link ProgressEvent} stream.
6
+ *
7
+ * Two presentation modes, chosen by the {@link ProgressSurface}:
8
+ * - `phases` → a checklist: ✓ done rows (label + detail + duration), `(cached)`
9
+ * rows, an active spinner row with a dim running sub-label + live elapsed, and
10
+ * ○ dim pending rows. (Visual ported verbatim from graph's former checklist.)
11
+ * - `pool` → the existing `<Spinner>` (frame + label + `completed/total (pct%)`).
12
+ *
13
+ * Presentational only: `useProgressState` folds the event stream into render
14
+ * state so the tool runners stay thin (they just wire `transport.onProgress`).
15
+ * Must be mounted inside a `<ThemeProvider>` + `<ClockProvider>` (the tool
16
+ * runners already provide both).
17
+ */
18
+ import React from 'react';
19
+ import type { ProgressCallback, ProgressStageDescriptor, ProgressSurface } from './progress-event.js';
20
+ type PhaseStatus = {
21
+ readonly kind: 'pending';
22
+ } | {
23
+ readonly kind: 'running';
24
+ readonly startedAt: number;
25
+ } | {
26
+ readonly kind: 'done';
27
+ readonly durationMs: number;
28
+ readonly detail?: string;
29
+ } | {
30
+ readonly kind: 'cached';
31
+ };
32
+ interface PhasesState {
33
+ readonly shape: 'phases';
34
+ readonly stages: readonly ProgressStageDescriptor[];
35
+ readonly status: Readonly<Record<string, PhaseStatus>>;
36
+ }
37
+ interface PoolState {
38
+ readonly shape: 'pool';
39
+ readonly label: string;
40
+ readonly completed: number;
41
+ readonly total: number;
42
+ }
43
+ type ProgressState = PhasesState | PoolState;
44
+ /**
45
+ * Subscribe to a transport's event stream and fold it into render state. The
46
+ * `subscribe` function is the transport's `onProgress`; it is called exactly
47
+ * once on mount (the transport buffers any events emitted before subscription
48
+ * and flushes them on attach, so none are lost).
49
+ */
50
+ export declare function useProgressState(surface: ProgressSurface, subscribe: (cb: ProgressCallback) => void): ProgressState;
51
+ export interface LiveProgressProps {
52
+ readonly surface: ProgressSurface;
53
+ readonly subscribe: (cb: ProgressCallback) => void;
54
+ }
55
+ export declare function LiveProgress({ surface, subscribe }: LiveProgressProps): React.ReactElement;
56
+ export {};
57
+ //# sourceMappingURL=live-progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-progress.d.ts","sourceRoot":"","sources":["../src/live-progress.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAMnD,OAAO,KAAK,EACV,gBAAgB,EAEhB,uBAAuB,EACvB,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAM7B,KAAK,WAAW,GACZ;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEhC,UAAU,WAAW;IACnB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACxD;AAED,UAAU,SAAS;IACjB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,KAAK,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;AAwC7C;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,IAAI,GACxC,aAAa,CAQf;AAMD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACpD;AAED,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,YAAY,CAoB1F"}
@@ -0,0 +1,106 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * LiveProgress — the single live-run renderer shared by fit, graph, and sim
4
+ * (ADR-0016). Replaces graph's bespoke StageChecklist/StageLine/RunningStageLine
5
+ * and fit's inline Spinner wiring with one component driven by the
6
+ * {@link ProgressEvent} stream.
7
+ *
8
+ * Two presentation modes, chosen by the {@link ProgressSurface}:
9
+ * - `phases` → a checklist: ✓ done rows (label + detail + duration), `(cached)`
10
+ * rows, an active spinner row with a dim running sub-label + live elapsed, and
11
+ * ○ dim pending rows. (Visual ported verbatim from graph's former checklist.)
12
+ * - `pool` → the existing `<Spinner>` (frame + label + `completed/total (pct%)`).
13
+ *
14
+ * Presentational only: `useProgressState` folds the event stream into render
15
+ * state so the tool runners stay thin (they just wire `transport.onProgress`).
16
+ * Must be mounted inside a `<ThemeProvider>` + `<ClockProvider>` (the tool
17
+ * runners already provide both).
18
+ */
19
+ import { Box, Text } from 'ink';
20
+ import { useEffect, useState } from 'react';
21
+ import { formatDuration } from './format-duration.js';
22
+ import { Spinner, useSpinner } from './spinner.js';
23
+ import { useTheme } from './theme.js';
24
+ function initState(surface) {
25
+ if (surface.shape === 'pool') {
26
+ return { shape: 'pool', label: surface.label, completed: 0, total: 0 };
27
+ }
28
+ const status = {};
29
+ for (const s of surface.stages)
30
+ status[s.id] = { kind: 'pending' };
31
+ return { shape: 'phases', stages: surface.stages, status };
32
+ }
33
+ function reduce(prev, event) {
34
+ if (prev.shape === 'pool') {
35
+ if (event.type === 'stage-progress') {
36
+ return { ...prev, completed: event.completed, total: event.total };
37
+ }
38
+ return prev;
39
+ }
40
+ // phases
41
+ const next = { ...prev.status };
42
+ switch (event.type) {
43
+ case 'stage-start': {
44
+ next[event.stage] = { kind: 'running', startedAt: Date.now() };
45
+ break;
46
+ }
47
+ case 'stage-done': {
48
+ next[event.stage] = { kind: 'done', durationMs: event.durationMs, detail: event.detail };
49
+ break;
50
+ }
51
+ case 'stage-cached': {
52
+ next[event.stage] = { kind: 'cached' };
53
+ break;
54
+ }
55
+ case 'stage-progress': {
56
+ break; // phases mode ignores pool counters
57
+ }
58
+ }
59
+ return { ...prev, status: next };
60
+ }
61
+ /**
62
+ * Subscribe to a transport's event stream and fold it into render state. The
63
+ * `subscribe` function is the transport's `onProgress`; it is called exactly
64
+ * once on mount (the transport buffers any events emitted before subscription
65
+ * and flushes them on attach, so none are lost).
66
+ */
67
+ export function useProgressState(surface, subscribe) {
68
+ const [state, setState] = useState(() => initState(surface));
69
+ // Subscribe once on mount — the transport owns the listener lifetime and
70
+ // buffers/flushes any events emitted before this effect runs.
71
+ useEffect(() => {
72
+ subscribe((event) => setState((prev) => reduce(prev, event)));
73
+ }, []);
74
+ return state;
75
+ }
76
+ export function LiveProgress({ surface, subscribe }) {
77
+ const state = useProgressState(surface, subscribe);
78
+ if (state.shape === 'pool') {
79
+ return (_jsx(Box, { paddingLeft: 2, children: _jsx(Spinner, { total: state.total, completed: state.completed, label: state.label }) }));
80
+ }
81
+ return (_jsx(Box, { flexDirection: "column", paddingLeft: 2, paddingTop: 1, children: state.stages.map((stage) => (_jsx(PhaseLine, { stage: stage, status: state.status[stage.id] ?? { kind: 'pending' } }, stage.id))) }));
82
+ }
83
+ function PhaseLine({ stage, status, }) {
84
+ const theme = useTheme();
85
+ if (status.kind === 'pending') {
86
+ return (_jsxs(Text, { dimColor: true, children: [' ', _jsx(Text, { children: "\u25CB" }), " ", stage.label] }));
87
+ }
88
+ if (status.kind === 'cached') {
89
+ return (_jsxs(Text, { children: [_jsx(Text, { color: theme.success, children: "\u2713" }), " ", _jsx(Text, { children: stage.label }), ' ', _jsx(Text, { dimColor: true, children: "(cached)" })] }));
90
+ }
91
+ if (status.kind === 'done') {
92
+ const dur = formatDuration(status.durationMs);
93
+ const detail = status.detail ? `${status.detail} (${dur})` : dur;
94
+ return (_jsxs(Text, { children: [_jsx(Text, { color: theme.success, children: "\u2713" }), " ", _jsx(Text, { children: stage.label }), ' ', _jsx(Text, { dimColor: true, children: detail })] }));
95
+ }
96
+ return _jsx(RunningPhaseLine, { stage: stage, startedAt: status.startedAt });
97
+ }
98
+ function RunningPhaseLine({ stage, startedAt, }) {
99
+ const theme = useTheme();
100
+ const frame = useSpinner();
101
+ // Re-render on each tick; derive wall-clock elapsed from Date.now() so it stays
102
+ // accurate regardless of how many ticks fired since startedAt.
103
+ const elapsed = formatDuration(Date.now() - startedAt);
104
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { color: theme.brand, children: frame }), " ", _jsx(Text, { bold: true, children: stage.label })] }), _jsxs(Text, { children: [' └─ ', stage.runningDetail ? _jsxs(Text, { dimColor: true, children: [stage.runningDetail, " "] }) : null, _jsxs(Text, { dimColor: true, children: ["(", elapsed, ")"] })] })] }));
105
+ }
106
+ //# sourceMappingURL=live-progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-progress.js","sourceRoot":"","sources":["../src/live-progress.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Progress currency — the universal live-run event vocabulary consumed by the
3
+ * shared `<LiveProgress>` renderer (ADR-0016). The run-time analogue of
4
+ * `@opensip-cli/contracts`' `SignalEnvelope` *output* currency.
5
+ *
6
+ * Why this lives in cli-ui (not contracts): progress is renderer-bound and
7
+ * ephemeral — it is never persisted or egressed the way a `SignalEnvelope` is.
8
+ * The renderer owns its input vocabulary, and cli-ui depends on ink/react only,
9
+ * so the pure presentational leaf carries no `@opensip-cli/*` dependency.
10
+ *
11
+ * One event union covers both tool shapes:
12
+ * - `phases` — few, fixed, ordered, named stages (graph's 7-stage pipeline),
13
+ * rendered as a checklist with one active spinner row.
14
+ * - `pool` — many, dynamic, possibly concurrent units (fit's checks, sim's
15
+ * scenarios), rendered as a single spinner + `completed/total` counter.
16
+ *
17
+ * `stage` is a free-form string id: graph maps its `GraphStage`; pool-shape tools
18
+ * use one synthetic id (`'checks'`, `'scenarios'`).
19
+ */
20
+ /** A single live-progress event emitted by a running tool. */
21
+ export type ProgressEvent = {
22
+ readonly type: 'stage-start';
23
+ readonly stage: string;
24
+ readonly label: string;
25
+ } | {
26
+ readonly type: 'stage-progress';
27
+ readonly stage: string;
28
+ readonly completed: number;
29
+ readonly total: number;
30
+ } | {
31
+ readonly type: 'stage-done';
32
+ readonly stage: string;
33
+ readonly durationMs: number;
34
+ readonly detail?: string;
35
+ }
36
+ /** Phases-mode only: a cache hit satisfied this stage (graph parse/walk/resolve). */
37
+ | {
38
+ readonly type: 'stage-cached';
39
+ readonly stage: string;
40
+ };
41
+ /** Listener invoked with each {@link ProgressEvent} as a run progresses. */
42
+ export type ProgressCallback = (event: ProgressEvent) => void;
43
+ /** Which of the two presentation modes a tool's progress uses. */
44
+ export type ProgressShape = 'phases' | 'pool';
45
+ /** A fixed pipeline stage declared up front so the checklist can render the
46
+ * pending (○) row before the stage starts. `id` matches the `stage` field of
47
+ * this stage's events. `runningDetail` is the dim sub-label shown under the
48
+ * active spinner row (e.g. "Binding symbols to edges..."). */
49
+ export interface ProgressStageDescriptor {
50
+ readonly id: string;
51
+ readonly label: string;
52
+ readonly runningDetail?: string;
53
+ }
54
+ /**
55
+ * What the renderer needs up front to pick a mode and pre-render rows.
56
+ * - `phases`: the fixed, ordered stage descriptors.
57
+ * - `pool`: a label for the single running line (e.g. "Running checks...").
58
+ */
59
+ export type ProgressSurface = {
60
+ readonly shape: 'phases';
61
+ readonly stages: readonly ProgressStageDescriptor[];
62
+ } | {
63
+ readonly shape: 'pool';
64
+ readonly label: string;
65
+ };
66
+ //# sourceMappingURL=progress-event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-event.d.ts","sourceRoot":"","sources":["../src/progress-event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,8DAA8D;AAC9D,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChF;IACE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AACH,qFAAqF;GACnF;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAE9D,kEAAkE;AAClE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9C;;;+DAG+D;AAC/D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAA;CAAE,GACjF;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Progress currency — the universal live-run event vocabulary consumed by the
3
+ * shared `<LiveProgress>` renderer (ADR-0016). The run-time analogue of
4
+ * `@opensip-cli/contracts`' `SignalEnvelope` *output* currency.
5
+ *
6
+ * Why this lives in cli-ui (not contracts): progress is renderer-bound and
7
+ * ephemeral — it is never persisted or egressed the way a `SignalEnvelope` is.
8
+ * The renderer owns its input vocabulary, and cli-ui depends on ink/react only,
9
+ * so the pure presentational leaf carries no `@opensip-cli/*` dependency.
10
+ *
11
+ * One event union covers both tool shapes:
12
+ * - `phases` — few, fixed, ordered, named stages (graph's 7-stage pipeline),
13
+ * rendered as a checklist with one active spinner row.
14
+ * - `pool` — many, dynamic, possibly concurrent units (fit's checks, sim's
15
+ * scenarios), rendered as a single spinner + `completed/total` counter.
16
+ *
17
+ * `stage` is a free-form string id: graph maps its `GraphStage`; pool-shape tools
18
+ * use one synthetic id (`'checks'`, `'scenarios'`).
19
+ */
20
+ export {};
21
+ //# sourceMappingURL=progress-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-event.js","sourceRoot":"","sources":["../src/progress-event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ProjectHeader — the single, canonical "Project: <root>" location marker.
3
+ *
4
+ * Rendered once per human-facing command, directly under the banner, by
5
+ * the CLI's App shell (static commands) and by each tool's live view
6
+ * (fit/graph). This is the ONLY renderer of the project line — RunHeader
7
+ * no longer carries it, and the imperative pre-action print is gone — so
8
+ * there is exactly one place the format lives.
9
+ *
10
+ * `--json` and `completion` never render UI, so they never reach here.
11
+ */
12
+ import React from 'react';
13
+ import { type ViewNode } from './view-model.js';
14
+ export interface ProjectHeaderInput {
15
+ /** Absolute path to the project root. */
16
+ readonly root: string;
17
+ /** Ancestor steps walked from cwd to root. 0 == cwd is the root. */
18
+ readonly walkedUp?: number;
19
+ }
20
+ /**
21
+ * The project-line text (no trailing newline — Ink owns line breaks):
22
+ * walkedUp 0 → `ℹ Project: <root>`
23
+ * walkedUp 1 → `ℹ Project: <root> (found 1 level up)`
24
+ * walkedUp N → `ℹ Project: <root> (found N levels up)`
25
+ */
26
+ export declare function formatProjectHeader(input: ProjectHeaderInput): string;
27
+ /** The project line as a renderer-agnostic view-model node (rendered dim). */
28
+ export declare function viewProjectHeader(input: ProjectHeaderInput): ViewNode;
29
+ /** Ink view of {@link viewProjectHeader}. Indented to align with RunHeader. */
30
+ export declare function ProjectHeader({ root, walkedUp }: ProjectHeaderInput): React.ReactElement;
31
+ //# sourceMappingURL=project-header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-header.d.ts","sourceRoot":"","sources":["../src/project-header.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAMrE;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,GAAG,QAAQ,CAErE;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAMxF"}
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * ProjectHeader — the single, canonical "Project: <root>" location marker.
4
+ *
5
+ * Rendered once per human-facing command, directly under the banner, by
6
+ * the CLI's App shell (static commands) and by each tool's live view
7
+ * (fit/graph). This is the ONLY renderer of the project line — RunHeader
8
+ * no longer carries it, and the imperative pre-action print is gone — so
9
+ * there is exactly one place the format lives.
10
+ *
11
+ * `--json` and `completion` never render UI, so they never reach here.
12
+ */
13
+ import { Box } from 'ink';
14
+ import { renderToInk } from './render-to-ink.js';
15
+ import { line } from './view-model.js';
16
+ /**
17
+ * The project-line text (no trailing newline — Ink owns line breaks):
18
+ * walkedUp 0 → `ℹ Project: <root>`
19
+ * walkedUp 1 → `ℹ Project: <root> (found 1 level up)`
20
+ * walkedUp N → `ℹ Project: <root> (found N levels up)`
21
+ */
22
+ export function formatProjectHeader(input) {
23
+ const walkedUp = input.walkedUp ?? 0;
24
+ const base = `ℹ Project: ${input.root}`;
25
+ if (walkedUp === 0)
26
+ return base;
27
+ const noun = walkedUp === 1 ? 'level' : 'levels';
28
+ return `${base} (found ${walkedUp} ${noun} up)`;
29
+ }
30
+ /** The project line as a renderer-agnostic view-model node (rendered dim). */
31
+ export function viewProjectHeader(input) {
32
+ return line([{ text: formatProjectHeader(input) }], true);
33
+ }
34
+ /** Ink view of {@link viewProjectHeader}. Indented to align with RunHeader. */
35
+ export function ProjectHeader({ root, walkedUp }) {
36
+ return (_jsx(Box, { paddingLeft: 2, paddingTop: 1, children: renderToInk(viewProjectHeader({ root, walkedUp })) }));
37
+ }
38
+ //# sourceMappingURL=project-header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-header.js","sourceRoot":"","sources":["../src/project-header.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG1B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAiB,MAAM,iBAAiB,CAAC;AAStD;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAyB;IAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,cAAc,KAAK,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,IAAI,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IACjD,OAAO,GAAG,IAAI,YAAY,QAAQ,IAAI,IAAI,MAAM,CAAC;AACnD,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,iBAAiB,CAAC,KAAyB;IACzD,OAAO,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;AAC5D,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAsB;IAClE,OAAO,CACL,KAAC,GAAG,IAAC,WAAW,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,YAC/B,WAAW,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,GAC/C,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * renderToInk — the interactive (TTY) interpreter.
3
+ *
4
+ * Walks the same `ViewNode` tree as `renderToText` and returns an Ink
5
+ * element, mapping each semantic `Tone` onto a `DEFAULT_THEME` token via
6
+ * `useTheme()` so the theme stays the single source of color truth. The
7
+ * visible text it produces is identical to `renderToText`'s output (the
8
+ * cross-renderer equivalence tests assert `stripAnsi(ink) === text`); the
9
+ * only thing Ink adds is color, weight, and dimming.
10
+ */
11
+ import React from 'react';
12
+ import type { ViewNode } from './view-model.js';
13
+ /** Render a view-model node to an Ink element. */
14
+ export declare function renderToInk(node: ViewNode): React.ReactElement;
15
+ //# sourceMappingURL=render-to-ink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-to-ink.d.ts","sourceRoot":"","sources":["../src/render-to-ink.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAkB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AA4KhE,kDAAkD;AAClD,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC,YAAY,CAE9D"}