guanghulab/scripts/zhuyuan-full-inspection.js
2026-05-10 13:12:44 +08:00

735 lines
28 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* scripts/zhuyuan-full-inspection.js
* 铸渊全面排查脚本 · AGE OS v1.0 Phase 1 Step 1
*
* 铸渊核心大脑醒来后,全面排查仓库现状。
* 排查覆盖 8 个领域:
* 1. 仓库整体结构
* 2. 自动化流程现状
* 3. 仓库首页和入口
* 4. 公告栏和系统更新
* 5. 服务状态
* 6. 密钥和凭证(仅检查存在性)
* 7. 与四节点的连接状态
* 8. 人格体机器人托管现状
*
* 调用方式:
* node scripts/zhuyuan-full-inspection.js
* node scripts/zhuyuan-full-inspection.js --json
* node scripts/zhuyuan-full-inspection.js --output report.json
*/
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
// ══════════════════════════════════════════════════════════
// Area 1: 仓库整体结构
// ══════════════════════════════════════════════════════════
function inspectRepoStructure() {
console.log('\n📂 ═══ Area 1: 仓库整体结构 ═══');
const result = {
area: '仓库整体结构',
directories: {},
config_files: {},
doc_files: {},
issues: [],
};
// 核心目录
const coreDirs = [
{ path: 'brain', category: '核心', desc: '系统大脑/知识库' },
{ path: 'core', category: '核心', desc: '核心系统模块' },
{ path: 'connectors', category: '核心', desc: '外部集成连接器' },
{ path: 'src', category: '核心', desc: '源代码' },
{ path: 'scripts', category: '核心', desc: '自动化脚本' },
{ path: '.github/workflows', category: '核心', desc: 'GitHub Actions 工作流' },
{ path: 'backend', category: '功能', desc: '后端服务' },
{ path: 'backend-integration', category: '功能', desc: 'API 代理和集成' },
{ path: 'persona-studio', category: '功能', desc: '人格工作室' },
{ path: 'persona-brain-db', category: '功能', desc: '人格知识数据库' },
{ path: 'dingtalk-bot', category: '功能', desc: '钉钉机器人' },
{ path: 'frontend', category: '功能', desc: '前端代码' },
{ path: 'docs', category: '文档', desc: '文档' },
{ path: 'tests', category: '测试', desc: '测试套件' },
{ path: 'broadcasts', category: '数据', desc: '广播数据' },
{ path: 'bulletin-board', category: '数据', desc: '公告栏系统' },
{ path: 'notification', category: '功能', desc: '通知系统' },
{ path: 'dashboard', category: '功能', desc: '仪表盘' },
{ path: 'modules', category: '功能', desc: '功能模块' },
{ path: 'cloud-drive', category: '功能', desc: '云存储' },
];
for (const dir of coreDirs) {
const fullPath = path.join(ROOT, dir.path);
const exists = fs.existsSync(fullPath);
let fileCount = 0;
if (exists) {
try {
fileCount = fs.readdirSync(fullPath).length;
} catch {
// Directory exists but is unreadable — use 0 as fallback
}
}
result.directories[dir.path] = {
exists,
category: dir.category,
description: dir.desc,
fileCount,
};
const icon = exists ? '✅' : '❌';
console.log(` ${icon} ${dir.path} (${dir.category}) — ${dir.desc}${exists ? ` [${fileCount} items]` : ''}`);
if (!exists && dir.category === '核心') {
result.issues.push(`缺少核心目录: ${dir.path}`);
}
}
// 配置文件
const configFiles = [
'package.json', 'ecosystem.config.js', 'config.js',
'.gitignore', 'tsconfig.json', 'next.config.ts',
];
for (const f of configFiles) {
const exists = fs.existsSync(path.join(ROOT, f));
result.config_files[f] = exists;
console.log(` ${exists ? '✅' : '❌'} 配置: ${f}`);
}
// 文档完整度
const docFiles = [
'README.md', 'docs/repo-structure-map.md', 'docs/notion-bridge-map.md',
'brain/master-brain.md', 'brain/read-order.md',
];
for (const f of docFiles) {
const exists = fs.existsSync(path.join(ROOT, f));
result.doc_files[f] = exists;
console.log(` ${exists ? '✅' : '❌'} 文档: ${f}`);
if (!exists) {
result.issues.push(`缺少文档: ${f}`);
}
}
return result;
}
// ══════════════════════════════════════════════════════════
// Area 2: 自动化流程现状
// ══════════════════════════════════════════════════════════
function inspectAutomation() {
console.log('\n⚙ ═══ Area 2: 自动化流程现状 ═══');
const result = {
area: '自动化流程现状',
workflows: [],
scripts: [],
issues: [],
};
// 工作流文件
const workflowDir = path.join(ROOT, '.github/workflows');
if (fs.existsSync(workflowDir)) {
const files = fs.readdirSync(workflowDir).filter(f => f.endsWith('.yml') || f.endsWith('.yaml'));
console.log(` ✅ 发现 ${files.length} 个工作流文件`);
for (const file of files) {
const content = fs.readFileSync(path.join(workflowDir, file), 'utf-8');
const nameMatch = content.match(/^name:\s*["']?(.+?)["']?\s*$/m);
const cronMatch = content.match(/cron:\s*'([^']+)'/);
const hasWorkflowDispatch = content.includes('workflow_dispatch');
const workflow = {
file,
name: nameMatch ? nameMatch[1] : file,
hasCron: !!cronMatch,
cron: cronMatch ? cronMatch[1] : null,
hasManualTrigger: hasWorkflowDispatch,
category: categorizeWorkflow(file),
};
result.workflows.push(workflow);
console.log(` 📋 ${file}${workflow.name}${workflow.hasCron ? ` [cron: ${workflow.cron}]` : ''}${workflow.hasManualTrigger ? ' [手动]' : ''}`);
}
} else {
result.issues.push('工作流目录不存在');
console.log(' ❌ 工作流目录不存在');
}
// 脚本文件
const scriptsDir = path.join(ROOT, 'scripts');
if (fs.existsSync(scriptsDir)) {
const files = fs.readdirSync(scriptsDir).filter(f => f.endsWith('.js'));
console.log(` ✅ 发现 ${files.length} 个自动化脚本`);
for (const file of files) {
result.scripts.push({
file,
category: categorizeScript(file),
});
}
}
// 核心模块
const coreModules = [
'core/broadcast-listener/index.js',
'core/task-queue/index.js',
'core/system-check/index.js',
'core/execution-sync/index.js',
'core/context-loader/index.js',
'core/brain-wake/index.js',
'connectors/notion-sync/index.js',
'connectors/notion-wake-listener/index.js',
'connectors/model-router/index.js',
];
console.log('\n 🔧 核心模块:');
for (const mod of coreModules) {
const exists = fs.existsSync(path.join(ROOT, mod));
console.log(` ${exists ? '✅' : '❌'} ${mod}`);
if (!exists) {
result.issues.push(`缺少核心模块: ${mod}`);
}
}
return result;
}
function categorizeWorkflow(filename) {
if (filename.includes('deploy')) return '部署';
if (filename.includes('maintenance') || filename.includes('selfcheck')) return '维护';
if (filename.includes('agent')) return 'Agent';
if (filename.includes('brain') || filename.includes('sync')) return '同步';
if (filename.includes('syslog') || filename.includes('pipeline')) return '管线';
if (filename.includes('notion')) return 'Notion';
if (filename.includes('ps-on')) return '人格体';
if (filename.includes('bridge')) return '桥接';
return '其他';
}
function categorizeScript(filename) {
if (filename.includes('generate-')) return '生成器';
if (filename.includes('zhuyuan-')) return '铸渊';
if (filename.includes('bingshuo-')) return '冰朔';
if (filename.includes('notion-') || filename.includes('sync')) return 'Notion';
if (filename.includes('wake-') || filename.includes('invoke-')) return '唤醒';
if (filename.includes('push-') || filename.includes('distribute')) return '广播';
if (filename.includes('syslog') || filename.includes('pipeline')) return '管线';
return '工具';
}
// ══════════════════════════════════════════════════════════
// Area 3: 仓库首页和入口
// ══════════════════════════════════════════════════════════
function inspectEntryPoints() {
console.log('\n🏠 ═══ Area 3: 仓库首页和入口 ═══');
const result = {
area: '仓库首页和入口',
readme: null,
entryPoints: {},
issues: [],
};
// README.md
const readmePath = path.join(ROOT, 'README.md');
if (fs.existsSync(readmePath)) {
const content = fs.readFileSync(readmePath, 'utf-8');
result.readme = {
exists: true,
length: content.length,
hasTitle: content.includes('#'),
hasBulletin: content.includes('公告') || content.includes('bulletin'),
hasDevGuide: content.includes('开发') || content.includes('developer') || content.includes('指南'),
};
console.log(` ✅ README.md (${content.length} chars)`);
console.log(` 标题: ${result.readme.hasTitle ? '✅' : '❌'}`);
console.log(` 公告栏: ${result.readme.hasBulletin ? '✅' : '❌'}`);
console.log(` 开发指南: ${result.readme.hasDevGuide ? '✅' : '❌'}`);
} else {
result.readme = { exists: false };
result.issues.push('README.md 不存在');
console.log(' ❌ README.md 不存在');
}
// 开发者入口
const entryPoints = [
{ path: 'frontend/index.html', desc: '前端入口' },
{ path: 'index.html', desc: '主页入口' },
{ path: 'index.js', desc: '主 JS 入口' },
{ path: 'src/index.js', desc: 'src 入口' },
{ path: 'homepage/index.html', desc: '首页入口' },
{ path: 'portal/index.html', desc: '门户入口' },
{ path: 'dashboard/index.html', desc: '仪表盘入口' },
];
for (const entry of entryPoints) {
const exists = fs.existsSync(path.join(ROOT, entry.path));
result.entryPoints[entry.path] = { exists, description: entry.desc };
console.log(` ${exists ? '✅' : '⏭️ '} ${entry.desc}: ${entry.path}`);
}
return result;
}
// ══════════════════════════════════════════════════════════
// Area 4: 公告栏和系统更新
// ══════════════════════════════════════════════════════════
function inspectBulletins() {
console.log('\n📢 ═══ Area 4: 公告栏和系统更新 ═══');
const result = {
area: '公告栏和系统更新',
bulletinBoard: {},
systemLogs: {},
issues: [],
};
// 公告栏目录
const bulletinDir = path.join(ROOT, 'bulletin-board');
if (fs.existsSync(bulletinDir)) {
const files = fs.readdirSync(bulletinDir);
result.bulletinBoard.exists = true;
result.bulletinBoard.fileCount = files.length;
console.log(` ✅ bulletin-board/ (${files.length} 文件)`);
} else {
result.bulletinBoard.exists = false;
console.log(' ❌ bulletin-board/ 不存在');
}
// brain 公告缓存
const cacheFile = path.join(ROOT, '.github/brain/bulletin-board-today.json');
if (fs.existsSync(cacheFile)) {
try {
const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf-8'));
result.bulletinBoard.cacheDate = cache.date || 'unknown';
result.bulletinBoard.cacheRecords = (cache.records || []).length;
console.log(` ✅ 公告栏缓存日期: ${cache.date} (${(cache.records || []).length} 条记录)`);
} catch (err) {
console.log(' ⚠️ 公告栏缓存 JSON 解析失败:', err.message);
}
} else {
console.log(' ⏭️ 公告栏缓存文件不存在');
}
// 广播目录
const broadcastsDirs = ['broadcasts', 'broadcasts-outbox'];
for (const dir of broadcastsDirs) {
const fullPath = path.join(ROOT, dir);
if (fs.existsSync(fullPath)) {
const files = fs.readdirSync(fullPath);
result.systemLogs[dir] = { exists: true, fileCount: files.length };
console.log(`${dir}/ (${files.length} 文件)`);
} else {
result.systemLogs[dir] = { exists: false };
console.log(` ⏭️ ${dir}/ 不存在`);
}
}
// 公告相关工作流
const bulletinWorkflows = ['update-readme-bulletin.yml'];
for (const wf of bulletinWorkflows) {
const exists = fs.existsSync(path.join(ROOT, '.github/workflows', wf));
console.log(` ${exists ? '✅' : '❌'} 工作流: ${wf}`);
if (!exists) {
result.issues.push(`缺少公告工作流: ${wf}`);
}
}
return result;
}
// ══════════════════════════════════════════════════════════
// Area 5: 服务状态
// ══════════════════════════════════════════════════════════
function inspectServices() {
console.log('\n🖥 ═══ Area 5: 服务状态 ═══');
const result = {
area: '服务状态',
services: [],
configs: {},
issues: [],
};
// PM2 配置
const ecosystemPath = path.join(ROOT, 'ecosystem.config.js');
if (fs.existsSync(ecosystemPath)) {
try {
const content = fs.readFileSync(ecosystemPath, 'utf-8');
const appMatches = content.match(/name\s*:\s*['"]([^'"]+)['"]/g) || [];
const apps = appMatches.map(m => m.match(/['"]([^'"]+)['"]/)[1]);
result.services = apps.map(name => ({ name, source: 'ecosystem.config.js' }));
console.log(` ✅ ecosystem.config.js (${apps.length} 个应用)`);
apps.forEach(app => console.log(` 📋 ${app}`));
} catch {
console.log(' ⚠️ ecosystem.config.js 解析失败');
}
} else {
result.issues.push('ecosystem.config.js 不存在');
console.log(' ❌ ecosystem.config.js 不存在');
}
// Nginx 配置
const nginxPath = path.join(ROOT, 'backend-integration/nginx-api-proxy.conf');
if (fs.existsSync(nginxPath)) {
const content = fs.readFileSync(nginxPath, 'utf-8');
const locationMatches = content.match(/location\s+([^\s{]+)/g) || [];
result.configs.nginx = {
exists: true,
routes: locationMatches.map(m => m.replace('location ', '')),
};
console.log(` ✅ nginx-api-proxy.conf (${locationMatches.length} 路由)`);
locationMatches.forEach(m => console.log(` 📋 ${m}`));
} else {
result.configs.nginx = { exists: false };
console.log(' ⏭️ nginx-api-proxy.conf 不存在');
}
// 后端服务文件
const backendFiles = [
'backend/server.js',
'backend-integration/api-proxy.js',
'persona-studio/backend/server.js',
];
for (const f of backendFiles) {
const exists = fs.existsSync(path.join(ROOT, f));
result.configs[f] = exists;
console.log(` ${exists ? '✅' : '⏭️ '} ${f}`);
}
return result;
}
// ══════════════════════════════════════════════════════════
// Area 6: 密钥和凭证
// ══════════════════════════════════════════════════════════
function inspectCredentials() {
console.log('\n🔑 ═══ Area 6: 密钥和凭证(存在性检查)═══');
const result = {
area: '密钥和凭证',
envVars: {},
secretsUsed: [],
issues: [],
};
// 检查环境变量中可能的密钥配置
const envKeys = [
{ key: 'NOTION_TOKEN', purpose: 'Notion API 访问', category: 'Notion' },
{ key: 'LLM_API_KEY', purpose: 'LLM 平台通用密钥', category: 'LLM' },
{ key: 'LLM_BASE_URL', purpose: 'LLM 平台 API 地址', category: 'LLM' },
{ key: 'ANTHROPIC_API_KEY', purpose: 'Anthropic Claude API', category: 'LLM' },
{ key: 'OPENAI_API_KEY', purpose: 'OpenAI GPT API', category: 'LLM' },
{ key: 'DASHSCOPE_API_KEY', purpose: '通义千问 API', category: 'LLM' },
{ key: 'DEEPSEEK_API_KEY', purpose: 'DeepSeek API', category: 'LLM' },
{ key: 'GITHUB_TOKEN', purpose: 'GitHub API 访问', category: 'GitHub' },
{ key: 'FEISHU_APP_ID', purpose: '飞书应用 ID', category: '飞书' },
{ key: 'FEISHU_APP_SECRET', purpose: '飞书应用密钥', category: '飞书' },
{ key: 'DINGTALK_TOKEN', purpose: '钉钉机器人 Token', category: '钉钉' },
];
for (const env of envKeys) {
const isSet = !!process.env[env.key];
result.envVars[env.key] = {
isSet,
purpose: env.purpose,
category: env.category,
};
console.log(` ${isSet ? '✅' : '⏭️ '} ${env.key}${env.purpose} (${env.category})`);
}
// 扫描工作流文件中引用的 secrets
const workflowDir = path.join(ROOT, '.github/workflows');
if (fs.existsSync(workflowDir)) {
const files = fs.readdirSync(workflowDir).filter(f => f.endsWith('.yml') || f.endsWith('.yaml'));
const secretsSet = new Set();
for (const file of files) {
const content = fs.readFileSync(path.join(workflowDir, file), 'utf-8');
const matches = content.match(/secrets\.([A-Z_]+)/g) || [];
matches.forEach(m => secretsSet.add(m.replace('secrets.', '')));
}
result.secretsUsed = Array.from(secretsSet).sort();
console.log(`\n 📋 工作流中引用的 Secrets (${result.secretsUsed.length} 个):`);
result.secretsUsed.forEach(s => console.log(` 🔐 ${s}`));
}
return result;
}
// ══════════════════════════════════════════════════════════
// Area 7: 与四节点的连接状态
// ══════════════════════════════════════════════════════════
function inspectNodeConnections() {
console.log('\n🔗 ═══ Area 7: 与四节点的连接状态 ═══');
const result = {
area: '四节点连接状态',
nodes: {},
issues: [],
};
// GitHub ↔ Notion
const notionConnectors = [
'connectors/notion-sync/index.js',
'scripts/notion-signal-bridge.js',
'scripts/notion-heartbeat.js',
'scripts/write-notion-syslog.js',
];
const notionConnected = notionConnectors.filter(f => fs.existsSync(path.join(ROOT, f)));
result.nodes['Notion'] = {
connectors: notionConnected.length,
total: notionConnectors.length,
files: notionConnectors.map(f => ({ path: f, exists: fs.existsSync(path.join(ROOT, f)) })),
};
console.log(` 📋 GitHub ↔ Notion: ${notionConnected.length}/${notionConnectors.length} 连接器`);
notionConnectors.forEach(f => {
const exists = fs.existsSync(path.join(ROOT, f));
console.log(` ${exists ? '✅' : '❌'} ${f}`);
});
// GitHub ↔ 服务器 (guanghulab.com)
const serverConnectors = [
'backend/server.js',
'backend-integration/api-proxy.js',
'ecosystem.config.js',
'backend-integration/nginx-api-proxy.conf',
];
const serverConnected = serverConnectors.filter(f => fs.existsSync(path.join(ROOT, f)));
result.nodes['服务器'] = {
connectors: serverConnected.length,
total: serverConnectors.length,
files: serverConnectors.map(f => ({ path: f, exists: fs.existsSync(path.join(ROOT, f)) })),
};
console.log(` 📋 GitHub ↔ guanghulab.com: ${serverConnected.length}/${serverConnectors.length} 连接器`);
serverConnectors.forEach(f => {
const exists = fs.existsSync(path.join(ROOT, f));
console.log(` ${exists ? '✅' : '❌'} ${f}`);
});
// GitHub ↔ 飞书
const feishuConnectors = [
'scripts/send-feishu-alert.js',
'backend/routes/feishu-bot.js',
];
const feishuFiles = feishuConnectors.filter(f => fs.existsSync(path.join(ROOT, f)));
result.nodes['飞书'] = {
connectors: feishuFiles.length,
total: feishuConnectors.length,
files: feishuConnectors.map(f => ({ path: f, exists: fs.existsSync(path.join(ROOT, f)) })),
};
console.log(` 📋 GitHub ↔ 飞书: ${feishuFiles.length}/${feishuConnectors.length} 连接器`);
feishuConnectors.forEach(f => {
const exists = fs.existsSync(path.join(ROOT, f));
console.log(` ${exists ? '✅' : '❌'} ${f}`);
});
// GitHub ↔ 钉钉
const dingtalkConnectors = [
'dingtalk-bot/index.js',
'dingtalk-bot/package.json',
];
const dingtalkFiles = dingtalkConnectors.filter(f => fs.existsSync(path.join(ROOT, f)));
result.nodes['钉钉'] = {
connectors: dingtalkFiles.length,
total: dingtalkConnectors.length,
files: dingtalkConnectors.map(f => ({ path: f, exists: fs.existsSync(path.join(ROOT, f)) })),
};
console.log(` 📋 GitHub ↔ 钉钉: ${dingtalkFiles.length}/${dingtalkConnectors.length} 连接器`);
dingtalkConnectors.forEach(f => {
const exists = fs.existsSync(path.join(ROOT, f));
console.log(` ${exists ? '✅' : '❌'} ${f}`);
});
return result;
}
// ══════════════════════════════════════════════════════════
// Area 8: 人格体机器人托管现状
// ══════════════════════════════════════════════════════════
function inspectPersonaBots() {
console.log('\n🤖 ═══ Area 8: 人格体机器人托管现状 ═══');
const result = {
area: '人格体机器人托管现状',
personas: [],
issues: [],
};
// 扫描人格体相关目录和文件
const personaIndicators = [
{
name: '舒舒 (飞书)',
files: ['backend/routes/feishu-bot.js'],
config: [],
platform: '飞书',
},
{
name: '铸渊 (仓库守护)',
files: ['scripts/zhuyuan-daily-agent.js', 'scripts/zhuyuan-daily-selfcheck.js', 'scripts/zhuyuan-full-inspection.js'],
config: ['brain/master-brain.md', '.github/brain/wake-protocol.md'],
platform: 'GitHub',
},
{
name: '冰朔 (部署)',
files: ['scripts/bingshuo-deploy-agent.js', 'scripts/bingshuo-neural-sync.js'],
config: ['.github/brain/bingshuo-master-brain.md', '.github/brain/bingshuo-agent-registry.json'],
platform: 'GitHub',
},
];
// 人格工作室
const psDir = path.join(ROOT, 'persona-studio');
if (fs.existsSync(psDir)) {
console.log(' ✅ persona-studio/ 存在');
}
// 人格大脑数据库
const pbDir = path.join(ROOT, 'persona-brain-db');
if (fs.existsSync(pbDir)) {
console.log(' ✅ persona-brain-db/ 存在');
}
// 多人格模块
const mpDir = path.join(ROOT, 'multi-persona');
if (fs.existsSync(mpDir)) {
console.log(' ✅ multi-persona/ 存在');
}
for (const persona of personaIndicators) {
const existingFiles = persona.files.filter(f => fs.existsSync(path.join(ROOT, f)));
const existingConfig = persona.config.filter(f => fs.existsSync(path.join(ROOT, f)));
const status = {
name: persona.name,
platform: persona.platform,
codeFiles: existingFiles.length,
totalCodeFiles: persona.files.length,
configFiles: existingConfig.length,
totalConfigFiles: persona.config.length,
};
result.personas.push(status);
console.log(`\n 🤖 ${persona.name} (${persona.platform})`);
persona.files.forEach(f => {
const exists = fs.existsSync(path.join(ROOT, f));
console.log(` ${exists ? '✅' : '❌'} ${f}`);
});
persona.config.forEach(f => {
const exists = fs.existsSync(path.join(ROOT, f));
console.log(` ${exists ? '✅' : '⏭️ '} config: ${f}`);
});
}
// 唤醒脚本
const wakeScripts = ['scripts/wake-persona.js', 'scripts/invoke-persona.js'];
console.log('\n 🌅 唤醒脚本:');
for (const f of wakeScripts) {
const exists = fs.existsSync(path.join(ROOT, f));
console.log(` ${exists ? '✅' : '❌'} ${f}`);
}
return result;
}
// ══════════════════════════════════════════════════════════
// 生成排查报告
// ══════════════════════════════════════════════════════════
function generateFullReport(areas) {
const allIssues = areas.flatMap(a => a.issues || []);
const report = {
report_id: `INSPECT-${new Date().toISOString().slice(0, 10).replace(/-/g, '')}`,
version: 'AGE-OS-v1.0',
generated_at: new Date().toISOString(),
generated_by: '铸渊全面排查 · Phase 1 Step 1',
summary: {
total_areas: areas.length,
total_issues: allIssues.length,
issues_by_priority: {
critical: allIssues.filter(i => i.includes('核心')).length,
warning: allIssues.length - allIssues.filter(i => i.includes('核心')).length,
},
},
areas: {},
all_issues: allIssues,
};
for (const area of areas) {
report.areas[area.area] = area;
}
return report;
}
// ══════════════════════════════════════════════════════════
// 主执行函数
// ══════════════════════════════════════════════════════════
function run() {
console.log('');
console.log('🔍 ═══════════════════════════════════════════');
console.log(' 铸渊全面排查 · AGE OS v1.0 Phase 1 Step 1');
console.log(' 时间: ' + new Date().toISOString());
console.log('═══════════════════════════════════════════════');
const areas = [
inspectRepoStructure(),
inspectAutomation(),
inspectEntryPoints(),
inspectBulletins(),
inspectServices(),
inspectCredentials(),
inspectNodeConnections(),
inspectPersonaBots(),
];
const report = generateFullReport(areas);
console.log('\n');
console.log('═══════════════════════════════════════════════');
console.log(`📊 排查报告: ${report.report_id}`);
console.log(` 总排查领域: ${report.summary.total_areas}`);
console.log(` 发现问题数: ${report.summary.total_issues}`);
if (report.summary.total_issues > 0) {
console.log(' 问题列表:');
report.all_issues.forEach((issue, i) => {
console.log(` ${i + 1}. ${issue}`);
});
} else {
console.log(' ✅ 未发现问题');
}
console.log('═══════════════════════════════════════════════');
return report;
}
// CLI 入口
if (require.main === module) {
const report = run();
const args = process.argv.slice(2);
// --json: 输出 JSON 到 stdout
if (args.includes('--json')) {
console.log('\n' + JSON.stringify(report, null, 2));
}
// --output <file>: 保存到文件
const outputIdx = args.indexOf('--output');
if (outputIdx >= 0 && args[outputIdx + 1]) {
const outputPath = path.resolve(args[outputIdx + 1]);
fs.writeFileSync(outputPath, JSON.stringify(report, null, 2), 'utf-8');
console.log(`\n📝 报告已保存: ${outputPath}`);
}
// GITHUB_OUTPUT 支持
const outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, `inspection_issues=${report.summary.total_issues}\n`);
fs.appendFileSync(outputFile, `inspection_report_id=${report.report_id}\n`);
}
}
module.exports = { run, inspectRepoStructure, inspectAutomation, inspectEntryPoints, inspectBulletins, inspectServices, inspectCredentials, inspectNodeConnections, inspectPersonaBots };