import type { Command } from 'commander'; import type { Config } from '../types/index.js'; import type { LlmProviderType } from '../types/config.schema.js'; /** * Launch command - Trigger a launch job on hula-project server * * Usage: hula launch [options] * Usage: hula launch --show * Usage: hula launch --logs */ /** * Commander accumulator for the repeatable `--plan =` option. * Each occurrence is parsed as `repoName=relativePath` and merged into the * override map. A missing `=` throws a clear error. */ export declare function collectPlanOverrides(value: string, previous: Record): Record; export declare function launchCommand(program: Command, config: Config): void; interface LaunchOptions { url?: string; apiKey?: string; duration?: number; launch?: string; worktree?: string | boolean; resume?: number; fix?: string; regression?: boolean; skipRegression?: boolean; kill?: boolean; killAndRelaunch?: boolean; verbose?: boolean; test?: boolean; handoff?: string; show?: string; logs?: string; lines?: number; type?: 'log' | 'output'; editor?: boolean; /** --provider: LLM provider type (claude | openai | openrouter). */ provider?: string; /** --provider-key: the provider credential (ephemeral). */ providerKey?: string; containerCpu?: number; containerMemory?: number; containerDisk?: number; updateNotificationUrl?: string; updateNotificationNameTag?: string; /** Parent folder containing sibling repos to fan out over. */ folder?: string; /** Explicit group id (join/retry an existing group). */ groupId?: string; /** Repeatable `--plan =` overrides, keyed by repo directory name. */ plan?: Record; /** * `--show-group [id]`: string when an id was given, `true` for the bare flag * (resolve the latest local group record), undefined when not passed. */ showGroup?: string | boolean; /** * `--yes`: skip the group-launch confirmation prompt and allow per-repo plan * auto-resolve without a TTY. The /hula-launch skill path runs the CLI as a * piped subprocess (never a TTY), so the skill passes this to opt in to the * same auto-resolve + roster flow an interactive terminal gets. */ yes?: boolean; } /** * Validate the `--kill` / `--kill-and-relaunch` flag combination. * * - The two flags are mutually exclusive. * - `--kill` composes with no other launch-only flag (`--resume`, `--fix`, * `--test`, `--handoff`, `--regression`). * - `--kill-and-relaunch` composes normally with every launch flag. * * Returns an error message when the combination is invalid, or `null` when OK. */ export declare function validateKillFlags(options: LaunchOptions): string | null; /** * Whether a plan path is required for the given flag combination. * `--kill` needs only the tracking name; every other mode needs a plan. */ export declare function requiresPlanPath(options: LaunchOptions): boolean; /** * Validate the multi-repo `--folder` / `--group-id` / `--plan` flag matrix. * * - `--folder` resolves plans per repository, so it is incompatible with a * positional `` and with the read/resume flags `--show`, `--logs`, * `--resume`, `--fix`. * - `--plan` (per-repo override) only makes sense with `--folder`. * - `--group-id` alone (no `--folder`) is allowed — it attaches a single-repo * launch to an existing group. * - `--kill --folder` is allowed (cancel-only fan-out). * * Returns an error message when the combination is invalid, or `null` when OK. */ export declare function validateFolderFlags(options: LaunchOptions, hasPlanPathPositional: boolean): string | null; /** * Derive the request `conflictMode` from the CLI flags (plus an optional explicit * override used when re-invoking after an interactive 409 resolution). * * Returns `undefined` for the default `reject` path so the request body stays * byte-identical to today's — the key is only added for `killAndRelaunch`. */ export declare function deriveConflictMode(options: LaunchOptions, override?: 'killAndRelaunch'): 'killAndRelaunch' | undefined; /** * Build the request body for a cancel-only (`--kill`) call. Carries NO secrets — * only the tracking name, repository id, and the `kill` conflict mode. */ export declare function buildKillRequestBody(issueName: string, repositoryId: string): Record; /** * Assemble the outgoing `steps` request field from the config-file `steps` * object plus the `--skip-regression` launch flag, and enforce the two * cross-field conflict rules the server also enforces (mirrors `resolveSteps()` * in hula-server's ralph-run route, PR #442). Doing the checks client-side turns * a would-be HTTP 400 round trip into an immediate, identically-worded failure: * 1. `bugfix.model` and `mergeConflict.model` map to the same * `RALPH_BUGFIX_MODEL` env var, so they cannot be set to different values. * 2. `regression.skip: true` (whether from config or `--skip-regression`) * contradicts the legacy `--regression` force-on flag. * * On success returns `{ steps }` where `steps` is `undefined` when there is * nothing to send (no config `steps`, no `--skip-regression`) — keeping the * request body byte-identical to pre-change behavior. On failure returns * `{ error }` with the server's exact error text. */ export declare function resolveSteps(configSteps: Config['steps'], skipRegressionFlag: boolean | undefined, legacyRegressionFlag: boolean | undefined): { steps?: Record; error?: string; }; /** * Result of a single-repo launch attempt. In folder (group) mode this is * captured per repo so the fan-out can continue past failures and print a * summary; in single-repo mode a failure exits the process directly. */ export interface RepoLaunchResult { ok: boolean; planId?: string; status?: number; message?: string; } /** * Inputs to {@link buildRalphRunRequestBody}. Every optional field is omitted * from the body when absent, keeping non-group / default request bodies * byte-identical to the pre-fan-out CLI. */ export interface RalphRunBodyInput { issueName: string; planPath: string; repositoryId: string; duration?: number; /** From `--launch`; serialized as `ralphPath` for server compatibility. */ launchPath?: string; worktree?: string | boolean; resume?: number; fix?: string; regression?: boolean; steps?: Record; test?: boolean; conflictMode?: 'killAndRelaunch'; /** Maps to RalphRunRequest.groupId (hula-server PR #505). */ groupId?: string; verbose?: boolean; handoff?: string; clientSessionId?: string; /** * LLM provider selection + credential. Replaces the pre-multi-provider * `anthropicApiKey` field (hula-server multi-provider plan). `authToken` is the * ephemeral credential; `type` selects the server-side agent harness. */ provider: { type: LlmProviderType; authToken: string; }; containerResources?: { cpu: number; memory: number; disk: number; }; updateNotificationUrl?: string; updateNotificationNameTag?: string; githubToken?: string; envVars?: Record; /** * True when the feature branch (with the plan committed) already exists on * origin — the plan-branch flow. The server then checks out the existing * branch in the sandbox instead of creating one from the base branch. */ branchExists?: boolean; } /** * Parse a beforeLaunch hook's stdout into an envVars object to merge into the * launch request. The contract is `{"envVars": {"KEY": "value", ...}}`. * * Returns `undefined` when the hook has nothing to contribute: * - empty stdout * - `{}` / valid JSON with no `envVars` key * - `{"envVars": {}}` (empty object) * * Throws when the contract is violated (Edge Case 3 — abort rather than launch * against the wrong resources): * - stdout is not valid JSON * - `envVars` is present but not a plain object */ export declare function parseBeforeLaunchHookOutput(stdout: string): Record | undefined; /** * Assemble the `POST /api/v1/ralph-run` request body from already-resolved * inputs. Fields are inserted in a fixed order and only when present, so a * launch with no group flag produces a body byte-identical to the pre-fan-out * CLI (verified by unit test — AC5). */ export declare function buildRalphRunRequestBody(input: RalphRunBodyInput): Record; /** * Handle API errors consistently * (exported for reuse by sibling commands, e.g. `hula info`) */ export declare function handleApiError(error: unknown, serverUrl: string): void; /** * Deprecated ralph command - alias for launch * @deprecated Use launchCommand instead */ export declare function ralphCommand(program: Command, config: Config): void; export {}; //# sourceMappingURL=launch.d.ts.map