@intentius/chant-lexicon-gitlab 0.1.0 → 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 (54) hide show
  1. package/README.md +10 -0
  2. package/dist/integrity.json +31 -31
  3. package/dist/manifest.json +1 -1
  4. package/dist/skills/chant-gitlab.md +3 -0
  5. package/package.json +7 -7
  6. package/src/codegen/__snapshots__/snapshot.test.ts.snap +5 -5
  7. package/src/codegen/docs.ts +7 -3
  8. package/src/codegen/fetch.test.ts +1 -1
  9. package/src/codegen/generate-cli.ts +1 -1
  10. package/src/codegen/generate.test.ts +1 -1
  11. package/src/codegen/idempotency.test.ts +1 -1
  12. package/src/codegen/naming.test.ts +1 -1
  13. package/src/codegen/package.ts +2 -5
  14. package/src/codegen/parse.test.ts +1 -1
  15. package/src/codegen/patches.test.ts +1 -1
  16. package/src/codegen/snapshot.test.ts +1 -1
  17. package/src/codegen/typecheck.test.ts +1 -1
  18. package/src/composites/composites.test.ts +1 -1
  19. package/src/coverage.test.ts +1 -1
  20. package/src/import/generator.test.ts +1 -1
  21. package/src/import/parser.test.ts +1 -1
  22. package/src/import/roundtrip.test.ts +1 -1
  23. package/src/intrinsics.test.ts +1 -1
  24. package/src/lint/post-synth/post-synth.test.ts +1 -1
  25. package/src/lint/post-synth/wgl012.test.ts +1 -1
  26. package/src/lint/post-synth/wgl013.test.ts +1 -1
  27. package/src/lint/post-synth/wgl014.test.ts +1 -1
  28. package/src/lint/post-synth/wgl015.test.ts +1 -1
  29. package/src/lint/post-synth/wgl016.test.ts +1 -1
  30. package/src/lint/post-synth/wgl017.test.ts +1 -1
  31. package/src/lint/post-synth/wgl018.test.ts +1 -1
  32. package/src/lint/post-synth/wgl019.test.ts +1 -1
  33. package/src/lint/post-synth/wgl020.test.ts +1 -1
  34. package/src/lint/post-synth/wgl021.test.ts +1 -1
  35. package/src/lint/post-synth/wgl022.test.ts +1 -1
  36. package/src/lint/post-synth/wgl023.test.ts +1 -1
  37. package/src/lint/post-synth/wgl024.test.ts +1 -1
  38. package/src/lint/post-synth/wgl025.test.ts +1 -1
  39. package/src/lint/post-synth/wgl026.test.ts +1 -1
  40. package/src/lint/post-synth/wgl027.test.ts +1 -1
  41. package/src/lint/post-synth/wgl028.test.ts +1 -1
  42. package/src/lint/rules/rules.test.ts +1 -1
  43. package/src/lsp/completions.test.ts +1 -1
  44. package/src/lsp/hover.test.ts +1 -1
  45. package/src/package-cli.ts +2 -2
  46. package/src/plugin.test.ts +4 -4
  47. package/src/plugin.ts +10 -12
  48. package/src/serializer.test.ts +1 -1
  49. package/src/skills/chant-gitlab.md +3 -0
  50. package/src/testdata/create-fixture.ts +3 -3
  51. package/src/testdata/load-fixtures.ts +1 -1
  52. package/src/validate-cli.ts +2 -2
  53. package/src/validate.test.ts +1 -1
  54. package/src/variables.test.ts +1 -1
