dsh-plugin-lookatstudy 0.25.1 → 0.25.2
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.
- package/lib/index.mjs +35 -9
- package/package.json +1 -1
package/lib/index.mjs
CHANGED
|
@@ -6582,12 +6582,19 @@ function validateDesign(design, validFiles) {
|
|
|
6582
6582
|
};
|
|
6583
6583
|
}
|
|
6584
6584
|
/**
|
|
6585
|
-
* Heading similarity
|
|
6586
|
-
*
|
|
6587
|
-
*
|
|
6588
|
-
*
|
|
6589
|
-
*
|
|
6590
|
-
*
|
|
6585
|
+
* Heading similarity — the translation misalignment guard. Ported from
|
|
6586
|
+
* upstream import-pipeline.ts (their audit F16, 2026-09-13): ordinal
|
|
6587
|
+
* alignment assumes both heading lists share structure; a machine-translated
|
|
6588
|
+
* file with a dropped header shifts every ordinal, and A's translation would
|
|
6589
|
+
* silently land on B's node — overlap too low skips the segment (宁缺毋错).
|
|
6590
|
+
* Empty titles cannot be checked and pass conservatively.
|
|
6591
|
+
*
|
|
6592
|
+
* 0.25.2 (owner real-import catch): upstream's word overlap normalizes on
|
|
6593
|
+
* whitespace, and a CJK title is ONE token — paraphrased Chinese headings
|
|
6594
|
+
* (课程总览与环境搭建指南 vs 课程总览) could never overlap and the guard
|
|
6595
|
+
* skipped every non-verbatim segment (38/110 paired on the owner's import;
|
|
6596
|
+
* the 38 were exact matches). CJK strings now compare by character
|
|
6597
|
+
* containment first, then character-bigram overlap ≥ 0.3.
|
|
6591
6598
|
*/
|
|
6592
6599
|
function headingsSimilar(a, b) {
|
|
6593
6600
|
const norm = (s) => s.toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim().split(/\s+/).filter(Boolean);
|
|
@@ -6595,6 +6602,24 @@ function headingsSimilar(a, b) {
|
|
|
6595
6602
|
const B = norm(b);
|
|
6596
6603
|
if (A.length === 0 || B.length === 0) return true;
|
|
6597
6604
|
if (A.join(" ") === B.join(" ")) return true;
|
|
6605
|
+
const han = (s) => s.toLowerCase().replace(/[^\p{Script=Han}\p{N}]/gu, "");
|
|
6606
|
+
const ca = han(a);
|
|
6607
|
+
const cb = han(b);
|
|
6608
|
+
if (ca.length >= 2 || cb.length >= 2) {
|
|
6609
|
+
if (ca === "" || cb === "") return true;
|
|
6610
|
+
if (ca.includes(cb) || cb.includes(ca)) return true;
|
|
6611
|
+
const bigramsOf = (s) => {
|
|
6612
|
+
const out = /* @__PURE__ */ new Set();
|
|
6613
|
+
const chars = Array.from(s);
|
|
6614
|
+
for (let i = 0; i + 1 < chars.length; i++) out.add(chars[i] + chars[i + 1]);
|
|
6615
|
+
return out;
|
|
6616
|
+
};
|
|
6617
|
+
const ba = bigramsOf(ca);
|
|
6618
|
+
const bb = bigramsOf(cb);
|
|
6619
|
+
let hit = 0;
|
|
6620
|
+
for (const g of ba) if (bb.has(g)) hit++;
|
|
6621
|
+
return hit / Math.max(1, ba.size) >= .3;
|
|
6622
|
+
}
|
|
6598
6623
|
const setB = new Set(B);
|
|
6599
6624
|
return A.filter((w) => setB.has(w)).length / A.length >= .3;
|
|
6600
6625
|
}
|
|
@@ -6675,7 +6700,8 @@ function buildCourseFromDesign(courseTitle, validated, contents, translations) {
|
|
|
6675
6700
|
let tIndex = titleIndex;
|
|
6676
6701
|
let keep = true;
|
|
6677
6702
|
if (lesson.anchor === null || titleIndex === -1) tIndex = -1;
|
|
6678
|
-
else if (titleIndex >= tHeadings.length
|
|
6703
|
+
else if (titleIndex >= tHeadings.length) keep = false;
|
|
6704
|
+
else if (!(tHeadings.length === headings.length && tHeadings.every((h, i) => h.level === headings[i].level)) && !headingsSimilar(lesson.title, tHeadings[titleIndex].title)) keep = false;
|
|
6679
6705
|
if (keep) translation = replaceImagesByPosition(sliceLessonBody(pair.content, tHeadings, tIndex, isFirst), originalImagesOf(body));
|
|
6680
6706
|
}
|
|
6681
6707
|
return {
|
|
@@ -7739,7 +7765,7 @@ ${p.text}`));
|
|
|
7739
7765
|
translations: {
|
|
7740
7766
|
type: "integer",
|
|
7741
7767
|
required: true,
|
|
7742
|
-
description: "Lessons that landed with a paired translation (the interface-language mirror existed and its anchor matched) — their teach tab offers
|
|
7768
|
+
description: "Lessons that landed with a paired translation (the interface-language mirror existed and its anchor matched) — their teach tab offers 原文/译文."
|
|
7743
7769
|
},
|
|
7744
7770
|
created: {
|
|
7745
7771
|
type: "boolean",
|
|
@@ -7754,7 +7780,7 @@ ${p.text}`));
|
|
|
7754
7780
|
},
|
|
7755
7781
|
render: (_args, value) => [{
|
|
7756
7782
|
type: "text",
|
|
7757
|
-
text: value.created === false ? `“${value.title}” (id ${value.courseId}) was ALREADY imported — the design did not create a new course. Continue with the existing course, or delete it first (study_delete_course) to rebuild from this design.` : `Imported designed course “${value.title}” (${value.sections} sections, ${value.lessons} lessons${value.droppedLessons > 0 ? `, ${value.droppedLessons} hallucinated lesson(s) dropped` : ""})${typeof value.translations === "number" && value.translations > 0 ? ` — ${value.translations} lesson(s) carry the learner's-language translation (
|
|
7783
|
+
text: value.created === false ? `“${value.title}” (id ${value.courseId}) was ALREADY imported — the design did not create a new course. Continue with the existing course, or delete it first (study_delete_course) to rebuild from this design.` : `Imported designed course “${value.title}” (${value.sections} sections, ${value.lessons} lessons${value.droppedLessons > 0 ? `, ${value.droppedLessons} hallucinated lesson(s) dropped` : ""})${typeof value.translations === "number" && value.translations > 0 ? ` — ${value.translations} lesson(s) carry the learner's-language translation (原文/译文 in the teach tab)` : ""}${typeof value.languageTarget === "string" ? ` — language course (${value.languageTarget}): keep reading passages, example sentences, and quiz language material in the target language` : ""}. First lesson: “${value.firstLessonTitle}” (id ${value.firstLessonId}). Present the course map to the learner.`
|
|
7758
7784
|
}]
|
|
7759
7785
|
},
|
|
7760
7786
|
async execute(args, exec) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-lookatstudy",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.2",
|
|
4
4
|
"packageManager": "pnpm@11.7.0",
|
|
5
5
|
"description": "Turn any markdown, local folder, or GitHub learning repo into a guided course inside DeepSeek Harness: gated skill-tree progression, BKT mastery tracking, SM-2 spaced repetition.",
|
|
6
6
|
"type": "module",
|