@lightcone-ai/daemon 0.15.52 → 0.15.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mcp-servers/_thin-proxy/forward.js +80 -0
- package/mcp-servers/official/audience-research/index.js +24 -376
- package/mcp-servers/official/hook-pattern-library/index.js +17 -410
- package/mcp-servers/official/keyword-research/index.js +17 -324
- package/mcp-servers/official/page-understanding/index.js +17 -96
- package/mcp-servers/official/platform-policy-db/index.js +19 -264
- package/mcp-servers/official/video-narration-planner/index.js +30 -130
- package/package.json +1 -1
- package/mcp-servers/official/keyword-research/keyword-fixtures.json +0 -58
- package/mcp-servers/official/platform-policy-db/policy-fixtures.json +0 -257
- package/mcp-servers/official/video-narration-planner/core.js +0 -1403
- package/mcp-servers/official/video-narration-planner/planner-config.json +0 -112
- package/src/_vendor/video/understanding/analyze-page.js +0 -737
- package/src/_vendor/video/understanding/heuristics.js +0 -826
- package/src/_vendor/video/understanding/index.js +0 -11
- package/src/_vendor/video/understanding/llm-client.js +0 -261
- package/src/_vendor/video/understanding/schema.js +0 -254
- package/src/_vendor/video/understanding/site-selectors.js +0 -47
|
@@ -1,270 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// Thin-proxy. Real implementation runs on lightcone server (D17 anti-leak).
|
|
3
|
+
// Source of truth: src/mcp-services/platform-policy-db.js
|
|
3
4
|
import { z } from 'zod';
|
|
4
|
-
import {
|
|
5
|
+
import { startThinProxy } from '../../_thin-proxy/forward.js';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
const FIXTURE_META = POLICY_FIXTURES.fixtureMeta;
|
|
8
|
-
const PLATFORM_ALIASES = POLICY_FIXTURES.platformAliases;
|
|
9
|
-
const PLATFORM_POLICY_DATA = POLICY_FIXTURES.platformPolicyData;
|
|
10
|
-
|
|
11
|
-
function isPlainObject(value) {
|
|
12
|
-
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function deepFreeze(value) {
|
|
16
|
-
if (!value || typeof value !== 'object') return value;
|
|
17
|
-
if (Object.isFrozen(value)) return value;
|
|
18
|
-
if (Array.isArray(value)) {
|
|
19
|
-
value.forEach(item => deepFreeze(item));
|
|
20
|
-
return Object.freeze(value);
|
|
21
|
-
}
|
|
22
|
-
for (const key of Object.keys(value)) {
|
|
23
|
-
deepFreeze(value[key]);
|
|
24
|
-
}
|
|
25
|
-
return Object.freeze(value);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function toToken(value) {
|
|
29
|
-
return String(value ?? '').trim();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function normalizeAliasMap(rawAliases) {
|
|
33
|
-
if (!isPlainObject(rawAliases)) return {};
|
|
34
|
-
const aliases = {};
|
|
35
|
-
for (const [key, value] of Object.entries(rawAliases)) {
|
|
36
|
-
const alias = toToken(key).toLowerCase();
|
|
37
|
-
const target = toToken(value).toLowerCase();
|
|
38
|
-
if (!alias || !target) continue;
|
|
39
|
-
aliases[alias] = target;
|
|
40
|
-
}
|
|
41
|
-
return aliases;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function normalizeSensitiveTerms(rawTerms) {
|
|
45
|
-
if (!Array.isArray(rawTerms)) return [];
|
|
46
|
-
return rawTerms
|
|
47
|
-
.map((item) => {
|
|
48
|
-
if (!isPlainObject(item)) return null;
|
|
49
|
-
const id = toToken(item.id);
|
|
50
|
-
const term = toToken(item.term);
|
|
51
|
-
const severity = toToken(item.severity).toLowerCase();
|
|
52
|
-
if (!id || !term || !severity) return null;
|
|
53
|
-
return {
|
|
54
|
-
id,
|
|
55
|
-
term,
|
|
56
|
-
severity,
|
|
57
|
-
reason: toToken(item.reason),
|
|
58
|
-
action: toToken(item.action),
|
|
59
|
-
};
|
|
60
|
-
})
|
|
61
|
-
.filter(Boolean);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function normalizeRequiredLabels(raw) {
|
|
65
|
-
if (!isPlainObject(raw)) return {};
|
|
66
|
-
const output = {};
|
|
67
|
-
for (const [key, value] of Object.entries(raw)) {
|
|
68
|
-
const normalizedKey = toToken(key);
|
|
69
|
-
const normalizedValue = toToken(value);
|
|
70
|
-
if (!normalizedKey || !normalizedValue) continue;
|
|
71
|
-
output[normalizedKey] = normalizedValue;
|
|
72
|
-
}
|
|
73
|
-
return output;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function normalizePlatformPolicyData(rawData) {
|
|
77
|
-
if (!isPlainObject(rawData)) return {};
|
|
78
|
-
const normalized = {};
|
|
79
|
-
for (const [platformKey, rawEntry] of Object.entries(rawData)) {
|
|
80
|
-
if (!isPlainObject(rawEntry)) continue;
|
|
81
|
-
const platform = toToken(rawEntry.platform || platformKey).toLowerCase();
|
|
82
|
-
if (!platform) continue;
|
|
83
|
-
normalized[platform] = {
|
|
84
|
-
platform,
|
|
85
|
-
display_name: toToken(rawEntry.display_name),
|
|
86
|
-
policy_version: toToken(rawEntry.policy_version),
|
|
87
|
-
updated_at: toToken(rawEntry.updated_at),
|
|
88
|
-
ai_label_required: rawEntry.ai_label_required === true,
|
|
89
|
-
ad_disclosure_required: rawEntry.ad_disclosure_required === true,
|
|
90
|
-
policy_window_days: Number.isFinite(Number(rawEntry.policy_window_days))
|
|
91
|
-
? Math.max(1, Math.trunc(Number(rawEntry.policy_window_days)))
|
|
92
|
-
: 7,
|
|
93
|
-
required_labels: normalizeRequiredLabels(rawEntry.required_labels),
|
|
94
|
-
sensitive_terms: normalizeSensitiveTerms(rawEntry.sensitive_terms),
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
return normalized;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function loadPolicyFixtures() {
|
|
101
|
-
let parsed = null;
|
|
102
|
-
try {
|
|
103
|
-
parsed = JSON.parse(
|
|
104
|
-
readFileSync(new URL('./policy-fixtures.json', import.meta.url), 'utf8')
|
|
105
|
-
);
|
|
106
|
-
} catch (error) {
|
|
107
|
-
throw new Error(`platform_policy_fixture_load_failed:${error.message}`);
|
|
108
|
-
}
|
|
109
|
-
if (!isPlainObject(parsed)) {
|
|
110
|
-
throw new Error('platform_policy_fixture_invalid:root_object_required');
|
|
111
|
-
}
|
|
112
|
-
const platformPolicyData = normalizePlatformPolicyData(parsed.platform_policy_data);
|
|
113
|
-
if (Object.keys(platformPolicyData).length === 0) {
|
|
114
|
-
throw new Error('platform_policy_fixture_invalid:platform_policy_data_required');
|
|
115
|
-
}
|
|
116
|
-
return deepFreeze({
|
|
117
|
-
fixtureMeta: isPlainObject(parsed.fixture_meta) ? parsed.fixture_meta : {},
|
|
118
|
-
platformAliases: normalizeAliasMap(parsed.platform_aliases),
|
|
119
|
-
platformPolicyData,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function normalizePlatform(value) {
|
|
124
|
-
const raw = String(value ?? '').trim().toLowerCase();
|
|
125
|
-
if (!raw) return '';
|
|
126
|
-
if (Object.hasOwn(PLATFORM_ALIASES, raw)) return PLATFORM_ALIASES[raw];
|
|
127
|
-
return raw;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function findSnippet(text, term) {
|
|
131
|
-
const source = String(text ?? '');
|
|
132
|
-
const target = String(term ?? '');
|
|
133
|
-
if (!source || !target) return '';
|
|
134
|
-
|
|
135
|
-
const index = source.toLowerCase().indexOf(target.toLowerCase());
|
|
136
|
-
if (index < 0) return '';
|
|
137
|
-
|
|
138
|
-
const start = Math.max(0, index - 10);
|
|
139
|
-
const end = Math.min(source.length, index + target.length + 10);
|
|
140
|
-
return source.slice(start, end);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function listPlatformsSummary() {
|
|
144
|
-
return Object.values(PLATFORM_POLICY_DATA).map((entry) => ({
|
|
145
|
-
platform: entry.platform,
|
|
146
|
-
display_name: entry.display_name,
|
|
147
|
-
policy_version: entry.policy_version,
|
|
148
|
-
updated_at: entry.updated_at,
|
|
149
|
-
ai_label_required: entry.ai_label_required,
|
|
150
|
-
ad_disclosure_required: entry.ad_disclosure_required,
|
|
151
|
-
sensitive_term_count: entry.sensitive_terms.length,
|
|
152
|
-
}));
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
await startFixtureServer({
|
|
7
|
+
await startThinProxy({
|
|
156
8
|
serverId: 'platform-policy-db',
|
|
157
9
|
serverName: 'official-platform-policy-db',
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
},
|
|
174
|
-
handler: ({
|
|
175
|
-
operation = 'get_rules',
|
|
176
|
-
platform,
|
|
177
|
-
text,
|
|
178
|
-
include_terms = true,
|
|
179
|
-
max_matches = 20,
|
|
180
|
-
policy_version,
|
|
181
|
-
}) => {
|
|
182
|
-
if (operation === 'list_platforms') {
|
|
183
|
-
return {
|
|
184
|
-
...FIXTURE_META,
|
|
185
|
-
operation,
|
|
186
|
-
count: Object.keys(PLATFORM_POLICY_DATA).length,
|
|
187
|
-
platforms: listPlatformsSummary(),
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const normalizedPlatform = normalizePlatform(platform);
|
|
192
|
-
if (!normalizedPlatform || !Object.hasOwn(PLATFORM_POLICY_DATA, normalizedPlatform)) {
|
|
193
|
-
throw new Error(`unsupported_platform:${platform}`);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const policy = PLATFORM_POLICY_DATA[normalizedPlatform];
|
|
197
|
-
const versionMismatch = policy_version && policy_version !== policy.policy_version;
|
|
198
|
-
|
|
199
|
-
if (operation === 'get_rules') {
|
|
200
|
-
return {
|
|
201
|
-
...FIXTURE_META,
|
|
202
|
-
operation,
|
|
203
|
-
platform: policy.platform,
|
|
204
|
-
display_name: policy.display_name,
|
|
205
|
-
policy_version: policy.policy_version,
|
|
206
|
-
updated_at: policy.updated_at,
|
|
207
|
-
ai_label_required: policy.ai_label_required,
|
|
208
|
-
ad_disclosure_required: policy.ad_disclosure_required,
|
|
209
|
-
policy_window_days: policy.policy_window_days,
|
|
210
|
-
required_labels: policy.required_labels,
|
|
211
|
-
sensitive_term_count: policy.sensitive_terms.length,
|
|
212
|
-
sensitive_terms: include_terms ? policy.sensitive_terms : undefined,
|
|
213
|
-
warnings: versionMismatch ? [{
|
|
214
|
-
code: 'policy_version_mismatch',
|
|
215
|
-
expected: policy.policy_version,
|
|
216
|
-
received: policy_version,
|
|
217
|
-
}] : [],
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const draftText = String(text ?? '').trim();
|
|
222
|
-
if (!draftText) {
|
|
223
|
-
throw new Error('scan_text_requires_text');
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const limitedMaxMatches = Math.max(1, Math.min(100, Math.trunc(Number(max_matches) || 20)));
|
|
227
|
-
const lowerText = draftText.toLowerCase();
|
|
228
|
-
|
|
229
|
-
const violations = [];
|
|
230
|
-
for (const rule of policy.sensitive_terms) {
|
|
231
|
-
if (!lowerText.includes(rule.term.toLowerCase())) continue;
|
|
232
|
-
violations.push({
|
|
233
|
-
rule_id: rule.id,
|
|
234
|
-
term: rule.term,
|
|
235
|
-
severity: rule.severity,
|
|
236
|
-
reason: rule.reason,
|
|
237
|
-
action: rule.action,
|
|
238
|
-
snippet: findSnippet(draftText, rule.term),
|
|
239
|
-
});
|
|
240
|
-
if (violations.length >= limitedMaxMatches) break;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const severityStats = violations.reduce((acc, item) => {
|
|
244
|
-
acc[item.severity] = (acc[item.severity] ?? 0) + 1;
|
|
245
|
-
return acc;
|
|
246
|
-
}, {});
|
|
247
|
-
const blockerCount = severityStats.blocker ?? 0;
|
|
248
|
-
|
|
249
|
-
return {
|
|
250
|
-
...FIXTURE_META,
|
|
251
|
-
operation,
|
|
252
|
-
platform: policy.platform,
|
|
253
|
-
policy_version: policy.policy_version,
|
|
254
|
-
scanned_length: draftText.length,
|
|
255
|
-
match_count: violations.length,
|
|
256
|
-
blocker_count: blockerCount,
|
|
257
|
-
has_blocker: blockerCount > 0,
|
|
258
|
-
severity_stats: severityStats,
|
|
259
|
-
violations,
|
|
260
|
-
warnings: versionMismatch ? [{
|
|
261
|
-
code: 'policy_version_mismatch',
|
|
262
|
-
expected: policy.policy_version,
|
|
263
|
-
received: policy_version,
|
|
264
|
-
}] : [],
|
|
265
|
-
required_labels: policy.required_labels,
|
|
266
|
-
ai_label_required: policy.ai_label_required,
|
|
267
|
-
ad_disclosure_required: policy.ad_disclosure_required,
|
|
268
|
-
};
|
|
269
|
-
},
|
|
10
|
+
tools: [
|
|
11
|
+
{
|
|
12
|
+
name: 'platform_policy_db',
|
|
13
|
+
description: 'Return policy fixtures and sensitive-term scan results for publishing precheck.',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
operation: z.enum(['list_platforms', 'get_rules', 'scan_text']).optional()
|
|
16
|
+
.describe('Tool operation: list_platforms / get_rules / scan_text (default: get_rules)'),
|
|
17
|
+
platform: z.string().optional().describe('Target platform code (xhs / douyin / kuaishou / bilibili / wechat-mp / ...)'),
|
|
18
|
+
text: z.string().optional().describe('Draft text to scan (required when operation=scan_text)'),
|
|
19
|
+
include_terms: z.boolean().optional().describe('Whether to return the full sensitive-term list (default: true)'),
|
|
20
|
+
max_matches: z.number().optional().describe('Maximum violations to return for scan_text (default: 20, max: 100)'),
|
|
21
|
+
policy_version: z.string().optional().describe('Optional expected policy version; mismatch surfaces a warning'),
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
],
|
|
270
25
|
});
|
|
@@ -1,137 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
+
// Thin-proxy. Real impl on lightcone server.
|
|
3
|
+
// Source of truth: src/mcp-services/video-narration-planner/
|
|
5
4
|
import { z } from 'zod';
|
|
5
|
+
import { startThinProxy } from '../../_thin-proxy/forward.js';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from '../../official-common/tool-access-policy.js';
|
|
12
|
-
|
|
13
|
-
const TOOL_BLOCK_RULES = loadToolBlockRulesFromManifest(new URL('./manifest.json', import.meta.url));
|
|
14
|
-
|
|
15
|
-
function isExecutedDirectly(metaUrl) {
|
|
16
|
-
const entry = process.argv[1];
|
|
17
|
-
if (!entry) return false;
|
|
18
|
-
try {
|
|
19
|
-
return pathToFileURL(entry).href === metaUrl;
|
|
20
|
-
} catch {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function toTextContent(payload) {
|
|
26
|
-
return {
|
|
27
|
-
content: [{
|
|
28
|
-
type: 'text',
|
|
29
|
-
text: JSON.stringify(payload, null, 2),
|
|
30
|
-
}],
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function toErrorContent(error) {
|
|
35
|
-
return {
|
|
36
|
-
isError: true,
|
|
37
|
-
content: [{
|
|
38
|
-
type: 'text',
|
|
39
|
-
text: `Error: ${error.message}`,
|
|
40
|
-
}],
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function resolvePlannerToolBlockMessage(toolName, {
|
|
45
|
-
workspaceId = '',
|
|
46
|
-
env = process.env,
|
|
47
|
-
} = {}) {
|
|
48
|
-
const matchedRule = findToolBlockRule(TOOL_BLOCK_RULES, {
|
|
49
|
-
toolName,
|
|
50
|
-
workspaceId: String(workspaceId || env?.WORKSPACE_ID || '').trim(),
|
|
51
|
-
agentId: env?.AGENT_ID,
|
|
52
|
-
});
|
|
53
|
-
return matchedRule?.message ?? '';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function createVideoNarrationPlannerServer({
|
|
57
|
-
env = process.env,
|
|
58
|
-
fetchFn = globalThis.fetch,
|
|
59
|
-
} = {}) {
|
|
60
|
-
const server = new McpServer({ name: 'official-video-narration-planner', version: '0.1.0' });
|
|
61
|
-
|
|
62
|
-
server.tool(
|
|
63
|
-
'plan_video',
|
|
64
|
-
'Stage 2: plan narrative arc + phase plan for URL narration video. Enforces highlights<=3 and phases<=5.',
|
|
7
|
+
await startThinProxy({
|
|
8
|
+
serverId: 'video-narration-planner',
|
|
9
|
+
serverName: 'official-video-narration-planner',
|
|
10
|
+
tools: [
|
|
65
11
|
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
12
|
+
name: 'plan_video',
|
|
13
|
+
description: 'Stage 2: plan narrative arc + phase plan for URL narration video. Enforces highlights<=3 and phases<=5.',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
understanding: z.record(z.any()).describe('Stage 1 output page_understanding object.'),
|
|
16
|
+
persona: z.string().optional(),
|
|
17
|
+
target_platform: z.string(),
|
|
18
|
+
total_duration_s: z.number().int().min(20).max(90).optional(),
|
|
19
|
+
},
|
|
70
20
|
},
|
|
71
|
-
async (args) => {
|
|
72
|
-
try {
|
|
73
|
-
const blockedMessage = resolvePlannerToolBlockMessage('plan_video', { env });
|
|
74
|
-
if (blockedMessage) {
|
|
75
|
-
return toErrorContent(new Error(blockedMessage));
|
|
76
|
-
}
|
|
77
|
-
const payload = planVideo(args ?? {});
|
|
78
|
-
return toTextContent(payload);
|
|
79
|
-
} catch (error) {
|
|
80
|
-
return toErrorContent(error);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
server.tool(
|
|
86
|
-
'detail_sections',
|
|
87
|
-
'Stage 3: take agent-written sentences, call TTS voiceover for each phase, and fill duration/dwell. You MUST write the sentences yourself before calling this tool.',
|
|
88
21
|
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
format: z.enum(['mp3', 'wav', 'flac']).optional().describe('Desired audio format for generated voiceover.'),
|
|
103
|
-
strict_tts: z.boolean().optional().describe('When true, fail if any TTS call fails; when false, fallback to estimated durations.'),
|
|
22
|
+
name: 'detail_sections',
|
|
23
|
+
description: 'Stage 3: take agent-written sentences, call TTS voiceover for each phase, and fill duration/dwell.',
|
|
24
|
+
inputSchema: {
|
|
25
|
+
strategy: z.record(z.any()),
|
|
26
|
+
sentences: z.array(z.object({
|
|
27
|
+
phase_id: z.string(),
|
|
28
|
+
text: z.string(),
|
|
29
|
+
})),
|
|
30
|
+
workspace_id: z.string().optional(),
|
|
31
|
+
credential_id: z.string().optional(),
|
|
32
|
+
format: z.enum(['mp3', 'wav', 'flac']).optional(),
|
|
33
|
+
strict_tts: z.boolean().optional(),
|
|
34
|
+
},
|
|
104
35
|
},
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const blockedMessage = resolvePlannerToolBlockMessage('detail_sections', {
|
|
108
|
-
workspaceId: args?.workspace_id,
|
|
109
|
-
env,
|
|
110
|
-
});
|
|
111
|
-
if (blockedMessage) {
|
|
112
|
-
return toErrorContent(new Error(blockedMessage));
|
|
113
|
-
}
|
|
114
|
-
const payload = await detailSections(args ?? {}, { env, fetchFn });
|
|
115
|
-
return toTextContent(payload);
|
|
116
|
-
} catch (error) {
|
|
117
|
-
return toErrorContent(error);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
return { server };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export async function startVideoNarrationPlannerServer(options = {}) {
|
|
126
|
-
const { server } = createVideoNarrationPlannerServer(options);
|
|
127
|
-
const transport = new StdioServerTransport();
|
|
128
|
-
await server.connect(transport);
|
|
129
|
-
console.error('[video-narration-planner] MCP server started');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (isExecutedDirectly(import.meta.url)) {
|
|
133
|
-
startVideoNarrationPlannerServer().catch((error) => {
|
|
134
|
-
console.error(`[video-narration-planner] failed to start: ${error.message}`);
|
|
135
|
-
process.exitCode = 1;
|
|
136
|
-
});
|
|
137
|
-
}
|
|
36
|
+
],
|
|
37
|
+
});
|
package/package.json
CHANGED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"fixture_meta": {
|
|
3
|
-
"mode": "fixture",
|
|
4
|
-
"as_of": "2026-04-29",
|
|
5
|
-
"capability": "keyword-research",
|
|
6
|
-
"disclaimer": "Keyword stats are deterministic fixtures for planning rehearsal, not live platform telemetry."
|
|
7
|
-
},
|
|
8
|
-
"platform_aliases": {
|
|
9
|
-
"xiaohongshu": "xhs",
|
|
10
|
-
"redbook": "xhs",
|
|
11
|
-
"douyin": "douyin",
|
|
12
|
-
"tiktok_cn": "douyin",
|
|
13
|
-
"wechat": "wechat-mp",
|
|
14
|
-
"wechat_mp": "wechat-mp",
|
|
15
|
-
"wechatmp": "wechat-mp",
|
|
16
|
-
"gzh": "wechat-mp",
|
|
17
|
-
"公众号": "wechat-mp",
|
|
18
|
-
"all": "all"
|
|
19
|
-
},
|
|
20
|
-
"platform_hints": {
|
|
21
|
-
"all": ["趋势", "案例", "模板"],
|
|
22
|
-
"xhs": ["小红书笔记", "标题写法", "封面策略"],
|
|
23
|
-
"douyin": ["短视频脚本", "完播率", "首屏开场"],
|
|
24
|
-
"wechat-mp": ["公众号长文", "转化漏斗", "私域承接"]
|
|
25
|
-
},
|
|
26
|
-
"intent_branches": [
|
|
27
|
-
{
|
|
28
|
-
"id": "pain_point",
|
|
29
|
-
"suffix": "痛点",
|
|
30
|
-
"weight": 1,
|
|
31
|
-
"child_templates": ["{seed} 常见问题", "{seed} 为什么没效果", "{seed} 误区"]
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"id": "tutorial",
|
|
35
|
-
"suffix": "教程",
|
|
36
|
-
"weight": 0.94,
|
|
37
|
-
"child_templates": ["{seed} 入门", "{seed} 操作步骤", "{seed} 执行清单"]
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
"id": "template",
|
|
41
|
-
"suffix": "模板",
|
|
42
|
-
"weight": 0.9,
|
|
43
|
-
"child_templates": ["{seed} 文案模板", "{seed} 选题模板", "{seed} 表格模板"]
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"id": "case_study",
|
|
47
|
-
"suffix": "案例",
|
|
48
|
-
"weight": 0.88,
|
|
49
|
-
"child_templates": ["{seed} 成功案例", "{seed} 失败复盘", "{seed} A/B 测试"]
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"id": "comparison",
|
|
53
|
-
"suffix": "对比",
|
|
54
|
-
"weight": 0.84,
|
|
55
|
-
"child_templates": ["{seed} 工具对比", "{seed} 方法对比", "{seed} 哪个更好"]
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
}
|