fallow 2.76.0 → 2.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -164,7 +164,7 @@ export type IssueAction = (FixAction | SuppressLineAction | SuppressFileAction |
164
164
  * Discriminant string for [`FixAction`]. Kebab-case per the JSON output
165
165
  * contract.
166
166
  */
167
- 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-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")
167
+ 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")
168
168
  /**
169
169
  * Singleton discriminant for [`SuppressLineAction`].
170
170
  */
@@ -233,6 +233,10 @@ export type DependencyLocation = ("dependencies" | "devDependencies" | "optional
233
233
  * ```
234
234
  */
235
235
  export type MemberKind = ("enum_member" | "class_method" | "class_property" | "namespace_member")
236
+ /**
237
+ * Discriminator for [`ReExportCycle`]: which structural shape was detected.
238
+ */
239
+ export type ReExportCycleKind = ("multi-node" | "self-loop")
236
240
  /**
237
241
  * The origin of a stale suppression: inline comment or JSDoc tag.
238
242
  */
@@ -245,6 +249,15 @@ issue_kind?: (string | null)
245
249
  * Whether this was a file-level suppression.
246
250
  */
247
251
  is_file_level: boolean
252
+ /**
253
+ * Whether `issue_kind` parses to a known `IssueKind`. False when the
254
+ * token is a typo or refers to a kind that was renamed or removed in
255
+ * a newer fallow release. JSON consumers (CI annotations, MCP agents,
256
+ * VS Code) branch on this to choose the right next-step text.
257
+ * Omitted from the wire when `true` so producers that have not yet
258
+ * adopted the field stay byte-compatible. See issue #449.
259
+ */
260
+ kind_known?: boolean
248
261
  type: "comment"
249
262
  } | {
250
263
  /**
@@ -273,6 +286,48 @@ export type RegressionStatus = ("pass" | "exceeded" | "skipped")
273
286
  * Interpretation of [`RegressionResult::tolerance`].
274
287
  */
275
288
  export type RegressionToleranceKind = ("absolute" | "percentage")
289
+ /**
290
+ * A diagnostic about a workspace-discovery candidate.
291
+ *
292
+ * The `message` field is a human-readable rendering derived from `kind`. It
293
+ * always ends with a concrete next step ("fix the JSON syntax", "remove from
294
+ * `workspaces`", "add to `ignorePatterns`") so first-time users have a path
295
+ * forward.
296
+ */
297
+ export type WorkspaceDiagnostic = ({
298
+ /**
299
+ * Path to the directory or file that triggered the diagnostic.
300
+ */
301
+ path: string
302
+ /**
303
+ * Human-readable rendering derived from `kind` + `path`. Always ends
304
+ * with a next-step hint.
305
+ */
306
+ message: string
307
+ } & WorkspaceDiagnostic1)
308
+ export type WorkspaceDiagnostic1 = ({
309
+ kind: "undeclared-workspace"
310
+ } | {
311
+ /**
312
+ * `serde_json` parse error text.
313
+ */
314
+ error: string
315
+ kind: "malformed-package-json"
316
+ } | {
317
+ /**
318
+ * The glob pattern that matched the directory.
319
+ */
320
+ pattern: string
321
+ kind: "glob-matched-no-package-json"
322
+ } | {
323
+ /**
324
+ * JSONC parse error text.
325
+ */
326
+ error: string
327
+ kind: "malformed-tsconfig"
328
+ } | {
329
+ kind: "tsconfig-reference-dir-missing"
330
+ })
276
331
  /**
277
332
  * Discriminant for [`CloneGroupAction::kind`]. Mirrors the action types
278
333
  * emitted by the legacy `build_clone_group_actions` walker.
@@ -495,7 +550,7 @@ export type GitLabReviewPositionType = "text"
495
550
  /**
496
551
  * Schema-version discriminator for the review envelope.
497
552
  */
498
- export type ReviewEnvelopeSchema = "fallow-review-envelope/v1"
553
+ export type ReviewEnvelopeSchema = ("fallow-review-envelope/v1" | "fallow-review-envelope/v2")
499
554
  /**
500
555
  * Review-envelope provider tag.
501
556
  */
@@ -769,6 +824,15 @@ test_only_dependencies?: TestOnlyDependencyFinding[]
769
824
  * array natively.
770
825
  */
771
826
  circular_dependencies: CircularDependencyFinding[]
827
+ /**
828
+ * Cycles or self-loops in the re-export edge subgraph (barrel files
829
+ * re-exporting from each other in a loop). Wrapped in
830
+ * [`ReExportCycleFinding`] so each entry carries a typed `actions`
831
+ * array natively (a `refactor-re-export-cycle` informational primary
832
+ * plus a `suppress-file` secondary; cycles are file-scoped so a single
833
+ * suppression breaks the cycle).
834
+ */
835
+ re_export_cycles?: ReExportCycleFinding[]
772
836
  /**
773
837
  * Imports that cross architecture boundary rules. Wrapped in
774
838
  * [`BoundaryViolationFinding`] so each entry carries a typed `actions`
@@ -837,6 +901,16 @@ regression?: (RegressionResult | null)
837
901
  * is passed (always present in MCP responses).
838
902
  */
839
903
  _meta?: (Meta | null)
904
+ /**
905
+ * Workspace-discovery diagnostics surfaced by
906
+ * `discover_workspaces_with_diagnostics` (issue #473): malformed
907
+ * declared-workspace `package.json`, glob matches with no `package.json`,
908
+ * malformed `tsconfig.json`, missing tsconfig reference paths. Omitted
909
+ * when empty so consumers on monorepos without discovery noise see no
910
+ * new field. Pairing of `#[serde(default, skip_serializing_if = ...)]`
911
+ * is required for schemars to mark the field non-required.
912
+ */
913
+ workspace_diagnostics?: WorkspaceDiagnostic[]
840
914
  }
841
915
  /**
842
916
  * Entry-point detection summary embedded in `CheckOutput` and the combined
@@ -922,6 +996,11 @@ test_only_dependencies: number
922
996
  * Cycles detected in the import graph.
923
997
  */
924
998
  circular_dependencies: number
999
+ /**
1000
+ * Cycles or self-loops in the re-export edge subgraph (barrel files
1001
+ * re-exporting from each other in a loop).
1002
+ */
1003
+ re_export_cycles?: number
925
1004
  /**
926
1005
  * Imports that cross architecture boundary rules.
927
1006
  */
@@ -1674,6 +1753,33 @@ actions: IssueAction[]
1674
1753
  */
1675
1754
  introduced?: (AuditIntroduced | null)
1676
1755
  }
