@webpieces/rules-config 0.4.655 → 0.4.656

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/rules-config",
3
- "version": "0.4.655",
3
+ "version": "0.4.656",
4
4
  "description": "Shared webpieces.config.json loader. Single source of truth for validation rule configuration consumed by @webpieces/ai-hook-rules, @webpieces/code-rules, and @webpieces/nx-webpieces-rules.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -0,0 +1,32 @@
1
+ /**
2
+ * `Option` is THE representation of one cure — "here is a way to fix this" — for BOTH rule engines.
3
+ *
4
+ * It lives HERE, in the lowest-level package, because both engines need it and the dependency runs one
5
+ * way: `@webpieces/ai-hook-rules` depends on `@webpieces/rules-config` (see its package.json), never the
6
+ * reverse. `RuleFailError` (this package) carries `readonly Option[]`, and `FixHint`
7
+ * (`ai-hook-rules/src/core/fix-hint.ts`) carries the same `Option` — one class, one import path.
8
+ *
9
+ * WHY it was moved down (2026-08-18): `RuleFailError.fixHints` used to be `readonly string[]` while
10
+ * `FixHint.fixOptions` was `readonly Option[]`. That was TWO shapes for one concept — the shim shape
11
+ * CLAUDE.md calls "two spellings of one thing" — and the `string[]` half could not express `preferred`
12
+ * at all, so a build-time rule had no way to say which cure to reach for first. There is now exactly one
13
+ * spelling; the old one does not compile.
14
+ *
15
+ * The framework — `formatFixOptions` below, and `report.ts` in ai-hook-rules — owns the
16
+ * "Fix Option N:" numbering and the "(preferred)" tag. Rule authors NEVER hand-write those labels, and
17
+ * never hand-number cures inside a string literal.
18
+ */
19
+ export declare class Option {
20
+ /** The fix text. May be multi-line; continuation lines are indented under the option. */
21
+ readonly text: string;
22
+ /** When true the framework prefixes the rendered option with "(preferred) ". */
23
+ readonly preferred: boolean;
24
+ constructor(text: string, preferred?: boolean);
25
+ }
26
+ /**
27
+ * The ONE renderer for a list of cures, so the numbering and the "(preferred)" tag have a single
28
+ * implementation across the edit-time report, the edit-time thrown-rule path, and the build-time
29
+ * console. `indent` is the leading whitespace for the "Fix Option N:" line; continuation lines of a
30
+ * multi-line option get `indent + ' '`.
31
+ */
32
+ export declare function formatFixOptions(options: readonly Option[], indent?: string): readonly string[];
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Option = void 0;
4
+ exports.formatFixOptions = formatFixOptions;
5
+ /**
6
+ * `Option` is THE representation of one cure — "here is a way to fix this" — for BOTH rule engines.
7
+ *
8
+ * It lives HERE, in the lowest-level package, because both engines need it and the dependency runs one
9
+ * way: `@webpieces/ai-hook-rules` depends on `@webpieces/rules-config` (see its package.json), never the
10
+ * reverse. `RuleFailError` (this package) carries `readonly Option[]`, and `FixHint`
11
+ * (`ai-hook-rules/src/core/fix-hint.ts`) carries the same `Option` — one class, one import path.
12
+ *
13
+ * WHY it was moved down (2026-08-18): `RuleFailError.fixHints` used to be `readonly string[]` while
14
+ * `FixHint.fixOptions` was `readonly Option[]`. That was TWO shapes for one concept — the shim shape
15
+ * CLAUDE.md calls "two spellings of one thing" — and the `string[]` half could not express `preferred`
16
+ * at all, so a build-time rule had no way to say which cure to reach for first. There is now exactly one
17
+ * spelling; the old one does not compile.
18
+ *
19
+ * The framework — `formatFixOptions` below, and `report.ts` in ai-hook-rules — owns the
20
+ * "Fix Option N:" numbering and the "(preferred)" tag. Rule authors NEVER hand-write those labels, and
21
+ * never hand-number cures inside a string literal.
22
+ */
23
+ class Option {
24
+ /** The fix text. May be multi-line; continuation lines are indented under the option. */
25
+ text;
26
+ /** When true the framework prefixes the rendered option with "(preferred) ". */
27
+ preferred;
28
+ constructor(text, preferred = false) {
29
+ this.text = text;
30
+ this.preferred = preferred;
31
+ }
32
+ }
33
+ exports.Option = Option;
34
+ /**
35
+ * The ONE renderer for a list of cures, so the numbering and the "(preferred)" tag have a single
36
+ * implementation across the edit-time report, the edit-time thrown-rule path, and the build-time
37
+ * console. `indent` is the leading whitespace for the "Fix Option N:" line; continuation lines of a
38
+ * multi-line option get `indent + ' '`.
39
+ */
40
+ // webpieces-disable no-function-outside-class -- a pure string formatter, sibling to `atRoot`; a class around it would be ceremony
41
+ function formatFixOptions(options, indent = ' ') {
42
+ const lines = [];
43
+ options.forEach((opt, i) => {
44
+ const optLines = opt.text.split('\n');
45
+ const tag = opt.preferred ? '(preferred) ' : '';
46
+ lines.push(`${indent}Fix Option ${String(i + 1)}: ${tag}${optLines[0] ?? ''}`);
47
+ for (const l of optLines.slice(1))
48
+ lines.push(`${indent} ${l}`);
49
+ });
50
+ return lines;
51
+ }
52
+ //# sourceMappingURL=fix-option.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-option.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/fix-option.ts"],"names":[],"mappings":";;;AAqCA,4CASC;AA9CD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,MAAM;IACf,yFAAyF;IAChF,IAAI,CAAS;IACtB,gFAAgF;IACvE,SAAS,CAAU;IAE5B,YAAY,IAAY,EAAE,SAAS,GAAG,KAAK;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;CACJ;AAVD,wBAUC;AAED;;;;;GAKG;AACH,mIAAmI;AACnI,SAAgB,gBAAgB,CAAC,OAA0B,EAAE,MAAM,GAAG,IAAI;IACtE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,OAAO,CAAC,OAAO,CAAC,CAAC,GAAW,EAAE,CAAS,EAAE,EAAE;QACvC,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,cAAc,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC/E,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["/**\n * `Option` is THE representation of one cure — \"here is a way to fix this\" — for BOTH rule engines.\n *\n * It lives HERE, in the lowest-level package, because both engines need it and the dependency runs one\n * way: `@webpieces/ai-hook-rules` depends on `@webpieces/rules-config` (see its package.json), never the\n * reverse. `RuleFailError` (this package) carries `readonly Option[]`, and `FixHint`\n * (`ai-hook-rules/src/core/fix-hint.ts`) carries the same `Option` — one class, one import path.\n *\n * WHY it was moved down (2026-08-18): `RuleFailError.fixHints` used to be `readonly string[]` while\n * `FixHint.fixOptions` was `readonly Option[]`. That was TWO shapes for one concept — the shim shape\n * CLAUDE.md calls \"two spellings of one thing\" — and the `string[]` half could not express `preferred`\n * at all, so a build-time rule had no way to say which cure to reach for first. There is now exactly one\n * spelling; the old one does not compile.\n *\n * The framework — `formatFixOptions` below, and `report.ts` in ai-hook-rules — owns the\n * \"Fix Option N:\" numbering and the \"(preferred)\" tag. Rule authors NEVER hand-write those labels, and\n * never hand-number cures inside a string literal.\n */\nexport class Option {\n /** The fix text. May be multi-line; continuation lines are indented under the option. */\n readonly text: string;\n /** When true the framework prefixes the rendered option with \"(preferred) \". */\n readonly preferred: boolean;\n\n constructor(text: string, preferred = false) {\n this.text = text;\n this.preferred = preferred;\n }\n}\n\n/**\n * The ONE renderer for a list of cures, so the numbering and the \"(preferred)\" tag have a single\n * implementation across the edit-time report, the edit-time thrown-rule path, and the build-time\n * console. `indent` is the leading whitespace for the \"Fix Option N:\" line; continuation lines of a\n * multi-line option get `indent + ' '`.\n */\n// webpieces-disable no-function-outside-class -- a pure string formatter, sibling to `atRoot`; a class around it would be ceremony\nexport function formatFixOptions(options: readonly Option[], indent = ' '): readonly string[] {\n const lines: string[] = [];\n options.forEach((opt: Option, i: number) => {\n const optLines = opt.text.split('\\n');\n const tag = opt.preferred ? '(preferred) ' : '';\n lines.push(`${indent}Fix Option ${String(i + 1)}: ${tag}${optLines[0] ?? ''}`);\n for (const l of optLines.slice(1)) lines.push(`${indent} ${l}`);\n });\n return lines;\n}\n"]}
package/src/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from './types';
2
2
  export { InformAiError } from './inform-ai-error';
3
- export { RuleFailError } from './rule-fail-error';
3
+ export { RuleFailError, renderRuleFailForAi, renderRuleFailForHuman } from './rule-fail-error';
4
+ export { Option, formatFixOptions } from './fix-option';
4
5
  export { CliExitError } from './cli-exit-error';
5
6
  export { CliUsage, CliFlag, CliArgSet, CliArgsCheck, CliArgs } from './cli-args';
6
7
  export { runMain } from './run-main';
