UNPKG

fallow

Version:

Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution

1,221 lines (1,218 loc) 277 kB
/** * AUTOGENERATED FILE. DO NOT EDIT. * * Generated from `docs/output-schema.json` by * `editors/vscode/scripts/codegen-types.mjs`. The same file is written to * `editors/vscode/src/generated/output-contract.d.ts` (extension internal) and * `npm/fallow/types/output-contract.d.ts` (published as `fallow/types`). * * To change a shape: * 1. Edit the Rust struct in `crates/types/src/results.rs` (or the * duplicates crate at `crates/core/src/duplicates/types.rs`). The Rust * side is the runtime source of truth for the JSON output. * 2. Update `docs/output-schema.json` to match. The schema is * hand-maintained against the Rust structs; the drift-guard test in * `crates/cli/src/report/json.rs` enforces only a subset of the * contract (the `HealthFindingAction` enum). Field-level drift between * Rust and the schema is currently caught by code review. * 3. Run `pnpm --filter fallow-vscode codegen:types` from anywhere. * 4. Commit both regenerated files alongside the schema edit. * * CI runs `pnpm --filter fallow-vscode check:codegen` which fails when * either committed file disagrees with what regen would produce. */ /* eslint-disable */ /** * Schemas for the JSON output of fallow commands. Object-shaped envelopes covered by the `FallowOutput` contract carry a top-level `kind` discriminator (for example `dead-code`, `dead-code-grouped`, `health`, `dupes`, `combined`, `audit`, `explain`, `impact`, `security`, `coverage-setup`, `coverage-analyze`, `list-boundaries`, `review-envelope`, and `review-reconcile`). Consumers should branch on `kind` instead of probing for unique field presence. `--legacy-envelope` removes only the document-root `kind` for one compatibility cycle. `CodeClimateOutput` is a bare JSON array (per the Code Climate / GitLab Code Quality spec) and stays a sibling root branch discriminated by checking whether the document root is an array. */ export type FallowJsonOutput = (FallowOutput | CodeClimateOutput) /** * Typed root of every fallow JSON envelope shape that serializes as a JSON * object and participates in the documented `FallowOutput` contract. The * schema derived from this enum drives the document-root `oneOf` in * `docs/output-schema.json`. * * The default wire shape now carries a top-level `kind` discriminator so * agents and schema-validating clients can select the variant in O(1) instead * of probing for unique field presence. `--legacy-envelope` is a one-cycle * compatibility flag that removes only this document-root `kind` field from * CLI JSON output; nested report objects are not rewritten. * * One envelope is intentionally NOT in this enum: * - `CodeClimateOutput` serializes as a bare JSON array * (`#[serde(transparent)]`) per the Code Climate / GitLab Code Quality * spec; `#[serde(tag = ...)]` cannot internally tag a non-object * variant and wrapping the array would break the spec. The root schema * carries it as a sibling `oneOf` branch alongside `FallowOutput`. */ export type FallowOutput = ((AuditOutput & { kind: "audit" }) | (ExplainOutput & { kind: "explain" }) | (ReviewEnvelopeOutput & { kind: "review-envelope" }) | (ReviewReconcileOutput & { kind: "review-reconcile" }) | (CoverageSetupOutput & { kind: "coverage-setup" }) | (CoverageAnalyzeOutput & { kind: "coverage-analyze" }) | (ListBoundariesOutput & { kind: "list-boundaries" }) | (WorkspacesOutput & { kind: "list-workspaces" }) | (HealthOutput & { kind: "health" }) | (DupesOutput & { kind: "dupes" }) | (CheckGroupedOutput & { kind: "dead-code-grouped" }) | (ImpactReport & { kind: "impact" }) | (CrossRepoImpactReport & { kind: "impact-cross-repo" }) | ((SecurityOutput | SecuritySummaryOutput) & { kind: "security" }) | (CheckOutput & { kind: "dead-code" }) | (CombinedOutput & { kind: "combined" })) /** * Schema version for this output format (independent of tool version). Bump * policy: ADDITIVE changes (new optional top-level fields, new optional struct * fields, new array entries, new MCP tools, new CLI flags that map to new * optional fields) do NOT bump the version; consumers receive new fields * without breaking. BREAKING changes (renamed fields, removed fields, type * changes, enum-variant removals, semantic changes to existing fields) DO * bump. To detect newly-added fields without a bump, check field presence via * JSON-key existence rather than gating on the version. v4 was introduced * alongside fallow-cov-protocol 0.2 (per-finding verdict, stable IDs, evidence * block, renamed summary fields); v5 introduced health_score formula_version 2 * with scale-invariant scoring semantics; v6 widened `AddToConfigAction.value` * from a scalar string to `oneOf: [string, array]` so the new `ignoreExports` * action can carry a paste-ready array of `{ file, exports }` rule objects * (the legacy `ignoreDependencies` etc. variants still emit strings, so * consumers that switch on `config_key` keep working unchanged). The * runtime-coverage block is extended additively as the protocol evolves * (currently 0.3, which adds an optional capture_quality summary field). Other * additive examples: dupes --group-by adds optional grouped_by, total_issues, * groups fields without bumping. */ export type SchemaVersion = 7 /** * Fallow CLI version that produced this envelope. Renders to the JSON wire as * a bare string (e.g. `"2.74.0"`). */ export type ToolVersion = string export type AuditCommand = "audit" /** * Verdict for the audit command. */ export type AuditVerdict = ("pass" | "warn" | "fail") /** * Analysis duration in milliseconds. Renders to the JSON wire as a bare * integer. */ export type ElapsedMs = number export type AuditGate = ("new-only" | "all") /** * A suggested action attached to a finding in the JSON output. Each finding * carries an `actions` array; consumers (agents, IDE clients, CI bots) can * dispatch on the `type` discriminant to choose the right remediation. * * The discriminator is `type` (snake_case `type` field), the payload uses the * matching kebab-case identifier per variant. * * ## `auto_fixable` is per-finding, not per action type * * Every action variant carries an `auto_fixable: bool` field. The value is * evaluated PER FINDING, not per action type: the same action type may * appear with `auto_fixable: true` on one finding and `auto_fixable: false` * on another, depending on per-instance guards in the `fallow fix` applier. * Agents that filter on `auto_fixable: true` must branch on the bool of * each individual finding's action, not on the action `type` alone. * * Current per-instance flips: * * - `remove-catalog-entry` (`unused-catalog-entries`): `true` only when the * finding's `hardcoded_consumers` array is empty. When a workspace * package still pins a hardcoded version of the same package, `fallow fix` * skips the entry to avoid breaking `pnpm install`, and the action is * emitted with `auto_fixable: false`. * - `remove-dependency` vs `move-dependency` (dependency findings): when the * finding's `used_in_workspaces` array is non-empty, the primary action * flips to `move-dependency` with `auto_fixable: false` (`fallow fix` will * not remove a dependency that another workspace imports). On findings * without cross-workspace consumers the action stays `remove-dependency` * with `auto_fixable: true`. * - `add-to-config` for `ignoreExports` (`duplicate-exports`): `true` when * `fallow fix` can safely apply the action without further user setup. * That is: a fallow config file exists on disk, OR no config exists AND * the working directory is NOT inside a monorepo subpackage (in which * case the applier creates `.fallowrc.json` from `fallow init`'s * framework-aware scaffolding and layers the new rules on top). * `false` inside a monorepo subpackage with no workspace-root config * (the applier refuses to fragment per-package configs across the * monorepo and points at the workspace root instead). * - `update-catalog-reference` (`unresolved-catalog-references`): always * `false` today (the catalog-switching applier is not wired in yet); the * field is non-singleton so that future enablement does not require a * schema change. * * All `suppress-line` and `suppress-file` actions are uniformly * `auto_fixable: false`. The field is non-singleton on the wire so that a * future auto-applier (e.g. an LLM-driven suppression writer) can promote * individual variants without a schema bump. */ export type IssueAction = (FixAction | SuppressLineAction | SuppressFileAction | AddToConfigAction) /** * Discriminant string for [`FixAction`]. Kebab-case per the JSON output * contract. */ export type FixActionType = ("remove-export" | "delete-file" | "remove-dependency" | "move-dependency" | "remove-enum-member" | "remove-class-member" | "resolve-import" | "install-dependency" | "remove-duplicate" | "move-to-dev" | "refactor-cycle" | "refactor-re-export-cycle" | "refactor-boundary" | "export-type" | "remove-catalog-entry" | "remove-empty-catalog-group" | "update-catalog-reference" | "add-catalog-entry" | "remove-catalog-reference" | "remove-dependency-override" | "fix-dependency-override" | "resolve-policy-violation" | "move-to-server-module" | "split-mixed-barrel" | "hoist-directive" | "resolve-route-collision" | "resolve-dynamic-segment-name-conflict") /** * Singleton discriminant for [`SuppressLineAction`]. */ export type SuppressLineKind = "suppress-line" /** * Scope marker for line suppressions that span multiple locations. */ export type SuppressLineScope = "per-location" /** * Singleton discriminant for [`SuppressFileAction`]. */ export type SuppressFileKind = "suppress-file" /** * Singleton discriminant for [`AddToConfigAction`]. */ export type AddToConfigKind = "add-to-config" /** * Value payload for [`AddToConfigAction::value`]. The variants line up with * the documented per-`config_key` shapes; deserialization is untagged so * downstream consumers can switch on the JSON value's type. */ export type AddToConfigValue = (string | IgnoreExportsRule[] | { [k: string]: unknown }) /** * Audit-mode marker emitted on each finding when `fallow audit --format json` * runs with a base ref. `true` means the finding's structural key was not * present at the base ref (introduced by the current changeset); `false` * means it was inherited. * * Outside of audit sub-results the field is omitted, so call sites typically * hold `Option<AuditIntroduced>`. Renders to the JSON wire as a bare boolean. */ export type AuditIntroduced = boolean /** * Where in package.json a dependency is listed. * * # Examples * * ``` * use fallow_types::results::DependencyLocation; * * // All three variants are constructible * let loc = DependencyLocation::Dependencies; * let dev = DependencyLocation::DevDependencies; * let opt = DependencyLocation::OptionalDependencies; * // Debug output includes the variant name * assert!(format!("{loc:?}").contains("Dependencies")); * assert!(format!("{dev:?}").contains("DevDependencies")); * assert!(format!("{opt:?}").contains("OptionalDependencies")); * ``` */ export type DependencyLocation = ("dependencies" | "devDependencies" | "optionalDependencies") /** * The kind of member. */ export type MemberKind = ("enum_member" | "class_method" | "class_property" | "namespace_member" | "store_member") /** * Discriminator for [`ReExportCycle`]: which structural shape was detected. */ export type ReExportCycleKind = ("multi-node" | "self-loop") /** * Which rule-pack rule kind produced a [`PolicyViolation`]. */ export type PolicyRuleKind = ("banned-call" | "banned-import") /** * Effective severity of a single [`PolicyViolation`]. Per-rule `severity` * overrides the `rules."policy-violation"` master; `off` rules emit nothing, * so only `error` and `warn` appear on the wire. The exit-code gate inspects * this per-finding value, not the master severity. */ export type PolicyViolationSeverity = ("error" | "warn") /** * The origin of a stale suppression: inline comment or JSDoc tag. */ export type SuppressionOrigin = ({ /** * The issue kind token from the comment (e.g., "unused-exports"), or None for blanket. */ issue_kind?: (string | null) /** * Whether this was a file-level suppression. */ is_file_level: boolean /** * Whether `issue_kind` parses to a known `IssueKind`. False when the * token is a typo or refers to a kind that was renamed or removed in * a newer fallow release. JSON consumers (CI annotations, MCP agents, * VS Code) branch on this to choose the right next-step text. * Omitted from the wire when `true` so producers that have not yet * adopted the field stay byte-compatible. See issue #449. */ kind_known?: boolean type: "comment" } | { /** * The name of the export that was tagged. */ export_name: string type: "jsdoc_tag" }) /** * Where an override entry was declared. Serialized as the filename label * (`"pnpm-workspace.yaml"` or `"package.json"`) so the value in JSON output * matches the value users write in `ignoreDependencyOverrides[].source`. */ export type DependencyOverrideSource = ("pnpm-workspace.yaml" | "package.json") /** * Why a dependency-override entry is misconfigured. `pnpm install` would * either fail at install time or silently no-op on these entries; surfacing * them statically catches the issue before pnpm does. */ export type DependencyOverrideMisconfigReason = ("unparsable-key" | "empty-value") /** * Status of a regression-check pass. */ export type RegressionStatus = ("pass" | "exceeded" | "skipped") /** * Interpretation of [`RegressionResult::tolerance`]. */ export type RegressionToleranceKind = ("absolute" | "percentage") /** * A diagnostic about a workspace-discovery candidate. * * The `message` field is a human-readable rendering derived from `kind`. It * always ends with a concrete next step ("fix the JSON syntax", "remove from * `workspaces`", "add to `ignorePatterns`") so first-time users have a path * forward. */ export type WorkspaceDiagnostic = ({ /** * Path to the directory or file that triggered the diagnostic. */ path: string /** * Human-readable rendering derived from `kind` + `path`. Always ends * with a next-step hint. */ message: string } & WorkspaceDiagnostic1) export type WorkspaceDiagnostic1 = ({ kind: "undeclared-workspace" } | { /** * `serde_json` parse error text. */ error: string kind: "malformed-package-json" } | { /** * The glob pattern that matched the directory. */ pattern: string kind: "glob-matched-no-package-json" } | { /** * JSONC parse error text. */ error: string kind: "malformed-tsconfig" } | { kind: "tsconfig-reference-dir-missing" } | { /** * On-disk size of the skipped file in bytes. */ size_bytes: number kind: "skipped-large-file" } | { /** * On-disk size of the skipped file in bytes. */ size_bytes: number kind: "skipped-minified-file" }) /** * Discriminant for [`CloneGroupAction::kind`]. Mirrors the action types * emitted by the legacy `build_clone_group_actions` walker. */ export type CloneGroupActionType = ("extract-shared" | "suppress-line") /** * The kind of refactoring suggested for a clone family. */ export type RefactoringKind = ("ExtractFunction" | "ExtractModule") /** * Discriminant for [`CloneFamilyAction::kind`]. */ export type CloneFamilyActionType = ("extract-shared" | "apply-suggestion" | "suppress-line") /** * Which complexity threshold was exceeded. */ export type ExceededThreshold = ("cyclomatic" | "cognitive" | "both" | "crap" | "cyclomatic_crap" | "cognitive_crap" | "all") /** * Severity tier indicating how far a function exceeds complexity thresholds. * * Determined by the highest tier reached across both cognitive and cyclomatic * scores. Default thresholds: cognitive 25/40, cyclomatic 30/50. */ export type FindingSeverity = ("moderate" | "high" | "critical") /** * Coverage tier classification for CRAP findings. */ export type CoverageTier = ("none" | "partial" | "high") /** * Provenance of a CRAP finding's coverage signal. */ export type CoverageSource = ("istanbul" | "estimated" | "estimated_component_inherited") /** * Which complexity metric a [`ComplexityContribution`] adds to. */ export type ComplexityMetric = ("cyclomatic" | "cognitive") /** * The syntactic construct that produced a single complexity increment. * * Mirrors `SonarSource` cognitive-complexity vocabulary where it overlaps. * `Case` means a `case` label carrying a test; a bare `default` adds nothing * to cyclomatic complexity and so produces no contribution. */ export type ComplexityContributionKind = ("if" | "else" | "else-if" | "ternary" | "logical-and" | "logical-or" | "nullish-coalescing" | "logical-assignment" | "optional-chain" | "for" | "for-in" | "for-of" | "while" | "do-while" | "switch" | "case" | "catch" | "labeled-break" | "labeled-continue" | "jsx-depth" | "hook-density" | "prop-count") /** * Source for a finding's effective thresholds. */ export type ThresholdSource = "override" /** * Discriminant for [`HealthFindingAction::kind`]. Mirrors the action types * emitted by `build_health_finding_actions`. A single finding's `actions` * array may carry multiple entries of different types: a finding that * exceeded both cyclomatic and CRAP at `coverage_tier: partial` will get * BOTH `increase-coverage` AND `refactor-function`, plus the trailing * `suppress-line`. */ export type HealthFindingActionType = ("refactor-function" | "add-tests" | "increase-coverage" | "suppress-file" | "suppress-line") /** * Coverage model used for CRAP score computation. */ export type CoverageModel = ("static_binary" | "static_estimated" | "istanbul") /** * Whether CRAP findings in the report used one coverage-source kind or a mix. */ export type CoverageSourceConsistency = ("uniform" | "mixed") /** * Lifecycle state for a configured threshold override. */ export type ThresholdOverrideStatus = ("active" | "stale" | "no_match") /** * Discriminant for [`UntestedFileAction::kind`]. Mirrors the action types * emitted by `build_untested_file_actions`. */ export type UntestedFileActionType = ("add-tests" | "suppress-file") /** * Discriminant for [`UntestedExportAction::kind`]. Mirrors the action * types emitted by `build_untested_export_actions`. */ export type UntestedExportActionType = ("add-test-import" | "suppress-file") /** * Churn trend indicator based on comparing recent vs older halves of the analysis period. */ export type ChurnTrend = ("accelerating" | "stable" | "cooling") export type ContributorIdentifierFormat = ("raw" | "handle" | "anonymized" | "hash") export type OwnershipState = ("active" | "unowned" | "declared_inactive" | "drifting") /** * Discriminant for [`HotspotAction::kind`]. */ export type HotspotActionType = ("refactor-file" | "add-tests" | "low-bus-factor" | "unowned-hotspot" | "ownership-drift") /** * Strategy discriminant for the suggested CODEOWNERS pattern attached to * an `unowned-hotspot` action. */ export type HotspotActionHeuristic = "directory-deepest" /** * Runtime coverage JSON contract version. This is scoped to the * `runtime_coverage` block and is independent of the top-level fallow * JSON `schema_version`. */ export type RuntimeCoverageSchemaVersion = "1" /** * Top-level verdict for the whole runtime-coverage report. Mirrors * `fallow_cov_protocol::ReportVerdict`. The verdict is the SINGLE most * actionable finding; for the full set of findings see * [`RuntimeCoverageReport::signals`]. The verdict promotes `hot-path-touched` * above `cold-code-detected` in PR-review context (when the CLI was * given a change-scope: `--diff-file` or `--changed-since`) because the * touched-hot-path is event-tied to the current diff and reviewers need * it to be the top-line signal. In standalone analysis (no change * scope), `cold-code-detected` remains primary. */ export type RuntimeCoverageReportVerdict = ("clean" | "hot-path-touched" | "cold-code-detected" | "license-expired-grace" | "unknown") /** * Discrete signal captured during runtime-coverage post-processing. * `verdict` collapses to one summary value; `signals` enumerates ALL * findings the report carries so JSON consumers, CI dashboards, and * agents can reason about them independently of the headline. Order is * stable: severity-descending so the first entry mirrors a sensible * non-PR-context verdict. */ export type RuntimeCoverageSignal = ("license-expired-grace" | "cold-code-detected" | "hot-path-touched") /** * Runtime coverage source used to produce the summary. */ export type RuntimeCoverageDataSource = ("local" | "cloud") /** * Protocol-level per-function runtime coverage verdict derived from the * decision table in fallow-cov-protocol. The CLI's `runtime_coverage.findings` * array omits `active` entries even though the underlying enum still includes * it. */ export type RuntimeCoverageVerdict = ("safe_to_delete" | "review_required" | "coverage_unavailable" | "low_traffic" | "active" | "unknown") /** * Confidence level for a runtime coverage finding. */ export type RuntimeCoverageConfidence = ("very_high" | "high" | "medium" | "low" | "none" | "unknown") /** * Blast-radius risk band. The current thresholds are high at >=20 static * callers or >=1,000,000 traffic-weighted caller reach; medium at >=5 callers * or >=50,000 weighted reach; low otherwise. */ export type RuntimeCoverageRiskBand = ("low" | "medium" | "high") /** * License or trial watermark applied to runtime coverage output. */ export type RuntimeCoverageWatermark = ("trial-expired" | "license-expired-grace" | "unknown") /** * Coverage-intelligence JSON contract version. Scoped to the * `coverage_intelligence` block and independent of the top-level fallow * JSON `schema_version`. */ export type CoverageIntelligenceSchemaVersion = "1" /** * Headline verdict for the combined coverage-intelligence report. */ export type CoverageIntelligenceVerdict = ("risky-change-detected" | "high-confidence-delete" | "review-required" | "refactor-carefully" | "clean" | "unknown") /** * Ordered evidence signals behind a coverage-intelligence finding. */ export type CoverageIntelligenceSignal = ("changed" | "hot_path" | "low_test_coverage" | "high_crap" | "static_unused" | "runtime_cold" | "no_test_path" | "runtime_reachable" | "ownership_drift" | "test_covered") /** * Recommended action family for a combined finding. */ export type CoverageIntelligenceRecommendation = ("add-test-or-split-before-merge" | "delete-after-confirming-owner" | "review-before-changing" | "refactor-carefully-keep-behavior") /** * Confidence in the joined evidence and resulting recommendation. */ export type CoverageIntelligenceConfidence = ("high" | "medium" | "low") /** * Confidence tier for the cross-surface evidence match. */ export type CoverageIntelligenceMatchConfidence = ("path-function-line" | "path-line" | "direct") /** * Category of refactoring recommendation. */ export type RecommendationCategory = ("urgent_churn_complexity" | "break_circular_dependency" | "split_high_impact" | "remove_dead_code" | "extract_complex_functions" | "extract_dependencies" | "add_test_coverage") /** * A ranked refactoring recommendation for a file. * * ## Priority Formula * * ```text * priority = min(density, 1) × 30 + hotspot_boost × 25 + dead_code × 20 + fan_in_norm × 15 + fan_out_norm × 10 * ``` * * Fan-in and fan-out normalization uses adaptive percentile-based thresholds * (p95 of the project distribution, with floors) instead of fixed constants. * * ## Efficiency (default sort) * * ```text * efficiency = priority / effort_numeric (Low=1, Medium=2, High=3) * ``` * * Surfaces quick wins: high-priority, low-effort targets rank first. * Effort estimate for a refactoring target. */ export type EffortEstimate = ("low" | "medium" | "high") /** * Confidence level for a refactoring recommendation. * * Based on the data source reliability: * - **High**: deterministic graph/AST analysis (dead code, circular deps, complexity) * - **Medium**: heuristic thresholds (fan-in/fan-out coupling) * - **Low**: depends on git history quality (churn-based recommendations) */ export type Confidence = ("high" | "medium" | "low") /** * Discriminant for [`RefactoringTargetAction::kind`]. */ export type RefactoringTargetActionType = ("apply-refactoring" | "suppress-line") /** * Direction of a metric's change, semantically (improving/declining/stable). */ export type TrendDirection = ("improving" | "declining" | "stable") /** * Discriminant for [`CssCandidateAction::kind`]. */ export type CssCandidateActionType = ("verify-unused" | "verify-undefined" | "consolidate" | "replace-with-token" | "standardize") /** * Discriminant for [`UnusedAtRule::kind`]. */ export type UnusedAtRuleKind = ("property-registration" | "layer") /** * Singleton GitHub review-event marker. */ export type ReviewEnvelopeEvent = "COMMENT" /** * Per-line review comment. Schema is an `anyOf` between GitHub and GitLab * shapes; at runtime every entry in a single envelope comes from the same * provider because the envelope is built from one provider's branch in * `crates/cli/src/report/ci/review.rs::render_review_envelope`. */ export type ReviewComment = (GitHubReviewComment | GitLabReviewComment) /** * Singleton side discriminator for [`GitHubReviewComment::side`]. */ export type GitHubReviewSide = "RIGHT" /** * Singleton position-type discriminator for [`GitLabReviewPosition`]. */ export type GitLabReviewPositionType = "text" /** * Schema-version discriminator for the review envelope. */ export type ReviewEnvelopeSchema = ("fallow-review-envelope/v1" | "fallow-review-envelope/v2") /** * Review-envelope provider tag. */ export type ReviewProvider = ("github" | "gitlab") /** * `meta.check_conclusion` for the GitHub review envelope. Maps to the * GitHub Checks API conclusion field. */ export type ReviewCheckConclusion = ("success" | "neutral" | "failure") /** * Schema-version discriminator for the review reconcile envelope. */ export type ReviewReconcileSchema = "fallow-review-reconcile/v1" export type CoverageSetupSchemaVersion = "1" export type CoverageSetupFramework = ("nextjs" | "nestjs" | "nuxt" | "sveltekit" | "astro" | "remix" | "vite" | "plain_node" | "unknown") export type CoverageSetupPackageManager = ("npm" | "pnpm" | "yarn" | "bun") export type CoverageSetupRuntimeTarget = ("node" | "browser") export type CoverageAnalyzeSchemaVersion = "1" /** * Discovery outcome for a [`LogicalGroup`]. */ export type LogicalGroupStatus = ("ok" | "empty" | "invalid_path") /** * Resolver mode label for grouped envelopes (dead-code, dupes, health). * * `owner` groups by CODEOWNERS team, `directory` groups by top-level * directory prefix, `package` groups by workspace package name, `section` * groups by GitLab CODEOWNERS `[Section]` header name. */ export type GroupByMode = ("owner" | "directory" | "package" | "section") /** * Wire-version discriminator for [`ImpactReport`]. Independent from the global * `SchemaVersion` (the impact report versions on its own cadence) and from the * on-disk `STORE_SCHEMA_VERSION` (the persisted store shape versions * separately). Serializes as a string `const` so JSON consumers can switch on * it, matching the other independently-versioned envelopes (e.g. * `CoverageAnalyzeSchemaVersion`). */ export type ImpactReportSchemaVersion = "1" /** * Why Impact tracking is (or is not) active for a project. `Project` = an * explicit per-repo `enable`; `User` = the user-global default with no per-repo * decision; `Default` = off (no per-repo decision and no global default). */ export type EnabledSource = ("project" | "user" | "default") /** * Direction of a count trend between two recorded runs. */ export type ImpactTrendDirection = ("improving" | "declining" | "stable") /** * Independent wire-version for the cross-repo report, on its own cadence (it * versions separately from the per-project `ImpactReportSchemaVersion` and the * on-disk `STORE_SCHEMA_VERSION`). */ export type CrossRepoImpactSchemaVersion = "1" /** * The `fallow security --format json` schema version. Independently versioned * from the main contract, mirroring `ImpactReportSchemaVersion`. */ export type SecuritySchemaVersion = ("1" | "2" | "3" | "4" | "5" | "6" | "7") /** * Severity level for rules. * * Controls whether an issue type causes CI failure (`error`), is reported * without failing (`warn`), or is suppressed entirely (`off`). */ export type Severity = ("error" | "warn" | "off") /** * Gate mode for `fallow security --gate <mode>`. */ export type SecurityGateMode = ("new" | "newly-reachable") /** * Gate verdict on the wire. `fail` is the CI-state token; human output renders * it as "REVIEW REQUIRED" because these stay unverified candidates, never * confirmed vulnerabilities. */ export type SecurityGateVerdict = ("pass" | "fail") /** * The kind of security candidate. Findings are CANDIDATES for downstream agent * verification, NOT verified vulnerabilities. */ export type SecurityFindingKind = ("client-server-leak" | "tainted-sink") /** * Verification-priority tier for a security candidate. This is ranking, not an * exploitability verdict. */ export type SecuritySeverity = ("high" | "medium" | "low") /** * The role a hop plays in a security finding's structural import trace. */ export type TraceHopRole = ("client-boundary" | "untrusted-source" | "module-source" | "intermediate" | "secret-source" | "sink") /** * Dead-code issue kind linked to a security candidate. */ export type SecurityDeadCodeKind = ("unused-file" | "unused-export") /** * How strongly the untrusted-source signal is associated with the sink, a * structured discriminator so a consumer can tier candidates without parsing * the human `evidence` prose. Present only when * [`SecurityReachability::reachable_from_untrusted_source`] is true. Neither * value proves exploitability; both are ranking signals (issue #885 doctrine: * rank, never gate). */ export type TaintConfidence = ("arg-level" | "module-level") /** * Static URL construction shape captured for URL-shaped security sinks. */ export type SecurityUrlShape = ("fixed-origin-dynamic-path" | "dynamic-origin") /** * Runtime coverage state for the function enclosing a security sink. * This is production-observation evidence, not an exploitability verdict. */ export type SecurityRuntimeState = ("runtime-hot" | "runtime-cold" | "never-executed" | "low-traffic" | "coverage-unavailable" | "runtime-unknown") /** * Defensive control family detected on a source to sink path. */ export type SecurityControlKind = ("sanitization" | "validation" | "authentication" | "authorization") /** * Why a sink-shaped callee could not be flattened into a static catalogue * path. */ export type SkippedSecurityCalleeReason = ("computed-member" | "dynamic-dispatch" | "unsupported-assignment-object") /** * Syntactic expression shape for a skipped security callee. */ export type SkippedSecurityCalleeExpressionKind = ("static-member-expression" | "computed-member-expression" | "identifier" | "other") /** * Discriminator value for [`CodeClimateIssue::kind`]. */ export type CodeClimateIssueKind = "issue" /** * CodeClimate severity scale. */ export type CodeClimateSeverity = ("info" | "minor" | "major" | "critical" | "blocker") /** * Envelope emitted by `fallow --format codeclimate` and * `fallow --format gitlab-codequality`. GitLab Code Quality consumes the * same shape. The wire form is a bare JSON array, not an object. */ export type CodeClimateOutput = CodeClimateIssue[] /** * `fallow audit --format json` envelope. */ export interface AuditOutput { schema_version: SchemaVersion version: ToolVersion command: AuditCommand verdict: AuditVerdict changed_files_count: number base_ref: string /** * Human-readable provenance of `base_ref`, e.g. `merge-base with * origin/main`, `local main`, or `FALLOW_AUDIT_BASE=upstream/main`. * Present when the base was auto-detected or set via `FALLOW_AUDIT_BASE`; * absent for an explicit `--base` (the ref the user typed is already * self-describing). */ base_description?: (string | null) head_sha?: (string | null) elapsed_ms: ElapsedMs base_snapshot_skipped?: (boolean | null) summary: AuditSummary attribution: AuditAttribution _meta?: (Meta | null) dead_code?: (CheckOutput | null) duplication?: (DupesReportPayload | null) complexity?: (HealthReport | null) /** * Read-only follow-up commands computed from this run's findings. See * [`CheckOutput::next_steps`] for the contract. */ next_steps?: NextStep[] } /** * Per-category summary counts for the audit result. */ export interface AuditSummary { dead_code_issues: number dead_code_has_errors: boolean complexity_findings: number max_cyclomatic?: (number | null) duplication_clone_groups: number } /** * New-vs-inherited issue counts for audit. */ export interface AuditAttribution { gate: AuditGate dead_code_introduced: number dead_code_inherited: number complexity_introduced: number complexity_inherited: number duplication_introduced: number duplication_inherited: number } /** * Metric and rule definitions emitted under `_meta` when `--explain` is * passed (always present in MCP responses). Helps AI agents and CI systems * interpret metric values without re-reading the docs site. */ export interface Meta { /** * URL to the documentation page for this command. */ docs?: (string | null) /** * Local telemetry correlation metadata for agent follow-up runs. */ telemetry?: (TelemetryMeta | null) /** * Per-field definitions for envelope fields and action payload fields. */ field_definitions?: { [k: string]: string } /** * Per-metric definitions: name, description, range, interpretation. */ metrics?: { [k: string]: MetaMetric } /** * Per-rule definitions for check command output. */ rules?: { [k: string]: MetaRule } } /** * Privacy-safe local run metadata emitted for JSON consumers. */ export interface TelemetryMeta { /** * Ephemeral local token that may be passed to the hidden `--parent-run` * flag on a later command. It is not derived from repository, path, user, * machine, project, or cloud data. */ analysis_run_id?: (string | null) } /** * Single-metric definition inside [`Meta::metrics`]. */ export interface MetaMetric { /** * Human-readable metric name. */ name?: (string | null) /** * What this metric measures and how it is computed. */ description?: (string | null) /** * Valid value range (e.g., `"[0, 100]"`). */ range?: (string | null) /** * How to read the value (e.g., `"lower is better"`). */ interpretation?: (string | null) } /** * Single-rule definition inside [`Meta::rules`]. */ export interface MetaRule { /** * Human-readable rule name. */ name?: (string | null) /** * What this rule detects. */ description?: (string | null) /** * URL to the rule documentation. */ docs?: (string | null) } /** * Envelope emitted by `fallow dead-code --format json` (plus the `check` * block inside the combined and audit envelopes). * * The body is the full `AnalysisResults` flattened into the envelope so * every issue array (`unused_files`, `unused_exports`, ...) lives at the * top level, matching the existing wire shape. `entry_points` lifts the * otherwise `#[serde(skip)]`'d `AnalysisResults::entry_point_summary` back * into the JSON output. `summary` carries the per-category counts the * JSON layer always emits. */ export interface CheckOutput { schema_version: SchemaVersion version: ToolVersion elapsed_ms: ElapsedMs total_issues: number entry_points?: (EntryPoints | null) summary: CheckSummary /** * Files not reachable from any entry point. Wrapped in * [`UnusedFileFinding`] so each entry carries a typed `actions` array * natively, replacing the pre-2.76 post-pass injection. */ unused_files: UnusedFileFinding[] /** * Exports never imported by other modules. Wrapped in * [`UnusedExportFinding`] so each entry carries a typed `actions` * array natively. */ unused_exports: UnusedExportFinding[] /** * Type exports never imported by other modules. Wrapped in * [`UnusedTypeFinding`]: the inner [`UnusedExport`] struct is shared * with `unused_exports` but the wrapper emits a type-targeted fix * description. */ unused_types: UnusedTypeFinding[] /** * Exported symbols whose public signature references same-file private * types. Wrapped in [`PrivateTypeLeakFinding`] so each entry carries a * typed `actions` array natively. */ private_type_leaks: PrivateTypeLeakFinding[] /** * Dependencies listed in package.json but never imported. Wrapped in * [`UnusedDependencyFinding`] so each entry carries a typed `actions` * array natively. The fix action swaps from `remove-dependency` to * `move-dependency` when `used_in_workspaces` is non-empty. */ unused_dependencies: UnusedDependencyFinding[] /** * Dev dependencies listed in package.json but never imported. Wrapped * in [`UnusedDevDependencyFinding`]: same bare struct as * `unused_dependencies` with a `devDependencies`-targeted fix * description. */ unused_dev_dependencies: UnusedDevDependencyFinding[] /** * Optional dependencies listed in package.json but never imported. * Wrapped in [`UnusedOptionalDependencyFinding`] with an * `optionalDependencies`-targeted fix description. */ unused_optional_dependencies: UnusedOptionalDependencyFinding[] /** * Enum members never accessed. Wrapped in * [`UnusedEnumMemberFinding`] so each entry carries a typed `actions` * array natively. */ unused_enum_members: UnusedEnumMemberFinding[] /** * Class members never accessed. Wrapped in * [`UnusedClassMemberFinding`]: same inner [`UnusedMember`] struct as * `unused_enum_members`, with a class-targeted fix description and the * `auto_fixable: false` default to reflect dependency-injection * patterns. */ unused_class_members: UnusedClassMemberFinding[] /** * Store members (Pinia `state` / `getters` / `actions` key, or a * setup-store returned key) declared but never accessed by any consumer * project-wide. Wrapped in [`UnusedStoreMemberFinding`]: same inner * [`UnusedMember`] struct as `unused_class_members`, with a * store-targeted fix description. Cross-graph: the store binding is * imported (the module is reachable) yet a specific member is dead. */ unused_store_members?: UnusedStoreMemberFinding[] /** * Import specifiers that could not be resolved. Wrapped in * [`UnresolvedImportFinding`] so each entry carries a typed `actions` * array natively. */ unresolved_imports: UnresolvedImportFinding[] /** * Dependencies used in code but not listed in package.json. Wrapped in * [`UnlistedDependencyFinding`]. */ unlisted_dependencies: UnlistedDependencyFinding[] /** * Exports with the same name across multiple modules. Wrapped in * [`DuplicateExportFinding`] so each entry carries a typed `actions` * array natively, with the position-0 `add-to-config` `ignoreExports` * snippet wired in at wrapper construction. */ duplicate_exports: DuplicateExportFinding[] /** * Production dependencies only used via type-only imports (could be * devDependencies). Only populated in production mode. Wrapped in * [`TypeOnlyDependencyFinding`]. */ type_only_dependencies: TypeOnlyDependencyFinding[] /** * Production dependencies only imported by test files (could be * devDependencies). Wrapped in [`TestOnlyDependencyFinding`]. */ test_only_dependencies?: TestOnlyDependencyFinding[] /** * Circular dependency chains detected in the module graph. Wrapped in * [`CircularDependencyFinding`] so each entry carries a typed `actions` * array natively. */ circular_dependencies: CircularDependencyFinding[] /** * Cycles or self-loops in the re-export edge subgraph (barrel files * re-exporting from each other in a loop). Wrapped in * [`ReExportCycleFinding`] so each entry carries a typed `actions` * array natively (a `refactor-re-export-cycle` informational primary * plus a `suppress-file` secondary; cycles are file-scoped so a single * suppression breaks the cycle). */ re_export_cycles?: ReExportCycleFinding[] /** * Imports that cross architecture boundary rules. Wrapped in * [`BoundaryViolationFinding`] so each entry carries a typed `actions` * array natively. */ boundary_violations?: BoundaryViolationFinding[] /** * Files that matched no architecture boundary zone while * `boundaries.coverage.requireAllFiles` was enabled. */ boundary_coverage_violations?: BoundaryCoverageViolationFinding[] /** * Calls from zoned files to callees forbidden for that zone via * `boundaries.calls.forbidden`. Wrapped in * [`BoundaryCallViolationFinding`] so each entry carries a typed * `actions` array natively. */ boundary_call_violations?: BoundaryCallViolationFinding[] /** * Banned calls and banned imports matched by declarative rule packs * (`rulePacks` config). Wrapped in [`PolicyViolationFinding`] so each * entry carries a typed `actions` array natively. Each finding carries * its effective per-rule severity. */ policy_violations?: PolicyViolationFinding[] /** * Suppression comments or JSDoc tags that no longer match any issue. */ stale_suppressions?: StaleSuppression[] /** * Entries in pnpm-workspace.yaml's catalog: or catalogs: sections not * referenced by any workspace package via the catalog: protocol. Wrapped * in [`UnusedCatalogEntryFinding`] so each entry carries a typed * `actions` array natively, with per-instance `auto_fixable` derived * from `hardcoded_consumers`. */ unused_catalog_entries?: UnusedCatalogEntryFinding[] /** * Named groups under pnpm-workspace.yaml's catalogs: section that declare * no package entries. The top-level catalog: map is not reported. Wrapped * in [`EmptyCatalogGroupFinding`]. */ empty_catalog_groups?: EmptyCatalogGroupFinding[] /** * Workspace package.json references to catalogs (`catalog:` or * `catalog:<name>`) that do not declare the consumed package. pnpm install * will error until the named catalog grows to include the package or the * reference is switched / removed. Wrapped in * [`UnresolvedCatalogReferenceFinding`] with the discriminated * `add-catalog-entry` / `update-catalog-reference` primary at position 0. */ unresolved_catalog_references?: UnresolvedCatalogReferenceFinding[] /** * Entries in pnpm-workspace.yaml's overrides: section, or package.json's * pnpm.overrides block, whose target package is not declared by any * workspace package and is not present in pnpm-lock.yaml. Default severity * is warn because projects without a readable lockfile fall back to * manifest-only checks; the hint field flags those conservative cases. * Wrapped in [`UnusedDependencyOverrideFinding`]. */ unused_dependency_overrides?: UnusedDependencyOverrideFinding[] /** * pnpm.overrides entries whose key or value does not parse as a valid * override spec (empty key, empty value, malformed selector, unbalanced * parent matcher). pnpm install will reject these. Default severity is * error. Wrapped in [`MisconfiguredDependencyOverrideFinding`]. */ misconfigured_dependency_overrides?: MisconfiguredDependencyOverrideFinding[] /** * `"use client"` files that export a Next.js server-only / route-segment * config name (e.g. `metadata`, `revalidate`, `GET`). Next.js rejects this * at build time. Wrapped in [`InvalidClientExportFinding`] so each entry * carries a typed `actions` array natively. Default severity is `warn`. */ invalid_client_exports?: InvalidClientExportFinding[] /** * Barrel files that re-export BOTH a `"use client"` origin module AND a * server-only origin module (the Next.js App Router footgun). Wrapped in * [`MixedClientServerBarrelFinding`] so each entry carries a typed * `actions` array natively. Default severity is `warn`. */ mixed_client_server_barrels?: MixedClientServerBarrelFinding[] /** * `"use client"` / `"use server"` directives written as expression * statements after a non-directive statement, so the RSC bundler parses * them as ordinary strings and silently ignores them. Wrapped in * [`MisplacedDirectiveFinding`] so each entry carries a typed `actions` * array natively. Default severity is `warn`. */ misplaced_directives?: MisplacedDirectiveFinding[] /** * Vue `inject(KEY)` / Svelte `getContext(KEY)` calls whose symbol KEY is * provided nowhere in the project (the injected-never-provided dead-half). * Wrapped in [`UnprovidedInjectFinding`] so each entry carries a typed * `actions` array natively. Default severity is `warn`. */ unprovided_injects?: UnprovidedInjectFinding[] /** * Vue/Svelte single-file components that are reachable but rendered nowhere * (the imported-but-never-rendered dead-half). Wrapped in * [`UnrenderedComponentFinding`] so each entry carries a typed `actions` * array natively. Default severity is `warn`. */ unrendered_components?: UnrenderedComponentFinding[] /** * Next.js App Router route files that resolve to the same URL within one * app-root (a guaranteed `next build` failure). Wrapped in * [`RouteCollisionFinding`] so each entry carries a typed `actions` array * natively. One finding per colliding file. Default severity is `warn`. */ route_collisions?: RouteCollisionFinding[] /** * Sibling Next.js dynamic route segments at one tree position using * different param spellings (a dev / runtime error; `next build` does NOT * catch it). Wrapped in [`DynamicSegmentNameConflictFinding`] so each entry * carries a typed `actions` array natively. Default severity is `warn`. */ dynamic_segment_name_conflicts?: DynamicSegmentNameConflictFinding[] /** * Vue `<script setup>` `defineProps` props referenced nowhere in their own * SFC (neither `<script>` nor `<template>`). Wrapped in * [`UnusedComponentPropFinding`] so each entry carries a typed `actions` * array natively. Default severity is `warn`. */ unused_component_props?: UnusedComponentPropFinding[] /** * Vue `<script setup>` `defineEmits` events emitted nowhere in their own SFC * (no `emit('<name>')` call). Wrapped in [`UnusedComponentEmitFinding`] so * each entry carries a typed `actions` array natively. Default severity is * `warn`. */ unused_component_emits?: UnusedComponentEmitFinding[] /** * Next.js Server Actions (exports of `"use server"` files) that no code in * the project references. Reclassified out of `unused_exports` for * `"use server"` files. Wrapped in [`UnusedServerActionFinding`] so each * entry carries a typed `actions` array natively. Default severity is * `warn`. */ unused_server_actions?: UnusedServerActionFinding[] /** * SvelteKit `+page.{ts,server.ts,js,server.js}` `load()` return-object keys * read by no consumer. Wrapped in [`UnusedLoadDataKeyFinding`] so each entry * carries a typed `actions` array natively. Default severity is `warn`. */ unused_load_data_keys?: UnusedLoadDataKeyFinding[] /** * `true` when the `unused-load-data-key` detector abstained project-wide * because a whole-object use of `page.data` / `$page.data` was seen * somewhere (S1 observability: an empty `unused_load_data_keys` with this * flag set is NOT a clean bill, it means the rule could not run safely). * Serialized only when `true` so the default JSON contract is unchanged. */ unused_load_data_keys_global_abstain?: boolean /** * React/Preact props forwarded unchanged through `>= N` intermediate * pass-through components until a consumer (located per-chain records). * Wrapped in [`PropDrillingChainFinding`] so each entry carries a typed * `actions` array natively. Health signal: the rule defaults to `off` * (opt-in), so this is dormant and populated ONLY when the user enables it. */ prop_drilling_chains?: PropDrillingChainFinding[] /** * React/Preact components whose entire body is a single spread-forwarded * child render (`return <Child {...props}/>`): pure structural indirection, * a candidate for inlining at call sites. Wrapped in [`ThinWrapperFinding`] * so each entry carries a typed `actions` array natively. Health signal: the * rule defaults to `off` (opt-in), so this is dormant and populated ONLY * when the user enables it. */ thin_wrappers?: ThinWrapperFinding[] /** * React/Preact components that participate in a duplicate-prop-shape group: * three or more components across two or more files whose statically-known * prop NAME set is identical after stripping ubiquitous DOM / passthrough * names (a missing shared `Props` type / base component). Wrapped in * [`DuplicatePropShapeFinding`] so each entry carries a typed `actions` * array and its sibling roster natively. Health signal: the rule defaults to * `off` (opt-in), so this is dormant and populated ONLY when the user * enables it. */ duplicate_prop_shapes?: DuplicatePropShapeFinding[] baseline_deltas?: (BaselineDeltas | null) baseline?: (BaselineMatch | null) regression?: (RegressionResult | null) _meta?: (Meta | null) workspace_diagnostics?: WorkspaceDiagnostic[] /** * Read-only follow-up commands computed from this run's findings, emitted * at the JSON root so an agent acting on the output is pointed at fallow's * adjacent verification capabilities (trace, complexity breakdown, audit, * workspace scoping). Each command is runnable as-is and never mutating; * see [`NextStep`] for both contracts. Omitted when empty or when * `FALLOW_SUGGESTIONS=off`; does NOT contribute to `total_issues`. */ next_steps?: NextStep[] } /** * Entry-point detection summary embedded in `CheckOutput` and the combined * envelope. */ export interface EntryPoints { /** * Total number of detected entry points. */ total: number /** * Breakdown of entry points by detection source (e.g., `"package.json"`, * `"next.js"`, `"config entry"`). Underscored keys so dashboards can * drill into individual sources. */ sources: { [k: string]: number } } /** * Per-category issue counts for dead-code analysis. Always present in