@savvy-web/silk-effects 5.1.1 → 5.2.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.
Files changed (34) hide show
  1. package/README.md +22 -22
  2. package/changesets/api/transformer.js +2 -1
  3. package/changesets/changelog/getDependencyReleaseLine.js +24 -5
  4. package/changesets/changelog/getReleaseLine.js +7 -4
  5. package/changesets/changelog/index.js +8 -6
  6. package/changesets/index.js +6 -11
  7. package/changesets/services/branch-analyzer.js +20 -19
  8. package/changesets/services/changelog.js +1 -1
  9. package/changesets/services/config-inspector.js +17 -17
  10. package/changesets/services/deps-regen.js +36 -34
  11. package/changesets/services/github.js +39 -40
  12. package/changesets/services/maintenance-reason.js +5 -1
  13. package/changesets/services/release-planner.js +7 -6
  14. package/changesets/utils/dependency-table.js +2 -1
  15. package/changesets/utils/jsonpath.js +5 -7
  16. package/changesets/utils/publishability.js +2 -2
  17. package/commitlint/detection/dco.js +2 -1
  18. package/commitlint/index.js +2 -1
  19. package/index.d.ts +254 -218
  20. package/index.js +7 -7
  21. package/lint/handlers/PnpmWorkspace.js +2 -1
  22. package/lint/handlers/Yaml.js +8 -4
  23. package/package.json +7 -7
  24. package/repos/index.js +3 -5
  25. package/repos/services/config-store.js +68 -67
  26. package/repos/services/manager.js +259 -258
  27. package/services/BiomeSchemaSync.js +65 -64
  28. package/services/ChangesetConfig.js +50 -50
  29. package/services/ChangesetConfigReader.js +59 -58
  30. package/services/ConfigDiscovery.js +42 -41
  31. package/services/SilkPublishability.js +54 -53
  32. package/services/SilkWorkspaceAnalyzer.js +110 -109
  33. package/turbo/index.js +2 -3
  34. package/turbo/services/TurboInspector.js +80 -79
@@ -1,9 +1,9 @@
1
1
  import { ChangesetIOError } from "../errors.js";
2
2
  import { serializeDependencyTableToMarkdown, sortDependencyRows } from "../utils/dependency-table.js";
3
- import { ChangesetConfigReaderLive } from "../../services/ChangesetConfigReader.js";
4
- import { ChangesetConfig, ChangesetConfigLive } from "../../services/ChangesetConfig.js";
5
- import { PublishabilityDetectorAdaptiveLive } from "../../services/SilkPublishability.js";
6
- import { ConfigInspector, ConfigInspectorLive } from "./config-inspector.js";
3
+ import { ChangesetConfigReader } from "../../services/ChangesetConfigReader.js";
4
+ import { ChangesetConfig } from "../../services/ChangesetConfig.js";
5
+ import { SilkPublishability } from "../../services/SilkPublishability.js";
6
+ import { ConfigInspector } from "./config-inspector.js";
7
7
  import { computeWorkspaceDependencyDiffs } from "../utils/dep-diff.js";
8
8
  import { gitListChangesetFilesAtRef, gitMergeBase } from "../utils/git.js";
9
9
  import { listPublishablePackageNames } from "../utils/publishability.js";