package/README.md CHANGED
@@ -17,6 +17,16 @@ npm install --save-dev @intentius/chant @intentius/chant-lexicon-gitlab
17
17
  | [@intentius/chant](https://www.npmjs.com/package/@intentius/chant) | Core type system, CLI, build pipeline |
18
18
  | [@intentius/chant-lexicon-aws](https://www.npmjs.com/package/@intentius/chant-lexicon-aws) | AWS CloudFormation lexicon |
19
19
 
20
+ ## Runtime observation: N/A
21
+
22
+ `chant state snapshot` and `chant state diff --live` operate by querying a runtime equivalent of each declared resource. The GitLab lexicon doesn't fit that model:
23
+
24
+ - The lexicon's chant entities (`Job`, `Workflow`, `Default`, `Image`, `Rule`, etc.) describe **CI pipeline definitions**, which are git-tracked. Drift in the definition itself is just `git diff` — no observation surface needed.
25
+ - Pipeline **runs** are events (per-execution), not declared state. They're observable via the GitLab API but the abstraction is `listRecentRuns()`, not `describeResources()` or `listArtifacts()`. That's a separate plugin contract if/when it's needed.
26
+ - "Is this workflow enabled in the GitLab UI?" is theoretically observable but a marginal use case.
27
+
28
+ If a concrete observation use case surfaces, file a focused issue rather than retrofitting `listArtifacts()` to fit.
29
+
20
30
  ## License
21
31
 
22
32
  See the main project LICENSE file.
@@ -1,35 +1,35 @@
1
1
  {
2
- "algorithm": "xxhash64",
2
+ "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "5e3bc0d403d8f621",
5
- "meta.json": "c663c6c63748a9d0",
6
- "types/index.d.ts": "64e65524615be023",
7
- "rules/missing-stage.ts": "6d5379e74209a735",
8
- "rules/missing-script.ts": "923dde9acb46cc28",
9
- "rules/deprecated-only-except.ts": "1f5a8c785777fb03",
10
- "rules/artifact-no-expiry.ts": "26874cb6adfbca26",
11
- "rules/wgl018.ts": "6ba77c7fa7a59f25",
12
- "rules/wgl012.ts": "3d188d13fb2236c0",
13
- "rules/wgl024.ts": "54fe7a6aec3d3e23",
14
- "rules/wgl020.ts": "eff135a38c29ff2f",
15
- "rules/wgl017.ts": "a9d460f549725f85",
16
- "rules/wgl023.ts": "d02ea51ac7da06c4",
17
- "rules/wgl011.ts": "b6b97e5104d91267",
18
- "rules/wgl021.ts": "42470ba28e215bae",
19
- "rules/wgl015.ts": "d7e9e080994f985",
20
- "rules/wgl025.ts": "fcdf14c9d296e7b5",
21
- "rules/wgl026.ts": "7c7a15478b702349",
22
- "rules/wgl010.ts": "1548cad287cdf286",
23
- "rules/wgl013.ts": "3519c933e23fc605",
24
- "rules/wgl028.ts": "77c31c05a975bacb",
25
- "rules/wgl016.ts": "f76358f42b1f39ea",
26
- "rules/wgl022.ts": "adba5b533dc416c9",
27
- "rules/wgl019.ts": "5a4ab8ebb115f074",
28
- "rules/wgl027.ts": "ea7928f37607a583",
29
- "rules/wgl014.ts": "6248a852888e8028",
30
- "rules/yaml-helpers.ts": "3e414c7affe56728",
31
- "skills/chant-gitlab.md": "fe29add147305b7e",
32
- "skills/chant-gitlab-patterns.md": "efb54bd8ea52071b"
4
+ "manifest.json": "028f9a5d3b18be085acb465fda8da6ed24113b6048008d46a02af5215024e394",
5
+ "meta.json": "931fc3246a55645b1493080bbeb160e5d205e42349e8bdca96ca243adb5f0da3",
6
+ "types/index.d.ts": "5cd2e99f135a929b72bdd822d00d780d39b1cd407ba0cfb3d511c7ac9d667b58",
7
+ "rules/artifact-no-expiry.ts": "3f3cabf9792cbf8207e53a25f506715466b19ec25e9c3b4d0d77fed6b2eb4542",
8
+ "rules/deprecated-only-except.ts": "2341b95c0aaf3013c375fb404969858e23451e3430f3d1a63b128fcb21b90156",
9
+ "rules/missing-script.ts": "1dba062d77fa248fc02857fd08bc7789f90eefd3206e552ac63782a04b843888",
10
+ "rules/missing-stage.ts": "ce810703cba6c8942282c4ebaeff23fe3312c4ecc362acce05baf85d0fd32ea3",
11
+ "rules/wgl010.ts": "e9a14d5f9e4c49b1524ba5ee3746be739603125ec3c2dc4eb4b7c0bfc32581b0",
12
+ "rules/wgl011.ts": "15954191c836d416f27585303b24bfbe458779520212fa47e854f2214a4deef6",
13
+ "rules/wgl012.ts": "baf33141114cfd80316fb1f0f7cf23d8966c58d0bb7c6cd99d92166cfe7e900b",
14
+ "rules/wgl013.ts": "f1309b1c048c00684181b9488a633f44068b537fd743ac21b0ae2712478158ba",
15
+ "rules/wgl014.ts": "acbbeec029ec7f23e74cebcd4965dae12ea991a5a29e754040edd4a0c3fd8f0c",
16
+ "rules/wgl015.ts": "040da46b2fe8126ba18c8d44957b402a710537eca0dc05d885498022ccec006a",
17
+ "rules/wgl016.ts": "d8bf9a371b22f37a767f92e3361d5f8e064e6dd6ba879ff1a5fc90b4b09fd304",
18
+ "rules/wgl017.ts": "2d212de62eee4f7b086b49c92975b09d988c1ff05c2fb20cffccdc500a14e668",
19
+ "rules/wgl018.ts": "6ba795cb9dddcc6f3432f4ffc86f2351d9db0e7fa1a71ffb35791d3631a73bad",
20
+ "rules/wgl019.ts": "9bc86b3f8e8f5a4b52fffc728c15850ce89b1a5c9e6a400ced987e24fc1b56f6",
21
+ "rules/wgl020.ts": "81a84b49308f36ab2b01342bd0e262b59b2a8395d233760ac52a679c2a4ae0e6",
22
+ "rules/wgl021.ts": "59a75e0b0123779bcd4c7f66eb068c4302860df8333a4bc7b41c68e3983505da",
23
+ "rules/wgl022.ts": "b901e9c5386cdcd9ac61cf94ead46ffeb08a6c0bb7b02e54e916075160c41eca",
24
+ "rules/wgl023.ts": "8a34c5bd5cf690bc3b22c583d2fc1412cf8c9b438c0e18385ebd119983e8b8de",
25
+ "rules/wgl024.ts": "07db98e5e3d7419f347e9c717e834b207168df9e8d029db61e9c3e3769ca9ccf",
26
+ "rules/wgl025.ts": "52dbd9d363230fd5bdea0407bc3363d408dd5f750c58c83cf8d87e55568bb81c",
27
+ "rules/wgl026.ts": "b7d9f075aa8fc9623e28745b68c2368c223c2899641cbb7796952018717dcee5",
28
+ "rules/wgl027.ts": "1ff29b9101a268c58756593b0d86396b557a79527b5dc390c190ae224c12597a",
29
+ "rules/wgl028.ts": "f1c64eda25e2ad8da634d64a397f877a46ae8327713db5cf3193882bb9b96453",
30
+ "rules/yaml-helpers.ts": "f2322530a7fd812e482c5a7df05d0d05787b207574b67b811776786e00fd3e18",
31
+ "skills/chant-gitlab.md": "1e26a0c50ea891423479bd7fec3bc133f9185727c4a3eaadd525d7e7436056b6",
32
+ "skills/chant-gitlab-patterns.md": "cefda1b656f222293d16381dfbf452b2b376b545a69f62e55dc38907fe8aa7fa"
33
33
  },
34
- "composite": "690703aa91a047dd"
34
+ "composite": "2f6e473cfad9b8e3afca160af10cfeb880fe4c71c90f15f9723ee620770e1549"
35
35
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitlab",
3
- "version": "0.1.0",
3
+ "version": "0.1.8",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "GitLab",
6
6
  "intrinsics": [
@@ -35,6 +35,7 @@ This creates `src/` with chant pipeline definitions. It does NOT create applicat
35
35
  |----------|-------------------|----------|
36
36
  | *(default)* | `config.ts` + `pipeline.ts` with build/test jobs | Custom pipelines from scratch |
37
37
  | `node-pipeline` | `NodePipeline` composite with npm install/build/test | Node.js apps |
38
+ | `bun-pipeline` | `BunPipeline` composite — Bun runtime with frozen lockfile | Bun apps |
38
39
  | `python-pipeline` | `PythonPipeline` composite with venv/pytest | Python apps |
39
40
  | `docker-build` | `DockerBuild` composite + test job | Containerized apps |
40
41
  | `review-app` | `ReviewApp` composite + test job | Apps needing per-MR environments |
@@ -87,6 +88,8 @@ NodePipeline({
87
88
 
88
89
  Or generate a lockfile: `npm install && git add package-lock.json`.
89
90
 
91
+ For Bun projects, use `BunPipeline` instead — it auto-configures `bun install --frozen-lockfile` and Bun's cache directory (`.bun/install/cache`). You can also pass `packageManager: "bun"` directly to `NodePipeline` for more control.
92
+
90
93
  ### Step-by-step: push to GitLab
91
94
 
92
95
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-gitlab",
3
- "version": "0.1.0",
3
+ "version": "0.1.8",
4
4
  "description": "GitLab CI lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -36,14 +36,14 @@
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
  "devDependencies": {
46
- "@intentius/chant": "0.1.0",
46
+ "@intentius/chant": "*",
47
47
  "typescript": "^5.9.3"
48
48
  },
49
49
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
- // Bun Snapshot v1, https://bun.sh/docs/test/snapshots
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`generated lexicon-gitlab.json entries match snapshot 1`] = `
3
+ exports[`generated lexicon-gitlab.json > entries match snapshot 1`] = `
4
4
  {
5
5
  "constraints": {
6
6
  "coverage": {
@@ -14,7 +14,7 @@ exports[`generated lexicon-gitlab.json entries match snapshot 1`] = `
14
14
  }
15
15
  `;
16
16
 
17
- exports[`generated lexicon-gitlab.json entries match snapshot 2`] = `
17
+ exports[`generated lexicon-gitlab.json > entries match snapshot 2`] = `
18
18
  {
19
19
  "constraints": {
20
20
  "access": {
@@ -46,7 +46,7 @@ exports[`generated lexicon-gitlab.json entries match snapshot 2`] = `
46
46
  }
47
47
  `;
48
48
 
49
- exports[`generated lexicon-gitlab.json entries match snapshot 3`] = `
49
+ exports[`generated lexicon-gitlab.json > entries match snapshot 3`] = `
50
50
  {
51
51
  "constraints": {
52
52
  "policy": {
@@ -74,7 +74,7 @@ exports[`generated lexicon-gitlab.json entries match snapshot 3`] = `
74
74
  }
75
75
  `;
76
76
 
77
- exports[`generated lexicon-gitlab.json entries match snapshot 4`] = `
77
+ exports[`generated lexicon-gitlab.json > entries match snapshot 4`] = `
78
78
  {
79
79
  "constraints": {
80
80
  "name": {
@@ -105,7 +105,11 @@ export async function generateDocs(opts?: { verbose?: boolean }): Promise<void>
105
105
  slug: "pipeline-concepts",
106
106
  title: "Pipeline Concepts",
107
107
  description: "Jobs, stages, artifacts, caching, images, rules, environments, and triggers in the GitLab CI/CD lexicon",
108
- content: `Every exported \`Job\` declaration becomes a job entry in the generated \`.gitlab-ci.yml\`. The serializer handles the translation automatically:
108
+ content: `import Diagram from '../../components/Diagram.astro';
109
+
110
+ Every exported \`Job\` declaration becomes a job entry in the generated \`.gitlab-ci.yml\`. The serializer handles the translation automatically:
111
+
112
+ <Diagram name="pipeline-hierarchy" alt="GitLab Pipeline with stages (build, test, deploy) each containing jobs, with stage dependencies flowing left to right" caption="GitLab CI pipeline hierarchy" />
109
113
 
110
114
  - Property names use spec-native snake_case (\`expire_in\`, \`allow_failure\`)
111
115
  - Converts export names to kebab-case job keys (\`buildApp\` → \`build-app\`)
@@ -469,10 +473,10 @@ export default {
469
473
 
470
474
  \`\`\`bash
471
475
  cd examples/getting-started
472
- bun install
476
+ npm install
473
477
  chant build # produces .gitlab-ci.yml
474
478
  chant lint # runs lint rules
475
- bun test # runs the example's tests
479
+ npx vitest run # run the tests
476
480
  \`\`\`
477
481
 
478
482
  ## Getting Started
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { fetchCISchema, fetchSchemas, getCachePath, GITLAB_SCHEMA_VERSION } from "./fetch";
3
3
 
4
4
  describe("fetch", () => {
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  /**
3
3
  * CLI entry point for GitLab CI lexicon generation.
4
4
  */
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { generate, writeGeneratedFiles } from "./generate";
3
3
  import { loadSchemaFixtureMap } from "../testdata/load-fixtures";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { generate } from "./generate";
3
3
  import { loadSchemaFixtureMap } from "../testdata/load-fixtures";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { gitlabShortName, type GitLabParseResult } from "./parse";
3
3
  import { NamingStrategy } from "./naming";
4
4
 
@@ -3,9 +3,8 @@
3
3
  * with GitLab-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);
7
+ import { gitlabPlugin } from "../plugin";
9
8
  import { join, dirname } from "path";
10
9
  import { fileURLToPath } from "url";
11
10
  import type { IntrinsicDef } from "@intentius/chant/lexicon";
@@ -53,9 +52,7 @@ export async function packageLexicon(opts: PackageOptions = {}): Promise<Package
53
52
 
54
53
  srcDir: pkgDir,
55
54
 
56
- collectSkills: () => {
57
- const { gitlabPlugin } = require("../plugin");
58
- const skillDefs = gitlabPlugin.skills?.() ?? [];
55
+ collectSkills: () => { const skillDefs = gitlabPlugin.skills?.() ?? [];
59
56
  return collectSkills(skillDefs);
60
57
  },
61
58
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { parseCISchema, gitlabShortName, gitlabServiceName } from "./parse";
3
3
  import { loadSchemaFixture } from "../testdata/load-fixtures";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { applyPatches, schemaPatches } from "./patches";
3
3
 
4
4
  describe("applyPatches", () => {
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { existsSync, readFileSync } 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 { typecheckDTS } from "./typecheck";
3
3
 
4
4
  describe("typecheckDTS", () => {
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { expandComposite, isCompositeInstance } from "@intentius/chant";
3
3
  import { DockerBuild } from "./docker-build";
4
4
  import { NodePipeline, BunPipeline, PnpmPipeline } from "./node-pipeline";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { existsSync, readFileSync } 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 { GitLabGenerator } from "./generator";
3
3
  import type { TemplateIR } from "@intentius/chant/import/parser";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { GitLabParser } from "./parser";
3
3
 
4
4
  const parser = new GitLabParser();
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { readFileSync, readdirSync } 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 { reference, ReferenceIntrinsic } from "./intrinsics";
3
3
  import { INTRINSIC_MARKER } from "@intentius/chant/intrinsic";
4
4
 
@@ -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 { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
4
4
  import { wgl010 } from "./wgl010";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl012, checkDeprecatedProperties } from "./wgl012";
@@ -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 { wgl013, checkInvalidNeeds } from "./wgl013";
4
4
 
@@ -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 { wgl014, checkInvalidExtends } from "./wgl014";
4
4
 
@@ -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 { wgl015, checkCircularNeeds } from "./wgl015";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { wgl016, checkSecretsInVariables } from "./wgl016";
3
3
 
4
4
  describe("WGL016: Secrets in Variables", () => {
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { wgl017, checkInsecureRegistry } from "./wgl017";
3
3
 
4
4
  describe("WGL017: Insecure Registry", () => {
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl018 } from "./wgl018";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl019 } from "./wgl019";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { wgl020, checkDuplicateJobNames } from "./wgl020";
3
3
 
4
4
  describe("WGL020: Duplicate Job Names", () => {
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { wgl021, checkUnusedVariables } from "./wgl021";
3
3
 
4
4
  describe("WGL021: Unused Variables", () => {
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl022 } from "./wgl022";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl023 } from "./wgl023";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl024 } from "./wgl024";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl025 } from "./wgl025";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl026 } from "./wgl026";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
3
3
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
4
4
  import { wgl027 } from "./wgl027";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { wgl028, checkRedundantNeeds } from "./wgl028";
3
3
 
4
4
  describe("WGL028: Redundant Needs", () => {
@@ -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 { deprecatedOnlyExceptRule } from "./deprecated-only-except";
@@ -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,6 +1,6 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  /**
3
- * Thin entry point for `bun run bundle` in lexicon-gitlab.
3
+ * Thin entry point for `npm run bundle` in lexicon-gitlab.
4
4
  * Generates src/generated/ files and writes dist/ bundle.
5
5
  */
6
6
  import { generate, writeGeneratedFiles } from "./codegen/generate";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { gitlabPlugin } from "./plugin";
3
3
  import { isLexiconPlugin } from "@intentius/chant/lexicon";
4
4
 
@@ -215,7 +215,7 @@ describe("gitlabPlugin", () => {
215
215
  test("returns MCP tools", () => {
216
216
  const tools = gitlabPlugin.mcpTools!();
217
217
  expect(tools).toHaveLength(1);
218
- expect(tools[0].name).toBe("diff");
218
+ expect(tools[0].name).toBe("gitlab:diff");
219
219
  expect(typeof tools[0].handler).toBe("function");
220
220
  });
221
221
 
@@ -223,13 +223,13 @@ describe("gitlabPlugin", () => {
223
223
  const resources = gitlabPlugin.mcpResources!();
224
224
  expect(resources.length).toBeGreaterThan(0);
225
225
  const uris = resources.map((r) => r.uri);
226
- expect(uris).toContain("resource-catalog");
226
+ expect(uris).toContain("gitlab:resource-catalog");
227
227
  expect(uris).toContain("examples/basic-pipeline");
228
228
  });
229
229
 
230
230
  test("MCP resource-catalog handler returns JSON", async () => {
231
231
  const resources = gitlabPlugin.mcpResources!();
232
- const catalog = resources.find((r) => r.uri === "resource-catalog")!;
232
+ const catalog = resources.find((r) => r.uri === "gitlab:resource-catalog")!;
233
233
  const result = await catalog.handler();
234
234
  const parsed = JSON.parse(result);
235
235
  expect(Array.isArray(parsed)).toBe(true);
package/src/plugin.ts CHANGED
@@ -5,25 +5,27 @@
5
5
  * for GitLab CI/CD pipelines.
6
6
  */
7
7
 
8
- import { createRequire } from "module";
9
8
  import type { LexiconPlugin, IntrinsicDef, InitTemplateSet } from "@intentius/chant/lexicon";
10
- const require = createRequire(import.meta.url);
11
9
  import type { LintRule } from "@intentius/chant/lint/rule";
12
10
  import { discoverPostSynthChecks } from "@intentius/chant/lint/discover";
13
11
  import { createSkillsLoader, createDiffTool, createCatalogResource } from "@intentius/chant/lexicon-plugin-helpers";
14
12
  import { join, dirname } from "path";
15
13
  import { fileURLToPath } from "url";
16
14
  import { gitlabSerializer } from "./serializer";
15
+ import { deprecatedOnlyExceptRule } from "./lint/rules/deprecated-only-except";
16
+ import { missingScriptRule } from "./lint/rules/missing-script";
17
+ import { missingStageRule } from "./lint/rules/missing-stage";
18
+ import { artifactNoExpiryRule } from "./lint/rules/artifact-no-expiry";
19
+ import { gitlabCompletions } from "./lsp/completions";
20
+ import { gitlabHover } from "./lsp/hover";
21
+ import { GitLabParser } from "./import/parser";
22
+ import { GitLabGenerator } from "./import/generator";
17
23
 
18
24
  export const gitlabPlugin: LexiconPlugin = {
19
25
  name: "gitlab",
20
26
  serializer: gitlabSerializer,
21
27
 
22
28
  lintRules(): LintRule[] {
23
- const { deprecatedOnlyExceptRule } = require("./lint/rules/deprecated-only-except");
24
- const { missingScriptRule } = require("./lint/rules/missing-script");
25
- const { missingStageRule } = require("./lint/rules/missing-stage");
26
- const { artifactNoExpiryRule } = require("./lint/rules/artifact-no-expiry");
27
29
  return [deprecatedOnlyExceptRule, missingScriptRule, missingStageRule, artifactNoExpiryRule];
28
30
  },
29
31
 
@@ -187,22 +189,18 @@ export const test = new Job({
187
189
  },
188
190
 
189
191
  completionProvider(ctx: import("@intentius/chant/lsp/types").CompletionContext) {
190
- const { gitlabCompletions } = require("./lsp/completions");
191
192
  return gitlabCompletions(ctx);
192
193
  },
193
194
 
194
195
  hoverProvider(ctx: import("@intentius/chant/lsp/types").HoverContext) {
195
- const { gitlabHover } = require("./lsp/hover");
196
196
  return gitlabHover(ctx);
197
197
  },
198
198
 
199
199
  templateParser() {
200
- const { GitLabParser } = require("./import/parser");
201
200
  return new GitLabParser();
202
201
  },
203
202
 
204
203
  templateGenerator() {
205
- const { GitLabGenerator } = require("./import/generator");
206
204
  return new GitLabGenerator();
207
205
  },
208
206
 
@@ -254,12 +252,12 @@ export const test = new Job({
254
252
  },
255
253
 
256
254
  mcpTools() {
257
- return [createDiffTool(gitlabSerializer, "Compare current build output against previous output for GitLab CI")];
255
+ return [createDiffTool(gitlabSerializer, "Compare current build output against previous output for GitLab CI", "gitlab")];
258
256
  },
259
257
 
260
258
  mcpResources() {
261
259
  return [
262
- createCatalogResource(import.meta.url, "GitLab CI Entity Catalog", "JSON list of all supported GitLab CI entity types", "lexicon-gitlab.json"),
260
+ createCatalogResource(import.meta.url, "GitLab CI Entity Catalog", "JSON list of all supported GitLab CI entity types", "lexicon-gitlab.json", "gitlab"),
263
261
  {
264
262
  uri: "examples/basic-pipeline",
265
263
  name: "Basic Pipeline Example",
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { gitlabSerializer } from "./serializer";
3
3
  import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
4
4
  import { createProperty, createResource } from "@intentius/chant/runtime";
@@ -35,6 +35,7 @@ This creates `src/` with chant pipeline definitions. It does NOT create applicat
35
35
  |----------|-------------------|----------|
36
36
  | *(default)* | `config.ts` + `pipeline.ts` with build/test jobs | Custom pipelines from scratch |
37
37
  | `node-pipeline` | `NodePipeline` composite with npm install/build/test | Node.js apps |
38
+ | `bun-pipeline` | `BunPipeline` composite — Bun runtime with frozen lockfile | Bun apps |
38
39
  | `python-pipeline` | `PythonPipeline` composite with venv/pytest | Python apps |
39
40
  | `docker-build` | `DockerBuild` composite + test job | Containerized apps |
40
41
  | `review-app` | `ReviewApp` composite + test job | Apps needing per-MR environments |
@@ -87,6 +88,8 @@ NodePipeline({
87
88
 
88
89
  Or generate a lockfile: `npm install && git add package-lock.json`.
89
90
 
91
+ For Bun projects, use `BunPipeline` instead — it auto-configures `bun install --frozen-lockfile` and Bun's cache directory (`.bun/install/cache`). You can also pass `packageManager: "bun"` directly to `NodePipeline` for more control.
92
+
90
93
  ### Step-by-step: push to GitLab
91
94
 
92
95
  ```bash
@@ -1,7 +1,7 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  /**
3
3
  * Script to create a minimal CI schema fixture for tests.
4
- * Run once: bun run src/testdata/create-fixture.ts
4
+ * Run once: npx tsx src/testdata/create-fixture.ts
5
5
  */
6
6
 
7
7
  import { readFileSync, writeFileSync } from "fs";
@@ -39,7 +39,7 @@ const minimal = {
39
39
  required: schema.required || [],
40
40
  };
41
41
 
42
- const outPath = join(import.meta.dir, "ci-schema-fixture.json");
42
+ const outPath = join(import.meta.dirname, "ci-schema-fixture.json");
43
43
  writeFileSync(outPath, JSON.stringify(minimal, null, 2));
44
44
  console.log(`Fixture written to ${outPath}`);
45
45
  console.log(`Definitions: ${Object.keys(defs).length}`);
@@ -9,7 +9,7 @@ import { join } from "path";
9
9
  * Load the minimal CI schema fixture for offline testing.
10
10
  */
11
11
  export function loadSchemaFixture(): Buffer {
12
- const fixturePath = join(import.meta.dir, "ci-schema-fixture.json");
12
+ const fixturePath = join(import.meta.dirname, "ci-schema-fixture.json");
13
13
  return Buffer.from(readFileSync(fixturePath));
14
14
  }
15
15
 
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  /**
3
- * Thin entry point for `bun run validate` in lexicon-gitlab.
3
+ * Thin entry point for `npm run validate` in lexicon-gitlab.
4
4
  */
5
5
  import { validate } from "./validate";
6
6
 
@@ -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 { CI } from "./variables";
3
3
 
4
4
  describe("CI variables", () => {