@bytevion/cli 0.4.0 → 0.5.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 (43) hide show
  1. package/bin/postinstall.js +58 -0
  2. package/dist/commands/connect.d.ts +12 -0
  3. package/dist/commands/connect.js +64 -0
  4. package/dist/commands/dash.d.ts +9 -0
  5. package/dist/commands/dash.js +120 -0
  6. package/dist/commands/integrate.d.ts +3 -0
  7. package/dist/commands/integrate.js +58 -6
  8. package/dist/commands/keys/rotate.d.ts +3 -0
  9. package/dist/commands/keys/rotate.js +9 -1
  10. package/dist/commands/mcp/add.d.ts +13 -0
  11. package/dist/commands/mcp/add.js +31 -0
  12. package/dist/commands/mcp/list.d.ts +5 -0
  13. package/dist/commands/mcp/list.js +22 -0
  14. package/dist/commands/mcp/remove.d.ts +11 -0
  15. package/dist/commands/mcp/remove.js +19 -0
  16. package/dist/commands/mcp/test.d.ts +11 -0
  17. package/dist/commands/mcp/test.js +20 -0
  18. package/dist/commands/providers/compare.d.ts +13 -0
  19. package/dist/commands/providers/compare.js +52 -0
  20. package/dist/commands/sync.d.ts +10 -0
  21. package/dist/commands/sync.js +39 -0
  22. package/dist/lib/api.d.ts +7 -0
  23. package/dist/lib/api.js +24 -0
  24. package/dist/lib/config-formats.d.ts +3 -0
  25. package/dist/lib/config-formats.js +88 -0
  26. package/dist/lib/detect.d.ts +9 -0
  27. package/dist/lib/detect.js +83 -0
  28. package/dist/lib/friendly.js +10 -0
  29. package/dist/lib/integrations.d.ts +1 -0
  30. package/dist/lib/integrations.js +33 -4
  31. package/dist/lib/paths.d.ts +2 -0
  32. package/dist/lib/paths.js +13 -0
  33. package/dist/lib/tui.d.ts +42 -0
  34. package/dist/lib/tui.js +10 -0
  35. package/dist/lib/wiring.d.ts +10 -0
  36. package/dist/lib/wiring.js +53 -0
  37. package/dist/tui/components/Dash.d.ts +16 -0
  38. package/dist/tui/components/Dash.js +53 -0
  39. package/dist/tui/contract.d.ts +42 -0
  40. package/dist/tui/index.d.ts +2 -1
  41. package/dist/tui/index.js +34 -0
  42. package/oclif.manifest.json +617 -128
  43. package/package.json +7 -2
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text, useApp, useInput } from 'ink';
3
+ import React from 'react';
4
+ import { glyphs, gradient, tones } from '../theme.js';
5
+ import { Panel } from './Panel.js';
6
+ function Spark({ series, ascii, plainColor }) {
7
+ const ramp = glyphs(ascii).spark;
8
+ const values = series.length ? series : [0];
9
+ const max = Math.max(...values, 1);
10
+ const cols = gradient(values.length);
11
+ return (_jsx(Box, { children: values.map((value, i) => {
12
+ const idx = Math.min(ramp.length - 1, Math.max(0, Math.round((value / max) * (ramp.length - 1))));
13
+ return (_jsx(Text, { color: plainColor ? undefined : cols[i], children: ramp[idx] }, i));
14
+ }) }));
15
+ }
16
+ // Dense live monitor: a brand/health header, a one-line metric strip with a savings sparkline,
17
+ // a Recent-requests panel beside an Optimizations panel, and a key-hint footer. Polls the
18
+ // injected refresh port every few seconds; q / Esc / Ctrl-C exits cleanly.
19
+ export function Dash({ data: initial, ports, ascii, plainColor, version, onDone }) {
20
+ const { exit } = useApp();
21
+ const [data, setData] = React.useState(initial);
22
+ const [tick, setTick] = React.useState(0);
23
+ const t = tones(plainColor);
24
+ const g = glyphs(ascii);
25
+ React.useEffect(() => {
26
+ let alive = true;
27
+ const timer = setInterval(() => {
28
+ ports
29
+ .refresh()
30
+ .then((next) => {
31
+ if (alive) {
32
+ setData(next);
33
+ setTick((n) => n + 1);
34
+ }
35
+ })
36
+ .catch(() => undefined);
37
+ }, 2500);
38
+ return () => {
39
+ alive = false;
40
+ clearInterval(timer);
41
+ };
42
+ }, [ports]);
43
+ useInput((input, key) => {
44
+ if (input === 'q' || key.escape || (key.ctrl && input === 'c')) {
45
+ onDone({ status: 'exit' });
46
+ exit();
47
+ }
48
+ });
49
+ const dot = data.gateway === 'healthy' ? t.ok : data.gateway === 'down' ? t.bad : t.muted;
50
+ const recent = data.recent.slice(0, 8);
51
+ const activeCount = data.layers.filter((l) => l.active).length;
52
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: t.brandMid, bold: true, children: [g.brand.join(''), " byte dash "] }), _jsxs(Text, { color: t.muted, children: ["v", version, " "] }), _jsxs(Text, { color: dot, children: [g.filled, " ", data.gateway] }), _jsxs(Text, { color: t.muted, children: [" ", data.email ?? '', data.org ? ` (${data.org})` : ''] })] }), _jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: t.muted, children: "mode " }), _jsx(Text, { color: t.accent, children: data.mode ?? 'maximum' }), _jsx(Text, { color: t.muted, children: " saved " }), _jsxs(Text, { color: t.ok, children: ["$", data.savedTotal.toFixed(4)] }), _jsx(Text, { color: t.muted, children: " req " }), _jsx(Text, { children: data.requests }), _jsx(Text, { color: t.muted, children: " cache " }), _jsxs(Text, { color: t.accent, children: [Math.round(data.cacheHitRate * 100), "%"] }), _jsx(Text, { color: t.muted, children: " tok " }), _jsx(Text, { children: data.tokensTotal }), _jsx(Text, { color: t.muted, children: " " }), _jsx(Spark, { series: data.savingsSeries, ascii: ascii, plainColor: plainColor })] }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { width: "56%", marginRight: 1, children: _jsx(Panel, { title: "Recent requests", ascii: ascii, plainColor: plainColor, children: recent.length === 0 ? (_jsx(Text, { color: t.muted, children: "no requests yet" })) : (recent.map((r, i) => (_jsxs(Box, { children: [_jsxs(Text, { color: r.status === 'ok' ? t.ok : t.bad, children: [g.bullet, " "] }), _jsx(Text, { children: r.model.padEnd(22).slice(0, 22) }), _jsxs(Text, { color: t.muted, children: [" ", String(r.latencyMs).padStart(5), "ms "] }), _jsxs(Text, { color: t.muted, children: [String(r.tokens).padStart(6), "tok "] }), _jsx(Text, { color: t.accent, children: r.cache ?? '' })] }, i)))) }) }), _jsx(Box, { width: "42%", children: _jsx(Panel, { title: `Optimizations ${activeCount}/${data.layers.length}`, tone: "ok", ascii: ascii, plainColor: plainColor, children: data.layers.slice(0, 12).map((l, i) => (_jsxs(Box, { children: [_jsxs(Text, { color: l.active ? t.ok : t.muted, children: [l.active ? g.filled : g.empty, " "] }), _jsx(Text, { color: l.active ? undefined : t.muted, children: l.label })] }, i))) }) })] }), _jsxs(Box, { marginTop: 1, children: [_jsxs(Text, { color: t.muted, children: ["providers ", data.providers, " \u00B7 models ", data.models, " \u00B7 refresh #", tick, " "] }), _jsx(Text, { color: t.accent, children: "q" }), _jsx(Text, { color: t.muted, children: " quit" })] })] }));
53
+ }
@@ -97,3 +97,45 @@ export type WizardResult = {
97
97
  status: 'done';
98
98
  summary: WizardSummary;
99
99
  };
