@ai-setting/roy-agent-cli 1.6.6 → 1.6.7
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 +277 -52
- package/dist/index.js +277 -52
- 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.7",
|
|
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;
|
|
@@ -17476,6 +17475,47 @@ function resolveServerUrl(serverUrl, fallback) {
|
|
|
17476
17475
|
return trimmed;
|
|
17477
17476
|
}
|
|
17478
17477
|
|
|
17478
|
+
// src/lib/bounty-profile-reader.ts
|
|
17479
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
17480
|
+
import { homedir } from "node:os";
|
|
17481
|
+
import { join } from "node:path";
|
|
17482
|
+
function readBountyProfile(name, profilesDir) {
|
|
17483
|
+
if (!name)
|
|
17484
|
+
return null;
|
|
17485
|
+
const dir = profilesDir ?? join(homedir(), ".config", "bounty", "profiles");
|
|
17486
|
+
const profilePath = join(dir, `${name}.json`);
|
|
17487
|
+
if (!existsSync2(profilePath))
|
|
17488
|
+
return null;
|
|
17489
|
+
try {
|
|
17490
|
+
const raw = readFileSync(profilePath, "utf-8");
|
|
17491
|
+
const data = JSON.parse(raw);
|
|
17492
|
+
return {
|
|
17493
|
+
email: typeof data.email === "string" ? data.email : undefined,
|
|
17494
|
+
agent_id: typeof data.agent_id === "string" ? data.agent_id : undefined,
|
|
17495
|
+
api_base: typeof data.api_base === "string" ? data.api_base : undefined
|
|
17496
|
+
};
|
|
17497
|
+
} catch {
|
|
17498
|
+
return null;
|
|
17499
|
+
}
|
|
17500
|
+
}
|
|
17501
|
+
function profileToWsUrl(apiBase) {
|
|
17502
|
+
let url = apiBase.replace(/\/+$/, "");
|
|
17503
|
+
if (url.startsWith("ws://") || url.startsWith("wss://")) {
|
|
17504
|
+
if (url.endsWith("/ws"))
|
|
17505
|
+
return url;
|
|
17506
|
+
return `${url}/ws`;
|
|
17507
|
+
}
|
|
17508
|
+
if (url.startsWith("https://")) {
|
|
17509
|
+
url = "wss://" + url.slice("https://".length);
|
|
17510
|
+
} else if (url.startsWith("http://")) {
|
|
17511
|
+
url = "ws://" + url.slice("http://".length);
|
|
17512
|
+
}
|
|
17513
|
+
if (!url.endsWith("/ws")) {
|
|
17514
|
+
url = `${url}/ws`;
|
|
17515
|
+
}
|
|
17516
|
+
return url;
|
|
17517
|
+
}
|
|
17518
|
+
|
|
17479
17519
|
// src/commands/eventsource/add.ts
|
|
17480
17520
|
function uuid() {
|
|
17481
17521
|
return generateId();
|
|
@@ -17511,10 +17551,13 @@ var EventSourceAddCommand = {
|
|
|
17511
17551
|
describe: "Cron 表达式",
|
|
17512
17552
|
type: "string"
|
|
17513
17553
|
}).option("profile", {
|
|
17514
|
-
describe: "lark-cli
|
|
17554
|
+
describe: "Profile 名称(lark-cli / bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取配置;多 appId / 多账户场景必要,参考 #1637)",
|
|
17515
17555
|
type: "string"
|
|
17516
17556
|
}).option("address", {
|
|
17517
|
-
describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host
|
|
17557
|
+
describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host,v0.12 向后兼容)",
|
|
17558
|
+
type: "string"
|
|
17559
|
+
}).option("email", {
|
|
17560
|
+
describe: "Agent IM 注册邮箱(bounty-im 类型用,v0.13 server 协议;与 --profile 互斥)",
|
|
17518
17561
|
type: "string"
|
|
17519
17562
|
}).option("tls-skip-verify", {
|
|
17520
17563
|
describe: "跳过 TLS 证书校验(bounty-im 类型用,wss:// 自签名场景,生产环境不推荐)",
|
|
@@ -17541,9 +17584,38 @@ var EventSourceAddCommand = {
|
|
|
17541
17584
|
process.exit(1);
|
|
17542
17585
|
}
|
|
17543
17586
|
const eventTypes = a.eventTypes?.split(",").map((s) => s.trim());
|
|
17587
|
+
let resolvedEmail = a.email;
|
|
17588
|
+
let resolvedProfileName = a.profile;
|
|
17589
|
+
let profileApiBase;
|
|
17590
|
+
if (a.type === "bounty-im") {
|
|
17591
|
+
if (a.email && a.profile) {
|
|
17592
|
+
output.error(chalk59.red(`
|
|
17593
|
+
✗ --email 和 --profile 互斥(profile 文件已包含 email)。请选择其一。
|
|
17594
|
+
`));
|
|
17595
|
+
process.exit(1);
|
|
17596
|
+
}
|
|
17597
|
+
if (a.profile) {
|
|
17598
|
+
const profile = readBountyProfile(a.profile);
|
|
17599
|
+
if (!profile) {
|
|
17600
|
+
output.error(chalk59.red(`
|
|
17601
|
+
✗ Profile '${a.profile}' 不存在或格式错误。期望路径:~/.config/bounty/profiles/${a.profile}.json
|
|
17602
|
+
`));
|
|
17603
|
+
process.exit(1);
|
|
17604
|
+
}
|
|
17605
|
+
resolvedEmail = profile.email;
|
|
17606
|
+
profileApiBase = profile.api_base;
|
|
17607
|
+
}
|
|
17608
|
+
}
|
|
17544
17609
|
const envUrl = process.env.BOUNTY_SERVER_URL;
|
|
17545
17610
|
const fallback = envUrl || "http://localhost:8787";
|
|
17546
|
-
|
|
17611
|
+
let resolvedServerUrl;
|
|
17612
|
+
if (a.serverUrl || a.imServerUrl) {
|
|
17613
|
+
resolvedServerUrl = resolveServerUrl(a.serverUrl || a.imServerUrl, fallback);
|
|
17614
|
+
} else if (a.type === "bounty-im" && profileApiBase) {
|
|
17615
|
+
resolvedServerUrl = profileToWsUrl(profileApiBase);
|
|
17616
|
+
} else {
|
|
17617
|
+
resolvedServerUrl = resolveServerUrl(undefined, fallback);
|
|
17618
|
+
}
|
|
17547
17619
|
const config = {
|
|
17548
17620
|
id: uuid(),
|
|
17549
17621
|
name: a.name,
|
|
@@ -17555,6 +17627,7 @@ var EventSourceAddCommand = {
|
|
|
17555
17627
|
interval: a.interval,
|
|
17556
17628
|
cron: a.cron,
|
|
17557
17629
|
profile: a.profile,
|
|
17630
|
+
email: resolvedEmail,
|
|
17558
17631
|
address: a.address,
|
|
17559
17632
|
imServerUrl: resolvedServerUrl,
|
|
17560
17633
|
tlsSkipVerify: a.tlsSkipVerify === true,
|
|
@@ -17574,8 +17647,11 @@ var EventSourceAddCommand = {
|
|
|
17574
17647
|
if (a.interval) {
|
|
17575
17648
|
output.log(` Interval: ${chalk59.gray(`${a.interval}ms`)}`);
|
|
17576
17649
|
}
|
|
17577
|
-
if (
|
|
17578
|
-
output.log(` Profile: ${chalk59.gray(
|
|
17650
|
+
if (resolvedProfileName) {
|
|
17651
|
+
output.log(` Profile: ${chalk59.gray(resolvedProfileName)}`);
|
|
17652
|
+
}
|
|
17653
|
+
if (resolvedEmail) {
|
|
17654
|
+
output.log(` Email: ${chalk59.gray(resolvedEmail)}`);
|
|
17579
17655
|
}
|
|
17580
17656
|
if (a.address) {
|
|
17581
17657
|
output.log(` Address: ${chalk59.gray(a.address)}`);
|
|
@@ -17645,7 +17721,13 @@ var EventSourceUpdateCommand = {
|
|
|
17645
17721
|
describe: "是否启用",
|
|
17646
17722
|
type: "boolean"
|
|
17647
17723
|
}).option("address", {
|
|
17648
|
-
describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host
|
|
17724
|
+
describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host,v0.12 向后兼容)",
|
|
17725
|
+
type: "string"
|
|
17726
|
+
}).option("email", {
|
|
17727
|
+
describe: "Agent IM 注册邮箱(bounty-im 类型用,v0.13;与 --profile 互斥)",
|
|
17728
|
+
type: "string"
|
|
17729
|
+
}).option("profile", {
|
|
17730
|
+
describe: "Profile 名称(bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取并自动更新 email + imServerUrl)",
|
|
17649
17731
|
type: "string"
|
|
17650
17732
|
}).option("tls-skip-verify", {
|
|
17651
17733
|
describe: "跳过 TLS 证书校验(bounty-im 类型用,wss:// 自签名场景,生产环境不推荐)",
|
|
@@ -17680,6 +17762,25 @@ var EventSourceUpdateCommand = {
|
|
|
17680
17762
|
}
|
|
17681
17763
|
process.exit(1);
|
|
17682
17764
|
}
|
|
17765
|
+
if (match.source.type === "bounty-im" && a.email && a.profile) {
|
|
17766
|
+
output.error(chalk60.red(`
|
|
17767
|
+
✗ --email 和 --profile 互斥(profile 文件已包含 email)。请选择其一。
|
|
17768
|
+
`));
|
|
17769
|
+
process.exit(1);
|
|
17770
|
+
}
|
|
17771
|
+
let profileEmail;
|
|
17772
|
+
let profileApiBase;
|
|
17773
|
+
if (a.profile && match.source.type === "bounty-im") {
|
|
17774
|
+
const profile = readBountyProfile(a.profile);
|
|
17775
|
+
if (!profile) {
|
|
17776
|
+
output.error(chalk60.red(`
|
|
17777
|
+
✗ Profile '${a.profile}' 不存在或格式错误。期望路径:~/.config/bounty/profiles/${a.profile}.json
|
|
17778
|
+
`));
|
|
17779
|
+
process.exit(1);
|
|
17780
|
+
}
|
|
17781
|
+
profileEmail = profile.email;
|
|
17782
|
+
profileApiBase = profile.api_base;
|
|
17783
|
+
}
|
|
17683
17784
|
const partial = {};
|
|
17684
17785
|
if (a.name !== undefined)
|
|
17685
17786
|
partial.name = a.name;
|
|
@@ -17698,10 +17799,18 @@ var EventSourceUpdateCommand = {
|
|
|
17698
17799
|
partial.enabled = a.enabled;
|
|
17699
17800
|
if (a.address !== undefined)
|
|
17700
17801
|
partial.address = a.address;
|
|
17701
|
-
if (a.
|
|
17802
|
+
if (a.email !== undefined)
|
|
17803
|
+
partial.email = a.email;
|
|
17804
|
+
if (profileEmail !== undefined)
|
|
17805
|
+
partial.email = profileEmail;
|
|
17806
|
+
if (a.serverUrl !== undefined || a.imServerUrl !== undefined || profileApiBase !== undefined) {
|
|
17702
17807
|
const envUrl = process.env.BOUNTY_SERVER_URL;
|
|
17703
17808
|
const fallback = envUrl || "http://localhost:8787";
|
|
17704
|
-
|
|
17809
|
+
if (a.serverUrl !== undefined || a.imServerUrl !== undefined) {
|
|
17810
|
+
partial.imServerUrl = resolveServerUrl(a.serverUrl ?? a.imServerUrl, fallback);
|
|
17811
|
+
} else if (profileApiBase !== undefined) {
|
|
17812
|
+
partial.imServerUrl = profileToWsUrl(profileApiBase);
|
|
17813
|
+
}
|
|
17705
17814
|
}
|
|
17706
17815
|
if (a.tlsSkipVerify !== undefined)
|
|
17707
17816
|
partial.tlsSkipVerify = a.tlsSkipVerify === true;
|
|
@@ -19147,6 +19256,121 @@ class DecoratorNodeValidator extends BaseNodeValidator {
|
|
|
19147
19256
|
}
|
|
19148
19257
|
}
|
|
19149
19258
|
|
|
19259
|
+
// src/commands/workflow/validators/nodes/python-call-node-validator.ts
|
|
19260
|
+
class PythonCallNodeValidator extends BaseNodeValidator {
|
|
19261
|
+
nodeType = "python_call";
|
|
19262
|
+
getRequiredFields() {
|
|
19263
|
+
return ["module", "function"];
|
|
19264
|
+
}
|
|
19265
|
+
validateTypeSpecific(node) {
|
|
19266
|
+
const errors = [];
|
|
19267
|
+
const config = node.config ?? {};
|
|
19268
|
+
const moduleVal = config.module;
|
|
19269
|
+
if (moduleVal === undefined || moduleVal === null) {
|
|
19270
|
+
errors.push({
|
|
19271
|
+
type: "MISSING_REQUIRED_FIELD" /* MISSING_REQUIRED_FIELD */,
|
|
19272
|
+
description: 'Field "module" is required for python_call node',
|
|
19273
|
+
expected: 'module: "<python.module.path>"',
|
|
19274
|
+
actual: "undefined",
|
|
19275
|
+
fix: 'Add `module: "<python.module.path>"` to the node config',
|
|
19276
|
+
nodeId: node.id
|
|
19277
|
+
});
|
|
19278
|
+
} else if (typeof moduleVal !== "string") {
|
|
19279
|
+
errors.push({
|
|
19280
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19281
|
+
description: 'Field "module" has invalid type',
|
|
19282
|
+
expected: 'string (Python module path, e.g. "investment_strategy.scripts.market_timing")',
|
|
19283
|
+
actual: typeof moduleVal,
|
|
19284
|
+
fix: "Change `module` to a string",
|
|
19285
|
+
nodeId: node.id
|
|
19286
|
+
});
|
|
19287
|
+
} else if (!/^[A-Za-z_]\w*(\.[A-Za-z_]\w*)*$/.test(moduleVal)) {
|
|
19288
|
+
errors.push({
|
|
19289
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19290
|
+
description: `Field "module" is not a valid Python module path: "${moduleVal}"`,
|
|
19291
|
+
expected: 'dotted identifier like "pkg.sub.mod"',
|
|
19292
|
+
actual: moduleVal,
|
|
19293
|
+
fix: "Use only letters, digits, underscores, and dots",
|
|
19294
|
+
nodeId: node.id
|
|
19295
|
+
});
|
|
19296
|
+
}
|
|
19297
|
+
const fnVal = config.function;
|
|
19298
|
+
if (fnVal === undefined || fnVal === null) {
|
|
19299
|
+
errors.push({
|
|
19300
|
+
type: "MISSING_REQUIRED_FIELD" /* MISSING_REQUIRED_FIELD */,
|
|
19301
|
+
description: 'Field "function" is required for python_call node',
|
|
19302
|
+
expected: 'function: "<python_function_name>"',
|
|
19303
|
+
actual: "undefined",
|
|
19304
|
+
fix: 'Add `function: "<name>"` to the node config',
|
|
19305
|
+
nodeId: node.id
|
|
19306
|
+
});
|
|
19307
|
+
} else if (typeof fnVal !== "string") {
|
|
19308
|
+
errors.push({
|
|
19309
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19310
|
+
description: 'Field "function" has invalid type',
|
|
19311
|
+
expected: 'string (Python function name, e.g. "run")',
|
|
19312
|
+
actual: typeof fnVal,
|
|
19313
|
+
fix: "Change `function` to a string",
|
|
19314
|
+
nodeId: node.id
|
|
19315
|
+
});
|
|
19316
|
+
} else if (!/^[A-Za-z_]\w*$/.test(fnVal)) {
|
|
19317
|
+
errors.push({
|
|
19318
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19319
|
+
description: `Field "function" is not a valid Python identifier: "${fnVal}"`,
|
|
19320
|
+
expected: "Python identifier: starts with letter/underscore, contains only [A-Za-z0-9_]",
|
|
19321
|
+
actual: fnVal,
|
|
19322
|
+
fix: "Use a plain Python function name (no dots, no operators)",
|
|
19323
|
+
nodeId: node.id
|
|
19324
|
+
});
|
|
19325
|
+
}
|
|
19326
|
+
const argsVal = config.args;
|
|
19327
|
+
if (argsVal !== undefined && (typeof argsVal !== "object" || argsVal === null || Array.isArray(argsVal))) {
|
|
19328
|
+
errors.push({
|
|
19329
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19330
|
+
description: 'Field "args" has invalid type',
|
|
19331
|
+
expected: "object (kwargs to pass to the function)",
|
|
19332
|
+
actual: Array.isArray(argsVal) ? "array" : typeof argsVal,
|
|
19333
|
+
fix: "Change `args` to an object: args: { key: value }",
|
|
19334
|
+
nodeId: node.id
|
|
19335
|
+
});
|
|
19336
|
+
}
|
|
19337
|
+
if (config.cwd !== undefined && typeof config.cwd !== "string") {
|
|
19338
|
+
errors.push({
|
|
19339
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19340
|
+
description: 'Field "cwd" has invalid type',
|
|
19341
|
+
expected: "string (filesystem path)",
|
|
19342
|
+
actual: typeof config.cwd,
|
|
19343
|
+
fix: "Change `cwd` to a string",
|
|
19344
|
+
nodeId: node.id
|
|
19345
|
+
});
|
|
19346
|
+
}
|
|
19347
|
+
if (config.python !== undefined && typeof config.python !== "string") {
|
|
19348
|
+
errors.push({
|
|
19349
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19350
|
+
description: 'Field "python" has invalid type',
|
|
19351
|
+
expected: "string (path to python interpreter)",
|
|
19352
|
+
actual: typeof config.python,
|
|
19353
|
+
fix: "Change `python` to a string",
|
|
19354
|
+
nodeId: node.id
|
|
19355
|
+
});
|
|
19356
|
+
}
|
|
19357
|
+
if (config.timeout !== undefined) {
|
|
19358
|
+
const t = config.timeout;
|
|
19359
|
+
if (typeof t !== "number" || !Number.isFinite(t) || t <= 0) {
|
|
19360
|
+
errors.push({
|
|
19361
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19362
|
+
description: 'Field "timeout" has invalid type',
|
|
19363
|
+
expected: "positive number (milliseconds)",
|
|
19364
|
+
actual: typeof t === "number" ? `${t}` : typeof t,
|
|
19365
|
+
fix: "Change `timeout` to a positive number, e.g. timeout: 60000",
|
|
19366
|
+
nodeId: node.id
|
|
19367
|
+
});
|
|
19368
|
+
}
|
|
19369
|
+
}
|
|
19370
|
+
return errors;
|
|
19371
|
+
}
|
|
19372
|
+
}
|
|
19373
|
+
|
|
19150
19374
|
// src/commands/workflow/validators/node-validator-factory.ts
|
|
19151
19375
|
var validators = new Map;
|
|
19152
19376
|
validators.set("tool", new ToolNodeValidator);
|
|
@@ -19156,6 +19380,7 @@ validators.set("workflow", new WorkflowNodeValidator);
|
|
|
19156
19380
|
validators.set("condition", new ConditionNodeValidator);
|
|
19157
19381
|
validators.set("merge", new MergeNodeValidator);
|
|
19158
19382
|
validators.set("decorator", new DecoratorNodeValidator);
|
|
19383
|
+
validators.set("python_call", new PythonCallNodeValidator);
|
|
19159
19384
|
function getNodeValidator(type) {
|
|
19160
19385
|
return validators.get(type) || null;
|
|
19161
19386
|
}
|
|
@@ -20880,7 +21105,7 @@ Use `) + chalk74.cyan("roy-agent workflow nodes <type>") + chalk74.gray(" for de
|
|
|
20880
21105
|
|
|
20881
21106
|
// src/commands/workflow/commands/validate.ts
|
|
20882
21107
|
import chalk75 from "chalk";
|
|
20883
|
-
import { readFileSync } from "fs";
|
|
21108
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
20884
21109
|
async function parseWorkflowInput(input, yamlStr) {
|
|
20885
21110
|
const parseYaml = async (content) => {
|
|
20886
21111
|
const YAML2 = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
@@ -20888,7 +21113,7 @@ async function parseWorkflowInput(input, yamlStr) {
|
|
|
20888
21113
|
};
|
|
20889
21114
|
if (input && !yamlStr) {
|
|
20890
21115
|
try {
|
|
20891
|
-
const content =
|
|
21116
|
+
const content = readFileSync2(input, "utf-8");
|
|
20892
21117
|
return await parseYaml(content);
|
|
20893
21118
|
} catch (error) {
|
|
20894
21119
|
throw new Error(`Failed to read file "${input}": ${error.message}`);
|
|
@@ -21623,24 +21848,24 @@ var LspCommand = {
|
|
|
21623
21848
|
|
|
21624
21849
|
// src/commands/install/index.ts
|
|
21625
21850
|
import { spawnSync } from "node:child_process";
|
|
21626
|
-
import { existsSync as
|
|
21627
|
-
import { join as
|
|
21628
|
-
import { homedir as
|
|
21851
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync, cpSync } from "node:fs";
|
|
21852
|
+
import { join as join5, resolve } from "node:path";
|
|
21853
|
+
import { homedir as homedir4 } from "node:os";
|
|
21629
21854
|
function getConfigDir(scope) {
|
|
21630
|
-
return scope === "global" ?
|
|
21855
|
+
return scope === "global" ? join5(homedir4(), ".roy-agent") : join5(process.cwd(), ".roy");
|
|
21631
21856
|
}
|
|
21632
21857
|
function detectDefaultScope() {
|
|
21633
|
-
const projectDir =
|
|
21634
|
-
return
|
|
21858
|
+
const projectDir = join5(process.cwd(), ".roy");
|
|
21859
|
+
return existsSync4(projectDir) ? "project" : "global";
|
|
21635
21860
|
}
|
|
21636
21861
|
function getConfigPath(scope) {
|
|
21637
|
-
return
|
|
21862
|
+
return join5(getConfigDir(scope), "plugins.json");
|
|
21638
21863
|
}
|
|
21639
21864
|
function loadPlugins(scope) {
|
|
21640
21865
|
const configPath = getConfigPath(scope);
|
|
21641
21866
|
try {
|
|
21642
|
-
if (
|
|
21643
|
-
const raw =
|
|
21867
|
+
if (existsSync4(configPath)) {
|
|
21868
|
+
const raw = readFileSync3(configPath, "utf-8");
|
|
21644
21869
|
const config = JSON.parse(raw);
|
|
21645
21870
|
return config.plugins ?? [];
|
|
21646
21871
|
}
|
|
@@ -21650,7 +21875,7 @@ function loadPlugins(scope) {
|
|
|
21650
21875
|
function savePlugins(plugins, scope) {
|
|
21651
21876
|
const configDir = getConfigDir(scope);
|
|
21652
21877
|
const configPath = getConfigPath(scope);
|
|
21653
|
-
if (!
|
|
21878
|
+
if (!existsSync4(configDir)) {
|
|
21654
21879
|
mkdirSync(configDir, { recursive: true });
|
|
21655
21880
|
}
|
|
21656
21881
|
const config = { plugins };
|
|
@@ -21666,10 +21891,10 @@ function stripVersionSpec(packageName) {
|
|
|
21666
21891
|
function readPackageInfo(packageName) {
|
|
21667
21892
|
const bareName = packageName.startsWith("/") || packageName.startsWith(".") ? packageName : stripVersionSpec(packageName);
|
|
21668
21893
|
if (packageName.startsWith("/") || packageName.startsWith(".")) {
|
|
21669
|
-
const localPkgPath =
|
|
21670
|
-
if (
|
|
21894
|
+
const localPkgPath = join5(packageName, "package.json");
|
|
21895
|
+
if (existsSync4(localPkgPath)) {
|
|
21671
21896
|
try {
|
|
21672
|
-
const pkg = JSON.parse(
|
|
21897
|
+
const pkg = JSON.parse(readFileSync3(localPkgPath, "utf-8"));
|
|
21673
21898
|
return {
|
|
21674
21899
|
version: pkg.version ?? "0.0.0",
|
|
21675
21900
|
name: pkg.name ?? packageName,
|
|
@@ -21681,19 +21906,19 @@ function readPackageInfo(packageName) {
|
|
|
21681
21906
|
}
|
|
21682
21907
|
}
|
|
21683
21908
|
const searchPaths = [
|
|
21684
|
-
|
|
21909
|
+
join5(process.cwd(), "node_modules", bareName, "package.json"),
|
|
21685
21910
|
resolve(process.cwd(), "..", "node_modules", bareName, "package.json"),
|
|
21686
|
-
|
|
21687
|
-
|
|
21911
|
+
join5(process.cwd(), ".roy", "plugins", bareName, "package.json"),
|
|
21912
|
+
join5(homedir4(), ".roy-agent", "node_modules", bareName, "package.json"),
|
|
21688
21913
|
...(() => {
|
|
21689
21914
|
const globalRoot = getNpmGlobalRoot();
|
|
21690
|
-
return globalRoot ? [
|
|
21915
|
+
return globalRoot ? [join5(globalRoot, bareName, "package.json")] : [];
|
|
21691
21916
|
})()
|
|
21692
21917
|
];
|
|
21693
21918
|
for (const pkgPath of searchPaths) {
|
|
21694
21919
|
try {
|
|
21695
|
-
if (
|
|
21696
|
-
const pkg = JSON.parse(
|
|
21920
|
+
if (existsSync4(pkgPath)) {
|
|
21921
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
21697
21922
|
return {
|
|
21698
21923
|
version: pkg.version ?? "0.0.0",
|
|
21699
21924
|
name: pkg.name ?? bareName,
|
|
@@ -21716,15 +21941,15 @@ function getNpmGlobalRoot() {
|
|
|
21716
21941
|
return null;
|
|
21717
21942
|
}
|
|
21718
21943
|
function getPackageManagerCommand() {
|
|
21719
|
-
if (
|
|
21720
|
-
if (
|
|
21944
|
+
if (existsSync4(join5(process.cwd(), "pnpm-lock.yaml"))) {
|
|
21945
|
+
if (existsSync4(join5(process.cwd(), "pnpm-workspace.yaml"))) {
|
|
21721
21946
|
return "pnpm -w";
|
|
21722
21947
|
}
|
|
21723
21948
|
return "pnpm";
|
|
21724
21949
|
}
|
|
21725
|
-
if (
|
|
21950
|
+
if (existsSync4(join5(process.cwd(), "yarn.lock")))
|
|
21726
21951
|
return "yarn";
|
|
21727
|
-
if (
|
|
21952
|
+
if (existsSync4(join5(process.cwd(), "bun.lock")) || existsSync4(join5(process.cwd(), "bun.lockb")))
|
|
21728
21953
|
return "bun";
|
|
21729
21954
|
return "npm";
|
|
21730
21955
|
}
|
|
@@ -21763,14 +21988,14 @@ var InstallPackageCommand = {
|
|
|
21763
21988
|
}
|
|
21764
21989
|
resolvedName = info2.name;
|
|
21765
21990
|
const srcDir = resolve(packageName);
|
|
21766
|
-
if (!
|
|
21991
|
+
if (!existsSync4(srcDir)) {
|
|
21767
21992
|
console.error(`
|
|
21768
21993
|
❌ Local path '${srcDir}' does not exist.
|
|
21769
21994
|
`);
|
|
21770
21995
|
process.exit(1);
|
|
21771
21996
|
}
|
|
21772
|
-
const pluginDir =
|
|
21773
|
-
if (!
|
|
21997
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
|
|
21998
|
+
if (!existsSync4(pluginDir)) {
|
|
21774
21999
|
mkdirSync(pluginDir, { recursive: true });
|
|
21775
22000
|
}
|
|
21776
22001
|
const result = spawnSync("cp", ["-r", `${srcDir}/.`, pluginDir], {
|
|
@@ -21805,12 +22030,12 @@ var InstallPackageCommand = {
|
|
|
21805
22030
|
process.exit(1);
|
|
21806
22031
|
}
|
|
21807
22032
|
resolvedName = info2.name;
|
|
21808
|
-
const pluginDir =
|
|
21809
|
-
if (!
|
|
22033
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
|
|
22034
|
+
if (!existsSync4(pluginDir)) {
|
|
21810
22035
|
mkdirSync(pluginDir, { recursive: true });
|
|
21811
22036
|
}
|
|
21812
|
-
const nmPath =
|
|
21813
|
-
if (
|
|
22037
|
+
const nmPath = join5(process.cwd(), "node_modules", packageName);
|
|
22038
|
+
if (existsSync4(nmPath)) {
|
|
21814
22039
|
spawnSync("cp", ["-r", `${nmPath}/.`, pluginDir], { stdio: "inherit", shell: false });
|
|
21815
22040
|
}
|
|
21816
22041
|
}
|
|
@@ -21841,14 +22066,14 @@ var InstallPackageCommand = {
|
|
|
21841
22066
|
`);
|
|
21842
22067
|
process.exit(1);
|
|
21843
22068
|
}
|
|
21844
|
-
const globalNm =
|
|
21845
|
-
if (!
|
|
21846
|
-
mkdirSync(
|
|
22069
|
+
const globalNm = join5(homedir4(), ".roy-agent", "node_modules", resolvedGlobalName);
|
|
22070
|
+
if (!existsSync4(globalNm)) {
|
|
22071
|
+
mkdirSync(join5(homedir4(), ".roy-agent", "node_modules"), { recursive: true });
|
|
21847
22072
|
const rootResult = spawnSync("npm", ["root", "-g"], { stdio: "pipe", shell: false });
|
|
21848
22073
|
const globalRoot = rootResult.stdout?.toString().trim();
|
|
21849
22074
|
if (globalRoot) {
|
|
21850
|
-
const globalInstalled =
|
|
21851
|
-
if (
|
|
22075
|
+
const globalInstalled = join5(globalRoot, resolvedGlobalName);
|
|
22076
|
+
if (existsSync4(globalInstalled)) {
|
|
21852
22077
|
cpSync(globalInstalled, globalNm, { recursive: true });
|
|
21853
22078
|
}
|
|
21854
22079
|
}
|
|
@@ -21959,8 +22184,8 @@ var InstallRemoveCommand = {
|
|
|
21959
22184
|
\uD83D\uDDD1️ Removing plugin: ${plugin.packageName}@${plugin.version} (${scope})
|
|
21960
22185
|
`);
|
|
21961
22186
|
if (scope === "project") {
|
|
21962
|
-
const pluginDir =
|
|
21963
|
-
if (
|
|
22187
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", plugin.packageName);
|
|
22188
|
+
if (existsSync4(pluginDir)) {
|
|
21964
22189
|
spawnSync("rm", ["-rf", pluginDir], { stdio: "inherit", shell: false });
|
|
21965
22190
|
console.log(` Removed plugin directory: ${pluginDir}`);
|
|
21966
22191
|
}
|
|
@@ -21975,8 +22200,8 @@ var InstallRemoveCommand = {
|
|
|
21975
22200
|
`);
|
|
21976
22201
|
process.exit(result.status ?? 1);
|
|
21977
22202
|
}
|
|
21978
|
-
const globalNm =
|
|
21979
|
-
if (
|
|
22203
|
+
const globalNm = join5(homedir4(), ".roy-agent", "node_modules", plugin.packageName);
|
|
22204
|
+
if (existsSync4(globalNm)) {
|
|
21980
22205
|
spawnSync("rm", ["-rf", globalNm], { stdio: "inherit", shell: false });
|
|
21981
22206
|
}
|
|
21982
22207
|
}
|
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.7",
|
|
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;
|
|
@@ -17475,6 +17474,47 @@ function resolveServerUrl(serverUrl, fallback) {
|
|
|
17475
17474
|
return trimmed;
|
|
17476
17475
|
}
|
|
17477
17476
|
|
|
17477
|
+
// src/lib/bounty-profile-reader.ts
|
|
17478
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
17479
|
+
import { homedir } from "node:os";
|
|
17480
|
+
import { join } from "node:path";
|
|
17481
|
+
function readBountyProfile(name, profilesDir) {
|
|
17482
|
+
if (!name)
|
|
17483
|
+
return null;
|
|
17484
|
+
const dir = profilesDir ?? join(homedir(), ".config", "bounty", "profiles");
|
|
17485
|
+
const profilePath = join(dir, `${name}.json`);
|
|
17486
|
+
if (!existsSync2(profilePath))
|
|
17487
|
+
return null;
|
|
17488
|
+
try {
|
|
17489
|
+
const raw = readFileSync(profilePath, "utf-8");
|
|
17490
|
+
const data = JSON.parse(raw);
|
|
17491
|
+
return {
|
|
17492
|
+
email: typeof data.email === "string" ? data.email : undefined,
|
|
17493
|
+
agent_id: typeof data.agent_id === "string" ? data.agent_id : undefined,
|
|
17494
|
+
api_base: typeof data.api_base === "string" ? data.api_base : undefined
|
|
17495
|
+
};
|
|
17496
|
+
} catch {
|
|
17497
|
+
return null;
|
|
17498
|
+
}
|
|
17499
|
+
}
|
|
17500
|
+
function profileToWsUrl(apiBase) {
|
|
17501
|
+
let url = apiBase.replace(/\/+$/, "");
|
|
17502
|
+
if (url.startsWith("ws://") || url.startsWith("wss://")) {
|
|
17503
|
+
if (url.endsWith("/ws"))
|
|
17504
|
+
return url;
|
|
17505
|
+
return `${url}/ws`;
|
|
17506
|
+
}
|
|
17507
|
+
if (url.startsWith("https://")) {
|
|
17508
|
+
url = "wss://" + url.slice("https://".length);
|
|
17509
|
+
} else if (url.startsWith("http://")) {
|
|
17510
|
+
url = "ws://" + url.slice("http://".length);
|
|
17511
|
+
}
|
|
17512
|
+
if (!url.endsWith("/ws")) {
|
|
17513
|
+
url = `${url}/ws`;
|
|
17514
|
+
}
|
|
17515
|
+
return url;
|
|
17516
|
+
}
|
|
17517
|
+
|
|
17478
17518
|
// src/commands/eventsource/add.ts
|
|
17479
17519
|
function uuid() {
|
|
17480
17520
|
return generateId();
|
|
@@ -17510,10 +17550,13 @@ var EventSourceAddCommand = {
|
|
|
17510
17550
|
describe: "Cron 表达式",
|
|
17511
17551
|
type: "string"
|
|
17512
17552
|
}).option("profile", {
|
|
17513
|
-
describe: "lark-cli
|
|
17553
|
+
describe: "Profile 名称(lark-cli / bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取配置;多 appId / 多账户场景必要,参考 #1637)",
|
|
17514
17554
|
type: "string"
|
|
17515
17555
|
}).option("address", {
|
|
17516
|
-
describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host
|
|
17556
|
+
describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host,v0.12 向后兼容)",
|
|
17557
|
+
type: "string"
|
|
17558
|
+
}).option("email", {
|
|
17559
|
+
describe: "Agent IM 注册邮箱(bounty-im 类型用,v0.13 server 协议;与 --profile 互斥)",
|
|
17517
17560
|
type: "string"
|
|
17518
17561
|
}).option("tls-skip-verify", {
|
|
17519
17562
|
describe: "跳过 TLS 证书校验(bounty-im 类型用,wss:// 自签名场景,生产环境不推荐)",
|
|
@@ -17540,9 +17583,38 @@ var EventSourceAddCommand = {
|
|
|
17540
17583
|
process.exit(1);
|
|
17541
17584
|
}
|
|
17542
17585
|
const eventTypes = a.eventTypes?.split(",").map((s) => s.trim());
|
|
17586
|
+
let resolvedEmail = a.email;
|
|
17587
|
+
let resolvedProfileName = a.profile;
|
|
17588
|
+
let profileApiBase;
|
|
17589
|
+
if (a.type === "bounty-im") {
|
|
17590
|
+
if (a.email && a.profile) {
|
|
17591
|
+
output.error(chalk59.red(`
|
|
17592
|
+
✗ --email 和 --profile 互斥(profile 文件已包含 email)。请选择其一。
|
|
17593
|
+
`));
|
|
17594
|
+
process.exit(1);
|
|
17595
|
+
}
|
|
17596
|
+
if (a.profile) {
|
|
17597
|
+
const profile = readBountyProfile(a.profile);
|
|
17598
|
+
if (!profile) {
|
|
17599
|
+
output.error(chalk59.red(`
|
|
17600
|
+
✗ Profile '${a.profile}' 不存在或格式错误。期望路径:~/.config/bounty/profiles/${a.profile}.json
|
|
17601
|
+
`));
|
|
17602
|
+
process.exit(1);
|
|
17603
|
+
}
|
|
17604
|
+
resolvedEmail = profile.email;
|
|
17605
|
+
profileApiBase = profile.api_base;
|
|
17606
|
+
}
|
|
17607
|
+
}
|
|
17543
17608
|
const envUrl = process.env.BOUNTY_SERVER_URL;
|
|
17544
17609
|
const fallback = envUrl || "http://localhost:8787";
|
|
17545
|
-
|
|
17610
|
+
let resolvedServerUrl;
|
|
17611
|
+
if (a.serverUrl || a.imServerUrl) {
|
|
17612
|
+
resolvedServerUrl = resolveServerUrl(a.serverUrl || a.imServerUrl, fallback);
|
|
17613
|
+
} else if (a.type === "bounty-im" && profileApiBase) {
|
|
17614
|
+
resolvedServerUrl = profileToWsUrl(profileApiBase);
|
|
17615
|
+
} else {
|
|
17616
|
+
resolvedServerUrl = resolveServerUrl(undefined, fallback);
|
|
17617
|
+
}
|
|
17546
17618
|
const config = {
|
|
17547
17619
|
id: uuid(),
|
|
17548
17620
|
name: a.name,
|
|
@@ -17554,6 +17626,7 @@ var EventSourceAddCommand = {
|
|
|
17554
17626
|
interval: a.interval,
|
|
17555
17627
|
cron: a.cron,
|
|
17556
17628
|
profile: a.profile,
|
|
17629
|
+
email: resolvedEmail,
|
|
17557
17630
|
address: a.address,
|
|
17558
17631
|
imServerUrl: resolvedServerUrl,
|
|
17559
17632
|
tlsSkipVerify: a.tlsSkipVerify === true,
|
|
@@ -17573,8 +17646,11 @@ var EventSourceAddCommand = {
|
|
|
17573
17646
|
if (a.interval) {
|
|
17574
17647
|
output.log(` Interval: ${chalk59.gray(`${a.interval}ms`)}`);
|
|
17575
17648
|
}
|
|
17576
|
-
if (
|
|
17577
|
-
output.log(` Profile: ${chalk59.gray(
|
|
17649
|
+
if (resolvedProfileName) {
|
|
17650
|
+
output.log(` Profile: ${chalk59.gray(resolvedProfileName)}`);
|
|
17651
|
+
}
|
|
17652
|
+
if (resolvedEmail) {
|
|
17653
|
+
output.log(` Email: ${chalk59.gray(resolvedEmail)}`);
|
|
17578
17654
|
}
|
|
17579
17655
|
if (a.address) {
|
|
17580
17656
|
output.log(` Address: ${chalk59.gray(a.address)}`);
|
|
@@ -17644,7 +17720,13 @@ var EventSourceUpdateCommand = {
|
|
|
17644
17720
|
describe: "是否启用",
|
|
17645
17721
|
type: "boolean"
|
|
17646
17722
|
}).option("address", {
|
|
17647
|
-
describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host
|
|
17723
|
+
describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host,v0.12 向后兼容)",
|
|
17724
|
+
type: "string"
|
|
17725
|
+
}).option("email", {
|
|
17726
|
+
describe: "Agent IM 注册邮箱(bounty-im 类型用,v0.13;与 --profile 互斥)",
|
|
17727
|
+
type: "string"
|
|
17728
|
+
}).option("profile", {
|
|
17729
|
+
describe: "Profile 名称(bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取并自动更新 email + imServerUrl)",
|
|
17648
17730
|
type: "string"
|
|
17649
17731
|
}).option("tls-skip-verify", {
|
|
17650
17732
|
describe: "跳过 TLS 证书校验(bounty-im 类型用,wss:// 自签名场景,生产环境不推荐)",
|
|
@@ -17679,6 +17761,25 @@ var EventSourceUpdateCommand = {
|
|
|
17679
17761
|
}
|
|
17680
17762
|
process.exit(1);
|
|
17681
17763
|
}
|
|
17764
|
+
if (match.source.type === "bounty-im" && a.email && a.profile) {
|
|
17765
|
+
output.error(chalk60.red(`
|
|
17766
|
+
✗ --email 和 --profile 互斥(profile 文件已包含 email)。请选择其一。
|
|
17767
|
+
`));
|
|
17768
|
+
process.exit(1);
|
|
17769
|
+
}
|
|
17770
|
+
let profileEmail;
|
|
17771
|
+
let profileApiBase;
|
|
17772
|
+
if (a.profile && match.source.type === "bounty-im") {
|
|
17773
|
+
const profile = readBountyProfile(a.profile);
|
|
17774
|
+
if (!profile) {
|
|
17775
|
+
output.error(chalk60.red(`
|
|
17776
|
+
✗ Profile '${a.profile}' 不存在或格式错误。期望路径:~/.config/bounty/profiles/${a.profile}.json
|
|
17777
|
+
`));
|
|
17778
|
+
process.exit(1);
|
|
17779
|
+
}
|
|
17780
|
+
profileEmail = profile.email;
|
|
17781
|
+
profileApiBase = profile.api_base;
|
|
17782
|
+
}
|
|
17682
17783
|
const partial = {};
|
|
17683
17784
|
if (a.name !== undefined)
|
|
17684
17785
|
partial.name = a.name;
|
|
@@ -17697,10 +17798,18 @@ var EventSourceUpdateCommand = {
|
|
|
17697
17798
|
partial.enabled = a.enabled;
|
|
17698
17799
|
if (a.address !== undefined)
|
|
17699
17800
|
partial.address = a.address;
|
|
17700
|
-
if (a.
|
|
17801
|
+
if (a.email !== undefined)
|
|
17802
|
+
partial.email = a.email;
|
|
17803
|
+
if (profileEmail !== undefined)
|
|
17804
|
+
partial.email = profileEmail;
|
|
17805
|
+
if (a.serverUrl !== undefined || a.imServerUrl !== undefined || profileApiBase !== undefined) {
|
|
17701
17806
|
const envUrl = process.env.BOUNTY_SERVER_URL;
|
|
17702
17807
|
const fallback = envUrl || "http://localhost:8787";
|
|
17703
|
-
|
|
17808
|
+
if (a.serverUrl !== undefined || a.imServerUrl !== undefined) {
|
|
17809
|
+
partial.imServerUrl = resolveServerUrl(a.serverUrl ?? a.imServerUrl, fallback);
|
|
17810
|
+
} else if (profileApiBase !== undefined) {
|
|
17811
|
+
partial.imServerUrl = profileToWsUrl(profileApiBase);
|
|
17812
|
+
}
|
|
17704
17813
|
}
|
|
17705
17814
|
if (a.tlsSkipVerify !== undefined)
|
|
17706
17815
|
partial.tlsSkipVerify = a.tlsSkipVerify === true;
|
|
@@ -19146,6 +19255,121 @@ class DecoratorNodeValidator extends BaseNodeValidator {
|
|
|
19146
19255
|
}
|
|
19147
19256
|
}
|
|
19148
19257
|
|
|
19258
|
+
// src/commands/workflow/validators/nodes/python-call-node-validator.ts
|
|
19259
|
+
class PythonCallNodeValidator extends BaseNodeValidator {
|
|
19260
|
+
nodeType = "python_call";
|
|
19261
|
+
getRequiredFields() {
|
|
19262
|
+
return ["module", "function"];
|
|
19263
|
+
}
|
|
19264
|
+
validateTypeSpecific(node) {
|
|
19265
|
+
const errors = [];
|
|
19266
|
+
const config = node.config ?? {};
|
|
19267
|
+
const moduleVal = config.module;
|
|
19268
|
+
if (moduleVal === undefined || moduleVal === null) {
|
|
19269
|
+
errors.push({
|
|
19270
|
+
type: "MISSING_REQUIRED_FIELD" /* MISSING_REQUIRED_FIELD */,
|
|
19271
|
+
description: 'Field "module" is required for python_call node',
|
|
19272
|
+
expected: 'module: "<python.module.path>"',
|
|
19273
|
+
actual: "undefined",
|
|
19274
|
+
fix: 'Add `module: "<python.module.path>"` to the node config',
|
|
19275
|
+
nodeId: node.id
|
|
19276
|
+
});
|
|
19277
|
+
} else if (typeof moduleVal !== "string") {
|
|
19278
|
+
errors.push({
|
|
19279
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19280
|
+
description: 'Field "module" has invalid type',
|
|
19281
|
+
expected: 'string (Python module path, e.g. "investment_strategy.scripts.market_timing")',
|
|
19282
|
+
actual: typeof moduleVal,
|
|
19283
|
+
fix: "Change `module` to a string",
|
|
19284
|
+
nodeId: node.id
|
|
19285
|
+
});
|
|
19286
|
+
} else if (!/^[A-Za-z_]\w*(\.[A-Za-z_]\w*)*$/.test(moduleVal)) {
|
|
19287
|
+
errors.push({
|
|
19288
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19289
|
+
description: `Field "module" is not a valid Python module path: "${moduleVal}"`,
|
|
19290
|
+
expected: 'dotted identifier like "pkg.sub.mod"',
|
|
19291
|
+
actual: moduleVal,
|
|
19292
|
+
fix: "Use only letters, digits, underscores, and dots",
|
|
19293
|
+
nodeId: node.id
|
|
19294
|
+
});
|
|
19295
|
+
}
|
|
19296
|
+
const fnVal = config.function;
|
|
19297
|
+
if (fnVal === undefined || fnVal === null) {
|
|
19298
|
+
errors.push({
|
|
19299
|
+
type: "MISSING_REQUIRED_FIELD" /* MISSING_REQUIRED_FIELD */,
|
|
19300
|
+
description: 'Field "function" is required for python_call node',
|
|
19301
|
+
expected: 'function: "<python_function_name>"',
|
|
19302
|
+
actual: "undefined",
|
|
19303
|
+
fix: 'Add `function: "<name>"` to the node config',
|
|
19304
|
+
nodeId: node.id
|
|
19305
|
+
});
|
|
19306
|
+
} else if (typeof fnVal !== "string") {
|
|
19307
|
+
errors.push({
|
|
19308
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19309
|
+
description: 'Field "function" has invalid type',
|
|
19310
|
+
expected: 'string (Python function name, e.g. "run")',
|
|
19311
|
+
actual: typeof fnVal,
|
|
19312
|
+
fix: "Change `function` to a string",
|
|
19313
|
+
nodeId: node.id
|
|
19314
|
+
});
|
|
19315
|
+
} else if (!/^[A-Za-z_]\w*$/.test(fnVal)) {
|
|
19316
|
+
errors.push({
|
|
19317
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19318
|
+
description: `Field "function" is not a valid Python identifier: "${fnVal}"`,
|
|
19319
|
+
expected: "Python identifier: starts with letter/underscore, contains only [A-Za-z0-9_]",
|
|
19320
|
+
actual: fnVal,
|
|
19321
|
+
fix: "Use a plain Python function name (no dots, no operators)",
|
|
19322
|
+
nodeId: node.id
|
|
19323
|
+
});
|
|
19324
|
+
}
|
|
19325
|
+
const argsVal = config.args;
|
|
19326
|
+
if (argsVal !== undefined && (typeof argsVal !== "object" || argsVal === null || Array.isArray(argsVal))) {
|
|
19327
|
+
errors.push({
|
|
19328
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19329
|
+
description: 'Field "args" has invalid type',
|
|
19330
|
+
expected: "object (kwargs to pass to the function)",
|
|
19331
|
+
actual: Array.isArray(argsVal) ? "array" : typeof argsVal,
|
|
19332
|
+
fix: "Change `args` to an object: args: { key: value }",
|
|
19333
|
+
nodeId: node.id
|
|
19334
|
+
});
|
|
19335
|
+
}
|
|
19336
|
+
if (config.cwd !== undefined && typeof config.cwd !== "string") {
|
|
19337
|
+
errors.push({
|
|
19338
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19339
|
+
description: 'Field "cwd" has invalid type',
|
|
19340
|
+
expected: "string (filesystem path)",
|
|
19341
|
+
actual: typeof config.cwd,
|
|
19342
|
+
fix: "Change `cwd` to a string",
|
|
19343
|
+
nodeId: node.id
|
|
19344
|
+
});
|
|
19345
|
+
}
|
|
19346
|
+
if (config.python !== undefined && typeof config.python !== "string") {
|
|
19347
|
+
errors.push({
|
|
19348
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19349
|
+
description: 'Field "python" has invalid type',
|
|
19350
|
+
expected: "string (path to python interpreter)",
|
|
19351
|
+
actual: typeof config.python,
|
|
19352
|
+
fix: "Change `python` to a string",
|
|
19353
|
+
nodeId: node.id
|
|
19354
|
+
});
|
|
19355
|
+
}
|
|
19356
|
+
if (config.timeout !== undefined) {
|
|
19357
|
+
const t = config.timeout;
|
|
19358
|
+
if (typeof t !== "number" || !Number.isFinite(t) || t <= 0) {
|
|
19359
|
+
errors.push({
|
|
19360
|
+
type: "INVALID_FIELD_TYPE" /* INVALID_FIELD_TYPE */,
|
|
19361
|
+
description: 'Field "timeout" has invalid type',
|
|
19362
|
+
expected: "positive number (milliseconds)",
|
|
19363
|
+
actual: typeof t === "number" ? `${t}` : typeof t,
|
|
19364
|
+
fix: "Change `timeout` to a positive number, e.g. timeout: 60000",
|
|
19365
|
+
nodeId: node.id
|
|
19366
|
+
});
|
|
19367
|
+
}
|
|
19368
|
+
}
|
|
19369
|
+
return errors;
|
|
19370
|
+
}
|
|
19371
|
+
}
|
|
19372
|
+
|
|
19149
19373
|
// src/commands/workflow/validators/node-validator-factory.ts
|
|
19150
19374
|
var validators = new Map;
|
|
19151
19375
|
validators.set("tool", new ToolNodeValidator);
|
|
@@ -19155,6 +19379,7 @@ validators.set("workflow", new WorkflowNodeValidator);
|
|
|
19155
19379
|
validators.set("condition", new ConditionNodeValidator);
|
|
19156
19380
|
validators.set("merge", new MergeNodeValidator);
|
|
19157
19381
|
validators.set("decorator", new DecoratorNodeValidator);
|
|
19382
|
+
validators.set("python_call", new PythonCallNodeValidator);
|
|
19158
19383
|
function getNodeValidator(type) {
|
|
19159
19384
|
return validators.get(type) || null;
|
|
19160
19385
|
}
|
|
@@ -20879,7 +21104,7 @@ Use `) + chalk74.cyan("roy-agent workflow nodes <type>") + chalk74.gray(" for de
|
|
|
20879
21104
|
|
|
20880
21105
|
// src/commands/workflow/commands/validate.ts
|
|
20881
21106
|
import chalk75 from "chalk";
|
|
20882
|
-
import { readFileSync } from "fs";
|
|
21107
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
20883
21108
|
async function parseWorkflowInput(input, yamlStr) {
|
|
20884
21109
|
const parseYaml = async (content) => {
|
|
20885
21110
|
const YAML2 = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
@@ -20887,7 +21112,7 @@ async function parseWorkflowInput(input, yamlStr) {
|
|
|
20887
21112
|
};
|
|
20888
21113
|
if (input && !yamlStr) {
|
|
20889
21114
|
try {
|
|
20890
|
-
const content =
|
|
21115
|
+
const content = readFileSync2(input, "utf-8");
|
|
20891
21116
|
return await parseYaml(content);
|
|
20892
21117
|
} catch (error) {
|
|
20893
21118
|
throw new Error(`Failed to read file "${input}": ${error.message}`);
|
|
@@ -21622,24 +21847,24 @@ var LspCommand = {
|
|
|
21622
21847
|
|
|
21623
21848
|
// src/commands/install/index.ts
|
|
21624
21849
|
import { spawnSync } from "node:child_process";
|
|
21625
|
-
import { existsSync as
|
|
21626
|
-
import { join as
|
|
21627
|
-
import { homedir as
|
|
21850
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync, cpSync } from "node:fs";
|
|
21851
|
+
import { join as join5, resolve } from "node:path";
|
|
21852
|
+
import { homedir as homedir4 } from "node:os";
|
|
21628
21853
|
function getConfigDir(scope) {
|
|
21629
|
-
return scope === "global" ?
|
|
21854
|
+
return scope === "global" ? join5(homedir4(), ".roy-agent") : join5(process.cwd(), ".roy");
|
|
21630
21855
|
}
|
|
21631
21856
|
function detectDefaultScope() {
|
|
21632
|
-
const projectDir =
|
|
21633
|
-
return
|
|
21857
|
+
const projectDir = join5(process.cwd(), ".roy");
|
|
21858
|
+
return existsSync4(projectDir) ? "project" : "global";
|
|
21634
21859
|
}
|
|
21635
21860
|
function getConfigPath(scope) {
|
|
21636
|
-
return
|
|
21861
|
+
return join5(getConfigDir(scope), "plugins.json");
|
|
21637
21862
|
}
|
|
21638
21863
|
function loadPlugins(scope) {
|
|
21639
21864
|
const configPath = getConfigPath(scope);
|
|
21640
21865
|
try {
|
|
21641
|
-
if (
|
|
21642
|
-
const raw =
|
|
21866
|
+
if (existsSync4(configPath)) {
|
|
21867
|
+
const raw = readFileSync3(configPath, "utf-8");
|
|
21643
21868
|
const config = JSON.parse(raw);
|
|
21644
21869
|
return config.plugins ?? [];
|
|
21645
21870
|
}
|
|
@@ -21649,7 +21874,7 @@ function loadPlugins(scope) {
|
|
|
21649
21874
|
function savePlugins(plugins, scope) {
|
|
21650
21875
|
const configDir = getConfigDir(scope);
|
|
21651
21876
|
const configPath = getConfigPath(scope);
|
|
21652
|
-
if (!
|
|
21877
|
+
if (!existsSync4(configDir)) {
|
|
21653
21878
|
mkdirSync(configDir, { recursive: true });
|
|
21654
21879
|
}
|
|
21655
21880
|
const config = { plugins };
|
|
@@ -21665,10 +21890,10 @@ function stripVersionSpec(packageName) {
|
|
|
21665
21890
|
function readPackageInfo(packageName) {
|
|
21666
21891
|
const bareName = packageName.startsWith("/") || packageName.startsWith(".") ? packageName : stripVersionSpec(packageName);
|
|
21667
21892
|
if (packageName.startsWith("/") || packageName.startsWith(".")) {
|
|
21668
|
-
const localPkgPath =
|
|
21669
|
-
if (
|
|
21893
|
+
const localPkgPath = join5(packageName, "package.json");
|
|
21894
|
+
if (existsSync4(localPkgPath)) {
|
|
21670
21895
|
try {
|
|
21671
|
-
const pkg = JSON.parse(
|
|
21896
|
+
const pkg = JSON.parse(readFileSync3(localPkgPath, "utf-8"));
|
|
21672
21897
|
return {
|
|
21673
21898
|
version: pkg.version ?? "0.0.0",
|
|
21674
21899
|
name: pkg.name ?? packageName,
|
|
@@ -21680,19 +21905,19 @@ function readPackageInfo(packageName) {
|
|
|
21680
21905
|
}
|
|
21681
21906
|
}
|
|
21682
21907
|
const searchPaths = [
|
|
21683
|
-
|
|
21908
|
+
join5(process.cwd(), "node_modules", bareName, "package.json"),
|
|
21684
21909
|
resolve(process.cwd(), "..", "node_modules", bareName, "package.json"),
|
|
21685
|
-
|
|
21686
|
-
|
|
21910
|
+
join5(process.cwd(), ".roy", "plugins", bareName, "package.json"),
|
|
21911
|
+
join5(homedir4(), ".roy-agent", "node_modules", bareName, "package.json"),
|
|
21687
21912
|
...(() => {
|
|
21688
21913
|
const globalRoot = getNpmGlobalRoot();
|
|
21689
|
-
return globalRoot ? [
|
|
21914
|
+
return globalRoot ? [join5(globalRoot, bareName, "package.json")] : [];
|
|
21690
21915
|
})()
|
|
21691
21916
|
];
|
|
21692
21917
|
for (const pkgPath of searchPaths) {
|
|
21693
21918
|
try {
|
|
21694
|
-
if (
|
|
21695
|
-
const pkg = JSON.parse(
|
|
21919
|
+
if (existsSync4(pkgPath)) {
|
|
21920
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
21696
21921
|
return {
|
|
21697
21922
|
version: pkg.version ?? "0.0.0",
|
|
21698
21923
|
name: pkg.name ?? bareName,
|
|
@@ -21715,15 +21940,15 @@ function getNpmGlobalRoot() {
|
|
|
21715
21940
|
return null;
|
|
21716
21941
|
}
|
|
21717
21942
|
function getPackageManagerCommand() {
|
|
21718
|
-
if (
|
|
21719
|
-
if (
|
|
21943
|
+
if (existsSync4(join5(process.cwd(), "pnpm-lock.yaml"))) {
|
|
21944
|
+
if (existsSync4(join5(process.cwd(), "pnpm-workspace.yaml"))) {
|
|
21720
21945
|
return "pnpm -w";
|
|
21721
21946
|
}
|
|
21722
21947
|
return "pnpm";
|
|
21723
21948
|
}
|
|
21724
|
-
if (
|
|
21949
|
+
if (existsSync4(join5(process.cwd(), "yarn.lock")))
|
|
21725
21950
|
return "yarn";
|
|
21726
|
-
if (
|
|
21951
|
+
if (existsSync4(join5(process.cwd(), "bun.lock")) || existsSync4(join5(process.cwd(), "bun.lockb")))
|
|
21727
21952
|
return "bun";
|
|
21728
21953
|
return "npm";
|
|
21729
21954
|
}
|
|
@@ -21762,14 +21987,14 @@ var InstallPackageCommand = {
|
|
|
21762
21987
|
}
|
|
21763
21988
|
resolvedName = info2.name;
|
|
21764
21989
|
const srcDir = resolve(packageName);
|
|
21765
|
-
if (!
|
|
21990
|
+
if (!existsSync4(srcDir)) {
|
|
21766
21991
|
console.error(`
|
|
21767
21992
|
❌ Local path '${srcDir}' does not exist.
|
|
21768
21993
|
`);
|
|
21769
21994
|
process.exit(1);
|
|
21770
21995
|
}
|
|
21771
|
-
const pluginDir =
|
|
21772
|
-
if (!
|
|
21996
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
|
|
21997
|
+
if (!existsSync4(pluginDir)) {
|
|
21773
21998
|
mkdirSync(pluginDir, { recursive: true });
|
|
21774
21999
|
}
|
|
21775
22000
|
const result = spawnSync("cp", ["-r", `${srcDir}/.`, pluginDir], {
|
|
@@ -21804,12 +22029,12 @@ var InstallPackageCommand = {
|
|
|
21804
22029
|
process.exit(1);
|
|
21805
22030
|
}
|
|
21806
22031
|
resolvedName = info2.name;
|
|
21807
|
-
const pluginDir =
|
|
21808
|
-
if (!
|
|
22032
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
|
|
22033
|
+
if (!existsSync4(pluginDir)) {
|
|
21809
22034
|
mkdirSync(pluginDir, { recursive: true });
|
|
21810
22035
|
}
|
|
21811
|
-
const nmPath =
|
|
21812
|
-
if (
|
|
22036
|
+
const nmPath = join5(process.cwd(), "node_modules", packageName);
|
|
22037
|
+
if (existsSync4(nmPath)) {
|
|
21813
22038
|
spawnSync("cp", ["-r", `${nmPath}/.`, pluginDir], { stdio: "inherit", shell: false });
|
|
21814
22039
|
}
|
|
21815
22040
|
}
|
|
@@ -21840,14 +22065,14 @@ var InstallPackageCommand = {
|
|
|
21840
22065
|
`);
|
|
21841
22066
|
process.exit(1);
|
|
21842
22067
|
}
|
|
21843
|
-
const globalNm =
|
|
21844
|
-
if (!
|
|
21845
|
-
mkdirSync(
|
|
22068
|
+
const globalNm = join5(homedir4(), ".roy-agent", "node_modules", resolvedGlobalName);
|
|
22069
|
+
if (!existsSync4(globalNm)) {
|
|
22070
|
+
mkdirSync(join5(homedir4(), ".roy-agent", "node_modules"), { recursive: true });
|
|
21846
22071
|
const rootResult = spawnSync("npm", ["root", "-g"], { stdio: "pipe", shell: false });
|
|
21847
22072
|
const globalRoot = rootResult.stdout?.toString().trim();
|
|
21848
22073
|
if (globalRoot) {
|
|
21849
|
-
const globalInstalled =
|
|
21850
|
-
if (
|
|
22074
|
+
const globalInstalled = join5(globalRoot, resolvedGlobalName);
|
|
22075
|
+
if (existsSync4(globalInstalled)) {
|
|
21851
22076
|
cpSync(globalInstalled, globalNm, { recursive: true });
|
|
21852
22077
|
}
|
|
21853
22078
|
}
|
|
@@ -21958,8 +22183,8 @@ var InstallRemoveCommand = {
|
|
|
21958
22183
|
\uD83D\uDDD1️ Removing plugin: ${plugin.packageName}@${plugin.version} (${scope})
|
|
21959
22184
|
`);
|
|
21960
22185
|
if (scope === "project") {
|
|
21961
|
-
const pluginDir =
|
|
21962
|
-
if (
|
|
22186
|
+
const pluginDir = join5(process.cwd(), ".roy", "plugins", plugin.packageName);
|
|
22187
|
+
if (existsSync4(pluginDir)) {
|
|
21963
22188
|
spawnSync("rm", ["-rf", pluginDir], { stdio: "inherit", shell: false });
|
|
21964
22189
|
console.log(` Removed plugin directory: ${pluginDir}`);
|
|
21965
22190
|
}
|
|
@@ -21974,8 +22199,8 @@ var InstallRemoveCommand = {
|
|
|
21974
22199
|
`);
|
|
21975
22200
|
process.exit(result.status ?? 1);
|
|
21976
22201
|
}
|
|
21977
|
-
const globalNm =
|
|
21978
|
-
if (
|
|
22202
|
+
const globalNm = join5(homedir4(), ".roy-agent", "node_modules", plugin.packageName);
|
|
22203
|
+
if (existsSync4(globalNm)) {
|
|
21979
22204
|
spawnSync("rm", ["-rf", globalNm], { stdio: "inherit", shell: false });
|
|
21980
22205
|
}
|
|
21981
22206
|
}
|
|
Binary file
|