Repository navigation
Add: Grok host skill placement #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
55c423f
609ae58
6002fb0
444a6c0
2117fbb
093e169
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,10 +11,10 @@ Manage shared CorvidLabs agent skills in one repository. | |
|
|
||
| Usage: | ||
| fledge skills list [--json] | ||
| fledge skills install <skill> [--repo <path>] [--host <auto|codex|claude|cursor>] [--link] [--dry-run] | ||
| fledge skills install <skill> [--repo <path>] [--host <auto|codex|claude|cursor|gemini|grok|openai>] [--link] [--dry-run] | ||
| fledge skills status [--repo <path>] [--json] | ||
| fledge skills update <skill>|--all [--repo <path>] [--host <codex|claude|cursor>] [--dry-run] | ||
| fledge skills uninstall <skill> [--repo <path>] [--host <codex|claude|cursor>] [--dry-run] | ||
| fledge skills update <skill>|--all [--repo <path>] [--host <codex|claude|cursor|gemini|grok|openai>] [--dry-run] | ||
| fledge skills uninstall <skill> [--repo <path>] [--host <codex|claude|cursor|gemini|grok|openai>] [--dry-run] | ||
|
|
||
| Install copies a selected skill into a repository-local agent directory and | ||
| records the exact source revision and content digest in .corvid-skills.json. | ||
|
|
@@ -38,6 +38,9 @@ host_directory() { | |
| codex) printf '.codex/skills' ;; | ||
| claude) printf '.claude/skills' ;; | ||
| cursor) printf '.cursor/skills' ;; | ||
| gemini) printf '.gemini/skills' ;; | ||
| grok) printf '.grok/skills' ;; | ||
| openai) printf '.openai/skills' ;; | ||
| *) fail "unsupported host: $1" ;; | ||
| esac | ||
| } | ||
|
|
@@ -82,13 +85,19 @@ ensure_safe_managed_paths() { | |
| [[ ! -L "$repo/$manifest_name" ]] || fail "refusing symlinked manifest: $repo/$manifest_name" | ||
| } | ||
|
|
||
| has_only_regular_entries() { | ||
| local directory="$1" | ||
| [[ -d "$directory" && ! -L "$directory" ]] || return 1 | ||
| [[ -z "$(find "$directory" -mindepth 1 ! -type d ! -type f -print -quit)" ]] | ||
| } | ||
|
|
||
| validate_skill_source() { | ||
| local skill="$1" | ||
| [[ "$skill" =~ ^[a-z0-9][a-z0-9-]*$ ]] || fail "invalid skill name: $skill" | ||
| [[ -d "$skills_dir/$skill" && ! -L "$skills_dir/$skill" && -f "$skills_dir/$skill/SKILL.md" ]] || | ||
| fail "unknown skill: $skill" | ||
| [[ -z "$(find "$skills_dir/$skill" -type l -print -quit)" ]] || | ||
| fail "skill contains a symlink: $skill" | ||
| has_only_regular_entries "$skills_dir/$skill" || | ||
| fail "skill contains unsupported filesystem entries: $skill" | ||
| } | ||
|
|
||
| resolve_host() { | ||
|
|
@@ -102,28 +111,31 @@ resolve_host() { | |
|
|
||
| local candidates=() | ||
| local host | ||
| for host in codex claude cursor; do | ||
| for host in codex claude cursor gemini grok openai; do | ||
| [[ -d "$repo/$(host_directory "$host")" ]] && candidates+=("$host") | ||
| done | ||
| if [[ ${#candidates[@]} -eq 1 ]]; then | ||
| printf '%s' "${candidates[0]}" | ||
| return | ||
| fi | ||
| if [[ ${#candidates[@]} -eq 0 ]]; then | ||
| fail "cannot infer an agent host; pass --host codex, --host claude, or --host cursor" | ||
| fail "cannot infer an agent host; pass --host codex, --host claude, --host cursor, --host gemini, --host grok, or --host openai" | ||
| fi | ||
| fail "multiple agent hosts are present (${candidates[*]}); pass --host explicitly" | ||
| } | ||
|
|
||
| directory_digest() { | ||
| local directory="$1" | ||
| has_only_regular_entries "$directory" || return 1 | ||
| ( | ||
| cd "$directory" | ||
| find . -type f -print0 | LC_ALL=C sort -z | while IFS= read -r -d '' file; do | ||
| if command -v shasum >/dev/null 2>&1; then | ||
| shasum -a 256 "$file" | ||
| find . -mindepth 1 -print0 | LC_ALL=C sort -z | while IFS= read -r -d '' entry; do | ||
| if [[ -d "$entry" ]]; then | ||
| printf 'directory\0%s\0' "$entry" | ||
| elif command -v shasum >/dev/null 2>&1; then | ||
| printf 'file\0%s\0%s\0' "$entry" "$(shasum -a 256 "$entry" | awk '{print $1}')" | ||
| else | ||
| sha256sum "$file" | ||
| printf 'file\0%s\0%s\0' "$entry" "$(sha256sum "$entry" | awk '{print $1}')" | ||
|
Comment on lines
+132
to
+138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a repository contains an install created by the previous catalog version, its manifest stores the old file-only digest, but this new algorithm always produces a different path/type-aware digest for the unchanged directory. After upgrading the catalog, Useful? React with 👍 / 👎. |
||
| fi | ||
| done | ||
| ) | if command -v shasum >/dev/null 2>&1; then | ||
|
|
@@ -235,6 +247,9 @@ expected_destination() { | |
| codex) printf '.codex/skills/%s' "$skill" ;; | ||
| claude) printf '.claude/skills/%s' "$skill" ;; | ||
| cursor) printf '.cursor/skills/%s' "$skill" ;; | ||
| gemini) printf '.gemini/skills/%s' "$skill" ;; | ||
| grok) printf '.grok/skills/%s' "$skill" ;; | ||
| openai) printf '.openai/skills/%s' "$skill" ;; | ||
| *) return 1 ;; | ||
| esac | ||
| } | ||
|
|
@@ -265,16 +280,24 @@ entry_state() { | |
|
|
||
| if [[ "$install_mode" == "link" && -L "$destination" ]]; then | ||
| if [[ "$(readlink "$destination")" == "$skills_dir/$skill" ]]; then | ||
| if has_only_regular_entries "$skills_dir/$skill"; then | ||
| local actual_digest | ||
| actual_digest="$(directory_digest "$skills_dir/$skill")" | ||
| [[ "$actual_digest" == "$expected_digest" ]] && printf 'current' || printf 'modified' | ||
| else | ||
| printf 'modified' | ||
| fi | ||
| else | ||
| printf 'modified' | ||
| fi | ||
| elif [[ "$install_mode" == "copy" && -d "$destination" && ! -L "$destination" ]]; then | ||
| if has_only_regular_entries "$destination"; then | ||
| local actual_digest | ||
| actual_digest="$(directory_digest "$skills_dir/$skill")" | ||
| actual_digest="$(directory_digest "$destination")" | ||
| [[ "$actual_digest" == "$expected_digest" ]] && printf 'current' || printf 'modified' | ||
| else | ||
| printf 'modified' | ||
| fi | ||
| elif [[ "$install_mode" == "copy" && -d "$destination" && ! -L "$destination" ]]; then | ||
| local actual_digest | ||
| actual_digest="$(directory_digest "$destination")" | ||
| [[ "$actual_digest" == "$expected_digest" ]] && printf 'current' || printf 'modified' | ||
| elif [[ -e "$destination" || -L "$destination" ]]; then | ||
| printf 'modified' | ||
| else | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the Bun installer’s default release changes, this step begins building the pinned Let v0.2.0 plugin with a different runtime even though the skills commit is unchanged, so an upstream Bun regression or compatibility change can break this integration lane nondeterministically. Install an explicitly tested Bun version rather than executing the installer without a version selection.
Useful? React with 👍 / 👎.