/**
 * dispatch.mjs — D-02 (c) wrap() helper + DISPATCH map.
 *
 * Layer 2 of the post-refactor architecture (D-02 (c) — early dispatcher
 * migration). Two responsibilities:
 *
 *   1. wrap(cmdFn) — adapts a Layer 1 cmd (sync or async) into a CLI handler.
 *      Recognises EXACTLY two acceptable return shapes (post-Wave-3, S20):
 *        a. JSON shape    — { envelope, exitCode } (typeof exitCode === 'number')
 *           → output(envelope) + (exitCode !== 0 ? process.exit(exitCode))
 *        b. RAW-TEXT shape — { rawText, exitCode } (typeof rawText === 'string')
 *           → process.stdout.write(rawText) + (exitCode !== 0 ? process.exit(exitCode))
 *           Used by cmds that emit non-JSON content: template, effects list,
 *           consistency check --format human, statusline plain, precompact-hook,
 *           init TTY mode (clack rendered the outro already).
 *      ANY other return shape — including the previously-tolerated `undefined`
 *      — is a partial-migration bug; trips fail() with a "non-conforming shape"
 *      message (Codex pass 2 rev A). Errors thrown out of cmdFn become
 *      fail(err.message).
 *
 *   2. DISPATCH — the command-name → handler map. Each handler slices argv into
 *      the cmd's expected positional/extra-flags shape and calls wrap(cmdFn).
 *      Domain-specific rejection envelopes (taste-infer, terminal) MUST be
 *      returned via exitWith(envelope, exitCode) inside the cmd — wrap()'s own
 *      try/catch consumes thrown errors before any per-cmd .catch() could fire,
 *      so throwing is not a valid D-04 backward-compat mechanism.
 *
 * History — the legacy-tolerance branch:
 *   Pre-S20, wrap() also accepted `result === undefined` and returned
 *   silently — a transitional escape hatch for cmds that wrote stdout
 *   themselves and called process.exit() inline. Subtask 19 closed the
 *   end-of-Wave-3 grep-zero invariant (no `process.exit` in any cmd file),
 *   so subtask 20 deleted the branch. Any cmd returning undefined now is
 *   indistinguishable from a partial-migration regression.
 */
