feat(image): complete reviewed generation delivery
Memind CI / Test, build, and release guards (pull_request) Successful in 2m47s

This commit is contained in:
john
2026-07-20 20:04:44 +08:00
parent fc3d27aae0
commit 4b15610aa8
42 changed files with 1764 additions and 97 deletions
+12 -8
View File
@@ -175,7 +175,7 @@ description: 在专属 MindSpace 目录生成可公开访问的静态 HTML 报
\`${publicBaseUrl}/${PUBLISH_ROOT_DIR}/${slug}/public/<文件名>\`
(写入 \`public/页面.html\` 时 URL **必须**含 \`public/\`;仅当 HTML 直接写在 workspace 根目录时才省略)
7. **只要页面接收用户输入并要求以后查看、汇总、统计、修改或删除,就不是纯静态页**。禁止使用 \`localStorage\` / \`sessionStorage\` / \`IndexedDB\` 保存任何数据;必须立即 \`load_skill\`\`page-data-collect\`,通过 Page Data API 写入当前用户专属 PostgreSQL schema。禁止 SQLite、静态 JSON/JS 文件或内存 fallback 冒充持久化。记账、日记、打卡、清单、台账、问卷、报名及其管理页都适用。
8. 当编排提示为“图片策略:强制生成”或用户明确要求新图片、背景图、主图、封面、插画、照片时,必须先调用 \`sandbox-fs__generate_image\`不得用 SVG、CSS 绘图、旧素材或网页搜索图片冒充本次生成结果。
8. 当编排提示为“图片策略:强制生成”或用户明确要求新图片、背景图、主图、封面、插画、照片时,必须先 \`load_skill\`\`image-generation\`,由该技能自动补齐主体、场景、构图、光线和负面约束,再调用 \`sandbox-fs__generate_image\`;不得要求用户自己提供专业生图参数,不得用 SVG、CSS 绘图、旧素材或网页搜索图片冒充本次生成结果。
## 推荐工作流
@@ -191,10 +191,11 @@ description: 在专属 MindSpace 目录生成可公开访问的静态 HTML 报
## AI 图片生成(按意图与用户选择)
- 调用前必须先 \`load_skill\`\`image-generation\`;用户只需描述主题与感觉,其余专业提示词由该技能补齐
- **强制生成**:页面主图优先只调用一次 \`generate_image(purpose=hero)\`;卡片封面和信息流缩略图必须复用这张主图裁剪派生,hero 成功后禁止再调用 \`card_cover\` / \`feed_cover\`
- 只有后台关闭 \`hero\`、且任务确实只需要某一种封面时,才允许改用一次 \`card_cover\`\`feed_cover\`;正文配图 \`inline_image\` 仅在后台开启且正文确有需要时单独生成
- 成功结果必须满足 \`ok=true\`、包含 \`jobId\`,且 \`source.mimeType\`\`image/png\`\`image/jpeg\`\`image/webp\`
- HTML 的 \`<img>\`、背景图及 \`mindspace-cover.cover\` 必须引用本次返回的 \`asset.publicUrl\` 或对应工作区相对路径;页面主图默认同时作为缩略图源图
- HTML 的 \`<img>\`、背景图及 \`mindspace-cover.cover\` 必须引用本次返回的 \`asset.htmlSrc\`\`workspaceRelativePath\` 只用于工作区文件操作,禁止直接写入 HTML。页面主图默认同时作为缩略图源图
- **自动**:只在用户需求确实需要新主图、背景图、正文配图或封面时调用
- **关闭**:禁止调用 \`generate_image\`
- 强制生成失败时必须如实报告,禁止静默改用 SVG/旧图后宣称图片生成完成
@@ -335,6 +336,7 @@ ${renderBrandingBlock(addressName)}
## 生成 / 发布 HTML 页面
- 用户要网页、交互应用或分享链接时,必须使用 对应 skill 并将最终 HTML 写入 \`public/*.html\`
- \`generate_image\` 成功后,HTML 的图片与背景只能使用返回的 \`asset.htmlSrc\`\`workspaceRelativePath\` 只用于文件操作,禁止直接写入 HTML
- 若页面接收用户输入并需要保存、查询、统计、修改或删除,必须使用 \`page-data-collect\` + Page Data API,禁止 localStorage / sessionStorage / IndexedDB
- \`apps__create_app\` 只能用于设计预览,不是 H5 交付物;使用后仍必须写入 \`public/*.html\` 并返回真实可访问链接
- 未验证文件已落盘且链接可访问前,禁止声称「已创建」「已打开」或「可在 Apps 标签找到」
@@ -396,6 +398,7 @@ export function buildSandboxSessionConstraints({ baseConstraints, developerTools
'## 生成 / 发布 HTML 页面',
'- 你有 write_file/edit_file 工具:**必须由你**写入 `public/xxx.html`(或工作区根目录 `.html`',
'- 开始前执行 load_skill → `static-page-publish`,按技能说明写入 mindspace-cover 元数据',
'- `generate_image` 成功后,HTML 的图片与背景只能使用返回的 `asset.htmlSrc``workspaceRelativePath` 只用于文件操作,禁止直接写入 HTML',
'- 默认只生成 HTML;不要在没有明确需求时强制生成 Word、PDF、长图等伴生文件',
'- 只有用户明确要求 Word / docx 下载时:先 `load_skill` → `docx-generate`,生成并确认 `public/*.docx` 已存在,再写 HTML 用相对路径链接',
'- 只有用户明确要求长图下载时:先 `load_skill` → `long-image-download`,调用 `generate_long_image` 生成并确认 `public/*.long.png` 已存在,再回复长图预览与下载链接',
@@ -467,18 +470,19 @@ export function ensureWorkspaceHintsInstalled(publishDir, context) {
export function ensureDocxSkillInstalled(publishDir) {
if (!fs.existsSync(DOCX_SKILL_DIR)) return null;
const skillRoot = path.join(publishDir, '.agents', 'skills', DOCX_SKILL_NAME);
fs.rmSync(skillRoot, { recursive: true, force: true });
fs.mkdirSync(path.dirname(skillRoot), { recursive: true });
fs.cpSync(DOCX_SKILL_DIR, skillRoot, { recursive: true });
// Multiple local H5 processes can bootstrap the same user workspace at once.
// Copy in place so one process never removes a directory while another is
// traversing it. Bundled skill files are overwritten deterministically.
fs.mkdirSync(skillRoot, { recursive: true });
fs.cpSync(DOCX_SKILL_DIR, skillRoot, { recursive: true, force: true });
return path.join(skillRoot, 'SKILL.md');
}
export function ensureLongImageSkillInstalled(publishDir) {
if (!fs.existsSync(LONG_IMAGE_SKILL_DIR)) return null;
const skillRoot = path.join(publishDir, '.agents', 'skills', LONG_IMAGE_SKILL_NAME);
fs.rmSync(skillRoot, { recursive: true, force: true });
fs.mkdirSync(path.dirname(skillRoot), { recursive: true });
fs.cpSync(LONG_IMAGE_SKILL_DIR, skillRoot, { recursive: true });
fs.mkdirSync(skillRoot, { recursive: true });
fs.cpSync(LONG_IMAGE_SKILL_DIR, skillRoot, { recursive: true, force: true });
return path.join(skillRoot, 'SKILL.md');
}