@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.
@@ -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.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
- 结果: ${truncatedResult}`;
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
- description: "最大展示深度(不限层级请忽略)"
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.maxDepth, rootId: args.rootId }));
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 profile(lark-cli 类型用,多 appId 场景必要,参考 #1637)",
17560
+ describe: "Profile 名称(lark-cli / bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取配置;多 appId / 多账户场景必要,参考 #1637)",
17515
17561
  type: "string"
17516
- }).option("address", {
17517
- describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host)",
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
- const resolvedServerUrl = resolveServerUrl(a.serverUrl || a.imServerUrl, fallback);
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
- address: a.address,
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 (a.profile) {
17578
- output.log(` Profile: ${chalk59.gray(a.profile)}`);
17652
+ if (resolvedProfileName) {
17653
+ output.log(` Profile: ${chalk59.gray(resolvedProfileName)}`);
17579
17654
  }
17580
- if (a.address) {
17581
- output.log(` Address: ${chalk59.gray(a.address)}`);
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("address", {
17648
- describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host)",
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.address !== undefined)
17700
- partial.address = a.address;
17701
- if (a.serverUrl !== undefined || a.imServerUrl !== undefined) {
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
- partial.imServerUrl = resolveServerUrl(a.serverUrl ?? a.imServerUrl, fallback);
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 = readFileSync(input, "utf-8");
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 existsSync3, readFileSync as readFileSync2, writeFileSync, mkdirSync, cpSync } from "node:fs";
21627
- import { join as join4, resolve } from "node:path";
21628
- import { homedir as homedir3 } from "node:os";
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" ? join4(homedir3(), ".roy-agent") : join4(process.cwd(), ".roy");
21849
+ return scope === "global" ? join5(homedir4(), ".roy-agent") : join5(process.cwd(), ".roy");
21631
21850
  }
21632
21851
  function detectDefaultScope() {
21633
- const projectDir = join4(process.cwd(), ".roy");
21634
- return existsSync3(projectDir) ? "project" : "global";
21852
+ const projectDir = join5(process.cwd(), ".roy");
21853
+ return existsSync4(projectDir) ? "project" : "global";
21635
21854
  }
21636
21855
  function getConfigPath(scope) {
21637
- return join4(getConfigDir(scope), "plugins.json");
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 (existsSync3(configPath)) {
21643
- const raw = readFileSync2(configPath, "utf-8");
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 (!existsSync3(configDir)) {
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 = join4(packageName, "package.json");
21670
- if (existsSync3(localPkgPath)) {
21888
+ const localPkgPath = join5(packageName, "package.json");
21889
+ if (existsSync4(localPkgPath)) {
21671
21890
  try {
21672
- const pkg = JSON.parse(readFileSync2(localPkgPath, "utf-8"));
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
- join4(process.cwd(), "node_modules", bareName, "package.json"),
21903
+ join5(process.cwd(), "node_modules", bareName, "package.json"),
21685
21904
  resolve(process.cwd(), "..", "node_modules", bareName, "package.json"),
21686
- join4(process.cwd(), ".roy", "plugins", bareName, "package.json"),
21687
- join4(homedir3(), ".roy-agent", "node_modules", bareName, "package.json"),
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 ? [join4(globalRoot, bareName, "package.json")] : [];
21909
+ return globalRoot ? [join5(globalRoot, bareName, "package.json")] : [];
21691
21910
  })()
21692
21911
  ];
21693
21912
  for (const pkgPath of searchPaths) {
21694
21913
  try {
21695
- if (existsSync3(pkgPath)) {
21696
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
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 (existsSync3(join4(process.cwd(), "pnpm-lock.yaml"))) {
21720
- if (existsSync3(join4(process.cwd(), "pnpm-workspace.yaml"))) {
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 (existsSync3(join4(process.cwd(), "yarn.lock")))
21944
+ if (existsSync4(join5(process.cwd(), "yarn.lock")))
21726
21945
  return "yarn";
21727
- if (existsSync3(join4(process.cwd(), "bun.lock")) || existsSync3(join4(process.cwd(), "bun.lockb")))
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 (!existsSync3(srcDir)) {
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 = join4(process.cwd(), ".roy", "plugins", resolvedName);
21773
- if (!existsSync3(pluginDir)) {
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 = join4(process.cwd(), ".roy", "plugins", resolvedName);
21809
- if (!existsSync3(pluginDir)) {
22027
+ const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
22028
+ if (!existsSync4(pluginDir)) {
21810
22029
  mkdirSync(pluginDir, { recursive: true });
21811
22030
  }
21812
- const nmPath = join4(process.cwd(), "node_modules", packageName);
21813
- if (existsSync3(nmPath)) {
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 = join4(homedir3(), ".roy-agent", "node_modules", resolvedGlobalName);
21845
- if (!existsSync3(globalNm)) {
21846
- mkdirSync(join4(homedir3(), ".roy-agent", "node_modules"), { recursive: true });
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 = join4(globalRoot, resolvedGlobalName);
21851
- if (existsSync3(globalInstalled)) {
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 = join4(process.cwd(), ".roy", "plugins", plugin.packageName);
21963
- if (existsSync3(pluginDir)) {
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 = join4(homedir3(), ".roy-agent", "node_modules", plugin.packageName);
21979
- if (existsSync3(globalNm)) {
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.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
- 结果: ${truncatedResult}`;
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
- description: "最大展示深度(不限层级请忽略)"
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.maxDepth, rootId: args.rootId }));
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 profile(lark-cli 类型用,多 appId 场景必要,参考 #1637)",
17559
+ describe: "Profile 名称(lark-cli / bounty-im 类型用,从 ~/.config/bounty/profiles/<name>.json 读取配置;多 appId / 多账户场景必要,参考 #1637)",
17514
17560
  type: "string"
17515
- }).option("address", {
17516
- describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host)",
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
- const resolvedServerUrl = resolveServerUrl(a.serverUrl || a.imServerUrl, fallback);
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
- address: a.address,
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 (a.profile) {
17577
- output.log(` Profile: ${chalk59.gray(a.profile)}`);
17651
+ if (resolvedProfileName) {
17652
+ output.log(` Profile: ${chalk59.gray(resolvedProfileName)}`);
17578
17653
  }
17579
- if (a.address) {
17580
- output.log(` Address: ${chalk59.gray(a.address)}`);
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("address", {
17647
- describe: "Agent IM 地址(bounty-im 类型用,格式:agent-id@host)",
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.address !== undefined)
17699
- partial.address = a.address;
17700
- if (a.serverUrl !== undefined || a.imServerUrl !== undefined) {
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
- partial.imServerUrl = resolveServerUrl(a.serverUrl ?? a.imServerUrl, fallback);
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 = readFileSync(input, "utf-8");
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 existsSync3, readFileSync as readFileSync2, writeFileSync, mkdirSync, cpSync } from "node:fs";
21626
- import { join as join4, resolve } from "node:path";
21627
- import { homedir as homedir3 } from "node:os";
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" ? join4(homedir3(), ".roy-agent") : join4(process.cwd(), ".roy");
21848
+ return scope === "global" ? join5(homedir4(), ".roy-agent") : join5(process.cwd(), ".roy");
21630
21849
  }
21631
21850
  function detectDefaultScope() {
21632
- const projectDir = join4(process.cwd(), ".roy");
21633
- return existsSync3(projectDir) ? "project" : "global";
21851
+ const projectDir = join5(process.cwd(), ".roy");
21852
+ return existsSync4(projectDir) ? "project" : "global";
21634
21853
  }
21635
21854
  function getConfigPath(scope) {
21636
- return join4(getConfigDir(scope), "plugins.json");
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 (existsSync3(configPath)) {
21642
- const raw = readFileSync2(configPath, "utf-8");
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 (!existsSync3(configDir)) {
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 = join4(packageName, "package.json");
21669
- if (existsSync3(localPkgPath)) {
21887
+ const localPkgPath = join5(packageName, "package.json");
21888
+ if (existsSync4(localPkgPath)) {
21670
21889
  try {
21671
- const pkg = JSON.parse(readFileSync2(localPkgPath, "utf-8"));
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
- join4(process.cwd(), "node_modules", bareName, "package.json"),
21902
+ join5(process.cwd(), "node_modules", bareName, "package.json"),
21684
21903
  resolve(process.cwd(), "..", "node_modules", bareName, "package.json"),
21685
- join4(process.cwd(), ".roy", "plugins", bareName, "package.json"),
21686
- join4(homedir3(), ".roy-agent", "node_modules", bareName, "package.json"),
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 ? [join4(globalRoot, bareName, "package.json")] : [];
21908
+ return globalRoot ? [join5(globalRoot, bareName, "package.json")] : [];
21690
21909
  })()
21691
21910
  ];
21692
21911
  for (const pkgPath of searchPaths) {
21693
21912
  try {
21694
- if (existsSync3(pkgPath)) {
21695
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
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 (existsSync3(join4(process.cwd(), "pnpm-lock.yaml"))) {
21719
- if (existsSync3(join4(process.cwd(), "pnpm-workspace.yaml"))) {
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 (existsSync3(join4(process.cwd(), "yarn.lock")))
21943
+ if (existsSync4(join5(process.cwd(), "yarn.lock")))
21725
21944
  return "yarn";
21726
- if (existsSync3(join4(process.cwd(), "bun.lock")) || existsSync3(join4(process.cwd(), "bun.lockb")))
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 (!existsSync3(srcDir)) {
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 = join4(process.cwd(), ".roy", "plugins", resolvedName);
21772
- if (!existsSync3(pluginDir)) {
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 = join4(process.cwd(), ".roy", "plugins", resolvedName);
21808
- if (!existsSync3(pluginDir)) {
22026
+ const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
22027
+ if (!existsSync4(pluginDir)) {
21809
22028
  mkdirSync(pluginDir, { recursive: true });
21810
22029
  }
21811
- const nmPath = join4(process.cwd(), "node_modules", packageName);
21812
- if (existsSync3(nmPath)) {
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 = join4(homedir3(), ".roy-agent", "node_modules", resolvedGlobalName);
21844
- if (!existsSync3(globalNm)) {
21845
- mkdirSync(join4(homedir3(), ".roy-agent", "node_modules"), { recursive: true });
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 = join4(globalRoot, resolvedGlobalName);
21850
- if (existsSync3(globalInstalled)) {
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 = join4(process.cwd(), ".roy", "plugins", plugin.packageName);
21962
- if (existsSync3(pluginDir)) {
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 = join4(homedir3(), ".roy-agent", "node_modules", plugin.packageName);
21978
- if (existsSync3(globalNm)) {
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-setting/roy-agent-cli",
3
- "version": "1.6.6",
3
+ "version": "1.6.8",
4
4
  "type": "module",
5
5
  "description": "CLI for roy-agent - Non-interactive command execution",
6
6
  "main": "./dist/index.js",