vargai 0.3.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/.claude/settings.local.json +7 -0
- package/.env.example +27 -0
- package/.github/workflows/ci.yml +23 -0
- package/.husky/README.md +102 -0
- package/.husky/commit-msg +6 -0
- package/.husky/pre-commit +9 -0
- package/.husky/pre-push +6 -0
- package/.size-limit.json +8 -0
- package/.test-hooks.ts +5 -0
- package/CLAUDE.md +125 -0
- package/CONTRIBUTING.md +150 -0
- package/LICENSE.md +53 -0
- package/README.md +78 -0
- package/SKILLS.md +173 -0
- package/STRUCTURE.md +92 -0
- package/biome.json +34 -0
- package/bun.lock +1254 -0
- package/commitlint.config.js +22 -0
- package/docs/plan.md +66 -0
- package/docs/todo.md +14 -0
- package/docs/varg-sdk.md +812 -0
- package/ffmpeg/CLAUDE.md +68 -0
- package/package.json +69 -0
- package/pipeline/cookbooks/SKILL.md +285 -0
- package/pipeline/cookbooks/remotion-video.md +585 -0
- package/pipeline/cookbooks/round-video-character.md +337 -0
- package/pipeline/cookbooks/scripts/animate-frames-parallel.ts +84 -0
- package/pipeline/cookbooks/scripts/combine-scenes.sh +53 -0
- package/pipeline/cookbooks/scripts/generate-frames-parallel.ts +99 -0
- package/pipeline/cookbooks/scripts/still-to-video.sh +37 -0
- package/pipeline/cookbooks/talking-character.md +59 -0
- package/pipeline/cookbooks/text-to-tiktok.md +669 -0
- package/pipeline/cookbooks/trendwatching.md +156 -0
- package/plan.md +281 -0
- package/scripts/.gitkeep +0 -0
- package/src/ai-sdk/cache.ts +142 -0
- package/src/ai-sdk/examples/cached-generation.ts +53 -0
- package/src/ai-sdk/examples/duet-scene-4.ts +53 -0
- package/src/ai-sdk/examples/duet-scene-5-audio.ts +32 -0
- package/src/ai-sdk/examples/duet-video.ts +56 -0
- package/src/ai-sdk/examples/editly-composition.ts +63 -0
- package/src/ai-sdk/examples/editly-test.ts +57 -0
- package/src/ai-sdk/examples/editly-video-test.ts +52 -0
- package/src/ai-sdk/examples/fal-lipsync.ts +43 -0
- package/src/ai-sdk/examples/higgsfield-image.ts +61 -0
- package/src/ai-sdk/examples/music-generation.ts +19 -0
- package/src/ai-sdk/examples/openai-sora.ts +34 -0
- package/src/ai-sdk/examples/replicate-bg-removal.ts +52 -0
- package/src/ai-sdk/examples/simpsons-scene.ts +61 -0
- package/src/ai-sdk/examples/talking-lion.ts +55 -0
- package/src/ai-sdk/examples/video-generation.ts +39 -0
- package/src/ai-sdk/examples/workflow-animated-girl.ts +104 -0
- package/src/ai-sdk/examples/workflow-before-after.ts +114 -0
- package/src/ai-sdk/examples/workflow-character-grid.ts +112 -0
- package/src/ai-sdk/examples/workflow-slideshow.ts +161 -0
- package/src/ai-sdk/file-cache.ts +112 -0
- package/src/ai-sdk/file.ts +238 -0
- package/src/ai-sdk/generate-element.ts +92 -0
- package/src/ai-sdk/generate-music.ts +46 -0
- package/src/ai-sdk/generate-video.ts +165 -0
- package/src/ai-sdk/index.ts +72 -0
- package/src/ai-sdk/music-model.ts +110 -0
- package/src/ai-sdk/providers/editly/editly.test.ts +1108 -0
- package/src/ai-sdk/providers/editly/ffmpeg.ts +60 -0
- package/src/ai-sdk/providers/editly/index.ts +817 -0
- package/src/ai-sdk/providers/editly/layers.ts +772 -0
- package/src/ai-sdk/providers/editly/plan.md +144 -0
- package/src/ai-sdk/providers/editly/types.ts +328 -0
- package/src/ai-sdk/providers/elevenlabs-provider.ts +255 -0
- package/src/ai-sdk/providers/fal-provider.ts +512 -0
- package/src/ai-sdk/providers/higgsfield.ts +379 -0
- package/src/ai-sdk/providers/openai.ts +251 -0
- package/src/ai-sdk/providers/replicate.ts +16 -0
- package/src/ai-sdk/video-model.ts +185 -0
- package/src/cli/commands/find.tsx +137 -0
- package/src/cli/commands/help.tsx +85 -0
- package/src/cli/commands/index.ts +9 -0
- package/src/cli/commands/list.tsx +238 -0
- package/src/cli/commands/run.tsx +511 -0
- package/src/cli/commands/which.tsx +253 -0
- package/src/cli/index.ts +112 -0
- package/src/cli/quiet.ts +44 -0
- package/src/cli/types.ts +32 -0
- package/src/cli/ui/components/Badge.tsx +29 -0
- package/src/cli/ui/components/DataTable.tsx +51 -0
- package/src/cli/ui/components/Header.tsx +23 -0
- package/src/cli/ui/components/HelpBlock.tsx +44 -0
- package/src/cli/ui/components/KeyValue.tsx +33 -0
- package/src/cli/ui/components/OptionRow.tsx +81 -0
- package/src/cli/ui/components/Separator.tsx +23 -0
- package/src/cli/ui/components/StatusBox.tsx +108 -0
- package/src/cli/ui/components/VargBox.tsx +51 -0
- package/src/cli/ui/components/VargProgress.tsx +36 -0
- package/src/cli/ui/components/VargSpinner.tsx +34 -0
- package/src/cli/ui/components/VargText.tsx +56 -0
- package/src/cli/ui/components/index.ts +19 -0
- package/src/cli/ui/index.ts +12 -0
- package/src/cli/ui/render.ts +35 -0
- package/src/cli/ui/theme.ts +63 -0
- package/src/cli/utils.ts +78 -0
- package/src/core/executor/executor.ts +201 -0
- package/src/core/executor/index.ts +13 -0
- package/src/core/executor/job.ts +214 -0
- package/src/core/executor/pipeline.ts +222 -0
- package/src/core/index.ts +11 -0
- package/src/core/registry/index.ts +9 -0
- package/src/core/registry/loader.ts +149 -0
- package/src/core/registry/registry.ts +221 -0
- package/src/core/registry/resolver.ts +206 -0
- package/src/core/schema/helpers.ts +134 -0
- package/src/core/schema/index.ts +8 -0
- package/src/core/schema/shared.ts +102 -0
- package/src/core/schema/types.ts +279 -0
- package/src/core/schema/validator.ts +92 -0
- package/src/definitions/actions/captions.ts +261 -0
- package/src/definitions/actions/edit.ts +298 -0
- package/src/definitions/actions/image.ts +125 -0
- package/src/definitions/actions/index.ts +114 -0
- package/src/definitions/actions/music.ts +205 -0
- package/src/definitions/actions/sync.ts +128 -0
- package/src/definitions/actions/transcribe.ts +200 -0
- package/src/definitions/actions/upload.ts +111 -0
- package/src/definitions/actions/video.ts +163 -0
- package/src/definitions/actions/voice.ts +119 -0
- package/src/definitions/index.ts +23 -0
- package/src/definitions/models/elevenlabs.ts +50 -0
- package/src/definitions/models/flux.ts +56 -0
- package/src/definitions/models/index.ts +36 -0
- package/src/definitions/models/kling.ts +56 -0
- package/src/definitions/models/llama.ts +54 -0
- package/src/definitions/models/nano-banana-pro.ts +102 -0
- package/src/definitions/models/sonauto.ts +68 -0
- package/src/definitions/models/soul.ts +65 -0
- package/src/definitions/models/wan.ts +54 -0
- package/src/definitions/models/whisper.ts +44 -0
- package/src/definitions/skills/index.ts +12 -0
- package/src/definitions/skills/talking-character.ts +87 -0
- package/src/definitions/skills/text-to-tiktok.ts +97 -0
- package/src/index.ts +118 -0
- package/src/providers/apify.ts +269 -0
- package/src/providers/base.ts +264 -0
- package/src/providers/elevenlabs.ts +217 -0
- package/src/providers/fal.ts +392 -0
- package/src/providers/ffmpeg.ts +544 -0
- package/src/providers/fireworks.ts +193 -0
- package/src/providers/groq.ts +149 -0
- package/src/providers/higgsfield.ts +145 -0
- package/src/providers/index.ts +143 -0
- package/src/providers/replicate.ts +147 -0
- package/src/providers/storage.ts +206 -0
- package/src/tests/all.test.ts +509 -0
- package/src/tests/index.ts +33 -0
- package/src/tests/unit.test.ts +403 -0
- package/tsconfig.json +45 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Separator - Horizontal divider line
|
|
3
|
+
* Minimal visual separator between sections
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Box, Text } from "ink";
|
|
7
|
+
import { theme } from "../theme.ts";
|
|
8
|
+
|
|
9
|
+
interface SeparatorProps {
|
|
10
|
+
width?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function Separator({
|
|
14
|
+
width = theme.layout.maxWidth - 4,
|
|
15
|
+
}: SeparatorProps) {
|
|
16
|
+
return (
|
|
17
|
+
<Box>
|
|
18
|
+
<Text dimColor>{"─".repeat(width)}</Text>
|
|
19
|
+
</Box>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default Separator;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StatusBox - Execution status display
|
|
3
|
+
* Shows running/done/error state with params and results
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Box, Text } from "ink";
|
|
7
|
+
import { icons, theme } from "../theme.ts";
|
|
8
|
+
import KeyValue from "./KeyValue.tsx";
|
|
9
|
+
import VargBox from "./VargBox.tsx";
|
|
10
|
+
import { VargProgress } from "./VargProgress.tsx";
|
|
11
|
+
import VargSpinner from "./VargSpinner.tsx";
|
|
12
|
+
import { VargText } from "./VargText.tsx";
|
|
13
|
+
|
|
14
|
+
type Status = "running" | "done" | "error";
|
|
15
|
+
|
|
16
|
+
interface StatusBoxProps {
|
|
17
|
+
title: string;
|
|
18
|
+
status: Status;
|
|
19
|
+
params?: Record<string, string>;
|
|
20
|
+
output?: string;
|
|
21
|
+
error?: string;
|
|
22
|
+
duration?: number;
|
|
23
|
+
progress?: number; // 0-100, shows progress bar when provided
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const statusConfig: Record<
|
|
27
|
+
Status,
|
|
28
|
+
{ icon: string; color: string; label: string }
|
|
29
|
+
> = {
|
|
30
|
+
running: {
|
|
31
|
+
icon: icons.running,
|
|
32
|
+
color: theme.colors.accent,
|
|
33
|
+
label: "running",
|
|
34
|
+
},
|
|
35
|
+
done: { icon: icons.success, color: theme.colors.success, label: "done" },
|
|
36
|
+
error: { icon: icons.error, color: theme.colors.error, label: "error" },
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function formatDuration(ms: number): string {
|
|
40
|
+
if (ms >= 1000) {
|
|
41
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
42
|
+
}
|
|
43
|
+
return `${ms}ms`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function StatusBox({
|
|
47
|
+
title,
|
|
48
|
+
status,
|
|
49
|
+
params,
|
|
50
|
+
output,
|
|
51
|
+
error,
|
|
52
|
+
duration,
|
|
53
|
+
progress,
|
|
54
|
+
}: StatusBoxProps) {
|
|
55
|
+
const config = statusConfig[status];
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<VargBox title={title} variant="bordered">
|
|
59
|
+
{/* Status indicator */}
|
|
60
|
+
<Box marginY={1}>
|
|
61
|
+
{status === "running" ? (
|
|
62
|
+
<VargSpinner label={config.label} />
|
|
63
|
+
) : (
|
|
64
|
+
<Text color={config.color}>
|
|
65
|
+
{config.icon} {config.label}
|
|
66
|
+
</Text>
|
|
67
|
+
)}
|
|
68
|
+
</Box>
|
|
69
|
+
|
|
70
|
+
{/* Progress bar (when provided) */}
|
|
71
|
+
{progress !== undefined && status === "running" && (
|
|
72
|
+
<Box marginBottom={1}>
|
|
73
|
+
<VargProgress value={progress} label="processing" />
|
|
74
|
+
</Box>
|
|
75
|
+
)}
|
|
76
|
+
|
|
77
|
+
{/* Parameters */}
|
|
78
|
+
{params && Object.keys(params).length > 0 && (
|
|
79
|
+
<Box flexDirection="column" marginBottom={1}>
|
|
80
|
+
{Object.entries(params).map(([key, value]) => (
|
|
81
|
+
<KeyValue key={key} label={key} value={value} />
|
|
82
|
+
))}
|
|
83
|
+
</Box>
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
{/* Output */}
|
|
87
|
+
{output && (
|
|
88
|
+
<Box marginTop={1}>
|
|
89
|
+
<KeyValue label="output" value={output} />
|
|
90
|
+
</Box>
|
|
91
|
+
)}
|
|
92
|
+
|
|
93
|
+
{/* Error */}
|
|
94
|
+
{error && (
|
|
95
|
+
<Box marginTop={1}>
|
|
96
|
+
<VargText variant="error">error: {error}</VargText>
|
|
97
|
+
</Box>
|
|
98
|
+
)}
|
|
99
|
+
|
|
100
|
+
{/* Duration */}
|
|
101
|
+
{duration !== undefined && (
|
|
102
|
+
<KeyValue label="time" value={formatDuration(duration)} />
|
|
103
|
+
)}
|
|
104
|
+
</VargBox>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export default StatusBox;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VargBox - Container component
|
|
3
|
+
* Luxury minimal styled box with optional title and borders
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Box, Text } from "ink";
|
|
7
|
+
import type { ReactNode } from "react";
|
|
8
|
+
import { theme } from "../theme.ts";
|
|
9
|
+
|
|
10
|
+
type BorderStyle = "single" | "double" | "round" | "bold" | "classic";
|
|
11
|
+
|
|
12
|
+
interface VargBoxProps {
|
|
13
|
+
title?: string;
|
|
14
|
+
subtitle?: string;
|
|
15
|
+
variant?: "default" | "minimal" | "bordered";
|
|
16
|
+
width?: number;
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function VargBox({
|
|
21
|
+
title,
|
|
22
|
+
subtitle,
|
|
23
|
+
variant = "default",
|
|
24
|
+
width = theme.layout.maxWidth,
|
|
25
|
+
children,
|
|
26
|
+
}: VargBoxProps) {
|
|
27
|
+
const showBorder = variant === "bordered" || (variant === "default" && title);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Box
|
|
31
|
+
flexDirection="column"
|
|
32
|
+
width={width}
|
|
33
|
+
borderStyle={
|
|
34
|
+
showBorder ? (theme.borders.style as BorderStyle) : undefined
|
|
35
|
+
}
|
|
36
|
+
borderColor={theme.colors.border}
|
|
37
|
+
paddingX={theme.layout.boxPadding}
|
|
38
|
+
paddingY={variant === "minimal" ? 0 : 1}
|
|
39
|
+
>
|
|
40
|
+
{title && (
|
|
41
|
+
<Box marginBottom={1}>
|
|
42
|
+
<Text bold>{title}</Text>
|
|
43
|
+
{subtitle && <Text dimColor> {subtitle}</Text>}
|
|
44
|
+
</Box>
|
|
45
|
+
)}
|
|
46
|
+
{children}
|
|
47
|
+
</Box>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default VargBox;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VargProgress - Progress bar component
|
|
3
|
+
* Elegant thin progress visualization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Text } from "ink";
|
|
7
|
+
import { theme } from "../theme.ts";
|
|
8
|
+
|
|
9
|
+
interface VargProgressProps {
|
|
10
|
+
value: number; // 0-100
|
|
11
|
+
width?: number;
|
|
12
|
+
showPercentage?: boolean;
|
|
13
|
+
label?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function VargProgress({
|
|
17
|
+
value,
|
|
18
|
+
width = 24,
|
|
19
|
+
showPercentage = true,
|
|
20
|
+
label,
|
|
21
|
+
}: VargProgressProps) {
|
|
22
|
+
const clampedValue = Math.max(0, Math.min(100, value));
|
|
23
|
+
const filled = Math.round((clampedValue / 100) * width);
|
|
24
|
+
const empty = width - filled;
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Text>
|
|
28
|
+
<Text color={theme.colors.accent}>{"█".repeat(filled)}</Text>
|
|
29
|
+
<Text dimColor>{"░".repeat(empty)}</Text>
|
|
30
|
+
{showPercentage && <Text dimColor> {clampedValue}%</Text>}
|
|
31
|
+
{label && <Text dimColor> {label}</Text>}
|
|
32
|
+
</Text>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default VargProgress;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VargSpinner - Animated loading indicator
|
|
3
|
+
* Elegant braille spinner with label
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Text } from "ink";
|
|
7
|
+
import { useEffect, useState } from "react";
|
|
8
|
+
import { theme } from "../theme.ts";
|
|
9
|
+
|
|
10
|
+
interface VargSpinnerProps {
|
|
11
|
+
label?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function VargSpinner({ label }: VargSpinnerProps) {
|
|
15
|
+
const [frame, setFrame] = useState(0);
|
|
16
|
+
const frames = theme.animation.spinnerFrames;
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const timer = setInterval(() => {
|
|
20
|
+
setFrame((f) => (f + 1) % frames.length);
|
|
21
|
+
}, theme.animation.spinnerInterval);
|
|
22
|
+
|
|
23
|
+
return () => clearInterval(timer);
|
|
24
|
+
}, [frames.length]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Text>
|
|
28
|
+
<Text color={theme.colors.accent}>{frames[frame]}</Text>
|
|
29
|
+
{label && <Text> {label}</Text>}
|
|
30
|
+
</Text>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default VargSpinner;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VargText - Typography component
|
|
3
|
+
* Provides semantic text variants for consistent styling
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Text } from "ink";
|
|
7
|
+
import type { ReactNode } from "react";
|
|
8
|
+
import { theme } from "../theme.ts";
|
|
9
|
+
|
|
10
|
+
export type TextVariant =
|
|
11
|
+
| "body"
|
|
12
|
+
| "label"
|
|
13
|
+
| "code"
|
|
14
|
+
| "muted"
|
|
15
|
+
| "accent"
|
|
16
|
+
| "success"
|
|
17
|
+
| "error"
|
|
18
|
+
| "warning";
|
|
19
|
+
|
|
20
|
+
interface VargTextProps {
|
|
21
|
+
variant?: TextVariant;
|
|
22
|
+
bold?: boolean;
|
|
23
|
+
dimColor?: boolean;
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const variantStyles: Record<
|
|
28
|
+
TextVariant,
|
|
29
|
+
{ color?: string; dimColor?: boolean }
|
|
30
|
+
> = {
|
|
31
|
+
body: {},
|
|
32
|
+
label: { dimColor: true },
|
|
33
|
+
code: { color: theme.colors.accent },
|
|
34
|
+
muted: { dimColor: true },
|
|
35
|
+
accent: { color: theme.colors.accent },
|
|
36
|
+
success: { color: theme.colors.success },
|
|
37
|
+
error: { color: theme.colors.error },
|
|
38
|
+
warning: { color: theme.colors.warning },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function VargText({
|
|
42
|
+
variant = "body",
|
|
43
|
+
bold,
|
|
44
|
+
dimColor,
|
|
45
|
+
children,
|
|
46
|
+
}: VargTextProps) {
|
|
47
|
+
const style = variantStyles[variant];
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Text color={style.color} dimColor={dimColor ?? style.dimColor} bold={bold}>
|
|
51
|
+
{children}
|
|
52
|
+
</Text>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default VargText;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Varg UI Components
|
|
3
|
+
* Re-exports all UI components for the CLI
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { Badge } from "./Badge.tsx";
|
|
7
|
+
export { DataTable } from "./DataTable.tsx";
|
|
8
|
+
export { Header } from "./Header.tsx";
|
|
9
|
+
export { HelpBlock } from "./HelpBlock.tsx";
|
|
10
|
+
export { KeyValue } from "./KeyValue.tsx";
|
|
11
|
+
export { OptionRow } from "./OptionRow.tsx";
|
|
12
|
+
export { Separator } from "./Separator.tsx";
|
|
13
|
+
export { StatusBox } from "./StatusBox.tsx";
|
|
14
|
+
export { VargBox } from "./VargBox.tsx";
|
|
15
|
+
export { VargProgress } from "./VargProgress.tsx";
|
|
16
|
+
export { VargSpinner } from "./VargSpinner.tsx";
|
|
17
|
+
// Re-export types
|
|
18
|
+
export type { TextVariant } from "./VargText.tsx";
|
|
19
|
+
export { VargText } from "./VargText.tsx";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Varg CLI UI Module
|
|
3
|
+
* Ink-based React components for the CLI
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Components
|
|
7
|
+
export * from "./components/index.ts";
|
|
8
|
+
// Render helpers
|
|
9
|
+
export { renderAndWait, renderLive, renderStatic } from "./render.ts";
|
|
10
|
+
export type { ThemeColors } from "./theme.ts";
|
|
11
|
+
// Theme and tokens
|
|
12
|
+
export { icons, theme } from "./theme.ts";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Citty ↔ Ink Bridge
|
|
3
|
+
* Helpers to render Ink components from citty commands
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { render } from "ink";
|
|
7
|
+
import type { ReactElement } from "react";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Render a static component that auto-exits after mounting
|
|
11
|
+
* Use for: list, help, which, find commands
|
|
12
|
+
*/
|
|
13
|
+
export function renderStatic(element: ReactElement): void {
|
|
14
|
+
const { unmount } = render(element);
|
|
15
|
+
// Give React time to render, then unmount
|
|
16
|
+
setTimeout(() => unmount(), 50);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Render a component with live updates
|
|
21
|
+
* Use for: run command with spinner/progress
|
|
22
|
+
* Returns control handle for manual rerender and unmount
|
|
23
|
+
*/
|
|
24
|
+
export function renderLive(element: ReactElement) {
|
|
25
|
+
return render(element);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Render and wait for component to signal exit
|
|
30
|
+
* Use for: interactive components (future)
|
|
31
|
+
*/
|
|
32
|
+
export async function renderAndWait(element: ReactElement): Promise<void> {
|
|
33
|
+
const { waitUntilExit } = render(element);
|
|
34
|
+
await waitUntilExit();
|
|
35
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design System for Varg CLI
|
|
3
|
+
* Luxury Minimal aesthetic - Vercel/Linear inspired
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const theme = {
|
|
7
|
+
colors: {
|
|
8
|
+
// Primary accent - single color for emphasis
|
|
9
|
+
accent: "cyan",
|
|
10
|
+
|
|
11
|
+
// Semantic colors
|
|
12
|
+
success: "green",
|
|
13
|
+
error: "red",
|
|
14
|
+
warning: "yellow",
|
|
15
|
+
|
|
16
|
+
// Neutrals (Ink uses color names, not hex)
|
|
17
|
+
text: {
|
|
18
|
+
primary: "white",
|
|
19
|
+
secondary: "gray",
|
|
20
|
+
muted: "gray",
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// Borders
|
|
24
|
+
border: "gray",
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
spacing: {
|
|
28
|
+
xs: 1,
|
|
29
|
+
sm: 2,
|
|
30
|
+
md: 3,
|
|
31
|
+
lg: 4,
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
borders: {
|
|
35
|
+
style: "round" as const, // Rounded corners: ╭╮╰╯
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
animation: {
|
|
39
|
+
// Elegant braille spinner
|
|
40
|
+
spinnerFrames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
|
|
41
|
+
spinnerInterval: 80,
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
layout: {
|
|
45
|
+
maxWidth: 100,
|
|
46
|
+
boxPadding: 2,
|
|
47
|
+
optionNameWidth: 22,
|
|
48
|
+
},
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
51
|
+
// Status icons - refined geometric shapes
|
|
52
|
+
export const icons = {
|
|
53
|
+
running: "●",
|
|
54
|
+
success: "✓",
|
|
55
|
+
error: "✗",
|
|
56
|
+
warning: "!",
|
|
57
|
+
info: "○",
|
|
58
|
+
arrow: "→",
|
|
59
|
+
bullet: "·",
|
|
60
|
+
required: "*",
|
|
61
|
+
} as const;
|
|
62
|
+
|
|
63
|
+
export type ThemeColors = keyof typeof theme.colors;
|
package/src/cli/utils.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import type { Definition } from "../core/schema/types";
|
|
7
|
+
import type { JsonSchema, NotFoundOptions } from "./types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Handle "not found" errors consistently
|
|
11
|
+
*/
|
|
12
|
+
export function handleNotFound(
|
|
13
|
+
name: string,
|
|
14
|
+
options: NotFoundOptions = {},
|
|
15
|
+
): never | undefined {
|
|
16
|
+
const {
|
|
17
|
+
suggestions = [],
|
|
18
|
+
maxSuggestions = 3,
|
|
19
|
+
hint = "run `varg list` to see available items",
|
|
20
|
+
errorColorFn = (s) => s,
|
|
21
|
+
hintColorFn = (s) => s,
|
|
22
|
+
exit = true,
|
|
23
|
+
} = options;
|
|
24
|
+
|
|
25
|
+
console.error(`\n ${errorColorFn("not found:")} '${name}'\n`);
|
|
26
|
+
|
|
27
|
+
if (suggestions.length > 0) {
|
|
28
|
+
const shown = suggestions.slice(0, maxSuggestions).join(", ");
|
|
29
|
+
console.log(` did you mean: ${shown}?\n`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (hint) {
|
|
33
|
+
console.log(` ${hintColorFn(hint)}\n`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (exit) {
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Convert a definition to a table row object
|
|
43
|
+
*/
|
|
44
|
+
export const definitionToRow = (d: Definition) => ({
|
|
45
|
+
name: d.name,
|
|
46
|
+
description: d.description,
|
|
47
|
+
type: d.type,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Convert an array of definitions to table rows
|
|
52
|
+
*/
|
|
53
|
+
export const definitionsToRows = (defs: Definition[]) =>
|
|
54
|
+
defs.map(definitionToRow);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get JSON Schema for display - converts Zod schema to JSON Schema
|
|
58
|
+
*/
|
|
59
|
+
export function getDisplaySchema(item: Definition): {
|
|
60
|
+
input: JsonSchema;
|
|
61
|
+
output: JsonSchema;
|
|
62
|
+
} {
|
|
63
|
+
if (!item.schema) {
|
|
64
|
+
return {
|
|
65
|
+
input: { type: "object", properties: {}, required: [] },
|
|
66
|
+
output: { type: "object" },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const input = z.toJSONSchema(item.schema.input, {
|
|
71
|
+
io: "input",
|
|
72
|
+
}) as JsonSchema;
|
|
73
|
+
const output = item.schema.output
|
|
74
|
+
? (z.toJSONSchema(item.schema.output, { io: "output" }) as JsonSchema)
|
|
75
|
+
: { type: "object" };
|
|
76
|
+
|
|
77
|
+
return { input, output };
|
|
78
|
+
}
|