@longzai-intelligence-workflow/core 0.0.1 → 0.0.5

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.
Files changed (48) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-lint.log +1305 -0
  3. package/.turbo/turbo-typecheck.log +12 -0
  4. package/CHANGELOG.md +24 -1
  5. package/coverage/.lcov.info.09bb1f2a9aba2380.tmp +169 -0
  6. package/coverage/.lcov.info.0e095d78ac9192b0.tmp +329 -0
  7. package/coverage/.lcov.info.53a7ebfa7c8664ce.tmp +12 -0
  8. package/coverage/.lcov.info.6ea86c7cbc796fe0.tmp +12 -0
  9. package/coverage/.lcov.info.8f2985e5b3ad22cc.tmp +329 -0
  10. package/coverage/.lcov.info.a6ce2b7c3df2438b.tmp +228 -0
  11. package/coverage/.lcov.info.cc45f2f81aa7e02f.tmp +12 -0
  12. package/coverage/.lcov.info.cd0e8c028b2d5097.tmp +329 -0
  13. package/coverage/.lcov.info.dae76ebcf998e663.tmp +12 -0
  14. package/coverage/.lcov.info.e3bdb201eb5ce330.tmp +170 -0
  15. package/coverage/.lcov.info.e54e42fa06f69854.tmp +12 -0
  16. package/coverage/.lcov.info.f3e7537ac7b81e07.tmp +12 -0
  17. package/coverage/.lcov.info.fbb8af17757faa2d.tmp +329 -0
  18. package/coverage/lcov.info +208 -48
  19. package/dist/index.d.ts +3 -29
  20. package/dist/index.js +3 -3
  21. package/docs/overview.md +1 -1
  22. package/package.json +2 -1
  23. package/src/__tests__/unit/constants.test.ts +75 -30
  24. package/src/__tests__/unit/utils.test.ts +110 -38
  25. package/src/__tests__/work-item-rules.test.ts +18 -5
  26. package/src/index.ts +19 -5
  27. package/src/ports/action-executor.port.ts +2 -1
  28. package/src/ports/feed-event.port.ts +1 -1
  29. package/src/ports/index.ts +1 -0
  30. package/src/schemas/action-executor.schema.ts +2 -1
  31. package/src/schemas/definition.schema.ts +1 -1
  32. package/src/schemas/feed-event-trigger.schema.ts +1 -1
  33. package/src/schemas/index.ts +7 -0
  34. package/src/schemas/instance.schema.ts +1 -1
  35. package/src/schemas/monitoring.schema.ts +1 -1
  36. package/src/schemas/trigger.schema.ts +1 -1
  37. package/src/schemas/workflow-doc.schema.ts +4 -2
  38. package/src/types/action-executor.ts +1 -1
  39. package/src/types/feed-event-trigger.ts +1 -1
  40. package/src/types/index.ts +5 -0
  41. package/src/utils/dag.utils.ts +14 -93
  42. package/src/utils/index.ts +4 -2
  43. package/src/utils/work-item-rules.utils.ts +28 -7
  44. package/tsconfig/.cache/build.tsbuildinfo +1 -1
  45. package/tsconfig/.cache/node.tsbuildinfo +1 -1
  46. package/tsconfig/.cache/test.tsbuildinfo +1 -1
  47. package/tsconfig/node.json +1 -1
  48. package/tsconfig.json +9 -1
