fix: include bundled skills/ dir in skills status and sync discovery (#461)
This commit is contained in:
@@ -335,11 +335,18 @@ async function main() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'skills': {
|
case 'skills': {
|
||||||
const { showStatus, runSkillsSync } = await import('./skills/index.js');
|
const { showStatus, runSkillsSync, enableSkill } = await import('./skills/index.js');
|
||||||
switch (subCommand) {
|
switch (subCommand) {
|
||||||
case 'status':
|
case 'status':
|
||||||
await showStatus();
|
await showStatus();
|
||||||
break;
|
break;
|
||||||
|
case 'enable':
|
||||||
|
if (!args[2]) {
|
||||||
|
console.error('Usage: lettabot skills enable <name>');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
enableSkill(args[2]);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
await runSkillsSync();
|
await runSkillsSync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
import { existsSync, readdirSync, cpSync, mkdirSync, rmSync } from 'node:fs';
|
import { existsSync, readdirSync, cpSync, mkdirSync, rmSync } from 'node:fs';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import * as p from '@clack/prompts';
|
import * as p from '@clack/prompts';
|
||||||
import { PROJECT_SKILLS_DIR, GLOBAL_SKILLS_DIR, SKILLS_SH_DIR, parseSkillFile } from './loader.js';
|
import { PROJECT_SKILLS_DIR, BUNDLED_SKILLS_DIR, GLOBAL_SKILLS_DIR, SKILLS_SH_DIR, parseSkillFile } from './loader.js';
|
||||||
|
|
||||||
const HOME = process.env.HOME || process.env.USERPROFILE || '';
|
const HOME = process.env.HOME || process.env.USERPROFILE || '';
|
||||||
const WORKING_DIR = process.env.WORKING_DIR || '/tmp/lettabot';
|
const WORKING_DIR = process.env.WORKING_DIR || '/tmp/lettabot';
|
||||||
@@ -68,10 +68,12 @@ function discoverSkills(): SkillInfo[] {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Discover from all sources (order matters - first source wins for duplicates)
|
// Discover from all sources (order matters - first source wins for duplicates).
|
||||||
|
// Priority matches the loader hierarchy: project (.skills/) > bundled (skills/) > external.
|
||||||
|
addFromDir(PROJECT_SKILLS_DIR, 'builtin'); // .skills/ project overrides
|
||||||
|
addFromDir(BUNDLED_SKILLS_DIR, 'builtin'); // skills/ bundled with repo
|
||||||
addFromDir(CLAWDHUB_DIR, 'clawdhub');
|
addFromDir(CLAWDHUB_DIR, 'clawdhub');
|
||||||
addFromDir(VERCEL_DIR, 'vercel');
|
addFromDir(VERCEL_DIR, 'vercel');
|
||||||
addFromDir(PROJECT_SKILLS_DIR, 'builtin');
|
|
||||||
|
|
||||||
return skills.sort((a, b) => a.name.localeCompare(b.name));
|
return skills.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
}
|
}
|
||||||
@@ -218,3 +220,32 @@ export async function runSkillsSync(): Promise<void> {
|
|||||||
p.log.info(`Skills directory: ${TARGET_DIR}`);
|
p.log.info(`Skills directory: ${TARGET_DIR}`);
|
||||||
p.outro(`✨ Added ${toAdd.length}, removed ${toRemove.length} skill(s)`);
|
p.outro(`✨ Added ${toAdd.length}, removed ${toRemove.length} skill(s)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-interactively enable a single skill by name.
|
||||||
|
* Searches BUNDLED_SKILLS_DIR, then GLOBAL_SKILLS_DIR, then SKILLS_SH_DIR.
|
||||||
|
*/
|
||||||
|
export function enableSkill(name: string): void {
|
||||||
|
// Search order: highest priority first (project local > global > bundled > skills.sh)
|
||||||
|
const sourceDirs = [PROJECT_SKILLS_DIR, GLOBAL_SKILLS_DIR, BUNDLED_SKILLS_DIR, SKILLS_SH_DIR];
|
||||||
|
|
||||||
|
mkdirSync(TARGET_DIR, { recursive: true });
|
||||||
|
|
||||||
|
const dest = join(TARGET_DIR, name);
|
||||||
|
if (existsSync(dest)) {
|
||||||
|
console.log(`Skill '${name}' is already enabled.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const dir of sourceDirs) {
|
||||||
|
const src = join(dir, name);
|
||||||
|
if (existsSync(src) && existsSync(join(src, 'SKILL.md'))) {
|
||||||
|
cpSync(src, dest, { recursive: true });
|
||||||
|
console.log(`Enabled skill '${name}' from ${dir}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`Skill '${name}' not found. Run 'lettabot skills status' to see available skills.`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as p from '@clack/prompts';
|
|||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import { getSkillsSummary, type SkillsSummary } from './status.js';
|
import { getSkillsSummary, type SkillsSummary } from './status.js';
|
||||||
import { installSkillDeps } from './install.js';
|
import { installSkillDeps } from './install.js';
|
||||||
import { hasBinary, GLOBAL_SKILLS_DIR, SKILLS_SH_DIR } from './loader.js';
|
import { hasBinary, BUNDLED_SKILLS_DIR, GLOBAL_SKILLS_DIR, SKILLS_SH_DIR } from './loader.js';
|
||||||
import type { NodeManager, SkillStatus } from './types.js';
|
import type { NodeManager, SkillStatus } from './types.js';
|
||||||
|
|
||||||
import { createLogger } from '../logger.js';
|
import { createLogger } from '../logger.js';
|
||||||
@@ -261,7 +261,7 @@ export async function listSkills(): Promise<void> {
|
|||||||
*/
|
*/
|
||||||
export async function showStatus(): Promise<void> {
|
export async function showStatus(): Promise<void> {
|
||||||
const enabledSummary = getSkillsSummary([WORKING_SKILLS_DIR]);
|
const enabledSummary = getSkillsSummary([WORKING_SKILLS_DIR]);
|
||||||
const availableSummary = getSkillsSummary([GLOBAL_SKILLS_DIR, SKILLS_SH_DIR]);
|
const availableSummary = getSkillsSummary([BUNDLED_SKILLS_DIR, GLOBAL_SKILLS_DIR, SKILLS_SH_DIR]);
|
||||||
|
|
||||||
// Get names of enabled skills to filter available
|
// Get names of enabled skills to filter available
|
||||||
const enabledNames = new Set(enabledSummary.skills.map(s => s.skill.name));
|
const enabledNames = new Set(enabledSummary.skills.map(s => s.skill.name));
|
||||||
@@ -297,6 +297,6 @@ export async function showStatus(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.info('');
|
log.info('');
|
||||||
log.info(` To enable: lettabot skills enable <name>`);
|
log.info(` To enable: lettabot skills enable <name> (or run: lettabot skills)`);
|
||||||
log.info(` Skills dir: ${WORKING_SKILLS_DIR}`);
|
log.info(` Skills dir: ${WORKING_SKILLS_DIR}`);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user