@pipeline-builder/pipeline-manager 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +145 -0
  3. package/cdk.json +91 -0
  4. package/config.yml +94 -0
  5. package/dist/agent/ai.d.ts +48 -0
  6. package/dist/agent/ai.d.ts.map +1 -0
  7. package/dist/agent/ai.js +149 -0
  8. package/dist/agent/bootstrap.d.ts +39 -0
  9. package/dist/agent/bootstrap.d.ts.map +1 -0
  10. package/dist/agent/bootstrap.js +66 -0
  11. package/dist/agent/env-file.d.ts +17 -0
  12. package/dist/agent/env-file.d.ts.map +1 -0
  13. package/dist/agent/env-file.js +47 -0
  14. package/dist/agent/executor.d.ts +30 -0
  15. package/dist/agent/executor.d.ts.map +1 -0
  16. package/dist/agent/executor.js +60 -0
  17. package/dist/agent/health.d.ts +43 -0
  18. package/dist/agent/health.d.ts.map +1 -0
  19. package/dist/agent/health.js +109 -0
  20. package/dist/agent/ports.d.ts +26 -0
  21. package/dist/agent/ports.d.ts.map +1 -0
  22. package/dist/agent/ports.js +132 -0
  23. package/dist/agent/post-steps.d.ts +61 -0
  24. package/dist/agent/post-steps.d.ts.map +1 -0
  25. package/dist/agent/post-steps.js +131 -0
  26. package/dist/agent/prereqs.d.ts +26 -0
  27. package/dist/agent/prereqs.d.ts.map +1 -0
  28. package/dist/agent/prereqs.js +134 -0
  29. package/dist/agent/targets.d.ts +128 -0
  30. package/dist/agent/targets.d.ts.map +1 -0
  31. package/dist/agent/targets.js +265 -0
  32. package/dist/agent/tools.d.ts +13 -0
  33. package/dist/agent/tools.d.ts.map +1 -0
  34. package/dist/agent/tools.js +75 -0
  35. package/dist/agent/troubleshoot.d.ts +30 -0
  36. package/dist/agent/troubleshoot.d.ts.map +1 -0
  37. package/dist/agent/troubleshoot.js +87 -0
  38. package/dist/boilerplate.d.ts +3 -0
  39. package/dist/boilerplate.d.ts.map +1 -0
  40. package/dist/boilerplate.js +54 -0
  41. package/dist/cdk.json +91 -0
  42. package/dist/cli.d.ts +62 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +463 -0
  45. package/dist/commands/audit-stacks.d.ts +24 -0
  46. package/dist/commands/audit-stacks.d.ts.map +1 -0
  47. package/dist/commands/audit-stacks.js +182 -0
  48. package/dist/commands/audit-tokens.d.ts +21 -0
  49. package/dist/commands/audit-tokens.d.ts.map +1 -0
  50. package/dist/commands/audit-tokens.js +153 -0
  51. package/dist/commands/bootstrap.d.ts +11 -0
  52. package/dist/commands/bootstrap.d.ts.map +1 -0
  53. package/dist/commands/bootstrap.js +159 -0
  54. package/dist/commands/create-pat.d.ts +27 -0
  55. package/dist/commands/create-pat.d.ts.map +1 -0
  56. package/dist/commands/create-pat.js +194 -0
  57. package/dist/commands/create-pipeline.d.ts +12 -0
  58. package/dist/commands/create-pipeline.d.ts.map +1 -0
  59. package/dist/commands/create-pipeline.js +315 -0
  60. package/dist/commands/deploy.d.ts +15 -0
  61. package/dist/commands/deploy.d.ts.map +1 -0
  62. package/dist/commands/deploy.js +157 -0
  63. package/dist/commands/entity-get.d.ts +51 -0
  64. package/dist/commands/entity-get.d.ts.map +1 -0
  65. package/dist/commands/entity-get.js +69 -0
  66. package/dist/commands/entity-list.d.ts +39 -0
  67. package/dist/commands/entity-list.d.ts.map +1 -0
  68. package/dist/commands/entity-list.js +88 -0
  69. package/dist/commands/get-pipeline.d.ts +13 -0
  70. package/dist/commands/get-pipeline.d.ts.map +1 -0
  71. package/dist/commands/get-pipeline.js +49 -0
  72. package/dist/commands/get-plugin.d.ts +13 -0
  73. package/dist/commands/get-plugin.d.ts.map +1 -0
  74. package/dist/commands/get-plugin.js +51 -0
  75. package/dist/commands/instantiate-template.d.ts +20 -0
  76. package/dist/commands/instantiate-template.d.ts.map +1 -0
  77. package/dist/commands/instantiate-template.js +274 -0
  78. package/dist/commands/list-pipelines.d.ts +20 -0
  79. package/dist/commands/list-pipelines.d.ts.map +1 -0
  80. package/dist/commands/list-pipelines.js +99 -0
  81. package/dist/commands/list-plugins.d.ts +20 -0
  82. package/dist/commands/list-plugins.d.ts.map +1 -0
  83. package/dist/commands/list-plugins.js +92 -0
  84. package/dist/commands/login.d.ts +21 -0
  85. package/dist/commands/login.d.ts.map +1 -0
  86. package/dist/commands/login.js +174 -0
  87. package/dist/commands/new-plugin.d.ts +12 -0
  88. package/dist/commands/new-plugin.d.ts.map +1 -0
  89. package/dist/commands/new-plugin.js +129 -0
  90. package/dist/commands/org-export.d.ts +25 -0
  91. package/dist/commands/org-export.d.ts.map +1 -0
  92. package/dist/commands/org-export.js +100 -0
  93. package/dist/commands/provision.d.ts +122 -0
  94. package/dist/commands/provision.d.ts.map +1 -0
  95. package/dist/commands/provision.js +867 -0
  96. package/dist/commands/redrive-events.d.ts +24 -0
  97. package/dist/commands/redrive-events.d.ts.map +1 -0
  98. package/dist/commands/redrive-events.js +127 -0
  99. package/dist/commands/register.d.ts +38 -0
  100. package/dist/commands/register.d.ts.map +1 -0
  101. package/dist/commands/register.js +160 -0
  102. package/dist/commands/setup-events.d.ts +15 -0
  103. package/dist/commands/setup-events.d.ts.map +1 -0
  104. package/dist/commands/setup-events.js +168 -0
  105. package/dist/commands/status.d.ts +11 -0
  106. package/dist/commands/status.d.ts.map +1 -0
  107. package/dist/commands/status.js +81 -0
  108. package/dist/commands/store-token.d.ts +26 -0
  109. package/dist/commands/store-token.d.ts.map +1 -0
  110. package/dist/commands/store-token.js +305 -0
  111. package/dist/commands/synth.d.ts +21 -0
  112. package/dist/commands/synth.d.ts.map +1 -0
  113. package/dist/commands/synth.js +158 -0
  114. package/dist/commands/upload-plugin.d.ts +21 -0
  115. package/dist/commands/upload-plugin.d.ts.map +1 -0
  116. package/dist/commands/upload-plugin.js +275 -0
  117. package/dist/commands/validate-plugin.d.ts +12 -0
  118. package/dist/commands/validate-plugin.d.ts.map +1 -0
  119. package/dist/commands/validate-plugin.js +175 -0
  120. package/dist/commands/validate-templates.d.ts +11 -0
  121. package/dist/commands/validate-templates.d.ts.map +1 -0
  122. package/dist/commands/validate-templates.js +116 -0
  123. package/dist/commands/version.d.ts +12 -0
  124. package/dist/commands/version.d.ts.map +1 -0
  125. package/dist/commands/version.js +216 -0
  126. package/dist/config/cli.constants.d.ts +116 -0
  127. package/dist/config/cli.constants.d.ts.map +1 -0
  128. package/dist/config/cli.constants.js +194 -0
  129. package/dist/config.yml +94 -0
  130. package/dist/lambda/token-renew-handler.d.ts +2 -0
  131. package/dist/lambda/token-renew-handler.d.ts.map +1 -0
  132. package/dist/lambda/token-renew-handler.js +125 -0
  133. package/dist/templates/events-stack.json +174 -0
  134. package/dist/templates/token-renew-stack.json +122 -0
  135. package/dist/types/config.d.ts +53 -0
  136. package/dist/types/config.d.ts.map +1 -0
  137. package/dist/types/config.js +4 -0
  138. package/dist/types/error.d.ts +61 -0
  139. package/dist/types/error.d.ts.map +1 -0
  140. package/dist/types/error.js +35 -0
  141. package/dist/types/index.d.ts +9 -0
  142. package/dist/types/index.d.ts.map +1 -0
  143. package/dist/types/index.js +11 -0
  144. package/dist/types/pipeline-template.d.ts +48 -0
  145. package/dist/types/pipeline-template.d.ts.map +1 -0
  146. package/dist/types/pipeline-template.js +4 -0
  147. package/dist/types/pipeline.d.ts +121 -0
  148. package/dist/types/pipeline.d.ts.map +1 -0
  149. package/dist/types/pipeline.js +4 -0
  150. package/dist/types/plugin.d.ts +135 -0
  151. package/dist/types/plugin.d.ts.map +1 -0
  152. package/dist/types/plugin.js +4 -0
  153. package/dist/utils/api-client.d.ts +26 -0
  154. package/dist/utils/api-client.d.ts.map +1 -0
  155. package/dist/utils/api-client.js +151 -0
  156. package/dist/utils/audit-log.d.ts +8 -0
  157. package/dist/utils/audit-log.d.ts.map +1 -0
  158. package/dist/utils/audit-log.js +57 -0
  159. package/dist/utils/auth-guard.d.ts +20 -0
  160. package/dist/utils/auth-guard.d.ts.map +1 -0
  161. package/dist/utils/auth-guard.js +22 -0
  162. package/dist/utils/auth-utils.d.ts +68 -0
  163. package/dist/utils/auth-utils.d.ts.map +1 -0
  164. package/dist/utils/auth-utils.js +77 -0
  165. package/dist/utils/aws-env.d.ts +21 -0
  166. package/dist/utils/aws-env.d.ts.map +1 -0
  167. package/dist/utils/aws-env.js +34 -0
  168. package/dist/utils/aws-secrets.d.ts +48 -0
  169. package/dist/utils/aws-secrets.d.ts.map +1 -0
  170. package/dist/utils/aws-secrets.js +115 -0
  171. package/dist/utils/banner.d.ts +19 -0
  172. package/dist/utils/banner.d.ts.map +1 -0
  173. package/dist/utils/banner.js +52 -0
  174. package/dist/utils/cdk-utils.d.ts +74 -0
  175. package/dist/utils/cdk-utils.d.ts.map +1 -0
  176. package/dist/utils/cdk-utils.js +152 -0
  177. package/dist/utils/command-utils.d.ts +75 -0
  178. package/dist/utils/command-utils.d.ts.map +1 -0
  179. package/dist/utils/command-utils.js +155 -0
  180. package/dist/utils/config-loader.d.ts +33 -0
  181. package/dist/utils/config-loader.d.ts.map +1 -0
  182. package/dist/utils/config-loader.js +154 -0
  183. package/dist/utils/cron.d.ts +28 -0
  184. package/dist/utils/cron.d.ts.map +1 -0
  185. package/dist/utils/cron.js +119 -0
  186. package/dist/utils/deploy-runner.d.ts +38 -0
  187. package/dist/utils/deploy-runner.d.ts.map +1 -0
  188. package/dist/utils/deploy-runner.js +112 -0
  189. package/dist/utils/error-handler.d.ts +29 -0
  190. package/dist/utils/error-handler.d.ts.map +1 -0
  191. package/dist/utils/error-handler.js +302 -0
  192. package/dist/utils/list-command-utils.d.ts +23 -0
  193. package/dist/utils/list-command-utils.d.ts.map +1 -0
  194. package/dist/utils/list-command-utils.js +57 -0
  195. package/dist/utils/output-utils.d.ts +40 -0
  196. package/dist/utils/output-utils.d.ts.map +1 -0
  197. package/dist/utils/output-utils.js +250 -0
  198. package/dist/utils/pipeline-config.d.ts +33 -0
  199. package/dist/utils/pipeline-config.d.ts.map +1 -0
  200. package/dist/utils/pipeline-config.js +55 -0
  201. package/dist/utils/platform-secret.d.ts +27 -0
  202. package/dist/utils/platform-secret.d.ts.map +1 -0
  203. package/dist/utils/platform-secret.js +92 -0
  204. package/dist/utils/plugin-resolver.d.ts +17 -0
  205. package/dist/utils/plugin-resolver.d.ts.map +1 -0
  206. package/dist/utils/plugin-resolver.js +101 -0
  207. package/dist/utils/preflight.d.ts +26 -0
  208. package/dist/utils/preflight.d.ts.map +1 -0
  209. package/dist/utils/preflight.js +59 -0
  210. package/dist/utils/rate-limiter.d.ts +15 -0
  211. package/dist/utils/rate-limiter.d.ts.map +1 -0
  212. package/dist/utils/rate-limiter.js +164 -0
  213. package/dist/utils/registry.d.ts +86 -0
  214. package/dist/utils/registry.d.ts.map +1 -0
  215. package/dist/utils/registry.js +140 -0
  216. package/dist/utils/response-utils.d.ts +21 -0
  217. package/dist/utils/response-utils.d.ts.map +1 -0
  218. package/dist/utils/response-utils.js +70 -0
  219. package/dist/utils/tls.d.ts +52 -0
  220. package/dist/utils/tls.d.ts.map +1 -0
  221. package/dist/utils/tls.js +88 -0
  222. package/package.json +181 -0
