llmnav 0.7.4 → 0.8.0
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 +6 -0
- package/README.md +3 -3
- package/docs/api.md +1 -1
- package/docs/cli.md +1 -1
- package/docs/configuration.md +22 -0
- package/docs/quickstart.md +1 -1
- package/package.json +1 -1
- package/schema/config.schema.json +28 -0
- package/src/agents.js +1 -1
- package/src/audit.js +38 -6
- package/src/cli.js +5 -1
- package/src/config.js +41 -0
- package/src/index.d.ts +10 -0
- package/src/spec.js +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@ The npm package follows Semantic Versioning. The `llmnav/N` source protocol is v
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.8.0] — 2026-08-15
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
* Added exact-path audit dispositions with mandatory review reasons, deterministic suppression, and stale-decision reporting so intentional non-cards do not reappear without becoming hidden permanent ignores.
|
|
14
|
+
|
|
9
15
|
## [0.7.4] — 2026-08-14
|
|
10
16
|
|
|
11
17
|
### Fixed
|
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ npx llmnav init --agents all --package-scripts
|
|
|
47
47
|
|
|
48
48
|
Initialization is explicit. LLMNav never edits a consumer repository from an npm `postinstall` script. Use `--agents none` when only the machine-readable control directory is desired.
|
|
49
49
|
|
|
50
|
-
Before writing cards, run `npx llmnav audit`. It ranks likely architectural boundaries and explains each score. The command never edits source and remains advisory unless `--fail-on high`, `medium`, or `low` is selected. Review the candidates: a high score is evidence to inspect a file, not permission to generate semantic meaning automatically.
|
|
50
|
+
Before writing cards, run `npx llmnav audit`. It ranks likely architectural boundaries and explains each score. The command never edits source and remains advisory unless `--fail-on high`, `medium`, or `low` is selected. Review the candidates: a high score is evidence to inspect a file, not permission to generate semantic meaning automatically. For a reviewed false positive or implementation detail, add its exact path and a concrete reason to `audit.dispositions`; stale decisions remain visible instead of becoming permanent hidden ignores.
|
|
51
51
|
|
|
52
52
|
## Add the first card
|
|
53
53
|
|
|
@@ -253,7 +253,7 @@ Do not annotate trivial getters, generated files, obvious wrappers, every test f
|
|
|
253
253
|
|
|
254
254
|
## Current implementation boundary
|
|
255
255
|
|
|
256
|
-
|
|
256
|
+
The deterministic coverage audit prioritizes root and nested-package entrypoints, structural boundaries, persistent artifact filename protocols, versioned schema literals, Rust/Tauri runtime signals, TypeScript Tauri invoke adapters, and high fan-in modules. It suppresses declaration files, dependency caches, test support code, simple barrels, and low-fan-in broad utilities. It suggests narrow coverage rules but never writes cards or invents semantic roles. Exact reviewed dispositions suppress known non-boundaries while stale dispositions expose obsolete decisions. Use `llmnav audit --summary --json` for a compact automation result or `llmnav audit --json --output .llmnav/audit.json` to keep the full candidate report out of captured stdout.
|
|
257
257
|
|
|
258
258
|
LLMNav does not discover sibling repositories automatically and does not ship an MCP server, embedding database, hosted service, SCIP generator, or complete language-aware call graph. External tools may export the documented compact graph-input schema. Generated structure never writes derived edges into source cards.
|
|
259
259
|
|
|
@@ -294,7 +294,7 @@ The project uses the Node.js standard library and built-in test runner. There is
|
|
|
294
294
|
|
|
295
295
|
## Status
|
|
296
296
|
|
|
297
|
-
LLMNav is an experimental protocol and a usable v0.
|
|
297
|
+
LLMNav is an experimental protocol and a usable v0.8 CLI. The source format remains `llmnav/1`; npm package changes and source-grammar changes are versioned independently.
|
|
298
298
|
|
|
299
299
|
## License
|
|
300
300
|
|
package/docs/api.md
CHANGED
|
@@ -75,7 +75,7 @@ for (const candidate of result.candidates) {
|
|
|
75
75
|
if (auditHasFindings(result, "high")) process.exitCode = 1;
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
`auditProject` is read-only and returns schemaVersion 1 data with repository-relative paths and deterministic ordering. Candidate signals are structural heuristics, not generated semantic meaning. Consumers should review high and medium candidates before adding a card and should never turn the suggested coverage rule into automatic source annotation.
|
|
78
|
+
`auditProject` is read-only and returns schemaVersion 1 data with repository-relative paths and deterministic ordering. Candidate signals are structural heuristics, not generated semantic meaning. Exact reviewed decisions from `audit.dispositions` are returned separately with `suppressed` or `stale` status; `auditHasFindings` considers only active candidates. Consumers should review high and medium candidates before adding a card and should never turn the suggested coverage rule into automatic source annotation.
|
|
79
79
|
|
|
80
80
|
## Generate incrementally and transactionally
|
|
81
81
|
|
package/docs/cli.md
CHANGED
|
@@ -39,7 +39,7 @@ Reads the selected source set and ranks files that lack file or module cards. Si
|
|
|
39
39
|
|
|
40
40
|
The command never modifies source, configuration, registries, or generated caches. Its output is advisory and exits with status 0 by default. `--fail-on high` fails only for high candidates; `medium` fails for high or medium; `low` fails for any candidate. Invalid thresholds exit with status 2.
|
|
41
41
|
|
|
42
|
-
JSON output uses schemaVersion 1, repository-relative paths, deterministic ordering, explainable `reasons` and `signals`, and a path-specific `suggestedCoverageRule` for high and medium candidates. `--summary` omits candidate details. `--output <path>` writes the selected report inside the repository and emits only a compact confirmation envelope to stdout; escaping paths and symbolic-link traversal are rejected. Suggestions require human or agent review: LLMNav cannot infer a durable role, ownership boundary, invariant, or semantic ID from structure alone.
|
|
42
|
+
JSON output uses schemaVersion 1, repository-relative paths, deterministic ordering, explainable `reasons` and `signals`, and a path-specific `suggestedCoverageRule` for high and medium candidates. Reviewed `audit.dispositions` appear separately as `suppressed` or `stale`; only active candidates participate in `--fail-on`. Stale reasons are `file-not-scanned`, `already-carded`, or `not-a-candidate`. `--summary` omits candidate and disposition details but retains their counters. `--output <path>` writes the selected report inside the repository and emits only a compact confirmation envelope to stdout; escaping paths and symbolic-link traversal are rejected. Suggestions require human or agent review: LLMNav cannot infer a durable role, ownership boundary, invariant, or semantic ID from structure alone.
|
|
43
43
|
|
|
44
44
|
## `llmnav check`
|
|
45
45
|
|
package/docs/configuration.md
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"excludeDirectories": ["node_modules", "dist", "target"],
|
|
15
15
|
"excludeFiles": ["*.generated.*", "*.gen.*"],
|
|
16
16
|
"coverageRules": [],
|
|
17
|
+
"audit": {
|
|
18
|
+
"dispositions": []
|
|
19
|
+
},
|
|
17
20
|
"graph": {
|
|
18
21
|
"indexFiles": []
|
|
19
22
|
},
|
|
@@ -90,6 +93,25 @@ A coverage rule checks files already selected by `sourceRoots` and extension fil
|
|
|
90
93
|
|
|
91
94
|
Run `llmnav audit` to obtain path-specific candidate rules. A suggestion is not applied automatically and should be accepted only after the file's durable responsibility is confirmed. This separation prevents structural heuristics from creating vague or stale semantic cards.
|
|
92
95
|
|
|
96
|
+
## Audit dispositions
|
|
97
|
+
|
|
98
|
+
When a candidate has been reviewed and intentionally does not need a semantic card, record that decision instead of repeatedly ignoring it:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"audit": {
|
|
103
|
+
"dispositions": [
|
|
104
|
+
{
|
|
105
|
+
"path": "src/adapters/local-cache.ts",
|
|
106
|
+
"reason": "This private adapter mirrors its carded module contract and owns no durable policy."
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Each disposition targets one exact normalized repository-relative path. Globs, trailing slashes, backslashes, duplicate paths, and reasons shorter than 12 characters are rejected. A matching candidate is omitted from the active queue and reported as `suppressed`. If the file disappears, gains card coverage, or stops qualifying as a candidate, the disposition is reported as `stale` with a machine-readable reason so obsolete decisions remain visible.
|
|
114
|
+
|
|
93
115
|
## Lint profile
|
|
94
116
|
|
|
95
117
|
Byte and field-count limits prevent semantic cards from becoming mini-documents. `maxSemanticRatio` produces a warning after the scanned source exceeds `minimumSourceBytesForRatio`.
|
package/docs/quickstart.md
CHANGED
|
@@ -23,7 +23,7 @@ Start with high and medium candidates. The audit explains whether a file is a pa
|
|
|
23
23
|
|
|
24
24
|
In Go repositories, candidates represent packages. Full imports below a repository-contained `go.mod` contribute package fan-in, `cmd/*/main.go` is treated as a command entrypoint, and `_test.go` files do not create separate production candidates. Put one `module` card on a durable package representative; do not repeat the same package role on every Go file.
|
|
25
25
|
|
|
26
|
-
After accepting a candidate, write its durable meaning by inspecting the source, add a narrow `coverageRules` entry for that exact boundary, and add a real task-language query to `.llmnav/eval/queries.jsonl`. Use `npx llmnav audit --fail-on high` in CI only after the initial review.
|
|
26
|
+
After accepting a candidate, write its durable meaning by inspecting the source, add a narrow `coverageRules` entry for that exact boundary, and add a real task-language query to `.llmnav/eval/queries.jsonl`. If review confirms that a candidate owns no durable navigation responsibility, add its exact path and a concrete reason to `audit.dispositions`. Never use a glob to dismiss a directory. The audit suppresses the reviewed candidate but reports the entry as stale when the file or its classification changes. Use `npx llmnav audit --fail-on high` in CI only after the initial review.
|
|
27
27
|
|
|
28
28
|
## Annotate a module boundary
|
|
29
29
|
|
package/package.json
CHANGED
|
@@ -101,6 +101,34 @@
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
|
+
"audit": {
|
|
105
|
+
"type": "object",
|
|
106
|
+
"additionalProperties": false,
|
|
107
|
+
"properties": {
|
|
108
|
+
"dispositions": {
|
|
109
|
+
"type": "array",
|
|
110
|
+
"items": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"required": [
|
|
113
|
+
"path",
|
|
114
|
+
"reason"
|
|
115
|
+
],
|
|
116
|
+
"additionalProperties": false,
|
|
117
|
+
"properties": {
|
|
118
|
+
"path": {
|
|
119
|
+
"type": "string",
|
|
120
|
+
"pattern": "^(?!/|[A-Za-z]:|.*(?:^|/)\\.\\.(?:/|$)|.*[\\\\*?\\[\\]{}])[^/]+(?:/[^/]+)*$"
|
|
121
|
+
},
|
|
122
|
+
"reason": {
|
|
123
|
+
"type": "string",
|
|
124
|
+
"minLength": 12,
|
|
125
|
+
"maxLength": 280
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
104
132
|
"graph": {
|
|
105
133
|
"type": "object",
|
|
106
134
|
"additionalProperties": false,
|
package/src/agents.js
CHANGED
|
@@ -30,7 +30,7 @@ Keep an existing LLMNav ID when a symbol or file is renamed or moved. Change \`r
|
|
|
30
30
|
|
|
31
31
|
Do not add hand-maintained \`calls\`, \`imports\`, \`references\`, \`implements\`, \`exports\`, or \`overrides\` relations. Do not put paths, line numbers, commit hashes, timestamps, callers, or current signatures in LLMNav source comments.
|
|
32
32
|
|
|
33
|
-
After initialization and whenever public entrypoints, commands, routes, schemas, migrations, or high fan-in modules change, run \`npm exec -- llmnav audit\`. Review high and medium candidates; never add cards automatically. Add a module card only after confirming a durable responsibility, then encode the accepted boundary in a path-specific \`coverageRules\` entry and add a representative retrieval query.
|
|
33
|
+
After initialization and whenever public entrypoints, commands, routes, schemas, migrations, or high fan-in modules change, run \`npm exec -- llmnav audit\`. Review high and medium candidates; never add cards automatically. Add a module card only after confirming a durable responsibility, then encode the accepted boundary in a path-specific \`coverageRules\` entry and add a representative retrieval query. When a reviewed candidate has no durable navigation responsibility, record its exact path and a concrete reason in \`audit.dispositions\`; never use a glob or broad directory suppression.
|
|
34
34
|
|
|
35
35
|
After semantic changes, run \`npm exec -- llmnav format\`, \`npm exec -- llmnav check\`, and \`npm exec -- llmnav generate\`. Use broad text search only when LLMNav returns no credible candidate.
|
|
36
36
|
${END}`;
|
package/src/audit.js
CHANGED
|
@@ -162,24 +162,56 @@ export async function auditProject(root) {
|
|
|
162
162
|
priorityRank(left.priority) - priorityRank(right.priority) ||
|
|
163
163
|
right.score - left.score ||
|
|
164
164
|
compareText(left.path, right.path));
|
|
165
|
+
const candidateByPath = new Map(candidates.map((candidate) => [candidate.path, candidate]));
|
|
166
|
+
const dispositions = [...project.config.audit.dispositions]
|
|
167
|
+
.sort((left, right) => compareText(left.path, right.path))
|
|
168
|
+
.map((disposition) => {
|
|
169
|
+
const candidate = candidateByPath.get(disposition.path);
|
|
170
|
+
if (candidate) {
|
|
171
|
+
candidateByPath.delete(disposition.path);
|
|
172
|
+
return {
|
|
173
|
+
path: disposition.path,
|
|
174
|
+
reason: disposition.reason,
|
|
175
|
+
status: "suppressed",
|
|
176
|
+
priority: candidate.priority,
|
|
177
|
+
score: candidate.score,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
path: disposition.path,
|
|
182
|
+
reason: disposition.reason,
|
|
183
|
+
status: "stale",
|
|
184
|
+
staleReason: classifyStaleDisposition(disposition.path, fileByPath, exactCardPaths, coveredModules),
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
const activeCandidates = candidates.filter((candidate) => candidateByPath.has(candidate.path));
|
|
165
188
|
const summary = {
|
|
166
189
|
analyzedFiles: fileByPath.size,
|
|
167
190
|
cardedFiles: cardedFilePaths.size,
|
|
168
191
|
filesWithoutModuleCards: fileByPath.size - cardedFilePaths.size,
|
|
169
|
-
candidates:
|
|
170
|
-
high:
|
|
171
|
-
medium:
|
|
172
|
-
low:
|
|
173
|
-
coverageSuggestions:
|
|
192
|
+
candidates: activeCandidates.length,
|
|
193
|
+
high: activeCandidates.filter((candidate) => candidate.priority === "high").length,
|
|
194
|
+
medium: activeCandidates.filter((candidate) => candidate.priority === "medium").length,
|
|
195
|
+
low: activeCandidates.filter((candidate) => candidate.priority === "low").length,
|
|
196
|
+
coverageSuggestions: activeCandidates.filter((candidate) => candidate.suggestedCoverageRule !== null).length,
|
|
197
|
+
suppressedCandidates: dispositions.filter((disposition) => disposition.status === "suppressed").length,
|
|
198
|
+
staleDispositions: dispositions.filter((disposition) => disposition.status === "stale").length,
|
|
174
199
|
};
|
|
175
200
|
return {
|
|
176
201
|
schemaVersion: AUDIT_SCHEMA_VERSION,
|
|
177
202
|
repositoryId: project.config.repositoryId,
|
|
178
203
|
summary,
|
|
179
|
-
candidates,
|
|
204
|
+
candidates: activeCandidates,
|
|
205
|
+
dispositions,
|
|
180
206
|
};
|
|
181
207
|
}
|
|
182
208
|
|
|
209
|
+
function classifyStaleDisposition(file, fileByPath, exactCardPaths, coveredModules) {
|
|
210
|
+
if (!fileByPath.has(file)) return "file-not-scanned";
|
|
211
|
+
if (exactCardPaths.has(file) || coveredModules.has(moduleKeyForFile(file))) return "already-carded";
|
|
212
|
+
return "not-a-candidate";
|
|
213
|
+
}
|
|
214
|
+
|
|
183
215
|
function groupFilesByModule(fileByPath) {
|
|
184
216
|
const output = new Map();
|
|
185
217
|
for (const [file, record] of fileByPath) {
|
package/src/cli.js
CHANGED
|
@@ -349,12 +349,16 @@ async function runAudit(root, args, json) {
|
|
|
349
349
|
const { summary } = result;
|
|
350
350
|
console.log(
|
|
351
351
|
`audit files=${summary.analyzedFiles} carded=${summary.cardedFiles} candidates=${summary.candidates} ` +
|
|
352
|
-
`high=${summary.high} medium=${summary.medium} low=${summary.low}
|
|
352
|
+
`high=${summary.high} medium=${summary.medium} low=${summary.low} ` +
|
|
353
|
+
`suppressed=${summary.suppressedCandidates} stale-dispositions=${summary.staleDispositions}`,
|
|
353
354
|
);
|
|
354
355
|
for (const candidate of result.candidates.filter((item) => item.priority !== "low")) {
|
|
355
356
|
console.log(`${candidate.priority} ${candidate.path} score=${candidate.score} ${candidate.reasons.join(",")}`);
|
|
356
357
|
}
|
|
357
358
|
if (summary.low > 0) console.log(`${summary.low} low-priority candidate(s) are available in --json output.`);
|
|
359
|
+
for (const disposition of result.dispositions.filter((item) => item.status === "stale")) {
|
|
360
|
+
console.log(`stale ${disposition.path} ${disposition.staleReason}: ${disposition.reason}`);
|
|
361
|
+
}
|
|
358
362
|
if (outputPath) console.log(`wrote ${relativePosix(root, outputPath)}`);
|
|
359
363
|
}
|
|
360
364
|
return auditHasFindings(result, failOn) ? 1 : 0;
|
package/src/config.js
CHANGED
|
@@ -30,7 +30,9 @@ const LINT_KEYS = new Set(Object.keys(DEFAULT_CONFIG.lint));
|
|
|
30
30
|
const GENERATION_KEYS = new Set(Object.keys(DEFAULT_CONFIG.generation));
|
|
31
31
|
const EVALUATION_KEYS = new Set(Object.keys(DEFAULT_CONFIG.evaluation));
|
|
32
32
|
const GRAPH_KEYS = new Set(Object.keys(DEFAULT_CONFIG.graph));
|
|
33
|
+
const AUDIT_KEYS = new Set(Object.keys(DEFAULT_CONFIG.audit));
|
|
33
34
|
const COVERAGE_KEYS = new Set(["name", "match", "scope", "requiredFields"]);
|
|
35
|
+
const AUDIT_DISPOSITION_KEYS = new Set(["path", "reason"]);
|
|
34
36
|
|
|
35
37
|
export async function loadConfig(root) {
|
|
36
38
|
const configPath = path.join(root, ".llmnav", "config.json");
|
|
@@ -72,6 +74,7 @@ export function validateConfig(config, configPath = ".llmnav/config.json") {
|
|
|
72
74
|
validateStringArray(config.excludeDirectories, "excludeDirectories", problems, { unique: true });
|
|
73
75
|
validateStringArray(config.excludeFiles, "excludeFiles", problems, { unique: true });
|
|
74
76
|
validateCoverageRules(config.coverageRules, problems);
|
|
77
|
+
validateAudit(config.audit, problems);
|
|
75
78
|
validateGraph(config.graph, problems);
|
|
76
79
|
|
|
77
80
|
validateLint(config.lint, problems);
|
|
@@ -83,6 +86,44 @@ export function validateConfig(config, configPath = ".llmnav/config.json") {
|
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
|
|
89
|
+
function validateAudit(audit, problems) {
|
|
90
|
+
if (!isObject(audit)) {
|
|
91
|
+
problems.push("audit must be an object");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
validateObjectKeys(audit, AUDIT_KEYS, "audit", problems);
|
|
95
|
+
if (!Array.isArray(audit.dispositions)) {
|
|
96
|
+
problems.push("audit.dispositions must be an array");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const seenPaths = new Set();
|
|
100
|
+
for (const [index, disposition] of audit.dispositions.entries()) {
|
|
101
|
+
const name = `audit.dispositions[${index}]`;
|
|
102
|
+
if (!isObject(disposition)) {
|
|
103
|
+
problems.push(`${name} must be an object`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
validateObjectKeys(disposition, AUDIT_DISPOSITION_KEYS, name, problems);
|
|
107
|
+
const pathProblem = validateProjectRelativePath(disposition.path);
|
|
108
|
+
if (pathProblem) {
|
|
109
|
+
problems.push(`${name}.path ${pathProblem}`);
|
|
110
|
+
} else {
|
|
111
|
+
const normalizedPath = path.posix.normalize(disposition.path);
|
|
112
|
+
if (normalizedPath !== disposition.path || disposition.path.endsWith("/") || /[*?[\]{}]/u.test(disposition.path)) {
|
|
113
|
+
problems.push(`${name}.path must be one exact normalized repository-relative path without glob syntax`);
|
|
114
|
+
}
|
|
115
|
+
const comparisonPath = normalizedPath.normalize("NFKC").toLocaleLowerCase("en-US");
|
|
116
|
+
if (seenPaths.has(comparisonPath)) problems.push(`${name}.path duplicates an earlier disposition`);
|
|
117
|
+
seenPaths.add(comparisonPath);
|
|
118
|
+
}
|
|
119
|
+
if (typeof disposition.reason !== "string" || disposition.reason.trim().length < 12) {
|
|
120
|
+
problems.push(`${name}.reason must explain the review decision in at least 12 characters`);
|
|
121
|
+
} else if (disposition.reason.length > 280) {
|
|
122
|
+
problems.push(`${name}.reason must not exceed 280 characters`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
86
127
|
function validateGraph(graph, problems) {
|
|
87
128
|
if (!isObject(graph)) {
|
|
88
129
|
problems.push("graph must be an object");
|
package/src/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type LlmnavScope = "file" | "module" | "symbol";
|
|
|
2
2
|
export type LlmnavStability = "architecture" | "contract" | "implementation";
|
|
3
3
|
export type DiagnosticSeverity = "error" | "warning" | "info";
|
|
4
4
|
export type AuditPriority = "high" | "medium" | "low";
|
|
5
|
+
export type AuditDispositionStaleReason = "file-not-scanned" | "already-carded" | "not-a-candidate";
|
|
5
6
|
|
|
6
7
|
export interface LlmnavCard {
|
|
7
8
|
scope: LlmnavScope;
|
|
@@ -108,8 +109,14 @@ export interface AuditResult {
|
|
|
108
109
|
medium: number;
|
|
109
110
|
low: number;
|
|
110
111
|
coverageSuggestions: number;
|
|
112
|
+
suppressedCandidates: number;
|
|
113
|
+
staleDispositions: number;
|
|
111
114
|
};
|
|
112
115
|
candidates: AuditCandidate[];
|
|
116
|
+
dispositions: Array<
|
|
117
|
+
| { path: string; reason: string; status: "suppressed"; priority: AuditPriority; score: number }
|
|
118
|
+
| { path: string; reason: string; status: "stale"; staleReason: AuditDispositionStaleReason }
|
|
119
|
+
>;
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
export interface IndexedLocation {
|
|
@@ -247,6 +254,9 @@ export interface LlmnavConfig {
|
|
|
247
254
|
excludeDirectories: string[];
|
|
248
255
|
excludeFiles: string[];
|
|
249
256
|
coverageRules: Array<Record<string, unknown>>;
|
|
257
|
+
audit: {
|
|
258
|
+
dispositions: Array<{ path: string; reason: string }>;
|
|
259
|
+
};
|
|
250
260
|
graph: {
|
|
251
261
|
indexFiles: string[];
|
|
252
262
|
};
|
package/src/spec.js
CHANGED
|
@@ -10,7 +10,7 @@ rel=workflow>llmnav.rules.validate
|
|
|
10
10
|
stability=contract
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
export const PACKAGE_VERSION = "0.
|
|
13
|
+
export const PACKAGE_VERSION = "0.8.0";
|
|
14
14
|
export const SPEC_VERSION = "1";
|
|
15
15
|
|
|
16
16
|
export const SCOPES = Object.freeze(["file", "module", "symbol"]);
|
|
@@ -208,6 +208,9 @@ export const DEFAULT_CONFIG = Object.freeze({
|
|
|
208
208
|
excludeDirectories: [...DEFAULT_EXCLUDED_DIRECTORIES],
|
|
209
209
|
excludeFiles: ["*.min.js", "*.bundle.js", "*.generated.*", "*.gen.*"],
|
|
210
210
|
coverageRules: [],
|
|
211
|
+
audit: {
|
|
212
|
+
dispositions: [],
|
|
213
|
+
},
|
|
211
214
|
graph: {
|
|
212
215
|
indexFiles: [],
|
|
213
216
|
},
|