@savvy-web/silk-effects 7.1.4 → 7.3.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.
package/README.md CHANGED
@@ -181,6 +181,7 @@ The Silk husky hooks are data. `SavvySections` supplies the section identities a
181
181
 
182
182
  - `SavvyBaseSection` is the shared preamble's identity (key `SAVVY-BASE`); pair it with `savvyBasePreamble()`, which defines `ROOT`, the `in_ci` predicate, `PM` via package-manager detection and `pm_exec`.
183
183
  - `SavvyHooksSection` (key `SAVVY-HOOKS`) pairs with `savvyHooksHygiene()`, a self-guarded repo-hygiene block that runs outside CI.
184
+ - `SavvyToolchainSection` (key `SAVVY-TOOLCHAIN`) pairs with `savvyToolchainCheck()`, a self-guarded block that warns when the running package manager has drifted off the repo's `devEngines.packageManager` pin. Warn only — it never blocks and never installs anything. It is self-contained (its hooks carry no `savvy-base` preamble), honours the manager named in the pin rather than assuming pnpm, strips the `+sha512…` integrity tail, skips inexact pins, and says nothing under CI.
184
185
  - `savvyToolSection(toolName, command)` builds a consumer's one-line tool section whose content is exactly `in_ci || pm_exec <command>` — the command is appended verbatim, so shell tokens like `$ROOT` and `$1` survive into the output. A `savvy-base` section must come first in the same hook file, so pass both to `syncAll` in that order.
185
186
 
