api #

a tool for managing many repos

54 modules ยท 264 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

BuildOperations
#

operations.ts view source

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

Build operations for validating packages compile before publishing.

build_package

Builds a package using gro build.

type (options: { repo: LocalRepo; }): Promise<Result<object, { message: string; output?: string | undefined; }>>

options

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

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: LocalRepo[], predicted_versions: Map<string, string>, breaking_packages: Set<string>): { dependency_updates: DependencyUpdate[]; breaking_cascades: Map<...>; } import {calculate_dependency_updates} from '@fuzdev/fuz_repos/publishing_plan_helpers.js';

Calculates all dependency updates between packages based on predicted versions.

Iterates through all repos, checking prod, peer, and dev dependencies to find which packages will need dependency version bumps after publishing.

Also tracks "breaking cascades" - when a breaking change propagates to dependents.

repos

type LocalRepo[]

predicted_versions

type Map<string, string>

breaking_packages

type Set<string>

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

capture_handler
#

publishing_event_handler.ts view source

(): CapturingEventHandler import {capture_handler} from '@fuzdev/fuz_repos/publishing_event_handler.js';

Collects events in memory. Used to build the run report and in tests.

returns

CapturingEventHandler

CapturingEventHandler
#

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: 18; 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: 18; 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; }
default {}

deps

default default_npm_registry_deps

returns

Promise<boolean>

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

check_publish_readiness
#

repo_readiness.ts view source

