@noodleseed/one 0.23.0 → 0.24.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 (245) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +2 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/author-loop.d.ts +1 -0
  5. package/dist/commands/author-loop.d.ts.map +1 -1
  6. package/dist/commands/author-loop.js +4 -0
  7. package/dist/commands/author-loop.js.map +1 -1
  8. package/dist/commands/catalog-data-core.d.ts.map +1 -1
  9. package/dist/commands/catalog-data-core.js +17 -3
  10. package/dist/commands/catalog-data-core.js.map +1 -1
  11. package/dist/commands/catalog-data-resources.js +2 -2
  12. package/dist/commands/catalog-data-resources.js.map +1 -1
  13. package/dist/commands/catalog-render.d.ts.map +1 -1
  14. package/dist/commands/catalog-render.js +6 -0
  15. package/dist/commands/catalog-render.js.map +1 -1
  16. package/dist/commands/deploy-ops.d.ts.map +1 -1
  17. package/dist/commands/deploy-ops.js +2 -2
  18. package/dist/commands/deploy-ops.js.map +1 -1
  19. package/dist/commands/deploy-status-ops.d.ts +1 -1
  20. package/dist/commands/deploy-status-ops.d.ts.map +1 -1
  21. package/dist/commands/deploy-status-ops.js +8 -4
  22. package/dist/commands/deploy-status-ops.js.map +1 -1
  23. package/dist/commands/devtools.d.ts +11 -0
  24. package/dist/commands/devtools.d.ts.map +1 -0
  25. package/dist/commands/devtools.js +123 -0
  26. package/dist/commands/devtools.js.map +1 -0
  27. package/dist/commands/mcp-apps.d.ts +0 -1
  28. package/dist/commands/mcp-apps.d.ts.map +1 -1
  29. package/dist/commands/mcp-apps.js +71 -122
  30. package/dist/commands/mcp-apps.js.map +1 -1
  31. package/dist/commands/shared.d.ts +6 -0
  32. package/dist/commands/shared.d.ts.map +1 -1
  33. package/dist/commands/shared.js +19 -0
  34. package/dist/commands/shared.js.map +1 -1
  35. package/dist/deploy.d.ts +1 -1
  36. package/dist/deploy.d.ts.map +1 -1
  37. package/dist/deploy.js +5 -1
  38. package/dist/deploy.js.map +1 -1
  39. package/dist/dev.d.ts.map +1 -1
  40. package/dist/dev.js +13 -1
  41. package/dist/dev.js.map +1 -1
  42. package/dist/fire.js +1 -1
  43. package/dist/fire.js.map +1 -1
  44. package/dist/flavor.d.ts +1 -1
  45. package/dist/flavor.d.ts.map +1 -1
  46. package/dist/flavor.js +12 -2
  47. package/dist/flavor.js.map +1 -1
  48. package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +4 -4
  49. package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js.map +1 -1
  50. package/node_modules/@noodle-borg/agent-kit/dist/skill-content.d.ts.map +1 -1
  51. package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js +66 -4
  52. package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js.map +1 -1
  53. package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.d.ts.map +1 -1
  54. package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.js +8 -3
  55. package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.js.map +1 -1
  56. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  57. package/node_modules/@noodle-borg/authoring/dist/connectors.d.ts +18 -1
  58. package/node_modules/@noodle-borg/authoring/dist/connectors.d.ts.map +1 -1
  59. package/node_modules/@noodle-borg/authoring/dist/connectors.js +17 -4
  60. package/node_modules/@noodle-borg/authoring/dist/connectors.js.map +1 -1
  61. package/node_modules/@noodle-borg/authoring/dist/recording.js +24 -5
  62. package/node_modules/@noodle-borg/authoring/dist/recording.js.map +1 -1
  63. package/node_modules/@noodle-borg/authoring/dist/server.js +57 -3
  64. package/node_modules/@noodle-borg/authoring/dist/server.js.map +1 -1
  65. package/node_modules/@noodle-borg/connector-defs/dist/auth-variables.js +1 -1
  66. package/node_modules/@noodle-borg/connector-defs/dist/auth-variables.js.map +1 -1
  67. package/node_modules/@noodle-borg/connector-defs/dist/call-graph.d.ts +14 -0
  68. package/node_modules/@noodle-borg/connector-defs/dist/call-graph.d.ts.map +1 -0
  69. package/node_modules/@noodle-borg/connector-defs/dist/call-graph.js +66 -0
  70. package/node_modules/@noodle-borg/connector-defs/dist/call-graph.js.map +1 -0
  71. package/node_modules/@noodle-borg/connector-defs/dist/compile-auth.d.ts +21 -0
  72. package/node_modules/@noodle-borg/connector-defs/dist/compile-auth.d.ts.map +1 -0
  73. package/node_modules/@noodle-borg/connector-defs/dist/compile-auth.js +102 -0
  74. package/node_modules/@noodle-borg/connector-defs/dist/compile-auth.js.map +1 -0
  75. package/node_modules/@noodle-borg/connector-defs/dist/compile.d.ts +19 -4
  76. package/node_modules/@noodle-borg/connector-defs/dist/compile.d.ts.map +1 -1
  77. package/node_modules/@noodle-borg/connector-defs/dist/compile.js +67 -99
  78. package/node_modules/@noodle-borg/connector-defs/dist/compile.js.map +1 -1
  79. package/node_modules/@noodle-borg/connector-defs/dist/index.d.ts +1 -1
  80. package/node_modules/@noodle-borg/connector-defs/dist/index.d.ts.map +1 -1
  81. package/node_modules/@noodle-borg/connector-defs/dist/index.js.map +1 -1
  82. package/node_modules/@noodle-borg/connector-defs/dist/schema.d.ts +168 -10
  83. package/node_modules/@noodle-borg/connector-defs/dist/schema.d.ts.map +1 -1
  84. package/node_modules/@noodle-borg/connector-defs/dist/schema.js +72 -5
  85. package/node_modules/@noodle-borg/connector-defs/dist/schema.js.map +1 -1
  86. package/node_modules/@noodle-borg/connector-http/dist/http-connector.d.ts +6 -0
  87. package/node_modules/@noodle-borg/connector-http/dist/http-connector.d.ts.map +1 -1
  88. package/node_modules/@noodle-borg/connector-http/dist/http-connector.js +2 -0
  89. package/node_modules/@noodle-borg/connector-http/dist/http-connector.js.map +1 -1
  90. package/node_modules/@noodle-borg/runtime/dist/execute.d.ts.map +1 -1
  91. package/node_modules/@noodle-borg/runtime/dist/execute.js +87 -62
  92. package/node_modules/@noodle-borg/runtime/dist/execute.js.map +1 -1
  93. package/node_modules/@noodle-borg/runtime/dist/result.d.ts +1 -1
  94. package/node_modules/@noodle-borg/runtime/dist/result.d.ts.map +1 -1
  95. package/node_modules/@noodle-borg/service/dist/credential-broker.d.ts.map +1 -1
  96. package/node_modules/@noodle-borg/service/dist/credential-broker.js +113 -11
  97. package/node_modules/@noodle-borg/service/dist/credential-broker.js.map +1 -1
  98. package/node_modules/@noodle-borg/service/dist/github/app-client.d.ts +28 -5
  99. package/node_modules/@noodle-borg/service/dist/github/app-client.d.ts.map +1 -1
  100. package/node_modules/@noodle-borg/service/dist/github/app-client.js +116 -7
  101. package/node_modules/@noodle-borg/service/dist/github/app-client.js.map +1 -1
  102. package/node_modules/@noodle-borg/service/dist/github/builder-auth.d.ts +12 -0
  103. package/node_modules/@noodle-borg/service/dist/github/builder-auth.d.ts.map +1 -0
  104. package/node_modules/@noodle-borg/service/dist/github/builder-auth.js +15 -0
  105. package/node_modules/@noodle-borg/service/dist/github/builder-auth.js.map +1 -0
  106. package/node_modules/@noodle-borg/service/dist/github/builder-main.d.ts +3 -0
  107. package/node_modules/@noodle-borg/service/dist/github/builder-main.d.ts.map +1 -0
  108. package/node_modules/@noodle-borg/service/dist/github/builder-main.js +9 -0
  109. package/node_modules/@noodle-borg/service/dist/github/builder-main.js.map +1 -0
  110. package/node_modules/@noodle-borg/service/dist/github/builder-runner.d.ts +21 -0
  111. package/node_modules/@noodle-borg/service/dist/github/builder-runner.d.ts.map +1 -0
  112. package/node_modules/@noodle-borg/service/dist/github/builder-runner.js +192 -0
  113. package/node_modules/@noodle-borg/service/dist/github/builder-runner.js.map +1 -0
  114. package/node_modules/@noodle-borg/service/dist/github/cloud-run-job-executor.d.ts +45 -0
  115. package/node_modules/@noodle-borg/service/dist/github/cloud-run-job-executor.d.ts.map +1 -0
  116. package/node_modules/@noodle-borg/service/dist/github/cloud-run-job-executor.js +60 -0
  117. package/node_modules/@noodle-borg/service/dist/github/cloud-run-job-executor.js.map +1 -0
  118. package/node_modules/@noodle-borg/service/dist/github/deploy-pipeline.d.ts +64 -0
  119. package/node_modules/@noodle-borg/service/dist/github/deploy-pipeline.d.ts.map +1 -0
  120. package/node_modules/@noodle-borg/service/dist/github/deploy-pipeline.js +121 -0
  121. package/node_modules/@noodle-borg/service/dist/github/deploy-pipeline.js.map +1 -0
  122. package/node_modules/@noodle-borg/service/dist/github/deploy-run-executor.d.ts +33 -0
  123. package/node_modules/@noodle-borg/service/dist/github/deploy-run-executor.d.ts.map +1 -0
  124. package/node_modules/@noodle-borg/service/dist/github/deploy-run-executor.js +14 -0
  125. package/node_modules/@noodle-borg/service/dist/github/deploy-run-executor.js.map +1 -0
  126. package/node_modules/@noodle-borg/service/dist/github/deploy-run-reconciler.d.ts +36 -0
  127. package/node_modules/@noodle-borg/service/dist/github/deploy-run-reconciler.d.ts.map +1 -0
  128. package/node_modules/@noodle-borg/service/dist/github/deploy-run-reconciler.js +107 -0
  129. package/node_modules/@noodle-borg/service/dist/github/deploy-run-reconciler.js.map +1 -0
  130. package/node_modules/@noodle-borg/service/dist/github/fast-lane-classifier.d.ts +38 -0
  131. package/node_modules/@noodle-borg/service/dist/github/fast-lane-classifier.d.ts.map +1 -0
  132. package/node_modules/@noodle-borg/service/dist/github/fast-lane-classifier.js +60 -0
  133. package/node_modules/@noodle-borg/service/dist/github/fast-lane-classifier.js.map +1 -0
  134. package/node_modules/@noodle-borg/service/dist/github/local-compile.d.ts +24 -0
  135. package/node_modules/@noodle-borg/service/dist/github/local-compile.d.ts.map +1 -0
  136. package/node_modules/@noodle-borg/service/dist/github/local-compile.js +98 -0
  137. package/node_modules/@noodle-borg/service/dist/github/local-compile.js.map +1 -0
  138. package/node_modules/@noodle-borg/service/dist/github/local-process-executor.d.ts +39 -0
  139. package/node_modules/@noodle-borg/service/dist/github/local-process-executor.d.ts.map +1 -0
  140. package/node_modules/@noodle-borg/service/dist/github/local-process-executor.js +67 -0
  141. package/node_modules/@noodle-borg/service/dist/github/local-process-executor.js.map +1 -0
  142. package/node_modules/@noodle-borg/service/dist/github/run-access-mode.d.ts +18 -0
  143. package/node_modules/@noodle-borg/service/dist/github/run-access-mode.d.ts.map +1 -0
  144. package/node_modules/@noodle-borg/service/dist/github/run-access-mode.js +32 -0
  145. package/node_modules/@noodle-borg/service/dist/github/run-access-mode.js.map +1 -0
  146. package/node_modules/@noodle-borg/service/dist/github/run-token.d.ts +41 -0
  147. package/node_modules/@noodle-borg/service/dist/github/run-token.d.ts.map +1 -0
  148. package/node_modules/@noodle-borg/service/dist/github/run-token.js +59 -0
  149. package/node_modules/@noodle-borg/service/dist/github/run-token.js.map +1 -0
  150. package/node_modules/@noodle-borg/service/dist/http-util.d.ts +7 -1
  151. package/node_modules/@noodle-borg/service/dist/http-util.d.ts.map +1 -1
  152. package/node_modules/@noodle-borg/service/dist/http-util.js +14 -0
  153. package/node_modules/@noodle-borg/service/dist/http-util.js.map +1 -1
  154. package/node_modules/@noodle-borg/service/dist/index.d.ts +13 -2
  155. package/node_modules/@noodle-borg/service/dist/index.d.ts.map +1 -1
  156. package/node_modules/@noodle-borg/service/dist/index.js +12 -1
  157. package/node_modules/@noodle-borg/service/dist/index.js.map +1 -1
  158. package/node_modules/@noodle-borg/service/dist/main.js +72 -0
  159. package/node_modules/@noodle-borg/service/dist/main.js.map +1 -1
  160. package/node_modules/@noodle-borg/service/dist/options.d.ts +26 -3
  161. package/node_modules/@noodle-borg/service/dist/options.d.ts.map +1 -1
  162. package/node_modules/@noodle-borg/service/dist/registry-helpers.d.ts +12 -0
  163. package/node_modules/@noodle-borg/service/dist/registry-helpers.d.ts.map +1 -1
  164. package/node_modules/@noodle-borg/service/dist/registry-helpers.js +3 -0
  165. package/node_modules/@noodle-borg/service/dist/registry-helpers.js.map +1 -1
  166. package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +7 -0
  167. package/node_modules/@noodle-borg/service/dist/registry-types.d.ts.map +1 -1
  168. package/node_modules/@noodle-borg/service/dist/registry.d.ts +7 -29
  169. package/node_modules/@noodle-borg/service/dist/registry.d.ts.map +1 -1
  170. package/node_modules/@noodle-borg/service/dist/registry.js +62 -57
  171. package/node_modules/@noodle-borg/service/dist/registry.js.map +1 -1
  172. package/node_modules/@noodle-borg/service/dist/routes/asset-control-plane.d.ts +3 -2
  173. package/node_modules/@noodle-borg/service/dist/routes/asset-control-plane.d.ts.map +1 -1
  174. package/node_modules/@noodle-borg/service/dist/routes/asset-control-plane.js +36 -8
  175. package/node_modules/@noodle-borg/service/dist/routes/asset-control-plane.js.map +1 -1
  176. package/node_modules/@noodle-borg/service/dist/routes/control-plane.d.ts +3 -2
  177. package/node_modules/@noodle-borg/service/dist/routes/control-plane.d.ts.map +1 -1
  178. package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +100 -12
  179. package/node_modules/@noodle-borg/service/dist/routes/control-plane.js.map +1 -1
  180. package/node_modules/@noodle-borg/service/dist/routes/github-dispatch.d.ts +7 -0
  181. package/node_modules/@noodle-borg/service/dist/routes/github-dispatch.d.ts.map +1 -1
  182. package/node_modules/@noodle-borg/service/dist/routes/github-dispatch.js +36 -1
  183. package/node_modules/@noodle-borg/service/dist/routes/github-dispatch.js.map +1 -1
  184. package/node_modules/@noodle-borg/service/dist/routes/github-run-claim.d.ts +13 -0
  185. package/node_modules/@noodle-borg/service/dist/routes/github-run-claim.d.ts.map +1 -0
  186. package/node_modules/@noodle-borg/service/dist/routes/github-run-claim.js +84 -0
  187. package/node_modules/@noodle-borg/service/dist/routes/github-run-claim.js.map +1 -0
  188. package/node_modules/@noodle-borg/service/dist/routes/github-run-status.d.ts +5 -0
  189. package/node_modules/@noodle-borg/service/dist/routes/github-run-status.d.ts.map +1 -0
  190. package/node_modules/@noodle-borg/service/dist/routes/github-run-status.js +73 -0
  191. package/node_modules/@noodle-borg/service/dist/routes/github-run-status.js.map +1 -0
  192. package/node_modules/@noodle-borg/service/dist/routes/github-webhook.d.ts +23 -1
  193. package/node_modules/@noodle-borg/service/dist/routes/github-webhook.d.ts.map +1 -1
  194. package/node_modules/@noodle-borg/service/dist/routes/github-webhook.js +41 -0
  195. package/node_modules/@noodle-borg/service/dist/routes/github-webhook.js.map +1 -1
  196. package/node_modules/@noodle-borg/service/dist/routes/paths.d.ts +4 -0
  197. package/node_modules/@noodle-borg/service/dist/routes/paths.d.ts.map +1 -1
  198. package/node_modules/@noodle-borg/service/dist/routes/paths.js +10 -0
  199. package/node_modules/@noodle-borg/service/dist/routes/paths.js.map +1 -1
  200. package/node_modules/@noodle-borg/service/dist/routes/run-deploy-auth.d.ts +85 -0
  201. package/node_modules/@noodle-borg/service/dist/routes/run-deploy-auth.d.ts.map +1 -0
  202. package/node_modules/@noodle-borg/service/dist/routes/run-deploy-auth.js +90 -0
  203. package/node_modules/@noodle-borg/service/dist/routes/run-deploy-auth.js.map +1 -0
  204. package/node_modules/@noodle-borg/service/dist/serve.d.ts.map +1 -1
  205. package/node_modules/@noodle-borg/service/dist/serve.js +31 -0
  206. package/node_modules/@noodle-borg/service/dist/serve.js.map +1 -1
  207. package/node_modules/@noodle-borg/service/dist/service.d.ts.map +1 -1
  208. package/node_modules/@noodle-borg/service/dist/service.js +8 -13
  209. package/node_modules/@noodle-borg/service/dist/service.js.map +1 -1
  210. package/node_modules/@noodle-borg/service/dist/store/github-connections-json-file.d.ts +1 -0
  211. package/node_modules/@noodle-borg/service/dist/store/github-connections-json-file.d.ts.map +1 -1
  212. package/node_modules/@noodle-borg/service/dist/store/github-connections-json-file.js +5 -0
  213. package/node_modules/@noodle-borg/service/dist/store/github-connections-json-file.js.map +1 -1
  214. package/node_modules/@noodle-borg/service/dist/store/github-connections.d.ts +1 -0
  215. package/node_modules/@noodle-borg/service/dist/store/github-connections.d.ts.map +1 -1
  216. package/node_modules/@noodle-borg/service/dist/store/github-connections.js +5 -0
  217. package/node_modules/@noodle-borg/service/dist/store/github-connections.js.map +1 -1
  218. package/node_modules/@noodle-borg/service/dist/store/github-deploy-run-contract.d.ts +120 -0
  219. package/node_modules/@noodle-borg/service/dist/store/github-deploy-run-contract.d.ts.map +1 -0
  220. package/node_modules/@noodle-borg/service/dist/store/github-deploy-run-contract.js +6 -0
  221. package/node_modules/@noodle-borg/service/dist/store/github-deploy-run-contract.js.map +1 -0
  222. package/node_modules/@noodle-borg/service/dist/store/github-runs-json-file.d.ts +6 -1
  223. package/node_modules/@noodle-borg/service/dist/store/github-runs-json-file.d.ts.map +1 -1
  224. package/node_modules/@noodle-borg/service/dist/store/github-runs-json-file.js +18 -1
  225. package/node_modules/@noodle-borg/service/dist/store/github-runs-json-file.js.map +1 -1
  226. package/node_modules/@noodle-borg/service/dist/store/github-runs.d.ts +22 -1
  227. package/node_modules/@noodle-borg/service/dist/store/github-runs.d.ts.map +1 -1
  228. package/node_modules/@noodle-borg/service/dist/store/github-runs.js +39 -2
  229. package/node_modules/@noodle-borg/service/dist/store/github-runs.js.map +1 -1
  230. package/node_modules/@noodle-borg/service/dist/store/postgres-github-runs.d.ts +13 -1
  231. package/node_modules/@noodle-borg/service/dist/store/postgres-github-runs.d.ts.map +1 -1
  232. package/node_modules/@noodle-borg/service/dist/store/postgres-github-runs.js +115 -1
  233. package/node_modules/@noodle-borg/service/dist/store/postgres-github-runs.js.map +1 -1
  234. package/node_modules/@noodle-borg/service/dist/store/postgres-github.d.ts +1 -0
  235. package/node_modules/@noodle-borg/service/dist/store/postgres-github.d.ts.map +1 -1
  236. package/node_modules/@noodle-borg/service/dist/store/postgres-github.js +6 -0
  237. package/node_modules/@noodle-borg/service/dist/store/postgres-github.js.map +1 -1
  238. package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts +15 -1
  239. package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts.map +1 -1
  240. package/node_modules/@noodle-borg/service/dist/store/postgres.js +22 -2
  241. package/node_modules/@noodle-borg/service/dist/store/postgres.js.map +1 -1
  242. package/node_modules/@noodle-borg/service/dist/store.d.ts +22 -99
  243. package/node_modules/@noodle-borg/service/dist/store.d.ts.map +1 -1
  244. package/node_modules/@noodle-borg/service/dist/store.js.map +1 -1
  245. package/package.json +2 -2