186
187
  ```typescript
@@ -42,6 +42,7 @@ import { ReleasePlanner, makeReleasePlannerTest } from "./services/release-plann
42
42
  import { SectionCategorySchema } from "./categories/types.js";
43
43
  import { CommitHashSchema, VersionTypeSchema } from "./schemas/git.js";
44
44
  import { ChangesetSchema, ChangesetSummarySchema, DependencyTypeSchema, DependencyUpdateSchema } from "./schemas/changeset.js";
45
+ import { CoexistingChangesetSchema, RegenDiffRowSchema, RegenPlanSchema, RegenResultSchema } from "./schemas/deps-regen.js";
45
46
  import { AppliedReleaseEntrySchema, AppliedReleaseSchema, BumpTypeSchema, ChangesetPreviewSchema, PendingChangesetSchema, PreviewReleaseSchema, VersionFileUpdateRecordSchema } from "./schemas/release-plan.js";
46
47
  import { ContentStructureRule as ContentStructureRule$1 } from "./markdownlint/rules/content-structure.js";
47
48
  import { DependencyTableFormatRule as DependencyTableFormatRule$1 } from "./markdownlint/rules/dependency-table-format.js";
@@ -72,6 +73,7 @@ var changesets_exports = /* @__PURE__ */ __exportAll({
72
73
  ChangesetValidationError: () => ChangesetValidationError,
73
74
  ClassificationReasonSchema: () => ClassificationReasonSchema,
74
75
  ClassificationSchema: () => ClassificationSchema,
76
+ CoexistingChangesetSchema: () => CoexistingChangesetSchema,
75
77
  CommitHashSchema: () => CommitHashSchema,
76
78
  ConfigInspector: () => ConfigInspector,
77
79
  ConfigurationError: () => ConfigurationError,
@@ -118,6 +120,9 @@ var changesets_exports = /* @__PURE__ */ __exportAll({
118
120
  PendingChangesetSchema: () => PendingChangesetSchema,
119
121
  PositiveInteger: () => PositiveInteger,
120
122
  PreviewReleaseSchema: () => PreviewReleaseSchema,
123
+ RegenDiffRowSchema: () => RegenDiffRowSchema,
124
+ RegenPlanSchema: () => RegenPlanSchema,
125
+ RegenResultSchema: () => RegenResultSchema,
121
126
  ReleasePlanError: () => ReleasePlanError,
122
127
  ReleasePlanner: () => ReleasePlanner,
123
128
  ReorderSectionsPlugin: () => ReorderSectionsPlugin,
@@ -157,4 +162,4 @@ var changesets_exports = /* @__PURE__ */ __exportAll({
157
162
  });
158
163
 
159
164
  //#endregion
160
- export { AggregateDependencyTablesPlugin, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysisSchema, BranchAnalyzer, BranchFileEntrySchema, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogTransformer, ChangesetIOError, ChangesetLinter, ChangesetOptionsSchema, ChangesetPreviewSchema, ChangesetSchema, ChangesetSummarySchema, ChangesetValidationError, ClassificationReasonSchema, ClassificationSchema, CommitHashSchema, ConfigInspector, ConfigurationError, ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, DependencyActionSchema, DependencyTable, DependencyTableFormatRule, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, DependencyTypeSchema, DependencyUpdateSchema, DepsRegen, DepsRegenDefault, FileStatusSchema, GitError, GitHubApiError, GitHubInfoSchema, GitHubService, GlobSchema, HeadingHierarchyRule, InspectedConfigSchema, IssueLinkRefsPlugin, IssueNumberSchema, JsonPathSchema, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema, MaintenanceNotePlugin, MaintenanceReasonSchema, MaintenanceTriggerSchema, MarkdownParseError, ContentStructureRule$1 as MarkdownlintContentStructureRule, DependencyTableFormatRule$1 as MarkdownlintDependencyTableFormatRule, HeadingHierarchyRule$1 as MarkdownlintHeadingHierarchyRule, RequiredSectionsRule$1 as MarkdownlintRequiredSectionsRule, UncategorizedContentRule$1 as MarkdownlintUncategorizedContentRule, MergeSectionsPlugin, NonEmptyString, NormalizeFormatPlugin, PackageScopeSchema, PackagesRecordSchema, PendingChangesetSchema, PositiveInteger, PreviewReleaseSchema, ReleasePlanError, ReleasePlanner, ReorderSectionsPlugin, RepoSchema, RequiredSectionsRule, ResolvedPackageScopeSchema, ResolvedVersionFileSchema, SectionCategorySchema, SilkChangesetPreset, SilkChangesetTransformPreset, SilkChangesetsRules, UncategorizedContentRule, UrlOrMarkdownLinkSchema, UsernameSchema, VERSION_RE, VersionFileConfigSchema, VersionFileError, VersionFileUpdateRecordSchema, VersionFiles, VersionFilesSchema, VersionOrEmptySchema, VersionTypeSchema, changelogFunctions, changesets_exports, computeWorkspaceDependencyDiffs, deriveMaintenanceReason, gitMergeBase, isPureDependencyChangeset, listPublishablePackageNames, makeBranchAnalyzerTest, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, parseChangesetPackages, serializeDependencyTableToMarkdown, vanillaChangelogFunctions };
165
+ export { AggregateDependencyTablesPlugin, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysisSchema, BranchAnalyzer, BranchFileEntrySchema, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogTransformer, ChangesetIOError, ChangesetLinter, ChangesetOptionsSchema, ChangesetPreviewSchema, ChangesetSchema, ChangesetSummarySchema, ChangesetValidationError, ClassificationReasonSchema, ClassificationSchema, CoexistingChangesetSchema, CommitHashSchema, ConfigInspector, ConfigurationError, ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, DependencyActionSchema, DependencyTable, DependencyTableFormatRule, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, DependencyTypeSchema, DependencyUpdateSchema, DepsRegen, DepsRegenDefault, FileStatusSchema, GitError, GitHubApiError, GitHubInfoSchema, GitHubService, GlobSchema, HeadingHierarchyRule, InspectedConfigSchema, IssueLinkRefsPlugin, IssueNumberSchema, JsonPathSchema, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema, MaintenanceNotePlugin, MaintenanceReasonSchema, MaintenanceTriggerSchema, MarkdownParseError, ContentStructureRule$1 as MarkdownlintContentStructureRule, DependencyTableFormatRule$1 as MarkdownlintDependencyTableFormatRule, HeadingHierarchyRule$1 as MarkdownlintHeadingHierarchyRule, RequiredSectionsRule$1 as MarkdownlintRequiredSectionsRule, UncategorizedContentRule$1 as MarkdownlintUncategorizedContentRule, MergeSectionsPlugin, NonEmptyString, NormalizeFormatPlugin, PackageScopeSchema, PackagesRecordSchema, PendingChangesetSchema, PositiveInteger, PreviewReleaseSchema, RegenDiffRowSchema, RegenPlanSchema, RegenResultSchema, ReleasePlanError, ReleasePlanner, ReorderSectionsPlugin, RepoSchema, RequiredSectionsRule, ResolvedPackageScopeSchema, ResolvedVersionFileSchema, SectionCategorySchema, SilkChangesetPreset, SilkChangesetTransformPreset, SilkChangesetsRules, UncategorizedContentRule, UrlOrMarkdownLinkSchema, UsernameSchema, VERSION_RE, VersionFileConfigSchema, VersionFileError, VersionFileUpdateRecordSchema, VersionFiles, VersionFilesSchema, VersionOrEmptySchema, VersionTypeSchema, changelogFunctions, changesets_exports, computeWorkspaceDependencyDiffs, deriveMaintenanceReason, gitMergeBase, isPureDependencyChangeset, listPublishablePackageNames, makeBranchAnalyzerTest, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, parseChangesetPackages, serializeDependencyTableToMarkdown, vanillaChangelogFunctions };
@@ -0,0 +1,78 @@
1
+ import { NonEmptyString } from "./primitives.js";
2
+ import { DependencyActionSchema, DependencyTableTypeSchema } from "./dependency-table.js";
3
+ import { Schema } from "effect";
4
+
5
+ //#region src/changesets/schemas/deps-regen.ts
6
+ /**
7
+ * Result schemas for DepsRegen: the side-effect-free regen plan and the result
8
+ * of applying it.
9
+ *
10
+ */
11
+ const RegenDeleteEntrySchema = Schema.Struct({
12
+ file: Schema.String,
13
+ package: Schema.String
14
+ }).annotate({ identifier: "RegenDeleteEntry" });
15
+ /**
16
+ * One dependency-diff row emitted by the deps-regen planner.
17
+ *
18
+ * @remarks
19
+ * `computeWorkspaceDependencyDiffs` intentionally falls back to raw unresolved
20
+ * specifier strings (`*`, `>=5.7.0`, `^1.2`, `latest`, etc.). This in-memory
21
+ * plan schema therefore accepts any non-empty `from`/`to` cell instead of the
22
+ * stricter changelog-table version pattern.
23
+ *
24
+ * @public
25
+ */
26
+ const RegenDiffRowSchema = Schema.Struct({
27
+ dependency: NonEmptyString,
28
+ type: DependencyTableTypeSchema,
29
+ action: DependencyActionSchema,
30
+ from: NonEmptyString,
31
+ to: NonEmptyString
32
+ }).annotate({ identifier: "RegenDiffRow" });
33
+ const WorkspaceDependencyDiffPayloadSchema = Schema.Struct({
34
+ package: Schema.String,
35
+ relativePath: Schema.String,
36
+ rows: Schema.Array(RegenDiffRowSchema).check(Schema.isMinLength(1))
37
+ }).annotate({ identifier: "WorkspaceDependencyDiffPayload" });
38
+ const RegenWriteEntrySchema = Schema.Struct({
39
+ file: Schema.String,
40
+ package: Schema.String,
41
+ diff: WorkspaceDependencyDiffPayloadSchema
42
+ }).annotate({ identifier: "RegenWriteEntry" });
43
+ /**
44
+ * A prose-only changeset that coexists with a deps-regen run (informational).
45
+ *
46
+ * @public
47
+ */
48
+ const CoexistingChangesetSchema = Schema.Struct({
49
+ /** Absolute path of the untouched prose changeset. */
50
+ file: Schema.String,
51
+ /** In-scope packages released by this changeset's frontmatter. */
52
+ packages: Schema.Array(Schema.String)
53
+ }).annotate({ identifier: "CoexistingChangeset" });
54
+ /**
55
+ * Complete side-effect-free deps-regen plan.
56
+ *
57
+ * @public
58
+ */
59
+ const RegenPlanSchema = Schema.Struct({
60
+ toDelete: Schema.Array(RegenDeleteEntrySchema),
61
+ toWrite: Schema.Array(RegenWriteEntrySchema),
62
+ skippedMixed: Schema.Array(Schema.String),
63
+ coexisting: Schema.Array(CoexistingChangesetSchema)
64
+ }).annotate({ identifier: "RegenPlan" });
65
+ /**
66
+ * Result of applying a {@link RegenPlan}.
67
+ *
68
+ * @public
69
+ */
70
+ const RegenResultSchema = Schema.Struct({
71
+ deleted: Schema.Array(Schema.String),
72
+ written: Schema.Array(Schema.String),
73
+ skippedMixed: Schema.Array(Schema.String),
74
+ coexisting: Schema.Array(CoexistingChangesetSchema)
75
+ }).annotate({ identifier: "RegenResult" });
76
+
77
+ //#endregion
78
+ export { CoexistingChangesetSchema, RegenDiffRowSchema, RegenPlanSchema, RegenResultSchema };
@@ -97,6 +97,8 @@ function makeReleasePlannerTest(fixed) {
97
97
  * either shells out through `npx` (network) or to an ambient binary, so a
98
98
  * fixture that names one passes or fails on what the machine happens to have
99
99
  * installed rather than on this rewrite.
100
+ *
101
+ * @internal
100
102
  */
101
103
  function withChangelogModules(config, changelogModules, phase) {
102
104
  const unformatted = {
@@ -117,7 +119,11 @@ function withChangelogModules(config, changelogModules, phase) {
117
119
  changelog: [changelogModules[configuredId], config.changelog[1]]
118
120
  });
119
121
  }
120
- /** Extract the `## <version>` block (down to the next H2 or EOF) from a changelog. */
122
+ /**
123
+ * Extract the `## <version>` block (down to the next H2 or EOF) from a changelog.
124
+ *
125
+ * @internal
126
+ */
121
127
  function extractVersionBlock(changelog, version) {
122
128
  const lines = changelog.split("\n");
123
129
  const start = lines.findIndex((l) => l.trim() === `## ${version}`);
package/index.d.ts CHANGED
@@ -3691,34 +3691,109 @@ declare class ChangesetConfig extends ChangesetConfig_base {
3691
3691
  static readonly layer: Layer.Layer<ChangesetConfig, never, ChangesetConfigReader>;
3692
3692
  }
3693
3693
  //#endregion
3694
- //#region src/changesets/utils/dep-diff.d.ts
3694
+ //#region src/changesets/schemas/deps-regen.d.ts
3695
3695
  /**
3696
- * A workspace package's worth of dependency-table rows.
3696
+ * One dependency-diff row emitted by the deps-regen planner.
3697
+ *
3698
+ * @remarks
3699
+ * `computeWorkspaceDependencyDiffs` intentionally falls back to raw unresolved
3700
+ * specifier strings (`*`, `>=5.7.0`, `^1.2`, `latest`, etc.). This in-memory
3701
+ * plan schema therefore accepts any non-empty `from`/`to` cell instead of the
3702
+ * stricter changelog-table version pattern.
3697
3703
  *
3698
3704
  * @public
3699
3705
  */
3700
- interface WorkspaceDependencyDiff {
3701
- /** The workspace package whose `package.json` changed. */
3702
- readonly package: string;
3703
- /** Repo-relative path of the package directory (taken from the `after` snapshot). */
3704
- readonly relativePath: string;
3705
- /** One row per dependency change, sorted by the existing `sortDependencyRows` convention. */
3706
- readonly rows: ReadonlyArray<DependencyTableRow>;
3707
- }
3706
+ declare const RegenDiffRowSchema: Schema.Struct<{
3707
+ readonly dependency: Schema.String;
3708
+ readonly type: Schema.Literals<readonly ["dependency", "devDependency", "peerDependency", "optionalDependency", "workspace", "config", "runtime", "packageManager"]>;
3709
+ readonly action: Schema.Literals<readonly ["added", "updated", "removed"]>;
3710
+ readonly from: Schema.String;
3711
+ readonly to: Schema.String;
3712
+ }>;
3708
3713
  /**
3709
- * Diff two workspace snapshots and return per-package dependency-table rows,
3710
- * comparing already-resolved specifier values per side.
3714
+ * One dependency-diff row emitted by the deps-regen planner.
3711
3715
  *
3712
- * @param before - Snapshot at the older ref (typically the merge base). A
3713
- * workspace package absent here reports every declared dep as `"added"`.
3714
- * @param after - Snapshot at the newer ref (typically the working tree).
3715
- * @returns One {@link WorkspaceDependencyDiff} entry per workspace package
3716
- * that has at least one row. Packages with no resolved-value changes are
3717
- * omitted.
3716
+ * @public
3717
+ */
3718
+ type RegenDiffRow = Schema.Schema.Type<typeof RegenDiffRowSchema>;
3719
+ /**
3720
+ * A prose-only changeset that coexists with a deps-regen run (informational).
3718
3721
  *
3719
3722
  * @public
3720
3723
  */
3721
- declare function computeWorkspaceDependencyDiffs(before: WorkspaceStateSnapshot, after: WorkspaceStateSnapshot): ReadonlyArray<WorkspaceDependencyDiff>;
3724
+ declare const CoexistingChangesetSchema: Schema.Struct<{
3725
+ /** Absolute path of the untouched prose changeset. */
3726
+ readonly file: Schema.String;
3727
+ /** In-scope packages released by this changeset's frontmatter. */
3728
+ readonly packages: Schema.$Array<Schema.String>;
3729
+ }>;
3730
+ /**
3731
+ * A prose-only changeset that coexists with a deps-regen run (informational).
3732
+ *
3733
+ * @public
3734
+ */
3735
+ type CoexistingChangeset = Schema.Schema.Type<typeof CoexistingChangesetSchema>;
3736
+ /**
3737
+ * Complete side-effect-free deps-regen plan.
3738
+ *
3739
+ * @public
3740
+ */
3741
+ declare const RegenPlanSchema: Schema.Struct<{
3742
+ readonly toDelete: Schema.$Array<Schema.Struct<{
3743
+ readonly file: Schema.String;
3744
+ readonly package: Schema.String;
3745
+ }>>;
3746
+ readonly toWrite: Schema.$Array<Schema.Struct<{
3747
+ readonly file: Schema.String;
3748
+ readonly package: Schema.String;
3749
+ readonly diff: Schema.Struct<{
3750
+ readonly package: Schema.String;
3751
+ readonly relativePath: Schema.String;
3752
+ readonly rows: Schema.$Array<Schema.Struct<{
3753
+ readonly dependency: Schema.String;
3754
+ readonly type: Schema.Literals<readonly ["dependency", "devDependency", "peerDependency", "optionalDependency", "workspace", "config", "runtime", "packageManager"]>;
3755
+ readonly action: Schema.Literals<readonly ["added", "updated", "removed"]>;
3756
+ readonly from: Schema.String;
3757
+ readonly to: Schema.String;
3758
+ }>>;
3759
+ }>;
3760
+ }>>;
3761
+ readonly skippedMixed: Schema.$Array<Schema.String>;
3762
+ readonly coexisting: Schema.$Array<Schema.Struct<{
3763
+ /** Absolute path of the untouched prose changeset. */
3764
+ readonly file: Schema.String;
3765
+ /** In-scope packages released by this changeset's frontmatter. */
3766
+ readonly packages: Schema.$Array<Schema.String>;
3767
+ }>>;
3768
+ }>;
3769
+ /**
3770
+ * Complete side-effect-free deps-regen plan.
3771
+ *
3772
+ * @public
3773
+ */
3774
+ type RegenPlan = Schema.Schema.Type<typeof RegenPlanSchema>;
3775
+ /**
3776
+ * Result of applying a {@link RegenPlan}.
3777
+ *
3778
+ * @public
3779
+ */
3780
+ declare const RegenResultSchema: Schema.Struct<{
3781
+ readonly deleted: Schema.$Array<Schema.String>;
3782
+ readonly written: Schema.$Array<Schema.String>;
3783
+ readonly skippedMixed: Schema.$Array<Schema.String>;
3784
+ readonly coexisting: Schema.$Array<Schema.Struct<{
3785
+ /** Absolute path of the untouched prose changeset. */
3786
+ readonly file: Schema.String;
3787
+ /** In-scope packages released by this changeset's frontmatter. */
3788
+ readonly packages: Schema.$Array<Schema.String>;
3789
+ }>>;
3790
+ }>;
3791
+ /**
3792
+ * Result of applying a {@link RegenPlan}.
3793
+ *
3794
+ * @public
3795
+ */
3796
+ type RegenResult = Schema.Schema.Type<typeof RegenResultSchema>;
3722
3797
  //#endregion
3723
3798
  //#region src/changesets/services/deps-regen.d.ts
3724
3799
  /**
@@ -3749,58 +3824,6 @@ declare function isPureDependencyChangeset(content: string): {
3749
3824
  * @public
3750
3825
  */
3751
3826
  declare function parseChangesetPackages(content: string): ReadonlyArray<string>;
3752
- /**
3753
- * A prose-only changeset that coexists with the run: it releases at least one
3754
- * package in scope for this run but was left untouched because it carries no
3755
- * `## Dependencies` section. Purely informational (#279) — surfaced so the
3756
- * regen/detect result accounts for every changeset touching an in-scope
3757
- * package, instead of leaving prose entries invisible and forcing a manual
3758
- * `.changeset/` cross-check.
3759
- *
3760
- * @public
3761
- */
3762
- interface CoexistingChangeset {
3763
- /** Absolute path of the untouched prose changeset. */
3764
- readonly file: string;
3765
- /** The in-scope packages its frontmatter releases (out-of-scope names are dropped). */
3766
- readonly packages: ReadonlyArray<string>;
3767
- }
3768
- /**
3769
- * A complete, side-effect-free regen plan: which stale pure-dependency
3770
- * changesets to delete, which fresh changesets to write (carrying the
3771
- * already-resolved diff), which mixed changesets were left untouched, and
3772
- * which coexisting prose changesets reference in-scope packages.
3773
- *
3774
- * @public
3775
- */
3776
- interface RegenPlan {
3777
- readonly toDelete: ReadonlyArray<{
3778
- readonly file: string;
3779
- readonly package: string;
3780
- }>;
3781
- readonly toWrite: ReadonlyArray<{
3782
- readonly file: string;
3783
- readonly package: string;
3784
- readonly diff: WorkspaceDependencyDiff;
3785
- }>;
3786
- readonly skippedMixed: ReadonlyArray<string>;
3787
- /** Informational: untouched prose changesets releasing in-scope packages (#279). */
3788
- readonly coexisting: ReadonlyArray<CoexistingChangeset>;
3789
- }
3790
- /**
3791
- * The result of applying a {@link RegenPlan}: the files actually deleted
3792
- * and written, plus the mixed changesets that were skipped and the
3793
- * coexisting prose changesets carried through from the plan.
3794
- *
3795
- * @public
3796
- */
3797
- interface RegenResult {
3798
- readonly deleted: ReadonlyArray<string>;
3799
- readonly written: ReadonlyArray<string>;
3800
- readonly skippedMixed: ReadonlyArray<string>;
3801
- /** Informational: untouched prose changesets releasing in-scope packages (#279). */
3802
- readonly coexisting: ReadonlyArray<CoexistingChangeset>;
3803
- }
3804
3827
  /**
3805
3828
  * Options for {@link DepsRegenShape.plan}.
3806
3829
  *
@@ -4764,6 +4787,35 @@ declare const LegacyVersionFilesSchema: Schema.$Array<Schema.Struct<{
4764
4787
  readonly package: Schema.optional<Schema.String>;
4765
4788
  }>>;
4766
4789
  //#endregion
4790
+ //#region src/changesets/utils/dep-diff.d.ts
4791
+ /**
4792
+ * A workspace package's worth of dependency-table rows.
4793
+ *
4794
+ * @public
4795
+ */
4796
+ interface WorkspaceDependencyDiff {
4797
+ /** The workspace package whose `package.json` changed. */
4798
+ readonly package: string;
4799
+ /** Repo-relative path of the package directory (taken from the `after` snapshot). */
4800
+ readonly relativePath: string;
4801
+ /** One row per dependency change, sorted by the existing `sortDependencyRows` convention. */
4802
+ readonly rows: ReadonlyArray<DependencyTableRow>;
4803
+ }
4804
+ /**
4805
+ * Diff two workspace snapshots and return per-package dependency-table rows,
4806
+ * comparing already-resolved specifier values per side.
4807
+ *
4808
+ * @param before - Snapshot at the older ref (typically the merge base). A
4809
+ * workspace package absent here reports every declared dep as `"added"`.
4810
+ * @param after - Snapshot at the newer ref (typically the working tree).
4811
+ * @returns One {@link WorkspaceDependencyDiff} entry per workspace package
4812
+ * that has at least one row. Packages with no resolved-value changes are
4813
+ * omitted.
4814
+ *
4815
+ * @public
4816
+ */
4817
+ declare function computeWorkspaceDependencyDiffs(before: WorkspaceStateSnapshot, after: WorkspaceStateSnapshot): ReadonlyArray<WorkspaceDependencyDiff>;
4818
+ //#endregion
4767
4819
  //#region src/changesets/utils/dependency-table.d.ts
4768
4820
  /**
4769
4821
  * Serialize dependency table rows to a markdown table string.
@@ -5794,7 +5846,7 @@ declare const RequiredSectionsRule: import("unified-lint-rule").Plugin<Root, unk
5794
5846
  //#region src/changesets/remark/rules/uncategorized-content.d.ts
5795
5847
  declare const UncategorizedContentRule: import("unified-lint-rule").Plugin<Root, unknown>;
5796
5848
  declare namespace index_d_exports {
5797
- export { AggregateDependencyTablesPlugin, AppliedRelease, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysis, BranchAnalysisSchema, BranchAnalyzer, BranchAnalyzerShape, BranchFileEntry, BranchFileEntrySchema, BumpType, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogServiceShape, ChangelogTransformer, Changeset, ChangesetIOError, ChangesetLinter, ChangesetOptions, ChangesetOptionsSchema, ChangesetPreview, ChangesetPreviewSchema, ChangesetSchema, ChangesetSummarySchema, ChangesetValidationError, Classification, ClassificationReason, ClassificationReasonSchema, ClassificationSchema, CoexistingChangeset, CommitHashSchema, ConfigInspector, ConfigInspectorShape, ConfigurationError, ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, DependencyAction, DependencyActionSchema, DependencyTable, DependencyTableFormatRule, DependencyTableRow, DependencyTableRowSchema, DependencyTableSchema, DependencyTableType, DependencyTableTypeSchema, DependencyType, DependencyTypeSchema, DependencyUpdate, DependencyUpdateSchema, DepsRegen, DepsRegenDefault, DepsRegenOptions, DepsRegenPlanError, DepsRegenShape, FileStatus, FileStatusSchema, GitError, GitHubApiError, GitHubCommitInfo, GitHubInfo, GitHubInfoSchema, GitHubService, GitHubServiceShape, GlobSchema, HeadingHierarchyRule, InspectedConfig, InspectedConfigSchema, IssueLinkRefsPlugin, IssueNumberSchema, JsonPathSchema, LegacyVersionFileConfig, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema, LintMessage, MaintenanceNoteOptions, MaintenanceNotePlugin, MaintenanceReason, MaintenanceReasonSchema, MaintenanceTrigger, MaintenanceTriggerSchema, MarkdownParseError, ContentStructureRule$1 as MarkdownlintContentStructureRule, DependencyTableFormatRule$1 as MarkdownlintDependencyTableFormatRule, HeadingHierarchyRule$1 as MarkdownlintHeadingHierarchyRule, RequiredSectionsRule$1 as MarkdownlintRequiredSectionsRule, UncategorizedContentRule$1 as MarkdownlintUncategorizedContentRule, MergeSectionsPlugin, NonEmptyString, NormalizeFormatPlugin, PackageScope, PackageScopeSchema, PackagesRecordSchema, PendingChangeset, PendingChangesetSchema, PositiveInteger, PreviewRelease, PreviewReleaseSchema, RegenPlan, RegenResult, ReleasePlanError, ReleasePlanner, ReleasePlannerShape, ReorderSectionsPlugin, RepoSchema, RequiredSectionsRule, ResolvedPackageScope, ResolvedPackageScopeSchema, ResolvedVersionFile, ResolvedVersionFileSchema, SectionCategory, SectionCategorySchema, SilkChangesetPreset, SilkChangesetTransformPreset, SilkChangesetsRules, TransformOptions, UncategorizedContentRule, UrlOrMarkdownLinkSchema, UsernameSchema, VERSION_RE, VersionFileConfig, VersionFileConfigSchema, VersionFileError, VersionFileUpdate, VersionFileUpdateRecordSchema, VersionFiles, VersionFilesSchema, VersionOrEmptySchema, VersionType, VersionTypeSchema, WorkspaceDependencyDiff, WorkspaceVersion, changelogFunctions, computeWorkspaceDependencyDiffs, deriveMaintenanceReason, gitMergeBase, isPureDependencyChangeset, listPublishablePackageNames, makeBranchAnalyzerTest, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, parseChangesetPackages, serializeDependencyTableToMarkdown, vanillaChangelogFunctions };
5849
+ export { AggregateDependencyTablesPlugin, AppliedRelease, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysis, BranchAnalysisSchema, BranchAnalyzer, BranchAnalyzerShape, BranchFileEntry, BranchFileEntrySchema, BumpType, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogServiceShape, ChangelogTransformer, Changeset, ChangesetIOError, ChangesetLinter, ChangesetOptions, ChangesetOptionsSchema, ChangesetPreview, ChangesetPreviewSchema, ChangesetSchema, ChangesetSummarySchema, ChangesetValidationError, Classification, ClassificationReason, ClassificationReasonSchema, ClassificationSchema, CoexistingChangeset, CoexistingChangesetSchema, CommitHashSchema, ConfigInspector, ConfigInspectorShape, ConfigurationError, ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, DependencyAction, DependencyActionSchema, DependencyTable, DependencyTableFormatRule, DependencyTableRow, DependencyTableRowSchema, DependencyTableSchema, DependencyTableType, DependencyTableTypeSchema, DependencyType, DependencyTypeSchema, DependencyUpdate, DependencyUpdateSchema, DepsRegen, DepsRegenDefault, DepsRegenOptions, DepsRegenPlanError, DepsRegenShape, FileStatus, FileStatusSchema, GitError, GitHubApiError, GitHubCommitInfo, GitHubInfo, GitHubInfoSchema, GitHubService, GitHubServiceShape, GlobSchema, HeadingHierarchyRule, InspectedConfig, InspectedConfigSchema, IssueLinkRefsPlugin, IssueNumberSchema, JsonPathSchema, LegacyVersionFileConfig, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema, LintMessage, MaintenanceNoteOptions, MaintenanceNotePlugin, MaintenanceReason, MaintenanceReasonSchema, MaintenanceTrigger, MaintenanceTriggerSchema, MarkdownParseError, ContentStructureRule$1 as MarkdownlintContentStructureRule, DependencyTableFormatRule$1 as MarkdownlintDependencyTableFormatRule, HeadingHierarchyRule$1 as MarkdownlintHeadingHierarchyRule, RequiredSectionsRule$1 as MarkdownlintRequiredSectionsRule, UncategorizedContentRule$1 as MarkdownlintUncategorizedContentRule, MergeSectionsPlugin, NonEmptyString, NormalizeFormatPlugin, PackageScope, PackageScopeSchema, PackagesRecordSchema, PendingChangeset, PendingChangesetSchema, PositiveInteger, PreviewRelease, PreviewReleaseSchema, RegenDiffRow, RegenDiffRowSchema, RegenPlan, RegenPlanSchema, RegenResult, RegenResultSchema, ReleasePlanError, ReleasePlanner, ReleasePlannerShape, ReorderSectionsPlugin, RepoSchema, RequiredSectionsRule, ResolvedPackageScope, ResolvedPackageScopeSchema, ResolvedVersionFile, ResolvedVersionFileSchema, SectionCategory, SectionCategorySchema, SilkChangesetPreset, SilkChangesetTransformPreset, SilkChangesetsRules, TransformOptions, UncategorizedContentRule, UrlOrMarkdownLinkSchema, UsernameSchema, VERSION_RE, VersionFileConfig, VersionFileConfigSchema, VersionFileError, VersionFileUpdate, VersionFileUpdateRecordSchema, VersionFiles, VersionFilesSchema, VersionOrEmptySchema, VersionType, VersionTypeSchema, WorkspaceDependencyDiff, WorkspaceVersion, changelogFunctions, computeWorkspaceDependencyDiffs, deriveMaintenanceReason, gitMergeBase, isPureDependencyChangeset, listPublishablePackageNames, makeBranchAnalyzerTest, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, parseChangesetPackages, serializeDependencyTableToMarkdown, vanillaChangelogFunctions };
5798
5850
  }
5799
5851
  //#endregion
5800
5852
  //#region src/commitlint/config/schema.d.ts
@@ -9861,6 +9913,43 @@ declare function savvyHooksHygiene(): string;
9861
9913
  * @public
9862
9914
  */
9863
9915
  declare function savvyToolSection(toolName: string, command: string): Section;
9916
+ /**
9917
+ * Section identity for the package-manager toolchain drift check.
9918
+ *
9919
+ * `toolName` is `"savvy-toolchain"`; pair with {@link savvyToolchainCheck}.
9920
+ *
9921
+ * @since 7.3.0
9922
+ * @public
9923
+ */
9924
+ declare const SavvyToolchainSection: SectionId;
9925
+ /**
9926
+ * Package-manager drift check shared across Silk Suite hook files.
9927
+ *
9928
+ * @remarks
9929
+ * Compares the running package manager's version against the repo's
9930
+ * `devEngines.packageManager` pin and prints a warning on mismatch. **Warn only** —
9931
+ * it never blocks the hook and never installs anything, so nobody mid-bisect or
9932
+ * mid-rebase on an older pin is stranded.
9933
+ *
9934
+ * Deliberately self-contained: its homes are `.husky/post-checkout` and
9935
+ * `.husky/post-merge`, which carry {@link SavvyHooksSection} but no
9936
+ * {@link SavvyBaseSection}, so it defines its own root/CI/pin lookups rather than
9937
+ * depending on `ROOT`, `in_ci` or `PM`. It honours the `name` recorded in the pin
9938
+ * rather than assuming pnpm.
9939
+ *
9940
+ * Every input is treated as optional: no `git` root, no `jq`, no `devEngines` block,
9941
+ * or a package manager that is not on `PATH` all mean "say nothing". Only an exact
9942
+ * pin is comparable, so ranges (`^1.2.3`, `>=1 || <2`) and wildcards (`1.x`) are
9943
+ * skipped, and the `+sha512…` integrity tail `devEngines` versions routinely carry is
9944
+ * stripped before comparison. Skipped under CI, where the runtime action installs the
9945
+ * pin by construction.
9946
+ *
9947
+ * @returns The drift-check shell, with no surrounding markers or trailing newline.
9948
+ *
9949
+ * @since 7.3.0
9950
+ * @public
9951
+ */
9952
+ declare function savvyToolchainCheck(): string;
9864
9953
  //#endregion
9865
9954
  //#region src/schemas/WorkspaceAnalysisSchemas.d.ts
9866
9955
  declare const SilkPublishConfig_base: Schema.Class<SilkPublishConfig, Schema.Struct<{
@@ -10796,5 +10885,5 @@ declare namespace index_d_exports$5 {
10796
10885
  export { AffectedResult, AffectedResultType, CacheDiagnosis, CacheDiagnosisType, DryRunParseError, GlobalHashSummary, GraphNode, MissExplanation, NotATurboRepoError, PackageCacheStatus, TaskGraphResult, TaskGraphResultType, TurboCache, TurboDigest, TurboDryRun, TurboDryRunType, TurboDryTask, TurboDryTaskType, TurboEnvVars, TurboError, TurboExecError, TurboGlobalCacheInputs, TurboInspector, TurboInspectorShape, TurboNotInstalledError };
10797
10886
  }
10798
10887
  //#endregion
10799
- export { AnalyzedWorkspace, BiomeSchemaSync, type BiomeSchemaSyncShape, BiomeSyncError, type BiomeSyncOptions, type BiomeSyncResult, ChangesetConfig, ChangesetConfigError, type ChangesetConfigFile, ChangesetConfigReader, type ChangesetConfigReaderShape, type ChangesetConfigShape, type ChangesetMode, index_d_exports as Changesets, index_d_exports$1 as Commitlint, type CommitlintPlugin, type CommitlintUserConfig, ConfigDiscovery, type ConfigDiscoveryOptions, type ConfigDiscoveryShape, type ConfigLocation, ConfigNotFoundError, type ConfigSource, index_d_exports$2 as Lint, index_d_exports$3 as PrBody, type PromptConfig, type PromptSettings, PublishTargetBindingError, type PublishablePackage, type RawPackageJson, type RawPublishConfig, type RawPublishTargets, type RawTargetObject, type RawTargetValue, index_d_exports$4 as Repos, type RuleApplicability, type RuleConfigTuple, type RuleSeverity, type RulesConfig, SavvyBaseSection, SavvyHooksSection, type SilkChangesetConfigFile, SilkPublishConfig, SilkPublishability, SilkWorkspaceAnalyzer, type SilkWorkspaceAnalyzerShape, type TargetBinding, type TargetGroupBinding, type TargetsBinding, index_d_exports$5 as Turbo, WorkspaceAnalysis, WorkspaceAnalysisError, buildSchemaUrl, extractSemver, readTargetsBinding, savvyBasePreamble, savvyHooksHygiene, savvyToolSection };
10888
+ export { AnalyzedWorkspace, BiomeSchemaSync, type BiomeSchemaSyncShape, BiomeSyncError, type BiomeSyncOptions, type BiomeSyncResult, ChangesetConfig, ChangesetConfigError, type ChangesetConfigFile, ChangesetConfigReader, type ChangesetConfigReaderShape, type ChangesetConfigShape, type ChangesetMode, index_d_exports as Changesets, index_d_exports$1 as Commitlint, type CommitlintPlugin, type CommitlintUserConfig, ConfigDiscovery, type ConfigDiscoveryOptions, type ConfigDiscoveryShape, type ConfigLocation, ConfigNotFoundError, type ConfigSource, index_d_exports$2 as Lint, index_d_exports$3 as PrBody, type PromptConfig, type PromptSettings, PublishTargetBindingError, type PublishablePackage, type RawPackageJson, type RawPublishConfig, type RawPublishTargets, type RawTargetObject, type RawTargetValue, index_d_exports$4 as Repos, type RuleApplicability, type RuleConfigTuple, type RuleSeverity, type RulesConfig, SavvyBaseSection, SavvyHooksSection, SavvyToolchainSection, type SilkChangesetConfigFile, SilkPublishConfig, SilkPublishability, SilkWorkspaceAnalyzer, type SilkWorkspaceAnalyzerShape, type TargetBinding, type TargetGroupBinding, type TargetsBinding, index_d_exports$5 as Turbo, WorkspaceAnalysis, WorkspaceAnalysisError, buildSchemaUrl, extractSemver, readTargetsBinding, savvyBasePreamble, savvyHooksHygiene, savvyToolSection, savvyToolchainCheck };
10800
10889
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { SavvyBaseSection, SavvyHooksSection, savvyBasePreamble, savvyHooksHygiene, savvyToolSection } from "./schemas/SavvySections.js";
1
+ import { SavvyBaseSection, SavvyHooksSection, SavvyToolchainSection, savvyBasePreamble, savvyHooksHygiene, savvyToolSection, savvyToolchainCheck } from "./schemas/SavvySections.js";
2
2
  import { ChangesetConfigError } from "./errors/ChangesetConfigError.js";
3
3
  import { ChangesetConfigReader } from "./services/ChangesetConfigReader.js";
4
4
  import { PublishTargetBindingError } from "./errors/PublishTargetBindingError.js";
@@ -18,4 +18,4 @@ import { ConfigDiscovery } from "./services/ConfigDiscovery.js";
18
18
  import { SilkWorkspaceAnalyzer } from "./services/SilkWorkspaceAnalyzer.js";
19
19
  import { turbo_exports } from "./turbo/index.js";
20
20
 
21
- export { AnalyzedWorkspace, BiomeSchemaSync, BiomeSyncError, ChangesetConfig, ChangesetConfigError, ChangesetConfigReader, changesets_exports as Changesets, commitlint_exports as Commitlint, ConfigDiscovery, ConfigNotFoundError, lint_exports as Lint, pr_body_exports as PrBody, PublishTargetBindingError, repos_exports as Repos, SavvyBaseSection, SavvyHooksSection, SilkPublishConfig, SilkPublishability, SilkWorkspaceAnalyzer, turbo_exports as Turbo, WorkspaceAnalysis, WorkspaceAnalysisError, buildSchemaUrl, extractSemver, readTargetsBinding, savvyBasePreamble, savvyHooksHygiene, savvyToolSection };
21
+ export { AnalyzedWorkspace, BiomeSchemaSync, BiomeSyncError, ChangesetConfig, ChangesetConfigError, ChangesetConfigReader, changesets_exports as Changesets, commitlint_exports as Commitlint, ConfigDiscovery, ConfigNotFoundError, lint_exports as Lint, pr_body_exports as PrBody, PublishTargetBindingError, repos_exports as Repos, SavvyBaseSection, SavvyHooksSection, SavvyToolchainSection, SilkPublishConfig, SilkPublishability, SilkWorkspaceAnalyzer, turbo_exports as Turbo, WorkspaceAnalysis, WorkspaceAnalysisError, buildSchemaUrl, extractSemver, readTargetsBinding, savvyBasePreamble, savvyHooksHygiene, savvyToolSection, savvyToolchainCheck };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/silk-effects",
3
- "version": "7.1.4",
3
+ "version": "7.3.0",
4
4
  "private": false,
5
5
  "description": "Shared Effect library for Silk Suite conventions",
6
6
  "homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk-effects",
@@ -130,6 +130,65 @@ fi`;
130
130
  function savvyToolSection(toolName, command) {
131
131
  return shellSection(toolName).section(`in_ci || pm_exec ${command}`);
132
132
  }
133
+ /**
134
+ * Section identity for the package-manager toolchain drift check.
135
+ *
136
+ * `toolName` is `"savvy-toolchain"`; pair with {@link savvyToolchainCheck}.
137
+ *
138
+ * @since 7.3.0
139
+ * @public
140
+ */
141
+ const SavvyToolchainSection = shellSection("savvy-toolchain");
142
+ /**
143
+ * Package-manager drift check shared across Silk Suite hook files.
144
+ *
145
+ * @remarks
146
+ * Compares the running package manager's version against the repo's
147
+ * `devEngines.packageManager` pin and prints a warning on mismatch. **Warn only** —
148
+ * it never blocks the hook and never installs anything, so nobody mid-bisect or
149
+ * mid-rebase on an older pin is stranded.
150
+ *
151
+ * Deliberately self-contained: its homes are `.husky/post-checkout` and
152
+ * `.husky/post-merge`, which carry {@link SavvyHooksSection} but no
153
+ * {@link SavvyBaseSection}, so it defines its own root/CI/pin lookups rather than
154
+ * depending on `ROOT`, `in_ci` or `PM`. It honours the `name` recorded in the pin
155
+ * rather than assuming pnpm.
156
+ *
157
+ * Every input is treated as optional: no `git` root, no `jq`, no `devEngines` block,
158
+ * or a package manager that is not on `PATH` all mean "say nothing". Only an exact
159
+ * pin is comparable, so ranges (`^1.2.3`, `>=1 || <2`) and wildcards (`1.x`) are
160
+ * skipped, and the `+sha512…` integrity tail `devEngines` versions routinely carry is
161
+ * stripped before comparison. Skipped under CI, where the runtime action installs the
162
+ * pin by construction.
163
+ *
164
+ * @returns The drift-check shell, with no surrounding markers or trailing newline.
165
+ *
166
+ * @since 7.3.0
167
+ * @public
168
+ */
169
+ function savvyToolchainCheck() {
170
+ return `if ! { [ -n "$CI" ] || [ -n "$GITHUB_ACTIONS" ]; }; then
171
+ toolchain_root=$(git rev-parse --show-toplevel 2>/dev/null)
172
+ toolchain_pm=""
173
+ toolchain_pin=""
174
+ if [ -n "$toolchain_root" ] && [ -f "$toolchain_root/package.json" ] && command -v jq >/dev/null 2>&1; then
175
+ toolchain_pm=$(jq -r '.devEngines.packageManager.name // empty' "$toolchain_root/package.json" 2>/dev/null)
176
+ toolchain_pin=$(jq -r '.devEngines.packageManager.version // empty' "$toolchain_root/package.json" 2>/dev/null | cut -d'+' -f1)
177
+ fi
178
+ # Only an exact pin is comparable: drop ranges (^ ~ >= ||) and wildcards (x, *).
179
+ case "$toolchain_pin" in ""|[!0-9]*|*[!0-9A-Za-z.-]*|*x*|*X*) toolchain_pin="" ;; esac
180
+ if [ -n "$toolchain_pm" ] && [ -n "$toolchain_pin" ] && command -v "$toolchain_pm" >/dev/null 2>&1; then
181
+ toolchain_have=$("$toolchain_pm" --version 2>/dev/null | head -n 1 | tr -d '[:space:]')
182
+ # A manager that failed or answered with prose says nothing about drift.
183
+ case "$toolchain_have" in [!0-9]*|*[!0-9A-Za-z.-]*) toolchain_have="" ;; esac
184
+ if [ -n "$toolchain_have" ] && [ "$toolchain_have" != "$toolchain_pin" ]; then
185
+ printf '⚠ %s %s does not match %s, the version pinned in devEngines.packageManager.\\n' "$toolchain_pm" "$toolchain_have" "$toolchain_pin" >&2
186
+ printf ' Lockfiles written by this version may differ from CI. Fix: corepack use %s@%s\\n' "$toolchain_pm" "$toolchain_pin" >&2
187
+ fi
188
+ fi
189
+ unset toolchain_root toolchain_pm toolchain_pin toolchain_have
190
+ fi`;
191
+ }
133
192
 
134
193
  //#endregion
135
- export { SavvyBaseSection, SavvyHooksSection, savvyBasePreamble, savvyHooksHygiene, savvyToolSection };
194
+ export { SavvyBaseSection, SavvyHooksSection, SavvyToolchainSection, savvyBasePreamble, savvyHooksHygiene, savvyToolSection, savvyToolchainCheck };
@@ -1,6 +1,6 @@
1
1
  import { BiomeSyncError } from "../errors/BiomeSyncError.js";
2
2
  import { Context, Effect, FileSystem, Layer } from "effect";
3
- import { Jsonc } from "@effected/jsonc";
3
+ import { Jsonc, JsoncEdit, JsoncModifier } from "@effected/jsonc";
4
4
 
5
5
  //#region src/services/BiomeSchemaSync.ts
6
6
  /**
@@ -28,6 +28,16 @@ function buildSchemaUrl(version) {
28
28
  return `https://biomejs.dev/schemas/${version}/schema.json`;