@@ -43,7 +43,6 @@ import { PublishabilityDetector, WorkspaceDiscovery, WorkspaceSnapshots, Workspa
43
43
  * and MCP tools are thin adapters over this service.
44
44
  *
45
45
  * @see {@link DepsRegen} for the service tag
46
- * @see {@link DepsRegenLive} for the production layer
47
46
  *
48
47
  */
49
48
  const ADJECTIVES = [
@@ -242,7 +241,30 @@ function renderChangesetContent(diff) {
242
241
  *
243
242
  * @public
244
243
  */
245
- var DepsRegen = class extends Context.Service()("Changesets/DepsRegen") {};
244
+ var DepsRegen = class extends Context.Service()("Changesets/DepsRegen") {
245
+ /**
246
+ * Production layer for {@link DepsRegen}.
247
+ *
248
+ * Requires `WorkspaceSnapshots`, `WorkspaceDiscovery`,
249
+ * `PublishabilityDetector` (all from `@effected/workspaces`),
250
+ * `Git` (from `@effected/git`, backing merge-base resolution),
251
+ * {@link ConfigInspector}, {@link ChangesetConfig}, and
252
+ * `FileSystem.FileSystem` (resolved once at construction and closed over by
253
+ * the shape, keeping `plan`/`execute` themselves requirement-free).
254
+ *
255
+ * @public
256
+ */
257
+ static layer = Layer.effect(this, Effect.gen(function* () {
258
+ const snapshots = yield* WorkspaceSnapshots;
259
+ const inspector = yield* ConfigInspector;
260
+ const discovery = yield* WorkspaceDiscovery;
261
+ const detector = yield* PublishabilityDetector;
262
+ const config = yield* ChangesetConfig;
263
+ const fs = yield* FileSystem.FileSystem;
264
+ const git = yield* Git;
265
+ return makeShape(snapshots, inspector, discovery, detector, config, fs, Layer.succeed(Git, git));
266
+ }));
267
+ };
246
268
  /**
247
269
  * Build a {@link DepsRegenShape} that closes over already-resolved service
248
270
  * implementations, keeping the public `plan`/`execute` signatures
@@ -262,7 +284,9 @@ function makeShape(snapshots, inspector, discovery, detector, config, fs, provid
262
284
  if (!baseBranch) baseBranch = (yield* inspector.inspect(resolvedCwd).pipe(Effect.catchTag("ConfigurationError", () => Effect.succeed({ baseBranch: "main" })))).baseBranch;
263
285
  fromRef = yield* gitMergeBase(resolvedCwd, baseBranch).pipe(Effect.provide(provideGit));
264
286
  }
265
- const rawDiffs = computeWorkspaceDependencyDiffs(yield* snapshots.at(fromRef), options.to ? yield* snapshots.at(options.to) : yield* snapshots.worktree());
287
+ const before = yield* snapshots.at(fromRef);
288
+ const after = options.to ? yield* snapshots.at(options.to) : yield* snapshots.worktree();
289
+ const rawDiffs = computeWorkspaceDependencyDiffs(before, after);
266
290
  const explicitTargets = /* @__PURE__ */ new Set([...options.packages ?? [], ...options.package ? [options.package] : []]);
267
291
  const excluded = new Set(options.exclude ?? []);
268
292
  const livePackages = yield* discovery.listPackages();
@@ -335,29 +359,7 @@ function makeShape(snapshots, inspector, discovery, detector, config, fs, provid
335
359
  execute
336
360
  };
337
361
  }
338
- /**
339
- * Live layer for {@link DepsRegen}.
340
- *
341
- * Requires `WorkspaceSnapshots`, `WorkspaceDiscovery`,
342
- * `PublishabilityDetector` (all from `@effected/workspaces`),
343
- * `Git` (from `@effected/git`, backing merge-base resolution),
344
- * {@link ConfigInspector}, {@link ChangesetConfig}, and
345
- * `FileSystem.FileSystem` (resolved once at construction and closed over by
346
- * the shape, keeping `plan`/`execute` themselves requirement-free).
347
- *
348
- * @public
349
- */
350
- const DepsRegenLive = Layer.effect(DepsRegen, Effect.gen(function* () {
351
- const snapshots = yield* WorkspaceSnapshots;
352
- const inspector = yield* ConfigInspector;
353
- const discovery = yield* WorkspaceDiscovery;
354
- const detector = yield* PublishabilityDetector;
355
- const config = yield* ChangesetConfig;
356
- const fs = yield* FileSystem.FileSystem;
357
- const git = yield* Git;
358
- return makeShape(snapshots, inspector, discovery, detector, config, fs, Layer.succeed(Git, git));
359
- }));
360
- const ConfigGraph = ChangesetConfigLive.pipe(Layer.provide(ChangesetConfigReaderLive));
362
+ const ConfigGraph = ChangesetConfig.layer.pipe(Layer.provide(ChangesetConfigReader.layer));
361
363
  /**
362
364
  * Build the batteries-included {@link DepsRegen} layer over a
363
365
  * `@effected/workspaces` kit graph bound to `options.cwd`.
@@ -379,7 +381,7 @@ const ConfigGraph = ChangesetConfigLive.pipe(Layer.provide(ChangesetConfigReader
379
381
  */
380
382
  function makeDepsRegenDefault(options) {
381
383
  const kitGraph = Workspaces.layerWithGit(options);
382
- return DepsRegenLive.pipe(Layer.provide(ConfigInspectorLive.pipe(Layer.provide(Layer.mergeAll(ChangesetConfigReaderLive, kitGraph)))), Layer.provide(PublishabilityDetectorAdaptiveLive.pipe(Layer.provide(Layer.mergeAll(ConfigGraph, kitGraph)))), Layer.provide(ConfigGraph), Layer.provide(kitGraph));
384
+ return DepsRegen.layer.pipe(Layer.provide(ConfigInspector.layer.pipe(Layer.provide(Layer.mergeAll(ChangesetConfigReader.layer, kitGraph)))), Layer.provide(SilkPublishability.layerAdaptive.pipe(Layer.provide(Layer.mergeAll(ConfigGraph, kitGraph)))), Layer.provide(ConfigGraph), Layer.provide(kitGraph));
383
385
  }
384
386
  /**
385
387
  * Batteries-included {@link DepsRegen} layer: silk's opinionated default
@@ -391,10 +393,10 @@ function makeDepsRegenDefault(options) {
391
393
  * (`NodeServices.layer`), not a bare filesystem-only layer.
392
394
  *
393
395
  * Gating uses silk's adaptive publishability detector
394
- * ({@link PublishabilityDetectorAdaptiveLive}), so the default semantics
396
+ * (`SilkPublishability.layerAdaptive`), so the default semantics
395
397
  * are "versionable minus ignored" — identical to the savvy CLI and MCP
396
398
  * runtimes. Consumers who need to swap any dependency (test detectors,
397
- * alternate config sources) should keep composing {@link DepsRegenLive}
399
+ * alternate config sources) should keep composing {@link DepsRegen.layer}
398
400
  * directly; this layer is purely additive.
399
401
  *
400
402
  * @example
@@ -411,4 +413,4 @@ function makeDepsRegenDefault(options) {
411
413
  const DepsRegenDefault = makeDepsRegenDefault();
412
414
 
413
415
  //#endregion
414
- export { DepsRegen, DepsRegenDefault, DepsRegenLive, isPureDependencyChangeset, makeDepsRegenDefault };
416
+ export { DepsRegen, DepsRegenDefault, isPureDependencyChangeset, makeDepsRegenDefault };
@@ -6,21 +6,20 @@ import { Context, Effect, Layer } from "effect";
6
6
  /**
7
7
  * GitHub service for fetching commit metadata.
8
8
  *
9
- * Defines the {@link GitHubService} Effect service tag, the
10
- * {@link GitHubLive | production layer} backed by `\@changesets/get-github-info`,
9
+ * Defines the {@link GitHubService} Effect service tag, its
10
+ * `GitHubService.layer` production layer backed by `\@changesets/get-github-info`,
11
11
  * and the {@link makeGitHubTest} helper for constructing deterministic test
12
12
  * layers.
13
13
  *
14
14
  * @remarks
15
15
  * The GitHub service is consumed by the changelog formatters to resolve
16
16
  * commit hashes into pull-request numbers, author usernames, and link URLs.
17
- * In production, {@link GitHubLive} calls the GitHub REST API via the
17
+ * In production, `GitHubService.layer` calls the GitHub REST API via the
18
18
  * vendored `getGitHubInfo` wrapper. In tests, {@link makeGitHubTest}
19
19
  * returns canned responses from a `Map` keyed by commit hash.
20
20
  *
21
21
  * @see {@link GitHubService} for the Effect service tag
22
22
  * @see {@link GitHubServiceShape} for the service interface
23
- * @see {@link GitHubLive} for the production layer
24
23
  * @see {@link makeGitHubTest} for constructing test layers
25
24
  */
26
25
  /**
@@ -34,13 +33,13 @@ import { Context, Effect, Layer } from "effect";
34
33
  * This tag follows the standard Effect `Context.Service` pattern. Two layers
35
34
  * are provided out of the box:
36
35
  *
37
- * - {@link GitHubLive} — production layer backed by the GitHub REST API
36
+ * - `GitHubService.layer` — production layer backed by the GitHub REST API
38
37
  * - {@link makeGitHubTest} — factory for deterministic test layers
39
38
  *
40
39
  * @example
41
40
  * ```typescript
42
- * import { Effect, Layer } from "effect";
43
- * import { GitHubService, GitHubLive } from "\@savvy-web/changesets";
41
+ * import { Effect } from "effect";
42
+ * import { GitHubService } from "\@savvy-web/changesets";
44
43
  *
45
44
  * const program = Effect.gen(function* () {
46
45
  * const github = yield* GitHubService;
@@ -52,7 +51,7 @@ import { Context, Effect, Layer } from "effect";
52
51
  * });
53
52
  *
54
53
  * // Provide the live layer and run
55
- * Effect.runPromise(program.pipe(Effect.provide(GitHubLive)));
54
+ * Effect.runPromise(program.pipe(Effect.provide(GitHubService.layer)));
56
55
  * ```
57
56
  *
58
57
  * @example Creating a test layer with canned responses
@@ -76,41 +75,41 @@ import { Context, Effect, Layer } from "effect";
76
75
  * ```
77
76
  *
78
77
  * @see {@link GitHubServiceShape} for the service interface
79
- * @see {@link GitHubLive} for the production layer
80
78
  * @see {@link makeGitHubTest} for creating test layers
81
79
  *
82
80
  * @public
83
81
  */
84
- var GitHubService = class extends Context.Service()("GitHubService") {};
85
- /**
86
- * Production layer for {@link GitHubService}.
87
- *
88
- * Delegates to `\@changesets/get-github-info` to fetch commit metadata
89
- * from the GitHub REST API. Requires a `GITHUB_TOKEN` environment variable
90
- * to be set for authenticated requests.
91
- *
92
- * @remarks
93
- * This layer is used by the `\@savvy-web/changesets/changelog` entry point
94
- * to resolve commit hashes into PR numbers and author attribution. It is
95
- * used by the changelog formatter's
96
- * `MainLayer`.
97
- *
98
- * @example
99
- * ```typescript
100
- * import { Effect } from "effect";
101
- * import { GitHubService, GitHubLive } from "\@savvy-web/changesets";
102
- *
103
- * const program = Effect.gen(function* () {
104
- * const github = yield* GitHubService;
105
- * return yield* github.getInfo({ commit: "abc1234", repo: "owner/repo" });
106
- * });
107
- *
108
- * Effect.runPromise(program.pipe(Effect.provide(GitHubLive)));
109
- * ```
110
- *
111
- * @public
112
- */
113
- const GitHubLive = Layer.succeed(GitHubService, { getInfo: getGitHubInfo });
82
+ var GitHubService = class extends Context.Service()("GitHubService") {
83
+ /**
84
+ * Production layer for {@link GitHubService}.
85
+ *
86
+ * Delegates to `\@changesets/get-github-info` to fetch commit metadata
87
+ * from the GitHub REST API. Requires a `GITHUB_TOKEN` environment variable
88
+ * to be set for authenticated requests.
89
+ *
90
+ * @remarks
91
+ * This layer is used by the `\@savvy-web/changesets/changelog` entry point
92
+ * to resolve commit hashes into PR numbers and author attribution. It is
93
+ * used by the changelog formatter's
94
+ * `MainLayer`.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * import { Effect } from "effect";
99
+ * import { GitHubService } from "\@savvy-web/changesets";
100
+ *
101
+ * const program = Effect.gen(function* () {
102
+ * const github = yield* GitHubService;
103
+ * return yield* github.getInfo({ commit: "abc1234", repo: "owner/repo" });
104
+ * });
105
+ *
106
+ * Effect.runPromise(program.pipe(Effect.provide(GitHubService.layer)));
107
+ * ```
108
+ *
109
+ * @public
110
+ */
111
+ static layer = Layer.succeed(this, { getInfo: getGitHubInfo });
112
+ };
114
113
  /**
115
114
  * Create a test layer for {@link GitHubService} with pre-configured responses.
116
115
  *
@@ -162,4 +161,4 @@ function makeGitHubTest(responses) {
162
161
  }
163
162
 
164
163
  //#endregion
165
- export { GitHubLive, GitHubService, makeGitHubTest };
164
+ export { GitHubService, makeGitHubTest };
@@ -44,6 +44,10 @@ const MaintenanceReasonSchema = Schema.Struct({
44
44
  * will not match here; the release then degrades gracefully to the
45
45
  * `"unspecified"` fallback sentence instead of naming its triggers.
46
46
  *
47
+ * Co-members releasing as `type: "none"` are never triggers — they carry no
48
+ * version bump (and, per `@changesets/types`, no guaranteed `newVersion`), so
49
+ * naming one would print an unchanged version as the cause of the release.
50
+ *
47
51
  * @public
48
52
  */
49
53
  function deriveMaintenanceReason(release, plan, config) {
@@ -51,7 +55,7 @@ function deriveMaintenanceReason(release, plan, config) {
51
55
  const groupKinds = [["fixed", config.fixed], ["linked", config.linked]];
52
56
  for (const [kind, groups] of groupKinds) for (const group of groups) {
53
57
  if (!group.some((pattern) => ChangesetConfig.matches(release.name, pattern))) continue;
54
- const triggers = plan.releases.filter((r) => r.name !== release.name && r.changesets.length > 0 && group.some((pattern) => ChangesetConfig.matches(r.name, pattern))).map((r) => ({
58
+ const triggers = plan.releases.filter((r) => r.name !== release.name && r.type !== "none" && r.changesets.length > 0 && group.some((pattern) => ChangesetConfig.matches(r.name, pattern))).map((r) => ({
55
59
  name: r.name,
56
60
  version: r.newVersion
57
61
  }));
@@ -39,7 +39,12 @@ async function loadConfig(root, packages) {
39
39
  };
40
40
  }
41
41
  /** Effect service tag for the release planner. @public */
42
- var ReleasePlanner = class extends Context.Service()("ReleasePlanner") {};
42
+ var ReleasePlanner = class extends Context.Service()("ReleasePlanner") {
43
+ /** Production layer. Requires {@link ConfigInspector} (used by `apply`) and `FileSystem`. @public */
44
+ static layer = Layer.effect(this, Effect.gen(function* () {
45
+ return makeShape(yield* ConfigInspector, yield* FileSystem.FileSystem);
46
+ }));
47
+ };
43
48
  /** Build the service shape over a resolved {@link ConfigInspector} and {@link FileSystem.FileSystem}. */
44
49
  function makeShape(inspector, fs) {
45
50
  const plan = (root) => Effect.tryPromise({
@@ -57,10 +62,6 @@ function makeShape(inspector, fs) {
57
62
  apply
58
63
  };
59
64
  }
60
- /** Production layer. Requires {@link ConfigInspector} (used by `apply`) and `FileSystem`. @public */
61
- const ReleasePlannerLive = Layer.effect(ReleasePlanner, Effect.gen(function* () {
62
- return makeShape(yield* ConfigInspector, yield* FileSystem.FileSystem);
63
- }));
64
65
  /**
65
66
  * Test factory — supply fixed results for any subset of methods. Unsupplied
66
67
  * methods fail with a `ReleasePlanError`.
@@ -355,4 +356,4 @@ function applyEffect(root, dryRun, changelogModules, inspector, fs) {
355
356
  }
356
357
 
357
358
  //#endregion
358
- export { ReleasePlanner, ReleasePlannerLive, extractVersionBlock, makeReleasePlannerTest, withChangelogModules };
359
+ export { ReleasePlanner, extractVersionBlock, makeReleasePlannerTest, withChangelogModules };
@@ -189,9 +189,10 @@ function serializeDependencyTable(rows) {
189
189
  * @internal
190
190
  */
191
191
  function serializeDependencyTableToMarkdown(rows) {
192
+ const table = serializeDependencyTable(rows);
192
193
  return stringifyMarkdown({
193
194
  type: "root",
194
- children: [serializeDependencyTable(rows)]
195
+ children: [table]
195
196
  }).trim();
196
197
  }
197
198
  /**
@@ -102,14 +102,12 @@ function walkJsonPath(obj, path) {
102
102
  path: [...nodePath, segment.index]
103
103
  });
104
104
  break;
105
- case "wildcard":
106
- if (Array.isArray(node)) node.forEach((element, index) => {
107
- next.push({
108
- node: element,
109
- path: [...nodePath, index]
110
- });
105
+ case "wildcard": if (Array.isArray(node)) node.forEach((element, index) => {
106
+ next.push({
107
+ node: element,
108
+ path: [...nodePath, index]
111
109
  });
112
- break;
110
+ });
113
111
  }
114
112
  }
115
113
  current = next;
@@ -7,10 +7,10 @@ import { PublishabilityDetector } from "@effected/workspaces";
7
7
  *
8
8
  * @remarks
9
9
  * Uses the currently-active {@link SilkPublishability} — wire the
10
- * {@link SilkPublishabilityDetectorLive} layer to get silk semantics.
10
+ * `SilkPublishability.layer` layer to get silk semantics.
11
11
  *
12
12
  * The kit's `PublishabilityDetector.detect` contract no longer receives the
13
- * workspace root — the ignore/mode-aware `PublishabilityDetectorAdaptiveLive`
13
+ * workspace root — the ignore/mode-aware `SilkPublishability.layerAdaptive`
14
14
  * derives the `.changeset/config.json` root per package from the package's
15
15
  * own discovery coordinates (`pkg.path` ascended by `pkg.relativePath`).
16
16
  * The `root` parameter is retained for signature stability
@@ -46,7 +46,8 @@ function findProjectRoot(cwd) {
46
46
  * @public
47
47
  */
48
48
  function detectDCO(cwd = process.cwd()) {
49
- return existsSync(join(findProjectRoot(cwd) ?? cwd, DCO_FILENAME));
49
+ const searchDir = findProjectRoot(cwd) ?? cwd;
50
+ return existsSync(join(searchDir, DCO_FILENAME));
50
51
  }
51
52
 
52
53
  //#endregion
@@ -133,7 +133,8 @@ var commitlint_exports = /* @__PURE__ */ __exportAll({
133
133
  */
134
134
  var CommitlintConfig = class {
135
135
  static silk(options = {}) {
136
- return createConfig(decodeConfigOptions(options));
136
+ const validated = decodeConfigOptions(options);
137
+ return createConfig(validated);
137
138
  }
138
139
  /* v8 ignore next 3 -- private constructor prevents direct instantiation */
139
140
  constructor() {}