@herdctl/core 0.0.1 → 0.0.2
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/dist/config/__tests__/agent.test.js +31 -13
- package/dist/config/__tests__/agent.test.js.map +1 -1
- package/dist/config/__tests__/merge.test.js +9 -2
- package/dist/config/__tests__/merge.test.js.map +1 -1
- package/dist/config/__tests__/schema.test.js +350 -1
- package/dist/config/__tests__/schema.test.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/schema.d.ts +828 -24
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +118 -6
- package/dist/config/schema.js.map +1 -1
- package/dist/fleet-manager/__tests__/coverage.test.js +11 -332
- package/dist/fleet-manager/__tests__/coverage.test.js.map +1 -1
- package/dist/fleet-manager/__tests__/errors.test.js +1 -49
- package/dist/fleet-manager/__tests__/errors.test.js.map +1 -1
- package/dist/fleet-manager/__tests__/integration.test.js +109 -0
- package/dist/fleet-manager/__tests__/integration.test.js.map +1 -1
- package/dist/fleet-manager/__tests__/reload.test.js +1 -1
- package/dist/fleet-manager/__tests__/reload.test.js.map +1 -1
- package/dist/fleet-manager/config-reload.d.ts +164 -0
- package/dist/fleet-manager/config-reload.d.ts.map +1 -0
- package/dist/fleet-manager/config-reload.js +445 -0
- package/dist/fleet-manager/config-reload.js.map +1 -0
- package/dist/fleet-manager/context.d.ts +76 -0
- package/dist/fleet-manager/context.d.ts.map +1 -0
- package/dist/fleet-manager/context.js +11 -0
- package/dist/fleet-manager/context.js.map +1 -0
- package/dist/fleet-manager/errors.d.ts +0 -25
- package/dist/fleet-manager/errors.d.ts.map +1 -1
- package/dist/fleet-manager/errors.js +0 -38
- package/dist/fleet-manager/errors.js.map +1 -1
- package/dist/fleet-manager/event-emitters.d.ts +123 -0
- package/dist/fleet-manager/event-emitters.d.ts.map +1 -0
- package/dist/fleet-manager/event-emitters.js +136 -0
- package/dist/fleet-manager/event-emitters.js.map +1 -0
- package/dist/fleet-manager/event-types.d.ts +0 -15
- package/dist/fleet-manager/event-types.d.ts.map +1 -1
- package/dist/fleet-manager/fleet-manager.d.ts +40 -653
- package/dist/fleet-manager/fleet-manager.d.ts.map +1 -1
- package/dist/fleet-manager/fleet-manager.js +95 -1720
- package/dist/fleet-manager/fleet-manager.js.map +1 -1
- package/dist/fleet-manager/index.d.ts +13 -2
- package/dist/fleet-manager/index.d.ts.map +1 -1
- package/dist/fleet-manager/index.js +19 -6
- package/dist/fleet-manager/index.js.map +1 -1
- package/dist/fleet-manager/job-control.d.ts +64 -0
- package/dist/fleet-manager/job-control.d.ts.map +1 -0
- package/dist/fleet-manager/job-control.js +296 -0
- package/dist/fleet-manager/job-control.js.map +1 -0
- package/dist/fleet-manager/log-streaming.d.ts +171 -0
- package/dist/fleet-manager/log-streaming.d.ts.map +1 -0
- package/dist/fleet-manager/log-streaming.js +503 -0
- package/dist/fleet-manager/log-streaming.js.map +1 -0
- package/dist/fleet-manager/schedule-executor.d.ts +63 -0
- package/dist/fleet-manager/schedule-executor.d.ts.map +1 -0
- package/dist/fleet-manager/schedule-executor.js +209 -0
- package/dist/fleet-manager/schedule-executor.js.map +1 -0
- package/dist/fleet-manager/schedule-management.d.ts +71 -0
- package/dist/fleet-manager/schedule-management.d.ts.map +1 -0
- package/dist/fleet-manager/schedule-management.js +171 -0
- package/dist/fleet-manager/schedule-management.js.map +1 -0
- package/dist/fleet-manager/status-queries.d.ts +105 -0
- package/dist/fleet-manager/status-queries.d.ts.map +1 -0
- package/dist/fleet-manager/status-queries.js +247 -0
- package/dist/fleet-manager/status-queries.js.map +1 -0
- package/dist/fleet-manager/types.d.ts +0 -39
- package/dist/fleet-manager/types.d.ts.map +1 -1
- package/dist/runner/__tests__/job-executor.test.js +206 -1
- package/dist/runner/__tests__/job-executor.test.js.map +1 -1
- package/dist/runner/job-executor.d.ts +9 -0
- package/dist/runner/job-executor.d.ts.map +1 -1
- package/dist/runner/job-executor.js +78 -4
- package/dist/runner/job-executor.js.map +1 -1
- package/dist/runner/types.d.ts +2 -0
- package/dist/runner/types.d.ts.map +1 -1
- package/dist/scheduler/__tests__/cron.test.d.ts +2 -0
- package/dist/scheduler/__tests__/cron.test.d.ts.map +1 -0
- package/dist/scheduler/__tests__/cron.test.js +867 -0
- package/dist/scheduler/__tests__/cron.test.js.map +1 -0
- package/dist/scheduler/__tests__/scheduler.test.js +164 -5
- package/dist/scheduler/__tests__/scheduler.test.js.map +1 -1
- package/dist/scheduler/cron.d.ts +126 -0
- package/dist/scheduler/cron.d.ts.map +1 -0
- package/dist/scheduler/cron.js +390 -0
- package/dist/scheduler/cron.js.map +1 -0
- package/dist/scheduler/errors.d.ts +81 -1
- package/dist/scheduler/errors.d.ts.map +1 -1
- package/dist/scheduler/errors.js +81 -6
- package/dist/scheduler/errors.js.map +1 -1
- package/dist/scheduler/index.d.ts +1 -0
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +2 -0
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/schedule-runner.d.ts +2 -2
- package/dist/scheduler/schedule-runner.d.ts.map +1 -1
- package/dist/scheduler/schedule-runner.js +20 -8
- package/dist/scheduler/schedule-runner.js.map +1 -1
- package/dist/scheduler/scheduler.d.ts +4 -4
- package/dist/scheduler/scheduler.d.ts.map +1 -1
- package/dist/scheduler/scheduler.js +86 -20
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/scheduler/types.d.ts +1 -1
- package/dist/scheduler/types.d.ts.map +1 -1
- package/dist/state/schemas/job-metadata.d.ts +2 -2
- package/package.json +33 -8
- package/.turbo/turbo-build.log +0 -4
- package/.turbo/turbo-test.log +0 -219
- package/.turbo/turbo-typecheck.log +0 -4
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/coverage-final.json +0 -51
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -251
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/src/config/index.html +0 -191
- package/coverage/src/config/index.ts.html +0 -442
- package/coverage/src/config/interpolate.ts.html +0 -652
- package/coverage/src/config/loader.ts.html +0 -1501
- package/coverage/src/config/merge.ts.html +0 -823
- package/coverage/src/config/parser.ts.html +0 -1213
- package/coverage/src/config/schema.ts.html +0 -1123
- package/coverage/src/fleet-manager/errors.ts.html +0 -2326
- package/coverage/src/fleet-manager/event-types.ts.html +0 -1219
- package/coverage/src/fleet-manager/fleet-manager.ts.html +0 -7030
- package/coverage/src/fleet-manager/index.html +0 -206
- package/coverage/src/fleet-manager/index.ts.html +0 -469
- package/coverage/src/fleet-manager/job-manager.ts.html +0 -2074
- package/coverage/src/fleet-manager/job-queue.ts.html +0 -2479
- package/coverage/src/fleet-manager/types.ts.html +0 -2602
- package/coverage/src/index.html +0 -116
- package/coverage/src/index.ts.html +0 -181
- package/coverage/src/runner/errors.ts.html +0 -1006
- package/coverage/src/runner/index.html +0 -191
- package/coverage/src/runner/index.ts.html +0 -256
- package/coverage/src/runner/job-executor.ts.html +0 -1429
- package/coverage/src/runner/message-processor.ts.html +0 -1150
- package/coverage/src/runner/sdk-adapter.ts.html +0 -658
- package/coverage/src/runner/types.ts.html +0 -559
- package/coverage/src/scheduler/errors.ts.html +0 -388
- package/coverage/src/scheduler/index.html +0 -206
- package/coverage/src/scheduler/index.ts.html +0 -244
- package/coverage/src/scheduler/interval.ts.html +0 -652
- package/coverage/src/scheduler/schedule-runner.ts.html +0 -1411
- package/coverage/src/scheduler/schedule-state.ts.html +0 -718
- package/coverage/src/scheduler/scheduler.ts.html +0 -1795
- package/coverage/src/scheduler/types.ts.html +0 -733
- package/coverage/src/state/directory.ts.html +0 -736
- package/coverage/src/state/errors.ts.html +0 -376
- package/coverage/src/state/fleet-state.ts.html +0 -937
- package/coverage/src/state/index.html +0 -221
- package/coverage/src/state/index.ts.html +0 -322
- package/coverage/src/state/job-metadata.ts.html +0 -1420
- package/coverage/src/state/job-output.ts.html +0 -1033
- package/coverage/src/state/schemas/fleet-state.ts.html +0 -445
- package/coverage/src/state/schemas/index.html +0 -176
- package/coverage/src/state/schemas/index.ts.html +0 -286
- package/coverage/src/state/schemas/job-metadata.ts.html +0 -628
- package/coverage/src/state/schemas/job-output.ts.html +0 -616
- package/coverage/src/state/schemas/session-info.ts.html +0 -361
- package/coverage/src/state/session.ts.html +0 -844
- package/coverage/src/state/types.ts.html +0 -262
- package/coverage/src/state/utils/atomic.ts.html +0 -748
- package/coverage/src/state/utils/index.html +0 -146
- package/coverage/src/state/utils/index.ts.html +0 -103
- package/coverage/src/state/utils/reads.ts.html +0 -1621
- package/coverage/src/work-sources/adapters/github.ts.html +0 -3583
- package/coverage/src/work-sources/adapters/index.html +0 -131
- package/coverage/src/work-sources/adapters/index.ts.html +0 -277
- package/coverage/src/work-sources/errors.ts.html +0 -298
- package/coverage/src/work-sources/index.html +0 -176
- package/coverage/src/work-sources/index.ts.html +0 -529
- package/coverage/src/work-sources/manager.ts.html +0 -1324
- package/coverage/src/work-sources/registry.ts.html +0 -619
- package/coverage/src/work-sources/types.ts.html +0 -568
- package/dist/fleet-manager/__tests__/event-helpers.test.d.ts +0 -7
- package/dist/fleet-manager/__tests__/event-helpers.test.d.ts.map +0 -1
- package/dist/fleet-manager/__tests__/event-helpers.test.js +0 -368
- package/dist/fleet-manager/__tests__/event-helpers.test.js.map +0 -1
- package/src/config/__tests__/agent.test.ts +0 -864
- package/src/config/__tests__/interpolate.test.ts +0 -644
- package/src/config/__tests__/loader.test.ts +0 -784
- package/src/config/__tests__/merge.test.ts +0 -751
- package/src/config/__tests__/parser.test.ts +0 -533
- package/src/config/__tests__/schema.test.ts +0 -873
- package/src/config/index.ts +0 -119
- package/src/config/interpolate.ts +0 -189
- package/src/config/loader.ts +0 -472
- package/src/config/merge.ts +0 -246
- package/src/config/parser.ts +0 -376
- package/src/config/schema.ts +0 -346
- package/src/fleet-manager/__tests__/coverage.test.ts +0 -2869
- package/src/fleet-manager/__tests__/errors.test.ts +0 -660
- package/src/fleet-manager/__tests__/event-helpers.test.ts +0 -448
- package/src/fleet-manager/__tests__/integration.test.ts +0 -1209
- package/src/fleet-manager/__tests__/job-control.test.ts +0 -283
- package/src/fleet-manager/__tests__/job-manager.test.ts +0 -869
- package/src/fleet-manager/__tests__/job-queue.test.ts +0 -401
- package/src/fleet-manager/__tests__/reload.test.ts +0 -751
- package/src/fleet-manager/__tests__/status-queries.test.ts +0 -595
- package/src/fleet-manager/__tests__/trigger.test.ts +0 -601
- package/src/fleet-manager/errors.ts +0 -747
- package/src/fleet-manager/event-types.ts +0 -378
- package/src/fleet-manager/fleet-manager.ts +0 -2315
- package/src/fleet-manager/index.ts +0 -128
- package/src/fleet-manager/job-manager.ts +0 -663
- package/src/fleet-manager/job-queue.ts +0 -798
- package/src/fleet-manager/types.ts +0 -839
- package/src/index.ts +0 -32
- package/src/runner/__tests__/errors.test.ts +0 -382
- package/src/runner/__tests__/job-executor.test.ts +0 -1708
- package/src/runner/__tests__/message-processor.test.ts +0 -960
- package/src/runner/__tests__/sdk-adapter.test.ts +0 -626
- package/src/runner/errors.ts +0 -307
- package/src/runner/index.ts +0 -57
- package/src/runner/job-executor.ts +0 -448
- package/src/runner/message-processor.ts +0 -355
- package/src/runner/sdk-adapter.ts +0 -191
- package/src/runner/types.ts +0 -158
- package/src/scheduler/__tests__/errors.test.ts +0 -159
- package/src/scheduler/__tests__/interval.test.ts +0 -515
- package/src/scheduler/__tests__/schedule-runner.test.ts +0 -798
- package/src/scheduler/__tests__/schedule-state.test.ts +0 -671
- package/src/scheduler/__tests__/scheduler.test.ts +0 -1280
- package/src/scheduler/errors.ts +0 -101
- package/src/scheduler/index.ts +0 -53
- package/src/scheduler/interval.ts +0 -189
- package/src/scheduler/schedule-runner.ts +0 -442
- package/src/scheduler/schedule-state.ts +0 -211
- package/src/scheduler/scheduler.ts +0 -570
- package/src/scheduler/types.ts +0 -216
- package/src/state/__tests__/directory.test.ts +0 -595
- package/src/state/__tests__/fleet-state.test.ts +0 -868
- package/src/state/__tests__/job-metadata-schema.test.ts +0 -414
- package/src/state/__tests__/job-metadata.test.ts +0 -831
- package/src/state/__tests__/job-output.test.ts +0 -856
- package/src/state/__tests__/session-schema.test.ts +0 -378
- package/src/state/__tests__/session.test.ts +0 -604
- package/src/state/directory.ts +0 -217
- package/src/state/errors.ts +0 -97
- package/src/state/fleet-state.ts +0 -284
- package/src/state/index.ts +0 -79
- package/src/state/job-metadata.ts +0 -445
- package/src/state/job-output.ts +0 -316
- package/src/state/schemas/__tests__/job-output.test.ts +0 -338
- package/src/state/schemas/fleet-state.ts +0 -120
- package/src/state/schemas/index.ts +0 -67
- package/src/state/schemas/job-metadata.ts +0 -181
- package/src/state/schemas/job-output.ts +0 -177
- package/src/state/schemas/session-info.ts +0 -92
- package/src/state/session.ts +0 -253
- package/src/state/types.ts +0 -59
- package/src/state/utils/__tests__/atomic.test.ts +0 -723
- package/src/state/utils/__tests__/reads.test.ts +0 -1071
- package/src/state/utils/atomic.ts +0 -221
- package/src/state/utils/index.ts +0 -6
- package/src/state/utils/reads.ts +0 -512
- package/src/work-sources/__tests__/github.test.ts +0 -1800
- package/src/work-sources/__tests__/manager.test.ts +0 -529
- package/src/work-sources/__tests__/registry.test.ts +0 -477
- package/src/work-sources/__tests__/types.test.ts +0 -479
- package/src/work-sources/adapters/github.ts +0 -1166
- package/src/work-sources/adapters/index.ts +0 -64
- package/src/work-sources/errors.ts +0 -71
- package/src/work-sources/index.ts +0 -148
- package/src/work-sources/manager.ts +0 -413
- package/src/work-sources/registry.ts +0 -178
- package/src/work-sources/types.ts +0 -161
- package/tsconfig.json +0 -9
- package/vitest.config.ts +0 -19
|
@@ -1,595 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for fleet status query methods (US-3)
|
|
3
|
-
*
|
|
4
|
-
* Tests getFleetStatus(), getAgentInfo(), and getAgentInfoByName() methods.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
8
|
-
import { mkdtemp, rm, mkdir, writeFile } from "fs/promises";
|
|
9
|
-
import { tmpdir } from "os";
|
|
10
|
-
import { join } from "path";
|
|
11
|
-
import { FleetManager } from "../fleet-manager.js";
|
|
12
|
-
import { AgentNotFoundError } from "../errors.js";
|
|
13
|
-
import type { FleetStatus, AgentInfo } from "../types.js";
|
|
14
|
-
|
|
15
|
-
describe("Fleet Status Query Methods", () => {
|
|
16
|
-
let tempDir: string;
|
|
17
|
-
let configDir: string;
|
|
18
|
-
let stateDir: string;
|
|
19
|
-
|
|
20
|
-
beforeEach(async () => {
|
|
21
|
-
// Create temp directory for test
|
|
22
|
-
tempDir = await mkdtemp(join(tmpdir(), "fleet-status-test-"));
|
|
23
|
-
configDir = join(tempDir, "config");
|
|
24
|
-
stateDir = join(tempDir, ".herdctl");
|
|
25
|
-
await mkdir(configDir, { recursive: true });
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
afterEach(async () => {
|
|
29
|
-
// Cleanup with retry to handle race conditions from async operations
|
|
30
|
-
await rm(tempDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Helper to create a test config file
|
|
34
|
-
async function createConfig(config: object) {
|
|
35
|
-
const configPath = join(configDir, "herdctl.yaml");
|
|
36
|
-
const yaml = await import("yaml");
|
|
37
|
-
await writeFile(configPath, yaml.stringify(config));
|
|
38
|
-
return configPath;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Helper to create an agent config file
|
|
42
|
-
async function createAgentConfig(name: string, config: object) {
|
|
43
|
-
const agentDir = join(configDir, "agents");
|
|
44
|
-
await mkdir(agentDir, { recursive: true });
|
|
45
|
-
const agentPath = join(agentDir, `${name}.yaml`);
|
|
46
|
-
const yaml = await import("yaml");
|
|
47
|
-
await writeFile(agentPath, yaml.stringify(config));
|
|
48
|
-
return agentPath;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
describe("getFleetStatus()", () => {
|
|
52
|
-
it("returns status before initialization", async () => {
|
|
53
|
-
const configPath = await createConfig({
|
|
54
|
-
version: 1,
|
|
55
|
-
agents: [],
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const manager = new FleetManager({
|
|
59
|
-
configPath,
|
|
60
|
-
stateDir,
|
|
61
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const status = await manager.getFleetStatus();
|
|
65
|
-
|
|
66
|
-
expect(status.state).toBe("uninitialized");
|
|
67
|
-
expect(status.uptimeSeconds).toBeNull();
|
|
68
|
-
expect(status.initializedAt).toBeNull();
|
|
69
|
-
expect(status.startedAt).toBeNull();
|
|
70
|
-
expect(status.counts.totalAgents).toBe(0);
|
|
71
|
-
expect(status.scheduler.status).toBe("stopped");
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("returns status after initialization", async () => {
|
|
75
|
-
// Create agent config
|
|
76
|
-
await createAgentConfig("test-agent", {
|
|
77
|
-
name: "test-agent",
|
|
78
|
-
description: "Test agent for status queries",
|
|
79
|
-
schedules: {
|
|
80
|
-
daily: {
|
|
81
|
-
type: "interval",
|
|
82
|
-
interval: "1h",
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
const configPath = await createConfig({
|
|
88
|
-
version: 1,
|
|
89
|
-
agents: [{ path: "./agents/test-agent.yaml" }],
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const manager = new FleetManager({
|
|
93
|
-
configPath,
|
|
94
|
-
stateDir,
|
|
95
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
await manager.initialize();
|
|
99
|
-
const status = await manager.getFleetStatus();
|
|
100
|
-
|
|
101
|
-
expect(status.state).toBe("initialized");
|
|
102
|
-
expect(status.uptimeSeconds).toBeNull(); // Not started yet
|
|
103
|
-
expect(status.initializedAt).not.toBeNull();
|
|
104
|
-
expect(status.counts.totalAgents).toBe(1);
|
|
105
|
-
expect(status.counts.idleAgents).toBe(1);
|
|
106
|
-
expect(status.counts.totalSchedules).toBe(1);
|
|
107
|
-
expect(status.scheduler.status).toBe("stopped");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("returns status after start", async () => {
|
|
111
|
-
await createAgentConfig("test-agent", {
|
|
112
|
-
name: "test-agent",
|
|
113
|
-
schedules: {
|
|
114
|
-
hourly: {
|
|
115
|
-
type: "interval",
|
|
116
|
-
interval: "1h",
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
const configPath = await createConfig({
|
|
122
|
-
version: 1,
|
|
123
|
-
agents: [{ path: "./agents/test-agent.yaml" }],
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const manager = new FleetManager({
|
|
127
|
-
configPath,
|
|
128
|
-
stateDir,
|
|
129
|
-
checkInterval: 10000, // Long interval to avoid triggers during test
|
|
130
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
await manager.initialize();
|
|
134
|
-
await manager.start();
|
|
135
|
-
|
|
136
|
-
// Give it a moment to start
|
|
137
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
138
|
-
|
|
139
|
-
const status = await manager.getFleetStatus();
|
|
140
|
-
|
|
141
|
-
expect(status.state).toBe("running");
|
|
142
|
-
expect(status.uptimeSeconds).toBeGreaterThanOrEqual(0);
|
|
143
|
-
expect(status.startedAt).not.toBeNull();
|
|
144
|
-
expect(status.scheduler.status).toBe("running");
|
|
145
|
-
expect(status.scheduler.checkIntervalMs).toBe(10000);
|
|
146
|
-
|
|
147
|
-
await manager.stop();
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("returns status after stop", async () => {
|
|
151
|
-
await createAgentConfig("test-agent", {
|
|
152
|
-
name: "test-agent",
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
const configPath = await createConfig({
|
|
156
|
-
version: 1,
|
|
157
|
-
agents: [{ path: "./agents/test-agent.yaml" }],
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
const manager = new FleetManager({
|
|
161
|
-
configPath,
|
|
162
|
-
stateDir,
|
|
163
|
-
checkInterval: 10000,
|
|
164
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
await manager.initialize();
|
|
168
|
-
await manager.start();
|
|
169
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
170
|
-
await manager.stop();
|
|
171
|
-
|
|
172
|
-
const status = await manager.getFleetStatus();
|
|
173
|
-
|
|
174
|
-
expect(status.state).toBe("stopped");
|
|
175
|
-
expect(status.uptimeSeconds).toBeGreaterThanOrEqual(0);
|
|
176
|
-
expect(status.stoppedAt).not.toBeNull();
|
|
177
|
-
expect(status.scheduler.status).toBe("stopped");
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it("returns correct counts for multiple agents", async () => {
|
|
181
|
-
await createAgentConfig("agent-1", {
|
|
182
|
-
name: "agent-1",
|
|
183
|
-
schedules: {
|
|
184
|
-
s1: { type: "interval", interval: "1h" },
|
|
185
|
-
s2: { type: "interval", interval: "2h" },
|
|
186
|
-
},
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
await createAgentConfig("agent-2", {
|
|
190
|
-
name: "agent-2",
|
|
191
|
-
schedules: {
|
|
192
|
-
s1: { type: "interval", interval: "30m" },
|
|
193
|
-
},
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
await createAgentConfig("agent-3", {
|
|
197
|
-
name: "agent-3",
|
|
198
|
-
// No schedules
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const configPath = await createConfig({
|
|
202
|
-
version: 1,
|
|
203
|
-
agents: [
|
|
204
|
-
{ path: "./agents/agent-1.yaml" },
|
|
205
|
-
{ path: "./agents/agent-2.yaml" },
|
|
206
|
-
{ path: "./agents/agent-3.yaml" },
|
|
207
|
-
],
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
const manager = new FleetManager({
|
|
211
|
-
configPath,
|
|
212
|
-
stateDir,
|
|
213
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
await manager.initialize();
|
|
217
|
-
const status = await manager.getFleetStatus();
|
|
218
|
-
|
|
219
|
-
expect(status.counts.totalAgents).toBe(3);
|
|
220
|
-
expect(status.counts.idleAgents).toBe(3);
|
|
221
|
-
expect(status.counts.runningAgents).toBe(0);
|
|
222
|
-
expect(status.counts.errorAgents).toBe(0);
|
|
223
|
-
expect(status.counts.totalSchedules).toBe(3);
|
|
224
|
-
expect(status.counts.runningSchedules).toBe(0);
|
|
225
|
-
expect(status.counts.runningJobs).toBe(0);
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
describe("getAgentInfo()", () => {
|
|
230
|
-
it("returns empty array before initialization", async () => {
|
|
231
|
-
const configPath = await createConfig({
|
|
232
|
-
version: 1,
|
|
233
|
-
agents: [],
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
const manager = new FleetManager({
|
|
237
|
-
configPath,
|
|
238
|
-
stateDir,
|
|
239
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
const agents = await manager.getAgentInfo();
|
|
243
|
-
expect(agents).toEqual([]);
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it("returns agent info with schedules", async () => {
|
|
247
|
-
await createAgentConfig("my-agent", {
|
|
248
|
-
name: "my-agent",
|
|
249
|
-
description: "My test agent",
|
|
250
|
-
model: "claude-3-5-sonnet",
|
|
251
|
-
workspace: "/path/to/workspace",
|
|
252
|
-
instances: { max_concurrent: 2 },
|
|
253
|
-
schedules: {
|
|
254
|
-
hourly: {
|
|
255
|
-
type: "interval",
|
|
256
|
-
interval: "1h",
|
|
257
|
-
},
|
|
258
|
-
daily: {
|
|
259
|
-
type: "interval",
|
|
260
|
-
interval: "24h",
|
|
261
|
-
},
|
|
262
|
-
},
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
const configPath = await createConfig({
|
|
266
|
-
version: 1,
|
|
267
|
-
agents: [{ path: "./agents/my-agent.yaml" }],
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
const manager = new FleetManager({
|
|
271
|
-
configPath,
|
|
272
|
-
stateDir,
|
|
273
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
await manager.initialize();
|
|
277
|
-
const agents = await manager.getAgentInfo();
|
|
278
|
-
|
|
279
|
-
expect(agents).toHaveLength(1);
|
|
280
|
-
expect(agents[0].name).toBe("my-agent");
|
|
281
|
-
expect(agents[0].description).toBe("My test agent");
|
|
282
|
-
expect(agents[0].model).toBe("claude-3-5-sonnet");
|
|
283
|
-
expect(agents[0].workspace).toBe("/path/to/workspace");
|
|
284
|
-
expect(agents[0].maxConcurrent).toBe(2);
|
|
285
|
-
expect(agents[0].status).toBe("idle");
|
|
286
|
-
expect(agents[0].currentJobId).toBeNull();
|
|
287
|
-
expect(agents[0].lastJobId).toBeNull();
|
|
288
|
-
expect(agents[0].runningCount).toBe(0);
|
|
289
|
-
expect(agents[0].scheduleCount).toBe(2);
|
|
290
|
-
|
|
291
|
-
// Check schedules
|
|
292
|
-
expect(agents[0].schedules).toHaveLength(2);
|
|
293
|
-
const hourlySchedule = agents[0].schedules.find((s) => s.name === "hourly");
|
|
294
|
-
expect(hourlySchedule).toBeDefined();
|
|
295
|
-
expect(hourlySchedule!.type).toBe("interval");
|
|
296
|
-
expect(hourlySchedule!.interval).toBe("1h");
|
|
297
|
-
expect(hourlySchedule!.status).toBe("idle");
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
it("returns agent info for agent without schedules", async () => {
|
|
301
|
-
await createAgentConfig("simple-agent", {
|
|
302
|
-
name: "simple-agent",
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
const configPath = await createConfig({
|
|
306
|
-
version: 1,
|
|
307
|
-
agents: [{ path: "./agents/simple-agent.yaml" }],
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
const manager = new FleetManager({
|
|
311
|
-
configPath,
|
|
312
|
-
stateDir,
|
|
313
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
await manager.initialize();
|
|
317
|
-
const agents = await manager.getAgentInfo();
|
|
318
|
-
|
|
319
|
-
expect(agents).toHaveLength(1);
|
|
320
|
-
expect(agents[0].name).toBe("simple-agent");
|
|
321
|
-
expect(agents[0].scheduleCount).toBe(0);
|
|
322
|
-
expect(agents[0].schedules).toEqual([]);
|
|
323
|
-
expect(agents[0].maxConcurrent).toBe(1); // Default
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it("returns consistent snapshot for multiple agents", async () => {
|
|
327
|
-
await createAgentConfig("agent-a", { name: "agent-a" });
|
|
328
|
-
await createAgentConfig("agent-b", { name: "agent-b" });
|
|
329
|
-
|
|
330
|
-
const configPath = await createConfig({
|
|
331
|
-
version: 1,
|
|
332
|
-
agents: [
|
|
333
|
-
{ path: "./agents/agent-a.yaml" },
|
|
334
|
-
{ path: "./agents/agent-b.yaml" },
|
|
335
|
-
],
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const manager = new FleetManager({
|
|
339
|
-
configPath,
|
|
340
|
-
stateDir,
|
|
341
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
await manager.initialize();
|
|
345
|
-
const agents = await manager.getAgentInfo();
|
|
346
|
-
|
|
347
|
-
expect(agents).toHaveLength(2);
|
|
348
|
-
expect(agents.map((a) => a.name).sort()).toEqual(["agent-a", "agent-b"]);
|
|
349
|
-
});
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
describe("getAgentInfoByName()", () => {
|
|
353
|
-
it("returns specific agent info", async () => {
|
|
354
|
-
await createAgentConfig("target-agent", {
|
|
355
|
-
name: "target-agent",
|
|
356
|
-
description: "The target",
|
|
357
|
-
model: "claude-opus",
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
await createAgentConfig("other-agent", {
|
|
361
|
-
name: "other-agent",
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
const configPath = await createConfig({
|
|
365
|
-
version: 1,
|
|
366
|
-
agents: [
|
|
367
|
-
{ path: "./agents/target-agent.yaml" },
|
|
368
|
-
{ path: "./agents/other-agent.yaml" },
|
|
369
|
-
],
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
const manager = new FleetManager({
|
|
373
|
-
configPath,
|
|
374
|
-
stateDir,
|
|
375
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
await manager.initialize();
|
|
379
|
-
const agent = await manager.getAgentInfoByName("target-agent");
|
|
380
|
-
|
|
381
|
-
expect(agent.name).toBe("target-agent");
|
|
382
|
-
expect(agent.description).toBe("The target");
|
|
383
|
-
expect(agent.model).toBe("claude-opus");
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
it("throws AgentNotFoundError for unknown agent", async () => {
|
|
387
|
-
await createAgentConfig("known-agent", {
|
|
388
|
-
name: "known-agent",
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
const configPath = await createConfig({
|
|
392
|
-
version: 1,
|
|
393
|
-
agents: [{ path: "./agents/known-agent.yaml" }],
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
const manager = new FleetManager({
|
|
397
|
-
configPath,
|
|
398
|
-
stateDir,
|
|
399
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
await manager.initialize();
|
|
403
|
-
|
|
404
|
-
await expect(
|
|
405
|
-
manager.getAgentInfoByName("unknown-agent")
|
|
406
|
-
).rejects.toThrow(AgentNotFoundError);
|
|
407
|
-
|
|
408
|
-
await expect(
|
|
409
|
-
manager.getAgentInfoByName("unknown-agent")
|
|
410
|
-
).rejects.toMatchObject({
|
|
411
|
-
name: "AgentNotFoundError",
|
|
412
|
-
agentName: "unknown-agent",
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it("throws AgentNotFoundError before initialization", async () => {
|
|
417
|
-
const configPath = await createConfig({
|
|
418
|
-
version: 1,
|
|
419
|
-
agents: [],
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
const manager = new FleetManager({
|
|
423
|
-
configPath,
|
|
424
|
-
stateDir,
|
|
425
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
await expect(
|
|
429
|
-
manager.getAgentInfoByName("any-agent")
|
|
430
|
-
).rejects.toThrow(AgentNotFoundError);
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
describe("status queries work with running fleet", () => {
|
|
435
|
-
it("getFleetStatus works while running", async () => {
|
|
436
|
-
await createAgentConfig("running-test", {
|
|
437
|
-
name: "running-test",
|
|
438
|
-
schedules: {
|
|
439
|
-
test: { type: "interval", interval: "1h" },
|
|
440
|
-
},
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
const configPath = await createConfig({
|
|
444
|
-
version: 1,
|
|
445
|
-
agents: [{ path: "./agents/running-test.yaml" }],
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
const manager = new FleetManager({
|
|
449
|
-
configPath,
|
|
450
|
-
stateDir,
|
|
451
|
-
checkInterval: 10000, // Long interval
|
|
452
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
await manager.initialize();
|
|
456
|
-
await manager.start();
|
|
457
|
-
|
|
458
|
-
// Query multiple times while running
|
|
459
|
-
const status1 = await manager.getFleetStatus();
|
|
460
|
-
const status2 = await manager.getFleetStatus();
|
|
461
|
-
|
|
462
|
-
expect(status1.state).toBe("running");
|
|
463
|
-
expect(status2.state).toBe("running");
|
|
464
|
-
expect(status1.scheduler.status).toBe("running");
|
|
465
|
-
expect(status2.scheduler.status).toBe("running");
|
|
466
|
-
|
|
467
|
-
await manager.stop();
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
it("getAgentInfo works while running", async () => {
|
|
471
|
-
await createAgentConfig("running-agent", {
|
|
472
|
-
name: "running-agent",
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
const configPath = await createConfig({
|
|
476
|
-
version: 1,
|
|
477
|
-
agents: [{ path: "./agents/running-agent.yaml" }],
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
const manager = new FleetManager({
|
|
481
|
-
configPath,
|
|
482
|
-
stateDir,
|
|
483
|
-
checkInterval: 10000,
|
|
484
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
await manager.initialize();
|
|
488
|
-
await manager.start();
|
|
489
|
-
|
|
490
|
-
const agents = await manager.getAgentInfo();
|
|
491
|
-
expect(agents).toHaveLength(1);
|
|
492
|
-
expect(agents[0].name).toBe("running-agent");
|
|
493
|
-
|
|
494
|
-
await manager.stop();
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
it("getAgentInfoByName works while running", async () => {
|
|
498
|
-
await createAgentConfig("specific-agent", {
|
|
499
|
-
name: "specific-agent",
|
|
500
|
-
description: "Specific running agent",
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
const configPath = await createConfig({
|
|
504
|
-
version: 1,
|
|
505
|
-
agents: [{ path: "./agents/specific-agent.yaml" }],
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
const manager = new FleetManager({
|
|
509
|
-
configPath,
|
|
510
|
-
stateDir,
|
|
511
|
-
checkInterval: 10000,
|
|
512
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
await manager.initialize();
|
|
516
|
-
await manager.start();
|
|
517
|
-
|
|
518
|
-
const agent = await manager.getAgentInfoByName("specific-agent");
|
|
519
|
-
expect(agent.name).toBe("specific-agent");
|
|
520
|
-
expect(agent.description).toBe("Specific running agent");
|
|
521
|
-
|
|
522
|
-
await manager.stop();
|
|
523
|
-
});
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
describe("workspace handling", () => {
|
|
527
|
-
it("handles string workspace", async () => {
|
|
528
|
-
await createAgentConfig("string-ws-agent", {
|
|
529
|
-
name: "string-ws-agent",
|
|
530
|
-
workspace: "/simple/path",
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
const configPath = await createConfig({
|
|
534
|
-
version: 1,
|
|
535
|
-
agents: [{ path: "./agents/string-ws-agent.yaml" }],
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
const manager = new FleetManager({
|
|
539
|
-
configPath,
|
|
540
|
-
stateDir,
|
|
541
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
542
|
-
});
|
|
543
|
-
|
|
544
|
-
await manager.initialize();
|
|
545
|
-
const agent = await manager.getAgentInfoByName("string-ws-agent");
|
|
546
|
-
expect(agent.workspace).toBe("/simple/path");
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
it("handles object workspace", async () => {
|
|
550
|
-
await createAgentConfig("object-ws-agent", {
|
|
551
|
-
name: "object-ws-agent",
|
|
552
|
-
workspace: {
|
|
553
|
-
root: "/workspace/root",
|
|
554
|
-
auto_clone: true,
|
|
555
|
-
},
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
const configPath = await createConfig({
|
|
559
|
-
version: 1,
|
|
560
|
-
agents: [{ path: "./agents/object-ws-agent.yaml" }],
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
const manager = new FleetManager({
|
|
564
|
-
configPath,
|
|
565
|
-
stateDir,
|
|
566
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
567
|
-
});
|
|
568
|
-
|
|
569
|
-
await manager.initialize();
|
|
570
|
-
const agent = await manager.getAgentInfoByName("object-ws-agent");
|
|
571
|
-
expect(agent.workspace).toBe("/workspace/root");
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
it("handles missing workspace", async () => {
|
|
575
|
-
await createAgentConfig("no-ws-agent", {
|
|
576
|
-
name: "no-ws-agent",
|
|
577
|
-
});
|
|
578
|
-
|
|
579
|
-
const configPath = await createConfig({
|
|
580
|
-
version: 1,
|
|
581
|
-
agents: [{ path: "./agents/no-ws-agent.yaml" }],
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
const manager = new FleetManager({
|
|
585
|
-
configPath,
|
|
586
|
-
stateDir,
|
|
587
|
-
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
await manager.initialize();
|
|
591
|
-
const agent = await manager.getAgentInfoByName("no-ws-agent");
|
|
592
|
-
expect(agent.workspace).toBeUndefined();
|
|
593
|
-
});
|
|
594
|
-
});
|
|
595
|
-
});
|