import { z } from 'zod'; import type { Config } from '../../types/index.js'; /** The server's `groupId` validation regex (hula-server PR #505). */ export declare const GROUP_ID_REGEX: RegExp; /** * A repository discovered under a `--folder` parent that qualifies for a group * launch (has both a `.git` entry and a `.hublaunch` config file). */ export interface DiscoveredRepo { /** The directory name (used as the `` key for `--plan` overrides). */ name: string; /** Absolute path to the repository root. */ path: string; } /** * A subdirectory that was inspected during discovery but did not qualify, with * the human-readable reason (for display in the skipped list). */ export interface SkippedRepo { name: string; reason: string; } /** * Result of scanning a parent folder for group-launchable repositories. */ export interface DiscoverResult { repos: DiscoveredRepo[]; skipped: SkippedRepo[]; /** * True when the folder itself is a git repository (a `.git` entry directly * under it) — the user probably pointed at a repo instead of its parent. */ folderIsRepo: boolean; } /** One repository entry inside a persisted group record. */ export interface GroupRecordRepo { name: string; path: string; project: string; } /** A single persisted group-launch record in `.hublaunch/group-launches.json`. */ export interface GroupRecord { groupId: string; issueName: string; createdAt: string; folder: string; repos: GroupRecordRepo[]; } /** Zod schema for the on-disk `.hublaunch/group-launches.json` file. */ export declare const GroupRecordSchema: z.ZodObject<{ groupId: z.ZodString; issueName: z.ZodString; createdAt: z.ZodString; folder: z.ZodString; repos: z.ZodArray, "many">; }, "strip", z.ZodTypeAny, { createdAt: string; issueName: string; groupId: string; folder: string; repos: { path: string; name: string; project: string; }[]; }, { createdAt: string; issueName: string; groupId: string; folder: string; repos: { path: string; name: string; project: string; }[]; }>; export declare const GroupLaunchesFileSchema: z.ZodObject<{ groups: z.ZodArray, "many">; }, "strip", z.ZodTypeAny, { createdAt: string; issueName: string; groupId: string; folder: string; repos: { path: string; name: string; project: string; }[]; }, { createdAt: string; issueName: string; groupId: string; folder: string; repos: { path: string; name: string; project: string; }[]; }>, "many">; }, "strip", z.ZodTypeAny, { groups: { createdAt: string; issueName: string; groupId: string; folder: string; repos: { path: string; name: string; project: string; }[]; }[]; }, { groups: { createdAt: string; issueName: string; groupId: string; folder: string; repos: { path: string; name: string; project: string; }[]; }[]; }>; export type GroupLaunchesFile = z.infer; /** Relative path (from a repo root) of the local group-record file. */ export declare const GROUP_LAUNCHES_RELATIVE_PATH = ".hublaunch/group-launches.json"; /** * Lowercase an issue name and replace every character outside `[A-Za-z0-9_-]` * with a hyphen. Used both for group-id generation and plan-filename matching. */ export declare function slugifyIssueName(issueName: string): string; /** * Service for the client-side multi-repo `--folder` fan-out: repository * discovery, group-id generation, per-repo plan resolution, and local group * record persistence. Deliberately free of network calls so it is trivially * unit-testable. */ export declare class GroupLaunchService { /** * Discover every immediate subdirectory of `folder` that qualifies as a * group-launchable repository — one that contains BOTH a `.git` entry and a * `.hublaunch/hublaunch.config.{ts,mjs,js}` file. Discovery does not recurse * deeper than one level. Non-qualifying subdirectories are returned in the * `skipped` list with a reason ("no .git" / "no .hublaunch config"). * * @param folder - Absolute or relative parent-folder path. * @returns The qualifying repos, the skipped entries with reasons, and a * `folderIsRepo` flag set when `folder` is itself a git repo. */ discoverRepos(folder: string): DiscoverResult; /** * Generate a group id of the form `-<6 hex chars>` where `` is the * slugified issue name, truncated so the full id is ≤ 64 characters. The hex * suffix comes from `crypto.randomBytes(3)`. * * @param issueName - The feature/issue name. * @returns A group id matching `^[A-Za-z0-9_-]{1,64}$`. */ generateGroupId(issueName: string): string; /** * Resolve the plan file to launch for a repository. * * Candidates are `*.md` files under the repo's configured plans directory * (`repoConfig.planPath`), searched recursively. Preference order: the newest * file (by `YYYY-MM-DD-HH:MM` filename prefix, falling back to mtime) whose * filename contains the issue-name slug; if none match, the newest plan file * overall. * * @param repo - The discovered repository. * @param repoConfig - That repo's loaded config (absolute `planPath`). * @param issueName - The feature/issue name whose slug is matched. * @returns The repo-relative plan path (e.g. `.hublaunch/plans/…md`), or null * when the repo has no plan files at all. */ resolvePlan(repo: DiscoveredRepo, repoConfig: Config, issueName: string): string | null; /** * Append a group record to `.hublaunch/group-launches.json` in each member * repo. Best-effort: a corrupt existing file is treated as empty and * rewritten fresh; any write failure warns and is otherwise ignored (it must * never fail the launch). * * @param repos - Repos whose local record file should receive the record. * @param record - The group record to append. */ recordGroup(repos: DiscoveredRepo[], record: GroupRecord): void; /** * Read the most recently recorded group id from the current repo's * `.hublaunch/group-launches.json`. Used by a bare `--show-group` (no id). * * @param repoRoot - The repository root to read the record file from. * @returns The latest group's id, or null when the file is absent/empty/corrupt. */ latestRecordedGroupId(repoRoot: string): string | null; } /** * Validate a user-supplied group id against the server's format rule. Returns * the server's exact error wording on failure, or null when valid. */ export declare function validateGroupId(groupId: string): string | null; //# sourceMappingURL=GroupLaunchService.d.ts.map