100
+ export interface DashRequest {
101
+ model: string;
102
+ status: string;
103
+ latencyMs: number;
104
+ tokens: number;
105
+ cache?: string;
106
+ }
107
+ export interface DashLayer {
108
+ label: string;
109
+ active: boolean;
110
+ }
111
+ export interface DashData {
112
+ email?: string;
113
+ org?: string;
114
+ gateway: 'healthy' | 'down' | 'unknown';
115
+ mode?: string;
116
+ requests: number;
117
+ cacheHitRate: number;
118
+ savedTotal: number;
119
+ tokensTotal: number;
120
+ costTotal: number;
121
+ savingsSeries: number[];
122
+ providers: number;
123
+ models: number;
124
+ recent: DashRequest[];
125
+ layers: DashLayer[];
126
+ }
127
+ export interface DashPorts {
128
+ refresh(): Promise<DashData>;
129
+ }
130
+ export interface DashIslandProps {
131
+ data: DashData;
132
+ ports: DashPorts;
133
+ plainColor: boolean;
134
+ ascii: boolean;
135
+ version: string;
136
+ }
137
+ export type DashResult = {
138
+ status: 'fallback';
139
+ } | {
140
+ status: 'exit';
141
+ };
@@ -1,3 +1,4 @@
1
- import type { HomeIslandProps, HomeResult, WizardIslandProps, WizardResult } from './contract.js';
1
+ import type { DashIslandProps, DashResult, HomeIslandProps, HomeResult, WizardIslandProps, WizardResult } from './contract.js';
2
2
  export declare function renderHome(props: HomeIslandProps): Promise<HomeResult>;
3
3
  export declare function renderWizard(props: WizardIslandProps): Promise<WizardResult>;
4
+ export declare function renderDash(props: DashIslandProps): Promise<DashResult>;
package/dist/tui/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { render } from 'ink';
2
2
  import React from 'react';
3
3
  import { App } from './components/App.js';
4
+ import { Dash } from './components/Dash.js';
4
5
  import { Home } from './components/Home.js';
5
6
  // ESM island entry. The CJS bridge (src/lib/tui.ts) dynamic-imports this and calls renderHome /
6
7
  // renderWizard. Each mounts an Ink root, resolves the result Promise when the component reports
@@ -76,3 +77,36 @@ export async function renderWizard(props) {
76
77
  }
77
78
  }
78
79
  }
80
+ export async function renderDash(props) {
81
+ let settled = false;
82
+ let resolve;
83
+ const done = new Promise((res) => {
84
+ resolve = (r) => {
85
+ if (!settled) {
86
+ settled = true;
87
+ res(r);
88
+ }
89
+ };
90
+ });
91
+ const instance = render(React.createElement(Dash, {
92
+ data: props.data,
93
+ ports: props.ports,
94
+ ascii: props.ascii,
95
+ plainColor: props.plainColor,
96
+ version: props.version,
97
+ onDone: resolve,
98
+ }), { exitOnCtrlC: false });
99
+ try {
100
+ instance.waitUntilExit().then(() => resolve({ status: 'exit' }), () => resolve({ status: 'fallback' }));
101
+ return await done;
102
+ }
103
+ finally {
104
+ instance.unmount();
105
+ try {
106
+ process.stdout.write(SHOW_CURSOR);
107
+ }
108
+ catch {
109
+ /* stream may be closed */
110
+ }
111
+ }
112
+ }