nextlevelbuilder/ui-ux-pro-max-skill · error · Error
Source directory does not exist: ${sourceDir}
Error message
Source directory does not exist: ${sourceDir} What it means
syncDir() refuses to mirror when the source directory doesn't exist. Sources are src/ui-ux-pro-max/{data,scripts,templates} and .claude/skills/<sub-skill> folders. This almost always means the checkout is incomplete — a sparse/partial clone, a shallow CI checkout missing paths, or the script being run outside the standard repo layout.
Source
Thrown at cli/scripts/sync-assets.mjs:126
for (const file of allFiles) {
const sourcePath = join(sourceDir, file);
const targetPath = join(targetDir, file);
if (!sourceFiles.includes(file)) {
drift.push(`extra asset file: ${label}/${file}`);
} else if (!targetFiles.includes(file)) {
drift.push(`missing asset file: ${label}/${file}`);
} else if ((await fileHash(sourcePath)) !== (await fileHash(targetPath))) {
drift.push(`stale asset file: ${label}/${file}`);
}
}
}
// Mirrors sourceDir -> targetDir (deletes targetDir first, so removed
// source files don't linger as orphans in the target).
async function syncDir(sourceDir, targetDir) {
if (!(await exists(sourceDir))) {
throw new Error(`Source directory does not exist: ${sourceDir}`);
}
const resolvedTarget = assertInsideRepo(targetDir);
if (await exists(resolvedTarget)) {
await rm(resolvedTarget, { recursive: true, force: true });
}
for (const file of await listFiles(sourceDir)) {
if (isExcludedAssetFile(file)) continue;
const targetPath = assertInsideRepo(join(resolvedTarget, file));
await mkdir(dirname(targetPath), { recursive: true });
await writeFile(targetPath, toLF(await readFile(join(sourceDir, file), 'utf8')));
}
}
async function checkAssets() {
const drift = [];
View on GitHub (pinned to a38d04c3d5)
Solutions
- Verify the source dir exists: `ls src/ui-ux-pro-max/{data,scripts,templates}` from the repo root.
- If missing, fix the checkout (full clone, un-sparse the paths) — do not create empty dirs to silence the error.
- If a path was renamed, update sourceRoot/dirsToSync/subSkills in cli/scripts/sync-assets.mjs to the new names.
- Ensure new sub-skills have their .claude/skills/<name> directory committed before adding them to the array.
Defensive patterns
Strategy: validation
Validate before calling
// preflight: every source dir the script will sync must exist
import { stat } from 'node:fs/promises';
async function assertDir(p: string, label: string) {
try { await stat(p); } catch {
throw new Error(`Missing source directory ${label} (${p}) - incomplete checkout?`);
}
}
for (const dir of ['data', 'scripts', 'templates']) {
await assertDir(join('src', 'ui-ux-pro-max', dir), `src/ui-ux-pro-max/${dir}`);
} Prevention
- CI should run check:assets/sync:assets only on full (non-sparse) checkouts.
- Commit new sub-skill directories in the same change that adds them to the subSkills array.
- If the src layout is renamed, update sync-assets.mjs constants in the same commit.
When it happens
Trigger: Running `npm run sync:assets` when src/ui-ux-pro-max/ was never checked out (sparse clone, misconfiguration, or the folder renamed); adding a name to the subSkills array whose .claude/skills/<name> directory doesn't exist yet; running the script from a copied cli/ folder without the rest of the repo.
Common situations: Sparse CI checkouts that only fetch cli/; renames of src/ui-ux-pro-max not propagated to sync-assets.mjs; a new sub-skill listed in the array before its directory is committed.
Related errors
- Refusing to modify path outside repository: ${resolvedPath}
- verified-at must use YYYY-MM-DD
- verified-at has suspicious date {value!r}
- catalog-summary.json is missing
AI-assisted analysis of nextlevelbuilder/ui-ux-pro-max-skill@a38d04c3d5 (2026-08-14).
Data as JSON: /api/errors/af17e82404e549f7.
Report an issue: GitHub.