Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
c48f48fc8b | |||
e21e7f0850 |
1
assets/overrides.json
Normal file
1
assets/overrides.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
@@ -1,5 +1,14 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-08-08 - 1.16.6 - fix(changecache)
|
||||||
|
Improve cache manifest validation and atomic file writes; add local settings and overrides
|
||||||
|
|
||||||
|
- Add manifest structure validation and default fallback in getManifest
|
||||||
|
- Implement atomic write in saveManifest using a temporary file and rename strategy
|
||||||
|
- Enhance error handling and cleanup for corrupted manifest files
|
||||||
|
- Introduce new .claude/settings.local.json for project-specific permission configuration
|
||||||
|
- Add an empty assets/overrides.json file for future overrides
|
||||||
|
|
||||||
## 2025-08-08 - 1.16.5 - fix(prettier)
|
## 2025-08-08 - 1.16.5 - fix(prettier)
|
||||||
Improve file selection in Prettier formatter, remove legacy package overrides, and update CI template indentation
|
Improve file selection in Prettier formatter, remove legacy package overrides, and update CI template indentation
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@git.zone/cli",
|
"name": "@git.zone/cli",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.16.5",
|
"version": "1.16.6",
|
||||||
"description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.",
|
"description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.",
|
||||||
"main": "dist_ts/index.ts",
|
"main": "dist_ts/index.ts",
|
||||||
"typings": "dist_ts/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/cli',
|
name: '@git.zone/cli',
|
||||||
version: '1.16.5',
|
version: '1.16.6',
|
||||||
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
|
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
|
||||||
}
|
}
|
||||||
|
@@ -29,21 +29,67 @@ export class ChangeCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getManifest(): Promise<ICacheManifest> {
|
async getManifest(): Promise<ICacheManifest> {
|
||||||
const exists = await plugins.smartfile.fs.fileExists(this.manifestPath);
|
const defaultManifest: ICacheManifest = {
|
||||||
if (!exists) {
|
|
||||||
return {
|
|
||||||
version: this.cacheVersion,
|
version: this.cacheVersion,
|
||||||
lastFormat: 0,
|
lastFormat: 0,
|
||||||
files: []
|
files: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const exists = await plugins.smartfile.fs.fileExists(this.manifestPath);
|
||||||
|
if (!exists) {
|
||||||
|
return defaultManifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const content = plugins.smartfile.fs.toStringSync(this.manifestPath);
|
const content = plugins.smartfile.fs.toStringSync(this.manifestPath);
|
||||||
return JSON.parse(content);
|
const manifest = JSON.parse(content);
|
||||||
|
|
||||||
|
// Validate the manifest structure
|
||||||
|
if (this.isValidManifest(manifest)) {
|
||||||
|
return manifest;
|
||||||
|
} else {
|
||||||
|
console.warn('Invalid manifest structure, returning default manifest');
|
||||||
|
return defaultManifest;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Failed to read cache manifest: ${error.message}, returning default manifest`);
|
||||||
|
// Try to delete the corrupted file
|
||||||
|
try {
|
||||||
|
await plugins.smartfile.fs.remove(this.manifestPath);
|
||||||
|
} catch (removeError) {
|
||||||
|
// Ignore removal errors
|
||||||
|
}
|
||||||
|
return defaultManifest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveManifest(manifest: ICacheManifest): Promise<void> {
|
async saveManifest(manifest: ICacheManifest): Promise<void> {
|
||||||
await plugins.smartfile.memory.toFs(JSON.stringify(manifest, null, 2), this.manifestPath);
|
// Validate before saving
|
||||||
|
if (!this.isValidManifest(manifest)) {
|
||||||
|
throw new Error('Invalid manifest structure, cannot save');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use atomic write: write to temp file, then move it
|
||||||
|
const tempPath = `${this.manifestPath}.tmp`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Write to temporary file
|
||||||
|
const jsonContent = JSON.stringify(manifest, null, 2);
|
||||||
|
await plugins.smartfile.memory.toFs(jsonContent, tempPath);
|
||||||
|
|
||||||
|
// Move temp file to actual manifest (atomic-like operation)
|
||||||
|
// Since smartfile doesn't have rename, we copy and delete
|
||||||
|
await plugins.smartfile.fs.copy(tempPath, this.manifestPath);
|
||||||
|
await plugins.smartfile.fs.remove(tempPath);
|
||||||
|
} catch (error) {
|
||||||
|
// Clean up temp file if it exists
|
||||||
|
try {
|
||||||
|
await plugins.smartfile.fs.remove(tempPath);
|
||||||
|
} catch (removeError) {
|
||||||
|
// Ignore removal errors
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async hasFileChanged(filePath: string): Promise<boolean> {
|
async hasFileChanged(filePath: string): Promise<boolean> {
|
||||||
@@ -95,7 +141,7 @@ export class ChangeCache {
|
|||||||
return; // Don't cache directories
|
return; // Don't cache directories
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await plugins.smartfile.fs.toStringSync(absolutePath);
|
const content = plugins.smartfile.fs.toStringSync(absolutePath);
|
||||||
const checksum = this.calculateChecksum(content);
|
const checksum = this.calculateChecksum(content);
|
||||||
|
|
||||||
// Update manifest
|
// Update manifest
|
||||||
@@ -153,4 +199,31 @@ export class ChangeCache {
|
|||||||
private calculateChecksum(content: string | Buffer): string {
|
private calculateChecksum(content: string | Buffer): string {
|
||||||
return plugins.crypto.createHash('sha256').update(content).digest('hex');
|
return plugins.crypto.createHash('sha256').update(content).digest('hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isValidManifest(manifest: any): manifest is ICacheManifest {
|
||||||
|
// Check if manifest has the required structure
|
||||||
|
if (!manifest || typeof manifest !== 'object') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check required fields
|
||||||
|
if (typeof manifest.version !== 'string' ||
|
||||||
|
typeof manifest.lastFormat !== 'number' ||
|
||||||
|
!Array.isArray(manifest.files)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check each file entry
|
||||||
|
for (const file of manifest.files) {
|
||||||
|
if (!file || typeof file !== 'object' ||
|
||||||
|
typeof file.path !== 'string' ||
|
||||||
|
typeof file.checksum !== 'string' ||
|
||||||
|
typeof file.modified !== 'number' ||
|
||||||
|
typeof file.size !== 'number') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user