#!/usr/bin/env node
import {
  deriveInstallMode,
  getAvailableSkills,
  resolveAlias
} from "./chunk-TZXYBG3R.js";
import {
  typedEntries,
  typedKeys
} from "./chunk-T4EXUIBY.js";
import {
  warn
} from "./chunk-LWXRUR6B.js";
import {
  BUILT_IN_DOMAIN_ORDER,
  DEFAULT_PRESELECTED_SKILLS,
  DEFAULT_PUBLIC_SOURCE_NAME,
  SOURCE_DISPLAY_NAMES
} from "./chunk-6OWHQ7HM.js";
import {
  init_esm_shims
} from "./chunk-DHET7RCE.js";

// src/cli/stores/wizard-store.ts
init_esm_shims();
import { unique } from "remeda";
import { create } from "zustand";

// src/cli/lib/wizard/build-step-logic.ts
init_esm_shims();
import { sortBy } from "remeda";
var FRAMEWORK_CATEGORY_ID = "web-framework";
var WEB_DOMAIN_ID = "web";
function validateBuildStep(categories, selections) {
  for (const category of categories) {
    if (category.required) {
      const categorySelections = selections[category.id] || [];
      if (categorySelections.length === 0) {
        return {
          valid: false,
          message: `Select at least one skill from the ${category.displayName} category. Use arrow keys to navigate, then SPACE to select.`
        };
      }
    }
  }
  return { valid: true };
}
function computeOptionState(skill) {
  if (skill.discouraged) {
    return "discouraged";
  }
  if (skill.recommended) {
    return "recommended";
  }
  return "normal";
}
function getSkillDisplayLabel(skill) {
  return skill.displayName;
}
function getStateReason(skill) {
  if (skill.discouraged && skill.discouragedReason) {
    return skill.discouragedReason;
  }
  if (skill.recommended && skill.recommendedReason) {
    return skill.recommendedReason;
  }
  return void 0;
}
function isFrameworkSelected(selections) {
  const frameworkSelections = selections[FRAMEWORK_CATEGORY_ID] ?? [];
  return frameworkSelections.length > 0;
}
function getSelectedFrameworks(selections, matrix) {
  const frameworkSelections = selections[FRAMEWORK_CATEGORY_ID] ?? [];
  return frameworkSelections.map((alias) => resolveAlias(alias, matrix));
}
function isCompatibleWithSelectedFrameworks(skillId, selectedFrameworkIds, matrix) {
  const skill = matrix.skills[skillId];
  if (!skill) return false;
  if (skill.compatibleWith.length === 0) {
    return true;
  }
  return selectedFrameworkIds.some((frameworkId) => skill.compatibleWith.includes(frameworkId));
}
function buildCategoriesForDomain(domain, allSelections, matrix, selections, installedSkillIds, skillConfigs) {
  const frameworkSource = selections;
  const frameworkSelected = isFrameworkSelected(frameworkSource);
  const selectedFrameworkIds = frameworkSelected ? getSelectedFrameworks(frameworkSource, matrix) : [];
  const categories = sortBy(
    Object.values(matrix.categories).filter(
      (cat) => cat.domain === domain
    ),
    (cat) => cat.order ?? 0
  );
  const categoryRows = categories.map((cat) => {
    const skillOptions = getAvailableSkills(cat.id, allSelections, matrix);
    const useFrameworkFilter = domain === WEB_DOMAIN_ID && cat.id !== FRAMEWORK_CATEGORY_ID && frameworkSelected;
    const filteredSkillOptions = useFrameworkFilter ? skillOptions.filter(
      (skill) => isCompatibleWithSelectedFrameworks(skill.id, selectedFrameworkIds, matrix)
    ) : skillOptions;
    const options = filteredSkillOptions.map((skill) => ({
      id: skill.id,
      label: getSkillDisplayLabel(skill),
      state: computeOptionState(skill),
      stateReason: getStateReason(skill),
      selected: skill.selected,
      local: matrix.skills[skill.id]?.local,
      installed: installedSkillIds?.includes(skill.id) || false,
      scope: skillConfigs?.find((sc) => sc.id === skill.id)?.scope
    }));
    return {
      id: cat.id,
      displayName: cat.displayName,
      required: cat.required ?? false,
      exclusive: cat.exclusive ?? true,
      options
    };
  });
  return categoryRows.filter((row) => row.options.length > 0);
}

