Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
82 changes: 82 additions & 0 deletions .github/instructions/bug-fixing.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
applyTo: "**"
excludeAgent: "code-review"
---

# Bug fixing — instructions for Copilot coding agent

Follow these steps when fixing a bug in this repository.

## 1. Reproduce the bug before writing any fix

A bug report should include:

- The exact command that was run (with `GITHUB_TOKEN` redacted).
- The observed vs. expected behaviour.
- The `github-code-search --version` output (contains commit SHA, OS, architecture).

If the report is incomplete, do not guess. Review the relevant module(s) to locate the most likely root cause.

## 2. Locate the root cause

Use the module map in `AGENTS.md` to identify where the bug likely lives:

| Symptom | Look in |
| -------------------------------------- | ---------------------------------- |
| Wrong grouping / filtering of results | `src/aggregate.ts`, `src/group.ts` |
| Incorrect markdown / JSON output | `src/output.ts` |
| Wrong syntax highlighting | `src/render/highlight.ts` |
| Bad row navigation or visibility | `src/render/rows.ts` |
| Incorrect select-all / select-none | `src/render/selection.ts` |
| Wrong stats / summary line | `src/render/summary.ts` |
| Filter stats incorrect | `src/render/filter.ts` |
| API pagination or rate-limit issue | `src/api.ts` |
| TUI keyboard handling / display glitch | `src/tui.ts` |
| Upgrade failure | `src/upgrade.ts` |
| CLI option parsing / defaults | `github-code-search.ts` |

## 3. Write a failing test before fixing

For any bug in a pure-function module (`aggregate.ts`, `group.ts`, `output.ts`, `render/`):

1. Open (or create) the companion `*.test.ts` file.
2. Write a test case that reproduces the exact bug scenario and **fails** with the current code.
3. Commit the failing test first (or keep it as part of the same commit with the fix, clearly noted).

This ensures the fix is verified and the regression cannot reappear undetected.

For bugs in `tui.ts` or `api.ts` (side-effectful code), a test may not be practical — document the manual reproduction steps in the PR instead.

## 4. Apply the minimal fix

- Fix only the root cause. Do not refactor unrelated code in the same PR.
- Respect the layering: pure functions stay pure, I/O stays in `api.ts` / `tui.ts` / entry point.
- If fixing the bug requires a type change in `src/types.ts`, update all usages across the codebase.

