feat: add github benchmark scan to quickstart
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from urllib.parse import quote
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
|
||||
API_ROOT = "https://api.github.com"
|
||||
API_VERSION = "2022-11-28"
|
||||
USER_AGENT = "yao-meta-skill/1.0"
|
||||
DEFAULT_TOP_N = 3
|
||||
DEFAULT_PER_PAGE = 8
|
||||
MIN_STARS = 50
|
||||
|
||||
STOPWORDS = {
|
||||
"the",
|
||||
"and",
|
||||
"for",
|
||||
"with",
|
||||
"into",
|
||||
"from",
|
||||
"this",
|
||||
"that",
|
||||
"your",
|
||||
"will",
|
||||
"make",
|
||||
"turn",
|
||||
"build",
|
||||
"create",
|
||||
"reusable",
|
||||
"skill",
|
||||
"package",
|
||||
"agent",
|
||||
"workflow",
|
||||
"prompt",
|
||||
"notes",
|
||||
"docs",
|
||||
"internal",
|
||||
"team",
|
||||
"real",
|
||||
"output",
|
||||
"outputs",
|
||||
"input",
|
||||
"inputs",
|
||||
}
|
||||
|
||||
PATTERN_RULES = [
|
||||
{
|
||||
"category": "method",
|
||||
"keywords": ["workflow", "process", "pipeline", "orchestrat", "runbook", "playbook"],
|
||||
"borrow": "Borrow the way it turns a messy workflow into a repeatable operating path.",
|
||||
"avoid": "Do not import process overhead that only exists for that project's scale.",
|
||||
},
|
||||
{
|
||||
"category": "execution",
|
||||
"keywords": ["cli", "command", "shell", "script", "automation", "toolchain"],
|
||||
"borrow": "Borrow the clear execution entrypoints and command structure.",
|
||||
"avoid": "Do not copy repo-specific commands or environment assumptions verbatim.",
|
||||
},
|
||||
{
|
||||
"category": "evaluation",
|
||||
"keywords": ["test", "benchmark", "eval", "assert", "validation", "quality"],
|
||||
"borrow": "Borrow explicit validation and quality gates that make iteration safer.",
|
||||
"avoid": "Do not clone heavyweight evaluation scaffolding if a lighter gate is enough here.",
|
||||
},
|
||||
{
|
||||
"category": "structure",
|
||||
"keywords": ["template", "example", "guide", "docs", "reference", "starter"],
|
||||
"borrow": "Borrow the way it separates explanation, examples, and reusable structure.",
|
||||
"avoid": "Do not mirror documentation bulk that adds context cost without improving reliability.",
|
||||
},
|
||||
{
|
||||
"category": "portability",
|
||||
"keywords": ["adapter", "portable", "plugin", "integration", "export", "compatibility"],
|
||||
"borrow": "Borrow how it keeps core semantics stable across environments or integrations.",
|
||||
"avoid": "Do not inherit platform lock-in or vendor-specific branching unless truly required.",
|
||||
},
|
||||
{
|
||||
"category": "governance",
|
||||
"keywords": ["govern", "policy", "security", "audit", "compliance", "review"],
|
||||
"borrow": "Borrow the explicit review, safety, or operational trust boundaries.",
|
||||
"avoid": "Do not import compliance-heavy process where the new skill does not need it.",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def github_headers() -> dict[str, str]:
|
||||
headers = {
|
||||
"Accept": "application/vnd.github+json",
|
||||
"X-GitHub-Api-Version": API_VERSION,
|
||||
"User-Agent": USER_AGENT,
|
||||
}
|
||||
token = os.getenv("GITHUB_TOKEN") or os.getenv("GH_TOKEN")
|
||||
if token:
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
return headers
|
||||
|
||||
|
||||
def api_get(url: str) -> dict[str, Any]:
|
||||
request = Request(url, headers=github_headers())
|
||||
with urlopen(request, timeout=15) as response: # nosec B310 - GitHub API fetch
|
||||
data = response.read().decode("utf-8")
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
def load_fixture_bundle(fixture_dir: Path | None) -> dict[str, Any] | None:
|
||||
if not fixture_dir:
|
||||
return None
|
||||
bundle_path = fixture_dir / "bundle.json"
|
||||
if not bundle_path.exists():
|
||||
raise FileNotFoundError(f"Missing fixture bundle: {bundle_path}")
|
||||
return json.loads(bundle_path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def build_query(seed_text: str) -> str:
|
||||
words = re.findall(r"[A-Za-z][A-Za-z0-9_-]{2,}", seed_text.lower())
|
||||
keywords = []
|
||||
seen = set()
|
||||
for word in words:
|
||||
if word in STOPWORDS or word in seen:
|
||||
continue
|
||||
seen.add(word)
|
||||
keywords.append(word)
|
||||
if len(keywords) == 4:
|
||||
break
|
||||
if keywords:
|
||||
return " ".join(keywords)
|
||||
compact = re.sub(r"\s+", " ", seed_text.strip())
|
||||
return compact[:64] or "agent workflow automation"
|
||||
|
||||
|
||||
def search_repositories(query: str, top_n: int, fixture_bundle: dict[str, Any] | None = None) -> list[dict[str, Any]]:
|
||||
if fixture_bundle is not None:
|
||||
items = fixture_bundle.get("search_items", [])
|
||||
return items[:top_n]
|
||||
|
||||
github_query = f"{query} fork:false archived:false stars:>={MIN_STARS}"
|
||||
url = (
|
||||
f"{API_ROOT}/search/repositories?q={quote(github_query)}"
|
||||
f"&sort=stars&order=desc&per_page={DEFAULT_PER_PAGE}"
|
||||
)
|
||||
payload = api_get(url)
|
||||
items = payload.get("items", [])
|
||||
filtered = [item for item in items if not item.get("fork") and not item.get("archived")]
|
||||
return filtered[:top_n]
|
||||
|
||||
|
||||
def fetch_readme(full_name: str, fixture_bundle: dict[str, Any] | None = None) -> str:
|
||||
if fixture_bundle is not None:
|
||||
return fixture_bundle.get("readmes", {}).get(full_name, "")
|
||||
|
||||
url = f"{API_ROOT}/repos/{full_name}/readme"
|
||||
request = Request(url, headers={**github_headers(), "Accept": "application/vnd.github.raw+json"})
|
||||
with urlopen(request, timeout=15) as response: # nosec B310 - GitHub API fetch
|
||||
return response.read().decode("utf-8", errors="replace")
|
||||
|
||||
|
||||
def detect_patterns(text: str) -> list[dict[str, str]]:
|
||||
lowered = text.lower()
|
||||
hits = []
|
||||
for rule in PATTERN_RULES:
|
||||
matched = [token for token in rule["keywords"] if token in lowered]
|
||||
if matched:
|
||||
hits.append(
|
||||
{
|
||||
"category": rule["category"],
|
||||
"matched": ", ".join(matched[:4]),
|
||||
"borrow": rule["borrow"],
|
||||
"avoid": rule["avoid"],
|
||||
}
|
||||
)
|
||||
return hits[:4]
|
||||
|
||||
|
||||
def repo_summary(repo: dict[str, Any], readme_text: str) -> dict[str, Any]:
|
||||
combined = " ".join(
|
||||
filter(
|
||||
None,
|
||||
[
|
||||
repo.get("name", ""),
|
||||
repo.get("description", "") or "",
|
||||
" ".join(repo.get("topics") or []),
|
||||
readme_text[:4000],
|
||||
],
|
||||
)
|
||||
)
|
||||
patterns = detect_patterns(combined)
|
||||
if not patterns:
|
||||
patterns = [
|
||||
{
|
||||
"category": "general",
|
||||
"matched": "high-level fit",
|
||||
"borrow": "Borrow only the parts that make the new skill clearer, safer, or easier to reuse.",
|
||||
"avoid": "Do not import source-specific scope, branding, or excess weight.",
|
||||
}
|
||||
]
|
||||
|
||||
borrow = [item["borrow"] for item in patterns[:3]]
|
||||
avoid = [item["avoid"] for item in patterns[:3]]
|
||||
return {
|
||||
"full_name": repo.get("full_name"),
|
||||
"html_url": repo.get("html_url"),
|
||||
"description": repo.get("description"),
|
||||
"stars": repo.get("stargazers_count", 0),
|
||||
"topics": repo.get("topics") or [],
|
||||
"primary_language": repo.get("language"),
|
||||
"patterns": patterns,
|
||||
"borrow": borrow,
|
||||
"avoid": avoid,
|
||||
"readme_excerpt": readme_text[:1200].strip(),
|
||||
}
|
||||
|
||||
|
||||
def cross_repo_insights(repos: list[dict[str, Any]]) -> dict[str, list[str]]:
|
||||
borrow = []
|
||||
avoid = []
|
||||
seen_borrow = set()
|
||||
seen_avoid = set()
|
||||
for repo in repos:
|
||||
for item in repo.get("borrow", []):
|
||||
if item not in seen_borrow:
|
||||
seen_borrow.add(item)
|
||||
borrow.append(item)
|
||||
for item in repo.get("avoid", []):
|
||||
if item not in seen_avoid:
|
||||
seen_avoid.add(item)
|
||||
avoid.append(item)
|
||||
borrow.append("Ask the user which of these patterns feels most worth borrowing before freezing the package shape.")
|
||||
return {"borrow": borrow[:6], "avoid": avoid[:6]}
|
||||
|
||||
|
||||
def repo_to_external_reference(repo: dict[str, Any]) -> dict[str, str]:
|
||||
primary = repo.get("patterns", [{}])[0]
|
||||
return {
|
||||
"name": repo.get("full_name") or "Unnamed repo",
|
||||
"category": primary.get("category", "general"),
|
||||
"borrow": repo.get("borrow", ["Borrow the strongest reusable pattern."])[0],
|
||||
"avoid": repo.get("avoid", ["Do not copy source-specific language or excess scope."])[0],
|
||||
"source": "external",
|
||||
}
|
||||
|
||||
|
||||
def render_markdown(payload: dict[str, Any]) -> str:
|
||||
lines = [
|
||||
"# GitHub Benchmark Scan",
|
||||
"",
|
||||
f"- Query: `{payload['query']}`",
|
||||
f"- Source: `{payload['source']}`",
|
||||
f"- Top repositories: `{len(payload['repositories'])}`",
|
||||
"",
|
||||
"## Suggested Next Step",
|
||||
"",
|
||||
"Review the three benchmark objects below, then decide whether any of their patterns are worth borrowing into the new skill.",
|
||||
"",
|
||||
]
|
||||
|
||||
if not payload["repositories"]:
|
||||
lines.extend(
|
||||
[
|
||||
"No benchmark repositories were collected.",
|
||||
"",
|
||||
"Possible reasons:",
|
||||
"- the query was too weak or too local",
|
||||
"- the network or API rate limit blocked the scan",
|
||||
"- this skill idea may need a manual benchmark query",
|
||||
]
|
||||
)
|
||||
return "\n".join(lines).strip() + "\n"
|
||||
|
||||
lines.extend(["## Top 3 Benchmark Repositories", ""])
|
||||
for repo in payload["repositories"]:
|
||||
lines.extend(
|
||||
[
|
||||
f"### {repo['full_name']}",
|
||||
f"- URL: {repo['html_url']}",
|
||||
f"- Stars: `{repo['stars']}`",
|
||||
f"- Description: {repo.get('description') or 'No public description provided.'}",
|
||||
f"- Topics: {', '.join(repo.get('topics') or []) or 'None'}",
|
||||
"",
|
||||
"#### Patterns worth studying",
|
||||
"",
|
||||
]
|
||||
)
|
||||
for pattern in repo["patterns"]:
|
||||
lines.append(
|
||||
f"- **{pattern['category']}** (`{pattern['matched']}`): {pattern['borrow']}"
|
||||
)
|
||||
lines.extend(["", "#### Borrow", ""])
|
||||
for item in repo["borrow"]:
|
||||
lines.append(f"- {item}")
|
||||
lines.extend(["", "#### Avoid", ""])
|
||||
for item in repo["avoid"]:
|
||||
lines.append(f"- {item}")
|
||||
lines.extend(["", "#### README glimpse", "", repo["readme_excerpt"] or "No README excerpt collected.", ""])
|
||||
|
||||
lines.extend(["## Cross-Repo Borrow Recommendations", ""])
|
||||
for item in payload["cross_repo"]["borrow"]:
|
||||
lines.append(f"- {item}")
|
||||
|
||||
lines.extend(["", "## Cross-Repo Avoid Recommendations", ""])
|
||||
for item in payload["cross_repo"]["avoid"]:
|
||||
lines.append(f"- {item}")
|
||||
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"## Borrow Prompt",
|
||||
"",
|
||||
payload["borrow_prompt"],
|
||||
"",
|
||||
]
|
||||
)
|
||||
return "\n".join(lines).strip() + "\n"
|
||||
|
||||
|
||||
def run_github_benchmark_scan(
|
||||
skill_dir: Path,
|
||||
query: str,
|
||||
top_n: int = DEFAULT_TOP_N,
|
||||
fixture_dir: Path | None = None,
|
||||
output_md: Path | None = None,
|
||||
output_json: Path | None = None,
|
||||
) -> dict[str, Any]:
|
||||
skill_dir = skill_dir.resolve()
|
||||
reports_dir = skill_dir / "reports"
|
||||
reports_dir.mkdir(parents=True, exist_ok=True)
|
||||
output_md = output_md or reports_dir / "github-benchmark-scan.md"
|
||||
output_json = output_json or reports_dir / "github-benchmark-scan.json"
|
||||
fixture_bundle = load_fixture_bundle(fixture_dir)
|
||||
|
||||
warnings = []
|
||||
try:
|
||||
repos = search_repositories(query, top_n=top_n, fixture_bundle=fixture_bundle)
|
||||
repo_summaries = []
|
||||
for repo in repos:
|
||||
readme_text = fetch_readme(repo["full_name"], fixture_bundle=fixture_bundle)
|
||||
repo_summaries.append(repo_summary(repo, readme_text))
|
||||
cross_repo = cross_repo_insights(repo_summaries)
|
||||
payload = {
|
||||
"ok": True,
|
||||
"query": query,
|
||||
"source": "fixture" if fixture_bundle is not None else "github-api",
|
||||
"repositories": repo_summaries,
|
||||
"cross_repo": cross_repo,
|
||||
"external_references": [repo_to_external_reference(repo) for repo in repo_summaries],
|
||||
"borrow_prompt": "I found three public GitHub projects worth studying. Do you want to borrow any of these patterns for method, structure, execution, or portability?",
|
||||
"warnings": warnings,
|
||||
}
|
||||
except Exception as exc: # pragma: no cover - network failures are environment-dependent
|
||||
payload = {
|
||||
"ok": False,
|
||||
"query": query,
|
||||
"source": "fixture" if fixture_bundle is not None else "github-api",
|
||||
"repositories": [],
|
||||
"cross_repo": {
|
||||
"borrow": [],
|
||||
"avoid": [],
|
||||
},
|
||||
"external_references": [],
|
||||
"borrow_prompt": "No benchmark suggestions were collected yet. You can retry with a stronger query or add manual references.",
|
||||
"warnings": [f"GitHub benchmark scan failed: {exc}"],
|
||||
}
|
||||
|
||||
output_md.write_text(render_markdown(payload), encoding="utf-8")
|
||||
output_json.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
payload["artifacts"] = {
|
||||
"markdown": str(output_md),
|
||||
"json": str(output_json),
|
||||
}
|
||||
payload["skill_dir"] = str(skill_dir)
|
||||
return payload
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Search GitHub for top benchmark repositories and extract reusable patterns.")
|
||||
parser.add_argument("skill_dir", nargs="?", default=".")
|
||||
parser.add_argument("--query", required=True)
|
||||
parser.add_argument("--top-n", type=int, default=DEFAULT_TOP_N)
|
||||
parser.add_argument("--fixture-dir")
|
||||
parser.add_argument("--output-md")
|
||||
parser.add_argument("--output-json")
|
||||
args = parser.parse_args()
|
||||
|
||||
result = run_github_benchmark_scan(
|
||||
Path(args.skill_dir),
|
||||
query=args.query,
|
||||
top_n=args.top_n,
|
||||
fixture_dir=Path(args.fixture_dir).resolve() if args.fixture_dir else None,
|
||||
output_md=Path(args.output_md).resolve() if args.output_md else None,
|
||||
output_json=Path(args.output_json).resolve() if args.output_json else None,
|
||||
)
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+62
-15
@@ -4,6 +4,7 @@ import json
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from github_benchmark_scan import run_github_benchmark_scan
|
||||
from render_intent_dialogue import render_intent_dialogue
|
||||
from render_iteration_directions import render_iteration_directions
|
||||
from render_reference_scan import parse_reference, render_reference_scan
|
||||
@@ -50,6 +51,7 @@ README_TEMPLATE = """# {title}
|
||||
- `agents/interface.yaml`: portable interface metadata
|
||||
- `manifest.json`: lifecycle and packaging metadata
|
||||
- `reports/intent-dialogue.md`: front-loaded discovery questions for better boundary design and clearer human alignment
|
||||
- `reports/github-benchmark-scan.md`: top public benchmark repositories, extracted patterns, and borrow or avoid notes
|
||||
- `reports/reference-scan.md`: benchmark notes from public references, user references, and local constraints
|
||||
- `reports/skill-overview.html`: visual overview report
|
||||
- `reports/review-viewer.html`: compact review page for architecture, usage, feedback, and next steps
|
||||
@@ -139,6 +141,24 @@ def build_manifest(name: str, mode: str, archetype: str) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def dedupe_references(references: list[dict]) -> list[dict]:
|
||||
seen = set()
|
||||
deduped = []
|
||||
for reference in references:
|
||||
key = (
|
||||
reference.get("source"),
|
||||
reference.get("name"),
|
||||
reference.get("category"),
|
||||
reference.get("borrow"),
|
||||
reference.get("avoid"),
|
||||
)
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
deduped.append(reference)
|
||||
return deduped
|
||||
|
||||
|
||||
def initialize_skill(
|
||||
name: str,
|
||||
description: str,
|
||||
@@ -149,6 +169,9 @@ def initialize_skill(
|
||||
external_references: list[dict] | None = None,
|
||||
user_references: list[dict] | None = None,
|
||||
local_constraints: list[dict] | None = None,
|
||||
github_query: str | None = None,
|
||||
github_top_n: int = 3,
|
||||
github_fixture_dir: str | None = None,
|
||||
) -> dict:
|
||||
title = title or name.replace("-", " ").title()
|
||||
root = Path(output_dir).resolve() / name
|
||||
@@ -179,28 +202,46 @@ def initialize_skill(
|
||||
)
|
||||
overview = render_skill_overview(root)
|
||||
intent_dialogue = render_intent_dialogue(root)
|
||||
reference_scan = render_reference_scan(root, [*(external_references or []), *(user_references or []), *(local_constraints or [])])
|
||||
benchmark_scan = None
|
||||
combined_external_references = [*(external_references or [])]
|
||||
if github_query:
|
||||
benchmark_scan = run_github_benchmark_scan(
|
||||
root,
|
||||
query=github_query,
|
||||
top_n=github_top_n,
|
||||
fixture_dir=Path(github_fixture_dir).resolve() if github_fixture_dir else None,
|
||||
)
|
||||
combined_external_references = [*benchmark_scan.get("external_references", []), *combined_external_references]
|
||||
reference_scan = render_reference_scan(
|
||||
root,
|
||||
dedupe_references([*combined_external_references, *(user_references or []), *(local_constraints or [])]),
|
||||
)
|
||||
iteration_directions = render_iteration_directions(root)
|
||||
review_viewer = render_review_viewer(root)
|
||||
artifacts = {
|
||||
"readme": str(root / "README.md"),
|
||||
"manifest": str(root / "manifest.json"),
|
||||
"skill_overview_html": overview["artifacts"]["html"],
|
||||
"skill_overview_json": overview["artifacts"]["json"],
|
||||
"intent_dialogue_md": intent_dialogue["artifacts"]["markdown"],
|
||||
"intent_dialogue_json": intent_dialogue["artifacts"]["json"],
|
||||
"reference_scan_md": reference_scan["artifacts"]["markdown"],
|
||||
"reference_scan_json": reference_scan["artifacts"]["json"],
|
||||
"iteration_directions_md": iteration_directions["artifacts"]["markdown"],
|
||||
"iteration_directions_json": iteration_directions["artifacts"]["json"],
|
||||
"review_viewer_html": review_viewer["artifacts"]["html"],
|
||||
"review_viewer_json": review_viewer["artifacts"]["json"],
|
||||
}
|
||||
if benchmark_scan is not None:
|
||||
artifacts["github_benchmark_scan_md"] = benchmark_scan["artifacts"]["markdown"]
|
||||
artifacts["github_benchmark_scan_json"] = benchmark_scan["artifacts"]["json"]
|
||||
return {
|
||||
"ok": True,
|
||||
"root": str(root),
|
||||
"mode": mode,
|
||||
"archetype": archetype,
|
||||
"artifacts": {
|
||||
"readme": str(root / "README.md"),
|
||||
"manifest": str(root / "manifest.json"),
|
||||
"skill_overview_html": overview["artifacts"]["html"],
|
||||
"skill_overview_json": overview["artifacts"]["json"],
|
||||
"intent_dialogue_md": intent_dialogue["artifacts"]["markdown"],
|
||||
"intent_dialogue_json": intent_dialogue["artifacts"]["json"],
|
||||
"reference_scan_md": reference_scan["artifacts"]["markdown"],
|
||||
"reference_scan_json": reference_scan["artifacts"]["json"],
|
||||
"iteration_directions_md": iteration_directions["artifacts"]["markdown"],
|
||||
"iteration_directions_json": iteration_directions["artifacts"]["json"],
|
||||
"review_viewer_html": review_viewer["artifacts"]["html"],
|
||||
"review_viewer_json": review_viewer["artifacts"]["json"],
|
||||
},
|
||||
"github_benchmark_scan": benchmark_scan,
|
||||
"artifacts": artifacts,
|
||||
}
|
||||
|
||||
|
||||
@@ -215,6 +256,9 @@ def main() -> None:
|
||||
parser.add_argument("--external-reference", action="append", default=[])
|
||||
parser.add_argument("--user-reference", action="append", default=[])
|
||||
parser.add_argument("--local-constraint", action="append", default=[])
|
||||
parser.add_argument("--github-query")
|
||||
parser.add_argument("--github-top-n", type=int, default=3)
|
||||
parser.add_argument("--github-fixture-dir")
|
||||
args = parser.parse_args()
|
||||
result = initialize_skill(
|
||||
args.name,
|
||||
@@ -226,6 +270,9 @@ def main() -> None:
|
||||
external_references=[parse_reference(item, "external") for item in args.external_reference],
|
||||
user_references=[parse_reference(item, "user") for item in args.user_reference],
|
||||
local_constraints=[parse_reference(item, "local") for item in args.local_constraint],
|
||||
github_query=args.github_query,
|
||||
github_top_n=args.github_top_n,
|
||||
github_fixture_dir=args.github_fixture_dir,
|
||||
)
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
+65
-4
@@ -5,6 +5,8 @@ import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from github_benchmark_scan import build_query
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
SCRIPTS = ROOT / "scripts"
|
||||
@@ -190,6 +192,11 @@ def command_init(args: argparse.Namespace) -> int:
|
||||
cmd.extend(["--user-reference", reference])
|
||||
for constraint in args.local_constraint:
|
||||
cmd.extend(["--local-constraint", constraint])
|
||||
if args.github_query:
|
||||
cmd.extend(["--github-query", args.github_query])
|
||||
cmd.extend(["--github-top-n", str(args.github_top_n)])
|
||||
if args.github_fixture_dir:
|
||||
cmd.extend(["--github-fixture-dir", args.github_fixture_dir])
|
||||
result = run_script("init_skill.py", cmd)
|
||||
print(json.dumps(result["payload"] if result["payload"] is not None else result, ensure_ascii=False, indent=2))
|
||||
return 0 if result["ok"] else 2
|
||||
@@ -197,7 +204,7 @@ def command_init(args: argparse.Namespace) -> int:
|
||||
|
||||
def command_quickstart(args: argparse.Namespace) -> int:
|
||||
sys.stderr.write("Let's shape this skill around the real work, the outcome, and the standards you care about before we add structure.\n")
|
||||
sys.stderr.write("If you already have references you admire, bring them in. We'll learn the pattern, not copy the source.\n")
|
||||
sys.stderr.write("I will also scan a few strong public GitHub references first, so we can borrow the right patterns without copying the source.\n")
|
||||
name = args.name or prompt_with_default("Skill name", "my-skill")
|
||||
job = args.job or prompt_with_default("What repeated work should this skill quietly take off your hands", "Turn a repeated workflow into a reusable skill.")
|
||||
primary_output = args.primary_output or prompt_with_default("What should it reliably hand back", "A reusable skill package.")
|
||||
@@ -209,14 +216,16 @@ def command_quickstart(args: argparse.Namespace) -> int:
|
||||
mode = args.mode or prompt_with_default("Mode (scaffold/production/library/governed)", default_mode)
|
||||
mode = mode if mode in ARCHETYPE_MODE.values() else default_mode
|
||||
user_references = args.user_reference or prompt_optional_entries(
|
||||
"Reference examples you want it to learn from (repo, product, page, workflow; comma-separated)"
|
||||
"Your own reference examples to learn from as pattern hints (repo, product, page, workflow; comma-separated)"
|
||||
)
|
||||
external_references = args.external_reference or prompt_optional_entries(
|
||||
"Public benchmark objects to scan first (high-star GitHub repo, official doc, product; comma-separated)"
|
||||
"Additional public benchmark objects you already know you want to borrow from (comma-separated)"
|
||||
)
|
||||
local_constraints = args.local_constraint or prompt_optional_entries(
|
||||
"Local constraints that must still be respected (privacy, naming, compatibility; comma-separated)"
|
||||
)
|
||||
github_query = args.github_query or build_query(" ".join(filter(None, [job, primary_output, description])))
|
||||
sys.stderr.write(f"GitHub benchmark query: {github_query}\n")
|
||||
title = args.title or name.replace("-", " ").title()
|
||||
guidance = archetype_guidance(archetype)
|
||||
cmd = [
|
||||
@@ -231,7 +240,13 @@ def command_quickstart(args: argparse.Namespace) -> int:
|
||||
mode,
|
||||
"--archetype",
|
||||
archetype,
|
||||
"--github-query",
|
||||
github_query,
|
||||
"--github-top-n",
|
||||
str(args.github_top_n),
|
||||
]
|
||||
if args.github_fixture_dir:
|
||||
cmd.extend(["--github-fixture-dir", args.github_fixture_dir])
|
||||
for reference in external_references:
|
||||
cmd.extend(["--external-reference", reference])
|
||||
for reference in user_references:
|
||||
@@ -240,17 +255,29 @@ def command_quickstart(args: argparse.Namespace) -> int:
|
||||
cmd.extend(["--local-constraint", constraint])
|
||||
result = run_script("init_skill.py", cmd)
|
||||
payload = result["payload"] if result["payload"] is not None else result
|
||||
benchmark_scan = payload.get("github_benchmark_scan") or {}
|
||||
benchmark_repositories = [
|
||||
{
|
||||
"name": repo.get("full_name"),
|
||||
"stars": repo.get("stars"),
|
||||
"url": repo.get("html_url"),
|
||||
}
|
||||
for repo in benchmark_scan.get("repositories", [])
|
||||
]
|
||||
report = {
|
||||
"ok": result["ok"],
|
||||
"root": payload.get("root"),
|
||||
"mode": mode,
|
||||
"archetype": archetype,
|
||||
"references": {
|
||||
"github_query": github_query,
|
||||
"benchmark_repositories": benchmark_repositories,
|
||||
"external_benchmarks": external_references,
|
||||
"user_references": user_references,
|
||||
"local_constraints": local_constraints,
|
||||
},
|
||||
"artifacts": payload.get("artifacts", {}),
|
||||
"github_benchmark_scan": benchmark_scan,
|
||||
"guidance": {
|
||||
"archetype_reason": archetype_reason,
|
||||
"why_this_mode": (
|
||||
@@ -262,10 +289,12 @@ def command_quickstart(args: argparse.Namespace) -> int:
|
||||
"focus": guidance["focus"],
|
||||
"next_steps": [
|
||||
"Open reports/intent-dialogue.md and tighten the real job, outputs, and exclusions.",
|
||||
"Open reports/reference-scan.md and decide which external patterns to borrow and which user references set the quality bar.",
|
||||
"Open reports/github-benchmark-scan.md and review the top three public benchmark repositories plus their borrow and avoid notes.",
|
||||
"Open reports/reference-scan.md and decide which benchmark patterns to borrow and which user references set the quality bar.",
|
||||
"Open reports/review-viewer.html to explain the package to a first-time reviewer.",
|
||||
"Use reports/iteration-directions.md to choose only one high-value next move before adding more files.",
|
||||
],
|
||||
"borrow_prompt": benchmark_scan.get("borrow_prompt"),
|
||||
},
|
||||
}
|
||||
print(json.dumps(report, ensure_ascii=False, indent=2))
|
||||
@@ -416,6 +445,20 @@ def command_reference_scan(args: argparse.Namespace) -> int:
|
||||
return 0 if result["ok"] else 2
|
||||
|
||||
|
||||
def command_github_benchmark_scan(args: argparse.Namespace) -> int:
|
||||
skill_dir = str(Path(args.skill_dir).resolve())
|
||||
cmd = [skill_dir, "--query", args.query, "--top-n", str(args.top_n)]
|
||||
if args.fixture_dir:
|
||||
cmd.extend(["--fixture-dir", args.fixture_dir])
|
||||
if args.output_md:
|
||||
cmd.extend(["--output-md", args.output_md])
|
||||
if args.output_json:
|
||||
cmd.extend(["--output-json", args.output_json])
|
||||
result = run_script("github_benchmark_scan.py", cmd)
|
||||
print(json.dumps(result["payload"] if result["payload"] is not None else result, ensure_ascii=False, indent=2))
|
||||
return 0 if result["ok"] else 2
|
||||
|
||||
|
||||
def command_intent_dialogue(args: argparse.Namespace) -> int:
|
||||
skill_dir = str(Path(args.skill_dir).resolve())
|
||||
cmd = [skill_dir]
|
||||
@@ -620,6 +663,9 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
init_cmd.add_argument("--external-reference", action="append", default=[])
|
||||
init_cmd.add_argument("--user-reference", action="append", default=[])
|
||||
init_cmd.add_argument("--local-constraint", action="append", default=[])
|
||||
init_cmd.add_argument("--github-query")
|
||||
init_cmd.add_argument("--github-top-n", type=int, default=3)
|
||||
init_cmd.add_argument("--github-fixture-dir")
|
||||
init_cmd.set_defaults(func=command_init)
|
||||
|
||||
quickstart_cmd = subparsers.add_parser(
|
||||
@@ -637,6 +683,9 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
quickstart_cmd.add_argument("--external-reference", action="append", default=[])
|
||||
quickstart_cmd.add_argument("--user-reference", action="append", default=[])
|
||||
quickstart_cmd.add_argument("--local-constraint", action="append", default=[])
|
||||
quickstart_cmd.add_argument("--github-query")
|
||||
quickstart_cmd.add_argument("--github-top-n", type=int, default=3)
|
||||
quickstart_cmd.add_argument("--github-fixture-dir")
|
||||
quickstart_cmd.set_defaults(func=command_quickstart)
|
||||
|
||||
validate_cmd = subparsers.add_parser("validate", help="Run validate, lint, governance, and resource checks.")
|
||||
@@ -714,6 +763,18 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
reference_scan_cmd.add_argument("--output-json")
|
||||
reference_scan_cmd.set_defaults(func=command_reference_scan)
|
||||
|
||||
github_scan_cmd = subparsers.add_parser(
|
||||
"github-benchmark-scan",
|
||||
help="Search top public GitHub repositories and extract borrow or avoid patterns for a skill.",
|
||||
)
|
||||
github_scan_cmd.add_argument("skill_dir", nargs="?", default=".")
|
||||
github_scan_cmd.add_argument("--query", required=True)
|
||||
github_scan_cmd.add_argument("--top-n", type=int, default=3)
|
||||
github_scan_cmd.add_argument("--fixture-dir")
|
||||
github_scan_cmd.add_argument("--output-md")
|
||||
github_scan_cmd.add_argument("--output-json")
|
||||
github_scan_cmd.set_defaults(func=command_github_benchmark_scan)
|
||||
|
||||
intent_dialogue_cmd = subparsers.add_parser(
|
||||
"intent-dialogue",
|
||||
help="Render a front-loaded intent dialogue guide for a skill package.",
|
||||
|
||||
Reference in New Issue
Block a user