smol-symphony 0.2.0 → 0.3.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 (716) hide show
  1. package/AGENTS.md +41 -22
  2. package/DESIGN.md +494 -273
  3. package/README.md +109 -57
  4. package/SPEC.md +33 -24
  5. package/WORKFLOW.minimal.yaml +34 -0
  6. package/{WORKFLOW.template.md → WORKFLOW.template.yaml} +409 -256
  7. package/WORKFLOW.yaml +487 -0
  8. package/assets/skills/symphony-issues/SKILL.md +136 -0
  9. package/assets/symphony-mise.system.toml +68 -0
  10. package/dist/src/bin/symphony.js +30 -0
  11. package/dist/src/bin/symphony.js.map +1 -0
  12. package/dist/src/core/actions/context.js +109 -0
  13. package/dist/src/core/actions/context.js.map +1 -0
  14. package/dist/{actions/parsing.js → src/core/actions/parse.js} +33 -114
  15. package/dist/src/core/actions/parse.js.map +1 -0
  16. package/dist/src/core/actions/plan.js +197 -0
  17. package/dist/src/core/actions/plan.js.map +1 -0
  18. package/dist/src/core/actions/predicates.js +111 -0
  19. package/dist/src/core/actions/predicates.js.map +1 -0
  20. package/dist/src/core/actions/run-fold.js +248 -0
  21. package/dist/src/core/actions/run-fold.js.map +1 -0
  22. package/dist/src/core/actions/template.js +118 -0
  23. package/dist/src/core/actions/template.js.map +1 -0
  24. package/dist/src/core/cli/args.js +116 -0
  25. package/dist/src/core/cli/args.js.map +1 -0
  26. package/dist/src/core/coerce.js +75 -0
  27. package/dist/src/core/coerce.js.map +1 -0
  28. package/dist/src/core/credential/account-id.js +20 -0
  29. package/dist/src/core/credential/account-id.js.map +1 -0
  30. package/dist/src/core/credential/adapter-config.js +136 -0
  31. package/dist/src/core/credential/adapter-config.js.map +1 -0
  32. package/dist/src/core/credential/availability.js +98 -0
  33. package/dist/src/core/credential/availability.js.map +1 -0
  34. package/dist/src/core/credential/extract.js +228 -0
  35. package/dist/src/core/credential/extract.js.map +1 -0
  36. package/dist/src/core/credential/fake-creds.js +171 -0
  37. package/dist/src/core/credential/fake-creds.js.map +1 -0
  38. package/dist/src/core/credential/identity.js +125 -0
  39. package/dist/src/core/credential/identity.js.map +1 -0
  40. package/dist/src/core/credential/shape.js +230 -0
  41. package/dist/src/core/credential/shape.js.map +1 -0
  42. package/dist/src/core/credential/strings.js +15 -0
  43. package/dist/src/core/credential/strings.js.map +1 -0
  44. package/dist/src/core/doctor/checks.js +303 -0
  45. package/dist/src/core/doctor/checks.js.map +1 -0
  46. package/dist/src/core/git/result.js +107 -0
  47. package/dist/src/core/git/result.js.map +1 -0
  48. package/dist/src/core/http/decisions.js +225 -0
  49. package/dist/src/core/http/decisions.js.map +1 -0
  50. package/dist/{http.js → src/core/http/render.js} +472 -738
  51. package/dist/src/core/http/render.js.map +1 -0
  52. package/dist/{http-handlers.js → src/core/http/routes.js} +52 -87
  53. package/dist/src/core/http/routes.js.map +1 -0
  54. package/dist/src/core/http/views.js +181 -0
  55. package/dist/src/core/http/views.js.map +1 -0
  56. package/dist/src/core/image/managed-image.js +95 -0
  57. package/dist/src/core/image/managed-image.js.map +1 -0
  58. package/dist/src/core/issue/file.js +149 -0
  59. package/dist/src/core/issue/file.js.map +1 -0
  60. package/dist/src/core/issue/parse.js +210 -0
  61. package/dist/src/core/issue/parse.js.map +1 -0
  62. package/dist/src/core/mcp/dispatch.js +239 -0
  63. package/dist/src/core/mcp/dispatch.js.map +1 -0
  64. package/dist/src/core/mcp/post-move.js +92 -0
  65. package/dist/src/core/mcp/post-move.js.map +1 -0
  66. package/dist/src/core/mcp/protocol.js +293 -0
  67. package/dist/src/core/mcp/protocol.js.map +1 -0
  68. package/dist/src/core/mcp/url.js +162 -0
  69. package/dist/src/core/mcp/url.js.map +1 -0
  70. package/dist/src/core/path.js +63 -0
  71. package/dist/src/core/path.js.map +1 -0
  72. package/dist/src/core/reconcile/image-decide.js +48 -0
  73. package/dist/src/core/reconcile/image-decide.js.map +1 -0
  74. package/dist/src/core/reconcile/ledger.js +142 -0
  75. package/dist/src/core/reconcile/ledger.js.map +1 -0
  76. package/dist/src/core/reconcile/pr-classify.js +62 -0
  77. package/dist/src/core/reconcile/pr-classify.js.map +1 -0
  78. package/dist/{reconciler → src/core/reconcile}/pr-decide.js +25 -12
  79. package/dist/src/core/reconcile/pr-decide.js.map +1 -0
  80. package/dist/src/core/reconcile/pr-loop.js +161 -0
  81. package/dist/src/core/reconcile/pr-loop.js.map +1 -0
  82. package/dist/src/core/reconcile/pr-notes.js +35 -0
  83. package/dist/src/core/reconcile/pr-notes.js.map +1 -0
  84. package/dist/src/core/reconcile/vm-decide.js +70 -0
  85. package/dist/src/core/reconcile/vm-decide.js.map +1 -0
  86. package/dist/src/core/reconcile/vm-reap.js +207 -0
  87. package/dist/src/core/reconcile/vm-reap.js.map +1 -0
  88. package/dist/src/core/reconcile/workspace-decide.js +162 -0
  89. package/dist/src/core/reconcile/workspace-decide.js.map +1 -0
  90. package/dist/src/core/runlog/summary.js +231 -0
  91. package/dist/src/core/runlog/summary.js.map +1 -0
  92. package/dist/src/core/runner/dispatch-config.js +95 -0
  93. package/dist/src/core/runner/dispatch-config.js.map +1 -0
  94. package/dist/src/core/runner/injection.js +61 -0
  95. package/dist/src/core/runner/injection.js.map +1 -0
  96. package/dist/src/core/runner/mise.js +210 -0
  97. package/dist/src/core/runner/mise.js.map +1 -0
  98. package/dist/src/core/runner/prompt.js +720 -0
  99. package/dist/src/core/runner/prompt.js.map +1 -0
  100. package/dist/src/core/runner/turn.js +242 -0
  101. package/dist/src/core/runner/turn.js.map +1 -0
  102. package/dist/src/core/runner/vm-plan.js +390 -0
  103. package/dist/src/core/runner/vm-plan.js.map +1 -0
  104. package/dist/src/core/schedule/admission.js +123 -0
  105. package/dist/src/core/schedule/admission.js.map +1 -0
  106. package/dist/src/core/schedule/circuit-breaker.js +111 -0
  107. package/dist/src/core/schedule/circuit-breaker.js.map +1 -0
  108. package/dist/src/core/schedule/eligibility.js +83 -0
  109. package/dist/src/core/schedule/eligibility.js.map +1 -0
  110. package/dist/src/core/schedule/reconcile-issue.js +82 -0
  111. package/dist/src/core/schedule/reconcile-issue.js.map +1 -0
  112. package/dist/src/core/schedule/retry.js +96 -0
  113. package/dist/src/core/schedule/retry.js.map +1 -0
  114. package/dist/src/core/schedule/sleep-cycle.js +133 -0
  115. package/dist/src/core/schedule/sleep-cycle.js.map +1 -0
  116. package/dist/src/core/schedule/slots.js +124 -0
  117. package/dist/src/core/schedule/slots.js.map +1 -0
  118. package/dist/src/core/schedule/tick.js +553 -0
  119. package/dist/src/core/schedule/tick.js.map +1 -0
  120. package/dist/src/core/schedule/token-fold.js +181 -0
  121. package/dist/src/core/schedule/token-fold.js.map +1 -0
  122. package/dist/src/core/state-resolve.js +86 -0
  123. package/dist/src/core/state-resolve.js.map +1 -0
  124. package/dist/src/core/vm-guards.js +278 -0
  125. package/dist/src/core/vm-guards.js.map +1 -0
  126. package/dist/src/core/workflow/derive.js +107 -0
  127. package/dist/src/core/workflow/derive.js.map +1 -0
  128. package/dist/src/core/workflow/parse.js +687 -0
  129. package/dist/src/core/workflow/parse.js.map +1 -0
  130. package/dist/src/core/workflow/prompt-probe.js +78 -0
  131. package/dist/src/core/workflow/prompt-probe.js.map +1 -0
  132. package/dist/src/core/workflow/validate.js +189 -0
  133. package/dist/src/core/workflow/validate.js.map +1 -0
  134. package/dist/src/core/workspace-key.js +19 -0
  135. package/dist/src/core/workspace-key.js.map +1 -0
  136. package/dist/src/shell/actions-runner.js +356 -0
  137. package/dist/src/shell/actions-runner.js.map +1 -0
  138. package/dist/src/shell/adapter/adapter-registry.js +45 -0
  139. package/dist/src/shell/adapter/adapter-registry.js.map +1 -0
  140. package/dist/src/shell/adapter/clock-random.js +96 -0
  141. package/dist/src/shell/adapter/clock-random.js.map +1 -0
  142. package/dist/src/shell/adapter/gondolin-dispatch-helpers.js +158 -0
  143. package/dist/src/shell/adapter/gondolin-dispatch-helpers.js.map +1 -0
  144. package/dist/src/shell/adapter/gondolin-dispatch.js +385 -0
  145. package/dist/src/shell/adapter/gondolin-dispatch.js.map +1 -0
  146. package/dist/src/shell/adapter/gondolin-image-converter.js +233 -0
  147. package/dist/src/shell/adapter/gondolin-image-converter.js.map +1 -0
  148. package/dist/src/shell/adapter/gondolin-image-fetch.js +180 -0
  149. package/dist/src/shell/adapter/gondolin-image-fetch.js.map +1 -0
  150. package/dist/src/shell/adapter/launcher-asset.js +57 -0
  151. package/dist/src/shell/adapter/launcher-asset.js.map +1 -0
  152. package/dist/src/shell/adapter/mise-config-asset.js +65 -0
  153. package/dist/src/shell/adapter/mise-config-asset.js.map +1 -0
  154. package/dist/src/shell/adapter/workflow-loader.js +304 -0
  155. package/dist/src/shell/adapter/workflow-loader.js.map +1 -0
  156. package/dist/src/shell/cli/doctor.js +268 -0
  157. package/dist/src/shell/cli/doctor.js.map +1 -0
  158. package/dist/src/shell/effect-interpreter-families.js +314 -0
  159. package/dist/src/shell/effect-interpreter-families.js.map +1 -0
  160. package/dist/src/shell/effect-interpreter.js +29 -0
  161. package/dist/src/shell/effect-interpreter.js.map +1 -0
  162. package/dist/src/shell/interp/acp-frame.js +137 -0
  163. package/dist/src/shell/interp/acp-frame.js.map +1 -0
  164. package/dist/src/shell/interp/acp-ws-conn.js +320 -0
  165. package/dist/src/shell/interp/acp-ws-conn.js.map +1 -0
  166. package/dist/src/shell/interp/acp-ws-frames.js +159 -0
  167. package/dist/src/shell/interp/acp-ws-frames.js.map +1 -0
  168. package/dist/src/shell/interp/acp-ws.js +197 -0
  169. package/dist/src/shell/interp/acp-ws.js.map +1 -0
  170. package/dist/src/shell/interp/acp.js +319 -0
  171. package/dist/src/shell/interp/acp.js.map +1 -0
  172. package/dist/src/shell/interp/credential-defaults.js +128 -0
  173. package/dist/src/shell/interp/credential-defaults.js.map +1 -0
  174. package/dist/src/shell/interp/credential-hooks.js +149 -0
  175. package/dist/src/shell/interp/credential-hooks.js.map +1 -0
  176. package/dist/src/shell/interp/credential-registry.js +226 -0
  177. package/dist/src/shell/interp/credential-registry.js.map +1 -0
  178. package/dist/src/shell/interp/credential.js +103 -0
  179. package/dist/src/shell/interp/credential.js.map +1 -0
  180. package/dist/src/shell/interp/gh.js +163 -0
  181. package/dist/src/shell/interp/gh.js.map +1 -0
  182. package/dist/src/shell/interp/git.js +28 -0
  183. package/dist/src/shell/interp/git.js.map +1 -0
  184. package/dist/src/shell/interp/log.js +213 -0
  185. package/dist/src/shell/interp/log.js.map +1 -0
  186. package/dist/src/shell/interp/process.js +178 -0
  187. package/dist/src/shell/interp/process.js.map +1 -0
  188. package/dist/src/shell/interp/runlog.js +193 -0
  189. package/dist/src/shell/interp/runlog.js.map +1 -0
  190. package/dist/src/shell/interp/timer.js +64 -0
  191. package/dist/src/shell/interp/timer.js.map +1 -0
  192. package/dist/src/shell/interp/tracker-disk.js +99 -0
  193. package/dist/src/shell/interp/tracker-disk.js.map +1 -0
  194. package/dist/src/shell/interp/tracker-parse.js +71 -0
  195. package/dist/src/shell/interp/tracker-parse.js.map +1 -0
  196. package/dist/src/shell/interp/tracker-scan.js +238 -0
  197. package/dist/src/shell/interp/tracker-scan.js.map +1 -0
  198. package/dist/src/shell/interp/tracker-write.js +91 -0
  199. package/dist/src/shell/interp/tracker-write.js.map +1 -0
  200. package/dist/src/shell/interp/tracker.js +41 -0
  201. package/dist/src/shell/interp/tracker.js.map +1 -0
  202. package/dist/src/shell/interp/tty.js +48 -0
  203. package/dist/src/shell/interp/tty.js.map +1 -0
  204. package/dist/src/shell/interp/vm.js +199 -0
  205. package/dist/src/shell/interp/vm.js.map +1 -0
  206. package/dist/src/shell/interp/workspace.js +310 -0
  207. package/dist/src/shell/interp/workspace.js.map +1 -0
  208. package/dist/src/shell/main-acp.js +78 -0
  209. package/dist/src/shell/main-acp.js.map +1 -0
  210. package/dist/src/shell/main-adapters.js +222 -0
  211. package/dist/src/shell/main-adapters.js.map +1 -0
  212. package/dist/src/shell/main-credential.js +122 -0
  213. package/dist/src/shell/main-credential.js.map +1 -0
  214. package/dist/src/shell/main-doctor.js +22 -0
  215. package/dist/src/shell/main-doctor.js.map +1 -0
  216. package/dist/src/shell/main-entry.js +46 -0
  217. package/dist/src/shell/main-entry.js.map +1 -0
  218. package/dist/src/shell/main-http-csrf.js +45 -0
  219. package/dist/src/shell/main-http-csrf.js.map +1 -0
  220. package/dist/src/shell/main-http-handler.js +389 -0
  221. package/dist/src/shell/main-http-handler.js.map +1 -0
  222. package/dist/src/shell/main-http-mcp.js +122 -0
  223. package/dist/src/shell/main-http-mcp.js.map +1 -0
  224. package/dist/src/shell/main-http-views.js +253 -0
  225. package/dist/src/shell/main-http-views.js.map +1 -0
  226. package/dist/src/shell/main-http.js +76 -0
  227. package/dist/src/shell/main-http.js.map +1 -0
  228. package/dist/src/shell/main-loops.js +130 -0
  229. package/dist/src/shell/main-loops.js.map +1 -0
  230. package/dist/src/shell/main-mcp.js +129 -0
  231. package/dist/src/shell/main-mcp.js.map +1 -0
  232. package/dist/src/shell/main-orchestrator.js +120 -0
  233. package/dist/src/shell/main-orchestrator.js.map +1 -0
  234. package/dist/src/shell/main-preflight.js +43 -0
  235. package/dist/src/shell/main-preflight.js.map +1 -0
  236. package/dist/src/shell/main-reconcilers-helpers.js +244 -0
  237. package/dist/src/shell/main-reconcilers-helpers.js.map +1 -0
  238. package/dist/src/shell/main-reconcilers-pr.js +148 -0
  239. package/dist/src/shell/main-reconcilers-pr.js.map +1 -0
  240. package/dist/src/shell/main-reconcilers.js +225 -0
  241. package/dist/src/shell/main-reconcilers.js.map +1 -0
  242. package/dist/src/shell/main-runner.js +355 -0
  243. package/dist/src/shell/main-runner.js.map +1 -0
  244. package/dist/src/shell/main-scaffold.js +116 -0
  245. package/dist/src/shell/main-scaffold.js.map +1 -0
  246. package/dist/src/shell/main-shutdown.js +115 -0
  247. package/dist/src/shell/main-shutdown.js.map +1 -0
  248. package/dist/src/shell/main-startup.js +48 -0
  249. package/dist/src/shell/main-startup.js.map +1 -0
  250. package/dist/src/shell/main-substrates.js +43 -0
  251. package/dist/src/shell/main-substrates.js.map +1 -0
  252. package/dist/src/shell/main.js +385 -0
  253. package/dist/src/shell/main.js.map +1 -0
  254. package/dist/src/shell/orchestrator-feedback.js +69 -0
  255. package/dist/src/shell/orchestrator-feedback.js.map +1 -0
  256. package/dist/src/shell/orchestrator-image.js +167 -0
  257. package/dist/src/shell/orchestrator-image.js.map +1 -0
  258. package/dist/src/shell/orchestrator-loop.js +468 -0
  259. package/dist/src/shell/orchestrator-loop.js.map +1 -0
  260. package/dist/src/shell/orchestrator-reconcile.js +36 -0
  261. package/dist/src/shell/orchestrator-reconcile.js.map +1 -0
  262. package/dist/src/shell/reconciler-loop.js +228 -0
  263. package/dist/src/shell/reconciler-loop.js.map +1 -0
  264. package/dist/src/shell/runner-loop-turn.js +301 -0
  265. package/dist/src/shell/runner-loop-turn.js.map +1 -0
  266. package/dist/src/shell/runner-loop.js +338 -0
  267. package/dist/src/shell/runner-loop.js.map +1 -0
  268. package/dist/src/shell/server/http.js +208 -0
  269. package/dist/src/shell/server/http.js.map +1 -0
  270. package/dist/src/shell/server/mcp-runtime-effects.js +237 -0
  271. package/dist/src/shell/server/mcp-runtime-effects.js.map +1 -0
  272. package/dist/src/shell/server/mcp-runtime.js +99 -0
  273. package/dist/src/shell/server/mcp-runtime.js.map +1 -0
  274. package/dist/src/shell/workspace-key.js +14 -0
  275. package/dist/src/shell/workspace-key.js.map +1 -0
  276. package/dist/src/types/acp.js +8 -0
  277. package/dist/src/types/acp.js.map +1 -0
  278. package/dist/src/types/actions/plan.js +6 -0
  279. package/dist/src/types/actions/plan.js.map +1 -0
  280. package/dist/src/types/actions/predicates.js +6 -0
  281. package/dist/src/types/actions/predicates.js.map +1 -0
  282. package/dist/src/types/actions/run-fold.js +8 -0
  283. package/dist/src/types/actions/run-fold.js.map +1 -0
  284. package/dist/src/types/actions.js +7 -0
  285. package/dist/src/types/actions.js.map +1 -0
  286. package/dist/src/types/adapter/clock-random.js +4 -0
  287. package/dist/src/types/adapter/clock-random.js.map +1 -0
  288. package/dist/src/types/adapter/gondolin-image-converter.js +5 -0
  289. package/dist/src/types/adapter/gondolin-image-converter.js.map +1 -0
  290. package/dist/src/types/adapter/gondolin-image-fetch.js +5 -0
  291. package/dist/src/types/adapter/gondolin-image-fetch.js.map +1 -0
  292. package/dist/src/types/adapter/workflow-loader.js +4 -0
  293. package/dist/src/types/adapter/workflow-loader.js.map +1 -0
  294. package/dist/src/types/cli/args.js +8 -0
  295. package/dist/src/types/cli/args.js.map +1 -0
  296. package/dist/src/types/config.js +8 -0
  297. package/dist/src/types/config.js.map +1 -0
  298. package/dist/src/types/credential-interp.js +6 -0
  299. package/dist/src/types/credential-interp.js.map +1 -0
  300. package/dist/src/types/credentials.js +10 -0
  301. package/dist/src/types/credentials.js.map +1 -0
  302. package/dist/src/types/doctor.js +7 -0
  303. package/dist/src/types/doctor.js.map +1 -0
  304. package/dist/src/types/domain.js +7 -0
  305. package/dist/src/types/domain.js.map +1 -0
  306. package/dist/src/types/effect.js +15 -0
  307. package/dist/src/types/effect.js.map +1 -0
  308. package/dist/src/types/errors.js +39 -0
  309. package/dist/src/types/errors.js.map +1 -0
  310. package/dist/src/types/http/decisions.js +6 -0
  311. package/dist/src/types/http/decisions.js.map +1 -0
  312. package/dist/src/types/http/render.js +10 -0
  313. package/dist/src/types/http/render.js.map +1 -0
  314. package/dist/src/types/http/views.js +6 -0
  315. package/dist/src/types/http/views.js.map +1 -0
  316. package/dist/src/types/http.js +9 -0
  317. package/dist/src/types/http.js.map +1 -0
  318. package/dist/src/types/image/managed-image.js +7 -0
  319. package/dist/src/types/image/managed-image.js.map +1 -0
  320. package/dist/src/types/interp/effect-interpreter.js +8 -0
  321. package/dist/src/types/interp/effect-interpreter.js.map +1 -0
  322. package/dist/src/types/interp/tracker.js +7 -0
  323. package/dist/src/types/interp/tracker.js.map +1 -0
  324. package/dist/src/types/issue/file.js +6 -0
  325. package/dist/src/types/issue/file.js.map +1 -0
  326. package/dist/src/types/issue/parse.js +8 -0
  327. package/dist/src/types/issue/parse.js.map +1 -0
  328. package/dist/src/types/main-acp.js +13 -0
  329. package/dist/src/types/main-acp.js.map +1 -0
  330. package/dist/src/types/main-adapters.js +5 -0
  331. package/dist/src/types/main-adapters.js.map +1 -0
  332. package/dist/src/types/main-credential.js +21 -0
  333. package/dist/src/types/main-credential.js.map +1 -0
  334. package/dist/src/types/main-doctor.js +6 -0
  335. package/dist/src/types/main-doctor.js.map +1 -0
  336. package/dist/src/types/main-http-handler.js +12 -0
  337. package/dist/src/types/main-http-handler.js.map +1 -0
  338. package/dist/src/types/main-http.js +5 -0
  339. package/dist/src/types/main-http.js.map +1 -0
  340. package/dist/src/types/main-loops.js +5 -0
  341. package/dist/src/types/main-loops.js.map +1 -0
  342. package/dist/src/types/main-mcp.js +12 -0
  343. package/dist/src/types/main-mcp.js.map +1 -0
  344. package/dist/src/types/main-orchestrator.js +5 -0
  345. package/dist/src/types/main-orchestrator.js.map +1 -0
  346. package/dist/src/types/main-reconcilers.js +11 -0
  347. package/dist/src/types/main-reconcilers.js.map +1 -0
  348. package/dist/src/types/main-runner.js +13 -0
  349. package/dist/src/types/main-runner.js.map +1 -0
  350. package/dist/src/types/main-startup.js +5 -0
  351. package/dist/src/types/main-startup.js.map +1 -0
  352. package/dist/src/types/main-substrates.js +5 -0
  353. package/dist/src/types/main-substrates.js.map +1 -0
  354. package/dist/src/types/mcp/dispatch.js +4 -0
  355. package/dist/src/types/mcp/dispatch.js.map +1 -0
  356. package/dist/src/types/mcp/post-move.js +7 -0
  357. package/dist/src/types/mcp/post-move.js.map +1 -0
  358. package/dist/src/types/mcp.js +9 -0
  359. package/dist/src/types/mcp.js.map +1 -0
  360. package/dist/src/types/ports.js +12 -0
  361. package/dist/src/types/ports.js.map +1 -0
  362. package/dist/src/types/reconcile/image-decide.js +5 -0
  363. package/dist/src/types/reconcile/image-decide.js.map +1 -0
  364. package/dist/src/types/reconcile/ledger.js +7 -0
  365. package/dist/src/types/reconcile/ledger.js.map +1 -0
  366. package/dist/src/types/reconcile/pr-loop.js +8 -0
  367. package/dist/src/types/reconcile/pr-loop.js.map +1 -0
  368. package/dist/src/types/reconcile/vm-reap.js +8 -0
  369. package/dist/src/types/reconcile/vm-reap.js.map +1 -0
  370. package/dist/src/types/reconcile/workspace-decide.js +7 -0
  371. package/dist/src/types/reconcile/workspace-decide.js.map +1 -0
  372. package/dist/src/types/reconcile.js +9 -0
  373. package/dist/src/types/reconcile.js.map +1 -0
  374. package/dist/src/types/runlog.js +7 -0
  375. package/dist/src/types/runlog.js.map +1 -0
  376. package/dist/src/types/runner/actions-runner.js +12 -0
  377. package/dist/src/types/runner/actions-runner.js.map +1 -0
  378. package/dist/src/types/runner/gondolin-dispatch.js +5 -0
  379. package/dist/src/types/runner/gondolin-dispatch.js.map +1 -0
  380. package/dist/src/types/runner/injection.js +6 -0
  381. package/dist/src/types/runner/injection.js.map +1 -0
  382. package/dist/src/types/runner/runner-loop.js +5 -0
  383. package/dist/src/types/runner/runner-loop.js.map +1 -0
  384. package/dist/src/types/runner/turn.js +4 -0
  385. package/dist/src/types/runner/turn.js.map +1 -0
  386. package/dist/src/types/runner/vm-plan.js +4 -0
  387. package/dist/src/types/runner/vm-plan.js.map +1 -0
  388. package/dist/src/types/runtime.js +9 -0
  389. package/dist/src/types/runtime.js.map +1 -0
  390. package/dist/src/types/schedule/admission.js +7 -0
  391. package/dist/src/types/schedule/admission.js.map +1 -0
  392. package/dist/src/types/schedule/circuit-breaker.js +2 -0
  393. package/dist/src/types/schedule/circuit-breaker.js.map +1 -0
  394. package/dist/src/types/schedule/eligibility.js +9 -0
  395. package/dist/src/types/schedule/eligibility.js.map +1 -0
  396. package/dist/src/types/schedule/orchestrator-loop.js +10 -0
  397. package/dist/src/types/schedule/orchestrator-loop.js.map +1 -0
  398. package/dist/src/types/schedule/sleep-cycle.js +4 -0
  399. package/dist/src/types/schedule/sleep-cycle.js.map +1 -0
  400. package/dist/src/types/schedule/slots.js +8 -0
  401. package/dist/src/types/schedule/slots.js.map +1 -0
  402. package/dist/src/types/schedule/tick.js +9 -0
  403. package/dist/src/types/schedule/tick.js.map +1 -0
  404. package/dist/src/types/server/mcp-runtime.js +8 -0
  405. package/dist/src/types/server/mcp-runtime.js.map +1 -0
  406. package/dist/src/types/workflow/parse.js +4 -0
  407. package/dist/src/types/workflow/parse.js.map +1 -0
  408. package/dist/tests/core/account-id.test.js +35 -0
  409. package/dist/tests/core/account-id.test.js.map +1 -0
  410. package/dist/tests/core/actions-parse.test.js +176 -0
  411. package/dist/tests/core/actions-parse.test.js.map +1 -0
  412. package/dist/tests/core/adapter-config.test.js +133 -0
  413. package/dist/tests/core/adapter-config.test.js.map +1 -0
  414. package/dist/tests/core/admission.test.js +215 -0
  415. package/dist/tests/core/admission.test.js.map +1 -0
  416. package/dist/tests/core/args.test.js +132 -0
  417. package/dist/tests/core/args.test.js.map +1 -0
  418. package/dist/tests/core/availability.test.js +62 -0
  419. package/dist/tests/core/availability.test.js.map +1 -0
  420. package/dist/tests/core/checks.test.js +395 -0
  421. package/dist/tests/core/checks.test.js.map +1 -0
  422. package/dist/tests/core/circuit-breaker.test.js +172 -0
  423. package/dist/tests/core/circuit-breaker.test.js.map +1 -0
  424. package/dist/tests/core/coerce.test.js +87 -0
  425. package/dist/tests/core/coerce.test.js.map +1 -0
  426. package/dist/tests/core/context.test.js +228 -0
  427. package/dist/tests/core/context.test.js.map +1 -0
  428. package/dist/tests/core/decisions.test.js +310 -0
  429. package/dist/tests/core/decisions.test.js.map +1 -0
  430. package/dist/tests/core/derive.test.js +205 -0
  431. package/dist/tests/core/derive.test.js.map +1 -0
  432. package/dist/tests/core/dispatch-config.test.js +164 -0
  433. package/dist/tests/core/dispatch-config.test.js.map +1 -0
  434. package/dist/tests/core/dispatch.test.js +302 -0
  435. package/dist/tests/core/dispatch.test.js.map +1 -0
  436. package/dist/tests/core/eligibility.test.js +163 -0
  437. package/dist/tests/core/eligibility.test.js.map +1 -0
  438. package/dist/tests/core/extract.test.js +139 -0
  439. package/dist/tests/core/extract.test.js.map +1 -0
  440. package/dist/tests/core/fake-creds.test.js +134 -0
  441. package/dist/tests/core/fake-creds.test.js.map +1 -0
  442. package/dist/tests/core/file.test.js +197 -0
  443. package/dist/tests/core/file.test.js.map +1 -0
  444. package/dist/tests/core/git-result.test.js +113 -0
  445. package/dist/tests/core/git-result.test.js.map +1 -0
  446. package/dist/tests/core/identity.test.js +180 -0
  447. package/dist/tests/core/identity.test.js.map +1 -0
  448. package/dist/tests/core/image-decide.test.js +59 -0
  449. package/dist/tests/core/image-decide.test.js.map +1 -0
  450. package/dist/tests/core/injection.test.js +163 -0
  451. package/dist/tests/core/injection.test.js.map +1 -0
  452. package/dist/tests/core/ledger.test.js +218 -0
  453. package/dist/tests/core/ledger.test.js.map +1 -0
  454. package/dist/tests/core/managed-image.test.js +68 -0
  455. package/dist/tests/core/managed-image.test.js.map +1 -0
  456. package/dist/tests/core/mise.test.js +138 -0
  457. package/dist/tests/core/mise.test.js.map +1 -0
  458. package/dist/tests/core/parse.test.js +174 -0
  459. package/dist/tests/core/parse.test.js.map +1 -0
  460. package/dist/tests/core/path.test.js +50 -0
  461. package/dist/tests/core/path.test.js.map +1 -0
  462. package/dist/tests/core/plan.test.js +218 -0
  463. package/dist/tests/core/plan.test.js.map +1 -0
  464. package/dist/tests/core/post-move.test.js +162 -0
  465. package/dist/tests/core/post-move.test.js.map +1 -0
  466. package/dist/tests/core/pr-classify.test.js +117 -0
  467. package/dist/tests/core/pr-classify.test.js.map +1 -0
  468. package/dist/tests/core/pr-decide.test.js +298 -0
  469. package/dist/tests/core/pr-decide.test.js.map +1 -0
  470. package/dist/tests/core/pr-loop.test.js +301 -0
  471. package/dist/tests/core/pr-loop.test.js.map +1 -0
  472. package/dist/tests/core/pr-notes.test.js +165 -0
  473. package/dist/tests/core/pr-notes.test.js.map +1 -0
  474. package/dist/tests/core/predicates.test.js +154 -0
  475. package/dist/tests/core/predicates.test.js.map +1 -0
  476. package/dist/tests/core/prompt.test.js +189 -0
  477. package/dist/tests/core/prompt.test.js.map +1 -0
  478. package/dist/tests/core/protocol.test.js +195 -0
  479. package/dist/tests/core/protocol.test.js.map +1 -0
  480. package/dist/tests/core/reconcile-issue.test.js +116 -0
  481. package/dist/tests/core/reconcile-issue.test.js.map +1 -0
  482. package/dist/tests/core/render.test.js +549 -0
  483. package/dist/tests/core/render.test.js.map +1 -0
  484. package/dist/tests/core/retry.test.js +186 -0
  485. package/dist/tests/core/retry.test.js.map +1 -0
  486. package/dist/tests/core/routes.test.js +247 -0
  487. package/dist/tests/core/routes.test.js.map +1 -0
  488. package/dist/tests/core/run-fold.test.js +299 -0
  489. package/dist/tests/core/run-fold.test.js.map +1 -0
  490. package/dist/tests/core/shape.test.js +185 -0
  491. package/dist/tests/core/shape.test.js.map +1 -0
  492. package/dist/tests/core/sleep-cycle.test.js +150 -0
  493. package/dist/tests/core/sleep-cycle.test.js.map +1 -0
  494. package/dist/tests/core/slots.test.js +201 -0
  495. package/dist/tests/core/slots.test.js.map +1 -0
  496. package/dist/tests/core/state-resolve.test.js +80 -0
  497. package/dist/tests/core/state-resolve.test.js.map +1 -0
  498. package/dist/tests/core/summary.test.js +200 -0
  499. package/dist/tests/core/summary.test.js.map +1 -0
  500. package/dist/tests/core/template.test.js +116 -0
  501. package/dist/tests/core/template.test.js.map +1 -0
  502. package/dist/tests/core/tick.test.js +558 -0
  503. package/dist/tests/core/tick.test.js.map +1 -0
  504. package/dist/tests/core/token-fold.test.js +176 -0
  505. package/dist/tests/core/token-fold.test.js.map +1 -0
  506. package/dist/tests/core/turn.test.js +388 -0
  507. package/dist/tests/core/turn.test.js.map +1 -0
  508. package/dist/tests/core/url.test.js +118 -0
  509. package/dist/tests/core/url.test.js.map +1 -0
  510. package/dist/tests/core/validate.test.js +247 -0
  511. package/dist/tests/core/validate.test.js.map +1 -0
  512. package/dist/tests/core/views.test.js +252 -0
  513. package/dist/tests/core/views.test.js.map +1 -0
  514. package/dist/tests/core/vm-decide.test.js +110 -0
  515. package/dist/tests/core/vm-decide.test.js.map +1 -0
  516. package/dist/tests/core/vm-guards.test.js +153 -0
  517. package/dist/tests/core/vm-guards.test.js.map +1 -0
  518. package/dist/tests/core/vm-plan.test.js +332 -0
  519. package/dist/tests/core/vm-plan.test.js.map +1 -0
  520. package/dist/tests/core/vm-reap.test.js +196 -0
  521. package/dist/tests/core/vm-reap.test.js.map +1 -0
  522. package/dist/tests/core/workflow-parse.test.js +493 -0
  523. package/dist/tests/core/workflow-parse.test.js.map +1 -0
  524. package/dist/tests/core/workspace-decide.test.js +236 -0
  525. package/dist/tests/core/workspace-decide.test.js.map +1 -0
  526. package/dist/tests/helpers/fixtures.js +167 -0
  527. package/dist/tests/helpers/fixtures.js.map +1 -0
  528. package/dist/tests/shell/acp-substrate.test.js +101 -0
  529. package/dist/tests/shell/acp-substrate.test.js.map +1 -0
  530. package/dist/tests/shell/actions-runner-push.test.js +203 -0
  531. package/dist/tests/shell/actions-runner-push.test.js.map +1 -0
  532. package/dist/tests/shell/credential-hooks.test.js +36 -0
  533. package/dist/tests/shell/credential-hooks.test.js.map +1 -0
  534. package/dist/tests/shell/credential-registry.test.js +165 -0
  535. package/dist/tests/shell/credential-registry.test.js.map +1 -0
  536. package/dist/tests/shell/credential-substrate.test.js +179 -0
  537. package/dist/tests/shell/credential-substrate.test.js.map +1 -0
  538. package/dist/tests/shell/dockerfile-mise-pin.test.js +51 -0
  539. package/dist/tests/shell/dockerfile-mise-pin.test.js.map +1 -0
  540. package/dist/tests/shell/doctor.test.js +101 -0
  541. package/dist/tests/shell/doctor.test.js.map +1 -0
  542. package/dist/tests/shell/effect-vm-create.test.js +52 -0
  543. package/dist/tests/shell/effect-vm-create.test.js.map +1 -0
  544. package/dist/tests/shell/gh-port.test.js +63 -0
  545. package/dist/tests/shell/gh-port.test.js.map +1 -0
  546. package/dist/tests/shell/gondolin-dispatch-guard.test.js +144 -0
  547. package/dist/tests/shell/gondolin-dispatch-guard.test.js.map +1 -0
  548. package/dist/tests/shell/gondolin-dispatch-shquote.test.js +168 -0
  549. package/dist/tests/shell/gondolin-dispatch-shquote.test.js.map +1 -0
  550. package/dist/tests/shell/gondolin-image-converter.test.js +208 -0
  551. package/dist/tests/shell/gondolin-image-converter.test.js.map +1 -0
  552. package/dist/tests/shell/gondolin-image-fetch.test.js +93 -0
  553. package/dist/tests/shell/gondolin-image-fetch.test.js.map +1 -0
  554. package/dist/tests/shell/http-handler.test.js +608 -0
  555. package/dist/tests/shell/http-handler.test.js.map +1 -0
  556. package/dist/tests/shell/http-server.test.js +53 -0
  557. package/dist/tests/shell/http-server.test.js.map +1 -0
  558. package/dist/tests/shell/mcp-runtime.test.js +366 -0
  559. package/dist/tests/shell/mcp-runtime.test.js.map +1 -0
  560. package/dist/tests/shell/mise-config-asset.test.js +87 -0
  561. package/dist/tests/shell/mise-config-asset.test.js.map +1 -0
  562. package/dist/tests/shell/orchestrator-loop.test.js +583 -0
  563. package/dist/tests/shell/orchestrator-loop.test.js.map +1 -0
  564. package/dist/tests/shell/reconciler-passes.test.js +314 -0
  565. package/dist/tests/shell/reconciler-passes.test.js.map +1 -0
  566. package/dist/tests/shell/runner-loop-turn.test.js +97 -0
  567. package/dist/tests/shell/runner-loop-turn.test.js.map +1 -0
  568. package/dist/tests/shell/runner-slice.test.js +536 -0
  569. package/dist/tests/shell/runner-slice.test.js.map +1 -0
  570. package/dist/tests/shell/scaffold.test.js +65 -0
  571. package/dist/tests/shell/scaffold.test.js.map +1 -0
  572. package/dist/tests/shell/tick-config.test.js +83 -0
  573. package/dist/tests/shell/tick-config.test.js.map +1 -0
  574. package/dist/tests/shell/tracker-parse-dates.test.js +44 -0
  575. package/dist/tests/shell/tracker-parse-dates.test.js.map +1 -0
  576. package/dist/tests/shell/tracker-write-issue.test.js +154 -0
  577. package/dist/tests/shell/tracker-write-issue.test.js.map +1 -0
  578. package/dist/tests/shell/workflow-prompt-split.test.js +208 -0
  579. package/dist/tests/shell/workflow-prompt-split.test.js.map +1 -0
  580. package/dist/tests/shell/workspace-live-config.test.js +140 -0
  581. package/dist/tests/shell/workspace-live-config.test.js.map +1 -0
  582. package/package.json +21 -9
  583. package/patches/@earendil-works+gondolin+0.12.0.patch +173 -0
  584. package/prompts/Reflect.md +91 -0
  585. package/prompts/Review.md +97 -0
  586. package/prompts/Todo.md +96 -0
  587. package/prompts/_footer.md +41 -0
  588. package/prompts/_preamble.md +42 -0
  589. package/prompts-minimal/Todo.md +26 -0
  590. package/scripts/postinstall.mjs +63 -0
  591. package/scripts/vm-agent.mjs +312 -90
  592. package/WORKFLOW.md +0 -744
  593. package/dist/acp-bridge.js +0 -324
  594. package/dist/acp-bridge.js.map +0 -1
  595. package/dist/actions/cache.js +0 -191
  596. package/dist/actions/cache.js.map +0 -1
  597. package/dist/actions/effects.js +0 -41
  598. package/dist/actions/effects.js.map +0 -1
  599. package/dist/actions/executor.js +0 -570
  600. package/dist/actions/executor.js.map +0 -1
  601. package/dist/actions/index.js +0 -13
  602. package/dist/actions/index.js.map +0 -1
  603. package/dist/actions/parsing.js.map +0 -1
  604. package/dist/actions/predicate-env.js +0 -27
  605. package/dist/actions/predicate-env.js.map +0 -1
  606. package/dist/actions/predicates.js +0 -49
  607. package/dist/actions/predicates.js.map +0 -1
  608. package/dist/actions/templating.js +0 -66
  609. package/dist/actions/templating.js.map +0 -1
  610. package/dist/actions/types.js +0 -15
  611. package/dist/actions/types.js.map +0 -1
  612. package/dist/agent/acp.js +0 -473
  613. package/dist/agent/acp.js.map +0 -1
  614. package/dist/agent/adapter-names.js +0 -159
  615. package/dist/agent/adapter-names.js.map +0 -1
  616. package/dist/agent/adapters.js +0 -511
  617. package/dist/agent/adapters.js.map +0 -1
  618. package/dist/agent/credential-extractors.js +0 -342
  619. package/dist/agent/credential-extractors.js.map +0 -1
  620. package/dist/agent/credential-secrets.js +0 -628
  621. package/dist/agent/credential-secrets.js.map +0 -1
  622. package/dist/agent/credential-ticker.js +0 -57
  623. package/dist/agent/credential-ticker.js.map +0 -1
  624. package/dist/agent/gondolin-creds-staging.js +0 -356
  625. package/dist/agent/gondolin-creds-staging.js.map +0 -1
  626. package/dist/agent/gondolin-dispatch.js +0 -375
  627. package/dist/agent/gondolin-dispatch.js.map +0 -1
  628. package/dist/agent/gondolin.js +0 -124
  629. package/dist/agent/gondolin.js.map +0 -1
  630. package/dist/agent/runner-decisions.js +0 -134
  631. package/dist/agent/runner-decisions.js.map +0 -1
  632. package/dist/agent/runner.js +0 -1456
  633. package/dist/agent/runner.js.map +0 -1
  634. package/dist/agent/tool-call-summary.js +0 -102
  635. package/dist/agent/tool-call-summary.js.map +0 -1
  636. package/dist/agent/vm-acp-mapping.js +0 -73
  637. package/dist/agent/vm-acp-mapping.js.map +0 -1
  638. package/dist/agent/vm-guards.js +0 -262
  639. package/dist/agent/vm-guards.js.map +0 -1
  640. package/dist/agent/vm-port.js +0 -22
  641. package/dist/agent/vm-port.js.map +0 -1
  642. package/dist/agent/vm-process-registry.js +0 -79
  643. package/dist/agent/vm-process-registry.js.map +0 -1
  644. package/dist/bin/cli-args.js +0 -105
  645. package/dist/bin/cli-args.js.map +0 -1
  646. package/dist/bin/symphony.js +0 -794
  647. package/dist/bin/symphony.js.map +0 -1
  648. package/dist/errors.js +0 -15
  649. package/dist/errors.js.map +0 -1
  650. package/dist/http-disk.js +0 -135
  651. package/dist/http-disk.js.map +0 -1
  652. package/dist/http-handlers.js.map +0 -1
  653. package/dist/http.js.map +0 -1
  654. package/dist/issues.js +0 -178
  655. package/dist/issues.js.map +0 -1
  656. package/dist/logging.js +0 -203
  657. package/dist/logging.js.map +0 -1
  658. package/dist/mcp.js +0 -706
  659. package/dist/mcp.js.map +0 -1
  660. package/dist/memory.js +0 -85
  661. package/dist/memory.js.map +0 -1
  662. package/dist/orchestrator-decisions.js +0 -331
  663. package/dist/orchestrator-decisions.js.map +0 -1
  664. package/dist/orchestrator.js +0 -1569
  665. package/dist/orchestrator.js.map +0 -1
  666. package/dist/prompt.js +0 -65
  667. package/dist/prompt.js.map +0 -1
  668. package/dist/reconciler/cache.js +0 -65
  669. package/dist/reconciler/cache.js.map +0 -1
  670. package/dist/reconciler/index.js +0 -448
  671. package/dist/reconciler/index.js.map +0 -1
  672. package/dist/reconciler/ledger.js +0 -131
  673. package/dist/reconciler/ledger.js.map +0 -1
  674. package/dist/reconciler/pr-adapters.js +0 -174
  675. package/dist/reconciler/pr-adapters.js.map +0 -1
  676. package/dist/reconciler/pr-decide.js.map +0 -1
  677. package/dist/reconciler/pr.js +0 -422
  678. package/dist/reconciler/pr.js.map +0 -1
  679. package/dist/reconciler/types.js +0 -12
  680. package/dist/reconciler/types.js.map +0 -1
  681. package/dist/reconciler/vm.js +0 -243
  682. package/dist/reconciler/vm.js.map +0 -1
  683. package/dist/reconciler/workspace-defaults.js +0 -83
  684. package/dist/reconciler/workspace-defaults.js.map +0 -1
  685. package/dist/reconciler/workspace.js +0 -272
  686. package/dist/reconciler/workspace.js.map +0 -1
  687. package/dist/runlog.js +0 -403
  688. package/dist/runlog.js.map +0 -1
  689. package/dist/scaffold.js +0 -165
  690. package/dist/scaffold.js.map +0 -1
  691. package/dist/trackers/local.js +0 -445
  692. package/dist/trackers/local.js.map +0 -1
  693. package/dist/trackers/types.js +0 -10
  694. package/dist/trackers/types.js.map +0 -1
  695. package/dist/types.js +0 -3
  696. package/dist/types.js.map +0 -1
  697. package/dist/util/clock.js +0 -12
  698. package/dist/util/clock.js.map +0 -1
  699. package/dist/util/crypto.js +0 -25
  700. package/dist/util/crypto.js.map +0 -1
  701. package/dist/util/frontmatter.js +0 -70
  702. package/dist/util/frontmatter.js.map +0 -1
  703. package/dist/util/fs-issues.js +0 -22
  704. package/dist/util/fs-issues.js.map +0 -1
  705. package/dist/util/process.js +0 -152
  706. package/dist/util/process.js.map +0 -1
  707. package/dist/util/workspace-key.js +0 -10
  708. package/dist/util/workspace-key.js.map +0 -1
  709. package/dist/workflow-loader.js +0 -147
  710. package/dist/workflow-loader.js.map +0 -1
  711. package/dist/workflow.js +0 -822
  712. package/dist/workflow.js.map +0 -1
  713. package/dist/workspace-types.js +0 -8
  714. package/dist/workspace-types.js.map +0 -1
  715. package/dist/workspace.js +0 -443
  716. package/dist/workspace.js.map +0 -1
