| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- #!/usr/bin/env node
- 'use strict';
- // 从接口目录生成 skills/voc-api-catalog/references/platforms.md。
- // 这份索引是给 Agent 离线速查用的:有哪些平台、各有多少接口、常用接口 id 是什么。
- // 目录变更后运行 `npm run catalog:index` 重新生成,不要手改生成的文件。
- const fs = require('fs');
- const path = require('path');
- const { catalogOverview, listEndpoints, hydrateEndpoint } = require('../mcp/src/core/api-catalog');
- const OUTPUT = path.resolve(__dirname, '..', 'skills', 'voc-api-catalog', 'references', 'platforms.md');
- const PER_PLATFORM = 6;
- const COMMON_USE = /search|comment|detail|review|hot|user_post|posted|list|搜索|评论|详情|热/i;
- function rank(endpoint) {
- let score = Number(endpoint.recommendationPriority || 0);
- if (endpoint.verifiedAt) score += 100;
- if (COMMON_USE.test(`${endpoint.id} ${endpoint.title}`)) score += 10;
- return score;
- }
- function pickEndpoints(channel, platform) {
- return listEndpoints()
- .filter(item => !item.deprecated && (item.channel || 'social') === channel && item.platform === platform)
- .map((item, index) => ({ item, index, score: rank(item) }))
- .sort((a, b) => (b.score - a.score) || (a.index - b.index))
- .slice(0, PER_PLATFORM)
- .map(entry => hydrateEndpoint(entry.item));
- }
- function build() {
- const overview = catalogOverview();
- const lines = [
- '# 平台与接口索引',
- '',
- `> 由接口目录自动生成(目录 v${overview.version},${overview.updatedAt})。不要手改,目录变更后重新生成。`,
- '',
- `共 ${overview.active} 个可用接口。本文件每个平台只列最常用的几个,完整清单用 \`voc_api_search\` 传 \`platform\` 查。`,
- '',
- '用法:在下面找到平台 key 和接口 id → `voc_api_doc` 传 id 读参数 → `voc_api_call` 调用。',
- '带 ✓ 的接口在目录更新当天做过真实调用验证。没有 ✓ 不代表不可用,只是没有逐个实测。',
- ''
- ];
- for (const channel of overview.channels) {
- lines.push(`## ${channel.label}(channel=${channel.channel})`, '');
- lines.push(`${channel.platforms.length} 个平台,${channel.active} 个接口。`, '');
- for (const platform of channel.platforms) {
- lines.push(`### ${platform.label} \`${platform.key}\`(${platform.active} 个)`, '');
- for (const endpoint of pickEndpoints(channel.channel, platform.key)) {
- const required = (endpoint.params || []).filter(param => param.required).map(param => param.name);
- const mark = endpoint.verifiedAt ? ' ✓' : '';
- lines.push(`- \`${endpoint.id}\`${mark} ${endpoint.title}。必填:${required.join(', ') || '无'}`);
- }
- lines.push('');
- }
- }
- return `${lines.join('\n').replace(/\n+$/, '')}\n`;
- }
- if (require.main === module) {
- const content = build();
- if (process.argv.includes('--check')) {
- const current = fs.existsSync(OUTPUT) ? fs.readFileSync(OUTPUT, 'utf8') : '';
- if (current !== content) {
- console.error('platforms.md 与接口目录不一致,请运行 npm run catalog:index');
- process.exit(1);
- }
- console.log('platforms.md is up to date');
- } else {
- fs.writeFileSync(OUTPUT, content, 'utf8');
- console.log(`wrote ${path.relative(process.cwd(), OUTPUT)} (${content.split('\n').length} lines)`);
- }
- }
- module.exports = { build, OUTPUT };
|