1756
+ /**
1757
+ * Wire-shape envelope for a [`ReExportCycle`] finding. Mirrors
1758
+ * [`CircularDependencyFinding`]: flattens the bare finding and carries a
1759
+ * typed `actions` array (`refactor-re-export-cycle` informational primary
1760
+ * plus `suppress-file` secondary; cycles are file-scoped so a single
1761
+ * file-level suppression on the alphabetically-first member breaks the
1762
+ * cycle, and no `// fallow-ignore-next-line` form makes sense because the
1763
+ * diagnostic is anchored at line 1 col 0 of each member).
1764
+ */
1765
+ export interface ReExportCycleFinding {
1766
+ /**
1767
+ * Files participating in the cycle, sorted lexicographically. For a
1768
+ * self-loop, exactly one entry.
1769
+ */
1770
+ files: string[]
1771
+ kind: ReExportCycleKind
1772
+ /**
1773
+ * Suggested next steps. Always emitted (possibly empty for
1774
+ * forward-compat).
1775
+ */
1776
+ actions: IssueAction[]
1777
+ /**
1778
+ * Set by the audit pass when this finding is introduced relative to
1779
+ * the merge-base.
1780
+ */
1781
+ introduced?: (AuditIntroduced | null)
1782
+ }
1677
1783
  /**
1678
1784
  * Wire-shape envelope for a [`BoundaryViolation`] finding. Mirrors
1679
1785
  * [`UnusedFileFinding`]: flattens the bare finding and carries a typed
@@ -2063,6 +2169,12 @@ export interface Meta {
2063
2169
  * URL to the documentation page for this command.
2064
2170
  */
2065
2171
  docs?: (string | null)
2172
+ /**
2173
+ * Per-field definitions for envelope fields and action payload fields.
2174
+ */
2175
+ field_definitions?: {
2176
+ [k: string]: string
2177
+ }
2066
2178
  /**
2067
2179
  * Per-metric definitions: name, description, range, interpretation.
2068
2180
  */