package/src/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ExcludePaths = exports.DESIGN_METADATA_KEYS = exports.isDocumentDesign = exports.DocumentDesign = exports.RulesConfigDesign = exports.atRoot = exports.AtomicFile = exports.CLAUDE_PROJECT_DIR_UNSET = exports.CLAUDE_PROJECT_DIR_ENV = exports.claudeEnv = exports.ClaudeEnv = exports.RETENTION_DAYS = exports.SweepCount = exports.AgedTreeSweeper = exports.StateMigrationReport = exports.StateDirMigrator = exports.LOGS_STATE_DIR = exports.WORKTREE_STATE_DIR = exports.GitDirs = exports.dotWebpieces = exports.DotWebpieces = exports.INSTRUCT_AI_LEAF = exports.INSTRUCT_AI_DIR = exports.RepoRootFinder = exports.CONFIG_PARSE_RETRY_MILLIS = exports.CONFIG_PARSE_ATTEMPTS = exports.ConfigParseAttempt = exports.ConfigFile = exports.CONFIG_FILENAME = exports.findConfigFile = exports.SECTION_PLACEMENT_MARKER = exports.RETIRED_TOP_LEVEL_MARKER = exports.RETIRED_KEY_MARKER = exports.CONFIG_POLICY_DOC = exports.formatConfigErrorsBanner = exports.ConfigLoader = exports.LoadedConfig = exports.loadAndValidate = exports.toError = exports.runMain = exports.CliArgs = exports.CliArgsCheck = exports.CliArgSet = exports.CliFlag = exports.CliUsage = exports.CliExitError = exports.RuleFailError = exports.InformAiError = exports.ResolvedRuleConfig = exports.ResolvedConfig = void 0;
4
- exports.renderMatchRuleMessage = exports.compileMatchRulePatterns = exports.isMatchRuleAllowedPath = exports.findMatchRuleViolations = exports.MatchRuleViolation = exports.MatchRuleConfig = exports.HOME_KEY_BUILD_GATE_LOG_CAPTURE = exports.HOME_EXPERIMENTAL_SECTION = exports.HOME_CONFIG_FILE = exports.HOME_CONFIG_DIR = exports.RETIRED_HOME_CONFIG_KEYS = exports.RetiredHomeConfigKey = exports.HomeConfigService = exports.HomeConfig = exports.validateChecklistDocs = exports.PrunedKey = exports.PruneResult = exports.ConfigPruner = exports.retiredRuleFor = exports.retiredKeyErrorsIn = exports.retiredKeyError = exports.retiredEntry = exports.isRetiredKey = exports.RetiredConfigKey = exports.RETIRED_SCOPE_RULE = exports.RETIRED_SCOPE_KEY = exports.RETIRED_CONFIG_KEYS = exports.COMMENT_KEY_SUFFIX = exports.validateTopLevelKeys = exports.isCommentKey = exports.unknownKeyErrors = exports.validateCommandsSection = exports.seedEntryForRule = exports.recommendedSeedModeFor = exports.recommendedSeedMode = exports.allRuleNames = exports.validateMatchRulesSection = exports.validateExcludePaths = exports.validateSectionPlacement = exports.validateChecklistsSection = exports.validatePrGateSection = exports.validateWebpiecesConfig = exports.TemplateWriter = exports.writeTemplate = exports.writeTemplateIfMissing = exports.loadTemplate = exports.defaultRulesDir = exports.defaultRules = exports.matchesAnyGlob = exports.isPathExcluded = void 0;
5
- exports.NoDestructureConfig = exports.PrismaConverterConfig = exports.PrismaValidateDtosConfig = exports.NoImplicitAnyConfig = exports.NoAnyUnknownConfig = exports.NoInlineTypeLiteralsConfig = exports.RequireReturnTypeConfig = exports.MaxFileLinesConfig = exports.MaxMethodLinesConfig = exports.WP_FINISH_PUSH_DEV = exports.WP_PUSH_DEV = exports.WP_FINISH_UPSERT_PR = exports.WP_START_UPSERT_PR = exports.WP_FINISH_UPDATE = exports.WP_START_UPDATE = exports.SyncFlowGuidance = exports.WebpiecesRulesConfig = exports.PRUNE_UNKNOWN_COMMAND = exports.PUSH_DEV_STATE_FILE = exports.MERGE_EXPLANATION_FILE = exports.MERGE_IN_PROGRESS_FILE = exports.PR_REVIEW_DIR = exports.MERGE_INFO_DIR = exports.WEBPIECES_TMP_DIR = exports.hasDisable = exports.RULE_NAMES = exports.WEBPIECES_DISABLE = exports.AbstractRule = exports.ChangedFilesOptions = exports.DiffRange = exports.DiffScope = exports.isNewOrModified = exports.hasChangesInRange = exports.findNewMethodSignaturesInDiff = exports.getChangedLineNumbers = exports.getFileDiff = exports.getChangedFiles = exports.resolveBase = exports.detectBase = exports.SkipRuleResult = exports.getCurrentBranch = exports.shouldSkipRule = exports.FieldDef = exports.sectionForRule = exports.isHookGuard = exports.PR_LIFECYCLE_GUARD_KEY = exports.BRANCH_STATE_GUARD_KEY = exports.HOOK_GUARD_NAMES = exports.schemaFieldNames = exports.DEFAULT_MATCH_RULES = void 0;
6
- exports.defaultGates = exports.ReviewContextEntry = exports.DEFAULT_DEV_BRANCH = exports.DEFAULT_DEV_BRANCH_NAMESPACE = exports.DevDeployConfig = exports.LandPrConfig = exports.DEFAULT_BUILD_COMMAND = exports.PrGateConfig = exports.GateDefinition = exports.BranchStateGuardConfig = exports.CLIENT_CREATION_SEVERITIES = exports.NoClientCreationOutsideServerOrClientConfig = exports.VALIDATE_TS_MODES = exports.STRUCTURAL_MODES = exports.ON_OFF_MODES = exports.THROW_CAUSE_MODES = exports.DIRECT_API_RESOLVER_MODES = exports.PRISMA_CONVERTER_MODES = exports.PRISMA_DTOS_MODES = exports.PROJECT_MODES = exports.MODIFIED_CODE_MODES = exports.INLINE_TYPE_MODES = exports.RETURN_TYPE_MODES = exports.FILE_LIMIT_MODES = exports.METHOD_LIMIT_MODES = exports.BaseRuleConfig = exports.ValidateEslintSyncConfig = exports.ValidateVersionsLockedConfig = exports.ValidatePackageJsonConfig = exports.ValidateNoArchitectureCyclesConfig = exports.ValidateArchitectureUnchangedConfig = exports.ValidateTsInSrcConfig = exports.NoJsFilesConfig = exports.DiGraphConfig = exports.NxWiringConfig = exports.RuntimeArchitectureConfig = exports.NoFileImportCyclesConfig = exports.PrLifecycleGuardConfig = exports.BranchCreationGuardConfig = exports.RoleTagConfig = exports.FrameworkTagConfig = exports.InjectAnnotationNotNeededForConcreteClassConfig = exports.NoFunctionOutsideClassConfig = exports.NoProcessExitOutsideMainConfig = exports.NoCustomCssConfig = exports.NoSymbolDiTokensConfig = exports.AngularNoDirectApiInResolverConfig = exports.ThrowCauseRequiredConfig = exports.CatchErrorPatternConfig = exports.NoUnmanagedExceptionsConfig = void 0;
7
- exports.CK_MISSING = exports.CK_FAIL = exports.CK_OVERRIDDEN = exports.CK_WARN = exports.CK_PASS = exports.ChecklistVerdict = exports.ChecklistResult = exports.PrContext = exports.ReviewJson = exports.DEFAULT_RETENTION_DAYS = exports.ProvenanceWriteRequest = exports.OfferedContext = exports.ReviewerPaths = exports.ReviewerTranscript = exports.ReviewProvenance = exports.ReviewProvenanceService = exports.PROVENANCE_SKIPPED = exports.PROVENANCE_MISSING = exports.PROVENANCE_OK = exports.ProvenanceResult = exports.TranscriptScan = exports.ReviewerContext = exports.ReviewerEvidence = exports.SubagentProvenanceService = exports.verifyGateToken = exports.extractGateToken = exports.gateTokenMarker = exports.computeGateToken = exports.GateTokenService = exports.ALL_DIFF_ONE_READ_LINES = exports.READ_TRUNCATION_LINES = exports.ContextEntry = exports.BriefedFile = exports.ReviewerBriefing = exports.ReviewerInstructionsService = exports.ChecklistInstructionsService = exports.ChecklistValidator = exports.formatFileList = exports.normalizeChecklistDoc = exports.toChecklist = exports.ChecklistDefinition = exports.MERGE_MODES = exports.MERGE_MODE_NONE = exports.MERGE_MODE_AUTO = exports.buildDevDeployConfig = exports.buildLandPrConfig = exports.buildPrGateConfig = exports.defaultDevDeployConfig = exports.defaultLandPrConfig = exports.defaultPrGateConfig = void 0;
8
- exports.CLASSIFICATION_CONTENT_IN_MAIN = exports.CLASSIFICATION_SUPERSEDED = exports.CLASSIFICATION_NO_COMMITS = exports.CLASSIFICATION_BACKUP_OF_LIVE = exports.CLASSIFICATION_BACKUP_OF_MERGED = exports.CLASSIFICATION_MERGED_PR = exports.CACHE_STALE_AFTER_MS = exports.CacheFreshness = exports.MergedBranchesService = exports.MergedBranchesCache = exports.DeletableWorktree = exports.DeletableBranch = exports.MergedBranch = exports.squashRecoverySteps = exports.stampCleanMainSyncStatus = exports.computeMainSyncStatus = exports.finishedLock = exports.inProcessLock = exports.tryAcquireMainSyncLock = exports.isRefreshInProgress = exports.isLockStale = exports.writeMainSyncLock = exports.readMainSyncLock = exports.computeAllMainSyncStatuses = exports.writeMainSyncStatusFile = exports.writeMainSyncStatus = exports.readMainSyncStatusFile = exports.readMainSyncStatus = exports.mainSyncLockPath = exports.mainSyncStatusPath = exports.DEFAULT_HANG_TIMEOUT_MINUTES = exports.MainSyncStatusService = exports.MainSyncLock = exports.MAIN_SYNC_STATUS_VERSION = exports.PullRequestIndex = exports.MainSyncFileStore = exports.MainSyncStatusFile = exports.MainSyncStatus = exports.reviewJsonSchemaHint = exports.reviewJsonPath = exports.prDirFor = exports.loadReviewJson = exports.ReviewJsonService = exports.ChecklistReviewContext = exports.RequiredChecklist = exports.VERDICT_STATUSES = exports.VERDICT_RED = exports.VERDICT_YELLOW = exports.VERDICT_GREEN = exports.CK_BAD_FORMAT = void 0;
9
- exports.DEFAULT_MERGE_COMPLETE_COMMAND = exports.DEFAULT_UPSERT_PR_COMMAND = exports.buildCommandsConfig = exports.CommandsConfig = exports.logBranchMutation = exports.branchMutationLogPath = exports.BranchMutationLog = exports.BranchMutationEvent = exports.WorktreeReaper = exports.WorktreeReapResult = exports.ReapedWorktree = exports.BranchReaper = exports.ReapResult = exports.ReapedBranch = exports.WorktreeService = exports.Worktree = exports.BRANCH_RETENTION_KEEP = exports.BRANCH_RETENTION_ARCHIVE_TAG = exports.BRANCH_RETENTION_DELETE = exports.BRANCH_RETENTIONS = exports.ARCHIVE_TAG_PREFIX = exports.ArchiveResult = exports.BranchArchiver = exports.PROMPTABLE_CLASSIFICATIONS = exports.CLASSIFICATION_DETACHED = exports.CLASSIFICATION_CURRENT = exports.CLASSIFICATION_LOCKED = exports.CLASSIFICATION_PRUNABLE = exports.CLASSIFICATION_IN_USE = exports.CLASSIFICATION_NEVER_PROPOSED = void 0;
3
+ exports.RulesConfigDesign = exports.atRoot = exports.AtomicFile = exports.CLAUDE_PROJECT_DIR_UNSET = exports.CLAUDE_PROJECT_DIR_ENV = exports.claudeEnv = exports.ClaudeEnv = exports.RETENTION_DAYS = exports.SweepCount = exports.AgedTreeSweeper = exports.StateMigrationReport = exports.StateDirMigrator = exports.LOGS_STATE_DIR = exports.WORKTREE_STATE_DIR = exports.GitDirs = exports.dotWebpieces = exports.DotWebpieces = exports.INSTRUCT_AI_LEAF = exports.INSTRUCT_AI_DIR = exports.RepoRootFinder = exports.CONFIG_PARSE_RETRY_MILLIS = exports.CONFIG_PARSE_ATTEMPTS = exports.ConfigParseAttempt = exports.ConfigFile = exports.CONFIG_FILENAME = exports.findConfigFile = exports.SECTION_PLACEMENT_MARKER = exports.RETIRED_TOP_LEVEL_MARKER = exports.RETIRED_KEY_MARKER = exports.CONFIG_POLICY_DOC = exports.formatConfigErrorsBanner = exports.ConfigLoader = exports.LoadedConfig = exports.loadAndValidate = exports.toError = exports.runMain = exports.CliArgs = exports.CliArgsCheck = exports.CliArgSet = exports.CliFlag = exports.CliUsage = exports.CliExitError = exports.formatFixOptions = exports.Option = exports.renderRuleFailForHuman = exports.renderRuleFailForAi = exports.RuleFailError = exports.InformAiError = exports.ResolvedRuleConfig = exports.ResolvedConfig = void 0;
4
+ exports.MatchRuleViolation = exports.MatchRuleConfig = exports.HOME_KEY_BUILD_GATE_LOG_CAPTURE = exports.HOME_EXPERIMENTAL_SECTION = exports.HOME_CONFIG_FILE = exports.HOME_CONFIG_DIR = exports.RETIRED_HOME_CONFIG_KEYS = exports.RetiredHomeConfigKey = exports.HomeConfigService = exports.HomeConfig = exports.validateChecklistDocs = exports.PrunedKey = exports.PruneResult = exports.ConfigPruner = exports.retiredRuleFor = exports.retiredKeyErrorsIn = exports.retiredKeyError = exports.retiredEntry = exports.isRetiredKey = exports.RetiredConfigKey = exports.RETIRED_SCOPE_RULE = exports.RETIRED_SCOPE_KEY = exports.RETIRED_CONFIG_KEYS = exports.COMMENT_KEY_SUFFIX = exports.validateTopLevelKeys = exports.isCommentKey = exports.unknownKeyErrors = exports.validateCommandsSection = exports.seedEntryForRule = exports.recommendedSeedModeFor = exports.recommendedSeedMode = exports.allRuleNames = exports.validateMatchRulesSection = exports.validateExcludePaths = exports.validateSectionPlacement = exports.validateChecklistsSection = exports.validatePrGateSection = exports.validateWebpiecesConfig = exports.TemplateWriter = exports.writeTemplate = exports.writeTemplateIfMissing = exports.loadTemplate = exports.defaultRulesDir = exports.defaultRules = exports.matchesAnyGlob = exports.isPathExcluded = exports.ExcludePaths = exports.DESIGN_METADATA_KEYS = exports.isDocumentDesign = exports.DocumentDesign = void 0;
5
+ exports.NoAnyUnknownConfig = exports.NoInlineTypeLiteralsConfig = exports.RequireReturnTypeConfig = exports.MaxFileLinesConfig = exports.MaxMethodLinesConfig = exports.WP_FINISH_PUSH_DEV = exports.WP_PUSH_DEV = exports.WP_FINISH_UPSERT_PR = exports.WP_START_UPSERT_PR = exports.WP_FINISH_UPDATE = exports.WP_START_UPDATE = exports.SyncFlowGuidance = exports.WebpiecesRulesConfig = exports.PRUNE_UNKNOWN_COMMAND = exports.PUSH_DEV_STATE_FILE = exports.MERGE_EXPLANATION_FILE = exports.MERGE_IN_PROGRESS_FILE = exports.PR_REVIEW_DIR = exports.MERGE_INFO_DIR = exports.WEBPIECES_TMP_DIR = exports.hasDisable = exports.RULE_NAMES = exports.WEBPIECES_DISABLE = exports.AbstractRule = exports.ChangedFilesOptions = exports.DiffRange = exports.DiffScope = exports.isNewOrModified = exports.hasChangesInRange = exports.findNewMethodSignaturesInDiff = exports.getChangedLineNumbers = exports.getFileDiff = exports.getChangedFiles = exports.resolveBase = exports.detectBase = exports.SkipRuleResult = exports.getCurrentBranch = exports.shouldSkipRule = exports.FieldDef = exports.sectionForRule = exports.isHookGuard = exports.PR_LIFECYCLE_GUARD_KEY = exports.BRANCH_STATE_GUARD_KEY = exports.HOOK_GUARD_NAMES = exports.schemaFieldNames = exports.DEFAULT_MATCH_RULES = exports.renderMatchRuleMessage = exports.compileMatchRulePatterns = exports.isMatchRuleAllowedPath = exports.findMatchRuleViolations = void 0;
6
+ exports.DevDeployConfig = exports.LandPrConfig = exports.DEFAULT_BUILD_COMMAND = exports.PrGateConfig = exports.GateDefinition = exports.BranchStateGuardConfig = exports.CLIENT_CREATION_SEVERITIES = exports.NoClientCreationOutsideServerOrClientConfig = exports.VALIDATE_TS_MODES = exports.STRUCTURAL_MODES = exports.ON_OFF_MODES = exports.THROW_CAUSE_MODES = exports.DIRECT_API_RESOLVER_MODES = exports.PRISMA_CONVERTER_MODES = exports.PRISMA_DTOS_MODES = exports.PROJECT_MODES = exports.MODIFIED_CODE_MODES = exports.INLINE_TYPE_MODES = exports.RETURN_TYPE_MODES = exports.FILE_LIMIT_MODES = exports.METHOD_LIMIT_MODES = exports.BaseRuleConfig = exports.ValidateEslintSyncConfig = exports.ValidateVersionsLockedConfig = exports.ValidatePackageJsonConfig = exports.ValidateNoArchitectureCyclesConfig = exports.ValidateArchitectureUnchangedConfig = exports.ValidateTsInSrcConfig = exports.NoJsFilesConfig = exports.DiGraphConfig = exports.NxWiringConfig = exports.RuntimeArchitectureConfig = exports.NoFileImportCyclesConfig = exports.PrLifecycleGuardConfig = exports.BranchCreationGuardConfig = exports.RoleTagConfig = exports.FrameworkTagConfig = exports.InjectAnnotationNotNeededForConcreteClassConfig = exports.NoFunctionOutsideClassConfig = exports.NoProcessExitOutsideMainConfig = exports.NoCustomCssConfig = exports.NoSymbolDiTokensConfig = exports.AngularNoDirectApiInResolverConfig = exports.ThrowCauseRequiredConfig = exports.CatchErrorPatternConfig = exports.NoUnmanagedExceptionsConfig = exports.NoDestructureConfig = exports.PrismaConverterConfig = exports.PrismaValidateDtosConfig = exports.NoImplicitAnyConfig = void 0;
7
+ exports.CK_PASS = exports.ChecklistVerdict = exports.ChecklistResult = exports.PrContext = exports.ReviewJson = exports.DEFAULT_RETENTION_DAYS = exports.ProvenanceWriteRequest = exports.OfferedContext = exports.ReviewerPaths = exports.ReviewerTranscript = exports.ReviewProvenance = exports.ReviewProvenanceService = exports.PROVENANCE_SKIPPED = exports.PROVENANCE_MISSING = exports.PROVENANCE_OK = exports.ProvenanceResult = exports.TranscriptScan = exports.ReviewerContext = exports.ReviewerEvidence = exports.SubagentProvenanceService = exports.verifyGateToken = exports.extractGateToken = exports.gateTokenMarker = exports.computeGateToken = exports.GateTokenService = exports.ALL_DIFF_ONE_READ_LINES = exports.READ_TRUNCATION_LINES = exports.ContextEntry = exports.BriefedFile = exports.ReviewerBriefing = exports.ReviewerInstructionsService = exports.ChecklistInstructionsService = exports.ChecklistValidator = exports.formatFileList = exports.normalizeChecklistDoc = exports.toChecklist = exports.ChecklistDefinition = exports.MERGE_MODES = exports.MERGE_MODE_NONE = exports.MERGE_MODE_AUTO = exports.buildDevDeployConfig = exports.buildLandPrConfig = exports.buildPrGateConfig = exports.defaultDevDeployConfig = exports.defaultLandPrConfig = exports.defaultPrGateConfig = exports.defaultGates = exports.ReviewContextEntry = exports.DEFAULT_DEV_BRANCH = exports.DEFAULT_DEV_BRANCH_NAMESPACE = void 0;
8
+ exports.CLASSIFICATION_BACKUP_OF_MERGED = exports.CLASSIFICATION_MERGED_PR = exports.CACHE_STALE_AFTER_MS = exports.CacheFreshness = exports.MergedBranchesService = exports.MergedBranchesCache = exports.DeletableWorktree = exports.DeletableBranch = exports.MergedBranch = exports.squashRecoverySteps = exports.stampCleanMainSyncStatus = exports.computeMainSyncStatus = exports.finishedLock = exports.inProcessLock = exports.tryAcquireMainSyncLock = exports.isRefreshInProgress = exports.isLockStale = exports.writeMainSyncLock = exports.readMainSyncLock = exports.computeAllMainSyncStatuses = exports.writeMainSyncStatusFile = exports.writeMainSyncStatus = exports.readMainSyncStatusFile = exports.readMainSyncStatus = exports.mainSyncLockPath = exports.mainSyncStatusPath = exports.DEFAULT_HANG_TIMEOUT_MINUTES = exports.MainSyncStatusService = exports.MainSyncLock = exports.MAIN_SYNC_STATUS_VERSION = exports.PullRequestIndex = exports.MainSyncFileStore = exports.MainSyncStatusFile = exports.MainSyncStatus = exports.reviewJsonSchemaHint = exports.reviewJsonPath = exports.prDirFor = exports.loadReviewJson = exports.ReviewJsonService = exports.ChecklistReviewContext = exports.RequiredChecklist = exports.VERDICT_STATUSES = exports.VERDICT_RED = exports.VERDICT_YELLOW = exports.VERDICT_GREEN = exports.CK_BAD_FORMAT = exports.CK_MISSING = exports.CK_FAIL = exports.CK_OVERRIDDEN = exports.CK_WARN = void 0;
9
+ exports.DEFAULT_MERGE_COMPLETE_COMMAND = exports.DEFAULT_UPSERT_PR_COMMAND = exports.buildCommandsConfig = exports.CommandsConfig = exports.logBranchMutation = exports.branchMutationLogPath = exports.BranchMutationLog = exports.BranchMutationEvent = exports.WorktreeReaper = exports.WorktreeReapResult = exports.ReapedWorktree = exports.BranchReaper = exports.ReapResult = exports.ReapedBranch = exports.WorktreeService = exports.Worktree = exports.BRANCH_RETENTION_KEEP = exports.BRANCH_RETENTION_ARCHIVE_TAG = exports.BRANCH_RETENTION_DELETE = exports.BRANCH_RETENTIONS = exports.ARCHIVE_TAG_PREFIX = exports.ArchiveResult = exports.BranchArchiver = exports.PROMPTABLE_CLASSIFICATIONS = exports.CLASSIFICATION_DETACHED = exports.CLASSIFICATION_CURRENT = exports.CLASSIFICATION_LOCKED = exports.CLASSIFICATION_PRUNABLE = exports.CLASSIFICATION_IN_USE = exports.CLASSIFICATION_NEVER_PROPOSED = exports.CLASSIFICATION_CONTENT_IN_MAIN = exports.CLASSIFICATION_SUPERSEDED = exports.CLASSIFICATION_NO_COMMITS = exports.CLASSIFICATION_BACKUP_OF_LIVE = void 0;
10
10
  var types_1 = require("./types");
