@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,671 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { mkdir, rm, realpath, writeFile, readFile } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import {
|
|
6
|
-
getScheduleState,
|
|
7
|
-
updateScheduleState,
|
|
8
|
-
getAgentScheduleStates,
|
|
9
|
-
type ScheduleStateLogger,
|
|
10
|
-
} from "../schedule-state.js";
|
|
11
|
-
import {
|
|
12
|
-
createDefaultScheduleState,
|
|
13
|
-
type ScheduleState,
|
|
14
|
-
type FleetState,
|
|
15
|
-
} from "../../state/schemas/fleet-state.js";
|
|
16
|
-
import { writeFleetState, readFleetState } from "../../state/fleet-state.js";
|
|
17
|
-
|
|
18
|
-
// Helper to create a temp directory
|
|
19
|
-
async function createTempDir(): Promise<string> {
|
|
20
|
-
const baseDir = join(
|
|
21
|
-
tmpdir(),
|
|
22
|
-
`herdctl-schedule-state-test-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
23
|
-
);
|
|
24
|
-
await mkdir(baseDir, { recursive: true });
|
|
25
|
-
// Resolve to real path to handle macOS /var -> /private/var symlink
|
|
26
|
-
return await realpath(baseDir);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Helper to create a mock logger
|
|
30
|
-
function createMockLogger(): ScheduleStateLogger & { warnings: string[] } {
|
|
31
|
-
const warnings: string[] = [];
|
|
32
|
-
return {
|
|
33
|
-
warnings,
|
|
34
|
-
warn: (message: string) => warnings.push(message),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
describe("getScheduleState", () => {
|
|
39
|
-
let tempDir: string;
|
|
40
|
-
|
|
41
|
-
beforeEach(async () => {
|
|
42
|
-
tempDir = await createTempDir();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
afterEach(async () => {
|
|
46
|
-
await rm(tempDir, { recursive: true, force: true });
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe("existing schedule state", () => {
|
|
50
|
-
it("returns schedule state for existing agent and schedule", async () => {
|
|
51
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
52
|
-
const initialState: FleetState = {
|
|
53
|
-
fleet: {},
|
|
54
|
-
agents: {
|
|
55
|
-
"my-agent": {
|
|
56
|
-
status: "idle",
|
|
57
|
-
schedules: {
|
|
58
|
-
hourly: {
|
|
59
|
-
last_run_at: "2024-01-15T10:00:00Z",
|
|
60
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
61
|
-
status: "idle",
|
|
62
|
-
last_error: null,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
await writeFleetState(stateFile, initialState);
|
|
69
|
-
|
|
70
|
-
const state = await getScheduleState(tempDir, "my-agent", "hourly");
|
|
71
|
-
|
|
72
|
-
expect(state.last_run_at).toBe("2024-01-15T10:00:00Z");
|
|
73
|
-
expect(state.next_run_at).toBe("2024-01-15T11:00:00Z");
|
|
74
|
-
expect(state.status).toBe("idle");
|
|
75
|
-
expect(state.last_error).toBeNull();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("returns schedule state with running status", async () => {
|
|
79
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
80
|
-
const initialState: FleetState = {
|
|
81
|
-
fleet: {},
|
|
82
|
-
agents: {
|
|
83
|
-
"my-agent": {
|
|
84
|
-
status: "running",
|
|
85
|
-
schedules: {
|
|
86
|
-
daily: {
|
|
87
|
-
last_run_at: "2024-01-14T00:00:00Z",
|
|
88
|
-
next_run_at: null,
|
|
89
|
-
status: "running",
|
|
90
|
-
last_error: null,
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
await writeFleetState(stateFile, initialState);
|
|
97
|
-
|
|
98
|
-
const state = await getScheduleState(tempDir, "my-agent", "daily");
|
|
99
|
-
|
|
100
|
-
expect(state.status).toBe("running");
|
|
101
|
-
expect(state.next_run_at).toBeNull();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it("returns schedule state with disabled status", async () => {
|
|
105
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
106
|
-
const initialState: FleetState = {
|
|
107
|
-
fleet: {},
|
|
108
|
-
agents: {
|
|
109
|
-
"my-agent": {
|
|
110
|
-
status: "idle",
|
|
111
|
-
schedules: {
|
|
112
|
-
weekly: {
|
|
113
|
-
last_run_at: "2024-01-08T00:00:00Z",
|
|
114
|
-
next_run_at: null,
|
|
115
|
-
status: "disabled",
|
|
116
|
-
last_error: null,
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
};
|
|
122
|
-
await writeFleetState(stateFile, initialState);
|
|
123
|
-
|
|
124
|
-
const state = await getScheduleState(tempDir, "my-agent", "weekly");
|
|
125
|
-
|
|
126
|
-
expect(state.status).toBe("disabled");
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it("returns schedule state with error information", async () => {
|
|
130
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
131
|
-
const initialState: FleetState = {
|
|
132
|
-
fleet: {},
|
|
133
|
-
agents: {
|
|
134
|
-
"my-agent": {
|
|
135
|
-
status: "error",
|
|
136
|
-
schedules: {
|
|
137
|
-
hourly: {
|
|
138
|
-
last_run_at: "2024-01-15T10:00:00Z",
|
|
139
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
140
|
-
status: "idle",
|
|
141
|
-
last_error: "Container exited with code 1",
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
};
|
|
147
|
-
await writeFleetState(stateFile, initialState);
|
|
148
|
-
|
|
149
|
-
const state = await getScheduleState(tempDir, "my-agent", "hourly");
|
|
150
|
-
|
|
151
|
-
expect(state.last_error).toBe("Container exited with code 1");
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
describe("missing state handling", () => {
|
|
156
|
-
it("returns default state when agent does not exist", async () => {
|
|
157
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
158
|
-
const initialState: FleetState = {
|
|
159
|
-
fleet: {},
|
|
160
|
-
agents: {},
|
|
161
|
-
};
|
|
162
|
-
await writeFleetState(stateFile, initialState);
|
|
163
|
-
|
|
164
|
-
const state = await getScheduleState(tempDir, "non-existent", "hourly");
|
|
165
|
-
|
|
166
|
-
expect(state).toEqual(createDefaultScheduleState());
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it("returns default state when schedule does not exist", async () => {
|
|
170
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
171
|
-
const initialState: FleetState = {
|
|
172
|
-
fleet: {},
|
|
173
|
-
agents: {
|
|
174
|
-
"my-agent": {
|
|
175
|
-
status: "idle",
|
|
176
|
-
schedules: {
|
|
177
|
-
hourly: {
|
|
178
|
-
last_run_at: null,
|
|
179
|
-
next_run_at: null,
|
|
180
|
-
status: "idle",
|
|
181
|
-
last_error: null,
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
};
|
|
187
|
-
await writeFleetState(stateFile, initialState);
|
|
188
|
-
|
|
189
|
-
const state = await getScheduleState(tempDir, "my-agent", "non-existent");
|
|
190
|
-
|
|
191
|
-
expect(state).toEqual(createDefaultScheduleState());
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it("returns default state when agent has no schedules map", async () => {
|
|
195
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
196
|
-
const initialState: FleetState = {
|
|
197
|
-
fleet: {},
|
|
198
|
-
agents: {
|
|
199
|
-
"my-agent": {
|
|
200
|
-
status: "idle",
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
await writeFleetState(stateFile, initialState);
|
|
205
|
-
|
|
206
|
-
const state = await getScheduleState(tempDir, "my-agent", "hourly");
|
|
207
|
-
|
|
208
|
-
expect(state).toEqual(createDefaultScheduleState());
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
it("returns default state when state file does not exist", async () => {
|
|
212
|
-
const state = await getScheduleState(tempDir, "my-agent", "hourly");
|
|
213
|
-
|
|
214
|
-
expect(state).toEqual(createDefaultScheduleState());
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
describe("updateScheduleState", () => {
|
|
220
|
-
let tempDir: string;
|
|
221
|
-
|
|
222
|
-
beforeEach(async () => {
|
|
223
|
-
tempDir = await createTempDir();
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
afterEach(async () => {
|
|
227
|
-
await rm(tempDir, { recursive: true, force: true });
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
describe("updating existing schedules", () => {
|
|
231
|
-
it("updates single field of existing schedule", async () => {
|
|
232
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
233
|
-
const initialState: FleetState = {
|
|
234
|
-
fleet: {},
|
|
235
|
-
agents: {
|
|
236
|
-
"my-agent": {
|
|
237
|
-
status: "idle",
|
|
238
|
-
schedules: {
|
|
239
|
-
hourly: {
|
|
240
|
-
last_run_at: "2024-01-15T10:00:00Z",
|
|
241
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
242
|
-
status: "idle",
|
|
243
|
-
last_error: null,
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
},
|
|
247
|
-
},
|
|
248
|
-
};
|
|
249
|
-
await writeFleetState(stateFile, initialState);
|
|
250
|
-
|
|
251
|
-
const updated = await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
252
|
-
status: "running",
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
expect(updated.status).toBe("running");
|
|
256
|
-
expect(updated.last_run_at).toBe("2024-01-15T10:00:00Z");
|
|
257
|
-
expect(updated.next_run_at).toBe("2024-01-15T11:00:00Z");
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
it("updates multiple fields of existing schedule", async () => {
|
|
261
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
262
|
-
const initialState: FleetState = {
|
|
263
|
-
fleet: {},
|
|
264
|
-
agents: {
|
|
265
|
-
"my-agent": {
|
|
266
|
-
status: "idle",
|
|
267
|
-
schedules: {
|
|
268
|
-
hourly: {
|
|
269
|
-
last_run_at: null,
|
|
270
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
271
|
-
status: "idle",
|
|
272
|
-
last_error: null,
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
};
|
|
278
|
-
await writeFleetState(stateFile, initialState);
|
|
279
|
-
|
|
280
|
-
const updated = await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
281
|
-
status: "running",
|
|
282
|
-
last_run_at: "2024-01-15T11:00:00Z",
|
|
283
|
-
next_run_at: null,
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
expect(updated.status).toBe("running");
|
|
287
|
-
expect(updated.last_run_at).toBe("2024-01-15T11:00:00Z");
|
|
288
|
-
expect(updated.next_run_at).toBeNull();
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
it("can set fields to null", async () => {
|
|
292
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
293
|
-
const initialState: FleetState = {
|
|
294
|
-
fleet: {},
|
|
295
|
-
agents: {
|
|
296
|
-
"my-agent": {
|
|
297
|
-
status: "idle",
|
|
298
|
-
schedules: {
|
|
299
|
-
hourly: {
|
|
300
|
-
last_run_at: "2024-01-15T10:00:00Z",
|
|
301
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
302
|
-
status: "idle",
|
|
303
|
-
last_error: "Previous error",
|
|
304
|
-
},
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
},
|
|
308
|
-
};
|
|
309
|
-
await writeFleetState(stateFile, initialState);
|
|
310
|
-
|
|
311
|
-
const updated = await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
312
|
-
last_error: null,
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
expect(updated.last_error).toBeNull();
|
|
316
|
-
expect(updated.last_run_at).toBe("2024-01-15T10:00:00Z");
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
it("preserves other schedules when updating one", async () => {
|
|
320
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
321
|
-
const initialState: FleetState = {
|
|
322
|
-
fleet: {},
|
|
323
|
-
agents: {
|
|
324
|
-
"my-agent": {
|
|
325
|
-
status: "idle",
|
|
326
|
-
schedules: {
|
|
327
|
-
hourly: {
|
|
328
|
-
last_run_at: null,
|
|
329
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
330
|
-
status: "idle",
|
|
331
|
-
last_error: null,
|
|
332
|
-
},
|
|
333
|
-
daily: {
|
|
334
|
-
last_run_at: "2024-01-14T00:00:00Z",
|
|
335
|
-
next_run_at: "2024-01-15T00:00:00Z",
|
|
336
|
-
status: "idle",
|
|
337
|
-
last_error: null,
|
|
338
|
-
},
|
|
339
|
-
},
|
|
340
|
-
},
|
|
341
|
-
},
|
|
342
|
-
};
|
|
343
|
-
await writeFleetState(stateFile, initialState);
|
|
344
|
-
|
|
345
|
-
await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
346
|
-
status: "running",
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
const fleetState = await readFleetState(stateFile);
|
|
350
|
-
expect(fleetState.agents["my-agent"].schedules?.daily).toEqual({
|
|
351
|
-
last_run_at: "2024-01-14T00:00:00Z",
|
|
352
|
-
next_run_at: "2024-01-15T00:00:00Z",
|
|
353
|
-
status: "idle",
|
|
354
|
-
last_error: null,
|
|
355
|
-
});
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
it("preserves other agents when updating one agent's schedule", async () => {
|
|
359
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
360
|
-
const initialState: FleetState = {
|
|
361
|
-
fleet: {},
|
|
362
|
-
agents: {
|
|
363
|
-
"agent-1": {
|
|
364
|
-
status: "idle",
|
|
365
|
-
schedules: {
|
|
366
|
-
hourly: {
|
|
367
|
-
last_run_at: null,
|
|
368
|
-
next_run_at: null,
|
|
369
|
-
status: "idle",
|
|
370
|
-
last_error: null,
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
},
|
|
374
|
-
"agent-2": {
|
|
375
|
-
status: "running",
|
|
376
|
-
current_job: "job-100",
|
|
377
|
-
},
|
|
378
|
-
},
|
|
379
|
-
};
|
|
380
|
-
await writeFleetState(stateFile, initialState);
|
|
381
|
-
|
|
382
|
-
await updateScheduleState(tempDir, "agent-1", "hourly", {
|
|
383
|
-
status: "running",
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
const fleetState = await readFleetState(stateFile);
|
|
387
|
-
expect(fleetState.agents["agent-2"]).toEqual({
|
|
388
|
-
status: "running",
|
|
389
|
-
current_job: "job-100",
|
|
390
|
-
});
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
it("preserves fleet metadata when updating schedule", async () => {
|
|
394
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
395
|
-
const initialState: FleetState = {
|
|
396
|
-
fleet: { started_at: "2024-01-15T00:00:00Z" },
|
|
397
|
-
agents: {
|
|
398
|
-
"my-agent": {
|
|
399
|
-
status: "idle",
|
|
400
|
-
schedules: {
|
|
401
|
-
hourly: {
|
|
402
|
-
last_run_at: null,
|
|
403
|
-
next_run_at: null,
|
|
404
|
-
status: "idle",
|
|
405
|
-
last_error: null,
|
|
406
|
-
},
|
|
407
|
-
},
|
|
408
|
-
},
|
|
409
|
-
},
|
|
410
|
-
};
|
|
411
|
-
await writeFleetState(stateFile, initialState);
|
|
412
|
-
|
|
413
|
-
await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
414
|
-
status: "running",
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
const fleetState = await readFleetState(stateFile);
|
|
418
|
-
expect(fleetState.fleet.started_at).toBe("2024-01-15T00:00:00Z");
|
|
419
|
-
});
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
describe("creating new schedules", () => {
|
|
423
|
-
it("creates new schedule if it does not exist", async () => {
|
|
424
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
425
|
-
const initialState: FleetState = {
|
|
426
|
-
fleet: {},
|
|
427
|
-
agents: {
|
|
428
|
-
"my-agent": {
|
|
429
|
-
status: "idle",
|
|
430
|
-
schedules: {},
|
|
431
|
-
},
|
|
432
|
-
},
|
|
433
|
-
};
|
|
434
|
-
await writeFleetState(stateFile, initialState);
|
|
435
|
-
|
|
436
|
-
const updated = await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
437
|
-
status: "running",
|
|
438
|
-
last_run_at: "2024-01-15T10:00:00Z",
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
expect(updated.status).toBe("running");
|
|
442
|
-
expect(updated.last_run_at).toBe("2024-01-15T10:00:00Z");
|
|
443
|
-
expect(updated.next_run_at).toBeNull();
|
|
444
|
-
expect(updated.last_error).toBeNull();
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
it("creates schedules map if agent has none", async () => {
|
|
448
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
449
|
-
const initialState: FleetState = {
|
|
450
|
-
fleet: {},
|
|
451
|
-
agents: {
|
|
452
|
-
"my-agent": {
|
|
453
|
-
status: "idle",
|
|
454
|
-
},
|
|
455
|
-
},
|
|
456
|
-
};
|
|
457
|
-
await writeFleetState(stateFile, initialState);
|
|
458
|
-
|
|
459
|
-
const updated = await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
460
|
-
status: "running",
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
expect(updated.status).toBe("running");
|
|
464
|
-
|
|
465
|
-
const fleetState = await readFleetState(stateFile);
|
|
466
|
-
expect(fleetState.agents["my-agent"].schedules).toBeDefined();
|
|
467
|
-
expect(fleetState.agents["my-agent"].schedules?.hourly).toBeDefined();
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
it("creates agent if it does not exist", async () => {
|
|
471
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
472
|
-
const initialState: FleetState = {
|
|
473
|
-
fleet: {},
|
|
474
|
-
agents: {},
|
|
475
|
-
};
|
|
476
|
-
await writeFleetState(stateFile, initialState);
|
|
477
|
-
|
|
478
|
-
const updated = await updateScheduleState(tempDir, "new-agent", "hourly", {
|
|
479
|
-
status: "running",
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
expect(updated.status).toBe("running");
|
|
483
|
-
|
|
484
|
-
const fleetState = await readFleetState(stateFile);
|
|
485
|
-
expect(fleetState.agents["new-agent"]).toBeDefined();
|
|
486
|
-
expect(fleetState.agents["new-agent"].status).toBe("idle");
|
|
487
|
-
expect(fleetState.agents["new-agent"].schedules?.hourly).toBeDefined();
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
it("creates state file if it does not exist", async () => {
|
|
491
|
-
const updated = await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
492
|
-
status: "running",
|
|
493
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
expect(updated.status).toBe("running");
|
|
497
|
-
expect(updated.next_run_at).toBe("2024-01-15T11:00:00Z");
|
|
498
|
-
|
|
499
|
-
const fleetState = await readFleetState(join(tempDir, "state.yaml"));
|
|
500
|
-
expect(fleetState.agents["my-agent"].schedules?.hourly).toBeDefined();
|
|
501
|
-
});
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
describe("persistence", () => {
|
|
505
|
-
it("persists updates to file", async () => {
|
|
506
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
507
|
-
const initialState: FleetState = {
|
|
508
|
-
fleet: {},
|
|
509
|
-
agents: {
|
|
510
|
-
"my-agent": {
|
|
511
|
-
status: "idle",
|
|
512
|
-
},
|
|
513
|
-
},
|
|
514
|
-
};
|
|
515
|
-
await writeFleetState(stateFile, initialState);
|
|
516
|
-
|
|
517
|
-
await updateScheduleState(tempDir, "my-agent", "hourly", {
|
|
518
|
-
status: "running",
|
|
519
|
-
last_run_at: "2024-01-15T10:00:00Z",
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
// Read from file directly to verify persistence
|
|
523
|
-
const content = await readFile(stateFile, "utf-8");
|
|
524
|
-
expect(content).toContain("hourly:");
|
|
525
|
-
expect(content).toContain("status: running");
|
|
526
|
-
expect(content).toContain("last_run_at:");
|
|
527
|
-
});
|
|
528
|
-
});
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
describe("getAgentScheduleStates", () => {
|
|
532
|
-
let tempDir: string;
|
|
533
|
-
|
|
534
|
-
beforeEach(async () => {
|
|
535
|
-
tempDir = await createTempDir();
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
afterEach(async () => {
|
|
539
|
-
await rm(tempDir, { recursive: true, force: true });
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
describe("existing schedules", () => {
|
|
543
|
-
it("returns all schedules for an agent", async () => {
|
|
544
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
545
|
-
const initialState: FleetState = {
|
|
546
|
-
fleet: {},
|
|
547
|
-
agents: {
|
|
548
|
-
"my-agent": {
|
|
549
|
-
status: "idle",
|
|
550
|
-
schedules: {
|
|
551
|
-
hourly: {
|
|
552
|
-
last_run_at: "2024-01-15T10:00:00Z",
|
|
553
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
554
|
-
status: "idle",
|
|
555
|
-
last_error: null,
|
|
556
|
-
},
|
|
557
|
-
daily: {
|
|
558
|
-
last_run_at: "2024-01-14T00:00:00Z",
|
|
559
|
-
next_run_at: "2024-01-15T00:00:00Z",
|
|
560
|
-
status: "idle",
|
|
561
|
-
last_error: null,
|
|
562
|
-
},
|
|
563
|
-
},
|
|
564
|
-
},
|
|
565
|
-
},
|
|
566
|
-
};
|
|
567
|
-
await writeFleetState(stateFile, initialState);
|
|
568
|
-
|
|
569
|
-
const schedules = await getAgentScheduleStates(tempDir, "my-agent");
|
|
570
|
-
|
|
571
|
-
expect(Object.keys(schedules)).toHaveLength(2);
|
|
572
|
-
expect(schedules.hourly).toBeDefined();
|
|
573
|
-
expect(schedules.daily).toBeDefined();
|
|
574
|
-
expect(schedules.hourly.last_run_at).toBe("2024-01-15T10:00:00Z");
|
|
575
|
-
expect(schedules.daily.last_run_at).toBe("2024-01-14T00:00:00Z");
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
it("returns single schedule for agent with one schedule", async () => {
|
|
579
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
580
|
-
const initialState: FleetState = {
|
|
581
|
-
fleet: {},
|
|
582
|
-
agents: {
|
|
583
|
-
"my-agent": {
|
|
584
|
-
status: "idle",
|
|
585
|
-
schedules: {
|
|
586
|
-
hourly: {
|
|
587
|
-
last_run_at: null,
|
|
588
|
-
next_run_at: "2024-01-15T11:00:00Z",
|
|
589
|
-
status: "idle",
|
|
590
|
-
last_error: null,
|
|
591
|
-
},
|
|
592
|
-
},
|
|
593
|
-
},
|
|
594
|
-
},
|
|
595
|
-
};
|
|
596
|
-
await writeFleetState(stateFile, initialState);
|
|
597
|
-
|
|
598
|
-
const schedules = await getAgentScheduleStates(tempDir, "my-agent");
|
|
599
|
-
|
|
600
|
-
expect(Object.keys(schedules)).toHaveLength(1);
|
|
601
|
-
expect(schedules.hourly).toBeDefined();
|
|
602
|
-
});
|
|
603
|
-
});
|
|
604
|
-
|
|
605
|
-
describe("missing state handling", () => {
|
|
606
|
-
it("returns empty object when agent does not exist", async () => {
|
|
607
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
608
|
-
const initialState: FleetState = {
|
|
609
|
-
fleet: {},
|
|
610
|
-
agents: {},
|
|
611
|
-
};
|
|
612
|
-
await writeFleetState(stateFile, initialState);
|
|
613
|
-
|
|
614
|
-
const schedules = await getAgentScheduleStates(tempDir, "non-existent");
|
|
615
|
-
|
|
616
|
-
expect(schedules).toEqual({});
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
it("returns empty object when agent has no schedules map", async () => {
|
|
620
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
621
|
-
const initialState: FleetState = {
|
|
622
|
-
fleet: {},
|
|
623
|
-
agents: {
|
|
624
|
-
"my-agent": {
|
|
625
|
-
status: "idle",
|
|
626
|
-
},
|
|
627
|
-
},
|
|
628
|
-
};
|
|
629
|
-
await writeFleetState(stateFile, initialState);
|
|
630
|
-
|
|
631
|
-
const schedules = await getAgentScheduleStates(tempDir, "my-agent");
|
|
632
|
-
|
|
633
|
-
expect(schedules).toEqual({});
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
it("returns empty object when state file does not exist", async () => {
|
|
637
|
-
const schedules = await getAgentScheduleStates(tempDir, "my-agent");
|
|
638
|
-
|
|
639
|
-
expect(schedules).toEqual({});
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
it("returns empty object when schedules map is empty", async () => {
|
|
643
|
-
const stateFile = join(tempDir, "state.yaml");
|
|
644
|
-
const initialState: FleetState = {
|
|
645
|
-
fleet: {},
|
|
646
|
-
agents: {
|
|
647
|
-
"my-agent": {
|
|
648
|
-
status: "idle",
|
|
649
|
-
schedules: {},
|
|
650
|
-
},
|
|
651
|
-
},
|
|
652
|
-
};
|
|
653
|
-
await writeFleetState(stateFile, initialState);
|
|
654
|
-
|
|
655
|
-
const schedules = await getAgentScheduleStates(tempDir, "my-agent");
|
|
656
|
-
|
|
657
|
-
expect(schedules).toEqual({});
|
|
658
|
-
});
|
|
659
|
-
});
|
|
660
|
-
});
|
|
661
|
-
|
|
662
|
-
describe("createDefaultScheduleState", () => {
|
|
663
|
-
it("returns correct default values", () => {
|
|
664
|
-
const state = createDefaultScheduleState();
|
|
665
|
-
|
|
666
|
-
expect(state.last_run_at).toBeNull();
|
|
667
|
-
expect(state.next_run_at).toBeNull();
|
|
668
|
-
expect(state.status).toBe("idle");
|
|
669
|
-
expect(state.last_error).toBeNull();
|
|
670
|
-
});
|
|
671
|
-
});
|