@@ -3927,15 +4039,15 @@ export interface TargetEvidence {
3927
4039
  /**
3928
4040
  * Names of unused exports (populated for `RemoveDeadCode` targets).
3929
4041
  */
3930
- unused_exports: string[]
4042
+ unused_exports?: string[]
3931
4043
  /**
3932
4044
  * Complex functions with line numbers and cognitive scores (populated for `ExtractComplexFunctions`).
3933
4045
  */
3934
- complex_functions: EvidenceFunction[]
4046
+ complex_functions?: EvidenceFunction[]
3935
4047
  /**
3936
4048
  * Files forming the import cycle (populated for `BreakCircularDependency` targets).
3937
4049
  */
3938
- cycle_path: string[]
4050
+ cycle_path?: string[]
3939
4051
  }
3940
4052
  /**
3941
4053
  * A function referenced in target evidence.
@@ -4199,16 +4311,75 @@ export interface ReviewEnvelopeOutput {
4199
4311
  */
4200
4312
  event?: (ReviewEnvelopeEvent | null)
4201
4313
  /**
4202
- * Review summary body (rendered above per-line comments).
4314
+ * Review summary body (rendered above per-line comments). Deprecated in
4315
+ * v2 envelopes: prefer [`summary.body`](`ReviewEnvelopeSummary::body`),
4316
+ * which is byte-identical to this field but carries a stable
4317
+ * fingerprint for reconciliation. Kept on v2 emit so v1 consumers that
4318
+ * only look at `body` keep working.
4203
4319
  */
4204
4320
  body: string
4321
+ summary?: ReviewEnvelopeSummary
4205
4322
  /**
4206
4323
  * Per-line comments. Each is either a [`GitHubReviewComment`] or a
4207
4324
  * [`GitLabReviewComment`] depending on `meta.provider`.
4208
4325
  */
4209
4326
  comments: ReviewComment[]
4327
+ /**
4328
+ * Regex consumers run against every existing PR/MR comment body to
4329
+ * extract a fallow-emitted fingerprint marker. Capture group 1 is the
4330
+ * fingerprint string (a bare 16-char hex hash for single-finding
4331
+ * comments, or `<kind>:<16-char-hex>` for compositions such as
4332
+ * `merged:` for same-line collapsed comments).
4333
+ *
4334
+ * The pattern is anchored with `^` / `$` and relies on multiline
4335
+ * matching to anchor at line boundaries inside a multi-line comment
4336
+ * body. Multiline is NOT baked into the pattern via `(?m)` (which
4337
+ * JavaScript RegExp rejects as `Invalid group`); instead the consumer
4338
+ * passes [`Self::marker_regex_flags`] as the flags argument to its
4339
+ * regex engine. JavaScript: `new RegExp(env.marker_regex,
4340
+ * env.marker_regex_flags)`. Rust: `regex::RegexBuilder::new(pat)
4341
+ * .multi_line(flags.contains('m')).build()` (or any equivalent).
4342
+ */
4343
+ marker_regex?: string
4344
+ /**
4345
+ * Flags consumers pass alongside [`Self::marker_regex`] when
4346
+ * constructing their regex engine. Currently always `"m"` (multiline
4347
+ * so the anchored `^` / `$` match at every line boundary within a
4348
+ * comment body). Emitting flags as a separate field instead of
4349
+ * baking `(?m)` into the pattern keeps the wire compatible with
4350
+ * JavaScript RegExp, which rejects inline flag groups outside a
4351
+ * `(?flags:X)` grouping.
4352
+ */
4353
+ marker_regex_flags?: string
4210
4354
  meta: ReviewEnvelopeMeta
4211
4355
  }
