@the-open-engine/zeroshot 6.38.1 → 6.39.1

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 (383) hide show
  1. package/README.md +6 -0
  2. package/cli/event-copy.js +8 -7
  3. package/cli/event-copy.ts +12 -0
  4. package/cli/index.js +67 -48
  5. package/cli/json-export.js +61 -64
  6. package/cli/json-export.ts +112 -0
  7. package/cli/message-formatter-utils.js +68 -56
  8. package/cli/message-formatter-utils.ts +121 -0
  9. package/cli/message-formatters-normal.js +124 -259
  10. package/cli/message-formatters-normal.ts +250 -0
  11. package/cli/message-formatters-watch.js +81 -84
  12. package/cli/message-formatters-watch.ts +189 -0
  13. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  14. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  15. package/lib/cluster/generated/protocol.d.cts +8 -0
  16. package/lib/cluster/generated/protocol.d.mts +8 -0
  17. package/lib/cluster/generated/protocol.d.ts +8 -0
  18. package/lib/clusters-registry.d.ts +23 -0
  19. package/lib/clusters-registry.js +17 -29
  20. package/lib/completion.d.ts +12 -0
  21. package/lib/completion.js +84 -94
  22. package/lib/compose-utils.d.ts +32 -0
  23. package/lib/compose-utils.js +57 -72
  24. package/lib/detached-startup.d.ts +84 -0
  25. package/lib/detached-startup.js +232 -302
  26. package/lib/docker-config.d.ts +43 -0
  27. package/lib/docker-config.js +150 -325
  28. package/lib/docker-env-auth.d.ts +17 -0
  29. package/lib/docker-env-auth.js +75 -0
  30. package/lib/git-remote-utils.d.ts +48 -0
  31. package/lib/git-remote-utils.js +147 -213
  32. package/lib/id-detector.d.ts +15 -0
  33. package/lib/id-detector.js +37 -41
  34. package/lib/path-check.d.ts +30 -0
  35. package/lib/path-check.js +42 -45
  36. package/lib/process-liveness.d.ts +16 -0
  37. package/lib/process-liveness.js +19 -12
  38. package/lib/provider-credential-path.d.ts +16 -0
  39. package/lib/provider-credential-path.js +31 -29
  40. package/lib/provider-defaults.d.ts +30 -0
  41. package/lib/provider-defaults.js +47 -42
  42. package/lib/provider-detection.d.ts +11 -0
  43. package/lib/provider-detection.js +91 -54
  44. package/lib/provider-names.d.ts +38 -0
  45. package/lib/provider-names.js +56 -64
  46. package/lib/repo-settings.d.ts +28 -0
  47. package/lib/repo-settings.js +83 -59
  48. package/lib/run-mode.d.ts +21 -0
  49. package/lib/run-mode.js +21 -20
  50. package/lib/run-plan.d.ts +28 -0
  51. package/lib/run-plan.js +17 -16
  52. package/lib/settings/claude-auth.d.ts +35 -0
  53. package/lib/settings/claude-auth.js +30 -47
  54. package/lib/settings-defaults.d.ts +20 -0
  55. package/lib/settings-defaults.js +149 -0
  56. package/lib/settings-error.d.ts +7 -0
  57. package/lib/settings-error.js +8 -0
  58. package/lib/settings-issue-providers.d.ts +10 -0
  59. package/lib/settings-issue-providers.js +12 -0
  60. package/lib/settings-models.d.ts +22 -0
  61. package/lib/settings-models.js +93 -0
  62. package/lib/settings-storage.d.ts +23 -0
  63. package/lib/settings-storage.js +205 -0
  64. package/lib/settings-validation.d.ts +7 -0
  65. package/lib/settings-validation.js +182 -0
  66. package/lib/settings.d.ts +29 -0
  67. package/lib/settings.js +41 -736
  68. package/lib/setup-apply-types.d.ts +66 -0
  69. package/lib/setup-apply-types.js +2 -0
  70. package/lib/setup-apply.d.ts +39 -0
  71. package/lib/setup-apply.js +267 -264
  72. package/lib/setup-journal.d.ts +41 -0
  73. package/lib/setup-journal.js +119 -76
  74. package/lib/setup-plan-types.d.ts +102 -0
  75. package/lib/setup-plan-types.js +2 -0
  76. package/lib/setup-plan.d.ts +30 -0
  77. package/lib/setup-plan.js +300 -324
  78. package/lib/setup-undo.d.ts +44 -0
  79. package/lib/setup-undo.js +61 -74
  80. package/lib/start-cluster-config.d.ts +26 -0
  81. package/lib/start-cluster-config.js +56 -0
  82. package/lib/start-cluster-environment.d.ts +41 -0
  83. package/lib/start-cluster-environment.js +134 -0
  84. package/lib/start-cluster-run-options.d.ts +54 -0
  85. package/lib/start-cluster-run-options.js +148 -0
  86. package/lib/start-cluster.d.ts +64 -0
  87. package/lib/start-cluster.js +98 -454
  88. package/lib/stream-json-parser.d.ts +17 -0
  89. package/lib/stream-json-parser.js +51 -52
  90. package/npm-shrinkwrap.json +6 -8
  91. package/package.json +14 -8
  92. package/scripts/postinstall.js +27 -0
  93. package/scripts/rust-distribution.js +36 -45
  94. package/src/agent/agent-command-proofs-context.js +35 -45
  95. package/src/agent/agent-command-proofs-context.ts +87 -0
  96. package/src/agent/agent-config-settings.js +19 -0
  97. package/src/agent/agent-config-settings.ts +41 -0
  98. package/src/agent/agent-config.js +122 -231
  99. package/src/agent/agent-config.ts +285 -0
  100. package/src/agent/agent-context-builder.js +38 -273
  101. package/src/agent/agent-context-builder.ts +51 -0
  102. package/src/agent/agent-context-environment-sections.js +105 -0
  103. package/src/agent/agent-context-environment-sections.ts +134 -0
  104. package/src/agent/agent-context-packs.js +165 -0
  105. package/src/agent/agent-context-packs.ts +296 -0
  106. package/src/agent/agent-context-prompt-sections.js +100 -0
  107. package/src/agent/agent-context-prompt-sections.ts +148 -0
  108. package/src/agent/agent-context-sections.js +25 -334
  109. package/src/agent/agent-context-sections.ts +36 -0
  110. package/src/agent/agent-context-sources.js +96 -149
  111. package/src/agent/agent-context-sources.ts +253 -0
  112. package/src/agent/agent-context-types.js +2 -0
  113. package/src/agent/agent-context-types.ts +132 -0
  114. package/src/agent/agent-context-validation-sections.js +73 -0
  115. package/src/agent/agent-context-validation-sections.ts +129 -0
  116. package/src/agent/agent-input-injector.js +99 -118
  117. package/src/agent/agent-input-injector.ts +195 -0
  118. package/src/agent/agent-liveness-poll.js +74 -78
  119. package/src/agent/agent-liveness-poll.ts +163 -0
  120. package/src/agent/agent-quality-gate-schema.js +77 -86
  121. package/src/agent/agent-quality-gate-schema.ts +135 -0
  122. package/src/agent/agent-quality-gates-context.js +44 -50
  123. package/src/agent/agent-quality-gates-context.ts +91 -0
  124. package/src/agent/agent-stuck-detector.js +171 -239
  125. package/src/agent/agent-stuck-detector.ts +288 -0
  126. package/src/agent/agent-trigger-evaluator.js +29 -46
  127. package/src/agent/agent-trigger-evaluator.ts +98 -0
  128. package/src/agent/context-metrics.js +110 -141
  129. package/src/agent/context-metrics.ts +261 -0
  130. package/src/agent/context-pack-builder.js +72 -358
  131. package/src/agent/context-pack-builder.ts +105 -0
  132. package/src/agent/context-pack-core.js +70 -0
  133. package/src/agent/context-pack-core.ts +96 -0
  134. package/src/agent/context-pack-selection.js +119 -0
  135. package/src/agent/context-pack-selection.ts +187 -0
  136. package/src/agent/context-pack-truncation.js +139 -0
  137. package/src/agent/context-pack-truncation.ts +208 -0
  138. package/src/agent/context-pack-types.js +2 -0
  139. package/src/agent/context-pack-types.ts +98 -0
  140. package/src/agent/context-replay-policy.js +30 -39
  141. package/src/agent/context-replay-policy.ts +71 -0
  142. package/src/agent/critical-agent-policy.js +6 -10
  143. package/src/agent/critical-agent-policy.ts +20 -0
  144. package/src/agent/guidance-queue.js +74 -87
  145. package/src/agent/guidance-queue.ts +166 -0
  146. package/src/agent/output-extraction-error-detail.js +45 -0
  147. package/src/agent/output-extraction-error-detail.ts +49 -0
  148. package/src/agent/output-extraction-failures.js +125 -0
  149. package/src/agent/output-extraction-failures.ts +149 -0
  150. package/src/agent/output-extraction-json.js +234 -0
  151. package/src/agent/output-extraction-json.ts +235 -0
  152. package/src/agent/output-extraction-pi.js +124 -0
  153. package/src/agent/output-extraction-pi.ts +137 -0
  154. package/src/agent/output-extraction-types.js +2 -0
  155. package/src/agent/output-extraction-types.ts +49 -0
  156. package/src/agent/output-extraction.js +17 -617
  157. package/src/agent/output-extraction.ts +30 -0
  158. package/src/agent/output-reformatter-errors.js +83 -0
  159. package/src/agent/output-reformatter-errors.ts +106 -0
  160. package/src/agent/output-reformatter-types.js +2 -0
  161. package/src/agent/output-reformatter-types.ts +86 -0
  162. package/src/agent/output-reformatter.js +140 -185
  163. package/src/agent/output-reformatter.ts +238 -0
  164. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  165. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  166. package/src/agent/pi-terminal-lifecycle.js +186 -206
  167. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  168. package/src/agent/provider-control-plane.js +22 -21
  169. package/src/agent/provider-control-plane.ts +52 -0
  170. package/src/agent/provider-terminal-failure-types.js +2 -0
  171. package/src/agent/provider-terminal-failure-types.ts +60 -0
  172. package/src/agent/provider-terminal-failure.js +194 -191
  173. package/src/agent/provider-terminal-failure.ts +262 -0
  174. package/src/agent/rate-limit-backoff.js +31 -74
  175. package/src/agent/rate-limit-backoff.ts +71 -0
  176. package/src/agent/schema-utils.js +85 -125
  177. package/src/agent/schema-utils.ts +148 -0
  178. package/src/agent/structured-output-error.js +34 -33
  179. package/src/agent/structured-output-error.ts +105 -0
  180. package/src/agent/validation-platform.js +27 -27
  181. package/src/agent/validation-platform.ts +49 -0
  182. package/src/agents/git-pusher-template.js +17 -34
  183. package/src/attach/attach-client.js +232 -405
  184. package/src/attach/attach-client.ts +300 -0
  185. package/src/attach/attach-server-cleanup.js +43 -0
  186. package/src/attach/attach-server-cleanup.ts +39 -0
  187. package/src/attach/attach-server-clients.js +117 -0
  188. package/src/attach/attach-server-clients.ts +122 -0
  189. package/src/attach/attach-server-events.js +38 -0
  190. package/src/attach/attach-server-events.ts +36 -0
  191. package/src/attach/attach-server-pty.js +45 -0
  192. package/src/attach/attach-server-pty.ts +64 -0
  193. package/src/attach/attach-server-runtime.js +73 -0
  194. package/src/attach/attach-server-runtime.ts +62 -0
  195. package/src/attach/attach-server-socket.js +28 -0
  196. package/src/attach/attach-server-socket.ts +23 -0
  197. package/src/attach/attach-server-types.js +2 -0
  198. package/src/attach/attach-server-types.ts +82 -0
  199. package/src/attach/attach-server.js +106 -523
  200. package/src/attach/attach-server.ts +158 -0
  201. package/src/attach/index.js +18 -35
  202. package/src/attach/index.ts +18 -0
  203. package/src/attach/protocol.js +95 -184
  204. package/src/attach/protocol.ts +181 -0
  205. package/src/attach/ring-buffer.js +76 -102
  206. package/src/attach/ring-buffer.ts +109 -0
  207. package/src/attach/send-input.js +64 -75
  208. package/src/attach/send-input.ts +94 -0
  209. package/src/attach/socket-discovery.js +164 -218
  210. package/src/attach/socket-discovery.ts +230 -0
  211. package/src/attach/socket-paths.js +42 -61
  212. package/src/attach/socket-paths.ts +81 -0
  213. package/src/claude-credentials.js +51 -54
  214. package/src/claude-credentials.ts +89 -0
  215. package/src/cluster/generated/protocol-schema.ts +1 -1
  216. package/src/cluster/generated/protocol.ts +2 -1
  217. package/src/command-proofs.js +110 -141
  218. package/src/command-proofs.ts +216 -0
  219. package/src/config-router.js +81 -73
  220. package/src/config-router.ts +131 -0
  221. package/src/copy-containment.js +191 -0
  222. package/src/copy-containment.ts +259 -0
  223. package/src/copy-worker.js +53 -30
  224. package/src/copy-worker.ts +88 -0
  225. package/src/darwin-keychain-boundary.js +80 -111
  226. package/src/darwin-keychain-boundary.ts +148 -0
  227. package/src/guidance-topics.js +4 -5
  228. package/src/guidance-topics.ts +10 -0
  229. package/src/input-helpers.js +33 -54
  230. package/src/input-helpers.ts +58 -0
  231. package/src/isolation-manager.js +59 -20
  232. package/src/ledger-sequence.js +45 -48
  233. package/src/ledger-sequence.ts +63 -0
  234. package/src/legacy-lib/clusters-registry.ts +40 -0
  235. package/src/legacy-lib/completion.ts +148 -0
  236. package/src/legacy-lib/compose-utils.ts +102 -0
  237. package/src/legacy-lib/detached-startup.ts +451 -0
  238. package/src/legacy-lib/docker-config.ts +282 -0
  239. package/src/legacy-lib/docker-env-auth.ts +116 -0
  240. package/src/legacy-lib/git-remote-utils.ts +244 -0
  241. package/src/legacy-lib/id-detector.ts +57 -0
  242. package/src/legacy-lib/js-yaml.d.ts +3 -0
  243. package/src/legacy-lib/omelette.d.ts +15 -0
  244. package/src/legacy-lib/path-check.ts +89 -0
  245. package/src/legacy-lib/process-liveness.ts +36 -0
  246. package/src/legacy-lib/provider-credential-path.ts +57 -0
  247. package/src/legacy-lib/provider-defaults.ts +114 -0
  248. package/src/legacy-lib/provider-detection.ts +67 -0
  249. package/src/legacy-lib/provider-names.ts +126 -0
  250. package/src/legacy-lib/repo-settings.ts +88 -0
  251. package/src/legacy-lib/run-mode.ts +58 -0
  252. package/src/legacy-lib/run-plan.ts +49 -0
  253. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  254. package/src/legacy-lib/settings-defaults.ts +212 -0
  255. package/src/legacy-lib/settings-error.ts +8 -0
  256. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  257. package/src/legacy-lib/settings-models.ts +124 -0
  258. package/src/legacy-lib/settings-storage.ts +277 -0
  259. package/src/legacy-lib/settings-validation.ts +220 -0
  260. package/src/legacy-lib/settings.ts +87 -0
  261. package/src/legacy-lib/setup-apply-types.ts +70 -0
  262. package/src/legacy-lib/setup-apply.ts +456 -0
  263. package/src/legacy-lib/setup-journal.ts +185 -0
  264. package/src/legacy-lib/setup-plan-types.ts +96 -0
  265. package/src/legacy-lib/setup-plan.ts +500 -0
  266. package/src/legacy-lib/setup-undo.ts +142 -0
  267. package/src/legacy-lib/start-cluster-config.ts +124 -0
  268. package/src/legacy-lib/start-cluster-environment.ts +166 -0
  269. package/src/legacy-lib/start-cluster-run-options.ts +281 -0
  270. package/src/legacy-lib/start-cluster.ts +237 -0
  271. package/src/legacy-lib/stream-json-parser.ts +88 -0
  272. package/src/message-buffer.js +55 -71
  273. package/src/message-buffer.ts +107 -0
  274. package/src/message-bus-bridge.js +92 -133
  275. package/src/message-bus-bridge.ts +149 -0
  276. package/src/name-generator-shared.js +220 -0
  277. package/src/name-generator-shared.ts +231 -0
  278. package/src/name-generator.js +8 -217
  279. package/src/name-generator.ts +27 -0
  280. package/src/omp-blob-root.js +83 -64
  281. package/src/omp-blob-root.ts +116 -0
  282. package/src/omp-config-overlay.js +65 -38
  283. package/src/omp-config-overlay.ts +110 -0
  284. package/src/omp-execution-fingerprint.js +38 -43
  285. package/src/omp-execution-fingerprint.ts +92 -0
  286. package/src/omp-session-limits.js +10 -15
  287. package/src/omp-session-limits.ts +53 -0
  288. package/src/omp-session-partition.js +2 -2
  289. package/src/omp-session-verifier.js +1 -1
  290. package/src/orchestrator.js +32 -7
  291. package/src/pr-body-template.js +71 -0
  292. package/src/providers/anthropic/index.js +3 -1
  293. package/src/providers/anthropic/index.ts +13 -0
  294. package/src/providers/capabilities.js +19 -27
  295. package/src/providers/capabilities.ts +44 -0
  296. package/src/providers/google/index.js +3 -1
  297. package/src/providers/google/index.ts +13 -0
  298. package/src/providers/openai/index.js +3 -1
  299. package/src/providers/openai/index.ts +13 -0
  300. package/src/providers/opencode/index.js +3 -1
  301. package/src/providers/opencode/index.ts +13 -0
  302. package/src/quality-gates.js +67 -127
  303. package/src/quality-gates.ts +149 -0
  304. package/src/repo-settings-access.js +40 -0
  305. package/src/repo-settings-access.ts +64 -0
  306. package/src/schemas/sub-cluster.js +127 -183
  307. package/src/schemas/sub-cluster.ts +238 -0
  308. package/src/state-snapshot-normalization.js +224 -0
  309. package/src/state-snapshot-normalization.ts +222 -0
  310. package/src/state-snapshot.js +192 -359
  311. package/src/state-snapshot.ts +291 -0
  312. package/src/state-snapshotter.js +118 -130
  313. package/src/state-snapshotter.ts +167 -0
  314. package/src/sub-cluster-wrapper.js +4 -13
  315. package/src/task-run-model-args.js +87 -124
  316. package/src/task-run-model-args.ts +204 -0
  317. package/src/task-runner.js +5 -25
  318. package/src/task-runner.ts +28 -0
  319. package/src/task-startup-error.js +73 -58
  320. package/src/task-startup-error.ts +126 -0
  321. package/src/template-validation/consensus-gate-contracts.js +2 -0
  322. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  323. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  324. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  325. package/src/template-validation/consensus-gate-stage.js +34 -0
  326. package/src/template-validation/consensus-gate-stage.ts +56 -0
  327. package/src/template-validation/random-topology-contracts.js +2 -0
  328. package/src/template-validation/random-topology-contracts.ts +54 -0
  329. package/src/template-validation/random-topology-dispatch.js +25 -0
  330. package/src/template-validation/random-topology-dispatch.ts +33 -0
  331. package/src/template-validation/random-topology-message-loop.js +53 -0
  332. package/src/template-validation/random-topology-message-loop.ts +73 -0
  333. package/src/template-validation/random-topology-operations.js +79 -0
  334. package/src/template-validation/random-topology-operations.ts +101 -0
  335. package/src/template-validation/random-topology-runtime.js +25 -0
  336. package/src/template-validation/random-topology-runtime.ts +43 -0
  337. package/src/template-validation/random-topology-scenario.js +52 -0
  338. package/src/template-validation/random-topology-scenario.ts +57 -0
  339. package/src/template-validation/random-topology-schema.js +159 -0
  340. package/src/template-validation/random-topology-schema.ts +190 -0
  341. package/src/template-validation/random-topology-state.js +28 -0
  342. package/src/template-validation/random-topology-state.ts +30 -0
  343. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  344. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  345. package/src/template-validation/random-topology-trigger.js +75 -0
  346. package/src/template-validation/random-topology-trigger.ts +88 -0
  347. package/src/template-validation/report-formatter.js +40 -46
  348. package/src/template-validation/report-formatter.ts +101 -0
  349. package/src/template-validation/simulate-consensus-gates.js +111 -302
  350. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  351. package/src/template-validation/simulate-random-topology.js +26 -519
  352. package/src/template-validation/simulate-random-topology.ts +57 -0
  353. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  354. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  355. package/src/template-validation/simulation-agent-runtime.js +25 -0
  356. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  357. package/src/template-validation/simulation-agent.js +29 -0
  358. package/src/template-validation/simulation-agent.ts +73 -0
  359. package/src/template-validation/simulation-runtime.js +34 -0
  360. package/src/template-validation/simulation-runtime.ts +72 -0
  361. package/src/template-validation/two-stage-contracts.js +2 -0
  362. package/src/template-validation/two-stage-contracts.ts +41 -0
  363. package/src/template-validation/two-stage-inputs.js +21 -0
  364. package/src/template-validation/two-stage-inputs.ts +29 -0
  365. package/src/template-validation/two-stage-results.js +30 -0
  366. package/src/template-validation/two-stage-results.ts +40 -0
  367. package/src/template-validation/two-stage-scenario.js +86 -0
  368. package/src/template-validation/two-stage-scenario.ts +120 -0
  369. package/src/worktree-claude-config.js +182 -220
  370. package/src/worktree-claude-config.ts +272 -0
  371. package/src/worktree-tooling-env.js +103 -125
  372. package/src/worktree-tooling-env.ts +142 -0
  373. package/task-lib/completion.js +2 -3
  374. package/task-lib/completion.ts +9 -0
  375. package/task-lib/config.js +1 -4
  376. package/task-lib/config.ts +11 -0
  377. package/task-lib/name-generator.js +4 -226
  378. package/task-lib/name-generator.ts +11 -0
  379. package/task-lib/omp-session-cleanup.js +1 -1
  380. package/task-lib/omp-storage-root.js +8 -12
  381. package/task-lib/omp-storage-root.ts +62 -0
  382. package/task-lib/process-termination.js +143 -166
  383. package/task-lib/process-termination.ts +268 -0
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Config Router - Maps 2D classification to parameterized templates
3
+ *
4
+ * Single source of truth for: Complexity × TaskType → { base, params }
5
+ * Used by both logic-engine.js (trigger evaluation) and agent-wrapper.js (transform scripts)
6
+ */
7
+
8
+ interface AgentConfigModule {
9
+ DEFAULT_MAX_ITERATIONS: number;
10
+ }
11
+
12
+ function isAgentConfigModule(value: unknown): value is AgentConfigModule {
13
+ return (
14
+ typeof value === 'object' &&
15
+ value !== null &&
16
+ 'DEFAULT_MAX_ITERATIONS' in value &&
17
+ typeof value.DEFAULT_MAX_ITERATIONS === 'number'
18
+ );
19
+ }
20
+
21
+ const agentConfig: unknown = require('./agent/agent-config');
22
+ if (!isAgentConfigModule(agentConfig)) {
23
+ throw new TypeError('agent-config must export a numeric DEFAULT_MAX_ITERATIONS');
24
+ }
25
+ const { DEFAULT_MAX_ITERATIONS } = agentConfig;
26
+
27
+ type BaseConfigName = 'debug-workflow' | 'full-workflow' | 'single-worker' | 'worker-validator';
28
+ type ModelLevel = 'level1' | 'level2' | 'level3';
29
+
30
+ interface ConfigOptions {
31
+ autoPr?: boolean;
32
+ }
33
+
34
+ interface ConfigParams {
35
+ task_type: string;
36
+ complexity: string;
37
+ max_tokens: number;
38
+ max_iterations: number;
39
+ worker_level?: ModelLevel;
40
+ validator_level?: ModelLevel;
41
+ investigator_level?: ModelLevel;
42
+ fixer_level?: ModelLevel;
43
+ tester_level?: ModelLevel;
44
+ planner_level?: ModelLevel;
45
+ validator_count?: number;
46
+ }
47
+
48
+ interface RoutedConfig {
49
+ base: BaseConfigName;
50
+ params: ConfigParams;
51
+ }
52
+
53
+ /**
54
+ * Get cluster config based on complexity and task type
55
+ */
56
+ function getConfig(
57
+ complexity: string,
58
+ taskType: string,
59
+ options: ConfigOptions = {}
60
+ ): RoutedConfig {
61
+ const isPrMode = options.autoPr === true || process.env.ZEROSHOT_PR === '1';
62
+
63
+ const getBase = (): BaseConfigName => {
64
+ if (taskType === 'DEBUG' && complexity !== 'TRIVIAL') {
65
+ return 'debug-workflow';
66
+ }
67
+ if (complexity === 'TRIVIAL' && isPrMode && taskType !== 'INQUIRY') {
68
+ return 'worker-validator';
69
+ }
70
+ if (complexity === 'TRIVIAL') {
71
+ return 'single-worker';
72
+ }
73
+ if (complexity === 'SIMPLE') {
74
+ return 'worker-validator';
75
+ }
76
+ return 'full-workflow';
77
+ };
78
+
79
+ const getLevel = (role: string): ModelLevel => {
80
+ if (complexity === 'CRITICAL' && role === 'planner') return 'level3';
81
+ if (complexity === 'TRIVIAL') return 'level1';
82
+ return 'level2';
83
+ };
84
+
85
+ const getValidatorCount = (): number => {
86
+ if (complexity === 'TRIVIAL') return 0;
87
+ if (complexity === 'SIMPLE') return 1;
88
+ if (complexity === 'STANDARD') return 2;
89
+ // CRITICAL uses two-stage validation pipeline (validators loaded dynamically via meta-coordinator)
90
+ // Setting validator_count=0 signals that inline validators should be skipped
91
+ if (complexity === 'CRITICAL') return 0;
92
+ return 1;
93
+ };
94
+
95
+ const getMaxTokens = (): number => {
96
+ if (complexity === 'TRIVIAL') return 50000;
97
+ if (complexity === 'SIMPLE') return 100000;
98
+ if (complexity === 'STANDARD') return 100000;
99
+ if (complexity === 'CRITICAL') return 150000;
100
+ return 100000;
101
+ };
102
+
103
+ const base = getBase();
104
+
105
+ const params: ConfigParams = {
106
+ task_type: taskType,
107
+ complexity,
108
+ max_tokens: getMaxTokens(),
109
+ max_iterations: DEFAULT_MAX_ITERATIONS,
110
+ };
111
+
112
+ if (base === 'single-worker') {
113
+ params.worker_level = getLevel('worker');
114
+ } else if (base === 'worker-validator') {
115
+ params.worker_level = getLevel('worker');
116
+ params.validator_level = getLevel('validator');
117
+ } else if (base === 'debug-workflow') {
118
+ params.investigator_level = getLevel('planner');
119
+ params.fixer_level = getLevel('worker');
120
+ params.tester_level = getLevel('validator');
121
+ } else if (base === 'full-workflow') {
122
+ params.planner_level = getLevel('planner');
123
+ params.worker_level = getLevel('worker');
124
+ params.validator_level = getLevel('validator');
125
+ params.validator_count = getValidatorCount();
126
+ }
127
+
128
+ return { base, params };
129
+ }
130
+
131
+ export = { getConfig };
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CopyContainmentError = exports.CONTAINMENT_ERROR_CODE = void 0;
4
+ exports.isCopyRecord = isCopyRecord;
5
+ exports.copyErrorCode = copyErrorCode;
6
+ exports.validateRelativePath = validateRelativePath;
7
+ exports.resolveSourcePath = resolveSourcePath;
8
+ exports.createCopyBoundary = createCopyBoundary;
9
+ exports.resolveCopyPath = resolveCopyPath;
10
+ exports.isCopyContainmentError = isCopyContainmentError;
11
+ exports.copyErrorFromPayload = copyErrorFromPayload;
12
+ const fs = require("fs");
13
+ const path = require("path");
14
+ exports.CONTAINMENT_ERROR_CODE = 'ERR_COPY_CONTAINMENT';
15
+ class CopyContainmentError extends Error {
16
+ code = exports.CONTAINMENT_ERROR_CODE;
17
+ relativePath;
18
+ constructor(relativePath, reason) {
19
+ super(`Copy containment violation for ${JSON.stringify(relativePath)}: ${reason}`);
20
+ this.name = 'CopyContainmentError';
21
+ this.relativePath = relativePath;
22
+ }
23
+ }
24
+ exports.CopyContainmentError = CopyContainmentError;
25
+ function isContained(rootPath, targetPath) {
26
+ const relative = path.relative(rootPath, targetPath);
27
+ return (relative === '' ||
28
+ (!path.isAbsolute(relative) && relative !== '..' && !relative.startsWith(`..${path.sep}`)));
29
+ }
30
+ function containmentError(relativePath, reason, cause) {
31
+ const error = new CopyContainmentError(relativePath, reason);
32
+ if (cause !== undefined) {
33
+ error.cause = cause;
34
+ }
35
+ return error;
36
+ }
37
+ function isCopyRecord(value) {
38
+ return typeof value === 'object' && value !== null;
39
+ }
40
+ function copyErrorCode(error) {
41
+ if (isCopyRecord(error) && 'code' in error) {
42
+ return typeof error.code === 'string' ? error.code : null;
43
+ }
44
+ return null;
45
+ }
46
+ function statIdentity(targetPath) {
47
+ const stats = fs.statSync(targetPath, { bigint: true });
48
+ return {
49
+ device: stats.dev.toString(),
50
+ inode: stats.ino.toString(),
51
+ directory: stats.isDirectory(),
52
+ };
53
+ }
54
+ function pinRoot(rootPath, label, expectedRoot) {
55
+ const requestedPath = path.resolve(rootPath);
56
+ const canonicalPath = fs.realpathSync.native(requestedPath);
57
+ const identity = statIdentity(canonicalPath);
58
+ if (!identity.directory) {
59
+ throw containmentError('', `${label} root is not a directory`);
60
+ }
61
+ const pinnedRoot = {
62
+ requestedPath,
63
+ canonicalPath,
64
+ device: identity.device,
65
+ inode: identity.inode,
66
+ };
67
+ if (expectedRoot &&
68
+ (expectedRoot.canonicalPath !== pinnedRoot.canonicalPath ||
69
+ expectedRoot.device !== pinnedRoot.device ||
70
+ expectedRoot.inode !== pinnedRoot.inode)) {
71
+ throw containmentError('', `${label} root changed after it was pinned`);
72
+ }
73
+ return pinnedRoot;
74
+ }
75
+ function assertPinnedRoot(root, label, relativePath) {
76
+ let identity;
77
+ try {
78
+ identity = statIdentity(root.canonicalPath);
79
+ }
80
+ catch (error) {
81
+ throw containmentError(relativePath, `${label} root can no longer be resolved`, error);
82
+ }
83
+ if (identity.device !== root.device || identity.inode !== root.inode || !identity.directory) {
84
+ throw containmentError(relativePath, `${label} root changed after it was pinned`);
85
+ }
86
+ }
87
+ function validateRelativePath(relativePath, pathApi = path) {
88
+ if (typeof relativePath !== 'string' || relativePath.length === 0) {
89
+ throw containmentError(relativePath, 'path must be a non-empty relative string');
90
+ }
91
+ if (relativePath.includes('\0')) {
92
+ throw containmentError(relativePath, 'path contains a null byte');
93
+ }
94
+ if (pathApi.isAbsolute(relativePath) || pathApi.parse(relativePath).root) {
95
+ throw containmentError(relativePath, 'absolute paths are not allowed');
96
+ }
97
+ const components = pathApi.sep === '\\' ? relativePath.split(/[\\/]/) : relativePath.split(pathApi.sep);
98
+ if (components.some((component) => component === '' || component === '.' || component === '..')) {
99
+ throw containmentError(relativePath, 'empty, current-directory, and traversal components are not allowed');
100
+ }
101
+ return pathApi.normalize(relativePath);
102
+ }
103
+ function resolveSourcePath(boundary, relativePath) {
104
+ const normalizedPath = validateRelativePath(relativePath);
105
+ const root = boundary.sourceRoot;
106
+ assertPinnedRoot(root, 'source', relativePath);
107
+ const candidatePath = path.resolve(root.canonicalPath, normalizedPath);
108
+ if (!isContained(root.canonicalPath, candidatePath)) {
109
+ throw containmentError(relativePath, 'source path escapes its pinned root');
110
+ }
111
+ let canonicalPath;
112
+ try {
113
+ canonicalPath = fs.realpathSync.native(candidatePath);
114
+ }
115
+ catch (error) {
116
+ if (copyErrorCode(error) === 'ELOOP') {
117
+ throw containmentError(relativePath, 'source path contains a symlink cycle', error);
118
+ }
119
+ throw error;
120
+ }
121
+ if (!isContained(root.canonicalPath, canonicalPath)) {
122
+ throw containmentError(relativePath, 'resolved source path escapes its pinned root');
123
+ }
124
+ return canonicalPath;
125
+ }
126
+ function resolveDestinationPath(boundary, relativePath) {
127
+ const normalizedPath = validateRelativePath(relativePath);
128
+ const root = boundary.destinationRoot;
129
+ assertPinnedRoot(root, 'destination', relativePath);
130
+ const candidatePath = path.resolve(root.canonicalPath, normalizedPath);
131
+ if (!isContained(root.canonicalPath, candidatePath)) {
132
+ throw containmentError(relativePath, 'destination path escapes its pinned root');
133
+ }
134
+ let existingPath;
135
+ try {
136
+ fs.lstatSync(candidatePath);
137
+ existingPath = candidatePath;
138
+ }
139
+ catch (error) {
140
+ if (copyErrorCode(error) !== 'ENOENT') {
141
+ throw error;
142
+ }
143
+ // The copy pipeline creates directories parent-first in phase two, so the
144
+ // immediate parent must exist before any mkdir/copy effect is attempted.
145
+ existingPath = path.dirname(candidatePath);
146
+ }
147
+ let canonicalExistingPath;
148
+ try {
149
+ canonicalExistingPath = fs.realpathSync.native(existingPath);
150
+ }
151
+ catch (error) {
152
+ throw containmentError(relativePath, 'destination contains an unresolved symlink', error);
153
+ }
154
+ if (!isContained(root.canonicalPath, canonicalExistingPath)) {
155
+ throw containmentError(relativePath, 'resolved destination path escapes its pinned root');
156
+ }
157
+ const unresolvedSuffix = path.relative(existingPath, candidatePath);
158
+ const resolvedPath = unresolvedSuffix
159
+ ? path.join(canonicalExistingPath, unresolvedSuffix)
160
+ : canonicalExistingPath;
161
+ if (!isContained(root.canonicalPath, resolvedPath)) {
162
+ throw containmentError(relativePath, 'resolved destination path escapes its pinned root');
163
+ }
164
+ return resolvedPath;
165
+ }
166
+ function createCopyBoundary(sourceBase, destinationBase, expectedBoundary) {
167
+ return {
168
+ sourceRoot: pinRoot(sourceBase, 'source', expectedBoundary?.sourceRoot),
169
+ destinationRoot: pinRoot(destinationBase, 'destination', expectedBoundary?.destinationRoot),
170
+ };
171
+ }
172
+ function resolveCopyPath(boundary, relativePath) {
173
+ return {
174
+ sourcePath: resolveSourcePath(boundary, relativePath),
175
+ destinationPath: resolveDestinationPath(boundary, relativePath),
176
+ };
177
+ }
178
+ function isCopyContainmentError(error) {
179
+ return isCopyRecord(error) && error.code === exports.CONTAINMENT_ERROR_CODE;
180
+ }
181
+ function copyErrorFromPayload(payload) {
182
+ const error = payload.code === exports.CONTAINMENT_ERROR_CODE
183
+ ? new CopyContainmentError(payload.relativePath, 'worker rejected an unsafe path')
184
+ : new Error(payload.message);
185
+ error.name = payload.name || error.name;
186
+ error.message = payload.message;
187
+ if (payload.code && !(error instanceof CopyContainmentError)) {
188
+ Object.assign(error, { code: payload.code });
189
+ }
190
+ return error;
191
+ }
@@ -0,0 +1,259 @@
1
+ import fs = require('fs');
2
+ import path = require('path');
3
+
4
+ export const CONTAINMENT_ERROR_CODE = 'ERR_COPY_CONTAINMENT';
5
+
6
+ export interface PinnedCopyRoot {
7
+ requestedPath: string;
8
+ canonicalPath: string;
9
+ device: string;
10
+ inode: string;
11
+ }
12
+
13
+ export interface CopyBoundary {
14
+ sourceRoot: PinnedCopyRoot;
15
+ destinationRoot: PinnedCopyRoot;
16
+ }
17
+
18
+ interface PathIdentity {
19
+ device: string;
20
+ inode: string;
21
+ directory: boolean;
22
+ }
23
+
24
+ interface CopyPathApi {
25
+ isAbsolute(targetPath: string): boolean;
26
+ normalize(targetPath: string): string;
27
+ parse(targetPath: string): { root: string };
28
+ readonly sep: string;
29
+ }
30
+
31
+ export class CopyContainmentError extends Error {
32
+ readonly code = CONTAINMENT_ERROR_CODE;
33
+ readonly relativePath: unknown;
34
+
35
+ constructor(relativePath: unknown, reason: string) {
36
+ super(`Copy containment violation for ${JSON.stringify(relativePath)}: ${reason}`);
37
+ this.name = 'CopyContainmentError';
38
+ this.relativePath = relativePath;
39
+ }
40
+ }
41
+
42
+ function isContained(rootPath: string, targetPath: string): boolean {
43
+ const relative = path.relative(rootPath, targetPath);
44
+ return (
45
+ relative === '' ||
46
+ (!path.isAbsolute(relative) && relative !== '..' && !relative.startsWith(`..${path.sep}`))
47
+ );
48
+ }
49
+
50
+ function containmentError(
51
+ relativePath: unknown,
52
+ reason: string,
53
+ cause?: unknown
54
+ ): CopyContainmentError {
55
+ const error = new CopyContainmentError(relativePath, reason);
56
+ if (cause !== undefined) {
57
+ error.cause = cause;
58
+ }
59
+ return error;
60
+ }
61
+
62
+ export function isCopyRecord(value: unknown): value is Record<PropertyKey, unknown> {
63
+ return typeof value === 'object' && value !== null;
64
+ }
65
+
66
+ export function copyErrorCode(error: unknown): string | null {
67
+ if (isCopyRecord(error) && 'code' in error) {
68
+ return typeof error.code === 'string' ? error.code : null;
69
+ }
70
+ return null;
71
+ }
72
+
73
+ function statIdentity(targetPath: string): PathIdentity {
74
+ const stats = fs.statSync(targetPath, { bigint: true });
75
+ return {
76
+ device: stats.dev.toString(),
77
+ inode: stats.ino.toString(),
78
+ directory: stats.isDirectory(),
79
+ };
80
+ }
81
+
82
+ function pinRoot(rootPath: string, label: string, expectedRoot?: PinnedCopyRoot): PinnedCopyRoot {
83
+ const requestedPath = path.resolve(rootPath);
84
+ const canonicalPath = fs.realpathSync.native(requestedPath);
85
+ const identity = statIdentity(canonicalPath);
86
+
87
+ if (!identity.directory) {
88
+ throw containmentError('', `${label} root is not a directory`);
89
+ }
90
+
91
+ const pinnedRoot = {
92
+ requestedPath,
93
+ canonicalPath,
94
+ device: identity.device,
95
+ inode: identity.inode,
96
+ };
97
+
98
+ if (
99
+ expectedRoot &&
100
+ (expectedRoot.canonicalPath !== pinnedRoot.canonicalPath ||
101
+ expectedRoot.device !== pinnedRoot.device ||
102
+ expectedRoot.inode !== pinnedRoot.inode)
103
+ ) {
104
+ throw containmentError('', `${label} root changed after it was pinned`);
105
+ }
106
+
107
+ return pinnedRoot;
108
+ }
109
+
110
+ function assertPinnedRoot(root: PinnedCopyRoot, label: string, relativePath: string): void {
111
+ let identity: PathIdentity;
112
+ try {
113
+ identity = statIdentity(root.canonicalPath);
114
+ } catch (error: unknown) {
115
+ throw containmentError(relativePath, `${label} root can no longer be resolved`, error);
116
+ }
117
+
118
+ if (identity.device !== root.device || identity.inode !== root.inode || !identity.directory) {
119
+ throw containmentError(relativePath, `${label} root changed after it was pinned`);
120
+ }
121
+ }
122
+
123
+ export function validateRelativePath(relativePath: unknown, pathApi: CopyPathApi = path): string {
124
+ if (typeof relativePath !== 'string' || relativePath.length === 0) {
125
+ throw containmentError(relativePath, 'path must be a non-empty relative string');
126
+ }
127
+ if (relativePath.includes('\0')) {
128
+ throw containmentError(relativePath, 'path contains a null byte');
129
+ }
130
+ if (pathApi.isAbsolute(relativePath) || pathApi.parse(relativePath).root) {
131
+ throw containmentError(relativePath, 'absolute paths are not allowed');
132
+ }
133
+
134
+ const components =
135
+ pathApi.sep === '\\' ? relativePath.split(/[\\/]/) : relativePath.split(pathApi.sep);
136
+ if (components.some((component) => component === '' || component === '.' || component === '..')) {
137
+ throw containmentError(
138
+ relativePath,
139
+ 'empty, current-directory, and traversal components are not allowed'
140
+ );
141
+ }
142
+
143
+ return pathApi.normalize(relativePath);
144
+ }
145
+
146
+ export function resolveSourcePath(boundary: CopyBoundary, relativePath: string): string {
147
+ const normalizedPath = validateRelativePath(relativePath);
148
+ const root = boundary.sourceRoot;
149
+ assertPinnedRoot(root, 'source', relativePath);
150
+
151
+ const candidatePath = path.resolve(root.canonicalPath, normalizedPath);
152
+ if (!isContained(root.canonicalPath, candidatePath)) {
153
+ throw containmentError(relativePath, 'source path escapes its pinned root');
154
+ }
155
+
156
+ let canonicalPath: string;
157
+ try {
158
+ canonicalPath = fs.realpathSync.native(candidatePath);
159
+ } catch (error: unknown) {
160
+ if (copyErrorCode(error) === 'ELOOP') {
161
+ throw containmentError(relativePath, 'source path contains a symlink cycle', error);
162
+ }
163
+ throw error;
164
+ }
165
+
166
+ if (!isContained(root.canonicalPath, canonicalPath)) {
167
+ throw containmentError(relativePath, 'resolved source path escapes its pinned root');
168
+ }
169
+ return canonicalPath;
170
+ }
171
+
172
+ function resolveDestinationPath(boundary: CopyBoundary, relativePath: string): string {
173
+ const normalizedPath = validateRelativePath(relativePath);
174
+ const root = boundary.destinationRoot;
175
+ assertPinnedRoot(root, 'destination', relativePath);
176
+
177
+ const candidatePath = path.resolve(root.canonicalPath, normalizedPath);
178
+ if (!isContained(root.canonicalPath, candidatePath)) {
179
+ throw containmentError(relativePath, 'destination path escapes its pinned root');
180
+ }
181
+
182
+ let existingPath: string;
183
+ try {
184
+ fs.lstatSync(candidatePath);
185
+ existingPath = candidatePath;
186
+ } catch (error: unknown) {
187
+ if (copyErrorCode(error) !== 'ENOENT') {
188
+ throw error;
189
+ }
190
+ // The copy pipeline creates directories parent-first in phase two, so the
191
+ // immediate parent must exist before any mkdir/copy effect is attempted.
192
+ existingPath = path.dirname(candidatePath);
193
+ }
194
+
195
+ let canonicalExistingPath: string;
196
+ try {
197
+ canonicalExistingPath = fs.realpathSync.native(existingPath);
198
+ } catch (error: unknown) {
199
+ throw containmentError(relativePath, 'destination contains an unresolved symlink', error);
200
+ }
201
+
202
+ if (!isContained(root.canonicalPath, canonicalExistingPath)) {
203
+ throw containmentError(relativePath, 'resolved destination path escapes its pinned root');
204
+ }
205
+
206
+ const unresolvedSuffix = path.relative(existingPath, candidatePath);
207
+ const resolvedPath = unresolvedSuffix
208
+ ? path.join(canonicalExistingPath, unresolvedSuffix)
209
+ : canonicalExistingPath;
210
+ if (!isContained(root.canonicalPath, resolvedPath)) {
211
+ throw containmentError(relativePath, 'resolved destination path escapes its pinned root');
212
+ }
213
+ return resolvedPath;
214
+ }
215
+
216
+ export function createCopyBoundary(
217
+ sourceBase: string,
218
+ destinationBase: string,
219
+ expectedBoundary?: CopyBoundary
220
+ ): CopyBoundary {
221
+ return {
222
+ sourceRoot: pinRoot(sourceBase, 'source', expectedBoundary?.sourceRoot),
223
+ destinationRoot: pinRoot(destinationBase, 'destination', expectedBoundary?.destinationRoot),
224
+ };
225
+ }
226
+
227
+ export function resolveCopyPath(
228
+ boundary: CopyBoundary,
229
+ relativePath: string
230
+ ): { sourcePath: string; destinationPath: string } {
231
+ return {
232
+ sourcePath: resolveSourcePath(boundary, relativePath),
233
+ destinationPath: resolveDestinationPath(boundary, relativePath),
234
+ };
235
+ }
236
+
237
+ export function isCopyContainmentError(error: unknown): boolean {
238
+ return isCopyRecord(error) && error.code === CONTAINMENT_ERROR_CODE;
239
+ }
240
+
241
+ interface CopyErrorPayload {
242
+ code?: string | null;
243
+ relativePath?: unknown;
244
+ name?: string;
245
+ message: string;
246
+ }
247
+
248
+ export function copyErrorFromPayload(payload: CopyErrorPayload): Error {
249
+ const error =
250
+ payload.code === CONTAINMENT_ERROR_CODE
251
+ ? new CopyContainmentError(payload.relativePath, 'worker rejected an unsafe path')
252
+ : new Error(payload.message);
253
+ error.name = payload.name || error.name;
254
+ error.message = payload.message;
255
+ if (payload.code && !(error instanceof CopyContainmentError)) {
256
+ Object.assign(error, { code: payload.code });
257
+ }
258
+ return error;
259
+ }
@@ -1,43 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
1
3
  /**
2
4
  * Copy Worker - Worker thread for parallel file copying
3
5
  *
4
6
  * Handles copying a batch of files from source to destination.
5
7
  * Used by IsolationManager._copyDirExcluding() for parallel copying.
6
8
  */
