@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.
- package/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/banner.d.ts +70 -0
- package/dist/banner.d.ts.map +1 -0
- package/dist/banner.js +203 -0
- package/dist/banner.js.map +1 -0
- package/dist/clock.d.ts +28 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +45 -0
- package/dist/clock.js.map +1 -0
- package/dist/error-message.d.ts +12 -0
- package/dist/error-message.d.ts.map +1 -0
- package/dist/error-message.js +13 -0
- package/dist/error-message.js.map +1 -0
- package/dist/fit-table-format.d.ts +35 -0
- package/dist/fit-table-format.d.ts.map +1 -0
- package/dist/fit-table-format.js +48 -0
- package/dist/fit-table-format.js.map +1 -0
- package/dist/format-duration.d.ts +13 -0
- package/dist/format-duration.d.ts.map +1 -0
- package/dist/format-duration.js +23 -0
- package/dist/format-duration.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/live-progress.d.ts +57 -0
- package/dist/live-progress.d.ts.map +1 -0
- package/dist/live-progress.js +106 -0
- package/dist/live-progress.js.map +1 -0
- package/dist/progress-event.d.ts +66 -0
- package/dist/progress-event.d.ts.map +1 -0
- package/dist/progress-event.js +21 -0
- package/dist/progress-event.js.map +1 -0
- package/dist/project-header.d.ts +31 -0
- package/dist/project-header.d.ts.map +1 -0
- package/dist/project-header.js +38 -0
- package/dist/project-header.js.map +1 -0
- package/dist/render-to-ink.d.ts +15 -0
- package/dist/render-to-ink.d.ts.map +1 -0
- package/dist/render-to-ink.js +104 -0
- package/dist/render-to-ink.js.map +1 -0
- package/dist/render-to-text.d.ts +24 -0
- package/dist/render-to-text.d.ts.map +1 -0
- package/dist/render-to-text.js +86 -0
- package/dist/render-to-text.js.map +1 -0
- package/dist/run-footer-hints.d.ts +32 -0
- package/dist/run-footer-hints.d.ts.map +1 -0
- package/dist/run-footer-hints.js +33 -0
- package/dist/run-footer-hints.js.map +1 -0
- package/dist/run-header.d.ts +25 -0
- package/dist/run-header.d.ts.map +1 -0
- package/dist/run-header.js +19 -0
- package/dist/run-header.js.map +1 -0
- package/dist/run-summary.d.ts +48 -0
- package/dist/run-summary.d.ts.map +1 -0
- package/dist/run-summary.js +56 -0
- package/dist/run-summary.js.map +1 -0
- package/dist/run-timing-provider.d.ts +59 -0
- package/dist/run-timing-provider.d.ts.map +1 -0
- package/dist/run-timing-provider.js +52 -0
- package/dist/run-timing-provider.js.map +1 -0
- package/dist/spinner.d.ts +29 -0
- package/dist/spinner.d.ts.map +1 -0
- package/dist/spinner.js +44 -0
- package/dist/spinner.js.map +1 -0
- package/dist/theme.d.ts +42 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +96 -0
- package/dist/theme.js.map +1 -0
- package/dist/verbose-detail.d.ts +43 -0
- package/dist/verbose-detail.d.ts.map +1 -0
- package/dist/verbose-detail.js +104 -0
- package/dist/verbose-detail.js.map +1 -0
- package/dist/view-model.d.ts +132 -0
- package/dist/view-model.d.ts.map +1 -0
- package/dist/view-model.js +71 -0
- package/dist/view-model.js.map +1 -0
- package/package.json +52 -0
package/dist/spinner.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Spinner — animated progress indicator. Renders one braille frame per tick
|
|
4
|
+
* plus an optional `completed/total (pct%)` suffix.
|
|
5
|
+
*
|
|
6
|
+
* Two modes:
|
|
7
|
+
* - Inside a `<ClockProvider>`: consumes the provider's tick via
|
|
8
|
+
* `useClock()`. Multiple spinners share the same timer.
|
|
9
|
+
* - Outside a provider (default): owns its own interval via `useTick()`.
|
|
10
|
+
* Convenient for single-spinner screens where setting up a provider
|
|
11
|
+
* is unnecessary.
|
|
12
|
+
*/
|
|
13
|
+
import { Text } from 'ink';
|
|
14
|
+
import { useClock, useTick } from './clock.js';
|
|
15
|
+
import { useTheme } from './theme.js';
|
|
16
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
17
|
+
/** Spinner frame keyed off the surrounding `<ClockProvider>`. */
|
|
18
|
+
export function useSpinner() {
|
|
19
|
+
const tick = useClock();
|
|
20
|
+
return SPINNER_FRAMES[tick % SPINNER_FRAMES.length] ?? '';
|
|
21
|
+
}
|
|
22
|
+
/** Spinner frame from a self-owned interval — provider-free. */
|
|
23
|
+
export function useStandaloneSpinner(intervalMs) {
|
|
24
|
+
const tick = useTick(intervalMs);
|
|
25
|
+
return SPINNER_FRAMES[tick % SPINNER_FRAMES.length] ?? '';
|
|
26
|
+
}
|
|
27
|
+
export function Spinner({ total, completed, label = 'Running...', standalone = false, }) {
|
|
28
|
+
return standalone ? (_jsx(SpinnerStandalone, { total: total, completed: completed, label: label })) : (_jsx(SpinnerCtx, { total: total, completed: completed, label: label }));
|
|
29
|
+
}
|
|
30
|
+
function SpinnerCtx({ total, completed, label, }) {
|
|
31
|
+
const theme = useTheme();
|
|
32
|
+
const frame = useSpinner();
|
|
33
|
+
return (_jsx(SpinnerLine, { frame: frame, brand: theme.brand, total: total, completed: completed, label: label }));
|
|
34
|
+
}
|
|
35
|
+
function SpinnerStandalone({ total, completed, label, }) {
|
|
36
|
+
const theme = useTheme();
|
|
37
|
+
const frame = useStandaloneSpinner();
|
|
38
|
+
return (_jsx(SpinnerLine, { frame: frame, brand: theme.brand, total: total, completed: completed, label: label }));
|
|
39
|
+
}
|
|
40
|
+
function SpinnerLine({ frame, brand, total, completed, label, }) {
|
|
41
|
+
const pct = total > 0 ? Math.round((completed / total) * 100) : 0;
|
|
42
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: brand, children: frame }), " ", label, total > 0 ? (_jsxs(Text, { children: [' ', completed, "/", total, " (", pct, "%)"] })) : null] }));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","sourceRoot":"","sources":["../src/spinner.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAG3B,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE1E,iEAAiE;AACjE,MAAM,UAAU,UAAU;IACxB,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,OAAO,cAAc,CAAC,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;AAC5D,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,oBAAoB,CAAC,UAAmB;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACjC,OAAO,cAAc,CAAC,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;AAC5D,CAAC;AAcD,MAAM,UAAU,OAAO,CAAC,EACtB,KAAK,EACL,SAAS,EACT,KAAK,GAAG,YAAY,EACpB,UAAU,GAAG,KAAK,GACL;IACb,OAAO,UAAU,CAAC,CAAC,CAAC,CAClB,KAAC,iBAAiB,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAI,CACxE,CAAC,CAAC,CAAC,CACF,KAAC,UAAU,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAI,CACjE,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,EAClB,KAAK,EACL,SAAS,EACT,KAAK,GAKN;IACC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,OAAO,CACL,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,GACZ,CACH,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,EACzB,KAAK,EACL,SAAS,EACT,KAAK,GAKN;IACC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,oBAAoB,EAAE,CAAC;IACrC,OAAO,CACL,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,GACZ,CACH,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EACnB,KAAK,EACL,KAAK,EACL,KAAK,EACL,SAAS,EACT,KAAK,GAON;IACC,MAAM,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,CACL,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,KAAK,GAAQ,OAAE,KAAK,EACxC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CACX,MAAC,IAAI,eACF,GAAG,EACH,SAAS,OAAG,KAAK,QAAI,GAAG,UACpB,CACR,CAAC,CAAC,CAAC,IAAI,IACH,CACR,CAAC;AACJ,CAAC"}
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme system for Ink UI components.
|
|
3
|
+
*
|
|
4
|
+
* Provides color tokens, terminal capability detection, and a React context
|
|
5
|
+
* so every component can access the theme via useTheme().
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
export interface Theme {
|
|
9
|
+
/** OpenSIP brand color — warm amber */
|
|
10
|
+
readonly brand: string;
|
|
11
|
+
readonly success: string;
|
|
12
|
+
readonly error: string;
|
|
13
|
+
readonly warning: string;
|
|
14
|
+
readonly info: string;
|
|
15
|
+
readonly muted: string;
|
|
16
|
+
/** Score color thresholds */
|
|
17
|
+
readonly scoreHigh: string;
|
|
18
|
+
readonly scoreMid: string;
|
|
19
|
+
readonly scoreLow: string;
|
|
20
|
+
/** Check status colors */
|
|
21
|
+
readonly statusPass: string;
|
|
22
|
+
readonly statusFail: string;
|
|
23
|
+
readonly statusTimeout: string;
|
|
24
|
+
/** Whether color output is enabled */
|
|
25
|
+
readonly colorsEnabled: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const DEFAULT_THEME: Theme;
|
|
28
|
+
export interface TerminalCapabilities {
|
|
29
|
+
readonly isTTY: boolean;
|
|
30
|
+
readonly supportsColor: boolean;
|
|
31
|
+
readonly supports256Color: boolean;
|
|
32
|
+
readonly supportsTrueColor: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare function detectTerminalCapabilities(): TerminalCapabilities;
|
|
35
|
+
export declare const ThemeContext: React.Context<Theme>;
|
|
36
|
+
export interface ThemeProviderProps {
|
|
37
|
+
readonly theme?: Theme;
|
|
38
|
+
readonly children: React.ReactNode;
|
|
39
|
+
}
|
|
40
|
+
export declare function ThemeProvider({ theme, children }: ThemeProviderProps): React.ReactElement;
|
|
41
|
+
export declare function useTheme(): Theme;
|
|
42
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,MAAM,WAAW,KAAK;IACpB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,6BAA6B;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,0BAA0B;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,sCAAsC;IACtC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAMD,eAAO,MAAM,aAAa,EAAE,KAiB3B,CAAC;AA4BF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;CACrC;AAED,wBAAgB,0BAA0B,IAAI,oBAAoB,CAgCjE;AAMD,eAAO,MAAM,YAAY,sBAA4C,CAAC;AAEtE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAezF;AAED,wBAAgB,QAAQ,IAAI,KAAK,CAEhC"}
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme system for Ink UI components.
|
|
3
|
+
*
|
|
4
|
+
* Provides color tokens, terminal capability detection, and a React context
|
|
5
|
+
* so every component can access the theme via useTheme().
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Default theme
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
export const DEFAULT_THEME = {
|
|
12
|
+
brand: '#C8956C',
|
|
13
|
+
success: 'green',
|
|
14
|
+
error: 'red',
|
|
15
|
+
warning: 'yellow',
|
|
16
|
+
info: 'cyan',
|
|
17
|
+
muted: 'gray',
|
|
18
|
+
scoreHigh: 'green',
|
|
19
|
+
scoreMid: 'yellow',
|
|
20
|
+
scoreLow: 'red',
|
|
21
|
+
statusPass: 'green',
|
|
22
|
+
statusFail: 'red',
|
|
23
|
+
statusTimeout: 'yellow',
|
|
24
|
+
colorsEnabled: true,
|
|
25
|
+
};
|
|
26
|
+
// In a no-color theme, all color tokens are zeroed out: Ink does not read
|
|
27
|
+
// `colorsEnabled` itself, so handing it any non-empty color string (`'red'`,
|
|
28
|
+
// `'#C8956C'`) would still emit ANSI escapes even with `NO_COLOR=1`. Empty
|
|
29
|
+
// strings cause Ink's `<Text color={...}>` to no-op, honoring the NO_COLOR
|
|
30
|
+
// convention without forcing every component to guard `theme.colorsEnabled`
|
|
31
|
+
// at every call site.
|
|
32
|
+
const NO_COLOR_THEME = {
|
|
33
|
+
brand: '',
|
|
34
|
+
success: '',
|
|
35
|
+
error: '',
|
|
36
|
+
warning: '',
|
|
37
|
+
info: '',
|
|
38
|
+
muted: '',
|
|
39
|
+
scoreHigh: '',
|
|
40
|
+
scoreMid: '',
|
|
41
|
+
scoreLow: '',
|
|
42
|
+
statusPass: '',
|
|
43
|
+
statusFail: '',
|
|
44
|
+
statusTimeout: '',
|
|
45
|
+
colorsEnabled: false,
|
|
46
|
+
};
|
|
47
|
+
export function detectTerminalCapabilities() {
|
|
48
|
+
const isTTY = !!process.stdout.isTTY;
|
|
49
|
+
const noColor = !!process.env.NO_COLOR;
|
|
50
|
+
const colorTerm = process.env.COLORTERM ?? '';
|
|
51
|
+
const termProgram = process.env.TERM_PROGRAM ?? '';
|
|
52
|
+
const term = process.env.TERM ?? '';
|
|
53
|
+
if (noColor) {
|
|
54
|
+
return { isTTY, supportsColor: false, supports256Color: false, supportsTrueColor: false };
|
|
55
|
+
}
|
|
56
|
+
const envSuggestsTrueColor = colorTerm === 'truecolor' ||
|
|
57
|
+
colorTerm === '24bit' ||
|
|
58
|
+
termProgram === 'iTerm.app' ||
|
|
59
|
+
termProgram === 'WezTerm' ||
|
|
60
|
+
termProgram === 'Hyper';
|
|
61
|
+
const envSuggests256Color = envSuggestsTrueColor || term.includes('256color') || termProgram === 'Apple_Terminal';
|
|
62
|
+
// All capability flags MUST be gated on `isTTY`. When stdout is piped to a
|
|
63
|
+
// file or CI log, ANSI truecolor escapes still leak in if callers inspect
|
|
64
|
+
// `supports256Color` / `supportsTrueColor` to decide whether to emit hex
|
|
65
|
+
// color values — even though `supportsColor` itself is correctly false.
|
|
66
|
+
// Treating capability as a single coherent gate (`isTTY && env signal`)
|
|
67
|
+
// prevents the exported surface from contradicting itself.
|
|
68
|
+
const supportsTrueColor = isTTY && envSuggestsTrueColor;
|
|
69
|
+
const supports256Color = isTTY && envSuggests256Color;
|
|
70
|
+
const supportsColor = isTTY && (envSuggests256Color || term !== 'dumb');
|
|
71
|
+
return { isTTY, supportsColor, supports256Color, supportsTrueColor };
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// React context + provider + hook
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
export const ThemeContext = React.createContext(DEFAULT_THEME);
|
|
77
|
+
export function ThemeProvider({ theme, children }) {
|
|
78
|
+
// Memoize the resolved theme so the context value reference is stable
|
|
79
|
+
// across re-renders. Ink's ClockProvider tick re-renders ThemeProvider
|
|
80
|
+
// on every frame; without useMemo, every render would re-read
|
|
81
|
+
// process.env, allocate a new `resolved` object, and force every
|
|
82
|
+
// `useTheme()` subscriber (Banner, Spinner, RunHeader, …) to re-render
|
|
83
|
+
// unnecessarily. Capability detection reads stable process state, so
|
|
84
|
+
// recomputing only when `theme` changes is correct.
|
|
85
|
+
const resolved = React.useMemo(() => {
|
|
86
|
+
if (theme)
|
|
87
|
+
return theme;
|
|
88
|
+
const caps = detectTerminalCapabilities();
|
|
89
|
+
return caps.supportsColor ? DEFAULT_THEME : NO_COLOR_THEME;
|
|
90
|
+
}, [theme]);
|
|
91
|
+
return React.createElement(ThemeContext.Provider, { value: resolved }, children);
|
|
92
|
+
}
|
|
93
|
+
export function useTheme() {
|
|
94
|
+
return React.useContext(ThemeContext);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared verbose-detail view producers (ADR-0021).
|
|
3
|
+
*
|
|
4
|
+
* `--verbose` is an output-currency concern: a tool's verbose detail body is
|
|
5
|
+
* carried as data on its `*DoneResult` and rendered ONCE through these
|
|
6
|
+
* producers, so the detail is identical in a TTY (`renderToInk`) and a pipe
|
|
7
|
+
* (`renderToText`). They replace the three hand-copied "Use --verbose…" hints
|
|
8
|
+
* and the fitness-local `FindingsBlock` Ink component.
|
|
9
|
+
*
|
|
10
|
+
* cli-ui must never import `@opensip-cli/contracts` (keystone boundary), so
|
|
11
|
+
* these take plain structural inputs ({@link FindingGroupView}) — the cli
|
|
12
|
+
* `resultToView` seam passes the contracts `FindingGroup` *values* straight in
|
|
13
|
+
* (the shapes are structurally identical; a type-compat test pins that).
|
|
14
|
+
*
|
|
15
|
+
* Pure data + types: no `ink`/`react` imports (same rule as view-model.ts).
|
|
16
|
+
*/
|
|
17
|
+
import { type HintItem, type ViewNode } from './view-model.js';
|
|
18
|
+
/** One displayed finding (structural twin of contracts' `FindingLine`). */
|
|
19
|
+
export interface FindingLineView {
|
|
20
|
+
readonly severity: 'error' | 'warning';
|
|
21
|
+
readonly message: string;
|
|
22
|
+
readonly location?: string;
|
|
23
|
+
readonly suggestion?: string;
|
|
24
|
+
}
|
|
25
|
+
/** A verbose findings block (structural twin of contracts' `FindingGroup`). */
|
|
26
|
+
export interface FindingGroupView {
|
|
27
|
+
readonly title: string;
|
|
28
|
+
readonly error?: string;
|
|
29
|
+
readonly errorCount: number;
|
|
30
|
+
readonly warningCount: number;
|
|
31
|
+
readonly findings: readonly FindingLineView[];
|
|
32
|
+
}
|
|
33
|
+
/** The single canonical "Use --verbose…" hint item. Tools that compose their
|
|
34
|
+
* own footer (e.g. graph, which also shows a report hint) reuse THIS item so
|
|
35
|
+
* the string is never re-typed. */
|
|
36
|
+
export declare const VERBOSE_DETAIL_HINT: HintItem;
|
|
37
|
+
/** The canonical next-step hint shown when a run was NOT verbose. */
|
|
38
|
+
export declare function viewVerboseHint(): ViewNode;
|
|
39
|
+
/** Render a line-oriented verbose body verbatim (graph's catalog/findings dump). */
|
|
40
|
+
export declare function viewVerboseLines(lines: readonly string[]): ViewNode;
|
|
41
|
+
/** Render a verbose findings body — header + one block per group. */
|
|
42
|
+
export declare function viewFindingsGroups(groups: readonly FindingGroupView[]): ViewNode;
|
|
43
|
+
//# sourceMappingURL=verbose-detail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verbose-detail.d.ts","sourceRoot":"","sources":["../src/verbose-detail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAe,KAAK,QAAQ,EAAa,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAKvF,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;CAC/C;AAED;;oCAEoC;AACpC,eAAO,MAAM,mBAAmB,EAAE,QAGjC,CAAC;AAEF,qEAAqE;AACrE,wBAAgB,eAAe,IAAI,QAAQ,CAE1C;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,CAEnE;AAkED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,QAAQ,CAchF"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared verbose-detail view producers (ADR-0021).
|
|
3
|
+
*
|
|
4
|
+
* `--verbose` is an output-currency concern: a tool's verbose detail body is
|
|
5
|
+
* carried as data on its `*DoneResult` and rendered ONCE through these
|
|
6
|
+
* producers, so the detail is identical in a TTY (`renderToInk`) and a pipe
|
|
7
|
+
* (`renderToText`). They replace the three hand-copied "Use --verbose…" hints
|
|
8
|
+
* and the fitness-local `FindingsBlock` Ink component.
|
|
9
|
+
*
|
|
10
|
+
* cli-ui must never import `@opensip-cli/contracts` (keystone boundary), so
|
|
11
|
+
* these take plain structural inputs ({@link FindingGroupView}) — the cli
|
|
12
|
+
* `resultToView` seam passes the contracts `FindingGroup` *values* straight in
|
|
13
|
+
* (the shapes are structurally identical; a type-compat test pins that).
|
|
14
|
+
*
|
|
15
|
+
* Pure data + types: no `ink`/`react` imports (same rule as view-model.ts).
|
|
16
|
+
*/
|
|
17
|
+
import { viewFooterHints } from './run-footer-hints.js';
|
|
18
|
+
import { group, line } from './view-model.js';
|
|
19
|
+
/** Per-check cap on rendered findings — mirrors the prior FindingsBlock limit. */
|
|
20
|
+
const DEFAULT_VIOLATIONS_PER_GROUP = 25;
|
|
21
|
+
/** The single canonical "Use --verbose…" hint item. Tools that compose their
|
|
22
|
+
* own footer (e.g. graph, which also shows a report hint) reuse THIS item so
|
|
23
|
+
* the string is never re-typed. */
|
|
24
|
+
export const VERBOSE_DETAIL_HINT = {
|
|
25
|
+
text: 'Use --verbose for detailed results',
|
|
26
|
+
bold: ['--verbose'],
|
|
27
|
+
};
|
|
28
|
+
/** The canonical next-step hint shown when a run was NOT verbose. */
|
|
29
|
+
export function viewVerboseHint() {
|
|
30
|
+
return viewFooterHints([VERBOSE_DETAIL_HINT]);
|
|
31
|
+
}
|
|
32
|
+
/** Render a line-oriented verbose body verbatim (graph's catalog/findings dump). */
|
|
33
|
+
export function viewVerboseLines(lines) {
|
|
34
|
+
return group(lines.map((l) => line([{ text: l }])));
|
|
35
|
+
}
|
|
36
|
+
/** Render one finding row: ` error <message> <location>` + optional suggestion. */
|
|
37
|
+
function findingNode(f) {
|
|
38
|
+
const spans = [
|
|
39
|
+
{ text: ' ' },
|
|
40
|
+
{
|
|
41
|
+
text: f.severity === 'error' ? 'error' : 'warn',
|
|
42
|
+
tone: f.severity === 'error' ? 'error' : 'warning',
|
|
43
|
+
},
|
|
44
|
+
{ text: ' ' },
|
|
45
|
+
{ text: f.message },
|
|
46
|
+
];
|
|
47
|
+
if (f.location !== undefined && f.location !== '') {
|
|
48
|
+
spans.push({ text: ' ' }, { text: f.location, dim: true });
|
|
49
|
+
}
|
|
50
|
+
const rows = [line(spans)];
|
|
51
|
+
if (f.suggestion !== undefined && f.suggestion !== '') {
|
|
52
|
+
rows.push(line([{ text: ' ' }, { text: f.suggestion, dim: true }]));
|
|
53
|
+
}
|
|
54
|
+
return group(rows);
|
|
55
|
+
}
|
|
56
|
+
/** Render one findings group: a check title + count, an optional error line, the
|
|
57
|
+
* capped findings, and a "+N more" line when truncated. */
|
|
58
|
+
function groupNode(g) {
|
|
59
|
+
const count = g.errorCount + g.warningCount + (g.error === undefined ? 0 : 1);
|
|
60
|
+
const visible = g.findings.slice(0, DEFAULT_VIOLATIONS_PER_GROUP);
|
|
61
|
+
const hidden = Math.max(0, g.findings.length - visible.length);
|
|
62
|
+
const children = [
|
|
63
|
+
line([
|
|
64
|
+
{ text: g.title, tone: 'brand' },
|
|
65
|
+
{ text: ` (${String(count)})`, dim: true },
|
|
66
|
+
]),
|
|
67
|
+
];
|
|
68
|
+
if (g.error !== undefined) {
|
|
69
|
+
children.push(line([
|
|
70
|
+
{ text: ' ' },
|
|
71
|
+
{ text: 'error', tone: 'error' },
|
|
72
|
+
{ text: ' ' },
|
|
73
|
+
{ text: g.error },
|
|
74
|
+
]));
|
|
75
|
+
}
|
|
76
|
+
for (const f of visible)
|
|
77
|
+
children.push(findingNode(f));
|
|
78
|
+
if (hidden > 0) {
|
|
79
|
+
children.push(line([
|
|
80
|
+
{ text: ' … ' },
|
|
81
|
+
{ text: `${String(hidden)} more hidden (use ` },
|
|
82
|
+
{ text: '--json', bold: true },
|
|
83
|
+
{ text: ' or ' },
|
|
84
|
+
{ text: 'opensip report', bold: true },
|
|
85
|
+
{ text: ' for all)' },
|
|
86
|
+
], true));
|
|
87
|
+
}
|
|
88
|
+
children.push({ kind: 'spacer' });
|
|
89
|
+
return group(children, 2);
|
|
90
|
+
}
|
|
91
|
+
/** Render a verbose findings body — header + one block per group. */
|
|
92
|
+
export function viewFindingsGroups(groups) {
|
|
93
|
+
const total = groups.reduce((sum, g) => sum + g.errorCount + g.warningCount + (g.error === undefined ? 0 : 1), 0);
|
|
94
|
+
const children = [
|
|
95
|
+
line([
|
|
96
|
+
{ text: 'Findings', bold: true },
|
|
97
|
+
{ text: ` (${String(total)}):`, dim: true },
|
|
98
|
+
]),
|
|
99
|
+
{ kind: 'spacer' },
|
|
100
|
+
...groups.map((g) => groupNode(g)),
|
|
101
|
+
];
|
|
102
|
+
return group(children, 2);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=verbose-detail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verbose-detail.js","sourceRoot":"","sources":["../src/verbose-detail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View-model — the renderer-agnostic vocabulary that decouples *what* a
|
|
3
|
+
* command shows from *how* it is rendered.
|
|
4
|
+
*
|
|
5
|
+
* A `ViewNode` describes output as a tree of line-oriented blocks. Two
|
|
6
|
+
* interpreters consume the same tree: `renderToInk` (TTY, themed) and
|
|
7
|
+
* `renderToText` (pipe/CI, zero ANSI). Because each piece of output is
|
|
8
|
+
* expressed once as a `ViewNode`, the interactive and non-interactive
|
|
9
|
+
* forms cannot structurally drift — there is no second definition to fall
|
|
10
|
+
* out of sync. This generalizes the existing `formatProjectHeader` +
|
|
11
|
+
* `ProjectHeader` pattern (format once, render twice) to all CLI output.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately NOT a general layout engine: there is no flexbox, no
|
|
14
|
+
* multi-column flow beyond the simple `table` node. Keep it line-oriented;
|
|
15
|
+
* if a node needs richer layout, that is a signal to reconsider rather
|
|
16
|
+
* than to grow this vocabulary.
|
|
17
|
+
*
|
|
18
|
+
* This module is pure data + types. It must stay free of `ink`/`react`
|
|
19
|
+
* imports so `renderToText` (and its consumers on the piped path) never
|
|
20
|
+
* pull React into the process.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Semantic color intent. The Ink interpreter maps each tone onto a
|
|
24
|
+
* `DEFAULT_THEME` token; the text interpreter ignores tones entirely. The
|
|
25
|
+
* theme remains the single source of color truth — producers never name
|
|
26
|
+
* raw colors.
|
|
27
|
+
*/
|
|
28
|
+
export type Tone = 'brand' | 'success' | 'error' | 'warning' | 'info' | 'muted' | 'default';
|
|
29
|
+
/** An inline run of text within a line, optionally toned, bold, and/or dimmed. */
|
|
30
|
+
export interface Span {
|
|
31
|
+
readonly text: string;
|
|
32
|
+
readonly tone?: Tone;
|
|
33
|
+
readonly bold?: boolean;
|
|
34
|
+
/** Render this span muted (Ink `dimColor`). Dropped by the text interpreter. */
|
|
35
|
+
readonly dim?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** A single hint in a footer strip: its text and which substrings to bold. */
|
|
38
|
+
export interface HintItem {
|
|
39
|
+
readonly text: string;
|
|
40
|
+
readonly bold?: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Block-level output node. The interpreters switch on `kind`; every kind
|
|
44
|
+
* is total in both interpreters (no node may render in one and throw in
|
|
45
|
+
* the other).
|
|
46
|
+
*/
|
|
47
|
+
export type ViewNode =
|
|
48
|
+
/** One line of styled spans. `dim` renders the whole line muted. */
|
|
49
|
+
{
|
|
50
|
+
readonly kind: 'line';
|
|
51
|
+
readonly spans: readonly Span[];
|
|
52
|
+
readonly dim?: boolean;
|
|
53
|
+
}
|
|
54
|
+
/** A section heading (e.g. `== Findings ==`). */
|
|
55
|
+
| {
|
|
56
|
+
readonly kind: 'heading';
|
|
57
|
+
readonly text: string;
|
|
58
|
+
readonly tone?: Tone;
|
|
59
|
+
}
|
|
60
|
+
/** A block of `label: value` pairs, one per line. */
|
|
61
|
+
| {
|
|
62
|
+
readonly kind: 'keyValues';
|
|
63
|
+
readonly pairs: readonly {
|
|
64
|
+
readonly label: string;
|
|
65
|
+
readonly value: string;
|
|
66
|
+
}[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A column-aligned table. Each row is a list of cell spans — one span per
|
|
70
|
+
* column (cell N styles column N). Both interpreters pad every cell to its
|
|
71
|
+
* column's width (the max of the header and all cells in that column), so the
|
|
72
|
+
* columns line up in a TTY and a pipe alike. `align` is per-column
|
|
73
|
+
* (`'right'` pads on the left — for numeric/duration columns); default left.
|
|
74
|
+
*/
|
|
75
|
+
| {
|
|
76
|
+
readonly kind: 'table';
|
|
77
|
+
readonly columns: readonly string[];
|
|
78
|
+
readonly rows: readonly (readonly Span[])[];
|
|
79
|
+
readonly align?: readonly ('left' | 'right')[];
|
|
80
|
+
/** When false, suppress the header row (a bare aligned grid). Default true. */
|
|
81
|
+
readonly showHeader?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/** A next-step hint strip, ` | `-joined, with bolded flag substrings. */
|
|
84
|
+
| {
|
|
85
|
+
readonly kind: 'hints';
|
|
86
|
+
readonly items: readonly HintItem[];
|
|
87
|
+
}
|
|
88
|
+
/** A horizontal rule. */
|
|
89
|
+
| {
|
|
90
|
+
readonly kind: 'separator';
|
|
91
|
+
}
|
|
92
|
+
/** A single blank line. */
|
|
93
|
+
| {
|
|
94
|
+
readonly kind: 'spacer';
|
|
95
|
+
}
|
|
96
|
+
/** A container; children render in order, optionally indented. */
|
|
97
|
+
| {
|
|
98
|
+
readonly kind: 'group';
|
|
99
|
+
readonly children: readonly ViewNode[];
|
|
100
|
+
readonly indent?: number;
|
|
101
|
+
};
|
|
102
|
+
/** A line from plain text (single default-toned span). */
|
|
103
|
+
export declare function text(value: string): Span;
|
|
104
|
+
/** A line node from spans (or a single string). */
|
|
105
|
+
export declare function line(spans: readonly Span[] | string, dim?: boolean): ViewNode;
|
|
106
|
+
/** A group node from children, optionally indented. */
|
|
107
|
+
export declare function group(children: readonly ViewNode[], indent?: number): ViewNode;
|
|
108
|
+
/**
|
|
109
|
+
* Per-column display widths for a `table` node — the max of each column's header
|
|
110
|
+
* and all its cells. Shared by both interpreters so the TTY and pipe forms pad
|
|
111
|
+
* identically. Pure (no react), so `render-to-text` can use it too.
|
|
112
|
+
*/
|
|
113
|
+
export declare function tableColumnWidths(columns: readonly string[], rows: readonly (readonly Span[])[]): number[];
|
|
114
|
+
/** Pad `value` to `width`; `'right'` pads on the left (numeric/duration columns). */
|
|
115
|
+
export declare function padTableCell(value: string, width: number, align: 'left' | 'right'): string;
|
|
116
|
+
/** Per-column spec for {@link viewTable}: a header label and optional alignment. */
|
|
117
|
+
export interface TableColumnSpec {
|
|
118
|
+
readonly header: string;
|
|
119
|
+
readonly align?: 'left' | 'right';
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build a column-aligned `table` node. Columns may be plain header strings or
|
|
123
|
+
* {@link TableColumnSpec}s (to right-align numeric columns). Each row is one
|
|
124
|
+
* span per column (cell N styles column N); the interpreters pad every cell to
|
|
125
|
+
* its column width so the grid lines up in a TTY and a pipe. This is the shared,
|
|
126
|
+
* reusable table primitive — producers (history, session replay, per-unit
|
|
127
|
+
* results) build one of these instead of hand-padding lines.
|
|
128
|
+
*/
|
|
129
|
+
export declare function viewTable(columns: readonly (string | TableColumnSpec)[], rows: readonly (readonly Span[])[], opts?: {
|
|
130
|
+
readonly showHeader?: boolean;
|
|
131
|
+
}): ViewNode;
|
|
132
|
+
//# sourceMappingURL=view-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-model.d.ts","sourceRoot":"","sources":["../src/view-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View-model — the renderer-agnostic vocabulary that decouples *what* a
|
|
3
|
+
* command shows from *how* it is rendered.
|
|
4
|
+
*
|
|
5
|
+
* A `ViewNode` describes output as a tree of line-oriented blocks. Two
|
|
6
|
+
* interpreters consume the same tree: `renderToInk` (TTY, themed) and
|
|
7
|
+
* `renderToText` (pipe/CI, zero ANSI). Because each piece of output is
|
|
8
|
+
* expressed once as a `ViewNode`, the interactive and non-interactive
|
|
9
|
+
* forms cannot structurally drift — there is no second definition to fall
|
|
10
|
+
* out of sync. This generalizes the existing `formatProjectHeader` +
|
|
11
|
+
* `ProjectHeader` pattern (format once, render twice) to all CLI output.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately NOT a general layout engine: there is no flexbox, no
|
|
14
|
+
* multi-column flow beyond the simple `table` node. Keep it line-oriented;
|
|
15
|
+
* if a node needs richer layout, that is a signal to reconsider rather
|
|
16
|
+
* than to grow this vocabulary.
|
|
17
|
+
*
|
|
18
|
+
* This module is pure data + types. It must stay free of `ink`/`react`
|
|
19
|
+
* imports so `renderToText` (and its consumers on the piped path) never
|
|
20
|
+
* pull React into the process.
|
|
21
|
+
*/
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Constructor helpers — keep producers terse without hiding the data shape.
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
/** A line from plain text (single default-toned span). */
|
|
26
|
+
export function text(value) {
|
|
27
|
+
return { text: value };
|
|
28
|
+
}
|
|
29
|
+
/** A line node from spans (or a single string). */
|
|
30
|
+
export function line(spans, dim) {
|
|
31
|
+
const resolved = typeof spans === 'string' ? [text(spans)] : spans;
|
|
32
|
+
return dim === undefined
|
|
33
|
+
? { kind: 'line', spans: resolved }
|
|
34
|
+
: { kind: 'line', spans: resolved, dim };
|
|
35
|
+
}
|
|
36
|
+
/** A group node from children, optionally indented. */
|
|
37
|
+
export function group(children, indent) {
|
|
38
|
+
return indent === undefined ? { kind: 'group', children } : { kind: 'group', children, indent };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Per-column display widths for a `table` node — the max of each column's header
|
|
42
|
+
* and all its cells. Shared by both interpreters so the TTY and pipe forms pad
|
|
43
|
+
* identically. Pure (no react), so `render-to-text` can use it too.
|
|
44
|
+
*/
|
|
45
|
+
export function tableColumnWidths(columns, rows) {
|
|
46
|
+
const colCount = Math.max(columns.length, ...rows.map((r) => r.length), 0);
|
|
47
|
+
return Array.from({ length: colCount }, (_, i) => Math.max(columns[i]?.length ?? 0, ...rows.map((r) => r[i]?.text.length ?? 0), 0));
|
|
48
|
+
}
|
|
49
|
+
/** Pad `value` to `width`; `'right'` pads on the left (numeric/duration columns). */
|
|
50
|
+
export function padTableCell(value, width, align) {
|
|
51
|
+
return align === 'right' ? value.padStart(width) : value.padEnd(width);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build a column-aligned `table` node. Columns may be plain header strings or
|
|
55
|
+
* {@link TableColumnSpec}s (to right-align numeric columns). Each row is one
|
|
56
|
+
* span per column (cell N styles column N); the interpreters pad every cell to
|
|
57
|
+
* its column width so the grid lines up in a TTY and a pipe. This is the shared,
|
|
58
|
+
* reusable table primitive — producers (history, session replay, per-unit
|
|
59
|
+
* results) build one of these instead of hand-padding lines.
|
|
60
|
+
*/
|
|
61
|
+
export function viewTable(columns, rows, opts) {
|
|
62
|
+
const specs = columns.map((c) => (typeof c === 'string' ? { header: c } : c));
|
|
63
|
+
return {
|
|
64
|
+
kind: 'table',
|
|
65
|
+
columns: specs.map((s) => s.header),
|
|
66
|
+
rows,
|
|
67
|
+
align: specs.map((s) => s.align ?? 'left'),
|
|
68
|
+
...(opts?.showHeader === undefined ? {} : { showHeader: opts.showHeader }),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=view-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-model.js","sourceRoot":"","sources":["../src/view-model.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opensip-cli/cli-ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"description": "Shared Ink/React presentational primitives for OpenSIP CLI CLI tools — banner, spinner, run header, theme. Used by every tool that ships an Ink live view.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"opensip-cli",
|
|
8
|
+
"static-analysis",
|
|
9
|
+
"code-quality",
|
|
10
|
+
"cli",
|
|
11
|
+
"terminal",
|
|
12
|
+
"ink",
|
|
13
|
+
"react"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/opensip-ai/opensip-cli.git",
|
|
18
|
+
"directory": "packages/cli-ui"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/opensip-ai/opensip-cli",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/opensip-ai/opensip-cli/issues"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": "./dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"NOTICE"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"ink": "^7.0.5",
|
|
37
|
+
"react": "^19.2.7"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^24.13.2",
|
|
41
|
+
"@types/react": "^19.2.17",
|
|
42
|
+
"ink-testing-library": "^4.0.0",
|
|
43
|
+
"typescript": "~6.0.3",
|
|
44
|
+
"vitest": "^4.1.8"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc",
|
|
48
|
+
"test": "vitest run --passWithNoTests",
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"clean": "rm -rf dist"
|
|
51
|
+
}
|
|
52
|
+
}
|