api #

a tool for managing many repos

50 modules ยท 239 declarations

Modules
#

analyze_repos
#

graph_validation.ts view source

(repos: LocalRepo[]): RepoAnalysis import {analyze_repos} from '@fuzdev/fuz_repos/graph_validation.js';

Builds the dependency graph and runs cycle/wildcard analysis, tolerating cycles (reports rather than throws). The shared core of gitops_analyze and gitops_validate, which format the result themselves.

repos

type LocalRepo[]

returns

RepoAnalysis

AwaitingRegistry
#

publishing_plan.ts view source

AwaitingRegistry import type {AwaitingRegistry} from '@fuzdev/fuz_repos/publishing_plan.js';

A package whose current version the registry doesn't show, with no changesets to publish.

name

type string

version

type string

BumpType
#

version_utils.ts view source

BumpType

type "major" | "minor" | "patch"

import type {BumpType} from '@fuzdev/fuz_repos/version_utils.js';

A semver bump kind: major, minor, or patch.

calculate_dependency_updates
#

publishing_plan_helpers.ts view source

(repos: readonly LocalRepo[], targets: ReadonlyMap<string, string>, changes: ReadonlyMap<string, VersionChange>): { dependency_updates: DependencyUpdate[]; breaking_cascades: Map<...>; } import {calculate_dependency_updates} from '@fuzdev/fuz_repos/publishing_plan_helpers.js';

Calculates every dependency update between packages (to_dependency_updates for each repo, in repos order) and the breaking cascades: each package whose release is breaking for some dependent's prod/peer range, with those dependents.

repos

type readonly LocalRepo[]

targets

type ReadonlyMap<string, string>

changes

type ReadonlyMap<string, VersionChange>

returns

{ dependency_updates: DependencyUpdate[]; breaking_cascades: Map<string, string[]>; }

calculate_next_version
#

version_utils.ts view source

(current_version: string, bump_type: BumpType): string import {calculate_next_version} from '@fuzdev/fuz_repos/version_utils.js';

current_version

type string

bump_type

returns

string

cargo_toml_load
#

cargo_toml.ts view source

(repo_dir: string): Promise<CargoMetadata | null> import {cargo_toml_load} from '@fuzdev/fuz_repos/cargo_toml.js';

Best-effort read of a repo's root Cargo.toml for the identity fields the dashboard renders. Returns null when there's no Cargo.toml.

repo_dir

absolute path to the repo

type string

returns

Promise<CargoMetadata | null>

cargo_toml_parse
#

cargo_toml.ts view source

(contents: string): CargoMetadata import {cargo_toml_parse} from '@fuzdev/fuz_repos/cargo_toml.js';

Extracts name/version/description/repository from the [package] and [workspace.package] tables of a Cargo.toml.

Deliberately not a full TOML parser: it scans for simple key = "value" string entries in those two tables, which covers both a single-crate manifest and a workspace root. Inline-table values like version = { workspace = true } (and the equivalent version.workspace = true) are ignored โ€” a member crate inheriting from the workspace has no literal here, and fuz_repos only ever reads a repo's root manifest, where these are concrete. The first non-empty value for a key wins, so a top-level [package] takes precedence over [workspace.package] when both appear.

contents

type string

returns

CargoMetadata

CargoMetadata
#

cargo_toml.ts view source

CargoMetadata import type {CargoMetadata} from '@fuzdev/fuz_repos/cargo_toml.js';

The handful of identity fields fuz_repos reads from a Rust repo's Cargo.toml to render it on the dashboard. Everything is optional โ€” a workspace root has no name, and any field may be absent or inherited.

name?

type string

version?

type string

description?

type string

repository?

type string

ChangesetInfo
#

changeset_reader.ts view source

ChangesetInfo import type {ChangesetInfo} from '@fuzdev/fuz_repos/changeset_reader.js';

filename

type string

packages

type { name: string; bump_type: BumpType; }[]

summary

type string

ChangesetOperations
#

operations.ts view source

ChangesetOperations import type {ChangesetOperations} from '@fuzdev/fuz_repos/operations.js';

