@ai-setting/roy-agent-cli 1.5.84 → 1.5.86
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/bin/roy-agent.js +533 -20
- package/dist/index.js +533 -20
- package/dist/roy-agent-linux-x64/bin/roy-agent +0 -0
- package/package.json +1 -1
package/dist/bin/roy-agent.js
CHANGED
|
@@ -7320,7 +7320,7 @@ var require_dist = __commonJS((exports) => {
|
|
|
7320
7320
|
var require_package = __commonJS((exports, module) => {
|
|
7321
7321
|
module.exports = {
|
|
7322
7322
|
name: "@ai-setting/roy-agent-cli",
|
|
7323
|
-
version: "1.5.
|
|
7323
|
+
version: "1.5.86",
|
|
7324
7324
|
type: "module",
|
|
7325
7325
|
description: "CLI for roy-agent - Non-interactive command execution",
|
|
7326
7326
|
main: "./dist/index.js",
|
|
@@ -9000,16 +9000,13 @@ class EventMessageFormatter {
|
|
|
9000
9000
|
}
|
|
9001
9001
|
formatTaskProgress(payload) {
|
|
9002
9002
|
const desc = payload.description || "未命名任务";
|
|
9003
|
-
const progress = payload.progress !== undefined ? `${payload.progress}%` : "";
|
|
9004
9003
|
const message = payload.progressMessage || "";
|
|
9005
9004
|
const taskId = payload.associatedTaskId;
|
|
9006
9005
|
let result = `${this.prefix} \uD83D\uDD04 后台任务「${desc}」`;
|
|
9007
9006
|
if (taskId !== undefined) {
|
|
9008
9007
|
result += `[Task #${taskId}] `;
|
|
9009
9008
|
}
|
|
9010
|
-
result +=
|
|
9011
|
-
if (progress)
|
|
9012
|
-
result += `: ${progress}`;
|
|
9009
|
+
result += `还在进行中,请耐心等待。需查询具体进度可调用 task_get / task_operation_list 等工具`;
|
|
9013
9010
|
if (message)
|
|
9014
9011
|
result += ` - ${message}`;
|
|
9015
9012
|
return result;
|
|
@@ -9255,8 +9252,16 @@ class InputHandler {
|
|
|
9255
9252
|
buffer = [];
|
|
9256
9253
|
static USER_PROMPT = "❯ ";
|
|
9257
9254
|
static CONTINUATION_PROMPT = "... ";
|
|
9255
|
+
static filterControlChars(input) {
|
|
9256
|
+
if (!input)
|
|
9257
|
+
return "";
|
|
9258
|
+
return input.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
9259
|
+
}
|
|
9258
9260
|
pushLine(line) {
|
|
9259
|
-
|
|
9261
|
+
if (line == null) {
|
|
9262
|
+
return;
|
|
9263
|
+
}
|
|
9264
|
+
this.buffer.push(InputHandler.filterControlChars(line));
|
|
9260
9265
|
}
|
|
9261
9266
|
getBuffer() {
|
|
9262
9267
|
return this.buffer.join(`
|
|
@@ -9341,6 +9346,7 @@ class REPL {
|
|
|
9341
9346
|
isShuttingDown = false;
|
|
9342
9347
|
env = null;
|
|
9343
9348
|
inputHandler;
|
|
9349
|
+
keypressHandler;
|
|
9344
9350
|
constructor(options, env) {
|
|
9345
9351
|
this.options = options;
|
|
9346
9352
|
this.env = env ?? null;
|
|
@@ -9361,6 +9367,17 @@ class REPL {
|
|
|
9361
9367
|
return;
|
|
9362
9368
|
}
|
|
9363
9369
|
this.isShuttingDown = true;
|
|
9370
|
+
if (process.stdin.isTTY) {
|
|
9371
|
+
try {
|
|
9372
|
+
process.stdin.setRawMode?.(false);
|
|
9373
|
+
} catch {}
|
|
9374
|
+
}
|
|
9375
|
+
if (this.keypressHandler) {
|
|
9376
|
+
try {
|
|
9377
|
+
process.stdin.removeListener("keypress", this.keypressHandler);
|
|
9378
|
+
} catch {}
|
|
9379
|
+
this.keypressHandler = undefined;
|
|
9380
|
+
}
|
|
9364
9381
|
this.rl.close();
|
|
9365
9382
|
await this.options.onShutdown();
|
|
9366
9383
|
}
|
|
@@ -9428,7 +9445,9 @@ ${COLORS.system("[没有正在执行的请求]")}`);
|
|
|
9428
9445
|
if (process.stdin.isTTY) {
|
|
9429
9446
|
process.stdin.setRawMode?.(true);
|
|
9430
9447
|
}
|
|
9431
|
-
|
|
9448
|
+
this.keypressHandler = (str, key) => {
|
|
9449
|
+
if (this.isShuttingDown)
|
|
9450
|
+
return;
|
|
9432
9451
|
if (key.meta && key.name === "return") {
|
|
9433
9452
|
readline2.moveCursor(process.stdout, 0, -1);
|
|
9434
9453
|
readline2.clearLine(process.stdout, 0);
|
|
@@ -9438,7 +9457,8 @@ ${COLORS.system("[没有正在执行的请求]")}`);
|
|
|
9438
9457
|
if (key.name === "escape") {
|
|
9439
9458
|
this.handleEscKey();
|
|
9440
9459
|
}
|
|
9441
|
-
}
|
|
9460
|
+
};
|
|
9461
|
+
process.stdin.on("keypress", this.keypressHandler);
|
|
9442
9462
|
return new Promise((resolve) => {
|
|
9443
9463
|
this.rl.on("line", async (line) => {
|
|
9444
9464
|
await this.handleLine(line.trim());
|
|
@@ -9452,6 +9472,9 @@ ${COLORS.system("[没有正在执行的请求]")}`);
|
|
|
9452
9472
|
});
|
|
9453
9473
|
}
|
|
9454
9474
|
async handleLine(line) {
|
|
9475
|
+
if (this.isShuttingDown) {
|
|
9476
|
+
return;
|
|
9477
|
+
}
|
|
9455
9478
|
if (line.startsWith("/") && this.inputHandler.getBuffer() === "") {
|
|
9456
9479
|
await this.handleCommand(line.slice(1));
|
|
9457
9480
|
this.inputHandler.reset();
|
|
@@ -17002,7 +17025,7 @@ var WorkflowListCommand = {
|
|
|
17002
17025
|
describe: "列出所有已注册的 Workflow",
|
|
17003
17026
|
builder: (yargs) => yargs.option("tag", {
|
|
17004
17027
|
alias: "t",
|
|
17005
|
-
describe: "
|
|
17028
|
+
describe: "按标签筛选(可多次 --tag ai --tag cli 表示 AND)",
|
|
17006
17029
|
type: "string"
|
|
17007
17030
|
}).option("task-id", {
|
|
17008
17031
|
alias: "i",
|
|
@@ -17022,6 +17045,27 @@ var WorkflowListCommand = {
|
|
|
17022
17045
|
describe: "分页偏移",
|
|
17023
17046
|
type: "number",
|
|
17024
17047
|
default: 0
|
|
17048
|
+
}).option("page", {
|
|
17049
|
+
describe: "页码(1-based,与 --page-size 配合;与 --offset 互斥)",
|
|
17050
|
+
type: "number",
|
|
17051
|
+
default: 1
|
|
17052
|
+
}).option("page-size", {
|
|
17053
|
+
describe: "每页大小(与 --page 配合;等价于 --limit)",
|
|
17054
|
+
type: "number"
|
|
17055
|
+
}).check((argv) => {
|
|
17056
|
+
if (typeof argv.page === "number" && argv.page < 1) {
|
|
17057
|
+
throw new Error("--page must be >= 1");
|
|
17058
|
+
}
|
|
17059
|
+
if (typeof argv.pageSize === "number" && argv.pageSize < 1) {
|
|
17060
|
+
throw new Error("--page-size must be >= 1");
|
|
17061
|
+
}
|
|
17062
|
+
if (typeof argv.limit === "number" && argv.limit < 1) {
|
|
17063
|
+
throw new Error("--limit must be >= 1");
|
|
17064
|
+
}
|
|
17065
|
+
if (typeof argv.offset === "number" && argv.offset < 0) {
|
|
17066
|
+
throw new Error("--offset must be >= 0");
|
|
17067
|
+
}
|
|
17068
|
+
return true;
|
|
17025
17069
|
}).option("json", {
|
|
17026
17070
|
alias: "j",
|
|
17027
17071
|
describe: "JSON 格式输出",
|
|
@@ -17056,12 +17100,20 @@ var WorkflowListCommand = {
|
|
|
17056
17100
|
output.error('WorkflowService not initialized. Please run "roy-agent workflow init" first.');
|
|
17057
17101
|
process.exit(1);
|
|
17058
17102
|
}
|
|
17103
|
+
const tagsArg = args.tag;
|
|
17104
|
+
const tagsList = Array.isArray(tagsArg) ? tagsArg : tagsArg ? [tagsArg] : [];
|
|
17105
|
+
const pageSize = typeof args.pageSize === "number" ? args.pageSize : typeof args.limit === "number" ? args.limit : 50;
|
|
17106
|
+
const page = typeof args.page === "number" ? args.page : 1;
|
|
17107
|
+
const effectiveOffset = (page - 1) * pageSize;
|
|
17108
|
+
const userOffset = typeof args.offset === "number" ? args.offset : 0;
|
|
17109
|
+
const finalOffset = page > 1 ? effectiveOffset : userOffset;
|
|
17059
17110
|
const tool = createWorkflowListTool(service);
|
|
17060
17111
|
const result = await tool.execute({
|
|
17061
|
-
tag:
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17112
|
+
tag: tagsList.length === 1 ? tagsList[0] : undefined,
|
|
17113
|
+
tags: tagsList.length > 1 ? tagsList : undefined,
|
|
17114
|
+
search: args.search !== undefined && typeof args.search === "string" ? args.search : undefined,
|
|
17115
|
+
limit: pageSize,
|
|
17116
|
+
offset: finalOffset
|
|
17065
17117
|
}, {});
|
|
17066
17118
|
if (!result.success) {
|
|
17067
17119
|
output.error(result.error || "Failed to list workflows");
|
|
@@ -17069,6 +17121,8 @@ var WorkflowListCommand = {
|
|
|
17069
17121
|
}
|
|
17070
17122
|
const data = JSON.parse(result.output);
|
|
17071
17123
|
const workflows = data.workflows || [];
|
|
17124
|
+
const availableTags = data.available_tags || [];
|
|
17125
|
+
const total = typeof data.total === "number" ? data.total : workflows.length;
|
|
17072
17126
|
if (args.json) {
|
|
17073
17127
|
output.json({
|
|
17074
17128
|
workflows: workflows.map((w) => ({
|
|
@@ -17079,7 +17133,12 @@ var WorkflowListCommand = {
|
|
|
17079
17133
|
createdAt: w.created_at,
|
|
17080
17134
|
updatedAt: w.created_at
|
|
17081
17135
|
})),
|
|
17082
|
-
|
|
17136
|
+
available_tags: availableTags,
|
|
17137
|
+
total,
|
|
17138
|
+
count: workflows.length,
|
|
17139
|
+
limit: pageSize,
|
|
17140
|
+
offset: finalOffset,
|
|
17141
|
+
page: page > 1 ? page : Math.floor(finalOffset / pageSize) + 1
|
|
17083
17142
|
});
|
|
17084
17143
|
} else {
|
|
17085
17144
|
const renderWorkflows = workflows.map((w) => ({
|
|
@@ -17094,8 +17153,25 @@ var WorkflowListCommand = {
|
|
|
17094
17153
|
metadata: {}
|
|
17095
17154
|
}));
|
|
17096
17155
|
output.log(renderWorkflowList(renderWorkflows));
|
|
17097
|
-
|
|
17098
|
-
|
|
17156
|
+
if (total > workflows.length) {
|
|
17157
|
+
const start = finalOffset + 1;
|
|
17158
|
+
const end = finalOffset + workflows.length;
|
|
17159
|
+
output.log(chalk61.green(`
|
|
17160
|
+
✅ 显示 ${start}-${end} / 共 ${total} 个 Workflow`));
|
|
17161
|
+
const totalPages = Math.ceil(total / pageSize);
|
|
17162
|
+
const currentPage = Math.floor(finalOffset / pageSize) + 1;
|
|
17163
|
+
if (totalPages > 1) {
|
|
17164
|
+
output.log(chalk61.cyan(`\uD83D\uDCC4 第 ${currentPage} / ${totalPages} 页`));
|
|
17165
|
+
}
|
|
17166
|
+
} else {
|
|
17167
|
+
output.log(chalk61.green(`
|
|
17168
|
+
✅ 共 ${total} 个 Workflow`));
|
|
17169
|
+
}
|
|
17170
|
+
if (availableTags.length > 0) {
|
|
17171
|
+
const tagsLine = availableTags.map((t) => `${t.name}(${t.count})`).join(", ");
|
|
17172
|
+
output.log(chalk61.cyan(`
|
|
17173
|
+
\uD83C\uDFF7️ Available tags: ${tagsLine}`));
|
|
17174
|
+
}
|
|
17099
17175
|
}
|
|
17100
17176
|
} catch (error) {
|
|
17101
17177
|
output.error(`Failed to list workflows: ${error}`);
|
|
@@ -17763,8 +17839,9 @@ var WorkflowAddCommand = {
|
|
|
17763
17839
|
type: "string"
|
|
17764
17840
|
}).option("tags", {
|
|
17765
17841
|
alias: "t",
|
|
17766
|
-
describe: "
|
|
17767
|
-
type: "
|
|
17842
|
+
describe: 'Tags (1-3 required). Select from existing tag pool when possible. Run "roy-agent workflow tag list" first to see available tags. Supports both --tags "a,b,c" and --tags a --tags b --tags c forms.',
|
|
17843
|
+
type: "array",
|
|
17844
|
+
string: true
|
|
17768
17845
|
}).option("task-id", {
|
|
17769
17846
|
alias: "i",
|
|
17770
17847
|
describe: "关联任务 ID",
|
|
@@ -17791,6 +17868,29 @@ var WorkflowAddCommand = {
|
|
|
17791
17868
|
const output = new OutputService;
|
|
17792
17869
|
const envService = new EnvironmentService(output);
|
|
17793
17870
|
try {
|
|
17871
|
+
let parseTags = function(input) {
|
|
17872
|
+
if (input === undefined || input === null)
|
|
17873
|
+
return;
|
|
17874
|
+
const list = [];
|
|
17875
|
+
if (Array.isArray(input)) {
|
|
17876
|
+
for (const item of input) {
|
|
17877
|
+
if (typeof item === "string") {
|
|
17878
|
+
for (const t of item.split(",")) {
|
|
17879
|
+
const trimmed = t.trim();
|
|
17880
|
+
if (trimmed)
|
|
17881
|
+
list.push(trimmed);
|
|
17882
|
+
}
|
|
17883
|
+
}
|
|
17884
|
+
}
|
|
17885
|
+
} else if (typeof input === "string") {
|
|
17886
|
+
for (const t of input.split(",")) {
|
|
17887
|
+
const trimmed = t.trim();
|
|
17888
|
+
if (trimmed)
|
|
17889
|
+
list.push(trimmed);
|
|
17890
|
+
}
|
|
17891
|
+
}
|
|
17892
|
+
return list.length > 0 ? list : undefined;
|
|
17893
|
+
};
|
|
17794
17894
|
await envService.create({ configPath: a.config });
|
|
17795
17895
|
const env = envService.getEnvironment();
|
|
17796
17896
|
if (!env) {
|
|
@@ -17902,7 +18002,19 @@ Agent output:
|
|
|
17902
18002
|
output.error('Usage: roy-agent workflow add --file <path> | --desc "<description>"');
|
|
17903
18003
|
process.exit(1);
|
|
17904
18004
|
}
|
|
17905
|
-
const tags = a.tags
|
|
18005
|
+
const tags = parseTags(a.tags);
|
|
18006
|
+
if (!tags || tags.length === 0) {
|
|
18007
|
+
output.error("❌ --tags is required.");
|
|
18008
|
+
output.error(' Please provide 1-3 tags using --tags "tag1,tag2,tag3"');
|
|
18009
|
+
output.error(' Example: roy-agent workflow add --file my.yaml --tags "ai,ml,etl"');
|
|
18010
|
+
process.exit(1);
|
|
18011
|
+
}
|
|
18012
|
+
if (tags.length > 3) {
|
|
18013
|
+
output.error(`❌ Too many tags: received ${tags.length}, maximum is 3.`);
|
|
18014
|
+
output.error(' Please reduce to 1-3 tags using --tags "tag1,tag2,tag3"');
|
|
18015
|
+
output.error(' Example: roy-agent workflow add --file my.yaml --tags "ai,ml,etl"');
|
|
18016
|
+
process.exit(1);
|
|
18017
|
+
}
|
|
17906
18018
|
const workflow = await service.createWorkflow(definition, {
|
|
17907
18019
|
tags,
|
|
17908
18020
|
taskId: a.taskId,
|
|
@@ -19140,11 +19252,412 @@ Error: ${error.message}`));
|
|
|
19140
19252
|
}
|
|
19141
19253
|
};
|
|
19142
19254
|
|
|
19255
|
+
// src/commands/workflow/commands/search.ts
|
|
19256
|
+
import chalk71 from "chalk";
|
|
19257
|
+
import { wrapFunction as wrapFunction3 } from "@ai-setting/roy-agent-core";
|
|
19258
|
+
var WorkflowSearchCommand = {
|
|
19259
|
+
command: "search",
|
|
19260
|
+
describe: "Search workflows by keyword and/or tags (multiple tags use AND filter). v2: returns available_tags.",
|
|
19261
|
+
builder: (yargs) => yargs.option("keyword", {
|
|
19262
|
+
alias: "k",
|
|
19263
|
+
describe: "Search keyword in name and description",
|
|
19264
|
+
type: "string"
|
|
19265
|
+
}).option("tag", {
|
|
19266
|
+
alias: "t",
|
|
19267
|
+
describe: "Filter by tag (can be specified multiple times for AND filter)",
|
|
19268
|
+
type: "array",
|
|
19269
|
+
string: true
|
|
19270
|
+
}).option("limit", {
|
|
19271
|
+
alias: "l",
|
|
19272
|
+
describe: "Maximum number of results",
|
|
19273
|
+
type: "number",
|
|
19274
|
+
default: 50
|
|
19275
|
+
}).option("offset", {
|
|
19276
|
+
alias: "o",
|
|
19277
|
+
describe: "Pagination offset",
|
|
19278
|
+
type: "number",
|
|
19279
|
+
default: 0
|
|
19280
|
+
}).option("json", {
|
|
19281
|
+
alias: "j",
|
|
19282
|
+
describe: "Output as JSON",
|
|
19283
|
+
type: "boolean",
|
|
19284
|
+
default: false
|
|
19285
|
+
}).option("yaml", {
|
|
19286
|
+
alias: "y",
|
|
19287
|
+
describe: "Output as YAML",
|
|
19288
|
+
type: "boolean",
|
|
19289
|
+
default: false
|
|
19290
|
+
}).option("config", {
|
|
19291
|
+
describe: "Config file path",
|
|
19292
|
+
type: "string"
|
|
19293
|
+
}).check((argv) => {
|
|
19294
|
+
const hasKeyword = typeof argv.keyword === "string" && argv.keyword.length > 0;
|
|
19295
|
+
const hasTags = Array.isArray(argv.tag) && argv.tag.length > 0;
|
|
19296
|
+
if (!hasKeyword && !hasTags) {
|
|
19297
|
+
throw new Error("At least one of --keyword or --tag must be provided");
|
|
19298
|
+
}
|
|
19299
|
+
if (Array.isArray(argv.tag)) {
|
|
19300
|
+
for (const t of argv.tag) {
|
|
19301
|
+
if (typeof t !== "string" || t.length === 0) {
|
|
19302
|
+
throw new Error("Empty tag values are not allowed");
|
|
19303
|
+
}
|
|
19304
|
+
if (t.length > 50) {
|
|
19305
|
+
throw new Error(`Tag "${t}" exceeds 50 characters`);
|
|
19306
|
+
}
|
|
19307
|
+
if (t.includes(",")) {
|
|
19308
|
+
throw new Error(`Tag "${t}" contains comma; pass them as separate --tags`);
|
|
19309
|
+
}
|
|
19310
|
+
}
|
|
19311
|
+
}
|
|
19312
|
+
return true;
|
|
19313
|
+
}),
|
|
19314
|
+
async handler(args) {
|
|
19315
|
+
const a = args;
|
|
19316
|
+
const output = new OutputService;
|
|
19317
|
+
const envService = new EnvironmentService(output);
|
|
19318
|
+
try {
|
|
19319
|
+
await runWorkflowSearch({
|
|
19320
|
+
keyword: a.keyword,
|
|
19321
|
+
tags: a.tag,
|
|
19322
|
+
limit: a.limit,
|
|
19323
|
+
offset: a.offset,
|
|
19324
|
+
asJson: a.json,
|
|
19325
|
+
asYaml: a.yaml,
|
|
19326
|
+
configPath: a.config,
|
|
19327
|
+
output,
|
|
19328
|
+
envService
|
|
19329
|
+
});
|
|
19330
|
+
} catch (error) {
|
|
19331
|
+
output.error(`Failed to search workflows: ${error}`);
|
|
19332
|
+
process.exit(1);
|
|
19333
|
+
} finally {
|
|
19334
|
+
await envService.dispose();
|
|
19335
|
+
}
|
|
19336
|
+
}
|
|
19337
|
+
};
|
|
19338
|
+
var _runWorkflowSearchImpl = async function(opts) {
|
|
19339
|
+
const { keyword, tags, limit, offset, asJson, asYaml, configPath, output, envService } = opts;
|
|
19340
|
+
await envService.create({ configPath });
|
|
19341
|
+
const env = envService.getEnvironment();
|
|
19342
|
+
if (!env) {
|
|
19343
|
+
output.error("Failed to create environment");
|
|
19344
|
+
process.exit(1);
|
|
19345
|
+
}
|
|
19346
|
+
const workflowComponent = env.getComponent("workflow");
|
|
19347
|
+
if (!workflowComponent) {
|
|
19348
|
+
output.error("WorkflowComponent not available");
|
|
19349
|
+
process.exit(1);
|
|
19350
|
+
}
|
|
19351
|
+
const service = workflowComponent.getService();
|
|
19352
|
+
if (!service) {
|
|
19353
|
+
output.error('WorkflowService not initialized. Please run "roy-agent workflow init" first.');
|
|
19354
|
+
process.exit(1);
|
|
19355
|
+
}
|
|
19356
|
+
const useWithTags = typeof service.searchWorkflowsWithTags === "function";
|
|
19357
|
+
const result = useWithTags ? await service.searchWorkflowsWithTags({
|
|
19358
|
+
keyword,
|
|
19359
|
+
tags,
|
|
19360
|
+
limit,
|
|
19361
|
+
offset
|
|
19362
|
+
}) : {
|
|
19363
|
+
workflows: service.searchWorkflows({ keyword, tags, limit, offset }),
|
|
19364
|
+
available_tags: []
|
|
19365
|
+
};
|
|
19366
|
+
const workflows = result.workflows ?? [];
|
|
19367
|
+
const availableTags = result.available_tags ?? [];
|
|
19368
|
+
if (asJson) {
|
|
19369
|
+
output.json({
|
|
19370
|
+
workflows: workflows.map((w) => ({
|
|
19371
|
+
name: w.name,
|
|
19372
|
+
version: w.version,
|
|
19373
|
+
description: w.description,
|
|
19374
|
+
tags: w.tags,
|
|
19375
|
+
createdAt: w.createdAt,
|
|
19376
|
+
updatedAt: w.updatedAt
|
|
19377
|
+
})),
|
|
19378
|
+
available_tags: availableTags,
|
|
19379
|
+
total: workflows.length,
|
|
19380
|
+
keyword,
|
|
19381
|
+
tags
|
|
19382
|
+
});
|
|
19383
|
+
return;
|
|
19384
|
+
}
|
|
19385
|
+
if (asYaml) {
|
|
19386
|
+
const yaml = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
19387
|
+
output.log(yaml.stringify({
|
|
19388
|
+
workflows: workflows.map((w) => ({
|
|
19389
|
+
name: w.name,
|
|
19390
|
+
version: w.version,
|
|
19391
|
+
description: w.description,
|
|
19392
|
+
tags: w.tags
|
|
19393
|
+
})),
|
|
19394
|
+
available_tags: availableTags,
|
|
19395
|
+
total: workflows.length,
|
|
19396
|
+
keyword,
|
|
19397
|
+
tags
|
|
19398
|
+
}));
|
|
19399
|
+
return;
|
|
19400
|
+
}
|
|
19401
|
+
const renderWorkflows = workflows.map((w) => ({
|
|
19402
|
+
id: w.name,
|
|
19403
|
+
name: w.name,
|
|
19404
|
+
version: w.version,
|
|
19405
|
+
description: w.description,
|
|
19406
|
+
tags: w.tags || [],
|
|
19407
|
+
createdAt: w.createdAt ? new Date(w.createdAt) : new Date,
|
|
19408
|
+
updatedAt: w.updatedAt ? new Date(w.updatedAt) : new Date,
|
|
19409
|
+
definition: { nodes: [], config: {}, inputs: {} },
|
|
19410
|
+
metadata: {}
|
|
19411
|
+
}));
|
|
19412
|
+
if (renderWorkflows.length === 0) {
|
|
19413
|
+
output.log(chalk71.yellow("\uD83D\uDD0D No workflows matched the search criteria."));
|
|
19414
|
+
output.log(chalk71.gray(` keyword: ${keyword || "(none)"}`));
|
|
19415
|
+
output.log(chalk71.gray(` tags: ${tags && tags.length > 0 ? tags.join(", ") : "(none)"}`));
|
|
19416
|
+
} else {
|
|
19417
|
+
output.log(chalk71.bold(`\uD83D\uDD0D Search results (${renderWorkflows.length}):`));
|
|
19418
|
+
output.log(renderWorkflowList(renderWorkflows));
|
|
19419
|
+
output.log(chalk71.green(`
|
|
19420
|
+
✅ Found ${renderWorkflows.length} workflow(s)`));
|
|
19421
|
+
}
|
|
19422
|
+
if (availableTags.length > 0) {
|
|
19423
|
+
output.log("");
|
|
19424
|
+
output.log(chalk71.bold("\uD83D\uDCDA Available tags (sorted by usage_count):"));
|
|
19425
|
+
for (const t of availableTags) {
|
|
19426
|
+
const name = t.name ?? t.tag;
|
|
19427
|
+
const count = t.count ?? t.usage_count;
|
|
19428
|
+
output.log(chalk71.gray(` - ${name} (${count})`));
|
|
19429
|
+
}
|
|
19430
|
+
}
|
|
19431
|
+
};
|
|
19432
|
+
var runWorkflowSearch = wrapFunction3(_runWorkflowSearchImpl, "workflow.cli.search", {
|
|
19433
|
+
recordParams: true,
|
|
19434
|
+
recordResult: false,
|
|
19435
|
+
log: false
|
|
19436
|
+
});
|
|
19437
|
+
|
|
19438
|
+
// src/commands/workflow/commands/tag.ts
|
|
19439
|
+
import { wrapFunction as wrapFunction4 } from "@ai-setting/roy-agent-core";
|
|
19440
|
+
import chalk72 from "chalk";
|
|
19441
|
+
var WorkflowTagListCommand = {
|
|
19442
|
+
command: "list",
|
|
19443
|
+
describe: "List all workflow tags from the workflow_tags table (sorted by usage_count DESC by default). Use this BEFORE `workflow add` to discover existing tags and reuse them for semantic consistency.",
|
|
19444
|
+
builder: (yargs) => yargs.option("sort-by", {
|
|
19445
|
+
describe: "Sort field",
|
|
19446
|
+
choices: ["usage_count", "name", "created_at"],
|
|
19447
|
+
default: "usage_count"
|
|
19448
|
+
}).option("order", {
|
|
19449
|
+
describe: "Sort order",
|
|
19450
|
+
choices: ["asc", "desc"],
|
|
19451
|
+
default: "desc"
|
|
19452
|
+
}).option("limit", {
|
|
19453
|
+
describe: "Max number of tags to return",
|
|
19454
|
+
type: "number",
|
|
19455
|
+
default: 100
|
|
19456
|
+
}).option("json", {
|
|
19457
|
+
alias: "j",
|
|
19458
|
+
describe: "Output as JSON",
|
|
19459
|
+
type: "boolean",
|
|
19460
|
+
default: false
|
|
19461
|
+
}).option("config", {
|
|
19462
|
+
describe: "Config file path",
|
|
19463
|
+
type: "string"
|
|
19464
|
+
}),
|
|
19465
|
+
async handler(args) {
|
|
19466
|
+
const a = args;
|
|
19467
|
+
const output = new OutputService;
|
|
19468
|
+
const envService = new EnvironmentService(output);
|
|
19469
|
+
try {
|
|
19470
|
+
await runWorkflowTagList({
|
|
19471
|
+
sortBy: a.sortBy,
|
|
19472
|
+
order: a.order,
|
|
19473
|
+
limit: a.limit,
|
|
19474
|
+
asJson: a.json,
|
|
19475
|
+
configPath: a.config,
|
|
19476
|
+
output,
|
|
19477
|
+
envService
|
|
19478
|
+
});
|
|
19479
|
+
} catch (error) {
|
|
19480
|
+
output.error(`Failed to list workflow tags: ${error}`);
|
|
19481
|
+
process.exit(1);
|
|
19482
|
+
} finally {
|
|
19483
|
+
await envService.dispose();
|
|
19484
|
+
}
|
|
19485
|
+
}
|
|
19486
|
+
};
|
|
19487
|
+
var WorkflowTagGetCommand = {
|
|
19488
|
+
command: "get <name>",
|
|
19489
|
+
describe: "Get details of a single workflow tag (usage_count, created_at, updated_at). Returns error if tag not in the workflow_tags table.",
|
|
19490
|
+
builder: (yargs) => yargs.positional("name", {
|
|
19491
|
+
describe: "Tag name",
|
|
19492
|
+
type: "string"
|
|
19493
|
+
}).option("json", {
|
|
19494
|
+
alias: "j",
|
|
19495
|
+
describe: "Output as JSON",
|
|
19496
|
+
type: "boolean",
|
|
19497
|
+
default: false
|
|
19498
|
+
}).option("config", {
|
|
19499
|
+
describe: "Config file path",
|
|
19500
|
+
type: "string"
|
|
19501
|
+
}).check((argv) => {
|
|
19502
|
+
if (typeof argv.name !== "string" || argv.name.length === 0) {
|
|
19503
|
+
throw new Error("Tag name is required");
|
|
19504
|
+
}
|
|
19505
|
+
if (argv.name.length > 50) {
|
|
19506
|
+
throw new Error(`Tag name exceeds 50 characters`);
|
|
19507
|
+
}
|
|
19508
|
+
return true;
|
|
19509
|
+
}),
|
|
19510
|
+
async handler(args) {
|
|
19511
|
+
const a = args;
|
|
19512
|
+
const output = new OutputService;
|
|
19513
|
+
const envService = new EnvironmentService(output);
|
|
19514
|
+
try {
|
|
19515
|
+
await runWorkflowTagGet({
|
|
19516
|
+
name: a.name,
|
|
19517
|
+
asJson: a.json,
|
|
19518
|
+
configPath: a.config,
|
|
19519
|
+
output,
|
|
19520
|
+
envService
|
|
19521
|
+
});
|
|
19522
|
+
} catch (error) {
|
|
19523
|
+
output.error(`Failed to get tag: ${error}`);
|
|
19524
|
+
process.exit(1);
|
|
19525
|
+
} finally {
|
|
19526
|
+
await envService.dispose();
|
|
19527
|
+
}
|
|
19528
|
+
}
|
|
19529
|
+
};
|
|
19530
|
+
var _runWorkflowTagListImpl = async function(opts) {
|
|
19531
|
+
const { output, envService } = opts;
|
|
19532
|
+
await envService.create({ configPath: opts.configPath });
|
|
19533
|
+
const env = envService.getEnvironment();
|
|
19534
|
+
if (!env) {
|
|
19535
|
+
output.error("Failed to create environment");
|
|
19536
|
+
process.exit(1);
|
|
19537
|
+
}
|
|
19538
|
+
const workflowComponent = env.getComponent("workflow");
|
|
19539
|
+
if (!workflowComponent) {
|
|
19540
|
+
output.error("WorkflowComponent not available");
|
|
19541
|
+
process.exit(1);
|
|
19542
|
+
}
|
|
19543
|
+
const service = workflowComponent.getService();
|
|
19544
|
+
if (!service) {
|
|
19545
|
+
output.error('WorkflowService not initialized. Please run "roy-agent workflow init" first.');
|
|
19546
|
+
process.exit(1);
|
|
19547
|
+
}
|
|
19548
|
+
const result = await callListTags(service, {
|
|
19549
|
+
sortBy: opts.sortBy ?? "usage_count",
|
|
19550
|
+
order: opts.order ?? "desc",
|
|
19551
|
+
limit: opts.limit ?? 100
|
|
19552
|
+
});
|
|
19553
|
+
if (opts.asJson) {
|
|
19554
|
+
output.json({
|
|
19555
|
+
tags: result.tags,
|
|
19556
|
+
total: result.total
|
|
19557
|
+
});
|
|
19558
|
+
return;
|
|
19559
|
+
}
|
|
19560
|
+
if (result.tags.length === 0) {
|
|
19561
|
+
output.log(chalk72.yellow("\uD83C\uDFF7️ No tags in the workflow_tags table yet."));
|
|
19562
|
+
output.log(chalk72.gray(" Tags are created automatically when you run `workflow add --tags <name>`."));
|
|
19563
|
+
return;
|
|
19564
|
+
}
|
|
19565
|
+
output.log(chalk72.bold(`\uD83C\uDFF7️ Workflow tags (${result.total}):`));
|
|
19566
|
+
output.log(chalk72.gray(` ${padRight("NAME", 24)}${padRight("USAGE", 8)}${padRight("CREATED", 22)}`));
|
|
19567
|
+
for (const t of result.tags) {
|
|
19568
|
+
const line = ` ${padRight(t.name, 24)}${padRight(String(t.usage_count), 8)}${padRight(formatDate2(t.created_at), 22)}`;
|
|
19569
|
+
output.log(line);
|
|
19570
|
+
}
|
|
19571
|
+
output.log(chalk72.gray(`
|
|
19572
|
+
\uD83D\uDCA1 Tip: when adding a new workflow, prefer tags from this list to ensure semantic consistency.`));
|
|
19573
|
+
};
|
|
19574
|
+
var _runWorkflowTagGetImpl = async function(opts) {
|
|
19575
|
+
const { output, envService } = opts;
|
|
19576
|
+
await envService.create({ configPath: opts.configPath });
|
|
19577
|
+
const env = envService.getEnvironment();
|
|
19578
|
+
if (!env) {
|
|
19579
|
+
output.error("Failed to create environment");
|
|
19580
|
+
process.exit(1);
|
|
19581
|
+
}
|
|
19582
|
+
const workflowComponent = env.getComponent("workflow");
|
|
19583
|
+
if (!workflowComponent) {
|
|
19584
|
+
output.error("WorkflowComponent not available");
|
|
19585
|
+
process.exit(1);
|
|
19586
|
+
}
|
|
19587
|
+
const service = workflowComponent.getService();
|
|
19588
|
+
if (!service) {
|
|
19589
|
+
output.error('WorkflowService not initialized. Please run "roy-agent workflow init" first.');
|
|
19590
|
+
process.exit(1);
|
|
19591
|
+
}
|
|
19592
|
+
const tag = callGetTag(service, opts.name);
|
|
19593
|
+
if (!tag) {
|
|
19594
|
+
if (opts.asJson) {
|
|
19595
|
+
output.json({ error: "Tag not found", name: opts.name });
|
|
19596
|
+
} else {
|
|
19597
|
+
output.error(`Tag "${opts.name}" not found in the workflow_tags table.`);
|
|
19598
|
+
output.log(chalk72.gray(`Tip: run \`roy-agent workflow tag list\` to see available tags.`));
|
|
19599
|
+
}
|
|
19600
|
+
process.exitCode = 1;
|
|
19601
|
+
return;
|
|
19602
|
+
}
|
|
19603
|
+
if (opts.asJson) {
|
|
19604
|
+
output.json(tag);
|
|
19605
|
+
return;
|
|
19606
|
+
}
|
|
19607
|
+
output.log(chalk72.bold(`\uD83C\uDFF7️ Tag: ${tag.name}`));
|
|
19608
|
+
output.log(chalk72.gray(` usage_count: ${tag.usage_count}`));
|
|
19609
|
+
output.log(chalk72.gray(` created_at: ${tag.created_at}`));
|
|
19610
|
+
output.log(chalk72.gray(` updated_at: ${tag.updated_at}`));
|
|
19611
|
+
};
|
|
19612
|
+
async function callListTags(service, options) {
|
|
19613
|
+
if (typeof service.listTags !== "function") {
|
|
19614
|
+
return { tags: [], total: 0 };
|
|
19615
|
+
}
|
|
19616
|
+
return await service.listTags(options);
|
|
19617
|
+
}
|
|
19618
|
+
function callGetTag(service, name) {
|
|
19619
|
+
if (typeof service.getTag !== "function") {
|
|
19620
|
+
return;
|
|
19621
|
+
}
|
|
19622
|
+
return service.getTag(name);
|
|
19623
|
+
}
|
|
19624
|
+
function padRight(str, width) {
|
|
19625
|
+
if (str.length >= width)
|
|
19626
|
+
return str.slice(0, width - 1) + " ";
|
|
19627
|
+
return str + " ".repeat(width - str.length);
|
|
19628
|
+
}
|
|
19629
|
+
function formatDate2(iso) {
|
|
19630
|
+
try {
|
|
19631
|
+
const d = new Date(iso);
|
|
19632
|
+
if (isNaN(d.getTime()))
|
|
19633
|
+
return iso;
|
|
19634
|
+
return d.toISOString().replace("T", " ").slice(0, 19);
|
|
19635
|
+
} catch {
|
|
19636
|
+
return iso;
|
|
19637
|
+
}
|
|
19638
|
+
}
|
|
19639
|
+
var runWorkflowTagList = wrapFunction4(_runWorkflowTagListImpl, "workflow.cli.tag.list", {
|
|
19640
|
+
recordParams: true,
|
|
19641
|
+
recordResult: false,
|
|
19642
|
+
log: false
|
|
19643
|
+
});
|
|
19644
|
+
var runWorkflowTagGet = wrapFunction4(_runWorkflowTagGetImpl, "workflow.cli.tag.get", {
|
|
19645
|
+
recordParams: true,
|
|
19646
|
+
recordResult: false,
|
|
19647
|
+
log: false
|
|
19648
|
+
});
|
|
19649
|
+
|
|
19143
19650
|
// src/commands/workflow/index.ts
|
|
19651
|
+
var WorkflowTagCommand = {
|
|
19652
|
+
command: "tag",
|
|
19653
|
+
describe: "Manage workflow tags — list and get from the workflow_tags table. Use BEFORE `workflow add` to discover existing tags.",
|
|
19654
|
+
builder: (yargs) => yargs.command(WorkflowTagListCommand).command(WorkflowTagGetCommand).demandCommand(1, "请指定 tag 子命令:list 或 get <name>").help(),
|
|
19655
|
+
handler() {}
|
|
19656
|
+
};
|
|
19144
19657
|
var WorkflowCommand = {
|
|
19145
19658
|
command: "workflow",
|
|
19146
19659
|
describe: "Workflow DAG management and execution - create, run, and monitor workflows",
|
|
19147
|
-
builder: (yargs) => yargs.command(WorkflowListCommand).command(WorkflowAddCommand).command(WorkflowNodesCommand).command(WorkflowValidateCommand).command(WorkflowGetCommand).command(WorkflowUpdateCommand).command(WorkflowRemoveCommand).command(WorkflowRunCommand).command(WorkflowStopCommand).command(WorkflowStatusCommand).demandCommand(1, "请指定子命令:list、add、validate、nodes、get、update、remove、run、stop、status\n\nResume: 使用 `workflow run -s <sessionId>` 恢复暂停的工作流").help(),
|
|
19660
|
+
builder: (yargs) => yargs.command(WorkflowListCommand).command(WorkflowAddCommand).command(WorkflowSearchCommand).command(WorkflowTagCommand).command(WorkflowNodesCommand).command(WorkflowValidateCommand).command(WorkflowGetCommand).command(WorkflowUpdateCommand).command(WorkflowRemoveCommand).command(WorkflowRunCommand).command(WorkflowStopCommand).command(WorkflowStatusCommand).demandCommand(1, "请指定子命令:list、add、search、tag、validate、nodes、get、update、remove、run、stop、status\n\nResume: 使用 `workflow run -s <sessionId>` 恢复暂停的工作流").help(),
|
|
19148
19661
|
handler() {}
|
|
19149
19662
|
};
|
|
19150
19663
|
|
package/dist/index.js
CHANGED
|
@@ -7319,7 +7319,7 @@ var require_dist = __commonJS((exports) => {
|
|
|
7319
7319
|
var require_package = __commonJS((exports, module) => {
|
|
7320
7320
|
module.exports = {
|
|
7321
7321
|
name: "@ai-setting/roy-agent-cli",
|
|
7322
|
-
version: "1.5.
|
|
7322
|
+
version: "1.5.86",
|
|
7323
7323
|
type: "module",
|
|
7324
7324
|
description: "CLI for roy-agent - Non-interactive command execution",
|
|
7325
7325
|
main: "./dist/index.js",
|
|
@@ -8999,16 +8999,13 @@ class EventMessageFormatter {
|
|
|
8999
8999
|
}
|
|
9000
9000
|
formatTaskProgress(payload) {
|
|
9001
9001
|
const desc = payload.description || "未命名任务";
|
|
9002
|
-
const progress = payload.progress !== undefined ? `${payload.progress}%` : "";
|
|
9003
9002
|
const message = payload.progressMessage || "";
|
|
9004
9003
|
const taskId = payload.associatedTaskId;
|
|
9005
9004
|
let result = `${this.prefix} \uD83D\uDD04 后台任务「${desc}」`;
|
|
9006
9005
|
if (taskId !== undefined) {
|
|
9007
9006
|
result += `[Task #${taskId}] `;
|
|
9008
9007
|
}
|
|
9009
|
-
result +=
|
|
9010
|
-
if (progress)
|
|
9011
|
-
result += `: ${progress}`;
|
|
9008
|
+
result += `还在进行中,请耐心等待。需查询具体进度可调用 task_get / task_operation_list 等工具`;
|
|
9012
9009
|
if (message)
|
|
9013
9010
|
result += ` - ${message}`;
|
|
9014
9011
|
return result;
|
|
@@ -9254,8 +9251,16 @@ class InputHandler {
|
|
|
9254
9251
|
buffer = [];
|
|
9255
9252
|
static USER_PROMPT = "❯ ";
|
|
9256
9253
|
static CONTINUATION_PROMPT = "... ";
|
|
9254
|
+
static filterControlChars(input) {
|
|
9255
|
+
if (!input)
|
|
9256
|
+
return "";
|
|
9257
|
+
return input.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
9258
|
+
}
|
|
9257
9259
|
pushLine(line) {
|
|
9258
|
-
|
|
9260
|
+
if (line == null) {
|
|
9261
|
+
return;
|
|
9262
|
+
}
|
|
9263
|
+
this.buffer.push(InputHandler.filterControlChars(line));
|
|
9259
9264
|
}
|
|
9260
9265
|
getBuffer() {
|
|
9261
9266
|
return this.buffer.join(`
|
|
@@ -9340,6 +9345,7 @@ class REPL {
|
|
|
9340
9345
|
isShuttingDown = false;
|
|
9341
9346
|
env = null;
|
|
9342
9347
|
inputHandler;
|
|
9348
|
+
keypressHandler;
|
|
9343
9349
|
constructor(options, env) {
|
|
9344
9350
|
this.options = options;
|
|
9345
9351
|
this.env = env ?? null;
|
|
@@ -9360,6 +9366,17 @@ class REPL {
|
|
|
9360
9366
|
return;
|
|
9361
9367
|
}
|
|
9362
9368
|
this.isShuttingDown = true;
|
|
9369
|
+
if (process.stdin.isTTY) {
|
|
9370
|
+
try {
|
|
9371
|
+
process.stdin.setRawMode?.(false);
|
|
9372
|
+
} catch {}
|
|
9373
|
+
}
|
|
9374
|
+
if (this.keypressHandler) {
|
|
9375
|
+
try {
|
|
9376
|
+
process.stdin.removeListener("keypress", this.keypressHandler);
|
|
9377
|
+
} catch {}
|
|
9378
|
+
this.keypressHandler = undefined;
|
|
9379
|
+
}
|
|
9363
9380
|
this.rl.close();
|
|
9364
9381
|
await this.options.onShutdown();
|
|
9365
9382
|
}
|
|
@@ -9427,7 +9444,9 @@ ${COLORS.system("[没有正在执行的请求]")}`);
|
|
|
9427
9444
|
if (process.stdin.isTTY) {
|
|
9428
9445
|
process.stdin.setRawMode?.(true);
|
|
9429
9446
|
}
|
|
9430
|
-
|
|
9447
|
+
this.keypressHandler = (str, key) => {
|
|
9448
|
+
if (this.isShuttingDown)
|
|
9449
|
+
return;
|
|
9431
9450
|
if (key.meta && key.name === "return") {
|
|
9432
9451
|
readline2.moveCursor(process.stdout, 0, -1);
|
|
9433
9452
|
readline2.clearLine(process.stdout, 0);
|
|
@@ -9437,7 +9456,8 @@ ${COLORS.system("[没有正在执行的请求]")}`);
|
|
|
9437
9456
|
if (key.name === "escape") {
|
|
9438
9457
|
this.handleEscKey();
|
|
9439
9458
|
}
|
|
9440
|
-
}
|
|
9459
|
+
};
|
|
9460
|
+
process.stdin.on("keypress", this.keypressHandler);
|
|
9441
9461
|
return new Promise((resolve) => {
|
|
9442
9462
|
this.rl.on("line", async (line) => {
|
|
9443
9463
|
await this.handleLine(line.trim());
|
|
@@ -9451,6 +9471,9 @@ ${COLORS.system("[没有正在执行的请求]")}`);
|
|
|
9451
9471
|
});
|
|
9452
9472
|
}
|
|
9453
9473
|
async handleLine(line) {
|
|
9474
|
+
if (this.isShuttingDown) {
|
|
9475
|
+
return;
|
|
9476
|
+
}
|
|
9454
9477
|
if (line.startsWith("/") && this.inputHandler.getBuffer() === "") {
|
|
9455
9478
|
await this.handleCommand(line.slice(1));
|
|
9456
9479
|
this.inputHandler.reset();
|
|
@@ -17001,7 +17024,7 @@ var WorkflowListCommand = {
|
|
|
17001
17024
|
describe: "列出所有已注册的 Workflow",
|
|
17002
17025
|
builder: (yargs) => yargs.option("tag", {
|
|
17003
17026
|
alias: "t",
|
|
17004
|
-
describe: "
|
|
17027
|
+
describe: "按标签筛选(可多次 --tag ai --tag cli 表示 AND)",
|
|
17005
17028
|
type: "string"
|
|
17006
17029
|
}).option("task-id", {
|
|
17007
17030
|
alias: "i",
|
|
@@ -17021,6 +17044,27 @@ var WorkflowListCommand = {
|
|
|
17021
17044
|
describe: "分页偏移",
|
|
17022
17045
|
type: "number",
|
|
17023
17046
|
default: 0
|
|
17047
|
+
}).option("page", {
|
|
17048
|
+
describe: "页码(1-based,与 --page-size 配合;与 --offset 互斥)",
|
|
17049
|
+
type: "number",
|
|
17050
|
+
default: 1
|
|
17051
|
+
}).option("page-size", {
|
|
17052
|
+
describe: "每页大小(与 --page 配合;等价于 --limit)",
|
|
17053
|
+
type: "number"
|
|
17054
|
+
}).check((argv) => {
|
|
17055
|
+
if (typeof argv.page === "number" && argv.page < 1) {
|
|
17056
|
+
throw new Error("--page must be >= 1");
|
|
17057
|
+
}
|
|
17058
|
+
if (typeof argv.pageSize === "number" && argv.pageSize < 1) {
|
|
17059
|
+
throw new Error("--page-size must be >= 1");
|
|
17060
|
+
}
|
|
17061
|
+
if (typeof argv.limit === "number" && argv.limit < 1) {
|
|
17062
|
+
throw new Error("--limit must be >= 1");
|
|
17063
|
+
}
|
|
17064
|
+
if (typeof argv.offset === "number" && argv.offset < 0) {
|
|
17065
|
+
throw new Error("--offset must be >= 0");
|
|
17066
|
+
}
|
|
17067
|
+
return true;
|
|
17024
17068
|
}).option("json", {
|
|
17025
17069
|
alias: "j",
|
|
17026
17070
|
describe: "JSON 格式输出",
|
|
@@ -17055,12 +17099,20 @@ var WorkflowListCommand = {
|
|
|
17055
17099
|
output.error('WorkflowService not initialized. Please run "roy-agent workflow init" first.');
|
|
17056
17100
|
process.exit(1);
|
|
17057
17101
|
}
|
|
17102
|
+
const tagsArg = args.tag;
|
|
17103
|
+
const tagsList = Array.isArray(tagsArg) ? tagsArg : tagsArg ? [tagsArg] : [];
|
|
17104
|
+
const pageSize = typeof args.pageSize === "number" ? args.pageSize : typeof args.limit === "number" ? args.limit : 50;
|
|
17105
|
+
const page = typeof args.page === "number" ? args.page : 1;
|
|
17106
|
+
const effectiveOffset = (page - 1) * pageSize;
|
|
17107
|
+
const userOffset = typeof args.offset === "number" ? args.offset : 0;
|
|
17108
|
+
const finalOffset = page > 1 ? effectiveOffset : userOffset;
|
|
17058
17109
|
const tool = createWorkflowListTool(service);
|
|
17059
17110
|
const result = await tool.execute({
|
|
17060
|
-
tag:
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17111
|
+
tag: tagsList.length === 1 ? tagsList[0] : undefined,
|
|
17112
|
+
tags: tagsList.length > 1 ? tagsList : undefined,
|
|
17113
|
+
search: args.search !== undefined && typeof args.search === "string" ? args.search : undefined,
|
|
17114
|
+
limit: pageSize,
|
|
17115
|
+
offset: finalOffset
|
|
17064
17116
|
}, {});
|
|
17065
17117
|
if (!result.success) {
|
|
17066
17118
|
output.error(result.error || "Failed to list workflows");
|
|
@@ -17068,6 +17120,8 @@ var WorkflowListCommand = {
|
|
|
17068
17120
|
}
|
|
17069
17121
|
const data = JSON.parse(result.output);
|
|
17070
17122
|
const workflows = data.workflows || [];
|
|
17123
|
+
const availableTags = data.available_tags || [];
|
|
17124
|
+
const total = typeof data.total === "number" ? data.total : workflows.length;
|
|
17071
17125
|
if (args.json) {
|
|
17072
17126
|
output.json({
|
|
17073
17127
|
workflows: workflows.map((w) => ({
|
|
@@ -17078,7 +17132,12 @@ var WorkflowListCommand = {
|
|
|
17078
17132
|
createdAt: w.created_at,
|
|
17079
17133
|
updatedAt: w.created_at
|
|
17080
17134
|
})),
|
|
17081
|
-
|
|
17135
|
+
available_tags: availableTags,
|
|
17136
|
+
total,
|
|
17137
|
+
count: workflows.length,
|
|
17138
|
+
limit: pageSize,
|
|
17139
|
+
offset: finalOffset,
|
|
17140
|
+
page: page > 1 ? page : Math.floor(finalOffset / pageSize) + 1
|
|
17082
17141
|
});
|
|
17083
17142
|
} else {
|
|
17084
17143
|
const renderWorkflows = workflows.map((w) => ({
|
|
@@ -17093,8 +17152,25 @@ var WorkflowListCommand = {
|
|
|
17093
17152
|
metadata: {}
|
|
17094
17153
|
}));
|
|
17095
17154
|
output.log(renderWorkflowList(renderWorkflows));
|
|
17096
|
-
|
|
17097
|
-
|
|
17155
|
+
if (total > workflows.length) {
|
|
17156
|
+
const start = finalOffset + 1;
|
|
17157
|
+
const end = finalOffset + workflows.length;
|
|
17158
|
+
output.log(chalk61.green(`
|
|
17159
|
+
✅ 显示 ${start}-${end} / 共 ${total} 个 Workflow`));
|
|
17160
|
+
const totalPages = Math.ceil(total / pageSize);
|
|
17161
|
+
const currentPage = Math.floor(finalOffset / pageSize) + 1;
|
|
17162
|
+
if (totalPages > 1) {
|
|
17163
|
+
output.log(chalk61.cyan(`\uD83D\uDCC4 第 ${currentPage} / ${totalPages} 页`));
|
|
17164
|
+
}
|
|
17165
|
+
} else {
|
|
17166
|
+
output.log(chalk61.green(`
|
|
17167
|
+
✅ 共 ${total} 个 Workflow`));
|
|
17168
|
+
}
|
|
17169
|
+
if (availableTags.length > 0) {
|
|
17170
|
+
const tagsLine = availableTags.map((t) => `${t.name}(${t.count})`).join(", ");
|
|
17171
|
+
output.log(chalk61.cyan(`
|
|
17172
|
+
\uD83C\uDFF7️ Available tags: ${tagsLine}`));
|
|
17173
|
+
}
|
|
17098
17174
|
}
|
|
17099
17175
|
} catch (error) {
|
|
17100
17176
|
output.error(`Failed to list workflows: ${error}`);
|
|
@@ -17762,8 +17838,9 @@ var WorkflowAddCommand = {
|
|
|
17762
17838
|
type: "string"
|
|
17763
17839
|
}).option("tags", {
|
|
17764
17840
|
alias: "t",
|
|
17765
|
-
describe: "
|
|
17766
|
-
type: "
|
|
17841
|
+
describe: 'Tags (1-3 required). Select from existing tag pool when possible. Run "roy-agent workflow tag list" first to see available tags. Supports both --tags "a,b,c" and --tags a --tags b --tags c forms.',
|
|
17842
|
+
type: "array",
|
|
17843
|
+
string: true
|
|
17767
17844
|
}).option("task-id", {
|
|
17768
17845
|
alias: "i",
|
|
17769
17846
|
describe: "关联任务 ID",
|
|
@@ -17790,6 +17867,29 @@ var WorkflowAddCommand = {
|
|
|
17790
17867
|
const output = new OutputService;
|
|
17791
17868
|
const envService = new EnvironmentService(output);
|
|
17792
17869
|
try {
|
|
17870
|
+
let parseTags = function(input) {
|
|
17871
|
+
if (input === undefined || input === null)
|
|
17872
|
+
return;
|
|
17873
|
+
const list = [];
|
|
17874
|
+
if (Array.isArray(input)) {
|
|
17875
|
+
for (const item of input) {
|
|
17876
|
+
if (typeof item === "string") {
|
|
17877
|
+
for (const t of item.split(",")) {
|
|
17878
|
+
const trimmed = t.trim();
|
|
17879
|
+
if (trimmed)
|
|
17880
|
+
list.push(trimmed);
|
|
17881
|
+
}
|
|
17882
|
+
}
|
|
17883
|
+
}
|
|
17884
|
+
} else if (typeof input === "string") {
|
|
17885
|
+
for (const t of input.split(",")) {
|
|
17886
|
+
const trimmed = t.trim();
|
|
17887
|
+
if (trimmed)
|
|
17888
|
+
list.push(trimmed);
|
|
17889
|
+
}
|
|
17890
|
+
}
|
|
17891
|
+
return list.length > 0 ? list : undefined;
|
|
17892
|
+
};
|
|
17793
17893
|
await envService.create({ configPath: a.config });
|
|
17794
17894
|
const env = envService.getEnvironment();
|
|
17795
17895
|
if (!env) {
|
|
@@ -17901,7 +18001,19 @@ Agent output:
|
|
|
17901
18001
|
output.error('Usage: roy-agent workflow add --file <path> | --desc "<description>"');
|
|
17902
18002
|
process.exit(1);
|
|
17903
18003
|
}
|
|
17904
|
-
const tags = a.tags
|
|
18004
|
+
const tags = parseTags(a.tags);
|
|
18005
|
+
if (!tags || tags.length === 0) {
|
|
18006
|
+
output.error("❌ --tags is required.");
|
|
18007
|
+
output.error(' Please provide 1-3 tags using --tags "tag1,tag2,tag3"');
|
|
18008
|
+
output.error(' Example: roy-agent workflow add --file my.yaml --tags "ai,ml,etl"');
|
|
18009
|
+
process.exit(1);
|
|
18010
|
+
}
|
|
18011
|
+
if (tags.length > 3) {
|
|
18012
|
+
output.error(`❌ Too many tags: received ${tags.length}, maximum is 3.`);
|
|
18013
|
+
output.error(' Please reduce to 1-3 tags using --tags "tag1,tag2,tag3"');
|
|
18014
|
+
output.error(' Example: roy-agent workflow add --file my.yaml --tags "ai,ml,etl"');
|
|
18015
|
+
process.exit(1);
|
|
18016
|
+
}
|
|
17905
18017
|
const workflow = await service.createWorkflow(definition, {
|
|
17906
18018
|
tags,
|
|
17907
18019
|
taskId: a.taskId,
|
|
@@ -19139,11 +19251,412 @@ Error: ${error.message}`));
|
|
|
19139
19251
|
}
|
|
19140
19252
|
};
|
|
19141
19253
|
|
|
19254
|
+
// src/commands/workflow/commands/search.ts
|
|
19255
|
+
import chalk71 from "chalk";
|
|
19256
|
+
import { wrapFunction as wrapFunction3 } from "@ai-setting/roy-agent-core";
|
|
19257
|
+
var WorkflowSearchCommand = {
|
|
19258
|
+
command: "search",
|
|
19259
|
+
describe: "Search workflows by keyword and/or tags (multiple tags use AND filter). v2: returns available_tags.",
|
|
19260
|
+
builder: (yargs) => yargs.option("keyword", {
|
|
19261
|
+
alias: "k",
|
|
19262
|
+
describe: "Search keyword in name and description",
|
|
19263
|
+
type: "string"
|
|
19264
|
+
}).option("tag", {
|
|
19265
|
+
alias: "t",
|
|
19266
|
+
describe: "Filter by tag (can be specified multiple times for AND filter)",
|
|
19267
|
+
type: "array",
|
|
19268
|
+
string: true
|
|
19269
|
+
}).option("limit", {
|
|
19270
|
+
alias: "l",
|
|
19271
|
+
describe: "Maximum number of results",
|
|
19272
|
+
type: "number",
|
|
19273
|
+
default: 50
|
|
19274
|
+
}).option("offset", {
|
|
19275
|
+
alias: "o",
|
|
19276
|
+
describe: "Pagination offset",
|
|
19277
|
+
type: "number",
|
|
19278
|
+
default: 0
|
|
19279
|
+
}).option("json", {
|
|
19280
|
+
alias: "j",
|
|
19281
|
+
describe: "Output as JSON",
|
|
19282
|
+
type: "boolean",
|
|
19283
|
+
default: false
|
|
19284
|
+
}).option("yaml", {
|
|
19285
|
+
alias: "y",
|
|
19286
|
+
describe: "Output as YAML",
|
|
19287
|
+
type: "boolean",
|
|
19288
|
+
default: false
|
|
19289
|
+
}).option("config", {
|
|
19290
|
+
describe: "Config file path",
|
|
19291
|
+
type: "string"
|
|
19292
|
+
}).check((argv) => {
|
|
19293
|
+
const hasKeyword = typeof argv.keyword === "string" && argv.keyword.length > 0;
|
|
19294
|
+
const hasTags = Array.isArray(argv.tag) && argv.tag.length > 0;
|
|
19295
|
+
if (!hasKeyword && !hasTags) {
|
|
19296
|
+
throw new Error("At least one of --keyword or --tag must be provided");
|
|
19297
|
+
}
|
|
19298
|
+
if (Array.isArray(argv.tag)) {
|
|
19299
|
+
for (const t of argv.tag) {
|
|
19300
|
+
if (typeof t !== "string" || t.length === 0) {
|
|
19301
|
+
throw new Error("Empty tag values are not allowed");
|
|
19302
|
+
}
|
|
19303
|
+
if (t.length > 50) {
|
|
19304
|
+
throw new Error(`Tag "${t}" exceeds 50 characters`);
|
|
19305
|
+
}
|
|
19306
|
+
if (t.includes(",")) {
|
|
19307
|
+
throw new Error(`Tag "${t}" contains comma; pass them as separate --tags`);
|
|
19308
|
+
}
|
|
19309
|
+
}
|
|
19310
|
+
}
|
|
19311
|
+
return true;
|
|
19312
|
+
}),
|
|
19313
|
+
async handler(args) {
|
|
19314
|
+
const a = args;
|
|
19315
|
+
const output = new OutputService;
|
|
19316
|
+
const envService = new EnvironmentService(output);
|
|
19317
|
+
try {
|
|
19318
|
+
await runWorkflowSearch({
|
|
19319
|
+
keyword: a.keyword,
|
|
19320
|
+
tags: a.tag,
|
|
19321
|
+
limit: a.limit,
|
|
19322
|
+
offset: a.offset,
|
|
19323
|
+
asJson: a.json,
|
|
19324
|
+
asYaml: a.yaml,
|
|
19325
|
+
configPath: a.config,
|
|
19326
|
+
output,
|
|
19327
|
+
envService
|
|
19328
|
+
});
|
|
19329
|
+
} catch (error) {
|
|
19330
|
+
output.error(`Failed to search workflows: ${error}`);
|
|
19331
|
+
process.exit(1);
|
|
19332
|
+
} finally {
|
|
19333
|
+
await envService.dispose();
|
|
19334
|
+
}
|
|
19335
|
+
}
|
|
19336
|
+
};
|
|
19337
|
+
var _runWorkflowSearchImpl = async function(opts) {
|
|
19338
|
+
const { keyword, tags, limit, offset, asJson, asYaml, configPath, output, envService } = opts;
|
|
19339
|
+
await envService.create({ configPath });
|
|
19340
|
+
const env = envService.getEnvironment();
|
|
19341
|
+
if (!env) {
|
|
19342
|
+
output.error("Failed to create environment");
|
|
19343
|
+
process.exit(1);
|
|
19344
|
+
}
|
|
19345
|
+
const workflowComponent = env.getComponent("workflow");
|
|
19346
|
+
if (!workflowComponent) {
|
|
19347
|
+
output.error("WorkflowComponent not available");
|
|
19348
|
+
process.exit(1);
|
|
19349
|
+
}
|
|
19350
|
+
const service = workflowComponent.getService();
|
|
19351
|
+
if (!service) {
|
|
19352
|
+
output.error('WorkflowService not initialized. Please run "roy-agent workflow init" first.');
|
|
19353
|
+
process.exit(1);
|
|
19354
|
+
}
|
|
19355
|
+
const useWithTags = typeof service.searchWorkflowsWithTags === "function";
|
|
19356
|
+
const result = useWithTags ? await service.searchWorkflowsWithTags({
|
|
19357
|
+
keyword,
|
|
19358
|
+
tags,
|
|
19359
|
+
limit,
|
|
19360
|
+
offset
|
|
19361
|
+
}) : {
|
|
19362
|
+
workflows: service.searchWorkflows({ keyword, tags, limit, offset }),
|
|
19363
|
+
available_tags: []
|
|
19364
|
+
};
|
|
19365
|
+
const workflows = result.workflows ?? [];
|
|
19366
|
+
const availableTags = result.available_tags ?? [];
|
|
19367
|
+
if (asJson) {
|
|
19368
|
+
output.json({
|
|
19369
|
+
workflows: workflows.map((w) => ({
|
|
19370
|
+
name: w.name,
|
|
19371
|
+
version: w.version,
|
|
19372
|
+
description: w.description,
|
|
19373
|
+
tags: w.tags,
|
|
19374
|
+
createdAt: w.createdAt,
|
|
19375
|
+
updatedAt: w.updatedAt
|
|
19376
|
+
})),
|
|
19377
|
+
available_tags: availableTags,
|
|
19378
|
+
total: workflows.length,
|
|
19379
|
+
keyword,
|
|
19380
|
+
tags
|
|
19381
|
+
});
|
|
19382
|
+
return;
|
|
19383
|
+
}
|
|
19384
|
+
if (asYaml) {
|
|
19385
|
+
const yaml = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
19386
|
+
output.log(yaml.stringify({
|
|
19387
|
+
workflows: workflows.map((w) => ({
|
|
19388
|
+
name: w.name,
|
|
19389
|
+
version: w.version,
|
|
19390
|
+
description: w.description,
|
|
19391
|
+
tags: w.tags
|
|
19392
|
+
})),
|
|
19393
|
+
available_tags: availableTags,
|
|
19394
|
+
total: workflows.length,
|
|
19395
|
+
keyword,
|
|
19396
|
+
tags
|
|
19397
|
+
}));
|
|
19398
|
+
return;
|
|
19399
|
+
}
|
|
19400
|
+
const renderWorkflows = workflows.map((w) => ({
|
|
19401
|
+
id: w.name,
|
|
19402
|
+
name: w.name,
|
|
19403
|
+
version: w.version,
|
|
19404
|
+
description: w.description,
|
|
19405
|
+
tags: w.tags || [],
|
|
19406
|
+
createdAt: w.createdAt ? new Date(w.createdAt) : new Date,
|
|
19407
|
+
updatedAt: w.updatedAt ? new Date(w.updatedAt) : new Date,
|
|
19408
|
+
definition: { nodes: [], config: {}, inputs: {} },
|
|
19409
|
+
metadata: {}
|
|
19410
|
+
}));
|
|
19411
|
+
if (renderWorkflows.length === 0) {
|
|
19412
|
+
output.log(chalk71.yellow("\uD83D\uDD0D No workflows matched the search criteria."));
|
|
19413
|
+
output.log(chalk71.gray(` keyword: ${keyword || "(none)"}`));
|
|
19414
|
+
output.log(chalk71.gray(` tags: ${tags && tags.length > 0 ? tags.join(", ") : "(none)"}`));
|
|
19415
|
+
} else {
|
|
19416
|
+
output.log(chalk71.bold(`\uD83D\uDD0D Search results (${renderWorkflows.length}):`));
|
|
19417
|
+
output.log(renderWorkflowList(renderWorkflows));
|
|
19418
|
+
output.log(chalk71.green(`
|
|
19419
|
+
✅ Found ${renderWorkflows.length} workflow(s)`));
|
|
19420
|
+
}
|
|
19421
|
+
if (availableTags.length > 0) {
|
|
19422
|
+
output.log("");
|
|
19423
|
+
output.log(chalk71.bold("\uD83D\uDCDA Available tags (sorted by usage_count):"));
|
|
19424
|
+
for (const t of availableTags) {
|
|
19425
|
+
const name = t.name ?? t.tag;
|
|
19426
|
+
const count = t.count ?? t.usage_count;
|
|
19427
|
+
output.log(chalk71.gray(` - ${name} (${count})`));
|
|
19428
|
+
}
|
|
19429
|
+
}
|
|
19430
|
+
};
|
|
19431
|
+
var runWorkflowSearch = wrapFunction3(_runWorkflowSearchImpl, "workflow.cli.search", {
|
|
19432
|
+
recordParams: true,
|
|
19433
|
+
recordResult: false,
|
|
19434
|
+
log: false
|
|
19435
|
+
});
|
|
19436
|
+
|
|
19437
|
+
// src/commands/workflow/commands/tag.ts
|
|
19438
|
+
import { wrapFunction as wrapFunction4 } from "@ai-setting/roy-agent-core";
|
|
19439
|
+
import chalk72 from "chalk";
|
|
19440
|
+
var WorkflowTagListCommand = {
|
|
19441
|
+
command: "list",
|
|
19442
|
+
describe: "List all workflow tags from the workflow_tags table (sorted by usage_count DESC by default). Use this BEFORE `workflow add` to discover existing tags and reuse them for semantic consistency.",
|
|
19443
|
+
builder: (yargs) => yargs.option("sort-by", {
|
|
19444
|
+
describe: "Sort field",
|
|
19445
|
+
choices: ["usage_count", "name", "created_at"],
|
|
19446
|
+
default: "usage_count"
|
|
19447
|
+
}).option("order", {
|
|
19448
|
+
describe: "Sort order",
|
|
19449
|
+
choices: ["asc", "desc"],
|
|
19450
|
+
default: "desc"
|
|
19451
|
+
}).option("limit", {
|
|
19452
|
+
describe: "Max number of tags to return",
|
|
19453
|
+
type: "number",
|
|
19454
|
+
default: 100
|
|
19455
|
+
}).option("json", {
|
|
19456
|
+
alias: "j",
|
|
19457
|
+
describe: "Output as JSON",
|
|
19458
|
+
type: "boolean",
|
|
19459
|
+
default: false
|
|
19460
|
+
}).option("config", {
|
|
19461
|
+
describe: "Config file path",
|
|
19462
|
+
type: "string"
|
|
19463
|
+
}),
|
|
19464
|
+
async handler(args) {
|
|
19465
|
+
const a = args;
|
|
19466
|
+
const output = new OutputService;
|
|
19467
|
+
const envService = new EnvironmentService(output);
|
|
19468
|
+
try {
|
|
19469
|
+
await runWorkflowTagList({
|
|
19470
|
+
sortBy: a.sortBy,
|
|
19471
|
+
order: a.order,
|
|
19472
|
+
limit: a.limit,
|
|
19473
|
+
asJson: a.json,
|
|
19474
|
+
configPath: a.config,
|
|
19475
|
+
output,
|
|
19476
|
+
envService
|
|
19477
|
+
});
|
|
19478
|
+
} catch (error) {
|
|
19479
|
+
output.error(`Failed to list workflow tags: ${error}`);
|
|
19480
|
+
process.exit(1);
|
|
19481
|
+
} finally {
|
|
19482
|
+
await envService.dispose();
|
|
19483
|
+
}
|
|
19484
|
+
}
|
|
19485
|
+
};
|
|
19486
|
+
var WorkflowTagGetCommand = {
|
|
19487
|
+
command: "get <name>",
|
|
19488
|
+
describe: "Get details of a single workflow tag (usage_count, created_at, updated_at). Returns error if tag not in the workflow_tags table.",
|
|
19489
|
+
builder: (yargs) => yargs.positional("name", {
|
|
19490
|
+
describe: "Tag name",
|
|
19491
|
+
type: "string"
|
|
19492
|
+
}).option("json", {
|
|
19493
|
+
alias: "j",
|
|
19494
|
+
describe: "Output as JSON",
|
|
19495
|
+
type: "boolean",
|
|
19496
|
+
default: false
|
|
19497
|
+
}).option("config", {
|
|
19498
|
+
describe: "Config file path",
|
|
19499
|
+
type: "string"
|
|
19500
|
+
}).check((argv) => {
|
|
19501
|
+
if (typeof argv.name !== "string" || argv.name.length === 0) {
|
|
19502
|
+
throw new Error("Tag name is required");
|
|
19503
|
+
}
|
|
19504
|
+
if (argv.name.length > 50) {
|
|
19505
|
+
throw new Error(`Tag name exceeds 50 characters`);
|
|
19506
|
+
}
|
|
19507
|
+
return true;
|
|
19508
|
+
}),
|
|
19509
|
+
async handler(args) {
|
|
19510
|
+
const a = args;
|
|
19511
|
+
const output = new OutputService;
|
|
19512
|
+
const envService = new EnvironmentService(output);
|
|
19513
|
+
try {
|
|
19514
|
+
await runWorkflowTagGet({
|
|
19515
|
+
name: a.name,
|
|
19516
|
+
asJson: a.json,
|
|
19517
|
+
configPath: a.config,
|
|
19518
|
+
output,
|
|
19519
|
+
envService
|
|
19520
|
+
});
|
|
19521
|
+
} catch (error) {
|
|
19522
|
+
output.error(`Failed to get tag: ${error}`);
|
|
19523
|
+
process.exit(1);
|
|
19524
|
+
} finally {
|
|
19525
|
+
await envService.dispose();
|
|
19526
|
+
}
|
|
19527
|
+
}
|
|
19528
|
+
};
|
|
19529
|
+
var _runWorkflowTagListImpl = async function(opts) {
|
|
19530
|
+
const { output, envService } = opts;
|
|
19531
|
+
await envService.create({ configPath: opts.configPath });
|
|
19532
|
+
const env = envService.getEnvironment();
|
|
19533
|
+
if (!env) {
|
|
19534
|
+
output.error("Failed to create environment");
|
|
19535
|
+
process.exit(1);
|
|
19536
|
+
}
|
|
19537
|
+
const workflowComponent = env.getComponent("workflow");
|
|
19538
|
+
if (!workflowComponent) {
|
|
19539
|
+
output.error("WorkflowComponent not available");
|
|
19540
|
+
process.exit(1);
|
|
19541
|
+
}
|
|
19542
|
+
const service = workflowComponent.getService();
|
|
19543
|
+
if (!service) {
|
|
19544
|
+
output.error('WorkflowService not initialized. Please run "roy-agent workflow init" first.');
|
|
19545
|
+
process.exit(1);
|
|
19546
|
+
}
|
|
19547
|
+
const result = await callListTags(service, {
|
|
19548
|
+
sortBy: opts.sortBy ?? "usage_count",
|
|
19549
|
+
order: opts.order ?? "desc",
|
|
19550
|
+
limit: opts.limit ?? 100
|
|
19551
|
+
});
|
|
19552
|
+
if (opts.asJson) {
|
|
19553
|
+
output.json({
|
|
19554
|
+
tags: result.tags,
|
|
19555
|
+
total: result.total
|
|
19556
|
+
});
|
|
19557
|
+
return;
|
|
19558
|
+
}
|
|
19559
|
+
if (result.tags.length === 0) {
|
|
19560
|
+
output.log(chalk72.yellow("\uD83C\uDFF7️ No tags in the workflow_tags table yet."));
|
|
19561
|
+
output.log(chalk72.gray(" Tags are created automatically when you run `workflow add --tags <name>`."));
|
|
19562
|
+
return;
|
|
19563
|
+
}
|
|
19564
|
+
output.log(chalk72.bold(`\uD83C\uDFF7️ Workflow tags (${result.total}):`));
|
|
19565
|
+
output.log(chalk72.gray(` ${padRight("NAME", 24)}${padRight("USAGE", 8)}${padRight("CREATED", 22)}`));
|
|
19566
|
+
for (const t of result.tags) {
|
|
19567
|
+
const line = ` ${padRight(t.name, 24)}${padRight(String(t.usage_count), 8)}${padRight(formatDate2(t.created_at), 22)}`;
|
|
19568
|
+
output.log(line);
|
|
19569
|
+
}
|
|
19570
|
+
output.log(chalk72.gray(`
|
|
19571
|
+
\uD83D\uDCA1 Tip: when adding a new workflow, prefer tags from this list to ensure semantic consistency.`));
|
|
19572
|
+
};
|
|
19573
|
+
var _runWorkflowTagGetImpl = async function(opts) {
|
|
19574
|
+
const { output, envService } = opts;
|
|
19575
|
+
await envService.create({ configPath: opts.configPath });
|
|
19576
|
+
const env = envService.getEnvironment();
|
|
19577
|
+
if (!env) {
|
|
19578
|
+
output.error("Failed to create environment");
|
|
19579
|
+
process.exit(1);
|
|
19580
|
+
}
|
|
19581
|
+
const workflowComponent = env.getComponent("workflow");
|
|
19582
|
+
if (!workflowComponent) {
|
|
19583
|
+
output.error("WorkflowComponent not available");
|
|
19584
|
+
process.exit(1);
|
|
19585
|
+
}
|
|
19586
|
+
const service = workflowComponent.getService();
|
|
19587
|
+
if (!service) {
|
|
19588
|
+
output.error('WorkflowService not initialized. Please run "roy-agent workflow init" first.');
|
|
19589
|
+
process.exit(1);
|
|
19590
|
+
}
|
|
19591
|
+
const tag = callGetTag(service, opts.name);
|
|
19592
|
+
if (!tag) {
|
|
19593
|
+
if (opts.asJson) {
|
|
19594
|
+
output.json({ error: "Tag not found", name: opts.name });
|
|
19595
|
+
} else {
|
|
19596
|
+
output.error(`Tag "${opts.name}" not found in the workflow_tags table.`);
|
|
19597
|
+
output.log(chalk72.gray(`Tip: run \`roy-agent workflow tag list\` to see available tags.`));
|
|
19598
|
+
}
|
|
19599
|
+
process.exitCode = 1;
|
|
19600
|
+
return;
|
|
19601
|
+
}
|
|
19602
|
+
if (opts.asJson) {
|
|
19603
|
+
output.json(tag);
|
|
19604
|
+
return;
|
|
19605
|
+
}
|
|
19606
|
+
output.log(chalk72.bold(`\uD83C\uDFF7️ Tag: ${tag.name}`));
|
|
19607
|
+
output.log(chalk72.gray(` usage_count: ${tag.usage_count}`));
|
|
19608
|
+
output.log(chalk72.gray(` created_at: ${tag.created_at}`));
|
|
19609
|
+
output.log(chalk72.gray(` updated_at: ${tag.updated_at}`));
|
|
19610
|
+
};
|
|
19611
|
+
async function callListTags(service, options) {
|
|
19612
|
+
if (typeof service.listTags !== "function") {
|
|
19613
|
+
return { tags: [], total: 0 };
|
|
19614
|
+
}
|
|
19615
|
+
return await service.listTags(options);
|
|
19616
|
+
}
|
|
19617
|
+
function callGetTag(service, name) {
|
|
19618
|
+
if (typeof service.getTag !== "function") {
|
|
19619
|
+
return;
|
|
19620
|
+
}
|
|
19621
|
+
return service.getTag(name);
|
|
19622
|
+
}
|
|
19623
|
+
function padRight(str, width) {
|
|
19624
|
+
if (str.length >= width)
|
|
19625
|
+
return str.slice(0, width - 1) + " ";
|
|
19626
|
+
return str + " ".repeat(width - str.length);
|
|
19627
|
+
}
|
|
19628
|
+
function formatDate2(iso) {
|
|
19629
|
+
try {
|
|
19630
|
+
const d = new Date(iso);
|
|
19631
|
+
if (isNaN(d.getTime()))
|
|
19632
|
+
return iso;
|
|
19633
|
+
return d.toISOString().replace("T", " ").slice(0, 19);
|
|
19634
|
+
} catch {
|
|
19635
|
+
return iso;
|
|
19636
|
+
}
|
|
19637
|
+
}
|
|
19638
|
+
var runWorkflowTagList = wrapFunction4(_runWorkflowTagListImpl, "workflow.cli.tag.list", {
|
|
19639
|
+
recordParams: true,
|
|
19640
|
+
recordResult: false,
|
|
19641
|
+
log: false
|
|
19642
|
+
});
|
|
19643
|
+
var runWorkflowTagGet = wrapFunction4(_runWorkflowTagGetImpl, "workflow.cli.tag.get", {
|
|
19644
|
+
recordParams: true,
|
|
19645
|
+
recordResult: false,
|
|
19646
|
+
log: false
|
|
19647
|
+
});
|
|
19648
|
+
|
|
19142
19649
|
// src/commands/workflow/index.ts
|
|
19650
|
+
var WorkflowTagCommand = {
|
|
19651
|
+
command: "tag",
|
|
19652
|
+
describe: "Manage workflow tags — list and get from the workflow_tags table. Use BEFORE `workflow add` to discover existing tags.",
|
|
19653
|
+
builder: (yargs) => yargs.command(WorkflowTagListCommand).command(WorkflowTagGetCommand).demandCommand(1, "请指定 tag 子命令:list 或 get <name>").help(),
|
|
19654
|
+
handler() {}
|
|
19655
|
+
};
|
|
19143
19656
|
var WorkflowCommand = {
|
|
19144
19657
|
command: "workflow",
|
|
19145
19658
|
describe: "Workflow DAG management and execution - create, run, and monitor workflows",
|
|
19146
|
-
builder: (yargs) => yargs.command(WorkflowListCommand).command(WorkflowAddCommand).command(WorkflowNodesCommand).command(WorkflowValidateCommand).command(WorkflowGetCommand).command(WorkflowUpdateCommand).command(WorkflowRemoveCommand).command(WorkflowRunCommand).command(WorkflowStopCommand).command(WorkflowStatusCommand).demandCommand(1, "请指定子命令:list、add、validate、nodes、get、update、remove、run、stop、status\n\nResume: 使用 `workflow run -s <sessionId>` 恢复暂停的工作流").help(),
|
|
19659
|
+
builder: (yargs) => yargs.command(WorkflowListCommand).command(WorkflowAddCommand).command(WorkflowSearchCommand).command(WorkflowTagCommand).command(WorkflowNodesCommand).command(WorkflowValidateCommand).command(WorkflowGetCommand).command(WorkflowUpdateCommand).command(WorkflowRemoveCommand).command(WorkflowRunCommand).command(WorkflowStopCommand).command(WorkflowStatusCommand).demandCommand(1, "请指定子命令:list、add、search、tag、validate、nodes、get、update、remove、run、stop、status\n\nResume: 使用 `workflow run -s <sessionId>` 恢复暂停的工作流").help(),
|
|
19147
19660
|
handler() {}
|
|
19148
19661
|
};
|
|
19149
19662
|
|
|
Binary file
|