agent-gear 2.3.0 → 2.5.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 +74 -3
- package/dist/cloud-host/supervisor.d.ts +92 -0
- package/dist/cloud-host/supervisor.d.ts.map +1 -0
- package/dist/cloud-host/supervisor.js +216 -0
- package/dist/cloud-host/supervisor.js.map +1 -0
- package/dist/cloud-host/supervisor.test.d.ts +2 -0
- package/dist/cloud-host/supervisor.test.d.ts.map +1 -0
- package/dist/cloud-host/supervisor.test.js +296 -0
- package/dist/cloud-host/supervisor.test.js.map +1 -0
- package/dist/commands/harness.d.ts +17 -0
- package/dist/commands/harness.d.ts.map +1 -0
- package/dist/commands/harness.js +35 -0
- package/dist/commands/harness.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -3
- package/dist/config.js.map +1 -1
- package/dist/harness/env.d.ts +36 -0
- package/dist/harness/env.d.ts.map +1 -0
- package/dist/harness/env.js +78 -0
- package/dist/harness/env.js.map +1 -0
- package/dist/harness/env.test.d.ts +2 -0
- package/dist/harness/env.test.d.ts.map +1 -0
- package/dist/harness/env.test.js +70 -0
- package/dist/harness/env.test.js.map +1 -0
- package/dist/harness/opencode-cli.d.ts +24 -0
- package/dist/harness/opencode-cli.d.ts.map +1 -0
- package/dist/harness/opencode-cli.js +74 -0
- package/dist/harness/opencode-cli.js.map +1 -0
- package/dist/harness/opencode-cli.test.d.ts +2 -0
- package/dist/harness/opencode-cli.test.d.ts.map +1 -0
- package/dist/harness/opencode-cli.test.js +62 -0
- package/dist/harness/opencode-cli.test.js.map +1 -0
- package/dist/harness/opencode-config.atomic-failure.test.d.ts +2 -0
- package/dist/harness/opencode-config.atomic-failure.test.d.ts.map +1 -0
- package/dist/harness/opencode-config.atomic-failure.test.js +35 -0
- package/dist/harness/opencode-config.atomic-failure.test.js.map +1 -0
- package/dist/harness/opencode-config.d.ts +54 -0
- package/dist/harness/opencode-config.d.ts.map +1 -0
- package/dist/harness/opencode-config.js +130 -0
- package/dist/harness/opencode-config.js.map +1 -0
- package/dist/harness/opencode-config.test.d.ts +2 -0
- package/dist/harness/opencode-config.test.d.ts.map +1 -0
- package/dist/harness/opencode-config.test.js +183 -0
- package/dist/harness/opencode-config.test.js.map +1 -0
- package/dist/harness/prepare.d.ts +34 -0
- package/dist/harness/prepare.d.ts.map +1 -0
- package/dist/harness/prepare.js +46 -0
- package/dist/harness/prepare.js.map +1 -0
- package/dist/harness/prepare.test.d.ts +2 -0
- package/dist/harness/prepare.test.d.ts.map +1 -0
- package/dist/harness/prepare.test.js +96 -0
- package/dist/harness/prepare.test.js.map +1 -0
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js +2 -0
- package/dist/heartbeat.js.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/socketio-client.d.ts +62 -3
- package/dist/socketio-client.d.ts.map +1 -1
- package/dist/socketio-client.js +155 -16
- package/dist/socketio-client.js.map +1 -1
- package/dist/socketio-client.test.d.ts +2 -0
- package/dist/socketio-client.test.d.ts.map +1 -0
- package/dist/socketio-client.test.js +132 -0
- package/dist/socketio-client.test.js.map +1 -0
- package/dist/workload-executor.d.ts +31 -2
- package/dist/workload-executor.d.ts.map +1 -1
- package/dist/workload-executor.js +89 -16
- package/dist/workload-executor.js.map +1 -1
- package/dist/workload-executor.test.js +180 -1
- package/dist/workload-executor.test.js.map +1 -1
- package/package.json +2 -1
- package/src/cloud-host/supervisor.test.ts +367 -0
- package/src/cloud-host/supervisor.ts +289 -0
- package/src/commands/harness.ts +44 -0
- package/src/config.ts +9 -3
- package/src/harness/env.test.ts +79 -0
- package/src/harness/env.ts +89 -0
- package/src/harness/opencode-cli.test.ts +82 -0
- package/src/harness/opencode-cli.ts +99 -0
- package/src/harness/opencode-config.atomic-failure.test.ts +51 -0
- package/src/harness/opencode-config.test.ts +238 -0
- package/src/harness/opencode-config.ts +176 -0
- package/src/harness/prepare.test.ts +117 -0
- package/src/harness/prepare.ts +69 -0
- package/src/heartbeat.ts +2 -0
- package/src/index.ts +22 -0
- package/src/socketio-client.test.ts +155 -0
- package/src/socketio-client.ts +204 -18
- package/src/workload-executor.test.ts +237 -0
- package/src/workload-executor.ts +115 -17
- package/tests/commands/harness.test.ts +90 -0
- package/tests/socketio-client.test.ts +140 -2
|
@@ -229,7 +229,7 @@ describe('SocketIO Client', () => {
|
|
|
229
229
|
expect(mockSocket.emit).toHaveBeenCalledWith('register', {
|
|
230
230
|
key: 'zag_k_1_abc123',
|
|
231
231
|
hostname: 'my-machine',
|
|
232
|
-
version: '2.
|
|
232
|
+
version: '2.5.0',
|
|
233
233
|
resumeToken: undefined,
|
|
234
234
|
homeDir: '/home/user',
|
|
235
235
|
platform: 'linux',
|
|
@@ -247,7 +247,7 @@ describe('SocketIO Client', () => {
|
|
|
247
247
|
expect(mockSocket.emit).toHaveBeenCalledWith('register', {
|
|
248
248
|
key: 'zag_k_1_abc123',
|
|
249
249
|
hostname: 'test-machine',
|
|
250
|
-
version: '2.
|
|
250
|
+
version: '2.5.0',
|
|
251
251
|
resumeToken: undefined,
|
|
252
252
|
homeDir: '/home/user',
|
|
253
253
|
platform: 'linux',
|
|
@@ -328,6 +328,144 @@ describe('SocketIO Client', () => {
|
|
|
328
328
|
|
|
329
329
|
expect(console.error).toHaveBeenCalledWith('Connection error: connection failed');
|
|
330
330
|
});
|
|
331
|
+
|
|
332
|
+
it('T-AG16: uses an explicit handshake token instead of the key (controller-api standard connection)', () => {
|
|
333
|
+
const mockSocket = createMockSocket();
|
|
334
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
335
|
+
|
|
336
|
+
connectToServer('wss://controller.example.com', 'zag_k_1_host_key', {
|
|
337
|
+
handshakeToken: 'zag_k_1_host_key',
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
expect(io).toHaveBeenCalledWith('wss://controller.example.com', expect.objectContaining({
|
|
341
|
+
auth: { token: 'zag_k_1_host_key' },
|
|
342
|
+
}));
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('T-AG16b: never puts the host key into the URL/query and supports handshakeToken=false', () => {
|
|
346
|
+
const mockSocket = createMockSocket();
|
|
347
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
348
|
+
|
|
349
|
+
connectToServer('wss://controller.example.com?token=leaked', 'zag_k_1_host_key', {
|
|
350
|
+
handshakeToken: false,
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
expect(io).toHaveBeenCalledWith(expect.not.stringContaining('token='), expect.objectContaining({ auth: {} }));
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('T-AG3: forwards the full registered payload (including initializing) to onRegistered', () => {
|
|
357
|
+
const mockSocket = createMockSocket();
|
|
358
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
359
|
+
const onRegistered = vi.fn();
|
|
360
|
+
|
|
361
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123', { onRegistered });
|
|
362
|
+
mockSocket._trigger('registered', { controllerId: 'ctrl-1', initializing: true });
|
|
363
|
+
|
|
364
|
+
expect(onRegistered).toHaveBeenCalledWith({ controllerId: 'ctrl-1', initializing: true });
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('T-AG4: invokes onWorkloadBatchComplete after an init batch ends', async () => {
|
|
368
|
+
const mockSocket = createMockSocket();
|
|
369
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
370
|
+
const onWorkloadBatchComplete = vi.fn();
|
|
371
|
+
|
|
372
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123', { onWorkloadBatchComplete });
|
|
373
|
+
mockSocket._trigger('workload:run', {
|
|
374
|
+
phase: 'init',
|
|
375
|
+
// 空脚本立即产生失败结果(不需要真实 spawn),用于锚定「批次结束即回调且摘要反映失败」
|
|
376
|
+
items: [{ logId: 'init-1', workloadName: 'Init', script: '', timeoutMs: 5000 }],
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
await vi.waitFor(() => {
|
|
380
|
+
expect(mockSocket.emit).toHaveBeenCalledWith('workload:result', expect.objectContaining({ logId: 'init-1' }));
|
|
381
|
+
expect(onWorkloadBatchComplete).toHaveBeenCalledWith({
|
|
382
|
+
phase: 'init',
|
|
383
|
+
itemCount: 1,
|
|
384
|
+
status: 'failed',
|
|
385
|
+
cancelled: false,
|
|
386
|
+
failedCount: 1,
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('T-AG4b: invokes onWorkloadBatchComplete even when a required init item fails', async () => {
|
|
392
|
+
const mockSocket = createMockSocket();
|
|
393
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
394
|
+
const onWorkloadBatchComplete = vi.fn();
|
|
395
|
+
|
|
396
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123', { onWorkloadBatchComplete });
|
|
397
|
+
mockSocket._trigger('workload:run', {
|
|
398
|
+
phase: 'init',
|
|
399
|
+
items: [{ logId: 'init-fail', workloadName: 'Fail', script: '', timeoutMs: 5000, required: true }],
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
await vi.waitFor(() => {
|
|
403
|
+
expect(onWorkloadBatchComplete).toHaveBeenCalledWith({
|
|
404
|
+
phase: 'init',
|
|
405
|
+
itemCount: 1,
|
|
406
|
+
status: 'failed',
|
|
407
|
+
cancelled: false,
|
|
408
|
+
failedCount: 1,
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('T-AG18: skips the local MCP server when skipLocalMcpStart is set (dual connection singleton)', () => {
|
|
414
|
+
const mockSocket = createMockSocket();
|
|
415
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
416
|
+
|
|
417
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123', { skipLocalMcpStart: true });
|
|
418
|
+
|
|
419
|
+
expect(localServerInstances).toHaveLength(0);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('T-AG17: delegates shutdown to onShutdown without clearing local config or exiting', () => {
|
|
423
|
+
const mockSocket = createMockSocket();
|
|
424
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
425
|
+
const onShutdown = vi.fn();
|
|
426
|
+
|
|
427
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123', { onShutdown });
|
|
428
|
+
mockSocket._trigger('shutdown', { reason: 'container destroyed' });
|
|
429
|
+
|
|
430
|
+
expect(onShutdown).toHaveBeenCalledWith({ reason: 'container destroyed' });
|
|
431
|
+
expect(clearConfigKey).not.toHaveBeenCalled();
|
|
432
|
+
expect(process.exit).not.toHaveBeenCalled();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('T-AG16c: does not handle workload events when handleWorkload=false', () => {
|
|
436
|
+
const mockSocket = createMockSocket();
|
|
437
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
438
|
+
const onWorkloadBatchComplete = vi.fn();
|
|
439
|
+
|
|
440
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123', {
|
|
441
|
+
handleWorkload: false,
|
|
442
|
+
onWorkloadBatchComplete,
|
|
443
|
+
});
|
|
444
|
+
mockSocket._trigger('connect');
|
|
445
|
+
mockSocket._trigger('workload:run', {
|
|
446
|
+
phase: 'init',
|
|
447
|
+
items: [{ logId: 'x', workloadName: 'X', script: 'echo nope', timeoutMs: 5000 }],
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
expect(onWorkloadBatchComplete).not.toHaveBeenCalled();
|
|
451
|
+
expect(mockSocket.emit).not.toHaveBeenCalledWith('workload:result', expect.anything());
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it('T-AG13: redacts secret values from invalid workload payload logs', () => {
|
|
455
|
+
const mockSocket = createMockSocket();
|
|
456
|
+
vi.mocked(io).mockReturnValue(mockSocket as never);
|
|
457
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
458
|
+
|
|
459
|
+
connectToServer('http://localhost:4001', 'zag_k_1_abc123');
|
|
460
|
+
mockSocket._trigger('workload:run', {
|
|
461
|
+
phase: 'init',
|
|
462
|
+
items: 'invalid',
|
|
463
|
+
env: { ZAG_MODEL_API_KEY: 'zag_sk_super_secret' },
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.not.stringContaining('zag_sk_super_secret'));
|
|
467
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('***'));
|
|
468
|
+
});
|
|
331
469
|
});
|
|
332
470
|
|
|
333
471
|
describe('unregister', () => {
|