fix(hooks/auto-update): apply .understandignore exclusions in Phase 0

Fixes #153. Phase 0 step 7 filters changed files to source extensions
only and never reads `.understandignore`, so files in user-excluded
paths (migrations, vendored code, tests) count as structural changes
and can spuriously escalate the action to FULL_UPDATE. The reporter
saw 50 → 38 structural files after applying their ignore patterns
(below the 30-file FULL_UPDATE threshold, ARCHITECTURE_UPDATE would
have sufficed).

Add step 9 that delegates to `createIgnoreFilter` from
`@understand-anything/core` via $CLAUDE_PLUGIN_ROOT. Same code path
as /understand's project-scanner Step 2.5, so the auto-update honors
the exact same patterns (hardcoded defaults + user .understandignore
files at both standard locations + `!` negation semantics).

If $CLAUDE_PLUGIN_ROOT can't be resolved, fail loud rather than
silently skipping — a silent skip reproduces the original bug.
This commit is contained in:
Lum1104
2026-05-18 09:58:11 +08:00
Unverified
parent 2da74848e5
commit 5304ff06f3
@@ -37,6 +37,58 @@ Incrementally update the knowledge graph using deterministic structural fingerpr
mkdir -p $PROJECT_ROOT/.understand-anything/intermediate
```
9. **Apply `.understandignore` exclusions** (same semantics as `/understand` Step 2.5 in `agents/project-scanner.md`).
Without this step, files in user-excluded paths (migrations, vendored code, tests) are counted as structural changes and can spuriously escalate the action to `FULL_UPDATE` even when the real change set is tiny.
1. If neither `$PROJECT_ROOT/.understand-anything/.understandignore` nor `$PROJECT_ROOT/.understandignore` exists, the step 7 extension filter is sufficient — skip to Phase 1.
2. Write the step 7 file list to `$PROJECT_ROOT/.understand-anything/intermediate/changed-files-pre.json` as a JSON array of relative paths.
3. Resolve `$PLUGIN_ROOT`:
- Use `$CLAUDE_PLUGIN_ROOT` if set (Claude Code's hook context sets this).
- Otherwise try `$HOME/.understand-anything-plugin`.
- Validate the chosen candidate by checking `$candidate/packages/core/dist/ignore-filter.js` exists.
- If neither resolves: report "Cannot locate plugin install at `$CLAUDE_PLUGIN_ROOT` or `$HOME/.understand-anything-plugin`; auto-update aborted. Run `/understand` to re-baseline." and **STOP**. Do **not** silently skip — silent skip reproduces issue #153.
4. Write `$PROJECT_ROOT/.understand-anything/intermediate/ignore-filter.mjs`:
```javascript
import { readFileSync, writeFileSync } from 'node:fs';
import { pathToFileURL } from 'node:url';
import path from 'node:path';
const PROJECT_ROOT = process.cwd();
const PLUGIN_ROOT = process.argv[2];
const inputPath = process.argv[3];
const modUrl = pathToFileURL(
path.join(PLUGIN_ROOT, 'packages/core/dist/ignore-filter.js'),
).href;
const { createIgnoreFilter } = await import(modUrl);
const filter = createIgnoreFilter(PROJECT_ROOT);
const input = JSON.parse(readFileSync(inputPath, 'utf-8'));
const kept = input.filter((p) => !filter.isIgnored(p));
const removed = input.length - kept.length;
writeFileSync(
path.join(PROJECT_ROOT, '.understand-anything/intermediate/changed-files.json'),
JSON.stringify({ kept, removed, total: input.length }, null, 2),
);
console.log(`.understandignore: kept ${kept.length}/${input.length} (removed ${removed})`);
```
5. Run it:
```bash
node $PROJECT_ROOT/.understand-anything/intermediate/ignore-filter.mjs \
"$PLUGIN_ROOT" \
$PROJECT_ROOT/.understand-anything/intermediate/changed-files-pre.json
```
6. Read `$PROJECT_ROOT/.understand-anything/intermediate/changed-files.json`. Pass the `kept` array as the input file list for Phase 1's fingerprint-check script.
7. If `kept.length === 0`: update `meta.json` with the new commit hash, report "All changed source files are in ignored paths. Metadata updated." and **STOP**.
---
## Phase 1 — Structural Fingerprint Check (Zero LLM Tokens)