digitalsee-ai-flow-cli 0.9.24-beta → 0.9.29-beta

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.
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerFlowTrigger = registerFlowTrigger;
4
+ const trigger_1 = require("@/api/trigger");
5
+ const triggerConfig_1 = require("@/services/triggerConfig");
6
+ const output_1 = require("@/utils/output");
7
+ function registerFlowTrigger(flowCmd) {
8
+ const triggerCmd = flowCmd.command('trigger').description('触发器配置操作');
9
+ triggerCmd
10
+ .command('show <flowId>')
11
+ .description('查看连接流的触发器配置')
12
+ .option('--json', '以 JSON 格式输出')
13
+ .action(async (flowId, options) => {
14
+ try {
15
+ if (options.json)
16
+ (0, output_1.setJsonMode)(true);
17
+ (0, output_1.printInfo)(`获取连接流 ${flowId} 的触发器配置...`);
18
+ const info = await (0, trigger_1.findTriggerNode)(flowId);
19
+ if (options.json) {
20
+ (0, output_1.printStructuredResult)({
21
+ ok: true,
22
+ data: {
23
+ flowId,
24
+ nodeId: info.nodeId,
25
+ connectorId: info.connectorId,
26
+ connectorName: info.connectorName,
27
+ actionId: info.actionId,
28
+ actionName: info.actionName,
29
+ trigger: info.config,
30
+ },
31
+ });
32
+ return;
33
+ }
34
+ (0, output_1.printHeader)(`触发器配置: ${flowId}`);
35
+ (0, output_1.printKeyValue)([
36
+ ['Flow ID', flowId],
37
+ ['节点 ID', info.nodeId],
38
+ ['连接器', info.connectorName || info.connectorId || '-'],
39
+ ['动作', info.actionName || info.actionId || '-'],
40
+ ]);
41
+ (0, output_1.printKeyValue)((0, triggerConfig_1.formatTriggerConfig)(info.config ?? { mode: 'manual' }));
42
+ if (!info.config) {
43
+ (0, output_1.printJson)({
44
+ 提示: '触发器节点尚未配置(默认 manual),可用 set-cron / set-webhook 配置',
45
+ });
46
+ }
47
+ (0, output_1.printSuccess)('触发器配置获取完成');
48
+ }
49
+ catch (error) {
50
+ if (options.json) {
51
+ (0, output_1.printStructuredResult)({ ok: false, message: error.message });
52
+ }
53
+ else {
54
+ (0, output_1.printError)(`获取触发器配置失败: ${error.message}`);
55
+ }
56
+ }
57
+ });
58
+ triggerCmd
59
+ .command('set-manual <flowId>')
60
+ .description('将触发器切换为手动触发(清除 cron/webhook 配置)')
61
+ .option('--json', '以 JSON 格式输出')
62
+ .action(async (flowId, options) => {
63
+ try {
64
+ if (options.json)
65
+ (0, output_1.setJsonMode)(true);
66
+ (0, output_1.printInfo)(`正在设置连接流 ${flowId} 为手动触发...`);
67
+ const info = await (0, trigger_1.setTriggerConfig)(flowId, { mode: 'manual' });
68
+ if (options.json) {
69
+ (0, output_1.printStructuredResult)({
70
+ ok: true,
71
+ id: info.nodeId,
72
+ message: '触发器已设置为手动触发',
73
+ data: { flowId, nodeId: info.nodeId, trigger: { mode: 'manual' } },
74
+ });
75
+ }
76
+ else {
77
+ (0, output_1.printSuccess)(`触发器已设置为手动触发(节点 ${info.nodeId})`);
78
+ }
79
+ }
80
+ catch (error) {
81
+ if (options.json) {
82
+ (0, output_1.printStructuredResult)({ ok: false, message: error.message });
83
+ }
84
+ else {
85
+ (0, output_1.printError)(`设置手动触发失败: ${error.message}`);
86
+ }
87
+ }
88
+ });
89
+ triggerCmd
90
+ .command('set-cron <flowId>')
91
+ .description('配置 cron 定时触发器(Quartz 风格表达式,如 "0 0/5 * * * ?")')
92
+ .requiredOption('--expression <expr>', 'Quartz cron 表达式(6-7 段:秒 分 时 日 月 周 [年])')
93
+ .option('--timezone <tz>', 'IANA 时区标识(如 Asia/Shanghai),默认服务器时区')
94
+ .option('--json', '以 JSON 格式输出')
95
+ .action(async (flowId, options) => {
96
+ try {
97
+ if (options.json)
98
+ (0, output_1.setJsonMode)(true);
99
+ const result = (0, triggerConfig_1.normalizeCronTriggerConfig)({
100
+ expression: options.expression,
101
+ timezone: options.timezone,
102
+ });
103
+ if (typeof result === 'string') {
104
+ if (options.json)
105
+ (0, output_1.printStructuredResult)({ ok: false, message: result });
106
+ else
107
+ (0, output_1.printError)(`cron 配置校验失败: ${result}`);
108
+ return;
109
+ }
110
+ (0, output_1.printInfo)(`正在为连接流 ${flowId} 配置 cron 触发器...`);
111
+ const info = await (0, trigger_1.setTriggerConfig)(flowId, result);
112
+ if (options.json) {
113
+ (0, output_1.printStructuredResult)({
114
+ ok: true,
115
+ id: info.nodeId,
116
+ message: 'cron 触发器配置成功',
117
+ data: { flowId, nodeId: info.nodeId, trigger: result },
118
+ });
119
+ }
120
+ else {
121
+ (0, output_1.printSuccess)(`cron 触发器配置成功(节点 ${info.nodeId})`);
122
+ (0, output_1.printKeyValue)((0, triggerConfig_1.formatTriggerConfig)(result));
123
+ }
124
+ }
125
+ catch (error) {
126
+ if (options.json) {
127
+ (0, output_1.printStructuredResult)({ ok: false, message: error.message });
128
+ }
129
+ else {
130
+ (0, output_1.printError)(`配置 cron 触发器失败: ${error.message}`);
131
+ }
132
+ }
133
+ });
134
+ triggerCmd
135
+ .command('set-webhook <flowId>')
136
+ .description('配置 webhook 触发器')
137
+ .requiredOption('--path <path>', 'webhook 路径,以 / 开头(如 /hooks/flow1)')
138
+ .option('--method <method>', `HTTP 方法: ${triggerConfig_1.WEBHOOK_HTTP_METHODS.join(' | ')}`, 'POST')
139
+ .option('--response-mode <mode>', `响应模式: ${triggerConfig_1.WEBHOOK_RESPONSE_MODES.join(' | ')}`, 'IMMEDIATE')
140
+ .option('--response-data <data>', 'responseMode=CUSTOM 时的自定义响应体(必填)')
141
+ .option('--auth-required', '启用 webhook 鉴权', false)
142
+ .option('--auth-header-name <name>', '鉴权 Header 名称(与 --auth-header-value 成对)')
143
+ .option('--auth-header-value <value>', '鉴权 Header 值(与 --auth-header-name 成对)')
144
+ .option('--json', '以 JSON 格式输出')
145
+ .action(async (flowId, options) => {
146
+ try {
147
+ if (options.json)
148
+ (0, output_1.setJsonMode)(true);
149
+ const result = (0, triggerConfig_1.normalizeWebhookTriggerConfig)({
150
+ path: options.path,
151
+ httpMethod: options.method,
152
+ responseMode: options.responseMode,
153
+ responseData: options.responseData,
154
+ authRequired: options.authRequired,
155
+ authHeaderName: options.authHeaderName,
156
+ authHeaderValue: options.authHeaderValue,
157
+ });
158
+ if (typeof result === 'string') {
159
+ if (options.json)
160
+ (0, output_1.printStructuredResult)({ ok: false, message: result });
161
+ else
162
+ (0, output_1.printError)(`webhook 配置校验失败: ${result}`);
163
+ return;
164
+ }
165
+ (0, output_1.printInfo)(`正在为连接流 ${flowId} 配置 webhook 触发器...`);
166
+ const info = await (0, trigger_1.setTriggerConfig)(flowId, result);
167
+ if (options.json) {
168
+ (0, output_1.printStructuredResult)({
169
+ ok: true,
170
+ id: info.nodeId,
171
+ message: 'webhook 触发器配置成功',
172
+ data: { flowId, nodeId: info.nodeId, trigger: result },
173
+ });
174
+ }
175
+ else {
176
+ (0, output_1.printSuccess)(`webhook 触发器配置成功(节点 ${info.nodeId})`);
177
+ (0, output_1.printKeyValue)((0, triggerConfig_1.formatTriggerConfig)(result));
178
+ }
179
+ }
180
+ catch (error) {
181
+ if (options.json) {
182
+ (0, output_1.printStructuredResult)({ ok: false, message: error.message });
183
+ }
184
+ else {
185
+ (0, output_1.printError)(`配置 webhook 触发器失败: ${error.message}`);
186
+ }
187
+ }
188
+ });
189
+ }
190
+ //# sourceMappingURL=trigger.js.map
@@ -5,6 +5,9 @@ const flow_1 = require("@/api/flow");
5
5
  const output_1 = require("@/utils/output");
