@thanh01.pmt/curriculum-kit 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6248,7 +6248,9 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
6248
6248
  };
6249
6249
  }
6250
6250
  const slcMap = normalizeSlcContract(opts.sectionLanguageContract);
6251
- const sections = parseMarkdownSections(source, slcMap, opts.artifactType);
6251
+ const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
6252
+ const sections = parseMarkdownSections(source, slcMap, effectiveArtifactType);
6253
+ const metaBlock = buildMetaBlock(source, effectiveArtifactType);
6252
6254
  if (sections.length === 0) {
6253
6255
  issues.push("parse:no-sections");
6254
6256
  const excerpt2 = truncateByBudget(source, budget);
@@ -6282,12 +6284,13 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
6282
6284
  const block = `## ${heading}
6283
6285
 
6284
6286
  ${trimmedBody}`;
6285
- if (used + block.length > budget && blocks.length > 0) return false;
6287
+ if (used + block.length > budget && used > 0) return false;
6286
6288
  blocks.push(block);
6287
6289
  used += block.length;
6288
6290
  includedSections.push(key);
6289
6291
  return true;
6290
6292
  };
6293
+ blocks.push(metaBlock);
6291
6294
  let sectionAware = false;
6292
6295
  for (const key of priorities) {
6293
6296
  const sec = byCanonical.get(key);
@@ -6304,6 +6307,9 @@ ${trimmedBody}`;
6304
6307
  if (used >= budget) break;
6305
6308
  if (!tryAdd(sec.cleanTitle, sec.body, sec.cleanTitle)) break;
6306
6309
  }
6310
+ if (includedSections.length === 0 && unmatched.length > 0) {
6311
+ issues.push("parse:no-canonical-resolution");
6312
+ }
6307
6313
  if (priorities.length > 0 && !priorities.some((k) => includedSections.includes(k))) {
6308
6314
  issues.push("parse:no-priority-resolution");
6309
6315
  }
@@ -6312,14 +6318,14 @@ ${trimmedBody}`;
6312
6318
  excerpt = truncateByBudget(excerpt, budget);
6313
6319
  }
6314
6320
  const effectiveMinChars = Math.min(minContentChars, source.length);
6315
- if (excerpt.length < effectiveMinChars) {
6321
+ if (excerpt.length - metaBlock.length < effectiveMinChars) {
6316
6322
  issues.push("content:insufficient");
6317
6323
  }
6318
- const verified = !issues.includes("parse:no-priority-resolution") && excerpt.length >= effectiveMinChars;
6324
+ const verified = !issues.includes("parse:no-priority-resolution") && !issues.includes("parse:no-canonical-resolution") && excerpt.length - metaBlock.length >= effectiveMinChars;
6319
6325
  return {
6320
6326
  excerpt,
6321
6327
  verified,
6322
- sectionAware: sectionAware || priorities.length === 0 && sections.length > 0,
6328
+ sectionAware: sectionAware || unmatched.length === 0,
6323
6329
  includedSections,
6324
6330
  issues,
6325
6331
  tokenEstimate: Math.round(excerpt.length / 4)
@@ -6435,6 +6441,26 @@ function truncateByBudget(source, budget) {
6435
6441
  if (fenceCount % 2 === 1) cut += "\n```";
6436
6442
  return cut;
6437
6443
  }
6444
+ function buildMetaBlock(source, artifactType) {
6445
+ const fm = source.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
6446
+ const pick = (key) => {
6447
+ if (!fm) return "";
6448
+ const m = fm[1].match(new RegExp(`^${key}:\\s*"?([^"\\n]+)"?`, "m"));
6449
+ return (m?.[1] || "").trim();
6450
+ };
6451
+ const id = pick("id");
6452
+ const title = pick("title");
6453
+ const type = pick("type") || artifactType || "";
6454
+ return `<!-- SOURCE: ${type || "ARTIFACT"} | ${id || "unknown"}${title ? ` \u2014 ${title}` : ""} (section-aware excerpt; canonical knowledge, do not contradict) -->`;
6455
+ }
6456
+ function deriveArtifactTypeFromFileName(fileName) {
6457
+ if (!fileName) return void 0;
6458
+ const base = fileName.replace(/\.md$/i, "");
6459
+ const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|SECTION_LANGUAGE_CONTRACT|CONTENT_STYLE_GUIDE|CURRICULUM_FRAMEWORK|LEARNER_PROFILE|PROJECT_BRIEF|REFERENCE_PACK|CURRICULUM_PLAN)/i);
6460
+ if (multiWord) return multiWord[1].toUpperCase();
6461
+ const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
6462
+ return token ? token[1] : void 0;
6463
+ }
6438
6464
  init_errors();
6439
6465
 
6440
6466
  // src/services/languageDirective.ts