/** * Legacy RuleHost contract dependency scanner (2026-08-19). * * When a public RuleHost contract symbol is retired (e.g. * `RuleHostInput.session.recentThinking`, `workspace.planStatus`, * `workspace.hasPlanFile`, the `getPlanStatus()`/`hasPlanFile()` helpers), * source-level deletion is not enough: persisted, owner-approved RuleCode in * existing workspaces may still reference the symbol. Executing such a rule * against the new contract silently changes its semantics (`undefined` * instead of a value) — the most dangerous failure mode because nothing * throws and the owner-approved behavior drifts quietly. * * This scanner is the shared detection point for: * - runtime load backstops (plugin RuleHost + host-runtime gate) — a rule * with a retired-contract dependency is NOT executed; * - upgrade preflights (installer, console update) — refuse to replace the * runtime while an active rule depends on a removed contract. * * Matching examines executable source only. Comments and string literals are * masked before symbol matching so explanatory text cannot disable a host. * A true executable reference is still rejected because reading a retired * field would silently change owner-approved behavior. */ /** Retired public RuleHost contract symbols and how they appear in RuleCode. */ export type LegacyRuleContractSymbol = 'recentThinking' | 'planStatus' | 'hasPlanFile' | 'getPlanStatus' | 'hasPlanFileHelper'; /** A rule implementation to scan, with its lineage for owner-facing output. */ export interface LegacyRuleContractRuleSource { activationId?: string; artifactId: string; ruleId?: string; principleId?: string; /** Raw RuleCode source as persisted in the artifact. */ implementationCode: string; } /** One retired-symbol usage found in one active rule. */ export interface LegacyRuleContractFinding { activationId?: string; artifactId: string; ruleId?: string; principleId?: string; symbol: LegacyRuleContractSymbol; channel: 'code_tool_hook'; } /** * Mask comments and string-literal CONTENTS (preserving newlines; template * `${...}` interpolation stays executable) so downstream static symbol scans * only see executable source. * * Shared by the retired-contract scanner here and by `checkForbiddenPatterns` * (rule-code-validator, PRI-668): a string literal can only become * executable via eval/Function/bracket access — each of which carries its own * forbidden pattern — so masking literals creates no sandbox escape. */ export declare function maskNonExecutableText(source: string): string; /** * Scan persisted RuleCode sources for retired RuleHost contract symbols. * Pure function — no I/O; callers own loading the code from persistence. */ export declare function scanLegacyRuleContractDependencies(rules: readonly LegacyRuleContractRuleSource[]): LegacyRuleContractFinding[]; /** Human-readable remediation text shared by all consumers of the scanner. */ export declare function formatLegacyRuleContractRemediation(findings: readonly LegacyRuleContractFinding[]): string; //# sourceMappingURL=legacy-rule-contract-scanner.d.ts.map