fix(mindspace): edit_file 落盘、Finish 聊天 merge 与回归守卫

- finish-sync 支持 edit_file 覆盖 public HTML
- Finish 同步 merge 本地流式消息,剥离 agent 内部前缀
- 新增 verify:mindspace-publish-guards 与 AGENTS.md 跨工具说明
- 发版脚本接入回归门禁;103 runtime 发布含备份回退

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-30 00:27:15 +08:00
parent 742aee7148
commit 98721371a4
31 changed files with 1440 additions and 141 deletions
+35 -1
View File
@@ -13,6 +13,12 @@ const WEB_NEWS_INTENT_PATTERNS = [
/(?:what(?:'s| is)?\s+the\s+latest|what(?:'s| is)?\s+trending)/i,
];
const PAGE_GENERATION_INTENT_PATTERNS = [
/(?:生成|做|制作|创建|设计|写|出)(?:一个|一份|个)?(?:H5|h5|HTML|html|网页|页面|活动页|宣传页|落地页|分享页)/u,
/(?:帮我|给我).*(?:H5|h5|HTML|html|网页|页面|活动页|宣传页|落地页|分享页)/u,
/(?:publish|create|generate|make|build|design).*(?:html|web\s?page|landing\s?page|h5)/i,
];
export const CHAT_SKILL_DEFINITIONS = [
{
id: 'web-search',
@@ -103,7 +109,11 @@ export function buildChatSkillPrompt(promptKey, skillName) {
case 'analyze':
return '请深入分析以下内容,给出结构化解读:背景、关键发现、风险或机会、以及建议下一步:';
case 'generate-page':
return `请使用 ${skillName ?? PUBLISH_SKILL_NAME} 技能:在我的专属 MindSpace 发布目录生成静态 HTML 页面,并给出可公网访问的完整链接。`;
return (
`请使用 ${skillName ?? PUBLISH_SKILL_NAME} 技能:在我的专属 MindSpace 发布目录生成静态 HTML 页面,并给出可公网访问的完整链接。` +
'必须先 load_skill,再用 write_file/edit_file 写入 public/页面.html;完成后直接返回 Markdown 可点击公网链接 `[页面标题](URL)`。' +
'禁止只给本地路径(如 hello/index.html),禁止询问是否还要发布,除非写文件工具实际失败。'
);
default:
return '';
}
@@ -124,6 +134,12 @@ export function filterChatSkills(options, ctx) {
export function buildAutoChatSkillPrefix(text, grantedSkills = []) {
const trimmed = String(text ?? '').trim();
if (!trimmed) return '';
if (
grantedSkills.includes(PUBLISH_SKILL_NAME) &&
PAGE_GENERATION_INTENT_PATTERNS.some((pattern) => pattern.test(trimmed))
) {
return buildChatSkillPrompt('generate-page', PUBLISH_SKILL_NAME);
}
if (!grantedSkills.includes('web')) return '';
if (WEB_NEWS_INTENT_PATTERNS.some((pattern) => pattern.test(trimmed))) {
return buildWebNewsSkillPrompt('web');
@@ -131,3 +147,21 @@ export function buildAutoChatSkillPrefix(text, grantedSkills = []) {
if (!WEB_INTENT_PATTERNS.some((pattern) => pattern.test(trimmed))) return '';
return buildChatSkillPrompt('web', 'web');
}
export function stripKnownChatSkillPrompt(text) {
let next = String(text ?? '').trimStart();
const candidates = [];
for (const definition of CHAT_SKILL_DEFINITIONS) {
if (!definition.promptKey) continue;
candidates.push(buildChatSkillPrompt(definition.promptKey, definition.skillName));
}
candidates.push(buildWebNewsSkillPrompt('web'));
candidates.sort((a, b) => b.length - a.length);
for (const prompt of candidates) {
if (prompt && next.startsWith(prompt)) {
next = next.slice(prompt.length);
break;
}
}
return next.trim();
}