@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,270 @@
1
+ const assert = require('node:assert');
2
+
3
+ const Ledger = require('../ledger');
4
+ const MessageBus = require('../message-bus');
5
+ const LogicEngine = require('../logic-engine');
6
+ const { executeHook } = require('../agent/agent-hook-executor');
7
+ const { parseResultOutput } = require('../agent/agent-task-executor');
8
+
9
+ function createSimAgent({ agentConfig, cluster, messageBus }) {
10
+ const simAgent = {
11
+ id: agentConfig.id,
12
+ role: agentConfig.role,
13
+ iteration: 1,
14
+ cluster,
15
+ messageBus,
16
+ config: agentConfig,
17
+ currentTaskId: 'sim-task',
18
+ workingDirectory: process.cwd(),
19
+ _log: () => {},
20
+ _resolveProvider: () => 'claude',
21
+ _parseResultOutput: (output) => parseResultOutput(simAgent, output),
22
+ _publish: (message) => {
23
+ const receiver = message.receiver || 'broadcast';
24
+ return messageBus.publish({
25
+ ...message,
26
+ receiver,
27
+ cluster_id: cluster.id,
28
+ sender: simAgent.id,
29
+ });
30
+ },
31
+ };
32
+ return simAgent;
33
+ }
34
+
35
+ async function simulateQuickValidation({ config }) {
36
+ const cluster = {
37
+ id: 'quick-sim',
38
+ agents: config.agents.map((a) => ({ id: a.id, role: a.role })),
39
+ };
40
+
41
+ const coordinator = config.agents.find((a) => a.id === 'consensus-coordinator');
42
+ assert.ok(coordinator, 'quick-validation: consensus-coordinator missing');
43
+
44
+ const trigger = coordinator.triggers.find((t) => t.topic === 'QUICK_VALIDATION_RESULT');
45
+ assert.ok(trigger?.logic?.script, 'quick-validation: coordinator trigger logic missing');
46
+ assert.ok(coordinator.hooks?.onComplete, 'quick-validation: coordinator onComplete missing');
47
+
48
+ const failures = [];
49
+
50
+ const runScenario = async (allApproved) => {
51
+ const ledger = new Ledger(':memory:');
52
+ const messageBus = new MessageBus(ledger);
53
+ const logicEngine = new LogicEngine(messageBus, cluster);
54
+
55
+ // Stage start
56
+ const now = Date.now();
57
+ messageBus.publish({
58
+ cluster_id: cluster.id,
59
+ topic: 'IMPLEMENTATION_READY',
60
+ sender: 'worker',
61
+ timestamp: now,
62
+ });
63
+
64
+ // Validator outputs (stage 1)
65
+ messageBus.publish({
66
+ cluster_id: cluster.id,
67
+ topic: 'QUICK_VALIDATION_RESULT',
68
+ sender: 'validator-requirements',
69
+ timestamp: now + 10,
70
+ content: { data: { approved: true, errors: ['req-error'] } },
71
+ });
72
+ messageBus.publish({
73
+ cluster_id: cluster.id,
74
+ topic: 'QUICK_VALIDATION_RESULT',
75
+ sender: 'validator-code',
76
+ timestamp: now + 20,
77
+ content: { data: { approved: true, errors: ['code-error'] } },
78
+ });
79
+
80
+ const gateOk = logicEngine.evaluate(
81
+ trigger.logic.script,
82
+ { id: 'consensus-coordinator', cluster_id: cluster.id },
83
+ { topic: 'QUICK_VALIDATION_RESULT' }
84
+ );
85
+ if (!gateOk) {
86
+ ledger.close();
87
+ return { ok: false, error: 'quick-validation: gate did not open after both validators' };
88
+ }
89
+
90
+ const simAgent = createSimAgent({ agentConfig: coordinator, cluster, messageBus });
91
+ const triggeringMessage = messageBus.findLast({
92
+ cluster_id: cluster.id,
93
+ topic: 'QUICK_VALIDATION_RESULT',
94
+ });
95
+
96
+ try {
97
+ await executeHook({
98
+ hook: coordinator.hooks.onComplete,
99
+ agent: simAgent,
100
+ message: triggeringMessage,
101
+ result: {
102
+ output: JSON.stringify({ allApproved, summary: allApproved ? 'ok' : 'nope' }),
103
+ success: true,
104
+ taskId: 'sim-task',
105
+ },
106
+ messageBus,
107
+ cluster,
108
+ });
109
+ } catch (err) {
110
+ ledger.close();
111
+ return { ok: false, error: `quick-validation: onComplete failed: ${err.message}` };
112
+ }
113
+
114
+ const passed = messageBus.findLast({
115
+ cluster_id: cluster.id,
116
+ topic: 'QUICK_VALIDATION_PASSED',
117
+ });
118
+ const validationResult = messageBus.findLast({
119
+ cluster_id: cluster.id,
120
+ topic: 'VALIDATION_RESULT',
121
+ });
122
+
123
+ ledger.close();
124
+
125
+ if (allApproved) {
126
+ if (!passed)
127
+ return { ok: false, error: 'quick-validation: expected QUICK_VALIDATION_PASSED' };
128
+ return { ok: true };
129
+ }
130
+
131
+ if (!validationResult) {
132
+ return { ok: false, error: 'quick-validation: expected VALIDATION_RESULT on rejection' };
133
+ }
134
+
135
+ const errors = validationResult.content?.data?.errors || [];
136
+ if (!errors.includes('req-error') || !errors.includes('code-error')) {
137
+ return { ok: false, error: 'quick-validation: rejection did not aggregate validator errors' };
138
+ }
139
+
140
+ return { ok: true };
141
+ };
142
+
143
+ for (const allApproved of [true, false]) {
144
+ const res = await runScenario(allApproved);
145
+ if (!res.ok) failures.push(res.error);
146
+ }
147
+
148
+ return failures;
149
+ }
150
+
151
+ async function simulateHeavyValidation({ config }) {
152
+ const cluster = {
153
+ id: 'heavy-sim',
154
+ agents: config.agents.map((a) => ({ id: a.id, role: a.role })),
155
+ };
156
+
157
+ const coordinator = config.agents.find((a) => a.id === 'consensus-coordinator');
158
+ assert.ok(coordinator, 'heavy-validation: consensus-coordinator missing');
159
+
160
+ const trigger = coordinator.triggers.find((t) => t.topic === 'HEAVY_VALIDATION_RESULT');
161
+ assert.ok(trigger?.logic?.script, 'heavy-validation: coordinator trigger logic missing');
162
+ assert.ok(coordinator.hooks?.onComplete, 'heavy-validation: coordinator onComplete missing');
163
+
164
+ const failures = [];
165
+
166
+ const runScenario = async (allApproved) => {
167
+ const ledger = new Ledger(':memory:');
168
+ const messageBus = new MessageBus(ledger);
169
+ const logicEngine = new LogicEngine(messageBus, cluster);
170
+
171
+ const now = Date.now();
172
+ messageBus.publish({
173
+ cluster_id: cluster.id,
174
+ topic: 'QUICK_VALIDATION_PASSED',
175
+ sender: 'consensus-coordinator',
176
+ timestamp: now,
177
+ });
178
+
179
+ messageBus.publish({
180
+ cluster_id: cluster.id,
181
+ topic: 'HEAVY_VALIDATION_RESULT',
182
+ sender: 'validator-security',
183
+ timestamp: now + 10,
184
+ content: { data: { approved: true, errors: ['sec-error'] } },
185
+ });
186
+ messageBus.publish({
187
+ cluster_id: cluster.id,
188
+ topic: 'HEAVY_VALIDATION_RESULT',
189
+ sender: 'validator-tester',
190
+ timestamp: now + 20,
191
+ content: { data: { approved: true, errors: ['test-error'] } },
192
+ });
193
+
194
+ const gateOk = logicEngine.evaluate(
195
+ trigger.logic.script,
196
+ { id: 'consensus-coordinator', cluster_id: cluster.id },
197
+ { topic: 'HEAVY_VALIDATION_RESULT' }
198
+ );
199
+ if (!gateOk) {
200
+ ledger.close();
201
+ return { ok: false, error: 'heavy-validation: gate did not open after both validators' };
202
+ }
203
+
204
+ const simAgent = createSimAgent({ agentConfig: coordinator, cluster, messageBus });
205
+ const triggeringMessage = messageBus.findLast({
206
+ cluster_id: cluster.id,
207
+ topic: 'HEAVY_VALIDATION_RESULT',
208
+ });
209
+
210
+ try {
211
+ await executeHook({
212
+ hook: coordinator.hooks.onComplete,
213
+ agent: simAgent,
214
+ message: triggeringMessage,
215
+ result: {
216
+ output: JSON.stringify({ allApproved, summary: allApproved ? 'ok' : 'nope' }),
217
+ success: true,
218
+ taskId: 'sim-task',
219
+ },
220
+ messageBus,
221
+ cluster,
222
+ });
223
+ } catch (err) {
224
+ ledger.close();
225
+ return { ok: false, error: `heavy-validation: onComplete failed: ${err.message}` };
226
+ }
227
+
228
+ const validationResult = messageBus.findLast({
229
+ cluster_id: cluster.id,
230
+ topic: 'VALIDATION_RESULT',
231
+ });
232
+ ledger.close();
233
+
234
+ if (!validationResult) {
235
+ return { ok: false, error: 'heavy-validation: expected VALIDATION_RESULT' };
236
+ }
237
+
238
+ const errors = validationResult.content?.data?.errors || [];
239
+ if (!errors.includes('sec-error') || !errors.includes('test-error')) {
240
+ return { ok: false, error: 'heavy-validation: did not aggregate validator errors' };
241
+ }
242
+
243
+ return { ok: true };
244
+ };
245
+
246
+ for (const allApproved of [true, false]) {
247
+ const res = await runScenario(allApproved);
248
+ if (!res.ok) failures.push(res.error);
249
+ }
250
+
251
+ return failures;
252
+ }
253
+
254
+ /**
255
+ * Deep sim: run deterministic two-stage validation scenarios for base templates.
256
+ * Returns an array of error strings.
257
+ */
258
+ function simulateTwoStageValidation({ templateId, config }) {
259
+ if (templateId === 'quick-validation') {
260
+ return simulateQuickValidation({ config });
261
+ }
262
+ if (templateId === 'heavy-validation') {
263
+ return simulateHeavyValidation({ config });
264
+ }
265
+ return Promise.resolve([]);
266
+ }
267
+
268
+ module.exports = {
269
+ simulateTwoStageValidation,
270
+ };
@@ -0,0 +1,135 @@
1
+ const fs = require('fs');
2
+ const os = require('os');
3
+ const path = require('path');
4
+
5
+ const { resolveWorktreeRoot } = require('./worktree-tooling-env');
6
+
7
+ const CLAUDE_DIRNAME = '.claude';
8
+ const SETTINGS_BASENAME = 'settings.json';
9
+ const MCP_BASENAME = '.mcp.json';
10
+
11
+ function isPlainObject(value) {
12
+ return value && typeof value === 'object' && !Array.isArray(value);
13
+ }
14
+
15
+ function readJsonIfExists(filePath) {
16
+ if (!fs.existsSync(filePath)) {
17
+ return null;
18
+ }
19
+
20
+ try {
21
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ function mergeJson(baseValue, overrideValue) {
28
+ if (Array.isArray(baseValue) && Array.isArray(overrideValue)) {
29
+ const seen = new Set();
30
+ const merged = [];
31
+
32
+ for (const entry of [...baseValue, ...overrideValue]) {
33
+ const key = JSON.stringify(entry);
34
+ if (seen.has(key)) {
35
+ continue;
36
+ }
37
+ seen.add(key);
38
+ merged.push(entry);
39
+ }
40
+
41
+ return merged;
42
+ }
43
+
44
+ if (isPlainObject(baseValue) && isPlainObject(overrideValue)) {
45
+ const merged = { ...baseValue };
46
+ for (const [key, value] of Object.entries(overrideValue)) {
47
+ if (Object.prototype.hasOwnProperty.call(merged, key)) {
48
+ merged[key] = mergeJson(merged[key], value);
49
+ } else {
50
+ merged[key] = value;
51
+ }
52
+ }
53
+ return merged;
54
+ }
55
+
56
+ return overrideValue === undefined ? baseValue : overrideValue;
57
+ }
58
+
59
+ function ensureDir(dirPath) {
60
+ fs.mkdirSync(dirPath, { recursive: true });
61
+ }
62
+
63
+ function copyIfExists(sourcePath, destPath) {
64
+ if (!fs.existsSync(sourcePath)) {
65
+ return;
66
+ }
67
+
68
+ ensureDir(path.dirname(destPath));
69
+ fs.copyFileSync(sourcePath, destPath);
70
+ }
71
+
72
+ function resolveRepoClaudeConfig(worktreeRoot) {
73
+ const configDir = path.join(worktreeRoot, CLAUDE_DIRNAME);
74
+ const settingsPath = path.join(configDir, SETTINGS_BASENAME);
75
+ const mcpPath = path.join(configDir, MCP_BASENAME);
76
+
77
+ if (!fs.existsSync(settingsPath) && !fs.existsSync(mcpPath)) {
78
+ return null;
79
+ }
80
+
81
+ return {
82
+ configDir,
83
+ settingsPath,
84
+ mcpPath,
85
+ };
86
+ }
87
+
88
+ function prepareClaudeConfigDir(options = {}) {
89
+ const worktreeRoot = resolveWorktreeRoot(options.worktreePath || options.cwd);
90
+ if (!worktreeRoot) {
91
+ return null;
92
+ }
93
+
94
+ const repoConfig = resolveRepoClaudeConfig(worktreeRoot);
95
+ if (!repoConfig) {
96
+ return null;
97
+ }
98
+
99
+ const sourceDir =
100
+ options.sourceDir || process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), CLAUDE_DIRNAME);
101
+ const tempRoot = path.join(os.tmpdir(), 'zeroshot-claude-configs');
102
+ ensureDir(tempRoot);
103
+
104
+ const overlayDir = fs.mkdtempSync(path.join(tempRoot, 'config-'));
105
+ ensureDir(path.join(overlayDir, 'hooks'));
106
+ ensureDir(path.join(overlayDir, 'projects'));
107
+
108
+ copyIfExists(
109
+ path.join(sourceDir, '.credentials.json'),
110
+ path.join(overlayDir, '.credentials.json')
111
+ );
112
+
113
+ const sourceSettings = readJsonIfExists(path.join(sourceDir, SETTINGS_BASENAME)) || {};
114
+ const repoSettings = readJsonIfExists(repoConfig.settingsPath) || {};
115
+ const mergedSettings = mergeJson(sourceSettings, repoSettings);
116
+ if (Object.keys(mergedSettings).length > 0) {
117
+ fs.writeFileSync(
118
+ path.join(overlayDir, SETTINGS_BASENAME),
119
+ JSON.stringify(mergedSettings, null, 2)
120
+ );
121
+ }
122
+
123
+ const sourceMcp = readJsonIfExists(path.join(sourceDir, MCP_BASENAME)) || {};
124
+ const repoMcp = readJsonIfExists(repoConfig.mcpPath) || {};
125
+ const mergedMcp = mergeJson(sourceMcp, repoMcp);
126
+ if (Object.keys(mergedMcp).length > 0) {
127
+ fs.writeFileSync(path.join(overlayDir, MCP_BASENAME), JSON.stringify(mergedMcp, null, 2));
128
+ }
129
+
130
+ return overlayDir;
131
+ }
132
+
133
+ module.exports = {
134
+ prepareClaudeConfigDir,
135
+ };
@@ -0,0 +1,150 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const TOOLING_METADATA_RELATIVE_PATH = path.join('.zeroshot', 'tooling-env.json');
5
+ const DEFAULT_TOOL_BIN_RELATIVE_PATHS = ['.zeroshot/bin', '.worktree-tool-bin'];
6
+ const FALLBACK_BIN_PREFIX = '.worktree-tool-bin.';
7
+
8
+ function pathKeyForEnv(env) {
9
+ return Object.keys(env).find((key) => key.toUpperCase() === 'PATH') || 'PATH';
10
+ }
11
+
12
+ function resolveExistingRealPath(candidatePath) {
13
+ try {
14
+ return fs.realpathSync(candidatePath);
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+
20
+ function isWithinRoot(candidatePath, rootPath) {
21
+ const candidateRealPath = resolveExistingRealPath(candidatePath);
22
+ const rootRealPath = resolveExistingRealPath(rootPath);
23
+ if (!candidateRealPath || !rootRealPath) {
24
+ return false;
25
+ }
26
+
27
+ return (
28
+ candidateRealPath === rootRealPath || candidateRealPath.startsWith(`${rootRealPath}${path.sep}`)
29
+ );
30
+ }
31
+
32
+ function dedupePaths(entries) {
33
+ const seen = new Set();
34
+ const orderedEntries = [];
35
+
36
+ for (const entry of entries) {
37
+ if (!entry || seen.has(entry)) {
38
+ continue;
39
+ }
40
+ seen.add(entry);
41
+ orderedEntries.push(entry);
42
+ }
43
+
44
+ return orderedEntries;
45
+ }
46
+
47
+ function hasToolingMetadata(dirPath) {
48
+ return fs.existsSync(path.join(dirPath, TOOLING_METADATA_RELATIVE_PATH));
49
+ }
50
+
51
+ function hasGitEntry(dirPath) {
52
+ return fs.existsSync(path.join(dirPath, '.git'));
53
+ }
54
+
55
+ function resolveWorktreeRoot(startDir) {
56
+ if (!startDir) {
57
+ return null;
58
+ }
59
+
60
+ let currentDir = path.resolve(startDir);
61
+ let nearestGitRoot = null;
62
+ while (true) {
63
+ if (hasToolingMetadata(currentDir)) {
64
+ return currentDir;
65
+ }
66
+ if (!nearestGitRoot && hasGitEntry(currentDir)) {
67
+ nearestGitRoot = currentDir;
68
+ }
69
+
70
+ const parentDir = path.dirname(currentDir);
71
+ if (parentDir === currentDir) {
72
+ return nearestGitRoot;
73
+ }
74
+ currentDir = parentDir;
75
+ }
76
+ }
77
+
78
+ function readToolingMetadata(worktreeRoot) {
79
+ const metadataPath = path.join(worktreeRoot, TOOLING_METADATA_RELATIVE_PATH);
80
+ if (!fs.existsSync(metadataPath)) {
81
+ return null;
82
+ }
83
+
84
+ try {
85
+ const parsed = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
86
+ if (!parsed || typeof parsed !== 'object') {
87
+ return null;
88
+ }
89
+ return parsed;
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+
95
+ function listFallbackBinDirectories(worktreeRoot) {
96
+ try {
97
+ return fs
98
+ .readdirSync(worktreeRoot, { withFileTypes: true })
99
+ .filter((entry) => entry.isDirectory() && entry.name.startsWith(FALLBACK_BIN_PREFIX))
100
+ .map((entry) => path.join(worktreeRoot, entry.name));
101
+ } catch {
102
+ return [];
103
+ }
104
+ }
105
+
106
+ function resolveWorktreeToolBinEntries(options = {}) {
107
+ const worktreeRoot = resolveWorktreeRoot(options.worktreePath || options.cwd);
108
+ if (!worktreeRoot) {
109
+ return [];
110
+ }
111
+
112
+ const metadata = readToolingMetadata(worktreeRoot);
113
+ const hasExplicitWorktreePath =
114
+ typeof options.worktreePath === 'string' && options.worktreePath.trim().length > 0;
115
+ if (!metadata && !hasExplicitWorktreePath) {
116
+ return [];
117
+ }
118
+
119
+ const candidates = [];
120
+ if (typeof metadata?.toolBinDir === 'string' && metadata.toolBinDir.trim()) {
121
+ candidates.push(metadata.toolBinDir.trim());
122
+ }
123
+
124
+ for (const relativePath of DEFAULT_TOOL_BIN_RELATIVE_PATHS) {
125
+ candidates.push(path.join(worktreeRoot, relativePath));
126
+ }
127
+ candidates.push(...listFallbackBinDirectories(worktreeRoot));
128
+
129
+ return dedupePaths(candidates).filter((candidatePath) =>
130
+ isWithinRoot(candidatePath, worktreeRoot)
131
+ );
132
+ }
133
+
134
+ function prependWorktreeToolBinToEnv(env, options = {}) {
135
+ const toolBinEntries = resolveWorktreeToolBinEntries(options);
136
+ if (toolBinEntries.length === 0) {
137
+ return env;
138
+ }
139
+
140
+ const pathKey = pathKeyForEnv(env);
141
+ const existingEntries = (env[pathKey] || '').split(path.delimiter).filter(Boolean);
142
+ env[pathKey] = dedupePaths([...toolBinEntries, ...existingEntries]).join(path.delimiter);
143
+ return env;
144
+ }
145
+
146
+ module.exports = {
147
+ prependWorktreeToolBinToEnv,
148
+ resolveWorktreeRoot,
149
+ resolveWorktreeToolBinEntries,
150
+ };