"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.setupPublish = setupPublish;
const chalk_1 = __importDefault(require("chalk"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importStar(require("path"));
const utils_js_1 = require("../utils.js");
const dirname__ = typeof __dirname !== 'undefined'
    ? __dirname
    : //@ts-ignore
        (0, path_1.dirname)(import.meta.url).replace('file:/', '');
// defaults/setup-publish/ lives at packages/cli/defaults/setup-publish/
// This file compiles to lib/{esm,cjs}/commands/setup-publish.js — go up three
// levels to reach the package root, then into defaults/setup-publish.
const TEMPLATE_ROOT = path_1.default.resolve(dirname__, '..', '..', '..', 'defaults', 'setup-publish');
/**
 * Set up a single-branch changesets publish workflow in the current package repo.
 *
 * Installs:
 * - .github/workflows/{ci,publish,changeset-check}.yml
 * - .changeset/config.json + README.md
 * - .changeset/initial-release.md
 * - .gitignore entries for node_modules, lib, yarn.lock, src-compiled-artifacts
 * - package.json: @changesets/cli + @changesets/changelog-github devDeps,
 *   publishConfig: {access: public}
 * - package-lock.json generated via npm install --package-lock-only
 *
 * With --configure-github: if `gh` CLI is available and authenticated, also sets
 * branch protection on main (strict + required "Build & Test" check).
 */
async function setupPublish(opts = {}) {
    const cwd = process.cwd();
    const scope = opts.scope || 'core';
    const npmSecretName = scope === 'community' ? 'NPM_AUTH_TOKEN_CM' : 'NPM_AUTH_TOKEN';
    const templateDir = opts.dualBranch
        ? path_1.default.join(TEMPLATE_ROOT, 'dual-branch')
        : TEMPLATE_ROOT;
    console.log(chalk_1.default.magenta(`Setting up ${opts.dualBranch ? 'dual-branch (main + dev)' : 'single-branch (main only)'} publish workflow...`));
    console.log(`  target: ${cwd}`);
    console.log(`  npm secret: ${npmSecretName} (${scope})`);
    const pkgJsonPath = path_1.default.join(cwd, 'package.json');
    if (!fs_extra_1.default.existsSync(pkgJsonPath)) {
        console.error(chalk_1.default.red('No package.json found in current directory. Run from the repo root.'));
        process.exit(1);
    }
    const pkgJson = JSON.parse(fs_extra_1.default.readFileSync(pkgJsonPath, 'utf8'));
    const repoSlug = await resolveRepoSlug(cwd, pkgJson);
    console.log(`  repo: ${repoSlug}`);
    console.log('');
    // 1. Workflow files (with {{NPM_SECRET_NAME}} substitution in publish.yml)
    await copyWorkflows(cwd, npmSecretName, templateDir);
    // 2. Changesets config + README
    await copyChangesetConfig(cwd, repoSlug, templateDir);
    // 3. Initial changeset
    await writeInitialChangeset(cwd, pkgJson.name);
    // 4. .gitignore
    await updateGitignore(cwd);
    // 5. package.json patches
    await patchPackageJson(pkgJsonPath, pkgJson);
    // 6. npm install --package-lock-only to generate lockfile (if not present)
    await ensureLockfile(cwd);
    // 7. Optional: configure GitHub branch protection
    if (opts.configureGithub) {
        await configureGithub(repoSlug);
    }
    // 8. Optional: grant a GitHub team push access
    if (opts.grantTeam) {
        await grantTeamAccess(repoSlug, opts.grantTeam);
    }
    // Summary + manual steps
    printNextSteps(repoSlug, npmSecretName, opts.configureGithub, opts.grantTeam);
}
async function resolveRepoSlug(cwd, pkgJson) {
    // Try git remote first
    try {
        const remoteUrl = await (0, utils_js_1.execPromise)('git config --get remote.origin.url', false, false, { cwd });
        const m = typeof remoteUrl === 'string' ? remoteUrl.match(/[:/]([^/:]+\/[^/]+?)(?:\.git)?\s*$/) : null;
        if (m)
            return m[1];
    }
    catch (_a) {
        // fall through
    }
    // Fallback: parse package.json repository
    const repoField = pkgJson.repository;
    if (typeof repoField === 'string') {
        const m = repoField.match(/github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
        if (m)
            return m[1];
    }
    else if (repoField === null || repoField === void 0 ? void 0 : repoField.url) {
        const m = repoField.url.match(/github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
        if (m)
            return m[1];
    }
    console.warn(chalk_1.default.yellow('Could not determine repo slug. Using placeholder "OWNER/REPO" — update .changeset/config.json manually.'));
    return 'OWNER/REPO';
}
async function copyWorkflows(cwd, npmSecretName, templateDir) {
    const srcDir = path_1.default.join(templateDir, 'github', 'workflows');
    const dstDir = path_1.default.join(cwd, '.github', 'workflows');
    fs_extra_1.default.mkdirpSync(dstDir);
    for (const file of ['ci.yml', 'publish.yml', 'changeset-check.yml']) {
        let content = fs_extra_1.default.readFileSync(path_1.default.join(srcDir, file), 'utf8');
        content = content.replace(/\{\{NPM_SECRET_NAME\}\}/g, npmSecretName);
        fs_extra_1.default.writeFileSync(path_1.default.join(dstDir, file), content);
        console.log(chalk_1.default.green('  ✓') + ` .github/workflows/${file}`);
    }
}
async function copyChangesetConfig(cwd, repoSlug, templateDir) {
    const srcDir = path_1.default.join(templateDir, 'changeset');
    const dstDir = path_1.default.join(cwd, '.changeset');
    fs_extra_1.default.mkdirpSync(dstDir);
    let configContent = fs_extra_1.default.readFileSync(path_1.default.join(srcDir, 'config.json'), 'utf8');
    configContent = configContent.replace(/\{\{REPO_SLUG\}\}/g, repoSlug);
    fs_extra_1.default.writeFileSync(path_1.default.join(dstDir, 'config.json'), configContent);
    console.log(chalk_1.default.green('  ✓') + ' .changeset/config.json');
    fs_extra_1.default.copyFileSync(path_1.default.join(srcDir, 'README.md'), path_1.default.join(dstDir, 'README.md'));
    console.log(chalk_1.default.green('  ✓') + ' .changeset/README.md');
}
async function writeInitialChangeset(cwd, pkgName) {
    const changelogPath = path_1.default.join(cwd, 'CHANGELOG.md');
    if (fs_extra_1.default.existsSync(changelogPath)) {
        console.log(chalk_1.default.gray('  · CHANGELOG.md exists — skipping initial changeset'));
        return;
    }
    const initial = path_1.default.join(cwd, '.changeset', 'initial-release.md');
    const body = `---\n'${pkgName}': patch\n---\n\nInitial release under the new publishing setup.\n`;
    fs_extra_1.default.writeFileSync(initial, body);
    console.log(chalk_1.default.green('  ✓') + ' .changeset/initial-release.md');
}
async function updateGitignore(cwd) {
    const gitignorePath = path_1.default.join(cwd, '.gitignore');
    const entries = [
        'node_modules/',
        'lib/',
        'yarn.lock',
        '*.log',
        '.DS_Store',
        '',
        '# tsc sourcemap output — always in lib/, never src/.',
        '# (.d.ts not ignored — hand-written type declarations like colors.d.ts',
        '#  are legit src files.)',
        'src/**/*.js.map',
    ];
    const existing = fs_extra_1.default.existsSync(gitignorePath)
        ? fs_extra_1.default.readFileSync(gitignorePath, 'utf8').split('\n')
        : [];
    const existingSet = new Set(existing.map((l) => l.trim()));
    const toAdd = entries.filter((e) => e && !existingSet.has(e.trim()));
    if (toAdd.length === 0) {
        console.log(chalk_1.default.gray('  · .gitignore already has all entries'));
        return;
    }
    const merged = [
        ...existing.filter((l) => l.trim() !== ''),
        '',
        ...entries,
    ].join('\n');
    fs_extra_1.default.writeFileSync(gitignorePath, merged + '\n');
    console.log(chalk_1.default.green('  ✓') + ' .gitignore');
}
async function patchPackageJson(pkgJsonPath, pkgJson) {
    let modified = false;
    if (!pkgJson.publishConfig) {
        pkgJson.publishConfig = { access: 'public' };
        modified = true;
    }
    else {
        if (pkgJson.publishConfig.access !== 'public') {
            pkgJson.publishConfig.access = 'public';
            modified = true;
        }
        // Strip provenance: true — it requires OIDC (id-token: write permission +
        // npm Trusted Publisher config), which conflicts with our NPM_AUTH_TOKEN
        // flow. Users who want provenance should use OIDC separately.
        if (pkgJson.publishConfig.provenance) {
            delete pkgJson.publishConfig.provenance;
            modified = true;
        }
    }
    pkgJson.devDependencies = pkgJson.devDependencies || {};
    if (!pkgJson.devDependencies['@changesets/cli']) {
        pkgJson.devDependencies['@changesets/cli'] = '^2.29.8';
        modified = true;
    }
    if (!pkgJson.devDependencies['@changesets/changelog-github']) {
        pkgJson.devDependencies['@changesets/changelog-github'] = '^0.5.2';
        modified = true;
    }
    if (modified) {
        fs_extra_1.default.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + '\n');
        console.log(chalk_1.default.green('  ✓') + ' package.json (publishConfig + changesets devDeps)');
    }
    else {
        console.log(chalk_1.default.gray('  · package.json already configured'));
    }
}
async function ensureLockfile(cwd) {
    // Always regenerate — package.json has just been patched (new devDeps etc.),
    // so any existing lockfile is stale.
    console.log(chalk_1.default.magenta('  Running npm install --package-lock-only...'));
    // When running inside a yarn workspace (e.g. CN's packages/* layout), npm
    // climbs up, detects the parent workspace, and writes the lockfile at the
    // wrong level. Work around by copying the package to a tmpdir, generating
    // the lockfile in isolation, and copying it back.
    const os = await Promise.resolve().then(() => __importStar(require('os')));
    const tmpBase = fs_extra_1.default.mkdtempSync(path_1.default.join(os.tmpdir(), 'linked-setup-'));
    const cacheDir = fs_extra_1.default.mkdtempSync(path_1.default.join(os.tmpdir(), 'linked-setup-cache-'));
    try {
        const pkgJsonPath = path_1.default.join(cwd, 'package.json');
        fs_extra_1.default.copyFileSync(pkgJsonPath, path_1.default.join(tmpBase, 'package.json'));
        await (0, utils_js_1.execp)(`npm install --legacy-peer-deps --package-lock-only --cache ${cacheDir}`, false, true, { cwd: tmpBase });
        const lockPath = path_1.default.join(tmpBase, 'package-lock.json');
        if (fs_extra_1.default.existsSync(lockPath)) {
            fs_extra_1.default.copyFileSync(lockPath, path_1.default.join(cwd, 'package-lock.json'));
            console.log(chalk_1.default.green('  ✓') + ' package-lock.json');
        }
        else {
            console.warn(chalk_1.default.yellow('  ⚠ npm install did not produce a package-lock.json — likely because a dependency is not yet published on npm.'));
            console.warn(chalk_1.default.yellow('    Regenerate manually once all deps are published: `npm install --package-lock-only`.'));
        }
    }
    catch (err) {
        console.warn(chalk_1.default.yellow('  ⚠ Failed to generate package-lock.json — likely because a dependency is not yet published on npm.'));
        console.warn(chalk_1.default.yellow('    Regenerate manually once all deps are published: `npm install --package-lock-only`.'));
    }
    finally {
        fs_extra_1.default.removeSync(tmpBase);
        fs_extra_1.default.removeSync(cacheDir);
    }
}
async function configureGithub(repoSlug) {
    console.log('');
    console.log(chalk_1.default.magenta('Configuring GitHub (branch protection)...'));
    // Check gh CLI available
    try {
        await (0, utils_js_1.execPromise)('gh --version', false, false);
    }
    catch (_a) {
        console.warn(chalk_1.default.yellow('  ⚠ `gh` CLI not found. Install from https://cli.github.com/ and retry with --configure-github,'));
        console.warn(chalk_1.default.yellow('    or set branch protection manually at https://github.com/' + repoSlug + '/settings/branches'));
        return;
    }
    // Check gh CLI authenticated
    try {
        await (0, utils_js_1.execPromise)('gh auth status', false, false);
    }
    catch (_b) {
        console.warn(chalk_1.default.yellow('  ⚠ `gh` CLI is not authenticated. Run `gh auth login` and retry.'));
        return;
    }
    const payload = JSON.stringify({
        required_status_checks: { strict: true, contexts: ['Build & Test'] },
        enforce_admins: false,
        required_pull_request_reviews: null,
        restrictions: null,
        allow_force_pushes: false,
        allow_deletions: false,
    });
    try {
        // Use --input - to pass the JSON payload via stdin
        await (0, utils_js_1.execPromise)(`echo '${payload.replace(/'/g, "'\\''")}' | gh api -X PUT /repos/${repoSlug}/branches/main/protection --input -`, false, false);
        console.log(chalk_1.default.green('  ✓') + ` branch protection enabled on ${repoSlug}/main`);
    }
    catch (err) {
        console.warn(chalk_1.default.yellow('  ⚠ Failed to set branch protection. Do it manually:'));
        console.warn(chalk_1.default.yellow(`    https://github.com/${repoSlug}/settings/branches`));
    }
}
async function grantTeamAccess(repoSlug, teamSlug) {
    console.log('');
    console.log(chalk_1.default.magenta(`Granting '${teamSlug}' team push access to ${repoSlug}...`));
    try {
        await (0, utils_js_1.execPromise)('gh --version', false, false);
    }
    catch (_a) {
        console.warn(chalk_1.default.yellow("  ⚠ `gh` CLI not found. Install from https://cli.github.com/ and retry with --grant-team,"));
        console.warn(chalk_1.default.yellow(`    or add the team manually at https://github.com/${repoSlug}/settings/access`));
        return;
    }
    const [owner, repo] = repoSlug.split('/');
    try {
        await (0, utils_js_1.execPromise)(`gh api -X PUT /orgs/${owner}/teams/${teamSlug}/repos/${owner}/${repo} -f permission=push`, false, false);
        console.log(chalk_1.default.green('  ✓') + ` team '${teamSlug}' granted push access on ${repoSlug}`);
    }
    catch (err) {
        const msg = (err === null || err === void 0 ? void 0 : err.stderr) || (err === null || err === void 0 ? void 0 : err.stdout) || String(err);
        console.warn(chalk_1.default.yellow(`  ⚠ Failed to grant team access: ${msg.slice(0, 200)}`));
        console.warn(chalk_1.default.yellow(`    Team may not exist in org '${owner}', or you may lack admin rights.`));
        console.warn(chalk_1.default.yellow(`    Manual: https://github.com/${repoSlug}/settings/access`));
    }
}
function printNextSteps(repoSlug, npmSecretName, configuredGithub, grantedTeam) {
    console.log('');
    console.log(chalk_1.default.green('Done.'));
    console.log('');
    console.log(chalk_1.default.bold('Next steps:'));
    console.log('');
    console.log(`  1. Review the generated files, adjust as needed.`);
    console.log(`  2. Commit:`);
    console.log(chalk_1.default.cyan('       git add . && git commit -m "set up single-branch publish workflow"'));
    console.log(`  3. Push to main — the publish workflow will trigger.`);
    console.log('');
    console.log(chalk_1.default.bold('One-time org-level setup (if not already done):'));
    console.log('');
    console.log(`  a. Create an org secret ${chalk_1.default.cyan(npmSecretName)} with a granular npm token`);
    console.log(`     (2FA-bypass, write access to the @_linked* scope).`);
    console.log(`     → https://github.com/organizations/${repoSlug.split('/')[0]}/settings/secrets/actions`);
    console.log('');
    console.log(`  b. Enable "Allow GitHub Actions to create and approve pull requests":`);
    console.log(`     → https://github.com/organizations/${repoSlug.split('/')[0]}/settings/actions`);
    if (!configuredGithub) {
        console.log('');
        console.log(chalk_1.default.bold('Branch protection:'));
        console.log(`  Rerun with ${chalk_1.default.cyan('linked setup-publish --configure-github')} to configure automatically,`);
        console.log(`  or set manually at https://github.com/${repoSlug}/settings/branches`);
    }
    console.log('');
}
//# sourceMappingURL=setup-publish.js.map