diff --git a/.github/instructions/bug-fixing.instructions.md b/.github/instructions/bug-fixing.instructions.md new file mode 100644 index 0000000..7510a09 --- /dev/null +++ b/.github/instructions/bug-fixing.instructions.md @@ -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: — see issue # +``` + +## 7. Commit & pull request + +- Branch name: `fix/` (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. diff --git a/.github/instructions/implement-feature.instructions.md b/.github/instructions/implement-feature.instructions.md new file mode 100644 index 0000000..b1817b9 --- /dev/null +++ b/.github/instructions/implement-feature.instructions.md @@ -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/.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/.ts`. + +## 4. Write tests for every new pure function + +- Create or update `src/.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/` (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. diff --git a/.github/instructions/refactoring.instructions.md b/.github/instructions/refactoring.instructions.md new file mode 100644 index 0000000..737b49c --- /dev/null +++ b/.github/instructions/refactoring.instructions.md @@ -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/` (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. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f45d3b1 --- /dev/null +++ b/AGENTS.md @@ -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. + +## 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`). + +## 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 `.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 `.test.ts`. +- When creating a new module that contains pure functions, create a companion `.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.