cwresdev 0.2.1 → 0.2.3
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/bin/cwgit.js +2 -4
- package/package.json +1 -1
- package/src/cwgit.js +47 -14
package/bin/cwgit.js
CHANGED
|
@@ -49,10 +49,8 @@ async function main() {
|
|
|
49
49
|
const docRoot = resolveDocRoot(workspaceRoot);
|
|
50
50
|
|
|
51
51
|
if (command === "init") {
|
|
52
|
-
|
|
53
|
-
process.stdout.write(
|
|
54
|
-
process.stdout.write(`[cwgit] Stored at: ${basePath}\n`);
|
|
55
|
-
process.stdout.write(`[cwgit] Tip: add .cwgit/ to .gitignore if using Git.\n`);
|
|
52
|
+
await initBase(targetPath, docRoot);
|
|
53
|
+
process.stdout.write("[cwgit] Successfully initiated.\n");
|
|
56
54
|
return;
|
|
57
55
|
}
|
|
58
56
|
|
package/package.json
CHANGED
package/src/cwgit.js
CHANGED
|
@@ -195,10 +195,9 @@ async function initBase(projectDir, docRoot) {
|
|
|
195
195
|
const filePaths = await collectFiles(resolvedProject, resolvedProject);
|
|
196
196
|
const fileCount = filePaths.length;
|
|
197
197
|
|
|
198
|
-
process.stderr.write(`[cwgit] Hashing ${fileCount} files...\n`);
|
|
199
|
-
|
|
200
198
|
const files = {};
|
|
201
199
|
let processed = 0;
|
|
200
|
+
let lastPercent = -1;
|
|
202
201
|
|
|
203
202
|
for (const filePath of filePaths) {
|
|
204
203
|
const relFilePath = path.relative(resolvedProject, filePath).replace(/\\/g, "/");
|
|
@@ -207,7 +206,6 @@ async function initBase(projectDir, docRoot) {
|
|
|
207
206
|
files[relFilePath] = await hashFile(filePath);
|
|
208
207
|
} catch (err) {
|
|
209
208
|
if (err.code === "EBUSY" || err.code === "EPERM" || err.code === "ENOENT") {
|
|
210
|
-
process.stderr.write(`[cwgit] Warning: skipped inaccessible file: ${relFilePath}\n`);
|
|
211
209
|
continue;
|
|
212
210
|
}
|
|
213
211
|
|
|
@@ -215,12 +213,16 @@ async function initBase(projectDir, docRoot) {
|
|
|
215
213
|
}
|
|
216
214
|
|
|
217
215
|
processed += 1;
|
|
216
|
+
const percent = Math.floor((processed / fileCount) * 100);
|
|
218
217
|
|
|
219
|
-
if (
|
|
220
|
-
|
|
218
|
+
if (percent !== lastPercent) {
|
|
219
|
+
lastPercent = percent;
|
|
220
|
+
process.stderr.write(`\r[cwgit] ${percent}%`);
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
process.stderr.write("\n");
|
|
225
|
+
|
|
224
226
|
const baseData = {
|
|
225
227
|
version: 1,
|
|
226
228
|
createdAt: new Date().toISOString(),
|
|
@@ -265,7 +267,10 @@ async function detectChanges(projectDir, docRoot) {
|
|
|
265
267
|
const currentPaths = await collectFiles(resolvedProject, resolvedProject);
|
|
266
268
|
const currentFiles = {};
|
|
267
269
|
|
|
268
|
-
process.stderr.write(
|
|
270
|
+
process.stderr.write(`\r[cwgit] 0%`);
|
|
271
|
+
|
|
272
|
+
let scanned = 0;
|
|
273
|
+
let lastScanPercent = -1;
|
|
269
274
|
|
|
270
275
|
for (const filePath of currentPaths) {
|
|
271
276
|
const relFilePath = path.relative(resolvedProject, filePath).replace(/\\/g, "/");
|
|
@@ -274,29 +279,54 @@ async function detectChanges(projectDir, docRoot) {
|
|
|
274
279
|
currentFiles[relFilePath] = await hashFile(filePath);
|
|
275
280
|
} catch (err) {
|
|
276
281
|
if (err.code === "EBUSY" || err.code === "EPERM" || err.code === "ENOENT") {
|
|
277
|
-
process.stderr.write(`[cwgit] Warning: skipped inaccessible file: ${relFilePath}\n`);
|
|
278
282
|
continue;
|
|
279
283
|
}
|
|
280
284
|
|
|
281
285
|
throw err;
|
|
282
286
|
}
|
|
287
|
+
|
|
288
|
+
scanned += 1;
|
|
289
|
+
const pct = Math.floor((scanned / currentPaths.length) * 100);
|
|
290
|
+
|
|
291
|
+
if (pct !== lastScanPercent) {
|
|
292
|
+
lastScanPercent = pct;
|
|
293
|
+
process.stderr.write(`\r[cwgit] ${pct}%`);
|
|
294
|
+
}
|
|
283
295
|
}
|
|
284
296
|
|
|
297
|
+
process.stderr.write("\n");
|
|
298
|
+
|
|
285
299
|
const changes = [];
|
|
286
300
|
|
|
287
301
|
// Check for modified and deleted files
|
|
288
302
|
for (const [file, hash] of Object.entries(baseFiles)) {
|
|
289
303
|
if (!(file in currentFiles)) {
|
|
290
|
-
changes.push({ file, status: "D" });
|
|
304
|
+
changes.push({ file, status: "D", mtime: null });
|
|
291
305
|
} else if (currentFiles[file] !== hash) {
|
|
292
|
-
|
|
306
|
+
const fullPath = path.join(resolvedProject, file.replace(/\//g, path.sep));
|
|
307
|
+
let mtime = null;
|
|
308
|
+
|
|
309
|
+
try {
|
|
310
|
+
const stat = await fs.promises.stat(fullPath);
|
|
311
|
+
mtime = stat.mtime;
|
|
312
|
+
} catch (_) {}
|
|
313
|
+
|
|
314
|
+
changes.push({ file, status: "M", mtime });
|
|
293
315
|
}
|
|
294
316
|
}
|
|
295
317
|
|
|
296
318
|
// Check for new/untracked files
|
|
297
319
|
for (const file of Object.keys(currentFiles)) {
|
|
298
320
|
if (!(file in baseFiles)) {
|
|
299
|
-
|
|
321
|
+
const fullPath = path.join(resolvedProject, file.replace(/\//g, path.sep));
|
|
322
|
+
let mtime = null;
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
const stat = await fs.promises.stat(fullPath);
|
|
326
|
+
mtime = stat.mtime;
|
|
327
|
+
} catch (_) {}
|
|
328
|
+
|
|
329
|
+
changes.push({ file, status: "U", mtime });
|
|
300
330
|
}
|
|
301
331
|
}
|
|
302
332
|
|
|
@@ -329,20 +359,23 @@ function sanitizeCsvCell(value) {
|
|
|
329
359
|
return value;
|
|
330
360
|
}
|
|
331
361
|
|
|
362
|
+
const STATUS_LABELS = { M: "Modified", U: "Untracked", D: "Deleted" };
|
|
363
|
+
|
|
332
364
|
/**
|
|
333
365
|
* Export changes to a CSV file.
|
|
334
366
|
*/
|
|
335
367
|
async function exportCsv(changes, outputDir) {
|
|
336
368
|
const csvPath = path.join(outputDir, "cwgit-changes.csv");
|
|
337
|
-
const lines = ["file,status"];
|
|
369
|
+
const lines = ["file,status,date"];
|
|
338
370
|
|
|
339
|
-
for (const { file, status } of changes) {
|
|
371
|
+
for (const { file, status, mtime } of changes) {
|
|
340
372
|
const safeFile = sanitizeCsvCell(file);
|
|
341
|
-
// Escape double quotes in file path and wrap in quotes if contains comma
|
|
342
373
|
const escaped = safeFile.includes(",") || safeFile.includes('"')
|
|
343
374
|
? `"${safeFile.replace(/"/g, '""')}"`
|
|
344
375
|
: safeFile;
|
|
345
|
-
|
|
376
|
+
const label = STATUS_LABELS[status] || status;
|
|
377
|
+
const date = mtime ? mtime.toISOString().replace("T", " ").slice(0, 19) : "";
|
|
378
|
+
lines.push(`${escaped},${label},${date}`);
|
|
346
379
|
}
|
|
347
380
|
|
|
348
381
|
await fs.promises.writeFile(csvPath, lines.join("\n") + "\n", "utf8");
|