@intentius/chant-lexicon-helm 0.1.4 → 0.1.8

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 (50) hide show
  1. package/dist/integrity.json +34 -34
  2. package/dist/manifest.json +1 -1
  3. package/package.json +8 -8
  4. package/src/codegen/docs-cli.ts +1 -1
  5. package/src/codegen/docs.test.ts +2 -2
  6. package/src/codegen/generate-cli.ts +1 -1
  7. package/src/codegen/generate.test.ts +3 -3
  8. package/src/codegen/package.test.ts +2 -2
  9. package/src/codegen/package.ts +1 -3
  10. package/src/composites/composites.test.ts +1 -1
  11. package/src/coverage.test.ts +1 -1
  12. package/src/helpers.test.ts +1 -1
  13. package/src/import/import.test.ts +1 -1
  14. package/src/import/roundtrip.test.ts +1 -1
  15. package/src/intrinsics.test.ts +1 -1
  16. package/src/lint/post-synth/post-synth.test.ts +1 -1
  17. package/src/lint/post-synth/whm101.test.ts +1 -1
  18. package/src/lint/post-synth/whm102.test.ts +1 -1
  19. package/src/lint/post-synth/whm103.test.ts +1 -1
  20. package/src/lint/post-synth/whm104.test.ts +1 -1
  21. package/src/lint/post-synth/whm105.test.ts +1 -1
  22. package/src/lint/post-synth/whm201.test.ts +1 -1
  23. package/src/lint/post-synth/whm202.test.ts +1 -1
  24. package/src/lint/post-synth/whm203.test.ts +1 -1
  25. package/src/lint/post-synth/whm204.test.ts +1 -1
  26. package/src/lint/post-synth/whm301.test.ts +1 -1
  27. package/src/lint/post-synth/whm302.test.ts +1 -1
  28. package/src/lint/post-synth/whm401.test.ts +1 -1
  29. package/src/lint/post-synth/whm402.test.ts +1 -1
  30. package/src/lint/post-synth/whm403.test.ts +1 -1
  31. package/src/lint/post-synth/whm404.test.ts +1 -1
  32. package/src/lint/post-synth/whm405.test.ts +1 -1
  33. package/src/lint/post-synth/whm406.test.ts +1 -1
  34. package/src/lint/post-synth/whm407.test.ts +1 -1
  35. package/src/lint/post-synth/whm501.test.ts +1 -1
  36. package/src/lint/post-synth/whm502.test.ts +1 -1
  37. package/src/lint/rules/chart-metadata.test.ts +1 -1
  38. package/src/lint/rules/lint-rules.test.ts +1 -1
  39. package/src/lint/rules/no-hardcoded-image.test.ts +1 -1
  40. package/src/lint/rules/values-no-secrets.test.ts +1 -1
  41. package/src/list-artifacts.test.ts +94 -0
  42. package/src/list-artifacts.ts +79 -0
  43. package/src/lsp/completions.test.ts +1 -1
  44. package/src/lsp/hover.test.ts +1 -1
  45. package/src/package-cli.ts +1 -1
  46. package/src/plugin.test.ts +1 -1
  47. package/src/plugin.ts +7 -2
  48. package/src/serializer.test.ts +4 -5
  49. package/src/validate-cli.ts +1 -1
  50. package/src/validate.test.ts +1 -1