@@ -0,0 +1,107 @@
1
+ import { noopLogger } from '@noodle-borg/transport-http';
2
+ import { resolveGithubStateSecret } from './install-nonce.js';
3
+ import { signRunToken } from './run-token.js';
4
+ export const GITHUB_RUN_RECONCILE_INTERVAL_MS = 60_000;
5
+ export const GITHUB_RUN_TIMEOUT_MS = 180_000;
6
+ export const GITHUB_RUN_QUEUED_REDISPATCH_GRACE_MS = 30_000;
7
+ /**
8
+ * Idempotent GitHub deploy-run reconciler. Webhook dispatch is intentionally fire-and-forget; this
9
+ * loop is the recovery path for missed Cloud Run Job launches and abandoned in-flight runs.
10
+ */
11
+ export class GithubDeployRunReconciler {
12
+ #runStore;
13
+ #connectionStore;
14
+ #executor;
15
+ #webhookSecret;
16
+ #serviceBaseUrl;
17
+ #clock;
18
+ #logger;
19
+ #intervalMs;
20
+ #runTimeoutMs;
21
+ #queuedRedispatchGraceMs;
22
+ #limitPerConnection;
23
+ #lastSweepStartedAt = Number.NEGATIVE_INFINITY;
24
+ #inFlight = false;
25
+ constructor(options) {
26
+ this.#runStore = options.runStore;
27
+ this.#connectionStore = options.connectionStore;
28
+ this.#executor = options.executor;
29
+ this.#webhookSecret = resolveGithubStateSecret(options.webhookSecret);
30
+ this.#serviceBaseUrl = options.serviceBaseUrl.replace(/\/+$/, '');
31
+ this.#clock = options.clock ?? (() => new Date());
32
+ this.#logger = options.logger ?? noopLogger;
33
+ this.#intervalMs = options.intervalMs ?? GITHUB_RUN_RECONCILE_INTERVAL_MS;
34
+ this.#runTimeoutMs = options.runTimeoutMs ?? GITHUB_RUN_TIMEOUT_MS;
35
+ this.#queuedRedispatchGraceMs =
36
+ options.queuedRedispatchGraceMs ?? GITHUB_RUN_QUEUED_REDISPATCH_GRACE_MS;
37
+ this.#limitPerConnection = options.limitPerConnection ?? 50;
38
+ }
39
+ maybeSweep() {
40
+ const now = this.#clock().getTime();
41
+ if (this.#inFlight || now - this.#lastSweepStartedAt < this.#intervalMs)
42
+ return;
43
+ this.#lastSweepStartedAt = now;
44
+ this.#inFlight = true;
45
+ void this.sweepNow()
46
+ .catch(() => {
47
+ this.#logger.warn('github.run.reconcile_failed', { status: 500 });
48
+ })
49
+ .finally(() => {
50
+ this.#inFlight = false;
51
+ });
52
+ }
53
+ async sweepNow() {
54
+ const now = this.#clock();
55
+ const connections = await this.#connectionStore.listRepoConnections();
56
+ let inspected = 0;
57
+ let dispatched = 0;
58
+ let failed = 0;
59
+ for (const connection of connections) {
60
+ const result = await this.#runStore.listDeployRuns(connection.orgSlug, connection.appSlug, {
61
+ limit: this.#limitPerConnection,
62
+ });
63
+ for (const run of result.runs) {
64
+ if (run.githubRepositoryId !== connection.githubRepositoryId)
65
+ continue;
66
+ inspected += 1;
67
+ if (run.blockedReason !== undefined)
68
+ continue;
69
+ if (run.status === 'queued') {
70
+ if (!this.#isOlderThan(run.createdAt, now, this.#queuedRedispatchGraceMs))
71
+ continue;
72
+ await this.#dispatch(run);
73
+ dispatched += 1;
74
+ continue;
75
+ }
76
+ if ((run.status === 'building' || run.status === 'deploying') &&
77
+ this.#isOlderThan(run.startedAt ?? run.createdAt, now, this.#runTimeoutMs)) {
78
+ const transition = await this.#runStore.transitionDeployRun(run.orgSlug, run.runId, 'failed', {
79
+ errorSummary: `github build worker timed out after ${Math.round(this.#runTimeoutMs / 1000)}s`,
80
+ });
81
+ if (transition.ok)
82
+ failed += 1;
83
+ }
84
+ }
85
+ }
86
+ return { connections: connections.length, inspected, dispatched, failed };
87
+ }
88
+ async #dispatch(run) {
89
+ const runToken = signRunToken({
90
+ runId: run.runId,
91
+ org: run.orgSlug,
92
+ app: run.appSlug,
93
+ env: run.envName,
94
+ issuedAt: this.#clock().getTime(),
95
+ }, this.#webhookSecret);
96
+ await this.#executor
97
+ .dispatch({ run, runToken, serviceBaseUrl: this.#serviceBaseUrl })
98
+ .catch(() => {
99
+ this.#logger.warn('github.run.dispatch_failed', { status: 200, runId: run.runId });
100
+ });
101
+ }
102
+ #isOlderThan(iso, now, thresholdMs) {
103
+ const started = Date.parse(iso);
104
+ return Number.isFinite(started) && now.getTime() - started >= thresholdMs;
105
+ }
106
+ }
107
+ //# sourceMappingURL=deploy-run-reconciler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy-run-reconciler.js","sourceRoot":"","sources":["../../src/github/deploy-run-reconciler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAGtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,CAAC,MAAM,gCAAgC,GAAG,MAAM,CAAC;AACvD,MAAM,CAAC,MAAM,qBAAqB,GAAG,OAAO,CAAC;AAC7C,MAAM,CAAC,MAAM,qCAAqC,GAAG,MAAM,CAAC;AAuB5D;;;GAGG;AACH,MAAM,OAAO,yBAAyB;IAC3B,SAAS,CAAuB;IAChC,gBAAgB,CAAwB;IACxC,SAAS,CAAoB;IAC7B,cAAc,CAAS;IACvB,eAAe,CAAS;IACxB,MAAM,CAAa;IACnB,OAAO,CAAS;IAChB,WAAW,CAAS;IACpB,aAAa,CAAS;IACtB,wBAAwB,CAAS;IACjC,mBAAmB,CAAS;IACrC,mBAAmB,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAC/C,SAAS,GAAG,KAAK,CAAC;IAElB,YAAY,OAAyC;QACnD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;QAChD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,cAAc,GAAG,wBAAwB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACtE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,IAAI,UAAU,CAAC;QAC5C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,UAAU,IAAI,gCAAgC,CAAC;QAC1E,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAC;QACnE,IAAI,CAAC,wBAAwB;YAC3B,OAAO,CAAC,uBAAuB,IAAI,qCAAqC,CAAC;QAC3E,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,IAAI,EAAE,CAAC;IAC9D,CAAC;IAED,UAAU;QACR,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,SAAS,IAAI,GAAG,GAAG,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,WAAW;YAAE,OAAO;QAChF,IAAI,CAAC,mBAAmB,GAAG,GAAG,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,KAAK,IAAI,CAAC,QAAQ,EAAE;aACjB,KAAK,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACpE,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACZ,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACzB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,CAAC;QACtE,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE;gBACzF,KAAK,EAAE,IAAI,CAAC,mBAAmB;aAChC,CAAC,CAAC;YACH,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC9B,IAAI,GAAG,CAAC,kBAAkB,KAAK,UAAU,CAAC,kBAAkB;oBAAE,SAAS;gBACvE,SAAS,IAAI,CAAC,CAAC;gBACf,IAAI,GAAG,CAAC,aAAa,KAAK,SAAS;oBAAE,SAAS;gBAC9C,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;oBAC5B,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,wBAAwB,CAAC;wBAAE,SAAS;oBACpF,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBAC1B,UAAU,IAAI,CAAC,CAAC;oBAChB,SAAS;gBACX,CAAC;gBACD,IACE,CAAC,GAAG,CAAC,MAAM,KAAK,UAAU,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC;oBACzD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,aAAa,CAAC,EAC1E,CAAC;oBACD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,mBAAmB,CACzD,GAAG,CAAC,OAAO,EACX,GAAG,CAAC,KAAK,EACT,QAAQ,EACR;wBACE,YAAY,EAAE,uCAAuC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG;qBAC9F,CACF,CAAC;oBACF,IAAI,UAAU,CAAC,EAAE;wBAAE,MAAM,IAAI,CAAC,CAAC;gBACjC,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,EAAE,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,GAAoB;QAClC,MAAM,QAAQ,GAAG,YAAY,CAC3B;YACE,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,GAAG,EAAE,GAAG,CAAC,OAAO;YAChB,GAAG,EAAE,GAAG,CAAC,OAAO;YAChB,GAAG,EAAE,GAAG,CAAC,OAAO;YAChB,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;SAClC,EACD,IAAI,CAAC,cAAc,CACpB,CAAC;QACF,MAAM,IAAI,CAAC,SAAS;aACjB,QAAQ,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC;aACjE,KAAK,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QACrF,CAAC,CAAC,CAAC;IACP,CAAC;IAED,YAAY,CAAC,GAAW,EAAE,GAAS,EAAE,WAAmB;QACtD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,IAAI,WAAW,CAAC;IAC5E,CAAC;CACF"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Fast-lane eligibility classifier (GHD-3, ADR 0132 Decision 2). A canonical Noodle app imports only
3
+ * the SDK and local files — nothing to install — so its git deploy is structurally *seconds*. This
4
+ * gate enforces exactly that BEFORE any user source executes: a repo whose `package.json` declares
5
+ * third-party dependencies is rejected up front with a structured reason, never compiled. The slow
6
+ * lane (frozen installs) is a later, separate decision behind the same executor seam.
7
+ *
8
+ * Pure over the parsed `package.json` (no fs, no network) so it runs identically in the untrusted
9
+ * sandbox and in unit tests.
10
+ */
11
+ /** SDK package names an app may depend on without leaving the fast lane. */
12
+ export declare const FAST_LANE_ALLOWED_DEPENDENCIES: ReadonlySet<string>;
13
+ export type FastLaneClassification = {
14
+ readonly eligible: true;
15
+ } | {
16
+ readonly eligible: false;
17
+ readonly reason: 'unsupported_dependencies';
18
+ readonly unsupported: readonly string[];
19
+ };
20
+ interface PackageJsonShape {
21
+ readonly dependencies?: Readonly<Record<string, unknown>>;
22
+ readonly devDependencies?: Readonly<Record<string, unknown>>;
23
+ }
24
+ /**
25
+ * Classify a repo from its parsed `package.json` (or `undefined` when the repo has none — a bare
26
+ * `server.ts` app is fast-lane eligible). Any dependency or devDependency outside the SDK allowlist
27
+ * makes the repo slow-lane (unsupported in the MVP): the offending names are returned so the failure
28
+ * can name them.
29
+ */
30
+ export declare function classifyFastLane(pkg: PackageJsonShape | undefined): FastLaneClassification;
31
+ /**
32
+ * Parse a raw `package.json` string, then classify. Malformed JSON is treated as "no package.json"
33
+ * (fast-lane eligible) — the compile step will surface any real problem — rather than failing the
34
+ * run on a formatting quirk. Callers that need strict parsing should classify the parsed object.
35
+ */
36
+ export declare function classifyFastLaneFromRaw(raw: string | undefined): FastLaneClassification;
37
+ export {};
38
+ //# sourceMappingURL=fast-lane-classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fast-lane-classifier.d.ts","sourceRoot":"","sources":["../../src/github/fast-lane-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,4EAA4E;AAC5E,eAAO,MAAM,8BAA8B,EAAE,WAAW,CAAC,MAAM,CAM7D,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,GAC3B;IACE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAEN,UAAU,gBAAgB;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC9D;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,SAAS,GAAG,sBAAsB,CAe1F;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,sBAAsB,CAOvF"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Fast-lane eligibility classifier (GHD-3, ADR 0132 Decision 2). A canonical Noodle app imports only
3
+ * the SDK and local files — nothing to install — so its git deploy is structurally *seconds*. This
4
+ * gate enforces exactly that BEFORE any user source executes: a repo whose `package.json` declares
5
+ * third-party dependencies is rejected up front with a structured reason, never compiled. The slow
6
+ * lane (frozen installs) is a later, separate decision behind the same executor seam.
7
+ *
8
+ * Pure over the parsed `package.json` (no fs, no network) so it runs identically in the untrusted
9
+ * sandbox and in unit tests.
10
+ */
11
+ /** SDK package names an app may depend on without leaving the fast lane. */
12
+ export const FAST_LANE_ALLOWED_DEPENDENCIES = new Set([
13
+ '@noodleseed/one',
14
+ // The widget runtime the SDK's React surface compiles against — provisioned in the builder image,
15
+ // never installed from a lockfile.
16
+ 'react',
17
+ 'react-dom',
18
+ ]);
19
+ /**
20
+ * Classify a repo from its parsed `package.json` (or `undefined` when the repo has none — a bare
21
+ * `server.ts` app is fast-lane eligible). Any dependency or devDependency outside the SDK allowlist
22
+ * makes the repo slow-lane (unsupported in the MVP): the offending names are returned so the failure
23
+ * can name them.
24
+ */
25
+ export function classifyFastLane(pkg) {
26
+ if (pkg === undefined)
27
+ return { eligible: true };
28
+ const names = new Set();
29
+ for (const record of [pkg.dependencies, pkg.devDependencies]) {
30
+ if (record === undefined)
31
+ continue;
32
+ for (const name of Object.keys(record)) {
33
+ if (!FAST_LANE_ALLOWED_DEPENDENCIES.has(name))
34
+ names.add(name);
35
+ }
36
+ }
37
+ if (names.size === 0)
38
+ return { eligible: true };
39
+ return {
40
+ eligible: false,
41
+ reason: 'unsupported_dependencies',
42
+ unsupported: [...names].sort(),
43
+ };
44
+ }
45
+ /**
46
+ * Parse a raw `package.json` string, then classify. Malformed JSON is treated as "no package.json"
47
+ * (fast-lane eligible) — the compile step will surface any real problem — rather than failing the
48
+ * run on a formatting quirk. Callers that need strict parsing should classify the parsed object.
49
+ */
50
+ export function classifyFastLaneFromRaw(raw) {
51
+ if (raw === undefined)
52
+ return { eligible: true };
53
+ try {
54
+ return classifyFastLane(JSON.parse(raw));
55
+ }
56
+ catch {
57
+ return { eligible: true };
58
+ }
59
+ }
60
+ //# sourceMappingURL=fast-lane-classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fast-lane-classifier.js","sourceRoot":"","sources":["../../src/github/fast-lane-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,8BAA8B,GAAwB,IAAI,GAAG,CAAC;IACzE,iBAAiB;IACjB,kGAAkG;IAClG,mCAAmC;IACnC,OAAO;IACP,WAAW;CACZ,CAAC,CAAC;AAeH;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAiC;IAChE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QAC7D,IAAI,MAAM,KAAK,SAAS;YAAE,SAAS;QACnC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,8BAA8B,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAChD,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,0BAA0B;QAClC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE;KAC/B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAuB;IAC7D,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjD,IAAI,CAAC;QACH,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAqB,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { CompileStageResult } from './deploy-pipeline.js';
2
+ /**
3
+ * The untrusted compile stage for the local/self-host build worker (GHD-3, ADR 0132 Decision 2/5).
4
+ * It reads a checked-out source directory and returns manifest data — it is NEVER handed the run token
5
+ * (the pipeline enforces that seam). The manifest emission itself is injected as {@link ManifestExporter}
6
+ * so the executor can run the real `noodle export manifest` subprocess while unit tests supply a
7
+ * manifest directly (no binary, no child process). Debuggability: the default exporter runs the exact
8
+ * command a human debugs with — `noodle export manifest` in the repo.
9
+ *
10
+ * Order matters for the fast-lane guarantee: the dependency gate runs BEFORE any source executes, so a
11
+ * repo with third-party deps is rejected up front with a named reason, never compiled.
12
+ */
13
+ export type ManifestExporter = (input: {
14
+ readonly sourceDir: string;
15
+ readonly entrypoint: string;
16
+ }) => Promise<{
17
+ readonly manifest: string;
18
+ readonly connectors?: string;
19
+ }>;
20
+ export interface LocalCompileOptions {
21
+ readonly exportManifest: ManifestExporter;
22
+ }
23
+ export declare function createLocalCompile(options: LocalCompileOptions): (sourceDir: string) => Promise<CompileStageResult>;
24
+ //# sourceMappingURL=local-compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-compile.d.ts","sourceRoot":"","sources":["../../src/github/local-compile.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAiB,MAAM,sBAAsB,CAAC;AAG9E;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,KAAK,OAAO,CAAC;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,cAAc,EAAE,gBAAgB,CAAC;CAC3C;AA2CD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,mBAAmB,GAC3B,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CA8DpD"}
@@ -0,0 +1,98 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { manifestSchema, prepareLocalAssets } from '@noodle-borg/compiler';
4
+ import { classifyFastLane } from './fast-lane-classifier.js';
5
+ async function readJsonFile(path) {
6
+ try {
7
+ return JSON.parse(await readFile(path, 'utf8'));
8
+ }
9
+ catch {
10
+ return undefined;
11
+ }
12
+ }
13
+ function truncate(text, max = 240) {
14
+ return text.length > max ? `${text.slice(0, max)}…` : text;
15
+ }
16
+ /**
17
+ * Resolve the manifest's local hosted assets (widget bundles, images) to upload-ready pairs: the wire
18
+ * metadata (absolutePath stripped) plus the bytes. Reuses the compiler's `prepareLocalAssets` so the
19
+ * git build worker and the CLI deploy path share one asset contract.
20
+ */
21
+ async function prepareAssetsForUpload(manifest, rootDir) {
22
+ let raw;
23
+ try {
24
+ raw = JSON.parse(manifest);
25
+ }
26
+ catch {
27
+ return [];
28
+ }
29
+ const parsed = manifestSchema.safeParse(raw);
30
+ if (!parsed.success)
31
+ return [];
32
+ const prepared = prepareLocalAssets(parsed.data, { rootDir });
33
+ if (prepared.errors.length > 0) {
34
+ throw new Error(prepared.errors.map((error) => error.message).join('; '));
35
+ }
36
+ const assets = [];
37
+ for (const asset of prepared.assets) {
38
+ const { absolutePath, ...wire } = asset;
39
+ assets.push({ prepared: wire, bytes: new Uint8Array(await readFile(absolutePath)) });
40
+ }
41
+ return assets;
42
+ }
43
+ export function createLocalCompile(options) {
44
+ return async (sourceDir) => {
45
+ // 1. Fast-lane dependency gate — reject third-party deps BEFORE running any source.
46
+ const pkg = await readJsonFile(join(sourceDir, 'package.json'));
47
+ const classification = classifyFastLane(pkg);
48
+ if (!classification.eligible) {
49
+ const noun = classification.unsupported.length === 1 ? 'dependency' : 'dependencies';
50
+ const list = classification.unsupported.map((name) => `"${name}"`).join(', ');
51
+ return {
52
+ ok: false,
53
+ errorSummary: `compile: unsupported ${noun} ${list} — the git build worker compiles Noodle-native source only (SDK + local files); deploy with the CLI instead`,
54
+ };
55
+ }
56
+ // 2. Entrypoint + declared access mode from committed noodle.json (the "declared" inherit source).
57
+ const noodleJson = await readJsonFile(join(sourceDir, 'noodle.json'));
58
+ const entrypoint = typeof noodleJson?.entrypoint === 'string' ? noodleJson.entrypoint : 'server.ts';
59
+ const declaredAccessMode = typeof noodleJson?.accessMode === 'string' ? noodleJson.accessMode : undefined;
60
+ // 3. Compile the manifest (untrusted — this runs the app's source).
61
+ let exported;
62
+ try {
63
+ exported = await options.exportManifest({
64
+ sourceDir,
65
+ entrypoint: join(sourceDir, entrypoint),
66
+ });
67
+ }
68
+ catch (error) {
69
+ const name = error instanceof Error ? error.name : 'Error';
70
+ const message = error instanceof Error ? error.message : '';
71
+ return {
72
+ ok: false,
73
+ errorSummary: `compile: ${entrypoint} failed to compile (${name})${message !== '' ? `: ${truncate(message)}` : ''}`,
74
+ };
75
+ }
76
+ // 4. Prepare local hosted assets for the pipeline to upload.
77
+ let assets;
78
+ try {
79
+ assets = await prepareAssetsForUpload(exported.manifest, sourceDir);
80
+ }
81
+ catch (error) {
82
+ return {
83
+ ok: false,
84
+ errorSummary: `compile: hosted asset preparation failed: ${error instanceof Error ? truncate(error.message) : 'unknown error'}`,
85
+ };
86
+ }
87
+ return {
88
+ ok: true,
89
+ input: {
90
+ manifest: exported.manifest,
91
+ ...(exported.connectors !== undefined ? { connectors: exported.connectors } : {}),
92
+ ...(declaredAccessMode !== undefined ? { declaredAccessMode } : {}),
93
+ ...(assets.length > 0 ? { assets } : {}),
94
+ },
95
+ };
96
+ };
97
+ }
98
+ //# sourceMappingURL=local-compile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-compile.js","sourceRoot":"","sources":["../../src/github/local-compile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { DeployRunRecord } from '../store.js';
2
+ import type { DeployRunDispatchInput, DeployRunExecutor } from './deploy-run-executor.js';
3
+ import { type ManifestExporter } from './local-compile.js';
4
+ /** A checked-out working copy of the run's source, plus an optional cleanup for its temp storage. */
5
+ export interface RepoCheckout {
6
+ readonly sourceDir: string;
7
+ readonly cleanup?: () => Promise<void>;
8
+ }
9
+ export interface LocalProcessExecutorDeps {
10
+ /**
11
+ * Fetch the run's source into a local directory — a git clone at `commitSha` in prod/self-host, a
12
+ * fixture directory in tests. This is the deferred credential-broker/git seam; it lives here so the
13
+ * rest of the pipeline never sees an installation token.
14
+ */
15
+ readonly checkout: (run: DeployRunRecord) => Promise<RepoCheckout>;
16
+ /** How the untrusted source becomes a manifest — the real adapter runs `noodle export manifest`. */
17
+ readonly exportManifest: ManifestExporter;
18
+ /** Injected so tests use a fake and prod uses global `fetch`. */
19
+ readonly httpFetch?: typeof fetch;
20
+ }
21
+ /**
22
+ * The C2 / self-host / E2E executor (GHD-3, ADR 0132 Decision 6): runs the untrusted-compile →
23
+ * trusted-deploy pipeline as a local async task. `checkout` (fetch source) and `exportManifest`
24
+ * (source → manifest) are the only environment-specific seams, and both are folded into the pipeline's
25
+ * untrusted `compile` closure — so a checkout OR compile failure lands the run at `failed` with a
26
+ * compile-stage `errorSummary`, never a hang.
27
+ *
28
+ * `dispatch` is fire-and-forget: it launches the task and resolves immediately (the webhook must answer
29
+ * GitHub at once) and never throws into the caller. `settled()` lets tests and graceful shutdown await
30
+ * the launched work.
31
+ */
32
+ export declare class LocalProcessExecutor implements DeployRunExecutor {
33
+ #private;
34
+ constructor(deps: LocalProcessExecutorDeps);
35
+ dispatch(input: DeployRunDispatchInput): Promise<void>;
36
+ /** Await every launched pipeline — for tests and graceful shutdown. */
37
+ settled(): Promise<void>;
38
+ }
39
+ //# sourceMappingURL=local-process-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-process-executor.d.ts","sourceRoot":"","sources":["../../src/github/local-process-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE/E,qGAAqG;AACrG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACnE,oGAAoG;IACpG,QAAQ,CAAC,cAAc,EAAE,gBAAgB,CAAC;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACnC;AAED;;;;;;;;;;GAUG;AACH,qBAAa,oBAAqB,YAAW,iBAAiB;;gBAMhD,IAAI,EAAE,wBAAwB;IAM1C,QAAQ,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtD,uEAAuE;IACjE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAiC/B"}
@@ -0,0 +1,67 @@
1
+ import { runDeployPipeline } from './deploy-pipeline.js';
2
+ import { createLocalCompile } from './local-compile.js';
3
+ /**
4
+ * The C2 / self-host / E2E executor (GHD-3, ADR 0132 Decision 6): runs the untrusted-compile →
5
+ * trusted-deploy pipeline as a local async task. `checkout` (fetch source) and `exportManifest`
6
+ * (source → manifest) are the only environment-specific seams, and both are folded into the pipeline's
7
+ * untrusted `compile` closure — so a checkout OR compile failure lands the run at `failed` with a
8
+ * compile-stage `errorSummary`, never a hang.
9
+ *
10
+ * `dispatch` is fire-and-forget: it launches the task and resolves immediately (the webhook must answer
11
+ * GitHub at once) and never throws into the caller. `settled()` lets tests and graceful shutdown await
12
+ * the launched work.
13
+ */
14
+ export class LocalProcessExecutor {
15
+ #checkout;
16
+ #localCompile;
17
+ #httpFetch;
18
+ #inflight = new Set();
19
+ constructor(deps) {
20
+ this.#checkout = deps.checkout;
21
+ this.#localCompile = createLocalCompile({ exportManifest: deps.exportManifest });
22
+ this.#httpFetch = deps.httpFetch ?? fetch;
23
+ }
24
+ dispatch(input) {
25
+ const task = this.#run(input);
26
+ this.#inflight.add(task);
27
+ void task.finally(() => this.#inflight.delete(task));
28
+ // Fire-and-forget: resolve once launched, never await the pipeline here.
29
+ return Promise.resolve();
30
+ }
31
+ /** Await every launched pipeline — for tests and graceful shutdown. */
32
+ async settled() {
33
+ await Promise.all([...this.#inflight]);
34
+ }
35
+ async #run(input) {
36
+ const compile = async (run) => {
37
+ let checkout;
38
+ try {
39
+ checkout = await this.#checkout(run);
40
+ }
41
+ catch (error) {
42
+ const name = error instanceof Error ? error.name : 'Error';
43
+ return {
44
+ ok: false,
45
+ errorSummary: `compile: could not fetch source at ${run.commitSha.slice(0, 7)} (${name})`,
46
+ };
47
+ }
48
+ try {
49
+ return await this.#localCompile(checkout.sourceDir);
50
+ }
51
+ finally {
52
+ // Best-effort: a cleanup failure (temp-dir hiccup) must never overwrite a successful
53
+ // compile result — a `finally` throw would discard the returned manifest and fail the run.
54
+ await checkout.cleanup?.().catch(() => undefined);
55
+ }
56
+ };
57
+ // The pipeline reports every transition + failure over the wire; it does not throw.
58
+ await runDeployPipeline({
59
+ run: input.run,
60
+ runToken: input.runToken,
61
+ serviceBaseUrl: input.serviceBaseUrl,
62
+ compile,
63
+ httpFetch: this.#httpFetch,
64
+ });
65
+ }
66
+ }
67
+ //# sourceMappingURL=local-process-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-process-executor.js","sourceRoot":"","sources":["../../src/github/local-process-executor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAE,kBAAkB,EAAyB,MAAM,oBAAoB,CAAC;AAqB/E;;;;;;;;;;GAUG;AACH,MAAM,OAAO,oBAAoB;IACtB,SAAS,CAAuC;IAChD,aAAa,CAAqD;IAClE,UAAU,CAAe;IACzB,SAAS,GAAG,IAAI,GAAG,EAAiB,CAAC;IAE9C,YAAY,IAA8B;QACxC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,aAAa,GAAG,kBAAkB,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;IAC5C,CAAC;IAED,QAAQ,CAAC,KAA6B;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzB,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACrD,yEAAyE;QACzE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,uEAAuE;IACvE,KAAK,CAAC,OAAO;QACX,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAA6B;QACtC,MAAM,OAAO,GAAG,KAAK,EAAE,GAAoB,EAA+B,EAAE;YAC1E,IAAI,QAAsB,CAAC;YAC3B,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC3D,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,YAAY,EAAE,sCAAsC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG;iBAC1F,CAAC;YACJ,CAAC;YACD,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACtD,CAAC;oBAAS,CAAC;gBACT,qFAAqF;gBACrF,2FAA2F;gBAC3F,MAAM,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC;QACF,oFAAoF;QACpF,MAAM,iBAAiB,CAAC;YACtB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,OAAO;YACP,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import type { AccessMode } from '@noodle-borg/transport-http';
2
+ export declare function isAccessMode(value: unknown): value is AccessMode;
3
+ export type ResolveRunAccessModeResult = {
4
+ readonly ok: true;
5
+ readonly accessMode: AccessMode;
6
+ readonly source: 'previous' | 'declared';
7
+ } | {
8
+ readonly ok: false;
9
+ readonly reason: 'access_mode_required';
10
+ };
11
+ export interface ResolveRunAccessModeInput {
12
+ /** Access mode of the env's current active deployment, if any (the inherit source). */
13
+ readonly previousActiveAccessMode?: AccessMode | undefined;
14
+ /** Access mode declared in committed `noodle.json` or the connection record, if any. */
15
+ readonly declaredAccessMode?: string | undefined;
16
+ }
17
+ export declare function resolveRunAccessMode(input: ResolveRunAccessModeInput): ResolveRunAccessModeResult;
18
+ //# sourceMappingURL=run-access-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-access-mode.d.ts","sourceRoot":"","sources":["../../src/github/run-access-mode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAuB9D,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAAA;CAAE,GAChG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAEpE,MAAM,WAAW,yBAAyB;IACxC,uFAAuF;IACvF,QAAQ,CAAC,wBAAwB,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC3D,wFAAwF;IACxF,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,0BAA0B,CAQjG"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Access-mode resolution for GitHub-run deploys (GHD-3, ADR 0132 Decision 4). Human CLI deploys
3
+ * default to `owner-only`, bound to the actor's subject — but a GitHub run deploys as automation, so
4
+ * defaulting there would lock the human owner out of their own endpoint. The resolution is therefore
5
+ * explicit, never guessed:
6
+ *
7
+ * 1. inherit the previous active deployment's access mode for this env, when one exists;
8
+ * 2. else an `accessMode` explicitly committed in `noodle.json` (or the connection record);
9
+ * 3. else FAIL structured (`access_mode_required`) — a first-ever git deploy with no declared mode
10
+ * must not silently become owner-only.
11
+ *
12
+ * Pure over its inputs so the executor can resolve it before touching the deploy route.
13
+ */
14
+ const ACCESS_MODES = new Set([
15
+ 'owner-only',
16
+ 'org-members',
17
+ 'authenticated',
18
+ 'customers',
19
+ ]);
20
+ export function isAccessMode(value) {
21
+ return typeof value === 'string' && ACCESS_MODES.has(value);
22
+ }
23
+ export function resolveRunAccessMode(input) {
24
+ if (input.previousActiveAccessMode !== undefined) {
25
+ return { ok: true, accessMode: input.previousActiveAccessMode, source: 'previous' };
26
+ }
27
+ if (isAccessMode(input.declaredAccessMode)) {
28
+ return { ok: true, accessMode: input.declaredAccessMode, source: 'declared' };
29
+ }
30
+ return { ok: false, reason: 'access_mode_required' };
31
+ }
32
+ //# sourceMappingURL=run-access-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-access-mode.js","sourceRoot":"","sources":["../../src/github/run-access-mode.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC;IAChD,YAAY;IACZ,aAAa;IACb,eAAe;IACf,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAaD,MAAM,UAAU,oBAAoB,CAAC,KAAgC;IACnE,IAAI,KAAK,CAAC,wBAAwB,KAAK,SAAS,EAAE,CAAC;QACjD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,wBAAwB,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACtF,CAAC;IACD,IAAI,YAAY,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC3C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,kBAAkB,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAChF,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;AACvD,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Run-scoped deploy credential (GHD-3, ADR 0132 Decision 3). Minted by the service when dispatching
3
+ * a deploy run; carried only by the TRUSTED runner phase — never by the sandboxed process that
4
+ * executes user source. It authorizes exactly three route surfaces for one `{runId, org, app, env}`:
5
+ * the run's own status transitions, asset preflight/upload for that tuple, and the final deploy
6
+ * POST. Verification is route-scoped on those handlers only — this is deliberately NOT a
7
+ * `DeployAuthGate`, so the token is meaningless on every other route.
8
+ *
9
+ * Same HMAC envelope discipline as `install-nonce.ts`: base64url(JSON payload) + hex HMAC-SHA256,
10
+ * timing-safe compare, hard expiry. Signing secret: `githubApp.webhookSecret` (the one secret the
11
+ * GHD feature already requires), via the same blank-rejecting resolver.
12
+ */
13
+ /** Build cap (2 min, ADR 0132 Decision 2) + dispatch/report slack. */
14
+ export declare const RUN_TOKEN_TTL_MS: number;
15
+ export interface RunTokenPayload {
16
+ readonly runId: string;
17
+ readonly org: string;
18
+ readonly app: string;
19
+ readonly env: string;
20
+ readonly issuedAt: number;
21
+ }
22
+ export declare function signRunToken(payload: RunTokenPayload, secret: string): string;
23
+ export type RunTokenVerification = {
24
+ readonly ok: true;
25
+ readonly payload: RunTokenPayload;
26
+ } | {
27
+ readonly ok: false;
28
+ readonly reason: 'malformed' | 'tampered' | 'expired';
29
+ };
30
+ export declare function verifyRunToken(token: string, secret: string, now?: () => Date): RunTokenVerification;
31
+ /**
32
+ * Route-scope check: does a verified token authorize THIS `{org, app, env}` tuple? Handlers must
33
+ * call this after `verifyRunToken` — a valid token for another app must read as forbidden, not as a
34
+ * different identity.
35
+ */
36
+ export declare function runTokenAuthorizes(payload: RunTokenPayload, target: {
37
+ readonly org: string;
38
+ readonly app: string;
39
+ readonly env: string;
40
+ }): boolean;
41
+ //# sourceMappingURL=run-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-token.d.ts","sourceRoot":"","sources":["../../src/github/run-token.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,QAAgB,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,CAAA;CAAE,CAAC;AAElF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,GAAE,MAAM,IAAuB,GACjC,oBAAoB,CA6BtB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC3E,OAAO,CAET"}