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.
Files changed (221) hide show
  1. package/README.md +225 -26
  2. package/dist/agents/cleanup-agent.d.ts.map +1 -1
  3. package/dist/agents/cleanup-agent.js +18 -6
  4. package/dist/agents/cleanup-agent.js.map +1 -1
  5. package/dist/agents/drift-agent.d.ts +7 -0
  6. package/dist/agents/drift-agent.d.ts.map +1 -1
  7. package/dist/agents/drift-agent.js +29 -8
  8. package/dist/agents/drift-agent.js.map +1 -1
  9. package/dist/cli/commands/cleanup.d.ts.map +1 -1
  10. package/dist/cli/commands/cleanup.js +8 -1
  11. package/dist/cli/commands/cleanup.js.map +1 -1
  12. package/dist/cli/commands/drift-detect.d.ts.map +1 -1
  13. package/dist/cli/commands/drift-detect.js +21 -1
  14. package/dist/cli/commands/drift-detect.js.map +1 -1
  15. package/dist/cli/commands/embeddings-refresh.d.ts +11 -0
  16. package/dist/cli/commands/embeddings-refresh.d.ts.map +1 -0
  17. package/dist/cli/commands/embeddings-refresh.js +114 -0
  18. package/dist/cli/commands/embeddings-refresh.js.map +1 -0
  19. package/dist/cli/commands/migrate.d.ts +11 -0
  20. package/dist/cli/commands/migrate.d.ts.map +1 -0
  21. package/dist/cli/commands/migrate.js +195 -0
  22. package/dist/cli/commands/migrate.js.map +1 -0
  23. package/dist/cli/commands/restore.d.ts +12 -0
  24. package/dist/cli/commands/restore.d.ts.map +1 -0
  25. package/dist/cli/commands/restore.js +261 -0
  26. package/dist/cli/commands/restore.js.map +1 -0
  27. package/dist/cli/commands/sync-templates.d.ts +15 -0
  28. package/dist/cli/commands/sync-templates.d.ts.map +1 -0
  29. package/dist/cli/commands/sync-templates.js +181 -0
  30. package/dist/cli/commands/sync-templates.js.map +1 -0
  31. package/dist/cli/commands/version-check.d.ts +12 -0
  32. package/dist/cli/commands/version-check.d.ts.map +1 -0
  33. package/dist/cli/commands/version-check.js +133 -0
  34. package/dist/cli/commands/version-check.js.map +1 -0
  35. package/dist/cli/generate.d.ts +5 -0
  36. package/dist/cli/generate.d.ts.map +1 -1
  37. package/dist/cli/generate.js +80 -16
  38. package/dist/cli/generate.js.map +1 -1
  39. package/dist/cli/index.js +215 -1
  40. package/dist/cli/index.js.map +1 -1
  41. package/dist/cli/repl/index.d.ts +1 -0
  42. package/dist/cli/repl/index.d.ts.map +1 -1
  43. package/dist/cli/repl/index.js +18 -6
  44. package/dist/cli/repl/index.js.map +1 -1
  45. package/dist/cli/utils/backup-manager.d.ts +94 -0
  46. package/dist/cli/utils/backup-manager.d.ts.map +1 -0
  47. package/dist/cli/utils/backup-manager.js +230 -0
  48. package/dist/cli/utils/backup-manager.js.map +1 -0
  49. package/dist/cli/utils/db-backup-manager.d.ts +55 -0
  50. package/dist/cli/utils/db-backup-manager.d.ts.map +1 -0
  51. package/dist/cli/utils/db-backup-manager.js +115 -0
  52. package/dist/cli/utils/db-backup-manager.js.map +1 -0
  53. package/dist/cli/utils/file-detector.d.ts +87 -0
  54. package/dist/cli/utils/file-detector.d.ts.map +1 -0
  55. package/dist/cli/utils/file-detector.js +131 -0
  56. package/dist/cli/utils/file-detector.js.map +1 -0
  57. package/dist/cli/utils/index.d.ts +9 -0
  58. package/dist/cli/utils/index.d.ts.map +1 -0
  59. package/dist/cli/utils/index.js +9 -0
  60. package/dist/cli/utils/index.js.map +1 -0
  61. package/dist/cli/utils/modification-prompt.d.ts +41 -0
  62. package/dist/cli/utils/modification-prompt.d.ts.map +1 -0
  63. package/dist/cli/utils/modification-prompt.js +84 -0
  64. package/dist/cli/utils/modification-prompt.js.map +1 -0
  65. package/dist/cli/version/checker.d.ts +47 -0
  66. package/dist/cli/version/checker.d.ts.map +1 -0
  67. package/dist/cli/version/checker.js +143 -0
  68. package/dist/cli/version/checker.js.map +1 -0
  69. package/dist/cli/version/comparator.d.ts +46 -0
  70. package/dist/cli/version/comparator.d.ts.map +1 -0
  71. package/dist/cli/version/comparator.js +99 -0
  72. package/dist/cli/version/comparator.js.map +1 -0
  73. package/dist/cli/version/index.d.ts +11 -0
  74. package/dist/cli/version/index.d.ts.map +1 -0
  75. package/dist/cli/version/index.js +11 -0
  76. package/dist/cli/version/index.js.map +1 -0
  77. package/dist/cli/version/parser.d.ts +38 -0
  78. package/dist/cli/version/parser.d.ts.map +1 -0
  79. package/dist/cli/version/parser.js +90 -0
  80. package/dist/cli/version/parser.js.map +1 -0
  81. package/dist/cli/version/prompt.d.ts +40 -0
  82. package/dist/cli/version/prompt.d.ts.map +1 -0
  83. package/dist/cli/version/prompt.js +162 -0
  84. package/dist/cli/version/prompt.js.map +1 -0
  85. package/dist/cli/version/types.d.ts +89 -0
  86. package/dist/cli/version/types.d.ts.map +1 -0
  87. package/dist/cli/version/types.js +7 -0
  88. package/dist/cli/version/types.js.map +1 -0
  89. package/dist/db/client.d.ts +79 -4
  90. package/dist/db/client.d.ts.map +1 -1
  91. package/dist/db/client.js +207 -12
  92. package/dist/db/client.js.map +1 -1
  93. package/dist/db/migrations/files/0014_add_schema_migrations_table.d.ts +14 -0
  94. package/dist/db/migrations/files/0014_add_schema_migrations_table.d.ts.map +1 -0
  95. package/dist/db/migrations/files/0014_add_schema_migrations_table.js +25 -0
  96. package/dist/db/migrations/files/0014_add_schema_migrations_table.js.map +1 -0
  97. package/dist/db/migrations/index.d.ts +9 -0
  98. package/dist/db/migrations/index.d.ts.map +1 -0
  99. package/dist/db/migrations/index.js +9 -0
  100. package/dist/db/migrations/index.js.map +1 -0
  101. package/dist/db/migrations/loader.d.ts +27 -0
  102. package/dist/db/migrations/loader.d.ts.map +1 -0
  103. package/dist/db/migrations/loader.js +106 -0
  104. package/dist/db/migrations/loader.js.map +1 -0
  105. package/dist/db/migrations/runner.d.ts +56 -0
  106. package/dist/db/migrations/runner.d.ts.map +1 -0
  107. package/dist/db/migrations/runner.js +266 -0
  108. package/dist/db/migrations/runner.js.map +1 -0
  109. package/dist/db/migrations/types.d.ts +71 -0
  110. package/dist/db/migrations/types.d.ts.map +1 -0
  111. package/dist/db/migrations/types.js +7 -0
  112. package/dist/db/migrations/types.js.map +1 -0
  113. package/dist/db/schema.d.ts +41 -2
  114. package/dist/db/schema.d.ts.map +1 -1
  115. package/dist/db/schema.js +77 -2
  116. package/dist/db/schema.js.map +1 -1
  117. package/dist/mcp.js +2 -2
  118. package/dist/mcp.js.map +1 -1
  119. package/dist/template-engine/data-transformer.d.ts +17 -0
  120. package/dist/template-engine/data-transformer.d.ts.map +1 -0
  121. package/dist/template-engine/data-transformer.js +343 -0
  122. package/dist/template-engine/data-transformer.js.map +1 -0
  123. package/dist/template-engine/engine.d.ts +74 -0
  124. package/dist/template-engine/engine.d.ts.map +1 -0
  125. package/dist/template-engine/engine.js +183 -0
  126. package/dist/template-engine/engine.js.map +1 -0
  127. package/dist/template-engine/helpers.d.ts +81 -0
  128. package/dist/template-engine/helpers.d.ts.map +1 -0
  129. package/dist/template-engine/helpers.js +153 -0
  130. package/dist/template-engine/helpers.js.map +1 -0
  131. package/dist/template-engine/index.d.ts +10 -0
  132. package/dist/template-engine/index.d.ts.map +1 -0
  133. package/dist/template-engine/index.js +10 -0
  134. package/dist/template-engine/index.js.map +1 -0
  135. package/dist/template-engine/types.d.ts +147 -0
  136. package/dist/template-engine/types.d.ts.map +1 -0
  137. package/dist/template-engine/types.js +7 -0
  138. package/dist/template-engine/types.js.map +1 -0
  139. package/dist/template-sync/comparator.d.ts +138 -0
  140. package/dist/template-sync/comparator.d.ts.map +1 -0
  141. package/dist/template-sync/comparator.js +353 -0
  142. package/dist/template-sync/comparator.js.map +1 -0
  143. package/dist/template-sync/conflict-resolver.d.ts +112 -0
  144. package/dist/template-sync/conflict-resolver.d.ts.map +1 -0
  145. package/dist/template-sync/conflict-resolver.js +328 -0
  146. package/dist/template-sync/conflict-resolver.js.map +1 -0
  147. package/dist/template-sync/engine.d.ts +93 -0
  148. package/dist/template-sync/engine.d.ts.map +1 -0
  149. package/dist/template-sync/engine.js +350 -0
  150. package/dist/template-sync/engine.js.map +1 -0
  151. package/dist/template-sync/hasher.d.ts +67 -0
  152. package/dist/template-sync/hasher.d.ts.map +1 -0
  153. package/dist/template-sync/hasher.js +94 -0
  154. package/dist/template-sync/hasher.js.map +1 -0
  155. package/dist/template-sync/index.d.ts +20 -0
  156. package/dist/template-sync/index.d.ts.map +1 -0
  157. package/dist/template-sync/index.js +14 -0
  158. package/dist/template-sync/index.js.map +1 -0
  159. package/dist/template-sync/manifest.d.ts +131 -0
  160. package/dist/template-sync/manifest.d.ts.map +1 -0
  161. package/dist/template-sync/manifest.js +309 -0
  162. package/dist/template-sync/manifest.js.map +1 -0
  163. package/dist/template-sync/merger.d.ts +125 -0
  164. package/dist/template-sync/merger.d.ts.map +1 -0
  165. package/dist/template-sync/merger.js +371 -0
  166. package/dist/template-sync/merger.js.map +1 -0
  167. package/dist/template-sync/scanner.d.ts +106 -0
  168. package/dist/template-sync/scanner.d.ts.map +1 -0
  169. package/dist/template-sync/scanner.js +196 -0
  170. package/dist/template-sync/scanner.js.map +1 -0
  171. package/dist/template-sync/types.d.ts +199 -0
  172. package/dist/template-sync/types.d.ts.map +1 -0
  173. package/dist/template-sync/types.js +30 -0
  174. package/dist/template-sync/types.js.map +1 -0
  175. package/package.json +2 -1
  176. package/src/agents/cleanup-agent.ts +21 -6
  177. package/src/agents/drift-agent.ts +31 -8
  178. package/src/cli/commands/cleanup.ts +9 -1
  179. package/src/cli/commands/drift-detect.ts +24 -1
  180. package/src/cli/commands/embeddings-refresh.ts +135 -0
  181. package/src/cli/commands/migrate.ts +231 -0
  182. package/src/cli/commands/restore.ts +318 -0
  183. package/src/cli/commands/sync-templates.ts +210 -0
  184. package/src/cli/commands/version-check.ts +158 -0
  185. package/src/cli/generate.ts +99 -17
  186. package/src/cli/index.ts +246 -1
  187. package/src/cli/repl/index.ts +16 -6
  188. package/src/cli/utils/backup-manager.ts +275 -0
  189. package/src/cli/utils/db-backup-manager.ts +146 -0
  190. package/src/cli/utils/file-detector.ts +181 -0
  191. package/src/cli/utils/index.ts +9 -0
  192. package/src/cli/utils/modification-prompt.ts +112 -0
  193. package/src/cli/version/checker.ts +172 -0
  194. package/src/cli/version/comparator.ts +106 -0
  195. package/src/cli/version/index.ts +11 -0
  196. package/src/cli/version/parser.ts +101 -0
  197. package/src/cli/version/prompt.ts +208 -0
  198. package/src/cli/version/types.ts +95 -0
  199. package/src/db/client.ts +285 -18
  200. package/src/db/migrations/files/0014_add_schema_migrations_table.sql +19 -0
  201. package/src/db/migrations/files/0014_add_schema_migrations_table.ts +30 -0
  202. package/src/db/migrations/index.ts +9 -0
  203. package/src/db/migrations/loader.ts +129 -0
  204. package/src/db/migrations/runner.ts +316 -0
  205. package/src/db/migrations/types.ts +71 -0
  206. package/src/db/schema.ts +109 -2
  207. package/src/mcp.ts +2 -2
  208. package/src/template-engine/data-transformer.ts +367 -0
  209. package/src/template-engine/engine.ts +213 -0
  210. package/src/template-engine/helpers.ts +163 -0
  211. package/src/template-engine/index.ts +10 -0
  212. package/src/template-engine/types.ts +158 -0
  213. package/src/template-sync/comparator.ts +452 -0
  214. package/src/template-sync/conflict-resolver.ts +401 -0
  215. package/src/template-sync/engine.ts +417 -0
  216. package/src/template-sync/hasher.ts +104 -0
  217. package/src/template-sync/index.ts +60 -0
  218. package/src/template-sync/manifest.ts +358 -0
  219. package/src/template-sync/merger.ts +454 -0
  220. package/src/template-sync/scanner.ts +254 -0
  221. 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