@chrisdudek/yg 5.1.0 → 5.2.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.
@@ -243,7 +243,7 @@ interface LlmConfig {
243
243
  timeout?: number;
244
244
  /**
245
245
  * Optional per-tier cap on assembled reviewer-prompt length in characters.
246
- * Absent = unlimited. This is a GATE checked deterministically before the LLM
246
+ * Absent defaults to 50000. This is a GATE checked deterministically before the LLM
247
247
  * call — it never participates in verdict identity or hash computation (excluded
248
248
  * from canonicalTierJson like api_key and timeout).
249
249
  */
@@ -460,4 +460,53 @@ interface RunStructureAspectResult {
460
460
  }
461
461
  declare function runStructureAspect(params: RunStructureAspectParams): Promise<RunStructureAspectResult>;
462
462
 
463
- export { type CheckFunction, type CompanionDescriptor, type CompanionFunction, type Ctx, type File, type FsEntry, type GraphNode$1 as GraphNode, type Port, type Relation$1 as Relation, type RelationType$1 as RelationType, StructureRunnerError, type Violation, runStructureAspect };
463
+ /**
464
+ * Pre-resolved suppress line ranges injected into the reviewer prompt so the LLM
465
+ * honors EXACTLY the same `(file, startLine..endLine)` spans the deterministic
466
+ * matcher (`ast/suppress.ts`) computes — no model-side re-derivation of marker
467
+ * scope. `byFile` carries only files that have at least one applicable range;
468
+ * an empty `byFile` (or an omitted `suppressedRanges`) renders no block and keeps
469
+ * the prompt byte-identical to the no-suppress case.
470
+ */
471
+ interface PromptSuppressedRangesInput {
472
+ byFile: Array<{
473
+ path: string;
474
+ ranges: Array<{
475
+ startLine: number;
476
+ endLine: number;
477
+ }>;
478
+ }>;
479
+ }
480
+
481
+ declare class SuppressMarkerError extends Error {
482
+ file: string;
483
+ line: number;
484
+ readonly code = "SUPPRESS_MARKER_MISSING_REASON";
485
+ constructor(message: string, file: string, line: number);
486
+ }
487
+
488
+ /**
489
+ * Resolve, per subject file, the suppress line ranges that apply to `aspectId`,
490
+ * shaped for injection into the reviewer prompt.
491
+ *
492
+ * Parse strategy mirrors the deterministic AST runner (`ast/runner.ts`): a file
493
+ * whose extension has a registered tree-sitter grammar is parsed and its markers
494
+ * read from comment nodes; a file with no grammar (`.sql`, `.md`, `.sh`, …) gets
495
+ * a raw-line content scan. Either way `collectSuppressions` produces the spans
496
+ * and `formatSuppressedRangesForAspect` filters them to this aspect (wildcard
497
+ * markers included).
498
+ *
499
+ * Only files with at least one applicable range appear in `byFile`, so an empty
500
+ * result renders no `<suppressed-ranges>` block and the prompt stays byte-identical
501
+ * to the no-suppress case.
502
+ *
503
+ * A reasonless marker throws `SuppressMarkerError` (out of `collectSuppressions`)
504
+ * — the caller treats that as an infrastructure failure and writes nothing, the
505
+ * same fail-closed disposition the deterministic path takes.
506
+ */
507
+ declare function resolveSuppressedRangesForPrompt(subjects: Array<{
508
+ path: string;
509
+ bytes: Buffer;
510
+ }>, aspectId: string): Promise<PromptSuppressedRangesInput>;
511
+
512
+ export { type CheckFunction, type CompanionDescriptor, type CompanionFunction, type Ctx, type File, type FsEntry, type GraphNode$1 as GraphNode, type Port, type Relation$1 as Relation, type RelationType$1 as RelationType, StructureRunnerError, SuppressMarkerError, type Violation, resolveSuppressedRangesForPrompt, runStructureAspect };
package/dist/structure.js CHANGED
@@ -820,6 +820,9 @@ function isLineSuppressed(ranges, aspectId, line) {
820
820
  return r.isWildcard || r.aspectIds.has(aspectId);
821
821
  });
822
822
  }
823
+ function formatSuppressedRangesForAspect(ranges, aspectId) {
824
+ return ranges.filter((r) => r.isWildcard || r.aspectIds.has(aspectId)).map((r) => ({ startLine: r.startLine, endLine: r.endLine })).sort((a, b) => a.startLine - b.startLine || a.endLine - b.endLine);
825
+ }
823
826
 
824
827
  // src/utils/validate-check-module.ts
825
828
  function validateCheckModuleExport(mod, opts) {
@@ -1571,6 +1574,27 @@ ${err.stack ?? ""}`,
1571
1574
  };
1572
1575
  }
1573
1576
 
1577
+ // src/structure/suppress-ranges.ts
1578
+ import { extname as extname5 } from "path";
1579
+ async function resolveSuppressedRangesForPrompt(subjects, aspectId) {
1580
+ const byFile = [];
1581
+ for (const subject of subjects) {
1582
+ const content = subject.bytes.toString("utf8");
1583
+ const hasGrammar = getLanguageForExtension(extname5(subject.path).toLowerCase()) !== null;
1584
+ let tree;
1585
+ if (hasGrammar) {
1586
+ tree = await parseFile(subject.path, content);
1587
+ }
1588
+ const totalLines = content.split("\n").length;
1589
+ const all = collectSuppressions(tree, subject.path, totalLines, content);
1590
+ const ranges = formatSuppressedRangesForAspect(all, aspectId);
1591
+ if (ranges.length > 0) {
1592
+ byFile.push({ path: subject.path, ranges });
1593
+ }
1594
+ }
1595
+ return { byFile };
1596
+ }
1597
+
1574
1598
  // src/ast/walk.ts
1575
1599
  function walk(node, visitor) {
1576
1600
  const result = visitor(node);
@@ -1609,10 +1633,12 @@ function inFile(file, pattern) {
1609
1633
  }
1610
1634
  export {
1611
1635
  StructureRunnerError,
1636
+ SuppressMarkerError,
1612
1637
  closest,
1613
1638
  findComments,
1614
1639
  inFile,
1615
1640
  report,
1641
+ resolveSuppressedRangesForPrompt,
1616
1642
  runStructureAspect,
1617
1643
  walk
1618
1644
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrisdudek/yg",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
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": {