feat: deepen discovery and review experience
This commit is contained in:
@@ -6,9 +6,9 @@
|
||||
"context_budget_tier": "production",
|
||||
"context_budget_limit": 1000,
|
||||
"skill_body_tokens": 824,
|
||||
"other_text_tokens": 271901,
|
||||
"other_text_tokens": 274311,
|
||||
"estimated_initial_load_tokens": 1000,
|
||||
"estimated_total_text_tokens": 272725,
|
||||
"estimated_total_text_tokens": 275135,
|
||||
"relevant_file_count": 165,
|
||||
"unused_resource_dirs": [],
|
||||
"quality_signal_points": 140,
|
||||
|
||||
@@ -100,6 +100,26 @@ def build_questions(focus: str) -> list[dict]:
|
||||
return base
|
||||
|
||||
|
||||
def build_opening_styles() -> list[dict]:
|
||||
return [
|
||||
{
|
||||
"label": "温柔陪伴型",
|
||||
"best_when": "用户想法还散、还在试探,或者需要先被接住。",
|
||||
"message": "我们先不急着把它说成一个很完整的 skill。你就像跟我聊天一样,先说说你最想让它以后稳稳接住哪类重复工作;如果它做得很理想,最后应该交回你一个什么结果。",
|
||||
},
|
||||
{
|
||||
"label": "专业教练型",
|
||||
"best_when": "用户目标比较明确,希望被高效带着走。",
|
||||
"message": "我们先把这件事讲清楚,再决定 skill 怎么设计。你先告诉我三件事:它要接住的重复任务是什么,别人通常会给它什么材料,最后你希望它交付什么结果。",
|
||||
},
|
||||
{
|
||||
"label": "共创伙伴型",
|
||||
"best_when": "用户已经有一些想法,希望一起打磨,不想被填表。",
|
||||
"message": "我们把这次当成一次共创。你先给我一个粗糙版本就行,我先帮你看它真正的核心任务是什么,再一起决定边界、结构和接下来最值的一步。",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def build_summary(skill_dir: Path) -> dict:
|
||||
skill_text = (skill_dir / "SKILL.md").read_text(encoding="utf-8")
|
||||
frontmatter, body = parse_frontmatter(skill_text)
|
||||
@@ -108,6 +128,7 @@ def build_summary(skill_dir: Path) -> dict:
|
||||
title = extract_title(body, name.replace("-", " ").title())
|
||||
focus = classify_focus(description)
|
||||
questions = build_questions(focus)
|
||||
opening_styles = build_opening_styles()
|
||||
output = {
|
||||
"capability_sentence": f"{title} should turn a recurring request into a reliable reusable output without widening the boundary unnecessarily.",
|
||||
"required_capture": [
|
||||
@@ -126,8 +147,20 @@ def build_summary(skill_dir: Path) -> dict:
|
||||
"title": title,
|
||||
"description": description,
|
||||
"focus": focus,
|
||||
"opening_frame": "Let's shape the skill around the real work, the desired outcome, and the standards you care about before we start adding structure.",
|
||||
"opening_frame": "Let's start from the real work, the result you care about, and the standards that matter here. We can make the structure clearer after that.",
|
||||
"reference_note": "If you already have examples you admire, bring them in. We will learn the pattern, not copy the source.",
|
||||
"conversation_path": [
|
||||
"Start with the user's own words, not package vocabulary.",
|
||||
"Reflect the job, output, and non-goals back in one clean sentence.",
|
||||
"Only then offer a tiny scaffold if it would help the user move faster.",
|
||||
],
|
||||
"opening_styles": opening_styles,
|
||||
"optional_scaffold": [
|
||||
"The repeated job it should take over",
|
||||
"The real inputs people will hand to it",
|
||||
"The useful output it should hand back",
|
||||
"What it should clearly refuse",
|
||||
],
|
||||
"questions": questions,
|
||||
"output": output,
|
||||
}
|
||||
@@ -143,20 +176,45 @@ def render_markdown(summary: dict) -> str:
|
||||
"",
|
||||
summary["opening_frame"],
|
||||
"",
|
||||
"## Why Start Here",
|
||||
"",
|
||||
"Use this short dialogue before deep authoring. The goal is to learn the real job, output, exclusions, and constraints so the first package is small but accurate.",
|
||||
"",
|
||||
"## Current Anchor",
|
||||
"",
|
||||
f"- Title: `{summary['title']}`",
|
||||
f"- Description: {summary['description']}",
|
||||
f"- Focus: `{summary['focus']}`",
|
||||
f"- Reference note: {summary['reference_note']}",
|
||||
"",
|
||||
"## Questions To Ask",
|
||||
"## Opening Tone Options",
|
||||
"",
|
||||
]
|
||||
for item in summary["opening_styles"]:
|
||||
lines.extend(
|
||||
[
|
||||
f"### {item['label']}",
|
||||
"",
|
||||
f"- Best when: {item['best_when']}",
|
||||
f"- Example: {item['message']}",
|
||||
"",
|
||||
]
|
||||
)
|
||||
lines.extend(
|
||||
[
|
||||
"## Conversation Path",
|
||||
"",
|
||||
]
|
||||
)
|
||||
for idx, item in enumerate(summary["conversation_path"], start=1):
|
||||
lines.append(f"{idx}. {item}")
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"## Why Start Here",
|
||||
"",
|
||||
"Use this short dialogue before deep authoring. The goal is to learn the real job, output, exclusions, and constraints so the first package is small but accurate.",
|
||||
"",
|
||||
"## Current Anchor",
|
||||
"",
|
||||
f"- Title: `{summary['title']}`",
|
||||
f"- Description: {summary['description']}",
|
||||
f"- Focus: `{summary['focus']}`",
|
||||
f"- Reference note: {summary['reference_note']}",
|
||||
"",
|
||||
"## Questions To Ask",
|
||||
"",
|
||||
]
|
||||
)
|
||||
for idx, item in enumerate(summary["questions"], start=1):
|
||||
lines.extend(
|
||||
[
|
||||
@@ -171,8 +229,11 @@ def render_markdown(summary: dict) -> str:
|
||||
"",
|
||||
f"- Capability sentence: {summary['output']['capability_sentence']}",
|
||||
f"- Recommended first gate: `{summary['output']['recommended_first_gate']}`",
|
||||
"- Tiny optional scaffold:",
|
||||
]
|
||||
)
|
||||
for item in summary["optional_scaffold"]:
|
||||
lines.append(f" - {item}")
|
||||
for item in summary["output"]["required_capture"]:
|
||||
lines.append(f"- Capture: `{item}`")
|
||||
return "\n".join(lines).strip() + "\n"
|
||||
|
||||
@@ -37,6 +37,12 @@ def load_manifest(path: Path) -> dict:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def load_json(path: Path) -> dict:
|
||||
if not path.exists():
|
||||
return {}
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def extract_sections(body: str) -> dict[str, str]:
|
||||
sections: dict[str, list[str]] = {}
|
||||
current = "_preamble"
|
||||
@@ -69,6 +75,8 @@ def direction(priority: int, title: str, why: str, actions: list[str], unlocks:
|
||||
"why": why,
|
||||
"actions": actions,
|
||||
"unlocks": unlocks,
|
||||
"do_now": "",
|
||||
"wait_on": "",
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +85,7 @@ def build_directions(skill_dir: Path) -> tuple[dict, list[dict]]:
|
||||
frontmatter, body = parse_frontmatter(skill_text)
|
||||
sections = extract_sections(body)
|
||||
manifest = load_manifest(skill_dir / "manifest.json")
|
||||
benchmark = load_json(skill_dir / "reports" / "github-benchmark-scan.json")
|
||||
description = frontmatter.get("description", "")
|
||||
maturity = manifest.get("maturity_tier", "scaffold")
|
||||
|
||||
@@ -109,6 +118,21 @@ def build_directions(skill_dir: Path) -> tuple[dict, list[dict]]:
|
||||
"Stronger execution quality without bloating the entrypoint.",
|
||||
)
|
||||
)
|
||||
if benchmark.get("repositories"):
|
||||
top_repo = benchmark["repositories"][0]
|
||||
candidates.append(
|
||||
direction(
|
||||
2,
|
||||
"Borrow one proven pattern on purpose",
|
||||
"You already have public benchmark objects. The next gain is to choose one pattern intentionally instead of absorbing everything loosely.",
|
||||
[
|
||||
f"Read the strongest pattern from {top_repo.get('full_name', 'the top benchmark repo')}.",
|
||||
"Decide whether to borrow method, structure, execution, or portability, but only one of them first.",
|
||||
"Record what you will not borrow so the package stays light.",
|
||||
],
|
||||
"A cleaner package shape with less accidental over-design.",
|
||||
)
|
||||
)
|
||||
if maturity == "scaffold":
|
||||
candidates.append(
|
||||
direction(
|
||||
@@ -169,11 +193,25 @@ def build_directions(skill_dir: Path) -> tuple[dict, list[dict]]:
|
||||
)
|
||||
|
||||
chosen = sorted(candidates, key=lambda item: item["priority"])[:3]
|
||||
for index, item in enumerate(chosen, start=1):
|
||||
item["do_now"] = (
|
||||
"Do this first."
|
||||
if index == 1
|
||||
else "Do this after the first move lands cleanly."
|
||||
)
|
||||
item["wait_on"] = (
|
||||
"Wait to add broader structure until this move clearly improves reliability."
|
||||
if index == 1
|
||||
else "Wait until the package has evidence that this extra structure is justified."
|
||||
)
|
||||
summary = {
|
||||
"skill_name": frontmatter.get("name", skill_dir.name),
|
||||
"description": description,
|
||||
"maturity_tier": maturity,
|
||||
"selection_rule": "Pick the three smallest next steps that increase reliability more than they increase context cost.",
|
||||
"recommended_now": chosen[0]["title"] if chosen else "",
|
||||
"recommended_now_why": chosen[0]["why"] if chosen else "",
|
||||
"defer_for_now": chosen[-1]["title"] if chosen else "",
|
||||
}
|
||||
return summary, chosen
|
||||
|
||||
@@ -186,6 +224,9 @@ def render_markdown(summary: dict, directions: list[dict]) -> str:
|
||||
"",
|
||||
f"- Maturity tier: `{summary['maturity_tier']}`",
|
||||
f"- Selection rule: {summary['selection_rule']}",
|
||||
f"- Start here: `{summary['recommended_now']}`",
|
||||
f"- Why first: {summary['recommended_now_why']}",
|
||||
f"- Defer for now: `{summary['defer_for_now']}`",
|
||||
"",
|
||||
"## Top 3 Next Moves",
|
||||
"",
|
||||
@@ -196,13 +237,15 @@ def render_markdown(summary: dict, directions: list[dict]) -> str:
|
||||
f"### {item['priority']}. {item['title']}",
|
||||
"",
|
||||
f"- Why now: {item['why']}",
|
||||
f"- Timing: {item['do_now']}",
|
||||
"- Recommended actions:",
|
||||
]
|
||||
)
|
||||
for action in item["actions"]:
|
||||
lines.append(f" - {action}")
|
||||
lines.append(f"- Unlocks: {item['unlocks']}")
|
||||
lines.append("")
|
||||
lines.append(f"- Unlocks: {item['unlocks']}")
|
||||
lines.append(f"- Wait on: {item['wait_on']}")
|
||||
lines.append("")
|
||||
return "\n".join(lines).strip() + "\n"
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,11 @@ def load_specific_promotion(skill_dir: Path) -> dict:
|
||||
return payload if isinstance(payload, dict) else {}
|
||||
|
||||
|
||||
def load_benchmark_summary(skill_dir: Path) -> dict:
|
||||
payload = load_json(skill_dir / "reports" / "github-benchmark-scan.json")
|
||||
return payload if isinstance(payload, dict) else {}
|
||||
|
||||
|
||||
def ensure_report_inputs(skill_dir: Path) -> dict:
|
||||
overview_json = skill_dir / "reports" / "skill-overview.json"
|
||||
intent_json = skill_dir / "reports" / "intent-dialogue.json"
|
||||
@@ -62,6 +67,7 @@ def ensure_report_inputs(skill_dir: Path) -> dict:
|
||||
baseline = load_baseline_summary(skill_dir)
|
||||
compare = load_specific_compare(skill_dir)
|
||||
promotion = load_specific_promotion(skill_dir)
|
||||
benchmark = load_benchmark_summary(skill_dir)
|
||||
return {
|
||||
"overview": overview,
|
||||
"intent": intent,
|
||||
@@ -71,6 +77,7 @@ def ensure_report_inputs(skill_dir: Path) -> dict:
|
||||
"baseline": baseline,
|
||||
"compare": compare,
|
||||
"promotion": promotion,
|
||||
"benchmark": benchmark,
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +119,19 @@ def compare_rows(compare: dict) -> list[dict]:
|
||||
return rows
|
||||
|
||||
|
||||
def benchmark_cards(benchmark: dict) -> list[dict]:
|
||||
cards = []
|
||||
for repo in benchmark.get("repositories", [])[:3]:
|
||||
cards.append(
|
||||
{
|
||||
"name": repo.get("full_name", "Unknown repo"),
|
||||
"borrow": repo.get("borrow", [])[:2],
|
||||
"avoid": repo.get("avoid", [])[:1],
|
||||
}
|
||||
)
|
||||
return cards
|
||||
|
||||
|
||||
def render_html(report: dict) -> str:
|
||||
overview = report["overview"]
|
||||
intent = report["intent"]
|
||||
@@ -122,8 +142,10 @@ def render_html(report: dict) -> str:
|
||||
baseline = report.get("baseline", {})
|
||||
compare = report.get("compare", {})
|
||||
promotion = report.get("promotion", {})
|
||||
benchmark = report.get("benchmark", {})
|
||||
architecture = architecture_steps(overview)
|
||||
compare_table_rows = compare_rows(compare)
|
||||
benchmark_rows = benchmark_cards(benchmark)
|
||||
|
||||
strength_items = "".join(f"<li>{html.escape(item)}</li>" for item in overview.get("strengths", []))
|
||||
logic_items = "".join(f"<li>{html.escape(item)}</li>" for item in overview.get("logic_steps", []))
|
||||
@@ -225,6 +247,23 @@ def render_html(report: dict) -> str:
|
||||
else:
|
||||
promotion_html = "<p class='minor'>No promotion summary is attached to this package yet.</p>"
|
||||
|
||||
benchmark_html = ""
|
||||
if benchmark_rows:
|
||||
benchmark_html = "".join(
|
||||
(
|
||||
"<div class='direction-card'>"
|
||||
f"<h3>{html.escape(item['name'])}</h3>"
|
||||
"<p><strong>Borrow now</strong></p>"
|
||||
+ ("<ul>" + "".join(f"<li>{html.escape(borrow)}</li>" for borrow in item.get('borrow', [])) + "</ul>" if item.get("borrow") else "<p>No borrow cues recorded.</p>")
|
||||
+ "<p><strong>Avoid</strong></p>"
|
||||
+ ("<ul>" + "".join(f"<li>{html.escape(avoid)}</li>" for avoid in item.get('avoid', [])) + "</ul>" if item.get("avoid") else "<p>No avoid cues recorded.</p>")
|
||||
+ "</div>"
|
||||
)
|
||||
for item in benchmark_rows
|
||||
)
|
||||
else:
|
||||
benchmark_html = "<p class='minor'>No GitHub benchmark scan has been attached to this package yet.</p>"
|
||||
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -414,6 +453,21 @@ def render_html(report: dict) -> str:
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid">
|
||||
<div class="panel">
|
||||
<h2>Reference coach</h2>
|
||||
<div class="direction-grid">{benchmark_html}</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<h2>Decide before you deepen</h2>
|
||||
<ul>
|
||||
<li>Choose one pattern to borrow on purpose, not three at once.</li>
|
||||
<li>State one thing this skill will not inherit from the benchmark objects.</li>
|
||||
<li>Only deepen the package after that choice is visible in the boundary or execution flow.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Top three next moves</h2>
|
||||
<div class="direction-grid">{direction_cards}</div>
|
||||
|
||||
@@ -66,6 +66,10 @@ def load_json(path: Path) -> dict:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def load_benchmark(skill_dir: Path) -> dict:
|
||||
return load_json(skill_dir / "reports" / "github-benchmark-scan.json")
|
||||
|
||||
|
||||
def extract_title(body: str, fallback: str) -> str:
|
||||
for line in body.splitlines():
|
||||
if line.startswith("# "):
|
||||
@@ -179,6 +183,27 @@ def card_items(interface_data: dict, logic_steps: list[str], package_map: list[d
|
||||
]
|
||||
|
||||
|
||||
def introduction_lines(description: str) -> list[str]:
|
||||
return [
|
||||
f"This skill is trying to quietly take over: {description}",
|
||||
"Start by clarifying the recurring job, the real input shape, and the output that lets the next person keep moving.",
|
||||
"If the idea is still fuzzy, use the intent dialogue first and let the structure come second.",
|
||||
]
|
||||
|
||||
|
||||
def benchmark_highlights(benchmark: dict) -> list[dict]:
|
||||
highlights = []
|
||||
for repo in benchmark.get("repositories", [])[:3]:
|
||||
highlights.append(
|
||||
{
|
||||
"name": repo.get("full_name", "Unknown repo"),
|
||||
"borrow": repo.get("borrow", [])[:2],
|
||||
"avoid": repo.get("avoid", [])[:1],
|
||||
}
|
||||
)
|
||||
return highlights
|
||||
|
||||
|
||||
def build_summary(skill_dir: Path) -> dict:
|
||||
skill_text = (skill_dir / "SKILL.md").read_text(encoding="utf-8")
|
||||
frontmatter, body = parse_frontmatter(skill_text)
|
||||
@@ -195,6 +220,7 @@ def build_summary(skill_dir: Path) -> dict:
|
||||
usage_steps = summarize_usage(sections, default_prompt, description)
|
||||
package_map = package_entries(skill_dir)
|
||||
strengths = derive_strengths(skill_dir, manifest)
|
||||
benchmark = load_benchmark(skill_dir)
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
@@ -206,6 +232,8 @@ def build_summary(skill_dir: Path) -> dict:
|
||||
"package_map": package_map,
|
||||
"strengths": strengths,
|
||||
"cards": card_items(interface_data, logic_steps, package_map, usage_steps, description),
|
||||
"introduction": introduction_lines(description),
|
||||
"benchmark_highlights": benchmark_highlights(benchmark),
|
||||
"metadata": {
|
||||
"canonical_format": interface_data.get("compatibility", {}).get("canonical_format", "agent-skills"),
|
||||
"targets": interface_data.get("compatibility", {}).get("adapter_targets", []),
|
||||
@@ -232,10 +260,23 @@ def render_html(summary: dict) -> str:
|
||||
target_badges = "".join(f"<span>{html.escape(str(target))}</span>" for target in summary["metadata"]["targets"])
|
||||
cards_html = "".join(render_card_body(card) for card in summary["cards"])
|
||||
strengths_html = "".join(f"<li>{html.escape(item)}</li>" for item in summary["strengths"])
|
||||
introduction_html = "".join(f"<li>{html.escape(item)}</li>" for item in summary.get("introduction", []))
|
||||
package_rows = "".join(
|
||||
f"<tr><td>{html.escape(item['path'])}</td><td>{html.escape(item['label'])}</td><td>{html.escape(item['kind'])}</td></tr>"
|
||||
for item in summary["package_map"]
|
||||
)
|
||||
benchmark_cards = "".join(
|
||||
(
|
||||
"<div class='card'>"
|
||||
f"<h3>{html.escape(item['name'])}</h3>"
|
||||
"<p><strong>Borrow now</strong></p>"
|
||||
+ ("<ul>" + "".join(f"<li>{html.escape(borrow)}</li>" for borrow in item.get("borrow", [])) + "</ul>" if item.get("borrow") else "<p>None yet.</p>")
|
||||
+ "<p><strong>Avoid</strong></p>"
|
||||
+ ("<ul>" + "".join(f"<li>{html.escape(avoid)}</li>" for avoid in item.get("avoid", [])) + "</ul>" if item.get("avoid") else "<p>None yet.</p>")
|
||||
+ "</div>"
|
||||
)
|
||||
for item in summary.get("benchmark_highlights", [])
|
||||
)
|
||||
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@@ -411,6 +452,16 @@ def render_html(summary: dict) -> str:
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2>How to introduce this skill</h2>
|
||||
<p>Use this section when a first-time reader needs the shape and intent quickly, before reading the full package.</p>
|
||||
</div>
|
||||
<ul class="strengths">{introduction_html}</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="section-head">
|
||||
<div>
|
||||
@@ -437,6 +488,16 @@ def render_html(summary: dict) -> str:
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2>Patterns worth borrowing now</h2>
|
||||
<p>If a GitHub benchmark scan exists, surface the strongest borrow and avoid cues here instead of hiding them in raw report files.</p>
|
||||
</div>
|
||||
<div class="cards">{benchmark_cards or "<div class='card'><p>No benchmark scan recorded yet. Run the GitHub benchmark scan first.</p></div>"}</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
-4
@@ -203,11 +203,12 @@ 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("I will also scan a few strong public GitHub references first, so we can borrow the right patterns without copying the source.\n")
|
||||
sys.stderr.write("Let's start gently and shape this skill around the real work, the outcome, and the standards you actually care about.\n")
|
||||
sys.stderr.write("You do not need a perfect brief. A rough description is enough, and I will help tighten it.\n")
|
||||
sys.stderr.write("I will also look at a few strong public GitHub references first, so we can borrow proven 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.")
|
||||
job = args.job or prompt_with_default("What repeated work do you most want this skill to quietly take off your hands", "Turn a repeated workflow into a reusable skill.")
|
||||
primary_output = args.primary_output or prompt_with_default("If it works well, what should it hand back so you can keep moving", "A reusable skill package.")
|
||||
description = args.description or f"{job.rstrip('.')} Primary output: {primary_output.rstrip('.')}."
|
||||
inferred_archetype, archetype_reason = infer_archetype(job, description)
|
||||
archetype = args.archetype or prompt_with_default("Archetype (scaffold/production/library/governed)", inferred_archetype)
|
||||
@@ -226,6 +227,7 @@ def command_quickstart(args: argparse.Namespace) -> int:
|
||||
)
|
||||
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")
|
||||
sys.stderr.write("I will use that query to pull three strong public examples, then surface only the patterns worth borrowing or avoiding.\n")
|
||||
title = args.title or name.replace("-", " ").title()
|
||||
guidance = archetype_guidance(archetype)
|
||||
cmd = [
|
||||
@@ -295,6 +297,7 @@ def command_quickstart(args: argparse.Namespace) -> int:
|
||||
"Use reports/iteration-directions.md to choose only one high-value next move before adding more files.",
|
||||
],
|
||||
"borrow_prompt": benchmark_scan.get("borrow_prompt"),
|
||||
"experience_note": "The first pass should feel more like guided co-creation than filling out a worksheet. Use the reports to explain, choose, and only then deepen the package.",
|
||||
},
|
||||
}
|
||||
print(json.dumps(report, ensure_ascii=False, indent=2))
|
||||
|
||||
@@ -37,6 +37,8 @@ def main() -> None:
|
||||
created = Path(init_payload["root"])
|
||||
report = run("iteration-directions", str(created))
|
||||
assert report["summary"]["selection_rule"], report
|
||||
assert report["summary"]["recommended_now"], report
|
||||
assert report["summary"]["defer_for_now"], report
|
||||
assert len(report["directions"]) == 3, report
|
||||
titles = {item["title"] for item in report["directions"]}
|
||||
assert "Tighten trigger and exclusions" in titles or "Add the first execution asset" in titles, titles
|
||||
|
||||
@@ -45,6 +45,7 @@ def main() -> None:
|
||||
html_text = html_path.read_text(encoding="utf-8")
|
||||
assert "Architecture at a glance" in html_text, html_text[:500]
|
||||
assert "Compare view" in html_text, html_text[:500]
|
||||
assert "Reference coach" in html_text, html_text[:900]
|
||||
assert "Top three next moves" in html_text, html_text[:500]
|
||||
print(json.dumps({"ok": True}, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ def main() -> None:
|
||||
assert "Skill Overview" in report_html, report_html[:200]
|
||||
assert "Architecture" in report_html, report_html[:400]
|
||||
assert "Why It Works" in report_html, report_html[:600]
|
||||
assert "How to introduce this skill" in report_html, report_html[:900]
|
||||
assert "Patterns worth borrowing now" in report_html, report_html[:1200]
|
||||
|
||||
intent_text = (created / "reports" / "intent-dialogue.md").read_text(encoding="utf-8")
|
||||
assert "Questions To Ask" in intent_text, intent_text[:400]
|
||||
|
||||
Reference in New Issue
Block a user