digitalsee-ai-flow-cli 0.7.6 → 0.7.24-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,6 +51,8 @@ exports.resolveErrorHandlerFile = resolveErrorHandlerFile;
51
51
  exports.checkPropertyValidation = checkPropertyValidation;
52
52
  exports.checkSpecialNodeValidation = checkSpecialNodeValidation;
53
53
  exports.validateVariableRefs = validateVariableRefs;
54
+ exports.validateNodeSchemaProperties = validateNodeSchemaProperties;
55
+ exports.printNodeSchemaFields = printNodeSchemaFields;
54
56
  const fs = __importStar(require("fs"));
55
57
  const chalk_1 = __importDefault(require("chalk"));
56
58
  const output_1 = require("@/utils/output");
@@ -263,14 +265,23 @@ function printNodeConfigDetail(node) {
263
265
  ];
264
266
  (0, output_1.printKeyValue)(pairs, ' ');
265
267
  const subParams = node.config_schema?.sub_params;
266
- if (subParams && subParams.length > 0) {
268
+ const hasSubParams = subParams && subParams.length > 0;
269
+ const hasFlatProperties = !hasSubParams && node.properties && Object.keys(node.properties).length > 0;
270
+ if (hasSubParams) {
267
271
  console.log(chalk_1.default.gray(` 配置字段 (${subParams.length}):`));
268
272
  for (const p of subParams) {
269
273
  const required = p.required ? chalk_1.default.red('*') : ' ';
270
274
  console.log(` ${required} ${chalk_1.default.cyan(p.name)} ${chalk_1.default.gray(`[${p.page_control || p.type}]`)} ${p.display_name || ''} ${p.description ? `- ${p.description}` : ''}`);
271
275
  }
272
276
  }
273
- if (node.properties && Object.keys(node.properties).length > 0) {
277
+ if (hasFlatProperties) {
278
+ console.log(chalk_1.default.gray(` 当前配置值:`));
279
+ for (const [key, val] of Object.entries(node.properties)) {
280
+ const displayVal = typeof val === 'object' ? JSON.stringify(val) : String(val);
281
+ console.log(` ${chalk_1.default.yellow(key)} = ${displayVal}`);
282
+ }
283
+ }
284
+ else if (node.properties && Object.keys(node.properties).length > 0) {
274
285
  console.log(chalk_1.default.gray(` 当前配置值:`));
275
286
  const subParamMap = new Map();
276
287
  for (const p of subParams ?? []) {
@@ -402,4 +413,69 @@ async function validateVariableRefs(configValues, flowId, nodeId, json) {
402
413
  (0, output_1.printInfo)('变量引用验证通过');
403
414
  return false;
404
415
  }
416
+ /**
417
+ * 校验 properties 是否符合 node_schema.input_fields 定义
418
+ */
419
+ function validateNodeSchemaProperties(properties, inputFields) {
420
+ const errors = [];
421
+ for (const field of inputFields) {
422
+ const value = properties[field.key];
423
+ const hasValue = value !== undefined && value !== null;
424
+ if (field.required && !hasValue) {
425
+ errors.push({
426
+ field: field.key,
427
+ rule: 'required',
428
+ message: `${field.label} (${field.key}) 是必填字段`,
429
+ sample: '',
430
+ });
431
+ }
432
+ if (hasValue) {
433
+ const type = field.type.toUpperCase();
434
+ if ((type === 'NUMBER' || type === 'INTEGER') &&
435
+ typeof value !== 'number' &&
436
+ (typeof value !== 'string' || isNaN(Number(value)))) {
437
+ errors.push({
438
+ field: field.key,
439
+ rule: 'type',
440
+ message: `${field.label} (${field.key}) 应为数字类型,实际为 ${typeof value}`,
441
+ sample: '',
442
+ });
443
+ }
444
+ else if (type === 'BOOLEAN' && typeof value !== 'boolean') {
445
+ errors.push({
446
+ field: field.key,
447
+ rule: 'type',
448
+ message: `${field.label} (${field.key}) 应为布尔类型,实际为 ${typeof value}`,
449
+ sample: '',
450
+ });
451
+ }
452
+ else if (type === 'SELECT' && typeof value !== 'string') {
453
+ errors.push({
454
+ field: field.key,
455
+ rule: 'type',
456
+ message: `${field.label} (${field.key}) 应为字符串类型 (SELECT),实际为 ${typeof value}`,
457
+ sample: '',
458
+ });
459
+ }
460
+ }
461
+ }
462
+ return errors;
463
+ }
464
+ /**
465
+ * 打印 node_schema.input_fields 字段列表
466
+ */
467
+ function printNodeSchemaFields(inputFields) {
468
+ if (!inputFields || inputFields.length === 0)
469
+ return;
470
+ console.log(chalk_1.default.gray(` 配置字段 (${inputFields.length}):`));
471
+ for (const field of inputFields) {
472
+ const required = field.required ? chalk_1.default.red('*') : ' ';
473
+ const typeLabel = field.type.toLowerCase();
474
+ const defaultStr = field.default_value !== undefined && field.default_value !== null
475
+ ? chalk_1.default.dim(` [默认: ${field.default_value}]`)
476
+ : '';
477
+ const helpStr = field.help_text ? chalk_1.default.gray(` - ${field.help_text}`) : '';
478
+ console.log(` ${required} ${chalk_1.default.cyan(field.key)} ${chalk_1.default.gray(`[${typeLabel}]`)} ${field.label}${defaultStr}${helpStr}`);
479
+ }
480
+ }
405
481
  //# sourceMappingURL=helpers.js.map
@@ -296,14 +296,28 @@ function registerFlowNode(flowCmd) {
296
296
  return;
297
297
  }
298
298
  }
299
- let configSchema = action.config_schema || {};
299
+ const hasNodeSchema = !!action.node_schema;
300
+ let configSchema = null;
301
+ if (!hasNodeSchema) {
302
+ configSchema =
303
+ action.config_schema || {};
304
+ }
300
305
  const overrideValues = (0, helpers_1.resolveDataOption)(options, helpers_1.NODE_CREATE_DATA_SCHEMA);
301
306
  if (overrideValues && overrideValues.position) {
302
307
  const ovPos = overrideValues.position;
303
308
  posX = Number(ovPos.x) || posX;
304
309
  posY = Number(ovPos.y) || posY;
305
310
  }
306
- const config = (0, format_1.deepMerge)({ properties: action.config_schema }, overrideValues ?? {});
311
+ let config;
312
+ if (hasNodeSchema) {
313
+ // node_schema 模式:properties 直接透传,不经过 deepMerge
314
+ config = {
315
+ properties: overrideValues?.properties ?? {},
316
+ };
317
+ }
318
+ else {
319
+ config = (0, format_1.deepMerge)({ properties: action.config_schema }, overrideValues ?? {});
320
+ }
307
321
  const defaultNodeType = trigger ? 'StartEventNode' : 'ActionNode';
308
322
  const node_type = options.nodeType || action.action_type || defaultNodeType;
309
323
  if (isFirstNode && node_type !== 'StartEventNode') {
@@ -329,6 +343,10 @@ function registerFlowNode(flowCmd) {
329
343
  if (accountId) {
330
344
  payload.account_id = accountId;
331
345
  }
346
+ if (hasNodeSchema && action.node_schema) {
347
+ payload.action_key = action.node_schema.key;
348
+ payload.action_ver = action.node_schema.version;
349
+ }
332
350
  if (options.name) {
333
351
  payload.action_name = options.name;
334
352
  }
@@ -340,12 +358,21 @@ function registerFlowNode(flowCmd) {
340
358
  return;
341
359
  if (eh)
342
360
  payload.error_handler = eh;
343
- if (configSchema) {
361
+ if (hasNodeSchema && action.node_schema) {
362
+ const inputFields = action.node_schema.input_fields;
363
+ if (inputFields && inputFields.length > 0) {
364
+ if ((0, helpers_1.checkPropertyValidation)((0, helpers_1.validateNodeSchemaProperties)(config.properties ?? {}, inputFields), !!options.json))
365
+ return;
366
+ }
367
+ }
368
+ else if (configSchema) {
344
369
  if ((0, helpers_1.checkPropertyValidation)((0, format_1.validateNodePropertyValues)(configSchema), !!options.json))
345
370
  return;
346
371
  }
347
- if ((0, helpers_1.checkSpecialNodeValidation)((0, format_1.validateSpecialNodeType)(node_type, payload, configSchema), !!options.json))
348
- return;
372
+ if (!hasNodeSchema && configSchema) {
373
+ if ((0, helpers_1.checkSpecialNodeValidation)((0, format_1.validateSpecialNodeType)(node_type, payload, configSchema), !!options.json))
374
+ return;
375
+ }
349
376
  (0, output_1.printInfo)('正在创建节点...');
350
377
  const result = await (0, node_1.createNode)(payload);
351
378
  const resultObj = result;
@@ -487,23 +514,70 @@ function registerFlowNode(flowCmd) {
487
514
  if ((0, helpers_1.checkFlowNotOnline)(nodeFlow, !!options.json))
488
515
  return;
489
516
  const nd = nodeDetail;
490
- let updateData = {
491
- flow_id: flowId,
492
- ...nd,
493
- };
517
+ const hasNodeSchema = !!(nd.action_key && nd.action_ver);
518
+ // node_schema 模式:获取 action 以拿到 action_key / action_ver
519
+ let nodeSchemaAction;
520
+ if (hasNodeSchema) {
521
+ try {
522
+ const params = {
523
+ name: nd.action_key,
524
+ flow_id: flowId,
525
+ trigger: nd.node_type === 'StartEventNode',
526
+ page: 1,
527
+ size: 20,
528
+ };
529
+ const actions = await (0, node_1.searchActions)(params);
530
+ nodeSchemaAction = actions.find((a) => a.action_key === nd.action_key);
531
+ }
532
+ catch (e) {
533
+ (0, output_1.printError)(`获取 node_schema action 失败: ${e.message}`);
534
+ // 获取失败则回退到旧模式
535
+ }
536
+ }
537
+ let updateData;
538
+ if (hasNodeSchema && nodeSchemaAction?.node_schema) {
539
+ const ns = nodeSchemaAction.node_schema;
540
+ const existingProps = nd.properties ?? {};
541
+ const pos = nd.position ?? { x: 0, y: 0 };
542
+ updateData = {
543
+ flow_id: flowId,
544
+ properties: { ...existingProps },
545
+ position: { ...pos },
546
+ action_id: options.actionId || nd.action_id,
547
+ account_id: options.accountId ?? nd.account_id ?? null,
548
+ action_key: ns.key,
549
+ action_ver: ns.version,
550
+ };
551
+ }
552
+ else {
553
+ updateData = {
554
+ flow_id: flowId,
555
+ ...nd,
556
+ };
557
+ if (nd.action_id)
558
+ updateData.action_id = nd.action_id;
559
+ if (nd.connector_id)
560
+ updateData.connector_id = nd.connector_id;
561
+ }
494
562
  if (nd.position)
495
563
  updateData.position = { ...nd.position };
496
- if (nd.action_id)
497
- updateData.action_id = nd.action_id;
498
- if (nd.connector_id)
499
- updateData.connector_id = nd.connector_id;
500
564
  if (nd.account_id)
501
565
  updateData.account_id = nd.account_id;
502
566
  if (nd.note != null)
503
567
  updateData.note = nd.note;
504
568
  const configValues = (0, helpers_1.resolveDataOption)(options, helpers_1.NODE_UPDATE_DATA_SCHEMA);
505
569
  if (configValues) {
506
- updateData = (0, format_1.deepMerge)(updateData, configValues);
570
+ if (hasNodeSchema && configValues.properties) {
571
+ // node_schema 模式:properties 浅合并,不经过 deepMerge
572
+ const existingProps = updateData.properties ?? {};
573
+ updateData.properties = {
574
+ ...existingProps,
575
+ ...configValues.properties,
576
+ };
577
+ }
578
+ else {
579
+ updateData = (0, format_1.deepMerge)(updateData, configValues);
580
+ }
507
581
  }
508
582
  if (options.validateVars && configValues) {
509
583
  if (await (0, helpers_1.validateVariableRefs)(configValues, flowId, nodeId, !!options.json))
@@ -541,11 +615,23 @@ function registerFlowNode(flowCmd) {
541
615
  return;
542
616
  }
543
617
  if (updateData.properties) {
544
- if ((0, helpers_1.checkPropertyValidation)((0, format_1.validateNodePropertyValues)(updateData.properties), !!options.json))
618
+ if (hasNodeSchema) {
619
+ const inputFields = (nodeSchemaAction?.node_schema?.input_fields ??
620
+ []);
621
+ if (inputFields.length > 0) {
622
+ if ((0, helpers_1.checkPropertyValidation)((0, helpers_1.validateNodeSchemaProperties)(updateData.properties, inputFields), !!options.json))
623
+ return;
624
+ }
625
+ }
626
+ else {
627
+ if ((0, helpers_1.checkPropertyValidation)((0, format_1.validateNodePropertyValues)(updateData.properties), !!options.json))
628
+ return;
629
+ }
630
+ }
631
+ if (!hasNodeSchema) {
632
+ if ((0, helpers_1.checkSpecialNodeValidation)((0, format_1.validateSpecialNodeType)(String(nd.node_type), updateData, nd.config_schema), !!options.json))
545
633
  return;
546
634
  }
547
- if ((0, helpers_1.checkSpecialNodeValidation)((0, format_1.validateSpecialNodeType)(String(nd.node_type), updateData, nd.config_schema), !!options.json))
548
- return;
549
635
  if (hasUpdateChanges) {
550
636
  (0, output_1.printInfo)('正在更新节点...');
551
637
  await (0, node_1.updateNode)(nodeId, updateData);
@@ -9,19 +9,24 @@ const node_1 = require("@/api/node");
9
9
  const skillGenerator_1 = require("@/services/skillGenerator");
10
10
  const output_1 = require("@/utils/output");
11
11
  const format_1 = require("@/utils/format");
12
+ const helpers_1 = require("@/commands/flow/helpers");
12
13
  const chalk_1 = __importDefault(require("chalk"));
13
14
  function registerKnowledgeCommand(program) {
14
15
  const knowledgeCmd = program.command('knowledge').description('获取节点类型知识');
15
16
  knowledgeCmd
16
17
  .command('categories')
17
18
  .description('列出所有节点分类')
18
- .option('--type <type>', '分类类型: trigger|action|tool|mcp|model|memory')
19
+ .option('--type [type]', 'normal|mcp', 'normal')
20
+ .option('--trigger', '仅 Trigger 分类')
19
21
  .option('--json', '以 JSON 格式输出')
20
22
  .action(async (options) => {
21
23
  try {
22
24
  if (options.json)
23
25
  (0, output_1.setJsonMode)(true);
24
- const categories = await (0, knowledge_1.getNodeCategories)({ type: options.type });
26
+ const categories = await (0, knowledge_1.getNodeCategories)({
27
+ trigger: options.trigger,
28
+ scene: options.type,
29
+ });
25
30
  if (options.json) {
26
31
  (0, output_1.printStructuredResult)({ ok: true, data: categories });
27
32
  return;
@@ -56,7 +61,6 @@ function registerKnowledgeCommand(program) {
56
61
  .description('搜索节点,展示匹配的 connector 及 actions(含 nodeType)')
57
62
  .option('--name <name>', '按名称搜索')
58
63
  .option('--trigger', '仅触发器')
59
- .option('--flow-id <flowId>', '连接流 ID')
60
64
  .option('--page <number>', '页码', '1')
61
65
  .option('--size <number>', '每页数量', '50')
62
66
  .option('--json', '以 JSON 格式输出')
@@ -66,10 +70,9 @@ function registerKnowledgeCommand(program) {
66
70
  if (opts.json)
67
71
  (0, output_1.setJsonMode)(true);
68
72
  const result = await (0, knowledge_1.searchNodesByCategory)({
69
- app_domain_category: category,
70
- name: opts.name,
73
+ category_name: category,
74
+ keyword: opts.name,
71
75
  trigger: opts.trigger || false,
72
- flow_id: opts.flowId,
73
76
  page: Number(opts.page),
74
77
  size: Number(opts.size),
75
78
  });
@@ -154,20 +157,39 @@ function registerKnowledgeCommand(program) {
154
157
  ['状态', action.status],
155
158
  ];
156
159
  (0, output_1.printKeyValue)(pairs, ' ');
157
- const params = (0, format_1.configSchemaToParams)(action.config_schema?.sub_params);
158
- if (params.length > 0) {
159
- console.log(chalk_1.default.gray(` 配置参数 (${params.length}):`));
160
- for (const p of params) {
161
- const required = p.required ? chalk_1.default.red(' *') : ' ';
162
- console.log(` ${required} ${chalk_1.default.cyan(p.name)} ${chalk_1.default.gray(`[${p.type}]`)} ${p.display_name} — ${p.description || '-'}`);
163
- if (p.options && p.options.length > 0) {
164
- const optStr = p.options.map((o) => `${o.key}:${o.label}`).join(', ');
165
- console.log(` ${chalk_1.default.dim('可选值:')} ${chalk_1.default.dim(optStr)}`);
160
+ const isNodePackageSupported = !!action.node_schema;
161
+ if (isNodePackageSupported) {
162
+ const inputFields = action.node_schema?.input_fields ?? [];
163
+ if (inputFields.length > 0) {
164
+ (0, helpers_1.printNodeSchemaFields)(inputFields);
165
+ }
166
+ else {
167
+ (0, output_1.printInfo)(' 无配置参数');
168
+ }
169
+ const outputFields = action.node_schema?.output_fields ?? [];
170
+ if (outputFields.length > 0) {
171
+ console.log(chalk_1.default.gray(` 输出结果 (${outputFields.length}):`));
172
+ for (const o of outputFields) {
173
+ console.log(` ${chalk_1.default.cyan(o.key)} ${chalk_1.default.gray(`[${o.type}]`)} ${o.label} - ${o.description ?? ''}`);
166
174
  }
167
175
  }
168
176
  }
169
177
  else {
170
- (0, output_1.printInfo)(' 无配置参数');
178
+ const params = (0, format_1.configSchemaToParams)(action.config_schema?.sub_params);
179
+ if (params.length > 0) {
180
+ console.log(chalk_1.default.gray(` 配置参数 (${params.length}):`));
181
+ for (const p of params) {
182
+ const required = p.required ? chalk_1.default.red(' *') : ' ';
183
+ console.log(` ${required} ${chalk_1.default.cyan(p.name)} ${chalk_1.default.gray(`[${p.type}]`)} ${p.display_name} — ${p.description || '-'}`);
184
+ if (p.options && p.options.length > 0) {
185
+ const optStr = p.options.map((o) => `${o.key}:${o.label}`).join(', ');
186
+ console.log(` ${chalk_1.default.dim('可选值:')} ${chalk_1.default.dim(optStr)}`);
187
+ }
188
+ }
189
+ }
190
+ else {
191
+ (0, output_1.printInfo)(' 无配置参数');
192
+ }
171
193
  }
172
194
  }
173
195
  }
@@ -8,6 +8,7 @@ const config_1 = require("@/utils/config");
8
8
  const output_1 = require("@/utils/output");
9
9
  const exit_code_1 = require("@/constants/exit-code");
10
10
  const client_1 = require("@/api/client");
11
+ const nodePackage_1 = require("@/utils/nodePackage");
11
12
  const chalk_1 = __importDefault(require("chalk"));
12
13
  function registerProfileCommand(program) {
13
14
  const profileCmd = program.command('profile').description('管理多配置环境(Profile)');
@@ -59,7 +60,7 @@ function registerProfileCommand(program) {
59
60
  .description('显示 Profile 的详细配置')
60
61
  .option('--name <name>', '指定要查看的 Profile')
61
62
  .option('--json', '以 JSON 格式输出')
62
- .action((options) => {
63
+ .action(async (options) => {
63
64
  if (options.json)
64
65
  (0, output_1.setJsonMode)(true);
65
66
  const profileName = options.name || (0, config_1.getActiveProfile)();
@@ -77,21 +78,32 @@ function registerProfileCommand(program) {
77
78
  }
78
79
  }
79
80
  const config = (0, config_1.loadConfig)(options.name || undefined);
81
+ const isActiveProfile = profileName === (0, config_1.getActiveProfile)();
82
+ const nodePackageSupported = isActiveProfile
83
+ ? await (0, nodePackage_1.checkAndCacheNodePackageSupport)()
84
+ : undefined;
80
85
  if (options.json) {
81
86
  (0, output_1.printStructuredResult)({
82
87
  ok: true,
83
88
  profile: profileName,
84
89
  baseUrl: config.baseUrl,
85
- token: config.token ? (0, output_1.truncateToken)(config.token) : '',
90
+ token: (0, output_1.truncateToken)((0, config_1.getAccessToken)(config)),
86
91
  insecure: config.insecure,
92
+ nodePackageSupported,
87
93
  });
88
94
  return;
89
95
  }
90
96
  (0, output_1.printHeader)(`Profile: ${profileName}`);
97
+ const npStatus = nodePackageSupported === undefined
98
+ ? '未检测'
99
+ : nodePackageSupported
100
+ ? chalk_1.default.green('支持')
101
+ : chalk_1.default.red('不支持');
91
102
  (0, output_1.printKeyValue)([
92
103
  ['baseUrl', config.baseUrl],
93
- ['token', (0, output_1.truncateToken)(config.token) || '(未设置)'],
104
+ ['token', (0, output_1.truncateToken)((0, config_1.getAccessToken)(config)) || '(未设置)'],
94
105
  ['insecure', String(config.insecure)],
106
+ ['Node Package', npStatus],
95
107
  ]);
96
108
  });
97
109
  profileCmd
@@ -130,7 +142,10 @@ function registerProfileCommand(program) {
130
142
  }
131
143
  const baseUrl = options.baseUrl || '';
132
144
  const token = options.token || '';
133
- (0, config_1.addProfile)(name, { baseUrl, token, insecure: !!options.insecure });
145
+ const auth = {
146
+ access_token: token,
147
+ };
148
+ (0, config_1.addProfile)(name, { baseUrl, auth, insecure: !!options.insecure });
134
149
  if (options.setDefault) {
135
150
  (0, config_1.setDefaultProfile)(name);
136
151
  (0, config_1.setActiveProfile)(name);