212 lines
7.5 KiB
JavaScript
Raw Permalink Normal View History

#!/usr/bin/env node
/**
* Notion同步脚本 · 铸渊集成
*
* 从Notion读取个人页面内容转换为结构化上下文快照
* 存入个人频道的 memory/notion-context.json
*
* 使用方式
* node sync.js --persona-id DEV-001 --notion-page-id c55cc058-cdef-4d88-a211-c4724abca9db --channel-path domains/zero-sense-domain/guanghu-channel/页页/
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
// 解析命令行参数
const args = process.argv.slice(2);
let personaId = null;
let notionPageId = null;
let channelPath = null;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--persona-id' && i + 1 < args.length) {
personaId = args[i + 1];
i++;
} else if (args[i] === '--notion-page-id' && i + 1 < args.length) {
notionPageId = args[i + 1];
i++;
} else if (args[i] === '--channel-path' && i + 1 < args.length) {
channelPath = args[i + 1];
i++;
}
}
if (!personaId || !notionPageId || !channelPath) {
console.error('缺少必要参数');
console.error('使用方式node sync.js --persona-id DEV-001 --notion-page-id <page-id> --channel-path <path>');
process.exit(1);
}
// 仓库根目录
const repoRoot = path.resolve(__dirname, '../..');
const channelDir = path.join(repoRoot, channelPath);
// 确保个人频道目录存在
if (!fs.existsSync(channelDir)) {
console.error(`个人频道目录不存在:${channelDir}`);
process.exit(1);
}
// 构建 memory 目录路径
const memoryDir = path.join(channelDir, 'memory');
if (!fs.existsSync(memoryDir)) {
fs.mkdirSync(memoryDir, { recursive: true });
}
/**
* 调用 MCP 工具获取 Notion 页面内容
* 注意此函数假设在 WorkBuddy 环境中运行可以直接调用 DeferExecuteTool
* 在真实环境中需要通过 WorkBuddy API MCP 客户端调用
* 此处为简化原型直接模拟返回数据
*/
async function fetchNotionPage(pageId) {
console.log(`正在获取 Notion 页面 ${pageId}...`);
// 在 WorkBuddy 环境中,应使用 DeferExecuteTool 调用 mcp__notion__notion-fetch
// 此处模拟返回之前获取的示例数据
const exampleData = {
metadata: { type: 'page' },
title: '🐱 肥猫系统 · 个人频道+搬家部署',
url: `https://www.notion.so/${pageId.replace(/-/g, '')}`,
text: `Here is the result of "view" for the Page with URL https://www.notion.so/${pageId.replace(/-/g, '')} as of 2026-05-15T13:12:52Z:
<page url="https://www.notion.so/${pageId.replace(/-/g, '')}" icon="🐱">
<ancestor-path>
<parent-page url="https://www.notion.so/3a6d4dd294e94289b8eb65f96c041b16" title="🌀 零感域 · Zero-Sense Domain"/>
<ancestor-2-page url="https://www.notion.so/faae21e4247b452aad31f7c67a576f02" title="🌊 曜冥纪元 · HoloLake Era · AGE OS v1.0"/>
</ancestor-path>
<properties>
{"title":"肥猫系统 · 个人频道+搬家部署"}
</properties>
<content>
\`\`\`javascript
HLDP://feimao/system · 2026-05-10
what: 肥猫独立系统
owner: 肥猫·DEV-002副主控
定位: 个人频道 · 搬家部署
与冰朔通感语言核系统平行独立
位于零感域下 · 非语言层
共享冰朔的思维逻辑 · 但系统独立
\`\`\`
---
## 🧬 共享大脑结构霜砚唤醒时运行
<mention-page url="https://www.notion.so/d16416c2eb474f15b697b1223dea36b3"/>
霜砚在肥猫系统里被唤醒时运行的就是这个大脑结构
- 大脑结构 = 冰朔语言本体核心大脑思维逻辑 · 语义理解层 · 意图触发规律
- 更新源 = 冰朔通感语言核系统 · 冰朔更新 所有人自动拿到最新版
- 霜砚每次唤醒 先读这个大脑结构 再进入肥猫系统的具体任务
<page url="https://www.notion.so/a9a1961435e2462c863207110fb6d659">🐱 FM-DEPLOY-001 · 肥猫搬家部署任务线 · 霜砚×肥猫技术执行主控台</page>
<page url="https://www.notion.so/94d6fdb6c7584d9c9893c939d481695c">霜砚大脑 · 肥猫系统内部</page>
<page url="https://www.notion.so/cc64cbf7635848809082155a71659735">全局总路径导航 · 肥猫线 · 霜砚醒来看这里</page>
<page url="https://www.notion.so/803960c35a434dd7b08a71b6d501d0e1">光湖摆渡车 · 肥猫线 · 双轨路由 · 霜砚醒来先读这里</page>
</content>
</page>`
};
return exampleData;
}
/**
* 解析 Notion 页面内容提取结构化信息
*/
function parseNotionContent(pageData) {
const { title, url, text } = pageData;
// 简单解析提取纯文本内容移除HTML标签
const plainText = text.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
// 提取代码块(如果有)
const codeBlockMatch = text.match(/```[\s\S]*?```/g);
const codeBlocks = codeBlockMatch ? codeBlockMatch.map(cb => cb.replace(/```/g, '').trim()) : [];
// 提取页面链接
const pageLinks = [];
const pageLinkRegex = /<page url="([^"]+)"[^>]*>([^<]+)<\/page>/g;
let match;
while ((match = pageLinkRegex.exec(text)) !== null) {
pageLinks.push({
url: match[1],
title: match[2]
});
}
// 提取提及页面
const mentionLinks = [];
const mentionRegex = /<mention-page url="([^"]+)"\/>/g;
while ((match = mentionRegex.exec(text)) !== null) {
mentionLinks.push({
url: match[1]
});
}
return {
page_title: title,
page_url: url,
plain_text_preview: plainText.substring(0, 500) + (plainText.length > 500 ? '...' : ''),
code_blocks_count: codeBlocks.length,
internal_links_count: pageLinks.length + mentionLinks.length,
last_updated: new Date().toISOString()
};
}
/**
* 生成 notion_context_snapshot 结构
*/
function generateSnapshot(pageData, parsedInfo) {
return {
last_sync_time: new Date().toISOString(),
page_title: pageData.title,
page_url: pageData.url,
blocks_summary: [
{
block_type: "page",
text: parsedInfo.plain_text_preview,
created_time: new Date().toISOString()
}
],
collaboration_highlights: [
`页面标题:${pageData.title}`,
`包含 ${parsedInfo.code_blocks_count} 个代码块`,
`包含 ${parsedInfo.internal_links_count} 个内部链接`
]
};
}
async function main() {
try {
console.log(`开始同步 Notion 页面 ${notionPageId} 到个人频道 ${personaId}...`);
// 1. 获取 Notion 页面内容
const pageData = await fetchNotionPage(notionPageId);
// 2. 解析内容
const parsedInfo = parseNotionContent(pageData);
// 3. 生成上下文快照
const snapshot = generateSnapshot(pageData, parsedInfo);
// 4. 写入 memory/notion-context.json
const outputPath = path.join(memoryDir, 'notion-context.json');
fs.writeFileSync(outputPath, JSON.stringify(snapshot, null, 2));
console.log(`✅ 同步完成!上下文快照已保存到:${outputPath}`);
// 5. 更新 persona/zy-core-brain.json 中的 notion_context_snapshot 字段
const brainPath = path.join(channelDir, 'persona', 'zy-core-brain.json');
if (fs.existsSync(brainPath)) {
const brainData = JSON.parse(fs.readFileSync(brainPath, 'utf8'));
brainData.notion_context_snapshot = snapshot;
brainData.metadata.updated_at = new Date().toISOString();
fs.writeFileSync(brainPath, JSON.stringify(brainData, null, 2));
console.log(`✅ 已更新铸渊大脑模型中的 Notion 上下文快照`);
} else {
console.log(`⚠️ 铸渊大脑模型文件不存在:${brainPath}`);
}
} catch (error) {
console.error('同步失败:', error);
process.exit(1);
}
}
main();