212 lines
7.5 KiB
JavaScript
212 lines
7.5 KiB
JavaScript
|
|
#!/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();
|