@the-open-engine/zeroshot 6.38.0 → 6.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/cli/event-copy.js +8 -7
  2. package/cli/event-copy.ts +12 -0
  3. package/cli/index.js +7 -31
  4. package/cli/json-export.js +61 -64
  5. package/cli/json-export.ts +112 -0
  6. package/cli/message-formatter-utils.js +68 -56
  7. package/cli/message-formatter-utils.ts +121 -0
  8. package/cli/message-formatters-normal.js +124 -259
  9. package/cli/message-formatters-normal.ts +250 -0
  10. package/cli/message-formatters-watch.js +81 -84
  11. package/cli/message-formatters-watch.ts +189 -0
  12. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
  13. package/lib/agent-cli-provider/adapters/codex.js +3 -1
  14. package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
  15. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  16. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  17. package/lib/cluster/generated/protocol.d.cts +8 -0
  18. package/lib/cluster/generated/protocol.d.mts +8 -0
  19. package/lib/cluster/generated/protocol.d.ts +8 -0
  20. package/lib/clusters-registry.d.ts +23 -0
  21. package/lib/clusters-registry.js +17 -29
  22. package/lib/completion.d.ts +12 -0
  23. package/lib/completion.js +84 -94
  24. package/lib/compose-utils.d.ts +32 -0
  25. package/lib/compose-utils.js +57 -72
  26. package/lib/detached-startup.d.ts +83 -0
  27. package/lib/detached-startup.js +231 -302
  28. package/lib/docker-config.d.ts +43 -0
  29. package/lib/docker-config.js +150 -325
  30. package/lib/docker-env-auth.d.ts +17 -0
  31. package/lib/docker-env-auth.js +75 -0
  32. package/lib/git-remote-utils.d.ts +48 -0
  33. package/lib/git-remote-utils.js +147 -213
  34. package/lib/id-detector.d.ts +15 -0
  35. package/lib/id-detector.js +37 -41
  36. package/lib/path-check.d.ts +30 -0
  37. package/lib/path-check.js +42 -45
  38. package/lib/process-liveness.d.ts +16 -0
  39. package/lib/process-liveness.js +19 -12
  40. package/lib/provider-credential-path.d.ts +16 -0
  41. package/lib/provider-credential-path.js +31 -29
  42. package/lib/provider-defaults.d.ts +30 -0
  43. package/lib/provider-defaults.js +47 -42
  44. package/lib/provider-detection.d.ts +11 -0
  45. package/lib/provider-detection.js +91 -54
  46. package/lib/provider-names.d.ts +38 -0
  47. package/lib/provider-names.js +56 -64
  48. package/lib/repo-settings.d.ts +28 -0
  49. package/lib/repo-settings.js +83 -59
  50. package/lib/run-mode.d.ts +21 -0
  51. package/lib/run-mode.js +21 -20
  52. package/lib/run-plan.d.ts +28 -0
  53. package/lib/run-plan.js +17 -16
  54. package/lib/settings/claude-auth.d.ts +35 -0
  55. package/lib/settings/claude-auth.js +30 -47
  56. package/lib/settings-defaults.d.ts +20 -0
  57. package/lib/settings-defaults.js +149 -0
  58. package/lib/settings-error.d.ts +7 -0
  59. package/lib/settings-error.js +8 -0
  60. package/lib/settings-issue-providers.d.ts +10 -0
  61. package/lib/settings-issue-providers.js +12 -0
  62. package/lib/settings-models.d.ts +22 -0
  63. package/lib/settings-models.js +93 -0
  64. package/lib/settings-storage.d.ts +23 -0
  65. package/lib/settings-storage.js +205 -0
  66. package/lib/settings-validation.d.ts +7 -0
  67. package/lib/settings-validation.js +182 -0
  68. package/lib/settings.d.ts +29 -0
  69. package/lib/settings.js +41 -736
  70. package/lib/setup-apply-types.d.ts +66 -0
  71. package/lib/setup-apply-types.js +2 -0
  72. package/lib/setup-apply.d.ts +39 -0
  73. package/lib/setup-apply.js +267 -264
  74. package/lib/setup-journal.d.ts +41 -0
  75. package/lib/setup-journal.js +119 -76
  76. package/lib/setup-plan-types.d.ts +102 -0
  77. package/lib/setup-plan-types.js +2 -0
  78. package/lib/setup-plan.d.ts +30 -0
  79. package/lib/setup-plan.js +300 -324
  80. package/lib/setup-undo.d.ts +44 -0
  81. package/lib/setup-undo.js +61 -74
  82. package/lib/start-cluster-config.d.ts +26 -0
  83. package/lib/start-cluster-config.js +56 -0
  84. package/lib/start-cluster-environment.d.ts +40 -0
  85. package/lib/start-cluster-environment.js +134 -0
  86. package/lib/start-cluster-run-options.d.ts +53 -0
  87. package/lib/start-cluster-run-options.js +147 -0
  88. package/lib/start-cluster.d.ts +64 -0
  89. package/lib/start-cluster.js +98 -454
  90. package/lib/stream-json-parser.d.ts +17 -0
  91. package/lib/stream-json-parser.js +51 -52
  92. package/npm-shrinkwrap.json +2 -2
  93. package/package.json +12 -6
  94. package/scripts/postinstall.js +27 -0
  95. package/scripts/rust-distribution.js +23 -14
  96. package/src/agent/agent-command-proofs-context.js +35 -45
  97. package/src/agent/agent-command-proofs-context.ts +87 -0
  98. package/src/agent/agent-config-settings.js +19 -0
  99. package/src/agent/agent-config-settings.ts +41 -0
  100. package/src/agent/agent-config.js +122 -231
  101. package/src/agent/agent-config.ts +285 -0
  102. package/src/agent/agent-context-builder.js +38 -273
  103. package/src/agent/agent-context-builder.ts +51 -0
  104. package/src/agent/agent-context-environment-sections.js +105 -0
  105. package/src/agent/agent-context-environment-sections.ts +134 -0
  106. package/src/agent/agent-context-packs.js +165 -0
  107. package/src/agent/agent-context-packs.ts +296 -0
  108. package/src/agent/agent-context-prompt-sections.js +100 -0
  109. package/src/agent/agent-context-prompt-sections.ts +148 -0
  110. package/src/agent/agent-context-sections.js +25 -334
  111. package/src/agent/agent-context-sections.ts +36 -0
  112. package/src/agent/agent-context-sources.js +96 -149
  113. package/src/agent/agent-context-sources.ts +253 -0
  114. package/src/agent/agent-context-types.js +2 -0
  115. package/src/agent/agent-context-types.ts +132 -0
  116. package/src/agent/agent-context-validation-sections.js +73 -0
  117. package/src/agent/agent-context-validation-sections.ts +129 -0
  118. package/src/agent/agent-input-injector.js +99 -118
  119. package/src/agent/agent-input-injector.ts +195 -0
  120. package/src/agent/agent-liveness-poll.js +74 -78
  121. package/src/agent/agent-liveness-poll.ts +163 -0
  122. package/src/agent/agent-quality-gate-schema.js +77 -86
  123. package/src/agent/agent-quality-gate-schema.ts +135 -0
  124. package/src/agent/agent-quality-gates-context.js +44 -50
  125. package/src/agent/agent-quality-gates-context.ts +91 -0
  126. package/src/agent/agent-stuck-detector.js +171 -239
  127. package/src/agent/agent-stuck-detector.ts +288 -0
  128. package/src/agent/agent-trigger-evaluator.js +29 -46
  129. package/src/agent/agent-trigger-evaluator.ts +98 -0
  130. package/src/agent/context-metrics.js +110 -141
  131. package/src/agent/context-metrics.ts +261 -0
  132. package/src/agent/context-pack-builder.js +72 -358
  133. package/src/agent/context-pack-builder.ts +105 -0
  134. package/src/agent/context-pack-core.js +70 -0
  135. package/src/agent/context-pack-core.ts +96 -0
  136. package/src/agent/context-pack-selection.js +119 -0
  137. package/src/agent/context-pack-selection.ts +187 -0
  138. package/src/agent/context-pack-truncation.js +139 -0
  139. package/src/agent/context-pack-truncation.ts +208 -0
  140. package/src/agent/context-pack-types.js +2 -0
  141. package/src/agent/context-pack-types.ts +98 -0
  142. package/src/agent/context-replay-policy.js +30 -39
  143. package/src/agent/context-replay-policy.ts +71 -0
  144. package/src/agent/critical-agent-policy.js +6 -10
  145. package/src/agent/critical-agent-policy.ts +20 -0
  146. package/src/agent/guidance-queue.js +74 -87
  147. package/src/agent/guidance-queue.ts +166 -0
  148. package/src/agent/output-extraction-error-detail.js +45 -0
  149. package/src/agent/output-extraction-error-detail.ts +49 -0
  150. package/src/agent/output-extraction-failures.js +125 -0
  151. package/src/agent/output-extraction-failures.ts +149 -0
  152. package/src/agent/output-extraction-json.js +234 -0
  153. package/src/agent/output-extraction-json.ts +235 -0
  154. package/src/agent/output-extraction-pi.js +124 -0
  155. package/src/agent/output-extraction-pi.ts +137 -0
  156. package/src/agent/output-extraction-types.js +2 -0
  157. package/src/agent/output-extraction-types.ts +49 -0
  158. package/src/agent/output-extraction.js +17 -617
  159. package/src/agent/output-extraction.ts +30 -0
  160. package/src/agent/output-reformatter-errors.js +83 -0
  161. package/src/agent/output-reformatter-errors.ts +106 -0
  162. package/src/agent/output-reformatter-types.js +2 -0
  163. package/src/agent/output-reformatter-types.ts +86 -0
  164. package/src/agent/output-reformatter.js +140 -185
  165. package/src/agent/output-reformatter.ts +238 -0
  166. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  167. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  168. package/src/agent/pi-terminal-lifecycle.js +186 -206
  169. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  170. package/src/agent/provider-control-plane.js +22 -21
  171. package/src/agent/provider-control-plane.ts +52 -0
  172. package/src/agent/provider-terminal-failure-types.js +2 -0
  173. package/src/agent/provider-terminal-failure-types.ts +60 -0
  174. package/src/agent/provider-terminal-failure.js +194 -191
  175. package/src/agent/provider-terminal-failure.ts +262 -0
  176. package/src/agent/rate-limit-backoff.js +31 -74
  177. package/src/agent/rate-limit-backoff.ts +71 -0
  178. package/src/agent/schema-utils.js +85 -125
  179. package/src/agent/schema-utils.ts +148 -0
  180. package/src/agent/structured-output-error.js +34 -33
  181. package/src/agent/structured-output-error.ts +105 -0
  182. package/src/agent/validation-platform.js +27 -27
  183. package/src/agent/validation-platform.ts +49 -0
  184. package/src/agent-cli-provider/adapters/codex.ts +3 -1
  185. package/src/attach/attach-client.js +232 -405
  186. package/src/attach/attach-client.ts +300 -0
  187. package/src/attach/attach-server-cleanup.js +43 -0
  188. package/src/attach/attach-server-cleanup.ts +39 -0
  189. package/src/attach/attach-server-clients.js +117 -0
  190. package/src/attach/attach-server-clients.ts +122 -0
  191. package/src/attach/attach-server-events.js +38 -0
  192. package/src/attach/attach-server-events.ts +36 -0
  193. package/src/attach/attach-server-pty.js +45 -0
  194. package/src/attach/attach-server-pty.ts +64 -0
  195. package/src/attach/attach-server-runtime.js +73 -0
  196. package/src/attach/attach-server-runtime.ts +62 -0
  197. package/src/attach/attach-server-socket.js +28 -0
  198. package/src/attach/attach-server-socket.ts +23 -0
  199. package/src/attach/attach-server-types.js +2 -0
  200. package/src/attach/attach-server-types.ts +82 -0
  201. package/src/attach/attach-server.js +106 -523
  202. package/src/attach/attach-server.ts +158 -0
  203. package/src/attach/index.js +18 -35
  204. package/src/attach/index.ts +18 -0
  205. package/src/attach/protocol.js +95 -184
  206. package/src/attach/protocol.ts +181 -0
  207. package/src/attach/ring-buffer.js +76 -102
  208. package/src/attach/ring-buffer.ts +109 -0
  209. package/src/attach/send-input.js +64 -75
  210. package/src/attach/send-input.ts +94 -0
  211. package/src/attach/socket-discovery.js +164 -218
  212. package/src/attach/socket-discovery.ts +230 -0
  213. package/src/attach/socket-paths.js +42 -61
  214. package/src/attach/socket-paths.ts +81 -0
  215. package/src/claude-credentials.js +51 -54
  216. package/src/claude-credentials.ts +89 -0
  217. package/src/cluster/generated/protocol-schema.ts +1 -1
  218. package/src/cluster/generated/protocol.ts +2 -1
  219. package/src/command-proofs.js +110 -141
  220. package/src/command-proofs.ts +216 -0
  221. package/src/config-router.js +81 -73
  222. package/src/config-router.ts +131 -0
  223. package/src/copy-worker.js +53 -29
  224. package/src/copy-worker.ts +75 -0
  225. package/src/darwin-keychain-boundary.js +80 -111
  226. package/src/darwin-keychain-boundary.ts +148 -0
  227. package/src/guidance-topics.js +4 -5
  228. package/src/guidance-topics.ts +10 -0
  229. package/src/input-helpers.js +33 -54
  230. package/src/input-helpers.ts +58 -0
  231. package/src/ledger-sequence.js +45 -48
  232. package/src/ledger-sequence.ts +63 -0
  233. package/src/legacy-lib/clusters-registry.ts +40 -0
  234. package/src/legacy-lib/completion.ts +148 -0
  235. package/src/legacy-lib/compose-utils.ts +102 -0
  236. package/src/legacy-lib/detached-startup.ts +449 -0
  237. package/src/legacy-lib/docker-config.ts +282 -0
  238. package/src/legacy-lib/docker-env-auth.ts +116 -0
  239. package/src/legacy-lib/git-remote-utils.ts +244 -0
  240. package/src/legacy-lib/id-detector.ts +57 -0
  241. package/src/legacy-lib/js-yaml.d.ts +3 -0
  242. package/src/legacy-lib/omelette.d.ts +15 -0
  243. package/src/legacy-lib/path-check.ts +89 -0
  244. package/src/legacy-lib/process-liveness.ts +36 -0
  245. package/src/legacy-lib/provider-credential-path.ts +57 -0
  246. package/src/legacy-lib/provider-defaults.ts +114 -0
  247. package/src/legacy-lib/provider-detection.ts +67 -0
  248. package/src/legacy-lib/provider-names.ts +126 -0
  249. package/src/legacy-lib/repo-settings.ts +88 -0
  250. package/src/legacy-lib/run-mode.ts +58 -0
  251. package/src/legacy-lib/run-plan.ts +49 -0
  252. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  253. package/src/legacy-lib/settings-defaults.ts +212 -0
  254. package/src/legacy-lib/settings-error.ts +8 -0
  255. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  256. package/src/legacy-lib/settings-models.ts +124 -0
  257. package/src/legacy-lib/settings-storage.ts +277 -0
  258. package/src/legacy-lib/settings-validation.ts +220 -0
  259. package/src/legacy-lib/settings.ts +87 -0
  260. package/src/legacy-lib/setup-apply-types.ts +70 -0
  261. package/src/legacy-lib/setup-apply.ts +456 -0
  262. package/src/legacy-lib/setup-journal.ts +185 -0
  263. package/src/legacy-lib/setup-plan-types.ts +96 -0
  264. package/src/legacy-lib/setup-plan.ts +500 -0
  265. package/src/legacy-lib/setup-undo.ts +142 -0
  266. package/src/legacy-lib/start-cluster-config.ts +124 -0
  267. package/src/legacy-lib/start-cluster-environment.ts +165 -0
  268. package/src/legacy-lib/start-cluster-run-options.ts +279 -0
  269. package/src/legacy-lib/start-cluster.ts +237 -0
  270. package/src/legacy-lib/stream-json-parser.ts +88 -0
  271. package/src/message-buffer.js +55 -71
  272. package/src/message-buffer.ts +107 -0
  273. package/src/message-bus-bridge.js +92 -133
  274. package/src/message-bus-bridge.ts +149 -0
  275. package/src/name-generator-shared.js +220 -0
  276. package/src/name-generator-shared.ts +231 -0
  277. package/src/name-generator.js +8 -217
  278. package/src/name-generator.ts +27 -0
  279. package/src/omp-blob-root.js +83 -64
  280. package/src/omp-blob-root.ts +116 -0
  281. package/src/omp-config-overlay.js +65 -38
  282. package/src/omp-config-overlay.ts +110 -0
  283. package/src/omp-execution-fingerprint.js +38 -43
  284. package/src/omp-execution-fingerprint.ts +92 -0
  285. package/src/omp-session-limits.js +10 -15
  286. package/src/omp-session-limits.ts +53 -0
  287. package/src/omp-session-partition.js +2 -2
  288. package/src/omp-session-verifier.js +1 -1
  289. package/src/orchestrator.js +19 -4
  290. package/src/providers/anthropic/index.js +3 -1
  291. package/src/providers/anthropic/index.ts +13 -0
  292. package/src/providers/capabilities.js +19 -27
  293. package/src/providers/capabilities.ts +44 -0
  294. package/src/providers/google/index.js +3 -1
  295. package/src/providers/google/index.ts +13 -0
  296. package/src/providers/openai/index.js +3 -1
  297. package/src/providers/openai/index.ts +13 -0
  298. package/src/providers/opencode/index.js +3 -1
  299. package/src/providers/opencode/index.ts +13 -0
  300. package/src/quality-gates.js +67 -127
  301. package/src/quality-gates.ts +149 -0
  302. package/src/repo-settings-access.js +40 -0
  303. package/src/repo-settings-access.ts +64 -0
  304. package/src/schemas/sub-cluster.js +127 -183
  305. package/src/schemas/sub-cluster.ts +238 -0
  306. package/src/state-snapshot-normalization.js +224 -0
  307. package/src/state-snapshot-normalization.ts +222 -0
  308. package/src/state-snapshot.js +192 -359
  309. package/src/state-snapshot.ts +291 -0
  310. package/src/state-snapshotter.js +118 -130
  311. package/src/state-snapshotter.ts +167 -0
  312. package/src/sub-cluster-wrapper.js +4 -13
  313. package/src/task-run-model-args.js +87 -124
  314. package/src/task-run-model-args.ts +204 -0
  315. package/src/task-runner.js +5 -25
  316. package/src/task-runner.ts +28 -0
  317. package/src/task-startup-error.js +73 -58
  318. package/src/task-startup-error.ts +126 -0
  319. package/src/template-validation/consensus-gate-contracts.js +2 -0
  320. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  321. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  322. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  323. package/src/template-validation/consensus-gate-stage.js +34 -0
  324. package/src/template-validation/consensus-gate-stage.ts +56 -0
  325. package/src/template-validation/random-topology-contracts.js +2 -0
  326. package/src/template-validation/random-topology-contracts.ts +54 -0
  327. package/src/template-validation/random-topology-dispatch.js +25 -0
  328. package/src/template-validation/random-topology-dispatch.ts +33 -0
  329. package/src/template-validation/random-topology-message-loop.js +53 -0
  330. package/src/template-validation/random-topology-message-loop.ts +73 -0
  331. package/src/template-validation/random-topology-operations.js +79 -0
  332. package/src/template-validation/random-topology-operations.ts +101 -0
  333. package/src/template-validation/random-topology-runtime.js +25 -0
  334. package/src/template-validation/random-topology-runtime.ts +43 -0
  335. package/src/template-validation/random-topology-scenario.js +52 -0
  336. package/src/template-validation/random-topology-scenario.ts +57 -0
  337. package/src/template-validation/random-topology-schema.js +159 -0
  338. package/src/template-validation/random-topology-schema.ts +190 -0
  339. package/src/template-validation/random-topology-state.js +28 -0
  340. package/src/template-validation/random-topology-state.ts +30 -0
  341. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  342. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  343. package/src/template-validation/random-topology-trigger.js +75 -0
  344. package/src/template-validation/random-topology-trigger.ts +88 -0
  345. package/src/template-validation/report-formatter.js +40 -46
  346. package/src/template-validation/report-formatter.ts +101 -0
  347. package/src/template-validation/simulate-consensus-gates.js +111 -302
  348. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  349. package/src/template-validation/simulate-random-topology.js +26 -519
  350. package/src/template-validation/simulate-random-topology.ts +57 -0
  351. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  352. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  353. package/src/template-validation/simulation-agent-runtime.js +25 -0
  354. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  355. package/src/template-validation/simulation-agent.js +29 -0
  356. package/src/template-validation/simulation-agent.ts +73 -0
  357. package/src/template-validation/simulation-runtime.js +34 -0
  358. package/src/template-validation/simulation-runtime.ts +72 -0
  359. package/src/template-validation/two-stage-contracts.js +2 -0
  360. package/src/template-validation/two-stage-contracts.ts +41 -0
  361. package/src/template-validation/two-stage-inputs.js +21 -0
  362. package/src/template-validation/two-stage-inputs.ts +29 -0
  363. package/src/template-validation/two-stage-results.js +30 -0
  364. package/src/template-validation/two-stage-results.ts +40 -0
  365. package/src/template-validation/two-stage-scenario.js +86 -0
  366. package/src/template-validation/two-stage-scenario.ts +120 -0
  367. package/src/worktree-claude-config.js +182 -220
  368. package/src/worktree-claude-config.ts +272 -0
  369. package/src/worktree-tooling-env.js +103 -125
  370. package/src/worktree-tooling-env.ts +142 -0
  371. package/task-lib/completion.js +2 -3
  372. package/task-lib/completion.ts +9 -0
  373. package/task-lib/config.js +1 -4
  374. package/task-lib/config.ts +11 -0
  375. package/task-lib/name-generator.js +4 -226
  376. package/task-lib/name-generator.ts +11 -0
  377. package/task-lib/omp-session-cleanup.js +1 -1
  378. package/task-lib/omp-storage-root.js +8 -12
  379. package/task-lib/omp-storage-root.ts +62 -0
  380. package/task-lib/process-termination.js +143 -166
  381. package/task-lib/process-termination.ts +268 -0
