[3.9.0] - 2026-07-29
Added
- HTML parser fallback for broken markup (#96, task F1.4) — new
parse_html()helper (cli/html_parsing.py) keepshtml.parseras the primary parser (well-formed pages stay byte-identical) but retries withlxml(if installed) thenhtml5libwhen parsing raises or yields a tag-free tree for tag-bearing markup, so severely malformed pages no longer scrape as empty. Wired into all web-scraper parse sites (doc_scraper.py) and local HTML file parsing (html_scraper.py);html5libadded as a core dependency so the fallback always exists. - Doc scraper retries transient network failures (#97) —
scrape_page/scrape_page_asyncnow wrap fetches inretry_with_backoff, so a connection blip or 5xx no longer silently drops the page and ships an incomplete skill. Only transient faults retry (connect/timeout errors, 5xx); 4xx is a definitive answer and returns un-retried. Attempts configurable via the newmax_retriesconfig option (default 3; 1 disables retrying). - MCP
fetch_configretries transient network failures (#92) — the registry list/detail/download GETs go through_get_with_retry(3 attempts, exponential backoff); 4xx like "config not found" still returns immediately. - Whisper transcription fallback (Tier 2) implemented (#420) —
transcribe_with_whisper()was a placeholder that always raised, so local videos without subtitle files produced no transcript despite the documented 3-tier fallback. Now implemented with faster-whisper (device auto,--whisper-modelsize, language hint, per-segment confidence), andget_transcript()logs the actual transcription error instead of swallowing it. - MiniMax image OCR + registry-driven multimodal provider support (#423) — MiniMax joins the AI provider registry for text enhancement and vision OCR (
MINIMAX_API_REGIONglobal_en/cn_zh,MINIMAX_API_PROTOCOLopenai/anthropic— China-issued keys no longer 401 against the global endpoint).API_PROVIDERSentries now declare wireprotocolandsupports_images,_call_apibranches on protocol (not provider name), andAgentClient.call_with_image()serves all image-capable providers withSKILL_SEEKER_VISION_PROVIDERauto-detection forvideo_visualframe OCR. word(docx) source in thescrape_genericMCP tool (#41) — the converter existed inCONVERTER_REGISTRYbut the MCP surface never listed it, so MCP clients had no way to scrape.docxsources.
Changed
- Token-lean GitHub issue defaults (#169) — GitHub-sourced skills no longer bundle a repo's full closed-issue history by default:
issue_statedefaults to"open"(was"all"),max_issuesto 20 (was 100), and labels/milestones are emitted only with the newinclude_issue_labels/include_issue_milestonesflags (default off).issues.mdomits empty sections and no longer prints "No labels" stubs. All defaults overridable.
Fixed
- Unified multi-source
skip_scrapenow rebuilds from cache —UnifiedScraperreloads each configured source from.skillseeker-cache/cached extraction files before conflict detection and build, so cached unified configs no longer re-scrape the network (#405). - Quality completeness checks no longer match inside code blocks (#229) —
SkillQualityChecker._check_skill_completenessran its workflow-step/prerequisites/error-handling regexes against raw SKILL.md, so a# Step 1:comment in a fenced example counted as workflow guidance. Fenced blocks and inline code are stripped before matching; prose detection unchanged. - Pattern-detector precision: getters are not factories, Java Singletons are detectable (#425) —
FactoryDetectormatched creation keywords as substrings, so a plain Java POJO scored Factory from its getters and a canonicalgetInstance()Singleton was misclassified as Factory. Creation verbs now match as word-boundary prefixes with accessor prefixes (get/set/is/has) excluded, andSingletonDetectorrecognizes class-named constructors (Java/C#/C++) and an overridden__new__. Also: dependency-graph node keys useas_posix()so Windows paths can't zero out import resolution, and a multi-file graph resolving zero edges now logs a warning. - Per-frame failures no longer abort visual extraction (#426) — one exception in the classify → OCR → track loop killed the whole video's
--visualextraction; a failing frame now logs a warning and is skipped while the scan continues. - Two CPU-environment crashes in visual extraction (#419) — newer OpenCV builds return
(N, 4)from HoughLinesP, crashing region classification (reshape(-1, 4)handles every layout); and EasyOCR's quantized backend SIGILLed on x86 CPUs without AVX2 (QEMU default model, homelab VMs) — AVX2 is now detected via/proc/cpuinfoandquantize=Falsepassed when missing (slower fp32, but completes). - Kotlin analyzer is string-aware (#407) — brace counting and declaration extraction now mask strings and comments via a single offset-preserving C-style scanner, fixing dropped declarations from backtick-escaped identifiers,
${...}string-template interpolation, C++14 digit separators, and unterminated block comments. - Streaming-package consumer snippets handle the real package shape (#416) — the usage examples generated by the LangChain/LlamaIndex/Haystack adaptors assumed a bare JSON list, but streaming packages wrap content in
{"documents": ...}/{"nodes": ...}; the snippets now handle both, and dead example classes were removed fromstreaming_adaptor.py. - Docker docs point at pullable images (#412) — all documented references now use the public Hub namespace
yusyusswith the CLI (skill-seekers) vs MCP (skill-seekers-mcp) image used correctly per context; Helm values and the raw Kubernetes manifest no longer reference unpullable names.
Security
- CORS origins are env-driven across all three servers (#422, #424) — the API, embedding, and MCP HTTP servers shipped
allow_origins=["*"]withallow_credentials=True, a combination browsers reject. A sharedresolve_cors_config()readsCORS_ORIGINS(comma-separated or*) and enables credentials only for a concrete origin list; a wildcard mixed into the list can't re-enable the rejected combo. Docker LABEL versions synced to pyproject and the stale MCP tool-count label corrected (35 → 40).