75 lines
2.9 KiB
JavaScript
75 lines
2.9 KiB
JavaScript
import { existsSync, readFileSync } from 'node:fs'
|
|
|
|
const requiredFiles = [
|
|
'src/app/App.tsx',
|
|
'src/pages/login.tsx',
|
|
'src/pages/workspace-body.tsx',
|
|
'src/pages/workspace-home.tsx',
|
|
'src/pages/workspace-explore.tsx',
|
|
'src/pages/projects/project-overview.tsx',
|
|
'src/pages/projects/project-channel-page.tsx',
|
|
'src/pages/projects/project-tasks.tsx',
|
|
'src/pages/projects/project-ai.tsx',
|
|
'src/pages/projects/project-notes.tsx',
|
|
'src/pages/projects/project-cron.tsx',
|
|
'src/pages/projects/project-new-channel.tsx',
|
|
'src/pages/projects/project-rail.tsx',
|
|
'src/pages/projects/project-sidebar.tsx',
|
|
'src/pages/projects/project-topbar.tsx',
|
|
'src/pages/projects/project-statusbar.tsx',
|
|
'src/pages/projects/project-types.ts',
|
|
'src/api/client.ts',
|
|
'src/api/projects.ts',
|
|
'src/api/mappers.tsx',
|
|
]
|
|
|
|
const failures = requiredFiles.filter((file) => !existsSync(file)).map((file) => `missing ${file}`)
|
|
|
|
const html = readFileSync('index.html', 'utf8')
|
|
if (!html.includes('<html lang="zh-CN">')) failures.push('index language must be zh-CN')
|
|
if (!html.includes('<title>森林AI</title>')) failures.push('document title must be 森林AI')
|
|
if (!html.includes('href="/senlinai-icon.svg"')) failures.push('favicon must use /senlinai-icon.svg')
|
|
if (!existsSync('public/senlinai-icon.svg')) failures.push('missing public/senlinai-icon.svg')
|
|
|
|
for (const file of ['src/pages/login.tsx', 'src/pages/projects/project-topbar.tsx', 'src/pages/projects/project-rail.tsx']) {
|
|
const source = readFileSync(file, 'utf8')
|
|
if (!source.includes('/senlinai-icon.svg')) failures.push(`${file} must use the brand icon`)
|
|
}
|
|
|
|
for (const forbidden of ['森林Agent', 'SenlinAI Workbench']) {
|
|
for (const file of requiredFiles.filter((name) => name.endsWith('.tsx'))) {
|
|
if (readFileSync(file, 'utf8').includes(forbidden)) failures.push(`${file} contains legacy product name ${forbidden}`)
|
|
}
|
|
}
|
|
|
|
const projectRailSource = readFileSync('src/pages/projects/project-rail.tsx', 'utf8')
|
|
if (!projectRailSource.includes('projectNameLabel(project.name)')) {
|
|
failures.push('project rail labels must derive from the project name')
|
|
}
|
|
|
|
if (existsSync('src/App.tsx')) {
|
|
failures.push('legacy src/App.tsx should be removed after page split')
|
|
}
|
|
|
|
for (const removed of ['src/pages/projects/project-data.tsx', 'src/pages/projects/project-inspector.tsx', 'src/pages/projects/project-inbox.tsx']) {
|
|
if (existsSync(removed)) {
|
|
failures.push(`${removed} should be removed; frontend data must come from backend APIs`)
|
|
}
|
|
}
|
|
|
|
if (existsSync('src/app/App.tsx')) {
|
|
const appSource = readFileSync('src/app/App.tsx', 'utf8')
|
|
for (const forbidden of ['function LoginPage', 'function Workbench', 'function OverviewContent']) {
|
|
if (appSource.includes(forbidden)) {
|
|
failures.push(`src/app/App.tsx still contains ${forbidden}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (failures.length) {
|
|
console.error(failures.join('\n'))
|
|
process.exit(1)
|
|
}
|
|
|
|
console.log('structure ok')
|