@savvy-web/silk-effects 4.0.1 → 4.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.
@@ -5,7 +5,7 @@ import { SilkPublishability, readTargetsBinding } from "../../services/SilkPubli
5
5
  import { Context, Effect, FileSystem, Layer, Path, Result, Schema } from "effect";
6
6
  import { isAbsolute, join, relative, resolve } from "node:path";
7
7
  import { GlobPattern, GlobPatternOptions } from "@effected/glob";
8
- import { descend } from "@effected/walker";
8
+ import { compileAndExpand } from "@effected/walker";
9
9
  import { WorkspaceDiscovery } from "@effected/workspaces";
10
10
 
11
11
  //#region src/changesets/services/config-inspector.ts
@@ -172,23 +172,13 @@ function normalizeLegacyOptions(options, configPath) {
172
172
  /** Match dotfiles, mirroring the former tinyglobby `dot: true` behavior. */
173
173
  const GLOB_OPTIONS = GlobPatternOptions.make({ dot: true });
174
174
  /**
175
- * Compile `glob` via `@effected/glob`, folding a compile-guard trip
176
- * (over-length pattern, brace-expansion budget, nesting depth) into a
177
- * {@link ConfigurationError} naming the offending glob on the typed channel.
178
- */
179
- function compileGlob(glob) {
180
- return GlobPattern.compile(glob, GLOB_OPTIONS).pipe(Effect.mapError((error) => new ConfigurationError({
181
- field: "glob",
182
- reason: `Invalid glob pattern ${JSON.stringify(glob)}: ${error.message}`
183
- })));
184
- }
185
175
  /**
186
176
  * Pure attribution helper: does `glob` (under this service's `dot: true`
187
177
  * semantics) match the repo-relative POSIX path `rel`? An uncompilable
188
178
  * pattern matches nothing.
189
179
  */
190
180
  function globMatchesRel(glob, rel) {
191
- const result = Effect.runSync(Effect.result(GlobPattern.compile(glob, GLOB_OPTIONS)));
181
+ const result = GlobPattern.compileResult(glob, GLOB_OPTIONS);
192
182
  return Result.isSuccess(result) && result.success.matches(rel);
193
183
  }
194
184
  /**
@@ -204,13 +194,14 @@ function globMatchesRel(glob, rel) {
204
194
  * module already speaks POSIX-relative match paths).
205
195
  */
206
196
  function materializeGlob(glob, cwd) {
207
- return compileGlob(glob).pipe(Effect.flatMap((pattern) => descend(pattern, {
197
+ return compileAndExpand(glob, {
208
198
  cwd,
209
- onUnreadable: "skip"
199
+ onUnreadable: "skip",
200
+ glob: GLOB_OPTIONS
210
201
  }).pipe(Effect.mapError((error) => new ConfigurationError({
211
202
  field: "glob",
212
- reason: `Failed to materialize glob ${JSON.stringify(glob)}: ${error.message}`
213
- })), Effect.provide(Path.layer))));
203
+ reason: error.stage === "compile" ? `Invalid glob pattern ${JSON.stringify(glob)}: ${error.cause.message}` : `Failed to materialize glob ${JSON.stringify(glob)}: ${error.cause.message}`
204
+ })), Effect.provide(Path.layer));
214
205
  }
