monomind 1.11.13 → 1.11.14

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.
Files changed (231) hide show
  1. package/.claude/commands/mastermind/idea.md +1 -1
  2. package/.claude/commands/mastermind/master.md +1 -1
  3. package/.claude/scheduled_tasks.lock +1 -1
  4. package/.claude/skills/mastermind/_protocol.md +4 -4
  5. package/.claude/skills/mastermind/architect.md +4 -7
  6. package/.claude/skills/mastermind/autodev.md +2 -4
  7. package/.claude/skills/mastermind/build.md +3 -3
  8. package/.claude/skills/mastermind/content.md +3 -3
  9. package/.claude/skills/mastermind/createorg.md +2 -2
  10. package/.claude/skills/mastermind/finance.md +3 -3
  11. package/.claude/skills/mastermind/idea.md +0 -8
  12. package/.claude/skills/mastermind/marketing.md +3 -3
  13. package/.claude/skills/mastermind/monitor.md +2 -2
  14. package/.claude/skills/mastermind/ops.md +3 -3
  15. package/.claude/skills/mastermind/release.md +3 -3
  16. package/.claude/skills/mastermind/research.md +3 -3
  17. package/.claude/skills/mastermind/review.md +3 -3
  18. package/.claude/skills/mastermind/sales.md +3 -3
  19. package/README.md +286 -129
  20. package/package.json +2 -2
  21. package/packages/@monomind/cli/README.md +286 -129
  22. package/packages/@monomind/cli/bundled-graph/dist/src/build.js +73 -0
  23. package/packages/@monomind/cli/bundled-graph/dist/src/cluster.js +120 -0
  24. package/packages/@monomind/cli/bundled-graph/package.json +57 -0
  25. package/packages/@monomind/cli/dist/src/agents/halt-signal.d.ts +25 -0
  26. package/packages/@monomind/cli/dist/src/agents/halt-signal.js +76 -0
  27. package/packages/@monomind/cli/dist/src/agents/index.d.ts +18 -0
  28. package/packages/@monomind/cli/dist/src/agents/index.js +13 -0
  29. package/packages/@monomind/cli/dist/src/agents/managed-agent.d.ts +41 -0
  30. package/packages/@monomind/cli/dist/src/agents/managed-agent.js +69 -0
  31. package/packages/@monomind/cli/dist/src/agents/prompt-experiment.d.ts +23 -0
  32. package/packages/@monomind/cli/dist/src/agents/prompt-experiment.js +49 -0
  33. package/packages/@monomind/cli/dist/src/agents/prompt-version-manager.d.ts +22 -0
  34. package/packages/@monomind/cli/dist/src/agents/prompt-version-manager.js +80 -0
  35. package/packages/@monomind/cli/dist/src/agents/registry-query.d.ts +71 -0
  36. package/packages/@monomind/cli/dist/src/agents/registry-query.js +125 -0
  37. package/packages/@monomind/cli/dist/src/agents/score-decay.d.ts +19 -0
  38. package/packages/@monomind/cli/dist/src/agents/score-decay.js +22 -0
  39. package/packages/@monomind/cli/dist/src/agents/shared-instructions-loader.d.ts +13 -0
  40. package/packages/@monomind/cli/dist/src/agents/shared-instructions-loader.js +40 -0
  41. package/packages/@monomind/cli/dist/src/agents/specialization-scorer.d.ts +54 -0
  42. package/packages/@monomind/cli/dist/src/agents/specialization-scorer.js +212 -0
  43. package/packages/@monomind/cli/dist/src/agents/termination-watcher.d.ts +30 -0
  44. package/packages/@monomind/cli/dist/src/agents/termination-watcher.js +84 -0
  45. package/packages/@monomind/cli/dist/src/agents/trigger-index.d.ts +20 -0
  46. package/packages/@monomind/cli/dist/src/agents/trigger-index.js +38 -0
  47. package/packages/@monomind/cli/dist/src/agents/trigger-scanner.d.ts +64 -0
  48. package/packages/@monomind/cli/dist/src/agents/trigger-scanner.js +308 -0
  49. package/packages/@monomind/cli/dist/src/agents/version-diff.d.ts +18 -0
  50. package/packages/@monomind/cli/dist/src/agents/version-diff.js +64 -0
  51. package/packages/@monomind/cli/dist/src/agents/version-store.d.ts +60 -0
  52. package/packages/@monomind/cli/dist/src/agents/version-store.js +235 -0
  53. package/packages/@monomind/cli/dist/src/benchmarks/pretrain/index.d.ts +45 -0
  54. package/packages/@monomind/cli/dist/src/benchmarks/pretrain/index.js +404 -0
  55. package/packages/@monomind/cli/dist/src/commands/agent-wasm.d.ts +14 -0
  56. package/packages/@monomind/cli/dist/src/commands/agent-wasm.js +333 -0
  57. package/packages/@monomind/cli/dist/src/commands/doctor.js +55 -1
  58. package/packages/@monomind/cli/dist/src/commands/ui.js +68 -0
  59. package/packages/@monomind/cli/dist/src/consensus/index.d.ts +7 -0
  60. package/packages/@monomind/cli/dist/src/consensus/index.js +6 -0
  61. package/packages/@monomind/cli/dist/src/context/context-provider.d.ts +44 -0
  62. package/packages/@monomind/cli/dist/src/context/context-provider.js +25 -0
  63. package/packages/@monomind/cli/dist/src/context/git-state-provider.d.ts +12 -0
  64. package/packages/@monomind/cli/dist/src/context/git-state-provider.js +34 -0
  65. package/packages/@monomind/cli/dist/src/context/index.d.ts +12 -0
  66. package/packages/@monomind/cli/dist/src/context/index.js +12 -0
  67. package/packages/@monomind/cli/dist/src/context/project-conventions-provider.d.ts +15 -0
  68. package/packages/@monomind/cli/dist/src/context/project-conventions-provider.js +19 -0
  69. package/packages/@monomind/cli/dist/src/context/prompt-assembler.d.ts +26 -0
  70. package/packages/@monomind/cli/dist/src/context/prompt-assembler.js +93 -0
  71. package/packages/@monomind/cli/dist/src/context/task-history-provider.d.ts +24 -0
  72. package/packages/@monomind/cli/dist/src/context/task-history-provider.js +32 -0
  73. package/packages/@monomind/cli/dist/src/context/user-preferences-provider.d.ts +14 -0
  74. package/packages/@monomind/cli/dist/src/context/user-preferences-provider.js +27 -0
  75. package/packages/@monomind/cli/dist/src/dlq/dlq-reader.d.ts +31 -0
  76. package/packages/@monomind/cli/dist/src/dlq/dlq-reader.js +81 -0
  77. package/packages/@monomind/cli/dist/src/dlq/dlq-writer.d.ts +24 -0
  78. package/packages/@monomind/cli/dist/src/dlq/dlq-writer.js +65 -0
  79. package/packages/@monomind/cli/dist/src/dlq/index.d.ts +10 -0
  80. package/packages/@monomind/cli/dist/src/dlq/index.js +7 -0
  81. package/packages/@monomind/cli/dist/src/eval/dataset-manager.d.ts +33 -0
  82. package/packages/@monomind/cli/dist/src/eval/dataset-manager.js +107 -0
  83. package/packages/@monomind/cli/dist/src/eval/dataset-runner.d.ts +23 -0
  84. package/packages/@monomind/cli/dist/src/eval/dataset-runner.js +59 -0
  85. package/packages/@monomind/cli/dist/src/eval/index.d.ts +10 -0
  86. package/packages/@monomind/cli/dist/src/eval/index.js +7 -0
  87. package/packages/@monomind/cli/dist/src/eval/trace-collector.d.ts +40 -0
  88. package/packages/@monomind/cli/dist/src/eval/trace-collector.js +102 -0
  89. package/packages/@monomind/cli/dist/src/infrastructure/in-memory-repositories.d.ts +68 -0
  90. package/packages/@monomind/cli/dist/src/infrastructure/in-memory-repositories.js +264 -0
  91. package/packages/@monomind/cli/dist/src/init/statusline-generator.js +3 -3
  92. package/packages/@monomind/cli/dist/src/interactive/interrupt.d.ts +22 -0
  93. package/packages/@monomind/cli/dist/src/interactive/interrupt.js +71 -0
  94. package/packages/@monomind/cli/dist/src/mcp/deprecation-injector.d.ts +25 -0
  95. package/packages/@monomind/cli/dist/src/mcp/deprecation-injector.js +48 -0
  96. package/packages/@monomind/cli/dist/src/mcp/tool-registry.d.ts +61 -0
  97. package/packages/@monomind/cli/dist/src/mcp/tool-registry.js +246 -0
  98. package/packages/@monomind/cli/dist/src/mcp-tools/wasm-agent-tools.d.ts +9 -0
  99. package/packages/@monomind/cli/dist/src/mcp-tools/wasm-agent-tools.js +230 -0
  100. package/packages/@monomind/cli/dist/src/model/complexity-scorer.d.ts +21 -0
  101. package/packages/@monomind/cli/dist/src/model/complexity-scorer.js +106 -0
  102. package/packages/@monomind/cli/dist/src/model/index.d.ts +4 -0
  103. package/packages/@monomind/cli/dist/src/model/index.js +4 -0
  104. package/packages/@monomind/cli/dist/src/model/model-settings.d.ts +22 -0
  105. package/packages/@monomind/cli/dist/src/model/model-settings.js +33 -0
  106. package/packages/@monomind/cli/dist/src/model/model-tier-resolver.d.ts +24 -0
  107. package/packages/@monomind/cli/dist/src/model/model-tier-resolver.js +65 -0
  108. package/packages/@monomind/cli/dist/src/monovector/capabilities.d.ts +34 -0
  109. package/packages/@monomind/cli/dist/src/monovector/capabilities.js +37 -0
  110. package/packages/@monomind/cli/dist/src/observability/replay-reader.d.ts +1 -1
  111. package/packages/@monomind/cli/dist/src/orchestration/index.d.ts +7 -0
  112. package/packages/@monomind/cli/dist/src/orchestration/index.js +6 -0
  113. package/packages/@monomind/cli/dist/src/orchestration/mode-dispatcher.d.ts +11 -0
  114. package/packages/@monomind/cli/dist/src/orchestration/mode-dispatcher.js +31 -0
  115. package/packages/@monomind/cli/dist/src/orchestration/routing-modes.d.ts +68 -0
  116. package/packages/@monomind/cli/dist/src/orchestration/routing-modes.js +180 -0
  117. package/packages/@monomind/cli/dist/src/plugins/tests/demo-plugin-store.d.ts +7 -0
  118. package/packages/@monomind/cli/dist/src/plugins/tests/demo-plugin-store.js +126 -0
  119. package/packages/@monomind/cli/dist/src/plugins/tests/standalone-test.d.ts +12 -0
  120. package/packages/@monomind/cli/dist/src/plugins/tests/standalone-test.js +188 -0
  121. package/packages/@monomind/cli/dist/src/plugins/tests/test-plugin-store.d.ts +7 -0
  122. package/packages/@monomind/cli/dist/src/plugins/tests/test-plugin-store.js +206 -0
  123. package/packages/@monomind/cli/dist/src/runtime/headless.d.ts +60 -0
  124. package/packages/@monomind/cli/dist/src/runtime/headless.js +284 -0
  125. package/packages/@monomind/cli/dist/src/services/agentic-flow-bridge.d.ts +50 -0
  126. package/packages/@monomind/cli/dist/src/services/agentic-flow-bridge.js +95 -0
  127. package/packages/@monomind/cli/dist/src/services/container-worker-pool.d.ts +197 -0
  128. package/packages/@monomind/cli/dist/src/services/container-worker-pool.js +623 -0
  129. package/packages/@monomind/cli/dist/src/services/index.d.ts +13 -0
  130. package/packages/@monomind/cli/dist/src/services/index.js +11 -0
  131. package/packages/@monomind/cli/dist/src/services/worker-queue.d.ts +201 -0
  132. package/packages/@monomind/cli/dist/src/services/worker-queue.js +594 -0
  133. package/packages/@monomind/cli/dist/src/swarm/communication-graph.d.ts +25 -0
  134. package/packages/@monomind/cli/dist/src/swarm/communication-graph.js +77 -0
  135. package/packages/@monomind/cli/dist/src/swarm/flow-enforcer.d.ts +31 -0
  136. package/packages/@monomind/cli/dist/src/swarm/flow-enforcer.js +61 -0
  137. package/packages/@monomind/cli/dist/src/swarm/flow-visualizer.d.ts +19 -0
  138. package/packages/@monomind/cli/dist/src/swarm/flow-visualizer.js +68 -0
  139. package/packages/@monomind/cli/dist/src/transfer/deploy-seraphine.d.ts +13 -0
  140. package/packages/@monomind/cli/dist/src/transfer/deploy-seraphine.js +205 -0
  141. package/packages/@monomind/cli/dist/src/transfer/store/tests/standalone-test.d.ts +12 -0
  142. package/packages/@monomind/cli/dist/src/transfer/store/tests/standalone-test.js +190 -0
  143. package/packages/@monomind/cli/dist/src/transfer/test-seraphine.d.ts +6 -0
  144. package/packages/@monomind/cli/dist/src/transfer/test-seraphine.js +105 -0
  145. package/packages/@monomind/cli/dist/src/transfer/tests/test-store.d.ts +7 -0
  146. package/packages/@monomind/cli/dist/src/transfer/tests/test-store.js +214 -0
  147. package/packages/@monomind/cli/dist/src/workflow/condition-evaluator.d.ts +10 -0
  148. package/packages/@monomind/cli/dist/src/workflow/condition-evaluator.js +82 -0
  149. package/packages/@monomind/cli/dist/src/workflow/context-resolver.d.ts +12 -0
  150. package/packages/@monomind/cli/dist/src/workflow/context-resolver.js +23 -0
  151. package/packages/@monomind/cli/dist/src/workflow/dag-builder.d.ts +17 -0
  152. package/packages/@monomind/cli/dist/src/workflow/dag-builder.js +129 -0
  153. package/packages/@monomind/cli/dist/src/workflow/dag-executor.d.ts +9 -0
  154. package/packages/@monomind/cli/dist/src/workflow/dag-executor.js +116 -0
  155. package/packages/@monomind/cli/dist/src/workflow/dag-types.d.ts +41 -0
  156. package/packages/@monomind/cli/dist/src/workflow/dag-types.js +8 -0
  157. package/packages/@monomind/cli/dist/src/workflow/dsl-parser.d.ts +12 -0
  158. package/packages/@monomind/cli/dist/src/workflow/dsl-parser.js +20 -0
  159. package/packages/@monomind/cli/dist/src/workflow/dsl-schema.d.ts +165 -0
  160. package/packages/@monomind/cli/dist/src/workflow/dsl-schema.js +82 -0
  161. package/packages/@monomind/cli/dist/src/workflow/index.d.ts +13 -0
  162. package/packages/@monomind/cli/dist/src/workflow/index.js +11 -0
  163. package/packages/@monomind/cli/dist/src/workflow/template-engine.d.ts +11 -0
  164. package/packages/@monomind/cli/dist/src/workflow/template-engine.js +40 -0
  165. package/packages/@monomind/cli/dist/src/workflow/workflow-executor.d.ts +29 -0
  166. package/packages/@monomind/cli/dist/src/workflow/workflow-executor.js +227 -0
  167. package/packages/@monomind/cli/package.json +9 -9
  168. package/packages/@monomind/guidance/dist/adversarial.d.ts +284 -0
  169. package/packages/@monomind/guidance/dist/adversarial.js +572 -0
  170. package/packages/@monomind/guidance/dist/analyzer.d.ts +530 -0
  171. package/packages/@monomind/guidance/dist/analyzer.js +2518 -0
  172. package/packages/@monomind/guidance/dist/artifacts.d.ts +283 -0
  173. package/packages/@monomind/guidance/dist/artifacts.js +356 -0
  174. package/packages/@monomind/guidance/dist/authority.d.ts +290 -0
  175. package/packages/@monomind/guidance/dist/authority.js +558 -0
  176. package/packages/@monomind/guidance/dist/capabilities.d.ts +209 -0
  177. package/packages/@monomind/guidance/dist/capabilities.js +485 -0
  178. package/packages/@monomind/guidance/dist/coherence.d.ts +233 -0
  179. package/packages/@monomind/guidance/dist/coherence.js +372 -0
  180. package/packages/@monomind/guidance/dist/compiler.d.ts +87 -0
  181. package/packages/@monomind/guidance/dist/compiler.js +419 -0
  182. package/packages/@monomind/guidance/dist/conformance-kit.d.ts +225 -0
  183. package/packages/@monomind/guidance/dist/conformance-kit.js +629 -0
  184. package/packages/@monomind/guidance/dist/continue-gate.d.ts +214 -0
  185. package/packages/@monomind/guidance/dist/continue-gate.js +353 -0
  186. package/packages/@monomind/guidance/dist/crypto-utils.d.ts +17 -0
  187. package/packages/@monomind/guidance/dist/crypto-utils.js +24 -0
  188. package/packages/@monomind/guidance/dist/evolution.d.ts +282 -0
  189. package/packages/@monomind/guidance/dist/evolution.js +500 -0
  190. package/packages/@monomind/guidance/dist/gates.d.ts +79 -0
  191. package/packages/@monomind/guidance/dist/gates.js +302 -0
  192. package/packages/@monomind/guidance/dist/gateway.d.ts +206 -0
  193. package/packages/@monomind/guidance/dist/gateway.js +452 -0
  194. package/packages/@monomind/guidance/dist/generators.d.ts +153 -0
  195. package/packages/@monomind/guidance/dist/generators.js +682 -0
  196. package/packages/@monomind/guidance/dist/headless.d.ts +177 -0
  197. package/packages/@monomind/guidance/dist/headless.js +342 -0
  198. package/packages/@monomind/guidance/dist/hooks.d.ts +109 -0
  199. package/packages/@monomind/guidance/dist/hooks.js +347 -0
  200. package/packages/@monomind/guidance/dist/index.d.ts +205 -0
  201. package/packages/@monomind/guidance/dist/index.js +321 -0
  202. package/packages/@monomind/guidance/dist/ledger.d.ts +162 -0
  203. package/packages/@monomind/guidance/dist/ledger.js +375 -0
  204. package/packages/@monomind/guidance/dist/manifest-validator.d.ts +289 -0
  205. package/packages/@monomind/guidance/dist/manifest-validator.js +838 -0
  206. package/packages/@monomind/guidance/dist/memory-gate.d.ts +222 -0
  207. package/packages/@monomind/guidance/dist/memory-gate.js +382 -0
  208. package/packages/@monomind/guidance/dist/meta-governance.d.ts +265 -0
  209. package/packages/@monomind/guidance/dist/meta-governance.js +348 -0
  210. package/packages/@monomind/guidance/dist/optimizer.d.ts +104 -0
  211. package/packages/@monomind/guidance/dist/optimizer.js +329 -0
  212. package/packages/@monomind/guidance/dist/persistence.d.ts +189 -0
  213. package/packages/@monomind/guidance/dist/persistence.js +464 -0
  214. package/packages/@monomind/guidance/dist/proof.d.ts +185 -0
  215. package/packages/@monomind/guidance/dist/proof.js +238 -0
  216. package/packages/@monomind/guidance/dist/retriever.d.ts +116 -0
  217. package/packages/@monomind/guidance/dist/retriever.js +394 -0
  218. package/packages/@monomind/guidance/dist/ruvbot-integration.d.ts +370 -0
  219. package/packages/@monomind/guidance/dist/ruvbot-integration.js +738 -0
  220. package/packages/@monomind/guidance/dist/temporal.d.ts +426 -0
  221. package/packages/@monomind/guidance/dist/temporal.js +658 -0
  222. package/packages/@monomind/guidance/dist/trust.d.ts +283 -0
  223. package/packages/@monomind/guidance/dist/trust.js +473 -0
  224. package/packages/@monomind/guidance/dist/truth-anchors.d.ts +276 -0
  225. package/packages/@monomind/guidance/dist/truth-anchors.js +488 -0
  226. package/packages/@monomind/guidance/dist/types.d.ts +378 -0
  227. package/packages/@monomind/guidance/dist/types.js +10 -0
  228. package/packages/@monomind/guidance/dist/uncertainty.d.ts +372 -0
  229. package/packages/@monomind/guidance/dist/uncertainty.js +619 -0
  230. package/packages/@monomind/guidance/dist/wasm-kernel.d.ts +48 -0
  231. package/packages/@monomind/guidance/dist/wasm-kernel.js +158 -0
@@ -0,0 +1,594 @@
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
@@ -0,0 +1,25 @@
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
@@ -0,0 +1,77 @@
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