@intentius/chant-lexicon-helm 0.0.16

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 (110) hide show
  1. package/README.md +22 -0
  2. package/dist/integrity.json +36 -0
  3. package/dist/manifest.json +37 -0
  4. package/dist/meta.json +208 -0
  5. package/dist/rules/chart-metadata.ts +64 -0
  6. package/dist/rules/helm-helpers.ts +64 -0
  7. package/dist/rules/no-hardcoded-image.ts +62 -0
  8. package/dist/rules/values-no-secrets.ts +82 -0
  9. package/dist/rules/whm101.ts +46 -0
  10. package/dist/rules/whm102.ts +33 -0
  11. package/dist/rules/whm103.ts +59 -0
  12. package/dist/rules/whm104.ts +35 -0
  13. package/dist/rules/whm105.ts +30 -0
  14. package/dist/rules/whm201.ts +36 -0
  15. package/dist/rules/whm202.ts +50 -0
  16. package/dist/rules/whm203.ts +39 -0
  17. package/dist/rules/whm204.ts +60 -0
  18. package/dist/rules/whm301.ts +41 -0
  19. package/dist/rules/whm302.ts +40 -0
  20. package/dist/rules/whm401.ts +57 -0
  21. package/dist/rules/whm402.ts +45 -0
  22. package/dist/rules/whm403.ts +45 -0
  23. package/dist/rules/whm404.ts +36 -0
  24. package/dist/rules/whm405.ts +53 -0
  25. package/dist/rules/whm406.ts +34 -0
  26. package/dist/rules/whm407.ts +83 -0
  27. package/dist/rules/whm501.ts +103 -0
  28. package/dist/rules/whm502.ts +94 -0
  29. package/dist/skills/chant-helm-chart-patterns.md +229 -0
  30. package/dist/skills/chant-helm-chart-security-patterns.md +192 -0
  31. package/dist/skills/chant-helm-create-chart.md +211 -0
  32. package/dist/types/index.d.ts +132 -0
  33. package/package.json +34 -0
  34. package/src/codegen/docs-cli.ts +4 -0
  35. package/src/codegen/docs.ts +483 -0
  36. package/src/codegen/generate-cli.ts +28 -0
  37. package/src/codegen/generate.ts +249 -0
  38. package/src/codegen/naming.ts +38 -0
  39. package/src/codegen/package.ts +64 -0
  40. package/src/composites/composites.test.ts +1050 -0
  41. package/src/composites/helm-batch-job.ts +209 -0
  42. package/src/composites/helm-crd-lifecycle.ts +184 -0
  43. package/src/composites/helm-cron-job.ts +177 -0
  44. package/src/composites/helm-daemon-set.ts +169 -0
  45. package/src/composites/helm-external-secret.ts +93 -0
  46. package/src/composites/helm-library.ts +51 -0
  47. package/src/composites/helm-microservice.ts +331 -0
  48. package/src/composites/helm-monitored-service.ts +252 -0
  49. package/src/composites/helm-namespace-env.ts +154 -0
  50. package/src/composites/helm-secure-ingress.ts +114 -0
  51. package/src/composites/helm-stateful-service.ts +213 -0
  52. package/src/composites/helm-web-app.ts +264 -0
  53. package/src/composites/helm-worker.ts +207 -0
  54. package/src/composites/index.ts +38 -0
  55. package/src/coverage.test.ts +21 -0
  56. package/src/coverage.ts +50 -0
  57. package/src/generated/index.d.ts +132 -0
  58. package/src/generated/index.ts +13 -0
  59. package/src/generated/lexicon-helm.json +208 -0
  60. package/src/helpers.test.ts +51 -0
  61. package/src/helpers.ts +100 -0
  62. package/src/import/generator.ts +285 -0
  63. package/src/import/import.test.ts +224 -0
  64. package/src/import/parser.ts +160 -0
  65. package/src/import/template-stripper.ts +123 -0
  66. package/src/index.ts +108 -0
  67. package/src/intrinsics.test.ts +380 -0
  68. package/src/intrinsics.ts +484 -0
  69. package/src/lint/post-synth/helm-helpers.ts +64 -0
  70. package/src/lint/post-synth/post-synth.test.ts +504 -0
  71. package/src/lint/post-synth/whm101.ts +46 -0
  72. package/src/lint/post-synth/whm102.ts +33 -0
  73. package/src/lint/post-synth/whm103.ts +59 -0
  74. package/src/lint/post-synth/whm104.ts +35 -0
  75. package/src/lint/post-synth/whm105.ts +30 -0
  76. package/src/lint/post-synth/whm201.ts +36 -0
  77. package/src/lint/post-synth/whm202.ts +50 -0
  78. package/src/lint/post-synth/whm203.ts +39 -0
  79. package/src/lint/post-synth/whm204.ts +60 -0
  80. package/src/lint/post-synth/whm301.ts +41 -0
  81. package/src/lint/post-synth/whm302.ts +40 -0
  82. package/src/lint/post-synth/whm401.ts +57 -0
  83. package/src/lint/post-synth/whm402.ts +45 -0
  84. package/src/lint/post-synth/whm403.ts +45 -0
  85. package/src/lint/post-synth/whm404.ts +36 -0
  86. package/src/lint/post-synth/whm405.ts +53 -0
  87. package/src/lint/post-synth/whm406.ts +34 -0
  88. package/src/lint/post-synth/whm407.ts +83 -0
  89. package/src/lint/post-synth/whm501.ts +103 -0
  90. package/src/lint/post-synth/whm502.ts +94 -0
  91. package/src/lint/rules/chart-metadata.ts +64 -0
  92. package/src/lint/rules/lint-rules.test.ts +97 -0
  93. package/src/lint/rules/no-hardcoded-image.ts +62 -0
  94. package/src/lint/rules/values-no-secrets.ts +82 -0
  95. package/src/lsp/completions.test.ts +72 -0
  96. package/src/lsp/completions.ts +20 -0
  97. package/src/lsp/hover.test.ts +46 -0
  98. package/src/lsp/hover.ts +46 -0
  99. package/src/package-cli.ts +28 -0
  100. package/src/plugin.test.ts +71 -0
  101. package/src/plugin.ts +206 -0
  102. package/src/resources.ts +77 -0
  103. package/src/serializer.test.ts +930 -0
  104. package/src/serializer.ts +835 -0
  105. package/src/skills/chart-patterns.md +229 -0
  106. package/src/skills/chart-security-patterns.md +192 -0
  107. package/src/skills/create-chart.md +211 -0
  108. package/src/validate-cli.ts +21 -0
  109. package/src/validate.test.ts +37 -0
  110. package/src/validate.ts +36 -0