4356
+ /**
4357
+ * Summary block on [`ReviewEnvelopeOutput`]. Always present on v2 emit;
4358
+ * `serde(default)` keeps schemars from marking it required so a future
4359
+ * Deserialize derivation against v1 historical input synthesizes an empty
4360
+ * value rather than erroring.
4361
+ */
4362
+ export interface ReviewEnvelopeSummary {
4363
+ /**
4364
+ * Markdown body of the summary. Byte-identical to the legacy top-level
4365
+ * [`ReviewEnvelopeOutput::body`] field; the duplication is intentional
4366
+ * so v1 consumers see no behavior change.
4367
+ */
4368
+ body: string
4369
+ /**
4370
+ * FNV-1a 64-bit hash (16 lowercase hex chars) of the summary body
4371
+ * BEFORE the trailing fallow-fingerprint marker line is appended.
4372
+ * (Computing the hash from the post-marker body would be circular:
4373
+ * the marker contains the fingerprint, so the fingerprint cannot
4374
+ * depend on the marker.) To reproduce from [`Self::body`], strip the
4375
+ * line matching [`ReviewEnvelopeOutput::marker_regex`] together with
4376
+ * its leading separator newlines and hash the remainder. Stable
4377
+ * across runs that produce the same summary content; consumers
4378
+ * upsert the sticky summary comment by matching this fingerprint
4379
+ * against the marker_regex extraction of every existing comment body.
4380
+ */
4381
+ fingerprint: string
4382
+ }
4212
4383
  /**
4213
4384
  * GitHub pull-request review comment.
4214
4385
  */
@@ -4229,8 +4400,30 @@ body: string
4229
4400
  /**
4230
4401
  * Stable fingerprint for the comment, used by `fallow ci
4231
4402
  * reconcile-review` to detect carryover comments across PR revisions.
4403
+ * For single-finding comments the value is a bare 16-char hex FNV-1a
4404
+ * hash. For merged comments (multiple findings on the same path:line)
4405
+ * the value is `merged:<16-char hex>` over the sorted constituent
4406
+ * fingerprints, so the identity shifts whenever constituent findings
4407
+ * change membership. Bundled wrappers and `fallow ci reconcile-review`
4408
+ * dedupe on this primary fingerprint only; consumers wanting
4409
+ * update-in-place reconciliation (preserving reviewer reply threads
4410
+ * across content changes) implement their own identity tracking via
4411
+ * `marker_regex`.
4232
4412
  */
4233
4413
  fingerprint: string
4414
+ /**
4415
+ * True when [`Self::body`] was truncated to fit a downstream provider's
4416
+ * note-size budget (today: 65,536 bytes). The body retains the closing
4417
+ * fallow-fingerprint marker so reconciliation continues to work after
4418
+ * truncation.
4419
+ *
4420
+ * Co-presence invariant: `truncated == true` always implies the body
4421
+ * contains an inline `<!-- fallow-truncated -->` HTML marker and the
4422
+ * `> Body truncated by fallow.` blockquote breadcrumb, and vice versa.
4423
+ * All three signals are emitted together; consumers may use any one
4424
+ * (the typed boolean is the authoritative machine-readable signal).
4425
+ */
4426
+ truncated?: boolean
4234
4427
  }
4235
4428
  /**
4236
4429
  * GitLab merge-request discussion comment.
@@ -4242,9 +4435,18 @@ export interface GitLabReviewComment {
4242
4435
  body: string
4243
4436
  position: GitLabReviewPosition
4244
4437
  /**
4245
- * Stable fingerprint for the comment.
4438
+ * Stable fingerprint for the comment. See
4439
+ * [`GitHubReviewComment::fingerprint`] for the single vs `merged:`
4440
+ * shape contract; semantics are identical across providers.
4246
4441
  */
4247
4442
  fingerprint: string
4443
+ /**
4444
+ * True when [`Self::body`] was truncated to fit GitLab's note-size
4445
+ * budget. See [`GitHubReviewComment::truncated`] for the full
4446
+ * co-presence invariant with the inline HTML marker and human
4447
+ * blockquote breadcrumb.
4448
+ */
4449
+ truncated?: boolean
4248
4450
  }
4249
4451
  /**
4250
4452
  * `position` block inside [`GitLabReviewComment`]. Mirrors the GitLab
@@ -4796,6 +4998,13 @@ groups?: (HealthGroup[] | null)
4796
4998
  * is passed (always present in MCP responses).
4797
4999
  */
4798
5000
  _meta?: (Meta | null)
5001
+ /**
5002
+ * Workspace-discovery diagnostics surfaced during config load
5003
+ * (issue #473). Mirror of [`CheckOutput::workspace_diagnostics`] so
5004
+ * stand-alone `fallow health --format json` consumers see the same
5005
+ * signal.
5006
+ */
5007
+ workspace_diagnostics?: WorkspaceDiagnostic[]
4799
5008
  }
4800
5009
  /**
4801
5010
  * A health report scoped to a single group.
@@ -4950,6 +5159,14 @@ groups?: (DuplicationGroup[] | null)
4950
5159
  * is passed (always present in MCP responses).
4951
5160
  */