7
-
8
- const { parentPort, workerData } = require('worker_threads');
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
- const { files, sourceBase, destBase } = workerData;
13
-
9
+ const fs = require("fs");
10
+ const worker_threads_1 = require("worker_threads");
11
+ const copy_containment_1 = require("./copy-containment");
12
+ function isCopyWorkerData(value) {
13
+ if (!(0, copy_containment_1.isCopyRecord)(value)) {
14
+ return false;
15
+ }
16
+ return (Array.isArray(value.files) &&
17
+ value.files.every((entry) => typeof entry === 'string') &&
18
+ typeof value.sourceBase === 'string' &&
19
+ typeof value.destBase === 'string' &&
20
+ (0, copy_containment_1.isCopyRecord)(value.expectedBoundary));
21
+ }
22
+ function errorMessage(error) {
23
+ return error instanceof Error ? error.message : String(error);
24
+ }
25
+ const rawWorkerData = worker_threads_1.workerData;
26
+ if (!isCopyWorkerData(rawWorkerData)) {
27
+ throw new TypeError('copy worker requires files, sourceBase, and destBase');
28
+ }
29
+ const { files, sourceBase, destBase, expectedBoundary } = rawWorkerData;
30
+ const copyBoundary = (0, copy_containment_1.createCopyBoundary)(sourceBase, destBase, expectedBoundary);
14
31
  let copied = 0;
