@the-open-engine/zeroshot 6.38.0 → 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 (381) 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/agent-cli-provider/adapters/codex.d.ts.map +1 -1
  13. package/lib/agent-cli-provider/adapters/codex.js +3 -1
  14. package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
  15. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  16. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  17. package/lib/cluster/generated/protocol.d.cts +8 -0
  18. package/lib/cluster/generated/protocol.d.mts +8 -0
  19. package/lib/cluster/generated/protocol.d.ts +8 -0
  20. package/lib/clusters-registry.d.ts +23 -0
  21. package/lib/clusters-registry.js +17 -29
  22. package/lib/completion.d.ts +12 -0
  23. package/lib/completion.js +84 -94
  24. package/lib/compose-utils.d.ts +32 -0
  25. package/lib/compose-utils.js +57 -72
  26. package/lib/detached-startup.d.ts +83 -0
  27. package/lib/detached-startup.js +231 -302
  28. package/lib/docker-config.d.ts +43 -0
  29. package/lib/docker-config.js +150 -325
  30. package/lib/docker-env-auth.d.ts +17 -0
  31. package/lib/docker-env-auth.js +75 -0
  32. package/lib/git-remote-utils.d.ts +48 -0
  33. package/lib/git-remote-utils.js +147 -213
  34. package/lib/id-detector.d.ts +15 -0
  35. package/lib/id-detector.js +37 -41
  36. package/lib/path-check.d.ts +30 -0
  37. package/lib/path-check.js +42 -45
  38. package/lib/process-liveness.d.ts +16 -0
  39. package/lib/process-liveness.js +19 -12
  40. package/lib/provider-credential-path.d.ts +16 -0
  41. package/lib/provider-credential-path.js +31 -29
  42. package/lib/provider-defaults.d.ts +30 -0
  43. package/lib/provider-defaults.js +47 -42
  44. package/lib/provider-detection.d.ts +11 -0
  45. package/lib/provider-detection.js +91 -54
  46. package/lib/provider-names.d.ts +38 -0
  47. package/lib/provider-names.js +56 -64
  48. package/lib/repo-settings.d.ts +28 -0
  49. package/lib/repo-settings.js +83 -59
  50. package/lib/run-mode.d.ts +21 -0
  51. package/lib/run-mode.js +21 -20
  52. package/lib/run-plan.d.ts +28 -0
  53. package/lib/run-plan.js +17 -16
  54. package/lib/settings/claude-auth.d.ts +35 -0
  55. package/lib/settings/claude-auth.js +30 -47
  56. package/lib/settings-defaults.d.ts +20 -0
  57. package/lib/settings-defaults.js +149 -0
  58. package/lib/settings-error.d.ts +7 -0
  59. package/lib/settings-error.js +8 -0
  60. package/lib/settings-issue-providers.d.ts +10 -0
  61. package/lib/settings-issue-providers.js +12 -0
  62. package/lib/settings-models.d.ts +22 -0
  63. package/lib/settings-models.js +93 -0
  64. package/lib/settings-storage.d.ts +23 -0
  65. package/lib/settings-storage.js +205 -0
  66. package/lib/settings-validation.d.ts +7 -0
  67. package/lib/settings-validation.js +182 -0
  68. package/lib/settings.d.ts +29 -0
  69. package/lib/settings.js +41 -736
  70. package/lib/setup-apply-types.d.ts +66 -0
  71. package/lib/setup-apply-types.js +2 -0
  72. package/lib/setup-apply.d.ts +39 -0
  73. package/lib/setup-apply.js +267 -264
  74. package/lib/setup-journal.d.ts +41 -0
  75. package/lib/setup-journal.js +119 -76
  76. package/lib/setup-plan-types.d.ts +102 -0
  77. package/lib/setup-plan-types.js +2 -0
  78. package/lib/setup-plan.d.ts +30 -0
  79. package/lib/setup-plan.js +300 -324
  80. package/lib/setup-undo.d.ts +44 -0
  81. package/lib/setup-undo.js +61 -74
  82. package/lib/start-cluster-config.d.ts +26 -0
  83. package/lib/start-cluster-config.js +56 -0
  84. package/lib/start-cluster-environment.d.ts +40 -0
  85. package/lib/start-cluster-environment.js +134 -0
  86. package/lib/start-cluster-run-options.d.ts +53 -0
  87. package/lib/start-cluster-run-options.js +147 -0
  88. package/lib/start-cluster.d.ts +64 -0
  89. package/lib/start-cluster.js +98 -454
  90. package/lib/stream-json-parser.d.ts +17 -0
  91. package/lib/stream-json-parser.js +51 -52
  92. package/npm-shrinkwrap.json +2 -2
  93. package/package.json +12 -6
  94. package/scripts/postinstall.js +27 -0
  95. package/scripts/rust-distribution.js +23 -14
  96. package/src/agent/agent-command-proofs-context.js +35 -45
  97. package/src/agent/agent-command-proofs-context.ts +87 -0
  98. package/src/agent/agent-config-settings.js +19 -0
  99. package/src/agent/agent-config-settings.ts +41 -0
  100. package/src/agent/agent-config.js +122 -231
  101. package/src/agent/agent-config.ts +285 -0
  102. package/src/agent/agent-context-builder.js +38 -273
  103. package/src/agent/agent-context-builder.ts +51 -0
  104. package/src/agent/agent-context-environment-sections.js +105 -0
  105. package/src/agent/agent-context-environment-sections.ts +134 -0
  106. package/src/agent/agent-context-packs.js +165 -0
  107. package/src/agent/agent-context-packs.ts +296 -0
  108. package/src/agent/agent-context-prompt-sections.js +100 -0
  109. package/src/agent/agent-context-prompt-sections.ts +148 -0
  110. package/src/agent/agent-context-sections.js +25 -334
  111. package/src/agent/agent-context-sections.ts +36 -0
  112. package/src/agent/agent-context-sources.js +96 -149
  113. package/src/agent/agent-context-sources.ts +253 -0
  114. package/src/agent/agent-context-types.js +2 -0
  115. package/src/agent/agent-context-types.ts +132 -0
  116. package/src/agent/agent-context-validation-sections.js +73 -0
  117. package/src/agent/agent-context-validation-sections.ts +129 -0
  118. package/src/agent/agent-input-injector.js +99 -118
  119. package/src/agent/agent-input-injector.ts +195 -0
  120. package/src/agent/agent-liveness-poll.js +74 -78
  121. package/src/agent/agent-liveness-poll.ts +163 -0
  122. package/src/agent/agent-quality-gate-schema.js +77 -86
  123. package/src/agent/agent-quality-gate-schema.ts +135 -0
  124. package/src/agent/agent-quality-gates-context.js +44 -50
  125. package/src/agent/agent-quality-gates-context.ts +91 -0
  126. package/src/agent/agent-stuck-detector.js +171 -239
  127. package/src/agent/agent-stuck-detector.ts +288 -0
  128. package/src/agent/agent-trigger-evaluator.js +29 -46
  129. package/src/agent/agent-trigger-evaluator.ts +98 -0
  130. package/src/agent/context-metrics.js +110 -141
  131. package/src/agent/context-metrics.ts +261 -0
  132. package/src/agent/context-pack-builder.js +72 -358
  133. package/src/agent/context-pack-builder.ts +105 -0
  134. package/src/agent/context-pack-core.js +70 -0
  135. package/src/agent/context-pack-core.ts +96 -0
  136. package/src/agent/context-pack-selection.js +119 -0
  137. package/src/agent/context-pack-selection.ts +187 -0
  138. package/src/agent/context-pack-truncation.js +139 -0
  139. package/src/agent/context-pack-truncation.ts +208 -0
  140. package/src/agent/context-pack-types.js +2 -0
  141. package/src/agent/context-pack-types.ts +98 -0
  142. package/src/agent/context-replay-policy.js +30 -39
  143. package/src/agent/context-replay-policy.ts +71 -0
  144. package/src/agent/critical-agent-policy.js +6 -10
  145. package/src/agent/critical-agent-policy.ts +20 -0
  146. package/src/agent/guidance-queue.js +74 -87
  147. package/src/agent/guidance-queue.ts +166 -0
  148. package/src/agent/output-extraction-error-detail.js +45 -0
  149. package/src/agent/output-extraction-error-detail.ts +49 -0
  150. package/src/agent/output-extraction-failures.js +125 -0
  151. package/src/agent/output-extraction-failures.ts +149 -0
  152. package/src/agent/output-extraction-json.js +234 -0
  153. package/src/agent/output-extraction-json.ts +235 -0
  154. package/src/agent/output-extraction-pi.js +124 -0
  155. package/src/agent/output-extraction-pi.ts +137 -0
  156. package/src/agent/output-extraction-types.js +2 -0
  157. package/src/agent/output-extraction-types.ts +49 -0
  158. package/src/agent/output-extraction.js +17 -617
  159. package/src/agent/output-extraction.ts +30 -0
  160. package/src/agent/output-reformatter-errors.js +83 -0
  161. package/src/agent/output-reformatter-errors.ts +106 -0
  162. package/src/agent/output-reformatter-types.js +2 -0
  163. package/src/agent/output-reformatter-types.ts +86 -0
  164. package/src/agent/output-reformatter.js +140 -185
  165. package/src/agent/output-reformatter.ts +238 -0
  166. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  167. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  168. package/src/agent/pi-terminal-lifecycle.js +186 -206
  169. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  170. package/src/agent/provider-control-plane.js +22 -21
  171. package/src/agent/provider-control-plane.ts +52 -0
  172. package/src/agent/provider-terminal-failure-types.js +2 -0
  173. package/src/agent/provider-terminal-failure-types.ts +60 -0
  174. package/src/agent/provider-terminal-failure.js +194 -191
  175. package/src/agent/provider-terminal-failure.ts +262 -0
  176. package/src/agent/rate-limit-backoff.js +31 -74
  177. package/src/agent/rate-limit-backoff.ts +71 -0
  178. package/src/agent/schema-utils.js +85 -125
  179. package/src/agent/schema-utils.ts +148 -0
  180. package/src/agent/structured-output-error.js +34 -33
  181. package/src/agent/structured-output-error.ts +105 -0
  182. package/src/agent/validation-platform.js +27 -27
  183. package/src/agent/validation-platform.ts +49 -0
  184. package/src/agent-cli-provider/adapters/codex.ts +3 -1
  185. package/src/attach/attach-client.js +232 -405
  186. package/src/attach/attach-client.ts +300 -0
  187. package/src/attach/attach-server-cleanup.js +43 -0
  188. package/src/attach/attach-server-cleanup.ts +39 -0
  189. package/src/attach/attach-server-clients.js +117 -0
  190. package/src/attach/attach-server-clients.ts +122 -0
  191. package/src/attach/attach-server-events.js +38 -0
  192. package/src/attach/attach-server-events.ts +36 -0
  193. package/src/attach/attach-server-pty.js +45 -0
  194. package/src/attach/attach-server-pty.ts +64 -0
  195. package/src/attach/attach-server-runtime.js +73 -0
  196. package/src/attach/attach-server-runtime.ts +62 -0
  197. package/src/attach/attach-server-socket.js +28 -0
  198. package/src/attach/attach-server-socket.ts +23 -0
  199. package/src/attach/attach-server-types.js +2 -0
  200. package/src/attach/attach-server-types.ts +82 -0
  201. package/src/attach/attach-server.js +106 -523
  202. package/src/attach/attach-server.ts +158 -0
  203. package/src/attach/index.js +18 -35
  204. package/src/attach/index.ts +18 -0
  205. package/src/attach/protocol.js +95 -184
  206. package/src/attach/protocol.ts +181 -0
  207. package/src/attach/ring-buffer.js +76 -102
  208. package/src/attach/ring-buffer.ts +109 -0
  209. package/src/attach/send-input.js +64 -75
  210. package/src/attach/send-input.ts +94 -0
  211. package/src/attach/socket-discovery.js +164 -218
  212. package/src/attach/socket-discovery.ts +230 -0
  213. package/src/attach/socket-paths.js +42 -61
  214. package/src/attach/socket-paths.ts +81 -0
  215. package/src/claude-credentials.js +51 -54
  216. package/src/claude-credentials.ts +89 -0
  217. package/src/cluster/generated/protocol-schema.ts +1 -1
  218. package/src/cluster/generated/protocol.ts +2 -1
  219. package/src/command-proofs.js +110 -141
  220. package/src/command-proofs.ts +216 -0
  221. package/src/config-router.js +81 -73
  222. package/src/config-router.ts +131 -0
  223. package/src/copy-worker.js +53 -29
  224. package/src/copy-worker.ts +75 -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/ledger-sequence.js +45 -48
  232. package/src/ledger-sequence.ts +63 -0
  233. package/src/legacy-lib/clusters-registry.ts +40 -0
  234. package/src/legacy-lib/completion.ts +148 -0
  235. package/src/legacy-lib/compose-utils.ts +102 -0
  236. package/src/legacy-lib/detached-startup.ts +449 -0
  237. package/src/legacy-lib/docker-config.ts +282 -0
  238. package/src/legacy-lib/docker-env-auth.ts +116 -0
  239. package/src/legacy-lib/git-remote-utils.ts +244 -0
  240. package/src/legacy-lib/id-detector.ts +57 -0
  241. package/src/legacy-lib/js-yaml.d.ts +3 -0
  242. package/src/legacy-lib/omelette.d.ts +15 -0
  243. package/src/legacy-lib/path-check.ts +89 -0
  244. package/src/legacy-lib/process-liveness.ts +36 -0
  245. package/src/legacy-lib/provider-credential-path.ts +57 -0
  246. package/src/legacy-lib/provider-defaults.ts +114 -0
  247. package/src/legacy-lib/provider-detection.ts +67 -0
  248. package/src/legacy-lib/provider-names.ts +126 -0
  249. package/src/legacy-lib/repo-settings.ts +88 -0
  250. package/src/legacy-lib/run-mode.ts +58 -0
  251. package/src/legacy-lib/run-plan.ts +49 -0
  252. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  253. package/src/legacy-lib/settings-defaults.ts +212 -0
  254. package/src/legacy-lib/settings-error.ts +8 -0
  255. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  256. package/src/legacy-lib/settings-models.ts +124 -0
  257. package/src/legacy-lib/settings-storage.ts +277 -0
  258. package/src/legacy-lib/settings-validation.ts +220 -0
  259. package/src/legacy-lib/settings.ts +87 -0
  260. package/src/legacy-lib/setup-apply-types.ts +70 -0
  261. package/src/legacy-lib/setup-apply.ts +456 -0
  262. package/src/legacy-lib/setup-journal.ts +185 -0
  263. package/src/legacy-lib/setup-plan-types.ts +96 -0
  264. package/src/legacy-lib/setup-plan.ts +500 -0
  265. package/src/legacy-lib/setup-undo.ts +142 -0
  266. package/src/legacy-lib/start-cluster-config.ts +124 -0
  267. package/src/legacy-lib/start-cluster-environment.ts +165 -0
  268. package/src/legacy-lib/start-cluster-run-options.ts +279 -0
  269. package/src/legacy-lib/start-cluster.ts +237 -0
  270. package/src/legacy-lib/stream-json-parser.ts +88 -0
  271. package/src/message-buffer.js +55 -71
  272. package/src/message-buffer.ts +107 -0
  273. package/src/message-bus-bridge.js +92 -133
  274. package/src/message-bus-bridge.ts +149 -0
  275. package/src/name-generator-shared.js +220 -0
  276. package/src/name-generator-shared.ts +231 -0
  277. package/src/name-generator.js +8 -217
  278. package/src/name-generator.ts +27 -0
  279. package/src/omp-blob-root.js +83 -64
  280. package/src/omp-blob-root.ts +116 -0
  281. package/src/omp-config-overlay.js +65 -38
  282. package/src/omp-config-overlay.ts +110 -0
  283. package/src/omp-execution-fingerprint.js +38 -43
  284. package/src/omp-execution-fingerprint.ts +92 -0
  285. package/src/omp-session-limits.js +10 -15
  286. package/src/omp-session-limits.ts +53 -0
  287. package/src/omp-session-partition.js +2 -2
  288. package/src/omp-session-verifier.js +1 -1
  289. package/src/orchestrator.js +19 -4
  290. package/src/providers/anthropic/index.js +3 -1
  291. package/src/providers/anthropic/index.ts +13 -0
  292. package/src/providers/capabilities.js +19 -27
  293. package/src/providers/capabilities.ts +44 -0
  294. package/src/providers/google/index.js +3 -1
  295. package/src/providers/google/index.ts +13 -0
  296. package/src/providers/openai/index.js +3 -1
  297. package/src/providers/openai/index.ts +13 -0
  298. package/src/providers/opencode/index.js +3 -1
  299. package/src/providers/opencode/index.ts +13 -0
  300. package/src/quality-gates.js +67 -127
  301. package/src/quality-gates.ts +149 -0
  302. package/src/repo-settings-access.js +40 -0
  303. package/src/repo-settings-access.ts +64 -0
  304. package/src/schemas/sub-cluster.js +127 -183
  305. package/src/schemas/sub-cluster.ts +238 -0
  306. package/src/state-snapshot-normalization.js +224 -0
  307. package/src/state-snapshot-normalization.ts +222 -0
  308. package/src/state-snapshot.js +192 -359
  309. package/src/state-snapshot.ts +291 -0
  310. package/src/state-snapshotter.js +118 -130
  311. package/src/state-snapshotter.ts +167 -0
  312. package/src/sub-cluster-wrapper.js +4 -13
  313. package/src/task-run-model-args.js +87 -124
  314. package/src/task-run-model-args.ts +204 -0
  315. package/src/task-runner.js +5 -25
  316. package/src/task-runner.ts +28 -0
  317. package/src/task-startup-error.js +73 -58
  318. package/src/task-startup-error.ts +126 -0
  319. package/src/template-validation/consensus-gate-contracts.js +2 -0
  320. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  321. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  322. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  323. package/src/template-validation/consensus-gate-stage.js +34 -0
  324. package/src/template-validation/consensus-gate-stage.ts +56 -0
  325. package/src/template-validation/random-topology-contracts.js +2 -0
  326. package/src/template-validation/random-topology-contracts.ts +54 -0
  327. package/src/template-validation/random-topology-dispatch.js +25 -0
  328. package/src/template-validation/random-topology-dispatch.ts +33 -0
  329. package/src/template-validation/random-topology-message-loop.js +53 -0
  330. package/src/template-validation/random-topology-message-loop.ts +73 -0
  331. package/src/template-validation/random-topology-operations.js +79 -0
  332. package/src/template-validation/random-topology-operations.ts +101 -0
  333. package/src/template-validation/random-topology-runtime.js +25 -0
  334. package/src/template-validation/random-topology-runtime.ts +43 -0
  335. package/src/template-validation/random-topology-scenario.js +52 -0
  336. package/src/template-validation/random-topology-scenario.ts +57 -0
  337. package/src/template-validation/random-topology-schema.js +159 -0
  338. package/src/template-validation/random-topology-schema.ts +190 -0
  339. package/src/template-validation/random-topology-state.js +28 -0
  340. package/src/template-validation/random-topology-state.ts +30 -0
  341. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  342. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  343. package/src/template-validation/random-topology-trigger.js +75 -0
  344. package/src/template-validation/random-topology-trigger.ts +88 -0
  345. package/src/template-validation/report-formatter.js +40 -46
  346. package/src/template-validation/report-formatter.ts +101 -0
  347. package/src/template-validation/simulate-consensus-gates.js +111 -302
  348. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  349. package/src/template-validation/simulate-random-topology.js +26 -519
  350. package/src/template-validation/simulate-random-topology.ts +57 -0
  351. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  352. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  353. package/src/template-validation/simulation-agent-runtime.js +25 -0
  354. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  355. package/src/template-validation/simulation-agent.js +29 -0
  356. package/src/template-validation/simulation-agent.ts +73 -0
  357. package/src/template-validation/simulation-runtime.js +34 -0
  358. package/src/template-validation/simulation-runtime.ts +72 -0
  359. package/src/template-validation/two-stage-contracts.js +2 -0
  360. package/src/template-validation/two-stage-contracts.ts +41 -0
  361. package/src/template-validation/two-stage-inputs.js +21 -0
  362. package/src/template-validation/two-stage-inputs.ts +29 -0
  363. package/src/template-validation/two-stage-results.js +30 -0
  364. package/src/template-validation/two-stage-results.ts +40 -0
  365. package/src/template-validation/two-stage-scenario.js +86 -0
  366. package/src/template-validation/two-stage-scenario.ts +120 -0
  367. package/src/worktree-claude-config.js +182 -220
  368. package/src/worktree-claude-config.ts +272 -0
  369. package/src/worktree-tooling-env.js +103 -125
  370. package/src/worktree-tooling-env.ts +142 -0
  371. package/task-lib/completion.js +2 -3
  372. package/task-lib/completion.ts +9 -0
  373. package/task-lib/config.js +1 -4
  374. package/task-lib/config.ts +11 -0
  375. package/task-lib/name-generator.js +4 -226
  376. package/task-lib/name-generator.ts +11 -0
  377. package/task-lib/omp-session-cleanup.js +1 -1
  378. package/task-lib/omp-storage-root.js +8 -12
  379. package/task-lib/omp-storage-root.ts +62 -0
  380. package/task-lib/process-termination.js +143 -166
  381. package/task-lib/process-termination.ts +268 -0
