@savvy-web/silk 1.3.10 → 2.0.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 (36) hide show
  1. package/changesets-changelog.cjs +39308 -96625
  2. package/changesets-changelog.d.cts +137 -36
  3. package/changesets-changelog.d.ts +137 -36
  4. package/changesets-markdownlint.cjs +39305 -96622
  5. package/changesets-markdownlint.d.cts +137 -36
  6. package/changesets-markdownlint.d.ts +137 -36
  7. package/package.json +12 -12
  8. package/packages/silk-effects/dist/dev/pkg/changesets/api/changelog.cjs +2 -2
  9. package/packages/silk-effects/dist/dev/pkg/changesets/api/changelog.js +2 -2
  10. package/packages/silk-effects/dist/dev/pkg/changesets/api/transformer.cjs +24 -30
  11. package/packages/silk-effects/dist/dev/pkg/changesets/api/transformer.js +24 -30
  12. package/packages/silk-effects/dist/dev/pkg/changesets/changelog/formatting.cjs +4 -10
  13. package/packages/silk-effects/dist/dev/pkg/changesets/changelog/formatting.js +4 -10
  14. package/packages/silk-effects/dist/dev/pkg/changesets/changelog/getDependencyReleaseLine.cjs +13 -9
  15. package/packages/silk-effects/dist/dev/pkg/changesets/changelog/getDependencyReleaseLine.js +13 -9
  16. package/packages/silk-effects/dist/dev/pkg/changesets/changelog/getReleaseLine.cjs +8 -8
  17. package/packages/silk-effects/dist/dev/pkg/changesets/changelog/getReleaseLine.js +8 -8
  18. package/packages/silk-effects/dist/dev/pkg/changesets/changelog/index.cjs +1 -1
  19. package/packages/silk-effects/dist/dev/pkg/changesets/changelog/index.js +1 -1
  20. package/packages/silk-effects/dist/dev/pkg/changesets/index.cjs +12 -2
  21. package/packages/silk-effects/dist/dev/pkg/changesets/index.js +9 -3
  22. package/packages/silk-effects/dist/dev/pkg/changesets/remark/plugins/deduplicate-items.cjs +11 -9
  23. package/packages/silk-effects/dist/dev/pkg/changesets/remark/plugins/deduplicate-items.js +11 -9
  24. package/packages/silk-effects/dist/dev/pkg/changesets/remark/plugins/maintenance-note.cjs +61 -0
  25. package/packages/silk-effects/dist/dev/pkg/changesets/remark/plugins/maintenance-note.js +61 -0
  26. package/packages/silk-effects/dist/dev/pkg/changesets/remark/presets.cjs +1 -1
  27. package/packages/silk-effects/dist/dev/pkg/changesets/remark/presets.js +1 -1
  28. package/packages/silk-effects/dist/dev/pkg/changesets/services/maintenance-reason.cjs +68 -0
  29. package/packages/silk-effects/dist/dev/pkg/changesets/services/maintenance-reason.js +66 -0
  30. package/packages/silk-effects/dist/dev/pkg/changesets/services/release-planner.cjs +105 -59
  31. package/packages/silk-effects/dist/dev/pkg/changesets/services/release-planner.js +104 -58
  32. package/packages/silk-effects/dist/dev/pkg/changesets/vendor/github-info.cjs +33 -11
  33. package/packages/silk-effects/dist/dev/pkg/changesets/vendor/github-info.js +33 -11
  34. package/packages/silk-effects/dist/dev/pkg/schemas/VersioningSchemas.cjs +1 -1
  35. package/packages/silk-effects/dist/dev/pkg/schemas/VersioningSchemas.js +1 -1
  36. package/tsconfig/node/dist/tsconfig.tsbuildinfo +1 -1
@@ -1,11 +1,12 @@
1
1
  const require_errors = require('../errors.cjs');
2
2
  const require_transformer = require('../api/transformer.cjs');
3
3
  const require_config_inspector = require('./config-inspector.cjs');
4
+ const require_maintenance_reason = require('./maintenance-reason.cjs');
4
5
  const require_version_files = require('../utils/version-files.cjs');
5
- const require_changesets_config_esm = require('../../../../../../../node_modules/.pnpm/@changesets_config@3.1.4/node_modules/@changesets/config/dist/changesets-config.esm.cjs');
6
- const require_changesets_apply_release_plan_esm = require('../../../../../../../node_modules/.pnpm/@changesets_apply-release-plan@7.1.1/node_modules/@changesets/apply-release-plan/dist/changesets-apply-release-plan.esm.cjs');
7
- const require_changesets_get_release_plan_esm = require('../../../../../../../node_modules/.pnpm/@changesets_get-release-plan@4.0.16/node_modules/@changesets/get-release-plan/dist/changesets-get-release-plan.esm.cjs');
8
6
  const require_manypkg_get_packages = require('../../../../../../../node_modules/.pnpm/@manypkg_get-packages@3.1.0/node_modules/@manypkg/get-packages/dist/manypkg-get-packages.cjs');
