@the-open-engine/zeroshot 6.38.1 → 6.39.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 (377) hide show
  1. package/cli/event-copy.js +8 -7
  2. package/cli/event-copy.ts +12 -0
  3. package/cli/index.js +7 -31
  4. package/cli/json-export.js +61 -64
  5. package/cli/json-export.ts +112 -0
  6. package/cli/message-formatter-utils.js +68 -56
  7. package/cli/message-formatter-utils.ts +121 -0
  8. package/cli/message-formatters-normal.js +124 -259
  9. package/cli/message-formatters-normal.ts +250 -0
  10. package/cli/message-formatters-watch.js +81 -84
  11. package/cli/message-formatters-watch.ts +189 -0
  12. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  13. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  14. package/lib/cluster/generated/protocol.d.cts +8 -0
  15. package/lib/cluster/generated/protocol.d.mts +8 -0
  16. package/lib/cluster/generated/protocol.d.ts +8 -0
  17. package/lib/clusters-registry.d.ts +23 -0
  18. package/lib/clusters-registry.js +17 -29
  19. package/lib/completion.d.ts +12 -0
  20. package/lib/completion.js +84 -94
  21. package/lib/compose-utils.d.ts +32 -0
  22. package/lib/compose-utils.js +57 -72
  23. package/lib/detached-startup.d.ts +83 -0
  24. package/lib/detached-startup.js +231 -302
  25. package/lib/docker-config.d.ts +43 -0
  26. package/lib/docker-config.js +150 -325
  27. package/lib/docker-env-auth.d.ts +17 -0
  28. package/lib/docker-env-auth.js +75 -0
  29. package/lib/git-remote-utils.d.ts +48 -0
  30. package/lib/git-remote-utils.js +147 -213
  31. package/lib/id-detector.d.ts +15 -0
  32. package/lib/id-detector.js +37 -41
  33. package/lib/path-check.d.ts +30 -0
  34. package/lib/path-check.js +42 -45
  35. package/lib/process-liveness.d.ts +16 -0
  36. package/lib/process-liveness.js +19 -12
  37. package/lib/provider-credential-path.d.ts +16 -0
  38. package/lib/provider-credential-path.js +31 -29
  39. package/lib/provider-defaults.d.ts +30 -0
  40. package/lib/provider-defaults.js +47 -42
  41. package/lib/provider-detection.d.ts +11 -0
  42. package/lib/provider-detection.js +91 -54
  43. package/lib/provider-names.d.ts +38 -0
  44. package/lib/provider-names.js +56 -64
  45. package/lib/repo-settings.d.ts +28 -0
  46. package/lib/repo-settings.js +83 -59
  47. package/lib/run-mode.d.ts +21 -0
  48. package/lib/run-mode.js +21 -20
  49. package/lib/run-plan.d.ts +28 -0
  50. package/lib/run-plan.js +17 -16
  51. package/lib/settings/claude-auth.d.ts +35 -0
  52. package/lib/settings/claude-auth.js +30 -47
  53. package/lib/settings-defaults.d.ts +20 -0
  54. package/lib/settings-defaults.js +149 -0
  55. package/lib/settings-error.d.ts +7 -0
  56. package/lib/settings-error.js +8 -0
  57. package/lib/settings-issue-providers.d.ts +10 -0
  58. package/lib/settings-issue-providers.js +12 -0
  59. package/lib/settings-models.d.ts +22 -0
  60. package/lib/settings-models.js +93 -0
  61. package/lib/settings-storage.d.ts +23 -0
  62. package/lib/settings-storage.js +205 -0
  63. package/lib/settings-validation.d.ts +7 -0
  64. package/lib/settings-validation.js +182 -0
  65. package/lib/settings.d.ts +29 -0
  66. package/lib/settings.js +41 -736
  67. package/lib/setup-apply-types.d.ts +66 -0
  68. package/lib/setup-apply-types.js +2 -0
  69. package/lib/setup-apply.d.ts +39 -0
  70. package/lib/setup-apply.js +267 -264
  71. package/lib/setup-journal.d.ts +41 -0
  72. package/lib/setup-journal.js +119 -76
  73. package/lib/setup-plan-types.d.ts +102 -0
  74. package/lib/setup-plan-types.js +2 -0
  75. package/lib/setup-plan.d.ts +30 -0
  76. package/lib/setup-plan.js +300 -324
  77. package/lib/setup-undo.d.ts +44 -0
  78. package/lib/setup-undo.js +61 -74
  79. package/lib/start-cluster-config.d.ts +26 -0
  80. package/lib/start-cluster-config.js +56 -0
  81. package/lib/start-cluster-environment.d.ts +40 -0
  82. package/lib/start-cluster-environment.js +134 -0
  83. package/lib/start-cluster-run-options.d.ts +53 -0
  84. package/lib/start-cluster-run-options.js +147 -0
  85. package/lib/start-cluster.d.ts +64 -0
  86. package/lib/start-cluster.js +98 -454
  87. package/lib/stream-json-parser.d.ts +17 -0
  88. package/lib/stream-json-parser.js +51 -52
  89. package/npm-shrinkwrap.json +2 -2
  90. package/package.json +12 -6
  91. package/scripts/postinstall.js +27 -0
  92. package/scripts/rust-distribution.js +23 -14
  93. package/src/agent/agent-command-proofs-context.js +35 -45
  94. package/src/agent/agent-command-proofs-context.ts +87 -0
  95. package/src/agent/agent-config-settings.js +19 -0
  96. package/src/agent/agent-config-settings.ts +41 -0
  97. package/src/agent/agent-config.js +122 -231
  98. package/src/agent/agent-config.ts +285 -0
  99. package/src/agent/agent-context-builder.js +38 -273
  100. package/src/agent/agent-context-builder.ts +51 -0
  101. package/src/agent/agent-context-environment-sections.js +105 -0
  102. package/src/agent/agent-context-environment-sections.ts +134 -0
  103. package/src/agent/agent-context-packs.js +165 -0
  104. package/src/agent/agent-context-packs.ts +296 -0
  105. package/src/agent/agent-context-prompt-sections.js +100 -0
  106. package/src/agent/agent-context-prompt-sections.ts +148 -0
  107. package/src/agent/agent-context-sections.js +25 -334
  108. package/src/agent/agent-context-sections.ts +36 -0
  109. package/src/agent/agent-context-sources.js +96 -149
  110. package/src/agent/agent-context-sources.ts +253 -0
  111. package/src/agent/agent-context-types.js +2 -0
  112. package/src/agent/agent-context-types.ts +132 -0
  113. package/src/agent/agent-context-validation-sections.js +73 -0
  114. package/src/agent/agent-context-validation-sections.ts +129 -0
  115. package/src/agent/agent-input-injector.js +99 -118
  116. package/src/agent/agent-input-injector.ts +195 -0
  117. package/src/agent/agent-liveness-poll.js +74 -78
  118. package/src/agent/agent-liveness-poll.ts +163 -0
  119. package/src/agent/agent-quality-gate-schema.js +77 -86
  120. package/src/agent/agent-quality-gate-schema.ts +135 -0
  121. package/src/agent/agent-quality-gates-context.js +44 -50
  122. package/src/agent/agent-quality-gates-context.ts +91 -0
  123. package/src/agent/agent-stuck-detector.js +171 -239
  124. package/src/agent/agent-stuck-detector.ts +288 -0
  125. package/src/agent/agent-trigger-evaluator.js +29 -46
  126. package/src/agent/agent-trigger-evaluator.ts +98 -0
  127. package/src/agent/context-metrics.js +110 -141
  128. package/src/agent/context-metrics.ts +261 -0
  129. package/src/agent/context-pack-builder.js +72 -358
  130. package/src/agent/context-pack-builder.ts +105 -0
  131. package/src/agent/context-pack-core.js +70 -0
  132. package/src/agent/context-pack-core.ts +96 -0
  133. package/src/agent/context-pack-selection.js +119 -0
  134. package/src/agent/context-pack-selection.ts +187 -0
  135. package/src/agent/context-pack-truncation.js +139 -0
  136. package/src/agent/context-pack-truncation.ts +208 -0
  137. package/src/agent/context-pack-types.js +2 -0
  138. package/src/agent/context-pack-types.ts +98 -0
  139. package/src/agent/context-replay-policy.js +30 -39
  140. package/src/agent/context-replay-policy.ts +71 -0
  141. package/src/agent/critical-agent-policy.js +6 -10
  142. package/src/agent/critical-agent-policy.ts +20 -0
  143. package/src/agent/guidance-queue.js +74 -87
  144. package/src/agent/guidance-queue.ts +166 -0
  145. package/src/agent/output-extraction-error-detail.js +45 -0
  146. package/src/agent/output-extraction-error-detail.ts +49 -0
  147. package/src/agent/output-extraction-failures.js +125 -0
  148. package/src/agent/output-extraction-failures.ts +149 -0
  149. package/src/agent/output-extraction-json.js +234 -0
  150. package/src/agent/output-extraction-json.ts +235 -0
  151. package/src/agent/output-extraction-pi.js +124 -0
  152. package/src/agent/output-extraction-pi.ts +137 -0
  153. package/src/agent/output-extraction-types.js +2 -0
  154. package/src/agent/output-extraction-types.ts +49 -0
  155. package/src/agent/output-extraction.js +17 -617
  156. package/src/agent/output-extraction.ts +30 -0
  157. package/src/agent/output-reformatter-errors.js +83 -0
  158. package/src/agent/output-reformatter-errors.ts +106 -0
  159. package/src/agent/output-reformatter-types.js +2 -0
  160. package/src/agent/output-reformatter-types.ts +86 -0
  161. package/src/agent/output-reformatter.js +140 -185
  162. package/src/agent/output-reformatter.ts +238 -0
  163. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  164. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  165. package/src/agent/pi-terminal-lifecycle.js +186 -206
  166. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  167. package/src/agent/provider-control-plane.js +22 -21
  168. package/src/agent/provider-control-plane.ts +52 -0
  169. package/src/agent/provider-terminal-failure-types.js +2 -0
  170. package/src/agent/provider-terminal-failure-types.ts +60 -0
  171. package/src/agent/provider-terminal-failure.js +194 -191
  172. package/src/agent/provider-terminal-failure.ts +262 -0
  173. package/src/agent/rate-limit-backoff.js +31 -74
  174. package/src/agent/rate-limit-backoff.ts +71 -0
  175. package/src/agent/schema-utils.js +85 -125
  176. package/src/agent/schema-utils.ts +148 -0
  177. package/src/agent/structured-output-error.js +34 -33
  178. package/src/agent/structured-output-error.ts +105 -0
  179. package/src/agent/validation-platform.js +27 -27
  180. package/src/agent/validation-platform.ts +49 -0
  181. package/src/attach/attach-client.js +232 -405
  182. package/src/attach/attach-client.ts +300 -0
  183. package/src/attach/attach-server-cleanup.js +43 -0
  184. package/src/attach/attach-server-cleanup.ts +39 -0
  185. package/src/attach/attach-server-clients.js +117 -0
  186. package/src/attach/attach-server-clients.ts +122 -0
  187. package/src/attach/attach-server-events.js +38 -0
  188. package/src/attach/attach-server-events.ts +36 -0
  189. package/src/attach/attach-server-pty.js +45 -0
  190. package/src/attach/attach-server-pty.ts +64 -0
  191. package/src/attach/attach-server-runtime.js +73 -0
  192. package/src/attach/attach-server-runtime.ts +62 -0
  193. package/src/attach/attach-server-socket.js +28 -0
  194. package/src/attach/attach-server-socket.ts +23 -0
  195. package/src/attach/attach-server-types.js +2 -0
  196. package/src/attach/attach-server-types.ts +82 -0
  197. package/src/attach/attach-server.js +106 -523
  198. package/src/attach/attach-server.ts +158 -0
  199. package/src/attach/index.js +18 -35
  200. package/src/attach/index.ts +18 -0
  201. package/src/attach/protocol.js +95 -184
  202. package/src/attach/protocol.ts +181 -0
  203. package/src/attach/ring-buffer.js +76 -102
  204. package/src/attach/ring-buffer.ts +109 -0
  205. package/src/attach/send-input.js +64 -75
  206. package/src/attach/send-input.ts +94 -0
  207. package/src/attach/socket-discovery.js +164 -218
  208. package/src/attach/socket-discovery.ts +230 -0
  209. package/src/attach/socket-paths.js +42 -61
  210. package/src/attach/socket-paths.ts +81 -0
  211. package/src/claude-credentials.js +51 -54
  212. package/src/claude-credentials.ts +89 -0
  213. package/src/cluster/generated/protocol-schema.ts +1 -1
  214. package/src/cluster/generated/protocol.ts +2 -1
  215. package/src/command-proofs.js +110 -141
  216. package/src/command-proofs.ts +216 -0
  217. package/src/config-router.js +81 -73
  218. package/src/config-router.ts +131 -0
  219. package/src/copy-worker.js +53 -29
  220. package/src/copy-worker.ts +75 -0
  221. package/src/darwin-keychain-boundary.js +80 -111
  222. package/src/darwin-keychain-boundary.ts +148 -0
  223. package/src/guidance-topics.js +4 -5
  224. package/src/guidance-topics.ts +10 -0
  225. package/src/input-helpers.js +33 -54
  226. package/src/input-helpers.ts +58 -0
  227. package/src/ledger-sequence.js +45 -48
  228. package/src/ledger-sequence.ts +63 -0
  229. package/src/legacy-lib/clusters-registry.ts +40 -0
  230. package/src/legacy-lib/completion.ts +148 -0
  231. package/src/legacy-lib/compose-utils.ts +102 -0
  232. package/src/legacy-lib/detached-startup.ts +449 -0
  233. package/src/legacy-lib/docker-config.ts +282 -0
  234. package/src/legacy-lib/docker-env-auth.ts +116 -0
  235. package/src/legacy-lib/git-remote-utils.ts +244 -0
  236. package/src/legacy-lib/id-detector.ts +57 -0
  237. package/src/legacy-lib/js-yaml.d.ts +3 -0
  238. package/src/legacy-lib/omelette.d.ts +15 -0
  239. package/src/legacy-lib/path-check.ts +89 -0
  240. package/src/legacy-lib/process-liveness.ts +36 -0
  241. package/src/legacy-lib/provider-credential-path.ts +57 -0
  242. package/src/legacy-lib/provider-defaults.ts +114 -0
  243. package/src/legacy-lib/provider-detection.ts +67 -0
  244. package/src/legacy-lib/provider-names.ts +126 -0
  245. package/src/legacy-lib/repo-settings.ts +88 -0
  246. package/src/legacy-lib/run-mode.ts +58 -0
  247. package/src/legacy-lib/run-plan.ts +49 -0
  248. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  249. package/src/legacy-lib/settings-defaults.ts +212 -0
  250. package/src/legacy-lib/settings-error.ts +8 -0
  251. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  252. package/src/legacy-lib/settings-models.ts +124 -0
  253. package/src/legacy-lib/settings-storage.ts +277 -0
  254. package/src/legacy-lib/settings-validation.ts +220 -0
  255. package/src/legacy-lib/settings.ts +87 -0
  256. package/src/legacy-lib/setup-apply-types.ts +70 -0
  257. package/src/legacy-lib/setup-apply.ts +456 -0
  258. package/src/legacy-lib/setup-journal.ts +185 -0
  259. package/src/legacy-lib/setup-plan-types.ts +96 -0
  260. package/src/legacy-lib/setup-plan.ts +500 -0
  261. package/src/legacy-lib/setup-undo.ts +142 -0
  262. package/src/legacy-lib/start-cluster-config.ts +124 -0
  263. package/src/legacy-lib/start-cluster-environment.ts +165 -0
  264. package/src/legacy-lib/start-cluster-run-options.ts +279 -0
  265. package/src/legacy-lib/start-cluster.ts +237 -0
  266. package/src/legacy-lib/stream-json-parser.ts +88 -0
  267. package/src/message-buffer.js +55 -71
  268. package/src/message-buffer.ts +107 -0
  269. package/src/message-bus-bridge.js +92 -133
  270. package/src/message-bus-bridge.ts +149 -0
  271. package/src/name-generator-shared.js +220 -0
  272. package/src/name-generator-shared.ts +231 -0
  273. package/src/name-generator.js +8 -217
  274. package/src/name-generator.ts +27 -0
  275. package/src/omp-blob-root.js +83 -64
  276. package/src/omp-blob-root.ts +116 -0
  277. package/src/omp-config-overlay.js +65 -38
  278. package/src/omp-config-overlay.ts +110 -0
  279. package/src/omp-execution-fingerprint.js +38 -43
  280. package/src/omp-execution-fingerprint.ts +92 -0
  281. package/src/omp-session-limits.js +10 -15
  282. package/src/omp-session-limits.ts +53 -0
  283. package/src/omp-session-partition.js +2 -2
  284. package/src/omp-session-verifier.js +1 -1
  285. package/src/orchestrator.js +19 -4
  286. package/src/providers/anthropic/index.js +3 -1
  287. package/src/providers/anthropic/index.ts +13 -0
  288. package/src/providers/capabilities.js +19 -27
  289. package/src/providers/capabilities.ts +44 -0
  290. package/src/providers/google/index.js +3 -1
  291. package/src/providers/google/index.ts +13 -0
  292. package/src/providers/openai/index.js +3 -1
  293. package/src/providers/openai/index.ts +13 -0
  294. package/src/providers/opencode/index.js +3 -1
  295. package/src/providers/opencode/index.ts +13 -0
  296. package/src/quality-gates.js +67 -127
  297. package/src/quality-gates.ts +149 -0
  298. package/src/repo-settings-access.js +40 -0
  299. package/src/repo-settings-access.ts +64 -0
  300. package/src/schemas/sub-cluster.js +127 -183
  301. package/src/schemas/sub-cluster.ts +238 -0
  302. package/src/state-snapshot-normalization.js +224 -0
  303. package/src/state-snapshot-normalization.ts +222 -0
  304. package/src/state-snapshot.js +192 -359
  305. package/src/state-snapshot.ts +291 -0
  306. package/src/state-snapshotter.js +118 -130
  307. package/src/state-snapshotter.ts +167 -0
  308. package/src/sub-cluster-wrapper.js +4 -13
  309. package/src/task-run-model-args.js +87 -124
  310. package/src/task-run-model-args.ts +204 -0
  311. package/src/task-runner.js +5 -25
  312. package/src/task-runner.ts +28 -0
  313. package/src/task-startup-error.js +73 -58
  314. package/src/task-startup-error.ts +126 -0
  315. package/src/template-validation/consensus-gate-contracts.js +2 -0
  316. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  317. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  318. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  319. package/src/template-validation/consensus-gate-stage.js +34 -0
  320. package/src/template-validation/consensus-gate-stage.ts +56 -0
  321. package/src/template-validation/random-topology-contracts.js +2 -0
  322. package/src/template-validation/random-topology-contracts.ts +54 -0
  323. package/src/template-validation/random-topology-dispatch.js +25 -0
  324. package/src/template-validation/random-topology-dispatch.ts +33 -0
  325. package/src/template-validation/random-topology-message-loop.js +53 -0
  326. package/src/template-validation/random-topology-message-loop.ts +73 -0
  327. package/src/template-validation/random-topology-operations.js +79 -0
  328. package/src/template-validation/random-topology-operations.ts +101 -0
  329. package/src/template-validation/random-topology-runtime.js +25 -0
  330. package/src/template-validation/random-topology-runtime.ts +43 -0
  331. package/src/template-validation/random-topology-scenario.js +52 -0
  332. package/src/template-validation/random-topology-scenario.ts +57 -0
  333. package/src/template-validation/random-topology-schema.js +159 -0
  334. package/src/template-validation/random-topology-schema.ts +190 -0
  335. package/src/template-validation/random-topology-state.js +28 -0
  336. package/src/template-validation/random-topology-state.ts +30 -0
  337. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  338. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  339. package/src/template-validation/random-topology-trigger.js +75 -0
  340. package/src/template-validation/random-topology-trigger.ts +88 -0
  341. package/src/template-validation/report-formatter.js +40 -46
  342. package/src/template-validation/report-formatter.ts +101 -0
  343. package/src/template-validation/simulate-consensus-gates.js +111 -302
  344. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  345. package/src/template-validation/simulate-random-topology.js +26 -519
  346. package/src/template-validation/simulate-random-topology.ts +57 -0
  347. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  348. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  349. package/src/template-validation/simulation-agent-runtime.js +25 -0
  350. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  351. package/src/template-validation/simulation-agent.js +29 -0
  352. package/src/template-validation/simulation-agent.ts +73 -0
  353. package/src/template-validation/simulation-runtime.js +34 -0
  354. package/src/template-validation/simulation-runtime.ts +72 -0
  355. package/src/template-validation/two-stage-contracts.js +2 -0
  356. package/src/template-validation/two-stage-contracts.ts +41 -0
  357. package/src/template-validation/two-stage-inputs.js +21 -0
  358. package/src/template-validation/two-stage-inputs.ts +29 -0
  359. package/src/template-validation/two-stage-results.js +30 -0
  360. package/src/template-validation/two-stage-results.ts +40 -0
  361. package/src/template-validation/two-stage-scenario.js +86 -0
  362. package/src/template-validation/two-stage-scenario.ts +120 -0
  363. package/src/worktree-claude-config.js +182 -220
  364. package/src/worktree-claude-config.ts +272 -0
  365. package/src/worktree-tooling-env.js +103 -125
  366. package/src/worktree-tooling-env.ts +142 -0
  367. package/task-lib/completion.js +2 -3
  368. package/task-lib/completion.ts +9 -0
  369. package/task-lib/config.js +1 -4
  370. package/task-lib/config.ts +11 -0
  371. package/task-lib/name-generator.js +4 -226
  372. package/task-lib/name-generator.ts +11 -0
  373. package/task-lib/omp-session-cleanup.js +1 -1
  374. package/task-lib/omp-storage-root.js +8 -12
  375. package/task-lib/omp-storage-root.ts +62 -0
  376. package/task-lib/process-termination.js +143 -166
  377. package/task-lib/process-termination.ts +268 -0
