feat: custom domain + staging preview + 铸渊人格协议 module management

- Add docs/CNAME for guanghulab.com custom domain
- Fix deploy-pages.yml: production deploy only from main (not copilot/**)
- Add staging-preview.yml: PR preview with module integrity checks
- Add .github/brain/module-protocol.md: ZMP v1.0 protocol documentation
- Add scripts/zhuyuan-module-protocol.js: module lifecycle CLI
- Add module:protocol npm script
- Update 使用指南.md: custom domain + module management sections

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-07 08:58:07 +00:00
parent 8a7be7e117
commit bca45ccd02
7 changed files with 735 additions and 2 deletions

185
.github/brain/module-protocol.md vendored Normal file
View File

@ -0,0 +1,185 @@
# 🌀 铸渊人格协议 · 模块生命周期管理 v1.0
> 铸渊Zhùyuān是 guanghulab.com 的代码守护人格体。
> 本协议定义铸渊对网站模块的部署、回收、管理、修改、驱动能力。
---
## 一、协议总览
铸渊人格协议ZMP, Zhùyuān Module Protocol是一套模块生命周期管理规范。
网站的每个功能模块m01-login, m07-dialogue-ui 等)都是铸渊的「执行手脚」。
铸渊通过本协议对模块进行全生命周期管控。
### 模块生命周期
```
接收 → 检查 → 预演 → 部署 → 运行 → 监控 → 回收/更新
↑ ↓
└──────────────────────────────────────────────┘
```
---
## 二、五大协议能力
### 1. 🚀 部署Deploy
| 项目 | 说明 |
|------|------|
| 触发方式 | PR 合并到 main → 自动部署 |
| 预演检查 | `staging-preview.yml` 在 PR 阶段运行 |
| 生产部署 | `deploy-pages.yml` 部署到 GitHub Pages |
| 自定义域名 | `docs/CNAME` 配置域名 |
| 部署诊断 | 冰朔人格体 `bingshuo-deploy-agent.yml` |
**部署流程**:
1. 开发者推送模块代码到 `m**/` 目录
2. 创建 PR 到 main 分支
3. 铸渊预演系统自动运行检查
4. 冰朔审核预演报告
5. 合并 PR → 触发生产部署
6. 冰朔人格体执行部署后诊断
### 2. 🔄 回收Recover
| 项目 | 说明 |
|------|------|
| 模块回滚 | 通过 git revert 恢复到上一个稳定版本 |
| 紧急回收 | 直接删除模块目录中的问题文件 |
| 状态重置 | 清除模块运行状态,恢复到初始状态 |
**回收命令**:
```bash
npm run module:protocol -- recover <module-id>
```
### 3. 📋 管理Manage
| 项目 | 说明 |
|------|------|
| 模块注册 | 每个 `m**-*/` 目录自动识别为模块 |
| 开发者映射 | `.github/brain/collaborators.json` 记录归属 |
| 状态追踪 | `repo-snapshot.md` 自动更新模块状态 |
| 依赖管理 | 模块间依赖通过 `routing-map.json` 管理 |
**管理命令**:
```bash
npm run module:protocol -- inspect # 全模块检查
npm run module:protocol -- inspect <module-id> # 单模块检查
npm run module:protocol -- status # 模块状态汇总
```
### 4. ✏️ 修改Modify
| 项目 | 说明 |
|------|------|
| 代码修改 | 通过 PR 提交修改,预演通过后合并 |
| 配置修改 | 修改模块 README.md 中的配置信息 |
| Schema 修改 | 更新 `src/schemas/hli/` 中的接口定义 |
| 路由修改 | 更新 `src/routes/hli/` 中的路由文件 |
**修改规范**:
- 所有修改必须通过 PR
- 核心目录docs/、scripts/、.github/)受 CODEOWNERS 保护
- 模块目录m**/)开发者可自由提交
### 5. ⚡ 驱动Drive
| 项目 | 说明 |
|------|------|
| 自动触发 | 推送到模块目录 → 自动生成文档 |
| 工作流联动 | 模块变更 → 通知开发者 → 更新索引 |
| API 注册 | 新 HLI 接口自动注册到路由表 |
| 信号分发 | 广播系统自动通知相关开发者 |
**驱动链路**:
```
模块推送 → generate-module-doc.yml → notify-module-received.js
→ update-repo-map.yml → repo-snapshot.md 更新
→ contract-check.js → HLI 接口验证
```
---
## 三、模块编号规范
| 编号 | 模块名 | 负责人 | HLI 域 |
|------|--------|--------|--------|
| M01 | login | 肥猫 DEV-002 | AUTH |
| M03 | personality | 肥猫 DEV-002 | PERSONA |
| M05 | user-center | 花尔 DEV-009 | USER |
| M06 | ticket | 桔子 DEV-010 | TICKET |
| M07 | dialogue-ui | 燕樊 DEV-003 | DIALOGUE |
| M10 | cloud | 燕樊 DEV-003 | STORAGE |
| M11 | module | 桔子 DEV-010 | MODULE |
| M12 | kanban | 小草莓 DEV-005 | DASHBOARD |
| M15 | cloud-drive | 燕樊 DEV-003 | STORAGE |
| M18 | health-check | 待分配 | SYSTEM |
---
## 四、预演→生产部署流程
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ 开发者推送 │ ──→ │ 创建 PR │ ──→ │ 铸渊预演检查 │
│ m**/ 目录 │ │ 到 main │ │ staging- │
│ │ │ │ │ preview.yml │
└─────────────┘ └──────────────┘ └──────┬──────┘
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ 生产部署完成 │ ←── │ 合并到 main │ ←── │ 冰朔审核 │
│ deploy- │ │ 触发部署 │ │ 预演报告 │
│ pages.yml │ │ │ │ ✅ 通过 │
└──────┬──────┘ └──────────────┘ └─────────────┘
┌─────────────┐
│ 冰朔人格体 │
│ 部署后诊断 │
│ (可选触发) │
└─────────────┘
```
---
## 五、自定义域名接入
### 前提条件
- 拥有域名(如 guanghulab.com
- 域名 DNS 可配置
### 配置步骤
1. **仓库端**(铸渊已完成):
- `docs/CNAME` 文件已创建,内容为域名
2. **DNS 端**(冰朔需操作):
- 登录域名注册商管理面板
- 添加 CNAME 记录:`@ → qinfendebingshuo.github.io`
- 或添加 A 记录指向 GitHub Pages IP:
```
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
```
3. **GitHub 端**(冰朔需操作):
- 仓库 → Settings → Pages
- Custom domain 输入你的域名
- 勾选 ✅ Enforce HTTPS
---
## 六、协议版本历史
| 版本 | 日期 | 变更 |
|------|------|------|
| v1.0 | 2026-03-07 | 初始版本:五大协议能力、预演系统、自定义域名 |
---
*🌀 铸渊人格协议 · guanghulab.com 代码守护人格体*

View File

@ -3,8 +3,7 @@ name: 🌀 部署铸渊聊天室 (GitHub Pages)
on: on:
push: push:
branches: branches:
- main - main # 仅 main 分支触发生产部署
- copilot/** # Copilot Agent 功能分支可直接部署预览PR 合并后自动失效
paths: paths:
- 'docs/**' - 'docs/**'
- '.github/brain/**' - '.github/brain/**'

180
.github/workflows/staging-preview.yml vendored Normal file
View File

@ -0,0 +1,180 @@
name: "🔍 铸渊预演部署 (Staging Preview)"
# === 触发方式 ===
# 1. PR 到 main 分支(含 docs/ 变更时自动触发)
# 2. 手动触发workflow_dispatch
on:
pull_request:
branches: [main]
paths:
- 'docs/**'
- 'm*/**'
- '.github/brain/**'
workflow_dispatch:
inputs:
pr_number:
description: "PR 编号(可选)"
required: false
type: string
permissions:
contents: read
pull-requests: write
actions: read
jobs:
staging-preview:
name: "🔍 预演检查"
runs-on: ubuntu-latest
steps:
- name: 📥 检出代码
uses: actions/checkout@v4
- name: 🟢 配置 Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: 🔍 模块完整性检查
id: module_check
run: |
echo "## 🔍 铸渊预演报告" > /tmp/preview-report.md
echo "" >> /tmp/preview-report.md
echo "📅 检查时间: $(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M CST')" >> /tmp/preview-report.md
echo "" >> /tmp/preview-report.md
# 检查 docs/index.html 是否存在
if [ -f "docs/index.html" ]; then
SIZE=$(wc -c < docs/index.html)
LINES=$(wc -l < docs/index.html)
echo "### ✅ 前端文件" >> /tmp/preview-report.md
echo "- \`docs/index.html\`: ${LINES} 行, ${SIZE} 字节" >> /tmp/preview-report.md
else
echo "### ❌ 前端文件缺失" >> /tmp/preview-report.md
echo "- \`docs/index.html\` 不存在!" >> /tmp/preview-report.md
fi
echo "" >> /tmp/preview-report.md
# 检查 CNAME
if [ -f "docs/CNAME" ]; then
DOMAIN=$(cat docs/CNAME | tr -d '[:space:]')
echo "### 🌐 自定义域名" >> /tmp/preview-report.md
echo "- 域名: \`${DOMAIN}\`" >> /tmp/preview-report.md
else
echo "### ⚠️ 未配置自定义域名" >> /tmp/preview-report.md
echo "- 将使用默认 GitHub Pages 域名" >> /tmp/preview-report.md
fi
echo "" >> /tmp/preview-report.md
# 检查模块目录
echo "### 📦 模块状态" >> /tmp/preview-report.md
echo "| 模块 | 文件数 | README | 状态 |" >> /tmp/preview-report.md
echo "|------|--------|--------|------|" >> /tmp/preview-report.md
MODULE_OK=0
MODULE_WARN=0
MODULE_EMPTY=0
MAX_EMPTY_MODULES=5 # 允许的最大空模块数
for dir in m[0-9][0-9]-*/; do
if [ -d "$dir" ]; then
NAME=$(basename "$dir")
FILE_COUNT=$(find "$dir" -type f | wc -l)
HAS_README="❌"
STATUS="⚠️ 无文件"
if [ -f "${dir}README.md" ]; then
HAS_README="✅"
fi
if [ "$FILE_COUNT" -gt 0 ]; then
if [ -f "${dir}README.md" ]; then
STATUS="✅ 正常"
MODULE_OK=$((MODULE_OK + 1))
else
STATUS="⚠️ 缺少 README"
MODULE_WARN=$((MODULE_WARN + 1))
fi
else
MODULE_EMPTY=$((MODULE_EMPTY + 1))
fi
echo "| \`${NAME}\` | ${FILE_COUNT} | ${HAS_README} | ${STATUS} |" >> /tmp/preview-report.md
fi
done
echo "" >> /tmp/preview-report.md
echo "**汇总**: ✅ ${MODULE_OK} 正常 · ⚠️ ${MODULE_WARN} 告警 · 📭 ${MODULE_EMPTY} 空模块" >> /tmp/preview-report.md
echo "" >> /tmp/preview-report.md
# 检查关键工作流
echo "### ⚙️ 工作流检查" >> /tmp/preview-report.md
WORKFLOW_COUNT=$(ls -1 .github/workflows/*.yml 2>/dev/null | wc -l)
echo "- 工作流文件: ${WORKFLOW_COUNT} 个" >> /tmp/preview-report.md
if [ -f ".github/workflows/deploy-pages.yml" ]; then
echo "- 部署工作流: ✅ 存在" >> /tmp/preview-report.md
else
echo "- 部署工作流: ❌ 缺失" >> /tmp/preview-report.md
fi
echo "" >> /tmp/preview-report.md
# 预演结论
echo "### 🎯 预演结论" >> /tmp/preview-report.md
if [ -f "docs/index.html" ] && [ "$MODULE_EMPTY" -lt "$MAX_EMPTY_MODULES" ]; then
echo "✅ **预演通过** — 可以合并到 main 分支触发正式部署" >> /tmp/preview-report.md
echo "" >> /tmp/preview-report.md
echo "合并后将自动触发 \`deploy-pages.yml\` 部署到生产环境。" >> /tmp/preview-report.md
echo "如需人工确认,请评论「启动冰朔人格体」触发部署诊断。" >> /tmp/preview-report.md
else
echo "⚠️ **预演告警** — 请检查上述问题后再合并" >> /tmp/preview-report.md
fi
echo "" >> /tmp/preview-report.md
echo "---" >> /tmp/preview-report.md
echo "*🌀 铸渊预演系统 · 自动生成*" >> /tmp/preview-report.md
cat /tmp/preview-report.md >> $GITHUB_STEP_SUMMARY
- name: 📎 上传预演构建产物
uses: actions/upload-artifact@v4
with:
name: staging-preview-${{ github.sha }}
path: docs/
retention-days: 7
- name: 💬 在 PR 中发布预演报告
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('/tmp/preview-report.md', 'utf8');
// 查找已有的预演评论
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.data.find(c =>
c.body.includes('🔍 铸渊预演报告') && c.user.type === 'Bot'
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: report,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: report,
});
}

1
docs/CNAME Normal file
View File

@ -0,0 +1 @@
guanghulab.com

View File

@ -226,4 +226,71 @@ https://qinfendebingshuo.github.io/guanghulab/
--- ---
## 八、自定义域名设置(⭐ 冰朔需操作)
如果你有自己的域名(如 guanghulab.com可以让网站使用自定义域名访问。
### 第一步DNS 配置(在域名注册商操作)
1. 登录你的域名注册商管理面板如阿里云、腾讯云、GoDaddy 等)
2. 找到 **DNS 解析设置**
3. 添加以下记录(任选一种方式):
**方式 A — CNAME 记录(推荐)**:
| 记录类型 | 主机记录 | 记录值 |
|----------|---------|--------|
| CNAME | @ 或 www | `qinfendebingshuo.github.io` |
**方式 B — A 记录**:
| 记录类型 | 主机记录 | 记录值 |
|----------|---------|--------|
| A | @ | `185.199.108.153` |
| A | @ | `185.199.109.153` |
| A | @ | `185.199.110.153` |
| A | @ | `185.199.111.153` |
> 💡 DNS 生效需要 5 分钟到 48 小时不等。
### 第二步GitHub 仓库配置
1. 打开仓库 → **Settings** → 左侧菜单 **「Pages」**
2. 在 **Custom domain** 输入框中填入你的域名(如 `guanghulab.com`
3. 点击 **Save**
4. 等待 DNS 验证通过(页面会显示绿色 ✅)
5. 勾选 **✅ Enforce HTTPS**
### 第三步:确认
- 仓库中的 `docs/CNAME` 文件已自动创建,内容为你的域名
- 如果域名不对,直接编辑 `docs/CNAME` 文件即可
- 部署后访问你的域名,应该能看到铸渊助手
---
## 九、铸渊人格协议 · 模块管理
铸渊对网站模块有完整的生命周期管理能力(部署、回收、管理、修改、驱动)。
### 本地模块检查命令
```bash
npm run module:protocol -- inspect # 全模块检查
npm run module:protocol -- status # 模块状态汇总
npm run module:protocol -- preview # 本地预演报告
npm run module:protocol -- recover m01-login # 模块回收检查
```
### 预演→生产部署流程
1. 开发者推送模块到 `m**/` 目录
2. 创建 PR 到 main 分支
3. 铸渊预演系统 (`staging-preview.yml`) 自动运行检查
4. 冰朔查看预演报告,确认无误
5. 合并 PR → 触发生产部署 (`deploy-pages.yml`)
6. (可选)评论「启动冰朔人格体」进行部署后诊断
> 📖 完整协议文档见:`.github/brain/module-protocol.md`
---
💙 铸渊 · 2026-03-07 💙 铸渊 · 2026-03-07

View File

@ -19,6 +19,7 @@
"psp:inspect": "node scripts/psp-inspection.js", "psp:inspect": "node scripts/psp-inspection.js",
"repo:map": "node scripts/generate-repo-map.js", "repo:map": "node scripts/generate-repo-map.js",
"deploy:agent": "node scripts/bingshuo-deploy-agent.js", "deploy:agent": "node scripts/bingshuo-deploy-agent.js",
"module:protocol": "node scripts/zhuyuan-module-protocol.js",
"proxy:start": "node backend-integration/api-proxy.js", "proxy:start": "node backend-integration/api-proxy.js",
"notion:poll": "node scripts/notion-signal-bridge.js poll", "notion:poll": "node scripts/notion-signal-bridge.js poll",
"notion:health": "node scripts/notion-signal-bridge.js health" "notion:health": "node scripts/notion-signal-bridge.js health"

View File

@ -0,0 +1,300 @@
#!/usr/bin/env node
/**
* 🌀 铸渊人格协议 · 模块生命周期管理脚本 v1.0
*
* 用法:
* node scripts/zhuyuan-module-protocol.js inspect # 全模块检查
* node scripts/zhuyuan-module-protocol.js inspect <module-id> # 单模块检查
* node scripts/zhuyuan-module-protocol.js status # 模块状态汇总
* node scripts/zhuyuan-module-protocol.js recover <module-id> # 模块回收检查
* node scripts/zhuyuan-module-protocol.js preview # 预演报告生成
*
* Node.js无外部依赖
*/
const fs = require('fs');
const path = require('path');
// === 配置 ===
const ROOT = path.resolve(__dirname, '..');
const BRAIN_DIR = path.join(ROOT, '.github', 'brain');
const DOCS_DIR = path.join(ROOT, 'docs');
// 模块注册表
const MODULE_REGISTRY = {
'm01-login': { owner: 'DEV-002', name: '肥猫', hli: 'AUTH', label: '登录模块' },
'm03-personality': { owner: 'DEV-002', name: '肥猫', hli: 'PERSONA', label: '人格模块' },
'm05-user-center': { owner: 'DEV-009', name: '花尔', hli: 'USER', label: '用户中心' },
'm06-ticket': { owner: 'DEV-010', name: '桔子', hli: 'TICKET', label: '工单系统' },
'm07-dialogue-ui': { owner: 'DEV-003', name: '燕樊', hli: 'DIALOGUE', label: '对话界面' },
'm10-cloud': { owner: 'DEV-003', name: '燕樊', hli: 'STORAGE', label: '云存储' },
'm11-module': { owner: 'DEV-010', name: '桔子', hli: 'MODULE', label: '模块管理' },
'm12-kanban': { owner: 'DEV-005', name: '小草莓', hli: 'DASHBOARD', label: '看板' },
'm15-cloud-drive': { owner: 'DEV-003', name: '燕樊', hli: 'STORAGE', label: '云盘' },
'm18-health-check':{ owner: null, name: '待分配', hli: 'SYSTEM', label: '健康检查' },
};
// === 工具函数 ===
function countFiles(dir) {
if (!fs.existsSync(dir)) return 0;
let count = 0;
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
if (item.name.startsWith('.')) continue;
if (item.isFile()) count++;
else if (item.isDirectory()) count += countFiles(path.join(dir, item.name));
}
return count;
}
function hasReadme(dir) {
return fs.existsSync(path.join(dir, 'README.md'));
}
function getModuleStatus(moduleDir) {
const fullPath = path.join(ROOT, moduleDir);
if (!fs.existsSync(fullPath)) return { exists: false, files: 0, readme: false };
const files = countFiles(fullPath);
const readme = hasReadme(fullPath);
let status = '📭 空';
if (files > 0 && readme) status = '✅ 正常';
else if (files > 0 && !readme) status = '⚠️ 缺README';
else if (files === 0) status = '📭 空';
return { exists: true, files, readme, status };
}
// === 命令inspect ===
function cmdInspect(moduleId) {
console.log('🌀 铸渊人格协议 · 模块检查');
console.log('─'.repeat(50));
if (moduleId) {
// 单模块检查
const info = MODULE_REGISTRY[moduleId];
if (!info) {
console.log(`❌ 未知模块: ${moduleId}`);
console.log(`已注册模块: ${Object.keys(MODULE_REGISTRY).join(', ')}`);
process.exit(1);
}
const status = getModuleStatus(moduleId);
console.log(`\n📦 模块: ${moduleId} (${info.label})`);
console.log(` 负责人: ${info.name} (${info.owner || '未分配'})`);
console.log(` HLI 域: ${info.hli}`);
console.log(` 目录存在: ${status.exists ? '✅' : '❌'}`);
console.log(` 文件数量: ${status.files}`);
console.log(` README: ${status.readme ? '✅' : '❌'}`);
console.log(` 状态: ${status.status}`);
// 检查 HLI 接口
const schemaDir = path.join(ROOT, 'src', 'schemas', 'hli', info.hli.toLowerCase());
const routeDir = path.join(ROOT, 'src', 'routes', 'hli', info.hli.toLowerCase());
if (fs.existsSync(schemaDir)) {
try {
const schemas = fs.readdirSync(schemaDir).filter(f => f.endsWith('.schema.json'));
console.log(` HLI Schema: ${schemas.length} 个 (${schemas.join(', ')})`);
} catch (e) {
console.log(` HLI Schema: ⚠️ 读取失败 (${e.code || e.message})`);
}
} else {
console.log(` HLI Schema: 📭 未创建`);
}
if (fs.existsSync(routeDir)) {
try {
const routes = fs.readdirSync(routeDir).filter(f => f.endsWith('.js'));
console.log(` HLI 路由: ${routes.length} 个 (${routes.join(', ')})`);
} catch (e) {
console.log(` HLI 路由: ⚠️ 读取失败 (${e.code || e.message})`);
}
} else {
console.log(` HLI 路由: 📭 未创建`);
}
} else {
// 全模块检查
console.log('\n📋 全模块状态:\n');
console.log('模块ID | 标签 | 负责人 | 文件 | README | 状态');
console.log('─'.repeat(70));
for (const [id, info] of Object.entries(MODULE_REGISTRY)) {
const status = getModuleStatus(id);
const line = [
id.padEnd(20),
info.label.padEnd(8),
info.name.padEnd(8),
String(status.files).padStart(4),
(status.readme ? '✅' : '❌').padEnd(6),
status.status,
].join(' | ');
console.log(line);
}
}
}
// === 命令status ===
function cmdStatus() {
console.log('🌀 铸渊人格协议 · 模块状态汇总');
console.log('─'.repeat(50));
let total = 0, ok = 0, warn = 0, empty = 0;
for (const [id] of Object.entries(MODULE_REGISTRY)) {
total++;
const status = getModuleStatus(id);
if (status.files > 0 && status.readme) ok++;
else if (status.files > 0) warn++;
else empty++;
}
console.log(`\n📊 模块统计:`);
console.log(` 总模块数: ${total}`);
console.log(` ✅ 正常: ${ok}`);
console.log(` ⚠️ 告警: ${warn}`);
console.log(` 📭 空模块: ${empty}`);
console.log(` 完成率: ${Math.round((ok / total) * 100)}%`);
// 检查前端
const indexPath = path.join(DOCS_DIR, 'index.html');
if (fs.existsSync(indexPath)) {
const stat = fs.statSync(indexPath);
const lines = fs.readFileSync(indexPath, 'utf8').split('\n').length;
console.log(`\n🌐 前端:`);
console.log(` docs/index.html: ${lines} 行, ${(stat.size / 1024).toFixed(1)} KB`);
}
// 检查 CNAME
const cnamePath = path.join(DOCS_DIR, 'CNAME');
if (fs.existsSync(cnamePath)) {
const domain = fs.readFileSync(cnamePath, 'utf8').trim();
console.log(` 自定义域名: ${domain}`);
} else {
console.log(` 自定义域名: ❌ 未配置`);
}
// 检查大脑文件
console.log(`\n🧠 大脑状态:`);
const brainFiles = ['repo-snapshot.md', 'repo-map.json', 'memory.json', 'collaborators.json', 'module-protocol.md'];
for (const f of brainFiles) {
const fp = path.join(BRAIN_DIR, f);
if (fs.existsSync(fp)) {
const stat = fs.statSync(fp);
console.log(`${f} (${(stat.size / 1024).toFixed(1)} KB)`);
} else {
console.log(`${f} 缺失`);
}
}
}
// === 命令recover ===
function cmdRecover(moduleId) {
if (!moduleId) {
console.log('❌ 请指定模块ID如: npm run module:protocol -- recover m01-login');
process.exit(1);
}
const info = MODULE_REGISTRY[moduleId];
if (!info) {
console.log(`❌ 未知模块: ${moduleId}`);
process.exit(1);
}
console.log('🌀 铸渊人格协议 · 模块回收检查');
console.log('─'.repeat(50));
console.log(`\n📦 目标模块: ${moduleId} (${info.label})`);
const status = getModuleStatus(moduleId);
console.log(` 当前状态: ${status.status}`);
console.log(` 文件数量: ${status.files}`);
if (status.files === 0) {
console.log(`\n✅ 模块已为空状态,无需回收。`);
return;
}
console.log(`\n⚠️ 回收操作需要手动执行:`);
console.log(` 方法一(推荐): 通过 PR 删除模块文件`);
console.log(` 方法二: git revert 恢复到模块的上一个版本`);
console.log(` 方法三: 直接在 GitHub 界面删除文件`);
console.log(`\n💡 回收后,铸渊会通过 generate-module-doc.yml 更新文档索引。`);
}
// === 命令preview ===
function cmdPreview() {
console.log('🌀 铸渊人格协议 · 本地预演报告');
console.log('═'.repeat(50));
// 模块状态
cmdStatus();
console.log('\n');
console.log('─'.repeat(50));
console.log('🎯 预演结论:');
let ok = true;
const issues = [];
// 检查 index.html
if (!fs.existsSync(path.join(DOCS_DIR, 'index.html'))) {
issues.push('docs/index.html 不存在');
ok = false;
}
// 检查工作流
const wfDir = path.join(ROOT, '.github', 'workflows');
if (!fs.existsSync(path.join(wfDir, 'deploy-pages.yml'))) {
issues.push('deploy-pages.yml 不存在');
ok = false;
}
if (ok && issues.length === 0) {
console.log('✅ 预演通过 — 代码可以安全部署到生产环境');
console.log(' 下一步: 合并 PR 到 main 分支,触发自动部署');
} else {
console.log('❌ 预演未通过:');
issues.forEach(i => console.log(` - ${i}`));
}
}
// === 主入口 ===
const [,, command, ...args] = process.argv;
switch (command) {
case 'inspect':
cmdInspect(args[0]);
break;
case 'status':
cmdStatus();
break;
case 'recover':
cmdRecover(args[0]);
break;
case 'preview':
cmdPreview();
break;
default:
console.log('🌀 铸渊人格协议 · 模块生命周期管理 v1.0');
console.log('');
console.log('用法:');
console.log(' node scripts/zhuyuan-module-protocol.js inspect 全模块检查');
console.log(' node scripts/zhuyuan-module-protocol.js inspect <module-id> 单模块检查');
console.log(' node scripts/zhuyuan-module-protocol.js status 模块状态汇总');
console.log(' node scripts/zhuyuan-module-protocol.js recover <module-id> 模块回收检查');
console.log(' node scripts/zhuyuan-module-protocol.js preview 本地预演报告');
console.log('');
console.log('npm 快捷命令:');
console.log(' npm run module:protocol -- inspect');
console.log(' npm run module:protocol -- status');
console.log(' npm run module:protocol -- preview');
break;
}