{"record":{"id":"3d65c7e497632e57","repo":"farion1231/cc-switch","slug":"skill-dir-not-found","errorCode":"SKILL_DIR_NOT_FOUND","errorMessage":"{\"code\":\"SKILL_DIR_NOT_FOUND\",\"context\":{\"path\":\"{path}\"},\"suggestion\":\"checkRepoUrl\"}","messagePattern":"(.+?)\"\\},\"suggestion\":\"checkRepoUrl\"\\}","errorType":"error_code","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/services/skill.rs","lineNumber":844,"sourceCode":"            .map_err(|_| {\n                anyhow!(format_skill_error(\n                    \"DOWNLOAD_TIMEOUT\",\n                    &[\n                        (\"owner\", &repo.owner),\n                        (\"name\", &repo.name),\n                        (\"timeout\", \"60\")\n                    ],\n                    Some(\"checkNetwork\"),\n                ))\n            })??;\n            let temp_dir = temp_guard.path();\n            repo_branch = used_branch;\n\n            // 复制到 SSOT\n            let source =\n                Self::resolve_skill_source_dir(temp_dir, &skill.directory).ok_or_else(|| {\n                    let missing = temp_dir.join(&source_rel).display().to_string();\n                    anyhow!(format_skill_error(\n                        \"SKILL_DIR_NOT_FOUND\",\n                        &[(\"path\", &missing)],\n                        Some(\"checkRepoUrl\"),\n                    ))\n                })?;\n\n            let canonical_temp = temp_dir\n                .canonicalize()\n                .unwrap_or_else(|_| temp_dir.to_path_buf());\n            let canonical_source = source.canonicalize().map_err(|_| {\n                anyhow!(format_skill_error(\n                    \"SKILL_DIR_NOT_FOUND\",\n                    &[(\"path\", &source.display().to_string())],\n                    Some(\"checkRepoUrl\"),\n                ))\n            })?;\n            if !canonical_source.starts_with(&canonical_temp) || !canonical_source.is_dir() {\n                return Err(anyhow!(format_skill_error(","sourceCodeStart":826,"sourceCodeEnd":862,"githubUrl":"https://github.com/farion1231/cc-switch/blob/a2e22f330273a5b6ffa87cb8b82b624601bac562/src-tauri/src/services/skill.rs#L826-L862","documentation":"Structured error from CC Switch's skill installer: after a successful repo download, resolve_skill_source_dir (src-tauri/src/services/skill.rs:2986-3019) failed to locate the skill. It tries (1) the exact relative path only if it is a directory containing SKILL.md, (2) a recursive search for a directory named after the install name that has SKILL.md, (3) the repo root if it has SKILL.md. None matched, so install() (line 843-852) emits code SKILL_DIR_NOT_FOUND with context.path set to the attempted path under the temp clone and suggestion 'checkRepoUrl'.","triggerScenarios":"The skills.sh index entry references a directory that was renamed/moved upstream; the declared branch's tree lacks the folder; the repo has a same-named directory WITHOUT a SKILL.md (an empty shell, which the resolver deliberately rejects); a wrapper repo whose inner skill is absent.","commonSituations":"Stale marketplace metadata after an upstream restructure; upstream deleted or relocated the skill; wrong repo/branch combination; the directory field only carries the skillId while the real content lives elsewhere (the resolver's fallbacks usually handle this — failure means even the fallbacks found nothing).","solutions":["Open the repo on GitHub at the reported path (context.path) and find where SKILL.md actually lives now","Refresh the skills.sh listing and reinstall so the corrected directory is picked up","If upstream is broken, install the skill from its canonical repo and report the stale index entry"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await install(skill);\n} catch (e) {\n  if (isSkillError(e) && e.code === \"SKILL_DIR_NOT_FOUND\") {\n    // e.context.path shows the attempted path inside the temp clone; e.suggestion === \"checkRepoUrl\"\n    openOnGitHub(`${skill.repoOwner}/${skill.repoName}`, e.context.path);\n    refreshCatalogThenRetry(skill);\n    return;\n  }\n  throw e;\n}","preventionTips":["Refresh the skills.sh index before installing older entries — upstream restructures are the top cause","A directory without SKILL.md never matches; verify the skill really exists at the declared path on GitHub","Report stale index entries upstream so the directory field gets corrected"],"tags":["skills","repository","install","not-found"],"backgroundTag":null,"analyzedSha":"a2e22f330273a5b6ffa87cb8b82b624601bac562","analyzedAt":"2026-08-16T03:46:07.889Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}