6
6
  const format_1 = require("@/utils/format");
7
7
  const portValidator_1 = require("@/services/portValidator");
8
+ const flowValidator_1 = require("@/services/flowValidator");
9
+ const helpers_1 = require("@/commands/flow/helpers");
10
+ const nodeSchemaCache_1 = require("@/utils/nodeSchemaCache");
8
11
  function registerFlowValidate(flowCmd) {
9
12
  flowCmd
10
13
  .command('validate <flowId>')
@@ -42,6 +45,29 @@ function registerFlowValidate(flowCmd) {
42
45
  }
43
46
  }
44
47
  }
48
+ // 特殊节点(ConditionNode/LoopNode/SelfLoopNode/SwitchNode)业务字段校验
49
+ for (const node of nodes) {
50
+ const nodeType = node.node_type || 'ActionNode';
51
+ if (nodeType === 'ActionNode')
52
+ continue;
53
+ const specialErrors = (0, format_1.validateSpecialNodeType)(nodeType, { properties: node.properties || {} }, node.config_schema);
54
+ for (const e of specialErrors) {
55
+ errors.push(`节点 ${node.n_id || node.id}: [${e.rule}] ${e.message}`);
56
+ }
57
+ }
58
+ // 环检测 / 孤立节点 / 触发器检查
59
+ (0, output_1.printInfo)('正在校验流图结构(环/孤立节点/触发器)...');
60
+ const graphResult = (0, flowValidator_1.validateFlowGraph)({ nodes, edges });
61
+ for (const issue of graphResult.issues) {
62
+ const line = `[${issue.code}] ${issue.message}`;
63
+ if (issue.severity === 'error')
64
+ errors.push(line);
65
+ else
66
+ warnings.push(line);
67
+ }
68
+ // node_schema 节点 properties 字段级校验(legacy 节点自动跳过)
69
+ (0, output_1.printInfo)('正在校验 node_schema 节点配置字段...');
70
+ await validateNodeSchemaFields(nodes, errors, warnings);
45
71
  // node_schema 端口级校验(legacy 节点自动跳过)
