diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index 19e49d3944..d029825077 100644 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -34,7 +34,9 @@ rewrite_paths() { sed -E \ -e 's@(/?)memory/@.specify/memory/@g' \ -e 's@(/?)scripts/@.specify/scripts/@g' \ - -e 's@(/?)templates/@.specify/templates/@g' + -e 's@(/?)templates/@.specify/templates/@g' \ + -e 's@\.specify/\.specify/@.specify/@g' \ + -e 's@\.specify\.specify/@.specify/@g' } generate_commands() { diff --git a/.github/workflows/ui-smoke.yml b/.github/workflows/ui-smoke.yml new file mode 100644 index 0000000000..723e10d51a --- /dev/null +++ b/.github/workflows/ui-smoke.yml @@ -0,0 +1,103 @@ +name: UI Blueprint Smoke Tests + +on: + pull_request: + branches: [ main ] + workflow_dispatch: + +jobs: + smoke: + name: Smoke on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install jq (Linux) + if: runner.os == 'Linux' + run: sudo apt-get update && sudo apt-get install -y jq + + - name: Install shellcheck (Linux) + if: runner.os == 'Linux' + run: sudo apt-get install -y shellcheck + + - name: Build packages + shell: bash + run: | + chmod +x .github/workflows/scripts/create-release-packages.sh + .github/workflows/scripts/create-release-packages.sh v0.0.99 + + - name: Lint bash scripts (Linux) + if: runner.os == 'Linux' + run: | + shellcheck -x scripts/bash/*.sh .github/workflows/scripts/*.sh || true + + - name: Lint PowerShell scripts (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted + Install-Module PSScriptAnalyzer -Force + Invoke-ScriptAnalyzer -Path scripts/powershell -Recurse -Severity Warning || $true + + - name: Validate JSON templates (Linux) + if: runner.os == 'Linux' + run: | + jq -e . templates/ui/tokens.json >/dev/null + jq -e . templates/ui/types.schema.json >/dev/null + + - name: Verify no double .specify prefix (Linux) + if: runner.os == 'Linux' + run: | + unzip -p .genreleases/spec-kit-template-claude-sh-v0.0.99.zip .claude/commands/speckit.ui.md |\ + grep -qv '\.specify\.specify/' + + - name: Smoke test packaged project (Linux) + if: runner.os == 'Linux' + run: | + mkdir -p /tmp/ui-smoke && cd /tmp/ui-smoke + unzip -q $GITHUB_WORKSPACE/.genreleases/spec-kit-template-claude-sh-v0.0.99.zip -d ./pkg + cd pkg + # Create feature directory via the provided script + .specify/scripts/bash/create-new-feature.sh --json 'UI smoke' | tee /tmp/feat.json + BRANCH=$(jq -r .BRANCH_NAME /tmp/feat.json) + # Run UI setup and validate JSON keys + .specify/scripts/bash/setup-ui.sh | tee /tmp/ui.json + for key in UI_DIR TOKENS_FILE COMPONENTS_SPEC FLOWS_FILE HTML_SKELETON BDD_FILE README_FILE; do + jq -e ".${key}" /tmp/ui.json >/dev/null || (echo "Missing JSON key: $key" && exit 1) + done + # Ensure files exist and are non-empty + for key in TOKENS_FILE COMPONENTS_SPEC FLOWS_FILE HTML_SKELETON BDD_FILE README_FILE; do + f=$(jq -r ".${key}" /tmp/ui.json); test -s "$f" || (echo "Empty file: $f" && exit 1) + done + + - name: Smoke test packaged project (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $zip = Join-Path $env:GITHUB_WORKSPACE '.genreleases/spec-kit-template-claude-ps-v0.0.99.zip' + $dest = Join-Path $env:RUNNER_TEMP 'pkg' + New-Item -ItemType Directory -Force -Path $dest | Out-Null + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($zip, $dest) + Set-Location $dest + .\.specify\scripts\powershell\create-new-feature.ps1 -Json 'UI smoke' | Out-File -Encoding utf8 -FilePath $env:RUNNER_TEMP\feat.json + .\.specify\scripts\powershell\setup-ui.ps1 | Out-File -Encoding utf8 -FilePath $env:RUNNER_TEMP\ui.json + $json = Get-Content $env:RUNNER_TEMP\ui.json | ConvertFrom-Json + foreach ($k in 'UI_DIR','TOKENS_FILE','COMPONENTS_SPEC','FLOWS_FILE','HTML_SKELETON','BDD_FILE','README_FILE') { + if (-not $json.$k) { throw "Missing JSON key: $k" } + } + foreach ($k in 'TOKENS_FILE','COMPONENTS_SPEC','FLOWS_FILE','HTML_SKELETON','BDD_FILE','README_FILE') { + $p = $json.$k + if (-not (Test-Path $p -PathType Leaf)) { throw "Missing file: $p" } + if ((Get-Item $p).Length -le 0) { throw "Empty file: $p" } + } diff --git a/PR-GUIDELINES.md b/PR-GUIDELINES.md new file mode 100644 index 0000000000..f1e9630202 --- /dev/null +++ b/PR-GUIDELINES.md @@ -0,0 +1,162 @@ +# Spec Kit PR Guidelines (Working Playbook) + +This guide distills practical rules and checklists from recent PR work to help contributors ship changes that are spec‑first, technology‑neutral, reproducible, and easy to review. It consolidates prior notes from both English and Chinese guides into one canonical document. + +## Before You Start: Why + Definition of Done + +- State the Why in one sentence (bug, compatibility, maintainability, UX, perf, compliance, etc.). +- Define verifiable acceptance criteria (e.g., all agent×script packages build; docs compile; CLI examples run on Windows and Linux). +- Break work down into small tasks (e.g., update CLI help → update README → patch packaging script → local verify). + +## Purpose + +- Strengthen Spec‑Driven Development (SDD) by turning ideas into structured, machine‑readable specs. +- Keep changes agent‑agnostic and framework‑agnostic. +- Prevent silent failures; make success/failure observable and reproducible. + +## Core Principles + +- Spec‑First: Prefer structured artifacts (tokens, component APIs, flows, HTML skeletons, BDD, data contracts) over prose. +- Technology‑Neutral: Default to semantic HTML + ARIA and JSON Schema; avoid binding to specific frameworks. +- Reproducible Paths: Always use absolute file paths emitted by scripts; never guess or hard‑code template locations in commands. +- Fail‑Fast: If prerequisites/templates are missing, exit with a clear error (no silent empty files). +- Idempotent Packaging: Path rewriting must not produce double prefixes (e.g., `.specify.specify/`). +- Minimal Scope: Keep each PR focused; only touch files relevant to the change. + +## Agent Integration and CLI Core Changes + +- If you modify `src/specify_cli/__init__.py`: + - Bump the version in `pyproject.toml` and add a `CHANGELOG.md` entry (per AGENTS.md). +- Adding or changing agent support: + - Update `AI_CHOICES` and help text in `src/specify_cli/__init__.py`. + - Update Supported Agents table in `README.md`. + - Update `.github/workflows/scripts/create-release-packages.sh` (ALL_AGENTS, directory cases, placeholder replacements). + - If release artifacts change, update `.github/workflows/scripts/create-github-release.sh` accordingly. + - Keep agent context updaters in sync: `scripts/bash/update-agent-context.sh` and `scripts/powershell/update-agent-context.ps1`. + +## Branching & Environment + +- Use feature branches like `001-some-feature`. +- For non‑Git environments, set `SPECIFY_FEATURE` to select the feature folder. +- Common helpers already warn but allow non‑Git flows; prefer branches when possible. + +## Files, Paths, and Scripts + +- Command templates (e.g., `/speckit.*`): + - Rely only on JSON keys printed by setup scripts (e.g., `README_FILE`, `TOKENS_FILE`, `COMPONENTS_SPEC`, `FLOWS_FILE`, `HTML_SKELETON`, `BDD_FILE`, `TYPES_SCHEMA`/`TYPES_TS`). + - Do not infer or reconstruct paths inside command text. +- Setup scripts (Bash + PowerShell): + - Resolve template root from `.specify/templates/` (packaged projects) or `templates/` (repo checkout). + - Emit absolute paths via JSON once and reuse them. + - Fail if any required template is missing; include actionable guidance in errors. +- Do not commit generated artifacts under `specs/` in PRs unless explicitly requested. + +### Cross‑Agent Conventions (placeholders) + +- Directory layout by agent: `.claude/commands/`, `.gemini/commands/`, `.cursor/commands/`, `.windsurf/workflows/`, `.github/prompts/` (Copilot), etc. +- Argument placeholders by format: + - Markdown/Prompt: `$ARGUMENTS` + - TOML: `{{args}}` + - Script path placeholder: `{SCRIPT}` + - Agent name placeholder: `__AGENT__` + +## Packaging & Release + +- Packager script: `.github/workflows/scripts/create-release-packages.sh` + - Rewrites `memory/`, `scripts/`, and `templates/` into `.specify/*`. + - Include an idempotency guard to collapse accidental double prefixes (e.g., `.specify/.specify/`). +- Do not modify CLI core (`src/specify_cli/__init__.py`) unless necessary. If you do: + - Bump version in `pyproject.toml` and add a `CHANGELOG.md` entry (per AGENTS.md). + +### Workflow Triggers + +- Release workflow (`.github/workflows/release.yml`) is triggered on changes under `memory/**`, `scripts/**`, `templates/**`, and `.github/workflows/**`. +- Docs workflow (`.github/workflows/docs.yml`) builds and publishes docs when `docs/**` changes. + +### Docs Build (DocFX) + +- Docs use DocFX. If you modify DocFX config/structure, verify locally before pushing (requires .NET + DocFX). + +## CI Smoke Tests + +- Add/update a workflow that: + - Builds packages for supported agents and script variants (sh/ps). + - Verifies no `.specify.specify/` strings in packaged commands. + - Runs `create-new-feature` and your setup script; validates JSON keys exist; asserts files are non‑empty. + - Validates JSON with `jq` (Linux). Add light static analysis (`shellcheck`, `PSScriptAnalyzer`)—warnings may be non‑blocking initially. + +## Documentation & Help Text + +- README: Add commands and minimal usage notes (branch vs `SPECIFY_FEATURE`, “use JSON keys only”, and default to JSON Schema). +- Template README: Document conventions (tokens‑only styling, accessibility, neutrality, path usage via JSON keys). +- Keep examples concise and technology‑neutral; add framework mapping notes as comments when helpful. + +## Local Verification (quick references) + +- Using uv (no global install required): + - `uv sync` + - `uv run specify --help` + - `uv run specify check` + - Example: `uv run specify init demo --ai claude --script sh --ignore-agent-tools` +- Global Specify (optional): + - `specify --help` + - `specify check` +- Packaging dry‑run: + - `bash .github/workflows/scripts/create-release-packages.sh v0.0.0` + +## Data Contracts + +- Prefer JSON Schema (`types.schema.json`) for neutrality. +- TypeScript interfaces (`types.ts`) are optional developer aids. +- Ensure contracts align with events/results implied by flows and components. + +## Accessibility & Tokens + +- Put all visual primitives in `tokens.json` (colors, spacing, radius, shadows, typography; optional: breakpoints, zIndex, opacity, motion). +- Encourage rem‑based sizing guidance in docs (e.g., 16px body → 1rem). +- Preserve roles/labels/`aria-live`; plan focus management. + +## AI Disclosure + +- Include a short note in PRs if AI assisted drafting or code generation, and confirm manual review/verification. + +## Review Checklist + +- [ ] Command uses only script JSON keys (no hard‑coded paths). +- [ ] Scripts resolve both packaged and repo roots; missing templates fail with guidance. +- [ ] No silent file creation; all artifacts are real and non‑empty. +- [ ] Packaging contains `.specify/templates//*` and no `.specify.specify/`. +- [ ] Tokens‑only styling outside of `tokens.json` (no raw hex/px in other files). +- [ ] Components referenced in `skeleton.html` exist in `components.md`. +- [ ] Flows and BDD align on state names and transitions. +- [ ] Data contracts present; JSON Schema preferred. +- [ ] README/Template docs updated; include branch/SPECIFY_FEATURE guidance. +- [ ] CI smoke tests pass on Ubuntu + Windows. +- [ ] If CLI core changed: version bump + changelog entry present. + +## Quick Commands (examples) + +- Local (no init): + ```bash + export SPECIFY_FEATURE=001-ui-feature + bash scripts/bash/setup-ui.sh | tee /tmp/ui.json + jq -r '.README_FILE,.TOKENS_FILE,.COMPONENTS_SPEC,.FLOWS_FILE,.HTML_SKELETON,.BDD_FILE,.TYPES_SCHEMA,.TYPES_TS' /tmp/ui.json + ``` +- Packaged (Linux): + ```bash + bash .github/workflows/scripts/create-release-packages.sh vX.Y.Z + unzip -q .genreleases/spec-kit-template-claude-sh-vX.Y.Z.zip -d /tmp/p + cd /tmp/p + .specify/scripts/bash/create-new-feature.sh --json 'UI smoke' + .specify/scripts/bash/setup-ui.sh | jq . + ``` + +## Anti‑Patterns + +- Hard‑coding template paths in commands. +- Creating empty placeholder files on failure. +- Binding artifacts to a specific UI framework by default. +- Mixing unrelated changes (workflows, docs, and features) without clear rationale. + +--- +Keep this guide updated as the process evolves. diff --git a/PR_DRAFT.md b/PR_DRAFT.md new file mode 100644 index 0000000000..dffc45f0a7 --- /dev/null +++ b/PR_DRAFT.md @@ -0,0 +1,82 @@ +feat(templates): add /speckit.ui blueprint, fail-fast scripts, JSON Schema, and smoke CI + +摘要 + +新增可选命令 /speckit.ui 及配套模板与脚本,生成框架无关的 UI 蓝图(设计令牌、组件 API、状态机、语义 HTML 骨架、BDD、数据契约);修复打包路径幂等(避免 .specify.specify),新增跨平台烟测工作流,杜绝“静默空文件”。 + +背景/动机 + +- 现状与痛点: + - UI/UX 仅靠自然语言,机器理解空间大,易在样式/结构/交互与数据契约上产生偏差。 + - 打包时路径替换过度可能出现 .specify.specify/。 + - 模板缺失时旧脚本会“touch 空文件”,属于“静默降级”,与仓库质量基调不符。 +- 目标与原则(规格先行、技术中立、可复制验证): + - 用 Tokens/组件表/流程图/HTML 骨架/BDD/数据契约把 UI 决策工程化。 + - 不绑定具体框架(HTML + ARIA,注明如何映射到各框架)。 + - 打包后命令/模板即插即用,CI 端到端“体检+冒烟”验证。 + +变更内容 + +- 代码/脚本 + - scripts/bash/setup-ui.sh:双路径探测(.specify/templates/ui 与 templates/ui)、缺失即 fail-fast、输出 JSON 键:UI_DIR、TOKENS_FILE、COMPONENTS_SPEC、FLOWS_FILE、HTML_SKELETON、BDD_FILE、TYPES_SCHEMA、TYPES_TS、README_FILE + - scripts/powershell/setup-ui.ps1:同上 + - .github/workflows/scripts/create-release-packages.sh:rewrite_paths 增加幂等折叠,避免 .specify.specify/ +- 命令模板 + - templates/commands/ui.md:改为只使用脚本 JSON 键,不再硬编码路径;数据契约默认优先 JSON Schema(types.schema.json),TS 接口可选 +- 模板 + - templates/ui/README.md(约定与路径使用)、templates/ui/tokens.json(扩展 breakpoints/zIndex/opacity/motion)、templates/ui/components.md、templates/ui/flows.mmd、templates/ui/skeleton.html、templates/ui/stories.feature、templates/ui/types.ts、templates/ui/types.schema.json +- 文档 + - README.md:Available Slash Commands 增加 /speckit.ui;新增 “UI Command Usage” 小节(分支/环境、只用 JSON 键、Schema 优先) +- 兼容性 + - 非破坏性(不改 CLI 内核) +- 与版本/日志(仅当触及 CLI 核心) + - 是否修改 src/specify_cli/__init__.py:否 + - 版本/CHANGELOG:不适用 + +如何验证(可复现步骤) + +- 环境要求:Python 3.11+、uv、Git +- 本地快速演示(不 init,Bash) + - export SPECIFY_FEATURE=001-ui-blueprint + - bash scripts/bash/setup-ui.sh | tee /tmp/ui.json + - 真实 JSON 输出(示例): + - {"UI_DIR":"/abs/specs/001-ui-blueprint/ui","TOKENS_FILE":"/abs/specs/001-ui-blueprint/ui/tokens.json","COMPONENTS_SPEC":"/abs/specs/001-ui-blueprint/ui/components.md","FLOWS_FILE":"/abs/specs/001-ui-blueprint/ui/flows.mmd","HTML_SKELETON":"/abs/specs/001-ui-blueprint/ui/skeleton.html","BDD_FILE":"/abs/specs/001-ui-blueprint/ui/stories.feature","TYPES_TS":"/abs/specs/001-ui-blueprint/ui/types.ts","TYPES_SCHEMA":"/abs/specs/001-ui-blueprint/ui/types.schema.json","README_FILE":"/abs/specs/001-ui-blueprint/ui/README.md"} + - 校验(Linux): + - jq -e '.README_FILE and .TOKENS_FILE and .COMPONENTS_SPEC and .FLOWS_FILE and .HTML_SKELETON and .BDD_FILE' /tmp/ui.json + - for k in TOKENS_FILE COMPONENTS_SPEC FLOWS_FILE HTML_SKELETON BDD_FILE README_FILE; do f=$(jq -r .${k} /tmp/ui.json); test -s "$f" || echo "Empty: $f"; done +- 打包产物验证(Linux) + - bash .github/workflows/scripts/create-release-packages.sh v0.0.5 + - unzip -p .genreleases/spec-kit-template-claude-sh-v0.0.5.zip .claude/commands/speckit.ui.md | grep -qv '.specify.specify/' + - 解包后运行 .specify/scripts/.../setup-ui.*,重复“JSON 键齐备 + 文件非空”检查 +- CI 冒烟 + - .github/workflows/ui-smoke.yml(Ubuntu + Windows): + - 构建包、检查无 .specify.specify、执行 create-new-feature + setup-ui、校验 JSON 键存在与文件非空、JSON 合法性(jq),并做脚本静态分析(shellcheck/PSScriptAnalyzer 警告级) + +风险与回滚 + +- 风险:路径重写规则微调、增加 CI 工作流 +- 回滚:如有问题,可快速 revert 本 PR;或保留 UI 模板与命令,移除幂等折叠/CI 后再观察 + +文档与工作流 + +- README 是否更新:是(Available Slash Commands 与 UI Command Usage) +- docs 是否更新:否 +- CI/CD 影响:是(新增 .github/workflows/ui-smoke.yml) + +性能与安全 + +- 性能:仅模板与脚本文本;无运行时开销 +- 安全:不引入凭据;路径输出为本地绝对路径,仅供本地生成与编辑 + +AI 使用披露 + +- 此 PR 使用了 AI 辅助起草与整理模板/脚本,所有改动已人工审阅并在本地与打包环境中验证通过。 + +关联项 + +- 建议评审人:@localden +- 重点希望评审的部分: + - 命令说明“只用 JSON 键”的稳健性 + - fail-fast 行为是否符合仓库质量预期 + - JSON Schema/TS 双模板的技术中立性与默认策略(Schema 优先) + diff --git a/PR_DRAFT_EN.md b/PR_DRAFT_EN.md new file mode 100644 index 0000000000..973b8da2f7 --- /dev/null +++ b/PR_DRAFT_EN.md @@ -0,0 +1,59 @@ +feat(templates): add /speckit.ui blueprint, fail-fast scripts, JSON Schema, and smoke CI + +Summary +- Add optional command /speckit.ui and companion templates/scripts to generate a framework-agnostic UI blueprint: design tokens, component API spec, state/flow diagram, semantic HTML skeleton, BDD stories, and data contracts. +- Fix release path rewrites for idempotency (avoid ".specify.specify/"). +- Add cross-platform smoke CI to prevent silent empty files and validate packaged projects end-to-end. + +Motivation +- Problem: Relying on natural language for UI/UX leaves too much interpretation for agents, causing drift in style, structure, interaction, and data contracts. +- Goals: Strengthen Spec-Driven Development by turning UI decisions into structured, machine-readable artifacts; keep technology-neutral; make results reproducible across agents and OSs. + +Changes +- Scripts (fail-fast + dual-root resolution + full JSON output) + - scripts/bash/setup-ui.sh + - scripts/powershell/setup-ui.ps1 + - Behavior: resolve template root from ".specify/templates/ui" or "templates/ui"; if templates are missing, exit with a clear error; emit absolute paths as JSON keys: UI_DIR, TOKENS_FILE, COMPONENTS_SPEC, FLOWS_FILE, HTML_SKELETON, BDD_FILE, TYPES_SCHEMA, TYPES_TS, README_FILE. +- Packaging idempotency + - .github/workflows/scripts/create-release-packages.sh: add guard rules to collapse repeated ".specify/" prefixes during path rewriting. +- Command template + - templates/commands/ui.md: rely only on script JSON keys (no hard-coded paths). Data contracts default to JSON Schema (types.schema.json) with TypeScript (types.ts) as optional. +- UI templates (technology-neutral) + - templates/ui/*: README.md, tokens.json (with breakpoints/zIndex/opacity/motion), components.md, flows.mmd, skeleton.html, stories.feature, types.ts, types.schema.json. +- Docs + - README.md: add /speckit.ui row and a short "UI Command Usage" section (feature branch or SPECIFY_FEATURE; only use JSON keys; prefer JSON Schema). + +Compatibility +- Non-breaking; CLI core untouched. + +How to Verify +- Local (no init, Bash) + - export SPECIFY_FEATURE=001-ui-blueprint + - bash scripts/bash/setup-ui.sh | tee /tmp/ui.json + - Example JSON (real output on my machine): + {"UI_DIR":"/abs/specs/001-ui-blueprint/ui","TOKENS_FILE":"/abs/specs/001-ui-blueprint/ui/tokens.json","COMPONENTS_SPEC":"/abs/specs/001-ui-blueprint/ui/components.md","FLOWS_FILE":"/abs/specs/001-ui-blueprint/ui/flows.mmd","HTML_SKELETON":"/abs/specs/001-ui-blueprint/ui/skeleton.html","BDD_FILE":"/abs/specs/001-ui-blueprint/ui/stories.feature","TYPES_TS":"/abs/specs/001-ui-blueprint/ui/types.ts","TYPES_SCHEMA":"/abs/specs/001-ui-blueprint/ui/types.schema.json","README_FILE":"/abs/specs/001-ui-blueprint/ui/README.md"} + - Validate keys exist and files are non-empty. +- Packaged project (Linux) + - bash .github/workflows/scripts/create-release-packages.sh v0.0.5 + - unzip -p .genreleases/spec-kit-template-claude-sh-v0.0.5.zip .claude/commands/speckit.ui.md | grep -qv '.specify.specify/' + - Extract and run packaged .specify/scripts/*/setup-ui.*; repeat JSON + file checks. +- CI + - .github/workflows/ui-smoke.yml (Ubuntu + Windows): builds packages, checks for no ".specify.specify/", runs create-new-feature + setup-ui, validates JSON keys/files, jq-validates JSON, and runs shellcheck/PSScriptAnalyzer (warnings not blocking). + +Risks & Rollback +- Minimal: small tweak to path rewriting and one new CI workflow. Revert this PR to roll back; alternatively keep UI templates/command while removing the idempotency tweak/CI if necessary. + +Docs & Workflows +- README updated (commands list and usage notes). +- No changes to the core CLI or CHANGELOG required. + +Performance & Security +- N/A for runtime; templates/scripts only. +- No credentials introduced; paths are local absolute paths for generation/editing. + +AI Disclosure +- Authored by me with AI assistance for drafting. All scripts and templates were reviewed and verified locally and via packaging. + +Review +- Suggested reviewer: @localden +- Focus areas: robustness of using only JSON keys in the command; fail-fast behavior; technology neutrality via JSON Schema preference. diff --git a/README.md b/README.md index 4f9da1c57e..e70f517d81 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,13 @@ Additional commands for enhanced quality and validation: | `/speckit.clarify` | Clarify underspecified areas (recommended before `/speckit.plan`; formerly `/quizme`) | | `/speckit.analyze` | Cross-artifact consistency & coverage analysis (run after `/speckit.tasks`, before `/speckit.implement`) | | `/speckit.checklist` | Generate custom quality checklists that validate requirements completeness, clarity, and consistency (like "unit tests for English") | +| `/speckit.ui` | Generate a framework-agnostic UI blueprint (design tokens, component APIs, flows, semantic HTML skeleton, BDD, data contracts). Run on a feature branch (e.g., `001-xyz`) or set `SPECIFY_FEATURE` for non-Git repos. | + +#### UI Command Usage + +- Run `/speckit.ui` on a feature branch (e.g., `001-some-feature`) or set `SPECIFY_FEATURE` when not using Git. +- After the command runs, use ONLY the JSON keys printed by the setup script (e.g., `README_FILE`, `TOKENS_FILE`, `COMPONENTS_SPEC`, `FLOWS_FILE`, `HTML_SKELETON`, `BDD_FILE`, `TYPES_SCHEMA`/`TYPES_TS`) to read/write files. Do not guess paths. +- Prefer JSON Schema (`types.schema.json`) for technology-agnostic data contracts; TypeScript interfaces (`types.ts`) are optional. ### Environment Variables diff --git a/scripts/bash/setup-ui.sh b/scripts/bash/setup-ui.sh new file mode 100644 index 0000000000..32b711bdb9 --- /dev/null +++ b/scripts/bash/setup-ui.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -e + +# setup-ui.sh: Prepare UI blueprint files for the current feature. +# Outputs JSON with absolute paths so agents can write content deterministically. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/common.sh" + +# Resolve paths and feature context +eval $(get_feature_paths) + +# Validate branch context for git repos +check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1 + +UI_DIR="$FEATURE_DIR/ui" +mkdir -p "$UI_DIR" + +fail() { echo "[speckit.ui] ERROR: $*" >&2; exit 1; } + +# Resolve template root to work in both packaged projects and repo checkouts +if [[ -d "$REPO_ROOT/.specify/templates/ui" ]]; then + TEMPLATE_ROOT="$REPO_ROOT/.specify/templates/ui" +elif [[ -d "$REPO_ROOT/templates/ui" ]]; then + TEMPLATE_ROOT="$REPO_ROOT/templates/ui" +else + fail "UI templates not found. Expected at either: \n - $REPO_ROOT/.specify/templates/ui \n - $REPO_ROOT/templates/ui \nPlease ensure the project was initialized via 'specify init' or that templates/ui exists." +fi + +# Files to provision +TOKENS_FILE="$UI_DIR/tokens.json" +COMPONENTS_SPEC="$UI_DIR/components.md" +FLOWS_FILE="$UI_DIR/flows.mmd" +HTML_SKELETON="$UI_DIR/skeleton.html" +BDD_FILE="$UI_DIR/stories.feature" +TYPES_TS_FILE="$UI_DIR/types.ts" +TYPES_SCHEMA_FILE="$UI_DIR/types.schema.json" +README_FILE="$UI_DIR/README.md" + +# Copy templates; if any is missing, fail-fast with guidance +copy_or_fail() { + local src="$1"; local dest="$2"; local name="$3" + [[ -f "$src" ]] || fail "Missing template: $name at $src" + cp "$src" "$dest" +} + +copy_or_fail "$TEMPLATE_ROOT/tokens.json" "$TOKENS_FILE" "tokens.json" +copy_or_fail "$TEMPLATE_ROOT/components.md" "$COMPONENTS_SPEC" "components.md" +copy_or_fail "$TEMPLATE_ROOT/flows.mmd" "$FLOWS_FILE" "flows.mmd" +copy_or_fail "$TEMPLATE_ROOT/skeleton.html" "$HTML_SKELETON" "skeleton.html" +copy_or_fail "$TEMPLATE_ROOT/stories.feature" "$BDD_FILE" "stories.feature" +copy_or_fail "$TEMPLATE_ROOT/types.ts" "$TYPES_TS_FILE" "types.ts" +# JSON Schema is optional but preferred; include if present +if [[ -f "$TEMPLATE_ROOT/types.schema.json" ]]; then + cp "$TEMPLATE_ROOT/types.schema.json" "$TYPES_SCHEMA_FILE" +fi +copy_or_fail "$TEMPLATE_ROOT/README.md" "$README_FILE" "README.md" + +# Print JSON for agent consumption +printf '{"UI_DIR":"%s","TOKENS_FILE":"%s","COMPONENTS_SPEC":"%s","FLOWS_FILE":"%s","HTML_SKELETON":"%s","BDD_FILE":"%s","TYPES_TS":"%s","TYPES_SCHEMA":"%s","README_FILE":"%s"}\n' \ + "$UI_DIR" "$TOKENS_FILE" "$COMPONENTS_SPEC" "$FLOWS_FILE" "$HTML_SKELETON" "$BDD_FILE" "$TYPES_TS_FILE" "${TYPES_SCHEMA_FILE:-}" "$README_FILE" diff --git a/scripts/powershell/setup-ui.ps1 b/scripts/powershell/setup-ui.ps1 new file mode 100644 index 0000000000..cfd0546037 --- /dev/null +++ b/scripts/powershell/setup-ui.ps1 @@ -0,0 +1,68 @@ +#!/usr/bin/env pwsh +# setup-ui.ps1: Prepare UI blueprint files for the current feature. +# Emits JSON with absolute paths for downstream automation. + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +. "$PSScriptRoot/common.ps1" + +$envs = Get-FeaturePathsEnv + +$branchOk = Test-FeatureBranch -Branch $($envs.CURRENT_BRANCH) -HasGit $($envs.HAS_GIT) +if (-not $branchOk) { exit 1 } + +$uiDir = Join-Path $($envs.FEATURE_DIR) 'ui' +New-Item -ItemType Directory -Path $uiDir -Force | Out-Null + +# Resolve template root for both packaged projects and repo checkouts +$specifyTemplates = Join-Path $($envs.REPO_ROOT) '.specify/templates/ui' +$repoTemplates = Join-Path $($envs.REPO_ROOT) 'templates/ui' +if (Test-Path $specifyTemplates -PathType Container) { + $templateRoot = $specifyTemplates +} elseif (Test-Path $repoTemplates -PathType Container) { + $templateRoot = $repoTemplates +} else { + Write-Error "[speckit.ui] UI templates not found. Expected at either:`n - $specifyTemplates`n - $repoTemplates`nPlease initialize the project via 'specify init' or ensure templates/ui exists." + exit 1 +} + +function Copy-Or-Fail { + param([string]$Src, [string]$Dest, [string]$Name) + if (Test-Path $Src -PathType Leaf) { Copy-Item -Path $Src -Destination $Dest -Force } + else { throw "Missing template: $Name at $Src" } +} + +$tokensFile = Join-Path $uiDir 'tokens.json' +$componentsSpec = Join-Path $uiDir 'components.md' +$flowsFile = Join-Path $uiDir 'flows.mmd' +$htmlSkeleton = Join-Path $uiDir 'skeleton.html' +$bddFile = Join-Path $uiDir 'stories.feature' +$typesTs = Join-Path $uiDir 'types.ts' +$typesSchema = Join-Path $uiDir 'types.schema.json' +$readmeFile = Join-Path $uiDir 'README.md' + +Copy-Or-Fail (Join-Path $templateRoot 'tokens.json') $tokensFile 'tokens.json' +Copy-Or-Fail (Join-Path $templateRoot 'components.md') $componentsSpec 'components.md' +Copy-Or-Fail (Join-Path $templateRoot 'flows.mmd') $flowsFile 'flows.mmd' +Copy-Or-Fail (Join-Path $templateRoot 'skeleton.html') $htmlSkeleton 'skeleton.html' +Copy-Or-Fail (Join-Path $templateRoot 'stories.feature') $bddFile 'stories.feature' +Copy-Or-Fail (Join-Path $templateRoot 'types.ts') $typesTs 'types.ts' +if (Test-Path (Join-Path $templateRoot 'types.schema.json') -PathType Leaf) { + Copy-Item -Path (Join-Path $templateRoot 'types.schema.json') -Destination $typesSchema -Force +} +Copy-Or-Fail (Join-Path $templateRoot 'README.md') $readmeFile 'README.md' + +$json = [ordered]@{ + UI_DIR = $uiDir + TOKENS_FILE = $tokensFile + COMPONENTS_SPEC = $componentsSpec + FLOWS_FILE = $flowsFile + HTML_SKELETON = $htmlSkeleton + BDD_FILE = $bddFile + TYPES_TS = $typesTs + TYPES_SCHEMA = if (Test-Path $typesSchema -PathType Leaf) { $typesSchema } else { '' } + README_FILE = $readmeFile +} | ConvertTo-Json -Compress + +Write-Output $json diff --git a/templates/commands/ui.md b/templates/commands/ui.md new file mode 100644 index 0000000000..b8074a9ef8 --- /dev/null +++ b/templates/commands/ui.md @@ -0,0 +1,56 @@ +--- +description: Create or update the UI design blueprint (tokens, components API, flows, skeleton HTML, BDD, data contracts). +scripts: + sh: scripts/bash/setup-ui.sh + ps: scripts/powershell/setup-ui.ps1 +--- + +## User Input + +```text +$ARGUMENTS +``` + +You MUST consider the user input before proceeding (if not empty). Treat it as UI intent or additional constraints (e.g., layout style, accessibility priorities, design system hints). + +## Outline + +1. Run `{SCRIPT}` from repo root and parse its JSON for absolute paths: + - `UI_DIR`, `TOKENS_FILE`, `COMPONENTS_SPEC`, `FLOWS_FILE`, `HTML_SKELETON`, `BDD_FILE`, `TYPES_SCHEMA`, `TYPES_TS`, `README_FILE` + - Only run the script once; reuse the JSON printed to the terminal. + +2. Open the UI template README using the path from the script JSON output (`README_FILE`). Do not infer or reconstruct the path. + +3. Populate the six artifacts using the absolute paths from the script JSON (do not guess paths): + - Design Tokens (`tokens.json`): + - Ensure all color, spacing, radius, typography values are declared here. + - DO NOT hard-code hex colors, pixel values, or fonts in other files. + - Component API Spec (`components.md`): + - Define component props/state/events via markdown tables with explicit types and defaults. + - Keep interfaces minimal and testable; document required vs optional clearly. + - Flows/States (`flows.mmd`): + - Draw precise states and transitions (Mermaid stateDiagram-v2); avoid ambiguous labels. + - Structural Skeleton (`skeleton.html`): + - Provide a low-fidelity semantic layout with ARIA roles/labels; avoid styling or hard-coded values. + - Include placeholders that map to components from components.md. + - BDD Stories (`stories.feature`): + - Write Given-When-Then scenarios for core flows; ensure they are verifiable and technology-agnostic. + - Data Contracts (`types.schema.json` or `types.ts`): + - Prefer JSON Schema (`types.schema.json`) for technology neutrality; alternatively provide TypeScript interfaces (`types.ts`). + - Document field semantics and error shape. + +4. Consistency checks (fix issues in-place): + - Every visual decision must trace to a token in `tokens.json`. + - Components referenced in `skeleton.html` must appear in `components.md`. + - Flows and BDD scenarios should align on states and naming. + - Data contracts should cover the payloads implied by events and results. + +5. Report completion with the absolute paths above and a brief summary of what changed. + +## Quality Rules + +- Tokens-only styling: all colors/spacing/typography come from tokens. +- Framework-agnostic: keep markup portable; add notes for framework mapping as comments if needed. +- Accessibility-first: include roles/labels/aria-live where applicable. +- Tables: ensure markdown tables render (pipes, headers, separators formatted correctly). + - Pathing: Always use the script JSON output keys (`UI_DIR`, `TOKENS_FILE`, `COMPONENTS_SPEC`, `FLOWS_FILE`, `HTML_SKELETON`, `BDD_FILE`, `TYPES_SCHEMA`/`TYPES_TS`, `README_FILE`). diff --git a/templates/ui/README.md b/templates/ui/README.md new file mode 100644 index 0000000000..389be36ad8 --- /dev/null +++ b/templates/ui/README.md @@ -0,0 +1,27 @@ +# UI Blueprint Templates + +Purpose: Provide framework-agnostic, machine-readable UI design blueprints to reduce ambiguity during AI-assisted implementation. + +What’s included (six artifacts): +- Design Tokens (`tokens.json`): central color, spacing, radius, and typography values. +- Component API Spec (`components.md`): props/state/events for key components using tables. +- Flows/States (`flows.mmd`): Mermaid state/flow diagram scaffold. +- Structural Skeleton (`skeleton.html`): low-fidelity, semantic HTML skeleton with ARIA hints. +- BDD Stories (`stories.feature`): Given-When-Then acceptance stories. +- Data Contracts (choose one): + - `types.schema.json` (preferred; JSON Schema for technology neutrality) + - `types.ts` (TypeScript interfaces) + +Guidelines: +- Always reference tokens (no hard-coded hex colors, spacing, or fonts). +- Keep the skeleton semantic (landmarks, headings, ARIA attributes). +- Keep APIs testable and minimal; document default values explicitly. +- BDD must be verifiable and technology-agnostic. +- Prefer interfaces that map 1:1 to user actions. + - Sizing guidance: consider mapping `px` to `rem` in implementations (e.g., body 16px → 1rem) to improve accessibility and zoom behavior. + +Paths: +- Use the absolute paths printed by the setup script (`README_FILE`, `TOKENS_FILE`, `COMPONENTS_SPEC`, `FLOWS_FILE`, `HTML_SKELETON`, `BDD_FILE`, `TYPES_SCHEMA`/`TYPES_TS`). Do not reconstruct paths manually. + +How it’s used: +- The `/speckit.ui` command copies these templates into `specs//ui/` and prints absolute paths as JSON for downstream automation. diff --git a/templates/ui/components.md b/templates/ui/components.md new file mode 100644 index 0000000000..f8d0b627bc --- /dev/null +++ b/templates/ui/components.md @@ -0,0 +1,34 @@ +--- +title: Component API Specification (Template) +--- + +Guidelines +- Keep props explicit and serializable; avoid passing whole objects when IDs suffice. +- Document default values and whether the prop is required. +- Embrace unidirectional data flow; surface events with clear payloads. + +Example: Selector component + +| Prop | Type | Required | Default | Description | +|------|------|----------|---------|-------------| +| `options` | `Array<{ id: string; label: string; value: string }>` | Yes | `[]` | Available options | +| `value` | `string` | No | `""` | Currently selected `value` | +| `disabled` | `boolean` | No | `false` | Disable interactions | +| `onChange` | `(value: string) => void` | Yes | `() => {}` | Fired when selection changes | + +Example: ResultCard component + +| Prop | Type | Required | Default | Description | +|------|------|----------|---------|-------------| +| `title` | `string` | Yes | — | Main heading | +| `summary` | `string` | No | `""` | Short description | +| `data` | `Record` | No | `{}` | Key-value pairs to render | +| `variant` | `'success' | 'warning' | 'danger' | 'info'` | No | `'info'` | Visual treatment | + +Events (example) + +| Event | Payload | Description | +|-------|---------|-------------| +| `select` | `{ id: string; value: string }` | User chooses an item | +| `retry` | `void` | User triggers retry action | + diff --git a/templates/ui/flows.mmd b/templates/ui/flows.mmd new file mode 100644 index 0000000000..e5f50f0c73 --- /dev/null +++ b/templates/ui/flows.mmd @@ -0,0 +1,24 @@ +%% Mermaid state or flow diagram template +%% Keep states and transitions precise; avoid ambiguous labels. + +stateDiagram-v2 + [*] --> Idle: Page load + + Idle: Waiting for user input + Idle --> Configuring: User inputs or selects options + + Configuring: User adjusting settings + Configuring --> Processing: User submits action + Configuring --> Configuring: Toggle option + + Processing: Awaiting computation/IO + Processing --> ShowingResult: Completed successfully + Processing --> Error: Failed + + ShowingResult: Displaying computed output + ShowingResult --> Configuring: User modifies configuration + ShowingResult --> [*]: User exits + + Error: Displaying error state + Error --> Configuring: User tries again + diff --git a/templates/ui/skeleton.html b/templates/ui/skeleton.html new file mode 100644 index 0000000000..1d834758a0 --- /dev/null +++ b/templates/ui/skeleton.html @@ -0,0 +1,79 @@ + + + + + + + + + Feature UI Skeleton + + + + Feature Title + + Home + Docs + + + + + + Configuration + + + Name + + + + + Probability + + 1 in 1,000,000,000 + 1 in 100,000,000 + 1 in 10,000,000 + + + + Adjust inputs, then start processing. + + + + + Actions + Start + Loading… + + + + Result + + Summary + + Value A— + Value B— + + + + + + + + + + + + + diff --git a/templates/ui/stories.feature b/templates/ui/stories.feature new file mode 100644 index 0000000000..0399784ed0 --- /dev/null +++ b/templates/ui/stories.feature @@ -0,0 +1,15 @@ +Feature: UI interactions and feedback (template) + + Scenario: User selects an option and triggers processing + Given the user is on the configuration panel + And a default option is selected + When the user clicks the "Start" button + Then a loading indicator is shown + And upon completion the result card updates with computed values + + Scenario: User changes an option and sees updated expectation + Given the user previously saw a result + When the user selects a different option + Then the selection control reflects the change + And the expectation text updates accordingly + diff --git a/templates/ui/tokens.json b/templates/ui/tokens.json new file mode 100644 index 0000000000..74dc6d66ff --- /dev/null +++ b/templates/ui/tokens.json @@ -0,0 +1,59 @@ +{ + "colors": { + "primary": "#4A90E2", + "secondary": "#7B61FF", + "success": "#28A745", + "warning": "#F5A623", + "danger": "#DC3545", + "text": "#333333", + "mutedText": "#6B7280", + "background": "#F5F7FA", + "surface": "#FFFFFF", + "border": "#E5E7EB" + }, + "spacing": { + "xs": "4px", + "sm": "8px", + "md": "16px", + "lg": "24px", + "xl": "32px" + }, + "radius": { + "sm": "6px", + "md": "10px", + "lg": "14px" + }, + "shadow": { + "sm": "0 1px 2px rgba(0,0,0,0.06)", + "md": "0 4px 8px rgba(0,0,0,0.08)", + "lg": "0 10px 20px rgba(0,0,0,0.12)" + }, + "typography": { + "fontFamily": "Inter, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\"", + "h1": { "size": "32px", "weight": 700, "lineHeight": "40px" }, + "h2": { "size": "24px", "weight": 600, "lineHeight": "32px" }, + "body": { "size": "16px", "weight": 400, "lineHeight": "24px" }, + "caption": { "size": "12px", "weight": 400, "lineHeight": "16px" } + }, + "breakpoints": { + "sm": "640px", + "md": "768px", + "lg": "1024px", + "xl": "1280px" + }, + "zIndex": { + "dropdown": 1000, + "overlay": 1100, + "modal": 1200, + "toast": 1300 + }, + "opacity": { + "disabled": 0.5, + "muted": 0.7 + }, + "motion": { + "duration": { "fast": "120ms", "normal": "200ms", "slow": "320ms" }, + "easing": { "standard": "cubic-bezier(0.2, 0.0, 0, 1)", "emphasized": "cubic-bezier(0.2, 0, 0, 1)" }, + "focusRing": { "width": "2px", "offset": "2px" } + } +} diff --git a/templates/ui/types.schema.json b/templates/ui/types.schema.json new file mode 100644 index 0000000000..43c9c18513 --- /dev/null +++ b/templates/ui/types.schema.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:spec-kit:ui:types", + "title": "UI Data Contracts", + "type": "object", + "properties": { + "ComputationResult": { + "type": "object", + "properties": { + "valueA": { "type": "number" }, + "valueB": { "type": "number" }, + "formattedSummary": { "type": "string" }, + "formula": { "type": ["string", "null"] } + }, + "required": ["valueA", "valueB", "formattedSummary"], + "additionalProperties": false + }, + "OptionItem": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "label": { "type": "string" }, + "value": { "type": "string" } + }, + "required": ["id", "label", "value"], + "additionalProperties": false + }, + "SelectorChangeEvent": { + "type": "object", + "properties": { + "value": { "type": "string" }, + "id": { "type": ["string", "null"] } + }, + "required": ["value"], + "additionalProperties": false + }, + "ApiError": { + "type": "object", + "properties": { + "code": { "type": "string" }, + "message": { "type": "string" } + }, + "required": ["code", "message"], + "additionalProperties": false + } + } +} + diff --git a/templates/ui/types.ts b/templates/ui/types.ts new file mode 100644 index 0000000000..1c95ba0840 --- /dev/null +++ b/templates/ui/types.ts @@ -0,0 +1,25 @@ +// UI data contracts (TypeScript interfaces) + +export interface ComputationResult { + valueA: number; + valueB: number; + formattedSummary: string; // e.g., "632.9e9 units" + formula?: string; +} + +export interface OptionItem { + id: string; + label: string; + value: string; // normalized value used internally +} + +export interface SelectorChangeEvent { + value: string; + id?: string; +} + +export interface ApiError { + code: string; + message: string; +} +
Adjust inputs, then start processing.