@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
package/lib/setup-plan.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Setup plan — read-only facts collector + the pinned, versioned setup contract.
3
4
  *
@@ -8,379 +9,354 @@
8
9
  * decisionId registry below are a stable contract — do not rename IDs or add a
9
10
  * parallel run-mode field without updating every consumer.
10
11
  */
11
-
12
- const path = require('path');
13
-
12
+ const path = require("path");
14
13
  const SCHEMA_VERSION = 2;
15
-
16
14
  // Canonical settings keys consumed by resolveEffectiveRunPlan. Never introduce
17
15
  // a parallel setting or translate a decision into a differently named key.
18
16
  const DECISION_PATHS = {
19
- defaultProvider: { scope: 'global', path: 'defaultProvider' },
20
- defaultIsolation: { scope: 'global', path: 'defaultIsolation' },
21
- allowLocalNoIsolation: { scope: 'global', path: 'allowLocalNoIsolation' },
22
- defaultDelivery: { scope: 'global', path: 'defaultDelivery' },
23
- defaultIssueSource: { scope: 'global', path: 'defaultIssueSource' },
24
- prBase: { scope: 'repo', path: 'prBase' },
25
- dockerMounts: { scope: 'global', path: 'dockerMounts' },
26
- dockerEnvPassthrough: { scope: 'global', path: 'dockerEnvPassthrough' },
27
- updatePolicy: { scope: 'global', path: 'updatePolicy' },
17
+ defaultProvider: { scope: 'global', path: 'defaultProvider' },
18
+ defaultIsolation: { scope: 'global', path: 'defaultIsolation' },
19
+ allowLocalNoIsolation: { scope: 'global', path: 'allowLocalNoIsolation' },
20
+ defaultDelivery: { scope: 'global', path: 'defaultDelivery' },
21
+ defaultIssueSource: { scope: 'global', path: 'defaultIssueSource' },
22
+ prBase: { scope: 'repo', path: 'prBase' },
23
+ dockerMounts: { scope: 'global', path: 'dockerMounts' },
24
+ dockerEnvPassthrough: { scope: 'global', path: 'dockerEnvPassthrough' },
25
+ updatePolicy: { scope: 'global', path: 'updatePolicy' },
28
26
  };
29
-
30
27
  function providerLevelDecisionId(providerName) {
31
- return `providerLevel.${providerName}`;
28
+ return `providerLevel.${providerName}`;
32
29
  }
33
-
34
30
  // Settings keys consumed by runtime resolvers. Shared by buildProposedWrites
35
31
  // and setup apply so neither surface can advertise dead configuration.
36
32
  const CONSUMED_PATHS = new Set([
37
- 'global:defaultProvider',
38
- 'global:defaultIsolation',
39
- 'global:defaultDelivery',
40
- 'global:defaultIssueSource',
41
- 'global:dockerMounts',
42
- 'global:dockerEnvPassthrough',
43
- // No resolver consumes this yet; consumption is deferred to a future
44
- // update-policy issue, but issue #606 explicitly sanctions writing it now.
45
- 'global:updatePolicy',
33
+ 'global:defaultProvider',
34
+ 'global:defaultIsolation',
35
+ 'global:defaultDelivery',
36
+ 'global:defaultIssueSource',
37
+ 'global:dockerMounts',
38
+ 'global:dockerEnvPassthrough',
39
+ // No resolver consumes this yet; consumption is deferred to a future
40
+ // update-policy issue, but issue #606 explicitly sanctions writing it now.
41
+ 'global:updatePolicy',
46
42
  ]);
47
-
48
43
  function isConsumedPath(scope, targetPath) {
49
- if (scope === 'global' && targetPath.startsWith('providerSettings.')) return true;
50
- return CONSUMED_PATHS.has(`${scope}:${targetPath}`);
44
+ if (scope === 'global' && targetPath.startsWith('providerSettings.'))
45
+ return true;
46
+ return CONSUMED_PATHS.has(`${scope}:${targetPath}`);
51
47
  }
52
-
53
48
  // providerLevel.<provider> decisionIds map to a per-provider settings key
54
49
  // (providerSettings.<provider>) not present in DECISION_PATHS above, since
55
50
  // the provider name is only known at runtime.