@@ -1,353 +1,178 @@
1
- /**
2
- * Docker mount configuration for isolation mode
3
- * Fully generic - no hardcoded paths, all configurable
4
- */
5
-
6
- const { URL } = require('url');
7
- const { listProviderMetadata, getProviderMetadata } = require('./provider-names');
8
- const { expandProviderCredentialPath } = require('./provider-credential-path');
9
- /**
10
- * Built-in mount presets
11
- * Uses $HOME placeholder - resolved at runtime based on dockerContainerHome setting
12
- * Host paths use ~ (expanded to host user's home)
13
- * Container paths use $HOME (expanded to configured container home)
14
- */
1
+ "use strict";
2
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
3
+ const providerNames = require('./provider-names');
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
5
+ const credentialPaths = require('./provider-credential-path');
6
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
7
+ const dockerEnvAuth = require('./docker-env-auth');
8
+ const { listProviderMetadata } = providerNames;
9
+ const { expandProviderCredentialPath } = credentialPaths;
10
+ const { isUsableEnvValue, isUsableHttpUrl, validateEnvPassthrough, validateProviderEnvAuth, } = dockerEnvAuth;
15
11
  const BASE_MOUNT_PRESETS = {
16
- gh: { host: '~/.config/gh', container: '$HOME/.config/gh', readonly: false },
17
- git: { host: '~/.gitconfig', container: '$HOME/.gitconfig', readonly: true },
18
- ssh: { host: '~/.ssh', container: '$HOME/.ssh', readonly: true },
19
- aws: { host: '~/.aws', container: '$HOME/.aws', readonly: true },
20
- azure: { host: '~/.azure', container: '$HOME/.azure', readonly: true },
21
- kube: { host: '~/.kube', container: '$HOME/.kube', readonly: true },
22
- terraform: { host: '~/.terraform.d', container: '$HOME/.terraform.d', readonly: false },
23
- gcloud: { host: '~/.config/gcloud', container: '$HOME/.config/gcloud', readonly: true },
12
+ gh: { host: '~/.config/gh', container: '$HOME/.config/gh', readonly: false },
13
+ git: { host: '~/.gitconfig', container: '$HOME/.gitconfig', readonly: true },
14
+ ssh: { host: '~/.ssh', container: '$HOME/.ssh', readonly: true },
15
+ aws: { host: '~/.aws', container: '$HOME/.aws', readonly: true },
16
+ azure: { host: '~/.azure', container: '$HOME/.azure', readonly: true },
17
+ kube: { host: '~/.kube', container: '$HOME/.kube', readonly: true },
18
+ terraform: { host: '~/.terraform.d', container: '$HOME/.terraform.d', readonly: false },
19
+ gcloud: { host: '~/.config/gcloud', container: '$HOME/.config/gcloud', readonly: true },
24
20
  };
