import fs from 'node:fs'; import path from 'node:path'; import { createRequire } from 'node:module'; import { execFileSync, spawnSync } from 'node:child_process'; import { createHash } from 'node:crypto'; import { parse } from '@babel/parser'; import postcss from 'postcss'; const require = createRequire(import.meta.url); const base = '0b2bc376aa8b6af9d2492b5620d8ae776391508d'; const output = '_local/quality-20261010'; const files = [...new Set(execFileSync('git', ['ls-files', '--cached', '--others', '--exclude-standard', '-z'], { encoding: 'utf8' }).split('\0'))].filter(Boolean); const original = f => execFileSync('git', ['show', `${base}:${f}`], { encoding: 'utf8', maxBuffer: 10e6 }); const read = f => fs.readFileSync(f, 'utf8'); const hash = v => createHash('sha256').update(v).digest('hex'); const protectedFiles = ['themes/default.json', 'packages/ui/src/theme/default.css', 'packages/ui/src/theme/primitives.css', 'packages/ui/src/theme/default-values.generated.ts', 'packages/ui/src/components/ui/tabs.tsx', 'packages/ui/src/theme/tabs.css', 'packages/ui/src/components/ui/carousel.tsx', 'packages/ui/src/theme/carousel.css', 'docs/guidelines/publisher-additional-review-2026-10-10.md']; const preservation = protectedFiles.map(file => ({ file, unchanged: hash(original(file)) === hash(read(file)) })); const cssImports = []; for (const file of files.filter(f => f.endsWith('.css'))) postcss.parse(read(file)).walkAtRules('import', n => { const spec = n.params.match(/^["']([^"']+)["']/)?.[1]; if (!spec) return; let resolved; try { resolved = spec.startsWith('.') ? path.resolve(path.dirname(file), spec) : require.resolve(spec); } catch {} if (!resolved && !spec.startsWith('.')) { try { const pieces = spec.split('/'); const pkg = pieces.slice(0, spec.startsWith('@') ? 2 : 1).join('/'); const directory = path.resolve('node_modules', pkg); const manifest = JSON.parse(read(path.join(directory, 'package.json'))); const entry = manifest.exports?.[spec === pkg ? '.' : `.${spec.slice(pkg.length)}`]; if (entry?.style) resolved = path.join(directory, entry.style); } catch {} } cssImports.push({ file, spec, resolved, exists: Boolean(resolved && fs.existsSync(resolved)) }); }); const exports = []; for (const pkg of ['ui', 'center-graphic']) { const dir = `packages/${pkg}`; const manifest = JSON.parse(read(`${dir}/package.json`)); const check = (v, key) => typeof v === 'string' ? exports.push({ package: manifest.name, key, file: `${dir}/${v}`, exists: fs.existsSync(path.join(dir, v)) }) : Object.entries(v).forEach(([name, value]) => check(value, `${key}/${name}`)); Object.entries(manifest.exports).forEach(([key, value]) => check(value, key)); } const walk = (n, fn) => { if (!n || typeof n !== 'object') return; if (n.type) fn(n); for (const [k, v] of Object.entries(n)) if (!['loc', 'start', 'end', 'comments'].includes(k)) Array.isArray(v) ? v.forEach(x => walk(x, fn)) : walk(v, fn); }; const clean = (key, value) => ['start', 'end', 'loc', 'extra', 'comments', 'leadingComments', 'trailingComments', 'innerComments'].includes(key) ? undefined : value; const tests = text => { const result = new Map(); walk(parse(text, { sourceType: 'module' }), n => { if (n.type === 'CallExpression' && n.callee.name === 'test' && n.arguments[0]?.type === 'StringLiteral') result.set(n.arguments[0].value, JSON.stringify(n, clean)); }); return result; }; const testPreservation = ['scripts/ai-generation-guard.test.mjs', 'scripts/publisher-components.test.mjs'].map(file => { const before = tests(original(file)), after = tests(read(file)); return { file, before: before.size, after: after.size, unchangedBodies: [...before].filter(([name, value]) => after.get(name) === value).length }; }); const snapshot = 'D:/디자인시스템/HMDesign-AI-Generation-Test/retest-20261010/reference/storybook-static/index.json'; const beforeIDs = Object.keys(JSON.parse(read(snapshot)).entries).sort(); const afterIDs = Object.keys(JSON.parse(read('storybook-static/index.json')).entries).sort(); const crossTokens = []; for (const id of ['02', '06', '07']) { const target = `D:/디자인시스템/HMDesign-AI-Generation-Test/retest-20261010/cross-model/${id}`; const r = spawnSync(process.execPath, ['scripts/ai-generation-guard.mjs', '--target', target, '--scope', 'FULL_SCREEN', '--mode', id === '07' ? 'DASHBOARD_ONLY' : 'GNB_ONLY', '--result', 'index.html', '--json'], { encoding: 'utf8' }); fs.writeFileSync(`${output}/cross-existing-${id}.json`, r.stdout); const report = JSON.parse(r.stdout); crossTokens.push({ id, guard: report.status, tokenFindings: report.issues.filter(i => i.code.startsWith('TOKEN')) }); } const result = { base, preservation, testPreservation, cssImports: { count: cssImports.length, missing: cssImports.filter(i => !i.exists) }, exports: { count: exports.length, missing: exports.filter(i => !i.exists) }, storyIDs: { before: beforeIDs.length, after: afterIDs.length, deleted: beforeIDs.filter(id => !afterIDs.includes(id)), added: afterIDs.filter(id => !beforeIDs.includes(id)) }, existingLowReasoningCases: { note: 'Reinspection of preserved historical output, not a new cross-model generation', cases: crossTokens } }; fs.writeFileSync(`${output}/contract-audit.json`, JSON.stringify(result, null, 2)); console.log(JSON.stringify(result, null, 2)); if (preservation.some(i => !i.unchanged) || testPreservation.some(i => i.before !== i.unchangedBodies) || result.cssImports.missing.length || result.exports.missing.length || result.storyIDs.deleted.length) process.exitCode = 1;