afv-library/scripts/sync-webapp-skills.js

119 lines
4.6 KiB
JavaScript
Raw Permalink Normal View History

feat: syncing webapp skills sync to afv @W-21338965@ (#57) * feat: removing old webapp skills * feat: adding sync of skills from webapps to afv * feat: adding the first iteration of skills * feat: pin template deps to latest npm versions and flatten skill folders - Add pin-template-deps.js to resolve "*" deps to exact npm versions - Integrate pinning into sync-template-skills npm script - Remove check-template-skills-versions.js (no longer needed) - Simplify workflow to single sync step - Flatten skill output: one folder per skill with cleaned names Made-with: Cursor * fix: resolve skill validation errors - Move .template-versions.json from skills/ to root - Shorten skill names to meet 64-char limit: - salesforce-webapp-feature-micro-frontend-generating-micro-frontend-lwc → salesforce-webapp-micro-frontend-lwc - salesforce-webapp-feature-react-agentforce-conversation-client-integrating-agentforce-conversation-client → salesforce-webapp-agentforce-conversation-client - salesforce-webapp-feature-react-file-upload-implementing-file-upload → salesforce-webapp-react-file-upload - Expand descriptions to meet 20-word minimum with trigger context * Add webapp skills from template, sync script updates - Rename skill folders from salesforce-webapp-* to *-webapp-* convention - Update sync-template-skills.js: set SKILL.md front matter name to dest folder - Remove sync-template-skills workflow and pin-template-deps script - Add .synced-template-skills.json manifest, deploying-webapp-to-salesforce skill - Replace salesforce-webapp-designing-webapp-ui-ux with designing-webapp-ui-ux Made-with: Cursor * Align SKILL.md front matter name with folder for all webapp skills Made-with: Cursor * Fix skill validation: description length and trigger context for configuring-webapp-metadata, creating-webapp Made-with: Cursor * Rename sync script to sync-webapp-skills, drop manifest file - Rename sync-template-skills.js to sync-webapp-skills.js - Update package.json script to sync-webapp-skills - Remove .synced-template-skills.json creation and add to .gitignore Made-with: Cursor * Revert sync-react-b2e-sample and sync-react-b2x-sample to upstream version Made-with: Cursor * Sync script: pin b2e and b2x to latest, sync skills from template - Pin both template packages to latest in sync-webapp-skills.js - Update package.json / package-lock.json (b2x 1.109.0) - Sync skills: managing-webapp-agentforce-conversation-client, bar-line-chart, remove building-webapp-analytics-charts and integrating-webapp-agentforce-conversation-client - Minor skill content updates Made-with: Cursor * Remove interactive map, weather widget, and Unsplash skills (no longer in template) Made-with: Cursor --------- Co-authored-by: Hemant Singh Bisht <hsinghbisht@salesforce.com>
2026-03-20 01:16:27 +08:00
#!/usr/bin/env node
/**
* Sync webapp skills: pins b2e and b2x template packages to latest npm versions,
* runs npm install, then copies skills from dist/.a4drules/skills/ into skills/.
* Run from repo root.
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const { copyRecursive } = require('./lib/copy-recursive');
const TEMPLATE_PACKAGES = [
'@salesforce/ui-bundle-template-app-react-sample-b2e',
'@salesforce/ui-bundle-template-app-react-sample-b2x',
feat: syncing webapp skills sync to afv @W-21338965@ (#57) * feat: removing old webapp skills * feat: adding sync of skills from webapps to afv * feat: adding the first iteration of skills * feat: pin template deps to latest npm versions and flatten skill folders - Add pin-template-deps.js to resolve "*" deps to exact npm versions - Integrate pinning into sync-template-skills npm script - Remove check-template-skills-versions.js (no longer needed) - Simplify workflow to single sync step - Flatten skill output: one folder per skill with cleaned names Made-with: Cursor * fix: resolve skill validation errors - Move .template-versions.json from skills/ to root - Shorten skill names to meet 64-char limit: - salesforce-webapp-feature-micro-frontend-generating-micro-frontend-lwc → salesforce-webapp-micro-frontend-lwc - salesforce-webapp-feature-react-agentforce-conversation-client-integrating-agentforce-conversation-client → salesforce-webapp-agentforce-conversation-client - salesforce-webapp-feature-react-file-upload-implementing-file-upload → salesforce-webapp-react-file-upload - Expand descriptions to meet 20-word minimum with trigger context * Add webapp skills from template, sync script updates - Rename skill folders from salesforce-webapp-* to *-webapp-* convention - Update sync-template-skills.js: set SKILL.md front matter name to dest folder - Remove sync-template-skills workflow and pin-template-deps script - Add .synced-template-skills.json manifest, deploying-webapp-to-salesforce skill - Replace salesforce-webapp-designing-webapp-ui-ux with designing-webapp-ui-ux Made-with: Cursor * Align SKILL.md front matter name with folder for all webapp skills Made-with: Cursor * Fix skill validation: description length and trigger context for configuring-webapp-metadata, creating-webapp Made-with: Cursor * Rename sync script to sync-webapp-skills, drop manifest file - Rename sync-template-skills.js to sync-webapp-skills.js - Update package.json script to sync-webapp-skills - Remove .synced-template-skills.json creation and add to .gitignore Made-with: Cursor * Revert sync-react-b2e-sample and sync-react-b2x-sample to upstream version Made-with: Cursor * Sync script: pin b2e and b2x to latest, sync skills from template - Pin both template packages to latest in sync-webapp-skills.js - Update package.json / package-lock.json (b2x 1.109.0) - Sync skills: managing-webapp-agentforce-conversation-client, bar-line-chart, remove building-webapp-analytics-charts and integrating-webapp-agentforce-conversation-client - Minor skill content updates Made-with: Cursor * Remove interactive map, weather widget, and Unsplash skills (no longer in template) Made-with: Cursor --------- Co-authored-by: Hemant Singh Bisht <hsinghbisht@salesforce.com>
2026-03-20 01:16:27 +08:00
];
const PACKAGE_NAME = TEMPLATE_PACKAGES[0]; // used for syncing skills
const SKILLS_SRC = 'dist/.a4drules/skills';
const repoRoot = process.cwd();
const pkgPath = path.join(repoRoot, 'package.json');
const skillsDir = path.join(repoRoot, 'skills');
// ── Pin template packages to latest npm versions ────────────────────
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
let pkgChanged = false;
for (const name of TEMPLATE_PACKAGES) {
const current = (pkg.devDependencies || {})[name];
if (!current || current.startsWith('file:')) continue;
let latest;
try {
latest = execSync(`npm view ${name} version`, { encoding: 'utf8' }).trim();
} catch (_) {
console.warn(`Could not resolve ${name} on npm, using current version.`);
continue;
}
if (current !== latest) {
console.log(`${name}: ${current} -> ${latest}`);
pkg.devDependencies[name] = latest;
pkgChanged = true;
}
}
if (pkgChanged) {
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
}
// ── Install ──────────────────────────────────────────────────────────
console.log('Installing dependencies...');
execSync('npm install', { cwd: repoRoot, stdio: 'inherit' });
// ── Sync skills ──────────────────────────────────────────────────────
const pkgRoot = path.join(repoRoot, 'node_modules', PACKAGE_NAME.replace('/', path.sep));
if (!fs.existsSync(pkgRoot)) {
console.error(`Package not found at ${pkgRoot}.`);
process.exit(1);
}
const srcDir = path.join(pkgRoot, SKILLS_SRC);
if (!fs.existsSync(srcDir)) {
console.error(`Skills not found at ${srcDir}.`);
process.exit(1);
}
if (!fs.existsSync(skillsDir)) fs.mkdirSync(skillsDir, { recursive: true });
function addWebappPrefix(name) {
const parts = name.split('-');
if (parts.length < 2) return name;
if (parts[1] === 'webapp') return name;
return parts[0] + '-webapp-' + parts.slice(1).join('-');
}
/** Dirs in skills/ that look like synced webapp skills (e.g. *-webapp-*, creating-webapp). */
function isSyncedWebappSkillDir(name) {
return name.includes('webapp');
}
/** Set front matter `name` in SKILL.md to match the destination folder name. */
function setSkillFrontMatterName(skillDir, destName) {
const skillPath = path.join(skillDir, 'SKILL.md');
if (!fs.existsSync(skillPath)) return;
let content = fs.readFileSync(skillPath, 'utf8');
content = content.replace(/^name:\s*.+$/m, `name: ${destName}`);
fs.writeFileSync(skillPath, content, 'utf8');
}
// ── Clean up: remove skills no longer in the package ───────────────────
const srcNames = fs.readdirSync(srcDir).filter((name) =>
fs.statSync(path.join(srcDir, name)).isDirectory()
);
const currentDestNames = new Set(srcNames.map(addWebappPrefix));
for (const name of fs.readdirSync(skillsDir)) {
const dirPath = path.join(skillsDir, name);
if (!fs.statSync(dirPath).isDirectory()) continue;
if (!isSyncedWebappSkillDir(name)) continue;
if (currentDestNames.has(name)) continue;
fs.rmSync(dirPath, { recursive: true });
console.log(`Removed skills/${name}/ (no longer in package)`);
}
// ── Copy each skill from package ──────────────────────────────────────
const syncedDirs = [];
for (const srcName of srcNames) {
const src = path.join(srcDir, srcName);
const destName = addWebappPrefix(srcName);
const dest = path.join(skillsDir, destName);
if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true });
copyRecursive(src, dest);
setSkillFrontMatterName(dest, destName);
syncedDirs.push(destName);
console.log(`Synced skills/${destName}/`);
}
const version = JSON.parse(
fs.readFileSync(path.join(pkgRoot, 'package.json'), 'utf8')
).version;
console.log(`Done — synced ${syncedDirs.length} skills from ${PACKAGE_NAME}@${version}.`);