@git.zone/cli 2.13.10 → 2.13.12

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 (105) hide show
  1. package/assets/templates/{npmextra/npmextra.json → smartconfig/_smartconfig.json} +3 -0
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/classes.gitzoneconfig.js +4 -4
  4. package/dist_ts/gitzone.cli.js +1 -15
  5. package/dist_ts/mod_commit/index.js +4 -4
  6. package/dist_ts/mod_config/classes.commitconfig.d.ts +3 -3
  7. package/dist_ts/mod_config/classes.commitconfig.js +20 -20
  8. package/dist_ts/mod_config/classes.releaseconfig.d.ts +3 -3
  9. package/dist_ts/mod_config/classes.releaseconfig.js +21 -21
  10. package/dist_ts/mod_config/index.js +12 -12
  11. package/dist_ts/mod_format/classes.baseformatter.d.ts +2 -9
  12. package/dist_ts/mod_format/classes.baseformatter.js +13 -26
  13. package/dist_ts/mod_format/classes.formatplanner.d.ts +1 -3
  14. package/dist_ts/mod_format/classes.formatplanner.js +11 -39
  15. package/dist_ts/mod_format/classes.formatstats.d.ts +0 -5
  16. package/dist_ts/mod_format/classes.formatstats.js +3 -35
  17. package/dist_ts/mod_format/formatters/cleanup.formatter.js +1 -2
  18. package/dist_ts/mod_format/formatters/copy.formatter.js +5 -8
  19. package/dist_ts/mod_format/formatters/gitignore.formatter.d.ts +5 -0
  20. package/dist_ts/mod_format/formatters/gitignore.formatter.js +23 -29
  21. package/dist_ts/mod_format/formatters/packagejson.formatter.js +5 -5
  22. package/dist_ts/mod_format/formatters/prettier.formatter.js +4 -12
  23. package/dist_ts/mod_format/formatters/{npmextra.formatter.d.ts → smartconfig.formatter.d.ts} +6 -1
  24. package/dist_ts/mod_format/formatters/smartconfig.formatter.js +180 -0
  25. package/dist_ts/mod_format/formatters/templates.formatter.d.ts +4 -0
  26. package/dist_ts/mod_format/formatters/templates.formatter.js +50 -43
  27. package/dist_ts/mod_format/formatters/tsconfig.formatter.js +6 -4
  28. package/dist_ts/mod_format/index.d.ts +0 -4
  29. package/dist_ts/mod_format/index.js +27 -78
  30. package/dist_ts/mod_format/interfaces.format.d.ts +1 -18
  31. package/dist_ts/mod_format/interfaces.format.js +16 -2
  32. package/dist_ts/mod_format/mod.plugins.d.ts +3 -7
  33. package/dist_ts/mod_format/mod.plugins.js +4 -8
  34. package/dist_ts/mod_services/classes.globalregistry.js +2 -2
  35. package/dist_ts/mod_services/classes.servicemanager.d.ts +2 -2
  36. package/dist_ts/mod_services/classes.servicemanager.js +21 -21
  37. package/dist_ts/plugins.d.ts +2 -2
  38. package/dist_ts/plugins.js +3 -3
  39. package/package.json +5 -11
  40. package/ts/00_commitinfo_data.ts +1 -1
  41. package/ts/classes.gitzoneconfig.ts +3 -3
  42. package/ts/gitzone.cli.ts +0 -17
  43. package/ts/mod_commit/index.ts +3 -3
  44. package/ts/mod_config/classes.commitconfig.ts +19 -19
  45. package/ts/mod_config/classes.releaseconfig.ts +20 -20
  46. package/ts/mod_config/index.ts +11 -11
  47. package/ts/mod_format/classes.baseformatter.ts +14 -25
  48. package/ts/mod_format/classes.formatplanner.ts +10 -39
  49. package/ts/mod_format/classes.formatstats.ts +2 -42
  50. package/ts/mod_format/formatters/cleanup.formatter.ts +0 -1
  51. package/ts/mod_format/formatters/copy.formatter.ts +4 -8
  52. package/ts/mod_format/formatters/gitignore.formatter.ts +25 -29
  53. package/ts/mod_format/formatters/packagejson.formatter.ts +4 -4
  54. package/ts/mod_format/formatters/prettier.formatter.ts +3 -13
  55. package/ts/mod_format/formatters/smartconfig.formatter.ts +213 -0
  56. package/ts/mod_format/formatters/templates.formatter.ts +55 -43
  57. package/ts/mod_format/formatters/tsconfig.formatter.ts +6 -3
  58. package/ts/mod_format/index.ts +35 -98
  59. package/ts/mod_format/interfaces.format.ts +16 -19
  60. package/ts/mod_format/mod.plugins.ts +4 -12
  61. package/ts/mod_services/classes.globalregistry.ts +2 -2
  62. package/ts/mod_services/classes.servicemanager.ts +20 -20
  63. package/ts/plugins.ts +2 -2
  64. package/dist_ts/mod_format/classes.changecache.d.ts +0 -26
  65. package/dist_ts/mod_format/classes.changecache.js +0 -181
  66. package/dist_ts/mod_format/classes.dependency-analyzer.d.ts +0 -13
  67. package/dist_ts/mod_format/classes.dependency-analyzer.js +0 -93
  68. package/dist_ts/mod_format/classes.rollbackmanager.d.ts +0 -22
  69. package/dist_ts/mod_format/classes.rollbackmanager.js +0 -259
  70. package/dist_ts/mod_format/format.cleanup.d.ts +0 -2
  71. package/dist_ts/mod_format/format.cleanup.js +0 -25
  72. package/dist_ts/mod_format/format.copy.d.ts +0 -24
  73. package/dist_ts/mod_format/format.copy.js +0 -77
  74. package/dist_ts/mod_format/format.gitignore.d.ts +0 -2
  75. package/dist_ts/mod_format/format.gitignore.js +0 -48
  76. package/dist_ts/mod_format/format.license.d.ts +0 -2
  77. package/dist_ts/mod_format/format.license.js +0 -26
  78. package/dist_ts/mod_format/format.npmextra.d.ts +0 -5
  79. package/dist_ts/mod_format/format.npmextra.js +0 -125
  80. package/dist_ts/mod_format/format.packagejson.d.ts +0 -2
  81. package/dist_ts/mod_format/format.packagejson.js +0 -145
  82. package/dist_ts/mod_format/format.prettier.d.ts +0 -2
  83. package/dist_ts/mod_format/format.prettier.js +0 -56
  84. package/dist_ts/mod_format/format.readme.d.ts +0 -1
  85. package/dist_ts/mod_format/format.readme.js +0 -29
  86. package/dist_ts/mod_format/format.templates.d.ts +0 -5
  87. package/dist_ts/mod_format/format.templates.js +0 -68
  88. package/dist_ts/mod_format/format.tsconfig.d.ts +0 -2
  89. package/dist_ts/mod_format/format.tsconfig.js +0 -28
  90. package/dist_ts/mod_format/formatters/npmextra.formatter.js +0 -142
  91. package/ts/mod_format/classes.changecache.ts +0 -235
  92. package/ts/mod_format/classes.dependency-analyzer.ts +0 -117
  93. package/ts/mod_format/classes.rollbackmanager.ts +0 -340
  94. package/ts/mod_format/format.cleanup.ts +0 -26
  95. package/ts/mod_format/format.copy.ts +0 -93
  96. package/ts/mod_format/format.gitignore.ts +0 -54
  97. package/ts/mod_format/format.license.ts +0 -32
  98. package/ts/mod_format/format.npmextra.ts +0 -151
  99. package/ts/mod_format/format.packagejson.ts +0 -196
  100. package/ts/mod_format/format.prettier.ts +0 -66
  101. package/ts/mod_format/format.readme.ts +0 -29
  102. package/ts/mod_format/format.templates.ts +0 -79
  103. package/ts/mod_format/format.tsconfig.ts +0 -31
  104. package/ts/mod_format/formatters/npmextra.formatter.ts +0 -174
  105. /package/{npmextra.json → .smartconfig.json} +0 -0
