diff --git a/.github/actions/start-preview-server/action.yml b/.github/actions/start-preview-server/action.yml new file mode 100644 index 0000000..ecc34f2 --- /dev/null +++ b/.github/actions/start-preview-server/action.yml @@ -0,0 +1,51 @@ +# Reusable composite action — Start VitePress preview server +# +# Starts `bun run docs:preview` in the background and polls until the server +# responds (or fails after a configurable timeout). Reused by a11y.yaml, +# responsive.yaml, and any future workflow that needs a running docs preview. +# +# Usage: +# - name: Start VitePress preview server +# uses: ./.github/actions/start-preview-server +# # (optionally) with: +# # port: "4173" +# # base: "/github-code-search/" +# # timeout: "60" +name: "Start VitePress preview server" +description: > + Starts `bun run docs:preview` in the background on a given port and polls + until the server responds — or fails after a configurable timeout. + +inputs: + port: + description: TCP port the preview server should listen on. + default: "4173" + base: + description: Base URL path to poll when checking readiness. + default: "/github-code-search/" + timeout: + description: Maximum number of seconds to wait for the server to be ready. + default: "60" + +runs: + using: composite + steps: + - name: Start VitePress preview + shell: bash + run: bun run docs:preview -- --port ${{ inputs.port }} & + + - name: Wait for preview server to be ready + shell: bash + run: | + URL="http://localhost:${{ inputs.port }}${{ inputs.base }}" + echo "Waiting for ${URL} …" + DEADLINE=$(( $(date +%s) + ${{ inputs.timeout }} )) + until curl -sf "${URL}" > /dev/null 2>&1; do + if [ "$(date +%s)" -ge "${DEADLINE}" ]; then + echo "::error::Preview server did not respond within ${{ inputs.timeout }} s on ${URL}." + exit 1 + fi + echo "… retrying in 2 s" + sleep 2 + done + echo "Preview server is ready." diff --git a/.github/instructions/bug-fixing.instructions.md b/.github/instructions/bug-fixing.instructions.md index 3771171..49d6961 100644 --- a/.github/instructions/bug-fixing.instructions.md +++ b/.github/instructions/bug-fixing.instructions.md @@ -5,6 +5,8 @@ excludeAgent: "code-review" # Bug fixing — instructions for Copilot coding agent +> **Skill reference:** for the extended symptom → module diagnostic table, test-first patterns and minimal fix principles read `.github/skills/bug-fixing.md` first. + Follow these steps when fixing a bug in this repository. ## 1. Reproduce the bug before writing any fix diff --git a/.github/instructions/documentation.instructions.md b/.github/instructions/documentation.instructions.md index 198e0fc..8ec039e 100644 --- a/.github/instructions/documentation.instructions.md +++ b/.github/instructions/documentation.instructions.md @@ -4,6 +4,8 @@ applyTo: "docs/**" # Documentation — instructions for Copilot coding agent +> **Skill reference:** for deep domain knowledge (VitePress theme architecture, CSS variables, accessibility patterns, responsive patterns, full validation commands) read `.github/skills/documentation.md` first. + Follow these conventions when writing or editing pages in the `docs/` directory. ## 1. Tool & rendering pipeline @@ -93,9 +95,20 @@ docs/ Before opening a PR for any docs change: ```bash -bun run docs:build # must complete without errors -bun run format:check # oxfmt — no formatting diff +bun run docs:build # must complete without errors or dead-link warnings +bun run format:check # oxfmt — no formatting diff ``` - All internal links must resolve (VitePress reports dead links on build). - No new `bun run knip` violations (docs/\*\* is excluded but `package.json` changes are not). + +If the PR modifies any Vue component, CSS, or page layout, also run the accessibility and responsive suites: + +```bash +bun run docs:build:a11y +bun run docs:preview -- --port 4173 & +bun run docs:a11y # pa11y-ci WCAG 2.1 AA — must report 0 errors +bun run docs:test:responsive # Playwright — 20/20 tests green (4 viewports × 5 pages) +``` + +See `.github/skills/documentation.md` for pa11y configuration details, WCAG contrast rules, accessible component patterns, and responsive breakpoint guidance. diff --git a/.github/instructions/github-actions.instructions.md b/.github/instructions/github-actions.instructions.md new file mode 100644 index 0000000..cb46890 --- /dev/null +++ b/.github/instructions/github-actions.instructions.md @@ -0,0 +1,145 @@ +--- +applyTo: ".github/workflows/**" +--- + +# GitHub Actions — instructions for Copilot coding agent + +> **Skill reference:** for the full best-practices guide, action-pinning decision table, composite action patterns and PR comment strategies read `.github/skills/github-actions.md` first. + +Follow these steps when creating or modifying GitHub Actions workflows in this repository. + +## 1. File conventions + +- All workflow files use the **`.yaml`** extension (not `.yml`). +- File names use **kebab-case**: `a11y.yaml`, `lighthouse.yaml`, `docs.yaml`. +- Every workflow must start with a block comment explaining its purpose, triggers and strategy. + +## 2. Pinning third-party actions + +**Every third-party action (anything not `actions/*` from GitHub itself) MUST be pinned +to an exact commit SHA, never to a tag or a branch.** + +```yaml +# ✅ correct — SHA-pinned with tag comment +uses: owner/repo@<40-char-sha> # v1.2.3 + +# ❌ wrong — mutable tag +uses: owner/repo@v1 + +# ❌ wrong — branch (can be force-pushed) +uses: owner/repo@main +``` + +To resolve a tag to its commit SHA: + +```bash +git ls-remote https://github.com//.git refs/tags/ refs/tags/^{} +# The ^{} peeled SHA (second line, if present) is the actual commit. Use that one. +``` + +Add a comment `# v1.2.3` to the right of the hash so the version is human-readable. + +**First-party GitHub actions** (`actions/checkout`, `actions/upload-artifact`, etc.) should +also be pinned. Always resolve the latest released tag before using any action. + +## 3. Coordinated version upgrades + +When bumping an action version, update **every workflow file** that uses it in the same commit. +Actions that appear in multiple workflows (e.g. `actions/checkout`, `oven-sh/setup-bun`) must +always reference **the same commit SHA** across all files. Use `grep` to find all usages before +opening a PR. + +```bash +grep -r "oven-sh/setup-bun" .github/workflows/ +``` + +## 4. DRY — composite action for shared steps + +If two or more workflows share identical steps (e.g. starting a preview server, waiting for it +to be ready), extract them into a **composite action** under `.github/actions//action.yml`. + +```yaml +# In a workflow: +- name: Start VitePress preview server + uses: ./.github/actions/start-preview-server +``` + +The composite action must declare all inputs with defaults and document each one. Never +duplicate multi-step shell sequences across workflows. + +## 5. PR comment reports + +Every workflow that produces a structured report (audit scores, coverage, test results) **must**: + +1. Generate a formatted Markdown summary (table preferred). +2. Post it as a **sticky PR comment** using + `marocchino/sticky-pull-request-comment@ # v2.9.4` with a unique `header:` value + so the comment is updated (not duplicated) on each push to the PR. +3. Use `actions/github-script` to build the comment body when the data comes from JSON files + produced by the workflow (avoids shelling out to `jq` / Python). + +```yaml +- name: Generate scores comment + id: comment-body + if: github.event_name == 'pull_request' + uses: actions/github-script@ # v7 + with: + result-encoding: string + script: | + // ... parse JSON, build Markdown table, return body + +- name: Post / update comment on PR + if: github.event_name == 'pull_request' + uses: marocchino/sticky-pull-request-comment@ # v2.9.4 + with: + header: + message: ${{ steps.comment-body.outputs.result }} +``` + +## 6. Minimum required permissions + +Set `permissions: contents: read` at the **workflow level** as the default. +Override to `write` **at the job level** only for the exact permissions needed: + +```yaml +permissions: + contents: read # workflow-level default (principle of least privilege) + +jobs: + audit: + permissions: + contents: read + pull-requests: write # needed only to post the PR comment +``` + +## 7. Concurrency + +Every workflow that produces side-effects (deploy, comment, upload) must define a +`concurrency` block to cancel stale runs: + +```yaml +concurrency: + group: -${{ github.ref }} + cancel-in-progress: true +``` + +## 8. Validation checklist before opening a PR + +```bash +# Lint all workflow files locally (requires actionlint): +actionlint .github/workflows/*.yaml .github/actions/**/*.yml + +# Confirm every action is pinned: +grep -rn "uses:" .github/workflows/ | grep -v "@[a-f0-9]\{40\}" +# → must return nothing +``` + +Also verify: + +- [ ] All `.yml` workflow files have been renamed to `.yaml` +- [ ] Every new third-party action has a `# vX.Y.Z` comment after its SHA +- [ ] New reusable composite actions are under `.github/actions//action.yml` +- [ ] The workflow self-references the correct filename (e.g. in `paths:`) +- [ ] `pull-requests: write` is set only on jobs that post comments +- [ ] No `bunx` in workflow `run:` steps — use binaries from `node_modules/.bin/` or + scripts defined in `package.json` via `bun run @@ -30,17 +82,26 @@ const ROWS: Row[] = [ org-wide code audits and interactive triage.

