@contrail/cli 3.4.4-alpha.e5b7d5d → 3.4.5-alpha.18160f5

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
@@ -17,7 +17,7 @@ $ npm install -g @contrail/cli
17
17
  $ contrail COMMAND
18
18
  running command...
19
19
  $ contrail (--version)
20
- @contrail/cli/3.4.4-alpha.e5b7d5d linux-x64 node-v18.20.8
20
+ @contrail/cli/3.4.5-alpha.18160f5 linux-x64 node-v18.20.8
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
@@ -0,0 +1,18 @@
1
+ import { BaseCommand } from '../../basecommand';
2
+ export default class LoadLocal extends BaseCommand {
3
+ static hidden: boolean;
4
+ static description: string;
5
+ static examples: string[];
6
+ static flags: {
7
+ yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ 'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ stage: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
+ alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
+ logLevel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
+ };
13
+ static args: {
14
+ dataFile: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
15
+ configFile: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
16
+ };
17
+ run(): Promise<void>;
18
+ }
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const core_1 = require("@oclif/core");
5
+ const sdk_1 = require("@contrail/sdk");
6
+ const loader_1 = require("@contrail/loader");
7
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
8
+ const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
9
+ const login_1 = require("../../auth/login");
10
+ const basecommand_1 = require("../../basecommand");
11
+ const helpers_1 = require("../../helpers/load/helpers");
12
+ const file_helpers_1 = require("../../helpers/file-helpers");
13
+ const logger_1 = tslib_1.__importDefault(require("../../logger"));
14
+ const formatters_1 = require("../../helpers/pipeline/formatters");
15
+ const fs = tslib_1.__importStar(require("fs"));
16
+ const path = tslib_1.__importStar(require("path"));
17
+ class LoadLocal extends basecommand_1.BaseCommand {
18
+ static hidden = true;
19
+ static description = 'Run the full data loading pipeline locally. Reads a CSV data file and a YAML/JSON config, then runs preprocess → analyze → validate → preview → execute stages with detailed feedback.';
20
+ static examples = [
21
+ '$ contrail load-local data.csv config.yml',
22
+ '$ contrail load-local data.csv config.yml --dry-run',
23
+ '$ contrail load-local data.csv config.yml --yes',
24
+ '$ contrail load-local data.csv config.yml --stage 3',
25
+ ];
26
+ static flags = {
27
+ ...basecommand_1.BaseCommand.baseFlags,
28
+ yes: core_1.Flags.boolean({
29
+ char: 'y',
30
+ description: 'Skip confirmation prompt before executing',
31
+ default: false,
32
+ }),
33
+ 'dry-run': core_1.Flags.boolean({
34
+ char: 'd',
35
+ description: 'Run stages 1-4 only (no execution)',
36
+ default: false,
37
+ }),
38
+ stage: core_1.Flags.integer({
39
+ char: 's',
40
+ description: 'Run only up to this stage (1-5)',
41
+ options: ['1', '2', '3', '4', '5'],
42
+ }),
43
+ };
44
+ static args = {
45
+ dataFile: core_1.Args.string({
46
+ description: 'Path to the CSV data file',
47
+ required: true,
48
+ }),
49
+ configFile: core_1.Args.string({
50
+ description: 'Path to the YAML or JSON configuration file',
51
+ required: true,
52
+ }),
53
+ };
54
+ async run() {
55
+ const maxStage = this.flags['dry-run'] ? 4 : this.flags.stage || 5;
56
+ // Read and parse files
57
+ let csvData;
58
+ let config;
59
+ try {
60
+ const csvPath = path.resolve(process.cwd(), this.args.dataFile);
61
+ const csvRaw = fs.readFileSync(csvPath, 'utf8');
62
+ csvData = (0, file_helpers_1.parseCSVData)(csvRaw);
63
+ logger_1.default.info(`${chalk_1.default.yellow.bold('LOAD-LOCAL')} Parsed ${csvData.length} rows from ${this.args.dataFile}`);
64
+ const ext = this.args.configFile.toLowerCase();
65
+ const fileExt = ext.endsWith('.yml') || ext.endsWith('.yaml')
66
+ ? helpers_1.FileExtension.YAML
67
+ : helpers_1.FileExtension.JSON;
68
+ config = (0, helpers_1.readFile)(this.args.configFile, fileExt);
69
+ logger_1.default.info(`${chalk_1.default.yellow.bold('LOAD-LOCAL')} Loaded config from ${this.args.configFile}`);
70
+ }
71
+ catch (e) {
72
+ logger_1.default.info(`${chalk_1.default.red.bold('FAIL')} Failed to read input files. ${e}`);
73
+ return;
74
+ }
75
+ // Authenticate and create pipeline
76
+ await (0, login_1.authUser)();
77
+ const pipeline = new loader_1.LoaderPipeline(new sdk_1.Entities());
78
+ try {
79
+ // Fetch type definitions (needed by both preprocessing and column analysis)
80
+ logger_1.default.info(`\n${chalk_1.default.yellow.bold('LOAD-LOCAL')} Fetching type definitions...`);
81
+ const typeDefs = await pipeline.fetchTypeDefinitions(csvData, config);
82
+ // Stage 1: Preprocess
83
+ logger_1.default.info(`\n${chalk_1.default.yellow.bold('LOAD-LOCAL')} Running Stage 1: Preprocess...`);
84
+ const preprocessed = await pipeline.preprocess(csvData, config, typeDefs);
85
+ console.log('\n' + (0, formatters_1.formatPreprocessResult)(preprocessed));
86
+ if (maxStage <= 1)
87
+ return;
88
+ // Stage 2: Analyze Columns
89
+ logger_1.default.info(`\n${chalk_1.default.yellow.bold('LOAD-LOCAL')} Running Stage 2: Analyze Columns...`);
90
+ const analysis = pipeline.analyzeColumns(preprocessed, config, typeDefs);
91
+ console.log('\n' + (0, formatters_1.formatColumnAnalysis)(analysis));
92
+ if (maxStage <= 2)
93
+ return;
94
+ // Stage 3: Validate
95
+ logger_1.default.info(`\n${chalk_1.default.yellow.bold('LOAD-LOCAL')} Running Stage 3: Validate...`);
96
+ const validation = await pipeline.validate(preprocessed, config, analysis);
97
+ console.log('\n' + (0, formatters_1.formatValidationResult)(validation));
98
+ if (!validation.valid) {
99
+ logger_1.default.info(`\n${chalk_1.default.red.bold('LOAD-LOCAL')} Validation failed. Fix the issues above before proceeding.`);
100
+ return;
101
+ }
102
+ if (maxStage <= 3)
103
+ return;
104
+ // Stage 4: Preview
105
+ logger_1.default.info(`\n${chalk_1.default.yellow.bold('LOAD-LOCAL')} Running Stage 4: Preview...`);
106
+ const previewResult = await pipeline.preview(preprocessed, config, analysis);
107
+ console.log('\n' + (0, formatters_1.formatPreviewResult)(previewResult));
108
+ if (maxStage <= 4)
109
+ return;
110
+ // Confirm before execute
111
+ if (!this.flags.yes) {
112
+ const noChangesDetected = previewResult.entities.every((e) => e.creates === 0 && e.updates === 0 && e.drops === 0);
113
+ const { confirm } = await inquirer_1.default.prompt([
114
+ {
115
+ type: 'confirm',
116
+ name: 'confirm',
117
+ message: noChangesDetected
118
+ ? 'Proceed with the execution step anyway? This will try to detect updates again and persist any detected changes.'
119
+ : 'Proceed with execution?',
120
+ default: false,
121
+ },
122
+ ]);
123
+ if (!confirm) {
124
+ logger_1.default.info(`${chalk_1.default.yellow.bold('LOAD-LOCAL')} Execution cancelled.`);
125
+ return;
126
+ }
127
+ }
128
+ // Stage 5: Execute
129
+ logger_1.default.info(`\n${chalk_1.default.yellow.bold('LOAD-LOCAL')} Running Stage 5: Execute...`);
130
+ const executeOptions = {
131
+ batchSize: config.options?.batchSize,
132
+ concurrency: config.options?.concurrency,
133
+ maxRetries: config.options?.maxRetries,
134
+ onProgress: (progress) => {
135
+ process.stdout.write(`\r ${chalk_1.default.dim(progress.stage)}: ${progress.current}/${progress.total}`);
136
+ },
137
+ };
138
+ const executionResult = await pipeline.execute(preprocessed, config, analysis, executeOptions, previewResult);
139
+ // Clear progress line
140
+ process.stdout.write('\r' + ' '.repeat(60) + '\r');
141
+ console.log('\n' + (0, formatters_1.formatExecutionResult)(executionResult));
142
+ if (executionResult.status === 'complete') {
143
+ logger_1.default.info(`\n${chalk_1.default.green.bold('COMPLETE')} Load finished successfully.`);
144
+ }
145
+ else if (executionResult.status === 'partial-failure') {
146
+ logger_1.default.info(`\n${chalk_1.default.yellow.bold('PARTIAL')} Load completed with some failures.`);
147
+ }
148
+ else {
149
+ logger_1.default.info(`\n${chalk_1.default.red.bold('FAILED')} Load failed.`);
150
+ }
151
+ }
152
+ catch (e) {
153
+ logger_1.default.info(`\n${chalk_1.default.red.bold('FAIL')} Pipeline error: ${e}`);
154
+ }
155
+ }
156
+ }
157
+ exports.default = LoadLocal;
@@ -0,0 +1,6 @@
1
+ import { ColumnAnalysisResult, PreprocessResult, PreviewResult, ExecutionResult, PreValidationResult } from '@contrail/loader';
2
+ export declare function formatColumnAnalysis(result: ColumnAnalysisResult): string;
3
+ export declare function formatPreprocessResult(result: PreprocessResult): string;
4
+ export declare function formatValidationResult(result: PreValidationResult): string;
5
+ export declare function formatPreviewResult(result: PreviewResult): string;
6
+ export declare function formatExecutionResult(result: ExecutionResult): string;
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatExecutionResult = exports.formatPreviewResult = exports.formatValidationResult = exports.formatPreprocessResult = exports.formatColumnAnalysis = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const cli_table3_1 = tslib_1.__importDefault(require("cli-table3"));
7
+ const loader_1 = require("@contrail/loader");
8
+ function formatColumnAnalysis(result) {
9
+ const table = new cli_table3_1.default({
10
+ head: [
11
+ chalk_1.default.cyan('CSV Header'),
12
+ chalk_1.default.cyan('Matched Slug'),
13
+ chalk_1.default.cyan('Property Type'),
14
+ chalk_1.default.cyan('Mapped'),
15
+ chalk_1.default.cyan('Required'),
16
+ chalk_1.default.cyan('Option Set'),
17
+ chalk_1.default.cyan('Archived'),
18
+ ],
19
+ style: { head: [] },
20
+ });
21
+ for (const col of result.columns) {
22
+ table.push([
23
+ col.csvHeader,
24
+ col.matchedSlug || chalk_1.default.dim('—'),
25
+ col.propertyType || chalk_1.default.dim('—'),
26
+ col.isMapped ? chalk_1.default.green('yes') : chalk_1.default.red('no'),
27
+ col.isRequired
28
+ ? chalk_1.default.yellow(col.requiredNote ? `yes (${col.requiredNote})` : 'yes')
29
+ : 'no',
30
+ col.hasOptionSet ? 'yes' : 'no',
31
+ col.isArchived ? chalk_1.default.red('yes') : 'no',
32
+ ]);
33
+ }
34
+ const mapped = result.columns.filter((c) => c.isMapped).length;
35
+ const unmapped = result.columns.filter((c) => !c.isMapped).length;
36
+ return [
37
+ chalk_1.default.bold.underline('Stage 2: Column Analysis'),
38
+ table.toString(),
39
+ ` ${chalk_1.default.green(mapped)} mapped, ${unmapped > 0 ? chalk_1.default.red(unmapped) : unmapped} unmapped, ${result.columns.length} total columns`,
40
+ ` Entity types: ${result.entityTypes.join(', ') || 'none'}`,
41
+ ].join('\n');
42
+ }
43
+ exports.formatColumnAnalysis = formatColumnAnalysis;
44
+ function formatPreprocessResult(result) {
45
+ const table = new cli_table3_1.default({
46
+ head: [
47
+ chalk_1.default.cyan('Step'),
48
+ chalk_1.default.cyan('Rows After'),
49
+ chalk_1.default.cyan('Errors'),
50
+ chalk_1.default.cyan('Warnings'),
51
+ ],
52
+ style: { head: [] },
53
+ });
54
+ for (const step of result.stepResults) {
55
+ table.push([
56
+ step.stepName,
57
+ step.rowCountAfter.toString(),
58
+ step.errorCount > 0 ? chalk_1.default.red(step.errorCount.toString()) : '0',
59
+ step.warningCount > 0 ? chalk_1.default.yellow(step.warningCount.toString()) : '0',
60
+ ]);
61
+ }
62
+ const totalErrors = result.errors.length + result.generalErrors.length;
63
+ const totalWarnings = result.warnings.length + result.generalWarnings.length;
64
+ return [
65
+ chalk_1.default.bold.underline('Stage 1: Preprocessing'),
66
+ table.toString(),
67
+ ` ${result.rows.length} rows after preprocessing, ${totalErrors > 0 ? chalk_1.default.red(`${totalErrors} errors`) : '0 errors'}, ${totalWarnings > 0 ? chalk_1.default.yellow(`${totalWarnings} warnings`) : '0 warnings'}`,
68
+ ].join('\n');
69
+ }
70
+ exports.formatPreprocessResult = formatPreprocessResult;
71
+ function formatValidationResult(result) {
72
+ const lines = [chalk_1.default.bold.underline('Stage 3: Validation')];
73
+ if (result.valid) {
74
+ lines.push(` ${chalk_1.default.green.bold('VALID')} — no issues found`);
75
+ return lines.join('\n');
76
+ }
77
+ const table = new cli_table3_1.default({
78
+ head: [
79
+ chalk_1.default.cyan('Severity'),
80
+ chalk_1.default.cyan('Category'),
81
+ chalk_1.default.cyan('Column'),
82
+ chalk_1.default.cyan('Message'),
83
+ chalk_1.default.cyan('Rows Affected'),
84
+ chalk_1.default.cyan('Suggested Fix'),
85
+ ],
86
+ style: { head: [] },
87
+ colWidths: [10, 16, 16, 40, 14, 24],
88
+ wordWrap: true,
89
+ });
90
+ for (const issue of result.issues) {
91
+ const severityStr = issue.severity === loader_1.PreValidationSeverity.ERROR
92
+ ? chalk_1.default.red('ERROR')
93
+ : issue.severity === loader_1.PreValidationSeverity.WARNING
94
+ ? chalk_1.default.yellow('WARN')
95
+ : chalk_1.default.blue('INFO');
96
+ table.push([
97
+ severityStr,
98
+ issue.category,
99
+ issue.columnName,
100
+ issue.message,
101
+ issue.affectedRows.length.toString(),
102
+ issue.suggestedFix ? `${issue.suggestedFix.type}` : chalk_1.default.dim('—'),
103
+ ]);
104
+ }
105
+ lines.push(table.toString());
106
+ lines.push(` ${chalk_1.default.red(`${result.summary.errorCount} errors`)}, ${chalk_1.default.yellow(`${result.summary.warningCount} warnings`)}, ${result.summary.infoCount} info`);
107
+ return lines.join('\n');
108
+ }
109
+ exports.formatValidationResult = formatValidationResult;
110
+ function formatPreviewResult(result) {
111
+ const table = new cli_table3_1.default({
112
+ head: [
113
+ chalk_1.default.cyan('Entity Type'),
114
+ chalk_1.default.cyan('Total'),
115
+ chalk_1.default.cyan('Creates'),
116
+ chalk_1.default.cyan('Updates'),
117
+ chalk_1.default.cyan('Unchanged'),
118
+ chalk_1.default.cyan('Drops'),
119
+ chalk_1.default.cyan('Stale Skipped'),
120
+ ],
121
+ style: { head: [] },
122
+ });
123
+ for (const entity of result.entities) {
124
+ table.push([
125
+ entity.entityType,
126
+ entity.total.toString(),
127
+ entity.creates > 0 ? chalk_1.default.green(entity.creates.toString()) : '0',
128
+ entity.updates > 0 ? chalk_1.default.blue(entity.updates.toString()) : '0',
129
+ entity.unchanged.toString(),
130
+ entity.drops > 0 ? chalk_1.default.red(entity.drops.toString()) : '0',
131
+ entity.skippedStale > 0 ? chalk_1.default.yellow(entity.skippedStale.toString()) : '0',
132
+ ]);
133
+ }
134
+ const totalChanges = result.entities.reduce((sum, e) => sum + e.creates + e.updates + e.drops, 0);
135
+ const hasWarnings = result.warnings.length > 0 || result.badRows.length > 0;
136
+ const lines = [chalk_1.default.bold.underline('Stage 4: Preview')];
137
+ if (totalChanges === 0 && !hasWarnings) {
138
+ lines.push(chalk_1.default.green.bold('\n ✔ No changes to make — all entities already exist and have the same property values as the load file.\n'));
139
+ }
140
+ else if (totalChanges === 0 && hasWarnings) {
141
+ lines.push(chalk_1.default.yellow.bold('\n No changes to make, but some rows could not be processed. See warnings below.\n'));
142
+ }
143
+ lines.push(table.toString());
144
+ if (result.badRows.length > 0) {
145
+ lines.push(chalk_1.default.red(` ${result.badRows.length} bad rows skipped:`));
146
+ for (const row of result.badRows.slice(0, 10)) {
147
+ lines.push(` Row ${row.rowNumber}: ${row.reason}`);
148
+ }
149
+ if (result.badRows.length > 10) {
150
+ lines.push(chalk_1.default.dim(` ... and ${result.badRows.length - 10} more`));
151
+ }
152
+ }
153
+ if (result.staleRows.length > 0) {
154
+ lines.push(chalk_1.default.yellow(` ${result.staleRows.length} stale rows skipped`));
155
+ }
156
+ if (result.warnings.length > 0) {
157
+ lines.push(chalk_1.default.yellow(` ${result.warnings.length} warnings:`));
158
+ for (const w of result.warnings.slice(0, 5)) {
159
+ lines.push(` ${w}`);
160
+ }
161
+ if (result.warnings.length > 5) {
162
+ lines.push(chalk_1.default.dim(` ... and ${result.warnings.length - 5} more`));
163
+ }
164
+ }
165
+ return lines.join('\n');
166
+ }
167
+ exports.formatPreviewResult = formatPreviewResult;
168
+ function formatExecutionResult(result) {
169
+ const statusColor = result.status === 'complete'
170
+ ? chalk_1.default.green.bold
171
+ : result.status === 'partial-failure'
172
+ ? chalk_1.default.yellow.bold
173
+ : chalk_1.default.red.bold;
174
+ const table = new cli_table3_1.default({
175
+ head: [
176
+ chalk_1.default.cyan('Entity Type'),
177
+ chalk_1.default.cyan('Total'),
178
+ chalk_1.default.cyan('Created'),
179
+ chalk_1.default.cyan('Updated'),
180
+ chalk_1.default.cyan('Dropped'),
181
+ chalk_1.default.cyan('Stale Skipped'),
182
+ chalk_1.default.cyan('Failed'),
183
+ ],
184
+ style: { head: [] },
185
+ });
186
+ for (const entity of result.entities) {
187
+ const total = entity.created + entity.updated + entity.dropped + entity.skippedStale + entity.failed;
188
+ table.push([
189
+ entity.entityType,
190
+ total.toString(),
191
+ entity.created > 0 ? chalk_1.default.green(entity.created.toString()) : '0',
192
+ entity.updated > 0 ? chalk_1.default.blue(entity.updated.toString()) : '0',
193
+ entity.dropped > 0 ? chalk_1.default.red(entity.dropped.toString()) : '0',
194
+ entity.skippedStale > 0 ? chalk_1.default.yellow(entity.skippedStale.toString()) : '0',
195
+ entity.failed > 0 ? chalk_1.default.red.bold(entity.failed.toString()) : '0',
196
+ ]);
197
+ }
198
+ const totalOps = result.entities.reduce((sum, e) => sum + e.created + e.updated + e.dropped, 0);
199
+ const lines = [
200
+ chalk_1.default.bold.underline('Stage 5: Execution'),
201
+ ` Status: ${statusColor(result.status.toUpperCase())}`,
202
+ ` Duration: ${(result.duration / 1000).toFixed(1)}s`,
203
+ ];
204
+ if (totalOps === 0 && result.entities.reduce((sum, e) => sum + e.failed, 0) === 0) {
205
+ lines.push(chalk_1.default.green.bold('\n ✔ No changes were needed — all entities already exist and have the same property values as the load file.\n'));
206
+ }
207
+ lines.push(table.toString());
208
+ const allFailures = result.entities.flatMap((e) => e.failures);
209
+ if (allFailures.length > 0) {
210
+ lines.push(chalk_1.default.red(` ${allFailures.length} failures:`));
211
+ for (const f of allFailures.slice(0, 10)) {
212
+ lines.push(` ${f.operation} ${f.federatedId}: ${f.error}`);
213
+ }
214
+ if (allFailures.length > 10) {
215
+ lines.push(chalk_1.default.dim(` ... and ${allFailures.length - 10} more`));
216
+ }
217
+ }
218
+ if (result.warnings.length > 0) {
219
+ lines.push(chalk_1.default.yellow(` ${result.warnings.length} warnings`));
220
+ }
221
+ return lines.join('\n');
222
+ }
223
+ exports.formatExecutionResult = formatExecutionResult;
@@ -0,0 +1,62 @@
1
+ <component name="ProjectCodeStyleConfiguration">
2
+ <code_scheme name="Project" version="173">
3
+ <HTMLCodeStyleSettings>
4
+ <option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
5
+ </HTMLCodeStyleSettings>
6
+ <JSCodeStyleSettings version="0">
7
+ <option name="FORCE_SEMICOLON_STYLE" value="true" />
8
+ <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
9
+ <option name="USE_DOUBLE_QUOTES" value="false" />
10
+ <option name="FORCE_QUOTE_STYlE" value="true" />
11
+ <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
12
+ <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
13
+ <option name="SPACES_WITHIN_IMPORTS" value="true" />
14
+ </JSCodeStyleSettings>
15
+ <TypeScriptCodeStyleSettings version="0">
16
+ <option name="FORCE_SEMICOLON_STYLE" value="true" />
17
+ <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
18
+ <option name="USE_DOUBLE_QUOTES" value="false" />
19
+ <option name="FORCE_QUOTE_STYlE" value="true" />
20
+ <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
21
+ <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
22
+ <option name="SPACES_WITHIN_IMPORTS" value="true" />
23
+ </TypeScriptCodeStyleSettings>
24
+ <VueCodeStyleSettings>
25
+ <option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
26
+ <option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
27
+ </VueCodeStyleSettings>
28
+ <editorconfig>
29
+ <option name="ENABLED" value="false" />
30
+ </editorconfig>
31
+ <codeStyleSettings language="HTML">
32
+ <option name="SOFT_MARGINS" value="120" />
33
+ <indentOptions>
34
+ <option name="INDENT_SIZE" value="2" />
35
+ <option name="CONTINUATION_INDENT_SIZE" value="2" />
36
+ <option name="TAB_SIZE" value="2" />
37
+ </indentOptions>
38
+ </codeStyleSettings>
39
+ <codeStyleSettings language="JavaScript">
40
+ <option name="SOFT_MARGINS" value="120" />
41
+ <indentOptions>
42
+ <option name="INDENT_SIZE" value="2" />
43
+ <option name="CONTINUATION_INDENT_SIZE" value="2" />
44
+ <option name="TAB_SIZE" value="2" />
45
+ </indentOptions>
46
+ </codeStyleSettings>
47
+ <codeStyleSettings language="TypeScript">
48
+ <option name="SOFT_MARGINS" value="120" />
49
+ <indentOptions>
50
+ <option name="INDENT_SIZE" value="2" />
51
+ <option name="CONTINUATION_INDENT_SIZE" value="2" />
52
+ <option name="TAB_SIZE" value="2" />
53
+ </indentOptions>
54
+ </codeStyleSettings>
55
+ <codeStyleSettings language="Vue">
56
+ <option name="SOFT_MARGINS" value="120" />
57
+ <indentOptions>
58
+ <option name="CONTINUATION_INDENT_SIZE" value="2" />
59
+ </indentOptions>
60
+ </codeStyleSettings>
61
+ </code_scheme>
62
+ </component>
@@ -0,0 +1,5 @@
1
+ <component name="ProjectCodeStyleConfiguration">
2
+ <state>
3
+ <option name="USE_PER_PROJECT_SETTINGS" value="true" />
4
+ </state>
5
+ </component>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="WEB_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/.tmp" />
6
+ <excludeFolder url="file://$MODULE_DIR$/temp" />
7
+ <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
+ </content>
9
+ <orderEntry type="inheritedJdk" />
10
+ <orderEntry type="sourceFolder" forTests="false" />
11
+ </component>
12
+ </module>
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="GitToolBoxProjectSettings">
4
+ <option name="commitMessageIssueKeyValidationOverride">
5
+ <BoolValueOverride>
6
+ <option name="enabled" value="true" />
7
+ </BoolValueOverride>
8
+ </option>
9
+ <option name="commitMessageValidationEnabledOverride">
10
+ <BoolValueOverride>
11
+ <option name="enabled" value="true" />
12
+ </BoolValueOverride>
13
+ </option>
14
+ </component>
15
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/contrail-entity-types.iml" filepath="$PROJECT_DIR$/.idea/contrail-entity-types.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -23,12 +23,21 @@ export declare class ValueToAssortment {
23
23
  }
