/** * `loops bundle …` - the on-disk half of a loop, and its immutable versions. * * ## Why a `bundle` noun instead of bare verbs * * `loops push` and `loops pull` already exist and mean "local SQLite <-> control * plane row backfill" (the cutover runbooks call them by name). Silently * repurposing them would break those runbooks the day this ships. So the * canonical spelling is `loops bundle `, and the bare verbs dispatch here * only when a POSITIONAL BUNDLE NAME is supplied - `loops push demo` is a * bundle push, `loops push --apply` is still the row backfill. `loops init`, * `loops versions`, `loops pin`, `loops sync` and `loops materialize` are new * names with no collision and are registered as plain aliases. * * ## Exit codes * * 0 success, or a `--dry-run` that produced a plan * 1 generic failure * 2 integrity refusal (digest mismatch, unsafe entry, credential in the tree, * drift refused without `--allow-dirty`) * 3 conflict (local and remote both moved, version exists, name taken, pin) * 4 not found (loop, bundle, or version) * 5 scope/authorisation refusal * 78 credentials or configuration missing (EX_CONFIG) */ import type { Command } from "commander"; import { type BundleApiClient } from "./bundle-client.js"; interface BundleCliContext { json: () => boolean; /** Injected by tests. Production resolves the client from the environment. */ client?: BundleApiClient; env?: NodeJS.ProcessEnv; } /** * Register every bundle command, and hand back the two actions the bare * `loops push` / `loops pull` verbs dispatch to when given a positional name. */ export declare function registerBundleCommands(program: Command, ctx: BundleCliContext): { push: (name: string, opts: { reason?: string; as?: string; adopt?: boolean; dryRun?: boolean; }) => Promise; pull: (name: string, opts: { version?: string; allowDirty?: boolean; }) => Promise; }; export {};