import { cmdActive } from './commands/active.mjs';
import { cmdAdr } from './commands/adr.mjs';
import { cmdAudit } from './commands/audit.mjs';
import { cmdAuthorSkill } from './commands/author-skill.mjs';
import { cmdBootstrap } from './commands/bootstrap.mjs';
import { cmdCheck } from './commands/check.mjs';
import { cmdCheckVersion } from './commands/check-version.mjs';
import { cmdCiWatch, cmdCiWatchSweep } from './commands/ci-watch.mjs';
import { cmdCommit } from './commands/commit.mjs';
import { cmdConsistency } from './commands/consistency.mjs';
import { cmdConstitution } from './commands/constitution.mjs';
import { cmdContext } from './commands/context.mjs';
import { cmdCoverageCheck } from './commands/coverage-check.mjs';
import { cmdCreateDocs } from './commands/create-docs.mjs';
import { cmdDesignLint } from './commands/design-lint.mjs';
import { cmdDesignScan } from './commands/design-scan.mjs';
import { cmdDesignTemplate } from './commands/design-template.mjs';
import { cmdDesignValidate } from './commands/design-validate.mjs';
import { cmdDetectProject } from './commands/detect-project.mjs';
import { cmdDetectRuntime } from './commands/detect-runtime.mjs';
import { cmdDocsAudit } from './commands/docs-audit.mjs';
import { cmdDriverDoctor } from './commands/driver-doctor.mjs';
import { cmdEditCheck } from './commands/edit-check.mjs';
import { cmdEffects } from './commands/effects.mjs';
import { cmdEvent } from './commands/event.mjs';
import { cmdFanOut } from './commands/fan-out.mjs';
import { cmdFeaturesAudit } from './commands/features-audit.mjs';
import { cmdGate } from './commands/gate.mjs';
import { cmdHealthCheck } from './commands/health-check.mjs';
import { cmdHostDetect, cmdReconcile } from './commands/host-detect.mjs';
import { cmdInit } from './commands/init.mjs';
import { cmdInitState } from './commands/init-state.mjs';
import { cmdInstallFromSource } from './commands/install-from-source.mjs';
import { cmdLock } from './commands/lock.mjs';
import { cmdMigratePrReviews } from './commands/migrate-pr-reviews.mjs';
import { cmdPersonas } from './commands/personas.mjs';
import { cmdPlanApproval } from './commands/plan-approval.mjs';
import { cmdPrReview } from './commands/pr-review.mjs';
import { cmdPrecompactHook } from './commands/precompact-hook.mjs';
import { cmdProductContext } from './commands/product-context.mjs';
import { cmdProfile } from './commands/profile.mjs';
import { cmdReleaseNotes } from './commands/release-notes.mjs';
import { cmdRiskCheck } from './commands/risk-check.mjs';
import { cmdRoadmap } from './commands/roadmap.mjs';
import { cmdRoute } from './commands/route.mjs';
import { cmdSeed } from './commands/seed.mjs';
import { cmdStandards } from './commands/standards.mjs';
import { cmdConfig, cmdState, cmdStateArtifacts, cmdStateUpdate } from './commands/state.mjs';
import { cmdStatusline } from './commands/statusline.mjs';
import { cmdTask } from './commands/task.mjs';
import { cmdTasteInfer } from './commands/taste-infer.mjs';
import { cmdTeam } from './commands/team.mjs';
import { cmdTemplate } from './commands/template.mjs';
import { cmdTerminal } from './commands/terminal.mjs';
import { cmdTokenBudget } from './commands/token-budget.mjs';
import { cmdTokens } from './commands/tokens.mjs';
import { cmdToolchainDetect } from './commands/toolchain-detect.mjs';
import { cmdTriage } from './commands/triage.mjs';
import { cmdUninstall } from './commands/uninstall.mjs';
import { cmdValidateEvidence } from './commands/validate-evidence.mjs';
import { cmdVariantGallery } from './commands/variant-gallery.mjs';
import { cmdVariantPick } from './commands/variant-pick.mjs';
import { cmdVariantPool } from './commands/variant-pool.mjs';
import { cmdVitestDoctor } from './commands/vitest-doctor.mjs';
import { cmdWave } from './commands/wave.mjs';
import { cmdWfrun } from './commands/wfrun.mjs';
import { cmdWorkflow } from './commands/workflow.mjs';
import { cmdDetectWorktree, cmdWorktree } from './commands/worktree.mjs';
import { cmdWorktreeInstall } from './commands/worktree-install.mjs';
import { fail, output } from './util/io.mjs';
// ===========================================================================
// wrap()
// ===========================================================================
/**
 * Adapt a cmdX function (any return shape) into a CLI handler that writes
 * stdout and exits.
 *
 * @param {Function} cmdFn
 * @returns {(...argv: unknown[]) => Promise<void>}
 */