@@ -1,38 +1,38 @@
1
1
  {
2
- "algorithm": "xxhash64",
2
+ "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "63a0898ec956a5de",
5
- "meta.json": "b7aab243e162dfaf",
6
- "types/index.d.ts": "e8011da51963f058",
7
- "rules/values-no-helm-tpl.ts": "ed23236546936fd0",
8
- "rules/chart-metadata.ts": "d0cff2b78fed78d3",
9
- "rules/values-no-secrets.ts": "213276bfe1fb8ff7",
10
- "rules/no-hardcoded-image.ts": "c75aa9c33016c3b9",
11
- "rules/whm301.ts": "f3ed3a269093527",
12
- "rules/whm104.ts": "e2d644da2a9dc605",
13
- "rules/whm005-no-empty-wrapper.ts": "1a1baea985f0bd86",
14
- "rules/whm103.ts": "a777a13f2eaf1831",
15
- "rules/whm406.ts": "c76ac5a44c3e9dcd",
16
- "rules/whm405.ts": "ec82442f9120e5e0",
17
- "rules/whm105.ts": "8977ec834713b90c",
18
- "rules/whm403.ts": "729d10edb48b0d03",
19
- "rules/whm203.ts": "2bb546d268c84232",
20
- "rules/whm407.ts": "f1fbc6942aff8e96",
21
- "rules/whm502.ts": "2c9901ecbfaf92cb",
22
- "rules/whm404.ts": "8847425e930d41c1",
23
- "rules/whm402.ts": "f722014a723654af",
24
- "rules/whm302.ts": "44e58ce621ae6d1a",
25
- "rules/whm501.ts": "e9a9f2b4e034a51f",
26
- "rules/helm-helpers.ts": "2e0cc249268227ed",
27
- "rules/whm101.ts": "533ae8f65cb2227b",
28
- "rules/whm102.ts": "4c0c494c253df56a",
29
- "rules/whm401.ts": "fe72c3c450a12f93",
30
- "rules/whm201.ts": "f263fe69901552eb",
31
- "rules/whm202.ts": "dbe1cbb3237be84f",
32
- "rules/whm204.ts": "7b57de71795fc102",
33
- "skills/chant-helm.md": "6476c552b9235085",
34
- "skills/chant-helm-patterns.md": "cc9bfe5595f22710",
35
- "skills/chant-helm-security.md": "a7b950513dac7d37"
4
+ "manifest.json": "d4a9a8168563da87916d1ff56334f061b9e7f573dd37a4b34714863a8570df1e",
5
+ "meta.json": "14243c5730a07c6a6edc35ddd351438547d58df5cf345f2233a355b0c7611ccc",
6
+ "types/index.d.ts": "5377696ca8698cd2999e4680feb8e8e4b54a7b49fb603a87b2f27356114d1794",
7
+ "rules/chart-metadata.ts": "8f3377e893d5e2828460b7fe5924fca098334245a9a2fdb90f6b67e490eaf091",
8
+ "rules/no-hardcoded-image.ts": "b00433bd5f4e963ffd56d8a623c00fbfaa40dc37b6d72609d26c91a309d75a90",
9
+ "rules/values-no-helm-tpl.ts": "bd30478da004bafaed6ed6231636f1e2867f5255deb6313c8f6e3505c5c91b11",
10
+ "rules/values-no-secrets.ts": "ec9193fb39764e65e44022e39fda124147350e4d2b4e2e34deaa5db82116f76c",
11
+ "rules/helm-helpers.ts": "c2631bbf261573c553e475cfc2f1b007fc5feb4b1f986b5ba660f3290f4d3eaf",
12
+ "rules/whm005-no-empty-wrapper.ts": "bfecf05449106c639b317eecdcd969ad2a851c4be9ee029380f99278e2a19630",
13
+ "rules/whm101.ts": "6fb49f184cec898640118a3ce14edc5d62c05c694491b0eab4e53dbc10921e8d",
14
+ "rules/whm102.ts": "99ea2a695b49fe39e20b8dccdec5bcf5b189e08ac026318ce633fbf9a226132d",
15
+ "rules/whm103.ts": "80f533af6d9bae924a3cc3ceedf158f13d4138d6ef3115a0e3093f5a0464592d",
16
+ "rules/whm104.ts": "1752338ade55c87dafee23dc09e0150c4ae55ac90eb8b8e9010c89b7ad73503d",
17
+ "rules/whm105.ts": "d710b04267c558839ec99001e0b4604017ef6484e7083585fe160192a5920d69",
18
+ "rules/whm201.ts": "0de1a8cad242feadbb4e9c4e0eebfb94df1f2c2bf535802ebf535067f7859619",
19
+ "rules/whm202.ts": "6a2fc424d8b753113cd13de565ce93dfd1cdf0e606c56977b9e17e92147abf54",
20
+ "rules/whm203.ts": "d98176fd2a2c0d6ddc2d3b37180c5e7be618b47b6c12821df9b51cfe7950d938",
21
+ "rules/whm204.ts": "b5e37aea05662e16e02843e20e4642de82b666026d58e1ebf18c337768fdaff8",
22
+ "rules/whm301.ts": "0ed09a07a8f3d59fb3c2bc330e7b92f7c2eb31655b6a301b06b10b485fe12edc",
23
+ "rules/whm302.ts": "d4cb8cdf776e4bdf0551fc8ab28c584f66efbe6648aef0b325acb07e415da73b",
24
+ "rules/whm401.ts": "a49b41ff9837f2c9ada011d4ee31fffe8e68b278d50badbab32459ea05bc4a01",
25
+ "rules/whm402.ts": "917f85fbc4d31c9b7eec5eda684aa24b847d33bd6f0507bdc435c1796bd66476",
26
+ "rules/whm403.ts": "716cc86eb1a4ba345ef875ac50cef033d017edf50964695ec9399b593d3bcce2",
27
+ "rules/whm404.ts": "e4c7d6877fb3f658ce3a109722fa65b508d7160e186fdf5a63d8ddfc6262e218",
28
+ "rules/whm405.ts": "6d7d230b94e694c3b94dd8fbfe719856c1fbf171ef6dd0552843f56f6c512c03",
29
+ "rules/whm406.ts": "79ce3b318ce53ee74bbf814ae31e0873fe882096dcb5c5369495bed022dbf57d",
30
+ "rules/whm407.ts": "200190f5de2d86d2bcc5aee0b5ce4807919ec727b1fc14576ea17b9b3073838b",
31
+ "rules/whm501.ts": "e6afa7c0eface9820380bf189fe8be58f4a6997dd5b74f76335022650616d080",
32
+ "rules/whm502.ts": "c3ed7b4b5215d96e46eba758aca2171928d8f8fb1eb20452ea6b4393672755b0",
33
+ "skills/chant-helm.md": "94528606c7a972f478d3c716eb7fe5fd79a6520532ccc4f9a3c99e9b0d691025",
34
+ "skills/chant-helm-patterns.md": "9e79e6a46391da46709d8aa57e2825a7cd9eb981cd923f02ad60836c49b2561e",
35
+ "skills/chant-helm-security.md": "bfc367eabceed2e84f1cf94501b407df78aeed963cec104f24a321d0962063c9"
36
36
  },
