#!/usr/bin/env node
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// src/server/course-entry.ts
var fs2 = __toESM(require("node:fs"));
var path2 = __toESM(require("node:path"));

// src/server/cred-shape.ts
var fs = __toESM(require("node:fs"));
var path = __toESM(require("node:path"));
var CONFIG_FILENAME = ".launch-secure.cred.config";
function inferCourseName(serverUrl) {
  try {
    const host = new URL(serverUrl).hostname.toLowerCase();
    if (host === "localhost" || host === "127.0.0.1" || host.endsWith(".local")) return "local";
    if (host.includes("staging")) return "staging";
    if (host.endsWith(".vercel.app")) return "prod";
    return host.split(".")[0] || "default";
  } catch {
    return "default";
  }
}
function toNested(cred) {
  if (cred.profiles && cred.active && cred.profiles[cred.active]) {
    return { active: cred.active, profiles: cred.profiles };
  }
  if (!cred.pat || !cred.orgSlug || !cred.projectSlug || !cred.serverUrl) {
    return null;
  }
  const name = inferCourseName(cred.serverUrl);
  return {
    active: name,
    profiles: {
      [name]: {
        pat: cred.pat,
        orgSlug: cred.orgSlug,
        projectSlug: cred.projectSlug,
        serverUrl: cred.serverUrl
      }
    }
  };
}
function readCredFile(repoRoot) {
  const p = path.join(repoRoot, CONFIG_FILENAME);
  if (!fs.existsSync(p)) return null;
  try {
    return JSON.parse(fs.readFileSync(p, "utf-8"));
  } catch (err) {
    throw new Error(`could not parse ${CONFIG_FILENAME}: ${err instanceof Error ? err.message : String(err)}`);
  }
}
function writeJsonAtomic(absPath, value, mode) {
  const tmp = `${absPath}.tmp`;
  fs.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n", "utf-8");
  if (mode !== void 0) {
    try {
      fs.chmodSync(tmp, mode);
    } catch {
    }
  }
  fs.renameSync(tmp, absPath);
}

