cruise 0.1.78

YAML-driven coding agent workflow orchestrator
Documentation
import type { ConfigEntry } from "../types";

interface ConfigSelectProps {
  id: string;
  value: string;
  onChange: (value: string) => void;
  disabled?: boolean;
  configs: ConfigEntry[];
  /** Base dir of the session/draft, used to derive the "Base dir (...)" group label and relative option text. */
  baseDir?: string;
  className?: string;
}

const DEFAULT_CLASS_NAME =
  "w-full bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 rounded px-3 py-2 text-sm text-gray-800 dark:text-gray-200 focus:border-blue-500 outline-none disabled:opacity-50";

function dirOf(path: string): string {
  const idx = path.lastIndexOf("/");
  return idx === -1 ? path : path.slice(0, idx);
}

function optionLabel(entry: ConfigEntry, baseDir: string | undefined): string {
  const normalizedBaseDir = baseDir?.replace(/\/+$/, "");
  const prefix = normalizedBaseDir ? `${normalizedBaseDir}/` : "";
  const name = prefix && entry.path.startsWith(prefix) ? entry.path.slice(prefix.length) : entry.name;
  return entry.description ? `${name} — ${entry.description}` : name;
}

function renderOptions(entries: ConfigEntry[], baseDir: string | undefined) {
  return entries.map((c) => (
    <option key={c.path} value={c.path}>
      {optionLabel(c, baseDir)}
    </option>
  ));
}

/**
 * Shared `<select>` for choosing a workflow config file, grouping options by
 * discovery source (`local` under the base dir, `user` under the user config dir,
 * anything without a `source` under "Other").
 */
export function ConfigSelect({
  id,
  value,
  onChange,
  disabled = false,
  configs,
  baseDir,
  className = DEFAULT_CLASS_NAME,
}: ConfigSelectProps): React.ReactElement {
  const localEntries = configs.filter((c) => c.source === "local");
  const userEntries = configs.filter((c) => c.source === "user");
  const otherEntries = configs.filter((c) => c.source !== "local" && c.source !== "user");

  return (
    <select
      id={id}
      value={value}
      onChange={(e) => onChange(e.target.value)}
      disabled={disabled}
      className={className}
    >
      <option value="">Auto (base dir / user config / builtin)</option>
      {localEntries.length > 0 && (
        <optgroup label={`Base dir (${baseDir || "."})`}>
          {renderOptions(localEntries, baseDir)}
        </optgroup>
      )}
      {userEntries.length > 0 && (
        <optgroup label={`User config (${dirOf(userEntries[0].path)})`}>
          {renderOptions(userEntries, baseDir)}
        </optgroup>
      )}
      {otherEntries.length > 0 && (
        <optgroup label="Other">{renderOptions(otherEntries, baseDir)}</optgroup>
      )}
    </select>
  );
}