37
- "composite": "3af38f2aed6c80fd"
37
+ "composite": "ca5dd2d974996391ad2e74466d0b3e8d2c879212cbf72b56ebe1499d6bb7d897"
38
38
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helm",
3
- "version": "0.1.4",
3
+ "version": "0.1.8",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "Helm",
6
6
  "intrinsics": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-helm",
3
- "version": "0.1.4",
3
+ "version": "0.1.8",
4
4
  "description": "Helm chart lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -36,17 +36,17 @@
36
36
  "./types": "./dist/types/index.d.ts"
37
37
  },
38
38
  "scripts": {
39
- "generate": "bun run src/codegen/generate-cli.ts",
40
- "bundle": "bun run src/package-cli.ts",
41
- "validate": "bun run src/validate-cli.ts",
42
- "docs": "bun run src/codegen/docs-cli.ts",
43
- "prepack": "bun run generate && bun run bundle && bun run validate"
39
+ "generate": "tsx src/codegen/generate-cli.ts",
40
+ "bundle": "tsx src/package-cli.ts",
41
+ "validate": "tsx src/validate-cli.ts",
42
+ "docs": "tsx src/codegen/docs-cli.ts",
43
+ "prepack": "npm run generate && npm run bundle && npm run validate"
44
44
  },
45
45
  "dependencies": {
46
- "@intentius/chant-lexicon-k8s": "0.1.4"
46
+ "@intentius/chant-lexicon-k8s": "*"
47
47
  },
48
48
  "devDependencies": {
49
- "@intentius/chant": "0.1.4",
49
+ "@intentius/chant": "*",
50
50
  "typescript": "^5.9.3"
51
51
  },
