/** * setup.ts * * Worktree cold-start setup, the per-project provisioning that makes an * isolated/worktree agent usable instead of broken-by-default. A fresh git * worktree is checked out from a committed branch, so it has NONE of the * working tree's installed dependencies, generated code, or untracked local * files. This module runs configured setup commands (install, codegen) in the * worktree and carries over configured untracked files (globs) from the source * working tree, capturing honest logs and an honest terminal state. * * Honesty contract: a command that exits non-zero stops the run and yields * state `failed` with the failing step's captured output, never a silent * best-effort. No commands AND no carry-over globs configured yields `skipped` * (there was nothing to do), which is distinct from `succeeded` (work ran and * passed). */ /** Per-project worktree setup configuration (resolved from the daemon config). */ export interface WorktreeSetupConfig { /** Shell command lines to run, in order, in the new worktree (e.g. `bun install`, `bun run codegen`). */ readonly commands: readonly string[]; /** Globs (relative to the source working tree) of UNTRACKED files to copy into the new worktree (e.g. `.env`, `.env.*`, `config/local.json`). */ readonly carryOverGlobs: readonly string[]; } /** The honest terminal state of a setup run. */ export type WorktreeSetupState = 'skipped' | 'succeeded' | 'failed'; /** One step of a setup run, a single command, or the aggregate carry-over pass. */ export interface WorktreeSetupStep { readonly kind: 'command' | 'carry-over'; /** The command line, or a human label for the carry-over pass. */ readonly label: string; readonly ok: boolean; /** Process exit code for a command step; absent for carry-over. */ readonly exitCode?: number | undefined; /** Captured combined stdout+stderr for a command, or the list of carried-over paths for carry-over. Bounded. */ readonly output: string; } /** The full result of a setup run, persisted onto the worktree record and returned by the rerun verb. */ export interface WorktreeSetupResult { readonly state: WorktreeSetupState; readonly startedAt: number; readonly completedAt: number; readonly steps: readonly WorktreeSetupStep[]; /** Present only when state === 'failed': the honest reason (the failing command line, or an I/O error). */ readonly error?: string | undefined; } /** Outcome of running one command: injectable so tests drive it without spawning real processes. */ export interface WorktreeCommandOutcome { readonly exitCode: number; readonly output: string; } /** Runs a single shell command line in `cwd`, returning its exit code and captured combined output. */ export type WorktreeCommandRunner = (commandLine: string, cwd: string) => Promise; /** Lists UNTRACKED files (relative paths) in the source working tree, the carry-over candidate set. Injectable for tests. */ export type UntrackedFileLister = (sourceRoot: string) => Promise; export interface RunWorktreeSetupOptions { readonly runCommand?: WorktreeCommandRunner | undefined; readonly listUntracked?: UntrackedFileLister | undefined; readonly now?: (() => number) | undefined; } /** * Run cold-start setup for a freshly-created worktree. Runs each command in * order (stopping on the first non-zero exit), then copies untracked files * matching the carry-over globs from `sourceRoot` into `worktreePath`. */ export declare function runWorktreeSetup(worktreePath: string, sourceRoot: string, config: WorktreeSetupConfig, options?: RunWorktreeSetupOptions): Promise; /** * Resolve the per-project worktree setup config from the daemon config. Reads * `worktree.setup.commands` (array of command lines) and * `worktree.setup.carryOverGlobs` (array of globs). Non-array/malformed values * degrade to empty (setup then `skipped`), never a throw. */ export declare function resolveWorktreeSetupConfig(get: (key: string) => unknown): WorktreeSetupConfig; /** Injectable filesystem probes for derivation, so tests never need a real repo. */ export interface DeriveSetupIo { readonly fileExists: (path: string) => boolean; readonly listDir: (path: string) => readonly string[]; } /** * Derive worktree setup from the repo itself: each ecosystem's lockfile yields * its install command, and the presence of `.env` / `.env.*` files at the repo * root yields the carry-over globs for them. A repo with no lockfile and no * env files derives NOTHING, setup stays an honest `skipped`, exactly as if * no config existed. */ export declare function deriveWorktreeSetup(sourceRoot: string, io?: DeriveSetupIo): WorktreeSetupConfig; /** * The EFFECTIVE worktree setup: derived from the repo by default, with user * config OVERRIDING the derivation per field, a configured `commands` array * replaces the derived install commands; a configured `carryOverGlobs` array * replaces the derived env globs. User config never merely enables derivation; * its presence supersedes it. An isolated agent therefore starts with deps and * env with ZERO configuration, and absence of any signal (no lockfile, no env * files, no config) is an honest no-op. */ export declare function resolveEffectiveWorktreeSetup(get: (key: string) => unknown, sourceRoot: string, io?: DeriveSetupIo): WorktreeSetupConfig; //# sourceMappingURL=setup.d.ts.map