Run shared safety gates for ``openkb skill new`` / ``/skill new``. Checks (in order): * skill name is a valid kebab-case slug * `` /wiki`` exists * any of `` /wiki/{summaries,concepts,entities}`` has at least one file (i.e. some document has been ingested + compi
(kb_dir: Path, name: str)
| 325 | |
| 326 | |
| 327 | def _preflight_skill_new(kb_dir: Path, name: str) -> str | None: |
| 328 | """Run shared safety gates for ``openkb skill new`` / ``/skill new``. |
| 329 | |
| 330 | Checks (in order): |
| 331 | * skill name is a valid kebab-case slug |
| 332 | * ``<kb>/wiki`` exists |
| 333 | * any of ``<kb>/wiki/{summaries,concepts,entities}`` has at least |
| 334 | one file (i.e. some document has been ingested + compiled) |
| 335 | |
| 336 | Returns ``None`` if all gates pass, else a single-line error message |
| 337 | suitable to print to the user. |
| 338 | |
| 339 | Overwrite handling is NOT done here — the CLI handles it with |
| 340 | ``-y`` + ``click.confirm``; chat refuses overwrite outright. |
| 341 | """ |
| 342 | err = _validate_skill_name(name) |
| 343 | if err: |
| 344 | return err |
| 345 | |
| 346 | wiki = kb_dir / "wiki" |
| 347 | if not wiki.is_dir(): |
| 348 | return "No wiki found in this KB. Run `openkb add <source>` to ingest documents first." |
| 349 | |
| 350 | has_content = any( |
| 351 | (wiki / sub).is_dir() and any((wiki / sub).iterdir()) for sub in PAGE_CONTENT_DIRS |
| 352 | ) |
| 353 | if not has_content: |
| 354 | return ( |
| 355 | "Wiki has no compiled content yet. Ingest at least one " |
| 356 | "document with `openkb add` first." |
| 357 | ) |
| 358 | |
| 359 | return None |
| 360 | |
| 361 | |
| 362 | def _clear_existing_skill_dir(kb_dir: Path, name: str) -> None: |