@savvy-web/silk 3.2.1 → 3.2.2

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.
@@ -16907,7 +16907,7 @@ var Package = class Package extends Schema.Class("Package")({
16907
16907
  };
16908
16908
 
16909
16909
  //#endregion
16910
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspacePackage.js
16910
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspacePackage.js
16911
16911
  const EMPTY$1 = Object.freeze(Object.create(null));
16912
16912
  const EMPTY_MANIFEST = Object.freeze(Object.create(null));
16913
16913
  /**
@@ -17516,7 +17516,7 @@ const Walker$1 = {
17516
17516
  };
17517
17517
 
17518
17518
  //#endregion
17519
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceRoot.js
17519
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceRoot.js
17520
17520
  /**
17521
17521
  * The marker filenames {@link WorkspaceRoot} probes for, in priority order.
17522
17522
  *
@@ -17704,7 +17704,7 @@ var WorkspaceRoot = class WorkspaceRoot extends Context.Service()("@effected/wor
17704
17704
  };
17705
17705
 
17706
17706
  //#endregion
17707
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/limits.js
17707
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/limits.js
17708
17708
  /**
17709
17709
  * Hard ceiling on directories the enumerator will visit for one pattern set.
17710
17710
  * Guards the pathological case a depth cap alone does not: a wide, shallow
@@ -17723,7 +17723,7 @@ const MAX_ENUMERATION_ENTRIES = 1e5;
17723
17723
  const PRUNED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
17724
17724
 
17725
17725
  //#endregion
17726
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/traverse.js
17726
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/traverse.js
17727
17727
  /** Directory names never descended into. */
17728
17728
  const isPruned = (entry) => PRUNED_DIRECTORIES.has(entry);
17729
17729
  /** Join root-relative POSIX segments; `""` is the root itself. */
@@ -17814,7 +17814,7 @@ var Traversal = class {
17814
17814
  };
17815
17815
 
17816
17816
  //#endregion
17817
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/enumerate.js
17817
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/enumerate.js
17818
17818
  /** Strip a trailing slash from `GlobPattern.enumerationPrefix` to get a relative directory. */
17819
17819
  const baseOf = (pattern) => pattern.enumerationPrefix.replace(/\/$/, "");
17820
17820
  /**
@@ -17885,7 +17885,7 @@ const enumerate = (root, globs, options) => Effect.gen(function* () {
17885
17885
  });
17886
17886
 
17887
17887
  //#endregion
17888
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/patterns.js
17888
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/patterns.js
17889
17889
  const stringsOf = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : void 0;
17890
17890
  /** The `packages:` list of a `pnpm-workspace.yaml` document. Total on a parsed document. */
17891
17891
  const pnpmPatternsOf = (document) => {
@@ -17943,7 +17943,7 @@ const readPatterns = (root) => Effect.gen(function* () {
17943
17943
  });
17944
17944
 
17945
17945
  //#endregion
17946
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceDiscovery.js
17946
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceDiscovery.js
17947
17947
  /**
17948
17948
  * Raised when a workspace member's `package.json` cannot be read, parsed, or
17949
17949
  * used — it is missing, malformed, or lacks a `name` or `version`.
@@ -18378,7 +18378,7 @@ var WorkspaceDiscovery = class WorkspaceDiscovery extends Context.Service()("@ef
18378
18378
  const isStringRecord$2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string");
18379
18379
 
18380
18380
  //#endregion
18381
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/DependencyGraph.js
18381
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/DependencyGraph.js
18382
18382
  /**
18383
18383
  * Raised when the workspace dependency graph cannot be topologically ordered
18384
18384
  * because it contains a cycle.
@@ -19980,7 +19980,7 @@ var Git = class extends Context.Service()("@effected/git/Git") {
19980
19980
  };
19981
19981
 
19982
19982
  //#endregion
19983
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/ChangeDetector.js
19983
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/ChangeDetector.js
19984
19984
  /**
19985
19985
  * Which git refs to compare, and whether to fold in the working tree.
19986
19986
  *
@@ -20262,7 +20262,7 @@ function resolveFromCatalog(catalogs, wantedDependency) {
20262
20262
  }
20263
20263
 
20264
20264
  //#endregion
20265
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/catalogs.js
20265
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/catalogs.js
20266
20266
  /** Project a pnpm-workspace manifest's `catalog` / `catalogs` fields into a `Catalogs` map. */
20267
20267
  const inlineCatalogs = (manifest) => {
20268
20268
  if (manifest.catalog === void 0 && manifest.catalogs === void 0) return {};
@@ -20327,7 +20327,7 @@ const rangeOf = (catalogs, dependency, specifier) => {
20327
20327
  };
20328
20328
 
20329
20329
  //#endregion
20330
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/ConfigDependencyHooks.js
20330
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/ConfigDependencyHooks.js
20331
20331
  /** Whether `value` is a non-null, non-array object. */
20332
20332
  const isObject$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
20333
20333
  /**
@@ -20514,7 +20514,7 @@ var ConfigDependencyHooks = class ConfigDependencyHooks extends Context.Service(
20514
20514
  };
20515
20515
 
20516
20516
  //#endregion
20517
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/PackageManagerName.js
20517
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/PackageManagerName.js
20518
20518
  /**
20519
20519
  * The four package managers this package understands.
20520
20520
  *
@@ -20757,7 +20757,7 @@ var PackageManagerDetector = class PackageManagerDetector extends Context.Servic
20757
20757
  };
20758
20758
 
20759
20759
  //#endregion
20760
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/LockfileReader.js
20760
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/LockfileReader.js
20761
20761
  /**
20762
20762
  * Raised when the workspace's lockfile cannot be read off disk.
20763
20763
  *
@@ -20868,7 +20868,7 @@ var LockfileReader = class LockfileReader extends Context.Service()("@effected/w
20868
20868
  };
20869
20869
 
20870
20870
  //#endregion
20871
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/Publishability.js
20871
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/Publishability.js
20872
20872
  /** The public npm registry, used when `publishConfig.registry` says nothing. */
20873
20873
  const DEFAULT_REGISTRY = "https://registry.npmjs.org/";
20874
20874
  /**
@@ -20969,7 +20969,94 @@ var PublishabilityDetector = class PublishabilityDetector extends Context.Servic
20969
20969
  };
20970
20970
 
20971
20971
  //#endregion
20972
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceCatalogs.js
20972
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/importerVersions.js
20973
+ /**
20974
+ * Strip pnpm's peer-disambiguation suffix from a recorded importer version.
20975
+ *
20976
+ * pnpm records an importer version as the resolved version followed by the peer
20977
+ * context it was resolved under — `4.0.0-beta.101(effect@4.0.0-beta.101)(ioredis@5.11.1(supports-color@8.1.1))`.
20978
+ * `@effected/lockfiles` stores that string verbatim (its `packages:` key parser
20979
+ * strips the suffix; the importer entries deliberately keep it), so the raw
20980
+ * value must never reach a consumer's dependency table — it would render the
20981
+ * whole parenthesized chain as the "version" a dependency moved to.
20982
+ *
20983
+ * Everything from the first `(` is dropped; a version with no suffix passes
20984
+ * through untouched.
20985
+ */
20986
+ const stripPeerSuffix = (version) => {
20987
+ const paren = version.indexOf("(");
20988
+ return paren === -1 ? version : version.slice(0, paren);
20989
+ };
20990
+ /**
20991
+ * Whether a recorded importer version is a concrete version usable as a
20992
+ * resolution answer.
20993
+ *
20994
+ * A `link:` / `file:` entry records a filesystem edge rather than a version, and
20995
+ * an empty string is pnpm's "specifier only, nothing installed" marker. Both
20996
+ * would be worse than no answer at all: the fallback exists to report a concrete
20997
+ * version movement, and reporting `link:../foo` as a version is noise a
20998
+ * changeset would carry into release notes.
20999
+ */
21000
+ const isConcreteVersion = (version) => version.length > 0 && !version.startsWith("link:") && !version.startsWith("file:");
21001
+ /**
21002
+ * Build the importer-path → dependency-name → version index a snapshot uses to
21003
+ * answer `catalog:` specifiers its catalog set cannot resolve.
21004
+ *
21005
+ * @remarks
21006
+ * Keyed by **name only** within each importer, deliberately across every
21007
+ * dependency field. The bug this fixes is a peer declared `catalog:effect:peers`
21008
+ * whose importer records no `peerDependencies` entry at all — pnpm writes peer
21009
+ * declarations into the importer block only when they are also installed, so the
21010
+ * concrete version lives on the package's `devDependencies` row for the same
21011
+ * name. Joining by name across fields is what finds it; joining by field, or by
21012
+ * matching the recorded specifier, would not.
21013
+ *
21014
+ * Only pnpm populates importer versions; bun and npm record resolved versions on
21015
+ * their package entries instead, so those formats yield an empty index and the
21016
+ * fallback is inert for them.
21017
+ */
21018
+ const importerVersionsOf = (lockfile) => {
21019
+ const index = Object.create(null);
21020
+ for (const importer of lockfile.importers) {
21021
+ const versions = Object.create(null);
21022
+ for (const dependency of importer.dependencies) {
21023
+ const recorded = dependency.version;
21024
+ if (recorded === void 0) continue;
21025
+ const version = stripPeerSuffix(recorded);
21026
+ if (!isConcreteVersion(version)) continue;
21027
+ versions[dependency.name] ??= version;
21028
+ }
21029
+ index[importer.path] = versions;
21030
+ }
21031
+ return index;
21032
+ };
21033
+ /**
21034
+ * The version every importer agrees `dependency` resolved to, or `undefined`
21035
+ * when they disagree or none record it.
21036
+ *
21037
+ * @remarks
21038
+ * The unambiguity rule is what makes a workspace-wide answer safe from a
21039
+ * snapshot method that receives no importer context. Two packages in one
21040
+ * monorepo may legitimately hold different versions of the same dependency; in
21041
+ * that case there is no single correct answer, so this yields nothing and the
21042
+ * caller keeps today's behavior (no row) rather than inventing a wrong one.
21043
+ */
21044
+ const unanimousVersionOf = (index, dependency) => {
21045
+ let agreed;
21046
+ for (const versions of Object.values(index)) {
21047
+ const version = versions[dependency];
21048
+ if (version === void 0) continue;
21049
+ if (agreed === void 0) {
21050
+ agreed = version;
21051
+ continue;
21052
+ }
21053
+ if (agreed !== version) return void 0;
21054
+ }
21055
+ return agreed;
21056
+ };
21057
+
21058
+ //#endregion
21059
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceCatalogs.js
20973
21060
  /**
20974
21061
  * An immutable, fully-normalized catalog collection — the one catalog
20975
21062
  * resolution semantic in the package.
@@ -21288,7 +21375,15 @@ var WorkspaceCatalogs = class WorkspaceCatalogs extends Context.Service()("@effe
21288
21375
  }));
21289
21376
  const assemble = Effect.gen(function* () {
21290
21377
  const root = yield* Effect.suspend(() => roots.find(options?.cwd ?? process.cwd()));
21291
- const fromLockfile = yield* lockfiles.read().pipe(Effect.map(CatalogSet.fromLockfile), Effect.catch((_failure) => Effect.succeed(CatalogSet.empty())));
21378
+ const lockfileOutputs = yield* lockfiles.read().pipe(Effect.map((lockfile) => ({
21379
+ catalogs: CatalogSet.fromLockfile(lockfile),
21380
+ importerVersions: importerVersionsOf(lockfile)
21381
+ })), Effect.catch((_failure) => Effect.succeed({
21382
+ catalogs: CatalogSet.empty(),
21383
+ importerVersions: {}
21384
+ })));
21385
+ const fromLockfile = lockfileOutputs.catalogs;
21386
+ const importerVersions = lockfileOutputs.importerVersions;
21292
21387
  const workspaceYaml = path.join(root, "pnpm-workspace.yaml");
21293
21388
  const hasPnpmWorkspace = yield* probeExists(workspaceYaml);
21294
21389
  let inline;
@@ -21316,7 +21411,8 @@ var WorkspaceCatalogs = class WorkspaceCatalogs extends Context.Service()("@effe
21316
21411
  const manifestPath = path.join(root, "package.json");
21317
21412
  if (!(yield* probeExists(manifestPath))) return {
21318
21413
  catalogs: fromLockfile,
21319
- releaseAgeGate: ReleaseAgeGate.combine()
21414
+ releaseAgeGate: ReleaseAgeGate.combine(),
21415
+ importerVersions
21320
21416
  };
21321
21417
  const text = yield* fs.readFileString(manifestPath).pipe(Effect.mapError((cause) => new CatalogAssemblyError({
21322
21418
  source: "manifest",
@@ -21335,7 +21431,8 @@ var WorkspaceCatalogs = class WorkspaceCatalogs extends Context.Service()("@effe
21335
21431
  }));
21336
21432
  return {
21337
21433
  catalogs: assembled,
21338
- releaseAgeGate
21434
+ releaseAgeGate,
21435
+ importerVersions
21339
21436
  };
21340
21437
  });
21341
21438
  const [resolveOnce, invalidate] = yield* Effect.cachedInvalidateWithTTL(assemble, Duration.infinity);
@@ -21349,6 +21446,9 @@ var WorkspaceCatalogs = class WorkspaceCatalogs extends Context.Service()("@effe
21349
21446
  }),
21350
21447
  releaseAgeGate: Effect.fn("WorkspaceCatalogs.releaseAgeGate")(function* () {
21351
21448
  return (yield* memo).releaseAgeGate;
21449
+ }),
21450
+ importerVersions: Effect.fn("WorkspaceCatalogs.importerVersions")(function* () {
21451
+ return (yield* memo).importerVersions;
21352
21452
  })
21353
21453
  };
21354
21454
  });
@@ -21400,7 +21500,7 @@ var WorkspaceCatalogs = class WorkspaceCatalogs extends Context.Service()("@effe
21400
21500
  };
21401
21501
 
21402
21502
  //#endregion
21403
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceStateSnapshot.js
21503
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceStateSnapshot.js
21404
21504
  const EMPTY = Object.freeze(Object.create(null));
21405
21505
  const DependencyMap = Schema.Record(Schema.String, Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed(EMPTY)), Schema.withConstructorDefault(Effect.succeed(EMPTY)));
21406
21506
  /**
@@ -21484,7 +21584,19 @@ var WorkspaceStateSnapshot = class extends Schema.Class("WorkspaceStateSnapshot"
21484
21584
  /** Every workspace package captured at this moment. */
21485
21585
  packages: Schema.Array(PackageStateSnapshot),
21486
21586
  /** The catalog set assembled at this moment. */
21487
- catalogs: CatalogSet
21587
+ catalogs: CatalogSet,
21588
+ /**
21589
+ * Each importer's dependency-name → resolved-version map, as the manager's
21590
+ * lockfile recorded it at this moment.
21591
+ *
21592
+ * @remarks
21593
+ * Defaults to `{}`, so a `WorkspaceStateSnapshot` serialized before this field
21594
+ * existed still decodes — and an empty index simply makes the `catalog:`
21595
+ * fallback in {@link WorkspaceStateSnapshot.resolve} inert, which is exactly
21596
+ * the behavior those older values were captured under. Only pnpm records
21597
+ * importer versions; bun and npm yield an empty index.
21598
+ */
21599
+ importerVersions: Schema.optionalKey(Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.String)))
21488
21600
  }) {
21489
21601
  #versionIndex;
21490
21602
  #packageIndex;
@@ -21519,16 +21631,62 @@ var WorkspaceStateSnapshot = class extends Schema.Class("WorkspaceStateSnapshot"
21519
21631
  * unparseable string — is `Option.none()`, because there is no indirection to
21520
21632
  * resolve. Total.
21521
21633
  *
21634
+ * A `catalog:` specifier the catalog set cannot resolve falls back to this
21635
+ * snapshot's `importerVersions` — but only to a version
21636
+ * **every** importer recording that dependency agrees on. A catalog injected
21637
+ * by a config-dependency pnpmfile hook appears in no committed catalog source,
21638
+ * so without this fallback both sides of a before/after diff resolve it to the
21639
+ * same raw string and a real version movement produces no row. When importers
21640
+ * disagree there is no single correct answer, so this stays `Option.none()`
21641
+ * rather than inventing one; {@link WorkspaceStateSnapshot.resolveIn} answers
21642
+ * precisely for callers that know which importer is asking.
21643
+ *
21522
21644
  * @param dependency - The dependency's package name (what `workspace:` /
21523
21645
  * `catalog:` resolve for).
21524
21646
  * @param specifier - The raw specifier string.
21525
21647
  */
21526
21648
  resolve(dependency, specifier) {
21649
+ return this.#resolveWith(dependency, specifier, () => Option.fromUndefinedOr(unanimousVersionOf(this.importerVersions ?? {}, dependency)));
21650
+ }
21651
+ /**
21652
+ * The concrete range or version a specifier resolved to AS OF this snapshot,
21653
+ * scoped to the importer that declared it.
21654
+ *
21655
+ * @remarks
21656
+ * Identical to {@link WorkspaceStateSnapshot.resolve} except in how an
21657
+ * unresolvable `catalog:` specifier falls back: this consults **only**
21658
+ * `importerPath`'s own recorded versions, so a monorepo whose packages hold
21659
+ * different versions of one dependency still gets an exact answer where
21660
+ * `resolve` must abstain. Prefer this whenever the caller knows the importer —
21661
+ * a consumer iterating `packages` has `relativePath` in hand, which is the
21662
+ * importer key (`"."` for the root package).
21663
+ *
21664
+ * An unknown `importerPath`, or one recording nothing for `dependency`, is
21665
+ * `Option.none()`. Total.
21666
+ *
21667
+ * @param importerPath - The importer's path relative to the workspace root,
21668
+ * `"."` for the root package — `PackageStateSnapshot.relativePath`.
21669
+ * @param dependency - The dependency's package name.
21670
+ * @param specifier - The raw specifier string.
21671
+ */
21672
+ resolveIn(importerPath, dependency, specifier) {
21673
+ return this.#resolveWith(dependency, specifier, () => Option.fromUndefinedOr(this.importerVersions?.[importerPath]?.[dependency]));
21674
+ }
21675
+ /**
21676
+ * The shared resolution path: classify, answer from the captured state, and
21677
+ * consult `onUnresolvedCatalog` only for a `catalog:` specifier the catalog set
21678
+ * could not answer. A plain range is already its own answer and must keep
21679
+ * resolving to `Option.none()` so the caller falls back to the raw string.
21680
+ */
21681
+ #resolveWith(dependency, specifier, onUnresolvedCatalog) {
21527
21682
  const exit = Schema.decodeUnknownExit(DependencySpecifier.FromString)(specifier);
21528
21683
  if (!Exit.isSuccess(exit)) return Option.none();
21529
21684
  const classified = exit.value;
21530
21685
  switch (classified._tag) {
21531
- case "catalog": return this.catalogs.rangeOf(dependency, classified.name);
21686
+ case "catalog": {
21687
+ const fromCatalogs = this.catalogs.rangeOf(dependency, classified.name);
21688
+ return Option.isSome(fromCatalogs) ? fromCatalogs : onUnresolvedCatalog();
21689
+ }
21532
21690
  case "workspace": return Option.fromUndefinedOr(this.#versions().get(dependency));
21533
21691
  default: return Option.none();
21534
21692
  }
@@ -21566,7 +21724,7 @@ var WorkspaceStateSnapshot = class extends Schema.Class("WorkspaceStateSnapshot"
21566
21724
  };
21567
21725
 
21568
21726
  //#endregion
21569
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceSnapshots.js
21727
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceSnapshots.js
21570
21728
  /** Whether `value` is a non-null, non-array object. */
21571
21729
  const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
21572
21730
  /** Whether every value in a record is a string — a usable dependency map. */
@@ -21620,6 +21778,11 @@ const bunInlineCatalogs = (manifest) => {
21620
21778
  catalogs: workspaces.catalogs
21621
21779
  });
21622
21780
  };
