Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
One-time setup that gathers your project's design context and saves it to CLAUDE.md for future sessions.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/impeccable-paths.mjs
1import fs from 'node:fs';2import path from 'node:path';34export const IMPECCABLE_DIR = '.impeccable';5export const LIVE_DIR = 'live';67export function getImpeccableDir(cwd = process.cwd()) {8return path.join(cwd, IMPECCABLE_DIR);9}1011export function getDesignSidecarPath(cwd = process.cwd()) {12return path.join(getImpeccableDir(cwd), 'design.json');13}1415export function getDesignSidecarCandidates(cwd = process.cwd(), contextDir = cwd) {16const candidates = [17getDesignSidecarPath(cwd),18path.join(cwd, 'DESIGN.json'),19];20const contextLegacy = path.join(contextDir, 'DESIGN.json');21if (!candidates.includes(contextLegacy)) candidates.push(contextLegacy);22return candidates;23}2425export function resolveDesignSidecarPath(cwd = process.cwd(), contextDir = cwd) {26return firstExisting(getDesignSidecarCandidates(cwd, contextDir));27}2829export function getLiveDir(cwd = process.cwd()) {30return path.join(getImpeccableDir(cwd), LIVE_DIR);31}3233export function getLiveConfigPath(cwd = process.cwd()) {34return path.join(getLiveDir(cwd), 'config.json');35}3637export function getLegacyLiveConfigPath(scriptsDir) {38return path.join(scriptsDir, 'config.json');39}4041export function resolveLiveConfigPath({ cwd = process.cwd(), scriptsDir, env = process.env } = {}) {42if (env.IMPECCABLE_LIVE_CONFIG && env.IMPECCABLE_LIVE_CONFIG.trim()) {43const configured = env.IMPECCABLE_LIVE_CONFIG.trim();44return path.isAbsolute(configured) ? configured : path.resolve(cwd, configured);45}46const primary = getLiveConfigPath(cwd);47if (fs.existsSync(primary)) return primary;48if (scriptsDir) {49const legacy = getLegacyLiveConfigPath(scriptsDir);50if (fs.existsSync(legacy)) return legacy;51}52return primary;53}5455export function getLiveServerPath(cwd = process.cwd()) {56return path.join(getLiveDir(cwd), 'server.json');57}5859export function getLegacyLiveServerPath(cwd = process.cwd()) {60return path.join(cwd, '.impeccable-live.json');61}6263export function readLiveServerInfo(cwd = process.cwd()) {64for (const filePath of [getLiveServerPath(cwd), getLegacyLiveServerPath(cwd)]) {65try {66return { info: JSON.parse(fs.readFileSync(filePath, 'utf-8')), path: filePath };67} catch {68/* try next */69}70}71return null;72}7374export function writeLiveServerInfo(cwd = process.cwd(), info) {75const filePath = getLiveServerPath(cwd);76fs.mkdirSync(path.dirname(filePath), { recursive: true });77fs.writeFileSync(filePath, JSON.stringify(info));78return filePath;79}8081export function removeLiveServerInfo(cwd = process.cwd()) {82for (const filePath of [getLiveServerPath(cwd), getLegacyLiveServerPath(cwd)]) {83try { fs.unlinkSync(filePath); } catch {}84}85}8687export function getLiveSessionsDir(cwd = process.cwd()) {88return path.join(getLiveDir(cwd), 'sessions');89}9091export function getLegacyLiveSessionsDir(cwd = process.cwd()) {92return path.join(cwd, '.impeccable-live', 'sessions');93}9495export function getLiveAnnotationsDir(cwd = process.cwd()) {96return path.join(getLiveDir(cwd), 'annotations');97}9899export function getLegacyLiveAnnotationsDir(cwd = process.cwd()) {100return path.join(cwd, '.impeccable-live', 'annotations');101}102103function firstExisting(paths) {104return paths.find((filePath) => fs.existsSync(filePath)) || null;105}106