Changeset operations for reading and predicting versions from .changeset/*.md files.

has_changesets

Checks if a repo has any changeset files. Returns true if changesets exist, false if none found.

type (options: { repo: LocalRepo; }): Promise<Result<{ value: boolean; }, { message: string; }>>

options

type { repo: LocalRepo; }
returns Promise<Result>

read_changesets

Reads all changeset files from a repo. Returns array of changeset info, or error if reading fails.

type (options: { repo: LocalRepo; log?: Logger | undefined; }): Promise<Result<{ value: ChangesetInfo[]; }, { message: string; }>>

options

type { repo: LocalRepo; log?: Logger | undefined; }
returns Promise<Result>

predict_next_version

Predicts the next version based on changesets. Returns null if no changesets found (expected, not an error). Returns error Result if changesets exist but can't be read/parsed.

type (options: { repo: LocalRepo; log?: Logger | undefined; }): Promise<Result<{ version: string; bump_type: BumpType; }, { message: string; }> | null>

options

type { repo: LocalRepo; log?: Logger | undefined; }
returns Promise<Result | null>

check_gen_readiness
#

repo_readiness.ts view source

(options: { report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | { ...; })[] | null; }; keys: readonly string[]; allow_dirty?: boolean | undefined; now?: number | undefined; } & RepoReadinessFormatOptions): Result<...> import {check_gen_readiness} from '@fuzdev/fuz_repos/repo_readiness.js';

Checks a repos status --json report on the repos gitops_sync generates the site data from (repo_readiness_for_gen).

options

type { report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 m... & RepoReadinessFormatOptions

returns

Result

warnings, a line per problem that doesn't refuse; and on failure also a message naming each refused repo, what's wrong, and the fix, and its lines

check_package_available
#

npm_registry.ts view source

(pkg: string, version: string, options: { log?: Logger | undefined; }, deps: NpmRegistryDeps): Promise<boolean> import {check_package_available} from '@fuzdev/fuz_repos/npm_registry.js';

Checks whether pkg@version is on the npm registry, by npm view.

pkg

type string

version

type string

options

type { log?: Logger | undefined; }

deps

returns

Promise<boolean>

true when the registry reports that exact version, false when it doesn't or npm couldn't run

check_release_readiness
#

repo_readiness.ts view source

(options: { report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | { ...; })[] | null; }; keys: readonly string[]; } & RepoReadinessFormatOptions): ReleaseReadiness import {check_release_readiness} from '@fuzdev/fuz_repos/repo_readiness.js';

Reads a repos status --fetch --json report for a release step: each key's entry ready (repo_readiness_for_publish), the report fetched, and busy detection available, since a live session it can't vouch for may be working in any checkout. A step commits rewrites in a dependent and names packages to publish, so a repo that isn't ready is held, and the reasons say how to fix it.

options

type { report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 m... & RepoReadinessFormatOptions

returns

ReleaseReadiness

the report-wide problems, and each not-ready repo's

CiDrift
#

ci_reconcile.ts view source

CiDrift import type {CiDrift} from '@fuzdev/fuz_repos/ci_reconcile.js';

repo_url

type string

ci

The declared/derived ci value.

type boolean

has_workflows

type boolean

kind

type CiDriftKind

CiDriftKind
#

ci_reconcile.ts view source

CiDriftKind

type "missing_ci" | "stray_ci"

import type {CiDriftKind} from '@fuzdev/fuz_repos/ci_reconcile.js';

How a repo's declared ci diverges from its workflow files on disk.

CiReconcileInput
#

ci_reconcile.ts view source

CiReconcileInput import type {CiReconcileInput} from '@fuzdev/fuz_repos/ci_reconcile.js';

repo_url

type string

ci

The declared/derived ci value from the registry.

type boolean

has_workflows

Whether the repo has at least one workflow file on disk.

type boolean

archived

Whether the repo is archived (frozen) on its host; archived repos are skipped.

type boolean

compare_bump_types
#

version_utils.ts view source

(a: BumpType, b: BumpType): number import {compare_bump_types} from '@fuzdev/fuz_repos/version_utils.js';

Compares bump types. Returns positive if a > b, negative if a < b, 0 if equal.

a

b

returns

number

compare_versions
#

version_utils.ts view source

(a: string, b: string): number | null import {compare_versions} from '@fuzdev/fuz_repos/version_utils.js';

Compares two x.y.z versions.

a

type string

b

type string

returns

number | null

negative when a is older, positive when newer, 0 when equal, or null when either isn't x.y.z

create_fs_fetch_value_cache
#

fs_fetch_value_cache.ts view source

(name: string, dir?: string): Promise<FetchCache> import {create_fs_fetch_value_cache} from '@fuzdev/fuz_repos/fs_fetch_value_cache.js';

Creates file-system backed cache for fuz_util's fetch.js API responses.

Cache invalidation strategy: If cache file can't be read or parsed, entire cache is cleared (delete file) and starts fresh. This handles format changes.

Uses structuredClone to track changes - only writes to disk if data modified. Formatted with gro's format_file before writing for version control friendliness.

name

cache filename (without .json extension)

type string

dir?

cache directory (defaults to .gro/build/fetch/)

type string
optional default join(paths.build, 'fetch')

returns

Promise<FetchCache>

cache object with Map-based data and save() method

create_npm_operations
#

operations_defaults.ts view source

(to_npm: () => SpawnProgram): NpmOperations import {create_npm_operations} from '@fuzdev/fuz_repos/operations_defaults.js';

The npm operations over a npm program, resolved each time one runs.

to_npm

makes the npm handle, called per operation so a missing npm reports as a failed operation rather than at import

type () => SpawnProgram

returns

NpmOperations

CreateGitopsConfig
#

gitops_config.ts view source

CreateGitopsConfig import type {CreateGitopsConfig} from '@fuzdev/fuz_repos/gitops_config.js';

A config module's default export in function form.

(call)

type (): { repos: string[]; } | Promise<{ repos: string[]; }>

returns GitopsConfig | Promise<GitopsConfig>

default_changeset_operations
#

default_fs_operations
#

default_git_operations
#

default_npm_operations
#

default_repos_operations
#

DEPENDENCY_SECTIONS
#

publishing_plan_helpers.ts view source

readonly ("dependencies" | "devDependencies" | "peerDependencies")[]

type readonly DependencySection[]

import {DEPENDENCY_SECTIONS} from '@fuzdev/fuz_repos/publishing_plan_helpers.js';

Every dependency section, in the order updates are listed.

DEPENDENCY_TYPE
#

dependency_graph.ts view source

{ readonly PROD: "prod"; readonly PEER: "peer"; readonly DEV: "dev"; } import {DEPENDENCY_TYPE} from '@fuzdev/fuz_repos/dependency_graph.js';

DEPENDENCY_UPDATES_CHANGESET_FILENAME
#

changeset_generator.ts view source

"dependency-updates.md" import {DEPENDENCY_UPDATES_CHANGESET_FILENAME} from '@fuzdev/fuz_repos/changeset_generator.js';

The auto-generated changeset's filename. A dependent keeps one, rewritten as each of its dependencies publishes, so its release notes list every dependency that moved under one entry rather than one entry per publish.

DependencyAnalysis
#

dependency_graph.ts view source

DependencyAnalysis import type {DependencyAnalysis} from '@fuzdev/fuz_repos/dependency_graph.js';

Cycles and wildcard dependencies found by DependencyGraph.analyze.

production_cycles

type string[][]

dev_cycles

type string[][]

wildcard_deps

type { pkg: string; dep: string; version: string; }[]

DependencyGraph
#

dependency_graph.ts view source

import {DependencyGraph} from '@fuzdev/fuz_repos/dependency_graph.js';

nodes

type Map<string, DependencyNode>

edges

type Map<string, Set<string>>

constructor

Builds the graph from local repos.

Two passes: first creates nodes, then builds edges (dependents). Prioritizes prod/peer deps over dev deps when the same package appears in multiple dependency types (the stronger constraint wins).

type new (repos: LocalRepo[]): DependencyGraph

repos

type LocalRepo[]

get_node

type (name: string): DependencyNode | undefined

name

type string
returns DependencyNode | undefined

topological_sort

Computes topological sort order for dependency graph.

Delegates to @fuzdev/fuz_util/sort.ts for the sorting algorithm. Throws if cycles detected.

type (exclude_dev?: boolean): string[]

exclude_dev?

if true, excludes dev dependencies to break cycles Publishing uses exclude_dev=true to handle circular dev deps.

type boolean
optional default false
returns string[]

array of package names in dependency order (dependencies before dependents)

throws

  • Error - if circular dependencies detected in included dependency types

get_prod_peer_dependencies

The names of a node's internal prod/peer dependencies โ€” the edges that order publishing (dev edges never do).

type (name: string): string[]

name

type string
returns string[]

detect_cycles_by_type

Detects circular dependencies, categorized by severity.

Production/peer cycles prevent publishing (impossible to order packages). Dev cycles are normal (test utils, shared configs) and safely ignored.

Uses DFS traversal with recursion stack to identify back edges. Deduplicates cycles using sorted cycle keys.

type (): { production_cycles: string[][]; dev_cycles: string[][]; }

returns { production_cycles: string[][]; dev_cycles: string[][]; }

object with production_cycles (errors) and dev_cycles (info)

analyze

Reports cycles by type and wildcard (*) dependency ranges. Tolerates cycles: it reports them rather than throwing.

type (): DependencyAnalysis

toJSON

type (): DependencyGraphJson

DependencyGraphJson
#

dependency_graph.ts view source

DependencyGraphJson import type {DependencyGraphJson} from '@fuzdev/fuz_repos/dependency_graph.js';

nodes

type { name: string; version: string; dependencies: { name: string; spec: DependencySpec; }[]; dependents: string[]; }[]

edges

type { from: string; to: string; }[]

DependencyNode
#

dependency_graph.ts view source

DependencyNode import type {DependencyNode} from '@fuzdev/fuz_repos/dependency_graph.js';

name

type string

version

type string

dependencies

type Map<string, DependencySpec>

dependents

type Set<string>

DependencySection
#

publishing_plan_helpers.ts view source

"dependencies" | "devDependencies" | "peerDependencies"

type "dependencies" | "devDependencies" | "peerDependencies"

import type {DependencySection} from '@fuzdev/fuz_repos/publishing_plan_helpers.js';

A package.json dependency section.

DependencySpec
#

DependencyType
#

dependency_graph.ts view source

DependencyType

type "prod" | "peer" | "dev"

import type {DependencyType} from '@fuzdev/fuz_repos/dependency_graph.js';

DependencyUpdate
#

publishing_plan.ts view source

DependencyUpdate import type {DependencyUpdate} from '@fuzdev/fuz_repos/publishing_plan.js';

A dependency range that moves to name its dependency's version after the release.

dependent_package

type string

updated_dependency

type string

current_version

The range as the dependent's package.json has it.

type string

new_version

The dependency's version after the release.

type string

type

type "dependencies" | "devDependencies" | "peerDependencies"

breaking

Whether the move from the range's base version is breaking.

type boolean

DependencyVersionChange
#

changeset_generator.ts view source

DependencyVersionChange import type {DependencyVersionChange} from '@fuzdev/fuz_repos/changeset_generator.js';

package_name

type string

from_version

type string

to_version

type string

bump_type

type "major" | "minor" | "patch"

breaking

type boolean

detect_bump_type
#

version_utils.ts view source

(old_version: string, new_version: string): BumpType import {detect_bump_type} from '@fuzdev/fuz_repos/version_utils.js';

old_version

type string

new_version

type string

returns

BumpType

determine_bump_from_changesets
#

changeset_reader.ts view source

(changesets: ChangesetInfo[], package_name: string): BumpType | null import {determine_bump_from_changesets} from '@fuzdev/fuz_repos/changeset_reader.js';

Determines the bump type for a package from its changesets.

When multiple changesets exist for the same package, returns the highest bump type (major > minor > patch) to ensure the most significant change is reflected in the version bump.

changesets

package_name

type string

returns

BumpType | null

the highest bump type, or null if package has no changesets

fetch_github_check_runs
#

github.ts view source

(repo_info: GithubRepoInfo, options: { cache?: FetchValueCache | undefined; log?: Logger | undefined; token?: string | undefined; api_version?: string | undefined; ref?: string | undefined; fetch: { ...; }; }): Promise<...> import {fetch_github_check_runs} from '@fuzdev/fuz_repos/github.js';

Fetches the check runs on ref and reduces them to one overall status and conclusion.

repo_info

the repo's GitHub owner and name

options

the cache, logger, token, API version, ref (main by default), and fetch

type { cache?: FetchValueCache | undefined; log?: Logger | undefined; token?: string | undefined; api_version?: string | undefined; ref?: string | undefined; fetch: { ...; }; }

returns

Promise<Result>

the reduced check runs, null for a ref with none (a repo without CI, or a commit CI skipped), or a failure when the request or its parse failed

throws

  • Error - on a 401 response (check `SECRET_GITHUB_API_TOKEN`) or a repo without an owner

see also

fetch_github_pull_requests
#

github.ts view source

(repo_info: GithubRepoInfo, options: { cache?: FetchValueCache | undefined; log?: Logger | undefined; token?: string | undefined; api_version?: string | undefined; fetch: { ...; }; }): Promise<...> import {fetch_github_pull_requests} from '@fuzdev/fuz_repos/github.js';

repo_info

options

type { cache?: FetchValueCache | undefined; log?: Logger | undefined; token?: string | undefined; api_version?: string | undefined; fetch: { (input: RequestInfo | URL, init?: RequestInit | undefined): Promise<...>; (input: string | ... 1 more ... | URL, init?: RequestInit | undefined): Promise<...>; }; }

returns

Promise<GithubPullRequest[] | null>

see also

fetch_repo_data
#

fetch_repo_data.ts view source

(options: FetchRepoDataOptions): Promise<RepoJson[]> import {fetch_repo_data} from '@fuzdev/fuz_repos/fetch_repo_data.js';

Fetches GitHub metadata (CI status, PRs) for all repos.

Fetches sequentially with a delay before each request to respect GitHub API rate limits. Uses await_in_loop intentionally to avoid parallel requests overwhelming the API. CI status is read for the branch each repo's registry entry follows (main when it names none), and that branch is written to RepoJson.branch.

A repo whose registry entry declares no CI (ci: false) isn't asked for check runs, and one with none on its branch isn't a failure: both leave check_runs null without logging. A failed fetch is logged as an error and leaves null for that repo's check_runs or pull_requests, and the remaining repos still fetch โ€” except a 401 response or a repo URL without a GitHub owner, which throw.

options

the repos, credentials, cache, and pacing

returns

Promise<RepoJson[]>

a RepoJson for each repo, in the order given

throws

  • Error - on a 401 response (check `SECRET_GITHUB_API_TOKEN`) or a repo whose URL has no GitHub owner

FetchCache
#

fs_fetch_value_cache.ts view source

FetchCache import type {FetchCache} from '@fuzdev/fuz_repos/fs_fetch_value_cache.js';

name

type string

data

type FetchValueCache

save

type (): Promise<boolean>

returns Promise<boolean>

true if anything changed, false if no-op

FetchRepoDataOptions
#

fetch_repo_data.ts view source

FetchRepoDataOptions import type {FetchRepoDataOptions} from '@fuzdev/fuz_repos/fetch_repo_data.js';

Options for fetch_repo_data.

local_repos

The repos to fetch GitHub metadata for, in order.

type LocalRepo[]

token?

GitHub API token, sent with each request.

type string

cache?

Response memoization, from fuz_util's fetch.ts.

type FetchValueCache

log?

type Logger

delay?

Milliseconds to wait before each API request. Defaults to 33.

type number

github_api_version?

Sent as the x-github-api-version header when set.

type string

fetch

The fetch the API requests go through, handed in by the caller.

type { (input: RequestInfo | URL, init?: RequestInit | undefined): Promise<Response>; (input: string | Request | URL, init?: RequestInit | undefined): Promise<...>; }

FilterPullRequest
#

github_helpers.ts view source

FilterPullRequest import type {FilterPullRequest} from '@fuzdev/fuz_repos/github_helpers.js';

(call)

type (pull_request: { number: number; title: string; user: { login: string; }; draft: boolean; }, repo: Repo): boolean

pull_request

repo

type Repo
returns boolean

format_and_output
#

output_helpers.ts view source

<T>(data: T, formatters: OutputFormatters<T>, options: OutputOptions): Promise<void> import {format_and_output} from '@fuzdev/fuz_repos/output_helpers.js';

Formats data and outputs to file or stdout based on options.

Supports three formats:

  • stdout: Uses logger for colored/styled output (cannot use with --outfile)
  • json: Stringified JSON
  • markdown: Formatted markdown text

data

type T

formatters

options

returns

Promise<void>

generics

format_and_output<T>
T

throws

  • Error - if stdout format used with `outfile`, or if logger missing for stdout

format_dev_cycles
#

log_helpers.ts view source

(analysis: DependencyAnalysis): string[] import {format_dev_cycles} from '@fuzdev/fuz_repos/log_helpers.js';

Formats dev circular dependencies as styled strings. Returns array of lines for inclusion in output.

analysis

returns

string[]

format_production_cycles
#

log_helpers.ts view source

(analysis: DependencyAnalysis): string[] import {format_production_cycles} from '@fuzdev/fuz_repos/log_helpers.js';

Formats production/peer circular dependencies as styled strings. Returns array of lines for inclusion in output.

analysis

returns

string[]

format_readiness_block
#

repo_readiness.ts view source

(not_ready: readonly RepoReadiness[], now: number): string[] import {format_readiness_block} from '@fuzdev/fuz_repos/repo_readiness.js';

Formats the diagnostics' readiness block: a header and a line per problem, saying what each repo not at rest is doing instead โ€” or no lines when every repo is at rest. Not a failure: the diagnostics read repos as they sit.

not_ready

type readonly RepoReadiness[]

now

the current time in unix seconds, for how long ago each repo was fetched

type number

returns

string[]

the block's lines, unindented header first

format_repo_readiness_problem
#

repo_readiness.ts view source

(key: string, problem: RepoReadinessProblem, options?: RepoReadinessFormatOptions): { what: string; fix: string; } import {format_repo_readiness_problem} from '@fuzdev/fuz_repos/repo_readiness.js';

What a readiness problem says is wrong with the repo keyed key, and the fix, when there is one to name.

key

the repo's registry key

type string

problem

one of the repo's readiness problems

options?

the repos invocation fixes name

optional default {}

returns

{ what: string; fix: string; }

what's wrong, and the fix

format_waves
#

publishing_plan_logging.ts view source

(waves: readonly (readonly string[])[]): string[] import {format_waves} from '@fuzdev/fuz_repos/publishing_plan_logging.js';

Formats waves as one line each, numbered from 1: 1. a, b.

waves

the plan's waves, shallowest first

type readonly (readonly string[])[]

returns

string[]

format_wildcard_dependencies
#

log_helpers.ts view source

(analysis: DependencyAnalysis): string[] import {format_wildcard_dependencies} from '@fuzdev/fuz_repos/log_helpers.js';

Formats wildcard dependencies as styled strings. Returns array of lines for inclusion in output.

analysis

returns

string[]

FsError
#

operations.ts view source

FsError

type { kind: "not_found"; message: string; } | { kind: "permission_denied"; message: string; } | { kind: "already_exists"; message: string; } | { kind: "io_error"; message: string; }

import type {FsError} from '@fuzdev/fuz_repos/operations.js';

The typed error of a failed FsOperations call, discriminated on kind.

FsOperations
#

operations.ts view source

FsOperations import type {FsOperations} from '@fuzdev/fuz_repos/operations.js';

File system operations for reading and writing files.

Errors are typed via FsError (`not_found | permission_denied | already_exists | io_error) so callers can branch on kind` instead of regex-matching message.

readFile

Reads a file from the file system.

type (options: { path: string; encoding: BufferEncoding; }): Promise<Result<{ value: string; }, FsError>>

options

type { path: string; encoding: BufferEncoding; }
returns Promise<Result>

writeFile

Writes a file to the file system.

type (options: { path: string; content: string; }): Promise<Result<object, FsError>>

options

type { path: string; content: string; }
returns Promise<Result>

mkdir

Creates a directory, optionally with recursive creation.

type (options: { path: string; recursive?: boolean | undefined; }): Promise<Result<object, FsError>>

options

type { path: string; recursive?: boolean | undefined; }
returns Promise<Result>

exists

Checks if a path exists on the file system.

type (options: { path: string; }): Promise<boolean>

options

type { path: string; }
returns Promise<boolean>

generate_changeset_content
#

changeset_generator.ts view source

(package_name: string, updates: DependencyVersionChange[], bump_type: "major" | "minor" | "patch"): string import {generate_changeset_content} from '@fuzdev/fuz_repos/changeset_generator.js';

Generates markdown changeset content for dependency updates.

Creates properly formatted changeset with YAML frontmatter, summary, and categorized list of breaking vs regular updates. Output format matches changesets CLI for consistency.

package_name

package receiving the dependency updates

type string

updates

list of dependency changes with version info

bump_type

required bump type (calculated from breaking changes)

type "major" | "minor" | "patch"

returns

string

markdown content ready to write to .changeset/*.md file

generate_publishing_plan
#

publishing_plan.ts view source

(all_repos: LocalRepo[], options?: GeneratePlanOptions): Promise<PublishingPlan> import {generate_publishing_plan} from '@fuzdev/fuz_repos/publishing_plan.js';

Generates the publishing plan in one pass over the prod/peer topological order. Each package's dependencies are settled before it is reached, so its required bump โ€” from its prod/peer ranges against each dependency's version after the release โ€” is final when computed: explicit changesets, escalation, or an auto-changeset, with no iteration.

Every package's version after the release is its predicted one when it publishes and its current one otherwise, so a dependent whose range trails a dependency's current version gets that rewrite too, along with the bump it implies.

all_repos

type LocalRepo[]

options?

optional default {}

returns

Promise<PublishingPlan>

GeneratePlanOptions
#

publishing_plan.ts view source

GeneratePlanOptions import type {GeneratePlanOptions} from '@fuzdev/fuz_repos/publishing_plan.js';

log?

type Logger

ops?

type ChangesetOperations

verbose?

type boolean

registry?

What the registry shows for each package's current version, by name. With no changesets, an unlisted one is awaiting_registry, and so is an unknown one some package depends on for prod or peer; any other unknown one is never_published. Without it, every current version counts as released.

type ReadonlyMap<string, RegistryVersion>

get_gitops_ready
#

gitops_task_helpers.ts view source

(options: ResolveGitopsReposOptions): Promise<{ local_repos: LocalRepo[]; report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { ...; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | { ...; })[] | null; }; }> import {get_gitops_ready} from '@fuzdev/fuz_repos/gitops_task_helpers.js';

Central initialization function for the publishing and dependency tasks (gitops_analyze, gitops_plan, gitops_release, gitops_validate): resolves the config's repos through repos status (resolve_gitops_repos), then loads each repo as its working tree sits (local_repos_load) with no module analysis โ€” those tasks read each package's name, version, and dependencies, never its modules โ€” so it moves no ref and writes nothing.

options

returns

Promise<{ local_repos: LocalRepo[]; report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregis...>

the loaded repos, in config order, and the repos status report they came from

throws

  • TaskError - if resolving the repos or loading them fails

get_update_prefix
#

version_utils.ts view source

(current_version: string, default_strategy?: "" | "^" | "~" | ">="): string import {get_update_prefix} from '@fuzdev/fuz_repos/version_utils.js';

Determines version prefix to use when updating dependencies.

Strategy:

  • Wildcard (*): Use caret (^) as default
  • Has existing prefix: Preserve it (^, ~, >=, <=, etc)
  • No prefix: Use default_strategy

This preserves user intent while handling wildcard replacements sensibly.

current_version

type string

default_strategy?

prefix to use when no existing prefix found

type "^" | "~" | "" | ">="
optional default '^'

returns

string

get_version_prefix
#

version_utils.ts view source

(version: string): string import {get_version_prefix} from '@fuzdev/fuz_repos/version_utils.js';

Gets the version prefix (^, ~, >=, <=, or empty string).

version

type string

returns

string

git_add
#

git_operations.ts view source

(git: SpawnProgram, files: string | string[], options?: SpawnCallOptions | undefined): Promise<void> import {git_add} from '@fuzdev/fuz_repos/git_operations.js';

Adds files to git staging area and throws if anything goes wrong.

git

type SpawnProgram

files

type string | string[]

options?

type SpawnCallOptions
optional

returns

Promise<void>

git_commit
#

git_operations.ts view source

(git: SpawnProgram, message: string, files: string[], options?: SpawnCallOptions | undefined): Promise<void> import {git_commit} from '@fuzdev/fuz_repos/git_operations.js';

Commits files alone with a message, leaving anything else staged out of the commit, and throws if anything goes wrong. files must be non-empty: an empty list would commit the whole index.

git

type SpawnProgram

message

type string

files

type string[]

options?

type SpawnCallOptions
optional

returns

Promise<void>

GithubCheckRuns
#

github.ts view source

value + type

{ total_count: number; check_runs: { status: "queued" | "in_progress" | "completed"; conclusion: "success" | "failure" | "neutral" | "cancelled" | "skipped" | "timed_out" | "action_required" | null; }[]; } import {GithubCheckRuns} from '@fuzdev/fuz_repos/github.js';

total_count

type number

check_runs

type GithubCheckRunsItem[]

GithubCheckRunsItem
#

github.ts view source

value + type

{ status: "queued" | "in_progress" | "completed"; conclusion: "success" | "failure" | "neutral" | "cancelled" | "skipped" | "timed_out" | "action_required" | null; } import {GithubCheckRunsItem} from '@fuzdev/fuz_repos/github.js';

see also

status

type "queued" | "in_progress" | "completed"

conclusion

type "success" | "failure" | "neutral" | "cancelled" | "skipped" | "timed_out" | "action_required" | null

GithubPullRequest
#

GithubPullRequests
#

github.ts view source

value + type

{ number: number; title: string; user: { login: string; }; draft: boolean; }[]

type GithubPullRequest[]

import {GithubPullRequests} from '@fuzdev/fuz_repos/github.js';

GithubRepoInfo
#

github.ts view source

GithubRepoInfo import type {GithubRepoInfo} from '@fuzdev/fuz_repos/github.js';

Minimal interface for GitHub API calls, satisfied structurally by fuz_ui's Library.

owner_name

type string | null

repo_name

type string

GitOperations
#

operations.ts view source

GitOperations import type {GitOperations} from '@fuzdev/fuz_repos/operations.js';

Git operations the release step authors with: staging and committing dependency rewrites and auto-changesets. All operations return Result instead of throwing errors. Where each repo sits (branch, dirt, relation to origin) is ReposOperations's to report.

add

Stages files for commit.

type (options: { files: string | string[]; cwd?: string | undefined; }): Promise<Result<object, { message: string; }>>

options

type { files: string | string[]; cwd?: string | undefined; }
returns Promise<Result>

commit

Commits files alone (git commit -- <files>), leaving anything else staged out of the commit; files must be non-empty.

type (options: { message: string; files: string[]; cwd?: string | undefined; }): Promise<Result<object, { message: string; }>>

options

type { message: string; files: string[]; cwd?: string | undefined; }
returns Promise<Result>

GITOPS_CONCURRENCY_DEFAULT
#

gitops_constants.ts view source

5 import {GITOPS_CONCURRENCY_DEFAULT} from '@fuzdev/fuz_repos/gitops_constants.js';

Default number of repos to process concurrently during parallel operations.

gitops_config_leaked_private_repos
#

gitops_config.ts view source

(entries: readonly { kind: "repo" | "reference"; key: string; dir: string; pinned: boolean; url: string; branch: string | null; needs_human: ({ kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | ... 5 more ... | "am"; checkout: string; } | ... 12 more ... | { ...; })[]; ... 16 more ...; visibility_check: { ...; } | ... 2 more ... | null; }[], host_is_private: boolean): { ...; }[] import {gitops_config_leaked_private_repos} from '@fuzdev/fuz_repos/gitops_config.js';

The private repos a public host package must not publish. gitops_sync writes every configured repo's GitHub metadata into the host project's generated repos.json โ€” a public site's data when the host package is public โ€” so a private repo in that config would leak. Empty when the host is private.

entries

the configured repos' registry entries

type readonly ReposEntryStatus[]

host_is_private

whether the host package.json sets private: true

type boolean

returns

ReposEntryStatus[]

GITOPS_CONFIG_PATH_DEFAULT
#

gitops_constants.ts view source

"gitops.config.ts" import {GITOPS_CONFIG_PATH_DEFAULT} from '@fuzdev/fuz_repos/gitops_constants.js';

Default path to the gitops configuration file.

GITOPS_NPM_WAIT_TIMEOUT_DEFAULT
#

gitops_constants.ts view source

600000 import {GITOPS_NPM_WAIT_TIMEOUT_DEFAULT} from '@fuzdev/fuz_repos/gitops_constants.js';

Default timeout in milliseconds for gitops_release --wait to wait on registry propagation (10 minutes). npm's CDN is eventually consistent, so a published version can take minutes to show.

GitopsConfig
#

gitops_config.ts view source

value + type

{ repos: string[]; } import {GitopsConfig} from '@fuzdev/fuz_repos/gitops_config.js';

A project's gitops config.

repos

type string[]

GitopsConfigModule
#

GraphValidationResult
#

graph_validation.ts view source

GraphValidationResult import type {GraphValidationResult} from '@fuzdev/fuz_repos/graph_validation.js';

graph

type DependencyGraph

order

Every package, dependencies before dependents over prod/peer edges.

type string[]

levels

order grouped by longest prod/peer dependency path (group_into_levels): each level depends only on earlier ones. In the repos' order within a level.

type string[][]

production_cycles

type string[][]

dev_cycles

type string[][]

sort_error?

Why the topological sort failed, when it did; order and levels are then empty.

type string

group_into_levels
#

dependency_graph.ts view source

(order: readonly string[], get_dependencies: (name: string) => Iterable<string>, names?: ReadonlySet<string> | undefined, rank?: ReadonlyMap<string, number> | undefined): string[][] import {group_into_levels} from '@fuzdev/fuz_repos/dependency_graph.js';

Groups names into levels by their longest dependency path: a name's level is one past the deepest of its dependencies in names, and dependencies outside names don't count. So a level's names never depend on each other, and each depends only on names in earlier levels โ€” work within a level can run in parallel. Within a level, names follow rank when given (config order, say), else order.

order

every name to group, dependencies before dependents (a topological order)

type readonly string[]

get_dependencies

the names one name depends on

type (name: string) => Iterable<string>

names?

the names to group, a subset of order; defaults to all of it

type ReadonlySet<string>
optional

rank?

each name's position within its level; names it lacks go last

type ReadonlyMap<string, number>
optional

returns

string[][]

the levels, shallowest first, with no empty level

has_changesets
#

changeset_reader.ts view source

(repo: LocalRepo): Promise<boolean> import {has_changesets} from '@fuzdev/fuz_repos/changeset_reader.js';

Checks if a repo has any changeset files (excluding README.md).

Used by the publishing plan to determine which packages need to be published. Returns false if .changeset directory doesn't exist or contains only README.md.

repo

returns

Promise<boolean>

true if repo has unpublished changesets

is_breaking_change
#

version_utils.ts view source

(old_version: string, bump_type: BumpType): boolean import {is_breaking_change} from '@fuzdev/fuz_repos/version_utils.js';

Determines if a bump is a breaking change based on semver rules. Pre-1.0: minor bumps are breaking 1.0+: major bumps are breaking

old_version

type string

bump_type

returns

boolean

is_wildcard
#

version_utils.ts view source

(version: string): boolean import {is_wildcard} from '@fuzdev/fuz_repos/version_utils.js';

version

type string

returns

boolean

load_gitops_config
#

gitops_config.ts view source

(config_path: string): Promise<{ repos: string[]; } | null> import {load_gitops_config} from '@fuzdev/fuz_repos/gitops_config.js';

Loads a gitops config module and validates it.

config_path

type string

returns

Promise<GitopsConfig | null>

the config, or null when no file exists at config_path

throws

  • Error - if the module's default export isn't a valid config

load_repos_status
#

repos_status_load.ts view source

(options: { keys: string[]; registry?: string | undefined; fetch?: boolean | undefined; repos_ops: ReposOperations; }): Promise<Result<{ report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { ...; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | { ...; })[] | null; }; }, ReposStatusLoadFailure>> import {load_repos_status} from '@fuzdev/fuz_repos/repos_status_load.js';

Runs repos status <keysโ€ฆ> --json and parses its report.

options

type { keys: string[]; registry?: string | undefined; fetch?: boolean | undefined; repos_ops: ReposOperations; }

returns

Promise<Result>

the report, or a message saying what went wrong and what to change

local_repo_load
#

local_repo.ts view source

(options: LocalRepoLoadOptions & { local_repo_path: LocalRepoPath; }): Promise<LocalRepo> import {local_repo_load} from '@fuzdev/fuz_repos/local_repo.js';

Loads a resolved repo as its working tree sits (the tasks read where each repo sits from repos status, and repos sync moves them). Moves no ref.

  1. Loads library_json, with the module analysis or without it (modules)
  2. Creates Library and extracts dependency maps

A repo with no package.json but a Rust Cargo.toml loads as a dashboard-only cargo repo instead.

options

type ({ log?: Logger | undefined; } & { modules: true; fs_paths: FsPaths; git: SpawnProgram; } & { local_repo_path: LocalRepoPath; }) | ({ log?: Logger | undefined; } & { modules: false; } & { local_repo_path: LocalRepoPath; })

returns

Promise<LocalRepo>

throws

  • TaskError - if the `package.json` or the analysis fails

local_repos_load
#

local_repo.ts view source

({ local_repo_paths, parallel, concurrency, ...load_options }: LocalRepoLoadOptions & { local_repo_paths: LocalRepoPath[]; parallel?: boolean | undefined; concurrency?: number | undefined; }): Promise<...> import {local_repos_load} from '@fuzdev/fuz_repos/local_repo.js';

Loads each resolved repo (local_repo_load), in order.

__0

type ({ log?: Logger | undefined; } & { modules: true; fs_paths: FsPaths; git: SpawnProgram; } & { local_repo_paths: LocalRepoPath[]; parallel?: boolean | undefined; concurrency?: number | undefined; }) | ({ log?: Logger | undefined; } & { modules: false; } & { local_repo_paths: LocalRepoPath[]; parallel?: boolean | undefined; concurrency?: number | undefined; })

returns

Promise<LocalRepo[]>

throws

  • TaskError - naming every repo that failed to load

local_repos_resolve
#

local_repo.ts view source

(options: { keys: readonly string[]; report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | { ...; })[] | null; }; host?: { ...; } | undefined; registry?: string | undefined; }): Result<...> import {local_repos_resolve} from '@fuzdev/fuz_repos/local_repo.js';

Resolves a gitops config's registry keys against a repos status report, in config order. Every key must name an owned repo that's present and was probed; each that doesn't is a problem, and any problem fails the whole resolve, naming them all.

options

type { keys: readonly string[]; report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregist...

returns

Result

the repos in config order, or a message listing every problem

LocalRepo
#

local_repo.ts view source

LocalRepo import type {LocalRepo} from '@fuzdev/fuz_repos/local_repo.js';

Fully loaded local repo with Library and extracted dependency data. Does not extend LocalRepoPath - Library is source of truth for name/repo_url/etc.

kind

Which packaging ecosystem the repo belongs to. npm repos (with a package.json) take part in the changeset publishing cascade; cargo repos (a Rust Cargo.toml, no package.json) are dashboard-only โ€” fetched and rendered like any repo but excluded from publishing/analysis. See repo_is_npm.

type "npm" | "cargo"

library

type Library

package_json

The repo's full package.json (with dependencies/devDependencies).

type PackageJson

repo_dir

type string

entry

The repo's registry entry as repos status --json reported it: its branch, visibility, ci, and archived, and its git state.

type ReposEntryStatus

dependencies?

type Map<string, string>

dev_dependencies?

type Map<string, string>

peer_dependencies?

type Map<string, string>

LocalRepoLoadOptions
#

local_repo.ts view source

LocalRepoLoadOptions

type ({ log?: Logger | undefined; } & { modules: true; fs_paths: FsPaths; git: SpawnProgram; }) | ({ log?: Logger | undefined; } & { modules: false; })

import type {LocalRepoLoadOptions} from '@fuzdev/fuz_repos/local_repo.js';

Options for loading resolved repos (local_repo_load, local_repos_load).

LocalRepoPath
#

local_repo.ts view source

LocalRepoPath import type {LocalRepoPath} from '@fuzdev/fuz_repos/local_repo.js';

A configured repo resolved through repos status: present on disk, before its library is loaded. See local_repos_resolve.

repo_name

The repo's registry key (for display/logging before Library is loaded).

type string

repo_dir

The workspace root joined with the entry's dir.

type string

repo_url

The registry's HTTPS URL for the repo.

type string

entry

The repo's registry entry as repos status --json reported it.

type ReposEntryStatus

log_dependency_analysis
#

log_helpers.ts view source

(analysis: DependencyAnalysis, log: Logger, indent?: string): void import {log_dependency_analysis} from '@fuzdev/fuz_repos/log_helpers.js';

Logs all dependency analysis results (wildcards, production cycles, dev cycles). Convenience function that calls all three logging functions in order.

analysis

log

type Logger

indent?

type string
optional default ''

returns

void

log_dev_cycles
#

log_helpers.ts view source

(analysis: DependencyAnalysis, log: Logger, indent?: string): void import {log_dev_cycles} from '@fuzdev/fuz_repos/log_helpers.js';

Logs dev circular dependencies as info. Dev cycles are normal and non-blocking, so they're informational, not warnings.

analysis

log

type Logger

indent?

type string
optional default ''

returns

void

log_production_cycles
#

log_helpers.ts view source

(analysis: DependencyAnalysis, log: Logger, indent?: string): void import {log_production_cycles} from '@fuzdev/fuz_repos/log_helpers.js';

Logs production/peer circular dependencies as errors. Production cycles block publishing and must be resolved.

analysis

log

type Logger

indent?

type string
optional default ''

returns

void

log_publishing_plan
#

publishing_plan_logging.ts view source

(plan: PublishingPlan, log: Logger, options?: LogPlanOptions): void import {log_publishing_plan} from '@fuzdev/fuz_repos/publishing_plan_logging.js';

Logs a complete publishing plan to the console.

Displays errors, the waves, version changes grouped by scenario, dependency-only updates, packages awaiting the registry, warnings, and a summary.

plan

log

type Logger

options?

optional default {}

returns

void

log_readiness_block
#

gitops_task_helpers.ts view source

(local_repos: readonly LocalRepo[], log: Logger, now?: number): void import {log_readiness_block} from '@fuzdev/fuz_repos/gitops_task_helpers.js';

Logs the diagnostics' readiness block as warnings (stderr, so a `--format json or markdown` document on stdout stays clean): each npm repo not at rest, and how. Logs nothing when every one is at rest. Reads the entries repos status already reported, from local refs.

local_repos

the loaded repos; the npm ones are reported

type readonly LocalRepo[]

log

where the warnings go

type Logger

now?

the current time in unix seconds (defaults to the clock)

type number
optional default Math.floor(Date.now() / 1000)

returns

void

log_wildcard_dependencies
#

log_helpers.ts view source

(analysis: DependencyAnalysis, log: Logger, indent?: string): void import {log_wildcard_dependencies} from '@fuzdev/fuz_repos/log_helpers.js';

Logs wildcard dependencies as warnings. Wildcard dependencies require attention and should be reviewed.

analysis

log

type Logger

indent?

type string
optional default ''

returns

void

LogPlanOptions
#

publishing_plan_logging.ts view source

LogPlanOptions import type {LogPlanOptions} from '@fuzdev/fuz_repos/publishing_plan_logging.js';

verbose?

type boolean

version_strategy?

The prefix strategy the release step rewrites unprefixed ranges with, so the diffs show what it writes. gitops_plan and gitops_validate take no strategy and show the default.

type VersionStrategy

merge_dependency_updates
#

changeset_generator.ts view source

(existing: DependencyVersionChange[], updates: DependencyVersionChange[]): DependencyVersionChange[] import {merge_dependency_updates} from '@fuzdev/fuz_repos/changeset_generator.js';

Merges new dependency changes into existing ones, in order: a dependency in both keeps its first from_version, takes the later to_version, the larger bump, and is breaking if either change was.

existing

updates

returns

DependencyVersionChange[]

ModulesDetail
#

ModulesNav
#

ModulesNav.svelte view source

import ModulesNav from '@fuzdev/fuz_repos/ModulesNav.svelte';

repos_modules

type { repo: Repo; modules: unknown[]; }[]

ModulesPage
#

needs_update
#

version_utils.ts view source

(current: string, new_version: string): boolean import {needs_update} from '@fuzdev/fuz_repos/version_utils.js';

Whether a dependency range must move to name new_version: a wildcard always does, and so does a range whose base version is older. One already naming it, or a newer version (a range staged ahead of a publish), doesn't โ€” the rewrite never moves a range backward. A base that isn't x.y.z moves whenever it differs, and a protocol range (file:, workspace:, npm:) never.

current

type string

new_version

type string

returns

boolean

examples

needs_update('^0.54.0', '0.55.0') // true
needs_update('>=0.56.0', '0.55.0') // false

normalize_version_for_comparison
#

version_utils.ts view source

(version: string): string import {normalize_version_for_comparison} from '@fuzdev/fuz_repos/version_utils.js';

Normalizes version string for comparison.

Strips prefixes (^, ~, >=) to get bare version number. Handles wildcards as-is. Used by needs_update to compare versions.

version

type string

returns

string

examples

normalize_version_for_comparison('^1.2.3') // '1.2.3'
normalize_version_for_comparison('>=2.0.0') // '2.0.0'
normalize_version_for_comparison('*') // '*'

NpmOperations
#

operations.ts view source

NpmOperations import type {NpmOperations} from '@fuzdev/fuz_repos/operations.js';

Registry operations: whether a version is out, and waiting for one to propagate. npm's own config picks the registry, so a scope pointed elsewhere is read there.

view_version

What the registry shows for pkg@version (RegistryVersion). Fails when npm can't answer (offline, auth, a crash), so an outage never reads as unpublished.

type (options: { pkg: string; version: string; }): Promise<Result<{ value: RegistryVersion; }, { message: string; }>>

options

type { pkg: string; version: string; }
returns Promise<Result>

wait_for_package

Waits for a package version to be available on NPM. Uses exponential backoff with configurable timeout.

type (options: { pkg: string; version: string; wait_options?: WaitOptions | undefined; log?: Logger | undefined; }): Promise<Result<object, { message: string; }>>

options

type { pkg: string; version: string; wait_options?: WaitOptions | undefined; log?: Logger | undefined; }
returns Promise<Result>

NpmRegistryDeps
#

npm_registry.ts view source

NpmRegistryDeps import type {NpmRegistryDeps} from '@fuzdev/fuz_repos/npm_registry.js';

The side effects of the registry checks โ€” running npm, sleeping, and reading the clock โ€” injected so tests drive them with plain objects.

run_npm

Runs npm with args and resolves to what it wrote to stdout โ€” empty when nothing, or when npm couldn't run. A throw counts as unavailable too.

type (args: string[]): Promise<string>

args

type string[]
returns Promise<string>

wait

Sleeps for ms milliseconds.

type (ms: number): Promise<void>

ms

type number
returns Promise<void>

now

The current time in milliseconds, as Date.now.

type (): number

returns number

output_is_machine
#

output_helpers.ts view source

(format: string, outfile: string | undefined): boolean import {output_is_machine} from '@fuzdev/fuz_repos/output_helpers.js';

Whether a task's stdout carries a machine-readable document: a json or markdown report not sent to --outfile.

format

the task's --format

type string

outfile

the task's --outfile, if any

type string | undefined

returns

boolean

OutputFormat
#

output_helpers.ts view source

OutputFormat

type "stdout" | "json" | "markdown"

import type {OutputFormat} from '@fuzdev/fuz_repos/output_helpers.js';

OutputFormatters
#

output_helpers.ts view source

OutputFormatters<T> import type {OutputFormatters} from '@fuzdev/fuz_repos/output_helpers.js';

generics

OutputFormatters<T>
T

json

type (data: T): string

data

type T
returns string

markdown

type (data: T): string[]

data

type T
returns string[]

stdout

This function should call log methods directly for colored/styled output.

type (data: T, log: Logger): void

data

type T

log

type Logger
returns void

OutputOptions
#

output_helpers.ts view source

OutputOptions import type {OutputOptions} from '@fuzdev/fuz_repos/output_helpers.js';

format

type OutputFormat

outfile?

type string

log?

type Logger

write_stdout?

Where a json or markdown document goes without outfile; the one route_human_output returns, so the document reaches stdout while the logger's lines go to stderr.

type (content: string): void

default `console.log`

content

type string
returns void

PageFooter
#

PageHeader
#

parse_changeset_content
#

changeset_reader.ts view source

(content: string, filename?: string): ChangesetInfo | null import {parse_changeset_content} from '@fuzdev/fuz_repos/changeset_reader.js';

Parses changeset content string from markdown format.

Pure function for testability - no file I/O, just string parsing. Extracts package names, bump types, and summary from YAML frontmatter format. Returns null if format is invalid or no packages found.

Expected format:

--- "package-name": patch "@scope/package": minor --- Summary of changes

content

changeset markdown with YAML frontmatter

type string

filename?

optional filename for error reporting context

type string
optional default 'changeset.md'

returns

ChangesetInfo | null

parsed changeset info or null if invalid format

parse_changeset_file
#

changeset_reader.ts view source

(filepath: string, log?: Logger | undefined): Promise<ChangesetInfo | null> import {parse_changeset_file} from '@fuzdev/fuz_repos/changeset_reader.js';

filepath

type string

log?

type Logger
optional

returns

Promise<ChangesetInfo | null>

parse_dependency_updates_changeset
#

changeset_generator.ts view source

(content: string, package_name: string): { bump_type: BumpType; updates: DependencyVersionChange[]; } | null import {parse_dependency_updates_changeset} from '@fuzdev/fuz_repos/changeset_generator.js';

Reads back a changeset generate_changeset_content wrote for package_name: its frontmatter bump and each - name: from โ†’ to (bump) line, breaking under its heading. Strict, so a merge never drops what it can't read: any other line โ€” prose, another package, a hand edit โ€” means the file isn't one.

content

type string

package_name

type string

returns

{ bump_type: BumpType; updates: DependencyVersionChange[]; } | null

the bump and changes, or null when the content isn't such a changeset

parse_gitops_config
#

gitops_config.ts view source

(raw: unknown, config_path: string): { repos: string[]; } import {parse_gitops_config} from '@fuzdev/fuz_repos/gitops_config.js';

Validates a loaded config value: registry keys, each listed once.

raw

type unknown

config_path

type string

returns

GitopsConfig

throws

  • Error - naming the config and what's wrong with it

parse_repos_status_output
#

repos_status_load.ts view source

(output: ReposCommandOutput): Result<{ report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | { ...; })[] | null; }; }, ReposStatusLoadFailure> import {parse_repos_status_output} from '@fuzdev/fuz_repos/repos_status_load.js';

Parses what repos status --json printed into its report, or a message saying what went wrong and what to change.

output

the command's stdout, stderr, and exit code

returns

Result

the report, or a message naming the error document's kind and hint, a format version mismatch, or output that isn't a status document; an error document rides along as error

predict_next_version
#

changeset_reader.ts view source

(repo: LocalRepo, log?: Logger | undefined): Promise<{ version: string; bump_type: BumpType; } | null> import {predict_next_version} from '@fuzdev/fuz_repos/changeset_reader.js';

Predicts the next version by analyzing all changesets in a repo.

Reads all changesets, determines the highest bump type for the package, and calculates the next version. Returns null if no changesets found.

Critical for dry-run mode accuracy - allows simulating publishes without actually running gro publish which consumes changesets.

repo

log?

type Logger
optional

returns

Promise<{ version: string; bump_type: BumpType; } | null>

predicted version and bump type, or null if no changesets

PublishingPlan
#

publishing_plan.ts view source

PublishingPlan import type {PublishingPlan} from '@fuzdev/fuz_repos/publishing_plan.js';

waves

The packages that publish, grouped by their longest prod/peer path to other packages that publish: a wave's packages depend only on earlier waves, never on each other, so each wave publishes together. In config order within a wave.

type string[][]

version_changes

type VersionChange[]

dependency_updates

type DependencyUpdate[]

breaking_cascades

type Map<string, string[]>

awaiting_registry

Packages whose current version the registry doesn't show, with no changesets: just published and still propagating, or a publish that failed. A package the registry has never seen is here too when another configured package has a prod/peer range on it โ€” a first publish npm answers E404 for until it shows. Empty without registry observations.

type AwaitingRegistry[]

never_published

Packages the registry has never seen, with no changesets of their own and no configured package depending on them for prod or peer โ€” apps or sites that never publish, most likely, which private would say. Like private packages they're update-only leaves: no auto-bump, and no range moves for them. Empty without registry observations.

type string[]

warnings

type string[]

info

Informational sentences, not warnings: excluded non-npm repos, dev dependency cycles.

type string[]

no_changes

Package names with no changesets and no version change โ€” nothing to publish.

type string[]

errors

type string[]

verbose_data?

type VerboseData

PullRequestMeta
#

PullRequestsDetail
#

PullRequestsPage
#

read_changesets
#

reconcile_ci
#

ci_reconcile.ts view source

(repos: CiReconcileInput[]): CiDrift[] import {reconcile_ci} from '@fuzdev/fuz_repos/ci_reconcile.js';

Compares each repo's declared ci against its actual workflow presence.

repos

returns

CiDrift[]

one CiDrift per repo whose declaration and reality disagree

RegistryVersion
#

npm_registry.ts view source

RegistryVersion

type "listed" | "unlisted" | "unknown"

import type {RegistryVersion} from '@fuzdev/fuz_repos/npm_registry.js';

What the registry shows for one package version: the version is listed, the package is known but the version unlisted (still propagating, or never published), or the package itself is unknown (never published at all).

ReleaseHeld
#

release_state.ts view source

ReleaseHeld import type {ReleaseHeld} from '@fuzdev/fuz_repos/release_state.js';

A rewrite or publish that waits, and why.

name

The held package's name.

type string

reasons

Why it waits, each a line naming the fix.

type string[]

ReleaseReadiness
#

repo_readiness.ts view source

ReleaseReadiness import type {ReleaseReadiness} from '@fuzdev/fuz_repos/repo_readiness.js';

Why the repos a release step reads aren't ready to be rewritten or published.

global

Problems with the whole report, which hold every repo.

type string[]

by_key

Each not-ready repo's problems, by registry key, as what โ€” fix lines.

type Map<string, string[]>

ReleaseRewrite
#

release_state.ts view source

ReleaseRewrite import type {ReleaseRewrite} from '@fuzdev/fuz_repos/release_state.js';

One dependent's rewrite: its ranges for released dependencies, in one commit.

name

The dependent's package name.

type string

updates

type DependencyUpdate[]

changeset

Whether the dependent republishes, so its prod/peer updates go in its auto-changeset.

type boolean

ReleaseState
#

release_state.ts view source

ReleaseState import type {ReleaseState} from '@fuzdev/fuz_repos/release_state.js';

rewrites

Rewrites whose dependencies are released and whose repos are ready.

type ReleaseRewrite[]

rewrites_held

Rewrites whose dependencies are released but whose repos aren't ready.

type (ReleaseHeld & { updates: DependencyUpdate[]; })[]

publish_now

Packages to publish now, in dependency order: the first wave's ready ones.

type string[]

publish_held

The first wave's packages that can't publish yet, and why.

type ReleaseHeld[]

done

Nothing left to publish, rewrite, or wait for.

type boolean

Repo
#

repo.svelte.ts view source

import {Repo} from '@fuzdev/fuz_repos/repo.svelte.js';

Runtime repo with Library composition for package metadata.

Wraps a Library instance and adds GitHub-specific data (CI status, PRs). Convenience getters delegate to this.library.* for common properties.

library

type Library

readonly

package_json

The repo's full package.json (with dependencies/devDependencies).

type PackageJson

readonly

branch

The branch CI status was fetched for and the dashboard links to.

type string

readonly

check_runs

type GithubCheckRunsItem | null

pull_requests

type GithubPullRequest[] | null

constructor

type new (repo_json: RepoJson): Repo

repo_json

name

type string

getter

repo_name

type string

getter

repo_url

type Url

getter

homepage_url

type Url | null

getter

logo_url

type Url | null

getter

logo_alt

type string

getter

npm_url

type Url | null

getter

changelog_url

type Url | null

getter

pkg_json

Curated package identity, delegating to library. Distinct from the full package_json.

type PkgJson

getter

source_json

type SourceJson

getter

repo_has_workflows
#

ci_reconcile.ts view source

(repo_dir: string): boolean import {repo_has_workflows} from '@fuzdev/fuz_repos/ci_reconcile.js';

Whether a local repo directory contains at least one GitHub Actions workflow.

repo_dir

absolute or cwd-relative path to the repo's local directory

type string

returns

boolean

repo_is_npm
#

local_repo.ts view source

(repo: LocalRepo): boolean import {repo_is_npm} from '@fuzdev/fuz_repos/local_repo.js';

Whether a repo is an npm package and so participates in publishing and dependency analysis. Non-npm repos (e.g. Rust cargo repos) are still rendered on the dashboard, but excluded from the changeset cascade.

repo

returns

boolean

repo_readiness_at_rest
#

repo_readiness.ts view source

(entry: { kind: "repo" | "reference"; key: string; dir: string; pinned: boolean; url: string; branch: string | null; needs_human: ({ kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | ... 5 more ... | "am"; checkout: string; } | ... 12 more ... | { ...; })[]; ... 16 more ...; visibility_check: { ...; } | ... 2 more ... | null; }): RepoReadinessProblem[] import {repo_readiness_at_rest} from '@fuzdev/fuz_repos/repo_readiness.js';

The ways an entry's primary checkout isn't at rest where the registry puts it, from its at_rest facts: empty when it is.

entry

the entry as repos status --json reported it

returns

RepoReadinessProblem[]

the problems, in a fixed order: unprobed alone, else branch, dirt, operation, then the followed branch's relation

repo_readiness_for_gen
#

repo_readiness.ts view source

(entry: { kind: "repo" | "reference"; key: string; dir: string; pinned: boolean; url: string; branch: string | null; needs_human: ({ kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | ... 5 more ... | "am"; checkout: string; } | ... 12 more ... | { ...; })[]; ... 16 more ...; visibility_check: { ...; } | ... 2 more ... | null; }, options?: { ...; }): { ...; } import {repo_readiness_for_gen} from '@fuzdev/fuz_repos/repo_readiness.js';

An entry's problems for gitops_sync, split by what they do to the run: refused stops it, warned is logged. Off its branch, dirty, or mid-operation refuses, since the site would show that working tree's modules beside origin's CI โ€” unless allow_dirty, which reads the repo as it sits and warns instead. A checkout that can't be read, or an entry following no branch (only a reference follows none, and the config refuses references), always refuses. The followed branch not in sync with origin (behind, say: CI is origin's tip, the modules the local tree) and a failed fetch (the last fetch's view stands) warn. Busy sessions and needs_human reasons don't matter: generating writes nothing in the repo.

entry

the entry as repos status --json reported it

options?

type { allow_dirty?: boolean | undefined; }
optional default {}

returns

{ refused: RepoReadinessProblem[]; warned: RepoReadinessProblem[]; }

the problems that refuse, and those that warn

repo_readiness_for_publish
#

repo_readiness.ts view source

(entry: { kind: "repo" | "reference"; key: string; dir: string; pinned: boolean; url: string; branch: string | null; needs_human: ({ kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | ... 5 more ... | "am"; checkout: string; } | ... 12 more ... | { ...; })[]; ... 16 more ...; visibility_check: { ...; } | ... 2 more ... | null; }): RepoReadinessProblem[] import {repo_readiness_for_publish} from '@fuzdev/fuz_repos/repo_readiness.js';

The ways an entry isn't ready for a release step to rewrite or publish it: not at rest (repo_readiness_at_rest) other than its followed branch being ahead of origin, its fetch failed, another live session works in its primary checkout, or it has a needs_human reason. Ahead is ready: origin's tip is an ancestor of the branch, so the plan misses nothing and `gro publish`'s push stays a fast-forward, pushing those commits with the release. A reason restating an at-rest problem (the primary's operation or detached HEAD) is left out, and a default_branch_* reason stands in for the followed-branch problem it explains.

entry

the entry as repos status --fetch --json reported it

returns

RepoReadinessProblem[]

the problems; empty when the entry is ready

RepoAnalysis
#

RepoJson
#

repo.svelte.ts view source

RepoJson import type {RepoJson} from '@fuzdev/fuz_repos/repo.svelte.js';

Serialized repo data as stored in repos.ts (JSON).

package_json is the repo's full package.json, carried alongside library_json because fuz_repos reads dependencies/devDependencies for the publishing cascade โ€” fields the curated LibraryJson.pkg_json omits.

library_json

type LibraryJson

package_json

type PackageJson

branch?

The branch the repo's registry entry follows, which check_runs was fetched for. Repo.branch reads main when it's absent.

type string

check_runs

type GithubCheckRunsItem | null

pull_requests

type GithubPullRequest[] | null

RepoReadiness
#

RepoReadinessFormatOptions
#

repo_readiness.ts view source

RepoReadinessFormatOptions import type {RepoReadinessFormatOptions} from '@fuzdev/fuz_repos/repo_readiness.js';

Options for the messages naming what's wrong and the fix.

repos_command?

The repos invocation fixes name; repos --registry <path> when the run passed one.

type string

RepoReadinessProblem
#

repo_readiness.ts view source

RepoReadinessProblem

type { kind: "unprobed"; detail: string; } | { kind: "no_branch"; } | { kind: "off_branch"; branch: string; head: { kind: "branch"; name: string; } | { kind: "detached"; commit: string; }; } | { kind: "dirty"; uncommitted: { staged: number; unstaged: number; untracked: number; conflicted: number; }; } | { kind: "in_progress"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am" | null; } | { kind: "followed"; branch: string; relation: { kind: "in_sync"; } | { kind: "ahead"; commits: number; } | { kind: "behind"; commits: number; } | { kind: "diverged"; ahead: number; behind: number; } | { kind: "shallow"; } | { kind: "gone"; } | { kind: "unmapped"; } | { kind: "untracked"; } | null; } | { kind: "fetch_failed"; failure: { kind: "ref_gone"; refname: string; fix: { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { kind: "by_hand"; }; } | { kind: "unreachable"; cause: "dns" | "connection" | "host_key" | "auth"; message: string; } | { kind: "repo_not_found"; message: string; } | { kind: "timed_out"; after_secs: number; } | { kind: "failed"; message: string; } | { kind: "refspec_outside_origin"; refspec: string; } | { kind: "origin_refs_shared"; refspec: string; remote: string; } | { kind: "legacy_remotes_unreadable"; path: string; }; } | { kind: "busy"; sessions: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { kind: "needs_human"; reason: { kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; checkout: string; } | ... 12 more ... | { ...; }; }

import type {RepoReadinessProblem} from '@fuzdev/fuz_repos/repo_readiness.js';

One way a repo isn't where the registry puts it, or isn't ready to publish.

Repos
#

repos_context
#

repo.svelte.ts view source

{ get: (error_message?: string | undefined) => Repos; get_maybe: () => Repos | undefined; set: (value: Repos) => Repos; } import {repos_context} from '@fuzdev/fuz_repos/repo.svelte.js';

REPOS_INSTALL_COMMAND
#

repos_status_load.ts view source

"cargo install --path crates/fuz_repos --locked" import {REPOS_INSTALL_COMMAND} from '@fuzdev/fuz_repos/repos_status_load.js';

How to install the repos binary, run in a fuz_repos checkout. The npm package doesn't carry the binary, so the two are installed separately.

repos_not_at_rest
#

repo_readiness.ts view source

(entries: readonly { kind: "repo" | "reference"; key: string; dir: string; pinned: boolean; url: string; branch: string | null; needs_human: ({ kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | ... 5 more ... | "am"; checkout: string; } | ... 12 more ... | { ...; })[]; ... 16 more ...; visibility_check: { ...; } | ... 2 more ... | null; }[]): RepoReadiness[] import {repos_not_at_rest} from '@fuzdev/fuz_repos/repo_readiness.js';

The repos not at rest, for the read-only diagnostics' readiness block.

entries

the entries of the repos a diagnostic reads

type readonly ReposEntryStatus[]

returns

RepoReadiness[]

each entry with at-rest problems, in the order given

repos_parse
#

repo.svelte.ts view source

(repos: Repo[], homepage_url: string): Repos import {repos_parse} from '@fuzdev/fuz_repos/repo.svelte.js';

repos

type Repo[]

homepage_url

type string

returns

Repos

REPOS_STATUS_FORMAT_VERSION
#

repos_status.ts view source

20 import {REPOS_STATUS_FORMAT_VERSION} from '@fuzdev/fuz_repos/repos_status.js';

The repos status --json document's format version, Rust's STATUS_FORMAT_VERSION: the one these schemas parse.

ReposAtRest
#

repos_status.ts view source

value + type

{ on_branch: boolean | null; clean: boolean; idle: boolean; followed: { kind: "in_sync"; } | { kind: "ahead"; commits: number; } | { kind: "behind"; commits: number; } | { kind: "diverged"; ahead: number; behind: number; } | ... 4 more ... | null; } import {ReposAtRest} from '@fuzdev/fuz_repos/repos_status.js';

Whether an entry's primary checkout sits where the registry puts it.

on_branch

type boolean | null

clean

type boolean

idle

type boolean

followed

type { kind: "in_sync"; } | { kind: "ahead"; commits: number; } | { kind: "behind"; commits: number; } | { kind: "diverged"; ahead: number; behind: number; } | { kind: "shallow"; } | { kind: "gone"; } | { kind: "unmapped"; } | { kind: "untracked"; } | null

ReposBranchHold
#

repos_status.ts view source

value + type

"entry" | "pinned" | "push_url" | "fetch_failed" | "dirty_checkout" | "unprobed_worktree" | "several_checkouts" | "busy" | "busy_unknown" | "lfs_objects" | "lfs_unscanned"

type "entry" | "pinned" | "push_url" | "fetch_failed" | "dirty_checkout" | "unprobed_worktree" | "several_checkouts" | "busy" | "busy_unknown" | "lfs_objects" | "lfs_unscanned"

import {ReposBranchHold} from '@fuzdev/fuz_repos/repos_status.js';

What holds a branch's action back.

ReposBranchNeedsHuman
#

repos_status.ts view source

value + type

"diverged" | "diverged_published" | "diverged_merge" | "diverged_tagged" | "unmapped" | "archived_ahead" | "shallow_local_work" | "upstream_not_a_branch"

type "diverged" | "diverged_published" | "diverged_merge" | "diverged_tagged" | "unmapped" | "archived_ahead" | "shallow_local_work" | "upstream_not_a_branch"

import {ReposBranchNeedsHuman} from '@fuzdev/fuz_repos/repos_status.js';

Why a branch is left to a person.

ReposBranchStatus
#

repos_status.ts view source

value + type

{ worktree: string | null; name: string; upstream: string | null; symref: string | null; unique_commits: number; newest_commit_at: number; relation: { kind: "in_sync"; } | { kind: "ahead"; commits: number; } | ... 5 more ... | { ...; }; verdict: { ...; } | ... 4 more ... | { ...; }; } import {ReposBranchStatus} from '@fuzdev/fuz_repos/repos_status.js';

One local branch and its verdict.

worktree

type string | null

name

type string

upstream

type string | null

symref

type string | null

unique_commits

type number

newest_commit_at

type number

relation

type ReposRelation

verdict

type ReposVerdict

ReposCheckout
#

repos_status.ts view source

value + type

{ in_progress: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am" | null; path: string; busy: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; ... 5 more ...; submodules: boolean | null; } import {ReposCheckout} from '@fuzdev/fuz_repos/repos_status.js';

One checkout of a repo: its primary, or a linked worktree probed.

in_progress

type "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am" | null

path

type string

busy

type ReposSession[]

primary

type boolean

head

type ReposHead

uncommitted

type ReposUncommitted

locked

type boolean

linked

type boolean

submodules

type boolean | null

ReposCheckoutList
#

repos_status.ts view source

value + type

"requires" | "consults"

type "requires" | "consults"

import {ReposCheckoutList} from '@fuzdev/fuz_repos/repos_status.js';

A repo's list of the sibling checkouts it uses.

ReposCleanupReason
#

repos_status.ts view source

value + type

"merged" | "upstream_gone"

type "merged" | "upstream_gone"

import {ReposCleanupReason} from '@fuzdev/fuz_repos/repos_status.js';

Why a branch reads as cleanup.

ReposCloneHold
#

repos_status.ts view source

value + type

"entry" | "unprobed_worktree" | "busy"

type "entry" | "unprobed_worktree" | "busy"

import {ReposCloneHold} from '@fuzdev/fuz_repos/repos_status.js';

What holds a missing entry's clone back.

ReposCloneRecipe
#

repos_status.ts view source

value + type

{ url: string; branch: string | null; shallow: boolean; sparse: string | null; } import {ReposCloneRecipe} from '@fuzdev/fuz_repos/repos_status.js';

How sync would clone a missing entry.

url

type string

branch

type string | null

shallow

type boolean

sparse

type string | null

ReposCloneVerdict
#

repos_status.ts view source

value + type

{ kind: "act"; recipe: { url: string; branch: string | null; shallow: boolean; sparse: string | null; }; } | { kind: "held"; by: "entry" | "unprobed_worktree" | "busy"; recipe: { url: string; branch: string | null; shallow: boolean; sparse: string | null; }; }

type { kind: "act"; recipe: { url: string; branch: string | null; shallow: boolean; sparse: string | null; }; } | { kind: "held"; by: "entry" | "unprobed_worktree" | "busy"; recipe: { url: string; branch: string | null; shallow: boolean; sparse: string | null; }; }

import {ReposCloneVerdict} from '@fuzdev/fuz_repos/repos_status.js';

What sync does about a missing entry: clone it, or why not yet.

ReposCommandOutput
#

operations.ts view source

ReposCommandOutput import type {ReposCommandOutput} from '@fuzdev/fuz_repos/operations.js';

What a repos command printed and how it exited, unparsed.

stdout

type string

stderr

type string

exit_code

0 for a report, 2 for an error document, 1 for a fatal I/O error (maybe no JSON).

type number

ReposEntryKind
#

repos_status.ts view source

value + type

"repo" | "reference"

type "repo" | "reference"

import {ReposEntryKind} from '@fuzdev/fuz_repos/repos_status.js';

Which registry table an entry comes from.

ReposEntryName
#

repos_status.ts view source

value + type

{ kind: "repo" | "reference"; key: string; } import {ReposEntryName} from '@fuzdev/fuz_repos/repos_status.js';

An entry by table and key.

kind

type "repo" | "reference"

key

type string

ReposEntryStatus
#

repos_status.ts view source

value + type

{ kind: "repo" | "reference"; key: string; dir: string; pinned: boolean; url: string; branch: string | null; needs_human: ({ kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | ... 5 more ... | "am"; checkout: string; } | ... 12 more ... | { ...; })[]; ... 16 more ...; visibility_... import {ReposEntryStatus} from '@fuzdev/fuz_repos/repos_status.js';

One registry entry's state.

kind

type "repo" | "reference"

key

type string

dir

type string

pinned

type boolean

url

type string

branch

type string | null

needs_human

type ReposNeedsHuman[]

writable

type boolean

archived

type boolean

visibility

type "public" | "private" | null

ci

type boolean

refresh

type { kind: "act"; } | { kind: "held"; by: "entry" | "pinned" | "origin_not_https"; } | null

presence

type ReposPresence

clone

type { kind: "act"; recipe: { url: string; branch: string | null; shallow: boolean; sparse: string | null; }; } | { kind: "held"; by: "entry" | "unprobed_worktree" | "busy"; recipe: { url: string; branch: string | null; shallow: boolean; sparse: string | null; }; } | null

layout

type ReposLayout | null

checkouts

type ReposCheckout[]

branches

type ReposBranchStatus[]

at_rest

type ReposAtRest | null

stashes

type number

fetched_at

type number | null

probe_error

type ReposProbeError | null

unprobed_worktrees

type ReposUnprobedWorktreeStatus[]

fetch_error

type { kind: "ref_gone"; refname: string; fix: { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { kind: "by_hand"; }; } | { kind: "unreachable"; cause: "dns" | "connection" | "host_key" | "auth"; message: string; } | { kind: "repo_not_found"; message: string; } | { kind: "timed_out"; after_secs: number; } | { kind: "failed"; message: string; } | { kind: "refspec_outside_origin"; refspec: string; } | { kind: "origin_refs_shared"; refspec: string; remote: string; } | { kind: "legacy_remotes_unreadable"; path: string; } | null

visibility_check

type { kind: "leak"; } | { kind: "private"; } | { failure: { kind: "ref_gone"; refname: string; fix: { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { kind: "by_hand"; }; } | { kind: "unreachable"; cause: "dns" | "connection" | "host_key" | "auth"; message: string; } | { kind: "repo_not_found"; message: string; } | { kind: "timed_out"; after_secs: number; } | { kind: "failed"; message: string; } | { kind: "refspec_outside_origin"; refspec: string; } | { kind: "origin_refs_shared"; refspec: string; remote: string; } | { kind: "legacy_remotes_unreadable"; path: string; }; kind: "unknown"; } | null

ReposFetchFailure
#

repos_status.ts view source

value + type

{ kind: "ref_gone"; refname: string; fix: { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { kind: "by_hand"; }; } | { kind: "unreachable"; cause: "dns" | ... 2 more ... | "auth"; message: string; } | ... 5 more ... | { ...; }

type { kind: "ref_gone"; refname: string; fix: { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { kind: "by_hand"; }; } | { kind: "unreachable"; cause: "dns" | "connection" | "host_key" | "auth"; message: string; } | { kind: "repo_not_found"; message: string; } | { kind: "timed_out"; after_secs: number; } | { kind: "failed"; message: string; } | { kind: "refspec_outside_origin"; refspec: string; } | { kind: "origin_refs_shared"; refspec: string; remote: string; } | { kind: "legacy_remotes_unreadable"; path: string; }

import {ReposFetchFailure} from '@fuzdev/fuz_repos/repos_status.js';

Why a fetch or the visibility check failed, or why the tool refused to fetch: Rust's RemoteFailure without rejected, which only a push meets.

ReposGitDirHolds
#

repos_status.ts view source

value + type

{ staged: boolean | null; submodules: boolean; worktree_refs: boolean; } import {ReposGitDirHolds} from '@fuzdev/fuz_repos/repos_status.js';

What an unprobed worktree's git dir holds that a prune would lose.

staged

type boolean | null

submodules

type boolean

worktree_refs

type boolean

ReposHead
#

repos_status.ts view source

value + type

{ kind: "branch"; name: string; } | { kind: "detached"; commit: string; }

type { kind: "branch"; name: string; } | { kind: "detached"; commit: string; }

import {ReposHead} from '@fuzdev/fuz_repos/repos_status.js';

A checkout's HEAD: a probed checkout's, an unprobed worktree's, or an unlisted git dir's โ€” the last two null when it can't be read.

ReposInProgressOp
#

repos_status.ts view source

value + type

"rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"

type "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"

import {ReposInProgressOp} from '@fuzdev/fuz_repos/repos_status.js';

A git operation in progress.

ReposLayout
#

repos_status.ts view source

value + type

{ shallow: boolean; sparse: boolean; partial_filter: string | null; } import {ReposLayout} from '@fuzdev/fuz_repos/repos_status.js';

A clone's shape: shallow, sparse, or partial.

shallow

type boolean

sparse

type boolean

partial_filter

type string | null

ReposNeedsHuman
#

repos_status.ts view source

value + type

{ kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; checkout: string; } | { kind: "origin_mismatch"; fix: { ...; } | ... 1 more ... | { ...; }; origin: { ...; } | ... 1 more ... | { ...; }; expected: string; } |...

type { kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; checkout: string; } | { kind: "origin_mismatch"; fix: { kind: "add"; } | { kind: "set_url"; } | { kind: "by_hand"; reason: "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"; }; origin: { kind: "url"; url: string; } | { kind: "no_url"; } | { kind: "missing"; }; expected: string; } | { kind: "origin_not_https"; fix: { kind: "add"; } | { kind: "set_url"; } | { kind: "by_hand"; reason: "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"; } | null; expected: string; fetch_url: string; } | { kind: "fetch_url_mismatch"; fix: { kind: "add"; } | { kind: "set_url"; } | { kind: "by_hand"; reason: "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"; } | null; expected: string; fetch_url: string; } | { kind: "worktree_unreadable"; path: string; } | { kind: "default_branch_missing"; branch: string; } | { kind: "default_branch_no_upstream"; branch: string; } | { kind: "default_branch_gone"; branch: string; } | { kind: "unexpected_detached"; checkout: string; } | { kind: "checkout_unresolvable"; path: string; error: string; checkout: string; } | { kind: "unlisted_git_dir"; busy: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; head: { kind: "branch"; name: string; } | { kind: "detached"; commit: string; } | null; git_dir: string; } | { kind: "push_url_mismatch"; expected: string; push_urls: string[]; } | { kind: "clone_shares_repo"; with: string; } | { kind: "cloned_unregistered"; dir: string; }

import {ReposNeedsHuman} from '@fuzdev/fuz_repos/repos_status.js';

Why sync would stop on an entry and leave it to a person.

ReposOperations
#

operations.ts view source

ReposOperations import type {ReposOperations} from '@fuzdev/fuz_repos/operations.js';

Operations running the Rust repos binary, which owns fleet git state. Parsing its output is repos_status_load.ts's, not the runner's.

status

Runs repos [--registry <path>] status [--fetch] <keysโ€ฆ> --json in the process's cwd and returns what it printed, whatever its exit code. With fetch, repos fetches each entry from origin first, which writes remote-tracking refs and nothing else. Fails only when the binary didn't run to an exit: not_found when it isn't on PATH.

type (options: { keys: string[]; registry?: string | undefined; fetch?: boolean | undefined; }): Promise<Result<{ output: ReposCommandOutput; }, { kind: "failed" | "not_found"; message: string; }>>

options

type { keys: string[]; registry?: string | undefined; fetch?: boolean | undefined; }
returns Promise<Result>

ReposOriginByHand
#

repos_status.ts view source

value + type

"outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"

type "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"

import {ReposOriginByHand} from '@fuzdev/fuz_repos/repos_status.js';

Why no git remote command fits an origin's fix.

ReposOriginFix
#

repos_status.ts view source

value + type

{ kind: "add"; } | { kind: "set_url"; } | { kind: "by_hand"; reason: "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"; }

type { kind: "add"; } | { kind: "set_url"; } | { kind: "by_hand"; reason: "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"; }

import {ReposOriginFix} from '@fuzdev/fuz_repos/repos_status.js';

How to point origin at the registry's URL.

ReposOriginRemote
#

repos_status.ts view source

value + type

{ kind: "url"; url: string; } | { kind: "no_url"; } | { kind: "missing"; }

type { kind: "url"; url: string; } | { kind: "no_url"; } | { kind: "missing"; }

import {ReposOriginRemote} from '@fuzdev/fuz_repos/repos_status.js';

The origin remote as git sees it, when it isn't the registry's url.

ReposPresence
#

repos_status.ts view source

value + type

{ kind: "present"; } | { kind: "missing"; } | { kind: "not_a_repo"; }

type { kind: "present"; } | { kind: "missing"; } | { kind: "not_a_repo"; }

import {ReposPresence} from '@fuzdev/fuz_repos/repos_status.js';

Whether a repo is at the entry's dir.

ReposProbeError
#

repos_status.ts view source

value + type

{ kind: "path_unreadable" | "non_utf8_path" | "config_unreadable" | "fetch_url_unreadable" | "push_urls_unreadable" | "git_not_run" | "git_timed_out" | "git_failed" | "unexpected_output"; message: string; } import {ReposProbeError} from '@fuzdev/fuz_repos/repos_status.js';

Why an entry's probe failed: its kind, and a message for display.

kind

type "path_unreadable" | "non_utf8_path" | "config_unreadable" | "fetch_url_unreadable" | "push_urls_unreadable" | "git_not_run" | "git_timed_out" | "git_failed" | "unexpected_output"

message

type string

ReposProbeErrorKind
#

repos_status.ts view source

value + type

"path_unreadable" | "non_utf8_path" | "config_unreadable" | "fetch_url_unreadable" | "push_urls_unreadable" | "git_not_run" | "git_timed_out" | "git_failed" | "unexpected_output"

type "path_unreadable" | "non_utf8_path" | "config_unreadable" | "fetch_url_unreadable" | "push_urls_unreadable" | "git_not_run" | "git_timed_out" | "git_failed" | "unexpected_output"

import {ReposProbeErrorKind} from '@fuzdev/fuz_repos/repos_status.js';

What kind of failure stopped an entry's probe.

ReposPrune
#

repos_status.ts view source

value + type

{ kind: "safe"; } | { kind: "loses"; losses: ({ kind: "operation"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; } | { kind: "detached_head"; } | { kind: "unknown_head"; } | ... 5 more ... | { ...; })[]; } | { ...; }

type { kind: "safe"; } | { kind: "loses"; losses: ({ kind: "operation"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; } | { kind: "detached_head"; } | { kind: "unknown_head"; } | { kind: "missing_branch"; name: string; } | { kind: "submodules"; } | { kind: "worktree_refs"; } | { kind: "staged_changes"; } | { kind: "unmatched_git_dir"; } | { kind: "relative_gitdir"; git_dir: string; })[]; } | { kind: "moved"; to: string[]; }

import {ReposPrune} from '@fuzdev/fuz_repos/repos_status.js';

Whether pruning an unprobed worktree is safe.

ReposPruneLoss
#

repos_status.ts view source

value + type

{ kind: "operation"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; } | { kind: "detached_head"; } | { kind: "unknown_head"; } | { kind: "missing_branch"; name: string; } | ... 4 more ... | { ...; }

type { kind: "operation"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; } | { kind: "detached_head"; } | { kind: "unknown_head"; } | { kind: "missing_branch"; name: string; } | { kind: "submodules"; } | { kind: "worktree_refs"; } | { kind: "staged_changes"; } | { kind: "unmatched_git_dir"; } | { kind: "relative_gitdir"; git_dir: string; }

import {ReposPruneLoss} from '@fuzdev/fuz_repos/repos_status.js';

What pruning an unprobed worktree would lose.

ReposRefGoneFix
#

repos_status.ts view source

value + type

{ kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { kind: "by_hand"; }

type { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { kind: "by_hand"; }

import {ReposRefGoneFix} from '@fuzdev/fuz_repos/repos_status.js';

How to repair a fetch refspec naming a ref gone from origin.

ReposRefreshHold
#

repos_status.ts view source

value + type

"entry" | "pinned" | "origin_not_https"

type "entry" | "pinned" | "origin_not_https"

import {ReposRefreshHold} from '@fuzdev/fuz_repos/repos_status.js';

What holds a reference's refresh back.

ReposRefreshVerdict
#

repos_status.ts view source

value + type

{ kind: "act"; } | { kind: "held"; by: "entry" | "pinned" | "origin_not_https"; }

type { kind: "act"; } | { kind: "held"; by: "entry" | "pinned" | "origin_not_https"; }

import {ReposRefreshVerdict} from '@fuzdev/fuz_repos/repos_status.js';

What a run does about refreshing a third-party reference or a pin.

ReposRegistryIssue
#

repos_status.ts view source

value + type

{ kind: "repo_not_owned"; key: string; account: string; } | { kind: "fork_not_owned"; key: string; } | { kind: "dir_not_a_name"; entry: { kind: "repo" | "reference"; key: string; }; dir: string; } | ... 5 more ... | { ...; }

type { kind: "repo_not_owned"; key: string; account: string; } | { kind: "fork_not_owned"; key: string; } | { kind: "dir_not_a_name"; entry: { kind: "repo" | "reference"; key: string; }; dir: string; } | { kind: "dir_claimed_twice"; dir: string; first: { kind: "repo" | "reference"; key: string; }; second: { kind: "repo" | "reference"; key: string; }; } | { kind: "key_in_both"; key: string; } | { kind: "key_is_other_dir"; key: string; entry: { kind: "repo" | "reference"; key: string; }; } | { kind: "unknown_checkout_ref"; key: string; field: "requires" | "consults"; target: string; } | { kind: "self_ref"; key: string; field: "requires" | "consults"; } | { kind: "requires_and_consults"; key: string; target: string; }

import {ReposRegistryIssue} from '@fuzdev/fuz_repos/repos_status.js';

A registry integrity rule broken.

ReposRelation
#

repos_status.ts view source

value + type

{ kind: "in_sync"; } | { kind: "ahead"; commits: number; } | { kind: "behind"; commits: number; } | { kind: "diverged"; ahead: number; behind: number; } | { kind: "shallow"; } | { kind: "gone"; } | { kind: "unmapped"; } | { ...; }

type { kind: "in_sync"; } | { kind: "ahead"; commits: number; } | { kind: "behind"; commits: number; } | { kind: "diverged"; ahead: number; behind: number; } | { kind: "shallow"; } | { kind: "gone"; } | { kind: "unmapped"; } | { kind: "untracked"; }

import {ReposRelation} from '@fuzdev/fuz_repos/repos_status.js';

A branch's relation to its upstream.

ReposRepairBlock
#

repos_status.ts view source

value + type

{ kind: "rewrites"; path: string; git_dir: string; } | { kind: "claimed_dir"; git_dir: string; } | { kind: "swapped"; git_dir: string; with: string; } | { kind: "relative_gitdir"; git_dir: string; } | { ...; } | { ...; } | { ...; }

type { kind: "rewrites"; path: string; git_dir: string; } | { kind: "claimed_dir"; git_dir: string; } | { kind: "swapped"; git_dir: string; with: string; } | { kind: "relative_gitdir"; git_dir: string; } | { kind: "unreadable_gitdir"; git_dir: string; } | { kind: "non_utf8_path"; } | { kind: "nul_in_gitdir"; git_dir: string; }

import {ReposRepairBlock} from '@fuzdev/fuz_repos/repos_status.js';

What keeps a moved worktree's repair from being offered.

ReposSession
#

repos_status.ts view source

value + type

{ pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; } import {ReposSession} from '@fuzdev/fuz_repos/repos_status.js';

A live Claude Code session: its process, and where it works.

pid

type number

cwd

type string

worktree

type string | null

process_cwd

type string | null

source

type "session_file" | "roster_worker"

ReposSessions
#

repos_status.ts view source

value + type

{ kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { kind: "unavailable"; reason: { ...; } | ... 3 more ... | { ...; }; }

type { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { kind: "unavailable"; reason: { kind: "home_unknown"; } | { kind: "relative_config_dir"; path: string; } | { kind: "unreadable"; path: string; error: string; } | { kind: "unparseable"; path: string; error: string; } | { source: "session_file" | "roster_worker"; kind: "foreign_pid_domain"; path: string; pid_domain: string; }; }

import {ReposSessions} from '@fuzdev/fuz_repos/repos_status.js';

Busy detection as the report carries it.

ReposSessionSource
#

repos_status.ts view source

value + type

"session_file" | "roster_worker"

type "session_file" | "roster_worker"

import {ReposSessionSource} from '@fuzdev/fuz_repos/repos_status.js';

Where a live Claude Code session was recorded.

ReposStatusDocument
#

repos_status.ts view source

value + type

{ version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | ...

type ReposStatusReport | ReposStatusErrorReport

import {ReposStatusDocument} from '@fuzdev/fuz_repos/repos_status.js';

Either document repos status --json prints. No tag is needed: error is the error document's alone, and each side's strictness refuses the other's fields. A consumer wanting a sharper parse error branches on error first and parses with that side's schema.

ReposStatusErrorBody
#

repos_status.ts view source

value + type

{ kind: "references_with_targets"; message: string; hint: string | null; } | { kind: "root_not_found"; message: string; hint: string | null; } | { kind: "registry_not_found"; message: string; hint: string | null; } | ... 7 more ... | { ...; }

type { kind: "references_with_targets"; message: string; hint: string | null; } | { kind: "root_not_found"; message: string; hint: string | null; } | { kind: "registry_not_found"; message: string; hint: string | null; } | { kind: "root_in_entry"; key: string; message: string; hint: string | null; } | { kind: "registry_read"; message: string; hint: string | null; } | { kind: "registry_parse"; message: string; hint: string | null; } | { kind: "registry_invalid"; message: string; hint: string | null; issues: ({ kind: "repo_not_owned"; key: string; account: string; } | { kind: "fork_not_owned"; key: string; } | { kind: "dir_not_a_name"; entry: { kind: "repo" | "reference"; key: string; }; dir: string; } | { kind: "dir_claimed_twice"; dir: string; first: { kind: "repo" | "reference"; key: string; }; second: { kind: "repo" | "reference"; key: string; }; } | { kind: "key_in_both"; key: string; } | { kind: "key_is_other_dir"; key: string; entry: { kind: "repo" | "reference"; key: string; }; } | { kind: "unknown_checkout_ref"; key: string; field: "requires" | "consults"; target: string; } | { kind: "self_ref"; key: string; field: "requires" | "consults"; } | { kind: "requires_and_consults"; key: string; target: string; })[]; } | { kind: "git_not_found"; message: string; hint: string | null; } | { kind: "git_too_old"; message: string; hint: string | null; found: string; required: string; } | { kind: "unknown_entry"; name: string; message: string; hint: string | null; suggestions: string[]; } | { kind: "io"; message: string; hint: string | null; }

import {ReposStatusErrorBody} from '@fuzdev/fuz_repos/repos_status.js';

A fatal error as repos status --json prints it, its kind flattened beside message and hint. Only the kinds status can print: the rest of Rust's ErrorKind are repos push's, or precede knowing --json.

ReposStatusErrorReport
#

repos_status.ts view source

value + type

{ error: { kind: "references_with_targets"; message: string; hint: string | null; } | { kind: "root_not_found"; message: string; hint: string | null; } | { kind: "registry_not_found"; message: string; hint: string | null; } | ... 7 more ... | { ...; }; version: 20; } import {ReposStatusErrorReport} from '@fuzdev/fuz_repos/repos_status.js';

The document repos status --json prints on a fatal error, in place of the report.

error

type ReposStatusErrorBody

version

type 20

ReposStatusLoadFailure
#

repos_status_load.ts view source

ReposStatusLoadFailure import type {ReposStatusLoadFailure} from '@fuzdev/fuz_repos/repos_status_load.js';

Why repos status gave no report: a message saying what to change, and the error document when repos printed one.

message

type string

error?

type ReposStatusErrorBody

ReposStatusReport
#

repos_status.ts view source

value + type

{ version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | ... import {ReposStatusReport} from '@fuzdev/fuz_repos/repos_status.js';

The repos status --json report.

version

type 20

workspace

type string

registry

type string

fetched

type boolean

sessions

type ReposSessions

entries

type ReposEntryStatus[]

unregistered

type ReposUnregisteredClone[] | null

ReposSyncAction
#

repos_status.ts view source

value + type

{ kind: "push"; commits: number; } | { kind: "fast_forward"; commits: number; } | { kind: "move"; } | { kind: "rebase"; ahead: number; behind: number; }

type { kind: "push"; commits: number; } | { kind: "fast_forward"; commits: number; } | { kind: "move"; } | { kind: "rebase"; ahead: number; behind: number; }

import {ReposSyncAction} from '@fuzdev/fuz_repos/repos_status.js';

A sync action on a branch.

ReposTable
#

ReposTable.svelte view source

import ReposTable from '@fuzdev/fuz_repos/ReposTable.svelte';

repos

type Repo[]

deps?

type string[]
optional default ['@fuzdev/fuz_ui', '@fuzdev/gro']

ReposTree
#

ReposTreeNav
#

ReposTreeNav.svelte view source

accepts children

import ReposTreeNav from '@fuzdev/fuz_repos/ReposTreeNav.svelte';

repos

type Repo[]

selected_repo?

type Repo
optional

children

type Snippet<[]>

CSS custom properties

--nav_width
fallback 240px

ReposUnavailable
#

repos_status.ts view source

value + type

{ kind: "home_unknown"; } | { kind: "relative_config_dir"; path: string; } | { kind: "unreadable"; path: string; error: string; } | { kind: "unparseable"; path: string; error: string; } | { source: "session_file" | "roster_worker"; kind: "foreign_pid_domain"; path: string; pid_domain: string; }

type { kind: "home_unknown"; } | { kind: "relative_config_dir"; path: string; } | { kind: "unreadable"; path: string; error: string; } | { kind: "unparseable"; path: string; error: string; } | { source: "session_file" | "roster_worker"; kind: "foreign_pid_domain"; path: string; pid_domain: string; }

import {ReposUnavailable} from '@fuzdev/fuz_repos/repos_status.js';

Why busy detection can't vouch for every live session.

ReposUncommitted
#

repos_status.ts view source

value + type

{ staged: number; unstaged: number; untracked: number; conflicted: number; } import {ReposUncommitted} from '@fuzdev/fuz_repos/repos_status.js';

A checkout's uncommitted work, by kind.

staged

type number

unstaged

type number

untracked

type number

conflicted

type number

ReposUnprobedWhy
#

repos_status.ts view source

value + type

{ kind: "prunable"; } | { kind: "missing"; } | { kind: "failed"; error: string; }

type { kind: "prunable"; } | { kind: "missing"; } | { kind: "failed"; error: string; }

import {ReposUnprobedWhy} from '@fuzdev/fuz_repos/repos_status.js';

Why a worktree wasn't probed.

ReposUnprobedWorktree
#

repos_status.ts view source

value + type

{ in_progress: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am" | null; path: string; head: { kind: "branch"; name: string; } | { kind: "detached"; commit: string; } | null; locked: boolean; git_dir: string | null; why: { ...; } | ... 1 more ... | { ...; }; holds: { ...; } | null; } import {ReposUnprobedWorktree} from '@fuzdev/fuz_repos/repos_status.js';

A worktree of the repo that couldn't be probed.

in_progress

type "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am" | null

path

type string

head

type { kind: "branch"; name: string; } | { kind: "detached"; commit: string; } | null

locked

type boolean

git_dir

type string | null

why

type ReposUnprobedWhy

holds

type ReposGitDirHolds | null

ReposUnprobedWorktreeStatus
#

repos_status.ts view source

value + type

{ in_progress: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am" | null; path: string; busy: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; ... 5 more ...; prune: { ...; } | ... 2 more ... | null; } import {ReposUnprobedWorktreeStatus} from '@fuzdev/fuz_repos/repos_status.js';

An unprobed worktree (flattened) with its prune verdict and live sessions.

in_progress

type "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am" | null

path

type string

busy

type ReposSession[]

head

type { kind: "branch"; name: string; } | { kind: "detached"; commit: string; } | null

locked

type boolean

git_dir

type string | null

why

type ReposUnprobedWhy

holds

type ReposGitDirHolds | null

prune

type { kind: "safe"; } | { kind: "loses"; losses: ({ kind: "operation"; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; } | { kind: "detached_head"; } | { kind: "unknown_head"; } | { kind: "missing_branch"; name: string; } | { kind: "submodules"; } | { kind: "worktree_refs"; } | { kind: "staged_changes"; } | { kind: "unmatched_git_dir"; } | { kind: "relative_gitdir"; git_dir: string; })[]; } | { kind: "moved"; to: string[]; } | null

ReposUnreachableCause
#

repos_status.ts view source

value + type

"dns" | "connection" | "host_key" | "auth"

type "dns" | "connection" | "host_key" | "auth"

import {ReposUnreachableCause} from '@fuzdev/fuz_repos/repos_status.js';

Why a remote couldn't be reached.

ReposUnregisteredClone
#

repos_status.ts view source

value + type

{ kind: "clone"; dir: string; origin: string | null; owned: boolean; } | { kind: "worktree"; dir: string; origin: string | null; owned: boolean; } | { kind: "moved_worktree"; entry: string; dir: string; origin: string | null; owned: boolean; blocked_by: { ...; } | ... 6 more ... | null; exit_noise: string | null; } ...

type { kind: "clone"; dir: string; origin: string | null; owned: boolean; } | { kind: "worktree"; dir: string; origin: string | null; owned: boolean; } | { kind: "moved_worktree"; entry: string; dir: string; origin: string | null; owned: boolean; blocked_by: { kind: "rewrites"; path: string; git_dir: string; } | { kind: "claimed_dir"; git_dir: string; } | { kind: "swapped"; git_dir: string; with: string; } | { kind: "relative_gitdir"; git_dir: string; } | { kind: "unreadable_gitdir"; git_dir: string; } | { kind: "non_utf8_path"; } | { kind: "nul_in_gitdir"; git_dir: string; } | null; exit_noise: string | null; } | { kind: "orphaned_worktree"; entry: string; dir: string; origin: string | null; owned: boolean; } | { kind: "shared_git_dir"; entry: string; dir: string; origin: string | null; with: string | null; owned: boolean; } | { kind: "unfinished_clone"; dir: string; origin: string | null; owned: boolean; }

import {ReposUnregisteredClone} from '@fuzdev/fuz_repos/repos_status.js';

A child of the workspace root holding a .git that no registry entry claims, its kind flattened beside its own fields.

ReposVerdict
#

repos_status.ts view source

value + type

{ kind: "quiet"; } | { kind: "act"; action: { kind: "push"; commits: number; } | { kind: "fast_forward"; commits: number; } | { kind: "move"; } | { kind: "rebase"; ahead: number; behind: number; }; } | { ...; } | { ...; } | { ...; } | { ...; }

type { kind: "quiet"; } | { kind: "act"; action: { kind: "push"; commits: number; } | { kind: "fast_forward"; commits: number; } | { kind: "move"; } | { kind: "rebase"; ahead: number; behind: number; }; } | { kind: "held"; by: "entry" | "pinned" | "push_url" | "fetch_failed" | "dirty_checkout" | "unprobed_worktree" | "several_checkouts" | "busy" | "busy_unknown" | "lfs_objects" | "lfs_unscanned"; action: { kind: "push"; commits: number; } | { kind: "fast_forward"; commits: number; } | { kind: "move"; } | { kind: "rebase"; ahead: number; behind: number; }; } | { kind: "needs_human"; reason: "diverged" | "diverged_published" | "diverged_merge" | "diverged_tagged" | "unmapped" | "archived_ahead" | "shallow_local_work" | "upstream_not_a_branch"; } | { kind: "local_only"; } | { kind: "cleanup"; reason: "merged" | "upstream_gone"; removable_worktree: string | null; }

import {ReposVerdict} from '@fuzdev/fuz_repos/repos_status.js';

What sync does about a branch.

ReposVisibility
#

repos_status.ts view source

value + type

"public" | "private"

type "public" | "private"

import {ReposVisibility} from '@fuzdev/fuz_repos/repos_status.js';

A repo's declared visibility on its host.

ReposVisibilityCheck
#

repos_status.ts view source

value + type

{ kind: "leak"; } | { kind: "private"; } | { failure: { kind: "ref_gone"; refname: string; fix: { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { ...; }; } | ... 6 more ... | { ...; }; kind: "unknown"; }

type { kind: "leak"; } | { kind: "private"; } | { failure: { kind: "ref_gone"; refname: string; fix: { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { kind: "by_hand"; }; } | { kind: "unreachable"; cause: "dns" | "connection" | "host_key" | "auth"; message: string; } | { kind: "repo_not_found"; message: string; } | { kind: "timed_out"; after_secs: number; } | { kind: "failed"; message: string; } | { kind: "refspec_outside_origin"; refspec: string; } | { kind: "origin_refs_shared"; refspec: string; remote: string; } | { kind: "legacy_remotes_unreadable"; path: string; }; kind: "unknown"; }

import {ReposVisibilityCheck} from '@fuzdev/fuz_repos/repos_status.js';

What an anonymous read of a repo declared private found.

required_bump_for_dependency_update
#

version_utils.ts view source

(current_version: string, has_breaking_deps: boolean): BumpType import {required_bump_for_dependency_update} from '@fuzdev/fuz_repos/version_utils.js';

The bump a package must take when one of its prod/peer dependencies updates. Pre-1.0: minor for a breaking dependency, otherwise patch. 1.0+: major for a breaking dependency, otherwise patch.

Single source of truth for the dependency-driven bump rule, shared by the plan (generate_publishing_plan) and the auto-changeset generator (calculate_required_bump) so the two never drift.

current_version

the package's current version, used to detect the pre-1.0 regime

type string

has_breaking_deps

whether any updated dependency is a breaking change

type boolean

returns

BumpType

resolve_gitops_repos
#

gitops_task_helpers.ts view source

(options: ResolveGitopsReposOptions): Promise<{ config_path: string; gitops_config: { repos: string[]; }; report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { ...; } | { ...; }; entries: { ...; }[]; unregistered: ({ ...; } | ... 4 more ... | { ...; })[] | null; }; local_repo_paths: LocalRepoPath[]; }> import {resolve_gitops_repos} from '@fuzdev/fuz_repos/gitops_task_helpers.js';

Resolves the gitops config's repos through repos status: loads the config's registry keys, reports on them, and resolves each to its checkout, in config order. Reads nothing but git state, and writes nothing but the remote-tracking refs a fetch refreshes.

options

returns

Promise<{ config_path: string; gitops_config: { repos: string[]; }; report: { version: 20; workspace: string; registry: string; fetched: boolean; sessions: { kind: "available"; unscoped: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { ...;...>

the config, the repos status report, and each repo's path and entry

throws

  • TaskError - if the config is missing, invalid, or lists no repos, `repos status` fails, or any configured repo is unknown, a reference, missing, not a repo, unprobed, or private under a public `host`

ResolveGitopsReposOptions
#

gitops_task_helpers.ts view source

ResolveGitopsReposOptions import type {ResolveGitopsReposOptions} from '@fuzdev/fuz_repos/gitops_task_helpers.js';

config

Path to the gitops config, absolute or relative to the cwd.

type string

registry?

A repos.toml to use instead of the one repos finds walking up from the cwd.

type string

fetch?

Fetch each repo from origin first (repos status --fetch), which writes remote-tracking refs and nothing else, so the report's relations to origin are current.

type boolean

host?

The package whose generated data the run writes; when it's public, a private repo in the config fails the resolve.

type { name: string; private: boolean; }

log?

type Logger

repos_ops?

type ReposOperations

route_human_output
#

output_helpers.ts view source

(log: Logger, machine: boolean): WriteStdout import {route_human_output} from '@fuzdev/fuz_repos/output_helpers.js';

Keeps a task's stdout for its machine-readable document or stream when machine is set: the logger's info and debug lines, which it writes with console.log, go where its errors go โ€” stderr โ€” and child loggers inherit that. Gro hands a task the logger its own lines go through, so gro's lines after the task runs (โœ“, the timings) follow to stderr; the two it prints before the task runs (invoking, โ†’ <task>) stay on stdout, out of the task's reach.

log

the task's logger

type Logger

machine

whether stdout carries a machine-readable document or stream

type boolean

returns

WriteStdout

writes to the stdout the logger wrote to before, for the document

mutates

  • log โ€” overrides its `console` when `machine` is set

spawn_capture
#

spawn_capture.ts view source

(program: SpawnProgram, args: readonly string[], options?: SpawnCallOptions | undefined): Promise<SpawnCaptured> import {spawn_capture} from '@fuzdev/fuz_repos/spawn_capture.js';

Runs program, capturing its stdout and stderr with stdin inherited. The inherited stream keeps the child in the terminal's session, so unlike SpawnProgram.out, /dev/tty still reaches ssh, a credential helper, or a pinentry. A process the program leaves running that still holds a pipe is cut off after a bounded wait, unreported, so its later output is lost.

program

type SpawnProgram

args

the arguments after argv[0]

type readonly string[]

options?

type SpawnCallOptions
optional

returns

Promise<SpawnCaptured>

throws

  • `SpawnError` - if the program can't start

SpawnCaptured
#

spawn_capture.ts view source

SpawnCaptured

type ({ readonly kind: "exited"; readonly code: number; } & { stdout: string; stderr: string; }) | ({ readonly kind: "signaled"; readonly signal: string; } & { stdout: string; stderr: string; }) | ({ readonly kind: "timed_out" | "aborted"; readonly code: number | null; readonly signal: string | null; } & { stdout: string; stderr: string; })

import type {SpawnCaptured} from '@fuzdev/fuz_repos/spawn_capture.js';

How a program ended and its output as UTF-8 text.

strip_version_prefix
#

version_utils.ts view source

(version: string): string import {strip_version_prefix} from '@fuzdev/fuz_repos/version_utils.js';

Strips version prefix (^, ~, >=, <=, etc) from a version string.

version

type string

returns

string

TablePage
#

to_dependency_type_label
#

publishing_plan_logging.ts view source

(type: "dependencies" | "devDependencies" | "peerDependencies"): "prod" | "peer" | "dev" import {to_dependency_type_label} from '@fuzdev/fuz_repos/publishing_plan_logging.js';

The short label of a dependency section: prod, peer, or dev.

type

type "dependencies" | "devDependencies" | "peerDependencies"

returns

"prod" | "peer" | "dev"

to_dependency_update_commit_message
#

dependency_updater.ts view source

(updates: Map<string, string>): string import {to_dependency_update_commit_message} from '@fuzdev/fuz_repos/dependency_updater.js';

The commit message for a dependency rewrite, naming each dependency and the version it moved to, so the history says what each of a cascade's commits did.

updates

type Map<string, string>

returns

string

examples

to_dependency_update_commit_message(new Map([['@fuzdev/fuz_util', '0.79.0']])) // 'update dependencies:

to_dependency_updates
#

publishing_plan_helpers.ts view source

(repo: LocalRepo, targets: ReadonlyMap<string, string>, changes: ReadonlyMap<string, VersionChange>, sections?: readonly ("dependencies" | "devDependencies" | "peerDependencies")[]): DependencyUpdate[] import {to_dependency_updates} from '@fuzdev/fuz_repos/publishing_plan_helpers.js';

The updates one package's dependency ranges need so each names its dependency's version after the release: targets maps every package to that version, its predicted one when it publishes and its current one otherwise. A range already naming it, or staged ahead of it, needs none (needs_update).

An update is breaking when the move from the range's base version is (to_range_update_bump), so a range lagging its dependency's last release counts what it skips; a range with no x.y.z base takes the dependency's own change's breaking flag.

repo

the dependent package

targets

every package's version after the release, by name

type ReadonlyMap<string, string>

changes

the version changes the release makes, by name

type ReadonlyMap<string, VersionChange>

sections?

the dependency sections to read

type readonly DependencySection[]
optional default DEPENDENCY_SECTIONS

returns

DependencyUpdate[]

to_dependency_version_changes
#

changeset_generator.ts view source

(updates: readonly DependencyUpdate[]): DependencyVersionChange[] import {to_dependency_version_changes} from '@fuzdev/fuz_repos/changeset_generator.js';

The auto-changeset lines for a dependent's prod/peer dependency updates, one per dependency: from the range's base version to the new one, with the bump and breaking flag the move amounts to. A range with no x.y.z base (a wildcard) counts as a patch.

updates

type readonly DependencyUpdate[]

returns

DependencyVersionChange[]

to_pull_requests
#

to_pull_url
#

github_helpers.ts view source

(repo_url: string, pull: { number: number; title: string; user: { login: string; }; draft: boolean; }): string import {to_pull_url} from '@fuzdev/fuz_repos/github_helpers.js';

repo_url

type string

pull

returns

string

to_range_update_bump
#

version_utils.ts view source

(current: string, new_version: string): { bump_type: BumpType; breaking: boolean; } | null import {to_range_update_bump} from '@fuzdev/fuz_repos/version_utils.js';

The bump a dependency range's move to new_version amounts to, measured from the range's base version, and whether that's breaking โ€” so a range lagging behind its dependency's last release counts what it skips.

current

type string

new_version

type string

returns

{ bump_type: BumpType; breaking: boolean; } | null

the bump, or null when the range has no x.y.z base (a wildcard, a compound range)

examples

to_range_update_bump('^0.54.0', '0.55.1') // {bump_type: 'minor', breaking: true}

to_rank
#

dependency_graph.ts view source

(names: Iterable<string>): Map<string, number> import {to_rank} from '@fuzdev/fuz_repos/dependency_graph.js';

Each name's position in names, for group_into_levels's rank.

names

type Iterable<string, any, any>

returns

Map<string, number>

to_release_state
#

release_state.ts view source

(options: ToReleaseStateOptions): ReleaseState import {to_release_state} from '@fuzdev/fuz_repos/release_state.js';

Derives the release step from the plan and each repo's readiness.

options

returns

ReleaseState

to_repos_command
#

repos_status_load.ts view source

(registry: string | undefined): string import {to_repos_command} from '@fuzdev/fuz_repos/repos_status_load.js';

The repos invocation a suggested fix names: repos, or `repos --registry <path>` when the run passed one, the path POSIX-shell-quoted when it needs it.

registry

the run's --registry, if any

type string | undefined

returns

string

the command prefix, ready for a subcommand

to_updated_range
#

version_utils.ts view source

(current: string, version: string, strategy?: VersionStrategy): string import {to_updated_range} from '@fuzdev/fuz_repos/version_utils.js';

The range a dependency entry is rewritten to when version publishes: the current range's prefix kept (see get_update_prefix), else the strategy's. The release step writes it and the plan shows it, so the two agree.

current

type string

version

type string

strategy?

optional default 'caret'

returns

string

examples

to_updated_range('>=0.78.0', '0.79.0') // '>=0.79.0'

to_version_strategy_prefix
#

version_utils.ts view source

(strategy: VersionStrategy): "" | "^" | "~" | ">=" import {to_version_strategy_prefix} from '@fuzdev/fuz_repos/version_utils.js';

strategy

returns

"" | "^" | "~" | ">="

ToReleaseStateOptions
#

release_state.ts view source

ToReleaseStateOptions import type {ToReleaseStateOptions} from '@fuzdev/fuz_repos/release_state.js';

plan

The plan, generated with registry observations.

type PublishingPlan

repos

The configured npm repos, as loaded.

type readonly LocalRepo[]

not_ready

Why each repo isn't ready to be written or published, by package name: a repo absent or with no reasons is ready. Its dependents are held with it.

type ReadonlyMap<string, readonly string[]>

held_all?

Problems with the whole report, which hold every repo.

type readonly string[]

TreeItemPage
#

TreePage
#

update_package_json
#

dependency_updater.ts view source

(repo: LocalRepo, updates: readonly DependencyUpdate[], options?: UpdatePackageJsonOptions): Promise<void> import {update_package_json} from '@fuzdev/fuz_repos/dependency_updater.js';

Rewrites one dependent's package.json for its dependency updates and commits it, with its auto-changeset when it republishes.

Workflow:

  1. Rewrites each updated name in every section that lists it (dependencies, devDependencies, peerDependencies), so a package that is both a peer and a dev dependency moves in one commit
  2. Writes updated package.json in the indentation it was read with, so the rewrite moves only the ranges (npm also takes its lockfile's indentation from it)
  3. With changeset, writes the dependent's one auto-changeset for its prod/peer updates, merging into it when an earlier rewrite wrote it (write_dependency_updates_changeset)
  4. Commits both package.json and changeset, the message naming each updated version

Each range keeps its existing prefix, else takes the strategy's (to_updated_range). When no entry's value changes โ€” every range already names its version โ€” it writes, creates, and commits nothing, or throws under changeset.

repo

the dependent

updates

its dependency updates, all naming repo as the dependent

type readonly DependencyUpdate[]

options?

optional default {}

returns

Promise<void>

throws

  • Error - if file operations or git operations fail, or if nothing changes for a republishing dependent (`changeset`), whose changeset would go missing

UpdatePackageJsonOptions
#

dependency_updater.ts view source

UpdatePackageJsonOptions import type {UpdatePackageJsonOptions} from '@fuzdev/fuz_repos/dependency_updater.js';

strategy?

type VersionStrategy

changeset?

Whether the dependent republishes, so its prod/peer updates go in its auto-changeset. A dev-only rewrite or a private dependent takes none.

type boolean

log?

type Logger

git_ops?

type GitOperations

fs_ops?

type FsOperations

validate_dependency_graph
#

graph_validation.ts view source

(repos: LocalRepo[]): GraphValidationResult import {validate_dependency_graph} from '@fuzdev/fuz_repos/graph_validation.js';

Builds the dependency graph, detects cycles, and computes the topological order and its levels (prod/peer dependencies only, so dev cycles don't block them).

Never throws on cycles: a production/peer cycle leaves order and levels empty and sets sort_error, and the caller reports it.

repos

type LocalRepo[]

returns

GraphValidationResult

the graph, order, levels, and detected cycles

validate_gitops_config_module
#

gitops_config.ts view source

(config_module: any, config_path: string): asserts config_module is GitopsConfigModule import {validate_gitops_config_module} from '@fuzdev/fuz_repos/gitops_config.js';

config_module

type any

config_path

type string

returns

void

VerboseChangesetDetail
#

publishing_plan.ts view source

VerboseChangesetDetail import type {VerboseChangesetDetail} from '@fuzdev/fuz_repos/publishing_plan.js';

package_name

type string

files

type { filename: string; bump_type: BumpType; summary: string; }[]

VerboseData
#

VerboseGraphSummary
#

publishing_plan.ts view source

VerboseGraphSummary import type {VerboseGraphSummary} from '@fuzdev/fuz_repos/publishing_plan.js';

package_count

type number

internal_dep_count

type number

prod_peer_edges

type { from: string; to: string; type: "prod" | "peer"; }[]

dev_edges

type { from: string; to: string; }[]

prod_cycle_count

type number

dev_cycle_count

type number

VerbosePropagation
#

publishing_plan.ts view source

VerbosePropagation import type {VerbosePropagation} from '@fuzdev/fuz_repos/publishing_plan.js';

A breaking package and the direct prod/peer dependents its release rewrites.

source

type string

dependents

type { pkg: string; dep_type: "prod" | "peer"; action: string; }[]

version_change_kind
#

publishing_plan.ts view source

(change: VersionChange): VersionChangeKind import {version_change_kind} from '@fuzdev/fuz_repos/publishing_plan.js';

Classifies a version change โ€” the one classification the plan's logger, markdown, and release step share. A change without changesets of its own is auto even if its bump was raised.

change

returns

VersionChangeKind

VersionChange
#

publishing_plan.ts view source

VersionChange import type {VersionChange} from '@fuzdev/fuz_repos/publishing_plan.js';

package_name

type string

from

type string

to

type string

bump_type

type BumpType

breaking

type boolean

has_changesets

type boolean

will_generate_changeset?

type boolean

needs_bump_escalation?

type boolean

existing_bump?

type BumpType

required_bump?

type BumpType

VersionChangeKind
#

publishing_plan.ts view source

VersionChangeKind

type "explicit" | "escalation" | "auto"

import type {VersionChangeKind} from '@fuzdev/fuz_repos/publishing_plan.js';

How a version change arises in the plan: from the package's own changesets (explicit), from its changesets with the bump raised to what a breaking dependency requires (escalation), or from a changeset generated for a dependency update (auto).

VersionStrategy
#

version_utils.ts view source

VersionStrategy

type "exact" | "caret" | "tilde" | "gte"

import type {VersionStrategy} from '@fuzdev/fuz_repos/version_utils.js';

How a rewritten range is prefixed when the current one has no prefix of its own (an existing prefix is always kept).

wait_for_package
#

npm_registry.ts view source

(pkg: string, version: string, options: WaitOptions, deps: NpmRegistryDeps): Promise<void> import {wait_for_package} from '@fuzdev/fuz_repos/npm_registry.js';

Waits for package version to propagate to NPM registry.

Uses exponential backoff with jitter to avoid hammering registry. Logs progress every 5 attempts. Respects timeout to avoid infinite waits.

Critical for multi-repo publishing: ensures published packages are available before updating dependent packages.

pkg

type string

version

type string

options

deps

returns

Promise<void>

throws

  • Error - if timeout reached or max attempts exceeded

WaitOptions
#

npm_registry.ts view source

WaitOptions import type {WaitOptions} from '@fuzdev/fuz_repos/npm_registry.js';

log?

type Logger

max_attempts?

type number

initial_delay?

type number

max_delay?

type number

timeout?

type number

write_dependency_updates_changeset
#

changeset_generator.ts view source

(repo: LocalRepo, updates: DependencyVersionChange[], options?: { log?: Logger | undefined; fs_ops?: FsOperations | undefined; }): Promise<...> import {write_dependency_updates_changeset} from '@fuzdev/fuz_repos/changeset_generator.js';

Writes the dependent's auto-generated changeset, merging updates into the one it already has: an earlier step of the release wrote it when another dependency was rewritten. A dependency listed in both keeps its earliest from_version and takes the latest to_version; the bump is recomputed over the merged list, never below the file's own.

repo

updates

options?

type { log?: Logger | undefined; fs_ops?: FsOperations | undefined; }
optional default {}

returns

Promise<string>

the changeset's path

throws

  • Error - if a file at that name isn't an auto-generated dependency changeset, or on fs failure

WriteStdout
#

output_helpers.ts view source

WriteStdout import type {WriteStdout} from '@fuzdev/fuz_repos/output_helpers.js';

Writes one machine-readable document, or one line of a stream, to stdout, ending it with a newline.

(call)

type (content: string): void

content

type string
returns void