@@ -1,9 +1,9 @@
1
- const fs = require('fs');
2
- const os = require('os');
3
- const path = require('path');
4
-
5
- const { resolveWorktreeRoot } = require('./worktree-tooling-env');
6
-
1
+ "use strict";
2
+ const fs = require("fs");
3
+ const os = require("os");
4
+ const path = require("path");
5
+ const worktreeToolingEnv = require("./worktree-tooling-env");
6
+ const { resolveWorktreeRoot } = worktreeToolingEnv;
7
7
  const CLAUDE_DIRNAME = '.claude';
8
8
  const MCP_BASENAME = '.mcp.json';
9
9
  const SETTINGS_BASENAME = 'settings.json';
@@ -12,238 +12,200 @@ const CLAUDE_SETTINGS_ENV = 'ZEROSHOT_CLAUDE_SETTINGS_FILE';
12
12
  const CLAUDE_MCP_CONFIG_ENV = 'ZEROSHOT_CLAUDE_MCP_CONFIG_FILE';
13
13
  const ASK_USER_HOOK = 'block-ask-user-question.py';
14
14
  const DANGEROUS_GIT_HOOK = 'block-dangerous-git.py';
15
-
16
-
15
+ function isMutableRecord(value) {
16
+ return typeof value === 'object' && value !== null;
17
+ }
18
+ function isHookEntries(value) {
19
+ return Array.isArray(value);
20
+ }
17
21
  function readSettings(settingsPath) {
18
- if (!fs.existsSync(settingsPath)) {
19
- return {};
20
- }
21
-
22
- try {
23
- return JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
24
- } catch (error) {
25
- throw new Error(`Could not parse Claude settings overlay ${settingsPath}: ${error.message}`);
26
- }
27
- }
28
-
22
+ if (!fs.existsSync(settingsPath))
23
+ return {};
24
+ let parsed;
25
+ try {
26
+ parsed = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
27
+ }
28
+ catch (error) {
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ throw new Error(`Could not parse Claude settings overlay ${settingsPath}: ${message}`);
31
+ }
32
+ if (!isMutableRecord(parsed)) {
33
+ throw new TypeError(`Claude settings overlay ${settingsPath} must contain an object.`);
34
+ }
35
+ return parsed;
36
+ }
29
37
  function writeSettings(settingsPath, settings) {
30
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), { mode: 0o600 });
38
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), { mode: 0o600 });
31
39
  }