24
24
  export interface LoaderConfiguration extends OrgManagedEntity {
25
25
  name?: string;
26
+ loadType: LoadType[];
27
+ messageGroupId?: string;
26
28
  federatedMappings?: any;
27
29
  conditionalColumns?: ColumnDefinition[];
28
30
  assortmentSplit?: AssortmentSplit;
29
31
  workspaceIdentifier?: string;
30
32
  propertiesToRemove?: string[];
31
33
  skipStaleUpdatesUsing?: string;
34
+ ignoreParameters?: IgnoreParameters;
35
+ loaderConfigurationId?: string;
36
+ shouldSkipAssortmentPublish?: boolean;
37
+ }
38
+ export interface IgnoreParameters {
39
+ ignoreFamilyNameOnUpdate: boolean;
40
+ ignoreOptionNameOnUpdate: boolean;
32
41
  }
33
42
  export declare enum LoadStatus {
34
43
  ACTIVE = "ACTIVE",
@@ -122,17 +131,10 @@ export interface ProcessedData {
122
131
  systemErrors: GeneralIssueDetails[];
123
132
  failureArea: LoaderFailureArea;
124
133
  }
125
- export declare class LoaderProcess implements OrgManagedEntity {
134
+ export interface LoaderProcess extends LoaderConfiguration {
126
135
  id: string;
127
- createdOn?: Date;
128
- updatedOn?: Date;
129
- createdById?: string;
130
- updatedById?: string;
131
136
  createdBy?: any;
132
137
  updatedBy?: any;
133
- orgId?: string;
134
- loaderConfigurationId?: string;
135
- name?: string;
136
138
  endedOn?: Date;
137
139
  status: LoadStatus;
138
140
  logLevel?: LogLevel;
@@ -147,21 +149,13 @@ export declare class LoaderProcess implements OrgManagedEntity {
147
149
  preprocessingStepResults?: PreprocessingStepStoredResultSummary[];
148
150
  processDurationSeconds?: number;
149
151
  loadFileId: string;
150
- loadType: LoadType[];
151
- federatedMappings?: any;
152
- conditionalColumns?: ColumnDefinition[];
153
- assortmentSplit?: AssortmentSplit;
154
152
  partialAssortmentUpdate?: boolean;
155
153
  assortmentItemDropField?: string;
156
- workspaceIdentifier?: string;
157
- propertiesToRemove?: string[];
158
154
  badRowsCount?: number;
159
155
  uploadErrorCount?: number;
160
156
  hasErrors?: boolean;
161
157
  parallelWorkerCount?: number;
162
- messageGroupId?: string;
163
158
  isPartialFailure?: boolean;
164
- skipStaleUpdatesUsing?: string;
165
159
  }
166
160
  export declare enum IssueType {
167
161
  CONFIG = "CONFIG",
@@ -191,7 +185,11 @@ export declare enum EntityType {
191
185
  export declare enum PreValidationCategory {
192
186
  OPTION_SET = "OPTION_SET",
193
187
  FORMAT_BOOLEAN = "FORMAT_BOOLEAN",
194
- FORMAT_MULTI_SELECT = "FORMAT_MULTI_SELECT"
188
+ FORMAT_MULTI_SELECT = "FORMAT_MULTI_SELECT",
189
+ CONFIG = "CONFIG",
190
+ MISSING_REQUIRED_FIELD = "MISSING_REQUIRED_FIELD",
191
+ REFERENCE_DATA_NOT_FOUND = "REFERENCE_DATA_NOT_FOUND",
192
+ FAMILY_PROPERTY_VALUES_INCONSISTENT = "FAMILY_PROPERTY_VALUES_INCONSISTENT"
195
193
  }
196
194
  export declare enum PreValidationSeverity {
197
195
  ERROR = "error",
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SuggestedFixType = exports.PreValidationSeverity = exports.PreValidationCategory = exports.EntityType = exports.LoaderFailureArea = exports.IssueType = exports.LoaderProcess = exports.LoadType = exports.LoadStatus = exports.ValueToAssortment = exports.AssortmentSplit = exports.ConditionalValues = exports.ColumnDefinition = void 0;
3
+ exports.SuggestedFixType = exports.PreValidationSeverity = exports.PreValidationCategory = exports.EntityType = exports.LoaderFailureArea = exports.IssueType = exports.LoadType = exports.LoadStatus = exports.ValueToAssortment = exports.AssortmentSplit = exports.ConditionalValues = exports.ColumnDefinition = void 0;
4
4
  class ColumnDefinition {
5
5
  fromProperty;
6
6
  toProperty;
@@ -44,48 +44,6 @@ var LoadType;
44
44
  LoadType["SIZE_RANGE_TEMPLATE"] = "SIZE_RANGE_TEMPLATE";
45
45
  LoadType["PROJECT"] = "PROJECT";
46
46
  })(LoadType = exports.LoadType || (exports.LoadType = {}));
47
- class LoaderProcess {
48
- id;
49
- createdOn;
50
- updatedOn;
51
- createdById;
52
- updatedById;
53
- createdBy;
54
- updatedBy;
55
- orgId;
56
- loaderConfigurationId;
57
- name;
58
- endedOn;
59
- status;
60
- logLevel;
61
- processLogs;
62
- processLogS3File;
63
- processLogS3FileDownloadLink;
64
- logsFileId;
65
- logFileDownloadLink;
66
- loadProcessResult;
67
- loadProcessResultFileId;
68
- loadProcessResultDownloadLink;
69
- preprocessingStepResults;
70
- processDurationSeconds;
71
- loadFileId;
72
- loadType;
73
- federatedMappings;
74
- conditionalColumns;
75
- assortmentSplit;
76
- partialAssortmentUpdate;
77
- assortmentItemDropField;
78
- workspaceIdentifier;
79
- propertiesToRemove;
80
- badRowsCount;
81
- uploadErrorCount;
82
- hasErrors;
83
- parallelWorkerCount;
84
- messageGroupId;
85
- isPartialFailure;
86
- skipStaleUpdatesUsing;
87
- }
88
- exports.LoaderProcess = LoaderProcess;
89
47
  var IssueType;
90
48
  (function (IssueType) {
91
49
  IssueType["CONFIG"] = "CONFIG";
@@ -119,6 +77,10 @@ var PreValidationCategory;
119
77
  PreValidationCategory["OPTION_SET"] = "OPTION_SET";
120
78
  PreValidationCategory["FORMAT_BOOLEAN"] = "FORMAT_BOOLEAN";
121
79
  PreValidationCategory["FORMAT_MULTI_SELECT"] = "FORMAT_MULTI_SELECT";
80
+ PreValidationCategory["CONFIG"] = "CONFIG";
81
+ PreValidationCategory["MISSING_REQUIRED_FIELD"] = "MISSING_REQUIRED_FIELD";
82
+ PreValidationCategory["REFERENCE_DATA_NOT_FOUND"] = "REFERENCE_DATA_NOT_FOUND";
83
+ PreValidationCategory["FAMILY_PROPERTY_VALUES_INCONSISTENT"] = "FAMILY_PROPERTY_VALUES_INCONSISTENT";
122
84
  })(PreValidationCategory = exports.PreValidationCategory || (exports.PreValidationCategory = {}));
123
85
  var PreValidationSeverity;
124
86
  (function (PreValidationSeverity) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/entity-types",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "A types library for Vibeiq entities.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.4.4-alpha.e5b7d5d",
2
+ "version": "3.4.5-alpha.18160f5",
3
3
  "commands": {
4
4
  "app:create": {
5
5
  "id": "app:create",
@@ -1155,6 +1155,91 @@
1155
1155
  }
1156
1156
  }
1157
1157
  },
1158
+ "load-local": {
1159
+ "id": "load-local",
1160
+ "description": "Run the full data loading pipeline locally. Reads a CSV data file and a YAML/JSON config, then runs preprocess → analyze → validate → preview → execute stages with detailed feedback.",
1161
+ "strict": true,
1162
+ "pluginName": "@contrail/cli",
1163
+ "pluginAlias": "@contrail/cli",
1164
+ "pluginType": "core",
1165
+ "hidden": true,
1166
+ "aliases": [],
1167
+ "examples": [
1168
+ "$ contrail load-local data.csv config.yml",
1169
+ "$ contrail load-local data.csv config.yml --dry-run",
1170
+ "$ contrail load-local data.csv config.yml --yes",
1171
+ "$ contrail load-local data.csv config.yml --stage 3"
1172
+ ],
1173
+ "flags": {
1174
+ "logLevel": {
1175
+ "name": "logLevel",
1176
+ "type": "option",
1177
+ "char": "l",
1178
+ "description": "The Log Level",
1179
+ "required": false,
1180
+ "multiple": false,
1181
+ "options": [
1182
+ "error",
1183
+ "warn",
1184
+ "info",
1185
+ "debug"
1186
+ ]
1187
+ },
1188
+ "alwaysConfirmEnv": {
1189
+ "name": "alwaysConfirmEnv",
1190
+ "type": "option",
1191
+ "char": "e",
1192
+ "description": "The Environment variables",
1193
+ "required": false,
1194
+ "multiple": false,
1195
+ "options": [
1196
+ "true",
1197
+ "false"
1198
+ ],
1199
+ "default": "true"
1200
+ },
1201
+ "yes": {
1202
+ "name": "yes",
1203
+ "type": "boolean",
1204
+ "char": "y",
1205
+ "description": "Skip confirmation prompt before executing",
1206
+ "allowNo": false
1207
+ },
1208
+ "dry-run": {
1209
+ "name": "dry-run",
1210
+ "type": "boolean",
1211
+ "char": "d",
1212
+ "description": "Run stages 1-4 only (no execution)",
1213
+ "allowNo": false
1214
+ },
1215
+ "stage": {
1216
+ "name": "stage",
1217
+ "type": "option",
1218
+ "char": "s",
1219
+ "description": "Run only up to this stage (1-5)",
1220
+ "multiple": false,
1221
+ "options": [
1222
+ "1",
1223
+ "2",
1224
+ "3",
1225
+ "4",
1226
+ "5"
1227
+ ]
1228
+ }
1229
+ },
1230
+ "args": {
1231
+ "dataFile": {
1232
+ "name": "dataFile",
1233
+ "description": "Path to the CSV data file",
1234
+ "required": true
1235
+ },
1236
+ "configFile": {
1237
+ "name": "configFile",
1238
+ "description": "Path to the YAML or JSON configuration file",
1239
+ "required": true
1240
+ }
1241
+ }
1242
+ },
1158
1243
  "projects:export": {
1159
1244
  "id": "projects:export",
1160
1245
  "description": "Export a project.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.4.4-alpha.e5b7d5d",
3
+ "version": "3.4.5-alpha.18160f5",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",
@@ -30,7 +30,7 @@
30
30
  "@contrail/util"
31
31
  ],
32
32
  "dependencies": {
33
- "@contrail/entity-types": "^1.6.0",
33
+ "@contrail/entity-types": "^1.6.1",
34
34
  "@contrail/loader": "1.0.32",
35
35
  "@contrail/org-config-migration": "^1.1.13",
36
36
  "@contrail/sdk": "^1.5.5",
@@ -45,6 +45,7 @@
45
45
  "aws-sdk": "^2.1044.0",
46
46
  "axios": "^1.3.5",
47
47
  "chalk": "^4.0.0",
48
+ "cli-table3": "^0.6.5",
48
49
  "command-line-usage": "^6.1.1",
49
50
  "csv-parse": "^5.5.5",
50
51
  "csvtojson": "^2.0.10",
@@ -99,6 +100,10 @@
99
100
  "load": {
100
101
  "description": "Load data to VibeIQ from local CSV files"
101
102
  },
103
+ "load-local": {
104
+ "description": "Run the full data loading pipeline locally with staged feedback",
105
+ "hidden": true
106
+ },
102
107
  "types": {
103
108
  "description": "Export, manage, and import types"
104
109
  },