Namespace Kuestenlogik.Bowire.Workspace.Git

Classes

BowireGitWorkspaceEndpoints

Endpoint surface for the git-backed workspace runtime — currently just the FS-watch SSE stream (#150). Hosts that called AddBowireGitWorkspace(IServiceCollection) at DI build call MapBowireGitWorkspaceEvents(IEndpointRouteBuilder, string) at endpoint-routing setup to mount the route.

BowireGitWorkspaceExtension

Marker + activation type for the git-backed workspace runtime. The workbench checks for an BowireGitWorkspaceExtension resolved from DI; presence means "the operator wired the runtime, route per-workspace reads/writes through the per-entity layout when workspace.storageRoot is set". Absence keeps GetWorkspacePath(string, string?, string) on the legacy per-user fallback.

BowireGitWorkspaceMigrationReport

Aggregate result of a single workspace migration. Carries the per-kind counts so callers can render a summary, plus a flag indicating whether any kind moved data on this run (useful for the CLI's idempotent "nothing to do" diagnostic).

BowireGitWorkspaceMigrator

One-shot migration from the legacy per-user bundle layout — one <entityKind>.json file per kind, each carrying an array of entities — to the per-entity file layout the git-backed runtime reads through (#196 Phase 2.2).

Used by the bowire workspace migrate-format CLI subcommand and exposed publicly so embedded hosts can run the migration from their own admin tooling. The migrator never deletes the legacy bundle outright — it renames each migrated file to <entityKind>.json.legacy so an operator can verify the per-entity files look right before binning the original.

BowireGitWorkspaceServiceCollectionExtensions

DI entry-point for the git-backed workspace runtime. Embedded hosts that want the surface call AddBowireGitWorkspace() after AddBowire(); standalone Kuestenlogik.Bowire.Tool references the package and wires it from BowireCli's host build so the CLI ships the runtime bundled.

FileEntityStore

File-backed IBowireEntityStore implementation — one .json per entity under <storageRoot>/<entityKind>/.

Collections get an additional per-request layout: each entry that looks like an HTTP request (heuristic: requests array on the document) writes a separate <request-id>.req.json sibling under collections/<collection-id>/ so OpenAPI-shaped collection diffs show one request per file in PR review — instead of the whole collection's request array exploding on every edit.

JSON serialisation matches the workbench's bundle store: WriteIndented on, camelCase preserved (we don't reshape the document — we trust the caller's shape — but the pretty-print pass keeps diffs reviewable).

The store is robust against missing directories: every write creates the per-kind directory on demand, every read against a missing file returns null, every delete against a missing target is a no-op. That lets the workbench's "save environment" path land without a separate "create the folder skeleton first" round-trip.

LockHeldException

Thrown by AcquireAsync(string, string, CancellationToken) when another live writer holds the workspace lock. Carries the holder's metadata so the caller can surface a friendly "process <pid> on <host> started at <timestamp>" diagnostic without re-reading the file.

SecretOverlayMerger

Merges <env>.secrets.json overlays on top of the committed <env>.json at load time. Implements the secret-separation convention shipped in Phase 1: the non-secret half is the reviewable, git-tracked half; .secrets.json siblings carry tokens and are .gitignore'd at workspace init.

WorkspaceLock

Cross-process workspace lockfile — guards concurrent writers against corrupting the per-entity layout. One holder per storageRoot; second writer hitting an active lock surfaces the friendly "another process is editing this workspace" hint instead of overwriting state.

WorkspaceWatcher

Singleton watcher fleet — keeps one FileSystemWatcher per watched storageRoot and fans events out to every subscriber listening on that root. The SSE endpoint (#150) gets a ChannelReader<T> per subscription so each connected browser tab consumes its own queue.

Structs

BowireGitWorkspaceMigrationKindReport

Per-entity-kind migration outcome. Counts the entities written to the per-entity layout, plus a flag indicating whether the migration actually fired (false = nothing-to-do, kind absent on disk or already migrated).

WorkspaceFileEvent

One file-system event surfaced by the workspace watcher. Emitted on the SSE stream the workbench subscribes to so it can react to external edits (a teammate's git pull, an editor saving an environment file, etc.) without hammering the disk on a poll.

WorkspaceLockInfo

Snapshot of a workspace lock holder's metadata — populated when AcquireAsync(string, string, CancellationToken) hits an active lock and surfaced on Holder, plus returned from Inspect(string) for diagnostic CLIs.

Interfaces

IBowireEntityStore

Per-entity reader/writer the workbench routes through when a workspace's storageRoot is set (#196 Phase 2.2). Replaces the legacy single-bundle layout — environments, collections, recordings, scripts and flows each live in their own subdirectory under the checked-out workspace folder so PR diffs show one JSON document per edited entity rather than the entire bundle on every keystroke.