{"record":{"id":"3d65c7e497632e57","repo":"farion1231/cc-switch","slug":"skill-dir-not-found","errorCode":"SKILL_DIR_NOT_FOUND","errorMessage":"SKILL_DIR_NOT_FOUND","messagePattern":"SKILL_DIR_NOT_FOUND","errorType":"error_code","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/services/skill.rs","lineNumber":845,"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":827,"sourceCodeEnd":863,"githubUrl":"https://github.com/farion1231/cc-switch/blob/06082e189d65e6d6dbadc35dacdac1ce6c79d89a/src-tauri/src/services/skill.rs#L827-L863","documentation":"After a successful download, install() locates the skill inside the temp clone via resolve_skill_source_dir(temp_dir, &skill.directory); when it returns None, the join of the expected relative path is formatted into SKILL_DIR_NOT_FOUND (context.path, suggestion 'checkRepoUrl'). This means the repository downloaded fine but the declared subdirectory does not exist at that path — the catalog's directory field points at something the repo layout does not contain (renamed upstream, branch mismatch, case-sensitive path typo, or nested layout moved).","triggerScenarios":"skill.directory = \"python/pdf-tools\" but the cloned repo has \"python/pdf_tools\" or moved it to \"tools/pdf-tools\" on the resolved branch; the default branch changed and the path only exists on another branch; the discovery entry is stale relative to the repo's HEAD.","commonSituations":"Upstream reorganizes folders after the aggregator indexed them; skills.sh metadata drift; case-sensitivity differences between macOS (where the entry was authored) and Linux (where install runs); wrong branch metadata in DiscoverableSkill.repo_branch.","solutions":["Open the repo at the URL in the error and find where the skill folder actually lives now, then install using the updated catalog/discovery entry.","If the skill only exists on a specific branch, ensure repo_branch in the skill metadata matches it before installing.","Match path casing exactly (Linux is case-sensitive); re-fetch the skill list so metadata is current."],"exampleFix":"# before\ndirectory field: \"python/PDF-Tools\"   # repo actually has python/pdf-tools\ninstall(...)  # -> SKILL_DIR_NOT_FOUND path=/tmp/xyz/python/PDF-Tools\n\n# after\ndirectory field: \"python/pdf-tools\"   # exact casing/layout from repo HEAD\ninstall(...)  # resolves and installs","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match install(&db, &skill, &app).await {\n    Err(e) if e.to_string().contains(\"SKILL_DIR_NOT_FOUND\") => {\n        let v: serde_json::Value = serde_json::from_str(&e.to_string())?;\n        let missing = v[\"context\"][\"path\"].as_str().unwrap_or(\"\");\n        // open the repo URL, locate the real folder, refresh catalog, offer re-install\n    }\n    other => other?,\n}","preventionTips":["Refresh the discovery list right before installing so path metadata matches repo HEAD.","Match path casing exactly, especially when installing from case-sensitive platforms."],"tags":["skills","install","path-not-found","repository","tauri"],"backgroundTag":"file-path-not-found","analyzedSha":"06082e189d65e6d6dbadc35dacdac1ce6c79d89a","analyzedAt":"2026-08-20T14:29:00.113Z","contentChangedAt":"2026-08-20T14:29:00.113Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}