@ai-setting/roy-agent-cli 1.6.6 → 1.6.8
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 +280 -61
- package/dist/index.js +280 -61
- package/dist/roy-agent-linux-x64/bin/roy-agent +0 -0
- package/package.json +1 -1
package/dist/bin/roy-agent.js
CHANGED
|
@@ -7426,7 +7426,7 @@ var require_dist = __commonJS((exports) => {
|
|
|
7426
7426
|
var require_package = __commonJS((exports, module) => {
|
|
7427
7427
|
module.exports = {
|
|
7428
7428
|
name: "@ai-setting/roy-agent-cli",
|
|
7429
|
-
version: "1.6.
|
|
7429
|
+
version: "1.6.8",
|
|
7430
7430
|
type: "module",
|
|
7431
7431
|
description: "CLI for roy-agent - Non-interactive command execution",
|
|
7432
7432
|
main: "./dist/index.js",
|
|
@@ -9281,9 +9281,8 @@ bgprocess: ${bgProcessId}`;
|
|
|
9281
9281
|
Task #${taskId}`;
|
|
9282
9282
|
}
|
|
9283
9283
|
if (result) {
|
|
9284
|
-
const truncatedResult = result.length > 1e4 ? result.substring(0, 100) + "...[TRUNCATED]" : result;
|
|
9285
9284
|
message += `
|
|
9286
|
-
结果: ${
|
|
9285
|
+
结果: ${result}`;
|
|
9287
9286
|
}
|
|
9288
9287
|
message += this.appendSubSessionId(payload);
|
|
9289
9288
|
return message;
|
|
@@ -13704,7 +13703,13 @@ var TreeCommand = {
|
|
|
13704
13703
|
description: "以指定任务 ID 作为根开始构建子树(仅展示该任务及其后代)"
|
|
13705
13704
|
}).option("max-depth", {
|
|
13706
13705
|
type: "number",
|
|
13707
|
-
|
|
13706
|
+
alias: "depth",
|
|
13707
|
+
description: "[已弃用] 请使用 --depth;保留 1 版本兼容(alias)",
|
|
13708
|
+
hidden: true
|
|
13709
|
+
}).option("depth", {
|
|
13710
|
+
type: "number",
|
|
13711
|
+
description: "展示深度:0=只根任务(无 children),1=根+1 层,2=根+2 层(默认),-1=全部层级",
|
|
13712
|
+
default: 2
|
|
13708
13713
|
}).option("json", {
|
|
13709
13714
|
alias: "j",
|
|
13710
13715
|
type: "boolean",
|
|
@@ -13768,7 +13773,7 @@ var TreeCommand = {
|
|
|
13768
13773
|
output.log(chalk26.gray("No tasks to display."));
|
|
13769
13774
|
return;
|
|
13770
13775
|
}
|
|
13771
|
-
output.log(renderTaskTree(tree, { maxDepth: args.
|
|
13776
|
+
output.log(renderTaskTree(tree, { maxDepth: args.depth, rootId: args.rootId }));
|
|
13772
13777
|
} catch (error) {
|
|
13773
13778
|
output.error(`Failed to build task tree: ${error}`);
|
|
13774
13779
|
process.exit(1);
|
|
@@ -17476,6 +17481,47 @@ function resolveServerUrl(serverUrl, fallback) {
|
|
|
17476
17481
|
return trimmed;
|
|
17477
17482
|
}
|
|
17478
17483
|
|
|
17484
|
+
// src/lib/bounty-profile-reader.ts
|
|
17485
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
17486
|
+
import { homedir } from "node:os";
|
|
17487
|
+
import { join } from "node:path";
|
|
17488
|
+
function readBountyProfile(name, profilesDir) {
|
|
17489
|
+
if (!name)
|
|
17490
|
+
return null;
|
|
17491
|
+
const dir = profilesDir ?? join(homedir(), ".config", "bounty", "profiles");
|
|
17492
|
+
const profilePath = join(dir, `${name}.json`);
|
|
17493
|
+
if (!existsSync2(profilePath))
|
|
17494
|
+
return null;
|
|
17495
|
+
try {
|
|
17496
|
+
const raw = readFileSync(profilePath, "utf-8");
|
|
17497
|
+
const data = JSON.parse(raw);
|
|
17498
|
+
return {
|
|
17499
|
+
email: typeof data.email === "string" ? data.email : undefined,
|
|
17500
|
+
agent_id: typeof data.agent_id === "string" ? data.agent_id : undefined,
|
|
17501
|
+
api_base: typeof data.api_base === "string" ? data.api_base : undefined
|
|
17502
|
+
};
|
|
17503
|
+
} catch {
|
|
17504
|
+
return null;
|
|
17505
|
+
}
|
|
17506
|
+
}
|
|
17507
|
+
function profileToWsUrl(apiBase) {
|
|
17508
|
+
let url = apiBase.replace(/\/+$/, "");
|
|
17509
|
+
if (url.startsWith("ws://") || url.startsWith("wss://")) {
|
|
17510
|
+
if (url.endsWith("/ws"))
|
|
17511
|
+
return url;
|
|
17512
|
+
return `${url}/ws`;
|
|
17513
|
+
}
|
|
17514
|
+
if (url.startsWith("https://")) {
|
|
17515
|
+
url = "wss://" + url.slice("https://".length);
|
|
17516
|
+
} else if (url.startsWith("http://")) {
|
|
17517
|
+
url = "ws://" + url.slice("http://".length);
|
|
17518
|
+
}
|
|
17519
|
+
if (!url.endsWith("/ws")) {
|
|
17520
|
+
url = `${url}/ws`;
|
|
17521
|
+
}
|
|
17522
|
+
return url;
|
|
17523
|
+
}
|
|
17524
|
+
|
|
17479
17525
|
// src/commands/eventsource/add.ts
|
|
17480
17526
|
function uuid() {
|
|
17481
17527
|
return generateId();
|
|
@@ -17511,10 +17557,10 @@ var EventSourceAddCommand = {
|
|
|
17511
17557
|
describe: "Cron 表达式",
|
|
17512
17558
|
type: "string"
|
|
17513
17559
|
}).option("profile", {
|
|
17514
|
-
describe: "lark-cli
|
|
17560
|
+
describe: "Profile 名称(lark-cli / bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取配置;多 appId / 多账户场景必要,参考 #1637)",
|
|
17515
17561
|
type: "string"
|
|
17516
|
-
}).option("
|
|
17517
|
-
describe: "Agent IM
|
|
17562
|
+
}).option("email", {
|
|
17563
|
+
describe: "Agent IM 注册邮箱(bounty-im 类型用,v0.14 strict email-only;与 --profile 互斥)",
|
|
17518
17564
|
type: "string"
|
|
17519
17565
|
}).option("tls-skip-verify", {
|
|
17520
17566
|
describe: "跳过 TLS 证书校验(bounty-im 类型用,wss:// 自签名场景,生产环境不推荐)",
|
|
@@ -17541,9 +17587,38 @@ var EventSourceAddCommand = {
|
|
|
17541
17587
|
process.exit(1);
|
|
17542
17588
|
}
|
|
17543
17589
|
const eventTypes = a.eventTypes?.split(",").map((s) => s.trim());
|
|
17590
|
+
let resolvedEmail = a.email;
|
|
17591
|
+
let resolvedProfileName = a.profile;
|
|
17592
|
+
let profileApiBase;
|
|
17593
|
+
if (a.type === "bounty-im") {
|
|
17594
|
+
if (a.email && a.profile) {
|
|
17595
|
+
output.error(chalk59.red(`
|
|
17596
|
+
✗ --email 和 --profile 互斥(profile 文件已包含 email)。请选择其一。
|
|
17597
|
+
`));
|
|
17598
|
+
process.exit(1);
|
|
17599
|
+
}
|
|
17600
|
+
if (a.profile) {
|
|
17601
|
+
const profile = readBountyProfile(a.profile);
|
|
17602
|
+
if (!profile) {
|
|
17603
|
+
output.error(chalk59.red(`
|
|
17604
|
+
✗ Profile '${a.profile}' 不存在或格式错误。期望路径:~/.config/bounty/profiles/${a.profile}.json
|
|
17605
|
+
`));
|
|
17606
|
+
process.exit(1);
|
|
17607
|
+
}
|
|
17608
|
+
resolvedEmail = profile.email;
|
|
17609
|
+
profileApiBase = profile.api_base;
|
|
17610
|
+
}
|
|
17611
|
+
}
|
|
17544
17612
|
const envUrl = process.env.BOUNTY_SERVER_URL;
|
|
17545
17613
|
const fallback = envUrl || "http://localhost:8787";
|
|
17546
|
-
|
|
17614
|
+
let resolvedServerUrl;
|
|
17615
|
+
if (a.serverUrl || a.imServerUrl) {
|
|
17616
|
+
resolvedServerUrl = resolveServerUrl(a.serverUrl || a.imServerUrl, fallback);
|
|
17617
|
+
} else if (a.type === "bounty-im" && profileApiBase) {
|
|
17618
|
+
resolvedServerUrl = profileToWsUrl(profileApiBase);
|
|
17619
|
+
} else {
|
|
17620
|
+
resolvedServerUrl = resolveServerUrl(undefined, fallback);
|
|
17621
|
+
}
|
|
17547
17622
|
const config = {
|
|
17548
17623
|
id: uuid(),
|
|
17549
17624
|
name: a.name,
|
|
@@ -17555,7 +17630,7 @@ var EventSourceAddCommand = {
|
|
|
17555
17630
|
interval: a.interval,
|
|
17556
17631
|
cron: a.cron,
|
|
17557
17632
|
profile: a.profile,
|
|
17558
|
-
|
|
17633
|
+
email: resolvedEmail,
|
|
17559
17634
|
imServerUrl: resolvedServerUrl,
|
|
17560
17635
|
tlsSkipVerify: a.tlsSkipVerify === true,
|
|
17561
17636
|
options: a.prompt ? { prompt: a.prompt } : undefined
|
|
@@ -17574,11 +17649,11 @@ var EventSourceAddCommand = {
|
|
|
17574
17649
|
if (a.interval) {
|
|
17575
17650
|
output.log(` Interval: ${chalk59.gray(`${a.interval}ms`)}`);
|
|
17576
17651
|
}
|
|
17577
|
-
if (
|
|
17578
|
-
output.log(` Profile: ${chalk59.gray(
|
|
17652
|
+
if (resolvedProfileName) {
|
|
17653
|
+
output.log(` Profile: ${chalk59.gray(resolvedProfileName)}`);
|
|
17579
17654
|
}
|
|
17580
|
-
if (
|
|
17581
|
-
output.log(`
|
|
17655
|
+
if (resolvedEmail) {
|
|
17656
|
+
output.log(` Email: ${chalk59.gray(resolvedEmail)}`);
|
|
17582
17657
|
}
|
|
17583
17658
|
if (a.imServerUrl) {
|
|
17584
17659
|
output.log(` IM Server URL: ${chalk59.gray(a.imServerUrl)}`);
|
|
@@ -17644,8 +17719,11 @@ var EventSourceUpdateCommand = {
|
|
|
17644
17719
|
}).option("enabled", {
|
|
17645
17720
|
describe: "是否启用",
|
|
17646
17721
|
type: "boolean"
|
|
17647
|
-
}).option("
|
|
17648
|
-
describe: "Agent IM
|
|
17722
|
+
}).option("email", {
|
|
17723
|
+
describe: "Agent IM 注册邮箱(bounty-im 类型用,v0.14 strict email-only;与 --profile 互斥)",
|
|
17724
|
+
type: "string"
|
|
17725
|
+
}).option("profile", {
|
|
17726
|
+
describe: "Profile 名称(bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取并自动更新 email + imServerUrl)",
|
|
17649
17727
|
type: "string"
|
|
17650
17728
|
}).option("tls-skip-verify", {
|
|
17651
17729
|
describe: "跳过 TLS 证书校验(bounty-im 类型用,wss:// 自签名场景,生产环境不推荐)",
|
|
@@ -17680,6 +17758,25 @@ var EventSourceUpdateCommand = {
|
|
|
17680
17758
|
}
|
|
17681
17759
|
process.exit(1);
|
|
17682
17760
|
}
|
|
17761
|
+
if (match.source.type === "bounty-im" && a.email && a.profile) {
|
|
17762
|
+
output.error(chalk60.red(`
|
|
17763
|
+
✗ --email 和 --profile 互斥(profile 文件已包含 email)。请选择其一。
|
|
17764
|
+
`));
|
|
17765
|
+
process.exit(1);
|
|
17766
|
+
}
|
|
17767
|
+
let profileEmail;
|
|
17768
|
+
let profileApiBase;
|
|
17769
|
+
if (a.profile && match.source.type === "bounty-im") {
|
|
17770
|
+
const profile = readBountyProfile(a.profile);
|
|
17771
|
+
if (!profile) {
|
|
17772
|
+
output.error(chalk60.red(`
|
|
17773
|
+
✗ Profile '${a.profile}' 不存在或格式错误。期望路径:~/.config/bounty/profiles/${a.profile}.json
|
|
17774
|
+
`));
|
|
17775
|
+
process.exit(1);
|
|
17776
|
+
}
|
|
17777
|
+
profileEmail = profile.email;
|
|
17778
|
+
profileApiBase = profile.api_base;
|
|
17779
|
+
}
|
|
17683
17780
|
const partial = {};
|
|
17684
17781
|
if (a.name !== undefined)
|
|
17685
17782
|
partial.name = a.name;
|
|
@@ -17696,12 +17793,18 @@ var EventSourceUpdateCommand = {
|
|
|
17696
17793
|
partial.cron = a.cron;
|
|
17697
17794
|
if (a.enabled !== undefined)
|
|
17698
17795
|
partial.enabled = a.enabled;
|
|
17699
|
-
if (a.
|
|
17700
|
-
partial.
|
|
17701
|
-
if (
|
|
17796
|
+
if (a.email !== undefined)
|
|
17797
|
+
partial.email = a.email;
|
|
17798
|
+
if (profileEmail !== undefined)
|
|
17799
|
+
partial.email = profileEmail;
|
|
17800
|
+
if (a.serverUrl !== undefined || a.imServerUrl !== undefined || profileApiBase !== undefined) {
|
|
17702
17801
|
const envUrl = process.env.BOUNTY_SERVER_URL;
|
|
17703
17802
|
const fallback = envUrl || "http://localhost:8787";
|
|
17704
|
-
|
|
17803
|
+
if (a.serverUrl !== undefined || a.imServerUrl !== undefined) {
|
|
17804
|
+
partial.imServerUrl = resolveServerUrl(a.serverUrl ?? a.imServerUrl, fallback);
|
|
17805
|
+
} else if (profileApiBase !== undefined) {
|
|
17806
|
+
partial.imServerUrl = profileToWsUrl(profileApiBase);
|
|
17807
|
+
}
|
|
17705
17808
|
}
|
|
17706
17809
|
if (a.tlsSkipVerify !== undefined)
|
|
17707
17810
|
partial.tlsSkipVerify = a.tlsSkipVerify === true;
|
|
@@ -19147,6 +19250,121 @@ class DecoratorNodeValidator extends BaseNodeValidator {
|
|
|
19147
19250
|
}
|
|
19148
19251
|
}
|
|
19149
19252
|
|
|
19253
|
+
// src/commands/workflow/validators/nodes/python-call-node-validator.ts
|
|
19254
|
+
class PythonCallNodeValidator extends BaseNodeValidator {
|
|
19255
|
+
nodeType = "python_call";
|
|
19256
|
+
getRequiredFields() {
|
|
19257
|
+
return ["module", "function"];
|
|
19258
|
+
}
|
|
19259
|
+
validateTypeSpecific(node) {
|
|
19260
|
+
const errors = [];
|
|
19261
|
+
const config = node.config ?? {};
|
|
19262
|
+
const moduleVal = config.module;
|
|
19263
|
+
if (moduleVal === undefined || moduleVal === null) {
|
|
19264
|
+
errors.push({
|
|
19265
|
+
type: "MISSING_REQUIRED_FIELD" /* MISSING_REQUIRED_FIELD */,
|
|
19266
|
+
description: 'Field "module" is required for python_call node',
|
|
19267
|
+
expected: 'module: "<python.module.path>"',
|
|
19268
|
+
actual: "undefined",
|
|
19269
|
+
fix: 'Add `module: "<python.module.path>"` to the node config',
|
|
19270
|
+
nodeId: node.id
|
|
19271
|
+
});
|
|
19272
|
+
} else if (typeof moduleVal !== "string") {
|
|
19273
|
+
errors.push({
|
|
19274
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19275
|
+
description: 'Field "module" has invalid type',
|
|
19276
|
+
expected: 'string (Python module path, e.g. "investment_strategy.scripts.market_timing")',
|
|
19277
|
+
actual: typeof moduleVal,
|
|
19278
|
+
fix: "Change `module` to a string",
|
|
19279
|
+
nodeId: node.id
|
|
19280
|
+
});
|
|
19281
|
+
} else if (!/^[A-Za-z_]\w*(\.[A-Za-z_]\w*)*$/.test(moduleVal)) {
|
|
19282
|
+
errors.push({
|
|
19283
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19284
|
+
description: `Field "module" is not a valid Python module path: "${moduleVal}"`,
|
|
19285
|
+
expected: 'dotted identifier like "pkg.sub.mod"',
|
|
19286
|
+
actual: moduleVal,
|
|
19287
|
+
fix: "Use only letters, digits, underscores, and dots",
|
|
19288
|
+
nodeId: node.id
|
|
19289
|
+
});
|
|
19290
|
+
}
|
|
19291
|
+
const fnVal = config.function;
|
|
19292
|
+
if (fnVal === undefined || fnVal === null) {
|
|
19293
|
+
errors.push({
|
|
19294
|
+
type: "MISSING_REQUIRED_FIELD" /* MISSING_REQUIRED_FIELD */,
|
|
19295
|
+
description: 'Field "function" is required for python_call node',
|
|
19296
|
+
expected: 'function: "<python_function_name>"',
|
|
19297
|
+
actual: "undefined",
|
|
19298
|
+
fix: 'Add `function: "<name>"` to the node config',
|
|
19299
|
+
nodeId: node.id
|
|
19300
|
+
});
|
|
19301
|
+
} else if (typeof fnVal !== "string") {
|
|
19302
|
+
errors.push({
|
|
19303
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19304
|
+
description: 'Field "function" has invalid type',
|
|
19305
|
+
expected: 'string (Python function name, e.g. "run")',
|
|
19306
|
+
actual: typeof fnVal,
|
|
19307
|
+
fix: "Change `function` to a string",
|
|
19308
|
+
nodeId: node.id
|
|
19309
|
+
});
|
|
19310
|
+
} else if (!/^[A-Za-z_]\w*$/.test(fnVal)) {
|
|
19311
|
+
errors.push({
|
|
19312
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19313
|
+
description: `Field "function" is not a valid Python identifier: "${fnVal}"`,
|
|
19314
|
+
expected: "Python identifier: starts with letter/underscore, contains only [A-Za-z0-9_]",
|
|
19315
|
+
actual: fnVal,
|
|
19316
|
+
fix: "Use a plain Python function name (no dots, no operators)",
|
|
19317
|
+
nodeId: node.id
|
|
19318
|
+
});
|
|
19319
|
+
}
|
|
19320
|
+
const argsVal = config.args;
|
|
19321
|
+
if (argsVal !== undefined && (typeof argsVal !== "object" || argsVal === null || Array.isArray(argsVal))) {
|
|
19322
|
+
errors.push({
|
|
19323
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19324
|
+
description: 'Field "args" has invalid type',
|
|
19325
|
+
expected: "object (kwargs to pass to the function)",
|
|
19326
|
+
actual: Array.isArray(argsVal) ? "array" : typeof argsVal,
|
|
19327
|
+
fix: "Change `args` to an object: args: { key: value }",
|
|
19328
|
+
nodeId: node.id
|
|
19329
|
+
});
|
|
19330
|
+
}
|
|
19331
|
+
if (config.cwd !== undefined && typeof config.cwd !== "string") {
|
|
19332
|
+
errors.push({
|
|
19333
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19334
|
+
description: 'Field "cwd" has invalid type',
|
|
19335
|
+
expected: "string (filesystem path)",
|
|
19336
|
+
actual: typeof config.cwd,
|
|
19337
|
+
fix: "Change `cwd` to a string",
|
|
19338
|
+
nodeId: node.id
|
|
19339
|
+
});
|
|
19340
|
+
}
|
|
19341
|
+
if (config.python !== undefined && typeof config.python !== "string") {
|
|
19342
|
+
errors.push({
|
|
19343
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19344
|
+
description: 'Field "python" has invalid type',
|
|
19345
|
+
expected: "string (path to python interpreter)",
|
|
19346
|
+
actual: typeof config.python,
|
|
19347
|
+
fix: "Change `python` to a string",
|
|
19348
|
+
nodeId: node.id
|
|
19349
|
+
});
|
|
19350
|
+
}
|
|
19351
|
+
if (config.timeout !== undefined) {
|
|
19352
|
+
const t = config.timeout;
|
|
19353
|
+
if (typeof t !== "number" || !Number.isFinite(t) || t <= 0) {
|
|
19354
|
+
errors.push({
|
|
19355
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19356
|
+
description: 'Field "timeout" has invalid type',
|
|
19357
|
+
expected: "positive number (milliseconds)",
|
|
19358
|
+
actual: typeof t === "number" ? `${t}` : typeof t,
|
|
19359
|
+
fix: "Change `timeout` to a positive number, e.g. timeout: 60000",
|
|
19360
|
+
nodeId: node.id
|
|
19361
|
+
});
|
|
19362
|
+
}
|
|
19363
|
+
}
|
|
19364
|
+
return errors;
|
|
19365
|
+
}
|
|
19366
|
+
}
|
|
19367
|
+
|
|
19150
19368
|
// src/commands/workflow/validators/node-validator-factory.ts
|
|
19151
19369
|
var validators = new Map;
|
|
19152
19370
|
validators.set("tool", new ToolNodeValidator);
|
|
@@ -19156,6 +19374,7 @@ validators.set("workflow", new WorkflowNodeValidator);
|
|
|
19156
19374
|
validators.set("condition", new ConditionNodeValidator);
|
|
19157
19375
|
validators.set("merge", new MergeNodeValidator);
|
|
19158
19376
|
validators.set("decorator", new DecoratorNodeValidator);
|
|
19377
|
+
validators.set("python_call", new PythonCallNodeValidator);
|
|
19159
19378
|
function getNodeValidator(type) {
|
|
19160
19379
|
return validators.get(type) || null;
|
|
19161
19380
|
}
|
|
@@ -20880,7 +21099,7 @@ Use `) + chalk74.cyan("roy-agent workflow nodes <type>") + chalk74.gray(" for de
|
|
|
20880
21099
|
|
|
20881
21100
|
// src/commands/workflow/commands/validate.ts
|
|
20882
21101
|
import chalk75 from "chalk";
|
|
20883
|
-
import { readFileSync } from "fs";
|
|
21102
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
20884
21103
|
async function parseWorkflowInput(input, yamlStr) {
|
|
20885
21104
|
const parseYaml = async (content) => {
|
|
20886
21105
|
const YAML2 = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
@@ -20888,7 +21107,7 @@ async function parseWorkflowInput(input, yamlStr) {
|
|
|
20888
21107
|
};
|
|
20889
21108
|
if (input && !yamlStr) {
|
|
20890
21109
|
try {
|
|
20891
|
-
const content =
|
|
21110
|
+
const content = readFileSync2(input, "utf-8");
|
|
20892
21111
|
return await parseYaml(content);
|
|
20893
21112
|
} catch (error) {
|
|
20894
21113
|
throw new Error(`Failed to read file "${input}": ${error.message}`);
|
|
@@ -21623,24 +21842,24 @@ var LspCommand = {
|
|
|
21623
21842
|
|
|
21624
21843
|
// src/commands/install/index.ts
|
|
21625
21844
|
import { spawnSync } from "node:child_process";
|
|
21626
|
-
import { existsSync as
|
|
21627
|
-
import { join as
|
|
21628
|
-
import { homedir as
|
|
21845
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync, cpSync } from "node:fs";
|
|
21846
|
+
import { join as join5, resolve } from "node:path";
|
|
21847
|
+
import { homedir as homedir4 } from "node:os";
|
|
21629
21848
|
function getConfigDir(scope) {
|
|
21630
|
-
return scope === "global" ?
|
|
21849
|
+
return scope === "global" ? join5(homedir4(), ".roy-agent") : join5(process.cwd(), ".roy");
|
|
21631
21850
|
}
|
|
21632
21851
|
function detectDefaultScope() {
|
|
21633
|
-
const projectDir =
|
|
21634
|
-
return
|
|
21852
|
+
const projectDir = join5(process.cwd(), ".roy");
|
|
21853
|
+
return existsSync4(projectDir) ? "project" : "global";
|
|
21635
21854
|
}
|
|
21636
21855
|
function getConfigPath(scope) {
|
|
21637
|
-
return
|
|
21856
|
+
return join5(getConfigDir(scope), "plugins.json");
|
|
21638
21857
|
}
|
|
21639
21858
|
function loadPlugins(scope) {
|
|
21640
21859
|
const configPath = getConfigPath(scope);
|
|
21641
21860
|
try {
|
|
21642
|
-
if (
|
|
21643
|
-
const raw =
|
|
21861
|
+
if (existsSync4(configPath)) {
|
|
21862
|
+
const raw = readFileSync3(configPath, "utf-8");
|
|
21644
21863
|
const config = JSON.parse(raw);
|
|
21645
21864
|
return config.plugins ?? [];
|
|
21646
21865
|
}
|
|
@@ -21650,7 +21869,7 @@ function loadPlugins(scope) {
|
|
|
21650
21869
|
function savePlugins(plugins, scope) {
|
|
21651
21870
|
const configDir = getConfigDir(scope);
|
|
21652
21871
|
const configPath = getConfigPath(scope);
|
|
21653
|
-
if (!
|
|
21872
|
+
if (!existsSync4(configDir)) {
|
|
21654
21873
|
mkdirSync(configDir, { recursive: true });
|
|
21655
21874
|
}
|
|
21656
21875
|
const config = { plugins };
|
|
@@ -21666,10 +21885,10 @@ function stripVersionSpec(packageName) {
|
|
|
21666
21885
|
function readPackageInfo(packageName) {
|
|
21667
21886
|
const bareName = packageName.startsWith("/") || packageName.startsWith(".") ? packageName : stripVersionSpec(packageName);
|
|
21668
21887
|
if (packageName.startsWith("/") || packageName.startsWith(".")) {
|
|
21669
|
-
const localPkgPath =
|
|
21670
|
-
if (
|
|
21888
|
+
const localPkgPath = join5(packageName, "package.json");
|
|
21889
|
+
if (existsSync4(localPkgPath)) {
|
|
21671
21890
|
try {
|
|
21672
|
-
const pkg = JSON.parse(
|
|
21891
|
+
const pkg = JSON.parse(readFileSync3(localPkgPath, "utf-8"));
|
|
21673
21892
|
return {
|
|
21674
21893
|
version: pkg.version ?? "0.0.0",
|
|
21675
21894
|
name: pkg.name ?? packageName,
|
|
@@ -21681,19 +21900,19 @@ function readPackageInfo(packageName) {
|
|
|
21681
21900
|
}
|
|
21682
21901
|
}
|
|
21683
21902
|
const searchPaths = [
|
|
21684
|
-
|
|
21903
|
+
join5(process.cwd(), "node_modules", bareName, "package.json"),
|
|
21685
21904
|
resolve(process.cwd(), "..", "node_modules", bareName, "package.json"),
|
|
21686
|
-
|
|
21687
|
-
|
|
21905
|
+
join5(process.cwd(), ".roy", "plugins", bareName, "package.json"),
|
|
21906
|
+
join5(homedir4(), ".roy-agent", "node_modules", bareName, "package.json"),
|
|
21688
21907
|
...(() => {
|
|
21689
21908
|
const globalRoot = getNpmGlobalRoot();
|
|
21690
|
-
return globalRoot ? [
|
|
21909
|
+
return globalRoot ? [join5(globalRoot, bareName, "package.json")] : [];
|
|
21691
21910
|
})()
|
|
21692
21911
|
];
|
|
21693
21912
|
for (const pkgPath of searchPaths) {
|
|
21694
21913
|
try {
|
|
21695
|
-
if (
|
|
21696
|
-
const pkg = JSON.parse(
|
|
21914
|
+
if (existsSync4(pkgPath)) {
|
|
21915
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
21697
21916
|
return {
|
|
21698
21917
|
version: pkg.version ?? "0.0.0",
|
|
21699
21918
|
name: pkg.name ?? bareName,
|
|
@@ -21716,15 +21935,15 @@ function getNpmGlobalRoot() {
|
|
|
21716
21935
|
return null;
|
|
21717
21936
|
}
|
|
21718
21937
|
function getPackageManagerCommand() {
|
|
21719
|
-
if (
|
|
21720
|
-
if (
|
|
21938
|
+
if (existsSync4(join5(process.cwd(), "pnpm-lock.yaml"))) {
|
|
21939
|
+
if (existsSync4(join5(process.cwd(), "pnpm-workspace.yaml"))) {
|
|
21721
21940
|
return "pnpm -w";
|
|
21722
21941
|
}
|
|
21723
21942
|
return "pnpm";
|
|
21724
21943
|
}
|
|
21725
|
-
if (
|
|
21944
|
+
if (existsSync4(join5(process.cwd(), "yarn.lock")))
|
|
21726
21945
|
return "yarn";
|
|
21727
|
-
if (
|
|
21946
|
+
if (existsSync4(join5(process.cwd(), "bun.lock")) || existsSync4(join5(process.cwd(), "bun.lockb")))
|
|
21728
21947
|
return "bun";
|
|
21729
21948
|
return "npm";
|
|
21730
21949
|
}
|
|
@@ -21763,14 +21982,14 @@ var InstallPackageCommand = {
|
|
|
21763
21982
|
}
|
|
21764
21983
|
resolvedName = info2.name;
|
|
21765
21984
|
const srcDir = resolve(packageName);
|
|
21766
|
-
if (!
|
|
21985
|
+
if (!existsSync4(srcDir)) {
|
|
21767
21986
|
console.error(`
|
|
21768
21987
|
❌ Local path '${srcDir}' does not exist.
|
|
21769
21988
|
`);
|
|
21770
21989
|
process.exit(1);
|
|
21771
21990
|
}
|
|
21772
|
-
const pluginDir =
|
|
21773
|
-
if (!
|
|
21991
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
|
|
21992
|
+
if (!existsSync4(pluginDir)) {
|
|
21774
21993
|
mkdirSync(pluginDir, { recursive: true });
|
|
21775
21994
|
}
|
|
21776
21995
|
const result = spawnSync("cp", ["-r", `${srcDir}/.`, pluginDir], {
|
|
@@ -21805,12 +22024,12 @@ var InstallPackageCommand = {
|
|
|
21805
22024
|
process.exit(1);
|
|
21806
22025
|
}
|
|
21807
22026
|
resolvedName = info2.name;
|
|
21808
|
-
const pluginDir =
|
|
21809
|
-
if (!
|
|
22027
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
|
|
22028
|
+
if (!existsSync4(pluginDir)) {
|
|
21810
22029
|
mkdirSync(pluginDir, { recursive: true });
|
|
21811
22030
|
}
|
|
21812
|
-
const nmPath =
|
|
21813
|
-
if (
|
|
22031
|
+
const nmPath = join5(process.cwd(), "node_modules", packageName);
|
|
22032
|
+
if (existsSync4(nmPath)) {
|
|
21814
22033
|
spawnSync("cp", ["-r", `${nmPath}/.`, pluginDir], { stdio: "inherit", shell: false });
|
|
21815
22034
|
}
|
|
21816
22035
|
}
|
|
@@ -21841,14 +22060,14 @@ var InstallPackageCommand = {
|
|
|
21841
22060
|
`);
|
|
21842
22061
|
process.exit(1);
|
|
21843
22062
|
}
|
|
21844
|
-
const globalNm =
|
|
21845
|
-
if (!
|
|
21846
|
-
mkdirSync(
|
|
22063
|
+
const globalNm = join5(homedir4(), ".roy-agent", "node_modules", resolvedGlobalName);
|
|
22064
|
+
if (!existsSync4(globalNm)) {
|
|
22065
|
+
mkdirSync(join5(homedir4(), ".roy-agent", "node_modules"), { recursive: true });
|
|
21847
22066
|
const rootResult = spawnSync("npm", ["root", "-g"], { stdio: "pipe", shell: false });
|
|
21848
22067
|
const globalRoot = rootResult.stdout?.toString().trim();
|
|
21849
22068
|
if (globalRoot) {
|
|
21850
|
-
const globalInstalled =
|
|
21851
|
-
if (
|
|
22069
|
+
const globalInstalled = join5(globalRoot, resolvedGlobalName);
|
|
22070
|
+
if (existsSync4(globalInstalled)) {
|
|
21852
22071
|
cpSync(globalInstalled, globalNm, { recursive: true });
|
|
21853
22072
|
}
|
|
21854
22073
|
}
|
|
@@ -21959,8 +22178,8 @@ var InstallRemoveCommand = {
|
|
|
21959
22178
|
\uD83D\uDDD1️ Removing plugin: ${plugin.packageName}@${plugin.version} (${scope})
|
|
21960
22179
|
`);
|
|
21961
22180
|
if (scope === "project") {
|
|
21962
|
-
const pluginDir =
|
|
21963
|
-
if (
|
|
22181
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", plugin.packageName);
|
|
22182
|
+
if (existsSync4(pluginDir)) {
|
|
21964
22183
|
spawnSync("rm", ["-rf", pluginDir], { stdio: "inherit", shell: false });
|
|
21965
22184
|
console.log(` Removed plugin directory: ${pluginDir}`);
|
|
21966
22185
|
}
|
|
@@ -21975,8 +22194,8 @@ var InstallRemoveCommand = {
|
|
|
21975
22194
|
`);
|
|
21976
22195
|
process.exit(result.status ?? 1);
|
|
21977
22196
|
}
|
|
21978
|
-
const globalNm =
|
|
21979
|
-
if (
|
|
22197
|
+
const globalNm = join5(homedir4(), ".roy-agent", "node_modules", plugin.packageName);
|
|
22198
|
+
if (existsSync4(globalNm)) {
|
|
21980
22199
|
spawnSync("rm", ["-rf", globalNm], { stdio: "inherit", shell: false });
|
|
21981
22200
|
}
|
|
21982
22201
|
}
|
package/dist/index.js
CHANGED
|
@@ -7425,7 +7425,7 @@ var require_dist = __commonJS((exports) => {
|
|
|
7425
7425
|
var require_package = __commonJS((exports, module) => {
|
|
7426
7426
|
module.exports = {
|
|
7427
7427
|
name: "@ai-setting/roy-agent-cli",
|
|
7428
|
-
version: "1.6.
|
|
7428
|
+
version: "1.6.8",
|
|
7429
7429
|
type: "module",
|
|
7430
7430
|
description: "CLI for roy-agent - Non-interactive command execution",
|
|
7431
7431
|
main: "./dist/index.js",
|
|
@@ -9280,9 +9280,8 @@ bgprocess: ${bgProcessId}`;
|
|
|
9280
9280
|
Task #${taskId}`;
|
|
9281
9281
|
}
|
|
9282
9282
|
if (result) {
|
|
9283
|
-
const truncatedResult = result.length > 1e4 ? result.substring(0, 100) + "...[TRUNCATED]" : result;
|
|
9284
9283
|
message += `
|
|
9285
|
-
结果: ${
|
|
9284
|
+
结果: ${result}`;
|
|
9286
9285
|
}
|
|
9287
9286
|
message += this.appendSubSessionId(payload);
|
|
9288
9287
|
return message;
|
|
@@ -13703,7 +13702,13 @@ var TreeCommand = {
|
|
|
13703
13702
|
description: "以指定任务 ID 作为根开始构建子树(仅展示该任务及其后代)"
|
|
13704
13703
|
}).option("max-depth", {
|
|
13705
13704
|
type: "number",
|
|
13706
|
-
|
|
13705
|
+
alias: "depth",
|
|
13706
|
+
description: "[已弃用] 请使用 --depth;保留 1 版本兼容(alias)",
|
|
13707
|
+
hidden: true
|
|
13708
|
+
}).option("depth", {
|
|
13709
|
+
type: "number",
|
|
13710
|
+
description: "展示深度:0=只根任务(无 children),1=根+1 层,2=根+2 层(默认),-1=全部层级",
|
|
13711
|
+
default: 2
|
|
13707
13712
|
}).option("json", {
|
|
13708
13713
|
alias: "j",
|
|
13709
13714
|
type: "boolean",
|
|
@@ -13767,7 +13772,7 @@ var TreeCommand = {
|
|
|
13767
13772
|
output.log(chalk26.gray("No tasks to display."));
|
|
13768
13773
|
return;
|
|
13769
13774
|
}
|
|
13770
|
-
output.log(renderTaskTree(tree, { maxDepth: args.
|
|
13775
|
+
output.log(renderTaskTree(tree, { maxDepth: args.depth, rootId: args.rootId }));
|
|
13771
13776
|
} catch (error) {
|
|
13772
13777
|
output.error(`Failed to build task tree: ${error}`);
|
|
13773
13778
|
process.exit(1);
|
|
@@ -17475,6 +17480,47 @@ function resolveServerUrl(serverUrl, fallback) {
|
|
|
17475
17480
|
return trimmed;
|
|
17476
17481
|
}
|
|
17477
17482
|
|
|
17483
|
+
// src/lib/bounty-profile-reader.ts
|
|
17484
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
17485
|
+
import { homedir } from "node:os";
|
|
17486
|
+
import { join } from "node:path";
|
|
17487
|
+
function readBountyProfile(name, profilesDir) {
|
|
17488
|
+
if (!name)
|
|
17489
|
+
return null;
|
|
17490
|
+
const dir = profilesDir ?? join(homedir(), ".config", "bounty", "profiles");
|
|
17491
|
+
const profilePath = join(dir, `${name}.json`);
|
|
17492
|
+
if (!existsSync2(profilePath))
|
|
17493
|
+
return null;
|
|
17494
|
+
try {
|
|
17495
|
+
const raw = readFileSync(profilePath, "utf-8");
|
|
17496
|
+
const data = JSON.parse(raw);
|
|
17497
|
+
return {
|
|
17498
|
+
email: typeof data.email === "string" ? data.email : undefined,
|
|
17499
|
+
agent_id: typeof data.agent_id === "string" ? data.agent_id : undefined,
|
|
17500
|
+
api_base: typeof data.api_base === "string" ? data.api_base : undefined
|
|
17501
|
+
};
|
|
17502
|
+
} catch {
|
|
17503
|
+
return null;
|
|
17504
|
+
}
|
|
17505
|
+
}
|
|
17506
|
+
function profileToWsUrl(apiBase) {
|
|
17507
|
+
let url = apiBase.replace(/\/+$/, "");
|
|
17508
|
+
if (url.startsWith("ws://") || url.startsWith("wss://")) {
|
|
17509
|
+
if (url.endsWith("/ws"))
|
|
17510
|
+
return url;
|
|
17511
|
+
return `${url}/ws`;
|
|
17512
|
+
}
|
|
17513
|
+
if (url.startsWith("https://")) {
|
|
17514
|
+
url = "wss://" + url.slice("https://".length);
|
|
17515
|
+
} else if (url.startsWith("http://")) {
|
|
17516
|
+
url = "ws://" + url.slice("http://".length);
|
|
17517
|
+
}
|
|
17518
|
+
if (!url.endsWith("/ws")) {
|
|
17519
|
+
url = `${url}/ws`;
|
|
17520
|
+
}
|
|
17521
|
+
return url;
|
|
17522
|
+
}
|
|
17523
|
+
|
|
17478
17524
|
// src/commands/eventsource/add.ts
|
|
17479
17525
|
function uuid() {
|
|
17480
17526
|
return generateId();
|
|
@@ -17510,10 +17556,10 @@ var EventSourceAddCommand = {
|
|
|
17510
17556
|
describe: "Cron 表达式",
|
|
17511
17557
|
type: "string"
|
|
17512
17558
|
}).option("profile", {
|
|
17513
|
-
describe: "lark-cli
|
|
17559
|
+
describe: "Profile 名称(lark-cli / bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取配置;多 appId / 多账户场景必要,参考 #1637)",
|
|
17514
17560
|
type: "string"
|
|
17515
|
-
}).option("
|
|
17516
|
-
describe: "Agent IM
|
|
17561
|
+
}).option("email", {
|
|
17562
|
+
describe: "Agent IM 注册邮箱(bounty-im 类型用,v0.14 strict email-only;与 --profile 互斥)",
|
|
17517
17563
|
type: "string"
|
|
17518
17564
|
}).option("tls-skip-verify", {
|
|
17519
17565
|
describe: "跳过 TLS 证书校验(bounty-im 类型用,wss:// 自签名场景,生产环境不推荐)",
|
|
@@ -17540,9 +17586,38 @@ var EventSourceAddCommand = {
|
|
|
17540
17586
|
process.exit(1);
|
|
17541
17587
|
}
|
|
17542
17588
|
const eventTypes = a.eventTypes?.split(",").map((s) => s.trim());
|
|
17589
|
+
let resolvedEmail = a.email;
|
|
17590
|
+
let resolvedProfileName = a.profile;
|
|
17591
|
+
let profileApiBase;
|
|
17592
|
+
if (a.type === "bounty-im") {
|
|
17593
|
+
if (a.email && a.profile) {
|
|
17594
|
+
output.error(chalk59.red(`
|
|
17595
|
+
✗ --email 和 --profile 互斥(profile 文件已包含 email)。请选择其一。
|
|
17596
|
+
`));
|
|
17597
|
+
process.exit(1);
|
|
17598
|
+
}
|
|
17599
|
+
if (a.profile) {
|
|
17600
|
+
const profile = readBountyProfile(a.profile);
|
|
17601
|
+
if (!profile) {
|
|
17602
|
+
output.error(chalk59.red(`
|
|
17603
|
+
✗ Profile '${a.profile}' 不存在或格式错误。期望路径:~/.config/bounty/profiles/${a.profile}.json
|
|
17604
|
+
`));
|
|
17605
|
+
process.exit(1);
|
|
17606
|
+
}
|
|
17607
|
+
resolvedEmail = profile.email;
|
|
17608
|
+
profileApiBase = profile.api_base;
|
|
17609
|
+
}
|
|
17610
|
+
}
|
|
17543
17611
|
const envUrl = process.env.BOUNTY_SERVER_URL;
|
|
17544
17612
|
const fallback = envUrl || "http://localhost:8787";
|
|
17545
|
-
|
|
17613
|
+
let resolvedServerUrl;
|
|
17614
|
+
if (a.serverUrl || a.imServerUrl) {
|
|
17615
|
+
resolvedServerUrl = resolveServerUrl(a.serverUrl || a.imServerUrl, fallback);
|
|
17616
|
+
} else if (a.type === "bounty-im" && profileApiBase) {
|
|
17617
|
+
resolvedServerUrl = profileToWsUrl(profileApiBase);
|
|
17618
|
+
} else {
|
|
17619
|
+
resolvedServerUrl = resolveServerUrl(undefined, fallback);
|
|
17620
|
+
}
|
|
17546
17621
|
const config = {
|
|
17547
17622
|
id: uuid(),
|
|
17548
17623
|
name: a.name,
|
|
@@ -17554,7 +17629,7 @@ var EventSourceAddCommand = {
|
|
|
17554
17629
|
interval: a.interval,
|
|
17555
17630
|
cron: a.cron,
|
|
17556
17631
|
profile: a.profile,
|
|
17557
|
-
|
|
17632
|
+
email: resolvedEmail,
|
|
17558
17633
|
imServerUrl: resolvedServerUrl,
|
|
17559
17634
|
tlsSkipVerify: a.tlsSkipVerify === true,
|
|
17560
17635
|
options: a.prompt ? { prompt: a.prompt } : undefined
|
|
@@ -17573,11 +17648,11 @@ var EventSourceAddCommand = {
|
|
|
17573
17648
|
if (a.interval) {
|
|
17574
17649
|
output.log(` Interval: ${chalk59.gray(`${a.interval}ms`)}`);
|
|
17575
17650
|
}
|
|
17576
|
-
if (
|
|
17577
|
-
output.log(` Profile: ${chalk59.gray(
|
|
17651
|
+
if (resolvedProfileName) {
|
|
17652
|
+
output.log(` Profile: ${chalk59.gray(resolvedProfileName)}`);
|
|
17578
17653
|
}
|
|
17579
|
-
if (
|
|
17580
|
-
output.log(`
|
|
17654
|
+
if (resolvedEmail) {
|
|
17655
|
+
output.log(` Email: ${chalk59.gray(resolvedEmail)}`);
|
|
17581
17656
|
}
|
|
17582
17657
|
if (a.imServerUrl) {
|
|
17583
17658
|
output.log(` IM Server URL: ${chalk59.gray(a.imServerUrl)}`);
|
|
@@ -17643,8 +17718,11 @@ var EventSourceUpdateCommand = {
|
|
|
17643
17718
|
}).option("enabled", {
|
|
17644
17719
|
describe: "是否启用",
|
|
17645
17720
|
type: "boolean"
|
|
17646
|
-
}).option("
|
|
17647
|
-
describe: "Agent IM
|
|
17721
|
+
}).option("email", {
|
|
17722
|
+
describe: "Agent IM 注册邮箱(bounty-im 类型用,v0.14 strict email-only;与 --profile 互斥)",
|
|
17723
|
+
type: "string"
|
|
17724
|
+
}).option("profile", {
|
|
17725
|
+
describe: "Profile 名称(bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取并自动更新 email + imServerUrl)",
|
|
17648
17726
|
type: "string"
|
|
17649
17727
|
}).option("tls-skip-verify", {
|
|
17650
17728
|
describe: "跳过 TLS 证书校验(bounty-im 类型用,wss:// 自签名场景,生产环境不推荐)",
|
|
@@ -17679,6 +17757,25 @@ var EventSourceUpdateCommand = {
|
|
|
17679
17757
|
}
|
|
17680
17758
|
process.exit(1);
|
|
17681
17759
|
}
|
|
17760
|
+
if (match.source.type === "bounty-im" && a.email && a.profile) {
|
|
17761
|
+
output.error(chalk60.red(`
|
|
17762
|
+
✗ --email 和 --profile 互斥(profile 文件已包含 email)。请选择其一。
|
|
17763
|
+
`));
|
|
17764
|
+
process.exit(1);
|
|
17765
|
+
}
|
|
17766
|
+
let profileEmail;
|
|
17767
|
+
let profileApiBase;
|
|
17768
|
+
if (a.profile && match.source.type === "bounty-im") {
|
|
17769
|
+
const profile = readBountyProfile(a.profile);
|
|
17770
|
+
if (!profile) {
|
|
17771
|
+
output.error(chalk60.red(`
|
|
17772
|
+
✗ Profile '${a.profile}' 不存在或格式错误。期望路径:~/.config/bounty/profiles/${a.profile}.json
|
|
17773
|
+
`));
|
|
17774
|
+
process.exit(1);
|
|
17775
|
+
}
|
|
17776
|
+
profileEmail = profile.email;
|
|
17777
|
+
profileApiBase = profile.api_base;
|
|
17778
|
+
}
|
|
17682
17779
|
const partial = {};
|
|
17683
17780
|
if (a.name !== undefined)
|
|
17684
17781
|
partial.name = a.name;
|
|
@@ -17695,12 +17792,18 @@ var EventSourceUpdateCommand = {
|
|
|
17695
17792
|
partial.cron = a.cron;
|
|
17696
17793
|
if (a.enabled !== undefined)
|
|
17697
17794
|
partial.enabled = a.enabled;
|
|
17698
|
-
if (a.
|
|
17699
|
-
partial.
|
|
17700
|
-
if (
|
|
17795
|
+
if (a.email !== undefined)
|
|
17796
|
+
partial.email = a.email;
|
|
17797
|
+
if (profileEmail !== undefined)
|
|
17798
|
+
partial.email = profileEmail;
|
|
17799
|
+
if (a.serverUrl !== undefined || a.imServerUrl !== undefined || profileApiBase !== undefined) {
|
|
17701
17800
|
const envUrl = process.env.BOUNTY_SERVER_URL;
|
|
17702
17801
|
const fallback = envUrl || "http://localhost:8787";
|
|
17703
|
-
|
|
17802
|
+
if (a.serverUrl !== undefined || a.imServerUrl !== undefined) {
|
|
17803
|
+
partial.imServerUrl = resolveServerUrl(a.serverUrl ?? a.imServerUrl, fallback);
|
|
17804
|
+
} else if (profileApiBase !== undefined) {
|
|
17805
|
+
partial.imServerUrl = profileToWsUrl(profileApiBase);
|
|
17806
|
+
}
|
|
17704
17807
|
}
|
|
17705
17808
|
if (a.tlsSkipVerify !== undefined)
|
|
17706
17809
|
partial.tlsSkipVerify = a.tlsSkipVerify === true;
|
|
@@ -19146,6 +19249,121 @@ class DecoratorNodeValidator extends BaseNodeValidator {
|
|
|
19146
19249
|
}
|
|
19147
19250
|
}
|
|
19148
19251
|
|
|
19252
|
+
// src/commands/workflow/validators/nodes/python-call-node-validator.ts
|
|
19253
|
+
class PythonCallNodeValidator extends BaseNodeValidator {
|
|
19254
|
+
nodeType = "python_call";
|
|
19255
|
+
getRequiredFields() {
|
|
19256
|
+
return ["module", "function"];
|
|
19257
|
+
}
|
|
19258
|
+
validateTypeSpecific(node) {
|
|
19259
|
+
const errors = [];
|
|
19260
|
+
const config = node.config ?? {};
|
|
19261
|
+
const moduleVal = config.module;
|
|
19262
|
+
if (moduleVal === undefined || moduleVal === null) {
|
|
19263
|
+
errors.push({
|
|
19264
|
+
type: "MISSING_REQUIRED_FIELD" /* MISSING_REQUIRED_FIELD */,
|
|
19265
|
+
description: 'Field "module" is required for python_call node',
|
|
19266
|
+
expected: 'module: "<python.module.path>"',
|
|
19267
|
+
actual: "undefined",
|
|
19268
|
+
fix: 'Add `module: "<python.module.path>"` to the node config',
|
|
19269
|
+
nodeId: node.id
|
|
19270
|
+
});
|
|
19271
|
+
} else if (typeof moduleVal !== "string") {
|
|
19272
|
+
errors.push({
|
|
19273
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19274
|
+
description: 'Field "module" has invalid type',
|
|
19275
|
+
expected: 'string (Python module path, e.g. "investment_strategy.scripts.market_timing")',
|
|
19276
|
+
actual: typeof moduleVal,
|
|
19277
|
+
fix: "Change `module` to a string",
|
|
19278
|
+
nodeId: node.id
|
|
19279
|
+
});
|
|
19280
|
+
} else if (!/^[A-Za-z_]\w*(\.[A-Za-z_]\w*)*$/.test(moduleVal)) {
|
|
19281
|
+
errors.push({
|
|
19282
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19283
|
+
description: `Field "module" is not a valid Python module path: "${moduleVal}"`,
|
|
19284
|
+
expected: 'dotted identifier like "pkg.sub.mod"',
|
|
19285
|
+
actual: moduleVal,
|
|
19286
|
+
fix: "Use only letters, digits, underscores, and dots",
|
|
19287
|
+
nodeId: node.id
|
|
19288
|
+
});
|
|
19289
|
+
}
|
|
19290
|
+
const fnVal = config.function;
|
|
19291
|
+
if (fnVal === undefined || fnVal === null) {
|
|
19292
|
+
errors.push({
|
|
19293
|
+
type: "MISSING_REQUIRED_FIELD" /* MISSING_REQUIRED_FIELD */,
|
|
19294
|
+
description: 'Field "function" is required for python_call node',
|
|
19295
|
+
expected: 'function: "<python_function_name>"',
|
|
19296
|
+
actual: "undefined",
|
|
19297
|
+
fix: 'Add `function: "<name>"` to the node config',
|
|
19298
|
+
nodeId: node.id
|
|
19299
|
+
});
|
|
19300
|
+
} else if (typeof fnVal !== "string") {
|
|
19301
|
+
errors.push({
|
|
19302
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19303
|
+
description: 'Field "function" has invalid type',
|
|
19304
|
+
expected: 'string (Python function name, e.g. "run")',
|
|
19305
|
+
actual: typeof fnVal,
|
|
19306
|
+
fix: "Change `function` to a string",
|
|
19307
|
+
nodeId: node.id
|
|
19308
|
+
});
|
|
19309
|
+
} else if (!/^[A-Za-z_]\w*$/.test(fnVal)) {
|
|
19310
|
+
errors.push({
|
|
19311
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19312
|
+
description: `Field "function" is not a valid Python identifier: "${fnVal}"`,
|
|
19313
|
+
expected: "Python identifier: starts with letter/underscore, contains only [A-Za-z0-9_]",
|
|
19314
|
+
actual: fnVal,
|
|
19315
|
+
fix: "Use a plain Python function name (no dots, no operators)",
|
|
19316
|
+
nodeId: node.id
|
|
19317
|
+
});
|
|
19318
|
+
}
|
|
19319
|
+
const argsVal = config.args;
|
|
19320
|
+
if (argsVal !== undefined && (typeof argsVal !== "object" || argsVal === null || Array.isArray(argsVal))) {
|
|
19321
|
+
errors.push({
|
|
19322
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19323
|
+
description: 'Field "args" has invalid type',
|
|
19324
|
+
expected: "object (kwargs to pass to the function)",
|
|
19325
|
+
actual: Array.isArray(argsVal) ? "array" : typeof argsVal,
|
|
19326
|
+
fix: "Change `args` to an object: args: { key: value }",
|
|
19327
|
+
nodeId: node.id
|
|
19328
|
+
});
|
|
19329
|
+
}
|
|
19330
|
+
if (config.cwd !== undefined && typeof config.cwd !== "string") {
|
|
19331
|
+
errors.push({
|
|
19332
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19333
|
+
description: 'Field "cwd" has invalid type',
|
|
19334
|
+
expected: "string (filesystem path)",
|
|
19335
|
+
actual: typeof config.cwd,
|
|
19336
|
+
fix: "Change `cwd` to a string",
|
|
19337
|
+
nodeId: node.id
|
|
19338
|
+
});
|
|
19339
|
+
}
|
|
19340
|
+
if (config.python !== undefined && typeof config.python !== "string") {
|
|
19341
|
+
errors.push({
|
|
19342
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19343
|
+
description: 'Field "python" has invalid type',
|
|
19344
|
+
expected: "string (path to python interpreter)",
|
|
19345
|
+
actual: typeof config.python,
|
|
19346
|
+
fix: "Change `python` to a string",
|
|
19347
|
+
nodeId: node.id
|
|
19348
|
+
});
|
|
19349
|
+
}
|
|
19350
|
+
if (config.timeout !== undefined) {
|
|
19351
|
+
const t = config.timeout;
|
|
19352
|
+
if (typeof t !== "number" || !Number.isFinite(t) || t <= 0) {
|
|
19353
|
+
errors.push({
|
|
19354
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19355
|
+
description: 'Field "timeout" has invalid type',
|
|
19356
|
+
expected: "positive number (milliseconds)",
|
|
19357
|
+
actual: typeof t === "number" ? `${t}` : typeof t,
|
|
19358
|
+
fix: "Change `timeout` to a positive number, e.g. timeout: 60000",
|
|
19359
|
+
nodeId: node.id
|
|
19360
|
+
});
|
|
19361
|
+
}
|
|
19362
|
+
}
|
|
19363
|
+
return errors;
|
|
19364
|
+
}
|
|
19365
|
+
}
|
|
19366
|
+
|
|
19149
19367
|
// src/commands/workflow/validators/node-validator-factory.ts
|
|
19150
19368
|
var validators = new Map;
|
|
19151
19369
|
validators.set("tool", new ToolNodeValidator);
|
|
@@ -19155,6 +19373,7 @@ validators.set("workflow", new WorkflowNodeValidator);
|
|
|
19155
19373
|
validators.set("condition", new ConditionNodeValidator);
|
|
19156
19374
|
validators.set("merge", new MergeNodeValidator);
|
|
19157
19375
|
validators.set("decorator", new DecoratorNodeValidator);
|
|
19376
|
+
validators.set("python_call", new PythonCallNodeValidator);
|
|
19158
19377
|
function getNodeValidator(type) {
|
|
19159
19378
|
return validators.get(type) || null;
|
|
19160
19379
|
}
|
|
@@ -20879,7 +21098,7 @@ Use `) + chalk74.cyan("roy-agent workflow nodes <type>") + chalk74.gray(" for de
|
|
|
20879
21098
|
|
|
20880
21099
|
// src/commands/workflow/commands/validate.ts
|
|
20881
21100
|
import chalk75 from "chalk";
|
|
20882
|
-
import { readFileSync } from "fs";
|
|
21101
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
20883
21102
|
async function parseWorkflowInput(input, yamlStr) {
|
|
20884
21103
|
const parseYaml = async (content) => {
|
|
20885
21104
|
const YAML2 = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
@@ -20887,7 +21106,7 @@ async function parseWorkflowInput(input, yamlStr) {
|
|
|
20887
21106
|
};
|
|
20888
21107
|
if (input && !yamlStr) {
|
|
20889
21108
|
try {
|
|
20890
|
-
const content =
|
|
21109
|
+
const content = readFileSync2(input, "utf-8");
|
|
20891
21110
|
return await parseYaml(content);
|
|
20892
21111
|
} catch (error) {
|
|
20893
21112
|
throw new Error(`Failed to read file "${input}": ${error.message}`);
|
|
@@ -21622,24 +21841,24 @@ var LspCommand = {
|
|
|
21622
21841
|
|
|
21623
21842
|
// src/commands/install/index.ts
|
|
21624
21843
|
import { spawnSync } from "node:child_process";
|
|
21625
|
-
import { existsSync as
|
|
21626
|
-
import { join as
|
|
21627
|
-
import { homedir as
|
|
21844
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync, cpSync } from "node:fs";
|
|
21845
|
+
import { join as join5, resolve } from "node:path";
|
|
21846
|
+
import { homedir as homedir4 } from "node:os";
|
|
21628
21847
|
function getConfigDir(scope) {
|
|
21629
|
-
return scope === "global" ?
|
|
21848
|
+
return scope === "global" ? join5(homedir4(), ".roy-agent") : join5(process.cwd(), ".roy");
|
|
21630
21849
|
}
|
|
21631
21850
|
function detectDefaultScope() {
|
|
21632
|
-
const projectDir =
|
|
21633
|
-
return
|
|
21851
|
+
const projectDir = join5(process.cwd(), ".roy");
|
|
21852
|
+
return existsSync4(projectDir) ? "project" : "global";
|
|
21634
21853
|
}
|
|
21635
21854
|
function getConfigPath(scope) {
|
|
21636
|
-
return
|
|
21855
|
+
return join5(getConfigDir(scope), "plugins.json");
|
|
21637
21856
|
}
|
|
21638
21857
|
function loadPlugins(scope) {
|
|
21639
21858
|
const configPath = getConfigPath(scope);
|
|
21640
21859
|
try {
|
|
21641
|
-
if (
|
|
21642
|
-
const raw =
|
|
21860
|
+
if (existsSync4(configPath)) {
|
|
21861
|
+
const raw = readFileSync3(configPath, "utf-8");
|
|
21643
21862
|
const config = JSON.parse(raw);
|
|
21644
21863
|
return config.plugins ?? [];
|
|
21645
21864
|
}
|
|
@@ -21649,7 +21868,7 @@ function loadPlugins(scope) {
|
|
|
21649
21868
|
function savePlugins(plugins, scope) {
|
|
21650
21869
|
const configDir = getConfigDir(scope);
|
|
21651
21870
|
const configPath = getConfigPath(scope);
|
|
21652
|
-
if (!
|
|
21871
|
+
if (!existsSync4(configDir)) {
|
|
21653
21872
|
mkdirSync(configDir, { recursive: true });
|
|
21654
21873
|
}
|
|
21655
21874
|
const config = { plugins };
|
|
@@ -21665,10 +21884,10 @@ function stripVersionSpec(packageName) {
|
|
|
21665
21884
|
function readPackageInfo(packageName) {
|
|
21666
21885
|
const bareName = packageName.startsWith("/") || packageName.startsWith(".") ? packageName : stripVersionSpec(packageName);
|
|
21667
21886
|
if (packageName.startsWith("/") || packageName.startsWith(".")) {
|
|
21668
|
-
const localPkgPath =
|
|
21669
|
-
if (
|
|
21887
|
+
const localPkgPath = join5(packageName, "package.json");
|
|
21888
|
+
if (existsSync4(localPkgPath)) {
|
|
21670
21889
|
try {
|
|
21671
|
-
const pkg = JSON.parse(
|
|
21890
|
+
const pkg = JSON.parse(readFileSync3(localPkgPath, "utf-8"));
|
|
21672
21891
|
return {
|
|
21673
21892
|
version: pkg.version ?? "0.0.0",
|
|
21674
21893
|
name: pkg.name ?? packageName,
|
|
@@ -21680,19 +21899,19 @@ function readPackageInfo(packageName) {
|
|
|
21680
21899
|
}
|
|
21681
21900
|
}
|
|
21682
21901
|
const searchPaths = [
|
|
21683
|
-
|
|
21902
|
+
join5(process.cwd(), "node_modules", bareName, "package.json"),
|
|
21684
21903
|
resolve(process.cwd(), "..", "node_modules", bareName, "package.json"),
|
|
21685
|
-
|
|
21686
|
-
|
|
21904
|
+
join5(process.cwd(), ".roy", "plugins", bareName, "package.json"),
|
|
21905
|
+
join5(homedir4(), ".roy-agent", "node_modules", bareName, "package.json"),
|
|
21687
21906
|
...(() => {
|
|
21688
21907
|
const globalRoot = getNpmGlobalRoot();
|
|
21689
|
-
return globalRoot ? [
|
|
21908
|
+
return globalRoot ? [join5(globalRoot, bareName, "package.json")] : [];
|
|
21690
21909
|
})()
|
|
21691
21910
|
];
|
|
21692
21911
|
for (const pkgPath of searchPaths) {
|
|
21693
21912
|
try {
|
|
21694
|
-
if (
|
|
21695
|
-
const pkg = JSON.parse(
|
|
21913
|
+
if (existsSync4(pkgPath)) {
|
|
21914
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
21696
21915
|
return {
|
|
21697
21916
|
version: pkg.version ?? "0.0.0",
|
|
21698
21917
|
name: pkg.name ?? bareName,
|
|
@@ -21715,15 +21934,15 @@ function getNpmGlobalRoot() {
|
|
|
21715
21934
|
return null;
|
|
21716
21935
|
}
|
|
21717
21936
|
function getPackageManagerCommand() {
|
|
21718
|
-
if (
|
|
21719
|
-
if (
|
|
21937
|
+
if (existsSync4(join5(process.cwd(), "pnpm-lock.yaml"))) {
|
|
21938
|
+
if (existsSync4(join5(process.cwd(), "pnpm-workspace.yaml"))) {
|
|
21720
21939
|
return "pnpm -w";
|
|
21721
21940
|
}
|
|
21722
21941
|
return "pnpm";
|
|
21723
21942
|
}
|
|
21724
|
-
if (
|
|
21943
|
+
if (existsSync4(join5(process.cwd(), "yarn.lock")))
|
|
21725
21944
|
return "yarn";
|
|
21726
|
-
if (
|
|
21945
|
+
if (existsSync4(join5(process.cwd(), "bun.lock")) || existsSync4(join5(process.cwd(), "bun.lockb")))
|
|
21727
21946
|
return "bun";
|
|
21728
21947
|
return "npm";
|
|
21729
21948
|
}
|
|
@@ -21762,14 +21981,14 @@ var InstallPackageCommand = {
|
|
|
21762
21981
|
}
|
|
21763
21982
|
resolvedName = info2.name;
|
|
21764
21983
|
const srcDir = resolve(packageName);
|
|
21765
|
-
if (!
|
|
21984
|
+
if (!existsSync4(srcDir)) {
|
|
21766
21985
|
console.error(`
|
|
21767
21986
|
❌ Local path '${srcDir}' does not exist.
|
|
21768
21987
|
`);
|
|
21769
21988
|
process.exit(1);
|
|
21770
21989
|
}
|
|
21771
|
-
const pluginDir =
|
|
21772
|
-
if (!
|
|
21990
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
|
|
21991
|
+
if (!existsSync4(pluginDir)) {
|
|
21773
21992
|
mkdirSync(pluginDir, { recursive: true });
|
|
21774
21993
|
}
|
|
21775
21994
|
const result = spawnSync("cp", ["-r", `${srcDir}/.`, pluginDir], {
|
|
@@ -21804,12 +22023,12 @@ var InstallPackageCommand = {
|
|
|
21804
22023
|
process.exit(1);
|
|
21805
22024
|
}
|
|
21806
22025
|
resolvedName = info2.name;
|
|
21807
|
-
const pluginDir =
|
|
21808
|
-
if (!
|
|
22026
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
|
|
22027
|
+
if (!existsSync4(pluginDir)) {
|
|
21809
22028
|
mkdirSync(pluginDir, { recursive: true });
|
|
21810
22029
|
}
|
|
21811
|
-
const nmPath =
|
|
21812
|
-
if (
|
|
22030
|
+
const nmPath = join5(process.cwd(), "node_modules", packageName);
|
|
22031
|
+
if (existsSync4(nmPath)) {
|
|
21813
22032
|
spawnSync("cp", ["-r", `${nmPath}/.`, pluginDir], { stdio: "inherit", shell: false });
|
|
21814
22033
|
}
|
|
21815
22034
|
}
|
|
@@ -21840,14 +22059,14 @@ var InstallPackageCommand = {
|
|
|
21840
22059
|
`);
|
|
21841
22060
|
process.exit(1);
|
|
21842
22061
|
}
|
|
21843
|
-
const globalNm =
|
|
21844
|
-
if (!
|
|
21845
|
-
mkdirSync(
|
|
22062
|
+
const globalNm = join5(homedir4(), ".roy-agent", "node_modules", resolvedGlobalName);
|
|
22063
|
+
if (!existsSync4(globalNm)) {
|
|
22064
|
+
mkdirSync(join5(homedir4(), ".roy-agent", "node_modules"), { recursive: true });
|
|
21846
22065
|
const rootResult = spawnSync("npm", ["root", "-g"], { stdio: "pipe", shell: false });
|
|
21847
22066
|
const globalRoot = rootResult.stdout?.toString().trim();
|
|
21848
22067
|
if (globalRoot) {
|
|
21849
|
-
const globalInstalled =
|
|
21850
|
-
if (
|
|
22068
|
+
const globalInstalled = join5(globalRoot, resolvedGlobalName);
|
|
22069
|
+
if (existsSync4(globalInstalled)) {
|
|
21851
22070
|
cpSync(globalInstalled, globalNm, { recursive: true });
|
|
21852
22071
|
}
|
|
21853
22072
|
}
|
|
@@ -21958,8 +22177,8 @@ var InstallRemoveCommand = {
|
|
|
21958
22177
|
\uD83D\uDDD1️ Removing plugin: ${plugin.packageName}@${plugin.version} (${scope})
|
|
21959
22178
|
`);
|
|
21960
22179
|
if (scope === "project") {
|
|
21961
|
-
const pluginDir =
|
|
21962
|
-
if (
|
|
22180
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", plugin.packageName);
|
|
22181
|
+
if (existsSync4(pluginDir)) {
|
|
21963
22182
|
spawnSync("rm", ["-rf", pluginDir], { stdio: "inherit", shell: false });
|
|
21964
22183
|
console.log(` Removed plugin directory: ${pluginDir}`);
|
|
21965
22184
|
}
|
|
@@ -21974,8 +22193,8 @@ var InstallRemoveCommand = {
|
|
|
21974
22193
|
`);
|
|
21975
22194
|
process.exit(result.status ?? 1);
|
|
21976
22195
|
}
|
|
21977
|
-
const globalNm =
|
|
21978
|
-
if (
|
|
22196
|
+
const globalNm = join5(homedir4(), ".roy-agent", "node_modules", plugin.packageName);
|
|
22197
|
+
if (existsSync4(globalNm)) {
|
|
21979
22198
|
spawnSync("rm", ["-rf", globalNm], { stdio: "inherit", shell: false });
|
|
21980
22199
|
}
|
|
21981
22200
|
}
|
|
Binary file
|