@rainy-updates/cli 0.5.4 → 0.5.7
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/CHANGELOG.md +136 -0
- package/README.md +5 -0
- package/dist/bin/cli.js +16 -438
- package/dist/bin/dispatch.d.ts +16 -0
- package/dist/bin/dispatch.js +150 -0
- package/dist/bin/help.d.ts +1 -0
- package/dist/bin/help.js +284 -0
- package/dist/commands/audit/runner.js +43 -26
- package/dist/commands/dashboard/parser.d.ts +2 -0
- package/dist/commands/dashboard/parser.js +59 -0
- package/dist/commands/dashboard/runner.d.ts +2 -0
- package/dist/commands/dashboard/runner.js +47 -0
- package/dist/commands/doctor/parser.js +12 -0
- package/dist/commands/doctor/runner.js +5 -2
- package/dist/commands/ga/parser.d.ts +2 -0
- package/dist/commands/ga/parser.js +50 -0
- package/dist/commands/ga/runner.d.ts +2 -0
- package/dist/commands/ga/runner.js +129 -0
- package/dist/commands/resolve/runner.js +7 -3
- package/dist/commands/review/parser.js +6 -0
- package/dist/commands/review/runner.js +4 -3
- package/dist/core/analysis/options.d.ts +6 -0
- package/dist/core/analysis/options.js +69 -0
- package/dist/core/analysis/review-items.d.ts +4 -0
- package/dist/core/analysis/review-items.js +128 -0
- package/dist/core/analysis/run-silenced.d.ts +1 -0
- package/dist/core/analysis/run-silenced.js +14 -0
- package/dist/core/analysis-bundle.d.ts +4 -0
- package/dist/core/analysis-bundle.js +33 -0
- package/dist/core/artifacts.d.ts +3 -0
- package/dist/core/artifacts.js +48 -0
- package/dist/core/check.js +6 -1
- package/dist/core/doctor/findings.d.ts +2 -0
- package/dist/core/doctor/findings.js +166 -0
- package/dist/core/doctor/render.d.ts +3 -0
- package/dist/core/doctor/render.js +44 -0
- package/dist/core/doctor/result.d.ts +2 -0
- package/dist/core/doctor/result.js +55 -0
- package/dist/core/doctor/score.d.ts +5 -0
- package/dist/core/doctor/score.js +28 -0
- package/dist/core/options.d.ts +7 -1
- package/dist/core/options.js +14 -0
- package/dist/core/review-model.d.ts +3 -3
- package/dist/core/review-model.js +55 -245
- package/dist/core/review-verdict.d.ts +2 -0
- package/dist/core/review-verdict.js +14 -0
- package/dist/core/summary.js +19 -0
- package/dist/output/format.js +22 -0
- package/dist/output/github.js +12 -0
- package/dist/output/sarif.js +16 -0
- package/dist/types/index.d.ts +120 -0
- package/dist/ui/dashboard/DashboardTUI.d.ts +6 -0
- package/dist/ui/dashboard/DashboardTUI.js +34 -0
- package/dist/ui/dashboard/components/DetailPanel.d.ts +4 -0
- package/dist/ui/dashboard/components/DetailPanel.js +30 -0
- package/dist/ui/dashboard/components/Footer.d.ts +4 -0
- package/dist/ui/dashboard/components/Footer.js +9 -0
- package/dist/ui/dashboard/components/Header.d.ts +4 -0
- package/dist/ui/dashboard/components/Header.js +12 -0
- package/dist/ui/dashboard/components/Sidebar.d.ts +4 -0
- package/dist/ui/dashboard/components/Sidebar.js +23 -0
- package/dist/ui/dashboard/store.d.ts +34 -0
- package/dist/ui/dashboard/store.js +148 -0
- package/dist/ui/tui.d.ts +2 -2
- package/dist/ui/tui.js +310 -79
- package/package.json +1 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DashboardOptions, CheckResult } from "../../types/index.js";
|
|
2
|
+
export interface DashboardTUIProps {
|
|
3
|
+
options: DashboardOptions;
|
|
4
|
+
initialResult: CheckResult;
|
|
5
|
+
}
|
|
6
|
+
export declare function DashboardTUI({ options, initialResult }: DashboardTUIProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, useInput, useApp } from "ink";
|
|
3
|
+
import { initStore, dashboardActions } from "./store.js";
|
|
4
|
+
import { Header } from "./components/Header.js";
|
|
5
|
+
import { Sidebar } from "./components/Sidebar.js";
|
|
6
|
+
import { DetailPanel } from "./components/DetailPanel.js";
|
|
7
|
+
import { Footer } from "./components/Footer.js";
|
|
8
|
+
export function DashboardTUI({ options, initialResult }) {
|
|
9
|
+
const { exit } = useApp();
|
|
10
|
+
// Initialize the singleton store synchronously before rendering children
|
|
11
|
+
// so that components can access it on the first render pass natively.
|
|
12
|
+
initStore(options, initialResult);
|
|
13
|
+
// Handle global keyboard input (doesn't trigger React re-renders unless store state affects this component)
|
|
14
|
+
// Our static layout theoretically will not re-render off this hook alone.
|
|
15
|
+
useInput((input, key) => {
|
|
16
|
+
if (key.upArrow) {
|
|
17
|
+
dashboardActions.moveCursorUp();
|
|
18
|
+
}
|
|
19
|
+
if (key.downArrow) {
|
|
20
|
+
dashboardActions.moveCursorDown();
|
|
21
|
+
}
|
|
22
|
+
if (key.return) {
|
|
23
|
+
dashboardActions.setShouldApply(true);
|
|
24
|
+
exit();
|
|
25
|
+
}
|
|
26
|
+
if (input === "r") {
|
|
27
|
+
void dashboardActions.runResolveAction();
|
|
28
|
+
}
|
|
29
|
+
if (input === "a") {
|
|
30
|
+
void dashboardActions.runAuditAction();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return (_jsxs(Box, { flexDirection: "column", minHeight: 25, children: [_jsx(Header, {}), _jsxs(Box, { flexDirection: "row", width: "100%", children: [_jsx(Sidebar, {}), _jsx(DetailPanel, {})] }), _jsx(Footer, {})] }));
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
import { useDashboardStore } from "../store.js";
|
|
5
|
+
function getRiskColor(risk) {
|
|
6
|
+
switch (risk) {
|
|
7
|
+
case "critical":
|
|
8
|
+
return "red";
|
|
9
|
+
case "high":
|
|
10
|
+
return "red";
|
|
11
|
+
case "medium":
|
|
12
|
+
return "yellow";
|
|
13
|
+
case "low":
|
|
14
|
+
return "blue";
|
|
15
|
+
default:
|
|
16
|
+
return "gray";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function DetailPanelComponent() {
|
|
20
|
+
const selectedIndex = useDashboardStore((s) => s.selectedIndex);
|
|
21
|
+
const updates = useDashboardStore((s) => s.updates);
|
|
22
|
+
// Fallback if list is empty
|
|
23
|
+
const update = updates[selectedIndex];
|
|
24
|
+
if (!update) {
|
|
25
|
+
return (_jsx(Box, { width: "50%", height: 22, padding: 1, borderStyle: "single", borderColor: "gray", children: _jsx(Text, { dimColor: true, children: "No package selected." }) }));
|
|
26
|
+
}
|
|
27
|
+
const { name, publishedAt, publishAgeDays, riskLevel, homepage, advisoryCount, peerConflictSeverity, } = update;
|
|
28
|
+
return (_jsxs(Box, { width: "50%", height: 22, flexDirection: "column", paddingX: 2, borderStyle: "single", borderColor: "gray", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: name }) }), _jsxs(Box, { marginBottom: 2, flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, children: "Risk: " }), _jsx(Text, { color: getRiskColor(riskLevel), children: riskLevel || "unknown" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, children: "Advisories: " }), _jsx(Text, { color: advisoryCount ? "red" : "green", children: advisoryCount || 0 })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, children: "Peer Conflicts: " }), _jsx(Text, { color: peerConflictSeverity ? "red" : "green", children: peerConflictSeverity || "none" })] })] }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Text, { color: "gray", children: homepage || "No homepage provided" }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Published ", publishAgeDays, " days ago", " ", publishedAt ? `(${publishedAt})` : ""] }) })] }));
|
|
29
|
+
}
|
|
30
|
+
export const DetailPanel = React.memo(DetailPanelComponent);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
import { useDashboardStore } from "../store.js";
|
|
5
|
+
function FooterComponent() {
|
|
6
|
+
const modal = useDashboardStore((s) => s.modal);
|
|
7
|
+
return (_jsxs(Box, { width: "100%", paddingX: 1, flexDirection: "row", justifyContent: "space-between", children: [_jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [_jsx(Text, { bold: true, color: "white", children: "\u2191\u2193" }), " ", "Navigate |", _jsxs(Text, { bold: true, color: "white", children: [" ", "Enter"] }), " ", "Apply |", _jsxs(Text, { bold: true, color: "white", children: [" ", "r"] }), "esolve |", _jsxs(Text, { bold: true, color: "white", children: [" ", "a"] }), "udit |", _jsxs(Text, { bold: true, color: "white", children: [" ", "i"] }), "gnore"] }) }), _jsx(Box, { children: _jsx(Text, { color: "yellow", children: modal !== "none" ? `Status: ${modal}...` : "Status: Idle" }) })] }));
|
|
8
|
+
}
|
|
9
|
+
export const Footer = React.memo(FooterComponent);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
import { useDashboardStore } from "../store.js";
|
|
5
|
+
function HeaderComponent() {
|
|
6
|
+
const scanned = useDashboardStore((s) => s.summary.scannedPackages);
|
|
7
|
+
const totalUpdates = useDashboardStore((s) => s.updates.length);
|
|
8
|
+
const view = useDashboardStore((s) => s.view);
|
|
9
|
+
return (_jsxs(Box, { width: "100%", paddingX: 1, borderStyle: "single", borderColor: "blue", flexDirection: "row", justifyContent: "space-between", children: [_jsx(Box, { children: _jsx(Text, { color: "cyan", bold: true, children: "\uD83C\uDF27\uFE0F Rainy Updates Dashboard" }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: view === "dependencies" ? "green" : "gray", children: "[Dependencies]" }), " ", _jsx(Text, { color: view === "security" ? "green" : "gray", children: "[Security]" }), " ", _jsx(Text, { color: view === "health" ? "green" : "gray", children: "[Health]" })] }) }), _jsx(Box, { children: _jsxs(Text, { dimColor: true, children: ["Packages: ", scanned, " | Found: ", totalUpdates] }) })] }));
|
|
10
|
+
}
|
|
11
|
+
// Memoize to ensure Header only renders when deeply affected (which is rare)
|
|
12
|
+
export const Header = React.memo(HeaderComponent);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
import { useDashboardStore } from "../store.js";
|
|
5
|
+
// A heavily memoized single row
|
|
6
|
+
const DependencyRow = React.memo(({ update, isActive }) => {
|
|
7
|
+
return (_jsxs(Box, { paddingX: 1, width: "100%", children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: "cyan", children: isActive ? "> " : " " }) }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { color: isActive ? "white" : "gray", bold: isActive, children: update.name }) }), _jsx(Box, { width: 15, justifyContent: "flex-end", children: _jsx(Text, { dimColor: true, children: update.fromRange }) }), _jsx(Box, { width: 3, justifyContent: "center", children: _jsx(Text, { dimColor: true, children: "\u2192" }) }), _jsx(Box, { width: 15, children: _jsx(Text, { color: "green", children: update.toRange }) })] }));
|
|
8
|
+
});
|
|
9
|
+
DependencyRow.displayName = "DependencyRow";
|
|
10
|
+
function SidebarComponent() {
|
|
11
|
+
const updates = useDashboardStore((s) => s.updates);
|
|
12
|
+
const selectedIndex = useDashboardStore((s) => s.selectedIndex);
|
|
13
|
+
// Simple windowing: in a real robust TUI we'd calculate terminal height
|
|
14
|
+
// For now we'll just slice the array based on a fixed viewport (e.g., 20 items)
|
|
15
|
+
const windowSize = 20;
|
|
16
|
+
const start = Math.max(0, Math.min(selectedIndex - windowSize / 2, updates.length - windowSize));
|
|
17
|
+
const visibleUpdates = updates.slice(start, start + windowSize);
|
|
18
|
+
return (_jsxs(Box, { width: "50%", flexDirection: "column", borderStyle: "single", borderColor: "gray", height: windowSize + 2, children: [visibleUpdates.map((update, i) => {
|
|
19
|
+
const actualIndex = start + i;
|
|
20
|
+
return (_jsx(DependencyRow, { update: update, index: actualIndex, isActive: actualIndex === selectedIndex }, `${update.name}-${update.toRange}`));
|
|
21
|
+
}), updates.length === 0 && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "No updates found." }) }))] }));
|
|
22
|
+
}
|
|
23
|
+
export const Sidebar = React.memo(SidebarComponent);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { DashboardOptions, CheckResult, PackageUpdate } from "../../types/index.js";
|
|
2
|
+
export interface DashboardState {
|
|
3
|
+
selectedIndex: number;
|
|
4
|
+
view: "dependencies" | "security" | "health";
|
|
5
|
+
modal: "none" | "resolving" | "auditing" | "applying";
|
|
6
|
+
updates: PackageUpdate[];
|
|
7
|
+
summary: CheckResult["summary"];
|
|
8
|
+
options: DashboardOptions;
|
|
9
|
+
error?: string;
|
|
10
|
+
shouldApply: boolean;
|
|
11
|
+
}
|
|
12
|
+
type Listener = () => void;
|
|
13
|
+
declare class DashboardStore {
|
|
14
|
+
private state;
|
|
15
|
+
private listeners;
|
|
16
|
+
constructor(initialState: DashboardState);
|
|
17
|
+
getState: () => DashboardState;
|
|
18
|
+
setState: (partial: Partial<DashboardState> | ((state: DashboardState) => Partial<DashboardState>)) => void;
|
|
19
|
+
subscribe: (listener: Listener) => () => boolean;
|
|
20
|
+
private emit;
|
|
21
|
+
}
|
|
22
|
+
export declare function initStore(options: DashboardOptions, initialResult: CheckResult): DashboardStore;
|
|
23
|
+
export declare function useDashboardStore<T>(selector: (state: DashboardState) => T): T;
|
|
24
|
+
export declare const dashboardActions: {
|
|
25
|
+
moveCursorUp: () => void;
|
|
26
|
+
moveCursorDown: () => void;
|
|
27
|
+
setView: (view: DashboardState["view"]) => void;
|
|
28
|
+
setModal: (modal: DashboardState["modal"]) => void;
|
|
29
|
+
setShouldApply: (shouldApply: boolean) => void;
|
|
30
|
+
runResolveAction: () => Promise<void>;
|
|
31
|
+
runAuditAction: () => Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
export declare function getStore(): DashboardStore | null;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
import { runResolve } from "../../commands/resolve/runner.js";
|
|
3
|
+
import { runAudit } from "../../commands/audit/runner.js";
|
|
4
|
+
class DashboardStore {
|
|
5
|
+
state;
|
|
6
|
+
listeners = new Set();
|
|
7
|
+
constructor(initialState) {
|
|
8
|
+
this.state = initialState;
|
|
9
|
+
}
|
|
10
|
+
getState = () => this.state;
|
|
11
|
+
setState = (partial) => {
|
|
12
|
+
const changes = typeof partial === "function" ? partial(this.state) : partial;
|
|
13
|
+
this.state = { ...this.state, ...changes };
|
|
14
|
+
this.emit();
|
|
15
|
+
};
|
|
16
|
+
subscribe = (listener) => {
|
|
17
|
+
this.listeners.add(listener);
|
|
18
|
+
return () => this.listeners.delete(listener);
|
|
19
|
+
};
|
|
20
|
+
emit() {
|
|
21
|
+
for (const listener of this.listeners) {
|
|
22
|
+
listener();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Global singleton per run
|
|
27
|
+
let store = null;
|
|
28
|
+
export function initStore(options, initialResult) {
|
|
29
|
+
if (!store) {
|
|
30
|
+
store = new DashboardStore({
|
|
31
|
+
selectedIndex: 0,
|
|
32
|
+
view: options.view ?? "dependencies",
|
|
33
|
+
modal: "none",
|
|
34
|
+
updates: initialResult.updates,
|
|
35
|
+
summary: initialResult.summary,
|
|
36
|
+
options,
|
|
37
|
+
shouldApply: false,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return store;
|
|
41
|
+
}
|
|
42
|
+
// Hook to use the store in components, taking a selector to prevent unnecessary re-renders
|
|
43
|
+
export function useDashboardStore(selector) {
|
|
44
|
+
if (!store)
|
|
45
|
+
throw new Error("Store not initialized");
|
|
46
|
+
// Custom equality check could be added, but returning primitive/stable references from selector works best
|
|
47
|
+
return useSyncExternalStore(store.subscribe, () => selector(store.getState()));
|
|
48
|
+
}
|
|
49
|
+
// Export actions to modify state without re-rendering the caller
|
|
50
|
+
export const dashboardActions = {
|
|
51
|
+
moveCursorUp: () => {
|
|
52
|
+
store?.setState((s) => ({
|
|
53
|
+
selectedIndex: Math.max(0, s.selectedIndex - 1),
|
|
54
|
+
}));
|
|
55
|
+
},
|
|
56
|
+
moveCursorDown: () => {
|
|
57
|
+
store?.setState((s) => ({
|
|
58
|
+
selectedIndex: Math.min(s.updates.length - 1, s.selectedIndex + 1),
|
|
59
|
+
}));
|
|
60
|
+
},
|
|
61
|
+
setView: (view) => {
|
|
62
|
+
store?.setState({ view, selectedIndex: 0 }); // reset cursor on view change
|
|
63
|
+
},
|
|
64
|
+
setModal: (modal) => {
|
|
65
|
+
store?.setState({ modal });
|
|
66
|
+
},
|
|
67
|
+
setShouldApply: (shouldApply) => {
|
|
68
|
+
store?.setState({ shouldApply });
|
|
69
|
+
},
|
|
70
|
+
runResolveAction: async () => {
|
|
71
|
+
if (!store)
|
|
72
|
+
return;
|
|
73
|
+
const s = store.getState();
|
|
74
|
+
store.setState({ modal: "resolving" });
|
|
75
|
+
try {
|
|
76
|
+
const resolveOpts = {
|
|
77
|
+
cwd: s.options.cwd,
|
|
78
|
+
workspace: s.options.workspace,
|
|
79
|
+
afterUpdate: true,
|
|
80
|
+
safe: true,
|
|
81
|
+
concurrency: s.options.concurrency,
|
|
82
|
+
registryTimeoutMs: s.options.registryTimeoutMs,
|
|
83
|
+
cacheTtlSeconds: s.options.cacheTtlSeconds,
|
|
84
|
+
silent: true,
|
|
85
|
+
};
|
|
86
|
+
const result = await runResolve(resolveOpts);
|
|
87
|
+
// Update updates array with the conflict severity
|
|
88
|
+
const updatedUpdates = s.updates.map((update) => {
|
|
89
|
+
const hasError = result.conflicts.some((c) => c.requester === update.name && c.severity === "error");
|
|
90
|
+
const hasWarning = result.conflicts.some((c) => c.requester === update.name && c.severity === "warning");
|
|
91
|
+
const severity = (hasError ? "error" : hasWarning ? "warning" : "none");
|
|
92
|
+
return { ...update, peerConflictSeverity: severity };
|
|
93
|
+
});
|
|
94
|
+
store.setState({ updates: updatedUpdates });
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
store.setState({ error: String(err) });
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
store.setState({ modal: "none" });
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
runAuditAction: async () => {
|
|
104
|
+
if (!store)
|
|
105
|
+
return;
|
|
106
|
+
const s = store.getState();
|
|
107
|
+
store.setState({ modal: "auditing" });
|
|
108
|
+
try {
|
|
109
|
+
const auditOpts = {
|
|
110
|
+
cwd: s.options.cwd,
|
|
111
|
+
workspace: s.options.workspace,
|
|
112
|
+
fix: false,
|
|
113
|
+
dryRun: false,
|
|
114
|
+
commit: false,
|
|
115
|
+
packageManager: "auto",
|
|
116
|
+
reportFormat: "summary",
|
|
117
|
+
sourceMode: "auto",
|
|
118
|
+
concurrency: s.options.concurrency,
|
|
119
|
+
registryTimeoutMs: s.options.registryTimeoutMs,
|
|
120
|
+
silent: true,
|
|
121
|
+
};
|
|
122
|
+
const result = await runAudit(auditOpts);
|
|
123
|
+
// Map advisories back to updates
|
|
124
|
+
const updatedUpdates = s.updates.map((update) => {
|
|
125
|
+
const pkgSummary = result.packages.find((p) => p.packageName === update.name);
|
|
126
|
+
if (pkgSummary) {
|
|
127
|
+
return {
|
|
128
|
+
...update,
|
|
129
|
+
riskLevel: pkgSummary.severity,
|
|
130
|
+
advisoryCount: pkgSummary.advisoryCount,
|
|
131
|
+
toRange: pkgSummary.patchedVersion || update.toRange, // suggest the patch!
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return update;
|
|
135
|
+
});
|
|
136
|
+
store.setState({ updates: updatedUpdates });
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
store.setState({ error: String(err) });
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
store.setState({ modal: "none" });
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
export function getStore() {
|
|
147
|
+
return store;
|
|
148
|
+
}
|
package/dist/ui/tui.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function runTui(
|
|
1
|
+
import type { ReviewItem } from "../types/index.js";
|
|
2
|
+
export declare function runTui(items: ReviewItem[]): Promise<ReviewItem[]>;
|