+ - - + - @@ -48,14 +109,31 @@ const ROWS: Row[] = [ - + @@ -109,7 +187,7 @@ const ROWS: Row[] = [ .ct-intro { margin: 0; padding: 20px 24px 18px; - font-size: 14px; + font-size: 15.5px; line-height: 1.7; color: var(--vp-c-text-2); border-bottom: 1px solid var(--vp-c-divider); @@ -123,6 +201,13 @@ const ROWS: Row[] = [ border-radius: 4px; } +/* Fix: brand-1 (#9933ff) on yellow brand-soft blended with card-bg = ~4.2:1 (fails) + * brand-2 (#7a1fd4) on white bg = 7.0:1 ✓ WCAG AA (light mode only) */ +html:not(.dark) .ct-intro code { + color: var(--vp-c-brand-2); + background: rgba(122, 31, 212, 0.08); +} + .ct-intro a { color: var(--vp-c-brand-1); text-decoration: underline; @@ -160,13 +245,14 @@ thead tr { } .ct-tool-name { - font-size: 13px; + font-size: 14px; font-weight: 600; white-space: nowrap; } .ct-tool-alt { - color: var(--vp-c-text-3); + /* Fix: var(--vp-c-text-3) = 2.87:1, below WCAG AA 4.5:1. text-2 ≥ 5.4:1. */ + color: var(--vp-c-text-2); } .ct-tool-brand { @@ -178,7 +264,8 @@ thead tr { padding: 2px 8px; border-radius: 9999px; background: rgba(153, 51, 255, 0.12); - color: var(--vp-c-brand-1); + /* Fix: brand-1 (#9933ff) on soft purple bg = ~3.6:1 → brand-2 (#7a1fd4) = 5.2:1 ✓ WCAG AA */ + color: var(--vp-c-brand-2); font-size: 10px; font-weight: 600; letter-spacing: 0.04em; @@ -210,12 +297,46 @@ thead tr { } .ct-feature { - padding: 14px 24px; - font-size: 14px; + padding: 12px 24px; + font-size: 15px; color: var(--vp-c-text-1); line-height: 1.5; } +.ct-feature-link, +.ct-feature-plain { + display: flex; + flex-direction: column; + gap: 3px; + color: var(--vp-c-text-1); + text-decoration: none; +} + +.ct-feature-link:hover { + color: var(--vp-c-text-1); +} + +.ct-feature-title { + display: inline-flex; + align-items: center; + gap: 5px; + font-size: 15px; + font-weight: 600; + color: inherit; +} + +.ct-feature-desc { + font-size: 13px; + font-weight: 400; + /* Fix: var(--vp-c-text-3) ≈ 2.87:1, below WCAG AA. text-1 ensures ≥4.5:1. */ + color: var(--vp-c-text-1); + line-height: 1.45; +} + +.ct-feature-link:hover .ct-feature-desc { + color: var(--vp-c-text-2); +} + .ct-cell { padding: 14px 12px; text-align: center; @@ -245,29 +366,68 @@ thead tr { color: #ef4444; } +/* Short/long label switching — long shown by default, short on mobile */ +.ct-name-short { + display: none; +} + /* ── Responsive ────────────────────────────────────────────────────────── */ + +/* + * ≤ 640 px — keep both tool columns but use abbreviated headers, drop badges + * and descriptions, tighten padding. + * Inspired by bun.sh's feature comparison table: 3 columns (feature + 2 tools) + * always visible, even on 360 px — tool headers very short, icons centred. + */ @media (max-width: 640px) { + /* Switch to abbreviated column headers */ + .ct-name-long { + display: none; + } + .ct-name-short { + display: inline; + } + + /* Feature col narrower, tool cols equal */ .ct-th-feature { - width: 55%; - padding: 14px 14px; + width: 56%; + padding: 10px 12px; } .ct-th-tool { - width: 22.5%; - padding: 14px 8px; + width: 22%; + padding: 10px 4px; } .ct-feature { - padding: 12px 14px; + padding: 10px 12px; font-size: 13px; } + .ct-cell { + padding: 10px 4px; + } + .ct-tool-name { font-size: 11px; + font-weight: 700; } .ct-badge { display: none; } + + /* Hide descriptions — feature title alone is sufficient at small sizes */ + .ct-feature-desc { + display: none; + } + + /* Slightly smaller icons so they fit the narrow cells */ + .ct-check, + .ct-cross { + width: 22px; + height: 22px; + font-size: 11px; + } } diff --git a/docs/.vitepress/theme/HowItWorks.vue b/docs/.vitepress/theme/HowItWorks.vue index b14884f..a42498b 100644 --- a/docs/.vitepress/theme/HowItWorks.vue +++ b/docs/.vitepress/theme/HowItWorks.vue @@ -1,7 +1,7 @@
+ Feature comparison between gh search code and github-code-search +
+
- gh search code + + gh search code + gh search +
+
- github-code-search + + github-code-search + gcs + Purpose-built
{{ row.feature }} + + {{ row.feature }} + {{ row.desc }} + + + {{ row.feature }} + {{ row.desc }} + + - - + + - - + +