@shivaedev/work-fleet 0.3.0 → 0.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/CHANGELOG.md +21 -0
- package/README.md +3 -3
- package/dist/engine/readRetry.d.ts +1 -0
- package/dist/engine/readRetry.d.ts.map +1 -1
- package/dist/engine/readRetry.js +2 -1
- package/dist/engine/readRetry.js.map +1 -1
- package/dist/host/cliOptions.d.ts +1 -1
- package/dist/host/cliOptions.d.ts.map +1 -1
- package/dist/host/cliOptions.js +1 -1
- package/dist/host/cliOptions.js.map +1 -1
- package/dist/host/commands.d.ts +0 -1089
- package/dist/host/commands.d.ts.map +1 -1
- package/dist/host/commands.js +1 -13
- package/dist/host/commands.js.map +1 -1
- package/dist/host/config.d.ts +2 -63
- package/dist/host/config.d.ts.map +1 -1
- package/dist/host/config.js +4 -34
- package/dist/host/config.js.map +1 -1
- package/dist/host/configFile.d.ts +66 -0
- package/dist/host/configFile.d.ts.map +1 -0
- package/dist/host/configFile.js +37 -0
- package/dist/host/configFile.js.map +1 -0
- package/dist/host/configSettings.d.ts +3 -1
- package/dist/host/configSettings.d.ts.map +1 -1
- package/dist/host/configSettings.js +2 -0
- package/dist/host/configSettings.js.map +1 -1
- package/dist/host/daemon.d.ts +1 -0
- package/dist/host/daemon.d.ts.map +1 -1
- package/dist/host/daemonClient.d.ts +1058 -1057
- package/dist/host/daemonClient.d.ts.map +1 -1
- package/dist/host/daemonContract.d.ts +3 -0
- package/dist/host/daemonContract.d.ts.map +1 -1
- package/dist/host/daemonHandlers.d.ts.map +1 -1
- package/dist/host/daemonHandlers.js +1 -1
- package/dist/host/daemonHandlers.js.map +1 -1
- package/dist/host/{status.d.ts → fleetStatus.d.ts} +1 -3
- package/dist/host/fleetStatus.d.ts.map +1 -0
- package/dist/host/{status.js → fleetStatus.js} +1 -5
- package/dist/host/fleetStatus.js.map +1 -0
- package/dist/host/liveConfig.d.ts.map +1 -1
- package/dist/host/liveConfig.js +2 -1
- package/dist/host/liveConfig.js.map +1 -1
- package/dist/host/releaseWork.d.ts.map +1 -1
- package/dist/host/releaseWork.js +2 -2
- package/dist/host/releaseWork.js.map +1 -1
- package/dist/host/runtime.d.ts.map +1 -1
- package/dist/host/runtime.js +1 -0
- package/dist/host/runtime.js.map +1 -1
- package/dist/packageInfo.d.ts +1 -1
- package/dist/packageInfo.js +1 -1
- package/dist/policy.d.ts +1 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js.map +1 -1
- package/dist/scheduling/areas.d.ts.map +1 -1
- package/dist/scheduling/areas.js +1 -0
- package/dist/scheduling/areas.js.map +1 -1
- package/package.json +5 -5
- package/src/engine/readRetry.ts +3 -1
- package/src/host/cliOptions.ts +1 -1
- package/src/host/commands.ts +1 -16
- package/src/host/config.ts +5 -38
- package/src/host/configFile.ts +40 -0
- package/src/host/configSettings.ts +2 -0
- package/src/host/daemonHandlers.ts +1 -1
- package/src/host/{status.ts → fleetStatus.ts} +0 -5
- package/src/host/liveConfig.ts +2 -1
- package/src/host/releaseWork.ts +5 -2
- package/src/host/runtime.ts +1 -0
- package/src/packageInfo.ts +1 -1
- package/src/policy.ts +1 -0
- package/src/scheduling/areas.ts +1 -0
- package/dist/host/reassignWork.d.ts +0 -549
- package/dist/host/reassignWork.d.ts.map +0 -1
- package/dist/host/reassignWork.js +0 -9
- package/dist/host/reassignWork.js.map +0 -1
- package/dist/host/status.d.ts.map +0 -1
- package/dist/host/status.js.map +0 -1
- package/src/host/reassignWork.ts +0 -17
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as FileSystem from "effect/FileSystem";
|
|
3
|
+
import * as Path from "effect/Path";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import * as SchemaIssue from "effect/SchemaIssue";
|
|
6
|
+
import { HostConfig, HostConfigRejected, HostFailure, resolveHost } from "#host/config.ts";
|
|
7
|
+
import { CONFIG_FILE } from "#host/defaults.ts";
|
|
8
|
+
|
|
9
|
+
export const readHostConfig = Effect.fn("FleetHost.readHostConfig")(function* (file: string) {
|
|
10
|
+
const fs = yield* FileSystem.FileSystem;
|
|
11
|
+
const text = yield* fs
|
|
12
|
+
.readFileString(file)
|
|
13
|
+
.pipe(Effect.mapError(() => new HostConfigRejected({ file, message: `Fleet host configuration is missing or unreadable: ${file}` })));
|
|
14
|
+
const config = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(HostConfig))(text).pipe(
|
|
15
|
+
Effect.mapError((error) => {
|
|
16
|
+
const field = SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues[0]?.path?.map(String).join(".");
|
|
17
|
+
return new HostConfigRejected({
|
|
18
|
+
...(field === undefined || field === "" ? {} : { field }),
|
|
19
|
+
file,
|
|
20
|
+
message: `Fleet host configuration ${file} is invalid: ${error.message}`,
|
|
21
|
+
});
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
24
|
+
if (config.provider === "cloud" && (config.cloud === undefined || config.worker === undefined)) {
|
|
25
|
+
return yield* new HostConfigRejected({
|
|
26
|
+
field: config.cloud === undefined ? "cloud" : "worker",
|
|
27
|
+
file,
|
|
28
|
+
message: `Fleet host configuration ${file} selects provider "cloud" without cloud and worker settings`,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return config;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const loadHost = Effect.fn("FleetHost.loadHost")(function* (board: string, configPath?: string) {
|
|
35
|
+
const path = yield* Path.Path;
|
|
36
|
+
const boardDir = path.resolve(board);
|
|
37
|
+
const file = configPath === undefined ? path.join(boardDir, CONFIG_FILE) : path.resolve(configPath);
|
|
38
|
+
const config = yield* readHostConfig(file).pipe(Effect.mapError((rejected) => new HostFailure({ message: rejected.message })));
|
|
39
|
+
return resolveHost(boardDir, config, file);
|
|
40
|
+
});
|
|
@@ -12,6 +12,7 @@ export const RELOADABLE_SETTINGS = [
|
|
|
12
12
|
"launch",
|
|
13
13
|
"openPullRequests",
|
|
14
14
|
"quota",
|
|
15
|
+
"readRetryMs",
|
|
15
16
|
"stallMinutes",
|
|
16
17
|
"worker.reviewerGuidance",
|
|
17
18
|
"worker.workerGuidance",
|
|
@@ -50,6 +51,7 @@ function appliedSettings(host: FleetHost): HostConfig {
|
|
|
50
51
|
...(host.openPullRequests === undefined ? {} : { openPullRequests: host.openPullRequests }),
|
|
51
52
|
provider: host.provider,
|
|
52
53
|
quota: host.quota,
|
|
54
|
+
readRetryMs: host.readRetryMs,
|
|
53
55
|
repository: host.repository,
|
|
54
56
|
...(host.result === undefined ? {} : { result: host.result }),
|
|
55
57
|
stallMinutes: host.stallMinutes,
|
|
@@ -7,10 +7,10 @@ import { ClientContract } from "#host/daemonContract.ts";
|
|
|
7
7
|
import { daemonDiagnostics } from "#host/daemonDiagnostics.ts";
|
|
8
8
|
import { daemonSnapshots } from "#host/daemonSnapshots.ts";
|
|
9
9
|
import { dispatchRequests } from "#host/dispatchRequests.ts";
|
|
10
|
+
import { fleetStatus } from "#host/fleetStatus.ts";
|
|
10
11
|
import { LiveConfig } from "#host/liveConfig.ts";
|
|
11
12
|
import { nameStoredThreads } from "#host/nameThreads.ts";
|
|
12
13
|
import { decisionResponses, releaseItems } from "#host/releaseWork.ts";
|
|
13
|
-
import { fleetStatus } from "#host/status.ts";
|
|
14
14
|
|
|
15
15
|
export const daemonHandlers = Effect.fn("FleetDaemon.daemonHandlers")(function* (host: FleetHost) {
|
|
16
16
|
const scope = yield* Effect.scope;
|
|
@@ -2,7 +2,6 @@ import { Effect, Schema } from "effect";
|
|
|
2
2
|
import { makeRepository } from "@shivaedev/effect-sql/repository.ts";
|
|
3
3
|
import { views } from "#engine/views.ts";
|
|
4
4
|
import type { FleetHost } from "#host/config.ts";
|
|
5
|
-
import { renderStatus as render } from "#host/renderStatus.ts";
|
|
6
5
|
import { FleetRecord } from "#model.ts";
|
|
7
6
|
import { dispatchStore } from "#storage/dispatchStore.ts";
|
|
8
7
|
import { recordModel } from "#storage/model.ts";
|
|
@@ -10,10 +9,6 @@ import { readRecords } from "#storage/readRecords.ts";
|
|
|
10
9
|
import { recordShape } from "#storage/recordShape.ts";
|
|
11
10
|
import { recordValues } from "#storage/recordValue.ts";
|
|
12
11
|
|
|
13
|
-
export function renderStatus(current: Parameters<typeof render>[0]) {
|
|
14
|
-
return render(current);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
12
|
export const fleetStatus = Effect.fn("FleetHost.fleetStatus")(function* (host: FleetHost, workId?: string) {
|
|
18
13
|
const repository = yield* makeRepository(recordModel(), {
|
|
19
14
|
idColumn: "work_id",
|
package/src/host/liveConfig.ts
CHANGED
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
Stream,
|
|
16
16
|
SubscriptionRef,
|
|
17
17
|
} from "effect";
|
|
18
|
-
import { type FleetHost, HostConfig, HostConfigRejected, type HostFailure,
|
|
18
|
+
import { type FleetHost, HostConfig, HostConfigRejected, type HostFailure, resolveHost } from "#host/config.ts";
|
|
19
|
+
import { readHostConfig } from "#host/configFile.ts";
|
|
19
20
|
import { changedSettings, withReloadable } from "#host/configSettings.ts";
|
|
20
21
|
import { hostGuidance } from "#host/guidance.ts";
|
|
21
22
|
|
package/src/host/releaseWork.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { recordDecisionResponse } from "#host/recordDecisionResponse.ts";
|
|
|
10
10
|
import { executing } from "#model.ts";
|
|
11
11
|
|
|
12
12
|
const { searchSnapshot, watchChanges } = board;
|
|
13
|
-
const {
|
|
13
|
+
const { Responses, Workspace, WorkspaceConfig } = responses;
|
|
14
14
|
|
|
15
15
|
export function releaseWork(host: FleetHost, workIds: readonly string[], parts: HostParts = productionParts(host)) {
|
|
16
16
|
return withDecisionResponses(host, releaseItems(host, workIds)).pipe(Effect.provide(hostLayer(host, parts)));
|
|
@@ -27,7 +27,10 @@ export function decisionResponses(host: FleetHost) {
|
|
|
27
27
|
const changes = yield* watchChanges(host.boardDir);
|
|
28
28
|
const index = (yield* searchSnapshot(host.boardDir, undefined, changes)).pipe(Effect.provide(NodeServices.layer));
|
|
29
29
|
yield* index.pipe(Effect.ignore, Effect.forkScoped);
|
|
30
|
-
return Responses.layer.pipe(
|
|
30
|
+
return Responses.layer.pipe(
|
|
31
|
+
Layer.provide(Workspace.layer),
|
|
32
|
+
Layer.provide(Layer.succeed(WorkspaceConfig, { changes, index, root: host.boardDir, writable: true })),
|
|
33
|
+
);
|
|
31
34
|
}),
|
|
32
35
|
);
|
|
33
36
|
}
|
package/src/host/runtime.ts
CHANGED
|
@@ -51,6 +51,7 @@ export function hostPolicy(host: FleetHost) {
|
|
|
51
51
|
operationId: () => crypto.randomUUID(),
|
|
52
52
|
quota: { expiresAt: 0, observedAt: 0 },
|
|
53
53
|
readGuidance: (role) => guidance[role].pipe(Effect.mapError((error) => new ServiceUnavailable({ message: error.message }))),
|
|
54
|
+
readRetryMs: applied.readRetryMs,
|
|
54
55
|
refreshQuota: refreshQuota(applied),
|
|
55
56
|
stallMinutes: applied.stallMinutes,
|
|
56
57
|
...(applied.worker === undefined ? {} : { sharedEnvironment: applied.worker.sharedEnvironment }),
|
package/src/packageInfo.ts
CHANGED
package/src/policy.ts
CHANGED
|
@@ -120,6 +120,7 @@ export interface FleetConfiguration {
|
|
|
120
120
|
readonly operationId: () => string;
|
|
121
121
|
readonly quota: { readonly available?: number; readonly observedAt: number; readonly expiresAt: number };
|
|
122
122
|
readonly readGuidance?: (role: "worker" | "reviewer") => Effect.Effect<string | undefined, FleetError>;
|
|
123
|
+
readonly readRetryMs?: number;
|
|
123
124
|
readonly refreshQuota?: () => Effect.Effect<FleetConfiguration["quota"], FleetError>;
|
|
124
125
|
readonly reviewerGuidance?: string;
|
|
125
126
|
readonly sharedEnvironment?: string;
|
package/src/scheduling/areas.ts
CHANGED
|
@@ -27,6 +27,7 @@ function holdsAreas(record: FleetRecord, now: number, mergeWaitMs: number): bool
|
|
|
27
27
|
return (
|
|
28
28
|
!["completed", "released"].includes(record.stage)
|
|
29
29
|
&& record.attempts.length > 0
|
|
30
|
+
&& (record.stage !== "prepared" || executing(record))
|
|
30
31
|
&& record.mergeAreasReleased !== true
|
|
31
32
|
&& !mergeWaitExpired(record, now, mergeWaitMs)
|
|
32
33
|
);
|