56
51
  function resolveDecisionPath(decisionId) {
57
- if (decisionId.startsWith('providerLevel.')) {
58
- const providerName = decisionId.slice('providerLevel.'.length);
59
- return { scope: 'global', path: `providerSettings.${providerName}` };
60
- }
61
- return DECISION_PATHS[decisionId] || null;
52
+ if (decisionId.startsWith('providerLevel.')) {
53
+ const providerName = decisionId.slice('providerLevel.'.length);
54
+ return { scope: 'global', path: `providerSettings.${providerName}` };
55
+ }
56
+ return DECISION_PATHS[decisionId] || null;
62
57
  }
63
-
64
58
  function getNestedValue(source, pathStr) {
65
- return pathStr
66
- .split('.')
67
- .reduce((acc, key) => (acc === null || acc === undefined ? undefined : acc[key]), source);
59
+ return pathStr
60
+ .split('.')
61
+ .reduce((acc, key) => {
62
+ if (acc === null || acc === undefined)
63
+ return undefined;
64
+ // Property access intentionally retains JavaScript's primitive boxing behavior.
65
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
66
+ return acc[key];
67
+ }, source);
68
68
  }
69
-
70
69
  function defaultDeps() {
71
- const { commandExists, getCommandPath } = require('./provider-detection');
72
- const { checkDocker, checkGhAuth } = require('../src/preflight');
73
- const { execSync } = require('../src/lib/safe-exec');
74
- const { listProviders, getProvider } = require('../src/providers');
75
- const { getProviderDefaults } = require('./provider-defaults');
76
- const { getDefaultProviderId, getProviderMetadata } = require('./provider-names');
77
- const packageJson = require('../package.json');
78
-
79
- return {
80
- commandExists,
81
- getCommandPath,
82
- checkDocker,
83
- checkGhAuth,
84
- execSync,
85
- listProviders,
86
- getProvider,
87
- getProviderDefaults,
88
- getDefaultProviderId,
89
- getProviderMetadata,
90
- getNodeVersion: () => process.version,
91
- getPackageVersion: () => packageJson.version,
92
- };
70
+ // These paths intentionally resolve beside the emitted module in lib/.
71
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
72
+ const { commandExists, getCommandPath } = require('./provider-detection');
73
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
74
+ const { checkDocker, checkGhAuth } = require('../src/preflight');
75
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
76
+ const { execSync } = require('../src/lib/safe-exec');
77
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
78
+ const { listProviders, getProvider } = require('../src/providers');
79
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
80
+ const { getProviderDefaults } = require('./provider-defaults');
81
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
82
+ const { getDefaultProviderId, getProviderMetadata } = require('./provider-names');
83
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
84
+ const packageJson = require('../package.json');
85
+ return {
86
+ commandExists,
87
+ getCommandPath,
88
+ checkDocker,
89
+ checkGhAuth,
90
+ execSync,
91
+ listProviders,
92
+ getProvider,
93
+ getProviderDefaults,
94
+ getDefaultProviderId,
95
+ getProviderMetadata,
96
+ getNodeVersion: () => process.version,
97
+ getPackageVersion: () => packageJson.version,
98
+ };
93
99
  }
94
-
95
100
  function detectInstallSource(cwd, env) {
96
- if (env.npm_config_global === 'true') return 'npm-global';
97
- if (env.npm_execpath && /_npx|npx/.test(env.npm_execpath)) return 'npx';
98
- const ownNodeModules = path.join(__dirname, '..', 'node_modules');
99
- if (cwd && (cwd === path.join(__dirname, '..') || cwd.startsWith(ownNodeModules))) return 'local';
100
- return 'unknown';
101
+ if (env.npm_config_global === 'true')
102
+ return 'npm-global';
103
+ if (env.npm_execpath && /_npx|npx/.test(env.npm_execpath))
104
+ return 'npx';
105
+ const ownNodeModules = path.join(__dirname, '..', 'node_modules');
106
+ if (cwd && (cwd === path.join(__dirname, '..') || cwd.startsWith(ownNodeModules)))
107
+ return 'local';
108
+ return 'unknown';
101
109
  }