32
-
33
40
  function requireTargetClaudeDir(targetClaudeDir) {
34
- if (typeof targetClaudeDir !== 'string' || !targetClaudeDir) {
35
- throw new Error('Claude safety hooks require an explicit per-run settings directory.');
36
- }
37
- if (!isClaudeSettingsOverlayDirectory(targetClaudeDir)) {
38
- throw new Error(
39
- `Claude safety hooks require a Zeroshot-owned Claude settings overlay: ${targetClaudeDir}`
40
- );
41
- }
42
- return targetClaudeDir;
43
- }
44
-
41
+ if (typeof targetClaudeDir !== 'string' || !targetClaudeDir) {
42
+ throw new Error('Claude safety hooks require an explicit per-run settings directory.');
43
+ }
44
+ if (!isClaudeSettingsOverlayDirectory(targetClaudeDir)) {
45
+ throw new Error(`Claude safety hooks require a Zeroshot-owned Claude settings overlay: ${targetClaudeDir}`);
46
+ }
47
+ return targetClaudeDir;
48
+ }
45
49
  function copyHookScript(targetClaudeDir, hookScriptName) {
46
- const hooksDir = path.join(targetClaudeDir, 'hooks');
47
- fs.mkdirSync(hooksDir, { recursive: true });
48
-
49
- const sourcePath = path.join(__dirname, '..', 'cluster-hooks', hookScriptName);
50
- if (!fs.existsSync(sourcePath)) {
51
- throw new Error(
52
- `Claude safety hook ${hookScriptName} is missing from the Zeroshot installation.`
53
- );
54
- }
55
-
56
- const destinationPath = path.join(hooksDir, hookScriptName);
57
- fs.copyFileSync(sourcePath, destinationPath);
58
- fs.chmodSync(destinationPath, 0o755);
59
- return destinationPath;
60
- }
61
-
50
+ const hooksDir = path.join(targetClaudeDir, 'hooks');
51
+ fs.mkdirSync(hooksDir, { recursive: true });
52
+ const sourcePath = path.join(__dirname, '..', 'cluster-hooks', hookScriptName);
53
+ if (!fs.existsSync(sourcePath)) {
54
+ throw new Error(`Claude safety hook ${hookScriptName} is missing from the Zeroshot installation.`);
55
+ }
56
+ const destinationPath = path.join(hooksDir, hookScriptName);
57
+ fs.copyFileSync(sourcePath, destinationPath);
58
+ fs.chmodSync(destinationPath, 0o755);
59
+ return destinationPath;
60
+ }
62
61
  function ensurePreToolUseHooks(settings) {
63
- settings.hooks ||= {};
64
- settings.hooks.PreToolUse ||= [];
65
- return settings.hooks.PreToolUse;
62
+ let hooks = settings.hooks;
63
+ if (!hooks) {
64
+ hooks = {};
65
+ settings.hooks = hooks;
66
+ }
67
+ if (!isMutableRecord(hooks)) {
68
+ throw new TypeError('Claude settings hooks must be an object.');
69
+ }
70
+ let preToolUse = hooks.PreToolUse;
71
+ if (!preToolUse) {
72
+ preToolUse = [];
73
+ hooks.PreToolUse = preToolUse;
74
+ }
75
+ if (!isHookEntries(preToolUse)) {
76
+ throw new TypeError('Claude settings hooks.PreToolUse must be an array.');
77
+ }
78
+ return preToolUse;
66
79
  }
