@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
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * `zeroshot setup apply` — writes decisions from #A's plan/decision contract
3
4
  * (lib/setup-plan.js) to global settings, repo-local settings, and the undo
@@ -10,311 +11,313 @@
10
11
  * — a settings key nobody reads is dead config, the exact drift the
11
12
  * canonical-path rule (issue #605) forbids.
12
13
  */
13
-
14
+ // These CommonJS paths intentionally resolve beside the emitted module in lib/.
15
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
14
16
  const { resolveDecisionPath, domainFor, isConsumedPath, CONSUMED_PATHS } = require('./setup-plan');
17
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
15
18
  const { validateMountConfig, validateEnvPassthrough } = require('./docker-config');
19
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
16
20
  const { VALID_PROVIDERS } = require('./provider-names');
17
21
  const VALID_LEVELS = Object.freeze(['level1', 'level2', 'level3']);
18
- const {
19
- loadJournal,
20
- saveJournal,
21
- upsertJournalEntry,
22
- getNestedValue,
23
- setNestedValue,
24
- deepEqual,
25
- } = require('./setup-journal');
26
-
22
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
23
+ const setupJournal = require('./setup-journal');
24
+ const { loadJournal, saveJournal, upsertJournalEntry } = setupJournal;
25
+ const { getNestedValue, setNestedValue, deepEqual } = setupJournal;
27
26
  const SECRET_PATTERN = /token|secret|password|api[_-]?key|credential/i;
28
-
27
+ function includesValue(values, value) {
28
+ return values.includes(value);
29
+ }
29
30
  function assertSecretSafePath(targetPath) {
30
- if (SECRET_PATTERN.test(targetPath)) {
31
- throw new Error(`Refusing to write secret-shaped settings path: ${targetPath}`);
32
- }
31
+ if (SECRET_PATTERN.test(targetPath)) {
32
+ throw new Error(`Refusing to write secret-shaped settings path: ${targetPath}`);
33
+ }
33
34
  }
34
-
35
35
  function domainError(decisionId, value) {
36
- return new Error(
37
- `Invalid value for decision "${decisionId}": expected ${domainFor(decisionId)}, got ${JSON.stringify(value)}`
38
- );
36
+ const expected = domainFor(decisionId);
37
+ const received = JSON.stringify(value);
38
+ return new Error(`Invalid value for decision "${decisionId}": expected ${expected}, got ${received}`);
39
39
  }
40
-
41
- // Resolve a submitted decision into the exact value stored at its canonical
42
- // settings path, validating its decision domain before any write occurs.
43
- function convertDecisionValue({ decisionId, value, globalSettings, deps }) {
44
- switch (decisionId) {
45
- case 'defaultProvider':
46
- if (typeof value !== 'string' || !deps.VALID_PROVIDERS.includes(value)) {
47
- throw domainError(decisionId, value);
48
- }
49
- return value;
50
-
51
- case 'defaultIsolation':
52
- if (!['worktree', 'docker', 'none'].includes(value)) throw domainError(decisionId, value);
53
- return value;
54
-
55
- case 'allowLocalNoIsolation':
56
- if (typeof value !== 'boolean') throw domainError(decisionId, value);
57
- return value;
58
-
59
- case 'defaultDelivery':
60
- if (!['none', 'pr', 'ship'].includes(value)) throw domainError(decisionId, value);
61
- return value;
62
-
63
- case 'defaultIssueSource':
64
- if (typeof value !== 'string' || !deps.listIssueProviders().includes(value)) {
65
- throw domainError(decisionId, value);
66
- }
67
- return value;
68
-
69
- case 'prBase':
70
- if (typeof value !== 'string' || value.trim() === '') throw domainError(decisionId, value);
71
- return value;
72
-
73
- case 'dockerMounts': {
74
- const err = validateMountConfig(value);
75
- if (err) throw new Error(`Invalid value for decision "${decisionId}": ${err}`);
76
- return value;
77
- }
78
-
79
- case 'dockerEnvPassthrough': {
80
- const err = validateEnvPassthrough(value);
81
- if (err) throw new Error(`Invalid value for decision "${decisionId}": ${err}`);
82
- return value;
83
- }
84
-
85
- case 'updatePolicy':
86
- if (!['off', 'notify', 'auto'].includes(value)) throw domainError(decisionId, value);
87
- return value;
88
-
89
- default: {
90
- if (!decisionId.startsWith('providerLevel.')) {
40
+ function convertProviderLevelDecision({ decisionId, value, globalSettings, deps, }) {
41
+ if (!decisionId.startsWith('providerLevel.')) {
91
42
  throw new Error(`Unknown decision ID: ${decisionId}`);
92
- }
93
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
43
+ }
44
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
94
45
  throw domainError(decisionId, value);
95
- }
96
- const keys = Object.keys(value).sort();
97
- const expectedKeys = ['defaultLevel', 'maxLevel', 'minLevel'];
98
- if (
99
- keys.length !== expectedKeys.length ||
46
+ }
47
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
48
+ const decisionValue = value;
49
+ // Preserve Array.prototype.sort's default UTF-16 ordering.
50
+ // eslint-disable-next-line sonarjs/no-alphabetical-sort
51
+ const keys = Object.keys(decisionValue).sort();
52
+ const expectedKeys = ['defaultLevel', 'maxLevel', 'minLevel'];
53
+ if (keys.length !== expectedKeys.length ||
100
54
  keys.some((key, index) => key !== expectedKeys[index]) ||
101
- expectedKeys.some((key) => !VALID_LEVELS.includes(value[key]))
102
- ) {
55
+ expectedKeys.some((key) => !includesValue(VALID_LEVELS, decisionValue[key]))) {
56
+ throw domainError(decisionId, value);
57
+ }
58
+ const providerName = decisionId.slice('providerLevel.'.length);
59
+ if (!deps.VALID_PROVIDERS.includes(providerName))
103
60
  throw domainError(decisionId, value);
104
- }
105
- const providerName = decisionId.slice('providerLevel.'.length);
106
- if (!deps.VALID_PROVIDERS.includes(providerName)) throw domainError(decisionId, value);
107
- const rank = (level) => VALID_LEVELS.indexOf(level);
108
- if (
109
- rank(value.minLevel) > rank(value.defaultLevel) ||
110
- rank(value.defaultLevel) > rank(value.maxLevel)
111
- ) {
61
+ const rank = (level) => VALID_LEVELS.findIndex((item) => item === level);
62
+ if (rank(decisionValue.minLevel) > rank(decisionValue.defaultLevel) ||
63
+ rank(decisionValue.defaultLevel) > rank(decisionValue.maxLevel)) {
112
64
  throw domainError(decisionId, value);
113
- }
114
- const existing = getNestedValue(globalSettings, `providerSettings.${providerName}`) || {};
115
- return { ...existing, ...value };
116
65
  }
117
- }
66
+ const existingValue = getNestedValue(globalSettings, `providerSettings.${providerName}`) || {};
67
+ // Both operands have passed the same object-domain checks used by the legacy implementation.
68
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
69
+ const existing = existingValue;
70
+ return { ...existing, ...decisionValue };
71
+ }
72
+ // Resolve a submitted decision into the exact value stored at its canonical
73
+ // settings path, validating its decision domain before any write occurs.
74
+ function convertDecisionValue({ decisionId, value, globalSettings, deps, }) {
75
+ switch (decisionId) {
76
+ case 'defaultProvider':
77
+ if (typeof value !== 'string' || !deps.VALID_PROVIDERS.includes(value)) {
78
+ throw domainError(decisionId, value);
79
+ }
80
+ return value;
81
+ case 'defaultIsolation':
82
+ if (!includesValue(['worktree', 'docker', 'none'], value)) {
83
+ throw domainError(decisionId, value);
84
+ }
85
+ return value;
86
+ case 'allowLocalNoIsolation':
87
+ if (typeof value !== 'boolean')
88
+ throw domainError(decisionId, value);
89
+ return value;
90
+ case 'defaultDelivery':
91
+ if (!includesValue(['none', 'pr', 'ship'], value))
92
+ throw domainError(decisionId, value);
93
+ return value;
94
+ case 'defaultIssueSource':
95
+ if (typeof value !== 'string' || !deps.listIssueProviders().includes(value)) {
96
+ throw domainError(decisionId, value);
97
+ }
98
+ return value;
99
+ case 'prBase':
100
+ if (typeof value !== 'string' || value.trim() === '')
101
+ throw domainError(decisionId, value);
102
+ return value;
103
+ case 'dockerMounts': {
104
+ const err = validateMountConfig(value);
105
+ if (err)
106
+ throw new Error(`Invalid value for decision "${decisionId}": ${err}`);
107
+ return value;
108
+ }
109
+ case 'dockerEnvPassthrough': {
110
+ const err = validateEnvPassthrough(value);
111
+ if (err)
112
+ throw new Error(`Invalid value for decision "${decisionId}": ${err}`);
113
+ return value;
114
+ }
115
+ case 'updatePolicy':
116
+ if (!includesValue(['off', 'notify', 'auto'], value))
117
+ throw domainError(decisionId, value);
118
+ return value;
119
+ default:
120
+ return convertProviderLevelDecision({ decisionId, value, globalSettings, deps });
121
+ }
118
122
  }
119
-
120
123
  function defaultApplyDeps() {
121
- const fs = require('fs');
122
- const { loadSettings, mutateSettings } = require('./settings');
123
- const { readRepoSettings, writeRepoSettings } = require('./repo-settings');
124
- const { checkGhAuth } = require('../src/preflight');
125
- const { listProviders: listIssueProviders } = require('../src/issue-providers');
126
-
127
- return {
128
- readFile: (filePath) => fs.readFileSync(filePath, 'utf8'),
129
- loadSettings,
130
- mutateSettings,
131
- readRepoSettings,
132
- writeRepoSettings,
133
- checkGhAuth,
134
- listIssueProviders,
135
- VALID_PROVIDERS,
136
- now: () => new Date().toISOString(),
137
- };
124
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
125
+ const fs = require('fs');
126
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
127
+ const { loadSettings, mutateSettings } = require('./settings');
128
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
129
+ const { readRepoSettings, writeRepoSettings } = require('./repo-settings');
130
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
131
+ const { checkGhAuth } = require('../src/preflight');
132
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
133
+ const { listProviders: listIssueProviders } = require('../src/issue-providers');
134
+ return {
135
+ readFile: (filePath) => fs.readFileSync(filePath, 'utf8'),
136
+ loadSettings,
137
+ mutateSettings,
138
+ readRepoSettings,
139
+ writeRepoSettings,
140
+ checkGhAuth,
141
+ listIssueProviders,
142
+ VALID_PROVIDERS,
143
+ now: () => new Date().toISOString(),
144
+ };
138
145
  }
139
-
140
146
  // Phase 1: resolve + validate EVERY input decision before any write happens
141
147
  // (fail-closed — a single bad decisionId or out-of-domain value rejects the
142
148
  // whole request, never a partial apply).
143
149
  function resolveAndValidateDecisions(input, globalSettings, deps) {
144
- const resolved = [];
145
- for (const [decisionId, value] of Object.entries(input)) {
146
- const target = resolveDecisionPath(decisionId);
147
- if (!target) {
148
- throw new Error(`Unknown decision ID: ${decisionId}`);
150
+ const resolved = [];
151
+ for (const [decisionId, value] of Object.entries(input)) {
152
+ const target = resolveDecisionPath(decisionId);
153
+ if (!target) {
154
+ throw new Error(`Unknown decision ID: ${decisionId}`);
155
+ }
156
+ assertSecretSafePath(target.path);
157
+ const writeValue = convertDecisionValue({ decisionId, value, globalSettings, deps });
158
+ resolved.push({ decisionId, target, inputValue: value, writeValue });
149
159
  }
150
- assertSecretSafePath(target.path);
151
- const writeValue = convertDecisionValue({ decisionId, value, globalSettings, deps });
152
- resolved.push({ decisionId, target, inputValue: value, writeValue });
153
- }
154
- return resolved;
160
+ return resolved;
155
161
  }
156
-
157
162
  // Decides the outcome for a single resolved decision: a skip (with reason)
158
163
  // or the write to perform. Returns the write descriptor rather than mutating
159
164
  // anything, so the caller controls when settings objects/journal are touched.
160
- function resolveDecisionOutcome(
161
- { decisionId, target, inputValue, writeValue },
162
- { globalSettings, repoSettings, allowRiskyDefaults }
163
- ) {
164
- const settingsObj = target.scope === 'repo' ? repoSettings : globalSettings;
165
- const currentValue = getNestedValue(settingsObj, target.path) ?? null;
166
- const base = { decisionId, from: currentValue, to: writeValue };
167
-
168
- if (decisionId === 'defaultDelivery' && inputValue === 'ship' && !allowRiskyDefaults) {
169
- return { result: { ...base, applied: false, skippedReason: 'requires-explicit-opt-in' } };
170
- }
171
- if (!isConsumedPath(target.scope, target.path)) {
172
- return { result: { ...base, applied: false, skippedReason: 'no-consumer' } };
173
- }
174
- if (deepEqual(currentValue, writeValue)) {
175
- return { result: { ...base, applied: false, skippedReason: 'unchanged' } };
176
- }
177
-
178
- return {
179
- result: { ...base, applied: true },
180
- write: {
181
- settingsObj,
182
- scope: target.scope,
183
- path: target.path,
184
- writeValue,
185
- priorValue: currentValue,
186
- },
187
- };
165
+ function resolveDecisionOutcome(decision, context) {
166
+ const { decisionId, target, inputValue, writeValue } = decision;
167
+ const { globalSettings, repoSettings, allowRiskyDefaults } = context;
168
+ const settingsObj = target.scope === 'repo' ? repoSettings : globalSettings;
169
+ const currentValue = getNestedValue(settingsObj, target.path) ?? null;
170
+ const base = { decisionId, from: currentValue, to: writeValue };
171
+ if (decisionId === 'defaultDelivery' && inputValue === 'ship' && !allowRiskyDefaults) {
172
+ return { result: { ...base, applied: false, skippedReason: 'requires-explicit-opt-in' } };
173
+ }
174
+ if (!isConsumedPath(target.scope, target.path)) {
175
+ return { result: { ...base, applied: false, skippedReason: 'no-consumer' } };
176
+ }
177
+ if (deepEqual(currentValue, writeValue)) {
178
+ return { result: { ...base, applied: false, skippedReason: 'unchanged' } };
179
+ }
180
+ return {
181
+ result: { ...base, applied: true },
182
+ write: {
183
+ settingsObj,
184
+ scope: target.scope,
185
+ path: target.path,
186
+ writeValue,
187
+ priorValue: currentValue,
188
+ },
189
+ };
188
190
  }
189
-
190
191
  // Applies one decision's write to its in-memory settings object and journals
191
192
  // it (deferred persistence — the caller flushes to disk once at the end).
192
- function applyWrite(write, { repoRoot, journal, deps }) {
193
- setNestedValue(write.settingsObj, write.path, write.writeValue);
194
- upsertJournalEntry(journal, {
195
- scope: write.scope,
196
- path: write.path,
197
- repoRoot: write.scope === 'repo' ? repoRoot : null,
198
- priorValue: write.priorValue,
199
- appliedValue: write.writeValue,
200
- appliedAt: deps.now(),
201
- });
202
- return write.scope;
193
+ function applyWrite(write, context) {
194
+ const { repoRoot, journal, deps } = context;
195
+ setNestedValue(write.settingsObj, write.path, write.writeValue);
196
+ upsertJournalEntry(journal, {
197
+ scope: write.scope,
198
+ path: write.path,
199
+ repoRoot: write.scope === 'repo' ? repoRoot : null,
200
+ priorValue: write.priorValue,
201
+ appliedValue: write.writeValue,
202
+ appliedAt: deps.now(),
203
+ });
204
+ return write.scope;
203
205
  }
204
-
205
206
  // Phase 2: resolve each global outcome against the locked, freshly read state.
206
207
  // Repo-local settings remain intentionally outside the global settings lock.
207
- function writeResolvedDecisions(
208
- resolved,
209
- { repoSettings, repoRoot, journal, allowRiskyDefaults, deps }
210
- ) {
211
- const resultsById = new Map();
212
- let repoDirty = false;
213
- let globalDirty = false;
214
- const globalDecisions = resolved.filter((decision) => decision.target.scope === 'global');
215
-
216
- if (globalDecisions.length > 0) {
217
- const globalResults = deps.mutateSettings((freshGlobalSettings) => {
218
- const results = [];
219
- for (const decision of globalDecisions) {
220
- const freshDecision = {
221
- ...decision,
222
- writeValue: convertDecisionValue({
223
- decisionId: decision.decisionId,
224
- value: decision.inputValue,
225
- globalSettings: freshGlobalSettings,
226
- deps,
227
- }),
228
- };
229
- const { result, write } = resolveDecisionOutcome(freshDecision, {
230
- globalSettings: freshGlobalSettings,
231
- repoSettings,
232
- allowRiskyDefaults,
208
+ function writeResolvedDecisions(resolved, context) {
209
+ const { repoSettings, repoRoot, journal, allowRiskyDefaults, deps } = context;
210
+ const resultsById = new Map();
211
+ let repoDirty = false;
212
+ let globalDirty = false;
213
+ const globalDecisions = resolved.filter((decision) => decision.target.scope === 'global');
214
+ if (globalDecisions.length > 0) {
215
+ const globalResults = deps.mutateSettings((freshGlobalSettings) => {
216
+ const results = [];
217
+ for (const decision of globalDecisions) {
218
+ const freshDecision = {
219
+ ...decision,
220
+ writeValue: convertDecisionValue({
221
+ decisionId: decision.decisionId,
222
+ value: decision.inputValue,
223
+ globalSettings: freshGlobalSettings,
224
+ deps,
225
+ }),
226
+ };
227
+ const { result, write } = resolveDecisionOutcome(freshDecision, {
228
+ globalSettings: freshGlobalSettings,
229
+ repoSettings,
230
+ allowRiskyDefaults,
231
+ });
232
+ results.push(result);
233
+ if (write) {
234
+ applyWrite(write, { repoRoot, journal, deps });
235
+ globalDirty = true;
236
+ }
237
+ }
238
+ return results;
233
239
  });
234
- results.push(result);
235
- if (write) {
236
- applyWrite(write, { repoRoot, journal, deps });
237
- globalDirty = true;
238
- }
239
- }
240
- return results;
241
- });
242
- for (const result of globalResults) resultsById.set(result.decisionId, result);
243
- }
244
-
245
- for (const decision of resolved.filter((item) => item.target.scope === 'repo')) {
246
- const { result, write } = resolveDecisionOutcome(decision, {
247
- globalSettings: {},
248
- repoSettings,
249
- allowRiskyDefaults,
240
+ for (const result of globalResults)
241
+ resultsById.set(result.decisionId, result);
242
+ }
243
+ for (const decision of resolved.filter((item) => item.target.scope === 'repo')) {
244
+ const { result, write } = resolveDecisionOutcome(decision, {
245
+ globalSettings: {},
246
+ repoSettings,
247
+ allowRiskyDefaults,
248
+ });
249
+ resultsById.set(result.decisionId, result);
250
+ if (!write)
251
+ continue;
252
+ applyWrite(write, { repoRoot, journal, deps });
253
+ repoDirty = true;
254
+ }
255
+ if (repoDirty)
256
+ deps.writeRepoSettings(repoRoot, repoSettings);
257
+ if (globalDirty || repoDirty)
258
+ saveJournal(journal);
259
+ return resolved.map((decision) => {
260
+ const result = resultsById.get(decision.decisionId);
261
+ if (!result)
262
+ throw new Error(`Missing apply result for decision: ${decision.decisionId}`);
263
+ return result;
250
264
  });
251
- resultsById.set(result.decisionId, result);
252
- if (!write) continue;
253
- applyWrite(write, { repoRoot, journal, deps });
254
- repoDirty = true;
255
- }
256
-
257
- if (repoDirty) deps.writeRepoSettings(repoRoot, repoSettings);
258
- if (globalDirty || repoDirty) saveJournal(journal);
259
- return resolved.map((decision) => resultsById.get(decision.decisionId));
260
265
  }
261
-
262
266
  function assertDecisionObject(decisions, label) {
263
- if (!decisions || typeof decisions !== 'object' || Array.isArray(decisions)) {
264
- throw new Error(`${label} must be a JSON object of { decisionId: value }`);
265
- }
267
+ if (!decisions || typeof decisions !== 'object' || Array.isArray(decisions)) {
268
+ throw new Error(`${label} must be a JSON object of { decisionId: value }`);
269
+ }
266
270
  }
267
-
268
271
  /** Apply an in-memory decision object without temporary files. */
269
- function applyDecisionValues({ decisions, cwd, allowRiskyDefaults = false, deps = {} }) {
270
- assertDecisionObject(decisions, 'Decisions');
271
- const resolvedDeps = { ...defaultApplyDeps(), ...deps };
272
- const globalSettings = resolvedDeps.loadSettings();
273
- const { repoRoot, settings: repoSettingsRaw } = resolvedDeps.readRepoSettings(cwd);
274
- const repoSettings = repoSettingsRaw || {};
275
- const resolved = resolveAndValidateDecisions(decisions, globalSettings, resolvedDeps);
276
- const results = writeResolvedDecisions(resolved, {
277
- repoSettings,
278
- repoRoot,
279
- journal: loadJournal(),
280
- allowRiskyDefaults,
281
- deps: resolvedDeps,
282
- });
283
-
284
- const issueSourceApplied = results.find(
285
- (result) => result.decisionId === 'defaultIssueSource' && result.applied
286
- );
287
- if (issueSourceApplied?.to === 'github') {
288
- const auth = resolvedDeps.checkGhAuth();
289
- if (!auth?.authenticated) console.log('Run: gh auth login');
290
- }
291
- return results;
272
+ function applyDecisionValues({ decisions, cwd, allowRiskyDefaults = false, deps = {}, }) {
273
+ assertDecisionObject(decisions, 'Decisions');
274
+ const resolvedDeps = { ...defaultApplyDeps(), ...deps };
275
+ const globalSettings = resolvedDeps.loadSettings();
276
+ const { repoRoot, settings: repoSettingsRaw } = resolvedDeps.readRepoSettings(cwd);
277
+ const repoSettings = repoSettingsRaw || {};
278
+ const resolved = resolveAndValidateDecisions(decisions, globalSettings, resolvedDeps);
279
+ const results = writeResolvedDecisions(resolved, {
280
+ repoSettings,
281
+ repoRoot,
282
+ journal: loadJournal(),
283
+ allowRiskyDefaults,
284
+ deps: resolvedDeps,
285
+ });
286
+ const issueSourceApplied = results.find((result) => result.decisionId === 'defaultIssueSource' && result.applied);
287
+ if (issueSourceApplied?.to === 'github') {
288
+ const auth = resolvedDeps.checkGhAuth();
289
+ if (!auth?.authenticated)
290
+ console.log('Run: gh auth login');
291
+ }
292
+ return results;
292
293
  }
293
-
294
294
  /** Apply a decisions JSON file through the shared object API. */
295
- function applyDecisions({ decisionsPath, cwd, allowRiskyDefaults = false, deps = {} }) {
296
- const resolvedDeps = { ...defaultApplyDeps(), ...deps };
297
- let decisions;
298
- try {
299
- decisions = JSON.parse(resolvedDeps.readFile(decisionsPath));
300
- } catch (error) {
301
- throw new Error(`Failed to read decisions file "${decisionsPath}": ${error.message}`);
302
- }
303
- assertDecisionObject(decisions, 'Decisions file');
304
- return applyDecisionValues({
305
- decisions,
306
- cwd,
307
- allowRiskyDefaults,
308
- deps: resolvedDeps,
309
- });
295
+ function applyDecisions({ decisionsPath, cwd, allowRiskyDefaults = false, deps = {}, }) {
296
+ const resolvedDeps = { ...defaultApplyDeps(), ...deps };
297
+ let decisions;
298
+ try {
299
+ decisions = JSON.parse(resolvedDeps.readFile(decisionsPath));
300
+ }
301
+ catch (error) {
302
+ const message = typeof error === 'object' && error !== null && 'message' in error
303
+ ? error.message
304
+ : undefined;
305
+ throw new Error(`Failed to read decisions file "${decisionsPath}": ${String(message)}`);
306
+ }
307
+ assertDecisionObject(decisions, 'Decisions file');
308
+ return applyDecisionValues({
309
+ decisions,
310
+ cwd,
311
+ allowRiskyDefaults,
312
+ deps: resolvedDeps,
313
+ });
310
314
  }
311
-
312
315
  module.exports = {
313
- applyDecisions,
314
- applyDecisionValues,
315
- resolveAndValidateDecisions,
316
- writeResolvedDecisions,
317
- assertSecretSafePath,
318
- isConsumedPath,
319
- CONSUMED_PATHS,
316
+ applyDecisions,
317
+ applyDecisionValues,
318
+ resolveAndValidateDecisions,
319
+ writeResolvedDecisions,
320
+ assertSecretSafePath,
321
+ isConsumedPath,
322
+ CONSUMED_PATHS,
320
323
  };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Undo journal for `zeroshot setup apply` / `zeroshot setup undo`.
3
+ *
4
+ * One journal entry per setting this setup owns: { scope, path, repoRoot,
5
+ * priorValue, appliedValue, appliedAt }. `priorValue: null` means the key
6
+ * did not exist before apply, so undo deletes it rather than restoring it.
7
+ * Shared by lib/setup-apply.js (writer) and lib/setup-undo.js (reader) so the
8
+ * nested-path mutation and equality semantics can't drift between the two.
9
+ */
10
+ interface JournalEntry {
11
+ readonly appliedAt: string;
12
+ readonly appliedValue: unknown;
13
+ readonly path: string;
14
+ readonly priorValue: unknown;
15
+ readonly repoRoot: string | null;
16
+ readonly scope: string;
17
+ readonly [key: string]: unknown;
18
+ }
19
+ interface SetupJournal {
20
+ entries: JournalEntry[];
21
+ version: number;
22
+ [key: string]: unknown;
23
+ }
24
+ declare function getJournalPath(): string;
25
+ declare function loadJournal(): SetupJournal;
26
+ declare function saveJournal(journal: SetupJournal): void;
27
+ declare function upsertJournalEntry(journal: SetupJournal, entry: JournalEntry): void;
28
+ declare function setNestedValue(target: Record<string, unknown>, pathStr: string, value: unknown): void;
29
+ declare function deleteNestedKey(target: Record<string, unknown>, pathStr: string): void;
30
+ declare function deepEqual(left: unknown, right: unknown): boolean;
31
+ declare const _default: {
32
+ getJournalPath: typeof getJournalPath;
33
+ loadJournal: typeof loadJournal;
34
+ saveJournal: typeof saveJournal;
35
+ upsertJournalEntry: typeof upsertJournalEntry;
36
+ getNestedValue: (source: Record<string, unknown>, pathStr: string) => unknown;
37
+ setNestedValue: typeof setNestedValue;
38
+ deleteNestedKey: typeof deleteNestedKey;
39
+ deepEqual: typeof deepEqual;
40
+ };
41
+ export = _default;