46
72
  (0, output_1.printInfo)('正在校验节点端口连线...');
47
73
  const portResult = await (0, portValidator_1.validateFlowPorts)({ nodes, edges });
@@ -61,6 +87,7 @@ function registerFlowValidate(flowCmd) {
61
87
  edgeCount: edges.length,
62
88
  errors,
63
89
  warnings,
90
+ cycles: graphResult.cycles,
64
91
  portViolations: portResult.violations,
65
92
  });
66
93
  return;
@@ -94,4 +121,34 @@ function registerFlowValidate(flowCmd) {
94
121
  }
95
122
  });
96
123
  }
124
+ /**
125
+ * NodePackage 节点(action_key + action_ver)按 node_schema.input_fields
126
+ * 校验 properties(必填/类型/元数据)。schema 拉取失败的节点跳过并提示。
127
+ */
128
+ async function validateNodeSchemaFields(nodes, errors, warnings) {
129
+ await Promise.all(nodes.map(async (node) => {
130
+ const nodeId = node.n_id || node.id;
131
+ const actionKey = node.action_key;
132
+ const actionVer = node.action_ver;
133
+ if (!actionKey || actionVer === undefined || actionVer === null)
134
+ return;
135
+ const schema = await (0, nodeSchemaCache_1.getNodePackageSchema)(String(actionKey), Number(actionVer));
136
+ if (!schema) {
137
+ warnings.push(`节点 ${nodeId} 的 node_schema (${actionKey}@${actionVer}) 获取失败,已跳过字段校验`);
138
+ return;
139
+ }
140
+ const inputFields = (schema.input_fields ?? []);
141
+ if (inputFields.length === 0)
142
+ return;
143
+ const properties = node.properties ?? {};
144
+ const fieldErrors = (0, helpers_1.validateNodeSchemaProperties)(properties, inputFields);
145
+ for (const e of fieldErrors) {
146
+ errors.push(`节点 ${nodeId}: [${e.rule}] ${e.message}`);
147
+ }
148
+ const proxyMisuse = (0, helpers_1.findProxyFieldMisuse)(properties, inputFields);
149
+ for (const msg of proxyMisuse) {
150
+ errors.push(`节点 ${nodeId}: ${msg}`);
151
+ }
152
+ }));
153
+ }
97
154
  //# sourceMappingURL=validate.js.map