11
11
  Object.defineProperty(exports, "ResolvedConfig", { enumerable: true, get: function () { return types_1.ResolvedConfig; } });
12
12
  Object.defineProperty(exports, "ResolvedRuleConfig", { enumerable: true, get: function () { return types_1.ResolvedRuleConfig; } });
@@ -14,6 +14,13 @@ var inform_ai_error_1 = require("./inform-ai-error");
14
14
  Object.defineProperty(exports, "InformAiError", { enumerable: true, get: function () { return inform_ai_error_1.InformAiError; } });
15
15
  var rule_fail_error_1 = require("./rule-fail-error");
16
16
  Object.defineProperty(exports, "RuleFailError", { enumerable: true, get: function () { return rule_fail_error_1.RuleFailError; } });
17
+ Object.defineProperty(exports, "renderRuleFailForAi", { enumerable: true, get: function () { return rule_fail_error_1.renderRuleFailForAi; } });
18
+ Object.defineProperty(exports, "renderRuleFailForHuman", { enumerable: true, get: function () { return rule_fail_error_1.renderRuleFailForHuman; } });
19
+ // THE one representation of a cure, shared by RuleFailError (build-time) and FixHint (edit-time), plus
20
+ // the one renderer that owns the "Fix Option N:" numbering and the "(preferred)" tag.
21
+ var fix_option_1 = require("./fix-option");
22
+ Object.defineProperty(exports, "Option", { enumerable: true, get: function () { return fix_option_1.Option; } });
23
+ Object.defineProperty(exports, "formatFixOptions", { enumerable: true, get: function () { return fix_option_1.formatFixOptions; } });
17
24
  var cli_exit_error_1 = require("./cli-exit-error");
18
25
  Object.defineProperty(exports, "CliExitError", { enumerable: true, get: function () { return cli_exit_error_1.CliExitError; } });
