@savvy-web/silk-effects 9.0.2 → 9.1.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.
@@ -342,6 +342,36 @@ var ChangesetIOError = class extends ChangesetIOErrorBase {
342
342
  }
343
343
  };
344
344
  /**
345
+ * Base class for {@link HookReplayError}.
346
+ *
347
+ * @privateRemarks
348
+ * Required export for api-extractor (anonymous Data.TaggedError base). Do not delete.
349
+ *
350
+ * @internal
351
+ */
352
+ const HookReplayErrorBase = Data.TaggedError("HookReplayError");
353
+ /**
354
+ * A workspace snapshot did not replay the config-dependency hooks the ref
355
+ * declares.
356
+ *
357
+ * @remarks
358
+ * Raised by {@link DepsRegen} before diffing when a ref's
359
+ * `pnpm-workspace.yaml` declares `configDependencies` that the snapshot's
360
+ * `hookReplays` record does not account for, or records at a different
361
+ * version. Catalogs that exist only through a config-dependency hook
362
+ * (`catalog:*:peers`) leave no lockfile trace, so a graph wired with a
363
+ * non-replaying `ConfigDependencyHooks` layer would diff them as unchanged
364
+ * and silently drop every `peerDependency` row — the regression this error
365
+ * exists to make loud (savvy-web/systems#674).
366
+ *
367
+ * @public
368
+ */
369
+ var HookReplayError = class extends HookReplayErrorBase {
370
+ get message() {
371
+ return `config dependencies declared at ${this.ref} were not replayed into its workspace snapshot (${this.missing.join(", ")}); the DepsRegen graph must be wired with a replaying ConfigDependencyHooks layer, or hook-injected peer catalogs diff as unchanged`;
372
+ }
373
+ };
374
+ /**
345
375
  * Base class for {@link ReleasePlanError}.
346
376
  *
347
377
  * @privateRemarks
@@ -367,4 +397,4 @@ var ReleasePlanError = class extends ReleasePlanErrorBase {
367
397
  };
368
398
 
369
399
  //#endregion
370
- export { ChangesetIOError, ChangesetIOErrorBase, ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitError, GitErrorBase, GitHubApiError, GitHubApiErrorBase, MarkdownParseError, MarkdownParseErrorBase, ReleasePlanError, ReleasePlanErrorBase, VersionFileError, VersionFileErrorBase };
400
+ export { ChangesetIOError, ChangesetIOErrorBase, ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitError, GitErrorBase, GitHubApiError, GitHubApiErrorBase, HookReplayError, HookReplayErrorBase, MarkdownParseError, MarkdownParseErrorBase, ReleasePlanError, ReleasePlanErrorBase, VersionFileError, VersionFileErrorBase };
@@ -1,6 +1,6 @@
1
1
  import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
2
  import { Categories } from "./api/categories.js";
3
- import { ChangesetIOError, ChangesetValidationError, ConfigurationError, GitError, GitHubApiError, MarkdownParseError, ReleasePlanError, VersionFileError } from "./errors.js";
3
+ import { ChangesetIOError, ChangesetValidationError, ConfigurationError, GitError, GitHubApiError, HookReplayError, MarkdownParseError, ReleasePlanError, VersionFileError } from "./errors.js";
4
4
  import { JsonPathSchema, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema, VersionFileConfigSchema, VersionFilesSchema } from "./schemas/version-files.js";
5
5
  import { GlobSchema, PackageScopeSchema, PackagesRecordSchema } from "./schemas/package-scope.js";
6
6
  import { ChangesetOptionsSchema, RepoSchema } from "./schemas/options.js";
@@ -99,6 +99,7 @@ var changesets_exports = /* @__PURE__ */ __exportAll({
99
99
  GitHubService: () => GitHubService,
100
100
  GlobSchema: () => GlobSchema,
101
101
  HeadingHierarchyRule: () => HeadingHierarchyRule,
102
+ HookReplayError: () => HookReplayError,
102
103
  InspectedConfigSchema: () => InspectedConfigSchema,
103
104
  IssueLinkRefsPlugin: () => IssueLinkRefsPlugin,
104
105
  IssueNumberSchema: () => IssueNumberSchema,
@@ -165,4 +166,4 @@ var changesets_exports = /* @__PURE__ */ __exportAll({
165
166
  });
166
167
 
167
168
  //#endregion
168
- export { AggregateDependencyTablesPlugin, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysisSchema, BranchAnalyzer, BranchFileEntrySchema, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogTransformer, ChangesetIOError, ChangesetLinter, ChangesetLogMode, 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, makeChangelogFunctions, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, parseChangesetPackages, serializeDependencyTableToMarkdown, vanillaChangelogFunctions };
169
+ export { AggregateDependencyTablesPlugin, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysisSchema, BranchAnalyzer, BranchFileEntrySchema, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogTransformer, ChangesetIOError, ChangesetLinter, ChangesetLogMode, 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, HookReplayError, 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, makeChangelogFunctions, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, parseChangesetPackages, serializeDependencyTableToMarkdown, vanillaChangelogFunctions };
@@ -1,16 +1,17 @@
1
- import { ChangesetIOError } from "../errors.js";
1
+ import { ChangesetIOError, HookReplayError } from "../errors.js";
2
2
  import { serializeDependencyTableToMarkdown, sortDependencyRows } from "../utils/dependency-table.js";
3
3
  import { ChangesetConfigReader } from "../../services/ChangesetConfigReader.js";
4
4
  import { ChangesetConfig } from "../../services/ChangesetConfig.js";
5
5
  import { SilkPublishability } from "../../services/SilkPublishability.js";
6
6
  import { ConfigInspector } from "./config-inspector.js";
7
7
  import { computeWorkspaceDependencyDiffs } from "../utils/dep-diff.js";
8
- import { gitListChangesetFilesAtRef, gitMergeBase } from "../utils/git.js";
8
+ import { gitListChangesetFilesAtRef, gitMergeBase, gitShowFileAtRef } from "../utils/git.js";
9
9
  import { listPublishablePackageNames } from "../utils/publishability.js";
10
10
  import { Context, Effect, FileSystem, Layer, Option } from "effect";
11
11
  import { basename, join, resolve } from "node:path";
12
12
  import { Git } from "@effected/git";
13
13
  import { PublishabilityDetector, WorkspaceDiscovery, WorkspaceSnapshots, Workspaces } from "@effected/workspaces";
14
+ import { Yaml } from "@effected/yaml";
14
15
 
15
16
  //#region src/changesets/services/deps-regen.ts
16
17
  /**
@@ -45,80 +46,77 @@ import { PublishabilityDetector, WorkspaceDiscovery, WorkspaceSnapshots, Workspa
45
46
  * @see {@link DepsRegen} for the service tag
46
47
  *
47
48
  */
48
- const ADJECTIVES = [
49
- "brave",
50
- "clever",
51
- "swift",
52
- "silver",
53
- "lucky",
54
- "happy",
55
- "calm",
56
- "bright",
57
- "quiet",
58
- "wild"
59
- ];
60
- const NOUNS = [
61
- "dogs",
62
- "cats",
63
- "wolves",
64
- "foxes",
65
- "cups",
66
- "ships",
67
- "trees",
68
- "owls",
69
- "cranes",
70
- "hills"
71
- ];
72
- const VERBS = [
73
- "laugh",
74
- "dream",
75
- "fly",
76
- "sing",
77
- "dance",
78
- "wander",
79
- "soar",
80
- "rest",
81
- "leap",
82
- "ponder"
83
- ];
84
- function pickRandomTriplet() {
85
- return `${ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)]}-${NOUNS[Math.floor(Math.random() * NOUNS.length)]}-${VERBS[Math.floor(Math.random() * VERBS.length)]}`;
86
- }
87
49
  /**
88
- * Pick a `<adjective>-<noun>-<verb>` filename slug that does not collide
89
- * with an existing `.changeset/*.md` OR with a slug already claimed
90
- * earlier in the same {@link RegenPlan.toWrite} computation. `plan()`
91
- * never writes to disk, so an on-disk existence check alone cannot see
92
- * slugs chosen moments earlier in the same call — the `chosen` set closes
93
- * that gap. The triplet space is 1,000 combinations, so a busy repo can
94
- * plausibly exhaust it across runs; fall back to a timestamp suffix after
95
- * 20 unlucky picks.
50
+ * Derive a stable, package-derived `.changeset/*.md` basename for a pure
51
+ * dependency changeset, replacing the earlier random
52
+ * `<adjective>-<noun>-<verb>` slug.
53
+ *
54
+ * @remarks
55
+ * A scoped `@scope/name` package joins its scope and name with `-` before
56
+ * appending the `-deps.md` suffix (e.g. `@savvy-web/cli` →
57
+ * `savvy-web-cli-deps.md`); an unscoped `name` package appends the suffix
58
+ * directly. Any character outside `[a-z0-9-]` in the joined name — dots,
59
+ * underscores, uppercase letters — is lowercased or replaced with `-`, and
60
+ * runs of `-` collapse to one, so the result is always a safe, deterministic
61
+ * filename that a stable-filename overwrite can target run after run.
96
62
  *
97
- * @param fileExists - Effectful on-disk existence check (never fails; a
98
- * filesystem error is treated as "does not exist" so filename selection
99
- * degrades gracefully rather than blocking the plan).
100
- * @param changesetDir - Directory checked for on-disk collisions.
101
- * @param chosen - Basenames (without extension) already picked within this plan;
102
- * the picked candidate is added to this set before returning.
63
+ * @param packageName - The workspace package name (e.g. `@savvy-web/cli`).
64
+ * @returns The stable changeset basename, including the `.md` extension.
103
65
  * @internal
104
66
  */
105
- function randomFilename(fileExists, changesetDir, chosen) {
106
- return Effect.gen(function* () {
107
- for (let i = 0; i < 20; i++) {
108
- const candidate = pickRandomTriplet();
109
- if (!chosen.has(candidate) && !(yield* fileExists(join(changesetDir, `${candidate}.md`)))) {
110
- chosen.add(candidate);
111
- return candidate;
112
- }
113
- }
114
- let attempt = 0;
115
- let fallback = `${pickRandomTriplet()}-${Date.now()}`;
116
- while (chosen.has(fallback) || (yield* fileExists(join(changesetDir, `${fallback}.md`)))) fallback = `${pickRandomTriplet()}-${Date.now()}-${++attempt}`;
117
- chosen.add(fallback);
118
- return fallback;
119
- });
67
+ function depsChangesetFilename(packageName) {
68
+ return `${(packageName.startsWith("@") ? packageName.slice(1).replace("/", "-") : packageName).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-")}-deps.md`;
120
69
  }
121
70
  /**
71
+ * Extract `configDependencies` (name → declared version, integrity stripped)
72
+ * from a `pnpm-workspace.yaml` text. Anything unparseable or absent reads as
73
+ * "nothing declared" — the guard built on this can only ever be as strict as
74
+ * the committed evidence.
75
+ *
76
+ * @internal
77
+ */
78
+ const declaredConfigDependencies = (text) => Effect.gen(function* () {
79
+ if (Option.isNone(text)) return {};
80
+ const doc = yield* Yaml.parse(text.value).pipe(Effect.orElseSucceed(() => void 0));
81
+ if (typeof doc !== "object" || doc === null) return {};
82
+ const raw = doc.configDependencies;
83
+ if (typeof raw !== "object" || raw === null) return {};
84
+ const out = {};
85
+ for (const [name, spec] of Object.entries(raw)) {
86
+ if (typeof spec !== "string") continue;
87
+ const plus = spec.indexOf("+");
88
+ out[name] = plus === -1 ? spec : spec.slice(0, plus);
89
+ }
90
+ return out;
91
+ });
92
+ /**
93
+ * Fail with {@link HookReplayError} unless every config dependency `declared`
94
+ * at `ref` is recorded in `snapshot.hookReplays` at the declared version.
95
+ *
96
+ * @remarks
97
+ * Catalogs injected by a config-dependency hook (`catalog:*:peers`) leave no
98
+ * lockfile trace, so a snapshot taken through a NON-replaying
99
+ * `ConfigDependencyHooks` layer answers them from nothing on both sides and a
100
+ * real floor change produces no `peerDependency` row (savvy-web/systems#674).
101
+ * The kit's replaying layers record every declared dependency in
102
+ * `hookReplays` (and fail typed when one cannot be resolved), so a declared
103
+ * name missing from the record means the graph is mis-wired — the one
104
+ * failure a downstream can detect without replaying anything itself. A ref
105
+ * that declares nothing has nothing to check; a snapshot decoded from a
106
+ * pre-`hookReplays` payload never reaches here (`plan()` reads fresh).
107
+ *
108
+ * @internal
109
+ */
110
+ const assertHooksReplayed = (ref, declared, snapshot) => {
111
+ const replays = snapshot.hookReplays ?? {};
112
+ const missing = Object.entries(declared).filter(([name, version]) => replays[name] !== version).map(([name]) => name);
113
+ return missing.length === 0 ? Effect.void : Effect.fail(new HookReplayError({
114
+ ref,
115
+ declared,
116
+ missing
117
+ }));
118
+ };
119
+ /**
122
120
  * Strict detection of "pure dependency changesets" per the documented
123
121
  * rules: single-package frontmatter, single `## Dependencies` heading,
124
122
  * no other body content beyond that section.
@@ -365,6 +363,11 @@ function makeShape(snapshots, inspector, discovery, detector, config, fs, provid
365
363
  }
366
364
  const before = yield* snapshots.at(fromRef);
367
365
  const after = options.to ? yield* snapshots.at(options.to) : yield* snapshots.worktree();
366
+ const workspaceYaml = "pnpm-workspace.yaml";
367
+ const declaredBefore = yield* declaredConfigDependencies(yield* gitShowFileAtRef(resolvedCwd, fromRef, workspaceYaml).pipe(Effect.provide(provideGit)));
368
+ const declaredAfter = yield* declaredConfigDependencies(options.to ? yield* gitShowFileAtRef(resolvedCwd, options.to, workspaceYaml).pipe(Effect.provide(provideGit)) : yield* fs.readFileString(join(resolvedCwd, workspaceYaml)).pipe(Effect.option));
369
+ yield* assertHooksReplayed(fromRef, declaredBefore, before);
370
+ yield* assertHooksReplayed(options.to ?? "worktree", declaredAfter, after);
368
371
  const rawDiffs = computeWorkspaceDependencyDiffs(before, after);
369
372
  const explicitTargets = /* @__PURE__ */ new Set([...options.packages ?? [], ...options.package ? [options.package] : []]);
370
373
  const excluded = new Set(options.exclude ?? []);
@@ -407,19 +410,30 @@ function makeShape(snapshots, inspector, discovery, detector, config, fs, provid
407
410
  const rewrittenPackages = new Set(resolved.map((d) => d.package));
408
411
  const atMergeBase = yield* gitListChangesetFilesAtRef(resolvedCwd, fromRef).pipe(Effect.provide(provideGit));
409
412
  const authoredOnBranch = (file) => !atMergeBase.has(basename(file));
410
- const toDelete = existingPure.filter((p) => inScopeFor(p.package) && rewrittenPackages.has(p.package) && authoredOnBranch(p.file));
411
- const chosenFilenames = /* @__PURE__ */ new Set();
413
+ const pureByFile = new Map(existingPure.map((p) => [p.file, p.package]));
414
+ const claimed = /* @__PURE__ */ new Set();
415
+ const isFreeFor = (file, pkg) => Effect.gen(function* () {
416
+ if (claimed.has(file) || !authoredOnBranch(file)) return false;
417
+ const owner = pureByFile.get(file);
418
+ if (owner !== void 0) return owner === pkg;
419
+ return !(yield* fileExists(file));
420
+ });
412
421
  const toWrite = [];
413
422
  for (const diff of resolved) {
414
- const filename = yield* randomFilename(fileExists, changesetDir, chosenFilenames);
423
+ const stable = depsChangesetFilename(diff.package);
424
+ const stem = stable.slice(0, -3);
425
+ let file = join(changesetDir, stable);
426
+ for (let n = 2; !(yield* isFreeFor(file, diff.package)); n++) file = join(changesetDir, `${stem}-${n}.md`);
427
+ claimed.add(file);
415
428
  toWrite.push({
416
- file: join(changesetDir, `${filename}.md`),
429
+ file,
417
430
  package: diff.package,
418
431
  diff
419
432
  });
420
433
  }
434
+ const writeTargets = claimed;
421
435
  return {
422
- toDelete,
436
+ toDelete: existingPure.filter((p) => inScopeFor(p.package) && rewrittenPackages.has(p.package) && authoredOnBranch(p.file) && !writeTargets.has(p.file)),
423
437
  toWrite,
424
438
  skippedMixed,
425
439
  coexisting
@@ -509,4 +523,4 @@ function makeDepsRegenDefault(options) {
509
523
  const DepsRegenDefault = makeDepsRegenDefault();
510
524
 
511
525
  //#endregion
512
- export { DepsRegen, DepsRegenDefault, isPureDependencyChangeset, makeDepsRegenDefault, parseChangesetPackages };
526
+ export { DepsRegen, DepsRegenDefault, depsChangesetFilename, isPureDependencyChangeset, makeDepsRegenDefault, parseChangesetPackages };
@@ -1,5 +1,5 @@
1
1
  import { GitError } from "../errors.js";
2
- import { Effect } from "effect";
2
+ import { Effect, Option } from "effect";
3
3
  import { basename } from "node:path";
4
4
  import { Git } from "@effected/git";
5
5
 
@@ -54,6 +54,34 @@ function gitListChangesetFilesAtRef(cwd, ref) {
54
54
  return new Set(entries.filter((entry) => entry.path.trim().length > 0).map((entry) => basename(entry.path)));
55
55
  });
56
56
  }
57
+ /**
58
+ * Read one tracked file's contents at `ref` via `git show <ref>:<path>`,
59
+ * as `Option.some(text)`; `Option.none()` when the file is absent at that
60
+ * ref, `cwd` is not a git repository, or `ref` does not resolve.
61
+ *
62
+ * @remarks
63
+ * Tolerant of exactly the three "nothing to read" shapes, for the same
64
+ * reason as {@link gitListChangesetFilesAtRef}: the consumer
65
+ * (`DepsRegen.plan()`'s hook-replay guard) treats them as "nothing
66
+ * declared", and a synthetic ref against a bare tmpdir must not turn a unit
67
+ * test into a git failure. Any OTHER failure — git itself erroring — is a
68
+ * {@link GitError}: swallowing it would let an operational fault read as an
69
+ * empty declaration and silently bypass the guard.
70
+ *
71
+ * @internal
72
+ */
73
+ function gitShowFileAtRef(cwd, ref, path) {
74
+ return Effect.gen(function* () {
75
+ return yield* (yield* Git).show(cwd, ref, path).pipe(Effect.catchTags({
76
+ NotARepositoryError: () => Effect.succeed(Option.none()),
77
+ UnknownRefError: () => Effect.succeed(Option.none())
78
+ }), Effect.mapError((error) => new GitError({
79
+ command: `git show ${ref}:${path}`,
80
+ cwd,
81
+ reason: error.message
82
+ })));
83
+ });
84
+ }
57
85
 
58
86
  //#endregion
59
- export { gitListChangesetFilesAtRef, gitMergeBase };
87
+ export { gitListChangesetFilesAtRef, gitMergeBase, gitShowFileAtRef };
package/index.d.ts CHANGED
@@ -2832,6 +2832,43 @@ declare class ChangesetIOError extends ChangesetIOErrorBase<{
2832
2832
  }> {
2833
2833
  get message(): string;
2834
2834
  }
2835
+ /**
2836
+ * Base class for {@link HookReplayError}.
2837
+ *
2838
+ * @privateRemarks
2839
+ * Required export for api-extractor (anonymous Data.TaggedError base). Do not delete.
2840
+ *
2841
+ * @internal
2842
+ */
2843
+ declare const HookReplayErrorBase: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
2844
+ readonly _tag: "HookReplayError";
2845
+ } & Readonly<A>;
2846
+ /**
2847
+ * A workspace snapshot did not replay the config-dependency hooks the ref
2848
+ * declares.
2849
+ *
2850
+ * @remarks
2851
+ * Raised by {@link DepsRegen} before diffing when a ref's
2852
+ * `pnpm-workspace.yaml` declares `configDependencies` that the snapshot's
2853
+ * `hookReplays` record does not account for, or records at a different
2854
+ * version. Catalogs that exist only through a config-dependency hook
2855
+ * (`catalog:*:peers`) leave no lockfile trace, so a graph wired with a
2856
+ * non-replaying `ConfigDependencyHooks` layer would diff them as unchanged
2857
+ * and silently drop every `peerDependency` row — the regression this error
2858
+ * exists to make loud (savvy-web/systems#674).
2859
+ *
2860
+ * @public
2861
+ */
2862
+ declare class HookReplayError extends HookReplayErrorBase<{
2863
+ /** The git ref whose snapshot was checked, or `"worktree"`. */
2864
+ readonly ref: string;
2865
+ /** Config dependencies declared at `ref` (name → declared version). */
2866
+ readonly declared: Readonly<Record<string, string>>;
2867
+ /** Declared names absent from, or mismatched in, the snapshot's replay record. */
2868
+ readonly missing: ReadonlyArray<string>;
2869
+ }> {
2870
+ get message(): string;
2871
+ }
2835
2872
  /**
2836
2873
  * Base class for {@link ReleasePlanError}.
2837
2874
  *
@@ -3856,7 +3893,7 @@ interface DepsRegenOptions {
3856
3893
  *
3857
3894
  * @public
3858
3895
  */
3859
- type DepsRegenPlanError = GitError | ChangesetIOError | WorkspaceDiscoveryFailure | WorkspaceSnapshotAtFailure | WorkspaceSnapshotWorktreeFailure;
3896
+ type DepsRegenPlanError = GitError | ChangesetIOError | HookReplayError | WorkspaceDiscoveryFailure | WorkspaceSnapshotAtFailure | WorkspaceSnapshotWorktreeFailure;
3860
3897
  /**
3861
3898
  * Effect service interface for the deps regen/detect orchestration.
3862
3899
  *
@@ -5829,7 +5866,7 @@ declare const RequiredSectionsRule: import("unified-lint-rule").Plugin<Root, unk
5829
5866
  //#region src/changesets/remark/rules/uncategorized-content.d.ts
5830
5867
  declare const UncategorizedContentRule: import("unified-lint-rule").Plugin<Root, unknown>;
5831
5868
  declare namespace index_d_exports {
5832
- export { AggregateDependencyTablesPlugin, AppliedRelease, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysis, BranchAnalysisSchema, BranchAnalyzer, BranchAnalyzerShape, BranchFileEntry, BranchFileEntrySchema, BumpType, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogServiceShape, ChangelogTransformer, Changeset, ChangesetIOError, ChangesetLinter, ChangesetLogMode, ChangesetLogModeValue, 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, MakeChangelogFunctionsOptions, 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, makeChangelogFunctions, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, parseChangesetPackages, serializeDependencyTableToMarkdown, vanillaChangelogFunctions };
5869
+ export { AggregateDependencyTablesPlugin, AppliedRelease, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysis, BranchAnalysisSchema, BranchAnalyzer, BranchAnalyzerShape, BranchFileEntry, BranchFileEntrySchema, BumpType, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogServiceShape, ChangelogTransformer, Changeset, ChangesetIOError, ChangesetLinter, ChangesetLogMode, ChangesetLogModeValue, 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, HookReplayError, InspectedConfig, InspectedConfigSchema, IssueLinkRefsPlugin, IssueNumberSchema, JsonPathSchema, LegacyVersionFileConfig, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema, LintMessage, MaintenanceNoteOptions, MaintenanceNotePlugin, MaintenanceReason, MaintenanceReasonSchema, MaintenanceTrigger, MaintenanceTriggerSchema, MakeChangelogFunctionsOptions, 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, makeChangelogFunctions, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, parseChangesetPackages, serializeDependencyTableToMarkdown, vanillaChangelogFunctions };
5833
5870
  }
5834
5871
  //#endregion
5835
5872
  //#region src/commitlint/config/schema.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/silk-effects",
3
- "version": "9.0.2",
3
+ "version": "9.1.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",
@@ -43,7 +43,7 @@
43
43
  "@effected/walker": "^0.10.0",
44
44
  "@effected/yaml": "^0.16.0",
45
45
  "@manypkg/get-packages": "^3.1.0",
46
- "@savvy-web/silk-core": "0.4.2",
46
+ "@savvy-web/silk-core": "0.4.3",
47
47
  "mdast-util-heading-range": "^4.0.0",
48
48
  "mdast-util-to-string": "^4.0.0",
49
49
  "remark-gfm": "^4.0.1",
@@ -58,7 +58,7 @@
58
58
  "@effected/commands": "^0.8.0",
59
59
  "@effected/git": "^0.16.0",
60
60
  "@effected/templates": "^0.7.0",
61
- "@effected/workspaces": "^0.23.0",
61
+ "@effected/workspaces": "^0.24.0",
62
62
  "effect": "4.0.0-rc.116"
63
63
  }
64
64
  }