@jamesaphoenix/tx-core 0.4.1
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/db.d.ts +42 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +46 -0
- package/dist/db.js.map +1 -0
- package/dist/errors.d.ts +231 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +139 -0
- package/dist/errors.js.map +1 -0
- package/dist/id.d.ts +6 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +21 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/layer.d.ts +50 -0
- package/dist/layer.d.ts.map +1 -0
- package/dist/layer.js +155 -0
- package/dist/layer.js.map +1 -0
- package/dist/mappers/anchor.d.ts +14 -0
- package/dist/mappers/anchor.d.ts.map +1 -0
- package/dist/mappers/anchor.js +38 -0
- package/dist/mappers/anchor.js.map +1 -0
- package/dist/mappers/attempt.d.ts +15 -0
- package/dist/mappers/attempt.d.ts.map +1 -0
- package/dist/mappers/attempt.js +23 -0
- package/dist/mappers/attempt.js.map +1 -0
- package/dist/mappers/candidate.d.ts +23 -0
- package/dist/mappers/candidate.d.ts.map +1 -0
- package/dist/mappers/candidate.js +53 -0
- package/dist/mappers/candidate.js.map +1 -0
- package/dist/mappers/claim.d.ts +30 -0
- package/dist/mappers/claim.d.ts.map +1 -0
- package/dist/mappers/claim.js +32 -0
- package/dist/mappers/claim.js.map +1 -0
- package/dist/mappers/deduplication.d.ts +39 -0
- package/dist/mappers/deduplication.d.ts.map +1 -0
- package/dist/mappers/deduplication.js +53 -0
- package/dist/mappers/deduplication.js.map +1 -0
- package/dist/mappers/edge.d.ts +10 -0
- package/dist/mappers/edge.d.ts.map +1 -0
- package/dist/mappers/edge.js +19 -0
- package/dist/mappers/edge.js.map +1 -0
- package/dist/mappers/file-learning.d.ts +14 -0
- package/dist/mappers/file-learning.d.ts.map +1 -0
- package/dist/mappers/file-learning.js +75 -0
- package/dist/mappers/file-learning.js.map +1 -0
- package/dist/mappers/index.d.ts +17 -0
- package/dist/mappers/index.d.ts.map +1 -0
- package/dist/mappers/index.js +30 -0
- package/dist/mappers/index.js.map +1 -0
- package/dist/mappers/learning.d.ts +19 -0
- package/dist/mappers/learning.d.ts.map +1 -0
- package/dist/mappers/learning.js +41 -0
- package/dist/mappers/learning.js.map +1 -0
- package/dist/mappers/orchestrator-state.d.ts +33 -0
- package/dist/mappers/orchestrator-state.d.ts.map +1 -0
- package/dist/mappers/orchestrator-state.js +34 -0
- package/dist/mappers/orchestrator-state.js.map +1 -0
- package/dist/mappers/run.d.ts +32 -0
- package/dist/mappers/run.d.ts.map +1 -0
- package/dist/mappers/run.js +64 -0
- package/dist/mappers/run.js.map +1 -0
- package/dist/mappers/task.d.ts +23 -0
- package/dist/mappers/task.d.ts.map +1 -0
- package/dist/mappers/task.js +54 -0
- package/dist/mappers/task.js.map +1 -0
- package/dist/mappers/tracked-project.d.ts +15 -0
- package/dist/mappers/tracked-project.d.ts.map +1 -0
- package/dist/mappers/tracked-project.js +23 -0
- package/dist/mappers/tracked-project.js.map +1 -0
- package/dist/mappers/worker.d.ts +33 -0
- package/dist/mappers/worker.d.ts.map +1 -0
- package/dist/mappers/worker.js +35 -0
- package/dist/mappers/worker.js.map +1 -0
- package/dist/repo/anchor-repo.d.ts +52 -0
- package/dist/repo/anchor-repo.d.ts.map +1 -0
- package/dist/repo/anchor-repo.js +204 -0
- package/dist/repo/anchor-repo.js.map +1 -0
- package/dist/repo/attempt-repo.d.ts +25 -0
- package/dist/repo/attempt-repo.d.ts.map +1 -0
- package/dist/repo/attempt-repo.js +78 -0
- package/dist/repo/attempt-repo.js.map +1 -0
- package/dist/repo/candidate-repo.d.ts +16 -0
- package/dist/repo/candidate-repo.d.ts.map +1 -0
- package/dist/repo/candidate-repo.js +143 -0
- package/dist/repo/candidate-repo.js.map +1 -0
- package/dist/repo/claim-repo.d.ts +17 -0
- package/dist/repo/claim-repo.d.ts.map +1 -0
- package/dist/repo/claim-repo.js +62 -0
- package/dist/repo/claim-repo.js.map +1 -0
- package/dist/repo/deduplication-repo.d.ts +37 -0
- package/dist/repo/deduplication-repo.d.ts.map +1 -0
- package/dist/repo/deduplication-repo.js +133 -0
- package/dist/repo/deduplication-repo.js.map +1 -0
- package/dist/repo/dep-repo.d.ts +19 -0
- package/dist/repo/dep-repo.d.ts.map +1 -0
- package/dist/repo/dep-repo.js +104 -0
- package/dist/repo/dep-repo.js.map +1 -0
- package/dist/repo/edge-repo.d.ts +26 -0
- package/dist/repo/edge-repo.d.ts.map +1 -0
- package/dist/repo/edge-repo.js +227 -0
- package/dist/repo/edge-repo.js.map +1 -0
- package/dist/repo/file-learning-repo.d.ts +17 -0
- package/dist/repo/file-learning-repo.d.ts.map +1 -0
- package/dist/repo/file-learning-repo.js +60 -0
- package/dist/repo/file-learning-repo.js.map +1 -0
- package/dist/repo/index.d.ts +18 -0
- package/dist/repo/index.d.ts.map +1 -0
- package/dist/repo/index.js +18 -0
- package/dist/repo/index.js.map +1 -0
- package/dist/repo/learning-repo.d.ts +31 -0
- package/dist/repo/learning-repo.d.ts.map +1 -0
- package/dist/repo/learning-repo.js +165 -0
- package/dist/repo/learning-repo.js.map +1 -0
- package/dist/repo/orchestrator-state-repo.d.ts +27 -0
- package/dist/repo/orchestrator-state-repo.d.ts.map +1 -0
- package/dist/repo/orchestrator-state-repo.js +96 -0
- package/dist/repo/orchestrator-state-repo.js.map +1 -0
- package/dist/repo/run-repo.d.ts +31 -0
- package/dist/repo/run-repo.d.ts.map +1 -0
- package/dist/repo/run-repo.js +132 -0
- package/dist/repo/run-repo.js.map +1 -0
- package/dist/repo/task-repo.d.ts +21 -0
- package/dist/repo/task-repo.d.ts.map +1 -0
- package/dist/repo/task-repo.js +169 -0
- package/dist/repo/task-repo.js.map +1 -0
- package/dist/repo/tracked-project-repo.d.ts +16 -0
- package/dist/repo/tracked-project-repo.d.ts.map +1 -0
- package/dist/repo/tracked-project-repo.js +54 -0
- package/dist/repo/tracked-project-repo.js.map +1 -0
- package/dist/repo/worker-repo.d.ts +19 -0
- package/dist/repo/worker-repo.d.ts.map +1 -0
- package/dist/repo/worker-repo.js +72 -0
- package/dist/repo/worker-repo.js.map +1 -0
- package/dist/schemas/index.d.ts +8 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +7 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/sync.d.ts +296 -0
- package/dist/schemas/sync.d.ts.map +1 -0
- package/dist/schemas/sync.js +146 -0
- package/dist/schemas/sync.js.map +1 -0
- package/dist/schemas/worker.d.ts +77 -0
- package/dist/schemas/worker.d.ts.map +1 -0
- package/dist/schemas/worker.js +80 -0
- package/dist/schemas/worker.js.map +1 -0
- package/dist/services/anchor-service.d.ts +147 -0
- package/dist/services/anchor-service.d.ts.map +1 -0
- package/dist/services/anchor-service.js +540 -0
- package/dist/services/anchor-service.js.map +1 -0
- package/dist/services/anchor-verification.d.ts +94 -0
- package/dist/services/anchor-verification.d.ts.map +1 -0
- package/dist/services/anchor-verification.js +617 -0
- package/dist/services/anchor-verification.js.map +1 -0
- package/dist/services/ast-grep-service.d.ts +58 -0
- package/dist/services/ast-grep-service.d.ts.map +1 -0
- package/dist/services/ast-grep-service.js +356 -0
- package/dist/services/ast-grep-service.js.map +1 -0
- package/dist/services/attempt-service.d.ts +24 -0
- package/dist/services/attempt-service.d.ts.map +1 -0
- package/dist/services/attempt-service.js +55 -0
- package/dist/services/attempt-service.js.map +1 -0
- package/dist/services/auto-sync-service.d.ts +56 -0
- package/dist/services/auto-sync-service.d.ts.map +1 -0
- package/dist/services/auto-sync-service.js +66 -0
- package/dist/services/auto-sync-service.js.map +1 -0
- package/dist/services/candidate-extractor-service.d.ts +56 -0
- package/dist/services/candidate-extractor-service.d.ts.map +1 -0
- package/dist/services/candidate-extractor-service.js +365 -0
- package/dist/services/candidate-extractor-service.js.map +1 -0
- package/dist/services/claim-service.d.ts +52 -0
- package/dist/services/claim-service.d.ts.map +1 -0
- package/dist/services/claim-service.js +134 -0
- package/dist/services/claim-service.js.map +1 -0
- package/dist/services/daemon-service.d.ts +214 -0
- package/dist/services/daemon-service.d.ts.map +1 -0
- package/dist/services/daemon-service.js +522 -0
- package/dist/services/daemon-service.js.map +1 -0
- package/dist/services/deduplication-service.d.ts +67 -0
- package/dist/services/deduplication-service.d.ts.map +1 -0
- package/dist/services/deduplication-service.js +145 -0
- package/dist/services/deduplication-service.js.map +1 -0
- package/dist/services/dep-service.d.ts +14 -0
- package/dist/services/dep-service.d.ts.map +1 -0
- package/dist/services/dep-service.js +34 -0
- package/dist/services/dep-service.js.map +1 -0
- package/dist/services/diversifier-service.d.ts +46 -0
- package/dist/services/diversifier-service.d.ts.map +1 -0
- package/dist/services/diversifier-service.js +197 -0
- package/dist/services/diversifier-service.js.map +1 -0
- package/dist/services/edge-service.d.ts +78 -0
- package/dist/services/edge-service.d.ts.map +1 -0
- package/dist/services/edge-service.js +158 -0
- package/dist/services/edge-service.js.map +1 -0
- package/dist/services/embedding-service.d.ts +138 -0
- package/dist/services/embedding-service.d.ts.map +1 -0
- package/dist/services/embedding-service.js +318 -0
- package/dist/services/embedding-service.js.map +1 -0
- package/dist/services/feedback-tracker.d.ts +64 -0
- package/dist/services/feedback-tracker.d.ts.map +1 -0
- package/dist/services/feedback-tracker.js +110 -0
- package/dist/services/feedback-tracker.js.map +1 -0
- package/dist/services/file-learning-service.d.ts +17 -0
- package/dist/services/file-learning-service.d.ts.map +1 -0
- package/dist/services/file-learning-service.js +41 -0
- package/dist/services/file-learning-service.js.map +1 -0
- package/dist/services/file-watcher-service.d.ts +141 -0
- package/dist/services/file-watcher-service.d.ts.map +1 -0
- package/dist/services/file-watcher-service.js +278 -0
- package/dist/services/file-watcher-service.js.map +1 -0
- package/dist/services/graph-expansion.d.ts +155 -0
- package/dist/services/graph-expansion.d.ts.map +1 -0
- package/dist/services/graph-expansion.js +466 -0
- package/dist/services/graph-expansion.js.map +1 -0
- package/dist/services/hierarchy-service.d.ts +16 -0
- package/dist/services/hierarchy-service.d.ts.map +1 -0
- package/dist/services/hierarchy-service.js +66 -0
- package/dist/services/hierarchy-service.js.map +1 -0
- package/dist/services/index.d.ts +36 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +36 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/learning-service.d.ts +39 -0
- package/dist/services/learning-service.d.ts.map +1 -0
- package/dist/services/learning-service.js +151 -0
- package/dist/services/learning-service.js.map +1 -0
- package/dist/services/migration-service.d.ts +67 -0
- package/dist/services/migration-service.d.ts.map +1 -0
- package/dist/services/migration-service.js +144 -0
- package/dist/services/migration-service.js.map +1 -0
- package/dist/services/orchestrator-service.d.ts +52 -0
- package/dist/services/orchestrator-service.d.ts.map +1 -0
- package/dist/services/orchestrator-service.js +203 -0
- package/dist/services/orchestrator-service.js.map +1 -0
- package/dist/services/promotion-service.d.ts +67 -0
- package/dist/services/promotion-service.d.ts.map +1 -0
- package/dist/services/promotion-service.js +151 -0
- package/dist/services/promotion-service.js.map +1 -0
- package/dist/services/query-expansion-service.d.ts +55 -0
- package/dist/services/query-expansion-service.d.ts.map +1 -0
- package/dist/services/query-expansion-service.js +174 -0
- package/dist/services/query-expansion-service.js.map +1 -0
- package/dist/services/ready-service.d.ts +16 -0
- package/dist/services/ready-service.d.ts.map +1 -0
- package/dist/services/ready-service.js +70 -0
- package/dist/services/ready-service.js.map +1 -0
- package/dist/services/reranker-service.d.ts +51 -0
- package/dist/services/reranker-service.d.ts.map +1 -0
- package/dist/services/reranker-service.js +128 -0
- package/dist/services/reranker-service.js.map +1 -0
- package/dist/services/retriever-service.d.ts +49 -0
- package/dist/services/retriever-service.d.ts.map +1 -0
- package/dist/services/retriever-service.js +419 -0
- package/dist/services/retriever-service.js.map +1 -0
- package/dist/services/score-service.d.ts +43 -0
- package/dist/services/score-service.d.ts.map +1 -0
- package/dist/services/score-service.js +82 -0
- package/dist/services/score-service.js.map +1 -0
- package/dist/services/swarm-verification.d.ts +104 -0
- package/dist/services/swarm-verification.d.ts.map +1 -0
- package/dist/services/swarm-verification.js +400 -0
- package/dist/services/swarm-verification.js.map +1 -0
- package/dist/services/sync-service.d.ts +115 -0
- package/dist/services/sync-service.d.ts.map +1 -0
- package/dist/services/sync-service.js +350 -0
- package/dist/services/sync-service.js.map +1 -0
- package/dist/services/task-service.d.ts +22 -0
- package/dist/services/task-service.d.ts.map +1 -0
- package/dist/services/task-service.js +221 -0
- package/dist/services/task-service.js.map +1 -0
- package/dist/services/worker-process.d.ts +41 -0
- package/dist/services/worker-process.d.ts.map +1 -0
- package/dist/services/worker-process.js +280 -0
- package/dist/services/worker-process.js.map +1 -0
- package/dist/services/worker-service.d.ts +74 -0
- package/dist/services/worker-service.d.ts.map +1 -0
- package/dist/services/worker-service.js +148 -0
- package/dist/services/worker-service.js.map +1 -0
- package/dist/utils/glob.d.ts +15 -0
- package/dist/utils/glob.d.ts.map +1 -0
- package/dist/utils/glob.js +27 -0
- package/dist/utils/glob.js.map +1 -0
- package/dist/utils/math.d.ts +6 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +21 -0
- package/dist/utils/math.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerProcess - PRD-018
|
|
3
|
+
*
|
|
4
|
+
* Implements the worker process with heartbeat fiber, lease renewal,
|
|
5
|
+
* Claude subprocess management, and graceful shutdown handling.
|
|
6
|
+
* Uses Effect-TS patterns per DD-002.
|
|
7
|
+
*/
|
|
8
|
+
import { Effect } from "effect";
|
|
9
|
+
import { WorkerService } from "./worker-service.js";
|
|
10
|
+
import { ClaimService } from "./claim-service.js";
|
|
11
|
+
import { ReadyService } from "./ready-service.js";
|
|
12
|
+
import { TaskService } from "./task-service.js";
|
|
13
|
+
/**
|
|
14
|
+
* Configuration for the worker process.
|
|
15
|
+
*/
|
|
16
|
+
export interface WorkerProcessConfig {
|
|
17
|
+
/** Optional worker name. Defaults to worker-{timestamp} */
|
|
18
|
+
readonly name?: string;
|
|
19
|
+
/** List of agent capabilities (e.g., ['tx-implementer', 'tx-tester']) */
|
|
20
|
+
readonly capabilities: readonly string[];
|
|
21
|
+
/** Heartbeat interval in seconds. Should match orchestrator config. */
|
|
22
|
+
readonly heartbeatIntervalSeconds: number;
|
|
23
|
+
/** How often to renew the lease (in seconds). Should be < lease duration. */
|
|
24
|
+
readonly leaseRenewalIntervalSeconds?: number;
|
|
25
|
+
/** Working directory for Claude subprocess. Defaults to process.cwd() */
|
|
26
|
+
readonly workingDirectory?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Run the worker process.
|
|
30
|
+
*
|
|
31
|
+
* This function:
|
|
32
|
+
* 1. Registers the worker with the orchestrator
|
|
33
|
+
* 2. Starts a background heartbeat fiber
|
|
34
|
+
* 3. Runs a work loop that claims and processes tasks
|
|
35
|
+
* 4. Handles graceful shutdown via SIGTERM/SIGINT
|
|
36
|
+
*
|
|
37
|
+
* @param config Worker process configuration
|
|
38
|
+
* @returns Effect that runs until shutdown is requested
|
|
39
|
+
*/
|
|
40
|
+
export declare const runWorkerProcess: (config: WorkerProcessConfig) => Effect.Effect<void, import("../errors.js").TaskNotFoundError | import("../errors.js").ValidationError | import("../errors.js").DatabaseError | import("../errors.js").RegistrationError | import("../errors.js").WorkerNotFoundError, TaskService | ReadyService | WorkerService | ClaimService>;
|
|
41
|
+
//# sourceMappingURL=worker-process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-process.d.ts","sourceRoot":"","sources":["../../src/services/worker-process.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAwB,MAAM,QAAQ,CAAA;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAG/C;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,yEAAyE;IACzE,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC,uEAAuE;IACvE,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAA;IACzC,6EAA6E;IAC7E,QAAQ,CAAC,2BAA2B,CAAC,EAAE,MAAM,CAAA;IAC7C,yEAAyE;IACzE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CACnC;AAmBD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,mBAAmB,qSAwLxD,CAAA"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerProcess - PRD-018
|
|
3
|
+
*
|
|
4
|
+
* Implements the worker process with heartbeat fiber, lease renewal,
|
|
5
|
+
* Claude subprocess management, and graceful shutdown handling.
|
|
6
|
+
* Uses Effect-TS patterns per DD-002.
|
|
7
|
+
*/
|
|
8
|
+
import { Effect, Duration, Fiber, Ref } from "effect";
|
|
9
|
+
import { spawn } from "child_process";
|
|
10
|
+
import * as os from "os";
|
|
11
|
+
import { WorkerService } from "./worker-service.js";
|
|
12
|
+
import { ClaimService } from "./claim-service.js";
|
|
13
|
+
import { ReadyService } from "./ready-service.js";
|
|
14
|
+
import { TaskService } from "./task-service.js";
|
|
15
|
+
/**
|
|
16
|
+
* Run the worker process.
|
|
17
|
+
*
|
|
18
|
+
* This function:
|
|
19
|
+
* 1. Registers the worker with the orchestrator
|
|
20
|
+
* 2. Starts a background heartbeat fiber
|
|
21
|
+
* 3. Runs a work loop that claims and processes tasks
|
|
22
|
+
* 4. Handles graceful shutdown via SIGTERM/SIGINT
|
|
23
|
+
*
|
|
24
|
+
* @param config Worker process configuration
|
|
25
|
+
* @returns Effect that runs until shutdown is requested
|
|
26
|
+
*/
|
|
27
|
+
export const runWorkerProcess = (config) => Effect.gen(function* () {
|
|
28
|
+
const workerService = yield* WorkerService;
|
|
29
|
+
const claimService = yield* ClaimService;
|
|
30
|
+
const readyService = yield* ReadyService;
|
|
31
|
+
const taskService = yield* TaskService;
|
|
32
|
+
// Shutdown state ref (mutable, shared with signal handlers)
|
|
33
|
+
const shutdownState = yield* Ref.make({
|
|
34
|
+
requested: false,
|
|
35
|
+
claudeProcess: null
|
|
36
|
+
});
|
|
37
|
+
// Register with orchestrator
|
|
38
|
+
const worker = yield* workerService.register({
|
|
39
|
+
name: config.name,
|
|
40
|
+
hostname: os.hostname(),
|
|
41
|
+
pid: process.pid,
|
|
42
|
+
capabilities: config.capabilities
|
|
43
|
+
});
|
|
44
|
+
const workerId = worker.id;
|
|
45
|
+
yield* Effect.log(`Worker ${workerId} registered`);
|
|
46
|
+
// Set up signal handlers for graceful shutdown
|
|
47
|
+
const handleSignal = (signal) => {
|
|
48
|
+
console.log(`Worker ${workerId} received ${signal}`);
|
|
49
|
+
// Mark shutdown as requested (sync since signal handlers can't use async)
|
|
50
|
+
Effect.runSync(Ref.update(shutdownState, (state) => ({
|
|
51
|
+
...state,
|
|
52
|
+
requested: true
|
|
53
|
+
})));
|
|
54
|
+
// Try to terminate Claude subprocess if running
|
|
55
|
+
Effect.runSync(Ref.get(shutdownState).pipe(Effect.map((state) => {
|
|
56
|
+
if (state.claudeProcess && !state.claudeProcess.killed) {
|
|
57
|
+
state.claudeProcess.kill("SIGTERM");
|
|
58
|
+
}
|
|
59
|
+
})));
|
|
60
|
+
};
|
|
61
|
+
process.on("SIGTERM", () => handleSignal("SIGTERM"));
|
|
62
|
+
process.on("SIGINT", () => handleSignal("SIGINT"));
|
|
63
|
+
// Completed tasks counter for metrics (shared with heartbeat loop)
|
|
64
|
+
const tasksCompletedRef = yield* Ref.make(0);
|
|
65
|
+
// Heartbeat fiber - runs continuously in background
|
|
66
|
+
const heartbeatFiber = yield* Effect.fork(runHeartbeatLoop(workerId, config.heartbeatIntervalSeconds, shutdownState, tasksCompletedRef));
|
|
67
|
+
try {
|
|
68
|
+
// Main work loop
|
|
69
|
+
while (true) {
|
|
70
|
+
// Check if shutdown was requested
|
|
71
|
+
const state = yield* Ref.get(shutdownState);
|
|
72
|
+
if (state.requested) {
|
|
73
|
+
yield* Effect.log(`Worker ${workerId} shutting down gracefully`);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
// Update status to idle
|
|
77
|
+
yield* workerService.updateStatus(workerId, "idle");
|
|
78
|
+
// Check for available work
|
|
79
|
+
const readyTasks = yield* readyService.getReady(1);
|
|
80
|
+
if (readyTasks.length === 0) {
|
|
81
|
+
// No work available, wait and try again
|
|
82
|
+
yield* Effect.sleep(Duration.seconds(5));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const task = readyTasks[0];
|
|
86
|
+
// Try to claim the task
|
|
87
|
+
const claimResult = yield* claimService.claim(task.id, workerId).pipe(Effect.either);
|
|
88
|
+
if (claimResult._tag === "Left") {
|
|
89
|
+
// Someone else claimed it, try again
|
|
90
|
+
yield* Effect.log(`Worker ${workerId} failed to claim task ${task.id}: ${claimResult.left._tag}`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const _claim = claimResult.right;
|
|
94
|
+
yield* Effect.log(`Worker ${workerId} claimed task ${task.id}`);
|
|
95
|
+
const tasksCompleted = yield* Ref.get(tasksCompletedRef);
|
|
96
|
+
// Update worker status to busy with current task
|
|
97
|
+
yield* workerService.heartbeat({
|
|
98
|
+
workerId,
|
|
99
|
+
timestamp: new Date(),
|
|
100
|
+
status: "busy",
|
|
101
|
+
currentTaskId: task.id,
|
|
102
|
+
metrics: {
|
|
103
|
+
cpuPercent: process.cpuUsage().user / 1000000,
|
|
104
|
+
memoryMb: process.memoryUsage().heapUsed / 1024 / 1024,
|
|
105
|
+
tasksCompleted
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
// Select appropriate agent for the task
|
|
109
|
+
const agent = selectAgent(task);
|
|
110
|
+
// Start lease renewal fiber
|
|
111
|
+
const renewalInterval = config.leaseRenewalIntervalSeconds ??
|
|
112
|
+
config.heartbeatIntervalSeconds * 10; // Default: 10x heartbeat interval
|
|
113
|
+
const renewFiber = yield* Effect.fork(runLeaseRenewalLoop(task.id, workerId, renewalInterval, shutdownState));
|
|
114
|
+
try {
|
|
115
|
+
// Run Claude subprocess
|
|
116
|
+
const result = yield* runClaude(agent, task, workerId, config.workingDirectory ?? process.cwd(), shutdownState);
|
|
117
|
+
if (result.success) {
|
|
118
|
+
// Mark task as done
|
|
119
|
+
yield* taskService.update(task.id, { status: "done" });
|
|
120
|
+
yield* Ref.update(tasksCompletedRef, (n) => n + 1);
|
|
121
|
+
yield* Effect.log(`Task ${task.id} completed successfully`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
yield* Effect.log(`Task ${task.id} failed: ${result.error ?? "Unknown error"}`);
|
|
125
|
+
}
|
|
126
|
+
// Release the claim
|
|
127
|
+
yield* claimService.release(task.id, workerId).pipe(Effect.catchAll((error) => Effect.log(`Failed to release claim for task ${task.id}: ${error.message}`)));
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
// Stop renewal fiber
|
|
131
|
+
yield* Fiber.interrupt(renewFiber);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Graceful shutdown: mark as stopping
|
|
135
|
+
yield* workerService.updateStatus(workerId, "stopping");
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
// Cleanup: stop heartbeat fiber and deregister
|
|
139
|
+
yield* Fiber.interrupt(heartbeatFiber);
|
|
140
|
+
// Release any active claims before deregistering
|
|
141
|
+
yield* claimService.releaseByWorker(workerId).pipe(Effect.catchAll((error) => Effect.log(`Failed to release claims for worker ${workerId}: ${error.message}`).pipe(Effect.as(0))));
|
|
142
|
+
yield* workerService.deregister(workerId).pipe(Effect.catchAll((error) => Effect.log(`Failed to deregister worker ${workerId}: ${error.message}`)));
|
|
143
|
+
yield* Effect.log(`Worker ${workerId} shutdown complete`);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
/**
|
|
147
|
+
* Run the heartbeat loop.
|
|
148
|
+
* Sends periodic heartbeats to the orchestrator.
|
|
149
|
+
*/
|
|
150
|
+
const runHeartbeatLoop = (workerId, intervalSeconds, shutdownState, tasksCompletedRef) => Effect.gen(function* () {
|
|
151
|
+
const workerService = yield* WorkerService;
|
|
152
|
+
while (true) {
|
|
153
|
+
// Check shutdown before heartbeat
|
|
154
|
+
const state = yield* Ref.get(shutdownState);
|
|
155
|
+
if (state.requested)
|
|
156
|
+
break;
|
|
157
|
+
// Determine current status based on whether Claude is running
|
|
158
|
+
const status = state.claudeProcess ? "busy" : "idle";
|
|
159
|
+
// Read current completed count from shared ref
|
|
160
|
+
const tasksCompleted = yield* Ref.get(tasksCompletedRef);
|
|
161
|
+
yield* workerService
|
|
162
|
+
.heartbeat({
|
|
163
|
+
workerId,
|
|
164
|
+
timestamp: new Date(),
|
|
165
|
+
status,
|
|
166
|
+
currentTaskId: undefined, // The main loop sets this
|
|
167
|
+
metrics: {
|
|
168
|
+
cpuPercent: process.cpuUsage().user / 1000000,
|
|
169
|
+
memoryMb: process.memoryUsage().heapUsed / 1024 / 1024,
|
|
170
|
+
tasksCompleted
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
.pipe(Effect.catchAll((error) => Effect.log(`Heartbeat failed for ${workerId}: ${error.message}`)));
|
|
174
|
+
yield* Effect.sleep(Duration.seconds(intervalSeconds));
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
/**
|
|
178
|
+
* Run the lease renewal loop.
|
|
179
|
+
* Periodically renews the lease on a claimed task.
|
|
180
|
+
*/
|
|
181
|
+
const runLeaseRenewalLoop = (taskId, workerId, intervalSeconds, shutdownState) => Effect.gen(function* () {
|
|
182
|
+
const claimService = yield* ClaimService;
|
|
183
|
+
while (true) {
|
|
184
|
+
// Wait before first renewal
|
|
185
|
+
yield* Effect.sleep(Duration.seconds(intervalSeconds));
|
|
186
|
+
// Check shutdown before renewal
|
|
187
|
+
const state = yield* Ref.get(shutdownState);
|
|
188
|
+
if (state.requested)
|
|
189
|
+
break;
|
|
190
|
+
yield* claimService
|
|
191
|
+
.renew(taskId, workerId)
|
|
192
|
+
.pipe(Effect.tap(() => Effect.log(`Renewed lease on task ${taskId}`)), Effect.catchAll((error) => Effect.log(`Lease renewal failed for task ${taskId}: ${error.message}`)));
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
/**
|
|
196
|
+
* Run a Claude subprocess to work on a task.
|
|
197
|
+
*/
|
|
198
|
+
const runClaude = (agent, task, workerId, workingDirectory, shutdownState) => Effect.async((resume) => {
|
|
199
|
+
const prompt = buildPrompt(agent, task);
|
|
200
|
+
const proc = spawn("claude", ["--dangerously-skip-permissions", "--print", prompt], {
|
|
201
|
+
cwd: workingDirectory,
|
|
202
|
+
env: { ...process.env, TX_WORKER_ID: workerId },
|
|
203
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
204
|
+
});
|
|
205
|
+
// Store the process reference for signal handling
|
|
206
|
+
Effect.runSync(Ref.update(shutdownState, (state) => ({
|
|
207
|
+
...state,
|
|
208
|
+
claudeProcess: proc
|
|
209
|
+
})));
|
|
210
|
+
let stderr = "";
|
|
211
|
+
proc.stderr?.on("data", (data) => {
|
|
212
|
+
stderr += data.toString();
|
|
213
|
+
});
|
|
214
|
+
proc.on("close", (code) => {
|
|
215
|
+
// Clear the process reference
|
|
216
|
+
Effect.runSync(Ref.update(shutdownState, (state) => ({
|
|
217
|
+
...state,
|
|
218
|
+
claudeProcess: null
|
|
219
|
+
})));
|
|
220
|
+
if (code === 0) {
|
|
221
|
+
resume(Effect.succeed({ success: true, exitCode: code ?? 0 }));
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
resume(Effect.succeed({
|
|
225
|
+
success: false,
|
|
226
|
+
error: stderr || `Exit code ${code}`,
|
|
227
|
+
exitCode: code ?? 1
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
proc.on("error", (err) => {
|
|
232
|
+
// Clear the process reference
|
|
233
|
+
Effect.runSync(Ref.update(shutdownState, (state) => ({
|
|
234
|
+
...state,
|
|
235
|
+
claudeProcess: null
|
|
236
|
+
})));
|
|
237
|
+
resume(Effect.succeed({
|
|
238
|
+
success: false,
|
|
239
|
+
error: err.message,
|
|
240
|
+
exitCode: 1
|
|
241
|
+
}));
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
/**
|
|
245
|
+
* Build the prompt for the Claude subprocess.
|
|
246
|
+
*/
|
|
247
|
+
const buildPrompt = (agent, task) => `Read .claude/agents/${agent}.md for your instructions.
|
|
248
|
+
|
|
249
|
+
Your assigned task: ${task.id}
|
|
250
|
+
Task title: ${task.title}
|
|
251
|
+
|
|
252
|
+
Run \`tx show ${task.id}\` to get full details, then follow your agent instructions.
|
|
253
|
+
When done, run \`tx done ${task.id}\` to mark the task complete.
|
|
254
|
+
If you discover new work, create subtasks with \`tx add\`.
|
|
255
|
+
If you hit a blocker, update the task status: \`tx update ${task.id} --status blocked\`.`;
|
|
256
|
+
/**
|
|
257
|
+
* Select the appropriate agent based on task characteristics.
|
|
258
|
+
*/
|
|
259
|
+
const selectAgent = (task) => {
|
|
260
|
+
const title = task.title.toLowerCase();
|
|
261
|
+
// Test/integration tasks go to tester
|
|
262
|
+
if (title.includes("test") ||
|
|
263
|
+
title.includes("integration") ||
|
|
264
|
+
title.includes("fixture")) {
|
|
265
|
+
return "tx-tester";
|
|
266
|
+
}
|
|
267
|
+
// Review/audit tasks go to reviewer
|
|
268
|
+
if (title.includes("review") ||
|
|
269
|
+
title.includes("audit") ||
|
|
270
|
+
title.includes("check")) {
|
|
271
|
+
return "tx-reviewer";
|
|
272
|
+
}
|
|
273
|
+
// High-priority tasks without children may need decomposition
|
|
274
|
+
if (task.score >= 800 && task.children.length === 0) {
|
|
275
|
+
return "tx-decomposer";
|
|
276
|
+
}
|
|
277
|
+
// Default to implementer
|
|
278
|
+
return "tx-implementer";
|
|
279
|
+
};
|
|
280
|
+
//# sourceMappingURL=worker-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-process.js","sourceRoot":"","sources":["../../src/services/worker-process.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerService - PRD-018
|
|
3
|
+
*
|
|
4
|
+
* Manages worker registration, heartbeats, and lifecycle.
|
|
5
|
+
* Uses Effect-TS patterns per DD-002.
|
|
6
|
+
*/
|
|
7
|
+
import { Context, Effect, Layer } from "effect";
|
|
8
|
+
import { WorkerRepository } from "../repo/worker-repo.js";
|
|
9
|
+
import { OrchestratorStateRepository } from "../repo/orchestrator-state-repo.js";
|
|
10
|
+
import { DatabaseError, RegistrationError, WorkerNotFoundError } from "../errors.js";
|
|
11
|
+
import type { Worker, WorkerStatus, Heartbeat } from "../schemas/worker.js";
|
|
12
|
+
/**
|
|
13
|
+
* Input for worker registration.
|
|
14
|
+
*/
|
|
15
|
+
export interface WorkerRegistration {
|
|
16
|
+
readonly workerId?: string;
|
|
17
|
+
readonly name?: string;
|
|
18
|
+
readonly hostname?: string;
|
|
19
|
+
readonly pid?: number;
|
|
20
|
+
readonly capabilities?: readonly string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Filter options for listing workers.
|
|
24
|
+
*/
|
|
25
|
+
export interface WorkerFilter {
|
|
26
|
+
readonly status?: readonly WorkerStatus[];
|
|
27
|
+
readonly noCurrentTask?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Configuration for finding dead workers.
|
|
31
|
+
*/
|
|
32
|
+
export interface FindDeadConfig {
|
|
33
|
+
readonly missedHeartbeats: number;
|
|
34
|
+
}
|
|
35
|
+
declare const WorkerService_base: Context.TagClass<WorkerService, "WorkerService", {
|
|
36
|
+
/**
|
|
37
|
+
* Register a new worker with the orchestrator.
|
|
38
|
+
* Checks orchestrator state and pool capacity before registration.
|
|
39
|
+
*/
|
|
40
|
+
readonly register: (registration: WorkerRegistration) => Effect.Effect<Worker, RegistrationError | DatabaseError>;
|
|
41
|
+
/**
|
|
42
|
+
* Process a heartbeat from a worker.
|
|
43
|
+
* Updates last heartbeat time, status, and optional metrics.
|
|
44
|
+
*/
|
|
45
|
+
readonly heartbeat: (heartbeat: Heartbeat) => Effect.Effect<void, WorkerNotFoundError | DatabaseError>;
|
|
46
|
+
/**
|
|
47
|
+
* Deregister a worker.
|
|
48
|
+
* Removes the worker from the registry.
|
|
49
|
+
* Note: Active claims should be released by ClaimService before calling this.
|
|
50
|
+
*/
|
|
51
|
+
readonly deregister: (workerId: string) => Effect.Effect<void, WorkerNotFoundError | DatabaseError>;
|
|
52
|
+
/**
|
|
53
|
+
* List workers with optional filtering.
|
|
54
|
+
*/
|
|
55
|
+
readonly list: (filter?: WorkerFilter) => Effect.Effect<readonly Worker[], DatabaseError>;
|
|
56
|
+
/**
|
|
57
|
+
* Find workers that have missed heartbeats.
|
|
58
|
+
* Uses the orchestrator's configured heartbeat interval.
|
|
59
|
+
*/
|
|
60
|
+
readonly findDead: (config: FindDeadConfig) => Effect.Effect<readonly Worker[], DatabaseError>;
|
|
61
|
+
/**
|
|
62
|
+
* Mark a worker as dead.
|
|
63
|
+
*/
|
|
64
|
+
readonly markDead: (workerId: string) => Effect.Effect<void, WorkerNotFoundError | DatabaseError>;
|
|
65
|
+
/**
|
|
66
|
+
* Update a worker's status.
|
|
67
|
+
*/
|
|
68
|
+
readonly updateStatus: (workerId: string, status: WorkerStatus) => Effect.Effect<void, WorkerNotFoundError | DatabaseError>;
|
|
69
|
+
}>;
|
|
70
|
+
export declare class WorkerService extends WorkerService_base {
|
|
71
|
+
}
|
|
72
|
+
export declare const WorkerServiceLive: Layer.Layer<WorkerService, never, WorkerRepository | OrchestratorStateRepository>;
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=worker-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-service.d.ts","sourceRoot":"","sources":["../../src/services/worker-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAA;AAChF,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAE3E;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC;;IAkBG;;;OAGG;uBACgB,CACjB,YAAY,EAAE,kBAAkB,KAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,aAAa,CAAC;IAE7D;;;OAGG;wBACiB,CAClB,SAAS,EAAE,SAAS,KACjB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,mBAAmB,GAAG,aAAa,CAAC;IAE7D;;;;OAIG;yBACkB,CACnB,QAAQ,EAAE,MAAM,KACb,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,mBAAmB,GAAG,aAAa,CAAC;IAE7D;;OAEG;mBACY,CACb,MAAM,CAAC,EAAE,YAAY,KAClB,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,aAAa,CAAC;IAEpD;;;OAGG;uBACgB,CACjB,MAAM,EAAE,cAAc,KACnB,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,aAAa,CAAC;IAEpD;;OAEG;uBACgB,CACjB,QAAQ,EAAE,MAAM,KACb,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,mBAAmB,GAAG,aAAa,CAAC;IAE7D;;OAEG;2BACoB,CACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,KACjB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,mBAAmB,GAAG,aAAa,CAAC;;AAxDjE,qBAAa,aAAc,SAAQ,kBA0DhC;CAAG;AAEN,eAAO,MAAM,iBAAiB,mFAqK7B,CAAA"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerService - PRD-018
|
|
3
|
+
*
|
|
4
|
+
* Manages worker registration, heartbeats, and lifecycle.
|
|
5
|
+
* Uses Effect-TS patterns per DD-002.
|
|
6
|
+
*/
|
|
7
|
+
import { Context, Effect, Layer } from "effect";
|
|
8
|
+
import { createHash, randomBytes } from "crypto";
|
|
9
|
+
import * as os from "os";
|
|
10
|
+
import { WorkerRepository } from "../repo/worker-repo.js";
|
|
11
|
+
import { OrchestratorStateRepository } from "../repo/orchestrator-state-repo.js";
|
|
12
|
+
import { RegistrationError, WorkerNotFoundError } from "../errors.js";
|
|
13
|
+
/**
|
|
14
|
+
* Generate a unique worker ID.
|
|
15
|
+
*/
|
|
16
|
+
const generateWorkerId = () => {
|
|
17
|
+
const random = randomBytes(16).toString("hex");
|
|
18
|
+
const timestamp = Date.now().toString(36);
|
|
19
|
+
const hash = createHash("sha256")
|
|
20
|
+
.update(timestamp + random)
|
|
21
|
+
.digest("hex")
|
|
22
|
+
.substring(0, 8);
|
|
23
|
+
return `worker-${hash}`;
|
|
24
|
+
};
|
|
25
|
+
export class WorkerService extends Context.Tag("WorkerService")() {
|
|
26
|
+
}
|
|
27
|
+
export const WorkerServiceLive = Layer.effect(WorkerService, Effect.gen(function* () {
|
|
28
|
+
const workerRepo = yield* WorkerRepository;
|
|
29
|
+
const orchestratorRepo = yield* OrchestratorStateRepository;
|
|
30
|
+
return {
|
|
31
|
+
register: (registration) => Effect.gen(function* () {
|
|
32
|
+
// Verify orchestrator is running
|
|
33
|
+
const state = yield* orchestratorRepo.get();
|
|
34
|
+
if (state.status !== "running") {
|
|
35
|
+
return yield* Effect.fail(new RegistrationError({
|
|
36
|
+
reason: "Orchestrator is not running"
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
// Count active workers (starting, idle, busy)
|
|
40
|
+
const startingCount = yield* workerRepo.countByStatus("starting");
|
|
41
|
+
const idleCount = yield* workerRepo.countByStatus("idle");
|
|
42
|
+
const busyCount = yield* workerRepo.countByStatus("busy");
|
|
43
|
+
const activeWorkers = startingCount + idleCount + busyCount;
|
|
44
|
+
// Check pool capacity
|
|
45
|
+
if (activeWorkers >= state.workerPoolSize) {
|
|
46
|
+
return yield* Effect.fail(new RegistrationError({
|
|
47
|
+
reason: `Worker pool at capacity (${state.workerPoolSize})`
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
const now = new Date();
|
|
51
|
+
const worker = {
|
|
52
|
+
id: registration.workerId ?? generateWorkerId(),
|
|
53
|
+
name: registration.name ?? `worker-${Date.now()}`,
|
|
54
|
+
hostname: registration.hostname ?? os.hostname(),
|
|
55
|
+
pid: registration.pid ?? process.pid,
|
|
56
|
+
status: "starting",
|
|
57
|
+
registeredAt: now,
|
|
58
|
+
lastHeartbeatAt: now,
|
|
59
|
+
currentTaskId: null,
|
|
60
|
+
capabilities: [...(registration.capabilities ?? ["tx-implementer"])],
|
|
61
|
+
metadata: {}
|
|
62
|
+
};
|
|
63
|
+
yield* workerRepo.insert(worker);
|
|
64
|
+
yield* Effect.log(`Worker ${worker.id} registered`);
|
|
65
|
+
return worker;
|
|
66
|
+
}),
|
|
67
|
+
heartbeat: (heartbeat) => Effect.gen(function* () {
|
|
68
|
+
const worker = yield* workerRepo.findById(heartbeat.workerId);
|
|
69
|
+
if (!worker) {
|
|
70
|
+
return yield* Effect.fail(new WorkerNotFoundError({ workerId: heartbeat.workerId }));
|
|
71
|
+
}
|
|
72
|
+
// Build updated worker
|
|
73
|
+
const updated = {
|
|
74
|
+
...worker,
|
|
75
|
+
lastHeartbeatAt: heartbeat.timestamp,
|
|
76
|
+
status: heartbeat.status,
|
|
77
|
+
currentTaskId: heartbeat.currentTaskId ?? null,
|
|
78
|
+
metadata: heartbeat.metrics
|
|
79
|
+
? { ...worker.metadata, lastMetrics: heartbeat.metrics }
|
|
80
|
+
: worker.metadata
|
|
81
|
+
};
|
|
82
|
+
yield* workerRepo.update(updated);
|
|
83
|
+
}),
|
|
84
|
+
deregister: (workerId) => Effect.gen(function* () {
|
|
85
|
+
const worker = yield* workerRepo.findById(workerId);
|
|
86
|
+
if (!worker) {
|
|
87
|
+
return yield* Effect.fail(new WorkerNotFoundError({ workerId }));
|
|
88
|
+
}
|
|
89
|
+
// Note: Active claims should be released by ClaimService before calling this.
|
|
90
|
+
// The ClaimService.releaseByWorker call is handled by the orchestrator/caller.
|
|
91
|
+
const deleted = yield* workerRepo.delete(workerId);
|
|
92
|
+
if (deleted) {
|
|
93
|
+
yield* Effect.log(`Worker ${workerId} deregistered`);
|
|
94
|
+
}
|
|
95
|
+
}),
|
|
96
|
+
list: (filter) => Effect.gen(function* () {
|
|
97
|
+
// Get all workers in a single query
|
|
98
|
+
const allWorkers = yield* workerRepo.findAll();
|
|
99
|
+
if (!filter) {
|
|
100
|
+
return allWorkers;
|
|
101
|
+
}
|
|
102
|
+
let results = [...allWorkers];
|
|
103
|
+
// Filter by status if specified
|
|
104
|
+
if (filter.status && filter.status.length > 0) {
|
|
105
|
+
const statusSet = new Set(filter.status);
|
|
106
|
+
results = results.filter((w) => statusSet.has(w.status));
|
|
107
|
+
}
|
|
108
|
+
// Filter by noCurrentTask if specified
|
|
109
|
+
if (filter.noCurrentTask) {
|
|
110
|
+
results = results.filter((w) => w.currentTaskId === null);
|
|
111
|
+
}
|
|
112
|
+
return results;
|
|
113
|
+
}),
|
|
114
|
+
findDead: (config) => Effect.gen(function* () {
|
|
115
|
+
const state = yield* orchestratorRepo.get();
|
|
116
|
+
const heartbeatTimeoutSeconds = state.heartbeatIntervalSeconds * config.missedHeartbeats;
|
|
117
|
+
const cutoff = new Date(Date.now() - heartbeatTimeoutSeconds * 1000);
|
|
118
|
+
// Get workers with old heartbeats
|
|
119
|
+
const staleWorkers = yield* workerRepo.findByLastHeartbeatBefore(cutoff);
|
|
120
|
+
// Exclude workers that are already dead or stopping
|
|
121
|
+
return staleWorkers.filter((w) => w.status !== "dead" && w.status !== "stopping");
|
|
122
|
+
}),
|
|
123
|
+
markDead: (workerId) => Effect.gen(function* () {
|
|
124
|
+
const worker = yield* workerRepo.findById(workerId);
|
|
125
|
+
if (!worker) {
|
|
126
|
+
return yield* Effect.fail(new WorkerNotFoundError({ workerId }));
|
|
127
|
+
}
|
|
128
|
+
const updated = {
|
|
129
|
+
...worker,
|
|
130
|
+
status: "dead"
|
|
131
|
+
};
|
|
132
|
+
yield* workerRepo.update(updated);
|
|
133
|
+
yield* Effect.log(`Worker ${workerId} marked as dead`);
|
|
134
|
+
}),
|
|
135
|
+
updateStatus: (workerId, status) => Effect.gen(function* () {
|
|
136
|
+
const worker = yield* workerRepo.findById(workerId);
|
|
137
|
+
if (!worker) {
|
|
138
|
+
return yield* Effect.fail(new WorkerNotFoundError({ workerId }));
|
|
139
|
+
}
|
|
140
|
+
const updated = {
|
|
141
|
+
...worker,
|
|
142
|
+
status
|
|
143
|
+
};
|
|
144
|
+
yield* workerRepo.update(updated);
|
|
145
|
+
})
|
|
146
|
+
};
|
|
147
|
+
}));
|
|
148
|
+
//# sourceMappingURL=worker-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-service.js","sourceRoot":"","sources":["../../src/services/worker-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple glob matching - checks if file path matches pattern.
|
|
3
|
+
* Supports: *, **, ?
|
|
4
|
+
*
|
|
5
|
+
* - `*` matches any characters except /
|
|
6
|
+
* - `**` matches any characters including /
|
|
7
|
+
* - `?` matches a single character
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* matchesGlob("src/utils/math.ts", "src/**\/*.ts") // true
|
|
11
|
+
* matchesGlob("src/index.ts", "*.ts") // false (no / in *)
|
|
12
|
+
* matchesGlob("file.ts", "file.??") // true
|
|
13
|
+
*/
|
|
14
|
+
export declare const matchesGlob: (filePath: string, pattern: string) => boolean;
|
|
15
|
+
//# sourceMappingURL=glob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/utils/glob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,EAAE,SAAS,MAAM,KAAG,OAa/D,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple glob matching - checks if file path matches pattern.
|
|
3
|
+
* Supports: *, **, ?
|
|
4
|
+
*
|
|
5
|
+
* - `*` matches any characters except /
|
|
6
|
+
* - `**` matches any characters including /
|
|
7
|
+
* - `?` matches a single character
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* matchesGlob("src/utils/math.ts", "src/**\/*.ts") // true
|
|
11
|
+
* matchesGlob("src/index.ts", "*.ts") // false (no / in *)
|
|
12
|
+
* matchesGlob("file.ts", "file.??") // true
|
|
13
|
+
*/
|
|
14
|
+
export const matchesGlob = (filePath, pattern) => {
|
|
15
|
+
// Simple glob matching without external dependencies
|
|
16
|
+
// Order matters: protect glob patterns, escape dots, then restore patterns
|
|
17
|
+
const regexPattern = pattern
|
|
18
|
+
.replace(/\*\*/g, "<<<GLOBSTAR>>>") // Protect ** (will become .*)
|
|
19
|
+
.replace(/\?/g, "<<<QUESTION>>>") // Protect ? (will become .)
|
|
20
|
+
.replace(/\*/g, "[^/]*") // Replace * with segment matcher
|
|
21
|
+
.replace(/\./g, "\\.") // Escape literal dots (e.g., .ts → \\.ts)
|
|
22
|
+
.replace(/<<<GLOBSTAR>>>/g, ".*") // Restore ** as .* (matches any path)
|
|
23
|
+
.replace(/<<<QUESTION>>>/g, "."); // Restore ? as . (matches single char)
|
|
24
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
25
|
+
return regex.test(filePath);
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=glob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/utils/glob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAgB,EAAE,OAAe,EAAW,EAAE;IACxE,qDAAqD;IACrD,2EAA2E;IAC3E,MAAM,YAAY,GAAG,OAAO;SACzB,OAAO,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,8BAA8B;SACjE,OAAO,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,4BAA4B;SAC7D,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,iCAAiC;SACzD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,0CAA0C;SAChE,OAAO,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC,sCAAsC;SACvE,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAA,CAAC,uCAAuC;IAE1E,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,YAAY,GAAG,CAAC,CAAA;IAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;AAC7B,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../../src/utils/math.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,GAAG,YAAY,EAAE,GAAG,YAAY,KAAG,MAiBnE,CAAA"}
|