// src/server/course-entry.ts
var MCP_FILENAME = ".mcp.json";
var DEFAULT_SERVER_URL = "https://launchsecure-v2.vercel.app";
function info(msg) {
  console.log(`[launch-course] ${msg}`);
}
function ok(msg) {
  console.log(`[launch-course] \u2713 ${msg}`);
}
function fail(msg) {
  console.error(`[launch-course] \u2717 ${msg}`);
  process.exit(1);
}
function readCredFile2() {
  const cred = readCredFile(process.cwd());
  if (!cred) {
    fail(`${CONFIG_FILENAME} not found in ${process.cwd()}. Run \`npx @launchsecure/launch-kit init \u2026\` first.`);
  }
  return cred;
}
function toNested2(cred) {
  const nested = toNested(cred);
  if (!nested) {
    fail(`${CONFIG_FILENAME} is missing required fields (pat, orgSlug, projectSlug, serverUrl) and has no profiles. Run \`npx @launchsecure/launch-kit init \u2026\` to (re)bootstrap.`);
  }
  return nested;
}
function parseFlag(argv, key) {
  const prefix = `--${key}=`;
  const found = argv.find((a) => a.startsWith(prefix));
  return found ? found.slice(prefix.length) : void 0;
}
function cmdList() {
  const nested = toNested2(readCredFile2());
  const names = Object.keys(nested.profiles).sort();
  if (names.length === 0) {
    info("(no courses)");
    return;
  }
  info(`courses (${names.length}):`);
  const nameWidth = Math.max(...names.map((n) => n.length), 8);
  for (const name of names) {
    const p = nested.profiles[name];
    const marker = name === nested.active ? "\u2605" : " ";
    console.log(`  ${marker} ${name.padEnd(nameWidth)}  ${p.serverUrl}  (${p.orgSlug}/${p.projectSlug})`);
  }
}
function cmdAdd(argv) {
  const name = argv.find((a) => !a.startsWith("--"));
  if (!name) fail("usage: launch-course add <name> --token=ls_pat_... --org=<slug> --project=<slug> [--url=<serverUrl>]");
  const token = parseFlag(argv, "token");
  const org = parseFlag(argv, "org");
  const project = parseFlag(argv, "project");
  const url = (parseFlag(argv, "url") ?? DEFAULT_SERVER_URL).replace(/\/+$/, "");
  if (!token || !token.startsWith("ls_pat_")) fail("--token=<ls_pat_...> required");
  if (!org) fail("--org=<slug> required");
  if (!project) fail("--project=<slug> required");
  const nested = toNested2(readCredFile2());
  const existed = Boolean(nested.profiles[name]);
  nested.profiles[name] = { pat: token, orgSlug: org, projectSlug: project, serverUrl: url };
  writeJsonAtomic(path2.join(process.cwd(), CONFIG_FILENAME), nested, 384);
  ok(`${existed ? "updated" : "added"} course "${name}" (${url})`);
  if (nested.active !== name) {
    info(`active course is still "${nested.active}" \u2014 run \`launch-course set ${name}\` to switch`);
  }
}
function cmdSet(argv) {
  const name = argv[0];
  if (!name) fail("usage: launch-course set <name>");
  const nested = toNested2(readCredFile2());
  const target = nested.profiles[name];
  if (!target) {
    const known = Object.keys(nested.profiles).sort().join(", ") || "(none)";
    fail(`no course named "${name}". known: ${known}`);
  }
  if (nested.active === name) {
    info(`already on "${name}" \u2014 nothing to do`);
    return;
  }
  const next = { active: name, profiles: nested.profiles };
  writeJsonAtomic(path2.join(process.cwd(), CONFIG_FILENAME), next, 384);
  const mcpStatus = updateMcpUrl(target.serverUrl);
  ok(`active course \u2192 "${name}" (${target.serverUrl})`);
  if (mcpStatus === "updated") {
    info("reconnect MCP in Claude Code: /mcp \u2192 toggle launch-secure off/on (URL is read at connect time)");
  }
}
function cmdRm(argv) {
  const name = argv[0];
  if (!name) fail("usage: launch-course rm <name>");
  const nested = toNested2(readCredFile2());
  if (!nested.profiles[name]) fail(`no course named "${name}"`);
  if (nested.active === name) {
    fail(`cannot remove the active course "${name}". \`launch-course set <other>\` first.`);
  }
  delete nested.profiles[name];
  writeJsonAtomic(path2.join(process.cwd(), CONFIG_FILENAME), nested, 384);
  ok(`removed course "${name}"`);
}
function updateMcpUrl(serverUrl) {
  const p = path2.join(process.cwd(), MCP_FILENAME);
  if (!fs2.existsSync(p)) {
    info(`(no ${MCP_FILENAME} \u2014 skipped URL update; run \`npx @launchsecure/launch-kit init \u2026\` to wire MCP)`);
    return "missing-file";
  }
  let mcp;
  try {
    mcp = JSON.parse(fs2.readFileSync(p, "utf-8"));
  } catch (err) {
    fail(`could not parse ${MCP_FILENAME}: ${err instanceof Error ? err.message : String(err)}`);
  }
  const entry = mcp.mcpServers?.["launch-secure"];
  if (!entry) {
    info(`(no "launch-secure" entry in ${MCP_FILENAME} \u2014 skipped URL update)`);
    return "missing-entry";
  }
  entry.url = `${serverUrl.replace(/\/+$/, "")}/api/mcp/project`;
  writeJsonAtomic(p, mcp);
  ok(`updated ${MCP_FILENAME} launch-secure.url \u2192 ${entry.url}`);
  return "updated";
}
function help() {
  console.log(`launch-course \u2014 manage LaunchSecure server profiles ("courses").

Usage:
  launch-course list
  launch-course add <name> --token=ls_pat_... --org=<slug> --project=<slug> [--url=<serverUrl>]
  launch-course set <name>
  launch-course rm  <name>

The cred file (.launch-secure.cred.config) holds every course under \`profiles\`,
with \`active\` selecting which one drives MCP / launch-sequencer auth. Legacy flat
files are auto-migrated on the first multi-profile op. \`launch-course set\`
also rewrites .mcp.json's launch-secure.url so Claude Code routes to the right
server on next MCP reconnect.
`);
}
function main() {
  const [cmd, ...rest] = process.argv.slice(2);
  switch (cmd) {
    case "list":
      return cmdList();
    case "add":
      return cmdAdd(rest);
    case "set":
    case "use":
      return cmdSet(rest);
    case "rm":
    case "remove":
    case "delete":
      return cmdRm(rest);
    case void 0:
    case "help":
    case "--help":
    case "-h":
      return help();
    default:
      fail(`unknown command "${cmd}". try \`launch-course help\``);
  }
}
main();