25
-
26
- /**
27
- * Environment variables to auto-pass for each preset
28
- * Supports:
29
- * - Simple: 'VAR_NAME' (pass if set in host env)
30
- * - Pattern: 'VAR_*' (pass all matching vars)
31
- * - Forced: 'VAR=value' (always set to value)
32
- * - Empty: 'VAR=' (always set to empty string)
33
- */
34
21
  const BASE_ENV_PRESETS = {
35
- aws: ['AWS_REGION', 'AWS_DEFAULT_REGION', 'AWS_PROFILE', 'AWS_PAGER='],
36
- azure: ['AZURE_SUBSCRIPTION_ID', 'AZURE_TENANT_ID', 'AZURE_CLIENT_ID'],
37
- gcloud: ['CLOUDSDK_CORE_PROJECT', 'GOOGLE_CLOUD_PROJECT'],
38
- kube: ['KUBECONFIG'],
39
- terraform: ['TF_VAR_*'],
22
+ aws: ['AWS_REGION', 'AWS_DEFAULT_REGION', 'AWS_PROFILE', 'AWS_PAGER='],
23
+ azure: ['AZURE_SUBSCRIPTION_ID', 'AZURE_TENANT_ID', 'AZURE_CLIENT_ID'],
24
+ gcloud: ['CLOUDSDK_CORE_PROJECT', 'GOOGLE_CLOUD_PROJECT'],
25
+ kube: ['KUBECONFIG'],
26
+ terraform: ['TF_VAR_*'],
40
27
  };
