Files
ycode/scripts/rea/prepare-css-runtime.mjs
T

164 lines
16 KiB
JavaScript

// Prepare a reviewable local REA 6.5.0 repair. Never reads WorkBuddy or changes global registration.
import fs from 'node:fs/promises'
import path from 'node:path'
import crypto from 'node:crypto'
const sourceRoot = path.resolve(process.argv[2] || 'C:/Users/Administrator/scoop/apps/nvm/current/nodejs/nodejs/node_modules/rea-agents')
const output = path.resolve('.tmp/rea-css-runtime')
const patchRoot = path.resolve('scripts/rea/patches')
const sourcePackage = JSON.parse(await fs.readFile(path.join(sourceRoot, 'package.json'), 'utf8'))
if (sourcePackage.name !== 'rea-agents' || sourcePackage.version !== '6.5.0') throw new Error('Repair requires installed rea-agents 6.5.0')
if (output === sourceRoot || !output.startsWith(path.resolve('.tmp') + path.sep)) throw new Error('Invalid local repair destination')
await fs.mkdir(output, { recursive: true })
const marker = path.join(output, 'css-repair-manifest.json')
try {
const previous = JSON.parse(await fs.readFile(marker, 'utf8'))
if (previous.sourceRoot !== sourceRoot) throw new Error('Local repair belongs to a different source installation')
} catch (error) {
if (error.code !== 'ENOENT') throw error
for (const entry of await fs.readdir(sourceRoot, { withFileTypes: true })) {
if (entry.name === 'node_modules') continue
await fs.cp(path.join(sourceRoot, entry.name), path.join(output, entry.name), { recursive: true, force: false, errorOnExist: true, verbatimSymlinks: true })
}
await fs.symlink(path.join(sourceRoot, 'node_modules'), path.join(output, 'node_modules'), process.platform === 'win32' ? 'junction' : 'dir')
}
const records = []
const digest = text => crypto.createHash('sha256').update(text).digest('hex')
async function patch(relative, transform) {
const original = await fs.readFile(path.join(sourceRoot, relative), 'utf8')
const modified = transform(original)
if (original === modified) throw new Error(`No change for ${relative}`)
const baseline = path.join(output, 'css-repair-baseline', relative)
await fs.mkdir(path.dirname(baseline), { recursive: true })
await fs.writeFile(baseline, original)
await fs.writeFile(path.join(output, relative), modified)
records.push({ path: relative, original_sha256: digest(original), modified_sha256: digest(modified) })
}
function once(text, before, after) {
if (text.split(before).length !== 2) throw new Error(`Expected exactly one patch anchor: ${before.slice(0, 70)}`)
return text.replace(before, after)
}
// Use the package's shipped unbundled build, so CLI and MCP load the repaired modules.
await patch('scripts/rea.mjs', text => once(text.replaceAll('dist/mcp/main.js', 'dist/main.js')
.replaceAll('dist/cli-runtime/cli.js', 'dist/cli.js')
.replaceAll('dist/cli-runtime/cliOutput.js', 'dist/cliOutput.js')
.replaceAll('dist/cli-runtime/cliResultOutput.js', 'dist/cli/cliResultOutput.js'), 'if (!(await compiledRuntimeExists(runtimeFiles))) {', `if (args[0] === "inspect-desktop-electron-processes") {
const { inspectDesktopElectronProcesses } = await import("../dist/browser/DesktopElectronProcesses.js");
process.stdout.write(JSON.stringify(await inspectDesktopElectronProcesses(args[1] || "WorkBuddy.exe")) + "\\n");
} else if (args[0] === "restart-desktop-electron-debug") {
const { restartDesktopElectronDebug } = await import("../dist/browser/DesktopElectronProcesses.js");
process.stdout.write(JSON.stringify(await restartDesktopElectronDebug(args[1], Number(args[2]), args.includes("--restart-authorized"))) + "\\n");
} else if (args[0] === "export-selected-artifact-text") {
const { exportSelectedArtifactText } = await import("../dist/artifacts/SelectedArtifactText.js");
process.stdout.write(JSON.stringify(await exportSelectedArtifactText(args[1], args[2], JSON.parse(args[3]))) + "\\n");
} else if (args[0] === "export-selected-artifact-binary") {
const { exportSelectedArtifactText } = await import("../dist/artifacts/SelectedArtifactText.js");
process.stdout.write(JSON.stringify(await exportSelectedArtifactText(args[1], args[2], JSON.parse(args[3]), true)) + "\\n");
} else if (args[0] === "export-selected-conversation-text") {
const { exportSelectedConversationText } = await import("../dist/artifacts/SelectedConversationText.js");
process.stdout.write(JSON.stringify(await exportSelectedConversationText(args[1], args[2], args.includes("--include-images"))) + "\\n");
} else if (!(await compiledRuntimeExists(runtimeFiles))) {`))
await patch('package.json', text => {
const pkg = JSON.parse(text)
pkg.version = '6.5.0-visual.3'
return JSON.stringify(pkg, null, 2) + '\n'
})
await patch('dist/generatedPackageMetadata.js', text => once(text, 'version: "6.5.0",', 'version: "6.5.0-visual.3",'))
await patch('dist/domain/javascript/electronObservation.js', text => {
text = 'import { electronVisualProbeInputSchema, electronMediaAssetsSchema, platformFontSampleSchema, visualProbeOutputSchema } from "./ElectronVisualProbeSchema.js";\nimport { webScreenshotArtifactSchema } from "../webScreenshot.js";\n' + text
text = once(text, ' target_id: z.string().trim().min(1),', ' target_id: z.string().trim().min(1),\n include_style_sources: z.boolean().default(false).describe("Include CSS text from stylesheets attributed to authorized Electron frames"),\n include_visuals: z.boolean().default(false).describe("Include visible viewport PNG and attributed DOM layout styles"),')
text = text.replace(' include_visuals: z.boolean()', ' visual_probe: electronVisualProbeInputSchema.optional(),\n include_visuals: z.boolean()')
text = once(text, ']);\nconst electronTargetSchema', `]).superRefine((value, ctx) => {
if (value.visual_probe && !value.include_visuals) ctx.addIssue({code: "custom", message: "visual_probe requires include_visuals"});
});
const electronTargetSchema`)
text = once(text, ' workers: z', ` visuals: z.object({
captured_at: z.iso.datetime(),
viewport: z.object({width:z.number().int().positive(),height:z.number().int().positive()}),
css_viewport: z.object({width:z.number().positive(),height:z.number().positive(),page_x:z.number(),page_y:z.number()}),
environment_media:z.object({reduced_motion:z.boolean().nullable()}).optional(),
environment_gpu:z.object({status:z.enum(['observed','unavailable']),devices:z.array(z.object({vendor_id:z.number(),device_id:z.number(),device_string:z.string().optional(),active:z.boolean().optional()})).optional(),aux_attributes:z.record(z.string(),z.union([z.string(),z.number(),z.boolean(),z.null()])).optional(),feature_status:z.record(z.string(),z.string()).optional()}).optional(),
artifact: webScreenshotArtifactSchema,
layout: z.object({properties:z.array(z.string()),documents:z.array(z.object({frame_id:z.string(),file_path:z.string(),scroll_x:z.number(),scroll_y:z.number(),nodes:z.array(z.object({node_index:z.number().int(),parent_index:z.number().int(),node_name:z.string(),attributes:z.record(z.string(),z.string()),bounds:z.tuple([z.number(),z.number(),z.number(),z.number()]),styles:z.record(z.string(),z.string())})),svg_nodes:z.array(z.object({node_index:z.number().int(),parent_index:z.number().int(),node_name:z.string(),attributes:z.record(z.string(),z.string())}))}))}),
limitations:z.array(z.string()),
font_samples:z.array(platformFontSampleSchema.extend({bounds:z.tuple([z.number(),z.number(),z.number(),z.number()]).optional(),styles:z.record(z.string(),z.string()).optional()})).optional(),
font_missing:z.array(z.object({category:z.string(),reason:z.string()})).optional(),
message_content:z.object({nodes:z.array(z.object({node_index:z.number().int(),parent_index:z.number().int(),node_name:z.string(),attributes:z.record(z.string(),z.string()),text:z.string().optional(),selector:z.string().optional()})),text_characters:z.number().int().min(0),truncated:z.boolean()}).optional(),
probe:visualProbeOutputSchema.optional(),
media_assets:electronMediaAssetsSchema.optional(),
}).optional(),
workers: z`)
return once(text, ' workers: z', ` styles: z.object({
total: z.number().int().min(0),
items: z.array(z.object({
style_sheet_key: prefixedDigestSchema("electron_stylesheet"),
style_sheet_id: z.string(), frame_id: z.string().nullable(), file_path: z.string().nullable(),
origin: z.string(), is_inline: z.boolean(), is_constructed: z.boolean(), source: electronSourceSchema,
})),
excluded: z.number().int().min(0), source_failures: z.number().int().min(0), truncated: z.boolean(),
limits: z.object({ max_sheets: z.number().int().positive(), max_sheet_bytes: z.number().int().positive(), max_total_bytes: z.number().int().positive() }),
}).optional(),
workers: z`)
})
await patch('dist/browser/CdpElectronInspection.js', text => {
text = 'import { captureElectronVisuals } from "./CdpElectronVisuals.js";\nimport { ingestElectronStyleEvent, captureElectronStyles } from "./CdpElectronStyles.js";\n' + text
text = once(text,'"REA does not evaluate renderer JavaScript, invoke Electron APIs, navigate, click, or close the page."','"REA does not evaluate renderer JavaScript or invoke Electron APIs; declared visual_probe native inputs are the only optional UI actions."')
text = once(text, ' scripts: [],', ' scripts: [],\n styles: new Map(),')
text = once(text, ' ingestElectronScriptEvent({', ' if (context.input.include_style_sources) ingestElectronStyleEvent(event, state.styles);\n ingestElectronScriptEvent({')
text = once(text, ' await enableElectronCapture(context);', ` await enableElectronCapture(context);
if (context.input.include_style_sources) {
await context.connection.send("DOM.enable", {}, context.sessionId, context.signal);
await context.connection.send("CSS.enable", {}, context.sessionId, context.signal);
state.limitations.push("CSS capture is a local REA 6.5.0-css.1 extension: only currently loaded styles attributed to authorized file-page frames are eligible. No renderer JavaScript is evaluated. Styles have independent coverage and budgets; inspect the styles section.");
}`)
return once(text, ' return { dom, scripts, resources, workers };', ` const styles = await captureElectronStyles({
connection: context.connection, sessionId: context.sessionId, signal: context.signal,
styles: state.styles, frameIds, request: context.input,
completeness: state.completeness, limitations: state.limitations,
});
const visuals = await captureElectronVisuals(context, frames);
return { dom, scripts, resources, workers, styles, ...(visuals ? {visuals} : {}) };`)
})
await patch('dist/browser/CdpElectronProvider.js', text => {
text = once(text, ' return CDP_ELECTRON_PROVIDER_IDENTITY;', ' return { ...CDP_ELECTRON_PROVIDER_IDENTITY, version: "1+visual-local.3" };')
return once(text, '["Debugger", "Runtime", "Page"]', '["CSS", "DOM", "Debugger", "Runtime", "Page"]')
})
await patch('dist/application/javascript/ElectronEvidence.js', text => once(once(text, 'authority: "external-service",','authority: input.visual_probe?.actions?.length ? "controlled-replay" : "external-service",'),
' include_script_sources: input.include_script_sources,',
' include_script_sources: input.include_script_sources,\n include_style_sources: input.include_style_sources,\n include_visuals: input.include_visuals,\n ...(input.visual_probe ? { visual_probe: input.visual_probe } : {}),'))
await patch('dist/cliObservationOptions.js', text => once(text,
'export const electronPageInspectionOptions = z.object({',
'export const electronPageInspectionOptions = z.object({\n visualProbe: z.string().optional().describe("JSON for declared native UI actions, sampled PNG frames, font usage and opt-in media_selectors for loaded IMG bytes"),\n includeStyleSources: z.boolean().default(false).describe("Include attributed local or inline stylesheet CSS text"),\n includeVisuals: z.boolean().default(false).describe("Include current viewport PNG and layout styles"),'))
await patch('dist/cli/electronCommands.js', text => once(text,
' include_script_sources: options.includeScriptSources,',
' include_script_sources: options.includeScriptSources,\n include_style_sources: options.includeStyleSources,\n include_visuals: options.includeVisuals,\n ...(options.visualProbe ? {visual_probe: JSON.parse(options.visualProbe)} : {}),'))
await patch('dist/contracts/javascript/electronToolContracts.js', text => once(text,
'Returns frames, DOM structure, resource paths, and scripts without evaluating renderer JavaScript or invoking Electron APIs.',
'Returns frames, DOM structure, resource paths, scripts and optional attributed CSS sources without evaluating renderer JavaScript or invoking Electron APIs. Default inspection is passive. include_style_sources selects CSS text; include_visuals selects viewport PNG and layout. Optional visual_probe declares native hover/click/scroll/key/viewport actions, sequential PNG samples, and actual platform fonts; UI actions can change application state and restoration is limited. visual_probe.media_selectors explicitly selects at most four unique main-frame IMG nodes and their already loaded PNG/JPEG/GIF/WebP/SVG resources, with byte budgets, SHA/base64 and visibility reported separately; no HTTP fetch is performed. These are local REA extensions; inspect coverage, budgets, restoration and limitations.'))
const styleModule = await fs.readFile(path.join(patchRoot, 'CdpElectronStyles.js'), 'utf8')
await fs.writeFile(path.join(output, 'dist/browser/CdpElectronStyles.js'), styleModule)
records.push({ path: 'dist/browser/CdpElectronStyles.js', original_sha256: null, modified_sha256: digest(styleModule) })
const visualModule = await fs.readFile(path.join(patchRoot, 'CdpElectronVisuals.js'), 'utf8')
await fs.writeFile(path.join(output, 'dist/browser/CdpElectronVisuals.js'), visualModule)
records.push({ path: 'dist/browser/CdpElectronVisuals.js', original_sha256: null, modified_sha256: digest(visualModule) })
const processModule = await fs.readFile(path.join(patchRoot, 'DesktopElectronProcesses.js'), 'utf8')
await fs.writeFile(path.join(output, 'dist/browser/DesktopElectronProcesses.js'), processModule)
records.push({ path: 'dist/browser/DesktopElectronProcesses.js', original_sha256: null, modified_sha256: digest(processModule) })
for(const [source,destination] of [['ElectronVisualProbeSchema.js','domain/javascript/ElectronVisualProbeSchema.js'],['CdpElectronVisualProbe.js','browser/CdpElectronVisualProbe.js'],['CdpElectronPlatformFonts.js','browser/CdpElectronPlatformFonts.js'],['CdpElectronMediaAssets.js','browser/CdpElectronMediaAssets.js']]) {
const module=await fs.readFile(path.join(patchRoot,source),'utf8')
await fs.writeFile(path.join(output,'dist',destination),module)
records.push({path:'dist/'+destination,original_sha256:null,modified_sha256:digest(module)})
}
const selectedArtifactModule=await fs.readFile(path.join(patchRoot,'SelectedArtifactText.js'),'utf8')
await fs.writeFile(path.join(output,'dist/artifacts/SelectedArtifactText.js'),selectedArtifactModule)
records.push({path:'dist/artifacts/SelectedArtifactText.js',original_sha256:null,modified_sha256:digest(selectedArtifactModule)})
const conversationModule=await fs.readFile(path.join(patchRoot,'SelectedConversationText.js'),'utf8')
await fs.writeFile(path.join(output,'dist/artifacts/SelectedConversationText.js'),conversationModule)
records.push({path:'dist/artifacts/SelectedConversationText.js',original_sha256:null,modified_sha256:digest(conversationModule)})
const manifest = { sourceRoot, upstreamVersion: sourcePackage.version, localVersion: '6.5.0-visual.3', output, files: records,
notes: ['Local REA repair, not an upstream release.', 'Global installation and Codex registration unchanged.', 'Public scripts/rea.mjs entry point loads the shipped unbundled build.', 'Dependencies reused read-only through node_modules link.'] }
await fs.writeFile(marker, JSON.stringify(manifest, null, 2) + '\n')
console.log(JSON.stringify({ output, localVersion: manifest.localVersion, files: records.length }))