19
26
  var cli_args_1 = require("./cli-args");
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from './types';\nexport { InformAiError } from './inform-ai-error';\nexport { RuleFailError } from './rule-fail-error';\nexport { CliExitError } from './cli-exit-error';\nexport { CliUsage, CliFlag, CliArgSet, CliArgsCheck, CliArgs } from './cli-args';\nexport { runMain } from './run-main';\nexport { toError } from './to-error';\nexport { loadAndValidate, LoadedConfig, ConfigLoader } from './load-config';\n// The validation-failure banner: ONE cure (edit the file), plus the marker phrases the validator\n// messages embed rather than re-type.\nexport {\n formatConfigErrorsBanner,\n CONFIG_POLICY_DOC,\n RETIRED_KEY_MARKER,\n RETIRED_TOP_LEVEL_MARKER,\n SECTION_PLACEMENT_MARKER,\n} from './config-error-banner';\nexport { findConfigFile, CONFIG_FILENAME, ConfigFile, ConfigParseAttempt, CONFIG_PARSE_ATTEMPTS, CONFIG_PARSE_RETRY_MILLIS } from './config-file';\n// The PARSED-BUT-UNVALIDATED config shape. Exported for readers that walk the file generically rather\n// than through the typed config (the pr-gate active-hatch dashboard section reads every rule's hatches).\nexport type { RawConfigFile } from './config-file';\nexport { RepoRootFinder, INSTRUCT_AI_DIR, INSTRUCT_AI_LEAF } from './repo-root';\n// The scoped `.webpieces` resolver. EVERY reader/writer of `.webpieces/...` goes through one of its two\n// named methods so the call site declares whether the state is repo-wide or worktree-private.\nexport { DotWebpieces, dotWebpieces, GitDirs, WORKTREE_STATE_DIR, LOGS_STATE_DIR } from './state-dir';\nexport { StateDirMigrator, StateMigrationReport } from './state-dir-migration';\n// There is NO machine-global state root. `MachineStateHome`/`StateHome`/`WEBPIECES_STATE_HOME` and the\n// `PrBodyStore` that used them are DELETED: the one artifact that needed a scope above the clone was the\n// gated squash body, and GitHub holds it now (it IS the PR description). Every `.webpieces` path a\n// webpieces tool writes is `{repo}/.webpieces`, resolved through `DotWebpieces` above. See\n// `decisions/0005-the-pr-description-is-the-merge-body.md`.\nexport { AgedTreeSweeper, SweepCount, RETENTION_DAYS } from './aged-tree-sweep';\nexport { ClaudeEnv, claudeEnv, CLAUDE_PROJECT_DIR_ENV, CLAUDE_PROJECT_DIR_UNSET } from './claude-env';\nexport { AtomicFile } from './atomic-file';\n// The ONE formatter for a remedy that must run in a named directory: `cd '<root>' && <command>`.\n// Single-quoted so a repo path containing a space is still runnable (and still un-smuggleable).\nexport { atRoot } from './at-root';\nexport { RulesConfigDesign } from './rules-config-design';\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './di';\nexport { ExcludePaths } from './exclude-hook-paths';\nexport { isPathExcluded, matchesAnyGlob } from './exclude-paths';\nexport { defaultRules, defaultRulesDir } from './default-rules';\nexport { loadTemplate, writeTemplateIfMissing, writeTemplate, TemplateWriter } from './load-template';\nexport { validateWebpiecesConfig, validatePrGateSection, validateChecklistsSection, validateSectionPlacement, validateExcludePaths, validateMatchRulesSection, allRuleNames, recommendedSeedMode, recommendedSeedModeFor, seedEntryForRule } from './validate-config';\nexport { validateCommandsSection } from './commands-section-validators';\nexport { unknownKeyErrors, isCommentKey, validateTopLevelKeys, COMMENT_KEY_SUFFIX } from './config-key-rules';\n// The retired-key table + the no-back-compat policy it enforces. Exported so the installer can migrate\n// what the errors instruct, and so consumers can enumerate retirements.\nexport { RETIRED_CONFIG_KEYS, RETIRED_SCOPE_KEY, RETIRED_SCOPE_RULE, RetiredConfigKey, isRetiredKey, retiredEntry, retiredKeyError, retiredKeyErrorsIn, retiredRuleFor } from './retired-config-keys';\n// The MECHANICAL cure the unknown-rule error and the banner both name: strip every key no validator has a\n// schema for, so cleanliness is one command rather than a judgement call made while every Bash call is\n// blocked. `PRUNE_UNKNOWN_COMMAND` (constants.ts) is the single spelling of that command.\nexport { ConfigPruner, PruneResult, PrunedKey } from './config-pruner';\nexport { validateChecklistDocs } from './checklist-docs-validator';\n// EXPERIMENTAL, and deliberately NOT an advertised knob. The OPTIONAL machine-local `~/.webpieces/config.json`:\n// absent (the normal state for every consumer) means all-defaults, silently; present means strictly validated,\n// with its own retirement table. `isHomeConfigPath` is what grants the file its unconditional Write/Edit PASS\n// in the hook guards, which is what keeps a rejection repairable.\nexport {\n HomeConfig, HomeConfigService, RetiredHomeConfigKey, RETIRED_HOME_CONFIG_KEYS,\n HOME_CONFIG_DIR, HOME_CONFIG_FILE, HOME_EXPERIMENTAL_SECTION, HOME_KEY_BUILD_GATE_LOG_CAPTURE,\n} from './home-config';\nexport {\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n isMatchRuleAllowedPath,\n compileMatchRulePatterns,\n renderMatchRuleMessage,\n DEFAULT_MATCH_RULES,\n} from './match-rules-config';\nexport type { ConfigSection } from './sections';\nexport { schemaFieldNames } from './rule-schemas';\nexport { HOOK_GUARD_NAMES, BRANCH_STATE_GUARD_KEY, PR_LIFECYCLE_GUARD_KEY, isHookGuard, sectionForRule } from './sections';\nexport { FieldDef } from './field-def';\nexport type { SchemaShape } from './field-def';\nexport { shouldSkipRule, getCurrentBranch } from './skip-rule';\nexport { SkipRuleResult } from './skip-rule';\nexport {\n detectBase,\n resolveBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n findNewMethodSignaturesInDiff,\n hasChangesInRange,\n isNewOrModified,\n DiffScope,\n DiffRange,\n ChangedFilesOptions,\n} from './diff-scope';\nexport { AbstractRule } from './abstract-rule';\nexport {\n WEBPIECES_DISABLE,\n RULE_NAMES,\n hasDisable,\n WEBPIECES_TMP_DIR,\n MERGE_INFO_DIR,\n PR_REVIEW_DIR,\n MERGE_IN_PROGRESS_FILE,\n MERGE_EXPLANATION_FILE,\n PUSH_DEV_STATE_FILE,\n PRUNE_UNKNOWN_COMMAND,\n} from './constants';\nexport { WebpiecesRulesConfig } from './WebpiecesRulesConfig';\nexport {\n SyncFlowGuidance,\n WP_START_UPDATE,\n WP_FINISH_UPDATE,\n WP_START_UPSERT_PR,\n WP_FINISH_UPSERT_PR,\n WP_PUSH_DEV,\n WP_FINISH_PUSH_DEV,\n} from './sync-flow-guidance';\nexport {\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n NoUnmanagedExceptionsConfig,\n CatchErrorPatternConfig,\n ThrowCauseRequiredConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n NoCustomCssConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n BranchCreationGuardConfig,\n PrLifecycleGuardConfig,\n NoFileImportCyclesConfig,\n RuntimeArchitectureConfig,\n NxWiringConfig,\n DiGraphConfig,\n NoJsFilesConfig,\n ValidateTsInSrcConfig,\n ValidateArchitectureUnchangedConfig,\n ValidateNoArchitectureCyclesConfig,\n ValidatePackageJsonConfig,\n ValidateVersionsLockedConfig,\n ValidateEslintSyncConfig,\n BaseRuleConfig,\n} from './rule-configs';\n// Mode unions + their value arrays — the single source of truth shared with code-rules.\nexport {\n METHOD_LIMIT_MODES,\n FILE_LIMIT_MODES,\n RETURN_TYPE_MODES,\n INLINE_TYPE_MODES,\n MODIFIED_CODE_MODES,\n PROJECT_MODES,\n PRISMA_DTOS_MODES,\n PRISMA_CONVERTER_MODES,\n DIRECT_API_RESOLVER_MODES,\n THROW_CAUSE_MODES,\n ON_OFF_MODES,\n STRUCTURAL_MODES,\n VALIDATE_TS_MODES,\n} from './rule-configs';\nexport {\n NoClientCreationOutsideServerOrClientConfig,\n CLIENT_CREATION_SEVERITIES,\n} from './no-client-creation-config';\nexport type { ClientCreationSeverity } from './no-client-creation-config';\nexport type {\n MethodLimitMode,\n FileLimitMode,\n ReturnTypeMode,\n InlineTypeMode,\n ModifiedCodeMode,\n ProjectMode,\n PrismaValidateDtosMode,\n PrismaConverterMode,\n DirectApiResolverMode,\n ThrowCauseMode,\n OnOffMode,\n StructuralMode,\n ValidateTsMode,\n} from './rule-configs';\nexport {\n BranchStateGuardConfig,\n} from './main-sync-guard-configs';\nexport {\n GateDefinition,\n PrGateConfig,\n DEFAULT_BUILD_COMMAND,\n LandPrConfig,\n DevDeployConfig,\n DEFAULT_DEV_BRANCH_NAMESPACE,\n DEFAULT_DEV_BRANCH,\n ReviewContextEntry,\n defaultGates,\n defaultPrGateConfig,\n defaultLandPrConfig,\n defaultDevDeployConfig,\n buildPrGateConfig,\n buildLandPrConfig,\n buildDevDeployConfig,\n MERGE_MODE_AUTO,\n MERGE_MODE_NONE,\n MERGE_MODES,\n} from './pr-gate-config';\nexport {\n ChecklistDefinition,\n toChecklist,\n normalizeChecklistDoc,\n formatFileList,\n} from './checklist-config';\nexport type { RawChecklistItem } from './checklist-config';\nexport { ChecklistValidator } from './checklist-validator';\nexport { ChecklistInstructionsService } from './checklist-instructions';\nexport {\n ReviewerInstructionsService,\n ReviewerBriefing,\n BriefedFile,\n ContextEntry,\n READ_TRUNCATION_LINES,\n ALL_DIFF_ONE_READ_LINES,\n} from './reviewer-instructions';\nexport {\n GateTokenService,\n computeGateToken,\n gateTokenMarker,\n extractGateToken,\n verifyGateToken,\n} from './gate-token';\nexport {\n SubagentProvenanceService,\n ReviewerEvidence,\n ReviewerContext,\n TranscriptScan,\n ProvenanceResult,\n PROVENANCE_OK,\n PROVENANCE_MISSING,\n PROVENANCE_SKIPPED,\n} from './subagent-provenance';\nexport {\n ReviewProvenanceService,\n ReviewProvenance,\n ReviewerTranscript,\n ReviewerPaths,\n OfferedContext,\n ProvenanceWriteRequest,\n DEFAULT_RETENTION_DAYS,\n} from './review-provenance';\nexport {\n ReviewJson,\n PrContext,\n ChecklistResult,\n ChecklistVerdict,\n CK_PASS,\n CK_WARN,\n CK_OVERRIDDEN,\n CK_FAIL,\n CK_MISSING,\n CK_BAD_FORMAT,\n VERDICT_GREEN,\n VERDICT_YELLOW,\n VERDICT_RED,\n VERDICT_STATUSES,\n RequiredChecklist,\n ChecklistReviewContext,\n ReviewJsonService,\n loadReviewJson,\n prDirFor,\n reviewJsonPath,\n reviewJsonSchemaHint,\n} from './review-json';\nexport {\n MainSyncStatus,\n MainSyncStatusFile,\n MainSyncFileStore,\n PullRequestIndex,\n MAIN_SYNC_STATUS_VERSION,\n} from './main-sync-file';\nexport {\n MainSyncLock,\n MainSyncStatusService,\n DEFAULT_HANG_TIMEOUT_MINUTES,\n mainSyncStatusPath,\n mainSyncLockPath,\n readMainSyncStatus,\n readMainSyncStatusFile,\n writeMainSyncStatus,\n writeMainSyncStatusFile,\n computeAllMainSyncStatuses,\n readMainSyncLock,\n writeMainSyncLock,\n isLockStale,\n isRefreshInProgress,\n tryAcquireMainSyncLock,\n inProcessLock,\n finishedLock,\n computeMainSyncStatus,\n stampCleanMainSyncStatus,\n squashRecoverySteps,\n} from './main-sync-status';\nexport {\n MergedBranch,\n DeletableBranch,\n DeletableWorktree,\n MergedBranchesCache,\n MergedBranchesService,\n CacheFreshness,\n CACHE_STALE_AFTER_MS,\n CLASSIFICATION_MERGED_PR,\n CLASSIFICATION_BACKUP_OF_MERGED,\n CLASSIFICATION_BACKUP_OF_LIVE,\n CLASSIFICATION_NO_COMMITS,\n CLASSIFICATION_SUPERSEDED,\n CLASSIFICATION_CONTENT_IN_MAIN,\n CLASSIFICATION_NEVER_PROPOSED,\n CLASSIFICATION_IN_USE,\n CLASSIFICATION_PRUNABLE,\n CLASSIFICATION_LOCKED,\n CLASSIFICATION_CURRENT,\n CLASSIFICATION_DETACHED,\n PROMPTABLE_CLASSIFICATIONS,\n} from './merged-branches';\nexport {\n BranchArchiver,\n ArchiveResult,\n ARCHIVE_TAG_PREFIX,\n BRANCH_RETENTIONS,\n BRANCH_RETENTION_DELETE,\n BRANCH_RETENTION_ARCHIVE_TAG,\n BRANCH_RETENTION_KEEP,\n} from './branch-archiver';\nexport {\n Worktree,\n WorktreeService,\n} from './worktrees';\nexport {\n ReapedBranch,\n ReapResult,\n BranchReaper,\n} from './branch-reaper';\nexport {\n ReapedWorktree,\n WorktreeReapResult,\n WorktreeReaper,\n} from './worktree-reaper';\nexport type { MutationVerb, MutationPhase } from './branch-mutation-log';\nexport {\n BranchMutationEvent,\n BranchMutationLog,\n branchMutationLogPath,\n logBranchMutation,\n} from './branch-mutation-log';\nexport {\n CommandsConfig,\n buildCommandsConfig,\n DEFAULT_UPSERT_PR_COMMAND,\n DEFAULT_MERGE_COMPLETE_COMMAND,\n} from './commands-config';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from './types';\nexport { InformAiError } from './inform-ai-error';\nexport { RuleFailError, renderRuleFailForAi, renderRuleFailForHuman } from './rule-fail-error';\n// THE one representation of a cure, shared by RuleFailError (build-time) and FixHint (edit-time), plus\n// the one renderer that owns the \"Fix Option N:\" numbering and the \"(preferred)\" tag.\nexport { Option, formatFixOptions } from './fix-option';\nexport { CliExitError } from './cli-exit-error';\nexport { CliUsage, CliFlag, CliArgSet, CliArgsCheck, CliArgs } from './cli-args';\nexport { runMain } from './run-main';\nexport { toError } from './to-error';\nexport { loadAndValidate, LoadedConfig, ConfigLoader } from './load-config';\n// The validation-failure banner: ONE cure (edit the file), plus the marker phrases the validator\n// messages embed rather than re-type.\nexport {\n formatConfigErrorsBanner,\n CONFIG_POLICY_DOC,\n RETIRED_KEY_MARKER,\n RETIRED_TOP_LEVEL_MARKER,\n SECTION_PLACEMENT_MARKER,\n} from './config-error-banner';\nexport { findConfigFile, CONFIG_FILENAME, ConfigFile, ConfigParseAttempt, CONFIG_PARSE_ATTEMPTS, CONFIG_PARSE_RETRY_MILLIS } from './config-file';\n// The PARSED-BUT-UNVALIDATED config shape. Exported for readers that walk the file generically rather\n// than through the typed config (the pr-gate active-hatch dashboard section reads every rule's hatches).\nexport type { RawConfigFile } from './config-file';\nexport { RepoRootFinder, INSTRUCT_AI_DIR, INSTRUCT_AI_LEAF } from './repo-root';\n// The scoped `.webpieces` resolver. EVERY reader/writer of `.webpieces/...` goes through one of its two\n// named methods so the call site declares whether the state is repo-wide or worktree-private.\nexport { DotWebpieces, dotWebpieces, GitDirs, WORKTREE_STATE_DIR, LOGS_STATE_DIR } from './state-dir';\nexport { StateDirMigrator, StateMigrationReport } from './state-dir-migration';\n// There is NO machine-global state root. `MachineStateHome`/`StateHome`/`WEBPIECES_STATE_HOME` and the\n// `PrBodyStore` that used them are DELETED: the one artifact that needed a scope above the clone was the\n// gated squash body, and GitHub holds it now (it IS the PR description). Every `.webpieces` path a\n// webpieces tool writes is `{repo}/.webpieces`, resolved through `DotWebpieces` above. See\n// `decisions/0005-the-pr-description-is-the-merge-body.md`.\nexport { AgedTreeSweeper, SweepCount, RETENTION_DAYS } from './aged-tree-sweep';\nexport { ClaudeEnv, claudeEnv, CLAUDE_PROJECT_DIR_ENV, CLAUDE_PROJECT_DIR_UNSET } from './claude-env';\nexport { AtomicFile } from './atomic-file';\n// The ONE formatter for a remedy that must run in a named directory: `cd '<root>' && <command>`.\n// Single-quoted so a repo path containing a space is still runnable (and still un-smuggleable).\nexport { atRoot } from './at-root';\nexport { RulesConfigDesign } from './rules-config-design';\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './di';\nexport { ExcludePaths } from './exclude-hook-paths';\nexport { isPathExcluded, matchesAnyGlob } from './exclude-paths';\nexport { defaultRules, defaultRulesDir } from './default-rules';\nexport { loadTemplate, writeTemplateIfMissing, writeTemplate, TemplateWriter } from './load-template';\nexport { validateWebpiecesConfig, validatePrGateSection, validateChecklistsSection, validateSectionPlacement, validateExcludePaths, validateMatchRulesSection, allRuleNames, recommendedSeedMode, recommendedSeedModeFor, seedEntryForRule } from './validate-config';\nexport { validateCommandsSection } from './commands-section-validators';\nexport { unknownKeyErrors, isCommentKey, validateTopLevelKeys, COMMENT_KEY_SUFFIX } from './config-key-rules';\n// The retired-key table + the no-back-compat policy it enforces. Exported so the installer can migrate\n// what the errors instruct, and so consumers can enumerate retirements.\nexport { RETIRED_CONFIG_KEYS, RETIRED_SCOPE_KEY, RETIRED_SCOPE_RULE, RetiredConfigKey, isRetiredKey, retiredEntry, retiredKeyError, retiredKeyErrorsIn, retiredRuleFor } from './retired-config-keys';\n// The MECHANICAL cure the unknown-rule error and the banner both name: strip every key no validator has a\n// schema for, so cleanliness is one command rather than a judgement call made while every Bash call is\n// blocked. `PRUNE_UNKNOWN_COMMAND` (constants.ts) is the single spelling of that command.\nexport { ConfigPruner, PruneResult, PrunedKey } from './config-pruner';\nexport { validateChecklistDocs } from './checklist-docs-validator';\n// EXPERIMENTAL, and deliberately NOT an advertised knob. The OPTIONAL machine-local `~/.webpieces/config.json`:\n// absent (the normal state for every consumer) means all-defaults, silently; present means strictly validated,\n// with its own retirement table. `isHomeConfigPath` is what grants the file its unconditional Write/Edit PASS\n// in the hook guards, which is what keeps a rejection repairable.\nexport {\n HomeConfig, HomeConfigService, RetiredHomeConfigKey, RETIRED_HOME_CONFIG_KEYS,\n HOME_CONFIG_DIR, HOME_CONFIG_FILE, HOME_EXPERIMENTAL_SECTION, HOME_KEY_BUILD_GATE_LOG_CAPTURE,\n} from './home-config';\nexport {\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n isMatchRuleAllowedPath,\n compileMatchRulePatterns,\n renderMatchRuleMessage,\n DEFAULT_MATCH_RULES,\n} from './match-rules-config';\nexport type { ConfigSection } from './sections';\nexport { schemaFieldNames } from './rule-schemas';\nexport { HOOK_GUARD_NAMES, BRANCH_STATE_GUARD_KEY, PR_LIFECYCLE_GUARD_KEY, isHookGuard, sectionForRule } from './sections';\nexport { FieldDef } from './field-def';\nexport type { SchemaShape } from './field-def';\nexport { shouldSkipRule, getCurrentBranch } from './skip-rule';\nexport { SkipRuleResult } from './skip-rule';\nexport {\n detectBase,\n resolveBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n findNewMethodSignaturesInDiff,\n hasChangesInRange,\n isNewOrModified,\n DiffScope,\n DiffRange,\n ChangedFilesOptions,\n} from './diff-scope';\nexport { AbstractRule } from './abstract-rule';\nexport {\n WEBPIECES_DISABLE,\n RULE_NAMES,\n hasDisable,\n WEBPIECES_TMP_DIR,\n MERGE_INFO_DIR,\n PR_REVIEW_DIR,\n MERGE_IN_PROGRESS_FILE,\n MERGE_EXPLANATION_FILE,\n PUSH_DEV_STATE_FILE,\n PRUNE_UNKNOWN_COMMAND,\n} from './constants';\nexport { WebpiecesRulesConfig } from './WebpiecesRulesConfig';\nexport {\n SyncFlowGuidance,\n WP_START_UPDATE,\n WP_FINISH_UPDATE,\n WP_START_UPSERT_PR,\n WP_FINISH_UPSERT_PR,\n WP_PUSH_DEV,\n WP_FINISH_PUSH_DEV,\n} from './sync-flow-guidance';\nexport {\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n NoUnmanagedExceptionsConfig,\n CatchErrorPatternConfig,\n ThrowCauseRequiredConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n NoCustomCssConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n BranchCreationGuardConfig,\n PrLifecycleGuardConfig,\n NoFileImportCyclesConfig,\n RuntimeArchitectureConfig,\n NxWiringConfig,\n DiGraphConfig,\n NoJsFilesConfig,\n ValidateTsInSrcConfig,\n ValidateArchitectureUnchangedConfig,\n ValidateNoArchitectureCyclesConfig,\n ValidatePackageJsonConfig,\n ValidateVersionsLockedConfig,\n ValidateEslintSyncConfig,\n BaseRuleConfig,\n} from './rule-configs';\n// Mode unions + their value arrays — the single source of truth shared with code-rules.\nexport {\n METHOD_LIMIT_MODES,\n FILE_LIMIT_MODES,\n RETURN_TYPE_MODES,\n INLINE_TYPE_MODES,\n MODIFIED_CODE_MODES,\n PROJECT_MODES,\n PRISMA_DTOS_MODES,\n PRISMA_CONVERTER_MODES,\n DIRECT_API_RESOLVER_MODES,\n THROW_CAUSE_MODES,\n ON_OFF_MODES,\n STRUCTURAL_MODES,\n VALIDATE_TS_MODES,\n} from './rule-configs';\nexport {\n NoClientCreationOutsideServerOrClientConfig,\n CLIENT_CREATION_SEVERITIES,\n} from './no-client-creation-config';\nexport type { ClientCreationSeverity } from './no-client-creation-config';\nexport type {\n MethodLimitMode,\n FileLimitMode,\n ReturnTypeMode,\n InlineTypeMode,\n ModifiedCodeMode,\n ProjectMode,\n PrismaValidateDtosMode,\n PrismaConverterMode,\n DirectApiResolverMode,\n ThrowCauseMode,\n OnOffMode,\n StructuralMode,\n ValidateTsMode,\n} from './rule-configs';\nexport {\n BranchStateGuardConfig,\n} from './main-sync-guard-configs';\nexport {\n GateDefinition,\n PrGateConfig,\n DEFAULT_BUILD_COMMAND,\n LandPrConfig,\n DevDeployConfig,\n DEFAULT_DEV_BRANCH_NAMESPACE,\n DEFAULT_DEV_BRANCH,\n ReviewContextEntry,\n defaultGates,\n defaultPrGateConfig,\n defaultLandPrConfig,\n defaultDevDeployConfig,\n buildPrGateConfig,\n buildLandPrConfig,\n buildDevDeployConfig,\n MERGE_MODE_AUTO,\n MERGE_MODE_NONE,\n MERGE_MODES,\n} from './pr-gate-config';\nexport {\n ChecklistDefinition,\n toChecklist,\n normalizeChecklistDoc,\n formatFileList,\n} from './checklist-config';\nexport type { RawChecklistItem } from './checklist-config';\nexport { ChecklistValidator } from './checklist-validator';\nexport { ChecklistInstructionsService } from './checklist-instructions';\nexport {\n ReviewerInstructionsService,\n ReviewerBriefing,\n BriefedFile,\n ContextEntry,\n READ_TRUNCATION_LINES,\n ALL_DIFF_ONE_READ_LINES,\n} from './reviewer-instructions';\nexport {\n GateTokenService,\n computeGateToken,\n gateTokenMarker,\n extractGateToken,\n verifyGateToken,\n} from './gate-token';\nexport {\n SubagentProvenanceService,\n ReviewerEvidence,\n ReviewerContext,\n TranscriptScan,\n ProvenanceResult,\n PROVENANCE_OK,\n PROVENANCE_MISSING,\n PROVENANCE_SKIPPED,\n} from './subagent-provenance';\nexport {\n ReviewProvenanceService,\n ReviewProvenance,\n ReviewerTranscript,\n ReviewerPaths,\n OfferedContext,\n ProvenanceWriteRequest,\n DEFAULT_RETENTION_DAYS,\n} from './review-provenance';\nexport {\n ReviewJson,\n PrContext,\n ChecklistResult,\n ChecklistVerdict,\n CK_PASS,\n CK_WARN,\n CK_OVERRIDDEN,\n CK_FAIL,\n CK_MISSING,\n CK_BAD_FORMAT,\n VERDICT_GREEN,\n VERDICT_YELLOW,\n VERDICT_RED,\n VERDICT_STATUSES,\n RequiredChecklist,\n ChecklistReviewContext,\n ReviewJsonService,\n loadReviewJson,\n prDirFor,\n reviewJsonPath,\n reviewJsonSchemaHint,\n} from './review-json';\nexport {\n MainSyncStatus,\n MainSyncStatusFile,\n MainSyncFileStore,\n PullRequestIndex,\n MAIN_SYNC_STATUS_VERSION,\n} from './main-sync-file';\nexport {\n MainSyncLock,\n MainSyncStatusService,\n DEFAULT_HANG_TIMEOUT_MINUTES,\n mainSyncStatusPath,\n mainSyncLockPath,\n readMainSyncStatus,\n readMainSyncStatusFile,\n writeMainSyncStatus,\n writeMainSyncStatusFile,\n computeAllMainSyncStatuses,\n readMainSyncLock,\n writeMainSyncLock,\n isLockStale,\n isRefreshInProgress,\n tryAcquireMainSyncLock,\n inProcessLock,\n finishedLock,\n computeMainSyncStatus,\n stampCleanMainSyncStatus,\n squashRecoverySteps,\n} from './main-sync-status';\nexport {\n MergedBranch,\n DeletableBranch,\n DeletableWorktree,\n MergedBranchesCache,\n MergedBranchesService,\n CacheFreshness,\n CACHE_STALE_AFTER_MS,\n CLASSIFICATION_MERGED_PR,\n CLASSIFICATION_BACKUP_OF_MERGED,\n CLASSIFICATION_BACKUP_OF_LIVE,\n CLASSIFICATION_NO_COMMITS,\n CLASSIFICATION_SUPERSEDED,\n CLASSIFICATION_CONTENT_IN_MAIN,\n CLASSIFICATION_NEVER_PROPOSED,\n CLASSIFICATION_IN_USE,\n CLASSIFICATION_PRUNABLE,\n CLASSIFICATION_LOCKED,\n CLASSIFICATION_CURRENT,\n CLASSIFICATION_DETACHED,\n PROMPTABLE_CLASSIFICATIONS,\n} from './merged-branches';\nexport {\n BranchArchiver,\n ArchiveResult,\n ARCHIVE_TAG_PREFIX,\n BRANCH_RETENTIONS,\n BRANCH_RETENTION_DELETE,\n BRANCH_RETENTION_ARCHIVE_TAG,\n BRANCH_RETENTION_KEEP,\n} from './branch-archiver';\nexport {\n Worktree,\n WorktreeService,\n} from './worktrees';\nexport {\n ReapedBranch,\n ReapResult,\n BranchReaper,\n} from './branch-reaper';\nexport {\n ReapedWorktree,\n WorktreeReapResult,\n WorktreeReaper,\n} from './worktree-reaper';\nexport type { MutationVerb, MutationPhase } from './branch-mutation-log';\nexport {\n BranchMutationEvent,\n BranchMutationLog,\n branchMutationLogPath,\n logBranchMutation,\n} from './branch-mutation-log';\nexport {\n CommandsConfig,\n buildCommandsConfig,\n DEFAULT_UPSERT_PR_COMMAND,\n DEFAULT_MERGE_COMPLETE_COMMAND,\n} from './commands-config';\n"]}
@@ -1,3 +1,4 @@
1
+ import { Option } from './fix-option';
1
2
  /**
2
3
  * Thrown by ANY rule — in `ai-hook-rules` (edit-time) OR `code-rules` (build/CI-time) — to report a
3
4
  * failure from anywhere in its logic. Each engine wraps every rule in a per-rule try/catch, so a
@@ -14,12 +15,19 @@
14
15
  * - `aiMessage` — what the AI sees in the ai-hook path (also `Error.message`).
15
16
  * - `humanMessage` — what a developer/CI sees in the code-rules console (defaults to `aiMessage`).
16
17
  *
17
- * `line`/`snippet`/`fixHints` are optional context the ai-hook engine folds into its `Violation`.
18
+ * `line`/`snippet`/`fixOptions` are optional context the ai-hook engine folds into its `Violation`.
19
+ *
20
+ * `fixOptions` is `readonly Option[]` — the SAME `Option` that `FixHint.fixOptions` carries, so there is
21
+ * exactly ONE representation of "the list of cures" across both engines, and a build-time rule can mark
22
+ * one cure `preferred` exactly like an edit-time rule can. It was `readonly string[]`; that spelling is
23
+ * deleted and does not compile. NEVER hand-number the cures inside `aiMessage` — the framework
24
+ * (`formatFixOptions`) owns the "Fix Option N:" numbering and the "(preferred)" tag.
18
25
  *
19
26
  * Constructor is positional to match this package's other data classes (`Violation`, `ResolvedConfig`)
20
27
  * and the project's classes-over-interfaces convention. Common throws:
21
28
  * throw new RuleFailError('no-any-unknown', 'Avoid `any` here — use `unknown`.', 42, 'const x: any');
22
- * throw new RuleFailError('max-file-lines', 'File exceeds the limit.', undefined, undefined, ['Split it up']);
29
+ * throw new RuleFailError('max-file-lines', 'File exceeds the limit.', undefined, undefined,
30
+ * [new Option('Split it into two modules', true), new Option('Move the helpers to a sibling file')]);
23
31
  */