// src/cli/stores/wizard-store.ts
var BUILT_IN_DOMAINS = ["web", "api", "cli", "mobile", "shared"];
function createDefaultSkillConfig(id) {
  return { id, scope: "project", source: DEFAULT_PUBLIC_SOURCE_NAME };
}
function getAllDomainsFromCategories(categories) {
  const allDomains = unique(
    Object.values(categories).map((cat) => cat?.domain).filter((d) => d != null)
  );
  return [...BUILT_IN_DOMAINS, ...allDomains.filter((d) => !BUILT_IN_DOMAINS.includes(d))];
}
function sortDomainsCanonically(domains) {
  const builtInSet = new Set(BUILT_IN_DOMAIN_ORDER);
  return [
    ...domains.filter((d) => !builtInSet.has(d)).sort(),
    ...BUILT_IN_DOMAIN_ORDER.filter((d) => domains.includes(d))
  ];
}
var DOMAIN_AGENTS = {
  web: [
    "web-developer",
    "web-reviewer",
    "web-researcher",
    "web-tester",
    "web-pm",
    "web-architecture"
  ],
  api: ["api-developer", "api-reviewer", "api-researcher"],
  cli: ["cli-developer", "cli-tester", "cli-reviewer"]
};
var SOURCE_SORT_TIER_LOCAL = 1;
var SOURCE_SORT_TIER_SCOPED = 2;
var SOURCE_SORT_TIER_PUBLIC = 3;
var SOURCE_SORT_TIER_THIRD_PARTY = 4;
function getSourceSortTier(source) {
  if (source.type === "local") return SOURCE_SORT_TIER_LOCAL;
  if (source.primary) return SOURCE_SORT_TIER_SCOPED;
  if (source.type === "public") return SOURCE_SORT_TIER_PUBLIC;
  return SOURCE_SORT_TIER_THIRD_PARTY;
}
function formatSourceLabel(source) {
  const displayName = SOURCE_DISPLAY_NAMES[source.name] ?? source.name;
  const prefix = source.installed ? "\u2713 " : "";
  return `${prefix}${displayName}`;
}
function resolveSkillForPopulation(skillId, skills, categories) {
  const skill = skills[skillId];
  if (!skill?.category) {
    warn(
      `Installed skill '${skillId}' is missing from the marketplace \u2014 it may have been removed or renamed`
    );
    return null;
  }
  const subcat = skill.category;
  const domain = categories[subcat]?.domain;
  if (!domain) {
    warn(`Installed skill '${skillId}' has unknown category '${skill.category}' \u2014 skipping`);
    return null;
  }
  return { domain, subcat, techId: skillId };
}
function buildBoundSkillOptions(boundSkills, alias, selectedSource) {
  return boundSkills.filter((b) => b.boundTo === alias).map((bound) => ({
    id: bound.sourceName,
    label: formatSourceLabel({
      name: bound.sourceName,
      installed: false
    }),
    selected: selectedSource === bound.sourceName,
    installed: false
  }));
}
function getSkillAlias(skillId, matrix) {
  const slug = matrix.slugMap.idToSlug[skillId];
  if (slug) return slug;
  const segments = skillId.split("-");
  const fallback = segments[segments.length - 1] || skillId;
  warn(`No slug found for skill '${skillId}', using fallback alias '${fallback}'`);
  return fallback;
}
var createInitialState = () => ({
  step: "stack",
  approach: null,
  selectedStackId: null,
  stackAction: null,
  selectedDomains: [],
  currentDomainIndex: 0,
  domainSelections: {},
  /** Snapshot of domainSelections from populateFromStack/populateFromSkillIds, used to restore on domain re-toggle */
  _stackDomainSelections: null,
  showLabels: false,
  skillConfigs: [],
  focusedSkillId: null,
  customizeSources: false,
  showSettings: false,
  showHelp: false,
  enabledSources: {},
  selectedAgents: [],
  agentConfigs: [],
  focusedAgentId: null,
  boundSkills: [],
  lockedSkillIds: [],
  lockedAgentNames: [],
  history: []
});
var useWizardStore = create((set, get) => ({
  ...createInitialState(),
  setStep: (step) => set((state) => ({
    step,
    history: [...state.history, state.step]
  })),
  setApproach: (approach) => set({ approach }),
  selectStack: (stackId) => set({ selectedStackId: stackId }),
  setStackAction: (action) => set({ stackAction: action }),
  populateFromStack: (stack, categories) => set(() => {
    const domainSelections = {};
    const domains = /* @__PURE__ */ new Set();
    const allSkillIds = /* @__PURE__ */ new Set();
    for (const agentConfig of Object.values(stack.agents)) {
      for (const [subcat, assignments] of typedEntries(
        agentConfig
      )) {
        const category = categories[subcat];
        const domain = category?.domain;
        if (!domain || !assignments) {
          continue;
        }
        domains.add(domain);
        if (!domainSelections[domain]) {
          domainSelections[domain] = {};
        }
        if (!domainSelections[domain][subcat]) {
          domainSelections[domain][subcat] = [];
        }
        for (const assignment of assignments) {
          if (!domainSelections[domain][subcat].includes(assignment.id)) {
            domainSelections[domain][subcat].push(assignment.id);
            allSkillIds.add(assignment.id);
          }
        }
      }
    }
    const skillConfigs = [...allSkillIds].map(createDefaultSkillConfig);
    return {
      domainSelections,
      _stackDomainSelections: structuredClone(domainSelections),
      selectedDomains: sortDomainsCanonically(getAllDomainsFromCategories(categories)),
      skillConfigs
    };
  }),
  populateFromSkillIds: (skillIds, skills, categories, savedConfigs) => set(() => {
    const domainSelections = {};
    const resolvedSkillIds = [];
    let skippedCount = 0;
    for (const skillId of skillIds) {
      const resolved = resolveSkillForPopulation(skillId, skills, categories);
      if (!resolved) {
        skippedCount++;
        continue;
      }
      const { domain, subcat, techId } = resolved;
      if (!domainSelections[domain]) domainSelections[domain] = {};
      if (!domainSelections[domain][subcat]) domainSelections[domain][subcat] = [];
      if (!domainSelections[domain][subcat].includes(techId)) {
        domainSelections[domain][subcat].push(techId);
        resolvedSkillIds.push(techId);
      }
    }
    if (skippedCount > 0) {
      warn(`${skippedCount} installed skill(s) could not be resolved and were skipped`);
    }
    const selectedDomains = sortDomainsCanonically(typedKeys(domainSelections));
    const skillConfigs = resolvedSkillIds.map((id) => {
      const saved = savedConfigs?.find((sc) => sc.id === id);
      return {
        id,
        scope: saved?.scope ?? "project",
        source: saved?.source ?? DEFAULT_PUBLIC_SOURCE_NAME
      };
    });
    return {
      domainSelections,
      _stackDomainSelections: structuredClone(domainSelections),
      selectedDomains,
      skillConfigs
    };
  }),
  toggleDomain: (domain) => set((state) => {
    const isSelected = state.selectedDomains.includes(domain);
    if (isSelected) {
      const { [domain]: _removed, ...remainingSelections } = state.domainSelections;
      const removedSkillIds = /* @__PURE__ */ new Set();
      if (_removed) {
        for (const skills of Object.values(_removed)) {
          if (skills) {
            for (const id of skills) {
              removedSkillIds.add(id);
            }
          }
        }
      }
      return {
        selectedDomains: state.selectedDomains.filter((d) => d !== domain),
        domainSelections: remainingSelections,
        skillConfigs: state.skillConfigs.filter((sc) => !removedSkillIds.has(sc.id))
      };
    }
    const stackSelections = state._stackDomainSelections?.[domain];
    if (stackSelections) {
      const restoredSkillIds = [];
      for (const skills of Object.values(stackSelections)) {
        if (skills) restoredSkillIds.push(...skills);
      }
      const existingIds = new Set(state.skillConfigs.map((sc) => sc.id));
      const newConfigs = restoredSkillIds.filter((id) => !existingIds.has(id)).map(createDefaultSkillConfig);
      return {
        selectedDomains: sortDomainsCanonically([...state.selectedDomains, domain]),
        domainSelections: {
          ...state.domainSelections,
          [domain]: structuredClone(stackSelections)
        },
        skillConfigs: [...state.skillConfigs, ...newConfigs]
      };
    }
    return {
      selectedDomains: sortDomainsCanonically([...state.selectedDomains, domain])
    };
  }),
  toggleTechnology: (domain, category, technology, exclusive) => set((state) => {
    if (state.lockedSkillIds.includes(technology)) return state;
    const currentSelections = state.domainSelections[domain]?.[category] || [];
    const isSelected = currentSelections.includes(technology);
    let newSelections;
    if (exclusive) {
      newSelections = isSelected ? [] : [technology];
    } else {
      newSelections = isSelected ? currentSelections.filter((t) => t !== technology) : [...currentSelections, technology];
    }
    const removed = currentSelections.filter((id) => !newSelections.includes(id));
    const added = newSelections.filter((id) => !currentSelections.includes(id));
    let updatedConfigs = state.skillConfigs.filter((sc) => !removed.includes(sc.id));
    for (const id of added) {
      if (!updatedConfigs.some((sc) => sc.id === id)) {
        updatedConfigs = [...updatedConfigs, createDefaultSkillConfig(id)];
      }
    }
    return {
      skillConfigs: updatedConfigs,
      domainSelections: {
        ...state.domainSelections,
        [domain]: {
          ...state.domainSelections[domain],
          [category]: newSelections
        }
      }
    };
  }),
  nextDomain: () => {
    const state = get();
    if (state.currentDomainIndex < state.selectedDomains.length - 1) {
      set({
        currentDomainIndex: state.currentDomainIndex + 1
      });
      return true;
    }
    return false;
  },
  prevDomain: () => {
    const state = get();
    if (state.currentDomainIndex > 0) {
      set({
        currentDomainIndex: state.currentDomainIndex - 1
      });
      return true;
    }
    return false;
  },
  toggleShowLabels: () => set((state) => ({ showLabels: !state.showLabels })),
  deriveInstallMode: () => {
    const { skillConfigs } = get();
    return deriveInstallMode(skillConfigs);
  },
  toggleSkillScope: (skillId) => set((state) => {
    if (state.lockedSkillIds.includes(skillId)) return state;
    return {
      skillConfigs: state.skillConfigs.map(
        (sc) => sc.id === skillId ? { ...sc, scope: sc.scope === "project" ? "global" : "project" } : sc
      )
    };
  }),
  setSkillSource: (skillId, source) => set((state) => ({
    skillConfigs: state.skillConfigs.map((sc) => sc.id === skillId ? { ...sc, source } : sc)
  })),
  setFocusedSkillId: (id) => set({ focusedSkillId: id }),
  setSourceSelection: (skillId, sourceId) => set((state) => {
    if (!skillId) {
      warn("Ignoring setSourceSelection call with empty skillId");
      return state;
    }
    if (!sourceId) {
      warn(`Ignoring setSourceSelection call with empty sourceId for skill '${skillId}'`);
      return state;
    }
    return {
      skillConfigs: state.skillConfigs.map(
        (sc) => sc.id === skillId ? { ...sc, source: sourceId } : sc
      )
    };
  }),
  setCustomizeSources: (customize) => set({ customizeSources: customize }),
  toggleSettings: () => set((state) => ({ showSettings: !state.showSettings })),
  toggleHelp: () => set((state) => ({ showHelp: !state.showHelp })),
  setEnabledSources: (sources) => {
    const invalidKeys = Object.keys(sources).filter((key) => !key.trim());
    if (invalidKeys.length > 0) {
      warn("Ignoring setEnabledSources call with empty source name(s)");
    }
    const validSources = Object.fromEntries(Object.entries(sources).filter(([key]) => key.trim()));
    return set({ enabledSources: validSources });
  },
  bindSkill: (skill) => set((state) => {
    const exists = state.boundSkills.some(
      (b) => b.id === skill.id && b.sourceUrl === skill.sourceUrl
    );
    if (exists) {
      warn(`Skill '${skill.id}' from '${skill.sourceUrl}' is already bound \u2014 skipping duplicate`);
      return state;
    }
    return { boundSkills: [...state.boundSkills, skill] };
  }),
  goBack: () => set((state) => {
    const history = [...state.history];
    const previousStep = history.pop();
    return {
      step: previousStep || "stack",
      history
    };
  }),
  toggleAgent: (agent) => set((state) => {
    if (state.lockedAgentNames.includes(agent)) return state;
    const isSelected = state.selectedAgents.includes(agent);
    if (isSelected) {
      return {
        selectedAgents: state.selectedAgents.filter((a) => a !== agent),
        agentConfigs: state.agentConfigs.filter((ac) => ac.name !== agent)
      };
    }
    return {
      selectedAgents: [...state.selectedAgents, agent],
      agentConfigs: [...state.agentConfigs, { name: agent, scope: "project" }]
    };
  }),
  toggleAgentScope: (agentName) => set((state) => {
    if (state.lockedAgentNames.includes(agentName)) return state;
    return {
      agentConfigs: state.agentConfigs.map(
        (ac) => ac.name === agentName ? { ...ac, scope: ac.scope === "project" ? "global" : "project" } : ac
      )
    };
  }),
  setFocusedAgentId: (id) => set({ focusedAgentId: id }),
  preselectAgentsFromDomains: () => set(() => {
    const agents = [];
    for (const domain of get().selectedDomains) {
      const domainAgents = DOMAIN_AGENTS[domain];
      if (domainAgents) {
        agents.push(...domainAgents);
      }
    }
    const sorted = agents.sort();
    return {
      selectedAgents: sorted,
      agentConfigs: sorted.map((name) => ({ name, scope: "project" }))
    };
  }),
  reset: () => set(createInitialState()),
  getAllSelectedTechnologies: () => {
    const state = get();
    const technologies = [];
    for (const domain of typedKeys(state.domainSelections)) {
      const domainSel = state.domainSelections[domain];
      if (!domainSel) continue;
      for (const category of typedKeys(domainSel)) {
        const techs = domainSel[category];
        if (techs) technologies.push(...techs);
      }
    }
    return technologies;
  },
  getSelectedTechnologiesPerDomain: () => {
    const state = get();
    const result = {};
    for (const domain of typedKeys(state.domainSelections)) {
      const domainSel = state.domainSelections[domain];
      if (!domainSel) continue;
      const techs = [];
      for (const category of typedKeys(domainSel)) {
        const subTechs = domainSel[category];
        if (subTechs) techs.push(...subTechs);
      }
      if (techs.length > 0) {
        result[domain] = techs;
      }
    }
    return result;
  },
  getCurrentDomain: () => {
    const state = get();
    return state.selectedDomains[state.currentDomainIndex] || null;
  },
  getDefaultMethodologySkills: () => {
    return [...DEFAULT_PRESELECTED_SKILLS];
  },
  getTechnologyCount: () => {
    return get().getAllSelectedTechnologies().length;
  },
  getStepProgress: () => {
    const state = get();
    const completed = [];
    const skipped = [];
    if (state.step !== "stack") {
      completed.push("stack");
    }
    if (state.approach === "stack" && state.selectedStackId && state.stackAction === "defaults") {
      skipped.push("build");
      skipped.push("sources");
      skipped.push("agents");
    } else if (state.step === "confirm") {
      completed.push("build");
      completed.push("sources");
      completed.push("agents");
    } else if (state.step === "agents") {
      completed.push("build");
      completed.push("sources");
    } else if (state.step === "sources") {
      completed.push("build");
    }
    return { completedSteps: completed, skippedSteps: skipped };
  },
  canGoToNextDomain: () => {
    const state = get();
    return state.currentDomainIndex < state.selectedDomains.length - 1;
  },
  canGoToPreviousDomain: () => {
    const state = get();
    return state.currentDomainIndex > 0;
  },
  setAllSourcesLocal: () => {
    set((state) => ({
      skillConfigs: state.skillConfigs.map((sc) => ({ ...sc, source: "local" }))
    }));
  },
  setAllSourcesPlugin: (matrix) => {
    set((state) => ({
      skillConfigs: state.skillConfigs.map((sc) => {
        const skill = matrix.skills[sc.id];
        if (skill?.availableSources) {
          const marketplaceSource = skill.availableSources.find((s) => s.type !== "local");
          if (marketplaceSource) {
            return { ...sc, source: marketplaceSource.name };
          }
        }
        return sc;
      })
    }));
  },
  buildSourceRows: (matrix) => {
    const state = get();
    const selectedTechnologies = get().getAllSelectedTechnologies();
    const { skillConfigs, boundSkills } = state;
    return selectedTechnologies.map((tech) => {
      const skillId = resolveAlias(tech, matrix);
      const skill = matrix.skills[skillId];
      const configEntry = skillConfigs.find((sc) => sc.id === skillId);
      const selectedSource = configEntry?.source || skill?.activeSource?.name || DEFAULT_PUBLIC_SOURCE_NAME;
      const alias = getSkillAlias(skillId, matrix);
      const displayLabel = skill ? getSkillDisplayLabel(skill) : skillId;
      const sortedSources = [...skill?.availableSources || []].sort(
        (a, b) => getSourceSortTier(a) - getSourceSortTier(b)
      );
      const options = sortedSources.length > 0 ? sortedSources.map((source) => ({
        id: source.name,
        label: formatSourceLabel({
          name: source.name,
          installed: source.installed
        }),
        selected: selectedSource === source.name,
        installed: source.installed
      })) : [
        {
          id: DEFAULT_PUBLIC_SOURCE_NAME,
          label: formatSourceLabel({ name: DEFAULT_PUBLIC_SOURCE_NAME, installed: false }),
          selected: selectedSource === DEFAULT_PUBLIC_SOURCE_NAME,
          installed: false
        }
      ];
      if (!options.some((o) => o.id === "local")) {
        options.unshift({
          id: "local",
          label: formatSourceLabel({ name: "local", installed: false }),
          selected: selectedSource === "local",
          installed: false
        });
      }
      options.push(...buildBoundSkillOptions(boundSkills, alias, selectedSource));
      return { skillId, displayName: displayLabel, alias, options };
    });
  }
}));

export {
  validateBuildStep,
  getSkillDisplayLabel,
  buildCategoriesForDomain,
  useWizardStore
};
//# sourceMappingURL=chunk-WF6RM73R.js.map