-
Notifications
You must be signed in to change notification settings - Fork 3.7k
fix(skills): detect installed built-in catalog entries #3656
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
433962e
fc0cbaa
886aea7
c3e4526
14a48b1
958c315
623031d
ac3f55c
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 |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| node_modules | ||
| dist | ||
| dist-web | ||
| coverage | ||
| app | ||
| src-tauri | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,58 @@ const log = debug('skills:explorer-tab'); | |
| const CATALOG_PAGE_SIZE = 60; | ||
| const SEARCH_DEBOUNCE_MS = 300; | ||
|
|
||
| function slugifyInstallKey(value: string | null | undefined): string | null { | ||
| const raw = value?.trim(); | ||
| if (!raw) return null; | ||
|
|
||
| let out = ''; | ||
| let lastDash = false; | ||
| for (const ch of raw) { | ||
| if (/[a-z0-9]/i.test(ch)) { | ||
| out += ch.toLowerCase(); | ||
| lastDash = false; | ||
| } else if (!lastDash && out.length > 0) { | ||
| out += '-'; | ||
| lastDash = true; | ||
| } | ||
| } | ||
| return out.replace(/-+$/, '') || null; | ||
| } | ||
|
|
||
| function lastPathSegment(value: string | null | undefined): string | null { | ||
| const raw = value?.trim(); | ||
| if (!raw) return null; | ||
| const parts = raw.split(/[/:#?]+/).filter(Boolean); | ||
| return parts.at(-1) ?? null; | ||
| } | ||
|
|
||
| function parentPathSegment(value: string | null | undefined): string | null { | ||
| const raw = value?.trim(); | ||
| if (!raw) return null; | ||
| const parts = raw.split(/[\\/]+/).filter(Boolean); | ||
| return parts.length >= 2 ? parts.at(-2) ?? null : null; | ||
| } | ||
|
|
||
| function catalogInstallKeys(entry: CatalogEntry): string[] { | ||
| return [ | ||
| slugifyInstallKey(entry.id), | ||
| slugifyInstallKey(lastPathSegment(entry.id)), | ||
| slugifyInstallKey(parentPathSegment(entry.docs_path)), | ||
| slugifyInstallKey(parentPathSegment(entry.download_url)), | ||
|
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.
For catalog entries whose Useful? React with 👍 / 👎. |
||
| ].filter((key): key is string => Boolean(key)); | ||
| } | ||
|
|
||
| function workflowInstallKeys(skill: WorkflowSummary): string[] { | ||
| return [ | ||
| slugifyInstallKey(skill.id), | ||
| slugifyInstallKey(parentPathSegment(skill.location)), | ||
| ].filter((key): key is string => Boolean(key)); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| function isCatalogEntryInstalled(entry: CatalogEntry, installedKeys: Set<string>): boolean { | ||
| return catalogInstallKeys(entry).some(key => installedKeys.has(key)); | ||
| } | ||
|
|
||
| function SourceBadge({ source }: { source: string }) { | ||
| const SOURCE_COLORS: Record<string, string> = { | ||
| 'built-in': | ||
|
|
@@ -577,7 +629,10 @@ export default function SkillsExplorerTab({ onToast }: SkillsExplorerTabProps) { | |
| } | ||
| }, [view, debouncedQuery, activeSourceFilter, fetchCatalog]); | ||
|
|
||
| const installedIds = useMemo(() => new Set(skills.map(s => s.id)), [skills]); | ||
| const installedKeys = useMemo( | ||
| () => new Set(skills.flatMap(skill => workflowInstallKeys(skill))), | ||
| [skills] | ||
| ); | ||
|
|
||
| const filteredSkills = useMemo(() => { | ||
| const q = searchQuery.toLowerCase().trim(); | ||
|
|
@@ -902,7 +957,7 @@ export default function SkillsExplorerTab({ onToast }: SkillsExplorerTabProps) { | |
| <CatalogTile | ||
| key={`${entry.source}-${entry.id}`} | ||
| entry={entry} | ||
| installed={installedIds.has(entry.id)} | ||
| installed={isCatalogEntryInstalled(entry, installedKeys)} | ||
| installing={installingId === entry.id} | ||
| onClick={() => setDetailEntry(entry)} | ||
| onInstall={() => void handleRegistryInstall(entry)} | ||
|
|
@@ -941,13 +996,13 @@ export default function SkillsExplorerTab({ onToast }: SkillsExplorerTabProps) { | |
| <SkillDetailDialog | ||
| entry={detailEntry} | ||
| skill={detailSkill} | ||
| installed={detailEntry ? installedIds.has(detailEntry.id) : true} | ||
| installed={detailEntry ? isCatalogEntryInstalled(detailEntry, installedKeys) : true} | ||
| onClose={() => { | ||
| setDetailEntry(null); | ||
| setDetailSkill(null); | ||
| }} | ||
| onInstall={ | ||
| detailEntry && !installedIds.has(detailEntry.id) | ||
| detailEntry && !isCatalogEntryInstalled(detailEntry, installedKeys) | ||
| ? () => { | ||
| void handleRegistryInstall(detailEntry); | ||
| setDetailEntry(null); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -128,14 +128,19 @@ export VITE_BACKEND_URL="$MOCK_API_URL" | |
|
|
||
| cd "$REPO_ROOT" | ||
| source "$HOME/.cargo/env" 2>/dev/null || true | ||
| RUSTC_BIN="$(command -v rustc)" | ||
| CARGO_BIN="${CARGO_BIN:-$(dirname "$RUSTC_BIN")/cargo}" | ||
| if [ ! -x "$CARGO_BIN" ]; then | ||
| CARGO_BIN="$(command -v cargo)" | ||
| fi | ||
|
|
||
| echo "[rust-e2e] Running ${#SUITES[@]} suite(s) serially." | ||
| for suite in "${SUITES[@]}"; do | ||
| if [ "${#EXTRA_ARGS[@]}" -gt 0 ]; then | ||
| echo "[rust-e2e] cargo test --manifest-path Cargo.toml --test $suite -- ${EXTRA_ARGS[*]}" | ||
| "$SCRIPT_DIR/ci-cancel-aware.sh" cargo test --manifest-path Cargo.toml --test "$suite" -- "${EXTRA_ARGS[@]}" | ||
| echo "[rust-e2e] $CARGO_BIN test --manifest-path Cargo.toml --test $suite -- ${EXTRA_ARGS[*]}" | ||
| bash "$SCRIPT_DIR/ci-cancel-aware.sh" "$CARGO_BIN" test --manifest-path Cargo.toml --test "$suite" -- "${EXTRA_ARGS[@]}" | ||
| else | ||
| echo "[rust-e2e] cargo test --manifest-path Cargo.toml --test $suite" | ||
| "$SCRIPT_DIR/ci-cancel-aware.sh" cargo test --manifest-path Cargo.toml --test "$suite" | ||
| echo "[rust-e2e] $CARGO_BIN test --manifest-path Cargo.toml --test $suite" | ||
| bash "$SCRIPT_DIR/ci-cancel-aware.sh" "$CARGO_BIN" test --manifest-path Cargo.toml --test "$suite" | ||
|
Comment on lines
+141
to
+144
Contributor
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. 🎯 Functional Correctness | 🟡 Minor 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Description: Verify CARGO_BIN initialization and error handling in the E2E test script
# Show the CARGO_BIN resolution logic (lines 131-144)
echo "=== CARGO_BIN resolution logic ==="
sed -n '131,144p' scripts/test-rust-e2e.sh
echo ""
echo "=== Checking for SCRIPT_DIR definition ==="
rg -n 'SCRIPT_DIR=' scripts/test-rust-e2e.sh | head -5
echo ""
echo "=== Checking for error handling when cargo/rustc not found ==="
rg -n -A2 -B2 'CARGO_BIN.*command -v|rustc.*not found|cargo.*not found' scripts/test-rust-e2e.shRepository: tinyhumansai/openhuman Length of output: 1122 Add error handling if cargo/rustc discovery fails. CARGO_BIN is properly initialized with a multi-step fallback (lines 131-135): env var override → rustc directory → 🤖 Prompt for AI Agents |
||
| fi | ||
| done | ||
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.
For Hermes entries,
docs_pathis shaped likebundled/<category>/<category>-<skill>(the parser test for apple-notes usesbundled/apple/apple-apple-notes), soparentPathSegment(entry.docs_path)adds only the category (apple,devops, etc.) to the catalog's install keys. If a user has an installed/local workflow whose slug is one of those categories, every registry entry in that category is treated as installed and the Install action/detail button is hidden even though the specific skill is absent; derive the skill slug from the last docsPath segment (stripping the category prefix) or avoid this key.Useful? React with 👍 / 👎.