/** * Utilities for reading, finding, and updating .uipx solution files. */ import type { IFileSystem } from "@uipath/filesystem"; import type { UipxFile, UipxProject } from "./types"; /** * Outcome of attempting to register a project in its parent `.uipx` solution. * * Status meanings: * - `Registered` — Project was added to `.uipx` Projects[] in this call. * - `AlreadyRegistered` — Project was already in Projects[]; no write performed. * - `Skipped` — A candidate solution was found but registration was deliberately * not attempted (ambiguous: multiple `.uipx` in same dir, or the * project dir sits outside the discovered solution dir, or the * project's type cannot live in a solution — see * {@link unsupportedSolutionProjectType}). * - `Failed` — Registration was attempted and an error occurred (read/write/parse). * - `NotInSolution` — No `.uipx` file was found by walking ancestor directories. The * project was created in standalone mode. This is the explicit * contract value for "no parent solution discovered" so that * downstream consumers (agents, the skill doc, CI scripts) can * distinguish "missing field due to old CLI" from "field * intentionally indicates no enclosing solution" (MST-10004). * - `OptedOut` — The caller passed `skipRegistration` (the `--skip-solution-registration` * CLI flag): discovery and registration were intentionally not * attempted. Distinct from `Skipped` (structural ambiguity the * tool could not resolve) and `NotInSolution` (no solution exists): * the user explicitly declined registration. */ export interface ProjectSolutionRegistration { Status: "Registered" | "AlreadyRegistered" | "Skipped" | "Failed" | "NotInSolution" | "OptedOut"; Message: string; Solution?: string; Project?: string; ProjectId?: string; Instructions?: string; } /** * Options for {@link tryRegisterProjectInParentSolution}. */ export interface RegisterProjectOptions { /** * When true, skip solution discovery and registration entirely and return an * `OptedOut` envelope. Set by the `--skip-solution-registration` CLI flag. The `OptedOut` * envelope is still returned (the field is never absent) so downstream consumers * keep a uniform `Data.SolutionRegistration` contract. */ skipRegistration?: boolean; } export declare const STUDIO_WEB_PROJECT_TYPE_OVERRIDES: Record; export declare function normalizeProjectType(projectType: string): string; /** * Converts a relative path to forward slashes. ProjectRelativePath values in * the .uipx manifest must always use forward slashes — Studio Web rejects * backslash separators, which `fs.path.relative`/`join` produce on Windows. */ export declare function toPortableRelativePath(relativePath: string): string; /** * Find and parse the .uipx file in a solution directory. * Validates the required fields (SolutionId, Projects). */ export declare function readUipxFile(fs: IFileSystem, solutionDir: string): Promise<{ uipx: UipxFile; uipxFileName: string; }>; export interface SolutionManifestCreation { solutionDir: string; solutionFile: string; solutionId: string; } export interface CreateSolutionManifestOptions { /** * When true, do not throw if `solutionDir` already exists; only the * `.uipx` manifest write happens. Lets callers recover from a partial- * failure prior run (dir created, manifest write failed) without manual * cleanup. `uip solution init` keeps the default (throw on existing dir); * `autoScaffoldSolution` sets this so the auto-scaffold path is genuinely * idempotent. */ allowExistingDir?: boolean; } /** * Create a new solution directory containing a `.uipx` manifest with an empty * Projects array. Used by commands that scaffold a parent solution on the * user's behalf (e.g. `uip maestro flow init` when invoked outside a * solution). `uip solution init` writes its own manifest in * `solution-init-service.ts` because it preserves a caller-supplied file * extension — keep the two skeletons in sync. * * Fails if `solutionDir` already exists unless `allowExistingDir` is set. * AGENTS.md / CLAUDE.md briefing files are NOT written here — that template * is owned by `@uipath/solution-tool`. Callers that want them should write * them after this returns. */ export declare function createSolutionManifest(fs: IFileSystem, solutionDir: string, solutionName: string, options?: CreateSolutionManifestOptions): Promise; /** * Reported under `Data.AutoCreatedSolution` in the *-init command output * whenever the CLI scaffolded the parent solution itself. Absent when the * command was run inside an existing solution. */ export interface AutoCreatedSolution { Name: string; Path: string; SolutionFile: string; } /** * Scaffold a `Solution/` sibling directory containing an empty * `.uipx` manifest. Idempotent across both happy and partial-failure paths: * * - Existing `.uipx` → reuse it (re-run with `--force`). * - Dir exists, no `.uipx` yet → write the manifest into the existing dir * (recovers a previous run that crashed * between mkdir and writeFile). * - Neither exists → mkdir + write manifest. * * Lower-level helper. Most callers want {@link prepareProjectLocation}, which * runs discovery first and only scaffolds when nothing is found. */ export declare function autoScaffoldSolution(fs: IFileSystem, baseDir: string, projectName: string): Promise; export interface PrepareProjectLocationOptions { /** * Set when the caller passed `--skip-solution-registration`. Short-circuits * the helper: no discovery, no scaffold, the candidate path is returned * unchanged. Lets the user opt out of both registration AND the parent * solution scaffold with a single flag. */ skipRegistration?: boolean; } export interface PrepareProjectLocationResult { /** * Absolute path the project should be created at. When the helper * scaffolded a parent solution, this is `/`; * otherwise it equals the resolved `candidateProjectDir`. */ projectDir: string; /** * Present when this call scaffolded a fresh parent solution. The * `*-init` command surfaces it under `Data.AutoCreatedSolution` so callers * can tell the auto-scaffold path apart from the in-existing-solution path. */ autoCreatedSolution?: AutoCreatedSolution; } /** * Resolve where an `*-init` command should write the new project, scaffolding * a parent `.uipx` solution on the user's behalf when needed. * * Behavior: * - `skipRegistration` set → return `candidateProjectDir` as-is. * - Inside an existing solution → return `candidateProjectDir` as-is. * - Ambiguous discovery (skipped) → return `candidateProjectDir` as-is; the * downstream `tryRegisterProjectInParentSolution` * call surfaces the ambiguity in * `SolutionRegistration.Status`. * - No parent solution found → scaffold `/Solution/` * and return its nested project path. * * The four `*-init` tools (agent / case / flow / maestro bpmn) share this * helper so the auto-scaffold behavior stays uniform. */ export declare function prepareProjectLocation(fs: IFileSystem, candidateProjectDir: string, projectName: string, options?: PrepareProjectLocationOptions): Promise; /** * Resolve input to a solution directory path. * Accepts a directory path or a .uipx file path. */ export declare function resolveSolutionDir(fs: IFileSystem, inputPath: string): string; /** * Update the SolutionId in a .uipx file at a known path. * Called after successful upload to ensure subsequent uploads use overwrite. */ export declare function updateUipxSolutionId(fs: IFileSystem, uipxPath: string, newSolutionId: string): Promise; /** * Find the .uipx solution file in the parent directory of a project path. * Returns the solutionId and projectId, or undefined if not found. */ export declare function findSolutionFile(fs: IFileSystem, projectPath: string): Promise<{ solutionId: string; projectId: string; } | undefined>; /** * Update the .uipx solution file in the parent directory of a project path. * Scans the parent dir for a .uipx file and updates its SolutionId. */ export declare function updateSolutionFile(fs: IFileSystem, projectPath: string, newSolutionId: string): Promise; export declare function tryRegisterProjectInParentSolution(fs: IFileSystem, projectDir: string, options?: RegisterProjectOptions): Promise; export type ParentSolutionDiscovery = { status: "found"; solutionFile: string; } | { status: "notFound"; } | { status: "skipped"; registration: ProjectSolutionRegistration; }; export declare function findNearestParentUipxFile(fs: IFileSystem, projectDir: string): Promise; export declare function readSolutionManifest(fs: IFileSystem, solutionFile: string): Promise<[Error, null] | [ null, { content: Record; projects: UipxProject[]; } ]>; /** * Read the .uipx solution manifest at `solutionFile` and report whether the * project at `projectDir` is registered in its `Projects[]` array. * * Matching is path-based: each `Projects[].ProjectRelativePath` is resolved * to an absolute project directory and compared to `projectDir` after * canonicalization via `realpath()`. Canonicalization makes the comparison * tolerant of: * - case-folding differences on macOS / Windows filesystems * - symlinks that resolve `projectDir` and the manifest entry to the same * underlying inode through different surface forms * If `realpath()` fails (e.g. the path does not exist), the literal path is * used — the surrounding pre-flight will already surface the missing-dir * error separately, so we should not double-fail here. * * Throws when the manifest cannot be read or parsed (invalid JSON, missing * `Projects` array, malformed entry). The boolean return is reserved for * the answerable question "is this project listed?" — a corrupt manifest * is a separate failure mode that callers must not silently translate * into "not registered", since the repair (`uip solution projects add`) * won't fix a manifest that fails to parse. * * Used by `flow debug` to catch the empty-solution-archive case BEFORE * uploading to Studio Web (MST-10004). Studio Web's import endpoint rejects * archives whose `Projects[]` is empty (or whose listed projects don't match * the staged contents) with an opaque HTTP 400 — failing locally with the * project path and the manifest path is far more actionable. */ export declare function isProjectRegisteredInSolution(fs: IFileSystem, projectDir: string, solutionFile: string): Promise; /** * Walks up from `startDir` to the filesystem root, returning the path of the * single `.uipx` solution file found. Throws when none — or more than one in a * single directory — is found. Distinct from {@link findSolutionFile}, which * peeks only the parent directory and returns solution/project ids. * * Used by the resource engine (`@uipath/solution-sdk/resources`) and the * solution CLI to resolve `--solution-folder` to a concrete manifest. */ export declare function findSolutionFileUpward(fs: IFileSystem, startDir: string): Promise;