@@ -0,0 +1,109 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Post-deploy health verification. A CloudFormation CREATE_COMPLETE (or a
5
+ * finished setup.sh) does NOT mean the app is serving — the ALB targets stay
6
+ * unhealthy until tasks/pods come up. The real done-signal is the platform's
7
+ * `/health` + `/ready` endpoints, so the executor polls them with backoff.
8
+ */
9
+ import { spawn } from 'child_process';
10
+ import axios from 'axios';
11
+ import { httpsAgentForUrl } from '../utils/tls.js';
12
+ /**
13
+ * Derive the URL the platform should be reachable at. Local/minikube front the
14
+ * stack on localhost:8443; EC2/EKS use the deploy domain. Returns null when
15
+ * it can't be determined (caller surfaces a "verify manually" note).
16
+ */
17
+ export function deriveHealthUrl(target, params) {
18
+ if (target === 'docker' || target === 'minikube')
19
+ return 'https://localhost:8443';
20
+ const domain = params.domain;
21
+ return typeof domain === 'string' && domain ? `https://${domain}` : null;
22
+ }
23
+ async function probe(url) {
24
+ try {
25
+ // Skip cert verification only for local/self-signed hosts (docker/minikube);
26
+ // a real ec2/eks domain presents a valid ACM cert and IS verified.
27
+ const res = await axios.get(url, { timeout: 5000, httpsAgent: httpsAgentForUrl(url), validateStatus: () => true });
28
+ return res.status >= 200 && res.status < 300;
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }
34
+ const delay = (ms) => new Promise((r) => setTimeout(r, ms));
35
+ /**
36
+ * Poll `<url>/health` then `<url>/ready` until both pass or the timeout elapses.
37
+ * Non-fatal by design: a timeout returns `healthy: false` with guidance, never throws.
38
+ */
39
+ export async function waitHealthy(url, opts = {}) {
40
+ const timeoutMs = opts.timeoutMs ?? 300_000; // 5 min — services come up async
41
+ const intervalMs = opts.intervalMs ?? 10_000;
42
+ // Once /health is up, only wait this much longer for /ready before proceeding.
43
+ const readyGraceMs = opts.readyGraceMs ?? 90_000; // 90s covers normal warmup
44
+ const deadline = Date.now() + timeoutMs;
45
+ // Wait for /health, then give /ready a BOUNDED grace window. /health flips first
46
+ // (the process is up); /ready also requires every backend dependency to be up.
47
+ // We prefer /ready (post-install register hits a not-yet-ready platform → 502),
48
+ // but if a dependency is DOWN (e.g. a crash-looping service) /ready never flips —
49
+ // so we must not block the full timeout on it. Once /health is up we wait at most
50
+ // `readyGraceMs` more, then proceed with a warning (register only needs the
51
+ // platform service, which /health already confirms is up).
52
+ let healthSeenAt = 0;
53
+ while (Date.now() < deadline) {
54
+ if (await probe(`${url}/health`)) {
55
+ if (healthSeenAt === 0)
56
+ healthSeenAt = Date.now();
57
+ if (await probe(`${url}/ready`)) {
58
+ return { url, healthy: true, ready: true, detail: 'health + ready OK' };
59
+ }
60
+ const leftMs = readyGraceMs - (Date.now() - healthSeenAt);
61
+ if (leftMs <= 0) {
62
+ return {
63
+ url,
64
+ healthy: true,
65
+ ready: false,
66
+ detail: `health OK, but /ready didn't pass within ${Math.round(readyGraceMs / 1000)}s — a backend service is likely down (check \`docker compose ps\` / its logs). Continuing; routes for that service may 502 until it's healthy.`,
67
+ };
68
+ }
69
+ opts.onTick?.(`Health OK — waiting up to ${Math.ceil(leftMs / 1000)}s for ${url}/ready (dependencies warming up) …`);
70
+ }
71
+ else {
72
+ opts.onTick?.(`Waiting for ${url}/health …`);
73
+ }
74
+ await delay(intervalMs);
75
+ }
76
+ // Overall timeout. If /health came up but /ready never did, proceed (non-fatal).
77
+ return healthSeenAt > 0
78
+ ? { url, healthy: true, ready: false, detail: 'health OK but /ready not reached — the platform is still warming up; post-install steps (register) may need a re-run' }
79
+ : { url, healthy: false, ready: false, detail: `not reachable within ${Math.round(timeoutMs / 1000)}s — check the stack / DNS / health logs` };
80
+ }
81
+ /**
82
+ * Minikube only: the gateway (https://localhost:8443) is reached through a
83
+ * `kubectl port-forward svc/nginx` that setup.sh backgrounds — which can die or
84
+ * fail to bind (e.g. a busy port) while the pods stay healthy, leaving the gateway
85
+ * unreachable so the health poll just times out. Before polling, probe the gateway;
86
+ * if it's down, (re)start the forward DETACHED so it outlives this CLI, then give
87
+ * it a moment to bind. Best-effort: never throws; on no-kubectl it logs the manual
88
+ * command. (setup.sh now forwards 8443 only, so a busy 8080 can't take it down.)
89
+ */
90
+ export async function ensureMinikubeGateway(url, opts = {}) {
91
+ const ns = opts.ns ?? 'pipeline-builder';
92
+ const port = opts.port ?? 8443;
93
+ if (await probe(`${url}/health`))
94
+ return; // forward already up — nothing to do
95
+ opts.onInfo?.(`Gateway unreachable — (re)starting the nginx port-forward (svc/nginx ${port}:${port}, ns ${ns}) …`);
96
+ // A missing kubectl surfaces as an async 'error' event (ENOENT), NOT a synchronous
97
+ // throw — a try/catch would miss it and the unhandled event would crash the CLI. Attach
98
+ // an 'error' listener so this stays best-effort (logs the manual command, never throws).
99
+ const child = spawn('kubectl', ['port-forward', '-n', ns, 'svc/nginx', `${port}:${port}`], {
100
+ detached: true,
101
+ stdio: 'ignore',
102
+ });
103
+ child.on('error', () => {
104
+ opts.onInfo?.(`Couldn't start it (is kubectl on PATH?). Start it manually: kubectl port-forward -n ${ns} svc/nginx ${port}:${port}`);
105
+ });
106
+ child.unref(); // detached + unref → survives this CLI so the user keeps the gateway
107
+ await delay(2000); // let it bind before the caller polls
108
+ }
109
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVhbHRoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FnZW50L2hlYWx0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN0QyxPQUFPLEtBQUssTUFBTSxPQUFPLENBQUM7QUFFMUIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFjbkQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUMsTUFBZ0IsRUFBRSxNQUErQjtJQUMvRSxJQUFJLE1BQU0sS0FBSyxRQUFRLElBQUksTUFBTSxLQUFLLFVBQVU7UUFBRSxPQUFPLHdCQUF3QixDQUFDO0lBQ2xGLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDN0IsT0FBTyxPQUFPLE1BQU0sS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxXQUFXLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFDM0UsQ0FBQztBQUVELEtBQUssVUFBVSxLQUFLLENBQUMsR0FBVztJQUM5QixJQUFJLENBQUM7UUFDSCw2RUFBNkU7UUFDN0UsbUVBQW1FO1FBQ25FLE1BQU0sR0FBRyxHQUFHLE1BQU0sS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsRUFBRSxjQUFjLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUNuSCxPQUFPLEdBQUcsQ0FBQyxNQUFNLElBQUksR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDO0lBQy9DLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7QUFDSCxDQUFDO0FBRUQsTUFBTSxLQUFLLEdBQUcsQ0FBQyxFQUFVLEVBQUUsRUFBRSxDQUFDLElBQUksT0FBTyxDQUFPLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFFMUU7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxXQUFXLENBQy9CLEdBQVcsRUFDWCxJQUFJLEdBQXVHLEVBQUU7SUFFN0csTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsSUFBSSxPQUFPLENBQUMsQ0FBQyxpQ0FBaUM7SUFDOUUsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFVBQVUsSUFBSSxNQUFNLENBQUM7SUFDN0MsK0VBQStFO0lBQy9FLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxZQUFZLElBQUksTUFBTSxDQUFDLENBQUMsMkJBQTJCO0lBQzdFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUM7SUFFeEMsaUZBQWlGO0lBQ2pGLCtFQUErRTtJQUMvRSxnRkFBZ0Y7SUFDaEYsa0ZBQWtGO0lBQ2xGLGtGQUFrRjtJQUNsRiw0RUFBNEU7SUFDNUUsMkRBQTJEO0lBQzNELElBQUksWUFBWSxHQUFHLENBQUMsQ0FBQztJQUNyQixPQUFPLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxRQUFRLEVBQUUsQ0FBQztRQUM3QixJQUFJLE1BQU0sS0FBSyxDQUFDLEdBQUcsR0FBRyxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQ2pDLElBQUksWUFBWSxLQUFLLENBQUM7Z0JBQUUsWUFBWSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNsRCxJQUFJLE1BQU0sS0FBSyxDQUFDLEdBQUcsR0FBRyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUNoQyxPQUFPLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsbUJBQW1CLEVBQUUsQ0FBQztZQUMxRSxDQUFDO1lBQ0QsTUFBTSxNQUFNLEdBQUcsWUFBWSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFlBQVksQ0FBQyxDQUFDO1lBQzFELElBQUksTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUNoQixPQUFPO29CQUNMLEdBQUc7b0JBQ0gsT0FBTyxFQUFFLElBQUk7b0JBQ2IsS0FBSyxFQUFFLEtBQUs7b0JBQ1osTUFBTSxFQUFFLDRDQUE0QyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsZ0pBQWdKO2lCQUNwTyxDQUFDO1lBQ0osQ0FBQztZQUNELElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLFNBQVMsR0FBRyxvQ0FBb0MsQ0FBQyxDQUFDO1FBQ3ZILENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLGVBQWUsR0FBRyxXQUFXLENBQUMsQ0FBQztRQUMvQyxDQUFDO1FBQ0QsTUFBTSxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUNELGlGQUFpRjtJQUNqRixPQUFPLFlBQVksR0FBRyxDQUFDO1FBQ3JCLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLHNIQUFzSCxFQUFFO1FBQ3RLLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLHdCQUF3QixJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMseUNBQXlDLEVBQUUsQ0FBQztBQUNuSixDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLHFCQUFxQixDQUN6QyxHQUFXLEVBQ1gsSUFBSSxHQUFtRSxFQUFFO0lBRXpFLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxFQUFFLElBQUksa0JBQWtCLENBQUM7SUFDekMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUM7SUFDL0IsSUFBSSxNQUFNLEtBQUssQ0FBQyxHQUFHLEdBQUcsU0FBUyxDQUFDO1FBQUUsT0FBTyxDQUFDLHFDQUFxQztJQUMvRSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsd0VBQXdFLElBQUksSUFBSSxJQUFJLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNuSCxtRkFBbUY7SUFDbkYsd0ZBQXdGO0lBQ3hGLHlGQUF5RjtJQUN6RixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUMsY0FBYyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsV0FBVyxFQUFFLEdBQUcsSUFBSSxJQUFJLElBQUksRUFBRSxDQUFDLEVBQUU7UUFDekYsUUFBUSxFQUFFLElBQUk7UUFDZCxLQUFLLEVBQUUsUUFBUTtLQUNoQixDQUFDLENBQUM7SUFDSCxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUU7UUFDckIsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLHVGQUF1RixFQUFFLGNBQWMsSUFBSSxJQUFJLElBQUksRUFBRSxDQUFDLENBQUM7SUFDdkksQ0FBQyxDQUFDLENBQUM7SUFDSCxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxxRUFBcUU7SUFDcEYsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxzQ0FBc0M7QUFDM0QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIFBvc3QtZGVwbG95IGhlYWx0aCB2ZXJpZmljYXRpb24uIEEgQ2xvdWRGb3JtYXRpb24gQ1JFQVRFX0NPTVBMRVRFIChvciBhXG4gKiBmaW5pc2hlZCBzZXR1cC5zaCkgZG9lcyBOT1QgbWVhbiB0aGUgYXBwIGlzIHNlcnZpbmcg4oCUIHRoZSBBTEIgdGFyZ2V0cyBzdGF5XG4gKiB1bmhlYWx0aHkgdW50aWwgdGFza3MvcG9kcyBjb21lIHVwLiBUaGUgcmVhbCBkb25lLXNpZ25hbCBpcyB0aGUgcGxhdGZvcm0nc1xuICogYC9oZWFsdGhgICsgYC9yZWFkeWAgZW5kcG9pbnRzLCBzbyB0aGUgZXhlY3V0b3IgcG9sbHMgdGhlbSB3aXRoIGJhY2tvZmYuXG4gKi9cblxuaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCBheGlvcyBmcm9tICdheGlvcyc7XG5pbXBvcnQgdHlwZSB7IFRhcmdldElkIH0gZnJvbSAnLi90YXJnZXRzLmpzJztcbmltcG9ydCB7IGh0dHBzQWdlbnRGb3JVcmwgfSBmcm9tICcuLi91dGlscy90bHMuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEhlYWx0aFJlc3VsdCB7XG4gIHJlYWRvbmx5IHVybDogc3RyaW5nO1xuICByZWFkb25seSBoZWFsdGh5OiBib29sZWFuO1xuICAvKipcbiAgICogVHJ1ZSBvbmx5IHdoZW4gQk9USCAvaGVhbHRoIGFuZCAvcmVhZHkgcGFzc2VkLiBEaXN0aW5ndWlzaGVzIGEgZnVsbHktcmVhZHlcbiAgICogcGxhdGZvcm0gZnJvbSB0aGUgZGVncmFkZWQgXCJoZWFsdGggT0sgYnV0IC9yZWFkeSBuZXZlciBjYW1lLCBwcm9jZWVkaW5nIGFueXdheVwiXG4gICAqIHN0YXRlIOKAlCBib3RoIGhhdmUgaGVhbHRoeTp0cnVlLCBzbyBjYWxsZXJzIHNob3VsZCBzdHlsZSBzdWNjZXNzIG9uIGByZWFkeWAuXG4gICAqL1xuICByZWFkb25seSByZWFkeTogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZGV0YWlsOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRGVyaXZlIHRoZSBVUkwgdGhlIHBsYXRmb3JtIHNob3VsZCBiZSByZWFjaGFibGUgYXQuIExvY2FsL21pbmlrdWJlIGZyb250IHRoZVxuICogc3RhY2sgb24gbG9jYWxob3N0Ojg0NDM7IEVDMi9FS1MgdXNlIHRoZSBkZXBsb3kgZG9tYWluLiBSZXR1cm5zIG51bGwgd2hlblxuICogaXQgY2FuJ3QgYmUgZGV0ZXJtaW5lZCAoY2FsbGVyIHN1cmZhY2VzIGEgXCJ2ZXJpZnkgbWFudWFsbHlcIiBub3RlKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlcml2ZUhlYWx0aFVybCh0YXJnZXQ6IFRhcmdldElkLCBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICh0YXJnZXQgPT09ICdkb2NrZXInIHx8IHRhcmdldCA9PT0gJ21pbmlrdWJlJykgcmV0dXJuICdodHRwczovL2xvY2FsaG9zdDo4NDQzJztcbiAgY29uc3QgZG9tYWluID0gcGFyYW1zLmRvbWFpbjtcbiAgcmV0dXJuIHR5cGVvZiBkb21haW4gPT09ICdzdHJpbmcnICYmIGRvbWFpbiA/IGBodHRwczovLyR7ZG9tYWlufWAgOiBudWxsO1xufVxuXG5hc3luYyBmdW5jdGlvbiBwcm9iZSh1cmw6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICB0cnkge1xuICAgIC8vIFNraXAgY2VydCB2ZXJpZmljYXRpb24gb25seSBmb3IgbG9jYWwvc2VsZi1zaWduZWQgaG9zdHMgKGRvY2tlci9taW5pa3ViZSk7XG4gICAgLy8gYSByZWFsIGVjMi9la3MgZG9tYWluIHByZXNlbnRzIGEgdmFsaWQgQUNNIGNlcnQgYW5kIElTIHZlcmlmaWVkLlxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGF4aW9zLmdldCh1cmwsIHsgdGltZW91dDogNTAwMCwgaHR0cHNBZ2VudDogaHR0cHNBZ2VudEZvclVybCh1cmwpLCB2YWxpZGF0ZVN0YXR1czogKCkgPT4gdHJ1ZSB9KTtcbiAgICByZXR1cm4gcmVzLnN0YXR1cyA+PSAyMDAgJiYgcmVzLnN0YXR1cyA8IDMwMDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbmNvbnN0IGRlbGF5ID0gKG1zOiBudW1iZXIpID0+IG5ldyBQcm9taXNlPHZvaWQ+KChyKSA9PiBzZXRUaW1lb3V0KHIsIG1zKSk7XG5cbi8qKlxuICogUG9sbCBgPHVybD4vaGVhbHRoYCB0aGVuIGA8dXJsPi9yZWFkeWAgdW50aWwgYm90aCBwYXNzIG9yIHRoZSB0aW1lb3V0IGVsYXBzZXMuXG4gKiBOb24tZmF0YWwgYnkgZGVzaWduOiBhIHRpbWVvdXQgcmV0dXJucyBgaGVhbHRoeTogZmFsc2VgIHdpdGggZ3VpZGFuY2UsIG5ldmVyIHRocm93cy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdhaXRIZWFsdGh5KFxuICB1cmw6IHN0cmluZyxcbiAgb3B0czogeyB0aW1lb3V0TXM/OiBudW1iZXI7IGludGVydmFsTXM/OiBudW1iZXI7IHJlYWR5R3JhY2VNcz86IG51bWJlcjsgb25UaWNrPzogKG1zZzogc3RyaW5nKSA9PiB2b2lkIH0gPSB7fSxcbik6IFByb21pc2U8SGVhbHRoUmVzdWx0PiB7XG4gIGNvbnN0IHRpbWVvdXRNcyA9IG9wdHMudGltZW91dE1zID8/IDMwMF8wMDA7IC8vIDUgbWluIOKAlCBzZXJ2aWNlcyBjb21lIHVwIGFzeW5jXG4gIGNvbnN0IGludGVydmFsTXMgPSBvcHRzLmludGVydmFsTXMgPz8gMTBfMDAwO1xuICAvLyBPbmNlIC9oZWFsdGggaXMgdXAsIG9ubHkgd2FpdCB0aGlzIG11Y2ggbG9uZ2VyIGZvciAvcmVhZHkgYmVmb3JlIHByb2NlZWRpbmcuXG4gIGNvbnN0IHJlYWR5R3JhY2VNcyA9IG9wdHMucmVhZHlHcmFjZU1zID8/IDkwXzAwMDsgLy8gOTBzIGNvdmVycyBub3JtYWwgd2FybXVwXG4gIGNvbnN0IGRlYWRsaW5lID0gRGF0ZS5ub3coKSArIHRpbWVvdXRNcztcblxuICAvLyBXYWl0IGZvciAvaGVhbHRoLCB0aGVuIGdpdmUgL3JlYWR5IGEgQk9VTkRFRCBncmFjZSB3aW5kb3cuIC9oZWFsdGggZmxpcHMgZmlyc3RcbiAgLy8gKHRoZSBwcm9jZXNzIGlzIHVwKTsgL3JlYWR5IGFsc28gcmVxdWlyZXMgZXZlcnkgYmFja2VuZCBkZXBlbmRlbmN5IHRvIGJlIHVwLlxuICAvLyBXZSBwcmVmZXIgL3JlYWR5IChwb3N0LWluc3RhbGwgcmVnaXN0ZXIgaGl0cyBhIG5vdC15ZXQtcmVhZHkgcGxhdGZvcm0g4oaSIDUwMiksXG4gIC8vIGJ1dCBpZiBhIGRlcGVuZGVuY3kgaXMgRE9XTiAoZS5nLiBhIGNyYXNoLWxvb3Bpbmcgc2VydmljZSkgL3JlYWR5IG5ldmVyIGZsaXBzIOKAlFxuICAvLyBzbyB3ZSBtdXN0IG5vdCBibG9jayB0aGUgZnVsbCB0aW1lb3V0IG9uIGl0LiBPbmNlIC9oZWFsdGggaXMgdXAgd2Ugd2FpdCBhdCBtb3N0XG4gIC8vIGByZWFkeUdyYWNlTXNgIG1vcmUsIHRoZW4gcHJvY2VlZCB3aXRoIGEgd2FybmluZyAocmVnaXN0ZXIgb25seSBuZWVkcyB0aGVcbiAgLy8gcGxhdGZvcm0gc2VydmljZSwgd2hpY2ggL2hlYWx0aCBhbHJlYWR5IGNvbmZpcm1zIGlzIHVwKS5cbiAgbGV0IGhlYWx0aFNlZW5BdCA9IDA7XG4gIHdoaWxlIChEYXRlLm5vdygpIDwgZGVhZGxpbmUpIHtcbiAgICBpZiAoYXdhaXQgcHJvYmUoYCR7dXJsfS9oZWFsdGhgKSkge1xuICAgICAgaWYgKGhlYWx0aFNlZW5BdCA9PT0gMCkgaGVhbHRoU2VlbkF0ID0gRGF0ZS5ub3coKTtcbiAgICAgIGlmIChhd2FpdCBwcm9iZShgJHt1cmx9L3JlYWR5YCkpIHtcbiAgICAgICAgcmV0dXJuIHsgdXJsLCBoZWFsdGh5OiB0cnVlLCByZWFkeTogdHJ1ZSwgZGV0YWlsOiAnaGVhbHRoICsgcmVhZHkgT0snIH07XG4gICAgICB9XG4gICAgICBjb25zdCBsZWZ0TXMgPSByZWFkeUdyYWNlTXMgLSAoRGF0ZS5ub3coKSAtIGhlYWx0aFNlZW5BdCk7XG4gICAgICBpZiAobGVmdE1zIDw9IDApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB1cmwsXG4gICAgICAgICAgaGVhbHRoeTogdHJ1ZSxcbiAgICAgICAgICByZWFkeTogZmFsc2UsXG4gICAgICAgICAgZGV0YWlsOiBgaGVhbHRoIE9LLCBidXQgL3JlYWR5IGRpZG4ndCBwYXNzIHdpdGhpbiAke01hdGgucm91bmQocmVhZHlHcmFjZU1zIC8gMTAwMCl9cyDigJQgYSBiYWNrZW5kIHNlcnZpY2UgaXMgbGlrZWx5IGRvd24gKGNoZWNrIFxcYGRvY2tlciBjb21wb3NlIHBzXFxgIC8gaXRzIGxvZ3MpLiBDb250aW51aW5nOyByb3V0ZXMgZm9yIHRoYXQgc2VydmljZSBtYXkgNTAyIHVudGlsIGl0J3MgaGVhbHRoeS5gLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgb3B0cy5vblRpY2s/LihgSGVhbHRoIE9LIOKAlCB3YWl0aW5nIHVwIHRvICR7TWF0aC5jZWlsKGxlZnRNcyAvIDEwMDApfXMgZm9yICR7dXJsfS9yZWFkeSAoZGVwZW5kZW5jaWVzIHdhcm1pbmcgdXApIOKApmApO1xuICAgIH0gZWxzZSB7XG4gICAgICBvcHRzLm9uVGljaz8uKGBXYWl0aW5nIGZvciAke3VybH0vaGVhbHRoIOKApmApO1xuICAgIH1cbiAgICBhd2FpdCBkZWxheShpbnRlcnZhbE1zKTtcbiAgfVxuICAvLyBPdmVyYWxsIHRpbWVvdXQuIElmIC9oZWFsdGggY2FtZSB1cCBidXQgL3JlYWR5IG5ldmVyIGRpZCwgcHJvY2VlZCAobm9uLWZhdGFsKS5cbiAgcmV0dXJuIGhlYWx0aFNlZW5BdCA+IDBcbiAgICA/IHsgdXJsLCBoZWFsdGh5OiB0cnVlLCByZWFkeTogZmFsc2UsIGRldGFpbDogJ2hlYWx0aCBPSyBidXQgL3JlYWR5IG5vdCByZWFjaGVkIOKAlCB0aGUgcGxhdGZvcm0gaXMgc3RpbGwgd2FybWluZyB1cDsgcG9zdC1pbnN0YWxsIHN0ZXBzIChyZWdpc3RlcikgbWF5IG5lZWQgYSByZS1ydW4nIH1cbiAgICA6IHsgdXJsLCBoZWFsdGh5OiBmYWxzZSwgcmVhZHk6IGZhbHNlLCBkZXRhaWw6IGBub3QgcmVhY2hhYmxlIHdpdGhpbiAke01hdGgucm91bmQodGltZW91dE1zIC8gMTAwMCl9cyDigJQgY2hlY2sgdGhlIHN0YWNrIC8gRE5TIC8gaGVhbHRoIGxvZ3NgIH07XG59XG5cbi8qKlxuICogTWluaWt1YmUgb25seTogdGhlIGdhdGV3YXkgKGh0dHBzOi8vbG9jYWxob3N0Ojg0NDMpIGlzIHJlYWNoZWQgdGhyb3VnaCBhXG4gKiBga3ViZWN0bCBwb3J0LWZvcndhcmQgc3ZjL25naW54YCB0aGF0IHNldHVwLnNoIGJhY2tncm91bmRzIOKAlCB3aGljaCBjYW4gZGllIG9yXG4gKiBmYWlsIHRvIGJpbmQgKGUuZy4gYSBidXN5IHBvcnQpIHdoaWxlIHRoZSBwb2RzIHN0YXkgaGVhbHRoeSwgbGVhdmluZyB0aGUgZ2F0ZXdheVxuICogdW5yZWFjaGFibGUgc28gdGhlIGhlYWx0aCBwb2xsIGp1c3QgdGltZXMgb3V0LiBCZWZvcmUgcG9sbGluZywgcHJvYmUgdGhlIGdhdGV3YXk7XG4gKiBpZiBpdCdzIGRvd24sIChyZSlzdGFydCB0aGUgZm9yd2FyZCBERVRBQ0hFRCBzbyBpdCBvdXRsaXZlcyB0aGlzIENMSSwgdGhlbiBnaXZlXG4gKiBpdCBhIG1vbWVudCB0byBiaW5kLiBCZXN0LWVmZm9ydDogbmV2ZXIgdGhyb3dzOyBvbiBuby1rdWJlY3RsIGl0IGxvZ3MgdGhlIG1hbnVhbFxuICogY29tbWFuZC4gKHNldHVwLnNoIG5vdyBmb3J3YXJkcyA4NDQzIG9ubHksIHNvIGEgYnVzeSA4MDgwIGNhbid0IHRha2UgaXQgZG93bi4pXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbnN1cmVNaW5pa3ViZUdhdGV3YXkoXG4gIHVybDogc3RyaW5nLFxuICBvcHRzOiB7IG5zPzogc3RyaW5nOyBwb3J0PzogbnVtYmVyOyBvbkluZm8/OiAobXNnOiBzdHJpbmcpID0+IHZvaWQgfSA9IHt9LFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IG5zID0gb3B0cy5ucyA/PyAncGlwZWxpbmUtYnVpbGRlcic7XG4gIGNvbnN0IHBvcnQgPSBvcHRzLnBvcnQgPz8gODQ0MztcbiAgaWYgKGF3YWl0IHByb2JlKGAke3VybH0vaGVhbHRoYCkpIHJldHVybjsgLy8gZm9yd2FyZCBhbHJlYWR5IHVwIOKAlCBub3RoaW5nIHRvIGRvXG4gIG9wdHMub25JbmZvPy4oYEdhdGV3YXkgdW5yZWFjaGFibGUg4oCUIChyZSlzdGFydGluZyB0aGUgbmdpbnggcG9ydC1mb3J3YXJkIChzdmMvbmdpbnggJHtwb3J0fToke3BvcnR9LCBucyAke25zfSkg4oCmYCk7XG4gIC8vIEEgbWlzc2luZyBrdWJlY3RsIHN1cmZhY2VzIGFzIGFuIGFzeW5jICdlcnJvcicgZXZlbnQgKEVOT0VOVCksIE5PVCBhIHN5bmNocm9ub3VzXG4gIC8vIHRocm93IOKAlCBhIHRyeS9jYXRjaCB3b3VsZCBtaXNzIGl0IGFuZCB0aGUgdW5oYW5kbGVkIGV2ZW50IHdvdWxkIGNyYXNoIHRoZSBDTEkuIEF0dGFjaFxuICAvLyBhbiAnZXJyb3InIGxpc3RlbmVyIHNvIHRoaXMgc3RheXMgYmVzdC1lZmZvcnQgKGxvZ3MgdGhlIG1hbnVhbCBjb21tYW5kLCBuZXZlciB0aHJvd3MpLlxuICBjb25zdCBjaGlsZCA9IHNwYXduKCdrdWJlY3RsJywgWydwb3J0LWZvcndhcmQnLCAnLW4nLCBucywgJ3N2Yy9uZ2lueCcsIGAke3BvcnR9OiR7cG9ydH1gXSwge1xuICAgIGRldGFjaGVkOiB0cnVlLFxuICAgIHN0ZGlvOiAnaWdub3JlJyxcbiAgfSk7XG4gIGNoaWxkLm9uKCdlcnJvcicsICgpID0+IHtcbiAgICBvcHRzLm9uSW5mbz8uKGBDb3VsZG4ndCBzdGFydCBpdCAoaXMga3ViZWN0bCBvbiBQQVRIPykuIFN0YXJ0IGl0IG1hbnVhbGx5OiBrdWJlY3RsIHBvcnQtZm9yd2FyZCAtbiAke25zfSBzdmMvbmdpbnggJHtwb3J0fToke3BvcnR9YCk7XG4gIH0pO1xuICBjaGlsZC51bnJlZigpOyAvLyBkZXRhY2hlZCArIHVucmVmIOKGkiBzdXJ2aXZlcyB0aGlzIENMSSBzbyB0aGUgdXNlciBrZWVwcyB0aGUgZ2F0ZXdheVxuICBhd2FpdCBkZWxheSgyMDAwKTsgLy8gbGV0IGl0IGJpbmQgYmVmb3JlIHRoZSBjYWxsZXIgcG9sbHNcbn1cbiJdfQ==
@@ -0,0 +1,26 @@
1
+ import type { TargetId, TargetSpec } from './targets.js';
2
+ export interface HostPort {
3
+ readonly service: string;
4
+ readonly port: number;
5
+ }
6
+ export interface PortCheck extends HostPort {
7
+ readonly available: boolean;
8
+ }
9
+ /**
10
+ * Derive the host ports a target binds from its ACTUAL (cloned) deploy source, so the
11
+ * list can't drift from the deploy. local → docker-compose.yml; minikube → setup.sh;
12
+ * ec2/eks → none (CloudFormation binds nothing on the operator's machine). Needs
13
+ * the deploy files on disk (run post-clone); falls back to the target's static
14
+ * `hostPorts` if the source is missing/unreadable.
15
+ */
16
+ export declare function discoverHostPorts(target: TargetId, cwd: string, spec: TargetSpec): HostPort[];
17
+ /** Probe each host port; returns one PortCheck per port (probed in parallel). */
18
+ export declare function checkHostPorts(ports: readonly HostPort[]): Promise<PortCheck[]>;
19
+ /**
20
+ * Is the target's OWN deploy stack already running? (local docker-compose only.) Used
21
+ * so the port pre-flight doesn't block an idempotent RE-RUN: if the "taken" ports are
22
+ * held by the stack you already have up, `docker compose up` just no-ops them — that's
23
+ * not a conflict. Read-only `docker compose ps`; false on any error / non-local target.
24
+ */
25
+ export declare function stackRunning(target: TargetId, cwd: string, spec: TargetSpec): boolean;
26
+ //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/agent/ports.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAU,SAAQ,QAAQ;IACzC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAqED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,QAAQ,EAAE,CAQ7F;AAED,iFAAiF;AACjF,wBAAsB,cAAc,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAErF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAWrF"}
@@ -0,0 +1,132 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Host-port pre-flight. Local (Docker-published) and minikube (kubectl port-forward)
5
+ * deploys bind fixed ports on the operator's machine; if one is already taken, the
6
+ * container/forward fails to bind — and for the gateway that surfaces as a silent
7
+ * "/health never reachable" hang. We probe the ports before deploying so provision
8
+ * can stop with a clear summary instead of failing mid-deploy.
9
+ *
10
+ * The port list is DERIVED from each target's actual (cloned) deploy source — so it
11
+ * can't drift from the deploy: local from `docker-compose.yml`'s published ports,
12
+ * minikube from `setup.sh`'s kubectl port-forwards. ec2/eks deploy via
13
+ * CloudFormation and bind NOTHING on the operator's machine (only the remote ALB),
14
+ * so they yield no host ports. `targets.hostPorts` is only a fallback when the source
15
+ * file can't be read.
16
+ */
17
+ import { execSync } from 'child_process';
18
+ import { readFileSync } from 'fs';
19
+ import net from 'net';
20
+ import path from 'path';
21
+ import { parse as parseYaml } from 'yaml';
22
+ /** Try to bind <host>:<port>; true if free, false on EADDRINUSE/EACCES. */
23
+ function canBind(port, host) {
24
+ return new Promise((resolve) => {
25
+ const srv = net.createServer();
26
+ srv.once('error', () => resolve(false));
27
+ srv.once('listening', () => srv.close(() => resolve(true)));
28
+ srv.listen(port, host);
29
+ });
30
+ }
31
+ /**
32
+ * Is `port` free? Probes BOTH `0.0.0.0` (where Docker publishes `0.0.0.0:<port>`)
33
+ * AND `127.0.0.1` (where kubectl port-forward / Docker Desktop bind), requiring both.
34
+ *
35
+ * This is NOT redundant — do not "simplify" to one bind. Verified empirically on
36
+ * macOS (Node sets SO_REUSEADDR): neither interface subsumes the other. With a holder
37
+ * on 127.0.0.1, binding 0.0.0.0 still SUCCEEDS (a single 0.0.0.0 probe would MISS a
38
+ * port-forward squatting the gateway on loopback); with a holder on 0.0.0.0, binding
39
+ * 127.0.0.1 still succeeds. Only checking both reliably catches the real conflict (a
40
+ * port-forward on 8443, AirPlay on 5000, …). For a pre-flight, a false positive
41
+ * (over-cautious) beats a false negative (miss it → the deploy fails mid-way).
42
+ */
43
+ async function isPortFree(port) {
44
+ const [allIfaces, loopback] = await Promise.all([canBind(port, '0.0.0.0'), canBind(port, '127.0.0.1')]);
45
+ return allIfaces && loopback;
46
+ }
47
+ /**
48
+ * Host (left-side) ports a docker-compose.yml publishes, keyed by service. Handles
49
+ * the short forms "HOST:CONTAINER", "HOST:CONTAINER/proto", "IP:HOST:CONTAINER" and
50
+ * the long form `{ published, target }`. Bare "CONTAINER" (random host port) is
51
+ * skipped — it can't conflict on a fixed port.
52
+ */
53
+ function composeHostPorts(file) {
54
+ const doc = parseYaml(readFileSync(file, 'utf8'));
55
+ const out = [];
56
+ for (const [service, def] of Object.entries(doc?.services ?? {})) {
57
+ for (const entry of def?.ports ?? []) {
58
+ let host;
59
+ if (typeof entry === 'string') {
60
+ const parts = (entry.split('/')[0] ?? '').split(':'); // strip /proto, split ip:host:container
61
+ if (parts.length >= 2)
62
+ host = Number(parts[parts.length - 2] ?? ''); // host is second-from-last
63
+ }
64
+ else if (entry && typeof entry === 'object' && 'published' in entry) {
65
+ host = Number(entry.published);
66
+ }
67
+ if (host !== undefined && Number.isInteger(host))
68
+ out.push({ service, port: host });
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ /** Host ports from minikube setup.sh's `port_forward "Name" svc "HOST:CONTAINER …"` calls. */
74
+ function forwardHostPorts(file) {
75
+ const out = [];
76
+ const re = /port_forward\s+"([^"]+)"\s+\S+\s+"([^"]+)"/g;
77
+ const text = readFileSync(file, 'utf8');
78
+ let m;
79
+ while ((m = re.exec(text)) !== null) {
80
+ const service = m[1] ?? '';
81
+ for (const pair of (m[2] ?? '').trim().split(/\s+/)) {
82
+ const host = Number(pair.split(':')[0] ?? '');
83
+ if (Number.isInteger(host))
84
+ out.push({ service, port: host });
85
+ }
86
+ }
87
+ return out;
88
+ }
89
+ /**
90
+ * Derive the host ports a target binds from its ACTUAL (cloned) deploy source, so the
91
+ * list can't drift from the deploy. local → docker-compose.yml; minikube → setup.sh;
92
+ * ec2/eks → none (CloudFormation binds nothing on the operator's machine). Needs
93
+ * the deploy files on disk (run post-clone); falls back to the target's static
94
+ * `hostPorts` if the source is missing/unreadable.
95
+ */
96
+ export function discoverHostPorts(target, cwd, spec) {
97
+ try {
98
+ if (target === 'docker')
99
+ return composeHostPorts(path.join(cwd, spec.dir, 'docker-compose.yml'));
100
+ if (target === 'minikube')
101
+ return forwardHostPorts(path.join(cwd, spec.dir, 'bin', 'setup.sh'));
102
+ return []; // ec2/eks deploy remotely — nothing binds locally
103
+ }
104
+ catch {
105
+ return spec.hostPorts.map((p) => ({ ...p }));
106
+ }
107
+ }
108
+ /** Probe each host port; returns one PortCheck per port (probed in parallel). */
109
+ export async function checkHostPorts(ports) {
110
+ return Promise.all(ports.map(async ({ service, port }) => ({ service, port, available: await isPortFree(port) })));
111
+ }
112
+ /**
113
+ * Is the target's OWN deploy stack already running? (local docker-compose only.) Used
114
+ * so the port pre-flight doesn't block an idempotent RE-RUN: if the "taken" ports are
115
+ * held by the stack you already have up, `docker compose up` just no-ops them — that's
116
+ * not a conflict. Read-only `docker compose ps`; false on any error / non-local target.
117
+ */
118
+ export function stackRunning(target, cwd, spec) {
119
+ if (target !== 'docker')
120
+ return false;
121
+ try {
122
+ const compose = path.join(cwd, spec.dir, 'docker-compose.yml');
123
+ const out = execSync(`docker compose -f '${compose}' ps -q`, { stdio: ['ignore', 'pipe', 'ignore'], timeout: 10000 })
124
+ .toString()
125
+ .trim();
126
+ return out.length > 0;
127
+ }
128
+ catch {
129
+ return false;
130
+ }
131
+ }
132
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9ydHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWdlbnQvcG9ydHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7OztHQWFHO0FBRUgsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ2xDLE9BQU8sR0FBRyxNQUFNLEtBQUssQ0FBQztBQUN0QixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxFQUFFLEtBQUssSUFBSSxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFZMUMsMkVBQTJFO0FBQzNFLFNBQVMsT0FBTyxDQUFDLElBQVksRUFBRSxJQUFZO0lBQ3pDLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtRQUM3QixNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDL0IsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDeEMsR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzVELEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3pCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsS0FBSyxVQUFVLFVBQVUsQ0FBQyxJQUFZO0lBQ3BDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsT0FB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SUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1FBQy9ELE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxzQkFBc0IsT0FBTyxTQUFTLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLFFBQVEsQ0FBQyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQzthQUNsSCxRQUFRLEVBQUU7YUFDVixJQUFJLEVBQUUsQ0FBQztRQUNWLE9BQU8sR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDeEIsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBIb3N0LXBvcnQgcHJlLWZsaWdodC4gTG9jYWwgKERvY2tlci1wdWJsaXNoZWQpIGFuZCBtaW5pa3ViZSAoa3ViZWN0bCBwb3J0LWZvcndhcmQpXG4gKiBkZXBsb3lzIGJpbmQgZml4ZWQgcG9ydHMgb24gdGhlIG9wZXJhdG9yJ3MgbWFjaGluZTsgaWYgb25lIGlzIGFscmVhZHkgdGFrZW4sIHRoZVxuICogY29udGFpbmVyL2ZvcndhcmQgZmFpbHMgdG8gYmluZCDigJQgYW5kIGZvciB0aGUgZ2F0ZXdheSB0aGF0IHN1cmZhY2VzIGFzIGEgc2lsZW50XG4gKiBcIi9oZWFsdGggbmV2ZXIgcmVhY2hhYmxlXCIgaGFuZy4gV2UgcHJvYmUgdGhlIHBvcnRzIGJlZm9yZSBkZXBsb3lpbmcgc28gcHJvdmlzaW9uXG4gKiBjYW4gc3RvcCB3aXRoIGEgY2xlYXIgc3VtbWFyeSBpbnN0ZWFkIG9mIGZhaWxpbmcgbWlkLWRlcGxveS5cbiAqXG4gKiBUaGUgcG9ydCBsaXN0IGlzIERFUklWRUQgZnJvbSBlYWNoIHRhcmdldCdzIGFjdHVhbCAoY2xvbmVkKSBkZXBsb3kgc291cmNlIOKAlCBzbyBpdFxuICogY2FuJ3QgZHJpZnQgZnJvbSB0aGUgZGVwbG95OiBsb2NhbCBmcm9tIGBkb2NrZXItY29tcG9zZS55bWxgJ3MgcHVibGlzaGVkIHBvcnRzLFxuICogbWluaWt1YmUgZnJvbSBgc2V0dXAuc2hgJ3Mga3ViZWN0bCBwb3J0LWZvcndhcmRzLiBlYzIvZWtzIGRlcGxveSB2aWFcbiAqIENsb3VkRm9ybWF0aW9uIGFuZCBiaW5kIE5PVEhJTkcgb24gdGhlIG9wZXJhdG9yJ3MgbWFjaGluZSAob25seSB0aGUgcmVtb3RlIEFMQiksXG4gKiBzbyB0aGV5IHlpZWxkIG5vIGhvc3QgcG9ydHMuIGB0YXJnZXRzLmhvc3RQb3J0c2AgaXMgb25seSBhIGZhbGxiYWNrIHdoZW4gdGhlIHNvdXJjZVxuICogZmlsZSBjYW4ndCBiZSByZWFkLlxuICovXG5cbmltcG9ydCB7IGV4ZWNTeW5jIH0gZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgbmV0IGZyb20gJ25ldCc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IHBhcnNlIGFzIHBhcnNlWWFtbCB9IGZyb20gJ3lhbWwnO1xuaW1wb3J0IHR5cGUgeyBUYXJnZXRJZCwgVGFyZ2V0U3BlYyB9IGZyb20gJy4vdGFyZ2V0cy5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgSG9zdFBvcnQge1xuICByZWFkb25seSBzZXJ2aWNlOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHBvcnQ6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQb3J0Q2hlY2sgZXh0ZW5kcyBIb3N0UG9ydCB7XG4gIHJlYWRvbmx5IGF2YWlsYWJsZTogYm9vbGVhbjtcbn1cblxuLyoqIFRyeSB0byBiaW5kIDxob3N0Pjo8cG9ydD47IHRydWUgaWYgZnJlZSwgZmFsc2Ugb24gRUFERFJJTlVTRS9FQUNDRVMuICovXG5mdW5jdGlvbiBjYW5CaW5kKHBvcnQ6IG51bWJlciwgaG9zdDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgIGNvbnN0IHNydiA9IG5ldC5jcmVhdGVTZXJ2ZXIoKTtcbiAgICBzcnYub25jZSgnZXJyb3InLCAoKSA9PiByZXNvbHZlKGZhbHNlKSk7XG4gICAgc3J2Lm9uY2UoJ2xpc3RlbmluZycsICgpID0+IHNydi5jbG9zZSgoKSA9PiByZXNvbHZlKHRydWUpKSk7XG4gICAgc3J2Lmxpc3Rlbihwb3J0LCBob3N0KTtcbiAgfSk7XG59XG5cbi8qKlxuICogSXMgYHBvcnRgIGZyZWU/IFByb2JlcyBCT1RIIGAwLjAuMC4wYCAod2hlcmUgRG9ja2VyIHB1Ymxpc2hlcyBgMC4wLjAuMDo8cG9ydD5gKVxuICogQU5EIGAxMjcuMC4wLjFgICh3aGVyZSBrdWJlY3RsIHBvcnQtZm9yd2FyZCAvIERvY2tlciBEZXNrdG9wIGJpbmQpLCByZXF1aXJpbmcgYm90aC5cbiAqXG4gKiBUaGlzIGlzIE5PVCByZWR1bmRhbnQg4oCUIGRvIG5vdCBcInNpbXBsaWZ5XCIgdG8gb25lIGJpbmQuIFZlcmlmaWVkIGVtcGlyaWNhbGx5IG9uXG4gKiBtYWNPUyAoTm9kZSBzZXRzIFNPX1JFVVNFQUREUik6IG5laXRoZXIgaW50ZXJmYWNlIHN1YnN1bWVzIHRoZSBvdGhlci4gV2l0aCBhIGhvbGRlclxuICogb24gMTI3LjAuMC4xLCBiaW5kaW5nIDAuMC4wLjAgc3RpbGwgU1VDQ0VFRFMgKGEgc2luZ2xlIDAuMC4wLjAgcHJvYmUgd291bGQgTUlTUyBhXG4gKiBwb3J0LWZvcndhcmQgc3F1YXR0aW5nIHRoZSBnYXRld2F5IG9uIGxvb3BiYWNrKTsgd2l0aCBhIGhvbGRlciBvbiAwLjAuMC4wLCBiaW5kaW5nXG4gKiAxMjcuMC4wLjEgc3RpbGwgc3VjY2VlZHMuIE9ubHkgY2hlY2tpbmcgYm90aCByZWxpYWJseSBjYXRjaGVzIHRoZSByZWFsIGNvbmZsaWN0IChhXG4gKiBwb3J0LWZvcndhcmQgb24gODQ0MywgQWlyUGxheSBvbiA1MDAwLCDigKYpLiBGb3IgYSBwcmUtZmxpZ2h0LCBhIGZhbHNlIHBvc2l0aXZlXG4gKiAob3Zlci1jYXV0aW91cykgYmVhdHMgYSBmYWxzZSBuZWdhdGl2ZSAobWlzcyBpdCDihpIgdGhlIGRlcGxveSBmYWlscyBtaWQtd2F5KS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gaXNQb3J0RnJlZShwb3J0OiBudW1iZXIpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3QgW2FsbElmYWNlcywgbG9vcGJhY2tdID0gYXdhaXQgUHJvbWlzZS5hbGwoW2NhbkJpbmQocG9ydCwgJzAuMC4wLjAnKSwgY2FuQmluZChwb3J0LCAnMTI3LjAuMC4xJyldKTtcbiAgcmV0dXJuIGFsbElmYWNlcyAmJiBsb29wYmFjaztcbn1cblxuLyoqXG4gKiBIb3N0IChsZWZ0LXNpZGUpIHBvcnRzIGEgZG9ja2VyLWNvbXBvc2UueW1sIHB1Ymxpc2hlcywga2V5ZWQgYnkgc2VydmljZS4gSGFuZGxlc1xuICogdGhlIHNob3J0IGZvcm1zIFwiSE9TVDpDT05UQUlORVJcIiwgXCJIT1NUOkNPTlRBSU5FUi9wcm90b1wiLCBcIklQOkhPU1Q6Q09OVEFJTkVSXCIgYW5kXG4gKiB0aGUgbG9uZyBmb3JtIGB7IHB1Ymxpc2hlZCwgdGFyZ2V0IH1gLiBCYXJlIFwiQ09OVEFJTkVSXCIgKHJhbmRvbSBob3N0IHBvcnQpIGlzXG4gKiBza2lwcGVkIOKAlCBpdCBjYW4ndCBjb25mbGljdCBvbiBhIGZpeGVkIHBvcnQuXG4gKi9cbmZ1bmN0aW9uIGNvbXBvc2VIb3N0UG9ydHMoZmlsZTogc3RyaW5nKTogSG9zdFBvcnRbXSB7XG4gIGNvbnN0IGRvYyA9IHBhcnNlWWFtbChyZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKSkgYXMgeyBzZXJ2aWNlcz86IFJlY29yZDxzdHJpbmcsIHsgcG9ydHM/OiB1bmtub3duW10gfT4gfTtcbiAgY29uc3Qgb3V0OiBIb3N0UG9ydFtdID0gW107XG4gIGZvciAoY29uc3QgW3NlcnZpY2UsIGRlZl0gb2YgT2JqZWN0LmVudHJpZXMoZG9jPy5zZXJ2aWNlcyA/PyB7fSkpIHtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGRlZj8ucG9ydHMgPz8gW10pIHtcbiAgICAgIGxldCBob3N0OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gICAgICBpZiAodHlwZW9mIGVudHJ5ID09PSAnc3RyaW5nJykge1xuICAgICAgICBjb25zdCBwYXJ0cyA9IChlbnRyeS5zcGxpdCgnLycpWzBdID8/ICcnKS5zcGxpdCgnOicpOyAvLyBzdHJpcCAvcHJvdG8sIHNwbGl0IGlwOmhvc3Q6Y29udGFpbmVyXG4gICAgICAgIGlmIChwYXJ0cy5sZW5ndGggPj0gMikgaG9zdCA9IE51bWJlcihwYXJ0c1twYXJ0cy5sZW5ndGggLSAyXSA/PyAnJyk7IC8vIGhvc3QgaXMgc2Vjb25kLWZyb20tbGFzdFxuICAgICAgfSBlbHNlIGlmIChlbnRyeSAmJiB0eXBlb2YgZW50cnkgPT09ICdvYmplY3QnICYmICdwdWJsaXNoZWQnIGluIGVudHJ5KSB7XG4gICAgICAgIGhvc3QgPSBOdW1iZXIoKGVudHJ5IGFzIHsgcHVibGlzaGVkOiB1bmtub3duIH0pLnB1Ymxpc2hlZCk7XG4gICAgICB9XG4gICAgICBpZiAoaG9zdCAhPT0gdW5kZWZpbmVkICYmIE51bWJlci5pc0ludGVnZXIoaG9zdCkpIG91dC5wdXNoKHsgc2VydmljZSwgcG9ydDogaG9zdCB9KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIEhvc3QgcG9ydHMgZnJvbSBtaW5pa3ViZSBzZXR1cC5zaCdzIGBwb3J0X2ZvcndhcmQgXCJOYW1lXCIgc3ZjIFwiSE9TVDpDT05UQUlORVIg4oCmXCJgIGNhbGxzLiAqL1xuZnVuY3Rpb24gZm9yd2FyZEhvc3RQb3J0cyhmaWxlOiBzdHJpbmcpOiBIb3N0UG9ydFtdIHtcbiAgY29uc3Qgb3V0OiBIb3N0UG9ydFtdID0gW107XG4gIGNvbnN0IHJlID0gL3BvcnRfZm9yd2FyZFxccytcIihbXlwiXSspXCJcXHMrXFxTK1xccytcIihbXlwiXSspXCIvZztcbiAgY29uc3QgdGV4dCA9IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpO1xuICBsZXQgbTogUmVnRXhwRXhlY0FycmF5IHwgbnVsbDtcbiAgd2hpbGUgKChtID0gcmUuZXhlYyh0ZXh0KSkgIT09IG51bGwpIHtcbiAgICBjb25zdCBzZXJ2aWNlID0gbVsxXSA/PyAnJztcbiAgICBmb3IgKGNvbnN0IHBhaXIgb2YgKG1bMl0gPz8gJycpLnRyaW0oKS5zcGxpdCgvXFxzKy8pKSB7XG4gICAgICBjb25zdCBob3N0ID0gTnVtYmVyKHBhaXIuc3BsaXQoJzonKVswXSA/PyAnJyk7XG4gICAgICBpZiAoTnVtYmVyLmlzSW50ZWdlcihob3N0KSkgb3V0LnB1c2goeyBzZXJ2aWNlLCBwb3J0OiBob3N0IH0pO1xuICAgIH1cbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vKipcbiAqIERlcml2ZSB0aGUgaG9zdCBwb3J0cyBhIHRhcmdldCBiaW5kcyBmcm9tIGl0cyBBQ1RVQUwgKGNsb25lZCkgZGVwbG95IHNvdXJjZSwgc28gdGhlXG4gKiBsaXN0IGNhbid0IGRyaWZ0IGZyb20gdGhlIGRlcGxveS4gbG9jYWwg4oaSIGRvY2tlci1jb21wb3NlLnltbDsgbWluaWt1YmUg4oaSIHNldHVwLnNoO1xuICogZWMyL2VrcyDihpIgbm9uZSAoQ2xvdWRGb3JtYXRpb24gYmluZHMgbm90aGluZyBvbiB0aGUgb3BlcmF0b3IncyBtYWNoaW5lKS4gTmVlZHNcbiAqIHRoZSBkZXBsb3kgZmlsZXMgb24gZGlzayAocnVuIHBvc3QtY2xvbmUpOyBmYWxscyBiYWNrIHRvIHRoZSB0YXJnZXQncyBzdGF0aWNcbiAqIGBob3N0UG9ydHNgIGlmIHRoZSBzb3VyY2UgaXMgbWlzc2luZy91bnJlYWRhYmxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGlzY292ZXJIb3N0UG9ydHModGFyZ2V0OiBUYXJnZXRJZCwgY3dkOiBzdHJpbmcsIHNwZWM6IFRhcmdldFNwZWMpOiBIb3N0UG9ydFtdIHtcbiAgdHJ5IHtcbiAgICBpZiAodGFyZ2V0ID09PSAnZG9ja2VyJykgcmV0dXJuIGNvbXBvc2VIb3N0UG9ydHMocGF0aC5qb2luKGN3ZCwgc3BlYy5kaXIsICdkb2NrZXItY29tcG9zZS55bWwnKSk7XG4gICAgaWYgKHRhcmdldCA9PT0gJ21pbmlrdWJlJykgcmV0dXJuIGZvcndhcmRIb3N0UG9ydHMocGF0aC5qb2luKGN3ZCwgc3BlYy5kaXIsICdiaW4nLCAnc2V0dXAuc2gnKSk7XG4gICAgcmV0dXJuIFtdOyAvLyBlYzIvZWtzIGRlcGxveSByZW1vdGVseSDigJQgbm90aGluZyBiaW5kcyBsb2NhbGx5XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBzcGVjLmhvc3RQb3J0cy5tYXAoKHApID0+ICh7IC4uLnAgfSkpO1xuICB9XG59XG5cbi8qKiBQcm9iZSBlYWNoIGhvc3QgcG9ydDsgcmV0dXJucyBvbmUgUG9ydENoZWNrIHBlciBwb3J0IChwcm9iZWQgaW4gcGFyYWxsZWwpLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNoZWNrSG9zdFBvcnRzKHBvcnRzOiByZWFkb25seSBIb3N0UG9ydFtdKTogUHJvbWlzZTxQb3J0Q2hlY2tbXT4ge1xuICByZXR1cm4gUHJvbWlzZS5hbGwocG9ydHMubWFwKGFzeW5jICh7IHNlcnZpY2UsIHBvcnQgfSkgPT4gKHsgc2VydmljZSwgcG9ydCwgYXZhaWxhYmxlOiBhd2FpdCBpc1BvcnRGcmVlKHBvcnQpIH0pKSk7XG59XG5cbi8qKlxuICogSXMgdGhlIHRhcmdldCdzIE9XTiBkZXBsb3kgc3RhY2sgYWxyZWFkeSBydW5uaW5nPyAobG9jYWwgZG9ja2VyLWNvbXBvc2Ugb25seS4pIFVzZWRcbiAqIHNvIHRoZSBwb3J0IHByZS1mbGlnaHQgZG9lc24ndCBibG9jayBhbiBpZGVtcG90ZW50IFJFLVJVTjogaWYgdGhlIFwidGFrZW5cIiBwb3J0cyBhcmVcbiAqIGhlbGQgYnkgdGhlIHN0YWNrIHlvdSBhbHJlYWR5IGhhdmUgdXAsIGBkb2NrZXIgY29tcG9zZSB1cGAganVzdCBuby1vcHMgdGhlbSDigJQgdGhhdCdzXG4gKiBub3QgYSBjb25mbGljdC4gUmVhZC1vbmx5IGBkb2NrZXIgY29tcG9zZSBwc2A7IGZhbHNlIG9uIGFueSBlcnJvciAvIG5vbi1sb2NhbCB0YXJnZXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdGFja1J1bm5pbmcodGFyZ2V0OiBUYXJnZXRJZCwgY3dkOiBzdHJpbmcsIHNwZWM6IFRhcmdldFNwZWMpOiBib29sZWFuIHtcbiAgaWYgKHRhcmdldCAhPT0gJ2RvY2tlcicpIHJldHVybiBmYWxzZTtcbiAgdHJ5IHtcbiAgICBjb25zdCBjb21wb3NlID0gcGF0aC5qb2luKGN3ZCwgc3BlYy5kaXIsICdkb2NrZXItY29tcG9zZS55bWwnKTtcbiAgICBjb25zdCBvdXQgPSBleGVjU3luYyhgZG9ja2VyIGNvbXBvc2UgLWYgJyR7Y29tcG9zZX0nIHBzIC1xYCwgeyBzdGRpbzogWydpZ25vcmUnLCAncGlwZScsICdpZ25vcmUnXSwgdGltZW91dDogMTAwMDAgfSlcbiAgICAgIC50b1N0cmluZygpXG4gICAgICAudHJpbSgpO1xuICAgIHJldHVybiBvdXQubGVuZ3RoID4gMDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Post-install steps.
3
+ *
4
+ * After the platform is deployed + health-checked, provision runs an ordered set
5
+ * of post-install steps: **register** (the admin, via `init-platform.sh`, driven
6
+ * non-interactively by env — which also performs any opt-in plugin/compliance/
7
+ * sample loads), then an optional **smoke-test**, **events** (AWS), and any
8
+ * operator **--post-step** commands. Pure, deterministic assembly here — provision
9
+ * runs each via the same gated `runScript()` as the deploy.
10
+ */
11
+ import { type TargetId } from './targets.js';
12
+ export interface PostStep {
13
+ /** Stable id (`register` / `smoke-test` / `events`) or `custom-N`. */
14
+ readonly id: string;
15
+ /** Human label shown in the plan. */
16
+ readonly label: string;
17
+ /** The exact command to run. */
18
+ readonly command: string;
19
+ /** Non-secret env applied to the child for this step (e.g. LOAD_* for register). */
20
+ readonly env?: Readonly<Record<string, string>>;
21
+ }
22
+ /** A requested step that doesn't apply to the chosen target. */
23
+ export interface SkippedStep {
24
+ readonly id: string;
25
+ readonly reason: string;
26
+ }
27
+ export interface ResolvedPostSteps {
28
+ readonly steps: PostStep[];
29
+ readonly skipped: SkippedStep[];
30
+ }
31
+ export interface PostStepOptions {
32
+ readonly target: TargetId;
33
+ /** Base URL of the deployed platform (from deriveHealthUrl), or null. */
34
+ readonly url: string | null;
35
+ /** AWS region (ec2/eks), if provided. */
36
+ readonly region?: string;
37
+ /** Load-step ids enabled via `--with-*` (drive init-platform's LOAD_* envs + sparse paths). */
38
+ readonly enabledLoadIds: readonly string[];
39
+ /** `--build-bootstrap`: build the CodeBuild bootstrap image during register. */
40
+ readonly buildBootstrap: boolean;
41
+ /** False when `--no-init` — skips the register step entirely. */
42
+ readonly init: boolean;
43
+ /** True for `--init auto` (the default mode). On the AWS targets the deploy self-runs
44
+ * init-platform (ec2 on first boot, eks in setup.sh's final phase), so the register step is
45
+ * NOT surfaced here — it would duplicate that deploy-managed run. (minikube/local run init
46
+ * via provision, not a deploy-managed init.) */
47
+ readonly autoInit?: boolean;
48
+ readonly smokeTest: boolean;
49
+ /** `--with-events`: the AWS event-ingestion bundle (store-token → setup-events). */
50
+ readonly events: boolean;
51
+ /** Raw operator `--post-step` commands, in order. */
52
+ readonly steps: readonly string[];
53
+ }
54
+ /**
55
+ * Resolve the ordered post-install step list: register → smoke-test → events →
56
+ * custom. `register` carries the load + BUILD_BOOTSTRAP env so init-platform runs
57
+ * the enabled loads non-interactively. Requested-but-inapplicable steps land in
58
+ * `skipped` so the caller can warn rather than silently drop them.
59
+ */
60
+ export declare function resolvePostSteps(opts: PostStepOptions): ResolvedPostSteps;
61
+ //# sourceMappingURL=post-steps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-steps.d.ts","sourceRoot":"","sources":["../../src/agent/post-steps.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,WAAW,QAAQ;IACvB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,oFAAoF;IACpF,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD;AAED,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,yCAAyC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+FAA+F;IAC/F,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,gFAAgF;IAChF,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB;;;qDAGiD;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,oFAAoF;IACpF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AASD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,iBAAiB,CA0GzE"}
@@ -0,0 +1,131 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Post-install steps.
5
+ *
6
+ * After the platform is deployed + health-checked, provision runs an ordered set
7
+ * of post-install steps: **register** (the admin, via `init-platform.sh`, driven
8
+ * non-interactively by env — which also performs any opt-in plugin/compliance/
9
+ * sample loads), then an optional **smoke-test**, **events** (AWS), and any
10
+ * operator **--post-step** commands. Pure, deterministic assembly here — provision
11
+ * runs each via the same gated `runScript()` as the deploy.
12
+ */
13
+ import { LOAD_STEPS } from './targets.js';
14
+ /** Compute the non-interactive env that drives init-platform's prompts. */
15
+ function registerEnv(enabledLoadIds, buildBootstrap) {
16
+ const env = { BUILD_BOOTSTRAP: buildBootstrap ? 'y' : 'n' };
17
+ for (const step of LOAD_STEPS)
18
+ env[step.env] = enabledLoadIds.includes(step.id) ? 'y' : 'n';
19
+ return env;
20
+ }
21
+ /**
22
+ * Resolve the ordered post-install step list: register → smoke-test → events →
23
+ * custom. `register` carries the load + BUILD_BOOTSTRAP env so init-platform runs
24
+ * the enabled loads non-interactively. Requested-but-inapplicable steps land in
25
+ * `skipped` so the caller can warn rather than silently drop them.
26
+ */
27
+ export function resolvePostSteps(opts) {
28
+ const steps = [];
29
+ const skipped = [];
30
+ // `--init auto` (the default) on the AWS targets: the deploy runs init-platform itself —
31
+ // ec2 on the instance on first boot, eks in setup.sh's final phase — so DON'T add a register
32
+ // step here; it would duplicate the deploy-managed run. (minikube/local run init via provision.)
33
+ const autoInitManaged = opts.init && opts.autoInit === true && (opts.target === 'ec2' || opts.target === 'eks');
34
+ if (opts.init && !autoInitManaged) {
35
+ const enabled = LOAD_STEPS.filter((s) => opts.enabledLoadIds.includes(s.id)).map((s) => s.id);
36
+ const loads = enabled.length > 0 ? ` (+ ${enabled.join(', ')})` : '';
37
+ // Register is surfaced as a manual next-step on AWS (see runPostSteps). The command differs:
38
+ // - ec2: runs ON the box as the minikube user, where the in-VPC URL resolves → bake PLATFORM_BASE_URL.
39
+ // - eks: init-platform port-forwards to svc/nginx, so it runs from anywhere with kubectl access —
40
+ // do NOT bake PLATFORM_BASE_URL (that would force the public URL and wait on the ALB/DNS).
41
+ // - local/minikube: plain command (the URL is localhost).
42
+ const registerCommand = opts.target === 'ec2' && opts.url
43
+ ? `PLATFORM_BASE_URL=${opts.url} ./deploy/bin/init-platform.sh ec2`
44
+ : `./deploy/bin/init-platform.sh ${opts.target}`;
45
+ steps.push({
46
+ id: 'register',
47
+ label: `Register admin${loads}`,
48
+ command: registerCommand,
49
+ env: registerEnv(opts.enabledLoadIds, opts.buildBootstrap),
50
+ });
51
+ }
52
+ if (opts.smokeTest) {
53
+ if (opts.url) {
54
+ // -k: local/minikube front a self-signed cert; harmless against real-cert AWS URLs.
55
+ // Probe /health — the one route guaranteed to exist and serve unauthenticated
56
+ // through nginx (every /api/* route requires auth → 401; /api/version doesn't
57
+ // exist and would fall through to the SPA, making `curl -f` meaningless).
58
+ steps.push({
59
+ id: 'smoke-test',
60
+ label: 'Smoke test — gateway/API reachability',
61
+ command: `curl -fsSk ${opts.url}/health && echo 'smoke-test: API reachable'`,
62
+ });
63
+ }
64
+ else {
65
+ skipped.push({ id: 'smoke-test', reason: 'no platform URL to probe for this target' });
66
+ }
67
+ }
68
+ if (opts.events) {
69
+ if (opts.target === 'ec2' || opts.target === 'eks') {
70
+ // Event ingestion is a THREE-step bundle, in this order:
71
+ // 1. store-token — the full-privilege platform JWT (synth/deploy
72
+ // callbacks read it; --schedule auto-renews it).
73
+ // 2. store-token --scope reporting:ingest --schedule
74
+ // — a DISTINCT least-privilege token whose `scope`
75
+ // claim is exactly `reporting:ingest`. The ingest
76
+ // endpoint requires this scope and `hasScope` is a
77
+ // single-value equality check, so the platform
78
+ // token (no scope) can NEVER ingest — the Lambda
79
+ // must read this dedicated token. Stored at
80
+ // `.../reporting-ingest`. --schedule deploys its OWN
81
+ // renewal stack (named `-reporting-ingest`, distinct
82
+ // from the platform one) whose handler preserves the
83
+ // scope on re-mint, so it auto-renews and never lapses.
84
+ // See setup-events --scoped-ingest.
85
+ // 3. setup-events --scoped-ingest
86
+ // — deploys the EventBridge → SQS → Lambda and points
87
+ // the Lambda at the reporting-ingest secret from #2.
88
+ // WITHOUT --scoped-ingest the Lambda reads the
89
+ // platform secret and every ingest 403s
90
+ // ("Token must carry the 'reporting:ingest' scope").
91
+ // provision surfaces (does not auto-run) the bundle on AWS — it needs a
92
+ // registered, in-VPC platform.
93
+ const region = opts.region ? ` --region ${opts.region}` : '';
94
+ // Mirror the register branch's target rule: bake PLATFORM_BASE_URL only on
95
+ // ec2 (the in-VPC URL resolves on the box). On eks the public ALB/DNS isn't
96
+ // up yet, so baking it would point store-token/setup-events at an
97
+ // unresolvable host — the operator sets PLATFORM_BASE_URL when running the
98
+ // surfaced bundle, once the ALB is ready.
99
+ const env = opts.target === 'ec2' && opts.url ? { PLATFORM_BASE_URL: opts.url } : undefined;
100
+ steps.push({
101
+ id: 'store-token',
102
+ label: 'Store platform token in AWS Secrets Manager (+ daily auto-renewal)',
103
+ // --schedule: synth/deploy callbacks read this token, so install the
104
+ // renewal stack so it never lapses (store-token no longer deploys it by default).
105
+ command: `pipeline-manager infra store-token --schedule${region}`,
106
+ env,
107
+ });
108
+ steps.push({
109
+ id: 'store-token-ingest',
110
+ label: 'Store reporting-ingest (scoped) token in AWS Secrets Manager (+ auto-renewal)',
111
+ command: `pipeline-manager infra store-token --scope reporting:ingest --schedule${region}`,
112
+ env,
113
+ });
114
+ steps.push({
115
+ id: 'events',
116
+ label: 'EventBridge ingestion (setup-events, scoped-ingest)',
117
+ command: `pipeline-manager infra setup-events --scoped-ingest${region}`,
118
+ env,
119
+ });
120
+ }
121
+ else {
122
+ skipped.push({ id: 'events', reason: `not applicable to target '${opts.target}' (ec2/eks only)` });
123
+ }
124
+ }
125
+ opts.steps.forEach((command, i) => {
126
+ if (command.trim() !== '')
127
+ steps.push({ id: `custom-${i + 1}`, label: `Custom step ${i + 1}`, command });
128
+ });
129
+ return { steps, skipped };
130
+ }
131
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9zdC1zdGVwcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZ2VudC9wb3N0LXN0ZXBzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7OztHQVNHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBaUIsTUFBTSxjQUFjLENBQUM7QUFnRHpELDJFQUEyRTtBQUMzRSxTQUFTLFdBQVcsQ0FBQyxjQUFpQyxFQUFFLGNBQXVCO0lBQzdFLE1BQU0sR0FBRyxHQUEyQixFQUFFLGVBQWUsRUFBRSxjQUFjLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDcEYsS0FBSyxNQUFNLElBQUksSUFBSSxVQUFVO1FBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxjQUFjLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFDNUYsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsSUFBcUI7SUFDcEQsTUFBTSxLQUFLLEdBQWUsRUFBRSxDQUFDO0lBQzdCLE1BQU0sT0FBTyxHQUFrQixFQUFFLENBQUM7SUFFbEMseUZBQXlGO0lBQ3pGLDZGQUE2RjtJQUM3RixpR0FBaUc7SUFDakcsTUFBTSxlQUFlLEdBQ25CLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLFFBQVEsS0FBSyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLEtBQUssQ0FBQyxDQUFDO0lBQzFGLElBQUksSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ2xDLE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzlGLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ3JFLDZGQUE2RjtRQUM3Rix3R0FBd0c7UUFDeEcsbUdBQW1HO1FBQ25HLDhGQUE4RjtRQUM5RiwyREFBMkQ7UUFDM0QsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLE1BQU0sS0FBSyxLQUFLLElBQUksSUFBSSxDQUFDLEdBQUc7WUFDdkQsQ0FBQyxDQUFDLHFCQUFxQixJQUFJLENBQUMsR0FBRyxvQ0FBb0M7WUFDbkUsQ0FBQyxDQUFDLGlDQUFpQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDbkQsS0FBSyxDQUFDLElBQUksQ0FBQztZQUNULEVBQUUsRUFBRSxVQUFVO1lBQ2QsS0FBSyxFQUFFLGlCQUFpQixLQUFLLEVBQUU7WUFDL0IsT0FBTyxFQUFFLGVBQWU7WUFDeEIsR0FBRyxFQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjLENBQUM7U0FDM0QsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ25CLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2Isb0ZBQW9GO1lBQ3BGLDhFQUE4RTtZQUM5RSw4RUFBOEU7WUFDOUUsMEVBQTBFO1lBQzFFLEtBQUssQ0FBQyxJQUFJLENBQUM7Z0JBQ1QsRUFBRSxFQUFFLFlBQVk7Z0JBQ2hCLEtBQUssRUFBRSx1Q0FBdUM7Z0JBQzlDLE9BQU8sRUFBRSxjQUFjLElBQUksQ0FBQyxHQUFHLDZDQUE2QzthQUM3RSxDQUFDLENBQUM7UUFDTCxDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSwwQ0FBMEMsRUFBRSxDQUFDLENBQUM7UUFDekYsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNoQixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssS0FBSyxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssS0FBSyxFQUFFLENBQUM7WUFDbkQseURBQXlEO1lBQ3pELDRFQUE0RTtZQUM1RSw2RUFBNkU7WUFDN0UsdURBQXVEO1lBQ3ZELDZFQUE2RTtZQUM3RSw4RUFBOEU7WUFDOUUsK0VBQStFO1lBQy9FLDJFQUEyRTtZQUMzRSw2RUFBNkU7WUFDN0Usd0VBQXdFO1lBQ3hFLGlGQUFpRjtZQUNqRixpRkFBaUY7WUFDakYsaUZBQWlGO1lBQ2pGLG9GQUFvRjtZQUNwRixnRUFBZ0U7WUFDaEUsb0NBQW9DO1lBQ3BDLGdGQUFnRjtZQUNoRixpRkFBaUY7WUFDakYsMkVBQTJFO1lBQzNFLG9FQUFvRTtZQUNwRSxpRkFBaUY7WUFDakYsd0VBQXdFO1lBQ3hFLCtCQUErQjtZQUMvQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxhQUFhLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQzdELDJFQUEyRTtZQUMzRSw0RUFBNEU7WUFDNUUsa0VBQWtFO1lBQ2xFLDJFQUEyRTtZQUMzRSwwQ0FBMEM7WUFDMUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sS0FBSyxLQUFLLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxpQkFBaUIsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztZQUM1RixLQUFLLENBQUMsSUFBSSxDQUFDO2dCQUNULEVBQUUsRUFBRSxhQUFhO2dCQUNqQixLQUFLLEVBQUUsb0VBQW9FO2dCQUMzRSxxRUFBcUU7Z0JBQ3JFLGtGQUFrRjtnQkFDbEYsT0FBTyxFQUFFLGdEQUFnRCxNQUFNLEVBQUU7Z0JBQ2pFLEdBQUc7YUFDSixDQUFDLENBQUM7WUFDSCxLQUFLLENBQUMsSUFBSSxDQUFDO2dCQUNULEVBQUUsRUFBRSxvQkFBb0I7Z0JBQ3hCLEtBQUssRUFBRSwrRUFBK0U7Z0JBQ3RGLE9BQU8sRUFBRSx5RUFBeUUsTUFBTSxFQUFFO2dCQUMxRixHQUFHO2FBQ0osQ0FBQyxDQUFDO1lBQ0gsS0FBSyxDQUFDLElBQUksQ0FBQztnQkFDVCxFQUFFLEVBQUUsUUFBUTtnQkFDWixLQUFLLEVBQUUscURBQXFEO2dCQUM1RCxPQUFPLEVBQUUsc0RBQXNELE1BQU0sRUFBRTtnQkFDdkUsR0FBRzthQUNKLENBQUMsQ0FBQztRQUNMLENBQUM7YUFBTSxDQUFDO1lBQ04sT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLDZCQUE2QixJQUFJLENBQUMsTUFBTSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7UUFDckcsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNoQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsZUFBZSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUMzRyxDQUFDLENBQUMsQ0FBQztJQUVILE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7QUFDNUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIFBvc3QtaW5zdGFsbCBzdGVwcy5cbiAqXG4gKiBBZnRlciB0aGUgcGxhdGZvcm0gaXMgZGVwbG95ZWQgKyBoZWFsdGgtY2hlY2tlZCwgcHJvdmlzaW9uIHJ1bnMgYW4gb3JkZXJlZCBzZXRcbiAqIG9mIHBvc3QtaW5zdGFsbCBzdGVwczogKipyZWdpc3RlcioqICh0aGUgYWRtaW4sIHZpYSBgaW5pdC1wbGF0Zm9ybS5zaGAsIGRyaXZlblxuICogbm9uLWludGVyYWN0aXZlbHkgYnkgZW52IOKAlCB3aGljaCBhbHNvIHBlcmZvcm1zIGFueSBvcHQtaW4gcGx1Z2luL2NvbXBsaWFuY2UvXG4gKiBzYW1wbGUgbG9hZHMpLCB0aGVuIGFuIG9wdGlvbmFsICoqc21va2UtdGVzdCoqLCAqKmV2ZW50cyoqIChBV1MpLCBhbmQgYW55XG4gKiBvcGVyYXRvciAqKi0tcG9zdC1zdGVwKiogY29tbWFuZHMuIFB1cmUsIGRldGVybWluaXN0aWMgYXNzZW1ibHkgaGVyZSDigJQgcHJvdmlzaW9uXG4gKiBydW5zIGVhY2ggdmlhIHRoZSBzYW1lIGdhdGVkIGBydW5TY3JpcHQoKWAgYXMgdGhlIGRlcGxveS5cbiAqL1xuXG5pbXBvcnQgeyBMT0FEX1NURVBTLCB0eXBlIFRhcmdldElkIH0gZnJvbSAnLi90YXJnZXRzLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBQb3N0U3RlcCB7XG4gIC8qKiBTdGFibGUgaWQgKGByZWdpc3RlcmAgLyBgc21va2UtdGVzdGAgLyBgZXZlbnRzYCkgb3IgYGN1c3RvbS1OYC4gKi9cbiAgcmVhZG9ubHkgaWQ6IHN0cmluZztcbiAgLyoqIEh1bWFuIGxhYmVsIHNob3duIGluIHRoZSBwbGFuLiAqL1xuICByZWFkb25seSBsYWJlbDogc3RyaW5nO1xuICAvKiogVGhlIGV4YWN0IGNvbW1hbmQgdG8gcnVuLiAqL1xuICByZWFkb25seSBjb21tYW5kOiBzdHJpbmc7XG4gIC8qKiBOb24tc2VjcmV0IGVudiBhcHBsaWVkIHRvIHRoZSBjaGlsZCBmb3IgdGhpcyBzdGVwIChlLmcuIExPQURfKiBmb3IgcmVnaXN0ZXIpLiAqL1xuICByZWFkb25seSBlbnY/OiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+Pjtcbn1cblxuLyoqIEEgcmVxdWVzdGVkIHN0ZXAgdGhhdCBkb2Vzbid0IGFwcGx5IHRvIHRoZSBjaG9zZW4gdGFyZ2V0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBTa2lwcGVkU3RlcCB7XG4gIHJlYWRvbmx5IGlkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJlYXNvbjogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkUG9zdFN0ZXBzIHtcbiAgcmVhZG9ubHkgc3RlcHM6IFBvc3RTdGVwW107XG4gIHJlYWRvbmx5IHNraXBwZWQ6IFNraXBwZWRTdGVwW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUG9zdFN0ZXBPcHRpb25zIHtcbiAgcmVhZG9ubHkgdGFyZ2V0OiBUYXJnZXRJZDtcbiAgLyoqIEJhc2UgVVJMIG9mIHRoZSBkZXBsb3llZCBwbGF0Zm9ybSAoZnJvbSBkZXJpdmVIZWFsdGhVcmwpLCBvciBudWxsLiAqL1xuICByZWFkb25seSB1cmw6IHN0cmluZyB8IG51bGw7XG4gIC8qKiBBV1MgcmVnaW9uIChlYzIvZWtzKSwgaWYgcHJvdmlkZWQuICovXG4gIHJlYWRvbmx5IHJlZ2lvbj86IHN0cmluZztcbiAgLyoqIExvYWQtc3RlcCBpZHMgZW5hYmxlZCB2aWEgYC0td2l0aC0qYCAoZHJpdmUgaW5pdC1wbGF0Zm9ybSdzIExPQURfKiBlbnZzICsgc3BhcnNlIHBhdGhzKS4gKi9cbiAgcmVhZG9ubHkgZW5hYmxlZExvYWRJZHM6IHJlYWRvbmx5IHN0cmluZ1tdO1xuICAvKiogYC0tYnVpbGQtYm9vdHN0cmFwYDogYnVpbGQgdGhlIENvZGVCdWlsZCBib290c3RyYXAgaW1hZ2UgZHVyaW5nIHJlZ2lzdGVyLiAqL1xuICByZWFkb25seSBidWlsZEJvb3RzdHJhcDogYm9vbGVhbjtcbiAgLyoqIEZhbHNlIHdoZW4gYC0tbm8taW5pdGAg4oCUIHNraXBzIHRoZSByZWdpc3RlciBzdGVwIGVudGlyZWx5LiAqL1xuICByZWFkb25seSBpbml0OiBib29sZWFuO1xuICAvKiogVHJ1ZSBmb3IgYC0taW5pdCBhdXRvYCAodGhlIGRlZmF1bHQgbW9kZSkuIE9uIHRoZSBBV1MgdGFyZ2V0cyB0aGUgZGVwbG95IHNlbGYtcnVuc1xuICAgKiAgaW5pdC1wbGF0Zm9ybSAoZWMyIG9uIGZpcnN0IGJvb3QsIGVrcyBpbiBzZXR1cC5zaCdzIGZpbmFsIHBoYXNlKSwgc28gdGhlIHJlZ2lzdGVyIHN0ZXAgaXNcbiAgICogIE5PVCBzdXJmYWNlZCBoZXJlIOKAlCBpdCB3b3VsZCBkdXBsaWNhdGUgdGhhdCBkZXBsb3ktbWFuYWdlZCBydW4uIChtaW5pa3ViZS9sb2NhbCBydW4gaW5pdFxuICAgKiAgdmlhIHByb3Zpc2lvbiwgbm90IGEgZGVwbG95LW1hbmFnZWQgaW5pdC4pICovXG4gIHJlYWRvbmx5IGF1dG9Jbml0PzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgc21va2VUZXN0OiBib29sZWFuO1xuICAvKiogYC0td2l0aC1ldmVudHNgOiB0aGUgQVdTIGV2ZW50LWluZ2VzdGlvbiBidW5kbGUgKHN0b3JlLXRva2VuIOKGkiBzZXR1cC1ldmVudHMpLiAqL1xuICByZWFkb25seSBldmVudHM6IGJvb2xlYW47XG4gIC8qKiBSYXcgb3BlcmF0b3IgYC0tcG9zdC1zdGVwYCBjb21tYW5kcywgaW4gb3JkZXIuICovXG4gIHJlYWRvbmx5IHN0ZXBzOiByZWFkb25seSBzdHJpbmdbXTtcbn1cblxuLyoqIENvbXB1dGUgdGhlIG5vbi1pbnRlcmFjdGl2ZSBlbnYgdGhhdCBkcml2ZXMgaW5pdC1wbGF0Zm9ybSdzIHByb21wdHMuICovXG5mdW5jdGlvbiByZWdpc3RlckVudihlbmFibGVkTG9hZElkczogcmVhZG9ubHkgc3RyaW5nW10sIGJ1aWxkQm9vdHN0cmFwOiBib29sZWFuKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gIGNvbnN0IGVudjogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHsgQlVJTERfQk9PVFNUUkFQOiBidWlsZEJvb3RzdHJhcCA/ICd5JyA6ICduJyB9O1xuICBmb3IgKGNvbnN0IHN0ZXAgb2YgTE9BRF9TVEVQUykgZW52W3N0ZXAuZW52XSA9IGVuYWJsZWRMb2FkSWRzLmluY2x1ZGVzKHN0ZXAuaWQpID8gJ3knIDogJ24nO1xuICByZXR1cm4gZW52O1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIG9yZGVyZWQgcG9zdC1pbnN0YWxsIHN0ZXAgbGlzdDogcmVnaXN0ZXIg4oaSIHNtb2tlLXRlc3Qg4oaSIGV2ZW50cyDihpJcbiAqIGN1c3RvbS4gYHJlZ2lzdGVyYCBjYXJyaWVzIHRoZSBsb2FkICsgQlVJTERfQk9PVFNUUkFQIGVudiBzbyBpbml0LXBsYXRmb3JtIHJ1bnNcbiAqIHRoZSBlbmFibGVkIGxvYWRzIG5vbi1pbnRlcmFjdGl2ZWx5LiBSZXF1ZXN0ZWQtYnV0LWluYXBwbGljYWJsZSBzdGVwcyBsYW5kIGluXG4gKiBgc2tpcHBlZGAgc28gdGhlIGNhbGxlciBjYW4gd2FybiByYXRoZXIgdGhhbiBzaWxlbnRseSBkcm9wIHRoZW0uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlUG9zdFN0ZXBzKG9wdHM6IFBvc3RTdGVwT3B0aW9ucyk6IFJlc29sdmVkUG9zdFN0ZXBzIHtcbiAgY29uc3Qgc3RlcHM6IFBvc3RTdGVwW10gPSBbXTtcbiAgY29uc3Qgc2tpcHBlZDogU2tpcHBlZFN0ZXBbXSA9IFtdO1xuXG4gIC8vIGAtLWluaXQgYXV0b2AgKHRoZSBkZWZhdWx0KSBvbiB0aGUgQVdTIHRhcmdldHM6IHRoZSBkZXBsb3kgcnVucyBpbml0LXBsYXRmb3JtIGl0c2VsZiDigJRcbiAgLy8gZWMyIG9uIHRoZSBpbnN0YW5jZSBvbiBmaXJzdCBib290LCBla3MgaW4gc2V0dXAuc2gncyBmaW5hbCBwaGFzZSDigJQgc28gRE9OJ1QgYWRkIGEgcmVnaXN0ZXJcbiAgLy8gc3RlcCBoZXJlOyBpdCB3b3VsZCBkdXBsaWNhdGUgdGhlIGRlcGxveS1tYW5hZ2VkIHJ1bi4gKG1pbmlrdWJlL2xvY2FsIHJ1biBpbml0IHZpYSBwcm92aXNpb24uKVxuICBjb25zdCBhdXRvSW5pdE1hbmFnZWQgPVxuICAgIG9wdHMuaW5pdCAmJiBvcHRzLmF1dG9Jbml0ID09PSB0cnVlICYmIChvcHRzLnRhcmdldCA9PT0gJ2VjMicgfHwgb3B0cy50YXJnZXQgPT09ICdla3MnKTtcbiAgaWYgKG9wdHMuaW5pdCAmJiAhYXV0b0luaXRNYW5hZ2VkKSB7XG4gICAgY29uc3QgZW5hYmxlZCA9IExPQURfU1RFUFMuZmlsdGVyKChzKSA9PiBvcHRzLmVuYWJsZWRMb2FkSWRzLmluY2x1ZGVzKHMuaWQpKS5tYXAoKHMpID0+IHMuaWQpO1xuICAgIGNvbnN0IGxvYWRzID0gZW5hYmxlZC5sZW5ndGggPiAwID8gYCAoKyAke2VuYWJsZWQuam9pbignLCAnKX0pYCA6ICcnO1xuICAgIC8vIFJlZ2lzdGVyIGlzIHN1cmZhY2VkIGFzIGEgbWFudWFsIG5leHQtc3RlcCBvbiBBV1MgKHNlZSBydW5Qb3N0U3RlcHMpLiBUaGUgY29tbWFuZCBkaWZmZXJzOlxuICAgIC8vICAtIGVjMjogcnVucyBPTiB0aGUgYm94IGFzIHRoZSBtaW5pa3ViZSB1c2VyLCB3aGVyZSB0aGUgaW4tVlBDIFVSTCByZXNvbHZlcyDihpIgYmFrZSBQTEFURk9STV9CQVNFX1VSTC5cbiAgICAvLyAgLSBla3M6IGluaXQtcGxhdGZvcm0gcG9ydC1mb3J3YXJkcyB0byBzdmMvbmdpbngsIHNvIGl0IHJ1bnMgZnJvbSBhbnl3aGVyZSB3aXRoIGt1YmVjdGwgYWNjZXNzIOKAlFxuICAgIC8vICAgIGRvIE5PVCBiYWtlIFBMQVRGT1JNX0JBU0VfVVJMICh0aGF0IHdvdWxkIGZvcmNlIHRoZSBwdWJsaWMgVVJMIGFuZCB3YWl0IG9uIHRoZSBBTEIvRE5TKS5cbiAgICAvLyAgLSBsb2NhbC9taW5pa3ViZTogcGxhaW4gY29tbWFuZCAodGhlIFVSTCBpcyBsb2NhbGhvc3QpLlxuICAgIGNvbnN0IHJlZ2lzdGVyQ29tbWFuZCA9IG9wdHMudGFyZ2V0ID09PSAnZWMyJyAmJiBvcHRzLnVybFxuICAgICAgPyBgUExBVEZPUk1fQkFTRV9VUkw9JHtvcHRzLnVybH0gLi9kZXBsb3kvYmluL2luaXQtcGxhdGZvcm0uc2ggZWMyYFxuICAgICAgOiBgLi9kZXBsb3kvYmluL2luaXQtcGxhdGZvcm0uc2ggJHtvcHRzLnRhcmdldH1gO1xuICAgIHN0ZXBzLnB1c2goe1xuICAgICAgaWQ6ICdyZWdpc3RlcicsXG4gICAgICBsYWJlbDogYFJlZ2lzdGVyIGFkbWluJHtsb2Fkc31gLFxuICAgICAgY29tbWFuZDogcmVnaXN0ZXJDb21tYW5kLFxuICAgICAgZW52OiByZWdpc3RlckVudihvcHRzLmVuYWJsZWRMb2FkSWRzLCBvcHRzLmJ1aWxkQm9vdHN0cmFwKSxcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChvcHRzLnNtb2tlVGVzdCkge1xuICAgIGlmIChvcHRzLnVybCkge1xuICAgICAgLy8gLWs6IGxvY2FsL21pbmlrdWJlIGZyb250IGEgc2VsZi1zaWduZWQgY2VydDsgaGFybWxlc3MgYWdhaW5zdCByZWFsLWNlcnQgQVdTIFVSTHMuXG4gICAgICAvLyBQcm9iZSAvaGVhbHRoIOKAlCB0aGUgb25lIHJvdXRlIGd1YXJhbnRlZWQgdG8gZXhpc3QgYW5kIHNlcnZlIHVuYXV0aGVudGljYXRlZFxuICAgICAgLy8gdGhyb3VnaCBuZ2lueCAoZXZlcnkgL2FwaS8qIHJvdXRlIHJlcXVpcmVzIGF1dGgg4oaSIDQwMTsgL2FwaS92ZXJzaW9uIGRvZXNuJ3RcbiAgICAgIC8vIGV4aXN0IGFuZCB3b3VsZCBmYWxsIHRocm91Z2ggdG8gdGhlIFNQQSwgbWFraW5nIGBjdXJsIC1mYCBtZWFuaW5nbGVzcykuXG4gICAgICBzdGVwcy5wdXNoKHtcbiAgICAgICAgaWQ6ICdzbW9rZS10ZXN0JyxcbiAgICAgICAgbGFiZWw6ICdTbW9rZSB0ZXN0IOKAlCBnYXRld2F5L0FQSSByZWFjaGFiaWxpdHknLFxuICAgICAgICBjb21tYW5kOiBgY3VybCAtZnNTayAke29wdHMudXJsfS9oZWFsdGggJiYgZWNobyAnc21va2UtdGVzdDogQVBJIHJlYWNoYWJsZSdgLFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNraXBwZWQucHVzaCh7IGlkOiAnc21va2UtdGVzdCcsIHJlYXNvbjogJ25vIHBsYXRmb3JtIFVSTCB0byBwcm9iZSBmb3IgdGhpcyB0YXJnZXQnIH0pO1xuICAgIH1cbiAgfVxuXG4gIGlmIChvcHRzLmV2ZW50cykge1xuICAgIGlmIChvcHRzLnRhcmdldCA9PT0gJ2VjMicgfHwgb3B0cy50YXJnZXQgPT09ICdla3MnKSB7XG4gICAgICAvLyBFdmVudCBpbmdlc3Rpb24gaXMgYSBUSFJFRS1zdGVwIGJ1bmRsZSwgaW4gdGhpcyBvcmRlcjpcbiAgICAgIC8vICAgMS4gc3RvcmUtdG9rZW4gICAgICAgICAg4oCUIHRoZSBmdWxsLXByaXZpbGVnZSBwbGF0Zm9ybSBKV1QgKHN5bnRoL2RlcGxveVxuICAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrcyByZWFkIGl0OyAtLXNjaGVkdWxlIGF1dG8tcmVuZXdzIGl0KS5cbiAgICAgIC8vICAgMi4gc3RvcmUtdG9rZW4gLS1zY29wZSByZXBvcnRpbmc6aW5nZXN0IC0tc2NoZWR1bGVcbiAgICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAg4oCUIGEgRElTVElOQ1QgbGVhc3QtcHJpdmlsZWdlIHRva2VuIHdob3NlIGBzY29wZWBcbiAgICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFpbSBpcyBleGFjdGx5IGByZXBvcnRpbmc6aW5nZXN0YC4gVGhlIGluZ2VzdFxuICAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZHBvaW50IHJlcXVpcmVzIHRoaXMgc2NvcGUgYW5kIGBoYXNTY29wZWAgaXMgYVxuICAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbmdsZS12YWx1ZSBlcXVhbGl0eSBjaGVjaywgc28gdGhlIHBsYXRmb3JtXG4gICAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9rZW4gKG5vIHNjb3BlKSBjYW4gTkVWRVIgaW5nZXN0IOKAlCB0aGUgTGFtYmRhXG4gICAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXVzdCByZWFkIHRoaXMgZGVkaWNhdGVkIHRva2VuLiBTdG9yZWQgYXRcbiAgICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgLi4uL3JlcG9ydGluZy1pbmdlc3RgLiAtLXNjaGVkdWxlIGRlcGxveXMgaXRzIE9XTlxuICAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmV3YWwgc3RhY2sgKG5hbWVkIGAtcmVwb3J0aW5nLWluZ2VzdGAsIGRpc3RpbmN0XG4gICAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSB0aGUgcGxhdGZvcm0gb25lKSB3aG9zZSBoYW5kbGVyIHByZXNlcnZlcyB0aGVcbiAgICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29wZSBvbiByZS1taW50LCBzbyBpdCBhdXRvLXJlbmV3cyBhbmQgbmV2ZXIgbGFwc2VzLlxuICAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNlZSBzZXR1cC1ldmVudHMgLS1zY29wZWQtaW5nZXN0LlxuICAgICAgLy8gICAzLiBzZXR1cC1ldmVudHMgLS1zY29wZWQtaW5nZXN0XG4gICAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgIOKAlCBkZXBsb3lzIHRoZSBFdmVudEJyaWRnZSDihpIgU1FTIOKGkiBMYW1iZGEgYW5kIHBvaW50c1xuICAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBMYW1iZGEgYXQgdGhlIHJlcG9ydGluZy1pbmdlc3Qgc2VjcmV0IGZyb20gIzIuXG4gICAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0lUSE9VVCAtLXNjb3BlZC1pbmdlc3QgdGhlIExhbWJkYSByZWFkcyB0aGVcbiAgICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGF0Zm9ybSBzZWNyZXQgYW5kIGV2ZXJ5IGluZ2VzdCA0MDNzXG4gICAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFwiVG9rZW4gbXVzdCBjYXJyeSB0aGUgJ3JlcG9ydGluZzppbmdlc3QnIHNjb3BlXCIpLlxuICAgICAgLy8gcHJvdmlzaW9uIHN1cmZhY2VzIChkb2VzIG5vdCBhdXRvLXJ1bikgdGhlIGJ1bmRsZSBvbiBBV1Mg4oCUIGl0IG5lZWRzIGFcbiAgICAgIC8vIHJlZ2lzdGVyZWQsIGluLVZQQyBwbGF0Zm9ybS5cbiAgICAgIGNvbnN0IHJlZ2lvbiA9IG9wdHMucmVnaW9uID8gYCAtLXJlZ2lvbiAke29wdHMucmVnaW9ufWAgOiAnJztcbiAgICAgIC8vIE1pcnJvciB0aGUgcmVnaXN0ZXIgYnJhbmNoJ3MgdGFyZ2V0IHJ1bGU6IGJha2UgUExBVEZPUk1fQkFTRV9VUkwgb25seSBvblxuICAgICAgLy8gZWMyICh0aGUgaW4tVlBDIFVSTCByZXNvbHZlcyBvbiB0aGUgYm94KS4gT24gZWtzIHRoZSBwdWJsaWMgQUxCL0ROUyBpc24ndFxuICAgICAgLy8gdXAgeWV0LCBzbyBiYWtpbmcgaXQgd291bGQgcG9pbnQgc3RvcmUtdG9rZW4vc2V0dXAtZXZlbnRzIGF0IGFuXG4gICAgICAvLyB1bnJlc29sdmFibGUgaG9zdCDigJQgdGhlIG9wZXJhdG9yIHNldHMgUExBVEZPUk1fQkFTRV9VUkwgd2hlbiBydW5uaW5nIHRoZVxuICAgICAgLy8gc3VyZmFjZWQgYnVuZGxlLCBvbmNlIHRoZSBBTEIgaXMgcmVhZHkuXG4gICAgICBjb25zdCBlbnYgPSBvcHRzLnRhcmdldCA9PT0gJ2VjMicgJiYgb3B0cy51cmwgPyB7IFBMQVRGT1JNX0JBU0VfVVJMOiBvcHRzLnVybCB9IDogdW5kZWZpbmVkO1xuICAgICAgc3RlcHMucHVzaCh7XG4gICAgICAgIGlkOiAnc3RvcmUtdG9rZW4nLFxuICAgICAgICBsYWJlbDogJ1N0b3JlIHBsYXRmb3JtIHRva2VuIGluIEFXUyBTZWNyZXRzIE1hbmFnZXIgKCsgZGFpbHkgYXV0by1yZW5ld2FsKScsXG4gICAgICAgIC8vIC0tc2NoZWR1bGU6IHN5bnRoL2RlcGxveSBjYWxsYmFja3MgcmVhZCB0aGlzIHRva2VuLCBzbyBpbnN0YWxsIHRoZVxuICAgICAgICAvLyByZW5ld2FsIHN0YWNrIHNvIGl0IG5ldmVyIGxhcHNlcyAoc3RvcmUtdG9rZW4gbm8gbG9uZ2VyIGRlcGxveXMgaXQgYnkgZGVmYXVsdCkuXG4gICAgICAgIGNvbW1hbmQ6IGBwaXBlbGluZS1tYW5hZ2VyIGluZnJhIHN0b3JlLXRva2VuIC0tc2NoZWR1bGUke3JlZ2lvbn1gLFxuICAgICAgICBlbnYsXG4gICAgICB9KTtcbiAgICAgIHN0ZXBzLnB1c2goe1xuICAgICAgICBpZDogJ3N0b3JlLXRva2VuLWluZ2VzdCcsXG4gICAgICAgIGxhYmVsOiAnU3RvcmUgcmVwb3J0aW5nLWluZ2VzdCAoc2NvcGVkKSB0b2tlbiBpbiBBV1MgU2VjcmV0cyBNYW5hZ2VyICgrIGF1dG8tcmVuZXdhbCknLFxuICAgICAgICBjb21tYW5kOiBgcGlwZWxpbmUtbWFuYWdlciBpbmZyYSBzdG9yZS10b2tlbiAtLXNjb3BlIHJlcG9ydGluZzppbmdlc3QgLS1zY2hlZHVsZSR7cmVnaW9ufWAsXG4gICAgICAgIGVudixcbiAgICAgIH0pO1xuICAgICAgc3RlcHMucHVzaCh7XG4gICAgICAgIGlkOiAnZXZlbnRzJyxcbiAgICAgICAgbGFiZWw6ICdFdmVudEJyaWRnZSBpbmdlc3Rpb24gKHNldHVwLWV2ZW50cywgc2NvcGVkLWluZ2VzdCknLFxuICAgICAgICBjb21tYW5kOiBgcGlwZWxpbmUtbWFuYWdlciBpbmZyYSBzZXR1cC1ldmVudHMgLS1zY29wZWQtaW5nZXN0JHtyZWdpb259YCxcbiAgICAgICAgZW52LFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNraXBwZWQucHVzaCh7IGlkOiAnZXZlbnRzJywgcmVhc29uOiBgbm90IGFwcGxpY2FibGUgdG8gdGFyZ2V0ICcke29wdHMudGFyZ2V0fScgKGVjMi9la3Mgb25seSlgIH0pO1xuICAgIH1cbiAgfVxuXG4gIG9wdHMuc3RlcHMuZm9yRWFjaCgoY29tbWFuZCwgaSkgPT4ge1xuICAgIGlmIChjb21tYW5kLnRyaW0oKSAhPT0gJycpIHN0ZXBzLnB1c2goeyBpZDogYGN1c3RvbS0ke2kgKyAxfWAsIGxhYmVsOiBgQ3VzdG9tIHN0ZXAgJHtpICsgMX1gLCBjb21tYW5kIH0pO1xuICB9KTtcblxuICByZXR1cm4geyBzdGVwcywgc2tpcHBlZCB9O1xufVxuIl19
@@ -0,0 +1,26 @@
1
+ import type { TargetId } from './targets.js';
2
+ export interface PrereqCheck {
3
+ readonly name: string;
4
+ readonly ok: boolean;
5
+ readonly detail: string;
6
+ /** A failing required check blocks deployment; advisory ones are warnings. */
7
+ readonly required: boolean;
8
+ }
9
+ /** True when git is on PATH (required to bootstrap a clone at all). */
10
+ export declare function gitAvailable(): boolean;
11
+ /**
12
+ * Cone `sparse-checkout` (+ `--filter=blob:none`) needs git ≥ 2.27. Below that,
13
+ * the bootstrap falls back to a (correct, just larger) full clone.
14
+ */
15
+ export declare function gitSupportsSparseCheckout(): boolean;
16
+ /**
17
+ * Run the read-only prerequisite checks for a target. Pure inspection — safe to
18
+ * run unconditionally (the plan assembles this before the gated execution).
19
+ */
20
+ export declare function checkPrereqs(target: TargetId, opts?: {
21
+ bootstrap?: boolean;
22
+ withPlugins?: boolean;
23
+ }): PrereqCheck[];
24
+ /** True when every REQUIRED prerequisite passed. */
25
+ export declare function prereqsSatisfied(checks: readonly PrereqCheck[]): boolean;
26
+ //# sourceMappingURL=prereqs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prereqs.d.ts","sourceRoot":"","sources":["../../src/agent/prereqs.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AA0CD,uEAAuE;AACvE,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAGnD;AAWD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,WAAW,EAAE,CAgEvH;AAED,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAExE"}