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,75 @@
1
+ // FCIS rewrite — canonical scalar coercers for YAML/JSON-decoded front-matter
2
+ // and config values. Pure + synchronous; imports nothing (src/types not even
3
+ // needed). This is the ONE home for the `asString`/`asInt`/`asStringList`/
4
+ // `asNumber`/`asTimestamp` family that had drifted across ~5 core modules.
5
+ //
6
+ // 100% PURE + SYNCHRONOUS. No IO, no node: imports, no clock/randomness.
7
+ //
8
+ // ─── Resolved drift (the reason this module exists) ──────────────────────────
9
+ // • asInt: the issue parser used `Number.isInteger` (rejects a fractional
10
+ // `2.5` → null) while the actions/workflow parsers used `Number.isFinite`
11
+ // + `Math.trunc` (accepts `2.5` → 2). The workflow-config path (20+ call
12
+ // sites: timeouts, counts) is the dominant consumer and relies on the
13
+ // truncating form, so `isFinite + Math.trunc` is canonical. Pinned by
14
+ // tests/core/coerce.test.ts.
15
+ // • asString: the http renderer carried a `&& v.length > 0` length-guard the
16
+ // three parse copies did not. The canonical (no length-guard) matches the
17
+ // issue-parsing contract; emptiness is the CALLER's concern (most sites
18
+ // already truthiness-check the result). Pinned by tests/core/coerce.test.ts.
19
+ /** A string value, or null. No length guard — an empty string passes through. */
20
+ export function asString(v) {
21
+ return typeof v === 'string' ? v : null;
22
+ }
23
+ /**
24
+ * An integer, or null. Accepts a finite number (truncated toward zero) or a
25
+ * decimal-digit string; everything else → null. `isFinite + Math.trunc` (NOT
26
+ * `Number.isInteger`) is canonical: a fractional `2.5` truncates to `2`.
27
+ */
28
+ export function asInt(v) {
29
+ if (typeof v === 'number' && Number.isFinite(v))
30
+ return Math.trunc(v);
31
+ if (typeof v === 'string' && /^-?\d+$/.test(v))
32
+ return parseInt(v, 10);
33
+ return null;
34
+ }
35
+ /**
36
+ * Like {@link asInt} but with a `fallback` for when the value is absent or
37
+ * un-coercible (the workflow-config form — every config knob has a default).
38
+ */
39
+ export function asIntOr(v, fallback) {
40
+ return asInt(v) ?? fallback;
41
+ }
42
+ /** The string elements of an array, or `[]`. Non-string elements are dropped. */
43
+ export function asStringList(v) {
44
+ if (Array.isArray(v))
45
+ return v.filter((x) => typeof x === 'string');
46
+ return [];
47
+ }
48
+ /** Like {@link asStringList} but returns `fallback` when `v` is not an array. */
49
+ export function asStringListOr(v, fallback) {
50
+ if (Array.isArray(v))
51
+ return v.filter((x) => typeof x === 'string');
52
+ return fallback;
53
+ }
54
+ /** A finite number, or null. (No truncation — fractional values pass through.) */
55
+ export function asNumber(v) {
56
+ if (typeof v === 'number' && Number.isFinite(v))
57
+ return v;
58
+ return null;
59
+ }
60
+ /**
61
+ * A timestamp as a string. A non-empty string passes through; everything else →
62
+ * null. The empty string is NOT a timestamp (folds the old `formatTimestamp`
63
+ * length-guard in, which the bare `asTimestamp` lacked).
64
+ *
65
+ * Core coercers operate over PLAIN DATA only, so this NEVER sees a `Date`: the
66
+ * `yaml` lib auto-decodes ISO timestamps to `Date`, but the shell front-matter
67
+ * decode (shell/interp/tracker-parse.ts:normalizeDates) renders any decoded `Date`
68
+ * back to its ISO string at the boundary before core consumes the map.
69
+ */
70
+ export function asTimestamp(v) {
71
+ if (typeof v === 'string')
72
+ return v.length > 0 ? v : null;
73
+ return null;
74
+ }
75
+ //# sourceMappingURL=coerce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coerce.js","sourceRoot":"","sources":["../../../src/core/coerce.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,EAAE;AACF,yEAAyE;AACzE,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,0EAA0E;AAC1E,0EAA0E;AAC1E,iCAAiC;AACjC,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,iFAAiF;AAEjF,iFAAiF;AACjF,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,CAAU;IAC9B,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,CAAU,EAAE,QAAgB;IAClD,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;AAC9B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,YAAY,CAAC,CAAU;IACrC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IACjF,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,cAAc,CAAC,CAAU,EAAE,QAAkB;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IACjF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,CAAU;IACpC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1D,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,20 @@
1
+ // FCIS rewrite — the ONE shared account-id guard (codex review HIGH).
2
+ //
3
+ // `validAccountId` + its `UUID_RE` were inlined BYTE-IDENTICAL across three
4
+ // credential modules (identity.ts / fake-creds.ts / shape.ts), each commenting
5
+ // "SHARED" / "codex review HIGH". This is the single canonical home; those three
6
+ // modules import and re-export it so every existing importer keeps its specifier.
7
+ //
8
+ // 100% PURE + SYNCHRONOUS. No IO, no node: imports, no clock/randomness.
9
+ /** Canonical RFC-4122-shaped UUID (any case). */
10
+ export const UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
11
+ /**
12
+ * Defense-in-depth guard for a credential `account_id`: returns the value iff it
13
+ * is a UUID, else null. A hostile/malformed `account_id` (a token, a JWT, a path
14
+ * fragment) must NOT flow into the placeholder/identity machinery — it is dropped
15
+ * to null rather than trusted.
16
+ */
17
+ export function validAccountId(v) {
18
+ return v !== null && UUID_RE.test(v) ? v : null;
19
+ }
20
+ //# sourceMappingURL=account-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-id.js","sourceRoot":"","sources":["../../../../src/core/credential/account-id.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,iFAAiF;AACjF,kFAAkF;AAClF,EAAE;AACF,yEAAyE;AAEzE,iDAAiD;AACjD,MAAM,CAAC,MAAM,OAAO,GAClB,+EAA+E,CAAC;AAElF;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,CAAgB;IAC7C,OAAO,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC"}
@@ -0,0 +1,136 @@
1
+ // FCIS rewrite — pure per-adapter staged-config generation.
2
+ //
3
+ // Ported faithfully from the reference `src/agent/adapters.ts`:
4
+ // • stageClaudeIdentity — the claude settings.json effortLevel file + the
5
+ // non-secret identity file content.
6
+ // • stageCodexPlaceholderAuth — the fake codex auth.json placeholder shape.
7
+ //
8
+ // In the reference these were `async` because they also did host IO (read
9
+ // `~/.claude.json`, write the file 0600 with symlink-race defenses, resolve the
10
+ // `.git/` vs `.symphony-runtime/` staging root). That IO is the SHELL's job in
11
+ // the FCIS split. What this module owns — and the "critic gap" the synthesis
12
+ // called out — is the PURE content/path decision: given the chosen model /
13
+ // effort / already-extracted host identity, return the `StagedFileSpec[]` that
14
+ // describe what file must land where in the guest, with what bytes. Zero IO, no
15
+ // node builtins, no clock/random — every input is plain data supplied by the
16
+ // caller (the shell reads `~/.claude.json` via `HostIdentityReaders` and passes
17
+ // the extracted `ClaudeIdentity` in; this module never touches the filesystem).
18
+ //
19
+ // A `StagedFileSpec` is `{ stagedName, content, guestPath }` (src/types/credentials):
20
+ // • stagedName — the name inside the workspace runtime staging dir; the shell
21
+ // composes the actual on-host path (`.git/symphony-runtime/...`
22
+ // or `.symphony-runtime/...`) — that resolution stays in the shell.
23
+ // • content — the exact UTF-8 bytes to write.
24
+ // • guestPath — the absolute path inside the VM the dispatcher materializes to.
25
+ //
26
+ // Faithful semantics preserved from the reference:
27
+ // • claude settings.json: `{ "effortLevel": <effort> }`, compact JSON, copied
28
+ // to /root/.claude/settings.json (matches the reference effortInjection).
29
+ // • claude identity: ONLY `{ oauthAccount: { accountUuid, organizationUuid } }`
30
+ // — no token strings, no device/session ids, no local config. Skipped
31
+ // (null) when no identity was extracted (reference returned null).
32
+ // • codex placeholder auth.json: `{ OPENAI_API_KEY: <placeholder>, auth_mode:
33
+ // 'apikey' }`, NO real credential, NO OAuth tokens block.
34
+ // ── claude settings.json (effortLevel) + non-secret identity ───────────────
35
+ /** Absolute guest path the claude settings.json (effortLevel) lands at. */
36
+ export const CLAUDE_SETTINGS_GUEST_PATH = '/root/.claude/settings.json';
37
+ /** Absolute guest path the non-secret claude identity file lands at. */
38
+ export const CLAUDE_IDENTITY_GUEST_PATH = '/root/.claude.json';
39
+ /**
40
+ * The claude `effortLevel` settings.json spec. Mirrors the reference
41
+ * `ADAPTERS.claude.effortInjection`: a compact `{ "effortLevel": <effort> }`
42
+ * copied to /root/.claude/settings.json before the adapter starts. Valid values
43
+ * (`low|medium|high|xhigh|max`) are gated per-model by claude-agent-acp; symphony
44
+ * lets the adapter reject invalid choices rather than mirroring the gate, so we
45
+ * emit whatever non-empty string the caller supplies.
46
+ */
47
+ export function claudeEffortSpec(effort) {
48
+ return {
49
+ stagedName: 'claude-settings.json',
50
+ content: JSON.stringify({ effortLevel: effort }),
51
+ guestPath: CLAUDE_SETTINGS_GUEST_PATH,
52
+ };
53
+ }
54
+ /**
55
+ * The non-secret claude identity staged-file spec (pure replacement for the
56
+ * reference `stageClaudeIdentity`, minus the host `~/.claude.json` read — that
57
+ * read + the `oauthAccount` extraction is the shell's `HostIdentityReaders` job;
58
+ * this module receives the already-extracted identity).
59
+ *
60
+ * Defensive shape (faithful): ONLY `{ oauthAccount: { accountUuid,
61
+ * organizationUuid } }` — NO token strings, NO device/session ids, NO local
62
+ * config. Returns `null` when no identity is available, exactly as the reference
63
+ * returned null when `~/.claude.json` was missing or had no `oauthAccount`
64
+ * (staging the identity is defense in depth, not a hard gate on dispatch).
65
+ */
66
+ export function claudeIdentitySpec(identity) {
67
+ if (!identity)
68
+ return null;
69
+ return {
70
+ stagedName: 'claude.json',
71
+ content: JSON.stringify({
72
+ oauthAccount: {
73
+ accountUuid: identity.accountUuid,
74
+ organizationUuid: identity.organizationUuid,
75
+ },
76
+ }),
77
+ guestPath: CLAUDE_IDENTITY_GUEST_PATH,
78
+ };
79
+ }
80
+ // ── codex placeholder auth.json ────────────────────────────────────────────
81
+ /** Absolute guest path the fake codex auth.json lands at. */
82
+ export const CODEX_AUTH_GUEST_PATH = '/root/.codex/auth.json';
83
+ /** Placeholder bearer staged into the fake codex auth.json (NOT a real token). */
84
+ export const CODEX_PLACEHOLDER_API_KEY = 'sk-symphony-placeholder';
85
+ /**
86
+ * The fake codex `~/.codex/auth.json` placeholder spec (pure replacement for the
87
+ * reference `stageCodexPlaceholderAuth`, minus the host write). It exists PURELY
88
+ * to satisfy codex-acp's session-init credential check; it contains NO real
89
+ * credential — `OPENAI_API_KEY` is a token-shaped placeholder and there is no
90
+ * OAuth `tokens` block — so codex falls through to the env `OPENAI_API_KEY`
91
+ * placeholder as its request bearer and Gondolin substitutes the real token at
92
+ * egress. `auth_mode: 'apikey'` forces the API-key path, never an OAuth
93
+ * handshake; `last_refresh` is omitted (no OAuth tokens to age).
94
+ */
95
+ export function codexPlaceholderAuthSpec() {
96
+ return {
97
+ stagedName: 'auth.json',
98
+ content: JSON.stringify({
99
+ OPENAI_API_KEY: CODEX_PLACEHOLDER_API_KEY,
100
+ auth_mode: 'apikey',
101
+ }),
102
+ guestPath: CODEX_AUTH_GUEST_PATH,
103
+ };
104
+ }
105
+ /**
106
+ * Aggregate every staged-file spec one adapter dispatch needs into a single
107
+ * `StagedFileSpec[]`, in a stable order (identity/config first, then the
108
+ * effort/model overlays). Pure: the shell materializes each spec into the
109
+ * workspace runtime tree + the guest. No spec is ever a secret — the only
110
+ * credential bytes are token-shaped placeholders.
111
+ *
112
+ * Per-adapter (faithful to the reference staging in `runner.stageAdapterExtras`):
113
+ * • claude — optional non-secret identity (when extracted) + optional
114
+ * effortLevel settings.json (when effort is set).
115
+ * • codex — the fake placeholder auth.json (always; the init check needs it).
116
+ */
117
+ export function buildStagedConfigs(input) {
118
+ const specs = [];
119
+ switch (input.adapter) {
120
+ case 'claude': {
121
+ const identity = claudeIdentitySpec(input.claudeIdentity);
122
+ if (identity)
123
+ specs.push(identity);
124
+ if (input.effort && input.effort.length > 0) {
125
+ specs.push(claudeEffortSpec(input.effort));
126
+ }
127
+ break;
128
+ }
129
+ case 'codex': {
130
+ specs.push(codexPlaceholderAuthSpec());
131
+ break;
132
+ }
133
+ }
134
+ return specs;
135
+ }
136
+ //# sourceMappingURL=adapter-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-config.js","sourceRoot":"","sources":["../../../../src/core/credential/adapter-config.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,gEAAgE;AAChE,mFAAmF;AACnF,qEAAqE;AACrE,+EAA+E;AAC/E,EAAE;AACF,0EAA0E;AAC1E,gFAAgF;AAChF,+EAA+E;AAC/E,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAC/E,gFAAgF;AAChF,6EAA6E;AAC7E,gFAAgF;AAChF,gFAAgF;AAChF,EAAE;AACF,sFAAsF;AACtF,gFAAgF;AAChF,iFAAiF;AACjF,qFAAqF;AACrF,mDAAmD;AACnD,mFAAmF;AACnF,EAAE;AACF,mDAAmD;AACnD,gFAAgF;AAChF,8EAA8E;AAC9E,kFAAkF;AAClF,0EAA0E;AAC1E,uEAAuE;AACvE,gFAAgF;AAChF,8DAA8D;AAS9D,8EAA8E;AAE9E,2EAA2E;AAC3E,MAAM,CAAC,MAAM,0BAA0B,GAAG,6BAA6B,CAAC;AAExE,wEAAwE;AACxE,MAAM,CAAC,MAAM,0BAA0B,GAAG,oBAAoB,CAAC;AAE/D;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO;QACL,UAAU,EAAE,sBAAsB;QAClC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;QAChD,SAAS,EAAE,0BAA0B;KACtC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAA+B;IAChE,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO;QACL,UAAU,EAAE,aAAa;QACzB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;YACtB,YAAY,EAAE;gBACZ,WAAW,EAAE,QAAQ,CAAC,WAAW;gBACjC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;aAC5C;SACF,CAAC;QACF,SAAS,EAAE,0BAA0B;KACtC,CAAC;AACJ,CAAC;AAED,8EAA8E;AAE9E,6DAA6D;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,wBAAwB,CAAC;AAE9D,kFAAkF;AAClF,MAAM,CAAC,MAAM,yBAAyB,GAAG,yBAAyB,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,UAAU,EAAE,WAAW;QACvB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;YACtB,cAAc,EAAE,yBAAyB;YACzC,SAAS,EAAE,QAAQ;SACpB,CAAC;QACF,SAAS,EAAE,qBAAqB;KACjC,CAAC;AACJ,CAAC;AAeD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAwB;IACzD,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,QAAQ,KAAK,CAAC,OAAO,EAAE,CAAC;QACtB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YAC1D,IAAI,QAAQ;gBAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5C,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7C,CAAC;YACD,MAAM;QACR,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,KAAK,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC;YACvC,MAAM;QACR,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,98 @@
1
+ // FCIS rewrite — PURE credential availability classification.
2
+ //
3
+ // Ports the pure half of the original `src/agent/adapter-names.ts`:
4
+ // codexCredentialAvailable, codexMissingCredentialMessage,
5
+ // host{Claude,Codex}CredentialPath, isKnownAdapter / KNOWN_ADAPTER_IDS.
6
+ //
7
+ // Critic gap this closes: availability classification is shared by BOTH the
8
+ // doctor check and the startup probe, so it must live in the core (one source of
9
+ // truth) rather than being re-implemented per call site.
10
+ //
11
+ // 100% synchronous, zero IO, imports ONLY from src/types.
12
+ //
13
+ // How the original's impure dependencies are made pure here:
14
+ // * `os.homedir()` (used to build the host credential paths) is replaced
15
+ // by an INJECTED `homeDir: string`. The shell derives it once (os.homedir())
16
+ // and threads it in; the core reads no real environment. This mirrors the
17
+ // homeDir(env) convention already used in src/core/workflow/parse.ts.
18
+ // * `node:path.join` is replaced by a tiny pure POSIX join (joinPath). The
19
+ // orchestrator targets Linux/macOS hosts, so POSIX semantics are faithful.
20
+ // * `NodeJS.ProcessEnv` becomes `WorkflowEnv` (Record<string, string|undefined>),
21
+ // the type already used across the core for injected environments.
22
+ //
23
+ // The actual file reads stay in the shell: the shell reads the credential file
24
+ // (passing its text, or `null` when absent/unreadable) and the env in here, so
25
+ // these functions mirror the host's egress read path EXACTLY — the startup probe
26
+ // accepts a dispatch iff a real dispatch would resolve a credential.
27
+ import { joinPosixParts } from '../path.js';
28
+ import { nonEmptyString } from './strings.js';
29
+ // ─── known-adapter registry ──────────────────────────────────────────────────
30
+ //
31
+ // The seam between the config layer and the IO adapter layer: both sides agree
32
+ // on which adapter ids exist. The full adapter *profile* lives elsewhere
33
+ // (AdapterProfile / the shell's adapter registry); this is only the id set.
34
+ export const KNOWN_ADAPTER_IDS = ['claude', 'codex'];
35
+ export function isKnownAdapter(id) {
36
+ return KNOWN_ADAPTER_IDS.includes(id);
37
+ }
38
+ // Host credential paths use the canonical variadic `joinPosixParts` from
39
+ // core/path.ts (the old local `joinPath` was byte-identical to it).
40
+ const joinPath = joinPosixParts;
41
+ // ─── host credential paths ───────────────────────────────────────────────────
42
+ //
43
+ // Absolute paths to the host's credential files. The host reads these to
44
+ // substitute the live access token into the outbound request at Gondolin egress
45
+ // (the guest only ever holds a token-shaped placeholder); the startup probe
46
+ // reads them once so a completely missing credential fails fast with a clear
47
+ // message instead of an opaque mid-dispatch error.
48
+ /** Absolute path to the host's claude OAuth credential file (`~/.claude/.credentials.json`). */
49
+ export function hostClaudeCredentialPath(homeDir) {
50
+ return joinPath(homeDir, '.claude', '.credentials.json');
51
+ }
52
+ /** Absolute path to the host's codex credential file (`~/.codex/auth.json`). */
53
+ export function hostCodexCredentialPath(homeDir) {
54
+ return joinPath(homeDir, '.codex', 'auth.json');
55
+ }
56
+ // ─── codex credential resolution ─────────────────────────────────────────────
57
+ /**
58
+ * Pure: does codex have a resolvable credential from either valid source? The
59
+ * host reads two — the `~/.codex/auth.json` token (a ChatGPT-OAuth
60
+ * `tokens.access_token` or a top-level `OPENAI_API_KEY`) or an `OPENAI_API_KEY`
61
+ * env var. The shell reads the file (passing `null` when absent/unreadable) and
62
+ * its env in; this mirrors the host's `extractCodexToken` + env fallback so the
63
+ * startup probe accepts exactly when a dispatch would.
64
+ */
65
+ export function codexCredentialAvailable(authFileText, env) {
66
+ if (nonEmptyString(env['OPENAI_API_KEY']))
67
+ return true;
68
+ if (authFileText === null)
69
+ return false;
70
+ let parsed;
71
+ try {
72
+ parsed = JSON.parse(authFileText);
73
+ }
74
+ catch {
75
+ return false;
76
+ }
77
+ return codexAuthFileHasToken(parsed);
78
+ }
79
+ /** Human-readable explanation of which codex credential sources were checked. */
80
+ export function codexMissingCredentialMessage(homeDir) {
81
+ return `adapter "codex" requires a host credential, but none is available: neither a token in ${hostCodexCredentialPath(homeDir)} (ChatGPT-OAuth tokens.access_token or OPENAI_API_KEY) nor an OPENAI_API_KEY environment variable is present`;
82
+ }
83
+ function codexAuthFileHasToken(parsed) {
84
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
85
+ return false;
86
+ const root = parsed;
87
+ const tokens = root['tokens'];
88
+ if (tokens && typeof tokens === 'object' && !Array.isArray(tokens)) {
89
+ if (nonEmptyString(tokens['access_token']))
90
+ return true;
91
+ }
92
+ return nonEmptyString(root['OPENAI_API_KEY']) !== null;
93
+ }
94
+ // nonEmptyString (string-valued) is the shared credential helper from
95
+ // ./strings.js — imported at the top. The boolean-returning local copy that
96
+ // used to live here was the §3a divergence; call sites that need a boolean use
97
+ // `nonEmptyString(...) !== null`, the rest rely on the truthy string/null.
98
+ //# sourceMappingURL=availability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.js","sourceRoot":"","sources":["../../../../src/core/credential/availability.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,oEAAoE;AACpE,6DAA6D;AAC7D,0EAA0E;AAC1E,EAAE;AACF,4EAA4E;AAC5E,iFAAiF;AACjF,yDAAyD;AACzD,EAAE;AACF,0DAA0D;AAC1D,EAAE;AACF,6DAA6D;AAC7D,2EAA2E;AAC3E,iFAAiF;AACjF,8EAA8E;AAC9E,0EAA0E;AAC1E,6EAA6E;AAC7E,+EAA+E;AAC/E,oFAAoF;AACpF,uEAAuE;AACvE,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,iFAAiF;AACjF,qEAAqE;AAIrE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,yEAAyE;AACzE,4EAA4E;AAE5E,MAAM,CAAC,MAAM,iBAAiB,GAA4B,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAE9E,MAAM,UAAU,cAAc,CAAC,EAAU;IACvC,OAAQ,iBAAuC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,yEAAyE;AACzE,oEAAoE;AACpE,MAAM,QAAQ,GAAG,cAAc,CAAC;AAEhC,gFAAgF;AAChF,EAAE;AACF,yEAAyE;AACzE,gFAAgF;AAChF,4EAA4E;AAC5E,6EAA6E;AAC7E,mDAAmD;AAEnD,gGAAgG;AAChG,MAAM,UAAU,wBAAwB,CAAC,OAAe;IACtD,OAAO,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;AAC3D,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,OAAO,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;AAClD,CAAC;AAED,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CACtC,YAA2B,EAC3B,GAAgB;IAEhB,IAAI,cAAc,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,qBAAqB,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,6BAA6B,CAAC,OAAe;IAC3D,OAAO,yFAAyF,uBAAuB,CACrH,OAAO,CACR,8GAA8G,CAAC;AAClH,CAAC;AAED,SAAS,qBAAqB,CAAC,MAAe;IAC5C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACjF,MAAM,IAAI,GAAG,MAAiC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,IAAI,cAAc,CAAE,MAAkC,CAAC,cAAc,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACvF,CAAC;IACD,OAAO,cAAc,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,KAAK,IAAI,CAAC;AACzD,CAAC;AAED,sEAAsE;AACtE,4EAA4E;AAC5E,+EAA+E;AAC/E,2EAA2E"}
@@ -0,0 +1,228 @@
1
+ // FCIS rewrite — PURE token/JWT extraction over ALREADY-PARSED JSON.
2
+ //
3
+ // Functional core: every export here is a pure, synchronous (data) -> data
4
+ // function. No IO, no clock, no randomness, no node: imports, no process/env
5
+ // read. Imports ONLY from src/types.
6
+ //
7
+ // SECURITY-LOAD-BEARING. This is the "impureCoreRisk fix" half of the original
8
+ // src/agent/credential-extractors.ts + src/agent/adapter-names.ts: the original
9
+ // extractors mixed pure parsing with host IO (file reads, https requests, flock,
10
+ // refresher spawns, `process.env`). Here we keep ONLY the pure decisions:
11
+ // - extractClaudeToken — pull accessToken+expiry out of parsed claude creds
12
+ // - extractCodexToken — prefer ChatGPT-OAuth tokens.access_token (NEVER
13
+ // reads refresh_token), else OPENAI_API_KEY; sets
14
+ // chatgptOAuth + JWT-derived expiry
15
+ // - decodeJwtExpMs — read a JWT `exp` claim (ms), signature unverified
16
+ // - coerceExpiresAtMs — number | numeric-string | date-string -> ms|null
17
+ // - codexEnvFallback — OPENAI_API_KEY env fallback as a codex credential
18
+ //
19
+ // The host invariant ("only the host refreshes; the guest never sees a refresh
20
+ // token") is preserved at the extraction boundary: extractCodexToken NEVER reads
21
+ // `tokens.refresh_token`. All host file/env reads that previously lived here are
22
+ // now `credential.probe` Effects performed by the shell; the SHELL parses the
23
+ // JSON and the host environment, then hands the already-parsed values to these
24
+ // functions.
25
+ import { nonEmptyString } from './strings.js';
26
+ // ── claude ────────────────────────────────────────────────────────────────────
27
+ /**
28
+ * Pull `accessToken` and `expiresAt` out of the already-parsed claude
29
+ * credentials JSON. The shape `claude` writes is
30
+ * `{ claudeAiOauth: { accessToken, expiresAt, ... } }`, but we tolerate flat
31
+ * top-level fields too for forward compatibility. Returns null when no non-empty
32
+ * access token is present.
33
+ */
34
+ export function extractClaudeToken(parsed) {
35
+ if (!parsed || typeof parsed !== 'object')
36
+ return null;
37
+ const root = parsed;
38
+ const oauth = root['claudeAiOauth'];
39
+ const candidate = oauth && typeof oauth === 'object' && !Array.isArray(oauth)
40
+ ? oauth
41
+ : root;
42
+ const accessToken = candidate['accessToken'];
43
+ if (typeof accessToken !== 'string' || accessToken.length === 0)
44
+ return null;
45
+ const expiresAtMs = coerceExpiresAtMs(candidate['expiresAt']);
46
+ return { accessToken, expiresAtMs };
47
+ }
48
+ // ── codex ─────────────────────────────────────────────────────────────────────
49
+ /**
50
+ * Pull the access token out of the already-parsed codex `~/.codex/auth.json`.
51
+ * Two flavours live there: a ChatGPT-OAuth `tokens.access_token` and an API-key
52
+ * `OPENAI_API_KEY`. We prefer the OAuth access token, then fall back to the API
53
+ * key. The `tokens.refresh_token` is NEVER read — it stays host-side so an in-VM
54
+ * agent cannot rotate (and thereby invalidate) the host's credential.
55
+ *
56
+ * For the ChatGPT-OAuth token, `expiresAtMs` is decoded from the access-token
57
+ * JWT `exp` claim so the proactive pre-expiry refresh tick can fire; a non-JWT /
58
+ * malformed token decodes to null (safe degradation to on-demand re-read). The
59
+ * API-key fallback keeps `expiresAtMs: null` (API keys do not expire/refresh).
60
+ */
61
+ export function extractCodexToken(parsed) {
62
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
63
+ return null;
64
+ const root = parsed;
65
+ const tokens = codexTokensObject(root);
66
+ if (tokens !== null) {
67
+ const oauth = nonEmptyString(tokens['access_token']);
68
+ if (oauth !== null) {
69
+ // ChatGPT-OAuth subscription credential → ChatGPT-backend route. The
70
+ // account id (when present) becomes the `chatgpt-account-id` header, but
71
+ // routing keys on `chatgptOAuth`: this token is ALWAYS rejected by the
72
+ // platform API, with or without the account id.
73
+ return {
74
+ accessToken: oauth,
75
+ expiresAtMs: decodeJwtExpMs(oauth),
76
+ chatgptOAuth: true,
77
+ chatgptAccountId: nonEmptyString(tokens['account_id']),
78
+ };
79
+ }
80
+ }
81
+ // API-key credential: forward to the platform API (api.openai.com/v1) unchanged.
82
+ const apiKey = nonEmptyString(root['OPENAI_API_KEY']);
83
+ return apiKey === null ? null : { accessToken: apiKey, expiresAtMs: null };
84
+ }
85
+ /**
86
+ * Pure: read `OPENAI_API_KEY` from a host-environment snapshot as a codex
87
+ * credential fallback. The shell passes the env in (a `credential.probe`-adjacent
88
+ * env read); core never touches `process.env`.
89
+ */
90
+ export function codexEnvFallback(env) {
91
+ const key = nonEmptyString(env['OPENAI_API_KEY']);
92
+ return key === null ? null : { accessToken: key, expiresAtMs: null };
93
+ }
94
+ // ── JWT / expiry coercion ───────────────────────────────────────────────────────
95
+ /**
96
+ * Decode a JWT's `exp` claim (seconds since epoch) and return it as ms since
97
+ * epoch, or null when `token` is not a well-formed three-segment JWT or carries
98
+ * no finite numeric `exp`. The signature is NEVER verified — codex's own client
99
+ * owns verification; we read only the public `exp` claim to schedule a refresh.
100
+ */
101
+ export function decodeJwtExpMs(token) {
102
+ const segments = token.split('.');
103
+ if (segments.length !== 3)
104
+ return null;
105
+ const payloadSeg = segments[1];
106
+ if (payloadSeg === undefined || payloadSeg.length === 0)
107
+ return null;
108
+ const json = decodeBase64UrlUtf8(payloadSeg);
109
+ if (json === null)
110
+ return null;
111
+ let payload;
112
+ try {
113
+ payload = JSON.parse(json);
114
+ }
115
+ catch {
116
+ return null;
117
+ }
118
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload))
119
+ return null;
120
+ const exp = payload['exp'];
121
+ if (typeof exp !== 'number' || !Number.isFinite(exp))
122
+ return null;
123
+ return exp * 1000;
124
+ }
125
+ /**
126
+ * Coerce an `expiresAt`-shaped value into ms since epoch: a finite number is
127
+ * taken verbatim; a numeric string is parsed as a number; otherwise a string is
128
+ * tried as a parseable date. Anything else → null.
129
+ */
130
+ export function coerceExpiresAtMs(value) {
131
+ if (typeof value === 'number' && Number.isFinite(value))
132
+ return value;
133
+ if (typeof value === 'string') {
134
+ const n = Number(value);
135
+ if (Number.isFinite(n))
136
+ return n;
137
+ const parsedDate = Date.parse(value);
138
+ if (Number.isFinite(parsedDate))
139
+ return parsedDate;
140
+ }
141
+ return null;
142
+ }
143
+ // ── internal helpers ─────────────────────────────────────────────────────────
144
+ /** The ChatGPT-OAuth `tokens` bundle from auth.json, or null when absent/malformed. */
145
+ function codexTokensObject(root) {
146
+ const tokens = root['tokens'];
147
+ if (!tokens || typeof tokens !== 'object' || Array.isArray(tokens))
148
+ return null;
149
+ return tokens;
150
+ }
151
+ // Standard base64 alphabet → 6-bit value (and -1 for non-alphabet chars).
152
+ const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
153
+ /**
154
+ * Decode a base64url segment to a UTF-8 string, or null on malformed input.
155
+ *
156
+ * The original used `Buffer.from(seg, 'base64url').toString('utf8')`; core may
157
+ * not import `node:buffer` (and must not depend on an ambient `atob` global that
158
+ * the project's `lib` config does not surface), so this is a self-contained pure
159
+ * decoder: base64url→bytes, then a manual UTF-8 → string decode. Any malformed
160
+ * input (bad char, bad length, invalid UTF-8) → null, matching the original's
161
+ * try/catch → null degradation (JSON.parse then fails on null and yields null).
162
+ */
163
+ function decodeBase64UrlUtf8(seg) {
164
+ const bytes = base64UrlToBytes(seg);
165
+ if (bytes === null)
166
+ return null;
167
+ return utf8BytesToString(bytes);
168
+ }
169
+ /** base64url string → byte values (0–255), or null on a malformed segment. */
170
+ function base64UrlToBytes(seg) {
171
+ // base64url → base64: '-'→'+', '_'→'/'. (Padding is recomputed below.)
172
+ const b64 = seg.replace(/-/g, '+').replace(/_/g, '/').replace(/=+$/, '');
173
+ if (b64.length % 4 === 1)
174
+ return null; // an invalid base64 length
175
+ const out = [];
176
+ let acc = 0;
177
+ let bits = 0;
178
+ for (const ch of b64) {
179
+ const v = BASE64_ALPHABET.indexOf(ch);
180
+ if (v === -1)
181
+ return null; // non-alphabet character
182
+ acc = (acc << 6) | v;
183
+ bits += 6;
184
+ if (bits >= 8) {
185
+ bits -= 8;
186
+ out.push((acc >> bits) & 0xff);
187
+ }
188
+ }
189
+ return out;
190
+ }
191
+ /** Decode a UTF-8 byte sequence into a string, or null on invalid UTF-8. */
192
+ function utf8BytesToString(bytes) {
193
+ let result = '';
194
+ let i = 0;
195
+ while (i < bytes.length) {
196
+ const b0 = bytes[i++];
197
+ if (b0 < 0x80) {
198
+ result += String.fromCharCode(b0);
199
+ continue;
200
+ }
201
+ let needed;
202
+ let cp;
203
+ if ((b0 & 0xe0) === 0xc0) {
204
+ needed = 1;
205
+ cp = b0 & 0x1f;
206
+ }
207
+ else if ((b0 & 0xf0) === 0xe0) {
208
+ needed = 2;
209
+ cp = b0 & 0x0f;
210
+ }
211
+ else if ((b0 & 0xf8) === 0xf0) {
212
+ needed = 3;
213
+ cp = b0 & 0x07;
214
+ }
215
+ else {
216
+ return null; // invalid leading byte
217
+ }
218
+ for (let k = 0; k < needed; k++) {
219
+ const cb = bytes[i++];
220
+ if (cb === undefined || (cb & 0xc0) !== 0x80)
221
+ return null; // bad continuation
222
+ cp = (cp << 6) | (cb & 0x3f);
223
+ }
224
+ result += String.fromCodePoint(cp);
225
+ }
226
+ return result;
227
+ }
228
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../../../src/core/credential/extract.ts"],"names":[],"mappings":"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"}