timonel 2.9.0 → 2.9.1

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [2.9.1](https://github.com/KenkoGeek/timonel/compare/v2.9.0...v2.9.1) (2025-09-19)
2
+
3
+ ### Bug Fixes
4
+
5
+ - **deps:** merge conflict solved [skip ci] ([3422464](https://github.com/KenkoGeek/timonel/commit/3422464ddee4a1408019ba4617b6f8e6f6c8fd12))
6
+ - **deps:** upgrade timonel version [skip ci] ([63901ef](https://github.com/KenkoGeek/timonel/commit/63901ef4277a1ebf702fc55337ed1eb7f6b226ea))
7
+
1
8
  # [2.9.0](https://github.com/KenkoGeek/timonel/compare/v2.8.3...v2.9.0) (2025-09-17)
2
9
 
3
10
  ### Features
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # Timonel
2
+
3
+ [![License: MIT][license-badge]][license-url]
4
+ [![npm version][npm-badge]][npm-url]
5
+ [![Security][security-badge]][security-url]
6
+ [![CodeQL][codeql-badge]][codeql-url]
7
+ [![CI][ci-badge]][ci-url]
8
+ [![pnpm][pnpm-badge]][pnpm-url]
9
+ [![Node.js][node-badge]][node-url]
10
+ [![TypeScript][ts-badge]][ts-url]
11
+ [![Maintained by KenkoGeek][maintained-badge]][maintained-url]
12
+
13
+ Timonel (Spanish for "helmsman") is a TypeScript library to programmatically generate Helm charts
14
+ using cdk8s. Define Kubernetes resources with classes and synthesize a full Helm chart with
15
+ `Chart.yaml`, `values.yaml`, per‑environment values files, and `templates/`.
16
+
17
+ ## ✨ Key Features
18
+
19
+ - **Type-safe API** with strict TypeScript and cdk8s constructs.
20
+ - **Flexible resource creation** with built-in methods and `addManifest()` for custom resources.
21
+ - **Multi-environment support** with automatic values files generation.
22
+ - **Umbrella Charts** for managing multiple subcharts as a single unit.
23
+ - **AWS integrations**:
24
+ - **AWS**: EBS/EFS StorageClass, ALB Ingress, IRSA ServiceAccount.
25
+ - **Security-first approach** with NetworkPolicies and best practices.
26
+ - **Minimal CLI** (`tl`) for scaffolding and chart generation.
27
+
28
+ ## 🚀 Quick Start
29
+
30
+ ```bash
31
+ # Install Timonel globally
32
+ npm install -g timonel
33
+
34
+ # Create your first chart
35
+ tl init my-app
36
+
37
+ # Generate Helm chart
38
+ tl synth charts/my-app charts/my-app-dist
39
+
40
+ # Use with Helm
41
+ helm install my-app charts/my-app-dist
42
+ ```
43
+
44
+ ## 📚 Documentation
45
+
46
+ ## 🔧 Troubleshooting
47
+
48
+ ### CDK8s Module Not Found Error
49
+
50
+ If you get `Error: Cannot find module 'cdk8s'` when running `tl umbrella synth`:
51
+
52
+ **Problem**: Timonel is installed globally, but your project needs CDK8s dependencies locally.
53
+
54
+ **Solution**: Create a `package.json` in your project directory:
55
+
56
+ ```json
57
+ {
58
+ "name": "my-timonel-project",
59
+ "version": "1.0.0",
60
+ "type": "module",
61
+ "dependencies": {
62
+ "cdk8s": "^2.70.11",
63
+ "cdk8s-plus-33": "^2.3.5",
64
+ "constructs": "^10.4.2",
65
+ "timonel": "^2.9.0"
66
+ },
67
+ "devDependencies": {
68
+ "@types/node": "^24.3.0",
69
+ "typescript": "^5.9.2"
70
+ }
71
+ }
72
+ ```
73
+
74
+ Then run:
75
+
76
+ ```bash
77
+ npm install
78
+ tl umbrella synth # Now it works!
79
+ ```
80
+
81
+ ## 🤝 Contributing
82
+
83
+ See our [Contributing Guide](https://github.com/KenkoGeek/timonel/wiki/Contributing) for development
84
+ setup and guidelines.
85
+
86
+ ## 📄 License
87
+
88
+ MIT
89
+
90
+ <!-- Badges -->
91
+
92
+ [license-badge]: https://img.shields.io/badge/License-MIT-yellow.svg
93
+ [license-url]: https://opensource.org/licenses/MIT
94
+ [npm-badge]: https://img.shields.io/npm/v/timonel.svg
95
+ [npm-url]: https://www.npmjs.com/package/timonel
96
+ [security-badge]: https://img.shields.io/badge/Security-Policy-2ea44f?logo=security&logoColor=fff
97
+ [security-url]: SECURITY.md
98
+ [pnpm-badge]: https://img.shields.io/badge/pm-pnpm-ffd95a?logo=pnpm&logoColor=fff&labelColor=24292e
99
+ [pnpm-url]: https://pnpm.io/
100
+ [node-badge]: https://img.shields.io/badge/node-%3E%3D20-339933?logo=node.js&logoColor=fff
101
+ [node-url]: https://nodejs.org/
102
+ [ts-badge]: https://img.shields.io/badge/TypeScript-5.x-3178C6?logo=typescript&logoColor=fff
103
+ [ts-url]: https://www.typescriptlang.org/
104
+ [maintained-badge]: https://img.shields.io/badge/maintained%20by-KenkoGeek-6C78AF?style=flat
105
+ [maintained-url]: https://github.com/kenkogeek/
106
+ [ci-badge]: https://github.com/KenkoGeek/timonel/actions/workflows/test.yaml/badge.svg?branch=main
107
+ [ci-url]: https://github.com/KenkoGeek/timonel/actions/workflows/teast.yaml
108
+ [codeql-badge]: https://github.com/KenkoGeek/timonel/actions/workflows/codeql.yaml/badge.svg
109
+ [codeql-url]: https://github.com/KenkoGeek/timonel/actions/workflows/codeql.yaml
package/dist/cli.js CHANGED
@@ -37,7 +37,6 @@ function usageAndExit(msg) {
37
37
  ' --silent Suppress output (useful for CI)',
38
38
  ' --env <environment> Use environment-specific values',
39
39
  ' --set <key=value> Override values (can be used multiple times)',
40
- ' --version, -v Show version information',
41
40
  ' --help, -h Show this help message',
42
41
  '',
43
42
  'Examples:',
@@ -5,21 +5,17 @@ import { SecurityUtils } from './security.js';
5
5
  export class HelmChartWriter {
6
6
  static write(opts) {
7
7
  const { outDir, meta, defaultValues = {}, envValues = {}, assets, helpersTpl, notesTpl, valuesSchema, } = opts;
8
+ console.log(`📝 Writing Helm chart: ${meta.name} v${meta.version} to ${outDir}`);
8
9
  const validatedOutDir = SecurityUtils.validatePath(outDir, process.cwd());
9
- console.log('📝 Validated outDir:', validatedOutDir);
10
10
  this.createDirectories(validatedOutDir);
11
- console.log('📝 Directories created');
12
11
  this.writeChartYaml(validatedOutDir, meta);
13
- console.log('📝 Chart.yaml written');
14
12
  this.writeValuesFiles(validatedOutDir, defaultValues, envValues);
15
- console.log('📝 Values files written');
16
13
  this.writeAssets(validatedOutDir, assets);
17
- console.log('📝 Assets written');
18
14
  this.writeHelpers(validatedOutDir, helpersTpl);
19
15
  this.writeNotes(validatedOutDir, notesTpl);
20
16
  this.writeSchema(validatedOutDir, valuesSchema);
21
17
  this.writeHelmIgnore(validatedOutDir);
22
- console.log('📝 HelmChartWriter.write completed');
18
+ console.log(`✅ Helm chart written successfully to ${validatedOutDir}`);
23
19
  }
24
20
  static createDirectories(outDir) {
25
21
  fs.mkdirSync(path.join(outDir, 'templates'), { recursive: true });
@@ -112,25 +108,24 @@ function splitDocs(yamlStr) {
112
108
  .filter((p) => p.length);
113
109
  }
114
110
  function writeAssets(outDir, assets) {
115
- console.log('🔍 writeAssets called with', assets.length, 'assets');
116
111
  for (const asset of assets) {
117
112
  const sanitizedId = asset.id.replace(/[^a-zA-Z0-9-_]/g, '');
118
113
  if (sanitizedId !== asset.id) {
114
+ console.error(`❌ Invalid asset ID detected: ${SecurityUtils.sanitizeLogMessage(asset.id)}`);
119
115
  throw new Error(`Invalid asset ID: ${SecurityUtils.sanitizeLogMessage(asset.id)}`);
120
116
  }
121
117
  const targetDir = getTargetDirectory(asset.target);
122
- console.log(`🔍 Processing asset: ${asset.id} -> ${sanitizedId}, singleFile: ${asset.singleFile}, target: ${asset.target}`);
123
- if (asset.id === 'ingress') {
124
- console.log('🔍 Ingress asset YAML preview:', asset.yaml.substring(0, 200));
125
- if (asset.yaml.includes('number:')) {
126
- console.log('🔍 Ingress contains number field:', asset.yaml.split('\n').filter((line) => line.includes('number:')));
118
+ try {
119
+ if (asset.singleFile) {
120
+ writeSingleAssetFile(outDir, targetDir, sanitizedId, asset.yaml);
121
+ }
122
+ else {
123
+ writeMultipleAssetFiles(outDir, targetDir, sanitizedId, asset.yaml);
127
124
  }
128
125
  }
129
- if (asset.singleFile) {
130
- writeSingleAssetFile(outDir, targetDir, sanitizedId, asset.yaml);
131
- }
132
- else {
133
- writeMultipleAssetFiles(outDir, targetDir, sanitizedId, asset.yaml);
126
+ catch (error) {
127
+ console.error(`❌ Failed to write asset ${asset.id}:`, error);
128
+ throw error;
134
129
  }
135
130
  }
136
131
  }
@@ -1,7 +1,7 @@
1
1
  import { ApiObject, App, Chart, Testing } from 'cdk8s';
2
2
  import Handlebars from 'handlebars';
3
3
  import YAML from 'yaml';
4
- import { helm, include } from './helm.js';
4
+ import { include } from './helm.js';
5
5
  import { HelmChartWriter } from './helmChartWriter.js';
6
6
  import { AWSResources } from './resources/cloud/aws/awsResources.js';
7
7
  import { KarpenterResources } from './resources/cloud/aws/karpenterResources.js';
@@ -9,6 +9,7 @@ import { generateHelpersTemplate } from './utils/helmHelpers.js';
9
9
  export class Rutter {
10
10
  constructor(props) {
11
11
  this.assets = [];
12
+ console.log(`🚀 Initializing Rutter chart: ${props.meta.name} v${props.meta.version}`);
12
13
  this.defaultValues = props.defaultValues ?? {};
13
14
  this.envValues = props.envValues ?? {};
14
15
  this.meta = props.meta;
@@ -140,33 +141,26 @@ export class Rutter {
140
141
  });
141
142
  }
142
143
  validateManifestStructure(manifest) {
143
- if (!manifest['apiVersion'] || typeof manifest['apiVersion'] !== 'string') {
144
- throw new Error('Kubernetes manifest must have a valid apiVersion');
144
+ if (!manifest.apiVersion) {
145
+ console.error(' Manifest validation failed: Missing apiVersion');
146
+ throw new Error('Manifest must have an apiVersion');
145
147
  }
146
- if (!manifest['kind'] || typeof manifest['kind'] !== 'string') {
147
- throw new Error('Kubernetes manifest must have a valid kind');
148
+ if (!manifest.kind) {
149
+ console.error(' Manifest validation failed: Missing kind');
150
+ throw new Error('Manifest must have a kind');
148
151
  }
149
- if (!manifest['metadata'] ||
150
- typeof manifest['metadata'] !== 'object' ||
151
- manifest['metadata'] === null) {
152
- throw new Error('Kubernetes manifest must have valid metadata');
152
+ if (!manifest.metadata) {
153
+ console.error(' Manifest validation failed: Missing metadata');
154
+ throw new Error('Manifest must have metadata');
153
155
  }
154
- const metadata = manifest['metadata'];
155
- if (!metadata['name'] || typeof metadata['name'] !== 'string') {
156
- throw new Error('Kubernetes manifest metadata must have a valid name');
156
+ const metadata = manifest.metadata;
157
+ if (!metadata.name) {
158
+ console.error(' Manifest validation failed: Missing metadata.name');
159
+ throw new Error('Manifest metadata must have a name');
157
160
  }
158
- const kind = manifest['kind'];
159
- if (kind === 'CustomResourceDefinition') {
160
- if (!manifest['spec'] || typeof manifest['spec'] !== 'object' || manifest['spec'] === null) {
161
- throw new Error('CustomResourceDefinition must have a valid spec');
162
- }
163
- const spec = manifest['spec'];
164
- if (!spec['group'] || typeof spec['group'] !== 'string') {
165
- throw new Error('CustomResourceDefinition spec must have a valid group');
166
- }
167
- if (!Array.isArray(spec['versions']) || spec['versions'].length === 0) {
168
- throw new Error('CustomResourceDefinition must have at least one version in spec.versions');
169
- }
161
+ if (typeof metadata.name !== 'string') {
162
+ console.error('❌ Manifest validation failed: metadata.name must be a string');
163
+ throw new Error('Manifest metadata.name must be a string');
170
164
  }
171
165
  }
172
166
  getMeta() {
@@ -182,7 +176,7 @@ export class Rutter {
182
176
  return [...this.assets];
183
177
  }
184
178
  toSynthArray() {
185
- console.log('🔍 toSynthArray called');
179
+ console.log(`📦 Synthesizing chart assets for: ${this.meta.name}`);
186
180
  const apiObjectIds = [];
187
181
  for (const child of this.chart.node.children) {
188
182
  if (child instanceof ApiObject && !child.node.id.endsWith('-placeholder')) {
@@ -198,6 +192,7 @@ export class Rutter {
198
192
  }
199
193
  return true;
200
194
  });
195
+ console.log(`📋 Found ${manifestObjs.length} manifest objects to process`);
201
196
  const enriched = manifestObjs.map((obj) => {
202
197
  if (obj && typeof obj === 'object') {
203
198
  const o = obj;
@@ -205,12 +200,12 @@ export class Rutter {
205
200
  o.metadata.labels = o.metadata.labels ?? {};
206
201
  const labels = o.metadata.labels;
207
202
  const defaults = {
208
- 'helm.sh/chart': '{{ .Chart.Name }}-{{ .Chart.Version }}',
209
- 'app.kubernetes.io/name': include(Rutter.HELPER_NAME),
210
- 'app.kubernetes.io/instance': helm.releaseName,
211
- 'app.kubernetes.io/version': helm.chartVersion,
203
+ 'helm.sh/chart': `{{ .Chart.Name }}-{{ .Chart.Version }}`,
204
+ 'app.kubernetes.io/name': `{{ ${include} "${Rutter.HELPER_NAME}" . }}`,
205
+ 'app.kubernetes.io/instance': '{{ .Release.Name }}',
206
+ 'app.kubernetes.io/version': '{{ .Chart.Version }}',
212
207
  'app.kubernetes.io/managed-by': '{{ .Release.Service }}',
213
- 'app.kubernetes.io/part-of': helm.chartName,
208
+ 'app.kubernetes.io/part-of': '{{ .Chart.Name }}',
214
209
  };
215
210
  for (const [key, value] of Object.entries(defaults)) {
216
211
  if (!(key in labels)) {
@@ -221,7 +216,6 @@ export class Rutter {
221
216
  return obj;
222
217
  });
223
218
  const synthAssets = [];
224
- console.log('🔍 singleManifestFile:', this.props.singleManifestFile);
225
219
  if (this.props.singleManifestFile) {
226
220
  const combinedYaml = enriched
227
221
  .map((obj) => this.processHelmTemplates(YAML.stringify(obj).trim()))
@@ -234,7 +228,6 @@ export class Rutter {
234
228
  enriched.forEach((obj, index) => {
235
229
  const apiObjectId = apiObjectIds[index];
236
230
  const manifestId = apiObjectId || `manifest-${index + 1}`;
237
- console.log(`🔍 Processing asset ${manifestId} (index ${index})`);
238
231
  const yaml = this.processHelmTemplates(YAML.stringify(obj).trim());
239
232
  if (yaml) {
240
233
  synthAssets.push({ id: manifestId, yaml });
@@ -247,15 +240,8 @@ export class Rutter {
247
240
  return synthAssets;
248
241
  }
249
242
  processHelmTemplates(yaml) {
250
- console.log('🔍 processHelmTemplates called with YAML length:', yaml.length);
251
- if (yaml.includes('{{ .Values.port }}')) {
252
- console.log('🎯 Found YAML with port template:');
253
- const portIndex = yaml.indexOf('{{ .Values.port }}');
254
- console.log(yaml.substring(Math.max(0, portIndex - 50), portIndex + 100));
255
- }
256
243
  let processed = this.fixCharacterMappingIssues(yaml);
257
244
  processed = this.applyHelmTemplateReplacements(processed);
258
- console.log('✅ processHelmTemplates completed');
259
245
  return processed;
260
246
  }
261
247
  fixCharacterMappingIssues(yaml) {
@@ -317,38 +303,11 @@ export class Rutter {
317
303
  return { nextIndex: j };
318
304
  }
319
305
  applyHelmTemplateReplacements(processed) {
320
- processed = this.fixIncludeStatements(processed);
321
- processed = this.fixFunctionCalls(processed);
322
- processed = this.fixChartReferences(processed);
323
- processed = this.removeHelmExpressionQuotes(processed);
324
- if (processed.includes('number:')) {
325
- console.log('DEBUG: Before fixConditionalBlocks:', processed.split('\n').filter((line) => line.includes('number:')));
326
- }
327
306
  processed = this.fixConditionalBlocks(processed);
328
- if (processed.includes('number:')) {
329
- console.log('DEBUG: After fixConditionalBlocks:', processed.split('\n').filter((line) => line.includes('number:')));
330
- }
331
- if (processed.includes('number:')) {
332
- console.log('DEBUG: Before fixPipeExpressions:', processed.split('\n').filter((line) => line.includes('number:')));
333
- }
334
307
  processed = this.fixPipeExpressions(processed);
335
- if (processed.includes('number:')) {
336
- console.log('DEBUG: After fixPipeExpressions:', processed.split('\n').filter((line) => line.includes('number:')));
337
- }
338
- if (processed.includes('number:')) {
339
- console.log('DEBUG: Before fixNestedQuotes:', processed.split('\n').filter((line) => line.includes('number:')));
340
- }
341
308
  processed = this.fixNestedQuotes(processed);
342
- if (processed.includes('number:')) {
343
- console.log('DEBUG: After fixNestedQuotes:', processed.split('\n').filter((line) => line.includes('number:')));
344
- }
345
- if (processed.includes('number:')) {
346
- console.log('DEBUG: Before cleanupArtifacts:', processed.split('\n').filter((line) => line.includes('number:')));
347
- }
348
309
  processed = this.cleanupArtifacts(processed);
349
- if (processed.includes('number:')) {
350
- console.log('DEBUG: After cleanupArtifacts:', processed.split('\n').filter((line) => line.includes('number:')));
351
- }
310
+ processed = this.removeHelmExpressionQuotes(processed);
352
311
  return processed;
353
312
  }
354
313
  fixIncludeStatements(processed) {
@@ -364,10 +323,6 @@ export class Rutter {
364
323
  }
365
324
  removeHelmExpressionQuotes(processed) {
366
325
  const HELM_EXPRESSION_REPLACEMENT = '$1$2: {{$3}}';
367
- console.log('🔧 removeHelmExpressionQuotes called');
368
- if (processed.includes('number:')) {
369
- console.log('DEBUG: removeHelmExpressionQuotes input contains number:', processed.split('\n').filter((line) => line.includes('number:')));
370
- }
371
326
  processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\|\s*(?:int|float|bool|number)[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
372
327
  processed = processed.replace(/^(\s*)(port):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
373
328
  processed = processed.replace(/^(\s*)(port\.number):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
@@ -375,23 +330,7 @@ export class Rutter {
375
330
  processed = processed.replace(/^(\s*)(backend\.service\.port\.number):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
376
331
  processed = processed.replace(/^(\s*)(spec\.port):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
377
332
  processed = processed.replace(/^(\s*)([^:\s]*\.number):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
378
- const numberMatches = processed.match(/^(\s*)(number):\s*"\{\{([^}]*)\}\}"/gm);
379
- if (numberMatches) {
380
- console.log('DEBUG: Found number pattern matches:', numberMatches);
381
- }
382
- else {
383
- const anyNumberFields = processed.match(/number:\s*"[^"]*"/gm);
384
- if (anyNumberFields) {
385
- console.log('DEBUG: Found number fields but regex did not match:', anyNumberFields);
386
- const lines = processed.split('\n');
387
- const numberLines = lines.filter((line) => line.includes('number:'));
388
- console.log('DEBUG: Number field lines:', numberLines);
389
- }
390
- }
391
333
  processed = processed.replace(/^(\s*)(number):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
392
- if (processed.includes('number:')) {
393
- console.log('DEBUG: removeHelmExpressionQuotes after number replacement:', processed.split('\n').filter((line) => line.includes('number:')));
394
- }
395
334
  processed = processed.replace(/^(\s*)(replicas):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
396
335
  processed = processed.replace(/^(\s*)(targetPort):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
397
336
  processed = processed.replace(/^(\s*)(nodePort):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
@@ -468,8 +407,7 @@ export class Rutter {
468
407
  return processed;
469
408
  }
470
409
  write(outDir) {
471
- console.log('🚀 Rutter.write called with outDir:', outDir);
472
- console.log('📊 Assets count:', this.assets.length);
410
+ console.log(`✍️ Writing Helm chart '${this.meta.name}' to: ${outDir}`);
473
411
  let helpersContent;
474
412
  if (this.props.helpersTpl) {
475
413
  if (typeof this.props.helpersTpl === 'string') {
@@ -490,7 +428,7 @@ ${helper.template}
490
428
  helpersContent = generateHelpersTemplate(this.props.cloudProvider);
491
429
  }
492
430
  const synthAssets = this.toSynthArray();
493
- console.log('📦 Generated synth assets:', synthAssets.length);
431
+ console.log(`📄 Generated ${synthAssets.length} assets for chart`);
494
432
  HelmChartWriter.write({
495
433
  outDir,
496
434
  meta: this.meta,
@@ -499,7 +437,7 @@ ${helper.template}
499
437
  assets: synthAssets,
500
438
  helpersTpl: helpersContent,
501
439
  });
502
- console.log('✅ Rutter.write completed');
440
+ console.log(`✅ Helm chart '${this.meta.name}' written successfully`);
503
441
  }
504
442
  }
505
443
  Rutter.HELPER_NAME = 'chart.name';
@@ -184,10 +184,7 @@ spec:
184
184
  return this.rutter;
185
185
  }
186
186
  writeHelmChart(outDir) {
187
- console.log('🔧 Subchart.writeHelmChart called with outDir:', outDir);
188
- console.log('🔧 Rutter instance exists:', !!this.rutter);
189
187
  this.rutter.write(outDir);
190
- console.log('🔧 Subchart.writeHelmChart completed');
191
188
  }
192
189
  }
193
190
  export function generateSubchart(props = {}, outDir = 'dist') {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "timonel",
3
3
  "type": "module",
4
- "version": "2.9.0",
4
+ "version": "2.9.1",
5
5
  "description": "Timonel: programmatic Helm chart generator using cdk8s (TypeScript)",
6
6
  "bin": {
7
7
  "timonel": "dist/cli.js",
@@ -37,13 +37,9 @@
37
37
  "deps:update": "pnpm update --latest",
38
38
  "md:lint": "markdownlint \"**/*.md\"",
39
39
  "md:fix": "markdownlint --fix \"**/*.md\"",
40
- "_comment_tests": "ALL TEST SCRIPTS DISABLED TEMPORARILY",
41
- "_test": "pnpm test:unit && pnpm test:integration",
42
- "_test:unit": "vitest run --config vitest.config.ts",
43
- "_test:integration": "vitest run --config vitest.integration.config.ts",
44
- "_test:watch": "vitest",
45
- "_test:coverage": "vitest run --coverage",
46
- "_test:basic-integration": "vitest run tests/integration/basic-chart-generation.int.spec.ts --config vitest.integration.config.ts",
40
+ "test:integration": "vitest run --config vitest.config.ts",
41
+ "test:watch": "vitest",
42
+ "test:coverage": "vitest run --coverage",
47
43
  "ci:check": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm build",
48
44
  "release": "semantic-release",
49
45
  "release:dry": "semantic-release --dry-run",
@@ -89,6 +85,7 @@
89
85
  "cdk8s-plus-33": "^2.3.5",
90
86
  "constructs": "^10.4.2",
91
87
  "handlebars": "^4.7.8",
88
+ "timonel": "^2.9.0",
92
89
  "ts-node": "^10.9.2",
93
90
  "yaml": "^2.8.1"
94
91
  },