From 40581435b2b3c5f320de1e7f6d13c0630853a18c Mon Sep 17 00:00:00 2001 From: Ismael Canal Date: Tue, 21 Apr 2026 14:26:48 +0200 Subject: [PATCH 1/3] Add dependabot config, issue/PR templates, and license section in README Address OSPO readiness scanner findings: - Add .github/dependabot.yml for npm and GitHub Actions - Add bug report and feature request issue templates - Add pull request template - Add License section to README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug_report.yml | 35 +++ .github/ISSUE_TEMPLATE/feature_request.yml | 22 ++ .github/dependabot.yml | 10 + .github/pull_request_template.md | 17 ++ README.md | 303 +-------------------- 5 files changed, 85 insertions(+), 302 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/dependabot.yml create mode 100644 .github/pull_request_template.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..2bdcec9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,35 @@ +name: Bug report +description: Report a problem with TUIKit +labels: ["bug"] +body: + - type: textarea + attributes: + label: Describe the bug + description: A clear description of what the bug is. + validations: + required: true + - type: textarea + attributes: + label: Steps to reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. Run command ... + 2. See error ... + validations: + required: true + - type: textarea + attributes: + label: Expected behavior + description: What you expected to happen. + validations: + required: true + - type: input + attributes: + label: TUIKit version or commit + description: Which version or commit SHA are you using? + validations: + required: false + - type: textarea + attributes: + label: Additional context + description: Any other context, screenshots, or logs. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..5aae818 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,22 @@ +name: Feature request +description: Suggest an idea for TUIKit +labels: ["enhancement"] +body: + - type: textarea + attributes: + label: Describe the feature + description: A clear description of what you would like to happen. + validations: + required: true + - type: textarea + attributes: + label: Use case + description: What problem does this solve? Why is this needed? + validations: + required: true + - type: textarea + attributes: + label: Alternatives considered + description: Any alternative solutions or features you have considered. + validations: + required: false diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..782a0ad --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..f02c6f9 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,17 @@ +## Summary + + + +## Changes + + + +## Testing + + + +## Checklist + +- [ ] Specs lint passes (`bun run lint`) +- [ ] Tests updated if applicable +- [ ] Documentation updated if applicable diff --git a/README.md b/README.md index 03c8a97..8cedd9e 100644 --- a/README.md +++ b/README.md @@ -1,302 +1 @@ -# TUIkit Specs - -A spec-driven system for building UI components across programming languages. -Each component is defined as a language-agnostic markdown spec with behavioral -tests. An LLM agent acts as the "compiler" — reading specs and generating -idiomatic implementations per target framework. - -## How it works - -```mermaid -flowchart LR - Specs["Spec files\n(.md)"] --> Compile["compile.ts\n(prompt)"] - Compile --> Agent["LLM Agent\n(compiler)"] - Agent --> Dist["dist/{target}/\n(generated code)"] - Agent --> Lock["lock file\n(.json)"] -``` - -1. **Specs** define behavior + semantic tokens (like headless UI libraries) -2. **Target specs** define how to translate to a specific language/framework -3. **compile.ts** detects changed specs and generates a self-contained prompt -4. An **LLM agent** reads the prompt and generates idiomatic code -5. Generated code goes to **dist/** — specs stay clean -6. **Lock files** track which spec versions have been compiled - -## Quick start - -### Prerequisites - -- [Bun](https://bun.sh/) 1.1+ installed (`bun --version`) - -### Install dependencies - -```bash -bun install -``` - -### Common commands - -```bash -# Lint all specs against the schema -bun run lint - -# Check what needs compiling -bun run compile status - -# Generate a prompt for a target -bun run compile prompt --target go - -# The prompt is written to dist/go/_compile-prompt.md -# Feed it to an LLM agent (e.g. Copilot CLI, Claude, etc.) -# The agent writes generated code to dist/go/ - -# After verifying the generated code works, lock the hashes -bun run compile lock --target go -``` - -## Repository structure - -``` -TUIKit/ - components/ Component specs, tests, and preview definitions - tokens/ Semantic design tokens (colors, icons, breakpoints) - targets/ Target language/framework definitions - docs/ Meta-schema and design foundations - scripts/ Compiler and linter CLIs - dist/ Compiled output per target (gitignored) -``` - -## Writing specs - -### Component spec - -Each component is a markdown file with YAML frontmatter and prose body: - -````yaml ---- -kind: component -name: MyComponent -description: One-line summary. -version: 1 -category: input # input | display | navigation | layout | feedback - -tokens: - colors: [textPrimary, selected] - icons: [iconPrompt] - -props: - label: - type: string - required: true - description: Display text. - -dependencies: - tokens: - - name: textPrimary - kind: color - usage: "Label text" - required: true - components: [] - -accessibility: - role: button - announce: - on_mount: "Button: {label}" ---- - -## Visual rules - -- Label text MUST use the `textPrimary` color token -- Active state MUST use the `selected` color token - -## Rendering example - -Given label: "Click me" - -​``` -Click me -​``` - -## Dependencies - -| Dependency | Kind | Usage | Required | -|------------|------|-------|----------| -| `textPrimary` | color | Label text | Yes | -| `selected` | color | Active state | Yes | -```` - -### Test spec - -Test specs live alongside component specs and use a block-based format: - -```markdown ---- -kind: test -component: MyComponent -version: 1 ---- - -## renders label text - -​`props -label: "Hello" -​` - -​`expect -Hello -​` -``` - -See `docs/schema.md` for the full format reference, including `input`, `state`, -`style`, and `accessibility` test blocks. - -### Conformance language - -All normative sections (Visual rules, Behavior, Edge cases) use -[RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords: - -- **MUST** — absolute requirement -- **SHOULD** — strong recommendation -- **MAY** — optional behavior -- **MUST NOT** — absolute prohibition - -## Compiling to a target - -### Available targets - -| Target | Language | Framework | File | -| -------- | ---------- | ---------------------- | ------------------- | -| `go` | Go | Bubbletea + Lipgloss | `targets/go.md` | -| `node` | TypeScript | Ink + React (Node.js) | `targets/node.md` | -| `bun` | TypeScript | OpenTUI + React (Bun) | `targets/bun.md` | -| `rust` | Rust | Ratatui + Crossterm | `targets/rust.md` | - -### Workflow - -```bash -# 1. See what's changed -bun run compile status - -# 2. Generate the compilation prompt -bun run compile prompt --target go - -# 3. Feed dist/go/_compile-prompt.md to an LLM agent -# The agent generates code into dist/go/ - -# 4. Verify: run tests, check the demo CLI -cd dist/go && go test ./... && go run ./cmd/demo - -# 5. Lock the hashes -bun run compile lock --target go -``` - -### Multi-pass compilation - -A single compilation pass across the full component suite (17 components + -tokens + demo) is usually not enough to reach production quality. We've found -that **2–3 passes** produce notably better results: - -| Pass | Focus | Typical outcome | -| ---- | ----- | --------------- | -| **1st** | Initial generation | All components scaffold correctly, most tests pass, demo wires up. Expect rough edges — missing edge cases, incomplete keybindings, demo wiring bugs. | -| **2nd** | Review & fix | Agent reviews its own output against specs, fixes test failures, fills in missing behavior, improves demo interactivity. Test count typically grows 30–50%. | -| **3rd** | Polish | Catches subtle spec violations, improves accessibility, hardens demo `--snapshot` smoke tests. Diminishing returns after this point. | - -To run a follow-up pass, generate a new prompt and tell the agent to review -and complete its existing work: - -```bash -# Generate a fresh prompt (it sees the current dist/ state) -bun run compile prompt --target go - -# Feed to the agent with instructions like: -# "Review your existing implementation against the specs. -# Fix any test failures, fill in missing behavior, -# and ensure all --snapshot smoke tests pass." -``` - -Each pass is fast because the agent builds on its own prior output rather than -starting from scratch. The demo's `--list` and `--snapshot` flags make it easy -for the agent to self-verify between passes. - -### Custom output directory - -By default, compiled code goes to `dist/`. Override with `--out`: - -```bash -# Output to a separate repo or directory -bun run compile prompt --target go --out ~/my-tuikit-go - -# The prompt and generated code go to ~/my-tuikit-go/go/ -``` - -### Adding a new target - -1. Create `targets/{name}.md` following the target spec format in `docs/schema.md` -2. Define: architecture pattern, type mapping, callback translation, state - machine pattern, token access, styling, composition, test pattern, key - mapping, dependencies, and demo CLI -3. Run `bun run compile status` — your target will show up with all specs dirty -4. Run `bun run compile prompt --target {name}` and compile - -## Linting - -```bash -# Lint all specs -bun run lint - -# Lint a single component -bun run lint --component Select - -# Show fix suggestions -bun run lint --fix - -# See all rules -bun run lint --help -``` - -The linter checks: - -- Required frontmatter fields and valid values (zod schemas) -- Naming conventions (PascalCase components, camelCase props) -- RFC 2119 keyword usage in normative sections -- ARIA accessibility structure for interactive components -- Token cross-references resolve to known tokens -- Required body sections (Visual rules, Rendering example, Dependencies) -- Test specs reference existing components -- Broken internal markdown links - -Rule definitions live in `scripts/lint-rules.ts` — edit that file to add or -change rules, severities, and fix hints. - -## CI checks - -The GitHub Actions workflow (`.github/workflows/specs-ci.yml`) runs on every PR: - -1. **Spec lint** — `bun run lint` -2. **Compiler health** — `bun run compile status` for each target -3. **Prompt smoke test** — `bun run compile prompt` for each target -4. **No generated output committed** — ensures `dist/` is not tracked -5. **Changed-spec completeness** — if `{Name}.md` changes, matching `.test.md` and `.preview.md` must also change - -## Design principles - -- **Specs capture intent, not implementation** — ~95% behavioral intent vs. - ~5% framework hints. This lets agents generate idiomatic code per framework - rather than awkward transliterations. - -- **Color tokens define meaning, not color values** — tokens like `textPrimary` - and `selected` define UI roles. The color engine (Rampa, hardcoded hex, - ANSI palette) is an implementation detail per target. - -- **Layout is out of scope** — specs define behavior and semantic tokens. - Spacing, padding, and spatial polish are per-target decisions (similar to - headless UI libraries like Radix or Base UI). - -- **Lock files enable incremental compilation** — only dirty specs trigger - regeneration. Schema changes invalidate everything. Lock files are gitignored; - a fresh clone starts with everything dirty. - -For TUI design foundations — color systems, typography, iconography, layout -grids, accessibility patterns, keybinding conventions, and buffer management — -see [`docs/foundations.md`](docs/foundations.md). +@- \ No newline at end of file From 4ae346f76ab47be212bdd8438c66f1cdf383740a Mon Sep 17 00:00:00 2001 From: Ismael Canal Date: Tue, 21 Apr 2026 14:32:57 +0200 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 782a0ad..907bfbb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,6 +1,6 @@ version: 2 updates: - - package-ecosystem: "npm" + - package-ecosystem: "bun" directory: "/" schedule: interval: "weekly" From 9346da6a46ebb88aed380d864a998ea1ee9413fa Mon Sep 17 00:00:00 2001 From: Ismael Canal Date: Tue, 21 Apr 2026 14:34:20 +0200 Subject: [PATCH 3/3] =?UTF-8?q?Fix=20README.md=20=E2=80=94=20restore=20ful?= =?UTF-8?q?l=20content=20and=20add=20License=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 306 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8cedd9e..d524f43 100644 --- a/README.md +++ b/README.md @@ -1 +1,306 @@ -@- \ No newline at end of file +# TUIkit Specs + +A spec-driven system for building UI components across programming languages. +Each component is defined as a language-agnostic markdown spec with behavioral +tests. An LLM agent acts as the "compiler" — reading specs and generating +idiomatic implementations per target framework. + +## How it works + +```mermaid +flowchart LR + Specs["Spec files\n(.md)"] --> Compile["compile.ts\n(prompt)"] + Compile --> Agent["LLM Agent\n(compiler)"] + Agent --> Dist["dist/{target}/\n(generated code)"] + Agent --> Lock["lock file\n(.json)"] +``` + +1. **Specs** define behavior + semantic tokens (like headless UI libraries) +2. **Target specs** define how to translate to a specific language/framework +3. **compile.ts** detects changed specs and generates a self-contained prompt +4. An **LLM agent** reads the prompt and generates idiomatic code +5. Generated code goes to **dist/** — specs stay clean +6. **Lock files** track which spec versions have been compiled + +## Quick start + +### Prerequisites + +- [Bun](https://bun.sh/) 1.1+ installed (`bun --version`) + +### Install dependencies + +```bash +bun install +``` + +### Common commands + +```bash +# Lint all specs against the schema +bun run lint + +# Check what needs compiling +bun run compile status + +# Generate a prompt for a target +bun run compile prompt --target go + +# The prompt is written to dist/go/_compile-prompt.md +# Feed it to an LLM agent (e.g. Copilot CLI, Claude, etc.) +# The agent writes generated code to dist/go/ + +# After verifying the generated code works, lock the hashes +bun run compile lock --target go +``` + +## Repository structure + +``` +TUIKit/ + components/ Component specs, tests, and preview definitions + tokens/ Semantic design tokens (colors, icons, breakpoints) + targets/ Target language/framework definitions + docs/ Meta-schema and design foundations + scripts/ Compiler and linter CLIs + dist/ Compiled output per target (gitignored) +``` + +## Writing specs + +### Component spec + +Each component is a markdown file with YAML frontmatter and prose body: + +````yaml +--- +kind: component +name: MyComponent +description: One-line summary. +version: 1 +category: input # input | display | navigation | layout | feedback + +tokens: + colors: [textPrimary, selected] + icons: [iconPrompt] + +props: + label: + type: string + required: true + description: Display text. + +dependencies: + tokens: + - name: textPrimary + kind: color + usage: "Label text" + required: true + components: [] + +accessibility: + role: button + announce: + on_mount: "Button: {label}" +--- + +## Visual rules + +- Label text MUST use the `textPrimary` color token +- Active state MUST use the `selected` color token + +## Rendering example + +Given label: "Click me" + +​``` +Click me +​``` + +## Dependencies + +| Dependency | Kind | Usage | Required | +|------------|------|-------|----------| +| `textPrimary` | color | Label text | Yes | +| `selected` | color | Active state | Yes | +```` + +### Test spec + +Test specs live alongside component specs and use a block-based format: + +```markdown +--- +kind: test +component: MyComponent +version: 1 +--- + +## renders label text + +​`props +label: "Hello" +​` + +​`expect +Hello +​` +``` + +See `docs/schema.md` for the full format reference, including `input`, `state`, +`style`, and `accessibility` test blocks. + +### Conformance language + +All normative sections (Visual rules, Behavior, Edge cases) use +[RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords: + +- **MUST** — absolute requirement +- **SHOULD** — strong recommendation +- **MAY** — optional behavior +- **MUST NOT** — absolute prohibition + +## Compiling to a target + +### Available targets + +| Target | Language | Framework | File | +| -------- | ---------- | ---------------------- | ------------------- | +| `go` | Go | Bubbletea + Lipgloss | `targets/go.md` | +| `node` | TypeScript | Ink + React (Node.js) | `targets/node.md` | +| `bun` | TypeScript | OpenTUI + React (Bun) | `targets/bun.md` | +| `rust` | Rust | Ratatui + Crossterm | `targets/rust.md` | + +### Workflow + +```bash +# 1. See what's changed +bun run compile status + +# 2. Generate the compilation prompt +bun run compile prompt --target go + +# 3. Feed dist/go/_compile-prompt.md to an LLM agent +# The agent generates code into dist/go/ + +# 4. Verify: run tests, check the demo CLI +cd dist/go && go test ./... && go run ./cmd/demo + +# 5. Lock the hashes +bun run compile lock --target go +``` + +### Multi-pass compilation + +A single compilation pass across the full component suite (17 components + +tokens + demo) is usually not enough to reach production quality. We've found +that **2–3 passes** produce notably better results: + +| Pass | Focus | Typical outcome | +| ---- | ----- | --------------- | +| **1st** | Initial generation | All components scaffold correctly, most tests pass, demo wires up. Expect rough edges — missing edge cases, incomplete keybindings, demo wiring bugs. | +| **2nd** | Review & fix | Agent reviews its own output against specs, fixes test failures, fills in missing behavior, improves demo interactivity. Test count typically grows 30–50%. | +| **3rd** | Polish | Catches subtle spec violations, improves accessibility, hardens demo `--snapshot` smoke tests. Diminishing returns after this point. | + +To run a follow-up pass, generate a new prompt and tell the agent to review +and complete its existing work: + +```bash +# Generate a fresh prompt (it sees the current dist/ state) +bun run compile prompt --target go + +# Feed to the agent with instructions like: +# "Review your existing implementation against the specs. +# Fix any test failures, fill in missing behavior, +# and ensure all --snapshot smoke tests pass." +``` + +Each pass is fast because the agent builds on its own prior output rather than +starting from scratch. The demo's `--list` and `--snapshot` flags make it easy +for the agent to self-verify between passes. + +### Custom output directory + +By default, compiled code goes to `dist/`. Override with `--out`: + +```bash +# Output to a separate repo or directory +bun run compile prompt --target go --out ~/my-tuikit-go + +# The prompt and generated code go to ~/my-tuikit-go/go/ +``` + +### Adding a new target + +1. Create `targets/{name}.md` following the target spec format in `docs/schema.md` +2. Define: architecture pattern, type mapping, callback translation, state + machine pattern, token access, styling, composition, test pattern, key + mapping, dependencies, and demo CLI +3. Run `bun run compile status` — your target will show up with all specs dirty +4. Run `bun run compile prompt --target {name}` and compile + +## Linting + +```bash +# Lint all specs +bun run lint + +# Lint a single component +bun run lint --component Select + +# Show fix suggestions +bun run lint --fix + +# See all rules +bun run lint --help +``` + +The linter checks: + +- Required frontmatter fields and valid values (zod schemas) +- Naming conventions (PascalCase components, camelCase props) +- RFC 2119 keyword usage in normative sections +- ARIA accessibility structure for interactive components +- Token cross-references resolve to known tokens +- Required body sections (Visual rules, Rendering example, Dependencies) +- Test specs reference existing components +- Broken internal markdown links + +Rule definitions live in `scripts/lint-rules.ts` — edit that file to add or +change rules, severities, and fix hints. + +## CI checks + +The GitHub Actions workflow (`.github/workflows/specs-ci.yml`) runs on every PR: + +1. **Spec lint** — `bun run lint` +2. **Compiler health** — `bun run compile status` for each target +3. **Prompt smoke test** — `bun run compile prompt` for each target +4. **No generated output committed** — ensures `dist/` is not tracked +5. **Changed-spec completeness** — if `{Name}.md` changes, matching `.test.md` and `.preview.md` must also change + +## Design principles + +- **Specs capture intent, not implementation** — ~95% behavioral intent vs. + ~5% framework hints. This lets agents generate idiomatic code per framework + rather than awkward transliterations. + +- **Color tokens define meaning, not color values** — tokens like `textPrimary` + and `selected` define UI roles. The color engine (Rampa, hardcoded hex, + ANSI palette) is an implementation detail per target. + +- **Layout is out of scope** — specs define behavior and semantic tokens. + Spacing, padding, and spatial polish are per-target decisions (similar to + headless UI libraries like Radix or Base UI). + +- **Lock files enable incremental compilation** — only dirty specs trigger + regeneration. Schema changes invalidate everything. Lock files are gitignored; + a fresh clone starts with everything dirty. + +For TUI design foundations — color systems, typography, iconography, layout +grids, accessibility patterns, keybinding conventions, and buffer management — +see [`docs/foundations.md`](docs/foundations.md). + +## License + +This project is licensed under the [MIT License](LICENSE). \ No newline at end of file