ai-cli 0.1.1 → 0.2.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/README.md +29 -2
- package/package.json +1 -1
- package/src/cli.test.ts +1 -26
- package/src/commands/image.ts +58 -5
- package/src/commands/models.ts +36 -47
- package/src/commands/text.ts +3 -2
- package/src/commands/video.ts +3 -2
- package/src/index.ts +0 -2
- package/src/lib/models.test.ts +236 -126
- package/src/lib/models.ts +128 -118
- package/src/commands/completions.ts +0 -296
package/src/lib/models.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { gateway } from "ai";
|
|
2
|
-
|
|
3
1
|
export type Modality = "text" | "image" | "video";
|
|
4
2
|
|
|
5
3
|
const DEFAULTS: Record<Modality, string> = {
|
|
@@ -8,156 +6,168 @@ const DEFAULTS: Record<Modality, string> = {
|
|
|
8
6
|
video: process.env.AI_CLI_VIDEO_MODEL ?? "bytedance/seedance-2.0",
|
|
9
7
|
};
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"openai/o3",
|
|
20
|
-
"openai/o4-mini",
|
|
21
|
-
"xai/grok-3",
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
export const FALLBACK_IMAGE_MODELS = [
|
|
25
|
-
"bfl/flux-2-flex",
|
|
26
|
-
"bfl/flux-2-klein-4b",
|
|
27
|
-
"bfl/flux-2-klein-9b",
|
|
28
|
-
"bfl/flux-2-max",
|
|
29
|
-
"bfl/flux-2-pro",
|
|
30
|
-
"bfl/flux-kontext-max",
|
|
31
|
-
"bfl/flux-kontext-pro",
|
|
32
|
-
"bfl/flux-pro-1.0-fill",
|
|
33
|
-
"bfl/flux-pro-1.1",
|
|
34
|
-
"bfl/flux-pro-1.1-ultra",
|
|
35
|
-
"bytedance/seedream-4.0",
|
|
36
|
-
"bytedance/seedream-4.5",
|
|
37
|
-
"bytedance/seedream-5.0-lite",
|
|
38
|
-
"google/imagen-4.0-fast-generate-001",
|
|
39
|
-
"google/imagen-4.0-generate-001",
|
|
40
|
-
"google/imagen-4.0-ultra-generate-001",
|
|
41
|
-
"openai/gpt-image-1",
|
|
42
|
-
"openai/gpt-image-1-mini",
|
|
43
|
-
"openai/gpt-image-1.5",
|
|
44
|
-
"openai/gpt-image-2",
|
|
45
|
-
"prodia/flux-fast-schnell",
|
|
46
|
-
"recraft/recraft-v2",
|
|
47
|
-
"recraft/recraft-v3",
|
|
48
|
-
"recraft/recraft-v4",
|
|
49
|
-
"recraft/recraft-v4-pro",
|
|
50
|
-
"xai/grok-imagine-image",
|
|
51
|
-
"xai/grok-imagine-image-pro",
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
export const FALLBACK_VIDEO_MODELS = [
|
|
55
|
-
"alibaba/wan-v2.5-t2v-preview",
|
|
56
|
-
"alibaba/wan-v2.6-i2v",
|
|
57
|
-
"alibaba/wan-v2.6-i2v-flash",
|
|
58
|
-
"alibaba/wan-v2.6-r2v",
|
|
59
|
-
"alibaba/wan-v2.6-r2v-flash",
|
|
60
|
-
"alibaba/wan-v2.6-t2v",
|
|
61
|
-
"bytedance/seedance-2.0",
|
|
62
|
-
"bytedance/seedance-2.0-fast",
|
|
63
|
-
"bytedance/seedance-v1.0-lite-i2v",
|
|
64
|
-
"bytedance/seedance-v1.0-lite-t2v",
|
|
65
|
-
"bytedance/seedance-v1.0-pro",
|
|
66
|
-
"bytedance/seedance-v1.0-pro-fast",
|
|
67
|
-
"bytedance/seedance-v1.5-pro",
|
|
68
|
-
"google/veo-3.0-fast-generate-001",
|
|
69
|
-
"google/veo-3.0-generate-001",
|
|
70
|
-
"google/veo-3.1-fast-generate-001",
|
|
71
|
-
"google/veo-3.1-generate-001",
|
|
72
|
-
"klingai/kling-v2.5-turbo-i2v",
|
|
73
|
-
"klingai/kling-v2.5-turbo-t2v",
|
|
74
|
-
"klingai/kling-v2.6-i2v",
|
|
75
|
-
"klingai/kling-v2.6-motion-control",
|
|
76
|
-
"klingai/kling-v2.6-t2v",
|
|
77
|
-
"klingai/kling-v3.0-i2v",
|
|
78
|
-
"klingai/kling-v3.0-t2v",
|
|
79
|
-
"xai/grok-imagine-video",
|
|
80
|
-
];
|
|
9
|
+
const GATEWAY_MODELS_URL = "https://ai-gateway.vercel.sh/v1/models";
|
|
10
|
+
const GATEWAY_TIMEOUT_MS = 5_000;
|
|
11
|
+
|
|
12
|
+
export interface ModelPricing {
|
|
13
|
+
input?: string;
|
|
14
|
+
output?: string;
|
|
15
|
+
image?: string;
|
|
16
|
+
}
|
|
81
17
|
|
|
82
18
|
export interface ModelEntry {
|
|
83
19
|
id: string;
|
|
84
20
|
name?: string;
|
|
85
21
|
description?: string;
|
|
22
|
+
creator: string;
|
|
23
|
+
capabilities: Modality[];
|
|
24
|
+
pricing?: ModelPricing;
|
|
86
25
|
}
|
|
87
26
|
|
|
88
27
|
export interface GatewayModels {
|
|
89
28
|
text: ModelEntry[];
|
|
90
29
|
image: ModelEntry[];
|
|
91
30
|
video: ModelEntry[];
|
|
31
|
+
all: ModelEntry[];
|
|
32
|
+
languageImageModelIds: Set<string>;
|
|
92
33
|
}
|
|
93
34
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
35
|
+
interface RawGatewayModel {
|
|
36
|
+
id: string;
|
|
37
|
+
name?: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
owned_by?: string;
|
|
40
|
+
type?: string;
|
|
41
|
+
tags?: string[];
|
|
42
|
+
pricing?: {
|
|
43
|
+
input?: string;
|
|
44
|
+
output?: string;
|
|
45
|
+
image?: string;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
99
48
|
|
|
100
|
-
|
|
101
|
-
|
|
49
|
+
let cached: Promise<GatewayModels> | null = null;
|
|
50
|
+
|
|
51
|
+
export function fetchGatewayModels(): Promise<GatewayModels> {
|
|
52
|
+
if (!cached) {
|
|
53
|
+
cached = doFetch().catch((err) => {
|
|
54
|
+
cached = null;
|
|
55
|
+
throw err;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return cached;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function resetGatewayCache(): void {
|
|
62
|
+
cached = null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function doFetch(): Promise<GatewayModels> {
|
|
66
|
+
const result: GatewayModels = {
|
|
67
|
+
text: [],
|
|
68
|
+
image: [],
|
|
69
|
+
video: [],
|
|
70
|
+
all: [],
|
|
71
|
+
languageImageModelIds: new Set(),
|
|
72
|
+
};
|
|
102
73
|
|
|
103
74
|
try {
|
|
104
|
-
const
|
|
75
|
+
const res = await fetch(GATEWAY_MODELS_URL, {
|
|
76
|
+
signal: AbortSignal.timeout(GATEWAY_TIMEOUT_MS),
|
|
77
|
+
});
|
|
78
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
79
|
+
const json = (await res.json()) as { data?: RawGatewayModel[] };
|
|
80
|
+
const models = json.data ?? [];
|
|
81
|
+
|
|
82
|
+
const entryMap = new Map<string, ModelEntry>();
|
|
83
|
+
|
|
105
84
|
for (const m of models) {
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
85
|
+
const tags = m.tags ?? [];
|
|
86
|
+
const isImageGen = tags.includes("image-generation");
|
|
87
|
+
const capabilities: Modality[] = [];
|
|
88
|
+
|
|
89
|
+
switch (m.type) {
|
|
90
|
+
case "language":
|
|
91
|
+
capabilities.push("text");
|
|
92
|
+
if (isImageGen) capabilities.push("image");
|
|
93
|
+
break;
|
|
94
|
+
case "image":
|
|
95
|
+
capabilities.push("image");
|
|
96
|
+
break;
|
|
97
|
+
case "video":
|
|
98
|
+
capabilities.push("video");
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const creator =
|
|
105
|
+
m.owned_by ??
|
|
106
|
+
(m.id.slice(0, Math.max(0, m.id.indexOf("/"))) || "other");
|
|
107
|
+
|
|
108
|
+
const pricing: ModelPricing | undefined =
|
|
109
|
+
m.pricing?.input || m.pricing?.output || m.pricing?.image
|
|
110
|
+
? {
|
|
111
|
+
...(m.pricing.input ? { input: m.pricing.input } : {}),
|
|
112
|
+
...(m.pricing.output ? { output: m.pricing.output } : {}),
|
|
113
|
+
...(m.pricing.image ? { image: m.pricing.image } : {}),
|
|
114
|
+
}
|
|
115
|
+
: undefined;
|
|
116
|
+
|
|
117
|
+
const entry: ModelEntry = {
|
|
110
118
|
id: m.id,
|
|
111
119
|
name: m.name,
|
|
112
|
-
description: m.description
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
result.image = FALLBACK_IMAGE_MODELS.map((id) => ({ id }));
|
|
118
|
-
result.video = FALLBACK_VIDEO_MODELS.map((id) => ({ id }));
|
|
119
|
-
}
|
|
120
|
+
description: m.description,
|
|
121
|
+
creator,
|
|
122
|
+
capabilities,
|
|
123
|
+
pricing,
|
|
124
|
+
};
|
|
120
125
|
|
|
121
|
-
|
|
122
|
-
result.text = FALLBACK_TEXT_MODELS.map((id) => ({ id }));
|
|
123
|
-
}
|
|
124
|
-
if (result.image.length === 0) {
|
|
125
|
-
result.image = FALLBACK_IMAGE_MODELS.map((id) => ({ id }));
|
|
126
|
-
}
|
|
127
|
-
if (result.video.length === 0) {
|
|
128
|
-
result.video = FALLBACK_VIDEO_MODELS.map((id) => ({ id }));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return result;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function expandModelId(input: string, modality: Modality): string {
|
|
135
|
-
if (input.includes("/")) return input;
|
|
126
|
+
entryMap.set(m.id, entry);
|
|
136
127
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
else if (modality === "video") knownLists.push(FALLBACK_VIDEO_MODELS);
|
|
128
|
+
if (capabilities.includes("text")) result.text.push(entry);
|
|
129
|
+
if (capabilities.includes("image")) result.image.push(entry);
|
|
130
|
+
if (capabilities.includes("video")) result.video.push(entry);
|
|
141
131
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (name === input) return fullId;
|
|
132
|
+
if (m.type === "language" && isImageGen) {
|
|
133
|
+
result.languageImageModelIds.add(m.id);
|
|
134
|
+
}
|
|
146
135
|
}
|
|
136
|
+
|
|
137
|
+
result.all = [...entryMap.values()];
|
|
138
|
+
} catch {
|
|
139
|
+
cached = null;
|
|
140
|
+
process.stderr.write("Warning: could not fetch models from AI Gateway\n");
|
|
147
141
|
}
|
|
148
142
|
|
|
149
|
-
return
|
|
143
|
+
return result;
|
|
150
144
|
}
|
|
151
145
|
|
|
152
146
|
export function resolveModels(
|
|
153
147
|
modality: Modality,
|
|
154
|
-
userModel?: string
|
|
148
|
+
userModel?: string,
|
|
149
|
+
knownModels?: Pick<ModelEntry, "id">[]
|
|
155
150
|
): string[] {
|
|
156
151
|
if (!userModel) return [DEFAULTS[modality]];
|
|
157
152
|
const models = userModel
|
|
158
153
|
.split(",")
|
|
159
154
|
.map((m) => m.trim())
|
|
160
155
|
.filter(Boolean)
|
|
161
|
-
.map((m) => expandModelId(m,
|
|
156
|
+
.map((m) => expandModelId(m, knownModels));
|
|
162
157
|
return models.length > 0 ? models : [DEFAULTS[modality]];
|
|
163
158
|
}
|
|
159
|
+
|
|
160
|
+
function expandModelId(
|
|
161
|
+
input: string,
|
|
162
|
+
knownModels?: Pick<ModelEntry, "id">[]
|
|
163
|
+
): string {
|
|
164
|
+
if (input.includes("/")) return input;
|
|
165
|
+
if (!knownModels) return input;
|
|
166
|
+
|
|
167
|
+
for (const m of knownModels) {
|
|
168
|
+
const name = m.id.slice(m.id.indexOf("/") + 1);
|
|
169
|
+
if (name === input) return m.id;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return input;
|
|
173
|
+
}
|
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
import type { Command } from "commander";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
FALLBACK_TEXT_MODELS,
|
|
5
|
-
FALLBACK_IMAGE_MODELS,
|
|
6
|
-
FALLBACK_VIDEO_MODELS,
|
|
7
|
-
} from "../lib/models.js";
|
|
8
|
-
|
|
9
|
-
export function registerCompletionsCommand(program: Command) {
|
|
10
|
-
program
|
|
11
|
-
.command("completions")
|
|
12
|
-
.description("Output shell completion script")
|
|
13
|
-
.argument("<shell>", "Shell type: zsh, bash, fish")
|
|
14
|
-
.action((shell: string) => {
|
|
15
|
-
switch (shell.toLowerCase()) {
|
|
16
|
-
case "zsh":
|
|
17
|
-
process.stdout.write(generateZsh());
|
|
18
|
-
break;
|
|
19
|
-
case "bash":
|
|
20
|
-
process.stdout.write(generateBash());
|
|
21
|
-
break;
|
|
22
|
-
case "fish":
|
|
23
|
-
process.stdout.write(generateFish());
|
|
24
|
-
break;
|
|
25
|
-
default:
|
|
26
|
-
process.stderr.write(
|
|
27
|
-
`Unknown shell: ${shell}. Supported: zsh, bash, fish\n`
|
|
28
|
-
);
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const SUBCOMMANDS = ["text", "image", "video", "models", "completions", "help"];
|
|
35
|
-
const GLOBAL_FLAGS = [
|
|
36
|
-
"--model",
|
|
37
|
-
"--output",
|
|
38
|
-
"--count",
|
|
39
|
-
"--concurrency",
|
|
40
|
-
"--quiet",
|
|
41
|
-
"--json",
|
|
42
|
-
"--help",
|
|
43
|
-
"--version",
|
|
44
|
-
];
|
|
45
|
-
const TEXT_FLAGS = ["--format", "--system", "--max-tokens", "--temperature"];
|
|
46
|
-
const IMAGE_FLAGS = [
|
|
47
|
-
"--size",
|
|
48
|
-
"--aspect-ratio",
|
|
49
|
-
"--quality",
|
|
50
|
-
"--style",
|
|
51
|
-
"--no-preview",
|
|
52
|
-
];
|
|
53
|
-
const VIDEO_FLAGS = ["--aspect-ratio", "--duration", "--no-preview"];
|
|
54
|
-
const MODEL_FLAGS = ["--type", "--provider", "--json", "--help"];
|
|
55
|
-
|
|
56
|
-
const ALL_MODELS = [
|
|
57
|
-
...FALLBACK_TEXT_MODELS,
|
|
58
|
-
...FALLBACK_IMAGE_MODELS,
|
|
59
|
-
...FALLBACK_VIDEO_MODELS,
|
|
60
|
-
];
|
|
61
|
-
const MODEL_NAMES = ALL_MODELS.map((m) => m.slice(m.indexOf("/") + 1));
|
|
62
|
-
|
|
63
|
-
function generateZsh(): string {
|
|
64
|
-
return `#compdef ai
|
|
65
|
-
|
|
66
|
-
_ai() {
|
|
67
|
-
local -a subcommands
|
|
68
|
-
subcommands=(
|
|
69
|
-
'text:Generate text from a prompt'
|
|
70
|
-
'image:Generate an image from a prompt'
|
|
71
|
-
'video:Generate a video from a prompt'
|
|
72
|
-
'models:List available models'
|
|
73
|
-
'completions:Output shell completion script'
|
|
74
|
-
'help:Display help'
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
local -a models
|
|
78
|
-
models=(${ALL_MODELS.join(" ")})
|
|
79
|
-
|
|
80
|
-
local -a model_names
|
|
81
|
-
model_names=(${MODEL_NAMES.join(" ")})
|
|
82
|
-
|
|
83
|
-
_arguments -C \\
|
|
84
|
-
'1:command:->cmd' \\
|
|
85
|
-
'*::arg:->args'
|
|
86
|
-
|
|
87
|
-
case $state in
|
|
88
|
-
cmd)
|
|
89
|
-
_describe 'command' subcommands
|
|
90
|
-
;;
|
|
91
|
-
args)
|
|
92
|
-
case $words[1] in
|
|
93
|
-
text)
|
|
94
|
-
_arguments \\
|
|
95
|
-
'-m[Model ID]:model:($models $model_names)' \\
|
|
96
|
-
'--model[Model ID]:model:($models $model_names)' \\
|
|
97
|
-
'-o[Output path]:file:_files' \\
|
|
98
|
-
'--output[Output path]:file:_files' \\
|
|
99
|
-
'-f[Format]:format:(md txt)' \\
|
|
100
|
-
'--format[Format]:format:(md txt)' \\
|
|
101
|
-
'-n[Count]:count:' \\
|
|
102
|
-
'--count[Count]:count:' \\
|
|
103
|
-
'-p[Concurrency]:concurrency:' \\
|
|
104
|
-
'--concurrency[Concurrency]:concurrency:' \\
|
|
105
|
-
'-s[System prompt]:system:' \\
|
|
106
|
-
'--system[System prompt]:system:' \\
|
|
107
|
-
'--max-tokens[Max tokens]:tokens:' \\
|
|
108
|
-
'-t[Temperature]:temp:' \\
|
|
109
|
-
'--temperature[Temperature]:temp:' \\
|
|
110
|
-
'-q[Quiet]' \\
|
|
111
|
-
'--quiet[Quiet]' \\
|
|
112
|
-
'--json[JSON output]' \\
|
|
113
|
-
'*:prompt:'
|
|
114
|
-
;;
|
|
115
|
-
image)
|
|
116
|
-
_arguments \\
|
|
117
|
-
'-m[Model ID]:model:($models $model_names)' \\
|
|
118
|
-
'--model[Model ID]:model:($models $model_names)' \\
|
|
119
|
-
'-o[Output path]:file:_files' \\
|
|
120
|
-
'--output[Output path]:file:_files' \\
|
|
121
|
-
'-n[Count]:count:' \\
|
|
122
|
-
'--count[Count]:count:' \\
|
|
123
|
-
'-p[Concurrency]:concurrency:' \\
|
|
124
|
-
'--concurrency[Concurrency]:concurrency:' \\
|
|
125
|
-
'--size[Size]:size:' \\
|
|
126
|
-
'--aspect-ratio[Aspect ratio]:ratio:' \\
|
|
127
|
-
'--quality[Quality]:quality:(standard hd)' \\
|
|
128
|
-
'--style[Style]:style:(vivid natural)' \\
|
|
129
|
-
'--no-preview[Disable inline image preview]' \\
|
|
130
|
-
'-q[Quiet]' \\
|
|
131
|
-
'--quiet[Quiet]' \\
|
|
132
|
-
'--json[JSON output]' \\
|
|
133
|
-
'*:prompt:'
|
|
134
|
-
;;
|
|
135
|
-
video)
|
|
136
|
-
_arguments \\
|
|
137
|
-
'-m[Model ID]:model:($models $model_names)' \\
|
|
138
|
-
'--model[Model ID]:model:($models $model_names)' \\
|
|
139
|
-
'-o[Output path]:file:_files' \\
|
|
140
|
-
'--output[Output path]:file:_files' \\
|
|
141
|
-
'-n[Count]:count:' \\
|
|
142
|
-
'--count[Count]:count:' \\
|
|
143
|
-
'-p[Concurrency]:concurrency:' \\
|
|
144
|
-
'--concurrency[Concurrency]:concurrency:' \\
|
|
145
|
-
'--aspect-ratio[Aspect ratio]:ratio:' \\
|
|
146
|
-
'--duration[Duration]:seconds:' \\
|
|
147
|
-
'--no-preview[Disable inline video frame preview]' \\
|
|
148
|
-
'-q[Quiet]' \\
|
|
149
|
-
'--quiet[Quiet]' \\
|
|
150
|
-
'--json[JSON output]' \\
|
|
151
|
-
'*:prompt:'
|
|
152
|
-
;;
|
|
153
|
-
models)
|
|
154
|
-
_arguments \\
|
|
155
|
-
'--type[Filter by type]:type:(text image video)' \\
|
|
156
|
-
'--provider[Filter by provider]:provider:' \\
|
|
157
|
-
'--json[JSON output]'
|
|
158
|
-
;;
|
|
159
|
-
completions)
|
|
160
|
-
_arguments '1:shell:(zsh bash fish)'
|
|
161
|
-
;;
|
|
162
|
-
esac
|
|
163
|
-
;;
|
|
164
|
-
esac
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
_ai "$@"
|
|
168
|
-
`;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function generateBash(): string {
|
|
172
|
-
return `_ai_completions() {
|
|
173
|
-
local cur prev subcmd
|
|
174
|
-
COMPREPLY=()
|
|
175
|
-
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
176
|
-
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
177
|
-
subcmd="\${COMP_WORDS[1]}"
|
|
178
|
-
|
|
179
|
-
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
180
|
-
COMPREPLY=($(compgen -W "${SUBCOMMANDS.join(" ")}" -- "$cur"))
|
|
181
|
-
return
|
|
182
|
-
fi
|
|
183
|
-
|
|
184
|
-
case "$prev" in
|
|
185
|
-
-m|--model)
|
|
186
|
-
COMPREPLY=($(compgen -W "${ALL_MODELS.join(" ")} ${MODEL_NAMES.join(" ")}" -- "$cur"))
|
|
187
|
-
return
|
|
188
|
-
;;
|
|
189
|
-
-o|--output)
|
|
190
|
-
COMPREPLY=($(compgen -f -- "$cur"))
|
|
191
|
-
return
|
|
192
|
-
;;
|
|
193
|
-
-f|--format)
|
|
194
|
-
COMPREPLY=($(compgen -W "md txt" -- "$cur"))
|
|
195
|
-
return
|
|
196
|
-
;;
|
|
197
|
-
--quality)
|
|
198
|
-
COMPREPLY=($(compgen -W "standard hd" -- "$cur"))
|
|
199
|
-
return
|
|
200
|
-
;;
|
|
201
|
-
--style)
|
|
202
|
-
COMPREPLY=($(compgen -W "vivid natural" -- "$cur"))
|
|
203
|
-
return
|
|
204
|
-
;;
|
|
205
|
-
--type)
|
|
206
|
-
COMPREPLY=($(compgen -W "text image video" -- "$cur"))
|
|
207
|
-
return
|
|
208
|
-
;;
|
|
209
|
-
esac
|
|
210
|
-
|
|
211
|
-
case "$subcmd" in
|
|
212
|
-
text)
|
|
213
|
-
COMPREPLY=($(compgen -W "${[...GLOBAL_FLAGS, ...TEXT_FLAGS].join(" ")}" -- "$cur"))
|
|
214
|
-
;;
|
|
215
|
-
image)
|
|
216
|
-
COMPREPLY=($(compgen -W "${[...GLOBAL_FLAGS, ...IMAGE_FLAGS].join(" ")}" -- "$cur"))
|
|
217
|
-
;;
|
|
218
|
-
video)
|
|
219
|
-
COMPREPLY=($(compgen -W "${[...GLOBAL_FLAGS, ...VIDEO_FLAGS].join(" ")}" -- "$cur"))
|
|
220
|
-
;;
|
|
221
|
-
models)
|
|
222
|
-
COMPREPLY=($(compgen -W "${MODEL_FLAGS.join(" ")}" -- "$cur"))
|
|
223
|
-
;;
|
|
224
|
-
completions)
|
|
225
|
-
COMPREPLY=($(compgen -W "zsh bash fish" -- "$cur"))
|
|
226
|
-
;;
|
|
227
|
-
esac
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
complete -F _ai_completions ai
|
|
231
|
-
`;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function generateFish(): string {
|
|
235
|
-
const lines: string[] = [];
|
|
236
|
-
lines.push("# ai completions for fish");
|
|
237
|
-
lines.push("");
|
|
238
|
-
|
|
239
|
-
for (const sub of SUBCOMMANDS) {
|
|
240
|
-
lines.push(`complete -c ai -n '__fish_use_subcommand' -a '${sub}'`);
|
|
241
|
-
}
|
|
242
|
-
lines.push("");
|
|
243
|
-
|
|
244
|
-
const SHORT_FLAG_MAP: Record<string, string> = {
|
|
245
|
-
"--model": "m",
|
|
246
|
-
"--output": "o",
|
|
247
|
-
"--count": "n",
|
|
248
|
-
"--concurrency": "p",
|
|
249
|
-
"--quiet": "q",
|
|
250
|
-
"--format": "f",
|
|
251
|
-
"--system": "s",
|
|
252
|
-
"--temperature": "t",
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
const addFlags = (sub: string, flags: string[]) => {
|
|
256
|
-
for (const flag of flags) {
|
|
257
|
-
const name = flag.replace(/^--/, "");
|
|
258
|
-
const short = SHORT_FLAG_MAP[flag];
|
|
259
|
-
const shortPart = short ? ` -s ${short}` : "";
|
|
260
|
-
lines.push(
|
|
261
|
-
`complete -c ai -n '__fish_seen_subcommand_from ${sub}'${shortPart} -l '${name}'`
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
addFlags("text", [...GLOBAL_FLAGS, ...TEXT_FLAGS]);
|
|
267
|
-
addFlags("image", [...GLOBAL_FLAGS, ...IMAGE_FLAGS]);
|
|
268
|
-
addFlags("video", [...GLOBAL_FLAGS, ...VIDEO_FLAGS]);
|
|
269
|
-
addFlags("models", MODEL_FLAGS);
|
|
270
|
-
|
|
271
|
-
lines.push("");
|
|
272
|
-
lines.push(
|
|
273
|
-
`complete -c ai -n '__fish_seen_subcommand_from completions' -a 'zsh bash fish'`
|
|
274
|
-
);
|
|
275
|
-
lines.push("");
|
|
276
|
-
|
|
277
|
-
const modelCompletions = ALL_MODELS.concat(MODEL_NAMES);
|
|
278
|
-
lines.push(
|
|
279
|
-
`complete -c ai -n '__fish_seen_subcommand_from text image video' -s m -l model -a '${modelCompletions.join(" ")}'`
|
|
280
|
-
);
|
|
281
|
-
lines.push(
|
|
282
|
-
`complete -c ai -n '__fish_seen_subcommand_from text' -s f -l format -a 'md txt'`
|
|
283
|
-
);
|
|
284
|
-
lines.push(
|
|
285
|
-
`complete -c ai -n '__fish_seen_subcommand_from image' -l quality -a 'standard hd'`
|
|
286
|
-
);
|
|
287
|
-
lines.push(
|
|
288
|
-
`complete -c ai -n '__fish_seen_subcommand_from image' -l style -a 'vivid natural'`
|
|
289
|
-
);
|
|
290
|
-
lines.push(
|
|
291
|
-
`complete -c ai -n '__fish_seen_subcommand_from models' -l type -a 'text image video'`
|
|
292
|
-
);
|
|
293
|
-
lines.push("");
|
|
294
|
-
|
|
295
|
-
return lines.join("\n");
|
|
296
|
-
}
|