15
32
  let skipped = 0;
16
- const errors = [];
17
-
33
+ let error = null;
18
34
  for (const relativePath of files) {
19
- const srcPath = path.join(sourceBase, relativePath);
20
- const destPath = path.join(destBase, relativePath);
21
-
22
- try {
23
- // Ensure parent directory exists
24
- const destDir = path.dirname(destPath);
25
- if (!fs.existsSync(destDir)) {
26
- fs.mkdirSync(destDir, { recursive: true });
35
+ try {
36
+ // Phase two creates every parent directory. Re-resolve the source and
37
+ // destination immediately before the only worker filesystem effect.
38
+ const { sourcePath, destinationPath } = (0, copy_containment_1.resolveCopyPath)(copyBoundary, relativePath);
39
+ fs.copyFileSync(sourcePath, destinationPath);
40
+ copied++;
27
41
  }
28
-
29
- // Copy the file
30
- fs.copyFileSync(srcPath, destPath);
31
- copied++;
32
- } catch (err) {
33
- // Skip files we can't copy (permission denied, broken symlinks, etc.)
34
- if (err.code === 'EACCES' || err.code === 'EPERM' || err.code === 'ENOENT') {
35
- skipped++;
36
- continue;
42
+ catch (caughtError) {
43
+ // Skip files we can't copy (permission denied, broken symlinks, etc.)
44
+ const code = (0, copy_containment_1.copyErrorCode)(caughtError);
45
+ if (!(0, copy_containment_1.isCopyContainmentError)(caughtError) &&
46
+ (code === 'EACCES' || code === 'EPERM' || code === 'ENOENT')) {
47
+ skipped++;
48
+ continue;
49
+ }
50
+ error = {
51
+ file: relativePath,
52
+ name: caughtError instanceof Error ? caughtError.name : 'Error',
53
+ code,
54
+ message: errorMessage(caughtError),
55
+ relativePath: (0, copy_containment_1.isCopyRecord)(caughtError) && 'relativePath' in caughtError
56
+ ? caughtError.relativePath
57
+ : relativePath,
58
+ };
59
+ break;
37
60
  }
38
- errors.push({ file: relativePath, error: err.message });
39
- }
40
61
  }
41
-
42
62
  // Report results back to main thread
43
- parentPort.postMessage({ copied, skipped, errors });
63
+ if (!worker_threads_1.parentPort) {
64
+ throw new Error('copy worker requires a parent port');
65
+ }
66
+ worker_threads_1.parentPort.postMessage({ copied, skipped, error });