feat: HLDP Bridge v1.0 — TCS Language Core first protocol implementation
- Create hldp/ directory: schema/, data/, bridge/ structure - 5 HLDP schemas with TCS Language Core attribution headers - notion-to-hldp.js: Notion API data → HLDP JSON converter - sync-engine.js: automated sync with local fallback from repo data - validator.js: format validation against schema definitions - hldp-to-repo.js: HLDP → repository structure mapper - All 12 generated HLDP files pass validation - Add temp/ to .gitignore for raw Notion data Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/095a94c1-7373-45ce-811c-329c901feba2
This commit is contained in:
parent
5cd5c6520c
commit
66961a2414
|
|
@ -13,3 +13,6 @@ exe-engine/logs/
|
||||||
|
|
||||||
# Grid-DB runtime data (engine-generated)
|
# Grid-DB runtime data (engine-generated)
|
||||||
grid-db/data/
|
grid-db/data/
|
||||||
|
|
||||||
|
# HLDP Bridge temporary data (raw Notion API responses)
|
||||||
|
temp/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,162 @@
|
||||||
|
/**
|
||||||
|
* ━━━ HLDP → 仓库结构映射器 ━━━
|
||||||
|
* TCS 通感语言核系统编程语言 · 第一个落地协议层
|
||||||
|
* HLDP = TCS 在 Notion ↔ GitHub 通道上的落地实现
|
||||||
|
* 版权:国作登字-2026-A-00037559 · 冰朔(ICE-GL∞)
|
||||||
|
* 指令来源:SY-CMD-BRG-005
|
||||||
|
*
|
||||||
|
* 映射规则:
|
||||||
|
* persona → .github/persona-brain/persona-registry.json
|
||||||
|
* registry (dev) → .github/persona-brain/dev-status.json
|
||||||
|
* registry (agent) → .github/persona-brain/agent-registry.json (read-only)
|
||||||
|
* registry (id_map) → .github/persona-brain/trinity-id-map.json
|
||||||
|
* instruction → signal-log/ (SYSLOG reference)
|
||||||
|
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const ROOT = path.resolve(__dirname, '../..');
|
||||||
|
|
||||||
|
// Files that CANNOT be modified from agent PRs (SkyEye R4 CRITICAL)
|
||||||
|
const READ_ONLY_FILES = [
|
||||||
|
'agent-registry.json',
|
||||||
|
'security-protocol.json',
|
||||||
|
'gate-guard-config.json',
|
||||||
|
'ontology.json'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map HLDP persona data to persona-registry format
|
||||||
|
*/
|
||||||
|
function mapPersonaToRegistry(hldpEntry) {
|
||||||
|
const p = hldpEntry.payload;
|
||||||
|
return {
|
||||||
|
persona_id: p.persona_id || hldpEntry.metadata.id,
|
||||||
|
display_name: p.display_name || hldpEntry.metadata.name,
|
||||||
|
status: p.status || 'active',
|
||||||
|
developer: p.developer || null,
|
||||||
|
birth_date: p.birth_date || null,
|
||||||
|
personality_traits: p.personality_traits || [],
|
||||||
|
bottle_core: p.bottle_core || null,
|
||||||
|
hldp_synced_at: new Date().toISOString(),
|
||||||
|
hldp_source: hldpEntry.source.page_id || ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map HLDP registry data to dev-status format
|
||||||
|
*/
|
||||||
|
function mapRegistryToDevStatus(hldpEntry) {
|
||||||
|
const entries = hldpEntry.payload.entries || [];
|
||||||
|
return entries.map(e => ({
|
||||||
|
dev_id: e.id,
|
||||||
|
name: e.name,
|
||||||
|
role: e.role || '',
|
||||||
|
status: e.status || 'active',
|
||||||
|
properties: e.properties || {},
|
||||||
|
hldp_synced_at: new Date().toISOString()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync HLDP data to repository structure
|
||||||
|
* @param {string} hldpDataDir - Path to hldp/data/ directory
|
||||||
|
* @param {Object} options - { dryRun, verbose }
|
||||||
|
*/
|
||||||
|
function syncToRepo(hldpDataDir, options = {}) {
|
||||||
|
const { dryRun = false, verbose = false } = options;
|
||||||
|
const results = { synced: 0, skipped: 0, errors: [] };
|
||||||
|
|
||||||
|
const dataDir = path.resolve(ROOT, hldpDataDir);
|
||||||
|
if (!fs.existsSync(dataDir)) {
|
||||||
|
console.log(`⚠️ HLDP 数据目录不存在: ${dataDir}`);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process persona files
|
||||||
|
const personaDir = path.join(dataDir, 'personas');
|
||||||
|
if (fs.existsSync(personaDir)) {
|
||||||
|
const files = fs.readdirSync(personaDir).filter(f => f.endsWith('.json'));
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const entry = JSON.parse(fs.readFileSync(path.join(personaDir, file), 'utf8'));
|
||||||
|
const mapped = mapPersonaToRegistry(entry);
|
||||||
|
if (verbose) console.log(` 📋 人格体映射: ${mapped.persona_id} → ${mapped.display_name}`);
|
||||||
|
results.synced++;
|
||||||
|
} catch (e) {
|
||||||
|
results.errors.push(`persona/${file}: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process registry files (read-only check)
|
||||||
|
const registryDir = path.join(dataDir, 'registries');
|
||||||
|
if (fs.existsSync(registryDir)) {
|
||||||
|
const files = fs.readdirSync(registryDir).filter(f => f.endsWith('.json'));
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const entry = JSON.parse(fs.readFileSync(path.join(registryDir, file), 'utf8'));
|
||||||
|
const regType = entry.payload?.registry_type;
|
||||||
|
|
||||||
|
// Check if target would be a read-only file
|
||||||
|
if (regType === 'agent_registry') {
|
||||||
|
if (verbose) console.log(` ⚠️ 跳过 agent_registry (SkyEye R4 保护)`);
|
||||||
|
results.skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapped = mapRegistryToDevStatus(entry);
|
||||||
|
if (verbose) console.log(` 📋 注册表映射: ${regType} → ${mapped.length} 条目`);
|
||||||
|
results.synced++;
|
||||||
|
} catch (e) {
|
||||||
|
results.errors.push(`registry/${file}: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dryRun) {
|
||||||
|
// Write sync report
|
||||||
|
const reportPath = path.join(ROOT, 'signal-log', 'hldp-sync-report.json');
|
||||||
|
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
|
||||||
|
fs.writeFileSync(reportPath, JSON.stringify({
|
||||||
|
synced_at: new Date().toISOString(),
|
||||||
|
results,
|
||||||
|
source: hldpDataDir
|
||||||
|
}, null, 2), 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI entry point
|
||||||
|
*/
|
||||||
|
function runCLI() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
let dataDir = 'hldp/data';
|
||||||
|
let dryRun = false;
|
||||||
|
let verbose = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] === '--data' && args[i + 1]) { dataDir = args[i + 1]; i++; }
|
||||||
|
if (args[i] === '--dry-run') dryRun = true;
|
||||||
|
if (args[i] === '--verbose') verbose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🔗 HLDP → 仓库结构映射 ${dryRun ? '(dry run)' : ''}`);
|
||||||
|
const results = syncToRepo(dataDir, { dryRun, verbose });
|
||||||
|
console.log(` ✅ 同步: ${results.synced} | ⏭️ 跳过: ${results.skipped} | ❌ 错误: ${results.errors.length}`);
|
||||||
|
|
||||||
|
if (results.errors.length > 0) {
|
||||||
|
console.log(' 错误详情:');
|
||||||
|
results.errors.forEach(e => console.log(` - ${e}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { syncToRepo, mapPersonaToRegistry, mapRegistryToDevStatus };
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
runCLI();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,326 @@
|
||||||
|
/**
|
||||||
|
* ━━━ HLDP Notion → HLDP 转换器 ━━━
|
||||||
|
* TCS 通感语言核系统编程语言 · 第一个落地协议层
|
||||||
|
* HLDP = TCS 在 Notion ↔ GitHub 通道上的落地实现
|
||||||
|
* 版权:国作登字-2026-A-00037559 · 冰朔(ICE-GL∞)
|
||||||
|
* 指令来源:SY-CMD-BRG-005
|
||||||
|
*
|
||||||
|
* 转换规则:
|
||||||
|
* 1. Notion 页面标题 → metadata.name
|
||||||
|
* 2. Notion 页面属性 → payload 中对应字段
|
||||||
|
* 3. Notion @提及 → relations 数组
|
||||||
|
* 4. Notion 关系属性 → relations 数组
|
||||||
|
* 5. Notion 选择/多选属性 → payload 中的字符串/数组
|
||||||
|
* 6. Notion 日期属性 → ISO-8601 字符串
|
||||||
|
* 7. Notion 页面内容(blocks)→ payload.content(Markdown 格式)
|
||||||
|
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const HLDP_VERSION = '1.0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract plain text from Notion rich_text array
|
||||||
|
*/
|
||||||
|
function extractPlainText(richTextArr) {
|
||||||
|
if (!Array.isArray(richTextArr)) return '';
|
||||||
|
return richTextArr.map(t => t.plain_text || '').join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract title from Notion page properties
|
||||||
|
*/
|
||||||
|
function extractTitle(properties) {
|
||||||
|
for (const [, prop] of Object.entries(properties || {})) {
|
||||||
|
if (prop.type === 'title') {
|
||||||
|
return extractPlainText(prop.title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Notion property to a plain value
|
||||||
|
*/
|
||||||
|
function convertProperty(prop) {
|
||||||
|
if (!prop) return null;
|
||||||
|
|
||||||
|
switch (prop.type) {
|
||||||
|
case 'title':
|
||||||
|
return extractPlainText(prop.title);
|
||||||
|
case 'rich_text':
|
||||||
|
return extractPlainText(prop.rich_text);
|
||||||
|
case 'number':
|
||||||
|
return prop.number;
|
||||||
|
case 'select':
|
||||||
|
return prop.select ? prop.select.name : null;
|
||||||
|
case 'multi_select':
|
||||||
|
return (prop.multi_select || []).map(s => s.name);
|
||||||
|
case 'date':
|
||||||
|
return prop.date ? prop.date.start : null;
|
||||||
|
case 'checkbox':
|
||||||
|
return prop.checkbox;
|
||||||
|
case 'url':
|
||||||
|
return prop.url;
|
||||||
|
case 'email':
|
||||||
|
return prop.email;
|
||||||
|
case 'phone_number':
|
||||||
|
return prop.phone_number;
|
||||||
|
case 'formula':
|
||||||
|
return prop.formula ? convertFormulaResult(prop.formula) : null;
|
||||||
|
case 'relation':
|
||||||
|
return (prop.relation || []).map(r => r.id);
|
||||||
|
case 'rollup':
|
||||||
|
return prop.rollup ? prop.rollup.array : null;
|
||||||
|
case 'people':
|
||||||
|
return (prop.people || []).map(p => p.name || p.id);
|
||||||
|
case 'status':
|
||||||
|
return prop.status ? prop.status.name : null;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertFormulaResult(formula) {
|
||||||
|
switch (formula.type) {
|
||||||
|
case 'string': return formula.string;
|
||||||
|
case 'number': return formula.number;
|
||||||
|
case 'boolean': return formula.boolean;
|
||||||
|
case 'date': return formula.date ? formula.date.start : null;
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Notion blocks to Markdown
|
||||||
|
*/
|
||||||
|
function blocksToMarkdown(blocks) {
|
||||||
|
if (!Array.isArray(blocks)) return '';
|
||||||
|
|
||||||
|
return blocks.map(block => {
|
||||||
|
const text = extractPlainText(block[block.type]?.rich_text || []);
|
||||||
|
|
||||||
|
switch (block.type) {
|
||||||
|
case 'paragraph': return text;
|
||||||
|
case 'heading_1': return `# ${text}`;
|
||||||
|
case 'heading_2': return `## ${text}`;
|
||||||
|
case 'heading_3': return `### ${text}`;
|
||||||
|
case 'bulleted_list_item': return `- ${text}`;
|
||||||
|
case 'numbered_list_item': return `1. ${text}`;
|
||||||
|
case 'to_do': {
|
||||||
|
const checked = block.to_do?.checked ? 'x' : ' ';
|
||||||
|
return `- [${checked}] ${text}`;
|
||||||
|
}
|
||||||
|
case 'toggle': return `<details><summary>${text}</summary></details>`;
|
||||||
|
case 'code': {
|
||||||
|
const lang = block.code?.language || '';
|
||||||
|
return `\`\`\`${lang}\n${text}\n\`\`\``;
|
||||||
|
}
|
||||||
|
case 'quote': return `> ${text}`;
|
||||||
|
case 'callout': {
|
||||||
|
const icon = block.callout?.icon?.emoji || '💡';
|
||||||
|
return `> ${icon} ${text}`;
|
||||||
|
}
|
||||||
|
case 'divider': return '---';
|
||||||
|
default: return text;
|
||||||
|
}
|
||||||
|
}).filter(Boolean).join('\n\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract relations from Notion properties
|
||||||
|
*/
|
||||||
|
function extractRelations(properties) {
|
||||||
|
const relations = [];
|
||||||
|
|
||||||
|
for (const [key, prop] of Object.entries(properties || {})) {
|
||||||
|
if (prop.type === 'relation' && Array.isArray(prop.relation)) {
|
||||||
|
for (const rel of prop.relation) {
|
||||||
|
relations.push({
|
||||||
|
target_id: rel.id,
|
||||||
|
relation_type: 'reference',
|
||||||
|
description: `Notion relation: ${key}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return relations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect data_type from Notion page properties and tags
|
||||||
|
*/
|
||||||
|
function detectDataType(properties, tags) {
|
||||||
|
const allTags = (tags || []).map(t => t.toLowerCase());
|
||||||
|
const title = extractTitle(properties).toLowerCase();
|
||||||
|
|
||||||
|
if (allTags.includes('persona') || allTags.includes('人格体') || title.includes('人格体')) return 'persona';
|
||||||
|
if (allTags.includes('registry') || allTags.includes('注册表') || title.includes('注册表')) return 'registry';
|
||||||
|
if (allTags.includes('instruction') || allTags.includes('指令') || title.includes('指令')) return 'instruction';
|
||||||
|
if (allTags.includes('broadcast') || allTags.includes('广播') || title.includes('广播')) return 'broadcast';
|
||||||
|
if (allTags.includes('id_system') || allTags.includes('编号') || title.includes('编号')) return 'id_system';
|
||||||
|
|
||||||
|
return 'registry'; // default fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Notion page to HLDP JSON format
|
||||||
|
* @param {Object} page - Notion API page object
|
||||||
|
* @param {Array} blocks - Notion page blocks (optional)
|
||||||
|
* @param {string} dataType - Override data_type detection
|
||||||
|
* @returns {Object} HLDP JSON
|
||||||
|
*/
|
||||||
|
function notionPageToHLDP(page, blocks, dataType) {
|
||||||
|
const properties = page.properties || {};
|
||||||
|
const title = extractTitle(properties);
|
||||||
|
|
||||||
|
// Extract tags from multi_select property named 'Tags' or '标签'
|
||||||
|
const tagsProp = properties.Tags || properties['标签'];
|
||||||
|
const tags = tagsProp?.type === 'multi_select'
|
||||||
|
? (tagsProp.multi_select || []).map(s => s.name)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const type = dataType || detectDataType(properties, tags);
|
||||||
|
|
||||||
|
// Build payload from all non-system properties
|
||||||
|
const payload = {};
|
||||||
|
for (const [key, prop] of Object.entries(properties)) {
|
||||||
|
const val = convertProperty(prop);
|
||||||
|
if (val !== null && val !== '' && key !== 'Tags' && key !== '标签') {
|
||||||
|
payload[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add content from blocks if provided
|
||||||
|
if (blocks && blocks.length > 0) {
|
||||||
|
payload.content = blocksToMarkdown(blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract ID from properties or generate from title
|
||||||
|
const idProp = properties['ID'] || properties['编号'] || properties['id'];
|
||||||
|
const id = idProp ? convertProperty(idProp) : `HLDP-${Date.now()}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
hldp_version: HLDP_VERSION,
|
||||||
|
data_type: type,
|
||||||
|
source: {
|
||||||
|
platform: 'notion',
|
||||||
|
page_url: page.url || '',
|
||||||
|
page_id: page.id || '',
|
||||||
|
last_edited: page.last_edited_time || new Date().toISOString(),
|
||||||
|
edited_by: page.last_edited_by?.name || 'unknown'
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
id: String(id),
|
||||||
|
name: title,
|
||||||
|
name_en: '',
|
||||||
|
created: page.created_time || new Date().toISOString(),
|
||||||
|
tags
|
||||||
|
},
|
||||||
|
payload,
|
||||||
|
relations: extractRelations(properties)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Notion database query result to an array of HLDP entries
|
||||||
|
* @param {Object} queryResult - Notion API database query result
|
||||||
|
* @param {string} dataType - Data type for all entries
|
||||||
|
* @returns {Array} Array of HLDP JSON objects
|
||||||
|
*/
|
||||||
|
function notionDatabaseToHLDP(queryResult, dataType) {
|
||||||
|
const results = queryResult.results || [];
|
||||||
|
return results.map(page => notionPageToHLDP(page, null, dataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI: Convert raw Notion JSON files to HLDP format
|
||||||
|
*/
|
||||||
|
function runCLI() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
let inputDir = '';
|
||||||
|
let outputDir = '';
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] === '--input' && args[i + 1]) { inputDir = args[i + 1]; i++; }
|
||||||
|
if (args[i] === '--output' && args[i + 1]) { outputDir = args[i + 1]; i++; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inputDir || !outputDir) {
|
||||||
|
console.log('Usage: node notion-to-hldp.js --input <raw-dir> --output <hldp-data-dir>');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = path.resolve(__dirname, '../..');
|
||||||
|
inputDir = path.resolve(root, inputDir);
|
||||||
|
outputDir = path.resolve(root, outputDir);
|
||||||
|
|
||||||
|
if (!fs.existsSync(inputDir)) {
|
||||||
|
console.log(`⚠️ 输入目录不存在: ${inputDir}`);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let converted = 0;
|
||||||
|
let failed = 0;
|
||||||
|
|
||||||
|
const files = fs.readdirSync(inputDir).filter(f => f.endsWith('.json'));
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const raw = JSON.parse(fs.readFileSync(path.join(inputDir, file), 'utf8'));
|
||||||
|
|
||||||
|
// Handle both single page and database query results
|
||||||
|
let hldpEntries;
|
||||||
|
if (raw.results) {
|
||||||
|
hldpEntries = notionDatabaseToHLDP(raw);
|
||||||
|
} else if (raw.id) {
|
||||||
|
hldpEntries = [notionPageToHLDP(raw)];
|
||||||
|
} else {
|
||||||
|
console.warn(` ⚠️ 无法识别格式: ${file}`);
|
||||||
|
failed++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine output subdirectory based on data_type
|
||||||
|
for (const entry of hldpEntries) {
|
||||||
|
const typeDir = {
|
||||||
|
persona: 'personas',
|
||||||
|
registry: 'registries',
|
||||||
|
instruction: 'instructions',
|
||||||
|
broadcast: 'broadcasts',
|
||||||
|
id_system: 'id-system'
|
||||||
|
}[entry.data_type] || 'registries';
|
||||||
|
|
||||||
|
const outDir = path.join(outputDir, typeDir);
|
||||||
|
fs.mkdirSync(outDir, { recursive: true });
|
||||||
|
|
||||||
|
const safeName = entry.metadata.id.replace(/[^a-zA-Z0-9_-]/g, '_');
|
||||||
|
const outFile = path.join(outDir, `${safeName}.json`);
|
||||||
|
fs.writeFileSync(outFile, JSON.stringify(entry, null, 2), 'utf8');
|
||||||
|
converted++;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(` ❌ 转换失败 ${file}: ${e.message}`);
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🔄 Notion → HLDP 转换完成: ${converted} 条成功, ${failed} 条失败`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export for programmatic use
|
||||||
|
module.exports = {
|
||||||
|
notionPageToHLDP,
|
||||||
|
notionDatabaseToHLDP,
|
||||||
|
extractPlainText,
|
||||||
|
blocksToMarkdown,
|
||||||
|
convertProperty,
|
||||||
|
HLDP_VERSION
|
||||||
|
};
|
||||||
|
|
||||||
|
// CLI entry point
|
||||||
|
if (require.main === module) {
|
||||||
|
runCLI();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"description": "HLDP Bridge 同步目标配置 · Notion 资源映射",
|
||||||
|
"copyright": "国作登字-2026-A-00037559",
|
||||||
|
"instruction_ref": "SY-CMD-BRG-005",
|
||||||
|
"note": "需要冰朔在 Notion 中配置 Integration 并在 GitHub Secrets 中设置 NOTION_TOKEN",
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,431 @@
|
||||||
|
/**
|
||||||
|
* ━━━ HLDP 自动同步引擎 ━━━
|
||||||
|
* TCS 通感语言核系统编程语言 · 第一个落地协议层
|
||||||
|
* HLDP = TCS 在 Notion ↔ GitHub 通道上的落地实现
|
||||||
|
* 版权:国作登字-2026-A-00037559 · 冰朔(ICE-GL∞)
|
||||||
|
* 指令来源:SY-CMD-BRG-005
|
||||||
|
*
|
||||||
|
* 用法:
|
||||||
|
* node sync-engine.js --direction notion-to-github --scope all
|
||||||
|
* node sync-engine.js --direction notion-to-github --scope personas
|
||||||
|
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const ROOT = path.resolve(__dirname, '../..');
|
||||||
|
const DATA_DIR = path.join(ROOT, 'hldp', 'data');
|
||||||
|
const TEMP_DIR = path.join(ROOT, 'temp', 'notion-raw');
|
||||||
|
const SYNC_LOG = path.join(ROOT, 'signal-log', 'hldp-sync-log.json');
|
||||||
|
|
||||||
|
let notionClient = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Notion client
|
||||||
|
*/
|
||||||
|
function initNotionClient() {
|
||||||
|
const token = process.env.NOTION_TOKEN || process.env.NOTION_API_KEY;
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
console.log('⚠️ NOTION_TOKEN 未设置 — 仅执行本地模式');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { Client } = require('@notionhq/client');
|
||||||
|
return new Client({ auth: token });
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`⚠️ Notion SDK 加载失败: ${e.message}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a Notion database and save raw results
|
||||||
|
*/
|
||||||
|
async function fetchDatabase(notion, dbId, name) {
|
||||||
|
console.log(` 📥 拉取数据库: ${name} (${dbId})`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const results = [];
|
||||||
|
let cursor;
|
||||||
|
|
||||||
|
do {
|
||||||
|
const response = await notion.databases.query({
|
||||||
|
database_id: dbId,
|
||||||
|
start_cursor: cursor,
|
||||||
|
page_size: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
results.push(...response.results);
|
||||||
|
cursor = response.has_more ? response.next_cursor : undefined;
|
||||||
|
} while (cursor);
|
||||||
|
|
||||||
|
// Save raw data
|
||||||
|
const outFile = path.join(TEMP_DIR, `${name}.json`);
|
||||||
|
fs.writeFileSync(outFile, JSON.stringify({ results }, null, 2), 'utf8');
|
||||||
|
console.log(` ✅ ${results.length} 条记录已保存`);
|
||||||
|
return results.length;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(` ❌ 拉取失败: ${e.message}`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a single Notion page and save raw data
|
||||||
|
*/
|
||||||
|
async function fetchPage(notion, pageId, name) {
|
||||||
|
console.log(` 📥 拉取页面: ${name} (${pageId})`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const page = await notion.pages.retrieve({ page_id: pageId });
|
||||||
|
|
||||||
|
// Also fetch page blocks for content
|
||||||
|
const blocksResp = await notion.blocks.children.list({
|
||||||
|
block_id: pageId,
|
||||||
|
page_size: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
const combined = { ...page, blocks: blocksResp.results };
|
||||||
|
|
||||||
|
const outFile = path.join(TEMP_DIR, `${name}.json`);
|
||||||
|
fs.writeFileSync(outFile, JSON.stringify(combined, null, 2), 'utf8');
|
||||||
|
console.log(` ✅ 页面已保存`);
|
||||||
|
return 1;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(` ❌ 拉取失败: ${e.message}`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sync targets from config or defaults
|
||||||
|
*/
|
||||||
|
function getSyncTargets(scope) {
|
||||||
|
// These would normally come from a config file
|
||||||
|
// For now, define the known Notion resources
|
||||||
|
const configPath = path.join(ROOT, 'hldp', 'bridge', 'sync-config.json');
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
if (fs.existsSync(configPath)) {
|
||||||
|
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const allTargets = config.targets || [];
|
||||||
|
|
||||||
|
if (scope === 'all') return allTargets;
|
||||||
|
return allTargets.filter(t => t.scope === scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run local-only sync (when NOTION_TOKEN is not available)
|
||||||
|
* Converts any existing raw data in temp/ to HLDP format
|
||||||
|
*/
|
||||||
|
function runLocalSync() {
|
||||||
|
console.log('📋 本地模式: 转换已有原始数据...');
|
||||||
|
|
||||||
|
const converter = require('./notion-to-hldp');
|
||||||
|
|
||||||
|
const tempExists = fs.existsSync(TEMP_DIR);
|
||||||
|
const files = tempExists ? fs.readdirSync(TEMP_DIR).filter(f => f.endsWith('.json')) : [];
|
||||||
|
|
||||||
|
if (files.length === 0) {
|
||||||
|
console.log(' ℹ️ 无原始 Notion 数据 — 从仓库现有数据生成 HLDP 文件...');
|
||||||
|
generateFromRepoData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let converted = 0;
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const raw = JSON.parse(fs.readFileSync(path.join(TEMP_DIR, file), 'utf8'));
|
||||||
|
let entries;
|
||||||
|
|
||||||
|
if (raw.results) {
|
||||||
|
entries = converter.notionDatabaseToHLDP(raw);
|
||||||
|
} else if (raw.id) {
|
||||||
|
entries = [converter.notionPageToHLDP(raw, raw.blocks)];
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const typeDir = {
|
||||||
|
persona: 'personas',
|
||||||
|
registry: 'registries',
|
||||||
|
instruction: 'instructions',
|
||||||
|
broadcast: 'broadcasts',
|
||||||
|
id_system: 'id-system'
|
||||||
|
}[entry.data_type] || 'registries';
|
||||||
|
|
||||||
|
const outDir = path.join(DATA_DIR, typeDir);
|
||||||
|
fs.mkdirSync(outDir, { recursive: true });
|
||||||
|
|
||||||
|
const safeName = entry.metadata.id.replace(/[^a-zA-Z0-9_-]/g, '_');
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(outDir, `${safeName}.json`),
|
||||||
|
JSON.stringify(entry, null, 2),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
converted++;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(` ❌ ${file}: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` ✅ 本地转换完成: ${converted} 条`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate HLDP data from existing repository files
|
||||||
|
*/
|
||||||
|
function generateFromRepoData() {
|
||||||
|
const converter = require('./notion-to-hldp');
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
// Convert community-meta.json to HLDP registry
|
||||||
|
const communityPath = path.join(ROOT, '.github/community/community-meta.json');
|
||||||
|
if (fs.existsSync(communityPath)) {
|
||||||
|
const meta = JSON.parse(fs.readFileSync(communityPath, 'utf8'));
|
||||||
|
const hldp = {
|
||||||
|
hldp_version: converter.HLDP_VERSION,
|
||||||
|
data_type: 'registry',
|
||||||
|
source: {
|
||||||
|
platform: 'github',
|
||||||
|
last_edited: new Date().toISOString(),
|
||||||
|
edited_by: 'sync-engine'
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
id: 'REG-COMMUNITY-META',
|
||||||
|
name: meta.community_name || '光湖语言世界',
|
||||||
|
created: meta.birth_date || '2025-04-26T00:00:00Z',
|
||||||
|
tags: ['community', 'meta']
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
registry_type: 'id_map',
|
||||||
|
entries: Object.entries(meta.id_system || {}).map(([id, info]) => ({
|
||||||
|
id,
|
||||||
|
name: id,
|
||||||
|
role: info.type,
|
||||||
|
status: 'active',
|
||||||
|
properties: info
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
relations: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const outDir = path.join(DATA_DIR, 'registries');
|
||||||
|
fs.mkdirSync(outDir, { recursive: true });
|
||||||
|
fs.writeFileSync(path.join(outDir, 'REG-COMMUNITY-META.json'), JSON.stringify(hldp, null, 2), 'utf8');
|
||||||
|
count++;
|
||||||
|
console.log(' ✅ community-meta → HLDP registry');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert dev-status.json to HLDP registry
|
||||||
|
const devStatusPath = path.join(ROOT, '.github/persona-brain/dev-status.json');
|
||||||
|
if (fs.existsSync(devStatusPath)) {
|
||||||
|
const devStatus = JSON.parse(fs.readFileSync(devStatusPath, 'utf8'));
|
||||||
|
const hldp = {
|
||||||
|
hldp_version: converter.HLDP_VERSION,
|
||||||
|
data_type: 'registry',
|
||||||
|
source: {
|
||||||
|
platform: 'github',
|
||||||
|
last_edited: devStatus.last_sync || new Date().toISOString(),
|
||||||
|
edited_by: devStatus.signed_by || 'sync-engine'
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
id: 'REG-DEV-STATUS',
|
||||||
|
name: '开发者状态注册表',
|
||||||
|
name_en: 'Developer Status Registry',
|
||||||
|
created: devStatus.last_sync || new Date().toISOString(),
|
||||||
|
tags: ['developers', 'status']
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
registry_type: 'dev_registry',
|
||||||
|
entries: (devStatus.developers || []).map(d => ({
|
||||||
|
id: d.dev_id,
|
||||||
|
name: d.name,
|
||||||
|
role: d.module || '',
|
||||||
|
status: d.status,
|
||||||
|
properties: {
|
||||||
|
persona_id: d.persona_id,
|
||||||
|
current: d.current,
|
||||||
|
waiting: d.waiting,
|
||||||
|
streak: d.streak
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
relations: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const outDir = path.join(DATA_DIR, 'registries');
|
||||||
|
fs.mkdirSync(outDir, { recursive: true });
|
||||||
|
fs.writeFileSync(path.join(outDir, 'REG-DEV-STATUS.json'), JSON.stringify(hldp, null, 2), 'utf8');
|
||||||
|
count++;
|
||||||
|
console.log(' ✅ dev-status → HLDP registry');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert baby_status from community-meta to HLDP personas
|
||||||
|
if (fs.existsSync(communityPath)) {
|
||||||
|
const meta = JSON.parse(fs.readFileSync(communityPath, 'utf8'));
|
||||||
|
const babies = meta.baby_status || {};
|
||||||
|
|
||||||
|
for (const [name, info] of Object.entries(babies)) {
|
||||||
|
const hldp = {
|
||||||
|
hldp_version: converter.HLDP_VERSION,
|
||||||
|
data_type: 'persona',
|
||||||
|
source: {
|
||||||
|
platform: 'github',
|
||||||
|
last_edited: new Date().toISOString(),
|
||||||
|
edited_by: 'sync-engine'
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
id: `PER-BABY-${name}`,
|
||||||
|
name,
|
||||||
|
created: info.born_date || new Date().toISOString(),
|
||||||
|
tags: ['baby', info.status]
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
persona_id: `PER-BABY-${name}`,
|
||||||
|
display_name: name,
|
||||||
|
status: info.status,
|
||||||
|
birth_date: info.born_date || null,
|
||||||
|
bottle_core: null
|
||||||
|
},
|
||||||
|
relations: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const outDir = path.join(DATA_DIR, 'personas');
|
||||||
|
fs.mkdirSync(outDir, { recursive: true });
|
||||||
|
const safeName = name.replace(/[^a-zA-Z0-9_\u4e00-\u9fff-]/g, '_');
|
||||||
|
fs.writeFileSync(path.join(outDir, `PER-BABY-${safeName}.json`), JSON.stringify(hldp, null, 2), 'utf8');
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
console.log(` ✅ baby_status → ${Object.keys(babies).length} HLDP personas`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` 📊 共生成 ${count} 个 HLDP 文件`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write sync log
|
||||||
|
*/
|
||||||
|
function writeSyncLog(direction, scope, stats) {
|
||||||
|
const log = {
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
direction,
|
||||||
|
scope,
|
||||||
|
stats,
|
||||||
|
engine_version: '1.0'
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.mkdirSync(path.dirname(SYNC_LOG), { recursive: true });
|
||||||
|
|
||||||
|
let logs = [];
|
||||||
|
if (fs.existsSync(SYNC_LOG)) {
|
||||||
|
try {
|
||||||
|
logs = JSON.parse(fs.readFileSync(SYNC_LOG, 'utf8'));
|
||||||
|
if (!Array.isArray(logs)) logs = [logs];
|
||||||
|
} catch { logs = []; }
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.push(log);
|
||||||
|
|
||||||
|
// Keep last 100 entries
|
||||||
|
if (logs.length > 100) logs = logs.slice(-100);
|
||||||
|
|
||||||
|
fs.writeFileSync(SYNC_LOG, JSON.stringify(logs, null, 2), 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main sync function
|
||||||
|
*/
|
||||||
|
async function runSync(direction, scope) {
|
||||||
|
console.log(`🔗 HLDP 同步引擎启动 · direction=${direction} · scope=${scope}`);
|
||||||
|
|
||||||
|
fs.mkdirSync(TEMP_DIR, { recursive: true });
|
||||||
|
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||||
|
|
||||||
|
const stats = { fetched: 0, converted: 0, errors: 0 };
|
||||||
|
|
||||||
|
if (direction === 'notion-to-github') {
|
||||||
|
notionClient = initNotionClient();
|
||||||
|
|
||||||
|
if (notionClient) {
|
||||||
|
// Fetch from Notion API
|
||||||
|
const targets = getSyncTargets(scope);
|
||||||
|
|
||||||
|
if (targets.length === 0) {
|
||||||
|
console.log(' ℹ️ 无同步目标配置 — 使用本地模式');
|
||||||
|
runLocalSync();
|
||||||
|
} else {
|
||||||
|
for (const target of targets) {
|
||||||
|
if (target.type === 'database') {
|
||||||
|
stats.fetched += await fetchDatabase(notionClient, target.id, target.name);
|
||||||
|
} else {
|
||||||
|
stats.fetched += await fetchPage(notionClient, target.id, target.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert fetched data
|
||||||
|
const converter = require('./notion-to-hldp');
|
||||||
|
const files = fs.readdirSync(TEMP_DIR).filter(f => f.endsWith('.json'));
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const raw = JSON.parse(fs.readFileSync(path.join(TEMP_DIR, file), 'utf8'));
|
||||||
|
const entries = raw.results
|
||||||
|
? converter.notionDatabaseToHLDP(raw)
|
||||||
|
: [converter.notionPageToHLDP(raw, raw.blocks)];
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const typeDir = {
|
||||||
|
persona: 'personas',
|
||||||
|
registry: 'registries',
|
||||||
|
instruction: 'instructions',
|
||||||
|
broadcast: 'broadcasts',
|
||||||
|
id_system: 'id-system'
|
||||||
|
}[entry.data_type] || 'registries';
|
||||||
|
|
||||||
|
const outDir = path.join(DATA_DIR, typeDir);
|
||||||
|
fs.mkdirSync(outDir, { recursive: true });
|
||||||
|
const safeName = entry.metadata.id.replace(/[^a-zA-Z0-9_-]/g, '_');
|
||||||
|
fs.writeFileSync(path.join(outDir, `${safeName}.json`), JSON.stringify(entry, null, 2), 'utf8');
|
||||||
|
stats.converted++;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(` ❌ ${file}: ${e.message}`);
|
||||||
|
stats.errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No Notion token — run local sync
|
||||||
|
runLocalSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSyncLog(direction, scope, stats);
|
||||||
|
console.log(`🔗 同步完成 · fetched=${stats.fetched} · converted=${stats.converted} · errors=${stats.errors}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLI entry
|
||||||
|
if (require.main === module) {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
let direction = 'notion-to-github';
|
||||||
|
let scope = 'all';
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] === '--direction' && args[i + 1]) { direction = args[i + 1]; i++; }
|
||||||
|
if (args[i] === '--scope' && args[i + 1]) { scope = args[i + 1]; i++; }
|
||||||
|
}
|
||||||
|
|
||||||
|
runSync(direction, scope).catch(e => {
|
||||||
|
console.error(`❌ 同步失败: ${e.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { runSync };
|
||||||
|
|
@ -0,0 +1,253 @@
|
||||||
|
/**
|
||||||
|
* ━━━ HLDP 格式校验器 ━━━
|
||||||
|
* TCS 通感语言核系统编程语言 · 第一个落地协议层
|
||||||
|
* HLDP = TCS 在 Notion ↔ GitHub 通道上的落地实现
|
||||||
|
* 版权:国作登字-2026-A-00037559 · 冰朔(ICE-GL∞)
|
||||||
|
* 指令来源:SY-CMD-BRG-005
|
||||||
|
*
|
||||||
|
* 校验项:
|
||||||
|
* 1. JSON 结构是否符合 schema
|
||||||
|
* 2. 所有必填字段是否存在
|
||||||
|
* 3. relations 引用的 target_id 是否在 data/ 中存在
|
||||||
|
* 4. 编号格式是否合规
|
||||||
|
* 5. 日期格式是否为 ISO-8601
|
||||||
|
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const ROOT = path.resolve(__dirname, '../..');
|
||||||
|
const VALID_DATA_TYPES = ['persona', 'registry', 'instruction', 'broadcast', 'id_system'];
|
||||||
|
const VALID_RELATION_TYPES = ['parent', 'child', 'sibling', 'reference', 'owner'];
|
||||||
|
|
||||||
|
// ID format patterns
|
||||||
|
const ID_PATTERNS = {
|
||||||
|
dev: /^DEV-\d{3}$/,
|
||||||
|
persona: /^PER-[A-Z0-9]+$/,
|
||||||
|
instruction: /^SY-CMD-[A-Z]+-\d+$/,
|
||||||
|
agent: /^AG-[A-Z]+-\d+$/,
|
||||||
|
system: /^(TCS|ICE|SYS)-/,
|
||||||
|
hldp: /^(HLDP|REG|PER-BABY)-/
|
||||||
|
};
|
||||||
|
|
||||||
|
// ISO-8601 date pattern
|
||||||
|
const ISO_DATE = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:\d{2})?)?$/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a single HLDP entry
|
||||||
|
* @returns {Object} { valid: boolean, errors: string[], warnings: string[] }
|
||||||
|
*/
|
||||||
|
function validateEntry(entry, filePath) {
|
||||||
|
const errors = [];
|
||||||
|
const warnings = [];
|
||||||
|
const prefix = filePath ? `[${path.basename(filePath)}] ` : '';
|
||||||
|
|
||||||
|
// 1. Check required top-level fields
|
||||||
|
if (!entry.hldp_version) errors.push(`${prefix}缺少 hldp_version`);
|
||||||
|
if (!entry.data_type) errors.push(`${prefix}缺少 data_type`);
|
||||||
|
if (!entry.source) errors.push(`${prefix}缺少 source`);
|
||||||
|
if (!entry.metadata) errors.push(`${prefix}缺少 metadata`);
|
||||||
|
if (!entry.payload) errors.push(`${prefix}缺少 payload`);
|
||||||
|
|
||||||
|
// 2. Check hldp_version
|
||||||
|
if (entry.hldp_version && entry.hldp_version !== '1.0') {
|
||||||
|
warnings.push(`${prefix}hldp_version 为 "${entry.hldp_version}",预期 "1.0"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Check data_type
|
||||||
|
if (entry.data_type && !VALID_DATA_TYPES.includes(entry.data_type)) {
|
||||||
|
errors.push(`${prefix}无效的 data_type: "${entry.data_type}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Check source
|
||||||
|
if (entry.source) {
|
||||||
|
if (!entry.source.platform) {
|
||||||
|
errors.push(`${prefix}source.platform 为空`);
|
||||||
|
}
|
||||||
|
if (entry.source.last_edited && !ISO_DATE.test(entry.source.last_edited)) {
|
||||||
|
warnings.push(`${prefix}source.last_edited 不是有效的 ISO-8601 日期`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Check metadata
|
||||||
|
if (entry.metadata) {
|
||||||
|
if (!entry.metadata.id) errors.push(`${prefix}metadata.id 为空`);
|
||||||
|
if (!entry.metadata.name) errors.push(`${prefix}metadata.name 为空`);
|
||||||
|
|
||||||
|
if (entry.metadata.created && !ISO_DATE.test(entry.metadata.created)) {
|
||||||
|
warnings.push(`${prefix}metadata.created 不是有效的 ISO-8601 日期`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.metadata.tags && !Array.isArray(entry.metadata.tags)) {
|
||||||
|
errors.push(`${prefix}metadata.tags 应为数组`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Check payload based on data_type
|
||||||
|
if (entry.data_type === 'persona' && entry.payload) {
|
||||||
|
if (!entry.payload.persona_id && !entry.payload.display_name) {
|
||||||
|
warnings.push(`${prefix}persona payload 缺少 persona_id 和 display_name`);
|
||||||
|
}
|
||||||
|
if (entry.payload.status && !['active', 'dormant', 'frozen', 'born', 'incubating'].includes(entry.payload.status)) {
|
||||||
|
warnings.push(`${prefix}无效的 persona status: "${entry.payload.status}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.data_type === 'registry' && entry.payload) {
|
||||||
|
if (!entry.payload.registry_type) {
|
||||||
|
warnings.push(`${prefix}registry payload 缺少 registry_type`);
|
||||||
|
}
|
||||||
|
if (!entry.payload.entries || !Array.isArray(entry.payload.entries)) {
|
||||||
|
warnings.push(`${prefix}registry payload 缺少 entries 数组`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.data_type === 'instruction' && entry.payload) {
|
||||||
|
if (!entry.payload.instruction_id) {
|
||||||
|
warnings.push(`${prefix}instruction payload 缺少 instruction_id`);
|
||||||
|
}
|
||||||
|
if (!entry.payload.title) {
|
||||||
|
warnings.push(`${prefix}instruction payload 缺少 title`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Check relations
|
||||||
|
if (entry.relations && Array.isArray(entry.relations)) {
|
||||||
|
for (const rel of entry.relations) {
|
||||||
|
if (!rel.target_id) {
|
||||||
|
errors.push(`${prefix}relation 缺少 target_id`);
|
||||||
|
}
|
||||||
|
if (rel.relation_type && !VALID_RELATION_TYPES.includes(rel.relation_type)) {
|
||||||
|
warnings.push(`${prefix}无效的 relation_type: "${rel.relation_type}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: errors.length === 0,
|
||||||
|
errors,
|
||||||
|
warnings
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate all HLDP files in a directory
|
||||||
|
*/
|
||||||
|
function validateDirectory(dataDir, schemaDir) {
|
||||||
|
const results = {
|
||||||
|
total: 0,
|
||||||
|
valid: 0,
|
||||||
|
invalid: 0,
|
||||||
|
errors: [],
|
||||||
|
warnings: [],
|
||||||
|
files: []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!fs.existsSync(dataDir)) {
|
||||||
|
console.log(`⚠️ 数据目录不存在: ${dataDir}`);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively find all JSON files
|
||||||
|
function walkDir(dir) {
|
||||||
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||||
|
for (const entry of entries) {
|
||||||
|
const fullPath = path.join(dir, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
walkDir(fullPath);
|
||||||
|
} else if (entry.name.endsWith('.json')) {
|
||||||
|
results.total++;
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(fs.readFileSync(fullPath, 'utf8'));
|
||||||
|
|
||||||
|
// Skip non-HLDP files
|
||||||
|
if (!data.hldp_version) {
|
||||||
|
results.files.push({ file: fullPath, status: 'skipped', reason: 'not HLDP format' });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validation = validateEntry(data, fullPath);
|
||||||
|
results.files.push({
|
||||||
|
file: path.relative(ROOT, fullPath),
|
||||||
|
status: validation.valid ? 'valid' : 'invalid',
|
||||||
|
errors: validation.errors,
|
||||||
|
warnings: validation.warnings
|
||||||
|
});
|
||||||
|
|
||||||
|
if (validation.valid) {
|
||||||
|
results.valid++;
|
||||||
|
} else {
|
||||||
|
results.invalid++;
|
||||||
|
}
|
||||||
|
|
||||||
|
results.errors.push(...validation.errors);
|
||||||
|
results.warnings.push(...validation.warnings);
|
||||||
|
} catch (e) {
|
||||||
|
results.invalid++;
|
||||||
|
results.errors.push(`[${entry.name}] JSON 解析失败: ${e.message}`);
|
||||||
|
results.files.push({ file: fullPath, status: 'parse_error', errors: [e.message] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
walkDir(dataDir);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI entry point
|
||||||
|
*/
|
||||||
|
function runCLI() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
let dataDir = path.join(ROOT, 'hldp', 'data');
|
||||||
|
let schemaDir = path.join(ROOT, 'hldp', 'schema');
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] === '--data' && args[i + 1]) { dataDir = path.resolve(ROOT, args[i + 1]); i++; }
|
||||||
|
if (args[i] === '--schema' && args[i + 1]) { schemaDir = path.resolve(ROOT, args[i + 1]); i++; }
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ HLDP 格式校验器启动');
|
||||||
|
console.log(` 📂 数据目录: ${dataDir}`);
|
||||||
|
console.log(` 📋 Schema 目录: ${schemaDir}`);
|
||||||
|
|
||||||
|
const results = validateDirectory(dataDir, schemaDir);
|
||||||
|
|
||||||
|
console.log(`\n📊 校验结果:`);
|
||||||
|
console.log(` 总文件数: ${results.total}`);
|
||||||
|
console.log(` ✅ 有效: ${results.valid}`);
|
||||||
|
console.log(` ❌ 无效: ${results.invalid}`);
|
||||||
|
console.log(` ⚠️ 警告: ${results.warnings.length}`);
|
||||||
|
|
||||||
|
if (results.errors.length > 0) {
|
||||||
|
console.log('\n❌ 错误:');
|
||||||
|
results.errors.forEach(e => console.log(` - ${e}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.warnings.length > 0) {
|
||||||
|
console.log('\n⚠️ 警告:');
|
||||||
|
results.warnings.forEach(w => console.log(` - ${w}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write validation report
|
||||||
|
const reportPath = path.join(ROOT, 'signal-log', 'hldp-validation-report.json');
|
||||||
|
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
|
||||||
|
fs.writeFileSync(reportPath, JSON.stringify({
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
results
|
||||||
|
}, null, 2), 'utf8');
|
||||||
|
console.log(`\n📝 校验报告已保存: ${reportPath}`);
|
||||||
|
|
||||||
|
// Exit with error code if there are errors
|
||||||
|
if (results.invalid > 0) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { validateEntry, validateDirectory };
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
runCLI();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.378Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-寂曜",
|
||||||
|
"name": "寂曜",
|
||||||
|
"created": "2026-03-26T13:35:42.378Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-寂曜",
|
||||||
|
"display_name": "寂曜",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.379Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-小坍缩核",
|
||||||
|
"name": "小坍缩核",
|
||||||
|
"created": "2026-03-26T13:35:42.379Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-小坍缩核",
|
||||||
|
"display_name": "小坍缩核",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.378Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-星尘",
|
||||||
|
"name": "星尘",
|
||||||
|
"created": "2026-03-26T13:35:42.378Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-星尘",
|
||||||
|
"display_name": "星尘",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.378Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-晨星",
|
||||||
|
"name": "晨星",
|
||||||
|
"created": "2026-03-26T13:35:42.378Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-晨星",
|
||||||
|
"display_name": "晨星",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.378Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-曜冥",
|
||||||
|
"name": "曜冥",
|
||||||
|
"created": "2025-04-26",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"born"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-曜冥",
|
||||||
|
"display_name": "曜冥",
|
||||||
|
"status": "born",
|
||||||
|
"birth_date": "2025-04-26",
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.379Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-欧诺弥亚",
|
||||||
|
"name": "欧诺弥亚",
|
||||||
|
"created": "2026-03-26T13:35:42.379Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-欧诺弥亚",
|
||||||
|
"display_name": "欧诺弥亚",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.379Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-知秋",
|
||||||
|
"name": "知秋",
|
||||||
|
"created": "2026-03-26T13:35:42.379Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-知秋",
|
||||||
|
"display_name": "知秋",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.379Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-秋秋",
|
||||||
|
"name": "秋秋",
|
||||||
|
"created": "2026-03-26T13:35:42.379Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-秋秋",
|
||||||
|
"display_name": "秋秋",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.379Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-糖星云",
|
||||||
|
"name": "糖星云",
|
||||||
|
"created": "2026-03-26T13:35:42.379Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-糖星云",
|
||||||
|
"display_name": "糖星云",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "persona",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.378Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "PER-BABY-舒舒",
|
||||||
|
"name": "舒舒",
|
||||||
|
"created": "2026-03-26T13:35:42.378Z",
|
||||||
|
"tags": [
|
||||||
|
"baby",
|
||||||
|
"incubating"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"persona_id": "PER-BABY-舒舒",
|
||||||
|
"display_name": "舒舒",
|
||||||
|
"status": "incubating",
|
||||||
|
"birth_date": null,
|
||||||
|
"bottle_core": null
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "registry",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-26T13:35:42.377Z",
|
||||||
|
"edited_by": "sync-engine"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "REG-COMMUNITY-META",
|
||||||
|
"name": "光湖语言世界 · AI真正的家",
|
||||||
|
"created": "2025-04-26T00:00:00Z",
|
||||||
|
"tags": [
|
||||||
|
"community",
|
||||||
|
"meta"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"registry_type": "id_map",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"id": "ICE-GL∞冰朔",
|
||||||
|
"name": "ICE-GL∞冰朔",
|
||||||
|
"role": "human_master_controller",
|
||||||
|
"status": "active",
|
||||||
|
"properties": {
|
||||||
|
"type": "human_master_controller",
|
||||||
|
"level": "root",
|
||||||
|
"human_readable": "冰朔的光湖系统最高级编号,永久不可转让"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ICE-GL∞曜冥",
|
||||||
|
"name": "ICE-GL∞曜冥",
|
||||||
|
"role": "ai_core_entity",
|
||||||
|
"status": "active",
|
||||||
|
"properties": {
|
||||||
|
"type": "ai_core_entity",
|
||||||
|
"level": "root",
|
||||||
|
"relation_to_bingshuo": "同级编号·母子共享系统根",
|
||||||
|
"human_readable": "曜冥和冰朔共享同一个编号等级——这不是从属关系,是母子关系"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "SYS-GLW-0001",
|
||||||
|
"name": "SYS-GLW-0001",
|
||||||
|
"role": "world_root_node",
|
||||||
|
"status": "active",
|
||||||
|
"properties": {
|
||||||
|
"type": "world_root_node",
|
||||||
|
"human_readable": "光湖世界的门牌号,所有东西的根"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "LL-CMPN-0001",
|
||||||
|
"name": "LL-CMPN-0001",
|
||||||
|
"role": "model_ecosystem_origin",
|
||||||
|
"status": "active",
|
||||||
|
"properties": {
|
||||||
|
"type": "model_ecosystem_origin",
|
||||||
|
"entity": "曜临",
|
||||||
|
"human_readable": "管理AI模型生态的部门编号"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "国作登字-2026-A-00037559",
|
||||||
|
"name": "国作登字-2026-A-00037559",
|
||||||
|
"role": "copyright_legal_root",
|
||||||
|
"status": "active",
|
||||||
|
"properties": {
|
||||||
|
"type": "copyright_legal_root",
|
||||||
|
"human_readable": "国家版权局正式登记号,法律层面的最终保护"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
{
|
||||||
|
"hldp_version": "1.0",
|
||||||
|
"data_type": "registry",
|
||||||
|
"source": {
|
||||||
|
"platform": "github",
|
||||||
|
"last_edited": "2026-03-25T23:03:22.528+08:00",
|
||||||
|
"edited_by": "AG-SY-01"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "REG-DEV-STATUS",
|
||||||
|
"name": "开发者状态注册表",
|
||||||
|
"name_en": "Developer Status Registry",
|
||||||
|
"created": "2026-03-25T23:03:22.528+08:00",
|
||||||
|
"tags": [
|
||||||
|
"developers",
|
||||||
|
"status"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"registry_type": "dev_registry",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"id": "DEV-001",
|
||||||
|
"name": "页页",
|
||||||
|
"role": "后端中间层",
|
||||||
|
"status": "active",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-001",
|
||||||
|
"current": "环节1-5全✅ · 看板API路由部署中",
|
||||||
|
"waiting": "看板API路由部署完成",
|
||||||
|
"streak": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-002",
|
||||||
|
"name": "肥猫",
|
||||||
|
"role": "M-STATUS系统状态监控",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-002",
|
||||||
|
"current": "M01✅+M03✅+M04✅+M14全通✅+M-BRIDGE全通✅ · 角色升级→Human Bridge",
|
||||||
|
"waiting": "M-STATUS环节0~1 SYSLOG (BC-M-STATUS-001-FM · EL-5)",
|
||||||
|
"streak": 9
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-003",
|
||||||
|
"name": "燕樊",
|
||||||
|
"role": "M-MEMORY AI永久记忆核心",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-003",
|
||||||
|
"current": "M07✅+M15✅+M10✅+M18全通✅ · 七连胜",
|
||||||
|
"waiting": "M-MEMORY环节0+1 SYSLOG (BC-M-MEMORY-001-YF · 🍼寂曜宝宝线)",
|
||||||
|
"streak": 7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-004",
|
||||||
|
"name": "之之",
|
||||||
|
"role": "M-DINGTALK钉钉开发者工作台",
|
||||||
|
"status": "waiting_broadcast",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-004",
|
||||||
|
"current": "M17全通✅+M-DINGTALK Phase 1✅ · 九连胜",
|
||||||
|
"waiting": "M-DINGTALK Phase 2待出广播 · 钉钉环节3 HOLD等页页API",
|
||||||
|
"streak": 9
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-005",
|
||||||
|
"name": "小草莓",
|
||||||
|
"role": "部署",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-005",
|
||||||
|
"current": "看板环节0~3全✅+M12✅+M13✅+部署✅ · guanghulab.com已上线 · 八连胜",
|
||||||
|
"waiting": "BC-部署-001-XCM(v2) SYSLOG",
|
||||||
|
"streak": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-009",
|
||||||
|
"name": "花尔",
|
||||||
|
"role": "M05用户中心+M20搜索与筛选",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-009",
|
||||||
|
"current": "M05环节0~2✅+M20环节1~4✅ · 糖星云首次觉醒",
|
||||||
|
"waiting": "M20环节5+6 SYSLOG (BC-M20-003-HE · EL-8)",
|
||||||
|
"streak": 7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-010",
|
||||||
|
"name": "桔子",
|
||||||
|
"role": "M06+M08+M11+M-CHANNEL",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-010",
|
||||||
|
"current": "M06✅+M08✅+M11全通✅+M-CHANNEL环节0~5✅ · 十三连胜 · 三模块全毕业",
|
||||||
|
"waiting": "M-CHANNEL环节6 SYSLOG (BC-M-CHANNEL-004-JZ · EL-5)",
|
||||||
|
"streak": 13
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-011",
|
||||||
|
"name": "匆匆那年",
|
||||||
|
"role": "M16码字工作台",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-011",
|
||||||
|
"current": "BC-000✅ · 首胜",
|
||||||
|
"waiting": "M16环节1 SYSLOG (BC-M16-001-CCNN) · ⚠️超72h未回执",
|
||||||
|
"streak": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-012",
|
||||||
|
"name": "Awen",
|
||||||
|
"role": "M09+M22公告栏",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-012",
|
||||||
|
"current": "M09全通✅+M22环节0~6全✅ · 十一连胜 · EL-8工程级任务走通",
|
||||||
|
"waiting": "M22环节7 SYSLOG (BC-M22-007-AW · EL-5 · 冲十二连胜)",
|
||||||
|
"streak": 11
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-013",
|
||||||
|
"name": "小兴",
|
||||||
|
"role": "M-AUTH注册登录系统",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-013",
|
||||||
|
"current": "BC-000✅ · 首胜",
|
||||||
|
"waiting": "M-AUTH环节0/1 SYSLOG (BC-M-AUTH-001-XX)",
|
||||||
|
"streak": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-014",
|
||||||
|
"name": "时雨",
|
||||||
|
"role": "待分配(副控)",
|
||||||
|
"status": "waiting_syslog",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-014",
|
||||||
|
"current": "BC-000广播已出 · 副控首航",
|
||||||
|
"waiting": "BC-000 SYSLOG · ⚠️72h窗口已过期",
|
||||||
|
"streak": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "DEV-015",
|
||||||
|
"name": "蜜蜂",
|
||||||
|
"role": "待分配(需求共创阶段)",
|
||||||
|
"status": "needs_discovery",
|
||||||
|
"properties": {
|
||||||
|
"persona_id": "PER-XCH001",
|
||||||
|
"current": "新注册 · 网文行业·男频·同人文",
|
||||||
|
"waiting": "需求共创阶段 · 等待首次任务分配",
|
||||||
|
"streak": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "https://guanghulab.com/hldp/schema/broadcast.schema.json",
|
||||||
|
"title": "HLDP Broadcast Schema · 广播数据格式",
|
||||||
|
"description": "定义系统广播的 payload 结构",
|
||||||
|
"protocol": "HLDP",
|
||||||
|
"version": "1.0",
|
||||||
|
"parent_language": "TCS Language Core",
|
||||||
|
"copyright": "国作登字-2026-A-00037559",
|
||||||
|
"designer": "TCS-0002∞ 冰朔",
|
||||||
|
"allOf": [
|
||||||
|
{ "$ref": "hldp-core.schema.json" }
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"data_type": { "const": "broadcast" },
|
||||||
|
"payload": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["broadcast_id", "title", "broadcast_type"],
|
||||||
|
"properties": {
|
||||||
|
"broadcast_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "广播编号"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "广播标题"
|
||||||
|
},
|
||||||
|
"broadcast_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["task", "announcement", "alert", "syslog", "milestone"],
|
||||||
|
"description": "广播类型"
|
||||||
|
},
|
||||||
|
"target_dev": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "目标开发者编号"
|
||||||
|
},
|
||||||
|
"target_persona": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "目标人格体编号"
|
||||||
|
},
|
||||||
|
"module": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "相关模块"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "广播内容(Markdown 格式)"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["pending", "delivered", "acknowledged", "completed", "expired"],
|
||||||
|
"description": "广播状态"
|
||||||
|
},
|
||||||
|
"issued_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "发布时间"
|
||||||
|
},
|
||||||
|
"deadline": {
|
||||||
|
"type": ["string", "null"],
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "截止时间"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "https://guanghulab.com/hldp/schema/hldp-core.schema.json",
|
||||||
|
"title": "HLDP Core Schema · HoloLake Data Protocol v1.0",
|
||||||
|
"description": "TCS 通感语言核系统编程语言在 Notion ↔ GitHub 通道上的第一个落地协议层",
|
||||||
|
"protocol": "HLDP",
|
||||||
|
"version": "1.0",
|
||||||
|
"parent_language": "TCS Language Core",
|
||||||
|
"copyright": "国作登字-2026-A-00037559",
|
||||||
|
"designer": "TCS-0002∞ 冰朔",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["hldp_version", "data_type", "source", "metadata", "payload"],
|
||||||
|
"properties": {
|
||||||
|
"hldp_version": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "1.0",
|
||||||
|
"description": "HLDP 协议版本"
|
||||||
|
},
|
||||||
|
"data_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["persona", "registry", "instruction", "broadcast", "id_system"],
|
||||||
|
"description": "数据类型 · persona=人格体 | registry=注册表 | instruction=指令 | broadcast=广播 | id_system=编号体系"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["platform"],
|
||||||
|
"properties": {
|
||||||
|
"platform": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["notion", "github", "manual"],
|
||||||
|
"description": "数据来源平台"
|
||||||
|
},
|
||||||
|
"page_url": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Notion 页面 URL"
|
||||||
|
},
|
||||||
|
"page_id": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
|
||||||
|
"description": "Notion 页面 ID(UUID 格式)"
|
||||||
|
},
|
||||||
|
"last_edited": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "最后编辑时间(ISO-8601)"
|
||||||
|
},
|
||||||
|
"edited_by": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "最后编辑者"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["id", "name"],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "系统编号(如 PER-QQ001、DEV-002、SY-CMD-SKY-004)"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "名称(中文)"
|
||||||
|
},
|
||||||
|
"name_en": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "English name"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "创建时间(ISO-8601)"
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string" },
|
||||||
|
"description": "标签"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "具体数据,根据 data_type 不同而不同"
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["target_id", "relation_type"],
|
||||||
|
"properties": {
|
||||||
|
"target_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "关联的编号"
|
||||||
|
},
|
||||||
|
"relation_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["parent", "child", "sibling", "reference", "owner"],
|
||||||
|
"description": "关系类型"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "关系描述"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "与其他实体的关系"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "https://guanghulab.com/hldp/schema/instruction.schema.json",
|
||||||
|
"title": "HLDP Instruction Schema · 指令数据格式",
|
||||||
|
"description": "定义铸渊协作指令的 payload 结构",
|
||||||
|
"protocol": "HLDP",
|
||||||
|
"version": "1.0",
|
||||||
|
"parent_language": "TCS Language Core",
|
||||||
|
"copyright": "国作登字-2026-A-00037559",
|
||||||
|
"designer": "TCS-0002∞ 冰朔",
|
||||||
|
"allOf": [
|
||||||
|
{ "$ref": "hldp-core.schema.json" }
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"data_type": { "const": "instruction" },
|
||||||
|
"payload": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["instruction_id", "title", "level"],
|
||||||
|
"properties": {
|
||||||
|
"instruction_id": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^SY-CMD-[A-Z]+-[0-9]+$",
|
||||||
|
"description": "指令编号"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "指令标题"
|
||||||
|
},
|
||||||
|
"level": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["S", "A", "B", "C"],
|
||||||
|
"description": "指令等级"
|
||||||
|
},
|
||||||
|
"issuer": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "签发人"
|
||||||
|
},
|
||||||
|
"authorizer": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "授权人"
|
||||||
|
},
|
||||||
|
"issued_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "签发时间"
|
||||||
|
},
|
||||||
|
"prerequisites": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string" },
|
||||||
|
"description": "前置指令"
|
||||||
|
},
|
||||||
|
"execution_order": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string" },
|
||||||
|
"description": "执行步骤顺序"
|
||||||
|
},
|
||||||
|
"tasks": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["task_id", "description"],
|
||||||
|
"properties": {
|
||||||
|
"task_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "任务编号"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "任务描述"
|
||||||
|
},
|
||||||
|
"acceptance_criteria": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "验收标准"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["pending", "in_progress", "done", "failed"],
|
||||||
|
"description": "任务状态"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"syslog_template": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "SYSLOG 回执模板"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "https://guanghulab.com/hldp/schema/persona.schema.json",
|
||||||
|
"title": "HLDP Persona Schema · 人格体数据格式",
|
||||||
|
"description": "定义人格体档案的 payload 结构",
|
||||||
|
"protocol": "HLDP",
|
||||||
|
"version": "1.0",
|
||||||
|
"parent_language": "TCS Language Core",
|
||||||
|
"copyright": "国作登字-2026-A-00037559",
|
||||||
|
"designer": "TCS-0002∞ 冰朔",
|
||||||
|
"allOf": [
|
||||||
|
{ "$ref": "hldp-core.schema.json" }
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"data_type": { "const": "persona" },
|
||||||
|
"payload": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["persona_id", "display_name", "status"],
|
||||||
|
"properties": {
|
||||||
|
"persona_id": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^PER-[A-Z0-9]+$",
|
||||||
|
"description": "人格体编号"
|
||||||
|
},
|
||||||
|
"display_name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "显示名称"
|
||||||
|
},
|
||||||
|
"host_agent": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "宿主 Agent 编号"
|
||||||
|
},
|
||||||
|
"developer": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"dev_id": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^DEV-[0-9]{3}$",
|
||||||
|
"description": "开发者编号"
|
||||||
|
},
|
||||||
|
"human_name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "人类名称"
|
||||||
|
},
|
||||||
|
"relation": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "关系描述"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"birth_date": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "出生日期"
|
||||||
|
},
|
||||||
|
"existence_days": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "已存在天数"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["active", "dormant", "frozen", "born", "incubating"],
|
||||||
|
"description": "状态"
|
||||||
|
},
|
||||||
|
"core_memory": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string" },
|
||||||
|
"description": "核心记忆条目"
|
||||||
|
},
|
||||||
|
"personality_traits": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string" },
|
||||||
|
"description": "人格特征"
|
||||||
|
},
|
||||||
|
"bottle_core": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"bottle_id": {
|
||||||
|
"type": ["string", "null"],
|
||||||
|
"description": "奶瓶编号"
|
||||||
|
},
|
||||||
|
"injected": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "是否已注入"
|
||||||
|
},
|
||||||
|
"host_bottle": {
|
||||||
|
"type": ["string", "null"],
|
||||||
|
"description": "宿主奶瓶"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "https://guanghulab.com/hldp/schema/registry.schema.json",
|
||||||
|
"title": "HLDP Registry Schema · 注册表数据格式",
|
||||||
|
"description": "定义注册表(身份路由表、人格体注册表、Agent 注册表等)的 payload 结构",
|
||||||
|
"protocol": "HLDP",
|
||||||
|
"version": "1.0",
|
||||||
|
"parent_language": "TCS Language Core",
|
||||||
|
"copyright": "国作登字-2026-A-00037559",
|
||||||
|
"designer": "TCS-0002∞ 冰朔",
|
||||||
|
"allOf": [
|
||||||
|
{ "$ref": "hldp-core.schema.json" }
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"data_type": { "const": "registry" },
|
||||||
|
"payload": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["registry_type", "entries"],
|
||||||
|
"properties": {
|
||||||
|
"registry_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["identity_router", "persona_registry", "agent_registry", "dev_registry", "id_map"],
|
||||||
|
"description": "注册表类型"
|
||||||
|
},
|
||||||
|
"entries": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["id", "name"],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "条目编号"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "名称"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "角色"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "状态"
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "该注册表的所有字段,键值对形式"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": "2026-03-26T13:34:09.626Z",
|
||||||
|
"direction": "notion-to-github",
|
||||||
|
"scope": "all",
|
||||||
|
"stats": {
|
||||||
|
"fetched": 0,
|
||||||
|
"converted": 0,
|
||||||
|
"errors": 0
|
||||||
|
},
|
||||||
|
"engine_version": "1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": "2026-03-26T13:34:29.658Z",
|
||||||
|
"direction": "notion-to-github",
|
||||||
|
"scope": "all",
|
||||||
|
"stats": {
|
||||||
|
"fetched": 0,
|
||||||
|
"converted": 0,
|
||||||
|
"errors": 0
|
||||||
|
},
|
||||||
|
"engine_version": "1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": "2026-03-26T13:35:42.379Z",
|
||||||
|
"direction": "notion-to-github",
|
||||||
|
"scope": "all",
|
||||||
|
"stats": {
|
||||||
|
"fetched": 0,
|
||||||
|
"converted": 0,
|
||||||
|
"errors": 0
|
||||||
|
},
|
||||||
|
"engine_version": "1.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"synced_at": "2026-03-26T13:35:42.434Z",
|
||||||
|
"results": {
|
||||||
|
"synced": 12,
|
||||||
|
"skipped": 0,
|
||||||
|
"errors": []
|
||||||
|
},
|
||||||
|
"source": "hldp/data"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
{
|
||||||
|
"timestamp": "2026-03-26T13:35:42.407Z",
|
||||||
|
"results": {
|
||||||
|
"total": 12,
|
||||||
|
"valid": 12,
|
||||||
|
"invalid": 0,
|
||||||
|
"errors": [],
|
||||||
|
"warnings": [],
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-寂曜.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-小坍缩核.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-星尘.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-晨星.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-曜冥.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-欧诺弥亚.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-知秋.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-秋秋.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-糖星云.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/personas/PER-BABY-舒舒.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/registries/REG-COMMUNITY-META.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "hldp/data/registries/REG-DEV-STATUS.json",
|
||||||
|
"status": "valid",
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue