@gadmin2n/cli 0.0.91 → 0.0.93

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 (36) hide show
  1. package/actions/index.d.ts +1 -1
  2. package/actions/index.js +1 -1
  3. package/actions/self-update.action.d.ts +5 -0
  4. package/actions/self-update.action.js +93 -0
  5. package/actions/update.action.d.ts +2 -0
  6. package/actions/update.action.js +945 -6
  7. package/commands/command.loader.js +2 -2
  8. package/commands/{template.command.d.ts → self-update.command.d.ts} +1 -1
  9. package/commands/self-update.command.js +35 -0
  10. package/commands/update.command.js +25 -8
  11. package/lib/install-manager.d.ts +48 -0
  12. package/lib/install-manager.js +125 -0
  13. package/lib/template-merge/config-loader.d.ts +15 -0
  14. package/lib/template-merge/config-loader.js +38 -0
  15. package/lib/template-merge/env-merger.d.ts +5 -0
  16. package/lib/template-merge/env-merger.js +57 -0
  17. package/lib/template-merge/glob.d.ts +5 -0
  18. package/lib/template-merge/glob.js +78 -0
  19. package/lib/template-merge/index.d.ts +8 -0
  20. package/lib/template-merge/index.js +24 -0
  21. package/lib/template-merge/json-merger.d.ts +5 -0
  22. package/lib/template-merge/json-merger.js +269 -0
  23. package/lib/template-merge/merger.d.ts +30 -0
  24. package/lib/template-merge/merger.js +2 -0
  25. package/lib/template-merge/prisma-merger.d.ts +5 -0
  26. package/lib/template-merge/prisma-merger.js +112 -0
  27. package/lib/template-merge/registry.d.ts +25 -0
  28. package/lib/template-merge/registry.js +42 -0
  29. package/lib/template-merge/ts-module-merger.d.ts +16 -0
  30. package/lib/template-merge/ts-module-merger.js +193 -0
  31. package/lib/version-check.d.ts +39 -0
  32. package/lib/version-check.js +157 -0
  33. package/package.json +2 -2
  34. package/actions/template.action.d.ts +0 -7
  35. package/actions/template.action.js +0 -570
  36. package/commands/template.command.js +0 -42