export function wrap(cmdFn) {
    return async (...argv) => {
        let result;
        try {
            result = await cmdFn(...argv);
        }
        catch (err) {
            fail(err && err.message ? err.message : String(err));
            return; // unreachable (fail() exits) but guards against future changes.
        }
        // Subtask 20 removed the legacy-tolerance branch
        // (`if (result === undefined) return`). After end-of-Wave-3 every cmd
        // returns one of the two recognised shapes; an `undefined` return is
        // indistinguishable from a partial-migration bug and falls through to
        // the non-conforming-shape fail() below.
        if (result !== null &&
            typeof result === 'object' &&
            'envelope' in result &&
            typeof ( /** @type {{exitCode: unknown}} */(result).exitCode) === 'number') {
            const { envelope, exitCode } = /** @type {{envelope: unknown, exitCode: number}} */ (result);
            output(envelope);
            if (exitCode !== 0)
                process.exit(exitCode);
            return;
        }
        // Subtask 15 — RAW-TEXT shape. Cmds that emit non-JSON content (template,
        // effects list, consistency check --format human, precompact-hook) return
        // `{ rawText: string, exitCode: number }` so they can carry a non-zero
        // exit code without calling process.exit() inside the cmd body.
        if (result !== null &&
            typeof result === 'object' &&
            'rawText' in result &&
            typeof ( /** @type {{rawText: unknown}} */(result).rawText) === 'string' &&
            typeof ( /** @type {{exitCode: unknown}} */(result).exitCode) === 'number') {
            const { rawText, exitCode } = /** @type {{rawText: string, exitCode: number}} */ (result);
            process.stdout.write(rawText);
            if (exitCode !== 0)
                process.exit(exitCode);
            return;
        }
        // Codex pass 2 revision A — fail-fast on non-conforming shapes. Bound
        // the offending shape's preview to 200 chars so the error stays scannable.
        let shapePreview;
        try {
            shapePreview = JSON.stringify(result);
            if (typeof shapePreview === 'string' && shapePreview.length > 200) {
                shapePreview = shapePreview.slice(0, 200) + '…';
            }
        }
        catch {
            shapePreview = String(result);
        }
        fail(`wrap(): cmdFn returned non-conforming shape: ${shapePreview} ` +
            `— expected { envelope, exitCode } or { rawText, exitCode }`);
    };
}
// ===========================================================================
// DISPATCH map — one entry per top-level subcommand.
// ===========================================================================
/** @type {Record<string, (args: string[]) => Promise<void>>} */
export const DISPATCH = {
    // ---- cwd-default + alias special cases ----
    init: (args) => {
        const hasProjectDir = args[1] && !args[1].startsWith('--');
        const initProjectDir = hasProjectDir ? args[1] : '.';
        const initExtra = hasProjectDir ? args.slice(2) : args.slice(1);
        return wrap(cmdInit)(initProjectDir, initExtra);
    },
    uninstall: (args) => {
        const hasProjectDir = args[1] && !args[1].startsWith('--');
        const unProjectDir = hasProjectDir ? args[1] : '.';
        const unExtra = hasProjectDir ? args.slice(2) : args.slice(1);
        return wrap(cmdUninstall)(unProjectDir, unExtra);
    },
    check: (args) => {
        const checkHasProjectDir = args[1] && !args[1].startsWith('--');
        const checkProjectDir = checkHasProjectDir ? args[1] : '.';
        const checkExtra = checkHasProjectDir ? args.slice(2) : args.slice(1);
        return wrap(cmdCheck)(checkProjectDir, checkExtra);
    },
    nyquist: (args) => {
        // Deprecated alias. Emit stderr warning + delegate to coverage-check.
        process.stderr.write('[apt-tools] warning: `nyquist` is deprecated, use `coverage-check`\n');
        return wrap(cmdCoverageCheck)(args[1], args[2], args.slice(3));
    },
    // ---- (positional dir, slice(2)) shape ----
    state: (args) => wrap(cmdState)(args[1]),
    config: (args) => wrap(cmdConfig)(args[1], args.slice(2)),
    'state-update': (args) => wrap(cmdStateUpdate)(args[1], args.slice(2)),
    'state-artifacts': (args) => wrap(cmdStateArtifacts)(args[1], args.slice(2)),
    'detect-project': (args) => wrap(cmdDetectProject)(args[1]),
    'detect-runtime': (args) => wrap(cmdDetectRuntime)(args[1], args.slice(2)),
    driver: (args) => {
        // `apt-tools driver doctor <project-dir>` — only subcommand for now.
        if (args[1] === 'doctor')
            return wrap(cmdDriverDoctor)(args[2], args.slice(3));
        return wrap(() => ({
            envelope: {
                status: 'error',
                error: `Usage: apt-tools driver doctor <project-dir>. Unknown subcommand: ${args[1] ?? '(none)'}`,
            },
            exitCode: 1,
        }))();
    },
    'features-audit': (args) => wrap(cmdFeaturesAudit)(args[1], args.slice(2)),
    'init-state': (args) => wrap(cmdInitState)(args[1], args.slice(2)),
    'risk-check': (args) => wrap(cmdRiskCheck)(args[1], args.slice(2)),
    'edit-check': (args) => wrap(cmdEditCheck)(args.slice(1)),
    commit: (args) => wrap(cmdCommit)(args.slice(1)),
    'token-budget': (args) => wrap(cmdTokenBudget)(args.slice(1), '.'),
    'design-scan': (args) => wrap(cmdDesignScan)(args[1], args.slice(2)),
    'design-validate': (args) => wrap(cmdDesignValidate)(args[1], args.slice(2)),
    'design-lint': (args) => wrap(cmdDesignLint)(args[1], args.slice(2)),
    'product-context': (args) => wrap(cmdProductContext)(args[1], args.slice(2)),
    bootstrap: (args) => wrap(cmdBootstrap)(args[1], args.slice(2)),
    personas: (args) => wrap(cmdPersonas)(args[1], args.slice(2)),
    'create-docs': (args) => wrap(cmdCreateDocs)(args[1], args.slice(2)),
    'variant-pool': (args) => wrap(cmdVariantPool)(args.slice(1)),
    'variant-gallery': (args) => wrap(cmdVariantGallery)(args[1], args.slice(2)),
    'worktree-install': (args) => wrap(cmdWorktreeInstall)(args[1], args.slice(2)),
    'detect-worktree': (args) => wrap(cmdDetectWorktree)(args[1]),
    template: (args) => wrap(cmdTemplate)(args[1]),
    'check-version': (args) => wrap(cmdCheckVersion)(args[1]),
    'install-from-source': (args) => wrap(cmdInstallFromSource)(args[1]),
    'health-check': (args) => wrap(cmdHealthCheck)(args[1]),
    route: (args) => wrap(cmdRoute)(args[1], args.slice(2)),
    statusline: (args) => wrap(cmdStatusline)(args[1], args.slice(2)),
    'author-skill': (args) => wrap(cmdAuthorSkill)(args[1], args.slice(2)),
    'toolchain-detect': (args) => wrap(cmdToolchainDetect)(args[1], args.slice(2)),
    'host-detect': () => wrap(cmdHostDetect)(),
    reconcile: (args) => wrap(cmdReconcile)(args[1], args.slice(2)),
    standards: (args) => wrap(cmdStandards)(args[1], args.slice(2)),
    'precompact-hook': (args) => wrap(cmdPrecompactHook)(args[1]),
    'migrate-pr-reviews': (args) => wrap(cmdMigratePrReviews)(args[1]),
    'validate-evidence': (args) => wrap(cmdValidateEvidence)(args[1], args.slice(2)),
    vitest: (args) => {
        // `vitest doctor <project-dir>` — currently the only `vitest`
        // subcommand. Reserved namespace for future vitest diagnostics.
        const subcommand = args[1];
        if (subcommand === 'doctor') {
            return wrap(cmdVitestDoctor)(args[2], args.slice(3));
        }
        return wrap(() => ({
            envelope: {
                status: 'error',
                error: `Usage: apt-tools vitest doctor <project-dir>. Unknown subcommand: ${subcommand ?? '(none)'}`,
            },
            exitCode: 1,
        }))();
    },
    // ---- (positional dir, args[2] subcommand, slice(3)) shape ----
    tokens: (args) => wrap(cmdTokens)(args[1], args[2], args.slice(3)),
    task: (args) => wrap(cmdTask)(args[1], args[2], args.slice(3)),
    lock: (args) => wrap(cmdLock)(args[1], args[2], args.slice(3)),
    event: (args) => wrap(cmdEvent)(args[1], args[2], args.slice(3)),
    effects: (args) => wrap(cmdEffects)(args[1], args[2], args.slice(3)),
    wave: (args) => wrap(cmdWave)(args[1], args[2], args.slice(3)),
    'fan-out': (args) => wrap(cmdFanOut)(args[1], args[2], args.slice(3)),
    'coverage-check': (args) => wrap(cmdCoverageCheck)(args[1], args[2], args.slice(3)),
    'design-template': (args) => wrap(cmdDesignTemplate)(args[1], args[2], args.slice(3)),
    'variant-pick': (args) => wrap(cmdVariantPick)(args[1], args[2], args.slice(3)),
    worktree: (args) => wrap(cmdWorktree)(args[1], args[2], args.slice(3)),
    audit: (args) => wrap(cmdAudit)(args[1], args[2], args.slice(3)),
    'release-notes': (args) => wrap(cmdReleaseNotes)(args[1], args[2], args.slice(3)),
    team: (args) => wrap(cmdTeam)(args[1], args[2], args.slice(3)),
    active: (args) => wrap(cmdActive)(args[1], args[2], args.slice(3)),
    roadmap: (args) => wrap(cmdRoadmap)(args[1], args[2], args.slice(3)),
    seed: (args) => wrap(cmdSeed)(args[1], args[2], args.slice(3)),
    workflow: (args) => wrap(cmdWorkflow)(args[1], args[2], args.slice(3)),
    'pr-review': (args) => wrap(cmdPrReview)(args[1], args[2], args.slice(3)),
    'ci-watch': (args) => {
        // `sweep` is async; route it to the async sibling so the sync dispatcher
        // path doesn't return a CommandResult | Promise<CommandResult> union.
        if (args[1] === 'sweep')
            return wrap(cmdCiWatchSweep)(args[2], args.slice(3));
        return wrap(cmdCiWatch)(args[1], args[2], args.slice(3));
    },
    'plan-approval': (args) => wrap(cmdPlanApproval)(args[1], args[2], args.slice(3)),
    // ---- Aperant adoption (ST-5, ST-6, ST-10, ST-13) artifact writers + discoverability ----
    context: (args) => wrap(cmdContext)(args[1], args[2], args.slice(3)),
    adr: (args) => wrap(cmdAdr)(args[1], args[2], args.slice(3)),
    triage: (args) => wrap(cmdTriage)(args[1], args[2], args.slice(3)),
    modes: async (args) => {
        const { cmdModes } = await import('./commands/modes.mjs');
        return wrap(cmdModes)(args[1], args[2], args.slice(3));
    },
    // ---- async cmds — wrap() awaits internally; thrown errors → fail() ----
    'docs-audit': (args) => wrap(cmdDocsAudit)(args[1], args.slice(2)),
    gate: (args) => wrap(cmdGate)(args[1], args[2], args.slice(3)),
    constitution: (args) => wrap(cmdConstitution)(args[1], args[2], args.slice(3)),
    profile: (args) => wrap(cmdProfile)(args[1], args[2], args.slice(3)),
    consistency: (args) => wrap(cmdConsistency)(args[1], args[2], args.slice(3)),
    wfrun: (args) => wrap(cmdWfrun)(args[1], args[2], args.slice(3)),
    // ---- cmds that previously had custom-rejection-envelope .catch() wrappers ----
    // taste-infer and terminal both funnel every error path into try/catch blocks
    // inside the cmd body that return domain-specific envelopes via exitWith().
    // wrap()'s own try/catch consumes any thrown error before a .catch() could
    // fire (fail() exits the process synchronously), so per-cmd .catch wrappers
    // are unreachable. Domain-specific rejection shapes MUST be returned via
    // exitWith(envelope, exitCode) — throwing is not the D-04 contract.
    'taste-infer': (args) => wrap(cmdTasteInfer)(args[1], args.slice(2)),
    terminal: (args) => wrap(cmdTerminal)(args[1], args.slice(2)),
};
//# sourceMappingURL=dispatch.mjs.map