helm-env-delta 1.5.0 โ†’ 1.6.0

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/README.md CHANGED
@@ -50,6 +50,8 @@ HelmEnvDelta (`hed`) automates environment synchronization for GitOps workflows
50
50
 
51
51
  ๐Ÿ” **Discovery Tools** - Preview files (`--list-files`), inspect config (`--show-config`), validate with warnings.
52
52
 
53
+ ๐Ÿ’ก **Smart Suggestions** - Heuristic analysis (`--suggest`) detects patterns and recommends transforms and stop rules automatically. Control sensitivity with `--suggest-threshold`.
54
+
53
55
  ๐Ÿ›ก๏ธ **Safety First** - Pre-execution summary, first-run tips, improved error messages with helpful examples.
54
56
 
55
57
  โšก **High Performance** - 45-60% faster than alternatives with intelligent caching and parallel processing.
@@ -107,6 +109,17 @@ helm-env-delta --config config.yaml
107
109
  helm-env-delta --config config.yaml --diff-html
108
110
  ```
109
111
 
112
+ ### 5๏ธโƒฃ Get Smart Suggestions (Optional)
113
+
114
+ ```bash
115
+ helm-env-delta --config config.yaml --suggest
116
+
117
+ # Control suggestion sensitivity (0-1, default: 0.3)
118
+ helm-env-delta --config config.yaml --suggest --suggest-threshold 0.7
119
+ ```
120
+
121
+ Analyzes differences and suggests transforms and stop rules automatically with configurable confidence filtering.
122
+
110
123
  **Done!** All files synced, production values preserved, changes validated.
111
124
 
112
125
  ---
@@ -241,6 +254,92 @@ helm-env-delta --config example/5-external-files/config.yaml --dry-run --diff
241
254
 
242
255
  ---
243
256
 
257
+ ## ๐Ÿ’ก Smart Configuration Suggestions (Heuristic)
258
+
259
+ The `--suggest` flag uses heuristic analysis to examine differences between environments and automatically recommend configuration updates. This intelligent pattern detection helps bootstrap your config by discovering repeated changes and potential safety rules.
260
+
261
+ ### How It Works
262
+
263
+ ```bash
264
+ helm-env-delta --config config.yaml --suggest
265
+
266
+ # Control suggestion sensitivity (higher threshold = fewer, higher-confidence suggestions)
267
+ helm-env-delta --config config.yaml --suggest --suggest-threshold 0.7
268
+ ```
269
+
270
+ **How heuristic analysis works:**
271
+
272
+ - ๐Ÿ” Intelligently detects repeated value changes across files
273
+ - ๐ŸŽฏ Suggests transform patterns (regex find/replace) based on semantic patterns
274
+ - ๐Ÿ›ก๏ธ Recommends stop rules for safety validation using pattern recognition
275
+ - ๐Ÿ“Š Provides confidence scores and occurrence counts for each suggestion
276
+ - ๐ŸŽ›๏ธ **NEW:** Configurable threshold filters suggestions by confidence level (0-1)
277
+ - ๐Ÿ“ Outputs copy-paste ready YAML configuration
278
+ - โœจ **Enhanced noise filtering:**
279
+ - Ignores UUIDs, timestamps, single-character changes
280
+ - Filters antonym pairs (enable/disable, true/false, on/off)
281
+ - Filters regex special characters (unless semantic keywords present)
282
+ - Filters version-number-only changes (service-v1 โ†’ service-v2)
283
+ - Allows semantic patterns even with special chars (db.uat.com โ†’ db.prod.com)
284
+
285
+ ### Example Output
286
+
287
+ ```yaml
288
+ # Suggested Transforms
289
+ transforms:
290
+ '**/*.yaml':
291
+ content:
292
+ - find: 'uat-cluster'
293
+ replace: 'prod-cluster'
294
+ # Confidence: 95% (42 occurrences across 12 files)
295
+
296
+ # Suggested Stop Rules
297
+ stopRules:
298
+ '**/*.yaml':
299
+ - type: 'semverMajorUpgrade'
300
+ path: 'image.tag'
301
+ # Detected version changes: v1.2.3 โ†’ v2.0.0
302
+ ```
303
+
304
+ ### When to Use
305
+
306
+ - ๐Ÿš€ **First-time setup**: Let heuristics discover patterns automatically instead of manual analysis
307
+ - ๐Ÿ”„ **Config refinement**: Find missing transforms or stop rules through smart detection
308
+ - ๐Ÿ“š **Learning tool**: Understand what's changing between environments
309
+ - โšก **Quick start**: Bootstrap configuration from existing files using intelligent pattern matching
310
+ - ๐Ÿง  **Pattern discovery**: Leverage heuristic algorithms to identify semantic transformations (uatโ†’prod, stagingโ†’production)
311
+ - ๐ŸŽฏ **Confidence tuning**: Adjust threshold to balance between finding all patterns vs. high-confidence only
312
+
313
+ **Confidence threshold control:**
314
+
315
+ ```bash
316
+ # More suggestions (lower threshold = less strict)
317
+ helm-env-delta --config config.yaml --suggest --suggest-threshold 0.2
318
+
319
+ # Default balance (standard heuristics, threshold: 0.3)
320
+ helm-env-delta --config config.yaml --suggest
321
+
322
+ # Only high-confidence (higher threshold = more strict)
323
+ helm-env-delta --config config.yaml --suggest --suggest-threshold 0.8
324
+ ```
325
+
326
+ **Workflow:**
327
+
328
+ ```bash
329
+ # 1. Get suggestions (optionally with custom threshold)
330
+ helm-env-delta --config config.yaml --suggest --suggest-threshold 0.5 > suggestions.yaml
331
+
332
+ # 2. Review and copy relevant sections to config.yaml
333
+
334
+ # 3. Test with dry-run
335
+ helm-env-delta --config config.yaml --dry-run --diff
336
+
337
+ # 4. Execute
338
+ helm-env-delta --config config.yaml
339
+ ```
340
+
341
+ ---
342
+
244
343
  ## โš™๏ธ Configuration Reference
245
344
 
246
345
  ### ๐ŸŽฏ Core Settings
@@ -511,21 +610,23 @@ hed --config <file> [options] # Short alias
511
610
 
512
611
  ### Options
513
612
 
514
- | Flag | Description |
515
- | ----------------- | ------------------------------------------------ |
516
- | `--config <path>` | **Required** - Configuration file |
517
- | `--validate` | Validate config and exit (shows warnings) |
518
- | `--dry-run` | Preview changes without writing files |
519
- | `--force` | Override stop rules |
520
- | `--diff` | Show console diff |
521
- | `--diff-html` | Generate HTML report (opens in browser) |
522
- | `--diff-json` | Output JSON to stdout (pipe to jq) |
523
- | `--list-files` | List source/destination files without processing |
524
- | `--show-config` | Display resolved config after inheritance |
525
- | `--skip-format` | Skip YAML formatting |
526
- | `--no-color` | Disable colored output (CI/accessibility) |
527
- | `--verbose` | Show detailed debug info |
528
- | `--quiet` | Suppress output except errors |
613
+ | Flag | Description |
614
+ | --------------------------- | ------------------------------------------------- |
615
+ | `--config <path>` | **Required** - Configuration file |
616
+ | `--validate` | Validate config and exit (shows warnings) |
617
+ | `--suggest` | Analyze differences and suggest config updates |
618
+ | `--suggest-threshold <0-1>` | Minimum confidence for suggestions (default: 0.3) |
619
+ | `--dry-run` | Preview changes without writing files |
620
+ | `--force` | Override stop rules |
621
+ | `--diff` | Show console diff |
622
+ | `--diff-html` | Generate HTML report (opens in browser) |
623
+ | `--diff-json` | Output JSON to stdout (pipe to jq) |
624
+ | `--list-files` | List source/destination files without processing |
625
+ | `--show-config` | Display resolved config after inheritance |
626
+ | `--skip-format` | Skip YAML formatting |
627
+ | `--no-color` | Disable colored output (CI/accessibility) |
628
+ | `--verbose` | Show detailed debug info |
629
+ | `--quiet` | Suppress output except errors |
529
630
 
530
631
  ### Examples
531
632
 
@@ -533,6 +634,12 @@ hed --config <file> [options] # Short alias
533
634
  # Validate configuration (shows warnings)
534
635
  hed --config config.yaml --validate
535
636
 
637
+ # Get smart configuration suggestions
638
+ hed --config config.yaml --suggest
639
+
640
+ # Get only high-confidence suggestions
641
+ hed --config config.yaml --suggest --suggest-threshold 0.7
642
+
536
643
  # Preview files that will be synced
537
644
  hed --config config.yaml --list-files
538
645
 
@@ -12,5 +12,7 @@ export type SyncCommand = {
12
12
  listFiles: boolean;
13
13
  showConfig: boolean;
14
14
  noColor: boolean;
15
+ suggest: boolean;
16
+ suggestThreshold: number;
15
17
  };
16
18
  export declare const parseCommandLine: (argv?: string[]) => SyncCommand;
@@ -22,6 +22,8 @@ const parseCommandLine = (argv) => {
22
22
  .option('--validate', 'Validate configuration file and exit', false)
23
23
  .option('--list-files', 'List files that would be synced without processing diffs', false)
24
24
  .option('--show-config', 'Display resolved configuration after inheritance and exit', false)
25
+ .option('--suggest', 'Analyze differences and suggest transforms and stop rules', false)
26
+ .option('--suggest-threshold <number>', 'Minimum confidence for suggestions (0-1, default: 0.3)', '0.3')
25
27
  .option('--no-color', 'Disable colored output')
26
28
  .option('--verbose', 'Show detailed debug information', false)
27
29
  .option('--quiet', 'Suppress all output except critical errors', false)
@@ -30,6 +32,9 @@ Examples:
30
32
  # Preview changes before syncing
31
33
  $ helm-env-delta --config config.yaml --dry-run --diff
32
34
 
35
+ # Get configuration suggestions
36
+ $ helm-env-delta --config config.yaml --suggest
37
+
33
38
  # Sync with HTML diff report
34
39
  $ helm-env-delta --config config.yaml --diff-html
35
40
 
@@ -48,6 +53,11 @@ Documentation: https://github.com/balazscsaba2006/helm-env-delta
48
53
  console.error('Error: --verbose and --quiet flags are mutually exclusive');
49
54
  process.exit(1);
50
55
  }
56
+ const threshold = Number.parseFloat(options['suggestThreshold']);
57
+ if (Number.isNaN(threshold) || threshold < 0 || threshold > 1) {
58
+ console.error('Error: --suggest-threshold must be a number between 0 and 1');
59
+ process.exit(1);
60
+ }
51
61
  return {
52
62
  config: options['config'],
53
63
  dryRun: options['dryRun'],
@@ -61,7 +71,9 @@ Documentation: https://github.com/balazscsaba2006/helm-env-delta
61
71
  showConfig: options['showConfig'],
62
72
  noColor: !options['color'],
63
73
  verbose: options['verbose'],
64
- quiet: options['quiet']
74
+ quiet: options['quiet'],
75
+ suggest: options['suggest'],
76
+ suggestThreshold: threshold
65
77
  };
66
78
  };
67
79
  exports.parseCommandLine = parseCommandLine;
@@ -14,6 +14,7 @@ export interface ChangedFile {
14
14
  processedDestContent: unknown;
15
15
  rawParsedSource: unknown;
16
16
  rawParsedDest: unknown;
17
+ skipPaths: string[];
17
18
  normalizedSource?: unknown;
18
19
  normalizedDest?: unknown;
19
20
  parsedSource?: unknown;
package/dist/fileDiff.js CHANGED
@@ -134,6 +134,7 @@ const processYamlFile = (filePath, sourceContent, destinationContent, skipPath,
134
134
  processedDestContent: normalizedDestination,
135
135
  rawParsedSource: sourceFiltered,
136
136
  rawParsedDest: destinationFiltered,
137
+ skipPaths: pathsToSkip,
137
138
  normalizedSource,
138
139
  normalizedDest: normalizedDestination,
139
140
  parsedSource: sourceParsed,
@@ -165,7 +166,8 @@ const processChangedFiles = (sourceFiles, destinationFiles, skipPath, transforms
165
166
  processedSourceContent: sourceContent,
166
167
  processedDestContent: destinationContent,
167
168
  rawParsedSource: sourceContent,
168
- rawParsedDest: destinationContent
169
+ rawParsedDest: destinationContent,
170
+ skipPaths: []
169
171
  });
170
172
  }
171
173
  return { changedFiles, unchangedFiles };
package/dist/index.js CHANGED
@@ -55,6 +55,7 @@ const htmlReporter_1 = require("./htmlReporter");
55
55
  const jsonReporter_1 = require("./jsonReporter");
56
56
  const logger_1 = require("./logger");
57
57
  const stopRulesValidator_1 = require("./stopRulesValidator");
58
+ const suggestionEngine_1 = require("./suggestionEngine");
58
59
  const collisionDetector_1 = require("./utils/collisionDetector");
59
60
  const filenameTransformer_1 = require("./utils/filenameTransformer");
60
61
  const versionChecker_1 = require("./utils/versionChecker");
@@ -147,6 +148,29 @@ const main = async () => {
147
148
  logger.log(` Changed files: ${diffResult.changedFiles.length}`);
148
149
  logger.log(` Unchanged files: ${diffResult.unchangedFiles.length}`);
149
150
  }
151
+ if (command.suggest) {
152
+ logger.log('\n' + (0, consoleFormatter_1.formatProgressMessage)('Analyzing differences for suggestions...', 'info'));
153
+ try {
154
+ const suggestions = (0, suggestionEngine_1.analyzeDifferencesForSuggestions)(diffResult, config, command.suggestThreshold);
155
+ const yaml = (0, suggestionEngine_1.formatSuggestionsAsYaml)(suggestions);
156
+ console.log(chalk_1.default.cyan('\n๐Ÿ’ก Suggested Configuration:\n'));
157
+ console.log(yaml);
158
+ if (suggestions.metadata.changedFiles === 0)
159
+ console.log(chalk_1.default.yellow('\nโ„น๏ธ No changes detected. Files are already in sync.'));
160
+ else {
161
+ console.log(chalk_1.default.dim('\n---'));
162
+ console.log(chalk_1.default.dim('๐Ÿ’ก Tip: Copy relevant sections to your config.yaml and test with --dry-run'));
163
+ }
164
+ return;
165
+ }
166
+ catch (error) {
167
+ if ((0, suggestionEngine_1.isSuggestionEngineError)(error)) {
168
+ logger.error('\nFailed to generate suggestions: ' + error.message, 'critical');
169
+ process.exit(1);
170
+ }
171
+ throw error;
172
+ }
173
+ }
150
174
  const configFileDirectory = node_path_1.default.dirname(node_path_1.default.resolve(command.config));
151
175
  const validationResult = (0, stopRulesValidator_1.validateStopRules)(diffResult, config.stopRules, configFileDirectory, logger);
152
176
  if (validationResult.violations.length > 0)
@@ -204,6 +228,8 @@ const main = async () => {
204
228
  console.error(error.message);
205
229
  else if ((0, jsonReporter_1.isJsonReporterError)(error))
206
230
  console.error(error.message);
231
+ else if ((0, suggestionEngine_1.isSuggestionEngineError)(error))
232
+ console.error(error.message);
207
233
  else if (error instanceof Error)
208
234
  console.error('Unexpected error:', error.message);
209
235
  else
@@ -0,0 +1,51 @@
1
+ import { Config, StopRule } from './configFile';
2
+ import { FileDiffResult } from './fileDiff';
3
+ export interface ValuePair {
4
+ oldValue: string;
5
+ targetValue: string;
6
+ path: string;
7
+ }
8
+ export interface TransformSuggestion {
9
+ find: string;
10
+ replace: string;
11
+ confidence: number;
12
+ occurrences: number;
13
+ affectedFiles: string[];
14
+ examples: ValuePair[];
15
+ }
16
+ export interface StopRuleSuggestion {
17
+ rule: StopRule;
18
+ confidence: number;
19
+ reason: string;
20
+ affectedPaths: string[];
21
+ affectedFiles: string[];
22
+ }
23
+ export interface SuggestionResult {
24
+ transforms: Map<string, TransformSuggestion[]>;
25
+ stopRules: Map<string, StopRuleSuggestion[]>;
26
+ metadata: {
27
+ filesAnalyzed: number;
28
+ changedFiles: number;
29
+ timestamp: string;
30
+ };
31
+ }
32
+ declare const SuggestionEngineErrorClass: {
33
+ new (message: string, options?: import("./utils/errors").ErrorOptions): {
34
+ [key: string]: unknown;
35
+ readonly code?: string;
36
+ readonly path?: string;
37
+ readonly cause?: Error;
38
+ name: string;
39
+ message: string;
40
+ stack?: string;
41
+ };
42
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
43
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
44
+ stackTraceLimit: number;
45
+ };
46
+ export declare class SuggestionEngineError extends SuggestionEngineErrorClass {
47
+ }
48
+ export declare const isSuggestionEngineError: (error: unknown) => error is SuggestionEngineError;
49
+ export declare const analyzeDifferencesForSuggestions: (diffResult: FileDiffResult, config: Config, confidenceThreshold?: number) => SuggestionResult;
50
+ export declare const formatSuggestionsAsYaml: (result: SuggestionResult) => string;
51
+ export {};