From 39ee76f492e7350305925149e3849a72a2ef06cb Mon Sep 17 00:00:00 2001 From: Lum1104 Date: Sat, 28 Mar 2026 12:13:22 +0800 Subject: [PATCH] fix: address remaining Copilot review findings - SKILL.md Phase 7: use core buildFingerprintStore instead of ad-hoc regex script - change-classifier: accurate FULL_UPDATE reason message (count vs percentage) - persistence: add saveConfig/loadConfig tests (round-trip, missing, corrupted) Co-Authored-By: Claude Opus 4.6 --- .../packages/core/src/change-classifier.ts | 12 +++++- .../core/src/persistence/persistence.test.ts | 26 ++++++++++++- .../skills/understand/SKILL.md | 37 +++++-------------- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/understand-anything-plugin/packages/core/src/change-classifier.ts b/understand-anything-plugin/packages/core/src/change-classifier.ts index b14964d..41660a6 100644 --- a/understand-anything-plugin/packages/core/src/change-classifier.ts +++ b/understand-anything-plugin/packages/core/src/change-classifier.ts @@ -43,13 +43,21 @@ export function classifyUpdate( } // Too many structural changes — suggest full rebuild - if (structuralCount > 30 || (totalFilesInGraph > 0 && structuralCount / totalFilesInGraph > 0.5)) { + const triggeredByCount = structuralCount > 30; + const triggeredByPercentage = totalFilesInGraph > 0 && structuralCount / totalFilesInGraph > 0.5; + if (triggeredByCount || triggeredByPercentage) { + const thresholdReason = + triggeredByCount && triggeredByPercentage + ? ">30 files and >50% of project" + : triggeredByCount + ? ">30 files" + : ">50% of project"; return { action: "FULL_UPDATE", filesToReanalyze: [...structurallyChangedFiles, ...newFiles], rerunArchitecture: true, rerunTour: true, - reason: `${structuralCount} files have structural changes (>${totalFilesInGraph > 0 ? "50% of project" : "30 files"}) — full rebuild recommended`, + reason: `${structuralCount} files have structural changes (${thresholdReason}) — full rebuild recommended`, }; } diff --git a/understand-anything-plugin/packages/core/src/persistence/persistence.test.ts b/understand-anything-plugin/packages/core/src/persistence/persistence.test.ts index 9629cb9..cde784e 100644 --- a/understand-anything-plugin/packages/core/src/persistence/persistence.test.ts +++ b/understand-anything-plugin/packages/core/src/persistence/persistence.test.ts @@ -3,7 +3,7 @@ import { mkdtempSync, rmSync, existsSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; import { writeFileSync } from "node:fs"; -import { saveGraph, loadGraph, saveMeta, loadMeta, saveFingerprints, loadFingerprints } from "./index.js"; +import { saveGraph, loadGraph, saveMeta, loadMeta, saveFingerprints, loadFingerprints, saveConfig, loadConfig } from "./index.js"; import type { KnowledgeGraph, AnalysisMeta } from "../types.js"; import type { FingerprintStore } from "../fingerprint.js"; @@ -159,4 +159,28 @@ describe("persistence", () => { expect(loaded).toBeNull(); }); }); + + describe("saveConfig / loadConfig", () => { + it("should round-trip config correctly", () => { + saveConfig(tempDir, { autoUpdate: true }); + const loaded = loadConfig(tempDir); + + expect(loaded).toEqual({ autoUpdate: true }); + }); + + it("should return default config when no file exists", () => { + const loaded = loadConfig(tempDir); + + expect(loaded).toEqual({ autoUpdate: false }); + }); + + it("should return default config when config.json is corrupted", () => { + saveConfig(tempDir, { autoUpdate: true }); + const dir = join(tempDir, ".understand-anything"); + writeFileSync(join(dir, "config.json"), "not json!!", "utf-8"); + + const loaded = loadConfig(tempDir); + expect(loaded).toEqual({ autoUpdate: false }); + }); + }); }); diff --git a/understand-anything-plugin/skills/understand/SKILL.md b/understand-anything-plugin/skills/understand/SKILL.md index 0f8fd0f..5dff038 100644 --- a/understand-anything-plugin/skills/understand/SKILL.md +++ b/understand-anything-plugin/skills/understand/SKILL.md @@ -482,34 +482,15 @@ Pass these parameters in the dispatch prompt: 2.5. **Generate structural fingerprints** for all analyzed files and save to `$PROJECT_ROOT/.understand-anything/fingerprints.json`. This creates the baseline for future automatic incremental updates. - Write and execute a Node.js script that: - 1. Reads each source file path from the scan results (Phase 1) - 2. For each file: computes a SHA-256 content hash, then extracts function/class/import/export declarations via regex matching: - - Functions: `function NAME(`, `const NAME = (`, `export function NAME(`, arrow functions assigned to const/let - - Classes: `class NAME`, `export class NAME` - - Imports: `import ... from '...'`, `import '...'` - - Exports: `export { ... }`, `export default`, `export function`, `export class`, `export const` - 3. For each function: record name, parameter names, whether exported, and line count - 4. For each class: record name, method names, property names, whether exported - 5. Writes the fingerprint store JSON to `$PROJECT_ROOT/.understand-anything/fingerprints.json`: - ```json - { - "version": "1.0.0", - "gitCommitHash": "", - "generatedAt": "", - "files": { - "": { - "filePath": "", - "contentHash": "", - "functions": [{ "name": "...", "params": ["..."], "exported": true, "lineCount": 35 }], - "classes": [{ "name": "...", "methods": ["..."], "properties": ["..."], "exported": true, "lineCount": 50 }], - "imports": [{ "source": "...", "specifiers": ["..."] }], - "exports": ["name1", "name2"], - "totalLines": 120 - } - } - } - ``` + Write and execute a Node.js script that uses the core fingerprint module (tree-sitter-based, not regex): + ```javascript + import { buildFingerprintStore } from '@understand-anything/core'; + import { saveFingerprints } from '@understand-anything/core'; + + const store = await buildFingerprintStore('', sourceFilePaths); + saveFingerprints('', store); + ``` + Where `sourceFilePaths` is the list of all analyzed source file paths from Phase 1. This uses the same tree-sitter analysis pipeline as the main fingerprint engine, ensuring the baseline matches the comparison logic used during auto-updates. 3. Clean up intermediate files: ```bash