52
52
  "peerDependencies": {
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  import { generateDocs } from "./docs";
3
3
 
4
4
  await generateDocs({ verbose: true });
@@ -1,9 +1,9 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
 
3
3
  describe("Helm docs generation", () => {
4
4
  test("docs module is importable", async () => {
5
5
  const mod = await import("./docs");
6
- expect(mod.generateDocs).toBeFunction();
6
+ expect(typeof mod.generateDocs).toBe("function");
7
7
  });
8
8
 
9
9
  test("generateDocs function signature accepts options", async () => {
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  /**
3
3
  * CLI entry point for Helm lexicon generation.
4
4
  */
@@ -1,11 +1,11 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { generate } from "./generate";
3
3
 
4
4
  describe("Helm generate pipeline", () => {
5
5
  test("generate module is importable", async () => {
6
6
  const mod = await import("./generate");
7
- expect(mod.generate).toBeFunction();
8
- expect(mod.writeGeneratedFiles).toBeFunction();
7
+ expect(typeof mod.generate).toBe("function");
8
+ expect(typeof mod.writeGeneratedFiles).toBe("function");
9
9
  });
10
10
 
11
11
  test("generates lexicon JSON, types, and index", async () => {
@@ -1,10 +1,10 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { packageLexicon } from "./package";
3
3
 
4
4
  describe("Helm package pipeline", () => {
5
5
  test("packageLexicon is importable", async () => {
6
6
  const mod = await import("./package");
7
- expect(mod.packageLexicon).toBeFunction();
7
+ expect(typeof mod.packageLexicon).toBe("function");
8
8
  });
9
9
 
10
10
  test("packageLexicon returns a valid result", async () => {
@@ -3,11 +3,10 @@
3
3
  * with Helm-specific manifest building and skill collection.
4
4
  */
5
5
 
6
- import { createRequire } from "module";
7
6
  import { readFileSync } from "fs";
8
- const require = createRequire(import.meta.url);
9
7
  import { join, dirname } from "path";
10
8
  import { fileURLToPath } from "url";
9
+ import { helmPlugin } from "../plugin";
11
10
  import {
12
11
  packagePipeline,
13
12
  collectSkills,
@@ -52,7 +51,6 @@ export async function packageLexicon(opts: PackageOptions = {}): Promise<Package
52
51
  srcDir: pkgDir,
53
52
 
54
53
  collectSkills: () => {
55
- const { helmPlugin } = require("../plugin");
56
54
  const skillDefs = helmPlugin.skills?.() ?? [];
57
55
  return collectSkills(skillDefs);
58
56
  },
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { INTRINSIC_MARKER } from "@intentius/chant/intrinsic";
3
3
  import { HelmWebApp } from "./helm-web-app";
4
4
  import { HelmStatefulService } from "./helm-stateful-service";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { existsSync } from "fs";
3
3
  import { join, dirname } from "path";
4
4
  import { fileURLToPath } from "url";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { generateHelpers } from "./helpers";
3
3
 
4
4
  describe("generateHelpers", () => {
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { stripTemplateExpressions, classifyExpression } from "./template-stripper";
3
3
  import { HelmParser } from "./parser";
4
4
  import { HelmGenerator } from "./generator";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { HelmParser } from "./parser";
3
3
  import { HelmGenerator } from "./generator";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { INTRINSIC_MARKER } from "@intentius/chant/intrinsic";
3
3
  import {
4
4
  HelmTpl,
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm101 } from "./whm101";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm101 } from "./whm101";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm102 } from "./whm102";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm103 } from "./whm103";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm104 } from "./whm104";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm105 } from "./whm105";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm201 } from "./whm201";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm202 } from "./whm202";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm203 } from "./whm203";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm204 } from "./whm204";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm301 } from "./whm301";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm302 } from "./whm302";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm401 } from "./whm401";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm402 } from "./whm402";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm403 } from "./whm403";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm404 } from "./whm404";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm405 } from "./whm405";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm406 } from "./whm406";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm407 } from "./whm407";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm501 } from "./whm501";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
3
3
  import type { SerializerResult } from "@intentius/chant/serializer";