@@ -0,0 +1,1305 @@
1
+ $ oxlint src && oxfmt --check src
2
+
3
+ ! @longzai-intelligence-oxlint/zod-plugin(prefer-zod-namespace): 请使用命名空间导入 zod(import * as z from "zod")代替命名导入。
4
+ ,-[src/schemas/instance.schema.ts:1:10]
5
+ 1 | import { z } from 'zod';
6
+ : ^
7
+ 2 |
8
+ `----
9
+
10
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
11
+ ,-[src/utils/index.ts:18:1]
12
+ 17 | export * from './declaration-frontmatter.utils';
13
+ 18 | export * from './work-item-rules.utils';
14
+ : ^
15
+ 19 | export * from './dag.utils';
16
+ `----
17
+
18
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
19
+ ,-[src/utils/index.ts:19:1]
20
+ 18 | export * from './work-item-rules.utils';
21
+ 19 | export * from './dag.utils';
22
+ : ^
23
+ `----
24
+
25
+ x @longzai-intelligence-oxlint/code-style-plugin(no-inline-type-definition): 函数 "getPagination" 的返回值使用了内联对象类型定义。请将其提取为具名的 type。
26
+ ,-[src/utils/index.ts:3:8]
27
+ 2 |
28
+ 3 | ,-> export function getPagination(page?: number, pageSize?: number): { offset: number; limit: number } {
29
+ 4 | | const limit = Math.min(pageSize ?? DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE);
30
+ 5 | | const offset = (Math.max(page ?? 1, 1) - 1) * limit;
31
+ 6 | | return { offset, limit };
32
+ 7 | `-> }
33
+ 8 |
34
+ `----
35
+
36
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "feed-event-trigger.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
37
+ ,-[src/types/feed-event-trigger.ts:8:1]
38
+ 7 |
39
+ 8 | ,-> import type {
40
+ 9 | | feedEventFilterSchema,
41
+ 10 | | feedEventNameSchema,
42
+ 11 | | feedEventPayloadSchema,
43
+ 12 | | feedEventTriggerSchema,
44
+ 13 | | } from '@/schemas';
45
+ 14 | | import type { z } from 'zod';
46
+ 15 | |
47
+ 16 | | /**
48
+ 17 | | * feed 事件名称类型
49
+ 18 | | */
50
+ 19 | | export type FeedEventName = z.infer<typeof feedEventNameSchema>;
51
+ 20 | |
52
+ 21 | | /**
53
+ 22 | | * feed 事件过滤条件类型
54
+ 23 | | */
55
+ 24 | | export type FeedEventFilter = z.infer<typeof feedEventFilterSchema>;
56
+ 25 | |
57
+ 26 | | /**
58
+ 27 | | * feed 事件触发器配置类型
59
+ 28 | | *
60
+ 29 | | * 工作流 trigger.type 为 'feed.event' 时的配置结构。
61
+ 30 | | */
62
+ 31 | | export type FeedEventTrigger = z.infer<typeof feedEventTriggerSchema>;
63
+ 32 | |
64
+ 33 | | /**
65
+ 34 | | * feed 事件 payload 类型
66
+ 35 | | *
67
+ 36 | | * feed 项目在事件触发时传递给工作流上下文的事件数据。
68
+ 37 | | */
69
+ 38 | `-> export type FeedEventPayload = z.infer<typeof feedEventPayloadSchema>;
70
+ `----
71
+
72
+ ! @longzai-intelligence-oxlint/zod-plugin(prefer-zod-namespace): 请使用命名空间导入 zod(import * as z from "zod")代替命名导入。
73
+ ,-[src/types/feed-event-trigger.ts:14:15]
74
+ 13 | } from '@/schemas';
75
+ 14 | import type { z } from 'zod';
76
+ : ^
77
+ 15 |
78
+ `----
79
+
80
+ ! @longzai-intelligence-oxlint/zod-plugin(prefer-zod-namespace): 请使用命名空间导入 zod(import * as z from "zod")代替命名导入。
81
+ ,-[src/schemas/definition.schema.ts:1:10]
82
+ 1 | import { z } from 'zod';
83
+ : ^
84
+ 2 |
85
+ `----
86
+
87
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
88
+ ,-[src/index.ts:10:1]
89
+ 9 | // 常量导出
90
+ 10 | export * from './constants/index';
91
+ : ^
92
+ 11 | // 工具函数导出
93
+ `----
94
+
95
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
96
+ ,-[src/index.ts:12:1]
97
+ 11 | // 工具函数导出
98
+ 12 | export * from './utils/index';
99
+ : ^
100
+ 13 | // zod schema 导出
101
+ `----
102
+
103
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
104
+ ,-[src/index.ts:14:1]
105
+ 13 | // zod schema 导出
106
+ 14 | export * from './schemas/index';
107
+ : ^
108
+ 15 | // 端口契约导出(C1 合规,零框架依赖)
109
+ `----
110
+
111
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
112
+ ,-[src/index.ts:16:1]
113
+ 15 | // 端口契约导出(C1 合规,零框架依赖)
114
+ 16 | export * from './ports/index';
115
+ : ^
116
+ `----
117
+
118
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
119
+ ,-[src/index.ts:7:1]
120
+ 6 | */
121
+ 7 | // 类型导出
122
+ : ^^^^^^^^^^^
123
+ 8 | export * from './types/index';
124
+ `----
125
+
126
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
127
+ ,-[src/index.ts:9:1]
128
+ 8 | export * from './types/index';
129
+ 9 | // 常量导出
130
+ : ^^^^^^^^^^^
131
+ 10 | export * from './constants/index';
132
+ `----
133
+
134
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
135
+ ,-[src/index.ts:11:1]
136
+ 10 | export * from './constants/index';
137
+ 11 | // 工具函数导出
138
+ : ^^^^^^^^^^^^^^^
139
+ 12 | export * from './utils/index';
140
+ `----
141
+
142
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
143
+ ,-[src/index.ts:13:1]
144
+ 12 | export * from './utils/index';
145
+ 13 | // zod schema 导出
146
+ : ^^^^^^^^^^^^^^^^^^
147
+ 14 | export * from './schemas/index';
148
+ `----
149
+
150
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
151
+ ,-[src/index.ts:15:1]
152
+ 14 | export * from './schemas/index';
153
+ 15 | // 端口契约导出(C1 合规,零框架依赖)
154
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
155
+ 16 | export * from './ports/index';
156
+ `----
157
+
158
+ ! @longzai-intelligence-oxlint/zod-plugin(prefer-zod-namespace): 请使用命名空间导入 zod(import * as z from "zod")代替命名导入。
159
+ ,-[src/schemas/monitoring.schema.ts:1:10]
160
+ 1 | import { z } from 'zod';
161
+ : ^
162
+ 2 |
163
+ `----
164
+
165
+ ! @longzai-intelligence-oxlint/zod-plugin(prefer-zod-namespace): 请使用命名空间导入 zod(import * as z from "zod")代替命名导入。
166
+ ,-[src/schemas/feed-event-trigger.schema.ts:13:10]
167
+ 12 |
168
+ 13 | import { z } from 'zod';
169
+ : ^
170
+ 14 |
171
+ `----
172
+
173
+ ! @longzai-intelligence-oxlint/zod-plugin(prefer-zod-namespace): 请使用命名空间导入 zod(import * as z from "zod")代替命名导入。
174
+ ,-[src/schemas/action-executor.schema.ts:16:10]
175
+ 15 |
176
+ 16 | import { z } from 'zod';
177
+ : ^
178
+ 17 |
179
+ `----
180
+
181
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
182
+ ,-[src/types/index.ts:2:1]
183
+ 1 | export * from './definition';
184
+ 2 | export * from './instance';
185
+ : ^
186
+ 3 | export * from './trigger';
187
+ `----
188
+
189
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
190
+ ,-[src/types/index.ts:3:1]
191
+ 2 | export * from './instance';
192
+ 3 | export * from './trigger';
193
+ : ^
194
+ 4 | export * from './monitoring';
195
+ `----
196
+
197
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
198
+ ,-[src/types/index.ts:4:1]
199
+ 3 | export * from './trigger';
200
+ 4 | export * from './monitoring';
201
+ : ^
202
+ 5 | export * from './feed-event-trigger';
203
+ `----
204
+
205
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
206
+ ,-[src/types/index.ts:5:1]
207
+ 4 | export * from './monitoring';
208
+ 5 | export * from './feed-event-trigger';
209
+ : ^
210
+ 6 | export * from './action-executor';
211
+ `----
212
+
213
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
214
+ ,-[src/types/index.ts:6:1]
215
+ 5 | export * from './feed-event-trigger';
216
+ 6 | export * from './action-executor';
217
+ : ^
218
+ `----
219
+
220
+ ! @longzai-intelligence-oxlint/zod-plugin(prefer-zod-namespace): 请使用命名空间导入 zod(import * as z from "zod")代替命名导入。
221
+ ,-[src/schemas/trigger.schema.ts:1:10]
222
+ 1 | import { z } from 'zod';
223
+ : ^
224
+ 2 |
225
+ `----
226
+
227
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "action-executor.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
228
+ ,-[src/types/action-executor.ts:8:1]
229
+ 7 |
230
+ 8 | ,-> import type {
231
+ 9 | | actionContextSchema,
232
+ 10 | | actionResultSchema,
233
+ 11 | | actionSchema,
234
+ 12 | | actionTypeSchema,
235
+ 13 | | feedApplyTagsActionSchema,
236
+ 14 | | feedSummarizeActionSchema,
237
+ 15 | | llmCompleteActionSchema,
238
+ 16 | | webhookSendActionSchema,
239
+ 17 | | } from '@/schemas';
240
+ 18 | | import type { z } from 'zod';
241
+ 19 | |
242
+ 20 | | /**
243
+ 21 | | * action 类型枚举
244
+ 22 | | */
245
+ 23 | | export type ActionType = z.infer<typeof actionTypeSchema>;
246
+ 24 | |
247
+ 25 | | /**
248
+ 26 | | * feed.applyTags action 输入类型
249
+ 27 | | */
250
+ 28 | | export type FeedApplyTagsAction = z.infer<typeof feedApplyTagsActionSchema>;
251
+ 29 | |
252
+ 30 | | /**
253
+ 31 | | * feed.summarize action 输入类型
254
+ 32 | | */
255
+ 33 | | export type FeedSummarizeAction = z.infer<typeof feedSummarizeActionSchema>;
256
+ 34 | |
257
+ 35 | | /**
258
+ 36 | | * llm.complete action 输入类型
259
+ 37 | | */
260
+ 38 | | export type LlmCompleteAction = z.infer<typeof llmCompleteActionSchema>;
261
+ 39 | |
262
+ 40 | | /**
263
+ 41 | | * webhook.send action 输入类型
264
+ 42 | | */
265
+ 43 | | export type WebhookSendAction = z.infer<typeof webhookSendActionSchema>;
266
+ 44 | |
267
+ 45 | | /**
268
+ 46 | | * action 联合类型
269
+ 47 | | *
270
+ 48 | | * 所有内置 action 的联合类型,按 type 字段区分。
271
+ 49 | | */
272
+ 50 | | export type Action = z.infer<typeof actionSchema>;
273
+ 51 | |
274
+ 52 | | /**
275
+ 53 | | * action 执行上下文类型
276
+ 54 | | *
277
+ 55 | | * 工作流引擎在执行 action 节点时传入的上下文信息。
278
+ 56 | | */
279
+ 57 | | export type ActionContext = z.infer<typeof actionContextSchema>;
280
+ 58 | |
281
+ 59 | | /**
282
+ 60 | | * action 执行结果类型
283
+ 61 | | *
284
+ 62 | | * action handler 执行完成后返回的结果。
285
+ 63 | | */
286
+ 64 | `-> export type ActionResult = z.infer<typeof actionResultSchema>;
287
+ `----
288
+
289
+ ! @longzai-intelligence-oxlint/zod-plugin(prefer-zod-namespace): 请使用命名空间导入 zod(import * as z from "zod")代替命名导入。
290
+ ,-[src/types/action-executor.ts:18:15]
291
+ 17 | } from '@/schemas';
292
+ 18 | import type { z } from 'zod';
293
+ : ^
294
+ 19 |
295
+ `----
296
+
297
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "monitoring.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
298
+ ,-[src/types/monitoring.ts:1:1]
299
+ 1 | ,-> export type AuditLogDTO = {
300
+ 2 | | id: string;
301
+ 3 | | instanceId: string;
302
+ 4 | | nodeId: string | null;
303
+ 5 | | action: string;
304
+ 6 | | fromStatus: string | null;
305
+ 7 | | toStatus: string;
306
+ 8 | | operator: string | null;
307
+ 9 | | detail: Record<string, unknown>;
308
+ 10 | | createdAt: string;
309
+ 11 | | };
310
+ 12 | |
311
+ 13 | | export type AlertDTO = {
312
+ 14 | | id: string;
313
+ 15 | | definitionId: string;
314
+ 16 | | type: AlertTypeDTO;
315
+ 17 | | threshold: number;
316
+ 18 | | notifyConfig: Record<string, unknown>;
317
+ 19 | | enabled: boolean;
318
+ 20 | | lastTriggeredAt: string | null;
319
+ 21 | | createdAt: string;
320
+ 22 | | updatedAt: string;
321
+ 23 | | };
322
+ 24 | |
323
+ 25 | | export type AlertTypeDTO = 'timeout' | 'failure_rate' | 'slow_execution';
324
+ 26 | |
325
+ 27 | | export type PerformanceMetricDTO = {
326
+ 28 | | id: string;
327
+ 29 | | definitionId: string;
328
+ 30 | | metricType: MetricTypeDTO;
329
+ 31 | | value: number;
330
+ 32 | | period: string;
331
+ 33 | | calculatedAt: string;
332
+ 34 | | };
333
+ 35 | |
334
+ 36 | | export type MetricTypeDTO =
335
+ 37 | | | 'avg_duration'
336
+ 38 | | | 'success_rate'
337
+ 39 | | | 'failure_rate'
338
+ 40 | | | 'timeout_rate'
339
+ 41 | | | 'instance_count';
340
+ 42 | |
341
+ 43 | | export type MonitoringDashboardDTO = {
342
+ 44 | | runningInstances: number;
343
+ 45 | | successRate: number;
344
+ 46 | | avgDuration: number;
345
+ 47 | | failureAlerts: number;
346
+ 48 | | trend: TrendPointDTO[];
347
+ 49 | | };
348
+ 50 | |
349
+ 51 | | export type TrendPointDTO = {
350
+ 52 | | date: string;
351
+ 53 | | value: number;
352
+ 54 | `-> };
353
+ `----
354
+
355
+ x @longzai-intelligence-oxlint/tsdoc-plugin(require-returns): 缺少 @returns 文档
356
+ ,-[src/utils/work-item-rules.utils.ts:138:1]
357
+ 137 | */
358
+ 138 | ,-> function isSettled(status: WorkItemStatus): boolean {
359
+ 139 | | return status === 'done' || status === 'dropped';
360
+ 140 | `-> }
361
+ 141 |
362
+ `----
363
+
364
+ x @longzai-intelligence-oxlint/tsdoc-plugin(require-returns): 缺少 @returns 文档
365
+ ,-[src/utils/work-item-rules.utils.ts:149:8]
366
+ 148 | */
367
+ 149 | ,-> export function deriveWorkflowView(
368
+ 150 | | items: readonly WorkflowItem[],
369
+ 151 | | edges: readonly WorkflowEdge[],
370
+ 152 | | gates: readonly WorkflowGate[],
371
+ 153 | | ): WorkflowView {
372
+ 154 | | /**
373
+ 155 | | * 已闭环工作项 id 集合
374
+ 156 | | */
375
+ 157 | | const settled = new Set(items.filter((item) => isSettled(item.status)).map((item) => item.id));
376
+ 158 | |
377
+ 159 | | /**
378
+ 160 | | * 各工作项挂靠的未批准门(ruling.status 非 approved 即阻塞)
379
+ 161 | | */
380
+ 162 | | const unapprovedGateAt = new Set(gates.filter((gate) => gate.ruling.status !== 'approved' && gate.at !== 'workflow').map((gate) => gate.at));
381
+ 163 | |
382
+ 164 | | /**
383
+ 165 | | * 工作项视图累积
384
+ 166 | | */
385
+ 167 | | const views: WorkItemView[] = items.map((item) => {
386
+ 168 | | /**
387
+ 169 | | * 依赖满足判定(DAG 基础能力域机件,闭环定义由本域注入)
388
+ 170 | | */
389
+ 171 | | const depsMet = dependenciesMet(item.id, edges, settled);
390
+ 172 | |
391
+ 173 | | return {
392
+ 174 | | id: item.id,
393
+ 175 | | status: item.status,
394
+ 176 | | depsMet,
395
+ 177 | | blockedOnPrerequisite: item.status === 'todo' && !depsMet,
396
+ 178 | | canStart: item.status === 'todo' && depsMet && !unapprovedGateAt.has(item.id),
397
+ 179 | | };
398
+ 180 | | });
399
+ 181 | |
400
+ 182 | | /**
401
+ 183 | | * 未决裁定视图累积(pending 与 escalated)
402
+ 184 | | */
403
+ 185 | | const pendingRulings: PendingRulingView[] = gates
404
+ 186 | | .filter((gate) => gate.ruling.status === 'pending' || gate.ruling.status === 'escalated')
405
+ 187 | | .map((gate) => ({
406
+ 188 | | key: `${gate.at}:${gate.kind}`,
407
+ 189 | | at: gate.at,
408
+ 190 | | kind: gate.kind,
409
+ 191 | | note: gate.note,
410
+ 192 | | rulingStatus: gate.ruling.status as 'pending' | 'escalated',
411
+ 193 | | }));
412
+ 194 | |
413
+ 195 | | return { items: views, pendingRulings };
414
+ 196 | `-> }
415
+ `----
416
+
417
+ x @longzai-intelligence-oxlint/typescript-eslint-plugin(consistent-type-assertions): 禁止使用 as 类型断言,请使用类型守卫或 Zod 进行类型验证
418
+ ,-[src/utils/work-item-rules.utils.ts:192:21]
419
+ 191 | note: gate.note,
420
+ 192 | rulingStatus: gate.ruling.status as 'pending' | 'escalated',
421
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
422
+ 193 | }));
423
+ `----
424
+
425
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "workflow.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
426
+ ,-[src/constants/workflow.ts:4:1]
427
+ 3 | */
428
+ 4 | ,-> export const NODE_TYPES = [
429
+ 5 | | 'StartEvent',
430
+ 6 | | 'EndEvent',
431
+ 7 | | 'UserTask',
432
+ 8 | | 'ServiceTask',
433
+ 9 | | 'ExclusiveGateway',
434
+ 10 | | 'ParallelGateway',
435
+ 11 | | 'InclusiveGateway',
436
+ 12 | | 'SubProcess',
437
+ 13 | | 'TimerEvent',
438
+ 14 | | 'ErrorEvent',
439
+ 15 | | 'SignalEvent',
440
+ 16 | | ] as const;
441
+ 17 | |
442
+ 18 | | /**
443
+ 19 | | * 工作流实例状态枚举
444
+ 20 | | */
445
+ 21 | | export const INSTANCE_STATUSES = [
446
+ 22 | | 'pending',
447
+ 23 | | 'running',
448
+ 24 | | 'paused',
449
+ 25 | | 'completed',
450
+ 26 | | 'cancelled',
451
+ 27 | | 'failed',
452
+ 28 | | ] as const;
453
+ 29 | |
454
+ 30 | | /**
455
+ 31 | | * 节点执行状态枚举
456
+ 32 | | */
457
+ 33 | | export const NODE_EXECUTION_STATUSES = [
458
+ 34 | | 'pending',
459
+ 35 | | 'running',
460
+ 36 | | 'completed',
461
+ 37 | | 'failed',
462
+ 38 | | 'skipped',
463
+ 39 | | ] as const;
464
+ 40 | |
465
+ 41 | | /**
466
+ 42 | | * 触发器类型枚举
467
+ 43 | | */
468
+ 44 | | export const TRIGGER_TYPES = ['timer', 'webhook', 'event', 'feed.event'] as const;
469
+ 45 | |
470
+ 46 | | /**
471
+ 47 | | * feed 事件名称枚举(W-2,Phase 2)
472
+ 48 | | *
473
+ 49 | | * 用于 feed.event 触发器订阅 feed 项目暴露的事件总线。
474
+ 50 | | */
475
+ 51 | | export const FEED_EVENT_NAMES = [
476
+ 52 | | /**
477
+ 53 | | * 新条目入库事件
478
+ 54 | | */
479
+ 55 | | 'item.ingested',
480
+ 56 | |
481
+ 57 | | /**
482
+ 58 | | * 信息源抓取完成事件
483
+ 59 | | */
484
+ 60 | | 'source.fetched',
485
+ 61 | |
486
+ 62 | | /**
487
+ 63 | | * 条目过滤事件
488
+ 64 | | */
489
+ 65 | | 'item.filtered',
490
+ 66 | |
491
+ 67 | | /**
492
+ 68 | | * 行业识别事件
493
+ 69 | | */
494
+ 70 | | 'industry.detected',
495
+ 71 | | ] as const;
496
+ 72 | |
497
+ 73 | | /**
498
+ 74 | | * 告警类型枚举
499
+ 75 | | */
500
+ 76 | | export const ALERT_TYPES = ['timeout', 'failure_rate', 'slow_execution'] as const;
501
+ 77 | |
502
+ 78 | | /**
503
+ 79 | | * 工作流内置 action 类型枚举(W-3,Phase 2)
504
+ 80 | | *
505
+ 81 | | * - feed.applyTags:调用 feed F-2 applyTags 为条目打标签
506
+ 82 | | * - feed.summarize:调用 feed F-3 summarize 生成摘要
507
+ 83 | | * - llm.complete:调用 agent LlmCompletePort 完成文本
508
+ 84 | | * - webhook.send:调用 webhook 项目发送 webhook
509
+ 85 | | *
510
+ 86 | | * D-08 决策:不暴露 DSL 编辑 UI,action 通过自然语言编译的 DSL 执行。
511
+ 87 | | */
512
+ 88 | | export const ACTION_TYPES = [
513
+ 89 | | 'feed.applyTags',
514
+ 90 | | 'feed.summarize',
515
+ 91 | | 'llm.complete',
516
+ 92 | | 'webhook.send',
517
+ 93 | | ] as const;
518
+ 94 | |
519
+ 95 | | /**
520
+ 96 | | * 监控指标类型枚举
521
+ 97 | | */
522
+ 98 | | export const METRIC_TYPES = [
523
+ 99 | | 'avg_duration',
524
+ 100 | | 'success_rate',
525
+ 101 | | 'failure_rate',
526
+ 102 | | 'timeout_rate',
527
+ 103 | | 'instance_count',
528
+ 104 | | ] as const;
529
+ 105 | |
530
+ 106 | | /**
531
+ 107 | | * 分页查询默认每页条数
532
+ 108 | | */
533
+ 109 | | export const DEFAULT_PAGE_SIZE = 20;
534
+ 110 | |
535
+ 111 | | /**
536
+ 112 | | * 分页查询每页最大条数上限
537
+ 113 | | */
538
+ 114 | `-> export const MAX_PAGE_SIZE = 100;
539
+ `----
540
+
541
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "instance.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
542
+ ,-[src/types/instance.ts:1:1]
543
+ 1 | ,-> export type InstanceDTO = {
544
+ 2 | | id: string;
545
+ 3 | | definitionId: string;
546
+ 4 | | definitionVersion: number;
547
+ 5 | | status: InstanceStatusDTO;
548
+ 6 | | currentState: string;
549
+ 7 | | previousState: string | null;
550
+ 8 | | currentNodeId: string | null;
551
+ 9 | | variables: Record<string, unknown>;
552
+ 10 | | startedAt: string | null;
553
+ 11 | | completedAt: string | null;
554
+ 12 | | createdAt: string;
555
+ 13 | | updatedAt: string;
556
+ 14 | | };
557
+ 15 | |
558
+ 16 | | export type InstanceStatusDTO =
559
+ 17 | | | 'pending'
560
+ 18 | | | 'running'
561
+ 19 | | | 'paused'
562
+ 20 | | | 'completed'
563
+ 21 | | | 'cancelled'
564
+ 22 | | | 'failed';
565
+ 23 | |
566
+ 24 | | export type NodeExecutionDTO = {
567
+ 25 | | id: string;
568
+ 26 | | instanceId: string;
569
+ 27 | | nodeId: string;
570
+ 28 | | nodeName: string;
571
+ 29 | | nodeType: string;
572
+ 30 | | status: NodeExecutionStatusDTO;
573
+ 31 | | startedAt: string | null;
574
+ 32 | | completedAt: string | null;
575
+ 33 | | error: string | null;
576
+ 34 | | createdAt: string;
577
+ 35 | | };
578
+ 36 | |
579
+ 37 | | export type NodeExecutionStatusDTO = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
580
+ 38 | |
581
+ 39 | | export type CreateInstanceInput = {
582
+ 40 | | definitionId: string;
583
+ 41 | | input?: Record<string, unknown>;
584
+ 42 | | };
585
+ 43 | |
586
+ 44 | | export type InstanceQueryParams = {
587
+ 45 | | status?: InstanceStatusDTO;
588
+ 46 | | definitionId?: string;
589
+ 47 | | page?: number;
590
+ 48 | | pageSize?: number;
591
+ 49 | `-> };
592
+ `----
593
+
594
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
595
+ ,-[src/ports/index.ts:9:1]
596
+ 8 | export * from './feed-event.port';
597
+ 9 | export * from './action-executor.port';
598
+ : ^
599
+ `----
600
+
601
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "trigger.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
602
+ ,-[src/types/trigger.ts:4:1]
603
+ 3 | */
604
+ 4 | ,-> export type TriggerDTO = {
605
+ 5 | | id: string;
606
+ 6 | | definitionId: string;
607
+ 7 | | name: string;
608
+ 8 | | type: TriggerTypeDTO;
609
+ 9 | | config: Record<string, unknown>;
610
+ 10 | | enabled: boolean;
611
+ 11 | | lastTriggeredAt: string | null;
612
+ 12 | | createdAt: string;
613
+ 13 | | updatedAt: string;
614
+ 14 | | };
615
+ 15 | |
616
+ 16 | | /**
617
+ 17 | | * 触发器类型枚举
618
+ 18 | | *
619
+ 19 | | * - timer:定时触发
620
+ 20 | | * - webhook:Webhook 触发
621
+ 21 | | * - event:通用事件触发
622
+ 22 | | * - feed.event:feed 事件触发(W-2,Phase 2)
623
+ 23 | | */
624
+ 24 | | export type TriggerTypeDTO = 'timer' | 'webhook' | 'event' | 'feed.event';
625
+ 25 | |
626
+ 26 | | /**
627
+ 27 | | * 创建触发器的入参
628
+ 28 | | */
629
+ 29 | | export type CreateTriggerInput = {
630
+ 30 | | definitionId: string;
631
+ 31 | | name: string;
632
+ 32 | | type: TriggerTypeDTO;
633
+ 33 | | config: Record<string, unknown>;
634
+ 34 | | };
635
+ 35 | |
636
+ 36 | | /**
637
+ 37 | | * 更新触发器的入参
638
+ 38 | | */
639
+ 39 | `-> export type UpdateTriggerInput = Partial<CreateTriggerInput>;
640
+ `----
641
+
642
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
643
+ ,-[src/__tests__/unit/utils.test.ts:8:5]
644
+ 7 | it('默认参数返回 offset=0, limit=DEFAULT_PAGE_SIZE', () => {
645
+ 8 | // Arrange & Act
646
+ : ^^^^^^^^^^^^^^^^
647
+ 9 | const result = getPagination();
648
+ `----
649
+
650
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
651
+ ,-[src/__tests__/unit/utils.test.ts:11:5]
652
+ 10 |
653
+ 11 | // Assert
654
+ : ^^^^^^^^^
655
+ 12 | expect(result.offset).toBe(0);
656
+ `----
657
+
658
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
659
+ ,-[src/__tests__/unit/utils.test.ts:17:5]
660
+ 16 | it('page=2, pageSize=10 返回 offset=10, limit=10', () => {
661
+ 17 | // Arrange & Act
662
+ : ^^^^^^^^^^^^^^^^
663
+ 18 | const result = getPagination(2, 10);
664
+ `----
665
+
666
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
667
+ ,-[src/__tests__/unit/utils.test.ts:20:5]
668
+ 19 |
669
+ 20 | // Assert
670
+ : ^^^^^^^^^
671
+ 21 | expect(result.offset).toBe(10);
672
+ `----
673
+
674
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
675
+ ,-[src/__tests__/unit/utils.test.ts:26:5]
676
+ 25 | it('pageSize 超过 MAX_PAGE_SIZE 时限制为 MAX_PAGE_SIZE', () => {
677
+ 26 | // Arrange
678
+ : ^^^^^^^^^^
679
+ 27 | const oversizedPageSize = MAX_PAGE_SIZE + 50;
680
+ `----
681
+
682
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
683
+ ,-[src/__tests__/unit/utils.test.ts:29:5]
684
+ 28 |
685
+ 29 | // Act
686
+ : ^^^^^^
687
+ 30 | const result = getPagination(1, oversizedPageSize);
688
+ `----
689
+
690
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
691
+ ,-[src/__tests__/unit/utils.test.ts:32:5]
692
+ 31 |
693
+ 32 | // Assert
694
+ : ^^^^^^^^^
695
+ 33 | expect(result.limit).toBe(MAX_PAGE_SIZE);
696
+ `----
697
+
698
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
699
+ ,-[src/__tests__/unit/utils.test.ts:37:5]
700
+ 36 | it('page=0 时默认为 page=1', () => {
701
+ 37 | // Arrange & Act
702
+ : ^^^^^^^^^^^^^^^^
703
+ 38 | const result = getPagination(0, 10);
704
+ `----
705
+
706
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
707
+ ,-[src/__tests__/unit/utils.test.ts:40:5]
708
+ 39 |
709
+ 40 | // Assert
710
+ : ^^^^^^^^^
711
+ 41 | expect(result.offset).toBe(0);
712
+ `----
713
+
714
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
715
+ ,-[src/__tests__/unit/utils.test.ts:46:5]
716
+ 45 | it('page 为负数时默认为 page=1', () => {
717
+ 46 | // Arrange & Act
718
+ : ^^^^^^^^^^^^^^^^
719
+ 47 | const result = getPagination(-1, 10);
720
+ `----
721
+
722
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
723
+ ,-[src/__tests__/unit/utils.test.ts:49:5]
724
+ 48 |
725
+ 49 | // Assert
726
+ : ^^^^^^^^^
727
+ 50 | expect(result.offset).toBe(0);
728
+ `----
729
+
730
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
731
+ ,-[src/__tests__/unit/utils.test.ts:54:5]
732
+ 53 | it('仅传入 page 时 pageSize 使用默认值', () => {
733
+ 54 | // Arrange & Act
734
+ : ^^^^^^^^^^^^^^^^
735
+ 55 | const result = getPagination(3);
736
+ `----
737
+
738
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
739
+ ,-[src/__tests__/unit/utils.test.ts:57:5]
740
+ 56 |
741
+ 57 | // Assert
742
+ : ^^^^^^^^^
743
+ 58 | expect(result.offset).toBe((3 - 1) * DEFAULT_PAGE_SIZE);
744
+ `----
745
+
746
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
747
+ ,-[src/__tests__/unit/utils.test.ts:63:5]
748
+ 62 | it('仅传入 pageSize 时 page 默认为 1', () => {
749
+ 63 | // Arrange & Act
750
+ : ^^^^^^^^^^^^^^^^
751
+ 64 | const result = getPagination(undefined, 15);
752
+ `----
753
+
754
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
755
+ ,-[src/__tests__/unit/utils.test.ts:66:5]
756
+ 65 |
757
+ 66 | // Assert
758
+ : ^^^^^^^^^
759
+ 67 | expect(result.offset).toBe(0);
760
+ `----
761
+
762
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
763
+ ,-[src/__tests__/unit/utils.test.ts:74:5]
764
+ 73 | it('正确计算总页数', () => {
765
+ 74 | // Arrange
766
+ : ^^^^^^^^^^
767
+ 75 | const total = 45;
768
+ `----
769
+
770
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
771
+ ,-[src/__tests__/unit/utils.test.ts:78:5]
772
+ 77 |
773
+ 78 | // Act
774
+ : ^^^^^^
775
+ 79 | const result = getTotalPages(total, pageSize);
776
+ `----
777
+
778
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
779
+ ,-[src/__tests__/unit/utils.test.ts:81:5]
780
+ 80 |
781
+ 81 | // Assert
782
+ : ^^^^^^^^^
783
+ 82 | expect(result).toBe(5);
784
+ `----
785
+
786
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
787
+ ,-[src/__tests__/unit/utils.test.ts:86:5]
788
+ 85 | it('总数恰好整除时返回精确页数', () => {
789
+ 86 | // Arrange
790
+ : ^^^^^^^^^^
791
+ 87 | const total = 40;
792
+ `----
793
+
794
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
795
+ ,-[src/__tests__/unit/utils.test.ts:90:5]
796
+ 89 |
797
+ 90 | // Act
798
+ : ^^^^^^
799
+ 91 | const result = getTotalPages(total, pageSize);
800
+ `----
801
+
802
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
803
+ ,-[src/__tests__/unit/utils.test.ts:93:5]
804
+ 92 |
805
+ 93 | // Assert
806
+ : ^^^^^^^^^
807
+ 94 | expect(result).toBe(4);
808
+ `----
809
+
810
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
811
+ ,-[src/__tests__/unit/utils.test.ts:98:5]
812
+ 97 | it('总数为 0 时返回 0', () => {
813
+ 98 | // Arrange
814
+ : ^^^^^^^^^^
815
+ 99 | const total = 0;
816
+ `----
817
+
818
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
819
+ ,-[src/__tests__/unit/utils.test.ts:102:5]
820
+ 101 |
821
+ 102 | // Act
822
+ : ^^^^^^
823
+ 103 | const result = getTotalPages(total, pageSize);
824
+ `----
825
+
826
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
827
+ ,-[src/__tests__/unit/utils.test.ts:105:5]
828
+ 104 |
829
+ 105 | // Assert
830
+ : ^^^^^^^^^
831
+ 106 | expect(result).toBe(0);
832
+ `----
833
+
834
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
835
+ ,-[src/__tests__/unit/utils.test.ts:110:5]
836
+ 109 | it('总数为 1 时返回 1', () => {
837
+ 110 | // Arrange
838
+ : ^^^^^^^^^^
839
+ 111 | const total = 1;
840
+ `----
841
+
842
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
843
+ ,-[src/__tests__/unit/utils.test.ts:114:5]
844
+ 113 |
845
+ 114 | // Act
846
+ : ^^^^^^
847
+ 115 | const result = getTotalPages(total, pageSize);
848
+ `----
849
+
850
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
851
+ ,-[src/__tests__/unit/utils.test.ts:117:5]
852
+ 116 |
853
+ 117 | // Assert
854
+ : ^^^^^^^^^
855
+ 118 | expect(result).toBe(1);
856
+ `----
857
+
858
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
859
+ ,-[src/__tests__/unit/utils.test.ts:124:5]
860
+ 123 | it('将 Date 对象转换为 ISO 字符串', () => {
861
+ 124 | // Arrange
862
+ : ^^^^^^^^^^
863
+ 125 | const date = new Date('2025-01-15T10:30:00.000Z');
864
+ `----
865
+
866
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
867
+ ,-[src/__tests__/unit/utils.test.ts:127:5]
868
+ 126 |
869
+ 127 | // Act
870
+ : ^^^^^^
871
+ 128 | const result = formatDate(date);
872
+ `----
873
+
874
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
875
+ ,-[src/__tests__/unit/utils.test.ts:130:5]
876
+ 129 |
877
+ 130 | // Assert
878
+ : ^^^^^^^^^
879
+ 131 | expect(result).toBe('2025-01-15T10:30:00.000Z');
880
+ `----
881
+
882
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
883
+ ,-[src/__tests__/unit/utils.test.ts:135:5]
884
+ 134 | it('将日期字符串转换为 ISO 字符串', () => {
885
+ 135 | // Arrange
886
+ : ^^^^^^^^^^
887
+ 136 | const dateStr = '2025-06-01';
888
+ `----
889
+
890
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
891
+ ,-[src/__tests__/unit/utils.test.ts:138:5]
892
+ 137 |
893
+ 138 | // Act
894
+ : ^^^^^^
895
+ 139 | const result = formatDate(dateStr);
896
+ `----
897
+
898
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
899
+ ,-[src/__tests__/unit/utils.test.ts:141:5]
900
+ 140 |
901
+ 141 | // Assert
902
+ : ^^^^^^^^^
903
+ 142 | expect(result).toContain('2025-06-01');
904
+ `----
905
+
906
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
907
+ ,-[src/__tests__/unit/utils.test.ts:147:5]
908
+ 146 | it('返回值为有效的 ISO 格式', () => {
909
+ 147 | // Arrange
910
+ : ^^^^^^^^^^
911
+ 148 | const date = new Date();
912
+ `----
913
+
914
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
915
+ ,-[src/__tests__/unit/utils.test.ts:150:5]
916
+ 149 |
917
+ 150 | // Act
918
+ : ^^^^^^
919
+ 151 | const result = formatDate(date);
920
+ `----
921
+
922
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
923
+ ,-[src/__tests__/unit/utils.test.ts:153:5]
924
+ 152 |
925
+ 153 | // Assert
926
+ : ^^^^^^^^^
927
+ 154 | expect(new Date(result).toISOString()).toBe(result);
928
+ `----
929
+
930
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
931
+ ,-[src/__tests__/unit/constants.test.ts:16:5]
932
+ 15 | it('默认分页大小为 20', () => {
933
+ 16 | // Arrange & Act & Assert
934
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^
935
+ 17 | expect(DEFAULT_PAGE_SIZE).toBe(20);
936
+ `----
937
+
938
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
939
+ ,-[src/__tests__/unit/constants.test.ts:23:5]
940
+ 22 | it('最大分页大小为 100', () => {
941
+ 23 | // Arrange & Act & Assert
942
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^
943
+ 24 | expect(MAX_PAGE_SIZE).toBe(100);
944
+ `----
945
+
946
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
947
+ ,-[src/__tests__/unit/constants.test.ts:30:5]
948
+ 29 | it('包含预期的节点类型', () => {
949
+ 30 | // Arrange
950
+ : ^^^^^^^^^^
951
+ 31 | const expectedTypes = [
952
+ `----
953
+
954
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
955
+ ,-[src/__tests__/unit/constants.test.ts:45:5]
956
+ 44 |
957
+ 45 | // Act & Assert
958
+ : ^^^^^^^^^^^^^^^
959
+ 46 | expect(NODE_TYPES).toEqual(expectedTypes);
960
+ `----
961
+
962
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
963
+ ,-[src/__tests__/unit/constants.test.ts:50:5]
964
+ 49 | it('包含 StartEvent', () => {
965
+ 50 | // Arrange & Act & Assert
966
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^
967
+ 51 | expect(NODE_TYPES).toContain('StartEvent');
968
+ `----
969
+
970
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
971
+ ,-[src/__tests__/unit/constants.test.ts:55:5]
972
+ 54 | it('包含 EndEvent', () => {
973
+ 55 | // Arrange & Act & Assert
974
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^
975
+ 56 | expect(NODE_TYPES).toContain('EndEvent');
976
+ `----
977
+
978
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
979
+ ,-[src/__tests__/unit/constants.test.ts:60:5]
980
+ 59 | it('为只读数组', () => {
981
+ 60 | // Arrange & Act & Assert
982
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^
983
+ 61 | expect(Array.isArray(NODE_TYPES)).toBe(true);
984
+ `----
985
+
986
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
987
+ ,-[src/__tests__/unit/constants.test.ts:67:5]
988
+ 66 | it('包含预期的实例状态', () => {
989
+ 67 | // Arrange
990
+ : ^^^^^^^^^^
991
+ 68 | const expectedStatuses = ['pending', 'running', 'paused', 'completed', 'cancelled', 'failed'];
992
+ `----
993
+
994
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
995
+ ,-[src/__tests__/unit/constants.test.ts:70:5]
996
+ 69 |
997
+ 70 | // Act & Assert
998
+ : ^^^^^^^^^^^^^^^
999
+ 71 | expect(INSTANCE_STATUSES).toEqual(expectedStatuses);
1000
+ `----
1001
+
1002
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1003
+ ,-[src/__tests__/unit/constants.test.ts:75:5]
1004
+ 74 | it('包含 pending 状态', () => {
1005
+ 75 | // Arrange & Act & Assert
1006
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^
1007
+ 76 | expect(INSTANCE_STATUSES).toContain('pending');
1008
+ `----
1009
+
1010
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1011
+ ,-[src/__tests__/unit/constants.test.ts:80:5]
1012
+ 79 | it('包含 failed 状态', () => {
1013
+ 80 | // Arrange & Act & Assert
1014
+ : ^^^^^^^^^^^^^^^^^^^^^^^^^
1015
+ 81 | expect(INSTANCE_STATUSES).toContain('failed');
1016
+ `----
1017
+
1018
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1019
+ ,-[src/__tests__/unit/constants.test.ts:87:5]
1020
+ 86 | it('包含预期的节点执行状态', () => {
1021
+ 87 | // Arrange
1022
+ : ^^^^^^^^^^
1023
+ 88 | const expectedStatuses = ['pending', 'running', 'completed', 'failed', 'skipped'];
1024
+ `----
1025
+
1026
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1027
+ ,-[src/__tests__/unit/constants.test.ts:90:5]
1028
+ 89 |
1029
+ 90 | // Act & Assert
1030
+ : ^^^^^^^^^^^^^^^
1031
+ 91 | expect(NODE_EXECUTION_STATUSES).toEqual(expectedStatuses);
1032
+ `----
1033
+
1034
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1035
+ ,-[src/__tests__/unit/constants.test.ts:97:5]
1036
+ 96 | it('包含预期的触发器类型', () => {
1037
+ 97 | // Arrange
1038
+ : ^^^^^^^^^^
1039
+ 98 | const expectedTypes = ['timer', 'webhook', 'event'];
1040
+ `----
1041
+
1042
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1043
+ ,-[src/__tests__/unit/constants.test.ts:100:5]
1044
+ 99 |
1045
+ 100 | // Act & Assert
1046
+ : ^^^^^^^^^^^^^^^
1047
+ 101 | expect(TRIGGER_TYPES).toEqual(expectedTypes);
1048
+ `----
1049
+
1050
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1051
+ ,-[src/__tests__/unit/constants.test.ts:107:5]
1052
+ 106 | it('包含预期的告警类型', () => {
1053
+ 107 | // Arrange
1054
+ : ^^^^^^^^^^
1055
+ 108 | const expectedTypes = ['timeout', 'failure_rate', 'slow_execution'];
1056
+ `----
1057
+
1058
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1059
+ ,-[src/__tests__/unit/constants.test.ts:110:5]
1060
+ 109 |
1061
+ 110 | // Act & Assert
1062
+ : ^^^^^^^^^^^^^^^
1063
+ 111 | expect(ALERT_TYPES).toEqual(expectedTypes);
1064
+ `----
1065
+
1066
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1067
+ ,-[src/__tests__/unit/constants.test.ts:117:5]
1068
+ 116 | it('包含预期的指标类型', () => {
1069
+ 117 | // Arrange
1070
+ : ^^^^^^^^^^
1071
+ 118 | const expectedTypes = [
1072
+ `----
1073
+
1074
+ x @longzai-intelligence-oxlint/stylistic-plugin(multiline-comment-style): 禁止双斜杠注释,只允许多行块注释
1075
+ ,-[src/__tests__/unit/constants.test.ts:126:5]
1076
+ 125 |
1077
+ 126 | // Act & Assert
1078
+ : ^^^^^^^^^^^^^^^
1079
+ 127 | expect(METRIC_TYPES).toEqual(expectedTypes);
1080
+ `----
1081
+
1082
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "setup.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
1083
+ ,-[src/__tests__/helpers/setup.ts:1:1]
1084
+ 1 | ,-> import { afterAll, afterEach, beforeAll } from 'bun:test';
1085
+ 2 | |
1086
+ 3 | | process.env.NODE_ENV ??= 'test';
1087
+ 4 | |
1088
+ 5 | | beforeAll(() => {});
1089
+ 6 | |
1090
+ 7 | | afterAll(() => {});
1091
+ 8 | |
1092
+ 9 | `-> afterEach(() => {});
1093
+ `----
1094
+
1095
+ x @longzai-intelligence-oxlint/architecture-library-plugin(test-file-matches-source): 测试文件 "work-item-rules.test.ts" 未找到匹配的源文件。测试文件应集中放置在 __tests__/ 目录下(可按 unit/integration/e2e 或 bun/vitest 分子目录组织),文件名与源文件名或目录名保持一致,例如 src/user.service.ts -> src/__tests__/user.service.test.ts、src/bridge/ -> src/__tests__/bridge.test.ts。同一源文件拆分多
1096
+ | 个测试时,用点号分隔拆分标识(如 src/comment.orm-repository.ts -> src/__tests__/comment.orm-repository.query.test.ts,而非 comment.orm-repository-query.test.ts)
1097
+ ,-[src/__tests__/work-item-rules.test.ts:4:1]
1098
+ 3 | */
1099
+ 4 | ,-> import { describe, expect, test } from 'bun:test';
1100
+ 5 | |
1101
+ 6 | | import { parseGateLine, parseItemLine, type WorkflowEdge, type WorkflowGate, type WorkflowItem } from '@/schemas/workflow-doc.schema';
1102
+ 7 | | import { checkStatusTransition, deriveWorkflowView } from '@/utils/work-item-rules.utils';
1103
+ 8 | |
1104
+ 9 | | describe('声明方言四段制解析', () => {
1105
+ 10 | | test('工作项行:状态段执法', () => {
1106
+ 11 | | expect(parseItemLine('t-011 | 生成器补全 | ref:demo/docs/tasks/a.md | todo')).toEqual({
1107
+ 12 | | id: 't-011',
1108
+ 13 | | title: '生成器补全',
1109
+ 14 | | ref: 'ref:demo/docs/tasks/a.md',
1110
+ 15 | | status: 'todo',
1111
+ 16 | | });
1112
+ 17 | | expect(parseItemLine('t-011 | 生成器补全 | ref:demo/docs/tasks/a.md')).toBeNull();
1113
+ 18 | | expect(parseItemLine('t-011 | 生成器补全 | ref:demo/docs/tasks/a.md | invalid')).toBeNull();
1114
+ 19 | | });
1115
+ 20 | |
1116
+ 21 | | test('裁定门行:裁定段四形态执法', () => {
1117
+ 22 | | expect(parseGateLine('t-013 | ruling | 载体指示待裁 | pending')?.ruling).toEqual({ status: 'pending' });
1118
+ 23 | | expect(parseGateLine('workflow | ruling | TE 悬置 | pending')?.at).toBe('workflow');
1119
+ 24 | | expect(parseGateLine('t-013 | ruling | 载体指示待裁 | approved:user:decisions/019.md')?.ruling).toEqual({
1120
+ 25 | | status: 'approved',
1121
+ 26 | | decidedBy: 'user',
1122
+ 27 | | evidence: 'decisions/019.md',
1123
+ 28 | | });
1124
+ 29 | | expect(parseGateLine('t-013 | ruling | 载体指示待裁 | rejected:user')?.ruling).toEqual({
1125
+ 30 | | status: 'rejected',
1126
+ 31 | | decidedBy: 'user',
1127
+ 32 | | });
1128
+ 33 | | expect(parseGateLine('t-013 | ruling | 载体指示待裁 | approved')).toBeNull();
1129
+ 34 | | });
1130
+ 35 | | });
1131
+ 36 | |
1132
+ 37 | | describe('状态转移表执法', () => {
1133
+ 38 | | test('合法/非法转移判定', () => {
1134
+ 39 | | expect(checkStatusTransition('todo', 'doing')).toBeNull();
1135
+ 40 | | expect(checkStatusTransition('doing', 'blocked')).toBeNull();
1136
+ 41 | | expect(checkStatusTransition('done', 'todo')).toBeNull();
1137
+ 42 | | const error = checkStatusTransition('todo', 'done');
1138
+ 43 | | expect(error?.code).toBe('INVALID_TRANSITION');
1139
+ 44 | | expect(error?.message).toContain('todo → done');
1140
+ 45 | | });
1141
+ 46 | | });
1142
+ 47 | |
1143
+ 48 | | describe('视图派生(依赖门控与未决裁定)', () => {
1144
+ 49 | | /**
1145
+ 50 | | * 拓扑:a -> b(b 挂门);c 独立;workflow 级门一枚
1146
+ 51 | | */
1147
+ 52 | | const items: readonly WorkflowItem[] = [
1148
+ 53 | | { id: 'a', title: '甲', ref: 'ref:demo/a.md', status: 'todo' },
1149
+ 54 | | { id: 'b', title: '乙', ref: 'ref:demo/b.md', status: 'todo' },
1150
+ 55 | | { id: 'c', title: '丙', ref: 'task:demo/c-item', status: 'doing' },
1151
+ 56 | | ];
1152
+ 57 | | const edges: readonly WorkflowEdge[] = [{ from: 'a', to: 'b' }];
1153
+ 58 | | const gates: readonly WorkflowGate[] = [
1154
+ 59 | | { at: 'b', kind: 'ruling', note: '乙项须裁定', ruling: { status: 'pending' } },
1155
+ 60 | | { at: 'workflow', kind: 'ruling', note: '工作流级悬置', ruling: { status: 'pending' } },
1156
+ 61 | | ];
1157
+ 62 | |
1158
+ 63 | | test('依赖未满足派生阻塞;门未批不可启动;未决裁定含工作流级', () => {
1159
+ 64 | | const view = deriveWorkflowView(items, edges, gates);
1160
+ 65 | | const byId = new Map(view.items.map((entry) => [entry.id, entry]));
1161
+ 66 | |
1162
+ 67 | | expect(byId.get('a')?.canStart).toBe(true);
1163
+ 68 | | expect(byId.get('b')?.blockedOnPrerequisite).toBe(true);
1164
+ 69 | | expect(byId.get('b')?.canStart).toBe(false);
1165
+ 70 | | expect(byId.get('c')?.canStart).toBe(false);
1166
+ 71 | | expect(view.pendingRulings.map((ruling) => ruling.key)).toEqual(['b:ruling', 'workflow:ruling']);
1167
+ 72 | | });
1168
+ 73 | |
1169
+ 74 | | test('前置闭环解除阻塞;门批准解除门控;escalated 仍属未决', () => {
1170
+ 75 | | const settledItems: readonly WorkflowItem[] = [
1171
+ 76 | | { id: 'a', title: '甲', ref: 'ref:demo/a.md', status: 'done' },
1172
+ 77 | | { id: 'b', title: '乙', ref: 'ref:demo/b.md', status: 'todo' },
1173
+ 78 | | ];
1174
+ 79 | | const approvedGates: readonly WorkflowGate[] = [
1175
+ 80 | | { at: 'b', kind: 'ruling', note: '已裁', ruling: { status: 'approved', decidedBy: 'user' } },
1176
+ 81 | | { at: 'workflow', kind: 'ruling', note: '升级待裁', ruling: { status: 'escalated' } },
1177
+ 82 | | ];
1178
+ 83 | | const view = deriveWorkflowView(settledItems, edges, approvedGates);
1179
+ 84 | | const byId = new Map(view.items.map((entry) => [entry.id, entry]));
1180
+ 85 | |
1181
+ 86 | | expect(byId.get('b')?.blockedOnPrerequisite).toBe(false);
1182
+ 87 | | expect(byId.get('b')?.canStart).toBe(true);
1183
+ 88 | | expect(view.pendingRulings.map((ruling) => ruling.rulingStatus)).toEqual(['escalated']);
1184
+ 89 | | });
1185
+ 90 | `-> });
1186
+ `----
1187
+
1188
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "definition.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
1189
+ ,-[src/types/definition.ts:1:1]
1190
+ 1 | ,-> export type DefinitionDTO = {
1191
+ 2 | | id: string;
1192
+ 3 | | name: string;
1193
+ 4 | | description: string | null;
1194
+ 5 | | version: number;
1195
+ 6 | | nodes: WorkflowNodeDTO[];
1196
+ 7 | | edges: WorkflowEdgeDTO[];
1197
+ 8 | | initialState: string;
1198
+ 9 | | states: string[];
1199
+ 10 | | publishedAt: string | null;
1200
+ 11 | | createdAt: string;
1201
+ 12 | | updatedAt: string;
1202
+ 13 | | };
1203
+ 14 | |
1204
+ 15 | | export type WorkflowNodeDTO = {
1205
+ 16 | | nodeId: string;
1206
+ 17 | | name: string;
1207
+ 18 | | type: string;
1208
+ 19 | | properties: Record<string, unknown>;
1209
+ 20 | | position: { x: number; y: number };
1210
+ 21 | | };
1211
+ 22 | |
1212
+ 23 | | export type WorkflowEdgeDTO = {
1213
+ 24 | | edgeId: string;
1214
+ 25 | | sourceNodeId: string;
1215
+ 26 | | targetNodeId: string;
1216
+ 27 | | condition?: string;
1217
+ 28 | | label?: string;
1218
+ 29 | | };
1219
+ 30 | |
1220
+ 31 | | export type CreateDefinitionInput = {
1221
+ 32 | | name: string;
1222
+ 33 | | description?: string;
1223
+ 34 | | nodes: WorkflowNodeDTO[];
1224
+ 35 | | edges: WorkflowEdgeDTO[];
1225
+ 36 | | initialState: string;
1226
+ 37 | | states: string[];
1227
+ 38 | | transitions: StateTransitionDTO[];
1228
+ 39 | | };
1229
+ 40 | |
1230
+ 41 | | export type StateTransitionDTO = {
1231
+ 42 | | from: string;
1232
+ 43 | | to: string;
1233
+ 44 | | event: string;
1234
+ 45 | | guard?: string;
1235
+ 46 | | action?: string;
1236
+ 47 | | };
1237
+ 48 | |
1238
+ 49 | `-> export type UpdateDefinitionInput = Partial<CreateDefinitionInput>;
1239
+ `----
1240
+
1241
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
1242
+ ,-[src/schemas/index.ts:2:1]
1243
+ 1 | export * from './definition.schema';
1244
+ 2 | export * from './workflow-doc.schema';
1245
+ : ^
1246
+ 3 | export * from './instance.schema';
1247
+ `----
1248
+
1249
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
1250
+ ,-[src/schemas/index.ts:3:1]
1251
+ 2 | export * from './workflow-doc.schema';
1252
+ 3 | export * from './instance.schema';
1253
+ : ^
1254
+ 4 | export * from './trigger.schema';
1255
+ `----
1256
+
1257
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
1258
+ ,-[src/schemas/index.ts:4:1]
1259
+ 3 | export * from './instance.schema';
1260
+ 4 | export * from './trigger.schema';
1261
+ : ^
1262
+ 5 | export * from './monitoring.schema';
1263
+ `----
1264
+
1265
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
1266
+ ,-[src/schemas/index.ts:5:1]
1267
+ 4 | export * from './trigger.schema';
1268
+ 5 | export * from './monitoring.schema';
1269
+ : ^
1270
+ 6 | export * from './feed-event-trigger.schema';
1271
+ `----
1272
+
1273
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
1274
+ ,-[src/schemas/index.ts:6:1]
1275
+ 5 | export * from './monitoring.schema';
1276
+ 6 | export * from './feed-event-trigger.schema';
1277
+ : ^
1278
+ 7 | export * from './action-executor.schema';
1279
+ `----
1280
+
1281
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
1282
+ ,-[src/schemas/index.ts:7:1]
1283
+ 6 | export * from './feed-event-trigger.schema';
1284
+ 7 | export * from './action-executor.schema';
1285
+ : ^
1286
+ 8 | export * from './workflow-doc.schema';
1287
+ `----
1288
+
1289
+ x @longzai-intelligence-oxlint/stylistic-plugin(padding-line-between-statements): export 语句之间需要空行
1290
+ ,-[src/schemas/index.ts:8:1]
1291
+ 7 | export * from './action-executor.schema';
1292
+ 8 | export * from './workflow-doc.schema';
1293
+ : ^
1294
+ `----
1295
+
1296
+ x @longzai-intelligence-oxlint/file-naming-plugin(require-type-suffix): 文件 "api.ts" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: .utils.ts, .config.ts, .constants.ts
1297
+ ,-[src/types/api.ts:10:1]
1298
+ 9 | */
1299
+ 10 | export {};
1300
+ : ^^^^^^^^^^^
1301
+ `----
1302
+
1303
+ Found 8 warnings and 93 errors.
1304
+ Finished in 938ms on 31 files with 199 rules using 10 threads.
1305
+ error: script "lint" exited with code 1