Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
851e4d8
feat: promotion polish — docs UX, CLI hyperlinks, completions auto-in…
shouze Mar 8, 2026
82a37b8
Make VitePress docs fully WCAG 2.1 AA accessible
shouze Mar 8, 2026
7906646
fix(docs): responsive CSS — mobile-first, VPNav hamburger, Comparison…
shouze Mar 8, 2026
800a06b
test(docs): add Playwright responsive regression tests
shouze Mar 8, 2026
4d3d183
ci: add responsive and a11y workflows, fix setup-bun pin comments
shouze Mar 8, 2026
aa08d48
docs(agents): introduce .github/skills/ knowledge base, update instru…
shouze Mar 8, 2026
c9226f9
chore(review): take into account some feedback
shouze Mar 8, 2026
0d1cd68
ci: pin actions/checkout to SHA de0fac2e (v6.0.2)
shouze Mar 8, 2026
8971570
fix(docs): address Copilot review comments (second batch)
shouze Mar 8, 2026
6be130d
Merge pull request #91 from fulll/feat/accessibility-homepage
shouze Mar 8, 2026
de2d7b1
Potential fix for code scanning alert no. 16: Workflow does not conta…
shouze Mar 8, 2026
6d02d13
Potential fix for code scanning alert no. 17: Workflow does not conta…
shouze Mar 8, 2026
4dbb551
fix(docs): fix tabRefs ref callback crash in UseCaseTabs
shouze Mar 8, 2026
240c25f
fix: address PR #90 review comments
shouze Mar 8, 2026
3ce04df
fix(ci): remove duplicate top-level permissions key in a11y.yml
shouze Mar 8, 2026
0c3ad29
fix(a11y): correct 20 WCAG AA contrast errors from pa11y audit
shouze Mar 8, 2026
7409291
ci: refactor GitHub Actions workflows
shouze Mar 8, 2026
cd269c7
ci: add Lighthouse CI workflow and report script
shouze Mar 8, 2026
f0f6c4c
docs: fix accessibility and apply glass navbar tint
shouze Mar 8, 2026
7403cd6
chore: add GitHub Actions agent instructions and skills
shouze Mar 8, 2026
5fe1b79
fix(a11y): fix 4 contrast failures in TerminalDemo
shouze Mar 8, 2026
dede3f6
fix(docs): use withBase() for ComparisonTable internal doc links
shouze Mar 8, 2026
c38b261
ci: remove legacy docs.yml superseded by docs.yaml
shouze Mar 8, 2026
885f135
fix(docs): fix double base in ComparisonTable docLinks
shouze Mar 8, 2026
5a7f0fa
perf(lhci): set perf budhet to 97 for homepage
shouze Mar 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/actions/start-preview-server/action.yml
Original file line number Diff line number Diff line change
@@ -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."
2 changes: 2 additions & 0 deletions .github/instructions/bug-fixing.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 15 additions & 2 deletions .github/instructions/documentation.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
145 changes: 145 additions & 0 deletions .github/instructions/github-actions.instructions.md
Original file line number Diff line number Diff line change
@@ -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/<owner>/<repo>.git refs/tags/<tag> refs/tags/<tag>^{}
# 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/<name>/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@<sha> # 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@<sha> # 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@<sha> # v2.9.4
with:
header: <unique-identifier>
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: <workflow-name>-${{ 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/<name>/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 <script>`
2 changes: 2 additions & 0 deletions .github/instructions/implement-feature.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ excludeAgent: "code-review"

# Implement feature — instructions for Copilot coding agent

> **Skill reference:** for the full architectural layer map, type-first design patterns, CLI option conventions, render sub-module extension playbook and test strategies read `.github/skills/feature.md` first.

Follow these steps when implementing a new feature in this repository.

## 1. Understand the task scope before writing code
Expand Down
2 changes: 2 additions & 0 deletions .github/instructions/refactoring.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ excludeAgent: "code-review"

# Refactoring — instructions for Copilot coding agent

> **Skill reference:** for architectural invariants, safe rename playbook, module extraction patterns, characterisation test strategy and `knip` output interpretation read `.github/skills/refactoring.md` first.

Follow these steps when refactoring existing code in this repository.

## 1. Define the goal and scope
Expand Down
2 changes: 2 additions & 0 deletions .github/instructions/release.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ excludeAgent: "code-review"

# Release — instructions for Copilot coding agent

> **Skill reference:** for the semver decision guide, CD pipeline mechanics, binary targets, blog post format reference and versioned docs snapshot details read `.github/skills/release.md` first.

Follow these steps when cutting a new release of `github-code-search`.

## 1. Determine the version bump
Expand Down
125 changes: 125 additions & 0 deletions .github/skills/bug-fixing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Bug fixing skill — github-code-search

Deep reference for diagnosing and fixing bugs in this codebase.
This skill complements `.github/instructions/bug-fixing.instructions.md`.

---

## Symptom → module diagnostic table

| Symptom | Primary suspect | Secondary suspect |
| ----------------------------------------------------------- | ----------------------------------------------- | --------------------------------- |
| Results missing or duplicated | `src/aggregate.ts` | `src/api.ts` (pagination) |
| Wrong repository grouping | `src/group.ts` | `src/aggregate.ts` |
| `--exclude-repositories` / `--exclude-extracts` not working | `src/aggregate.ts` | `github-code-search.ts` (parsing) |
| Markdown output malformed | `src/output.ts` | — |
| JSON output missing fields or wrong shape | `src/output.ts` | `src/types.ts` (interface) |
| Syntax highlighting wrong colour / wrong language | `src/render/highlight.ts` | — |
| Row navigation skips or wraps incorrectly | `src/render/rows.ts` | `src/tui.ts` (key handler) |
| Select-all / select-none inconsistent | `src/render/selection.ts` | `src/tui.ts` |
| Filter count / stats incorrect | `src/render/filter.ts`, `src/render/summary.ts` | — |
| Path filter (`/regex/`) doesn't match expected | `src/render/filter-match.ts` | `src/tui.ts` (filter state) |
| API returns 0 results or stops paginating | `src/api.ts` | `src/api-utils.ts` |
| Rate limit hit / 429 not retried | `src/api-utils.ts` (`fetchWithRetry`) | — |
| TUI shows blank screen or wrong row | `src/tui.ts` | `src/render/rows.ts` |
| Help overlay doesn't appear / has wrong keys | `src/render.ts` (`renderHelpOverlay`) | `src/tui.ts` |
| Upgrade fails or replaces wrong binary | `src/upgrade.ts` | — |
| Completion script wrong content | `src/completions.ts` | — |
| Completion file written to wrong path | `src/completions.ts` (`getCompletionFilePath`) | env vars (`XDG_*`, `ZDOTDIR`) |
| Completion not refreshed after upgrade | `src/upgrade.ts` (`refreshCompletions`) | — |
| `--version` shows wrong info | `build.ts` (SHA injection) | — |
| CLI option ignored or parsed wrong | `github-code-search.ts` | `src/types.ts` (`OutputType`) |

---

## Reproducing a bug

A complete bug report must have:

1. **Exact command** (redact `GITHUB_TOKEN` with `***`):
```
GITHUB_TOKEN=*** github-code-search query "pattern" --org acme
```
2. **Observed output** vs **expected output**.
3. **Version string**: `github-code-search --version` → e.g. `1.8.0 (a1b2c3d · darwin/arm64)`.
4. **Bun version** (when running from source): `bun --version`.

If the report is missing items 1 or 3, read the relevant module(s) to hypothesise the root cause before asking for more info.

---

## Test-first patterns for bugs

### Pure function bug (aggregate, group, output, render/\*)

```typescript
// src/aggregate.test.ts
describe("applyFiltersAndExclusions — bug #N", () => {
it("excludes org-prefixed repo names correctly", () => {
const result = applyFiltersAndExclusions(matches, {
excludeRepositories: ["acme/my-repo"], // the previously broken form
});
expect(result).not.toContainEqual(expect.objectContaining({ repo: "acme/my-repo" }));
});
});
```

The test must **fail** with the current code before the fix. Commit the test, then fix.

### api-utils bug (retry / pagination)

```typescript
// src/api-utils.test.ts
it("retries on 429 with Retry-After header", async () => {
let callCount = 0;
globalThis.fetch = async () => {
callCount++;
if (callCount === 1) {
return new Response(null, {
status: 429,
headers: { "Retry-After": "0" },
});
}
return new Response(JSON.stringify({ ok: true }), { status: 200 });
};
await fetchWithRetry("https://api.github.com/test");
expect(callCount).toBe(2);
});
```

### Side-effectful bug (tui, api) — no unit test possible

Document manual repro steps in the PR description:

```markdown
## Steps to reproduce (before fix)

1. `GITHUB_TOKEN=... github-code-search query "foo" --org acme`
2. Press `↓` past the last result
3. Expected: cursor stays on last row / Expected: wraps to first row
4. Observed: cursor jumps to blank row
```

---

## Minimal fix principles

- **Touch only the root cause.** Do not opportunistically refactor neighbouring code in the same PR — it makes the fix harder to review and risks introducing new bugs.
- **Respect pure/IO layering**: a fix in `aggregate.ts` must not add a `console.log` call.
- **Type changes cascade**: if `src/types.ts` must change, run `bun run knip` to find all affected consumers and update them all in the same PR.
- **Regression comment**: if the root cause is non-obvious, add one line above the fix:
```typescript
// Fix: short names ("repo") and qualified names ("org/repo") must both match — see issue #N
```

---

## Validation after fix

```bash
bun test # the previously failing test now passes; full suite still green
bun run lint # oxlint — zero errors
bun run format:check # oxfmt — no formatting diff
bun run knip # no unused exports or imports
bun run build.ts # binary compiles without errors
```
Loading