@the-open-engine/zeroshot 6.38.1 → 6.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/README.md +6 -0
  2. package/cli/event-copy.js +8 -7
  3. package/cli/event-copy.ts +12 -0
  4. package/cli/index.js +67 -48
  5. package/cli/json-export.js +61 -64
  6. package/cli/json-export.ts +112 -0
  7. package/cli/message-formatter-utils.js +68 -56
  8. package/cli/message-formatter-utils.ts +121 -0
  9. package/cli/message-formatters-normal.js +124 -259
  10. package/cli/message-formatters-normal.ts +250 -0
  11. package/cli/message-formatters-watch.js +81 -84
  12. package/cli/message-formatters-watch.ts +189 -0
  13. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  14. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  15. package/lib/cluster/generated/protocol.d.cts +8 -0
  16. package/lib/cluster/generated/protocol.d.mts +8 -0
  17. package/lib/cluster/generated/protocol.d.ts +8 -0
  18. package/lib/clusters-registry.d.ts +23 -0
  19. package/lib/clusters-registry.js +17 -29
  20. package/lib/completion.d.ts +12 -0
  21. package/lib/completion.js +84 -94
  22. package/lib/compose-utils.d.ts +32 -0
  23. package/lib/compose-utils.js +57 -72
  24. package/lib/detached-startup.d.ts +84 -0
  25. package/lib/detached-startup.js +232 -302
  26. package/lib/docker-config.d.ts +43 -0
  27. package/lib/docker-config.js +150 -325
  28. package/lib/docker-env-auth.d.ts +17 -0
  29. package/lib/docker-env-auth.js +75 -0
  30. package/lib/git-remote-utils.d.ts +48 -0
  31. package/lib/git-remote-utils.js +147 -213
  32. package/lib/id-detector.d.ts +15 -0
  33. package/lib/id-detector.js +37 -41
  34. package/lib/path-check.d.ts +30 -0
  35. package/lib/path-check.js +42 -45
  36. package/lib/process-liveness.d.ts +16 -0
  37. package/lib/process-liveness.js +19 -12
  38. package/lib/provider-credential-path.d.ts +16 -0
  39. package/lib/provider-credential-path.js +31 -29
  40. package/lib/provider-defaults.d.ts +30 -0
  41. package/lib/provider-defaults.js +47 -42
  42. package/lib/provider-detection.d.ts +11 -0
  43. package/lib/provider-detection.js +91 -54
  44. package/lib/provider-names.d.ts +38 -0
  45. package/lib/provider-names.js +56 -64
  46. package/lib/repo-settings.d.ts +28 -0
  47. package/lib/repo-settings.js +83 -59
  48. package/lib/run-mode.d.ts +21 -0
  49. package/lib/run-mode.js +21 -20
  50. package/lib/run-plan.d.ts +28 -0
  51. package/lib/run-plan.js +17 -16
  52. package/lib/settings/claude-auth.d.ts +35 -0
  53. package/lib/settings/claude-auth.js +30 -47
  54. package/lib/settings-defaults.d.ts +20 -0
  55. package/lib/settings-defaults.js +149 -0
  56. package/lib/settings-error.d.ts +7 -0
  57. package/lib/settings-error.js +8 -0
  58. package/lib/settings-issue-providers.d.ts +10 -0
  59. package/lib/settings-issue-providers.js +12 -0
  60. package/lib/settings-models.d.ts +22 -0
  61. package/lib/settings-models.js +93 -0
  62. package/lib/settings-storage.d.ts +23 -0
  63. package/lib/settings-storage.js +205 -0
  64. package/lib/settings-validation.d.ts +7 -0
  65. package/lib/settings-validation.js +182 -0
  66. package/lib/settings.d.ts +29 -0
  67. package/lib/settings.js +41 -736
  68. package/lib/setup-apply-types.d.ts +66 -0
  69. package/lib/setup-apply-types.js +2 -0
  70. package/lib/setup-apply.d.ts +39 -0
  71. package/lib/setup-apply.js +267 -264
  72. package/lib/setup-journal.d.ts +41 -0
  73. package/lib/setup-journal.js +119 -76
  74. package/lib/setup-plan-types.d.ts +102 -0
  75. package/lib/setup-plan-types.js +2 -0
  76. package/lib/setup-plan.d.ts +30 -0
  77. package/lib/setup-plan.js +300 -324
  78. package/lib/setup-undo.d.ts +44 -0
  79. package/lib/setup-undo.js +61 -74
  80. package/lib/start-cluster-config.d.ts +26 -0
  81. package/lib/start-cluster-config.js +56 -0
  82. package/lib/start-cluster-environment.d.ts +41 -0
  83. package/lib/start-cluster-environment.js +134 -0
  84. package/lib/start-cluster-run-options.d.ts +54 -0
  85. package/lib/start-cluster-run-options.js +148 -0
  86. package/lib/start-cluster.d.ts +64 -0
  87. package/lib/start-cluster.js +98 -454
  88. package/lib/stream-json-parser.d.ts +17 -0
  89. package/lib/stream-json-parser.js +51 -52
  90. package/npm-shrinkwrap.json +6 -8
  91. package/package.json +14 -8
  92. package/scripts/postinstall.js +27 -0
  93. package/scripts/rust-distribution.js +36 -45
  94. package/src/agent/agent-command-proofs-context.js +35 -45
  95. package/src/agent/agent-command-proofs-context.ts +87 -0
  96. package/src/agent/agent-config-settings.js +19 -0
  97. package/src/agent/agent-config-settings.ts +41 -0
  98. package/src/agent/agent-config.js +122 -231
  99. package/src/agent/agent-config.ts +285 -0
  100. package/src/agent/agent-context-builder.js +38 -273
  101. package/src/agent/agent-context-builder.ts +51 -0
  102. package/src/agent/agent-context-environment-sections.js +105 -0
  103. package/src/agent/agent-context-environment-sections.ts +134 -0
  104. package/src/agent/agent-context-packs.js +165 -0
  105. package/src/agent/agent-context-packs.ts +296 -0
  106. package/src/agent/agent-context-prompt-sections.js +100 -0
  107. package/src/agent/agent-context-prompt-sections.ts +148 -0
  108. package/src/agent/agent-context-sections.js +25 -334
  109. package/src/agent/agent-context-sections.ts +36 -0
  110. package/src/agent/agent-context-sources.js +96 -149
  111. package/src/agent/agent-context-sources.ts +253 -0
  112. package/src/agent/agent-context-types.js +2 -0
  113. package/src/agent/agent-context-types.ts +132 -0
  114. package/src/agent/agent-context-validation-sections.js +73 -0
  115. package/src/agent/agent-context-validation-sections.ts +129 -0
  116. package/src/agent/agent-input-injector.js +99 -118
  117. package/src/agent/agent-input-injector.ts +195 -0
  118. package/src/agent/agent-liveness-poll.js +74 -78
  119. package/src/agent/agent-liveness-poll.ts +163 -0
  120. package/src/agent/agent-quality-gate-schema.js +77 -86
  121. package/src/agent/agent-quality-gate-schema.ts +135 -0
  122. package/src/agent/agent-quality-gates-context.js +44 -50
  123. package/src/agent/agent-quality-gates-context.ts +91 -0
  124. package/src/agent/agent-stuck-detector.js +171 -239
  125. package/src/agent/agent-stuck-detector.ts +288 -0
  126. package/src/agent/agent-trigger-evaluator.js +29 -46
  127. package/src/agent/agent-trigger-evaluator.ts +98 -0
  128. package/src/agent/context-metrics.js +110 -141
  129. package/src/agent/context-metrics.ts +261 -0
  130. package/src/agent/context-pack-builder.js +72 -358
  131. package/src/agent/context-pack-builder.ts +105 -0
  132. package/src/agent/context-pack-core.js +70 -0
  133. package/src/agent/context-pack-core.ts +96 -0
  134. package/src/agent/context-pack-selection.js +119 -0
  135. package/src/agent/context-pack-selection.ts +187 -0
  136. package/src/agent/context-pack-truncation.js +139 -0
  137. package/src/agent/context-pack-truncation.ts +208 -0
  138. package/src/agent/context-pack-types.js +2 -0
  139. package/src/agent/context-pack-types.ts +98 -0
  140. package/src/agent/context-replay-policy.js +30 -39
  141. package/src/agent/context-replay-policy.ts +71 -0
  142. package/src/agent/critical-agent-policy.js +6 -10
  143. package/src/agent/critical-agent-policy.ts +20 -0
  144. package/src/agent/guidance-queue.js +74 -87
  145. package/src/agent/guidance-queue.ts +166 -0
  146. package/src/agent/output-extraction-error-detail.js +45 -0
  147. package/src/agent/output-extraction-error-detail.ts +49 -0
  148. package/src/agent/output-extraction-failures.js +125 -0
  149. package/src/agent/output-extraction-failures.ts +149 -0
  150. package/src/agent/output-extraction-json.js +234 -0
  151. package/src/agent/output-extraction-json.ts +235 -0
  152. package/src/agent/output-extraction-pi.js +124 -0
  153. package/src/agent/output-extraction-pi.ts +137 -0
  154. package/src/agent/output-extraction-types.js +2 -0
  155. package/src/agent/output-extraction-types.ts +49 -0
  156. package/src/agent/output-extraction.js +17 -617
  157. package/src/agent/output-extraction.ts +30 -0
  158. package/src/agent/output-reformatter-errors.js +83 -0
  159. package/src/agent/output-reformatter-errors.ts +106 -0
  160. package/src/agent/output-reformatter-types.js +2 -0
  161. package/src/agent/output-reformatter-types.ts +86 -0
  162. package/src/agent/output-reformatter.js +140 -185
  163. package/src/agent/output-reformatter.ts +238 -0
  164. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  165. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  166. package/src/agent/pi-terminal-lifecycle.js +186 -206
  167. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  168. package/src/agent/provider-control-plane.js +22 -21
  169. package/src/agent/provider-control-plane.ts +52 -0
  170. package/src/agent/provider-terminal-failure-types.js +2 -0
  171. package/src/agent/provider-terminal-failure-types.ts +60 -0
  172. package/src/agent/provider-terminal-failure.js +194 -191
  173. package/src/agent/provider-terminal-failure.ts +262 -0
  174. package/src/agent/rate-limit-backoff.js +31 -74
  175. package/src/agent/rate-limit-backoff.ts +71 -0
  176. package/src/agent/schema-utils.js +85 -125
  177. package/src/agent/schema-utils.ts +148 -0
  178. package/src/agent/structured-output-error.js +34 -33
  179. package/src/agent/structured-output-error.ts +105 -0
  180. package/src/agent/validation-platform.js +27 -27
  181. package/src/agent/validation-platform.ts +49 -0
  182. package/src/agents/git-pusher-template.js +17 -34
  183. package/src/attach/attach-client.js +232 -405
  184. package/src/attach/attach-client.ts +300 -0
  185. package/src/attach/attach-server-cleanup.js +43 -0
  186. package/src/attach/attach-server-cleanup.ts +39 -0
  187. package/src/attach/attach-server-clients.js +117 -0
  188. package/src/attach/attach-server-clients.ts +122 -0
  189. package/src/attach/attach-server-events.js +38 -0
  190. package/src/attach/attach-server-events.ts +36 -0
  191. package/src/attach/attach-server-pty.js +45 -0
  192. package/src/attach/attach-server-pty.ts +64 -0
  193. package/src/attach/attach-server-runtime.js +73 -0
  194. package/src/attach/attach-server-runtime.ts +62 -0
  195. package/src/attach/attach-server-socket.js +28 -0
  196. package/src/attach/attach-server-socket.ts +23 -0
  197. package/src/attach/attach-server-types.js +2 -0
  198. package/src/attach/attach-server-types.ts +82 -0
  199. package/src/attach/attach-server.js +106 -523
  200. package/src/attach/attach-server.ts +158 -0
  201. package/src/attach/index.js +18 -35
  202. package/src/attach/index.ts +18 -0
  203. package/src/attach/protocol.js +95 -184
  204. package/src/attach/protocol.ts +181 -0
  205. package/src/attach/ring-buffer.js +76 -102
  206. package/src/attach/ring-buffer.ts +109 -0
  207. package/src/attach/send-input.js +64 -75
  208. package/src/attach/send-input.ts +94 -0
  209. package/src/attach/socket-discovery.js +164 -218
  210. package/src/attach/socket-discovery.ts +230 -0
  211. package/src/attach/socket-paths.js +42 -61
  212. package/src/attach/socket-paths.ts +81 -0
  213. package/src/claude-credentials.js +51 -54
  214. package/src/claude-credentials.ts +89 -0
  215. package/src/cluster/generated/protocol-schema.ts +1 -1
  216. package/src/cluster/generated/protocol.ts +2 -1
  217. package/src/command-proofs.js +110 -141
  218. package/src/command-proofs.ts +216 -0
  219. package/src/config-router.js +81 -73
  220. package/src/config-router.ts +131 -0
  221. package/src/copy-containment.js +191 -0
  222. package/src/copy-containment.ts +259 -0
  223. package/src/copy-worker.js +53 -30
  224. package/src/copy-worker.ts +88 -0
  225. package/src/darwin-keychain-boundary.js +80 -111
  226. package/src/darwin-keychain-boundary.ts +148 -0
  227. package/src/guidance-topics.js +4 -5
  228. package/src/guidance-topics.ts +10 -0
  229. package/src/input-helpers.js +33 -54
  230. package/src/input-helpers.ts +58 -0
  231. package/src/isolation-manager.js +59 -20
  232. package/src/ledger-sequence.js +45 -48
  233. package/src/ledger-sequence.ts +63 -0
  234. package/src/legacy-lib/clusters-registry.ts +40 -0
  235. package/src/legacy-lib/completion.ts +148 -0
  236. package/src/legacy-lib/compose-utils.ts +102 -0
  237. package/src/legacy-lib/detached-startup.ts +451 -0
  238. package/src/legacy-lib/docker-config.ts +282 -0
  239. package/src/legacy-lib/docker-env-auth.ts +116 -0
  240. package/src/legacy-lib/git-remote-utils.ts +244 -0
  241. package/src/legacy-lib/id-detector.ts +57 -0
  242. package/src/legacy-lib/js-yaml.d.ts +3 -0
  243. package/src/legacy-lib/omelette.d.ts +15 -0
  244. package/src/legacy-lib/path-check.ts +89 -0
  245. package/src/legacy-lib/process-liveness.ts +36 -0
  246. package/src/legacy-lib/provider-credential-path.ts +57 -0
  247. package/src/legacy-lib/provider-defaults.ts +114 -0
  248. package/src/legacy-lib/provider-detection.ts +67 -0
  249. package/src/legacy-lib/provider-names.ts +126 -0
  250. package/src/legacy-lib/repo-settings.ts +88 -0
  251. package/src/legacy-lib/run-mode.ts +58 -0
  252. package/src/legacy-lib/run-plan.ts +49 -0
  253. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  254. package/src/legacy-lib/settings-defaults.ts +212 -0
  255. package/src/legacy-lib/settings-error.ts +8 -0
  256. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  257. package/src/legacy-lib/settings-models.ts +124 -0
  258. package/src/legacy-lib/settings-storage.ts +277 -0
  259. package/src/legacy-lib/settings-validation.ts +220 -0
  260. package/src/legacy-lib/settings.ts +87 -0
  261. package/src/legacy-lib/setup-apply-types.ts +70 -0
  262. package/src/legacy-lib/setup-apply.ts +456 -0
  263. package/src/legacy-lib/setup-journal.ts +185 -0
  264. package/src/legacy-lib/setup-plan-types.ts +96 -0
  265. package/src/legacy-lib/setup-plan.ts +500 -0
  266. package/src/legacy-lib/setup-undo.ts +142 -0
  267. package/src/legacy-lib/start-cluster-config.ts +124 -0
  268. package/src/legacy-lib/start-cluster-environment.ts +166 -0
  269. package/src/legacy-lib/start-cluster-run-options.ts +281 -0
  270. package/src/legacy-lib/start-cluster.ts +237 -0
  271. package/src/legacy-lib/stream-json-parser.ts +88 -0
  272. package/src/message-buffer.js +55 -71
  273. package/src/message-buffer.ts +107 -0
  274. package/src/message-bus-bridge.js +92 -133
  275. package/src/message-bus-bridge.ts +149 -0
  276. package/src/name-generator-shared.js +220 -0
  277. package/src/name-generator-shared.ts +231 -0
  278. package/src/name-generator.js +8 -217
  279. package/src/name-generator.ts +27 -0
  280. package/src/omp-blob-root.js +83 -64
  281. package/src/omp-blob-root.ts +116 -0
  282. package/src/omp-config-overlay.js +65 -38
  283. package/src/omp-config-overlay.ts +110 -0
  284. package/src/omp-execution-fingerprint.js +38 -43
  285. package/src/omp-execution-fingerprint.ts +92 -0
  286. package/src/omp-session-limits.js +10 -15
  287. package/src/omp-session-limits.ts +53 -0
  288. package/src/omp-session-partition.js +2 -2
  289. package/src/omp-session-verifier.js +1 -1
  290. package/src/orchestrator.js +32 -7
  291. package/src/pr-body-template.js +71 -0
  292. package/src/providers/anthropic/index.js +3 -1
  293. package/src/providers/anthropic/index.ts +13 -0
  294. package/src/providers/capabilities.js +19 -27
  295. package/src/providers/capabilities.ts +44 -0
  296. package/src/providers/google/index.js +3 -1
  297. package/src/providers/google/index.ts +13 -0
  298. package/src/providers/openai/index.js +3 -1
  299. package/src/providers/openai/index.ts +13 -0
  300. package/src/providers/opencode/index.js +3 -1
  301. package/src/providers/opencode/index.ts +13 -0
  302. package/src/quality-gates.js +67 -127
  303. package/src/quality-gates.ts +149 -0
  304. package/src/repo-settings-access.js +40 -0
  305. package/src/repo-settings-access.ts +64 -0
  306. package/src/schemas/sub-cluster.js +127 -183
  307. package/src/schemas/sub-cluster.ts +238 -0
  308. package/src/state-snapshot-normalization.js +224 -0
  309. package/src/state-snapshot-normalization.ts +222 -0
  310. package/src/state-snapshot.js +192 -359
  311. package/src/state-snapshot.ts +291 -0
  312. package/src/state-snapshotter.js +118 -130
  313. package/src/state-snapshotter.ts +167 -0
  314. package/src/sub-cluster-wrapper.js +4 -13
  315. package/src/task-run-model-args.js +87 -124
  316. package/src/task-run-model-args.ts +204 -0
  317. package/src/task-runner.js +5 -25
  318. package/src/task-runner.ts +28 -0
  319. package/src/task-startup-error.js +73 -58
  320. package/src/task-startup-error.ts +126 -0
  321. package/src/template-validation/consensus-gate-contracts.js +2 -0
  322. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  323. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  324. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  325. package/src/template-validation/consensus-gate-stage.js +34 -0
  326. package/src/template-validation/consensus-gate-stage.ts +56 -0
  327. package/src/template-validation/random-topology-contracts.js +2 -0
  328. package/src/template-validation/random-topology-contracts.ts +54 -0
  329. package/src/template-validation/random-topology-dispatch.js +25 -0
  330. package/src/template-validation/random-topology-dispatch.ts +33 -0
  331. package/src/template-validation/random-topology-message-loop.js +53 -0
  332. package/src/template-validation/random-topology-message-loop.ts +73 -0
  333. package/src/template-validation/random-topology-operations.js +79 -0
  334. package/src/template-validation/random-topology-operations.ts +101 -0
  335. package/src/template-validation/random-topology-runtime.js +25 -0
  336. package/src/template-validation/random-topology-runtime.ts +43 -0
  337. package/src/template-validation/random-topology-scenario.js +52 -0
  338. package/src/template-validation/random-topology-scenario.ts +57 -0
  339. package/src/template-validation/random-topology-schema.js +159 -0
  340. package/src/template-validation/random-topology-schema.ts +190 -0
  341. package/src/template-validation/random-topology-state.js +28 -0
  342. package/src/template-validation/random-topology-state.ts +30 -0
  343. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  344. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  345. package/src/template-validation/random-topology-trigger.js +75 -0
  346. package/src/template-validation/random-topology-trigger.ts +88 -0
  347. package/src/template-validation/report-formatter.js +40 -46
  348. package/src/template-validation/report-formatter.ts +101 -0
  349. package/src/template-validation/simulate-consensus-gates.js +111 -302
  350. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  351. package/src/template-validation/simulate-random-topology.js +26 -519
  352. package/src/template-validation/simulate-random-topology.ts +57 -0
  353. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  354. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  355. package/src/template-validation/simulation-agent-runtime.js +25 -0
  356. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  357. package/src/template-validation/simulation-agent.js +29 -0
  358. package/src/template-validation/simulation-agent.ts +73 -0
  359. package/src/template-validation/simulation-runtime.js +34 -0
  360. package/src/template-validation/simulation-runtime.ts +72 -0
  361. package/src/template-validation/two-stage-contracts.js +2 -0
  362. package/src/template-validation/two-stage-contracts.ts +41 -0
  363. package/src/template-validation/two-stage-inputs.js +21 -0
  364. package/src/template-validation/two-stage-inputs.ts +29 -0
  365. package/src/template-validation/two-stage-results.js +30 -0
  366. package/src/template-validation/two-stage-results.ts +40 -0
  367. package/src/template-validation/two-stage-scenario.js +86 -0
  368. package/src/template-validation/two-stage-scenario.ts +120 -0
  369. package/src/worktree-claude-config.js +182 -220
  370. package/src/worktree-claude-config.ts +272 -0
  371. package/src/worktree-tooling-env.js +103 -125
  372. package/src/worktree-tooling-env.ts +142 -0
  373. package/task-lib/completion.js +2 -3
  374. package/task-lib/completion.ts +9 -0
  375. package/task-lib/config.js +1 -4
  376. package/task-lib/config.ts +11 -0
  377. package/task-lib/name-generator.js +4 -226
  378. package/task-lib/name-generator.ts +11 -0
  379. package/task-lib/omp-session-cleanup.js +1 -1
  380. package/task-lib/omp-storage-root.js +8 -12
  381. package/task-lib/omp-storage-root.ts +62 -0
  382. package/task-lib/process-termination.js +143 -166
  383. package/task-lib/process-termination.ts +268 -0
@@ -1,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;