@chrisdudek/yg 5.2.5 → 5.2.6
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/dist/bin.js +134 -144
- package/dist/structure.js +13 -6
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -10084,6 +10084,14 @@ async function parseFile(filePath, content20) {
|
|
|
10084
10084
|
}
|
|
10085
10085
|
return tree;
|
|
10086
10086
|
}
|
|
10087
|
+
async function withParsedFile(filePath, content20, fn) {
|
|
10088
|
+
const tree = await parseFile(filePath, content20);
|
|
10089
|
+
try {
|
|
10090
|
+
return await fn(tree);
|
|
10091
|
+
} finally {
|
|
10092
|
+
tree.delete();
|
|
10093
|
+
}
|
|
10094
|
+
}
|
|
10087
10095
|
|
|
10088
10096
|
// src/structure/ctx-parsers.ts
|
|
10089
10097
|
var ParseAstNotPrewarmedError = class extends Error {
|
|
@@ -10706,94 +10714,99 @@ function companionInfra(what, why, next) {
|
|
|
10706
10714
|
}
|
|
10707
10715
|
async function runCompanionHook(params) {
|
|
10708
10716
|
const { aspectDir, aspectId, nodePath, graph, projectRoot, subjectScope } = params;
|
|
10717
|
+
const ownCache = !params.parseCache;
|
|
10709
10718
|
const astCache = params.parseCache ?? /* @__PURE__ */ new Map();
|
|
10710
10719
|
const touchedFiles = [];
|
|
10711
|
-
let mod;
|
|
10712
10720
|
try {
|
|
10713
|
-
mod
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
if (typeof fn !== "function") {
|
|
10731
|
-
return companionInfra(
|
|
10732
|
-
`companion.mjs does not export a function named 'companion' (aspect '${aspectId}'; got ${typeof fn}).`,
|
|
10733
|
-
`The runner imports the named export 'companion' and calls companion(ctx).`,
|
|
10734
|
-
`Add 'export function companion(ctx) { ... }' to companion.mjs (it may be async).`
|
|
10735
|
-
);
|
|
10736
|
-
}
|
|
10737
|
-
let built;
|
|
10738
|
-
try {
|
|
10739
|
-
built = await buildUnitCtx({ aspectId, nodePath, graph, projectRoot, astCache, touchedFiles, subjectScope });
|
|
10740
|
-
} catch (err) {
|
|
10741
|
-
if (err instanceof StructureRunnerError) {
|
|
10742
|
-
return { kind: "infra", messageData: err.messageData };
|
|
10721
|
+
let mod;
|
|
10722
|
+
try {
|
|
10723
|
+
mod = await loadHookModule({
|
|
10724
|
+
aspectDir,
|
|
10725
|
+
projectRoot,
|
|
10726
|
+
filename: "companion.mjs",
|
|
10727
|
+
resolveFailedCode: "COMPANION_LOADER_RESOLVE_FAILED"
|
|
10728
|
+
});
|
|
10729
|
+
} catch (err) {
|
|
10730
|
+
if (err instanceof StructureRunnerError) {
|
|
10731
|
+
return { kind: "infra", messageData: err.messageData };
|
|
10732
|
+
}
|
|
10733
|
+
return companionInfra(
|
|
10734
|
+
`Failed to load companion.mjs for aspect '${aspectId}': ${err.message}`,
|
|
10735
|
+
`The runner dynamically imports the aspect's companion.mjs before resolving companions.`,
|
|
10736
|
+
`Ensure companion.mjs exists at the aspect directory and has no unresolved imports.`
|
|
10737
|
+
);
|
|
10743
10738
|
}
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
const { ctx, recorder } = built;
|
|
10747
|
-
let out;
|
|
10748
|
-
try {
|
|
10749
|
-
out = await fn(ctx);
|
|
10750
|
-
} catch (err) {
|
|
10751
|
-
if (err instanceof UndeclaredFsReadError || err instanceof UndeclaredGraphReadError || err instanceof ParseAstNotPrewarmedError) {
|
|
10739
|
+
const fn = mod.companion;
|
|
10740
|
+
if (typeof fn !== "function") {
|
|
10752
10741
|
return companionInfra(
|
|
10753
|
-
`companion.mjs
|
|
10754
|
-
`
|
|
10755
|
-
`
|
|
10742
|
+
`companion.mjs does not export a function named 'companion' (aspect '${aspectId}'; got ${typeof fn}).`,
|
|
10743
|
+
`The runner imports the named export 'companion' and calls companion(ctx).`,
|
|
10744
|
+
`Add 'export function companion(ctx) { ... }' to companion.mjs (it may be async).`
|
|
10756
10745
|
);
|
|
10757
10746
|
}
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10747
|
+
let built;
|
|
10748
|
+
try {
|
|
10749
|
+
built = await buildUnitCtx({ aspectId, nodePath, graph, projectRoot, astCache, touchedFiles, subjectScope });
|
|
10750
|
+
} catch (err) {
|
|
10751
|
+
if (err instanceof StructureRunnerError) {
|
|
10752
|
+
return { kind: "infra", messageData: err.messageData };
|
|
10753
|
+
}
|
|
10754
|
+
throw err;
|
|
10755
|
+
}
|
|
10756
|
+
const { ctx, recorder } = built;
|
|
10757
|
+
let out;
|
|
10758
|
+
try {
|
|
10759
|
+
out = await fn(ctx);
|
|
10760
|
+
} catch (err) {
|
|
10761
|
+
if (err instanceof UndeclaredFsReadError || err instanceof UndeclaredGraphReadError || err instanceof ParseAstNotPrewarmedError) {
|
|
10762
|
+
return companionInfra(
|
|
10763
|
+
`companion.mjs for aspect '${aspectId}' read an undeclared path or node: ${err.message}`,
|
|
10764
|
+
`A companion resolves the prompt only \u2014 it cannot judge code, so an undeclared read is an infrastructure fault, not a code violation.`,
|
|
10765
|
+
`Declare a relation in yg-node.yaml to the node owning that path, or read only relation-reachable files.`
|
|
10766
|
+
);
|
|
10767
|
+
}
|
|
10774
10768
|
return companionInfra(
|
|
10775
|
-
`companion
|
|
10776
|
-
|
|
10777
|
-
`
|
|
10769
|
+
`companion hook threw while resolving companions (aspect '${aspectId}'): ${err.message}`,
|
|
10770
|
+
`${err.stack ?? ""}`,
|
|
10771
|
+
`Fix the bug in companion.mjs, then re-run: yg check --approve`
|
|
10778
10772
|
);
|
|
10779
10773
|
}
|
|
10780
|
-
|
|
10781
|
-
if (dd.label !== void 0 && typeof dd.label !== "string") {
|
|
10774
|
+
if (!Array.isArray(out)) {
|
|
10782
10775
|
return companionInfra(
|
|
10783
|
-
`companion.mjs returned an
|
|
10784
|
-
`
|
|
10785
|
-
`
|
|
10776
|
+
`companion.mjs returned ${typeof out}, expected an array of { path: string, label?: string } (aspect '${aspectId}').`,
|
|
10777
|
+
`The runner attaches each returned path to the reviewer prompt; a non-array return cannot be interpreted.`,
|
|
10778
|
+
`Return [] or { path, label? }[] from companion.`
|
|
10786
10779
|
);
|
|
10787
10780
|
}
|
|
10788
|
-
descriptors
|
|
10781
|
+
const descriptors = [];
|
|
10782
|
+
for (const d of out) {
|
|
10783
|
+
if (typeof d !== "object" || d === null || typeof d.path !== "string") {
|
|
10784
|
+
return companionInfra(
|
|
10785
|
+
`companion.mjs returned an entry that is not { path: string, label?: string } (aspect '${aspectId}').`,
|
|
10786
|
+
`Each companion descriptor must carry a string 'path' (and an optional string 'label').`,
|
|
10787
|
+
`Return objects shaped { path: string, label?: string } from companion.`
|
|
10788
|
+
);
|
|
10789
|
+
}
|
|
10790
|
+
const dd = d;
|
|
10791
|
+
if (dd.label !== void 0 && typeof dd.label !== "string") {
|
|
10792
|
+
return companionInfra(
|
|
10793
|
+
`companion.mjs returned an entry whose 'label' is not a string (aspect '${aspectId}'; got ${typeof dd.label}).`,
|
|
10794
|
+
`A companion descriptor's optional 'label' is a human tag and must be a string when present.`,
|
|
10795
|
+
`Omit 'label' or set it to a string in companion.`
|
|
10796
|
+
);
|
|
10797
|
+
}
|
|
10798
|
+
descriptors.push({ path: dd.path, ...dd.label !== void 0 ? { label: dd.label } : {} });
|
|
10799
|
+
}
|
|
10800
|
+
return {
|
|
10801
|
+
kind: "ok",
|
|
10802
|
+
descriptors,
|
|
10803
|
+
touchedFiles,
|
|
10804
|
+
observations: recorder.snapshot(),
|
|
10805
|
+
observationsTainted: recorder.tainted
|
|
10806
|
+
};
|
|
10807
|
+
} finally {
|
|
10808
|
+
if (ownCache) destroyParseCache(astCache);
|
|
10789
10809
|
}
|
|
10790
|
-
return {
|
|
10791
|
-
kind: "ok",
|
|
10792
|
-
descriptors,
|
|
10793
|
-
touchedFiles,
|
|
10794
|
-
observations: recorder.snapshot(),
|
|
10795
|
-
observationsTainted: recorder.tainted
|
|
10796
|
-
};
|
|
10797
10810
|
}
|
|
10798
10811
|
|
|
10799
10812
|
// src/structure/runner.ts
|
|
@@ -10951,13 +10964,12 @@ async function resolveSuppressedRangesForPrompt(subjects, aspectId) {
|
|
|
10951
10964
|
for (const subject of subjects) {
|
|
10952
10965
|
const content20 = subject.bytes.toString("utf8");
|
|
10953
10966
|
const hasGrammar = getLanguageForExtension(extname5(subject.path).toLowerCase()) !== null;
|
|
10954
|
-
let tree;
|
|
10955
|
-
if (hasGrammar) {
|
|
10956
|
-
tree = await parseFile(subject.path, content20);
|
|
10957
|
-
}
|
|
10958
10967
|
const totalLines = content20.split("\n").length;
|
|
10959
|
-
const all =
|
|
10960
|
-
|
|
10968
|
+
const all = hasGrammar ? await withParsedFile(
|
|
10969
|
+
subject.path,
|
|
10970
|
+
content20,
|
|
10971
|
+
(tree) => collectSuppressions(tree, subject.path, totalLines, content20)
|
|
10972
|
+
) : collectSuppressions(void 0, subject.path, totalLines, content20);
|
|
10961
10973
|
const ranges = formatSuppressedRangesForAspect(all, aspectId);
|
|
10962
10974
|
if (ranges.length > 0) {
|
|
10963
10975
|
byFile.push({ path: subject.path, ranges });
|
|
@@ -12144,22 +12156,14 @@ async function runRelationPass(graph, projectRoot, deps) {
|
|
|
12144
12156
|
}
|
|
12145
12157
|
}
|
|
12146
12158
|
const ownerIndex = buildOwnerIndex(graph.nodes);
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
if (parseCache.has(record.path)) return parseCache.get(record.path) ?? null;
|
|
12150
|
-
if (!record.language) {
|
|
12151
|
-
parseCache.set(record.path, null);
|
|
12152
|
-
return null;
|
|
12153
|
-
}
|
|
12154
|
-
let parsed;
|
|
12159
|
+
async function parseSingle(record) {
|
|
12160
|
+
if (!record.language) return null;
|
|
12155
12161
|
try {
|
|
12156
12162
|
const tree = await parseFile(record.path, record.content);
|
|
12157
|
-
|
|
12163
|
+
return { path: record.path, content: record.content, tree, language: record.language };
|
|
12158
12164
|
} catch {
|
|
12159
|
-
|
|
12165
|
+
return null;
|
|
12160
12166
|
}
|
|
12161
|
-
parseCache.set(record.path, parsed);
|
|
12162
|
-
return parsed;
|
|
12163
12167
|
}
|
|
12164
12168
|
const symbolTable = new SymbolTable();
|
|
12165
12169
|
const recordsByLanguage = /* @__PURE__ */ new Map();
|
|
@@ -12183,11 +12187,15 @@ async function runRelationPass(graph, projectRoot, deps) {
|
|
|
12183
12187
|
}
|
|
12184
12188
|
const symbols = [];
|
|
12185
12189
|
for (const record of records) {
|
|
12186
|
-
const parsed = await
|
|
12190
|
+
const parsed = await parseSingle(record);
|
|
12187
12191
|
if (!parsed) continue;
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12192
|
+
try {
|
|
12193
|
+
for (const decl of extractor.declarations(parsed)) {
|
|
12194
|
+
symbols.push([decl.symbolKey, record.path]);
|
|
12195
|
+
symbolTable.declare(language, decl.symbolKey, record.path);
|
|
12196
|
+
}
|
|
12197
|
+
} finally {
|
|
12198
|
+
parsed.tree.delete();
|
|
12191
12199
|
}
|
|
12192
12200
|
}
|
|
12193
12201
|
const toPersist = { builtFrom, symbols };
|
|
@@ -12197,10 +12205,14 @@ async function runRelationPass(graph, projectRoot, deps) {
|
|
|
12197
12205
|
const projectGlobalUsings = /* @__PURE__ */ new Set();
|
|
12198
12206
|
const projectGlobalUsingAliases = /* @__PURE__ */ new Map();
|
|
12199
12207
|
for (const record of csharpRecords) {
|
|
12200
|
-
const parsed = await
|
|
12208
|
+
const parsed = await parseSingle(record);
|
|
12201
12209
|
if (!parsed) continue;
|
|
12202
|
-
|
|
12203
|
-
|
|
12210
|
+
try {
|
|
12211
|
+
for (const prefix of collectGlobalUsings(parsed)) projectGlobalUsings.add(prefix);
|
|
12212
|
+
for (const [name, fqn] of collectGlobalUsingAliases(parsed)) projectGlobalUsingAliases.set(name, fqn);
|
|
12213
|
+
} finally {
|
|
12214
|
+
parsed.tree.delete();
|
|
12215
|
+
}
|
|
12204
12216
|
}
|
|
12205
12217
|
const csharpGlobalUsings = [...projectGlobalUsings];
|
|
12206
12218
|
const csharpGlobalUsingAliases = [...projectGlobalUsingAliases.entries()];
|
|
@@ -12235,17 +12247,21 @@ async function runRelationPass(graph, projectRoot, deps) {
|
|
|
12235
12247
|
if (!record.language) continue;
|
|
12236
12248
|
const extractor = deps.extractorFor(record.language);
|
|
12237
12249
|
if (!extractor) continue;
|
|
12238
|
-
const parsed = await
|
|
12250
|
+
const parsed = await parseSingle(record);
|
|
12239
12251
|
if (!parsed) continue;
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
12244
|
-
|
|
12245
|
-
const
|
|
12246
|
-
|
|
12247
|
-
|
|
12252
|
+
try {
|
|
12253
|
+
const detected = record.language === "csharp" ? csharpUses(parsed, {
|
|
12254
|
+
projectGlobalUsings: csharpGlobalUsings,
|
|
12255
|
+
projectGlobalUsingAliases: csharpGlobalUsingAliases
|
|
12256
|
+
}) : extractor.uses(parsed);
|
|
12257
|
+
for (const dep of detected) {
|
|
12258
|
+
const ownerNode = resolveCandidateGroup(dep.candidates, resolver, record.path, record.language);
|
|
12259
|
+
if (ownerNode !== void 0) {
|
|
12260
|
+
resolvedDeps.push({ fromFile: record.path, line: dep.line, ownerNode });
|
|
12261
|
+
}
|
|
12248
12262
|
}
|
|
12263
|
+
} finally {
|
|
12264
|
+
parsed.tree.delete();
|
|
12249
12265
|
}
|
|
12250
12266
|
}
|
|
12251
12267
|
const violations = verifyNodeDeps(nodeId, resolvedDeps, graphView);
|
|
@@ -12256,9 +12272,6 @@ async function runRelationPass(graph, projectRoot, deps) {
|
|
|
12256
12272
|
violationsByNode.set(nodeId, { verdict: "approved", violations: [] });
|
|
12257
12273
|
}
|
|
12258
12274
|
}
|
|
12259
|
-
for (const entry of parseCache.values()) {
|
|
12260
|
-
if (entry) entry.tree.delete();
|
|
12261
|
-
}
|
|
12262
12275
|
return { violationsByNode };
|
|
12263
12276
|
}
|
|
12264
12277
|
|
|
@@ -15818,21 +15831,7 @@ async function runFill(graph, opts) {
|
|
|
15818
15831
|
}
|
|
15819
15832
|
|
|
15820
15833
|
// src/cli/check.ts
|
|
15821
|
-
import { execFileSync } from "child_process";
|
|
15822
15834
|
import path48 from "path";
|
|
15823
|
-
function collectGitFiles(projectRoot) {
|
|
15824
|
-
try {
|
|
15825
|
-
const output = execFileSync("git", ["ls-files", "."], {
|
|
15826
|
-
cwd: projectRoot,
|
|
15827
|
-
encoding: "utf-8",
|
|
15828
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
15829
|
-
});
|
|
15830
|
-
return output.trim().split("\n").filter((f) => f.length > 0);
|
|
15831
|
-
} catch (e) {
|
|
15832
|
-
debugWrite(`[check] git ls-files failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
15833
|
-
return null;
|
|
15834
|
-
}
|
|
15835
|
-
}
|
|
15836
15835
|
function registerCheckCommand(program2) {
|
|
15837
15836
|
program2.command("check").description("Unified graph gate \u2014 verification, coverage, completeness").option("--approve", "Fill every unverified pair (deterministic first, then LLM), then report").option("--only-deterministic", "With --approve: fill ONLY deterministic pairs (keyless, free); committed locks stay untouched. For CI and pre-commit.").option("--dry-run", "With --approve: free cost preview \u2014 print the budget + per-node/per-aspect breakdown, then exit 0 WITHOUT writing anything or calling the reviewer.").option("--top [n]", "Read-only triage: print only the N highest-priority issue blocks (bare --top = just the single suggestedNext block). Header counts + exit code stay TRUE.").option("--summary", "Read-only triage: print per-node counts only (no per-issue blocks). Header counts + exit code stay TRUE.").action(async (opts) => {
|
|
15838
15837
|
try {
|
|
@@ -15840,7 +15839,7 @@ function registerCheckCommand(program2) {
|
|
|
15840
15839
|
const graph = await loadGraphOrAbort(cwd, { tolerateInvalidConfig: true });
|
|
15841
15840
|
initDebugLog(graph.rootPath, graph.config.debug ?? false, appendToDebugLog);
|
|
15842
15841
|
const projectRoot = path48.dirname(graph.rootPath);
|
|
15843
|
-
const gitFiles =
|
|
15842
|
+
const gitFiles = await walkRepoFiles(projectRoot);
|
|
15844
15843
|
const wantsTop = opts.top !== void 0;
|
|
15845
15844
|
if (wantsTop && opts.summary) {
|
|
15846
15845
|
process.stderr.write(chalk8.red(buildIssueMessage({
|
|
@@ -16259,6 +16258,9 @@ async function runAstAspect(params) {
|
|
|
16259
16258
|
next: `Reinstall the CLI.`
|
|
16260
16259
|
});
|
|
16261
16260
|
}
|
|
16261
|
+
if (!params.parseCache) {
|
|
16262
|
+
localTrees.push(ast);
|
|
16263
|
+
}
|
|
16262
16264
|
if (ast.rootNode.hasError) {
|
|
16263
16265
|
const err = findFirstErrorNode(ast.rootNode);
|
|
16264
16266
|
throw new AstRunnerError("AST_SOURCE_PARSE_ERROR", {
|
|
@@ -16269,8 +16271,6 @@ async function runAstAspect(params) {
|
|
|
16269
16271
|
}
|
|
16270
16272
|
if (params.parseCache) {
|
|
16271
16273
|
params.parseCache.set(f.path, { content: content20, ast });
|
|
16272
|
-
} else {
|
|
16273
|
-
localTrees.push(ast);
|
|
16274
16274
|
}
|
|
16275
16275
|
sourceFiles.push({ path: f.path, content: content20, ast });
|
|
16276
16276
|
}
|
|
@@ -21823,7 +21823,6 @@ function registerSchemasCommand(program2) {
|
|
|
21823
21823
|
// src/cli/suppressions.ts
|
|
21824
21824
|
import chalk14 from "chalk";
|
|
21825
21825
|
import { readFileSync as readFileSync8, existsSync as existsSync9 } from "fs";
|
|
21826
|
-
import { execFileSync as execFileSync2 } from "child_process";
|
|
21827
21826
|
import path57 from "path";
|
|
21828
21827
|
function isBinaryContent(buf) {
|
|
21829
21828
|
const checkLen = Math.min(buf.length, 8192);
|
|
@@ -21852,10 +21851,11 @@ async function scanMarkersForFile(relFile, text2) {
|
|
|
21852
21851
|
return scanSuppressionMarkers(text2);
|
|
21853
21852
|
}
|
|
21854
21853
|
try {
|
|
21855
|
-
|
|
21856
|
-
|
|
21857
|
-
|
|
21858
|
-
|
|
21854
|
+
return await withParsedFile(
|
|
21855
|
+
relFile,
|
|
21856
|
+
text2,
|
|
21857
|
+
(tree) => scanSuppressionMarkersInComments(tree, relFile)
|
|
21858
|
+
);
|
|
21859
21859
|
} catch (error) {
|
|
21860
21860
|
debugWrite(`[suppressions] parse fallback (raw scan): ${relFile}: ${error instanceof Error ? error.message : String(error)}`);
|
|
21861
21861
|
return scanSuppressionMarkers(text2);
|
|
@@ -21974,17 +21974,7 @@ function registerSuppressionsCommand(program2) {
|
|
|
21974
21974
|
const graph = await loadGraphOrAbort(cwd);
|
|
21975
21975
|
initDebugLog(graph.rootPath, graph.config.debug ?? false, appendToDebugLog);
|
|
21976
21976
|
const projectRoot = path57.dirname(graph.rootPath);
|
|
21977
|
-
|
|
21978
|
-
try {
|
|
21979
|
-
const output = execFileSync2("git", ["ls-files", "."], {
|
|
21980
|
-
cwd: projectRoot,
|
|
21981
|
-
encoding: "utf-8",
|
|
21982
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
21983
|
-
});
|
|
21984
|
-
gitFiles = output.trim().split("\n").filter((f) => f.length > 0);
|
|
21985
|
-
} catch (error) {
|
|
21986
|
-
debugWrite(`[suppressions] git ls-files fallback: ${error instanceof Error ? error.message : String(error)}`);
|
|
21987
|
-
}
|
|
21977
|
+
const gitFiles = await walkRepoFiles(projectRoot);
|
|
21988
21978
|
const knownAspectIds = new Set(graph.aspects.map((a) => a.id));
|
|
21989
21979
|
const report2 = await runSuppressionsScan(projectRoot, gitFiles, knownAspectIds);
|
|
21990
21980
|
process.stdout.write(formatSuppressionsOutput(report2));
|
package/dist/structure.js
CHANGED
|
@@ -606,6 +606,14 @@ async function parseFile(filePath, content) {
|
|
|
606
606
|
}
|
|
607
607
|
return tree;
|
|
608
608
|
}
|
|
609
|
+
async function withParsedFile(filePath, content, fn) {
|
|
610
|
+
const tree = await parseFile(filePath, content);
|
|
611
|
+
try {
|
|
612
|
+
return await fn(tree);
|
|
613
|
+
} finally {
|
|
614
|
+
tree.delete();
|
|
615
|
+
}
|
|
616
|
+
}
|
|
609
617
|
|
|
610
618
|
// src/structure/ctx-parsers.ts
|
|
611
619
|
var ParseAstNotPrewarmedError = class extends Error {
|
|
@@ -1599,13 +1607,12 @@ async function resolveSuppressedRangesForPrompt(subjects, aspectId) {
|
|
|
1599
1607
|
for (const subject of subjects) {
|
|
1600
1608
|
const content = subject.bytes.toString("utf8");
|
|
1601
1609
|
const hasGrammar = getLanguageForExtension(extname5(subject.path).toLowerCase()) !== null;
|
|
1602
|
-
let tree;
|
|
1603
|
-
if (hasGrammar) {
|
|
1604
|
-
tree = await parseFile(subject.path, content);
|
|
1605
|
-
}
|
|
1606
1610
|
const totalLines = content.split("\n").length;
|
|
1607
|
-
const all =
|
|
1608
|
-
|
|
1611
|
+
const all = hasGrammar ? await withParsedFile(
|
|
1612
|
+
subject.path,
|
|
1613
|
+
content,
|
|
1614
|
+
(tree) => collectSuppressions(tree, subject.path, totalLines, content)
|
|
1615
|
+
) : collectSuppressions(void 0, subject.path, totalLines, content);
|
|
1609
1616
|
const ranges = formatSuppressedRangesForAspect(all, aspectId);
|
|
1610
1617
|
if (ranges.length > 0) {
|
|
1611
1618
|
byFile.push({ path: subject.path, ranges });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrisdudek/yg",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.6",
|
|
4
4
|
"description": "Architecture rules your AI coding agent can't ignore. It gets the rules for a file before it edits, and every change is checked — by a free local script or an LLM reviewer — before it moves on. Works with Claude Code, Cursor, Copilot, Codex, Cline.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|