promptimizer-cli 0.1.24 → 0.1.26
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 +21 -11
- package/bin/promptimizer.mjs +204 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
# promptimizer-cli
|
|
2
2
|
|
|
3
|
-
Gemini-style interactive routing CLI for Promptimizer.
|
|
3
|
+
Gemini-style interactive routing CLI for Promptimizer. Multi-host fleets: add and remove providers; the router picks across the merged model set.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install -g
|
|
6
|
+
npm install -g ./packages/cli
|
|
7
|
+
# or after publish: npm install -g promptimizer-cli@latest
|
|
7
8
|
promptimizer
|
|
8
9
|
```
|
|
9
10
|
|
|
10
|
-
Requires **≥ 0.1.
|
|
11
|
+
Requires **≥ 0.1.23** for `/hosts`, `/connect`, `/disconnect`.
|
|
11
12
|
|
|
12
13
|
```text
|
|
13
|
-
Promptimizer v0.1.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
Promptimizer v0.1.23
|
|
15
|
+
● Baseten (16) · NVIDIA NIM (74) · 90 models
|
|
16
|
+
2 hosts merged · router picks across all
|
|
17
|
+
› /hosts
|
|
18
|
+
✓ Baseten 16 models
|
|
19
|
+
✓ NVIDIA NIM 74 models
|
|
19
20
|
```
|
|
20
21
|
|
|
21
22
|
## Commands
|
|
@@ -25,9 +26,18 @@ Requires **≥ 0.1.22** for REPL `/logout`. If `/help` does not list `/logout`,
|
|
|
25
26
|
| `promptimizer` | Interactive multi-turn session |
|
|
26
27
|
| `promptimizer login --key pmz_live_…` | Save API key |
|
|
27
28
|
| `promptimizer logout` / REPL `/logout` | Remove `~/.promptimizer/config.json` |
|
|
28
|
-
| `promptimizer connect baseten --key $BASETEN_API_KEY` |
|
|
29
|
+
| `promptimizer connect baseten --key $BASETEN_API_KEY` | **Add** a host (keeps existing) |
|
|
30
|
+
| `promptimizer connect nvidia --key $NVIDIA_API_KEY` | Add another host |
|
|
31
|
+
| `promptimizer disconnect nvidia` | **Remove** a host |
|
|
32
|
+
| `promptimizer hosts` | List connected hosts |
|
|
33
|
+
| `promptimizer models` | List merged fleet (tier · host · id) |
|
|
29
34
|
| `promptimizer chat "…"` | One-shot completion |
|
|
30
|
-
| `promptimizer models` | List fleet |
|
|
31
35
|
| `promptimizer savings` | Account ledger |
|
|
32
36
|
|
|
37
|
+
Aliases: `add` → connect, `remove` / `rm` → disconnect.
|
|
38
|
+
|
|
39
|
+
### REPL slash commands
|
|
40
|
+
|
|
41
|
+
`/hosts` · `/models` · `/connect <host> --key …` · `/disconnect <host>` · `/savings` · `/clear` · `/logout` · `/quit`
|
|
42
|
+
|
|
33
43
|
Defaults to the hosted gateway. Override with `--url` or `PROMPTIMIZER_URL`.
|
package/bin/promptimizer.mjs
CHANGED
|
@@ -30,9 +30,11 @@ const COMMANDS = [
|
|
|
30
30
|
["", "Start interactive session (Gemini-style REPL)"],
|
|
31
31
|
["login", "Save a Promptimizer API key"],
|
|
32
32
|
["logout", "Remove the saved key"],
|
|
33
|
-
["connect", "
|
|
33
|
+
["connect", "Add a model host (keeps existing hosts)"],
|
|
34
|
+
["disconnect", "Remove a model host from the fleet"],
|
|
35
|
+
["hosts", "List connected hosts"],
|
|
34
36
|
["chat", "Route one completion"],
|
|
35
|
-
["models", "List the
|
|
37
|
+
["models", "List the merged fleet"],
|
|
36
38
|
["savings", "Show account savings"],
|
|
37
39
|
["providers", "List known provider URLs"],
|
|
38
40
|
];
|
|
@@ -50,7 +52,20 @@ const COMMAND_HELP = {
|
|
|
50
52
|
" promptimizer connect <provider> --key <vendor-key>",
|
|
51
53
|
" promptimizer connect custom --base-url <url> --key <vendor-key>",
|
|
52
54
|
" promptimizer connect simulator",
|
|
55
|
+
"",
|
|
56
|
+
"Adds a host to your fleet without replacing others.",
|
|
57
|
+
"Aliases: add",
|
|
58
|
+
],
|
|
59
|
+
disconnect: [
|
|
60
|
+
"Usage",
|
|
61
|
+
" promptimizer disconnect <provider>",
|
|
62
|
+
" promptimizer disconnect baseten",
|
|
63
|
+
" promptimizer disconnect nvidia",
|
|
64
|
+
"",
|
|
65
|
+
"Removes that host and its models. Other hosts stay.",
|
|
66
|
+
"Aliases: remove, rm",
|
|
53
67
|
],
|
|
68
|
+
hosts: ["Usage", " promptimizer hosts", "", "Show connected hosts and model counts."],
|
|
54
69
|
chat: [
|
|
55
70
|
"Usage",
|
|
56
71
|
' promptimizer chat "What is 17 * 24?"',
|
|
@@ -103,6 +118,15 @@ function parse(argv) {
|
|
|
103
118
|
return { flags, positional };
|
|
104
119
|
}
|
|
105
120
|
|
|
121
|
+
/** Parse slash-command args inside the REPL: `/connect baseten --key sk-…` */
|
|
122
|
+
function parseLineArgs(line) {
|
|
123
|
+
const parts = [];
|
|
124
|
+
const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
|
|
125
|
+
let m;
|
|
126
|
+
while ((m = re.exec(line))) parts.push(m[1] ?? m[2] ?? m[3]);
|
|
127
|
+
return parse(parts);
|
|
128
|
+
}
|
|
129
|
+
|
|
106
130
|
function readConfig() {
|
|
107
131
|
try {
|
|
108
132
|
return JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
|
|
@@ -133,10 +157,24 @@ function printVersion() {
|
|
|
133
157
|
return pkg.version;
|
|
134
158
|
}
|
|
135
159
|
|
|
160
|
+
function hostSummary(session) {
|
|
161
|
+
const connections = session?.connections ?? [];
|
|
162
|
+
if (connections.length) {
|
|
163
|
+
return connections
|
|
164
|
+
.map((c) => {
|
|
165
|
+
const count = (session.models ?? []).filter((m) => m.provider_id === c.id).length;
|
|
166
|
+
return `${c.label}${count ? ` (${count})` : ""}`;
|
|
167
|
+
})
|
|
168
|
+
.join(" · ");
|
|
169
|
+
}
|
|
170
|
+
return session?.label || "not connected";
|
|
171
|
+
}
|
|
172
|
+
|
|
136
173
|
function banner(session, version) {
|
|
137
|
-
const
|
|
174
|
+
const hosts = hostSummary(session);
|
|
138
175
|
const models = session?.models?.length ?? 0;
|
|
139
176
|
const baseline = session?.baseline_model || "—";
|
|
177
|
+
const hostCount = session?.connections?.length ?? 0;
|
|
140
178
|
out();
|
|
141
179
|
out(color(ANSI.cyan, " ██████╗ ███╗ ███╗███████╗"));
|
|
142
180
|
out(color(ANSI.cyan, " ██╔══██╗████╗ ████║╚══███╔╝"));
|
|
@@ -148,14 +186,30 @@ function banner(session, version) {
|
|
|
148
186
|
out(` ${color(ANSI.bold, "Promptimizer")} ${color(ANSI.dim, `v${version}`)}`);
|
|
149
187
|
out(` ${color(ANSI.dim, "Quality-aware routing · OpenAI-compatible")}`);
|
|
150
188
|
out();
|
|
151
|
-
out(` ${color(ANSI.green, "●")} ${
|
|
189
|
+
out(` ${color(ANSI.green, "●")} ${hosts}${models ? ` · ${models} models` : ""}`);
|
|
190
|
+
if (hostCount > 1) out(` ${color(ANSI.dim, `${hostCount} hosts merged · router picks across all`)}`);
|
|
152
191
|
out(` ${color(ANSI.dim, `baseline ${baseline}`)}`);
|
|
153
192
|
out();
|
|
154
|
-
out(
|
|
193
|
+
out(
|
|
194
|
+
` ${color(ANSI.dim, "Type a prompt, or /help /hosts /models /connect /disconnect /clear /quit")}`,
|
|
195
|
+
);
|
|
155
196
|
out(` ${color(ANSI.dim, "Cache keys on full history — /clear then repeat a prompt to see cache hit")}`);
|
|
156
197
|
out();
|
|
157
198
|
}
|
|
158
199
|
|
|
200
|
+
function printFleetSummary(session, { added, removed } = {}) {
|
|
201
|
+
const connections = session.connections ?? [];
|
|
202
|
+
if (added) out(`${color(ANSI.green, "✓")} Added ${added}`);
|
|
203
|
+
if (removed) out(`${color(ANSI.green, "✓")} Removed ${removed}`);
|
|
204
|
+
if (!added && !removed) out(`${color(ANSI.green, "✓")} ${session.label}`);
|
|
205
|
+
if (connections.length) {
|
|
206
|
+
out(` hosts ${connections.map((c) => c.label).join(" · ")}`);
|
|
207
|
+
} else {
|
|
208
|
+
out(` ${session.label} ${session.base_url}`);
|
|
209
|
+
}
|
|
210
|
+
out(` models ${session.models?.length ?? 0} · baseline ${session.baseline_model ?? "—"}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
159
213
|
function help() {
|
|
160
214
|
out("Usage: promptimizer [--url <gateway>] [command] [options]");
|
|
161
215
|
out();
|
|
@@ -178,8 +232,10 @@ function help() {
|
|
|
178
232
|
out(" promptimizer");
|
|
179
233
|
out(" promptimizer login --key pmz_live_…");
|
|
180
234
|
out(" promptimizer connect baseten --key $BASETEN_API_KEY");
|
|
235
|
+
out(" promptimizer connect nvidia --key $NVIDIA_API_KEY");
|
|
236
|
+
out(" promptimizer hosts");
|
|
237
|
+
out(" promptimizer disconnect nvidia");
|
|
181
238
|
out(' promptimizer chat "What is 17 * 24?"');
|
|
182
|
-
out(" promptimizer savings");
|
|
183
239
|
out();
|
|
184
240
|
}
|
|
185
241
|
|
|
@@ -243,10 +299,20 @@ function printMeta(result) {
|
|
|
243
299
|
const saved = result.usage?.cost?.saved_usd;
|
|
244
300
|
const bits = [meta.model || result.model, meta.tier].filter(Boolean);
|
|
245
301
|
if (meta.routing_policy) bits.push(String(meta.routing_policy));
|
|
302
|
+
if (meta.provider_id || meta.host) bits.push(String(meta.provider_id || meta.host));
|
|
246
303
|
if (saved != null) bits.push(`saved ${usd(saved)}`);
|
|
247
304
|
if (meta.exact_cache_hit) bits.push(color(ANSI.green, "cache hit"));
|
|
248
|
-
else if (meta.
|
|
305
|
+
else if (meta.semantic_cache_hit) {
|
|
306
|
+
const mode = meta.semantic_cache_mode === "full" ? "semantic full" : "semantic hybrid";
|
|
307
|
+
const sim =
|
|
308
|
+
meta.semantic_similarity != null ? ` ${Math.round(Number(meta.semantic_similarity) * 100)}%` : "";
|
|
309
|
+
bits.push(color(ANSI.green, `${mode}${sim}`));
|
|
310
|
+
} else if (meta.prefix_cache_hit) bits.push(color(ANSI.green, "prefix cache"));
|
|
249
311
|
else if ("cache_hit" in meta) bits.push(color(ANSI.gray, "miss"));
|
|
312
|
+
if (meta.quality_gate) bits.push(`gate:${meta.quality_gate}`);
|
|
313
|
+
if (meta.quality_audit) {
|
|
314
|
+
bits.push(meta.quality_audit_pass === false ? color(ANSI.yellow, "audit fail") : "audit ok");
|
|
315
|
+
}
|
|
250
316
|
if (meta.escalated) bits.push(meta.escalation_reason ? `escalated:${meta.escalation_reason}` : "escalated");
|
|
251
317
|
if (meta.latency_ms != null) bits.push(`${Math.round(Number(meta.latency_ms))}ms`);
|
|
252
318
|
out(color(ANSI.dim, ` ↳ ${bits.join(" · ")}`));
|
|
@@ -303,11 +369,14 @@ async function cmdConnect(flags, positional) {
|
|
|
303
369
|
const provider = String(flags.provider || positional[0] || "").trim();
|
|
304
370
|
const baseURL = flags["base-url"] || flags.baseUrl;
|
|
305
371
|
if (!provider && !baseURL) {
|
|
306
|
-
die(
|
|
372
|
+
die(
|
|
373
|
+
"Usage: promptimizer connect <provider> --key <vendor-key>\n promptimizer connect custom --base-url https://… --key …",
|
|
374
|
+
);
|
|
307
375
|
}
|
|
308
376
|
|
|
309
377
|
const mock = provider === "simulator" || provider === "mock";
|
|
310
378
|
let vendorKey = flags.key || flags.k;
|
|
379
|
+
let label = flags.label;
|
|
311
380
|
if (!mock && !baseURL && provider && provider !== "custom") {
|
|
312
381
|
const catalog = await request("/v1/providers", { gatewayURL });
|
|
313
382
|
const found = (catalog.data ?? []).find(
|
|
@@ -318,6 +387,7 @@ async function cmdConnect(flags, positional) {
|
|
|
318
387
|
if (!vendorKey && found.id !== "ollama") {
|
|
319
388
|
die(`Missing API key for ${found.label}. Pass --key or set ${found.env}.`);
|
|
320
389
|
}
|
|
390
|
+
label = label || found.label;
|
|
321
391
|
} else if (!mock && !vendorKey && provider !== "ollama") {
|
|
322
392
|
die("Missing provider key. Pass --key.");
|
|
323
393
|
}
|
|
@@ -331,6 +401,7 @@ async function cmdConnect(flags, positional) {
|
|
|
331
401
|
? { mode: "mock", label: "Promptimizer simulator" }
|
|
332
402
|
: {
|
|
333
403
|
mode: "byok",
|
|
404
|
+
label,
|
|
334
405
|
provider: provider && provider !== "custom" ? provider : undefined,
|
|
335
406
|
base_url: baseURL,
|
|
336
407
|
api_key: vendorKey,
|
|
@@ -338,8 +409,57 @@ async function cmdConnect(flags, positional) {
|
|
|
338
409
|
});
|
|
339
410
|
|
|
340
411
|
writeConfig({ ...config, gatewayURL, apiKey, sessionId: session.session_id });
|
|
341
|
-
out(
|
|
342
|
-
|
|
412
|
+
out();
|
|
413
|
+
printFleetSummary(session, { added: label || provider || session.label });
|
|
414
|
+
out();
|
|
415
|
+
return session;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async function cmdDisconnect(flags, positional) {
|
|
419
|
+
const config = readConfig();
|
|
420
|
+
const gatewayURL = gateway(flags, config);
|
|
421
|
+
const provider = String(flags.provider || flags.host || positional[0] || "").trim();
|
|
422
|
+
if (!provider) die("Usage: promptimizer disconnect <provider>\n promptimizer disconnect baseten");
|
|
423
|
+
|
|
424
|
+
const { apiKey, sessionId } = authFromConfig(flags, config);
|
|
425
|
+
const session = await request("/v1/providers/disconnect", {
|
|
426
|
+
method: "POST",
|
|
427
|
+
gatewayURL,
|
|
428
|
+
apiKey,
|
|
429
|
+
sessionId,
|
|
430
|
+
body: { provider },
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
writeConfig({ ...config, gatewayURL, apiKey, sessionId: session.session_id ?? sessionId });
|
|
434
|
+
out();
|
|
435
|
+
printFleetSummary(session, { removed: session.removed?.label || provider });
|
|
436
|
+
out();
|
|
437
|
+
return session;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
async function cmdHosts(flags) {
|
|
441
|
+
const config = readConfig();
|
|
442
|
+
const session = await loadSession(flags, config);
|
|
443
|
+
const connections = session.connections ?? [];
|
|
444
|
+
out();
|
|
445
|
+
if (!connections.length) {
|
|
446
|
+
out(` ${session.label} (simulator)`);
|
|
447
|
+
out(` ${session.models?.length ?? 0} models`);
|
|
448
|
+
out();
|
|
449
|
+
return session;
|
|
450
|
+
}
|
|
451
|
+
const width = Math.max(8, ...connections.map((c) => String(c.label).length));
|
|
452
|
+
for (const c of connections) {
|
|
453
|
+
const count = (session.models ?? []).filter((m) => m.provider_id === c.id).length;
|
|
454
|
+
out(` ${color(ANSI.green, "✓")} ${c.label.padEnd(width + 2)}${count} models`);
|
|
455
|
+
out(` ${color(ANSI.dim, c.base_url)}`);
|
|
456
|
+
}
|
|
457
|
+
out();
|
|
458
|
+
out(` ${session.models?.length ?? 0} models total · baseline ${session.baseline_model ?? "—"}`);
|
|
459
|
+
out(` ${color(ANSI.dim, "Add: promptimizer connect <host> --key …")}`);
|
|
460
|
+
out(` ${color(ANSI.dim, "Remove: promptimizer disconnect <host>")}`);
|
|
461
|
+
out();
|
|
462
|
+
return session;
|
|
343
463
|
}
|
|
344
464
|
|
|
345
465
|
async function cmdChat(flags, positional) {
|
|
@@ -359,15 +479,30 @@ async function cmdModels(flags) {
|
|
|
359
479
|
const config = readConfig();
|
|
360
480
|
const gatewayURL = gateway(flags, config);
|
|
361
481
|
const { apiKey, sessionId } = authFromConfig(flags, config);
|
|
362
|
-
const data = await
|
|
482
|
+
const [data, session] = await Promise.all([
|
|
483
|
+
request("/v1/models", { gatewayURL, apiKey, sessionId }),
|
|
484
|
+
request("/v1/session", { gatewayURL, apiKey, sessionId }).catch(() => null),
|
|
485
|
+
]);
|
|
363
486
|
const models = data.data ?? [];
|
|
364
|
-
const
|
|
487
|
+
const labelById = new Map((session?.connections ?? []).map((c) => [c.id, c.label]));
|
|
488
|
+
const hostWidth = Math.max(
|
|
489
|
+
4,
|
|
490
|
+
...models.map((m) => String(m.provider_label || labelById.get(m.provider_id) || m.provider_id || "—").length),
|
|
491
|
+
);
|
|
492
|
+
const tierWidth = Math.max(8, ...models.map((m) => String(m.tier).length));
|
|
365
493
|
out();
|
|
366
494
|
for (const model of models) {
|
|
495
|
+
const host = model.provider_label || labelById.get(model.provider_id) || model.provider_id || "—";
|
|
367
496
|
const mark = model.id === data.baseline_model ? color(ANSI.yellow, " baseline") : "";
|
|
368
|
-
out(
|
|
497
|
+
out(
|
|
498
|
+
` ${color(ANSI.dim, String(model.tier).padEnd(tierWidth + 2))}${color(ANSI.cyan, String(host).padEnd(hostWidth + 2))}${model.id}${mark}`,
|
|
499
|
+
);
|
|
369
500
|
}
|
|
370
501
|
out();
|
|
502
|
+
if (session?.connections?.length) {
|
|
503
|
+
out(color(ANSI.dim, ` ${session.connections.length} host(s) · ${models.length} models`));
|
|
504
|
+
out();
|
|
505
|
+
}
|
|
371
506
|
}
|
|
372
507
|
|
|
373
508
|
async function cmdSavings(flags) {
|
|
@@ -419,13 +554,16 @@ async function interactive(flags) {
|
|
|
419
554
|
|
|
420
555
|
const slashHelp = () => {
|
|
421
556
|
out();
|
|
422
|
-
out(` ${color(ANSI.bold, "/help")}
|
|
423
|
-
out(` ${color(ANSI.bold, "/
|
|
424
|
-
out(` ${color(ANSI.bold, "/
|
|
425
|
-
out(` ${color(ANSI.bold, "/
|
|
426
|
-
out(` ${color(ANSI.bold, "/
|
|
427
|
-
out(` ${color(ANSI.bold, "/
|
|
428
|
-
out(` ${color(ANSI.bold, "/
|
|
557
|
+
out(` ${color(ANSI.bold, "/help")} this list`);
|
|
558
|
+
out(` ${color(ANSI.bold, "/hosts")} connected hosts`);
|
|
559
|
+
out(` ${color(ANSI.bold, "/models")} fleet + host + tier`);
|
|
560
|
+
out(` ${color(ANSI.bold, "/connect <host> --key …")} add a host (keeps others)`);
|
|
561
|
+
out(` ${color(ANSI.bold, "/disconnect <host>")} remove a host`);
|
|
562
|
+
out(` ${color(ANSI.bold, "/savings")} account ledger`);
|
|
563
|
+
out(` ${color(ANSI.bold, "/session")} provider status`);
|
|
564
|
+
out(` ${color(ANSI.bold, "/clear")} clear chat history`);
|
|
565
|
+
out(` ${color(ANSI.bold, "/logout")} remove saved API key and exit`);
|
|
566
|
+
out(` ${color(ANSI.bold, "/quit")} exit`);
|
|
429
567
|
out();
|
|
430
568
|
};
|
|
431
569
|
|
|
@@ -463,8 +601,15 @@ async function interactive(flags) {
|
|
|
463
601
|
try {
|
|
464
602
|
session = await loadSession(flags, readConfig());
|
|
465
603
|
out();
|
|
466
|
-
out(` ${session
|
|
467
|
-
|
|
604
|
+
out(` ${hostSummary(session)} · ${session.mode}`);
|
|
605
|
+
if (session.connections?.length) {
|
|
606
|
+
for (const c of session.connections) {
|
|
607
|
+
const count = session.models.filter((m) => m.provider_id === c.id).length;
|
|
608
|
+
out(` ${color(ANSI.green, "✓")} ${c.label} · ${count} models`);
|
|
609
|
+
}
|
|
610
|
+
} else {
|
|
611
|
+
out(` ${session.base_url}`);
|
|
612
|
+
}
|
|
468
613
|
out(` ${session.models.length} models · baseline ${session.baseline_model}`);
|
|
469
614
|
out();
|
|
470
615
|
} catch (error) {
|
|
@@ -473,6 +618,15 @@ async function interactive(flags) {
|
|
|
473
618
|
continue;
|
|
474
619
|
}
|
|
475
620
|
|
|
621
|
+
if (trimmed === "/hosts" || trimmed === "/providers") {
|
|
622
|
+
try {
|
|
623
|
+
session = await cmdHosts(flags);
|
|
624
|
+
} catch (error) {
|
|
625
|
+
out(color(ANSI.yellow, ` ${error instanceof Error ? error.message : String(error)}`));
|
|
626
|
+
}
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
|
|
476
630
|
if (trimmed === "/models") {
|
|
477
631
|
try {
|
|
478
632
|
await cmdModels(flags);
|
|
@@ -491,6 +645,29 @@ async function interactive(flags) {
|
|
|
491
645
|
continue;
|
|
492
646
|
}
|
|
493
647
|
|
|
648
|
+
if (
|
|
649
|
+
trimmed.startsWith("/connect") ||
|
|
650
|
+
trimmed.startsWith("/add ") ||
|
|
651
|
+
trimmed === "/add" ||
|
|
652
|
+
trimmed.startsWith("/disconnect") ||
|
|
653
|
+
trimmed.startsWith("/remove") ||
|
|
654
|
+
trimmed.startsWith("/rm ")
|
|
655
|
+
) {
|
|
656
|
+
const body = trimmed.replace(/^\/(connect|add|disconnect|remove|rm)\s*/i, "");
|
|
657
|
+
const { flags: slashFlags, positional } = parseLineArgs(body);
|
|
658
|
+
const mergedFlags = { ...flags, ...slashFlags };
|
|
659
|
+
const isDisconnect = /^\/(disconnect|remove|rm)\b/i.test(trimmed);
|
|
660
|
+
try {
|
|
661
|
+
session = isDisconnect
|
|
662
|
+
? await cmdDisconnect(mergedFlags, positional)
|
|
663
|
+
: await cmdConnect(mergedFlags, positional);
|
|
664
|
+
} catch (error) {
|
|
665
|
+
out(color(ANSI.yellow, ` ${error instanceof Error ? error.message : String(error)}`));
|
|
666
|
+
out();
|
|
667
|
+
}
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
|
|
494
671
|
if (trimmed.startsWith("/")) {
|
|
495
672
|
out(color(ANSI.dim, " Unknown command. Try /help"));
|
|
496
673
|
continue;
|
|
@@ -550,7 +727,11 @@ async function main() {
|
|
|
550
727
|
if (command === "login") return await cmdLogin(flags);
|
|
551
728
|
if (command === "logout") return cmdLogout();
|
|
552
729
|
if (command === "providers") return await cmdProviders(flags);
|
|
553
|
-
if (command === "connect") return await cmdConnect(flags, rest);
|
|
730
|
+
if (command === "connect" || command === "add") return await cmdConnect(flags, rest);
|
|
731
|
+
if (command === "disconnect" || command === "remove" || command === "rm") {
|
|
732
|
+
return await cmdDisconnect(flags, rest);
|
|
733
|
+
}
|
|
734
|
+
if (command === "hosts") return await cmdHosts(flags);
|
|
554
735
|
if (command === "chat") return await cmdChat(flags, rest);
|
|
555
736
|
if (command === "models") return await cmdModels(flags);
|
|
556
737
|
if (command === "savings") return await cmdSavings(flags);
|