41
-
42
28
  function listProviderDockerPresetEntries() {
43
- return listProviderMetadata().map((metadata) => [metadata.id, metadata.docker]);
29
+ return listProviderMetadata().map((metadata) => [metadata.id, metadata.docker]);
30
+ }
31
+ function listProviderMountEntries() {
32
+ const entries = [];
33
+ for (const [providerId, docker] of listProviderDockerPresetEntries()) {
34
+ if (docker.mount) {
35
+ entries.push([providerId, docker.mount]);
36
+ }
37
+ }
38
+ return entries;
44
39
  }
45
-
46
40
  const MOUNT_PRESETS = Object.freeze({
47
- ...BASE_MOUNT_PRESETS,
48
- ...Object.fromEntries(
49
- listProviderDockerPresetEntries()
50
- .filter(([, docker]) => docker.mount)
51
- .map(([providerId, docker]) => [providerId, docker.mount])
52
- ),
41
+ ...BASE_MOUNT_PRESETS,
42
+ ...Object.fromEntries(listProviderMountEntries()),
53
43
  });
54
-
55
44
  const ENV_PRESETS = Object.freeze({
56
- ...BASE_ENV_PRESETS,
57
- ...Object.fromEntries(
58
- listProviderDockerPresetEntries().map(([providerId, docker]) => [
59
- providerId,
60
- [...docker.envPassthrough],
61
- ])
62
- ),
45
+ ...BASE_ENV_PRESETS,
46
+ ...Object.fromEntries(listProviderDockerPresetEntries().map(([providerId, docker]) => [
47
+ providerId,
48
+ [...docker.envPassthrough],
49
+ ])),
63
50
  });
