@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,265 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Deterministic registry of platform deploy targets — the source of truth the
5
+ * `provision` advisor uses to assemble the EXACT deploy command. The agent is a
6
+ * thin wrapper over the existing deploy scripts; it never reimplements
7
+ * deployment, only validates inputs and assembles the command to run.
8
+ *
9
+ * Keep this in lock-step with the flags the scripts accept — every target's
10
+ * operator entrypoint is `bin/setup.sh` (deploy/<target>/bin/setup.sh).
11
+ */
12
+ import { assertShellSafe, shellQuote } from '../config/cli.constants.js';
13
+ import { resolveAwsRegion } from '../utils/aws-env.js';
14
+ // --- Shared input specs -----------------------------------------------------
15
+ const DOMAIN = { flag: 'domain', key: 'domain', description: 'Fully-qualified domain name (ALB ACM cert + SES DKIM)' };
16
+ const HOSTED_ZONE = { flag: 'hosted-zone-id', key: 'hostedZoneId', description: 'Public Route 53 hosted zone ID authoritative for the domain' };
17
+ const GHCR_TOKEN = { flag: 'ghcr-token', key: 'ghcrToken', description: 'GitHub PAT with read:packages (avoids ghcr.io anonymous rate limits)', secret: true };
18
+ const REGION = { flag: 'region', key: 'region', description: 'AWS region' };
19
+ const DEPLOY_MODE = { flag: 'deploy-mode', key: 'deployMode', description: 'public (internet-facing ALB) or private (internal, default)' };
20
+ const KEY_PAIR = { flag: 'key-pair', key: 'keyPair', description: 'EC2 key pair in the region (break-glass serial console; routine access is SSM)' };
21
+ const INSTANCE_TYPE = { flag: 'instance-type', key: 'instanceType', description: 'EC2 instance type (default t3.2xlarge)' };
22
+ // ec2 deploy/teardown stack name (CloudFormation). The `stackName` param key is also reused
23
+ // by the teardown path as the resource identifier (ec2 stack / eks cluster name).
24
+ const STACK_NAME = { flag: 'stack-name', key: 'stackName', description: 'CloudFormation stack name (default pipeline-builder) — set to run a second ec2 environment' };
25
+ // eks cluster name (eksctl). Set to run a second EKS environment in one account.
26
+ const CLUSTER_NAME = { flag: 'cluster-name', key: 'clusterName', description: 'EKS cluster name (default pipeline-builder)' };
27
+ // Auto-init is ON BY DEFAULT on the AWS targets (ec2 + eks setup.sh default AUTO_INIT=true),
28
+ // so `--no-auto-init` is the load-bearing opt-out and `--auto-init` is a no-op reaffirm —
29
+ // mirrors --email/--no-email. ec2 self-inits on the instance on first boot; eks self-inits in
30
+ // setup.sh's final phase (over a kubectl port-forward). minikube/local run init via provision.
31
+ // NOTE: `--no-auto-init`'s key (noAutoInit) is NOT derivable from its flag the way the other
32
+ // specs' keys are (commander folds --x/--no-x into a single `x` option); provision.ts assembles
33
+ // both keys explicitly — see the param-assembly there.
34
+ const AUTO_INIT = { flag: 'auto-init', key: 'autoInit', description: 'ec2/eks: the deploy self-runs init-platform (register + all loads) — the DEFAULT on AWS', boolean: true };
35
+ const NO_AUTO_INIT = { flag: 'no-auto-init', key: 'noAutoInit', description: 'ec2/eks: skip the deploy-managed auto-init and run init-platform manually instead', boolean: true };
36
+ // ec2 only: LEAN drops the optional observability/admin services so the core stack +
37
+ // mesh fits a t3.xlarge instead of t3.2xlarge. Flows through the CFN `Lean` param into
38
+ // the instance's startup.sh. (minikube reads LEAN as an env var; eks doesn't support it.)
39
+ const LEAN = { flag: 'lean', key: 'lean', description: 'ec2: trim optional observability/admin services so the stack fits a t3.xlarge (pair with --instance-type t3.xlarge)', boolean: true };
40
+ // SES / email family — shared by ec2 + eks. SES is provisioned BY DEFAULT
41
+ // on AWS deploys; `--no-email` is the opt-out (`--email` is a harmless no-op kept
42
+ // for back-compat).
43
+ const EMAIL = [
44
+ { flag: 'email', key: 'email', description: 'Enable SES transactional email (on by default for AWS)', boolean: true },
45
+ { flag: 'no-email', key: 'noEmail', description: 'Skip SES (transactional email is provisioned by default)', boolean: true },
46
+ { flag: 'email-from', key: 'emailFrom', description: 'From address (default noreply@<domain>)' },
47
+ { flag: 'email-from-name', key: 'emailFromName', description: 'Display name on outbound email' },
48
+ { flag: 'alert-email', key: 'alertEmail', description: 'Subscribe an address to the bounce/complaint SNS topic' },
49
+ { flag: 'no-create-ses-identity', key: 'noCreateSesIdentity', description: 'Skip SES identity creation (domain already verified)', boolean: true },
50
+ ];
51
+ // --- Targets ----------------------------------------------------------------
52
+ export const TARGETS = {
53
+ docker: {
54
+ id: 'docker',
55
+ label: 'Local (Docker Compose)',
56
+ dir: 'deploy/local/docker',
57
+ entrypoint: 'bin/setup.sh',
58
+ sparsePaths: ['deploy/local/docker'],
59
+ required: [],
60
+ optional: [],
61
+ postDeploy: './deploy/bin/init-platform.sh docker',
62
+ cost: 'Free',
63
+ bestFor: 'Development',
64
+ deploys: 'the platform as a Docker Compose stack — an nginx TLS proxy, the API services (platform, plugin, pipeline, message, reporting, compliance, quota, billing, image-registry), the frontend, and postgres + mongo + redis. First run pulls the ghcr.io images and generates a local TLS cert (a few minutes).',
65
+ destroys: 'stops all containers — data under deploy/local/docker/data persists on disk (delete it manually for a clean slate)',
66
+ // Mirrors the published ports in deploy/local/docker/docker-compose.yml.
67
+ hostPorts: [
68
+ { service: 'nginx — HTTPS gateway (UI/API)', port: 8443 },
69
+ { service: 'nginx — HTTP redirect', port: 8080 },
70
+ { service: 'pgAdmin (Postgres UI)', port: 5480 },
71
+ { service: 'Mongo Express (Mongo UI)', port: 27081 },
72
+ { service: 'Docker registry', port: 5000 },
73
+ { service: 'Jaeger (tracing UI)', port: 16686 },
74
+ ],
75
+ },
76
+ minikube: {
77
+ id: 'minikube',
78
+ label: 'Minikube (local Kubernetes)',
79
+ dir: 'deploy/local/minikube',
80
+ entrypoint: 'bin/setup.sh',
81
+ sparsePaths: ['deploy/local/minikube'],
82
+ required: [],
83
+ optional: [],
84
+ postDeploy: './deploy/bin/init-platform.sh minikube',
85
+ cost: 'Free',
86
+ bestFor: 'Local Kubernetes',
87
+ deploys: 'the platform onto a local Minikube cluster — the same services as Kubernetes Deployments/Services behind an ingress, plus in-cluster postgres + mongo + redis. First run pulls images, builds the cluster, and generates a TLS cert (several minutes).',
88
+ destroys: 'stops the minikube stack — persistent volumes (PVC data) remain until the cluster is deleted',
89
+ // Mirrors the kubectl port-forwards started in deploy/local/minikube/bin/setup.sh.
90
+ hostPorts: [
91
+ { service: 'nginx — HTTPS gateway (UI/API)', port: 8443 },
92
+ { service: 'Mongo Express (Mongo UI)', port: 8081 },
93
+ { service: 'pgAdmin (Postgres UI)', port: 5480 },
94
+ ],
95
+ },
96
+ ec2: {
97
+ id: 'ec2',
98
+ label: 'AWS EC2 (single Minikube instance behind an ALB)',
99
+ dir: 'deploy/aws/ec2',
100
+ entrypoint: 'bin/setup.sh',
101
+ sparsePaths: ['deploy/aws/ec2'],
102
+ required: [KEY_PAIR, DOMAIN, HOSTED_ZONE],
103
+ optional: [REGION, DEPLOY_MODE, GHCR_TOKEN, INSTANCE_TYPE, STACK_NAME, AUTO_INIT, NO_AUTO_INIT, LEAN, ...EMAIL],
104
+ postDeploy: './deploy/bin/init-platform.sh ec2 # auto-runs on the instance by default; --no-auto-init to do it manually',
105
+ cost: '~$140-265/mo',
106
+ bestFor: 'Dev / staging',
107
+ deploys: 'the platform on a single EC2 instance via CloudFormation — a VPC, the instance (running the Minikube stack), an ALB, a Route 53 record + ACM cert for the domain, and (by default) SES email. The instance pulls images on first boot.',
108
+ destroys: 'DELETES the CloudFormation stack: the VPC, EC2 instance, and its EBS data volume (databases, registry, plugin builds). Irreversible.',
109
+ hostPorts: [], // remote (AWS) — binds nothing on the operator's machine
110
+ },
111
+ eks: {
112
+ id: 'eks',
113
+ label: 'AWS EKS Auto Mode (managed Kubernetes)',
114
+ dir: 'deploy/aws/eks',
115
+ entrypoint: 'bin/setup.sh',
116
+ sparsePaths: ['deploy/aws/eks'],
117
+ required: [DOMAIN, HOSTED_ZONE],
118
+ optional: [REGION, DEPLOY_MODE, GHCR_TOKEN, CLUSTER_NAME, AUTO_INIT, NO_AUTO_INIT, ...EMAIL],
119
+ postDeploy: './deploy/bin/init-platform.sh eks # auto-runs at the end of setup.sh by default; --no-auto-init to do it manually',
120
+ cost: '~$150-400/mo',
121
+ bestFor: 'Production',
122
+ deploys: 'the platform on Amazon EKS Auto Mode — an AWS-managed Kubernetes cluster (Karpenter-scaled EC2 nodes, AWS Load Balancer Controller, EBS/EFS CSI), the same Kubernetes workloads as the other k8s targets, an ALB Ingress + ACM for the domain, and (by default) SES email. Plugin builds run on the in-cluster rootless buildkitd (EC2 nodes allow it).',
123
+ destroys: 'Runs bin/shutdown.sh: DELETES the EKS cluster + nodes (eksctl), the EFS filesystem, and — when --domain is set — the ACM cert + Route 53 alias. EBS volumes on the Retain StorageClass are NOT auto-deleted (reported at the end). Irreversible.',
124
+ hostPorts: [], // remote (AWS) — binds nothing on the operator's machine
125
+ },
126
+ };
127
+ export const TARGET_IDS = ['docker', 'minikube', 'ec2', 'eks'];
128
+ export function isTargetId(value) {
129
+ return typeof value === 'string' && TARGET_IDS.includes(value);
130
+ }
131
+ // --- Sparse bootstrap paths -------------------------------------------------
132
+ /**
133
+ * Folders every `--repo` bootstrap needs regardless of target: the orchestration
134
+ * scripts. Each target's setup.sh + init-platform.sh live in / drive these.
135
+ * Deliberately minimal — heavier folders (plugins/compliance/samples) are pulled
136
+ * in only when their post-install option is selected (see LOAD_STEPS).
137
+ */
138
+ export const COMMON_SPARSE_PATHS = ['deploy/bin'];
139
+ /**
140
+ * Opt-in post-install load steps. Each maps a provision `--with-*` flag to the
141
+ * init-platform env var that enables it AND the repo folder(s) it reads — so the
142
+ * sparse checkout grows exactly with the selected options.
143
+ */
144
+ export const LOAD_STEPS = [
145
+ // The plugin build reads deploy/plugins/_base AND deploy/codebuild/bootstrap.
146
+ { id: 'plugins', flag: 'withPlugins', env: 'LOAD_PLUGINS', paths: ['deploy/plugins', 'deploy/codebuild'] },
147
+ { id: 'compliance', flag: 'withCompliance', env: 'LOAD_COMPLIANCE', paths: ['deploy/compliance'] },
148
+ { id: 'samples', flag: 'withSamples', env: 'LOAD_TEMPLATES', paths: ['deploy/samples'] },
149
+ ];
150
+ /**
151
+ * The de-duplicated set of sparse paths for a target plus the enabled load
152
+ * steps: common base ∪ target folder(s) ∪ each enabled step's folder(s).
153
+ */
154
+ export function sparsePathsFor(target, enabledLoadIds) {
155
+ const paths = new Set(COMMON_SPARSE_PATHS);
156
+ for (const p of TARGETS[target].sparsePaths)
157
+ paths.add(p);
158
+ for (const step of LOAD_STEPS) {
159
+ if (enabledLoadIds.includes(step.id))
160
+ for (const p of step.paths)
161
+ paths.add(p);
162
+ }
163
+ return [...paths];
164
+ }
165
+ /**
166
+ * Quote only when the value would otherwise be word-split or mis-parsed by the
167
+ * shell (whitespace or embedded quotes). `assertShellSafe` already rejects the
168
+ * dangerous metacharacters, so simple tokens stay unquoted for readability.
169
+ */
170
+ function maybeShellQuote(value) {
171
+ return /[\s'"]/.test(value) ? shellQuote(value) : value;
172
+ }
173
+ /**
174
+ * Assemble the deploy command for a target from the provided params. Pure and
175
+ * deterministic — no shell, no LLM. Missing required inputs are reported (never
176
+ * guessed). By default secrets are masked (`***`) for DISPLAY; pass `mask: false`
177
+ * to build the real command for EXECUTION — that string must never be logged or
178
+ * shown to the model.
179
+ */
180
+ export function assembleCommand(target, params, opts = {}) {
181
+ const mask = opts.mask ?? true;
182
+ const provided = (spec) => {
183
+ const v = params[spec.key];
184
+ return v !== undefined && v !== '' && v !== false;
185
+ };
186
+ const missing = target.required.filter((spec) => !provided(spec));
187
+ const parts = [`cd ${target.dir} && bash ${target.entrypoint}`];
188
+ for (const spec of [...target.required, ...target.optional]) {
189
+ if (!provided(spec))
190
+ continue;
191
+ if (spec.boolean) {
192
+ parts.push(`--${spec.flag}`);
193
+ continue;
194
+ }
195
+ const raw = String(params[spec.key]);
196
+ // The assembled command is executed via a shell (runScript), so a param
197
+ // value carrying shell metacharacters would be command injection. Validate
198
+ // the REAL value even when masking for display — the executed command uses
199
+ // the unmasked value. Redact secrets so the error never echoes a token.
200
+ assertShellSafe(raw, `--${spec.flag}`, { redactValue: spec.secret });
201
+ // assertShellSafe still permits spaces and quotes (e.g. --email-from-name
202
+ // "Pipeline Builder", or O'Brien), which would word-split when emitted bare;
203
+ // quote those so the value reaches the script as a single argument.
204
+ const value = spec.secret && mask ? '***' : maybeShellQuote(raw);
205
+ parts.push(`--${spec.flag} ${value}`);
206
+ }
207
+ return { command: parts.join(' \\\n '), missing };
208
+ }
209
+ /** CloudFormation stack name the EC2 setup.sh defaults to. */
210
+ const DEFAULT_EC2_STACK = 'pipeline-builder';
211
+ /** EKS cluster name eksctl defaults to. */
212
+ const DEFAULT_EKS_CLUSTER = 'pipeline-builder';
213
+ /**
214
+ * Assemble the teardown command for a target. Pure and deterministic — mirrors
215
+ * `assembleCommand` for the destroy path. local/minikube STOP the stack
216
+ * (non-destructive — on-disk / PVC data survives); ec2 DELETEs its CloudFormation
217
+ * stack and eks DELETEs its cluster (eksctl) — both irreversible. EC2 `delete-stack`
218
+ * and `eksctl delete cluster` have no native prompt, which is exactly why the agent's
219
+ * typed-confirmation gate is mandatory there.
220
+ */
221
+ export function teardownCommand(target, opts = {}) {
222
+ const region = resolveAwsRegion(opts.region);
223
+ // Anything flowing unquoted into a shell-executed teardown command is rejected
224
+ // for shell metacharacters (mirrors assembleCommand).
225
+ assertShellSafe(region, 'region');
226
+ if (opts.stackName)
227
+ assertShellSafe(opts.stackName, 'stack-name');
228
+ if (opts.clusterName)
229
+ assertShellSafe(opts.clusterName, 'cluster-name');
230
+ if (opts.domain)
231
+ assertShellSafe(opts.domain, 'domain');
232
+ if (opts.hostedZoneId)
233
+ assertShellSafe(opts.hostedZoneId, 'hosted-zone-id');
234
+ switch (target) {
235
+ case 'docker':
236
+ return { command: 'cd deploy/local/docker && bash bin/shutdown.sh', destructive: false };
237
+ case 'minikube':
238
+ return { command: 'cd deploy/local/minikube && bash bin/shutdown.sh', destructive: false };
239
+ case 'ec2': {
240
+ const stack = opts.stackName || DEFAULT_EC2_STACK;
241
+ return {
242
+ command: `aws cloudformation delete-stack --stack-name ${stack} --region ${region} && ` +
243
+ `aws cloudformation wait stack-delete-complete --stack-name ${stack} --region ${region}`,
244
+ destructive: true,
245
+ };
246
+ }
247
+ case 'eks': {
248
+ // eks tears down via bin/shutdown.sh (like local/minikube use bin/shutdown.sh):
249
+ // it deletes the cluster AND the resources eksctl alone would orphan — the EFS
250
+ // filesystem and, when --domain is given, the ACM cert + Route 53 alias. The
251
+ // agent's typed-confirmation gate already ran, so pass --yes to skip the
252
+ // script's own prompt.
253
+ const cluster = opts.clusterName || DEFAULT_EKS_CLUSTER;
254
+ let command = `cd deploy/aws/eks && bash bin/shutdown.sh --cluster-name ${cluster} --region ${region}`;
255
+ if (opts.domain)
256
+ command += ` --domain ${opts.domain}`;
257
+ if (opts.hostedZoneId)
258
+ command += ` --hosted-zone-id ${opts.hostedZoneId}`;
259
+ if (opts.assumeYes)
260
+ command += ' --yes';
261
+ return { command, destructive: true };
262
+ }
263
+ }
264
+ }
265
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFyZ2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZ2VudC90YXJnZXRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7O0dBUUc7QUFFSCxPQUFPLEVBQUUsZUFBZSxFQUFFLFVBQVUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBc0R2RCwrRUFBK0U7QUFFL0UsTUFBTSxNQUFNLEdBQWMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLHVEQUF1RCxFQUFFLENBQUM7QUFDbEksTUFBTSxXQUFXLEdBQWMsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFLGNBQWMsRUFBRSxXQUFXLEVBQUUsNkRBQTZELEVBQUUsQ0FBQztBQUMzSixNQUFNLFVBQVUsR0FBYyxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsR0FBRyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsc0VBQXNFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDO0FBQzFLLE1BQU0sTUFBTSxHQUFjLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsQ0FBQztBQUN2RixNQUFNLFdBQVcsR0FBYyxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsNkRBQTZELEVBQUUsQ0FBQztBQUN0SixNQUFNLFFBQVEsR0FBYyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsZ0ZBQWdGLEVBQUUsQ0FBQztBQUNoSyxNQUFNLGFBQWEsR0FBYyxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsR0FBRyxFQUFF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TyxJQUFJLHFCQUFxQixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDM0UsSUFBSSxJQUFJLENBQUMsU0FBUztnQkFBRSxPQUFPLElBQUksUUFBUSxDQUFDO1lBQ3hDLE9BQU8sRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxDQUFDO1FBQ3hDLENBQUM7SUFDSCxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIERldGVybWluaXN0aWMgcmVnaXN0cnkgb2YgcGxhdGZvcm0gZGVwbG95IHRhcmdldHMg4oCUIHRoZSBzb3VyY2Ugb2YgdHJ1dGggdGhlXG4gKiBgcHJvdmlzaW9uYCBhZHZpc29yIHVzZXMgdG8gYXNzZW1ibGUgdGhlIEVYQUNUIGRlcGxveSBjb21tYW5kLiBUaGUgYWdlbnQgaXMgYVxuICogdGhpbiB3cmFwcGVyIG92ZXIgdGhlIGV4aXN0aW5nIGRlcGxveSBzY3JpcHRzOyBpdCBuZXZlciByZWltcGxlbWVudHNcbiAqIGRlcGxveW1lbnQsIG9ubHkgdmFsaWRhdGVzIGlucHV0cyBhbmQgYXNzZW1ibGVzIHRoZSBjb21tYW5kIHRvIHJ1bi5cbiAqXG4gKiBLZWVwIHRoaXMgaW4gbG9jay1zdGVwIHdpdGggdGhlIGZsYWdzIHRoZSBzY3JpcHRzIGFjY2VwdCDigJQgZXZlcnkgdGFyZ2V0J3NcbiAqIG9wZXJhdG9yIGVudHJ5cG9pbnQgaXMgYGJpbi9zZXR1cC5zaGAgKGRlcGxveS88dGFyZ2V0Pi9iaW4vc2V0dXAuc2gpLlxuICovXG5cbmltcG9ydCB7IGFzc2VydFNoZWxsU2FmZSwgc2hlbGxRdW90ZSB9IGZyb20gJy4uL2NvbmZpZy9jbGkuY29uc3RhbnRzLmpzJztcbmltcG9ydCB7IHJlc29sdmVBd3NSZWdpb24gfSBmcm9tICcuLi91dGlscy9hd3MtZW52LmpzJztcblxuZXhwb3J0IHR5cGUgVGFyZ2V0SWQgPSAnZG9ja2VyJyB8ICdtaW5pa3ViZScgfCAnZWMyJyB8ICdla3MnO1xuXG4vKiogQSBzaW5nbGUgaW5wdXQgdGhlIHVuZGVybHlpbmcgZGVwbG95IHNjcmlwdCBhY2NlcHRzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbnB1dFNwZWMge1xuICAvKiogRmxhZyBuYW1lIHBhc3NlZCB0byB0aGUgc2NyaXB0ICh3aXRob3V0IHRoZSBsZWFkaW5nIGAtLWApLiAqL1xuICByZWFkb25seSBmbGFnOiBzdHJpbmc7XG4gIC8qKiBLZXkgb24gdGhlIHByb3Zpc2lvbiBwYXJhbXMgb2JqZWN0LiAqL1xuICByZWFkb25seSBrZXk6IHN0cmluZztcbiAgLyoqIEh1bWFuIGRlc2NyaXB0aW9uIOKAlCBzaG93biB3aGVuIGEgcmVxdWlyZWQgaW5wdXQgaXMgbWlzc2luZy4gKi9cbiAgcmVhZG9ubHkgZGVzY3JpcHRpb246IHN0cmluZztcbiAgLyoqIFNlY3JldCDigJQgbmV2ZXIgcHJpbnRlZCBpbiB0aGUgYXNzZW1ibGVkIGNvbW1hbmQgKG1hc2tlZCBhcyBgKioqYCkuICovXG4gIHJlYWRvbmx5IHNlY3JldD86IGJvb2xlYW47XG4gIC8qKiBCb29sZWFuIGZsYWcgd2l0aCBubyB2YWx1ZSAoZS5nLiBgLS1lbWFpbGApLiAqL1xuICByZWFkb25seSBib29sZWFuPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUYXJnZXRTcGVjIHtcbiAgcmVhZG9ubHkgaWQ6IFRhcmdldElkO1xuICByZWFkb25seSBsYWJlbDogc3RyaW5nO1xuICAvKiogRGlyZWN0b3J5IHRoZSBlbnRyeXBvaW50IHJ1bnMgZnJvbSAocmVsYXRpdmUgdG8gcmVwbyByb290KS4gKi9cbiAgcmVhZG9ubHkgZGlyOiBzdHJpbmc7XG4gIC8qKiBFbnRyeXBvaW50IHNjcmlwdCAocmVsYXRpdmUgdG8gYGRpcmApLiAqL1xuICByZWFkb25seSBlbnRyeXBvaW50OiBzdHJpbmc7XG4gIC8qKiBJbnB1dHMgdGhlIHNjcmlwdCBSRVFVSVJFUyDigJQgdGhlIGFkdmlzb3IgcmVwb3J0cyBhbnkgdGhhdCBhcmUgbWlzc2luZy4gKi9cbiAgcmVhZG9ubHkgcmVxdWlyZWQ6IHJlYWRvbmx5IElucHV0U3BlY1tdO1xuICAvKiogT3B0aW9uYWwgaW5wdXRzLCBwYXNzZWQgdGhyb3VnaCBvbmx5IHdoZW4gcHJvdmlkZWQuICovXG4gIHJlYWRvbmx5IG9wdGlvbmFsOiByZWFkb25seSBJbnB1dFNwZWNbXTtcbiAgLyoqXG4gICAqIFJlcG8gZm9sZGVyKHMpIHRoaXMgdGFyZ2V0J3MgZGVwbG95IG5lZWRzLCBmb3IgYSBzcGFyc2UgYC0tcmVwb2AgYm9vdHN0cmFwLlxuICAgKiBDb21iaW5lZCB3aXRoIENPTU1PTl9TUEFSU0VfUEFUSFMgYW5kIGFueSBzZWxlY3RlZCBsb2FkIHN0ZXBzJyBwYXRocy5cbiAgICovXG4gIHJlYWRvbmx5IHNwYXJzZVBhdGhzOiByZWFkb25seSBzdHJpbmdbXTtcbiAgLyoqIFBvc3QtZGVwbG95IHN0ZXAgdG8gc3VyZmFjZSAocmVnaXN0ZXJzIGFkbWluICsgbG9hZHMgcGx1Z2lucykuICovXG4gIHJlYWRvbmx5IHBvc3REZXBsb3k/OiBzdHJpbmc7XG4gIC8qKiBSb3VnaCBtb250aGx5IGNvc3QgKGZyb20gZG9jcykuICovXG4gIHJlYWRvbmx5IGNvc3Q6IHN0cmluZztcbiAgLyoqIE9uZS1saW5lIFwiYmVzdCBmb3JcIi4gKi9cbiAgcmVhZG9ubHkgYmVzdEZvcjogc3RyaW5nO1xuICAvKiogV2hhdCB0aGUgZGVwbG95IGNyZWF0ZXMg4oCUIHNob3duIHdoZW4gZGVwbG95aW5nIHNvIFwiRGVwbG95aW5nXCIgaXNuJ3Qgb3BhcXVlLiAqL1xuICByZWFkb25seSBkZXBsb3lzOiBzdHJpbmc7XG4gIC8qKiBXaGF0IGEgdGVhcmRvd24gb2YgdGhpcyB0YXJnZXQgZGVzdHJveXMg4oCUIHNob3duIGJlZm9yZSBhIChnYXRlZCkgdGVhcmRvd24uICovXG4gIHJlYWRvbmx5IGRlc3Ryb3lzOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBIb3N0IHBvcnRzIHRoZSBkZXBsb3kgYmluZHMg4oCUIGEgRkFMTEJBQ0sgb25seS4gVGhlIGxpdmUgbGlzdCBpcyBERVJJVkVEIGZyb20gdGhlXG4gICAqIGNsb25lZCBkZXBsb3kgc291cmNlIGF0IHJ1bnRpbWUgKHBvcnRzLnRzIGBkaXNjb3Zlckhvc3RQb3J0c2ApOiBsb2NhbCBmcm9tXG4gICAqIGRvY2tlci1jb21wb3NlLnltbCdzIHB1Ymxpc2hlZCBwb3J0cywgbWluaWt1YmUgZnJvbSBzZXR1cC5zaCdzIHBvcnQtZm9yd2FyZHMuIFRoaXNcbiAgICogc3RhdGljIGNvcHkgaXMgdXNlZCBvbmx5IHdoZW4gdGhhdCBzb3VyY2UgY2FuJ3QgYmUgcmVhZC4gRW1wdHkgZm9yIHJlbW90ZSB0YXJnZXRzXG4gICAqIChlYzIvZWtzIGJpbmQgbm90aGluZyBvbiB0aGUgb3BlcmF0b3IncyBtYWNoaW5lKS5cbiAgICovXG4gIHJlYWRvbmx5IGhvc3RQb3J0czogcmVhZG9ubHkgeyBzZXJ2aWNlOiBzdHJpbmc7IHBvcnQ6IG51bWJlciB9W107XG59XG5cbi8vIC0tLSBTaGFyZWQgaW5wdXQgc3BlY3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuY29uc3QgRE9NQUlOOiBJbnB1dFNwZWMgPSB7IGZsYWc6ICdkb21haW4nLCBrZXk6ICdkb21haW4nLCBkZXNjcmlwdGlvbjogJ0Z1bGx5LXF1YWxpZmllZCBkb21haW4gbmFtZSAoQUxCIEFDTSBjZXJ0ICsgU0VTIERLSU0pJyB9O1xuY29uc3QgSE9TVEVEX1pPTkU6IElucHV0U3BlYyA9IHsgZmxhZzogJ2hvc3RlZC16b25lLWlkJywga2V5OiAnaG9zdGVkWm9uZUlkJywgZGVzY3JpcHRpb246ICdQdWJsaWMgUm91dGUgNTMgaG9zdGVkIHpvbmUgSUQgYXV0aG9yaXRhdGl2ZSBmb3IgdGhlIGRvbWFpbicgfTtcbmNvbnN0IEdIQ1JfVE9LRU46IElucHV0U3BlYyA9IHsgZmxhZzogJ2doY3ItdG9rZW4nLCBrZXk6ICdnaGNyVG9rZW4nLCBkZXNjcmlwdGlvbjogJ0dpdEh1YiBQQVQgd2l0aCByZWFkOnBhY2thZ2VzIChhdm9pZHMgZ2hjci5pbyBhbm9ueW1vdXMgcmF0ZSBsaW1pdHMpJywgc2VjcmV0OiB0cnVlIH07XG5jb25zdCBSRUdJT046IElucHV0U3BlYyA9IHsgZmxhZzogJ3JlZ2lvbicsIGtleTogJ3JlZ2lvbicsIGRlc2NyaXB0aW9uOiAnQVdTIHJlZ2lvbicgfTtcbmNvbnN0IERFUExPWV9NT0RFOiBJbnB1dFNwZWMgPSB7IGZsYWc6ICdkZXBsb3ktbW9kZScsIGtleTogJ2RlcGxveU1vZGUnLCBkZXNjcmlwdGlvbjogJ3B1YmxpYyAoaW50ZXJuZXQtZmFjaW5nIEFMQikgb3IgcHJpdmF0ZSAoaW50ZXJuYWwsIGRlZmF1bHQpJyB9O1xuY29uc3QgS0VZX1BBSVI6IElucHV0U3BlYyA9IHsgZmxhZzogJ2tleS1wYWlyJywga2V5OiAna2V5UGFpcicsIGRlc2NyaXB0aW9uOiAnRUMyIGtleSBwYWlyIGluIHRoZSByZWdpb24gKGJyZWFrLWdsYXNzIHNlcmlhbCBjb25zb2xlOyByb3V0aW5lIGFjY2VzcyBpcyBTU00pJyB9O1xuY29uc3QgSU5TVEFOQ0VfVFlQRTogSW5wdXRTcGVjID0geyBmbGFnOiAnaW5zdGFuY2UtdHlwZScsIGtleTogJ2luc3RhbmNlVHlwZScsIGRlc2NyaXB0aW9uOiAnRUMyIGluc3RhbmNlIHR5cGUgKGRlZmF1bHQgdDMuMnhsYXJnZSknIH07XG4vLyBlYzIgZGVwbG95L3RlYXJkb3duIHN0YWNrIG5hbWUgKENsb3VkRm9ybWF0aW9uKS4gVGhlIGBzdGFja05hbWVgIHBhcmFtIGtleSBpcyBhbHNvIHJldXNlZFxuLy8gYnkgdGhlIHRlYXJkb3duIHBhdGggYXMgdGhlIHJlc291cmNlIGlkZW50aWZpZXIgKGVjMiBzdGFjayAvIGVrcyBjbHVzdGVyIG5hbWUpLlxuY29uc3QgU1RBQ0tfTkFNRTogSW5wdXRTcGVjID0geyBmbGFnOiAnc3RhY2stbmFtZScsIGtleTogJ3N0YWNrTmFtZScsIGRlc2NyaXB0aW9uOiAnQ2xvdWRGb3JtYXRpb24gc3RhY2sgbmFtZSAoZGVmYXVsdCBwaXBlbGluZS1idWlsZGVyKSDigJQgc2V0IHRvIHJ1biBhIHNlY29uZCBlYzIgZW52aXJvbm1lbnQnIH07XG4vLyBla3MgY2x1c3RlciBuYW1lIChla3NjdGwpLiBTZXQgdG8gcnVuIGEgc2Vjb25kIEVLUyBlbnZpcm9ubWVudCBpbiBvbmUgYWNjb3VudC5cbmNvbnN0IENMVVNURVJfTkFNRTogSW5wdXRTcGVjID0geyBmbGFnOiAnY2x1c3Rlci1uYW1lJywga2V5OiAnY2x1c3Rlck5hbWUnLCBkZXNjcmlwdGlvbjogJ0VLUyBjbHVzdGVyIG5hbWUgKGRlZmF1bHQgcGlwZWxpbmUtYnVpbGRlciknIH07XG4vLyBBdXRvLWluaXQgaXMgT04gQlkgREVGQVVMVCBvbiB0aGUgQVdTIHRhcmdldHMgKGVjMiArIGVrcyBzZXR1cC5zaCBkZWZhdWx0IEFVVE9fSU5JVD10cnVlKSxcbi8vIHNvIGAtLW5vLWF1dG8taW5pdGAgaXMgdGhlIGxvYWQtYmVhcmluZyBvcHQtb3V0IGFuZCBgLS1hdXRvLWluaXRgIGlzIGEgbm8tb3AgcmVhZmZpcm0g4oCUXG4vLyBtaXJyb3JzIC0tZW1haWwvLS1uby1lbWFpbC4gZWMyIHNlbGYtaW5pdHMgb24gdGhlIGluc3RhbmNlIG9uIGZpcnN0IGJvb3Q7IGVrcyBzZWxmLWluaXRzIGluXG4vLyBzZXR1cC5zaCdzIGZpbmFsIHBoYXNlIChvdmVyIGEga3ViZWN0bCBwb3J0LWZvcndhcmQpLiBtaW5pa3ViZS9sb2NhbCBydW4gaW5pdCB2aWEgcHJvdmlzaW9uLlxuLy8gTk9URTogYC0tbm8tYXV0by1pbml0YCdzIGtleSAobm9BdXRvSW5pdCkgaXMgTk9UIGRlcml2YWJsZSBmcm9tIGl0cyBmbGFnIHRoZSB3YXkgdGhlIG90aGVyXG4vLyBzcGVjcycga2V5cyBhcmUgKGNvbW1hbmRlciBmb2xkcyAtLXgvLS1uby14IGludG8gYSBzaW5nbGUgYHhgIG9wdGlvbik7IHByb3Zpc2lvbi50cyBhc3NlbWJsZXNcbi8vIGJvdGgga2V5cyBleHBsaWNpdGx5IOKAlCBzZWUgdGhlIHBhcmFtLWFzc2VtYmx5IHRoZXJlLlxuY29uc3QgQVVUT19JTklUOiBJbnB1dFNwZWMgPSB7IGZsYWc6ICdhdXRvLWluaXQnLCBrZXk6ICdhdXRvSW5pdCcsIGRlc2NyaXB0aW9uOiAnZWMyL2VrczogdGhlIGRlcGxveSBzZWxmLXJ1bnMgaW5pdC1wbGF0Zm9ybSAocmVnaXN0ZXIgKyBhbGwgbG9hZHMpIOKAlCB0aGUgREVGQVVMVCBvbiBBV1MnLCBib29sZWFuOiB0cnVlIH07XG5jb25zdCBOT19BVVRPX0lOSVQ6IElucHV0U3BlYyA9IHsgZmxhZzogJ25vLWF1dG8taW5pdCcsIGtleTogJ25vQXV0b0luaXQnLCBkZXNjcmlwdGlvbjogJ2VjMi9la3M6IHNraXAgdGhlIGRlcGxveS1tYW5hZ2VkIGF1dG8taW5pdCBhbmQgcnVuIGluaXQtcGxhdGZvcm0gbWFudWFsbHkgaW5zdGVhZCcsIGJvb2xlYW46IHRydWUgfTtcbi8vIGVjMiBvbmx5OiBMRUFOIGRyb3BzIHRoZSBvcHRpb25hbCBvYnNlcnZhYmlsaXR5L2FkbWluIHNlcnZpY2VzIHNvIHRoZSBjb3JlIHN0YWNrICtcbi8vIG1lc2ggZml0cyBhIHQzLnhsYXJnZSBpbnN0ZWFkIG9mIHQzLjJ4bGFyZ2UuIEZsb3dzIHRocm91Z2ggdGhlIENGTiBgTGVhbmAgcGFyYW0gaW50b1xuLy8gdGhlIGluc3RhbmNlJ3Mgc3RhcnR1cC5zaC4gKG1pbmlrdWJlIHJlYWRzIExFQU4gYXMgYW4gZW52IHZhcjsgZWtzIGRvZXNuJ3Qgc3VwcG9ydCBpdC4pXG5jb25zdCBMRUFOOiBJbnB1dFNwZWMgPSB7IGZsYWc6ICdsZWFuJywga2V5OiAnbGVhbicsIGRlc2NyaXB0aW9uOiAnZWMyOiB0cmltIG9wdGlvbmFsIG9ic2VydmFiaWxpdHkvYWRtaW4gc2VydmljZXMgc28gdGhlIHN0YWNrIGZpdHMgYSB0My54bGFyZ2UgKHBhaXIgd2l0aCAtLWluc3RhbmNlLXR5cGUgdDMueGxhcmdlKScsIGJvb2xlYW46IHRydWUgfTtcblxuLy8gU0VTIC8gZW1haWwgZmFtaWx5IOKAlCBzaGFyZWQgYnkgZWMyICsgZWtzLiBTRVMgaXMgcHJvdmlzaW9uZWQgQlkgREVGQVVMVFxuLy8gb24gQVdTIGRlcGxveXM7IGAtLW5vLWVtYWlsYCBpcyB0aGUgb3B0LW91dCAoYC0tZW1haWxgIGlzIGEgaGFybWxlc3Mgbm8tb3Aga2VwdFxuLy8gZm9yIGJhY2stY29tcGF0KS5cbmNvbnN0IEVNQUlMOiByZWFkb25seSBJbnB1dFNwZWNbXSA9IFtcbiAgeyBmbGFnOiAnZW1haWwnLCBrZXk6ICdlbWFpbCcsIGRlc2NyaXB0aW9uOiAnRW5hYmxlIFNFUyB0cmFuc2FjdGlvbmFsIGVtYWlsIChvbiBieSBkZWZhdWx0IGZvciBBV1MpJywgYm9vbGVhbjogdHJ1ZSB9LFxuICB7IGZsYWc6ICduby1lbWFpbCcsIGtleTogJ25vRW1haWwnLCBkZXNjcmlwdGlvbjogJ1NraXAgU0VTICh0cmFuc2FjdGlvbmFsIGVtYWlsIGlzIHByb3Zpc2lvbmVkIGJ5IGRlZmF1bHQpJywgYm9vbGVhbjogdHJ1ZSB9LFxuICB7IGZsYWc6ICdlbWFpbC1mcm9tJywga2V5OiAnZW1haWxGcm9tJywgZGVzY3JpcHRpb246ICdGcm9tIGFkZHJlc3MgKGRlZmF1bHQgbm9yZXBseUA8ZG9tYWluPiknIH0sXG4gIHsgZmxhZzogJ2VtYWlsLWZyb20tbmFtZScsIGtleTogJ2VtYWlsRnJvbU5hbWUnLCBkZXNjcmlwdGlvbjogJ0Rpc3BsYXkgbmFtZSBvbiBvdXRib3VuZCBlbWFpbCcgfSxcbiAgeyBmbGFnOiAnYWxlcnQtZW1haWwnLCBrZXk6ICdhbGVydEVtYWlsJywgZGVzY3JpcHRpb246ICdTdWJzY3JpYmUgYW4gYWRkcmVzcyB0byB0aGUgYm91bmNlL2NvbXBsYWludCBTTlMgdG9waWMnIH0sXG4gIHsgZmxhZzogJ25vLWNyZWF0ZS1zZXMtaWRlbnRpdHknLCBrZXk6ICdub0NyZWF0ZVNlc0lkZW50aXR5JywgZGVzY3JpcHRpb246ICdTa2lwIFNFUyBpZGVudGl0eSBjcmVhdGlvbiAoZG9tYWluIGFscmVhZHkgdmVyaWZpZWQpJywgYm9vbGVhbjogdHJ1ZSB9LFxuXTtcblxuLy8gLS0tIFRhcmdldHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5leHBvcnQgY29uc3QgVEFSR0VUUzogUmVhZG9ubHk8UmVjb3JkPFRhcmdldElkLCBUYXJnZXRTcGVjPj4gPSB7XG4gIGRvY2tlcjoge1xuICAgIGlkOiAnZG9ja2VyJyxcbiAgICBsYWJlbDogJ0xvY2FsIChEb2NrZXIgQ29tcG9zZSknLFxuICAgIGRpcjogJ2RlcGxveS9sb2NhbC9kb2NrZXInLFxuICAgIGVudHJ5cG9pbnQ6ICdiaW4vc2V0dXAuc2gnLFxuICAgIHNwYXJzZVBhdGhzOiBbJ2RlcGxveS9sb2NhbC9kb2NrZXInXSxcbiAgICByZXF1aXJlZDogW10sXG4gICAgb3B0aW9uYWw6IFtdLFxuICAgIHBvc3REZXBsb3k6ICcuL2RlcGxveS9iaW4vaW5pdC1wbGF0Zm9ybS5zaCBkb2NrZXInLFxuICAgIGNvc3Q6ICdGcmVlJyxcbiAgICBiZXN0Rm9yOiAnRGV2ZWxvcG1lbnQnLFxuICAgIGRlcGxveXM6ICd0aGUgcGxhdGZvcm0gYXMgYSBEb2NrZXIgQ29tcG9zZSBzdGFjayDigJQgYW4gbmdpbnggVExTIHByb3h5LCB0aGUgQVBJIHNlcnZpY2VzIChwbGF0Zm9ybSwgcGx1Z2luLCBwaXBlbGluZSwgbWVzc2FnZSwgcmVwb3J0aW5nLCBjb21wbGlhbmNlLCBxdW90YSwgYmlsbGluZywgaW1hZ2UtcmVnaXN0cnkpLCB0aGUgZnJvbnRlbmQsIGFuZCBwb3N0Z3JlcyArIG1vbmdvICsgcmVkaXMuIEZpcnN0IHJ1biBwdWxscyB0aGUgZ2hjci5pbyBpbWFnZXMgYW5kIGdlbmVyYXRlcyBhIGxvY2FsIFRMUyBjZXJ0IChhIGZldyBtaW51dGVzKS4nLFxuICAgIGRlc3Ryb3lzOiAnc3RvcHMgYWxsIGNvbnRhaW5lcnMg4oCUIGRhdGEgdW5kZXIgZGVwbG95L2xvY2FsL2RvY2tlci9kYXRhIHBlcnNpc3RzIG9uIGRpc2sgKGRlbGV0ZSBpdCBtYW51YWxseSBmb3IgYSBjbGVhbiBzbGF0ZSknLFxuICAgIC8vIE1pcnJvcnMgdGhlIHB1Ymxpc2hlZCBwb3J0cyBpbiBkZXBsb3kvbG9jYWwvZG9ja2VyL2RvY2tlci1jb21wb3NlLnltbC5cbiAgICBob3N0UG9ydHM6IFtcbiAgICAgIHsgc2VydmljZTogJ25naW54IOKAlCBIVFRQUyBnYXRld2F5IChVSS9BUEkpJywgcG9ydDogODQ0MyB9LFxuICAgICAgeyBzZXJ2aWNlOiAnbmdpbngg4oCUIEhUVFAgcmVkaXJlY3QnLCBwb3J0OiA4MDgwIH0sXG4gICAgICB7IHNlcnZpY2U6ICdwZ0FkbWluIChQb3N0Z3JlcyBVSSknLCBwb3J0OiA1NDgwIH0sXG4gICAgICB7IHNlcnZpY2U6ICdNb25nbyBFeHByZXNzIChNb25nbyBVSSknLCBwb3J0OiAyNzA4MSB9LFxuICAgICAgeyBzZXJ2aWNlOiAnRG9ja2VyIHJlZ2lzdHJ5JywgcG9ydDogNTAwMCB9LFxuICAgICAgeyBzZXJ2aWNlOiAnSmFlZ2VyICh0cmFjaW5nIFVJKScsIHBvcnQ6IDE2Njg2IH0sXG4gICAgXSxcbiAgfSxcbiAgbWluaWt1YmU6IHtcbiAgICBpZDogJ21pbmlrdWJlJyxcbiAgICBsYWJlbDogJ01pbmlrdWJlIChsb2NhbCBLdWJlcm5ldGVzKScsXG4gICAgZGlyOiAnZGVwbG95L2xvY2FsL21pbmlrdWJlJyxcbiAgICBlbnRyeXBvaW50OiAnYmluL3NldHVwLnNoJyxcbiAgICBzcGFyc2VQYXRoczogWydkZXBsb3kvbG9jYWwvbWluaWt1YmUnXSxcbiAgICByZXF1aXJlZDogW10sXG4gICAgb3B0aW9uYWw6IFtdLFxuICAgIHBvc3REZXBsb3k6ICcuL2RlcGxveS9iaW4vaW5pdC1wbGF0Zm9ybS5zaCBtaW5pa3ViZScsXG4gICAgY29zdDogJ0ZyZWUnLFxuICAgIGJlc3RGb3I6ICdMb2NhbCBLdWJlcm5ldGVzJyxcbiAgICBkZXBsb3lzOiAndGhlIHBsYXRmb3JtIG9udG8gYSBsb2NhbCBNaW5pa3ViZSBjbHVzdGVyIOKAlCB0aGUgc2FtZSBzZXJ2aWNlcyBhcyBLdWJlcm5ldGVzIERlcGxveW1lbnRzL1NlcnZpY2VzIGJlaGluZCBhbiBpbmdyZXNzLCBwbHVzIGluLWNsdXN0ZXIgcG9zdGdyZXMgKyBtb25nbyArIHJlZGlzLiBGaXJzdCBydW4gcHVsbHMgaW1hZ2VzLCBidWlsZHMgdGhlIGNsdXN0ZXIsIGFuZCBnZW5lcmF0ZXMgYSBUTFMgY2VydCAoc2V2ZXJhbCBtaW51dGVzKS4nLFxuICAgIGRlc3Ryb3lzOiAnc3RvcHMgdGhlIG1pbmlrdWJlIHN0YWNrIOKAlCBwZXJzaXN0ZW50IHZvbHVtZXMgKFBWQyBkYXRhKSByZW1haW4gdW50aWwgdGhlIGNsdXN0ZXIgaXMgZGVsZXRlZCcsXG4gICAgLy8gTWlycm9ycyB0aGUga3ViZWN0bCBwb3J0LWZvcndhcmRzIHN0YXJ0ZWQgaW4gZGVwbG95L2xvY2FsL21pbmlrdWJlL2Jpbi9zZXR1cC5zaC5cbiAgICBob3N0UG9ydHM6IFtcbiAgICAgIHsgc2VydmljZTogJ25naW54IOKAlCBIVFRQUyBnYXRld2F5IChVSS9BUEkpJywgcG9ydDogODQ0MyB9LFxuICAgICAgeyBzZXJ2aWNlOiAnTW9uZ28gRXhwcmVzcyAoTW9uZ28gVUkpJywgcG9ydDogODA4MSB9LFxuICAgICAgeyBzZXJ2aWNlOiAncGdBZG1pbiAoUG9zdGdyZXMgVUkpJywgcG9ydDogNTQ4MCB9LFxuICAgIF0sXG4gIH0sXG4gIGVjMjoge1xuICAgIGlkOiAnZWMyJyxcbiAgICBsYWJlbDogJ0FXUyBFQzIgKHNpbmdsZSBNaW5pa3ViZSBpbnN0YW5jZSBiZWhpbmQgYW4gQUxCKScsXG4gICAgZGlyOiAnZGVwbG95L2F3cy9lYzInLFxuICAgIGVudHJ5cG9pbnQ6ICdiaW4vc2V0dXAuc2gnLFxuICAgIHNwYXJzZVBhdGhzOiBbJ2RlcGxveS9hd3MvZWMyJ10sXG4gICAgcmVxdWlyZWQ6IFtLRVlfUEFJUiwgRE9NQUlOLCBIT1NURURfWk9ORV0sXG4gICAgb3B0aW9uYWw6IFtSRUdJT04sIERFUExPWV9NT0RFLCBHSENSX1RPS0VOLCBJTlNUQU5DRV9UWVBFLCBTVEFDS19OQU1FLCBBVVRPX0lOSVQsIE5PX0FVVE9fSU5JVCwgTEVBTiwgLi4uRU1BSUxdLFxuICAgIHBvc3REZXBsb3k6ICcuL2RlcGxveS9iaW4vaW5pdC1wbGF0Zm9ybS5zaCBlYzIgICMgYXV0by1ydW5zIG9uIHRoZSBpbnN0YW5jZSBieSBkZWZhdWx0OyAtLW5vLWF1dG8taW5pdCB0byBkbyBpdCBtYW51YWxseScsXG4gICAgY29zdDogJ34kMTQwLTI2NS9tbycsXG4gICAgYmVzdEZvcjogJ0RldiAvIHN0YWdpbmcnLFxuICAgIGRlcGxveXM6ICd0aGUgcGxhdGZvcm0gb24gYSBzaW5nbGUgRUMyIGluc3RhbmNlIHZpYSBDbG91ZEZvcm1hdGlvbiDigJQgYSBWUEMsIHRoZSBpbnN0YW5jZSAocnVubmluZyB0aGUgTWluaWt1YmUgc3RhY2spLCBhbiBBTEIsIGEgUm91dGUgNTMgcmVjb3JkICsgQUNNIGNlcnQgZm9yIHRoZSBkb21haW4sIGFuZCAoYnkgZGVmYXVsdCkgU0VTIGVtYWlsLiBUaGUgaW5zdGFuY2UgcHVsbHMgaW1hZ2VzIG9uIGZpcnN0IGJvb3QuJyxcbiAgICBkZXN0cm95czogJ0RFTEVURVMgdGhlIENsb3VkRm9ybWF0aW9uIHN0YWNrOiB0aGUgVlBDLCBFQzIgaW5zdGFuY2UsIGFuZCBpdHMgRUJTIGRhdGEgdm9sdW1lIChkYXRhYmFzZXMsIHJlZ2lzdHJ5LCBwbHVnaW4gYnVpbGRzKS4gSXJyZXZlcnNpYmxlLicsXG4gICAgaG9zdFBvcnRzOiBbXSwgLy8gcmVtb3RlIChBV1MpIOKAlCBiaW5kcyBub3RoaW5nIG9uIHRoZSBvcGVyYXRvcidzIG1hY2hpbmVcbiAgfSxcbiAgZWtzOiB7XG4gICAgaWQ6ICdla3MnLFxuICAgIGxhYmVsOiAnQVdTIEVLUyBBdXRvIE1vZGUgKG1hbmFnZWQgS3ViZXJuZXRlcyknLFxuICAgIGRpcjogJ2RlcGxveS9hd3MvZWtzJyxcbiAgICBlbnRyeXBvaW50OiAnYmluL3NldHVwLnNoJyxcbiAgICBzcGFyc2VQYXRoczogWydkZXBsb3kvYXdzL2VrcyddLFxuICAgIHJlcXVpcmVkOiBbRE9NQUlOLCBIT1NURURfWk9ORV0sXG4gICAgb3B0aW9uYWw6IFtSRUdJT04sIERFUExPWV9NT0RFLCBHSENSX1RPS0VOLCBDTFVTVEVSX05BTUUsIEFVVE9fSU5JVCwgTk9fQVVUT19JTklULCAuLi5FTUFJTF0sXG4gICAgcG9zdERlcGxveTogJy4vZGVwbG95L2Jpbi9pbml0LXBsYXRmb3JtLnNoIGVrcyAgIyBhdXRvLXJ1bnMgYXQgdGhlIGVuZCBvZiBzZXR1cC5zaCBieSBkZWZhdWx0OyAtLW5vLWF1dG8taW5pdCB0byBkbyBpdCBtYW51YWxseScsXG4gICAgY29zdDogJ34kMTUwLTQwMC9tbycsXG4gICAgYmVzdEZvcjogJ1Byb2R1Y3Rpb24nLFxuICAgIGRlcGxveXM6ICd0aGUgcGxhdGZvcm0gb24gQW1hem9uIEVLUyBBdXRvIE1vZGUg4oCUIGFuIEFXUy1tYW5hZ2VkIEt1YmVybmV0ZXMgY2x1c3RlciAoS2FycGVudGVyLXNjYWxlZCBFQzIgbm9kZXMsIEFXUyBMb2FkIEJhbGFuY2VyIENvbnRyb2xsZXIsIEVCUy9FRlMgQ1NJKSwgdGhlIHNhbWUgS3ViZXJuZXRlcyB3b3JrbG9hZHMgYXMgdGhlIG90aGVyIGs4cyB0YXJnZXRzLCBhbiBBTEIgSW5ncmVzcyArIEFDTSBmb3IgdGhlIGRvbWFpbiwgYW5kIChieSBkZWZhdWx0KSBTRVMgZW1haWwuIFBsdWdpbiBidWlsZHMgcnVuIG9uIHRoZSBpbi1jbHVzdGVyIHJvb3RsZXNzIGJ1aWxka2l0ZCAoRUMyIG5vZGVzIGFsbG93IGl0KS4nLFxuICAgIGRlc3Ryb3lzOiAnUnVucyBiaW4vc2h1dGRvd24uc2g6IERFTEVURVMgdGhlIEVLUyBjbHVzdGVyICsgbm9kZXMgKGVrc2N0bCksIHRoZSBFRlMgZmlsZXN5c3RlbSwgYW5kIOKAlCB3aGVuIC0tZG9tYWluIGlzIHNldCDigJQgdGhlIEFDTSBjZXJ0ICsgUm91dGUgNTMgYWxpYXMuIEVCUyB2b2x1bWVzIG9uIHRoZSBSZXRhaW4gU3RvcmFnZUNsYXNzIGFyZSBOT1QgYXV0by1kZWxldGVkIChyZXBvcnRlZCBhdCB0aGUgZW5kKS4gSXJyZXZlcnNpYmxlLicsXG4gICAgaG9zdFBvcnRzOiBbXSwgLy8gcmVtb3RlIChBV1MpIOKAlCBiaW5kcyBub3RoaW5nIG9uIHRoZSBvcGVyYXRvcidzIG1hY2hpbmVcbiAgfSxcbn07XG5cbmV4cG9ydCBjb25zdCBUQVJHRVRfSURTOiByZWFkb25seSBUYXJnZXRJZFtdID0gWydkb2NrZXInLCAnbWluaWt1YmUnLCAnZWMyJywgJ2VrcyddO1xuXG5leHBvcnQgZnVuY3Rpb24gaXNUYXJnZXRJZCh2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIFRhcmdldElkIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgKFRBUkdFVF9JRFMgYXMgcmVhZG9ubHkgc3RyaW5nW10pLmluY2x1ZGVzKHZhbHVlKTtcbn1cblxuLy8gLS0tIFNwYXJzZSBib290c3RyYXAgcGF0aHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIEZvbGRlcnMgZXZlcnkgYC0tcmVwb2AgYm9vdHN0cmFwIG5lZWRzIHJlZ2FyZGxlc3Mgb2YgdGFyZ2V0OiB0aGUgb3JjaGVzdHJhdGlvblxuICogc2NyaXB0cy4gRWFjaCB0YXJnZXQncyBzZXR1cC5zaCArIGluaXQtcGxhdGZvcm0uc2ggbGl2ZSBpbiAvIGRyaXZlIHRoZXNlLlxuICogRGVsaWJlcmF0ZWx5IG1pbmltYWwg4oCUIGhlYXZpZXIgZm9sZGVycyAocGx1Z2lucy9jb21wbGlhbmNlL3NhbXBsZXMpIGFyZSBwdWxsZWRcbiAqIGluIG9ubHkgd2hlbiB0aGVpciBwb3N0LWluc3RhbGwgb3B0aW9uIGlzIHNlbGVjdGVkIChzZWUgTE9BRF9TVEVQUykuXG4gKi9cbmV4cG9ydCBjb25zdCBDT01NT05fU1BBUlNFX1BBVEhTOiByZWFkb25seSBzdHJpbmdbXSA9IFsnZGVwbG95L2JpbiddO1xuXG4vKipcbiAqIE9wdC1pbiBwb3N0LWluc3RhbGwgbG9hZCBzdGVwcy4gRWFjaCBtYXBzIGEgcHJvdmlzaW9uIGAtLXdpdGgtKmAgZmxhZyB0byB0aGVcbiAqIGluaXQtcGxhdGZvcm0gZW52IHZhciB0aGF0IGVuYWJsZXMgaXQgQU5EIHRoZSByZXBvIGZvbGRlcihzKSBpdCByZWFkcyDigJQgc28gdGhlXG4gKiBzcGFyc2UgY2hlY2tvdXQgZ3Jvd3MgZXhhY3RseSB3aXRoIHRoZSBzZWxlY3RlZCBvcHRpb25zLlxuICovXG5leHBvcnQgY29uc3QgTE9BRF9TVEVQUyA9IFtcbiAgLy8gVGhlIHBsdWdpbiBidWlsZCByZWFkcyBkZXBsb3kvcGx1Z2lucy9fYmFzZSBBTkQgZGVwbG95L2NvZGVidWlsZC9ib290c3RyYXAuXG4gIHsgaWQ6ICdwbHVnaW5zJywgZmxhZzogJ3dpdGhQbHVnaW5zJywgZW52OiAnTE9BRF9QTFVHSU5TJywgcGF0aHM6IFsnZGVwbG95L3BsdWdpbnMnLCAnZGVwbG95L2NvZGVidWlsZCddIH0sXG4gIHsgaWQ6ICdjb21wbGlhbmNlJywgZmxhZzogJ3dpdGhDb21wbGlhbmNlJywgZW52OiAnTE9BRF9DT01QTElBTkNFJywgcGF0aHM6IFsnZGVwbG95L2NvbXBsaWFuY2UnXSB9LFxuICB7IGlkOiAnc2FtcGxlcycsIGZsYWc6ICd3aXRoU2FtcGxlcycsIGVudjogJ0xPQURfVEVNUExBVEVTJywgcGF0aHM6IFsnZGVwbG95L3NhbXBsZXMnXSB9LFxuXSBhcyBjb25zdDtcblxuZXhwb3J0IHR5cGUgTG9hZFN0ZXBJZCA9ICh0eXBlb2YgTE9BRF9TVEVQUylbbnVtYmVyXVsnaWQnXTtcblxuLyoqXG4gKiBUaGUgZGUtZHVwbGljYXRlZCBzZXQgb2Ygc3BhcnNlIHBhdGhzIGZvciBhIHRhcmdldCBwbHVzIHRoZSBlbmFibGVkIGxvYWRcbiAqIHN0ZXBzOiBjb21tb24gYmFzZSDiiKogdGFyZ2V0IGZvbGRlcihzKSDiiKogZWFjaCBlbmFibGVkIHN0ZXAncyBmb2xkZXIocykuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzcGFyc2VQYXRoc0Zvcih0YXJnZXQ6IFRhcmdldElkLCBlbmFibGVkTG9hZElkczogcmVhZG9ubHkgc3RyaW5nW10pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IHBhdGhzID0gbmV3IFNldDxzdHJpbmc+KENPTU1PTl9TUEFSU0VfUEFUSFMpO1xuICBmb3IgKGNvbnN0IHAgb2YgVEFSR0VUU1t0YXJnZXRdLnNwYXJzZVBhdGhzKSBwYXRocy5hZGQocCk7XG4gIGZvciAoY29uc3Qgc3RlcCBvZiBMT0FEX1NURVBTKSB7XG4gICAgaWYgKGVuYWJsZWRMb2FkSWRzLmluY2x1ZGVzKHN0ZXAuaWQpKSBmb3IgKGNvbnN0IHAgb2Ygc3RlcC5wYXRocykgcGF0aHMuYWRkKHApO1xuICB9XG4gIHJldHVybiBbLi4ucGF0aHNdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFzc2VtYmxlUmVzdWx0IHtcbiAgLyoqIFRoZSBleGFjdCBjb21tYW5kIHRvIHJ1biDigJQgc2VjcmV0cyBtYXNrZWQgYXMgYCoqKmAuICovXG4gIHJlYWRvbmx5IGNvbW1hbmQ6IHN0cmluZztcbiAgLyoqIFJlcXVpcmVkIGlucHV0cyB0aGF0IHdlcmUgbm90IHN1cHBsaWVkLiAqL1xuICByZWFkb25seSBtaXNzaW5nOiByZWFkb25seSBJbnB1dFNwZWNbXTtcbn1cblxuLyoqXG4gKiBRdW90ZSBvbmx5IHdoZW4gdGhlIHZhbHVlIHdvdWxkIG90aGVyd2lzZSBiZSB3b3JkLXNwbGl0IG9yIG1pcy1wYXJzZWQgYnkgdGhlXG4gKiBzaGVsbCAod2hpdGVzcGFjZSBvciBlbWJlZGRlZCBxdW90ZXMpLiBgYXNzZXJ0U2hlbGxTYWZlYCBhbHJlYWR5IHJlamVjdHMgdGhlXG4gKiBkYW5nZXJvdXMgbWV0YWNoYXJhY3RlcnMsIHNvIHNpbXBsZSB0b2tlbnMgc3RheSB1bnF1b3RlZCBmb3IgcmVhZGFiaWxpdHkuXG4gKi9cbmZ1bmN0aW9uIG1heWJlU2hlbGxRdW90ZSh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIC9bXFxzJ1wiXS8udGVzdCh2YWx1ZSkgPyBzaGVsbFF1b3RlKHZhbHVlKSA6IHZhbHVlO1xufVxuXG4vKipcbiAqIEFzc2VtYmxlIHRoZSBkZXBsb3kgY29tbWFuZCBmb3IgYSB0YXJnZXQgZnJvbSB0aGUgcHJvdmlkZWQgcGFyYW1zLiBQdXJlIGFuZFxuICogZGV0ZXJtaW5pc3RpYyDigJQgbm8gc2hlbGwsIG5vIExMTS4gTWlzc2luZyByZXF1aXJlZCBpbnB1dHMgYXJlIHJlcG9ydGVkIChuZXZlclxuICogZ3Vlc3NlZCkuIEJ5IGRlZmF1bHQgc2VjcmV0cyBhcmUgbWFza2VkIChgKioqYCkgZm9yIERJU1BMQVk7IHBhc3MgYG1hc2s6IGZhbHNlYFxuICogdG8gYnVpbGQgdGhlIHJlYWwgY29tbWFuZCBmb3IgRVhFQ1VUSU9OIOKAlCB0aGF0IHN0cmluZyBtdXN0IG5ldmVyIGJlIGxvZ2dlZCBvclxuICogc2hvd24gdG8gdGhlIG1vZGVsLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZW1ibGVDb21tYW5kKFxuICB0YXJnZXQ6IFRhcmdldFNwZWMsXG4gIHBhcmFtczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIG9wdHM6IHsgbWFzaz86IGJvb2xlYW4gfSA9IHt9LFxuKTogQXNzZW1ibGVSZXN1bHQge1xuICBjb25zdCBtYXNrID0gb3B0cy5tYXNrID8/IHRydWU7XG4gIGNvbnN0IHByb3ZpZGVkID0gKHNwZWM6IElucHV0U3BlYyk6IGJvb2xlYW4gPT4ge1xuICAgIGNvbnN0IHYgPSBwYXJhbXNbc3BlYy5rZXldO1xuICAgIHJldHVybiB2ICE9PSB1bmRlZmluZWQgJiYgdiAhPT0gJycgJiYgdiAhPT0gZmFsc2U7XG4gIH07XG5cbiAgY29uc3QgbWlzc2luZyA9IHRhcmdldC5yZXF1aXJlZC5maWx0ZXIoKHNwZWMpID0+ICFwcm92aWRlZChzcGVjKSk7XG5cbiAgY29uc3QgcGFydHM6IHN0cmluZ1tdID0gW2BjZCAke3RhcmdldC5kaXJ9ICYmIGJhc2ggJHt0YXJnZXQuZW50cnlwb2ludH1gXTtcbiAgZm9yIChjb25zdCBzcGVjIG9mIFsuLi50YXJnZXQucmVxdWlyZWQsIC4uLnRhcmdldC5vcHRpb25hbF0pIHtcbiAgICBpZiAoIXByb3ZpZGVkKHNwZWMpKSBjb250aW51ZTtcbiAgICBpZiAoc3BlYy5ib29sZWFuKSB7XG4gICAgICBwYXJ0cy5wdXNoKGAtLSR7c3BlYy5mbGFnfWApO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IHJhdyA9IFN0cmluZyhwYXJhbXNbc3BlYy5rZXldKTtcbiAgICAvLyBUaGUgYXNzZW1ibGVkIGNvbW1hbmQgaXMgZXhlY3V0ZWQgdmlhIGEgc2hlbGwgKHJ1blNjcmlwdCksIHNvIGEgcGFyYW1cbiAgICAvLyB2YWx1ZSBjYXJyeWluZyBzaGVsbCBtZXRhY2hhcmFjdGVycyB3b3VsZCBiZSBjb21tYW5kIGluamVjdGlvbi4gVmFsaWRhdGVcbiAgICAvLyB0aGUgUkVBTCB2YWx1ZSBldmVuIHdoZW4gbWFza2luZyBmb3IgZGlzcGxheSDigJQgdGhlIGV4ZWN1dGVkIGNvbW1hbmQgdXNlc1xuICAgIC8vIHRoZSB1bm1hc2tlZCB2YWx1ZS4gUmVkYWN0IHNlY3JldHMgc28gdGhlIGVycm9yIG5ldmVyIGVjaG9lcyBhIHRva2VuLlxuICAgIGFzc2VydFNoZWxsU2FmZShyYXcsIGAtLSR7c3BlYy5mbGFnfWAsIHsgcmVkYWN0VmFsdWU6IHNwZWMuc2VjcmV0IH0pO1xuICAgIC8vIGFzc2VydFNoZWxsU2FmZSBzdGlsbCBwZXJtaXRzIHNwYWNlcyBhbmQgcXVvdGVzIChlLmcuIC0tZW1haWwtZnJvbS1uYW1lXG4gICAgLy8gXCJQaXBlbGluZSBCdWlsZGVyXCIsIG9yIE8nQnJpZW4pLCB3aGljaCB3b3VsZCB3b3JkLXNwbGl0IHdoZW4gZW1pdHRlZCBiYXJlO1xuICAgIC8vIHF1b3RlIHRob3NlIHNvIHRoZSB2YWx1ZSByZWFjaGVzIHRoZSBzY3JpcHQgYXMgYSBzaW5nbGUgYXJndW1lbnQuXG4gICAgY29uc3QgdmFsdWUgPSBzcGVjLnNlY3JldCAmJiBtYXNrID8gJyoqKicgOiBtYXliZVNoZWxsUXVvdGUocmF3KTtcbiAgICBwYXJ0cy5wdXNoKGAtLSR7c3BlYy5mbGFnfSAke3ZhbHVlfWApO1xuICB9XG5cbiAgcmV0dXJuIHsgY29tbWFuZDogcGFydHMuam9pbignIFxcXFxcXG4gICcpLCBtaXNzaW5nIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVhcmRvd25SZXN1bHQge1xuICAvKiogVGhlIGV4YWN0IHRlYXJkb3duIGNvbW1hbmQgdG8gcnVuLiAqL1xuICByZWFkb25seSBjb21tYW5kOiBzdHJpbmc7XG4gIC8qKiBXaGV0aGVyIHRoaXMgdGVhcmRvd24gaXJyZXZlcnNpYmx5IGRlc3Ryb3lzIGRhdGEgKEFXUyB0YXJnZXRzKS4gKi9cbiAgcmVhZG9ubHkgZGVzdHJ1Y3RpdmU6IGJvb2xlYW47XG59XG5cbi8qKiBDbG91ZEZvcm1hdGlvbiBzdGFjayBuYW1lIHRoZSBFQzIgc2V0dXAuc2ggZGVmYXVsdHMgdG8uICovXG5jb25zdCBERUZBVUxUX0VDMl9TVEFDSyA9ICdwaXBlbGluZS1idWlsZGVyJztcbi8qKiBFS1MgY2x1c3RlciBuYW1lIGVrc2N0bCBkZWZhdWx0cyB0by4gKi9cbmNvbnN0IERFRkFVTFRfRUtTX0NMVVNURVIgPSAncGlwZWxpbmUtYnVpbGRlcic7XG5cbi8qKlxuICogQXNzZW1ibGUgdGhlIHRlYXJkb3duIGNvbW1hbmQgZm9yIGEgdGFyZ2V0LiBQdXJlIGFuZCBkZXRlcm1pbmlzdGljIOKAlCBtaXJyb3JzXG4gKiBgYXNzZW1ibGVDb21tYW5kYCBmb3IgdGhlIGRlc3Ryb3kgcGF0aC4gbG9jYWwvbWluaWt1YmUgU1RPUCB0aGUgc3RhY2tcbiAqIChub24tZGVzdHJ1Y3RpdmUg4oCUIG9uLWRpc2sgLyBQVkMgZGF0YSBzdXJ2aXZlcyk7IGVjMiBERUxFVEVzIGl0cyBDbG91ZEZvcm1hdGlvblxuICogc3RhY2sgYW5kIGVrcyBERUxFVEVzIGl0cyBjbHVzdGVyIChla3NjdGwpIOKAlCBib3RoIGlycmV2ZXJzaWJsZS4gRUMyIGBkZWxldGUtc3RhY2tgXG4gKiBhbmQgYGVrc2N0bCBkZWxldGUgY2x1c3RlcmAgaGF2ZSBubyBuYXRpdmUgcHJvbXB0LCB3aGljaCBpcyBleGFjdGx5IHdoeSB0aGUgYWdlbnQnc1xuICogdHlwZWQtY29uZmlybWF0aW9uIGdhdGUgaXMgbWFuZGF0b3J5IHRoZXJlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdGVhcmRvd25Db21tYW5kKFxuICB0YXJnZXQ6IFRhcmdldElkLFxuICBvcHRzOiB7IHN0YWNrTmFtZT86IHN0cmluZzsgY2x1c3Rlck5hbWU/OiBzdHJpbmc7IHJlZ2lvbj86IHN0cmluZzsgZG9tYWluPzogc3RyaW5nOyBob3N0ZWRab25lSWQ/OiBzdHJpbmc7IGFzc3VtZVllcz86IGJvb2xlYW4gfSA9IHt9LFxuKTogVGVhcmRvd25SZXN1bHQge1xuICBjb25zdCByZWdpb24gPSByZXNvbHZlQXdzUmVnaW9uKG9wdHMucmVnaW9uKTtcbiAgLy8gQW55dGhpbmcgZmxvd2luZyB1bnF1b3RlZCBpbnRvIGEgc2hlbGwtZXhlY3V0ZWQgdGVhcmRvd24gY29tbWFuZCBpcyByZWplY3RlZFxuICAvLyBmb3Igc2hlbGwgbWV0YWNoYXJhY3RlcnMgKG1pcnJvcnMgYXNzZW1ibGVDb21tYW5kKS5cbiAgYXNzZXJ0U2hlbGxTYWZlKHJlZ2lvbiwgJ3JlZ2lvbicpO1xuICBpZiAob3B0cy5zdGFja05hbWUpIGFzc2VydFNoZWxsU2FmZShvcHRzLnN0YWNrTmFtZSwgJ3N0YWNrLW5hbWUnKTtcbiAgaWYgKG9wdHMuY2x1c3Rlck5hbWUpIGFzc2VydFNoZWxsU2FmZShvcHRzLmNsdXN0ZXJOYW1lLCAnY2x1c3Rlci1uYW1lJyk7XG4gIGlmIChvcHRzLmRvbWFpbikgYXNzZXJ0U2hlbGxTYWZlKG9wdHMuZG9tYWluLCAnZG9tYWluJyk7XG4gIGlmIChvcHRzLmhvc3RlZFpvbmVJZCkgYXNzZXJ0U2hlbGxTYWZlKG9wdHMuaG9zdGVkWm9uZUlkLCAnaG9zdGVkLXpvbmUtaWQnKTtcbiAgc3dpdGNoICh0YXJnZXQpIHtcbiAgICBjYXNlICdkb2NrZXInOlxuICAgICAgcmV0dXJuIHsgY29tbWFuZDogJ2NkIGRlcGxveS9sb2NhbC9kb2NrZXIgJiYgYmFzaCBiaW4vc2h1dGRvd24uc2gnLCBkZXN0cnVjdGl2ZTogZmFsc2UgfTtcbiAgICBjYXNlICdtaW5pa3ViZSc6XG4gICAgICByZXR1cm4geyBjb21tYW5kOiAnY2QgZGVwbG95L2xvY2FsL21pbmlrdWJlICYmIGJhc2ggYmluL3NodXRkb3duLnNoJywgZGVzdHJ1Y3RpdmU6IGZhbHNlIH07XG4gICAgY2FzZSAnZWMyJzoge1xuICAgICAgY29uc3Qgc3RhY2sgPSBvcHRzLnN0YWNrTmFtZSB8fCBERUZBVUxUX0VDMl9TVEFDSztcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbW1hbmQ6XG4gICAgICAgICAgYGF3cyBjbG91ZGZvcm1hdGlvbiBkZWxldGUtc3RhY2sgLS1zdGFjay1uYW1lICR7c3RhY2t9IC0tcmVnaW9uICR7cmVnaW9ufSAmJiBgICtcbiAgICAgICAgICBgYXdzIGNsb3VkZm9ybWF0aW9uIHdhaXQgc3RhY2stZGVsZXRlLWNvbXBsZXRlIC0tc3RhY2stbmFtZSAke3N0YWNrfSAtLXJlZ2lvbiAke3JlZ2lvbn1gLFxuICAgICAgICBkZXN0cnVjdGl2ZTogdHJ1ZSxcbiAgICAgIH07XG4gICAgfVxuICAgIGNhc2UgJ2Vrcyc6IHtcbiAgICAgIC8vIGVrcyB0ZWFycyBkb3duIHZpYSBiaW4vc2h1dGRvd24uc2ggKGxpa2UgbG9jYWwvbWluaWt1YmUgdXNlIGJpbi9zaHV0ZG93bi5zaCk6XG4gICAgICAvLyBpdCBkZWxldGVzIHRoZSBjbHVzdGVyIEFORCB0aGUgcmVzb3VyY2VzIGVrc2N0bCBhbG9uZSB3b3VsZCBvcnBoYW4g4oCUIHRoZSBFRlNcbiAgICAgIC8vIGZpbGVzeXN0ZW0gYW5kLCB3aGVuIC0tZG9tYWluIGlzIGdpdmVuLCB0aGUgQUNNIGNlcnQgKyBSb3V0ZSA1MyBhbGlhcy4gVGhlXG4gICAgICAvLyBhZ2VudCdzIHR5cGVkLWNvbmZpcm1hdGlvbiBnYXRlIGFscmVhZHkgcmFuLCBzbyBwYXNzIC0teWVzIHRvIHNraXAgdGhlXG4gICAgICAvLyBzY3JpcHQncyBvd24gcHJvbXB0LlxuICAgICAgY29uc3QgY2x1c3RlciA9IG9wdHMuY2x1c3Rlck5hbWUgfHwgREVGQVVMVF9FS1NfQ0xVU1RFUjtcbiAgICAgIGxldCBjb21tYW5kID0gYGNkIGRlcGxveS9hd3MvZWtzICYmIGJhc2ggYmluL3NodXRkb3duLnNoIC0tY2x1c3Rlci1uYW1lICR7Y2x1c3Rlcn0gLS1yZWdpb24gJHtyZWdpb259YDtcbiAgICAgIGlmIChvcHRzLmRvbWFpbikgY29tbWFuZCArPSBgIC0tZG9tYWluICR7b3B0cy5kb21haW59YDtcbiAgICAgIGlmIChvcHRzLmhvc3RlZFpvbmVJZCkgY29tbWFuZCArPSBgIC0taG9zdGVkLXpvbmUtaWQgJHtvcHRzLmhvc3RlZFpvbmVJZH1gO1xuICAgICAgaWYgKG9wdHMuYXNzdW1lWWVzKSBjb21tYW5kICs9ICcgLS15ZXMnO1xuICAgICAgcmV0dXJuIHsgY29tbWFuZCwgZGVzdHJ1Y3RpdmU6IHRydWUgfTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,13 @@
1
+ /** Cache dir for fetched tool binaries (kept across runs so we fetch once). */
2
+ export declare const TOOLS_DIR: string;
3
+ /** True when `tool` is a single-binary prereq provision knows how to fetch. */
4
+ export declare function isFetchable(tool: string): boolean;
5
+ /**
6
+ * Download `tool` into {@link TOOLS_DIR} (idempotent — skips if already present)
7
+ * and mark it executable. Returns true on success. Single-quoted args are
8
+ * injection-safe; `tool` is only ever a known key from {@link FETCHABLE}.
9
+ */
10
+ export declare function fetchTool(tool: string): boolean;
11
+ /** Prepend the tools cache dir to PATH so fetched binaries are discoverable. */
12
+ export declare function withToolsOnPath(): void;
13
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/agent/tools.ts"],"names":[],"mappings":"AAgBA,+EAA+E;AAC/E,eAAO,MAAM,SAAS,QAAwD,CAAC;AAwB/E,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AASD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAa/C;AAED,gFAAgF;AAChF,wBAAgB,eAAe,IAAI,IAAI,CAItC"}
@@ -0,0 +1,75 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * On-demand fetch of single-binary prerequisites (e.g. `yq`) so provision can
5
+ * satisfy a missing host tool WITHOUT a system install (no brew/apt). The binary
6
+ * is downloaded into a per-user cache dir; the caller prepends that dir to PATH
7
+ * so both the prereq checks (`has()` → `command -v`) and the deploy (`bash -lc`,
8
+ * which inherits process.env.PATH) find it.
9
+ */
10
+ import { execSync } from 'child_process';
11
+ import { existsSync, mkdirSync } from 'fs';
12
+ import * as os from 'os';
13
+ import * as path from 'path';
14
+ /** Cache dir for fetched tool binaries (kept across runs so we fetch once). */
15
+ export const TOOLS_DIR = path.join(os.homedir(), '.pipeline-manager', 'tools');
16
+ /**
17
+ * Tools that are a single self-contained binary we can fetch on demand, keyed by
18
+ * the prereq-check name. Each entry builds the release-asset URL for the host's
19
+ * OS + arch (assets use darwin|linux and arm64|amd64). Builders may resolve a
20
+ * version first (kubectl) — failures throw and fetchTool() reports them.
21
+ *
22
+ * NOT fetchable here (they aren't relocatable single binaries — keep the
23
+ * system/external install + the prereq block's instruction):
24
+ * - git → Xcode Command Line Tools (`xcode-select --install`) or `brew install git`
25
+ * - docker / docker compose → Docker Desktop (external host requirement)
26
+ * - aws → AWS CLI v2 is a pkg/zip installer, not a drop-in binary
27
+ * - openssl → ships with macOS/Linux; install via the system package manager
28
+ */
29
+ const FETCHABLE = {
30
+ yq: (osId, arch) => `https://github.com/mikefarah/yq/releases/latest/download/yq_${osId}_${arch}`,
31
+ minikube: (osId, arch) => `https://storage.googleapis.com/minikube/releases/latest/minikube-${osId}-${arch}`,
32
+ kubectl: (osId, arch) => {
33
+ const ver = execSync('curl -fsSL https://dl.k8s.io/release/stable.txt', { timeout: 15000 }).toString().trim();
34
+ return `https://dl.k8s.io/release/${ver}/bin/${osId}/${arch}/kubectl`;
35
+ },
36
+ };
37
+ /** True when `tool` is a single-binary prereq provision knows how to fetch. */
38
+ export function isFetchable(tool) {
39
+ return tool in FETCHABLE;
40
+ }
41
+ /** Host OS + arch in the naming the release assets use. */
42
+ function hostOsArch() {
43
+ const osId = process.platform === 'darwin' ? 'darwin' : 'linux';
44
+ const arch = process.arch === 'arm64' ? 'arm64' : 'amd64';
45
+ return { osId, arch };
46
+ }
47
+ /**
48
+ * Download `tool` into {@link TOOLS_DIR} (idempotent — skips if already present)
49
+ * and mark it executable. Returns true on success. Single-quoted args are
50
+ * injection-safe; `tool` is only ever a known key from {@link FETCHABLE}.
51
+ */
52
+ export function fetchTool(tool) {
53
+ const urlFor = FETCHABLE[tool];
54
+ if (!urlFor)
55
+ return false;
56
+ const dest = path.join(TOOLS_DIR, tool);
57
+ if (existsSync(dest))
58
+ return true;
59
+ const { osId, arch } = hostOsArch();
60
+ try {
61
+ mkdirSync(TOOLS_DIR, { recursive: true });
62
+ execSync(`curl -fsSL --output '${dest}' '${urlFor(osId, arch)}' && chmod +x '${dest}'`, { stdio: 'ignore', timeout: 120000 });
63
+ return existsSync(dest);
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ /** Prepend the tools cache dir to PATH so fetched binaries are discoverable. */
70
+ export function withToolsOnPath() {
71
+ if (!process.env.PATH?.split(path.delimiter).includes(TOOLS_DIR)) {
72
+ process.env.PATH = `${TOOLS_DIR}${path.delimiter}${process.env.PATH ?? ''}`;
73
+ }
74
+ }
75
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWdlbnQvdG9vbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzNDLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3pCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBRTdCLCtFQUErRTtBQUMvRSxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsbUJBQW1CLEVBQUUsT0FBTyxDQUFDLENBQUM7QUFFL0U7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxTQUFTLEdBQTJEO0lBQ3hFLEVBQUUsRUFBRSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLCtEQUErRCxJQUFJLElBQUksSUFBSSxFQUFFO0lBQ2pHLFFBQVEsRUFBRSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLG9FQUFvRSxJQUFJLElBQUksSUFBSSxFQUFFO0lBQzVHLE9BQU8sRUFBRSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsRUFBRTtRQUN0QixNQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsaURBQWlELEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUM5RyxPQUFPLDZCQUE2QixHQUFHLFFBQVEsSUFBSSxJQUFJLElBQUksVUFBVSxDQUFDO0lBQ3hFLENBQUM7Q0FDRixDQUFDO0FBRUYsK0VBQStFO0FBQy9FLE1BQU0sVUFBVSxXQUFXLENBQUMsSUFBWTtJQUN0QyxPQUFPLElBQUksSUFBSSxTQUFTLENBQUM7QUFDM0IsQ0FBQztBQUVELDJEQUEyRDtBQUMzRCxTQUFTLFVBQVU7SUFDakIsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFFBQVEsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO0lBQ2hFLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztJQUMxRCxPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO0FBQ3hCLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxJQUFZO0lBQ3BDLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMvQixJQUFJLENBQUMsTUFBTTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQzFCLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3hDLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ2xDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEdBQUcsVUFBVSxFQUFFLENBQUM7SUFDcEMsSUFBSSxDQUFDO1FBQ0gsU0FBUyxDQUFDLFNBQVMsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzFDLFFBQVEsQ0FBQyx3QkFBd0IsSUFBSSxNQUFNLE1BQU0sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixJQUFJLEdBQUcsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDOUgsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztBQUNILENBQUM7QUFFRCxnRkFBZ0Y7QUFDaEYsTUFBTSxVQUFVLGVBQWU7SUFDN0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDakUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsR0FBRyxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLEVBQUUsQ0FBQztJQUM5RSxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIE9uLWRlbWFuZCBmZXRjaCBvZiBzaW5nbGUtYmluYXJ5IHByZXJlcXVpc2l0ZXMgKGUuZy4gYHlxYCkgc28gcHJvdmlzaW9uIGNhblxuICogc2F0aXNmeSBhIG1pc3NpbmcgaG9zdCB0b29sIFdJVEhPVVQgYSBzeXN0ZW0gaW5zdGFsbCAobm8gYnJldy9hcHQpLiBUaGUgYmluYXJ5XG4gKiBpcyBkb3dubG9hZGVkIGludG8gYSBwZXItdXNlciBjYWNoZSBkaXI7IHRoZSBjYWxsZXIgcHJlcGVuZHMgdGhhdCBkaXIgdG8gUEFUSFxuICogc28gYm90aCB0aGUgcHJlcmVxIGNoZWNrcyAoYGhhcygpYCDihpIgYGNvbW1hbmQgLXZgKSBhbmQgdGhlIGRlcGxveSAoYGJhc2ggLWxjYCxcbiAqIHdoaWNoIGluaGVyaXRzIHByb2Nlc3MuZW52LlBBVEgpIGZpbmQgaXQuXG4gKi9cblxuaW1wb3J0IHsgZXhlY1N5bmMgfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIG9zIGZyb20gJ29zJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbi8qKiBDYWNoZSBkaXIgZm9yIGZldGNoZWQgdG9vbCBiaW5hcmllcyAoa2VwdCBhY3Jvc3MgcnVucyBzbyB3ZSBmZXRjaCBvbmNlKS4gKi9cbmV4cG9ydCBjb25zdCBUT09MU19ESVIgPSBwYXRoLmpvaW4ob3MuaG9tZWRpcigpLCAnLnBpcGVsaW5lLW1hbmFnZXInLCAndG9vbHMnKTtcblxuLyoqXG4gKiBUb29scyB0aGF0IGFyZSBhIHNpbmdsZSBzZWxmLWNvbnRhaW5lZCBiaW5hcnkgd2UgY2FuIGZldGNoIG9uIGRlbWFuZCwga2V5ZWQgYnlcbiAqIHRoZSBwcmVyZXEtY2hlY2sgbmFtZS4gRWFjaCBlbnRyeSBidWlsZHMgdGhlIHJlbGVhc2UtYXNzZXQgVVJMIGZvciB0aGUgaG9zdCdzXG4gKiBPUyArIGFyY2ggKGFzc2V0cyB1c2UgZGFyd2lufGxpbnV4IGFuZCBhcm02NHxhbWQ2NCkuIEJ1aWxkZXJzIG1heSByZXNvbHZlIGFcbiAqIHZlcnNpb24gZmlyc3QgKGt1YmVjdGwpIOKAlCBmYWlsdXJlcyB0aHJvdyBhbmQgZmV0Y2hUb29sKCkgcmVwb3J0cyB0aGVtLlxuICpcbiAqIE5PVCBmZXRjaGFibGUgaGVyZSAodGhleSBhcmVuJ3QgcmVsb2NhdGFibGUgc2luZ2xlIGJpbmFyaWVzIOKAlCBrZWVwIHRoZVxuICogc3lzdGVtL2V4dGVybmFsIGluc3RhbGwgKyB0aGUgcHJlcmVxIGJsb2NrJ3MgaW5zdHJ1Y3Rpb24pOlxuICogICAtIGdpdCAgICAgIOKGkiBYY29kZSBDb21tYW5kIExpbmUgVG9vbHMgKGB4Y29kZS1zZWxlY3QgLS1pbnN0YWxsYCkgb3IgYGJyZXcgaW5zdGFsbCBnaXRgXG4gKiAgIC0gZG9ja2VyIC8gZG9ja2VyIGNvbXBvc2Ug4oaSIERvY2tlciBEZXNrdG9wIChleHRlcm5hbCBob3N0IHJlcXVpcmVtZW50KVxuICogICAtIGF3cyAgICAgIOKGkiBBV1MgQ0xJIHYyIGlzIGEgcGtnL3ppcCBpbnN0YWxsZXIsIG5vdCBhIGRyb3AtaW4gYmluYXJ5XG4gKiAgIC0gb3BlbnNzbCAg4oaSIHNoaXBzIHdpdGggbWFjT1MvTGludXg7IGluc3RhbGwgdmlhIHRoZSBzeXN0ZW0gcGFja2FnZSBtYW5hZ2VyXG4gKi9cbmNvbnN0IEZFVENIQUJMRTogUmVjb3JkPHN0cmluZywgKG9zSWQ6IHN0cmluZywgYXJjaDogc3RyaW5nKSA9PiBzdHJpbmc+ID0ge1xuICB5cTogKG9zSWQsIGFyY2gpID0+IGBodHRwczovL2dpdGh1Yi5jb20vbWlrZWZhcmFoL3lxL3JlbGVhc2VzL2xhdGVzdC9kb3dubG9hZC95cV8ke29zSWR9XyR7YXJjaH1gLFxuICBtaW5pa3ViZTogKG9zSWQsIGFyY2gpID0+IGBodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb20vbWluaWt1YmUvcmVsZWFzZXMvbGF0ZXN0L21pbmlrdWJlLSR7b3NJZH0tJHthcmNofWAsXG4gIGt1YmVjdGw6IChvc0lkLCBhcmNoKSA9PiB7XG4gICAgY29uc3QgdmVyID0gZXhlY1N5bmMoJ2N1cmwgLWZzU0wgaHR0cHM6Ly9kbC5rOHMuaW8vcmVsZWFzZS9zdGFibGUudHh0JywgeyB0aW1lb3V0OiAxNTAwMCB9KS50b1N0cmluZygpLnRyaW0oKTtcbiAgICByZXR1cm4gYGh0dHBzOi8vZGwuazhzLmlvL3JlbGVhc2UvJHt2ZXJ9L2Jpbi8ke29zSWR9LyR7YXJjaH0va3ViZWN0bGA7XG4gIH0sXG59O1xuXG4vKiogVHJ1ZSB3aGVuIGB0b29sYCBpcyBhIHNpbmdsZS1iaW5hcnkgcHJlcmVxIHByb3Zpc2lvbiBrbm93cyBob3cgdG8gZmV0Y2guICovXG5leHBvcnQgZnVuY3Rpb24gaXNGZXRjaGFibGUodG9vbDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiB0b29sIGluIEZFVENIQUJMRTtcbn1cblxuLyoqIEhvc3QgT1MgKyBhcmNoIGluIHRoZSBuYW1pbmcgdGhlIHJlbGVhc2UgYXNzZXRzIHVzZS4gKi9cbmZ1bmN0aW9uIGhvc3RPc0FyY2goKTogeyBvc0lkOiBzdHJpbmc7IGFyY2g6IHN0cmluZyB9IHtcbiAgY29uc3Qgb3NJZCA9IHByb2Nlc3MucGxhdGZvcm0gPT09ICdkYXJ3aW4nID8gJ2RhcndpbicgOiAnbGludXgnO1xuICBjb25zdCBhcmNoID0gcHJvY2Vzcy5hcmNoID09PSAnYXJtNjQnID8gJ2FybTY0JyA6ICdhbWQ2NCc7XG4gIHJldHVybiB7IG9zSWQsIGFyY2ggfTtcbn1cblxuLyoqXG4gKiBEb3dubG9hZCBgdG9vbGAgaW50byB7QGxpbmsgVE9PTFNfRElSfSAoaWRlbXBvdGVudCDigJQgc2tpcHMgaWYgYWxyZWFkeSBwcmVzZW50KVxuICogYW5kIG1hcmsgaXQgZXhlY3V0YWJsZS4gUmV0dXJucyB0cnVlIG9uIHN1Y2Nlc3MuIFNpbmdsZS1xdW90ZWQgYXJncyBhcmVcbiAqIGluamVjdGlvbi1zYWZlOyBgdG9vbGAgaXMgb25seSBldmVyIGEga25vd24ga2V5IGZyb20ge0BsaW5rIEZFVENIQUJMRX0uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmZXRjaFRvb2wodG9vbDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IHVybEZvciA9IEZFVENIQUJMRVt0b29sXTtcbiAgaWYgKCF1cmxGb3IpIHJldHVybiBmYWxzZTtcbiAgY29uc3QgZGVzdCA9IHBhdGguam9pbihUT09MU19ESVIsIHRvb2wpO1xuICBpZiAoZXhpc3RzU3luYyhkZXN0KSkgcmV0dXJuIHRydWU7XG4gIGNvbnN0IHsgb3NJZCwgYXJjaCB9ID0gaG9zdE9zQXJjaCgpO1xuICB0cnkge1xuICAgIG1rZGlyU3luYyhUT09MU19ESVIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIGV4ZWNTeW5jKGBjdXJsIC1mc1NMIC0tb3V0cHV0ICcke2Rlc3R9JyAnJHt1cmxGb3Iob3NJZCwgYXJjaCl9JyAmJiBjaG1vZCAreCAnJHtkZXN0fSdgLCB7IHN0ZGlvOiAnaWdub3JlJywgdGltZW91dDogMTIwMDAwIH0pO1xuICAgIHJldHVybiBleGlzdHNTeW5jKGRlc3QpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLyoqIFByZXBlbmQgdGhlIHRvb2xzIGNhY2hlIGRpciB0byBQQVRIIHNvIGZldGNoZWQgYmluYXJpZXMgYXJlIGRpc2NvdmVyYWJsZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3aXRoVG9vbHNPblBhdGgoKTogdm9pZCB7XG4gIGlmICghcHJvY2Vzcy5lbnYuUEFUSD8uc3BsaXQocGF0aC5kZWxpbWl0ZXIpLmluY2x1ZGVzKFRPT0xTX0RJUikpIHtcbiAgICBwcm9jZXNzLmVudi5QQVRIID0gYCR7VE9PTFNfRElSfSR7cGF0aC5kZWxpbWl0ZXJ9JHtwcm9jZXNzLmVudi5QQVRIID8/ICcnfWA7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Deterministic known-issue matcher for deploy failures. This is the structured,
3
+ * safe complement to the LLM diagnosis: it recognizes well-known CloudFormation /
4
+ * deploy signatures and maps them to a concrete cause + suggestion, and — for a
5
+ * few — a param fix the executor can re-apply for a gated retry. Pattern matching
6
+ * on output is a script's job, not the model's; the LLM only adds free-form
7
+ * diagnosis on top.
8
+ */
9
+ export interface KnownIssue {
10
+ readonly id: string;
11
+ /** Plain-English root cause. */
12
+ readonly cause: string;
13
+ /** Concrete next step. */
14
+ readonly suggestion: string;
15
+ /** Whether a re-run can plausibly resolve it (deploy scripts are idempotent). */
16
+ readonly retryable: boolean;
17
+ /** A param the executor can set, then re-run automatically (gated). */
18
+ readonly paramFix?: {
19
+ readonly key: string;
20
+ readonly value: unknown;
21
+ };
22
+ }
23
+ /** Return every known issue whose signature appears in the failure output. */
24
+ export declare function matchIssues(failureText: string): KnownIssue[];
25
+ /**
26
+ * Post-deploy guidance to print after a successful deploy that enabled SES.
27
+ * Surfaces the two things the operator must act on (async DKIM, the sandbox).
28
+ */
29
+ export declare function sesPostDeployGuidance(): string[];
30
+ //# sourceMappingURL=troubleshoot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"troubleshoot.d.ts","sourceRoot":"","sources":["../../src/agent/troubleshoot.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0BAA0B;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;CACvE;AAwED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,EAAE,CAE7D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAMhD"}
@@ -0,0 +1,87 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ const RULES = [
4
+ {
5
+ // SES identity already verified in this account/region → reuse it.
6
+ // CFN phrasings vary: "Email identity … already exists", "SesEmailIdentity … AlreadyExists".
7
+ match: /(?:email\s*identity|ses[\s\S]{0,40}?identity|:identity\/)[\s\S]{0,160}?(?:already exists|AlreadyExists)/i,
8
+ issue: {
9
+ id: 'ses-identity-exists',
10
+ cause: 'The SES email identity for this domain already exists in the account/region.',
11
+ suggestion: 'Reuse it with --skip-ses-identity instead of creating a new one.',
12
+ retryable: true,
13
+ paramFix: { key: 'noCreateSesIdentity', value: true },
14
+ },
15
+ },
16
+ {
17
+ // A prior failed attempt left the stack un-updatable.
18
+ match: /ROLLBACK_COMPLETE|is in ROLLBACK_COMPLETE state and can not be updated/i,
19
+ issue: {
20
+ id: 'stack-rollback-complete',
21
+ cause: 'A previous attempt left the stack in ROLLBACK_COMPLETE — CloudFormation cannot update a stack in that state.',
22
+ suggestion: 'Delete the failed stack, then re-run. For ec2: `aws cloudformation delete-stack --stack-name <name>`. For eks (eksctl-managed stacks): `eksctl delete cluster --name <cluster>` (or `provision --target eks --teardown`). Destructive — not auto-applied.',
23
+ retryable: false,
24
+ },
25
+ },
26
+ {
27
+ match: /toomanyrequests|rate.?limit|HTTP 429|denied: requested access to the resource is denied/i,
28
+ issue: {
29
+ id: 'ghcr-rate-limit',
30
+ cause: 'ghcr.io anonymous pulls are rate-limited (60/hr) and tripped mid-deploy.',
31
+ suggestion: 'Pass --ghcr-token <GitHub PAT with read:packages>, then re-run.',
32
+ retryable: false, // needs a token value the agent does not hold
33
+ },
34
+ },
35
+ {
36
+ match: /ses:SendEmail|FromAddress|MessageRejected|Email address (?:is )?not verified/i,
37
+ issue: {
38
+ id: 'ses-from-mismatch',
39
+ cause: 'SES rejected the sender — the From address is not verified or not covered by the identity.',
40
+ suggestion: 'Make sure --email-from is on the verified domain; in the SES sandbox, verify the recipient too.',
41
+ retryable: false,
42
+ },
43
+ },
44
+ {
45
+ match: /ExpiredToken|InvalidClientTokenId|Unable to locate credentials|security token.*invalid|AuthFailure/i,
46
+ issue: {
47
+ id: 'aws-credentials',
48
+ cause: 'AWS credentials are missing or expired.',
49
+ suggestion: 'Refresh credentials (aws configure / AWS_PROFILE / SSO login), then re-run.',
50
+ retryable: false,
51
+ },
52
+ },
53
+ {
54
+ match: /(?:HostedZone|hosted zone)[\s\S]{0,80}?(?:not found|NoSuchHostedZone|does not exist)/i,
55
+ issue: {
56
+ id: 'hosted-zone-not-found',
57
+ cause: 'The Route 53 hosted zone could not be found.',
58
+ suggestion: 'Check --hosted-zone-id is the PUBLIC zone ID authoritative for --domain.',
59
+ retryable: false,
60
+ },
61
+ },
62
+ {
63
+ match: /Certificate[\s\S]{0,80}?(?:failed|timed out|PENDING_VALIDATION)|CertificateValidation.*(?:FAILED|timed out)/i,
64
+ issue: {
65
+ id: 'acm-validation',
66
+ cause: 'The ACM certificate did not validate in time — DNS validation needs the CNAME in the hosted zone, and propagation can take several minutes.',
67
+ suggestion: 'Confirm --hosted-zone-id matches --domain, then re-run to resume once DNS propagates.',
68
+ retryable: true, // a plain re-run can resume
69
+ },
70
+ },
71
+ ];
72
+ /** Return every known issue whose signature appears in the failure output. */
73
+ export function matchIssues(failureText) {
74
+ return RULES.filter((r) => r.match.test(failureText)).map((r) => r.issue);
75
+ }
76
+ /**
77
+ * Post-deploy guidance to print after a successful deploy that enabled SES.
78
+ * Surfaces the two things the operator must act on (async DKIM, the sandbox).
79
+ */
80
+ export function sesPostDeployGuidance() {
81
+ return [
82
+ 'DKIM verification is ASYNCHRONOUS (minutes–hours) — check SES console → Verified identities.',
83
+ 'New SES accounts are SANDBOXED: you can only send to verified recipients (200/day) until you request production access. To smoke-test in sandbox, verify a REAL recipient — never admin@internal.',
84
+ 'Bounces/complaints publish to the stack\'s SNS topic — subscribe to it (or pass --alert-email next time) to get warned before SES throttles you.',
85
+ ];
86
+ }
87
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJvdWJsZXNob290LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FnZW50L3Ryb3VibGVzaG9vdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBdUJ0QyxNQUFNLEtBQUssR0FBMEU7SUFDbkY7UUFDRSxtRUFBbUU7UUFDbkUsNkZBQTZGO1FBQzdGLEtBQUssRUFBRSwwR0FBMEc7UUFDakgsS0FBSyxFQUFFO1lBQ0wsRUFBRSxFQUFFLHFCQUFxQjtZQUN6QixLQUFLLEVBQUUsOEVBQThFO1lBQ3JGLFVBQVUsRUFBRSxrRUFBa0U7WUFDOUUsU0FBUyxFQUFFLElBQUk7WUFDZixRQUFRLEVBQUUsRUFBRSxHQUFHLEVBQUUscUJBQXFCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRTtTQUN0RDtLQUNGO0lBQ0Q7UUFDRSxzREFBc0Q7UUFDdEQsS0FBSyxFQUFFLHlFQUF5RTtRQUNoRixLQUFLLEVBQUU7WUFDTCxFQUFFLEVBQUUseUJBQXlCO1lBQzdCLEtBQUssRUFBRSw4R0FBOEc7WUFDckgsVUFBVSxFQUFFLDJQQUEyUDtZQUN2USxTQUFTLEVBQUUsS0FBSztTQUNqQjtLQUNGO0lBQ0Q7UUFDRSxLQUFLLEVBQUUsMEZBQTBGO1FBQ2pHLEtBQUssRUFBRTtZQUNMLEVBQUUsRUFBRSxpQkFBaUI7WUFDckIsS0FBSyxFQUFFLDBFQUEwRTtZQUNqRixVQUFVLEVBQUUsaUVBQWlFO1lBQzdFLFNBQVMsRUFBRSxLQUFLLEVBQUUsOENBQThDO1NBQ2pFO0tBQ0Y7SUFDRDtRQUNFLEtBQUssRUFBRSwrRUFBK0U7UUFDdEYsS0FBSyxFQUFFO1lBQ0wsRUFBRSxFQUFFLG1CQUFtQjtZQUN2QixLQUFLLEVBQUUsNEZBQTRGO1lBQ25HLFVBQVUsRUFBRSxpR0FBaUc7WUFDN0csU0FBUyxFQUFFLEtBQUs7U0FDakI7S0FDRjtJQUNEO1FBQ0UsS0FBSyxFQUFFLHFHQUFxRztRQUM1RyxLQUFLLEVBQUU7WUFDTCxFQUFFLEVBQUUsaUJBQWlCO1lBQ3JCLEtBQUssRUFBRSx5Q0FBeUM7WUFDaEQsVUFBVSxFQUFFLDZFQUE2RTtZQUN6RixTQUFTLEVBQUUsS0FBSztTQUNqQjtLQUNGO0lBQ0Q7UUFDRSxLQUFLLEVBQUUsdUZBQXVGO1FBQzlGLEtBQUssRUFBRTtZQUNMLEVBQUUsRUFBRSx1QkFBdUI7WUFDM0IsS0FBSyxFQUFFLDhDQUE4QztZQUNyRCxVQUFVLEVBQUUsMEVBQTBFO1lBQ3RGLFNBQVMsRUFBRSxLQUFLO1NBQ2pCO0tBQ0Y7SUFDRDtRQUNFLEtBQUssRUFBRSw4R0FBOEc7UUFDckgsS0FBSyxFQUFFO1lBQ0wsRUFBRSxFQUFFLGdCQUFnQjtZQUNwQixLQUFLLEVBQUUsNklBQTZJO1lBQ3BKLFVBQVUsRUFBRSx1RkFBdUY7WUFDbkcsU0FBUyxFQUFFLElBQUksRUFBRSw0QkFBNEI7U0FDOUM7S0FDRjtDQUNGLENBQUM7QUFFRiw4RUFBOEU7QUFDOUUsTUFBTSxVQUFVLFdBQVcsQ0FBQyxXQUFtQjtJQUM3QyxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDNUUsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxxQkFBcUI7SUFDbkMsT0FBTztRQUNMLDhGQUE4RjtRQUM5RixtTUFBbU07UUFDbk0sa0pBQWtKO0tBQ25KLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogRGV0ZXJtaW5pc3RpYyBrbm93bi1pc3N1ZSBtYXRjaGVyIGZvciBkZXBsb3kgZmFpbHVyZXMuIFRoaXMgaXMgdGhlIHN0cnVjdHVyZWQsXG4gKiBzYWZlIGNvbXBsZW1lbnQgdG8gdGhlIExMTSBkaWFnbm9zaXM6IGl0IHJlY29nbml6ZXMgd2VsbC1rbm93biBDbG91ZEZvcm1hdGlvbiAvXG4gKiBkZXBsb3kgc2lnbmF0dXJlcyBhbmQgbWFwcyB0aGVtIHRvIGEgY29uY3JldGUgY2F1c2UgKyBzdWdnZXN0aW9uLCBhbmQg4oCUIGZvciBhXG4gKiBmZXcg4oCUIGEgcGFyYW0gZml4IHRoZSBleGVjdXRvciBjYW4gcmUtYXBwbHkgZm9yIGEgZ2F0ZWQgcmV0cnkuIFBhdHRlcm4gbWF0Y2hpbmdcbiAqIG9uIG91dHB1dCBpcyBhIHNjcmlwdCdzIGpvYiwgbm90IHRoZSBtb2RlbCdzOyB0aGUgTExNIG9ubHkgYWRkcyBmcmVlLWZvcm1cbiAqIGRpYWdub3NpcyBvbiB0b3AuXG4gKi9cblxuZXhwb3J0IGludGVyZmFjZSBLbm93bklzc3VlIHtcbiAgcmVhZG9ubHkgaWQ6IHN0cmluZztcbiAgLyoqIFBsYWluLUVuZ2xpc2ggcm9vdCBjYXVzZS4gKi9cbiAgcmVhZG9ubHkgY2F1c2U6IHN0cmluZztcbiAgLyoqIENvbmNyZXRlIG5leHQgc3RlcC4gKi9cbiAgcmVhZG9ubHkgc3VnZ2VzdGlvbjogc3RyaW5nO1xuICAvKiogV2hldGhlciBhIHJlLXJ1biBjYW4gcGxhdXNpYmx5IHJlc29sdmUgaXQgKGRlcGxveSBzY3JpcHRzIGFyZSBpZGVtcG90ZW50KS4gKi9cbiAgcmVhZG9ubHkgcmV0cnlhYmxlOiBib29sZWFuO1xuICAvKiogQSBwYXJhbSB0aGUgZXhlY3V0b3IgY2FuIHNldCwgdGhlbiByZS1ydW4gYXV0b21hdGljYWxseSAoZ2F0ZWQpLiAqL1xuICByZWFkb25seSBwYXJhbUZpeD86IHsgcmVhZG9ubHkga2V5OiBzdHJpbmc7IHJlYWRvbmx5IHZhbHVlOiB1bmtub3duIH07XG59XG5cbmNvbnN0IFJVTEVTOiBSZWFkb25seUFycmF5PHsgcmVhZG9ubHkgbWF0Y2g6IFJlZ0V4cDsgcmVhZG9ubHkgaXNzdWU6IEtub3duSXNzdWUgfT4gPSBbXG4gIHtcbiAgICAvLyBTRVMgaWRlbnRpdHkgYWxyZWFkeSB2ZXJpZmllZCBpbiB0aGlzIGFjY291bnQvcmVnaW9uIOKGkiByZXVzZSBpdC5cbiAgICAvLyBDRk4gcGhyYXNpbmdzIHZhcnk6IFwiRW1haWwgaWRlbnRpdHkg4oCmIGFscmVhZHkgZXhpc3RzXCIsIFwiU2VzRW1haWxJZGVudGl0eSDigKYgQWxyZWFkeUV4aXN0c1wiLlxuICAgIG1hdGNoOiAvKD86ZW1haWxcXHMqaWRlbnRpdHl8c2VzW1xcc1xcU117MCw0MH0/aWRlbnRpdHl8OmlkZW50aXR5XFwvKVtcXHNcXFNdezAsMTYwfT8oPzphbHJlYWR5IGV4aXN0c3xBbHJlYWR5RXhpc3RzKS9pLFxuICAgIGlzc3VlOiB7XG4gICAgICBpZDogJ3Nlcy1pZGVudGl0eS1leGlzdHMnLFxuICAgICAgY2F1c2U6ICdUaGUgU0VTIGVtYWlsIGlkZW50aXR5IGZvciB0aGlzIGRvbWFpbiBhbHJlYWR5IGV4aXN0cyBpbiB0aGUgYWNjb3VudC9yZWdpb24uJyxcbiAgICAgIHN1Z2dlc3Rpb246ICdSZXVzZSBpdCB3aXRoIC0tc2tpcC1zZXMtaWRlbnRpdHkgaW5zdGVhZCBvZiBjcmVhdGluZyBhIG5ldyBvbmUuJyxcbiAgICAgIHJldHJ5YWJsZTogdHJ1ZSxcbiAgICAgIHBhcmFtRml4OiB7IGtleTogJ25vQ3JlYXRlU2VzSWRlbnRpdHknLCB2YWx1ZTogdHJ1ZSB9LFxuICAgIH0sXG4gIH0sXG4gIHtcbiAgICAvLyBBIHByaW9yIGZhaWxlZCBhdHRlbXB0IGxlZnQgdGhlIHN0YWNrIHVuLXVwZGF0YWJsZS5cbiAgICBtYXRjaDogL1JPTExCQUNLX0NPTVBMRVRFfGlzIGluIFJPTExCQUNLX0NPTVBMRVRFIHN0YXRlIGFuZCBjYW4gbm90IGJlIHVwZGF0ZWQvaSxcbiAgICBpc3N1ZToge1xuICAgICAgaWQ6ICdzdGFjay1yb2xsYmFjay1jb21wbGV0ZScsXG4gICAgICBjYXVzZTogJ0EgcHJldmlvdXMgYXR0ZW1wdCBsZWZ0IHRoZSBzdGFjayBpbiBST0xMQkFDS19DT01QTEVURSDigJQgQ2xvdWRGb3JtYXRpb24gY2Fubm90IHVwZGF0ZSBhIHN0YWNrIGluIHRoYXQgc3RhdGUuJyxcbiAgICAgIHN1Z2dlc3Rpb246ICdEZWxldGUgdGhlIGZhaWxlZCBzdGFjaywgdGhlbiByZS1ydW4uIEZvciBlYzI6IGBhd3MgY2xvdWRmb3JtYXRpb24gZGVsZXRlLXN0YWNrIC0tc3RhY2stbmFtZSA8bmFtZT5gLiBGb3IgZWtzIChla3NjdGwtbWFuYWdlZCBzdGFja3MpOiBgZWtzY3RsIGRlbGV0ZSBjbHVzdGVyIC0tbmFtZSA8Y2x1c3Rlcj5gIChvciBgcHJvdmlzaW9uIC0tdGFyZ2V0IGVrcyAtLXRlYXJkb3duYCkuIERlc3RydWN0aXZlIOKAlCBub3QgYXV0by1hcHBsaWVkLicsXG4gICAgICByZXRyeWFibGU6IGZhbHNlLFxuICAgIH0sXG4gIH0sXG4gIHtcbiAgICBtYXRjaDogL3Rvb21hbnlyZXF1ZXN0c3xyYXRlLj9saW1pdHxIVFRQIDQyOXxkZW5pZWQ6IHJlcXVlc3RlZCBhY2Nlc3MgdG8gdGhlIHJlc291cmNlIGlzIGRlbmllZC9pLFxuICAgIGlzc3VlOiB7XG4gICAgICBpZDogJ2doY3ItcmF0ZS1saW1pdCcsXG4gICAgICBjYXVzZTogJ2doY3IuaW8gYW5vbnltb3VzIHB1bGxzIGFyZSByYXRlLWxpbWl0ZWQgKDYwL2hyKSBhbmQgdHJpcHBlZCBtaWQtZGVwbG95LicsXG4gICAgICBzdWdnZXN0aW9uOiAnUGFzcyAtLWdoY3ItdG9rZW4gPEdpdEh1YiBQQVQgd2l0aCByZWFkOnBhY2thZ2VzPiwgdGhlbiByZS1ydW4uJyxcbiAgICAgIHJldHJ5YWJsZTogZmFsc2UsIC8vIG5lZWRzIGEgdG9rZW4gdmFsdWUgdGhlIGFnZW50IGRvZXMgbm90IGhvbGRcbiAgICB9LFxuICB9LFxuICB7XG4gICAgbWF0Y2g6IC9zZXM6U2VuZEVtYWlsfEZyb21BZGRyZXNzfE1lc3NhZ2VSZWplY3RlZHxFbWFpbCBhZGRyZXNzICg/OmlzICk/bm90IHZlcmlmaWVkL2ksXG4gICAgaXNzdWU6IHtcbiAgICAgIGlkOiAnc2VzLWZyb20tbWlzbWF0Y2gnLFxuICAgICAgY2F1c2U6ICdTRVMgcmVqZWN0ZWQgdGhlIHNlbmRlciDigJQgdGhlIEZyb20gYWRkcmVzcyBpcyBub3QgdmVyaWZpZWQgb3Igbm90IGNvdmVyZWQgYnkgdGhlIGlkZW50aXR5LicsXG4gICAgICBzdWdnZXN0aW9uOiAnTWFrZSBzdXJlIC0tZW1haWwtZnJvbSBpcyBvbiB0aGUgdmVyaWZpZWQgZG9tYWluOyBpbiB0aGUgU0VTIHNhbmRib3gsIHZlcmlmeSB0aGUgcmVjaXBpZW50IHRvby4nLFxuICAgICAgcmV0cnlhYmxlOiBmYWxzZSxcbiAgICB9LFxuICB9LFxuICB7XG4gICAgbWF0Y2g6IC9FeHBpcmVkVG9rZW58SW52YWxpZENsaWVudFRva2VuSWR8VW5hYmxlIHRvIGxvY2F0ZSBjcmVkZW50aWFsc3xzZWN1cml0eSB0b2tlbi4qaW52YWxpZHxBdXRoRmFpbHVyZS9pLFxuICAgIGlzc3VlOiB7XG4gICAgICBpZDogJ2F3cy1jcmVkZW50aWFscycsXG4gICAgICBjYXVzZTogJ0FXUyBjcmVkZW50aWFscyBhcmUgbWlzc2luZyBvciBleHBpcmVkLicsXG4gICAgICBzdWdnZXN0aW9uOiAnUmVmcmVzaCBjcmVkZW50aWFscyAoYXdzIGNvbmZpZ3VyZSAvIEFXU19QUk9GSUxFIC8gU1NPIGxvZ2luKSwgdGhlbiByZS1ydW4uJyxcbiAgICAgIHJldHJ5YWJsZTogZmFsc2UsXG4gICAgfSxcbiAgfSxcbiAge1xuICAgIG1hdGNoOiAvKD86SG9zdGVkWm9uZXxob3N0ZWQgem9uZSlbXFxzXFxTXXswLDgwfT8oPzpub3QgZm91bmR8Tm9TdWNoSG9zdGVkWm9uZXxkb2VzIG5vdCBleGlzdCkvaSxcbiAgICBpc3N1ZToge1xuICAgICAgaWQ6ICdob3N0ZWQtem9uZS1ub3QtZm91bmQnLFxuICAgICAgY2F1c2U6ICdUaGUgUm91dGUgNTMgaG9zdGVkIHpvbmUgY291bGQgbm90IGJlIGZvdW5kLicsXG4gICAgICBzdWdnZXN0aW9uOiAnQ2hlY2sgLS1ob3N0ZWQtem9uZS1pZCBpcyB0aGUgUFVCTElDIHpvbmUgSUQgYXV0aG9yaXRhdGl2ZSBmb3IgLS1kb21haW4uJyxcbiAgICAgIHJldHJ5YWJsZTogZmFsc2UsXG4gICAgfSxcbiAgfSxcbiAge1xuICAgIG1hdGNoOiAvQ2VydGlmaWNhdGVbXFxzXFxTXXswLDgwfT8oPzpmYWlsZWR8dGltZWQgb3V0fFBFTkRJTkdfVkFMSURBVElPTil8Q2VydGlmaWNhdGVWYWxpZGF0aW9uLiooPzpGQUlMRUR8dGltZWQgb3V0KS9pLFxuICAgIGlzc3VlOiB7XG4gICAgICBpZDogJ2FjbS12YWxpZGF0aW9uJyxcbiAgICAgIGNhdXNlOiAnVGhlIEFDTSBjZXJ0aWZpY2F0ZSBkaWQgbm90IHZhbGlkYXRlIGluIHRpbWUg4oCUIEROUyB2YWxpZGF0aW9uIG5lZWRzIHRoZSBDTkFNRSBpbiB0aGUgaG9zdGVkIHpvbmUsIGFuZCBwcm9wYWdhdGlvbiBjYW4gdGFrZSBzZXZlcmFsIG1pbnV0ZXMuJyxcbiAgICAgIHN1Z2dlc3Rpb246ICdDb25maXJtIC0taG9zdGVkLXpvbmUtaWQgbWF0Y2hlcyAtLWRvbWFpbiwgdGhlbiByZS1ydW4gdG8gcmVzdW1lIG9uY2UgRE5TIHByb3BhZ2F0ZXMuJyxcbiAgICAgIHJldHJ5YWJsZTogdHJ1ZSwgLy8gYSBwbGFpbiByZS1ydW4gY2FuIHJlc3VtZVxuICAgIH0sXG4gIH0sXG5dO1xuXG4vKiogUmV0dXJuIGV2ZXJ5IGtub3duIGlzc3VlIHdob3NlIHNpZ25hdHVyZSBhcHBlYXJzIGluIHRoZSBmYWlsdXJlIG91dHB1dC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXRjaElzc3VlcyhmYWlsdXJlVGV4dDogc3RyaW5nKTogS25vd25Jc3N1ZVtdIHtcbiAgcmV0dXJuIFJVTEVTLmZpbHRlcigocikgPT4gci5tYXRjaC50ZXN0KGZhaWx1cmVUZXh0KSkubWFwKChyKSA9PiByLmlzc3VlKTtcbn1cblxuLyoqXG4gKiBQb3N0LWRlcGxveSBndWlkYW5jZSB0byBwcmludCBhZnRlciBhIHN1Y2Nlc3NmdWwgZGVwbG95IHRoYXQgZW5hYmxlZCBTRVMuXG4gKiBTdXJmYWNlcyB0aGUgdHdvIHRoaW5ncyB0aGUgb3BlcmF0b3IgbXVzdCBhY3Qgb24gKGFzeW5jIERLSU0sIHRoZSBzYW5kYm94KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlc1Bvc3REZXBsb3lHdWlkYW5jZSgpOiBzdHJpbmdbXSB7XG4gIHJldHVybiBbXG4gICAgJ0RLSU0gdmVyaWZpY2F0aW9uIGlzIEFTWU5DSFJPTk9VUyAobWludXRlc+KAk2hvdXJzKSDigJQgY2hlY2sgU0VTIGNvbnNvbGUg4oaSIFZlcmlmaWVkIGlkZW50aXRpZXMuJyxcbiAgICAnTmV3IFNFUyBhY2NvdW50cyBhcmUgU0FOREJPWEVEOiB5b3UgY2FuIG9ubHkgc2VuZCB0byB2ZXJpZmllZCByZWNpcGllbnRzICgyMDAvZGF5KSB1bnRpbCB5b3UgcmVxdWVzdCBwcm9kdWN0aW9uIGFjY2Vzcy4gVG8gc21va2UtdGVzdCBpbiBzYW5kYm94LCB2ZXJpZnkgYSBSRUFMIHJlY2lwaWVudCDigJQgbmV2ZXIgYWRtaW5AaW50ZXJuYWwuJyxcbiAgICAnQm91bmNlcy9jb21wbGFpbnRzIHB1Ymxpc2ggdG8gdGhlIHN0YWNrXFwncyBTTlMgdG9waWMg4oCUIHN1YnNjcmliZSB0byBpdCAob3IgcGFzcyAtLWFsZXJ0LWVtYWlsIG5leHQgdGltZSkgdG8gZ2V0IHdhcm5lZCBiZWZvcmUgU0VTIHRocm90dGxlcyB5b3UuJyxcbiAgXTtcbn1cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=boilerplate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boilerplate.d.ts","sourceRoot":"","sources":["../src/boilerplate.ts"],"names":[],"mappings":""}