mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-02 02:11:29 +00:00
`gitnexus status` reported "stale (re-run gitnexus analyze)" whenever the working tree held any modified or untracked file, including files the index never reads. Because `analyze` cannot commit, stash or delete such a file, the remedy it prescribed could not clear the verdict — the only way back to up-to-date was to remove the file. `meta.fileHashes` already records the exact set of files a run covered, so answer the question directly: compare those hashes against disk, reusing analyze's own scan, hash and diff helpers so the two cannot disagree about what "changed" means. A new coverable file still counts as stale (the index is genuinely incomplete then), but one `analyze` now settles it. The repo-wide dirty flag survives only as the fallback for metadata written before `fileHashes` existed. Both freshness checks now read GitNexus's own analyze output (AGENTS.md, CLAUDE.md, the agent skill mirrors) from one shared list. They previously held separate copies, and since analyze rewrites those files after recording hashes, a per-file comparison that missed them would report a freshly indexed repository as permanently stale. Closes #3077 Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
/**
|
|
* The paths GitNexus itself writes during `analyze`.
|
|
*
|
|
* `analyze` rewrites the stats blocks in AGENTS.md/CLAUDE.md and refreshes the
|
|
* agent skill mirrors as its final step — after it has recorded the per-file
|
|
* hashes for the run. Counting its own output as a repository change makes
|
|
* every completed run look immediately out of date, which is the regression
|
|
* PR #1233 introduced and #1233's fix excluded these paths to prevent.
|
|
*
|
|
* Two freshness checks depend on this list agreeing: `isWorkingTreeDirty`
|
|
* (analyze's up-to-date fast-path gate) and the per-file comparison behind
|
|
* `status`. They used to hold separate copies of it, so a path added to one
|
|
* silently became a permanent "stale" verdict in the other. One list, imported
|
|
* by both.
|
|
*/
|
|
|
|
/**
|
|
* Repository-root-relative. A directory entry covers everything beneath it;
|
|
* a file entry matches only itself. Prefix collisions are NOT matches —
|
|
* `.agentsrc` is an ordinary file, not part of the `.agents` tree.
|
|
*/
|
|
export const GITNEXUS_MANAGED_PATHS = [
|
|
'.gitnexus',
|
|
'.claude',
|
|
'.cursor',
|
|
'.agents',
|
|
'AGENTS.md',
|
|
'CLAUDE.md',
|
|
] as const;
|
|
|
|
/**
|
|
* Git pathspecs excluding {@link GITNEXUS_MANAGED_PATHS} from a `git status`
|
|
* run rooted at the repository. Patterns include `./` so they match only at
|
|
* the repo root: a slash-free `:(exclude)AGENTS.md` would also drop
|
|
* `docs/AGENTS.md`, which {@link isGitNexusManagedPath} does not treat as
|
|
* managed. Both forms are emitted per entry: the root path itself, and `/**`
|
|
* for directory contents.
|
|
*/
|
|
export const GITNEXUS_MANAGED_PATH_EXCLUDES: readonly string[] = GITNEXUS_MANAGED_PATHS.flatMap(
|
|
(managed) => [`:(exclude,glob)./${managed}`, `:(exclude,glob)./${managed}/**`],
|
|
);
|
|
|
|
/**
|
|
* True when a repository-relative path is GitNexus's own output. Mirrors the
|
|
* pathspec semantics above: root-relative, whole path segments only, so
|
|
* neither `.agentsrc` nor a nested `subdir/.agents/` is treated as managed.
|
|
*/
|
|
export const isGitNexusManagedPath = (relPath: string): boolean => {
|
|
const normalized = relPath.replace(/\\/g, '/');
|
|
return GITNEXUS_MANAGED_PATHS.some(
|
|
(managed) => normalized === managed || normalized.startsWith(`${managed}/`),
|
|
);
|
|
};
|