k0ntext 3.3.1 → 3.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 +225 -26
- package/dist/agents/cleanup-agent.d.ts.map +1 -1
- package/dist/agents/cleanup-agent.js +18 -6
- package/dist/agents/cleanup-agent.js.map +1 -1
- package/dist/agents/drift-agent.d.ts +7 -0
- package/dist/agents/drift-agent.d.ts.map +1 -1
- package/dist/agents/drift-agent.js +29 -8
- package/dist/agents/drift-agent.js.map +1 -1
- package/dist/cli/commands/cleanup.d.ts.map +1 -1
- package/dist/cli/commands/cleanup.js +8 -1
- package/dist/cli/commands/cleanup.js.map +1 -1
- package/dist/cli/commands/drift-detect.d.ts.map +1 -1
- package/dist/cli/commands/drift-detect.js +21 -1
- package/dist/cli/commands/drift-detect.js.map +1 -1
- package/dist/cli/commands/embeddings-refresh.d.ts +11 -0
- package/dist/cli/commands/embeddings-refresh.d.ts.map +1 -0
- package/dist/cli/commands/embeddings-refresh.js +114 -0
- package/dist/cli/commands/embeddings-refresh.js.map +1 -0
- package/dist/cli/commands/migrate.d.ts +11 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +195 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/restore.d.ts +12 -0
- package/dist/cli/commands/restore.d.ts.map +1 -0
- package/dist/cli/commands/restore.js +261 -0
- package/dist/cli/commands/restore.js.map +1 -0
- package/dist/cli/commands/sync-templates.d.ts +15 -0
- package/dist/cli/commands/sync-templates.d.ts.map +1 -0
- package/dist/cli/commands/sync-templates.js +181 -0
- package/dist/cli/commands/sync-templates.js.map +1 -0
- package/dist/cli/commands/version-check.d.ts +12 -0
- package/dist/cli/commands/version-check.d.ts.map +1 -0
- package/dist/cli/commands/version-check.js +133 -0
- package/dist/cli/commands/version-check.js.map +1 -0
- package/dist/cli/generate.d.ts +5 -0
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +80 -16
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/index.js +215 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/repl/index.d.ts +1 -0
- package/dist/cli/repl/index.d.ts.map +1 -1
- package/dist/cli/repl/index.js +18 -6
- package/dist/cli/repl/index.js.map +1 -1
- package/dist/cli/utils/backup-manager.d.ts +94 -0
- package/dist/cli/utils/backup-manager.d.ts.map +1 -0
- package/dist/cli/utils/backup-manager.js +230 -0
- package/dist/cli/utils/backup-manager.js.map +1 -0
- package/dist/cli/utils/db-backup-manager.d.ts +55 -0
- package/dist/cli/utils/db-backup-manager.d.ts.map +1 -0
- package/dist/cli/utils/db-backup-manager.js +115 -0
- package/dist/cli/utils/db-backup-manager.js.map +1 -0
- package/dist/cli/utils/file-detector.d.ts +87 -0
- package/dist/cli/utils/file-detector.d.ts.map +1 -0
- package/dist/cli/utils/file-detector.js +131 -0
- package/dist/cli/utils/file-detector.js.map +1 -0
- package/dist/cli/utils/index.d.ts +9 -0
- package/dist/cli/utils/index.d.ts.map +1 -0
- package/dist/cli/utils/index.js +9 -0
- package/dist/cli/utils/index.js.map +1 -0
- package/dist/cli/utils/modification-prompt.d.ts +41 -0
- package/dist/cli/utils/modification-prompt.d.ts.map +1 -0
- package/dist/cli/utils/modification-prompt.js +84 -0
- package/dist/cli/utils/modification-prompt.js.map +1 -0
- package/dist/cli/version/checker.d.ts +47 -0
- package/dist/cli/version/checker.d.ts.map +1 -0
- package/dist/cli/version/checker.js +143 -0
- package/dist/cli/version/checker.js.map +1 -0
- package/dist/cli/version/comparator.d.ts +46 -0
- package/dist/cli/version/comparator.d.ts.map +1 -0
- package/dist/cli/version/comparator.js +99 -0
- package/dist/cli/version/comparator.js.map +1 -0
- package/dist/cli/version/index.d.ts +11 -0
- package/dist/cli/version/index.d.ts.map +1 -0
- package/dist/cli/version/index.js +11 -0
- package/dist/cli/version/index.js.map +1 -0
- package/dist/cli/version/parser.d.ts +38 -0
- package/dist/cli/version/parser.d.ts.map +1 -0
- package/dist/cli/version/parser.js +90 -0
- package/dist/cli/version/parser.js.map +1 -0
- package/dist/cli/version/prompt.d.ts +40 -0
- package/dist/cli/version/prompt.d.ts.map +1 -0
- package/dist/cli/version/prompt.js +162 -0
- package/dist/cli/version/prompt.js.map +1 -0
- package/dist/cli/version/types.d.ts +89 -0
- package/dist/cli/version/types.d.ts.map +1 -0
- package/dist/cli/version/types.js +7 -0
- package/dist/cli/version/types.js.map +1 -0
- package/dist/db/client.d.ts +79 -4
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +207 -12
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrations/files/0014_add_schema_migrations_table.d.ts +14 -0
- package/dist/db/migrations/files/0014_add_schema_migrations_table.d.ts.map +1 -0
- package/dist/db/migrations/files/0014_add_schema_migrations_table.js +25 -0
- package/dist/db/migrations/files/0014_add_schema_migrations_table.js.map +1 -0
- package/dist/db/migrations/index.d.ts +9 -0
- package/dist/db/migrations/index.d.ts.map +1 -0
- package/dist/db/migrations/index.js +9 -0
- package/dist/db/migrations/index.js.map +1 -0
- package/dist/db/migrations/loader.d.ts +27 -0
- package/dist/db/migrations/loader.d.ts.map +1 -0
- package/dist/db/migrations/loader.js +106 -0
- package/dist/db/migrations/loader.js.map +1 -0
- package/dist/db/migrations/runner.d.ts +56 -0
- package/dist/db/migrations/runner.d.ts.map +1 -0
- package/dist/db/migrations/runner.js +266 -0
- package/dist/db/migrations/runner.js.map +1 -0
- package/dist/db/migrations/types.d.ts +71 -0
- package/dist/db/migrations/types.d.ts.map +1 -0
- package/dist/db/migrations/types.js +7 -0
- package/dist/db/migrations/types.js.map +1 -0
- package/dist/db/schema.d.ts +41 -2
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +77 -2
- package/dist/db/schema.js.map +1 -1
- package/dist/mcp.js +2 -2
- package/dist/mcp.js.map +1 -1
- package/dist/template-engine/data-transformer.d.ts +17 -0
- package/dist/template-engine/data-transformer.d.ts.map +1 -0
- package/dist/template-engine/data-transformer.js +343 -0
- package/dist/template-engine/data-transformer.js.map +1 -0
- package/dist/template-engine/engine.d.ts +74 -0
- package/dist/template-engine/engine.d.ts.map +1 -0
- package/dist/template-engine/engine.js +183 -0
- package/dist/template-engine/engine.js.map +1 -0
- package/dist/template-engine/helpers.d.ts +81 -0
- package/dist/template-engine/helpers.d.ts.map +1 -0
- package/dist/template-engine/helpers.js +153 -0
- package/dist/template-engine/helpers.js.map +1 -0
- package/dist/template-engine/index.d.ts +10 -0
- package/dist/template-engine/index.d.ts.map +1 -0
- package/dist/template-engine/index.js +10 -0
- package/dist/template-engine/index.js.map +1 -0
- package/dist/template-engine/types.d.ts +147 -0
- package/dist/template-engine/types.d.ts.map +1 -0
- package/dist/template-engine/types.js +7 -0
- package/dist/template-engine/types.js.map +1 -0
- package/dist/template-sync/comparator.d.ts +138 -0
- package/dist/template-sync/comparator.d.ts.map +1 -0
- package/dist/template-sync/comparator.js +353 -0
- package/dist/template-sync/comparator.js.map +1 -0
- package/dist/template-sync/conflict-resolver.d.ts +112 -0
- package/dist/template-sync/conflict-resolver.d.ts.map +1 -0
- package/dist/template-sync/conflict-resolver.js +328 -0
- package/dist/template-sync/conflict-resolver.js.map +1 -0
- package/dist/template-sync/engine.d.ts +93 -0
- package/dist/template-sync/engine.d.ts.map +1 -0
- package/dist/template-sync/engine.js +350 -0
- package/dist/template-sync/engine.js.map +1 -0
- package/dist/template-sync/hasher.d.ts +67 -0
- package/dist/template-sync/hasher.d.ts.map +1 -0
- package/dist/template-sync/hasher.js +94 -0
- package/dist/template-sync/hasher.js.map +1 -0
- package/dist/template-sync/index.d.ts +20 -0
- package/dist/template-sync/index.d.ts.map +1 -0
- package/dist/template-sync/index.js +14 -0
- package/dist/template-sync/index.js.map +1 -0
- package/dist/template-sync/manifest.d.ts +131 -0
- package/dist/template-sync/manifest.d.ts.map +1 -0
- package/dist/template-sync/manifest.js +309 -0
- package/dist/template-sync/manifest.js.map +1 -0
- package/dist/template-sync/merger.d.ts +125 -0
- package/dist/template-sync/merger.d.ts.map +1 -0
- package/dist/template-sync/merger.js +371 -0
- package/dist/template-sync/merger.js.map +1 -0
- package/dist/template-sync/scanner.d.ts +106 -0
- package/dist/template-sync/scanner.d.ts.map +1 -0
- package/dist/template-sync/scanner.js +196 -0
- package/dist/template-sync/scanner.js.map +1 -0
- package/dist/template-sync/types.d.ts +199 -0
- package/dist/template-sync/types.d.ts.map +1 -0
- package/dist/template-sync/types.js +30 -0
- package/dist/template-sync/types.js.map +1 -0
- package/package.json +2 -1
- package/src/agents/cleanup-agent.ts +21 -6
- package/src/agents/drift-agent.ts +31 -8
- package/src/cli/commands/cleanup.ts +9 -1
- package/src/cli/commands/drift-detect.ts +24 -1
- package/src/cli/commands/embeddings-refresh.ts +135 -0
- package/src/cli/commands/migrate.ts +231 -0
- package/src/cli/commands/restore.ts +318 -0
- package/src/cli/commands/sync-templates.ts +210 -0
- package/src/cli/commands/version-check.ts +158 -0
- package/src/cli/generate.ts +99 -17
- package/src/cli/index.ts +246 -1
- package/src/cli/repl/index.ts +16 -6
- package/src/cli/utils/backup-manager.ts +275 -0
- package/src/cli/utils/db-backup-manager.ts +146 -0
- package/src/cli/utils/file-detector.ts +181 -0
- package/src/cli/utils/index.ts +9 -0
- package/src/cli/utils/modification-prompt.ts +112 -0
- package/src/cli/version/checker.ts +172 -0
- package/src/cli/version/comparator.ts +106 -0
- package/src/cli/version/index.ts +11 -0
- package/src/cli/version/parser.ts +101 -0
- package/src/cli/version/prompt.ts +208 -0
- package/src/cli/version/types.ts +95 -0
- package/src/db/client.ts +285 -18
- package/src/db/migrations/files/0014_add_schema_migrations_table.sql +19 -0
- package/src/db/migrations/files/0014_add_schema_migrations_table.ts +30 -0
- package/src/db/migrations/index.ts +9 -0
- package/src/db/migrations/loader.ts +129 -0
- package/src/db/migrations/runner.ts +316 -0
- package/src/db/migrations/types.ts +71 -0
- package/src/db/schema.ts +109 -2
- package/src/mcp.ts +2 -2
- package/src/template-engine/data-transformer.ts +367 -0
- package/src/template-engine/engine.ts +213 -0
- package/src/template-engine/helpers.ts +163 -0
- package/src/template-engine/index.ts +10 -0
- package/src/template-engine/types.ts +158 -0
- package/src/template-sync/comparator.ts +452 -0
- package/src/template-sync/conflict-resolver.ts +401 -0
- package/src/template-sync/engine.ts +417 -0
- package/src/template-sync/hasher.ts +104 -0
- package/src/template-sync/index.ts +60 -0
- package/src/template-sync/manifest.ts +358 -0
- package/src/template-sync/merger.ts +454 -0
- package/src/template-sync/scanner.ts +254 -0
- package/src/template-sync/types.ts +247 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Merger
|
|
3
|
+
*
|
|
4
|
+
* Auto-merge strategies for template updates.
|
|
5
|
+
* Handles safe updates, new file creation, and diff generation.
|
|
6
|
+
*/
|
|
7
|
+
import { promises as fs } from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
/**
|
|
10
|
+
* Auto-merge strategies for template updates
|
|
11
|
+
*/
|
|
12
|
+
export class TemplateMerger {
|
|
13
|
+
projectRoot;
|
|
14
|
+
templateRoot;
|
|
15
|
+
options;
|
|
16
|
+
constructor(projectRoot = process.cwd(), templateRoot, options = {}) {
|
|
17
|
+
this.projectRoot = projectRoot;
|
|
18
|
+
this.templateRoot = templateRoot;
|
|
19
|
+
this.options = options;
|
|
20
|
+
// Default options
|
|
21
|
+
this.options = {
|
|
22
|
+
createBackups: true,
|
|
23
|
+
generateDiffs: true,
|
|
24
|
+
diffContext: 3,
|
|
25
|
+
...options
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Process multiple files for merging
|
|
30
|
+
*
|
|
31
|
+
* @param comparisons - File comparisons to process
|
|
32
|
+
* @returns Array of merge results
|
|
33
|
+
*/
|
|
34
|
+
async mergeFiles(comparisons) {
|
|
35
|
+
const results = [];
|
|
36
|
+
for (const comparison of comparisons) {
|
|
37
|
+
const result = await this.mergeFile(comparison);
|
|
38
|
+
results.push(result);
|
|
39
|
+
}
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Merge a single file based on comparison state
|
|
44
|
+
*
|
|
45
|
+
* @param comparison - File comparison
|
|
46
|
+
* @returns Merge result
|
|
47
|
+
*/
|
|
48
|
+
async mergeFile(comparison) {
|
|
49
|
+
const templatePath = path.join(this.templateRoot, comparison.path);
|
|
50
|
+
const localPath = path.join(this.projectRoot, '.claude', comparison.path);
|
|
51
|
+
try {
|
|
52
|
+
switch (comparison.state) {
|
|
53
|
+
case 'new':
|
|
54
|
+
return await this.createNewFile(templatePath, localPath, comparison);
|
|
55
|
+
case 'safe-update':
|
|
56
|
+
return await this.safeUpdate(templatePath, localPath, comparison);
|
|
57
|
+
case 'identical':
|
|
58
|
+
return {
|
|
59
|
+
path: comparison.path,
|
|
60
|
+
success: true,
|
|
61
|
+
method: 'auto-safe'
|
|
62
|
+
};
|
|
63
|
+
case 'conflict':
|
|
64
|
+
return {
|
|
65
|
+
path: comparison.path,
|
|
66
|
+
success: false,
|
|
67
|
+
method: 'conflict',
|
|
68
|
+
diff: this.options.generateDiffs ? await this.generateDiff(localPath, templatePath) : undefined
|
|
69
|
+
};
|
|
70
|
+
case 'deleted':
|
|
71
|
+
case 'user-only':
|
|
72
|
+
return {
|
|
73
|
+
path: comparison.path,
|
|
74
|
+
success: false,
|
|
75
|
+
method: 'skip',
|
|
76
|
+
error: `File state '${comparison.state}' cannot be auto-merged`
|
|
77
|
+
};
|
|
78
|
+
default:
|
|
79
|
+
return {
|
|
80
|
+
path: comparison.path,
|
|
81
|
+
success: false,
|
|
82
|
+
method: 'skip',
|
|
83
|
+
error: `Unknown state: ${comparison.state}`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
path: comparison.path,
|
|
90
|
+
success: false,
|
|
91
|
+
method: 'skip',
|
|
92
|
+
error: error instanceof Error ? error.message : String(error)
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create new file (no local version exists)
|
|
98
|
+
*
|
|
99
|
+
* @param templatePath - Path to template file
|
|
100
|
+
* @param localPath - Path where local file should be created
|
|
101
|
+
* @param comparison - File comparison
|
|
102
|
+
* @returns Merge result
|
|
103
|
+
*/
|
|
104
|
+
async createNewFile(templatePath, localPath, comparison) {
|
|
105
|
+
try {
|
|
106
|
+
// Read template content
|
|
107
|
+
const content = await fs.readFile(templatePath, 'utf8');
|
|
108
|
+
// Create directory if needed
|
|
109
|
+
await fs.mkdir(path.dirname(localPath), { recursive: true });
|
|
110
|
+
// Write file
|
|
111
|
+
await fs.writeFile(localPath, content, 'utf8');
|
|
112
|
+
return {
|
|
113
|
+
path: comparison.path,
|
|
114
|
+
success: true,
|
|
115
|
+
method: 'auto-create'
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
return {
|
|
120
|
+
path: comparison.path,
|
|
121
|
+
success: false,
|
|
122
|
+
method: 'skip',
|
|
123
|
+
error: error instanceof Error ? error.message : String(error)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Safe update (local exists but not user-modified)
|
|
129
|
+
*
|
|
130
|
+
* @param templatePath - Path to template file
|
|
131
|
+
* @param localPath - Path to local file
|
|
132
|
+
* @param comparison - File comparison
|
|
133
|
+
* @returns Merge result
|
|
134
|
+
*/
|
|
135
|
+
async safeUpdate(templatePath, localPath, comparison) {
|
|
136
|
+
try {
|
|
137
|
+
// Read template content
|
|
138
|
+
const content = await fs.readFile(templatePath, 'utf8');
|
|
139
|
+
// Generate diff before updating
|
|
140
|
+
const diff = this.options.generateDiffs
|
|
141
|
+
? await this.generateDiff(localPath, templatePath)
|
|
142
|
+
: undefined;
|
|
143
|
+
// Create backup if enabled
|
|
144
|
+
if (this.options.createBackups) {
|
|
145
|
+
await this.createBackup(localPath);
|
|
146
|
+
}
|
|
147
|
+
// Write file
|
|
148
|
+
await fs.writeFile(localPath, content, 'utf8');
|
|
149
|
+
return {
|
|
150
|
+
path: comparison.path,
|
|
151
|
+
success: true,
|
|
152
|
+
method: 'auto-safe',
|
|
153
|
+
diff
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
path: comparison.path,
|
|
159
|
+
success: false,
|
|
160
|
+
method: 'skip',
|
|
161
|
+
error: error instanceof Error ? error.message : String(error)
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Overwrite file with template (for conflict resolution)
|
|
167
|
+
*
|
|
168
|
+
* @param templatePath - Path to template file
|
|
169
|
+
* @param localPath - Path to local file
|
|
170
|
+
* @returns Merge result
|
|
171
|
+
*/
|
|
172
|
+
async overwriteFile(templatePath, localPath) {
|
|
173
|
+
try {
|
|
174
|
+
// Read template content
|
|
175
|
+
const content = await fs.readFile(templatePath, 'utf8');
|
|
176
|
+
// Create backup if enabled
|
|
177
|
+
if (this.options.createBackups) {
|
|
178
|
+
await this.createBackup(localPath);
|
|
179
|
+
}
|
|
180
|
+
// Write file
|
|
181
|
+
await fs.writeFile(localPath, content, 'utf8');
|
|
182
|
+
return {
|
|
183
|
+
path: path.relative(this.projectRoot, localPath),
|
|
184
|
+
success: true,
|
|
185
|
+
method: 'overwrite'
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
return {
|
|
190
|
+
path: path.relative(this.projectRoot, localPath),
|
|
191
|
+
success: false,
|
|
192
|
+
method: 'skip',
|
|
193
|
+
error: error instanceof Error ? error.message : String(error)
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Create backup of a file
|
|
199
|
+
*
|
|
200
|
+
* @param filePath - Path to file to backup
|
|
201
|
+
*/
|
|
202
|
+
async createBackup(filePath) {
|
|
203
|
+
const backupDir = this.options.backupDir ?? path.join(this.projectRoot, '.k0ntext', 'backups');
|
|
204
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
205
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
206
|
+
const backupPath = path.join(backupDir, `${path.basename(filePath)}.${timestamp}.bak`);
|
|
207
|
+
await fs.copyFile(filePath, backupPath);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generate unified diff between two files
|
|
211
|
+
*
|
|
212
|
+
* @param localPath - Path to local file
|
|
213
|
+
* @param templatePath - Path to template file
|
|
214
|
+
* @returns Unified diff string
|
|
215
|
+
*/
|
|
216
|
+
async generateDiff(localPath, templatePath) {
|
|
217
|
+
try {
|
|
218
|
+
const localContent = await this.readFileSafe(localPath);
|
|
219
|
+
const templateContent = await this.readFileSafe(templatePath);
|
|
220
|
+
const localLines = localContent.split('\n');
|
|
221
|
+
const templateLines = templateContent.split('\n');
|
|
222
|
+
return this.unifiedDiff(localLines, templateLines, localPath, templatePath);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return '(diff unavailable)';
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Read file safely, return empty string if not found
|
|
230
|
+
*
|
|
231
|
+
* @param filePath - Path to file
|
|
232
|
+
* @returns File content
|
|
233
|
+
*/
|
|
234
|
+
async readFileSafe(filePath) {
|
|
235
|
+
try {
|
|
236
|
+
return await fs.readFile(filePath, 'utf8');
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return '';
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Generate unified diff (simplified implementation)
|
|
244
|
+
*
|
|
245
|
+
* @param localLines - Local file lines
|
|
246
|
+
* @param templateLines - Template file lines
|
|
247
|
+
* @param localPath - Local file path (for header)
|
|
248
|
+
* @param templatePath - Template file path (for header)
|
|
249
|
+
* @returns Unified diff string
|
|
250
|
+
*/
|
|
251
|
+
unifiedDiff(localLines, templateLines, localPath, templatePath) {
|
|
252
|
+
const context = this.options.diffContext ?? 3;
|
|
253
|
+
const lines = [];
|
|
254
|
+
// Simple diff header
|
|
255
|
+
lines.push(`--- ${path.basename(localPath)}`);
|
|
256
|
+
lines.push(`+++ ${path.basename(templatePath)}`);
|
|
257
|
+
// Find differences
|
|
258
|
+
let i = 0;
|
|
259
|
+
let j = 0;
|
|
260
|
+
while (i < localLines.length || j < templateLines.length) {
|
|
261
|
+
if (i < localLines.length && j < templateLines.length) {
|
|
262
|
+
if (localLines[i] === templateLines[j]) {
|
|
263
|
+
// Context line (show only first few around changes)
|
|
264
|
+
if (this.shouldShowContext(i, localLines, templateLines)) {
|
|
265
|
+
lines.push(` ${localLines[i]}`);
|
|
266
|
+
}
|
|
267
|
+
i++;
|
|
268
|
+
j++;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
// Difference found - show context
|
|
272
|
+
this.showContext(lines, localLines, templateLines, i, j, context);
|
|
273
|
+
// Show changes
|
|
274
|
+
const localEnd = this.findChangeEnd(localLines, i, templateLines[j]);
|
|
275
|
+
const templateEnd = this.findChangeEnd(templateLines, j, localLines[i]);
|
|
276
|
+
for (let k = i; k < localEnd; k++) {
|
|
277
|
+
lines.push(`-${localLines[k]}`);
|
|
278
|
+
}
|
|
279
|
+
for (let k = j; k < templateEnd; k++) {
|
|
280
|
+
lines.push(`+${templateLines[k]}`);
|
|
281
|
+
}
|
|
282
|
+
i = localEnd;
|
|
283
|
+
j = templateEnd;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else if (i < localLines.length) {
|
|
287
|
+
// Remaining lines in local (deletions)
|
|
288
|
+
lines.push(`-${localLines[i]}`);
|
|
289
|
+
i++;
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
// Remaining lines in template (additions)
|
|
293
|
+
lines.push(`+${templateLines[j]}`);
|
|
294
|
+
j++;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return lines.join('\n');
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Check if context should be shown
|
|
301
|
+
*/
|
|
302
|
+
shouldShowContext(i, localLines, templateLines) {
|
|
303
|
+
// Show context if we're near a change or at the start/end
|
|
304
|
+
const context = this.options.diffContext ?? 3;
|
|
305
|
+
// Check if there's a change nearby
|
|
306
|
+
for (let offset = 1; offset <= context; offset++) {
|
|
307
|
+
if (i + offset < localLines.length && i + offset < templateLines.length) {
|
|
308
|
+
if (localLines[i + offset] !== templateLines[i + offset]) {
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Show context lines before a change
|
|
317
|
+
*/
|
|
318
|
+
showContext(lines, localLines, templateLines, i, j, context) {
|
|
319
|
+
const start = Math.max(0, i - context);
|
|
320
|
+
// Show context lines if not already shown
|
|
321
|
+
for (let k = start; k < i; k++) {
|
|
322
|
+
if (localLines[k] === templateLines[k]) {
|
|
323
|
+
const lastLine = lines[lines.length - 1];
|
|
324
|
+
if (!lastLine || lastLine[0] !== ' ') {
|
|
325
|
+
lines.push(` ${localLines[k]}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Find end of a change block
|
|
332
|
+
*/
|
|
333
|
+
findChangeEnd(lines, start, otherValue) {
|
|
334
|
+
let end = start + 1;
|
|
335
|
+
while (end < lines.length && lines[end] !== otherValue) {
|
|
336
|
+
end++;
|
|
337
|
+
}
|
|
338
|
+
return end;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Get merge statistics from results
|
|
342
|
+
*
|
|
343
|
+
* @param results - Array of merge results
|
|
344
|
+
* @returns Statistics
|
|
345
|
+
*/
|
|
346
|
+
static getStatistics(results) {
|
|
347
|
+
const stats = {
|
|
348
|
+
total: results.length,
|
|
349
|
+
successful: 0,
|
|
350
|
+
failed: 0,
|
|
351
|
+
byMethod: {
|
|
352
|
+
'auto-safe': 0,
|
|
353
|
+
'auto-create': 0,
|
|
354
|
+
overwrite: 0,
|
|
355
|
+
skip: 0,
|
|
356
|
+
conflict: 0
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
for (const result of results) {
|
|
360
|
+
if (result.success) {
|
|
361
|
+
stats.successful++;
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
stats.failed++;
|
|
365
|
+
}
|
|
366
|
+
stats.byMethod[result.method]++;
|
|
367
|
+
}
|
|
368
|
+
return stats;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=merger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merger.js","sourceRoot":"","sources":["../../src/template-sync/merger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans template directories for files to sync.
|
|
5
|
+
* Recursively discovers files while respecting exclude patterns.
|
|
6
|
+
*/
|
|
7
|
+
import type { TemplateFile, TemplateSubdir } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Scan result with metadata
|
|
10
|
+
*/
|
|
11
|
+
export interface ScanResult {
|
|
12
|
+
/** Files found */
|
|
13
|
+
files: TemplateFile[];
|
|
14
|
+
/** Subdirectories scanned */
|
|
15
|
+
subdirectories: TemplateSubdir[];
|
|
16
|
+
/** Files skipped due to exclude patterns */
|
|
17
|
+
skipped: string[];
|
|
18
|
+
/** Scan duration in milliseconds */
|
|
19
|
+
durationMs: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Scans template directories for files
|
|
23
|
+
*/
|
|
24
|
+
export declare class TemplateScanner {
|
|
25
|
+
/**
|
|
26
|
+
* Scan a directory for template files recursively
|
|
27
|
+
*
|
|
28
|
+
* @param rootPath - Root directory to scan (e.g., templates/base/.claude/)
|
|
29
|
+
* @param subdirectories - Subdirectories to include
|
|
30
|
+
* @param excludePatterns - Patterns to exclude
|
|
31
|
+
* @returns Array of template files found
|
|
32
|
+
*/
|
|
33
|
+
static scanDirectory(rootPath: string, subdirectories?: TemplateSubdir[], excludePatterns?: string[]): Promise<TemplateFile[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Scan with detailed result metadata
|
|
36
|
+
*
|
|
37
|
+
* @param rootPath - Root directory to scan
|
|
38
|
+
* @param subdirectories - Subdirectories to include
|
|
39
|
+
* @param excludePatterns - Patterns to exclude
|
|
40
|
+
* @returns Detailed scan result
|
|
41
|
+
*/
|
|
42
|
+
static scan(rootPath: string, subdirectories?: TemplateSubdir[], excludePatterns?: string[]): Promise<ScanResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Recursively scan directory
|
|
45
|
+
*
|
|
46
|
+
* @param dirPath - Current directory path
|
|
47
|
+
* @param basePath - Base path for relative path calculation
|
|
48
|
+
* @param excludePatterns - Patterns to exclude
|
|
49
|
+
* @returns Array of template files found
|
|
50
|
+
*/
|
|
51
|
+
private static scanRecursive;
|
|
52
|
+
/**
|
|
53
|
+
* Check if a file/directory should be excluded
|
|
54
|
+
*
|
|
55
|
+
* @param name - File or directory name
|
|
56
|
+
* @param excludePatterns - Patterns to check against
|
|
57
|
+
* @returns true if should be excluded
|
|
58
|
+
*/
|
|
59
|
+
private static shouldExclude;
|
|
60
|
+
/**
|
|
61
|
+
* Get all template subdirectories to sync
|
|
62
|
+
*/
|
|
63
|
+
static getSyncedSubdirs(): TemplateSubdir[];
|
|
64
|
+
/**
|
|
65
|
+
* Get excluded subdirectories
|
|
66
|
+
*/
|
|
67
|
+
static getExcludedSubdirs(): string[];
|
|
68
|
+
/**
|
|
69
|
+
* Check if a subdirectory should be synced
|
|
70
|
+
*
|
|
71
|
+
* @param subdir - Subdirectory name
|
|
72
|
+
* @returns true if subdirectory should be synced
|
|
73
|
+
*/
|
|
74
|
+
static isSyncedSubdir(subdir: string): subdir is TemplateSubdir;
|
|
75
|
+
/**
|
|
76
|
+
* Check if a subdirectory should be excluded
|
|
77
|
+
*
|
|
78
|
+
* @param subdir - Subdirectory name
|
|
79
|
+
* @returns true if subdirectory should be excluded
|
|
80
|
+
*/
|
|
81
|
+
static isExcludedSubdir(subdir: string): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Scan and hash files in one pass
|
|
84
|
+
*
|
|
85
|
+
* @param rootPath - Root directory to scan
|
|
86
|
+
* @param subdirectories - Subdirectories to include
|
|
87
|
+
* @returns Array of template files with hashes
|
|
88
|
+
*/
|
|
89
|
+
static scanAndHash(rootPath: string, subdirectories?: TemplateSubdir[]): Promise<TemplateFile[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Get file count by subdirectory
|
|
92
|
+
*
|
|
93
|
+
* @param files - Array of template files
|
|
94
|
+
* @returns Map of subdirectory to file count
|
|
95
|
+
*/
|
|
96
|
+
static getFileCountBySubdir(files: TemplateFile[]): Map<string, number>;
|
|
97
|
+
/**
|
|
98
|
+
* Filter files by subdirectory
|
|
99
|
+
*
|
|
100
|
+
* @param files - Array of template files
|
|
101
|
+
* @param subdir - Subdirectory to filter by
|
|
102
|
+
* @returns Filtered array of files
|
|
103
|
+
*/
|
|
104
|
+
static filterBySubdir(files: TemplateFile[], subdir: string): TemplateFile[];
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/template-sync/scanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAI/D;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,kBAAkB;IAClB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,6BAA6B;IAC7B,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,4CAA4C;IAC5C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAaD;;GAEG;AACH,qBAAa,eAAe;IAC1B;;;;;;;OAOG;WACU,aAAa,CACxB,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,cAAc,EAAqB,EACnD,eAAe,GAAE,MAAM,EAA6B,GACnD,OAAO,CAAC,YAAY,EAAE,CAAC;IAY1B;;;;;;;OAOG;WACU,IAAI,CACf,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,cAAc,EAAqB,EACnD,eAAe,GAAE,MAAM,EAA6B,GACnD,OAAO,CAAC,UAAU,CAAC;IActB;;;;;;;OAOG;mBACkB,aAAa;IA8ClC;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAa5B;;OAEG;IACH,MAAM,CAAC,gBAAgB,IAAI,cAAc,EAAE;IAI3C;;OAEG;IACH,MAAM,CAAC,kBAAkB,IAAI,MAAM,EAAE;IAIrC;;;;;OAKG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,cAAc;IAI/D;;;;;OAKG;IACH,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIhD;;;;;;OAMG;WACU,WAAW,CACtB,QAAQ,EAAE,MAAM,EAChB,cAAc,CAAC,EAAE,cAAc,EAAE,GAChC,OAAO,CAAC,YAAY,EAAE,CAAC;IAgB1B;;;;;OAKG;IACH,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAWvE;;;;;;OAMG;IACH,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;CAG7E"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans template directories for files to sync.
|
|
5
|
+
* Recursively discovers files while respecting exclude patterns.
|
|
6
|
+
*/
|
|
7
|
+
import { promises as fs } from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { TEMPLATE_SUBDIRS, EXCLUDED_SUBDIRS } from './types.js';
|
|
10
|
+
import { TemplateHasher } from './hasher.js';
|
|
11
|
+
/**
|
|
12
|
+
* Default exclude patterns for directory scanning
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_EXCLUDE_PATTERNS = [
|
|
15
|
+
'node_modules',
|
|
16
|
+
'.git',
|
|
17
|
+
'.DS_Store',
|
|
18
|
+
'*.log',
|
|
19
|
+
'.k0ntext-manifest.json'
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Scans template directories for files
|
|
23
|
+
*/
|
|
24
|
+
export class TemplateScanner {
|
|
25
|
+
/**
|
|
26
|
+
* Scan a directory for template files recursively
|
|
27
|
+
*
|
|
28
|
+
* @param rootPath - Root directory to scan (e.g., templates/base/.claude/)
|
|
29
|
+
* @param subdirectories - Subdirectories to include
|
|
30
|
+
* @param excludePatterns - Patterns to exclude
|
|
31
|
+
* @returns Array of template files found
|
|
32
|
+
*/
|
|
33
|
+
static async scanDirectory(rootPath, subdirectories = TEMPLATE_SUBDIRS, excludePatterns = DEFAULT_EXCLUDE_PATTERNS) {
|
|
34
|
+
const results = [];
|
|
35
|
+
for (const subdir of subdirectories) {
|
|
36
|
+
const dirPath = path.join(rootPath, subdir);
|
|
37
|
+
const files = await this.scanRecursive(dirPath, rootPath, excludePatterns);
|
|
38
|
+
results.push(...files);
|
|
39
|
+
}
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Scan with detailed result metadata
|
|
44
|
+
*
|
|
45
|
+
* @param rootPath - Root directory to scan
|
|
46
|
+
* @param subdirectories - Subdirectories to include
|
|
47
|
+
* @param excludePatterns - Patterns to exclude
|
|
48
|
+
* @returns Detailed scan result
|
|
49
|
+
*/
|
|
50
|
+
static async scan(rootPath, subdirectories = TEMPLATE_SUBDIRS, excludePatterns = DEFAULT_EXCLUDE_PATTERNS) {
|
|
51
|
+
const startTime = Date.now();
|
|
52
|
+
const skipped = [];
|
|
53
|
+
const files = await this.scanDirectory(rootPath, subdirectories, excludePatterns);
|
|
54
|
+
return {
|
|
55
|
+
files,
|
|
56
|
+
subdirectories,
|
|
57
|
+
skipped,
|
|
58
|
+
durationMs: Date.now() - startTime
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Recursively scan directory
|
|
63
|
+
*
|
|
64
|
+
* @param dirPath - Current directory path
|
|
65
|
+
* @param basePath - Base path for relative path calculation
|
|
66
|
+
* @param excludePatterns - Patterns to exclude
|
|
67
|
+
* @returns Array of template files found
|
|
68
|
+
*/
|
|
69
|
+
static async scanRecursive(dirPath, basePath, excludePatterns) {
|
|
70
|
+
const results = [];
|
|
71
|
+
try {
|
|
72
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
// Skip excluded patterns
|
|
75
|
+
if (this.shouldExclude(entry.name, excludePatterns)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
79
|
+
if (entry.isDirectory()) {
|
|
80
|
+
// Recursively scan subdirectories
|
|
81
|
+
const subdirResults = await this.scanRecursive(fullPath, basePath, excludePatterns);
|
|
82
|
+
results.push(...subdirResults);
|
|
83
|
+
}
|
|
84
|
+
else if (entry.isFile()) {
|
|
85
|
+
// Get file stats
|
|
86
|
+
const stats = await fs.stat(fullPath);
|
|
87
|
+
const relativePath = path.relative(basePath, fullPath).split(path.sep).join('/');
|
|
88
|
+
results.push({
|
|
89
|
+
relativePath,
|
|
90
|
+
hash: '', // Hashed later to avoid double work
|
|
91
|
+
size: stats.size,
|
|
92
|
+
mtime: stats.mtime
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
// Directory doesn't exist or cannot be read - skip silently
|
|
99
|
+
if (error.code !== 'ENOENT') {
|
|
100
|
+
// Log non-ENOINT errors but don't fail
|
|
101
|
+
console.warn(`Warning: Could not scan directory ${dirPath}: ${error}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return results;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Check if a file/directory should be excluded
|
|
108
|
+
*
|
|
109
|
+
* @param name - File or directory name
|
|
110
|
+
* @param excludePatterns - Patterns to check against
|
|
111
|
+
* @returns true if should be excluded
|
|
112
|
+
*/
|
|
113
|
+
static shouldExclude(name, excludePatterns) {
|
|
114
|
+
return excludePatterns.some(pattern => {
|
|
115
|
+
if (pattern.includes('*')) {
|
|
116
|
+
// Glob pattern
|
|
117
|
+
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
|
|
118
|
+
return regex.test(name);
|
|
119
|
+
}
|
|
120
|
+
return name === pattern || name.includes(pattern);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get all template subdirectories to sync
|
|
125
|
+
*/
|
|
126
|
+
static getSyncedSubdirs() {
|
|
127
|
+
return [...TEMPLATE_SUBDIRS];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get excluded subdirectories
|
|
131
|
+
*/
|
|
132
|
+
static getExcludedSubdirs() {
|
|
133
|
+
return [...EXCLUDED_SUBDIRS];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Check if a subdirectory should be synced
|
|
137
|
+
*
|
|
138
|
+
* @param subdir - Subdirectory name
|
|
139
|
+
* @returns true if subdirectory should be synced
|
|
140
|
+
*/
|
|
141
|
+
static isSyncedSubdir(subdir) {
|
|
142
|
+
return TEMPLATE_SUBDIRS.includes(subdir);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Check if a subdirectory should be excluded
|
|
146
|
+
*
|
|
147
|
+
* @param subdir - Subdirectory name
|
|
148
|
+
* @returns true if subdirectory should be excluded
|
|
149
|
+
*/
|
|
150
|
+
static isExcludedSubdir(subdir) {
|
|
151
|
+
return EXCLUDED_SUBDIRS.includes(subdir);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Scan and hash files in one pass
|
|
155
|
+
*
|
|
156
|
+
* @param rootPath - Root directory to scan
|
|
157
|
+
* @param subdirectories - Subdirectories to include
|
|
158
|
+
* @returns Array of template files with hashes
|
|
159
|
+
*/
|
|
160
|
+
static async scanAndHash(rootPath, subdirectories) {
|
|
161
|
+
// Use scan() to get files, then hash them
|
|
162
|
+
const result = await this.scan(rootPath, subdirectories);
|
|
163
|
+
// Hash files in parallel
|
|
164
|
+
const hashedFiles = await Promise.all(result.files.map(async (file) => {
|
|
165
|
+
const fullPath = path.join(rootPath, file.relativePath);
|
|
166
|
+
const hash = await TemplateHasher.hashFileSafe(fullPath);
|
|
167
|
+
return { ...file, hash };
|
|
168
|
+
}));
|
|
169
|
+
return hashedFiles;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get file count by subdirectory
|
|
173
|
+
*
|
|
174
|
+
* @param files - Array of template files
|
|
175
|
+
* @returns Map of subdirectory to file count
|
|
176
|
+
*/
|
|
177
|
+
static getFileCountBySubdir(files) {
|
|
178
|
+
const counts = new Map();
|
|
179
|
+
for (const file of files) {
|
|
180
|
+
const subdir = file.relativePath.split(path.sep)[0];
|
|
181
|
+
counts.set(subdir, (counts.get(subdir) ?? 0) + 1);
|
|
182
|
+
}
|
|
183
|
+
return counts;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Filter files by subdirectory
|
|
187
|
+
*
|
|
188
|
+
* @param files - Array of template files
|
|
189
|
+
* @param subdir - Subdirectory to filter by
|
|
190
|
+
* @returns Filtered array of files
|
|
191
|
+
*/
|
|
192
|
+
static filterBySubdir(files, subdir) {
|
|
193
|
+
return files.filter(file => file.relativePath.startsWith(subdir + path.sep));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=scanner.js.map
|