(options: { report: { version: 18; 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): Result<...> import {check_publish_readiness} from '@fuzdev/fuz_repos/repo_readiness.js';

Checks a repos status --fetch --json report on the repos a real publish reads and writes: every 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.

options

type { report: { version: 18; 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

ahead, the ready repos whose followed branch is ahead of origin; and on failure a message naming each repo, what's wrong, and the fix, its lines, and every not-ready repo

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

create_changeset_for_dependency_updates
#

changeset_generator.ts view source

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

Creates a changeset file for dependency updates. Returns the path to the created changeset file.

repo

updates

options

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

returns

Promise<string>

create_dependency_updates
#

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
default join(paths.build, 'fetch')

returns

Promise<FetchCache>

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

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>

decide_publish_gate
#

publish_gate.ts view source

(options: PublishGateOptions): PublishGate import {decide_publish_gate} from '@fuzdev/fuz_repos/publish_gate.js';

Decides whether a publish run must block, prompt for confirmation, or proceed without prompting, from the pre-execution inputs.

  • blocked: a real publish whose plan has errors โ€” fail loud before prompting. The executor enforces this too, so --no-plan can't bypass the gate; this branch only avoids prompting for (and printing the "this will publish" banner of) a plan that can't run.
  • confirm: a real publish that shows its plan โ€” the user must confirm interactively.
  • proceed: a dry run, or a --no-plan real publish โ€” no prompt.

options

returns

PublishGate

default_build_operations
#

default_changeset_operations
#

default_fs_operations
#

default_git_operations
#

default_gitops_operations
#

operations_defaults.ts view source

GitopsOperations import {default_gitops_operations} from '@fuzdev/fuz_repos/operations_defaults.js';

Combined default operations for all gitops functionality.

default_npm_operations
#

default_npm_registry_deps
#

default_preflight_operations
#

default_process_operations
#

default_repos_operations
#

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';

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
default false
returns string[]

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

throws

  • Error - if circular dependencies detected in included dependency types

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>

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';

dependent_package

type string

updated_dependency

type string

current_version

type string

new_version

type string

type

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

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

derive_publish_steps
#

publish_steps.ts view source

(plan: PublishingPlan, options?: DerivePublishStepsOptions): PublishStep[] import {derive_publish_steps} from '@fuzdev/fuz_repos/publish_steps.js';

Derives the ordered side-effects a wetrun would perform from a frozen plan.

Reads only publishing_order, version_changes, and dependency_updates โ€” the same data execute_publishing_plan consumes, in the same order โ€” so the preview reflects the real pass. A dependency is only propagated to its dependents if it actually publishes this run.

plan

options

default {}

returns

PublishStep[]

DerivePublishStepsOptions
#

publish_steps.ts view source

DerivePublishStepsOptions import type {DerivePublishStepsOptions} from '@fuzdev/fuz_repos/publish_steps.js';

deploy?

Include the deploy phase (the publisher only deploys with --deploy).

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

execute_publishing_plan
#

multi_repo_publisher.ts view source

(all_repos: LocalRepo[], plan: PublishingPlan, options: PublishingOptions): Promise<PublishingResult> import {execute_publishing_plan} from '@fuzdev/fuz_repos/multi_repo_publisher.js';

Executes a frozen publishing plan in a single linear pass โ€” the "dumb executor" half of the zap model. The plan is the single source of truth; this re-derives nothing.

Fails loud when the plan couldn't be fully computed (plan.errors): a wetrun aborts before any side effect, a dry run still reports the partial cascade but returns ok: false. This is the single error gate โ€” --no-plan can't bypass it.

all_repos

type LocalRepo[]

plan

options

returns

Promise<PublishingResult>

fetch_github_check_runs
#

github.ts view source

(repo_info: GithubRepoInfo, options?: { cache?: Map<string, { key: string; url: string; params: any; value: any; etag: string | null; last_modified: string | null; }> | undefined; ... 4 more ...; fetch?: { ...; } | undefined; }): 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?: Map<string, { key: string; url: string; params: any; value: any; etag: string | null; last_modified: string | null; }> | undefined; log?: Logger | undefined; token?: string | undefined; api_version?: string | undefined; ref?: string | undefined; fetch?: { ...; } | undefined; }
default {}

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?: Map<string, { key: string; url: string; params: any; value: any; etag: string | null; last_modified: string | null; }> | undefined; log?: Logger | undefined; token?: string | undefined; api_version?: string | undefined; fetch?: { ...; } | undefined; }): Promise<...> import {fetch_github_pull_requests} from '@fuzdev/fuz_repos/github.js';

repo_info

options

type { cache?: Map<string, { key: string; url: string; params: any; value: any; etag: string | null; last_modified: string | null; }> | undefined; log?: Logger | undefined; token?: string | undefined; api_version?: string | undefined; fetch?: { ...; } | undefined; }
default {}

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 Map<string, { key: string; url: string; params: any; value: any; etag: string | null; last_modified: string | null; }>

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 Map<string, { key: string; url: string; params: any; value: any; etag: string | null; last_modified: string | null; }>

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. Defaults to globalThis.fetch.

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

find_updates_needed
#

dependency_updater.ts view source

(repo: LocalRepo, published: Map<string, string>): Map<string, { current: string; new: string; type: "dependencies" | "devDependencies" | "peerDependencies"; }> import {find_updates_needed} from '@fuzdev/fuz_repos/dependency_updater.js';

repo

published

type Map<string, string>

returns

Map<string, { current: string; new: string; type: "dependencies" | "devDependencies" | "peerDependencies"; }>

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_publish_steps
#

publish_steps.ts view source

(steps: PublishStep[]): string[] import {format_publish_steps} from '@fuzdev/fuz_repos/publish_steps.js';

Formats steps as human-readable lines (one per step) for stdout and markdown output. Returns a single placeholder line when there are no side effects.

steps

returns

string[]

format_readiness_ahead
#

repo_readiness.ts view source

(ahead: ReadinessAhead, publishes: boolean, options?: RepoReadinessFormatOptions): string import {format_readiness_ahead} from '@fuzdev/fuz_repos/repo_readiness.js';

Says what happens to a ready repo's commits ahead of origin: its release push carries them when it publishes, else they stay unpushed.

ahead

the repo, its branch, and how many commits it's ahead

publishes

whether the plan publishes it

type boolean

options

the repos invocation the message names

default {}

returns

string

the line to log

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

default {}

returns

{ what: string; fix: string; }

what's wrong, and the fix

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[]

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. See @fuzdev/fuz_util/fs.ts.

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>

gate_publish_readiness
#

gitops_task_helpers.ts view source

(options: GatePublishReadinessOptions): Promise<void> import {gate_publish_readiness} from '@fuzdev/fuz_repos/gitops_task_helpers.js';

The readiness gate gitops_publish --wetrun runs before its confirmation prompt: fetches every npm repo from origin (`repos status <keysโ€ฆ> --fetch --json`, which writes remote-tracking refs and nothing else) and refuses unless each is ready (check_publish_readiness) โ€” on its registry branch, clean, idle, in sync with origin or ahead of it, fetched without error, no other live session in its checkout, and nothing left to a person. Each ready repo ahead of origin is logged, saying whether its release push carries those commits or they stay unpushed.

Every npm repo, not just those the plan publishes or rewrites: the plan reads each one's working tree (changesets, versions, dependency ranges), so a repo off its branch or behind origin can hide a changeset and leave the plan wrong about what to publish. Changes nothing.

options

the loaded repos, the --registry if any, the package names the plan publishes, a logger, and the repos runner

returns

Promise<void>

throws

  • TaskError - if `repos status` fails or any npm repo isn't ready, naming each problem and its fix

GatePublishReadinessOptions
#

gitops_task_helpers.ts view source

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

local_repos

The loaded repos; the npm ones are gated.

type readonly LocalRepo[]

registry?

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

type string

publishing?

The package names the plan publishes, to say whether a repo's commits ahead of origin go out with its release or stay unpushed.

type ReadonlySet<string>

log?

type Logger

repos_ops?

type ReposOperations

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 a publishing plan showing what would happen during publishing. Shows version changes, dependency updates, and breaking change cascades. Uses fixed-point iteration to resolve transitive cascades.

all_repos

type LocalRepo[]

options

default {}

returns

Promise<PublishingPlan>

GeneratePlanOptions
#

get_gitops_ready
#

gitops_task_helpers.ts view source

(options: ResolveGitopsReposOptions): Promise<{ local_repos: LocalRepo[]; }> import {get_gitops_ready} from '@fuzdev/fuz_repos/gitops_task_helpers.js';

Central initialization function for the gitops tasks that load libraries: resolves the config's repos through repos status (resolve_gitops_repos), then loads each repo's library as its working tree sits (local_repos_load). Moves no ref; gro caches each library at .gro/library.json in its repo, at a clean commit.

options

returns

Promise<{ local_repos: LocalRepo[]; }>

the loaded repos, in config order

throws

  • TaskError - if resolving the repos or loading them fails

get_required_bump_for_dependencies
#

publishing_plan_helpers.ts view source

(repo: LocalRepo, dependency_updates: DependencyUpdate[], breaking_packages: Set<string>): BumpType | null import {get_required_bump_for_dependencies} from '@fuzdev/fuz_repos/publishing_plan_helpers.js';

Determines the required bump type for a package based on its dependency updates.

Returns null if no prod/peer dependency updates, otherwise returns the minimum required bump type (major for breaking deps, patch otherwise).

Respects pre-1.0 semver conventions (minor for breaking in 0.x).

repo

dependency_updates

breaking_packages

type Set<string>

returns

BumpType | null

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 "" | "^" | "~" | ">="
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

(files: string | string[], options?: SpawnOptions | 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.

files

type string | string[]

options?

type SpawnOptions
optional

returns

Promise<void>

git_commit
#

git_operations.ts view source

(message: string, files: string[], options?: SpawnOptions | 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.

message

type string

files

type string[]

options?

type SpawnOptions
optional

returns

Promise<void>

git_current_commit_hash_required
#

git_operations.ts view source

(options?: SpawnOptions | undefined): Promise<string> import {git_current_commit_hash_required} from '@fuzdev/fuz_repos/git_operations.js';

Wrapper for gro's git_current_commit_hash that reads HEAD and throws if null.

options?

type SpawnOptions
optional

returns

Promise<string>

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 publishing executor authors with: staging and committing dependency updates and auto-changesets, and reading the commit it published. All operations return Result instead of throwing errors. Where each repo sits (branch, dirt, relation to origin) is ReposOperations's to report.

current_commit_hash

Gets the current commit hash.

type (options?: { cwd?: string | undefined; } | undefined): Promise<Result<{ value: string; }, { message: string; }>>

options?

type { cwd?: string | undefined; }
optional
returns Promise<Result>

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 { key: string; kind: "repo" | "reference"; dir: string; url: string; writable: boolean; archived: boolean; visibility: "public" | "private" | null; ci: boolean; branch: string | null; pinned: boolean; ... 13 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_MAX_ITERATIONS_DEFAULT
#

gitops_constants.ts view source

10 import {GITOPS_MAX_ITERATIONS_DEFAULT} from '@fuzdev/fuz_repos/gitops_constants.js';

Maximum number of fixed-point iterations plan generation runs to resolve transitive dependency cascades. Publishing executes the frozen plan in a single pass and doesn't iterate.

Each iteration reaches at least one more level of dependents, so a deep dependency chain needs more; a plan that hits the limit still changing warns, naming the packages left.

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 waiting on NPM package propagation (10 minutes). NPM's CDN uses eventual consistency, so published packages may not be immediately available.

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
#

GitopsOperations
#

operations.ts view source

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

Combined operations interface grouping all gitops functionality. This is the main interface injected into publishing and validation workflows.

changeset

type ChangesetOperations

git

type GitOperations

process

type ProcessOperations

npm

type NpmOperations

preflight

type PreflightOperations

fs

type FsOperations

build

type BuildOperations

repos

repos status, for the executor's re-check of each repo right before its publish.

type ReposOperations

GraphValidationResult
#

graph_validation.ts view source

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

graph

type DependencyGraph

publishing_order

type string[]

production_cycles

type string[][]

dev_cycles

type string[][]

sort_error?

Why the topological sort failed, when it did; publishing_order is then empty.

type string

group_dependency_updates
#

multi_repo_publisher.ts view source

(updates: DependencyUpdate[], published: Map<string, PublishedVersion>, predicate: (update: DependencyUpdate) => boolean): Map<...> import {group_dependency_updates} from '@fuzdev/fuz_repos/multi_repo_publisher.js';

Groups dependency updates by dependent package โ€” `dependent โ†’ (dependency โ†’ new version), the shape update_package_json consumes. Restricted by predicate` (e.g. prod/peer for a given package, or all dev deps) and to dependencies that actually published this run, so a failed/aborted publish never propagates to its dependents.

updates

published

type Map<string, PublishedVersion>

predicate

type (update: DependencyUpdate) => boolean

returns

Map<string, Map<string, string>>

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 preflight checks and publishing workflow 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: 18; 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

({ local_repo_path, log }: { local_repo_path: LocalRepoPath; log?: Logger | undefined; }): 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; gro caches the library at .gro/library.json in the repo, at a clean commit.

  1. Loads library_json via library_load_from_repo (svelte-docinfo analysis)
  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.

__0

type { local_repo_path: LocalRepoPath; log?: Logger | undefined; }

returns

Promise<LocalRepo>

throws

  • TaskError - if the analysis fails

local_repos_load
#

local_repo.ts view source

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

__0

type { local_repo_paths: LocalRepoPath[]; log?: Logger | undefined; parallel?: boolean | undefined; concurrency?: number | undefined; }

returns

Promise<LocalRepo[]>

local_repos_resolve
#

local_repo.ts view source

(options: { keys: readonly string[]; report: { version: 18; 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: 18; 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>

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
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
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
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, publishing order, version changes grouped by scenario, dependency-only updates, warnings, and a summary.

plan

log

type Logger

options

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
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
default ''

returns

void

LogPlanOptions
#

mask_secrets
#

publishing_event_handler.ts view source

(event: { event: "run_started"; wetrun: boolean; total: number; } | { event: "package_skipped"; name: string; reason: string; } | { event: "package_completed"; name: string; old_version: string; new_version: string; bump_type: "major" | ... 1 more ... | "patch"; breaking: boolean; commit: string; tag: string; } | ... 6 more ... | { ...; }): { ...; } | ... 8 more ... | { ...; } import {mask_secrets} from '@fuzdev/fuz_repos/publishing_event_handler.js';

Returns a copy of the event with secrets redacted from its string-valued fields.

event

returns

PublishingEvent

masking_handler
#

publishing_event_handler.ts view source

(inner: PublishingEventHandler): PublishingEventHandler import {masking_handler} from '@fuzdev/fuz_repos/publishing_event_handler.js';

Wraps a handler, masking secrets in each event's string fields (mask_secrets) before forwarding.

inner

the handler to forward masked events to

returns

PublishingEventHandler

ModulesDetail
#

ModulesNav
#

ModulesNav.svelte view source

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

repos_modules

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

ModulesPage
#

multi_handler
#

needs_update
#

version_utils.ts view source

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

current

type string

new_version

type string

returns

boolean

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';

NPM registry operations for package availability checks and authentication. Includes exponential backoff for waiting on package propagation.

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>

check_auth

Checks npm authentication status.

type (): Promise<Result<{ username: string; }, { message: string; }>>

returns Promise<Result>

check_registry

Checks if npm registry is reachable.

type (): Promise<Result<object, { message: string; }>>

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

output_tail
#

operations_defaults.ts view source

(text: string, max_lines?: number, max_chars?: number): string import {output_tail} from '@fuzdev/fuz_repos/operations_defaults.js';

The end of a process's output, for a failure message: its last lines, then its last characters, with terminal escape sequences stripped and trailing whitespace trimmed.

text

the output, or as much of its end as was kept

type string

max_lines

the most lines to keep

type number
default OUTPUT_TAIL_MAX_LINES

max_chars

the most characters to keep, applied after max_lines

type number
default OUTPUT_TAIL_MAX_CHARS

returns

string

OUTPUT_TAIL_MAX_CHARS
#

operations_defaults.ts view source

4096 import {OUTPUT_TAIL_MAX_CHARS} from '@fuzdev/fuz_repos/operations_defaults.js';

The most characters of a child's stderr a failure carries.

OUTPUT_TAIL_MAX_LINES
#

operations_defaults.ts view source

20 import {OUTPUT_TAIL_MAX_LINES} from '@fuzdev/fuz_repos/operations_defaults.js';

The most lines of a child's stderr a failure carries.

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
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_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: 18; 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

PreflightOperations
#

operations.ts view source

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

Preflight validation operations run before publishing: building every package the plan publishes, and npm authentication. Repo git state is the readiness gate's, before preflight (see repo_readiness.ts).

run_preflight_checks

Runs preflight validation checks before publishing.

type (options: RunPreflightChecksOptions): Promise<PreflightResult>

options

returns Promise<PreflightResult>

PreflightResult
#

preflight_checks.ts view source

PreflightResult import type {PreflightResult} from '@fuzdev/fuz_repos/preflight_checks.js';

ok

type boolean

warnings

type string[]

errors

type string[]

ProcessOperations
#

operations.ts view source

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

Process operations for the commands the publishing executor runs in a repo (gro publish, gro deploy).

run_interactive

Runs a command in the foreground and waits for it to exit: stdin is the terminal's, so a prompt (npm's 2FA one-time password) can be answered, and the child's output shows live โ€” its stdout on ours, or on our stderr when stdout says so, and its stderr on ours. A failure carries the end of what the child wrote to stderr, bounded in lines and characters.

type (options: { cmd: string; args: string[]; cwd?: string | undefined; stdout?: "stdout" | "stderr" | undefined; }): Promise<Result<object, { message: string; stderr_tail?: string | undefined; }>>

options

type { cmd: string; args: string[]; cwd?: string | undefined; stdout?: "stdout" | "stderr" | undefined; }
returns Promise<Result>

publish_repos
#

publish_run_failed
#

publish_gate.ts view source

(result: Pick<PublishingResult, "ok">, fatal_error: Error | null): boolean import {publish_run_failed} from '@fuzdev/fuz_repos/publish_gate.js';

Whether a finished run should exit non-zero: an unsuccessful result, or a fatal error thrown out of the executor.

result

type Pick<PublishingResult, "ok">

fatal_error

type Error | null

returns

boolean

PublishedVersion
#

multi_repo_publisher.ts view source

PublishedVersion import type {PublishedVersion} from '@fuzdev/fuz_repos/multi_repo_publisher.js';

name

type string

old_version

type string

new_version

type string

bump_type

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

breaking

type boolean

commit

type string

tag

type string

PublishGate
#

publish_gate.ts view source

PublishGate

type { action: "blocked"; message: string; } | { action: "confirm"; } | { action: "proceed"; }

import type {PublishGate} from '@fuzdev/fuz_repos/publish_gate.js';

What the task should do with a generated plan before executing the cascade.

PublishGateOptions
#

publish_gate.ts view source

PublishGateOptions import type {PublishGateOptions} from '@fuzdev/fuz_repos/publish_gate.js';

wetrun

A real publish (--wetrun); a dry run never prompts.

type boolean

show_plan

Show the plan and confirm (plan); --no-plan skips the prompt.

type boolean

plan

type Pick<PublishingPlan, "errors">

PublishingErrorCode
#

publishing_event.ts view source

value + type

"publish" | "network" | "drift" | "not_ready"

type "publish" | "network" | "drift" | "not_ready"

import {PublishingErrorCode} from '@fuzdev/fuz_repos/publishing_event.js';

Coarse triage classification for a failed package. Lets consumers branch on failure kind without parsing the message.

PublishingEvent
#

publishing_event.ts view source

value + type

{ event: "run_started"; wetrun: boolean; total: number; } | { event: "package_skipped"; name: string; reason: string; } | { event: "package_completed"; name: string; old_version: string; new_version: string; bump_type: "major" | ... 1 more ... | "patch"; breaking: boolean; commit: string; tag: string; } | ... 6 more...

type { event: "run_started"; wetrun: boolean; total: number; } | { event: "package_skipped"; name: string; reason: string; } | { event: "package_completed"; name: string; old_version: string; new_version: string; bump_type: "major" | "minor" | "patch"; breaking: boolean; commit: string; tag: string; } | { event: "npm_waited"; name: string; version: string; } | { event: "package_failed"; name: string; error: string; code: "publish" | "network" | "drift" | "not_ready"; } | { event: "dependency_updated"; dependent: string; dependency: string; version: string; dep_type: "prod" | "peer" | "dev"; creates_changeset: boolean; } | { event: "deploy_started"; name: string; } | { event: "deploy_completed"; name: string; } | { event: "deploy_failed"; name: string; error: string; } | { event: "run_finished"; summary: { total: number; published: number; failed: number; skipped: number; duration: number; }; }

import {PublishingEvent} from '@fuzdev/fuz_repos/publishing_event.js';

A single structured event emitted during a publishing run. Tagged on event so the union serializes as one self-describing JSON object per event (JSON-lines on the wire).

PublishingEventHandler
#

publishing_event_handler.ts view source

PublishingEventHandler import type {PublishingEventHandler} from '@fuzdev/fuz_repos/publishing_event_handler.js';

A sink for publishing events.

emit

type (event: { event: "run_started"; wetrun: boolean; total: number; } | { event: "package_skipped"; name: string; reason: string; } | { event: "package_completed"; name: string; old_version: string; new_version: string; bump_type: "major" | ... 1 more ... | "patch"; breaking: boolean; commit: string; tag: string; } | ... 6 more ... | { ...; }): void

event

returns void

PublishingOptions
#

multi_repo_publisher.ts view source

PublishingOptions import type {PublishingOptions} from '@fuzdev/fuz_repos/multi_repo_publisher.js';

wetrun

type boolean

version_strategy?

type VersionStrategy

deploy?

type boolean

max_wait?

type number

log?

type Logger

ops?

type GitopsOperations

registry?

A repos.toml for the per-repo readiness re-check, when repos wouldn't find it from the cwd.

type string

events?

Structured event sink; defaults to capture-only (events surface on the result).

type PublishingEventHandler

child_stdout?

Where gro publish and gro deploy show their stdout: ours, or our stderr when our stdout carries a machine-readable stream (--emit_json, or a JSON or markdown report written to stdout).

type "stdout" | "stderr"

default 'stdout'

PublishingPlan
#

publishing_plan.ts view source

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

publishing_order

type string[]

version_changes

type VersionChange[]

dependency_updates

type DependencyUpdate[]

breaking_cascades

type Map<string, 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

PublishingResult
#

multi_repo_publisher.ts view source

PublishingResult import type {PublishingResult} from '@fuzdev/fuz_repos/multi_repo_publisher.js';

ok

type boolean

published

type PublishedVersion[]

failed

type { name: string; error: Error; }[]

duration

type number

events

The structured event stream for this run, in emission order.

type PublishingEvent[]

summary

Tallied outcome, derived from events.

type PublishingRunSummary

plan_errors

Plan errors that blocked (wetrun) or would block (dry run) publishing; empty when clean.

type string[]

plan_warnings

Non-blocking plan warnings (e.g. the fixed-point iteration limit).

type string[]

PublishingRunSummary
#

publishing_event.ts view source

value + type

{ total: number; published: number; failed: number; skipped: number; duration: number; } import {PublishingRunSummary} from '@fuzdev/fuz_repos/publishing_event.js';

Tallied outcome of a publishing run, derived from its events via summarize_events.

total

type number

published

type number

failed

type number

skipped

type number

duration

type number

PublishStep
#

publish_steps.ts view source

PublishStep

type { kind: "publish"; repo: string; from: string; to: string; bump: BumpType; via: VersionChangeKind; } | { kind: "npm_wait"; repo: string; version: string; } | { kind: "dependency_update"; dependent: string; dependency: string; to: string; dep_type: "prod" | "peer"; creates_changeset: boolean; } | { kind: "dev_dep_update"; repo: string; dependency: string; to: string; } | { kind: "deploy"; repo: string; builds: boolean; }

import type {PublishStep} from '@fuzdev/fuz_repos/publish_steps.js';

One ordered side-effect a wetrun would perform.

PullRequestMeta
#

PullRequestsDetail
#

PullRequestsPage
#

read_changesets
#

ReadinessAhead
#

repo_readiness.ts view source

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

A ready repo whose followed branch is ahead of origin: commits a publish pushes.

key

type string

branch

type string

commits

type number

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

redact_secrets
#

publishing_event_handler.ts view source

(text: string): string import {redact_secrets} from '@fuzdev/fuz_repos/publishing_event_handler.js';

Redacts known secret shapes from a string.

text

type string

returns

string

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: { key: string; kind: "repo" | "reference"; dir: string; url: string; writable: boolean; archived: boolean; visibility: "public" | "private" | null; ci: boolean; branch: string | null; pinned: boolean; ... 13 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: { key: string; kind: "repo" | "reference"; dir: string; url: string; writable: boolean; archived: boolean; visibility: "public" | "private" | null; ci: boolean; branch: string | null; pinned: boolean; ... 13 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; }
default {}

returns

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

the problems that refuse, and those that warn

repo_readiness_for_publish
#

repo_readiness.ts view source

(entry: { key: string; kind: "repo" | "reference"; dir: string; url: string; writable: boolean; archived: boolean; visibility: "public" | "private" | null; ci: boolean; branch: string | null; pinned: boolean; ... 13 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 gitops_publish --wetrun: 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 (see format_readiness_ahead). 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"; remote: string; refspec: 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"; checkout: string; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; } | ... 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 { key: string; kind: "repo" | "reference"; dir: string; url: string; writable: boolean; archived: boolean; visibility: "public" | "private" | null; ci: boolean; branch: string | null; pinned: boolean; ... 13 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

18 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"

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

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" | "unmapped" | "archived_ahead" | "shallow_local_work" | "upstream_not_a_branch"

type "diverged" | "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

{ name: string; upstream: string | null; worktree: 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.

name

type string

upstream

type string | null

worktree

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

{ path: string; primary: boolean; head: { kind: "branch"; name: string; } | { kind: "detached"; commit: string; }; uncommitted: { staged: number; unstaged: number; untracked: number; conflicted: number; }; ... 4 more ...; busy: { ...; }[]; } import {ReposCheckout} from '@fuzdev/fuz_repos/repos_status.js';

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

path

type string

primary

type boolean

head

type ReposHead

uncommitted

type ReposUncommitted

in_progress

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

locked

type boolean

linked

type boolean

submodules

type boolean | null

busy

type ReposSession[]

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"; recipe: { url: string; branch: string | null; shallow: boolean; sparse: string | null; }; by: "entry" | ... 1 more ... | "busy"; }

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

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

{ key: string; kind: "repo" | "reference"; dir: string; url: string; writable: boolean; archived: boolean; visibility: "public" | "private" | null; ci: boolean; branch: string | null; pinned: boolean; ... 13 more ...; visibility_check: { ...; } | ... 2 more ... | null; } import {ReposEntryStatus} from '@fuzdev/fuz_repos/repos_status.js';

One registry entry's state.

key

type string

kind

type "repo" | "reference"

dir

type string

url

type string

writable

type boolean

archived

type boolean

visibility

type "public" | "private" | null

ci

type boolean

branch

type string | null

pinned

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"; recipe: { url: string; branch: string | null; shallow: boolean; sparse: string | null; }; by: "entry" | "unprobed_worktree" | "busy"; } | null

layout

type ReposLayout | null

checkouts

type ReposCheckout[]

branches

type ReposBranchStatus[]

at_rest

type ReposAtRest | null

stashes

type number

fetched_at

type number | null

needs_human

type ReposNeedsHuman[]

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"; remote: string; refspec: string; } | { kind: "legacy_remotes_unreadable"; path: string; } | null

visibility_check

type { kind: "leak"; } | { kind: "private"; } | { kind: "unknown"; 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"; remote: string; refspec: string; } | { kind: "legacy_remotes_unreadable"; path: string; }; } | 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"; remote: string; refspec: 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

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

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

submodules

type boolean

worktree_refs

type boolean

staged

type boolean | null

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"; checkout: string; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; } | { kind: "origin_mismatch"; origin: { ...; } | ... 1 more ... | { ...; }; expected: string; fix: { ...; } | ... 1 more ... | { ...; }; } |...

type { kind: "not_a_repo"; detail: string; } | { kind: "operation_in_progress"; checkout: string; op: "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am"; } | { kind: "origin_mismatch"; origin: { kind: "url"; url: string; } | { kind: "no_url"; } | { kind: "missing"; }; expected: string; fix: { kind: "add"; } | { kind: "set_url"; } | { kind: "by_hand"; reason: "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"; }; } | { kind: "origin_not_https"; fetch_url: string; expected: string; fix: { kind: "add"; } | { kind: "set_url"; } | { kind: "by_hand"; reason: "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"; } | null; } | { kind: "fetch_url_mismatch"; fetch_url: string; expected: string; fix: { kind: "add"; } | { kind: "set_url"; } | { kind: "by_hand"; reason: "outside_repo_file" | "valueless_url" | "empty_value" | "several_urls"; } | null; } | { 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"; checkout: string; path: string; error: string; } | { kind: "unlisted_git_dir"; git_dir: string; head: { kind: "branch"; name: string; } | { kind: "detached"; commit: string; } | null; busy: { pid: number; cwd: string; worktree: string | null; process_cwd: string | null; source: "session_file" | "roster_worker"; }[]; } | { kind: "push_url_mismatch"; push_urls: string[]; expected: 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; } | { kind: "foreign_pid_domain"; path: string; pid_domain: string; source: "session_file" | "roster_worker"; }; }

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: 18; 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"; 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; })[]; message: string; hint: string | null; } | { kind: "git_not_found"; message: string; hint: string | null; } | { kind: "git_too_old"; found: string; required: string; message: string; hint: string | null; } | { kind: "unknown_entry"; name: string; suggestions: string[]; message: string; hint: string | null; } | { 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

{ version: 18; 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 ... | { ...; }; } import {ReposStatusErrorReport} from '@fuzdev/fuz_repos/repos_status.js';

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

version

type 18

error

type ReposStatusErrorBody

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: 18; 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 18

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"; }

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

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<[]>

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; } | { kind: "foreign_pid_domain"; path: string; pid_domain: string; source: "session_file" | "roster_worker"; }

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

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

{ path: string; git_dir: string | null; head: { kind: "branch"; name: string; } | { kind: "detached"; commit: string; } | null; locked: boolean; in_progress: "rebase" | "merge" | "cherry_pick" | ... 4 more ... | 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.

path

type string

git_dir

type string | null

head

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

locked

type boolean

in_progress

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

why

type ReposUnprobedWhy

holds

type ReposGitDirHolds | null

ReposUnprobedWorktreeStatus
#

repos_status.ts view source

value + type

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

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

path

type string

git_dir

type string | null

head

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

locked

type boolean

in_progress

type "rebase" | "merge" | "cherry_pick" | "revert" | "bisect" | "sequencer" | "am" | 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

busy

type ReposSession[]

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; blocked_by: { ...; } | ... 6 more ... | null; exit_noise: string | null; dir: string; origin: string | null; owned: boolean; } ...

type { kind: "clone"; dir: string; origin: string | null; owned: boolean; } | { kind: "worktree"; dir: string; origin: string | null; owned: boolean; } | { kind: "moved_worktree"; entry: string; 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; dir: string; origin: string | null; owned: boolean; } | { kind: "orphaned_worktree"; entry: string; dir: string; origin: string | null; owned: boolean; } | { kind: "shared_git_dir"; entry: string; with: string | null; dir: string; origin: 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: "held"; action: { kind: "push"; commits: number; } | { ...; } | { ...; }; by: "entry" | ... 7 more ... | "busy_unknown"; } | { ...; } | { ...; } | { ...; }

type { kind: "quiet"; } | { kind: "act"; action: { kind: "push"; commits: number; } | { kind: "fast_forward"; commits: number; } | { kind: "move"; }; } | { kind: "held"; action: { kind: "push"; commits: number; } | { kind: "fast_forward"; commits: number; } | { kind: "move"; }; by: "entry" | "pinned" | "push_url" | "fetch_failed" | "dirty_checkout" | "unprobed_worktree" | "several_checkouts" | "busy" | "busy_unknown"; } | { kind: "needs_human"; reason: "diverged" | "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"; } | { kind: "unknown"; failure: { kind: "ref_gone"; refname: string; fix: { kind: "unset_refspec"; pattern: string; } | { kind: "set_branches"; branch: string | null; } | { ...; }; } | ... 6 more ... | { ...; }; }

type { kind: "leak"; } | { kind: "private"; } | { kind: "unknown"; 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"; remote: string; refspec: string; } | { kind: "legacy_remotes_unreadable"; path: string; }; }

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 (get_required_bump_for_dependencies) 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: 18; 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.

options

returns

Promise<{ config_path: string; gitops_config: { repos: string[]; }; report: { version: 18; 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

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

run_preflight_checks
#

preflight_checks.ts view source

({ repos, version_changes, log, npm_ops, build_ops }: RunPreflightChecksOptions): Promise<PreflightResult> import {run_preflight_checks} from '@fuzdev/fuz_repos/preflight_checks.js';

Validates the publish-time requirements beyond repo git state:

  • every package the plan publishes builds (fail-fast to prevent broken state)
  • npm authentication
  • npm registry connectivity

What publishes is the plan's to decide, so preflight reads no changesets: it builds each package in version_changes. Git state โ€” each repo on its registry branch, clean, idle, in sync with origin or ahead of it, and no live session in its checkout โ€” is the readiness gate's, which `gitops_publish --wetrun runs before the plan's confirmation prompt (repo_readiness.ts`), so preflight reads no git.

Build validation runs BEFORE any publishing to prevent the scenario where version is bumped but build fails, leaving repo in broken state.

__0

returns

Promise<PreflightResult>

result with ok=false if any errors, plus warnings

RunPreflightChecksOptions
#

preflight_checks.ts view source

RunPreflightChecksOptions import type {RunPreflightChecksOptions} from '@fuzdev/fuz_repos/preflight_checks.js';

repos

type LocalRepo[]

version_changes

The plan's version changes โ€” every package the run publishes, explicit, escalated, and auto-generated alike. Preflight builds exactly these.

type VersionChange[]

log?

type Logger

npm_ops?

type NpmOperations

build_ops?

type BuildOperations

stdout_handler
#

publishing_event_handler.ts view source

(write_line?: WriteStdout): PublishingEventHandler import {stdout_handler} from '@fuzdev/fuz_repos/publishing_event_handler.js';

Writes each event as one JSON object per line (JSON-lines) to stdout. Write failures are swallowed โ€” the stream is observability, not control flow.

write_line

writes one line and its newline; defaults to process.stdout

default write_process_stdout_line

returns

PublishingEventHandler

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

summarize_events
#

publishing_event.ts view source

(events: ({ event: "run_started"; wetrun: boolean; total: number; } | { event: "package_skipped"; name: string; reason: string; } | { event: "package_completed"; name: string; old_version: string; new_version: string; bump_type: "major" | ... 1 more ... | "patch"; breaking: boolean; commit: string; tag: string; } | ... 6 more ... | { ...; })[], duration: number): { ...; } import {summarize_events} from '@fuzdev/fuz_repos/publishing_event.js';

Derives a run summary from the captured event list โ€” the single canonical path from events to summary, so the run_finished summary always agrees with the stream. Call before emitting run_finished (which is not itself counted).

events

the events captured so far this run

duration

wall-clock duration in milliseconds

type number

returns

PublishingRunSummary

TablePage
#

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_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

TreeItemPage
#

TreePage
#

update_all_repos
#

dependency_updater.ts view source

(repos: LocalRepo[], published: Map<string, string>, options?: UpdateAllReposOptions): Promise<{ updated: number; failed: { repo: string; error: Error; }[]; }> import {update_all_repos} from '@fuzdev/fuz_repos/dependency_updater.js';

repos

type LocalRepo[]

published

type Map<string, string>

options

default {}

returns

Promise<{ updated: number; failed: { repo: string; error: Error; }[]; }>

update_package_json
#

dependency_updater.ts view source

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

Updates package.json dependencies and creates changeset if needed.

Workflow:

  1. Updates all dependency types (dependencies, devDependencies, peerDependencies)
  2. Writes updated package.json with tabs formatting
  3. Creates auto-changeset if published_versions provided (for transitive updates)
  4. Commits both package.json and changeset with standard message

Uses version strategy to determine prefix (exact, caret, tilde, gte) while preserving existing prefixes when possible.

repo

updates

type Map<string, string>

options

default {}

returns

Promise<void>

throws

  • Error - if file operations or git operations fail

UpdateAllReposOptions
#

UpdatePackageJsonOptions
#

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 publishing order (prod/peer dependencies only, so dev cycles don't block it).

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

repos

type LocalRepo[]

returns

GraphValidationResult

the graph, publishing order, 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

VerboseIteration
#

VerboseIterationPackage
#

publishing_plan.ts view source

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

name

type string

changeset_count

type number

bump_from_changesets

type BumpType | null

required_bump

type BumpType | null

triggering_dep

type string | null

action

type "publish" | "escalation" | "auto_changeset" | "skip"

version_to

type string | null

is_breaking

type boolean

VerbosePropagationChain
#

publishing_plan.ts view source

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

source

type string

chain

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 side-effect preview 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 the executor generates for a dependency update (auto).

VersionStrategy
#

dependency_updater.ts view source

VersionStrategy

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

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

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

default {}

deps

default default_npm_registry_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

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