67
-
68
80
  function ensureAskUserQuestionHook(targetClaudeDir) {
69
- const overlayDir = requireTargetClaudeDir(targetClaudeDir);
70
-
71
- const hookScriptPath = copyHookScript(overlayDir, ASK_USER_HOOK);
72
- const settingsPath = path.join(overlayDir, SETTINGS_BASENAME);
73
- const settings = readSettings(settingsPath);
74
- const hooks = ensurePreToolUseHooks(settings);
75
- const hasHook = hooks.some(
76
- (entry) =>
77
- entry.matcher === 'AskUserQuestion' ||
78
- entry.hooks?.some((hook) => hook.command?.includes(ASK_USER_HOOK))
79
- );
80
-
81
- if (!hasHook) {
82
- hooks.push({
83
- matcher: 'AskUserQuestion',
84
- hooks: [{ type: 'command', command: hookScriptPath }],
85
- });
86
- writeSettings(settingsPath, settings);
87
- }
88
-
89
- }
90
-
81
+ const overlayDir = requireTargetClaudeDir(targetClaudeDir);
82
+ const hookScriptPath = copyHookScript(overlayDir, ASK_USER_HOOK);
83
+ const settingsPath = path.join(overlayDir, SETTINGS_BASENAME);
84
+ const settings = readSettings(settingsPath);
85
+ const hooks = ensurePreToolUseHooks(settings);
86
+ const hasHook = hooks.some((entry) => entry.matcher === 'AskUserQuestion' ||
87
+ entry.hooks?.some((hook) => hook.command?.includes(ASK_USER_HOOK)));
88
+ if (!hasHook) {
89
+ hooks.push({
90
+ matcher: 'AskUserQuestion',
91
+ hooks: [{ type: 'command', command: hookScriptPath }],
92
+ });
93
+ writeSettings(settingsPath, settings);
94
+ }
95
+ }
91
96
  function ensureDangerousGitHook(targetClaudeDir) {
92
- const overlayDir = requireTargetClaudeDir(targetClaudeDir);
93
-
94
- const hookScriptPath = copyHookScript(overlayDir, DANGEROUS_GIT_HOOK);
95
- const settingsPath = path.join(overlayDir, SETTINGS_BASENAME);
96
- const settings = readSettings(settingsPath);
97
- const hooks = ensurePreToolUseHooks(settings);
98
- const hasHook = hooks.some(
99
- (entry) =>
100
- entry.matcher === 'Bash' &&
101
- entry.hooks?.some((hook) => hook.command?.includes(DANGEROUS_GIT_HOOK))
102
- );
103
-
104
- if (!hasHook) {
105
- hooks.push({
106
- matcher: 'Bash',
107
- hooks: [{ type: 'command', command: hookScriptPath }],
108
- });
109
- writeSettings(settingsPath, settings);
110
- }
111
-
112
- }
113
-
97
+ const overlayDir = requireTargetClaudeDir(targetClaudeDir);
98
+ const hookScriptPath = copyHookScript(overlayDir, DANGEROUS_GIT_HOOK);
99
+ const settingsPath = path.join(overlayDir, SETTINGS_BASENAME);
100
+ const settings = readSettings(settingsPath);
101
+ const hooks = ensurePreToolUseHooks(settings);
102
+ const hasHook = hooks.some((entry) => entry.matcher === 'Bash' &&
103
+ entry.hooks?.some((hook) => hook.command?.includes(DANGEROUS_GIT_HOOK)));
104
+ if (!hasHook) {
105
+ hooks.push({
106
+ matcher: 'Bash',
107
+ hooks: [{ type: 'command', command: hookScriptPath }],
108
+ });
109
+ writeSettings(settingsPath, settings);
110
+ }
111
+ }
114
112
  function prepareClaudeSettingsOverlay(options = {}) {
115
- const overlayDir = fs.mkdtempSync(path.join(os.tmpdir(), OVERLAY_PREFIX));
116
- fs.chmodSync(overlayDir, 0o700);
117
- try {
118
- ensureAskUserQuestionHook(overlayDir);
119
- if (options.includeDangerousGit) {
120
- ensureDangerousGitHook(overlayDir);
121
- }
122
- return path.join(overlayDir, SETTINGS_BASENAME);
123
- } catch (error) {
124
- fs.rmSync(overlayDir, { recursive: true, force: true });
125
- throw error;
126
- }
113
+ const overlayDir = fs.mkdtempSync(path.join(os.tmpdir(), OVERLAY_PREFIX));
114
+ fs.chmodSync(overlayDir, 0o700);
115
+ try {
116
+ ensureAskUserQuestionHook(overlayDir);
117
+ if (options.includeDangerousGit)
118
+ ensureDangerousGitHook(overlayDir);
119
+ return path.join(overlayDir, SETTINGS_BASENAME);
120
+ }
121
+ catch (error) {
122
+ fs.rmSync(overlayDir, { recursive: true, force: true });
123
+ throw error;
124
+ }
127
125
  }