@@ -1,570 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.TemplateAction = void 0;
13
- const chalk = require("chalk");
14
- const fs = require("fs");
15
- const path = require("path");
16
- const inquirer = require("inquirer");
17
- const child_process_1 = require("child_process");
18
- const abstract_action_1 = require("./abstract.action");
19
- const DEFAULT_EXCLUDES = [
20
- 'node_modules',
21
- '.git',
22
- 'dist',
23
- 'generated',
24
- '.DS_Store',
25
- '.env.local',
26
- 'readme.md'
27
- ];
28
- /**
29
- * Convert a glob pattern to a RegExp.
30
- * Supports: * (any chars except /), ** (any path segments), ? (single char)
31
- */
32
- function globToRegex(pattern) {
33
- let regexStr = '^';
34
- let i = 0;
35
- while (i < pattern.length) {
36
- const c = pattern[i];
37
- if (c === '*') {
38
- if (pattern[i + 1] === '*') {
39
- // ** matches any path segments
40
- if (pattern[i + 2] === '/') {
41
- regexStr += '(?:.+/)?';
42
- i += 3;
43
- }
44
- else {
45
- regexStr += '.*';
46
- i += 2;
47
- }
48
- }
49
- else {
50
- // * matches anything except /
51
- regexStr += '[^/]*';
52
- i++;
53
- }
54
- }
55
- else if (c === '?') {
56
- regexStr += '[^/]';
57
- i++;
58
- }
59
- else if (c === '.' || c === '(' || c === ')' || c === '[' || c === ']' || c === '{' || c === '}' || c === '+' || c === '^' || c === '$' || c === '|' || c === '\\') {
60
- regexStr += '\\' + c;
61
- i++;
62
- }
63
- else {
64
- regexStr += c;
65
- i++;
66
- }
67
- }
68
- regexStr += '$';
69
- return new RegExp(regexStr);
70
- }
71
- function matchesPattern(filePath, pattern) {
72
- // Exact match or directory prefix match
73
- if (filePath === pattern)
74
- return true;
75
- if (filePath.startsWith(pattern + '/'))
76
- return true;
77
- // Check each path segment for exact match (e.g. "node_modules" matches "a/node_modules/b")
78
- const parts = filePath.split('/');
79
- if (!pattern.includes('/') && !pattern.includes('*') && !pattern.includes('?')) {
80
- if (parts.includes(pattern))
81
- return true;
82
- }
83
- // Glob pattern matching
84
- if (pattern.includes('*') || pattern.includes('?')) {
85
- const regex = globToRegex(pattern);
86
- return regex.test(filePath);
87
- }
88
- return false;
89
- }
90
- function loadTemplateConfig() {
91
- const configPaths = [
92
- path.join(process.cwd(), 'server/gadmin-cli.json'),
93
- path.join(process.cwd(), 'gadmin-cli.json'),
94
- ];
95
- let templateName;
96
- let userExcludes = [];
97
- for (const configPath of configPaths) {
98
- if (fs.existsSync(configPath)) {
99
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
100
- templateName = config.template;
101
- if (Array.isArray(config.templateExcludes)) {
102
- userExcludes = config.templateExcludes;
103
- }
104
- break;
105
- }
106
- }
107
- if (!templateName) {
108
- throw new Error('Cannot find "template" field in gadmin-cli.json. ' +
109
- 'Make sure you are in a gadmin2 project root directory.');
110
- }
111
- return {
112
- templateName,
113
- excludes: [...DEFAULT_EXCLUDES, ...userExcludes],
114
- };
115
- }
116
- function shouldExclude(filePath, excludes) {
117
- for (const pattern of excludes) {
118
- if (matchesPattern(filePath, pattern))
119
- return true;
120
- }
121
- return false;
122
- }
123
- function collectFiles(dir, excludes, base = '') {
124
- const results = [];
125
- const entries = fs.readdirSync(path.join(dir, base), { withFileTypes: true });
126
- for (const entry of entries) {
127
- const rel = base ? `${base}/${entry.name}` : entry.name;
128
- if (shouldExclude(rel, excludes))
129
- continue;
130
- if (entry.isDirectory()) {
131
- results.push(...collectFiles(dir, excludes, rel));
132
- }
133
- else if (entry.isFile()) {
134
- results.push(rel);
135
- }
136
- }
137
- return results.sort();
138
- }
139
- function resolveTemplatePath(templateName) {
140
- // Resolve @gadmin2n/schematics package path
141
- // Try multiple locations: project's node_modules, CLI's own node_modules
142
- let schematicsRoot;
143
- const searchPaths = [
144
- process.cwd(),
145
- path.join(process.cwd(), 'server'),
146
- path.resolve(__dirname, '..'), // CLI package root
147
- ];
148
- for (const searchPath of searchPaths) {
149
- try {
150
- const pkgPath = require.resolve('@gadmin2n/schematics/package.json', {
151
- paths: [searchPath],
152
- });
153
- schematicsRoot = path.dirname(pkgPath);
154
- break;
155
- }
156
- catch (_a) {
157
- // continue trying next path
158
- }
159
- }
160
- if (!schematicsRoot) {
161
- throw new Error('Cannot resolve @gadmin2n/schematics package. ' +
162
- 'Make sure it is installed.');
163
- }
164
- // Check dist path first (published package), then src path (yalc/dev link)
165
- // Also try with name variants (gadmin2n → gadmin2) for backward compatibility
166
- const nameVariants = [templateName];
167
- if (templateName.startsWith('gadmin2n-')) {
168
- nameVariants.push(templateName.replace('gadmin2n-', 'gadmin2-'));
169
- }
170
- else if (templateName.startsWith('gadmin2-')) {
171
- nameVariants.push(templateName.replace('gadmin2-', 'gadmin2n-'));
172
- }
173
- for (const name of nameVariants) {
174
- const distPath = path.join(schematicsRoot, 'dist/lib/application/files', name);
175
- const srcPath = path.join(schematicsRoot, 'src/lib/application/files', name);
176
- if (fs.existsSync(distPath))
177
- return distPath;
178
- if (fs.existsSync(srcPath))
179
- return srcPath;
180
- }
181
- throw new Error(`Template directory not found for "${templateName}" in ${schematicsRoot}`);
182
- }
183
- function createUnifiedDiff(filePath, instanceContent, templateContent) {
184
- const instanceLines = instanceContent.split('\n');
185
- const templateLines = templateContent.split('\n');
186
- // Simple line-by-line diff output
187
- const lines = [];
188
- lines.push(chalk.bold(`--- a/${filePath} (instance)`));
189
- lines.push(chalk.bold(`+++ b/${filePath} (template)`));
190
- // Find differing regions using a simple approach
191
- const maxLen = Math.max(instanceLines.length, templateLines.length);
192
- const hunks = [];
193
- let currentHunk = null;
194
- for (let i = 0; i < maxLen; i++) {
195
- const a = i < instanceLines.length ? instanceLines[i] : undefined;
196
- const b = i < templateLines.length ? templateLines[i] : undefined;
197
- if (a !== b) {
198
- if (!currentHunk) {
199
- currentHunk = { start: i, instanceLines: [], templateLines: [] };
200
- }
201
- if (a !== undefined)
202
- currentHunk.instanceLines.push(a);
203
- if (b !== undefined)
204
- currentHunk.templateLines.push(b);
205
- }
206
- else {
207
- if (currentHunk) {
208
- hunks.push(currentHunk);
209
- currentHunk = null;
210
- }
211
- }
212
- }
213
- if (currentHunk)
214
- hunks.push(currentHunk);
215
- // Output hunks with context
216
- for (const hunk of hunks.slice(0, 10)) { // Limit to first 10 hunks
217
- const contextStart = Math.max(0, hunk.start - 2);
218
- lines.push(chalk.cyan(`@@ -${hunk.start + 1},${hunk.instanceLines.length} +${hunk.start + 1},${hunk.templateLines.length} @@`));
219
- // Context before
220
- for (let i = contextStart; i < hunk.start; i++) {
221
- if (i < instanceLines.length) {
222
- lines.push(` ${instanceLines[i]}`);
223
- }
224
- }
225
- // Removed lines (instance)
226
- for (const line of hunk.instanceLines) {
227
- lines.push(chalk.red(`-${line}`));
228
- }
229
- // Added lines (template)
230
- for (const line of hunk.templateLines) {
231
- lines.push(chalk.green(`+${line}`));
232
- }
233
- // Context after
234
- const afterStart = hunk.start + Math.max(hunk.instanceLines.length, hunk.templateLines.length);
235
- for (let i = afterStart; i < Math.min(afterStart + 2, instanceLines.length); i++) {
236
- lines.push(` ${instanceLines[i]}`);
237
- }
238
- }
239
- if (hunks.length > 10) {
240
- lines.push(chalk.yellow(` ... and ${hunks.length - 10} more hunks`));
241
- }
242
- return lines.join('\n');
243
- }
244
- function createConflictContent(instanceContent, templateContent) {
245
- return [
246
- '<<<<<<< INSTANCE',
247
- instanceContent,
248
- '=======',
249
- templateContent,
250
- '>>>>>>> TEMPLATE',
251
- ].join('\n');
252
- }
253
- /**
254
- * Attempt a 3-way merge using git merge-file with an empty base.
255
- * Both instance and template are treated as "additions from nothing".
256
- * Identical sections pass through cleanly; differing sections produce conflicts.
257
- */
258
- function tryAutoMerge(instanceContent, templateContent) {
259
- const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'gadmin-merge-'));
260
- const basePath = path.join(tmpDir, 'base');
261
- const oursPath = path.join(tmpDir, 'ours');
262
- const theirsPath = path.join(tmpDir, 'theirs');
263
- try {
264
- fs.writeFileSync(basePath, '', 'utf-8');
265
- fs.writeFileSync(oursPath, instanceContent, 'utf-8');
266
- fs.writeFileSync(theirsPath, templateContent, 'utf-8');
267
- try {
268
- (0, child_process_1.execSync)(`git merge-file -L "INSTANCE" -L "BASE" -L "TEMPLATE" "${oursPath}" "${basePath}" "${theirsPath}"`, { stdio: 'pipe' });
269
- const merged = fs.readFileSync(oursPath, 'utf-8');
270
- return { merged, hasConflicts: false };
271
- }
272
- catch (err) {
273
- if (err.status > 0) {
274
- const merged = fs.readFileSync(oursPath, 'utf-8');
275
- return { merged, hasConflicts: true };
276
- }
277
- return { merged: createConflictContent(instanceContent, templateContent), hasConflicts: true };
278
- }
279
- }
280
- finally {
281
- fs.rmSync(tmpDir, { recursive: true, force: true });
282
- }
283
- }
284
- class TemplateAction extends abstract_action_1.AbstractAction {
285
- handle(inputs, options) {
286
- var _a;
287
- return __awaiter(this, void 0, void 0, function* () {
288
- const subcommand = (_a = inputs.find((i) => i.name === 'subcommand')) === null || _a === void 0 ? void 0 : _a.value;
289
- if (subcommand === 'diff') {
290
- yield this.handleDiff(options);
291
- }
292
- else if (subcommand === 'update') {
293
- yield this.handleUpdate(options);
294
- }
295
- });
296
- }
297
- handleDiff(options) {
298
- var _a;
299
- return __awaiter(this, void 0, void 0, function* () {
300
- const noContent = (_a = options.find((o) => o.name === 'no-content')) === null || _a === void 0 ? void 0 : _a.value;
301
- let templateDir;
302
- let excludes;
303
- try {
304
- const config = loadTemplateConfig();
305
- templateDir = resolveTemplatePath(config.templateName);
306
- excludes = config.excludes;
307
- }
308
- catch (err) {
309
- console.error(chalk.red(err.message));
310
- process.exit(1);
311
- }
312
- const instanceDir = process.cwd();
313
- console.info(`\n${chalk.gray('Template:')} ${templateDir}`);
314
- console.info(`${chalk.gray('Instance:')} ${instanceDir}\n`);
315
- const templateFiles = collectFiles(templateDir, excludes);
316
- const instanceFiles = collectFiles(instanceDir, excludes);
317
- const templateSet = new Set(templateFiles);
318
- const instanceSet = new Set(instanceFiles);
319
- // Modified: both have, content differs
320
- const modified = [];
321
- // Only in template (would be added on update)
322
- const onlyInTemplate = [];
323
- // Only in instance (instance-specific)
324
- const onlyInInstance = [];
325
- for (const file of templateFiles) {
326
- if (instanceSet.has(file)) {
327
- const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
328
- const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
329
- if (tContent !== iContent) {
330
- modified.push(file);
331
- }
332
- }
333
- else {
334
- onlyInTemplate.push(file);
335
- }
336
- }
337
- for (const file of instanceFiles) {
338
- if (!templateSet.has(file)) {
339
- onlyInInstance.push(file);
340
- }
341
- }
342
- // Summary
343
- console.info(chalk.bold('═══════════════════════════════════════════════════'));
344
- console.info(chalk.bold(' Template Diff Summary'));
345
- console.info(chalk.bold('═══════════════════════════════════════════════════\n'));
346
- if (modified.length > 0) {
347
- console.info(chalk.yellow(`📝 Modified (${modified.length} files)`));
348
- for (const f of modified) {
349
- console.info(` ${f}`);
350
- }
351
- console.info();
352
- }
353
- if (onlyInTemplate.length > 0) {
354
- console.info(chalk.green(`➕ Only in template (${onlyInTemplate.length} files)`));
355
- for (const f of onlyInTemplate) {
356
- console.info(` ${f}`);
357
- }
358
- console.info();
359
- }
360
- if (onlyInInstance.length > 0) {
361
- console.info(chalk.cyan(`📄 Only in instance (${onlyInInstance.length} files)`));
362
- for (const f of onlyInInstance) {
363
- console.info(` ${f}`);
364
- }
365
- console.info();
366
- }
367
- if (modified.length === 0 && onlyInTemplate.length === 0 && onlyInInstance.length === 0) {
368
- console.info(chalk.green('✅ No differences found. Instance matches template.\n'));
369
- return;
370
- }
371
- // Show diff content for modified files
372
- if (!noContent && modified.length > 0) {
373
- console.info(chalk.bold('───────────────────────────────────────────────────'));
374
- console.info(chalk.bold(' File Diffs (instance vs template)'));
375
- console.info(chalk.bold('───────────────────────────────────────────────────\n'));
376
- for (const file of modified) {
377
- const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
378
- const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
379
- const diff = createUnifiedDiff(file, iContent, tContent);
380
- console.info(diff);
381
- console.info();
382
- }
383
- }
384
- });
385
- }
386
- handleUpdate(options) {
387
- var _a, _b;
388
- return __awaiter(this, void 0, void 0, function* () {
389
- const dryRun = (_a = options.find((o) => o.name === 'dry-run')) === null || _a === void 0 ? void 0 : _a.value;
390
- const autoYes = (_b = options.find((o) => o.name === 'yes')) === null || _b === void 0 ? void 0 : _b.value;
391
- let templateDir;
392
- let excludes;
393
- try {
394
- const config = loadTemplateConfig();
395
- templateDir = resolveTemplatePath(config.templateName);
396
- excludes = config.excludes;
397
- }
398
- catch (err) {
399
- console.error(chalk.red(err.message));
400
- process.exit(1);
401
- }
402
- const instanceDir = process.cwd();
403
- console.info(`\n${chalk.gray('Template:')} ${templateDir}`);
404
- console.info(`${chalk.gray('Instance:')} ${instanceDir}\n`);
405
- const templateFiles = collectFiles(templateDir, excludes);
406
- const instanceFiles = collectFiles(instanceDir, excludes);
407
- const instanceSet = new Set(instanceFiles);
408
- // Categorize changes (template → instance direction)
409
- const toUpdate = []; // exists in both, content differs
410
- const toAdd = []; // only in template
411
- for (const file of templateFiles) {
412
- if (instanceSet.has(file)) {
413
- const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
414
- const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
415
- if (tContent !== iContent) {
416
- toUpdate.push(file);
417
- }
418
- }
419
- else {
420
- toAdd.push(file);
421
- }
422
- }
423
- if (toUpdate.length === 0 && toAdd.length === 0) {
424
- console.info(chalk.green('✅ Instance is up to date with template.\n'));
425
- return;
426
- }
427
- // Summary
428
- console.info(chalk.bold('═══════════════════════════════════════════════════'));
429
- console.info(chalk.bold(' Template Update Summary'));
430
- console.info(chalk.bold('═══════════════════════════════════════════════════\n'));
431
- if (toUpdate.length > 0) {
432
- console.info(chalk.yellow(`📝 To update (${toUpdate.length} files)`));
433
- for (const f of toUpdate) {
434
- console.info(` ${f}`);
435
- }
436
- console.info();
437
- }
438
- if (toAdd.length > 0) {
439
- console.info(chalk.green(`➕ To add (${toAdd.length} files)`));
440
- for (const f of toAdd) {
441
- console.info(` ${f}`);
442
- }
443
- console.info();
444
- }
445
- console.info(chalk.gray('───────────────────────────────────────────────────'));
446
- console.info(chalk.gray(` Total: ${toUpdate.length} update | ${toAdd.length} add`));
447
- console.info(chalk.gray('───────────────────────────────────────────────────\n'));
448
- if (dryRun) {
449
- console.info(chalk.gray('(dry-run mode, no changes made)\n'));
450
- return;
451
- }
452
- // Confirm proceed
453
- if (!autoYes) {
454
- const { confirm } = yield inquirer.prompt([
455
- {
456
- type: 'confirm',
457
- name: 'confirm',
458
- message: 'Proceed with update?',
459
- default: false,
460
- },
461
- ]);
462
- if (!confirm) {
463
- console.info('Cancelled.\n');
464
- return;
465
- }
466
- }
467
- // Process modified files — per-file strategy selection
468
- let skippedCount = 0;
469
- let overwrittenCount = 0;
470
- let mergedCount = 0;
471
- let conflictCount = 0;
472
- // Track "apply to all" choice
473
- let applyAll = null;
474
- for (let i = 0; i < toUpdate.length; i++) {
475
- const file = toUpdate[i];
476
- const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
477
- const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
478
- let strategy = applyAll;
479
- if (!strategy && !autoYes) {
480
- // Show brief diff summary
481
- const diff = createUnifiedDiff(file, iContent, tContent);
482
- console.info(`\n${chalk.bold(`[${i + 1}/${toUpdate.length}]`)} ${chalk.yellow(file)}`);
483
- console.info(diff);
484
- console.info();
485
- const { action } = yield inquirer.prompt([
486
- {
487
- type: 'list',
488
- name: 'action',
489
- message: `How to handle ${file}?`,
490
- choices: [
491
- { name: 'Skip — keep instance as-is', value: 'skip', short: 'skip' },
492
- { name: 'Overwrite — use template version', value: 'overwrite', short: 'overwrite' },
493
- { name: 'Auto merge — attempt git merge', value: 'merge', short: 'merge' },
494
- { name: 'Conflict markers — write both versions for manual resolve', value: 'conflict', short: 'conflict' },
495
- new inquirer.Separator(),
496
- { name: 'Skip ALL remaining', value: 'skip-all', short: 'skip all' },
497
- { name: 'Overwrite ALL remaining', value: 'overwrite-all', short: 'overwrite all' },
498
- { name: 'Conflict markers ALL remaining', value: 'conflict-all', short: 'conflict all' },
499
- ],
500
- },
501
- ]);
502
- if (action.endsWith('-all')) {
503
- applyAll = action.replace('-all', '');
504
- strategy = applyAll;
505
- }
506
- else {
507
- strategy = action;
508
- }
509
- }
510
- else if (autoYes) {
511
- strategy = 'conflict';
512
- }
513
- // Execute strategy
514
- const destPath = path.join(instanceDir, file);
515
- switch (strategy) {
516
- case 'skip':
517
- skippedCount++;
518
- break;
519
- case 'overwrite':
520
- fs.writeFileSync(destPath, tContent, 'utf-8');
521
- overwrittenCount++;
522
- break;
523
- case 'merge': {
524
- const result = tryAutoMerge(iContent, tContent);
525
- fs.writeFileSync(destPath, result.merged, 'utf-8');
526
- if (result.hasConflicts) {
527
- conflictCount++;
528
- console.info(chalk.yellow(` ⚠️ ${file} — merge has conflicts`));
529
- }
530
- else {
531
- mergedCount++;
532
- console.info(chalk.green(` ✓ ${file} — merged cleanly`));
533
- }
534
- break;
535
- }
536
- case 'conflict':
537
- default:
538
- fs.writeFileSync(destPath, createConflictContent(iContent, tContent), 'utf-8');
539
- conflictCount++;
540
- break;
541
- }
542
- }
543
- // Process new files (always add)
544
- for (const file of toAdd) {
545
- const destPath = path.join(instanceDir, file);
546
- fs.mkdirSync(path.dirname(destPath), { recursive: true });
547
- fs.copyFileSync(path.join(templateDir, file), destPath);
548
- }
549
- // Final summary
550
- console.info(chalk.bold('\n✅ Update complete!\n'));
551
- const stats = [];
552
- if (overwrittenCount > 0)
553
- stats.push(`${overwrittenCount} overwritten`);
554
- if (mergedCount > 0)
555
- stats.push(`${mergedCount} merged`);
556
- if (conflictCount > 0)
557
- stats.push(`${conflictCount} with conflicts`);
558
- if (skippedCount > 0)
559
- stats.push(`${skippedCount} skipped`);
560
- if (toAdd.length > 0)
561
- stats.push(`${toAdd.length} added`);
562
- console.info(` ${stats.join(' | ')}\n`);
563
- if (conflictCount > 0) {
564
- console.info(chalk.yellow(`⚠️ ${conflictCount} files have conflict markers. ` +
565
- `Search for "<<<<<<< INSTANCE" to resolve them.\n`));
566
- }
567
- });
568
- }
569
- }
570
- exports.TemplateAction = TemplateAction;
@@ -1,42 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.TemplateCommand = void 0;
13
- const abstract_command_1 = require("./abstract.command");
14
- class TemplateCommand extends abstract_command_1.AbstractCommand {
15
- load(program) {
16
- program
17
- .command('template <subcommand>')
18
- .alias('tpl')
19
- .description('Compare or sync with the project template.\n\n' +
20
- ' Subcommands:\n' +
21
- ' diff Show differences between instance and template\n' +
22
- ' update Pull updates from template into instance\n\n' +
23
- ' Update strategies (per-file interactive prompt):\n' +
24
- ' skip Keep instance file as-is\n' +
25
- ' overwrite Replace with template version\n' +
26
- ' merge Attempt auto merge via git merge-file\n' +
27
- ' conflict Write conflict markers for manual resolve\n')
28
- .option('--no-content', '[diff] Only show file list, skip inline diff content.')
29
- .option('-d, --dry-run', '[update] Show what would be updated without making changes.')
30
- .option('-y, --yes', '[update] Skip per-file prompt, use conflict markers for all.')
31
- .action((subcommand, command) => __awaiter(this, void 0, void 0, function* () {
32
- const inputs = [];
33
- inputs.push({ name: 'subcommand', value: subcommand });
34
- const options = [];
35
- options.push({ name: 'no-content', value: !command.content });
36
- options.push({ name: 'dry-run', value: !!command.dryRun });
37
- options.push({ name: 'yes', value: !!command.yes });
38
- yield this.action.handle(inputs, options);
39
- }));
40
- }
41
- }
42
- exports.TemplateCommand = TemplateCommand;