import { Catalog, Catalogs, Catalogs as Catalogs$1 } from "@pnpm/catalogs.types"; import { CommandExecutor, FileSystem, Path } from "@effect/platform"; import { Context, Effect, Layer, Option, Schema } from "effect"; //#region src/errors/CatalogAssemblyError.d.ts /** * Base constant for {@link CatalogAssemblyError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const CatalogAssemblyErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "CatalogAssemblyError"; } & Readonly; /** * Raised when assembling the workspace catalog set fails irrecoverably * (e.g. `pnpm-workspace.yaml` unreadable/malformed, default catalog defined twice). * Per-config-dependency hook failures do NOT raise this — they are logged and skipped. * * @public */ declare class CatalogAssemblyError extends CatalogAssemblyErrorBase<{ readonly source: "manifest" | "config-dependency" | "lockfile"; readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/CatalogResolutionError.d.ts /** * Base constant for {@link CatalogResolutionError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const CatalogResolutionErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "CatalogResolutionError"; } & Readonly; /** * Raised when a `catalog:`/`workspace:` specifier in a manifest cannot be resolved * (unknown catalog, catalog misconfiguration, or unresolvable workspace reference). * * @public */ declare class CatalogResolutionError extends CatalogResolutionErrorBase<{ readonly field: string; readonly dependency: string; readonly specifier: string; readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/ChangeDetectionError.d.ts /** * Base constant for {@link ChangeDetectionError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const ChangeDetectionErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "ChangeDetectionError"; } & Readonly; /** * Emitted when a git operation fails during change detection. * * @remarks * Raised by {@link ChangeDetector} when a specific git command (diff, log, * merge-base, etc.) fails after git availability has already been confirmed. * The `operation` field identifies which command failed. * * Fields: * - `operation` — the git operation that failed (e.g., "diff", "merge-base"). * - `reason` — human-readable explanation of the failure. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { ChangeDetectionError } from "workspaces-effect"; * import { ChangeDetector, ChangeDetectorLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const detector = yield* ChangeDetector; * return yield* detector.changedPackages("main"); * }).pipe( * Effect.catchTag("ChangeDetectionError", (e) => * Effect.logError(`Git ${e.operation} failed: ${e.reason}`) * ) * ); * ``` * * @public */ declare class ChangeDetectionError extends ChangeDetectionErrorBase<{ readonly operation: string; readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/CyclicDependencyError.d.ts /** * Base constant for {@link CyclicDependencyError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const CyclicDependencyErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "CyclicDependencyError"; } & Readonly; /** * Emitted when a cycle is detected in the dependency graph. * * @remarks * Raised by {@link DependencyGraph} during topological sorting or cycle * detection. The `cycle` array contains all package names that could not * be topologically sorted — i.e., packages that are part of or blocked * by a cyclic dependency. * * Fields: * - `cycle` — set of package names involved in or blocked by the cycle. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { CyclicDependencyError } from "workspaces-effect"; * import { DependencyGraph, DependencyGraphLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const graph = yield* DependencyGraph; * return yield* graph.topologicalSort(); * }).pipe( * Effect.catchTag("CyclicDependencyError", (e) => * Effect.logError(`Cycle found: ${e.cycle.join(" -> ")}`) * ) * ); * ``` * * @public */ declare class CyclicDependencyError extends CyclicDependencyErrorBase<{ readonly cycle: ReadonlyArray; }> { get message(): string; } //#endregion //#region src/errors/DependencyResolutionError.d.ts /** * Base constant for {@link DependencyResolutionError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const DependencyResolutionErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "DependencyResolutionError"; } & Readonly; /** * Emitted when a dependency cannot be resolved within the workspace. * * @remarks * Raised by {@link DependencyGraph} when a workspace package declares a * dependency on another workspace package whose version constraint cannot be * satisfied or whose name does not match any known workspace package. * * Fields: * - `packageName` — the package that declares the unresolvable dependency. * - `dependency` — the dependency name that could not be resolved. * - `reason` — human-readable explanation of the resolution failure. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { DependencyResolutionError } from "workspaces-effect"; * import { DependencyGraph, DependencyGraphLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const graph = yield* DependencyGraph; * return yield* graph.resolve(); * }).pipe( * Effect.catchTag("DependencyResolutionError", (e) => * Effect.logError(`${e.packageName} -> ${e.dependency}: ${e.reason}`) * ) * ); * ``` * * @public */ declare class DependencyResolutionError extends DependencyResolutionErrorBase<{ readonly packageName: string; readonly dependency: string; readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/GitNotAvailableError.d.ts /** * Base constant for {@link GitNotAvailableError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const GitNotAvailableErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "GitNotAvailableError"; } & Readonly; /** * Emitted when git is not installed or the directory is not a git repository. * * @remarks * Raised by {@link ChangeDetector} as a precondition check before any git * operations. This indicates that change detection is unavailable entirely, * as opposed to {@link ChangeDetectionError} which indicates a specific * git operation failed. * * Fields: * - `reason` — human-readable explanation (e.g., "git not found in PATH" * or "not a git repository"). * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { GitNotAvailableError } from "workspaces-effect"; * import { ChangeDetector, ChangeDetectorLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const detector = yield* ChangeDetector; * return yield* detector.changedPackages("main"); * }).pipe( * Effect.catchTag("GitNotAvailableError", (e) => * Effect.logWarning(`Git unavailable: ${e.reason}`).pipe( * Effect.map(() => []) * ) * ) * ); * ``` * * @public */ declare class GitNotAvailableError extends GitNotAvailableErrorBase<{ readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/GitReadError.d.ts /** * Base constant for {@link GitReadError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. * * @public */ declare const GitReadErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "GitReadError"; } & Readonly; /** * Raised when reading workspace state at a git ref fails irrecoverably * (git unavailable, unknown revision, command failure). A path that simply * does not exist at the ref is NOT an error — readers surface that as * `Option.none`. * * @public */ declare class GitReadError extends GitReadErrorBase<{ /** The git command that failed, including arguments. */ readonly command: string; /** Working directory in which the command was invoked. */ readonly cwd: string; /** Human-readable failure reason — typically captured stderr. */ readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/LockfileIntegrityError.d.ts /** * Base constant for {@link LockfileIntegrityError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const LockfileIntegrityErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "LockfileIntegrityError"; } & Readonly; /** * Emitted when integrity checking cannot complete. * * @remarks * Raised by {@link LockfileReader} during integrity validation when the * comparison between the lockfile's resolved packages and the workspace's * declared dependencies encounters an unrecoverable error. Note that * integrity *mismatches* (missing workspaces, unsatisfied constraints) are * reported via {@link LockfileIntegrity} — this error indicates the check * itself could not run. * * Fields: * - `reason` — human-readable explanation of why the integrity check failed. * - `cause` — the underlying error that prevented the check. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { LockfileIntegrityError } from "workspaces-effect"; * import { LockfileReader, LockfileReaderLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * return yield* reader.checkIntegrity("/workspace/root"); * }).pipe( * Effect.catchTag("LockfileIntegrityError", (e) => * Effect.logError(`Integrity check failed: ${e.reason}`) * ) * ); * ``` * * @public */ declare class LockfileIntegrityError extends LockfileIntegrityErrorBase<{ readonly reason: string; readonly cause: unknown; }> { get message(): string; } //#endregion //#region src/errors/LockfileParseError.d.ts /** * Base constant for {@link LockfileParseError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const LockfileParseErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "LockfileParseError"; } & Readonly; /** * Emitted when a lockfile exists but cannot be parsed. * * @remarks * Raised by {@link LockfileReader} when the lockfile is successfully read from * disk but its contents cannot be parsed into the expected format. Each package * manager has a different lockfile format (YAML for pnpm, JSON for npm/bun, * custom format for yarn Berry). * * Fields: * - `lockfilePath` — absolute path to the lockfile that failed to parse. * - `format` — the package manager format that was attempted (`"pnpm"`, `"npm"`, `"yarn"`, or `"bun"`). * - `cause` — the underlying parse error. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { LockfileParseError } from "workspaces-effect"; * import { LockfileReader, LockfileReaderLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * return yield* reader.read("/workspace/root"); * }).pipe( * Effect.catchTag("LockfileParseError", (e) => * Effect.logError(`Cannot parse ${e.format} lockfile at ${e.lockfilePath}`) * ) * ); * ``` * * @public */ declare class LockfileParseError extends LockfileParseErrorBase<{ readonly lockfilePath: string; readonly format: "pnpm" | "npm" | "yarn" | "bun"; readonly cause: unknown; }> { get message(): string; } //#endregion //#region src/errors/LockfileReadError.d.ts /** * Base constant for {@link LockfileReadError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const LockfileReadErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "LockfileReadError"; } & Readonly; /** * Emitted when a lockfile cannot be read from disk. * * @remarks * Raised by {@link LockfileReader} when the expected lockfile for the detected * package manager (e.g., `pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, * `bun.lock`) does not exist or cannot be read due to filesystem permissions. * * Fields: * - `lockfilePath` — absolute path to the lockfile that could not be read. * - `reason` — human-readable explanation (e.g., "file not found", "permission denied"). * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { LockfileReadError } from "workspaces-effect"; * import { LockfileReader, LockfileReaderLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * return yield* reader.read("/workspace/root"); * }).pipe( * Effect.catchTag("LockfileReadError", (e) => * Effect.logWarning(`No lockfile at ${e.lockfilePath}: ${e.reason}`) * ) * ); * ``` * * @public */ declare class LockfileReadError extends LockfileReadErrorBase<{ readonly lockfilePath: string; readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/PackageJsonParseError.d.ts /** * Base constant for {@link PackageJsonParseError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const PackageJsonParseErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "PackageJsonParseError"; } & Readonly; /** * Emitted when a package.json file cannot be parsed or validated. * * @remarks * Raised by {@link WorkspaceDiscovery} when a package.json file is found but * contains invalid JSON or does not conform to {@link PackageJsonSchema}. The * `cause` field preserves the underlying parse or schema validation error. * * Fields: * - `filePath` — absolute path to the package.json that failed to parse. * - `cause` — the underlying error (JSON syntax error or Schema decode failure). * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { PackageJsonParseError } from "workspaces-effect"; * import { WorkspaceDiscovery, WorkspaceDiscoveryLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const discovery = yield* WorkspaceDiscovery; * return yield* discovery.discover("/workspace/root"); * }).pipe( * Effect.catchTag("PackageJsonParseError", (e) => * Effect.logError(`Bad package.json at ${e.filePath}`).pipe( * Effect.map(() => []) * ) * ) * ); * ``` * * @public */ declare class PackageJsonParseError extends PackageJsonParseErrorBase<{ readonly filePath: string; readonly cause: unknown; }> { get message(): string; } //#endregion //#region src/errors/PackageManagerDetectionError.d.ts /** * Base constant for {@link PackageManagerDetectionError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const PackageManagerDetectionErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "PackageManagerDetectionError"; } & Readonly; /** * Emitted when the package manager type cannot be determined. * * @remarks * Raised by {@link PackageManagerDetector} when heuristics (lockfile presence, * `packageManager` field in root package.json) fail to identify a single * package manager for the workspace. * * Fields: * - `searchPath` — the workspace root path that was inspected. * - `reason` — human-readable explanation of the detection failure. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { PackageManagerDetectionError } from "workspaces-effect"; * import { PackageManagerDetector, PackageManagerDetectorLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const detector = yield* PackageManagerDetector; * return yield* detector.detect("/workspace/root"); * }).pipe( * Effect.catchTag("PackageManagerDetectionError", (e) => * Effect.succeed(`Could not detect PM at ${e.searchPath}: ${e.reason}`) * ) * ); * ``` * * @public */ declare class PackageManagerDetectionError extends PackageManagerDetectionErrorBase<{ readonly searchPath: string; readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/PackageNotFoundError.d.ts /** * Base constant for {@link PackageNotFoundError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const PackageNotFoundErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "PackageNotFoundError"; } & Readonly; /** * Emitted when a named package is not found in the workspace. * * @remarks * Raised by {@link WorkspaceDiscovery} or {@link DependencyGraph} when a * lookup by package name yields no match. The `available` field lists all * known package names to aid debugging typos or missing packages. * * Fields: * - `name` — the package name that was requested but not found. * - `available` — all package names currently known in the workspace. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { PackageNotFoundError } from "workspaces-effect"; * import { DependencyGraph, DependencyGraphLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const graph = yield* DependencyGraph; * return yield* graph.dependenciesOf("@my-org/missing-pkg"); * }).pipe( * Effect.catchTag("PackageNotFoundError", (e) => * Effect.logWarning(`"${e.name}" not found. Available: ${e.available.join(", ")}`) * ) * ); * ``` * * @public */ declare class PackageNotFoundError extends PackageNotFoundErrorBase<{ readonly name: string; readonly available: ReadonlyArray; }> { get message(): string; } //#endregion //#region src/errors/WorkspaceDiscoveryError.d.ts /** * Base constant for {@link WorkspaceDiscoveryError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const WorkspaceDiscoveryErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "WorkspaceDiscoveryError"; } & Readonly; /** * Emitted when workspace package discovery fails. * * @remarks * Raised by {@link WorkspaceDiscovery} when glob expansion of workspace * patterns or subsequent package.json reads fail. This can occur if patterns * in pnpm-workspace.yaml or the root package.json `workspaces` field resolve * to invalid or inaccessible directories. * * Fields: * - `root` — the workspace root path where discovery was attempted. * - `reason` — human-readable explanation of what went wrong. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { WorkspaceDiscoveryError } from "workspaces-effect"; * import { WorkspaceDiscovery, WorkspaceDiscoveryLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const discovery = yield* WorkspaceDiscovery; * return yield* discovery.discover("/workspace/root"); * }).pipe( * Effect.catchTag("WorkspaceDiscoveryError", (e) => * Effect.succeed(`Discovery failed at ${e.root}: ${e.reason}`) * ) * ); * ``` * * @public */ declare class WorkspaceDiscoveryError extends WorkspaceDiscoveryErrorBase<{ readonly root: string; readonly reason: string; }> { get message(): string; } //#endregion //#region src/errors/WorkspaceRootNotFoundError.d.ts /** * Base constant for {@link WorkspaceRootNotFoundError}. * * @remarks * Exported for api-extractor DTS bundling — the `_base` symbol from * `Data.TaggedError` must be visible in the generated .d.ts file. Tagged * `@public` because it appears in the `extends` clause of a `@public` * subclass; consumers should construct and catch the subclass, not this * base directly. * * @public */ declare const WorkspaceRootNotFoundErrorBase: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "WorkspaceRootNotFoundError"; } & Readonly; /** * Emitted when no workspace root can be found from the search path. * * @remarks * Raised by {@link WorkspaceRoot} when directory traversal from the search path * to the filesystem root finds no workspace markers (pnpm-workspace.yaml or * package.json with workspaces field). * * Fields: * - `searchPath` — the absolute path from which upward traversal started. * - `reason` — human-readable explanation of why no root was found. * * @example Catching the error * ```typescript * import { Effect } from "effect"; * import type { WorkspaceRootNotFoundError } from "workspaces-effect"; * import { WorkspaceRoot, WorkspaceRootLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const root = yield* WorkspaceRoot; * return yield* root.find("/some/path"); * }).pipe( * Effect.catchTag("WorkspaceRootNotFoundError", (e) => * Effect.succeed(`Fallback: ${e.searchPath}`) * ) * ); * ``` * * @public */ declare class WorkspaceRootNotFoundError extends WorkspaceRootNotFoundErrorBase<{ readonly searchPath: string; readonly reason: string; }> { get message(): string; } //#endregion //#region src/layers/catalog/resolve.d.ts /** * Minimal shape of a `package.json` manifest needed to resolve catalog and * workspace specifiers. * * @public */ interface ManifestLike { readonly name: string; readonly version: string; dependencies?: Record; devDependencies?: Record; peerDependencies?: Record; optionalDependencies?: Record; [k: string]: unknown; } //#endregion //#region src/services/CatalogResolver.d.ts /** * Errors surfaced by {@link CatalogResolver} methods (assembly defers I/O to first call). * * @remarks * Assembly reads the working tree through the shared worktree-catalog pipeline, * so the only failure modes are locating the workspace root * ({@link WorkspaceRootNotFoundError}) and reading/parsing the manifest or an * unreadable lockfile ({@link CatalogAssemblyError}). A missing or malformed * lockfile degrades to empty catalogs rather than failing. * * @public */ type CatalogResolverError = CatalogAssemblyError | WorkspaceRootNotFoundError; declare const CatalogResolver_base: Context.TagClass Effect.Effect; /** Rewrite all catalog:/workspace: specifiers in a manifest to concrete specs. */ readonly resolve: (manifest: ManifestLike) => Effect.Effect; /** Resolve a single dependency specifier; None when no rewrite is needed. */ readonly resolveSpecifier: (dependency: string, specifier: string) => Effect.Effect, CatalogResolverError | CatalogResolutionError>; }>; /** * Resolves a workspace's catalogs and rewrites catalog:/workspace: specifiers. * * @remarks * Assembles the complete catalog set — inline `pnpm-workspace.yaml` catalogs, * catalogs injected by config dependencies (via pnpmfile `updateConfig` replay), * and lockfile catalogs — without depending on the transient workspace-state file. * * @public */ declare class CatalogResolver extends CatalogResolver_base {} //#endregion //#region src/schemas/core.d.ts /** * Schema for supported package manager identifiers. * * @remarks * Valid values are `"npm"`, `"pnpm"`, `"yarn"`, and `"bun"`. Used throughout * the library to narrow behavior to a specific package manager. The literal * union is enforced at the schema level so invalid values are caught during * decode rather than at runtime. * * @example Decoding a package manager value * ```typescript * import { Schema } from "effect"; * import { PackageManager } from "workspaces-effect"; * * const result = Schema.decodeUnknownSync(PackageManager)("pnpm"); * // result: "pnpm" * ``` * * @public */ declare const PackageManager: Schema.Literal<["npm", "pnpm", "yarn", "bun"]>; /** * TypeScript type for the {@link PackageManager} schema. * * @remarks * Equivalent to `"npm" | "pnpm" | "yarn" | "bun"`. * * @public */ type PackageManagerType = Schema.Schema.Type; /** * Branded non-empty string representing a package name. * * @remarks * Applies the `PackageName` brand to `Schema.NonEmptyString`, ensuring that * decoded values are both non-empty and carry a nominal type tag to prevent * accidental interchange with other string types. * * @example Decoding a package name * ```typescript * import { Schema } from "effect"; * import { PackageName } from "workspaces-effect"; * * const name = Schema.decodeUnknownSync(PackageName)("@my-org/utils"); * // name: PackageName (branded string) * ``` * * @public */ declare const PackageName: Schema.brand; /** * TypeScript type for the {@link PackageName} schema. * * @remarks * A branded `string` that is guaranteed to be non-empty. Use * `Schema.decodeUnknownSync(PackageName)` to produce values of this type. * * @public */ type PackageNameType = Schema.Schema.Type; /** * Branded non-empty string representing an absolute workspace path. * * @remarks * Applies the `WorkspacePath` brand to `Schema.NonEmptyString`. Used to * distinguish workspace directory paths from arbitrary strings in the type * system, preventing accidental misuse of unvalidated path values. * * @example Decoding a workspace path * ```typescript * import { Schema } from "effect"; * import { WorkspacePath } from "workspaces-effect"; * * const path = Schema.decodeUnknownSync(WorkspacePath)("/workspace/pkgs/utils"); * // path: WorkspacePath (branded string) * ``` * * @public */ declare const WorkspacePath: Schema.brand; /** * TypeScript type for the {@link WorkspacePath} schema. * * @remarks * A branded `string` that is guaranteed to be non-empty. Use * `Schema.decodeUnknownSync(WorkspacePath)` to produce values of this type. * * @public */ type WorkspacePathType = Schema.Schema.Type; declare const PublishConfig_base: Schema.Class>; registry: Schema.optional; directory: Schema.optional; tag: Schema.optional; linkDirectory: Schema.optional; }, Schema.Struct.Encoded<{ access: Schema.optional>; registry: Schema.optional; directory: Schema.optional; tag: Schema.optional; linkDirectory: Schema.optional; }>, never, { readonly access?: "public" | "restricted" | undefined; } & { readonly directory?: string | undefined; } & { readonly linkDirectory?: boolean | undefined; } & { readonly registry?: string | undefined; } & { readonly tag?: string | undefined; }, {}, {}>; /** * Schema for the `publishConfig` field in package.json. * * @remarks * Captures the subset of `publishConfig` properties relevant to workspace * tooling: registry selection, access control, and publish directory override. * * Fields: * - `access` — `"public"` or `"restricted"` (scoped package visibility). * - `registry` — custom registry URL for publishing. * - `directory` — subdirectory to publish instead of the package root. * * @example Decoding publishConfig * ```typescript * import { Schema } from "effect"; * import { PublishConfig } from "workspaces-effect"; * * const config = new PublishConfig({ * access: "public", * registry: "https://registry.npmjs.org", * }); * ``` * * @public */ declare class PublishConfig extends PublishConfig_base {} /** * Type alias for the decoded shape of {@link PublishConfig}. * * @public */ type PublishConfigType = PublishConfig; /** * Minimal package.json schema for workspace discovery. * * @remarks * Captures only the fields needed by workspace tooling — name, version, * private flag, workspace patterns, dependency maps, the `packageManager` * field (used by Corepack), and `publishConfig`. Unknown fields are silently * ignored during decode. * * Fields: * - `name` — the package name. * - `version` — the package version string. * - `private` — whether the package is private (not published). * - `workspaces` — workspace glob patterns (array or object form). * - `dependencies` — production dependency map. * - `devDependencies` — development dependency map. * - `peerDependencies` — peer dependency map. * - `packageManager` — Corepack package manager spec (e.g., `"pnpm@9.1.0"`). * - `publishConfig` — publishing configuration overrides. * * @example Decoding a package.json * ```typescript * import { Schema } from "effect"; * import { PackageJsonSchema } from "workspaces-effect"; * * const pkg = Schema.decodeUnknownSync(PackageJsonSchema)({ * name: "@my-org/app", * version: "1.0.0", * workspaces: ["packages/*"], * }); * ``` * * @public */ declare const PackageJsonSchema: Schema.Struct<{ name: Schema.optional; version: Schema.optional; private: Schema.optional; workspaces: Schema.optional, Schema.Struct<{ packages: Schema.Array$; }>]>>; dependencies: Schema.optional>; devDependencies: Schema.optional>; peerDependencies: Schema.optional>; optionalDependencies: Schema.optional>; packageManager: Schema.optional; publishConfig: Schema.optional; }>; /** * TypeScript type for the {@link PackageJsonSchema} schema. * * @public */ type PackageJsonType = Schema.Schema.Type; /** * Result of comparing two WorkspacePackage dependency snapshots. * @public */ interface DependencyDiff { readonly added: Record; readonly removed: Record; readonly changed: Record; } declare const WorkspacePackage_base: Schema.Class false; }>; dependencies: Schema.optionalWith, { default: () => {}; }>; devDependencies: Schema.optionalWith, { default: () => {}; }>; peerDependencies: Schema.optionalWith, { default: () => {}; }>; optionalDependencies: Schema.optionalWith, { default: () => {}; }>; publishConfig: Schema.optional; }, Schema.Struct.Encoded<{ name: typeof Schema.NonEmptyString; version: typeof Schema.String; path: typeof Schema.NonEmptyString; packageJsonPath: typeof Schema.NonEmptyString; relativePath: typeof Schema.String; private: Schema.optionalWith false; }>; dependencies: Schema.optionalWith, { default: () => {}; }>; devDependencies: Schema.optionalWith, { default: () => {}; }>; peerDependencies: Schema.optionalWith, { default: () => {}; }>; optionalDependencies: Schema.optionalWith, { default: () => {}; }>; publishConfig: Schema.optional; }>, never, { readonly publishConfig?: PublishConfig | undefined; } & { readonly dependencies?: { readonly [x: string]: string; } | undefined; } & { readonly devDependencies?: { readonly [x: string]: string; } | undefined; } & { readonly optionalDependencies?: { readonly [x: string]: string; } | undefined; } & { readonly peerDependencies?: { readonly [x: string]: string; } | undefined; } & { readonly private?: boolean | undefined; } & { readonly name: string; } & { readonly packageJsonPath: string; } & { readonly path: string; } & { readonly relativePath: string; } & { readonly version: string; }, {}, {}>; /** * A single workspace package within a monorepo. * * @remarks * Produced by {@link WorkspaceDiscovery} for each package found by expanding * the workspace glob patterns. Contains the parsed metadata from the * package's `package.json` plus its filesystem location. * * Fields: * - `name` — the package name (non-empty string). * - `version` — the package version string. * - `path` — absolute filesystem path to the package directory. * - `packageJsonPath` — absolute path to the package's `package.json` file. * - `relativePath` — path relative to the workspace root. * - `private` — whether the package is marked private (defaults to `false`). * - `dependencies` — production dependency map (defaults to `{}`). * - `devDependencies` — development dependency map (defaults to `{}`). * - `peerDependencies` — peer dependency map (defaults to `{}`). * - `optionalDependencies` — optional dependency map (defaults to `{}`). * - `publishConfig` — optional publishing configuration overrides. * * @example Creating a WorkspacePackage * ```typescript * import { WorkspacePackage } from "workspaces-effect"; * * const pkg = new WorkspacePackage({ * name: "@my-org/utils", * version: "1.0.0", * path: "/workspace/packages/utils", * packageJsonPath: "/workspace/packages/utils/package.json", * relativePath: "packages/utils", * }); * ``` * * @public */ declare class WorkspacePackage extends WorkspacePackage_base { get isRootWorkspace(): boolean; get isPublic(): boolean; get scope(): Option.Option; get unscopedName(): string; get allDependencies(): Record; hasDependency(name: string): boolean; hasDevDependency(name: string): boolean; hasPeerDependency(name: string): boolean; hasOptionalDependency(name: string): boolean; hasAnyDependencyOn(name: string): boolean; dependencyVersion(name: string): Option.Option; matchesDependency(pattern: string): boolean; /** * Compare two WorkspacePackage dependency snapshots. * * Compares across all dependency types combined. A dependency that moves * between categories (e.g. from `dependencies` to `peerDependencies`) at * the same version will not appear in the diff. */ dependencyDiff(other: WorkspacePackage): DependencyDiff; static hasDependency: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; static hasDevDependency: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; static hasPeerDependency: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; static hasOptionalDependency: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; static hasAnyDependencyOn: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; static dependencyVersion: { (name: string): (self: WorkspacePackage) => Option.Option; (self: WorkspacePackage, name: string): Option.Option; }; static matchesDependency: { (pattern: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, pattern: string): boolean; }; static dependencyDiff: { (other: WorkspacePackage): (self: WorkspacePackage) => DependencyDiff; (self: WorkspacePackage, other: WorkspacePackage): DependencyDiff; }; static readPackageJson: (self: WorkspacePackage) => Effect.Effect; } declare const WorkspaceInfo_base: Schema.Class; packageManagerVersion: Schema.optional; patterns: Schema.Array$; }, Schema.Struct.Encoded<{ root: typeof Schema.NonEmptyString; packageManager: Schema.Literal<["npm", "pnpm", "yarn", "bun"]>; packageManagerVersion: Schema.optional; patterns: Schema.Array$; }>, never, { readonly packageManagerVersion?: string | undefined; } & { readonly packageManager: "bun" | "npm" | "pnpm" | "yarn"; } & { readonly patterns: readonly string[]; } & { readonly root: string; }, {}, {}>; /** * Top-level workspace info for a monorepo. * * @remarks * Produced by {@link WorkspaceRoot} and {@link PackageManagerDetector} to * describe the workspace root's configuration. Contains the detected package * manager, its version (if determinable), and the workspace glob patterns. * * Fields: * - `root` — absolute path to the workspace root directory. * - `packageManager` — the detected package manager (`"npm"`, `"pnpm"`, `"yarn"`, or `"bun"`). * - `packageManagerVersion` — optional version string from the `packageManager` field. * - `patterns` — the workspace glob patterns (e.g., `["packages/*", "apps/*"]`). * * @example Creating a WorkspaceInfo * ```typescript * import { WorkspaceInfo } from "workspaces-effect"; * * const info = new WorkspaceInfo({ * root: "/workspace", * packageManager: "pnpm", * patterns: ["packages/*", "apps/*"], * }); * ``` * * @public */ declare class WorkspaceInfo extends WorkspaceInfo_base {} //#endregion //#region src/services/WorkspaceDiscovery.d.ts declare const WorkspaceDiscovery_base: Context.TagClass Effect.Effect, WorkspaceDiscoveryError>; /** * Get a specific workspace package by name. * * @param name - The package name as declared in its `package.json` `name` field. * @param cwd - Optional starting directory. See {@link listPackages} for behavior. * @returns An Effect that succeeds with the matching {@link WorkspacePackage}, * or fails with {@link PackageNotFoundError} if no workspace package has that * name, or {@link WorkspaceDiscoveryError} if discovery itself fails. */ readonly getPackage: (name: string, cwd?: string) => Effect.Effect; /** * Get a map of workspace-relative directory paths to packages. * * Useful for mapping lockfile importer keys to their workspace packages. * Built from `listPackages()` output and inherits its caching. * * @param cwd - Optional starting directory. See {@link listPackages} for behavior. * @returns An Effect that succeeds with a ReadonlyMap keyed by relativePath. */ readonly importerMap: (cwd?: string) => Effect.Effect, WorkspaceDiscoveryError>; /** * Discard cached discovery results so the next {@link listPackages} * (and {@link getPackage} / {@link importerMap}, which build on it) * re-reads every `package.json` from disk. * * @remarks * `listPackages` memoizes its result per resolved workspace root for the * lifetime of the layer. That cache is correct for a static tree, but a * process that mutates `package.json` mid-run — for example running * `changeset version` to bump versions and then reading the new versions * back — would otherwise observe the pre-mutation snapshot. Call * `refresh` after such a mutation to force a re-scan. * * The resolved workspace root itself is not discarded (the root does not * move when package contents change), so the next call pays only the * package re-scan, not the root walk. `refresh` clears the cache for * every resolved root. * * @returns An Effect that clears the cache and succeeds with `void`. */ readonly refresh: () => Effect.Effect; }>; /** * Service for discovering workspace packages in a monorepo. * * Reads workspace patterns from the PM-specific config (e.g., `pnpm-workspace.yaml`, * `package.json` `workspaces` field), resolves glob patterns against the filesystem, * and reads each matched `package.json` to produce {@link WorkspacePackage} records. * * @remarks * WorkspaceDiscovery is the last service in the Discovery group and the primary * data source for downstream services. DependencyGraph, TopologicalSorter, * PackageResolver, and ChangeDetector all depend on the package list it produces. * * The live layer (`WorkspaceDiscoveryLive`) depends on `WorkspaceRoot` and * `PackageManagerDetector`. It requires `FileSystem` and `Path` from * `@effect/platform`. Use `WorkspacesLive` or `WorkspacesFullLive` to get all * wiring handled automatically. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/WorkspaceDiscovery`. Dependencies (WorkspaceRoot, * PackageManagerDetector) are resolved at layer construction time so that service * methods have `R = never`. * * @example Listing all workspace packages * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { WorkspaceDiscovery, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const discovery = yield* WorkspaceDiscovery; * const packages = yield* discovery.listPackages(); * for (const pkg of packages) { * console.log(`${pkg.name} @ ${pkg.path}`); * } * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class WorkspaceDiscovery extends WorkspaceDiscovery_base {} //#endregion //#region src/services/WorkspaceRoot.d.ts declare const WorkspaceRoot_base: Context.TagClass Effect.Effect; }>; /** * Service for finding the workspace root directory. * * Walks up from a given directory looking for workspace markers * (pnpm-workspace.yaml, package.json with workspaces field, bun.lock, yarn.lock). * * @remarks * WorkspaceRoot is the foundation of the Discovery service group. Nearly every * other service depends on it transitively, since workspace operations need a * known root directory. The implementation uses `@effect/platform` FileSystem * to traverse parent directories, so it works on any platform that provides a * FileSystem layer (Node, Bun, etc.). * * The live layer (`WorkspaceRootLive`) requires `FileSystem` and `Path` from * `@effect/platform`. For convenience, these are provided by `NodeContext.layer` * or `BunContext.layer`. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/WorkspaceRoot`. All dependencies are * resolved at layer construction time so that service methods have `R = never`. * * @example Finding the workspace root * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { WorkspaceRoot, WorkspaceRootLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const root = yield* WorkspaceRoot; * const rootPath = yield* root.find(process.cwd()); * console.log("Workspace root:", rootPath); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspaceRootLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class WorkspaceRoot extends WorkspaceRoot_base {} //#endregion //#region src/layers/CatalogResolverLive.d.ts /** * Convenience type alias for the {@link CatalogResolverLive} layer signature. * * @public */ type CatalogResolverLiveLayer = Layer.Layer; /** * Live layer for the {@link CatalogResolver} service. * * Provides catalog assembly and specifier resolution backed by: * - Inline `catalog:` / `catalogs:` declarations in `pnpm-workspace.yaml` * - Config-dependency `updateConfig` hooks (pnpmfile hook replay) * - Lockfile-recorded catalogs (pnpm `pmSpecific.catalogs`) * * Assembly is deferred to the first use and memoized via `Effect.cached`, * matching the lazy-init pattern used by {@link LockfileReaderLive}. * * @public */ declare const CatalogResolverLive: CatalogResolverLiveLayer; //#endregion //#region src/services/ChangeDetector.d.ts declare const ChangeDetectionOptions_base: Schema.Class string; }>; /** * Head ref to compare to. * * @defaultValue `"HEAD"` */ head: Schema.optionalWith string; }>; /** * If true, include uncommitted working tree changes in addition to * committed changes between `base` and `head`. * * @defaultValue `false` */ includeUncommitted: Schema.optionalWith false; }>; }, Schema.Struct.Encoded<{ /** * Base ref to compare against (commit SHA, branch, tag). * * @defaultValue `"HEAD~1"` */ base: Schema.optionalWith string; }>; /** * Head ref to compare to. * * @defaultValue `"HEAD"` */ head: Schema.optionalWith string; }>; /** * If true, include uncommitted working tree changes in addition to * committed changes between `base` and `head`. * * @defaultValue `false` */ includeUncommitted: Schema.optionalWith false; }>; }>, never, { readonly base?: string | undefined; } & { readonly head?: string | undefined; } & { readonly includeUncommitted?: boolean | undefined; }, {}, {}>; /** * Options for change detection operations. * * Configures the git ref range and whether to include uncommitted changes. * All fields have sensible defaults and can be omitted. * * @remarks * This is an Effect `Schema.Class`, so instances can be created with * `new ChangeDetectionOptions({ ... })` or decoded from unknown data via * `Schema.decodeUnknown(ChangeDetectionOptions)`. Default values are applied * for omitted fields. * * @example Creating options * ```typescript * import { ChangeDetectionOptions } from "workspaces-effect"; * * // Use defaults: base="HEAD~1", head="HEAD", includeUncommitted=false * const defaults = new ChangeDetectionOptions({}); * * // Compare against a specific branch * const vsBranch = new ChangeDetectionOptions({ base: "origin/main" }); * * // Include working tree changes * const withUncommitted = new ChangeDetectionOptions({ * base: "HEAD~3", * includeUncommitted: true, * }); * ``` * * @public */ declare class ChangeDetectionOptions extends ChangeDetectionOptions_base {} declare const ChangeDetector_base: Context.TagClass Effect.Effect, GitNotAvailableError | ChangeDetectionError>; /** * Get packages that contain changed files. * * Combines `changedFiles` with PackageResolver to determine which workspace * packages own the changed files. Files outside workspace packages are ignored. * * @param options - The {@link ChangeDetectionOptions} specifying the ref range. * @returns An Effect that succeeds with a readonly array of * {@link WorkspacePackage} records representing directly changed packages, or * fails with {@link GitNotAvailableError} or {@link ChangeDetectionError}. */ readonly changedPackages: (options: ChangeDetectionOptions) => Effect.Effect, GitNotAvailableError | ChangeDetectionError>; /** * Get changed packages plus all packages that transitively depend on them. * * Extends `changedPackages` by walking the reverse dependency graph to find * all packages that could be affected by the changes. * * @param options - The {@link ChangeDetectionOptions} specifying the ref range. * @returns An Effect that succeeds with a readonly array of * {@link WorkspacePackage} records representing all affected packages, or * fails with {@link GitNotAvailableError}, {@link ChangeDetectionError}, or * {@link CyclicDependencyError}. */ readonly affectedPackages: (options: ChangeDetectionOptions) => Effect.Effect, GitNotAvailableError | ChangeDetectionError | CyclicDependencyError>; }>; /** * Service for detecting changes in workspace packages using git. * * Provides progressive disclosure: raw changed files, changed packages, and * affected packages (including transitive dependents). All git operations use * the `Command` service from `@effect/platform` for runtime independence. * * @remarks * ChangeDetector is the second service in the Change Detection group. It * composes PackageResolver (to map files to packages), DependencyGraph (for * transitive impact), and git commands (for diff output). This makes it the * most dependency-heavy service in the library. * * The three methods offer increasing levels of analysis: * - `changedFiles` — raw git diff output (file paths only) * - `changedPackages` — files resolved to their owning workspace packages * - `affectedPackages` — changed packages plus all transitive dependents * * The live layer (`ChangeDetectorLive`) depends on `PackageResolver`, * `DependencyGraph`, `TopologicalSorter`, and `WorkspaceRoot`. It requires * `FileSystem`, `Path`, and `CommandExecutor` from `@effect/platform`. Use * `WorkspacesFullLive` to get all wiring handled automatically. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/ChangeDetector`. The CommandExecutor * dependency is resolved at layer construction time so that service methods * have `R = never`. * * @example Detecting affected packages in a CI pipeline * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { ChangeDetector, ChangeDetectionOptions, WorkspacesFullLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const detector = yield* ChangeDetector; * const options = new ChangeDetectionOptions({ base: "origin/main" }); * * const affected = yield* detector.affectedPackages(options); * console.log("Packages to rebuild:", affected.map((p) => p.name)); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesFullLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class ChangeDetector extends ChangeDetector_base {} //#endregion //#region src/services/DependencyGraph.d.ts declare const DependencyGraph_base: Context.TagClass Effect.Effect, PackageNotFoundError>; /** * Get direct dependents of a package (packages that depend on it). * * @param name - The workspace package name. * @returns An Effect that succeeds with a readonly array of dependent package * names, or fails with {@link PackageNotFoundError} if `name` is not in the * workspace. */ readonly dependentsOf: (name: string) => Effect.Effect, PackageNotFoundError>; /** * Get all package names in the graph. * * @returns An Effect that succeeds with a readonly array of all workspace * package names. Never fails. */ readonly packages: () => Effect.Effect>; /** * Check if the graph contains any cycles. * * @returns An Effect that succeeds with `true` if a cycle exists, `false` * otherwise. Never fails. */ readonly hasCycle: () => Effect.Effect; /** * Get the full adjacency map (package name to its dependency names). * * @returns An Effect that succeeds with a `ReadonlyMap` where each key is a * package name and each value is the set of packages it depends on. Never fails. */ readonly adjacencyMap: () => Effect.Effect>>; }>; /** * Service for querying the inter-workspace dependency graph. * * The graph contains only edges between workspace packages — external npm * dependencies are excluded. Edges are derived from `dependencies`, * `devDependencies`, and `peerDependencies` in each workspace `package.json`. * * @remarks * DependencyGraph is the first service in the Package Analysis group. It provides * the structural data that TopologicalSorter uses for build ordering and that * ChangeDetector uses for transitive impact analysis. * * The graph is eagerly constructed at layer creation time from the workspace * package list provided by WorkspaceDiscovery. This means all queries are fast * lookups with no additional filesystem or process I/O. * * The live layer (`DependencyGraphLive`) depends on `WorkspaceDiscovery` (and * transitively on `WorkspaceRoot`). Use `WorkspacesLive` or `WorkspacesFullLive` * to get all wiring handled automatically. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/DependencyGraph`. The adjacency map is built * eagerly via `Layer.effect`, so all service methods have `R = never` and perform * pure in-memory lookups. * * @example Querying dependencies of a package * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { DependencyGraph, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const graph = yield* DependencyGraph; * const deps = yield* graph.dependenciesOf("@myorg/ui"); * console.log("Dependencies:", deps); * * const dependents = yield* graph.dependentsOf("@myorg/core"); * console.log("Packages that depend on core:", dependents); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class DependencyGraph extends DependencyGraph_base {} //#endregion //#region src/services/PackageResolver.d.ts declare const PackageResolver_base: Context.TagClass Effect.Effect>; /** * Batch resolve: map multiple file paths to their owning packages (deduped by package). * * @param filePaths - Readonly array of absolute file paths. * @returns An Effect that succeeds with a `ReadonlyMap` keyed by package name, * with the corresponding {@link WorkspacePackage} as the value. Files outside * all packages are silently excluded. Never fails. */ readonly resolveFiles: (filePaths: ReadonlyArray) => Effect.Effect>; /** * Get all indexed package paths (sorted by path length, longest first). * * Useful for debugging or inspecting the internal path index. * * @returns An Effect that succeeds with a readonly array of path/package pairs. * Never fails. */ readonly packagePaths: () => Effect.Effect>; }>; /** * Service for resolving file paths to workspace packages. * * Uses prefix matching on absolute paths to determine which workspace package * owns a given file. The package path index is built from WorkspaceDiscovery * output at layer construction time for fast lookups. * * @remarks * PackageResolver is the first service in the Change Detection group. It provides * the bridge between raw file paths (e.g., from `git diff`) and workspace package * identities. ChangeDetector uses it to map changed files to their owning packages. * * Path matching is done longest-prefix-first so that nested packages (e.g., * `packages/foo/packages/bar`) are resolved correctly. * * The live layer (`PackageResolverLive`) depends on `WorkspaceDiscovery` (and * transitively on `WorkspaceRoot`). It requires `FileSystem`, `Path`, and * `CommandExecutor` from `@effect/platform`. Use `WorkspacesFullLive` to get * all wiring handled automatically. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/PackageResolver`. The path index is built * eagerly via `Layer.effect` and sorted by path length (longest first) to ensure * correct longest-prefix matching. * * @example Resolving changed files to packages * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { PackageResolver, WorkspacesFullLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const resolver = yield* PackageResolver; * const owner = yield* resolver.resolveFile("/workspace/packages/ui/src/Button.tsx"); * console.log("Owner:", owner); * * const changedFiles = [ * "/workspace/packages/ui/src/Button.tsx", * "/workspace/packages/core/src/index.ts", * ]; * const packageMap = yield* resolver.resolveFiles(changedFiles); * console.log("Affected packages:", [...packageMap.keys()]); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesFullLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class PackageResolver extends PackageResolver_base {} //#endregion //#region src/layers/ChangeDetectorLive.d.ts /** * Live layer for the {@link ChangeDetector} service. * * Provides git-based change detection for monorepo packages. Compares * commits to identify changed files, maps them to owning packages, * and optionally walks the dependency graph to find transitively * affected packages. * * @remarks * Requires {@link PackageResolver}, {@link DependencyGraph}, and * `CommandExecutor` from `@effect/platform`. The `CommandExecutor` is * resolved at construction time so all service methods have `R = never`. * * @privateRemarks * Git commands are executed via `Command.make` + `CommandExecutor.string`. * The working directory for git operations is derived from the first * entry in the package path index. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { ChangeDetector, WorkspacesFullLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const detector = yield* ChangeDetector; * const affected = yield* detector.affectedPackages({ * base: "main", * head: "HEAD", * }); * return affected; * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesFullLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const ChangeDetectorLive: Layer.Layer; //#endregion //#region src/schemas/CatalogSet.d.ts declare const CatalogSet_base: Schema.Class>; }, Schema.Struct.Encoded<{ entries: Schema.Record$>; }>, never, { readonly entries: { readonly [x: string]: { readonly [x: string]: string; }; }; }, {}, {}>; /** * An immutable, fully-normalized catalog collection with the one * resolution semantic shared by live and point-in-time resolution. * * @public */ declare class CatalogSet extends CatalogSet_base { /** An empty catalog set. */ static empty(): CatalogSet; /** Wrap a pnpm `Catalogs` map, dropping undefined entries. */ static fromCatalogs(catalogs: Catalogs$1): CatalogSet; /** Parse the `catalog:`/`catalogs:` sections of a pnpm-workspace.yaml text. */ static fromWorkspaceYaml(text: string): Effect.Effect; /** * Normalize a pnpm lockfile `catalogs:` section — entries are either a * specifier string or a `{ specifier, version }` object. */ static fromLockfileCatalogs(raw: unknown): CatalogSet; /** Merge sets; later sets win per dependency within a catalog. */ static merge(...sets: ReadonlyArray): CatalogSet; /** View as the pnpm `Catalogs` shape. */ toCatalogs(): Catalogs$1; /** * Resolve a `catalog:` specifier to its concrete range. `Option.none` * for non-catalog specifiers and unresolved catalog entries. * * @remarks * Deliberately contrasts with `CatalogResolver.resolveSpecifier`: this * method is catalog-only and returns `Option.none` on unresolvable refs, * whereas the live service also handles `workspace:` specifiers and fails * with a typed `CatalogResolutionError`. Both route through * `resolveManifest`, which is the single resolution semantic. */ resolveSpecifier(dependency: string, specifier: string): Option.Option; } //#endregion //#region src/layers/catalog/package-json-workspaces.d.ts /** * The catalog- and glob-bearing slice of the npm/bun `workspaces` field of a * root `package.json`. * * @remarks * npm and bun accept `workspaces` as an array of globs, or as an object with a * `packages` array. Bun additionally reads `catalog` (the default catalog) and * `catalogs` (named catalogs) from the object form — the package.json analogue * of pnpm's `pnpm-workspace.yaml` `catalog:` / `catalogs:` keys. * * @public */ interface PackageJsonWorkspaces { readonly packages?: ReadonlyArray | undefined; readonly catalog?: Record | undefined; readonly catalogs?: Record> | undefined; } /** * Parse the `workspaces` field out of a root `package.json`'s text. * * @param content - Raw `package.json` text. * @returns An Effect yielding the workspaces slice; all fields are `undefined` * when the manifest has no `workspaces` field, or when `workspaces` is * explicitly `null` (both are legitimate, common shapes — not every root * `package.json` declares workspaces, and `null` is a plausible output of * tooling that serializes a stripped field). Fails with * {@link CatalogAssemblyError} when the text is not valid JSON, or when a * present, non-null `workspaces` field is not a valid npm/bun shape (not an * array of strings and not an object with valid * `packages`/`catalog`/`catalogs`) — an unreadable manifest must never be * silently treated as an empty one, since that would make every dependency * in the workspace look "added". * * @public */ declare const parsePackageJsonWorkspaces: (content: string) => Effect.Effect; /** * Build a {@link CatalogSet} from a root `package.json`'s `workspaces` field. * * @remarks * `workspaces.catalog` becomes the `"default"` catalog; every key of * `workspaces.catalogs` becomes a catalog of that name. This mirrors how * {@link CatalogSet.fromWorkspaceYaml} treats pnpm's `catalog:` / `catalogs:`. * * Declaring the default catalog twice — once as `workspaces.catalog` and * again as `workspaces.catalogs.default` — is rejected with * {@link CatalogAssemblyError} rather than silently resolved (pnpm itself * rejects the equivalent duplication in `pnpm-workspace.yaml`). Presence is * checked structurally (`!== undefined` / `Object.hasOwn`), not by * truthiness, so an explicitly-declared empty catalog (`catalog: {}` or * `catalogs: { default: {} }`) still counts as a declaration. * * @param content - Raw `package.json` text. * * @public */ declare const catalogSetFromPackageJson: (content: string) => Effect.Effect; //#endregion //#region src/layers/catalog/workspace-manifest.d.ts /** * The catalog-relevant slice of pnpm-workspace.yaml. * * @remarks * Exported (and tagged `@public`) because it appears in the `extends` * clause of the `@public` {@link WorkspaceManifestData} interface — * api-extractor requires base types of public exports to themselves be * exported from the entry point. * * @public */ interface WorkspaceManifestCatalogs { /** The default (unnamed) catalog. */ readonly catalog?: Record | undefined; /** Named catalogs. */ readonly catalogs?: Record> | undefined; /** configDependencies map (name to versionSpec). */ readonly configDependencies?: Record | undefined; } /** The point-in-time-relevant slice of pnpm-workspace.yaml. @public */ interface WorkspaceManifestData extends WorkspaceManifestCatalogs { /** Workspace package globs (the `packages:` list). */ readonly packages?: ReadonlyArray | undefined; } /** * Parse a pnpm-workspace.yaml text into its catalog/config-dependency/packages * slice. Pure with respect to the filesystem. * * @public */ declare const workspaceManifestFromYaml: (content: string) => Effect.Effect; //#endregion //#region src/layers/DependencyGraphLive.d.ts /** * Live layer for the {@link DependencyGraph} service. * * Builds a directed dependency graph of inter-workspace packages at * construction time. Provides cached lookups for forward dependencies, * reverse dependents, and cycle detection. * * @remarks * Requires {@link WorkspaceDiscovery}. The graph is built eagerly at * layer construction and uses an Effect `Request.Cache` for deduplicating * `dependenciesOf` and `dependentsOf` lookups. * * @privateRemarks * Graph construction happens via {@link buildGraph}, which scans both * `dependencies` and `devDependencies` for inter-workspace edges. Uses * `RequestResolver.fromEffect` with per-layer caching to avoid redundant * lookups within the same fiber. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { DependencyGraph, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const graph = yield* DependencyGraph; * const deps = yield* graph.dependenciesOf("@my/package"); * return deps; * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const DependencyGraphLive: Layer.Layer; //#endregion //#region src/schemas/lockfile.d.ts declare const ResolvedPackage_base: Schema.Class; isWorkspace: typeof Schema.Boolean; relativePath: Schema.optional; dependencies: Schema.optionalWith, { default: () => {}; }>; }, Schema.Struct.Encoded<{ name: typeof Schema.NonEmptyString; version: typeof Schema.String; integrity: Schema.optional; isWorkspace: typeof Schema.Boolean; relativePath: Schema.optional; dependencies: Schema.optionalWith, { default: () => {}; }>; }>, never, { readonly integrity?: string | undefined; } & { readonly relativePath?: string | undefined; } & { readonly dependencies?: { readonly [x: string]: string; } | undefined; } & { readonly isWorkspace: boolean; } & { readonly name: string; } & { readonly version: string; }, {}, {}>; /** * A package resolved from a lockfile. * * @remarks * Represents a single resolved package entry from any supported lockfile * format. The {@link LockfileReader} normalizes format-specific entries * (pnpm YAML, npm JSON, yarn Berry, bun JSONC) into this common shape. * * Fields: * - `name` — the resolved package name (non-empty string). * - `version` — the resolved version string. * - `integrity` — optional SRI integrity hash (e.g., `"sha512-..."`). * - `isWorkspace` — `true` if this package is a workspace-local reference. * - `dependencies` — map of this package's own dependencies (defaults to `{}`). * * @example Creating a ResolvedPackage * ```typescript * import { ResolvedPackage } from "workspaces-effect"; * * const pkg = new ResolvedPackage({ * name: "lodash", * version: "4.17.21", * integrity: "sha512-v2kDE...", * isWorkspace: false, * }); * ``` * * @public */ declare class ResolvedPackage extends ResolvedPackage_base {} declare const ImporterDependency_base: Schema.Class; depType: Schema.Literal<["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]>; }, Schema.Struct.Encoded<{ name: typeof Schema.NonEmptyString; specifier: typeof Schema.String; version: Schema.optional; depType: Schema.Literal<["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]>; }>, never, { readonly version?: string | undefined; } & { readonly depType: "dependencies" | "devDependencies" | "optionalDependencies" | "peerDependencies"; } & { readonly name: string; } & { readonly specifier: string; }, {}, {}>; /** * One declared dependency of one workspace importer, as the lockfile records it. * * @remarks * `specifier` is the range declared in the importer's `package.json` (which may * be a `catalog:` reference); `version` is the concrete version the lockfile * resolved it to. Together they are what a before/after lockfile diff needs — * the pair the parsers used to discard. * * `version` is populated by **pnpm only**: pnpm records `{ specifier, version }` * per importer dependency, while bun and npm record the resolved version on * their package tuples/entries instead. So for a bun or npm lockfile every * `ImporterDependency` carries a `specifier` and no `version`, and a consumer * that needs the resolved version joins by name against the `packages` field of * {@link LockfileData}. yarn does not record importers at all — its `importers` * field is always empty. * * @example Reading an importer's dependencies * ```typescript * import { Effect } from "effect"; * import { LockfileReader } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * const data = yield* reader.readLockfile(); * for (const importer of data.importers) { * for (const dep of importer.dependencies) { * console.log(importer.path, dep.name, dep.specifier, dep.version); * } * } * }); * ``` * * @public */ declare class ImporterDependency extends ImporterDependency_base {} declare const LockfileImporter_base: Schema.Class; }, Schema.Struct.Encoded<{ path: typeof Schema.String; dependencies: Schema.Array$; }>, never, { readonly dependencies: readonly ImporterDependency[]; } & { readonly path: string; }, {}, {}>; /** * One workspace importer's declared dependencies, as the lockfile records them. * * @remarks * `path` is the importer path relative to the workspace root — `"."` for the * root package — matching the keys of `WorkspaceDiscovery.importerMap()`. * * Populated by the pnpm, bun, and npm parsers. yarn does not record importers, * so a yarn lockfile always yields an empty `importers` array. * * @example Finding the root importer * ```typescript * import { Effect } from "effect"; * import { LockfileReader } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * const data = yield* reader.readLockfile(); * const root = data.importers.find((i) => i.path === "."); * return root?.dependencies.length ?? 0; * }); * ``` * * @public */ declare class LockfileImporter extends LockfileImporter_base {} declare const WorkspaceDependency_base: Schema.Class; constraint: typeof Schema.String; }, Schema.Struct.Encoded<{ from: typeof Schema.NonEmptyString; to: typeof Schema.NonEmptyString; depType: Schema.Literal<["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]>; constraint: typeof Schema.String; }>, never, { readonly constraint: string; } & { readonly depType: "dependencies" | "devDependencies" | "optionalDependencies" | "peerDependencies"; } & { readonly from: string; } & { readonly to: string; }, {}, {}>; /** * A dependency relationship between two workspace packages in the lockfile. * * @remarks * Captures the directed edge from one workspace package to another as recorded * in the lockfile. Used by {@link LockfileReader} to build the workspace * dependency subgraph from lockfile data. * * Fields: * - `from` — the name of the workspace package that declares the dependency. * - `to` — the name of the workspace package that is depended upon. * - `depType` — which dependency map contains this relationship * (`"dependencies"`, `"devDependencies"`, `"peerDependencies"`, or `"optionalDependencies"`). * - `constraint` — the version constraint string (e.g., `"workspace:*"`, `"^1.0.0"`). * * @example Creating a WorkspaceDependency * ```typescript * import { WorkspaceDependency } from "workspaces-effect"; * * const dep = new WorkspaceDependency({ * from: "@my-org/app", * to: "@my-org/utils", * depType: "dependencies", * constraint: "workspace:*", * }); * ``` * * @public */ declare class WorkspaceDependency extends WorkspaceDependency_base {} declare const PnpmExtension_base: Schema.Class; catalogs: Schema.optional]>>>>; overrides: Schema.optional>; settings: Schema.optional; excludeLinksFromLockfile: Schema.optional; }>>; }, Schema.Struct.Encoded<{ _tag: Schema.Literal<["pnpm"]>; catalogs: Schema.optional]>>>>; overrides: Schema.optional>; settings: Schema.optional; excludeLinksFromLockfile: Schema.optional; }>>; }>, never, { readonly catalogs?: { readonly [x: string]: { readonly [x: string]: string | { readonly specifier: string; readonly version: string; }; }; } | undefined; } & { readonly overrides?: { readonly [x: string]: string; } | undefined; } & { readonly settings?: { readonly autoInstallPeers?: boolean | undefined; readonly excludeLinksFromLockfile?: boolean | undefined; } | undefined; } & { readonly _tag: "pnpm"; }, {}, {}>; /** * Extension data specific to pnpm lockfiles. * * @remarks * Captures pnpm-specific lockfile features that do not have equivalents in * other package managers. Attached to {@link LockfileData} via the * `pmSpecific` field when the package manager is pnpm. * * Fields: * - `_tag` — discriminant literal `"pnpm"`. * - `catalogs` — pnpm catalog definitions (named groups of version constraints). * - `overrides` — version override map from `pnpm.overrides` in package.json. * - `settings` — pnpm-specific settings recorded in the lockfile header. * * @example Accessing pnpm-specific data * ```typescript * import { Effect } from "effect"; * import { LockfileReader, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * const data = yield* reader.readLockfile(); * if (data.pmSpecific?._tag === "pnpm") { * console.log("Catalogs:", data.pmSpecific.catalogs); * } * }); * ``` * * @public */ declare class PnpmExtension extends PnpmExtension_base {} declare const BunExtension_base: Schema.Class; catalog: Schema.optional>; catalogs: Schema.optional>>; overrides: Schema.optional>; trustedDependencies: Schema.optional>; }, Schema.Struct.Encoded<{ _tag: Schema.Literal<["bun"]>; catalog: Schema.optional>; catalogs: Schema.optional>>; overrides: Schema.optional>; trustedDependencies: Schema.optional>; }>, never, { readonly catalog?: { readonly [x: string]: unknown; } | undefined; } & { readonly catalogs?: { readonly [x: string]: { readonly [x: string]: unknown; }; } | undefined; } & { readonly overrides?: { readonly [x: string]: string; } | undefined; } & { readonly trustedDependencies?: readonly string[] | undefined; } & { readonly _tag: "bun"; }, {}, {}>; /** * Extension data specific to bun lockfiles. * * @remarks * Captures bun-specific lockfile features that do not have equivalents in * other package managers. Attached to {@link LockfileData} via the * `pmSpecific` field when the package manager is bun. Bun lockfiles use * JSONC format (JSON with comments). * * Fields: * - `_tag` — discriminant literal `"bun"`. * - `catalog` — the default (unnamed) catalog. * - `catalogs` — named catalog definitions. * - `overrides` — version override map. * - `trustedDependencies` — list of packages allowed to run install scripts. * * @example Accessing bun-specific data * ```typescript * import { Effect } from "effect"; * import { LockfileReader, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * const data = yield* reader.readLockfile(); * if (data.pmSpecific?._tag === "bun") { * console.log("Trusted deps:", data.pmSpecific.trustedDependencies); * } * }); * ``` * * @public */ declare class BunExtension extends BunExtension_base {} declare const LockfileData_base: Schema.Class; lockfileVersion: typeof Schema.String; packages: Schema.Array$; workspaceDependencies: Schema.Array$; importers: Schema.optionalWith, { default: () => never[]; }>; pmSpecific: Schema.optional>; }, Schema.Struct.Encoded<{ packageManager: Schema.Literal<["npm", "pnpm", "yarn", "bun"]>; lockfileVersion: typeof Schema.String; packages: Schema.Array$; workspaceDependencies: Schema.Array$; importers: Schema.optionalWith, { default: () => never[]; }>; pmSpecific: Schema.optional>; }>, never, { readonly pmSpecific?: BunExtension | PnpmExtension | undefined; } & { readonly importers?: readonly LockfileImporter[] | undefined; } & { readonly lockfileVersion: string; } & { readonly packageManager: "bun" | "npm" | "pnpm" | "yarn"; } & { readonly packages: readonly ResolvedPackage[]; } & { readonly workspaceDependencies: readonly WorkspaceDependency[]; }, {}, {}>; /** * Normalized lockfile data common to all package managers. * * @remarks * The primary output of {@link LockfileReader}. Provides a unified view of * lockfile contents regardless of the underlying package manager format. * Package-manager-specific extensions are available via the `pmSpecific` * discriminated union field. * * Fields: * - `packageManager` — which package manager produced the lockfile. * - `lockfileVersion` — the lockfile format version string. * - `packages` — all resolved packages as {@link ResolvedPackage} instances. * - `workspaceDependencies` — inter-workspace edges as {@link WorkspaceDependency} instances. * - `importers` — each workspace importer's declared dependencies as * {@link LockfileImporter} instances (empty for yarn, which does not record them). * - `pmSpecific` — optional package-manager-specific data ({@link PnpmExtension} or {@link BunExtension}). * * @example Reading lockfile data * ```typescript * import { Effect } from "effect"; * import { LockfileReader, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * const data = yield* reader.readLockfile(); * console.log(`${data.packages.length} packages resolved by ${data.packageManager}`); * }); * ``` * * @public */ declare class LockfileData extends LockfileData_base {} declare const LockfileIntegrity_base: Schema.Class; extraWorkspaces: Schema.Array$; unsatisfiedConstraints: Schema.Array$; }>>; }, Schema.Struct.Encoded<{ valid: typeof Schema.Boolean; missingWorkspaces: Schema.Array$; extraWorkspaces: Schema.Array$; unsatisfiedConstraints: Schema.Array$; }>>; }>, never, { readonly extraWorkspaces: readonly string[]; } & { readonly missingWorkspaces: readonly string[]; } & { readonly unsatisfiedConstraints: readonly { readonly workspace: string; readonly dependency: string; readonly constraint: string; readonly resolved: string; readonly depType: "dependencies" | "devDependencies" | "optionalDependencies" | "peerDependencies"; }[]; } & { readonly valid: boolean; }, {}, {}>; /** * Result of lockfile integrity validation. * * @remarks * Produced by {@link LockfileReader} when comparing lockfile contents against * the workspace's declared dependencies. Unlike {@link LockfileIntegrityError}, * this is a data type (not an error) — it reports *what* mismatches exist * without failing the pipeline. * * Fields: * - `valid` — `true` if the lockfile is fully consistent with workspace declarations. * - `missingWorkspaces` — workspace package names present in the workspace but absent from the lockfile. * - `extraWorkspaces` — entries in the lockfile that do not correspond to any workspace package. * - `unsatisfiedConstraints` — dependency constraints declared in workspace packages * that the lockfile's resolved versions do not satisfy. * * @example Checking integrity * ```typescript * import { Effect } from "effect"; * import type { LockfileIntegrity } from "workspaces-effect"; * import { LockfileReader, LockfileReaderLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * const integrity = yield* reader.checkIntegrity(); * if (!integrity.valid) { * console.log("Missing:", integrity.missingWorkspaces); * console.log("Extra:", integrity.extraWorkspaces); * } * }); * ``` * * @public */ declare class LockfileIntegrity extends LockfileIntegrity_base {} //#endregion //#region src/services/LockfileReader.d.ts /** * Union of errors that may surface from {@link LockfileReader} method calls * because the live layer defers workspace-root discovery, package-manager * detection, and lockfile read/parse to the first invocation. * * @public */ type LockfileInitError = WorkspaceRootNotFoundError | PackageManagerDetectionError | LockfileReadError | LockfileParseError; declare const LockfileReader_base: Context.TagClass Effect.Effect; /** * Look up the resolved version of a package in the lockfile. * * @param packageName - The npm package name to look up (e.g., `"react"`). * @returns An Effect that succeeds with `Option.some(resolvedPackage)` if the * package is found in the lockfile, or `Option.none()` if it is not present. * Fails with a {@link LockfileInitError} variant on first invocation if * initialization fails. */ readonly resolvedVersion: (packageName: string) => Effect.Effect, LockfileInitError>; /** * Get all workspace-to-workspace dependency links from the lockfile. * * @returns An Effect that succeeds with a readonly array of * {@link WorkspaceDependency} records representing inter-workspace * dependency relationships as declared in the lockfile. Fails with a * {@link LockfileInitError} variant on first invocation if initialization * fails. */ readonly workspaceDependencies: () => Effect.Effect, LockfileInitError>; /** * Verify lockfile integrity against the current `package.json` files. * * Checks that all workspace dependencies in `package.json` are properly * reflected in the lockfile. * * @returns An Effect that succeeds with a {@link LockfileIntegrity} report, or * fails with {@link LockfileIntegrityError} if critical integrity violations * are detected. May also fail with a {@link LockfileInitError} variant on * first invocation if initialization fails. */ readonly checkIntegrity: () => Effect.Effect; }>; /** * Service for reading and querying package manager lockfile data. * * Provides a unified interface over all four lockfile formats (npm * `package-lock.json`, pnpm `pnpm-lock.yaml`, yarn `yarn.lock`, bun `bun.lock`). * The correct parser is selected automatically based on the detected package manager. * * @remarks * LockfileReader is part of the Configuration and Lockfiles service group. It * abstracts over the substantial format differences between lockfiles, exposing * a consistent query API regardless of the underlying package manager. * * The live layer (`LockfileReaderLive`) depends on `WorkspaceRoot` and * `PackageManagerDetector`. It requires `FileSystem` and `Path` from * `@effect/platform`. Use `WorkspacesLive` or `WorkspacesFullLive` to get all * wiring handled automatically. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/LockfileReader`. The lockfile is parsed lazily * on first access and cached internally. The parsing strategy is determined by * the `PackageManagerType` from `PackageManagerDetector`. * * @example Reading lockfile data * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { LockfileReader, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * const lockfile = yield* reader.readLockfile(); * console.log(`Package manager: ${lockfile.packageManager}`); * console.log(`Total packages: ${lockfile.packages.length}`); * * const react = yield* reader.resolvedVersion("react"); * console.log("React version:", react); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class LockfileReader extends LockfileReader_base {} //#endregion //#region src/services/PackageManagerDetector.d.ts /** * Result of package manager detection. * * @remarks * The `type` field identifies the package manager (`npm`, `pnpm`, `yarn`, or `bun`). * The `version` field's provenance depends on which detection source matched: * it may come from the root `package.json`'s `packageManager` field (e.g., * `"pnpm@9.15.4"` yields `"9.15.4"`) OR from `devEngines.packageManager.version`. * When `devEngines.packageManager` names the same package manager as the * `packageManager` field, the `packageManager` field's version wins — it is an * exact pin, whereas `devEngines.packageManager.version` may be a semver range. * Consumers that need an exact, installable version should not assume `version` * is always a single resolved version: when it was sourced from `devEngines` * alone (no matching `packageManager` field), it may be a range such as `"^9"`. * `version` is `undefined` when neither source yields a value for the detected * package manager (e.g. detection fell back to lock file heuristics with no * `packageManager` field present). * * @public */ interface DetectedPackageManager { /** The detected package manager type. */ readonly type: PackageManagerType; /** * The version string, or `undefined` when neither `packageManager` nor * `devEngines.packageManager` yields one. May be an exact pin (from * `packageManager`) or a semver range (from `devEngines.packageManager` * alone) — see the {@link DetectedPackageManager} remarks for the full * provenance and precedence rules. */ readonly version: string | undefined; /** * The inferred runtime environment based on the detected package manager. * `"bun"` when the PM is Bun; `"node"` for npm, pnpm, and yarn. * Note: this reflects the package manager type, not the actual Node.js/Bun * process — a Bun project using npm will still report `"node"`. */ readonly runtime: "node" | "bun"; } declare const PackageManagerDetector_base: Context.TagClass Effect.Effect; }>; /** * Service for detecting the package manager used by a workspace. * * Detection priority: * 1. pnpm — `pnpm-workspace.yaml` exists * 2. bun — `bun.lock`/`bun.lockb` exists AND `packageManager` starts with `bun@` * 3. yarn — `yarn.lock` exists AND `packageManager` starts with `yarn@` * 4. npm — fallback if `package.json` has a `workspaces` field * * @remarks * PackageManagerDetector is part of the Discovery service group. It is used by * downstream services (WorkspaceDiscovery, LockfileReader) to select the * correct parsing strategy for workspace configuration and lockfiles. * * The live layer (`PackageManagerDetectorLive`) requires `FileSystem` and `Path` * from `@effect/platform`. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/PackageManagerDetector`. Dependencies are * resolved at layer construction time so that service methods have `R = never`. * * @example Detecting the package manager * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import type { DetectedPackageManager } from "workspaces-effect"; * import { PackageManagerDetector, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const detector = yield* PackageManagerDetector; * const pm: DetectedPackageManager = yield* detector.detect("/path/to/monorepo"); * console.log(`Package manager: ${pm.type}${pm.version ? `@${pm.version}` : ""}`); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class PackageManagerDetector extends PackageManagerDetector_base {} //#endregion //#region src/layers/LockfileReaderLive.d.ts /** * Parse lockfile text for a known package manager. * * @remarks * The pure core of {@link LockfileReader}, exposed so a caller holding two * snapshots of a lockfile — a "before" and an "after" — can parse both in one * process. The service itself reads a single lockfile from the workspace root * and memoizes it, which cannot express a diff. * * @param content - Raw lockfile text. * @param lockfilePath - Path used only for error reporting. * @param pm - The package manager whose format `content` is in. * * @example Diffing two snapshots * ```typescript * import { Effect } from "effect"; * import { parseLockfileContent } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const before = yield* parseLockfileContent(beforeText, "pnpm-lock.yaml", "pnpm"); * const after = yield* parseLockfileContent(afterText, "pnpm-lock.yaml", "pnpm"); * return after.importers.length - before.importers.length; * }); * ``` * * @public */ declare const parseLockfileContent: (content: string, lockfilePath: string, pm: PackageManagerType) => Effect.Effect; /** * Convenience type alias for the {@link LockfileReaderLive} layer signature. * * Useful for consumers who want to annotate layer types explicitly. Layer * construction is now O(1); read and parse errors surface from service * methods on first use. * * @public */ type LockfileReaderLiveLayer = Layer.Layer; /** * Live layer for the {@link LockfileReader} service. * * Provides a unified view of the workspace lockfile (npm, pnpm, yarn Berry, * or bun) with cached version lookups, workspace dependency extraction, and * integrity checking. * * @remarks * Requires {@link WorkspaceRoot}, {@link PackageManagerDetector}, `FileSystem`, * and `Path` from `@effect/platform`. Layer construction allocates the service * record but performs no I/O. The first invocation of any method resolves the * workspace root, detects the package manager, and reads/parses the lockfile; * subsequent calls reuse the cached result for the lifetime of the layer * (success or failure are both memoized via `Effect.cached`). * * @privateRemarks * Wraps the eager initialization (root find, PM detect, lockfile read, * format-specific parse, pnpm name resolution, multi-version index) in * `Effect.cached` so the cost is paid once per service instance rather than * once per layer construction. Format-specific parsers live in `./parsers/`. * Uses an Effect `Request.Cache` for deduplicating `resolvedVersion` lookups * (same pattern as `DependencyGraphLive`). Integrity checking delegates to * {@link checkLockfileIntegrity}. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { LockfileReader, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const reader = yield* LockfileReader; * const data = yield* reader.readLockfile(); * return data.packages.length; * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const LockfileReaderLive: LockfileReaderLiveLayer; //#endregion //#region src/layers/PackageManagerDetectorLive.d.ts /** * Live layer for the {@link PackageManagerDetector} service. * * Detects which package manager (pnpm, npm, yarn, or bun) manages * a given workspace root by inspecting lockfiles and the `packageManager` * field in `package.json`. * * @remarks * Requires `FileSystem` and `Path` from `@effect/platform`. Provide these * via `NodeContext.layer` (Node.js) or `BunContext.layer` (Bun). * * @privateRemarks * Resolves `FileSystem` and `Path` at construction time, then delegates * to {@link detectPackageManager} for each `detect()` call. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { PackageManagerDetector, PackageManagerDetectorLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const detector = yield* PackageManagerDetector; * return yield* detector.detect("/path/to/monorepo"); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(PackageManagerDetectorLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const PackageManagerDetectorLive: Layer.Layer; //#endregion //#region src/layers/PackageResolverLive.d.ts /** * Live layer for the {@link PackageResolver} service. * * Resolves file paths to their owning workspace packages using * longest-prefix matching on a pre-built path index. * * @remarks * Requires {@link WorkspaceDiscovery} and `Path` from `@effect/platform`. * The path index is built eagerly at layer construction time and sorted by * path length descending so that the most specific match wins. * * @privateRemarks * Uses {@link buildPathIndex} to create a sorted array of path entries, * then performs linear scans in {@link findOwner} for each resolution. * This is efficient for typical monorepo sizes (tens of packages). * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { PackageResolver, WorkspacesFullLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const resolver = yield* PackageResolver; * const owner = yield* resolver.resolveFile("/path/to/packages/foo/src/index.ts"); * return owner; * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesFullLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const PackageResolverLive: Layer.Layer; //#endregion //#region src/schemas/WorkspaceStateSnapshot.d.ts declare const PackageStateSnapshot_base: Schema.Class, { default: () => {}; }>; devDependencies: Schema.optionalWith, { default: () => {}; }>; peerDependencies: Schema.optionalWith, { default: () => {}; }>; optionalDependencies: Schema.optionalWith, { default: () => {}; }>; }, Schema.Struct.Encoded<{ name: typeof Schema.NonEmptyString; version: typeof Schema.String; relativePath: typeof Schema.String; dependencies: Schema.optionalWith, { default: () => {}; }>; devDependencies: Schema.optionalWith, { default: () => {}; }>; peerDependencies: Schema.optionalWith, { default: () => {}; }>; optionalDependencies: Schema.optionalWith, { default: () => {}; }>; }>, never, { readonly dependencies?: { readonly [x: string]: string; } | undefined; } & { readonly devDependencies?: { readonly [x: string]: string; } | undefined; } & { readonly optionalDependencies?: { readonly [x: string]: string; } | undefined; } & { readonly peerDependencies?: { readonly [x: string]: string; } | undefined; } & { readonly name: string; } & { readonly relativePath: string; } & { readonly version: string; }, {}, {}>; /** * One workspace package as it existed at a point in time. * * @public */ declare class PackageStateSnapshot extends PackageStateSnapshot_base {} declare const WorkspaceStateSnapshot_base: Schema.Class; catalogs: typeof CatalogSet; }, Schema.Struct.Encoded<{ packages: Schema.Array$; catalogs: typeof CatalogSet; }>, never, { readonly catalogs: CatalogSet; } & { readonly packages: readonly PackageStateSnapshot[]; }, {}, {}>; /** * The full workspace state at a point in time: every package plus that * moment's assembled catalogs. `resolve` answers "what did this specifier * mean HERE" — catalog: against this snapshot's catalogs, workspace: * against this snapshot's package versions. * * @public */ declare class WorkspaceStateSnapshot extends WorkspaceStateSnapshot_base { #private; /** * name → version map for workspace: resolution. Stable reference. * * @remarks * The returned record is this instance's memo, built once and reused by * every subsequent `resolve` call. Treat it as * read-only -- mutating it corrupts resolution for the lifetime of this * snapshot. */ get versions(): Record; /** Find a package snapshot by name (O(1) after the first call). */ package(name: string): Option.Option; /** * Resolve a catalog:/workspace: specifier against THIS snapshot. * `Option.none` for plain specifiers and unresolvable references. */ resolve(dependency: string, specifier: string): Option.Option; } //#endregion //#region src/services/PointInTimeWorkspace.d.ts /** * The umbrella error union covering both {@link PointInTimeWorkspace} * methods: {@link PointInTimeAtError} (raised by `at`) unioned with * {@link PointInTimeWorktreeError} (raised by `worktree`). * * @remarks * - {@link GitReadError} — a `git show`/`git ls-tree` invocation failed for a * reason other than "path absent at this ref" (absent paths degrade to * `Option.none`, never an error). `at`-only. * - {@link CatalogAssemblyError} — the `pnpm-workspace.yaml` at the ref (or on * disk) is malformed YAML. A malformed *lockfile* never fails; it degrades to * an empty catalog set. * - {@link WorkspaceRootNotFoundError} — the workspace root could not be * located walking up from `options.cwd` (or `process.cwd()` when omitted). * - {@link WorkspaceDiscoveryError} — `worktree` failed to enumerate the live * packages via `WorkspaceDiscovery`. `worktree`-only. * * @public */ type PointInTimeReadError = PointInTimeAtError | PointInTimeWorktreeError; /** * Options accepted by both {@link PointInTimeWorkspace} methods. * * @public */ interface PointInTimeOptions { /** * Starting directory for workspace-root resolution. The root is found by * walking UP from here (same semantics as `WorkspaceDiscovery`); when * omitted, resolution starts from `process.cwd()`. */ readonly cwd?: string; } /** * Errors `at` can raise. `at` never enumerates the live filesystem, so * {@link WorkspaceDiscoveryError} cannot occur. * * @public */ type PointInTimeAtError = GitReadError | CatalogAssemblyError | WorkspaceRootNotFoundError; /** * Errors `worktree` can raise. `worktree` never invokes git, so * {@link GitReadError} cannot occur. * * @public */ type PointInTimeWorktreeError = CatalogAssemblyError | WorkspaceRootNotFoundError | WorkspaceDiscoveryError; declare const PointInTimeWorkspace_base: Context.TagClass Effect.Effect; /** * Workspace state of the live working tree (staged + unstaged edits). * * Enumerates packages via `WorkspaceDiscovery` and reads catalogs from the * on-disk `pnpm-workspace.yaml` and `pnpm-lock.yaml`. Uncached. * * @param options - Optional {@link PointInTimeOptions}; `options.cwd` is a * starting directory to walk UP from when resolving the workspace root * (same semantics as `WorkspaceDiscovery`) — when omitted, resolution * starts from `process.cwd()`. * @returns An Effect that succeeds with the live {@link WorkspaceStateSnapshot}, * or fails with {@link PointInTimeWorktreeError}. */ readonly worktree: (options?: PointInTimeOptions) => Effect.Effect; }>; /** * Service for reading a monorepo's workspace state at a specific moment: any * git ref (via `git show`/`git ls-tree`, without checking the ref out) or the * live working tree (via `WorkspaceDiscovery`). * * @remarks * Each snapshot carries that moment's packages plus its assembled pnpm catalog * set, so `catalog:`/`workspace:` specifiers resolve against the state as it * existed *then* — not against the current working tree. Catalog precedence is * lockfile-then-inline (inline `pnpm-workspace.yaml` catalogs win). * * The live layer ({@link PointInTimeWorkspaceLive}) resolves `WorkspaceRoot`, * `WorkspaceDiscovery`, `CommandExecutor`, `FileSystem`, and `Path` at layer * construction so both methods have `R = never`. Use `WorkspacesFullLive` to * get all wiring handled automatically. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/PointInTimeWorkspace`. * * @see {@link PointInTimeWorkspaceLive} for the live implementation. * * @public */ declare class PointInTimeWorkspace extends PointInTimeWorkspace_base {} //#endregion //#region src/layers/PointInTimeWorkspaceLive.d.ts /** * Convenience type alias for the {@link PointInTimeWorkspaceLive} layer signature. * * @public */ type PointInTimeWorkspaceLiveLayer = Layer.Layer; /** * Live layer for the {@link PointInTimeWorkspace} service. * * Resolves `WorkspaceRoot`, `WorkspaceDiscovery`, `CommandExecutor`, * `FileSystem`, and `Path` at layer construction so both service methods have * `R = never`. Wired into `WorkspacesFullLive`. * * @public */ declare const PointInTimeWorkspaceLive: PointInTimeWorkspaceLiveLayer; //#endregion //#region src/schemas/publish.d.ts declare const PublishTarget_base: Schema.Class; provenance: Schema.optionalWith false; }>; }, Schema.Struct.Encoded<{ name: typeof Schema.NonEmptyString; registry: typeof Schema.NonEmptyString; directory: typeof Schema.String; access: Schema.Literal<["public", "restricted"]>; provenance: Schema.optionalWith false; }>; }>, never, { readonly provenance?: boolean | undefined; } & { readonly access: "public" | "restricted"; } & { readonly directory: string; } & { readonly name: string; } & { readonly registry: string; }, {}, {}>; /** * A single publish target for a workspace package. * * @remarks * Represents the resolved publishing configuration for a workspace package, * combining defaults with any overrides from the package's `publishConfig` * field. Used to determine where and how each package should be published. * * Fields: * - `name` — the package name (non-empty string). * - `registry` — the target registry URL (e.g., `"https://registry.npmjs.org"`). * - `directory` — the directory to publish (empty string means the package root). * - `access` — `"public"` or `"restricted"` (scoped package visibility). * - `provenance` — whether to publish with provenance attestation (defaults to `false`). * * @example Creating a PublishTarget * ```typescript * import { PublishTarget } from "workspaces-effect"; * * const target = new PublishTarget({ * name: "@my-org/utils", * registry: "https://registry.npmjs.org", * directory: "dist/npm", * access: "public", * }); * ``` * * @public */ declare class PublishTarget extends PublishTarget_base {} //#endregion //#region src/services/PublishabilityDetector.d.ts declare const PublishabilityDetector_base: Context.TagClass Effect.Effect>; }>; /** * Service for detecting whether a workspace package is publishable and * identifying its publish targets (npm, GitHub Packages, etc.). * * Inspects `package.json` fields such as `private`, `publishConfig`, and * `repository` to determine publishability and target registries. * * @remarks * PublishabilityDetector is part of the Configuration and Lockfiles service * group. It is a pure service with no dependencies on other services — it * operates solely on the {@link WorkspacePackage} data and the workspace root * path passed to it. * * A package is considered publishable when `private` is not `true` and it has a * `name` and `version`. The returned {@link PublishTarget} array describes where * the package would be published (e.g., npmjs.org, GitHub Packages) based on * `publishConfig.registry` and other signals. * * The live layer (`PublishabilityDetectorLive`) is a pure layer with no * dependencies — it can be provided standalone or via `WorkspacesLive` / * `WorkspacesFullLive`. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/PublishabilityDetector`. Since this service * has no dependencies, the layer is constructed with `Layer.succeed` rather than * `Layer.effect`. * * @example Checking publishability of all packages * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { PublishabilityDetector, WorkspaceDiscovery, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const discovery = yield* WorkspaceDiscovery; * const publishability = yield* PublishabilityDetector; * const packages = yield* discovery.listPackages(); * * for (const pkg of packages) { * const targets = yield* publishability.detect(pkg, "/path/to/monorepo"); * if (targets.length > 0) { * console.log(`${pkg.name} publishes to:`, targets.map((t) => t.registry)); * } else { * console.log(`${pkg.name} is not publishable`); * } * } * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class PublishabilityDetector extends PublishabilityDetector_base {} //#endregion //#region src/layers/PublishabilityDetectorLive.d.ts /** * Live layer for the {@link PublishabilityDetector} service. * * Determines whether a workspace package is publishable to npm based * on its `private` flag and `publishConfig` settings. * * @remarks * This layer is pure -- it has no dependencies on `FileSystem`, `Path`, or * any other platform services. It uses `Layer.succeed` rather than * `Layer.effect`. Custom layers can override by providing their own * `Layer` for `PublishabilityDetector`. * * @privateRemarks * Builds a single {@link PublishTarget} from `publishConfig` fields, * defaulting to the public npm registry when no registry is specified. * * @example * ```typescript * import { Effect } from "effect"; * import { PublishabilityDetector, PublishabilityDetectorLive } from "workspaces-effect"; * import { WorkspacePackage } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const detector = yield* PublishabilityDetector; * const targets = yield* detector.detect(somePackage, "/path/to/root"); * return targets; * }); * * Effect.runPromise( * program.pipe(Effect.provide(PublishabilityDetectorLive)) * ); * ``` * * @public */ declare const PublishabilityDetectorLive: Layer.Layer; //#endregion //#region src/services/TopologicalSorter.d.ts declare const TopologicalSorter_base: Context.TagClass Effect.Effect, CyclicDependencyError>; /** * Sort a subset of packages including their transitive dependencies. * * Given a list of target packages, computes the transitive closure of their * dependencies and returns all of them in topological order. * * @param names - The package names to include (their transitive deps are added * automatically). * @returns An Effect that succeeds with a readonly array of package names in * dependency order, or fails with {@link CyclicDependencyError} if the * subgraph contains a cycle, or {@link PackageNotFoundError} if a named * package does not exist in the workspace. */ readonly sortSubset: (names: ReadonlyArray) => Effect.Effect, CyclicDependencyError | PackageNotFoundError>; /** * Get packages grouped by parallel execution level. * * Level 0 contains packages with no workspace dependencies. Level 1 contains * packages whose dependencies are all in level 0, and so on. Packages within * the same level can be built concurrently. * * @returns An Effect that succeeds with a readonly array of levels, where each * level is a readonly array of package names, or fails with * {@link CyclicDependencyError} if the graph contains a cycle. */ readonly levels: () => Effect.Effect>, CyclicDependencyError>; }>; /** * Service for topological sorting of workspace packages. * * Uses Kahn's algorithm (BFS-based) for deterministic ordering and natural * parallel level detection. Packages with no dependencies appear first in * the sorted output. * * @remarks * TopologicalSorter is the second service in the Package Analysis group. It * consumes the dependency graph built by DependencyGraph and produces ordered * sequences suitable for build pipelines. The `levels` method groups * packages by execution level, enabling maximum parallelism — packages within * the same level can be built concurrently. * * The live layer (`TopologicalSorterLive`) depends on `DependencyGraph` (and * transitively on `WorkspaceDiscovery` and `WorkspaceRoot`). Use `WorkspacesLive` * or `WorkspacesFullLive` to get all wiring handled automatically. * * @privateRemarks * Uses the class-based `Context.Tag` pattern. The internal tag identifier is * `@spencerbeggs/workspaces-effect/TopologicalSorter`. Kahn's algorithm is * preferred over DFS-based topological sort because it naturally detects cycles * (incomplete processing means a cycle exists) and produces level groupings * without a separate pass. * * @example Building packages in topological order * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { TopologicalSorter, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const sorter = yield* TopologicalSorter; * const order = yield* sorter.sort(); * console.log("Build order:", order); * * const levels = yield* sorter.levels(); * for (const [i, level] of levels.entries()) { * console.log(`Level ${i} (can run in parallel):`, level); * } * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare class TopologicalSorter extends TopologicalSorter_base {} //#endregion //#region src/layers/TopologicalSorterLive.d.ts /** * Live layer for the {@link TopologicalSorter} service. * * Provides deterministic topological ordering of workspace packages * using Kahn's algorithm with parallel level detection. * * @remarks * Requires {@link DependencyGraph}. The adjacency map is resolved eagerly * at construction time. Results are sorted lexicographically within each * level for deterministic output. * * @privateRemarks * Retrieves the adjacency map from `DependencyGraph.adjacencyMap()` once * at construction, then uses it for all `sort`, `sortSubset`, and `levels` * calls. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { TopologicalSorter, WorkspacesLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const sorter = yield* TopologicalSorter; * const buildOrder = yield* sorter.sort(); * return buildOrder; * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const TopologicalSorterLive: Layer.Layer; //#endregion //#region src/layers/WorkspaceDiscoveryLive.d.ts /** * Live layer for the {@link WorkspaceDiscovery} service. * * Discovers all workspace packages by reading PM-specific configuration, * resolving glob patterns to directories, and parsing each `package.json`. * * @remarks * Requires {@link WorkspaceRoot}, `FileSystem`, and `Path`. Layer construction * is O(1); the default workspace root (resolved from `process.cwd()`) is looked * up lazily on the first method call and cached for the lifetime of the layer. * Discovery method calls accept an optional `cwd` parameter to resolve a * different root for that single call; results are cached per resolved root * path for the lifetime of the layer. * * @privateRemarks * The default-root lookup is wrapped in `Effect.cached` so layer construction * is free and consumers that build the layer but never call a method pay * nothing. Per-call `cwd` arguments are resolved on demand via * `WorkspaceRoot.find` and memoized in a `Map` keyed by the absolute * resolved root path. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { WorkspaceDiscovery, WorkspaceDiscoveryLive, WorkspaceRootLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const discovery = yield* WorkspaceDiscovery; * return yield* discovery.listPackages(); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspaceDiscoveryLive), * Effect.provide(WorkspaceRootLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const WorkspaceDiscoveryLive: Layer.Layer; //#endregion //#region src/layers/WorkspaceRootLive.d.ts /** * Live layer for the {@link WorkspaceRoot} service. * * Provides workspace root discovery by walking up the directory tree * looking for workspace markers. * * @remarks * Requires `FileSystem` and `Path` from `@effect/platform`. Provide these * via `NodeContext.layer` (Node.js) or `BunContext.layer` (Bun). * * @privateRemarks * Resolves `FileSystem` and `Path` at construction time, then delegates * to {@link findWorkspaceRoot} for each `find()` call. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { WorkspaceRoot, WorkspaceRootLive } from "workspaces-effect"; * * const program = Effect.gen(function* () { * const root = yield* WorkspaceRoot; * return yield* root.find(process.cwd()); * }); * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspaceRootLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const WorkspaceRootLive: Layer.Layer; //#endregion //#region src/layers/WorkspacesLive.d.ts /** * Composite layer providing all services except git-dependent ones. * * Provides: `WorkspaceRoot`, `PackageManagerDetector`, `WorkspaceDiscovery`, * `DependencyGraph`, `TopologicalSorter`, `LockfileReader`, `PublishabilityDetector`, * `CatalogResolver`. * * @remarks * Requires `FileSystem` and `Path` from `@effect/platform`. Provide these * via `NodeContext.layer` (Node.js) or `BunContext.layer` (Bun). * * @privateRemarks * Wires individual `*Live` layers together using `Layer.mergeAll` with * `Layer.provide` to thread dependencies. `PublishabilityDetectorLive` is * a pure layer with no dependencies. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { WorkspacesLive } from "workspaces-effect"; * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const WorkspacesLive: Layer.Layer; /** * Composite layer providing all services including git-dependent ones. * * Extends {@link WorkspacesLive} with `PackageResolver`, `ChangeDetector`, * and `PointInTimeWorkspace`. * * @remarks * Requires `FileSystem`, `Path`, and `CommandExecutor` from `@effect/platform`. * Provide these via `NodeContext.layer` (Node.js) or `BunContext.layer` (Bun). * * @privateRemarks * Composes `WorkspacesLive` with `PackageResolverLive` and `ChangeDetectorLive`, * wiring the graph and resolver dependencies via `Layer.provide`. * * @example * ```typescript * import { Effect } from "effect"; * import { NodeContext } from "@effect/platform-node"; * import { WorkspacesFullLive } from "workspaces-effect"; * * Effect.runPromise( * program.pipe( * Effect.provide(WorkspacesFullLive), * Effect.provide(NodeContext.layer), * ) * ); * ``` * * @public */ declare const WorkspacesFullLive: Layer.Layer; //#endregion //#region src/sync.d.ts /** * Find the workspace root by walking up from `cwd`. * * Resolution order at each level: * * 1. `pnpm-workspace.yaml` — return this directory. * 2. `package.json` with a `workspaces` field — return this directory. * 3. `.git` (project boundary) — stop ascent. If a `package.json` exists * alongside `.git`, return that directory; otherwise throw, because a * git project missing a root `package.json` is an error. * * If the walk reaches the filesystem root without seeing any workspace * marker or `.git`, returns `null` — `cwd` is not inside a project. * * @param cwd - Starting directory (defaults to `process.cwd()`) * @returns Absolute path to workspace root, or `null` when not inside any project * @throws If the provided path does not exist, or if a `.git` boundary is * reached without a sibling `package.json` * * @public */ declare const findWorkspaceRootSync: (cwd?: string) => string | null; /** * List workspace packages synchronously. * * Reads workspace patterns from `pnpm-workspace.yaml` or `package.json`, * resolves them to directories, and parses each `package.json` into a * {@link WorkspacePackage}. The root package is always the first entry, * matching the behavior of the Effect-based `WorkspaceDiscovery.listPackages()`. * * @param root - Absolute path to the workspace root * @returns Array of workspace packages with root as first entry * @throws If the root directory does not exist, or if the root * `package.json` is missing required `name` or `version` fields * * @public */ declare const getWorkspacePackagesSync: (root: string) => ReadonlyArray; //#endregion //#region src/utils/workspace-package.d.ts /** * Check if a package has a production dependency. Dual API. * * @public */ declare const hasDependency: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; /** * Check if a package has a dev dependency. Dual API. * * @public */ declare const hasDevDependency: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; /** * Check if a package has a peer dependency. Dual API. * * @public */ declare const hasPeerDependency: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; /** * Check if a package has an optional dependency. Dual API. * * @public */ declare const hasOptionalDependency: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; /** * Check if a package depends on a name in any dep type. Dual API. * * @public */ declare const hasAnyDependencyOn: { (name: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, name: string): boolean; }; /** * Look up version across all dep types. Dual API. * * @public */ declare const dependencyVersion: { (name: string): (self: WorkspacePackage) => Option.Option; (self: WorkspacePackage, name: string): Option.Option; }; /** * Check if any dep name matches a glob pattern. Dual API. * * @public */ declare const matchesDependency: { (pattern: string): (self: WorkspacePackage) => boolean; (self: WorkspacePackage, pattern: string): boolean; }; /** * Compare two WorkspacePackage dependency snapshots. Dual API. * * @public */ declare const dependencyDiff: { (other: WorkspacePackage): (self: WorkspacePackage) => DependencyDiff; (self: WorkspacePackage, other: WorkspacePackage): DependencyDiff; }; /** * Read and parse a package's package.json from disk. * * Returns the minimal `PackageJsonType` schema fields. For full raw * package.json access, read `pkg.packageJsonPath` directly. * * Not a dual function — takes a single WorkspacePackage argument. * Pipeable via `pipe(pkg, readPackageJson)`. * * @public */ declare const readPackageJson: (self: WorkspacePackage) => Effect.Effect, PackageJsonParseError, FileSystem.FileSystem>; //#endregion export { BunExtension, type Catalog, CatalogAssemblyError, CatalogAssemblyErrorBase, CatalogResolutionError, CatalogResolutionErrorBase, CatalogResolver, type CatalogResolverError, CatalogResolverLive, type CatalogResolverLiveLayer, CatalogSet, type Catalogs, ChangeDetectionError, ChangeDetectionErrorBase, ChangeDetectionOptions, ChangeDetector, ChangeDetectorLive, CyclicDependencyError, CyclicDependencyErrorBase, type DependencyDiff, DependencyGraph, DependencyGraphLive, DependencyResolutionError, DependencyResolutionErrorBase, type DetectedPackageManager, GitNotAvailableError, GitNotAvailableErrorBase, GitReadError, GitReadErrorBase, ImporterDependency, LockfileData, LockfileImporter, type LockfileInitError, LockfileIntegrity, LockfileIntegrityError, LockfileIntegrityErrorBase, LockfileParseError, LockfileParseErrorBase, LockfileReadError, LockfileReadErrorBase, LockfileReader, LockfileReaderLive, type LockfileReaderLiveLayer, type ManifestLike, PackageJsonParseError, PackageJsonParseErrorBase, PackageJsonSchema, type PackageJsonType, type PackageJsonWorkspaces, PackageManager, PackageManagerDetectionError, PackageManagerDetectionErrorBase, PackageManagerDetector, PackageManagerDetectorLive, type PackageManagerType, PackageName, type PackageNameType, PackageNotFoundError, PackageNotFoundErrorBase, PackageResolver, PackageResolverLive, PackageStateSnapshot, PnpmExtension, type PointInTimeAtError, type PointInTimeOptions, type PointInTimeReadError, PointInTimeWorkspace, PointInTimeWorkspaceLive, type PointInTimeWorkspaceLiveLayer, type PointInTimeWorktreeError, PublishConfig, type PublishConfigType, PublishTarget, PublishabilityDetector, PublishabilityDetectorLive, ResolvedPackage, TopologicalSorter, TopologicalSorterLive, WorkspaceDependency, WorkspaceDiscovery, WorkspaceDiscoveryError, WorkspaceDiscoveryErrorBase, WorkspaceDiscoveryLive, WorkspaceInfo, type WorkspaceManifestCatalogs, type WorkspaceManifestData, WorkspacePackage, WorkspacePath, type WorkspacePathType, WorkspaceRoot, WorkspaceRootLive, WorkspaceRootNotFoundError, WorkspaceRootNotFoundErrorBase, WorkspaceStateSnapshot, WorkspacesFullLive, WorkspacesLive, catalogSetFromPackageJson, dependencyDiff, dependencyVersion, findWorkspaceRootSync, getWorkspacePackagesSync, hasAnyDependencyOn, hasDependency, hasDevDependency, hasOptionalDependency, hasPeerDependency, matchesDependency, parseLockfileContent, parsePackageJsonWorkspaces, readPackageJson, workspaceManifestFromYaml }; //# sourceMappingURL=index.d.ts.map