128
-
129
126
  function cleanupClaudeSettingsOverlay(settingsPath) {
130
- if (!isCanonicalClaudeSettingsOverlayPath(settingsPath)) {
131
- return false;
132
- }
133
-
134
- const overlayDir = path.dirname(settingsPath);
135
- if (!fs.existsSync(overlayDir)) {
127
+ if (!isCanonicalClaudeSettingsOverlayPath(settingsPath))
128
+ return false;
129
+ const overlayDir = path.dirname(settingsPath);
130
+ if (!fs.existsSync(overlayDir))
131
+ return true;
132
+ if (!isClaudeSettingsOverlayPath(settingsPath))
133
+ return false;
134
+ fs.rmSync(overlayDir, { recursive: true, force: true });
136
135
  return true;
137
- }
138
- if (!isClaudeSettingsOverlayPath(settingsPath)) {
139
- return false;
140
- }
141
-
142
- fs.rmSync(overlayDir, { recursive: true, force: true });
143
- return true;
144
- }
145
-
136
+ }
146
137
  function isCanonicalClaudeSettingsOverlayPath(settingsPath) {
147
- if (typeof settingsPath !== 'string' || !settingsPath) {
148
- return false;
149
- }
150
- const resolvedSettingsPath = path.resolve(settingsPath);
151
- const overlayDir = path.dirname(resolvedSettingsPath);
152
- return (
153
- resolvedSettingsPath === settingsPath &&
154
- path.basename(resolvedSettingsPath) === SETTINGS_BASENAME &&
155
- path.dirname(overlayDir) === path.resolve(os.tmpdir()) &&
156
- path.basename(overlayDir).startsWith(OVERLAY_PREFIX)
157
- );
158
- }
159
-
138
+ if (typeof settingsPath !== 'string' || !settingsPath)
139
+ return false;
140
+ const resolvedSettingsPath = path.resolve(settingsPath);
141
+ const overlayDir = path.dirname(resolvedSettingsPath);
142
+ return (resolvedSettingsPath === settingsPath &&
143
+ path.basename(resolvedSettingsPath) === SETTINGS_BASENAME &&
144
+ path.dirname(overlayDir) === path.resolve(os.tmpdir()) &&
145
+ path.basename(overlayDir).startsWith(OVERLAY_PREFIX));
146
+ }
160
147
  function isClaudeSettingsOverlayPath(settingsPath, platform = process.platform) {
161
- if (!isCanonicalClaudeSettingsOverlayPath(settingsPath)) {
162
- return false;
163
- }
164
-
165
- const resolvedSettingsPath = path.resolve(settingsPath);
166
- const overlayDir = path.dirname(resolvedSettingsPath);
167
-
168
- try {
169
- const stat = fs.lstatSync(overlayDir);
170
- const ownedByProcess =
171
- typeof process.getuid !== 'function' || stat.uid === process.getuid();
172
- const privateMode = platform === 'win32' || (stat.mode & 0o777) === 0o700;
173
- return stat.isDirectory() && !stat.isSymbolicLink() && ownedByProcess && privateMode;
174
- } catch {
175
- return false;
176
- }
177
- }
178
-
148
+ if (!isCanonicalClaudeSettingsOverlayPath(settingsPath))
149
+ return false;
150
+ const overlayDir = path.dirname(settingsPath);
151
+ try {
152
+ const stat = fs.lstatSync(overlayDir);
153
+ const ownedByProcess = typeof process.getuid !== 'function' || stat.uid === process.getuid();
154
+ const privateMode = platform === 'win32' || (stat.mode & 0o777) === 0o700;
155
+ return stat.isDirectory() && !stat.isSymbolicLink() && ownedByProcess && privateMode;
156
+ }
157
+ catch {
158
+ return false;
159
+ }
160
+ }
179
161
  function isCanonicalClaudeSettingsOverlayDirectory(overlayDir) {
180
- if (
181
- typeof overlayDir !== 'string' ||
182
- !overlayDir ||
183
- path.resolve(overlayDir) !== overlayDir
184
- ) {
185
- return false;
186
- }
187
- return isCanonicalClaudeSettingsOverlayPath(path.join(overlayDir, SETTINGS_BASENAME));
188
- }
189
-
162
+ if (typeof overlayDir !== 'string' ||
163
+ !overlayDir ||
164
+ path.resolve(overlayDir) !== overlayDir) {
165
+ return false;
166
+ }
167
+ return isCanonicalClaudeSettingsOverlayPath(path.join(overlayDir, SETTINGS_BASENAME));
168
+ }
190
169
  function isClaudeSettingsOverlayDirectory(overlayDir) {
191
- if (typeof overlayDir !== 'string' || !overlayDir) {
192
- return false;
193
- }
194
- return isClaudeSettingsOverlayPath(path.join(overlayDir, SETTINGS_BASENAME));
195
- }
196
-
197
- /**
198
- * Resolve the repo's MCP config for a given worktree/cwd. The project-root
199
- * `.mcp.json` is Claude's current convention. `.claude/.mcp.json` remains a
200
- * deliberate compatibility fallback for repositories created by Zeroshot's
201
- * earlier worktree integration.
202
- */
170
+ return (typeof overlayDir === 'string' &&
171
+ Boolean(overlayDir) &&
172
+ isClaudeSettingsOverlayPath(path.join(overlayDir, SETTINGS_BASENAME)));
173
+ }
203
174
  function resolveRepoMcpConfigPath(options = {}) {
204
- const worktreeRoot = resolveWorktreeRoot(options.worktreePath || options.cwd);
205
- if (!worktreeRoot) {
206
- return null;
207
- }
208
-
209
- const candidates = [
210
- path.join(worktreeRoot, MCP_BASENAME),
211
- path.join(worktreeRoot, CLAUDE_DIRNAME, MCP_BASENAME),
212
- ];
213
- return candidates.find((candidate) => fs.existsSync(candidate)) || null;
214
- }
215
-
175
+ const worktreeRoot = resolveWorktreeRoot(options.worktreePath || options.cwd);
176
+ if (!worktreeRoot)
177
+ return null;
178
+ const candidates = [
179
+ path.join(worktreeRoot, MCP_BASENAME),
180
+ path.join(worktreeRoot, CLAUDE_DIRNAME, MCP_BASENAME),
181
+ ];
182
+ return candidates.find((candidate) => fs.existsSync(candidate)) || null;
183
+ }
216
184
  function resolveContainerMcpConfigPath(options = {}) {
217
- const worktreeRoot = resolveWorktreeRoot(options.worktreePath || options.cwd);
218
- const hostConfigPath = resolveRepoMcpConfigPath(options);
219
- if (!worktreeRoot || !hostConfigPath) {
220
- return null;
221
- }
222
-
223
- const relativePath = path.relative(worktreeRoot, hostConfigPath);
224
- if (
225
- !relativePath ||
226
- path.isAbsolute(relativePath) ||
227
- relativePath === '..' ||
228
- relativePath.startsWith(`..${path.sep}`)
229
- ) {
230
- throw new Error(`Repository MCP config is outside the mounted workspace: ${hostConfigPath}`);
231
- }
232
-
233
- return path.posix.join('/workspace', relativePath.split(path.sep).join('/'));
234
- }
235
-
185
+ const worktreeRoot = resolveWorktreeRoot(options.worktreePath || options.cwd);
186
+ const hostConfigPath = resolveRepoMcpConfigPath(options);
187
+ if (!worktreeRoot || !hostConfigPath)
188
+ return null;
189
+ const relativePath = path.relative(worktreeRoot, hostConfigPath);
190
+ if (!relativePath ||
191
+ path.isAbsolute(relativePath) ||
192
+ relativePath === '..' ||
193
+ relativePath.startsWith(`..${path.sep}`)) {
194
+ throw new Error(`Repository MCP config is outside the mounted workspace: ${hostConfigPath}`);
195
+ }
196
+ return path.posix.join('/workspace', relativePath.split(path.sep).join('/'));
197
+ }
236
198
  module.exports = {
237
- CLAUDE_MCP_CONFIG_ENV,
238
- CLAUDE_SETTINGS_ENV,
239
- cleanupClaudeSettingsOverlay,
240
- ensureAskUserQuestionHook,
241
- ensureDangerousGitHook,
242
- isCanonicalClaudeSettingsOverlayDirectory,
243
- isCanonicalClaudeSettingsOverlayPath,
244
- isClaudeSettingsOverlayDirectory,
245
- isClaudeSettingsOverlayPath,
246
- prepareClaudeSettingsOverlay,
247
- resolveContainerMcpConfigPath,
248
- resolveRepoMcpConfigPath,
199
+ CLAUDE_MCP_CONFIG_ENV,
200
+ CLAUDE_SETTINGS_ENV,
201
+ cleanupClaudeSettingsOverlay,
202
+ ensureAskUserQuestionHook,
203
+ ensureDangerousGitHook,
204
+ isCanonicalClaudeSettingsOverlayDirectory,
205
+ isCanonicalClaudeSettingsOverlayPath,
206
+ isClaudeSettingsOverlayDirectory,
207
+ isClaudeSettingsOverlayPath,
208
+ prepareClaudeSettingsOverlay,
209
+ resolveContainerMcpConfigPath,
210
+ resolveRepoMcpConfigPath,
249
211
  };