@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,541 @@
1
+ const fs = require('node:fs');
2
+ const path = require('node:path');
3
+
4
+ const Ledger = require('../ledger');
5
+ const MessageBus = require('../message-bus');
6
+ const LogicEngine = require('../logic-engine');
7
+ const TemplateResolver = require('../template-resolver');
8
+ const { executeHook } = require('../agent/agent-hook-executor');
9
+ const { parseResultOutput } = require('../agent/agent-task-executor');
10
+ const { findMatchingTrigger, evaluateTrigger } = require('../agent/agent-trigger-evaluator');
11
+
12
+ const DEFAULT_SAMPLES = 6;
13
+ const DEFAULT_MAX_STEPS = 120;
14
+ const DEFAULT_MAX_SCENARIO_MS = 120;
15
+ const MAX_ERRORS = 3;
16
+
17
+ function createSeededRng(seed) {
18
+ let state = seed >>> 0 || 0x9e3779b9;
19
+ return () => {
20
+ state ^= state << 13;
21
+ state >>>= 0;
22
+ state ^= state >>> 17;
23
+ state >>>= 0;
24
+ state ^= state << 5;
25
+ state >>>= 0;
26
+ return state / 4294967296;
27
+ };
28
+ }
29
+
30
+ function randomInt(rng, min, max) {
31
+ if (!Number.isFinite(min) || !Number.isFinite(max)) {
32
+ return 0;
33
+ }
34
+ if (max <= min) {
35
+ return Math.round(min);
36
+ }
37
+ return Math.floor(rng() * (max - min + 1)) + min;
38
+ }
39
+
40
+ function randomPick(rng, values, fallback = null) {
41
+ if (!Array.isArray(values) || values.length === 0) {
42
+ return fallback;
43
+ }
44
+ return values[randomInt(rng, 0, values.length - 1)];
45
+ }
46
+
47
+ function normalizeType(schema) {
48
+ if (!schema || !schema.type) return null;
49
+ if (Array.isArray(schema.type)) {
50
+ return schema.type[0] || null;
51
+ }
52
+ return schema.type;
53
+ }
54
+
55
+ function sampleString(schema, rng) {
56
+ const candidates = [];
57
+ if (typeof schema.default === 'string') candidates.push(schema.default);
58
+ if (typeof schema.description === 'string') candidates.push(schema.description);
59
+ candidates.push('sample', 'ok', 'done', 'pass', 'fail');
60
+ let value = randomPick(rng, candidates, 'sample');
61
+
62
+ const minLength = Number.isInteger(schema.minLength) ? schema.minLength : 0;
63
+ const maxLength = Number.isInteger(schema.maxLength) ? schema.maxLength : value.length;
64
+
65
+ while (value.length < minLength) {
66
+ value += 'x';
67
+ }
68
+ if (maxLength >= 0 && value.length > maxLength) {
69
+ value = value.slice(0, maxLength);
70
+ }
71
+ if (!value && minLength > 0) {
72
+ value = 'x'.repeat(minLength);
73
+ }
74
+ return value;
75
+ }
76
+
77
+ function sampleNumber(schema, rng, asInteger) {
78
+ const minimum = Number.isFinite(schema.minimum) ? schema.minimum : asInteger ? 0 : 0;
79
+ const maximum = Number.isFinite(schema.maximum) ? schema.maximum : asInteger ? 10 : 10;
80
+ if (maximum < minimum) {
81
+ return asInteger ? Math.round(minimum) : minimum;
82
+ }
83
+
84
+ if (asInteger) {
85
+ return randomInt(rng, Math.ceil(minimum), Math.floor(maximum));
86
+ }
87
+ const fraction = rng();
88
+ return minimum + (maximum - minimum) * fraction;
89
+ }
90
+
91
+ function sampleFromSchema(schema, rng, depth = 0) {
92
+ if (!schema || typeof schema !== 'object') {
93
+ return null;
94
+ }
95
+
96
+ if (depth > 4) {
97
+ return null;
98
+ }
99
+
100
+ if (schema.const !== undefined) {
101
+ return schema.const;
102
+ }
103
+
104
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) {
105
+ return randomPick(rng, schema.enum);
106
+ }
107
+
108
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
109
+ return sampleFromSchema(randomPick(rng, schema.oneOf), rng, depth + 1);
110
+ }
111
+ if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
112
+ return sampleFromSchema(randomPick(rng, schema.anyOf), rng, depth + 1);
113
+ }
114
+ if (Array.isArray(schema.allOf) && schema.allOf.length > 0) {
115
+ return sampleFromSchema(schema.allOf[0], rng, depth + 1);
116
+ }
117
+
118
+ const type = normalizeType(schema);
119
+
120
+ if (type === 'boolean') {
121
+ return rng() >= 0.5;
122
+ }
123
+
124
+ if (type === 'integer') {
125
+ return sampleNumber(schema, rng, true);
126
+ }
127
+
128
+ if (type === 'number') {
129
+ return sampleNumber(schema, rng, false);
130
+ }
131
+
132
+ if (type === 'array') {
133
+ const minItems = Number.isInteger(schema.minItems) ? schema.minItems : 0;
134
+ const maxItemsRaw = Number.isInteger(schema.maxItems) ? schema.maxItems : minItems + 2;
135
+ const maxItems = Math.max(minItems, Math.min(maxItemsRaw, 3));
136
+ const length = randomInt(rng, minItems, maxItems);
137
+
138
+ const itemsSchema = Array.isArray(schema.items)
139
+ ? randomPick(rng, schema.items, {})
140
+ : schema.items || {};
141
+ const values = [];
142
+ for (let i = 0; i < length; i += 1) {
143
+ values.push(sampleFromSchema(itemsSchema, rng, depth + 1));
144
+ }
145
+ return values;
146
+ }
147
+
148
+ if (type === 'object' || schema.properties) {
149
+ const properties = schema.properties || {};
150
+ const value = {};
151
+
152
+ for (const [key, propSchema] of Object.entries(properties)) {
153
+ value[key] = sampleFromSchema(propSchema, rng, depth + 1);
154
+ }
155
+
156
+ if (Object.keys(value).length === 0 && Object.keys(properties).length > 0) {
157
+ const key = Object.keys(properties)[0];
158
+ value[key] = sampleFromSchema(properties[key], rng, depth + 1);
159
+ }
160
+
161
+ return value;
162
+ }
163
+
164
+ return sampleString(schema, rng);
165
+ }
166
+
167
+ function sampleResultData(agentConfig, rng) {
168
+ const schema = agentConfig?.jsonSchema || agentConfig?.structuredOutput || null;
169
+ if (schema) {
170
+ return sampleFromSchema(schema, rng);
171
+ }
172
+ return {
173
+ summary: 'sample',
174
+ result: 'sample',
175
+ };
176
+ }
177
+
178
+ function createSimAgent({ agentConfig, cluster, messageBus, iteration }) {
179
+ const simAgent = {
180
+ id: agentConfig.id,
181
+ role: agentConfig.role,
182
+ iteration,
183
+ cluster,
184
+ messageBus,
185
+ config: agentConfig,
186
+ currentTaskId: `sim-${agentConfig.id}-${iteration}`,
187
+ workingDirectory: process.cwd(),
188
+ _log: () => {},
189
+ _resolveProvider: () => 'claude',
190
+ _parseResultOutput: (output) => parseResultOutput(simAgent, output),
191
+ _publish: (message) => {
192
+ const receiver = message.receiver || 'broadcast';
193
+ return messageBus.publish({
194
+ ...message,
195
+ receiver,
196
+ cluster_id: cluster.id,
197
+ sender: simAgent.id,
198
+ });
199
+ },
200
+ };
201
+ return simAgent;
202
+ }
203
+
204
+ function addAgentsToState(state, agents) {
205
+ for (const agent of agents || []) {
206
+ if (!agent?.id) {
207
+ continue;
208
+ }
209
+
210
+ if (state.agentConfigs.some((existing) => existing.id === agent.id)) {
211
+ continue;
212
+ }
213
+
214
+ state.agentConfigs.push(agent);
215
+ state.cluster.agents.push({ id: agent.id, role: agent.role });
216
+ }
217
+ }
218
+
219
+ function parseOperations(raw) {
220
+ if (Array.isArray(raw)) {
221
+ return raw;
222
+ }
223
+ if (typeof raw === 'string') {
224
+ return JSON.parse(raw);
225
+ }
226
+ return null;
227
+ }
228
+
229
+ function resolveConfigOperation({ configOp, templatesDir }) {
230
+ if (typeof configOp === 'object' && configOp?.base) {
231
+ const resolver = new TemplateResolver(templatesDir);
232
+ return resolver.resolve(configOp.base, configOp.params || {});
233
+ }
234
+ if (typeof configOp === 'string') {
235
+ const configPath = path.join(templatesDir, `${configOp}.json`);
236
+ const configContent = fs.readFileSync(configPath, 'utf8');
237
+ return JSON.parse(configContent);
238
+ }
239
+ throw new Error(`Unsupported load_config payload: ${JSON.stringify(configOp)}`);
240
+ }
241
+
242
+ function applyClusterOperation({ state, messageBus, operation, sourceMessage, templatesDir }) {
243
+ if (!operation?.action) {
244
+ return;
245
+ }
246
+
247
+ if (operation.action === 'load_config') {
248
+ const loadedConfig = resolveConfigOperation({
249
+ configOp: operation.config,
250
+ templatesDir,
251
+ });
252
+ addAgentsToState(state, loadedConfig.agents || []);
253
+ return;
254
+ }
255
+
256
+ if (operation.action === 'add_agents') {
257
+ addAgentsToState(state, operation.agents || []);
258
+ return;
259
+ }
260
+
261
+ if (operation.action === 'remove_agents') {
262
+ const ids = new Set(operation.agentIds || []);
263
+ state.agentConfigs = state.agentConfigs.filter((agent) => !ids.has(agent.id));
264
+ state.cluster.agents = state.cluster.agents.filter((agent) => !ids.has(agent.id));
265
+ return;
266
+ }
267
+
268
+ if (operation.action === 'update_agent') {
269
+ const target = state.agentConfigs.find((agent) => agent.id === operation.agentId);
270
+ if (!target || !operation.updates || typeof operation.updates !== 'object') {
271
+ return;
272
+ }
273
+ Object.assign(target, operation.updates);
274
+ return;
275
+ }
276
+
277
+ if (operation.action === 'publish') {
278
+ messageBus.publish({
279
+ cluster_id: state.cluster.id,
280
+ topic: operation.topic,
281
+ sender: '__sim_orchestrator__',
282
+ receiver: operation.receiver || 'broadcast',
283
+ content: operation.content || {},
284
+ metadata: operation.metadata || {
285
+ fromTopic: sourceMessage.topic,
286
+ },
287
+ });
288
+ }
289
+ }
290
+
291
+ function handleClusterOperationsMessage({ state, messageBus, message, templatesDir }) {
292
+ const raw = message?.content?.data?.operations;
293
+ const operations = parseOperations(raw);
294
+ if (!Array.isArray(operations)) {
295
+ throw new Error(`CLUSTER_OPERATIONS missing operations array: ${JSON.stringify(raw)}`);
296
+ }
297
+
298
+ for (const operation of operations) {
299
+ applyClusterOperation({ state, messageBus, operation, sourceMessage: message, templatesDir });
300
+ }
301
+ }
302
+
303
+ function createIssueOpenedMessage(clusterId) {
304
+ return {
305
+ cluster_id: clusterId,
306
+ topic: 'ISSUE_OPENED',
307
+ sender: 'system',
308
+ receiver: 'broadcast',
309
+ content: {
310
+ text: 'template validation simulation',
311
+ data: {},
312
+ },
313
+ };
314
+ }
315
+
316
+ async function runScenario({ config, templateId, seed, maxSteps, maxScenarioMs, templatesDir }) {
317
+ const initialAgentConfigs = JSON.parse(JSON.stringify(config.agents || []));
318
+ const state = {
319
+ agentConfigs: initialAgentConfigs,
320
+ cluster: {
321
+ id: `sim-${templateId}-${seed}`,
322
+ agents: initialAgentConfigs.map((agent) => ({ id: agent.id, role: agent.role })),
323
+ },
324
+ };
325
+
326
+ const rng = createSeededRng(seed);
327
+ const ledger = new Ledger(':memory:');
328
+ const messageBus = new MessageBus(ledger);
329
+ const logicEngine = new LogicEngine(messageBus, state.cluster);
330
+ const iterations = new Map();
331
+ const queue = [];
332
+ const unsubscribe = messageBus.subscribe((message) => {
333
+ queue.push(message);
334
+ });
335
+
336
+ const startedAt = Date.now();
337
+
338
+ try {
339
+ messageBus.publish(createIssueOpenedMessage(state.cluster.id));
340
+ let stepCount = 0;
341
+
342
+ while (queue.length > 0) {
343
+ if (Date.now() - startedAt > maxScenarioMs) {
344
+ return {
345
+ ok: false,
346
+ reason: `scenario timed out after ${maxScenarioMs}ms`,
347
+ };
348
+ }
349
+ if (stepCount >= maxSteps) {
350
+ return {
351
+ ok: false,
352
+ reason: `scenario exceeded step budget (${maxSteps})`,
353
+ };
354
+ }
355
+ stepCount += 1;
356
+
357
+ const message = queue.shift();
358
+ if (!message) continue;
359
+
360
+ if (message.topic === 'CLUSTER_COMPLETE') {
361
+ return { ok: true };
362
+ }
363
+ if (message.topic === 'CLUSTER_FAILED') {
364
+ return {
365
+ ok: false,
366
+ reason: `scenario reached CLUSTER_FAILED`,
367
+ };
368
+ }
369
+ if (message.topic === 'CLUSTER_OPERATIONS') {
370
+ try {
371
+ handleClusterOperationsMessage({
372
+ state,
373
+ messageBus,
374
+ message,
375
+ templatesDir,
376
+ });
377
+ } catch (error) {
378
+ return {
379
+ ok: false,
380
+ reason: `invalid CLUSTER_OPERATIONS: ${error.message}`,
381
+ };
382
+ }
383
+ continue;
384
+ }
385
+
386
+ for (const agentConfig of state.agentConfigs) {
387
+ const trigger = findMatchingTrigger({
388
+ triggers: agentConfig.triggers || [],
389
+ message,
390
+ });
391
+ if (!trigger) {
392
+ continue;
393
+ }
394
+
395
+ let shouldExecute = true;
396
+ try {
397
+ shouldExecute = evaluateTrigger({
398
+ trigger,
399
+ message,
400
+ agent: {
401
+ id: agentConfig.id,
402
+ role: agentConfig.role,
403
+ iteration: iterations.get(agentConfig.id) || 0,
404
+ cluster_id: state.cluster.id,
405
+ },
406
+ logicEngine,
407
+ });
408
+ } catch (error) {
409
+ return {
410
+ ok: false,
411
+ reason: `trigger logic error (${agentConfig.id} on ${message.topic}): ${error.message}`,
412
+ };
413
+ }
414
+
415
+ if (!shouldExecute) {
416
+ continue;
417
+ }
418
+
419
+ const action = trigger.action || 'execute_task';
420
+ if (action === 'stop_cluster') {
421
+ messageBus.publish({
422
+ cluster_id: state.cluster.id,
423
+ topic: 'CLUSTER_COMPLETE',
424
+ sender: agentConfig.id,
425
+ receiver: 'system',
426
+ content: {
427
+ text: 'simulated completion',
428
+ data: { topic: message.topic },
429
+ },
430
+ });
431
+ continue;
432
+ }
433
+
434
+ if (action !== 'execute_task') {
435
+ continue;
436
+ }
437
+
438
+ const nextIteration = (iterations.get(agentConfig.id) || 0) + 1;
439
+ iterations.set(agentConfig.id, nextIteration);
440
+ const maxIterations = Number.isInteger(agentConfig.maxIterations)
441
+ ? agentConfig.maxIterations
442
+ : 100;
443
+ if (nextIteration > maxIterations) {
444
+ messageBus.publish({
445
+ cluster_id: state.cluster.id,
446
+ topic: 'CLUSTER_FAILED',
447
+ sender: agentConfig.id,
448
+ receiver: 'system',
449
+ content: {
450
+ text: `maxIterations exceeded: ${agentConfig.id}`,
451
+ data: { maxIterations, iteration: nextIteration },
452
+ },
453
+ });
454
+ continue;
455
+ }
456
+
457
+ const sampledResult = sampleResultData(agentConfig, rng);
458
+ const simAgent = createSimAgent({
459
+ agentConfig,
460
+ cluster: state.cluster,
461
+ messageBus,
462
+ iteration: nextIteration,
463
+ });
464
+
465
+ try {
466
+ await executeHook({
467
+ hook: agentConfig.hooks?.onComplete,
468
+ agent: simAgent,
469
+ message,
470
+ result: {
471
+ output: JSON.stringify(sampledResult || {}),
472
+ success: true,
473
+ taskId: `sim-task-${agentConfig.id}-${nextIteration}`,
474
+ },
475
+ messageBus,
476
+ cluster: state.cluster,
477
+ });
478
+ } catch (error) {
479
+ return {
480
+ ok: false,
481
+ reason: `hook execution failed (${agentConfig.id}): ${error.message}`,
482
+ };
483
+ }
484
+ }
485
+ }
486
+
487
+ return {
488
+ ok: false,
489
+ reason: 'message flow quiesced without CLUSTER_COMPLETE',
490
+ };
491
+ } finally {
492
+ unsubscribe();
493
+ ledger.close();
494
+ }
495
+ }
496
+
497
+ async function simulateRandomTopology({
498
+ config,
499
+ templateId,
500
+ templatesDir,
501
+ samples = DEFAULT_SAMPLES,
502
+ maxSteps = DEFAULT_MAX_STEPS,
503
+ maxScenarioMs = DEFAULT_MAX_SCENARIO_MS,
504
+ }) {
505
+ const errors = [];
506
+ if (!config?.agents || config.agents.length === 0) {
507
+ return errors;
508
+ }
509
+
510
+ const baseSeed = 1337;
511
+ const scenarioCount = Math.max(1, Number(samples) || DEFAULT_SAMPLES);
512
+
513
+ for (let i = 0; i < scenarioCount; i += 1) {
514
+ const seed = baseSeed + i * 9973;
515
+ const outcome = await runScenario({
516
+ config,
517
+ templateId,
518
+ seed,
519
+ maxSteps,
520
+ maxScenarioMs,
521
+ templatesDir,
522
+ });
523
+ if (outcome.ok) {
524
+ continue;
525
+ }
526
+ errors.push(
527
+ `[RandomSim] ${templateId} seed=${seed}: ${outcome.reason}. ` +
528
+ `Topology may be unsound under sampled schema-conformant outputs.`
529
+ );
530
+ if (errors.length >= MAX_ERRORS) {
531
+ break;
532
+ }
533
+ }
534
+
535
+ return errors;
536
+ }
537
+
538
+ module.exports = {
539
+ simulateRandomTopology,
540
+ sampleFromSchema,
541
+ };