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
+74 -29
View File
@@ -12,6 +12,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
export const PAGE_DATA_COLLECT_SKILL_NAME = 'page-data-collect';
export const EXCEL_ANALYST_SKILL_NAME = 'excel-analyst';
export const IMAGE_GENERATION_SKILL_NAME = 'image-generation';
export const DEFAULT_USER_SKILLS = {
web: true,
@@ -25,6 +26,7 @@ export const DEFAULT_USER_SKILLS = {
'product-campaign-page': true,
'docx-generate': true,
'long-image-download': true,
[IMAGE_GENERATION_SKILL_NAME]: true,
[PAGE_DATA_COLLECT_SKILL_NAME]: true,
[PUBLISH_SKILL_NAME]: false,
};
@@ -214,6 +216,47 @@ function copySkillTree(srcDir, destDir) {
}
}
const SKILL_SYNC_LOCK_RETRY_MS = 25;
const SKILL_SYNC_LOCK_TIMEOUT_MS = 10_000;
const SKILL_SYNC_LOCK_STALE_MS = 60_000;
const skillSyncWaitBuffer = new Int32Array(new SharedArrayBuffer(4));
function withWorkspaceSkillSyncLock(publishDir, callback) {
const agentsRoot = path.join(publishDir, '.agents');
const lockDir = path.join(agentsRoot, '.skills-sync.lock');
fs.mkdirSync(agentsRoot, { recursive: true });
const startedAt = Date.now();
while (true) {
try {
fs.mkdirSync(lockDir);
break;
} catch (error) {
if (error?.code !== 'EEXIST') throw error;
try {
const ageMs = Date.now() - fs.statSync(lockDir).mtimeMs;
if (ageMs > SKILL_SYNC_LOCK_STALE_MS) {
fs.rmSync(lockDir, { recursive: true, force: true });
continue;
}
} catch (statError) {
if (statError?.code === 'ENOENT') continue;
throw statError;
}
if (Date.now() - startedAt >= SKILL_SYNC_LOCK_TIMEOUT_MS) {
throw new Error(`Timed out waiting for workspace skill sync lock: ${publishDir}`);
}
Atomics.wait(skillSyncWaitBuffer, 0, 0, SKILL_SYNC_LOCK_RETRY_MS);
}
}
try {
return callback();
} finally {
fs.rmSync(lockDir, { recursive: true, force: true });
}
}
export function syncSkillsToWorkspace({
h5Root,
publishDir,
@@ -222,38 +265,40 @@ export function syncSkillsToWorkspace({
user,
publicBaseUrl,
}) {
const enabled = new Set(grantedSkillNames(skillMap));
const platformNames = new Set(catalog.map((item) => item.name));
const agentsSkills = path.join(publishDir, '.agents', 'skills');
return withWorkspaceSkillSyncLock(publishDir, () => {
const enabled = new Set(grantedSkillNames(skillMap));
const platformNames = new Set(catalog.map((item) => item.name));
const agentsSkills = path.join(publishDir, '.agents', 'skills');
if (fs.existsSync(agentsSkills)) {
for (const entry of fs.readdirSync(agentsSkills, { withFileTypes: true })) {
if (!entry.isDirectory()) continue;
const skillName = entry.name;
const catalogItem = catalog.find((item) => item.name === skillName || item.dirName === skillName);
const resolvedName = catalogItem?.name ?? skillName;
if (platformNames.has(resolvedName) && !enabled.has(resolvedName)) {
fs.rmSync(path.join(agentsSkills, entry.name), { recursive: true, force: true });
if (fs.existsSync(agentsSkills)) {
for (const entry of fs.readdirSync(agentsSkills, { withFileTypes: true })) {
if (!entry.isDirectory()) continue;
const skillName = entry.name;
const catalogItem = catalog.find((item) => item.name === skillName || item.dirName === skillName);
const resolvedName = catalogItem?.name ?? skillName;
if (platformNames.has(resolvedName) && !enabled.has(resolvedName)) {
fs.rmSync(path.join(agentsSkills, entry.name), { recursive: true, force: true });
}
}
}
}
for (const item of catalog) {
if (!enabled.has(item.name)) continue;
const srcDir = path.join(h5Root, 'skills', item.dirName);
const destDir = path.join(agentsSkills, item.name);
if (item.name === PUBLISH_SKILL_NAME && user) {
ensurePublishSkillInstalled(publishDir, {
slug: String(user.id).trim().toLowerCase(),
username: user.username ? String(user.username).trim().toLowerCase() : undefined,
publicBaseUrl,
publishDir,
});
continue;
for (const item of catalog) {
if (!enabled.has(item.name)) continue;
const srcDir = path.join(h5Root, 'skills', item.dirName);
const destDir = path.join(agentsSkills, item.name);
if (item.name === PUBLISH_SKILL_NAME && user) {
ensurePublishSkillInstalled(publishDir, {
slug: String(user.id).trim().toLowerCase(),
username: user.username ? String(user.username).trim().toLowerCase() : undefined,
publicBaseUrl,
publishDir,
});
continue;
}
if (fs.existsSync(srcDir)) {
if (fs.existsSync(destDir)) fs.rmSync(destDir, { recursive: true, force: true });
copySkillTree(srcDir, destDir);
}
}
if (fs.existsSync(srcDir)) {
if (fs.existsSync(destDir)) fs.rmSync(destDir, { recursive: true, force: true });
copySkillTree(srcDir, destDir);
}
}
});
}