import {
  DERIVED_FROM_MEMORY_ID_RE
} from "./chunk-G7D6GZ5J.js";

// src/training-export/date-parse.ts
var DAYS_IN_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
function isLeapYear(year) {
  return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
}
function isCalendarDateValid(year, month, day) {
  if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) {
    return false;
  }
  if (month < 1 || month > 12) return false;
  if (day < 1) return false;
  const maxDay = month === 2 && isLeapYear(year) ? 29 : DAYS_IN_MONTH[month];
  return day <= maxDay;
}
function parseStrictCliDate(value, flagName) {
  const shape = /^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?(Z|[+-]\d{2}:\d{2})?)?$/;
  const match = value.match(shape);
  if (!match) {
    throw new Error(
      `Invalid ${flagName} value "${value}": expected ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss[.sss][Z|\xB1HH:MM]).`
    );
  }
  const year = Number(match[1]);
  const month = Number(match[2]);
  const day = Number(match[3]);
  if (!isCalendarDateValid(year, month, day)) {
    throw new Error(
      `Invalid ${flagName} value "${value}": date components overflow (e.g. month has fewer days). Provide a valid calendar date.`
    );
  }
  if (match[4] !== void 0) {
    const hour = Number(match[4]);
    const minute = Number(match[5]);
    const second = match[6] !== void 0 ? Number(match[6]) : 0;
    if (hour > 23 || minute > 59 || second > 59) {
      throw new Error(
        `Invalid ${flagName} value "${value}": time components out of range.`
      );
    }
  }
  const d = new Date(value);
  if (!Number.isFinite(d.getTime())) {
    throw new Error(
      `Invalid ${flagName} value "${value}". Provide an ISO 8601 date string (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss).`
    );
  }
  return d;
}

