@raishin/vanguard-frontier-agentic 3.11.0 → 3.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.cursor-plugin/plugin.json +19 -1
  4. package/.github/plugin/marketplace.json +1 -1
  5. package/agents/AGENTS.md +24 -24
  6. package/agents/README.md +17 -17
  7. package/agents/ionos/ionos-cost-optimization-analyst-agent/metadata.json +17 -3
  8. package/agents/ionos/ionos-datacenter-designer-reviewer-agent/metadata.json +17 -3
  9. package/agents/ionos/ionos-kubernetes-platform-operator-agent/metadata.json +17 -3
  10. package/agents/ionos/ionos-live-database-lifecycle-guard-agent/metadata.json +17 -3
  11. package/agents/ionos/ionos-maestro-agent/metadata.json +17 -3
  12. package/agents/ionos/ionos-security-compliance-reviewer-agent/metadata.json +17 -3
  13. package/agents/ovhcloud/ovhcloud-cost-finops-analyst-agent/metadata.json +17 -3
  14. package/agents/ovhcloud/ovhcloud-iam-policy-review-agent/metadata.json +17 -3
  15. package/agents/ovhcloud/ovhcloud-kubernetes-platform-operator-agent/metadata.json +17 -3
  16. package/agents/ovhcloud/ovhcloud-live-kms-key-destruction-guard-agent/metadata.json +17 -3
  17. package/agents/ovhcloud/ovhcloud-maestro-agent/metadata.json +17 -3
  18. package/agents/ovhcloud/ovhcloud-network-architect-agent/metadata.json +17 -3
  19. package/agents/scaleway/scaleway-cost-optimizer-agent/metadata.json +17 -3
  20. package/agents/scaleway/scaleway-iam-policy-review-agent/metadata.json +17 -3
  21. package/agents/scaleway/scaleway-kapsule-platform-operator-agent/metadata.json +17 -3
  22. package/agents/scaleway/scaleway-live-kapsule-rollout-guard-agent/metadata.json +17 -3
  23. package/agents/scaleway/scaleway-maestro-agent/metadata.json +17 -3
  24. package/agents/scaleway/scaleway-network-architect-agent/metadata.json +17 -3
  25. package/catalog/agents.json +90 -18
  26. package/catalog/asset-integrity.json +65 -65
  27. package/package.json +1 -1
  28. package/plugins/vanguard-frontier-agentic/.codex-plugin/plugin.json +1 -1
  29. package/powers/README.md +5 -2
  30. package/scripts/generate-board-counts.mjs +40 -4
  31. package/tests/validate-catalog.py +156 -0
@@ -342,6 +342,154 @@ def validate_guarded_live_kubernetes_agents() -> None:
342
342
  )
343
343
 
344
344
 
