fallow 2.76.0 → 2.77.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
@@ -4199,16 +4305,75 @@ export interface ReviewEnvelopeOutput {
4199
4305
  */
4200
4306
  event?: (ReviewEnvelopeEvent | null)
4201
4307
  /**
4202
- * Review summary body (rendered above per-line comments).
4308
+ * Review summary body (rendered above per-line comments). Deprecated in
4309
+ * v2 envelopes: prefer [`summary.body`](`ReviewEnvelopeSummary::body`),
4310
+ * which is byte-identical to this field but carries a stable
4311
+ * fingerprint for reconciliation. Kept on v2 emit so v1 consumers that
4312
+ * only look at `body` keep working.
4203
4313
  */
4204
4314
  body: string
4315
+ summary?: ReviewEnvelopeSummary
4205
4316
  /**
4206
4317
  * Per-line comments. Each is either a [`GitHubReviewComment`] or a
4207
4318
  * [`GitLabReviewComment`] depending on `meta.provider`.
4208
4319
  */
4209
4320
  comments: ReviewComment[]
4321
+ /**
4322
+ * Regex consumers run against every existing PR/MR comment body to
4323
+ * extract a fallow-emitted fingerprint marker. Capture group 1 is the
4324
+ * fingerprint string (a bare 16-char hex hash for single-finding
4325
+ * comments, or `<kind>:<16-char-hex>` for compositions such as
4326
+ * `merged:` for same-line collapsed comments).
4327
+ *
4328
+ * The pattern is anchored with `^` / `$` and relies on multiline
4329
+ * matching to anchor at line boundaries inside a multi-line comment
4330
+ * body. Multiline is NOT baked into the pattern via `(?m)` (which
4331
+ * JavaScript RegExp rejects as `Invalid group`); instead the consumer
4332
+ * passes [`Self::marker_regex_flags`] as the flags argument to its
4333
+ * regex engine. JavaScript: `new RegExp(env.marker_regex,
4334
+ * env.marker_regex_flags)`. Rust: `regex::RegexBuilder::new(pat)
4335
+ * .multi_line(flags.contains('m')).build()` (or any equivalent).
4336
+ */
4337
+ marker_regex?: string
4338
+ /**
4339
+ * Flags consumers pass alongside [`Self::marker_regex`] when
4340
+ * constructing their regex engine. Currently always `"m"` (multiline
4341
+ * so the anchored `^` / `$` match at every line boundary within a
4342
+ * comment body). Emitting flags as a separate field instead of
4343
+ * baking `(?m)` into the pattern keeps the wire compatible with
4344
+ * JavaScript RegExp, which rejects inline flag groups outside a
4345
+ * `(?flags:X)` grouping.
4346
+ */
4347
+ marker_regex_flags?: string
4210
4348
  meta: ReviewEnvelopeMeta
4211
4349
  }
4350
+ /**
4351
+ * Summary block on [`ReviewEnvelopeOutput`]. Always present on v2 emit;
4352
+ * `serde(default)` keeps schemars from marking it required so a future
4353
+ * Deserialize derivation against v1 historical input synthesizes an empty
4354
+ * value rather than erroring.
4355
+ */
4356
+ export interface ReviewEnvelopeSummary {
4357
+ /**
4358
+ * Markdown body of the summary. Byte-identical to the legacy top-level
4359
+ * [`ReviewEnvelopeOutput::body`] field; the duplication is intentional
4360
+ * so v1 consumers see no behavior change.
4361
+ */
4362
+ body: string
4363
+ /**
4364
+ * FNV-1a 64-bit hash (16 lowercase hex chars) of the summary body
4365
+ * BEFORE the trailing fallow-fingerprint marker line is appended.
4366
+ * (Computing the hash from the post-marker body would be circular:
4367
+ * the marker contains the fingerprint, so the fingerprint cannot
4368
+ * depend on the marker.) To reproduce from [`Self::body`], strip the
4369
+ * line matching [`ReviewEnvelopeOutput::marker_regex`] together with
4370
+ * its leading separator newlines and hash the remainder. Stable
4371
+ * across runs that produce the same summary content; consumers
4372
+ * upsert the sticky summary comment by matching this fingerprint
4373
+ * against the marker_regex extraction of every existing comment body.
4374
+ */
4375
+ fingerprint: string
4376
+ }
4212
4377
  /**
4213
4378
  * GitHub pull-request review comment.
4214
4379
  */
@@ -4229,8 +4394,30 @@ body: string
4229
4394
  /**
4230
4395
  * Stable fingerprint for the comment, used by `fallow ci
4231
4396
  * reconcile-review` to detect carryover comments across PR revisions.
4397
+ * For single-finding comments the value is a bare 16-char hex FNV-1a
4398
+ * hash. For merged comments (multiple findings on the same path:line)
4399
+ * the value is `merged:<16-char hex>` over the sorted constituent
4400
+ * fingerprints, so the identity shifts whenever constituent findings
4401
+ * change membership. Bundled wrappers and `fallow ci reconcile-review`
4402
+ * dedupe on this primary fingerprint only; consumers wanting
4403
+ * update-in-place reconciliation (preserving reviewer reply threads
4404
+ * across content changes) implement their own identity tracking via
4405
+ * `marker_regex`.
4232
4406
  */
4233
4407
  fingerprint: string
