/**
 * Shared build pipeline.
 *
 * Both `agentuity build` (the standalone command) and the deploy
 * command's "Build, Verify and Package" step go through this single
 * function. Each caller wraps the result with its own surface
 * (TUI progress, Step state machine, deploy-metadata emission), but
 * the core ordering — detect, typecheck, build, package — lives here
 * so the two paths can't drift apart again.
 *
 * Why ordering matters:
 *   1. Detect framework and detect monorepo *first*, because
 *      `monorepo` determines where staging output goes
 *      (`<monorepoRoot>/.agentuity`, not `<projectDir>/.agentuity`).
 *   2. Typecheck *before* the build, so a broken project fails fast
 *      without spending minutes compiling. The deploy flow has done
 *      this for a while; the standalone command used to typecheck
 *      after the build, which wasted CI time and hid type errors
 *      behind framework build noise.
 *   3. Adapter build receives the monorepo context (so it runs
 *      install at the workspace root, builds the subpackage in
 *      place, and copies the whole tree into the staging dir).
 *   4. Packaging writes launch metadata with `workingDirectory` set
 *      when monorepo is non-null, so pilot starts the process in
 *      the right subdirectory.
 */
import { join, resolve } from 'node:path';
import { getAdapter } from "./adapters/index.js";
import { detectFrameworkWithPackageJson, NO_DEPLOYABLE_PROJECT_MESSAGE } from "./detect/index.js";
import { detectMonorepoContext } from "./detect/monorepo.js";
import { packageBuildOutput } from "./package/index.js";
import { typecheck } from "./typecheck.js";
/**
 * Error subclasses used to carry phase-specific context back to the
 * caller. Both callers map these onto their own surfaces: `agentuity
 * build` calls `tui.fatal`, the deploy step returns `stepError`.
 */
export class FrameworkDetectionError extends Error {
    code = 'NO_DEPLOYABLE_PROJECT';
    constructor() {
        super(NO_DEPLOYABLE_PROJECT_MESSAGE);
        this.name = 'FrameworkDetectionError';
    }
}
export class TypecheckError extends Error {
    code = 'TYPECHECK_FAILED';
    /** Raw tsc output for the caller to render. */
    output;
    constructor(output) {
        super('Typecheck failed');
        this.name = 'TypecheckError';
        this.output = output;
    }
}
/**
 * Run the shared build pipeline. Throws `FrameworkDetectionError` or
 * `TypecheckError` on the structured failure cases; any other error
 * propagates as-is so the caller can decide how to surface it.
 */
export async function runBuildPipeline(input) {
    const { projectDir, logger, collector } = input;
    const absoluteProjectDir = resolve(projectDir);
    const logs = [];
    // 1. Detect framework (reuse prediscovered if the caller already ran
    //    detection in an earlier step — Discover phase in the deploy
    //    pipeline does this).
    const detection = input.prediscovered ?? (await detectFrameworkWithPackageJson(absoluteProjectDir));
    if (!detection || !detection.framework) {
        throw new FrameworkDetectionError();
    }
    const { framework, packageJson } = detection;
    // 2. Detect monorepo so we can stage the build at the workspace
    //    root rather than inside the subpackage. The detector returns
    //    `null` when projectDir is not part of a workspace, or when it
    //    *is* the workspace root itself (single-package mode covers
    //    that case).
    const monorepo = await detectMonorepoContext(absoluteProjectDir);
    // In monorepo mode, the *workspace root's* package manager is the
    // one that owns install/build. A subpackage typically has no
    // lockfile of its own, so `detectPackageManager(projectDir)`
    // defaults to bun — which is wrong for npm/pnpm/yarn workspaces
    // and silently produces a rogue `bun.lock` at the root when the
    // build runs. Override here so every downstream step (install,
    // build, runtime manifests) sees the right pm.
    if (monorepo) {
        framework.packageManager = monorepo.packageManager;
    }
    const outputDir = input.outputDir
        ? resolve(input.outputDir)
        : join(monorepo?.root ?? absoluteProjectDir, '.agentuity');
    // 3. Typecheck before build (skip in dev mode or when explicitly
    //    disabled). Failing fast saves CI time when types are broken.
    let typecheckMs = 0;
    if (!input.dev && !input.skipTypeCheck) {
        const endTypecheck = collector.startDiagnostic('typecheck');
        const started = Date.now();
        const typeResult = await typecheck(absoluteProjectDir, {
            collector,
            typegenCommand: framework.typegenCommand,
        });
        endTypecheck();
        typecheckMs = Date.now() - started;
        if (!typeResult.success) {
            throw new TypecheckError(typeResult.output);
        }
        logs.push(`✓ Typechecked in ${typecheckMs}ms`);
    }
    // 4. Run the framework adapter's build. The adapter is responsible
    //    for staging artifacts into `outputDir`; in monorepo mode it
    //    mirrors the whole workspace tree, in single-package mode it
    //    copies the build output and runtime manifests directly.
    const endBuild = collector.startDiagnostic('build');
    const buildStarted = Date.now();
    const adapter = getAdapter(framework.name);
    const buildResult = await adapter.build({
        projectDir: absoluteProjectDir,
        framework,
        packageJson: packageJson ?? {},
        outputDir,
        logger,
        collector,
        dev: input.dev,
        projectId: input.projectId,
        orgId: input.orgId,
        region: input.region,
        deploymentId: input.deploymentId,
        deploymentOptions: input.deploymentOptions,
        deploymentConfig: input.deploymentConfig,
        monorepo: monorepo ?? undefined,
    });
    endBuild();
    const buildMs = Date.now() - buildStarted;
    logs.push(...buildResult.logs);
    // 5. Package the output — writes launch.json with `workingDirectory`
    //    set from monorepo.subpath when in monorepo mode.
    const packageResult = packageBuildOutput(framework, buildResult, buildResult.outputDir, absoluteProjectDir, monorepo ?? undefined);
    return {
        framework,
        packageJson,
        monorepo,
        buildResult,
        packageResult,
        outputDir: buildResult.outputDir,
        typecheckMs,
        buildMs,
        logs,
    };
}
//# sourceMappingURL=run.js.map