@intentius/chant-lexicon-k8s 0.124.31 → 0.124.33

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 (270) hide show
  1. package/dist/actions/apps.js +18 -0
  2. package/dist/actions/batch.js +6 -0
  3. package/dist/actions/core.js +48 -0
  4. package/dist/actions/index.js +13 -0
  5. package/dist/actions/networking.js +11 -0
  6. package/dist/actions/rbac.js +8 -0
  7. package/dist/api/classify.js +123 -0
  8. package/dist/api/connect.js +62 -0
  9. package/dist/api/fake-cluster.js +175 -0
  10. package/dist/api/operation-surface.d.ts.map +1 -1
  11. package/dist/api/operation-surface.js +109 -0
  12. package/dist/api/owner-chain.js +100 -0
  13. package/dist/api/sweep-types.js +35 -0
  14. package/dist/behaviour-kinds.js +82 -0
  15. package/dist/codegen/docs-cli.js +2 -0
  16. package/dist/codegen/docs.js +146 -0
  17. package/dist/codegen/generate-cli.js +30 -0
  18. package/dist/codegen/generate-lexicon.js +74 -0
  19. package/dist/codegen/generate-list-map-keys.js +88 -0
  20. package/dist/codegen/generate-operations.js +53 -0
  21. package/dist/codegen/generate-typescript.js +124 -0
  22. package/dist/codegen/generate.js +173 -0
  23. package/dist/codegen/naming.js +174 -0
  24. package/dist/codegen/package.js +36 -0
  25. package/dist/codegen/patches.js +88 -0
  26. package/dist/codegen/typecheck.js +4 -0
  27. package/dist/codegen/versions.js +41 -0
  28. package/dist/components/argo-app.js +51 -0
  29. package/dist/components/builders.js +22 -0
  30. package/dist/components/capability-plugin.js +31 -0
  31. package/dist/components/flux-reconcile.js +61 -0
  32. package/dist/components/index.d.ts +1 -1
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/components/index.js +18 -0
  35. package/dist/components/kubectl-apply.d.ts +83 -1
  36. package/dist/components/kubectl-apply.d.ts.map +1 -1
  37. package/dist/components/kubectl-apply.js +274 -0
  38. package/dist/components/kustomize-apply.js +25 -0
  39. package/dist/composites/adot-collector.js +184 -0
  40. package/dist/composites/agic-ingress.js +85 -0
  41. package/dist/composites/aks-external-dns-agent.js +146 -0
  42. package/dist/composites/alb-ingress.js +86 -0
  43. package/dist/composites/argo-app.js +199 -0
  44. package/dist/composites/autoscaled-service.js +174 -0
  45. package/dist/composites/azure-disk-storage-class.js +47 -0
  46. package/dist/composites/azure-file-storage-class.js +48 -0
  47. package/dist/composites/azure-monitor-collector.js +176 -0
  48. package/dist/composites/batch-job.js +139 -0
  49. package/dist/composites/catalog.js +4110 -0
  50. package/dist/composites/cockroachdb-cluster.js +371 -0
  51. package/dist/composites/cockroachdb-region-stack.js +369 -0
  52. package/dist/composites/config-connector-context.js +40 -0
  53. package/dist/composites/configured-app.js +135 -0
  54. package/dist/composites/cron-schedule.js +38 -0
  55. package/dist/composites/cron-workload.js +109 -0
  56. package/dist/composites/ebs-storage-class.js +54 -0
  57. package/dist/composites/efs-storage-class.js +46 -0
  58. package/dist/composites/external-dns-agent.js +122 -0
  59. package/dist/composites/filestore-storage-class.js +49 -0
  60. package/dist/composites/fluent-bit-agent.js +157 -0
  61. package/dist/composites/flux-app.js +156 -0
  62. package/dist/composites/gce-ingress.js +83 -0
  63. package/dist/composites/gce-pd-storage-class.js +49 -0
  64. package/dist/composites/gke-external-dns-agent.js +129 -0
  65. package/dist/composites/gke-fluent-bit-agent.js +165 -0
  66. package/dist/composites/gke-gateway.js +91 -0
  67. package/dist/composites/gke-otel-collector.js +94 -0
  68. package/dist/composites/index.js +51 -0
  69. package/dist/composites/inference-service.js +76 -0
  70. package/dist/composites/irsa-service-account.js +77 -0
  71. package/dist/composites/member-defaults.js +14 -0
  72. package/dist/composites/metrics-server.js +181 -0
  73. package/dist/composites/model.js +92 -0
  74. package/dist/composites/monitored-service.js +152 -0
  75. package/dist/composites/namespace-env.js +114 -0
  76. package/dist/composites/network-isolated-app.js +124 -0
  77. package/dist/composites/node-agent.js +149 -0
  78. package/dist/composites/operator-stack.js +268 -0
  79. package/dist/composites/otel-collector-agent.js +142 -0
  80. package/dist/composites/otel-collector-gateway.js +216 -0
  81. package/dist/composites/otel-collector-node.js +176 -0
  82. package/dist/composites/otel-collector-rbac.js +115 -0
  83. package/dist/composites/otel-collector-shape.js +128 -0
  84. package/dist/composites/otel-collector.js +115 -0
  85. package/dist/composites/otel-operator-collector.js +123 -0
  86. package/dist/composites/ray-cluster.js +378 -0
  87. package/dist/composites/ray-job.js +136 -0
  88. package/dist/composites/ray-service.js +178 -0
  89. package/dist/composites/secure-ingress.js +100 -0
  90. package/dist/composites/security-context.js +1 -0
  91. package/dist/composites/sidecar-app.js +105 -0
  92. package/dist/composites/stateful-app.js +111 -0
  93. package/dist/composites/vllm-serving-runtime.js +114 -0
  94. package/dist/composites/web-app.js +157 -0
  95. package/dist/composites/worker-pool.js +167 -0
  96. package/dist/composites/workload-identity-sa.js +81 -0
  97. package/dist/composites/workload-identity-service-account.js +77 -0
  98. package/dist/config-schema.js +72 -0
  99. package/dist/config.js +59 -0
  100. package/dist/coverage.js +27 -0
  101. package/dist/crd/crd-sources.js +615 -0
  102. package/dist/crd/loader.js +181 -0
  103. package/dist/crd/oci-chart.js +144 -0
  104. package/dist/crd/parser.js +382 -0
  105. package/dist/crd/project-codegen.js +273 -0
  106. package/dist/crd/types.js +7 -0
  107. package/dist/deep-observe-hooks.js +306 -0
  108. package/dist/deep-observe.js +234 -0
  109. package/dist/default-labels.js +87 -0
  110. package/dist/describe-resources.js +699 -0
  111. package/dist/describe-stack-status.js +99 -0
  112. package/dist/detect.js +11 -0
  113. package/dist/effect-receipt-row.js +205 -0
  114. package/dist/export-resources.js +39 -0
  115. package/dist/generated/index.js +1092 -0
  116. package/dist/generated/runtime.js +4 -0
  117. package/dist/group-namespace.js +96 -0
  118. package/dist/import/embedded.js +197 -0
  119. package/dist/import/generator.js +288 -0
  120. package/dist/import/live-export.js +85 -0
  121. package/dist/import/parser.js +204 -0
  122. package/dist/import/testdata/embedded/fixtures.js +60 -0
  123. package/dist/include/entity.js +78 -0
  124. package/dist/include/resolve.js +170 -0
  125. package/dist/index.js +59 -0
  126. package/dist/integrity.json +3 -3
  127. package/dist/kube/apply.js +90 -0
  128. package/dist/kube/connect.js +46 -0
  129. package/dist/kube/delete.js +138 -0
  130. package/dist/kube/describe.js +169 -0
  131. package/dist/kube/events.js +132 -0
  132. package/dist/kube/flags.js +91 -0
  133. package/dist/kube/get.js +159 -0
  134. package/dist/kube/group.js +123 -0
  135. package/dist/kube/logs.js +82 -0
  136. package/dist/kube/project.js +94 -0
  137. package/dist/kube/render.js +227 -0
  138. package/dist/kube/source.js +122 -0
  139. package/dist/kube/target.js +63 -0
  140. package/dist/kube/testing.js +28 -0
  141. package/dist/kube/top.js +99 -0
  142. package/dist/kube/verdict.js +72 -0
  143. package/dist/kube/wait.js +129 -0
  144. package/dist/kustomize/render.js +73 -0
  145. package/dist/kustomize/rendered-entity.js +67 -0
  146. package/dist/kustomize/root.js +68 -0
  147. package/dist/lint/audit-catalog.js +61 -0
  148. package/dist/lint/audit-lineage.js +118 -0
  149. package/dist/lint/post-synth/argo-helpers.js +36 -0
  150. package/dist/lint/post-synth/argo002.js +31 -0
  151. package/dist/lint/post-synth/argo003.js +53 -0
  152. package/dist/lint/post-synth/argo005.js +54 -0
  153. package/dist/lint/post-synth/crd-schema-helpers.d.ts.map +1 -1
  154. package/dist/lint/post-synth/crd-schema-helpers.js +214 -0
  155. package/dist/lint/post-synth/flux002.js +56 -0
  156. package/dist/lint/post-synth/flux003.js +50 -0
  157. package/dist/lint/post-synth/index.js +104 -0
  158. package/dist/lint/post-synth/k8s-helpers.js +186 -0
  159. package/dist/lint/post-synth/monitoring-selection-helpers.js +163 -0
  160. package/dist/lint/post-synth/otel-placement-helpers.js +293 -0
  161. package/dist/lint/post-synth/sops-helpers.js +43 -0
  162. package/dist/lint/post-synth/wk8005.js +44 -0
  163. package/dist/lint/post-synth/wk8006.js +56 -0
  164. package/dist/lint/post-synth/wk8041.js +60 -0
  165. package/dist/lint/post-synth/wk8042.js +36 -0
  166. package/dist/lint/post-synth/wk8101.js +52 -0
  167. package/dist/lint/post-synth/wk8102.js +30 -0
  168. package/dist/lint/post-synth/wk8103.js +33 -0
  169. package/dist/lint/post-synth/wk8104.js +58 -0
  170. package/dist/lint/post-synth/wk8105.js +33 -0
  171. package/dist/lint/post-synth/wk8201.js +44 -0
  172. package/dist/lint/post-synth/wk8202.js +34 -0
  173. package/dist/lint/post-synth/wk8203.js +34 -0
  174. package/dist/lint/post-synth/wk8204.js +71 -0
  175. package/dist/lint/post-synth/wk8205.js +38 -0
  176. package/dist/lint/post-synth/wk8207.js +33 -0
  177. package/dist/lint/post-synth/wk8208.js +33 -0
  178. package/dist/lint/post-synth/wk8209.js +33 -0
  179. package/dist/lint/post-synth/wk8301.js +49 -0
  180. package/dist/lint/post-synth/wk8302.js +34 -0
  181. package/dist/lint/post-synth/wk8303.js +68 -0
  182. package/dist/lint/post-synth/wk8304.js +58 -0
  183. package/dist/lint/post-synth/wk8305.js +96 -0
  184. package/dist/lint/post-synth/wk8306.js +38 -0
  185. package/dist/lint/post-synth/wk8401.js +86 -0
  186. package/dist/lint/post-synth/wk8402.js +31 -0
  187. package/dist/lint/post-synth/wk8403.js +49 -0
  188. package/dist/lint/post-synth/wk8404.js +36 -0
  189. package/dist/lint/post-synth/wk8405.js +65 -0
  190. package/dist/lint/post-synth/wk8406.js +50 -0
  191. package/dist/lint/post-synth/wk8407.js +58 -0
  192. package/dist/lint/post-synth/wk8501.js +36 -0
  193. package/dist/lint/post-synth/wk8502.js +35 -0
  194. package/dist/lint/post-synth/wk8503.js +164 -0
  195. package/dist/lint/post-synth/wk8504.js +20 -0
  196. package/dist/lint/post-synth/wk8505.js +31 -0
  197. package/dist/lint/post-synth/wk8601.js +40 -0
  198. package/dist/lint/post-synth/wk8602.js +120 -0
  199. package/dist/lint/post-synth/wk8603.js +63 -0
  200. package/dist/lint/post-synth/wk8604.js +31 -0
  201. package/dist/lint/post-synth/wk8605.js +124 -0
  202. package/dist/lint/post-synth/wk8606.js +22 -0
  203. package/dist/lint/post-synth/wk8701.js +31 -0
  204. package/dist/lint/post-synth/wk8702.js +37 -0
  205. package/dist/lint/post-synth/wk8703.js +31 -0
  206. package/dist/lint/post-synth/wk8704.js +135 -0
  207. package/dist/lint/post-synth/wk8705.js +38 -0
  208. package/dist/lint/rules/argo-appset-single-project.js +56 -0
  209. package/dist/lint/rules/argo-ast.js +94 -0
  210. package/dist/lint/rules/argo-automated-prune.js +59 -0
  211. package/dist/lint/rules/flux-source-ref-pin.js +44 -0
  212. package/dist/lint/rules/hardcoded-namespace.js +57 -0
  213. package/dist/lint/rules/latest-image-tag.js +103 -0
  214. package/dist/lint/rules/missing-resource-limits.js +85 -0
  215. package/dist/lsp/completions.d.ts.map +1 -1
  216. package/dist/lsp/completions.js +18 -0
  217. package/dist/lsp/hover.d.ts.map +1 -1
  218. package/dist/lsp/hover.js +57 -0
  219. package/dist/manifest-entity.js +71 -0
  220. package/dist/manifest.json +1 -1
  221. package/dist/micro-time.js +49 -0
  222. package/dist/op/activities/apply-diff.d.ts +31 -0
  223. package/dist/op/activities/apply-diff.d.ts.map +1 -0
  224. package/dist/op/activities/apply-diff.js +79 -0
  225. package/dist/op/activities/argo.js +98 -0
  226. package/dist/op/activities/ensure-secret.js +38 -0
  227. package/dist/op/activities/index.js +51 -0
  228. package/dist/op/activities/kubectl.d.ts +64 -0
  229. package/dist/op/activities/kubectl.d.ts.map +1 -1
  230. package/dist/op/activities/kubectl.js +517 -0
  231. package/dist/op/activities/wait-for-ready.js +229 -0
  232. package/dist/op/builders.js +68 -0
  233. package/dist/package-cli.js +21 -0
  234. package/dist/patch/json-patch.js +187 -0
  235. package/dist/patch/rendered-patch.js +94 -0
  236. package/dist/plugin.js +741 -0
  237. package/dist/project-kinds.js +56 -0
  238. package/dist/receipt-store.js +216 -0
  239. package/dist/rules/crd-schema-helpers.ts +2 -1
  240. package/dist/secret-labels.js +33 -0
  241. package/dist/secret-store.js +116 -0
  242. package/dist/serializer.d.ts.map +1 -1
  243. package/dist/serializer.js +578 -0
  244. package/dist/sops/encrypted-secret-file.js +194 -0
  245. package/dist/sops/entity.js +32 -0
  246. package/dist/spec/fetch.js +58 -0
  247. package/dist/spec/parse.js +622 -0
  248. package/dist/subscribe-changes.js +168 -0
  249. package/dist/teardown.js +197 -0
  250. package/dist/telemetry-release.js +86 -0
  251. package/dist/validate-cli.js +17 -0
  252. package/dist/validate.js +47 -0
  253. package/dist/variables.js +34 -0
  254. package/dist/whoami.js +109 -0
  255. package/package.json +12 -12
  256. package/src/api/operation-surface.ts +2 -1
  257. package/src/codegen/package.ts +2 -2
  258. package/src/components/index.ts +3 -0
  259. package/src/components/kubectl-apply-plan.k3d.e2e.test.ts +127 -0
  260. package/src/components/kubectl-apply.test.ts +262 -0
  261. package/src/components/kubectl-apply.ts +341 -12
  262. package/src/deep-observe-hooks.ts +2 -2
  263. package/src/import/roundtrip-build.test.ts +46 -0
  264. package/src/lint/post-synth/crd-schema-helpers.ts +2 -1
  265. package/src/lsp/completions.ts +2 -1
  266. package/src/lsp/hover.ts +2 -1
  267. package/src/op/activities/apply-diff.ts +87 -0
  268. package/src/op/activities/kubectl-plan.test.ts +224 -0
  269. package/src/op/activities/kubectl.ts +204 -16
  270. package/src/serializer.ts +2 -1
