| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- import { readdirSync, readFileSync, existsSync, statSync } from "fs"
- import { resolve, join } from "path"
- import process from "process"
- const ROOT = process.argv[2] || process.cwd()
- const NVWA = resolve(ROOT, "skills", "soulskill")
- const CHARACTER_AURA_PATH = resolve(ROOT, "src", "lib", "novel", "character-aura.ts")
- const CURLY_LEFT = "\u201C"
- const CURLY_RIGHT = "\u201D"
- const ENGLISH_BASED_SLUGS = new Set([
- "elon-musk", "feynman", "munger", "charlie-munger",
- "naval", "steve-jobs", "taleb", "trump",
- "paul-graham", "andrei-kapasi", "ilya-sutskaver",
- "mr-beast", "sun-yuchen",
- ])
- let errors = 0
- function report(file, message) {
- console.error(` ${file} ${message}`)
- errors++
- }
- function checkCurlyQuotes(content, file) {
- const lines = content.split("\n")
- for (let i = 0; i < lines.length; i++) {
- if (lines[i].includes(CURLY_LEFT) || lines[i].includes(CURLY_RIGHT)) {
- report(file, `第${i + 1}行 包含中文弯引号 ""(oxc 不兼容),请替换为 「」`)
- }
- }
- }
- function stripFrontmatter(content) {
- const start = content.indexOf("---")
- if (start !== 0) return content
- const end = content.indexOf("---", start + 3)
- if (end === -1) return content
- return content.slice(end + 3)
- }
- function isEnglishBased(folderName) {
- return ENGLISH_BASED_SLUGS.has(folderName)
- }
- function walk(dir, cb, depth = 0) {
- if (!existsSync(dir)) return
- const entries = readdirSync(dir)
- for (const entry of entries) {
- if (entry.startsWith(".")) continue
- const full = join(dir, entry)
- const stat = statSync(full)
- if (stat.isDirectory()) {
- if (entry.startsWith("x-") || entry.startsWith("SKILL")) continue
- if (depth === 0 && isEnglishBased(entry)) continue
- walk(full, cb, depth + 1)
- } else if (entry.endsWith(".md")) {
- if (depth >= 1 && isEnglishBased(full.split("\\").slice(-3, -2)[0] || "")) continue
- cb(full)
- }
- }
- }
- console.log("=== 角色灵魂内容校验 ===")
- console.log()
- console.log("--- character-aura.ts 弯引号 + 字段英文检查 ---")
- const auraContent = readFileSync(CHARACTER_AURA_PATH, "utf8")
- checkCurlyQuotes(auraContent, "src/lib/novel/character-aura.ts")
- const createBuiltInCalls = auraContent.match(/createBuiltInAura\([\s\S]*?\)\s*,?\s*$/gm) || []
- for (const call of createBuiltInCalls) {
- const stringArgs = call.match(/"([^"]*)"/g) || []
- if (stringArgs.length < 8) continue
- const fields = {
- name: stringArgs[2].replace(/"/g, ""),
- corpus: stringArgs[3].replace(/"/g, ""),
- expressionDna: stringArgs[4].replace(/"/g, ""),
- mentalModel: stringArgs[5].replace(/"/g, ""),
- decisionHeuristics: stringArgs[6].replace(/"/g, ""),
- valueAntiPatterns: stringArgs[7].replace(/"/g, ""),
- }
- for (const [fieldName, value] of Object.entries(fields)) {
- if (/[A-Za-z]/.test(value)) {
- report("src/lib/novel/character-aura.ts", `角色 ${fields.name} 字段 ${fieldName} 包含英文: ${value.slice(0, 60)}`)
- }
- if (value.includes(CURLY_LEFT) || value.includes(CURLY_RIGHT)) {
- report("src/lib/novel/character-aura.ts", `角色 ${fields.name} 字段 ${fieldName} 包含弯引号`)
- }
- }
- }
- console.log()
- console.log("--- 中文角色 SKILL.md 弯引号检查 ---")
- walk(NVWA, (file) => {
- if (!file.endsWith("SKILL.md")) return
- const content = readFileSync(file, "utf8")
- const relPath = file.replace(ROOT, "").replace(/^[\\/]/, "")
- checkCurlyQuotes(stripFrontmatter(content), relPath)
- })
- console.log()
- console.log("--- 中文角色研究文件弯引号检查 ---")
- walk(NVWA, (file) => {
- if (!file.includes("research") || !file.endsWith(".md")) return
- const content = readFileSync(file, "utf8")
- const relPath = file.replace(ROOT, "").replace(/^[\\/]/, "")
- checkCurlyQuotes(content, relPath)
- })
- console.log()
- if (errors === 0) {
- console.log("✓ 全部通过!没有发现英文或弯引号问题。")
- process.exit(0)
- } else {
- console.log(`✗ 发现 ${errors} 个问题,请修复后重新运行。`)
- process.exit(1)
- }
|