Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1

permissions:
contents: write

jobs:
verify-version:
name: Verify Version
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,5 @@ commondir
gitdir
index
.newton
CLAUDE.md
CLAUDE.md
repomix-output.xml
9 changes: 9 additions & 0 deletions .repomixignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Add patterns to ignore here, one per line
# Example:
# *.log
# tmp/
*.md
*.lcov
webdocs
tests
.github
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

91 changes: 70 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,34 @@ For detailed Kubernetes deployment instructions, see the [Kubernetes Deployment

### 1. Configure FastSkill

Create `.fastskill.yaml` in your project root:
Create `skill-project.toml` in your project root:

```yaml
embedding:
openai_base_url: "https://api.openai.com/v1"
embedding_model: "text-embedding-3-small"
```toml
[metadata]
id = "my-project"
version = "1.0.0"

[dependencies]
# Add skill dependencies here

[tool.fastskill]
skills_directory = ".claude/skills"

[tool.fastskill.embedding]
openai_base_url = "https://api.openai.com/v1"
embedding_model = "text-embedding-3-small"

[[tool.fastskill.repositories]]
name = "anthropic"
type = "git-marketplace"
url = "https://github.com/anthropics/skills"
priority = 0
```

Or use the init command:

```bash
fastskill init
```

Set your OpenAI API key:
Expand Down Expand Up @@ -241,39 +263,66 @@ FastSkill provides a unified repository system for managing all skill storage lo
- **ZIP URL sources** (static hosting with marketplace.json)
- **Local folders** (for development)

All repository types are configured in `.claude/repositories.toml` (or automatically loaded from `sources.toml` and `registries.toml` for backward compatibility).
All repository types are configured in `skill-project.toml` under `[[tool.fastskill.repositories]]`.

For detailed repository setup, usage, and management instructions, see [docs/REGISTRY.md](docs/REGISTRY.md).

## Configuration

Create `.fastskill.yaml` in your project root:
FastSkill uses `skill-project.toml` as the unified configuration file for both project-level and skill-level contexts.

### skill-project.toml Structure

```toml
[metadata]
id = "my-skill"
version = "1.0.0"

```yaml
embedding:
openai_base_url: "https://api.openai.com/v1"
embedding_model: "text-embedding-3-small"
[dependencies]
# Add your skill dependencies here

# Optional: Custom skills directory
skills_directory: ".claude/skills"
[tool.fastskill]
skills_directory = ".claude/skills"

[tool.fastskill.embedding]
openai_base_url = "https://api.openai.com/v1"
embedding_model = "text-embedding-3-small"

[[tool.fastskill.repositories]]
name = "anthropic"
type = "git-marketplace"
url = "https://github.com/anthropics/skills"
priority = 0
```

The CLI resolves the skills directory using this priority:
### Configuration Resolution

The CLI resolves configuration from `skill-project.toml`:

1. Searches current directory and parents for `skill-project.toml`
2. Extracts `[tool.fastskill]` section for skills directory and embedding config
3. Extracts `[tool.fastskill.repositories]` for repository sources
4. Defaults to `.claude/skills/` if no skills_directory is configured

### Quick Setup

1. `skills_directory` from `.fastskill.yaml`
2. Walk up directory tree to find existing `.claude/skills/`
3. Default to `.claude/skills/` in current directory (doesn't auto-create)
```bash
# Initialize a new project
fastskill init

# Set OpenAI API key for semantic search
export OPENAI_API_KEY="your-key-here"
```

## Troubleshooting

### Configuration Not Found

If you see "Embedding configuration required but not found":

1. Create `.fastskill.yaml` with embedding configuration (see Quick Start section)
2. Set `OPENAI_API_KEY` environment variable

**Note**: The error message may mention `fastskill init`, but that command is for skill authors only. For project setup, manually create `.fastskill.yaml` as shown in Quick Start.
1. Run `fastskill init` to create `skill-project.toml`
2. Add `[tool.fastskill.embedding]` section with embedding configuration
3. Set `OPENAI_API_KEY` environment variable

### API Key Issues

Expand Down
99 changes: 99 additions & 0 deletions coverage-after/html/control.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@

function next_uncovered(selector, reverse, scroll_selector) {
function visit_element(element) {
element.classList.add("seen");
element.classList.add("selected");

if (!scroll_selector) {
scroll_selector = "tr:has(.selected) td.line-number"
}

const scroll_to = document.querySelector(scroll_selector);
if (scroll_to) {
scroll_to.scrollIntoView({behavior: "smooth", block: "center", inline: "end"});
}
}

function select_one() {
if (!reverse) {
const previously_selected = document.querySelector(".selected");

if (previously_selected) {
previously_selected.classList.remove("selected");
}

return document.querySelector(selector + ":not(.seen)");
} else {
const previously_selected = document.querySelector(".selected");

if (previously_selected) {
previously_selected.classList.remove("selected");
previously_selected.classList.remove("seen");
}

const nodes = document.querySelectorAll(selector + ".seen");
if (nodes) {
const last = nodes[nodes.length - 1]; // last
return last;
} else {
return undefined;
}
}
}

function reset_all() {
if (!reverse) {
const all_seen = document.querySelectorAll(selector + ".seen");

if (all_seen) {
all_seen.forEach(e => e.classList.remove("seen"));
}
} else {
const all_seen = document.querySelectorAll(selector + ":not(.seen)");

if (all_seen) {
all_seen.forEach(e => e.classList.add("seen"));
}
}

}

const uncovered = select_one();

if (uncovered) {
visit_element(uncovered);
} else {
reset_all();

const uncovered = select_one();

if (uncovered) {
visit_element(uncovered);
}
}
}

function next_line(reverse) {
next_uncovered("td.uncovered-line", reverse)
}

function next_region(reverse) {
next_uncovered("span.red.region", reverse);
}

function next_branch(reverse) {
next_uncovered("span.red.branch", reverse);
}

document.addEventListener("keypress", function(event) {
const reverse = event.shiftKey;
if (event.code == "KeyL") {
next_line(reverse);
}
if (event.code == "KeyB") {
next_branch(reverse);
}
if (event.code == "KeyR") {
next_region(reverse);
}
});
Loading