/** * Fix subject-line stripping: optional colon + multi-line subject block */ import fs from "fs"; const SUBJECT_LINE_RE = "/(?:\\u4e3b\\u9898|\\u4e3b\\u65e8|Subject)\\s*[\\uFF1A:]?/i"; const helper = `/** Drop subject / \\u4e3b\\u65e8 block (optional colon, multi-line wrap) */\nfunction stripSubjectLines(text: string): string {\n const lines = text.split(/\\n/);\n const out: string[] = [];\n let inSubject = false;\n for (const line of lines) {\n if (/(?:\\u4e3b\\u9898|\\u4e3b\\u65e8|Subject)\\s*[\\uFF1A:]?/i.test(line)) {\n inSubject = true;\n continue;\n }\n if (inSubject) {\n const t = line.trim();\n if (!t) {\n inSubject = false;\n continue;\n }\n if (\n /^(?:\\u5bc4\\u4ef6\\u4eba|\\u53d1\\u4ef6\\u4eba|\\u6536\\u4ef6\\u4eba|\\u6284\\u9001|\\u65e5\\u671f|\\u53d1\\u9001\\u65f6\\u95f4|From|To|Cc|Date|Sent|Dear|----)/i.test(\n t,\n ) ||\n /^date@/i.test(t) ||\n t === "date" ||\n /^[\\u5728\\\\s]*\\d{4}/.test(t)\n ) {\n inSubject = false;\n out.push(line);\n continue;\n }\n continue;\n }\n out.push(line);\n }\n return out.join("\\n");\n}\n`; // Simpler: write file with real unicode via \u in the script string that becomes Chinese const stripFn = ` function stripSubjectLines(text: string): string { const lines = text.split(/\\n/); const out: string[] = []; let inSubject = false; for (const line of lines) { // "\\u4e3b\\u9898 Re:..." often has NO colon after \\u4e3b\\u9898 if (/(?:\u4e3b\u9898|\u4e3b\u65e8|Subject)\\s*[\uFF1A:]?/i.test(line)) { inSubject = true; continue; } if (inSubject) { const t = line.trim(); if (!t) { inSubject = false; continue; } if ( /^(?:\u5bc4\u4ef6\u4eba|\u53d1\u4ef6\u4eba|\u6536\u4ef6\u4eba|\u6284\u9001|\u65e5\u671f|\u53d1\u9001\u65f6\u95f4|From|To|Cc|Date|Sent|Dear|----)/i.test( t, ) || /^date@/i.test(t) || t === "date" || /^\u5728\\s*\\d{4}/.test(t) ) { inSubject = false; out.push(line); continue; } continue; } out.push(line); } return out.join("\\n"); } `.trimStart(); { const path = "src/services/parse/instruction-lexicon.ts"; let src = fs.readFileSync(path, "utf8"); const a = src.indexOf("function stripSubjectLines"); const b = src.indexOf("export function isForwardShellSegment"); if (a < 0 || b < 0) throw new Error("markers"); // keep any comment before function - find from /** Drop or function let start = src.lastIndexOf("/** Drop subject", a); if (start < 0) start = a; src = src.slice(0, start) + "/** Drop subject/\u4e3b\u65e8 block (optional colon; multi-line wrap) */\n" + stripFn + "\n" + src.slice(b); fs.writeFileSync(path, src); console.log("lexicon stripSubjectLines updated"); } { const path = "src/services/parse/split-instructions.ts"; let src = fs.readFileSync(path, "utf8"); const neu = `function bodyForKindDetect(segBody: string): string { // reuse same multi-line subject strip as lexicon (inline copy to avoid circular import) const lines = segBody.split(/\\n/); const out: string[] = []; let inSubject = false; for (const line of lines) { if (/(?:\u4e3b\u9898|\u4e3b\u65e8|Subject)\\s*[\uFF1A:]?/i.test(line)) { inSubject = true; continue; } if (inSubject) { const t = line.trim(); if (!t) { inSubject = false; continue; } if ( /^(?:\u5bc4\u4ef6\u4eba|\u53d1\u4ef6\u4eba|\u6536\u4ef6\u4eba|\u6284\u9001|\u65e5\u671f|\u53d1\u9001\u65f6\u95f4|From|To|Cc|Date|Sent|Dear|----)/i.test( t, ) || /^date@/i.test(t) || t === "date" || /^\\u5728\\s*\\d{4}/.test(t) || /^\u5728\\s*\\d{4}/.test(t) ) { inSubject = false; out.push(line); continue; } continue; } out.push(line); } return out.join("\\n"); } `; const a = src.indexOf("function bodyForKindDetect"); const b = src.indexOf("export function detectKindsForSegment"); if (a < 0 || b < 0) throw new Error("bounds"); src = src.slice(0, a) + neu + "\n" + src.slice(b); fs.writeFileSync(path, src); console.log("split bodyForKindDetect updated"); }