@effected/workspaces 0.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.
package/index.d.ts ADDED
@@ -0,0 +1,1559 @@
1
+ import { Context, Effect, FileSystem, Layer, Option, Path, Schema } from "effect";
2
+ import { Git, GitCommandError, NotARepositoryError, UnknownRefError } from "@effected/git";
3
+ import { CatalogResolver, WorkspaceResolver } from "@effected/npm";
4
+ import { GlobPattern } from "@effected/glob";
5
+ import { Lockfile, LockfileFramingError, LockfileIntegrity, LockfileParseError, ResolvedPackage, WorkspaceManifest } from "@effected/lockfiles";
6
+ import { Package } from "@effected/package-json";
7
+ import { ChildProcessSpawner } from "effect/unstable/process";
8
+ //#region src/CatalogAssemblyError.d.ts
9
+ declare const CatalogAssemblyError_base: Schema.Class<CatalogAssemblyError, Schema.TaggedStruct<"CatalogAssemblyError", {
10
+ /**
11
+ * Which input failed: `manifest` for a file-level or top-level shape problem,
12
+ * `catalog` for a malformed catalog block or the double-default duplication,
13
+ * `hooks` for a config-dependency `pnpmfile.cjs` load or replay failure.
14
+ */
15
+ readonly source: Schema.Literals<readonly ["manifest", "catalog", "hooks"]>;
16
+ /** The file, the catalog name, or the config dependency name. */
17
+ readonly path: Schema.String;
18
+ /** The originating failure. */
19
+ readonly cause: Schema.Defect;
20
+ }>, import("effect/Cause").YieldableError>;
21
+ /**
22
+ * Raised when a workspace's catalogs cannot be assembled — a `pnpm-workspace.yaml`
23
+ * that is unreadable or not valid YAML, a root `package.json` `workspaces` field
24
+ * whose shape or catalog blocks are malformed in a way pnpm itself rejects
25
+ * (including the default catalog declared twice), or a config dependency whose
26
+ * `pnpmfile.cjs` cannot be loaded or replayed.
27
+ *
28
+ * @remarks
29
+ * A *missing* `pnpm-workspace.yaml`, an *absent* `workspaces` field, or one
30
+ * explicitly `null` is not an error: there is simply nothing to misread, so
31
+ * assembly yields the empty set. The reader is otherwise **hard-fail by design** —
32
+ * a silently-empty catalog read is the "every dependency looks newly added" bug,
33
+ * because catalog output is load-bearing for snapshot diffing.
34
+ *
35
+ * @public
36
+ */
37
+ declare class CatalogAssemblyError extends CatalogAssemblyError_base {
38
+ /** Renders the failing source into a one-line message. */
39
+ get message(): string;
40
+ }
41
+ //#endregion
42
+ //#region src/WorkspacePackage.d.ts
43
+ declare const PublishConfig_base: Schema.Class<PublishConfig, Schema.Struct<{
44
+ /** Scoped-package visibility. Its presence overrides `private`. */
45
+ readonly access: Schema.optionalKey<Schema.Literals<readonly ["public", "restricted"]>>;
46
+ /** The registry to publish to. */
47
+ readonly registry: Schema.optionalKey<Schema.String>;
48
+ /** A subdirectory to publish instead of the package root. */
49
+ readonly directory: Schema.optionalKey<Schema.String>;
50
+ /** The dist-tag to publish under. */
51
+ readonly tag: Schema.optionalKey<Schema.String>;
52
+ }>, {}>;
53
+ /**
54
+ * The `publishConfig` fields workspace tooling reads.
55
+ *
56
+ * @remarks
57
+ * Deliberately narrow. `@effected/package-json` models `publishConfig` as an
58
+ * open `Record<string, unknown>` for round-trip fidelity, which preserves every
59
+ * key but types none of them; this is the typed projection of the four that
60
+ * decide *where and whether* a package publishes. Unknown keys are ignored, not
61
+ * rejected.
62
+ *
63
+ * @public
64
+ */
65
+ declare class PublishConfig extends PublishConfig_base {}
66
+ /**
67
+ * The result of comparing two {@link WorkspacePackage} dependency snapshots.
68
+ *
69
+ * @remarks
70
+ * Comparison runs across all four dependency kinds combined, so a dependency
71
+ * that moves between kinds at the same version does not appear in the diff.
72
+ *
73
+ * @public
74
+ */
75
+ interface DependencyDiff {
76
+ /** Present in the receiver, absent from the other. */
77
+ readonly added: Record<string, string>;
78
+ /** Present in the other, absent from the receiver. */
79
+ readonly removed: Record<string, string>;
80
+ /** Present in both at different specifiers. */
81
+ readonly changed: Record<string, {
82
+ readonly from: string;
83
+ readonly to: string;
84
+ }>;
85
+ }
86
+ declare const WorkspaceManifestError_base: Schema.Class<WorkspaceManifestError, Schema.TaggedStruct<"WorkspaceManifestError", {
87
+ /** Absolute path to the `package.json` that failed. */
88
+ readonly packageJsonPath: Schema.String;
89
+ /** Whether the file could not be read, or read but not decoded. */
90
+ readonly kind: Schema.Literals<readonly ["read", "decode"]>;
91
+ /** The originating failure, preserved rather than flattened to a string. */
92
+ readonly cause: Schema.Defect;
93
+ }>, import("effect/Cause").YieldableError>;
94
+ /**
95
+ * Raised when a workspace member's `package.json` cannot be read or decoded
96
+ * into the strict `@effected/package-json` `Package` model.
97
+ *
98
+ * @remarks
99
+ * Discovery itself never raises this — it uses the tolerant projection. Only
100
+ * `WorkspacePackage.manifest` does, so opting into the strict model is an
101
+ * explicit, individually recoverable step.
102
+ *
103
+ * @public
104
+ */
105
+ declare class WorkspaceManifestError extends WorkspaceManifestError_base {
106
+ /** Renders the path and failure kind into a one-line message. */
107
+ get message(): string;
108
+ }
109
+ declare const WorkspacePackage_base: Schema.Class<WorkspacePackage, Schema.Struct<{
110
+ /** The package name. */
111
+ readonly name: Schema.NonEmptyString;
112
+ /** The raw `version` string — deliberately not semver-validated. */
113
+ readonly version: Schema.String;
114
+ /** Absolute path to the package directory. */
115
+ readonly path: Schema.NonEmptyString;
116
+ /** Absolute path to the package's `package.json`. */
117
+ readonly packageJsonPath: Schema.NonEmptyString;
118
+ /** POSIX path relative to the workspace root; `"."` for the root package. */
119
+ readonly relativePath: Schema.String;
120
+ /** Whether the package is marked private. */
121
+ readonly private: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.Boolean, never>>;
122
+ /** Production dependencies. */
123
+ readonly dependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
124
+ /** Development dependencies. */
125
+ readonly devDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
126
+ /** Peer dependencies. */
127
+ readonly peerDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
128
+ /** Optional dependencies. */
129
+ readonly optionalDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
130
+ /** The `publishConfig` block, when present. */
131
+ readonly publishConfig: Schema.optionalKey<typeof PublishConfig>;
132
+ }>, {}>;
133
+ /**
134
+ * A single package inside a workspace: the discovery-relevant slice of its
135
+ * `package.json` plus its filesystem location.
136
+ *
137
+ * @remarks
138
+ * Produced by `WorkspaceDiscovery` for every directory the `packages:` patterns
139
+ * enumerate. The root package is always present with `relativePath` `"."`.
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * import { WorkspacePackage } from "@effected/workspaces";
144
+ *
145
+ * const pkg = WorkspacePackage.make({
146
+ * name: "@my-org/utils",
147
+ * version: "1.0.0",
148
+ * path: "/repo/packages/utils",
149
+ * packageJsonPath: "/repo/packages/utils/package.json",
150
+ * relativePath: "packages/utils",
151
+ * });
152
+ *
153
+ * pkg.isRootWorkspace; // false
154
+ * pkg.unscopedName; // "utils"
155
+ * ```
156
+ *
157
+ * @public
158
+ */
159
+ declare class WorkspacePackage extends WorkspacePackage_base {
160
+ /** Whether this is the workspace root package. */
161
+ get isRootWorkspace(): boolean;
162
+ /** Whether the package is publishable in principle (not marked private). */
163
+ get isPublic(): boolean;
164
+ /** The npm scope (`@org`), or `Option.none()` for an unscoped name. */
165
+ get scope(): Option.Option<string>;
166
+ /** The name with any scope stripped. */
167
+ get unscopedName(): string;
168
+ /**
169
+ * Every dependency, merged across the four kinds.
170
+ *
171
+ * @remarks
172
+ * Precedence on a name declared in several kinds runs
173
+ * `dependencies` \> `devDependencies` \> `peerDependencies` \>
174
+ * `optionalDependencies`.
175
+ */
176
+ get allDependencies(): Record<string, string>;
177
+ /** Whether `name` is a production dependency. */
178
+ hasDependency(name: string): boolean;
179
+ /** Whether `name` is a development dependency. */
180
+ hasDevDependency(name: string): boolean;
181
+ /** Whether `name` is a peer dependency. */
182
+ hasPeerDependency(name: string): boolean;
183
+ /** Whether `name` is an optional dependency. */
184
+ hasOptionalDependency(name: string): boolean;
185
+ /** Whether `name` appears in any of the four dependency kinds. */
186
+ hasAnyDependencyOn(name: string): boolean;
187
+ /** The declared specifier for `name`, searched across all four kinds. */
188
+ dependencyVersion(name: string): Option.Option<string>;
189
+ /**
190
+ * Whether any dependency name matches `pattern` — the `minimatch` runtime
191
+ * dependency's one call site, now over `@effected/glob`'s vendored engine.
192
+ *
193
+ * @remarks
194
+ * A `GlobPattern` is total and free to test. A `string` is compiled on every
195
+ * call and an **uncompilable** literal throws: a glob written into a call
196
+ * site is developer wiring, not untrusted input, so it belongs in the defect
197
+ * channel rather than widening the typed channel every caller must branch
198
+ * on. Compile once with `GlobPattern.compile` and pass the result when
199
+ * testing many packages.
200
+ *
201
+ * @param pattern - A compiled pattern, or a source string to compile.
202
+ */
203
+ matchesDependency(pattern: GlobPattern | string): boolean;
204
+ /** Compare this package's dependencies against `other`'s. */
205
+ dependencyDiff(other: WorkspacePackage): DependencyDiff;
206
+ /**
207
+ * Project to `@effected/lockfiles`' `WorkspaceManifest` — the input shape of
208
+ * `LockfileIntegrity.compare`. Total.
209
+ */
210
+ toWorkspaceManifest(): WorkspaceManifest;
211
+ /**
212
+ * Read and decode this package's `package.json` into the strict
213
+ * `@effected/package-json` `Package` model — the bridge from the
214
+ * tolerant discovery projection to the fully typed manifest.
215
+ */
216
+ static readonly manifest: (self: WorkspacePackage) => Effect.Effect<Package, WorkspaceManifestError, FileSystem.FileSystem>;
217
+ /** Instance form of `WorkspacePackage.manifest`. */
218
+ manifest(): Effect.Effect<Package, WorkspaceManifestError, FileSystem.FileSystem>;
219
+ }
220
+ //#endregion
221
+ //#region src/WorkspaceRoot.d.ts
222
+ /**
223
+ * The marker filenames {@link WorkspaceRoot} probes for, in priority order.
224
+ *
225
+ * @public
226
+ */
227
+ declare const WORKSPACE_MARKERS: ReadonlyArray<string>;
228
+ declare const WorkspaceRootNotFoundError_base: Schema.Class<WorkspaceRootNotFoundError, Schema.TaggedStruct<"WorkspaceRootNotFoundError", {
229
+ /** The directory the ascent started from. */
230
+ readonly searchPath: Schema.String;
231
+ /** The marker filenames probed at each ancestor. */
232
+ readonly markers: Schema.$Array<Schema.String>;
233
+ }>, import("effect/Cause").YieldableError>;
234
+ /**
235
+ * Raised when no workspace root can be found by ascending from a directory.
236
+ *
237
+ * @remarks
238
+ * `markers` records what was probed, so the failure names the contract rather
239
+ * than paraphrasing it in prose.
240
+ *
241
+ * @public
242
+ */
243
+ declare class WorkspaceRootNotFoundError extends WorkspaceRootNotFoundError_base {
244
+ /** Renders the search path and probed markers into a one-line message. */
245
+ get message(): string;
246
+ }
247
+ declare const WorkspaceRoot_base: Context.ServiceClass<WorkspaceRoot, "@effected/workspaces/WorkspaceRoot", {
248
+ /**
249
+ * The nearest workspace root at or above `cwd`.
250
+ *
251
+ * @param cwd - The directory to start the ascent from; resolved to an
252
+ * absolute path first.
253
+ */
254
+ readonly find: (cwd: string) => Effect.Effect<string, WorkspaceRootNotFoundError>;
255
+ }>;
256
+ /**
257
+ * Locates the workspace root by ascending from a starting directory.
258
+ *
259
+ * @example
260
+ * ```ts
261
+ * import { WorkspaceRoot } from "@effected/workspaces";
262
+ * import { Effect } from "effect";
263
+ *
264
+ * const program = Effect.gen(function* () {
265
+ * const root = yield* WorkspaceRoot;
266
+ * return yield* root.find("/repo/packages/utils/src");
267
+ * });
268
+ * ```
269
+ *
270
+ * @public
271
+ */
272
+ declare class WorkspaceRoot extends WorkspaceRoot_base {
273
+ /** Builds the service over core `FileSystem` and `Path`. */
274
+ static readonly make: Effect.Effect<{
275
+ readonly find: (cwd: string) => Effect.Effect<string, WorkspaceRootNotFoundError>;
276
+ }, never, FileSystem.FileSystem | Path.Path>;
277
+ /** The live layer. */
278
+ static readonly layer: Layer.Layer<WorkspaceRoot, never, FileSystem.FileSystem | Path.Path>;
279
+ }
280
+ //#endregion
281
+ //#region src/WorkspaceDiscovery.d.ts
282
+ declare const WorkspaceDiscoveryError_base: Schema.Class<WorkspaceDiscoveryError, Schema.TaggedStruct<"WorkspaceDiscoveryError", {
283
+ /** The workspace root discovery was running against. */
284
+ readonly root: Schema.String;
285
+ /** The file that failed. */
286
+ readonly path: Schema.String;
287
+ /** What went wrong with it. */
288
+ readonly kind: Schema.Literals<readonly ["read", "invalidJson", "invalidShape", "invalidYaml", "missingName", "missingVersion"]>;
289
+ /** The originating failure, if there was one. */
290
+ readonly cause: Schema.Defect;
291
+ }>, import("effect/Cause").YieldableError>;
292
+ /**
293
+ * Raised when a workspace member's `package.json` cannot be read, parsed, or
294
+ * used — it is missing, malformed, or lacks a `name` or `version`.
295
+ *
296
+ * @remarks
297
+ * `kind` is the discriminant a caller branches on; `cause` preserves the
298
+ * originating failure rather than flattening it into a sentence.
299
+ *
300
+ * @public
301
+ */
302
+ declare class WorkspaceDiscoveryError extends WorkspaceDiscoveryError_base {
303
+ /** Renders the failing file and kind into a one-line message. */
304
+ get message(): string;
305
+ }
306
+ declare const WorkspacePatternError_base: Schema.Class<WorkspacePatternError, Schema.TaggedStruct<"WorkspacePatternError", {
307
+ /** The workspace root the patterns were expanded against. */
308
+ readonly root: Schema.String;
309
+ /** The offending pattern, verbatim. */
310
+ readonly pattern: Schema.String;
311
+ /** Why it could not be enumerated. */
312
+ readonly kind: Schema.Literals<readonly ["missingBaseDir", "uncompilable", "depthExceeded", "budgetExceeded", "unreadableDirectory"]>;
313
+ /** A short, structured detail — the missing directory, or the bound exceeded. */
314
+ readonly detail: Schema.String;
315
+ }>, import("effect/Cause").YieldableError>;
316
+ /**
317
+ * Raised when a `packages:` pattern cannot be enumerated: its base directory is
318
+ * absent (usually a typo), the descent exceeded its depth cap, or the visit
319
+ * budget was exhausted.
320
+ *
321
+ * @public
322
+ */
323
+ declare class WorkspacePatternError extends WorkspacePatternError_base {
324
+ /** Renders the pattern and failure kind into a one-line message. */
325
+ get message(): string;
326
+ }
327
+ declare const PackageNotFoundError_base: Schema.Class<PackageNotFoundError, Schema.TaggedStruct<"PackageNotFoundError", {
328
+ /** The name that was requested. */
329
+ readonly name: Schema.String;
330
+ /** Every workspace package name that does exist. */
331
+ readonly available: Schema.$Array<Schema.String>;
332
+ }>, import("effect/Cause").YieldableError>;
333
+ /**
334
+ * Raised when a workspace package is requested by a name no member carries.
335
+ *
336
+ * @remarks
337
+ * `available` lists every known member, which is what makes the error
338
+ * actionable — a typo is obvious next to the list it missed.
339
+ *
340
+ * @public
341
+ */
342
+ declare class PackageNotFoundError extends PackageNotFoundError_base {
343
+ /** Renders the requested name into a one-line message. */
344
+ get message(): string;
345
+ }
346
+ declare const WorkspaceInfo_base: Schema.Class<WorkspaceInfo, Schema.Struct<{
347
+ /** Absolute path to the workspace root. */
348
+ readonly root: Schema.String;
349
+ /** The `packages:` patterns, verbatim. */
350
+ readonly patterns: Schema.$Array<Schema.String>;
351
+ }>, {}>;
352
+ /**
353
+ * Top-level facts about a workspace: where it is, what manages it, and the
354
+ * patterns that define its membership.
355
+ *
356
+ * @public
357
+ */
358
+ declare class WorkspaceInfo extends WorkspaceInfo_base {}
359
+ /**
360
+ * Every failure `WorkspaceDiscovery.getPackage` can surface: the discovery
361
+ * failures plus a name that matches no member.
362
+ *
363
+ * @public
364
+ */
365
+ type WorkspaceLookupFailure = WorkspaceRootNotFoundError | WorkspaceDiscoveryError | WorkspacePatternError | PackageNotFoundError;
366
+ /**
367
+ * The error channel of the discovery methods that do not look a package up by
368
+ * name — everything except `getPackage`.
369
+ *
370
+ * @public
371
+ */
372
+ type WorkspaceDiscoveryFailure = Exclude<WorkspaceLookupFailure, PackageNotFoundError>;
373
+ /**
374
+ * Options for the {@link WorkspaceDiscovery} layer.
375
+ *
376
+ * @public
377
+ */
378
+ interface WorkspaceDiscoveryOptions {
379
+ /**
380
+ * The directory the workspace root is resolved from.
381
+ *
382
+ * @defaultValue `process.cwd()`, read lazily on first use — so a
383
+ * `process.chdir` between providing the layer and the first call is
384
+ * honoured.
385
+ */
386
+ readonly cwd?: string;
387
+ /** Descent cap for segment-crossing patterns. Defaults to 32. */
388
+ readonly maxDepth?: number;
389
+ }
390
+ /**
391
+ * The {@link WorkspaceDiscovery} service shape.
392
+ *
393
+ * @public
394
+ */
395
+ interface WorkspaceDiscoveryShape {
396
+ /** Facts about the resolved workspace. */
397
+ readonly info: () => Effect.Effect<WorkspaceInfo, WorkspaceDiscoveryFailure>;
398
+ /** Every workspace package, root first, then the rest sorted by relative path. */
399
+ readonly listPackages: () => Effect.Effect<ReadonlyArray<WorkspacePackage>, WorkspaceDiscoveryFailure>;
400
+ /** The discovered packages keyed by their root-relative importer path. */
401
+ readonly importerMap: () => Effect.Effect<ReadonlyMap<string, WorkspacePackage>, WorkspaceDiscoveryFailure>;
402
+ /** A single package by name. */
403
+ readonly getPackage: (name: string) => Effect.Effect<WorkspacePackage, WorkspaceLookupFailure>;
404
+ /** The package owning an absolute file path, by longest-prefix match. */
405
+ readonly resolveFile: (filePath: string) => Effect.Effect<Option.Option<WorkspacePackage>, WorkspaceDiscoveryFailure>;
406
+ /** The distinct packages owning any of `filePaths`. */
407
+ readonly resolveFiles: (filePaths: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<WorkspacePackage>, WorkspaceDiscoveryFailure>;
408
+ /** Drop the memoized discovery so the next call re-reads the filesystem. */
409
+ readonly refresh: () => Effect.Effect<void>;
410
+ }
411
+ declare const WorkspaceDiscovery_base: Context.ServiceClass<WorkspaceDiscovery, "@effected/workspaces/WorkspaceDiscovery", WorkspaceDiscoveryShape>;
412
+ /**
413
+ * Discovers the packages of a workspace.
414
+ *
415
+ * @remarks
416
+ * Layer construction is O(1): the root walk, pattern read, enumeration and
417
+ * per-package decode all happen on the first method call and are memoized for
418
+ * the lifetime of the layer. A Vitest reporter that builds the layer per call
419
+ * site and never queries it pays nothing.
420
+ *
421
+ * The memo is **success-only**. `Effect.cached` memoizes the first `Exit`,
422
+ * *including an interrupt* — an init interrupted by an unrelated timeout would
423
+ * otherwise brick the layer permanently with a cause outside its declared error
424
+ * channel. A failure or interrupt is therefore retried on the next call, which
425
+ * is a deliberate behaviour change from the v3 library.
426
+ *
427
+ * @example
428
+ * ```ts
429
+ * import { WorkspaceDiscovery } from "@effected/workspaces";
430
+ * import { Effect } from "effect";
431
+ *
432
+ * const program = Effect.gen(function* () {
433
+ * const discovery = yield* WorkspaceDiscovery;
434
+ * const packages = yield* discovery.listPackages();
435
+ * return packages.map((p) => p.name);
436
+ * });
437
+ * ```
438
+ *
439
+ * @public
440
+ */
441
+ declare class WorkspaceDiscovery extends WorkspaceDiscovery_base {
442
+ /**
443
+ * Builds the service. Root resolution is one explicit concern: `cwd` is an
444
+ * option here, never an ambient `process.cwd()` read inside a method.
445
+ */
446
+ static readonly make: (options?: WorkspaceDiscoveryOptions) => Effect.Effect<WorkspaceDiscoveryShape, never, WorkspaceRoot | FileSystem.FileSystem | Path.Path>;
447
+ /**
448
+ * The live layer.
449
+ *
450
+ * @remarks
451
+ * A parameterized layer factory mints a **fresh reference per call**, and
452
+ * layers memoize by reference — bind the result to a `const` and reuse it
453
+ * rather than calling `layer(...)` at each composition site.
454
+ */
455
+ static readonly layer: (options?: WorkspaceDiscoveryOptions) => Layer.Layer<WorkspaceDiscovery, never, WorkspaceRoot | FileSystem.FileSystem | Path.Path>;
456
+ /**
457
+ * The real implementation of `@effected/npm`'s `WorkspaceResolver` contract
458
+ * — the one `@effected/package-json` declares but cannot fill.
459
+ *
460
+ * @remarks
461
+ * `versionOf` returns `Option.none()` for a name that is not a workspace
462
+ * member, per the contract's convention; the `DependencyResolutionError`
463
+ * channel is reserved for a failure of the resolution *mechanism* (an
464
+ * unfindable root, an unreadable manifest), never an ordinary miss.
465
+ *
466
+ * @example
467
+ * ```ts
468
+ * import { Package } from "@effected/package-json";
469
+ * import { WorkspaceDiscovery } from "@effected/workspaces";
470
+ * import { Layer } from "effect";
471
+ *
472
+ * const resolvers = WorkspaceDiscovery.workspaceResolver.pipe(
473
+ * Layer.provide(WorkspaceDiscovery.layer()),
474
+ * );
475
+ * // `Package.resolve` now resolves `workspace:*` for real.
476
+ * ```
477
+ */
478
+ static readonly workspaceResolver: Layer.Layer<WorkspaceResolver, never, WorkspaceDiscovery>;
479
+ }
480
+ //#endregion
481
+ //#region src/ChangeDetector.d.ts
482
+ declare const ChangeDetectionOptions_base: Schema.Class<ChangeDetectionOptions, Schema.Struct<{
483
+ /**
484
+ * The ref to compare against.
485
+ *
486
+ * @defaultValue `"HEAD~1"`
487
+ */
488
+ readonly base: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.String, never>>;
489
+ /**
490
+ * The ref to compare to.
491
+ *
492
+ * @defaultValue `"HEAD"`
493
+ */
494
+ readonly head: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.String, never>>;
495
+ /**
496
+ * Whether to include staged, unstaged and untracked working-tree changes on
497
+ * top of the committed range.
498
+ *
499
+ * @defaultValue `false`
500
+ */
501
+ readonly includeUncommitted: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.Boolean, never>>;
502
+ }>, {}>;
503
+ /**
504
+ * Which git refs to compare, and whether to fold in the working tree.
505
+ *
506
+ * @example
507
+ * ```ts
508
+ * import { ChangeDetectionOptions } from "@effected/workspaces";
509
+ *
510
+ * ChangeDetectionOptions.make({}); // HEAD~1...HEAD
511
+ * ChangeDetectionOptions.make({ base: "origin/main" }); // against a branch
512
+ * ```
513
+ *
514
+ * @public
515
+ */
516
+ declare class ChangeDetectionOptions extends ChangeDetectionOptions_base {}
517
+ declare const ChangeDetectionError_base: Schema.Class<ChangeDetectionError, Schema.TaggedStruct<"ChangeDetectionError", {
518
+ /** The operation that could not run. */
519
+ readonly operation: Schema.String;
520
+ /** The originating failure. */
521
+ readonly cause: Schema.Defect;
522
+ }>, import("effect/Cause").YieldableError>;
523
+ /**
524
+ * Raised when change detection cannot proceed for a reason that is not one of
525
+ * git's own typed failures — the wrapper for "detection has no ground to stand
526
+ * on".
527
+ *
528
+ * @remarks
529
+ * A git command that merely *fails* surfaces as one of `@effected/git`'s typed
530
+ * errors ({@link ChangeDetectionFailure} carries `GitCommandError`,
531
+ * `NotARepositoryError` and `UnknownRefError`) rather than being flattened into
532
+ * this wrapper — a caller branches on git's taxonomy directly.
533
+ *
534
+ * @public
535
+ */
536
+ declare class ChangeDetectionError extends ChangeDetectionError_base {
537
+ /** Renders the failed operation into a one-line message. */
538
+ get message(): string;
539
+ }
540
+ /**
541
+ * Every failure the change-detection methods can surface.
542
+ *
543
+ * @remarks
544
+ * `@effected/git`'s typed errors surface directly alongside
545
+ * {@link ChangeDetectionError} and the discovery failures — a git command that
546
+ * fails is reported as git classified it (`NotARepositoryError` for a
547
+ * non-repository, `UnknownRefError` for a bad ref, `GitCommandError`
548
+ * otherwise), not re-wrapped.
549
+ *
550
+ * @public
551
+ */
552
+ type ChangeDetectionFailure = ChangeDetectionError | GitCommandError | NotARepositoryError | UnknownRefError | WorkspaceDiscoveryFailure;
553
+ /**
554
+ * The {@link ChangeDetector} service shape.
555
+ *
556
+ * @public
557
+ */
558
+ interface ChangeDetectorShape {
559
+ /** The file paths (workspace-root-relative, as git reports them) changed in the range. */
560
+ readonly changedFiles: (options?: ChangeDetectionOptions) => Effect.Effect<ReadonlyArray<string>, ChangeDetectionFailure>;
561
+ /** The workspace packages owning those files. */
562
+ readonly changedPackages: (options?: ChangeDetectionOptions) => Effect.Effect<ReadonlyArray<WorkspacePackage>, ChangeDetectionFailure>;
563
+ /** Those packages plus every workspace package that transitively depends on one. */
564
+ readonly affectedPackages: (options?: ChangeDetectionOptions) => Effect.Effect<ReadonlyArray<WorkspacePackage>, ChangeDetectionFailure>;
565
+ }
566
+ declare const ChangeDetector_base: Context.ServiceClass<ChangeDetector, "@effected/workspaces/ChangeDetector", ChangeDetectorShape>;
567
+ /**
568
+ * Detects which workspace packages a git range touches.
569
+ *
570
+ * @remarks
571
+ * Three depths on one service, cheapest first — raw file paths, the packages
572
+ * owning them, and the transitive blast radius through the dependency graph.
573
+ *
574
+ * @example
575
+ * ```ts
576
+ * import { ChangeDetectionOptions, ChangeDetector } from "@effected/workspaces";
577
+ * import { Effect } from "effect";
578
+ *
579
+ * const program = Effect.gen(function* () {
580
+ * const detector = yield* ChangeDetector;
581
+ * const affected = yield* detector.affectedPackages(
582
+ * ChangeDetectionOptions.make({ base: "origin/main" }),
583
+ * );
584
+ * return affected.map((pkg) => pkg.name);
585
+ * });
586
+ * ```
587
+ *
588
+ * @public
589
+ */
590
+ declare class ChangeDetector extends ChangeDetector_base {
591
+ /** Builds the service over `Git` and {@link WorkspaceDiscovery}. */
592
+ static readonly make: Effect.Effect<ChangeDetectorShape, never, Git | WorkspaceDiscovery>;
593
+ /** The live layer. */
594
+ static readonly layer: Layer.Layer<ChangeDetector, never, Git | WorkspaceDiscovery>;
595
+ }
596
+ //#endregion
597
+ //#region src/ConfigDependencyHooks.d.ts
598
+ /**
599
+ * The {@link ConfigDependencyHooks} service shape.
600
+ *
601
+ * @remarks
602
+ * `inject` is given the workspace root, the manifest's `configDependencies`
603
+ * (name → version+integrity), and the inline-catalog seed as a plain
604
+ * `catalog name → dependency name → range` record, and produces the catalogs the
605
+ * replayed hooks yield. The default (no-op) implementation returns the seed
606
+ * unchanged and loads nothing.
607
+ *
608
+ * @public
609
+ */
610
+ interface ConfigDependencyHooksShape {
611
+ /**
612
+ * Replay each config dependency's `updateConfig` hook over `seed`, in
613
+ * declaration order, and return the resulting catalogs.
614
+ *
615
+ * @param root - The workspace root; config dependencies resolve under
616
+ * `<root>/node_modules/.pnpm-config/<name>`.
617
+ * @param configDependencies - The `configDependencies` map (name →
618
+ * version+integrity) declared in `pnpm-workspace.yaml`.
619
+ * @param seed - The inline catalogs, as `catalog name → dependency → range`.
620
+ */
621
+ readonly inject: (root: string, configDependencies: Readonly<Record<string, string>>, seed: Readonly<Record<string, Readonly<Record<string, string>>>>) => Effect.Effect<Readonly<Record<string, Readonly<Record<string, string>>>>, CatalogAssemblyError>;
622
+ }
623
+ declare const ConfigDependencyHooks_base: Context.ServiceClass<ConfigDependencyHooks, "@effected/workspaces/ConfigDependencyHooks", ConfigDependencyHooksShape>;
624
+ /**
625
+ * Replays a workspace's `configDependencies` `updateConfig` hooks over the inline
626
+ * catalogs — the opt-in seam that lets hook-injected catalogs participate in
627
+ * assembly.
628
+ *
629
+ * @remarks
630
+ * A contract-only service: it declares the shape and ships two layers, never a
631
+ * baked-in default. {@link ConfigDependencyHooks.layerNoop} executes no
632
+ * config-dependency code (it returns the seed untouched) and is what the default
633
+ * {@link WorkspaceCatalogs} layer wires; {@link ConfigDependencyHooks.layerLive}
634
+ * dynamically imports each `pnpmfile.cjs` and replays it, and is wired only by the
635
+ * explicit `WorkspaceCatalogs.layerWithConfigDependencies` opt-in.
636
+ *
637
+ * @public
638
+ */
639
+ declare class ConfigDependencyHooks extends ConfigDependencyHooks_base {
640
+ /**
641
+ * The no-op layer: `inject` returns the seed unchanged and never touches a
642
+ * config dependency. The default {@link WorkspaceCatalogs} layer wires this, so
643
+ * the default catalog path provably executes no config-dependency code.
644
+ */
645
+ static readonly layerNoop: Layer.Layer<ConfigDependencyHooks>;
646
+ /**
647
+ * The live layer: dynamically imports each config dependency's `pnpmfile.cjs`
648
+ * (in process, no subprocess) and replays its `updateConfig` hook over the
649
+ * seed, in declaration order. A dependency without a `pnpmfile.cjs` contributes
650
+ * nothing; a dependency whose file fails to load or replay fails typed with a
651
+ * `hooks`-source {@link CatalogAssemblyError}, never a silent skip.
652
+ *
653
+ * @remarks
654
+ * Node-coupled by design — the `node:fs` / `node:path` / `node:url` imports are
655
+ * the sanctioned Node-only overlay, matching the other seams here. Only ever
656
+ * wired by `WorkspaceCatalogs.layerWithConfigDependencies`.
657
+ */
658
+ static readonly layerLive: Layer.Layer<ConfigDependencyHooks>;
659
+ }
660
+ //#endregion
661
+ //#region src/DependencyGraph.d.ts
662
+ declare const CyclicDependencyError_base: Schema.Class<CyclicDependencyError, Schema.TaggedStruct<"CyclicDependencyError", {
663
+ /** The packages participating in the cycle. */
664
+ readonly cycle: Schema.$Array<Schema.String>;
665
+ }>, import("effect/Cause").YieldableError>;
666
+ /**
667
+ * Raised when the workspace dependency graph cannot be topologically ordered
668
+ * because it contains a cycle.
669
+ *
670
+ * @remarks
671
+ * `cycle` lists every package still carrying unsatisfied dependencies when
672
+ * Kahn's algorithm stalls — the strongly-connected residue, sorted. It is the
673
+ * set to break, not necessarily a single ordered loop.
674
+ *
675
+ * @public
676
+ */
677
+ declare class CyclicDependencyError extends CyclicDependencyError_base {
678
+ /** Renders the cycle members into a one-line message. */
679
+ get message(): string;
680
+ }
681
+ declare const DependencyGraph_base: Schema.Class<DependencyGraph, Schema.Struct<{
682
+ /** The workspace packages the graph is drawn over. */
683
+ readonly packages: Schema.$Array<typeof WorkspacePackage>;
684
+ }>, {}>;
685
+ /**
686
+ * The directed graph of dependencies **between workspace packages**. External
687
+ * npm dependencies are not nodes.
688
+ *
689
+ * @remarks
690
+ * A pure value over the discovered package list, with the edge indexes built
691
+ * lazily into `#private` fields the schema never encodes. Edges are drawn from
692
+ * `dependencies`, `devDependencies`, `peerDependencies` and
693
+ * `optionalDependencies`; a self-edge is dropped.
694
+ *
695
+ * Total accessors never fail; the four fallible operations are `Effect.fn`
696
+ * boundaries.
697
+ *
698
+ * @example
699
+ * ```ts
700
+ * import { DependencyGraph, WorkspaceDiscovery } from "@effected/workspaces";
701
+ * import { Effect } from "effect";
702
+ *
703
+ * const program = Effect.gen(function* () {
704
+ * const discovery = yield* WorkspaceDiscovery;
705
+ * const graph = DependencyGraph.make({ packages: yield* discovery.listPackages() });
706
+ * return yield* graph.levels();
707
+ * });
708
+ * ```
709
+ *
710
+ * @public
711
+ */
712
+ declare class DependencyGraph extends DependencyGraph_base {
713
+ #private;
714
+ /** Every workspace package name, sorted. Total. */
715
+ get names(): ReadonlyArray<string>;
716
+ /** The adjacency map: name → the names it depends on. Total. */
717
+ get adjacency(): ReadonlyMap<string, ReadonlySet<string>>;
718
+ /**
719
+ * Whether the graph contains a cycle. Total.
720
+ *
721
+ * @remarks
722
+ * An explicit-stack DFS with an on-stack set — never recursive, so a long
723
+ * dependency chain cannot overflow.
724
+ */
725
+ get hasCycle(): boolean;
726
+ /** The workspace packages `name` depends on, sorted. */
727
+ readonly dependenciesOf: (name: string) => Effect.Effect<readonly string[], PackageNotFoundError, never>;
728
+ /** The workspace packages that depend on `name`, sorted. */
729
+ readonly dependentsOf: (name: string) => Effect.Effect<readonly string[], PackageNotFoundError, never>;
730
+ /**
731
+ * `name` plus every package that transitively depends on it — the blast
732
+ * radius of a change. Sorted; includes `name` itself.
733
+ */
734
+ readonly affectedBy: (names: readonly string[]) => Effect.Effect<readonly string[], never, never>;
735
+ /**
736
+ * Packages grouped into parallel build levels: level 0 depends on nothing in
737
+ * the workspace, level *n* depends only on levels below it.
738
+ *
739
+ * @remarks
740
+ * Kahn's algorithm over the reverse-edge index — linear, where v3's rescanned
741
+ * the whole adjacency map per processed node. Each level is sorted
742
+ * lexicographically, so the output is deterministic.
743
+ */
744
+ readonly levels: () => Effect.Effect<readonly (readonly string[])[], CyclicDependencyError, never>;
745
+ /** The flattened topological order — `levels()` concatenated. */
746
+ readonly sort: () => Effect.Effect<readonly string[], CyclicDependencyError, never>;
747
+ /**
748
+ * A topological order over `names` plus their transitive workspace
749
+ * dependencies — the build order for a subset.
750
+ */
751
+ readonly sortSubset: (names: readonly string[]) => Effect.Effect<readonly string[], CyclicDependencyError | PackageNotFoundError, never>;
752
+ }
753
+ //#endregion
754
+ //#region src/PackageManagerName.d.ts
755
+ /**
756
+ * The four package managers this package understands.
757
+ *
758
+ * @public
759
+ */
760
+ declare const PackageManagerName: Schema.Literals<readonly ["npm", "pnpm", "yarn", "bun"]>;
761
+ /**
762
+ * The decoded type of {@link (PackageManagerName:variable)}: `"npm" | "pnpm" | "yarn" | "bun"`.
763
+ *
764
+ * @public
765
+ */
766
+ type PackageManagerName = typeof PackageManagerName.Type;
767
+ declare const DetectedPackageManager_base: Schema.Class<DetectedPackageManager, Schema.Struct<{
768
+ /** The detected manager. */
769
+ readonly name: Schema.Literals<readonly ["npm", "pnpm", "yarn", "bun"]>;
770
+ /** Its version, when a manifest field agrees on the manager and carries one. */
771
+ readonly version: Schema.Option<Schema.String>;
772
+ /** The JavaScript runtime the manager implies. */
773
+ readonly runtime: Schema.Literals<readonly ["node", "bun"]>;
774
+ }>, {}>;
775
+ /**
776
+ * The outcome of package-manager detection at a workspace root.
777
+ *
778
+ * @remarks
779
+ * `version` is `Option.none()` unless a manifest field naming the *same* manager
780
+ * that was detected also carries a version — a `packageManager: "yarn@4"` in a
781
+ * pnpm workspace tells us nothing about pnpm's version, so it is not reported as
782
+ * one. The two fields consulted are the corepack top-level `packageManager` and
783
+ * `devEngines.packageManager`; see {@link PackageManagerDetector} for the
784
+ * precedence between them.
785
+ *
786
+ * @public
787
+ */
788
+ declare class DetectedPackageManager extends DetectedPackageManager_base {}
789
+ declare const PackageManagerDetectionError_base: Schema.Class<PackageManagerDetectionError, Schema.TaggedStruct<"PackageManagerDetectionError", {
790
+ /** The workspace root that was probed. */
791
+ readonly root: Schema.String;
792
+ /** The marker files probed, in the order they were probed. */
793
+ readonly checked: Schema.$Array<Schema.String>;
794
+ }>, import("effect/Cause").YieldableError>;
795
+ /**
796
+ * Raised when a directory carries no lockfile and no workspace configuration,
797
+ * so no package manager can be attributed to it.
798
+ *
799
+ * @public
800
+ */
801
+ declare class PackageManagerDetectionError extends PackageManagerDetectionError_base {
802
+ /** Renders the root and probed markers into a one-line message. */
803
+ get message(): string;
804
+ }
805
+ /**
806
+ * Every failure {@link PackageManagerDetector} can surface: no manager could be
807
+ * attributed to the root, or the root's `package.json` exists but cannot be read
808
+ * or parsed.
809
+ *
810
+ * @public
811
+ */
812
+ type PackageManagerDetectionFailure = PackageManagerDetectionError | WorkspaceManifestError;
813
+ declare const PackageManagerDetector_base: Context.ServiceClass<PackageManagerDetector, "@effected/workspaces/PackageManagerDetector", {
814
+ /** Detect the package manager at a workspace root. */
815
+ readonly detect: (root: string) => Effect.Effect<DetectedPackageManager, PackageManagerDetectionFailure>;
816
+ }>;
817
+ /**
818
+ * Detects which package manager owns a workspace root.
819
+ *
820
+ * @remarks
821
+ * **Lockfile evidence is the primary signal** — it is what says which manager
822
+ * actually ran. Priority, first match wins: a `pnpm-workspace.yaml` means pnpm;
823
+ * a bun lockfile *plus* a manifest field naming bun means bun; a `yarn.lock`
824
+ * *plus* a manifest field naming yarn means yarn; a root `package.json` with a
825
+ * `workspaces` field falls back to npm.
826
+ *
827
+ * The manifest conjunction is deliberate: a stray `yarn.lock` in an npm repo is
828
+ * common, and only a declared manager name disambiguates it.
829
+ *
830
+ * **Two manifest fields declare a manager, and they are not interchangeable.**
831
+ * Corepack reads both, and this is the rule that falls out of how it treats
832
+ * them:
833
+ *
834
+ * - `devEngines.packageManager.name` is authoritative for the **name**.
835
+ * Corepack *errors* when a top-level `packageManager` disagrees with it (per
836
+ * `devEngines.packageManager.onFail`), so where both are present and disagree,
837
+ * `devEngines` is the one to believe. When `devEngines` names a manager, the
838
+ * top-level field's name is not consulted as a disambiguator at all.
839
+ * - The top-level `packageManager` is authoritative for the exact **version**:
840
+ * it is the field that carries the integrity hash. Where both name the same
841
+ * manager, its version wins; where it is absent, `devEngines.packageManager.version`
842
+ * supplies the version instead.
843
+ *
844
+ * A version is reported **only when the field it came from names the manager
845
+ * that was actually detected**. A `packageManager: "yarn@4"` in a pnpm workspace
846
+ * says nothing about pnpm's version, so no version is reported — and the same
847
+ * discipline applies to `devEngines`.
848
+ *
849
+ * Malformed manifest *hints* are ignored rather than fatal, matching corepack: a
850
+ * non-object or array `devEngines.packageManager`, a `name` containing `@`, or a
851
+ * version that is not an exact version cannot turn a detectable workspace into a
852
+ * detection failure. A manifest that exists but cannot be **read or parsed** is a
853
+ * different thing entirely and fails with a `WorkspaceManifestError` — a corrupt
854
+ * root manifest is a real problem, not a missing hint.
855
+ *
856
+ * @public
857
+ */
858
+ declare class PackageManagerDetector extends PackageManagerDetector_base {
859
+ /** Builds the service over core `FileSystem` and `Path`. */
860
+ static readonly make: Effect.Effect<{
861
+ readonly detect: (root: string) => Effect.Effect<DetectedPackageManager, PackageManagerDetectionFailure>;
862
+ }, never, FileSystem.FileSystem | Path.Path>;
863
+ /** The live layer. */
864
+ static readonly layer: Layer.Layer<PackageManagerDetector, never, FileSystem.FileSystem | Path.Path>;
865
+ }
866
+ //#endregion
867
+ //#region src/LockfileReader.d.ts
868
+ declare const LockfileReadError_base: Schema.Class<LockfileReadError, Schema.TaggedStruct<"LockfileReadError", {
869
+ /** Absolute path to the lockfile that could not be read. */
870
+ readonly lockfilePath: Schema.String;
871
+ /** The format the detected package manager implies. */
872
+ readonly format: Schema.Literals<readonly ["bun", "npm", "pnpm", "yarn"]>;
873
+ /** The originating failure. */
874
+ readonly cause: Schema.Defect;
875
+ }>, import("effect/Cause").YieldableError>;
876
+ /**
877
+ * Raised when the workspace's lockfile cannot be read off disk.
878
+ *
879
+ * @remarks
880
+ * Parse failures are `@effected/lockfiles`' `LockfileParseError`, not this —
881
+ * this is strictly the IO half.
882
+ *
883
+ * @public
884
+ */
885
+ declare class LockfileReadError extends LockfileReadError_base {
886
+ /** Renders the unreadable path into a one-line message. */
887
+ get message(): string;
888
+ }
889
+ /**
890
+ * Every failure the lockfile methods can surface — the exported init-error
891
+ * union the review named best-in-class DX.
892
+ *
893
+ * @remarks
894
+ * Layer construction does no IO, so every member surfaces from the *methods*
895
+ * rather than from `Layer.build`: the root cannot be found, no package manager
896
+ * can be attributed to it (or its manifest is corrupt), its lockfile cannot be
897
+ * read, the lockfile is malformed, or the lockfile's YAML stream carries no
898
+ * lockfile document.
899
+ *
900
+ * @public
901
+ */
902
+ type LockfileReadFailure = WorkspaceRootNotFoundError | PackageManagerDetectionFailure | LockfileReadError | LockfileParseError | LockfileFramingError;
903
+ /**
904
+ * The {@link LockfileReader} service shape.
905
+ *
906
+ * @public
907
+ */
908
+ interface LockfileReaderShape {
909
+ /** The parsed lockfile, with pnpm importer paths already resolved to real names. */
910
+ readonly read: () => Effect.Effect<Lockfile, LockfileReadFailure>;
911
+ /**
912
+ * The lockfile's record of a package, when it records one.
913
+ *
914
+ * @remarks
915
+ * A name can resolve at **several versions** in one lockfile (two members
916
+ * depending on different majors of the same package). This returns the
917
+ * **first** entry in lockfile order and does not attempt to rank them — there
918
+ * is no single "the" version to return, and picking the highest semver would
919
+ * imply a resolution decision this reader is not entitled to make. Callers
920
+ * that must see every resolution should read `lockfile.packagesNamed(name)`
921
+ * off `read()` directly.
922
+ */
923
+ readonly resolvedVersion: (packageName: string) => Effect.Effect<Option.Option<ResolvedPackage>, LockfileReadFailure>;
924
+ /**
925
+ * Whether the lockfile agrees with the workspace manifests on disk — the
926
+ * pure `LockfileIntegrity.compare`, fed the manifests this package reads.
927
+ */
928
+ readonly integrity: () => Effect.Effect<LockfileIntegrity, LockfileReadFailure | WorkspaceDiscoveryFailure>;
929
+ /** Drop the memoized read so the next call re-reads the lockfile. */
930
+ readonly refresh: () => Effect.Effect<void>;
931
+ }
932
+ /**
933
+ * Options for the {@link LockfileReader} layer.
934
+ *
935
+ * @public
936
+ */
937
+ interface LockfileReaderOptions {
938
+ /**
939
+ * The directory the workspace root is resolved from.
940
+ *
941
+ * @defaultValue `process.cwd()`, read lazily on first use.
942
+ */
943
+ readonly cwd?: string;
944
+ }
945
+ declare const LockfileReader_base: Context.ServiceClass<LockfileReader, "@effected/workspaces/LockfileReader", LockfileReaderShape>;
946
+ /**
947
+ * Reads and parses the workspace's lockfile.
948
+ *
949
+ * @remarks
950
+ * Layer construction is O(1). The root walk, package-manager detection, file
951
+ * read, parse and pnpm name resolution all happen on the first method call and
952
+ * are memoized success-only for the lifetime of the layer.
953
+ *
954
+ * @example
955
+ * ```ts
956
+ * import { LockfileReader } from "@effected/workspaces";
957
+ * import { Effect } from "effect";
958
+ *
959
+ * const program = Effect.gen(function* () {
960
+ * const reader = yield* LockfileReader;
961
+ * const lockfile = yield* reader.read();
962
+ * return lockfile.packages.length;
963
+ * });
964
+ * ```
965
+ *
966
+ * @public
967
+ */
968
+ declare class LockfileReader extends LockfileReader_base {
969
+ /** Builds the service. */
970
+ static readonly make: (options?: LockfileReaderOptions) => Effect.Effect<LockfileReaderShape, never, WorkspaceRoot | PackageManagerDetector | WorkspaceDiscovery | FileSystem.FileSystem | Path.Path>;
971
+ /**
972
+ * The live layer.
973
+ *
974
+ * @remarks
975
+ * Parameterized, so it mints a fresh reference per call — bind it to a
976
+ * `const` and reuse it.
977
+ */
978
+ static readonly layer: (options?: LockfileReaderOptions) => Layer.Layer<LockfileReader, never, WorkspaceRoot | PackageManagerDetector | WorkspaceDiscovery | FileSystem.FileSystem | Path.Path>;
979
+ }
980
+ //#endregion
981
+ //#region src/Publishability.d.ts
982
+ declare const PublishTarget_base: Schema.Class<PublishTarget, Schema.Struct<{
983
+ /** The package name being published. */
984
+ readonly name: Schema.NonEmptyString;
985
+ /** The registry URL. */
986
+ readonly registry: Schema.NonEmptyString;
987
+ /** The directory to publish, relative to the package root; `"."` for the root itself. */
988
+ readonly directory: Schema.String;
989
+ /** Scoped-package visibility. */
990
+ readonly access: Schema.Literals<readonly ["public", "restricted"]>;
991
+ /** Whether to publish with a provenance attestation. */
992
+ readonly provenance: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.Boolean, never>>;
993
+ }>, {}>;
994
+ /**
995
+ * A resolved publish destination for a workspace package.
996
+ *
997
+ * @public
998
+ */
999
+ declare class PublishTarget extends PublishTarget_base {}
1000
+ declare const PublishabilityDetector_base: Context.ServiceClass<PublishabilityDetector, "@effected/workspaces/PublishabilityDetector", {
1001
+ /** The publish targets for a package; empty means it does not publish. */
1002
+ readonly detect: (pkg: WorkspacePackage) => Effect.Effect<ReadonlyArray<PublishTarget>>;
1003
+ }>;
1004
+ /**
1005
+ * Decides whether a workspace package publishes, and to where.
1006
+ *
1007
+ * @remarks
1008
+ * The default layer implements standard npm semantics: a `private` package with
1009
+ * no `publishConfig.access` publishes nowhere; an explicit
1010
+ * `publishConfig.access` overrides `private`; anything else publishes to the
1011
+ * public registry with defaults.
1012
+ *
1013
+ * Those are *npm's* semantics, not necessarily yours. Swap the layer:
1014
+ *
1015
+ * @example
1016
+ * ```ts
1017
+ * import { PublishabilityDetector, PublishTarget } from "@effected/workspaces";
1018
+ * import { Effect, Layer } from "effect";
1019
+ *
1020
+ * const internalOnly = Layer.succeed(PublishabilityDetector, {
1021
+ * detect: (pkg) =>
1022
+ * Effect.succeed(
1023
+ * pkg.name.startsWith("@acme/")
1024
+ * ? [PublishTarget.make({
1025
+ * name: pkg.name,
1026
+ * registry: "https://npm.acme.internal/",
1027
+ * directory: ".",
1028
+ * access: "restricted",
1029
+ * })]
1030
+ * : [],
1031
+ * ),
1032
+ * });
1033
+ * ```
1034
+ *
1035
+ * @public
1036
+ */
1037
+ declare class PublishabilityDetector extends PublishabilityDetector_base {
1038
+ /** Standard npm publishing semantics. Pure — no filesystem, no platform services. */
1039
+ static readonly layer: Layer.Layer<PublishabilityDetector>;
1040
+ }
1041
+ //#endregion
1042
+ //#region src/WorkspaceCatalogs.d.ts
1043
+ declare const CatalogSet_base: Schema.Class<CatalogSet, Schema.Struct<{
1044
+ /** Catalog name → dependency name → version range. */
1045
+ readonly entries: Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.String>>;
1046
+ }>, {}>;
1047
+ /**
1048
+ * An immutable, fully-normalized catalog collection — the one catalog
1049
+ * resolution semantic in the package.
1050
+ *
1051
+ * @remarks
1052
+ * `entries` is catalog name → dependency → range, with pnpm's unnamed
1053
+ * top-level `catalog:` block normalized under the key `"default"`. Lockfile
1054
+ * catalog entries, which pnpm records as `{ specifier, version }`, are
1055
+ * normalized to their `specifier` — the declared range, which is what a catalog
1056
+ * resolves to.
1057
+ *
1058
+ * @public
1059
+ */
1060
+ declare class CatalogSet extends CatalogSet_base {
1061
+ /** The empty set — a workspace with no catalogs. */
1062
+ static empty(): CatalogSet;
1063
+ /** Wrap a pnpm `Catalogs` map, dropping unusable entries. */
1064
+ static fromCatalogs(catalogs: unknown): CatalogSet;
1065
+ /**
1066
+ * The `catalog:` and `catalogs:` blocks of a `pnpm-workspace.yaml` document.
1067
+ *
1068
+ * @param text - The raw YAML text.
1069
+ */
1070
+ static readonly fromWorkspaceYaml: (text: string) => Effect.Effect<CatalogSet, CatalogAssemblyError, never>;
1071
+ /**
1072
+ * The `catalogs:` section of a pnpm lockfile, whose entries are either a bare
1073
+ * range or a `{ specifier, version }` pair.
1074
+ */
1075
+ static fromLockfileCatalogs(raw: unknown): CatalogSet;
1076
+ /**
1077
+ * The catalog set a parsed lockfile records, PM-aware.
1078
+ *
1079
+ * @remarks
1080
+ * Both pnpm and bun record catalogs in the lockfile, in different shapes:
1081
+ * pnpm under `extension.catalogs`, bun under `extension.catalog` /
1082
+ * `extension.catalogs`. Assembly reads whichever the parsed lockfile carries
1083
+ * rather than assuming the pnpm extension. A lockfile with no extension, or a
1084
+ * pnpm one with no catalogs, yields the empty set.
1085
+ *
1086
+ * @param lockfile - A parsed lockfile from `@effected/lockfiles`.
1087
+ */
1088
+ static fromLockfile(lockfile: Lockfile): CatalogSet;
1089
+ /**
1090
+ * A catalog set from bun's `{ catalog, catalogs }` blocks — used for the
1091
+ * `bun.lock` extension and for the root `package.json` `workspaces` block. The
1092
+ * unnamed default catalog normalizes under `"default"`. Tolerant: unusable
1093
+ * values are dropped, never fatal.
1094
+ *
1095
+ * @param blocks - The `catalog` (default) and `catalogs` (named) blocks.
1096
+ */
1097
+ static fromBunBlocks(blocks: {
1098
+ readonly catalog?: unknown;
1099
+ readonly catalogs?: unknown;
1100
+ }): CatalogSet;
1101
+ /**
1102
+ * The `catalog` / `catalogs` blocks of a root `package.json` `workspaces` field
1103
+ * — bun's package.json analogue of pnpm's `pnpm-workspace.yaml` blocks.
1104
+ *
1105
+ * @remarks
1106
+ * **Hard-fail by design**, preserving the semantics catalog output is
1107
+ * load-bearing for: a present-but-malformed `workspaces` shape (a number, a
1108
+ * string, an object with a malformed `packages` / `catalog` / `catalogs`), or
1109
+ * the default catalog declared twice — once as `workspaces.catalog` and again
1110
+ * as `workspaces.catalogs.default` — fails with {@link CatalogAssemblyError}
1111
+ * naming what was wrong. An absent `workspaces` field, one explicitly `null`,
1112
+ * or the plain array form (npm/yarn patterns, which carry no catalogs) yields
1113
+ * the empty set. Presence is checked structurally, so an explicitly-declared
1114
+ * empty `catalog: {}` still counts as a declaration.
1115
+ *
1116
+ * @param text - The raw root `package.json` text.
1117
+ */
1118
+ static readonly fromManifestWorkspaces: (text: string) => Effect.Effect<CatalogSet, CatalogAssemblyError, never>;
1119
+ /** Merge sets. Later sets win per dependency within a catalog. */
1120
+ static merge(...sets: ReadonlyArray<CatalogSet>): CatalogSet;
1121
+ /** Whether any catalog declares anything. */
1122
+ get isEmpty(): boolean;
1123
+ /**
1124
+ * The range a `catalog:` specifier resolves to.
1125
+ *
1126
+ * @remarks
1127
+ * Total: an unmatched dependency, an unknown catalog name, or a non-catalog
1128
+ * specifier all yield `Option.none()`. A *malformed* catalog — one pnpm
1129
+ * itself rejects — also yields `Option.none()` here; the fallible surface is
1130
+ * {@link WorkspaceCatalogs}, which fails typed on assembly instead.
1131
+ *
1132
+ * @param dependency - The package name being resolved.
1133
+ * @param specifier - The declared specifier, e.g. `catalog:` or `catalog:build`.
1134
+ */
1135
+ resolveSpecifier(dependency: string, specifier: string): Option.Option<string>;
1136
+ /**
1137
+ * The range `dependency` carries in a named catalog, or in the default
1138
+ * catalog when `catalog` is `Option.none()`.
1139
+ *
1140
+ * @remarks
1141
+ * The shape `@effected/npm`'s `CatalogResolver` contract asks for.
1142
+ */
1143
+ rangeOf(dependency: string, catalog: Option.Option<string>): Option.Option<string>;
1144
+ }
1145
+ /**
1146
+ * Every failure catalog assembly can surface.
1147
+ *
1148
+ * @public
1149
+ */
1150
+ type CatalogAssemblyFailure = CatalogAssemblyError | WorkspaceRootNotFoundError;
1151
+ /**
1152
+ * The {@link WorkspaceCatalogs} service shape.
1153
+ *
1154
+ * @public
1155
+ */
1156
+ interface WorkspaceCatalogsShape {
1157
+ /** The assembled catalog set for the workspace. Memoized after the first call. */
1158
+ readonly set: () => Effect.Effect<CatalogSet, CatalogAssemblyFailure>;
1159
+ /** Resolve one `catalog:` specifier; `Option.none()` when it names nothing. */
1160
+ readonly resolveSpecifier: (dependency: string, specifier: string) => Effect.Effect<Option.Option<string>, CatalogAssemblyFailure>;
1161
+ }
1162
+ /**
1163
+ * Options for the {@link WorkspaceCatalogs} layer.
1164
+ *
1165
+ * @public
1166
+ */
1167
+ interface WorkspaceCatalogsOptions {
1168
+ /**
1169
+ * The directory the workspace root is resolved from.
1170
+ *
1171
+ * @defaultValue `process.cwd()`, read lazily on first use.
1172
+ */
1173
+ readonly cwd?: string;
1174
+ }
1175
+ declare const WorkspaceCatalogs_base: Context.ServiceClass<WorkspaceCatalogs, "@effected/workspaces/WorkspaceCatalogs", WorkspaceCatalogsShape>;
1176
+ /**
1177
+ * Assembles a workspace's catalogs, package-manager-aware.
1178
+ *
1179
+ * @remarks
1180
+ * The inline source is picked by **file presence**, the same rule
1181
+ * `internal/patterns.ts` uses for globs: a `pnpm-workspace.yaml` selects the pnpm
1182
+ * path (its `catalog:` / `catalogs:` blocks); its absence selects the root
1183
+ * `package.json` `workspaces.catalog` / `workspaces.catalogs` (bun's analogue).
1184
+ * The lockfile source is PM-aware too — whichever extension the parsed lockfile
1185
+ * carries (pnpm or bun) contributes its recorded catalogs.
1186
+ *
1187
+ * Precedence, lowest first: catalogs recorded in the lockfile, then the inline
1188
+ * declaration, then — only under {@link WorkspaceCatalogs.layerWithConfigDependencies}
1189
+ * — the config-dependency `pnpmfile.cjs` hooks, each layer winning per dependency
1190
+ * within a catalog. An unreadable or absent lockfile degrades to no lockfile
1191
+ * catalogs rather than failing (the inline declaration is the source of truth, the
1192
+ * lockfile a record of what was installed); a malformed inline source **fails
1193
+ * typed** with {@link CatalogAssemblyError}, because a silently-empty catalog read
1194
+ * is the "every dependency looks newly added" bug.
1195
+ *
1196
+ * Assembly is deferred to the first call and memoized success-only, matching
1197
+ * {@link WorkspaceDiscovery}.
1198
+ *
1199
+ * @public
1200
+ */
1201
+ declare class WorkspaceCatalogs extends WorkspaceCatalogs_base {
1202
+ /** Builds the service. */
1203
+ static readonly make: (options?: WorkspaceCatalogsOptions) => Effect.Effect<WorkspaceCatalogsShape, never, WorkspaceRoot | LockfileReader | ConfigDependencyHooks | FileSystem.FileSystem | Path.Path>;
1204
+ /**
1205
+ * The live layer — the default, which **never executes config-dependency
1206
+ * code**: it wires {@link ConfigDependencyHooks.layerNoop}, whose hooks return
1207
+ * the inline-catalog seed untouched.
1208
+ *
1209
+ * @remarks
1210
+ * Parameterized, so it mints a fresh reference per call — bind it to a
1211
+ * `const` and reuse it, or layer memoization does not apply.
1212
+ */
1213
+ static readonly layer: (options?: WorkspaceCatalogsOptions) => Layer.Layer<WorkspaceCatalogs, never, WorkspaceRoot | LockfileReader | FileSystem.FileSystem | Path.Path>;
1214
+ /**
1215
+ * The opt-in live layer that **does** replay config-dependency `pnpmfile.cjs`
1216
+ * hooks: it wires {@link ConfigDependencyHooks.layerLive}, which dynamically
1217
+ * imports and runs each config dependency's `updateConfig` in process.
1218
+ *
1219
+ * @remarks
1220
+ * Same output and requirement set as {@link WorkspaceCatalogs.layer} — the only
1221
+ * difference is that config-dependency code is executed. Use it deliberately;
1222
+ * the default catalog path stays free of any config-dependency execution.
1223
+ * Parameterized, so bind it to a `const` and reuse it.
1224
+ */
1225
+ static readonly layerWithConfigDependencies: (options?: WorkspaceCatalogsOptions) => Layer.Layer<WorkspaceCatalogs, never, WorkspaceRoot | LockfileReader | FileSystem.FileSystem | Path.Path>;
1226
+ /**
1227
+ * The real implementation of `@effected/npm`'s `CatalogResolver` contract —
1228
+ * the one `@effected/package-json` declares but cannot fill.
1229
+ *
1230
+ * @remarks
1231
+ * `rangeOf` returns `Option.none()` for a dependency no catalog declares, per
1232
+ * the contract's convention; `DependencyResolutionError` is reserved for a
1233
+ * failure of the resolution *mechanism* — an unfindable workspace root, an
1234
+ * unreadable or malformed `pnpm-workspace.yaml`.
1235
+ */
1236
+ static readonly catalogResolver: Layer.Layer<CatalogResolver, never, WorkspaceCatalogs>;
1237
+ }
1238
+ //#endregion
1239
+ //#region src/WorkspaceStateSnapshot.d.ts
1240
+ declare const PackageStateSnapshot_base: Schema.Class<PackageStateSnapshot, Schema.Struct<{
1241
+ /** The package name. */
1242
+ readonly name: Schema.NonEmptyString;
1243
+ /** The raw `version` string, as recorded at the captured moment. */
1244
+ readonly version: Schema.String;
1245
+ /** POSIX path relative to the workspace root; `"."` for the root package. */
1246
+ readonly relativePath: Schema.String;
1247
+ /** Production dependencies. */
1248
+ readonly dependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
1249
+ /** Development dependencies. */
1250
+ readonly devDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
1251
+ /** Peer dependencies. */
1252
+ readonly peerDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
1253
+ /** Optional dependencies. */
1254
+ readonly optionalDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
1255
+ }>, {}>;
1256
+ /**
1257
+ * One workspace member as captured in a {@link WorkspaceStateSnapshot} — the
1258
+ * serializable slice a snapshot diff reads: identity, version, location, and the
1259
+ * four dependency records.
1260
+ *
1261
+ * @remarks
1262
+ * Deliberately narrower than {@link WorkspacePackage}: a snapshot is a value to
1263
+ * store and diff, not a located member to act on, so it carries no absolute
1264
+ * paths, `publishConfig`, or `private` flag. The four records are keyed by the
1265
+ * standard manifest field names, which are exactly `@effected/npm`'s
1266
+ * `DependencyField` values.
1267
+ *
1268
+ * @public
1269
+ */
1270
+ declare class PackageStateSnapshot extends PackageStateSnapshot_base {
1271
+ /**
1272
+ * Every dependency, merged across the four kinds.
1273
+ *
1274
+ * @remarks
1275
+ * Precedence on a name declared in several kinds runs
1276
+ * `dependencies` \> `devDependencies` \> `peerDependencies` \>
1277
+ * `optionalDependencies`.
1278
+ */
1279
+ get allDependencies(): Record<string, string>;
1280
+ }
1281
+ declare const WorkspaceStateSnapshot_base: Schema.Class<WorkspaceStateSnapshot, Schema.Struct<{
1282
+ /** Every workspace package captured at this moment. */
1283
+ readonly packages: Schema.$Array<typeof PackageStateSnapshot>;
1284
+ /** The catalog set assembled at this moment. */
1285
+ readonly catalogs: typeof CatalogSet;
1286
+ }>, {}>;
1287
+ /**
1288
+ * The state of a whole workspace at one moment — its packages and its assembled
1289
+ * catalog set — as a serializable value.
1290
+ *
1291
+ * @remarks
1292
+ * Produced by `WorkspaceSnapshots.at` (a git ref, read with no checkout)
1293
+ * or `WorkspaceSnapshots.worktree` (the live tree). The lookup and
1294
+ * resolution surfaces (`versions`, `package`, `resolve`, the resolver layers)
1295
+ * are backed by `#private` indexes built lazily on first use and never encoded —
1296
+ * the `DependencyGraph` edge-index precedent.
1297
+ *
1298
+ * `resolve` and the resolver layers answer specifiers against THIS snapshot's
1299
+ * own captured state, so a consumer can ask "what did `catalog:` /
1300
+ * `workspace:*` mean as of that ref". An unmatched specifier is always
1301
+ * `Option.none()`, never an error.
1302
+ *
1303
+ * @example
1304
+ * ```ts
1305
+ * import { WorkspaceSnapshots } from "@effected/workspaces";
1306
+ * import { Effect } from "effect";
1307
+ *
1308
+ * const program = Effect.gen(function* () {
1309
+ * const snapshots = yield* WorkspaceSnapshots;
1310
+ * const before = yield* snapshots.at("origin/main");
1311
+ * return before.resolve("effect", "catalog:");
1312
+ * });
1313
+ * ```
1314
+ *
1315
+ * @public
1316
+ */
1317
+ declare class WorkspaceStateSnapshot extends WorkspaceStateSnapshot_base {
1318
+ #private;
1319
+ /** Every captured package's name → version. Total; O(1) after the first call. */
1320
+ get versions(): ReadonlyMap<string, string>;
1321
+ /** A single captured package by name, or `Option.none()`. Total. */
1322
+ package(name: string): Option.Option<PackageStateSnapshot>;
1323
+ /**
1324
+ * The concrete range or version a specifier resolved to AS OF this snapshot.
1325
+ *
1326
+ * @remarks
1327
+ * The specifier is classified through `@effected/npm`'s
1328
+ * `DependencySpecifier.FromString` — never by prefix-sniffing.
1329
+ * A `workspace:` specifier resolves to the captured version of `dependency`; a
1330
+ * `catalog:` specifier resolves against the captured catalog set. Every other
1331
+ * form — a plain range, a dist-tag, a `file:`/git/url specifier, or an
1332
+ * unparseable string — is `Option.none()`, because there is no indirection to
1333
+ * resolve. Total.
1334
+ *
1335
+ * @param dependency - The dependency's package name (what `workspace:` /
1336
+ * `catalog:` resolve for).
1337
+ * @param specifier - The raw specifier string.
1338
+ */
1339
+ resolve(dependency: string, specifier: string): Option.Option<string>;
1340
+ /**
1341
+ * A `CatalogResolver` layer implementing `@effected/npm`'s contract against
1342
+ * THIS snapshot's catalog set — so code written to the contract resolves
1343
+ * `catalog:` specifiers as of this ref. Built once per instance and cached, so
1344
+ * it memoizes by reference.
1345
+ */
1346
+ get catalogResolver(): Layer.Layer<CatalogResolver>;
1347
+ /**
1348
+ * A `WorkspaceResolver` layer implementing `@effected/npm`'s contract against
1349
+ * THIS snapshot's captured versions — so code written to the contract resolves
1350
+ * `workspace:` specifiers as of this ref. Built once per instance and cached.
1351
+ */
1352
+ get workspaceResolver(): Layer.Layer<WorkspaceResolver>;
1353
+ /** Both snapshot-scoped resolver layers merged. Built once per instance and cached. */
1354
+ get resolvers(): Layer.Layer<CatalogResolver | WorkspaceResolver>;
1355
+ }
1356
+ //#endregion
1357
+ //#region src/WorkspaceSnapshots.d.ts
1358
+ /**
1359
+ * Every failure `WorkspaceSnapshots.at` can surface: git's own typed
1360
+ * errors, a catalog-assembly failure from the inline config source at the ref,
1361
+ * or an unfindable workspace root.
1362
+ *
1363
+ * @remarks
1364
+ * Narrow by design. `at` reads through git and never enumerates the live
1365
+ * filesystem, so no `WorkspaceDiscoveryError` / `WorkspacePatternError` appears —
1366
+ * and a malformed *lockfile* at the ref degrades to no catalogs (a lockfile is a
1367
+ * record, not a source of truth), so only the inline source raises
1368
+ * {@link CatalogAssemblyError}.
1369
+ *
1370
+ * @public
1371
+ */
1372
+ type WorkspaceSnapshotAtFailure = GitCommandError | NotARepositoryError | UnknownRefError | CatalogAssemblyError | WorkspaceRootNotFoundError;
1373
+ /**
1374
+ * Every failure `WorkspaceSnapshots.worktree` can surface: the discovery
1375
+ * failures plus a catalog-assembly failure.
1376
+ *
1377
+ * @remarks
1378
+ * `worktree` never invokes git — it reads the live tree over
1379
+ * {@link WorkspaceDiscovery} and {@link WorkspaceCatalogs} — so no git error is
1380
+ * reachable.
1381
+ *
1382
+ * @public
1383
+ */
1384
+ type WorkspaceSnapshotWorktreeFailure = WorkspaceDiscoveryFailure | CatalogAssemblyError;
1385
+ /**
1386
+ * Options for the {@link WorkspaceSnapshots} layer.
1387
+ *
1388
+ * @public
1389
+ */
1390
+ interface WorkspaceSnapshotsOptions {
1391
+ /**
1392
+ * The directory `at(ref)` resolves the workspace root from.
1393
+ *
1394
+ * @defaultValue `process.cwd()`, read lazily on first use inside
1395
+ * `Effect.suspend`, so a `process.chdir` between providing the layer and the
1396
+ * first call is honoured.
1397
+ */
1398
+ readonly cwd?: string;
1399
+ }
1400
+ /**
1401
+ * The {@link WorkspaceSnapshots} service shape.
1402
+ *
1403
+ * @public
1404
+ */
1405
+ interface WorkspaceSnapshotsShape {
1406
+ /** The workspace state at a git ref, read with no checkout. Cached per `(root, ref)`. */
1407
+ readonly at: (ref: string) => Effect.Effect<WorkspaceStateSnapshot, WorkspaceSnapshotAtFailure>;
1408
+ /** The live workspace state, over discovery and catalog assembly. Uncached. */
1409
+ readonly worktree: () => Effect.Effect<WorkspaceStateSnapshot, WorkspaceSnapshotWorktreeFailure>;
1410
+ }
1411
+ declare const WorkspaceSnapshots_base: Context.ServiceClass<WorkspaceSnapshots, "@effected/workspaces/WorkspaceSnapshots", WorkspaceSnapshotsShape>;
1412
+ /**
1413
+ * Reads workspace state at a git ref with no checkout, and the live worktree.
1414
+ *
1415
+ * @remarks
1416
+ * `at(ref)` is cached per `(resolved root, ref)` via
1417
+ * `Effect.cachedInvalidateWithTTL` at `Duration.infinity`, invalidated on any
1418
+ * non-success exit — never bare `Effect.cached`, which would memoize an
1419
+ * interrupt. A failed `at(ref)` init is therefore retried on the next call, not
1420
+ * memoized.
1421
+ *
1422
+ * @example
1423
+ * ```ts
1424
+ * import { WorkspaceSnapshots } from "@effected/workspaces";
1425
+ * import { Effect } from "effect";
1426
+ *
1427
+ * const program = Effect.gen(function* () {
1428
+ * const snapshots = yield* WorkspaceSnapshots;
1429
+ * const before = yield* snapshots.at("origin/main");
1430
+ * const after = yield* snapshots.worktree();
1431
+ * return { before: before.versions, after: after.versions };
1432
+ * });
1433
+ * ```
1434
+ *
1435
+ * @public
1436
+ */
1437
+ declare class WorkspaceSnapshots extends WorkspaceSnapshots_base {
1438
+ /** Builds the service over `Git`, {@link WorkspaceRoot}, {@link WorkspaceDiscovery} and {@link WorkspaceCatalogs}. */
1439
+ static readonly make: (options?: WorkspaceSnapshotsOptions) => Effect.Effect<WorkspaceSnapshotsShape, never, Git | WorkspaceRoot | WorkspaceDiscovery | WorkspaceCatalogs>;
1440
+ /**
1441
+ * The live layer.
1442
+ *
1443
+ * @remarks
1444
+ * Parameterized, so it mints a fresh reference per call — bind it to a
1445
+ * `const` and reuse it, or layer memoization does not apply.
1446
+ */
1447
+ static readonly layer: (options?: WorkspaceSnapshotsOptions) => Layer.Layer<WorkspaceSnapshots, never, Git | WorkspaceRoot | WorkspaceDiscovery | WorkspaceCatalogs>;
1448
+ }
1449
+ //#endregion
1450
+ //#region src/Workspaces.d.ts
1451
+ /**
1452
+ * Options shared by the composite layers.
1453
+ *
1454
+ * @public
1455
+ */
1456
+ interface WorkspacesOptions {
1457
+ /**
1458
+ * The directory every root-consuming service resolves the workspace root
1459
+ * from — one explicit concern, applied uniformly.
1460
+ *
1461
+ * @defaultValue `process.cwd()`, read lazily on first use.
1462
+ */
1463
+ readonly cwd?: string;
1464
+ /** Descent cap for segment-crossing `packages:` patterns. Defaults to 32. */
1465
+ readonly maxDepth?: number;
1466
+ }
1467
+ /**
1468
+ * Every service the git-free composite layer provides.
1469
+ *
1470
+ * @public
1471
+ */
1472
+ type WorkspacesServices = WorkspaceRoot | PackageManagerDetector | WorkspaceDiscovery | LockfileReader | WorkspaceCatalogs | PublishabilityDetector;
1473
+ /**
1474
+ * The composite layers.
1475
+ *
1476
+ * @public
1477
+ */
1478
+ declare const Workspaces: {
1479
+ readonly layer: (options?: WorkspacesOptions) => Layer.Layer<WorkspacesServices, never, FileSystem.FileSystem | Path.Path>;
1480
+ readonly layerWithConfigDependencies: (options?: WorkspacesOptions) => Layer.Layer<WorkspacesServices, never, FileSystem.FileSystem | Path.Path>;
1481
+ readonly layerWithGit: (options?: WorkspacesOptions) => Layer.Layer<WorkspacesServices | ChangeDetector | WorkspaceSnapshots | Git, never, FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
1482
+ readonly resolvers: Layer.Layer<CatalogResolver | WorkspaceResolver, never, WorkspaceCatalogs | WorkspaceDiscovery>;
1483
+ };
1484
+ //#endregion
1485
+ //#region src/WorkspacesSync.d.ts
1486
+ /**
1487
+ * The nearest workspace root at or above `cwd`, or `null`.
1488
+ *
1489
+ * @remarks
1490
+ * **Synchronous and Node-only.** The Effect surface is `WorkspaceRoot`; reach
1491
+ * for this one only where you genuinely cannot run an Effect — a Vitest config
1492
+ * being the motivating case.
1493
+ *
1494
+ * Markers match the async service exactly: a `pnpm-workspace.yaml`, or a
1495
+ * `package.json` carrying a `workspaces` field.
1496
+ *
1497
+ * @param cwd - Where to start the ascent. Defaults to `process.cwd()`.
1498
+ *
1499
+ * @example
1500
+ * ```ts
1501
+ * import { findWorkspaceRootSync } from "@effected/workspaces";
1502
+ *
1503
+ * const root = findWorkspaceRootSync();
1504
+ * ```
1505
+ *
1506
+ * @public
1507
+ */
1508
+ declare const findWorkspaceRootSync: (cwd?: string) => string | null;
1509
+ /**
1510
+ * Options for {@link getWorkspacePackagesSync}.
1511
+ *
1512
+ * @public
1513
+ */
1514
+ interface GetWorkspacePackagesSyncOptions {
1515
+ /**
1516
+ * Descent cap below a wildcard's enumeration prefix, mirroring
1517
+ * `WorkspaceDiscovery.layer({ maxDepth })`.
1518
+ *
1519
+ * @defaultValue 32
1520
+ */
1521
+ readonly maxDepth?: number;
1522
+ }
1523
+ /**
1524
+ * Every workspace package under `root`, root package first.
1525
+ *
1526
+ * @remarks
1527
+ * **Synchronous and Node-only.** The Effect surface is `WorkspaceDiscovery`.
1528
+ *
1529
+ * Pattern semantics are not merely "shared" with the Effect enumerator — both
1530
+ * drive the **same traversal state machine** (`internal/traverse.ts`), so the
1531
+ * dequeue order, the depth rule, the visit budget and the prune list cannot
1532
+ * drift apart. A `packages/**` finds exactly the same packages here as there,
1533
+ * including at the depth boundary.
1534
+ *
1535
+ * The one deliberate difference is what happens at a bound: the Effect surface
1536
+ * fails typed (`depthExceeded` / `budgetExceeded`), while this one is **total**
1537
+ * and truncates. An unenumerable pattern or an unreadable manifest is skipped,
1538
+ * not raised — a function with no error channel should not pretend to have one,
1539
+ * and a Vitest config has nowhere to put a failure. Totality covers *data*, not
1540
+ * caller mistakes: a `maxDepth` that is not a positive integer throws, matching
1541
+ * the enumerator's defect.
1542
+ *
1543
+ * @param root - The workspace root, from {@link findWorkspaceRootSync}.
1544
+ * @param options - Traversal bounds; see {@link GetWorkspacePackagesSyncOptions}.
1545
+ *
1546
+ * @example
1547
+ * ```ts
1548
+ * import { findWorkspaceRootSync, getWorkspacePackagesSync } from "@effected/workspaces";
1549
+ *
1550
+ * const root = findWorkspaceRootSync();
1551
+ * const packages = root === null ? [] : getWorkspacePackagesSync(root);
1552
+ * ```
1553
+ *
1554
+ * @public
1555
+ */
1556
+ declare const getWorkspacePackagesSync: (root: string, options?: GetWorkspacePackagesSyncOptions) => ReadonlyArray<WorkspacePackage>;
1557
+ //#endregion
1558
+ export { CatalogAssemblyError, type CatalogAssemblyFailure, CatalogSet, ChangeDetectionError, type ChangeDetectionFailure, ChangeDetectionOptions, ChangeDetector, type ChangeDetectorShape, ConfigDependencyHooks, type ConfigDependencyHooksShape, CyclicDependencyError, type DependencyDiff, DependencyGraph, DetectedPackageManager, type GetWorkspacePackagesSyncOptions, LockfileReadError, type LockfileReadFailure, LockfileReader, type LockfileReaderOptions, type LockfileReaderShape, PackageManagerDetectionError, type PackageManagerDetectionFailure, PackageManagerDetector, PackageManagerName, PackageNotFoundError, PackageStateSnapshot, PublishConfig, PublishTarget, PublishabilityDetector, WORKSPACE_MARKERS, WorkspaceCatalogs, type WorkspaceCatalogsOptions, type WorkspaceCatalogsShape, WorkspaceDiscovery, WorkspaceDiscoveryError, type WorkspaceDiscoveryFailure, type WorkspaceDiscoveryOptions, type WorkspaceDiscoveryShape, WorkspaceInfo, type WorkspaceLookupFailure, WorkspaceManifestError, WorkspacePackage, WorkspacePatternError, WorkspaceRoot, WorkspaceRootNotFoundError, type WorkspaceSnapshotAtFailure, type WorkspaceSnapshotWorktreeFailure, WorkspaceSnapshots, type WorkspaceSnapshotsOptions, type WorkspaceSnapshotsShape, WorkspaceStateSnapshot, Workspaces, type WorkspacesOptions, type WorkspacesServices, findWorkspaceRootSync, getWorkspacePackagesSync };
1559
+ //# sourceMappingURL=index.d.ts.map