4
4
  import { whm502 } from "./whm502";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import type { LintContext } from "@intentius/chant/lint/rule";
4
4
  import { chartMetadataRule } from "./chart-metadata";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import type { LintContext } from "@intentius/chant/lint/rule";
4
4
  import { chartMetadataRule } from "./chart-metadata";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import type { LintContext } from "@intentius/chant/lint/rule";
4
4
  import { noHardcodedImageRule } from "./no-hardcoded-image";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import type { LintContext } from "@intentius/chant/lint/rule";
4
4
  import { valuesNoSecretsRule } from "./values-no-secrets";
@@ -0,0 +1,94 @@
1
+ import { describe, test, expect, vi, beforeEach } from "vitest";
2
+
3
+ const execMock = vi.fn();
4
+ vi.mock("node:child_process", async () => {
5
+ const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
6
+ return { ...actual, exec: (cmd: string, cb: (err: Error | null, out: { stdout: string; stderr: string }) => void) => {
7
+ Promise.resolve(execMock(cmd)).then(
8
+ (out) => cb(null, out),
9
+ (err) => cb(err as Error, { stdout: "", stderr: "" }),
10
+ );
11
+ } };
12
+ });
13
+
14
+ const { listArtifacts } = await import("./list-artifacts");
15
+
16
+ describe("helm listArtifacts", () => {
17
+ beforeEach(() => {
18
+ execMock.mockReset();
19
+ });
20
+
21
+ test("queries `helm list -A -o json` and maps releases to artifacts", async () => {
22
+ let receivedCmd = "";
23
+ execMock.mockImplementation((cmd: string) => {
24
+ receivedCmd = cmd;
25
+ return {
26
+ stdout: JSON.stringify([
27
+ {
28
+ name: "web", namespace: "default", revision: "1",
29
+ updated: "2026-05-09 10:00:00.000000 +0000 UTC",
30
+ status: "deployed", chart: "web-1.0.0", app_version: "1.0",
31
+ },
32
+ {
33
+ name: "redis", namespace: "infra", revision: "3",
34
+ updated: "2026-05-09 09:00:00.000000 +0000 UTC",
35
+ status: "deployed", chart: "redis-7.4.0", app_version: "7.4",
36
+ },
37
+ ]),
38
+ stderr: "",
39
+ };
40
+ });
41
+
42
+ const result = await listArtifacts({ environment: "prod", entities: new Map() });
43
+
44
+ expect(receivedCmd).toBe("helm list -A -o json");
45
+ expect(Object.keys(result).sort()).toEqual(["release/default/web", "release/infra/redis"]);
46
+ expect(result["release/default/web"]).toEqual({
47
+ type: "Helm::Release",
48
+ physicalId: "default/web",
49
+ status: "deployed",
50
+ lastUpdated: "2026-05-09 10:00:00.000000 +0000 UTC",
51
+ attributes: { chart: "web-1.0.0", revision: "1", appVersion: "1.0", namespace: "default" },
52
+ });
53
+ });
54
+
55
+ test("helm binary not installed → returns {} cleanly", async () => {
56
+ execMock.mockImplementation(() => { throw new Error("helm: command not found"); });
57
+ const result = await listArtifacts({ environment: "prod", entities: new Map() });
58
+ expect(result).toEqual({});
59
+ });
60
+
61
+ test("empty cluster (no releases) → returns {}", async () => {
62
+ execMock.mockResolvedValue({ stdout: "[]", stderr: "" });
63
+ const result = await listArtifacts({ environment: "prod", entities: new Map() });
64
+ expect(result).toEqual({});
65
+ });
66
+
67
+ test("status mapping for non-deployed states surfaces correctly", async () => {
68
+ execMock.mockResolvedValue({
69
+ stdout: JSON.stringify([
70
+ { name: "broken", namespace: "default", revision: "2", status: "failed", chart: "x-1.0", app_version: "1" },
71
+ ]),
72
+ stderr: "",
73
+ });
74
+ const result = await listArtifacts({ environment: "prod", entities: new Map() });
75
+ expect(result["release/default/broken"].status).toBe("failed");
76
+ });
77
+
78
+ test("revision attribute changes between releases (drift signal)", async () => {
79
+ execMock.mockResolvedValue({
80
+ stdout: JSON.stringify([
81
+ { name: "web", namespace: "default", revision: "5", status: "deployed", chart: "web-2.0.0", app_version: "2.0" },
82
+ ]),
83
+ stderr: "",
84
+ });
85
+ const result = await listArtifacts({ environment: "prod", entities: new Map() });
86
+ expect(result["release/default/web"].attributes).toMatchObject({ revision: "5", chart: "web-2.0.0" });
87
+ });
88
+
89
+ test("malformed JSON output → returns {} (don't fail the snapshot)", async () => {
90
+ execMock.mockResolvedValue({ stdout: "not json", stderr: "" });
91
+ const result = await listArtifacts({ environment: "prod", entities: new Map() });
92
+ expect(result).toEqual({});
93
+ });
94
+ });
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Live introspection of Helm releases via `helm list -A -o json`.
3
+ *
4
+ * The Helm lexicon's chant entities describe chart-authoring primitives
5
+ * (Chart.yaml, templates/, values.yaml). The runtime concept — a Helm
6
+ * release installed in a kubeconfig context — is created by `helm install`
7
+ * outside chant's entity model. This implementation reports those releases
8
+ * as artifacts so `state diff --live` / `WatchOp` can detect manual
9
+ * installs/upgrades/rollbacks that slip past CI.
10
+ *
11
+ * Helm-not-installed (binary missing) → returns `{}` cleanly so other
12
+ * lexicons' snapshots aren't blocked.
13
+ */
14
+
15
+ import { exec } from "node:child_process";
16
+ import { promisify } from "node:util";
17
+ import type { ArtifactMetadata } from "@intentius/chant/lexicon";
18
+
19
+ const execAsync = promisify(exec);
20
+
21
+ interface HelmListEntry {
22
+ name?: string;
23
+ namespace?: string;
24
+ revision?: string;
25
+ updated?: string;
26
+ status?: string;
27
+ chart?: string;
28
+ app_version?: string;
29
+ }
30
+
31
+ function pruneUndefined<T extends Record<string, unknown>>(obj: T): Record<string, unknown> {
32
+ const out: Record<string, unknown> = {};
33
+ for (const [k, v] of Object.entries(obj)) {
34
+ if (v !== undefined) out[k] = v;
35
+ }
36
+ return out;
37
+ }
38
+
39
+ export async function listArtifacts(_options: {
40
+ environment: string;
41
+ entities: Map<string, { entityType: string; props: Record<string, unknown> }>;
42
+ }): Promise<Record<string, ArtifactMetadata>> {
43
+ const result: Record<string, ArtifactMetadata> = {};
44
+
45
+ let stdout: string;
46
+ try {
47
+ ({ stdout } = await execAsync("helm list -A -o json"));
48
+ } catch {
49
+ // Binary not installed, no kubeconfig, or some other error — return
50
+ // empty rather than blocking the whole snapshot.
51
+ return result;
52
+ }
53
+
54
+ let entries: HelmListEntry[];
55
+ try {
56
+ entries = JSON.parse(stdout);
57
+ } catch {
58
+ return result;
59
+ }
60
+
61
+ for (const entry of entries) {
62
+ if (!entry.name || !entry.namespace) continue;
63
+ const key = `release/${entry.namespace}/${entry.name}`;
64
+ result[key] = {
65
+ type: "Helm::Release",
66
+ physicalId: `${entry.namespace}/${entry.name}`,
67
+ status: entry.status ?? "unknown",
68
+ lastUpdated: entry.updated,
69
+ attributes: pruneUndefined({
70
+ chart: entry.chart,
71
+ revision: entry.revision,
72
+ appVersion: entry.app_version,
73
+ namespace: entry.namespace,
74
+ }),
75
+ };
76
+ }
77
+
78
+ return result;
79
+ }
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { existsSync } from "fs";
3
3
  import { join, dirname } from "path";