21781
+ /** The contribution of an absent or malformed lockfile: nothing, on both counts. */
21782
+ const EMPTY_LOCKFILE_RECORD = {
21783
+ catalogs: CatalogSet.empty(),
21784
+ importerVersions: {}
21785
+ };
21623
21786
  /**
21624
21787
  * Reads workspace state at a git ref with no checkout, and the live worktree.
21625
21788
  *
@@ -21652,10 +21815,17 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
21652
21815
  const roots = yield* WorkspaceRoot;
21653
21816
  const discovery = yield* WorkspaceDiscovery;
21654
21817
  const catalogsService = yield* WorkspaceCatalogs;
21655
- /** The catalog set a manager's lockfile records at the ref, or empty when absent/malformed. */
21656
- const lockfileCatalogs = (root, ref, format) => git.show(root, ref, `./${filenameFor(format)}`).pipe(Effect.flatMap((content) => Option.match(content, {
21657
- onNone: () => Effect.succeed(CatalogSet.empty()),
21658
- onSome: (text) => Lockfile.parse(text, { format }).pipe(Effect.map(CatalogSet.fromLockfile), Effect.catch(() => Effect.succeed(CatalogSet.empty())))
21818
+ /**
21819
+ * What a manager's lockfile records at the ref: its catalog set and its
21820
+ * importer versions, from ONE parse. Empty on both counts when the
21821
+ * lockfile is absent or malformed.
21822
+ */
21823
+ const lockfileRecord = (root, ref, format) => git.show(root, ref, `./${filenameFor(format)}`).pipe(Effect.flatMap((content) => Option.match(content, {
21824
+ onNone: () => Effect.succeed(EMPTY_LOCKFILE_RECORD),
21825
+ onSome: (text) => Lockfile.parse(text, { format }).pipe(Effect.map((lockfile) => ({
21826
+ catalogs: CatalogSet.fromLockfile(lockfile),
21827
+ importerVersions: importerVersionsOf(lockfile)
21828
+ })), Effect.catch(() => Effect.succeed(EMPTY_LOCKFILE_RECORD)))
21659
21829
  })));
21660
21830
  const computeAt = (root, ref) => Effect.gen(function* () {
21661
21831
  const pnpmWorkspaceText = yield* git.show(root, ref, "./pnpm-workspace.yaml");
@@ -21666,7 +21836,7 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
21666
21836
  });
21667
21837
  let patterns;
21668
21838
  let inline;
21669
- let fromLockfile;
21839
+ let recorded;
21670
21840
  if (Option.isSome(pnpmWorkspaceText)) {
21671
21841
  const pnpmPatterns = pnpmPatternsOf(yield* Yaml.parse(pnpmWorkspaceText.value).pipe(Effect.mapError((cause) => new CatalogAssemblyError({
21672
21842
  source: "manifest",
@@ -21675,13 +21845,13 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
21675
21845
  }))));
21676
21846
  patterns = pnpmPatterns.length > 0 ? pnpmPatterns : manifestPatternsOf(rootManifest);
21677
21847
  inline = yield* CatalogSet.fromWorkspaceYaml(pnpmWorkspaceText.value);
21678
- fromLockfile = yield* lockfileCatalogs(root, ref, "pnpm");
21848
+ recorded = yield* lockfileRecord(root, ref, "pnpm");
21679
21849
  } else {
21680
21850
  patterns = manifestPatternsOf(rootManifest);
21681
21851
  inline = bunInlineCatalogs(rootManifest);
21682
- fromLockfile = yield* lockfileCatalogs(root, ref, "bun");
21852
+ recorded = yield* lockfileRecord(root, ref, "bun");
21683
21853
  }
21684
- const catalogs = CatalogSet.merge(fromLockfile, inline);
21854
+ const catalogs = CatalogSet.merge(recorded.catalogs, inline);
21685
21855
  const globs = yield* GlobSet.compile(patterns).pipe(Effect.mapError((error) => new CatalogAssemblyError({
21686
21856
  source: "manifest",
21687
21857
  path: error.pattern,
@@ -21708,7 +21878,8 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
21708
21878
  for (const member of members) if (Option.isSome(member)) packages.push(member.value);
21709
21879
  return WorkspaceStateSnapshot.make({
21710
21880
  packages,
21711
- catalogs
21881
+ catalogs,
21882
+ importerVersions: recorded.importerVersions
21712
21883
  });
21713
21884
  });
21714
21885
  const atCaches = /* @__PURE__ */ new Map();
@@ -21732,6 +21903,7 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
21732
21903
  worktree: Effect.fn("WorkspaceSnapshots.worktree")(function* () {
21733
21904
  const packages = yield* discovery.listPackages();
21734
21905
  const catalogs = yield* catalogsService.set();
21906
+ const importerVersions = yield* catalogsService.importerVersions();
21735
21907
  const snapshotPackages = packages.map((pkg) => PackageStateSnapshot.make({
21736
21908
  name: pkg.name,
21737
21909
  version: pkg.version,
@@ -21743,7 +21915,8 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
21743
21915
  }));
21744
21916
  return WorkspaceStateSnapshot.make({
21745
21917
  packages: snapshotPackages,
21746
- catalogs
21918
+ catalogs,
21919
+ importerVersions
21747
21920
  });
21748
21921
  })
21749
21922
  };
@@ -21759,7 +21932,7 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
21759
21932
  };
21760
21933
 
21761
21934
  //#endregion
21762
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.6.2_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/Workspaces.js
21935
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.7.0_@effected+jsonc@0.5.1_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/Workspaces.js
21763
21936
  /**
21764
21937
  * Every service that needs only a filesystem: root, package-manager detection,
21765
21938
  * discovery, lockfile reading, catalogs and publishability.
@@ -43647,6 +43820,80 @@ function isUint8Array(value) {
43647
43820
  //#endregion
43648
43821
  //#region ../silk-effects/dist/dev/pkg/changesets/utils/remark-pipeline.js
43649
43822
  /**
43823
+ * Marker set on the `data` of a text node whose value must be written to
43824
+ * markdown verbatim rather than escaped.
43825
+ *
43826
+ * @remarks
43827
+ * `remark-stringify` escapes any character that could open a markdown
43828
+ * construct. Inside a dependency table that is always wrong: with
43829
+ * `remark-gfm` enabled `~` is the strikethrough delimiter, so the specifier
43830
+ * `~0.2.1` is written as `\~0.2.1`, and `_` in a package name becomes `\_`.
43831
+ * The corruption compounds on every re-serialization, and dependency-table
43832
+ * cells round-trip through consolidation and PR-body reconstruction.
43833
+ *
43834
+ * The marker is deliberately narrow. It is set only by the dependency-table
43835
+ * cell builder, whose cell vocabulary is closed — package name, dependency
43836
+ * type, action, version specifier, and the em-dash sentinel — and none of
43837
+ * those can legitimately carry markdown. Prose elsewhere in a changeset keeps
43838
+ * the default escaping.
43839
+ *
43840
+ * @internal
43841
+ */
43842
+ const LITERAL_TEXT_MARKER = "silkLiteralText";
43843
+ /**
43844
+ * Mark a text node so {@link createRemarkProcessor} writes it verbatim.
43845
+ *
43846
+ * @param value - The literal cell text
43847
+ * @returns An MDAST `Text` node carrying the literal marker
43848
+ *
43849
+ * @internal
43850
+ */
43851
+ function literalText(value) {
43852
+ return {
43853
+ type: "text",
43854
+ value,
43855
+ data: { [LITERAL_TEXT_MARKER]: true }
43856
+ };
43857
+ }
43858
+ /**
43859
+ * Whether a text node was marked by {@link literalText}.
43860
+ *
43861
+ * @internal
43862
+ */
43863
+ function isLiteralText(node) {
43864
+ return node.data?.[LITERAL_TEXT_MARKER] === true;
43865
+ }
43866
+ /**
43867
+ * Escape the two characters that would otherwise corrupt the table grid.
43868
+ *
43869
+ * @remarks
43870
+ * A `|` would close the cell early and a `\` would be read as an escape
43871
+ * introducer, so both are escaped to keep the written cell parseable back to
43872
+ * its exact input. Every other character is emitted as-is. Because parsing
43873
+ * consumes the backslash, a value that already carries a legacy `\~` from the
43874
+ * old escaping path re-parses to its clean form rather than accumulating
43875
+ * another layer.
43876
+ *
43877
+ * @internal
43878
+ */
43879
+ function escapeCellLiteral(value) {
43880
+ return value.replace(/[\\|]/g, "\\$&");
43881
+ }
43882
+ /**
43883
+ * `mdast-util-to-markdown` handler overrides used by the shared processor.
43884
+ *
43885
+ * @remarks
43886
+ * Replaces the default `text` handler — which is `state.safe(node.value, info)`
43887
+ * — with one that bypasses escaping for nodes marked by {@link literalText}
43888
+ * and delegates to the default behavior for everything else.
43889
+ *
43890
+ * @internal
43891
+ */
43892
+ const literalTextHandlers = { text: (node, _parent, state, info) => {
43893
+ const text = node;
43894
+ return isLiteralText(text) ? escapeCellLiteral(text.value) : state.safe(text.value, info);
43895
+ } };
43896
+ /**
43650
43897
  * Create a unified processor configured with remark-parse, remark-gfm,
43651
43898
  * and remark-stringify.
43652
43899
  *
@@ -43654,7 +43901,8 @@ function isUint8Array(value) {
43654
43901
  * Each call creates a fresh processor instance. The plugin chain is:
43655
43902
  * 1. `remark-parse` — markdown to MDAST
43656
43903
  * 2. `remark-gfm` — GitHub Flavored Markdown extensions (tables, etc.)
43657
- * 3. `remark-stringify` — MDAST back to markdown
43904
+ * 3. `remark-stringify` — MDAST back to markdown, with the
43905
+ * {@link literalText} handler override
43658
43906
  *
43659
43907
  * @privateRemarks
43660
43908
  * Return type is intentionally inferred because the unified `Processor`
@@ -43665,7 +43913,7 @@ function isUint8Array(value) {
43665
43913
  * @internal
43666
43914
  */
43667
43915
  function createRemarkProcessor() {
43668
- return unified().use(remarkParse).use(remarkGfm).use(remarkStringify);
43916
+ return unified().use(remarkParse).use(remarkGfm).use(remarkStringify, { handlers: literalTextHandlers });
43669
43917
  }
43670
43918
  /**
43671
43919
  * Parse a markdown string into an MDAST AST synchronously.
@@ -44177,6 +44425,12 @@ function parseDependencyTable(table) {
44177
44425
  /**
44178
44426
  * Create a table cell with a text node.
44179
44427
  *
44428
+ * @remarks
44429
+ * The cell text is marked literal, so stringification writes it verbatim
44430
+ * instead of escaping characters that could open a markdown construct. See
44431
+ * {@link literalText} — without it `~0.2.1` is written as `\~0.2.1` and
44432
+ * `some_pkg` as `some\_pkg`.
44433
+ *
44180
44434
  * @param text - The cell text content
44181
44435
  * @returns An MDAST `TableCell` node
44182
44436
  *
@@ -44185,10 +44439,7 @@ function parseDependencyTable(table) {
44185
44439
  function makeCell(text) {
44186
44440
  return {
44187
44441
  type: "tableCell",
44188
- children: [{
44189
- type: "text",
44190
- value: text
44191
- }]
44442
+ children: [literalText(text)]
44192
44443
  };
44193
44444
  }
44194
44445
  /**
@@ -44263,11 +44514,10 @@ function serializeDependencyTable(rows) {
44263
44514
  * @internal
44264
44515
  */
44265
44516
  function serializeDependencyTableToMarkdown(rows) {
44266
- const tree = {
44517
+ return stringifyMarkdown({
44267
44518
  type: "root",
44268
44519
  children: [serializeDependencyTable(rows)]
44269
- };
44270
- return unified().use(remarkGfm).use(remarkStringify).stringify(tree).trim();
44520
+ }).trim();
44271
44521
  }
44272
44522
  /**
44273
44523
  * Sort priority for dependency actions: removed first, then updated, then added.
@@ -47495,10 +47745,23 @@ const DEP_TYPE_MAP = [
47495
47745
  ["optionalDependencies", "optionalDependency"]
47496
47746
  ];
47497
47747
  /**
47498
- * Resolve a specifier against the snapshot it belongs to, falling back to
47499
- * the raw specifier string when the snapshot cannot resolve it.
47500
- */
47501
- const resolveOrRaw = (snapshot, dep, spec) => Option.getOrElse(snapshot.resolve(dep, spec), () => spec);
47748
+ * Resolve a specifier against the snapshot it belongs to, scoped to the
47749
+ * importer that declared it, falling back to the raw specifier string when
47750
+ * the snapshot cannot resolve it.
47751
+ *
47752
+ * @remarks
47753
+ * Uses `resolveIn` rather than the workspace-wide `resolve`. Both consult the
47754
+ * ref's own lockfile importer entries when a `catalog:` specifier is not in the
47755
+ * catalog set — which is what makes hook-injected catalogs (`catalog:effect:peers`,
47756
+ * injected by a config-dependency pnpmfile and recorded in neither
47757
+ * `pnpm-workspace.yaml` nor the lockfile's `catalogs:` block) resolvable at all.
47758
+ * The workspace-wide form abstains whenever two importers disagree on a
47759
+ * dependency's version, which in a multi-package repo reproduces the original
47760
+ * defect: both sides fall back to the identical raw specifier, compare equal,
47761
+ * and emit no row. Scoping to the declaring importer answers precisely where
47762
+ * the workspace-wide form cannot.
47763
+ */
47764
+ const resolveOrRaw = (snapshot, importerPath, dep, spec) => Option.getOrElse(snapshot.resolveIn(importerPath, dep, spec), () => spec);
47502
47765
  /**
47503
47766
  * Drop no-net-change field moves: the same dependency removed from one field
47504
47767
  * and added to another with an equal resolved version (e.g. a dep promoted
@@ -47543,13 +47806,15 @@ function computeWorkspaceDependencyDiffs(before, after) {
47543
47806
  for (const afterPkg of after.packages) {
47544
47807
  const beforePkg = Option.getOrNull(before.package(afterPkg.name));
47545
47808
  const rows = [];
47809
+ const afterImporter = afterPkg.relativePath;
47810
+ const beforeImporter = beforePkg?.relativePath ?? afterImporter;
47546
47811
  for (const [field, type] of DEP_TYPE_MAP) {
47547
47812
  const beforeRecord = beforePkg?.[field] ?? {};
47548
47813
  const afterRecord = afterPkg[field];
47549
47814
  const seen = /* @__PURE__ */ new Set();
47550
47815
  for (const [name, beforeSpec] of Object.entries(beforeRecord)) {
47551
47816
  seen.add(name);
47552
- const from = resolveOrRaw(before, name, beforeSpec);
47817
+ const from = resolveOrRaw(before, beforeImporter, name, beforeSpec);
47553
47818
  const afterSpec = afterRecord[name];
47554
47819
  if (afterSpec === void 0) {
47555
47820
  rows.push({
@@ -47561,7 +47826,7 @@ function computeWorkspaceDependencyDiffs(before, after) {
47561
47826
  });
47562
47827
  continue;
47563
47828
  }
47564
- const to = resolveOrRaw(after, name, afterSpec);
47829
+ const to = resolveOrRaw(after, afterImporter, name, afterSpec);
47565
47830
  if (from !== to) rows.push({
47566
47831
  dependency: name,
47567
47832
  type,
@@ -47577,7 +47842,7 @@ function computeWorkspaceDependencyDiffs(before, after) {
47577
47842
  type,
47578
47843
  action: "added",
47579
47844
  from: EM_DASH$1,
47580
- to: resolveOrRaw(after, name, afterSpec)
47845
+ to: resolveOrRaw(after, afterImporter, name, afterSpec)
47581
47846
  });
47582
47847
  }
47583
47848
  }
@@ -65886,8 +66151,38 @@ function getHeadingLevel(heading) {
65886
66151
  return sequence ? sequence.text.length : 0;
65887
66152
  }
65888
66153
  /**
66154
+ * CommonMark backslash escapes: a backslash is literal unless it precedes an
66155
+ * ASCII punctuation character, in which case the pair denotes that character.
66156
+ */
66157
+ const BACKSLASH_ESCAPE_RE = /\\([!-/:-@[-`{-~])/g;
66158
+ /**
66159
+ * Resolve CommonMark backslash escapes in raw micromark source text.
66160
+ *
66161
+ * @remarks
66162
+ * Every rule in this directory has a sibling remark implementation that reads
66163
+ * the parsed mdast tree, where the parser has already resolved escapes, via
66164
+ * `mdast-util-to-string`. Micromark tokens instead carry RAW source. Comparing
66165
+ * raw text against a value the parsed form would produce makes the two
66166
+ * implementations of one documented rule disagree about the same file
66167
+ * (issue #367).
66168
+ *
66169
+ * Applied at the shared extractors below so both implementations judge the
66170
+ * value a reader actually sees, rather than per-rule where the next extractor
66171
+ * added would silently reintroduce the split.
66172
+ *
66173
+ * @internal
66174
+ */
66175
+ function unescapeMarkdown(raw) {
66176
+ return raw.replace(BACKSLASH_ESCAPE_RE, "$1");
66177
+ }
66178
+ /**
65889
66179
  * Get the plain text content of an `atxHeading` token.
65890
66180
  *
66181
+ * @remarks
66182
+ * Escape-resolved, so a heading compares equal to the same heading as the
66183
+ * remark rules see it. `getHeadingLevel` needs no equivalent — it counts
66184
+ * sequence characters rather than reading text.
66185
+ *
65891
66186
  * @param heading - The `atxHeading` micromark token
65892
66187
  * @returns The heading text, or empty string if no text token found
65893
66188
  *
@@ -65895,7 +66190,7 @@ function getHeadingLevel(heading) {
65895
66190
  */
65896
66191
  function getHeadingText(heading) {
65897
66192
  const textToken = heading.children.find((c) => c.type === "atxHeadingText");
65898
- return textToken ? textToken.text : "";
66193
+ return textToken ? unescapeMarkdown(textToken.text) : "";
65899
66194
  }
65900
66195
 
65901
66196
  //#endregion
@@ -66022,13 +66317,13 @@ const EXPECTED_HEADERS = [
66022
66317
  * The `tableContent` token has a `.text` property with the cell value.
66023
66318
  *
66024
66319
  * @param cell - A GFM table cell token (header or data)
66025
- * @returns The trimmed text content of the cell, or an empty string
66320
+ * @returns The trimmed, escape-resolved text content of the cell, or an empty string
66026
66321
  *
66027
66322
  * @internal
66028
66323
  */
66029
66324
  function getCellText(cell) {
66030
66325
  const content = cell.children.find((c) => c.type === "tableContent");
66031
- return content ? content.text.trim() : "";
66326
+ return content ? unescapeMarkdown(content.text.trim()) : "";
66032
66327
  }
66033
66328
  /**
66034
66329
  * Extract all cell texts from a `tableRow` token.