24
32
  export declare class RuleFailError extends Error {
25
33
  cause?: Error;
@@ -28,6 +36,18 @@ export declare class RuleFailError extends Error {
28
36
  readonly humanMessage: string;
29
37
  readonly line: number | undefined;
30
38
  readonly snippet: string | undefined;
31
- readonly fixHints: readonly string[];
32
- constructor(ruleName: string, aiMessage: string, line?: number, snippet?: string, fixHints?: readonly string[], humanMessage?: string, cause?: Error);
39
+ readonly fixOptions: readonly Option[];
40
+ constructor(ruleName: string, aiMessage: string, line?: number, snippet?: string, fixOptions?: readonly Option[], humanMessage?: string, cause?: Error);
33
41
  }
42
+ /**
43
+ * The AI-audience rendering of a thrown `RuleFailError`: its `aiMessage` plus its cures, numbered and
44
+ * tagged by the framework. Used by the top-level handlers in `ai-hook-rules`.
45
+ *
46
+ * WHY it exists: every handler used to print `aiMessage`/`humanMessage` alone, so a `RuleFailError`
47
+ * that escaped a per-rule catch reached the AI or the CI console with its `fixOptions` SILENTLY
48
+ * DROPPED — the rule had said how to fix the problem and the renderer threw that away. One renderer per
49
+ * audience means a cure cannot go missing depending on which catch caught the throw.
50
+ */
51
+ export declare function renderRuleFailForAi(error: RuleFailError): string;
52
+ /** The developer/CI rendering: `humanMessage` (which defaults to `aiMessage`) plus the same cures. */
53
+ export declare function renderRuleFailForHuman(error: RuleFailError): string;
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RuleFailError = void 0;
4
+ exports.renderRuleFailForAi = renderRuleFailForAi;
5
+ exports.renderRuleFailForHuman = renderRuleFailForHuman;
6
+ const fix_option_1 = require("./fix-option");
4
7
  /**
5
8
  * Thrown by ANY rule — in `ai-hook-rules` (edit-time) OR `code-rules` (build/CI-time) — to report a
6
9
  * failure from anywhere in its logic. Each engine wraps every rule in a per-rule try/catch, so a
@@ -17,12 +20,19 @@ exports.RuleFailError = void 0;
17
20
  * - `aiMessage` — what the AI sees in the ai-hook path (also `Error.message`).
18
21
  * - `humanMessage` — what a developer/CI sees in the code-rules console (defaults to `aiMessage`).
19
22
  *
20
- * `line`/`snippet`/`fixHints` are optional context the ai-hook engine folds into its `Violation`.
23
+ * `line`/`snippet`/`fixOptions` are optional context the ai-hook engine folds into its `Violation`.
24
+ *
25
+ * `fixOptions` is `readonly Option[]` — the SAME `Option` that `FixHint.fixOptions` carries, so there is
26
+ * exactly ONE representation of "the list of cures" across both engines, and a build-time rule can mark
27
+ * one cure `preferred` exactly like an edit-time rule can. It was `readonly string[]`; that spelling is
28
+ * deleted and does not compile. NEVER hand-number the cures inside `aiMessage` — the framework
29
+ * (`formatFixOptions`) owns the "Fix Option N:" numbering and the "(preferred)" tag.
21
30
  *
22
31
  * Constructor is positional to match this package's other data classes (`Violation`, `ResolvedConfig`)
23
32
  * and the project's classes-over-interfaces convention. Common throws:
24
33
  * throw new RuleFailError('no-any-unknown', 'Avoid `any` here — use `unknown`.', 42, 'const x: any');
25
- * throw new RuleFailError('max-file-lines', 'File exceeds the limit.', undefined, undefined, ['Split it up']);
34
+ * throw new RuleFailError('max-file-lines', 'File exceeds the limit.', undefined, undefined,
35
+ * [new Option('Split it into two modules', true), new Option('Move the helpers to a sibling file')]);
26
36
  */
27
37
  class RuleFailError extends Error {
28
38
  cause;
@@ -31,8 +41,8 @@ class RuleFailError extends Error {
31
41
  humanMessage;
32
42
  line;
33
43
  snippet;
34
- fixHints;
35
- constructor(ruleName, aiMessage, line, snippet, fixHints = [], humanMessage, cause) {
44
+ fixOptions;
45
+ constructor(ruleName, aiMessage, line, snippet, fixOptions = [], humanMessage, cause) {
36
46
  super(aiMessage);
37
47
  this.name = 'RuleFailError';
38
48
  this.ruleName = ruleName;
@@ -40,9 +50,32 @@ class RuleFailError extends Error {
40
50
  this.humanMessage = humanMessage ?? aiMessage;
41
51
  this.line = line;
42
52
  this.snippet = snippet;
43
- this.fixHints = fixHints;
53
+ this.fixOptions = fixOptions;
44
54
  this.cause = cause;
45
55
  }
46
56
  }
47
57
  exports.RuleFailError = RuleFailError;
58
+ /**
59
+ * The AI-audience rendering of a thrown `RuleFailError`: its `aiMessage` plus its cures, numbered and
60
+ * tagged by the framework. Used by the top-level handlers in `ai-hook-rules`.
61
+ *
62
+ * WHY it exists: every handler used to print `aiMessage`/`humanMessage` alone, so a `RuleFailError`
63
+ * that escaped a per-rule catch reached the AI or the CI console with its `fixOptions` SILENTLY
64
+ * DROPPED — the rule had said how to fix the problem and the renderer threw that away. One renderer per
65
+ * audience means a cure cannot go missing depending on which catch caught the throw.
66
+ */
67
+ // webpieces-disable no-function-outside-class -- string formatter, sibling of formatFixOptions
68
+ function renderRuleFailForAi(error) {
69
+ return joinCures(error.aiMessage, error.fixOptions);
70
+ }
71
+ /** The developer/CI rendering: `humanMessage` (which defaults to `aiMessage`) plus the same cures. */
72
+ // webpieces-disable no-function-outside-class -- string formatter, sibling of formatFixOptions
73
+ function renderRuleFailForHuman(error) {
74
+ return joinCures(error.humanMessage, error.fixOptions);
75
+ }
76
+ // webpieces-disable no-function-outside-class -- private helper of the two renderers above
77
+ function joinCures(message, fixOptions) {
78
+ const rendered = (0, fix_option_1.formatFixOptions)(fixOptions);
79
+ return rendered.length === 0 ? message : `${message}\n${rendered.join('\n')}`;
80
+ }
48
81
  //# sourceMappingURL=rule-fail-error.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rule-fail-error.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/rule-fail-error.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAa,aAAc,SAAQ,KAAK;IAC3B,KAAK,CAAS;IACd,QAAQ,CAAS;IACjB,SAAS,CAAS;IAClB,YAAY,CAAS;IACrB,IAAI,CAAqB;IACzB,OAAO,CAAqB;IAC5B,QAAQ,CAAoB;IAErC,YACI,QAAgB,EAChB,SAAiB,EACjB,IAAa,EACb,OAAgB,EAChB,WAA8B,EAAE,EAChC,YAAqB,EACrB,KAAa;QAEb,KAAK,CAAC,SAAS,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,SAAS,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;CACJ;AA5BD,sCA4BC","sourcesContent":["/**\n * Thrown by ANY rule — in `ai-hook-rules` (edit-time) OR `code-rules` (build/CI-time) — to report a\n * failure from anywhere in its logic. Each engine wraps every rule in a per-rule try/catch, so a\n * thrown `RuleFailError` becomes one visible failure entry and the loop keeps going to the next rule;\n * a plain `Error` (a real bug) is caught the same way and surfaced too — one rule can never abort the\n * others.\n *\n * It is a STANDALONE `Error` — deliberately NOT an `InformAiError`. `InformAiError` is an AI-only\n * concept (it informs Claude Code); `code-rules` has no notion of \"AI\", so a shared rule-failure type\n * must not depend on it. Rules report failures with `RuleFailError`; `InformAiError` stays for\n * config/stdin/plumbing errors and the AI-facing guards path.\n *\n * Two audiences, one throw:\n * - `aiMessage` — what the AI sees in the ai-hook path (also `Error.message`).\n * - `humanMessage` — what a developer/CI sees in the code-rules console (defaults to `aiMessage`).\n *\n * `line`/`snippet`/`fixHints` are optional context the ai-hook engine folds into its `Violation`.\n *\n * Constructor is positional to match this package's other data classes (`Violation`, `ResolvedConfig`)\n * and the project's classes-over-interfaces convention. Common throws:\n * throw new RuleFailError('no-any-unknown', 'Avoid `any` here — use `unknown`.', 42, 'const x: any');\n * throw new RuleFailError('max-file-lines', 'File exceeds the limit.', undefined, undefined, ['Split it up']);\n */\nexport class RuleFailError extends Error {\n override cause?: Error;\n readonly ruleName: string;\n readonly aiMessage: string;\n readonly humanMessage: string;\n readonly line: number | undefined;\n readonly snippet: string | undefined;\n readonly fixHints: readonly string[];\n\n constructor(\n ruleName: string,\n aiMessage: string,\n line?: number,\n snippet?: string,\n fixHints: readonly string[] = [],\n humanMessage?: string,\n cause?: Error,\n ) {\n super(aiMessage);\n this.name = 'RuleFailError';\n this.ruleName = ruleName;\n this.aiMessage = aiMessage;\n this.humanMessage = humanMessage ?? aiMessage;\n this.line = line;\n this.snippet = snippet;\n this.fixHints = fixHints;\n this.cause = cause;\n }\n}\n"]}
1
+ {"version":3,"file":"rule-fail-error.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/rule-fail-error.ts"],"names":[],"mappings":";;;AAwEA,kDAEC;AAID,wDAEC;AAhFD,6CAAwD;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAa,aAAc,SAAQ,KAAK;IAC3B,KAAK,CAAS;IACd,QAAQ,CAAS;IACjB,SAAS,CAAS;IAClB,YAAY,CAAS;IACrB,IAAI,CAAqB;IACzB,OAAO,CAAqB;IAC5B,UAAU,CAAoB;IAEvC,YACI,QAAgB,EAChB,SAAiB,EACjB,IAAa,EACb,OAAgB,EAChB,aAAgC,EAAE,EAClC,YAAqB,EACrB,KAAa;QAEb,KAAK,CAAC,SAAS,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,SAAS,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;CACJ;AA5BD,sCA4BC;AAED;;;;;;;;GAQG;AACH,+FAA+F;AAC/F,SAAgB,mBAAmB,CAAC,KAAoB;IACpD,OAAO,SAAS,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;AACxD,CAAC;AAED,sGAAsG;AACtG,+FAA+F;AAC/F,SAAgB,sBAAsB,CAAC,KAAoB;IACvD,OAAO,SAAS,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;AAC3D,CAAC;AAED,2FAA2F;AAC3F,SAAS,SAAS,CAAC,OAAe,EAAE,UAA6B;IAC7D,MAAM,QAAQ,GAAG,IAAA,6BAAgB,EAAC,UAAU,CAAC,CAAC;IAC9C,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAClF,CAAC","sourcesContent":["import { Option, formatFixOptions } from './fix-option';\n\n/**\n * Thrown by ANY rule — in `ai-hook-rules` (edit-time) OR `code-rules` (build/CI-time) — to report a\n * failure from anywhere in its logic. Each engine wraps every rule in a per-rule try/catch, so a\n * thrown `RuleFailError` becomes one visible failure entry and the loop keeps going to the next rule;\n * a plain `Error` (a real bug) is caught the same way and surfaced too — one rule can never abort the\n * others.\n *\n * It is a STANDALONE `Error` — deliberately NOT an `InformAiError`. `InformAiError` is an AI-only\n * concept (it informs Claude Code); `code-rules` has no notion of \"AI\", so a shared rule-failure type\n * must not depend on it. Rules report failures with `RuleFailError`; `InformAiError` stays for\n * config/stdin/plumbing errors and the AI-facing guards path.\n *\n * Two audiences, one throw:\n * - `aiMessage` — what the AI sees in the ai-hook path (also `Error.message`).\n * - `humanMessage` — what a developer/CI sees in the code-rules console (defaults to `aiMessage`).\n *\n * `line`/`snippet`/`fixOptions` are optional context the ai-hook engine folds into its `Violation`.\n *\n * `fixOptions` is `readonly Option[]` — the SAME `Option` that `FixHint.fixOptions` carries, so there is\n * exactly ONE representation of \"the list of cures\" across both engines, and a build-time rule can mark\n * one cure `preferred` exactly like an edit-time rule can. It was `readonly string[]`; that spelling is\n * deleted and does not compile. NEVER hand-number the cures inside `aiMessage` — the framework\n * (`formatFixOptions`) owns the \"Fix Option N:\" numbering and the \"(preferred)\" tag.\n *\n * Constructor is positional to match this package's other data classes (`Violation`, `ResolvedConfig`)\n * and the project's classes-over-interfaces convention. Common throws:\n * throw new RuleFailError('no-any-unknown', 'Avoid `any` here — use `unknown`.', 42, 'const x: any');\n * throw new RuleFailError('max-file-lines', 'File exceeds the limit.', undefined, undefined,\n * [new Option('Split it into two modules', true), new Option('Move the helpers to a sibling file')]);\n */\nexport class RuleFailError extends Error {\n override cause?: Error;\n readonly ruleName: string;\n readonly aiMessage: string;\n readonly humanMessage: string;\n readonly line: number | undefined;\n readonly snippet: string | undefined;\n readonly fixOptions: readonly Option[];\n\n constructor(\n ruleName: string,\n aiMessage: string,\n line?: number,\n snippet?: string,\n fixOptions: readonly Option[] = [],\n humanMessage?: string,\n cause?: Error,\n ) {\n super(aiMessage);\n this.name = 'RuleFailError';\n this.ruleName = ruleName;\n this.aiMessage = aiMessage;\n this.humanMessage = humanMessage ?? aiMessage;\n this.line = line;\n this.snippet = snippet;\n this.fixOptions = fixOptions;\n this.cause = cause;\n }\n}\n\n/**\n * The AI-audience rendering of a thrown `RuleFailError`: its `aiMessage` plus its cures, numbered and\n * tagged by the framework. Used by the top-level handlers in `ai-hook-rules`.\n *\n * WHY it exists: every handler used to print `aiMessage`/`humanMessage` alone, so a `RuleFailError`\n * that escaped a per-rule catch reached the AI or the CI console with its `fixOptions` SILENTLY\n * DROPPED — the rule had said how to fix the problem and the renderer threw that away. One renderer per\n * audience means a cure cannot go missing depending on which catch caught the throw.\n */\n// webpieces-disable no-function-outside-class -- string formatter, sibling of formatFixOptions\nexport function renderRuleFailForAi(error: RuleFailError): string {\n return joinCures(error.aiMessage, error.fixOptions);\n}\n\n/** The developer/CI rendering: `humanMessage` (which defaults to `aiMessage`) plus the same cures. */\n// webpieces-disable no-function-outside-class -- string formatter, sibling of formatFixOptions\nexport function renderRuleFailForHuman(error: RuleFailError): string {\n return joinCures(error.humanMessage, error.fixOptions);\n}\n\n// webpieces-disable no-function-outside-class -- private helper of the two renderers above\nfunction joinCures(message: string, fixOptions: readonly Option[]): string {\n const rendered = formatFixOptions(fixOptions);\n return rendered.length === 0 ? message : `${message}\\n${rendered.join('\\n')}`;\n}\n"]}
package/src/skip-rule.js CHANGED
@@ -8,6 +8,7 @@ const child_process_1 = require("child_process");
8
8
  const fs = tslib_1.__importStar(require("fs"));
9
9
  const inform_ai_error_1 = require("./inform-ai-error");
10
10
  const rule_fail_error_1 = require("./rule-fail-error");
11
+ const fix_option_1 = require("./fix-option");
11
12
  const to_error_1 = require("./to-error");
12
13
  // Universal "should this rule be skipped right now?" logic, shared by code-rules,
13
14
  // ai-hook-rules and the Nx executors so every rule honors the same two escape
@@ -136,19 +137,18 @@ function readHeadRepoFullName(branchName) {
136
137
  const error = (0, to_error_1.toError)(err);
137
138
  throw new rule_fail_error_1.RuleFailError('turnOffRuleWhileOnBranch', `turnOffRuleWhileOnBranch: "${branchName}" is configured and this is a pull_request run, so the ` +
138
139
  `head repository must be checked before the hatch may fire — but the runner's event file ` +
139
- `${eventPath} could not be read: ${error.message}`, undefined, undefined, ['Use turnOffRuleUntilEpoch instead — it is TIME based and needs no event file.',
140
- 'Or clear turnOffRuleWhileOnBranch (set it to null) so no trust check is needed at all.'], undefined, error);
140
+ `${eventPath} could not be read: ${error.message}`, undefined, undefined, [new fix_option_1.Option('Use turnOffRuleUntilEpoch instead — it is TIME based and needs no event file.', true),
141
+ new fix_option_1.Option('Or clear turnOffRuleWhileOnBranch (set it to null) so no trust check is needed at all.')], undefined, error);
141
142
  }
142
143
  }
143
144
  /**
144
145
  * The fork refusal, as a `RuleFailError`.
145
146
  *
146
- * The cures are `fixHints` — a LIST — because the framework owns how they are labelled and numbered
147
- * (`rule-reporter.ts` prefixes each with "Fix: "; the hook runner folds them into its Violation). A
148
- * hand-numbered "WORKAROUNDS: 1. … 2. …" string literal, which is what this used to be, is exactly the
149
- * shape `FixHint`/`Option` exist to prevent. `FixHint` itself lives in `ai-hook-rules`, which
150
- * `rules-config` sits BELOW and cannot import, so `RuleFailError.fixHints` is the structured list
151
- * available at this layer.
147
+ * The cures are `fixOptions` — a LIST of `Option` — because the framework owns how they are labelled
148
+ * and numbered (`formatFixOptions` renders "Fix Option N:" and the "(preferred)" tag for BOTH engines).
149
+ * A hand-numbered "WORKAROUNDS: 1. … 2. …" string literal, which is what this used to be, is exactly
150
+ * the shape `Option` exists to prevent. `Option` lives HERE in `rules-config`, so the same class serves
151
+ * this build-time throw and `FixHint` in `ai-hook-rules` one cure shape, one definition.
152
152
  *
153
153
  * `ruleName` is the HATCH, not the rule being evaluated: `shouldSkipRule` is handed only the two hatch
154
154
  * values and does not know whose rule it is deciding for — and the thing that failed genuinely is the
@@ -161,11 +161,11 @@ function forkRefusal(branchName, what) {
161
161
  `is committed), so honoring the hatch would let anyone turn this rule off on their own PR just ` +
162
162
  `by naming their branch after it. The rule is NOT skipped, and this fails loudly rather than ` +
163
163
  `quietly enforcing a rule the config says is off.`, undefined, undefined, [
164
- 'If the rule must be off for outside contributions too, use turnOffRuleUntilEpoch — it is TIME ' +
164
+ new fix_option_1.Option('If the rule must be off for outside contributions too, use turnOffRuleUntilEpoch — it is TIME ' +
165
165
  'based, so it cannot be self-granted by naming a branch. Keep the date short: it is repo-wide ' +
166
- 'while it lasts, so it also shelters unrelated work landing in the same window.',
167
- 'Otherwise clear turnOffRuleWhileOnBranch (set it to null) and fix the findings on the ' +
168
- 'contributed branch like any other.',
166
+ 'while it lasts, so it also shelters unrelated work landing in the same window.', true),
167
+ new fix_option_1.Option('Otherwise clear turnOffRuleWhileOnBranch (set it to null) and fix the findings on the ' +
168
+ 'contributed branch like any other.'),
169
169
  ]);
170
170
  }
171
171
  function shouldSkipRule(epoch,
@@ -1 +1 @@
1
- {"version":3,"file":"skip-rule.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/skip-rule.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync } from 'child_process';\nimport * as fs from 'fs';\n\nimport { InformAiError } from './inform-ai-error';\nimport { RuleFailError } from './rule-fail-error';\nimport { toError } from './to-error';\n\n// Universal \"should this rule be skipped right now?\" logic, shared by code-rules,\n// ai-hook-rules and the Nx executors so every rule honors the same two escape\n// hatches: turnOffRuleWhileOnBranch (skip while on a named branch) and\n// turnOffRuleUntilEpoch (skip until an epoch passes).\n\n/**\n * The skip decision. A CLASS, not an interface (CLAUDE.md rule 1), because it carries a THIRD fact\n * beyond yes/no that a caller has to be able to read rather than read about in a log line.\n *\n * `hatchNotApplied` is that fact: a branch hatch WAS configured, and it could NOT apply — today only\n * because HEAD is detached (a tag checkout, a `git bisect` step, a CI checkout of a merge ref). The rule\n * is ENFORCED in that case, so there is nothing to report unless the rule then FAILS; when it does, its\n * own RuleFailError is where this belongs, as context on why the hatch the config shows did not save it.\n *\n * It is deliberately NOT printed here. Everything in this framework throws to ONE place that renders per\n * audience; a console write from a library function cannot be caught, re-rendered or asserted on.\n */\nexport class SkipRuleResult {\n skip: boolean;\n /** Why the rule IS being skipped. '' whenever `skip` is false. */\n reason: string;\n /** Why a CONFIGURED branch hatch did not apply, or '' when there is nothing to say. */\n hatchNotApplied: string;\n\n constructor(skip: boolean, reason: string = '', hatchNotApplied: string = '') {\n this.skip = skip;\n this.reason = reason;\n this.hatchNotApplied = hatchNotApplied;\n }\n}\n\n// The actual checked-out branch. The grab bag of ambient env vars (BRANCH_NAME, GIT_BRANCH,\n// CI_COMMIT_BRANCH, …) was intentionally REMOVED and must stay removed: a stray GIT_BRANCH=main\n// locally made this return \"main\" on a feature branch, which (a) mislabeled the main-sync cache and\n// (b) silently disabled merged-PR detection (detectMergedPr skips \"main\").\n//\n// The two vars below are NOT that. They are consulted BEFORE git because git cannot answer at all in\n// the case they cover — a `pull_request` checkout leaves HEAD detached on refs/pull/<N>/merge, where\n// `git rev-parse --abbrev-ref HEAD` returns the literal string \"HEAD\" and no branch hatch can match.\n// Neither can go stale the way GIT_BRANCH did:\n// GITHUB_HEAD_REF — set by the GitHub runner ONLY on pull_request/pull_request_target, and it IS\n// the source branch name. Absent on push, so the fallthrough stays safe. (Not\n// GITHUB_REF_NAME: on pull_request that is \"<N>/merge\", not a branch.)\n// WEBPIECES_BRANCH — one documented opt-in override for CI systems not special-cased here\n// (GitLab, CircleCI, Buildkite). Nobody sets it by accident.\n//\n// This getter answers \"what branch am I on?\" and NOTHING about whether that answer may be TRUSTED to\n// unlock an escape hatch. That second question is asked by shouldSkipRule alone (see\n// assertBranchIsTrustworthy) because this getter has callers — the main-sync cache label, merged-PR\n// detection, code-rules' re-export of it — for which a fork's own branch name is a perfectly good\n// answer, and making the getter itself throw would redden all of them.\nexport function getCurrentBranch(): string {\n const prBranch = process.env['GITHUB_HEAD_REF'];\n if (prBranch) return prBranch;\n\n const override = process.env['WEBPIECES_BRANCH'];\n if (override) return override;\n\n // webpieces-disable no-unmanaged-exceptions -- rethrow as InformAiError so global catch surfaces readable message to AI\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- rethrow as InformAiError so global catch surfaces readable message to AI\n try {\n return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(`Failed to determine current git branch: ${error.message}`, { cause: error });\n }\n}\n\n// The slice of the GitHub `pull_request` event payload that says WHO OWNS the head branch. Only the\n// one field below is read; everything else in that file is ignored.\ninterface RawPullRequestEvent {\n pull_request?: {\n head?: {\n repo?: {\n full_name?: string;\n };\n };\n };\n}\n\n/**\n * Refuse the branch hatch on a pull request whose head branch this repo does not own.\n *\n * The hole it closes: hatch names live in `webpieces.config.json`, which is COMMITTED and public. On a\n * `pull_request` from a FORK the runner sets GITHUB_HEAD_REF to the FORK AUTHOR's branch name, so an\n * outside contributor who names their branch after one of your hatches silently disables that rule on\n * their PR — the one place you least want a rule off.\n *\n * It is answered with no network and no token, from `$GITHUB_EVENT_PATH` — a JSON file the runner writes\n * before the job starts:\n * - `pull_request_target` runs with the BASE repo's secrets against contributor-authored code, so it is\n * untrusted unconditionally; there is nothing to compare.\n * - `pull_request` is trusted only when the head repo's `full_name` EQUALS `GITHUB_REPOSITORY`.\n *\n * \"Cannot tell\" counts as untrusted — a `pull_request` run with no readable event file cannot make the\n * comparison, and a hatch that cannot be proven to be yours must not fire.\n *\n * This is the ONE hard failure left in this module, and it is not the \"no branch here\" case (see\n * shouldSkipRule, which enforces quietly when HEAD is detached). It is a hatch name that DOES resolve but\n * is attacker-chosen — a security property, not a checkout that happens not to be editing.\n *\n * Called ONLY from inside `if (branchName)`. With turnOffRuleWhileOnBranch null — the overwhelmingly\n * common value — nothing here runs and no fork PR is affected in any way.\n */\n// webpieces-disable no-function-outside-class -- module-scope helper of the module-scope shouldSkipRule it serves; this whole module is functional by design (imported as free functions by code-rules, ai-hook-rules and the nx executors)\nfunction assertBranchIsTrustworthy(branchName: string): void {\n const eventName = process.env['GITHUB_EVENT_NAME'];\n if (eventName !== 'pull_request' && eventName !== 'pull_request_target') return;\n if (eventName === 'pull_request_target') throw forkRefusal(branchName, 'pull_request_target run');\n\n const headRepo = readHeadRepoFullName(branchName);\n const thisRepo = process.env['GITHUB_REPOSITORY'] ?? '';\n if (headRepo !== null && thisRepo !== '' && headRepo === thisRepo) return;\n throw forkRefusal(branchName, headRepo === null\n ? 'pull_request run with no readable $GITHUB_EVENT_PATH, so the head branch cannot be proven to belong to this repo'\n : `pull_request run whose head branch lives in \"${headRepo}\", not in \"${thisRepo}\"`);\n}\n\n/**\n * The head repo's `owner/name` from the runner's event file, or null when there is no such file.\n *\n * A file that exists but cannot be parsed is a different thing from one that is absent, and it throws:\n * it means the runner wrote something this code does not understand, and silently downgrading that to\n * \"untrusted\" would hide a real incompatibility behind a message about forks.\n */\n// webpieces-disable no-function-outside-class -- module-scope helper, see assertBranchIsTrustworthy\nfunction readHeadRepoFullName(branchName: string): string | null {\n const eventPath = process.env['GITHUB_EVENT_PATH'];\n if (!eventPath || !fs.existsSync(eventPath)) return null;\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: a raw SyntaxError from the runner's event file would say nothing about hatches; this names the hatch, the file and the rule that stayed ON\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- see above\n try {\n const parsed = JSON.parse(fs.readFileSync(eventPath, 'utf8')) as RawPullRequestEvent;\n return parsed.pull_request?.head?.repo?.full_name ?? null;\n } catch (err: unknown) {\n const error = toError(err);\n throw new RuleFailError(\n 'turnOffRuleWhileOnBranch',\n `turnOffRuleWhileOnBranch: \"${branchName}\" is configured and this is a pull_request run, so the ` +\n `head repository must be checked before the hatch may fire — but the runner's event file ` +\n `${eventPath} could not be read: ${error.message}`,\n undefined,\n undefined,\n ['Use turnOffRuleUntilEpoch instead — it is TIME based and needs no event file.',\n 'Or clear turnOffRuleWhileOnBranch (set it to null) so no trust check is needed at all.'],\n undefined,\n error);\n }\n}\n\n/**\n * The fork refusal, as a `RuleFailError`.\n *\n * The cures are `fixHints` — a LIST — because the framework owns how they are labelled and numbered\n * (`rule-reporter.ts` prefixes each with \"Fix: \"; the hook runner folds them into its Violation). A\n * hand-numbered \"WORKAROUNDS: 1. … 2. …\" string literal, which is what this used to be, is exactly the\n * shape `FixHint`/`Option` exist to prevent. `FixHint` itself lives in `ai-hook-rules`, which\n * `rules-config` sits BELOW and cannot import, so `RuleFailError.fixHints` is the structured list\n * available at this layer.\n *\n * `ruleName` is the HATCH, not the rule being evaluated: `shouldSkipRule` is handed only the two hatch\n * values and does not know whose rule it is deciding for — and the thing that failed genuinely is the\n * hatch, which cannot be honored here.\n */\n// webpieces-disable no-function-outside-class -- module-scope helper, see assertBranchIsTrustworthy\nfunction forkRefusal(branchName: string, what: string): RuleFailError {\n return new RuleFailError(\n 'turnOffRuleWhileOnBranch',\n `turnOffRuleWhileOnBranch: \"${branchName}\" is configured, but this is a ${what}. The branch name ` +\n `there is chosen by the PULL REQUEST AUTHOR, and hatch names are public (webpieces.config.json ` +\n `is committed), so honoring the hatch would let anyone turn this rule off on their own PR just ` +\n `by naming their branch after it. The rule is NOT skipped, and this fails loudly rather than ` +\n `quietly enforcing a rule the config says is off.`,\n undefined,\n undefined,\n [\n 'If the rule must be off for outside contributions too, use turnOffRuleUntilEpoch — it is TIME ' +\n 'based, so it cannot be self-granted by naming a branch. Keep the date short: it is repo-wide ' +\n 'while it lasts, so it also shelters unrelated work landing in the same window.',\n 'Otherwise clear turnOffRuleWhileOnBranch (set it to null) and fix the findings on the ' +\n 'contributed branch like any other.',\n ],\n );\n}\n\nexport function shouldSkipRule(\n epoch: number | undefined,\n // The branch hatch is an EXACT branch name — compared with `===`, never a glob, regex or prefix.\n // That is deliberate and is not to be \"improved\": the hatch turns a rule OFF, and a pattern lets one\n // config line switch rules off on branches nobody enumerated when it was written. If two branches\n // need the same rule off, that is two branches renamed to one hatch name, not one wildcard.\n //\n // null (the \"no branch / always on\" value of turnOffRuleWhileOnBranch) is treated exactly like\n // undefined — no branch scoping. Only a non-empty branch name activates the branch hatch.\n branchName: string | undefined | null\n): SkipRuleResult {\n if (branchName) {\n // The fork gate fires ONLY inside `if (branchName)`. With turnOffRuleWhileOnBranch=null — the\n // overwhelmingly common value — nothing below runs, so an outside contribution to a repo that\n // configured no hatch is an ordinary run.\n //\n // A DETACHED HEAD is NOT an error here. The branch hatch exists to relax a rule while you EDIT on\n // a branch; a tag checkout or a `git bisect` step is not editing (you cannot commit to a tag, and\n // to edit you branch off it first). So when no branch can be resolved the hatch simply does not\n // apply and THE RULE IS ENFORCED — whoever hits a violation then gets that rule's own message and\n // cure, which is the useful output. WHY the hatch did not fire rides back on the result\n // (SkipRuleResult.hatchNotApplied) rather than being printed, so a caller that does fail can fold\n // it into its own error instead of a library writing to a console nobody can catch.\n assertBranchIsTrustworthy(branchName);\n const current = getCurrentBranch();\n if (current === 'HEAD' || current === '') {\n return new SkipRuleResult(false, '',\n `turnOffRuleWhileOnBranch: \"${branchName}\" did not apply — HEAD is detached, so there is no ` +\n `branch to match (a tag checkout, a git bisect step, or a CI checkout of a merge ref).`);\n }\n if (current === branchName) {\n return new SkipRuleResult(true, `on branch \"${branchName}\"`);\n }\n }\n if (epoch !== undefined) {\n const nowSeconds = Date.now() / 1000;\n if (nowSeconds < epoch) {\n const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];\n return new SkipRuleResult(true, `turnOffRuleUntilEpoch active, expires: ${expiresDate}`);\n }\n }\n return new SkipRuleResult(false);\n}\n"]}
1
+ {"version":3,"file":"skip-rule.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/skip-rule.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync } from 'child_process';\nimport * as fs from 'fs';\n\nimport { InformAiError } from './inform-ai-error';\nimport { RuleFailError } from './rule-fail-error';\nimport { Option } from './fix-option';\nimport { toError } from './to-error';\n\n// Universal \"should this rule be skipped right now?\" logic, shared by code-rules,\n// ai-hook-rules and the Nx executors so every rule honors the same two escape\n// hatches: turnOffRuleWhileOnBranch (skip while on a named branch) and\n// turnOffRuleUntilEpoch (skip until an epoch passes).\n\n/**\n * The skip decision. A CLASS, not an interface (CLAUDE.md rule 1), because it carries a THIRD fact\n * beyond yes/no that a caller has to be able to read rather than read about in a log line.\n *\n * `hatchNotApplied` is that fact: a branch hatch WAS configured, and it could NOT apply — today only\n * because HEAD is detached (a tag checkout, a `git bisect` step, a CI checkout of a merge ref). The rule\n * is ENFORCED in that case, so there is nothing to report unless the rule then FAILS; when it does, its\n * own RuleFailError is where this belongs, as context on why the hatch the config shows did not save it.\n *\n * It is deliberately NOT printed here. Everything in this framework throws to ONE place that renders per\n * audience; a console write from a library function cannot be caught, re-rendered or asserted on.\n */\nexport class SkipRuleResult {\n skip: boolean;\n /** Why the rule IS being skipped. '' whenever `skip` is false. */\n reason: string;\n /** Why a CONFIGURED branch hatch did not apply, or '' when there is nothing to say. */\n hatchNotApplied: string;\n\n constructor(skip: boolean, reason: string = '', hatchNotApplied: string = '') {\n this.skip = skip;\n this.reason = reason;\n this.hatchNotApplied = hatchNotApplied;\n }\n}\n\n// The actual checked-out branch. The grab bag of ambient env vars (BRANCH_NAME, GIT_BRANCH,\n// CI_COMMIT_BRANCH, …) was intentionally REMOVED and must stay removed: a stray GIT_BRANCH=main\n// locally made this return \"main\" on a feature branch, which (a) mislabeled the main-sync cache and\n// (b) silently disabled merged-PR detection (detectMergedPr skips \"main\").\n//\n// The two vars below are NOT that. They are consulted BEFORE git because git cannot answer at all in\n// the case they cover — a `pull_request` checkout leaves HEAD detached on refs/pull/<N>/merge, where\n// `git rev-parse --abbrev-ref HEAD` returns the literal string \"HEAD\" and no branch hatch can match.\n// Neither can go stale the way GIT_BRANCH did:\n// GITHUB_HEAD_REF — set by the GitHub runner ONLY on pull_request/pull_request_target, and it IS\n// the source branch name. Absent on push, so the fallthrough stays safe. (Not\n// GITHUB_REF_NAME: on pull_request that is \"<N>/merge\", not a branch.)\n// WEBPIECES_BRANCH — one documented opt-in override for CI systems not special-cased here\n// (GitLab, CircleCI, Buildkite). Nobody sets it by accident.\n//\n// This getter answers \"what branch am I on?\" and NOTHING about whether that answer may be TRUSTED to\n// unlock an escape hatch. That second question is asked by shouldSkipRule alone (see\n// assertBranchIsTrustworthy) because this getter has callers — the main-sync cache label, merged-PR\n// detection, code-rules' re-export of it — for which a fork's own branch name is a perfectly good\n// answer, and making the getter itself throw would redden all of them.\nexport function getCurrentBranch(): string {\n const prBranch = process.env['GITHUB_HEAD_REF'];\n if (prBranch) return prBranch;\n\n const override = process.env['WEBPIECES_BRANCH'];\n if (override) return override;\n\n // webpieces-disable no-unmanaged-exceptions -- rethrow as InformAiError so global catch surfaces readable message to AI\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- rethrow as InformAiError so global catch surfaces readable message to AI\n try {\n return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(`Failed to determine current git branch: ${error.message}`, { cause: error });\n }\n}\n\n// The slice of the GitHub `pull_request` event payload that says WHO OWNS the head branch. Only the\n// one field below is read; everything else in that file is ignored.\ninterface RawPullRequestEvent {\n pull_request?: {\n head?: {\n repo?: {\n full_name?: string;\n };\n };\n };\n}\n\n/**\n * Refuse the branch hatch on a pull request whose head branch this repo does not own.\n *\n * The hole it closes: hatch names live in `webpieces.config.json`, which is COMMITTED and public. On a\n * `pull_request` from a FORK the runner sets GITHUB_HEAD_REF to the FORK AUTHOR's branch name, so an\n * outside contributor who names their branch after one of your hatches silently disables that rule on\n * their PR — the one place you least want a rule off.\n *\n * It is answered with no network and no token, from `$GITHUB_EVENT_PATH` — a JSON file the runner writes\n * before the job starts:\n * - `pull_request_target` runs with the BASE repo's secrets against contributor-authored code, so it is\n * untrusted unconditionally; there is nothing to compare.\n * - `pull_request` is trusted only when the head repo's `full_name` EQUALS `GITHUB_REPOSITORY`.\n *\n * \"Cannot tell\" counts as untrusted — a `pull_request` run with no readable event file cannot make the\n * comparison, and a hatch that cannot be proven to be yours must not fire.\n *\n * This is the ONE hard failure left in this module, and it is not the \"no branch here\" case (see\n * shouldSkipRule, which enforces quietly when HEAD is detached). It is a hatch name that DOES resolve but\n * is attacker-chosen — a security property, not a checkout that happens not to be editing.\n *\n * Called ONLY from inside `if (branchName)`. With turnOffRuleWhileOnBranch null — the overwhelmingly\n * common value — nothing here runs and no fork PR is affected in any way.\n */\n// webpieces-disable no-function-outside-class -- module-scope helper of the module-scope shouldSkipRule it serves; this whole module is functional by design (imported as free functions by code-rules, ai-hook-rules and the nx executors)\nfunction assertBranchIsTrustworthy(branchName: string): void {\n const eventName = process.env['GITHUB_EVENT_NAME'];\n if (eventName !== 'pull_request' && eventName !== 'pull_request_target') return;\n if (eventName === 'pull_request_target') throw forkRefusal(branchName, 'pull_request_target run');\n\n const headRepo = readHeadRepoFullName(branchName);\n const thisRepo = process.env['GITHUB_REPOSITORY'] ?? '';\n if (headRepo !== null && thisRepo !== '' && headRepo === thisRepo) return;\n throw forkRefusal(branchName, headRepo === null\n ? 'pull_request run with no readable $GITHUB_EVENT_PATH, so the head branch cannot be proven to belong to this repo'\n : `pull_request run whose head branch lives in \"${headRepo}\", not in \"${thisRepo}\"`);\n}\n\n/**\n * The head repo's `owner/name` from the runner's event file, or null when there is no such file.\n *\n * A file that exists but cannot be parsed is a different thing from one that is absent, and it throws:\n * it means the runner wrote something this code does not understand, and silently downgrading that to\n * \"untrusted\" would hide a real incompatibility behind a message about forks.\n */\n// webpieces-disable no-function-outside-class -- module-scope helper, see assertBranchIsTrustworthy\nfunction readHeadRepoFullName(branchName: string): string | null {\n const eventPath = process.env['GITHUB_EVENT_PATH'];\n if (!eventPath || !fs.existsSync(eventPath)) return null;\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: a raw SyntaxError from the runner's event file would say nothing about hatches; this names the hatch, the file and the rule that stayed ON\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- see above\n try {\n const parsed = JSON.parse(fs.readFileSync(eventPath, 'utf8')) as RawPullRequestEvent;\n return parsed.pull_request?.head?.repo?.full_name ?? null;\n } catch (err: unknown) {\n const error = toError(err);\n throw new RuleFailError(\n 'turnOffRuleWhileOnBranch',\n `turnOffRuleWhileOnBranch: \"${branchName}\" is configured and this is a pull_request run, so the ` +\n `head repository must be checked before the hatch may fire — but the runner's event file ` +\n `${eventPath} could not be read: ${error.message}`,\n undefined,\n undefined,\n [new Option('Use turnOffRuleUntilEpoch instead — it is TIME based and needs no event file.', true),\n new Option('Or clear turnOffRuleWhileOnBranch (set it to null) so no trust check is needed at all.')],\n undefined,\n error);\n }\n}\n\n/**\n * The fork refusal, as a `RuleFailError`.\n *\n * The cures are `fixOptions` — a LIST of `Option` — because the framework owns how they are labelled\n * and numbered (`formatFixOptions` renders \"Fix Option N:\" and the \"(preferred)\" tag for BOTH engines).\n * A hand-numbered \"WORKAROUNDS: 1. … 2. …\" string literal, which is what this used to be, is exactly\n * the shape `Option` exists to prevent. `Option` lives HERE in `rules-config`, so the same class serves\n * this build-time throw and `FixHint` in `ai-hook-rules` — one cure shape, one definition.\n *\n * `ruleName` is the HATCH, not the rule being evaluated: `shouldSkipRule` is handed only the two hatch\n * values and does not know whose rule it is deciding for — and the thing that failed genuinely is the\n * hatch, which cannot be honored here.\n */\n// webpieces-disable no-function-outside-class -- module-scope helper, see assertBranchIsTrustworthy\nfunction forkRefusal(branchName: string, what: string): RuleFailError {\n return new RuleFailError(\n 'turnOffRuleWhileOnBranch',\n `turnOffRuleWhileOnBranch: \"${branchName}\" is configured, but this is a ${what}. The branch name ` +\n `there is chosen by the PULL REQUEST AUTHOR, and hatch names are public (webpieces.config.json ` +\n `is committed), so honoring the hatch would let anyone turn this rule off on their own PR just ` +\n `by naming their branch after it. The rule is NOT skipped, and this fails loudly rather than ` +\n `quietly enforcing a rule the config says is off.`,\n undefined,\n undefined,\n [\n new Option(\n 'If the rule must be off for outside contributions too, use turnOffRuleUntilEpoch — it is TIME ' +\n 'based, so it cannot be self-granted by naming a branch. Keep the date short: it is repo-wide ' +\n 'while it lasts, so it also shelters unrelated work landing in the same window.',\n true,\n ),\n new Option(\n 'Otherwise clear turnOffRuleWhileOnBranch (set it to null) and fix the findings on the ' +\n 'contributed branch like any other.',\n ),\n ],\n );\n}\n\nexport function shouldSkipRule(\n epoch: number | undefined,\n // The branch hatch is an EXACT branch name — compared with `===`, never a glob, regex or prefix.\n // That is deliberate and is not to be \"improved\": the hatch turns a rule OFF, and a pattern lets one\n // config line switch rules off on branches nobody enumerated when it was written. If two branches\n // need the same rule off, that is two branches renamed to one hatch name, not one wildcard.\n //\n // null (the \"no branch / always on\" value of turnOffRuleWhileOnBranch) is treated exactly like\n // undefined — no branch scoping. Only a non-empty branch name activates the branch hatch.\n branchName: string | undefined | null\n): SkipRuleResult {\n if (branchName) {\n // The fork gate fires ONLY inside `if (branchName)`. With turnOffRuleWhileOnBranch=null — the\n // overwhelmingly common value — nothing below runs, so an outside contribution to a repo that\n // configured no hatch is an ordinary run.\n //\n // A DETACHED HEAD is NOT an error here. The branch hatch exists to relax a rule while you EDIT on\n // a branch; a tag checkout or a `git bisect` step is not editing (you cannot commit to a tag, and\n // to edit you branch off it first). So when no branch can be resolved the hatch simply does not\n // apply and THE RULE IS ENFORCED — whoever hits a violation then gets that rule's own message and\n // cure, which is the useful output. WHY the hatch did not fire rides back on the result\n // (SkipRuleResult.hatchNotApplied) rather than being printed, so a caller that does fail can fold\n // it into its own error instead of a library writing to a console nobody can catch.\n assertBranchIsTrustworthy(branchName);\n const current = getCurrentBranch();\n if (current === 'HEAD' || current === '') {\n return new SkipRuleResult(false, '',\n `turnOffRuleWhileOnBranch: \"${branchName}\" did not apply — HEAD is detached, so there is no ` +\n `branch to match (a tag checkout, a git bisect step, or a CI checkout of a merge ref).`);\n }\n if (current === branchName) {\n return new SkipRuleResult(true, `on branch \"${branchName}\"`);\n }\n }\n if (epoch !== undefined) {\n const nowSeconds = Date.now() / 1000;\n if (nowSeconds < epoch) {\n const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];\n return new SkipRuleResult(true, `turnOffRuleUntilEpoch active, expires: ${expiresDate}`);\n }\n }\n return new SkipRuleResult(false);\n}\n"]}