@@ -8,23 +8,23 @@ import { runFormatter, type ICheckResult } from '../mod_format/index.js';
8
8
  export { ReleaseConfig, CommitConfig };
9
9
 
10
10
  /**
11
- * Format npmextra.json with diff preview
11
+ * Format .smartconfig.json with diff preview
12
12
  * Shows diff first, asks for confirmation, then applies
13
13
  */
14
- async function formatNpmextraWithDiff(): Promise<void> {
14
+ async function formatSmartconfigWithDiff(): Promise<void> {
15
15
  // Check for diffs first
16
- const checkResult = await runFormatter('npmextra', {
16
+ const checkResult = await runFormatter('smartconfig', {
17
17
  checkOnly: true,
18
18
  showDiff: true,
19
19
  }) as ICheckResult | void;
20
20
 
21
21
  if (checkResult && checkResult.hasDiff) {
22
22
  const shouldApply = await plugins.smartinteract.SmartInteract.getCliConfirmation(
23
- 'Apply formatting changes to npmextra.json?',
23
+ 'Apply formatting changes to .smartconfig.json?',
24
24
  true
25
25
  );
26
26
  if (shouldApply) {
27
- await runFormatter('npmextra', { silent: true });
27
+ await runFormatter('smartconfig', { silent: true });
28
28
  }
29
29
  }
30
30
  }
@@ -187,7 +187,7 @@ async function handleAdd(url?: string): Promise<void> {
187
187
  if (added) {
188
188
  await config.save();
189
189
  plugins.logger.log('success', `Added registry: ${url}`);
190
- await formatNpmextraWithDiff();
190
+ await formatSmartconfigWithDiff();
191
191
  } else {
192
192
  plugins.logger.log('warn', `Registry already exists: ${url}`);
193
193
  }
@@ -223,7 +223,7 @@ async function handleRemove(url?: string): Promise<void> {
223
223
  if (removed) {
224
224
  await config.save();
225
225
  plugins.logger.log('success', `Removed registry: ${url}`);
226
- await formatNpmextraWithDiff();
226
+ await formatSmartconfigWithDiff();
227
227
  } else {
228
228
  plugins.logger.log('warn', `Registry not found: ${url}`);
229
229
  }
@@ -250,7 +250,7 @@ async function handleClear(): Promise<void> {
250
250
  config.clearRegistries();
251
251
  await config.save();
252
252
  plugins.logger.log('success', 'All registries cleared.');
253
- await formatNpmextraWithDiff();
253
+ await formatSmartconfigWithDiff();
254
254
  } else {
255
255
  plugins.logger.log('info', 'Operation cancelled.');
256
256
  }
@@ -290,7 +290,7 @@ async function handleAccessLevel(level?: string): Promise<void> {
290
290
  config.setAccessLevel(level as 'public' | 'private');
291
291
  await config.save();
292
292
  plugins.logger.log('success', `Access level set to: ${level}`);
293
- await formatNpmextraWithDiff();
293
+ await formatSmartconfigWithDiff();
294
294
  }
295
295
 
296
296
  /**
@@ -350,7 +350,7 @@ async function handleCommitInteractive(config: CommitConfig): Promise<void> {
350
350
  await config.save();
351
351
 
352
352
  plugins.logger.log('success', 'Commit configuration updated');
353
- await formatNpmextraWithDiff();
353
+ await formatSmartconfigWithDiff();
354
354
  }
355
355
 
356
356
  /**
@@ -368,7 +368,7 @@ async function handleCommitSetting(config: CommitConfig, setting: string, value?
368
368
 
369
369
  await config.save();
370
370
  plugins.logger.log('success', `Set ${setting} to ${boolValue}`);
371
- await formatNpmextraWithDiff();
371
+ await formatSmartconfigWithDiff();
372
372
  }
373
373
 
374
374
  /**
@@ -2,11 +2,12 @@ import * as plugins from './mod.plugins.js';
2
2
  import { FormatContext } from './classes.formatcontext.js';
3
3
  import type { IPlannedChange, ICheckResult } from './interfaces.format.js';
4
4
  import { Project } from '../classes.project.js';
5
+ import { FormatStats } from './classes.formatstats.js';
5
6
 
6
7
  export abstract class BaseFormatter {
7
8
  protected context: FormatContext;
8
9
  protected project: Project;
9
- protected stats: any; // Will be FormatStats from context
10
+ protected stats: FormatStats;
10
11
 
11
12
  constructor(context: FormatContext, project: Project) {
12
13
  this.context = context;
@@ -36,9 +37,6 @@ export abstract class BaseFormatter {
36
37
  }
37
38
 
38
39
  await this.postExecute();
39
- } catch (error) {
40
- // Don't rollback here - let the FormatPlanner handle it
41
- throw error;
42
40
  } finally {
43
41
  this.stats.endModule(this.name, startTime);
44
42
  }
@@ -53,13 +51,10 @@ export abstract class BaseFormatter {
53
51
  }
54
52
 
55
53
  protected async modifyFile(filepath: string, content: string): Promise<void> {
56
- // Validate filepath before writing
57
54
  if (!filepath || filepath.trim() === '') {
58
55
  throw new Error(`Invalid empty filepath in modifyFile`);
59
56
  }
60
57
 
61
- // Ensure we have a proper path with directory component
62
- // If the path has no directory component (e.g., "package.json"), prepend "./"
63
58
  let normalizedPath = filepath;
64
59
  if (!plugins.path.parse(filepath).dir) {
65
60
  normalizedPath = './' + filepath;
@@ -69,44 +64,46 @@ export abstract class BaseFormatter {
69
64
  }
70
65
 
71
66
  protected async createFile(filepath: string, content: string): Promise<void> {
72
- await plugins.smartfs.file(filepath).encoding('utf8').write(content);
67
+ let normalizedPath = filepath;
68
+ if (!plugins.path.parse(filepath).dir) {
69
+ normalizedPath = './' + filepath;
70
+ }
71
+
72
+ // Ensure parent directory exists
73
+ const dir = plugins.path.dirname(normalizedPath);
74
+ if (dir && dir !== '.') {
75
+ await plugins.smartfs.directory(dir).recursive().create();
76
+ }
77
+
78
+ await plugins.smartfs.file(normalizedPath).encoding('utf8').write(content);
73
79
  }
74
80
 
75
81
  protected async deleteFile(filepath: string): Promise<void> {
76
82
  await plugins.smartfs.file(filepath).delete();
77
83
  }
78
84
 
79
- protected async shouldProcessFile(filepath: string): Promise<boolean> {
80
- return true;
81
- }
82
-
83
85
  /**
84
86
  * Check for diffs without applying changes
85
- * Returns information about what would change
86
87
  */
87
88
  async check(): Promise<ICheckResult> {
88
89
  const changes = await this.analyze();
89
90
  const diffs: ICheckResult['diffs'] = [];
90
91
 
91
92
  for (const change of changes) {
92
- // Skip generic changes that don't have actual content
93
93
  if (change.path === '<various files>') {
94
94
  continue;
95
95
  }
96
96
 
97
97
  if (change.type === 'modify' || change.type === 'create') {
98
- // Read current content if file exists
99
98
  let currentContent: string | undefined;
100
99
  try {
101
100
  currentContent = await plugins.smartfs.file(change.path).encoding('utf8').read() as string;
102
101
  } catch {
103
- // File doesn't exist yet
104
102
  currentContent = undefined;
105
103
  }
106
104
 
107
105
  const newContent = change.content;
108
106
 
109
- // Check if there's an actual diff
110
107
  if (currentContent !== newContent && newContent !== undefined) {
111
108
  diffs.push({
112
109
  path: change.path,
@@ -116,7 +113,6 @@ export abstract class BaseFormatter {
116
113
  });
117
114
  }
118
115
  } else if (change.type === 'delete') {
119
- // Check if file exists before marking for deletion
120
116
  try {
121
117
  const currentContent = await plugins.smartfs.file(change.path).encoding('utf8').read() as string;
122
118
  diffs.push({
@@ -137,9 +133,6 @@ export abstract class BaseFormatter {
137
133
  };
138
134
  }
139
135
 
140
- /**
141
- * Display a single diff using smartdiff
142
- */
143
136
  displayDiff(diff: ICheckResult['diffs'][0]): void {
144
137
  console.log(`\n--- ${diff.path}`);
145
138
  if (diff.before && diff.after) {
@@ -150,7 +143,6 @@ export abstract class BaseFormatter {
150
143
  }));
151
144
  } else if (diff.after && !diff.before) {
152
145
  console.log(' (new file)');
153
- // Show first few lines of new content
154
146
  const lines = diff.after.split('\n').slice(0, 10);
155
147
  lines.forEach(line => console.log(` + ${line}`));
156
148
  if (diff.after.split('\n').length > 10) {
@@ -161,9 +153,6 @@ export abstract class BaseFormatter {
161
153
  }
162
154
  }
163
155
 
164
- /**
165
- * Display all diffs from a check result
166
- */
167
156
  displayAllDiffs(result: ICheckResult): void {
168
157
  if (!result.hasDiff) {
169
158
  console.log(' No changes detected');
@@ -2,13 +2,12 @@ import * as plugins from './mod.plugins.js';
2
2
  import { FormatContext } from './classes.formatcontext.js';
3
3
  import { BaseFormatter } from './classes.baseformatter.js';
4
4
  import type { IFormatPlan, IPlannedChange } from './interfaces.format.js';
5
+ import { getModuleIcon } from './interfaces.format.js';
5
6
  import { logger } from '../gitzone.logging.js';
6
- import { DependencyAnalyzer } from './classes.dependency-analyzer.js';
7
7
  import { DiffReporter } from './classes.diffreporter.js';
8
8
 
9
9
  export class FormatPlanner {
10
10
  private plannedChanges: Map<string, IPlannedChange[]> = new Map();
11
- private dependencyAnalyzer = new DependencyAnalyzer();
12
11
  private diffReporter = new DiffReporter();
13
12
 
14
13
  async planFormat(modules: BaseFormatter[]): Promise<IFormatPlan> {
@@ -18,7 +17,6 @@ export class FormatPlanner {
18
17
  filesAdded: 0,
19
18
  filesModified: 0,
20
19
  filesRemoved: 0,
21
- estimatedTime: 0,
22
20
  },
23
21
  changes: [],
24
22
  warnings: [],
@@ -32,7 +30,6 @@ export class FormatPlanner {
32
30
  for (const change of changes) {
33
31
  plan.changes.push(change);
34
32
 
35
- // Update summary
36
33
  switch (change.type) {
37
34
  case 'create':
38
35
  plan.summary.filesAdded++;
@@ -58,7 +55,6 @@ export class FormatPlanner {
58
55
  plan.summary.filesAdded +
59
56
  plan.summary.filesModified +
60
57
  plan.summary.filesRemoved;
61
- plan.summary.estimatedTime = plan.summary.totalFiles * 100; // 100ms per file estimate
62
58
 
63
59
  return plan;
64
60
  }
@@ -67,27 +63,20 @@ export class FormatPlanner {
67
63
  plan: IFormatPlan,
68
64
  modules: BaseFormatter[],
69
65
  context: FormatContext,
70
- parallel: boolean = false,
71
66
  ): Promise<void> {
72
67
  const startTime = Date.now();
73
68
 
74
- try {
75
- // Always use sequential execution to avoid race conditions
76
- for (const module of modules) {
77
- const changes = this.plannedChanges.get(module.name) || [];
69
+ for (const module of modules) {
70
+ const changes = this.plannedChanges.get(module.name) || [];
78
71
 
79
- if (changes.length > 0) {
80
- logger.log('info', `Executing ${module.name} formatter...`);
81
- await module.execute(changes);
82
- }
72
+ if (changes.length > 0) {
73
+ logger.log('info', `Executing ${module.name} formatter...`);
74
+ await module.execute(changes);
83
75
  }
84
-
85
- const endTime = Date.now();
86
- const duration = endTime - startTime;
87
- logger.log('info', `Format operations completed in ${duration}ms`);
88
- } catch (error) {
89
- throw error;
90
76
  }
77
+
78
+ const duration = Date.now() - startTime;
79
+ logger.log('info', `Format operations completed in ${duration}ms`);
91
80
  }
92
81
 
93
82
  async displayPlan(
@@ -103,7 +92,6 @@ export class FormatPlanner {
103
92
  console.log('');
104
93
  console.log('Changes by module:');
105
94
 
106
- // Group changes by module
107
95
  const changesByModule = new Map<string, IPlannedChange[]>();
108
96
  for (const change of plan.changes) {
109
97
  const moduleChanges = changesByModule.get(change.module) || [];
@@ -113,14 +101,13 @@ export class FormatPlanner {
113
101
 
114
102
  for (const [module, changes] of changesByModule) {
115
103
  console.log(
116
- `\n${this.getModuleIcon(module)} ${module} (${changes.length} ${changes.length === 1 ? 'file' : 'files'})`,
104
+ `\n${getModuleIcon(module)} ${module} (${changes.length} ${changes.length === 1 ? 'file' : 'files'})`,
117
105
  );
118
106
 
119
107
  for (const change of changes) {
120
108
  const icon = this.getChangeIcon(change.type);
121
109
  console.log(` ${icon} ${change.path} - ${change.description}`);
122
110
 
123
- // Show diff for modified files if detailed view is requested
124
111
  if (detailed && change.type === 'modify') {
125
112
  const diff = await this.diffReporter.generateDiffForChange(change);
126
113
  if (diff) {
@@ -141,22 +128,6 @@ export class FormatPlanner {
141
128
  console.log('\n' + '━'.repeat(50));
142
129
  }
143
130
 
144
- private getModuleIcon(module: string): string {
145
- const icons: Record<string, string> = {
146
- packagejson: '📦',
147
- license: '📝',
148
- tsconfig: '🔧',
149
- cleanup: '🚮',
150
- gitignore: '🔒',
151
- prettier: '✨',
152
- readme: '📖',
153
- templates: '📄',
154
- npmextra: '⚙️',
155
- copy: '📋',
156
- };
157
- return icons[module] || '📁';
158
- }
159
-
160
131
  private getChangeIcon(type: 'create' | 'modify' | 'delete'): string {
161
132
  switch (type) {
162
133
  case 'create':
@@ -1,5 +1,6 @@
1
1
  import * as plugins from './mod.plugins.js';
2
2
  import { logger } from '../gitzone.logging.js';
3
+ import { getModuleIcon } from './interfaces.format.js';
3
4
 
4
5
  export interface IModuleStats {
5
6
  name: string;
@@ -23,8 +24,6 @@ export interface IFormatStats {
23
24
  totalModified: number;
24
25
  totalDeleted: number;
25
26
  totalErrors: number;
26
- cacheHits: number;
27
- cacheMisses: number;
28
27
  };
29
28
  }
30
29
 
@@ -43,8 +42,6 @@ export class FormatStats {
43
42
  totalModified: 0,
44
43
  totalDeleted: 0,
45
44
  totalErrors: 0,
46
- cacheHits: 0,
47
- cacheMisses: 0,
48
45
  },
49
46
  };
50
47
  }
@@ -107,14 +104,6 @@ export class FormatStats {
107
104
  }
108
105
  }
109
106
 
110
- recordCacheHit(): void {
111
- this.stats.overallStats.cacheHits++;
112
- }
113
-
114
- recordCacheMiss(): void {
115
- this.stats.overallStats.cacheMisses++;
116
- }
117
-
118
107
  finish(): void {
119
108
  this.stats.endTime = Date.now();
120
109
  this.stats.totalExecutionTime = this.stats.endTime - this.stats.startTime;
@@ -135,20 +124,6 @@ export class FormatStats {
135
124
  console.log(` • Deleted: ${this.stats.overallStats.totalDeleted}`);
136
125
  console.log(` Errors: ${this.stats.overallStats.totalErrors}`);
137
126
 
138
- if (
139
- this.stats.overallStats.cacheHits > 0 ||
140
- this.stats.overallStats.cacheMisses > 0
141
- ) {
142
- const cacheHitRate =
143
- (this.stats.overallStats.cacheHits /
144
- (this.stats.overallStats.cacheHits +
145
- this.stats.overallStats.cacheMisses)) *
146
- 100;
147
- console.log(` Cache Hit Rate: ${cacheHitRate.toFixed(1)}%`);
148
- console.log(` • Hits: ${this.stats.overallStats.cacheHits}`);
149
- console.log(` • Misses: ${this.stats.overallStats.cacheMisses}`);
150
- }
151
-
152
127
  // Module stats
153
128
  console.log('\nModule Breakdown:');
154
129
  console.log('─'.repeat(50));
@@ -159,7 +134,7 @@ export class FormatStats {
159
134
 
160
135
  for (const moduleStats of sortedModules) {
161
136
  console.log(
162
- `\n${this.getModuleIcon(moduleStats.name)} ${moduleStats.name}:`,
137
+ `\n${getModuleIcon(moduleStats.name)} ${moduleStats.name}:`,
163
138
  );
164
139
  console.log(
165
140
  ` Execution Time: ${this.formatDuration(moduleStats.executionTime)}`,
@@ -211,19 +186,4 @@ export class FormatStats {
211
186
  }
212
187
  }
213
188
 
214
- private getModuleIcon(module: string): string {
215
- const icons: Record<string, string> = {
216
- packagejson: '📦',
217
- license: '📝',
218
- tsconfig: '🔧',
219
- cleanup: '🚮',
220
- gitignore: '🔒',
221
- prettier: '✨',
222
- readme: '📖',
223
- templates: '📄',
224
- npmextra: '⚙️',
225
- copy: '📋',
226
- };
227
- return icons[module] || '📁';
228
- }
229
189
  }
@@ -1,7 +1,6 @@
1
1
  import { BaseFormatter } from '../classes.baseformatter.js';
2
2
  import type { IPlannedChange } from '../interfaces.format.js';
3
3
  import * as plugins from '../mod.plugins.js';
4
- import * as cleanupFormatter from '../format.cleanup.js';
5
4
 
6
5
  export class CleanupFormatter extends BaseFormatter {
7
6
  get name(): string {
@@ -17,15 +17,15 @@ export class CopyFormatter extends BaseFormatter {
17
17
  async analyze(): Promise<IPlannedChange[]> {
18
18
  const changes: IPlannedChange[] = [];
19
19
 
20
- // Get copy configuration from npmextra.json
21
- const npmextraConfig = new plugins.npmextra.Smartconfig();
22
- const copyConfig = npmextraConfig.dataFor<{ patterns: ICopyPattern[] }>(
20
+ // Get copy configuration from .smartconfig.json
21
+ const smartconfigInstance = new plugins.smartconfig.Smartconfig();
22
+ const copyConfig = smartconfigInstance.dataFor<{ patterns: ICopyPattern[] }>(
23
23
  'gitzone.format.copy',
24
24
  { patterns: [] },
25
25
  );
26
26
 
27
27
  if (!copyConfig.patterns || copyConfig.patterns.length === 0) {
28
- logVerbose('No copy patterns configured in npmextra.json');
28
+ logVerbose('No copy patterns configured in .smartconfig.json');
29
29
  return changes;
30
30
  }
31
31
 
@@ -103,10 +103,6 @@ export class CopyFormatter extends BaseFormatter {
103
103
  async applyChange(change: IPlannedChange): Promise<void> {
104
104
  if (!change.content) return;
105
105
 
106
- // Ensure destination directory exists
107
- const destDir = plugins.path.dirname(change.path);
108
- await plugins.smartfs.directory(destDir).recursive().create();
109
-
110
106
  if (change.type === 'create') {
111
107
  await this.createFile(change.path, change.content);
112
108
  } else {
@@ -1,42 +1,39 @@
1
1
  import { BaseFormatter } from '../classes.baseformatter.js';
2
2
  import type { IPlannedChange } from '../interfaces.format.js';
3
3
  import * as plugins from '../mod.plugins.js';
4
+ import * as paths from '../../paths.js';
4
5
  import { logger } from '../../gitzone.logging.js';
5
6
 
6
- // Standard gitignore template content (without front-matter)
7
- const GITIGNORE_TEMPLATE = `.nogit/
8
-
9
- # artifacts
10
- coverage/
11
- public/
12
-
13
- # installs
14
- node_modules/
15
-
16
- # caches
17
- .yarn/
18
- .cache/
19
- .rpt2_cache
20
-
21
- # builds
22
- dist/
23
- dist_*/
24
-
25
- # AI
26
- .claude/
27
- .serena/
28
-
29
- #------# custom`;
30
-
31
7
  export class GitignoreFormatter extends BaseFormatter {
32
8
  get name(): string {
33
9
  return 'gitignore';
34
10
  }
35
11
 
12
+ /**
13
+ * Read the standard gitignore template from the asset file,
14
+ * stripping the YAML frontmatter.
15
+ */
16
+ private async getStandardTemplate(): Promise<string> {
17
+ const templatePath = plugins.path.join(paths.templatesDir, 'gitignore', '_gitignore');
18
+ const raw = (await plugins.smartfs
19
+ .file(templatePath)
20
+ .encoding('utf8')
21
+ .read()) as string;
22
+
23
+ // Strip YAML frontmatter (---\n...\n---)
24
+ const frontmatterEnd = raw.indexOf('---', 3);
25
+ if (frontmatterEnd !== -1) {
26
+ return raw.slice(frontmatterEnd + 3).trimStart();
27
+ }
28
+ return raw;
29
+ }
30
+
36
31
  async analyze(): Promise<IPlannedChange[]> {
37
32
  const changes: IPlannedChange[] = [];
38
33
  const gitignorePath = '.gitignore';
39
34
 
35
+ const standardTemplate = await this.getStandardTemplate();
36
+
40
37
  // Check if file exists and extract custom content
41
38
  let customContent = '';
42
39
  const exists = await plugins.smartfs.file(gitignorePath).exists();
@@ -59,11 +56,11 @@ export class GitignoreFormatter extends BaseFormatter {
59
56
  }
60
57
 
61
58
  // Compute new content
62
- let newContent = GITIGNORE_TEMPLATE;
59
+ let newContent = standardTemplate;
63
60
  if (customContent) {
64
- newContent = GITIGNORE_TEMPLATE + '\n' + customContent + '\n';
61
+ newContent = standardTemplate + '\n' + customContent + '\n';
65
62
  } else {
66
- newContent = GITIGNORE_TEMPLATE + '\n';
63
+ newContent = standardTemplate + '\n';
67
64
  }
68
65
 
69
66
  // Read current content to compare
@@ -75,7 +72,6 @@ export class GitignoreFormatter extends BaseFormatter {
75
72
  .read()) as string;
76
73
  }
77
74
 
78
- // Determine change type
79
75
  if (!exists) {
80
76
  changes.push({
81
77
  type: 'create',
@@ -100,9 +100,9 @@ export class PackageJsonFormatter extends BaseFormatter {
100
100
  // Parse and compute new content
101
101
  const packageJson = JSON.parse(currentContent);
102
102
 
103
- // Get gitzone config from npmextra
104
- const npmextraConfig = new plugins.npmextra.Smartconfig(paths.cwd);
105
- const gitzoneData: any = npmextraConfig.dataFor('@git.zone/cli', {});
103
+ // Get gitzone config from smartconfig
104
+ const smartconfigInstance = new plugins.smartconfig.Smartconfig(paths.cwd);
105
+ const gitzoneData: any = smartconfigInstance.dataFor('@git.zone/cli', {});
106
106
 
107
107
  // Set metadata from gitzone config
108
108
  if (gitzoneData.module) {
@@ -156,7 +156,7 @@ export class PackageJsonFormatter extends BaseFormatter {
156
156
  'dist_ts_web/**/*',
157
157
  'assets/**/*',
158
158
  'cli.js',
159
- 'smartconfig.json',
159
+ '.smartconfig.json',
160
160
  'readme.md',
161
161
  ];
162
162
 
@@ -21,7 +21,7 @@ export class PrettierFormatter extends BaseFormatter {
21
21
  const rootConfigFiles = [
22
22
  'package.json',
23
23
  'tsconfig.json',
24
- 'smartconfig.json',
24
+ '.smartconfig.json',
25
25
  '.prettierrc',
26
26
  '.prettierrc.json',
27
27
  '.prettierrc.js',
@@ -79,12 +79,9 @@ export class PrettierFormatter extends BaseFormatter {
79
79
  // Remove duplicates
80
80
  const uniqueFiles = [...new Set(allFiles)];
81
81
 
82
- // Get all files that match the pattern
83
- const files = uniqueFiles;
84
-
85
82
  // Ensure we only process actual files (not directories)
86
83
  const validFiles: string[] = [];
87
- for (const file of files) {
84
+ for (const file of uniqueFiles) {
88
85
  try {
89
86
  const stats = await plugins.smartfs.file(file).stat();
90
87
  if (!stats.isDirectory) {
@@ -96,14 +93,7 @@ export class PrettierFormatter extends BaseFormatter {
96
93
  }
97
94
  }
98
95
 
99
- // Check which files need formatting
100
96
  for (const file of validFiles) {
101
- // Skip files that haven't changed
102
- if (!(await this.shouldProcessFile(file))) {
103
- logVerbose(`Skipping ${file} - no changes detected`);
104
- continue;
105
- }
106
-
107
97
  changes.push({
108
98
  type: 'modify',
109
99
  path: file,
@@ -232,7 +222,7 @@ export class PrettierFormatter extends BaseFormatter {
232
222
 
233
223
  private async getPrettierConfig(): Promise<any> {
234
224
  // Try to load prettier config from the project
235
- const prettierConfig = new plugins.npmextra.Smartconfig();
225
+ const prettierConfig = new plugins.smartconfig.Smartconfig();
236
226
  return prettierConfig.dataFor('prettier', {
237
227
  // Default prettier config
238
228
  singleQuote: true,