## 5. Verify the 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
```

## 6. Regression note

Add a one-line comment above the fix if the root cause is non-obvious:

```typescript
// Fix: <what was wrong and why> — see issue #<N>
```

## 7. Commit & pull request

- Branch name: `fix/<short-description>` (e.g. `fix/exclude-repos-with-org-prefix`).
- Commit message: imperative mood, e.g. `Fix --exclude-repositories ignoring org-prefixed names`.
- PR description:
- Root cause explanation.
- Steps to reproduce (before the fix).
- Steps to verify (after the fix).
- Reference to the issue number.
69 changes: 69 additions & 0 deletions .github/instructions/implement-feature.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
applyTo: "**"
excludeAgent: "code-review"
---

# Implement feature — instructions for Copilot coding agent

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

## 1. Understand the task scope before writing code

- Read the issue description and acceptance criteria carefully.
- Identify which modules will host the new logic (check `src/types.ts`, `AGENTS.md` and existing modules for context).
- If the feature introduces a new shared type, add it to `src/types.ts` before touching anything else.
- If the feature touches the CLI surface, the entry point is `github-code-search.ts` (Commander subcommands).

## 2. Follow the architectural boundaries

| Layer | Location | Rule |
| ------------------- | ------------------------------------------------- | ----------------------------------------------- |
| Shared types | `src/types.ts` | All new interfaces go here |
| Pure business logic | `src/aggregate.ts`, `src/group.ts`, `src/render/` | Pure functions only — no I/O |
| Output formatting | `src/output.ts` | Markdown and JSON renderers |
| Rendering façade | `src/render.ts` | Re-export new sub-module symbols here |
| API calls | `src/api.ts` | Only place allowed to call GitHub REST API |
| TUI interaction | `src/tui.ts` | Only place allowed to read stdin / write to TTY |
| CLI parsing | `github-code-search.ts` | Commander options and subcommands |
| Auto-upgrade | `src/upgrade.ts` | Binary self-replacement logic |

Never mix pure logic with I/O. If a new feature requires both, split it: write a pure function in the appropriate module and call it from `api.ts`, `tui.ts` or `github-code-search.ts`.

## 3. Adding a new render sub-module

If the feature introduces a new rendering concern (e.g. a new display component):

1. Create `src/render/<name>.ts` with pure functions.
2. Export the new symbols from `src/render.ts` (the façade).
3. Import from `src/render.ts` in consumers — never directly from `src/render/<name>.ts`.

## 4. Write tests for every new pure function

- Create or update `src/<module>.test.ts` (co-located with the source file).
- Use `describe` / `it` / `expect` from Bun's built-in test runner.
- Tests must be self-contained: no network calls, no filesystem side effects.
- Cover edge cases: empty arrays, undefined/null guards, boundary values.
- Run `bun test` to verify the full suite passes before considering the implementation done.

## 5. Update the CLI documentation if the public interface changes

- If a new CLI option or subcommand is added, update `README.md` (usage section, options table, examples).
- If a new flag requires additional GitHub token scopes, document them in `README.md` and `AGENTS.md`.

## 6. Validation checklist

Before opening the pull request, ensure every item passes:

```bash
bun test # all tests 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
```

## 7. Commit & pull request

- Branch name: `feat/<short-description>` (e.g. `feat/json-output-type`).
- Commit message: imperative mood, e.g. `Add --output-type flag for JSON format`.
- PR description: motivation, what changed, how to test manually.
78 changes: 78 additions & 0 deletions .github/instructions/refactoring.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
applyTo: "**"
excludeAgent: "code-review"
---

# Refactoring — instructions for Copilot coding agent

Follow these steps when refactoring existing code in this repository.

## 1. Define the goal and scope

A good refactoring task has a clearly bounded scope. Before making any change, identify:

- Which module(s) are affected (consult `AGENTS.md` for the layer map).
- Whether the public API (exported symbols, CLI options) is changing or staying the same.
- Whether the refactoring is purely internal (no behavior change) or also simplifies the API.

**Prefer behaviour-preserving refactorings.** If the public API must change, document it explicitly in the PR.

## 2. Do not break the architectural boundaries

This codebase enforces a strict layering:

- **Pure functions** must stay pure — do not introduce side effects (I/O, global state, `Date.now()`, `Math.random()`) into `aggregate.ts`, `group.ts`, `output.ts`, or `render/` sub-modules.
- **I/O is isolated** in `api.ts`, `tui.ts` and `github-code-search.ts`. Keep it there.
- **`render.ts` is a façade** — if you move or rename symbols in `render/`, update the re-exports in `render.ts` accordingly.
- **`types.ts` is the single source of truth** — if you merge or rename interfaces, update all usages across the codebase.

## 3. Verify test coverage first

Before touching code:

```bash
bun test # baseline — all tests must be green before you start
```

If the area you are refactoring lacks tests, **add tests before refactoring** (characterisation tests). This ensures you can verify the refactoring is behaviour-preserving.

## 4. Make changes incrementally

- Refactor one logical unit at a time (one function, one module boundary).
- Run `bun test` after each meaningful step to catch regressions early.
- Avoid mixing a refactoring with a feature addition in the same commit; separate concerns.

## 5. Update all usages when renaming

If you rename an exported function, type or constant:

- Update every import site across the codebase — use a global search before renaming.
- Update `render.ts` if the renamed symbol is re-exported there.
- Update `src/types.ts` if it's a shared type.
- Run `bun run knip` to detect any forgotten reference.

## 6. Keep `knip` clean

Every exported symbol must be used. After a refactoring:

```bash
bun run knip # zero unused exports / imports
```

Remove dead code rather than leaving it commented out.

## 7. Validation checklist

```bash
bun test # full suite passes — same behaviour before and after
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
```

## 8. Commit & pull request

- Branch name: `refactor/<short-description>` (e.g. `refactor/extract-filter-module`).
- Commit message: imperative mood, e.g. `Extract FilterStats helpers into render/filter.ts`.
- PR description: what was restructured, why, and a note confirming no behaviour change.
117 changes: 117 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# github-code-search — Agent instructions

This file provides context for AI coding agents (GitHub Copilot, Claude, Gemini, etc.) working in this repository.

## What this project does

`github-code-search` is an interactive CLI (powered by [Bun](https://bun.sh)) to search GitHub code across an organisation. It aggregates results per repository, displays a keyboard-driven TUI and lets the user select extracts before printing structured markdown or JSON output. A `query` subcommand and an `upgrade` subcommand are exposed via [Commander](https://github.com/tj/commander.js).

## Runtime & toolchain

| Tool | Version |
| -------------- | -------------------------------------------------------- |
| **Bun** | ≥ 1.0 (runtime, bundler, test runner, package manager) |
| **TypeScript** | via Bun (no separate `tsc` invocation needed at runtime) |
| **oxlint** | linter (`bun run lint`) |
| **oxfmt** | formatter (`bun run format`) |
| **knip** | dead-code detector (`bun run knip`) |

There is **no Node.js / npm** involved. Always use `bun` commands.

## Bootstrap

```bash
bun install # install dependencies (reads bunfig.toml + package.json)
```

`bunfig.toml` sets `smol = true` (lighter install). No additional setup step is needed.
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The statement that "bunfig.toml sets smol = true (lighter install)" is inaccurate. The current bunfig.toml file only contains test-related configuration and does not include a smol setting.

Suggested change
`bunfig.toml` sets `smol = true` (lighter install). No additional setup step is needed.
`bunfig.toml` currently only contains test-related configuration (e.g. test setup file). No additional setup step is needed.

Copilot uses AI. Check for mistakes.

## Build commands

```bash
bun run build.ts # compile a self-contained binary → dist/github-code-search
bun run build.ts --target=bun-darwin-arm64 # cross-compile (see CONTRIBUTING.md for all targets)
```

The build script (`build.ts`) injects the git commit SHA, target OS and architecture into the binary. The produced binary has no runtime dependency and can be distributed as a single file.

## Running tests

```bash
bun test # run the whole test suite
bun test --watch # re-run on file changes (development)
```

All tests use Bun's built-in test runner (`@jest/globals`-compatible API: `describe`, `it`, `expect`). No additional testing library is needed. The setup file is `src/test-setup.ts` (referenced in `bunfig.toml`).
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description of the test API is misleading. Tests import from "bun:test", not from "@jest/globals". While Bun's test API is jest-compatible, the actual import source should be accurately documented as "bun:test" to help developers understand the toolchain.

Suggested change
All tests use Bun's built-in test runner (`@jest/globals`-compatible API: `describe`, `it`, `expect`). No additional testing library is needed. The setup file is `src/test-setup.ts` (referenced in `bunfig.toml`).
All tests use Bun's built-in test runner, importing from `bun:test` (API compatible with `@jest/globals`: `describe`, `it`, `expect`). No additional testing library is needed. The setup file is `src/test-setup.ts` (referenced in `bunfig.toml`).

Copilot uses AI. Check for mistakes.

## Linting & formatting

```bash
bun run lint # oxlint — must pass before submitting
bun run format # oxfmt write (auto-fix)
bun run format:check # oxfmt check (CI check)
bun run knip # detect unused exports / files
```

Always run `bun run lint` and `bun run format:check` before considering a change complete.

## Project layout

```
github-code-search.ts # CLI entry point — Commander subcommands: query, upgrade
build.ts # Build script (Bun.build)
bunfig.toml # Bun configuration (smol install, test preload)
tsconfig.json # TypeScript configuration
knip.json # knip (dead-code) configuration