215
206
  /**
216
207
  * Determine whether `child` is the same directory as `parent` or sits inside
@@ -1,10 +1,10 @@
1
1
  import { LegacyVersionFilesSchema } from "../schemas/version-files.js";
2
2
  import { jsonPathGet, jsonPathResolve, parseJsonPath } from "./jsonpath.js";
3
- import { Effect, Option, Path, Schema } from "effect";
3
+ import { Effect, Path, Schema } from "effect";
4
4
  import { readFileSync, writeFileSync } from "node:fs";
5
5
  import { join, relative, resolve } from "node:path";
6
- import { GlobPattern } from "@effected/glob";
7
- import { descend } from "@effected/walker";
6
+ import { GlobPatternOptions } from "@effected/glob";
7
+ import { compileAndExpand } from "@effected/walker";
8
8
  import { Jsonc, JsoncEdit, JsoncFormattingOptions, JsoncModifier } from "@effected/jsonc";
9
9
 
10
10
  //#region src/changesets/utils/version-files.ts
@@ -405,19 +405,29 @@ var VersionFiles = class VersionFiles {
405
405
  }
406
406
  };
407
407
  /**
408
+ * Match dotfiles, matching `ConfigInspector`'s glob dialect.
409
+ *
410
+ * @remarks
411
+ * This module previously compiled with minimatch DEFAULTS while
412
+ * `ConfigInspector` compiled with `dot: true`, so a wildcard segment matching
413
+ * a dotted directory was attributed to a package but never materialized (or
414
+ * the reverse). The two paths must agree: attribution and materialization
415
+ * answer the same question about the same glob.
416
+ */
417
+ const GLOB_OPTIONS = GlobPatternOptions.make({ dot: true });
418
+ /**
408
419
  * Expand a glob pattern against the filesystem, returning matching FILE paths
409
420
  * relative to `cwd` (POSIX separators), sorted by relative path.
410
421
  *
411
422
  * @remarks
412
- * The walk is `@effected/walker`'s `descend` (literal fast path,
423
+ * The walk is `@effected/walker`'s `compileAndExpand` (literal fast path,
413
424
  * `enumerationPrefix` bounding, `node_modules`/`.git` pruning), with
414
425
  * `onUnreadable: "skip"` preserving this module's silent-skip policy for
415
- * unreadable directories. Matching semantics are minimatch DEFAULTS via the
416
- * compiled pattern notably, wildcards do not match dotfiles, same as the
417
- * previous `tinyglobby` defaults. An uncompilable pattern expands to no
418
- * matches. `descend`'s `Path` requirement is satisfied internally with the
419
- * core POSIX `Path.layer` this module already speaks POSIX relative match
420
- * paths and node-bound absolute paths throughout.
426
+ * unreadable directories. Matching semantics are {@link GLOB_OPTIONS}
427
+ * wildcards DO match dotfiles, aligning this module with `ConfigInspector`. An
428
+ * uncompilable pattern expands to no matches. The `Path` requirement is
429
+ * satisfied internally with the core POSIX `Path.layer` this module already
430
+ * speaks POSIX relative match paths and node-bound absolute paths throughout.
421
431
  *
422
432
  * @param source - The glob pattern, repo-relative
423
433
  * @param cwd - Absolute directory the pattern is resolved against
@@ -426,13 +436,11 @@ var VersionFiles = class VersionFiles {
426
436
  * @internal
427
437
  */
428
438
  function expandGlob(source, cwd) {
429
- return Effect.option(GlobPattern.compile(source)).pipe(Effect.flatMap(Option.match({
430
- onNone: () => Effect.succeed([]),
431
- onSome: (pattern) => descend(pattern, {
432
- cwd,
433
- onUnreadable: "skip"
434
- })
435
- })), Effect.provide(Path.layer));
439
+ return compileAndExpand(source, {
440
+ cwd,
441
+ onUnreadable: "skip",
442
+ glob: GLOB_OPTIONS
443
+ }).pipe(Effect.catch((error) => error.stage === "compile" ? Effect.succeed([]) : Effect.fail(error)), Effect.provide(Path.layer));
436
444
  }
437
445
  /**
438
446
  * Read the `version` field from a `package.json` in the given directory.
package/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { Plugin } from "unified";
3
3
  import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
4
4
  import { PackageManagerDetector, PublishConfig, PublishTarget, PublishabilityDetector, WorkspaceDiscovery, WorkspaceDiscoveryFailure, WorkspacePackage, WorkspaceRoot, WorkspaceSnapshotAtFailure, WorkspaceSnapshotWorktreeFailure, WorkspaceSnapshots, WorkspaceStateSnapshot, WorkspacesOptions } from "@effected/workspaces";
5
5
  import { Git } from "@effected/git";
6
- import { DescendError } from "@effected/walker";
6
+ import { GlobExpansionError } from "@effected/walker";
7
7
  //#endregion
8
8
  //#region src/changesets/categories/types.d.ts
9
9
  /**
@@ -287,7 +287,7 @@ declare class Categories {
287
287
  static isValidHeading(heading: string): boolean;
288
288
  }
289
289
  //#endregion
290
- //#region ../../node_modules/.pnpm/@changesets+types@7.0.0-next.6/node_modules/@changesets/types/dist/index.d.mts
290
+ //#region ../../node_modules/.pnpm/@changesets+types@7.0.0-next.7/node_modules/@changesets/types/dist/index.d.mts
291
291
  //#region src/index.d.ts
292
292
  type MaybePromise<T> = T | Promise<T>;
293
293
  type VersionType$1 = "major" | "minor" | "patch" | "none";
@@ -360,10 +360,13 @@ type Config = {
360
360
  * The formatter to use to format changesets and changelogs. Set `false` to disable formatting.
361
361
  * The default value of `"auto"` will auto-detect the formatter based on the project's configuration files.
362
362
  */