@@ -0,0 +1,483 @@
1
+ /**
2
+ * Documentation generation for the Helm lexicon.
3
+ *
4
+ * Generates Starlight MDX pages for Helm entities using the core docs pipeline.
5
+ */
6
+
7
+ import { dirname, join } from "path";
8
+ import { fileURLToPath } from "url";
9
+ import { docsPipeline, writeDocsSite, type DocsConfig } from "@intentius/chant/codegen/docs";
10
+
11
+ function serviceFromType(resourceType: string): string {
12
+ const parts = resourceType.split("::");
13
+ return parts.length >= 2 ? parts[1] : "Helm";
14
+ }
15
+
16
+ const overview = `The **Helm** lexicon generates production-quality, parameterized Helm charts from typed TypeScript.
17
+
18
+ Unlike static manifest generators, the Helm lexicon produces real \`{{ .Values.x }}\` directives, \`values.yaml\`, \`values.schema.json\`, conditional resources, Helm hooks, and standard \`_helpers.tpl\`.
19
+
20
+ Install it with:
21
+
22
+ \`\`\`bash
23
+ npm install --save-dev @intentius/chant-lexicon-helm @intentius/chant-lexicon-k8s
24
+ \`\`\`
25
+
26
+ ## Quick Start
27
+
28
+ \`\`\`typescript
29
+ import { Chart, Values } from "@intentius/chant-lexicon-helm";
30
+ import { values, include, printf, toYaml } from "@intentius/chant-lexicon-helm";
31
+ import { Deployment, Service } from "@intentius/chant-lexicon-k8s";
32
+
33
+ export const chart = new Chart({
34
+ apiVersion: "v2",
35
+ name: "my-app",
36
+ version: "0.1.0",
37
+ type: "application",
38
+ });
39
+
40
+ export const valuesSchema = new Values({
41
+ replicaCount: 1,
42
+ image: { repository: "nginx", tag: "", pullPolicy: "IfNotPresent" },
43
+ service: { type: "ClusterIP", port: 80 },
44
+ });
45
+
46
+ export const deployment = new Deployment({
47
+ metadata: {
48
+ name: include("my-app.fullname"),
49
+ labels: include("my-app.labels"),
50
+ },
51
+ spec: {
52
+ replicas: values.replicaCount,
53
+ template: {
54
+ spec: {
55
+ containers: [{
56
+ name: "my-app",
57
+ image: printf("%s:%s", values.image.repository, values.image.tag),
58
+ ports: [{ containerPort: values.service.port, name: "http" }],
59
+ resources: toYaml(values.resources),
60
+ }],
61
+ },
62
+ },
63
+ },
64
+ });
65
+ \`\`\`
66
+
67
+ Build the chart:
68
+
69
+ \`\`\`bash
70
+ chant build
71
+ helm lint dist/
72
+ helm template test dist/
73
+ \`\`\`
74
+ `;
75
+
76
+ const outputFormat = `## Output structure
77
+
78
+ The Helm serializer produces a complete chart directory:
79
+
80
+ \`\`\`
81
+ dist/
82
+ Chart.yaml ← from Chart entity
83
+ values.yaml ← from Values entity (defaults)
84
+ values.schema.json ← auto-generated JSON Schema from Values types
85
+ .helmignore
86
+ templates/
87
+ _helpers.tpl ← auto-generated standard helpers
88
+ deployment.yaml ← K8s resources with {{ .Values.x }} directives
89
+ service.yaml
90
+ NOTES.txt ← from HelmNotes entity
91
+ tests/
92
+ test-connection.yaml ← from HelmTest entities
93
+ \`\`\`
94
+ `;
95
+
96
+ export async function generateDocs(opts?: { verbose?: boolean }): Promise<void> {
97
+ const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
98
+
99
+ const config: DocsConfig = {
100
+ name: "helm",
101
+ displayName: "Helm",
102
+ description: "Typed constructors for parameterized Helm charts",
103
+ distDir: join(pkgDir, "dist"),
104
+ outDir: join(pkgDir, "docs"),
105
+ overview,
106
+ outputFormat,
107
+ serviceFromType,
108
+ suppressPages: ["pseudo-parameters"],
109
+ extraPages: [
110
+ {
111
+ slug: "getting-started",
112
+ title: "Getting Started",
113
+ description: "Create your first typed Helm chart in 5 minutes",
114
+ content: `## What is the Helm lexicon?
115
+
116
+ The Helm lexicon extends chant to produce **real, parameterized Helm charts** from typed TypeScript. Unlike static manifest generators (like cdk8s's Helm output), the Helm lexicon generates:
117
+
118
+ - \`{{ .Values.x }}\` template directives
119
+ - \`values.yaml\` with typed defaults
120
+ - \`values.schema.json\` for validation
121
+ - Conditional resources via \`{{- if }}\`
122
+ - Standard \`_helpers.tpl\`
123
+ - Helm hooks and tests
124
+
125
+ ## Install
126
+
127
+ \`\`\`bash
128
+ npm install --save-dev @intentius/chant @intentius/chant-lexicon-helm @intentius/chant-lexicon-k8s
129
+ \`\`\`
130
+
131
+ ## Your first chart
132
+
133
+ \`\`\`bash
134
+ chant init --lexicon helm
135
+ \`\`\`
136
+
137
+ This creates a scaffold with a Chart, Values, Deployment, and Service. Run \`chant build\` to produce a complete Helm chart directory.
138
+
139
+ ## Key imports
140
+
141
+ \`\`\`typescript
142
+ // Resources
143
+ import { Chart, Values, HelmNotes } from "@intentius/chant-lexicon-helm";
144
+
145
+ // Intrinsics (produce Go template expressions)
146
+ import { values, Release, include, printf, toYaml, If } from "@intentius/chant-lexicon-helm";
147
+
148
+ // K8s resources
149
+ import { Deployment, Service, Ingress } from "@intentius/chant-lexicon-k8s";
150
+ \`\`\`
151
+ `,
152
+ },
153
+ {
154
+ slug: "intrinsics",
155
+ title: "Intrinsics Reference",
156
+ description: "All Helm template intrinsics and how they map to Go template expressions",
157
+ content: `## Values proxy
158
+
159
+ \`\`\`typescript
160
+ import { values } from "@intentius/chant-lexicon-helm";
161
+
162
+ values.replicaCount // {{ .Values.replicaCount }}
163
+ values.image.repository // {{ .Values.image.repository }}
164
+ values.x.pipe("upper") // {{ .Values.x | upper }}
165
+ \`\`\`
166
+
167
+ ## Built-in objects
168
+
169
+ \`\`\`typescript
170
+ import { Release, ChartRef } from "@intentius/chant-lexicon-helm";
171
+
172
+ Release.Name // {{ .Release.Name }}
173
+ Release.Namespace // {{ .Release.Namespace }}
174
+ Release.IsUpgrade // {{ .Release.IsUpgrade }}
175
+ ChartRef.Name // {{ .Chart.Name }}
176
+ ChartRef.Version // {{ .Chart.Version }}
177
+ \`\`\`
178
+
179
+ ## Template functions
180
+
181
+ | Function | Output |
182
+ |----------|--------|
183
+ | \`include("name")\` | \`{{ include "name" . }}\` |
184
+ | \`required("msg", values.x)\` | \`{{ required "msg" .Values.x }}\` |
185
+ | \`helmDefault("val", values.x)\` | \`{{ default "val" .Values.x }}\` |
186
+ | \`toYaml(values.x)\` | \`{{ toYaml .Values.x }}\` |
187
+ | \`toYaml(values.x, 12)\` | \`{{ toYaml .Values.x \\| nindent 12 }}\` |
188
+ | \`quote(values.x)\` | \`{{ .Values.x \\| quote }}\` |
189
+ | \`printf("%s:%s", a, b)\` | \`{{ printf "%s:%s" a b }}\` |
190
+ | \`tpl(values.x)\` | \`{{ tpl .Values.x . }}\` |
191
+ | \`lookup("v1", "Secret", "ns", "name")\` | \`{{ lookup "v1" "Secret" "ns" "name" }}\` |
192
+
193
+ ## Control flow
194
+
195
+ \`\`\`typescript
196
+ import { If, Range, With, values } from "@intentius/chant-lexicon-helm";
197
+
198
+ // Conditional resource
199
+ export const ingress = If(values.ingress.enabled, new Ingress({ ... }));
200
+
201
+ // Conditional value
202
+ const image = If(values.image.tag, printf("%s:%s", values.image.repo, values.image.tag));
203
+ \`\`\`
204
+
205
+ ## Resource ordering
206
+
207
+ | Function | Output |
208
+ |----------|--------|
209
+ | \`withOrder(5)\` | \`helm.sh/hook: pre-install,pre-upgrade\` + \`helm.sh/hook-weight: "5"\` |
210
+ | \`argoWave(2)\` | \`argocd.argoproj.io/sync-wave: "2"\` |
211
+
212
+ \`\`\`typescript
213
+ import { withOrder, argoWave } from "@intentius/chant-lexicon-helm";
214
+
215
+ const job = new Job({
216
+ metadata: { annotations: { ...withOrder(-5) } },
217
+ // ...
218
+ });
219
+ \`\`\`
220
+ `,
221
+ },
222
+ {
223
+ slug: "composites",
224
+ title: "Composites",
225
+ description: "Pre-built Helm chart patterns",
226
+ content: `## Available composites
227
+
228
+ | Composite | Description | Resources |
229
+ |-----------|-------------|-----------|
230
+ | \`HelmWebApp\` | Web application | Deployment, Service, Ingress?, HPA?, ServiceAccount? |
231
+ | \`HelmStatefulService\` | Stateful workload | StatefulSet, headless Service, PVC |
232
+ | \`HelmCronJob\` | Scheduled job | CronJob |
233
+ | \`HelmMicroservice\` | Full microservice | Deployment, Service, Ingress?, HPA?, PDB?, ServiceAccount, ConfigMap? |
234
+ | \`HelmLibrary\` | Library chart | Chart.yaml (type: library), _helpers.tpl |
235
+ | \`HelmCRDLifecycle\` | Managed CRD lifecycle | Job (hook), ConfigMap, ServiceAccount, ClusterRole, ClusterRoleBinding |
236
+ | \`HelmDaemonSet\` | Node-level workload | DaemonSet, ServiceAccount? |
237
+ | \`HelmWorker\` | Background processor | Deployment (no Service), ServiceAccount, HPA?, PDB? |
238
+ | \`HelmExternalSecret\` | Secret management | ExternalSecret CR (external-secrets.io) |
239
+ | \`HelmBatchJob\` | One-shot batch job | Job, ServiceAccount?, Role?, RoleBinding? |
240
+ | \`HelmMonitoredService\` | Service with monitoring | Deployment, Service, ServiceAccount?, ServiceMonitor, PrometheusRule? |
241
+ | \`HelmSecureIngress\` | TLS ingress + cert-manager | Ingress, Certificate? |
242
+ | \`HelmNamespaceEnv\` | Namespace environment | Namespace, ResourceQuota?, LimitRange?, NetworkPolicy? |
243
+
244
+ ## Example
245
+
246
+ \`\`\`typescript
247
+ import { HelmWebApp } from "@intentius/chant-lexicon-helm";
248
+
249
+ const result = HelmWebApp({
250
+ name: "my-app",
251
+ imageRepository: "myregistry/app",
252
+ port: 3000,
253
+ replicas: 3,
254
+ ingress: true,
255
+ autoscaling: true,
256
+ });
257
+
258
+ // result.chart, result.values, result.deployment, result.service, result.ingress, result.hpa
259
+ \`\`\`
260
+ `,
261
+ },
262
+ {
263
+ slug: "rules",
264
+ title: "Lint Rules",
265
+ description: "Pre-synth and post-synth lint rules for Helm charts",
266
+ content: `## Pre-synth rules (AST-level)
267
+
268
+ | Rule | Severity | Description |
269
+ |------|----------|-------------|
270
+ | WHM001 | error | Chart must have name, version, and apiVersion |
271
+ | WHM002 | warning | Values should not contain bare secrets (password, token, key) |
272
+ | WHM003 | warning | Container images should use values references, not hardcoded tags |
273
+
274
+ ## Post-synth checks (output validation)
275
+
276
+ | Check | Severity | Description |
277
+ |-------|----------|-------------|
278
+ | WHM101 | error | Chart.yaml has required fields and apiVersion v2 |
279
+ | WHM102 | warning | values.schema.json present when Values type used |
280
+ | WHM103 | error | Go template syntax valid (balanced braces) |
281
+ | WHM104 | info | NOTES.txt exists for application charts |
282
+ | WHM105 | warning | _helpers.tpl exists |
283
+ | WHM201 | info | Resources have standard Helm labels |
284
+ | WHM202 | info | Hook weights defined for multi-hook charts |
285
+ | WHM203 | info | Values entries documented |
286
+ | WHM204 | warning | Dependencies use semver ranges |
287
+ | WHM301 | info | At least one test for application charts |
288
+ | WHM302 | info | Resource limits set (via values or defaults) |
289
+ | WHM401 | warning | Image uses :latest tag or no tag |
290
+ | WHM402 | warning | runAsNonRoot not set in security context |
291
+ | WHM403 | info | readOnlyRootFilesystem not set |
292
+ | WHM404 | error | privileged: true detected |
293
+ | WHM405 | warning | Resource spec missing cpu/memory detail |
294
+ | WHM406 | info | CRDs in crds/ — Helm never upgrades/deletes them |
295
+ | WHM407 | warning | Secret with inline data, no ExternalSecret/SealedSecret |
296
+ | WHM501 | info | Values keys defined but never referenced in templates |
297
+ | WHM502 | warning | Deprecated or invalid K8s API versions |
298
+ `,
299
+ },
300
+ {
301
+ slug: "security",
302
+ title: "Security",
303
+ description: "Security best practices and checks for Helm charts",
304
+ content: `## Secret management
305
+
306
+ Avoid inline secrets in Kubernetes Secret manifests. Use ExternalSecret or SealedSecret instead:
307
+
308
+ \`\`\`typescript
309
+ import { HelmExternalSecret } from "@intentius/chant-lexicon-helm";
310
+
311
+ const { externalSecret, values } = HelmExternalSecret({
312
+ name: "app-secrets",
313
+ secretStoreName: "vault",
314
+ data: {
315
+ DB_PASSWORD: "secret/data/db-password",
316
+ API_KEY: "secret/data/api-key",
317
+ },
318
+ });
319
+ \`\`\`
320
+
321
+ WHM407 warns when a \`kind: Secret\` template contains inline data values without an ExternalSecret or SealedSecret in the chart.
322
+
323
+ ## Security context best practices
324
+
325
+ Always set security context on pods and containers:
326
+
327
+ \`\`\`typescript
328
+ spec: {
329
+ securityContext: {
330
+ runAsNonRoot: true,
331
+ runAsUser: 1000,
332
+ },
333
+ containers: [{
334
+ securityContext: {
335
+ readOnlyRootFilesystem: true,
336
+ allowPrivilegeEscalation: false,
337
+ },
338
+ }],
339
+ }
340
+ \`\`\`
341
+
342
+ ### Related checks
343
+
344
+ | Check | Severity | Description |
345
+ |-------|----------|-------------|
346
+ | WHM401 | warning | Image uses :latest tag or no tag |
347
+ | WHM402 | warning | runAsNonRoot not set |
348
+ | WHM403 | info | readOnlyRootFilesystem not set |
349
+ | WHM404 | error | privileged: true detected |
350
+ | WHM405 | warning | Resource spec missing cpu/memory |
351
+ | WHM406 | info | CRD lifecycle limitation |
352
+ | WHM407 | warning | Secret with inline data |
353
+
354
+ ## Image pinning
355
+
356
+ Always pin container images to specific tags or digests:
357
+
358
+ \`\`\`typescript
359
+ // Bad — triggers WHM401
360
+ image: "nginx:latest"
361
+ image: "nginx"
362
+
363
+ // Good
364
+ image: printf("%s:%s", values.image.repository, values.image.tag)
365
+ \`\`\`
366
+
367
+ Set a specific default tag in your values:
368
+
369
+ \`\`\`typescript
370
+ const valuesSchema = new Values({
371
+ image: {
372
+ repository: "nginx",
373
+ tag: "1.25.0", // Pinned version
374
+ pullPolicy: "IfNotPresent",
375
+ },
376
+ });
377
+ \`\`\`
378
+ `,
379
+ },
380
+ {
381
+ slug: "best-practices",
382
+ title: "Best Practices",
383
+ description: "Common patterns and recommendations for Helm charts with chant",
384
+ content: `## CRD lifecycle
385
+
386
+ Helm installs CRDs from the \`crds/\` directory but **never upgrades or deletes them**. For managed CRD lifecycle, use the \`HelmCRDLifecycle\` composite:
387
+
388
+ \`\`\`typescript
389
+ import { HelmCRDLifecycle } from "@intentius/chant-lexicon-helm";
390
+
391
+ const lifecycle = HelmCRDLifecycle({
392
+ name: "my-operator",
393
+ crdContent: crdYaml,
394
+ kubectlImage: "bitnami/kubectl",
395
+ kubectlTag: "1.28",
396
+ });
397
+ \`\`\`
398
+
399
+ This creates a Job-based hook that runs \`kubectl apply\` for CRDs during pre-install/pre-upgrade, with proper RBAC.
400
+
401
+ ## Resource ordering
402
+
403
+ Use \`withOrder()\` for Helm hook ordering and \`argoWave()\` for Argo CD sync waves:
404
+
405
+ \`\`\`typescript
406
+ import { withOrder, argoWave } from "@intentius/chant-lexicon-helm";
407
+
408
+ // Helm hook ordering (lower weight = runs first)
409
+ metadata: { annotations: { ...withOrder(-5) } }
410
+
411
+ // Argo CD sync waves
412
+ metadata: { annotations: { ...argoWave(1) } }
413
+ \`\`\`
414
+
415
+ ## Multi-environment values
416
+
417
+ Structure your chant project with base values and environment overlays:
418
+
419
+ \`\`\`
420
+ src/
421
+ chart.ts ← Base chart with shared values
422
+ values-dev.yaml ← Override for dev
423
+ values-staging.yaml ← Override for staging
424
+ values-prod.yaml ← Override for production
425
+ \`\`\`
426
+
427
+ Use \`helm install -f values-prod.yaml\` to merge environment-specific values.
428
+
429
+ ## List merge workaround
430
+
431
+ Helm's strategic merge patch does not merge lists — it replaces them. Use map-of-maps instead:
432
+
433
+ \`\`\`typescript
434
+ // Instead of a list (hard to override per-environment)
435
+ hosts: [{ host: "app.example.com" }]
436
+
437
+ // Use a map-of-maps pattern
438
+ hosts:
439
+ primary:
440
+ host: "app.example.com"
441
+ paths: [{ path: "/", pathType: "Prefix" }]
442
+ \`\`\`
443
+
444
+ ## Unused values
445
+
446
+ WHM501 detects values keys that are defined but never referenced in templates. This helps keep \`values.yaml\` clean and avoids confusion.
447
+
448
+ ## Deprecated API versions
449
+
450
+ WHM502 detects deprecated Kubernetes API versions (like \`extensions/v1beta1\` for Ingress) and suggests current replacements.
451
+ `,
452
+ },
453
+ {
454
+ slug: "skills",
455
+ title: "AI Skills",
456
+ description: "AI agent skills bundled with the Helm lexicon",
457
+ content: `## What are skills?
458
+
459
+ Skills are structured markdown documents bundled with a lexicon. When an AI agent works in a chant project, it discovers and loads relevant skills automatically — giving it operational knowledge about the Helm chart workflow.
460
+
461
+ ## Bundled skill: chant-helm
462
+
463
+ The \`chant-helm\` skill teaches AI agents how to:
464
+
465
+ - Scaffold new Helm chart projects with \`chant init --lexicon helm\`
466
+ - Use Helm intrinsics (values proxy, include, printf, toYaml, If/Range/With)
467
+ - Build and validate charts with chant + helm CLI
468
+ - Debug common issues (unbalanced braces, hardcoded images, missing metadata)
469
+ - Use composites for common patterns (WebApp, Microservice, StatefulService)
470
+
471
+ When you scaffold a new project with \`chant init --lexicon helm\`, the skill is installed to \`skills/chant-helm/SKILL.md\` for automatic discovery by Claude Code.
472
+ `,
473
+ },
474
+ ],
475
+ };
476
+
477
+ const result = await docsPipeline(config);
478
+ writeDocsSite(result, config.outDir);
479
+
480
+ if (opts?.verbose) {
481
+ console.error(`Generated ${result.pages.length} documentation pages`);
482
+ }
483
+ }
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * CLI entry point for Helm lexicon generation.
4
+ */
5
+
6
+ import { dirname } from "path";
7
+ import { fileURLToPath } from "url";
8
+ import { generate, writeGeneratedFiles } from "./generate";
9
+
10
+ const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
11
+
12
+ async function main() {
13
+ const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");
14
+
15
+ console.error("Generating Helm lexicon (static types)...");
16
+
17
+ const result = await generate({ verbose });
18
+ writeGeneratedFiles(result, pkgDir);
19
+
20
+ console.error(
21
+ `Generated ${result.resources} resources, ${result.properties} property types`,
22
+ );
23
+ }
24
+
25
+ main().catch((err) => {
26
+ console.error("Generation failed:", err);
27
+ process.exit(1);
28
+ });