4
4
  import { fileURLToPath } from "url";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { existsSync } from "fs";
3
3
  import { join, dirname } from "path";
4
4
  import { fileURLToPath } from "url";
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  /**
3
3
  * CLI entry point for Helm lexicon packaging.
4
4
  */
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { helmPlugin } from "./plugin";
3
3
  import { isLexiconPlugin } from "@intentius/chant/lexicon";
4
4
 
package/src/plugin.ts CHANGED
@@ -65,13 +65,13 @@ export const helmPlugin: LexiconPlugin = {
65
65
  },
66
66
 
67
67
  mcpTools() {
68
- return [createDiffTool(helmSerializer, "Compare current Helm chart build output against previous output")];
68
+ return [createDiffTool(helmSerializer, "Compare current Helm chart build output against previous output", "helm")];
69
69
  },
70
70
 
71
71
  mcpResources() {
72
72
  return [
73
73
  {
74
- uri: "resource-catalog",
74
+ uri: "helm:resource-catalog",
75
75
  name: "Helm Chart Resource Catalog",
76
76
  description: "JSON list of all supported Helm chart resource types",
77
77
  mimeType: "application/json",
@@ -374,4 +374,9 @@ export const service = new Service({
374
374
 
375
375
  console.error(`Packaged ${stats.resources} resources, ${stats.ruleCount} rules, ${stats.skillCount} skills`);
376
376
  },
377
+
378
+ async listArtifacts(options) {
379
+ const { listArtifacts } = await import("./list-artifacts");
380
+ return listArtifacts(options);
381
+ },
377
382
  };
@@ -1,8 +1,9 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { createResource, createProperty } from "@intentius/chant/runtime";
3
3
  import type { Declarable } from "@intentius/chant/declarable";
4
4
  import type { SerializerResult } from "@intentius/chant/serializer";
5
5
  import { helmSerializer } from "./serializer";
6
+ import { generateHelpers } from "./helpers";
6
7
  import { Chart, Values, ValuesOverride, HelmNotes, HelmTest, HelmHook, HelmDependency, HelmMaintainer, HelmCRD } from "./resources";
7
8
  import { values, include, printf, toYaml, quote, helmDefault, required, If, ElseIf, Range, With, Release, ChartRef, Capabilities, runtimeSlot } from "./intrinsics";
8
9
 
@@ -318,12 +319,12 @@ describe("resource-level If", () => {
318
319
  const template = result.files!["templates/ingress.yaml"];
319
320
 
320
321
  expect(template).toBeDefined();
321
- expect(template).toStartWith("{{- if .Values.ingress.enabled }}\n");
322
+ expect(template.startsWith("{{- if .Values.ingress.enabled }}\n")).toBe(true);
322
323
  expect(template).toContain("apiVersion: networking.k8s.io/v1");
323
324
  expect(template).toContain("kind: Ingress");
324
325
  expect(template).toContain('{{ include "test.fullname" . }}');
325
326
  expect(template).toContain("{{ .Values.ingress.host }}");
326
- expect(template.trimEnd()).toEndWith("{{- end }}");
327
+ expect(template.trimEnd().endsWith("{{- end }}")).toBe(true);
327
328
  });
328
329
 
329
330
  test("does not wrap non-conditional resources", () => {
@@ -905,7 +906,6 @@ describe("ValuesOverride serialization", () => {
905
906
 
906
907
  describe("helpers", () => {
907
908
  test("generateHelpers includes all standard templates", () => {
908
- const { generateHelpers } = require("./helpers");
909
909
  const content = generateHelpers({ chartName: "my-chart" });
910
910
 
911
911
  expect(content).toContain('define "my-chart.name"');
@@ -917,7 +917,6 @@ describe("helpers", () => {
917
917
  });
918
918
 
919
919
  test("generateHelpers respects includeServiceAccount=false", () => {
920
- const { generateHelpers } = require("./helpers");
921
920
  const content = generateHelpers({ chartName: "test", includeServiceAccount: false });
922
921
 
923
922
  expect(content).toContain('define "test.name"');
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  /**
3
3
  * CLI entry point for Helm lexicon validation.
4
4
  */
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { existsSync } from "fs";
3
3
  import { join, dirname } from "path";
4
4
  import { fileURLToPath } from "url";