mthds 0.2.0 → 0.2.1
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/agent/commands/api-commands.d.ts +13 -0
- package/dist/agent/commands/api-commands.js +494 -0
- package/dist/agent/commands/api-commands.js.map +1 -0
- package/dist/agent/commands/pipelex-commands.d.ts +13 -0
- package/dist/agent/commands/pipelex-commands.js +63 -0
- package/dist/agent/commands/pipelex-commands.js.map +1 -0
- package/dist/agent/commands/pipelex-passthrough.d.ts +15 -0
- package/dist/agent/commands/pipelex-passthrough.js +43 -0
- package/dist/agent/commands/pipelex-passthrough.js.map +1 -0
- package/dist/agent-cli.d.ts +8 -2
- package/dist/agent-cli.js +85 -113
- package/dist/agent-cli.js.map +1 -1
- package/dist/runners/api-runner.d.ts +2 -2
- package/dist/runners/api-runner.js +2 -2
- package/dist/runners/api-runner.js.map +1 -1
- package/dist/runners/pipelex-runner.d.ts +2 -2
- package/dist/runners/pipelex-runner.js +11 -37
- package/dist/runners/pipelex-runner.js.map +1 -1
- package/dist/runners/types.d.ts +10 -12
- package/package.json +1 -1
- package/dist/agent/commands/build.d.ts +0 -32
- package/dist/agent/commands/build.js +0 -291
- package/dist/agent/commands/build.js.map +0 -1
- package/dist/agent/commands/runner-commands.d.ts +0 -20
- package/dist/agent/commands/runner-commands.js +0 -800
- package/dist/agent/commands/runner-commands.js.map +0 -1
|
@@ -1,800 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runner-aware commands — registered at the top level.
|
|
3
|
-
*
|
|
4
|
-
* mthds-agent [--runner <type>] <cmd> [args...]
|
|
5
|
-
*
|
|
6
|
-
* Runner resolution: --runner flag → default runner from config.
|
|
7
|
-
* For pipelex runner: run and validate use passthrough for full CLI compatibility.
|
|
8
|
-
* For all runners: concept, pipe, assemble, inputs, models use the Runner interface.
|
|
9
|
-
*/
|
|
10
|
-
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
11
|
-
import { join } from "node:path";
|
|
12
|
-
import { agentError, agentSuccess, AGENT_ERROR_DOMAINS } from "../output.js";
|
|
13
|
-
import { createRunner } from "../../runners/registry.js";
|
|
14
|
-
import { isPipelexRunner } from "../../cli/commands/utils.js";
|
|
15
|
-
function collect(val, prev) {
|
|
16
|
-
return [...prev, val];
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Try to read `value` as a file path; if the file does not exist (ENOENT),
|
|
20
|
-
* treat `value` as inline content and return it as-is.
|
|
21
|
-
*/
|
|
22
|
-
export function resolveFileOrInline(value) {
|
|
23
|
-
try {
|
|
24
|
-
return readFileSync(value, "utf-8");
|
|
25
|
-
}
|
|
26
|
-
catch (err) {
|
|
27
|
-
if (err.code === "ENOENT") {
|
|
28
|
-
return value;
|
|
29
|
-
}
|
|
30
|
-
throw err;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/** Extract raw args after a command keyword, filtering out global options */
|
|
34
|
-
function extractPassthroughArgs(keyword) {
|
|
35
|
-
const argv = process.argv;
|
|
36
|
-
const idx = argv.indexOf(keyword);
|
|
37
|
-
if (idx === -1)
|
|
38
|
-
return [];
|
|
39
|
-
const raw = argv.slice(idx + 1);
|
|
40
|
-
const result = [];
|
|
41
|
-
let i = 0;
|
|
42
|
-
while (i < raw.length) {
|
|
43
|
-
if (raw[i] === "--runner" ||
|
|
44
|
-
raw[i] === "-L" ||
|
|
45
|
-
raw[i] === "--library-dir" ||
|
|
46
|
-
raw[i] === "--log-level") {
|
|
47
|
-
i += 2;
|
|
48
|
-
}
|
|
49
|
-
else if (raw[i].startsWith("--runner=") ||
|
|
50
|
-
raw[i].startsWith("--library-dir=") ||
|
|
51
|
-
raw[i].startsWith("--log-level=")) {
|
|
52
|
-
i += 1;
|
|
53
|
-
}
|
|
54
|
-
else if (raw[i] === "--auto-install") {
|
|
55
|
-
i += 1;
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
result.push(raw[i]);
|
|
59
|
-
i++;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return result;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Register all runner-aware commands directly on the program.
|
|
66
|
-
* Uses --runner flag or default runner from config.
|
|
67
|
-
*/
|
|
68
|
-
export function registerRunnerCommands(program, logLevelArgs, _autoInstall) {
|
|
69
|
-
const getLibraryDirs = () => (program.optsWithGlobals().libraryDir ?? []);
|
|
70
|
-
function makeRunner() {
|
|
71
|
-
const runnerType = program.optsWithGlobals().runner;
|
|
72
|
-
const libraryDirs = getLibraryDirs();
|
|
73
|
-
return createRunner(runnerType, libraryDirs.length ? libraryDirs : undefined);
|
|
74
|
-
}
|
|
75
|
-
// ── concept ──
|
|
76
|
-
program
|
|
77
|
-
.command("concept")
|
|
78
|
-
.description("Structure a concept from JSON spec and output TOML")
|
|
79
|
-
.option("--spec <json>", "JSON string with concept specification")
|
|
80
|
-
.option("--spec-file <path>", "Path to JSON file with concept specification")
|
|
81
|
-
.allowUnknownOption()
|
|
82
|
-
.allowExcessArguments(true)
|
|
83
|
-
.exitOverride()
|
|
84
|
-
.action(async (options) => {
|
|
85
|
-
let runner;
|
|
86
|
-
try {
|
|
87
|
-
runner = makeRunner();
|
|
88
|
-
}
|
|
89
|
-
catch (err) {
|
|
90
|
-
agentError(err.message, "RunnerError", {
|
|
91
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
let specStr = options.spec;
|
|
95
|
-
if (!specStr && options.specFile) {
|
|
96
|
-
try {
|
|
97
|
-
specStr = readFileSync(options.specFile, "utf-8");
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
agentError(`Cannot read spec file: ${err.message}`, "IOError", {
|
|
101
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
if (!specStr) {
|
|
106
|
-
agentError("--spec or --spec-file is required.", "ArgumentError", {
|
|
107
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
let spec;
|
|
111
|
-
try {
|
|
112
|
-
spec = JSON.parse(specStr);
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
agentError("--spec must be valid JSON.", "ArgumentError", {
|
|
116
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
try {
|
|
120
|
-
const result = await runner.concept({ spec });
|
|
121
|
-
agentSuccess({ ...result });
|
|
122
|
-
}
|
|
123
|
-
catch (err) {
|
|
124
|
-
agentError(err.message, "RunnerError", {
|
|
125
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
// ── pipe ──
|
|
130
|
-
program
|
|
131
|
-
.command("pipe")
|
|
132
|
-
.description("Structure a pipe from JSON spec and output TOML")
|
|
133
|
-
.option("--type <type>", "Pipe type (PipeLLM, PipeSequence, etc.)")
|
|
134
|
-
.option("--spec <json>", "JSON string with pipe specification")
|
|
135
|
-
.option("--spec-file <path>", "Path to JSON file with pipe specification")
|
|
136
|
-
.allowUnknownOption()
|
|
137
|
-
.allowExcessArguments(true)
|
|
138
|
-
.exitOverride()
|
|
139
|
-
.action(async (options) => {
|
|
140
|
-
let runner;
|
|
141
|
-
try {
|
|
142
|
-
runner = makeRunner();
|
|
143
|
-
}
|
|
144
|
-
catch (err) {
|
|
145
|
-
agentError(err.message, "RunnerError", {
|
|
146
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
if (!options.type) {
|
|
150
|
-
agentError("--type is required.", "ArgumentError", {
|
|
151
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
let specStr = options.spec;
|
|
155
|
-
if (!specStr && options.specFile) {
|
|
156
|
-
try {
|
|
157
|
-
specStr = readFileSync(options.specFile, "utf-8");
|
|
158
|
-
}
|
|
159
|
-
catch (err) {
|
|
160
|
-
agentError(`Cannot read spec file: ${err.message}`, "IOError", {
|
|
161
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (!specStr) {
|
|
166
|
-
agentError("--spec or --spec-file is required.", "ArgumentError", {
|
|
167
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
let spec;
|
|
171
|
-
try {
|
|
172
|
-
spec = JSON.parse(specStr);
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
agentError("--spec must be valid JSON.", "ArgumentError", {
|
|
176
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
try {
|
|
180
|
-
const result = await runner.pipeSpec({ pipe_type: options.type, spec });
|
|
181
|
-
agentSuccess({ ...result });
|
|
182
|
-
}
|
|
183
|
-
catch (err) {
|
|
184
|
-
agentError(err.message, "RunnerError", {
|
|
185
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
// ── assemble ──
|
|
190
|
-
program
|
|
191
|
-
.command("assemble")
|
|
192
|
-
.description("Assemble a complete .mthds bundle from TOML parts")
|
|
193
|
-
.requiredOption("--domain <domain>", "Domain code for the bundle")
|
|
194
|
-
.requiredOption("--main-pipe <pipe>", "Main pipe code for the bundle")
|
|
195
|
-
.option("--description <desc>", "Description of the bundle")
|
|
196
|
-
.option("--system-prompt <prompt>", "Default system prompt for LLM pipes")
|
|
197
|
-
.option("--concepts <toml>", "TOML for concepts (repeatable)", collect, [])
|
|
198
|
-
.option("--pipes <toml>", "TOML for pipes (repeatable)", collect, [])
|
|
199
|
-
.allowUnknownOption()
|
|
200
|
-
.allowExcessArguments(true)
|
|
201
|
-
.exitOverride()
|
|
202
|
-
.action(async (options) => {
|
|
203
|
-
let runner;
|
|
204
|
-
try {
|
|
205
|
-
runner = makeRunner();
|
|
206
|
-
}
|
|
207
|
-
catch (err) {
|
|
208
|
-
agentError(err.message, "RunnerError", {
|
|
209
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
// Read file contents for concepts/pipes so both runners get TOML content
|
|
213
|
-
let concepts;
|
|
214
|
-
if (options.concepts?.length) {
|
|
215
|
-
try {
|
|
216
|
-
concepts = options.concepts.map(resolveFileOrInline);
|
|
217
|
-
}
|
|
218
|
-
catch (err) {
|
|
219
|
-
agentError(`Failed to read concept file: ${err.message}`, "FileError", {
|
|
220
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
221
|
-
});
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
let pipes;
|
|
226
|
-
if (options.pipes?.length) {
|
|
227
|
-
try {
|
|
228
|
-
pipes = options.pipes.map(resolveFileOrInline);
|
|
229
|
-
}
|
|
230
|
-
catch (err) {
|
|
231
|
-
agentError(`Failed to read pipe file: ${err.message}`, "FileError", {
|
|
232
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
233
|
-
});
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
const request = {
|
|
238
|
-
domain: options.domain,
|
|
239
|
-
main_pipe: options.mainPipe,
|
|
240
|
-
description: options.description,
|
|
241
|
-
system_prompt: options.systemPrompt,
|
|
242
|
-
concepts,
|
|
243
|
-
pipes,
|
|
244
|
-
};
|
|
245
|
-
try {
|
|
246
|
-
const result = await runner.assemble(request);
|
|
247
|
-
agentSuccess({ ...result });
|
|
248
|
-
}
|
|
249
|
-
catch (err) {
|
|
250
|
-
agentError(err.message, "RunnerError", {
|
|
251
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
// ── validate ──
|
|
256
|
-
const validateGroup = program
|
|
257
|
-
.command("validate")
|
|
258
|
-
.description("Validate a method, pipe, or bundle")
|
|
259
|
-
.passThroughOptions()
|
|
260
|
-
.allowUnknownOption();
|
|
261
|
-
validateGroup
|
|
262
|
-
.command("bundle")
|
|
263
|
-
.argument("[target]", "Bundle file (.mthds) or directory")
|
|
264
|
-
.option("--pipe <code>", "Pipe code to validate within the bundle")
|
|
265
|
-
.option("--content <mthds>", "Bundle content as a string (alternative to file path)")
|
|
266
|
-
.description("Validate a bundle file or content")
|
|
267
|
-
.allowUnknownOption()
|
|
268
|
-
.allowExcessArguments(true)
|
|
269
|
-
.exitOverride()
|
|
270
|
-
.action(async (target, options) => {
|
|
271
|
-
let runner;
|
|
272
|
-
try {
|
|
273
|
-
runner = makeRunner();
|
|
274
|
-
}
|
|
275
|
-
catch (err) {
|
|
276
|
-
agentError(err.message, "RunnerError", {
|
|
277
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
// Passthrough for pipelex runner (forwards all CLI flags like --graph)
|
|
281
|
-
if (isPipelexRunner(runner)) {
|
|
282
|
-
try {
|
|
283
|
-
await runner.validatePassthrough([...logLevelArgs(), ...extractPassthroughArgs("validate")]);
|
|
284
|
-
}
|
|
285
|
-
catch (err) {
|
|
286
|
-
agentError(err.message, "ValidationError", {
|
|
287
|
-
error_domain: AGENT_ERROR_DOMAINS.VALIDATION,
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
let mthdsContent;
|
|
293
|
-
if (options.content) {
|
|
294
|
-
mthdsContent = options.content;
|
|
295
|
-
}
|
|
296
|
-
else if (target) {
|
|
297
|
-
try {
|
|
298
|
-
mthdsContent = readFileSync(target, "utf-8");
|
|
299
|
-
}
|
|
300
|
-
catch (err) {
|
|
301
|
-
agentError(`Cannot read bundle: ${err.message}`, "IOError", {
|
|
302
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
else {
|
|
307
|
-
agentError("Either <target> or --content is required.", "ArgumentError", {
|
|
308
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
try {
|
|
312
|
-
const result = await runner.validate({
|
|
313
|
-
mthds_contents: [mthdsContent],
|
|
314
|
-
pipe_code: options.pipe,
|
|
315
|
-
});
|
|
316
|
-
if (result.success) {
|
|
317
|
-
agentSuccess({ ...result });
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
agentError(result.message, "ValidationError", {
|
|
321
|
-
error_domain: AGENT_ERROR_DOMAINS.VALIDATION,
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
catch (err) {
|
|
326
|
-
agentError(err.message, "RunnerError", {
|
|
327
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
validateGroup
|
|
332
|
-
.command("pipe")
|
|
333
|
-
.argument("<target>", "Pipe code or .mthds bundle file")
|
|
334
|
-
.option("--pipe <code>", "Pipe code to validate")
|
|
335
|
-
.option("--bundle <file>", "Bundle file path (alternative to positional)")
|
|
336
|
-
.description("Validate a pipe by code or bundle file")
|
|
337
|
-
.allowUnknownOption()
|
|
338
|
-
.allowExcessArguments(true)
|
|
339
|
-
.exitOverride()
|
|
340
|
-
.action(async (target, options) => {
|
|
341
|
-
let runner;
|
|
342
|
-
try {
|
|
343
|
-
runner = makeRunner();
|
|
344
|
-
}
|
|
345
|
-
catch (err) {
|
|
346
|
-
agentError(err.message, "RunnerError", {
|
|
347
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
// Passthrough for pipelex runner
|
|
351
|
-
if (isPipelexRunner(runner)) {
|
|
352
|
-
try {
|
|
353
|
-
await runner.validatePassthrough([...logLevelArgs(), ...extractPassthroughArgs("validate")]);
|
|
354
|
-
}
|
|
355
|
-
catch (err) {
|
|
356
|
-
agentError(err.message, "ValidationError", {
|
|
357
|
-
error_domain: AGENT_ERROR_DOMAINS.VALIDATION,
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
if (target.endsWith(".mthds")) {
|
|
363
|
-
let mthdsContent;
|
|
364
|
-
try {
|
|
365
|
-
mthdsContent = readFileSync(target, "utf-8");
|
|
366
|
-
}
|
|
367
|
-
catch (err) {
|
|
368
|
-
agentError(`Cannot read bundle: ${err.message}`, "IOError", {
|
|
369
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
try {
|
|
373
|
-
const result = await runner.validate({
|
|
374
|
-
mthds_contents: [mthdsContent],
|
|
375
|
-
pipe_code: options.pipe,
|
|
376
|
-
});
|
|
377
|
-
if (result.success) {
|
|
378
|
-
agentSuccess({ ...result });
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
agentError(result.message, "ValidationError", {
|
|
382
|
-
error_domain: AGENT_ERROR_DOMAINS.VALIDATION,
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
catch (err) {
|
|
387
|
-
agentError(err.message, "RunnerError", {
|
|
388
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
try {
|
|
394
|
-
const result = await runner.validate({ pipe_code: target });
|
|
395
|
-
if (result.success) {
|
|
396
|
-
agentSuccess({ ...result });
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
agentError(result.message, "ValidationError", {
|
|
400
|
-
error_domain: AGENT_ERROR_DOMAINS.VALIDATION,
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
catch (err) {
|
|
405
|
-
agentError(err.message, "RunnerError", {
|
|
406
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
validateGroup
|
|
412
|
-
.command("method")
|
|
413
|
-
.argument("<target>", "Method name, GitHub URL, or local path")
|
|
414
|
-
.option("--pipe <code>", "Pipe code to validate")
|
|
415
|
-
.description("Validate a method")
|
|
416
|
-
.allowUnknownOption()
|
|
417
|
-
.allowExcessArguments(true)
|
|
418
|
-
.exitOverride()
|
|
419
|
-
.action(async (target, options) => {
|
|
420
|
-
let runner;
|
|
421
|
-
try {
|
|
422
|
-
runner = makeRunner();
|
|
423
|
-
}
|
|
424
|
-
catch (err) {
|
|
425
|
-
agentError(err.message, "RunnerError", {
|
|
426
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
// Passthrough for pipelex runner
|
|
430
|
-
if (isPipelexRunner(runner)) {
|
|
431
|
-
try {
|
|
432
|
-
await runner.validatePassthrough([...logLevelArgs(), ...extractPassthroughArgs("validate")]);
|
|
433
|
-
}
|
|
434
|
-
catch (err) {
|
|
435
|
-
agentError(err.message, "ValidationError", {
|
|
436
|
-
error_domain: AGENT_ERROR_DOMAINS.VALIDATION,
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
try {
|
|
442
|
-
const result = await runner.validate({
|
|
443
|
-
method_url: target,
|
|
444
|
-
pipe_code: options.pipe,
|
|
445
|
-
});
|
|
446
|
-
if (result.success) {
|
|
447
|
-
agentSuccess({ ...result });
|
|
448
|
-
}
|
|
449
|
-
else {
|
|
450
|
-
agentError(result.message, "ValidationError", {
|
|
451
|
-
error_domain: AGENT_ERROR_DOMAINS.VALIDATION,
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
catch (err) {
|
|
456
|
-
agentError(err.message, "RunnerError", {
|
|
457
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
});
|
|
461
|
-
// ── inputs ──
|
|
462
|
-
const inputsGroup = program
|
|
463
|
-
.command("inputs")
|
|
464
|
-
.description("Generate example input JSON for a pipe")
|
|
465
|
-
.passThroughOptions()
|
|
466
|
-
.allowUnknownOption();
|
|
467
|
-
inputsGroup
|
|
468
|
-
.command("bundle")
|
|
469
|
-
.argument("[target]", "Bundle file (.mthds) or directory")
|
|
470
|
-
.option("--pipe <code>", "Pipe code to generate inputs for")
|
|
471
|
-
.option("--content <mthds>", "Bundle content as a string (alternative to file path)")
|
|
472
|
-
.description("Generate inputs from a bundle file or content")
|
|
473
|
-
.allowUnknownOption()
|
|
474
|
-
.allowExcessArguments(true)
|
|
475
|
-
.exitOverride()
|
|
476
|
-
.action(async (target, options) => {
|
|
477
|
-
let runner;
|
|
478
|
-
try {
|
|
479
|
-
runner = makeRunner();
|
|
480
|
-
}
|
|
481
|
-
catch (err) {
|
|
482
|
-
agentError(err.message, "RunnerError", {
|
|
483
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
let mthdsContent;
|
|
487
|
-
if (options.content) {
|
|
488
|
-
mthdsContent = options.content;
|
|
489
|
-
}
|
|
490
|
-
else if (target) {
|
|
491
|
-
try {
|
|
492
|
-
mthdsContent = readFileSync(target, "utf-8");
|
|
493
|
-
}
|
|
494
|
-
catch (err) {
|
|
495
|
-
agentError(`Cannot read bundle: ${err.message}`, "IOError", {
|
|
496
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
else {
|
|
501
|
-
agentError("Either <target> or --content is required.", "ArgumentError", {
|
|
502
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
let pipeCode = options.pipe;
|
|
506
|
-
if (!pipeCode) {
|
|
507
|
-
const match = mthdsContent.match(/^main_pipe\s*=\s*"([^"]+)"/m);
|
|
508
|
-
if (match)
|
|
509
|
-
pipeCode = match[1];
|
|
510
|
-
}
|
|
511
|
-
if (!pipeCode) {
|
|
512
|
-
agentError("Could not determine pipe code. Use --pipe to specify it.", "ArgumentError", {
|
|
513
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
try {
|
|
517
|
-
const result = await runner.buildInputs({
|
|
518
|
-
mthds_contents: [mthdsContent],
|
|
519
|
-
pipe_code: pipeCode,
|
|
520
|
-
});
|
|
521
|
-
agentSuccess({ success: true, pipe_code: pipeCode, inputs: result });
|
|
522
|
-
}
|
|
523
|
-
catch (err) {
|
|
524
|
-
agentError(err.message, "RunnerError", {
|
|
525
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
inputsGroup
|
|
530
|
-
.command("pipe")
|
|
531
|
-
.argument("<target>", "Bundle file (.mthds) or pipe code")
|
|
532
|
-
.option("--pipe <code>", "Pipe code to generate inputs for")
|
|
533
|
-
.description("Generate inputs for a pipe")
|
|
534
|
-
.allowUnknownOption()
|
|
535
|
-
.allowExcessArguments(true)
|
|
536
|
-
.exitOverride()
|
|
537
|
-
.action(async (target, options) => {
|
|
538
|
-
let runner;
|
|
539
|
-
try {
|
|
540
|
-
runner = makeRunner();
|
|
541
|
-
}
|
|
542
|
-
catch (err) {
|
|
543
|
-
agentError(err.message, "RunnerError", {
|
|
544
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
if (target.endsWith(".mthds")) {
|
|
548
|
-
let mthdsContent;
|
|
549
|
-
try {
|
|
550
|
-
mthdsContent = readFileSync(target, "utf-8");
|
|
551
|
-
}
|
|
552
|
-
catch (err) {
|
|
553
|
-
agentError(`Cannot read bundle: ${err.message}`, "IOError", {
|
|
554
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
let pipeCode = options.pipe;
|
|
558
|
-
if (!pipeCode) {
|
|
559
|
-
const match = mthdsContent.match(/^main_pipe\s*=\s*"([^"]+)"/m);
|
|
560
|
-
if (match)
|
|
561
|
-
pipeCode = match[1];
|
|
562
|
-
}
|
|
563
|
-
if (!pipeCode) {
|
|
564
|
-
agentError("Could not determine pipe code. Use --pipe to specify it.", "ArgumentError", {
|
|
565
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
try {
|
|
569
|
-
const result = await runner.buildInputs({
|
|
570
|
-
mthds_contents: [mthdsContent],
|
|
571
|
-
pipe_code: pipeCode,
|
|
572
|
-
});
|
|
573
|
-
agentSuccess({ success: true, pipe_code: pipeCode, inputs: result });
|
|
574
|
-
}
|
|
575
|
-
catch (err) {
|
|
576
|
-
agentError(err.message, "RunnerError", {
|
|
577
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
else {
|
|
582
|
-
agentError("Pipe code without a bundle file is not supported yet. Provide a .mthds file.", "ArgumentError", { error_domain: AGENT_ERROR_DOMAINS.ARGUMENT });
|
|
583
|
-
}
|
|
584
|
-
});
|
|
585
|
-
inputsGroup
|
|
586
|
-
.command("method")
|
|
587
|
-
.argument("<name>", "Method name")
|
|
588
|
-
.option("--pipe <code>", "Pipe code to generate inputs for")
|
|
589
|
-
.description("Generate inputs for an installed method")
|
|
590
|
-
.allowUnknownOption()
|
|
591
|
-
.allowExcessArguments(true)
|
|
592
|
-
.exitOverride()
|
|
593
|
-
.action(async () => {
|
|
594
|
-
agentError("'inputs method' is not yet supported via the runner interface.", "UnsupportedError", { error_domain: AGENT_ERROR_DOMAINS.RUNNER });
|
|
595
|
-
});
|
|
596
|
-
// ── run ──
|
|
597
|
-
const runGroup = program
|
|
598
|
-
.command("run")
|
|
599
|
-
.description("Execute a pipeline")
|
|
600
|
-
.passThroughOptions()
|
|
601
|
-
.allowUnknownOption();
|
|
602
|
-
runGroup
|
|
603
|
-
.command("method")
|
|
604
|
-
.argument("<name>", "Name of the installed method")
|
|
605
|
-
.option("--pipe <code>", "Pipe code (overrides method's main_pipe)")
|
|
606
|
-
.option("-i, --inputs <file>", "Path to JSON inputs file")
|
|
607
|
-
.description("Run an installed method by name")
|
|
608
|
-
.allowUnknownOption()
|
|
609
|
-
.allowExcessArguments(true)
|
|
610
|
-
.exitOverride()
|
|
611
|
-
.action(async () => {
|
|
612
|
-
let runner;
|
|
613
|
-
try {
|
|
614
|
-
runner = makeRunner();
|
|
615
|
-
}
|
|
616
|
-
catch (err) {
|
|
617
|
-
agentError(err.message, "RunnerError", {
|
|
618
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
// Passthrough for pipelex runner
|
|
622
|
-
if (isPipelexRunner(runner)) {
|
|
623
|
-
try {
|
|
624
|
-
await runner.runPassthrough([...logLevelArgs(), ...extractPassthroughArgs("run")]);
|
|
625
|
-
}
|
|
626
|
-
catch (err) {
|
|
627
|
-
agentError(err.message, "RunError", {
|
|
628
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
return;
|
|
632
|
-
}
|
|
633
|
-
agentError("Method target is not yet supported for the API runner. Use 'mthds-agent run pipe <target>' instead, or specify a different runner with --runner <name>.", "ArgumentError", { error_domain: AGENT_ERROR_DOMAINS.ARGUMENT });
|
|
634
|
-
});
|
|
635
|
-
/** Shared execution logic for run pipe / run bundle */
|
|
636
|
-
async function executeViaRunner(runner, target, options) {
|
|
637
|
-
let mthdsContent;
|
|
638
|
-
if (options.content) {
|
|
639
|
-
mthdsContent = options.content;
|
|
640
|
-
}
|
|
641
|
-
else if (target) {
|
|
642
|
-
// Resolve target: if directory, look for bundle.mthds inside
|
|
643
|
-
let bundlePath = target;
|
|
644
|
-
if (existsSync(target) && statSync(target).isDirectory()) {
|
|
645
|
-
const candidate = join(target, "bundle.mthds");
|
|
646
|
-
if (existsSync(candidate)) {
|
|
647
|
-
bundlePath = candidate;
|
|
648
|
-
}
|
|
649
|
-
else {
|
|
650
|
-
agentError(`No bundle.mthds found in directory: ${target}`, "IOError", {
|
|
651
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
// Also check for inputs.json in directory if not specified
|
|
655
|
-
if (!options.inputs && !options.inputsJson) {
|
|
656
|
-
const inputsCandidate = join(target, "inputs.json");
|
|
657
|
-
if (existsSync(inputsCandidate)) {
|
|
658
|
-
options.inputs = inputsCandidate;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
try {
|
|
663
|
-
mthdsContent = readFileSync(bundlePath, "utf-8");
|
|
664
|
-
}
|
|
665
|
-
catch (err) {
|
|
666
|
-
agentError(`Cannot read bundle: ${err.message}`, "IOError", {
|
|
667
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
agentError("Either <target> or --content is required.", "ArgumentError", {
|
|
673
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
let pipeCode = options.pipe;
|
|
677
|
-
if (!pipeCode) {
|
|
678
|
-
const match = mthdsContent.match(/^main_pipe\s*=\s*"([^"]+)"/m);
|
|
679
|
-
if (match)
|
|
680
|
-
pipeCode = match[1];
|
|
681
|
-
}
|
|
682
|
-
let inputs;
|
|
683
|
-
if (options.inputsJson) {
|
|
684
|
-
try {
|
|
685
|
-
inputs = JSON.parse(options.inputsJson);
|
|
686
|
-
}
|
|
687
|
-
catch {
|
|
688
|
-
agentError("--inputs-json must be valid JSON.", "ArgumentError", {
|
|
689
|
-
error_domain: AGENT_ERROR_DOMAINS.ARGUMENT,
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
else if (options.inputs) {
|
|
694
|
-
try {
|
|
695
|
-
inputs = JSON.parse(readFileSync(options.inputs, "utf-8"));
|
|
696
|
-
}
|
|
697
|
-
catch (err) {
|
|
698
|
-
agentError(`Cannot read inputs: ${err.message}`, "IOError", {
|
|
699
|
-
error_domain: AGENT_ERROR_DOMAINS.IO,
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
try {
|
|
704
|
-
const result = await runner.execute({
|
|
705
|
-
mthds_contents: [mthdsContent],
|
|
706
|
-
pipe_code: pipeCode,
|
|
707
|
-
inputs,
|
|
708
|
-
});
|
|
709
|
-
agentSuccess({ ...result });
|
|
710
|
-
}
|
|
711
|
-
catch (err) {
|
|
712
|
-
agentError(err.message, "RunnerError", {
|
|
713
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
/** Shared runner dispatch for run pipe / run bundle */
|
|
718
|
-
async function runAction(target, options) {
|
|
719
|
-
let runner;
|
|
720
|
-
try {
|
|
721
|
-
runner = makeRunner();
|
|
722
|
-
}
|
|
723
|
-
catch (err) {
|
|
724
|
-
agentError(err.message, "RunnerError", {
|
|
725
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
726
|
-
});
|
|
727
|
-
}
|
|
728
|
-
// Passthrough for pipelex runner (forwards all CLI flags like --dry-run, --output-dir, etc.)
|
|
729
|
-
if (isPipelexRunner(runner)) {
|
|
730
|
-
try {
|
|
731
|
-
await runner.runPassthrough([...logLevelArgs(), ...extractPassthroughArgs("run")]);
|
|
732
|
-
}
|
|
733
|
-
catch (err) {
|
|
734
|
-
agentError(err.message, "RunError", {
|
|
735
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
736
|
-
});
|
|
737
|
-
}
|
|
738
|
-
return;
|
|
739
|
-
}
|
|
740
|
-
await executeViaRunner(runner, target, options);
|
|
741
|
-
}
|
|
742
|
-
// run pipe [target] [--pipe <code>] [-i <inputs>] [--content <mthds>] [--inputs-json <json>]
|
|
743
|
-
runGroup
|
|
744
|
-
.command("pipe")
|
|
745
|
-
.argument("[target]", "Bundle file (.mthds) or directory")
|
|
746
|
-
.option("--pipe <code>", "Pipe code to run")
|
|
747
|
-
.option("-i, --inputs <file>", "Path to JSON inputs file")
|
|
748
|
-
.option("--content <mthds>", "Bundle content as a string (alternative to file path)")
|
|
749
|
-
.option("--inputs-json <json>", "Inputs as a JSON string (alternative to inputs file)")
|
|
750
|
-
.option("--dry-run", "Validate without executing")
|
|
751
|
-
.option("--mock-inputs", "Use mock inputs for dry run")
|
|
752
|
-
.description("Run a pipe from a bundle file, directory, or content")
|
|
753
|
-
.allowUnknownOption()
|
|
754
|
-
.allowExcessArguments(true)
|
|
755
|
-
.exitOverride()
|
|
756
|
-
.action(runAction);
|
|
757
|
-
// run bundle [target] (alias for run pipe)
|
|
758
|
-
runGroup
|
|
759
|
-
.command("bundle")
|
|
760
|
-
.argument("[target]", "Bundle file (.mthds) or directory")
|
|
761
|
-
.option("--pipe <code>", "Pipe code to run")
|
|
762
|
-
.option("-i, --inputs <file>", "Path to JSON inputs file")
|
|
763
|
-
.option("--content <mthds>", "Bundle content as a string (alternative to file path)")
|
|
764
|
-
.option("--inputs-json <json>", "Inputs as a JSON string (alternative to inputs file)")
|
|
765
|
-
.description("Run a bundle file or content")
|
|
766
|
-
.allowUnknownOption()
|
|
767
|
-
.allowExcessArguments(true)
|
|
768
|
-
.exitOverride()
|
|
769
|
-
.action(runAction);
|
|
770
|
-
// ── models ──
|
|
771
|
-
program
|
|
772
|
-
.command("models")
|
|
773
|
-
.description("List available model presets, aliases, and talent mappings")
|
|
774
|
-
.option("--type <type>", "Filter by model category (repeatable): llm, extract, img_gen, search", collect, [])
|
|
775
|
-
.allowUnknownOption()
|
|
776
|
-
.allowExcessArguments(true)
|
|
777
|
-
.exitOverride()
|
|
778
|
-
.action(async (options) => {
|
|
779
|
-
let runner;
|
|
780
|
-
try {
|
|
781
|
-
runner = makeRunner();
|
|
782
|
-
}
|
|
783
|
-
catch (err) {
|
|
784
|
-
agentError(err.message, "RunnerError", {
|
|
785
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
786
|
-
});
|
|
787
|
-
}
|
|
788
|
-
try {
|
|
789
|
-
const request = options.type?.length ? { type: options.type } : undefined;
|
|
790
|
-
const result = await runner.models(request);
|
|
791
|
-
agentSuccess({ ...result });
|
|
792
|
-
}
|
|
793
|
-
catch (err) {
|
|
794
|
-
agentError(err.message, "RunnerError", {
|
|
795
|
-
error_domain: AGENT_ERROR_DOMAINS.RUNNER,
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
//# sourceMappingURL=runner-commands.js.map
|