|
24 | 24 |
|
25 | 25 | SKIP_DIRECTORIES = {"_book", "node_modules", ".git", ".docs"} |
26 | 26 |
|
| 27 | +# Mutable holder for the docs repo root, set by main() |
| 28 | +DOCS_REPO_ROOT: list = [None] |
| 29 | + |
27 | 30 | # Paths to reference files (relative to this script) |
28 | 31 | SCRIPT_DIR = Path(__file__).resolve().parent |
29 | 32 | SKILL_DIR = SCRIPT_DIR.parent |
@@ -179,13 +182,17 @@ def search_docs_for_terms(docs_text: dict[str, str], terms: list[str]) -> list[s |
179 | 182 |
|
180 | 183 | def parse_feature_flags(warp_internal: Path) -> list[str]: |
181 | 184 | """Parse FeatureFlag enum variants from features.rs.""" |
182 | | - # The FeatureFlag enum lives in the warp_features crate |
183 | | - features_rs = warp_internal / "crates" / "warp_features" / "src" / "lib.rs" |
184 | | - if not features_rs.exists(): |
185 | | - # Fall back to legacy path |
186 | | - features_rs = warp_internal / "warp_core" / "src" / "features.rs" |
187 | | - if not features_rs.exists(): |
188 | | - print(f"Warning: {features_rs} not found", file=sys.stderr) |
| 185 | + # Try known locations in order |
| 186 | + candidates = [ |
| 187 | + warp_internal / "crates" / "warp_features" / "src" / "lib.rs", |
| 188 | + warp_internal / "crates" / "warp_core" / "src" / "features.rs", |
| 189 | + warp_internal / "app" / "src" / "features.rs", |
| 190 | + warp_internal / "warp_core" / "src" / "features.rs", |
| 191 | + ] |
| 192 | + features_rs = next((c for c in candidates if c.exists()), None) |
| 193 | + if features_rs is None: |
| 194 | + print(f"Warning: features.rs not found. Tried: {[str(c) for c in candidates]}", |
| 195 | + file=sys.stderr) |
189 | 196 | return [] |
190 | 197 |
|
191 | 198 | content = features_rs.read_text() |
@@ -213,9 +220,14 @@ def parse_feature_flags(warp_internal: Path) -> list[str]: |
213 | 220 |
|
214 | 221 | def parse_default_features(warp_internal: Path) -> set[str]: |
215 | 222 | """Parse the default feature list from app/Cargo.toml.""" |
216 | | - cargo_toml = warp_internal / "app" / "Cargo.toml" |
217 | | - if not cargo_toml.exists(): |
218 | | - print(f"Warning: {cargo_toml} not found", file=sys.stderr) |
| 223 | + candidates = [ |
| 224 | + warp_internal / "app" / "Cargo.toml", |
| 225 | + warp_internal / "crates" / "warp_features" / "Cargo.toml", |
| 226 | + ] |
| 227 | + cargo_toml = next((c for c in candidates if c.exists()), None) |
| 228 | + if cargo_toml is None: |
| 229 | + print(f"Warning: app/Cargo.toml not found. Tried: {[str(c) for c in candidates]}", |
| 230 | + file=sys.stderr) |
219 | 231 | return set() |
220 | 232 |
|
221 | 233 | content = cargo_toml.read_text() |
@@ -292,8 +304,14 @@ def audit_features(warp_internal: Path, docs_root: Path, surface_map: dict, |
292 | 304 |
|
293 | 305 | def parse_cli_commands(warp_internal: Path) -> list[dict]: |
294 | 306 | """Parse CLI subcommands from warp_cli/src/lib.rs.""" |
295 | | - lib_rs = warp_internal / "warp_cli" / "src" / "lib.rs" |
296 | | - if not lib_rs.exists(): |
| 307 | + candidates = [ |
| 308 | + warp_internal / "crates" / "warp_cli" / "src" / "lib.rs", |
| 309 | + warp_internal / "warp_cli" / "src" / "lib.rs", |
| 310 | + ] |
| 311 | + lib_rs = next((c for c in candidates if c.exists()), None) |
| 312 | + if lib_rs is None: |
| 313 | + print(f"Warning: warp_cli/src/lib.rs not found. Tried: {[str(c) for c in candidates]}", |
| 314 | + file=sys.stderr) |
297 | 315 | return [] |
298 | 316 |
|
299 | 317 | content = lib_rs.read_text() |
@@ -329,8 +347,12 @@ def parse_cli_commands(warp_internal: Path) -> list[dict]: |
329 | 347 |
|
330 | 348 | def parse_subcommands_from_file(warp_internal: Path, filename: str) -> list[str]: |
331 | 349 | """Parse subcommand names from a CLI command file (e.g., agent.rs).""" |
332 | | - filepath = warp_internal / "warp_cli" / "src" / filename |
333 | | - if not filepath.exists(): |
| 350 | + candidates = [ |
| 351 | + warp_internal / "crates" / "warp_cli" / "src" / filename, |
| 352 | + warp_internal / "warp_cli" / "src" / filename, |
| 353 | + ] |
| 354 | + filepath = next((c for c in candidates if c.exists()), None) |
| 355 | + if filepath is None: |
334 | 356 | return [] |
335 | 357 |
|
336 | 358 | content = filepath.read_text() |
@@ -366,6 +388,10 @@ def audit_cli(warp_internal: Path, docs_root: Path, surface_map: dict, |
366 | 388 | # Check surface map |
367 | 389 | if cmd_str in cli_to_doc: |
368 | 390 | doc_path = cli_to_doc[cmd_str] |
| 391 | + # `internal` is a sentinel for hidden/internal commands that |
| 392 | + # intentionally have no public docs (matches API audit semantics). |
| 393 | + if doc_path == "internal": |
| 394 | + continue |
369 | 395 | if (docs_root.parent / doc_path).exists(): |
370 | 396 | continue # Mapped and exists |
371 | 397 |
|
@@ -437,8 +463,13 @@ def audit_api(warp_server: Path, docs_root: Path, surface_map: dict, |
437 | 463 | except Exception: |
438 | 464 | pass |
439 | 465 |
|
440 | | - # Also check OpenAPI spec |
441 | | - openapi_path = docs_root / "developers" / "agent-api-openapi.yaml" |
| 466 | + # Also check OpenAPI spec (lives at repo root, not under content/docs) |
| 467 | + repo_root = DOCS_REPO_ROOT[0] or docs_root.parent |
| 468 | + openapi_candidates = [ |
| 469 | + repo_root / "developers" / "agent-api-openapi.yaml", |
| 470 | + docs_root / "developers" / "agent-api-openapi.yaml", |
| 471 | + ] |
| 472 | + openapi_path = next((c for c in openapi_candidates if c.exists()), openapi_candidates[0]) |
442 | 473 | openapi_text = "" |
443 | 474 | if openapi_path.exists(): |
444 | 475 | try: |
@@ -640,12 +671,20 @@ def main(): |
640 | 671 | args = parser.parse_args() |
641 | 672 |
|
642 | 673 | # Find repos |
643 | | - docs_root = SKILL_DIR.parent.parent.parent # .warp/skills/missing_docs -> docs root |
644 | | - docs_root = docs_root / "docs" |
645 | | - |
646 | | - if not docs_root.exists(): |
647 | | - print(f"Error: docs directory not found at {docs_root}", file=sys.stderr) |
| 674 | + # SKILL_DIR is at <repo>/.agents/skills/missing_docs (or legacy <repo>/.warp/skills/...) |
| 675 | + repo_root = SKILL_DIR.parent.parent.parent |
| 676 | + # Astro Starlight docs live at src/content/docs |
| 677 | + candidates = [ |
| 678 | + repo_root / "src" / "content" / "docs", |
| 679 | + repo_root / "docs", |
| 680 | + ] |
| 681 | + docs_root = next((c for c in candidates if c.exists()), None) |
| 682 | + if docs_root is None: |
| 683 | + print(f"Error: docs directory not found. Tried: {[str(c) for c in candidates]}", |
| 684 | + file=sys.stderr) |
648 | 685 | sys.exit(1) |
| 686 | + # repo_root carries the developers/ openapi spec etc. |
| 687 | + DOCS_REPO_ROOT[0] = repo_root |
649 | 688 |
|
650 | 689 | warp_internal = find_repo("warp-internal", args.warp_internal, docs_root) |
651 | 690 | warp_server = find_repo("warp-server", args.warp_server, docs_root) |
|
0 commit comments