@the-open-engine/zeroshot 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/CHANGELOG.md +539 -0
  2. package/LICENSE +21 -0
  3. package/README.md +508 -0
  4. package/cli/commands/inspect-render.js +135 -0
  5. package/cli/commands/inspect.js +294 -0
  6. package/cli/commands/providers.js +149 -0
  7. package/cli/index.js +5431 -0
  8. package/cli/lib/first-run.js +211 -0
  9. package/cli/lib/update-checker.js +281 -0
  10. package/cli/message-formatter-utils.js +75 -0
  11. package/cli/message-formatters-normal.js +275 -0
  12. package/cli/message-formatters-watch.js +185 -0
  13. package/cluster-templates/base-templates/debug-workflow.json +422 -0
  14. package/cluster-templates/base-templates/full-workflow.json +727 -0
  15. package/cluster-templates/base-templates/heavy-validation.json +272 -0
  16. package/cluster-templates/base-templates/quick-validation.json +285 -0
  17. package/cluster-templates/base-templates/single-worker.json +71 -0
  18. package/cluster-templates/base-templates/worker-validator.json +230 -0
  19. package/cluster-templates/conductor-bootstrap.json +130 -0
  20. package/docker/zeroshot-cluster/Dockerfile +153 -0
  21. package/docker/zeroshot-cluster/pre-baked-deps.json +28 -0
  22. package/lib/agent-cli-provider/adapters/claude-parser.d.ts +3 -0
  23. package/lib/agent-cli-provider/adapters/claude-parser.d.ts.map +1 -0
  24. package/lib/agent-cli-provider/adapters/claude-parser.js +122 -0
  25. package/lib/agent-cli-provider/adapters/claude-parser.js.map +1 -0
  26. package/lib/agent-cli-provider/adapters/claude-recovery.d.ts +15 -0
  27. package/lib/agent-cli-provider/adapters/claude-recovery.d.ts.map +1 -0
  28. package/lib/agent-cli-provider/adapters/claude-recovery.js +165 -0
  29. package/lib/agent-cli-provider/adapters/claude-recovery.js.map +1 -0
  30. package/lib/agent-cli-provider/adapters/claude.d.ts +3 -0
  31. package/lib/agent-cli-provider/adapters/claude.d.ts.map +1 -0
  32. package/lib/agent-cli-provider/adapters/claude.js +181 -0
  33. package/lib/agent-cli-provider/adapters/claude.js.map +1 -0
  34. package/lib/agent-cli-provider/adapters/codex-parser.d.ts +3 -0
  35. package/lib/agent-cli-provider/adapters/codex-parser.d.ts.map +1 -0
  36. package/lib/agent-cli-provider/adapters/codex-parser.js +192 -0
  37. package/lib/agent-cli-provider/adapters/codex-parser.js.map +1 -0
  38. package/lib/agent-cli-provider/adapters/codex.d.ts +3 -0
  39. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -0
  40. package/lib/agent-cli-provider/adapters/codex.js +151 -0
  41. package/lib/agent-cli-provider/adapters/codex.js.map +1 -0
  42. package/lib/agent-cli-provider/adapters/common.d.ts +28 -0
  43. package/lib/agent-cli-provider/adapters/common.d.ts.map +1 -0
  44. package/lib/agent-cli-provider/adapters/common.js +71 -0
  45. package/lib/agent-cli-provider/adapters/common.js.map +1 -0
  46. package/lib/agent-cli-provider/adapters/gemini.d.ts +3 -0
  47. package/lib/agent-cli-provider/adapters/gemini.d.ts.map +1 -0
  48. package/lib/agent-cli-provider/adapters/gemini.js +176 -0
  49. package/lib/agent-cli-provider/adapters/gemini.js.map +1 -0
  50. package/lib/agent-cli-provider/adapters/index.d.ts +9 -0
  51. package/lib/agent-cli-provider/adapters/index.d.ts.map +1 -0
  52. package/lib/agent-cli-provider/adapters/index.js +95 -0
  53. package/lib/agent-cli-provider/adapters/index.js.map +1 -0
  54. package/lib/agent-cli-provider/adapters/opencode.d.ts +3 -0
  55. package/lib/agent-cli-provider/adapters/opencode.d.ts.map +1 -0
  56. package/lib/agent-cli-provider/adapters/opencode.js +228 -0
  57. package/lib/agent-cli-provider/adapters/opencode.js.map +1 -0
  58. package/lib/agent-cli-provider/contract-actions.d.ts +5 -0
  59. package/lib/agent-cli-provider/contract-actions.d.ts.map +1 -0
  60. package/lib/agent-cli-provider/contract-actions.js +140 -0
  61. package/lib/agent-cli-provider/contract-actions.js.map +1 -0
  62. package/lib/agent-cli-provider/contract-env.d.ts +11 -0
  63. package/lib/agent-cli-provider/contract-env.d.ts.map +1 -0
  64. package/lib/agent-cli-provider/contract-env.js +113 -0
  65. package/lib/agent-cli-provider/contract-env.js.map +1 -0
  66. package/lib/agent-cli-provider/contract-envelope.d.ts +49 -0
  67. package/lib/agent-cli-provider/contract-envelope.d.ts.map +1 -0
  68. package/lib/agent-cli-provider/contract-envelope.js +52 -0
  69. package/lib/agent-cli-provider/contract-envelope.js.map +1 -0
  70. package/lib/agent-cli-provider/contract-errors.d.ts +22 -0
  71. package/lib/agent-cli-provider/contract-errors.d.ts.map +1 -0
  72. package/lib/agent-cli-provider/contract-errors.js +71 -0
  73. package/lib/agent-cli-provider/contract-errors.js.map +1 -0
  74. package/lib/agent-cli-provider/contract-fallback.d.ts +7 -0
  75. package/lib/agent-cli-provider/contract-fallback.d.ts.map +1 -0
  76. package/lib/agent-cli-provider/contract-fallback.js +102 -0
  77. package/lib/agent-cli-provider/contract-fallback.js.map +1 -0
  78. package/lib/agent-cli-provider/contract-invoke.d.ts +5 -0
  79. package/lib/agent-cli-provider/contract-invoke.d.ts.map +1 -0
  80. package/lib/agent-cli-provider/contract-invoke.js +89 -0
  81. package/lib/agent-cli-provider/contract-invoke.js.map +1 -0
  82. package/lib/agent-cli-provider/contract-options.d.ts +3 -0
  83. package/lib/agent-cli-provider/contract-options.d.ts.map +1 -0
  84. package/lib/agent-cli-provider/contract-options.js +140 -0
  85. package/lib/agent-cli-provider/contract-options.js.map +1 -0
  86. package/lib/agent-cli-provider/contract-parse.d.ts +15 -0
  87. package/lib/agent-cli-provider/contract-parse.d.ts.map +1 -0
  88. package/lib/agent-cli-provider/contract-parse.js +81 -0
  89. package/lib/agent-cli-provider/contract-parse.js.map +1 -0
  90. package/lib/agent-cli-provider/contract-support.d.ts +18 -0
  91. package/lib/agent-cli-provider/contract-support.d.ts.map +1 -0
  92. package/lib/agent-cli-provider/contract-support.js +154 -0
  93. package/lib/agent-cli-provider/contract-support.js.map +1 -0
  94. package/lib/agent-cli-provider/contract.d.ts +13 -0
  95. package/lib/agent-cli-provider/contract.d.ts.map +1 -0
  96. package/lib/agent-cli-provider/contract.js +30 -0
  97. package/lib/agent-cli-provider/contract.js.map +1 -0
  98. package/lib/agent-cli-provider/env-safety.d.ts +11 -0
  99. package/lib/agent-cli-provider/env-safety.d.ts.map +1 -0
  100. package/lib/agent-cli-provider/env-safety.js +83 -0
  101. package/lib/agent-cli-provider/env-safety.js.map +1 -0
  102. package/lib/agent-cli-provider/errors.d.ts +5 -0
  103. package/lib/agent-cli-provider/errors.d.ts.map +1 -0
  104. package/lib/agent-cli-provider/errors.js +115 -0
  105. package/lib/agent-cli-provider/errors.js.map +1 -0
  106. package/lib/agent-cli-provider/executable.d.ts +3 -0
  107. package/lib/agent-cli-provider/executable.d.ts.map +1 -0
  108. package/lib/agent-cli-provider/executable.js +24 -0
  109. package/lib/agent-cli-provider/executable.js.map +1 -0
  110. package/lib/agent-cli-provider/index.d.ts +8 -0
  111. package/lib/agent-cli-provider/index.d.ts.map +1 -0
  112. package/lib/agent-cli-provider/index.js +31 -0
  113. package/lib/agent-cli-provider/index.js.map +1 -0
  114. package/lib/agent-cli-provider/invoke-evidence.d.ts +4 -0
  115. package/lib/agent-cli-provider/invoke-evidence.d.ts.map +1 -0
  116. package/lib/agent-cli-provider/invoke-evidence.js +17 -0
  117. package/lib/agent-cli-provider/invoke-evidence.js.map +1 -0
  118. package/lib/agent-cli-provider/json.d.ts +16 -0
  119. package/lib/agent-cli-provider/json.d.ts.map +1 -0
  120. package/lib/agent-cli-provider/json.js +110 -0
  121. package/lib/agent-cli-provider/json.js.map +1 -0
  122. package/lib/agent-cli-provider/log-prefix.d.ts +2 -0
  123. package/lib/agent-cli-provider/log-prefix.d.ts.map +1 -0
  124. package/lib/agent-cli-provider/log-prefix.js +22 -0
  125. package/lib/agent-cli-provider/log-prefix.js.map +1 -0
  126. package/lib/agent-cli-provider/process-runner.d.ts +17 -0
  127. package/lib/agent-cli-provider/process-runner.d.ts.map +1 -0
  128. package/lib/agent-cli-provider/process-runner.js +89 -0
  129. package/lib/agent-cli-provider/process-runner.js.map +1 -0
  130. package/lib/agent-cli-provider/redaction.d.ts +9 -0
  131. package/lib/agent-cli-provider/redaction.d.ts.map +1 -0
  132. package/lib/agent-cli-provider/redaction.js +227 -0
  133. package/lib/agent-cli-provider/redaction.js.map +1 -0
  134. package/lib/agent-cli-provider/schema.d.ts +5 -0
  135. package/lib/agent-cli-provider/schema.d.ts.map +1 -0
  136. package/lib/agent-cli-provider/schema.js +136 -0
  137. package/lib/agent-cli-provider/schema.js.map +1 -0
  138. package/lib/agent-cli-provider/single-agent-runtime.d.ts +15 -0
  139. package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -0
  140. package/lib/agent-cli-provider/single-agent-runtime.js +228 -0
  141. package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -0
  142. package/lib/agent-cli-provider/types.d.ts +194 -0
  143. package/lib/agent-cli-provider/types.d.ts.map +1 -0
  144. package/lib/agent-cli-provider/types.js +12 -0
  145. package/lib/agent-cli-provider/types.js.map +1 -0
  146. package/lib/completion.js +174 -0
  147. package/lib/detached-startup.js +220 -0
  148. package/lib/docker-config.js +220 -0
  149. package/lib/git-remote-utils.js +165 -0
  150. package/lib/id-detector.js +55 -0
  151. package/lib/provider-defaults.js +62 -0
  152. package/lib/provider-detection.js +59 -0
  153. package/lib/provider-names.js +57 -0
  154. package/lib/repo-settings.js +69 -0
  155. package/lib/settings/claude-auth.js +78 -0
  156. package/lib/settings.js +542 -0
  157. package/lib/start-cluster.js +321 -0
  158. package/lib/stream-json-parser.js +67 -0
  159. package/package.json +162 -0
  160. package/scripts/fix-node-pty-permissions.js +75 -0
  161. package/scripts/record-demo.sh +279 -0
  162. package/scripts/setup-merge-queue.sh +170 -0
  163. package/scripts/test-install.sh +40 -0
  164. package/scripts/validate-templates.js +107 -0
  165. package/src/agent/agent-config.js +266 -0
  166. package/src/agent/agent-context-builder.js +189 -0
  167. package/src/agent/agent-context-sections.js +338 -0
  168. package/src/agent/agent-context-sources.js +147 -0
  169. package/src/agent/agent-hook-executor.js +721 -0
  170. package/src/agent/agent-input-injector.js +141 -0
  171. package/src/agent/agent-lifecycle.js +982 -0
  172. package/src/agent/agent-quality-gate-schema.js +93 -0
  173. package/src/agent/agent-quality-gates-context.js +51 -0
  174. package/src/agent/agent-stuck-detector.js +256 -0
  175. package/src/agent/agent-task-executor.js +2028 -0
  176. package/src/agent/agent-trigger-evaluator.js +67 -0
  177. package/src/agent/context-metrics.js +160 -0
  178. package/src/agent/context-pack-builder.js +367 -0
  179. package/src/agent/context-replay-policy.js +51 -0
  180. package/src/agent/guidance-queue.js +77 -0
  181. package/src/agent/output-extraction.js +367 -0
  182. package/src/agent/output-reformatter.js +175 -0
  183. package/src/agent/pr-verification.js +653 -0
  184. package/src/agent/rate-limit-backoff.js +82 -0
  185. package/src/agent/schema-utils.js +146 -0
  186. package/src/agent/validation-platform.js +35 -0
  187. package/src/agent-cli-provider/adapters/claude-parser.ts +133 -0
  188. package/src/agent-cli-provider/adapters/claude-recovery.ts +203 -0
  189. package/src/agent-cli-provider/adapters/claude.ts +247 -0
  190. package/src/agent-cli-provider/adapters/codex-parser.ts +211 -0
  191. package/src/agent-cli-provider/adapters/codex.ts +217 -0
  192. package/src/agent-cli-provider/adapters/common.ts +124 -0
  193. package/src/agent-cli-provider/adapters/gemini.ts +243 -0
  194. package/src/agent-cli-provider/adapters/index.ts +126 -0
  195. package/src/agent-cli-provider/adapters/opencode.ts +286 -0
  196. package/src/agent-cli-provider/contract-actions.ts +150 -0
  197. package/src/agent-cli-provider/contract-env.ts +111 -0
  198. package/src/agent-cli-provider/contract-envelope.ts +110 -0
  199. package/src/agent-cli-provider/contract-errors.ts +66 -0
  200. package/src/agent-cli-provider/contract-fallback.ts +121 -0
  201. package/src/agent-cli-provider/contract-invoke.ts +104 -0
  202. package/src/agent-cli-provider/contract-options.ts +173 -0
  203. package/src/agent-cli-provider/contract-parse.ts +94 -0
  204. package/src/agent-cli-provider/contract-support.ts +167 -0
  205. package/src/agent-cli-provider/contract.ts +56 -0
  206. package/src/agent-cli-provider/env-safety.ts +82 -0
  207. package/src/agent-cli-provider/errors.ts +122 -0
  208. package/src/agent-cli-provider/executable.ts +24 -0
  209. package/src/agent-cli-provider/index.ts +83 -0
  210. package/src/agent-cli-provider/invoke-evidence.ts +18 -0
  211. package/src/agent-cli-provider/json.ts +114 -0
  212. package/src/agent-cli-provider/log-prefix.ts +20 -0
  213. package/src/agent-cli-provider/process-runner.ts +145 -0
  214. package/src/agent-cli-provider/redaction.ts +282 -0
  215. package/src/agent-cli-provider/schema.ts +115 -0
  216. package/src/agent-cli-provider/single-agent-runtime.ts +311 -0
  217. package/src/agent-cli-provider/types.ts +237 -0
  218. package/src/agent-wrapper.js +615 -0
  219. package/src/agents/git-pusher-template.js +705 -0
  220. package/src/attach/attach-client.js +438 -0
  221. package/src/attach/attach-server.js +543 -0
  222. package/src/attach/index.js +37 -0
  223. package/src/attach/protocol.js +220 -0
  224. package/src/attach/ring-buffer.js +121 -0
  225. package/src/attach/send-input.js +88 -0
  226. package/src/attach/socket-discovery.js +267 -0
  227. package/src/claude-task-runner.js +661 -0
  228. package/src/config-router.js +89 -0
  229. package/src/config-validator.js +2202 -0
  230. package/src/copy-worker.js +43 -0
  231. package/src/guidance-topics.js +10 -0
  232. package/src/input-helpers.js +65 -0
  233. package/src/isolation-manager.js +1734 -0
  234. package/src/issue-providers/README.md +305 -0
  235. package/src/issue-providers/azure-devops-provider.js +307 -0
  236. package/src/issue-providers/base-provider.js +232 -0
  237. package/src/issue-providers/github-provider.js +210 -0
  238. package/src/issue-providers/gitlab-provider.js +262 -0
  239. package/src/issue-providers/index.js +196 -0
  240. package/src/issue-providers/jira-provider.js +260 -0
  241. package/src/ledger.js +692 -0
  242. package/src/lib/gc.js +232 -0
  243. package/src/lib/safe-exec.js +88 -0
  244. package/src/logic-engine.js +201 -0
  245. package/src/message-buffer.js +81 -0
  246. package/src/message-bus-bridge.js +144 -0
  247. package/src/message-bus.js +256 -0
  248. package/src/name-generator.js +232 -0
  249. package/src/orchestrator.js +3924 -0
  250. package/src/preflight.js +712 -0
  251. package/src/process-metrics.js +608 -0
  252. package/src/providers/anthropic/index.js +3 -0
  253. package/src/providers/base-provider.js +355 -0
  254. package/src/providers/capabilities.js +60 -0
  255. package/src/providers/google/index.js +3 -0
  256. package/src/providers/index.js +293 -0
  257. package/src/providers/openai/index.js +3 -0
  258. package/src/providers/opencode/index.js +3 -0
  259. package/src/quality-gates.js +143 -0
  260. package/src/schemas/sub-cluster.js +208 -0
  261. package/src/state-snapshot.js +398 -0
  262. package/src/state-snapshotter.js +142 -0
  263. package/src/status-footer.js +1026 -0
  264. package/src/sub-cluster-wrapper.js +693 -0
  265. package/src/task-runner.js +30 -0
  266. package/src/template-resolver.js +425 -0
  267. package/src/template-validation/index.js +338 -0
  268. package/src/template-validation/simulate-consensus-gates.js +324 -0
  269. package/src/template-validation/simulate-random-topology.js +541 -0
  270. package/src/template-validation/simulate-two-stage-validation.js +270 -0
  271. package/src/worktree-claude-config.js +135 -0
  272. package/src/worktree-tooling-env.js +150 -0
  273. package/task-lib/attachable-watcher.js +381 -0
  274. package/task-lib/commands/clean.js +50 -0
  275. package/task-lib/commands/episodes.js +105 -0
  276. package/task-lib/commands/get-log-path.js +23 -0
  277. package/task-lib/commands/kill.js +32 -0
  278. package/task-lib/commands/list.js +105 -0
  279. package/task-lib/commands/logs.js +439 -0
  280. package/task-lib/commands/resume.js +42 -0
  281. package/task-lib/commands/run.js +57 -0
  282. package/task-lib/commands/schedule.js +105 -0
  283. package/task-lib/commands/scheduler-cmd.js +96 -0
  284. package/task-lib/commands/schedules.js +148 -0
  285. package/task-lib/commands/status.js +44 -0
  286. package/task-lib/commands/unschedule.js +16 -0
  287. package/task-lib/completion.js +9 -0
  288. package/task-lib/config.js +11 -0
  289. package/task-lib/name-generator.js +230 -0
  290. package/task-lib/package.json +3 -0
  291. package/task-lib/provider-helper-runtime.js +29 -0
  292. package/task-lib/runner.js +190 -0
  293. package/task-lib/scheduler.js +252 -0
  294. package/task-lib/store.js +529 -0
  295. package/task-lib/watcher.js +305 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * MessageBusBridge - Bridges parent and child message buses
