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.
- package/README.md +84 -22
- package/dist/api/client.js +34 -4
- package/dist/api/knowledge.js +10 -8
- package/dist/api/node.js +36 -0
- package/dist/api/refresh.js +81 -0
- package/dist/api/service-log.js +125 -0
- package/dist/commands/auth.js +39 -15
- package/dist/commands/config.js +5 -3
- package/dist/commands/flow/helpers.js +78 -2
- package/dist/commands/flow/node.js +103 -17
- package/dist/commands/knowledge.js +38 -16
- package/dist/commands/profile.js +19 -4
- package/dist/commands/service-log.js +286 -0
- package/dist/index.js +2 -0
- package/dist/services/skillGenerator.js +62 -13
- package/dist/utils/common.js +16 -0
- package/dist/utils/config.js +9 -2
- package/dist/utils/format.js +14 -0
- package/dist/utils/nodePackage.js +87 -0
- package/dist/utils/oauth.js +27 -8
- package/package.json +4 -2
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerServiceLogCommand = registerServiceLogCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const service_log_1 = require("@/api/service-log");
|
|
9
|
+
const output_1 = require("@/utils/output");
|
|
10
|
+
const exit_code_1 = require("@/constants/exit-code");
|
|
11
|
+
const common_1 = require("@/utils/common");
|
|
12
|
+
const config_1 = require("@/utils/config");
|
|
13
|
+
const DATETIME_REGEX = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
|
|
14
|
+
function pad2(n) {
|
|
15
|
+
return n < 10 ? `0${n}` : String(n);
|
|
16
|
+
}
|
|
17
|
+
function formatDateTime(d) {
|
|
18
|
+
return (`${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ` +
|
|
19
|
+
`${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`);
|
|
20
|
+
}
|
|
21
|
+
function colorizeLevel(level) {
|
|
22
|
+
const upper = (level || '').toUpperCase();
|
|
23
|
+
if (upper === 'ERROR' || upper === 'FATAL')
|
|
24
|
+
return chalk_1.default.red(level);
|
|
25
|
+
if (upper === 'WARN' || upper === 'WARNING')
|
|
26
|
+
return chalk_1.default.yellow(level);
|
|
27
|
+
if (upper === 'INFO')
|
|
28
|
+
return chalk_1.default.green(level);
|
|
29
|
+
if (upper === 'DEBUG' || upper === 'TRACE')
|
|
30
|
+
return chalk_1.default.gray(level);
|
|
31
|
+
return level;
|
|
32
|
+
}
|
|
33
|
+
function pickLogTime(entry) {
|
|
34
|
+
return entry.log_time || entry.timestamp || '-';
|
|
35
|
+
}
|
|
36
|
+
function flattenMessage(message) {
|
|
37
|
+
return (message ?? '').replace(/\r?\n/g, ' ');
|
|
38
|
+
}
|
|
39
|
+
function registerServiceLogCommand(program) {
|
|
40
|
+
const cmd = program.command('service-log').description('运维日志查询');
|
|
41
|
+
registerSearch(cmd);
|
|
42
|
+
registerStream(cmd);
|
|
43
|
+
}
|
|
44
|
+
function registerSearch(serviceLogCmd) {
|
|
45
|
+
serviceLogCmd
|
|
46
|
+
.command('search')
|
|
47
|
+
.description('查询历史运维日志')
|
|
48
|
+
.option('--time-range <r>', '相对时间范围,格式: <N>s|m|h|d(如 30s, 15m, 3h, 7d)(与 --start-time 互斥)')
|
|
49
|
+
.option('--start-time <time>', '开始时间 yyyy-MM-dd HH:mm:ss(与 --time-range 互斥)')
|
|
50
|
+
.option('--end-time <time>', '结束时间 yyyy-MM-dd HH:mm:ss(不传则服务端用请求时刻)')
|
|
51
|
+
.option('--limit <n>', '最大返回条数(默认 50,上限 500)', '50')
|
|
52
|
+
.option('--level <level>', '日志级别: INFO / WARN / ERROR')
|
|
53
|
+
.option('--request-id <id>', '链路 trace id(精确匹配)')
|
|
54
|
+
.option('--keyword <text>', '日志正文关键词')
|
|
55
|
+
.option('--service-type <type>', '服务类型: iam / acm / ncm / adm / mdm / nginx 等')
|
|
56
|
+
.option('--json', '以 JSON 输出')
|
|
57
|
+
.action(async (options) => {
|
|
58
|
+
try {
|
|
59
|
+
if (options.json)
|
|
60
|
+
(0, output_1.setJsonMode)(true);
|
|
61
|
+
const req = buildSearchRequest(options);
|
|
62
|
+
if (req instanceof Error) {
|
|
63
|
+
if (options.json) {
|
|
64
|
+
(0, output_1.printStructuredResult)({ ok: false, message: req.message });
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
(0, output_1.printError)(req.message);
|
|
68
|
+
}
|
|
69
|
+
process.exitCode = exit_code_1.ExitCode.FAILURE;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (!options.json) {
|
|
73
|
+
(0, output_1.printInfo)('正在查询历史日志...');
|
|
74
|
+
}
|
|
75
|
+
const logs = await (0, service_log_1.searchServiceLogs)(req);
|
|
76
|
+
if (options.json) {
|
|
77
|
+
(0, output_1.printStructuredResult)({ ok: true, data: logs, total: logs.length });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (logs.length === 0) {
|
|
81
|
+
(0, output_1.printInfo)('暂无符合条件的日志');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
(0, output_1.printHeader)(`运维日志 (共 ${logs.length} 条,按时间倒序)`);
|
|
85
|
+
const rows = logs.map((entry) => [
|
|
86
|
+
pickLogTime(entry),
|
|
87
|
+
colorizeLevel(entry.level || '-'),
|
|
88
|
+
String(entry.host ?? '-'),
|
|
89
|
+
String(entry.trace_id ?? '-'),
|
|
90
|
+
flattenMessage(entry.message),
|
|
91
|
+
]);
|
|
92
|
+
(0, output_1.printTable)(['时间', '级别', '服务实例', 'Trace', '消息'], rows, {
|
|
93
|
+
wrapCols: [4],
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (options.json) {
|
|
98
|
+
(0, output_1.printStructuredResult)({ ok: false, message: error.message });
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
(0, output_1.printError)(`查询日志失败: ${error.message}`);
|
|
102
|
+
}
|
|
103
|
+
process.exitCode = exit_code_1.ExitCode.FAILURE;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function buildSearchRequest(options) {
|
|
108
|
+
const hasRange = Boolean(options.timeRange);
|
|
109
|
+
const hasStart = Boolean(options.startTime);
|
|
110
|
+
if (!hasRange && !hasStart) {
|
|
111
|
+
return new Error('必须指定 --time-range 或 --start-time 之一');
|
|
112
|
+
}
|
|
113
|
+
if (hasRange && hasStart) {
|
|
114
|
+
return new Error('--time-range 与 --start-time 不可同时使用');
|
|
115
|
+
}
|
|
116
|
+
let start_time;
|
|
117
|
+
let end_time;
|
|
118
|
+
if (hasRange) {
|
|
119
|
+
const rangeKey = String(options.timeRange);
|
|
120
|
+
const ms = (0, common_1.parseTimeRange)(rangeKey);
|
|
121
|
+
if (ms === null) {
|
|
122
|
+
return new Error(`不支持的 --time-range 格式: "${rangeKey}",应为 <N>s|m|h|d(如 30s, 15m, 3h, 7d)`);
|
|
123
|
+
}
|
|
124
|
+
const now = new Date();
|
|
125
|
+
start_time = formatDateTime(new Date(now.getTime() - ms));
|
|
126
|
+
end_time = formatDateTime(now);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
const st = String(options.startTime);
|
|
130
|
+
if (!DATETIME_REGEX.test(st)) {
|
|
131
|
+
return new Error('--start-time 格式应为 yyyy-MM-dd HH:mm:ss');
|
|
132
|
+
}
|
|
133
|
+
start_time = st;
|
|
134
|
+
if (options.endTime) {
|
|
135
|
+
const et = String(options.endTime);
|
|
136
|
+
if (!DATETIME_REGEX.test(et)) {
|
|
137
|
+
return new Error('--end-time 格式应为 yyyy-MM-dd HH:mm:ss');
|
|
138
|
+
}
|
|
139
|
+
end_time = et;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const limit = Number(options.limit);
|
|
143
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
144
|
+
return new Error('--limit 必须为正整数');
|
|
145
|
+
}
|
|
146
|
+
const req = { start_time, limit };
|
|
147
|
+
if (end_time)
|
|
148
|
+
req.end_time = end_time;
|
|
149
|
+
if (options.level)
|
|
150
|
+
req.log_level = String(options.level);
|
|
151
|
+
if (options.requestId)
|
|
152
|
+
req.request_id = String(options.requestId);
|
|
153
|
+
if (options.keyword)
|
|
154
|
+
req.keyword = String(options.keyword);
|
|
155
|
+
if (options.serviceType)
|
|
156
|
+
req.service_type = String(options.serviceType);
|
|
157
|
+
return req;
|
|
158
|
+
}
|
|
159
|
+
function registerStream(serviceLogCmd) {
|
|
160
|
+
serviceLogCmd
|
|
161
|
+
.command('stream')
|
|
162
|
+
.description('实时跟随运维日志(WebSocket,Ctrl+C 退出)')
|
|
163
|
+
.option('--level <level>', '日志级别: INFO / WARN / ERROR')
|
|
164
|
+
.option('--request-id <id>', '链路 trace id(精确匹配)')
|
|
165
|
+
.option('--keyword <text>', '日志正文关键词')
|
|
166
|
+
.option('--service-type <type>', '服务类型: iam / acm / ncm / adm / mdm / nginx 等')
|
|
167
|
+
.option('--limit <n>', '单次 ES 拉取批量(默认 20)', '20')
|
|
168
|
+
.option('--max <n>', '收到 N 条后自动退出(默认不限)')
|
|
169
|
+
.option('--json', 'NDJSON 输出(每行一条 { ok, data })')
|
|
170
|
+
.action(async (options) => {
|
|
171
|
+
if (options.json)
|
|
172
|
+
(0, output_1.setJsonMode)(true);
|
|
173
|
+
const cfg = (0, config_1.loadConfig)();
|
|
174
|
+
if (!cfg.auth || !cfg.auth.access_token) {
|
|
175
|
+
const msg = '未登录,请先执行 ai-flow auth login';
|
|
176
|
+
if (options.json) {
|
|
177
|
+
(0, output_1.printStructuredResult)({ ok: false, message: msg });
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
(0, output_1.printError)(msg);
|
|
181
|
+
}
|
|
182
|
+
process.exitCode = exit_code_1.ExitCode.FAILURE;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
await (0, service_log_1.verifyToken)();
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
const msg = error.message || 'Token 校验失败';
|
|
190
|
+
if (options.json) {
|
|
191
|
+
(0, output_1.printStructuredResult)({ ok: false, message: msg });
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
(0, output_1.printError)(`Token 不可用: ${msg}`);
|
|
195
|
+
}
|
|
196
|
+
process.exitCode = exit_code_1.ExitCode.FAILURE;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const filters = buildStreamFilters(options);
|
|
200
|
+
if (filters instanceof Error) {
|
|
201
|
+
if (options.json) {
|
|
202
|
+
(0, output_1.printStructuredResult)({ ok: false, message: filters.message });
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
(0, output_1.printError)(filters.message);
|
|
206
|
+
}
|
|
207
|
+
process.exitCode = exit_code_1.ExitCode.FAILURE;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const maxCount = options.max ? Number(options.max) : 0;
|
|
211
|
+
if (options.max && (!Number.isFinite(maxCount) || maxCount <= 0)) {
|
|
212
|
+
const msg = '--max 必须为正整数';
|
|
213
|
+
if (options.json) {
|
|
214
|
+
(0, output_1.printStructuredResult)({ ok: false, message: msg });
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
(0, output_1.printError)(msg);
|
|
218
|
+
}
|
|
219
|
+
process.exitCode = exit_code_1.ExitCode.FAILURE;
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
let received = 0;
|
|
223
|
+
let closed = false;
|
|
224
|
+
if (!options.json) {
|
|
225
|
+
(0, output_1.printInfo)('正在连接实时日志... (Ctrl+C 退出)');
|
|
226
|
+
}
|
|
227
|
+
const control = (0, service_log_1.openServiceLogStream)(filters, {
|
|
228
|
+
onLog: (entry) => {
|
|
229
|
+
received += 1;
|
|
230
|
+
if (options.json) {
|
|
231
|
+
(0, output_1.printStructuredResult)({ ok: true, data: entry });
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
const time = pickLogTime(entry);
|
|
235
|
+
const level = colorizeLevel(entry.level || '-');
|
|
236
|
+
const host = entry.host ?? '-';
|
|
237
|
+
const msg = flattenMessage(entry.message);
|
|
238
|
+
console.log(`[${time}] [${level}] [${host}] ${msg}`);
|
|
239
|
+
}
|
|
240
|
+
if (maxCount > 0 && received >= maxCount) {
|
|
241
|
+
control.cancel();
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
onError: (message) => {
|
|
245
|
+
if (options.json) {
|
|
246
|
+
(0, output_1.printStructuredResult)({ ok: false, message });
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
(0, output_1.printWarning)(message);
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
onClose: (code) => {
|
|
253
|
+
if (closed)
|
|
254
|
+
return;
|
|
255
|
+
closed = true;
|
|
256
|
+
if (!options.json) {
|
|
257
|
+
(0, output_1.printInfo)(`实时日志连接已关闭 (code=${code})`);
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
const onSigInt = () => {
|
|
262
|
+
if (!closed) {
|
|
263
|
+
control.cancel();
|
|
264
|
+
}
|
|
265
|
+
process.removeListener('SIGINT', onSigInt);
|
|
266
|
+
};
|
|
267
|
+
process.on('SIGINT', onSigInt);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function buildStreamFilters(options) {
|
|
271
|
+
const limit = Number(options.limit);
|
|
272
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
273
|
+
return new Error('--limit 必须为正整数');
|
|
274
|
+
}
|
|
275
|
+
const filters = { limit };
|
|
276
|
+
if (options.level)
|
|
277
|
+
filters.log_level = String(options.level);
|
|
278
|
+
if (options.requestId)
|
|
279
|
+
filters.request_id = String(options.requestId);
|
|
280
|
+
if (options.keyword)
|
|
281
|
+
filters.keyword = String(options.keyword);
|
|
282
|
+
if (options.serviceType)
|
|
283
|
+
filters.service_type = String(options.serviceType);
|
|
284
|
+
return filters;
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=service-log.js.map
|
package/dist/index.js
CHANGED
|
@@ -57,6 +57,7 @@ const link_1 = require("@/commands/link");
|
|
|
57
57
|
const sync_1 = require("@/commands/sync");
|
|
58
58
|
const org_1 = require("@/commands/org");
|
|
59
59
|
const profile_1 = require("@/commands/profile");
|
|
60
|
+
const service_log_1 = require("@/commands/service-log");
|
|
60
61
|
const updateCheck_1 = require("@/utils/updateCheck");
|
|
61
62
|
const output_1 = require("@/utils/output");
|
|
62
63
|
const config_2 = require("@/utils/config");
|
|
@@ -76,6 +77,7 @@ async function main() {
|
|
|
76
77
|
(0, sync_1.registerSyncCommand)(program);
|
|
77
78
|
(0, org_1.registerOrgCommand)(program);
|
|
78
79
|
(0, profile_1.registerProfileCommand)(program);
|
|
80
|
+
(0, service_log_1.registerServiceLogCommand)(program);
|
|
79
81
|
program.hook('preAction', (thisCommand) => {
|
|
80
82
|
const opts = thisCommand.optsWithGlobals();
|
|
81
83
|
if (opts.quiet) {
|
|
@@ -51,24 +51,23 @@ async function generateAllSkills(outputDir) {
|
|
|
51
51
|
skillsGenerated: 0,
|
|
52
52
|
errors: [],
|
|
53
53
|
};
|
|
54
|
-
//TODO 此部分目前硬编码 后续需要根据实际调整
|
|
55
54
|
const categoryTypes = [
|
|
56
|
-
{ type: '
|
|
57
|
-
{ type: 'trigger', trigger: true, label: '
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// { type: "model", trigger: false, label: "模型" },
|
|
61
|
-
// { type: "memory", trigger: false, label: "记忆" },
|
|
55
|
+
{ type: 'normal', trigger: false, label: '自动化' },
|
|
56
|
+
{ type: 'normal-trigger', trigger: true, label: '自动化触发器' },
|
|
57
|
+
{ type: 'mcp', trigger: true, label: 'MCP' },
|
|
58
|
+
{ type: 'mcp-trigger', trigger: true, label: 'MCP触发器' },
|
|
62
59
|
];
|
|
63
60
|
for (const ct of categoryTypes) {
|
|
64
61
|
try {
|
|
65
|
-
const categories = await (0, knowledge_1.getNodeCategories)({
|
|
62
|
+
const categories = await (0, knowledge_1.getNodeCategories)({ trigger: ct.trigger });
|
|
66
63
|
progress.totalCategories += categories.length;
|
|
67
64
|
(0, output_1.printInfo)(`发现 ${categories.length} 个${ct.label}分类`);
|
|
68
65
|
const mdDir = path.join(outputDir, ct.type);
|
|
69
66
|
fs.mkdirSync(mdDir, { recursive: true });
|
|
70
67
|
for (const category of categories) {
|
|
71
|
-
|
|
68
|
+
const categoryMdDir = path.join(mdDir, category.name);
|
|
69
|
+
fs.mkdirSync(categoryMdDir, { recursive: true });
|
|
70
|
+
await processCategory(category, categoryMdDir, progress, ct.trigger);
|
|
72
71
|
}
|
|
73
72
|
}
|
|
74
73
|
catch (error) {
|
|
@@ -87,7 +86,7 @@ async function processCategory(category, mdDir, progress, trigger = false) {
|
|
|
87
86
|
let hasMore = true;
|
|
88
87
|
while (hasMore) {
|
|
89
88
|
const result = await (0, knowledge_1.searchNodesByCategory)({
|
|
90
|
-
|
|
89
|
+
category_name: categoryKey,
|
|
91
90
|
trigger,
|
|
92
91
|
page,
|
|
93
92
|
size: batchSize,
|
|
@@ -130,7 +129,10 @@ async function processConnector(connector, category, mdDir, progress, trigger =
|
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
131
|
async function generateSkillFile(action, category, connector, mdDir, progress) {
|
|
133
|
-
const
|
|
132
|
+
const hasNodeSchema = !!action.node_schema;
|
|
133
|
+
const parameters = hasNodeSchema
|
|
134
|
+
? (0, format_1.nodeSchemaToParams)(action.node_schema?.input_fields)
|
|
135
|
+
: (0, format_1.configSchemaToParams)(action.config_schema?.sub_params);
|
|
134
136
|
const scenarios = (0, format_1.inferScenarios)(action.name, action.description);
|
|
135
137
|
const skill = {
|
|
136
138
|
name: action.name,
|
|
@@ -142,7 +144,7 @@ async function generateSkillFile(action, category, connector, mdDir, progress) {
|
|
|
142
144
|
desc: category.desc || '',
|
|
143
145
|
},
|
|
144
146
|
action_type: action.action_type || 'action',
|
|
145
|
-
action_key: action.action_key,
|
|
147
|
+
action_key: hasNodeSchema ? action.node_schema?.key || action.action_key : action.action_key,
|
|
146
148
|
connector_id: action.connector_id,
|
|
147
149
|
link_id: connector.id,
|
|
148
150
|
action_id: action.id,
|
|
@@ -156,6 +158,21 @@ async function generateSkillFile(action, category, connector, mdDir, progress) {
|
|
|
156
158
|
},
|
|
157
159
|
parameters,
|
|
158
160
|
scenarios,
|
|
161
|
+
node_schema: hasNodeSchema && action.node_schema
|
|
162
|
+
? {
|
|
163
|
+
key: action.node_schema.key,
|
|
164
|
+
version: action.node_schema.version,
|
|
165
|
+
name: action.node_schema.name,
|
|
166
|
+
description: action.node_schema.description,
|
|
167
|
+
input_fields: (0, format_1.nodeSchemaToParams)(action.node_schema.input_fields),
|
|
168
|
+
output_fields: (action.node_schema.output_fields || []).map((o) => ({
|
|
169
|
+
key: o.key,
|
|
170
|
+
label: o.label,
|
|
171
|
+
type: o.type,
|
|
172
|
+
description: o.description ?? undefined,
|
|
173
|
+
})),
|
|
174
|
+
}
|
|
175
|
+
: undefined,
|
|
159
176
|
};
|
|
160
177
|
const safeName = (0, format_1.sanitizeFileName)(`${connector.name}_${action.name}`);
|
|
161
178
|
try {
|
|
@@ -171,7 +188,39 @@ function skillToMarkdown(skill) {
|
|
|
171
188
|
if (skill.description) {
|
|
172
189
|
lines.push('## 功能描述', '', skill.description, '');
|
|
173
190
|
}
|
|
174
|
-
if (skill.
|
|
191
|
+
if (skill.node_schema) {
|
|
192
|
+
const ns = skill.node_schema;
|
|
193
|
+
lines.push('## Node Package 信息', '');
|
|
194
|
+
lines.push(`- **Schema Key**: \`${ns.key}\``);
|
|
195
|
+
lines.push(`- **Version**: ${ns.version}`);
|
|
196
|
+
if (ns.name)
|
|
197
|
+
lines.push(`- **Name**: ${ns.name}`);
|
|
198
|
+
if (ns.description)
|
|
199
|
+
lines.push(`- **Description**: ${ns.description}`);
|
|
200
|
+
lines.push('');
|
|
201
|
+
if (ns.input_fields.length > 0) {
|
|
202
|
+
lines.push('## 配置参数 (Input Fields)', '');
|
|
203
|
+
lines.push('| 字段名 | 显示名 | 类型 | 必填 | 说明 | 默认值 | 可选值 |');
|
|
204
|
+
lines.push('|--------|--------|------|------|------|--------|--------|');
|
|
205
|
+
for (const param of ns.input_fields) {
|
|
206
|
+
const options = (param.options || [])
|
|
207
|
+
?.map((o) => (o.label !== o.key ? `\`${o.key}\` (${o.label})` : `\`${o.key}\``))
|
|
208
|
+
.join(', ') || '-';
|
|
209
|
+
lines.push(`| \`${param.name}\` | ${param.display_name} | ${param.type} | ${param.required ? '是' : '否'} | ${param.description || '-'} | ${param.default ?? '-'} | ${options} |`);
|
|
210
|
+
}
|
|
211
|
+
lines.push('');
|
|
212
|
+
}
|
|
213
|
+
if (ns.output_fields.length > 0) {
|
|
214
|
+
lines.push('## 输出字段', '');
|
|
215
|
+
lines.push('| 字段名 | 显示名 | 类型 | 说明 |');
|
|
216
|
+
lines.push('|--------|--------|------|------|');
|
|
217
|
+
for (const o of ns.output_fields) {
|
|
218
|
+
lines.push(`| \`${o.key}\` | ${o.label} | ${o.type} | ${o.description || '-'} |`);
|
|
219
|
+
}
|
|
220
|
+
lines.push('');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else if (skill.parameters.length > 0) {
|
|
175
224
|
lines.push('## 配置参数', '');
|
|
176
225
|
lines.push('| 字段名 | 显示名 | 类型 | 必填 | 说明 | 默认值 | 可选值 |');
|
|
177
226
|
lines.push('|--------|--------|------|------|------|--------|--------|');
|
package/dist/utils/common.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.safeParseJSON = safeParseJSON;
|
|
4
|
+
exports.parseTimeRange = parseTimeRange;
|
|
4
5
|
function safeParseJSON(value, fallback) {
|
|
5
6
|
if (typeof value !== 'string')
|
|
6
7
|
return fallback;
|
|
@@ -11,4 +12,19 @@ function safeParseJSON(value, fallback) {
|
|
|
11
12
|
return fallback;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
15
|
+
const UNIT_MS = {
|
|
16
|
+
s: 1000,
|
|
17
|
+
m: 60 * 1000,
|
|
18
|
+
h: 60 * 60 * 1000,
|
|
19
|
+
d: 24 * 60 * 60 * 1000,
|
|
20
|
+
};
|
|
21
|
+
function parseTimeRange(value) {
|
|
22
|
+
const trimmed = String(value).trim();
|
|
23
|
+
const match = trimmed.match(/^(\d+)([smhd])$/i);
|
|
24
|
+
if (!match)
|
|
25
|
+
return null;
|
|
26
|
+
const num = parseInt(match[1], 10);
|
|
27
|
+
const unit = match[2].toLowerCase();
|
|
28
|
+
return num * (UNIT_MS[unit] ?? 0);
|
|
29
|
+
}
|
|
14
30
|
//# sourceMappingURL=common.js.map
|
package/dist/utils/config.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getAccessToken = getAccessToken;
|
|
36
37
|
exports.setActiveProfile = setActiveProfile;
|
|
37
38
|
exports.getActiveProfile = getActiveProfile;
|
|
38
39
|
exports.loadConfig = loadConfig;
|
|
@@ -55,8 +56,8 @@ const PROJECT_RC = '.ai-flowrc';
|
|
|
55
56
|
const DEFAULT_PROFILE_NAME = 'default';
|
|
56
57
|
const DEFAULT_CONFIG = {
|
|
57
58
|
baseUrl: 'https://poc.digitalsee.cn',
|
|
58
|
-
token: '',
|
|
59
59
|
insecure: false,
|
|
60
|
+
auth: null,
|
|
60
61
|
};
|
|
61
62
|
let activeProfileOverride = null;
|
|
62
63
|
function ensureConfigDir() {
|
|
@@ -88,12 +89,18 @@ function buildProfileStoreFromFlat(raw) {
|
|
|
88
89
|
profiles: {
|
|
89
90
|
[DEFAULT_PROFILE_NAME]: {
|
|
90
91
|
baseUrl: raw.baseUrl || DEFAULT_CONFIG.baseUrl,
|
|
91
|
-
token: raw.token
|
|
92
|
+
auth: raw.auth ?? (raw.token ? { access_token: raw.token } : DEFAULT_CONFIG.auth),
|
|
92
93
|
insecure: raw.insecure ?? DEFAULT_CONFIG.insecure,
|
|
93
94
|
},
|
|
94
95
|
},
|
|
95
96
|
};
|
|
96
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* 从 FlowConfig 中提取 access_token,不存在时返回空字符串。
|
|
100
|
+
*/
|
|
101
|
+
function getAccessToken(config) {
|
|
102
|
+
return config.auth?.access_token ?? '';
|
|
103
|
+
}
|
|
97
104
|
function setActiveProfile(name) {
|
|
98
105
|
activeProfileOverride = name;
|
|
99
106
|
try {
|
package/dist/utils/format.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.configSchemaToParams = configSchemaToParams;
|
|
4
|
+
exports.nodeSchemaToParams = nodeSchemaToParams;
|
|
4
5
|
exports.inferScenarios = inferScenarios;
|
|
5
6
|
exports.sanitizeFileName = sanitizeFileName;
|
|
6
7
|
exports.fillConfigSchemaDefaults = fillConfigSchemaDefaults;
|
|
@@ -51,6 +52,19 @@ function inferFieldType(param) {
|
|
|
51
52
|
}
|
|
52
53
|
return 'string';
|
|
53
54
|
}
|
|
55
|
+
function nodeSchemaToParams(inputFields) {
|
|
56
|
+
if (!inputFields || !Array.isArray(inputFields))
|
|
57
|
+
return [];
|
|
58
|
+
return inputFields.map((f) => ({
|
|
59
|
+
name: f.key,
|
|
60
|
+
type: f.type,
|
|
61
|
+
required: f.required ?? false,
|
|
62
|
+
description: f.help_text || '',
|
|
63
|
+
display_name: f.label,
|
|
64
|
+
options: f.options?.map((o) => ({ key: o.value, label: o.label })),
|
|
65
|
+
default: f.default_value,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
54
68
|
function inferScenarios(actionName, description) {
|
|
55
69
|
const scenarios = [];
|
|
56
70
|
const text = `${actionName} ${description || ''}`.toLowerCase();
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getCachedNodePackageSupport = getCachedNodePackageSupport;
|
|
37
|
+
exports.getNodePackageSupportFor = getNodePackageSupportFor;
|
|
38
|
+
exports.checkAndCacheNodePackageSupport = checkAndCacheNodePackageSupport;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const os = __importStar(require("os"));
|
|
42
|
+
const node_1 = require("@/api/node");
|
|
43
|
+
const config_1 = require("@/utils/config");
|
|
44
|
+
const STATE_DIR = path.join(os.homedir(), '.ai-flow-cli');
|
|
45
|
+
function getStateFile() {
|
|
46
|
+
return path.join(STATE_DIR, `node-package-${(0, config_1.getActiveProfile)()}.json`);
|
|
47
|
+
}
|
|
48
|
+
function ensureStateDir() {
|
|
49
|
+
if (!fs.existsSync(STATE_DIR)) {
|
|
50
|
+
fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function getCachedNodePackageSupport() {
|
|
54
|
+
try {
|
|
55
|
+
const stateFile = getStateFile();
|
|
56
|
+
if (fs.existsSync(stateFile)) {
|
|
57
|
+
const content = fs.readFileSync(stateFile, 'utf-8');
|
|
58
|
+
const state = JSON.parse(content);
|
|
59
|
+
return state.supported;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
function getNodePackageSupportFor(profileName) {
|
|
68
|
+
try {
|
|
69
|
+
const stateFile = path.join(STATE_DIR, `node-package-${profileName}.json`);
|
|
70
|
+
if (fs.existsSync(stateFile)) {
|
|
71
|
+
const content = fs.readFileSync(stateFile, 'utf-8');
|
|
72
|
+
const state = JSON.parse(content);
|
|
73
|
+
return state.supported;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
async function checkAndCacheNodePackageSupport() {
|
|
82
|
+
const supported = await (0, node_1.isNodePackageSupported)();
|
|
83
|
+
ensureStateDir();
|
|
84
|
+
fs.writeFileSync(getStateFile(), JSON.stringify({ supported, checkedAt: Date.now() }), 'utf-8');
|
|
85
|
+
return supported;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=nodePackage.js.map
|
package/dist/utils/oauth.js
CHANGED
|
@@ -219,8 +219,8 @@ function createAuthServer() {
|
|
|
219
219
|
return;
|
|
220
220
|
}
|
|
221
221
|
const port = addr.port;
|
|
222
|
-
const
|
|
223
|
-
resolve({ server, port,
|
|
222
|
+
const waitForResult = createWaitForCode(server, 'http', port);
|
|
223
|
+
resolve({ server, port, waitForResult });
|
|
224
224
|
});
|
|
225
225
|
});
|
|
226
226
|
}
|
|
@@ -236,8 +236,8 @@ function createAuthServerHttps() {
|
|
|
236
236
|
return;
|
|
237
237
|
}
|
|
238
238
|
const port = addr.port;
|
|
239
|
-
const
|
|
240
|
-
resolve({ server, port,
|
|
239
|
+
const waitForResult = createWaitForCode(server, 'https', port);
|
|
240
|
+
resolve({ server, port, waitForResult });
|
|
241
241
|
});
|
|
242
242
|
});
|
|
243
243
|
}
|
|
@@ -300,14 +300,22 @@ function createWaitForCode(server, protocol, _port) {
|
|
|
300
300
|
server.on('request', (req, res) => {
|
|
301
301
|
const url = new URL(req.url || '/', `${protocol}://127.0.0.1`);
|
|
302
302
|
const error = url.searchParams.get('error');
|
|
303
|
-
const
|
|
304
|
-
|
|
303
|
+
const accessToken = url.searchParams.get('access_token');
|
|
304
|
+
const refreshToken = url.searchParams.get('refresh_token');
|
|
305
|
+
const idToken = url.searchParams.get('id_token');
|
|
306
|
+
const tokenType = url.searchParams.get('token_type');
|
|
307
|
+
const expiresIn = url.searchParams.get('expires_in');
|
|
308
|
+
if (!accessToken && !error) {
|
|
305
309
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
306
|
-
const str = "`${location.href.substring(0, location.href.indexOf('#'))}?
|
|
310
|
+
const str = "`${location.href.substring(0, location.href.indexOf('#'))}?access_token=${token}&refresh_token=${refresh_token}&id_token=${id_token}&token_type=${token_type}&expires_in=${expires_in}`";
|
|
307
311
|
res.end(renderPage('等待授权回调', `<p>正在等待浏览器授权,请勿关闭此页面...</p><div class="spinner"></div>`, '').replace('</body>', `<script>
|
|
308
312
|
(function(){
|
|
309
313
|
var params = new URLSearchParams(location.hash.substring(1));
|
|
310
314
|
var token = params.get('access_token');
|
|
315
|
+
var refresh_token = params.get('refresh_token');
|
|
316
|
+
var id_token = params.get('id_token');
|
|
317
|
+
var token_type = params.get('token_type');
|
|
318
|
+
var expires_in = params.get('expires_in');
|
|
311
319
|
location.href = ${str};
|
|
312
320
|
})();
|
|
313
321
|
</script></body>`));
|
|
@@ -325,7 +333,18 @@ function createWaitForCode(server, protocol, _port) {
|
|
|
325
333
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
326
334
|
res.end(renderPage('登录成功', '<p>请关闭此页面返回终端</p>', '').replace('card">', 'card success">'));
|
|
327
335
|
server.close();
|
|
328
|
-
|
|
336
|
+
const result = {
|
|
337
|
+
access_token: accessToken ?? '',
|
|
338
|
+
refresh_token: refreshToken ?? '',
|
|
339
|
+
id_token: idToken ?? '',
|
|
340
|
+
token_type: tokenType ?? '',
|
|
341
|
+
expires_in: expiresIn ? Number(expiresIn) : 0,
|
|
342
|
+
};
|
|
343
|
+
if (!accessToken) {
|
|
344
|
+
rejectCode(new Error('授权回调缺少 access_token'));
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
resolveCode(result);
|
|
329
348
|
});
|
|
330
349
|
server.on('error', (err) => {
|
|
331
350
|
clearTimeout(timer);
|