// src/patterns-cli.ts
var PATTERNS_OUTPUT_FORMATS = ["text", "markdown", "json"];
function parsePatternsFormat(value) {
  if (value === void 0 || value === null) return "text";
  if (typeof value !== "string" || !PATTERNS_OUTPUT_FORMATS.includes(value)) {
    throw new Error(
      `--format expects one of ${PATTERNS_OUTPUT_FORMATS.join(", ")}; got ${JSON.stringify(value)}`
    );
  }
  return value;
}
function parsePatternsLimit(value) {
  if (value === void 0 || value === null) return void 0;
  const parsed = typeof value === "number" ? value : Number(value);
  if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) {
    throw new Error(
      `--limit expects a positive integer; got ${JSON.stringify(value)}`
    );
  }
  return parsed;
}
function parsePatternsCategory(value) {
  if (value === void 0 || value === null) return void 0;
  if (typeof value !== "string") {
    throw new Error(
      `--category expects a comma-separated list of category names; got ${JSON.stringify(value)}`
    );
  }
  const parts = value.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
  if (parts.length === 0) {
    throw new Error(
      `--category expects at least one non-empty category name; got ${JSON.stringify(value)}`
    );
  }
  const seen = /* @__PURE__ */ new Set();
  const unique = [];
  for (const part of parts) {
    if (!seen.has(part)) {
      seen.add(part);
      unique.push(part);
    }
  }
  return unique;
}
function parsePatternsSince(value) {
  if (value === void 0 || value === null) return void 0;
  if (typeof value !== "string" || value.trim().length === 0) {
    throw new Error(
      `--since expects an ISO 8601 timestamp (e.g. 2026-04-01T00:00:00Z); got ${JSON.stringify(value)}`
    );
  }
  return parseStrictCliDate(value.trim(), "--since").toISOString();
}
function parsePatternsListOptions(options) {
  const format = parsePatternsFormat(options.format);
  const limit = parsePatternsLimit(options.limit);
  const categories = parsePatternsCategory(options.category);
  const sinceIso = parsePatternsSince(options.since);
  return {
    format,
    ...limit !== void 0 ? { limit } : {},
    ...categories !== void 0 ? { categories } : {},
    ...sinceIso !== void 0 ? { sinceIso } : {}
  };
}
function parsePatternsExplainOptions(rawId, options) {
  if (typeof rawId !== "string" || rawId.trim().length === 0) {
    throw new Error("patterns explain: <memoryId> is required and must be non-empty");
  }
  const format = parsePatternsFormat(options.format);
  return { id: rawId.trim(), format };
}
var DEFAULT_LIST_LIMIT = 50;
function collectPatternMemories(memories, opts) {
  const sinceMs = opts.sinceIso !== void 0 ? Date.parse(opts.sinceIso) : void 0;
  const categorySet = opts.categories !== void 0 ? new Set(opts.categories) : void 0;
  const rows = [];
  for (const memory of memories) {
    const fm = memory.frontmatter;
    const count = fm.reinforcement_count;
    if (typeof count !== "number" || !Number.isInteger(count) || count <= 0) {
      continue;
    }
    if (categorySet !== void 0 && !categorySet.has(fm.category)) {
      continue;
    }
    if (sinceMs !== void 0) {
      if (typeof fm.last_reinforced_at !== "string") continue;
      const ts = Date.parse(fm.last_reinforced_at);
      if (!Number.isFinite(ts) || ts < sinceMs) continue;
    }
    rows.push({
      id: fm.id,
      category: fm.category,
      reinforcementCount: count,
      ...fm.last_reinforced_at !== void 0 ? { lastReinforcedAt: fm.last_reinforced_at } : {},
      status: fm.status ?? "active",
      preview: extractPreview(memory.content),
      path: memory.path
    });
  }
  rows.sort((a, b) => {
    if (b.reinforcementCount !== a.reinforcementCount) {
      return b.reinforcementCount - a.reinforcementCount;
    }
    const aRaw = a.lastReinforcedAt ? Date.parse(a.lastReinforcedAt) : NaN;
    const bRaw = b.lastReinforcedAt ? Date.parse(b.lastReinforcedAt) : NaN;
    const aTs = Number.isFinite(aRaw) ? aRaw : 0;
    const bTs = Number.isFinite(bRaw) ? bRaw : 0;
    if (bTs !== aTs) return bTs - aTs;
    if (a.id < b.id) return -1;
    if (a.id > b.id) return 1;
    return 0;
  });
  const limit = opts.limit ?? DEFAULT_LIST_LIMIT;
  return rows.slice(0, limit);
}
function explainPatternMemory(memories, id) {
  const canonical = memories.find((m) => m.frontmatter.id === id);
  if (!canonical) return null;
  const fm = canonical.frontmatter;
  const count = fm.reinforcement_count;
  if (typeof count !== "number" || !Number.isInteger(count) || count <= 0) {
    return null;
  }
  const derivedFrom = (fm.derived_from ?? []).map(
    (ref) => {
      const lastColon = ref.lastIndexOf(":");
      const pathLikeRef = looksLikeDerivedFromPath(ref);
      if (lastColon >= 0) {
        const path = ref.slice(0, lastColon);
        const versionStr = ref.slice(lastColon + 1);
        if (looksLikeDerivedFromPath(path) && /^\d+$/.test(versionStr)) {
          return { ref, path, version: Number(versionStr) };
        }
        if (!pathLikeRef && DERIVED_FROM_MEMORY_ID_RE.test(ref)) {
          return { ref, path: ref, version: null };
        }
        return { ref, path: ref, version: null, malformed: true };
      }
      if (DERIVED_FROM_MEMORY_ID_RE.test(ref)) {
        return {
          ref,
          path: ref,
          version: null
        };
      }
      return { ref, path: ref, version: null, malformed: true };
    }
  );
  const members = [];
  for (const m of memories) {
    if (m.frontmatter.supersededBy === id) {
      members.push({
        id: m.frontmatter.id,
        status: m.frontmatter.status ?? "active",
        ...m.frontmatter.supersededAt !== void 0 ? { supersededAt: m.frontmatter.supersededAt } : {},
        path: m.path,
        preview: extractPreview(m.content)
      });
    }
  }
  members.sort((a, b) => {
    const aRaw = a.supersededAt ? Date.parse(a.supersededAt) : NaN;
    const bRaw = b.supersededAt ? Date.parse(b.supersededAt) : NaN;
    const aTs = Number.isFinite(aRaw) ? aRaw : 0;
    const bTs = Number.isFinite(bRaw) ? bRaw : 0;
    if (bTs !== aTs) return bTs - aTs;
    if (a.id < b.id) return -1;
    if (a.id > b.id) return 1;
    return 0;
  });
  return {
    id: fm.id,
    category: fm.category,
    reinforcementCount: count,
    ...fm.last_reinforced_at !== void 0 ? { lastReinforcedAt: fm.last_reinforced_at } : {},
    status: fm.status ?? "active",
    ...fm.derived_via !== void 0 ? { derivedVia: fm.derived_via } : {},
    canonicalContent: canonical.content.trim(),
    canonicalPath: canonical.path,
    derivedFrom,
    clusterMembers: members
  };
}
function renderPatternsList(rows, format) {
  if (format === "json") {
    return JSON.stringify({ rows }, null, 2);
  }
  if (rows.length === 0) {
    if (format === "markdown") {
      return "# Pattern memories\n\n_No reinforced patterns found._\n";
    }
    return "No reinforced patterns found.";
  }
  if (format === "markdown") {
    const lines2 = ["# Pattern memories", ""];
    lines2.push("| Count | ID | Category | Last reinforced | Preview |");
    lines2.push("| --- | --- | --- | --- | --- |");
    for (const row of rows) {
      const last = row.lastReinforcedAt ?? "\u2014";
      const preview = escapePipes(row.preview);
      lines2.push(
        `| ${row.reinforcementCount} | \`${row.id}\` | ${row.category} | ${last} | ${preview} |`
      );
    }
    return lines2.join("\n") + "\n";
  }
  const lines = [];
  lines.push(`Pattern memories (${rows.length}):`);
  lines.push("");
  for (const row of rows) {
    const last = row.lastReinforcedAt ?? "\u2014";
    lines.push(
      `  [${row.reinforcementCount}x] ${row.id}  (${row.category}, last_reinforced=${last}, status=${row.status})`
    );
    if (row.preview.length > 0) {
      lines.push(`        ${row.preview}`);
    }
    lines.push(`        path: ${row.path}`);
  }
  return lines.join("\n");
}
function renderPatternExplain(detail, format) {
  if (format === "json") {
    return JSON.stringify(detail, null, 2);
  }
  const last = detail.lastReinforcedAt ?? "\u2014";
  const derivedVia = detail.derivedVia ?? "\u2014";
  if (format === "markdown") {
    const lines2 = [];
    lines2.push(`# Pattern: \`${detail.id}\``);
    lines2.push("");
    lines2.push(`- **Reinforcement count:** ${detail.reinforcementCount}`);
    lines2.push(`- **Last reinforced:** ${last}`);
    lines2.push(`- **Category:** ${detail.category}`);
    lines2.push(`- **Status:** ${detail.status}`);
    lines2.push(`- **Derived via:** ${derivedVia}`);
    lines2.push(`- **Path:** \`${detail.canonicalPath}\``);
    lines2.push("");
    lines2.push("## Canonical content");
    lines2.push("");
    lines2.push("```");
    lines2.push(detail.canonicalContent);
    lines2.push("```");
    lines2.push("");
    lines2.push(`## Derived from (${detail.derivedFrom.length})`);
    lines2.push("");
    if (detail.derivedFrom.length === 0) {
      lines2.push("_No derived_from entries recorded._");
    } else {
      for (const entry of detail.derivedFrom) {
        const versionStr = entry.version !== null ? ` v${entry.version}` : entry.malformed ? " (malformed)" : "";
        lines2.push(`- \`${entry.path}\`${versionStr}`);
      }
    }
    lines2.push("");
    lines2.push(`## Cluster members (${detail.clusterMembers.length})`);
    lines2.push("");
    if (detail.clusterMembers.length === 0) {
      lines2.push("_No superseded members reference this canonical._");
    } else {
      for (const member of detail.clusterMembers) {
        const ts = member.supersededAt ?? "\u2014";
        lines2.push(`- \`${member.id}\` (status=${member.status}, supersededAt=${ts})`);
        if (member.preview.length > 0) {
          lines2.push(`  - ${escapePipes(member.preview)}`);
        }
      }
    }
    return lines2.join("\n") + "\n";
  }
  const lines = [];
  lines.push(`Pattern: ${detail.id}`);
  lines.push(`  reinforcement_count: ${detail.reinforcementCount}`);
  lines.push(`  last_reinforced_at: ${last}`);
  lines.push(`  category:           ${detail.category}`);
  lines.push(`  status:             ${detail.status}`);
  lines.push(`  derived_via:        ${derivedVia}`);
  lines.push(`  path:               ${detail.canonicalPath}`);
  lines.push("");
  lines.push("Canonical content:");
  for (const line of detail.canonicalContent.split("\n")) {
    lines.push(`  ${line}`);
  }
  lines.push("");
  lines.push(`Derived from (${detail.derivedFrom.length}):`);
  if (detail.derivedFrom.length === 0) {
    lines.push("  (none)");
  } else {
    for (const entry of detail.derivedFrom) {
      const versionStr = entry.version !== null ? ` v${entry.version}` : entry.malformed ? " (malformed)" : "";
      lines.push(`  - ${entry.path}${versionStr}`);
    }
  }
  lines.push("");
  lines.push(`Cluster members (${detail.clusterMembers.length}):`);
  if (detail.clusterMembers.length === 0) {
    lines.push("  (none)");
  } else {
    for (const member of detail.clusterMembers) {
      const ts = member.supersededAt ?? "\u2014";
      lines.push(`  - ${member.id} (status=${member.status}, supersededAt=${ts})`);
      if (member.preview.length > 0) {
        lines.push(`      ${member.preview}`);
      }
    }
  }
  return lines.join("\n");
}
function extractPreview(content) {
  const trimmed = content.trim();
  if (trimmed.length === 0) return "";
  const firstLine = trimmed.split("\n").find((line) => line.trim().length > 0) ?? "";
  const collapsed = firstLine.trim().replace(/\s+/g, " ");
  if (collapsed.length <= 120) return collapsed;
  return collapsed.slice(0, 117) + "...";
}
function looksLikeDerivedFromPath(value) {
  return value.includes("/") || value.includes(".");
}
function escapePipes(value) {
  return value.replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
}

export {
  parseStrictCliDate,
  PATTERNS_OUTPUT_FORMATS,
  parsePatternsFormat,
  parsePatternsLimit,
  parsePatternsCategory,
  parsePatternsSince,
  parsePatternsListOptions,
  parsePatternsExplainOptions,
  collectPatternMemories,
  explainPatternMemory,
  renderPatternsList,
  renderPatternExplain
};
//# sourceMappingURL=chunk-AJA46VX5.js.map