agent-gear 2.1.1 → 2.3.0
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/AGENTS.md +16 -2
- package/dist/socketio-client.d.ts.map +1 -1
- package/dist/socketio-client.js +35 -5
- package/dist/socketio-client.js.map +1 -1
- package/dist/workload-executor.d.ts +85 -0
- package/dist/workload-executor.d.ts.map +1 -0
- package/dist/workload-executor.js +327 -0
- package/dist/workload-executor.js.map +1 -0
- package/dist/workload-executor.test.d.ts +2 -0
- package/dist/workload-executor.test.d.ts.map +1 -0
- package/dist/workload-executor.test.js +328 -0
- package/dist/workload-executor.test.js.map +1 -0
- package/package.json +1 -1
- package/src/socketio-client.ts +36 -6
- package/src/workload-executor.test.ts +441 -0
- package/src/workload-executor.ts +393 -0
- package/tests/socketio-client.test.ts +2 -2
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtemp, mkdir, rm, access } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
5
|
+
import { WorkloadExecutor, MAX_OUTPUT_BYTES, MAX_PENDING_RESULTS, EMPTY_SCRIPT_MESSAGE, } from './workload-executor.js';
|
|
6
|
+
const TMP_BASE = '/tmp/opencode';
|
|
7
|
+
function collect() {
|
|
8
|
+
const results = [];
|
|
9
|
+
return { results, sink: (result) => results.push(result) };
|
|
10
|
+
}
|
|
11
|
+
async function makeTmpDir() {
|
|
12
|
+
await mkdir(TMP_BASE, { recursive: true });
|
|
13
|
+
return mkdtemp(join(TMP_BASE, 'we-'));
|
|
14
|
+
}
|
|
15
|
+
async function fileExists(path) {
|
|
16
|
+
try {
|
|
17
|
+
await access(path);
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
describe('WorkloadExecutor', () => {
|
|
25
|
+
const dirs = [];
|
|
26
|
+
afterEach(async () => {
|
|
27
|
+
await Promise.all(dirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
|
|
28
|
+
});
|
|
29
|
+
it('T-WE1 runs items serially, merges stdout+stderr and reports success in item order', async () => {
|
|
30
|
+
const executor = new WorkloadExecutor();
|
|
31
|
+
const { results, sink } = collect();
|
|
32
|
+
await executor.runBatch({
|
|
33
|
+
phase: 'init',
|
|
34
|
+
items: [
|
|
35
|
+
{ logId: 'a', workloadName: 'A', script: 'echo out-a; echo err-a >&2', timeoutMs: 5000 },
|
|
36
|
+
{ logId: 'b', workloadName: 'B', script: 'echo out-b', timeoutMs: 5000 },
|
|
37
|
+
],
|
|
38
|
+
}, sink);
|
|
39
|
+
expect(results.map((r) => r.logId)).toEqual(['a', 'b']);
|
|
40
|
+
expect(results[0]).toMatchObject({ status: 'success', exitCode: 0 });
|
|
41
|
+
expect(results[0].log).toContain('out-a');
|
|
42
|
+
expect(results[0].log).toContain('err-a');
|
|
43
|
+
expect(results[1]).toMatchObject({ status: 'success', exitCode: 0 });
|
|
44
|
+
expect(results[1].log).toContain('out-b');
|
|
45
|
+
expect(results[0].startedAt).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
|
46
|
+
expect(results[0].finishedAt).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
|
47
|
+
});
|
|
48
|
+
it('T-WE2 reports failed with exitCode on non-zero exit and continues the batch', async () => {
|
|
49
|
+
const executor = new WorkloadExecutor();
|
|
50
|
+
const { results, sink } = collect();
|
|
51
|
+
await executor.runBatch({
|
|
52
|
+
phase: 'init',
|
|
53
|
+
items: [
|
|
54
|
+
{ logId: 'fail', workloadName: 'F', script: 'echo boom >&2; exit 3', timeoutMs: 5000 },
|
|
55
|
+
{ logId: 'ok', workloadName: 'O', script: 'echo ok', timeoutMs: 5000 },
|
|
56
|
+
],
|
|
57
|
+
}, sink);
|
|
58
|
+
expect(results[0]).toMatchObject({ logId: 'fail', status: 'failed', exitCode: 3 });
|
|
59
|
+
expect(results[0].log).toContain('boom');
|
|
60
|
+
expect(results[1]).toMatchObject({ logId: 'ok', status: 'success' });
|
|
61
|
+
});
|
|
62
|
+
it('T-WE3 kills the whole process group on per-item timeout and continues', async () => {
|
|
63
|
+
const dir = await makeTmpDir();
|
|
64
|
+
dirs.push(dir);
|
|
65
|
+
const marker = join(dir, 'leaked.txt');
|
|
66
|
+
const executor = new WorkloadExecutor();
|
|
67
|
+
const { results, sink } = collect();
|
|
68
|
+
const started = Date.now();
|
|
69
|
+
await executor.runBatch({
|
|
70
|
+
phase: 'init',
|
|
71
|
+
items: [
|
|
72
|
+
{ logId: 'slow', workloadName: 'S', script: `( sleep 1.5; echo leaked > ${marker} ) & sleep 30`, timeoutMs: 300 },
|
|
73
|
+
{ logId: 'next', workloadName: 'N', script: 'echo next', timeoutMs: 5000 },
|
|
74
|
+
],
|
|
75
|
+
}, sink);
|
|
76
|
+
const elapsed = Date.now() - started;
|
|
77
|
+
expect(elapsed).toBeLessThan(5000);
|
|
78
|
+
expect(results[0]).toMatchObject({ logId: 'slow', status: 'timeout', exitCode: null });
|
|
79
|
+
expect(results[1]).toMatchObject({ logId: 'next', status: 'success' });
|
|
80
|
+
// the backgrounded child would write the marker at 1.5s if the group was not killed
|
|
81
|
+
await delay(2000);
|
|
82
|
+
expect(await fileExists(marker)).toBe(false);
|
|
83
|
+
}, 15000);
|
|
84
|
+
it('T-WE4 truncates oversized output keeping the tail <= 256 KiB', async () => {
|
|
85
|
+
const executor = new WorkloadExecutor();
|
|
86
|
+
const { results, sink } = collect();
|
|
87
|
+
await executor.runBatch({
|
|
88
|
+
phase: 'init',
|
|
89
|
+
items: [{ logId: 'big', workloadName: 'Big', script: "yes A | head -c 300000; printf 'ENDMARK'", timeoutMs: 10000 }],
|
|
90
|
+
}, sink);
|
|
91
|
+
expect(results).toHaveLength(1);
|
|
92
|
+
expect(results[0].status).toBe('success');
|
|
93
|
+
expect(Buffer.byteLength(results[0].log, 'utf8')).toBeLessThanOrEqual(MAX_OUTPUT_BYTES);
|
|
94
|
+
expect(results[0].log.endsWith('ENDMARK')).toBe(true);
|
|
95
|
+
}, 15000);
|
|
96
|
+
it('T-WE4b: skips a leading split UTF-8 continuation byte when truncating the tail', async () => {
|
|
97
|
+
const executor = new WorkloadExecutor();
|
|
98
|
+
const { results, sink } = collect();
|
|
99
|
+
// 总长 262145 字节(3 字节「中」+ 262142 个 A),尾部保留 262144 字节 => 起点落在
|
|
100
|
+
// 「中」的第 2 个字节(续字节)上;截断后必须跳过续字节到字符边界,首字符不得是乱码。
|
|
101
|
+
await executor.runBatch({
|
|
102
|
+
phase: 'init',
|
|
103
|
+
items: [
|
|
104
|
+
{
|
|
105
|
+
logId: 'utf8',
|
|
106
|
+
workloadName: 'Utf8',
|
|
107
|
+
script: "printf '中'; head -c 262142 /dev/zero | tr '\\0' 'A'",
|
|
108
|
+
timeoutMs: 10000,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
}, sink);
|
|
112
|
+
expect(results).toHaveLength(1);
|
|
113
|
+
const log = results[0].log;
|
|
114
|
+
expect(log.includes('\uFFFD')).toBe(false);
|
|
115
|
+
expect(log).toBe('A'.repeat(262142));
|
|
116
|
+
expect(Buffer.byteLength(log, 'utf8')).toBeLessThanOrEqual(MAX_OUTPUT_BYTES);
|
|
117
|
+
}, 15000);
|
|
118
|
+
it('T-WE5 shares the post budget and reports timeout without starting later items', async () => {
|
|
119
|
+
const executor = new WorkloadExecutor();
|
|
120
|
+
const { results, sink } = collect();
|
|
121
|
+
const started = Date.now();
|
|
122
|
+
await executor.runBatch({
|
|
123
|
+
phase: 'post',
|
|
124
|
+
budgetMs: 300,
|
|
125
|
+
items: [
|
|
126
|
+
{ logId: 'p1', workloadName: 'P1', script: 'sleep 2', timeoutMs: 10000 },
|
|
127
|
+
{ logId: 'p2', workloadName: 'P2', script: 'echo should-not-run', timeoutMs: 10000 },
|
|
128
|
+
],
|
|
129
|
+
}, sink);
|
|
130
|
+
const elapsed = Date.now() - started;
|
|
131
|
+
expect(elapsed).toBeLessThan(5000);
|
|
132
|
+
expect(results.map((r) => r.logId)).toEqual(['p1', 'p2']);
|
|
133
|
+
expect(results[0]).toMatchObject({ status: 'timeout', exitCode: null });
|
|
134
|
+
expect(results[1]).toMatchObject({ status: 'timeout', exitCode: null });
|
|
135
|
+
expect(results[1].log).not.toContain('should-not-run');
|
|
136
|
+
}, 15000);
|
|
137
|
+
it('T-WE6 buffers unconfirmed results and replays then clears on reconnect', async () => {
|
|
138
|
+
const executor = new WorkloadExecutor();
|
|
139
|
+
await executor.runBatch({
|
|
140
|
+
phase: 'init',
|
|
141
|
+
items: [
|
|
142
|
+
{ logId: 'r1', workloadName: 'R1', script: 'echo one', timeoutMs: 5000 },
|
|
143
|
+
{ logId: 'r2', workloadName: 'R2', script: 'echo two', timeoutMs: 5000 },
|
|
144
|
+
],
|
|
145
|
+
}, () => { });
|
|
146
|
+
expect(executor.getPendingResults().map((r) => r.logId)).toEqual(['r1', 'r2']);
|
|
147
|
+
const replayed = [];
|
|
148
|
+
executor.replayPendingResults((result) => replayed.push(result));
|
|
149
|
+
expect(replayed.map((r) => r.logId)).toEqual(['r1', 'r2']);
|
|
150
|
+
expect(executor.getPendingResults()).toHaveLength(0);
|
|
151
|
+
});
|
|
152
|
+
it('T-WE6b caps the replay buffer at 50 results', async () => {
|
|
153
|
+
const executor = new WorkloadExecutor();
|
|
154
|
+
const items = Array.from({ length: MAX_PENDING_RESULTS + 5 }, (_, i) => ({
|
|
155
|
+
logId: `x${i}`,
|
|
156
|
+
workloadName: `X${i}`,
|
|
157
|
+
script: ':',
|
|
158
|
+
timeoutMs: 5000,
|
|
159
|
+
}));
|
|
160
|
+
await executor.runBatch({ phase: 'init', items }, () => { });
|
|
161
|
+
const pending = executor.getPendingResults();
|
|
162
|
+
expect(pending).toHaveLength(MAX_PENDING_RESULTS);
|
|
163
|
+
expect(pending[pending.length - 1].logId).toBe(`x${MAX_PENDING_RESULTS + 4}`);
|
|
164
|
+
}, 30000);
|
|
165
|
+
it('T-WE7 terminates the running init batch when a new post batch arrives', async () => {
|
|
166
|
+
const dir = await makeTmpDir();
|
|
167
|
+
dirs.push(dir);
|
|
168
|
+
const startedFile = join(dir, 'init-started');
|
|
169
|
+
const executor = new WorkloadExecutor();
|
|
170
|
+
const initResults = [];
|
|
171
|
+
const initBatch = executor.runBatch({
|
|
172
|
+
phase: 'init',
|
|
173
|
+
items: [{ logId: 'init-1', workloadName: 'Init', script: `touch ${startedFile}; sleep 30`, timeoutMs: 60000 }],
|
|
174
|
+
}, (result) => initResults.push(result));
|
|
175
|
+
// wait until the init child process has actually started
|
|
176
|
+
const deadline = Date.now() + 5000;
|
|
177
|
+
let startedFlag = false;
|
|
178
|
+
while (Date.now() < deadline) {
|
|
179
|
+
if (await fileExists(startedFile)) {
|
|
180
|
+
startedFlag = true;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
await delay(25);
|
|
184
|
+
}
|
|
185
|
+
expect(startedFlag).toBe(true);
|
|
186
|
+
const postResults = [];
|
|
187
|
+
await executor.runBatch({ phase: 'post', items: [{ logId: 'post-1', workloadName: 'Post', script: 'echo post-ok', timeoutMs: 5000 }] }, (result) => postResults.push(result));
|
|
188
|
+
await initBatch;
|
|
189
|
+
expect(postResults.map((r) => r.logId)).toEqual(['post-1']);
|
|
190
|
+
expect(postResults[0].status).toBe('success');
|
|
191
|
+
// the interrupted init item is not reported; the server marks it TIMEOUT
|
|
192
|
+
expect(initResults).toHaveLength(0);
|
|
193
|
+
}, 20000);
|
|
194
|
+
it('T-WE8 reports failed for an empty script and does nothing for empty items', async () => {
|
|
195
|
+
const executor = new WorkloadExecutor();
|
|
196
|
+
const { results, sink } = collect();
|
|
197
|
+
await executor.runBatch({ phase: 'init', items: [{ logId: 'empty', workloadName: 'Empty', script: ' ', timeoutMs: 5000 }] }, sink);
|
|
198
|
+
expect(results).toHaveLength(1);
|
|
199
|
+
expect(results[0]).toMatchObject({ logId: 'empty', status: 'failed', exitCode: null, log: EMPTY_SCRIPT_MESSAGE });
|
|
200
|
+
const empty = collect();
|
|
201
|
+
await executor.runBatch({ phase: 'init', items: [] }, empty.sink);
|
|
202
|
+
expect(empty.results).toHaveLength(0);
|
|
203
|
+
});
|
|
204
|
+
it('T-WE10 injects TEXT/BOOLEAN params as WORKLOAD_PARAM_* and the full JSON as WORKLOAD_PARAMS', async () => {
|
|
205
|
+
const executor = new WorkloadExecutor();
|
|
206
|
+
const { results, sink } = collect();
|
|
207
|
+
await executor.runBatch({
|
|
208
|
+
phase: 'init',
|
|
209
|
+
items: [
|
|
210
|
+
{
|
|
211
|
+
logId: 'params',
|
|
212
|
+
workloadName: 'Params',
|
|
213
|
+
script: `printf 'P=%s\\n' "$WORKLOAD_PARAMS"; printf 'V=%s\\n' "$WORKLOAD_PARAM_VERSION"; printf 'D=%s\\n' "$WORKLOAD_PARAM_DEBUG"; printf 'E=%s\\n' "$WORKLOAD_PARAM_ENABLED"`,
|
|
214
|
+
timeoutMs: 5000,
|
|
215
|
+
workloadId: 'w-text',
|
|
216
|
+
params: { version: '22', debug: true, enabled: false },
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
}, sink);
|
|
220
|
+
expect(results).toHaveLength(1);
|
|
221
|
+
expect(results[0].status).toBe('success');
|
|
222
|
+
expect(results[0].log).toContain('P={"version":"22","debug":true,"enabled":false}');
|
|
223
|
+
expect(results[0].log).toContain('V=22');
|
|
224
|
+
expect(results[0].log).toContain('D=true');
|
|
225
|
+
expect(results[0].log).toContain('E=false');
|
|
226
|
+
});
|
|
227
|
+
it('T-WE11 injects MULTI_SELECT params as a JSON array string that scripts can parse', async () => {
|
|
228
|
+
const executor = new WorkloadExecutor();
|
|
229
|
+
const { results, sink } = collect();
|
|
230
|
+
await executor.runBatch({
|
|
231
|
+
phase: 'init',
|
|
232
|
+
items: [
|
|
233
|
+
{
|
|
234
|
+
logId: 'multi',
|
|
235
|
+
workloadName: 'Multi',
|
|
236
|
+
script: `printf 'PM=%s\\n' "$WORKLOAD_PARAM_PACKAGE_MANAGER"; node -e 'const v = JSON.parse(process.argv[1] || "[]"); process.stdout.write("parsed=" + v.join(","))' "$WORKLOAD_PARAM_PACKAGE_MANAGER"`,
|
|
237
|
+
timeoutMs: 10000,
|
|
238
|
+
workloadId: 'w-multi',
|
|
239
|
+
params: { package_manager: ['pnpm', 'bun'] },
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
}, sink);
|
|
243
|
+
expect(results).toHaveLength(1);
|
|
244
|
+
expect(results[0].status).toBe('success');
|
|
245
|
+
expect(results[0].log).toContain('PM=["pnpm","bun"]');
|
|
246
|
+
expect(results[0].log).toContain('parsed=pnpm,bun');
|
|
247
|
+
}, 15000);
|
|
248
|
+
it('T-WE12 keeps legacy behavior for empty params (only WORKLOAD_PARAMS={}, host env inherited)', async () => {
|
|
249
|
+
const executor = new WorkloadExecutor();
|
|
250
|
+
const { results, sink } = collect();
|
|
251
|
+
process.env.ZAG_WORKLOAD_TEST_INHERITED = 'inherited';
|
|
252
|
+
try {
|
|
253
|
+
await executor.runBatch({
|
|
254
|
+
phase: 'init',
|
|
255
|
+
items: [
|
|
256
|
+
{
|
|
257
|
+
logId: 'empty-params',
|
|
258
|
+
workloadName: 'EmptyParams',
|
|
259
|
+
script: `printf 'P=%s\\n' "$WORKLOAD_PARAMS"; printf 'FOO=%s\\n' "\${WORKLOAD_PARAM_FOO-unset}"; printf 'INHERIT=%s\\n' "\${ZAG_WORKLOAD_TEST_INHERITED-unset}"`,
|
|
260
|
+
timeoutMs: 5000,
|
|
261
|
+
workloadId: 'w-empty',
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
}, sink);
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
delete process.env.ZAG_WORKLOAD_TEST_INHERITED;
|
|
268
|
+
}
|
|
269
|
+
expect(results).toHaveLength(1);
|
|
270
|
+
expect(results[0].status).toBe('success');
|
|
271
|
+
expect(results[0].log).toContain('P={}');
|
|
272
|
+
expect(results[0].log).toContain('FOO=unset');
|
|
273
|
+
expect(results[0].log).toContain('INHERIT=inherited');
|
|
274
|
+
});
|
|
275
|
+
it('T-WE13 scopes params to the current item and does not leak them to later items', async () => {
|
|
276
|
+
const executor = new WorkloadExecutor();
|
|
277
|
+
const { results, sink } = collect();
|
|
278
|
+
await executor.runBatch({
|
|
279
|
+
phase: 'init',
|
|
280
|
+
items: [
|
|
281
|
+
{
|
|
282
|
+
logId: 'first',
|
|
283
|
+
workloadName: 'First',
|
|
284
|
+
script: `printf 'P=%s\\n' "$WORKLOAD_PARAMS"`,
|
|
285
|
+
timeoutMs: 5000,
|
|
286
|
+
workloadId: 'w-first',
|
|
287
|
+
params: { version: '22', package_manager: ['pnpm'] },
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
logId: 'second',
|
|
291
|
+
workloadName: 'Second',
|
|
292
|
+
script: `printf 'P=%s\\n' "$WORKLOAD_PARAMS"; printf 'V=%s\\n' "\${WORKLOAD_PARAM_VERSION-unset}"; printf 'PM=%s\\n' "\${WORKLOAD_PARAM_PACKAGE_MANAGER-unset}"`,
|
|
293
|
+
timeoutMs: 5000,
|
|
294
|
+
workloadId: 'w-second',
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
}, sink);
|
|
298
|
+
expect(results.map((r) => r.logId)).toEqual(['first', 'second']);
|
|
299
|
+
expect(results[0].log).toContain('P={"version":"22","package_manager":["pnpm"]}');
|
|
300
|
+
expect(results[1].log).toContain('P={}');
|
|
301
|
+
expect(results[1].log).toContain('V=unset');
|
|
302
|
+
expect(results[1].log).toContain('PM=unset');
|
|
303
|
+
});
|
|
304
|
+
it('T-WE14 treats workloadId as log-only: order and result shape are unchanged', async () => {
|
|
305
|
+
const executor = new WorkloadExecutor();
|
|
306
|
+
const { results, sink } = collect();
|
|
307
|
+
await executor.runBatch({
|
|
308
|
+
phase: 'init',
|
|
309
|
+
items: [
|
|
310
|
+
{ logId: 'one', workloadName: 'One', workloadId: 'w-1', script: 'echo one', timeoutMs: 5000, params: { a: 'x' } },
|
|
311
|
+
{ logId: 'two', workloadName: 'Two', workloadId: 'w-2', script: 'echo two', timeoutMs: 5000 },
|
|
312
|
+
],
|
|
313
|
+
}, sink);
|
|
314
|
+
expect(results.map((r) => r.logId)).toEqual(['one', 'two']);
|
|
315
|
+
expect(results.map((r) => r.status)).toEqual(['success', 'success']);
|
|
316
|
+
expect(Object.keys(results[0]).sort()).toEqual(['exitCode', 'finishedAt', 'log', 'logId', 'startedAt', 'status'].sort());
|
|
317
|
+
});
|
|
318
|
+
it('T-WE9 exposes running state and waitForIdle resolves after the batch completes', async () => {
|
|
319
|
+
const executor = new WorkloadExecutor();
|
|
320
|
+
expect(executor.isRunning()).toBe(false);
|
|
321
|
+
const batch = executor.runBatch({ phase: 'post', items: [{ logId: 'w', workloadName: 'W', script: 'sleep 0.4', timeoutMs: 5000 }] }, () => { });
|
|
322
|
+
expect(executor.isRunning()).toBe(true);
|
|
323
|
+
await executor.waitForIdle(2000);
|
|
324
|
+
expect(executor.isRunning()).toBe(false);
|
|
325
|
+
await batch;
|
|
326
|
+
}, 10000);
|
|
327
|
+
});
|
|
328
|
+
//# sourceMappingURL=workload-executor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workload-executor.test.js","sourceRoot":"","sources":["../src/workload-executor.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/socketio-client.ts
CHANGED
|
@@ -18,8 +18,14 @@ import { gatewayManager } from './gateway.js';
|
|
|
18
18
|
import { processRegistry, isProcessAlive } from './acp/process-registry.js';
|
|
19
19
|
import { McpRelay } from './mcp/relay.js';
|
|
20
20
|
import { LocalMcpServer } from './mcp/local-server.js';
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
import { WorkloadExecutor, type WorkloadRunPayload } from './workload-executor.js';
|
|
22
|
+
|
|
23
|
+
// 与 package.json 版本保持一致(register 上报的完整版本;服务端按 MIN_WORKER_VERSION=2.2.0 门禁)。
|
|
24
|
+
const CONTROLLER_VERSION = '2.3.0';
|
|
25
|
+
// 进程内全局单实例:工作负载批次严格串行(新批次打断旧批次,见 workload-executor)。
|
|
26
|
+
const workloadExecutor = new WorkloadExecutor();
|
|
27
|
+
// shutdown 到达时若仍有 post 批次在跑,最多等待该时长后退出(契约 §2.8)。
|
|
28
|
+
const SHUTDOWN_WORKLOAD_WAIT_MS = 5000;
|
|
23
29
|
const acpBridges = new Map<string, AcpSessionBridge>();
|
|
24
30
|
const permissionRequestBridge = new Map<string, AcpSessionBridge>();
|
|
25
31
|
const elicitationRequestBridge = new Map<string, AcpSessionBridge>();
|
|
@@ -330,6 +336,8 @@ export function connectToServer(
|
|
|
330
336
|
homeDir: homedir(),
|
|
331
337
|
platform: platform(),
|
|
332
338
|
});
|
|
339
|
+
// 重连重放:将未确认的工作负载执行结果重新上报;服务端按终态幂等忽略(契约 §2.9)。
|
|
340
|
+
workloadExecutor.replayPendingResults((result) => socket.emit('workload:result', result));
|
|
333
341
|
});
|
|
334
342
|
|
|
335
343
|
socket.on('registered', (data: RegisteredPayload) => {
|
|
@@ -371,10 +379,32 @@ export function connectToServer(
|
|
|
371
379
|
|
|
372
380
|
socket.on('shutdown', (data: ShutdownPayload) => {
|
|
373
381
|
console.log(`Shutdown requested: ${data.reason}`);
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
382
|
+
const finishShutdown = (): void => {
|
|
383
|
+
heartbeat.stop();
|
|
384
|
+
clearConfigKey();
|
|
385
|
+
socket.close();
|
|
386
|
+
process.exit(0);
|
|
387
|
+
};
|
|
388
|
+
// post 批次仍在执行时,等待其结束(≤5s)后再退出,避免清理脚本被中途打断。
|
|
389
|
+
// 无批次在跑时保持同步退出,行为与现状完全一致。
|
|
390
|
+
if (workloadExecutor.isRunning()) {
|
|
391
|
+
workloadExecutor.waitForIdle(SHUTDOWN_WORKLOAD_WAIT_MS).then(finishShutdown);
|
|
392
|
+
} else {
|
|
393
|
+
finishShutdown();
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Workload events
|
|
398
|
+
socket.on('workload:run', (data: WorkloadRunPayload) => {
|
|
399
|
+
if (!data || !Array.isArray(data.items)) {
|
|
400
|
+
console.warn(`[Workload] workload:run ignored: invalid payload ${JSON.stringify(data)}`);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const budget = typeof data.budgetMs === 'number' ? ` budgetMs=${data.budgetMs}` : '';
|
|
404
|
+
console.log(`[Workload] workload:run received: phase=${data.phase} items=${data.items.length}${budget}`);
|
|
405
|
+
workloadExecutor.runBatch(data, (result) => socket.emit('workload:result', result)).catch((error: Error) => {
|
|
406
|
+
console.error(`[Workload] batch execution failed: ${error.message}`);
|
|
407
|
+
});
|
|
378
408
|
});
|
|
379
409
|
|
|
380
410
|
// ACP events
|