monomind 1.11.11 → 1.11.13
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/.claude/commands/mastermind/idea.md +1 -1
- package/.claude/commands/mastermind/master.md +1 -1
- package/.claude/skills/mastermind/_protocol.md +4 -4
- package/.claude/skills/mastermind/architect.md +7 -4
- package/.claude/skills/mastermind/autodev.md +4 -2
- package/.claude/skills/mastermind/build.md +3 -3
- package/.claude/skills/mastermind/content.md +3 -3
- package/.claude/skills/mastermind/createorg.md +2 -2
- package/.claude/skills/mastermind/finance.md +3 -3
- package/.claude/skills/mastermind/idea.md +8 -0
- package/.claude/skills/mastermind/marketing.md +3 -3
- package/.claude/skills/mastermind/ops.md +3 -3
- package/.claude/skills/mastermind/release.md +3 -3
- package/.claude/skills/mastermind/research.md +3 -3
- package/.claude/skills/mastermind/review.md +3 -3
- package/.claude/skills/mastermind/sales.md +3 -3
- package/package.json +1 -1
- package/packages/@monomind/cli/dist/src/index.js +19 -14
- package/packages/@monomind/cli/dist/src/init/statusline-generator.js +3 -3
- package/packages/@monomind/cli/dist/src/observability/replay-reader.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/update/checker.js +24 -7
- package/packages/@monomind/cli/dist/src/update/index.d.ts +10 -0
- package/packages/@monomind/cli/dist/src/update/index.js +29 -2
- package/packages/@monomind/cli/package.json +1 -1
- package/packages/@monomind/cli/dist/src/agents/halt-signal.d.ts +0 -25
- package/packages/@monomind/cli/dist/src/agents/halt-signal.js +0 -76
- package/packages/@monomind/cli/dist/src/agents/index.d.ts +0 -18
- package/packages/@monomind/cli/dist/src/agents/index.js +0 -13
- package/packages/@monomind/cli/dist/src/agents/managed-agent.d.ts +0 -41
- package/packages/@monomind/cli/dist/src/agents/managed-agent.js +0 -69
- package/packages/@monomind/cli/dist/src/agents/prompt-experiment.d.ts +0 -23
- package/packages/@monomind/cli/dist/src/agents/prompt-experiment.js +0 -49
- package/packages/@monomind/cli/dist/src/agents/prompt-version-manager.d.ts +0 -22
- package/packages/@monomind/cli/dist/src/agents/prompt-version-manager.js +0 -80
- package/packages/@monomind/cli/dist/src/agents/registry-query.d.ts +0 -71
- package/packages/@monomind/cli/dist/src/agents/registry-query.js +0 -125
- package/packages/@monomind/cli/dist/src/agents/score-decay.d.ts +0 -19
- package/packages/@monomind/cli/dist/src/agents/score-decay.js +0 -22
- package/packages/@monomind/cli/dist/src/agents/shared-instructions-loader.d.ts +0 -13
- package/packages/@monomind/cli/dist/src/agents/shared-instructions-loader.js +0 -40
- package/packages/@monomind/cli/dist/src/agents/specialization-scorer.d.ts +0 -54
- package/packages/@monomind/cli/dist/src/agents/specialization-scorer.js +0 -212
- package/packages/@monomind/cli/dist/src/agents/termination-watcher.d.ts +0 -30
- package/packages/@monomind/cli/dist/src/agents/termination-watcher.js +0 -84
- package/packages/@monomind/cli/dist/src/agents/trigger-index.d.ts +0 -20
- package/packages/@monomind/cli/dist/src/agents/trigger-index.js +0 -38
- package/packages/@monomind/cli/dist/src/agents/trigger-scanner.d.ts +0 -64
- package/packages/@monomind/cli/dist/src/agents/trigger-scanner.js +0 -308
- package/packages/@monomind/cli/dist/src/agents/version-diff.d.ts +0 -18
- package/packages/@monomind/cli/dist/src/agents/version-diff.js +0 -64
- package/packages/@monomind/cli/dist/src/agents/version-store.d.ts +0 -60
- package/packages/@monomind/cli/dist/src/agents/version-store.js +0 -235
- package/packages/@monomind/cli/dist/src/benchmarks/pretrain/index.d.ts +0 -45
- package/packages/@monomind/cli/dist/src/benchmarks/pretrain/index.js +0 -404
- package/packages/@monomind/cli/dist/src/commands/agent-wasm.d.ts +0 -14
- package/packages/@monomind/cli/dist/src/commands/agent-wasm.js +0 -333
- package/packages/@monomind/cli/dist/src/commands/ui.js +0 -68
- package/packages/@monomind/cli/dist/src/consensus/index.d.ts +0 -7
- package/packages/@monomind/cli/dist/src/consensus/index.js +0 -6
- package/packages/@monomind/cli/dist/src/context/context-provider.d.ts +0 -44
- package/packages/@monomind/cli/dist/src/context/context-provider.js +0 -25
- package/packages/@monomind/cli/dist/src/context/git-state-provider.d.ts +0 -12
- package/packages/@monomind/cli/dist/src/context/git-state-provider.js +0 -34
- package/packages/@monomind/cli/dist/src/context/index.d.ts +0 -12
- package/packages/@monomind/cli/dist/src/context/index.js +0 -12
- package/packages/@monomind/cli/dist/src/context/project-conventions-provider.d.ts +0 -15
- package/packages/@monomind/cli/dist/src/context/project-conventions-provider.js +0 -19
- package/packages/@monomind/cli/dist/src/context/prompt-assembler.d.ts +0 -26
- package/packages/@monomind/cli/dist/src/context/prompt-assembler.js +0 -93
- package/packages/@monomind/cli/dist/src/context/task-history-provider.d.ts +0 -24
- package/packages/@monomind/cli/dist/src/context/task-history-provider.js +0 -32
- package/packages/@monomind/cli/dist/src/context/user-preferences-provider.d.ts +0 -14
- package/packages/@monomind/cli/dist/src/context/user-preferences-provider.js +0 -27
- package/packages/@monomind/cli/dist/src/dlq/dlq-reader.d.ts +0 -31
- package/packages/@monomind/cli/dist/src/dlq/dlq-reader.js +0 -81
- package/packages/@monomind/cli/dist/src/dlq/dlq-writer.d.ts +0 -24
- package/packages/@monomind/cli/dist/src/dlq/dlq-writer.js +0 -65
- package/packages/@monomind/cli/dist/src/dlq/index.d.ts +0 -10
- package/packages/@monomind/cli/dist/src/dlq/index.js +0 -7
- package/packages/@monomind/cli/dist/src/eval/dataset-manager.d.ts +0 -33
- package/packages/@monomind/cli/dist/src/eval/dataset-manager.js +0 -107
- package/packages/@monomind/cli/dist/src/eval/dataset-runner.d.ts +0 -23
- package/packages/@monomind/cli/dist/src/eval/dataset-runner.js +0 -59
- package/packages/@monomind/cli/dist/src/eval/index.d.ts +0 -10
- package/packages/@monomind/cli/dist/src/eval/index.js +0 -7
- package/packages/@monomind/cli/dist/src/eval/trace-collector.d.ts +0 -40
- package/packages/@monomind/cli/dist/src/eval/trace-collector.js +0 -102
- package/packages/@monomind/cli/dist/src/infrastructure/in-memory-repositories.d.ts +0 -68
- package/packages/@monomind/cli/dist/src/infrastructure/in-memory-repositories.js +0 -264
- package/packages/@monomind/cli/dist/src/interactive/interrupt.d.ts +0 -22
- package/packages/@monomind/cli/dist/src/interactive/interrupt.js +0 -71
- package/packages/@monomind/cli/dist/src/mcp/deprecation-injector.d.ts +0 -25
- package/packages/@monomind/cli/dist/src/mcp/deprecation-injector.js +0 -48
- package/packages/@monomind/cli/dist/src/mcp/tool-registry.d.ts +0 -61
- package/packages/@monomind/cli/dist/src/mcp/tool-registry.js +0 -246
- package/packages/@monomind/cli/dist/src/mcp-tools/wasm-agent-tools.d.ts +0 -9
- package/packages/@monomind/cli/dist/src/mcp-tools/wasm-agent-tools.js +0 -230
- package/packages/@monomind/cli/dist/src/model/complexity-scorer.d.ts +0 -21
- package/packages/@monomind/cli/dist/src/model/complexity-scorer.js +0 -106
- package/packages/@monomind/cli/dist/src/model/index.d.ts +0 -4
- package/packages/@monomind/cli/dist/src/model/index.js +0 -4
- package/packages/@monomind/cli/dist/src/model/model-settings.d.ts +0 -22
- package/packages/@monomind/cli/dist/src/model/model-settings.js +0 -33
- package/packages/@monomind/cli/dist/src/model/model-tier-resolver.d.ts +0 -24
- package/packages/@monomind/cli/dist/src/model/model-tier-resolver.js +0 -65
- package/packages/@monomind/cli/dist/src/monovector/capabilities.d.ts +0 -34
- package/packages/@monomind/cli/dist/src/monovector/capabilities.js +0 -37
- package/packages/@monomind/cli/dist/src/orchestration/index.d.ts +0 -7
- package/packages/@monomind/cli/dist/src/orchestration/index.js +0 -6
- package/packages/@monomind/cli/dist/src/orchestration/mode-dispatcher.d.ts +0 -11
- package/packages/@monomind/cli/dist/src/orchestration/mode-dispatcher.js +0 -31
- package/packages/@monomind/cli/dist/src/orchestration/routing-modes.d.ts +0 -68
- package/packages/@monomind/cli/dist/src/orchestration/routing-modes.js +0 -180
- package/packages/@monomind/cli/dist/src/plugins/tests/demo-plugin-store.d.ts +0 -7
- package/packages/@monomind/cli/dist/src/plugins/tests/demo-plugin-store.js +0 -126
- package/packages/@monomind/cli/dist/src/plugins/tests/standalone-test.d.ts +0 -12
- package/packages/@monomind/cli/dist/src/plugins/tests/standalone-test.js +0 -188
- package/packages/@monomind/cli/dist/src/plugins/tests/test-plugin-store.d.ts +0 -7
- package/packages/@monomind/cli/dist/src/plugins/tests/test-plugin-store.js +0 -206
- package/packages/@monomind/cli/dist/src/runtime/headless.d.ts +0 -60
- package/packages/@monomind/cli/dist/src/runtime/headless.js +0 -284
- package/packages/@monomind/cli/dist/src/services/agentic-flow-bridge.d.ts +0 -50
- package/packages/@monomind/cli/dist/src/services/agentic-flow-bridge.js +0 -95
- package/packages/@monomind/cli/dist/src/services/container-worker-pool.d.ts +0 -197
- package/packages/@monomind/cli/dist/src/services/container-worker-pool.js +0 -623
- package/packages/@monomind/cli/dist/src/services/index.d.ts +0 -13
- package/packages/@monomind/cli/dist/src/services/index.js +0 -11
- package/packages/@monomind/cli/dist/src/services/worker-queue.d.ts +0 -201
- package/packages/@monomind/cli/dist/src/services/worker-queue.js +0 -594
- package/packages/@monomind/cli/dist/src/swarm/communication-graph.d.ts +0 -25
- package/packages/@monomind/cli/dist/src/swarm/communication-graph.js +0 -77
- package/packages/@monomind/cli/dist/src/swarm/flow-enforcer.d.ts +0 -31
- package/packages/@monomind/cli/dist/src/swarm/flow-enforcer.js +0 -61
- package/packages/@monomind/cli/dist/src/swarm/flow-visualizer.d.ts +0 -19
- package/packages/@monomind/cli/dist/src/swarm/flow-visualizer.js +0 -68
- package/packages/@monomind/cli/dist/src/transfer/deploy-seraphine.d.ts +0 -13
- package/packages/@monomind/cli/dist/src/transfer/deploy-seraphine.js +0 -205
- package/packages/@monomind/cli/dist/src/transfer/store/tests/standalone-test.d.ts +0 -12
- package/packages/@monomind/cli/dist/src/transfer/store/tests/standalone-test.js +0 -190
- package/packages/@monomind/cli/dist/src/transfer/test-seraphine.d.ts +0 -6
- package/packages/@monomind/cli/dist/src/transfer/test-seraphine.js +0 -105
- package/packages/@monomind/cli/dist/src/transfer/tests/test-store.d.ts +0 -7
- package/packages/@monomind/cli/dist/src/transfer/tests/test-store.js +0 -214
- package/packages/@monomind/cli/dist/src/workflow/condition-evaluator.d.ts +0 -10
- package/packages/@monomind/cli/dist/src/workflow/condition-evaluator.js +0 -82
- package/packages/@monomind/cli/dist/src/workflow/context-resolver.d.ts +0 -12
- package/packages/@monomind/cli/dist/src/workflow/context-resolver.js +0 -23
- package/packages/@monomind/cli/dist/src/workflow/dag-builder.d.ts +0 -17
- package/packages/@monomind/cli/dist/src/workflow/dag-builder.js +0 -129
- package/packages/@monomind/cli/dist/src/workflow/dag-executor.d.ts +0 -9
- package/packages/@monomind/cli/dist/src/workflow/dag-executor.js +0 -116
- package/packages/@monomind/cli/dist/src/workflow/dag-types.d.ts +0 -41
- package/packages/@monomind/cli/dist/src/workflow/dag-types.js +0 -8
- package/packages/@monomind/cli/dist/src/workflow/dsl-parser.d.ts +0 -12
- package/packages/@monomind/cli/dist/src/workflow/dsl-parser.js +0 -20
- package/packages/@monomind/cli/dist/src/workflow/dsl-schema.d.ts +0 -165
- package/packages/@monomind/cli/dist/src/workflow/dsl-schema.js +0 -82
- package/packages/@monomind/cli/dist/src/workflow/index.d.ts +0 -13
- package/packages/@monomind/cli/dist/src/workflow/index.js +0 -11
- package/packages/@monomind/cli/dist/src/workflow/template-engine.d.ts +0 -11
- package/packages/@monomind/cli/dist/src/workflow/template-engine.js +0 -40
- package/packages/@monomind/cli/dist/src/workflow/workflow-executor.d.ts +0 -29
- package/packages/@monomind/cli/dist/src/workflow/workflow-executor.js +0 -227
- package/packages/@monomind/guidance/dist/adversarial.d.ts +0 -284
- package/packages/@monomind/guidance/dist/adversarial.js +0 -572
- package/packages/@monomind/guidance/dist/analyzer.d.ts +0 -530
- package/packages/@monomind/guidance/dist/analyzer.js +0 -2518
- package/packages/@monomind/guidance/dist/artifacts.d.ts +0 -283
- package/packages/@monomind/guidance/dist/artifacts.js +0 -356
- package/packages/@monomind/guidance/dist/authority.d.ts +0 -290
- package/packages/@monomind/guidance/dist/authority.js +0 -558
- package/packages/@monomind/guidance/dist/capabilities.d.ts +0 -209
- package/packages/@monomind/guidance/dist/capabilities.js +0 -485
- package/packages/@monomind/guidance/dist/coherence.d.ts +0 -233
- package/packages/@monomind/guidance/dist/coherence.js +0 -372
- package/packages/@monomind/guidance/dist/compiler.d.ts +0 -87
- package/packages/@monomind/guidance/dist/compiler.js +0 -419
- package/packages/@monomind/guidance/dist/conformance-kit.d.ts +0 -225
- package/packages/@monomind/guidance/dist/conformance-kit.js +0 -629
- package/packages/@monomind/guidance/dist/continue-gate.d.ts +0 -214
- package/packages/@monomind/guidance/dist/continue-gate.js +0 -353
- package/packages/@monomind/guidance/dist/crypto-utils.d.ts +0 -17
- package/packages/@monomind/guidance/dist/crypto-utils.js +0 -24
- package/packages/@monomind/guidance/dist/evolution.d.ts +0 -282
- package/packages/@monomind/guidance/dist/evolution.js +0 -500
- package/packages/@monomind/guidance/dist/gates.d.ts +0 -79
- package/packages/@monomind/guidance/dist/gates.js +0 -302
- package/packages/@monomind/guidance/dist/gateway.d.ts +0 -206
- package/packages/@monomind/guidance/dist/gateway.js +0 -452
- package/packages/@monomind/guidance/dist/generators.d.ts +0 -153
- package/packages/@monomind/guidance/dist/generators.js +0 -682
- package/packages/@monomind/guidance/dist/headless.d.ts +0 -177
- package/packages/@monomind/guidance/dist/headless.js +0 -342
- package/packages/@monomind/guidance/dist/hooks.d.ts +0 -109
- package/packages/@monomind/guidance/dist/hooks.js +0 -347
- package/packages/@monomind/guidance/dist/index.d.ts +0 -205
- package/packages/@monomind/guidance/dist/index.js +0 -321
- package/packages/@monomind/guidance/dist/ledger.d.ts +0 -162
- package/packages/@monomind/guidance/dist/ledger.js +0 -375
- package/packages/@monomind/guidance/dist/manifest-validator.d.ts +0 -289
- package/packages/@monomind/guidance/dist/manifest-validator.js +0 -838
- package/packages/@monomind/guidance/dist/memory-gate.d.ts +0 -222
- package/packages/@monomind/guidance/dist/memory-gate.js +0 -382
- package/packages/@monomind/guidance/dist/meta-governance.d.ts +0 -265
- package/packages/@monomind/guidance/dist/meta-governance.js +0 -348
- package/packages/@monomind/guidance/dist/optimizer.d.ts +0 -104
- package/packages/@monomind/guidance/dist/optimizer.js +0 -329
- package/packages/@monomind/guidance/dist/persistence.d.ts +0 -189
- package/packages/@monomind/guidance/dist/persistence.js +0 -464
- package/packages/@monomind/guidance/dist/proof.d.ts +0 -185
- package/packages/@monomind/guidance/dist/proof.js +0 -238
- package/packages/@monomind/guidance/dist/retriever.d.ts +0 -116
- package/packages/@monomind/guidance/dist/retriever.js +0 -394
- package/packages/@monomind/guidance/dist/ruvbot-integration.d.ts +0 -370
- package/packages/@monomind/guidance/dist/ruvbot-integration.js +0 -738
- package/packages/@monomind/guidance/dist/temporal.d.ts +0 -426
- package/packages/@monomind/guidance/dist/temporal.js +0 -658
- package/packages/@monomind/guidance/dist/trust.d.ts +0 -283
- package/packages/@monomind/guidance/dist/trust.js +0 -473
- package/packages/@monomind/guidance/dist/truth-anchors.d.ts +0 -276
- package/packages/@monomind/guidance/dist/truth-anchors.js +0 -488
- package/packages/@monomind/guidance/dist/types.d.ts +0 -378
- package/packages/@monomind/guidance/dist/types.js +0 -10
- package/packages/@monomind/guidance/dist/uncertainty.d.ts +0 -372
- package/packages/@monomind/guidance/dist/uncertainty.js +0 -619
- package/packages/@monomind/guidance/dist/wasm-kernel.d.ts +0 -48
- package/packages/@monomind/guidance/dist/wasm-kernel.js +0 -158
|
@@ -1,594 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Worker Queue Service
|
|
3
|
-
* Redis-based task queue for distributed headless worker execution.
|
|
4
|
-
*
|
|
5
|
-
* ADR-020: Headless Worker Integration Architecture - Phase 4
|
|
6
|
-
* - Priority-based task scheduling
|
|
7
|
-
* - Result persistence and retrieval
|
|
8
|
-
* - Distributed locking for task assignment
|
|
9
|
-
* - Dead letter queue for failed tasks
|
|
10
|
-
* - Metrics and monitoring
|
|
11
|
-
*
|
|
12
|
-
* Key Features:
|
|
13
|
-
* - FIFO with priority levels (critical, high, normal, low)
|
|
14
|
-
* - Automatic retry with exponential backoff
|
|
15
|
-
* - Task timeout detection
|
|
16
|
-
* - Result caching with TTL
|
|
17
|
-
* - Worker heartbeat monitoring
|
|
18
|
-
*/
|
|
19
|
-
import { EventEmitter } from 'events';
|
|
20
|
-
import { randomUUID } from 'crypto';
|
|
21
|
-
// ============================================
|
|
22
|
-
// Constants
|
|
23
|
-
// ============================================
|
|
24
|
-
const DEFAULT_CONFIG = {
|
|
25
|
-
redisUrl: 'redis://localhost:6379',
|
|
26
|
-
queuePrefix: 'monomind:queue',
|
|
27
|
-
defaultTimeoutMs: 300000, // 5 minutes
|
|
28
|
-
maxRetries: 3,
|
|
29
|
-
resultTtlSeconds: 86400, // 24 hours
|
|
30
|
-
heartbeatIntervalMs: 30000, // 30 seconds
|
|
31
|
-
deadLetterEnabled: true,
|
|
32
|
-
visibilityTimeoutMs: 60000, // 1 minute
|
|
33
|
-
};
|
|
34
|
-
const PRIORITY_SCORES = {
|
|
35
|
-
critical: 4,
|
|
36
|
-
high: 3,
|
|
37
|
-
normal: 2,
|
|
38
|
-
low: 1,
|
|
39
|
-
};
|
|
40
|
-
// ============================================
|
|
41
|
-
// In-Memory Redis Simulation (for non-Redis environments)
|
|
42
|
-
// ============================================
|
|
43
|
-
/**
|
|
44
|
-
* Simple in-memory queue implementation for environments without Redis
|
|
45
|
-
* Production should use actual Redis connection
|
|
46
|
-
*/
|
|
47
|
-
class InMemoryStore {
|
|
48
|
-
tasks = new Map();
|
|
49
|
-
queues = new Map();
|
|
50
|
-
workers = new Map();
|
|
51
|
-
results = new Map();
|
|
52
|
-
cleanupTimer;
|
|
53
|
-
/**
|
|
54
|
-
* Start cleanup timer (called after initialization)
|
|
55
|
-
*/
|
|
56
|
-
startCleanup() {
|
|
57
|
-
if (this.cleanupTimer)
|
|
58
|
-
return;
|
|
59
|
-
this.cleanupTimer = setInterval(() => this.cleanupExpired(), 60000);
|
|
60
|
-
this.cleanupTimer.unref();
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Stop cleanup timer
|
|
64
|
-
*/
|
|
65
|
-
stopCleanup() {
|
|
66
|
-
if (this.cleanupTimer) {
|
|
67
|
-
clearInterval(this.cleanupTimer);
|
|
68
|
-
this.cleanupTimer = undefined;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
// Task operations
|
|
72
|
-
setTask(id, task) {
|
|
73
|
-
this.tasks.set(id, task);
|
|
74
|
-
}
|
|
75
|
-
getTask(id) {
|
|
76
|
-
return this.tasks.get(id);
|
|
77
|
-
}
|
|
78
|
-
deleteTask(id) {
|
|
79
|
-
this.tasks.delete(id);
|
|
80
|
-
}
|
|
81
|
-
// Queue operations
|
|
82
|
-
pushToQueue(queue, taskId, priority) {
|
|
83
|
-
const queueTasks = this.queues.get(queue) || [];
|
|
84
|
-
// Insert based on priority (higher priority = earlier in queue)
|
|
85
|
-
let insertIndex = queueTasks.length;
|
|
86
|
-
for (let i = 0; i < queueTasks.length; i++) {
|
|
87
|
-
const task = this.tasks.get(queueTasks[i]);
|
|
88
|
-
if (task && PRIORITY_SCORES[task.priority] < priority) {
|
|
89
|
-
insertIndex = i;
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
queueTasks.splice(insertIndex, 0, taskId);
|
|
94
|
-
this.queues.set(queue, queueTasks);
|
|
95
|
-
}
|
|
96
|
-
popFromQueue(queue) {
|
|
97
|
-
const queueTasks = this.queues.get(queue) || [];
|
|
98
|
-
if (queueTasks.length === 0)
|
|
99
|
-
return null;
|
|
100
|
-
return queueTasks.shift() || null;
|
|
101
|
-
}
|
|
102
|
-
getQueueLength(queue) {
|
|
103
|
-
return (this.queues.get(queue) || []).length;
|
|
104
|
-
}
|
|
105
|
-
// Worker operations
|
|
106
|
-
setWorker(workerId, registration) {
|
|
107
|
-
this.workers.set(workerId, registration);
|
|
108
|
-
}
|
|
109
|
-
getWorker(workerId) {
|
|
110
|
-
return this.workers.get(workerId);
|
|
111
|
-
}
|
|
112
|
-
deleteWorker(workerId) {
|
|
113
|
-
this.workers.delete(workerId);
|
|
114
|
-
}
|
|
115
|
-
getAllWorkers() {
|
|
116
|
-
return Array.from(this.workers.values());
|
|
117
|
-
}
|
|
118
|
-
// Result operations
|
|
119
|
-
setResult(taskId, result, ttlSeconds) {
|
|
120
|
-
this.results.set(taskId, {
|
|
121
|
-
result,
|
|
122
|
-
expiresAt: Date.now() + ttlSeconds * 1000,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
getResult(taskId) {
|
|
126
|
-
const entry = this.results.get(taskId);
|
|
127
|
-
if (!entry)
|
|
128
|
-
return undefined;
|
|
129
|
-
if (Date.now() > entry.expiresAt) {
|
|
130
|
-
this.results.delete(taskId);
|
|
131
|
-
return undefined;
|
|
132
|
-
}
|
|
133
|
-
return entry.result;
|
|
134
|
-
}
|
|
135
|
-
// Stats
|
|
136
|
-
getStats() {
|
|
137
|
-
return {
|
|
138
|
-
tasks: this.tasks.size,
|
|
139
|
-
workers: this.workers.size,
|
|
140
|
-
results: this.results.size,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
// Cleanup
|
|
144
|
-
cleanupExpired() {
|
|
145
|
-
const now = Date.now();
|
|
146
|
-
for (const [id, entry] of this.results) {
|
|
147
|
-
if (now > entry.expiresAt) {
|
|
148
|
-
this.results.delete(id);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
// ============================================
|
|
154
|
-
// WorkerQueue Class
|
|
155
|
-
// ============================================
|
|
156
|
-
/**
|
|
157
|
-
* WorkerQueue - Redis-based task queue for distributed worker execution
|
|
158
|
-
*/
|
|
159
|
-
export class WorkerQueue extends EventEmitter {
|
|
160
|
-
config;
|
|
161
|
-
store;
|
|
162
|
-
workerId;
|
|
163
|
-
heartbeatTimer;
|
|
164
|
-
visibilityTimer;
|
|
165
|
-
retryTimers = new Set();
|
|
166
|
-
processingTasks = new Set();
|
|
167
|
-
// Per-task lease generation. When the visibility reaper requeues a task
|
|
168
|
-
// because of timeout, the generation is bumped. The original (still-running)
|
|
169
|
-
// handler's complete()/fail() call carries the old generation and is
|
|
170
|
-
// rejected — first-finisher wins, the loser drops. This prevents
|
|
171
|
-
// double-execution side effects on non-idempotent workers (audit reports,
|
|
172
|
-
// GitHub posts, memory writes).
|
|
173
|
-
taskGenerations = new Map();
|
|
174
|
-
isShuttingDown = false;
|
|
175
|
-
maxConcurrent = 1;
|
|
176
|
-
initialized = false;
|
|
177
|
-
constructor(config) {
|
|
178
|
-
super();
|
|
179
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
180
|
-
this.store = new InMemoryStore();
|
|
181
|
-
this.workerId = `worker-${randomUUID().slice(0, 8)}`;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Initialize the queue (starts cleanup timers)
|
|
185
|
-
*/
|
|
186
|
-
async initialize() {
|
|
187
|
-
if (this.initialized)
|
|
188
|
-
return;
|
|
189
|
-
this.store.startCleanup();
|
|
190
|
-
this.startVisibilityReaper();
|
|
191
|
-
this.initialized = true;
|
|
192
|
-
this.emit('initialized', { workerId: this.workerId });
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Requeue processing tasks that exceeded the visibility timeout (crashed workers).
|
|
196
|
-
*/
|
|
197
|
-
startVisibilityReaper() {
|
|
198
|
-
this.visibilityTimer = setInterval(() => {
|
|
199
|
-
// Skip running the reaper while we're shutting down so it can't requeue
|
|
200
|
-
// tasks back into a queue that is about to be torn down.
|
|
201
|
-
if (this.isShuttingDown)
|
|
202
|
-
return;
|
|
203
|
-
const now = Date.now();
|
|
204
|
-
for (const taskId of this.processingTasks) {
|
|
205
|
-
const task = this.store.getTask(taskId);
|
|
206
|
-
if (!task) {
|
|
207
|
-
this.processingTasks.delete(taskId);
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
const startedMs = task.startedAt ? task.startedAt.getTime() : 0;
|
|
211
|
-
if (now - startedMs > this.config.visibilityTimeoutMs) {
|
|
212
|
-
this.processingTasks.delete(taskId);
|
|
213
|
-
if (task.retryCount < task.maxRetries) {
|
|
214
|
-
task.retryCount++;
|
|
215
|
-
task.status = 'pending';
|
|
216
|
-
task.startedAt = undefined;
|
|
217
|
-
task.workerId = undefined;
|
|
218
|
-
this.store.setTask(taskId, task);
|
|
219
|
-
const queueName = this.getQueueName(task.workerType);
|
|
220
|
-
this.store.pushToQueue(queueName, taskId, PRIORITY_SCORES[task.priority]);
|
|
221
|
-
this.emit('taskRetrying', { taskId, retryCount: task.retryCount, delay: 0 });
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
task.status = 'failed';
|
|
225
|
-
task.completedAt = new Date();
|
|
226
|
-
task.error = 'Visibility timeout exceeded';
|
|
227
|
-
this.store.setTask(taskId, task);
|
|
228
|
-
this.emit('taskFailed', { taskId, error: task.error });
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}, Math.max(5000, this.config.visibilityTimeoutMs / 4));
|
|
233
|
-
this.visibilityTimer.unref();
|
|
234
|
-
}
|
|
235
|
-
// ============================================
|
|
236
|
-
// Public API - Task Management
|
|
237
|
-
// ============================================
|
|
238
|
-
/**
|
|
239
|
-
* Enqueue a new task
|
|
240
|
-
*/
|
|
241
|
-
async enqueue(workerType, payload = {}, options) {
|
|
242
|
-
// Initialize if needed
|
|
243
|
-
if (!this.initialized) {
|
|
244
|
-
await this.initialize();
|
|
245
|
-
}
|
|
246
|
-
// Validate worker type
|
|
247
|
-
if (!workerType || typeof workerType !== 'string') {
|
|
248
|
-
throw new Error('Invalid worker type');
|
|
249
|
-
}
|
|
250
|
-
// Validate priority
|
|
251
|
-
const priority = options?.priority || 'normal';
|
|
252
|
-
if (!['critical', 'high', 'normal', 'low'].includes(priority)) {
|
|
253
|
-
throw new Error(`Invalid priority: ${priority}`);
|
|
254
|
-
}
|
|
255
|
-
const taskId = `task-${Date.now()}-${randomUUID().slice(0, 8)}`;
|
|
256
|
-
const task = {
|
|
257
|
-
id: taskId,
|
|
258
|
-
workerType,
|
|
259
|
-
priority,
|
|
260
|
-
payload: {
|
|
261
|
-
...payload,
|
|
262
|
-
timeoutMs: options?.timeoutMs || this.config.defaultTimeoutMs,
|
|
263
|
-
},
|
|
264
|
-
status: 'pending',
|
|
265
|
-
createdAt: new Date(),
|
|
266
|
-
retryCount: 0,
|
|
267
|
-
maxRetries: options?.maxRetries ?? this.config.maxRetries,
|
|
268
|
-
};
|
|
269
|
-
// Store task
|
|
270
|
-
this.store.setTask(taskId, task);
|
|
271
|
-
// Add to priority queue
|
|
272
|
-
const queueName = this.getQueueName(workerType);
|
|
273
|
-
this.store.pushToQueue(queueName, taskId, PRIORITY_SCORES[priority]);
|
|
274
|
-
this.emit('taskEnqueued', { taskId, workerType, priority });
|
|
275
|
-
return taskId;
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Dequeue a task for processing
|
|
279
|
-
*/
|
|
280
|
-
async dequeue(workerTypes) {
|
|
281
|
-
if (this.isShuttingDown)
|
|
282
|
-
return null;
|
|
283
|
-
// Check queues in priority order
|
|
284
|
-
for (const workerType of workerTypes) {
|
|
285
|
-
const queueName = this.getQueueName(workerType);
|
|
286
|
-
const taskId = this.store.popFromQueue(queueName);
|
|
287
|
-
if (taskId) {
|
|
288
|
-
const task = this.store.getTask(taskId);
|
|
289
|
-
if (task && task.status === 'pending') {
|
|
290
|
-
task.status = 'processing';
|
|
291
|
-
task.startedAt = new Date();
|
|
292
|
-
task.workerId = this.workerId;
|
|
293
|
-
this.store.setTask(taskId, task);
|
|
294
|
-
this.processingTasks.add(taskId);
|
|
295
|
-
// Bump lease generation. Stamp on the in-memory task so the
|
|
296
|
-
// handler's later complete()/fail() can compare and detect a
|
|
297
|
-
// reap-and-redequeue cycle.
|
|
298
|
-
const gen = (this.taskGenerations.get(taskId) ?? 0) + 1;
|
|
299
|
-
this.taskGenerations.set(taskId, gen);
|
|
300
|
-
task.__leaseGen = gen;
|
|
301
|
-
this.emit('taskDequeued', { taskId, workerType });
|
|
302
|
-
return task;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return null;
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Complete a task with result
|
|
310
|
-
*/
|
|
311
|
-
async complete(taskId, result, leaseGen) {
|
|
312
|
-
const task = this.store.getTask(taskId);
|
|
313
|
-
if (!task) {
|
|
314
|
-
this.emit('warning', { message: `Task ${taskId} not found for completion` });
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
// Reject stale leases: if the reaper requeued this task and another
|
|
318
|
-
// worker has already taken it (bumping the generation), drop our result.
|
|
319
|
-
if (leaseGen !== undefined && this.taskGenerations.get(taskId) !== leaseGen) {
|
|
320
|
-
this.emit('warning', { message: `Task ${taskId} complete() rejected: lease expired` });
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
task.status = 'completed';
|
|
324
|
-
task.completedAt = new Date();
|
|
325
|
-
task.result = result;
|
|
326
|
-
this.store.setTask(taskId, task);
|
|
327
|
-
// Store result with TTL
|
|
328
|
-
this.store.setResult(taskId, result, this.config.resultTtlSeconds);
|
|
329
|
-
this.processingTasks.delete(taskId);
|
|
330
|
-
this.emit('taskCompleted', { taskId, result, duration: task.completedAt.getTime() - (task.startedAt?.getTime() || 0) });
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Fail a task with error
|
|
334
|
-
*/
|
|
335
|
-
async fail(taskId, error, retryable = true, leaseGen) {
|
|
336
|
-
const task = this.store.getTask(taskId);
|
|
337
|
-
if (!task) {
|
|
338
|
-
this.emit('warning', { message: `Task ${taskId} not found for failure` });
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
if (leaseGen !== undefined && this.taskGenerations.get(taskId) !== leaseGen) {
|
|
342
|
-
this.emit('warning', { message: `Task ${taskId} fail() rejected: lease expired` });
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
this.processingTasks.delete(taskId);
|
|
346
|
-
// Check if we should retry
|
|
347
|
-
if (retryable && task.retryCount < task.maxRetries) {
|
|
348
|
-
task.retryCount++;
|
|
349
|
-
task.status = 'pending';
|
|
350
|
-
task.startedAt = undefined;
|
|
351
|
-
task.workerId = undefined;
|
|
352
|
-
task.error = error;
|
|
353
|
-
this.store.setTask(taskId, task);
|
|
354
|
-
// Re-queue with delay (exponential backoff). Track the timer so shutdown
|
|
355
|
-
// can clear it — otherwise pending retries fire after shutdown and push
|
|
356
|
-
// tasks back into a torn-down queue.
|
|
357
|
-
const delay = Math.min(30000, 1000 * Math.pow(2, task.retryCount));
|
|
358
|
-
const retryTimer = setTimeout(() => {
|
|
359
|
-
this.retryTimers.delete(retryTimer);
|
|
360
|
-
if (this.isShuttingDown)
|
|
361
|
-
return;
|
|
362
|
-
const queueName = this.getQueueName(task.workerType);
|
|
363
|
-
this.store.pushToQueue(queueName, taskId, PRIORITY_SCORES[task.priority]);
|
|
364
|
-
}, delay);
|
|
365
|
-
retryTimer.unref();
|
|
366
|
-
this.retryTimers.add(retryTimer);
|
|
367
|
-
this.emit('taskRetrying', { taskId, retryCount: task.retryCount, delay });
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
// Move to failed/dead letter
|
|
371
|
-
task.status = 'failed';
|
|
372
|
-
task.completedAt = new Date();
|
|
373
|
-
task.error = error;
|
|
374
|
-
this.store.setTask(taskId, task);
|
|
375
|
-
if (this.config.deadLetterEnabled) {
|
|
376
|
-
const dlqName = `${this.config.queuePrefix}:dlq`;
|
|
377
|
-
this.store.pushToQueue(dlqName, taskId, 0);
|
|
378
|
-
}
|
|
379
|
-
this.emit('taskFailed', { taskId, error, retryCount: task.retryCount });
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* Get task status
|
|
384
|
-
*/
|
|
385
|
-
async getTask(taskId) {
|
|
386
|
-
return this.store.getTask(taskId) || null;
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* Get task result
|
|
390
|
-
*/
|
|
391
|
-
async getResult(taskId) {
|
|
392
|
-
return this.store.getResult(taskId) || null;
|
|
393
|
-
}
|
|
394
|
-
/**
|
|
395
|
-
* Cancel a pending task
|
|
396
|
-
*/
|
|
397
|
-
async cancel(taskId) {
|
|
398
|
-
const task = this.store.getTask(taskId);
|
|
399
|
-
if (!task || task.status !== 'pending') {
|
|
400
|
-
return false;
|
|
401
|
-
}
|
|
402
|
-
task.status = 'cancelled';
|
|
403
|
-
task.completedAt = new Date();
|
|
404
|
-
this.store.setTask(taskId, task);
|
|
405
|
-
this.emit('taskCancelled', { taskId });
|
|
406
|
-
return true;
|
|
407
|
-
}
|
|
408
|
-
// ============================================
|
|
409
|
-
// Public API - Worker Management
|
|
410
|
-
// ============================================
|
|
411
|
-
/**
|
|
412
|
-
* Register this instance as a worker
|
|
413
|
-
*/
|
|
414
|
-
async registerWorker(workerTypes, options) {
|
|
415
|
-
// Initialize if needed
|
|
416
|
-
if (!this.initialized) {
|
|
417
|
-
await this.initialize();
|
|
418
|
-
}
|
|
419
|
-
// Validate worker types
|
|
420
|
-
if (!Array.isArray(workerTypes) || workerTypes.length === 0) {
|
|
421
|
-
throw new Error('Worker types must be a non-empty array');
|
|
422
|
-
}
|
|
423
|
-
this.maxConcurrent = options?.maxConcurrent || 1;
|
|
424
|
-
const registration = {
|
|
425
|
-
workerId: this.workerId,
|
|
426
|
-
workerTypes,
|
|
427
|
-
maxConcurrent: this.maxConcurrent,
|
|
428
|
-
currentTasks: 0,
|
|
429
|
-
lastHeartbeat: new Date(),
|
|
430
|
-
registeredAt: new Date(),
|
|
431
|
-
hostname: options?.hostname,
|
|
432
|
-
containerId: options?.containerId,
|
|
433
|
-
};
|
|
434
|
-
this.store.setWorker(this.workerId, registration);
|
|
435
|
-
// Start heartbeat
|
|
436
|
-
this.startHeartbeat();
|
|
437
|
-
this.emit('workerRegistered', { workerId: this.workerId, workerTypes });
|
|
438
|
-
return this.workerId;
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* Unregister this worker
|
|
442
|
-
*/
|
|
443
|
-
async unregisterWorker() {
|
|
444
|
-
this.stopHeartbeat();
|
|
445
|
-
this.store.deleteWorker(this.workerId);
|
|
446
|
-
this.emit('workerUnregistered', { workerId: this.workerId });
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Get all registered workers
|
|
450
|
-
*/
|
|
451
|
-
async getWorkers() {
|
|
452
|
-
return this.store.getAllWorkers();
|
|
453
|
-
}
|
|
454
|
-
// ============================================
|
|
455
|
-
// Public API - Statistics
|
|
456
|
-
// ============================================
|
|
457
|
-
/**
|
|
458
|
-
* Get queue statistics
|
|
459
|
-
*/
|
|
460
|
-
async getStats() {
|
|
461
|
-
const storeStats = this.store.getStats();
|
|
462
|
-
// This is a simplified implementation
|
|
463
|
-
// Full implementation would aggregate across all queues
|
|
464
|
-
const stats = {
|
|
465
|
-
pending: 0,
|
|
466
|
-
processing: this.processingTasks.size,
|
|
467
|
-
completed: 0,
|
|
468
|
-
failed: 0,
|
|
469
|
-
deadLetter: 0,
|
|
470
|
-
byPriority: { critical: 0, high: 0, normal: 0, low: 0 },
|
|
471
|
-
byWorkerType: {},
|
|
472
|
-
averageWaitTimeMs: 0,
|
|
473
|
-
averageProcessingTimeMs: 0,
|
|
474
|
-
};
|
|
475
|
-
return stats;
|
|
476
|
-
}
|
|
477
|
-
// ============================================
|
|
478
|
-
// Public API - Lifecycle
|
|
479
|
-
// ============================================
|
|
480
|
-
/**
|
|
481
|
-
* Start processing tasks
|
|
482
|
-
*/
|
|
483
|
-
async start(workerTypes, handler, options) {
|
|
484
|
-
await this.registerWorker(workerTypes, { maxConcurrent: options?.maxConcurrent });
|
|
485
|
-
const processLoop = async () => {
|
|
486
|
-
while (!this.isShuttingDown) {
|
|
487
|
-
try {
|
|
488
|
-
// Respect concurrency limit
|
|
489
|
-
if (this.processingTasks.size >= this.maxConcurrent) {
|
|
490
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
491
|
-
continue;
|
|
492
|
-
}
|
|
493
|
-
const task = await this.dequeue(workerTypes);
|
|
494
|
-
if (task) {
|
|
495
|
-
// Process task without blocking the loop (allows concurrency)
|
|
496
|
-
this.processTask(task, handler).catch(error => {
|
|
497
|
-
this.emit('error', { taskId: task.id, error: String(error) });
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
else {
|
|
501
|
-
// No task available, wait before polling again
|
|
502
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
catch (error) {
|
|
506
|
-
this.emit('error', { error: error instanceof Error ? error.message : String(error) });
|
|
507
|
-
// Wait before retrying to avoid tight error loop
|
|
508
|
-
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
// Start processing
|
|
513
|
-
processLoop().catch(error => {
|
|
514
|
-
this.emit('error', { error: error instanceof Error ? error.message : String(error) });
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* Process a single task
|
|
519
|
-
*/
|
|
520
|
-
async processTask(task, handler) {
|
|
521
|
-
try {
|
|
522
|
-
const result = await handler(task);
|
|
523
|
-
await this.complete(task.id, result);
|
|
524
|
-
}
|
|
525
|
-
catch (error) {
|
|
526
|
-
await this.fail(task.id, error instanceof Error ? error.message : String(error));
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
/**
|
|
530
|
-
* Shutdown the queue gracefully
|
|
531
|
-
*/
|
|
532
|
-
async shutdown() {
|
|
533
|
-
if (this.isShuttingDown)
|
|
534
|
-
return;
|
|
535
|
-
this.isShuttingDown = true;
|
|
536
|
-
// Wait for processing tasks to complete (with timeout)
|
|
537
|
-
const timeout = 30000;
|
|
538
|
-
const start = Date.now();
|
|
539
|
-
while (this.processingTasks.size > 0 && Date.now() - start < timeout) {
|
|
540
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
541
|
-
}
|
|
542
|
-
// Force fail remaining tasks
|
|
543
|
-
for (const taskId of this.processingTasks) {
|
|
544
|
-
await this.fail(taskId, 'Worker shutdown', false);
|
|
545
|
-
}
|
|
546
|
-
// Stop store cleanup and timers
|
|
547
|
-
this.store.stopCleanup();
|
|
548
|
-
if (this.visibilityTimer) {
|
|
549
|
-
clearInterval(this.visibilityTimer);
|
|
550
|
-
this.visibilityTimer = undefined;
|
|
551
|
-
}
|
|
552
|
-
for (const t of this.retryTimers)
|
|
553
|
-
clearTimeout(t);
|
|
554
|
-
this.retryTimers.clear();
|
|
555
|
-
await this.unregisterWorker();
|
|
556
|
-
this.initialized = false;
|
|
557
|
-
this.emit('shutdown', {});
|
|
558
|
-
}
|
|
559
|
-
// ============================================
|
|
560
|
-
// Private Methods
|
|
561
|
-
// ============================================
|
|
562
|
-
/**
|
|
563
|
-
* Get queue name for worker type
|
|
564
|
-
*/
|
|
565
|
-
getQueueName(workerType) {
|
|
566
|
-
return `${this.config.queuePrefix}:${workerType}`;
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Start heartbeat timer
|
|
570
|
-
*/
|
|
571
|
-
startHeartbeat() {
|
|
572
|
-
this.heartbeatTimer = setInterval(() => {
|
|
573
|
-
const registration = this.store.getWorker(this.workerId);
|
|
574
|
-
if (registration) {
|
|
575
|
-
registration.lastHeartbeat = new Date();
|
|
576
|
-
registration.currentTasks = this.processingTasks.size;
|
|
577
|
-
this.store.setWorker(this.workerId, registration);
|
|
578
|
-
}
|
|
579
|
-
}, this.config.heartbeatIntervalMs);
|
|
580
|
-
this.heartbeatTimer.unref();
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* Stop heartbeat timer
|
|
584
|
-
*/
|
|
585
|
-
stopHeartbeat() {
|
|
586
|
-
if (this.heartbeatTimer) {
|
|
587
|
-
clearInterval(this.heartbeatTimer);
|
|
588
|
-
this.heartbeatTimer = undefined;
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
// Export default
|
|
593
|
-
export default WorkerQueue;
|
|
594
|
-
//# sourceMappingURL=worker-queue.js.map
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CommunicationGraph (Task 40)
|
|
3
|
-
*
|
|
4
|
-
* Directed graph of allowed agent-to-agent communication flows.
|
|
5
|
-
* Empty flows = unrestricted (backward compatible).
|
|
6
|
-
*/
|
|
7
|
-
import type { FlowEdge } from '../../../shared/src/types/communication-flow.js';
|
|
8
|
-
export declare class CommunicationGraph {
|
|
9
|
-
private readonly adjacency;
|
|
10
|
-
private readonly reverse;
|
|
11
|
-
private readonly edges;
|
|
12
|
-
private readonly unrestricted;
|
|
13
|
-
constructor(flows: FlowEdge[]);
|
|
14
|
-
/** Check whether fromSlug is allowed to send to toSlug */
|
|
15
|
-
isAuthorized(fromSlug: string, toSlug: string): boolean;
|
|
16
|
-
/** Outbound targets for a given sender */
|
|
17
|
-
getTargets(fromSlug: string): string[];
|
|
18
|
-
/** Inbound sources for a given receiver */
|
|
19
|
-
getSources(toSlug: string): string[];
|
|
20
|
-
/** All declared edges */
|
|
21
|
-
allEdges(): FlowEdge[];
|
|
22
|
-
/** Detect cycles via DFS (returns true if at least one cycle exists) */
|
|
23
|
-
hasCycles(): boolean;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=communication-graph.d.ts.map
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CommunicationGraph (Task 40)
|
|
3
|
-
*
|
|
4
|
-
* Directed graph of allowed agent-to-agent communication flows.
|
|
5
|
-
* Empty flows = unrestricted (backward compatible).
|
|
6
|
-
*/
|
|
7
|
-
export class CommunicationGraph {
|
|
8
|
-
adjacency = new Map();
|
|
9
|
-
reverse = new Map();
|
|
10
|
-
edges;
|
|
11
|
-
unrestricted;
|
|
12
|
-
constructor(flows) {
|
|
13
|
-
this.edges = [...flows];
|
|
14
|
-
this.unrestricted = flows.length === 0;
|
|
15
|
-
for (const [from, to] of flows) {
|
|
16
|
-
if (!this.adjacency.has(from))
|
|
17
|
-
this.adjacency.set(from, new Set());
|
|
18
|
-
this.adjacency.get(from).add(to);
|
|
19
|
-
if (!this.reverse.has(to))
|
|
20
|
-
this.reverse.set(to, new Set());
|
|
21
|
-
this.reverse.get(to).add(from);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
/** Check whether fromSlug is allowed to send to toSlug */
|
|
25
|
-
isAuthorized(fromSlug, toSlug) {
|
|
26
|
-
if (this.unrestricted)
|
|
27
|
-
return true;
|
|
28
|
-
return this.adjacency.get(fromSlug)?.has(toSlug) === true;
|
|
29
|
-
}
|
|
30
|
-
/** Outbound targets for a given sender */
|
|
31
|
-
getTargets(fromSlug) {
|
|
32
|
-
if (this.unrestricted)
|
|
33
|
-
return [];
|
|
34
|
-
return Array.from(this.adjacency.get(fromSlug) ?? []);
|
|
35
|
-
}
|
|
36
|
-
/** Inbound sources for a given receiver */
|
|
37
|
-
getSources(toSlug) {
|
|
38
|
-
if (this.unrestricted)
|
|
39
|
-
return [];
|
|
40
|
-
return Array.from(this.reverse.get(toSlug) ?? []);
|
|
41
|
-
}
|
|
42
|
-
/** All declared edges */
|
|
43
|
-
allEdges() {
|
|
44
|
-
return [...this.edges];
|
|
45
|
-
}
|
|
46
|
-
/** Detect cycles via DFS (returns true if at least one cycle exists) */
|
|
47
|
-
hasCycles() {
|
|
48
|
-
const WHITE = 0, GREY = 1, BLACK = 2;
|
|
49
|
-
const color = new Map();
|
|
50
|
-
// Collect all nodes
|
|
51
|
-
const nodes = new Set();
|
|
52
|
-
for (const [from, to] of this.edges) {
|
|
53
|
-
nodes.add(from);
|
|
54
|
-
nodes.add(to);
|
|
55
|
-
}
|
|
56
|
-
for (const n of nodes)
|
|
57
|
-
color.set(n, WHITE);
|
|
58
|
-
const dfs = (node) => {
|
|
59
|
-
color.set(node, GREY);
|
|
60
|
-
for (const neighbor of this.adjacency.get(node) ?? []) {
|
|
61
|
-
const c = color.get(neighbor) ?? WHITE;
|
|
62
|
-
if (c === GREY)
|
|
63
|
-
return true;
|
|
64
|
-
if (c === WHITE && dfs(neighbor))
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
color.set(node, BLACK);
|
|
68
|
-
return false;
|
|
69
|
-
};
|
|
70
|
-
for (const n of nodes) {
|
|
71
|
-
if (color.get(n) === WHITE && dfs(n))
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
//# sourceMappingURL=communication-graph.js.map
|