@@ -0,0 +1,128 @@
1
+ // FCIS rewrite — default IO providers for the host-only credential adapter (kind:
2
+ // adapter). Holds the real side effects the {@link CredentialPort} threads in:
3
+ // default host credential paths, JSON file reads, the flock(1) cross-process
4
+ // refresh lock, and the claude/codex refresher spawns. Re-exported from
5
+ // interp/credential.ts so callers stay untouched.
6
+ //
7
+ // NodeNext ESM, .js extensions on relative imports. Imports src/types ONLY (plus
8
+ // real node builtins) per the shell rule.
9
+ import path from 'node:path';
10
+ import os from 'node:os';
11
+ import { Buffer } from 'node:buffer';
12
+ import { readFile, mkdir } from 'node:fs/promises';
13
+ import { spawn } from 'node:child_process';
14
+ // ─── default host paths ─────────────────────────────────────────────────────────
15
+ export const defaultClaudeCredentialsPath = () => path.join(os.homedir(), '.claude', '.credentials.json');
16
+ export const defaultCodexCredentialsPath = () => path.join(os.homedir(), '.codex', 'auth.json');
17
+ export const defaultClaudeIdentityPath = () => path.join(os.homedir(), '.claude.json');
18
+ export const defaultLockPath = () => path.join(os.homedir(), '.symphony', 'oauth', 'refresh.lock');
19
+ /** Read+parse a JSON file; returns null on any IO/parse failure (warns once). */
20
+ export async function readJsonFile(p, log) {
21
+ let raw;
22
+ try {
23
+ raw = await readFile(p, 'utf8');
24
+ }
25
+ catch (err) {
26
+ log.emit('warn', 'credential: cannot read credentials', { path: p, error: err.message });
27
+ return null;
28
+ }
29
+ try {
30
+ return JSON.parse(raw);
31
+ }
32
+ catch (err) {
33
+ log.emit('warn', 'credential: credentials JSON parse failed', { path: p, error: err.message });
34
+ return null;
35
+ }
36
+ }
37
+ // ─── flock(1) cross-process refresh lock ────────────────────────────────────────
38
+ /**
39
+ * Default cross-process lock: spawn `flock(1)` holding LOCK_EX on `lockPath`. The
40
+ * child prints `READY` once the kernel grants the lock then blocks on stdin via
41
+ * `exec cat`; release closes stdin → cat EOFs → flock exits → the kernel releases
42
+ * the lock on FD close. `-o` closes the lock FD in the exec'd child so only the
43
+ * flock parent holds it. Ported verbatim from credential-extractors.ts.
44
+ */
45
+ export function defaultFlockAcquire(lockPath) {
46
+ return async (timeoutMs) => {
47
+ await mkdir(path.dirname(lockPath), { recursive: true });
48
+ const child = spawn('flock', ['-x', '-o', lockPath, 'sh', '-c', 'echo READY; exec cat'], {
49
+ stdio: ['pipe', 'pipe', 'pipe'],
50
+ });
51
+ try {
52
+ await waitForFlockReady(child, timeoutMs);
53
+ }
54
+ catch (err) {
55
+ try {
56
+ child.kill('SIGKILL');
57
+ }
58
+ catch { /* ignore */ }
59
+ throw err;
60
+ }
61
+ return makeFlockRelease(child);
62
+ };
63
+ }
64
+ function waitForFlockReady(child, timeoutMs) {
65
+ return new Promise((resolve, reject) => {
66
+ let settled = false;
67
+ let stdoutBuf = '';
68
+ let stderrBuf = '';
69
+ const timer = setTimeout(() => {
70
+ if (settled)
71
+ return;
72
+ settled = true;
73
+ reject(new Error('credential: refresh lock acquire timeout'));
74
+ }, timeoutMs);
75
+ const settle = (err) => {
76
+ if (settled)
77
+ return;
78
+ settled = true;
79
+ clearTimeout(timer);
80
+ if (err)
81
+ reject(err);
82
+ else
83
+ resolve();
84
+ };
85
+ child.stdout?.on('data', (c) => { stdoutBuf += c.toString('utf8'); if (stdoutBuf.includes('READY'))
86
+ settle(null); });
87
+ child.stderr?.on('data', (c) => { stderrBuf += c.toString('utf8'); });
88
+ child.once('error', (err) => settle(err));
89
+ child.once('exit', (code, signal) => settle(new Error(`flock exited before ready (code=${code}, signal=${signal}, stderr=${stderrBuf.trim()})`)));
90
+ });
91
+ }
92
+ function makeFlockRelease(child) {
93
+ let released = false;
94
+ return async () => {
95
+ if (released)
96
+ return;
97
+ released = true;
98
+ try {
99
+ child.stdin?.end();
100
+ }
101
+ catch { /* ignore */ }
102
+ if (child.exitCode !== null || child.signalCode !== null)
103
+ return;
104
+ const sigterm = setTimeout(() => { try {
105
+ child.kill('SIGTERM');
106
+ }
107
+ catch { /* ignore */ } }, 2_000);
108
+ await new Promise((resolve) => child.once('exit', () => resolve()));
109
+ clearTimeout(sigterm);
110
+ };
111
+ }
112
+ // ─── default refreshers (claude -p / codex exec) ────────────────────────────────
113
+ /** Spawn `claude -p ok` — Anthropic's own client refreshes + rewrites ~/.claude/.credentials.json. */
114
+ export function defaultClaudeRefresher() {
115
+ return () => spawnExit('claude', ['-p', 'ok']);
116
+ }
117
+ /** Spawn `codex exec` — codex's own auth manager rotates ~/.codex/auth.json (issue 161). */
118
+ export function defaultCodexRefresher() {
119
+ return () => spawnExit('codex', ['exec', '--skip-git-repo-check', '-s', 'read-only', 'ok']);
120
+ }
121
+ function spawnExit(cmd, args) {
122
+ return new Promise((resolve, reject) => {
123
+ const p = spawn(cmd, args, { stdio: 'ignore' });
124
+ p.once('error', reject);
125
+ p.once('exit', (code) => (code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${code ?? '<null>'}`))));
126
+ });
127
+ }
128
+ //# sourceMappingURL=credential-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-defaults.js","sourceRoot":"","sources":["../../../../src/shell/interp/credential-defaults.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ // FCIS rewrite — Gondolin egress onRequest hooks + per-VM createHttpHooks builder
2
+ // for the host-only credential adapter (kind: adapter). Standing egress audit, the
3
+ // codex chatgpt-backend route swap, the hook chainer, and buildVmHttpHooks.
4
+ // Re-exported from interp/credential.ts.
5
+ //
6
+ // NodeNext ESM, .js extensions on relative imports. Imports src/types ONLY (plus
7
+ // the real Gondolin SDK) per the shell rule.
8
+ import { createHttpHooks, } from '@earendil-works/gondolin';
9
+ /**
10
+ * The codex METERED platform host the chatgpt-backend route redirects FROM. The route
11
+ * swap applies ONLY to this host (→ `route.host`) and to requests already aimed at the
12
+ * backend host (`route.host`, so the path rewrite + `chatgpt-account-id` header still
13
+ * attach); EVERY other egress host passes through untouched. Without this gate the hook
14
+ * host-rewrites all non-backend egress to chatgpt.com — which broke a codex VM's
15
+ * `mise install` egress to registry.npmjs.org / nodejs.org (403 "Invalid URL").
16
+ * RCA: docs/research/codex-route-hook-host-rewrite-rca.md.
17
+ */
18
+ const CODEX_PLATFORM_HOST = 'api.openai.com';
19
+ /**
20
+ * Egress audit. Logs method+host+path (NEVER query/headers — a token can ride
21
+ * either) for EVERY guest egress request, then delegates to `inner`. Gondolin runs
22
+ * onRequest BEFORE its allow/deny check, so this is the only host-side window into
23
+ * in-VM egress. Pure pass-through. Ported from credential-secrets.ts.
24
+ */
25
+ export function makeEgressAuditHook(adapterId, allowedHosts, inner, log) {
26
+ return async (request) => {
27
+ try {
28
+ const u = new URL(request.url);
29
+ const host = u.hostname;
30
+ const allowed = allowedHosts.some((h) => host === h || host.endsWith(`.${h}`));
31
+ log.emit('info', 'egress request', { adapter: adapterId, method: request.method, host, path: u.pathname, allowed });
32
+ }
33
+ catch { /* logging must never break egress */ }
34
+ return inner ? inner(request) : undefined;
35
+ };
36
+ }
37
+ /**
38
+ * Apply a codex chatgpt-backend route (critic gap): swap host → chatgpt.com,
39
+ * rewrite `/v1/*` → `/backend-api/codex/*`, and attach `chatgpt-account-id` when
40
+ * present. The DECISION (codexUpstreamRoute over a TokenInfo) lives in core; this
41
+ * shell hook just rebuilds the outbound Request with the decided host/path/headers
42
+ * so a ChatGPT-OAuth subscription token reaches the backend that accepts it (the
43
+ * platform API 401s the missing `api.responses.write` scope). API-key creds get a
44
+ * null route → the request passes through unchanged.
45
+ */
46
+ export function makeCodexUpstreamRouteHook(resolveRoute) {
47
+ return (request) => {
48
+ const route = resolveRoute();
49
+ if (route === null)
50
+ return; // API-key credential: default platform route, untouched
51
+ let url;
52
+ try {
53
+ url = new URL(request.url);
54
+ }
55
+ catch {
56
+ return;
57
+ }
58
+ // Source-host gate: ONLY the metered platform host gets host-redirected to the
59
+ // backend; a request already at the backend host keeps its host but still gets the
60
+ // path rewrite + header; every OTHER host (npm, nodejs, the mise registry, …) passes
61
+ // through untouched (see CODEX_PLATFORM_HOST).
62
+ if (url.hostname !== CODEX_PLATFORM_HOST && url.hostname !== route.host)
63
+ return;
64
+ if (url.hostname === CODEX_PLATFORM_HOST) {
65
+ url.host = route.host;
66
+ url.hostname = route.host;
67
+ }
68
+ url.pathname = route.rewritePath(url.pathname);
69
+ const headers = new Headers(request.headers);
70
+ for (const [k, v] of Object.entries(route.extraHeaders))
71
+ headers.set(k, v);
72
+ // `duplex: 'half'` is required by undici/Node when a body stream is present; it
73
+ // is not in the lib `RequestInit` type, so the init object is cast at this seam.
74
+ const init = {
75
+ method: request.method,
76
+ headers,
77
+ body: request.body,
78
+ duplex: 'half',
79
+ redirect: request.redirect,
80
+ };
81
+ return new Request(url.toString(), init);
82
+ };
83
+ }
84
+ /**
85
+ * Egress request-side lazy refresh (issue 214). A pass-through `onRequest` hook that,
86
+ * for requests bound to one of the credential's substitution hosts, awaits `ensureFresh`
87
+ * (the registry's expiry-gated host refresh + fan-out) BEFORE returning — so when Gondolin
88
+ * substitutes the SecretManager value into the Authorization header, it injects the
89
+ * fresh token rather than the one that just expired in the refresh/request race.
90
+ *
91
+ * REQUEST-side ONLY: it never returns a Response and never buffers — so it cannot
92
+ * re-introduce the issue-135 streaming regression that an `onResponse` hook would (the
93
+ * NON-goal this issue pins). Other hosts pass straight through; refresh failures inside
94
+ * `ensureFresh` are swallowed (logging must never break egress).
95
+ */
96
+ export function makeLazyRefreshHook(substitutionHosts, ensureFresh, log) {
97
+ return async (request) => {
98
+ try {
99
+ const host = new URL(request.url).hostname;
100
+ const onSubstitutionHost = substitutionHosts.some((h) => host === h || host.endsWith(`.${h}`));
101
+ if (onSubstitutionHost)
102
+ await ensureFresh();
103
+ }
104
+ catch (err) {
105
+ log.emit('warn', 'credential: lazy refresh hook error (egress continues)', { error: err.message });
106
+ }
107
+ // Pass-through: Gondolin substitutes the (now-fresh) secret value after this returns.
108
+ };
109
+ }
110
+ /** Chain two optional onRequest hooks; a Response/Request short-circuit from the first wins. */
111
+ export function chainOnRequest(first, second) {
112
+ if (!first)
113
+ return second;
114
+ if (!second)
115
+ return first;
116
+ return async (request) => {
117
+ const r = await first(request);
118
+ if (r instanceof Response)
119
+ return r;
120
+ return second(r instanceof Request ? r : request);
121
+ };
122
+ }
123
+ /**
124
+ * Build the Gondolin `createHttpHooks` result for one adapter's VM. Wraps the
125
+ * adapter's optional guard in the egress-audit hook (standing observability).
126
+ *
127
+ * FIX (issue 135): NEVER register an `onResponse` hook — Gondolin only streams when
128
+ * `!onResponse` (`canStream = Boolean(body) && !httpHooks.onResponse`); with one set
129
+ * it FULLY BUFFERS every response, starving the in-VM streaming SDK → stream timeout
130
+ * → silent retry → ECONNRESET loop. The old onResponse was a pure billing-tell.
131
+ */
132
+ export function buildVmHttpHooks(input, log) {
133
+ const allowedHosts = [...input.allowedHosts];
134
+ const onRequest = makeEgressAuditHook(input.adapterId, allowedHosts, input.onRequest, log);
135
+ const options = {
136
+ allowedHosts,
137
+ secrets: {
138
+ [input.secretName]: {
139
+ hosts: [...input.substitutionHosts],
140
+ // Seeded via updateSecret (registry seeds BEFORE first exec); never forwarded empty on the happy path.
141
+ value: '',
142
+ placeholder: input.placeholder,
143
+ },
144
+ },
145
+ onRequest,
146
+ };
147
+ return createHttpHooks(options);
148
+ }
149
+ //# sourceMappingURL=credential-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-hooks.js","sourceRoot":"","sources":["../../../../src/shell/interp/credential-hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,226 @@
1
+ // FCIS rewrite — live per-VM SecretManager registry (the §4.3 fan-out + proactive
2
+ // expiresAt tick) + the periodic refresh ticker, for the host-only credential
3
+ // adapter (kind: adapter). Re-exported from interp/credential.ts so callers stay
4
+ // untouched.
5
+ //
6
+ // NodeNext ESM, .js extensions on relative imports. Imports src/types ONLY (plus
7
+ // the real Gondolin SDK) per the shell rule.
8
+ /**
9
+ * Owns the live per-VM SecretManagers + the cached latest value per adapter. The
10
+ * §4.3 fan-out contract: register seeds from the latest cached value before
11
+ * returning (so a VM created during a refresh never starts stale) and schedules a
12
+ * per-VM proactive `expiresAt` tick; pushToAll updates every live manager (dropping
13
+ * any torn down mid-push); refreshAdapter runs the host refresh, re-reads, and fans
14
+ * out. Ported faithfully from credential-secrets.CredentialSecretRegistry.
15
+ */
16
+ /** Default proactive-refresh margin when the substrate doesn't override it (5 min). */
17
+ const DEFAULT_REFRESH_MARGIN_MS = 5 * 60 * 1000;
18
+ export class CredentialSecretRegistry {
19
+ entries = new Map();
20
+ cachedValue = new Map();
21
+ cacheSeq = new Map();
22
+ /** Latest known absolute expiry per adapter (null = unknown); drives the lazy refresh. */
23
+ cachedExpiresAt = new Map();
24
+ /** In-flight host refresh per adapter, so concurrent egress requests share one round-trip. */
25
+ inFlight = new Map();
26
+ seq = 0;
27
+ readToken;
28
+ refresh;
29
+ log;
30
+ now;
31
+ setTimer;
32
+ clearTimer;
33
+ refreshMarginMs;
34
+ constructor(opts) {
35
+ this.readToken = opts.readToken;
36
+ this.refresh = opts.refresh;
37
+ this.log = opts.log;
38
+ this.now = opts.now ?? (() => Date.now());
39
+ this.setTimer =
40
+ opts.setTimer ??
41
+ ((cb, delayMs) => {
42
+ const t = setTimeout(cb, delayMs);
43
+ if (typeof t.unref === 'function')
44
+ t.unref();
45
+ return t;
46
+ });
47
+ this.clearTimer = opts.clearTimer ?? ((t) => clearTimeout(t));
48
+ this.refreshMarginMs = opts.refreshMarginMs ?? DEFAULT_REFRESH_MARGIN_MS;
49
+ }
50
+ async register(args) {
51
+ const key = `vm-${++this.seq}`;
52
+ const entry = { manager: args.manager, secretName: args.secretName, adapterId: args.adapterId, timer: null };
53
+ this.entries.set(key, entry);
54
+ const seqBefore = this.cacheSeq.get(args.adapterId) ?? 0;
55
+ const token = await this.safeReadToken(args.adapterId);
56
+ this.seedUnlessRotated(key, entry, args.adapterId, seqBefore, token);
57
+ if (token?.expiresAtMs != null)
58
+ this.scheduleProactive(key, entry, token.expiresAtMs);
59
+ return { key, deregister: () => this.deregister(key) };
60
+ }
61
+ deregister(key) {
62
+ const entry = this.entries.get(key);
63
+ if (!entry)
64
+ return;
65
+ if (entry.timer !== null) {
66
+ this.clearTimer(entry.timer);
67
+ entry.timer = null;
68
+ }
69
+ this.entries.delete(key);
70
+ }
71
+ size() {
72
+ return this.entries.size;
73
+ }
74
+ /** Push a fresh value to EVERY live manager for `adapterId` (cache first; drop the dead). */
75
+ pushToAll(adapterId, value) {
76
+ this.cachedValue.set(adapterId, value);
77
+ this.cacheSeq.set(adapterId, (this.cacheSeq.get(adapterId) ?? 0) + 1);
78
+ for (const [key, entry] of [...this.entries]) {
79
+ if (entry.adapterId !== adapterId)
80
+ continue;
81
+ this.applyToEntry(key, entry, value);
82
+ }
83
+ }
84
+ /**
85
+ * Run a host refresh for `adapterId`, re-read, fan out, and reschedule each VM's tick.
86
+ * Returns true when the host refresh SPAWN succeeded and a token was re-read; false on a
87
+ * GENUINE auth failure — the refresh threw (e.g. a revoked/expired refresh token that
88
+ * `claude -p ok` can't rotate, needing operator re-login) or no token could be re-read.
89
+ * The in-session 401 recovery (issue 214) keys its re-prompt-vs-end decision on this
90
+ * boolean — it ends the attempt only when the refresh itself failed. Either way the
91
+ * re-read value is still fanned out (a peer may have rotated the file under the shared
92
+ * flock). Concurrent callers share one host round-trip.
93
+ */
94
+ refreshAdapter(adapterId) {
95
+ const existing = this.inFlight.get(adapterId);
96
+ if (existing)
97
+ return existing;
98
+ const pending = this.runRefreshAndFanOut(adapterId).finally(() => {
99
+ if (this.inFlight.get(adapterId) === pending)
100
+ this.inFlight.delete(adapterId);
101
+ });
102
+ this.inFlight.set(adapterId, pending);
103
+ return pending;
104
+ }
105
+ async runRefreshAndFanOut(adapterId) {
106
+ let refreshOk = true;
107
+ try {
108
+ await this.refresh(adapterId);
109
+ }
110
+ catch (err) {
111
+ refreshOk = false;
112
+ this.log.emit('warn', 'credential: refresh failed', { adapter: adapterId, error: err.message });
113
+ // Fall through: re-read anyway — a peer may have rotated the file under the shared flock.
114
+ }
115
+ const token = await this.safeReadToken(adapterId);
116
+ if (token === null)
117
+ return false;
118
+ this.pushToAll(adapterId, token.accessToken);
119
+ this.cachedExpiresAt.set(adapterId, token.expiresAtMs ?? null);
120
+ if (token.expiresAtMs != null) {
121
+ for (const [key, entry] of [...this.entries]) {
122
+ if (entry.adapterId !== adapterId)
123
+ continue;
124
+ this.scheduleProactive(key, entry, token.expiresAtMs);
125
+ }
126
+ }
127
+ return refreshOk;
128
+ }
129
+ /**
130
+ * Egress request-side lazy refresh (issue 214): called from the per-VM `onRequest`
131
+ * hook BEFORE Gondolin substitutes the secret value. If the cached token's expiry is
132
+ * KNOWN and within the refresh margin, await a host refresh + fan-out so the request
133
+ * proceeds on the fresh token. Expiry-unknown adapters are left to the proactive tick /
134
+ * ticker (refreshing on every request would hammer the host). Never throws.
135
+ */
136
+ async ensureFreshForRequest(adapterId) {
137
+ const expiresAt = this.cachedExpiresAt.get(adapterId);
138
+ if (expiresAt == null)
139
+ return; // unknown expiry → proactive tick owns it
140
+ if (expiresAt - this.now() > this.refreshMarginMs)
141
+ return; // still comfortably fresh
142
+ await this.refreshAdapter(adapterId);
143
+ }
144
+ seedUnlessRotated(key, entry, adapterId, seqBefore, token) {
145
+ if ((this.cacheSeq.get(adapterId) ?? 0) !== seqBefore)
146
+ return;
147
+ const seedValue = token?.accessToken ?? this.cachedValue.get(adapterId) ?? '';
148
+ if (token?.accessToken) {
149
+ this.cachedValue.set(adapterId, token.accessToken);
150
+ this.cachedExpiresAt.set(adapterId, token.expiresAtMs ?? null);
151
+ }
152
+ this.applyToEntry(key, entry, seedValue);
153
+ }
154
+ applyToEntry(key, entry, value) {
155
+ try {
156
+ entry.manager.updateSecret(entry.secretName, { value });
157
+ }
158
+ catch (err) {
159
+ this.log.emit('warn', 'credential: dropping dead secret manager', { adapter: entry.adapterId, error: err.message });
160
+ this.deregister(key);
161
+ }
162
+ }
163
+ async safeReadToken(adapterId) {
164
+ try {
165
+ return await this.readToken(adapterId);
166
+ }
167
+ catch (err) {
168
+ this.log.emit('warn', 'credential: readToken failed', { adapter: adapterId, error: err.message });
169
+ return null;
170
+ }
171
+ }
172
+ scheduleProactive(key, entry, expiresAtMs) {
173
+ if (entry.timer !== null) {
174
+ this.clearTimer(entry.timer);
175
+ entry.timer = null;
176
+ }
177
+ const delay = Math.max(0, expiresAtMs - this.now() - this.refreshMarginMs);
178
+ entry.timer = this.setTimer(() => {
179
+ entry.timer = null;
180
+ void this.refreshAdapter(entry.adapterId);
181
+ }, delay);
182
+ }
183
+ }
184
+ /** Periodic host-side refresh so a long idle window doesn't strand the access token. */
185
+ export class CredentialTicker {
186
+ timer = null;
187
+ stopped = false;
188
+ intervalMs;
189
+ refreshAll;
190
+ log;
191
+ constructor(opts) {
192
+ this.intervalMs = opts.intervalMs;
193
+ this.refreshAll = opts.refreshAll;
194
+ this.log = opts.log;
195
+ }
196
+ start() {
197
+ if (this.timer || this.stopped)
198
+ return;
199
+ if (this.intervalMs <= 0) {
200
+ this.log.emit('info', 'credential ticker disabled (interval_ms <= 0)');
201
+ return;
202
+ }
203
+ this.timer = setInterval(() => void this.tick(), this.intervalMs);
204
+ if (typeof this.timer.unref === 'function')
205
+ this.timer.unref();
206
+ this.log.emit('info', 'credential ticker started', { interval_ms: this.intervalMs });
207
+ }
208
+ stop() {
209
+ this.stopped = true;
210
+ if (this.timer) {
211
+ clearInterval(this.timer);
212
+ this.timer = null;
213
+ }
214
+ }
215
+ async tick() {
216
+ if (this.stopped)
217
+ return;
218
+ try {
219
+ await this.refreshAll();
220
+ }
221
+ catch (err) {
222
+ this.log.emit('warn', 'credential ticker: refresh failed', { error: err.message });
223
+ }
224
+ }
225
+ }
226
+ //# sourceMappingURL=credential-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-registry.js","sourceRoot":"","sources":["../../../../src/shell/interp/credential-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ // FCIS rewrite — host-only credential adapter (kind: adapter).
2
+ //
3
+ // Interprets the CredentialEffect family by implementing the {@link CredentialPort}
4
+ // from src/types/ports. The host stays the SOLE owner of the durable refresh token;
5
+ // the guest only ever sees a token-shaped placeholder that Gondolin substitutes at
6
+ // egress (TLS-MITM).
7
+ //
8
+ // This is the IMPURE half of the original src/agent/credential-secrets.ts +
9
+ // credential-extractors.ts + credential-ticker.ts. The PURE half (token/JWT
10
+ // extraction, placeholder-JWT assembly, host-identity extraction, allowlist union,
11
+ // codexUpstreamRoute decision) lives in src/core/credential and is wired in by the
12
+ // composition root, which passes the pure deciders into this adapter as injected
13
+ // function deps — so this file imports from src/types ONLY (plus the real Gondolin
14
+ // SDK + node builtins + its credential-* shell siblings), per the shell rule.
15
+ //
16
+ // The cohesive IO providers / hooks / registry live in sibling files that
17
+ // consumers import DIRECTLY (no barrel re-export here):
18
+ // - credential-defaults.ts: default paths, readJsonFile, flock, refreshers
19
+ // - credential-hooks.ts: egress audit, codex route, builder
20
+ // - credential-registry.ts: the per-VM SecretManager registry + the refresh ticker
21
+ //
22
+ // NodeNext ESM, .js extensions on relative imports. Keep THIN — decisions live in core.
23
+ import { defaultClaudeCredentialsPath, defaultCodexCredentialsPath, defaultClaudeIdentityPath, defaultLockPath, defaultFlockAcquire, defaultClaudeRefresher, defaultCodexRefresher, readJsonFile, } from './credential-defaults.js';
24
+ function resolvePaths(opts) {
25
+ return {
26
+ claudeCredsPath: opts.claudeCredentialsPath ?? defaultClaudeCredentialsPath(),
27
+ codexCredsPath: opts.codexCredentialsPath ?? defaultCodexCredentialsPath(),
28
+ claudeIdentityPath: opts.claudeIdentityPath ?? defaultClaudeIdentityPath(),
29
+ codexIdentityPath: opts.codexIdentityPath ?? defaultCodexCredentialsPath(),
30
+ };
31
+ }
32
+ function resolveProviders(opts) {
33
+ return {
34
+ env: opts.env ?? process.env,
35
+ lockTimeoutMs: opts.lockAcquireTimeoutMs ?? 90_000,
36
+ acquireLock: opts.lockAcquire ?? defaultFlockAcquire(opts.lockPath ?? defaultLockPath()),
37
+ claudeRefresher: opts.claudeRefresher ?? defaultClaudeRefresher(),
38
+ codexRefresher: opts.codexRefresher ?? defaultCodexRefresher(),
39
+ };
40
+ }
41
+ function resolveConfig(opts) {
42
+ return { ...resolvePaths(opts), ...resolveProviders(opts) };
43
+ }
44
+ /**
45
+ * The host-only CredentialPort over real files + flock + refresher spawns. Probe
46
+ * does the file READ here, then hands the parsed JSON to the injected PURE
47
+ * extractor — keeping every decision in core.
48
+ */
49
+ export class GondolinCredentialAdapter {
50
+ acquireLock;
51
+ pure;
52
+ log;
53
+ cfg;
54
+ constructor(opts) {
55
+ this.pure = opts.pure;
56
+ this.log = opts.log;
57
+ this.cfg = resolveConfig(opts);
58
+ this.acquireLock = this.cfg.acquireLock;
59
+ }
60
+ async probe(adapter) {
61
+ switch (adapter) {
62
+ case 'claude':
63
+ return this.pure.extractClaudeToken(await readJsonFile(this.cfg.claudeCredsPath, this.log));
64
+ case 'codex':
65
+ return (this.pure.extractCodexToken(await readJsonFile(this.cfg.codexCredsPath, this.log)) ??
66
+ this.pure.codexEnvFallback(this.cfg.env));
67
+ }
68
+ }
69
+ async readClaudeIdentity() {
70
+ return this.pure.extractClaudeIdentity(await readJsonFile(this.cfg.claudeIdentityPath, this.log));
71
+ }
72
+ async readCodexIdentity() {
73
+ return this.pure.extractCodexMetadata(await readJsonFile(this.cfg.codexIdentityPath, this.log));
74
+ }
75
+ /** Refresh under the shared flock (fail-closed: never run the refresher unserialized). */
76
+ async refresh(adapter) {
77
+ await this.underLock(() => this.runRefresh(adapter));
78
+ }
79
+ async runRefresh(adapter) {
80
+ if (adapter === 'claude')
81
+ return this.cfg.claudeRefresher();
82
+ return this.cfg.codexRefresher();
83
+ }
84
+ async underLock(fn) {
85
+ let release = null;
86
+ try {
87
+ release = await this.acquireLock(this.cfg.lockTimeoutMs);
88
+ }
89
+ catch (err) {
90
+ // Fail closed: never run the refresher unserialized (would race a peer on the
91
+ // same creds file). The caller re-reads the cache and picks up the peer's rotation.
92
+ this.log.emit('warn', 'credential: lock acquire failed; skipping refresh', { error: err.message });
93
+ throw new Error('credential: refresh lock acquire timeout');
94
+ }
95
+ try {
96
+ await fn();
97
+ }
98
+ finally {
99
+ await release().catch((err) => this.log.emit('warn', 'credential: lock release error', { error: err.message }));
100
+ }
101
+ }
102
+ }
103
+ //# sourceMappingURL=credential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.js","sourceRoot":"","sources":["../../../../src/shell/interp/credential.ts"],"names":[],"mappings":"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"}