@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.
@@ -6257,7 +6257,9 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
6257
6257
  };
6258
6258
  }
6259
6259
  const slcMap = normalizeSlcContract(opts.sectionLanguageContract);
6260
- const sections = parseMarkdownSections(source, slcMap, opts.artifactType);
6260
+ const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
6261
+ const sections = parseMarkdownSections(source, slcMap, effectiveArtifactType);
6262
+ const metaBlock = buildMetaBlock(source, effectiveArtifactType);
6261
6263
  if (sections.length === 0) {
6262
6264
  issues.push("parse:no-sections");
6263
6265
  const excerpt2 = truncateByBudget(source, budget);
@@ -6291,12 +6293,13 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
6291
6293
  const block = `## ${heading}
6292
6294
 
6293
6295
  ${trimmedBody}`;
6294
- if (used + block.length > budget && blocks.length > 0) return false;
6296
+ if (used + block.length > budget && used > 0) return false;
6295
6297
  blocks.push(block);
6296
6298
  used += block.length;
6297
6299
  includedSections.push(key);
6298
6300
  return true;
6299
6301
  };
6302
+ blocks.push(metaBlock);
6300
6303
  let sectionAware = false;
6301
6304
  for (const key of priorities) {
6302
6305
  const sec = byCanonical.get(key);
@@ -6313,6 +6316,9 @@ ${trimmedBody}`;
6313
6316
  if (used >= budget) break;
6314
6317
  if (!tryAdd(sec.cleanTitle, sec.body, sec.cleanTitle)) break;
6315
6318
  }
6319
+ if (includedSections.length === 0 && unmatched.length > 0) {
6320
+ issues.push("parse:no-canonical-resolution");
6321
+ }
6316
6322
  if (priorities.length > 0 && !priorities.some((k) => includedSections.includes(k))) {
6317
6323
  issues.push("parse:no-priority-resolution");
6318
6324
  }
@@ -6321,14 +6327,14 @@ ${trimmedBody}`;
6321
6327
  excerpt = truncateByBudget(excerpt, budget);
6322
6328
  }
6323
6329
  const effectiveMinChars = Math.min(minContentChars, source.length);
6324
- if (excerpt.length < effectiveMinChars) {
6330
+ if (excerpt.length - metaBlock.length < effectiveMinChars) {
6325
6331
  issues.push("content:insufficient");
6326
6332
  }
6327
- const verified = !issues.includes("parse:no-priority-resolution") && excerpt.length >= effectiveMinChars;
6333
+ const verified = !issues.includes("parse:no-priority-resolution") && !issues.includes("parse:no-canonical-resolution") && excerpt.length - metaBlock.length >= effectiveMinChars;
6328
6334
  return {
6329
6335
  excerpt,
6330
6336
  verified,
6331
- sectionAware: sectionAware || priorities.length === 0 && sections.length > 0,
6337
+ sectionAware: sectionAware || unmatched.length === 0,
6332
6338
  includedSections,
6333
6339
  issues,
6334
6340
  tokenEstimate: Math.round(excerpt.length / 4)
@@ -6444,6 +6450,26 @@ function truncateByBudget(source, budget) {
6444
6450
  if (fenceCount % 2 === 1) cut += "\n```";
6445
6451
  return cut;
6446
6452
  }
6453
+ function buildMetaBlock(source, artifactType) {
6454
+ const fm = source.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
6455
+ const pick = (key) => {
6456
+ if (!fm) return "";
6457
+ const m = fm[1].match(new RegExp(`^${key}:\\s*"?([^"\\n]+)"?`, "m"));
6458
+ return (m?.[1] || "").trim();
6459
+ };
6460
+ const id = pick("id");
6461
+ const title = pick("title");
6462
+ const type = pick("type") || artifactType || "";
6463
+ return `<!-- SOURCE: ${type || "ARTIFACT"} | ${id || "unknown"}${title ? ` \u2014 ${title}` : ""} (section-aware excerpt; canonical knowledge, do not contradict) -->`;
6464
+ }
6465
+ function deriveArtifactTypeFromFileName(fileName) {
6466
+ if (!fileName) return void 0;
6467
+ const base = fileName.replace(/\.md$/i, "");
6468
+ const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|SECTION_LANGUAGE_CONTRACT|CONTENT_STYLE_GUIDE|CURRICULUM_FRAMEWORK|LEARNER_PROFILE|PROJECT_BRIEF|REFERENCE_PACK|CURRICULUM_PLAN)/i);
6469
+ if (multiWord) return multiWord[1].toUpperCase();
6470
+ const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
6471
+ return token ? token[1] : void 0;
6472
+ }
6447
6473
  init_errors();
6448
6474
 
6449
6475
  // src/services/languageDirective.ts