242 lines
11 KiB
JavaScript
242 lines
11 KiB
JavaScript
// Recover the pure source MetaFold summary closure from retained REA evidence. Never execute target code.
|
|
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import crypto from 'node:crypto'
|
|
import { parse } from '@babel/parser'
|
|
import generateModule from '@babel/generator'
|
|
|
|
const generate = generateModule.default ?? generateModule
|
|
const EVIDENCE_ID = 'ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb'
|
|
const SOURCE_SHA256 = '6c6ce63c93854783270e855572797d75e536e3b8d4548410e31fe9d147e1feb4'
|
|
const SOURCE_FILE = 'renderer/assets/src-DbE1_mgM.js'
|
|
const SOURCE_OFFSETS = {
|
|
isToolCallContent: 952112,
|
|
normalizeToolName: 952201,
|
|
getToolDescriptor: 952401,
|
|
descriptorTable: 952539,
|
|
objectHelpers: 961954,
|
|
extractAtom: 963323,
|
|
summaryDecision: 966216,
|
|
summaryRender: 967441,
|
|
computeFoldSummary: 969838
|
|
}
|
|
const BUNDLE_PATH = '.tmp/rea-runtime-scripts.json'
|
|
const OUTPUT_DIR = 'src/renderer/src/workbuddy/conversation/recovered-fold-summary'
|
|
|
|
const bundle = JSON.parse(fs.readFileSync(BUNDLE_PATH, 'utf8'))
|
|
if (bundle.evidence_id !== EVIDENCE_ID) throw new Error(`Unexpected REA Evidence: ${bundle.evidence_id}`)
|
|
const sourceItems = bundle.items.filter(item => item.file_path?.replaceAll('\\', '/').endsWith(`/${SOURCE_FILE}`))
|
|
if (sourceItems.length !== 1 || !sourceItems[0].source?.included) throw new Error(`Expected one included REA artifact ${SOURCE_FILE}`)
|
|
const artifact = sourceItems[0].source.artifact
|
|
const source = artifact.text
|
|
const digest = crypto.createHash('sha256').update(source).digest('hex')
|
|
if (artifact.sha256 !== SOURCE_SHA256 || digest !== SOURCE_SHA256) throw new Error(`REA source identity mismatch: ${digest}`)
|
|
|
|
const ast = parse(source, { sourceType: 'unambiguous', errorRecovery: true, plugins: ['jsx', 'decorators-legacy'] })
|
|
if (ast.errors.length) throw new Error(`Babel reported parse errors: ${ast.errors.map(error => error.message).join('; ')}`)
|
|
|
|
const declarations = new Map()
|
|
const assignments = new Map()
|
|
function visit(node) {
|
|
if (!node || typeof node !== 'object' || typeof node.type !== 'string') return
|
|
if (node.type === 'FunctionDeclaration' && node.id) {
|
|
const matches = declarations.get(node.id.name) ?? []
|
|
matches.push(node)
|
|
declarations.set(node.id.name, matches)
|
|
}
|
|
if (node.type === 'AssignmentExpression' && node.left.type === 'Identifier') {
|
|
const matches = assignments.get(node.left.name) ?? []
|
|
matches.push(node)
|
|
assignments.set(node.left.name, matches)
|
|
}
|
|
for (const value of Object.values(node)) {
|
|
if (Array.isArray(value)) value.forEach(visit)
|
|
else if (value && typeof value === 'object' && typeof value.type === 'string') visit(value)
|
|
}
|
|
}
|
|
visit(ast.program)
|
|
|
|
function code(node) {
|
|
return generate(node, { compact: false, concise: false, comments: false }).code
|
|
}
|
|
|
|
function uniqueFunction(name, start, end) {
|
|
const matches = (declarations.get(name) ?? []).filter(node => node.start >= start && node.start < end)
|
|
if (matches.length !== 1) throw new Error(`Expected one source function ${name} in [${start}, ${end}), found ${matches.length}`)
|
|
return matches[0]
|
|
}
|
|
|
|
function uniqueAssignment(name, predicate, start, end) {
|
|
const matches = (assignments.get(name) ?? []).filter(node => node.start >= start && node.start < end && predicate(node.right))
|
|
if (matches.length !== 1) throw new Error(`Expected one anchored source initializer ${name} in [${start}, ${end}), found ${matches.length}`)
|
|
return matches[0].right
|
|
}
|
|
|
|
function staticString(node) {
|
|
if (node?.type === 'StringLiteral') return node.value
|
|
if (node?.type === 'TemplateLiteral' && node.expressions.length === 0) return node.quasis[0].value.cooked
|
|
return undefined
|
|
}
|
|
|
|
function staticObjectValues(node) {
|
|
if (node?.type !== 'ObjectExpression') return new Map()
|
|
return new Map(node.properties
|
|
.filter(property => property.type === 'ObjectProperty')
|
|
.map(property => [staticString(property.key) ?? property.key.name, staticString(property.value)])
|
|
.filter(([key]) => key !== undefined))
|
|
}
|
|
|
|
const descriptorTable = uniqueAssignment('Nw', node => {
|
|
if (node.type !== 'ArrayExpression' || node.elements.length < 30) return false
|
|
const first = staticObjectValues(node.elements[0])
|
|
return first.get('canonical') === 'read_file' && first.get('category') === 'file_read' && first.get('group') === 'read'
|
|
}, 952500, 961600)
|
|
if (descriptorTable.elements.length !== 40) throw new Error(`Unexpected source descriptor count: ${descriptorTable.elements.length}`)
|
|
|
|
const sourceConstants = [
|
|
['Pw', node => staticString(node) === '__automation_update', 961580, 961650],
|
|
['Fw', node => staticObjectValues(node).get('canonical') === 'unknown' && staticObjectValues(node).get('category') === 'unknown', 961600, 961800],
|
|
['zw', node => node.type === 'NewExpression' && node.callee.name === 'Set', 963650, 963800],
|
|
['Bw', node => node.type === 'NewExpression' && node.callee.name === 'Set', 963750, 963850],
|
|
['Vw', node => node.type === 'NewExpression' && node.callee.name === 'Set', 963800, 963900],
|
|
['Hw', node => node.type === 'NumericLiteral' && node.value === 16, 963850, 963900],
|
|
['Uw', node => node.type === 'NumericLiteral' && node.value === 6, 963850, 963920],
|
|
['Gw', node => node.type === 'ArrayExpression' && staticString(node.elements[0]) === '现在', 965580, 965950],
|
|
['Kw', node => node.type === 'ArrayExpression' && staticString(node.elements[0]) === '已完成', 965900, 966100],
|
|
['qw', node => node.type === 'RegExpLiteral' && node.pattern.includes('u4EFB'), 966050, 966220],
|
|
['Jw', node => node.type === 'NumericLiteral' && node.value === 10, 966190, 966250],
|
|
['Yw', node => node.type === 'NumericLiteral' && node.value === 0.7, 966190, 966250],
|
|
['Qw', node => node.type === 'ObjectExpression' && staticObjectValues(node).get('read') === 'metaFold.summary.group.read', 968480, 968930],
|
|
['$w', node => node.type === 'ObjectExpression' && staticObjectValues(node).get('read') === 'metaFold.summary.groupNoTopic.read', 968900, 969420],
|
|
['eT', node => node.type === 'ObjectExpression' && staticObjectValues(node).get('read') === 'metaFold.summary.groupVerb.read', 969350, 969850]
|
|
]
|
|
const constants = sourceConstants.map(([name, predicate, start, end]) => [name, uniqueAssignment(name, predicate, start, end)])
|
|
|
|
const functionNames = [
|
|
'isToolCallContent', 'normalizeToolName$1', 'getToolDescriptor',
|
|
'hasCJK', 'compressPath', 'compressUrl', 'truncateObject', 'displayText', 'compressObject',
|
|
'extractObject', 'resolveStatus', 'extractAtom', 'bucketByGroup', 'dominantBucket',
|
|
'stripLeadingFillers', 'stripTrailingModifiers', 'extractKeyPhrase', 'topicFromAdjacentText',
|
|
'deriveTopic', 'aggregateStatus', 'hasUsefulInfo', 'selectSummary', 'compose', 'groupText',
|
|
'renderBase', 'renderTemplate', 'computeFoldSummary'
|
|
]
|
|
const summaryFunctions = functionNames.map(name => {
|
|
const node = name === 'isToolCallContent' || name === 'normalizeToolName$1' || name === 'getToolDescriptor'
|
|
? uniqueFunction(name, 952000, 952510)
|
|
: uniqueFunction(name, 961900, 970050)
|
|
return { name, node }
|
|
})
|
|
const expectedOffsets = {
|
|
isToolCallContent: 952112,
|
|
'normalizeToolName$1': 952201,
|
|
getToolDescriptor: 952401,
|
|
hasCJK: 961954,
|
|
extractAtom: 963323,
|
|
aggregateStatus: 966216,
|
|
compose: 967441,
|
|
computeFoldSummary: 969838
|
|
}
|
|
for (const { name, node } of summaryFunctions) {
|
|
const expected = expectedOffsets[name]
|
|
if (expected !== undefined && node.start !== expected) throw new Error(`${name} source offset changed: ${node.start}`)
|
|
}
|
|
|
|
const constantCode = [
|
|
`const Nw = ${code(descriptorTable)};`,
|
|
...constants.map(([name, value]) => `const ${name} = ${code(value)};`),
|
|
'const Iw = new Map();',
|
|
'const Lw = new Map();',
|
|
'for (const descriptor of Nw) {',
|
|
' Lw.set(descriptor.canonical, descriptor);',
|
|
' Iw.set(descriptor.canonical.toLowerCase(), descriptor.canonical);',
|
|
' for (const alias of descriptor.aliases) Iw.set(alias.toLowerCase(), descriptor.canonical);',
|
|
'}'
|
|
].join('\n')
|
|
|
|
const recoveredFunctions = summaryFunctions.map(({ node }) => code(node)).join('\n\n')
|
|
const generated = `// Generated from REA ${EVIDENCE_ID}; source SHA-256 ${SOURCE_SHA256}.
|
|
// AST-scoped pure MetaFold summary closure; source initialization code and the application translator are excluded.
|
|
${constantCode}
|
|
|
|
${recoveredFunctions}
|
|
|
|
// The source function falls back to its application-level xa translator. This adapter always supplies t.
|
|
export function computeSourceFoldSummary(parts, options) {
|
|
if (typeof options?.t !== 'function') throw new TypeError('A source-label translator must be provided')
|
|
return computeFoldSummary(parts, {
|
|
adjacentText: options.adjacentText,
|
|
isRunning: options.isRunning,
|
|
t: options.t
|
|
})
|
|
}
|
|
`
|
|
|
|
const declaration = `// Generated from REA ${EVIDENCE_ID}; source SHA-256 ${SOURCE_SHA256}.
|
|
export type SourceFoldSummaryStatus = 'waiting' | 'cancelled' | 'running' | 'success'
|
|
|
|
export interface SourceFoldSummary {
|
|
text: string
|
|
status: SourceFoldSummaryStatus
|
|
isFallback: boolean
|
|
}
|
|
|
|
export interface SourceFoldSummaryTool {
|
|
name?: string
|
|
args?: unknown
|
|
result?: unknown
|
|
status?: string
|
|
pendingConfirmation?: boolean
|
|
}
|
|
|
|
export interface SourceFoldSummaryPart {
|
|
type?: string
|
|
tool?: SourceFoldSummaryTool
|
|
}
|
|
|
|
export interface SourceFoldSummaryOptions {
|
|
adjacentText?: string
|
|
isRunning?: boolean
|
|
t: (key: string, params?: Readonly<Record<string, string | number>>) => string
|
|
}
|
|
|
|
export function computeSourceFoldSummary(
|
|
parts: readonly SourceFoldSummaryPart[],
|
|
options: SourceFoldSummaryOptions
|
|
): SourceFoldSummary
|
|
`
|
|
|
|
fs.mkdirSync(OUTPUT_DIR, { recursive: true })
|
|
fs.writeFileSync(path.join(OUTPUT_DIR, 'index.mjs'), generated)
|
|
fs.writeFileSync(path.join(OUTPUT_DIR, 'index.d.ts'), declaration)
|
|
fs.writeFileSync(path.join(OUTPUT_DIR, 'index.d.mts'), declaration)
|
|
|
|
const outputDigest = crypto.createHash('sha256').update(generated).digest('hex')
|
|
const manifest = {
|
|
evidenceId: EVIDENCE_ID,
|
|
artifact: SOURCE_FILE,
|
|
sha256: SOURCE_SHA256,
|
|
parser: '@babel/parser; source was not executed',
|
|
generator: '@babel/generator',
|
|
sourceOffsetsUtf16: {
|
|
...SOURCE_OFFSETS,
|
|
descriptorTableEndExclusive: descriptorTable.end,
|
|
descriptorCount: descriptorTable.elements.length,
|
|
constants: Object.fromEntries(constants.map(([name, value]) => [name, { start: value.start, endExclusive: value.end }]))
|
|
},
|
|
extractedFunctions: summaryFunctions.map(({ name, node }) => ({ name, start: node.start, endExclusive: node.end })),
|
|
applicationDependenciesExcluded: ['xa translator fallback (adapter requires options.t)', 'lazy module initialization', 'React and tool icon rendering'],
|
|
mapInitialization: 'source descriptor literal Nw plus exact canonical/alias Map population loop',
|
|
generatedFile: path.join(OUTPUT_DIR, 'index.mjs').replaceAll('\\', '/'),
|
|
generatedSha256: outputDigest
|
|
}
|
|
fs.writeFileSync(path.join(OUTPUT_DIR, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`)
|
|
console.log(JSON.stringify({
|
|
generatedFile: manifest.generatedFile,
|
|
evidenceId: EVIDENCE_ID,
|
|
sha256: SOURCE_SHA256,
|
|
generatedSha256: outputDigest,
|
|
descriptorCount: descriptorTable.elements.length,
|
|
functionCount: summaryFunctions.length,
|
|
sourceOffsetsUtf16: manifest.sourceOffsetsUtf16
|
|
}))
|