7
+ const require_index = require('../../../../../../../node_modules/.pnpm/@changesets_config@4.0.0-next.6/node_modules/@changesets/config/dist/index.cjs');
8
+ const require_index$1 = require('../../../../../../../node_modules/.pnpm/@changesets_apply-release-plan@8.0.0-next.7/node_modules/@changesets/apply-release-plan/dist/index.cjs');
9
+ const require_index$2 = require('../../../../../../../node_modules/.pnpm/@changesets_get-release-plan@5.0.0-next.7/node_modules/@changesets/get-release-plan/dist/index.cjs');
9
10
  let effect = require("effect");
10
11
  let _effect_platform = require("@effect/platform");
11
12
  let node_path = require("node:path");
@@ -23,37 +24,21 @@ let node_path = require("node:path");
23
24
  * (e.g. `getChangelogEntry`) is re-implemented.
24
25
  *
25
26
  */
26
- const V1_TOOLS = /* @__PURE__ */ new Set([
27
- "yarn",
28
- "bolt",
29
- "pnpm",
30
- "lerna",
31
- "root"
32
- ]);
27
+ const errMsg = (e) => e instanceof Error ? e.message : String(e);
33
28
  /**
34
- * Single workspace-discovery seam; swap to an Effect-native stack later here.
35
- *
36
- * Discovers with `@manypkg/get-packages@3.x` and adapts to the v1 shape:
37
- * `tool` collapses to its type string (tools unknown to v1 map to `"root"` —
38
- * the engine never reads `tool` at runtime, only `root.dir`), and
39
- * `rootDir`/`rootPackage` fold back into `root`.
29
+ * Read the changesets config, surfacing non-throwing `readConfig` errors as a
30
+ * thrown `Error` so callers inside `Effect.tryPromise` land on the existing
31
+ * `ReleasePlanError` mapping. Warnings are returned alongside the config so
32
+ * the caller can log them via the Effect runtime rather than console output.
40
33
  */
41
- const buildPackages = async (root) => {
42
- const { tool, rootDir, rootPackage, packages } = await require_manypkg_get_packages.getPackages(root);
43
- if (!rootPackage) throw new Error(`Workspace root has no package.json: ${rootDir}`);
34
+ async function loadConfig(root, packages) {
35
+ const configResult = await require_index.readConfig(root, packages);
36
+ if (configResult.config === void 0) throw new Error(`Invalid changeset config:\n${configResult.errors.join("\n")}`);
44
37
  return {
45
- tool: V1_TOOLS.has(tool.type) ? tool.type : "root",
46
- root: {
47
- dir: rootPackage.dir,
48
- packageJson: rootPackage.packageJson
49
- },
50
- packages: packages.map((p) => ({
51
- dir: p.dir,
52
- packageJson: p.packageJson
53
- }))
38
+ config: configResult.config,
39
+ warnings: configResult.warnings
54
40
  };
55
- };
56
- const errMsg = (e) => e instanceof Error ? e.message : String(e);
41
+ }
57
42
  /**
58
43
  * Base class for {@link ReleasePlanner}.
59
44
  *
@@ -66,14 +51,14 @@ var ReleasePlanner = class extends ReleasePlannerBase {};
66
51
  /** Build the service shape over a resolved {@link ConfigInspector} and {@link FileSystem.FileSystem}. */