package/dist/plugin.js ADDED
@@ -0,0 +1,741 @@
1
+ /**
2
+ * Kubernetes lexicon plugin.
3
+ *
4
+ * Provides serializer, template detection, code generation,
5
+ * lint rules, and LSP/MCP integration for Kubernetes manifests.
6
+ */
7
+ import { compositeCatalog } from "./composites/catalog.js";
8
+ import { k8sBehaviourKinds } from "./behaviour-kinds.js";
9
+ import { kubeCommandGroup } from "./kube/group.js";
10
+ import { detectTemplate } from "./detect.js";
11
+ import { postSynthChecks as postSynthCheckList } from "./lint/post-synth/index.js";
12
+ import { k8sAuditCatalog } from "./lint/audit-catalog.js";
13
+ import { createSkillsLoader, createDiffTool, createCatalogResource } from "@intentius/chant/lexicon-plugin-helpers";
14
+ import { k8sSerializer } from "./serializer.js";
15
+ import { hardcodedNamespaceRule } from "./lint/rules/hardcoded-namespace.js";
16
+ import { latestImageTagRule } from "./lint/rules/latest-image-tag.js";
17
+ import { missingResourceLimitsRule } from "./lint/rules/missing-resource-limits.js";
18
+ import { argoAutomatedPruneRule } from "./lint/rules/argo-automated-prune.js";
19
+ import { argoAppSetSingleProjectRule } from "./lint/rules/argo-appset-single-project.js";
20
+ import { fluxSourceRefPinRule } from "./lint/rules/flux-source-ref-pin.js";
21
+ import { k8sCompletions } from "./lsp/completions.js";
22
+ import { k8sHover } from "./lsp/hover.js";
23
+ import { K8sParser } from "./import/parser.js";
24
+ import { K8sGenerator } from "./import/generator.js";
25
+ import { k8sDeepNormalizationHooks } from "./deep-observe-hooks.js";
26
+ import { LABEL_OWNERSHIP_KEYS } from "@intentius/chant/ownership";
27
+ import { k8sConfigSchema } from "./config-schema.js";
28
+ import { renderKustomizeRoots } from "./kustomize/root.js";
29
+ import { encryptedSecretBuildRoot } from "./sops/encrypted-secret-file.js";
30
+ import { k8sProjectCodegen } from "./crd/project-codegen.js";
31
+ import { includeBuildRoot } from "./include/resolve.js";
32
+ export const k8sPlugin = {
33
+ behaviourKinds: k8sBehaviourKinds,
34
+ name: "k8s",
35
+ ownershipChannel: { keys: LABEL_OWNERSHIP_KEYS, reads: ["describeResources", "observeResourcesDeep", "exportResources"] },
36
+ configSchema: k8sConfigSchema,
37
+ auditCatalog: () => k8sAuditCatalog,
38
+ serializer: k8sSerializer,
39
+ // Self-upgrade: where the pinned Kubernetes schema version lives + its upstream (#685).
40
+ upstreamPin: {
41
+ file: "src/spec/fetch.ts",
42
+ pattern: /export const K8S_SCHEMA_VERSION\s*=\s*"([^"]+)"/,
43
+ replace: (v, line) => line.replace(/export const K8S_SCHEMA_VERSION\s*=\s*"[^"]+"/, `export const K8S_SCHEMA_VERSION = "${v}"`),
44
+ upstream: { owner: "kubernetes", repo: "kubernetes", kind: "releases" },
45
+ },
46
+ // chant #1078/#1079 — the command-group seam's tenant. `kube` mounts the
47
+ // terminal surface over the typed client: kubectl-compatible reads (get,
48
+ // describe, logs, events, top, wait), chant's own additions (source, the
49
+ // `get` verdict column, -o chant), and gated writes (apply, delete) that
50
+ // route through the exact same machinery the Op activities use — never a
51
+ // parallel implementation. See ./kube/group.ts for the full verb list;
52
+ // this plugin only mounts it.
53
+ commands() {
54
+ return kubeCommandGroup();
55
+ },
56
+ lintRules() {
57
+ return [
58
+ hardcodedNamespaceRule,
59
+ latestImageTagRule,
60
+ missingResourceLimitsRule,
61
+ argoAutomatedPruneRule,
62
+ argoAppSetSingleProjectRule,
63
+ fluxSourceRefPinRule,
64
+ ];
65
+ },
66
+ postSynthChecks() {
67
+ return postSynthCheckList;
68
+ },
69
+ // Typed classes for the project's own CRDs (`k8s.crds`), written by
70
+ // `chant generate` and checked for drift by every build. See
71
+ // ./crd/project-codegen.ts.
72
+ projectCodegen() {
73
+ return k8sProjectCodegen();
74
+ },
75
+ // #1548 piece 3 — kustomization dirs declared as build roots. Each entry in
76
+ // `k8s.kustomize.roots` renders at build time (same injectable runner as
77
+ // the kustomize-apply capability: `kustomize build`, `kubectl kustomize`
78
+ // fallback) and the documents join the build as verbatim manifest entities:
79
+ // serialized with ownership stamping, checked post-synth, observed by
80
+ // `lifecycle diff --live`. See ./kustomize/root.ts.
81
+ //
82
+ // The same hook also resolves committed-encrypted `declareSecret()`
83
+ // declarations: it reads the ciphertext each one names and contributes it
84
+ // as a verbatim sidecar entity (see ./sops/encrypted-secret-file.ts), and
85
+ // `k8sInclude()` declarations: it reads or fetches each declared YAML and
86
+ // contributes its documents as verbatim manifest entities (see
87
+ // ./include/resolve.ts). All three read at the one sanctioned impure seam.
88
+ async buildRoots(ctx) {
89
+ const entities = new Map();
90
+ const warnings = [];
91
+ const roots = ctx.config.k8s?.kustomize?.roots ?? [];
92
+ if (roots.length > 0) {
93
+ const rendered = await renderKustomizeRoots({ projectRoot: ctx.projectRoot, roots });
94
+ for (const [name, entity] of rendered.entities)
95
+ entities.set(name, entity);
96
+ warnings.push(...rendered.warnings);
97
+ }
98
+ const included = await includeBuildRoot(ctx);
99
+ for (const [name, entity] of included.entities)
100
+ entities.set(name, entity);
101
+ const encrypted = await encryptedSecretBuildRoot(ctx);
102
+ for (const [name, entity] of encrypted.entities)
103
+ entities.set(name, entity);
104
+ warnings.push(...(encrypted.warnings ?? []));
105
+ return { entities, warnings };
106
+ },
107
+ // K8s YAML has no template interpolation functions like CloudFormation's
108
+ // Fn::Sub or GitLab's !reference. Cross-resource references are handled by
109
+ // the AttrRef system in the serializer (resolves to metadata.name).
110
+ // ConfigMap/Secret valueFrom references are expressed as plain property
111
+ // values, not intrinsics.
112
+ intrinsics() {
113
+ return [];
114
+ },
115
+ initTemplates(template) {
116
+ if (template === "microservice") {
117
+ return {
118
+ src: {
119
+ "infra.ts": `import { Deployment, Service, HorizontalPodAutoscaler, PodDisruptionBudget, Container, Probe, ResourceRequirements } from "@intentius/chant-lexicon-k8s";
120
+
121
+ export const deployment = new Deployment({
122
+ metadata: { name: "my-service", labels: { "app.kubernetes.io/name": "my-service" } },
123
+ spec: {
124
+ replicas: 2,
125
+ selector: { matchLabels: { "app.kubernetes.io/name": "my-service" } },
126
+ template: {
127
+ metadata: { labels: { "app.kubernetes.io/name": "my-service" } },
128
+ spec: {
129
+ containers: [
130
+ new Container({
131
+ name: "app",
132
+ image: "my-service:latest",
133
+ ports: [{ containerPort: 8080, name: "http" }],
134
+ resources: new ResourceRequirements({
135
+ limits: { cpu: "500m", memory: "256Mi" },
136
+ requests: { cpu: "100m", memory: "128Mi" },
137
+ }),
138
+ livenessProbe: new Probe({ httpGet: { path: "/healthz", port: 8080 }, initialDelaySeconds: 10 }),
139
+ readinessProbe: new Probe({ httpGet: { path: "/readyz", port: 8080 }, initialDelaySeconds: 5 }),
140
+ }),
141
+ ],
142
+ },
143
+ },
144
+ },
145
+ });
146
+
147
+ export const service = new Service({
148
+ metadata: { name: "my-service", labels: { "app.kubernetes.io/name": "my-service" } },
149
+ spec: {
150
+ selector: { "app.kubernetes.io/name": "my-service" },
151
+ ports: [{ port: 80, targetPort: 8080, protocol: "TCP", name: "http" }],
152
+ },
153
+ });
154
+
155
+ export const hpa = new HorizontalPodAutoscaler({
156
+ metadata: { name: "my-service" },
157
+ spec: {
158
+ scaleTargetRef: { apiVersion: "apps/v1", kind: "Deployment", name: "my-service" },
159
+ minReplicas: 2,
160
+ maxReplicas: 10,
161
+ metrics: [{ type: "Resource", resource: { name: "cpu", target: { type: "Utilization", averageUtilization: 70 } } }],
162
+ },
163
+ });
164
+
165
+ export const pdb = new PodDisruptionBudget({
166
+ metadata: { name: "my-service" },
167
+ spec: {
168
+ minAvailable: 1,
169
+ selector: { matchLabels: { "app.kubernetes.io/name": "my-service" } },
170
+ },
171
+ });
172
+ `,
173
+ },
174
+ };
175
+ }
176
+ if (template === "stateful") {
177
+ return {
178
+ src: {
179
+ "infra.ts": `import { StatefulSet, Service } from "@intentius/chant-lexicon-k8s";
180
+
181
+ export const statefulSet = new StatefulSet({
182
+ metadata: { name: "my-db", labels: { "app.kubernetes.io/name": "my-db" } },
183
+ spec: {
184
+ serviceName: "my-db",
185
+ replicas: 3,
186
+ selector: { matchLabels: { "app.kubernetes.io/name": "my-db" } },
187
+ template: {
188
+ metadata: { labels: { "app.kubernetes.io/name": "my-db" } },
189
+ spec: {
190
+ containers: [
191
+ {
192
+ name: "db",
193
+ image: "postgres:16",
194
+ ports: [{ containerPort: 5432, name: "postgres" }],
195
+ volumeMounts: [{ name: "data", mountPath: "/var/lib/postgresql/data" }],
196
+ env: [
197
+ { name: "POSTGRES_DB", value: "mydb" },
198
+ ],
199
+ },
200
+ ],
201
+ },
202
+ },
203
+ volumeClaimTemplates: [
204
+ {
205
+ metadata: { name: "data" },
206
+ spec: {
207
+ accessModes: ["ReadWriteOnce"],
208
+ resources: { requests: { storage: "10Gi" } },
209
+ },
210
+ },
211
+ ],
212
+ },
213
+ });
214
+
215
+ export const service = new Service({
216
+ metadata: { name: "my-db", labels: { "app.kubernetes.io/name": "my-db" } },
217
+ spec: {
218
+ selector: { "app.kubernetes.io/name": "my-db" },
219
+ ports: [{ port: 5432, targetPort: 5432, name: "postgres" }],
220
+ clusterIP: "None",
221
+ },
222
+ });
223
+ `,
224
+ },
225
+ };
226
+ }
227
+ // Default template — Deployment + Service
228
+ return {
229
+ src: {
230
+ "infra.ts": `import { Deployment, Service, Container, Probe } from "@intentius/chant-lexicon-k8s";
231
+
232
+ export const deployment = new Deployment({
233
+ metadata: { name: "my-app", labels: { "app.kubernetes.io/name": "my-app" } },
234
+ spec: {
235
+ replicas: 2,
236
+ selector: { matchLabels: { "app.kubernetes.io/name": "my-app" } },
237
+ template: {
238
+ metadata: { labels: { "app.kubernetes.io/name": "my-app" } },
239
+ spec: {
240
+ containers: [
241
+ new Container({
242
+ name: "app",
243
+ image: "my-app:latest",
244
+ ports: [{ containerPort: 8080, name: "http" }],
245
+ livenessProbe: new Probe({ httpGet: { path: "/healthz", port: 8080 } }),
246
+ readinessProbe: new Probe({ httpGet: { path: "/readyz", port: 8080 } }),
247
+ }),
248
+ ],
249
+ },
250
+ },
251
+ },
252
+ });
253
+
254
+ export const service = new Service({
255
+ metadata: { name: "my-app", labels: { "app.kubernetes.io/name": "my-app" } },
256
+ spec: {
257
+ selector: { "app.kubernetes.io/name": "my-app" },
258
+ ports: [{ port: 80, targetPort: 8080, protocol: "TCP", name: "http" }],
259
+ },
260
+ });
261
+ `,
262
+ },
263
+ };
264
+ },
265
+ detectTemplate,
266
+ completionProvider(ctx) {
267
+ return k8sCompletions(ctx);
268
+ },
269
+ hoverProvider(ctx) {
270
+ return k8sHover(ctx);
271
+ },
272
+ templateParser() {
273
+ return new K8sParser();
274
+ },
275
+ templateGenerator() {
276
+ return new K8sGenerator();
277
+ },
278
+ async docs(options) {
279
+ const { generateDocs } = await import("./codegen/docs.js");
280
+ await generateDocs(options);
281
+ },
282
+ async generate(options) {
283
+ const { generate, writeGeneratedFiles } = await import("./codegen/generate.js");
284
+ const { dirname } = await import("path");
285
+ const { fileURLToPath } = await import("url");
286
+ const result = await generate({ verbose: options?.verbose ?? true });
287
+ const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
288
+ writeGeneratedFiles(result, pkgDir);
289
+ console.error(`Generated ${result.resources} resources, ${result.properties} property types, ${result.enums} enums`);
290
+ if (result.warnings.length > 0) {
291
+ console.error(`${result.warnings.length} warnings`);
292
+ }
293
+ },
294
+ async validate(options) {
295
+ const { validate } = await import("./validate.js");
296
+ const { printValidationResult } = await import("@intentius/chant/codegen/validate");
297
+ const result = await validate();
298
+ printValidationResult(result);
299
+ },
300
+ async coverage(options) {
301
+ const { analyzeK8sCoverage } = await import("./coverage.js");
302
+ await analyzeK8sCoverage({
303
+ verbose: options?.verbose,
304
+ minOverall: options?.minOverall,
305
+ });
306
+ },
307
+ async package(options) {
308
+ const { packageLexicon } = await import("./codegen/package.js");
309
+ const { writeBundleSpec } = await import("@intentius/chant/codegen/package");
310
+ const { join, dirname } = await import("path");
311
+ const { fileURLToPath } = await import("url");
312
+ const { spec, stats } = await packageLexicon({ verbose: options?.verbose, force: options?.force });
313
+ const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
314
+ const distDir = join(pkgDir, "dist");
315
+ writeBundleSpec(spec, distDir);
316
+ console.error(`Packaged ${stats.resources} resources, ${stats.ruleCount} rules, ${stats.skillCount} skills`);
317
+ },
318
+ composites() {
319
+ return compositeCatalog;
320
+ },
321
+ mcpTools() {
322
+ return [createDiffTool(k8sSerializer, "Compare current build output against previous output for Kubernetes manifests", "k8s")];
323
+ },
324
+ mcpResources() {
325
+ return [
326
+ createCatalogResource(import.meta.url, "Kubernetes Resource Catalog", "JSON list of all supported Kubernetes resource types", "lexicon-k8s.json", "k8s"),
327
+ {
328
+ uri: "examples/basic-deployment",
329
+ name: "Basic Deployment Example",
330
+ description: "A basic Kubernetes Deployment with Service",
331
+ mimeType: "text/typescript",
332
+ async handler() {
333
+ return `import { Deployment, Service, Container, Probe } from "@intentius/chant-lexicon-k8s";
334
+
335
+ export const deployment = new Deployment({
336
+ metadata: { name: "my-app", labels: { "app.kubernetes.io/name": "my-app" } },
337
+ spec: {
338
+ replicas: 2,
339
+ selector: { matchLabels: { "app.kubernetes.io/name": "my-app" } },
340
+ template: {
341
+ metadata: { labels: { "app.kubernetes.io/name": "my-app" } },
342
+ spec: {
343
+ containers: [
344
+ new Container({
345
+ name: "app",
346
+ image: "my-app:1.0",
347
+ ports: [{ containerPort: 8080, name: "http" }],
348
+ livenessProbe: new Probe({ httpGet: { path: "/healthz", port: 8080 } }),
349
+ readinessProbe: new Probe({ httpGet: { path: "/readyz", port: 8080 } }),
350
+ }),
351
+ ],
352
+ },
353
+ },
354
+ },
355
+ });
356
+
357
+ export const service = new Service({
358
+ metadata: { name: "my-app" },
359
+ spec: {
360
+ selector: { "app.kubernetes.io/name": "my-app" },
361
+ ports: [{ port: 80, targetPort: 8080, name: "http" }],
362
+ },
363
+ });
364
+ `;
365
+ },
366
+ },
367
+ ];
368
+ },
369
+ skills: createSkillsLoader(import.meta.url, [
370
+ {
371
+ file: "chant-k8s.md",
372
+ name: "chant-k8s",
373
+ description: "Kubernetes manifest lifecycle — scaffold, generate, lint, build, apply, troubleshoot, rollback",
374
+ triggers: [
375
+ { type: "file-pattern", value: "**/*.k8s.ts" },
376
+ { type: "file-pattern", value: "**/k8s/**/*.ts" },
377
+ { type: "context", value: "kubernetes" },
378
+ { type: "context", value: "k8s" },
379
+ { type: "context", value: "kubectl" },
380
+ { type: "context", value: "deployment" },
381
+ { type: "context", value: "pod" },
382
+ { type: "context", value: "composite" },
383
+ { type: "context", value: "autoscaled" },
384
+ { type: "context", value: "workerpool" },
385
+ { type: "context", value: "namespace-env" },
386
+ { type: "context", value: "node-agent" },
387
+ ],
388
+ preConditions: [
389
+ "chant CLI is installed (chant --version succeeds)",
390
+ "kubectl is configured and can access the cluster",
391
+ "Project has chant source files in src/",
392
+ ],
393
+ postConditions: [
394
+ "All pods are in Running state",
395
+ "No CrashLoopBackOff or Error pods",
396
+ ],
397
+ parameters: [],
398
+ examples: [
399
+ {
400
+ title: "Basic deployment",
401
+ description: "Create a Deployment with Service",
402
+ input: "Create a web app deployment",
403
+ output: `new Deployment({
404
+ metadata: { name: "my-app", labels: { "app.kubernetes.io/name": "my-app" } },
405
+ spec: {
406
+ replicas: 2,
407
+ selector: { matchLabels: { "app.kubernetes.io/name": "my-app" } },
408
+ template: {
409
+ metadata: { labels: { "app.kubernetes.io/name": "my-app" } },
410
+ spec: {
411
+ containers: [{
412
+ name: "app",
413
+ image: "my-app:1.0",
414
+ ports: [{ containerPort: 8080 }],
415
+ }],
416
+ },
417
+ },
418
+ },
419
+ })`,
420
+ },
421
+ {
422
+ title: "Deploy to cluster",
423
+ description: "Build and apply manifests",
424
+ input: "Deploy my app to the cluster",
425
+ output: `chant build src/ --output manifests.yaml
426
+ kubectl apply -f manifests.yaml --dry-run=server
427
+ kubectl apply -f manifests.yaml
428
+ kubectl rollout status deployment/my-app`,
429
+ },
430
+ {
431
+ title: "AutoscaledService composite",
432
+ description: "Production HTTP service with HPA, PDB, and zone spreading",
433
+ input: "Create an autoscaled API service",
434
+ output: `import { AutoscaledService } from "@intentius/chant-lexicon-k8s";
435
+
436
+ const { deployment, service, hpa, pdb } = AutoscaledService({
437
+ name: "api",
438
+ image: "api:1.0",
439
+ port: 8080,
440
+ maxReplicas: 10,
441
+ cpuRequest: "100m",
442
+ memoryRequest: "128Mi",
443
+ topologySpread: true,
444
+ });`,
445
+ },
446
+ {
447
+ title: "BatchJob composite",
448
+ description: "One-shot batch job with RBAC",
449
+ input: "Run a database migration job",
450
+ output: `import { BatchJob } from "@intentius/chant-lexicon-k8s";
451
+
452
+ const { job, serviceAccount, role, roleBinding } = BatchJob({
453
+ name: "db-migrate",
454
+ image: "api:1.0",
455
+ command: ["python", "manage.py", "migrate"],
456
+ backoffLimit: 3,
457
+ ttlSecondsAfterFinished: 3600,
458
+ });`,
459
+ },
460
+ ],
461
+ },
462
+ {
463
+ file: "chant-k8s-patterns.md",
464
+ name: "chant-k8s-patterns",
465
+ description: "Advanced K8s patterns — sidecars, observability, TLS, network isolation, config/secret mounting",
466
+ triggers: [
467
+ { type: "context", value: "sidecar" },
468
+ { type: "context", value: "init-container" },
469
+ { type: "context", value: "prometheus" },
470
+ { type: "context", value: "cert-manager" },
471
+ { type: "context", value: "tls" },
472
+ { type: "context", value: "network-policy" },
473
+ { type: "context", value: "canary" },
474
+ { type: "context", value: "blue-green" },
475
+ { type: "context", value: "configmap-mount" },
476
+ { type: "context", value: "secret-mount" },
477
+ ],
478
+ preConditions: [
479
+ "chant CLI is installed (chant --version succeeds)",
480
+ "kubectl is configured and can access the cluster",
481
+ ],
482
+ postConditions: [
483
+ "Pattern resources are deployed and functional",
484
+ ],
485
+ parameters: [],
486
+ examples: [
487
+ {
488
+ title: "Sidecar with envoy proxy",
489
+ description: "Deploy an app with an Envoy sidecar",
490
+ input: "Add an envoy sidecar proxy to my API",
491
+ output: `import { SidecarApp } from "@intentius/chant-lexicon-k8s";
492
+
493
+ const { deployment, service } = SidecarApp({
494
+ name: "api",
495
+ image: "api:1.0",
496
+ port: 8080,
497
+ sidecars: [{ name: "envoy", image: "envoyproxy/envoy:v1.28", ports: [{ containerPort: 9901 }] }],
498
+ });`,
499
+ },
500
+ {
501
+ title: "Monitored service with alerts",
502
+ description: "Deploy a service with Prometheus monitoring and alerting",
503
+ input: "Set up monitoring for my API with error rate alerts",
504
+ output: `import { MonitoredService } from "@intentius/chant-lexicon-k8s";
505
+
506
+ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService({
507
+ name: "api",
508
+ image: "api:1.0",
509
+ metricsPort: 9090,
510
+ alertRules: [{ name: "HighErrorRate", expr: 'rate(http_errors[5m]) > 0.1', severity: "critical" }],
511
+ });`,
512
+ },
513
+ ],
514
+ },
515
+ {
516
+ file: "chant-k8s-deployment-strategies.md",
517
+ name: "chant-k8s-deployment-strategies",
518
+ description: "Kubernetes deployment strategies, stateful workloads, RBAC, and networking patterns",
519
+ triggers: [
520
+ { type: "context", value: "deployment strategy" },
521
+ { type: "context", value: "statefulset" },
522
+ { type: "context", value: "rbac" },
523
+ { type: "context", value: "network policy" },
524
+ { type: "context", value: "rolling update" },
525
+ { type: "context", value: "blue green" },
526
+ ],
527
+ parameters: [],
528
+ examples: [
529
+ {
530
+ title: "Blue/Green Deployment",
531
+ input: "Set up a blue/green deployment for my app",
532
+ output: "import { WebApp } from \"@intentius/chant-lexicon-k8s\";\n\nconst blue = WebApp({ name: \"app-blue\", image: \"app:1.0\" });\nconst green = WebApp({ name: \"app-green\", image: \"app:2.0\" });",
533
+ },
534
+ ],
535
+ },
536
+ {
537
+ file: "chant-k8s-security.md",
538
+ name: "chant-k8s-security",
539
+ description: "Kubernetes pod security, image scanning, network policies, and secrets management",
540
+ triggers: [
541
+ { type: "context", value: "k8s security" },
542
+ { type: "context", value: "pod security" },
543
+ { type: "context", value: "image security" },
544
+ { type: "context", value: "k8s secrets" },
545
+ { type: "context", value: "security context" },
546
+ ],
547
+ parameters: [],
548
+ examples: [
549
+ {
550
+ title: "Hardened Container",
551
+ input: "Create a hardened container with security context",
552
+ output: "WebApp({ name: \"api\", image: \"api:1.0\", securityContext: { runAsNonRoot: true, readOnlyRootFilesystem: true, capabilities: { drop: [\"ALL\"] } } })",
553
+ },
554
+ ],
555
+ },
556
+ {
557
+ file: "chant-k8s-eks.md",
558
+ name: "chant-k8s-eks",
559
+ description: "EKS-specific Kubernetes composites — IRSA, ALB, EBS/EFS, Fluent Bit, ExternalDNS, ADOT",
560
+ triggers: [
561
+ { type: "context", value: "eks composites" },
562
+ { type: "context", value: "irsa" },
563
+ { type: "context", value: "alb ingress" },
564
+ { type: "context", value: "ebs storage" },
565
+ { type: "context", value: "karpenter" },
566
+ ],
567
+ parameters: [],
568
+ examples: [
569
+ {
570
+ title: "IRSA ServiceAccount",
571
+ input: "Create an IRSA ServiceAccount for my app",
572
+ output: "import { IrsaServiceAccount } from \"@intentius/chant-lexicon-k8s\";\n\nconst { serviceAccount } = IrsaServiceAccount({ name: \"app-sa\", iamRoleArn: \"arn:aws:iam::123456789012:role/app-role\" });",
573
+ },
574
+ ],
575
+ },
576
+ {
577
+ file: "chant-k8s-gke.md",
578
+ name: "chant-k8s-gke",
579
+ description: "GKE-specific Kubernetes composites — Workload Identity, GCE PD, Filestore, FluentBit, OTel, ExternalDNS, Gateway",
580
+ triggers: [
581
+ { type: "context", value: "gke composites" },
582
+ { type: "context", value: "workload identity gke" },
583
+ { type: "context", value: "config connector k8s" },
584
+ ],
585
+ parameters: [],
586
+ examples: [
587
+ {
588
+ title: "GKE Workload Identity",
589
+ input: "Create a ServiceAccount with GKE Workload Identity",
590
+ output: "import { WorkloadIdentityServiceAccount } from \"@intentius/chant-lexicon-k8s\";\n\nconst { serviceAccount } = WorkloadIdentityServiceAccount({ name: \"app-sa\", gcpServiceAccountEmail: \"app@project.iam.gserviceaccount.com\" });",
591
+ },
592
+ ],
593
+ },
594
+ {
595
+ file: "chant-k8s-aks.md",
596
+ name: "chant-k8s-aks",
597
+ description: "AKS-specific Kubernetes composites — Workload Identity, AGIC, Azure Disk/File, ExternalDNS, Azure Monitor",
598
+ triggers: [
599
+ { type: "context", value: "aks composites" },
600
+ { type: "context", value: "workload identity aks" },
601
+ { type: "context", value: "agic ingress" },
602
+ ],
603
+ parameters: [],
604
+ examples: [
605
+ {
606
+ title: "AKS Workload Identity",
607
+ input: "Create a ServiceAccount with AKS Workload Identity",
608
+ output: "import { AksWorkloadIdentityServiceAccount } from \"@intentius/chant-lexicon-k8s\";\n\nconst { serviceAccount } = AksWorkloadIdentityServiceAccount({ name: \"app-sa\", clientId: \"12345678-abcd-1234-abcd-123456789012\" });",
609
+ },
610
+ ],
611
+ },
612
+ {
613
+ file: "chant-k8s-argo.md",
614
+ name: "chant-k8s-argo",
615
+ description: "Argo CD composites — ArgoAppFor, ArgoAppSetForRegions, AppProject scoping, cluster registration, and how a deploy splits between Argo and a chant Op",
616
+ triggers: [
617
+ { type: "context", value: "argo" },
618
+ { type: "context", value: "argo cd" },
619
+ { type: "context", value: "argocd" },
620
+ { type: "context", value: "gitops" },
621
+ { type: "context", value: "application" },
622
+ { type: "context", value: "applicationset" },
623
+ { type: "context", value: "appproject" },
624
+ { type: "context", value: "reconcile" },
625
+ ],
626
+ parameters: [],
627
+ examples: [
628
+ {
629
+ title: "Application from a build target",
630
+ description: "Reconcile a Chant build target with Argo CD",
631
+ input: "Deploy my api target through Argo CD",
632
+ output: "import { ArgoAppFor } from \"@intentius/chant-lexicon-k8s\";\n\nexport const api = ArgoAppFor(\"api\", {\n repo: \"https://github.com/acme/infra\",\n path: \"dist/api\",\n destination: { server: \"https://kubernetes.default.svc\", namespace: \"api\" },\n});",
633
+ },
634
+ {
635
+ title: "Per-region ApplicationSet",
636
+ description: "Fan one app out across regional clusters",
637
+ input: "Deploy crdb to east, central, and west clusters via Argo",
638
+ output: "import { ArgoAppSetForRegions } from \"@intentius/chant-lexicon-k8s\";\n\nexport const crdb = ArgoAppSetForRegions(\n [\"east\", \"central\", \"west\"],\n (region) => ({ server: servers[region], namespace: `crdb-${region}`, path: `dist/${region}` }),\n { name: \"crdb\", repo: \"https://github.com/acme/infra\", project: \"crdb\" },\n);",
639
+ },
640
+ ],
641
+ },
642
+ {
643
+ file: "chant-k8s-flux.md",
644
+ name: "chant-k8s-flux",
645
+ description: "Flux CD composites — FluxGitSource + FluxAppFor, the one-source-many-apps shape, dependsOn ordering, the FLUX rules, and the flux-reconcile deploy step",
646
+ triggers: [
647
+ { type: "context", value: "flux" },
648
+ { type: "context", value: "fluxcd" },
649
+ { type: "context", value: "flux cd" },
650
+ { type: "context", value: "gitops" },
651
+ { type: "context", value: "gitrepository" },
652
+ { type: "context", value: "kustomization" },
653
+ { type: "context", value: "source-controller" },
654
+ { type: "context", value: "kustomize-controller" },
655
+ { type: "context", value: "reconcile" },
656
+ ],
657
+ parameters: [],
658
+ examples: [
659
+ {
660
+ title: "Source + Kustomization from a build target",
661
+ description: "Reconcile a Chant build target with Flux",
662
+ input: "Deploy my app through Flux",
663
+ output: "import { FluxGitSource, FluxAppFor } from \"@intentius/chant-lexicon-k8s\";\n\nexport const source = FluxGitSource(\"infra\", {\n url: \"https://github.com/acme/infra\",\n branch: \"main\",\n});\n\nexport const app = FluxAppFor(\"app\", {\n source,\n path: \"./dist/apps/app\",\n dependsOn: [\"platform\"],\n});",
664
+ },
665
+ {
666
+ title: "One source, many apps",
667
+ description: "The multi-app repo shape — one GitRepository shared by every Kustomization",
668
+ input: "Reconcile platform, api, and web from one repo with ordering",
669
+ output: "import { FluxGitSource, FluxAppFor } from \"@intentius/chant-lexicon-k8s\";\n\nconst source = FluxGitSource(\"infra\", { url: \"https://github.com/acme/infra\" });\n\nexport const platform = FluxAppFor(\"platform\", { source, path: \"./dist/platform\" });\nexport const api = FluxAppFor(\"api\", { source, path: \"./dist/apps/api\", dependsOn: [\"platform\"] });\nexport const web = FluxAppFor(\"web\", { source, path: \"./dist/apps/web\", dependsOn: [\"platform\", \"api\"] });",
670
+ },
671
+ ],
672
+ },
673
+ ]),
674
+ async describeResources(options) {
675
+ const { describeResources } = await import("./describe-resources.js");
676
+ return describeResources(options);
677
+ },
678
+ /**
679
+ * Who chant would act as in this cluster, before it acts (#1982) — the
680
+ * connector's own context/credential resolution plus the API server's
681
+ * `SelfSubjectReview`, reported through the same connect path the read uses
682
+ * so the cluster named is the cluster read. Implementation in ./whoami.ts.
683
+ */
684
+ async describeIdentity(options) {
685
+ const { describeIdentity } = await import("./whoami.js");
686
+ return describeIdentity(options);
687
+ },
688
+ // Env teardown (#1222): enumeration + execution over the marker label
689
+ // selector (managed-by + stack + env), through the same typed client the
690
+ // prune uses. Execution deletes namespaces last. See ./teardown.ts.
691
+ async teardownOwned(options) {
692
+ const { teardownOwned } = await import("./teardown.js");
693
+ return teardownOwned(options);
694
+ },
695
+ async executeTeardown(options) {
696
+ const { executeTeardown } = await import("./teardown.js");
697
+ return executeTeardown(options);
698
+ },
699
+ /**
700
+ * Deploy-unit presence + health for `chant components status --live`
701
+ * (#1495 piece 3): a Kubernetes deploy unit is the label selector chant's
702
+ * own serializer stamps, so this reads back
703
+ * `app.kubernetes.io/managed-by=chant, chant.intentius.io/stack=<stack>`
704
+ * and rolls readiness up from the matching workloads' controllers.
705
+ */
706
+ async describeStackStatus(options) {
707
+ const { describeStackStatus } = await import("./describe-stack-status.js");
708
+ return describeStackStatus(options);
709
+ },
710
+ async exportResources(options) {
711
+ const { exportResources } = await import("./export-resources.js");
712
+ return exportResources(options);
713
+ },
714
+ /**
715
+ * The change signal (#1981). A Watch on every declared kind, reported as a
716
+ * bare `onChange()` that wakes an operator tick early. Nothing a frame
717
+ * carries reaches the tick: the seam has no payload, and the tick that runs
718
+ * is the tick the timer would have run. Kubernetes is the one substrate
719
+ * chant reaches whose change stream needs nothing deployed into the observed
720
+ * cluster; see the verdict table in the operator guide. Implementation in
721
+ * ./subscribe-changes.ts, dynamically imported for the same reason
722
+ * describeResources is.
723
+ */
724
+ async subscribeChanges(options) {
725
+ const { subscribeChanges } = await import("./subscribe-changes.js");
726
+ return subscribeChanges(options);
727
+ },
728
+ // Property-level live drift via SSA managed-fields (#1076, epic #1073).
729
+ // The reader lives in ./deep-observe.ts, loaded only through this dynamic
730
+ // import — same reason describeResources/exportResources are — so the API
731
+ // client never becomes reachable from the build path (chant #1074,
732
+ // examples/k8s-client-boundary.test.ts). deepNormalizationHooks is plain
733
+ // data with no client dependency (./deep-observe-hooks.ts) and is imported
734
+ // statically above, because core applies it to the *declared* tree whether
735
+ // or not a live read ever happens.
736
+ async observeResourcesDeep(options) {
737
+ const { observeResourcesDeepK8s } = await import("./deep-observe.js");
738
+ return observeResourcesDeepK8s(options);
739
+ },
740
+ deepNormalizationHooks: k8sDeepNormalizationHooks,
741
+ };