feat(image): complete reviewed generation delivery
Memind CI / Test, build, and release guards (pull_request) Successful in 2m47s
Memind CI / Test, build, and release guards (pull_request) Successful in 2m47s
This commit is contained in:
+74
-29
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user