67
52
  function makeShape(inspector, fs) {
68
53
  const plan = (root) => effect.Effect.tryPromise({
69
- try: () => require_changesets_get_release_plan_esm.default(root),
54
+ try: () => require_index$2.getReleasePlan(root),
70
55
  catch: (e) => new require_errors.ReleasePlanError({
71
56
  phase: "plan",
72
57
  reason: errMsg(e)
73
58
  })
74
59
  });
75
60
  const preview = (root) => previewEffect(root, fs);
76
- const apply = (root, options) => applyEffect(root, options?.dryRun ?? false, inspector, fs);
61
+ const apply = (root, options) => applyEffect(root, options?.dryRun ?? false, options?.changelogModules, inspector, fs);
77
62
  return {
78
63
  plan,
79
64
  preview,
@@ -113,6 +98,16 @@ function extractVersionBlock(changelog, version) {
113
98
  }
114
99
  return lines.slice(start, end).join("\n").trim();
115
100
  }
101
+ /** Maintenance reasons for every changeset-less release in the plan, keyed by package name. */
102
+ function maintenanceReasons(plan, config) {
103
+ const reasons = /* @__PURE__ */ new Map();
104
+ for (const r of plan.releases) {
105
+ if (r.type === "none") continue;
106
+ const reason = require_maintenance_reason.deriveMaintenanceReason(r, plan, config);
107
+ if (reason) reasons.set(r.name, reason);
108
+ }
109
+ return reasons;
110
+ }
116
111
  /**
117
112
  * Render a non-destructive preview by redirecting every write into a
118
113
  * scope-managed temp directory (cleaned up automatically when the scope
@@ -121,19 +116,26 @@ function extractVersionBlock(changelog, version) {
121
116
  function previewEffect(root, fs) {
122
117
  const program = effect.Effect.gen(function* () {
123
118
  const [plan, packages] = yield* effect.Effect.tryPromise({
124
- try: () => Promise.all([require_changesets_get_release_plan_esm.default(root), buildPackages(root)]),
119
+ try: () => Promise.all([require_index$2.getReleasePlan(root), require_manypkg_get_packages.getPackages(root)]),
125
120
  catch: (e) => new require_errors.ReleasePlanError({
126
121
  phase: "preview",
127
122
  reason: errMsg(e)
128
123
  })
129
124
  });
130
- const config = yield* effect.Effect.tryPromise({
131
- try: () => require_changesets_config_esm.read(root, packages),
125
+ if (!packages.rootPackage) return yield* effect.Effect.fail(new require_errors.ReleasePlanError({
126
+ phase: "preview",
127
+ reason: `Workspace root has no package.json: ${root}`
128
+ }));
129
+ const rootPackage = packages.rootPackage;
130
+ const { config, warnings } = yield* effect.Effect.tryPromise({
131
+ try: () => loadConfig(root, packages),
132
132
  catch: (e) => new require_errors.ReleasePlanError({
133
133
  phase: "preview",
134
134
  reason: errMsg(e)
135
135
  })
136
136
  });
137
+ yield* effect.Effect.forEach(warnings, (w) => effect.Effect.logWarning(w));
138
+ const reasonByName = maintenanceReasons(plan, config);
137
139
  const preMode = plan.preState ? plan.preState.mode : null;
138
140
  const changesets = plan.changesets.map((cs) => ({
139
141
  id: cs.id,
@@ -151,7 +153,7 @@ function previewEffect(root, fs) {
151
153
  };
152
154
  const tempRoot = yield* fs.makeTempDirectoryScoped({ prefix: "silk-preview-" });
153
155
  const mapDir = (dir) => {
154
- const rel = (0, node_path.relative)(packages.root.dir, dir);
156
+ const rel = (0, node_path.relative)(packages.rootDir, dir);
155
157
  if (rel.startsWith("..") || (0, node_path.isAbsolute)(rel)) return effect.Effect.fail(new require_errors.ReleasePlanError({
156
158
  phase: "preview",
157
159
  reason: `Package directory is outside the workspace root: ${dir}`
@@ -161,13 +163,12 @@ function previewEffect(root, fs) {
161
163
  const tempDirs = yield* effect.Effect.forEach(packages.packages, (p) => mapDir(p.dir));
162
164
  const tempPackages = {
163
165
  tool: packages.tool,
164
- root: {
165
- ...packages.root,
166
+ rootDir: tempRoot,
167
+ rootPackage: {
166
168
  dir: tempRoot,
167
- packageJson: structuredClone(packages.root.packageJson)
169
+ packageJson: structuredClone(rootPackage.packageJson)
168
170
  },
169
171
  packages: packages.packages.map((p, i) => ({
170
- ...p,
171
172
  dir: tempDirs[i],
172
173
  packageJson: structuredClone(p.packageJson)
173
174
  }))
@@ -184,10 +185,10 @@ function previewEffect(root, fs) {
184
185
  const realCl = (0, node_path.join)(p.dir, "CHANGELOG.md");
185
186
  if (yield* fs.exists(realCl)) yield* fs.copyFile(realCl, (0, node_path.join)(tDir, "CHANGELOG.md"));
186
187
  }
187
- const rootCl = (0, node_path.join)(packages.root.dir, "CHANGELOG.md");
188
+ const rootCl = (0, node_path.join)(packages.rootDir, "CHANGELOG.md");
188
189
  if (yield* fs.exists(rootCl)) yield* fs.copyFile(rootCl, (0, node_path.join)(tempRoot, "CHANGELOG.md"));
189
190
  yield* effect.Effect.tryPromise({
190
- try: () => require_changesets_apply_release_plan_esm.default(plan, tempPackages, config, void 0, root),
191
+ try: () => require_index$1.applyReleasePlan(plan, tempPackages, config, void 0, root),
191
192
  catch: (e) => new require_errors.ReleasePlanError({
192
193
  phase: "preview",
193
194
  reason: errMsg(e)
@@ -195,15 +196,19 @@ function previewEffect(root, fs) {
195
196
  });
196
197
  const dirByName = /* @__PURE__ */ new Map();
197
198
  for (const p of tempPackages.packages) dirByName.set(p.packageJson.name, p.dir);
198
- if (tempPackages.root.packageJson.name) dirByName.set(tempPackages.root.packageJson.name, tempRoot);
199
+ if (tempPackages.rootPackage?.packageJson.name) dirByName.set(tempPackages.rootPackage.packageJson.name, tempRoot);
199
200
  const releases = [];
200
201
  for (const r of releasesToRender) {
201
202
  const dir = dirByName.get(r.name);
202
203
  if (!dir) continue;
203
204
  const clPath = (0, node_path.join)(dir, "CHANGELOG.md");
204
205
  if (!(yield* fs.exists(clPath))) continue;
206
+ const reason = reasonByName.get(r.name);
205
207
  yield* effect.Effect.try({
206
- try: () => require_transformer.ChangelogTransformer.transformFile(clPath),
208
+ try: () => require_transformer.ChangelogTransformer.transformFile(clPath, reason ? { maintenance: {
209
+ version: r.newVersion,
210
+ reason
211
+ } } : void 0),
207
212
  catch: (e) => new require_errors.ReleasePlanError({
208
213
  phase: "preview",
209
214
  reason: errMsg(e)
@@ -234,15 +239,17 @@ function previewEffect(root, fs) {
234
239
  function diskVersion(workspaceDir, fallback, fs) {
235
240
  return fs.readFileString((0, node_path.join)(workspaceDir, "package.json")).pipe(effect.Effect.flatMap((raw) => effect.Effect.try(() => JSON.parse(raw).version ?? fallback)), effect.Effect.orElseSucceed(() => fallback));
236
241
  }
237
- function applyEffect(root, dryRun, inspector, fs) {
242
+ function applyEffect(root, dryRun, changelogModules, inspector, fs) {
238
243
  return effect.Effect.gen(function* () {
239
- const { plan, packages, config } = yield* effect.Effect.tryPromise({
244
+ const { plan, packages, config, warnings } = yield* effect.Effect.tryPromise({
240
245
  try: async () => {
241
- const [plan, packages] = await Promise.all([require_changesets_get_release_plan_esm.default(root), buildPackages(root)]);
246
+ const [plan, packages] = await Promise.all([require_index$2.getReleasePlan(root), require_manypkg_get_packages.getPackages(root)]);
247
+ const { config, warnings } = await loadConfig(root, packages);
242
248
  return {
243
249
  plan,
244
250
  packages,
245
- config: await require_changesets_config_esm.read(root, packages)
251
+ config,
252
+ warnings
246
253
  };
247
254
  },
248
255
  catch: (e) => new require_errors.ReleasePlanError({
@@ -250,6 +257,29 @@ function applyEffect(root, dryRun, inspector, fs) {
250
257
  reason: errMsg(e)
251
258
  })
252
259
  });
260
+ yield* effect.Effect.forEach(warnings, (w) => effect.Effect.logWarning(w));
261
+ let engineConfig = config;
262
+ if (changelogModules) {
263
+ engineConfig = {
264
+ ...config,
265
+ format: false
266
+ };
267
+ if (Array.isArray(config.changelog)) {
268
+ const configuredId = config.changelog[0];
269
+ const mapped = changelogModules[configuredId];
270
+ if (mapped === void 0) {
271
+ const supported = Object.keys(changelogModules).join(", ");
272
+ return yield* effect.Effect.fail(new require_errors.ReleasePlanError({
273
+ phase: "apply",
274
+ reason: `changelog id "${configuredId}" is not in changelogModules (supported: ${supported})`
275
+ }));
276
+ }
277
+ engineConfig = {
278
+ ...engineConfig,
279
+ changelog: [mapped, config.changelog[1]]
280
+ };
281
+ }
282
+ }
253
283
  const releases = plan.releases.filter((r) => r.type !== "none").map((r) => ({
254
284
  name: r.name,
255
285
  type: r.type,
@@ -257,17 +287,33 @@ function applyEffect(root, dryRun, inspector, fs) {
257
287
  newVersion: r.newVersion
258
288
  }));
259
289
  let touchedFiles = [];
260
- if (!dryRun) touchedFiles = yield* effect.Effect.tryPromise({
261
- try: async () => {
262
- const touched = await require_changesets_apply_release_plan_esm.default(plan, packages, config);
263
- for (const f of touched) if (f.endsWith("CHANGELOG.md")) require_transformer.ChangelogTransformer.transformFile(f);
264
- return touched;
265
- },
266
- catch: (e) => new require_errors.ReleasePlanError({
267
- phase: "apply",
268
- reason: errMsg(e)
269
- })
270
- });
290
+ if (!dryRun) {
291
+ const reasonByName = maintenanceReasons(plan, config);
292
+ const versionByPkgName = new Map(plan.releases.map((r) => [r.name, r.newVersion]));
293
+ const nameByDir = /* @__PURE__ */ new Map();
294
+ for (const p of packages.packages) nameByDir.set(p.dir, p.packageJson.name);
295
+ if (packages.rootPackage?.packageJson.name) nameByDir.set(packages.rootDir, packages.rootPackage.packageJson.name);
296
+ touchedFiles = yield* effect.Effect.tryPromise({
297
+ try: async () => {
298
+ const touched = await require_index$1.applyReleasePlan(plan, packages, engineConfig);
299
+ for (const f of touched) {
300
+ if (!f.endsWith("CHANGELOG.md")) continue;
301
+ const pkgName = nameByDir.get((0, node_path.dirname)(f));
302
+ const reason = pkgName ? reasonByName.get(pkgName) : void 0;
303
+ const newVersion = pkgName ? versionByPkgName.get(pkgName) : void 0;
304
+ require_transformer.ChangelogTransformer.transformFile(f, reason && newVersion ? { maintenance: {
305
+ version: newVersion,
306
+ reason
307
+ } } : void 0);
308
+ }
309
+ return touched;
310
+ },
311
+ catch: (e) => new require_errors.ReleasePlanError({
312
+ phase: "apply",
313
+ reason: errMsg(e)
314
+ })
315
+ });
316
+ }
271
317
  const newVersionByName = new Map(plan.releases.map((r) => [r.name, r.newVersion]));
272
318
  const inspected = yield* inspector.inspect(root).pipe(effect.Effect.catchAll((error) => effect.Effect.logWarning(`Skipping versionFiles update: ${errMsg(error)}`).pipe(effect.Effect.as(null))));
273
319
  let versionFileUpdates = [];
@@ -1,14 +1,15 @@
1
1
  import { ReleasePlanError } from "../errors.js";
2
2
  import { ChangelogTransformer } from "../api/transformer.js";
3
3
  import { ConfigInspector } from "./config-inspector.js";
4
+ import { deriveMaintenanceReason } from "./maintenance-reason.js";
4
5
  import { VersionFiles } from "../utils/version-files.js";
5
- import { read } from "../../../../../../../node_modules/.pnpm/@changesets_config@3.1.4/node_modules/@changesets/config/dist/changesets-config.esm.js";
6
- import applyReleasePlan from "../../../../../../../node_modules/.pnpm/@changesets_apply-release-plan@7.1.1/node_modules/@changesets/apply-release-plan/dist/changesets-apply-release-plan.esm.js";
7
- import getReleasePlan from "../../../../../../../node_modules/.pnpm/@changesets_get-release-plan@4.0.16/node_modules/@changesets/get-release-plan/dist/changesets-get-release-plan.esm.js";
8
6
  import { getPackages } from "../../../../../../../node_modules/.pnpm/@manypkg_get-packages@3.1.0/node_modules/@manypkg/get-packages/dist/manypkg-get-packages.js";
7
+ import { readConfig } from "../../../../../../../node_modules/.pnpm/@changesets_config@4.0.0-next.6/node_modules/@changesets/config/dist/index.js";
8
+ import { applyReleasePlan } from "../../../../../../../node_modules/.pnpm/@changesets_apply-release-plan@8.0.0-next.7/node_modules/@changesets/apply-release-plan/dist/index.js";
9
+ import { getReleasePlan } from "../../../../../../../node_modules/.pnpm/@changesets_get-release-plan@5.0.0-next.7/node_modules/@changesets/get-release-plan/dist/index.js";
9
10
  import { Context, Effect, Layer } from "effect";
10
11
  import { FileSystem } from "@effect/platform";
11
- import { isAbsolute, join, relative } from "node:path";
12
+ import { dirname, isAbsolute, join, relative } from "node:path";
12
13
 
13
14
  //#region ../silk-effects/dist/dev/pkg/changesets/services/release-planner.js
14
15
  /**
@@ -23,37 +24,21 @@ import { isAbsolute, join, relative } from "node:path";
23
24
  * (e.g. `getChangelogEntry`) is re-implemented.
24
25
  *
25
26
  */
26
- const V1_TOOLS = /* @__PURE__ */ new Set([
27
- "yarn",
28
- "bolt",
29
- "pnpm",
30
- "lerna",
31
- "root"
32
- ]);
27
+ const errMsg = (e) => e instanceof Error ? e.message : String(e);
33
28
  /**
34
- * Single workspace-discovery seam; swap to an Effect-native stack later here.
35
- *
36
- * Discovers with `@manypkg/get-packages@3.x` and adapts to the v1 shape:
37
- * `tool` collapses to its type string (tools unknown to v1 map to `"root"` —
38
- * the engine never reads `tool` at runtime, only `root.dir`), and
39
- * `rootDir`/`rootPackage` fold back into `root`.
29
+ * Read the changesets config, surfacing non-throwing `readConfig` errors as a
30
+ * thrown `Error` so callers inside `Effect.tryPromise` land on the existing
31
+ * `ReleasePlanError` mapping. Warnings are returned alongside the config so
32
+ * the caller can log them via the Effect runtime rather than console output.
40
33
  */
41
- const buildPackages = async (root) => {
42
- const { tool, rootDir, rootPackage, packages } = await getPackages(root);
43
- if (!rootPackage) throw new Error(`Workspace root has no package.json: ${rootDir}`);
34
+ async function loadConfig(root, packages) {
35
+ const configResult = await readConfig(root, packages);
36
+ if (configResult.config === void 0) throw new Error(`Invalid changeset config:\n${configResult.errors.join("\n")}`);
44
37
  return {
45
- tool: V1_TOOLS.has(tool.type) ? tool.type : "root",
46
- root: {
47
- dir: rootPackage.dir,
48
- packageJson: rootPackage.packageJson
49
- },
50
- packages: packages.map((p) => ({
51
- dir: p.dir,
52
- packageJson: p.packageJson
53
- }))
38
+ config: configResult.config,
39
+ warnings: configResult.warnings
54
40
  };
55
- };
56
- const errMsg = (e) => e instanceof Error ? e.message : String(e);
41
+ }
57
42
  /**
58
43
  * Base class for {@link ReleasePlanner}.
59
44
  *
@@ -73,7 +58,7 @@ function makeShape(inspector, fs) {
73
58
  })
74
59
  });
75
60
  const preview = (root) => previewEffect(root, fs);
76
- const apply = (root, options) => applyEffect(root, options?.dryRun ?? false, inspector, fs);
61
+ const apply = (root, options) => applyEffect(root, options?.dryRun ?? false, options?.changelogModules, inspector, fs);
77
62
  return {
78
63
  plan,
79
64
  preview,
@@ -113,6 +98,16 @@ function extractVersionBlock(changelog, version) {
113
98
  }
114
99
  return lines.slice(start, end).join("\n").trim();
115
100
  }
101
+ /** Maintenance reasons for every changeset-less release in the plan, keyed by package name. */
102
+ function maintenanceReasons(plan, config) {
103
+ const reasons = /* @__PURE__ */ new Map();
104
+ for (const r of plan.releases) {
105
+ if (r.type === "none") continue;
106
+ const reason = deriveMaintenanceReason(r, plan, config);
107
+ if (reason) reasons.set(r.name, reason);
108
+ }
109
+ return reasons;
110
+ }
116
111
  /**
117
112
  * Render a non-destructive preview by redirecting every write into a
118
113
  * scope-managed temp directory (cleaned up automatically when the scope
@@ -121,19 +116,26 @@ function extractVersionBlock(changelog, version) {
121
116
  function previewEffect(root, fs) {
122
117
  const program = Effect.gen(function* () {
123
118
  const [plan, packages] = yield* Effect.tryPromise({
124
- try: () => Promise.all([getReleasePlan(root), buildPackages(root)]),
119
+ try: () => Promise.all([getReleasePlan(root), getPackages(root)]),
125
120
  catch: (e) => new ReleasePlanError({
126
121
  phase: "preview",
127
122
  reason: errMsg(e)
128
123
  })
129
124
  });
130
- const config = yield* Effect.tryPromise({
131
- try: () => read(root, packages),
125
+ if (!packages.rootPackage) return yield* Effect.fail(new ReleasePlanError({
126
+ phase: "preview",
127
+ reason: `Workspace root has no package.json: ${root}`
128
+ }));
129
+ const rootPackage = packages.rootPackage;
130
+ const { config, warnings } = yield* Effect.tryPromise({
131
+ try: () => loadConfig(root, packages),
132
132
  catch: (e) => new ReleasePlanError({
133
133
  phase: "preview",
134
134
  reason: errMsg(e)
135
135
  })
136
136
  });
137
+ yield* Effect.forEach(warnings, (w) => Effect.logWarning(w));
138
+ const reasonByName = maintenanceReasons(plan, config);
137
139
  const preMode = plan.preState ? plan.preState.mode : null;
138
140
  const changesets = plan.changesets.map((cs) => ({
139
141
  id: cs.id,
@@ -151,7 +153,7 @@ function previewEffect(root, fs) {
151
153
  };
152
154
  const tempRoot = yield* fs.makeTempDirectoryScoped({ prefix: "silk-preview-" });
153
155
  const mapDir = (dir) => {
154
- const rel = relative(packages.root.dir, dir);
156
+ const rel = relative(packages.rootDir, dir);
155
157
  if (rel.startsWith("..") || isAbsolute(rel)) return Effect.fail(new ReleasePlanError({
156
158
  phase: "preview",
157
159
  reason: `Package directory is outside the workspace root: ${dir}`
@@ -161,13 +163,12 @@ function previewEffect(root, fs) {
161
163
  const tempDirs = yield* Effect.forEach(packages.packages, (p) => mapDir(p.dir));
162
164
  const tempPackages = {
163
165
  tool: packages.tool,
164
- root: {
165
- ...packages.root,
166
+ rootDir: tempRoot,
167
+ rootPackage: {
166
168
  dir: tempRoot,
167
- packageJson: structuredClone(packages.root.packageJson)
169
+ packageJson: structuredClone(rootPackage.packageJson)
168
170
  },
169
171
  packages: packages.packages.map((p, i) => ({
170
- ...p,
171
172
  dir: tempDirs[i],
172
173
  packageJson: structuredClone(p.packageJson)
173
174
  }))
@@ -184,7 +185,7 @@ function previewEffect(root, fs) {
184
185
  const realCl = join(p.dir, "CHANGELOG.md");
185
186
  if (yield* fs.exists(realCl)) yield* fs.copyFile(realCl, join(tDir, "CHANGELOG.md"));
186
187
  }
187
- const rootCl = join(packages.root.dir, "CHANGELOG.md");
188
+ const rootCl = join(packages.rootDir, "CHANGELOG.md");
188
189
  if (yield* fs.exists(rootCl)) yield* fs.copyFile(rootCl, join(tempRoot, "CHANGELOG.md"));
189
190
  yield* Effect.tryPromise({
190
191
  try: () => applyReleasePlan(plan, tempPackages, config, void 0, root),
@@ -195,15 +196,19 @@ function previewEffect(root, fs) {
195
196
  });
196
197
  const dirByName = /* @__PURE__ */ new Map();
197
198
  for (const p of tempPackages.packages) dirByName.set(p.packageJson.name, p.dir);
198
- if (tempPackages.root.packageJson.name) dirByName.set(tempPackages.root.packageJson.name, tempRoot);
199
+ if (tempPackages.rootPackage?.packageJson.name) dirByName.set(tempPackages.rootPackage.packageJson.name, tempRoot);
199
200
  const releases = [];
200
201
  for (const r of releasesToRender) {
201
202
  const dir = dirByName.get(r.name);
202
203
  if (!dir) continue;
203
204
  const clPath = join(dir, "CHANGELOG.md");
204
205
  if (!(yield* fs.exists(clPath))) continue;
206
+ const reason = reasonByName.get(r.name);
205
207
  yield* Effect.try({
206
- try: () => ChangelogTransformer.transformFile(clPath),
208
+ try: () => ChangelogTransformer.transformFile(clPath, reason ? { maintenance: {
209
+ version: r.newVersion,
210
+ reason
211
+ } } : void 0),
207
212
  catch: (e) => new ReleasePlanError({
208
213
  phase: "preview",
209
214
  reason: errMsg(e)
@@ -234,15 +239,17 @@ function previewEffect(root, fs) {
234
239
  function diskVersion(workspaceDir, fallback, fs) {
235
240
  return fs.readFileString(join(workspaceDir, "package.json")).pipe(Effect.flatMap((raw) => Effect.try(() => JSON.parse(raw).version ?? fallback)), Effect.orElseSucceed(() => fallback));
236
241
  }
237
- function applyEffect(root, dryRun, inspector, fs) {
242
+ function applyEffect(root, dryRun, changelogModules, inspector, fs) {
238
243
  return Effect.gen(function* () {
239
- const { plan, packages, config } = yield* Effect.tryPromise({
244
+ const { plan, packages, config, warnings } = yield* Effect.tryPromise({
240
245
  try: async () => {
241
- const [plan, packages] = await Promise.all([getReleasePlan(root), buildPackages(root)]);
246
+ const [plan, packages] = await Promise.all([getReleasePlan(root), getPackages(root)]);
247
+ const { config, warnings } = await loadConfig(root, packages);
242
248
  return {
243
249
  plan,
244
250
  packages,
245
- config: await read(root, packages)
251
+ config,
252
+ warnings
246
253
  };
247
254
  },
248
255
  catch: (e) => new ReleasePlanError({
@@ -250,6 +257,29 @@ function applyEffect(root, dryRun, inspector, fs) {
250
257
  reason: errMsg(e)
251
258
  })
252
259
  });
260
+ yield* Effect.forEach(warnings, (w) => Effect.logWarning(w));
261
+ let engineConfig = config;
262
+ if (changelogModules) {
263
+ engineConfig = {
264
+ ...config,
265
+ format: false
266
+ };
267
+ if (Array.isArray(config.changelog)) {
268
+ const configuredId = config.changelog[0];
269
+ const mapped = changelogModules[configuredId];
270
+ if (mapped === void 0) {
271
+ const supported = Object.keys(changelogModules).join(", ");
272
+ return yield* Effect.fail(new ReleasePlanError({
273
+ phase: "apply",
274
+ reason: `changelog id "${configuredId}" is not in changelogModules (supported: ${supported})`
275
+ }));
276
+ }
277
+ engineConfig = {
278
+ ...engineConfig,
279
+ changelog: [mapped, config.changelog[1]]
280
+ };
281
+ }
282
+ }
253
283
  const releases = plan.releases.filter((r) => r.type !== "none").map((r) => ({
254
284
  name: r.name,
255
285
  type: r.type,
@@ -257,17 +287,33 @@ function applyEffect(root, dryRun, inspector, fs) {
257
287
  newVersion: r.newVersion
258
288
  }));
259
289
  let touchedFiles = [];
260
- if (!dryRun) touchedFiles = yield* Effect.tryPromise({
261
- try: async () => {
262
- const touched = await applyReleasePlan(plan, packages, config);
263
- for (const f of touched) if (f.endsWith("CHANGELOG.md")) ChangelogTransformer.transformFile(f);
264
- return touched;
265
- },
266
- catch: (e) => new ReleasePlanError({
267
- phase: "apply",
268
- reason: errMsg(e)
269
- })
270
- });
290
+ if (!dryRun) {
291
+ const reasonByName = maintenanceReasons(plan, config);
292
+ const versionByPkgName = new Map(plan.releases.map((r) => [r.name, r.newVersion]));
293
+ const nameByDir = /* @__PURE__ */ new Map();
294
+ for (const p of packages.packages) nameByDir.set(p.dir, p.packageJson.name);
295
+ if (packages.rootPackage?.packageJson.name) nameByDir.set(packages.rootDir, packages.rootPackage.packageJson.name);
296
+ touchedFiles = yield* Effect.tryPromise({
297
+ try: async () => {
298
+ const touched = await applyReleasePlan(plan, packages, engineConfig);
299
+ for (const f of touched) {
300
+ if (!f.endsWith("CHANGELOG.md")) continue;
301
+ const pkgName = nameByDir.get(dirname(f));
302
+ const reason = pkgName ? reasonByName.get(pkgName) : void 0;
303
+ const newVersion = pkgName ? versionByPkgName.get(pkgName) : void 0;
304
+ ChangelogTransformer.transformFile(f, reason && newVersion ? { maintenance: {
305
+ version: newVersion,
306
+ reason
307
+ } } : void 0);
308
+ }
309
+ return touched;
310
+ },
311
+ catch: (e) => new ReleasePlanError({
312
+ phase: "apply",
313
+ reason: errMsg(e)
314
+ })
315
+ });
316
+ }
271
317
  const newVersionByName = new Map(plan.releases.map((r) => [r.name, r.newVersion]));
272
318
  const inspected = yield* inspector.inspect(root).pipe(Effect.catchAll((error) => Effect.logWarning(`Skipping versionFiles update: ${errMsg(error)}`).pipe(Effect.as(null))));
273
319
  let versionFileUpdates = [];
@@ -1,5 +1,5 @@
1
1
  const require_errors = require('../errors.cjs');
2
- const require_changesets_get_github_info_esm = require('../../../../../../../node_modules/.pnpm/@changesets_get-github-info@0.8.0/node_modules/@changesets/get-github-info/dist/changesets-get-github-info.esm.cjs');
2
+ const require_index = require('../../../../../../../node_modules/.pnpm/@changesets_get-github-info@1.0.0-next.3/node_modules/@changesets/get-github-info/dist/index.cjs');
3
3
  let effect = require("effect");
4
4
 
5
5
  //#region ../silk-effects/dist/dev/pkg/changesets/vendor/github-info.js
@@ -9,8 +9,14 @@ let effect = require("effect");
9
9
  * @remarks
10
10
  * Bridges the `\@changesets/get-github-info` package (which returns
11
11
  * promises) into the Effect ecosystem. The {@link getGitHubInfo}
12
- * function wraps the upstream `getInfo()` call in `Effect.tryPromise`,
13
- * mapping failures to {@link GitHubApiError}.
12
+ * function wraps the upstream `getCommitInfo()` call in `Effect.tryPromise`,
13
+ * adapting its structured `CommitInfo | undefined` return back to the
14
+ * legacy {@link GitHubCommitInfo} shape and mapping failures (including a
15
+ * `not found` result) to {@link GitHubApiError}.
16
+ *
17
+ * The upstream v1 package added a `.env` fallback: it reads
18
+ * `GITHUB_TOKEN` from `process.env` directly when no token is otherwise
19
+ * configured, so the caller does not need to plumb one through.
14
20
  *
15
21
  * The {@link GitHubCommitInfo} type is the only item from this module
16
22
  * that is part of the public API (re-exported from the package root).
@@ -24,9 +30,13 @@ let effect = require("effect");
24
30
  * Fetch GitHub info for a commit, wrapped in Effect.
25
31
  *
26
32
  * @remarks
27
- * Calls the upstream `getInfo()` from `\@changesets/get-github-info`
28
- * within `Effect.tryPromise`. Any thrown error is caught and mapped
29
- * to a {@link GitHubApiError} with the operation set to `"getInfo"`.
33
+ * Calls the upstream `getCommitInfo()` from `\@changesets/get-github-info`
34
+ * within `Effect.tryPromise`, adapting its structured `CommitInfo`
35
+ * return to the legacy {@link GitHubCommitInfo} shape. An `undefined`
36
+ * result (commit or repo not found) is treated as a thrown error so it
37
+ * is mapped to the same {@link GitHubApiError} failure channel. Any
38
+ * thrown error is caught and mapped to a {@link GitHubApiError} with
39
+ * the operation set to `"getCommitInfo"`.
30
40
  *
31
41
  * Requires a `GITHUB_TOKEN` environment variable to be set for
32
42
  * authenticated API access (the upstream library reads it directly).
@@ -39,13 +49,25 @@ let effect = require("effect");
39
49
  */
40
50
  function getGitHubInfo(params) {
41
51
  return effect.Effect.tryPromise({
42
- try: () => require_changesets_get_github_info_esm.getInfo({
43
- commit: params.commit,
44
- repo: params.repo
45
- }),
52
+ try: async () => {
53
+ const info = await require_index.getCommitInfo({
54
+ commit: params.commit,
55
+ repo: params.repo
56
+ });
57
+ if (info === void 0) throw new Error(`commit ${params.commit} not found in ${params.repo}`);
58
+ return {
59
+ user: info.author?.login ?? null,
60
+ pull: info.pull?.number ?? null,
61
+ links: {
62
+ commit: info.commit.markdownLink,
63
+ pull: info.pull?.markdownLink ?? null,
64
+ user: info.author?.markdownLink ?? null
65
+ }
66
+ };
67
+ },
46
68
  /* v8 ignore next 5 -- error mapping tested via GitHubService test layer */
47
69
  catch: (error) => new require_errors.GitHubApiError({
48
- operation: "getInfo",
70
+ operation: "getCommitInfo",
49
71
  reason: error instanceof Error ? error.message : String(error)
50
72
  })
51
73
  });