@intentius/chant 0.124.44 → 0.124.46

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 (249) hide show
  1. package/dist/capabilities/aws.paths +148 -0
  2. package/dist/capabilities/base-mappings.json +122 -0
  3. package/dist/capabilities/catalog.d.ts +89 -0
  4. package/dist/capabilities/catalog.d.ts.map +1 -0
  5. package/dist/capabilities/catalog.js +204 -0
  6. package/dist/capabilities/language.d.ts +103 -0
  7. package/dist/capabilities/language.d.ts.map +1 -0
  8. package/dist/capabilities/language.js +335 -0
  9. package/dist/capabilities/matcher.d.ts +65 -0
  10. package/dist/capabilities/matcher.d.ts.map +1 -0
  11. package/dist/capabilities/matcher.js +299 -0
  12. package/dist/capabilities/view.d.ts +207 -0
  13. package/dist/capabilities/view.d.ts.map +1 -0
  14. package/dist/capabilities/view.js +484 -0
  15. package/dist/ci-identity.d.ts +183 -12
  16. package/dist/ci-identity.d.ts.map +1 -1
  17. package/dist/ci-identity.js +362 -53
  18. package/dist/cli/commands/lint.d.ts.map +1 -1
  19. package/dist/cli/commands/lint.js +1 -0
  20. package/dist/cli/handlers/build.d.ts.map +1 -1
  21. package/dist/cli/handlers/build.js +17 -1
  22. package/dist/cli/handlers/declared-graph.d.ts +44 -0
  23. package/dist/cli/handlers/declared-graph.d.ts.map +1 -0
  24. package/dist/cli/handlers/declared-graph.js +87 -0
  25. package/dist/cli/handlers/graph.d.ts +25 -0
  26. package/dist/cli/handlers/graph.d.ts.map +1 -1
  27. package/dist/cli/handlers/graph.js +93 -87
  28. package/dist/cli/handlers/pr-env.d.ts +8 -2
  29. package/dist/cli/handlers/pr-env.d.ts.map +1 -1
  30. package/dist/cli/handlers/pr-env.js +127 -225
  31. package/dist/cli/handlers/pr.d.ts +3 -0
  32. package/dist/cli/handlers/pr.d.ts.map +1 -1
  33. package/dist/cli/handlers/pr.js +1 -0
  34. package/dist/cli/handlers/search-count.d.ts +89 -0
  35. package/dist/cli/handlers/search-count.d.ts.map +1 -0
  36. package/dist/cli/handlers/search-count.js +132 -0
  37. package/dist/cli/handlers/search.d.ts +358 -6
  38. package/dist/cli/handlers/search.d.ts.map +1 -1
  39. package/dist/cli/handlers/search.js +1065 -155
  40. package/dist/cli/main.d.ts.map +1 -1
  41. package/dist/cli/main.js +23 -3
  42. package/dist/cli/mcp/server.d.ts.map +1 -1
  43. package/dist/cli/mcp/server.js +3 -0
  44. package/dist/cli/mcp/tools/capabilities.d.ts +7 -0
  45. package/dist/cli/mcp/tools/capabilities.d.ts.map +1 -0
  46. package/dist/cli/mcp/tools/capabilities.js +27 -0
  47. package/dist/cli/mcp/workspace-tools.d.ts +3 -1
  48. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  49. package/dist/cli/mcp/workspace-tools.js +47 -2
  50. package/dist/cli/parse-args.d.ts.map +1 -1
  51. package/dist/cli/parse-args.js +64 -17
  52. package/dist/cli/registry.d.ts +22 -0
  53. package/dist/cli/registry.d.ts.map +1 -1
  54. package/dist/components/cli-support.d.ts +2 -0
  55. package/dist/components/cli-support.d.ts.map +1 -1
  56. package/dist/components/cli-support.js +4 -2
  57. package/dist/components/fan-out-support.d.ts +3 -0
  58. package/dist/components/fan-out-support.d.ts.map +1 -1
  59. package/dist/components/fan-out-support.js +1 -1
  60. package/dist/components/pr-env-ports.d.ts +29 -0
  61. package/dist/components/pr-env-ports.d.ts.map +1 -0
  62. package/dist/components/pr-env-ports.js +77 -0
  63. package/dist/components/pr-env-run.d.ts +254 -0
  64. package/dist/components/pr-env-run.d.ts.map +1 -0
  65. package/dist/components/pr-env-run.js +376 -0
  66. package/dist/components/pr-environment.d.ts +91 -15
  67. package/dist/components/pr-environment.d.ts.map +1 -1
  68. package/dist/components/pr-environment.js +95 -9
  69. package/dist/components/pr-pipeline.d.ts +10 -1
  70. package/dist/components/pr-pipeline.d.ts.map +1 -1
  71. package/dist/config-environments.d.ts +92 -0
  72. package/dist/config-environments.d.ts.map +1 -0
  73. package/dist/config-environments.js +102 -0
  74. package/dist/config.d.ts +24 -84
  75. package/dist/config.d.ts.map +1 -1
  76. package/dist/config.js +9 -96
  77. package/dist/graph-detail.d.ts.map +1 -1
  78. package/dist/graph-detail.js +15 -3
  79. package/dist/graph-effective.d.ts +33 -2
  80. package/dist/graph-effective.d.ts.map +1 -1
  81. package/dist/graph-effective.js +215 -68
  82. package/dist/graph-ir.d.ts +23 -0
  83. package/dist/graph-ir.d.ts.map +1 -1
  84. package/dist/graph-ir.js +130 -0
  85. package/dist/graph-sub-template.d.ts +11 -0
  86. package/dist/graph-sub-template.d.ts.map +1 -0
  87. package/dist/graph-sub-template.js +19 -0
  88. package/dist/lexicon.d.ts +9 -0
  89. package/dist/lexicon.d.ts.map +1 -1
  90. package/dist/lifecycle/observe.d.ts +28 -0
  91. package/dist/lifecycle/observe.d.ts.map +1 -1
  92. package/dist/lifecycle/observe.js +23 -1
  93. package/dist/lint/rule.d.ts +6 -0
  94. package/dist/lint/rule.d.ts.map +1 -1
  95. package/dist/live-endpoint.d.ts +1 -1
  96. package/dist/live-endpoint.d.ts.map +1 -1
  97. package/dist/live-endpoint.js +1 -1
  98. package/dist/observation.d.ts +48 -1
  99. package/dist/observation.d.ts.map +1 -1
  100. package/dist/observation.js +21 -5
  101. package/dist/op/activities/activity-contracts.d.ts +4 -4
  102. package/dist/op/op-waves.d.ts +17 -0
  103. package/dist/op/op-waves.d.ts.map +1 -1
  104. package/dist/op/op-waves.js +23 -1
  105. package/dist/pr-forge.d.ts +15 -1
  106. package/dist/pr-forge.d.ts.map +1 -1
  107. package/dist/pr-forge.js +28 -16
  108. package/dist/pr-requires.d.ts +5 -1
  109. package/dist/pr-requires.d.ts.map +1 -1
  110. package/dist/wave-runtime.mjs +251 -250
  111. package/dist/workspace/capabilities-contract.d.ts +66 -0
  112. package/dist/workspace/capabilities-contract.d.ts.map +1 -0
  113. package/dist/workspace/capabilities-contract.js +107 -0
  114. package/dist/workspace/capabilities.schema.json +229 -0
  115. package/dist/workspace/ci-cloud-identity.d.ts +3 -1
  116. package/dist/workspace/ci-cloud-identity.d.ts.map +1 -1
  117. package/dist/workspace/ci-cloud-identity.js +16 -1
  118. package/dist/workspace/ci-run.d.ts +35 -8
  119. package/dist/workspace/ci-run.d.ts.map +1 -1
  120. package/dist/workspace/ci-run.js +95 -21
  121. package/dist/workspace/ci-secrets.d.ts.map +1 -1
  122. package/dist/workspace/ci-secrets.js +4 -3
  123. package/dist/workspace/compose-graph.d.ts +9 -0
  124. package/dist/workspace/compose-graph.d.ts.map +1 -1
  125. package/dist/workspace/compose-graph.js +3 -1
  126. package/dist/workspace/conformance/index.d.ts +1 -1
  127. package/dist/workspace/conformance/index.d.ts.map +1 -1
  128. package/dist/workspace/conformance/index.js +39 -2
  129. package/dist/workspace/declaration.d.ts +10 -0
  130. package/dist/workspace/declaration.d.ts.map +1 -1
  131. package/dist/workspace/declaration.js +17 -1
  132. package/dist/workspace/declaration.schema.json +36 -1
  133. package/dist/workspace/graph-cache.d.ts +8 -0
  134. package/dist/workspace/graph-cache.d.ts.map +1 -1
  135. package/dist/workspace/graph-cache.js +27 -3
  136. package/dist/workspace/graph-cli.d.ts +39 -2
  137. package/dist/workspace/graph-cli.d.ts.map +1 -1
  138. package/dist/workspace/graph-cli.js +66 -24
  139. package/dist/workspace/graph.schema.json +148 -0
  140. package/dist/workspace/kind-readers.d.ts +3 -0
  141. package/dist/workspace/kind-readers.d.ts.map +1 -1
  142. package/dist/workspace/kind-readers.js +7 -1
  143. package/dist/workspace/member-commands.d.ts +10 -1
  144. package/dist/workspace/member-commands.d.ts.map +1 -1
  145. package/dist/workspace/member-commands.js +17 -1
  146. package/dist/workspace/nested-graph.d.ts +2 -0
  147. package/dist/workspace/nested-graph.d.ts.map +1 -1
  148. package/dist/workspace/nested-graph.js +32 -1
  149. package/dist/workspace/reason-codes.d.ts +10 -0
  150. package/dist/workspace/reason-codes.d.ts.map +1 -1
  151. package/dist/workspace/reason-codes.js +12 -0
  152. package/dist/workspace/search-cli.d.ts +204 -0
  153. package/dist/workspace/search-cli.d.ts.map +1 -0
  154. package/dist/workspace/search-cli.js +466 -0
  155. package/dist/workspace/search-contract.d.ts +56 -0
  156. package/dist/workspace/search-contract.d.ts.map +1 -0
  157. package/dist/workspace/search-contract.js +70 -0
  158. package/dist/workspace/search.schema.json +822 -0
  159. package/package.json +1 -1
  160. package/src/__snapshots__/okf.test.ts.snap +10 -0
  161. package/src/capabilities/aws.paths +148 -0
  162. package/src/capabilities/base-mappings.json +122 -0
  163. package/src/capabilities/catalog.ts +230 -0
  164. package/src/capabilities/language.test.ts +191 -0
  165. package/src/capabilities/language.ts +373 -0
  166. package/src/capabilities/matcher.ts +315 -0
  167. package/src/capabilities/view-compose.test.ts +76 -0
  168. package/src/capabilities/view.ts +631 -0
  169. package/src/ci-identity-targets.test.ts +275 -0
  170. package/src/ci-identity.ts +394 -61
  171. package/src/cli/commands/lint.ts +1 -0
  172. package/src/cli/handlers/build.ts +15 -1
  173. package/src/cli/handlers/declared-graph.ts +99 -0
  174. package/src/cli/handlers/graph.test.ts +94 -3
  175. package/src/cli/handlers/graph.ts +123 -96
  176. package/src/cli/handlers/pr-env.ts +135 -227
  177. package/src/cli/handlers/pr.ts +4 -0
  178. package/src/cli/handlers/search-build-roots.test.ts +144 -0
  179. package/src/cli/handlers/search-count.test.ts +191 -0
  180. package/src/cli/handlers/search-count.ts +165 -0
  181. package/src/cli/handlers/search-json.test.ts +333 -0
  182. package/src/cli/handlers/search-live.test.ts +387 -0
  183. package/src/cli/handlers/search-paths.test.ts +235 -0
  184. package/src/cli/handlers/search.ts +1312 -166
  185. package/src/cli/main.test.ts +28 -3
  186. package/src/cli/main.ts +23 -3
  187. package/src/cli/mcp/server.test.ts +3 -3
  188. package/src/cli/mcp/server.ts +3 -0
  189. package/src/cli/mcp/tools/capabilities.ts +32 -0
  190. package/src/cli/mcp/workspace-tools.e2e.test.ts +21 -1
  191. package/src/cli/mcp/workspace-tools.ts +47 -2
  192. package/src/cli/parse-args.ts +52 -13
  193. package/src/cli/registry.ts +22 -0
  194. package/src/components/cli-support.ts +6 -1
  195. package/src/components/fan-out-support.ts +4 -1
  196. package/src/components/pr-env-ports.ts +89 -0
  197. package/src/components/pr-env-run-bundle.test.ts +54 -0
  198. package/src/components/pr-env-run.test.ts +290 -0
  199. package/src/components/pr-env-run.ts +563 -0
  200. package/src/components/pr-environment.ts +161 -13
  201. package/src/components/pr-pipeline.ts +10 -1
  202. package/src/config-environments.ts +133 -0
  203. package/src/config.ts +37 -124
  204. package/src/graph-detail.ts +15 -3
  205. package/src/graph-effective.ts +226 -75
  206. package/src/graph-ir.test.ts +163 -0
  207. package/src/graph-ir.ts +147 -0
  208. package/src/graph-sub-template.ts +22 -0
  209. package/src/lexicon.ts +10 -0
  210. package/src/lifecycle/observe.test.ts +27 -1
  211. package/src/lifecycle/observe.ts +43 -1
  212. package/src/lint/rule.ts +6 -0
  213. package/src/live-endpoint.ts +1 -1
  214. package/src/observation.test.ts +25 -0
  215. package/src/observation.ts +69 -5
  216. package/src/op/op-waves.ts +38 -1
  217. package/src/pr-forge-bundle.test.ts +1 -1
  218. package/src/pr-forge.ts +44 -17
  219. package/src/pr-requires.test.ts +43 -6
  220. package/src/pr-requires.ts +5 -1
  221. package/src/workspace/capabilities-contract.test.ts +88 -0
  222. package/src/workspace/capabilities-contract.ts +132 -0
  223. package/src/workspace/capabilities.schema.json +229 -0
  224. package/src/workspace/ci-cloud-identity.test.ts +20 -0
  225. package/src/workspace/ci-cloud-identity.ts +14 -1
  226. package/src/workspace/ci-run.test.ts +74 -1
  227. package/src/workspace/ci-run.ts +122 -29
  228. package/src/workspace/ci-secrets.test.ts +1 -1
  229. package/src/workspace/ci-secrets.ts +4 -3
  230. package/src/workspace/compose-graph.ts +10 -1
  231. package/src/workspace/conformance/conformance.e2e.test.ts +14 -1
  232. package/src/workspace/conformance/index.ts +31 -2
  233. package/src/workspace/declaration.schema.json +36 -1
  234. package/src/workspace/declaration.test.ts +7 -0
  235. package/src/workspace/declaration.ts +24 -2
  236. package/src/workspace/graph-cache.ts +27 -3
  237. package/src/workspace/graph-cli.ts +96 -24
  238. package/src/workspace/graph.schema.json +148 -0
  239. package/src/workspace/kind-readers.e2e.test.ts +28 -0
  240. package/src/workspace/kind-readers.test.ts +1 -1
  241. package/src/workspace/kind-readers.ts +7 -1
  242. package/src/workspace/member-commands.ts +22 -1
  243. package/src/workspace/nested-graph.ts +32 -1
  244. package/src/workspace/reason-codes.test.ts +7 -0
  245. package/src/workspace/reason-codes.ts +12 -0
  246. package/src/workspace/search-cli.e2e.test.ts +305 -0
  247. package/src/workspace/search-cli.ts +591 -0
  248. package/src/workspace/search-contract.ts +95 -0
  249. package/src/workspace/search.schema.json +822 -0
