|
|
@@ -4,18 +4,18 @@ import { spawnSync } from 'node:child_process';
|
|
|
* A recommended skill to install via `npx skills add`.
|
|
|
*/
|
|
|
export interface RecommendedSkill {
|
|
|
- /** Human-readable name for prompts */
|
|
|
- name: string;
|
|
|
- /** GitHub repo URL for `npx skills add` */
|
|
|
- repo: string;
|
|
|
- /** Skill name within the repo (--skill flag) */
|
|
|
- skillName: string;
|
|
|
- /** List of agents that should auto-allow this skill */
|
|
|
- allowedAgents: string[];
|
|
|
- /** Description shown to user during install */
|
|
|
- description: string;
|
|
|
- /** Optional commands to run after the skill is added */
|
|
|
- postInstallCommands?: string[];
|
|
|
+ /** Human-readable name for prompts */
|
|
|
+ name: string;
|
|
|
+ /** GitHub repo URL for `npx skills add` */
|
|
|
+ repo: string;
|
|
|
+ /** Skill name within the repo (--skill flag) */
|
|
|
+ skillName: string;
|
|
|
+ /** List of agents that should auto-allow this skill */
|
|
|
+ allowedAgents: string[];
|
|
|
+ /** Description shown to user during install */
|
|
|
+ description: string;
|
|
|
+ /** Optional commands to run after the skill is added */
|
|
|
+ postInstallCommands?: string[];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -23,24 +23,24 @@ export interface RecommendedSkill {
|
|
|
* Add new skills here to include them in the installation flow.
|
|
|
*/
|
|
|
export const RECOMMENDED_SKILLS: RecommendedSkill[] = [
|
|
|
- {
|
|
|
- name: 'simplify',
|
|
|
- repo: 'https://github.com/brianlovin/claude-config',
|
|
|
- skillName: 'simplify',
|
|
|
- allowedAgents: ['orchestrator'],
|
|
|
- description: 'YAGNI code simplification expert',
|
|
|
- },
|
|
|
- {
|
|
|
- name: 'agent-browser',
|
|
|
- repo: 'https://github.com/vercel-labs/agent-browser',
|
|
|
- skillName: 'agent-browser',
|
|
|
- allowedAgents: ['designer'],
|
|
|
- description: 'High-performance browser automation',
|
|
|
- postInstallCommands: [
|
|
|
- 'npm install -g agent-browser',
|
|
|
- 'agent-browser install',
|
|
|
- ],
|
|
|
- },
|
|
|
+ {
|
|
|
+ name: 'simplify',
|
|
|
+ repo: 'https://github.com/brianlovin/claude-config',
|
|
|
+ skillName: 'simplify',
|
|
|
+ allowedAgents: ['orchestrator'],
|
|
|
+ description: 'YAGNI code simplification expert',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'agent-browser',
|
|
|
+ repo: 'https://github.com/vercel-labs/agent-browser',
|
|
|
+ skillName: 'agent-browser',
|
|
|
+ allowedAgents: ['designer'],
|
|
|
+ description: 'High-performance browser automation',
|
|
|
+ postInstallCommands: [
|
|
|
+ 'npm install -g agent-browser',
|
|
|
+ 'agent-browser install',
|
|
|
+ ],
|
|
|
+ },
|
|
|
];
|
|
|
|
|
|
/**
|
|
|
@@ -49,42 +49,42 @@ export const RECOMMENDED_SKILLS: RecommendedSkill[] = [
|
|
|
* @returns True if installation succeeded, false otherwise
|
|
|
*/
|
|
|
export function installSkill(skill: RecommendedSkill): boolean {
|
|
|
- const args = [
|
|
|
- 'skills',
|
|
|
- 'add',
|
|
|
- skill.repo,
|
|
|
- '--skill',
|
|
|
- skill.skillName,
|
|
|
- '-a',
|
|
|
- 'opencode',
|
|
|
- '-y',
|
|
|
- '--global',
|
|
|
- ];
|
|
|
+ const args = [
|
|
|
+ 'skills',
|
|
|
+ 'add',
|
|
|
+ skill.repo,
|
|
|
+ '--skill',
|
|
|
+ skill.skillName,
|
|
|
+ '-a',
|
|
|
+ 'opencode',
|
|
|
+ '-y',
|
|
|
+ '--global',
|
|
|
+ ];
|
|
|
|
|
|
- try {
|
|
|
- const result = spawnSync('npx', args, { stdio: 'inherit' });
|
|
|
- if (result.status !== 0) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ try {
|
|
|
+ const result = spawnSync('npx', args, { stdio: 'inherit' });
|
|
|
+ if (result.status !== 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- // Run post-install commands if any
|
|
|
- if (skill.postInstallCommands && skill.postInstallCommands.length > 0) {
|
|
|
- console.log(`Running post-install commands for ${skill.name}...`);
|
|
|
- for (const cmd of skill.postInstallCommands) {
|
|
|
- console.log(`> ${cmd}`);
|
|
|
- const [command, ...cmdArgs] = cmd.split(' ');
|
|
|
- const cmdResult = spawnSync(command, cmdArgs, { stdio: 'inherit' });
|
|
|
- if (cmdResult.status !== 0) {
|
|
|
- console.warn(`Post-install command failed: ${cmd}`);
|
|
|
- }
|
|
|
- }
|
|
|
+ // Run post-install commands if any
|
|
|
+ if (skill.postInstallCommands && skill.postInstallCommands.length > 0) {
|
|
|
+ console.log(`Running post-install commands for ${skill.name}...`);
|
|
|
+ for (const cmd of skill.postInstallCommands) {
|
|
|
+ console.log(`> ${cmd}`);
|
|
|
+ const [command, ...cmdArgs] = cmd.split(' ');
|
|
|
+ const cmdResult = spawnSync(command, cmdArgs, { stdio: 'inherit' });
|
|
|
+ if (cmdResult.status !== 0) {
|
|
|
+ console.warn(`Post-install command failed: ${cmd}`);
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
- } catch (error) {
|
|
|
- console.error(`Failed to install skill: ${skill.name}`, error);
|
|
|
- return false;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`Failed to install skill: ${skill.name}`, error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -94,40 +94,38 @@ export function installSkill(skill: RecommendedSkill): boolean {
|
|
|
* @returns Permission rules for the skill permission type
|
|
|
*/
|
|
|
export function getSkillPermissionsForAgent(
|
|
|
- agentName: string,
|
|
|
- skillList?: string[],
|
|
|
+ agentName: string,
|
|
|
+ skillList?: string[],
|
|
|
): Record<string, 'allow' | 'ask' | 'deny'> {
|
|
|
- // Orchestrator gets all skills by default, others are restricted
|
|
|
- const permissions: Record<string, 'allow' | 'ask' | 'deny'> = {
|
|
|
- '*': agentName === 'orchestrator' ? 'allow' : 'deny',
|
|
|
- };
|
|
|
+ // Orchestrator gets all skills by default, others are restricted
|
|
|
+ const permissions: Record<string, 'allow' | 'ask' | 'deny'> = {
|
|
|
+ '*': agentName === 'orchestrator' ? 'allow' : 'deny',
|
|
|
+ };
|
|
|
|
|
|
- // If the user provided an explicit skill list (even empty), honor it
|
|
|
- if (skillList) {
|
|
|
- permissions['*'] = 'deny';
|
|
|
- for (const name of skillList) {
|
|
|
- if (name === '*') {
|
|
|
- permissions['*'] = 'allow';
|
|
|
- } else if (name.startsWith('!')) {
|
|
|
- permissions[name.slice(1)] = 'deny';
|
|
|
- } else {
|
|
|
- permissions[name] = 'allow';
|
|
|
- }
|
|
|
- }
|
|
|
- return permissions;
|
|
|
+ // If the user provided an explicit skill list (even empty), honor it
|
|
|
+ if (skillList) {
|
|
|
+ permissions['*'] = 'deny';
|
|
|
+ for (const name of skillList) {
|
|
|
+ if (name === '*') {
|
|
|
+ permissions['*'] = 'allow';
|
|
|
+ } else if (name.startsWith('!')) {
|
|
|
+ permissions[name.slice(1)] = 'deny';
|
|
|
+ } else {
|
|
|
+ permissions[name] = 'allow';
|
|
|
+ }
|
|
|
}
|
|
|
+ return permissions;
|
|
|
+ }
|
|
|
|
|
|
- // Otherwise, use recommended defaults
|
|
|
- for (const skill of RECOMMENDED_SKILLS) {
|
|
|
- const isAllowed =
|
|
|
- skill.allowedAgents.includes('*') ||
|
|
|
- skill.allowedAgents.includes(agentName);
|
|
|
- if (isAllowed) {
|
|
|
- permissions[skill.skillName] = 'allow';
|
|
|
- }
|
|
|
+ // Otherwise, use recommended defaults
|
|
|
+ for (const skill of RECOMMENDED_SKILLS) {
|
|
|
+ const isAllowed =
|
|
|
+ skill.allowedAgents.includes('*') ||
|
|
|
+ skill.allowedAgents.includes(agentName);
|
|
|
+ if (isAllowed) {
|
|
|
+ permissions[skill.skillName] = 'allow';
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- return permissions;
|
|
|
+ return permissions;
|
|
|
}
|
|
|
-
|
|
|
-
|