- ローダーがユーザーファイル優先、なければdist/resources/からbuiltinを読む方式に変更 - /ejectコマンドを追加(builtinを~/.takt/にコピーしてカスタマイズ可能に) - /refresh-builtinを簡素化(ejectへの移行案内) - config.yamlにdisabled_builtinsフィールドを追加 - ワークフローYAMLをrules形式に統一
106 lines
3.3 KiB
TypeScript
106 lines
3.3 KiB
TypeScript
/**
|
|
* Embedded resources for takt
|
|
*
|
|
* Contains default workflow definitions and resource paths.
|
|
* Resources are organized into:
|
|
* - resources/global/{lang}/workflows/ - Builtin workflows (loaded via fallback)
|
|
* - resources/global/{lang}/agents/ - Builtin agents (loaded via fallback)
|
|
* - resources/project/ - Project-level template files (.gitignore)
|
|
*/
|
|
|
|
import { readFileSync, readdirSync, existsSync, statSync, mkdirSync, writeFileSync } from 'fs';
|
|
import { join, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import type { Language } from '../models/types.js';
|
|
|
|
/**
|
|
* Get the resources directory path
|
|
* Supports both development (src/) and production (dist/) environments
|
|
*/
|
|
export function getResourcesDir(): string {
|
|
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
// From src/resources or dist/resources, go up to project root then into resources/
|
|
return join(currentDir, '..', '..', 'resources');
|
|
}
|
|
|
|
/**
|
|
* Get the global resources directory path (resources/global/)
|
|
*/
|
|
export function getGlobalResourcesDir(): string {
|
|
return join(getResourcesDir(), 'global');
|
|
}
|
|
|
|
/**
|
|
* Get the project resources directory path (resources/project/)
|
|
*/
|
|
export function getProjectResourcesDir(): string {
|
|
return join(getResourcesDir(), 'project');
|
|
}
|
|
|
|
/**
|
|
* Get the language-specific global resources directory path (resources/global/{lang}/)
|
|
*/
|
|
export function getLanguageResourcesDir(lang: Language): string {
|
|
return join(getGlobalResourcesDir(), lang);
|
|
}
|
|
|
|
/**
|
|
* Copy project resources directory to .takt in project.
|
|
* Only copies files that don't exist in target (e.g., .gitignore).
|
|
*/
|
|
export function copyProjectResourcesToDir(targetDir: string): void {
|
|
const resourcesDir = getProjectResourcesDir();
|
|
if (!existsSync(resourcesDir)) {
|
|
return;
|
|
}
|
|
copyDirRecursive(resourcesDir, targetDir, {
|
|
renameMap: { dotgitignore: '.gitignore' },
|
|
});
|
|
}
|
|
|
|
/** Files to skip during resource copy (OS-generated files) */
|
|
const SKIP_FILES = ['.DS_Store', 'Thumbs.db'];
|
|
|
|
interface CopyOptions {
|
|
/** Directory names to skip at the top level */
|
|
skipDirs?: string[];
|
|
/** Overwrite existing files (default: false) */
|
|
overwrite?: boolean;
|
|
/** Collect copied file paths into this array */
|
|
copiedFiles?: string[];
|
|
/** Rename files during copy (source name → dest name) */
|
|
renameMap?: Record<string, string>;
|
|
}
|
|
|
|
/**
|
|
* Recursively copy directory contents.
|
|
* @param overwrite - If false (default), skips files that already exist in target.
|
|
* If true, overwrites existing files.
|
|
*/
|
|
function copyDirRecursive(srcDir: string, destDir: string, options: CopyOptions = {}): void {
|
|
const { skipDirs = [], overwrite = false, copiedFiles, renameMap } = options;
|
|
|
|
if (!existsSync(destDir)) {
|
|
mkdirSync(destDir, { recursive: true });
|
|
}
|
|
|
|
for (const entry of readdirSync(srcDir)) {
|
|
if (SKIP_FILES.includes(entry)) continue;
|
|
if (skipDirs.includes(entry)) continue;
|
|
|
|
const srcPath = join(srcDir, entry);
|
|
const destName = renameMap?.[entry] ?? entry;
|
|
const destPath = join(destDir, destName);
|
|
const stat = statSync(srcPath);
|
|
|
|
if (stat.isDirectory()) {
|
|
copyDirRecursive(srcPath, destPath, { overwrite, copiedFiles });
|
|
} else if (overwrite || !existsSync(destPath)) {
|
|
const content = readFileSync(srcPath);
|
|
writeFileSync(destPath, content);
|
|
copiedFiles?.push(destPath);
|
|
}
|
|
}
|
|
}
|
|
|