add /refresh-builtin
This commit is contained in:
parent
4671af954a
commit
7270b29044
@ -30,6 +30,7 @@ import {
|
||||
switchWorkflow,
|
||||
switchConfig,
|
||||
addTask,
|
||||
refreshBuiltin,
|
||||
} from './commands/index.js';
|
||||
import { listWorkflows } from './config/workflowLoader.js';
|
||||
import { selectOptionWithDefault } from './prompt/index.js';
|
||||
@ -109,9 +110,13 @@ program
|
||||
await addTask(cwd, args);
|
||||
return;
|
||||
|
||||
case 'refresh-builtin':
|
||||
await refreshBuiltin();
|
||||
return;
|
||||
|
||||
default:
|
||||
error(`Unknown command: /${command}`);
|
||||
info('Available: /run-tasks, /add-task, /switch, /clear, /help, /config');
|
||||
info('Available: /run-tasks, /add-task, /switch, /clear, /refresh-builtin, /help, /config');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,18 +13,20 @@ export function showHelp(): void {
|
||||
|
||||
console.log(`
|
||||
Usage:
|
||||
takt {task} Execute task with current workflow (continues session)
|
||||
takt /run-tasks Run all pending tasks from .takt/tasks/
|
||||
takt /add-task Add a new task (interactive, YAML format)
|
||||
takt /switch Switch workflow interactively
|
||||
takt /clear Clear agent conversation sessions (reset to initial state)
|
||||
takt /help Show this help
|
||||
takt {task} Execute task with current workflow (continues session)
|
||||
takt /run-tasks Run all pending tasks from .takt/tasks/
|
||||
takt /add-task Add a new task (interactive, YAML format)
|
||||
takt /switch Switch workflow interactively
|
||||
takt /clear Clear agent conversation sessions (reset to initial state)
|
||||
takt /refresh-builtin Overwrite builtin agents/workflows with latest version
|
||||
takt /help Show this help
|
||||
|
||||
Examples:
|
||||
takt "Fix the bug in main.ts" # Execute task (continues session)
|
||||
takt /add-task "認証機能を追加する" # Quick add task
|
||||
takt /add-task # Interactive task creation
|
||||
takt /clear # Clear sessions, start fresh
|
||||
takt /refresh-builtin # Update builtin resources
|
||||
takt /switch
|
||||
takt /run-tasks
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
export { executeWorkflow, type WorkflowExecutionResult, type WorkflowExecutionOptions } from './workflowExecution.js';
|
||||
export { executeTask, runAllTasks } from './taskExecution.js';
|
||||
export { addTask } from './addTask.js';
|
||||
export { refreshBuiltin } from './refreshBuiltin.js';
|
||||
export { showHelp } from './help.js';
|
||||
export { withAgentSession } from './session.js';
|
||||
export { switchWorkflow } from './workflow.js';
|
||||
|
||||
43
src/commands/refreshBuiltin.ts
Normal file
43
src/commands/refreshBuiltin.ts
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* /refresh-builtin command implementation
|
||||
*
|
||||
* Overwrites builtin workflow and agent files in ~/.takt/ with the latest
|
||||
* embedded resources. Does NOT touch config.yaml or user-added files.
|
||||
*/
|
||||
|
||||
import { getGlobalConfigDir } from '../config/paths.js';
|
||||
import { getLanguage } from '../config/globalConfig.js';
|
||||
import { forceRefreshLanguageResources } from '../resources/index.js';
|
||||
import { header, success, info, error } from '../utils/ui.js';
|
||||
import { createLogger } from '../utils/debug.js';
|
||||
|
||||
const log = createLogger('refresh-builtin');
|
||||
|
||||
/**
|
||||
* Refresh builtin agents and workflows to latest version.
|
||||
*/
|
||||
export async function refreshBuiltin(): Promise<void> {
|
||||
const globalDir = getGlobalConfigDir();
|
||||
const lang = getLanguage();
|
||||
|
||||
header('Refresh Builtin Resources');
|
||||
info(`Language: ${lang}`);
|
||||
info(`Target: ${globalDir}`);
|
||||
|
||||
try {
|
||||
const overwritten = forceRefreshLanguageResources(globalDir, lang);
|
||||
|
||||
log.info('Builtin resources refreshed', { count: overwritten.length, lang });
|
||||
|
||||
console.log();
|
||||
success(`${overwritten.length} files refreshed.`);
|
||||
|
||||
for (const filePath of overwritten) {
|
||||
info(` ✓ ${filePath}`);
|
||||
}
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
log.error('Failed to refresh builtin resources', { error: message });
|
||||
error(`Failed to refresh: ${message}`);
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ export function copyGlobalResourcesToDir(targetDir: string): void {
|
||||
return;
|
||||
}
|
||||
// Skip language directories (they are handled by copyLanguageResourcesToDir)
|
||||
copyDirRecursive(resourcesDir, targetDir, ['en', 'ja']);
|
||||
copyDirRecursive(resourcesDir, targetDir, { skipDirs: ['en', 'ja'] });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,24 +106,62 @@ export function copyLanguageResourcesToDir(targetDir: string, lang: Language): v
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force-refresh language-specific resources (agents and workflows) to ~/.takt.
|
||||
* Overwrites existing builtin files. Does NOT touch config.yaml.
|
||||
*/
|
||||
export function forceRefreshLanguageResources(targetDir: string, lang: Language): string[] {
|
||||
const langDir = getLanguageResourcesDir(lang);
|
||||
if (!existsSync(langDir)) {
|
||||
throw new Error(`Language resources not found: ${langDir}`);
|
||||
}
|
||||
|
||||
const copiedFiles: string[] = [];
|
||||
const forceOptions = { overwrite: true, copiedFiles };
|
||||
|
||||
// Overwrite agents directory
|
||||
const langAgentsDir = join(langDir, 'agents');
|
||||
const targetAgentsDir = join(targetDir, 'agents');
|
||||
if (existsSync(langAgentsDir)) {
|
||||
copyDirRecursive(langAgentsDir, targetAgentsDir, forceOptions);
|
||||
}
|
||||
|
||||
// Overwrite workflows directory
|
||||
const langWorkflowsDir = join(langDir, 'workflows');
|
||||
const targetWorkflowsDir = join(targetDir, 'workflows');
|
||||
if (existsSync(langWorkflowsDir)) {
|
||||
copyDirRecursive(langWorkflowsDir, targetWorkflowsDir, forceOptions);
|
||||
}
|
||||
|
||||
return copiedFiles;
|
||||
}
|
||||
|
||||
/** 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[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively copy directory contents.
|
||||
* Skips files that already exist in target.
|
||||
* @param skipDirs - Directory names to skip at top level
|
||||
* @param overwrite - If false (default), skips files that already exist in target.
|
||||
* If true, overwrites existing files.
|
||||
*/
|
||||
function copyDirRecursive(srcDir: string, destDir: string, skipDirs: string[] = []): void {
|
||||
function copyDirRecursive(srcDir: string, destDir: string, options: CopyOptions = {}): void {
|
||||
const { skipDirs = [], overwrite = false, copiedFiles } = options;
|
||||
|
||||
if (!existsSync(destDir)) {
|
||||
mkdirSync(destDir, { recursive: true });
|
||||
}
|
||||
|
||||
for (const entry of readdirSync(srcDir)) {
|
||||
// Skip OS-generated files
|
||||
if (SKIP_FILES.includes(entry)) continue;
|
||||
|
||||
// Skip specified directories
|
||||
if (skipDirs.includes(entry)) continue;
|
||||
|
||||
const srcPath = join(srcDir, entry);
|
||||
@ -131,11 +169,11 @@ function copyDirRecursive(srcDir: string, destDir: string, skipDirs: string[] =
|
||||
const stat = statSync(srcPath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
copyDirRecursive(srcPath, destPath);
|
||||
} else if (!existsSync(destPath)) {
|
||||
// Only copy if file doesn't exist
|
||||
copyDirRecursive(srcPath, destPath, { overwrite, copiedFiles });
|
||||
} else if (overwrite || !existsSync(destPath)) {
|
||||
const content = readFileSync(srcPath);
|
||||
writeFileSync(destPath, content);
|
||||
copiedFiles?.push(destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user