feat: external skills
This commit is contained in:
48
AGENTS.md
48
AGENTS.md
@@ -87,15 +87,61 @@ agents = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Exports:**
|
**Exports:**
|
||||||
|
- `lib.mkOpencodeSkills` — compose custom + external [skills.sh](https://skills.sh) skills into one directory
|
||||||
- `packages.skills-runtime` — composable runtime with all skill dependencies
|
- `packages.skills-runtime` — composable runtime with all skill dependencies
|
||||||
- `devShells.default` — dev environment for working on skills
|
- `devShells.default` — dev environment for working on skills
|
||||||
|
|
||||||
**Mapping** (via home-manager):
|
**Mapping** (via home-manager):
|
||||||
- `skills/`, `context/`, `commands/`, `prompts/` → symlinks
|
- `skills/` → composed via `mkOpencodeSkills` (custom + external merged)
|
||||||
|
- `context/`, `commands/`, `prompts/` → symlinks
|
||||||
- `agents/agents.json` → embedded into config.json
|
- `agents/agents.json` → embedded into config.json
|
||||||
- Agent changes: require `home-manager switch`
|
- Agent changes: require `home-manager switch`
|
||||||
- Other changes: visible immediately
|
- Other changes: visible immediately
|
||||||
|
|
||||||
|
### External Skills (skills.sh)
|
||||||
|
|
||||||
|
This repo supports composing skills from external [skills.sh](https://skills.sh) repositories
|
||||||
|
alongside custom skills. External repos follow the [Agent Skills](https://agentskills.io)
|
||||||
|
standard (same `SKILL.md` format).
|
||||||
|
|
||||||
|
**`lib.mkOpencodeSkills` parameters:**
|
||||||
|
- `pkgs` (required) — nixpkgs package set
|
||||||
|
- `customSkills` (optional) — path to custom skills directory (e.g., `"${inputs.agents}/skills"`)
|
||||||
|
- `externalSkills` (optional) — list of external sources, each with:
|
||||||
|
- `src` — flake input or path to repo root
|
||||||
|
- `skillsDir` — subdirectory containing skills (default: `"skills"`)
|
||||||
|
- `selectSkills` — list of skill names to include (default: all)
|
||||||
|
|
||||||
|
**Collision handling:** Custom skills always win. Among externals, earlier entries take priority.
|
||||||
|
|
||||||
|
**Home-manager example:**
|
||||||
|
```nix
|
||||||
|
inputs = {
|
||||||
|
agents.url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
|
||||||
|
skills-anthropic = { url = "github:anthropics/skills"; flake = false; };
|
||||||
|
};
|
||||||
|
|
||||||
|
xdg.configFile."opencode/skills".source =
|
||||||
|
inputs.agents.lib.mkOpencodeSkills {
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
customSkills = "${inputs.agents}/skills";
|
||||||
|
externalSkills = [
|
||||||
|
{ src = inputs.skills-anthropic; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Project flake example (selective):**
|
||||||
|
```nix
|
||||||
|
".agents/skills".source =
|
||||||
|
inputs.agents.lib.mkOpencodeSkills {
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
externalSkills = [
|
||||||
|
{ src = inputs.skills-anthropic; selectSkills = [ "mcp-builder" ]; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## Rules System
|
## Rules System
|
||||||
|
|
||||||
Centralized AI coding rules consumed via `mkOpencodeRules` from m3ta-nixpkgs:
|
Centralized AI coding rules consumed via `mkOpencodeRules` from m3ta-nixpkgs:
|
||||||
|
|||||||
80
README.md
80
README.md
@@ -67,27 +67,20 @@ This repository is a **Nix flake** that exports:
|
|||||||
|
|
||||||
- **`devShells.default`** — development environment for working on skills (activated via direnv)
|
- **`devShells.default`** — development environment for working on skills (activated via direnv)
|
||||||
- **`packages.skills-runtime`** — composable runtime with all skill script dependencies (Python packages + system tools)
|
- **`packages.skills-runtime`** — composable runtime with all skill script dependencies (Python packages + system tools)
|
||||||
|
- **`lib.mkOpencodeSkills`** — compose custom skills with external [skills.sh](https://skills.sh) skills into a single directory
|
||||||
|
|
||||||
**Consume in your system flake:**
|
**Consume in your system flake:**
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
# flake.nix
|
# flake.nix
|
||||||
inputs.agents = {
|
inputs = {
|
||||||
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
|
agents = {
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
# Optional: add external skill repositories (skills.sh / agentskills.io)
|
||||||
|
skills-anthropic = { url = "github:anthropics/skills"; flake = false; };
|
||||||
};
|
};
|
||||||
|
|
||||||
# In your home-manager module (e.g., opencode.nix)
|
|
||||||
xdg.configFile = {
|
|
||||||
"opencode/skills".source = "${inputs.agents}/skills";
|
|
||||||
"opencode/context".source = "${inputs.agents}/context";
|
|
||||||
"opencode/commands".source = "${inputs.agents}/commands";
|
|
||||||
"opencode/prompts".source = "${inputs.agents}/prompts";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Agent config is embedded into config.json, not deployed as files
|
|
||||||
programs.opencode.settings.agent = builtins.fromJSON
|
|
||||||
(builtins.readFile "${inputs.agents}/agents/agents.json");
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Deploy skills via home-manager:**
|
**Deploy skills via home-manager:**
|
||||||
@@ -95,14 +88,26 @@ programs.opencode.settings.agent = builtins.fromJSON
|
|||||||
```nix
|
```nix
|
||||||
# home-manager module (e.g., opencode.nix)
|
# home-manager module (e.g., opencode.nix)
|
||||||
{ inputs, system, ... }:
|
{ inputs, system, ... }:
|
||||||
{
|
let
|
||||||
# Skill files — symlinked, changes visible immediately
|
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
||||||
xdg.configFile = {
|
in {
|
||||||
"opencode/skills".source = "${inputs.agents}/skills";
|
# Skills — composed from custom + external sources
|
||||||
"opencode/context".source = "${inputs.agents}/context";
|
xdg.configFile."opencode/skills".source =
|
||||||
"opencode/commands".source = "${inputs.agents}/commands";
|
inputs.agents.lib.mkOpencodeSkills {
|
||||||
"opencode/prompts".source = "${inputs.agents}/prompts";
|
inherit pkgs;
|
||||||
};
|
customSkills = "${inputs.agents}/skills";
|
||||||
|
externalSkills = [
|
||||||
|
# Include all skills from anthropics/skills
|
||||||
|
{ src = inputs.skills-anthropic; }
|
||||||
|
# Or cherry-pick specific skills:
|
||||||
|
# { src = inputs.skills-anthropic; selectSkills = [ "mcp-builder" ]; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Other config — symlinked directly
|
||||||
|
xdg.configFile."opencode/context".source = "${inputs.agents}/context";
|
||||||
|
xdg.configFile."opencode/commands".source = "${inputs.agents}/commands";
|
||||||
|
xdg.configFile."opencode/prompts".source = "${inputs.agents}/prompts";
|
||||||
|
|
||||||
# Agent config — embedded into config.json (requires home-manager switch)
|
# Agent config — embedded into config.json (requires home-manager switch)
|
||||||
programs.opencode.settings.agent = builtins.fromJSON
|
programs.opencode.settings.agent = builtins.fromJSON
|
||||||
@@ -113,24 +118,39 @@ programs.opencode.settings.agent = builtins.fromJSON
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Compose into project flakes** (so opencode has skill deps in any project):
|
> **Note**: If you don't use external skills, you can still use the simple form:
|
||||||
|
> ```nix
|
||||||
|
> xdg.configFile."opencode/skills".source = "${inputs.agents}/skills";
|
||||||
|
> ```
|
||||||
|
|
||||||
|
**Compose into project flakes** (project-level skills for a specific repo):
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
# Any project's flake.nix
|
# Any project's flake.nix
|
||||||
{
|
{
|
||||||
inputs.agents.url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
|
inputs = {
|
||||||
inputs.agents.inputs.nixpkgs.follows = "nixpkgs";
|
agents.url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
|
||||||
|
agents.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
skills-anthropic = { url = "github:anthropics/skills"; flake = false; };
|
||||||
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, agents, ... }:
|
outputs = { self, nixpkgs, agents, skills-anthropic, ... }:
|
||||||
let
|
let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
in {
|
in {
|
||||||
|
# Project-level skills (placed in .agents/skills/)
|
||||||
|
".agents/skills".source =
|
||||||
|
agents.lib.mkOpencodeSkills {
|
||||||
|
inherit pkgs;
|
||||||
|
externalSkills = [
|
||||||
|
{ src = skills-anthropic; selectSkills = [ "mcp-builder" ]; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
devShells.${system}.default = pkgs.mkShell {
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
packages = [
|
packages = [
|
||||||
# project-specific tools
|
|
||||||
pkgs.nodejs
|
pkgs.nodejs
|
||||||
# skill script dependencies
|
|
||||||
agents.packages.${system}.skills-runtime
|
agents.packages.${system}.skills-runtime
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@@ -144,6 +164,8 @@ Rebuild:
|
|||||||
home-manager switch
|
home-manager switch
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Collision handling**: When a custom skill and an external skill share the same name, the custom skill always wins. Among external sources, earlier entries in the `externalSkills` list take priority.
|
||||||
|
|
||||||
**Note**: The `agents/` directory is NOT deployed as files. Instead, `agents.json` is read at Nix evaluation time and embedded into the opencode `config.json`.
|
**Note**: The `agents/` directory is NOT deployed as files. Instead, `agents.json` is read at Nix evaluation time and embedded into the opencode `config.json`.
|
||||||
|
|
||||||
#### Option 2: Manual Installation
|
#### Option 2: Manual Installation
|
||||||
|
|||||||
124
flake.nix
124
flake.nix
@@ -7,13 +7,132 @@
|
|||||||
let
|
let
|
||||||
supportedSystems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ];
|
supportedSystems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ];
|
||||||
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||||
|
inherit (nixpkgs) lib;
|
||||||
in {
|
in {
|
||||||
# Composable runtime for project flakes and home-manager.
|
|
||||||
|
# ── Skill composition library ──────────────────────────────────
|
||||||
|
#
|
||||||
|
# Merges custom skills with external skills.sh sources into a
|
||||||
|
# single directory suitable for ~/.config/opencode/skills or
|
||||||
|
# .agents/skills in project flakes.
|
||||||
|
#
|
||||||
|
# Usage (home-manager):
|
||||||
|
# xdg.configFile."opencode/skills".source =
|
||||||
|
# inputs.agents.lib.mkOpencodeSkills {
|
||||||
|
# pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
# customSkills = "${inputs.agents}/skills";
|
||||||
|
# externalSkills = [
|
||||||
|
# { src = inputs.skills-anthropic; }
|
||||||
|
# { src = inputs.skills-vercel; selectSkills = [ "find-skills" ]; }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# Usage (project flake — project-level skills):
|
||||||
|
# ".agents/skills".source =
|
||||||
|
# inputs.agents.lib.mkOpencodeSkills {
|
||||||
|
# pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
# externalSkills = [
|
||||||
|
# { src = inputs.skills-anthropic; selectSkills = [ "mcp-builder" ]; }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# pkgs — nixpkgs package set (required)
|
||||||
|
# customSkills — path to a directory of skill subdirectories (optional)
|
||||||
|
# externalSkills — list of external skill sources (optional, default [])
|
||||||
|
# Each element is an attrset:
|
||||||
|
# src — path to repo root (flake input or local path)
|
||||||
|
# skillsDir — subdirectory containing skills (default "skills")
|
||||||
|
# selectSkills — list of skill names to include (default: all)
|
||||||
|
#
|
||||||
|
# Collision handling:
|
||||||
|
# Custom skills always take priority over external ones.
|
||||||
|
# Among external sources, earlier entries in the list take priority.
|
||||||
|
|
||||||
|
lib.mkOpencodeSkills =
|
||||||
|
{ pkgs
|
||||||
|
, customSkills ? null
|
||||||
|
, externalSkills ? []
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
# Resolve a single external source into a list of { name, path } entries.
|
||||||
|
resolveExternal = entry:
|
||||||
|
let
|
||||||
|
skillsRoot = "${entry.src}/${entry.skillsDir or "skills"}";
|
||||||
|
# List skill subdirectories (each must contain SKILL.md).
|
||||||
|
allSkillDirs = lib.pipe (builtins.readDir skillsRoot) [
|
||||||
|
(lib.filterAttrs (_: type: type == "directory"))
|
||||||
|
(dirs: lib.attrNames dirs)
|
||||||
|
];
|
||||||
|
selected =
|
||||||
|
if entry ? selectSkills
|
||||||
|
then builtins.filter (name: builtins.elem name entry.selectSkills) allSkillDirs
|
||||||
|
else allSkillDirs;
|
||||||
|
in
|
||||||
|
map (name: { inherit name; path = "${skillsRoot}/${name}"; }) selected;
|
||||||
|
|
||||||
|
# Collect all external skills, flattened.
|
||||||
|
allExternal = lib.concatMap resolveExternal externalSkills;
|
||||||
|
|
||||||
|
# Collect custom skill names for collision detection.
|
||||||
|
customSkillNames =
|
||||||
|
if customSkills != null
|
||||||
|
then lib.attrNames (lib.filterAttrs (_: type: type == "directory") (builtins.readDir customSkills))
|
||||||
|
else [];
|
||||||
|
|
||||||
|
# Filter out external skills that collide with custom ones.
|
||||||
|
# Among externals, keep first occurrence (earlier sources win).
|
||||||
|
filterExternals = externals:
|
||||||
|
let
|
||||||
|
go = acc: remaining:
|
||||||
|
if remaining == []
|
||||||
|
then acc.result
|
||||||
|
else
|
||||||
|
let
|
||||||
|
head = builtins.head remaining;
|
||||||
|
tail = builtins.tail remaining;
|
||||||
|
isDuplicate = builtins.elem head.name acc.seen;
|
||||||
|
in
|
||||||
|
if isDuplicate
|
||||||
|
then go acc tail
|
||||||
|
else go {
|
||||||
|
seen = acc.seen ++ [ head.name ];
|
||||||
|
result = acc.result ++ [ head ];
|
||||||
|
} tail;
|
||||||
|
in
|
||||||
|
go { seen = customSkillNames; result = []; } externals;
|
||||||
|
|
||||||
|
filteredExternal = filterExternals allExternal;
|
||||||
|
|
||||||
|
# Build a linkFarm entry for each external skill.
|
||||||
|
externalLinks = map (skill: {
|
||||||
|
name = skill.name;
|
||||||
|
path = skill.path;
|
||||||
|
}) filteredExternal;
|
||||||
|
|
||||||
|
# Build a linkFarm entry for each custom skill.
|
||||||
|
customLinks =
|
||||||
|
if customSkills != null
|
||||||
|
then map (name: {
|
||||||
|
inherit name;
|
||||||
|
path = "${customSkills}/${name}";
|
||||||
|
}) customSkillNames
|
||||||
|
else [];
|
||||||
|
|
||||||
|
in
|
||||||
|
pkgs.linkFarm "opencode-skills" (customLinks ++ externalLinks);
|
||||||
|
|
||||||
|
# ── Composable runtime ─────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Runtime dependencies for skill scripts (Python packages, system
|
||||||
|
# tools). Include in home.packages or project devShells.
|
||||||
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# home.packages = [ inputs.agents.packages.${system}.skills-runtime ];
|
# home.packages = [ inputs.agents.packages.${system}.skills-runtime ];
|
||||||
# devShells.default = pkgs.mkShell {
|
# devShells.default = pkgs.mkShell {
|
||||||
# packages = [ inputs.agents.packages.${system}.skills-runtime ];
|
# packages = [ inputs.agents.packages.${system}.skills-runtime ];
|
||||||
# };
|
# };
|
||||||
|
|
||||||
packages = forAllSystems (system:
|
packages = forAllSystems (system:
|
||||||
let
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
@@ -49,7 +168,8 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
# Dev shell for working on this repo (wraps skills-runtime).
|
# ── Dev shell ──────────────────────────────────────────────────
|
||||||
|
|
||||||
devShells = forAllSystems (system:
|
devShells = forAllSystems (system:
|
||||||
let
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
|||||||
@@ -6,10 +6,15 @@
|
|||||||
# ./scripts/test-skill.sh # List all development skills
|
# ./scripts/test-skill.sh # List all development skills
|
||||||
# ./scripts/test-skill.sh <skill> # Validate specific skill
|
# ./scripts/test-skill.sh <skill> # Validate specific skill
|
||||||
# ./scripts/test-skill.sh --run # Launch interactive opencode session
|
# ./scripts/test-skill.sh --run # Launch interactive opencode session
|
||||||
|
# ./scripts/test-skill.sh --run --external /path/to/skills-repo/skills
|
||||||
#
|
#
|
||||||
# This script creates a temporary XDG_CONFIG_HOME with symlinks to this
|
# This script creates a temporary XDG_CONFIG_HOME with symlinks to this
|
||||||
# repository's skills/, context/, command/, and prompts/ directories,
|
# repository's skills/, context/, command/, and prompts/ directories,
|
||||||
# allowing you to test skill changes before deploying via home-manager.
|
# allowing you to test skill changes before deploying via home-manager.
|
||||||
|
#
|
||||||
|
# The --external flag allows testing with external skills.sh repositories.
|
||||||
|
# Point it to the skills/ subdirectory of a cloned skills.sh repo.
|
||||||
|
# Custom skills take priority over external ones with the same name.
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -21,12 +26,49 @@ GREEN='\033[0;32m'
|
|||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
NC='\033[0m'
|
NC='\033[0m'
|
||||||
|
|
||||||
|
EXTERNAL_SKILLS_DIRS=()
|
||||||
|
|
||||||
setup_test_config() {
|
setup_test_config() {
|
||||||
local tmp_base="${TMPDIR:-/tmp}/opencode-test-$$"
|
local tmp_base="${TMPDIR:-/tmp}/opencode-test-$$"
|
||||||
local tmp_config="$tmp_base/opencode"
|
local tmp_config="$tmp_base/opencode"
|
||||||
|
local tmp_skills="$tmp_config/skills"
|
||||||
|
|
||||||
mkdir -p "$tmp_config"
|
mkdir -p "$tmp_config"
|
||||||
ln -sf "$REPO_ROOT/skills" "$tmp_config/skills"
|
|
||||||
|
if [[ ${#EXTERNAL_SKILLS_DIRS[@]} -gt 0 ]]; then
|
||||||
|
# Merge mode: create a real directory with symlinks to individual skills.
|
||||||
|
# Custom skills take priority (linked first), externals fill gaps.
|
||||||
|
mkdir -p "$tmp_skills"
|
||||||
|
|
||||||
|
# Link custom skills first (they always win).
|
||||||
|
for skill_dir in "$REPO_ROOT/skills/"*/; do
|
||||||
|
local skill_name
|
||||||
|
skill_name=$(basename "$skill_dir")
|
||||||
|
ln -sf "$skill_dir" "$tmp_skills/$skill_name"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Link external skills (skip if name already exists from custom).
|
||||||
|
for ext_dir in "${EXTERNAL_SKILLS_DIRS[@]}"; do
|
||||||
|
if [[ ! -d "$ext_dir" ]]; then
|
||||||
|
echo -e "${RED}❌ External skills directory not found: $ext_dir${NC}" >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
for skill_dir in "$ext_dir/"*/; do
|
||||||
|
[[ -d "$skill_dir" ]] || continue
|
||||||
|
local skill_name
|
||||||
|
skill_name=$(basename "$skill_dir")
|
||||||
|
if [[ ! -e "$tmp_skills/$skill_name" ]]; then
|
||||||
|
ln -sf "$skill_dir" "$tmp_skills/$skill_name"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW} ⚠ Skipping external '$skill_name' (custom takes priority)${NC}" >&2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# Simple mode: symlink entire directory.
|
||||||
|
ln -sf "$REPO_ROOT/skills" "$tmp_skills"
|
||||||
|
fi
|
||||||
|
|
||||||
ln -sf "$REPO_ROOT/context" "$tmp_config/context"
|
ln -sf "$REPO_ROOT/context" "$tmp_config/context"
|
||||||
ln -sf "$REPO_ROOT/commands" "$tmp_config/commands"
|
ln -sf "$REPO_ROOT/commands" "$tmp_config/commands"
|
||||||
ln -sf "$REPO_ROOT/prompts" "$tmp_config/prompts"
|
ln -sf "$REPO_ROOT/prompts" "$tmp_config/prompts"
|
||||||
@@ -48,6 +90,7 @@ usage() {
|
|||||||
echo " --run Launch interactive opencode session with dev skills"
|
echo " --run Launch interactive opencode session with dev skills"
|
||||||
echo " --list List all skills (default if no args)"
|
echo " --list List all skills (default if no args)"
|
||||||
echo " --validate Validate all skills"
|
echo " --validate Validate all skills"
|
||||||
|
echo " --external <path> Add external skills directory (repeatable)"
|
||||||
echo " --help Show this help message"
|
echo " --help Show this help message"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Arguments:"
|
echo "Arguments:"
|
||||||
@@ -58,6 +101,7 @@ usage() {
|
|||||||
echo " $0 task-management # Validate task-management skill"
|
echo " $0 task-management # Validate task-management skill"
|
||||||
echo " $0 --validate # Validate all skills"
|
echo " $0 --validate # Validate all skills"
|
||||||
echo " $0 --run # Launch interactive session"
|
echo " $0 --run # Launch interactive session"
|
||||||
|
echo " $0 --run --external ~/src/anthropics-skills/skills"
|
||||||
}
|
}
|
||||||
|
|
||||||
list_skills() {
|
list_skills() {
|
||||||
@@ -127,25 +171,55 @@ run_opencode() {
|
|||||||
XDG_CONFIG_HOME="$tmp_base" opencode
|
XDG_CONFIG_HOME="$tmp_base" opencode
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main
|
# Main — parse arguments
|
||||||
case "${1:-}" in
|
ACTION=""
|
||||||
--help|-h)
|
SKILL_NAME=""
|
||||||
usage
|
|
||||||
exit 0
|
while [[ $# -gt 0 ]]; do
|
||||||
;;
|
case "$1" in
|
||||||
--run)
|
--help|-h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--run)
|
||||||
|
ACTION="run"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--list)
|
||||||
|
ACTION="list"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--validate)
|
||||||
|
ACTION="validate"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--external)
|
||||||
|
if [[ -z "${2:-}" ]]; then
|
||||||
|
echo -e "${RED}❌ --external requires a path argument${NC}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EXTERNAL_SKILLS_DIRS+=("$2")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
SKILL_NAME="$1"
|
||||||
|
ACTION="validate_one"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
case "${ACTION:-list}" in
|
||||||
|
run)
|
||||||
run_opencode
|
run_opencode
|
||||||
;;
|
;;
|
||||||
--list)
|
list)
|
||||||
list_skills
|
list_skills
|
||||||
;;
|
;;
|
||||||
--validate)
|
validate)
|
||||||
validate_all
|
validate_all
|
||||||
;;
|
;;
|
||||||
"")
|
validate_one)
|
||||||
list_skills
|
validate_skill "$SKILL_NAME"
|
||||||
;;
|
|
||||||
*)
|
|
||||||
validate_skill "$1"
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Reference in New Issue
Block a user