4952
5161
  _meta?: (Meta | null)
5162
+ /**
5163
+ * Workspace-discovery diagnostics surfaced during config load
5164
+ * (issue #473). See [`CheckOutput::workspace_diagnostics`] for the full
5165
+ * contract; the same list is repeated on each top-level command's
5166
+ * envelope so single-command consumers see it without having to look at
5167
+ * a separate top-level field.
5168
+ */
5169
+ workspace_diagnostics?: WorkspaceDiagnostic[]
4953
5170
  }
4954
5171
  /**
4955
5172
  * A single grouped duplication bucket. Per-group `stats` are dedup-aware and
@@ -5187,6 +5404,15 @@ test_only_dependencies?: TestOnlyDependencyFinding[]
5187
5404
  * array natively.
5188
5405
  */
5189
5406
  circular_dependencies: CircularDependencyFinding[]
5407
+ /**
5408
+ * Cycles or self-loops in the re-export edge subgraph (barrel files
5409
+ * re-exporting from each other in a loop). Wrapped in
5410
+ * [`ReExportCycleFinding`] so each entry carries a typed `actions`
5411
+ * array natively (a `refactor-re-export-cycle` informational primary
5412
+ * plus a `suppress-file` secondary; cycles are file-scoped so a single
5413
+ * suppression breaks the cycle).
5414
+ */
5415
+ re_export_cycles?: ReExportCycleFinding[]
5190
5416
  /**
5191
5417
  * Imports that cross architecture boundary rules. Wrapped in
5192
5418
  * [`BoundaryViolationFinding`] so each entry carries a typed `actions`
@@ -5259,6 +5485,12 @@ export interface CombinedOutput {
5259
5485
  schema_version: SchemaVersion
5260
5486
  version: ToolVersion
5261
5487
  elapsed_ms: ElapsedMs
5488
+ /**
5489
+ * Sectioned `_meta` block emitted only when `--explain` is passed.
5490
+ * Contains `check`, `dupes`, and/or `health` keys matching the analyses
5491
+ * enabled for the combined run.
5492
+ */
5493
+ _meta?: (CombinedMeta | null)
5262
5494
  /**
5263
5495
  * Dead-code analysis sub-envelope. Absent when `--skip check`.
5264
5496
  */
@@ -5276,6 +5508,23 @@ dupes?: (DupesReportPayload | null)
5276
5508
  */
5277
5509
  health?: (HealthReport | null)
5278
5510
  }
5511
+ /**
5512
+ * Sectioned `_meta` block for the bare combined JSON envelope.
5513
+ */
5514
+ export interface CombinedMeta {
5515
+ /**
5516
+ * Dead-code metadata from `crate::explain::check_meta()`.
5517
+ */
5518
+ check?: (Meta | null)
5519
+ /**
5520
+ * Duplication metadata from `crate::explain::dupes_meta()`.
5521
+ */
5522
+ dupes?: (Meta | null)
5523
+ /**
5524
+ * Health metadata from `crate::explain::health_meta()`.
5525
+ */
5526
+ health?: (Meta | null)
5527
+ }
5279
5528
  /**
5280
5529
  * Single CodeClimate-compatible issue inside [`CodeClimateOutput`].
5281
5530
  */
@@ -5496,6 +5745,16 @@ export type MisconfiguredDependencyOverride = MisconfiguredDependencyOverrideFin
5496
5745
  */
5497
5746
  export type PrivateTypeLeak = PrivateTypeLeakFinding;
5498
5747
 
5748
+ /**
5749
+ * Backwards-compat alias for the pre-#384 bare `ReExportCycle` name.
5750
+ * The wire shape is byte-identical: `ReExportCycleFinding` flattens the bare
5751
+ * finding's fields via `#[serde(flatten)]` and adds `actions[]` plus
5752
+ * the optional audit-mode `introduced` flag. Consumers that imported
5753
+ * `ReExportCycle` from `fallow/types` pre-migration continue to work via
5754
+ * this alias; new code should prefer `ReExportCycleFinding`.
5755
+ */
5756
+ export type ReExportCycle = ReExportCycleFinding;
5757
+
5499
5758
  /**
5500
5759
  * Backwards-compat alias for the pre-#384 bare `TestOnlyDependency` name.
5501
5760
  * The wire shape is byte-identical: `TestOnlyDependencyFinding` flattens the bare