@@ -99,6 +99,7 @@ function registerFlowVariables(flowCmd) {
99
99
  (0, output_1.printError)(`获取全局变量失败: ${error.message}`);
100
100
  }
101
101
  }
102
+ (0, output_1.printInfo)('提示: 配置值中可通过 {{global.<key>}} 引用全局变量、{{sys_tenant_id}} / {{response.<path>}} 引用内置变量');
102
103
  (0, output_1.printSuccess)('变量查询完成');
103
104
  }
104
105
  catch (error) {
@@ -22,6 +22,7 @@ const export_1 = require("@/commands/flow/export");
22
22
  const import_1 = require("@/commands/flow/import");
23
23
  const delete_1 = require("@/commands/flow/delete");
24
24
  const version_1 = require("@/commands/flow/version");
25
+ const trigger_1 = require("@/commands/flow/trigger");
25
26
  function registerFlowCommand(program) {
26
27
  const flowCmd = program.command('flow').description('连接流操作');
27
28
  (0, create_1.registerFlowCreate)(flowCmd);
@@ -45,5 +46,6 @@ function registerFlowCommand(program) {
45
46
  (0, import_1.registerFlowImport)(flowCmd);
46
47
  (0, delete_1.registerFlowDelete)(flowCmd);
47
48
  (0, version_1.registerFlowVersion)(flowCmd);
49
+ (0, trigger_1.registerFlowTrigger)(flowCmd);
48
50
  }
49
51
  //# sourceMappingURL=flow.js.map
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TRIGGER_NODE_TYPES = void 0;
4
+ exports.isTriggerNodeType = isTriggerNodeType;
5
+ /**
6
+ * 触发器类节点类型集合。
7
+ *
8
+ * 对齐 uep-service acm NodeEnum 注释:StartEventNode 为通用触发器,
9
+ * UserSyncAiNode / UserPushAiNode 为通讯录集成新版协议 trigger 节点。
10
+ * 读路径(api.trigger / flowAnalyzer / flowValidator 的 isTriggerNode)
11
+ * 与写路径(flow node create 的 trigger 推断 / 首节点检查)统一引用,
12
+ * 避免判定逻辑漂移。
13
+ */
14
+ exports.TRIGGER_NODE_TYPES = new Set([
15
+ 'StartEventNode',
16
+ 'UserSyncAiNode',
17
+ 'UserPushAiNode',
18
+ ]);
19
+ /** 判断节点类型是否为触发器类(不含 START 旧数据别名与 webhook 连接器名启发式) */
20
+ function isTriggerNodeType(type) {
21
+ return exports.TRIGGER_NODE_TYPES.has(type);
22
+ }
23
+ //# sourceMappingURL=node-type.js.map