@@ -25,17 +25,24 @@
25
25
  * `down` reads the environment's record on chant/lifecycle, checks it names
26
26
  * this pull request's environment, and tears down what `planTeardown` finds
27
27
  * under the record's marker, after dropping any entry whose marker is not
28
- * exactly that one. No gate holds it: closing the pull request is the
29
- * decision, as is the TTL the base set for `sweep`.
28
+ * exactly that one. The lexicons tear down what they own, and the command
29
+ * `ci.prEnvironment.teardown` names tears down the rest (#4330). No gate
30
+ * holds it: closing the pull request is the decision, as is the TTL the base
31
+ * set for `sweep`.
32
+ *
33
+ * The runs themselves are ../../components/pr-env-run.ts, which a product
34
+ * calls with an adapter of its own (#4330). This file supplies the
35
+ * components adapter and the CLI's ports.
30
36
  */
31
37
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
32
38
  import { join, resolve } from "node:path";
33
39
  import { loadChantConfig } from "../../config.js";
34
40
  import { ENV_VAR } from "../../env.js";
35
41
  import { isEmptyChangeSet } from "../../change-set.js";
36
- import { PR_ENV_EXIT, PR_ENV_GATE, PR_ENV_LEDGER_DIR, PR_ENV_LEDGER_FILE, PR_ENV_RECORD_FILE, PR_ENV_REPORT_DIR, acceptHandedRecord, handedPrEnvReport, PR_ENV_TEMPLATE_VAR, derivePrEnvironment, expired, livePrEnvironments, parsePrEnvRecords, prEnvApproveCommand, prEnvNoteMarker, prEnvStatusContext, prEnvStatusDescription, prEnvStatusState, prEnvironmentName, renderPrEnvNote, teardownComplete, teardownCounts, tearDownPrEnvironment, ttlMs, } from "../../components/pr-environment.js";
37
- import { applyPrSet, approvalOf, decidePrGate, readOnlyLedger } from "../../components/pr-run.js";
38
- import { gitGateLedgerPort } from "../../op/gate.js";
42
+ import { PR_ENV_EXIT, PR_ENV_GATE, PR_ENV_RECORD_FILE, PR_ENV_REPORT_DIR, acceptHandedRecord, handedPrEnvReport, PR_ENV_TEMPLATE_VAR, derivePrEnvironment, prEnvApproveCommand, prEnvStatusState, prEnvironmentName, prEnvironmentSite, renderPrEnvNote, ttlMs, } from "../../components/pr-environment.js";
43
+ import { commandTeardownAdapter, prEnvDown as prEnvDownRun, prEnvOp, prEnvSweep as prEnvSweepRun, prEnvUp as prEnvUpRun, } from "../../components/pr-env-run.js";
44
+ import { forgePrEnvPublisher, lifecyclePrEnvPorts } from "../../components/pr-env-ports.js";
45
+ import { applyPrSet } from "../../components/pr-run.js";
39
46
  import { prOp } from "../../pr-loop.js";
40
47
  import { FORGE_KINDS, forgeFromEnv, forgePrincipalOf } from "../../pr-forge.js";
41
48
  import { formatError, formatInfo, formatWarning } from "../format.js";
@@ -77,36 +84,29 @@ function actor() {
77
84
  function memberOf(ctx) {
78
85
  return ctx.args.members?.length === 1 ? ctx.args.members[0] : undefined;
79
86
  }
80
- // ── the ledger ─────────────────────────────────────────────────────────────
81
- async function readRecords() {
82
- const { fetchLifecycle, readBlobFromPath } = await import("../../lifecycle/git.js");
83
- await fetchLifecycle().catch(() => false);
84
- return parsePrEnvRecords(await readBlobFromPath(PR_ENV_LEDGER_DIR, PR_ENV_LEDGER_FILE));
85
- }
87
+ // ── the ports ──────────────────────────────────────────────────────────────
88
+ const log = (line) => console.error(formatInfo(line));
89
+ const warn = (message) => console.error(formatWarning({ message }));
86
90
  /**
87
- * Append `record` to chant/lifecycle and push it. With `--no-push` (#4295)
88
- * the record is written to `pr-env-record.json` under `--output` instead,
89
- * for `pr-env post` to append from a job that runs none of the change's
90
- * code. A failure warns: what was applied or torn down stands.
91
+ * The ports `pr-env` runs with (../../components/pr-env-run.ts): the records
92
+ * and the gate ledger on chant/lifecycle here, and the report written under
93
+ * `--output` and posted through `forge`. With `--no-push` (#4295) the record
94
+ * is written to `pr-env-record.json` under `--output` instead, for `pr-env
95
+ * post` to append from a job that runs none of the change's code.
91
96
  */
92
- async function appendRecord(ctx, record) {
93
- if (ctx.args.noPush) {
94
- const dir = resolve(ctx.args.output ?? PR_ENV_REPORT_DIR);
95
- mkdirSync(dir, { recursive: true });
96
- writeFileSync(join(dir, PR_ENV_RECORD_FILE), JSON.stringify(record, null, 2) + "\n");
97
- return;
98
- }
99
- const { appendLedgerLine, fetchLifecycle, pushLifecycleReport } = await import("../../lifecycle/git.js");
100
- try {
101
- await fetchLifecycle().catch(() => false);
102
- await appendLedgerLine(PR_ENV_LEDGER_DIR, PR_ENV_LEDGER_FILE, JSON.stringify(record), `Pull request environment ${record.env} ${record.kind} (${record.result})`);
103
- const pushed = await pushLifecycleReport();
104
- if (pushed.pushWarning)
105
- console.error(formatWarning({ message: pushed.pushWarning }));
106
- }
107
- catch (err) {
108
- console.error(formatWarning({ message: `could not record ${record.env}'s ${record.kind} on chant/lifecycle: ${err instanceof Error ? err.message : String(err)}` }));
109
- }
97
+ function cliPorts(ctx, forge) {
98
+ const lifecycle = lifecyclePrEnvPorts({ ...(forge ? { forge } : {}), log, warn });
99
+ return {
100
+ ...lifecycle,
101
+ async appendRecord(record) {
102
+ if (!ctx.args.noPush)
103
+ return lifecycle.appendRecord(record);
104
+ const dir = resolve(ctx.args.output ?? PR_ENV_REPORT_DIR);
105
+ mkdirSync(dir, { recursive: true });
106
+ writeFileSync(join(dir, PR_ENV_RECORD_FILE), JSON.stringify(record, null, 2) + "\n");
107
+ },
108
+ publish: (report) => finish(ctx, forge, report),
109
+ };
110
110
  }
111
111
  // ── the report and the note ────────────────────────────────────────────────
112
112
  async function finish(ctx, forge, report) {
@@ -117,27 +117,8 @@ async function finish(ctx, forge, report) {
117
117
  writeFileSync(join(dir, "pr-env-note.md"), note);
118
118
  if (ctx.args.json)
119
119
  console.log(JSON.stringify(report, null, 2));
120
- if (!forge)
121
- return;
122
- if (report.head) {
123
- try {
124
- await forge.setStatus(report.head, {
125
- context: prEnvStatusContext(report.member),
126
- state: prEnvStatusState(report),
127
- description: prEnvStatusDescription(report),
128
- ...(forge.runUrl ? { url: forge.runUrl } : {}),
129
- });
130
- }
131
- catch (err) {
132
- console.error(formatWarning({ message: `could not set the ${prEnvStatusContext(report.member)} status: ${err instanceof Error ? err.message : String(err)}` }));
133
- }
134
- }
135
- try {
136
- await forge.upsertNote(report.pr, prEnvNoteMarker(report.env, report.member), note);
137
- }
138
- catch (err) {
139
- console.error(formatWarning({ message: `could not post the note on #${report.pr}: ${err instanceof Error ? err.message : String(err)}` }));
140
- }
120
+ if (forge)
121
+ await forgePrEnvPublisher(forge, warn)(report);
141
122
  }
142
123
  // ── up ─────────────────────────────────────────────────────────────────────
143
124
  async function prEnvUp(ctx) {
@@ -159,7 +140,6 @@ async function prEnvUp(ctx) {
159
140
  const derived = derivePrEnvironment(config, setting.template, pr);
160
141
  if ("refusal" in derived)
161
142
  return fail(derived.refusal);
162
- const ttl = ttlMs(setting.ttl) ?? ttlMs("72h");
163
143
  // The build sees pr-<n> as its environment and the template's name beside it.
164
144
  process.env[ENV_VAR] = derived.env;
165
145
  process.env[PR_ENV_TEMPLATE_VAR] = derived.template;
@@ -168,108 +148,77 @@ async function prEnvUp(ctx) {
168
148
  args: { ...args, env: derived.env, param: [...(args.param ?? []).filter((p) => !p.startsWith(`${derived.param}=`)), `${derived.param}=${derived.env}`] },
169
149
  };
170
150
  console.error(formatInfo(`pr-env up: ${derived.env}, derived from ${derived.template}${derived.endpoint ? ` at ${derived.endpoint}` : ""}, marker ${derived.stack}/${derived.env}`));
171
- return withComponentEndpoint(envCtx, () => up(envCtx, pr, derived, ttl), { config: { ...config, environments: derived.environments }, environment: derived.env });
151
+ return withComponentEndpoint(envCtx, () => up(envCtx, pr, derived, setting.ttl), { config: { ...config, environments: derived.environments }, environment: derived.env });
172
152
  }
173
153
  async function up(ctx, pr, derived, ttl) {
174
154
  const { prepare, planAll, placeHooks, runStageHook } = await import("./pr.js");
175
155
  const p = await prepare(ctx, "plan");
176
156
  if (typeof p === "number")
177
157
  return p;
178
- const forge = p.forge;
179
- const op = prOp(pr, p.member);
180
158
  // ci.hooks (#4288), read at base as the other pull-request jobs read them, around the plan and the apply.
181
- placeHooks(ctx, p, "apply", op);
182
- const base = {
183
- stage: "up",
159
+ placeHooks(ctx, p, "apply", prEnvOp(pr, p.member));
160
+ const result = await prEnvUpRun({
184
161
  pr,
185
- env: derived.env,
186
- ...(p.member ? { member: p.member } : {}),
187
- template: derived.template,
188
162
  head: p.head,
189
- op,
190
- gate: PR_ENV_GATE,
191
- digest: "",
192
- status: "nothing",
193
- ...(derived.endpoint ? { endpoint: derived.endpoint } : {}),
194
- components: [],
195
- };
196
- if (p.plan.order.length === 0) {
197
- await finish(ctx, forge, { ...base, ...(p.routedAway ? { message: p.routedAway } : {}) });
198
- console.error(formatInfo(`pr-env up: nothing this change touches is deployed by a component, so ${derived.env} gets nothing`));
199
- return PR_ENV_EXIT.done;
200
- }
201
- const set = await planAll(p);
202
- const rows = (status) => p.plan.order.map((component) => {
203
- const ms = set.members.filter((m) => m.component === component);
204
- const sum = (k) => ms.reduce((n, m) => n + m.counts[k], 0);
205
- return { component, status: status(component), create: sum("create"), update: sum("update"), replace: sum("replace"), delete: sum("delete") };
206
- });
207
- const digest = set.doc.digest;
208
- if (set.failed) {
209
- await finish(ctx, forge, { ...base, digest, status: "plan-failed", ...(p.hookFailed ? { message: p.hookFailed } : {}), components: rows((c) => (set.members.some((m) => m.component === c && m.status === "plan-failed") ? "plan failed" : "planned")) });
210
- return PR_ENV_EXIT.failed;
211
- }
212
- // ws-080, ws-104: a non-empty plan applies only under a person's approval of its digest. An empty one passes.
213
- let approvedBy;
214
- if (!isEmptyChangeSet(set.doc)) {
215
- let approval;
216
- try {
217
- approval = approvalOf(await decidePrGate(readOnlyLedger(gitGateLedgerPort()), { op, gate: PR_ENV_GATE, digest, description: `${derived.env}: ${p.plan.order.join(", ")}` }));
218
- }
219
- catch (err) {
220
- return fail(`could not read the gate ledger, so ${derived.env} does not apply: ${err instanceof Error ? err.message : String(err)}`);
221
- }
222
- if (approval.status !== "approved") {
223
- const status = approval.status === "changed" ? "changed" : "waiting";
224
- await finish(ctx, forge, { ...base, digest, status, components: rows(() => "planned") });
225
- console.error(formatInfo(`pr-env up: ${derived.env} waits for an approval of ${digest}`));
226
- console.error(formatInfo(`approve : ${prEnvApproveCommand(op, digest)}`));
227
- return PR_ENV_EXIT.waiting;
228
- }
229
- approvedBy = approval.approvedBy ?? [];
230
- }
231
- const hookStop = runStageHook(p, "before-apply", p.plan.order, set);
232
- if (hookStop) {
233
- await finish(ctx, forge, { ...base, digest, status: "failed", message: hookStop, components: rows(() => "planned"), ...(approvedBy ? { approvedBy } : {}) });
234
- return PR_ENV_EXIT.failed;
235
- }
236
- const applied = await applyPrSet({ components: p.components, plan: p.plan, registry: p.registry, env: derived.env, set, gate: PR_ENV_GATE });
237
- const afterHook = runStageHook(p, "after-apply", p.plan.order, set, "the environment stands as applied");
238
- const status = (component) => applied.members.find((m) => m.component === component)?.status ?? "planned";
239
- const ok = applied.status === "applied";
240
- const now = new Date();
241
- const expiresAt = new Date(now.getTime() + ttl).toISOString();
242
- // A copy that failed part way is live too: what applied is torn down on close or at expiry like the rest.
243
- await appendRecord(ctx, {
244
- version: 1,
245
- kind: "up",
246
- pr,
247
- env: derived.env,
248
- ...(p.member ? { member: p.member } : {}),
249
163
  template: derived.template,
250
- marker: { stack: derived.stack, env: derived.env },
251
- commit: p.head,
252
- components: p.plan.order,
253
- planDigest: digest,
254
- result: ok ? "applied" : "failed",
255
- by: actor(),
256
- timestamp: now.toISOString(),
257
- expiresAt,
258
- ...(approvedBy ? { approvedBy } : {}),
259
- releaseTarget: false,
260
- ...(forge?.runUrl ? { runUrl: forge.runUrl } : {}),
164
+ ttl,
165
+ stack: derived.stack,
166
+ ...(p.member ? { member: p.member } : {}),
167
+ ...(derived.endpoint ? { endpoint: derived.endpoint } : {}),
168
+ adapter: componentsPrEnvAdapter(p, { planAll, runStageHook }),
169
+ ports: cliPorts(ctx, p.forge),
170
+ actor: actor(),
171
+ ...(p.forge?.runUrl ? { runUrl: p.forge.runUrl } : {}),
261
172
  });
262
- await finish(ctx, forge, {
263
- ...base,
264
- digest,
265
- status: ok ? "applied" : "failed",
266
- components: rows(status),
267
- ...(approvedBy ? { approvedBy } : {}),
268
- expiresAt,
269
- ...(ok ? (afterHook ? { message: afterHook } : {}) : { message: applied.status === "waiting" ? "A component read an upstream output that moved when it applied; run the job again to plan it against the new value." : "A component failed to apply; what applied stays in the environment and is torn down with it." }),
173
+ if (result.report.status === "waiting" || result.report.status === "changed")
174
+ console.error(formatInfo(`approve : ${prEnvApproveCommand(result.report.op, result.report.digest)}`));
175
+ return result.exit;
176
+ }
177
+ /**
178
+ * The components as a pull request environment's adapter: the plan is
179
+ * `pr-plan`'s, with the plan-side hooks around it, and the apply is the
180
+ * fan-out's, with the apply-side hooks around it. Each row carries the
181
+ * component's site in `pr-<n>`, carried over from the template's (#4330,
182
+ * `prEnvironmentSite`).
183
+ */
184
+ function componentsPrEnvAdapter(p, run) {
185
+ let set;
186
+ const rows = (target, status) => p.plan.order.map((component) => {
187
+ const ms = (set?.members ?? []).filter((m) => m.component === component);
188
+ const sum = (k) => ms.reduce((n, m) => n + m.counts[k], 0);
189
+ const found = prEnvironmentSite(p.sites?.[component], target.template, target.env);
190
+ const site = found ? { ...(found.runtime ? { runtime: found.runtime } : {}), ...(found.url ? { url: found.url } : {}), ...(found.domain ? { domain: found.domain } : {}) } : undefined;
191
+ return { component, status: status(component), create: sum("create"), update: sum("update"), replace: sum("replace"), delete: sum("delete"), ...(site && Object.keys(site).length > 0 ? { site } : {}) };
270
192
  });
271
- console.error((ok ? formatInfo : (m) => formatWarning({ message: m }))(`pr-env up: ${derived.env} ${ok ? "applied" : applied.status}; it expires ${expiresAt}`));
272
- return ok && !afterHook ? PR_ENV_EXIT.done : PR_ENV_EXIT.failed;
193
+ return {
194
+ async plan(target) {
195
+ if (p.plan.order.length === 0)
196
+ return { digest: "", empty: true, rows: [], ...(p.routedAway ? { message: p.routedAway } : {}) };
197
+ set = await run.planAll(p);
198
+ const planned = set;
199
+ return {
200
+ digest: planned.doc.digest,
201
+ empty: isEmptyChangeSet(planned.doc),
202
+ ...(planned.failed ? { failed: true } : {}),
203
+ rows: rows(target, (c) => (planned.failed && planned.members.some((m) => m.component === c && m.status === "plan-failed") ? "plan failed" : "planned")),
204
+ ...(p.hookFailed ? { message: p.hookFailed } : {}),
205
+ };
206
+ },
207
+ async apply(target) {
208
+ const planned = set;
209
+ const hookStop = run.runStageHook(p, "before-apply", p.plan.order, planned);
210
+ if (hookStop)
211
+ return { status: "stopped", rows: rows(target, () => "planned"), message: hookStop };
212
+ const applied = await applyPrSet({ components: p.components, plan: p.plan, registry: p.registry, env: target.env, set: planned, gate: PR_ENV_GATE });
213
+ const afterHook = run.runStageHook(p, "after-apply", p.plan.order, planned, "the environment stands as applied");
214
+ const status = (component) => applied.members.find((m) => m.component === component)?.status ?? "planned";
215
+ return {
216
+ status: applied.status === "applied" ? "applied" : applied.status === "waiting" ? "waiting" : "failed",
217
+ rows: rows(target, status),
218
+ ...(afterHook ? { afterFailure: afterHook } : {}),
219
+ };
220
+ },
221
+ };
273
222
  }
274
223
  // ── post ───────────────────────────────────────────────────────────────────
275
224
  /**
@@ -319,7 +268,7 @@ async function prEnvPost(ctx) {
319
268
  code = PR_ENV_EXIT.failed;
320
269
  }
321
270
  else {
322
- await appendRecord({ ...ctx, args: { ...args, noPush: false } }, accepted.record);
271
+ await lifecyclePrEnvPorts({ warn }).appendRecord(accepted.record);
323
272
  if (accepted.record.expiresAt)
324
273
  report.expiresAt = accepted.record.expiresAt;
325
274
  }
@@ -329,6 +278,18 @@ async function prEnvPost(ctx) {
329
278
  return code;
330
279
  }
331
280
  // ── down ───────────────────────────────────────────────────────────────────
281
+ /**
282
+ * What tears the environment down: the lexicons, and the command
283
+ * `ci.prEnvironment.teardown` names in the declaration at this commit
284
+ * (#4330), which the down and sweep jobs check out from the base branch.
285
+ */
286
+ async function teardownSources() {
287
+ const projectPath = resolve(".");
288
+ const { config } = await loadChantConfig(projectPath).catch(() => ({ config: {} }));
289
+ const { scopeSource } = await import("../../workspace/write-scope.js");
290
+ const hook = scopeSource(projectPath, "HEAD").declaration?.ci?.prEnvironment?.teardown;
291
+ return { config, adapters: hook ? [commandTeardownAdapter(hook, { cwd: projectPath })] : [] };
292
+ }
332
293
  async function prEnvDown(ctx) {
333
294
  const { args } = ctx;
334
295
  if (args.pr === undefined)
@@ -339,61 +300,21 @@ async function prEnvDown(ctx) {
339
300
  const forge = forgeOf(ctx);
340
301
  if (typeof forge === "number")
341
302
  return forge;
342
- const live = livePrEnvironments(await readRecords()).get(prEnvironmentName(args.pr));
343
- return teardown(ctx, forge, args.pr, live, reason);
344
- }
345
- async function teardown(ctx, forge, pr, live, reason) {
346
- const env = prEnvironmentName(pr);
347
303
  const member = memberOf(ctx);
348
- const report = { stage: "down", pr, env, ...(member ? { member } : {}), template: live?.template ?? "", head: "", op: prOp(pr, member), gate: PR_ENV_GATE, digest: "", status: "absent", components: [] };
349
- if (!live) {
350
- console.error(formatInfo(`pr-env down: ${env} has no live record, so there is nothing to tear down`));
351
- if (forge)
352
- await finish(ctx, forge, report);
353
- return PR_ENV_EXIT.done;
354
- }
355
- const { config } = await loadChantConfig(resolve(".")).catch(() => ({ config: {} }));
356
- const torn = await tearDownPrEnvironment({ pr, live, config, plugins: ctx.plugins, warn: (message) => console.error(formatWarning({ message })) });
357
- if ("refusal" in torn) {
358
- await finish(ctx, forge, { ...report, template: live.template, status: "refused", message: torn.refusal });
359
- return fail(torn.refusal);
360
- }
361
- const { report: result, dropped, marker } = torn;
362
- const counts = teardownCounts(result);
363
- const complete = teardownComplete(result);
364
- const lexicons = [...new Set(result.outcomes.map((o) => o.lexicon))].sort();
365
- const head = await headCommit();
366
- await appendRecord(ctx, {
367
- version: 1,
368
- kind: "down",
369
- pr,
370
- env,
371
- ...(live.member ? { member: live.member } : {}),
372
- template: live.template,
373
- marker,
374
- commit: head,
375
- components: lexicons,
376
- planDigest: "",
377
- result: complete ? "destroyed" : "incomplete",
378
- by: actor(),
379
- timestamp: new Date().toISOString(),
304
+ const result = await prEnvDownRun({
305
+ pr: args.pr,
380
306
  reason,
381
- outcomes: counts,
382
- releaseTarget: false,
307
+ ...(member ? { member } : {}),
308
+ ports: cliPorts(ctx, forge),
309
+ ...(await teardownSources()),
310
+ plugins: ctx.plugins,
311
+ commit: await headCommit(),
312
+ actor: actor(),
383
313
  ...(forge?.runUrl ? { runUrl: forge.runUrl } : {}),
384
314
  });
385
- const why = [];
386
- if (dropped > 0)
387
- why.push(`${dropped} candidate${dropped === 1 ? "" : "s"} whose marker was not ${marker.stack}/${env} left alone`);
388
- if (result.unimplemented.length > 0)
389
- why.push(`no teardown execution in ${result.unimplemented.join(", ")}`);
390
- if (result.plan.holes.length > 0)
391
- why.push(`${result.plan.holes.length} part${result.plan.holes.length === 1 ? "" : "s"} could not be read`);
392
- for (const o of result.outcomes.filter((x) => x.outcome === "failed"))
393
- why.push(`${o.lexicon} ${o.name}: ${o.detail ?? "failed"}`);
394
- await finish(ctx, forge, { ...report, template: live.template, status: complete ? "destroyed" : "incomplete", outcomes: counts, ...(why.length > 0 ? { message: why.join("; ") } : {}) });
395
- console.error((complete ? formatInfo : (m) => formatWarning({ message: m }))(`pr-env down: ${env} ${complete ? "torn down" : "not wholly torn down; it stays live and the sweep tries again"} (${counts.deleted} deleted, ${counts.failed} failed, ${counts.skipped} skipped)`));
396
- return complete ? PR_ENV_EXIT.done : PR_ENV_EXIT.failed;
315
+ if (result.report.status === "refused")
316
+ return fail(result.report.message ?? "refused");
317
+ return result.exit;
397
318
  }
398
319
  async function headCommit() {
399
320
  const { spawnSync } = await import("node:child_process");
@@ -405,32 +326,13 @@ async function prEnvSweep(ctx) {
405
326
  const forge = forgeOf(ctx);
406
327
  if (typeof forge === "number")
407
328
  return forge;
408
- const live = [...livePrEnvironments(await readRecords()).values()];
409
- if (live.length === 0) {
410
- console.error(formatInfo("pr-env sweep: no pull request environment is live"));
411
- return PR_ENV_EXIT.done;
412
- }
413
- const now = new Date();
414
- let code = PR_ENV_EXIT.done;
415
- for (const e of live) {
416
- let reason = expired(e, now) ? "expired" : undefined;
417
- if (!reason && forge?.pullRequestState) {
418
- try {
419
- const state = await forge.pullRequestState(e.pr);
420
- if (state !== "open")
421
- reason = "closed";
422
- }
423
- catch (err) {
424
- console.error(formatWarning({ message: `could not read whether #${e.pr} is open (${err instanceof Error ? err.message : String(err)}); its TTL still holds` }));
425
- }
426
- }
427
- if (!reason) {
428
- console.error(formatInfo(`pr-env sweep: ${e.env} stays; it expires ${e.expiresAt}`));
429
- continue;
430
- }
431
- const c = await teardown(ctx, forge, e.pr, e, reason);
432
- if (c !== PR_ENV_EXIT.done)
433
- code = PR_ENV_EXIT.failed;
434
- }
435
- return code;
329
+ const result = await prEnvSweepRun({
330
+ ports: cliPorts(ctx, forge),
331
+ ...(await teardownSources()),
332
+ plugins: ctx.plugins,
333
+ commit: await headCommit(),
334
+ actor: actor(),
335
+ ...(forge?.runUrl ? { runUrl: forge.runUrl } : {}),
336
+ });
337
+ return result.exit;
436
338
  }
@@ -72,6 +72,7 @@ import type { CommandContext } from "../registry.js";
72
72
  import type { ComponentChangeSignal, FanOutPlan } from "../../components/fan-out.js";
73
73
  import { type DriverComponent } from "../../components/driver.js";
74
74
  import type { CapabilityRegistry } from "../../components/capability.js";
75
+ import type { ComponentEnvironmentDeclaration } from "../../components/component.js";
75
76
  import { type PrHookPlace, type PrLoopHooks } from "../../components/pr-hooks.js";
76
77
  import { type PrLoopPolicy } from "../../components/pr-policy.js";
77
78
  import type { OpWaveHookMoment } from "../../op/op-waves.js";
@@ -97,6 +98,8 @@ export interface Prepared {
97
98
  signal: ComponentChangeSignal;
98
99
  registry: CapabilityRegistry;
99
100
  seededOutputs: Record<string, Record<string, unknown>>;
101
+ /** Component name to the environments it declares (#3153), whose sites `pr-env up` carries over (#4330). */
102
+ sites?: Record<string, ComponentEnvironmentDeclaration[]>;
100
103
  /** `ci.hooks` from the declaration at base (#4288). */
101
104
  hooks: PrLoopHooks;
102
105
  /** Every hook the stage ran so far, for the report's `hooks`. */
@@ -1 +1 @@
1
- {"version":3,"file":"pr.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/pr.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pr.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/pr.ts"],"names":[],"mappings":"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"}
@@ -218,6 +218,7 @@ export async function prepare(ctx, stage) {
218
218
  components: derived.components,
219
219
  plan: routedAway ? { ...derived.plan, order: [], waves: [], seeds: [], indeterminate: [] } : derived.plan,
220
220
  signal: derived.signal,
221
+ ...(derived.sites ? { sites: derived.sites } : {}),
221
222
  registry,
222
223
  seededOutputs,
223
224
  hooks,
@@ -0,0 +1,89 @@
1
+ import type { GraphIR, IRNode } from "../../graph-ir.js";
2
+ import { terraformType } from "../../graph-effective.js";
3
+ export { terraformType };
4
+ /**
5
+ * `chant search --count-by <kind|module|attr:<name>>` (#4360): grouped counts
6
+ * over the matched set, one line per group, instead of one row per match.
7
+ *
8
+ * An agent asking "how many resources of each type does each module own" used
9
+ * to run one search per value, or read every row and count them itself. The
10
+ * second is the token cost `search` exists to avoid.
11
+ *
12
+ * Every matched node lands in exactly one group. A node with no value for the
13
+ * grouped dimension is counted under `(none)`, never dropped, so the groups
14
+ * always add up to the total line.
15
+ */
16
+ export type CountBy = {
17
+ by: "kind";
18
+ } | {
19
+ by: "module";
20
+ } | {
21
+ by: "attr";
22
+ name: string;
23
+ };
24
+ /** The group a node with no value for the grouped dimension is counted under. */
25
+ export declare const NONE_GROUP = "(none)";
26
+ /** The module group of a Terraform block declared in the root module itself. */
27
+ export declare const ROOT_MODULE_GROUP = "(root)";
28
+ /** Parse a `--count-by` value, or say what the accepted spellings are. */
29
+ export declare function parseCountBy(raw: string): CountBy | {
30
+ error: string;
31
+ hint: string;
32
+ };
33
+ /**
34
+ * The group one node belongs to.
35
+ *
36
+ * `module` on a Terraform node is its call chain. When the graph holds more
37
+ * than one Terraform root, the chain is prefixed with the root (`app/(root)`,
38
+ * `net/module.vpc`): `module.vpc` in two roots is two modules, applied
39
+ * separately, and counting them as one would add up resources that never sit
40
+ * in the same state. A node of another lexicon groups under the composite that
41
+ * expanded it, chant's own unit of reuse, or `(none)`.
42
+ */
43
+ export declare function groupOf(n: IRNode, countBy: CountBy, multiRoot?: boolean): string;
44
+ /** Whether the graph holds blocks from more than one Terraform root. */
45
+ export declare function hasManyTerraformRoots(ir: GraphIR): boolean;
46
+ /** Count `matches` per group, sorted by count (highest first) and then by name. */
47
+ export declare function countGroups(matches: IRNode[], countBy: CountBy, multiRoot?: boolean): Array<{
48
+ group: string;
49
+ count: number;
50
+ }>;
51
+ /**
52
+ * The groups with the ids of the matches in each, in match order (#4382), in
53
+ * the order {@link countGroups} gives. `count` is always `ids.length`. A
54
+ * reader that draws the groups (behold#922) lights each group's nodes from
55
+ * `ids`, so it never has to read a node's group itself.
56
+ */
57
+ export declare function groupMembers(matches: IRNode[], countBy: CountBy, multiRoot?: boolean): Array<{
58
+ group: string;
59
+ count: number;
60
+ ids: string[];
61
+ }>;
62
+ /** `--count-by` with `--json`: the groups, in printed order, each with its matched ids, and the total they add up to. */
63
+ export interface CountsJson {
64
+ query: string;
65
+ source: unknown;
66
+ countBy: string;
67
+ groups: Array<{
68
+ group: string;
69
+ count: number;
70
+ ids: string[];
71
+ }>;
72
+ total: number;
73
+ liveFailures?: string[];
74
+ }
75
+ export declare function countsJson(query: string, source: unknown, groups: Array<{
76
+ group: string;
77
+ count: number;
78
+ ids: string[];
79
+ }>, countBy: CountBy, liveFailures?: string[]): CountsJson;
80
+ /**
81
+ * Render grouped counts: one `<count> <group>` line per group, counts right
82
+ * aligned, then the total. The total is the number of matches, which is the
83
+ * sum of the group counts by construction.
84
+ */
85
+ export declare function formatCounts(groups: Array<{
86
+ group: string;
87
+ count: number;
88
+ }>, countBy: CountBy): string[];
89
+ //# sourceMappingURL=search-count.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-count.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/search-count.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAItD,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,OAAO,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,iFAAiF;AACjF,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAUnF;AAiCD;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,UAAQ,GAAG,MAAM,CAQ9E;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAI1D;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,UAAQ,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAE3H;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,UAAQ,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAW3I;AAED,yHAAyH;AACzH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,EAC9D,OAAO,EAAE,OAAO,EAChB,YAAY,GAAE,MAAM,EAAO,GAC1B,UAAU,CASZ;AAOD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CAMxG"}