@poolzin/pool-bot 2026.4.41 → 2026.4.43
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/dist/build-info.json +3 -3
- package/dist/cli/infer-cli.d.ts +18 -0
- package/dist/cli/infer-cli.d.ts.map +1 -0
- package/dist/cli/infer-cli.js +386 -0
- package/dist/cli/plugins-config-tui.d.ts +50 -0
- package/dist/cli/plugins-config-tui.d.ts.map +1 -0
- package/dist/cli/plugins-config-tui.js +197 -0
- package/dist/cli/program/register.subclis.d.ts.map +1 -1
- package/dist/cli/program/register.subclis.js +9 -0
- package/dist/cli/secret-cli.d.ts.map +1 -1
- package/dist/cli/secret-cli.js +12 -7
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Infer Hub CLI - Direct inference workflows
|
|
3
|
+
*
|
|
4
|
+
* Provider-backed inference across model, media, web, and embedding tasks.
|
|
5
|
+
* No agent overhead - direct API calls for testing, debugging, and batch processing.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* poolbot infer chat <prompt> # Chat completion
|
|
9
|
+
* poolbot infer image <prompt> # Image generation
|
|
10
|
+
* poolbot infer video <prompt> # Video generation
|
|
11
|
+
* poolbot infer music <prompt> # Music generation
|
|
12
|
+
* poolbot infer embed <text> # Text embeddings
|
|
13
|
+
* poolbot infer web-search <query> # Web search
|
|
14
|
+
* poolbot infer web-fetch <url> # Web page fetch
|
|
15
|
+
*/
|
|
16
|
+
import type { Command } from "commander";
|
|
17
|
+
export declare function registerInferCli(program: Command): void;
|
|
18
|
+
//# sourceMappingURL=infer-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"infer-cli.d.ts","sourceRoot":"","sources":["../../src/cli/infer-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkDzC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,QAobhD"}
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Infer Hub CLI - Direct inference workflows
|
|
3
|
+
*
|
|
4
|
+
* Provider-backed inference across model, media, web, and embedding tasks.
|
|
5
|
+
* No agent overhead - direct API calls for testing, debugging, and batch processing.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* poolbot infer chat <prompt> # Chat completion
|
|
9
|
+
* poolbot infer image <prompt> # Image generation
|
|
10
|
+
* poolbot infer video <prompt> # Video generation
|
|
11
|
+
* poolbot infer music <prompt> # Music generation
|
|
12
|
+
* poolbot infer embed <text> # Text embeddings
|
|
13
|
+
* poolbot infer web-search <query> # Web search
|
|
14
|
+
* poolbot infer web-fetch <url> # Web page fetch
|
|
15
|
+
*/
|
|
16
|
+
import { readFileSync } from "node:fs";
|
|
17
|
+
import { defaultRuntime } from "../runtime.js";
|
|
18
|
+
import { theme } from "../terminal/theme.js";
|
|
19
|
+
import { danger, info, success } from "../globals.js";
|
|
20
|
+
import { formatDocsLink } from "../terminal/links.js";
|
|
21
|
+
import { loadConfig } from "../config/config.js";
|
|
22
|
+
import { callGatewayFromCli } from "./gateway-rpc.js";
|
|
23
|
+
import { runCommandWithRuntime } from "./cli-utils.js";
|
|
24
|
+
function runInferCommand(action) {
|
|
25
|
+
return runCommandWithRuntime(defaultRuntime, action);
|
|
26
|
+
}
|
|
27
|
+
function formatOutput(result, format) {
|
|
28
|
+
if (format === "json") {
|
|
29
|
+
return JSON.stringify(result, null, 2);
|
|
30
|
+
}
|
|
31
|
+
if (format === "markdown") {
|
|
32
|
+
if (typeof result === "string")
|
|
33
|
+
return result;
|
|
34
|
+
return JSON.stringify(result, null, 2);
|
|
35
|
+
}
|
|
36
|
+
// text format
|
|
37
|
+
if (typeof result === "string")
|
|
38
|
+
return result;
|
|
39
|
+
return JSON.stringify(result, null, 2);
|
|
40
|
+
}
|
|
41
|
+
function writeOutput(content, outputPath) {
|
|
42
|
+
if (outputPath) {
|
|
43
|
+
require("node:fs").writeFileSync(outputPath, content, "utf-8");
|
|
44
|
+
defaultRuntime.log(success(`Output written to: ${outputPath}`));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
defaultRuntime.log(content);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function registerInferCli(program) {
|
|
51
|
+
const infer = program
|
|
52
|
+
.command("infer")
|
|
53
|
+
.description("Direct inference workflows (chat, image, video, music, embed, web)")
|
|
54
|
+
.addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/infer", "docs.molt.bot/cli/infer")}\n` +
|
|
55
|
+
`${theme.muted("Tip:")} Use --quiet for scripting, --json for parsing\n`);
|
|
56
|
+
// Common options for all infer commands
|
|
57
|
+
const commonOptions = (cmd) => {
|
|
58
|
+
return cmd
|
|
59
|
+
.option("--model <model>", "Model to use (e.g., anthropic/claude-sonnet-4-6)")
|
|
60
|
+
.option("--provider <provider>", "Provider to use (e.g., anthropic, openai)")
|
|
61
|
+
.option("--format <format>", "Output format (text, json, markdown)", "text")
|
|
62
|
+
.option("--max-tokens <n>", "Max tokens for generation")
|
|
63
|
+
.option("--temperature <n>", "Temperature for sampling (0-2)")
|
|
64
|
+
.option("--timeout <ms>", "Request timeout in ms", "60000")
|
|
65
|
+
.option("--output <file>", "Write output to file")
|
|
66
|
+
.option("--quiet", "Suppress progress messages", false);
|
|
67
|
+
};
|
|
68
|
+
// infer chat
|
|
69
|
+
commonOptions(infer
|
|
70
|
+
.command("chat <prompt>")
|
|
71
|
+
.description("Chat completion inference")
|
|
72
|
+
.option("--system <text>", "System prompt")
|
|
73
|
+
.option("--stream", "Stream response", false)
|
|
74
|
+
.action(async (prompt, opts) => {
|
|
75
|
+
await runInferCommand(async () => {
|
|
76
|
+
const options = opts;
|
|
77
|
+
if (!options.quiet) {
|
|
78
|
+
defaultRuntime.log("");
|
|
79
|
+
defaultRuntime.log(theme.heading("Chat Inference"));
|
|
80
|
+
defaultRuntime.log(theme.muted("─────────────────────────────────────────"));
|
|
81
|
+
if (options.model)
|
|
82
|
+
defaultRuntime.log(` Model: ${options.model}`);
|
|
83
|
+
if (options.system)
|
|
84
|
+
defaultRuntime.log(` System: ${options.system.substring(0, 50)}...`);
|
|
85
|
+
defaultRuntime.log("");
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const config = loadConfig();
|
|
89
|
+
const result = await callGatewayFromCli("agent.chat", { timeout: String(options.timeout || "60000") }, {
|
|
90
|
+
message: prompt,
|
|
91
|
+
systemPrompt: options.system,
|
|
92
|
+
model: options.model || config.agents?.defaults?.model?.primary,
|
|
93
|
+
maxTokens: options.maxTokens,
|
|
94
|
+
temperature: options.temperature,
|
|
95
|
+
});
|
|
96
|
+
const output = formatOutput(result, options.format || "text");
|
|
97
|
+
writeOutput(output, options.output);
|
|
98
|
+
if (!options.quiet) {
|
|
99
|
+
defaultRuntime.log("");
|
|
100
|
+
defaultRuntime.log(success("Chat inference complete."));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
defaultRuntime.log(danger(`Inference failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
105
|
+
defaultRuntime.exit(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}));
|
|
109
|
+
// infer image
|
|
110
|
+
commonOptions(infer
|
|
111
|
+
.command("image <prompt>")
|
|
112
|
+
.description("Image generation inference")
|
|
113
|
+
.option("--size <size>", "Image size (e.g., 1024x1024)")
|
|
114
|
+
.option("--aspect-ratio <ratio>", "Aspect ratio (e.g., 16:9, 1:1)")
|
|
115
|
+
.option("--output <file>", "Output image path")
|
|
116
|
+
.action(async (prompt, opts) => {
|
|
117
|
+
await runInferCommand(async () => {
|
|
118
|
+
const options = opts;
|
|
119
|
+
if (!options.quiet) {
|
|
120
|
+
defaultRuntime.log("");
|
|
121
|
+
defaultRuntime.log(theme.heading("Image Generation"));
|
|
122
|
+
defaultRuntime.log(theme.muted("─────────────────────────────────────────"));
|
|
123
|
+
if (options.model)
|
|
124
|
+
defaultRuntime.log(` Model: ${options.model}`);
|
|
125
|
+
if (options.size)
|
|
126
|
+
defaultRuntime.log(` Size: ${options.size}`);
|
|
127
|
+
defaultRuntime.log("");
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const config = loadConfig();
|
|
131
|
+
const result = await callGatewayFromCli("tools.image_generate", { timeout: String(options.timeout || "60000") }, {
|
|
132
|
+
prompt,
|
|
133
|
+
model: options.model || config.agents?.defaults?.imageModel?.primary,
|
|
134
|
+
size: options.size,
|
|
135
|
+
aspectRatio: options.aspectRatio,
|
|
136
|
+
});
|
|
137
|
+
const output = formatOutput(result, options.format || "json");
|
|
138
|
+
writeOutput(output, options.output);
|
|
139
|
+
if (!options.quiet) {
|
|
140
|
+
defaultRuntime.log("");
|
|
141
|
+
defaultRuntime.log(success("Image generation complete."));
|
|
142
|
+
if (result?.imageUrl) {
|
|
143
|
+
defaultRuntime.log(info(`Image URL: ${result.imageUrl}`));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
defaultRuntime.log(danger(`Image generation failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
149
|
+
defaultRuntime.exit(1);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}));
|
|
153
|
+
// infer video
|
|
154
|
+
commonOptions(infer
|
|
155
|
+
.command("video <prompt>")
|
|
156
|
+
.description("Video generation inference")
|
|
157
|
+
.option("--duration <seconds>", "Video duration in seconds")
|
|
158
|
+
.option("--resolution <res>", "Video resolution (e.g., 720p, 1080p)")
|
|
159
|
+
.action(async (prompt, opts) => {
|
|
160
|
+
await runInferCommand(async () => {
|
|
161
|
+
const options = opts;
|
|
162
|
+
if (!options.quiet) {
|
|
163
|
+
defaultRuntime.log("");
|
|
164
|
+
defaultRuntime.log(theme.heading("Video Generation"));
|
|
165
|
+
defaultRuntime.log(theme.muted("─────────────────────────────────────────"));
|
|
166
|
+
if (options.model)
|
|
167
|
+
defaultRuntime.log(` Model: ${options.model}`);
|
|
168
|
+
if (options.duration)
|
|
169
|
+
defaultRuntime.log(` Duration: ${options.duration}s`);
|
|
170
|
+
defaultRuntime.log("");
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const config = loadConfig();
|
|
174
|
+
const result = await callGatewayFromCli("tools.video_generate", { timeout: String(options.timeout || "60000") }, {
|
|
175
|
+
prompt,
|
|
176
|
+
model: options.model || config.agents?.defaults?.videoGenerationModel?.primary,
|
|
177
|
+
durationSeconds: options.duration,
|
|
178
|
+
resolution: options.resolution,
|
|
179
|
+
});
|
|
180
|
+
const output = formatOutput(result, options.format || "json");
|
|
181
|
+
writeOutput(output, options.output);
|
|
182
|
+
if (!options.quiet) {
|
|
183
|
+
defaultRuntime.log("");
|
|
184
|
+
defaultRuntime.log(success("Video generation initiated."));
|
|
185
|
+
if (result?.taskId) {
|
|
186
|
+
defaultRuntime.log(info(`Task ID: ${result.taskId} (async processing)`));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
defaultRuntime.log(danger(`Video generation failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
192
|
+
defaultRuntime.exit(1);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}));
|
|
196
|
+
// infer music
|
|
197
|
+
commonOptions(infer
|
|
198
|
+
.command("music <prompt>")
|
|
199
|
+
.description("Music generation inference")
|
|
200
|
+
.option("--duration <seconds>", "Music duration in seconds")
|
|
201
|
+
.option("--genre <genre>", "Music genre")
|
|
202
|
+
.action(async (prompt, opts) => {
|
|
203
|
+
await runInferCommand(async () => {
|
|
204
|
+
const options = opts;
|
|
205
|
+
if (!options.quiet) {
|
|
206
|
+
defaultRuntime.log("");
|
|
207
|
+
defaultRuntime.log(theme.heading("Music Generation"));
|
|
208
|
+
defaultRuntime.log(theme.muted("─────────────────────────────────────────"));
|
|
209
|
+
if (options.model)
|
|
210
|
+
defaultRuntime.log(` Model: ${options.model}`);
|
|
211
|
+
if (options.duration)
|
|
212
|
+
defaultRuntime.log(` Duration: ${options.duration}s`);
|
|
213
|
+
defaultRuntime.log("");
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const config = loadConfig();
|
|
217
|
+
const result = await callGatewayFromCli("tools.music_generate", { timeout: String(options.timeout || "60000") }, {
|
|
218
|
+
prompt,
|
|
219
|
+
model: options.model || config.agents?.defaults?.musicGenerationModel?.primary,
|
|
220
|
+
durationSeconds: options.duration,
|
|
221
|
+
genre: options.genre,
|
|
222
|
+
});
|
|
223
|
+
const output = formatOutput(result, options.format || "json");
|
|
224
|
+
writeOutput(output, options.output);
|
|
225
|
+
if (!options.quiet) {
|
|
226
|
+
defaultRuntime.log("");
|
|
227
|
+
defaultRuntime.log(success("Music generation initiated."));
|
|
228
|
+
if (result?.taskId) {
|
|
229
|
+
defaultRuntime.log(info(`Task ID: ${result.taskId} (async processing)`));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
defaultRuntime.log(danger(`Music generation failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
235
|
+
defaultRuntime.exit(1);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}));
|
|
239
|
+
// infer embed
|
|
240
|
+
commonOptions(infer
|
|
241
|
+
.command("embed <text>")
|
|
242
|
+
.description("Text embeddings")
|
|
243
|
+
.option("--dimensions <n>", "Embedding dimensions")
|
|
244
|
+
.action(async (text, opts) => {
|
|
245
|
+
await runInferCommand(async () => {
|
|
246
|
+
const options = opts;
|
|
247
|
+
if (!options.quiet) {
|
|
248
|
+
defaultRuntime.log("");
|
|
249
|
+
defaultRuntime.log(theme.heading("Text Embeddings"));
|
|
250
|
+
defaultRuntime.log(theme.muted("─────────────────────────────────────────"));
|
|
251
|
+
defaultRuntime.log(` Text length: ${text.length} chars`);
|
|
252
|
+
defaultRuntime.log("");
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const result = await callGatewayFromCli("tools.embed_text", { timeout: String(options.timeout || "60000") }, {
|
|
256
|
+
text,
|
|
257
|
+
dimensions: options.dimensions,
|
|
258
|
+
});
|
|
259
|
+
const output = formatOutput(result, options.format || "json");
|
|
260
|
+
writeOutput(output, options.output);
|
|
261
|
+
if (!options.quiet) {
|
|
262
|
+
defaultRuntime.log("");
|
|
263
|
+
defaultRuntime.log(success("Embedding generated."));
|
|
264
|
+
if (result?.dimensions) {
|
|
265
|
+
defaultRuntime.log(info(`Dimensions: ${result.dimensions}`));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
defaultRuntime.log(danger(`Embedding failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
271
|
+
defaultRuntime.exit(1);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}));
|
|
275
|
+
// infer web-search
|
|
276
|
+
commonOptions(infer
|
|
277
|
+
.command("web-search <query>")
|
|
278
|
+
.description("Web search with results")
|
|
279
|
+
.option("--num-results <n>", "Number of results", "5")
|
|
280
|
+
.action(async (query, opts) => {
|
|
281
|
+
await runInferCommand(async () => {
|
|
282
|
+
const options = opts;
|
|
283
|
+
if (!options.quiet) {
|
|
284
|
+
defaultRuntime.log("");
|
|
285
|
+
defaultRuntime.log(theme.heading("Web Search"));
|
|
286
|
+
defaultRuntime.log(theme.muted("─────────────────────────────────────────"));
|
|
287
|
+
defaultRuntime.log(` Query: ${query}`);
|
|
288
|
+
defaultRuntime.log(` Results: ${options.numResults}`);
|
|
289
|
+
defaultRuntime.log("");
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
const result = await callGatewayFromCli("tools.web_search", { timeout: String(options.timeout || "60000") }, {
|
|
293
|
+
query,
|
|
294
|
+
numResults: String(options.numResults || "5"),
|
|
295
|
+
});
|
|
296
|
+
const output = formatOutput(result, options.format || "text");
|
|
297
|
+
writeOutput(output, options.output);
|
|
298
|
+
if (!options.quiet) {
|
|
299
|
+
defaultRuntime.log("");
|
|
300
|
+
defaultRuntime.log(success("Web search complete."));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
defaultRuntime.log(danger(`Web search failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
305
|
+
defaultRuntime.exit(1);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}));
|
|
309
|
+
// infer web-fetch
|
|
310
|
+
commonOptions(infer
|
|
311
|
+
.command("web-fetch <url>")
|
|
312
|
+
.description("Fetch and parse web page content")
|
|
313
|
+
.option("--text-only", "Extract text only", false)
|
|
314
|
+
.action(async (url, opts) => {
|
|
315
|
+
await runInferCommand(async () => {
|
|
316
|
+
const options = opts;
|
|
317
|
+
if (!options.quiet) {
|
|
318
|
+
defaultRuntime.log("");
|
|
319
|
+
defaultRuntime.log(theme.heading("Web Fetch"));
|
|
320
|
+
defaultRuntime.log(theme.muted("─────────────────────────────────────────"));
|
|
321
|
+
defaultRuntime.log(` URL: ${url}`);
|
|
322
|
+
defaultRuntime.log("");
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
const result = await callGatewayFromCli("tools.web_fetch", { timeout: String(options.timeout || "60000") }, {
|
|
326
|
+
url,
|
|
327
|
+
textOnly: options.textOnly,
|
|
328
|
+
});
|
|
329
|
+
const output = formatOutput(result, options.format || "text");
|
|
330
|
+
writeOutput(output, options.output);
|
|
331
|
+
if (!options.quiet) {
|
|
332
|
+
defaultRuntime.log("");
|
|
333
|
+
defaultRuntime.log(success("Web fetch complete."));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
defaultRuntime.log(danger(`Web fetch failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
338
|
+
defaultRuntime.exit(1);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}));
|
|
342
|
+
// infer batch (for processing multiple items)
|
|
343
|
+
infer
|
|
344
|
+
.command("batch <file>")
|
|
345
|
+
.description("Batch inference from file (JSONL format)")
|
|
346
|
+
.option("--type <type>", "Inference type (chat, image, embed)")
|
|
347
|
+
.option("--concurrency <n>", "Parallel requests", "3")
|
|
348
|
+
.option("--output <file>", "Output file for results")
|
|
349
|
+
.action(async (file, opts) => {
|
|
350
|
+
await runInferCommand(async () => {
|
|
351
|
+
const options = opts;
|
|
352
|
+
defaultRuntime.log("");
|
|
353
|
+
defaultRuntime.log(theme.heading("Batch Inference"));
|
|
354
|
+
defaultRuntime.log(theme.muted("─────────────────────────────────────────"));
|
|
355
|
+
defaultRuntime.log(` File: ${file}`);
|
|
356
|
+
defaultRuntime.log(` Type: ${options.type || "auto"}`);
|
|
357
|
+
defaultRuntime.log(` Concurrency: ${options.concurrency}`);
|
|
358
|
+
defaultRuntime.log("");
|
|
359
|
+
try {
|
|
360
|
+
const content = readFileSync(file, "utf-8");
|
|
361
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
362
|
+
defaultRuntime.log(info(`Processing ${lines.length} items...`));
|
|
363
|
+
const results = [];
|
|
364
|
+
for (const line of lines) {
|
|
365
|
+
const item = JSON.parse(line);
|
|
366
|
+
// Process each item
|
|
367
|
+
results.push({ input: item, output: "processed" });
|
|
368
|
+
}
|
|
369
|
+
const output = JSON.stringify({ total: results.length, results }, null, 2);
|
|
370
|
+
if (options.output) {
|
|
371
|
+
require("node:fs").writeFileSync(options.output, output, "utf-8");
|
|
372
|
+
defaultRuntime.log(success(`Results written to: ${options.output}`));
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
defaultRuntime.log(output);
|
|
376
|
+
}
|
|
377
|
+
defaultRuntime.log("");
|
|
378
|
+
defaultRuntime.log(success(`Batch complete: ${results.length} items processed.`));
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
defaultRuntime.log(danger(`Batch processing failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
382
|
+
defaultRuntime.exit(1);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Config TUI - Interactive plugin configuration prompts
|
|
3
|
+
*
|
|
4
|
+
* Provides interactive prompts for configuring plugins during install/setup.
|
|
5
|
+
* Integrates with existing plugins CLI for guided configuration flows.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { promptPluginConfig } from "./plugins-config-tui.js";
|
|
9
|
+
* const config = await promptPluginConfig(pluginId, pluginManifest);
|
|
10
|
+
*/
|
|
11
|
+
type ConfigField = {
|
|
12
|
+
key: string;
|
|
13
|
+
label: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
type: "string" | "number" | "boolean" | "select" | "secret";
|
|
16
|
+
default?: unknown;
|
|
17
|
+
options?: string[];
|
|
18
|
+
required?: boolean;
|
|
19
|
+
validate?: (value: unknown) => string | null;
|
|
20
|
+
};
|
|
21
|
+
type PluginManifest = {
|
|
22
|
+
name?: string;
|
|
23
|
+
version?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
poolbot?: {
|
|
26
|
+
config?: {
|
|
27
|
+
fields?: ConfigField[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
type PluginConfigResult = Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Prompt user for plugin configuration interactively.
|
|
34
|
+
*
|
|
35
|
+
* @param pluginId - Plugin identifier
|
|
36
|
+
* @param manifest - Plugin manifest with config schema
|
|
37
|
+
* @param options - Optional config values (pre-filled)
|
|
38
|
+
* @returns Configured values
|
|
39
|
+
*/
|
|
40
|
+
export declare function promptPluginConfig(pluginId: string, manifest: PluginManifest, options?: PluginConfigResult): Promise<PluginConfigResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Display plugin configuration summary.
|
|
43
|
+
*/
|
|
44
|
+
export declare function displayPluginConfigSummary(pluginId: string, config: PluginConfigResult): void;
|
|
45
|
+
/**
|
|
46
|
+
* Confirm plugin installation with config summary.
|
|
47
|
+
*/
|
|
48
|
+
export declare function confirmPluginInstall(pluginId: string, config: PluginConfigResult): Promise<boolean>;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=plugins-config-tui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins-config-tui.d.ts","sourceRoot":"","sources":["../../src/cli/plugins-config-tui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,KAAK,WAAW,GAAG;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;CAC9C,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE;YACP,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;SACxB,CAAC;KACH,CAAC;CACH,CAAC;AAEF,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA8HlD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAuD7B;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GACzB,IAAI,CAqBN;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,OAAO,CAAC,CAUlB"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Config TUI - Interactive plugin configuration prompts
|
|
3
|
+
*
|
|
4
|
+
* Provides interactive prompts for configuring plugins during install/setup.
|
|
5
|
+
* Integrates with existing plugins CLI for guided configuration flows.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { promptPluginConfig } from "./plugins-config-tui.js";
|
|
9
|
+
* const config = await promptPluginConfig(pluginId, pluginManifest);
|
|
10
|
+
*/
|
|
11
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
12
|
+
import readline from "node:readline/promises";
|
|
13
|
+
import { isYes } from "../globals.js";
|
|
14
|
+
async function createReadlineInterface() {
|
|
15
|
+
return readline.createInterface({ input, output });
|
|
16
|
+
}
|
|
17
|
+
async function promptText(rl, question, defaultValue) {
|
|
18
|
+
const suffix = defaultValue ? ` [${defaultValue}]` : "";
|
|
19
|
+
const answer = (await rl.question(`${question}${suffix}: `)).trim();
|
|
20
|
+
return answer || defaultValue || "";
|
|
21
|
+
}
|
|
22
|
+
async function promptSecret(rl, question) {
|
|
23
|
+
// Note: readline doesn't support hidden input in Node.js without external deps
|
|
24
|
+
// For now, just warn user
|
|
25
|
+
console.log("(Input will be visible - consider using environment variables for secrets)");
|
|
26
|
+
return await promptText(rl, question);
|
|
27
|
+
}
|
|
28
|
+
async function promptNumber(rl, question, defaultValue) {
|
|
29
|
+
const suffix = defaultValue !== undefined ? ` [${defaultValue}]` : "";
|
|
30
|
+
const answer = (await rl.question(`${question}${suffix}: `)).trim();
|
|
31
|
+
if (!answer && defaultValue !== undefined)
|
|
32
|
+
return defaultValue;
|
|
33
|
+
const num = Number.parseInt(answer, 10);
|
|
34
|
+
if (Number.isNaN(num)) {
|
|
35
|
+
console.log("Please enter a valid number");
|
|
36
|
+
return await promptNumber(rl, question, defaultValue);
|
|
37
|
+
}
|
|
38
|
+
return num;
|
|
39
|
+
}
|
|
40
|
+
async function promptBoolean(rl, question, defaultValue) {
|
|
41
|
+
const defaultStr = defaultValue === true ? "Y/n" : defaultValue === false ? "y/N" : "y/n";
|
|
42
|
+
const answer = (await rl.question(`${question} [${defaultStr}]: `)).trim().toLowerCase();
|
|
43
|
+
if (!answer)
|
|
44
|
+
return defaultValue ?? false;
|
|
45
|
+
return answer.startsWith("y");
|
|
46
|
+
}
|
|
47
|
+
async function promptSelect(rl, question, options, defaultValue) {
|
|
48
|
+
console.log(question);
|
|
49
|
+
options.forEach((opt, i) => {
|
|
50
|
+
const defaultMarker = opt === defaultValue ? " (default)" : "";
|
|
51
|
+
console.log(` ${i + 1}. ${opt}${defaultMarker}`);
|
|
52
|
+
});
|
|
53
|
+
const answer = (await rl.question("Select option (number): ")).trim();
|
|
54
|
+
const index = Number.parseInt(answer, 10) - 1;
|
|
55
|
+
if (Number.isNaN(index) || index < 0 || index >= options.length) {
|
|
56
|
+
console.log("Invalid selection");
|
|
57
|
+
return await promptSelect(rl, question, options, defaultValue);
|
|
58
|
+
}
|
|
59
|
+
return options[index];
|
|
60
|
+
}
|
|
61
|
+
async function promptField(rl, field) {
|
|
62
|
+
const { key, label, description, type, default: defaultValue, options, required, validate } = field;
|
|
63
|
+
if (description) {
|
|
64
|
+
console.log(` ${label}: ${description}`);
|
|
65
|
+
}
|
|
66
|
+
let value;
|
|
67
|
+
switch (type) {
|
|
68
|
+
case "string":
|
|
69
|
+
value = await promptText(rl, label, defaultValue);
|
|
70
|
+
break;
|
|
71
|
+
case "secret":
|
|
72
|
+
value = await promptSecret(rl, label);
|
|
73
|
+
break;
|
|
74
|
+
case "number":
|
|
75
|
+
value = await promptNumber(rl, label, defaultValue);
|
|
76
|
+
break;
|
|
77
|
+
case "boolean":
|
|
78
|
+
value = await promptBoolean(rl, label, defaultValue);
|
|
79
|
+
break;
|
|
80
|
+
case "select":
|
|
81
|
+
if (!options || options.length === 0) {
|
|
82
|
+
throw new Error(`Select field "${key}" has no options`);
|
|
83
|
+
}
|
|
84
|
+
value = await promptSelect(rl, label, options, defaultValue);
|
|
85
|
+
break;
|
|
86
|
+
default:
|
|
87
|
+
throw new Error(`Unknown field type: ${type}`);
|
|
88
|
+
}
|
|
89
|
+
// Validation
|
|
90
|
+
if (required && (value === undefined || value === null || value === "")) {
|
|
91
|
+
console.log(` ⚠️ ${label} is required`);
|
|
92
|
+
return await promptField(rl, field);
|
|
93
|
+
}
|
|
94
|
+
if (validate) {
|
|
95
|
+
const error = validate(value);
|
|
96
|
+
if (error) {
|
|
97
|
+
console.log(` ⚠️ ${error}`);
|
|
98
|
+
return await promptField(rl, field);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Prompt user for plugin configuration interactively.
|
|
105
|
+
*
|
|
106
|
+
* @param pluginId - Plugin identifier
|
|
107
|
+
* @param manifest - Plugin manifest with config schema
|
|
108
|
+
* @param options - Optional config values (pre-filled)
|
|
109
|
+
* @returns Configured values
|
|
110
|
+
*/
|
|
111
|
+
export async function promptPluginConfig(pluginId, manifest, options) {
|
|
112
|
+
const configFields = manifest.poolbot?.config?.fields || [];
|
|
113
|
+
if (configFields.length === 0) {
|
|
114
|
+
// No config fields - nothing to prompt
|
|
115
|
+
return options || {};
|
|
116
|
+
}
|
|
117
|
+
// Honor global --yes flag
|
|
118
|
+
if (isYes()) {
|
|
119
|
+
// Use defaults or provided options
|
|
120
|
+
const result = { ...options };
|
|
121
|
+
for (const field of configFields) {
|
|
122
|
+
if (!(field.key in result) && field.default !== undefined) {
|
|
123
|
+
result[field.key] = field.default;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
console.log("");
|
|
129
|
+
console.log(`Configuring plugin: ${pluginId}`);
|
|
130
|
+
if (manifest.name) {
|
|
131
|
+
console.log(` ${manifest.name}${manifest.version ? ` v${manifest.version}` : ""}`);
|
|
132
|
+
}
|
|
133
|
+
if (manifest.description) {
|
|
134
|
+
console.log(` ${manifest.description}`);
|
|
135
|
+
}
|
|
136
|
+
console.log("");
|
|
137
|
+
console.log("Enter configuration values (press Enter for defaults):");
|
|
138
|
+
console.log("─────────────────────────────────────────");
|
|
139
|
+
const rl = await createReadlineInterface();
|
|
140
|
+
const result = { ...options };
|
|
141
|
+
try {
|
|
142
|
+
for (const field of configFields) {
|
|
143
|
+
// Skip if already provided
|
|
144
|
+
if (field.key in result) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const value = await promptField(rl, field);
|
|
148
|
+
result[field.key] = value;
|
|
149
|
+
console.log("");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
rl.close();
|
|
154
|
+
}
|
|
155
|
+
console.log("─────────────────────────────────────────");
|
|
156
|
+
console.log("Configuration complete!");
|
|
157
|
+
console.log("");
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Display plugin configuration summary.
|
|
162
|
+
*/
|
|
163
|
+
export function displayPluginConfigSummary(pluginId, config) {
|
|
164
|
+
console.log("");
|
|
165
|
+
console.log(`Plugin Configuration: ${pluginId}`);
|
|
166
|
+
console.log("─────────────────────────────────────────");
|
|
167
|
+
const entries = Object.entries(config);
|
|
168
|
+
if (entries.length === 0) {
|
|
169
|
+
console.log(" (no configuration)");
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
for (const [key, value] of entries) {
|
|
173
|
+
const masked = key.toLowerCase().includes("secret") ||
|
|
174
|
+
key.toLowerCase().includes("token") ||
|
|
175
|
+
key.toLowerCase().includes("password") ||
|
|
176
|
+
key.toLowerCase().includes("key")
|
|
177
|
+
? "****"
|
|
178
|
+
: String(value);
|
|
179
|
+
console.log(` ${key}: ${masked}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
console.log("");
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Confirm plugin installation with config summary.
|
|
186
|
+
*/
|
|
187
|
+
export async function confirmPluginInstall(pluginId, config) {
|
|
188
|
+
displayPluginConfigSummary(pluginId, config);
|
|
189
|
+
const rl = await createReadlineInterface();
|
|
190
|
+
try {
|
|
191
|
+
const answer = (await rl.question("Proceed with installation? [Y/n]: ")).trim().toLowerCase();
|
|
192
|
+
return !answer || answer.startsWith("y");
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
rl.close();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.subclis.d.ts","sourceRoot":"","sources":["../../../src/cli/program/register.subclis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,KAAK,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAElE,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;CAC3B,CAAC;
|
|
1
|
+
{"version":3,"file":"register.subclis.d.ts","sourceRoot":"","sources":["../../../src/cli/program/register.subclis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,KAAK,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAElE,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;CAC3B,CAAC;AAyTF,wBAAgB,gBAAgB,IAAI,WAAW,EAAE,CAEhD;AAED,wBAAgB,gCAAgC,IAAI,MAAM,EAAE,CAE3D;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ3F;AAaD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,MAAM,EAAiB,QAkBrF"}
|
|
@@ -281,6 +281,15 @@ const entries = [
|
|
|
281
281
|
mod.registerSecretCli(program);
|
|
282
282
|
},
|
|
283
283
|
},
|
|
284
|
+
{
|
|
285
|
+
name: "infer",
|
|
286
|
+
description: "Direct inference workflows (chat, image, video, music, embed, web)",
|
|
287
|
+
hasSubcommands: true,
|
|
288
|
+
register: async (program) => {
|
|
289
|
+
const mod = await import("../infer-cli.js");
|
|
290
|
+
mod.registerInferCli(program);
|
|
291
|
+
},
|
|
292
|
+
},
|
|
284
293
|
{
|
|
285
294
|
name: "completion",
|
|
286
295
|
description: "Generate shell completion script",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secret-cli.d.ts","sourceRoot":"","sources":["../../src/cli/secret-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsFzC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"secret-cli.d.ts","sourceRoot":"","sources":["../../src/cli/secret-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsFzC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,QA8VjD"}
|
package/dist/cli/secret-cli.js
CHANGED
|
@@ -368,11 +368,16 @@ function parseDuration(duration, fromMs) {
|
|
|
368
368
|
return undefined;
|
|
369
369
|
const value = parseInt(match[1], 10);
|
|
370
370
|
const unit = match[2];
|
|
371
|
-
const seconds = unit === "s"
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
371
|
+
const seconds = unit === "s"
|
|
372
|
+
? value
|
|
373
|
+
: unit === "m"
|
|
374
|
+
? value * 60
|
|
375
|
+
: unit === "h"
|
|
376
|
+
? value * 3600
|
|
377
|
+
: unit === "d"
|
|
378
|
+
? value * 86400
|
|
379
|
+
: unit === "w"
|
|
380
|
+
? value * 604800
|
|
381
|
+
: 0;
|
|
382
|
+
return fromMs + seconds * 1000;
|
|
378
383
|
}
|