3
+ *
4
+ * Forwards specified topics between parent and child clusters while maintaining
5
+ * isolation and preventing message loops.
6
+ *
7
+ * Features:
8
+ * - Forward specified parent topics to child (contextStrategy.parentTopics)
9
+ * - Forward child completion events to parent
10
+ * - Namespace child topics to avoid collisions
11
+ * - Prevent message loops via forwarding flags
12
+ */
13
+
14
+ class MessageBusBridge {
15
+ constructor(parentBus, childBus, config) {
16
+ this.parentBus = parentBus;
17
+ this.childBus = childBus;
18
+ this.config = config;
19
+ this.parentTopicNames = new Set(
20
+ (config.parentTopics || [])
21
+ .map((entry) => (typeof entry === 'string' ? entry : entry?.topic))
22
+ .filter((topic) => typeof topic === 'string' && topic.length > 0)
23
+ );
24
+
25
+ this.parentUnsubscribe = null;
26
+ this.childUnsubscribe = null;
27
+ this.active = false;
28
+
29
+ this._setupBridge();
30
+ }
31
+
32
+ /**
33
+ * Set up bidirectional message forwarding
34
+ * @private
35
+ */
36
+ _setupBridge() {
37
+ // Forward specified parent topics to child
38
+ if (this.parentTopicNames.size > 0) {
39
+ this.parentUnsubscribe = this.parentBus.subscribe((message) => {
40
+ this._forwardParentToChild(message);
41
+ });
42
+ }
43
+
44
+ // Forward child completion/failure events to parent
45
+ this.childUnsubscribe = this.childBus.subscribe((message) => {
46
+ this._forwardChildToParent(message);
47
+ });
48
+
49
+ this.active = true;
50
+ }
51
+
52
+ /**
53
+ * Forward parent message to child cluster
54
+ * @private
55
+ */
56
+ _forwardParentToChild(message) {
57
+ // Only forward messages from parent cluster
58
+ if (message.cluster_id !== this.config.parentClusterId) {
59
+ return;
60
+ }
61
+
62
+ // Only forward topics specified in config
63
+ if (!this.parentTopicNames.has(message.topic)) {
64
+ return;
65
+ }
66
+
67
+ // Skip already-forwarded messages (prevent loops)
68
+ if (message.metadata?.forwarded) {
69
+ return;
70
+ }
71
+
72
+ // Forward to child with metadata flag
73
+ this.childBus.publish({
74
+ ...message,
75
+ cluster_id: this.config.childClusterId,
76
+ metadata: {
77
+ ...message.metadata,
78
+ forwarded: true,
79
+ forwardedFrom: this.config.parentClusterId,
80
+ },
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Forward child message to parent cluster
86
+ * @private
87
+ */
88
+ _forwardChildToParent(message) {
89
+ // Only forward messages from child cluster
90
+ if (message.cluster_id !== this.config.childClusterId) {
91
+ return;
92
+ }
93
+
94
+ // Only forward completion/failure events
95
+ const forwardTopics = ['CLUSTER_COMPLETE', 'CLUSTER_FAILED', 'AGENT_ERROR'];
96
+ if (!forwardTopics.includes(message.topic)) {
97
+ return;
98
+ }
99
+
100
+ // Skip already-forwarded messages (prevent loops)
101
+ if (message.metadata?.forwarded) {
102
+ return;
103
+ }
104
+
105
+ // Forward to parent with namespaced topic and metadata flag
106
+ this.parentBus.publish({
107
+ ...message,
108
+ cluster_id: this.config.parentClusterId,
109
+ topic: `CHILD_${message.topic}`,
110
+ metadata: {
111
+ ...message.metadata,
112
+ forwarded: true,
113
+ forwardedFrom: this.config.childClusterId,
114
+ childClusterId: this.config.childClusterId,
115
+ },
116
+ });
117
+ }
118
+
119
+ /**
120
+ * Close the bridge and stop forwarding
121
+ */
122
+ close() {
123
+ if (this.parentUnsubscribe) {
124
+ this.parentUnsubscribe();
125
+ this.parentUnsubscribe = null;
126
+ }
127
+
128
+ if (this.childUnsubscribe) {
129
+ this.childUnsubscribe();
130
+ this.childUnsubscribe = null;
131
+ }
132
+
133
+ this.active = false;
134
+ }
135
+
136
+ /**
137
+ * Check if bridge is active
138
+ */
139
+ isActive() {
140
+ return this.active;
141
+ }
142
+ }
143
+
144
+ module.exports = MessageBusBridge;
@@ -0,0 +1,256 @@
1
+ /**
2
+ * MessageBus - Pub/sub layer over Ledger with WebSocket support
3
+ *
4
+ * Provides:
5
+ * - High-level publish/subscribe API
6
+ * - WebSocket broadcasting for UI clients
7
+ * - Topic-based routing
8
+ * - Real-time event distribution
9
+ */
10
+
11
+ const EventEmitter = require('events');
12
+ const Ledger = require('./ledger');
13
+
14
+ // Expected listeners per cluster:
15
+ // - 5 orchestrator subscriptions (CLUSTER_COMPLETE, CLUSTER_FAILED, AGENT_ERROR, AGENT_LIFECYCLE, CLUSTER_OPERATIONS)
16
+ // - 1 ledger internal
17
+ // - 1 per agent (can be 10+ with dynamic spawning)
18
+ // - topic-specific listeners
19
+ const MAX_LISTENERS = 50;
20
+
21
+ class MessageBus extends EventEmitter {
22
+ constructor(ledger) {
23
+ super();
24
+ this.setMaxListeners(MAX_LISTENERS);
25
+ this.ledger = ledger || new Ledger();
26
+ this.wsClients = new Set();
27
+
28
+ // Forward ledger events
29
+ this.ledger.on('message', (message) => {
30
+ this.emit('message', message);
31
+ this._broadcastToWebSocket(message);
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Publish a message to the ledger
37
+ * @param {Object} message - Message to publish
38
+ * @returns {Object} Published message with ID
39
+ */
40
+ publish(message) {
41
+ if (!message.cluster_id) {
42
+ throw new Error('cluster_id is required');
43
+ }
44
+
45
+ if (!message.topic) {
46
+ throw new Error('topic is required');
47
+ }
48
+
49
+ if (!message.sender) {
50
+ throw new Error('sender is required');
51
+ }
52
+
53
+ const published = this.ledger.append(message);
54
+
55
+ // If ledger is closed, append returns null - skip emission
56
+ if (!published) {
57
+ return null;
58
+ }
59
+
60
+ // Emit to topic-specific listeners
61
+ this.emit(`topic:${message.topic}`, published);
62
+
63
+ return published;
64
+ }
65
+
66
+ /**
67
+ * Subscribe to all messages
68
+ * @param {Function} callback - Called with each message
69
+ * @returns {Function} Unsubscribe function
70
+ */
71
+ subscribe(callback) {
72
+ this.on('message', callback);
73
+ return () => this.off('message', callback);
74
+ }
75
+
76
+ /**
77
+ * Subscribe to specific topic
78
+ * @param {String} topic - Topic to subscribe to
79
+ * @param {Function} callback - Called with matching messages
80
+ * @returns {Function} Unsubscribe function
81
+ */
82
+ subscribeTopic(topic, callback) {
83
+ const event = `topic:${topic}`;
84
+ this.on(event, callback);
85
+ return () => this.off(event, callback);
86
+ }
87
+
88
+ /**
89
+ * Subscribe to multiple topics
90
+ * @param {Array<String>} topics - Topics to subscribe to
91
+ * @param {Function} callback - Called with matching messages
92
+ * @returns {Function} Unsubscribe function
93
+ */
94
+ subscribeTopics(topics, callback) {
95
+ const unsubscribers = topics.map((topic) => this.subscribeTopic(topic, callback));
96
+ return () => unsubscribers.forEach((unsub) => unsub());
97
+ }
98
+
99
+ /**
100
+ * Query messages (passthrough to ledger)
101
+ */
102
+ query(criteria) {
103
+ return this.ledger.query(criteria);
104
+ }
105
+
106
+ /**
107
+ * Query guidance mailbox (passthrough to ledger)
108
+ */
109
+ queryGuidanceMailbox(criteria) {
110
+ return this.ledger.queryGuidanceMailbox(criteria);
111
+ }
112
+
113
+ /**
114
+ * Find last message (passthrough to ledger)
115
+ */
116
+ findLast(criteria) {
117
+ return this.ledger.findLast(criteria);
118
+ }
119
+
120
+ /**
121
+ * Count messages (passthrough to ledger)
122
+ */
123
+ count(criteria) {
124
+ return this.ledger.count(criteria);
125
+ }
126
+
127
+ /**
128
+ * Get messages since timestamp (passthrough to ledger)
129
+ */
130
+ since(params) {
131
+ return this.ledger.since(params);
132
+ }
133
+
134
+ /**
135
+ * Get all messages (passthrough to ledger)
136
+ */
137
+ getAll(cluster_id) {
138
+ return this.ledger.getAll(cluster_id);
139
+ }
140
+
141
+ /**
142
+ * Publish multiple messages atomically
143
+ * All messages are committed in a single transaction with contiguous timestamps.
144
+ * Use this for task completion to prevent message interleaving between agents.
145
+ *
146
+ * @param {Array<Object>} messages - Array of messages to publish
147
+ * @returns {Array<Object>} Published messages with IDs
148
+ */
149
+ batchPublish(messages) {
150
+ // Validate all messages
151
+ for (const message of messages) {
152
+ if (!message.cluster_id) {
153
+ throw new Error('cluster_id is required for all messages');
154
+ }
155
+ if (!message.topic) {
156
+ throw new Error('topic is required for all messages');
157
+ }
158
+ if (!message.sender) {
159
+ throw new Error('sender is required for all messages');
160
+ }
161
+ }
162
+
163
+ // Delegate to ledger's atomic batchAppend
164
+ const published = this.ledger.batchAppend(messages);
165
+
166
+ // Emit to topic-specific listeners for each message
167
+ for (const msg of published) {
168
+ this.emit(`topic:${msg.topic}`, msg);
169
+ }
170
+
171
+ return published;
172
+ }
173
+
174
+ /**
175
+ * Get aggregated token usage by role (passthrough to ledger)
176
+ * @param {String} cluster_id - Cluster ID
177
+ * @returns {Object} Token usage aggregated by role with _total key
178
+ */
179
+ getTokensByRole(cluster_id) {
180
+ return this.ledger.getTokensByRole(cluster_id);
181
+ }
182
+
183
+ /**
184
+ * Register a WebSocket client for broadcasts
185
+ * @param {WebSocket} ws - WebSocket connection
186
+ */
187
+ addWebSocketClient(ws) {
188
+ this.wsClients.add(ws);
189
+
190
+ ws.on('close', () => {
191
+ this.wsClients.delete(ws);
192
+ });
193
+
194
+ ws.on('error', () => {
195
+ this.wsClients.delete(ws);
196
+ });
197
+ }
198
+
199
+ /**
200
+ * Remove a WebSocket client
201
+ * @param {WebSocket} ws - WebSocket connection
202
+ */
203
+ removeWebSocketClient(ws) {
204
+ this.wsClients.delete(ws);
205
+ }
206
+
207
+ /**
208
+ * Broadcast message to all WebSocket clients
209
+ * @private
210
+ */
211
+ _broadcastToWebSocket(message) {
212
+ const payload = JSON.stringify({
213
+ type: 'message',
214
+ data: message,
215
+ });
216
+
217
+ for (const ws of this.wsClients) {
218
+ if (ws.readyState === 1) {
219
+ // OPEN
220
+ try {
221
+ ws.send(payload);
222
+ } catch (error) {
223
+ console.error('WebSocket send error:', error);
224
+ this.wsClients.delete(ws);
225
+ }
226
+ }
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Close the message bus
232
+ */
233
+ close() {
234
+ // Close all WebSocket connections
235
+ for (const ws of this.wsClients) {
236
+ try {
237
+ ws.close();
238
+ } catch {
239
+ // Ignore errors on close
240
+ }
241
+ }
242
+ this.wsClients.clear();
243
+
244
+ // Close ledger
245
+ this.ledger.close();
246
+ }
247
+
248
+ /**
249
+ * Clear all messages (for testing)
250
+ */
251
+ clear() {
252
+ this.ledger.clear();
253
+ }
254
+ }
255
+
256
+ module.exports = MessageBus;
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Human-readable name generator (like Weights & Biases)
3
+ * Generates names like "wandering-forest-42" or "bright-star-17"
4
+ *
5
+ * No prefix - short forms used everywhere for simplicity
6
+ */
7
+
8
+ const ADJECTIVES = [
9
+ // Colors
10
+ 'amber',
11
+ 'azure',
12
+ 'crimson',
13
+ 'emerald',
14
+ 'golden',
15
+ 'indigo',
16
+ 'jade',
17
+ 'ruby',
18
+ 'sapphire',
19
+ 'silver',
20
+ 'violet',
21
+ 'bronze',
22
+ 'coral',
23
+ 'ivory',
24
+ 'pearl',
25
+ 'platinum',
26
+ 'scarlet',
27
+ 'cobalt',
28
+ 'copper',
29
+ 'obsidian',
30
+ 'onyx',
31
+ 'opal',
32
+ 'topaz',
33
+ 'turquoise',
34
+ // Nature
35
+ 'wandering',
36
+ 'bright',
37
+ 'silent',
38
+ 'ancient',
39
+ 'swift',
40
+ 'noble',
41
+ 'bold',
42
+ 'wild',
43
+ 'gentle',
44
+ 'hidden',
45
+ 'fierce',
46
+ 'calm',
47
+ 'frozen',
48
+ 'misty',
49
+ 'stormy',
50
+ 'sunny',
51
+ // Cosmic
52
+ 'cosmic',
53
+ 'crystal',
54
+ 'electric',
55
+ 'lunar',
56
+ 'solar',
57
+ 'stellar',
58
+ 'astral',
59
+ 'orbital',
60
+ 'mystic',
61
+ 'quantum',
62
+ 'radiant',
63
+ 'twilight',
64
+ 'vivid',
65
+ 'zen',
66
+ 'infinite',
67
+ 'eternal',
68
+ // Tech/Abstract
69
+ 'clever',
70
+ 'rapid',
71
+ 'steady',
72
+ 'agile',
73
+ 'nimble',
74
+ 'keen',
75
+ 'sharp',
76
+ 'quick',
77
+ 'prime',
78
+ 'binary',
79
+ 'neural',
80
+ 'atomic',
81
+ 'sonic',
82
+ 'hyper',
83
+ 'mega',
84
+ 'ultra',
85
+ // Descriptive
86
+ 'blazing',
87
+ 'gleaming',
88
+ 'glowing',
89
+ 'shining',
90
+ 'burning',
91
+ 'flaming',
92
+ 'sparkling',
93
+ 'dazzling',
94
+ 'roaring',
95
+ 'rushing',
96
+ 'soaring',
97
+ 'flying',
98
+ 'rising',
99
+ 'falling',
100
+ 'spinning',
101
+ 'dancing',
102
+ ];
103
+
104
+ const NOUNS = [
105
+ // Nature
106
+ 'forest',
107
+ 'river',
108
+ 'mountain',
109
+ 'ocean',
110
+ 'thunder',
111
+ 'canyon',
112
+ 'summit',
113
+ 'valley',
114
+ 'cascade',
115
+ 'glacier',
116
+ 'volcano',
117
+ 'desert',
118
+ 'meadow',
119
+ 'tundra',
120
+ 'jungle',
121
+ 'reef',
122
+ // Space
123
+ 'star',
124
+ 'comet',
125
+ 'nebula',
126
+ 'galaxy',
127
+ 'pulsar',
128
+ 'quasar',
129
+ 'aurora',
130
+ 'eclipse',
131
+ 'meteor',
132
+ 'nova',
133
+ 'cosmos',
134
+ 'orbit',
135
+ 'void',
136
+ 'horizon',
137
+ 'zenith',
138
+ 'equinox',
139
+ // Mythical
140
+ 'phoenix',
141
+ 'dragon',
142
+ 'griffin',
143
+ 'sphinx',
144
+ 'hydra',
145
+ 'kraken',
146
+ 'titan',
147
+ 'atlas',
148
+ 'oracle',
149
+ 'rune',
150
+ 'sigil',
151
+ 'glyph',
152
+ 'totem',
153
+ 'aegis',
154
+ 'aether',
155
+ 'flux',
156
+ // Animals
157
+ 'falcon',
158
+ 'eagle',
159
+ 'wolf',
160
+ 'bear',
161
+ 'tiger',
162
+ 'hawk',
163
+ 'lion',
164
+ 'panther',
165
+ 'raven',
166
+ 'serpent',
167
+ 'shark',
168
+ 'owl',
169
+ 'fox',
170
+ 'lynx',
171
+ 'viper',
172
+ 'condor',
173
+ // Architecture
174
+ 'citadel',
175
+ 'temple',
176
+ 'spire',
177
+ 'tower',
178
+ 'fortress',
179
+ 'bastion',
180
+ 'vault',
181
+ 'sanctum',
182
+ 'beacon',
183
+ 'arch',
184
+ 'bridge',
185
+ 'gate',
186
+ 'hall',
187
+ 'keep',
188
+ 'dome',
189
+ 'obelisk',
190
+ // Abstract
191
+ 'cipher',
192
+ 'echo',
193
+ 'nexus',
194
+ 'prism',
195
+ 'relic',
196
+ 'vertex',
197
+ 'vortex',
198
+ 'pulse',
199
+ 'surge',
200
+ 'spark',
201
+ 'flame',
202
+ 'storm',
203
+ 'wave',
204
+ 'drift',
205
+ 'shift',
206
+ 'core',
207
+ ];
208
+
209
+ // 96 adjectives × 96 nouns × 100 numbers = 921,600 combinations
210
+
211
+ /**
212
+ * Generate a human-readable name
213
+ * @param {string} _prefix - DEPRECATED: Ignored for backwards compat, short form always used
214
+ * @returns {string} Human-readable name (e.g., 'wandering-forest-42')
215
+ */
216
+ function generateName(_prefix = '') {
217
+ const adjective = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
218
+ const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
219
+ const number = Math.floor(Math.random() * 100);
220
+
221
+ return `${adjective}-${noun}-${number}`;
222
+ }
223
+
224
+ /**
225
+ * Generate a short unique suffix (for collision prevention)
226
+ * @returns {string} Short random suffix (e.g., 'a3f9')
227
+ */
228
+ function generateSuffix() {
229
+ return Math.random().toString(36).slice(2, 6);
230
+ }
231
+
232
+ module.exports = { generateName, generateSuffix };