64
-
65
- // Providers that declare an envPassthrough preset but no automatic mount (e.g. omp: env/broker
66
- // auth only, zero automatic credential mounts). `resolveMounts` treats these as a valid preset
67
- // that resolves to no mount specs, rather than an unknown-preset error.
68
- const PROVIDER_ENV_ONLY_PRESETS = Object.freeze(
69
- new Set(
70
- listProviderDockerPresetEntries()
71
- .filter(([, docker]) => !docker.mount && docker.envPassthrough.length > 0)
72
- .map(([providerId]) => providerId)
73
- )
74
- );
75
-
76
- /**
77
- * Resolve mount config to actual mount specs
78
- * @param {Array<string|object>} config - Preset names or {host, container, readonly?} objects
79
- * @param {object} options - Resolution options
80
- * @param {string} [options.containerHome='/root'] - Container home directory for $HOME expansion
81
- * @returns {Array<{host: string, container: string, readonly: boolean}>}
82
- */
83
- function resolveMounts(config, options = {}) {
84
- if (!Array.isArray(config)) {
85
- throw new Error('dockerMounts must be an array');
86
- }
87
-
88
- const containerHome = options.containerHome || '/root';
89
-
90
- return config.flatMap((item) => {
51
+ const PROVIDER_ENV_ONLY_PRESETS = Object.freeze(new Set(listProviderDockerPresetEntries()
52
+ .filter(([, docker]) => !docker.mount && docker.envPassthrough.length > 0)
53
+ .map(([providerId]) => providerId)));
54
+ function isCustomMount(value) {
55
+ return typeof value === 'object' && value !== null;
56
+ }
57
+ function resolveMountItem(item, containerHome) {
91
58
  if (typeof item === 'string') {
92
- const preset = MOUNT_PRESETS[item];
93
- if (!preset) {
94
- if (PROVIDER_ENV_ONLY_PRESETS.has(item)) {
95
- return [];
59
+ const preset = MOUNT_PRESETS[item];
60
+ if (!preset) {
61
+ if (PROVIDER_ENV_ONLY_PRESETS.has(item)) {
62
+ return [];
63
+ }
64
+ throw new Error(`Unknown mount preset: "${item}". Valid presets: ${Object.keys(MOUNT_PRESETS).join(', ')}. ` +
65
+ `Env-only presets (no mount): ${[...PROVIDER_ENV_ONLY_PRESETS].join(', ')}`);
96
66
  }
97
- throw new Error(
98
- `Unknown mount preset: "${item}". Valid presets: ${Object.keys(MOUNT_PRESETS).join(', ')}. ` +
99
- `Env-only presets (no mount): ${[...PROVIDER_ENV_ONLY_PRESETS].join(', ')}`
100
- );
101
- }
102
- const overriddenHost =
103
- typeof preset.hostEnv === 'string' && process.env[preset.hostEnv]?.trim()
104
- ? expandProviderCredentialPath(`$${preset.hostEnv}`)
105
- : preset.host;
106
- return {
107
- host: overriddenHost,
108
- container: preset.container.replace(/\$HOME/g, containerHome),
109
- readonly: preset.readonly,
110
- };
67
+ const overriddenHost = typeof preset.hostEnv === 'string' && process.env[preset.hostEnv]?.trim()
68
+ ? expandProviderCredentialPath(`$${preset.hostEnv}`)
69
+ : preset.host;
70
+ return [
71
+ {
72
+ host: overriddenHost,
73
+ container: preset.container.replace(/\$HOME/g, containerHome),
74
+ readonly: preset.readonly,
75
+ },
76
+ ];
111
77
  }
112
-
113
- if (typeof item === 'object' && item !== null) {
114
- if (!item.host || !item.container) {
115
- throw new Error('Custom mount must have "host" and "container" properties');
116
- }
117
- return {
118
- host: item.host,
119
- container: item.container.replace(/\$HOME/g, containerHome),
120
- readonly: item.readonly !== false,
121
- };
78
+ if (isCustomMount(item)) {
79
+ if (!item.host || !item.container) {
80
+ throw new Error('Custom mount must have "host" and "container" properties');
81
+ }
82
+ return [
83
+ {
84
+ host: item.host,
85
+ container: item.container.replace(/\$HOME/g, containerHome),
86
+ readonly: item.readonly !== false,
87
+ },
88
+ ];
122
89
  }
123
-
124
- throw new Error(
125
- `Invalid mount config: ${JSON.stringify(item)}. Use preset name or {host, container, readonly?}`
126
- );
127
- });
90
+ throw new Error(`Invalid mount config: ${JSON.stringify(item)}. Use preset name or {host, container, readonly?}`);
91
+ }
92
+ function resolveMounts(config, options = {}) {
93
+ if (!Array.isArray(config)) {
94
+ throw new Error('dockerMounts must be an array');
95
+ }
96
+ const containerHome = options.containerHome || '/root';
97
+ return config.flatMap((item) => resolveMountItem(item, containerHome));
128
98
  }
129
-
130
- /**
131
- * Resolve env vars to pass based on enabled presets + explicit additions
132
- * @param {Array<string|object>} mountConfig - The mount config (to detect presets)
133
- * @param {Array<string>} extraEnvs - Additional env vars to pass
134
- * @returns {Array<string>} - List of env var specs
135
- */
136
99
  function resolveEnvs(mountConfig, extraEnvs = []) {
137
- const envs = new Set(extraEnvs);
138
-
139
- for (const item of mountConfig) {
140
- if (typeof item === 'string' && ENV_PRESETS[item]) {
141
- for (const envVar of ENV_PRESETS[item]) {
142
- envs.add(envVar);
143
- }
100
+ const envs = new Set(extraEnvs);
101
+ for (const item of mountConfig) {
102
+ if (typeof item === 'string') {
103
+ const preset = ENV_PRESETS[item];
104
+ if (preset) {
105
+ for (const envVar of preset) {
106
+ envs.add(envVar);
107
+ }
108
+ }
109
+ }
144
110
  }
145
- }
146
-
147
- return [...envs];
111
+ return [...envs];
148
112
  }
149
-
150
- /**
151
- * Expand env var patterns and resolve values
152
- * Supports:
153
- * - Simple: 'VAR_NAME' (use value from env if set)
154
- * - Pattern: 'VAR_*' (expand to all matching vars)
155
- * - Forced: 'VAR=value' (always set to value)
156
- * - Empty: 'VAR=' (always set to empty string)
157
- *
158
- * @param {Array<string>} envVars - List of env var specs
159
- * @param {object} env - Environment object (defaults to process.env)
160
- * @returns {Array<{name: string, value: string|null, forced: boolean}>}
161
- */
162
113
  function expandEnvPatterns(envVars, env = process.env) {
163
- const result = [];
164
-
165
- for (const envVar of envVars) {
166
- // Forced value: VAR=value or VAR=
167
- if (envVar.includes('=')) {
168
- const [name, ...valueParts] = envVar.split('=');
169
- const value = valueParts.join('=');
170
- result.push({ name, value, forced: true });
171
- }
172
- // Pattern: VAR_*
173
- else if (envVar.endsWith('*')) {
174
- const prefix = envVar.slice(0, -1);
175
- for (const key of Object.keys(env)) {
176
- if (key.startsWith(prefix)) {
177
- result.push({ name: key, value: null, forced: false });
114
+ const result = [];
115
+ for (const envVar of envVars) {
116
+ if (envVar.includes('=')) {
117
+ const separator = envVar.indexOf('=');
118
+ result.push({
119
+ name: envVar.slice(0, separator),
120
+ value: envVar.slice(separator + 1),
121
+ forced: true,
122
+ });
123
+ }
124
+ else if (envVar.endsWith('*')) {
125
+ const prefix = envVar.slice(0, -1);
126
+ for (const key of Object.keys(env)) {
127
+ if (key.startsWith(prefix)) {
128
+ result.push({ name: key, value: null, forced: false });
129
+ }
130
+ }
131
+ }
132
+ else {
133
+ result.push({ name: envVar, value: null, forced: false });
178
134
  }
179
- }
180
- }
181
- // Simple: VAR_NAME
182
- else {
183
- result.push({ name: envVar, value: null, forced: false });
184
135
  }
185
- }
186
-
187
- return result;
136
+ return result;
188
137
  }
189
-
190
- /**
191
- * Validate mount config
192
- * @param {unknown} value - Value to validate
193
- * @returns {string|null} - Error message if invalid, null if valid
194
- */
195
138
  function validateMountConfig(value) {
196
- if (!Array.isArray(value)) {
197
- return 'dockerMounts must be an array';
198
- }
199
-
200
- for (const item of value) {
201
- if (typeof item === 'string') {
202
- if (!MOUNT_PRESETS[item] && !PROVIDER_ENV_ONLY_PRESETS.has(item)) {
203
- return (
204
- `Unknown mount preset: "${item}". Valid: ${Object.keys(MOUNT_PRESETS).join(', ')}. ` +
205
- `Env-only presets (no mount): ${[...PROVIDER_ENV_ONLY_PRESETS].join(', ')}`
206
- );
207
- }
208
- } else if (typeof item === 'object' && item !== null) {
209
- if (!item.host) {
210
- return 'Custom mount missing "host" property';
211
- }
212
- if (!item.container) {
213
- return 'Custom mount missing "container" property';
214
- }
215
- if (item.readonly !== undefined && typeof item.readonly !== 'boolean') {
216
- return '"readonly" must be a boolean';
217
- }
218
- } else {
219
- return `Invalid mount: ${JSON.stringify(item)}. Use preset name or {host, container, readonly?}`;
220
- }
221
- }
222
-
223
- return null;
224
- }
225
-
226
- /**
227
- * Validate env passthrough config
228
- * @param {unknown} value - Value to validate
229
- * @returns {string|null} - Error message if invalid, null if valid
230
- */
231
- function validateEnvPassthrough(value) {
232
- if (!Array.isArray(value)) {
233
- return 'dockerEnvPassthrough must be an array';
234
- }
235
-
236
- for (const item of value) {
237
- if (typeof item !== 'string') {
238
- return `Invalid env var: ${JSON.stringify(item)}. Must be a string`;
239
- }
240
- // Allow: VAR, VAR_*, VAR=value, VAR=
241
- if (!/^[A-Z_][A-Z0-9_]*(\*|=.*)?$/i.test(item)) {
242
- return `Invalid env var spec: "${item}". Use VAR, VAR_*, or VAR=value`;
243
- }
244
- }
245
-
246
- return null;
247
- }
248
-
249
- /**
250
- * A credential env var counts as present only when the container would actually receive a
251
- * usable value. An absent, non-string, empty, or whitespace-only value is NOT a credential —
252
- * `dockerEnvPassthrough: ["OPENAI_API_KEY="]` forces an empty value into `docker run -e`, which
253
- * would otherwise read as "authenticated" while the CLI inside the container has nothing to use.
254
- * @param {unknown} value
255
- * @returns {boolean}
256
- */
257
- function isUsableEnvValue(value) {
258
- return typeof value === 'string' && value.trim() !== '';
259
- }
260
-
261
- /**
262
- * A broker/base-URL env var is usable only when it parses as an absolute http(s) URL. Anything
263
- * else (a bare host, a `file:` URL, a token pasted into the URL slot) fails closed rather than
264
- * being handed to the provider to blow up on inside the container.
265
- * @param {unknown} value
266
- * @returns {boolean}
267
- */
268
- function isUsableHttpUrl(value) {
269
- if (!isUsableEnvValue(value)) {
270
- return false;
271
- }
272
- let parsed;
273
- try {
274
- parsed = new URL(value.trim());
275
- } catch {
276
- return false;
277
- }
278
- return parsed.protocol === 'http:' || parsed.protocol === 'https:';
279
- }
280
-
281
- /**
282
- * Validate a provider's fail-closed env/broker auth requirement (registry `docker.envAuth`)
283
- * against the env vars actually forwarded into the container, using their ACTUAL values (a
284
- * presence flag cannot distinguish a real key from a forced-empty one). Providers with no
285
- * `envAuth` declared always pass (their auth is validated by mount/credential presence instead).
286
- *
287
- * Never includes a value in its output — only variable NAMES.
288
- *
289
- * @param {string} providerId
290
- * @param {Record<string, string|undefined>} forwardedEnv - NAME -> the exact value the container
291
- * would receive
292
- * @returns {{ok: boolean, satisfiedOneOf: boolean, malformed: string[], message: string}}
293
- * `satisfiedOneOf` reports whether an *automatic allowlist* credential is usable; `malformed`
294
- * lists hard plan defects (partial required pair, unusable URL) that no other credential can
295
- * compensate for. `ok` is the combination of both.
296
- */
297
- function validateProviderEnvAuth(providerId, forwardedEnv) {
298
- const metadata = getProviderMetadata(providerId);
299
- const envAuth = metadata.docker && metadata.docker.envAuth;
300
- if (!envAuth) {
301
- return { ok: true, satisfiedOneOf: true, malformed: [], message: '' };
302
- }
303
-
304
- const requireUrl = new Set(envAuth.requireUrl || []);
305
- const valueOf = (name) => (forwardedEnv ? forwardedEnv[name] : undefined);
306
- // A URL-shaped var counts as "set" only when it is a usable http(s) URL; a malformed one is
307
- // reported separately below so the remediation says "malformed", not "missing".
308
- const isSet = (name) =>
309
- requireUrl.has(name) ? isUsableHttpUrl(valueOf(name)) : isUsableEnvValue(valueOf(name));
310
-
311
- const requireOneOf = envAuth.requireOneOf || [];
312
- const satisfiedOneOf = requireOneOf.length === 0 || requireOneOf.some(isSet);
313
-
314
- const malformed = [];
315
- for (const name of requireUrl) {
316
- if (isUsableEnvValue(valueOf(name)) && !isUsableHttpUrl(valueOf(name))) {
317
- malformed.push(`${name} is set but is not a usable http(s) URL`);
139
+ if (!Array.isArray(value)) {
140
+ return 'dockerMounts must be an array';
318
141
  }
319
- }
320
-
321
- for (const group of envAuth.requireTogether || []) {
322
- const missing = group.filter((name) => !isSet(name));
323
- if (missing.length > 0 && missing.length < group.length) {
324
- malformed.push(`${group.join(' + ')} must be set together (missing ${missing.join(', ')})`);
142
+ for (const item of value) {
143
+ if (typeof item === 'string') {
144
+ if (!MOUNT_PRESETS[item] && !PROVIDER_ENV_ONLY_PRESETS.has(item)) {
145
+ return (`Unknown mount preset: "${item}". Valid: ${Object.keys(MOUNT_PRESETS).join(', ')}. ` +
146
+ `Env-only presets (no mount): ${[...PROVIDER_ENV_ONLY_PRESETS].join(', ')}`);
147
+ }
148
+ }
149
+ else if (isCustomMount(item)) {
150
+ if (!item.host) {
151
+ return 'Custom mount missing "host" property';
152
+ }
153
+ if (!item.container) {
154
+ return 'Custom mount missing "container" property';
155
+ }
156
+ if (item.readonly !== undefined && typeof item.readonly !== 'boolean') {
157
+ return '"readonly" must be a boolean';
158
+ }
159
+ }
160
+ else {
161
+ return `Invalid mount: ${JSON.stringify(item)}. Use preset name or {host, container, readonly?}`;
162
+ }
325
163
  }
326
- }
327
-
328
- const reasons = [...malformed];
329
- if (!satisfiedOneOf) {
330
- reasons.push(`one of ${requireOneOf.join(', ')} must be set to a non-empty value`);
331
- }
332
-
333
- return {
334
- ok: malformed.length === 0 && satisfiedOneOf,
335
- satisfiedOneOf,
336
- malformed,
337
- message: reasons.join('; '),
338
- };
164
+ return null;
339
165
  }
340
-
341
166
  module.exports = {
342
- MOUNT_PRESETS,
343
- ENV_PRESETS,
344
- PROVIDER_ENV_ONLY_PRESETS,
345
- resolveMounts,
346
- resolveEnvs,
347
- expandEnvPatterns,
348
- isUsableEnvValue,
349
- isUsableHttpUrl,
350
- validateMountConfig,
351
- validateEnvPassthrough,
352
- validateProviderEnvAuth,
167
+ MOUNT_PRESETS,
168
+ ENV_PRESETS,
169
+ PROVIDER_ENV_ONLY_PRESETS,
170
+ resolveMounts,
171
+ resolveEnvs,
172
+ expandEnvPatterns,
173
+ isUsableEnvValue,
174
+ isUsableHttpUrl,
175
+ validateMountConfig,
176
+ validateEnvPassthrough,
177
+ validateProviderEnvAuth,
353
178
  };
@@ -0,0 +1,17 @@
1
+ interface ProviderEnvAuthResult {
2
+ ok: boolean;
3
+ satisfiedOneOf: boolean;
4
+ malformed: string[];
5
+ message: string;
6
+ }
7
+ declare function validateEnvPassthrough(value: unknown): string | null;
8
+ declare function isUsableEnvValue(value: unknown): value is string;
9
+ declare function isUsableHttpUrl(value: unknown): boolean;
10
+ declare function validateProviderEnvAuth(providerId: string, forwardedEnv: Readonly<Record<string, string | undefined>> | null | undefined): ProviderEnvAuthResult;
11
+ declare const _default: {
12
+ isUsableEnvValue: typeof isUsableEnvValue;
13
+ isUsableHttpUrl: typeof isUsableHttpUrl;
14
+ validateEnvPassthrough: typeof validateEnvPassthrough;
15
+ validateProviderEnvAuth: typeof validateProviderEnvAuth;
16
+ };
17
+ export = _default;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ const url_1 = require("url");
3
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
4
+ const providerNames = require('./provider-names');
5
+ const ENV_SPEC_PATTERN = /^[A-Z_][A-Z0-9_]*(\*|=.*)?$/i;
6
+ function validateEnvPassthrough(value) {
7
+ if (!Array.isArray(value)) {
8
+ return 'dockerEnvPassthrough must be an array';
9
+ }
10
+ for (const item of value) {
11
+ if (typeof item !== 'string') {
12
+ return `Invalid env var: ${JSON.stringify(item)}. Must be a string`;
13
+ }
14
+ if (!ENV_SPEC_PATTERN.test(item)) {
15
+ return `Invalid env var spec: "${item}". Use VAR, VAR_*, or VAR=value`;
16
+ }
17
+ }
18
+ return null;
19
+ }
20
+ function isUsableEnvValue(value) {
21
+ return typeof value === 'string' && value.trim() !== '';
22
+ }
23
+ function isUsableHttpUrl(value) {
24
+ if (!isUsableEnvValue(value)) {
25
+ return false;
26
+ }
27
+ let parsed;
28
+ try {
29
+ parsed = new url_1.URL(value.trim());
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ return parsed.protocol === 'http:' || parsed.protocol === 'https:';
35
+ }
36
+ function validateProviderEnvAuth(providerId, forwardedEnv) {
37
+ const metadata = providerNames.getProviderMetadata(providerId);
38
+ const envAuth = metadata.docker && metadata.docker.envAuth;
39
+ if (!envAuth) {
40
+ return { ok: true, satisfiedOneOf: true, malformed: [], message: '' };
41
+ }
42
+ const requireUrl = new Set(envAuth.requireUrl || []);
43
+ const valueOf = (name) => forwardedEnv ? forwardedEnv[name] : undefined;
44
+ const isSet = (name) => requireUrl.has(name) ? isUsableHttpUrl(valueOf(name)) : isUsableEnvValue(valueOf(name));
45
+ const requireOneOf = envAuth.requireOneOf || [];
46
+ const satisfiedOneOf = requireOneOf.length === 0 || requireOneOf.some(isSet);
47
+ const malformed = [];
48
+ for (const name of requireUrl) {
49
+ if (isUsableEnvValue(valueOf(name)) && !isUsableHttpUrl(valueOf(name))) {
50
+ malformed.push(`${name} is set but is not a usable http(s) URL`);
51
+ }
52
+ }
53
+ for (const group of envAuth.requireTogether || []) {
54
+ const missing = group.filter((name) => !isSet(name));
55
+ if (missing.length > 0 && missing.length < group.length) {
56
+ malformed.push(`${group.join(' + ')} must be set together (missing ${missing.join(', ')})`);
57
+ }
58
+ }
59
+ const reasons = [...malformed];
60
+ if (!satisfiedOneOf) {
61
+ reasons.push(`one of ${requireOneOf.join(', ')} must be set to a non-empty value`);
62
+ }
63
+ return {
64
+ ok: malformed.length === 0 && satisfiedOneOf,
65
+ satisfiedOneOf,
66
+ malformed,
67
+ message: reasons.join('; '),
68
+ };
69
+ }
70
+ module.exports = {
71
+ isUsableEnvValue,
72
+ isUsableHttpUrl,
73
+ validateEnvPassthrough,
74
+ validateProviderEnvAuth,
75
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Git remote URL parsing and provider detection.
3
+ * Automatically detects issue provider from git remote URL.
4
+ */
5
+ interface HostedGitContext {
6
+ provider: 'github' | 'gitlab';
7
+ host: string;
8
+ org: string;
9
+ repo: string;
10
+ fullRepo: string;
11
+ }
12
+ interface AzureDevOpsGitContext {
13
+ provider: 'azure-devops';
14
+ host: string;
15
+ azureOrg: string;
16
+ azureProject: string;
17
+ repo: string;
18
+ }
19
+ type GitContext = HostedGitContext | AzureDevOpsGitContext;
20
+ type GitContextWithRemote = GitContext & {
21
+ remote: string;
22
+ };
23
+ /**
24
+ * Normalize a Git remote name using the same ref-format rules Git applies to
25
+ * refs/remotes/<name>. Keeping this next to detection prevents a discovered
26
+ * remote from being rejected later by a narrower consumer-specific allowlist.
27
+ */
28
+ declare function normalizeGitRemoteName(value: unknown): string | null;
29
+ /** Quote one argument for the POSIX shell snippets embedded in agent prompts. */
30
+ declare function quoteShellArgument(value: string): string;
31
+ /**
32
+ * Parse git remote URL into structured provider context.
33
+ * Supports GitHub, GitLab, and Azure DevOps (cloud + self-hosted).
34
+ * Handles both HTTPS and SSH URL formats.
35
+ */
36
+ declare function parseGitRemoteUrl(remoteUrl: unknown): GitContext | null;
37
+ /**
38
+ * Detect git repository context from current working directory.
39
+ * Returns provider context extracted from git remote URL.
40
+ */
41
+ declare function detectGitContext(cwd?: string): GitContextWithRemote | null;
42
+ declare const _default: {
43
+ normalizeGitRemoteName: typeof normalizeGitRemoteName;
44
+ quoteShellArgument: typeof quoteShellArgument;
45
+ parseGitRemoteUrl: typeof parseGitRemoteUrl;
46
+ detectGitContext: typeof detectGitContext;
47
+ };
48
+ export = _default;