4408
+ /**
4409
+ * True when [`Self::body`] was truncated to fit a downstream provider's
4410
+ * note-size budget (today: 65,536 bytes). The body retains the closing
4411
+ * fallow-fingerprint marker so reconciliation continues to work after
4412
+ * truncation.
4413
+ *
4414
+ * Co-presence invariant: `truncated == true` always implies the body
4415
+ * contains an inline `<!-- fallow-truncated -->` HTML marker and the
4416
+ * `> Body truncated by fallow.` blockquote breadcrumb, and vice versa.
4417
+ * All three signals are emitted together; consumers may use any one
4418
+ * (the typed boolean is the authoritative machine-readable signal).
4419
+ */
4420
+ truncated?: boolean
4234
4421
  }
4235
4422
  /**
4236
4423
  * GitLab merge-request discussion comment.
@@ -4242,9 +4429,18 @@ export interface GitLabReviewComment {
4242
4429
  body: string
4243
4430
  position: GitLabReviewPosition
4244
4431
  /**
4245
- * Stable fingerprint for the comment.
4432
+ * Stable fingerprint for the comment. See
4433
+ * [`GitHubReviewComment::fingerprint`] for the single vs `merged:`
4434
+ * shape contract; semantics are identical across providers.
4246
4435
  */
4247
4436
  fingerprint: string
4437
+ /**
4438
+ * True when [`Self::body`] was truncated to fit GitLab's note-size
4439
+ * budget. See [`GitHubReviewComment::truncated`] for the full
4440
+ * co-presence invariant with the inline HTML marker and human
4441
+ * blockquote breadcrumb.
4442
+ */
4443
+ truncated?: boolean
4248
4444
  }
4249
4445
  /**
4250
4446
  * `position` block inside [`GitLabReviewComment`]. Mirrors the GitLab
@@ -4796,6 +4992,13 @@ groups?: (HealthGroup[] | null)
4796
4992
  * is passed (always present in MCP responses).
4797
4993
  */
4798
4994
  _meta?: (Meta | null)
4995
+ /**
4996
+ * Workspace-discovery diagnostics surfaced during config load
4997
+ * (issue #473). Mirror of [`CheckOutput::workspace_diagnostics`] so
4998
+ * stand-alone `fallow health --format json` consumers see the same
4999
+ * signal.
5000
+ */
5001
+ workspace_diagnostics?: WorkspaceDiagnostic[]
4799
5002
  }
4800
5003
  /**
4801
5004
  * A health report scoped to a single group.
@@ -4950,6 +5153,14 @@ groups?: (DuplicationGroup[] | null)
4950
5153
  * is passed (always present in MCP responses).
4951
5154
  */
4952
5155
  _meta?: (Meta | null)
5156
+ /**
5157
+ * Workspace-discovery diagnostics surfaced during config load
5158
+ * (issue #473). See [`CheckOutput::workspace_diagnostics`] for the full
5159
+ * contract; the same list is repeated on each top-level command's
5160
+ * envelope so single-command consumers see it without having to look at
5161
+ * a separate top-level field.
5162
+ */
5163
+ workspace_diagnostics?: WorkspaceDiagnostic[]
4953
5164
  }
4954
5165
  /**
4955
5166
  * A single grouped duplication bucket. Per-group `stats` are dedup-aware and
@@ -5187,6 +5398,15 @@ test_only_dependencies?: TestOnlyDependencyFinding[]
5187
5398
  * array natively.
5188
5399
  */
5189
5400
  circular_dependencies: CircularDependencyFinding[]
5401
+ /**
5402
+ * Cycles or self-loops in the re-export edge subgraph (barrel files
5403
+ * re-exporting from each other in a loop). Wrapped in
5404
+ * [`ReExportCycleFinding`] so each entry carries a typed `actions`
5405
+ * array natively (a `refactor-re-export-cycle` informational primary
5406
+ * plus a `suppress-file` secondary; cycles are file-scoped so a single
5407
+ * suppression breaks the cycle).
5408
+ */
5409
+ re_export_cycles?: ReExportCycleFinding[]
5190
5410
  /**
5191
5411
  * Imports that cross architecture boundary rules. Wrapped in
5192
5412
  * [`BoundaryViolationFinding`] so each entry carries a typed `actions`
@@ -5496,6 +5716,16 @@ export type MisconfiguredDependencyOverride = MisconfiguredDependencyOverrideFin
5496
5716
  */
5497
5717
  export type PrivateTypeLeak = PrivateTypeLeakFinding;
5498
5718
 
5719
+ /**
5720
+ * Backwards-compat alias for the pre-#384 bare `ReExportCycle` name.
5721
+ * The wire shape is byte-identical: `ReExportCycleFinding` flattens the bare
5722
+ * finding's fields via `#[serde(flatten)]` and adds `actions[]` plus
5723
+ * the optional audit-mode `introduced` flag. Consumers that imported
5724
+ * `ReExportCycle` from `fallow/types` pre-migration continue to work via
5725
+ * this alias; new code should prefer `ReExportCycleFinding`.
5726
+ */
5727
+ export type ReExportCycle = ReExportCycleFinding;
5728
+
5499
5729
  /**
5500
5730
  * Backwards-compat alias for the pre-#384 bare `TestOnlyDependency` name.
5501
5731
  * The wire shape is byte-identical: `TestOnlyDependencyFinding` flattens the bare