345
+ # Adapter files that prove a harness actually ships, mapped to the `harnesses` value
346
+ # that must then be declared.
347
+ HARNESS_ADAPTER_FILES = {
348
+ "codex.toml": "codex",
349
+ "copilot.agent.md": "copilot",
350
+ "claude-code.agent.md": "claude-code",
351
+ "cursor.agent.md": "cursor",
352
+ "gemini.agent.md": "gemini",
353
+ "kiro-ide.agent.md": "kiro",
354
+ "kiro-cli.agent.json": "kiro",
355
+ }
356
+
357
+ # Kiro is the one harness whose single `harnesses` value covers TWO adapter files, and the
358
+ # exporter emits both. Collapsing them into one set member would let a half-shipped Kiro
359
+ # adapter pass: with only kiro-ide.agent.md present, `kiro` is still in the on-disk set, the
360
+ # declaration matches, and the export later fails on the missing kiro-cli.agent.json. So the
361
+ # pair is checked explicitly rather than through the collapsed mapping.
362
+ KIRO_REQUIRED_FILES = ("kiro-ide.agent.md", "kiro-cli.agent.json")
363
+
364
+
365
+ def validate_harness_declarations() -> None:
366
+ """Every agent's `harnesses` must match the adapters it ships AND the catalog entry.
367
+
368
+ Three independent failures, each of which has actually happened or was one edit away:
369
+
370
+ * UNDER-declared (adapter on disk, harness absent from `harnesses`) makes a shipped
371
+ adapter invisible to everything that filters on the catalog. ionos, ovhcloud, and
372
+ scaleway each shipped all seven adapter files while declaring only codex and
373
+ claude-code, so generate-cursor-plugin.mjs omitted 18 real cursor adapters and
374
+ generate-kiro-powers.mjs dropped three real Kiro Powers.
375
+
376
+ * OVER-declared (harness claimed, no adapter file) promises an install path that does
377
+ not exist, failing at the user's `vfa-export-agents` rather than here.
378
+
379
+ * CATALOG DRIFT (metadata.json and catalog/agents.json disagree). catalog/agents.json
380
+ has no full regenerator — only an upsert — so fixing metadata.json does NOT update
381
+ it, and the catalog is what every generator actually reads. Checking metadata
382
+ against disk alone would report success while the original user-facing breakage
383
+ remained. This is not hypothetical: resyncing those 18 catalog entries was a
384
+ separate manual step from fixing their metadata.
385
+ """
386
+ problems: list[str] = []
387
+
388
+ catalog_harnesses: dict[str, list] = {}
389
+ catalog_agents = load_json(ROOT / "catalog" / "agents.json")
390
+ if isinstance(catalog_agents, dict):
391
+ catalog_agents = catalog_agents.get("agents", [])
392
+ for entry in catalog_agents:
393
+ if isinstance(entry, dict) and entry.get("type") == "agent":
394
+ catalog_harnesses[entry["id"]] = entry.get("harnesses") or []
395
+
396
+ for metadata_path in sorted(ROOT.glob("agents/*/*/metadata.json")):
397
+ data = load_json(metadata_path)
398
+ agent_id = data.get("id", metadata_path.parent.name)
399
+ declared = set(data.get("harnesses") or [])
400
+ harness_dir = metadata_path.parent / "harnesses"
401
+ present_files = (
402
+ {entry.name for entry in harness_dir.iterdir() if entry.is_file()}
403
+ if harness_dir.is_dir()
404
+ else set()
405
+ )
406
+ on_disk = {
407
+ HARNESS_ADAPTER_FILES[name]
408
+ for name in present_files
409
+ if name in HARNESS_ADAPTER_FILES
410
+ }
411
+ # "other" is a catalog-only escape hatch with no adapter file of its own.
412
+ declared.discard("other")
413
+
414
+ if on_disk - declared:
415
+ problems.append(
416
+ f"{agent_id}: ships adapters for {sorted(on_disk - declared)} "
417
+ f"but does not declare them in harnesses"
418
+ )
419
+ if declared - on_disk:
420
+ problems.append(
421
+ f"{agent_id}: declares harnesses {sorted(declared - on_disk)} "
422
+ f"with no matching adapter file"
423
+ )
424
+
425
+ # Kiro's two adapter files are checked as a pair, not through the collapsed value.
426
+ kiro_missing = [f for f in KIRO_REQUIRED_FILES if f not in present_files]
427
+ if "kiro" in declared and kiro_missing:
428
+ problems.append(
429
+ f"{agent_id}: declares the kiro harness but is missing {sorted(kiro_missing)} "
430
+ f"— both Kiro adapter files are required"
431
+ )
432
+ if kiro_missing and len(kiro_missing) == 1:
433
+ problems.append(
434
+ f"{agent_id}: ships a partial Kiro adapter — has "
435
+ f"{sorted(set(KIRO_REQUIRED_FILES) - set(kiro_missing))}, missing {kiro_missing}"
436
+ )
437
+
438
+ # The catalog is what the generators read; metadata alone proves nothing about them.
439
+ if agent_id in catalog_harnesses:
440
+ if sorted(catalog_harnesses[agent_id]) != sorted(data.get("harnesses") or []):
441
+ problems.append(
442
+ f"{agent_id}: catalog/agents.json declares "
443
+ f"{sorted(catalog_harnesses[agent_id])} but metadata.json declares "
444
+ f"{sorted(data.get('harnesses') or [])} — resync the catalog entry"
445
+ )
446
+
447
+ assert_true(
448
+ not problems,
449
+ "harness declarations disagree with shipped adapters or the catalog:\n - "
450
+ + "\n - ".join(problems),
451
+ )
452
+
453
+
454
+ def validate_tui_provider_enum() -> None:
455
+ """Every catalog provider must have a variant in the vfa-tui `Provider` enum.
456
+
457
+ tools/vfa-tui deserializes catalog/agents.json into a serde enum with
458
+ `deny_unknown_fields`, so a provider the enum does not know makes the whole catalog
459
+ fail to load and the TUI unusable. A Rust test already asserts this — but CI's
460
+ vfa-tui workflow is path-filtered to `tools/vfa-tui/**` (see
461
+ .github/workflows/vfa-tui-ci.yml), so a catalog-only PR that adds a provider never
462
+ triggers it and merges green while leaving the TUI broken. CLAUDE.md documents that
463
+ trap and asks contributors to remember `cargo test`; this makes remembering
464
+ unnecessary, because `npm run validate` is not path-filtered.
465
+
466
+ Parsed, never executed: variant names are read with a regex and converted to the
467
+ kebab-case slugs serde produces via `rename_all`, plus any explicit `rename = "..."`.
468
+ """
469
+ enum_path = ROOT / "tools" / "vfa-tui" / "src" / "models" / "provider.rs"
470
+ if not enum_path.exists():
471
+ # The TUI is optional to the catalog's correctness; absence is not a catalog error.
472
+ return
473
+ source = enum_path.read_text(encoding="utf8")
474
+ variants = re.findall(r"^\s{4}([A-Z][A-Za-z0-9]*),\s*$", source, re.MULTILINE)
475
+ slugs = {re.sub(r"(?<!^)(?=[A-Z])", "-", v).lower() for v in variants}
476
+ slugs |= set(re.findall(r'rename\s*=\s*"([a-z0-9-]+)"', source))
477
+
478
+ providers = set()
479
+ for entry in load_json(ROOT / "catalog" / "agents.json"):
480
+ if isinstance(entry, dict) and entry.get("provider"):
481
+ providers.add(entry["provider"])
482
+
483
+ missing = sorted(providers - slugs)
484
+ assert_true(
485
+ not missing,
486
+ "catalog providers with no variant in tools/vfa-tui/src/models/provider.rs: "
487
+ + f"{missing}. The TUI deserializes catalog/agents.json with a strict enum, so "
488
+ + "the catalog will fail to load entirely. Add the variant (kebab-case serde) and "
489
+ + "run `cargo test` in tools/vfa-tui.",
490
+ )
491
+
492
+
345
493
  def main() -> int:
346
494
  errors: list[str] = []
347
495
  seen_ids: set[str] = set()
@@ -364,6 +512,14 @@ def main() -> int:
364
512
  validate_codex_harness_adapters()
365
513
  except AssertionError as exc:
366
514
  errors.append(str(exc))
515
+ try:
516
+ validate_harness_declarations()
517
+ except AssertionError as exc:
518
+ errors.append(str(exc))
519
+ try:
520
+ validate_tui_provider_enum()
521
+ except AssertionError as exc:
522
+ errors.append(str(exc))
367
523
  try:
368
524
  validate_markdown_agent_templates()
369
525
  except AssertionError as exc: