@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,721 @@
1
+ /**
2
+ * AgentHookExecutor - Hook transformation and execution
3
+ *
4
+ * Provides:
5
+ * - Hook execution (publish_message, stop_cluster, etc.)
6
+ * - Template variable substitution
7
+ * - Transform script execution in VM sandbox
8
+ * - Logic scripts for conditional config (like triggers)
9
+ */
10
+
11
+ const vm = require('vm');
12
+ const { execSync } = require('../lib/safe-exec'); // Enforces timeouts
13
+ const { verifyPullRequest } = require('./pr-verification');
14
+
15
+ /**
16
+ * Deep merge two objects, with source taking precedence
17
+ * @param {Object} target - Base object
18
+ * @param {Object} source - Override object
19
+ * @returns {Object} Merged object
20
+ */
21
+ function deepMerge(target, source) {
22
+ if (!source || typeof source !== 'object') return target;
23
+ if (!target || typeof target !== 'object') return source;
24
+
25
+ const result = { ...target };
26
+ for (const key of Object.keys(source)) {
27
+ if (
28
+ source[key] &&
29
+ typeof source[key] === 'object' &&
30
+ !Array.isArray(source[key]) &&
31
+ target[key] &&
32
+ typeof target[key] === 'object' &&
33
+ !Array.isArray(target[key])
34
+ ) {
35
+ result[key] = deepMerge(target[key], source[key]);
36
+ } else {
37
+ result[key] = source[key];
38
+ }
39
+ }
40
+ return result;
41
+ }
42
+
43
+ async function parseResultDataForHookLogic({ agent, result }) {
44
+ if (!result?.output) return null;
45
+ try {
46
+ return await agent._parseResultOutput(result.output);
47
+ } catch (parseError) {
48
+ agent._log(
49
+ `⚠️ Hook logic: result parsing failed, continuing with null: ${parseError.message}`
50
+ );
51
+ return null;
52
+ }
53
+ }
54
+
55
+ async function resolveHookConfigWithLogic({ hook, agent, context, result }) {
56
+ if (!hook.logic) return hook.config;
57
+
58
+ const resultData = await parseResultDataForHookLogic({ agent, result });
59
+ const overrides = evaluateHookLogic({
60
+ logic: hook.logic,
61
+ resultData,
62
+ agent,
63
+ context,
64
+ });
65
+
66
+ if (!overrides) {
67
+ return hook.config;
68
+ }
69
+
70
+ agent._log(`Hook logic returned overrides: ${JSON.stringify(overrides)}`);
71
+ return deepMerge(hook.config, overrides);
72
+ }
73
+
74
+ async function resolvePublishMessage({ hook, agent, context, cluster, result }) {
75
+ if (hook.transform) {
76
+ return executeTransform({
77
+ transform: hook.transform,
78
+ context,
79
+ agent,
80
+ });
81
+ }
82
+
83
+ const effectiveConfig = await resolveHookConfigWithLogic({
84
+ hook,
85
+ agent,
86
+ context,
87
+ result,
88
+ });
89
+
90
+ return substituteTemplate({
91
+ config: effectiveConfig,
92
+ context,
93
+ agent,
94
+ cluster,
95
+ });
96
+ }
97
+
98
+ /**
99
+ * Execute a hook
100
+ * THROWS on failure - no silent errors
101
+ * @param {Object} params - Hook execution parameters
102
+ * @param {Object} params.hook - Hook configuration
103
+ * @param {Object} params.agent - Agent instance
104
+ * @param {Object} params.message - Triggering message
105
+ * @param {Object} params.result - Agent execution result
106
+ * @param {Object} params.messageBus - Message bus instance
107
+ * @param {Object} params.cluster - Cluster object
108
+ * @param {Object} params.orchestrator - Orchestrator instance
109
+ * @returns {Promise<void>}
110
+ */
111
+ async function executeHook(params) {
112
+ const { hook, agent, message, result, cluster } = params;
113
+
114
+ if (!hook) {
115
+ return;
116
+ }
117
+
118
+ // Build context for hook execution
119
+ const context = {
120
+ result,
121
+ triggeringMessage: message,
122
+ agent,
123
+ cluster,
124
+ };
125
+
126
+ // NO try/catch - errors must propagate
127
+ if (hook.action === 'publish_message') {
128
+ const messageToPublish = await resolvePublishMessage({
129
+ hook,
130
+ agent,
131
+ context,
132
+ cluster,
133
+ result,
134
+ });
135
+ agent._publish(messageToPublish);
136
+ return;
137
+ }
138
+
139
+ if (hook.action === 'execute_system_command') {
140
+ throw new Error('execute_system_command not implemented');
141
+ }
142
+
143
+ if (hook.action === 'verify_pull_request') {
144
+ await verifyPullRequest({ result, agent });
145
+ return;
146
+ }
147
+
148
+ throw new Error(`Unknown hook action: ${hook.action}`);
149
+ }
150
+
151
+ function getAccessedFields(script) {
152
+ return [...script.matchAll(/result\.([a-zA-Z_]+)/g)].map((m) => m[1]);
153
+ }
154
+
155
+ function logTransformParseFailure({ agent, context, parseError }) {
156
+ const taskId = context.result?.taskId || agent.currentTaskId || 'UNKNOWN';
157
+ console.error(`\n${'='.repeat(80)}`);
158
+ console.error(`🔴 TRANSFORM SCRIPT BLOCKED - RESULT PARSING FAILED`);
159
+ console.error(`${'='.repeat(80)}`);
160
+ console.error(`Agent: ${agent.id}, Role: ${agent.role}`);
161
+ console.error(`TaskID: ${taskId}`);
162
+ console.error(`Parse error: ${parseError.message}`);
163
+ console.error(`Output (last 500 chars): ${(context.result.output || '').slice(-500)}`);
164
+ console.error(`${'='.repeat(80)}\n`);
165
+ }
166
+
167
+ function logMissingResultFields({ agent, context, accessedFields, missingFields, resultData }) {
168
+ const taskId = context.result?.taskId || agent.currentTaskId || 'UNKNOWN';
169
+ console.error(`\n${'='.repeat(80)}`);
170
+ console.error(`🔴 TRANSFORM SCRIPT BLOCKED - MISSING REQUIRED FIELDS`);
171
+ console.error(`${'='.repeat(80)}`);
172
+ console.error(`Agent: ${agent.id}, Role: ${agent.role}, TaskID: ${taskId}`);
173
+ console.error(`Script accesses: ${accessedFields.join(', ')}`);
174
+ console.error(`Missing from result: ${missingFields.join(', ')}`);
175
+ console.error(`Result keys: ${Object.keys(resultData).join(', ')}`);
176
+ console.error(`Result data: ${JSON.stringify(resultData, null, 2)}`);
177
+ console.error(`${'='.repeat(80)}\n`);
178
+ }
179
+
180
+ async function parseTransformResultData({ context, agent, script, scriptUsesResult }) {
181
+ if (context.result?.output) {
182
+ let resultData = null;
183
+ try {
184
+ resultData = await agent._parseResultOutput(context.result.output);
185
+ } catch (parseError) {
186
+ logTransformParseFailure({ agent, context, parseError });
187
+ throw new Error(
188
+ `Transform script cannot run: result parsing failed. ` +
189
+ `Agent: ${agent.id}, Error: ${parseError.message}`
190
+ );
191
+ }
192
+
193
+ const accessedFields = getAccessedFields(script);
194
+ const missingFields = accessedFields.filter((f) => resultData[f] === undefined);
195
+ if (missingFields.length > 0) {
196
+ logMissingResultFields({ agent, context, accessedFields, missingFields, resultData });
197
+ const taskId = context.result?.taskId || agent.currentTaskId || 'UNKNOWN';
198
+ throw new Error(
199
+ `Transform script accesses undefined fields: ${missingFields.join(', ')}. ` +
200
+ `Agent ${agent.id} (task ${taskId}) output missing required fields. ` +
201
+ `Check agent's jsonSchema and output format.`
202
+ );
203
+ }
204
+
205
+ return resultData;
206
+ }
207
+
208
+ if (scriptUsesResult) {
209
+ const taskId = context.result?.taskId || agent.currentTaskId || 'UNKNOWN';
210
+ const outputLength = (context.result?.output || '').length;
211
+ throw new Error(
212
+ `Transform script uses result.* variables but no output was captured. ` +
213
+ `Agent: ${agent.id}, TaskID: ${taskId}, Iteration: ${agent.iteration}, ` +
214
+ `Output length: ${outputLength}. ` +
215
+ `Check that the task completed successfully and the get-log-path command exists.`
216
+ );
217
+ }
218
+
219
+ return null;
220
+ }
221
+
222
+ function buildTransformSandbox({ resultData, context, agent }) {
223
+ const clusterId = agent.cluster?.id || context.cluster?.id || agent.cluster_id || 'unknown';
224
+ const messageBus = agent.messageBus;
225
+ const cluster = context.cluster || agent.cluster || null;
226
+
227
+ // Ledger API wrapper (auto-scoped to cluster) - mirrors logic-engine.js
228
+ const ledgerAPI = messageBus
229
+ ? {
230
+ query: (criteria) => {
231
+ return messageBus.query({ ...criteria, cluster_id: clusterId });
232
+ },
233
+ findLast: (criteria) => {
234
+ return messageBus.findLast({ ...criteria, cluster_id: clusterId });
235
+ },
236
+ count: (criteria) => {
237
+ return messageBus.count({ ...criteria, cluster_id: clusterId });
238
+ },
239
+ since: (timestamp) => {
240
+ return messageBus.since({ cluster_id: clusterId, timestamp });
241
+ },
242
+ }
243
+ : null;
244
+
245
+ // Cluster API wrapper - mirrors logic-engine.js
246
+ const clusterAPI = {
247
+ id: clusterId,
248
+ getAgents: () => {
249
+ return cluster ? cluster.agents || [] : [];
250
+ },
251
+ getAgentsByRole: (role) => {
252
+ return cluster ? (cluster.agents || []).filter((a) => a.role === role) : [];
253
+ },
254
+ getAgent: (id) => {
255
+ return cluster ? (cluster.agents || []).find((a) => a.id === id) : null;
256
+ },
257
+ };
258
+
259
+ // Helper functions - mirrors logic-engine.js
260
+ const helpers = {
261
+ getConfig: require('../config-router').getConfig,
262
+ allResponded: (agents, topic, since) => {
263
+ if (!ledgerAPI) return false;
264
+ const responses = ledgerAPI.query({ topic, since });
265
+ const responders = new Set(responses.map((r) => r.sender));
266
+ return agents.every((a) => responders.has(a.id || a));
267
+ },
268
+ hasConsensus: (topic, since) => {
269
+ if (!ledgerAPI) return false;
270
+ const responses = ledgerAPI.query({ topic, since });
271
+ if (responses.length === 0) return false;
272
+ return responses.every((r) => r.content?.data?.approved === true);
273
+ },
274
+ };
275
+
276
+ return {
277
+ result: resultData,
278
+ triggeringMessage: context.triggeringMessage,
279
+ ledger: ledgerAPI,
280
+ cluster: clusterAPI,
281
+ helpers,
282
+ // Safe built-ins
283
+ JSON,
284
+ Set,
285
+ Map,
286
+ Array,
287
+ Object,
288
+ console: {
289
+ log: (...args) => agent._log('[transform]', ...args),
290
+ error: (...args) => console.error('[transform]', ...args),
291
+ warn: (...args) => console.warn('[transform]', ...args),
292
+ },
293
+ };
294
+ }
295
+
296
+ function runTransformScript(script, sandbox) {
297
+ const vmContext = vm.createContext(sandbox);
298
+ // codeql[js/bad-code-sanitization] Transform scripts are repo-authored config code executed only inside Zeroshot's restricted VM sandbox.
299
+ const wrappedScript = `(function() { ${script} })()`;
300
+
301
+ try {
302
+ return vm.runInContext(wrappedScript, vmContext, { timeout: 5000 });
303
+ } catch (err) {
304
+ throw new Error(`Transform script error: ${err.message}`);
305
+ }
306
+ }
307
+
308
+ function validateTransformResult(result) {
309
+ if (!result || typeof result !== 'object') {
310
+ throw new Error(
311
+ `Transform script must return an object with topic and content, got: ${typeof result}`
312
+ );
313
+ }
314
+ if (!result.topic) {
315
+ throw new Error(`Transform script result must have a 'topic' property`);
316
+ }
317
+ if (!result.content) {
318
+ throw new Error(`Transform script result must have a 'content' property`);
319
+ }
320
+ }
321
+
322
+ function validateClusterOperationsResult(result, agent) {
323
+ if (result.topic !== 'CLUSTER_OPERATIONS') return;
324
+
325
+ const operations = result.content?.data?.operations;
326
+ if (!operations) {
327
+ console.error(`\n${'='.repeat(80)}`);
328
+ console.error(`🔴 CLUSTER_OPERATIONS MALFORMED - MISSING OPERATIONS ARRAY`);
329
+ console.error(`${'='.repeat(80)}`);
330
+ console.error(`Agent: ${agent.id}`);
331
+ console.error(`Result: ${JSON.stringify(result, null, 2)}`);
332
+ console.error(`${'='.repeat(80)}\n`);
333
+ throw new Error(
334
+ `CLUSTER_OPERATIONS message missing operations array. ` +
335
+ `Agent ${agent.id} transform script returned invalid structure.`
336
+ );
337
+ }
338
+ if (!Array.isArray(operations)) {
339
+ throw new Error(`CLUSTER_OPERATIONS.operations must be an array, got: ${typeof operations}`);
340
+ }
341
+ if (operations.length === 0) {
342
+ throw new Error(`CLUSTER_OPERATIONS.operations is empty - no operations to execute`);
343
+ }
344
+
345
+ for (let i = 0; i < operations.length; i++) {
346
+ const op = operations[i];
347
+ if (!op || !op.action) {
348
+ throw new Error(`CLUSTER_OPERATIONS.operations[${i}] missing required 'action' field`);
349
+ }
350
+ }
351
+
352
+ agent._log(`✅ CLUSTER_OPERATIONS validated: ${operations.length} operations`);
353
+ }
354
+
355
+ /**
356
+ * Execute a hook transform script
357
+ * Transform scripts return the message to publish, with access to:
358
+ * - result: parsed agent output
359
+ * - triggeringMessage: the message that triggered the agent
360
+ * - helpers: { getConfig(complexity, taskType) }
361
+ * @param {Object} params - Transform parameters
362
+ * @param {Object} params.transform - Transform configuration
363
+ * @param {Object} params.context - Execution context
364
+ * @param {Object} params.agent - Agent instance
365
+ * @returns {Promise<Object>} Message to publish
366
+ */
367
+ async function executeTransform(params) {
368
+ const { transform, context, agent } = params;
369
+ const { engine, script } = transform;
370
+
371
+ if (engine !== 'javascript') {
372
+ throw new Error(`Unsupported transform engine: ${engine}`);
373
+ }
374
+
375
+ // Parse result output if we have a result
376
+ // VALIDATION: Check if script uses result.* variables and fail early if no output
377
+ const scriptUsesResult = /\bresult\.[a-zA-Z]/.test(script);
378
+ const resultData = await parseTransformResultData({
379
+ context,
380
+ agent,
381
+ script,
382
+ scriptUsesResult,
383
+ });
384
+
385
+ const sandbox = buildTransformSandbox({ resultData, context, agent });
386
+ const result = runTransformScript(script, sandbox);
387
+
388
+ validateTransformResult(result);
389
+ validateClusterOperationsResult(result, agent);
390
+
391
+ return result;
392
+ }
393
+
394
+ /**
395
+ * Substitute template variables in hook config
396
+ * ONLY parses result output if result.* variables are used
397
+ * THROWS on any error - no silent failures
398
+ * @param {Object} params - Substitution parameters
399
+ * @param {Object} params.config - Hook configuration
400
+ * @param {Object} params.context - Execution context
401
+ * @param {Object} params.agent - Agent instance
402
+ * @param {Object} params.cluster - Cluster object
403
+ * @returns {Promise<Object>} Substituted configuration
404
+ */
405
+ async function substituteTemplate(params) {
406
+ const { config, context, agent, cluster } = params;
407
+
408
+ if (!config) {
409
+ throw new Error('_substituteTemplate: config is required');
410
+ }
411
+
412
+ const json = JSON.stringify(config);
413
+
414
+ // Check if ANY result.* variables are used BEFORE parsing
415
+ // Generic pattern - no hardcoded field names, works with any agent config
416
+ const usesResultVars = /\{\{result\.[^}]+\}\}/.test(json);
417
+
418
+ let resultData = null;
419
+ if (usesResultVars) {
420
+ if (!context.result) {
421
+ throw new Error(
422
+ `Hook uses result.* variables but no result in context. ` +
423
+ `Agent: ${agent.id}, TaskID: ${agent.currentTaskId}, Iteration: ${agent.iteration}`
424
+ );
425
+ }
426
+ if (!context.result.output) {
427
+ // Log detailed context for debugging
428
+ const taskId = context.result.taskId || agent.currentTaskId || 'UNKNOWN';
429
+ console.error(`\n${'='.repeat(80)}`);
430
+ console.error(`🔴 HOOK FAILURE - EMPTY OUTPUT`);
431
+ console.error(`${'='.repeat(80)}`);
432
+ console.error(`Agent: ${agent.id}`);
433
+ console.error(`Task ID: ${taskId}`);
434
+ console.error(`Iteration: ${context.result.iteration || agent.iteration}`);
435
+ console.error(`Result success: ${context.result.success}`);
436
+ console.error(`Result error: ${context.result.error || 'none'}`);
437
+ console.error(`Output length: ${(context.result.output || '').length}`);
438
+ console.error(`Hook config: ${JSON.stringify(config, null, 2)}`);
439
+
440
+ // Auto-fetch and publish task logs for debugging
441
+ let taskLogs = 'Task logs unavailable';
442
+ if (taskId !== 'UNKNOWN') {
443
+ console.error(`\nFetching task logs for ${taskId}...`);
444
+ try {
445
+ const ctPath = agent._getClaudeTasksPath();
446
+ taskLogs = execSync(`${ctPath} logs ${taskId} --lines 100`, {
447
+ encoding: 'utf-8',
448
+ timeout: 5000,
449
+ maxBuffer: 1024 * 1024, // 1MB
450
+ }).trim();
451
+ console.error(`✓ Retrieved ${taskLogs.split('\n').length} lines of logs`);
452
+ } catch (err) {
453
+ taskLogs = `Failed to retrieve logs: ${err.message}`;
454
+ console.error(`✗ Failed to retrieve logs: ${err.message}`);
455
+ }
456
+ }
457
+ console.error(`${'='.repeat(80)}\n`);
458
+
459
+ // Publish task logs to message bus for visibility in zeroshot logs
460
+ agent._publish({
461
+ topic: 'AGENT_ERROR',
462
+ receiver: 'broadcast',
463
+ content: {
464
+ text: `Task logs for ${taskId} (last 100 lines)`,
465
+ data: {
466
+ taskId,
467
+ logs: taskLogs,
468
+ logsPreview: taskLogs.split('\n').slice(-20).join('\n'), // Last 20 lines as preview
469
+ },
470
+ },
471
+ });
472
+
473
+ throw new Error(
474
+ `Hook uses result.* variables but result.output is empty. ` +
475
+ `Agent: ${agent.id}, TaskID: ${taskId}, ` +
476
+ `Iteration: ${context.result.iteration || agent.iteration}, ` +
477
+ `Success: ${context.result.success}. ` +
478
+ `Task logs posted to message bus.`
479
+ );
480
+ }
481
+ // Parse result output - WILL THROW if no JSON block
482
+ resultData = await agent._parseResultOutput(context.result.output);
483
+ }
484
+
485
+ // Helper to escape a value for JSON string substitution
486
+ // Uses JSON.stringify for ALL escaping - no manual replace() calls
487
+ const escapeForJsonString = (value) => {
488
+ if (value === null || value === undefined) {
489
+ throw new Error(`Cannot escape null/undefined value for JSON`);
490
+ }
491
+ // JSON.stringify handles ALL escaping (newlines, quotes, backslashes, control chars)
492
+ // .slice(1, -1) strips the outer quotes it adds
493
+ // For arrays/objects: stringify twice - once for JSON, once to escape for string embedding
494
+ const stringified =
495
+ typeof value === 'string' ? JSON.stringify(value) : JSON.stringify(JSON.stringify(value));
496
+ return stringified.slice(1, -1);
497
+ };
498
+
499
+ // Helper to escape template-like patterns in substituted values
500
+ // This prevents content containing "{{result.foo}}" from being flagged as unsubstituted variables
501
+ // Uses Unicode escape for first brace: {{ -> \u007B{ (invisible to humans, breaks pattern match)
502
+ const escapeTemplatePatterns = (str) => {
503
+ return str.replace(/\{\{/g, '\\u007B{');
504
+ };
505
+
506
+ let substituted = json
507
+ .replace(/\{\{cluster\.id\}\}/g, escapeTemplatePatterns(cluster.id))
508
+ .replace(/\{\{cluster\.createdAt\}\}/g, String(cluster.createdAt))
509
+ .replace(/\{\{iteration\}\}/g, String(agent.iteration))
510
+ .replace(
511
+ /\{\{error\.message\}\}/g,
512
+ escapeTemplatePatterns(escapeForJsonString(context.error?.message ?? ''))
513
+ )
514
+ .replace(
515
+ /\{\{result\.output\}\}/g,
516
+ escapeTemplatePatterns(escapeForJsonString(context.result?.output ?? ''))
517
+ );
518
+
519
+ // Substitute ALL result.* variables dynamically from parsed resultData
520
+ if (resultData) {
521
+ // Generic substitution - replace {{result.fieldName}} with resultData[fieldName]
522
+ // No hardcoded field names - works with any agent output schema
523
+ // CRITICAL: For booleans/nulls/numbers, we need to match and remove surrounding quotes
524
+ // to produce valid JSON (e.g., "{{result.approved}}" -> true, not "true")
525
+ substituted = substituted.replace(/"?\{\{result\.([^}]+)\}\}"?/g, (match, fieldName) => {
526
+ const value = resultData[fieldName];
527
+ if (value === undefined) {
528
+ // Missing fields should gracefully default to null or empty values
529
+ // This allows optional schema fields without hardcoding field names
530
+ // If a field is truly required, the schema validation will catch it
531
+ console.warn(
532
+ `⚠️ Agent ${agent.id}: Template variable {{result.${fieldName}}} not found in output. ` +
533
+ `If this field is required by the schema, the agent violated its own schema. ` +
534
+ `Defaulting to null. Agent output keys: ${Object.keys(resultData).join(', ')}`
535
+ );
536
+ return 'null';
537
+ }
538
+ // Booleans, numbers, and null should be unquoted JSON primitives
539
+ if (typeof value === 'boolean' || typeof value === 'number' || value === null) {
540
+ return String(value);
541
+ }
542
+ // Strings need to be quoted and escaped for JSON
543
+ // Also escape any template-like patterns in the content to prevent false positives
544
+ return escapeTemplatePatterns(JSON.stringify(value));
545
+ });
546
+ }
547
+
548
+ // Check for unsubstituted KNOWN template variables only
549
+ // KNOWN patterns: {{cluster.X}}, {{iteration}}, {{error.X}}, {{result.X}}
550
+ // Content may contain arbitrary {{...}} patterns (React dangerouslySetInnerHTML, Mustache, etc.)
551
+ // Those are NOT template variables - they're just content that happens to contain braces
552
+ const KNOWN_TEMPLATE_PREFIXES = ['cluster', 'iteration', 'error', 'result'];
553
+ const knownVariablePattern = new RegExp(
554
+ `\\{\\{(${KNOWN_TEMPLATE_PREFIXES.join('|')})(\\.[a-zA-Z_][a-zA-Z0-9_]*)?\\}\\}`,
555
+ 'g'
556
+ );
557
+ const remaining = substituted.match(knownVariablePattern);
558
+ if (remaining) {
559
+ throw new Error(`Unsubstituted template variables: ${remaining.join(', ')}`);
560
+ }
561
+
562
+ // Parse and validate result
563
+ let result;
564
+ try {
565
+ result = JSON.parse(substituted);
566
+ } catch (e) {
567
+ console.error('JSON parse failed. Substituted string:');
568
+ console.error(substituted);
569
+ throw new Error(`Template substitution produced invalid JSON: ${e.message}`);
570
+ }
571
+
572
+ return result;
573
+ }
574
+
575
+ /**
576
+ * Evaluate hook logic script to get config overrides
577
+ * Similar to trigger logic, but returns an object to merge into config
578
+ * @param {Object} params - Evaluation parameters
579
+ * @param {Object} params.logic - Logic configuration { engine, script }
580
+ * @param {Object} params.resultData - Parsed agent result data
581
+ * @param {Object} params.agent - Agent instance
582
+ * @param {Object} params.context - Execution context
583
+ * @returns {Object|null} Config overrides to merge, or null if none
584
+ */
585
+ function evaluateHookLogic(params) {
586
+ const { logic, resultData, agent, context } = params;
587
+
588
+ if (!logic || !logic.script) {
589
+ return null;
590
+ }
591
+
592
+ if (logic.engine !== 'javascript') {
593
+ throw new Error(`Unsupported hook logic engine: ${logic.engine}`);
594
+ }
595
+
596
+ const clusterId = agent.cluster?.id || context.cluster?.id || agent.cluster_id || 'unknown';
597
+ const messageBus = agent.messageBus;
598
+ const cluster = context.cluster || agent.cluster || null;
599
+
600
+ // Ledger API wrapper (auto-scoped to cluster) - mirrors logic-engine.js
601
+ const ledgerAPI = messageBus
602
+ ? {
603
+ query: (criteria) => {
604
+ return messageBus.query({ ...criteria, cluster_id: clusterId });
605
+ },
606
+ findLast: (criteria) => {
607
+ return messageBus.findLast({ ...criteria, cluster_id: clusterId });
608
+ },
609
+ count: (criteria) => {
610
+ return messageBus.count({ ...criteria, cluster_id: clusterId });
611
+ },
612
+ since: (timestamp) => {
613
+ return messageBus.since({ cluster_id: clusterId, timestamp });
614
+ },
615
+ }
616
+ : null;
617
+
618
+ // Cluster API wrapper - mirrors logic-engine.js
619
+ const clusterAPI = {
620
+ id: clusterId,
621
+ getAgents: () => {
622
+ return cluster ? cluster.agents || [] : [];
623
+ },
624
+ getAgentsByRole: (role) => {
625
+ return cluster ? (cluster.agents || []).filter((a) => a.role === role) : [];
626
+ },
627
+ getAgent: (id) => {
628
+ return cluster ? (cluster.agents || []).find((a) => a.id === id) : null;
629
+ },
630
+ };
631
+
632
+ // Helper functions - mirrors logic-engine.js
633
+ const helpers = {
634
+ getConfig: require('../config-router').getConfig,
635
+ allResponded: (agents, topic, since) => {
636
+ if (!ledgerAPI) return false;
637
+ const responses = ledgerAPI.query({ topic, since });
638
+ const responders = new Set(responses.map((r) => r.sender));
639
+ return agents.every((a) => responders.has(a.id || a));
640
+ },
641
+ hasConsensus: (topic, since) => {
642
+ if (!ledgerAPI) return false;
643
+ const responses = ledgerAPI.query({ topic, since });
644
+ if (responses.length === 0) return false;
645
+ return responses.every((r) => r.content?.data?.approved === true);
646
+ },
647
+ };
648
+
649
+ // Build sandbox context - similar to LogicEngine but focused on result data
650
+ const sandbox = {
651
+ // The parsed result from agent output - this is the main input
652
+ result: resultData || {},
653
+
654
+ // Agent context
655
+ agent: {
656
+ id: agent.id,
657
+ role: agent.role,
658
+ iteration: agent.iteration || 0,
659
+ },
660
+
661
+ // Triggering message (if available)
662
+ message: context.triggeringMessage || null,
663
+
664
+ // APIs
665
+ ledger: ledgerAPI,
666
+ cluster: clusterAPI,
667
+ helpers,
668
+
669
+ // Safe built-ins
670
+ Set,
671
+ Map,
672
+ Array,
673
+ Object,
674
+ String,
675
+ Number,
676
+ Boolean,
677
+ Math,
678
+ Date,
679
+ JSON,
680
+
681
+ // Console for debugging (logs to agent log)
682
+ console: {
683
+ log: (...args) => agent._log('[hook-logic]', ...args),
684
+ error: (...args) => console.error('[hook-logic]', ...args),
685
+ warn: (...args) => console.warn('[hook-logic]', ...args),
686
+ },
687
+ };
688
+
689
+ // Execute in VM sandbox with timeout
690
+ const vmContext = vm.createContext(sandbox);
691
+ // codeql[js/bad-code-sanitization] Hook logic scripts are repo-authored config code executed only inside Zeroshot's restricted VM sandbox.
692
+ const wrappedScript = `(function() { 'use strict'; ${logic.script} })()`;
693
+
694
+ let result;
695
+ try {
696
+ result = vm.runInContext(wrappedScript, vmContext, { timeout: 1000 });
697
+ } catch (err) {
698
+ throw new Error(`Hook logic script error: ${err.message}`);
699
+ }
700
+
701
+ // Logic scripts can return:
702
+ // - undefined/null: no overrides
703
+ // - object: merge into config
704
+ if (result === undefined || result === null) {
705
+ return null;
706
+ }
707
+
708
+ if (typeof result !== 'object') {
709
+ throw new Error(`Hook logic script must return an object or undefined, got: ${typeof result}`);
710
+ }
711
+
712
+ return result;
713
+ }
714
+
715
+ module.exports = {
716
+ executeHook,
717
+ executeTransform,
718
+ substituteTemplate,
719
+ evaluateHookLogic,
720
+ deepMerge,
721
+ };