Files
ycode/scripts/rea/recover-skill-picker.mjs

48 lines
3.4 KiB
JavaScript

import fs from 'node:fs/promises'
import { createHash } from 'node:crypto'
import postcss from 'postcss'
const sha = text => createHash('sha256').update(text).digest('hex')
const archive = JSON.parse(await fs.readFile('.tmp/rea-runtime-scripts.json', 'utf8'))
const source = archive.items.find(item => item.file_path.endsWith('contexts-BMeWSUHk.js')).source.artifact
if (sha(source.text) !== '5f35b7489b107e21ef452c8ee88a95265756f6fc444841eef869228bbc44768b') throw Error('REA context SHA mismatch')
function definition(name) {
const start = source.text.indexOf(name + '=')
let quote = '', escaped = false, depth = 0
for (let i = start + name.length + 1; i < source.text.length; i++) {
const char = source.text[i]
if (quote) { if (escaped) escaped = false; else if (char === '\\') escaped = true; else if (char === quote) quote = ''; continue }
if (['`', '"', "'"].includes(char)) { quote = char; continue }
if (!depth && [',', '}'].includes(char)) return { start, end: i, value: source.text.slice(start + name.length + 1, i) }
if ('([{'.includes(char)) depth++
if (')]}'.includes(char)) depth--
}
throw Error('Unbounded source icon ' + name)
}
let icons = `/* REA ${archive.evidence_id}; contexts-BMeWSUHk.js ${source.sha256}. Literal SVG bodies recovered from archived source. */\nimport { useId, type SVGProps } from 'react'\nimport { jsx as sourceJsx, jsxs as sourceJsxs } from 'react/jsx-runtime'\n`
for (const name of ['SkillsIcon', 'PinIcon', 'UnpinIcon', 'SettingsIcon', 'SearchIcon$1', 'ClearFilledIcon']) {
const item = definition(name)
const body = item.value.replace(/^e=>/, '(e: SVGProps<SVGSVGElement>) =>').replaceAll('(0,bV.jsx)', 'sourceJsx').replaceAll('(0,bV.jsxs)', 'sourceJsxs').replaceAll('returnsource', 'return source').replaceAll('_Nt.useId', 'useId').replaceAll('...xV', 'width:16,height:16,xmlns:"http://www.w3.org/2000/svg"')
if (/bV\.|xV/.test(body)) throw Error('Unresolved source icon binding')
icons += `// UTF-16 [${item.start}, ${item.end})\nexport const ${name.replace('$1', '')} = ${body}\n`
}
await fs.mkdir('src/renderer/src/capabilities', { recursive: true })
await fs.writeFile('src/renderer/src/capabilities/SkillSourceIcons.tsx', icons)
const manifest = JSON.parse(await fs.readFile('.tmp/rea-css-recovered/manifest.json', 'utf8'))
let css = `/* REA ${manifest.sourceEvidenceId}; source modules _1mrhu_ and _s54xa_ only. */\n`
for (const file of ['contexts-BkjwYSZT.css', 'wb-input-add-CDNucW11.css']) {
const bytes = await fs.readFile('.tmp/rea-css-recovered/' + file)
// The export manifest pins the source digest; never silently consume a changed sheet.
if (!JSON.stringify(manifest).includes(sha(bytes))) throw Error('Unpinned CSS ' + file)
css += `/* ${file} sha256=${sha(bytes)} */\n`
const parsed = postcss.parse(bytes.toString())
parsed.walkRules(rule => {
if (!rule.selector.includes('_1mrhu_') && !rule.selector.includes('_s54xa_')) return
const clone = rule.clone()
clone.selector = clone.selectors.map(selector => '.yc-skill-picker ' + selector).join(',')
if (rule.parent.type === 'atrule') { const wrapper = rule.parent.clone({ nodes: [] }); wrapper.append(clone); css += wrapper.toString() + '\n' }
else css += clone.toString() + '\n'
})
}
await fs.writeFile('src/renderer/src/capabilities/skill-picker-source.css', css)
console.log(JSON.stringify({ source: archive.evidence_id, css: manifest.sourceEvidenceId, cssBytes: css.length }))