29
29
  }
30
30
  const BIOME_SCHEMA_HOSTNAME = "biomejs.dev";
31
+ function normalizeHostname(hostname) {
32
+ return hostname.toLowerCase().replace(/\.+$/, "");
33
+ }
34
+ function isBiomeSchemaUrl(schema) {
35
+ try {
36
+ return normalizeHostname(new URL(schema).hostname) === BIOME_SCHEMA_HOSTNAME;
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
31
41
  /** Check which biome config files exist in cwd. */
32
42
  function findBiomeConfigs(cwd, fs) {
33
43
  const candidates = [`${cwd}/biome.json`, `${cwd}/biome.jsonc`];
@@ -100,7 +110,7 @@ var BiomeSchemaSync = class extends Context.Service()("@savvy-web/silk-effects/B
100
110
  skipped.push(configPath);
101
111
  continue;
102
112
  }
103
- if (!schema.includes(BIOME_SCHEMA_HOSTNAME)) {
113
+ if (!isBiomeSchemaUrl(schema)) {
104
114
  skipped.push(configPath);
105
115
  continue;
106
116
  }
@@ -109,8 +119,14 @@ var BiomeSchemaSync = class extends Context.Service()("@savvy-web/silk-effects/B
109
119
  continue;
110
120
  }
111
121
  if (write) {
112
- const updated_content = raw.replaceAll(schema, expectedUrl);
113
- yield* fs.writeFileString(configPath, updated_content).pipe(Effect.mapError(
122
+ const updatedContent = yield* JsoncModifier.modify(raw, ["$schema"], expectedUrl).pipe(Effect.map((edits) => JsoncEdit.applyAll(raw, edits)), Effect.mapError(
123
+ /* v8 ignore next 4 -- error path requires a JSONC edit failure */
124
+ (error) => new BiomeSyncError({
125
+ path: configPath,
126
+ reason: `Failed to update JSONC: ${String(error)}`
127
+ })
128
+ ));
129
+ yield* fs.writeFileString(configPath, updatedContent).pipe(Effect.mapError(
114
130
  /* v8 ignore next 4 -- error path requires a filesystem write failure */
115
131
  (cause) => new BiomeSyncError({
116
132
  path: configPath,