import { type CodegraphProcessRunner } from './codegraph-service.js'; import { applyCodegraphConfigRepair, CODEGRAPH_CONFIG_BACKUP_SUFFIX, repairCodegraphExclude, type CodegraphConfigRepairOutcome, type CodegraphConfigRepairPlan, type CodegraphExcludeRepairPlan } from './codegraph-config-repair-writer.js'; export { applyCodegraphConfigRepair, CODEGRAPH_CONFIG_BACKUP_SUFFIX, repairCodegraphExclude }; export type { CodegraphConfigRepairOutcome, CodegraphConfigRepairPlan, CodegraphExcludeRepairPlan }; export type CodegraphExcludeRepairReport = { /** True when the config was actually rewritten. */ readonly applied: boolean; /** Rules dropped from `exclude`. */ readonly rulesRemoved: readonly string[]; /** Distinct tracked source files the dropped rules had been hiding. */ readonly filesRecovered: number; /** * Absolute path of the rewritten config. Empty when nothing was written * AND the reads failed (there is no config to name). */ readonly configPath: string; /** * Byte-exact rollback copy (null when nothing was written). * * It is a rollback POINT, not a rollback: nothing in this seam reads it back. * Putting the config back is the separate, explicit * `peaks codegraph config-restore` verb, so this field is what that verb * would read — and its presence is the one guarantee that a restore is * possible at all. */ readonly backupPath: string | null; /** True when the post-repair `codegraph index` finished successfully. */ readonly reindexed: boolean; /** * True when the follow-up index was run with upstream's `--force`, i.e. * as a full rebuild that drops rows for files that no longer exist. An * incremental index cannot do that — see `CodegraphExcludeRepairOptions`. */ readonly forcedRebuild: boolean; /** * Non-null when the step could not run to completion (no git repo, * missing config, malformed config, upstream index failure, …). * Always reported, never swallowed — but never thrown either, so a * successful `peaks codegraph init` is never undone by it. */ readonly warning: string | null; }; export type CodegraphExcludeRepairOptions = { /** * When `false`, skip the follow-up `codegraph index` rebuild and * return `reindexed: false` (with no warning — nothing went wrong). * * Set by callers that run their OWN index immediately after this * step: the pre-dispatch preflight and the post-slice autorefresh * both call `init` → `index`, and an index is expensive enough * (5-30 s on this repo) that a fresh init must not pay for it twice. * * When `'force'`, run `codegraph index --force` instead: upstream's * `--force` is `clear()` + full re-index, and it is the ONLY documented * way to drop rows for files deleted in an earlier commit. Verified in * the installed upstream source (0.7.10): * * - `dist/bin/codegraph.js` → `index --force` calls `cg.clear()` then * `cg.indexAll()`; * - `dist/db/queries.js` `clear()` deletes unresolved_refs, edges, * nodes and files; * - plain `indexAll()` (`dist/extraction/index.js`) scans and upserts * every file but never removes a row, so an incremental index keeps * rows for paths that are gone; * - `codegraph sync` DOES delete them, but only for the deletions * `git status --porcelain` reports in the WORKING TREE. Measured on * this repo: all four dead rows are committed deletions, invisible to * `git status`, so `sync` would purge none of them. * * Cost note. The PARSE half of the old claim here was exactly true and * is kept: plain `indexAll()` already re-reads and re-parses EVERY file * (its only skip is `maxFileSize`). The PRICE half was wrong and is * corrected to the perf audit's measurements, because it is the sentence * a future reader would quote: `storeExtractionResult` * (`dist/extraction/index.js`) hash-skips all WRITES for unchanged files * in a plain `index`, so `--force` additionally pays a full re-insert of * every node and edge after `clear()`. Executed with the real binary on a * 2,100-file fixture, paired 5 runs: plain median 3,810 ms vs forced * 5,400 ms = +1,590 ms (+42 %), positive 5/5; on a copy of this repo's db, * `clear()` alone is 414/462/537 ms while clear+reinsert is 2.7-6.2 s. * "Forced" is a real cost, not a rounding error. * * That does NOT change the policy: the reason the automatic seams do not * force is policy, not cost. The advisory-by-default decision (user option * C) exists so that upgrading peaks-loop cannot change a downstream * project's cost profile, and purging dead rows is the caller's explicit * request instead. * * `'force'` changes ONLY the rebuild, never the config: it is the same * two-axis repair as `'exclude'`, followed by `cg.clear()` + `indexAll()` * instead of an incremental index. The config repair STAYS — that is what * makes the force mode worth its cost, because `include` has to be widened * before a rebuild can admit the files the config was dropping. * * Not a self-cancelling run, and that is a design decision rather than a * detail: a mode that wrote the repair and then restored the pre-repair bytes * would leave the config exactly as it found it, `peaks codegraph status` * would still report the gap, and exit 75 would never clear. Putting the * config BACK is the explicit `peaks codegraph config-restore` verb, which * reads the `.bak` this run leaves — an operator decision, not a side effect * of asking for a rebuild. */ readonly reindex?: boolean | 'force'; }; /** * Reconcile `projectRoot`'s config against its tracked files — drop the * `exclude` rules that block tracked source files — and rebuild the index so * the recovered files actually land in it. * * The reconciliation runs the config's OWN `include` filter first, exactly as * upstream applies it, so a rule that only blocks files the index would not * ingest anyway is not a violation. See the module header for what this seam * no longer does and why. * * This is the ONE shared "after upstream init" self-heal: the CLI's * fresh `peaks codegraph init`, the pre-dispatch preflight and the * post-slice autorefresh all call it, so a fresh clone cannot end up * with a peaks-loop marker stamped over an incomplete index that no * later `init` would ever repair. * * Never throws. Every failure becomes a populated `warning` field, so * the caller can surface it without the step being able to break the * command it is attached to — including the fail-soft preflight and * the never-throwing `refreshCodegraphAfterSlice`. */ export declare function repairCodegraphExcludeFromProject(projectRoot: string, runner?: CodegraphProcessRunner, options?: CodegraphExcludeRepairOptions): Promise;