feat: add intent dialogue and iteration directions
This commit is contained in:
@@ -8,4 +8,5 @@ tests/tmp_cli/
|
||||
tests/tmp_skill_overview/
|
||||
tests/tmp_skill_preview/
|
||||
tests/tmp_reference_scan/
|
||||
tests/tmp_iteration_directions/
|
||||
reports/release_snapshots/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
PYTHON ?= python3
|
||||
|
||||
.PHONY: eval eval-suite route-scorecard route-confusion-check description-optimization judge-blind-eval description-optimization-check promotion-check yao-cli-check skill-overview-check reference-scan-check description-drift-history iteration-ledger results-panel regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check snapshot-check validate lint governance-check resource-boundary-check quality-check test clean
|
||||
.PHONY: eval eval-suite route-scorecard route-confusion-check description-optimization judge-blind-eval description-optimization-check promotion-check yao-cli-check skill-overview-check reference-scan-check iteration-directions-check description-drift-history iteration-ledger results-panel regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check snapshot-check validate lint governance-check resource-boundary-check quality-check test clean
|
||||
|
||||
eval:
|
||||
$(PYTHON) scripts/trigger_eval.py --description-file evals/improved_description.txt --cases evals/trigger_cases.json --baseline-description-file evals/baseline_description.txt
|
||||
@@ -35,6 +35,9 @@ skill-overview-check:
|
||||
reference-scan-check:
|
||||
$(PYTHON) tests/verify_reference_scan.py
|
||||
|
||||
iteration-directions-check:
|
||||
$(PYTHON) tests/verify_iteration_directions.py
|
||||
|
||||
description-drift-history:
|
||||
$(PYTHON) scripts/render_description_drift_history.py
|
||||
|
||||
@@ -83,7 +86,7 @@ resource-boundary-check:
|
||||
quality-check:
|
||||
$(PYTHON) tests/verify_quality_checks.py
|
||||
|
||||
test: eval eval-suite route-scorecard route-confusion-check description-optimization description-optimization-check promotion-check yao-cli-check skill-overview-check reference-scan-check description-drift-history iteration-ledger regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check snapshot-check validate lint governance-check resource-boundary-check quality-check
|
||||
test: eval eval-suite route-scorecard route-confusion-check description-optimization description-optimization-check promotion-check yao-cli-check skill-overview-check reference-scan-check iteration-directions-check description-drift-history iteration-ledger regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check snapshot-check validate lint governance-check resource-boundary-check quality-check
|
||||
|
||||
clean:
|
||||
rm -rf dist tests/tmp tests/tmp_snapshot
|
||||
rm -rf dist tests/tmp tests/tmp_snapshot tests/tmp_cli tests/tmp_skill_overview tests/tmp_reference_scan tests/tmp_iteration_directions
|
||||
|
||||
@@ -19,8 +19,10 @@ It turns rough workflows, transcripts, prompts, notes, and runbooks into reusabl
|
||||
- a clear trigger surface
|
||||
- a lean `SKILL.md`
|
||||
- optional references, scripts, and evals
|
||||
- a front-loaded intent dialogue before deep authoring
|
||||
- a controlled benchmark scan before deep authoring
|
||||
- a generated visual HTML overview for each newly initialized skill
|
||||
- three high-value next iteration directions after the first package is created
|
||||
- neutral source metadata plus client-specific adapters
|
||||
- governance, promotion, and portability checks built into the default flow
|
||||
|
||||
@@ -47,18 +49,21 @@ Read it in 10 seconds:
|
||||
## Quick Start
|
||||
|
||||
1. Describe the workflow, prompt set, or repeated task you want to turn into a skill.
|
||||
2. Run a short reference scan with external benchmarks first, then use local files only for fit and privacy checks.
|
||||
3. Use `yao-meta-skill` to generate or improve the package in scaffold, production, or library mode.
|
||||
4. Run `context_sizer.py`, `resource_boundary_check.py`, `governance_check.py`, `trigger_eval.py`, and `cross_packager.py` as needed to validate and export the result.
|
||||
2. Start with a short intent dialogue so the real job, outputs, exclusions, and constraints are explicit.
|
||||
3. Run a short reference scan with external benchmarks first, then use local files only for fit and privacy checks.
|
||||
4. Use `yao-meta-skill` to generate or improve the package in scaffold, production, or library mode.
|
||||
5. Review the generated `reports/intent-dialogue.md`, `reports/skill-overview.html`, and `reports/iteration-directions.md` before adding more structure.
|
||||
|
||||
Or use the unified authoring CLI:
|
||||
|
||||
```bash
|
||||
python3 scripts/yao.py init my-skill --description "Describe what the skill does."
|
||||
python3 scripts/yao.py intent-dialogue my-skill
|
||||
python3 scripts/yao.py reference-scan my-skill \
|
||||
--external-reference "World Class Method::method::Borrow a tight evaluation loop.::Do not copy heavy process." \
|
||||
--local-constraint "Current Library Naming::structure::Keep naming aligned with the local skill library.::Do not inherit private references."
|
||||
python3 scripts/yao.py skill-report my-skill
|
||||
python3 scripts/yao.py iteration-directions my-skill
|
||||
python3 scripts/yao.py package . --platform generic --output-dir dist
|
||||
```
|
||||
|
||||
@@ -201,9 +206,11 @@ The design logic is simple:
|
||||
The repository now treats method as a first-class asset instead of scattered guidance.
|
||||
|
||||
- [Skill Engineering Method](references/skill-engineering-method.md)
|
||||
- [Intent Dialogue](references/intent-dialogue.md)
|
||||
- [Reference Scan Strategy](references/reference-scan.md)
|
||||
- [Skill Archetypes](references/skill-archetypes.md)
|
||||
- [Gate Selection](references/gate-selection.md)
|
||||
- [Iteration Philosophy](references/iteration-philosophy.md)
|
||||
- [Non-Skill Decision Tree](references/non-skill-decision-tree.md)
|
||||
- [Regression Cause Taxonomy](references/regression-cause-taxonomy.md)
|
||||
- [Human Review Template](references/human-review-template.md)
|
||||
|
||||
@@ -28,12 +28,13 @@ Mode rules: [Operating Modes](references/operating-modes.md), [QA Ladder](refere
|
||||
## Compact Workflow
|
||||
|
||||
1. Decide whether the request should become a skill, then choose the lightest archetype.
|
||||
2. Run a short reference scan with external benchmark objects first, then use local files only for fit, privacy, and compatibility calibration.
|
||||
3. Capture the recurring job, outputs, trigger phrases, and exclusions.
|
||||
2. Run a short intent dialogue to capture the recurring job, outputs, trigger phrases, exclusions, and constraints.
|
||||
3. Run a short reference scan with external benchmark objects first, then use local files only for fit, privacy, and compatibility calibration.
|
||||
4. Write the `description` early, then test route quality before expanding the package.
|
||||
5. Add only the folders and gates that earn their keep: `trigger_eval.py`, `optimize_description.py`, `judge_blind_eval.py`, `resource_boundary_check.py`, `governance_check.py`, `cross_packager.py`.
|
||||
6. After the first package exists, surface the top three next iteration directions instead of expanding the skill in every direction at once.
|
||||
|
||||
Playbooks: [Skill Engineering Method](references/skill-engineering-method.md), [Reference Scan Strategy](references/reference-scan.md), [Skill Archetypes](references/skill-archetypes.md), [Gate Selection](references/gate-selection.md), [Non-Skill Decision Tree](references/non-skill-decision-tree.md), [Operating Modes](references/operating-modes.md), [Trigger And Eval Playbook](references/eval-playbook.md).
|
||||
Playbooks: [Skill Engineering Method](references/skill-engineering-method.md), [Intent Dialogue](references/intent-dialogue.md), [Reference Scan Strategy](references/reference-scan.md), [Skill Archetypes](references/skill-archetypes.md), [Gate Selection](references/gate-selection.md), [Iteration Philosophy](references/iteration-philosophy.md), [Non-Skill Decision Tree](references/non-skill-decision-tree.md), [Operating Modes](references/operating-modes.md), [Trigger And Eval Playbook](references/eval-playbook.md).
|
||||
|
||||
## Output Contract
|
||||
|
||||
@@ -49,8 +50,10 @@ Unless the user asks otherwise, produce:
|
||||
|
||||
- [Skill Engineering Method](references/skill-engineering-method.md)
|
||||
- [Reference Scan Strategy](references/reference-scan.md)
|
||||
- [Intent Dialogue](references/intent-dialogue.md)
|
||||
- [Skill Archetypes](references/skill-archetypes.md)
|
||||
- [Gate Selection](references/gate-selection.md)
|
||||
- [Iteration Philosophy](references/iteration-philosophy.md)
|
||||
- [Non-Skill Decision Tree](references/non-skill-decision-tree.md)
|
||||
- [Operating Modes](references/operating-modes.md)
|
||||
- [Governance Model](references/governance.md)
|
||||
|
||||
@@ -9,8 +9,10 @@ Il transforme des workflows bruts, des transcripts, des prompts, des notes et de
|
||||
- une surface de déclenchement claire
|
||||
- un `SKILL.md` léger
|
||||
- des references, scripts et evals optionnels
|
||||
- un court dialogue d'intention avant l'authoring approfondi
|
||||
- un benchmark/reference scan contrôlé avant l'authoring profond
|
||||
- un rapport HTML minimaliste en fond blanc généré automatiquement pour chaque nouveau skill
|
||||
- trois directions d'itération à plus forte valeur après la première création
|
||||
- des métadonnées sources neutres et des adaptateurs spécifiques au client
|
||||
- des contrôles de gouvernance, de promotion et de portabilité intégrés au flux standard
|
||||
|
||||
@@ -37,9 +39,10 @@ Lecture en 10 secondes :
|
||||
## Quick Start
|
||||
|
||||
1. Décrivez le workflow, l'ensemble de prompts ou la tâche répétée que vous voulez transformer en skill.
|
||||
2. Lancez un court reference scan en privilégiant GitHub et les objets publics de référence ; les fichiers locaux ne servent ensuite qu'à l'ajustement, à la confidentialité et à la compatibilité.
|
||||
3. Utilisez `yao-meta-skill` pour générer ou améliorer le paquet en mode scaffold, production ou library.
|
||||
4. Chaque nouveau skill reçoit aussi `reports/skill-overview.html` et `reports/reference-scan.md`, pour comprendre rapidement son architecture, sa logique, son usage et ses références utiles.
|
||||
2. Commencez par un court dialogue d'intention pour clarifier le vrai job, les sorties, les exclusions et les contraintes.
|
||||
3. Lancez ensuite un short reference scan en privilégiant GitHub et les objets publics de référence ; les fichiers locaux ne servent ensuite qu'à l'ajustement, à la confidentialité et à la compatibilité.
|
||||
4. Utilisez `yao-meta-skill` pour générer ou améliorer le paquet en mode scaffold, production ou library.
|
||||
5. Chaque nouveau skill reçoit aussi `reports/intent-dialogue.md`, `reports/skill-overview.html`, `reports/reference-scan.md` et `reports/iteration-directions.md`.
|
||||
|
||||
## Results
|
||||
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
- 明確なトリガー面
|
||||
- 軽量な `SKILL.md`
|
||||
- 必要に応じた references、scripts、evals
|
||||
- 深い authoring の前に行う短い intent dialogue
|
||||
- 深い authoring の前に、制御された benchmark/reference scan を 1 回行う
|
||||
- 新しい skill ごとに、白背景の簡潔な HTML overview を自動生成
|
||||
- 初回作成後に自動で提示される 3 つの高価値な次の iteration direction
|
||||
- 中立的なソースメタデータとクライアント別アダプタ
|
||||
- ガバナンス、昇格判定、portability チェックを標準フローに内蔵
|
||||
|
||||
@@ -37,9 +39,10 @@ flowchart LR
|
||||
## Quick Start
|
||||
|
||||
1. skill 化したい workflow、prompt 集合、または反復タスクを説明します。
|
||||
2. まず短い reference scan を行い、GitHub や世界トップ級の公開対象を主参照にし、ローカル資産は適合確認と privacy 調整だけに使います。
|
||||
3. `yao-meta-skill` を使って scaffold、production、library のいずれかのモードでパッケージを生成または改善します。
|
||||
4. 新しく作成した skill には `reports/skill-overview.html` と `reports/reference-scan.md` が付き、構造、ロジック、使い方、参考対象をすぐ確認できます。
|
||||
2. まず短い intent dialogue で、実際の job、outputs、boundary、constraints を明確にします。
|
||||
3. 次に短い reference scan を行い、GitHub や世界トップ級の公開対象を主参照にし、ローカル資産は適合確認と privacy 調整だけに使います。
|
||||
4. `yao-meta-skill` を使って scaffold、production、library のいずれかのモードでパッケージを生成または改善します。
|
||||
5. 新しく作成した skill には `reports/intent-dialogue.md`、`reports/skill-overview.html`、`reports/reference-scan.md`、`reports/iteration-directions.md` が付きます。
|
||||
|
||||
## Results
|
||||
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
- понятной поверхностью срабатывания
|
||||
- компактным `SKILL.md`
|
||||
- необязательными references, scripts и evals
|
||||
- коротким intent dialogue перед глубокой разработкой
|
||||
- контролируемым benchmark/reference scan до глубокого authoring
|
||||
- автоматически создаваемым минималистичным HTML-обзором на белом фоне для каждого нового skill
|
||||
- тремя наиболее ценными направлениями следующей итерации после первого создания
|
||||
- нейтральными исходными метаданными и клиентскими адаптерами
|
||||
- встроенными проверками governance, promotion и portability в стандартном потоке
|
||||
|
||||
@@ -37,9 +39,10 @@ flowchart LR
|
||||
## Quick Start
|
||||
|
||||
1. Опишите workflow, набор prompts или повторяющуюся задачу, которую хотите превратить в skill.
|
||||
2. Сначала выполните короткий reference scan, где основными источниками будут GitHub и сильные публичные эталоны, а локальные файлы будут использоваться только для адаптации, приватности и совместимости.
|
||||
3. Используйте `yao-meta-skill`, чтобы сгенерировать или улучшить пакет в режиме scaffold, production или library.
|
||||
4. Каждый новый skill также получает `reports/skill-overview.html` и `reports/reference-scan.md`, чтобы быстро понять архитектуру, логику, способ использования и полезные ориентиры.
|
||||
2. Сначала проведите короткий intent dialogue, чтобы уточнить реальную job-to-be-done, outputs, exclusions и constraints.
|
||||
3. Затем выполните короткий reference scan, где основными источниками будут GitHub и сильные публичные эталоны, а локальные файлы будут использоваться только для адаптации, приватности и совместимости.
|
||||
4. Используйте `yao-meta-skill`, чтобы сгенерировать или улучшить пакет в режиме scaffold, production или library.
|
||||
5. Каждый новый skill также получает `reports/intent-dialogue.md`, `reports/skill-overview.html`, `reports/reference-scan.md` и `reports/iteration-directions.md`.
|
||||
|
||||
## Results
|
||||
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
- 清晰的触发面
|
||||
- 精简的 `SKILL.md`
|
||||
- 可选的 references、scripts 和 evals
|
||||
- 深度起草前先做一轮意图对话,补齐真实任务、输出物和边界
|
||||
- 深度起草前先做一轮受控的 benchmark/reference scan
|
||||
- 新建 skill 时自动生成一份极简白底 HTML 可视化说明
|
||||
- 首次建包后会自动给出 3 个最有价值的下一步迭代方向
|
||||
- 中性的源元数据以及面向不同客户端的适配层
|
||||
- 内建的治理、晋升和 portability 检查
|
||||
|
||||
@@ -37,9 +39,10 @@ flowchart LR
|
||||
## Quick Start
|
||||
|
||||
1. 先描述你想沉淀成 skill 的 workflow、prompt 集合或重复任务。
|
||||
2. 先做一轮简短的参考扫描,以 GitHub 和世界级公开对象为主来源,本地文件只做适配和隐私校准。
|
||||
3. 使用 `yao-meta-skill` 以 scaffold、production 或 library 模式生成或改进 skill 包。
|
||||
4. 新建 skill 后,会默认附带 `reports/skill-overview.html` 和 `reports/reference-scan.md`,方便理解架构、逻辑、使用方法和可借鉴对象。
|
||||
2. 先做一轮简短的意图对话,把真实任务、输出物、边界和约束说清楚。
|
||||
3. 再做一轮参考扫描,以 GitHub 和世界级公开对象为主来源,本地文件只做适配和隐私校准。
|
||||
4. 使用 `yao-meta-skill` 以 scaffold、production 或 library 模式生成或改进 skill 包。
|
||||
5. 新建 skill 后,会默认附带 `reports/intent-dialogue.md`、`reports/skill-overview.html`、`reports/reference-scan.md` 和 `reports/iteration-directions.md`,方便理解架构、逻辑、使用方法、可借鉴对象以及下一步最值的 3 个迭代方向。
|
||||
|
||||
## Results
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Intent Dialogue
|
||||
|
||||
Use a short intent dialogue before deep authoring so the first version of the skill is anchored in the real job rather than in a guessed prompt shape.
|
||||
|
||||
## Why This Step Exists
|
||||
|
||||
- raw workflow material is often incomplete, mixed, or ambiguous
|
||||
- the wrong boundary chosen early is expensive to repair later
|
||||
- good trigger design depends on knowing what should not route here
|
||||
- execution assets should follow confirmed outputs, not assumptions
|
||||
|
||||
## What To Capture
|
||||
|
||||
Ask only the questions that change the package design.
|
||||
|
||||
1. What recurring job should this skill own?
|
||||
2. What inputs will people actually hand to it?
|
||||
3. What outputs should it produce every time?
|
||||
4. What near-neighbor requests should stay out of scope?
|
||||
5. What quality bar matters most: speed, consistency, auditability, portability, or governance?
|
||||
6. What assets already exist: docs, scripts, templates, examples, or prior prompts?
|
||||
7. What constraints matter: privacy, naming, local library fit, or target environments?
|
||||
|
||||
## Interview Rule
|
||||
|
||||
- prefer `5-7` sharp questions over a long discovery questionnaire
|
||||
- ask boundary questions early
|
||||
- ask output questions before architecture questions
|
||||
- stop once the skill can be described clearly in one sentence
|
||||
|
||||
## Output
|
||||
|
||||
The dialogue should produce:
|
||||
|
||||
- one clear capability sentence
|
||||
- a list of real inputs
|
||||
- a list of required outputs
|
||||
- a short exclusion list
|
||||
- one recommended archetype
|
||||
- one recommended first evaluation target
|
||||
|
||||
## Failure Pattern
|
||||
|
||||
Do not continue into full authoring when the dialogue still leaves these unresolved:
|
||||
|
||||
- whether the request is really reusable
|
||||
- which near-neighbor requests should not trigger
|
||||
- what concrete deliverable the skill must return
|
||||
@@ -0,0 +1,30 @@
|
||||
# Iteration Philosophy
|
||||
|
||||
The first skill package is a routeable baseline, not the final answer.
|
||||
|
||||
## Principle
|
||||
|
||||
Improve the skill by the smallest change that increases reliability more than it increases context cost.
|
||||
|
||||
## What Good Iteration Looks Like
|
||||
|
||||
- tighten boundary before adding prose
|
||||
- improve description before enlarging the file tree
|
||||
- add references only when they remove ambiguity
|
||||
- add scripts only when deterministic logic repeats
|
||||
- add gates only when risk justifies maintenance cost
|
||||
- prefer one strong next step over five vague upgrades
|
||||
|
||||
## Default Priority Order
|
||||
|
||||
1. trigger clarity and exclusions
|
||||
2. execution assets that remove repeated manual work
|
||||
3. promotion, governance, and portability only when reuse justifies them
|
||||
|
||||
## First-Version Rule
|
||||
|
||||
After the initial package is created, always surface the three highest-value next iteration directions. This keeps the author focused on the best improvement path instead of expanding the skill in every direction at once.
|
||||
|
||||
## Anti-Pattern
|
||||
|
||||
Do not treat iteration as "make the package bigger." A larger package is only better when routing, execution, or governance becomes materially more reliable.
|
||||
@@ -5,11 +5,13 @@ This doctrine defines the default method for turning messy workflow material int
|
||||
## Core Loop
|
||||
|
||||
1. Decide whether the request should become a skill at all.
|
||||
2. Choose the smallest viable archetype.
|
||||
3. Set one clear capability boundary.
|
||||
4. Write and test the trigger description before expanding the body.
|
||||
5. Add only the gates that match the risk.
|
||||
6. Package and govern the skill only as far as real reuse demands.
|
||||
2. Run a short intent dialogue to capture the real job, outputs, exclusions, and constraints.
|
||||
3. Choose the smallest viable archetype.
|
||||
4. Set one clear capability boundary.
|
||||
5. Write and test the trigger description before expanding the body.
|
||||
6. Add only the gates that match the risk.
|
||||
7. Ship the first routeable package, then pick the three highest-value next iteration directions.
|
||||
8. Package and govern the skill only as far as real reuse demands.
|
||||
|
||||
## Phase 1: Qualification
|
||||
|
||||
@@ -31,7 +33,19 @@ Reject skill creation when the request is only:
|
||||
|
||||
See [Non-Skill Decision Tree](non-skill-decision-tree.md).
|
||||
|
||||
## Phase 2: Archetype Selection
|
||||
## Phase 2: Intent Dialogue
|
||||
|
||||
Before deep authoring, ask only the questions that change the package design.
|
||||
|
||||
- what recurring job should the skill own
|
||||
- what real inputs will users hand to it
|
||||
- what outputs must it produce
|
||||
- what near-neighbor requests should stay out of scope
|
||||
- what constraints matter: privacy, naming, portability, governance, or local fit
|
||||
|
||||
See [Intent Dialogue](intent-dialogue.md).
|
||||
|
||||
## Phase 3: Archetype Selection
|
||||
|
||||
Choose the lightest archetype that fits the job.
|
||||
|
||||
@@ -42,7 +56,7 @@ Choose the lightest archetype that fits the job.
|
||||
|
||||
See [Skill Archetypes](skill-archetypes.md).
|
||||
|
||||
## Phase 3: Boundary Design
|
||||
## Phase 4: Boundary Design
|
||||
|
||||
Every skill should answer four questions clearly:
|
||||
|
||||
@@ -53,7 +67,7 @@ Every skill should answer four questions clearly:
|
||||
|
||||
Boundary work comes before polishing prose.
|
||||
|
||||
## Phase 4: Reference Scan
|
||||
## Phase 5: Reference Scan
|
||||
|
||||
Run a short benchmark pass before deep authoring.
|
||||
|
||||
@@ -66,7 +80,7 @@ Run a short benchmark pass before deep authoring.
|
||||
|
||||
See [Reference Scan Strategy](reference-scan.md).
|
||||
|
||||
## Phase 5: Trigger-First Authoring
|
||||
## Phase 6: Trigger-First Authoring
|
||||
|
||||
Author the frontmatter `description` before expanding the body.
|
||||
|
||||
@@ -84,7 +98,7 @@ Trigger quality is improved through:
|
||||
- adversarial holdout
|
||||
- route confusion
|
||||
|
||||
## Phase 6: Gate Selection
|
||||
## Phase 7: Gate Selection
|
||||
|
||||
Add gates by risk, not by habit.
|
||||
|
||||
@@ -95,7 +109,18 @@ Add gates by risk, not by habit.
|
||||
|
||||
See [Gate Selection](gate-selection.md).
|
||||
|
||||
## Phase 7: Promotion
|
||||
## Phase 8: First Iteration Philosophy
|
||||
|
||||
The first package is a routeable baseline, not the final answer.
|
||||
|
||||
- improve trigger and exclusions before growing prose
|
||||
- add one execution asset before adding many documents
|
||||
- surface the three highest-value next moves so authors do not expand in every direction at once
|
||||
- prefer the smallest step that increases reliability more than context cost
|
||||
|
||||
See [Iteration Philosophy](iteration-philosophy.md).
|
||||
|
||||
## Phase 9: Promotion
|
||||
|
||||
A candidate route or package is promotable only when:
|
||||
|
||||
|
||||
+18
-4
@@ -4,6 +4,8 @@ import json
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from render_intent_dialogue import render_intent_dialogue
|
||||
from render_iteration_directions import render_iteration_directions
|
||||
from render_reference_scan import render_reference_scan
|
||||
from render_skill_overview import render_skill_overview
|
||||
|
||||
@@ -34,15 +36,19 @@ README_TEMPLATE = """# {title}
|
||||
## How To Use
|
||||
|
||||
1. Load the skill through `SKILL.md`.
|
||||
2. Follow the workflow steps in `SKILL.md`.
|
||||
3. Check `reports/skill-overview.html` if you want a fast visual explanation of the package.
|
||||
2. Start with `reports/intent-dialogue.md` to tighten the real job, outputs, and exclusions.
|
||||
3. Follow the workflow steps in `SKILL.md`.
|
||||
4. Check `reports/skill-overview.html` if you want a fast visual explanation of the package.
|
||||
5. Review `reports/iteration-directions.md` for the three most valuable next moves.
|
||||
|
||||
## Package Map
|
||||
|
||||
- `SKILL.md`: trigger and workflow entrypoint
|
||||
- `agents/interface.yaml`: portable interface metadata
|
||||
- `manifest.json`: lifecycle and packaging metadata
|
||||
- `reports/intent-dialogue.md`: front-loaded discovery questions for better boundary design
|
||||
- `reports/skill-overview.html`: visual overview report
|
||||
- `reports/iteration-directions.md`: the top three next iteration directions
|
||||
"""
|
||||
|
||||
|
||||
@@ -131,7 +137,9 @@ def main() -> None:
|
||||
encoding="utf-8",
|
||||
)
|
||||
overview = render_skill_overview(root)
|
||||
intent_dialogue = render_intent_dialogue(root)
|
||||
reference_scan = render_reference_scan(root, [])
|
||||
iteration_directions = render_iteration_directions(root)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
@@ -140,8 +148,14 @@ def main() -> None:
|
||||
"artifacts": {
|
||||
"readme": str(root / "README.md"),
|
||||
"manifest": str(root / "manifest.json"),
|
||||
**overview["artifacts"],
|
||||
**reference_scan["artifacts"],
|
||||
"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"],
|
||||
},
|
||||
},
|
||||
ensure_ascii=False,
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError: # pragma: no cover
|
||||
yaml = None
|
||||
|
||||
|
||||
def parse_frontmatter(text: str) -> tuple[dict, str]:
|
||||
lines = text.splitlines()
|
||||
if not lines or lines[0].strip() != "---":
|
||||
return {}, text
|
||||
try:
|
||||
end_index = lines[1:].index("---") + 1
|
||||
except ValueError:
|
||||
return {}, text
|
||||
frontmatter = "\n".join(lines[1:end_index])
|
||||
body = "\n".join(lines[end_index + 1 :]).lstrip()
|
||||
if yaml is not None:
|
||||
payload = yaml.safe_load(frontmatter) or {}
|
||||
return payload if isinstance(payload, dict) else {}, body
|
||||
data = {}
|
||||
for line in frontmatter.splitlines():
|
||||
if ":" not in line:
|
||||
continue
|
||||
key, value = line.split(":", 1)
|
||||
data[key.strip()] = value.strip().strip('"')
|
||||
return data, body
|
||||
|
||||
|
||||
def extract_title(body: str, fallback: str) -> str:
|
||||
for line in body.splitlines():
|
||||
if line.startswith("# "):
|
||||
return line[2:].strip()
|
||||
return fallback
|
||||
|
||||
|
||||
def classify_focus(description: str) -> str:
|
||||
lowered = description.lower()
|
||||
if any(token in lowered for token in ["review", "audit", "incident", "risk", "govern"]):
|
||||
return "quality-and-boundary"
|
||||
if any(token in lowered for token in ["export", "package", "adapter", "client", "portable"]):
|
||||
return "portability-and-contract"
|
||||
if any(token in lowered for token in ["workflow", "coordinate", "orchestrate", "process"]):
|
||||
return "execution-and-assets"
|
||||
return "trigger-and-output"
|
||||
|
||||
|
||||
def build_questions(focus: str) -> list[dict]:
|
||||
base = [
|
||||
{
|
||||
"question": "What recurring job should this skill own every time?",
|
||||
"why": "This defines the core capability sentence and keeps the package from drifting.",
|
||||
},
|
||||
{
|
||||
"question": "What inputs will users actually hand to this skill?",
|
||||
"why": "Input shape decides whether references, scripts, or templates are needed.",
|
||||
},
|
||||
{
|
||||
"question": "What concrete outputs must the skill produce?",
|
||||
"why": "Outputs should drive the package structure before extra guidance is added.",
|
||||
},
|
||||
{
|
||||
"question": "Which near-neighbor requests should not trigger this skill?",
|
||||
"why": "The exclusion list is the fastest route to better trigger quality.",
|
||||
},
|
||||
{
|
||||
"question": "What constraints matter: privacy, naming, local fit, portability, or governance?",
|
||||
"why": "Constraints decide how much structure, packaging, and review the skill actually needs.",
|
||||
},
|
||||
]
|
||||
if focus == "quality-and-boundary":
|
||||
base.append(
|
||||
{
|
||||
"question": "What failure would make this skill untrustworthy in practice?",
|
||||
"why": "The answer usually reveals the first evaluation gate worth adding.",
|
||||
}
|
||||
)
|
||||
elif focus == "portability-and-contract":
|
||||
base.append(
|
||||
{
|
||||
"question": "Which environments or clients must be able to consume this skill?",
|
||||
"why": "This sets the minimum metadata and degradation strategy.",
|
||||
}
|
||||
)
|
||||
else:
|
||||
base.append(
|
||||
{
|
||||
"question": "What repeated manual step should become a deterministic asset first?",
|
||||
"why": "This usually reveals whether a script or reference should be created next.",
|
||||
}
|
||||
)
|
||||
return base
|
||||
|
||||
|
||||
def build_summary(skill_dir: Path) -> dict:
|
||||
skill_text = (skill_dir / "SKILL.md").read_text(encoding="utf-8")
|
||||
frontmatter, body = parse_frontmatter(skill_text)
|
||||
name = frontmatter.get("name", skill_dir.name)
|
||||
description = frontmatter.get("description", "No description found.")
|
||||
title = extract_title(body, name.replace("-", " ").title())
|
||||
focus = classify_focus(description)
|
||||
questions = build_questions(focus)
|
||||
output = {
|
||||
"capability_sentence": f"{title} should turn a recurring request into a reliable reusable output without widening the boundary unnecessarily.",
|
||||
"required_capture": [
|
||||
"recurring job",
|
||||
"real inputs",
|
||||
"required outputs",
|
||||
"exclusions",
|
||||
"constraints",
|
||||
"first evaluation target",
|
||||
],
|
||||
"recommended_first_gate": "trigger and boundary" if focus != "portability-and-contract" else "portability and contract",
|
||||
}
|
||||
return {
|
||||
"skill_name": name,
|
||||
"title": title,
|
||||
"description": description,
|
||||
"focus": focus,
|
||||
"questions": questions,
|
||||
"output": output,
|
||||
}
|
||||
|
||||
|
||||
def render_markdown(summary: dict) -> str:
|
||||
lines = [
|
||||
"# Intent Dialogue",
|
||||
"",
|
||||
f"Skill: `{summary['skill_name']}`",
|
||||
"",
|
||||
"## 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']}`",
|
||||
"",
|
||||
"## Questions To Ask",
|
||||
"",
|
||||
]
|
||||
for idx, item in enumerate(summary["questions"], start=1):
|
||||
lines.extend(
|
||||
[
|
||||
f"{idx}. {item['question']}",
|
||||
f" Why: {item['why']}",
|
||||
]
|
||||
)
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"## Capture Before Drafting",
|
||||
"",
|
||||
f"- Capability sentence: {summary['output']['capability_sentence']}",
|
||||
f"- Recommended first gate: `{summary['output']['recommended_first_gate']}`",
|
||||
]
|
||||
)
|
||||
for item in summary["output"]["required_capture"]:
|
||||
lines.append(f"- Capture: `{item}`")
|
||||
return "\n".join(lines).strip() + "\n"
|
||||
|
||||
|
||||
def render_intent_dialogue(skill_dir: Path, output_md: Path | None = None, output_json: Path | None = None) -> dict:
|
||||
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 / "intent-dialogue.md"
|
||||
output_json = output_json or reports_dir / "intent-dialogue.json"
|
||||
|
||||
summary = build_summary(skill_dir)
|
||||
output_md.write_text(render_markdown(summary), encoding="utf-8")
|
||||
output_json.write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
|
||||
return {
|
||||
"ok": True,
|
||||
"skill_dir": str(skill_dir),
|
||||
"artifacts": {
|
||||
"markdown": str(output_md),
|
||||
"json": str(output_json),
|
||||
},
|
||||
"summary": summary,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Render an intent dialogue guide for a skill package.")
|
||||
parser.add_argument("skill_dir", nargs="?", default=".")
|
||||
parser.add_argument("--output-md")
|
||||
parser.add_argument("--output-json")
|
||||
args = parser.parse_args()
|
||||
result = render_intent_dialogue(
|
||||
Path(args.skill_dir),
|
||||
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()
|
||||
@@ -0,0 +1,246 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError: # pragma: no cover
|
||||
yaml = None
|
||||
|
||||
|
||||
def parse_frontmatter(text: str) -> tuple[dict, str]:
|
||||
lines = text.splitlines()
|
||||
if not lines or lines[0].strip() != "---":
|
||||
return {}, text
|
||||
try:
|
||||
end_index = lines[1:].index("---") + 1
|
||||
except ValueError:
|
||||
return {}, text
|
||||
frontmatter = "\n".join(lines[1:end_index])
|
||||
body = "\n".join(lines[end_index + 1 :]).lstrip()
|
||||
if yaml is not None:
|
||||
payload = yaml.safe_load(frontmatter) or {}
|
||||
return payload if isinstance(payload, dict) else {}, body
|
||||
data = {}
|
||||
for line in frontmatter.splitlines():
|
||||
if ":" not in line:
|
||||
continue
|
||||
key, value = line.split(":", 1)
|
||||
data[key.strip()] = value.strip().strip('"')
|
||||
return data, body
|
||||
|
||||
|
||||
def load_manifest(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"
|
||||
sections[current] = []
|
||||
for line in body.splitlines():
|
||||
if line.startswith("## "):
|
||||
current = line[3:].strip()
|
||||
sections[current] = []
|
||||
continue
|
||||
sections[current].append(line)
|
||||
return {name: "\n".join(lines).strip() for name, lines in sections.items()}
|
||||
|
||||
|
||||
def section_text(sections: dict[str, str], *names: str) -> str:
|
||||
lowered = {key.lower(): value for key, value in sections.items()}
|
||||
for name in names:
|
||||
if name.lower() in lowered:
|
||||
return lowered[name.lower()]
|
||||
return ""
|
||||
|
||||
|
||||
def has_any_files(path: Path) -> bool:
|
||||
return path.exists() and any(path.iterdir())
|
||||
|
||||
|
||||
def direction(priority: int, title: str, why: str, actions: list[str], unlocks: str) -> dict:
|
||||
return {
|
||||
"priority": priority,
|
||||
"title": title,
|
||||
"why": why,
|
||||
"actions": actions,
|
||||
"unlocks": unlocks,
|
||||
}
|
||||
|
||||
|
||||
def build_directions(skill_dir: Path) -> tuple[dict, list[dict]]:
|
||||
skill_text = (skill_dir / "SKILL.md").read_text(encoding="utf-8")
|
||||
frontmatter, body = parse_frontmatter(skill_text)
|
||||
sections = extract_sections(body)
|
||||
manifest = load_manifest(skill_dir / "manifest.json")
|
||||
description = frontmatter.get("description", "")
|
||||
maturity = manifest.get("maturity_tier", "scaffold")
|
||||
|
||||
candidates: list[dict] = []
|
||||
if "Do not use" not in body and "exclusion" not in body.lower():
|
||||
candidates.append(
|
||||
direction(
|
||||
1,
|
||||
"Tighten trigger and exclusions",
|
||||
"The package needs clearer near-neighbor exclusions before it grows.",
|
||||
[
|
||||
"Add 3 to 5 should-trigger and should-not-trigger examples.",
|
||||
"Refine the frontmatter description to name the recurring job and non-goals.",
|
||||
"Run a first trigger evaluation pass before expanding the package.",
|
||||
],
|
||||
"Cleaner routing and fewer accidental activations.",
|
||||
)
|
||||
)
|
||||
if not has_any_files(skill_dir / "references") or not has_any_files(skill_dir / "scripts"):
|
||||
candidates.append(
|
||||
direction(
|
||||
2,
|
||||
"Add the first execution asset",
|
||||
"The package is still mostly prose. Add one asset that removes repeated manual work.",
|
||||
[
|
||||
"Move stable procedural guidance into references if users will need it repeatedly.",
|
||||
"Create one deterministic helper script if a repeated step can be executed instead of described.",
|
||||
"Keep the main SKILL.md compact and route-oriented.",
|
||||
],
|
||||
"Stronger execution quality without bloating the entrypoint.",
|
||||
)
|
||||
)
|
||||
if maturity == "scaffold":
|
||||
candidates.append(
|
||||
direction(
|
||||
3,
|
||||
"Promote from scaffold to production-ready",
|
||||
"The first version exists; the next gain usually comes from adding the smallest useful gates.",
|
||||
[
|
||||
"Decide whether this skill is personal, team-reused, or library-grade.",
|
||||
"Add only the gates that match that risk level.",
|
||||
"Record lifecycle metadata and review cadence once reuse becomes real.",
|
||||
],
|
||||
"A clearer path from exploratory package to maintained asset.",
|
||||
)
|
||||
)
|
||||
workflow_section = section_text(sections, "Workflow", "Compact Workflow", "How To Use")
|
||||
if workflow_section and len(workflow_section) < 120:
|
||||
candidates.append(
|
||||
direction(
|
||||
4,
|
||||
"Deepen operator guidance",
|
||||
"The workflow is still thin and may not be repeatable by another operator.",
|
||||
[
|
||||
"Split the job into distinct phases or checkpoints.",
|
||||
"Add success conditions and failure boundaries for each phase.",
|
||||
"Link outputs to the step that produces them.",
|
||||
],
|
||||
"Better repeatability and easier human review.",
|
||||
)
|
||||
)
|
||||
if "portable" in description.lower() or "package" in description.lower():
|
||||
candidates.append(
|
||||
direction(
|
||||
5,
|
||||
"Harden portability semantics",
|
||||
"The skill already signals reuse across environments, so contract clarity matters early.",
|
||||
[
|
||||
"Confirm activation mode, execution context, and trust assumptions.",
|
||||
"Add or review degradation strategy for non-native targets.",
|
||||
"Package the skill once to verify adapter expectations.",
|
||||
],
|
||||
"Safer cross-environment reuse with less target drift.",
|
||||
)
|
||||
)
|
||||
|
||||
if len(candidates) < 3:
|
||||
candidates.append(
|
||||
direction(
|
||||
len(candidates) + 10,
|
||||
"Create an iteration evidence loop",
|
||||
"The package should show what changed and why after the first draft.",
|
||||
[
|
||||
"Generate a visual overview and keep it aligned with the package.",
|
||||
"Record reference scan choices and non-goals.",
|
||||
"Capture the next iteration choice explicitly before adding more files.",
|
||||
],
|
||||
"A clearer path for the next author or reviewer.",
|
||||
)
|
||||
)
|
||||
|
||||
chosen = sorted(candidates, key=lambda item: item["priority"])[:3]
|
||||
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.",
|
||||
}
|
||||
return summary, chosen
|
||||
|
||||
|
||||
def render_markdown(summary: dict, directions: list[dict]) -> str:
|
||||
lines = [
|
||||
"# Iteration Directions",
|
||||
"",
|
||||
f"Skill: `{summary['skill_name']}`",
|
||||
"",
|
||||
f"- Maturity tier: `{summary['maturity_tier']}`",
|
||||
f"- Selection rule: {summary['selection_rule']}",
|
||||
"",
|
||||
"## Top 3 Next Moves",
|
||||
"",
|
||||
]
|
||||
for item in directions:
|
||||
lines.extend(
|
||||
[
|
||||
f"### {item['priority']}. {item['title']}",
|
||||
"",
|
||||
f"- Why now: {item['why']}",
|
||||
"- Recommended actions:",
|
||||
]
|
||||
)
|
||||
for action in item["actions"]:
|
||||
lines.append(f" - {action}")
|
||||
lines.append(f"- Unlocks: {item['unlocks']}")
|
||||
lines.append("")
|
||||
return "\n".join(lines).strip() + "\n"
|
||||
|
||||
|
||||
def render_iteration_directions(skill_dir: Path, output_md: Path | None = None, output_json: Path | None = None) -> dict:
|
||||
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 / "iteration-directions.md"
|
||||
output_json = output_json or reports_dir / "iteration-directions.json"
|
||||
|
||||
summary, directions = build_directions(skill_dir)
|
||||
payload = {"summary": summary, "directions": directions}
|
||||
output_md.write_text(render_markdown(summary, directions), encoding="utf-8")
|
||||
output_json.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
return {
|
||||
"ok": True,
|
||||
"skill_dir": str(skill_dir),
|
||||
"artifacts": {
|
||||
"markdown": str(output_md),
|
||||
"json": str(output_json),
|
||||
},
|
||||
**payload,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Render the top three next iteration directions for a skill package.")
|
||||
parser.add_argument("skill_dir", nargs="?", default=".")
|
||||
parser.add_argument("--output-md")
|
||||
parser.add_argument("--output-json")
|
||||
args = parser.parse_args()
|
||||
result = render_iteration_directions(
|
||||
Path(args.skill_dir),
|
||||
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()
|
||||
@@ -243,6 +243,30 @@ def command_reference_scan(args: argparse.Namespace) -> int:
|
||||
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]
|
||||
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("render_intent_dialogue.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_iteration_directions(args: argparse.Namespace) -> int:
|
||||
skill_dir = str(Path(args.skill_dir).resolve())
|
||||
cmd = [skill_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("render_iteration_directions.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_review(args: argparse.Namespace) -> int:
|
||||
target_name = resolve_promotion_target(args.target)
|
||||
bundle_dir = ROOT / "reports" / "iteration_bundles" / target_name
|
||||
@@ -464,6 +488,24 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
reference_scan_cmd.add_argument("--output-json")
|
||||
reference_scan_cmd.set_defaults(func=command_reference_scan)
|
||||
|
||||
intent_dialogue_cmd = subparsers.add_parser(
|
||||
"intent-dialogue",
|
||||
help="Render a front-loaded intent dialogue guide for a skill package.",
|
||||
)
|
||||
intent_dialogue_cmd.add_argument("skill_dir", nargs="?", default=".")
|
||||
intent_dialogue_cmd.add_argument("--output-md")
|
||||
intent_dialogue_cmd.add_argument("--output-json")
|
||||
intent_dialogue_cmd.set_defaults(func=command_intent_dialogue)
|
||||
|
||||
iteration_directions_cmd = subparsers.add_parser(
|
||||
"iteration-directions",
|
||||
help="Render the top three next iteration directions for a skill package.",
|
||||
)
|
||||
iteration_directions_cmd.add_argument("skill_dir", nargs="?", default=".")
|
||||
iteration_directions_cmd.add_argument("--output-md")
|
||||
iteration_directions_cmd.add_argument("--output-json")
|
||||
iteration_directions_cmd.set_defaults(func=command_iteration_directions)
|
||||
|
||||
package_cmd = subparsers.add_parser("package", help="Export compatibility artifacts for selected targets.")
|
||||
package_cmd.add_argument("skill_dir", nargs="?", default=".")
|
||||
package_cmd.add_argument("--platform", action="append")
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
CLI = ROOT / "scripts" / "yao.py"
|
||||
|
||||
|
||||
def run(*args: str) -> dict:
|
||||
proc = subprocess.run(
|
||||
[sys.executable, str(CLI), *args],
|
||||
cwd=ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
return json.loads(proc.stdout)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
tmp_root = ROOT / "tests" / "tmp_iteration_directions"
|
||||
if tmp_root.exists():
|
||||
subprocess.run(["rm", "-rf", str(tmp_root)], check=True)
|
||||
tmp_root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
init_payload = run(
|
||||
"init",
|
||||
"iteration-demo-skill",
|
||||
"--description",
|
||||
"Turn a repeated release checklist into a reusable reusable skill package.",
|
||||
"--output-dir",
|
||||
str(tmp_root),
|
||||
)
|
||||
created = Path(init_payload["root"])
|
||||
report = run("iteration-directions", str(created))
|
||||
assert report["summary"]["selection_rule"], 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
|
||||
print(json.dumps({"ok": True}, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -44,8 +44,12 @@ def main() -> None:
|
||||
created = tmp_root / "skill-overview-demo"
|
||||
assert (created / "README.md").exists(), created
|
||||
assert (created / "manifest.json").exists(), created
|
||||
assert (created / "reports" / "intent-dialogue.md").exists(), created
|
||||
assert (created / "reports" / "intent-dialogue.json").exists(), created
|
||||
assert (created / "reports" / "skill-overview.html").exists(), created
|
||||
assert (created / "reports" / "skill-overview.json").exists(), created
|
||||
assert (created / "reports" / "iteration-directions.md").exists(), created
|
||||
assert (created / "reports" / "iteration-directions.json").exists(), created
|
||||
|
||||
rerender_result = run("skill-report", str(created))
|
||||
assert rerender_result["ok"], rerender_result
|
||||
@@ -56,6 +60,12 @@ def main() -> None:
|
||||
assert "Architecture" in report_html, report_html[:400]
|
||||
assert "Why It Works" in report_html, report_html[:600]
|
||||
|
||||
intent_text = (created / "reports" / "intent-dialogue.md").read_text(encoding="utf-8")
|
||||
assert "Questions To Ask" in intent_text, intent_text[:400]
|
||||
|
||||
directions_text = (created / "reports" / "iteration-directions.md").read_text(encoding="utf-8")
|
||||
assert "Top 3 Next Moves" in directions_text, directions_text[:400]
|
||||
|
||||
print(json.dumps({"ok": True}, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
|
||||
@@ -36,8 +36,10 @@ def main() -> None:
|
||||
created = Path(init_result["payload"]["root"])
|
||||
assert (created / "SKILL.md").exists(), created
|
||||
assert (created / "README.md").exists(), created
|
||||
assert (created / "reports" / "intent-dialogue.md").exists(), created
|
||||
assert (created / "reports" / "skill-overview.html").exists(), created
|
||||
assert (created / "reports" / "reference-scan.md").exists(), created
|
||||
assert (created / "reports" / "iteration-directions.md").exists(), created
|
||||
|
||||
validate_result = run("validate", str(created))
|
||||
assert validate_result["ok"], validate_result
|
||||
@@ -58,6 +60,14 @@ def main() -> None:
|
||||
assert reference_scan_result["ok"], reference_scan_result
|
||||
assert reference_scan_result["payload"]["artifacts"]["markdown"].endswith("reports/reference-scan.md"), reference_scan_result
|
||||
|
||||
intent_result = run("intent-dialogue", str(created))
|
||||
assert intent_result["ok"], intent_result
|
||||
assert intent_result["payload"]["artifacts"]["markdown"].endswith("reports/intent-dialogue.md"), intent_result
|
||||
|
||||
directions_result = run("iteration-directions", str(created))
|
||||
assert directions_result["ok"], directions_result
|
||||
assert directions_result["payload"]["artifacts"]["markdown"].endswith("reports/iteration-directions.md"), directions_result
|
||||
|
||||
optimize_result = run("optimize-description", "--target", "root")
|
||||
assert optimize_result["ok"], optimize_result
|
||||
assert optimize_result["payload"]["winner"]["label"] == "Current", optimize_result
|
||||
|
||||
Reference in New Issue
Block a user