Compare commits
5 Commits
0.2.0
..
12aea0fc26
| Author | SHA1 | Date | |
|---|---|---|---|
|
12aea0fc26
|
|||
|
74cbccc5a8
|
|||
|
b08904586d
|
|||
|
c92a660b86
|
|||
|
5a855183ea
|
@@ -1,8 +1,11 @@
|
|||||||
name: Build
|
name: Build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
push:
|
||||||
types: [published]
|
branches: [main]
|
||||||
|
tags: ["*"]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -61,10 +64,8 @@ jobs:
|
|||||||
tar czf "${{ matrix.archive }}" "${{ matrix.binary }}"
|
tar czf "${{ matrix.archive }}" "${{ matrix.binary }}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload to release
|
- name: Upload artifact
|
||||||
run: |
|
uses: actions/upload-artifact@v4
|
||||||
curl --fail -X POST \
|
with:
|
||||||
-H "Authorization: Bearer ${{ secrets.GITEA_TOKEN }}" \
|
name: ${{ matrix.archive }}
|
||||||
-H "Content-Type: application/octet-stream" \
|
path: target/${{ matrix.target }}/release/${{ matrix.archive }}
|
||||||
--data-binary @"target/${{ matrix.target }}/release/${{ matrix.archive }}" \
|
|
||||||
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${{ github.event.release.id }}/assets?name=${{ matrix.archive }}"
|
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
# Contributing
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://onixbyte.dev/onixbyte/claude-code-skill-manager.git
|
|
||||||
cd claude-code-skill-manager
|
|
||||||
cargo build
|
|
||||||
```
|
|
||||||
|
|
||||||
## Before submitting
|
|
||||||
|
|
||||||
- Run `cargo fmt` to format your code
|
|
||||||
- Run `cargo clippy` and fix any warnings
|
|
||||||
- Ensure `cargo build` succeeds
|
|
||||||
|
|
||||||
## Pull requests
|
|
||||||
|
|
||||||
- Keep changes focused and atomic
|
|
||||||
- Write clear commit messages following the [conventional commits](https://www.conventionalcommits.org/) format
|
|
||||||
- Open PRs against the `main` branch
|
|
||||||
|
|
||||||
## Issues
|
|
||||||
|
|
||||||
Bug reports and feature requests are welcome. Please include steps to reproduce when reporting bugs.
|
|
||||||
|
|
||||||
## Licence
|
|
||||||
|
|
||||||
By contributing, you agree that your contributions will be licensed under the [MIT Licence](LICENCE).
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2025 OnixByte
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
# Claude Code Skill Manager (CCSM)
|
|
||||||
|
|
||||||
A CLI tool for discovering, installing, and managing [Claude Code](https://claude.ai/code) skills from Git-based marketplace repositories.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### From source
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://onixbyte.dev/onixbyte/claude-code-skill-manager.git
|
|
||||||
cd claude-code-skill-manager
|
|
||||||
cargo install --path .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pre-built binaries
|
|
||||||
|
|
||||||
Download the latest binary for your platform from the [Releases](https://onixbyte.dev/onixbyte/claude-code-skill-manager/releases) page.
|
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Register a skill marketplace
|
|
||||||
ccsm marketplace add https://github.com/example/skills
|
|
||||||
|
|
||||||
# Browse available skills
|
|
||||||
ccsm search
|
|
||||||
|
|
||||||
# Install a skill
|
|
||||||
ccsm install my-skill
|
|
||||||
|
|
||||||
# List installed skills
|
|
||||||
ccsm list
|
|
||||||
|
|
||||||
# See details about a skill
|
|
||||||
ccsm info my-skill
|
|
||||||
|
|
||||||
# Update installed skills
|
|
||||||
ccsm update
|
|
||||||
|
|
||||||
# Remove a skill
|
|
||||||
ccsm remove my-skill
|
|
||||||
```
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
### Marketplace management
|
|
||||||
|
|
||||||
| Command | Description |
|
|
||||||
|---|---|
|
|
||||||
| `ccsm marketplace add <url>` | Register a Git repository as a skill marketplace |
|
|
||||||
| `ccsm marketplace remove <name>` | Unregister a marketplace |
|
|
||||||
| `ccsm marketplace list` | List registered marketplaces |
|
|
||||||
| `ccsm marketplace update [name]` | Refresh marketplace manifests |
|
|
||||||
|
|
||||||
### Skill management
|
|
||||||
|
|
||||||
| Command | Description |
|
|
||||||
|---|---|
|
|
||||||
| `ccsm search [query]` | Search available skills across all marketplaces |
|
|
||||||
| `ccsm install <name>` | Install a skill (supports `--copy` and `--link` modes) |
|
|
||||||
| `ccsm list` | Show installed skills |
|
|
||||||
| `ccsm info <name>` | Show details about an installed skill |
|
|
||||||
| `ccsm update [name]` | Update installed skills to latest |
|
|
||||||
| `ccsm remove <name>` | Uninstall a skill |
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
Skills are directories placed under `~/.claude/skills/` that Claude Code reads at startup. CCSM manages these directories by pulling skill definitions from marketplace repositories that expose a `skills.json` manifest:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "My Marketplace",
|
|
||||||
"skills": [
|
|
||||||
{
|
|
||||||
"name": "example-skill",
|
|
||||||
"description": "An example Claude Code skill",
|
|
||||||
"repository": "https://github.com/user/skill-repo",
|
|
||||||
"branch": "main"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deploy modes
|
|
||||||
|
|
||||||
- **Copy** (default): Skill files are physically copied to `~/.claude/skills/<name>/`.
|
|
||||||
- **Link**: A symlink is created from `~/.claude/skills/<name>/` to the local store, useful for development.
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
Cross-compilation targets: Linux (amd64), macOS (amd64), and Windows (amd64) via `cargo-zigbuild`.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
||||||
|
|
||||||
## Licence
|
|
||||||
|
|
||||||
[MIT](LICENCE)
|
|
||||||
@@ -19,8 +19,6 @@ pub struct SkillEntry {
|
|||||||
pub repository: String,
|
pub repository: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub branch: Option<String>,
|
pub branch: Option<String>,
|
||||||
#[serde(default)]
|
|
||||||
pub path: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(url: &str, name: Option<&str>) -> Result<MarketplaceEntry, String> {
|
pub fn add(url: &str, name: Option<&str>) -> Result<MarketplaceEntry, String> {
|
||||||
|
|||||||
+3
-17
@@ -38,20 +38,10 @@ pub fn install(
|
|||||||
let branch = entry.branch.as_deref().unwrap_or("main");
|
let branch = entry.branch.as_deref().unwrap_or("main");
|
||||||
download::download_skill(&entry.repository, branch, &target)?;
|
download::download_skill(&entry.repository, branch, &target)?;
|
||||||
|
|
||||||
let deploy_source = match &entry.path {
|
// Deploy to Claude skills directory (copy or link)
|
||||||
Some(subdir) => {
|
|
||||||
let p = target.join(subdir);
|
|
||||||
if !p.exists() {
|
|
||||||
return Err(format!("Path '{}' not found in skill repository", subdir));
|
|
||||||
}
|
|
||||||
p
|
|
||||||
}
|
|
||||||
None => target.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let config = Config::load().map_err(|e| format!("Cannot read config: {e}"))?;
|
let config = Config::load().map_err(|e| format!("Cannot read config: {e}"))?;
|
||||||
let deploy_mode = mode.unwrap_or_else(|| config.default_mode.clone());
|
let deploy_mode = mode.unwrap_or_else(|| config.default_mode.clone());
|
||||||
deploy_skill(name, &deploy_source, &deploy_mode)?;
|
deploy_skill(name, &target, &deploy_mode)?;
|
||||||
|
|
||||||
Ok(Skill {
|
Ok(Skill {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
@@ -243,16 +233,12 @@ pub fn update(name: Option<&str>) -> Result<Vec<(String, String)>, String> {
|
|||||||
|
|
||||||
match download::download_skill(&skill_entry.repository, branch, &old_path) {
|
match download::download_skill(&skill_entry.repository, branch, &old_path) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
let deploy_source = match &skill_entry.path {
|
|
||||||
Some(subdir) => old_path.join(subdir),
|
|
||||||
None => old_path.clone(),
|
|
||||||
};
|
|
||||||
// Redeploy if previously deployed
|
// Redeploy if previously deployed
|
||||||
if deploy_mode.is_some() || config.default_mode != InstallMode::Copy {
|
if deploy_mode.is_some() || config.default_mode != InstallMode::Copy {
|
||||||
let mode = deploy_mode
|
let mode = deploy_mode
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| config.default_mode.clone());
|
.unwrap_or_else(|| config.default_mode.clone());
|
||||||
match deploy_skill(skill_name, &deploy_source, &mode) {
|
match deploy_skill(skill_name, &old_path, &mode) {
|
||||||
Ok(()) => results.push((skill_name.clone(), "Updated".to_string())),
|
Ok(()) => results.push((skill_name.clone(), "Updated".to_string())),
|
||||||
Err(e) => results.push((skill_name.clone(), format!("Downloaded but deploy failed: {e}"))),
|
Err(e) => results.push((skill_name.clone(), format!("Downloaded but deploy failed: {e}"))),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user