Files
ycode/scripts/rea/recover-conversation-labels.mjs
T

36 lines
2.9 KiB
JavaScript

// Select literal locale strings from previously exported REA evidence; never execute target scripts.
import fs from 'node:fs/promises'
import crypto from 'node:crypto'
import { parse } from '@babel/parser'
const bundle = JSON.parse(await fs.readFile('.tmp/rea-runtime-scripts.json', 'utf8'))
const script = bundle.items.find(item => item.file_path?.endsWith('i18n-Cxy1Uuvv.js'))
if (!script?.source?.included) throw new Error('Missing REA-captured conversation locale')
const source = script.source.artifact.text
const hash = crypto.createHash('sha256').update(source).digest('hex')
if (hash !== script.source.artifact.sha256) throw new Error('REA source digest mismatch')
const literal = node => node?.type === 'StringLiteral' ? node.value : node?.type === 'TemplateLiteral' && node.expressions.length === 0 ? node.quasis[0].value.cooked : undefined
const objects = []
function visit(node) {
if (!node || typeof node !== 'object') return
if (node.type === 'ObjectExpression') {
const values = Object.fromEntries(node.properties.filter(p => p.type === 'ObjectProperty' && typeof p.key.value === 'string' && literal(p.value) !== undefined).map(p => [p.key.value, literal(p.value)]))
if (values['task.creating']) objects.push(values)
}
for (const value of Object.values(node)) {
if (Array.isArray(value)) value.forEach(visit)
else if (value && typeof value === 'object') visit(value)
}
}
visit(parse(source, { sourceType: 'module' }).program)
const chinese = objects.find(values => values['task.creating'] === '正在创建任务')
const english = objects.find(values => values['task.creating'] === 'Creating task')
if (!chinese || !english) throw new Error('Selected literal locale dictionaries not found')
const wanted = key => /^(tool\.planCreate\.|tool\.task\.|task\.|action\.(accept|reject)$|message\.loading\.thinking$|common\.loading$)/.test(key)
const zh = Object.fromEntries(Object.entries(chinese).filter(([key]) => wanted(key)))
const en = Object.fromEntries(Object.entries(english).filter(([key]) => wanted(key)))
const file = 'src/renderer/src/workbuddy/conversation/labels.ts'
const header = `// Generated from REA ${bundle.evidence_id}.\n// i18n-Cxy1Uuvv.js SHA-256 ${hash}.\n// Default zh-cn matches the captured package default and YCode's current Chinese interface.\n`
const text = header + `const zhCN = ${JSON.stringify(zh, null, 2)} as const\nconst en = ${JSON.stringify(en, null, 2)} as const\n\nexport function conversationLabel(key: keyof typeof zhCN, params: Record<string, string | number> = {}, locale: 'zh-cn' | 'en' = 'zh-cn'): string {\n const dictionary = locale === 'en' ? en : zhCN\n return dictionary[key].replace(/\\{([^{}]+)\\}/g, (match, name: string) => params[name] === undefined ? match : String(params[name]))\n}\n`
await fs.writeFile(file, text)
console.log(JSON.stringify({ file, evidence: bundle.evidence_id, sourceSha256: hash, keys: Object.keys(zh).length }))