// Only retained REA evidence is read; this script never opens WorkBuddy or its installation. import fs from 'node:fs' import path from 'node:path' import { createHash } from 'node:crypto' import postcss from 'postcss' const sha = text => createHash('sha256').update(text).digest('hex') const archive = JSON.parse(fs.readFileSync('.tmp/rea-runtime-scripts.json', 'utf8')) const source = archive.items.find(item => item.file_path.endsWith('contexts-BMeWSUHk.js'))?.source.artifact const sourcePin = '5f35b7489b107e21ef452c8ee88a95265756f6fc444841eef869228bbc44768b' if (!source || source.sha256 !== sourcePin || sha(source.text) !== sourcePin) throw Error('REA runtime source digest mismatch') const cssManifest = JSON.parse(fs.readFileSync('.tmp/rea-css-recovered/manifest.json', 'utf8')) const cssIdentity = cssManifest.files.find(file => file.file === 'contexts-BkjwYSZT.css') const css = fs.readFileSync(path.join('.tmp/rea-css-recovered', cssIdentity.file), 'utf8') if (sha(css) !== cssIdentity.sha256) throw Error('REA CSS source digest mismatch') const output = postcss.root() postcss.parse(css).walkRules(rule => { if (!/\.conversation-(?:team-collaboration|member-detail)(?:[\s_.:#\[>+-]|$)/.test(rule.selector)) return let copy = rule.clone() for (let parent = rule.parent; parent?.type === 'atrule'; parent = parent.parent) { copy = parent.clone({ nodes: [copy] }) } output.append(copy) }) if (!output.nodes.length) throw Error('REA member CSS was not found') const folder = 'src/renderer/src/workbuddy/subagents' const header = `/* WorkBuddy 5.8.2; retained REA ${cssManifest.sourceEvidenceId}.\n * Exact selected source rules; host primitive adapters are kept separately.\n */\n` const result = header + output.toString().replaceAll('}', '}\n').trimEnd() + '\n' // The conversation's generated theme is scoped to .chat-pane. Give the sibling // member surface the same retained token declarations without leaking them globally. const memberTheme = postcss.root() postcss.parse(fs.readFileSync('src/renderer/src/workbuddy/conversation/source-styles.css', 'utf8')).walkRules(rule => { const selectors = rule.selectors.filter(selector => /^\.chat-pane\.cr-theme(?:\[data-cr-theme=(?:light|dark)\])?$/.test(selector)) if (!selectors.length) return const declarations = rule.nodes.filter(node => node.type === 'decl' && node.prop.startsWith('--')).map(node => node.clone()) if (declarations.length) memberTheme.append(postcss.rule({ selector: selectors.map(selector => selector.replace('.chat-pane', '.conversation-member-detail')).join(','), nodes: declarations })) }) if (!memberTheme.nodes.length) throw Error('Scoped conversation theme tokens were not found') const themeResult = '/* Same retained conversation token scopes for the sibling member detail surface. */\n' + memberTheme.toString().replaceAll('}', '}\n').trimEnd() + '\n' const manifest = { version: '5.8.2', runtimeEvidenceId: archive.evidence_id, runtimeFile: 'contexts-BMeWSUHk.js', runtimeSha256: sourcePin, cssEvidenceId: cssManifest.sourceEvidenceId, cssFile: cssIdentity.file, cssSha256: cssIdentity.sha256, rules: output.nodes.length, sourceRanges: { members: [6187325, 6193670], detail: [5913738, 5917850], finishedFooter: [6891900, 6892500], streamingFooter: [6977800, 6978800] }, adaptations: ['YCode SubagentSnapshot supplies identity, status and events.', 'The existing workbench owns member selection and its detail surface.', 'Source button/avatar/icon primitives bind to local React elements; adapters are separate.', 'Cancellation remains available from the member detail header.'], limitations: ['No current live WorkBuddy capture; full-state pixel and motion equivalence remains unverified.'], outputSha256: sha(result), themeOutputSha256: sha(themeResult) } fs.mkdirSync(folder, { recursive: true }) for (const [file, content] of [['source.css', result], ['theme.css', themeResult], ['manifest.json', JSON.stringify(manifest, null, 2) + '\n']]) { const target = path.join(folder, file) if (process.argv.includes('--check')) { if (fs.readFileSync(target, 'utf8') !== content) throw Error('Recovered source drift: ' + target) } else fs.writeFileSync(target, content) } console.log(JSON.stringify({ rules: output.nodes.length, cssEvidenceId: manifest.cssEvidenceId, outputSha256: manifest.outputSha256 }))