363
- format: "auto" | "prettier" | "oxfmt" | "deno" | "dprint" | false; /** Features enabled for Private packages */
364
- privatePackages: PrivatePackages; /** The minimum bump type to trigger automatic update of internal dependencies that are part of the same release */
363
+ format: "auto" | "prettier" | "oxfmt" | "deno" | "dprint" | false;
364
+ /** Features enabled for Private packages */
365
+ privatePackages: PrivatePackages;
366
+ /** The minimum bump type to trigger automatic update of internal dependencies that are part of the same release */
365
367
  updateInternalDependencies: "patch" | "minor";
366
- ignore: ReadonlyArray<string>; /** This is supposed to be used with pnpm's `link-workspace-packages: false` and Berry's `enableTransparentWorkspaces: false` */
368
+ ignore: ReadonlyArray<string>;
369
+ /** This is supposed to be used with pnpm's `link-workspace-packages: false` and Berry's `enableTransparentWorkspaces: false` */
367
370
  bumpVersionsWithWorkspaceProtocolOnly?: boolean;
368
371
  ___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH: Required<ExperimentalOptions>;
369
372
  snapshot: {
@@ -4928,7 +4931,7 @@ declare class VersionFiles {
4928
4931
  * @param cwd - Project root directory
4929
4932
  * @returns Effect of `[filePath, config]` tuples
4930
4933
  */
4931
- static resolveGlobs(configs: readonly LegacyVersionFileConfig[], cwd: string): Effect.Effect<Array<[string, LegacyVersionFileConfig]>, DescendError, FileSystem.FileSystem>;
4934
+ static resolveGlobs(configs: readonly LegacyVersionFileConfig[], cwd: string): Effect.Effect<Array<[string, LegacyVersionFileConfig]>, GlobExpansionError, FileSystem.FileSystem>;
4932
4935
  /**
4933
4936
  * Detect indentation from file content.
4934
4937
  *
@@ -5030,7 +5033,7 @@ declare class VersionFiles {
5030
5033
  name: string;
5031
5034
  version: string;
5032
5035
  path: string;
5033
- }>): Effect.Effect<VersionFileUpdate[], DescendError, FileSystem.FileSystem>;
5036
+ }>): Effect.Effect<VersionFileUpdate[], GlobExpansionError, FileSystem.FileSystem>;
5034
5037
  /**
5035
5038
  * Apply version-file updates from the resolved (post-`ConfigInspector`)
5036
5039
  * representation. Each {@link ResolvedPackageScope} already names the
@@ -5174,7 +5177,7 @@ interface TokenTypeMap {
5174
5177
  chunkString: 'chunkString';
5175
5178
  }
5176
5179
  //#endregion
5177
- //#region ../../node_modules/.pnpm/markdownlint@0.41.1/node_modules/markdownlint/lib/markdownlint.d.mts
5180
+ //#region ../../node_modules/.pnpm/markdownlint@0.41.1_supports-color@8.1.1/node_modules/markdownlint/lib/markdownlint.d.mts
5178
5181
  /**
5179
5182
  * Function to implement rule logic.
5180
5183
  */
@@ -5447,7 +5450,7 @@ type Rule$2 = {
5447
5450
  */
5448
5451
  type RuleConfiguration = boolean | any;
5449
5452
  //#endregion
5450
- //#region ../../node_modules/.pnpm/markdownlint@0.41.1/node_modules/markdownlint/lib/exports.d.mts
5453
+ //#region ../../node_modules/.pnpm/markdownlint@0.41.1_supports-color@8.1.1/node_modules/markdownlint/lib/exports.d.mts
5451
5454
  type Rule$1 = Rule$2;
5452
5455
  //#endregion
5453
5456
  //#region src/changesets/markdownlint/rules/content-structure.d.ts
@@ -7281,7 +7284,7 @@ declare class Markdown {
7281
7284
  /**
7282
7285
  * Handler for package.json files.
7283
7286
  *
7284
- * Sorts fields with sort-package-json and formats with Biome.
7287
+ * Sorts fields with @effected/package-json and formats with Biome.
7285
7288
  *
7286
7289
  * @example
7287
7290
  * ```typescript
@@ -7350,12 +7353,20 @@ declare class PackageJson {
7350
7353
  * Sort the keys of a package.json document string.
7351
7354
  *
7352
7355
  * @remarks
7353
- * Pure transform over the file contents using `sort-package-json`. Used by
7354
- * the `savvy lint fmt package-json` subcommand so the CLI does not depend on
7355
- * `sort-package-json` directly.
7356
+ * Pure transform over the file contents using `@effected/package-json`'s
7357
+ * `PackageJsonFormat.formatToString` the tolerant text path, which sorts
7358
+ * canonically without decoding through the strict `Package` schema (so a
7359
+ * private or version-less root is sorted rather than rejected). Byte-verified
7360
+ * identical to the previous `sort-package-json` output on this repo's
7361
+ * manifests. Used by the `savvy lint fmt package-json` subcommand so the CLI
7362
+ * does not depend on a sorter directly.
7363
+ *
7364
+ * Unparseable content is returned UNCHANGED rather than throwing: a formatter
7365
+ * must not mangle a file it cannot read, and the surrounding Biome pass
7366
+ * reports the syntax error.
7356
7367
  *
7357
7368
  * @param content - The raw package.json file contents
7358
- * @returns The sorted package.json file contents
7369
+ * @returns The sorted package.json file contents, or `content` if unparseable
7359
7370
  */
7360
7371
  static sortContent(content: string): string;
7361
7372
  /**
@@ -7433,6 +7444,26 @@ declare class PnpmWorkspace {
7433
7444
  * @returns Sorted content
7434
7445
  */
7435
7446
  static sortContent(content: PnpmWorkspaceContent): PnpmWorkspaceContent;
7447
+ /**
7448
+ * Stringify sorted workspace content to the repo's canonical YAML byte format.
7449
+ *
7450
+ * @remarks
7451
+ * The single source of truth for pnpm-workspace.yaml formatting. Both
7452
+ * {@link create} and the `savvy lint fmt pnpm-workspace` CLI subcommand route
7453
+ * through here so the two paths cannot drift.
7454
+ *
7455
+ * {@link DEFAULT_STRINGIFY_OPTIONS} produces the repo's byte format directly.
7456
+ * The former Prettier post-process — which existed only to re-indent block
7457
+ * sequences and re-quote scalars — is gone: `indentSequences` and
7458
+ * `quoteStyle` now express both, so there is no second printer to drift from.
7459
+ *
7460
+ * Still `async` for source compatibility with existing callers; it performs
7461
+ * no asynchronous work and can become synchronous in the next major.
7462
+ *
7463
+ * @param content - Sorted pnpm-workspace.yaml content
7464
+ * @returns The formatted YAML source
7465
+ */
7466
+ static formatContent(content: PnpmWorkspaceContent): Promise<string>;
7436
7467
  /**
7437
7468
  * Create a handler that returns a CLI command to sort/format pnpm-workspace.yaml.
7438
7469
  *
@@ -10238,9 +10269,9 @@ declare const SilkPublishabilityDetectorLive: Layer.Layer<PublishabilityDetector
10238
10269
  *
10239
10270
  * @remarks Requires `FileSystem` and {@link ChangesetConfig} at build.
10240
10271
  * The kit's `detect` contract no longer receives the workspace root, so the changeset
10241
- * lookups derive it per package from the package's own discovery coordinates
10242
- * (`pkg.path` ascended by `pkg.relativePath` — never a filesystem marker walk,
10243
- * which could escape an unmarked root and read the wrong `.changeset/config.json`).
10272
+ * lookups read it from `pkg.workspaceRoot` the discovery root the package was found
10273
+ * against, never a filesystem marker walk, which could escape an unmarked root and read
10274
+ * the wrong `.changeset/config.json`.
10244
10275
  *
10245
10276
  * @since 0.4.0
10246
10277
  * @public
@@ -1,19 +1,20 @@
1
1
  import { Command } from "../utils/Command.js";
2
2
  import { Filter } from "../utils/Filter.js";
3
3
  import { isWorkspacePackagePath } from "../utils/Workspace.js";
4
+ import { Result } from "effect";
4
5
  import { readFileSync, writeFileSync } from "node:fs";
5
- import sortPackageJson from "sort-package-json";
6
+ import { PackageJsonFormat } from "@effected/package-json";
6
7
 
7
8
  //#region src/lint/handlers/PackageJson.ts
8
9
  /**
9
10
  * Handler for package.json files.
10
11
  *
11
- * Sorts fields with sort-package-json and formats with Biome.
12
+ * Sorts fields with @effected/package-json and formats with Biome.
12
13
  */
13
14
  /**
14
15
  * Handler for package.json files.
15
16
  *
16
- * Sorts fields with sort-package-json and formats with Biome.
17
+ * Sorts fields with @effected/package-json and formats with Biome.
17
18
  *
18
19
  * @example
19
20
  * ```typescript
@@ -91,15 +92,24 @@ var PackageJson = class PackageJson {
91
92
  * Sort the keys of a package.json document string.
92
93
  *
93
94
  * @remarks
94
- * Pure transform over the file contents using `sort-package-json`. Used by
95
- * the `savvy lint fmt package-json` subcommand so the CLI does not depend on
96
- * `sort-package-json` directly.
95
+ * Pure transform over the file contents using `@effected/package-json`'s
96
+ * `PackageJsonFormat.formatToString` the tolerant text path, which sorts
97
+ * canonically without decoding through the strict `Package` schema (so a
98
+ * private or version-less root is sorted rather than rejected). Byte-verified
99
+ * identical to the previous `sort-package-json` output on this repo's
100
+ * manifests. Used by the `savvy lint fmt package-json` subcommand so the CLI
101
+ * does not depend on a sorter directly.
102
+ *
103
+ * Unparseable content is returned UNCHANGED rather than throwing: a formatter
104
+ * must not mangle a file it cannot read, and the surrounding Biome pass
105
+ * reports the syntax error.
97
106
  *
98
107
  * @param content - The raw package.json file contents
99
- * @returns The sorted package.json file contents
108
+ * @returns The sorted package.json file contents, or `content` if unparseable
100
109
  */
101
110
  static sortContent(content) {
102
- return sortPackageJson(content);
111
+ const result = PackageJsonFormat.formatToString(content);
112
+ return Result.isSuccess(result) ? result.success : content;
103
113
  }
104
114
  /**
105
115
  * Create a handler with custom options.
@@ -116,7 +126,7 @@ var PackageJson = class PackageJson {
116
126
  if (filtered.length === 0) return [];
117
127
  if (!skipSort) for (const filepath of filtered) {
118
128
  const content = readFileSync(filepath, "utf-8");
119
- const sorted = sortPackageJson(content);
129
+ const sorted = PackageJson.sortContent(content);
120
130
  if (sorted !== content) writeFileSync(filepath, sorted, "utf-8");
121
131
  }
122
132
  if (skipFormat) return [];
@@ -2,7 +2,6 @@ import { Command } from "../utils/Command.js";
2
2
  import { Effect, Result } from "effect";
3
3
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
4
4
  import { Yaml, YamlStringifyOptions } from "@effected/yaml";
5
- import { format, resolveConfig } from "prettier";
6
5
 
7
6
  //#region src/lint/handlers/PnpmWorkspace.ts
8
7
  /**
@@ -14,18 +13,21 @@ import { format, resolveConfig } from "prettier";
14
13
  * Default YAML stringify options for consistent formatting.
15
14
  *
16
15
  * @remarks
17
- * `lineWidth: 0` disables line wrapping, matching the v3 `yaml` package
18
- * behavior. `@effected/yaml` emits block sequences without the extra
19
- * two-space indentation the v3 `yaml` package used, so the stringified
20
- * output is normalized through Prettier's YAML printer below — probed
21
- * byte-identical to the v3 `yaml.stringify(..., { indent: 2, lineWidth: 0,
22
- * singleQuote: false })` output on this repo's real `pnpm-workspace.yaml`
23
- * and on hostile synthetic shapes (quoted keys, block scalars, nested
24
- * sequences of maps).
16
+ * `lineWidth: 0` disables line wrapping, `indentSequences: true` indents block
17
+ * sequences one level under their key, and `quoteStyle: "double"` selects the
18
+ * quote character for plain scalars that require quoting. Together these
19
+ * reproduce the v3 `yaml.stringify(..., { indent: 2, lineWidth: 0,
20
+ * singleQuote: false })` byte format directly probed byte-identical to the
21
+ * previous Prettier-normalized output on this repo's real
22
+ * `pnpm-workspace.yaml` and on hostile synthetic shapes (scoped package keys,
23
+ * block scalars, nested sequences of maps), which is what let the Prettier
24
+ * post-process be removed.
25
25
  */
26
26
  const DEFAULT_STRINGIFY_OPTIONS = new YamlStringifyOptions({
27
27
  indent: 2,
28
- lineWidth: 0
28
+ lineWidth: 0,
29
+ indentSequences: true,
30
+ quoteStyle: "double"
29
31
  });
30
32
  /**
31
33
  * Handler for pnpm-workspace.yaml.
@@ -101,6 +103,28 @@ var PnpmWorkspace = class PnpmWorkspace {
101
103
  return result;
102
104
  }
103
105
  /**
106
+ * Stringify sorted workspace content to the repo's canonical YAML byte format.
107
+ *
108
+ * @remarks
109
+ * The single source of truth for pnpm-workspace.yaml formatting. Both
110
+ * {@link create} and the `savvy lint fmt pnpm-workspace` CLI subcommand route
111
+ * through here so the two paths cannot drift.
112
+ *
113
+ * {@link DEFAULT_STRINGIFY_OPTIONS} produces the repo's byte format directly.
114
+ * The former Prettier post-process — which existed only to re-indent block
115
+ * sequences and re-quote scalars — is gone: `indentSequences` and
116
+ * `quoteStyle` now express both, so there is no second printer to drift from.
117
+ *
118
+ * Still `async` for source compatibility with existing callers; it performs
119
+ * no asynchronous work and can become synchronous in the next major.
120
+ *
121
+ * @param content - Sorted pnpm-workspace.yaml content
122
+ * @returns The formatted YAML source
123
+ */
124
+ static async formatContent(content) {
125
+ return Effect.runSync(Yaml.stringify(content, DEFAULT_STRINGIFY_OPTIONS));
126
+ }
127
+ /**
104
128
  * Create a handler that returns a CLI command to sort/format pnpm-workspace.yaml.
105
129
  *
106
130
  * @remarks
@@ -139,11 +163,7 @@ var PnpmWorkspace = class PnpmWorkspace {
139
163
  let parsed = parseResult.success;
140
164
  if (!skipSort) parsed = PnpmWorkspace.sortContent(parsed);
141
165
  if (!skipSort || !skipFormat) {
142
- writeFileSync(filepath, await format(Effect.runSync(Yaml.stringify(parsed, DEFAULT_STRINGIFY_OPTIONS)), {
143
- ...await resolveConfig(filepath),
144
- filepath,
145
- parser: "yaml"
146
- }), "utf-8");
166
+ writeFileSync(filepath, await PnpmWorkspace.formatContent(parsed), "utf-8");
147
167
  return [];
148
168
  }
149
169
  return [];
@@ -27,7 +27,7 @@ let cachedPaths = UNRESOLVED;
27
27
  */
28
28
  function getWorkspaceRoot() {
29
29
  if (cachedRoot !== UNRESOLVED) return cachedRoot;
30
- cachedRoot = findWorkspaceRootSync(nodeSyncOps);
30
+ cachedRoot = findWorkspaceRootSync(process.cwd(), nodeSyncOps);
31
31
  return cachedRoot;
32
32
  }
33
33
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/silk-effects",
3
- "version": "4.0.1",
3
+ "version": "4.2.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",
@@ -33,13 +33,13 @@
33
33
  "@changesets/config": "^4.0.0-next.6",
34
34
  "@changesets/get-github-info": "^1.0.0-next.3",
35
35
  "@changesets/get-release-plan": "^5.0.0-next.7",
36
- "@effected/git": "^0.4.0",
37
- "@effected/glob": "^0.1.1",
38
- "@effected/jsonc": "^0.2.0",
39
- "@effected/package-json": "^0.3.0",
40
- "@effected/walker": "^0.2.1",
41
- "@effected/workspaces": "^0.3.1",
42
- "@effected/yaml": "^0.3.0",
36
+ "@effected/git": "^0.4.1",
37
+ "@effected/glob": "^0.2.0",
38
+ "@effected/jsonc": "^0.5.0",
39
+ "@effected/package-json": "^0.4.1",
40
+ "@effected/walker": "^0.3.1",
41
+ "@effected/workspaces": "^0.5.2",
42
+ "@effected/yaml": "^0.5.0",
43
43
  "@manypkg/get-packages": "^3.1.0",
44
44
  "mdast-util-heading-range": "^4.0.0",
45
45
  "mdast-util-to-string": "^4.0.0",
@@ -48,13 +48,12 @@
48
48
  "remark-parse": "^11.0.0",
49
49
  "remark-stringify": "^11.0.0",
50
50
  "shell-quote": "^1.10.0",
51
- "sort-package-json": "^4.0.0",
52
51
  "unified": "^11.0.5",
53
52
  "unified-lint-rule": "^3.0.1",
54
53
  "unist-util-visit": "^5.1.0",
55
54
  "yaml-lint": "^1.7.0"
56
55
  },
57
56
  "peerDependencies": {
58
- "effect": "4.0.0-beta.98"
57
+ "effect": "4.0.0-beta.99"
59
58
  }
60
59
  }
@@ -244,34 +244,15 @@ const SilkPublishabilityDetectorLive = Layer.effect(PublishabilityDetector, Effe
244
244
  }) };