102
-
103
- function buildNodeFacts({ cwd, env, deps }) {
104
- return {
105
- version: deps.getNodeVersion(),
106
- packageVersion: deps.getPackageVersion(),
107
- installSource: detectInstallSource(cwd, env),
108
- };
110
+ function buildNodeFacts({ cwd, env, deps, }) {
111
+ return {
112
+ version: deps.getNodeVersion(),
113
+ packageVersion: deps.getPackageVersion(),
114
+ installSource: detectInstallSource(cwd, env),
115
+ };
109
116
  }
110
-
111
117
  function buildProviderFacts(deps) {
112
- const providers = {};
113
- for (const name of deps.listProviders()) {
114
- const metadata = deps.getProviderMetadata(name);
115
- const provider = deps.getProvider(name);
116
- let available = false;
117
- try {
118
- available = provider.isAvailable() === true;
119
- } catch {
120
- available = false;
118
+ const providers = {};
119
+ for (const name of deps.listProviders()) {
120
+ const metadata = deps.getProviderMetadata(name);
121
+ const provider = deps.getProvider(name);
122
+ let available = false;
123
+ try {
124
+ available = provider.isAvailable() === true;
125
+ }
126
+ catch {
127
+ available = false;
128
+ }
129
+ const cliCommand = provider.cliCommand || metadata.binary;
130
+ providers[name] = {
131
+ available,
132
+ displayName: metadata.displayName,
133
+ installInstructions: metadata.installInstructions,
134
+ path: available && deps.commandExists(cliCommand) ? deps.getCommandPath(cliCommand) : null,
135
+ };
121
136
  }
122
- const cliCommand = provider.cliCommand || metadata.binary;
123
- providers[name] = {
124
- available,
125
- displayName: metadata.displayName,
126
- installInstructions: metadata.installInstructions,
127
- path: available && deps.commandExists(cliCommand) ? deps.getCommandPath(cliCommand) : null,
128
- };
129
- }
130
- return providers;
137
+ return providers;
131
138
  }
132
-
133
139
  function safeExecTrim(deps, command, cwd) {
134
- try {
135
- return deps.execSync(command, { cwd, stdio: 'pipe', encoding: 'utf8' }).trim();
136
- } catch {
137
- return null;
138
- }
140
+ try {
141
+ return deps.execSync(command, { cwd, stdio: 'pipe', encoding: 'utf8' }).trim();
142
+ }
143
+ catch {
144
+ return null;
145
+ }
139
146
  }
140
-
141
- function buildGitFacts({ cwd, deps }) {
142
- const isRepo = safeExecTrim(deps, 'git rev-parse --is-inside-work-tree', cwd) === 'true';
143
- const ghAvailable = deps.commandExists('gh');
144
-
145
- if (!isRepo) {
146
- return { isRepo: false, branch: null, remote: null, ghAvailable, ghAuthed: null };
147
- }
148
-
149
- const branch = safeExecTrim(deps, 'git rev-parse --abbrev-ref HEAD', cwd);
150
- const remote = safeExecTrim(deps, 'git remote get-url origin', cwd);
151
- const ghAuthed = ghAvailable ? !!deps.checkGhAuth().authenticated : null;
152
-
153
- return { isRepo: true, branch, remote, ghAvailable, ghAuthed };
147
+ function buildGitFacts({ cwd, deps, }) {
148
+ const isRepo = safeExecTrim(deps, 'git rev-parse --is-inside-work-tree', cwd) === 'true';
149
+ const ghAvailable = deps.commandExists('gh');
150
+ if (!isRepo) {
151
+ return { isRepo: false, branch: null, remote: null, ghAvailable, ghAuthed: null };
152
+ }
153
+ const branch = safeExecTrim(deps, 'git rev-parse --abbrev-ref HEAD', cwd);
154
+ const remote = safeExecTrim(deps, 'git remote get-url origin', cwd);
155
+ const ghAuthed = ghAvailable ? !!deps.checkGhAuth().authenticated : null;
156
+ return { isRepo: true, branch, remote, ghAvailable, ghAuthed };
154
157
  }
155
-
156
- function buildFacts({ cwd, settings, repoSettings, env, deps }) {
157
- return {
158
- node: buildNodeFacts({ cwd, env, deps }),
159
- providers: buildProviderFacts(deps),
160
- git: buildGitFacts({ cwd, deps }),
161
- docker: { available: !!deps.checkDocker().available },
162
- settings: {
163
- hasGlobal: settings?.__meta ? !!settings.__meta.fileExists : true,
164
- hasRepo: repoSettings !== null && repoSettings !== undefined,
165
- },
166
- };
158
+ function buildFacts({ cwd, settings, repoSettings, env, deps, }) {
159
+ return {
160
+ node: buildNodeFacts({ cwd, env, deps }),
161
+ providers: buildProviderFacts(deps),
162
+ git: buildGitFacts({ cwd, deps }),
163
+ docker: { available: !!deps.checkDocker().available },
164
+ settings: {
165
+ hasGlobal: settings.__meta ? Boolean(getNestedValue(settings.__meta, 'fileExists')) : true,
166
+ hasRepo: repoSettings !== null && repoSettings !== undefined,
167
+ },
168
+ };
167
169
  }
168
-
169
170
  function inferIssueSource(facts) {
170
- const { parseGitRemoteUrl } = require('./git-remote-utils');
171
- const parsed = parseGitRemoteUrl(facts.git.remote);
172
- return parsed?.provider || null;
171
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
172
+ const { parseGitRemoteUrl } = require('./git-remote-utils');
173
+ const parsed = parseGitRemoteUrl(facts.git.remote);
174
+ return parsed?.provider || null;
173
175
  }
174
-
175
176
  function inferPrBase(cwd, deps) {
176
- const branch = safeExecTrim(deps, 'git rev-parse --abbrev-ref origin/HEAD', cwd);
177
- if (!branch) return null;
178
- return branch.replace(/^origin\//, '');
177
+ const branch = safeExecTrim(deps, 'git rev-parse --abbrev-ref origin/HEAD', cwd);
178
+ if (!branch)
179
+ return null;
180
+ return branch.replace(/^origin\//, '');
179
181
  }
180
-
181
182
  function buildProviderLevelRecommendation(name, deps) {
182
- const providerDefaults = deps.getProviderDefaults()[name] || {};
183
- return {
184
- minLevel: providerDefaults.minLevel || 'level1',
185
- defaultLevel: providerDefaults.defaultLevel || 'level2',
186
- maxLevel: providerDefaults.maxLevel || 'level3',
187
- };
183
+ const providerDefaults = deps.getProviderDefaults()[name] || {};
184
+ return {
185
+ minLevel: providerDefaults.minLevel || 'level1',
186
+ defaultLevel: providerDefaults.defaultLevel || 'level2',
187
+ maxLevel: providerDefaults.maxLevel || 'level3',
188
+ };
188
189
  }
189
-
190
- function buildRecommendedAndRisk({ cwd, facts, env, deps }) {
191
- const recommended = {};
192
- const risk = {};
193
- const registryDefault = deps.getDefaultProviderId();
194
- recommended.defaultProvider = registryDefault;
195
- risk.defaultProvider = facts.providers[registryDefault]?.available ? 'low' : 'medium';
196
-
197
- for (const name of Object.keys(facts.providers)) {
198
- recommended[providerLevelDecisionId(name)] = buildProviderLevelRecommendation(name, deps);
199
- risk[providerLevelDecisionId(name)] = 'low';
200
- }
201
-
202
- if (facts.git.isRepo) {
203
- recommended.defaultIsolation = 'worktree';
204
- risk.defaultIsolation = 'low';
205
- } else if (facts.docker.available) {
206
- recommended.defaultIsolation = 'docker';
207
- risk.defaultIsolation = 'low';
208
- } else {
209
- recommended.defaultIsolation = 'none';
210
- risk.defaultIsolation = 'high';
211
- }
212
-
213
- recommended.allowLocalNoIsolation = false;
214
- risk.allowLocalNoIsolation = 'low';
215
- recommended.defaultDelivery = 'none';
216
- risk.defaultDelivery = 'low';
217
-
218
- const inferredIssueSource = inferIssueSource(facts);
219
- recommended.defaultIssueSource = inferredIssueSource || 'github';
220
- risk.defaultIssueSource = inferredIssueSource ? 'low' : 'medium';
221
-
222
- const inferredPrBase = inferPrBase(cwd, deps);
223
- recommended.prBase = inferredPrBase || 'main';
224
- risk.prBase = inferredPrBase ? 'low' : 'medium';
225
- recommended.dockerMounts = ['gh', 'git', 'ssh'];
226
- risk.dockerMounts = 'low';
227
- recommended.dockerEnvPassthrough = [];
228
- risk.dockerEnvPassthrough = 'low';
229
-
230
- const nonInteractive = env.CI === 'true' || env.__isTTY === false;
231
- recommended.updatePolicy = nonInteractive ? 'off' : 'notify';
232
- risk.updatePolicy = 'low';
233
-
234
- return { recommended, risk, inferredIssueSource, inferredPrBase };
190
+ function buildRecommendedAndRisk({ cwd, facts, env, deps, }) {
191
+ const recommended = {};
192
+ const risk = {};
193
+ const registryDefault = deps.getDefaultProviderId();
194
+ recommended.defaultProvider = registryDefault;
195
+ risk.defaultProvider = facts.providers[registryDefault]?.available ? 'low' : 'medium';
196
+ for (const name of Object.keys(facts.providers)) {
197
+ recommended[providerLevelDecisionId(name)] = buildProviderLevelRecommendation(name, deps);
198
+ risk[providerLevelDecisionId(name)] = 'low';
199
+ }
200
+ if (facts.git.isRepo) {
201
+ recommended.defaultIsolation = 'worktree';
202
+ risk.defaultIsolation = 'low';
203
+ }
204
+ else if (facts.docker.available) {
205
+ recommended.defaultIsolation = 'docker';
206
+ risk.defaultIsolation = 'low';
207
+ }
208
+ else {
209
+ recommended.defaultIsolation = 'none';
210
+ risk.defaultIsolation = 'high';
211
+ }
212
+ recommended.allowLocalNoIsolation = false;
213
+ risk.allowLocalNoIsolation = 'low';
214
+ recommended.defaultDelivery = 'none';
215
+ risk.defaultDelivery = 'low';
216
+ const inferredIssueSource = inferIssueSource(facts);
217
+ recommended.defaultIssueSource = inferredIssueSource || 'github';
218
+ risk.defaultIssueSource = inferredIssueSource ? 'low' : 'medium';
219
+ const inferredPrBase = inferPrBase(cwd, deps);
220
+ recommended.prBase = inferredPrBase || 'main';
221
+ risk.prBase = inferredPrBase ? 'low' : 'medium';
222
+ recommended.dockerMounts = ['gh', 'git', 'ssh'];
223
+ risk.dockerMounts = 'low';
224
+ recommended.dockerEnvPassthrough = [];
225
+ risk.dockerEnvPassthrough = 'low';
226
+ const nonInteractive = env.CI === 'true' || env.__isTTY === false;
227
+ recommended.updatePolicy = nonInteractive ? 'off' : 'notify';
228
+ risk.updatePolicy = 'low';
229
+ return { recommended, risk, inferredIssueSource, inferredPrBase };
235
230
  }
236
-
237
231
  function currentValueFor(decisionId, settings, repoSettings) {
238
- const target = resolveDecisionPath(decisionId);
239
- if (!target) return null;
240
- const source = target.scope === 'repo' ? repoSettings || {} : settings || {};
241
- const value = getNestedValue(source, target.path);
242
- return value === undefined ? null : value;
232
+ const target = resolveDecisionPath(decisionId);
233
+ if (!target)
234
+ return null;
235
+ const source = target.scope === 'repo' ? repoSettings || {} : settings || {};
236
+ const value = getNestedValue(source, target.path);
237
+ return value === undefined ? null : value;
243
238
  }
244
-
245
- function buildDecisions({ facts, settings, repoSettings, inferredIssueSource, inferredPrBase }) {
246
- const decisions = [];
247
- const hasGlobal = facts.settings.hasGlobal;
248
- const hasRepo = facts.settings.hasRepo;
249
-
250
- const globalDecisionIds = [
251
- 'defaultProvider',
252
- ...Object.keys(facts.providers).map(providerLevelDecisionId),
253
- 'defaultIsolation',
254
- 'allowLocalNoIsolation',
255
- 'defaultDelivery',
256
- 'defaultIssueSource',
257
- 'dockerMounts',
258
- 'dockerEnvPassthrough',
259
- 'updatePolicy',
260
- ];
261
-
262
- for (const decisionId of globalDecisionIds) {
263
- const shouldInclude =
264
- !hasGlobal || (decisionId === 'defaultIssueSource' && !inferredIssueSource);
265
- if (!shouldInclude) continue;
266
- decisions.push({
267
- decisionId,
268
- domain: domainFor(decisionId),
269
- currentValue: currentValueFor(decisionId, settings, repoSettings),
270
- });
271
- }
272
-
273
- if (!hasRepo || !inferredPrBase) {
274
- decisions.push({
275
- decisionId: 'prBase',
276
- domain: domainFor('prBase'),
277
- currentValue: currentValueFor('prBase', settings, repoSettings),
278
- });
279
- }
280
-
281
- return decisions;
239
+ function buildDecisions({ facts, settings, repoSettings, inferredIssueSource, inferredPrBase, }) {
240
+ const decisions = [];
241
+ const hasGlobal = facts.settings.hasGlobal;
242
+ const hasRepo = facts.settings.hasRepo;
243
+ const globalDecisionIds = [
244
+ 'defaultProvider',
245
+ ...Object.keys(facts.providers).map(providerLevelDecisionId),
246
+ 'defaultIsolation',
247
+ 'allowLocalNoIsolation',
248
+ 'defaultDelivery',
249
+ 'defaultIssueSource',
250
+ 'dockerMounts',
251
+ 'dockerEnvPassthrough',
252
+ 'updatePolicy',
253
+ ];
254
+ for (const decisionId of globalDecisionIds) {
255
+ const shouldInclude = !hasGlobal || (decisionId === 'defaultIssueSource' && !inferredIssueSource);
256
+ if (!shouldInclude)
257
+ continue;
258
+ decisions.push({
259
+ decisionId,
260
+ domain: domainFor(decisionId),
261
+ currentValue: currentValueFor(decisionId, settings, repoSettings),
262
+ });
263
+ }
264
+ if (!hasRepo || !inferredPrBase) {
265
+ decisions.push({
266
+ decisionId: 'prBase',
267
+ domain: domainFor('prBase'),
268
+ currentValue: currentValueFor('prBase', settings, repoSettings),
269
+ });
270
+ }
271
+ return decisions;
282
272
  }
283
-
284
273
  function domainFor(decisionId) {
285
- if (decisionId.startsWith('providerLevel.')) {
286
- return '{ minLevel, defaultLevel, maxLevel } of level1|level2|level3';
287
- }
288
- const domains = {
289
- defaultProvider: 'registry provider id',
290
- defaultIsolation: 'worktree | docker | none',
291
- allowLocalNoIsolation: 'boolean',
292
- defaultDelivery: 'none | pr | ship',
293
- defaultIssueSource: 'github | gitlab | jira | azure-devops | linear',
294
- prBase: 'string (branch)',
295
- dockerMounts: 'array of presets/objects',
296
- dockerEnvPassthrough: 'string[]',
297
- updatePolicy: 'off | notify | auto',
298
- };
299
- return domains[decisionId] || 'unknown';
274
+ if (decisionId.startsWith('providerLevel.')) {
275
+ return '{ minLevel, defaultLevel, maxLevel } of level1|level2|level3';
276
+ }
277
+ const domains = {
278
+ defaultProvider: 'registry provider id',
279
+ defaultIsolation: 'worktree | docker | none',
280
+ allowLocalNoIsolation: 'boolean',
281
+ defaultDelivery: 'none | pr | ship',
282
+ defaultIssueSource: 'github | gitlab | jira | azure-devops | linear',
283
+ prBase: 'string (branch)',
284
+ dockerMounts: 'array of presets/objects',
285
+ dockerEnvPassthrough: 'string[]',
286
+ updatePolicy: 'off | notify | auto',
287
+ };
288
+ return domains[decisionId] || 'unknown';
300
289
  }
301
-
302
- function buildProposedWrites({ decisions, recommended }) {
303
- const writes = [];
304
- for (const decision of decisions) {
305
- const target = resolveDecisionPath(decision.decisionId);
306
- if (!target) continue;
307
- // A decision can still be surfaced for the user to make (e.g. a future
308
- // wizard asking about prBase), but proposing a *write* for a settings key
309
- // no resolver reads would advertise a write that apply will always skip —
310
- // dead config. Only propose writes apply will actually perform.
311
- if (!isConsumedPath(target.scope, target.path)) continue;
312
- const to = recommended[decision.decisionId];
313
- if (to === decision.currentValue) continue;
314
- writes.push({
315
- scope: target.scope,
316
- path: target.path,
317
- from: decision.currentValue ?? null,
318
- to,
319
- decisionId: decision.decisionId,
320
- });
321
- }
322
- return writes;
290
+ function buildProposedWrites({ decisions, recommended, }) {
291
+ const writes = [];
292
+ for (const decision of decisions) {
293
+ const target = resolveDecisionPath(decision.decisionId);
294
+ if (!target)
295
+ continue;
296
+ // A decision can still be surfaced for the user to make (e.g. a future
297
+ // wizard asking about prBase), but proposing a *write* for a settings key
298
+ // no resolver reads would advertise a write that apply will always skip —
299
+ // dead config. Only propose writes apply will actually perform.
300
+ if (!isConsumedPath(target.scope, target.path))
301
+ continue;
302
+ const to = recommended[decision.decisionId];
303
+ if (to === decision.currentValue)
304
+ continue;
305
+ writes.push({
306
+ scope: target.scope,
307
+ path: target.path,
308
+ from: decision.currentValue ?? null,
309
+ to,
310
+ decisionId: decision.decisionId,
311
+ });
312
+ }
313
+ return writes;
323
314
  }
324
-
325
315
  /**
326
316
  * Build the pinned, versioned setup contract. Pure over injected inputs —
327
317
  * performs only cheap, read-only detection (no writes, no prompts).
328
- *
329
- * @param {Object} params
330
- * @param {string} params.cwd
331
- * @param {Object} params.settings - loaded global settings (optionally with __meta.fileExists)
332
- * @param {Object|null} params.repoSettings - repo-local settings object, or null
333
- * @param {Object} params.env - caller-provided env (e.g. process.env), plus optional __isTTY
334
- * @param {Object} [params.deps] - injected dependencies (for testing)
335
- * @returns {Object} plan
336
318
  */
337
- function buildSetupPlan({ cwd, settings, repoSettings, env, deps } = {}) {
338
- const resolvedDeps = { ...defaultDeps(), ...(deps || {}) };
339
- const resolvedEnv = env || {};
340
- const resolvedCwd = cwd || '.';
341
- const resolvedSettings = settings || {};
342
-
343
- const facts = buildFacts({
344
- cwd: resolvedCwd,
345
- settings: resolvedSettings,
346
- repoSettings,
347
- env: resolvedEnv,
348
- deps: resolvedDeps,
349
- });
350
-
351
- const { recommended, risk, inferredIssueSource, inferredPrBase } = buildRecommendedAndRisk({
352
- cwd: resolvedCwd,
353
- facts,
354
- env: resolvedEnv,
355
- deps: resolvedDeps,
356
- });
357
-
358
- const decisions = buildDecisions({
359
- facts,
360
- settings: resolvedSettings,
361
- repoSettings,
362
- inferredIssueSource,
363
- inferredPrBase,
364
- });
365
-
366
- const proposedWrites = buildProposedWrites({ decisions, recommended });
367
-
368
- return {
369
- schemaVersion: SCHEMA_VERSION,
370
- facts,
371
- decisions,
372
- recommended,
373
- risk,
374
- proposedWrites,
375
- };
319
+ function buildSetupPlan({ cwd, settings, repoSettings, env, deps, } = {}) {
320
+ const resolvedDeps = { ...defaultDeps(), ...(deps || {}) };
321
+ const resolvedEnv = env || {};
322
+ const resolvedCwd = cwd || '.';
323
+ const resolvedSettings = settings || {};
324
+ const facts = buildFacts({
325
+ cwd: resolvedCwd,
326
+ settings: resolvedSettings,
327
+ repoSettings,
328
+ env: resolvedEnv,
329
+ deps: resolvedDeps,
330
+ });
331
+ const { recommended, risk, inferredIssueSource, inferredPrBase } = buildRecommendedAndRisk({
332
+ cwd: resolvedCwd,
333
+ facts,
334
+ env: resolvedEnv,
335
+ deps: resolvedDeps,
336
+ });
337
+ const decisions = buildDecisions({
338
+ facts,
339
+ settings: resolvedSettings,
340
+ repoSettings,
341
+ inferredIssueSource,
342
+ inferredPrBase,
343
+ });
344
+ const proposedWrites = buildProposedWrites({ decisions, recommended });
345
+ return {
346
+ schemaVersion: SCHEMA_VERSION,
347
+ facts,
348
+ decisions,
349
+ recommended,
350
+ risk,
351
+ proposedWrites,
352
+ };
376
353
  }
377
-
378
354
  module.exports = {
379
- buildSetupPlan,
380
- resolveDecisionPath,
381
- domainFor,
382
- DECISION_PATHS,
383
- getNestedValue,
384
- isConsumedPath,
385
- CONSUMED_PATHS,
355
+ buildSetupPlan,
356
+ resolveDecisionPath,
357
+ domainFor,
358
+ DECISION_PATHS,
359
+ getNestedValue,
360
+ isConsumedPath,
361
+ CONSUMED_PATHS,
386
362
  };