src/
types.ts # All shared TypeScript interfaces (TextMatchSegment,
# TextMatch, CodeMatch, RepoGroup, Row, TeamSection,
# OutputFormat, OutputType)
api.ts # GitHub REST API client (search, team fetching)
aggregate.ts # Result grouping & filtering (applyFiltersAndExclusions)
group.ts # groupByTeamPrefix — team-prefix grouping logic
render.ts # Façade re-exporting sub-modules + top-level
# renderGroups() / renderHelpOverlay()
tui.ts # Interactive keyboard-driven UI (navigation, filter mode,
# help overlay, selection)
output.ts # Text (markdown) and JSON output formatters
upgrade.ts # Auto-upgrade logic (fetch latest GitHub release, replace binary)

render/
highlight.ts # Syntax highlighting (language detection + token rules)
filter.ts # FilterStats + buildFilterStats
rows.ts # buildRows, rowTerminalLines, isCursorVisible
summary.ts # buildSummary, buildSummaryFull, buildSelectionSummary
selection.ts # applySelectAll, applySelectNone

*.test.ts # Unit tests co-located with source files
test-setup.ts # Global test setup (Bun preload)
```

## Key architectural principles

- **Pure functions first.** All business logic lives in pure, side-effect-free functions (`aggregate.ts`, `group.ts`, `output.ts`, `render/` sub-modules). This makes them straightforward to unit-test.
- **Side effects are isolated.** API calls (`api.ts`), TTY interaction (`tui.ts`) and CLI parsing (`github-code-search.ts`) are the only side-effectful surfaces.
- **`render.ts` is a façade.** It re-exports everything from `render/` and adds two top-level rendering functions. Consumers import from `render.ts`, not directly from sub-modules.
- **`types.ts` is the single source of truth** for all shared interfaces. Any new shared type must go there.
- **No classes** — the codebase uses plain TypeScript interfaces and functions throughout.

## Writing tests

- Test files are named `<module>.test.ts` and sit next to their source file.
- Use `describe` / `it` / `expect` from Bun's test runner.
- Only pure functions need tests; `tui.ts` and `api.ts` are not unit-tested.
- When adding a function to an existing module, add the corresponding test case in the existing `<module>.test.ts`.
- When creating a new module that contains pure functions, create a companion `<module>.test.ts`.
- Tests must be self-contained: no network calls, no filesystem side effects.

## Development notes

- **TypeScript throughout** — no `.js` files in `src/`.
- Bun executes `.ts` files directly; no transpilation step is needed to run the CLI locally (`bun github-code-search.ts query ...`).
- The `--exclude-repositories` and `--exclude-extracts` options accept both short (`repoName`) and long (`org/repoName`) forms — this normalisation happens in `aggregate.ts`.
- The `--group-by-team-prefix` option requires a `read:org` GitHub token scope; this is documented in `README.md`.
- The `upgrade` subcommand replaces the running binary in-place using `src/upgrade.ts`; be careful with filesystem operations there.
- `picocolors` is the only styling dependency; do not add `chalk` or similar.
- Keep `knip` clean: every exported symbol must be used; every import must resolve.