245
245
  }));
246
246
  /**
247
- * The workspace root a package was discovered against, derived from its own
248
- * coordinates: `relativePath` is the package directory relative to the
249
- * discovery root (POSIX, `"."` for the root package), so ascending one level
250
- * per path segment from `pkg.path` lands exactly on that root.
251
- *
252
- * @remarks
253
- * Derivation is deliberate — probing the filesystem for workspace markers
254
- * (`WorkspaceRoot.find`) can walk PAST the intended root when that root
255
- * carries no marker (a fixture tree, a bare directory) and land on an
256
- * enclosing workspace, silently swapping in that outer root's
257
- * `.changeset/config.json` and dropping the ignore/mode gating (the #209
258
- * regression class). The discovery root needs no probing: whoever built the
259
- * `WorkspacePackage` already knew it.
260
- */
261
- const packageRoot = (pkg) => {
262
- const segments = pkg.relativePath.split("/").filter((segment) => segment !== "" && segment !== ".");
263
- return segments.length === 0 ? pkg.path : join(pkg.path, ...segments.map(() => ".."));
264
- };
265
- /**
266
247
  * Ignore-aware override of `PublishabilityDetector`. `detect` short-circuits to `[]`
267
248
  * for changeset-ignored packages, then dispatches on `ChangesetConfig.mode`:
268
249
  * `none` → `[]`; `silk` → `SilkPublishability.detect`; `vanilla` → the library default.
269
250
  *
270
251
  * @remarks Requires `FileSystem` and {@link ChangesetConfig} at build.
271
252
  * The kit's `detect` contract no longer receives the workspace root, so the changeset
272
- * lookups derive it per package from the package's own discovery coordinates
273
- * (`pkg.path` ascended by `pkg.relativePath` — never a filesystem marker walk,
274
- * which could escape an unmarked root and read the wrong `.changeset/config.json`).
253
+ * lookups read it from `pkg.workspaceRoot` the discovery root the package was found
254
+ * against, never a filesystem marker walk, which could escape an unmarked root and read
255
+ * the wrong `.changeset/config.json`.
275
256
  *
276
257
  * @since 0.4.0
277
258
  * @public
@@ -281,7 +262,7 @@ const PublishabilityDetectorAdaptiveLive = Layer.effect(PublishabilityDetector,
281
262
  const config = yield* ChangesetConfig;
282
263
  const vanilla = yield* Effect.provide(PublishabilityDetector, PublishabilityDetector.layer);
283
264
  return { detect: (pkg) => Effect.gen(function* () {
284
- const root = packageRoot(pkg);
265
+ const root = pkg.workspaceRoot;
285
266
  if (yield* config.isIgnored(pkg.name, root)) return [];
286
267
  const mode = yield* config.mode(root);
287
268
  if (mode === "none") return [];
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.58.10"
8
+ "packageVersion": "7.58.11"
9
9
  }
10
10
  ]
11
11
  }