peaks-loop 4.0.51 → 4.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/dist/cli/commands/baseline-commands.js +11 -1
- package/dist/cli/commands/codegraph-command-runtime.d.ts +28 -0
- package/dist/cli/commands/codegraph-command-runtime.js +72 -0
- package/dist/cli/commands/codegraph-commands.d.ts +2 -11
- package/dist/cli/commands/codegraph-commands.js +173 -228
- package/dist/cli/commands/codegraph-status-command.d.ts +22 -0
- package/dist/cli/commands/codegraph-status-command.js +299 -0
- package/dist/cli/commands/core/memory-command.js +6 -2
- package/dist/cli/commands/job-commands.js +121 -30
- package/dist/cli/commands/project-commands.js +13 -3
- package/dist/cli/commands/request-commands.js +19 -8
- package/dist/cli/commands/slice-commands.js +2 -2
- package/dist/services/artifacts/artifact-prerequisites.js +23 -1
- package/dist/services/codegraph/codegraph-autorefresh.d.ts +16 -0
- package/dist/services/codegraph/codegraph-autorefresh.js +51 -5
- package/dist/services/codegraph/codegraph-config-repair-writer.d.ts +88 -0
- package/dist/services/codegraph/codegraph-config-repair-writer.js +322 -0
- package/dist/services/codegraph/codegraph-exclude-integrity.d.ts +20 -2
- package/dist/services/codegraph/codegraph-exclude-integrity.js +24 -3
- package/dist/services/codegraph/codegraph-exclude-reconciler.d.ts +23 -2
- package/dist/services/codegraph/codegraph-exclude-reconciler.js +123 -12
- package/dist/services/codegraph/codegraph-exclude-repair.d.ts +109 -55
- package/dist/services/codegraph/codegraph-exclude-repair.js +249 -195
- package/dist/services/codegraph/codegraph-include-reconciler.d.ts +10 -0
- package/dist/services/codegraph/codegraph-include-reconciler.js +160 -0
- package/dist/services/codegraph/codegraph-index-integrity.d.ts +268 -0
- package/dist/services/codegraph/codegraph-index-integrity.js +471 -0
- package/dist/services/codegraph/codegraph-service.d.ts +54 -0
- package/dist/services/codegraph/codegraph-service.js +84 -1
- package/dist/services/doctor/doctor-service/checks/codegraph-exclude-integrity.js +19 -4
- package/dist/services/doctor/doctor-service/checks/codegraph-index-integrity.d.ts +54 -0
- package/dist/services/doctor/doctor-service/checks/codegraph-index-integrity.js +151 -0
- package/dist/services/doctor/doctor-service/checks/l3-orphan-sessions.js +10 -10
- package/dist/services/doctor/doctor-service/plugin-registry.js +2 -0
- package/dist/services/doctor/doctor-service/types.d.ts +25 -0
- package/dist/services/memory/project-memory-service/index/kind-dispatch.js +48 -13
- package/dist/services/memory/project-memory-service/index.d.ts +5 -3
- package/dist/services/memory/project-memory-service/index.js +2 -2
- package/dist/services/memory/project-memory-service/parsers/frontmatter.d.ts +15 -1
- package/dist/services/memory/project-memory-service/parsers/frontmatter.js +34 -6
- package/dist/services/memory/project-memory-service/parsers/markdown-pure.d.ts +27 -1
- package/dist/services/memory/project-memory-service/parsers/markdown-pure.js +92 -7
- package/dist/services/memory/project-memory-service/types.d.ts +86 -0
- package/dist/services/slice/slice-check-types.d.ts +1 -1
- package/dist/services/workspace/runtime-layout.d.ts +91 -0
- package/dist/services/workspace/runtime-layout.js +148 -0
- package/dist/services/workspace/workspace-claude-settings-materializer.js +14 -0
- package/package.json +6 -6
- package/scripts/clean-dist.mjs +15 -3
- package/scripts/sync-version.mjs +26 -4
- package/skills/bee/peaks-prd/SKILL.md +1 -1
- package/skills/bee/peaks-qa/references/qa-skill-presence.md +1 -1
- package/skills/bee/peaks-rd/references/skill-presence-and-title.md +1 -1
- package/skills/bee/peaks-sc/SKILL.md +1 -1
- package/skills/bee/peaks-txt/SKILL.md +3 -3
- package/skills/peaks-code/SKILL.md +1 -1
- package/skills/peaks-code/references/project-memory-loading.md +19 -1
- package/skills/peaks-code/references/step-11-memory-sediment.md +1 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// src/services/codegraph/codegraph-include-reconciler.ts
|
|
2
|
+
//
|
|
3
|
+
// Slice-002 of `2026-09-16-codegraph-index-integrity` — the INCLUDE axis
|
|
4
|
+
// of the config repair. It answers one question:
|
|
5
|
+
//
|
|
6
|
+
// "Which extensions does upstream's extractor support but upstream's own
|
|
7
|
+
// default `include` template never names, and which of those does THIS
|
|
8
|
+
// project's `include` still not admit?"
|
|
9
|
+
//
|
|
10
|
+
// Why this exists (the real defect, measured): upstream
|
|
11
|
+
// `@colbymchenry/codegraph` decides what to parse from its own
|
|
12
|
+
// `EXTENSION_MAP` (37 extensions in 0.7.10), but `init` writes a 32-entry
|
|
13
|
+
// `DEFAULT_CONFIG.include` template that names only 32 of them. Five
|
|
14
|
+
// supported extensions are therefore absent from every fresh config:
|
|
15
|
+
// `.mjs`, `.cjs`, `.pyw`, `.hxx`, `.rake`. Upstream's `mergeConfig` has no
|
|
16
|
+
// separate override channel — `config.json`'s `include` replaces the
|
|
17
|
+
// defaults wholesale — so a fresh clone indexes none of them while
|
|
18
|
+
// `peaks codegraph status` still prints `[OK] Index is up to date`. On this
|
|
19
|
+
// repo that was 31 tracked files (30 `.mjs` + 1 `.cjs`) absent from a
|
|
20
|
+
// 1220-row index. It is the same class of defect as upstream's default
|
|
21
|
+
// `exclude` template colliding with real source directories, which slice S2
|
|
22
|
+
// of `2026-09-12-codegraph-exclude-integrity` already self-heals at the
|
|
23
|
+
// `init` seam; the include axis was simply never reconciled.
|
|
24
|
+
//
|
|
25
|
+
// Genericity (binding — mirrors the exclude reconciler): no hardcoded
|
|
26
|
+
// extension list, no hardcoded rule names, no project-specific paths. The
|
|
27
|
+
// candidate set is COMPUTED from upstream's own two tables (`EXTENSION_MAP`
|
|
28
|
+
// in `dist/extraction/grammars.js`, `DEFAULT_CONFIG` in `dist/types.js`),
|
|
29
|
+
// and every candidate is confirmed against upstream's own decision pair
|
|
30
|
+
// (`isLanguageSupported(detectLanguage(...))` — the same two functions
|
|
31
|
+
// `extraction/index.js` calls). Upstream can add an extension tomorrow and
|
|
32
|
+
// this module picks it up with no edit here; the "five" above is a
|
|
33
|
+
// measurement, not a constant in the code.
|
|
34
|
+
//
|
|
35
|
+
// Additive, never clobbering: a project's `include` is append-only from
|
|
36
|
+
// here. No user entry is removed, reordered or rewritten, and an extension
|
|
37
|
+
// any existing entry already admits is left alone. Append-only is the same
|
|
38
|
+
// posture `codegraph-exclude-repair.ts` takes toward a third-party config
|
|
39
|
+
// file it edits.
|
|
40
|
+
//
|
|
41
|
+
// Scope: PURE (`normalizeCodegraphInclude`) plus ONE read-only adapter
|
|
42
|
+
// (`upstreamIncludeCandidateExtensions`, which reads the installed upstream
|
|
43
|
+
// package). Nothing in this module writes a file.
|
|
44
|
+
//
|
|
45
|
+
// NOTE FOR FUTURE EDITORS: glob literals contain the two-character
|
|
46
|
+
// sequence that ends a block comment, so every comment in this file uses
|
|
47
|
+
// `//` lines — INCLUDING the exported API documentation, which is why this
|
|
48
|
+
// file has no `/** ... */` blocks. Do not convert them.
|
|
49
|
+
import { createRequire } from 'node:module';
|
|
50
|
+
import { dirname, extname, join } from 'node:path';
|
|
51
|
+
import { compileCodegraphGlobs } from './codegraph-exclude-reconciler.js';
|
|
52
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
53
|
+
// Which extensions does this project's `include` already admit?
|
|
54
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
55
|
+
// The pattern upstream's own template uses for a bare extension: all 32
|
|
56
|
+
// entries of `DEFAULT_CONFIG.include` have exactly this shape, and they are
|
|
57
|
+
// matched with `picomatch(..., { dot: true })` — the same engine, and the
|
|
58
|
+
// same options, that `matchesCodegraphGlob` delegates to. So an appended
|
|
59
|
+
// pattern is indistinguishable in form from an upstream-authored one.
|
|
60
|
+
function includePatternForExtension(extension) {
|
|
61
|
+
return `**/*${extension}`;
|
|
62
|
+
}
|
|
63
|
+
// A synthetic path used ONLY to ask "does any existing rule admit a file
|
|
64
|
+
// with this extension". A root-level probe answers that question exactly
|
|
65
|
+
// for every pattern shape upstream itself writes, because `picomatch`'s
|
|
66
|
+
// trailing-slash-star-star prefix matches zero path segments (measured:
|
|
67
|
+
// the `.mjs` pattern matches both `probe.mjs` and `a/b/probe.mjs`).
|
|
68
|
+
//
|
|
69
|
+
// KNOWN PROXY LIMIT, stated rather than hidden: a path-narrowed rule such as
|
|
70
|
+
// a `src`-prefixed brace list of js/mjs does NOT match the root-level probe,
|
|
71
|
+
// so an extension admitted only under a subdirectory is treated as
|
|
72
|
+
// uncovered and the bare extension pattern is appended. That errs ADDITIVE —
|
|
73
|
+
// the index admits more tracked files, never fewer — and it is pinned by a
|
|
74
|
+
// test rather than left to be discovered. A false "already covered" cannot
|
|
75
|
+
// occur for any pattern upstream's template can produce, and if it did its
|
|
76
|
+
// only effect would be to leave the gap the inspector already reports.
|
|
77
|
+
function extensionProbePath(extension) {
|
|
78
|
+
return `codegraph-include-probe${extension}`;
|
|
79
|
+
}
|
|
80
|
+
// Compiled ONCE per rule, never per (candidate x rule) pair — see
|
|
81
|
+
// `compileCodegraphGlobs`. The `matchers` list is the include list the
|
|
82
|
+
// candidate is tested against: the caller's entries first, then the
|
|
83
|
+
// patterns this same pass has already decided to append, so a duplicate
|
|
84
|
+
// candidate cannot append twice without re-parsing the list each time
|
|
85
|
+
// (perf audit S10: the re-parse was 0.25 / 2.15 / 23.4 / 234.4 ms at
|
|
86
|
+
// 32 / 320 / 3,200 / 32,000 rules, plus a spread array per candidate).
|
|
87
|
+
function isExtensionAdmitted(extension, matchers) {
|
|
88
|
+
const probe = extensionProbePath(extension);
|
|
89
|
+
return matchers.some((matcher) => matcher.matchesAny(probe));
|
|
90
|
+
}
|
|
91
|
+
// Pure: given the current `include` list and the extensions upstream
|
|
92
|
+
// supports but its own template omits, return the list with the uncovered
|
|
93
|
+
// ones appended. No fs, no clock, no serialization.
|
|
94
|
+
//
|
|
95
|
+
// The result is always a SUPERSET of the input, in the input's order, so a
|
|
96
|
+
// caller can never remove or reorder a user entry. Appending an extension
|
|
97
|
+
// the list already admits is a no-op, which is what makes the whole
|
|
98
|
+
// normalization idempotent: feeding the repaired list back in yields
|
|
99
|
+
// `changed: false`.
|
|
100
|
+
//
|
|
101
|
+
// Candidates are de-duplicated by their EFFECT, not by string equality:
|
|
102
|
+
// each candidate is tested against the input list PLUS the patterns this
|
|
103
|
+
// call has already appended, so a duplicate candidate cannot append twice.
|
|
104
|
+
export function normalizeCodegraphInclude(input) {
|
|
105
|
+
const addedPatterns = [];
|
|
106
|
+
// The include list as this pass sees it, compiled once. Appending a
|
|
107
|
+
// pattern extends the list by ONE compiled rule instead of re-parsing
|
|
108
|
+
// every entry on the next candidate (see `isExtensionAdmitted`).
|
|
109
|
+
const matchers = [compileCodegraphGlobs(input.include)];
|
|
110
|
+
for (const candidate of input.candidateExtensions) {
|
|
111
|
+
const extension = candidate.startsWith('.') ? candidate : `.${candidate}`;
|
|
112
|
+
if (isExtensionAdmitted(extension, matchers)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const pattern = includePatternForExtension(extension);
|
|
116
|
+
addedPatterns.push(pattern);
|
|
117
|
+
matchers.push(compileCodegraphGlobs([pattern]));
|
|
118
|
+
}
|
|
119
|
+
if (addedPatterns.length === 0) {
|
|
120
|
+
return { changed: false, include: input.include, addedPatterns: [] };
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
changed: true,
|
|
124
|
+
include: [...input.include, ...addedPatterns],
|
|
125
|
+
addedPatterns
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
let cachedCandidateExtensions = null;
|
|
129
|
+
// The extensions upstream's extractor supports but its own default
|
|
130
|
+
// `include` template never names, as dotted extensions — measured against
|
|
131
|
+
// the installed `@colbymchenry/codegraph` 0.7.10 as `.mjs`, `.cjs`,
|
|
132
|
+
// `.pyw`, `.hxx`, `.rake`, in that order.
|
|
133
|
+
//
|
|
134
|
+
// Derived entirely from upstream's own data:
|
|
135
|
+
//
|
|
136
|
+
// 1. `EXTENSION_MAP` keys are the extension universe the extractor knows.
|
|
137
|
+
// 2. The extensions upstream's template already names are read off
|
|
138
|
+
// `DEFAULT_CONFIG.include` — the entry's own extension, so the
|
|
139
|
+
// comparison is extension-to-extension and cannot be confused by a
|
|
140
|
+
// template that switches glob syntax.
|
|
141
|
+
// 3. A candidate is kept only when upstream's own support decision
|
|
142
|
+
// accepts it, so a table entry with no grammar behind it is never
|
|
143
|
+
// repaired into the config.
|
|
144
|
+
//
|
|
145
|
+
// Returns the same array on every call (module-level cache); the two
|
|
146
|
+
// modules only define tables and functions, so the load is cheap and
|
|
147
|
+
// Node's `require` cache makes later calls free.
|
|
148
|
+
export function upstreamUnnamedIncludeExtensions() {
|
|
149
|
+
if (cachedCandidateExtensions === null) {
|
|
150
|
+
const require = createRequire(import.meta.url);
|
|
151
|
+
const packageJsonPath = require.resolve('@colbymchenry/codegraph/package.json');
|
|
152
|
+
const distDir = join(dirname(packageJsonPath), 'dist');
|
|
153
|
+
const types = require(join(distDir, 'types.js'));
|
|
154
|
+
const grammars = require(join(distDir, 'extraction', 'grammars.js'));
|
|
155
|
+
const namedByTemplate = new Set(types.DEFAULT_CONFIG.include.map((entry) => extname(entry).toLowerCase()));
|
|
156
|
+
cachedCandidateExtensions = Object.keys(grammars.EXTENSION_MAP).filter((extension) => !namedByTemplate.has(extension.toLowerCase()) &&
|
|
157
|
+
grammars.isLanguageSupported(grammars.detectLanguage(`probe${extension}`)));
|
|
158
|
+
}
|
|
159
|
+
return cachedCandidateExtensions;
|
|
160
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { type ReadCodegraphExcludeConfig, type ReadTrackedFiles } from './codegraph-exclude-reconciler.js';
|
|
2
|
+
/**
|
|
3
|
+
* Exit code `peaks codegraph status` uses when the index itself is
|
|
4
|
+
* incomplete or stale — distinct from `CODEGRAPH_INTEGRITY_EXIT_CODE` (74,
|
|
5
|
+
* the exclude-rule gate) and from `CODEGRAPH_INIT_CONFLICT_EXIT_CODE` (73).
|
|
6
|
+
*
|
|
7
|
+
* Why distinct rather than reusing 74: the two gates have different
|
|
8
|
+
* REMEDIATIONS. 74 means "these `exclude` rules must be dropped", and a CI
|
|
9
|
+
* job keyed on 74 already knows to run `repair-exclude`. 75 means "the
|
|
10
|
+
* index content does not match the repository — a supported tracked file
|
|
11
|
+
* is missing from it, or it holds rows for files that are gone". Folding
|
|
12
|
+
* that into 74 would silently re-point an existing consumer at a different
|
|
13
|
+
* fix. When BOTH gates fire, 74 wins (the exclude gap is the upstream
|
|
14
|
+
* cause; repairing it and rebuilding also clears staleness).
|
|
15
|
+
*
|
|
16
|
+
* NOTE (2026-09-16 policy change): 75 is only reachable in STRICT mode.
|
|
17
|
+
* See `isCodegraphIndexStrictMode`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CODEGRAPH_INDEX_INTEGRITY_EXIT_CODE = 75;
|
|
20
|
+
/**
|
|
21
|
+
* Exit code for "the index axis could not be measured at all" — the db is
|
|
22
|
+
* present but unreadable, or its schema no longer has the `files` table
|
|
23
|
+
* (an upstream bump), or `git ls-files` / the config read failed.
|
|
24
|
+
*
|
|
25
|
+
* Distinct from BOTH 0 and 75 on purpose, and it applies in every mode
|
|
26
|
+
* including the advisory default:
|
|
27
|
+
*
|
|
28
|
+
* - 0 would say "I checked and it is fine". It does not.
|
|
29
|
+
* - 75 would say "I checked and the index does not cover the
|
|
30
|
+
* repository", which asserts a measurement that never happened.
|
|
31
|
+
*
|
|
32
|
+
* Why it is not merely advisory (the user's option C covers `gap`, not
|
|
33
|
+
* this): option C exists so that upgrading peaks-loop cannot turn a
|
|
34
|
+
* *healthy* project red — the three downstream triggers it names (a
|
|
35
|
+
* tracked `.mjs`, an un-purged dead row, a deliberately narrowed
|
|
36
|
+
* `include`) are all `gap`-class. "Could not read my own input" is never a
|
|
37
|
+
* healthy-project condition: it requires `.codegraph/codegraph.db` to be
|
|
38
|
+
* present but unreadable, and `.codegraph/` is gitignored, so a downstream
|
|
39
|
+
* CI checkout normally has no index at all and reports `not-applicable`
|
|
40
|
+
* (exit 0, no output). This is the exact failure class
|
|
41
|
+
* `codegraph-exclude-reconciler.ts:76-82` documents as the reason that
|
|
42
|
+
* module exists.
|
|
43
|
+
*/
|
|
44
|
+
export declare const CODEGRAPH_INDEX_UNEVALUABLE_EXIT_CODE = 76;
|
|
45
|
+
/**
|
|
46
|
+
* The one command that repairs what this axis detects (slice-002). Exported
|
|
47
|
+
* as a constant rather than spelled out at each site so the human line, the
|
|
48
|
+
* doctor message and the JSON `nextActions` cannot name three different
|
|
49
|
+
* things: the renderer below, the doctor check and the CLI envelope all
|
|
50
|
+
* interpolate this value.
|
|
51
|
+
*
|
|
52
|
+
* It repairs BOTH axes in one run — `include` normalization, `exclude` rule
|
|
53
|
+
* drops against the normalized include, then a FORCED index rebuild (the
|
|
54
|
+
* only upstream path that drops rows for files deleted in an earlier
|
|
55
|
+
* commit; see `CodegraphExcludeRepairOptions.reindex`).
|
|
56
|
+
*/
|
|
57
|
+
export declare const CODEGRAPH_REPAIR_INDEX_COMMAND = "peaks codegraph repair-index --project <root>";
|
|
58
|
+
/**
|
|
59
|
+
* Opt-in switch for the user's option C decision (advisory by default,
|
|
60
|
+
* blocking on request). Set `PEAKS_CODEGRAPH_INDEX_STRICT=1` (or `true`)
|
|
61
|
+
* to make a detected index gap block: `status` exits 75 and the doctor
|
|
62
|
+
* check loses its `severity: 'warning'` tag and flips the doctor exit code.
|
|
63
|
+
*
|
|
64
|
+
* Why an environment variable rather than a config key or a CLI flag:
|
|
65
|
+
*
|
|
66
|
+
* - ONE mechanism covers both consumers. `peaks codegraph status` and
|
|
67
|
+
* `peaks doctor` are separate command surfaces; a CLI flag would have
|
|
68
|
+
* to be threaded through the doctor's option plumbing as well, and the
|
|
69
|
+
* default doctor probe takes no arguments.
|
|
70
|
+
* - CI is where the need lives, and CI sets environment variables.
|
|
71
|
+
* - A config key would have to live in the gitignored
|
|
72
|
+
* `.codegraph/config.json` (upstream's file, which this slice must
|
|
73
|
+
* never write) — so it would not survive a clone and could not
|
|
74
|
+
* configure a CI job at all.
|
|
75
|
+
* - It writes no state, so it does not weaken the read-only contract.
|
|
76
|
+
*
|
|
77
|
+
* Discoverability: the advisory warning text names this variable
|
|
78
|
+
* verbatim, so an operator who wants blocking is told how to get it at
|
|
79
|
+
* the moment they see the finding.
|
|
80
|
+
*/
|
|
81
|
+
export declare const CODEGRAPH_INDEX_STRICT_ENV_VAR = "PEAKS_CODEGRAPH_INDEX_STRICT";
|
|
82
|
+
/** True when the project opted in to blocking index-gap verdicts. */
|
|
83
|
+
export declare function isCodegraphIndexStrictMode(env?: Readonly<Record<string, string | undefined>>): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* The four outcomes of the index axis, kept apart so that no consumer
|
|
86
|
+
* that CAN carry four outcomes collapses two:
|
|
87
|
+
*
|
|
88
|
+
* - `clean` — measured, nothing wrong.
|
|
89
|
+
* - `gap` — measured, the index does not cover the repository.
|
|
90
|
+
* - `not-evaluated` — the axis was attempted and FAILED (unreadable db,
|
|
91
|
+
* schema drift, no git work tree, malformed/missing
|
|
92
|
+
* config). The index is NOT known to be fine.
|
|
93
|
+
* - `not-applicable`— there is no index here at all (no `codegraph.db`):
|
|
94
|
+
* the pre-init / dangling state, which is not a defect.
|
|
95
|
+
*
|
|
96
|
+
* `not-evaluated` and `not-applicable` both used to be `null` in the
|
|
97
|
+
* machine envelope, which is how "I could not check" came to be reported
|
|
98
|
+
* identically to "there is nothing to check".
|
|
99
|
+
*
|
|
100
|
+
* SCOPE OF THE CLAIM (narrowed under R12-2 — the earlier wording, "no
|
|
101
|
+
* consumer can collapse two of them", was overbroad). This module keeps
|
|
102
|
+
* all four apart, and so do `peaks codegraph status`'s two channels (the
|
|
103
|
+
* `[FAIL]`/`[WARN]` tags and `indexIntegrityVerdict` + the exit codes 0 /
|
|
104
|
+
* 75 / 76). The DOCTOR does not: its check shape is `{ok, severity?}`
|
|
105
|
+
* (legacy `DoctorCheck`, kept back-compatible on purpose), so
|
|
106
|
+
* `not-evaluated` and an advisory `gap` are BOTH `ok:false,
|
|
107
|
+
* severity:'warning'` and are told apart by message text alone — see
|
|
108
|
+
* `doctor-service/checks/codegraph-index-integrity.ts`. That collapse is
|
|
109
|
+
* recorded, not fixed: neither state reads as `ok:true`, so the invariant
|
|
110
|
+
* this axis exists for ("could not evaluate" must never pass as "verified
|
|
111
|
+
* clean") still holds there, and in the advisory default neither state
|
|
112
|
+
* moves the doctor exit code — so no exit-code consumer is misled by it.
|
|
113
|
+
* Under `PEAKS_CODEGRAPH_INDEX_STRICT=1` the two ARE separated in the
|
|
114
|
+
* machine fields (`severity` survives on `not-evaluated`, is dropped from
|
|
115
|
+
* `gap`), which is pinned by a test.
|
|
116
|
+
*/
|
|
117
|
+
export type CodegraphIndexIntegrityVerdict = 'clean' | 'gap' | 'not-evaluated' | 'not-applicable';
|
|
118
|
+
/**
|
|
119
|
+
* Fold the inspected report (null when there is no index to inspect) and
|
|
120
|
+
* the caught failure (null when nothing threw) into one verdict. This is
|
|
121
|
+
* the single place the four outcomes are distinguished, so a caller
|
|
122
|
+
* cannot re-derive them differently.
|
|
123
|
+
*/
|
|
124
|
+
export declare function resolveCodegraphIndexIntegrityVerdict(report: CodegraphIndexIntegrityReport | null, warning: string | null): CodegraphIndexIntegrityVerdict;
|
|
125
|
+
/**
|
|
126
|
+
* The exit code the index axis contributes, or `null` when it
|
|
127
|
+
* contributes none (clean / not-applicable → the caller's exit code is
|
|
128
|
+
* left alone).
|
|
129
|
+
*/
|
|
130
|
+
export declare function codegraphIndexIntegrityExitCode(verdict: CodegraphIndexIntegrityVerdict, strict: boolean): number | null;
|
|
131
|
+
export type CodegraphIndexIntegrityReport = {
|
|
132
|
+
/** Absolute path of the inspected `.codegraph/config.json`. */
|
|
133
|
+
readonly configPath: string;
|
|
134
|
+
/** Absolute path of the inspected index database. */
|
|
135
|
+
readonly databasePath: string;
|
|
136
|
+
/** True when either axis is non-empty. `[OK]` must not be printed then. */
|
|
137
|
+
readonly gap: boolean;
|
|
138
|
+
/** Git-tracked files upstream's extractor would ingest (any extension). */
|
|
139
|
+
readonly trackedSourceCount: number;
|
|
140
|
+
/** Of those, the ones the config's `include` globs admit. */
|
|
141
|
+
readonly admittedTrackedCount: number;
|
|
142
|
+
/** Class ① — supported tracked files `include` does not admit. */
|
|
143
|
+
readonly includeGap: readonly string[];
|
|
144
|
+
/** Rows in the index's `files` table. */
|
|
145
|
+
readonly indexedFileCount: number;
|
|
146
|
+
/** Class ② — index rows whose path no longer exists on disk. */
|
|
147
|
+
readonly deadRows: readonly string[];
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Everything `inspectCodegraphIndexIntegrityFrom` needs, already resolved.
|
|
151
|
+
* Pure input: no fs, no spawn, no clock — the adapters below supply it.
|
|
152
|
+
*/
|
|
153
|
+
export type CodegraphIndexIntegrityInput = {
|
|
154
|
+
readonly configPath: string;
|
|
155
|
+
readonly databasePath: string;
|
|
156
|
+
readonly trackedFiles: readonly string[];
|
|
157
|
+
readonly include: readonly string[];
|
|
158
|
+
/** Project-relative paths carried by the index's `files` table. */
|
|
159
|
+
readonly indexedPaths: readonly string[];
|
|
160
|
+
/** True when upstream's extractor supports `filePath`'s language. */
|
|
161
|
+
readonly supportsPath: (filePath: string) => boolean;
|
|
162
|
+
/** True when a project-relative index path still exists on disk. */
|
|
163
|
+
readonly pathExists: (projectRelativePath: string) => boolean;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Pure fold over already-resolved data. Both axes are set differences, so
|
|
167
|
+
* neither can be satisfied by a self-consistency assertion: axis ① compares
|
|
168
|
+
* git's tracked set against the `include` matcher, axis ② compares the
|
|
169
|
+
* index's own rows against the filesystem.
|
|
170
|
+
*/
|
|
171
|
+
export declare function inspectCodegraphIndexIntegrityFrom(input: CodegraphIndexIntegrityInput): CodegraphIndexIntegrityReport;
|
|
172
|
+
/** The upstream decision, verbatim: detect the language, then ask if it has a grammar. */
|
|
173
|
+
export declare function upstreamSupportsPath(filePath: string): boolean;
|
|
174
|
+
/**
|
|
175
|
+
* Per-call, bounded replacement for the per-row `existsSync` above.
|
|
176
|
+
*
|
|
177
|
+
* WHY: the fold calls `pathExists` once per index row (`inspectCodegraph
|
|
178
|
+
* IndexIntegrityFrom`), so the gate is O(rows) full-path stats at ~13.5 µs
|
|
179
|
+
* each — 35 ms at 1.2k rows, 1,923 ms at 100x. It is unbounded in the size
|
|
180
|
+
* of the index. What is replaced is the COST, not the authority: a row is
|
|
181
|
+
* confirmed PRESENT by looking its basename up in one cached listing of its
|
|
182
|
+
* parent directory, so the number of filesystem calls is bounded by the
|
|
183
|
+
* number of DISTINCT DIRECTORIES the index names — which is bounded by the
|
|
184
|
+
* repository, not by the index.
|
|
185
|
+
*
|
|
186
|
+
* A listing may only answer `true`, and only for an entry whose dirent is
|
|
187
|
+
* positively a plain file or a plain directory. For exactly those entries,
|
|
188
|
+
* "the name is in `readdir`" and "`existsSync` on the joined path is true"
|
|
189
|
+
* cannot disagree. Everything else falls through to
|
|
190
|
+
* `codegraphIndexPathExists` — the old implementation, verbatim — so the
|
|
191
|
+
* classes this cache cannot decide are decided exactly as they always were:
|
|
192
|
+
*
|
|
193
|
+
* - a symlink or junction entry (`isSymbolicLink()`, Windows included:
|
|
194
|
+
* a junction reports `isDirectory() === false`), because a BROKEN link
|
|
195
|
+
* is listed by `readdir` and is absent from disk;
|
|
196
|
+
* - a case-differing path on a case-insensitive filesystem — the listing
|
|
197
|
+
* carries the on-disk spelling, so `SRC/OK.TS` misses and the stat
|
|
198
|
+
* decides (true on Windows, false on Linux, exactly as before);
|
|
199
|
+
* - a path naming a directory, or any non-file special entry;
|
|
200
|
+
* - a parent that is missing, unreadable, or not a directory at all
|
|
201
|
+
* (`readdir` throws → `null`, memoized so the failure costs one call);
|
|
202
|
+
* - a trailing-slash or empty row, and a project root that does not exist.
|
|
203
|
+
*
|
|
204
|
+
* The cache lives for ONE `inspectCodegraphIndexIntegrity` call, so a
|
|
205
|
+
* second command re-reads the tree and cannot be served a stale listing.
|
|
206
|
+
* Within a call, a listing taken before a concurrent delete is the only
|
|
207
|
+
* divergence from the old code — both implementations race the filesystem,
|
|
208
|
+
* and neither holds a snapshot.
|
|
209
|
+
*/
|
|
210
|
+
export declare function createCodegraphIndexPathExists(): (projectRoot: string, projectRelativePath: string) => boolean;
|
|
211
|
+
/**
|
|
212
|
+
* Injection seam for `inspectCodegraphIndexIntegrity`.
|
|
213
|
+
*
|
|
214
|
+
* `trackedFiles` / `config` are the ALREADY-READ shared inputs (perf audit
|
|
215
|
+
* F1) — the CLI reads them once and hands the same values to both codegraph
|
|
216
|
+
* axes, so the `git ls-files` spawn, the config read and the `include`
|
|
217
|
+
* glob compilation happen once per command instead of twice. They are
|
|
218
|
+
* values, not reader functions, because that is what the caller has: the
|
|
219
|
+
* read has already happened by the time either axis runs.
|
|
220
|
+
*
|
|
221
|
+
* Both are READ-MARKED (code review R4-1): only a value returned by the
|
|
222
|
+
* readers is admissible. An explicit `[]` — which the seam used to accept
|
|
223
|
+
* and which silently meant "nothing is tracked", erasing every include-gap
|
|
224
|
+
* — is now a compile error and a run-time throw. `undefined`/omitted still
|
|
225
|
+
* means "read it yourself", exactly as before.
|
|
226
|
+
*
|
|
227
|
+
* The three remaining fields are genuine per-call adapters, used by tests
|
|
228
|
+
* to drive the fold without touching a real db or the real oracle.
|
|
229
|
+
*/
|
|
230
|
+
export type CodegraphIndexIntegrityDeps = {
|
|
231
|
+
readonly trackedFiles?: ReadTrackedFiles | undefined;
|
|
232
|
+
readonly config?: ReadCodegraphExcludeConfig | undefined;
|
|
233
|
+
readonly readIndexedPaths?: (projectRoot: string) => readonly string[];
|
|
234
|
+
readonly supportsPath?: (filePath: string) => boolean;
|
|
235
|
+
readonly pathExists?: (projectRoot: string, projectRelativePath: string) => boolean;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Read-only entry point: resolve git's tracked files, the config's
|
|
239
|
+
* `include` globs and the index's own rows from disk, then fold them into
|
|
240
|
+
* one report. Throws (never silently degrades) when the project is not a
|
|
241
|
+
* git work tree, the config is missing/malformed, or the index is absent —
|
|
242
|
+
* callers that must stay alive (`status`, doctor) catch and surface it.
|
|
243
|
+
*/
|
|
244
|
+
export declare function inspectCodegraphIndexIntegrity(projectRoot: string, deps?: CodegraphIndexIntegrityDeps): CodegraphIndexIntegrityReport;
|
|
245
|
+
/**
|
|
246
|
+
* Human-readable detail lines for a gapped report, grouped by axis so an
|
|
247
|
+
* operator can tell which defect they have (and whether they have both).
|
|
248
|
+
*
|
|
249
|
+
* Returns an empty array for a clean report — the caller decides whether
|
|
250
|
+
* "clean" is worth printing at all.
|
|
251
|
+
*
|
|
252
|
+
* `blocking` is the user's option C switch, and it changes the TAG, not
|
|
253
|
+
* the finding: advisory (the default) prints `[WARN]` and the command
|
|
254
|
+
* exits 0; strict prints `[FAIL]` and the command exits 75. The verdict
|
|
255
|
+
* word is chosen here rather than by the caller so the two channels
|
|
256
|
+
* cannot disagree about the same report.
|
|
257
|
+
*
|
|
258
|
+
* The remediation sentence NAMES the real command (`peaks codegraph
|
|
259
|
+
* repair-index`). Slice-001 deliberately named none, because naming a
|
|
260
|
+
* command that does not exist yet reproduces the exact failure this gate
|
|
261
|
+
* exists to prevent (an operator following a hint into "command not
|
|
262
|
+
* found"). Slice-002 shipped that command, so the obligation recorded in
|
|
263
|
+
* slice-001's design decision 4 is discharged here — and the name is
|
|
264
|
+
* exported as a constant so the renderer, the doctor message and the
|
|
265
|
+
* error envelope cannot drift from the command that is actually
|
|
266
|
+
* registered.
|
|
267
|
+
*/
|
|
268
|
+
export declare function renderCodegraphIndexIntegrityLines(report: CodegraphIndexIntegrityReport, blocking: boolean): readonly string[];
|