@@ -0,0 +1,148 @@
1
+ import os = require('os');
2
+ import path = require('path');
3
+ import type { Command, Option } from 'commander';
4
+ import omelette = require('omelette');
5
+ import clustersRegistry = require('./clusters-registry');
6
+
7
+ interface ClustersRegistryFacade {
8
+ readClustersFileSync(storageDir: string): unknown;
9
+ }
10
+
11
+ interface CompletionDependencies {
12
+ listClusterIds?: () => unknown;
13
+ }
14
+
15
+ const { readClustersFileSync }: ClustersRegistryFacade = clustersRegistry;
16
+
17
+ const CLUSTER_ID_COMMANDS = new Set([
18
+ 'attach',
19
+ 'export',
20
+ 'finish',
21
+ 'kill',
22
+ 'logs',
23
+ 'resume',
24
+ 'status',
25
+ 'stop',
26
+ ]);
27
+
28
+ function commandNames(command: Command): string[] {
29
+ return [command.name(), ...command.aliases()];
30
+ }
31
+
32
+ function visibleCommands(command: Command): Command[] {
33
+ return command.createHelp().visibleCommands(command);
34
+ }
35
+
36
+ function visibleOptions(command: Command): Option[] {
37
+ return command.createHelp().visibleOptions(command);
38
+ }
39
+
40
+ function optionNames(option: Option): string[] {
41
+ return [option.short, option.long].filter((name): name is string => Boolean(name));
42
+ }
43
+
44
+ function findSubcommand(command: Command, token: string): Command | undefined {
45
+ return visibleCommands(command).find((candidate) => commandNames(candidate).includes(token));
46
+ }
47
+
48
+ function findOption(command: Command, token: string): Option | undefined {
49
+ const optionToken = token.split('=', 1)[0] ?? '';
50
+ return visibleOptions(command).find((option) => optionNames(option).includes(optionToken));
51
+ }
52
+
53
+ function parseCompletionLine(line: string): { completed: string[]; current: string } {
54
+ const trailingSpace = /\s$/.test(line);
55
+ const tokens = line.trim().split(/\s+/).filter(Boolean);
56
+ tokens.shift();
57
+ const current = trailingSpace ? '' : (tokens.pop() ?? '');
58
+ return { completed: tokens, current };
59
+ }
60
+
61
+ function resolveCommandContext(
62
+ program: Command,
63
+ tokens: string[]
64
+ ): { command: Command; commandPath: string } {
65
+ let command = program;
66
+ const pathParts: string[] = [];
67
+ let expectsOptionValue = false;
68
+ let sawPositional = false;
69
+
70
+ for (const token of tokens) {
71
+ if (expectsOptionValue) {
72
+ expectsOptionValue = false;
73
+ continue;
74
+ }
75
+
76
+ const option = findOption(command, token);
77
+ if (option) {
78
+ expectsOptionValue = !token.includes('=') && (option.required || option.optional);
79
+ continue;
80
+ }
81
+ if (token.startsWith('-')) continue;
82
+
83
+ const subcommand = sawPositional ? undefined : findSubcommand(command, token);
84
+ if (subcommand) {
85
+ command = subcommand;
86
+ pathParts.push(subcommand.name());
87
+ continue;
88
+ }
89
+ sawPositional = true;
90
+ }
91
+
92
+ return { command, commandPath: pathParts.join(' ') };
93
+ }
94
+
95
+ function defaultListClusterIds(): string[] {
96
+ const homeDir =
97
+ process.env.ZEROSHOT_HOME || process.env.HOME || process.env.USERPROFILE || os.homedir();
98
+ const registry = readClustersFileSync(path.join(homeDir, '.zeroshot'));
99
+ // Preserve the legacy failure behavior if a corrupt registry is not an object.
100
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
101
+ return Object.keys(registry as object);
102
+ }
103
+
104
+ function safeDynamicIds(commandPath: string, listClusterIds: () => unknown): string[] {
105
+ if (!CLUSTER_ID_COMMANDS.has(commandPath)) return [];
106
+ try {
107
+ const ids = listClusterIds();
108
+ if (!Array.isArray(ids)) return [];
109
+ const unknownIds: unknown[] = ids;
110
+ return unknownIds.filter((id): id is string => typeof id === 'string' && id.length > 0);
111
+ } catch {
112
+ return [];
113
+ }
114
+ }
115
+
116
+ function getCompletionCandidates(
117
+ program: Command,
118
+ line: string,
119
+ deps: CompletionDependencies = {}
120
+ ): string[] {
121
+ const { completed, current } = parseCompletionLine(line);
122
+ const { command, commandPath } = resolveCommandContext(program, completed);
123
+ const listClusterIds = deps.listClusterIds || defaultListClusterIds;
124
+ const candidates = [
125
+ ...visibleCommands(command).flatMap(commandNames),
126
+ ...visibleOptions(command).flatMap(optionNames),
127
+ ...safeDynamicIds(commandPath, listClusterIds),
128
+ ];
129
+
130
+ return [...new Set(candidates)].filter((candidate) => candidate.startsWith(current));
131
+ }
132
+
133
+ function setupCompletion(
134
+ program: Command,
135
+ deps: CompletionDependencies = {}
136
+ ): ReturnType<typeof omelette> {
137
+ const complete = omelette('zeroshot');
138
+ complete.on('complete', (_fragment, data) => {
139
+ data.reply(getCompletionCandidates(program, data.line, deps));
140
+ });
141
+ complete.init();
142
+ return complete;
143
+ }
144
+
145
+ export = {
146
+ getCompletionCandidates,
147
+ setupCompletion,
148
+ };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Docker Compose teardown resolution for worktree cleanup.
3
+ *
4
+ * Zeroshot never runs `docker compose up` — any compose file found in a worktree
5
+ * belongs to the target repo, not to zeroshot. Tearing it down is only safe when
6
+ * the resolved Compose project name is scoped to the worktree directory itself
7
+ * (i.e. nothing pins it to the host's real, possibly-already-running project).
8
+ */
9
+
10
+ import fs = require('fs');
11
+ import path = require('path');
12
+ import yaml = require('js-yaml');
13
+
14
+ const COMPOSE_FILENAMES = [
15
+ 'docker-compose.yml',
16
+ 'docker-compose.yaml',
17
+ 'compose.yml',
18
+ 'compose.yaml',
19
+ ] as const;
20
+
21
+ interface ComposeTeardownResolution {
22
+ readonly args?: string[];
23
+ readonly composePath?: string;
24
+ readonly reason?: string;
25
+ readonly shouldTeardown: boolean;
26
+ }
27
+
28
+ /**
29
+ * Reproduce Docker Compose's default project-name normalization
30
+ * (compose-go NormalizeProjectName: lowercase -> keep [a-z0-9_-] -> trim leading '_'/'-').
31
+ */
32
+ function normalizeComposeProjectName(name: string): string {
33
+ return name
34
+ .toLowerCase()
35
+ .replace(/[^a-z0-9_-]/g, '')
36
+ .replace(/^[-_]+/, '');
37
+ }
38
+
39
+ /**
40
+ * Decide whether it's safe to run `docker compose down` in a worktree, and with what args.
41
+ * Never includes `--volumes` — automatic cleanup must not delete named volumes.
42
+ * Skips teardown entirely when the Compose project name is pinned (top-level `name:`
43
+ * in the compose file, or `COMPOSE_PROJECT_NAME` env var), since that resolves to a
44
+ * shared/host project zeroshot did not create.
45
+ */
46
+ function resolveWorktreeComposeTeardown(worktreePath: string): ComposeTeardownResolution {
47
+ let composePath: string | null = null;
48
+ for (const filename of COMPOSE_FILENAMES) {
49
+ const candidate = path.join(worktreePath, filename);
50
+ if (fs.existsSync(candidate)) {
51
+ composePath = candidate;
52
+ break;
53
+ }
54
+ }
55
+
56
+ if (!composePath) {
57
+ return { shouldTeardown: false, reason: 'no compose file' };
58
+ }
59
+
60
+ if (
61
+ typeof process.env.COMPOSE_PROJECT_NAME === 'string' &&
62
+ process.env.COMPOSE_PROJECT_NAME.trim() !== ''
63
+ ) {
64
+ return {
65
+ shouldTeardown: false,
66
+ reason: 'pinned compose project name (shared host project)',
67
+ composePath,
68
+ };
69
+ }
70
+
71
+ try {
72
+ const contents = fs.readFileSync(composePath, 'utf8');
73
+ const parsed = yaml.load(contents);
74
+ if (parsed && typeof parsed === 'object' && Reflect.get(parsed, 'name')) {
75
+ return {
76
+ shouldTeardown: false,
77
+ reason: 'pinned compose project name (shared host project)',
78
+ composePath,
79
+ };
80
+ }
81
+ } catch {
82
+ // Fail safe: if the compose file can't be read/parsed, we cannot confirm project
83
+ // identity is worktree-scoped, so never tear down.
84
+ return { shouldTeardown: false, reason: 'compose file unreadable or unparsable', composePath };
85
+ }
86
+
87
+ return {
88
+ shouldTeardown: true,
89
+ composePath,
90
+ args: [
91
+ 'compose',
92
+ '-p',
93
+ normalizeComposeProjectName(path.basename(worktreePath)),
94
+ 'down',
95
+ '--remove-orphans',
96
+ '--timeout',
97
+ '10',
98
+ ],
99
+ };
100
+ }
101
+
102
+ export = { resolveWorktreeComposeTeardown, normalizeComposeProjectName };
@@ -0,0 +1,449 @@
1
+ import fs = require('fs');
2
+ import os = require('os');
3
+ import path = require('path');
4
+
5
+ interface LockOptions {
6
+ lockfilePath: string;
7
+ stale: number;
8
+ retries: {
9
+ retries: number;
10
+ minTimeout: number;
11
+ maxTimeout: number;
12
+ randomize: boolean;
13
+ };
14
+ }
15
+
16
+ type ReleaseLock = () => Promise<void>;
17
+
18
+ interface LockfileFacade {
19
+ lock(filePath: string, options: LockOptions): Promise<ReleaseLock>;
20
+ }
21
+
22
+ interface RunOptions extends Record<string, unknown> {
23
+ autoMerge?: unknown;
24
+ closeIssue?: unknown;
25
+ docker?: unknown;
26
+ mergeQueue?: unknown;
27
+ pr?: unknown;
28
+ prBase?: unknown;
29
+ ship?: unknown;
30
+ worktree?: unknown;
31
+ }
32
+
33
+ interface RunPlan {
34
+ isolation: 'none' | 'worktree' | 'docker';
35
+ delivery: 'none' | 'pr' | 'ship';
36
+ autoMerge: boolean;
37
+ }
38
+
39
+ interface RunPlanFacade {
40
+ resolveRunPlan(options?: RunOptions): Readonly<RunPlan>;
41
+ }
42
+
43
+ interface ProcessLivenessFacade {
44
+ isProcessRunning(pid: unknown): boolean;
45
+ }
46
+
47
+ interface IsolationManagerFacade {
48
+ getDetachedSetupResources(clusterId: string): unknown;
49
+ }
50
+
51
+ interface ClusterRecord extends Record<string, unknown> {
52
+ createdAt?: number;
53
+ id?: string;
54
+ pid?: number | null;
55
+ resumeDaemonPid?: number | null;
56
+ setupLogPath?: string | null;
57
+ state?: string;
58
+ }
59
+
60
+ type ClusterRegistry = Record<string, ClusterRecord>;
61
+ type ClusterUpdater = (clusters: ClusterRegistry) => ClusterRegistry | void;
62
+
63
+ interface DetachedSetupParams {
64
+ clusterId: string;
65
+ pid?: number;
66
+ storageDir?: string;
67
+ logPath?: string | null;
68
+ worktree?: unknown;
69
+ runOptions?: RunOptions;
70
+ cwd?: string;
71
+ }
72
+
73
+ interface ClusterIdentityParams {
74
+ clusterId: string;
75
+ storageDir?: string;
76
+ }
77
+
78
+ interface SetupFailureParams extends ClusterIdentityParams {
79
+ error: unknown;
80
+ logPath?: string | null;
81
+ }
82
+
83
+ interface ResumePatchParams extends ClusterIdentityParams {
84
+ daemonPid: number;
85
+ }
86
+
87
+ interface RegistrationWaitParams extends ClusterIdentityParams {
88
+ timeoutMs?: number;
89
+ pollMs?: number;
90
+ daemonPid?: number;
91
+ logPath?: string | null;
92
+ }
93
+
94
+ interface OwnershipWaitParams extends ResumePatchParams {
95
+ timeoutMs?: number;
96
+ pollMs?: number;
97
+ }
98
+
99
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
100
+ const lockfile: LockfileFacade = require('proper-lockfile');
101
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
102
+ const runPlan: RunPlanFacade = require('./run-plan');
103
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
104
+ const processLiveness: ProcessLivenessFacade = require('./process-liveness');
105
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
106
+ const IsolationManager: IsolationManagerFacade = require('../src/isolation-manager');
107
+
108
+ const { resolveRunPlan } = runPlan;
109
+ const { isProcessRunning } = processLiveness;
110
+
111
+ const DEFAULT_WAIT_TIMEOUT_SECONDS = 180;
112
+ const DEFAULT_WAIT_POLL_MS = 1000;
113
+ const CLUSTERS_LOCK_STALE_MS = 5000;
114
+ const DEFAULT_OWNERSHIP_TIMEOUT_MS = 10000;
115
+
116
+ function isClusterRegistry(value: unknown): value is ClusterRegistry {
117
+ return value !== null && typeof value === 'object';
118
+ }
119
+
120
+ function hasErrorCode(error: unknown, code: string): boolean {
121
+ return error !== null && typeof error === 'object' && 'code' in error && error.code === code;
122
+ }
123
+
124
+ function getStorageDir(storageDir?: string | null): string {
125
+ return storageDir || path.join(os.homedir(), '.zeroshot');
126
+ }
127
+
128
+ function getClustersFilePath(storageDir?: string | null): string {
129
+ return path.join(getStorageDir(storageDir), 'clusters.json');
130
+ }
131
+
132
+ function resolveWaitTimeoutMs(waitTimeoutSeconds: unknown): number {
133
+ const parsed = Number(waitTimeoutSeconds);
134
+ if (!Number.isFinite(parsed) || parsed <= 0) {
135
+ return DEFAULT_WAIT_TIMEOUT_SECONDS * 1000;
136
+ }
137
+ return Math.floor(parsed * 1000);
138
+ }
139
+
140
+ // Kept as an alias: this module used to carry its own copy of this check.
141
+ const isProcessAlive = isProcessRunning;
142
+
143
+ function isClusterRegistered(clusterId: string, storageDir?: string): boolean {
144
+ const clustersFile = getClustersFilePath(storageDir);
145
+ if (!fs.existsSync(clustersFile)) {
146
+ return false;
147
+ }
148
+
149
+ try {
150
+ const raw = fs.readFileSync(clustersFile, 'utf8');
151
+ const parsed: unknown = JSON.parse(raw);
152
+ return isClusterRegistry(parsed) && Boolean(parsed[clusterId]);
153
+ } catch {
154
+ return false;
155
+ }
156
+ }
157
+
158
+ function ensureStorageDir(storageDir?: string): string {
159
+ const resolvedStorageDir = getStorageDir(storageDir);
160
+ fs.mkdirSync(resolvedStorageDir, { recursive: true });
161
+ return resolvedStorageDir;
162
+ }
163
+
164
+ function ensureClustersFile(storageDir?: string): string {
165
+ const resolvedStorageDir = ensureStorageDir(storageDir);
166
+ const clustersFile = getClustersFilePath(resolvedStorageDir);
167
+ try {
168
+ fs.writeFileSync(clustersFile, '{}', { flag: 'wx', mode: 0o600 });
169
+ } catch (error: unknown) {
170
+ if (!hasErrorCode(error, 'EEXIST')) {
171
+ throw error;
172
+ }
173
+ }
174
+ return clustersFile;
175
+ }
176
+
177
+ function readClustersFile(clustersFile: string): ClusterRegistry {
178
+ try {
179
+ const parsed: unknown = JSON.parse(fs.readFileSync(clustersFile, 'utf8'));
180
+ return isClusterRegistry(parsed) ? parsed : {};
181
+ } catch {
182
+ return {};
183
+ }
184
+ }
185
+
186
+ async function updateClustersFile(
187
+ storageDir: string | undefined,
188
+ updater: ClusterUpdater
189
+ ): Promise<ClusterRegistry> {
190
+ const clustersFile = ensureClustersFile(storageDir);
191
+ const lockfilePath = path.join(path.dirname(clustersFile), 'clusters.json.lock');
192
+ let release: ReleaseLock | undefined;
193
+
194
+ try {
195
+ release = await lockfile.lock(clustersFile, {
196
+ lockfilePath,
197
+ stale: CLUSTERS_LOCK_STALE_MS,
198
+ retries: {
199
+ retries: 20,
200
+ minTimeout: 100,
201
+ maxTimeout: 250,
202
+ randomize: true,
203
+ },
204
+ });
205
+
206
+ const clusters = readClustersFile(clustersFile);
207
+ const updated = updater(clusters) || clusters;
208
+ fs.writeFileSync(clustersFile, JSON.stringify(updated, null, 2));
209
+ return updated;
210
+ } finally {
211
+ if (release) {
212
+ await release();
213
+ }
214
+ }
215
+ }
216
+
217
+ async function registerDetachedSetupCluster({
218
+ clusterId,
219
+ pid,
220
+ storageDir,
221
+ logPath,
222
+ worktree,
223
+ runOptions = {},
224
+ cwd,
225
+ }: DetachedSetupParams): Promise<void> {
226
+ const plan = resolveRunPlan(runOptions);
227
+ const setupResources =
228
+ plan.isolation === 'docker' ? IsolationManager.getDetachedSetupResources(clusterId) : null;
229
+ await updateClustersFile(storageDir, (clusters) => {
230
+ clusters[clusterId] = {
231
+ id: clusterId,
232
+ state: 'setup',
233
+ createdAt: Date.now(),
234
+ pid: typeof pid === 'number' && Number.isInteger(pid) ? pid : null,
235
+ setupLogPath: logPath || null,
236
+ setupStartedAt: Date.now(),
237
+ setupStage: 'starting',
238
+ autoPr: plan.delivery !== 'none',
239
+ prOptions: runOptions.prBase
240
+ ? {
241
+ prBase: runOptions.prBase,
242
+ mergeQueue: runOptions.mergeQueue || false,
243
+ closeIssue: runOptions.closeIssue || null,
244
+ autoMerge: plan.autoMerge,
245
+ cwd: cwd || null,
246
+ }
247
+ : null,
248
+ worktree: worktree || null,
249
+ config: null,
250
+ issue: null,
251
+ isolation: null,
252
+ agentStates: [],
253
+ failureInfo: null,
254
+ setupResources,
255
+ provisional: true,
256
+ };
257
+ return clusters;
258
+ });
259
+ }
260
+
261
+ async function removeDetachedSetupCluster({
262
+ clusterId,
263
+ storageDir,
264
+ }: ClusterIdentityParams): Promise<void> {
265
+ await updateClustersFile(storageDir, (clusters) => {
266
+ delete clusters[clusterId];
267
+ return clusters;
268
+ });
269
+ }
270
+
271
+ async function markDetachedSetupFailed({
272
+ clusterId,
273
+ storageDir,
274
+ error,
275
+ logPath,
276
+ }: SetupFailureParams): Promise<void> {
277
+ await updateClustersFile(storageDir, (clusters) => {
278
+ const existing = clusters[clusterId] || { id: clusterId, createdAt: Date.now() };
279
+ clusters[clusterId] = {
280
+ ...existing,
281
+ state: 'failed',
282
+ pid: null,
283
+ setupLogPath: existing.setupLogPath || logPath || null,
284
+ setupFinishedAt: Date.now(),
285
+ failureInfo: {
286
+ type: 'setup',
287
+ error: error instanceof Error ? error.message : String(error),
288
+ timestamp: Date.now(),
289
+ },
290
+ provisional: true,
291
+ };
292
+ return clusters;
293
+ });
294
+ }
295
+
296
+ function sleep(ms: number): Promise<void> {
297
+ return new Promise((resolve) => setTimeout(resolve, ms));
298
+ }
299
+
300
+ function formatLogHint(logPath?: string | null): string {
301
+ return logPath ? ` Check log: ${logPath}` : '';
302
+ }
303
+
304
+ async function waitForClusterRegistration({
305
+ clusterId,
306
+ timeoutMs,
307
+ pollMs = DEFAULT_WAIT_POLL_MS,
308
+ storageDir,
309
+ daemonPid,
310
+ logPath,
311
+ }: RegistrationWaitParams): Promise<{ ready: true; elapsedMs: number }> {
312
+ const effectiveTimeoutMs =
313
+ typeof timeoutMs === 'number' && Number.isFinite(timeoutMs) && timeoutMs > 0
314
+ ? timeoutMs
315
+ : DEFAULT_WAIT_TIMEOUT_SECONDS * 1000;
316
+ const startedAt = Date.now();
317
+ const deadline = startedAt + effectiveTimeoutMs;
318
+ const logHint = formatLogHint(logPath);
319
+
320
+ while (Date.now() < deadline) {
321
+ if (isClusterRegistered(clusterId, storageDir)) {
322
+ return { ready: true, elapsedMs: Date.now() - startedAt };
323
+ }
324
+
325
+ if (daemonPid && !isProcessAlive(daemonPid)) {
326
+ throw new Error(
327
+ `Detached daemon exited before cluster "${clusterId}" registered in storage.${logHint}`
328
+ );
329
+ }
330
+
331
+ await sleep(pollMs);
332
+ }
333
+
334
+ const timeoutSeconds = Math.ceil(effectiveTimeoutMs / 1000);
335
+ throw new Error(
336
+ `Timed out after ${timeoutSeconds}s waiting for cluster "${clusterId}" to appear in status/list.${logHint}`
337
+ );
338
+ }
339
+
340
+ /**
341
+ * Atomically claim the right to resume-daemon an existing cluster record.
342
+ * Ownership for the handoff is tracked separately from cluster.pid/state so
343
+ * orchestrator.resume() can still perform its own eligibility check.
344
+ */
345
+ async function patchDetachedResumeCluster({
346
+ clusterId,
347
+ daemonPid,
348
+ storageDir,
349
+ }: ResumePatchParams): Promise<void> {
350
+ await updateClustersFile(storageDir, (clusters) => {
351
+ const existing = clusters[clusterId];
352
+ if (!existing) {
353
+ throw new Error(`Cannot start resume daemon: cluster "${clusterId}" not found in registry`);
354
+ }
355
+ if (existing.resumeDaemonPid && isProcessRunning(existing.resumeDaemonPid)) {
356
+ const ownership = `Cluster "${clusterId}" already has a live resume daemon`;
357
+ throw new Error(
358
+ `${ownership} (PID ${existing.resumeDaemonPid}); refusing to start a second one`
359
+ );
360
+ }
361
+ if (existing.state === 'running' && existing.pid && isProcessRunning(existing.pid)) {
362
+ throw new Error(
363
+ `Cluster "${clusterId}" is already running (PID ${existing.pid}); refusing to start a second resume daemon`
364
+ );
365
+ }
366
+ clusters[clusterId] = { ...existing, resumeDaemonPid: daemonPid };
367
+ return clusters;
368
+ });
369
+ }
370
+
371
+ /**
372
+ * Undo a resume handoff that did not complete so a dead daemon cannot leave
373
+ * the cluster stuck in a running state.
374
+ */
375
+ async function revertDetachedResumeCluster({
376
+ clusterId,
377
+ storageDir,
378
+ error,
379
+ }: SetupFailureParams): Promise<void> {
380
+ await updateClustersFile(storageDir, (clusters) => {
381
+ const existing = clusters[clusterId];
382
+ if (!existing) return clusters;
383
+ clusters[clusterId] = {
384
+ ...existing,
385
+ state: 'failed',
386
+ pid: null,
387
+ resumeDaemonPid: null,
388
+ failureInfo: {
389
+ type: 'resume-daemon',
390
+ error: error instanceof Error ? error.message : String(error),
391
+ timestamp: Date.now(),
392
+ },
393
+ };
394
+ return clusters;
395
+ });
396
+ }
397
+
398
+ function getRegisteredResumeDaemonPid(clusterId: string, storageDir?: string): number | null {
399
+ const clustersFile = getClustersFilePath(storageDir);
400
+ if (!fs.existsSync(clustersFile)) {
401
+ return null;
402
+ }
403
+ try {
404
+ const parsed: unknown = JSON.parse(fs.readFileSync(clustersFile, 'utf8'));
405
+ if (!isClusterRegistry(parsed)) {
406
+ return null;
407
+ }
408
+ return parsed[clusterId]?.resumeDaemonPid ?? null;
409
+ } catch {
410
+ return null;
411
+ }
412
+ }
413
+
414
+ /**
415
+ * Daemon-side half of the resume handoff: wait until the registry shows this
416
+ * process's PID as resumeDaemonPid before touching the cluster.
417
+ */
418
+ async function waitForResumeOwnership({
419
+ clusterId,
420
+ daemonPid,
421
+ storageDir,
422
+ timeoutMs = DEFAULT_OWNERSHIP_TIMEOUT_MS,
423
+ pollMs = DEFAULT_WAIT_POLL_MS,
424
+ }: OwnershipWaitParams): Promise<boolean> {
425
+ const deadline = Date.now() + timeoutMs;
426
+ while (Date.now() < deadline) {
427
+ if (getRegisteredResumeDaemonPid(clusterId, storageDir) === daemonPid) {
428
+ return true;
429
+ }
430
+ await sleep(pollMs);
431
+ }
432
+ return getRegisteredResumeDaemonPid(clusterId, storageDir) === daemonPid;
433
+ }
434
+
435
+ export = {
436
+ DEFAULT_WAIT_TIMEOUT_SECONDS,
437
+ getClustersFilePath,
438
+ getRegisteredResumeDaemonPid,
439
+ isClusterRegistered,
440
+ isProcessAlive,
441
+ markDetachedSetupFailed,
442
+ patchDetachedResumeCluster,
443
+ registerDetachedSetupCluster,
444
+ removeDetachedSetupCluster,
445
+ resolveWaitTimeoutMs,
446
+ revertDetachedResumeCluster,
447
+ waitForClusterRegistration,
448
+ waitForResumeOwnership,
449
+ };