@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.
- package/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-lint.log +1305 -0
- package/.turbo/turbo-typecheck.log +12 -0
- package/CHANGELOG.md +24 -1
- package/coverage/.lcov.info.09bb1f2a9aba2380.tmp +169 -0
- package/coverage/.lcov.info.0e095d78ac9192b0.tmp +329 -0
- package/coverage/.lcov.info.53a7ebfa7c8664ce.tmp +12 -0
- package/coverage/.lcov.info.6ea86c7cbc796fe0.tmp +12 -0
- package/coverage/.lcov.info.8f2985e5b3ad22cc.tmp +329 -0
- package/coverage/.lcov.info.a6ce2b7c3df2438b.tmp +228 -0
- package/coverage/.lcov.info.cc45f2f81aa7e02f.tmp +12 -0
- package/coverage/.lcov.info.cd0e8c028b2d5097.tmp +329 -0
- package/coverage/.lcov.info.dae76ebcf998e663.tmp +12 -0
- package/coverage/.lcov.info.e3bdb201eb5ce330.tmp +170 -0
- package/coverage/.lcov.info.e54e42fa06f69854.tmp +12 -0
- package/coverage/.lcov.info.f3e7537ac7b81e07.tmp +12 -0
- package/coverage/.lcov.info.fbb8af17757faa2d.tmp +329 -0
- package/coverage/lcov.info +208 -48
- package/dist/index.d.ts +3 -29
- package/dist/index.js +3 -3
- package/docs/overview.md +1 -1
- package/package.json +2 -1
- package/src/__tests__/unit/constants.test.ts +75 -30
- package/src/__tests__/unit/utils.test.ts +110 -38
- package/src/__tests__/work-item-rules.test.ts +18 -5
- package/src/index.ts +19 -5
- package/src/ports/action-executor.port.ts +2 -1
- package/src/ports/feed-event.port.ts +1 -1
- package/src/ports/index.ts +1 -0
- package/src/schemas/action-executor.schema.ts +2 -1
- package/src/schemas/definition.schema.ts +1 -1
- package/src/schemas/feed-event-trigger.schema.ts +1 -1
- package/src/schemas/index.ts +7 -0
- package/src/schemas/instance.schema.ts +1 -1
- package/src/schemas/monitoring.schema.ts +1 -1
- package/src/schemas/trigger.schema.ts +1 -1
- package/src/schemas/workflow-doc.schema.ts +4 -2
- package/src/types/action-executor.ts +1 -1
- package/src/types/feed-event-trigger.ts +1 -1
- package/src/types/index.ts +5 -0
- package/src/utils/dag.utils.ts +14 -93
- package/src/utils/index.ts +4 -2
- package/src/utils/work-item-rules.utils.ts +28 -7
- package/tsconfig/.cache/build.tsbuildinfo +1 -1
- package/tsconfig/.cache/node.tsbuildinfo +1 -1
- package/tsconfig/.cache/test.tsbuildinfo +1 -1
- package/tsconfig/node.json +1 -1
- package/tsconfig.json +9 -1
|
@@ -9,25 +9,31 @@ import {
|
|
|
9
9
|
NODE_EXECUTION_STATUSES,
|
|
10
10
|
NODE_TYPES,
|
|
11
11
|
TRIGGER_TYPES,
|
|
12
|
-
} from '
|
|
12
|
+
} from '@/constants/workflow';
|
|
13
13
|
|
|
14
14
|
describe('DEFAULT_PAGE_SIZE', () => {
|
|
15
15
|
it('默认分页大小为 20', () => {
|
|
16
|
-
|
|
16
|
+
/*
|
|
17
|
+
* 断言 DEFAULT_PAGE_SIZE 的导出值为 20
|
|
18
|
+
*/
|
|
17
19
|
expect(DEFAULT_PAGE_SIZE).toBe(20);
|
|
18
20
|
});
|
|
19
21
|
});
|
|
20
22
|
|
|
21
23
|
describe('MAX_PAGE_SIZE', () => {
|
|
22
24
|
it('最大分页大小为 100', () => {
|
|
23
|
-
|
|
25
|
+
/*
|
|
26
|
+
* 断言 MAX_PAGE_SIZE 的导出值为 100
|
|
27
|
+
*/
|
|
24
28
|
expect(MAX_PAGE_SIZE).toBe(100);
|
|
25
29
|
});
|
|
26
30
|
});
|
|
27
31
|
|
|
28
32
|
describe('NODE_TYPES', () => {
|
|
29
33
|
it('包含预期的节点类型', () => {
|
|
30
|
-
|
|
34
|
+
/*
|
|
35
|
+
* 列出全部预期节点类型的字面量清单
|
|
36
|
+
*/
|
|
31
37
|
const expectedTypes = [
|
|
32
38
|
'StartEvent',
|
|
33
39
|
'EndEvent',
|
|
@@ -40,90 +46,129 @@ describe('NODE_TYPES', () => {
|
|
|
40
46
|
'TimerEvent',
|
|
41
47
|
'ErrorEvent',
|
|
42
48
|
'SignalEvent',
|
|
43
|
-
];
|
|
49
|
+
] as const;
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
/*
|
|
52
|
+
* 断言 NODE_TYPES 与清单逐项一致
|
|
53
|
+
*/
|
|
46
54
|
expect(NODE_TYPES).toEqual(expectedTypes);
|
|
47
55
|
});
|
|
48
56
|
|
|
49
57
|
it('包含 StartEvent', () => {
|
|
50
|
-
|
|
58
|
+
/*
|
|
59
|
+
* 断言 NODE_TYPES 包含 StartEvent 成员
|
|
60
|
+
*/
|
|
51
61
|
expect(NODE_TYPES).toContain('StartEvent');
|
|
52
62
|
});
|
|
53
63
|
|
|
54
64
|
it('包含 EndEvent', () => {
|
|
55
|
-
|
|
65
|
+
/*
|
|
66
|
+
* 断言 NODE_TYPES 包含 EndEvent 成员
|
|
67
|
+
*/
|
|
56
68
|
expect(NODE_TYPES).toContain('EndEvent');
|
|
57
69
|
});
|
|
58
70
|
|
|
59
71
|
it('为只读数组', () => {
|
|
60
|
-
|
|
72
|
+
/*
|
|
73
|
+
* 断言 NODE_TYPES 本体是数组实例
|
|
74
|
+
*/
|
|
61
75
|
expect(Array.isArray(NODE_TYPES)).toBe(true);
|
|
62
76
|
});
|
|
63
77
|
});
|
|
64
78
|
|
|
65
79
|
describe('INSTANCE_STATUSES', () => {
|
|
66
80
|
it('包含预期的实例状态', () => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
/*
|
|
82
|
+
* 列出全部预期实例状态的字面量清单
|
|
83
|
+
*/
|
|
84
|
+
const expectedStatuses = [
|
|
85
|
+
'pending',
|
|
86
|
+
'running',
|
|
87
|
+
'paused',
|
|
88
|
+
'completed',
|
|
89
|
+
'cancelled',
|
|
90
|
+
'failed',
|
|
91
|
+
] as const;
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* 断言 INSTANCE_STATUSES 与清单逐项一致
|
|
95
|
+
*/
|
|
71
96
|
expect(INSTANCE_STATUSES).toEqual(expectedStatuses);
|
|
72
97
|
});
|
|
73
98
|
|
|
74
99
|
it('包含 pending 状态', () => {
|
|
75
|
-
|
|
100
|
+
/*
|
|
101
|
+
* 断言 INSTANCE_STATUSES 包含 pending
|
|
102
|
+
*/
|
|
76
103
|
expect(INSTANCE_STATUSES).toContain('pending');
|
|
77
104
|
});
|
|
78
105
|
|
|
79
106
|
it('包含 failed 状态', () => {
|
|
80
|
-
|
|
107
|
+
/*
|
|
108
|
+
* 断言 INSTANCE_STATUSES 包含 failed
|
|
109
|
+
*/
|
|
81
110
|
expect(INSTANCE_STATUSES).toContain('failed');
|
|
82
111
|
});
|
|
83
112
|
});
|
|
84
113
|
|
|
85
114
|
describe('NODE_EXECUTION_STATUSES', () => {
|
|
86
115
|
it('包含预期的节点执行状态', () => {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
116
|
+
/*
|
|
117
|
+
* 列出全部预期节点执行状态的字面量清单
|
|
118
|
+
*/
|
|
119
|
+
const expectedStatuses = ['pending', 'running', 'completed', 'failed', 'skipped'] as const;
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* 断言 NODE_EXECUTION_STATUSES 与清单逐项一致
|
|
123
|
+
*/
|
|
91
124
|
expect(NODE_EXECUTION_STATUSES).toEqual(expectedStatuses);
|
|
92
125
|
});
|
|
93
126
|
});
|
|
94
127
|
|
|
95
128
|
describe('TRIGGER_TYPES', () => {
|
|
96
129
|
it('包含预期的触发器类型', () => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
130
|
+
/*
|
|
131
|
+
* 列出全部预期触发器类型的字面量清单
|
|
132
|
+
*/
|
|
133
|
+
const expectedTypes = ['timer', 'webhook', 'event', 'feed.event'] as const;
|
|
134
|
+
|
|
135
|
+
/*
|
|
136
|
+
* 断言 TRIGGER_TYPES 与清单逐项一致
|
|
137
|
+
*/
|
|
101
138
|
expect(TRIGGER_TYPES).toEqual(expectedTypes);
|
|
102
139
|
});
|
|
103
140
|
});
|
|
104
141
|
|
|
105
142
|
describe('ALERT_TYPES', () => {
|
|
106
143
|
it('包含预期的告警类型', () => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
144
|
+
/*
|
|
145
|
+
* 列出全部预期告警类型的字面量清单
|
|
146
|
+
*/
|
|
147
|
+
const expectedTypes = ['timeout', 'failure_rate', 'slow_execution'] as const;
|
|
148
|
+
|
|
149
|
+
/*
|
|
150
|
+
* 断言 ALERT_TYPES 与清单逐项一致
|
|
151
|
+
*/
|
|
111
152
|
expect(ALERT_TYPES).toEqual(expectedTypes);
|
|
112
153
|
});
|
|
113
154
|
});
|
|
114
155
|
|
|
115
156
|
describe('METRIC_TYPES', () => {
|
|
116
157
|
it('包含预期的指标类型', () => {
|
|
117
|
-
|
|
158
|
+
/*
|
|
159
|
+
* 列出全部预期指标类型的字面量清单
|
|
160
|
+
*/
|
|
118
161
|
const expectedTypes = [
|
|
119
162
|
'avg_duration',
|
|
120
163
|
'success_rate',
|
|
121
164
|
'failure_rate',
|
|
122
165
|
'timeout_rate',
|
|
123
166
|
'instance_count',
|
|
124
|
-
];
|
|
167
|
+
] as const;
|
|
125
168
|
|
|
126
|
-
|
|
169
|
+
/*
|
|
170
|
+
* 断言 METRIC_TYPES 与清单逐项一致
|
|
171
|
+
*/
|
|
127
172
|
expect(METRIC_TYPES).toEqual(expectedTypes);
|
|
128
173
|
});
|
|
129
174
|
});
|
|
@@ -1,69 +1,99 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test';
|
|
2
2
|
|
|
3
|
-
import { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '
|
|
4
|
-
import { formatDate, getPagination, getTotalPages } from '
|
|
3
|
+
import { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '@/constants/workflow';
|
|
4
|
+
import { formatDate, getPagination, getTotalPages } from '@/utils/index';
|
|
5
5
|
|
|
6
6
|
describe('getPagination', () => {
|
|
7
7
|
it('默认参数返回 offset=0, limit=DEFAULT_PAGE_SIZE', () => {
|
|
8
|
-
|
|
8
|
+
/*
|
|
9
|
+
* 不传参直接调用 getPagination 取得分页结果
|
|
10
|
+
*/
|
|
9
11
|
const result = getPagination();
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
/*
|
|
14
|
+
* 断言默认偏移为 0 且条数取默认分页大小
|
|
15
|
+
*/
|
|
12
16
|
expect(result.offset).toBe(0);
|
|
13
17
|
expect(result.limit).toBe(DEFAULT_PAGE_SIZE);
|
|
14
18
|
});
|
|
15
19
|
|
|
16
20
|
it('page=2, pageSize=10 返回 offset=10, limit=10', () => {
|
|
17
|
-
|
|
21
|
+
/*
|
|
22
|
+
* 以第二页与每页十条的参数调用 getPagination
|
|
23
|
+
*/
|
|
18
24
|
const result = getPagination(2, 10);
|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
/*
|
|
27
|
+
* 断言偏移跳过第一页且条数原样返回
|
|
28
|
+
*/
|
|
21
29
|
expect(result.offset).toBe(10);
|
|
22
30
|
expect(result.limit).toBe(10);
|
|
23
31
|
});
|
|
24
32
|
|
|
25
33
|
it('pageSize 超过 MAX_PAGE_SIZE 时限制为 MAX_PAGE_SIZE', () => {
|
|
26
|
-
|
|
34
|
+
/*
|
|
35
|
+
* 构造超出 MAX_PAGE_SIZE 的每页条数
|
|
36
|
+
*/
|
|
27
37
|
const oversizedPageSize = MAX_PAGE_SIZE + 50;
|
|
28
38
|
|
|
29
|
-
|
|
39
|
+
/*
|
|
40
|
+
* 将超限条数传入 getPagination
|
|
41
|
+
*/
|
|
30
42
|
const result = getPagination(1, oversizedPageSize);
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
/*
|
|
45
|
+
* 断言条数被收口到 MAX_PAGE_SIZE
|
|
46
|
+
*/
|
|
33
47
|
expect(result.limit).toBe(MAX_PAGE_SIZE);
|
|
34
48
|
});
|
|
35
49
|
|
|
36
50
|
it('page=0 时默认为 page=1', () => {
|
|
37
|
-
|
|
51
|
+
/*
|
|
52
|
+
* 以零页码调用 getPagination
|
|
53
|
+
*/
|
|
38
54
|
const result = getPagination(0, 10);
|
|
39
55
|
|
|
40
|
-
|
|
56
|
+
/*
|
|
57
|
+
* 断言零页码被归位到首页偏移
|
|
58
|
+
*/
|
|
41
59
|
expect(result.offset).toBe(0);
|
|
42
60
|
expect(result.limit).toBe(10);
|
|
43
61
|
});
|
|
44
62
|
|
|
45
63
|
it('page 为负数时默认为 page=1', () => {
|
|
46
|
-
|
|
64
|
+
/*
|
|
65
|
+
* 以负数页码调用 getPagination
|
|
66
|
+
*/
|
|
47
67
|
const result = getPagination(-1, 10);
|
|
48
68
|
|
|
49
|
-
|
|
69
|
+
/*
|
|
70
|
+
* 断言负页码同样回落到首页偏移
|
|
71
|
+
*/
|
|
50
72
|
expect(result.offset).toBe(0);
|
|
51
73
|
});
|
|
52
74
|
|
|
53
75
|
it('仅传入 page 时 pageSize 使用默认值', () => {
|
|
54
|
-
|
|
76
|
+
/*
|
|
77
|
+
* 只传页码而省略每页条数调用 getPagination
|
|
78
|
+
*/
|
|
55
79
|
const result = getPagination(3);
|
|
56
80
|
|
|
57
|
-
|
|
81
|
+
/*
|
|
82
|
+
* 断言偏移按默认条数折算且条数取默认值
|
|
83
|
+
*/
|
|
58
84
|
expect(result.offset).toBe((3 - 1) * DEFAULT_PAGE_SIZE);
|
|
59
85
|
expect(result.limit).toBe(DEFAULT_PAGE_SIZE);
|
|
60
86
|
});
|
|
61
87
|
|
|
62
88
|
it('仅传入 pageSize 时 page 默认为 1', () => {
|
|
63
|
-
|
|
89
|
+
/*
|
|
90
|
+
* 页码缺省而只传每页条数调用 getPagination
|
|
91
|
+
*/
|
|
64
92
|
const result = getPagination(undefined, 15);
|
|
65
93
|
|
|
66
|
-
|
|
94
|
+
/*
|
|
95
|
+
* 断言首页偏移为零且条数原样保留
|
|
96
|
+
*/
|
|
67
97
|
expect(result.offset).toBe(0);
|
|
68
98
|
expect(result.limit).toBe(15);
|
|
69
99
|
});
|
|
@@ -71,86 +101,128 @@ describe('getPagination', () => {
|
|
|
71
101
|
|
|
72
102
|
describe('getTotalPages', () => {
|
|
73
103
|
it('正确计算总页数', () => {
|
|
74
|
-
|
|
104
|
+
/*
|
|
105
|
+
* 准备总数 45 与每页 10 条的输入
|
|
106
|
+
*/
|
|
75
107
|
const total = 45;
|
|
76
108
|
const pageSize = 10;
|
|
77
109
|
|
|
78
|
-
|
|
110
|
+
/*
|
|
111
|
+
* 用该输入计算总页数
|
|
112
|
+
*/
|
|
79
113
|
const result = getTotalPages(total, pageSize);
|
|
80
114
|
|
|
81
|
-
|
|
115
|
+
/*
|
|
116
|
+
* 断言有余数时向上取整为 5 页
|
|
117
|
+
*/
|
|
82
118
|
expect(result).toBe(5);
|
|
83
119
|
});
|
|
84
120
|
|
|
85
121
|
it('总数恰好整除时返回精确页数', () => {
|
|
86
|
-
|
|
122
|
+
/*
|
|
123
|
+
* 准备总数 40 与每页 10 条的整除输入
|
|
124
|
+
*/
|
|
87
125
|
const total = 40;
|
|
88
126
|
const pageSize = 10;
|
|
89
127
|
|
|
90
|
-
|
|
128
|
+
/*
|
|
129
|
+
* 用该输入计算总页数
|
|
130
|
+
*/
|
|
91
131
|
const result = getTotalPages(total, pageSize);
|
|
92
132
|
|
|
93
|
-
|
|
133
|
+
/*
|
|
134
|
+
* 断言整除时返回精确的 4 页
|
|
135
|
+
*/
|
|
94
136
|
expect(result).toBe(4);
|
|
95
137
|
});
|
|
96
138
|
|
|
97
139
|
it('总数为 0 时返回 0', () => {
|
|
98
|
-
|
|
140
|
+
/*
|
|
141
|
+
* 准备总数为 0 的空集输入
|
|
142
|
+
*/
|
|
99
143
|
const total = 0;
|
|
100
144
|
const pageSize = 10;
|
|
101
145
|
|
|
102
|
-
|
|
146
|
+
/*
|
|
147
|
+
* 用该输入计算总页数
|
|
148
|
+
*/
|
|
103
149
|
const result = getTotalPages(total, pageSize);
|
|
104
150
|
|
|
105
|
-
|
|
151
|
+
/*
|
|
152
|
+
* 断言空集时总页数为 0
|
|
153
|
+
*/
|
|
106
154
|
expect(result).toBe(0);
|
|
107
155
|
});
|
|
108
156
|
|
|
109
157
|
it('总数为 1 时返回 1', () => {
|
|
110
|
-
|
|
158
|
+
/*
|
|
159
|
+
* 准备总数为 1 的单条输入
|
|
160
|
+
*/
|
|
111
161
|
const total = 1;
|
|
112
162
|
const pageSize = 10;
|
|
113
163
|
|
|
114
|
-
|
|
164
|
+
/*
|
|
165
|
+
* 用该输入计算总页数
|
|
166
|
+
*/
|
|
115
167
|
const result = getTotalPages(total, pageSize);
|
|
116
168
|
|
|
117
|
-
|
|
169
|
+
/*
|
|
170
|
+
* 断言单条数据占 1 页
|
|
171
|
+
*/
|
|
118
172
|
expect(result).toBe(1);
|
|
119
173
|
});
|
|
120
174
|
});
|
|
121
175
|
|
|
122
176
|
describe('formatDate', () => {
|
|
123
177
|
it('将 Date 对象转换为 ISO 字符串', () => {
|
|
124
|
-
|
|
178
|
+
/*
|
|
179
|
+
* 构造固定时刻的日期对象
|
|
180
|
+
*/
|
|
125
181
|
const date = new Date('2025-01-15T10:30:00.000Z');
|
|
126
182
|
|
|
127
|
-
|
|
183
|
+
/*
|
|
184
|
+
* 将日期对象交给 formatDate 转换
|
|
185
|
+
*/
|
|
128
186
|
const result = formatDate(date);
|
|
129
187
|
|
|
130
|
-
|
|
188
|
+
/*
|
|
189
|
+
* 断言输出与输入的 ISO 表示逐字符一致
|
|
190
|
+
*/
|
|
131
191
|
expect(result).toBe('2025-01-15T10:30:00.000Z');
|
|
132
192
|
});
|
|
133
193
|
|
|
134
194
|
it('将日期字符串转换为 ISO 字符串', () => {
|
|
135
|
-
|
|
195
|
+
/*
|
|
196
|
+
* 准备纯日期字符串输入
|
|
197
|
+
*/
|
|
136
198
|
const dateStr = '2025-06-01';
|
|
137
199
|
|
|
138
|
-
|
|
200
|
+
/*
|
|
201
|
+
* 把字符串交给 formatDate 转换
|
|
202
|
+
*/
|
|
139
203
|
const result = formatDate(dateStr);
|
|
140
204
|
|
|
141
|
-
|
|
205
|
+
/*
|
|
206
|
+
* 断言输出包含原日期且类型为字符串
|
|
207
|
+
*/
|
|
142
208
|
expect(result).toContain('2025-06-01');
|
|
143
209
|
expect(typeof result).toBe('string');
|
|
144
210
|
});
|
|
145
211
|
|
|
146
212
|
it('返回值为有效的 ISO 格式', () => {
|
|
147
|
-
|
|
213
|
+
/*
|
|
214
|
+
* 取当前时刻构造日期对象
|
|
215
|
+
*/
|
|
148
216
|
const date = new Date();
|
|
149
217
|
|
|
150
|
-
|
|
218
|
+
/*
|
|
219
|
+
* 将当前日期交给 formatDate 转换
|
|
220
|
+
*/
|
|
151
221
|
const result = formatDate(date);
|
|
152
222
|
|
|
153
|
-
|
|
223
|
+
/*
|
|
224
|
+
* 断言输出经日期还原后与自身一致
|
|
225
|
+
*/
|
|
154
226
|
expect(new Date(result).toISOString()).toBe(result);
|
|
155
227
|
});
|
|
156
228
|
});
|
|
@@ -3,8 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { describe, expect, test } from 'bun:test';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
parseGateLine,
|
|
8
|
+
parseItemLine,
|
|
9
|
+
type WorkflowEdge,
|
|
10
|
+
type WorkflowGate,
|
|
11
|
+
type WorkflowItem,
|
|
12
|
+
} from '@/schemas/workflow-doc.schema';
|
|
13
|
+
import { checkStatusTransition, deriveWorkflowView } from '@/utils/work-item-rules.utils';
|
|
8
14
|
|
|
9
15
|
describe('声明方言四段制解析', () => {
|
|
10
16
|
test('工作项行:状态段执法', () => {
|
|
@@ -19,9 +25,13 @@ describe('声明方言四段制解析', () => {
|
|
|
19
25
|
});
|
|
20
26
|
|
|
21
27
|
test('裁定门行:裁定段四形态执法', () => {
|
|
22
|
-
expect(parseGateLine('t-013 | ruling | 载体指示待裁 | pending')?.ruling).toEqual({
|
|
28
|
+
expect(parseGateLine('t-013 | ruling | 载体指示待裁 | pending')?.ruling).toEqual({
|
|
29
|
+
status: 'pending',
|
|
30
|
+
});
|
|
23
31
|
expect(parseGateLine('workflow | ruling | TE 悬置 | pending')?.at).toBe('workflow');
|
|
24
|
-
expect(
|
|
32
|
+
expect(
|
|
33
|
+
parseGateLine('t-013 | ruling | 载体指示待裁 | approved:user:decisions/019.md')?.ruling,
|
|
34
|
+
).toEqual({
|
|
25
35
|
status: 'approved',
|
|
26
36
|
decidedBy: 'user',
|
|
27
37
|
evidence: 'decisions/019.md',
|
|
@@ -68,7 +78,10 @@ describe('视图派生(依赖门控与未决裁定)', () => {
|
|
|
68
78
|
expect(byId.get('b')?.blockedOnPrerequisite).toBe(true);
|
|
69
79
|
expect(byId.get('b')?.canStart).toBe(false);
|
|
70
80
|
expect(byId.get('c')?.canStart).toBe(false);
|
|
71
|
-
expect(view.pendingRulings.map((ruling) => ruling.key)).toEqual([
|
|
81
|
+
expect(view.pendingRulings.map((ruling) => ruling.key)).toEqual([
|
|
82
|
+
'b:ruling',
|
|
83
|
+
'workflow:ruling',
|
|
84
|
+
]);
|
|
72
85
|
});
|
|
73
86
|
|
|
74
87
|
test('前置闭环解除阻塞;门批准解除门控;escalated 仍属未决', () => {
|
package/src/index.ts
CHANGED
|
@@ -4,13 +4,27 @@
|
|
|
4
4
|
* 提供共享基础类型、Schema、常量和工具函数。
|
|
5
5
|
* 不依赖任何 domain 包。
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
/*
|
|
8
|
+
* 类型导出
|
|
9
|
+
*/
|
|
8
10
|
export * from './types/index';
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* 常量导出
|
|
14
|
+
*/
|
|
10
15
|
export * from './constants/index';
|
|
11
|
-
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* 工具函数导出
|
|
19
|
+
*/
|
|
12
20
|
export * from './utils/index';
|
|
13
|
-
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* zod schema 导出
|
|
24
|
+
*/
|
|
14
25
|
export * from './schemas/index';
|
|
15
|
-
|
|
26
|
+
|
|
27
|
+
/*
|
|
28
|
+
* 端口契约导出(C1 合规,零框架依赖)
|
|
29
|
+
*/
|
|
16
30
|
export * from './ports/index';
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* 当工作流执行到 action 节点时,根据 action.type 调用对应 handler。
|
|
7
7
|
*
|
|
8
8
|
* 支持的 action 类型:
|
|
9
|
+
*
|
|
9
10
|
* - feed.applyTags:调用 feed F-2 applyTags(Phase 2)
|
|
10
11
|
* - feed.summarize:调用 feed F-3 summarize(Phase 2)
|
|
11
12
|
* - llm.complete:调用 agent LlmCompletePort
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
* C1 合规:本端口为零框架依赖的纯类型契约,由具体适配器层提供实现。
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
|
-
import type { Action, ActionContext, ActionResult, ActionType } from '
|
|
20
|
+
import type { Action, ActionContext, ActionResult, ActionType } from '@/types';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* 单个 action handler 函数签名
|
package/src/ports/index.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* 供 execution 子插件注册 action handler 时使用。
|
|
6
6
|
*
|
|
7
7
|
* 支持的 action 类型:
|
|
8
|
+
*
|
|
8
9
|
* - feed.applyTags:调用 feed F-2 applyTags,为条目打标签
|
|
9
10
|
* - feed.summarize:调用 feed F-3 summarize,生成摘要
|
|
10
11
|
* - llm.complete:调用 agent LlmCompletePort,完成文本
|
|
@@ -15,7 +16,7 @@
|
|
|
15
16
|
|
|
16
17
|
import { z } from 'zod';
|
|
17
18
|
|
|
18
|
-
import { ACTION_TYPES } from '
|
|
19
|
+
import { ACTION_TYPES } from '@/constants/workflow';
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* action 类型 Schema
|
package/src/schemas/index.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
export * from './definition.schema';
|
|
2
|
+
|
|
2
3
|
export * from './workflow-doc.schema';
|
|
4
|
+
|
|
3
5
|
export * from './instance.schema';
|
|
6
|
+
|
|
4
7
|
export * from './trigger.schema';
|
|
8
|
+
|
|
5
9
|
export * from './monitoring.schema';
|
|
10
|
+
|
|
6
11
|
export * from './feed-event-trigger.schema';
|
|
12
|
+
|
|
7
13
|
export * from './action-executor.schema';
|
|
14
|
+
|
|
8
15
|
export * from './workflow-doc.schema';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
-
import { INSTANCE_STATUSES, NODE_EXECUTION_STATUSES } from '
|
|
3
|
+
import { INSTANCE_STATUSES, NODE_EXECUTION_STATUSES } from '@/constants/workflow';
|
|
4
4
|
|
|
5
5
|
export const instanceStatusDtoSchema = z.enum(INSTANCE_STATUSES);
|
|
6
6
|
|
|
@@ -26,7 +26,8 @@ const KEBAB_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
|
26
26
|
/**
|
|
27
27
|
* 工作项指针备选:`task:<仓>/<slug>`(task 台账引用)或 `ref:<仓>/<仓内路径>`
|
|
28
28
|
*/
|
|
29
|
-
const ITEM_REF_ALTERNATION =
|
|
29
|
+
const ITEM_REF_ALTERNATION =
|
|
30
|
+
'task:[a-z0-9][a-z0-9-]*\\/[a-z0-9\\/-]+|ref:[a-z0-9][a-z0-9-]*\\/[a-z0-9\\/. _-]+';
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* 工作项行:`<itemId> | <标题> | <指针> | <状态>`(四段制)
|
|
@@ -362,4 +363,5 @@ export function parseGateLine(line: string): WorkflowGate | null {
|
|
|
362
363
|
/**
|
|
363
364
|
* 家族引用(条目档 frontmatter 的 ref 字段值)
|
|
364
365
|
*/
|
|
365
|
-
export const WORKFLOW_REF_PATTERN =
|
|
366
|
+
export const WORKFLOW_REF_PATTERN =
|
|
367
|
+
/^workflow:(global|[a-z0-9][a-z0-9-]*)\/([a-z0-9]+(?:-[a-z0-9]+)*)$/;
|