Initial commit: Memind H5 portal with MindSpace, Plaza, and agent jobs.
Track application source and tests; exclude local env, user workspaces, and runtime data via .gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
const VIEW_LABELS = {
|
||||
home: '空间首页',
|
||||
category: '分类列表',
|
||||
page: '页面详情',
|
||||
};
|
||||
|
||||
const STATUS_LABELS = {
|
||||
draft: '草稿',
|
||||
reviewing: '待检查',
|
||||
risk_found: '发现风险',
|
||||
ready: '可发布',
|
||||
published: '已公开',
|
||||
protected: '受保护',
|
||||
expired: '已过期',
|
||||
offline: '已下线',
|
||||
};
|
||||
|
||||
const TEMPLATE_LABELS = {
|
||||
editorial: '编辑长文',
|
||||
report: '分析报告',
|
||||
'knowledge-card': '知识卡片',
|
||||
profile: '个人介绍',
|
||||
'static-html': '静态 HTML',
|
||||
};
|
||||
|
||||
const CONTENT_EXCERPT_LIMIT = 1800;
|
||||
const ASSET_PREVIEW_LIMIT = 10;
|
||||
|
||||
function stripHtml(value) {
|
||||
return String(value ?? '')
|
||||
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
||||
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
||||
.replace(/<[^>]+>/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function excerptContent(content, contentFormat, max = CONTENT_EXCERPT_LIMIT) {
|
||||
const raw = String(content ?? '').trim();
|
||||
if (!raw) return '';
|
||||
const text = contentFormat === 'html' ? stripHtml(raw) : raw;
|
||||
if (text.length <= max) return text;
|
||||
return `${text.slice(0, max - 1)}…`;
|
||||
}
|
||||
|
||||
function resolveCategory(space, selectedCategory, page) {
|
||||
if (selectedCategory) return selectedCategory;
|
||||
if (!page?.categoryCode) return null;
|
||||
return space.categories?.find((item) => item.code === page.categoryCode) ?? null;
|
||||
}
|
||||
|
||||
function resolvePageRecord(selectedPageId, pages, pageLive) {
|
||||
const listed = selectedPageId ? pages.find((item) => item.id === selectedPageId) : undefined;
|
||||
if (!pageLive) return listed;
|
||||
return {
|
||||
...(listed ?? {}),
|
||||
...pageLive.page,
|
||||
title: pageLive.title,
|
||||
summary: pageLive.summary,
|
||||
content: pageLive.content,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildMindSpaceChatContext(input) {
|
||||
const {
|
||||
space,
|
||||
ownerUsername,
|
||||
selectedCategory,
|
||||
selectedPageId,
|
||||
pages = [],
|
||||
pageLive = null,
|
||||
assets = [],
|
||||
focusedAsset = null,
|
||||
route,
|
||||
} = input;
|
||||
|
||||
const pageRecord = resolvePageRecord(selectedPageId, pages, pageLive);
|
||||
const category = resolveCategory(space, selectedCategory, pageRecord);
|
||||
|
||||
let view = 'home';
|
||||
if (pageRecord && selectedPageId) view = 'page';
|
||||
else if (selectedCategory) view = 'category';
|
||||
|
||||
const context = {
|
||||
spaceId: space.id,
|
||||
spaceName: space.name,
|
||||
view,
|
||||
route,
|
||||
...(ownerUsername ? { ownerUsername } : {}),
|
||||
...(category
|
||||
? {
|
||||
category: {
|
||||
code: category.code,
|
||||
name: category.name,
|
||||
itemCount: category.itemCount,
|
||||
...(view === 'category' && assets.length
|
||||
? {
|
||||
assets: assets.slice(0, ASSET_PREVIEW_LIMIT).map((asset) => ({
|
||||
id: asset.id,
|
||||
displayName: asset.displayName,
|
||||
mimeType: asset.mimeType,
|
||||
})),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(pageRecord && selectedPageId
|
||||
? {
|
||||
page: {
|
||||
id: pageRecord.id,
|
||||
title: pageLive?.title ?? pageRecord.title,
|
||||
summary: pageLive?.summary ?? pageRecord.summary ?? '',
|
||||
status: pageRecord.status,
|
||||
versionNo: pageRecord.versionNo,
|
||||
categoryCode: pageRecord.categoryCode,
|
||||
templateId: pageRecord.templateId,
|
||||
contentFormat: pageRecord.contentFormat ?? 'markdown',
|
||||
pageType: pageRecord.pageType,
|
||||
contentExcerpt: excerptContent(
|
||||
pageLive?.content ?? pageRecord.content ?? '',
|
||||
pageRecord.contentFormat ?? 'markdown',
|
||||
),
|
||||
publicationUrl: pageRecord.publication?.publicUrl ?? null,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(focusedAsset
|
||||
? {
|
||||
focusedAsset: {
|
||||
id: focusedAsset.id,
|
||||
displayName: focusedAsset.displayName,
|
||||
mimeType: focusedAsset.mimeType,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
||||
if (view === 'home' && space.categories?.length) {
|
||||
context.homeCategories = space.categories.map((item) => ({
|
||||
code: item.code,
|
||||
name: item.name,
|
||||
itemCount: item.itemCount,
|
||||
}));
|
||||
}
|
||||
|
||||
if (view === 'home' && pages.length) {
|
||||
context.recentPages = pages.slice(0, 8).map((item) => ({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
status: item.status,
|
||||
categoryCode: item.categoryCode,
|
||||
}));
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
function buildLocationHint(context) {
|
||||
if (context.page) {
|
||||
return `用户正在查看/编辑页面「${context.page.title}」(id: ${context.page.id})。指代「这个页面」「改这里」时默认指该页面。`;
|
||||
}
|
||||
if (context.focusedAsset) {
|
||||
return `用户正在处理资料「${context.focusedAsset.displayName}」(id: ${context.focusedAsset.id})。指代「这个文件」「这份资料」时默认指该资产。`;
|
||||
}
|
||||
if (context.category) {
|
||||
return `用户正在「${context.category.name}」分类中浏览。指代「这里的文件」时默认指该分类下的资料。`;
|
||||
}
|
||||
return '用户在 MindSpace 空间首页。指代「我的空间」时指整个个人空间。';
|
||||
}
|
||||
|
||||
export function buildContextPrefix(context) {
|
||||
const lines = [
|
||||
'[MindSpace 上下文]',
|
||||
`- 空间:${context.spaceName}(id: ${context.spaceId})`,
|
||||
];
|
||||
|
||||
if (context.ownerUsername) {
|
||||
lines.push(`- 账号:${context.ownerUsername}`);
|
||||
}
|
||||
|
||||
lines.push(`- 当前视图:${VIEW_LABELS[context.view]}`);
|
||||
|
||||
if (context.category) {
|
||||
const count =
|
||||
typeof context.category.itemCount === 'number'
|
||||
? `,共 ${context.category.itemCount} 项`
|
||||
: '';
|
||||
lines.push(`- 分类:${context.category.name}(${context.category.code}${count})`);
|
||||
if (context.category.assets?.length) {
|
||||
lines.push('- 当前分类资料(节选):');
|
||||
for (const asset of context.category.assets) {
|
||||
lines.push(` · ${asset.displayName}(id: ${asset.id},${asset.mimeType})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.page) {
|
||||
lines.push(`- 页面:${context.page.title}(id: ${context.page.id})`);
|
||||
if (context.page.categoryCode) {
|
||||
lines.push(`- 页面所属分类:${context.page.categoryCode}`);
|
||||
}
|
||||
if (context.page.status) {
|
||||
lines.push(
|
||||
`- 页面状态:${STATUS_LABELS[context.page.status] ?? context.page.status}`,
|
||||
);
|
||||
}
|
||||
if (typeof context.page.versionNo === 'number') {
|
||||
lines.push(`- 页面版本:v${context.page.versionNo}`);
|
||||
}
|
||||
if (context.page.templateId) {
|
||||
lines.push(
|
||||
`- 页面模板:${TEMPLATE_LABELS[context.page.templateId] ?? context.page.templateId}`,
|
||||
);
|
||||
}
|
||||
if (context.page.contentFormat) {
|
||||
lines.push(`- 内容格式:${context.page.contentFormat}`);
|
||||
}
|
||||
if (context.page.summary?.trim()) {
|
||||
lines.push(`- 页面摘要:${context.page.summary.trim()}`);
|
||||
}
|
||||
if (context.page.publicationUrl) {
|
||||
lines.push(`- 公开地址:${context.page.publicationUrl}`);
|
||||
}
|
||||
if (context.page.contentExcerpt) {
|
||||
lines.push('- 当前正文摘录(供直接修改参考):');
|
||||
lines.push('"""');
|
||||
lines.push(context.page.contentExcerpt);
|
||||
lines.push('"""');
|
||||
}
|
||||
}
|
||||
|
||||
if (context.focusedAsset) {
|
||||
lines.push(
|
||||
`- 当前聚焦资料:${context.focusedAsset.displayName}(${context.focusedAsset.mimeType},id: ${context.focusedAsset.id})`,
|
||||
);
|
||||
}
|
||||
|
||||
if (context.homeCategories?.length) {
|
||||
lines.push('- 空间分类概览:');
|
||||
for (const item of context.homeCategories) {
|
||||
lines.push(` · ${item.name}(${item.code},${item.itemCount ?? 0} 项)`);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.recentPages?.length) {
|
||||
lines.push('- 最近页面(节选):');
|
||||
for (const item of context.recentPages) {
|
||||
lines.push(` · ${item.title}(id: ${item.id},${item.categoryCode},${item.status})`);
|
||||
}
|
||||
}
|
||||
|
||||
lines.push(`- 路径:${context.route}`);
|
||||
lines.push('');
|
||||
lines.push('【定位说明】');
|
||||
lines.push(buildLocationHint(context));
|
||||
lines.push('');
|
||||
lines.push('---');
|
||||
lines.push('');
|
||||
return `${lines.join('\n')}\n`;
|
||||
}
|
||||
|
||||
export function formatContextChip(context) {
|
||||
if (context.page) {
|
||||
const version =
|
||||
typeof context.page.versionNo === 'number' ? ` · v${context.page.versionNo}` : '';
|
||||
return `${context.page.title}${version}`;
|
||||
}
|
||||
if (context.category) {
|
||||
const count =
|
||||
typeof context.category.itemCount === 'number' ? ` · ${context.category.itemCount} 项` : '';
|
||||
return `${context.category.name}${count}`;
|
||||
}
|
||||
return context.spaceName;
|
||||
}
|
||||
|
||||
export const mindspaceChatContextInternals = {
|
||||
stripHtml,
|
||||
excerptContent,
|
||||
};
|
||||
Reference in New Issue
Block a user