15 |
16 |
52 |
--------------------------------------------------------------------------------
/docs/src/content/config.ts:
--------------------------------------------------------------------------------
1 | import { defineCollection } from 'astro:content';
2 | import { docsSchema } from '@astrojs/starlight/schema';
3 |
4 | export const collections = {
5 | docs: defineCollection({ schema: docsSchema() }),
6 | };
7 |
--------------------------------------------------------------------------------
/docs/src/content/docs/README.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Documentation
3 | description: Documentation for kit.
4 | ---
5 |
6 | This uses [Starlight](https://starlight.astro.build) to build the documentation.
7 |
8 | ## 🧞 Commands
9 |
10 | All commands are run from the root of the project, from a terminal:
11 |
12 | | Command | Action |
13 | | :------------------------ | :----------------------------------------------- |
14 | | `pnpm install` | Installs dependencies |
15 | | `pnpm dev` | Starts local dev server at `localhost:4321` |
16 | | `pnpm build` | Build your production site to `./dist/` |
17 | | `pnpm preview` | Preview your build locally, before deploying |
18 | | `pnpm astro ...` | Run CLI commands like `astro add`, `astro check` |
19 | | `pnpm astro -- --help` | Get help using the Astro CLI |
20 |
21 | ## 👀 Want to learn more?
22 |
23 | Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
24 |
--------------------------------------------------------------------------------
/docs/src/content/docs/api/code_searcher.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: CodeSearcher API
3 | ---
4 |
5 | import { Aside } from '@astrojs/starlight/components';
6 |
7 | This page details the API for the `CodeSearcher` class, used for performing text and regular expression searches across your repository.
8 |
9 | ## Initialization
10 |
11 | To use the `CodeSearcher`, you first need to initialize it with the path to your repository:
12 |
13 | ```python
14 | from kit.code_searcher import CodeSearcher
15 |
16 | searcher = CodeSearcher(repo_path="/path/to/your/repo")
17 | # Or, if you have a kit.Repository object:
18 | searcher = repo.get_code_searcher()
19 | ```
20 |
21 |
24 |
25 | ## `SearchOptions` Dataclass
26 |
27 | The `search_text` method uses a `SearchOptions` dataclass to control search behavior. You can import it from `kit.code_searcher`.
28 |
29 | ```python
30 | from kit.code_searcher import SearchOptions
31 | ```
32 |
33 | **Fields:**
34 |
35 | * `case_sensitive` (bool):
36 | * If `True` (default), the search query is case-sensitive.
37 | * If `False`, the search is case-insensitive.
38 | * `context_lines_before` (int):
39 | * The number of lines to include before each matching line. Defaults to `0`.
40 | * `context_lines_after` (int):
41 | * The number of lines to include after each matching line. Defaults to `0`.
42 | * `use_gitignore` (bool):
43 | * If `True` (default), files and directories listed in the repository's `.gitignore` file will be excluded from the search.
44 | * If `False`, `.gitignore` rules are ignored.
45 |
46 | ## Methods
47 |
48 | ### `search_text(query: str, file_pattern: str = "*.py", options: Optional[SearchOptions] = None) -> List[Dict[str, Any]]`
49 |
50 | Searches for a text pattern (which can be a regular expression) in files matching the `file_pattern`.
51 |
52 | * **Parameters:**
53 | * `query` (str): The text pattern or regular expression to search for.
54 | * `file_pattern` (str): A glob pattern specifying which files to search in. Defaults to `"*.py"` (all Python files).
55 | * `options` (Optional[SearchOptions]): An instance of `SearchOptions` to customize search behavior. If `None`, default options are used.
56 | * **Returns:**
57 | * `List[Dict[str, Any]]`: A list of dictionaries, where each dictionary represents a match and contains:
58 | * `"file"` (str): The relative path to the file from the repository root.
59 | * `"line_number"` (int): The 1-indexed line number where the match occurred.
60 | * `"line"` (str): The content of the matching line (with trailing newline stripped).
61 | * `"context_before"` (List[str]): A list of strings, each being a line of context before the match.
62 | * `"context_after"` (List[str]): A list of strings, each being a line of context after the match.
63 | * **Raises:**
64 | * The method includes basic error handling for file operations and will print an error message to the console if a specific file cannot be processed, then continue with other files.
65 |
66 | **Example Usage:**
67 |
68 | ```python
69 | from kit.code_searcher import CodeSearcher, SearchOptions
70 |
71 | # Assuming 'searcher' is an initialized CodeSearcher instance
72 |
73 | # Basic search for 'my_function' in Python files
74 | results_basic = searcher.search_text("my_function")
75 |
76 | # Case-insensitive search with 2 lines of context before and after
77 | custom_options = SearchOptions(
78 | case_sensitive=False,
79 | context_lines_before=2,
80 | context_lines_after=2
81 | )
82 | results_with_options = searcher.search_text(
83 | query=r"my_variable\s*=\s*\d+", # Example regex query
84 | file_pattern="*.txt",
85 | options=custom_options
86 | )
87 |
88 | for match in results_with_options:
89 | print(f"Found in {match['file']} at line {match['line_number']}:")
90 | for before_line in match['context_before']:
91 | print(f" {before_line}")
92 | print(f"> {match['line']}")
93 | for after_line in match['context_after']:
94 | print(f" {after_line}")
95 | print("---")
96 |
--------------------------------------------------------------------------------
/docs/src/content/docs/api/summarizer.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Summarizer API
3 | ---
4 |
5 | import { Aside } from '@astrojs/starlight/components';
6 |
7 | This page details the API for the `Summarizer` class, used for interacting with LLMs for code summarization tasks.
8 |
9 | ## Initialization
10 |
11 | Details on how to initialize the `Summarizer` (likely via `repo.get_summarizer()`).
12 |
13 |
16 |
17 | ## Methods
18 |
19 | ### `summarize_file(file_path: str) -> str`
20 |
21 | Summarizes the content of the specified file.
22 |
23 | * **Parameters:**
24 | * `file_path` (str): The path to the file within the repository.
25 | * **Returns:**
26 | * `str`: The summary generated by the LLM.
27 | * **Raises:**
28 | * `FileNotFoundError`: If the `file_path` does not exist in the repo.
29 | * `LLMError`: If there's an issue communicating with the LLM.
30 |
31 |
32 | ### `summarize_function(file_path: str, function_name: str) -> str`
33 |
34 | Summarizes a specific function within the specified file.
35 |
36 | * **Parameters:**
37 | * `file_path` (str): The path to the file containing the function.
38 | * `function_name` (str): The name of the function to summarize.
39 | * **Returns:**
40 | * `str`: The summary generated by the LLM.
41 | * **Raises:**
42 | * `FileNotFoundError`: If the `file_path` does not exist in the repo.
43 | * `SymbolNotFoundError`: If the function cannot be found in the file.
44 | * `LLMError`: If there's an issue communicating with the LLM.
45 |
46 | ### `summarize_class(file_path: str, class_name: str) -> str`
47 |
48 | Summarizes a specific class within the specified file.
49 |
50 | * **Parameters:**
51 | * `file_path` (str): The path to the file containing the class.
52 | * `class_name` (str): The name of the class to summarize.
53 | * **Returns:**
54 | * `str`: The summary generated by the LLM.
55 | * **Raises:**
56 | * `FileNotFoundError`: If the `file_path` does not exist in the repo.
57 | * `SymbolNotFoundError`: If the class cannot be found in the file.
58 | * `LLMError`: If there's an issue communicating with the LLM.
59 |
60 | ## Configuration
61 |
62 | Details on the configuration options (`OpenAIConfig`, etc.).
63 | This is typically handled when calling `repo.get_summarizer(config=...)` or via environment variables read by the default `OpenAIConfig`.
64 |
65 | The `Summarizer` currently uses `OpenAIConfig` for its LLM settings. When a `Summarizer` is initialized without a specific config object, it creates a default `OpenAIConfig` with the following parameters:
66 |
67 | * `api_key` (str, optional): Your OpenAI API key. Defaults to the `OPENAI_API_KEY` environment variable. If not found, an error will be raised.
68 | * `model` (str): The OpenAI model to use. Defaults to `"gpt-4o"`.
69 | * `temperature` (float): Sampling temperature for the LLM. Defaults to `0.7`.
70 | * `max_tokens` (int): The maximum number of tokens to generate in the summary. Defaults to `1000`.
71 |
72 | You can customize this by creating an `OpenAIConfig` instance and passing it to `repo.get_summarizer()`:
73 |
74 | ```python
75 | from kit.summaries import OpenAIConfig
76 |
77 | # Example: Customize model and temperature
78 | my_config = OpenAIConfig(model="o3-mini", temperature=0.2)
79 | summarizer = repo.get_summarizer(config=my_config)
80 |
81 | # Now summarizer will use o3-mini with temperature 0.2
82 | summary = summarizer.summarize_file("path/to/your/file.py")
83 | ```
84 |
--------------------------------------------------------------------------------
/docs/src/content/docs/api/summary-searcher.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: SummarySearcher API
3 | description: API documentation for the SummarySearcher class.
4 | ---
5 |
6 | The `SummarySearcher` class provides a simple way to query an index built by [`DocstringIndexer`](/api/docstring-indexer). It takes a search query, embeds it using the same embedding function used for indexing, and retrieves the most semantically similar summaries from the vector database.
7 |
8 | ## Constructor
9 |
10 | **Class: `SummarySearcher`**
11 | *(defined in `kit/docstring_indexer.py`)*
12 |
13 | The `SummarySearcher` is typically initialized with an instance of `DocstringIndexer`. It uses the `DocstringIndexer`'s configured backend and embedding function to perform searches.
14 |
15 | ```python
16 | from kit.docstring_indexer import DocstringIndexer, SummarySearcher
17 |
18 | # Assuming 'indexer' is an already initialized DocstringIndexer instance
19 | # indexer = DocstringIndexer(repo=my_repo, summarizer=my_summarizer)
20 | # indexer.build() # Ensure the index is built
21 |
22 | searcher = SummarySearcher(indexer=indexer)
23 | ```
24 |
25 | **Parameters:**
26 |
27 | * **`indexer`** (`DocstringIndexer`, required):
28 | An instance of `DocstringIndexer` that has been configured and preferably has had its `build()` method called. The `SummarySearcher` will use this indexer's `backend` and `embed_fn`. See the [`DocstringIndexer API docs`](./docstring-indexer) for more details on the indexer.
29 |
30 | ## Methods
31 |
32 | ### `search`
33 |
34 | **Method: `SummarySearcher.search`**
35 | *(defined in `kit/docstring_indexer.py`)*
36 |
37 | Embeds the given `query` string and searches the vector database (via the indexer's backend) for the `top_k` most similar document summaries.
38 |
39 | ```python
40 | query_text = "How is user authentication handled?"
41 | results = searcher.search(query=query_text, top_k=3)
42 |
43 | for result in results:
44 | print(f"Found in: {result.get('file_path')} ({result.get('symbol_name')})")
45 | print(f"Score: {result.get('score')}")
46 | print(f"Summary: {result.get('summary')}")
47 | print("----")}
48 | ```
49 |
50 | **Parameters:**
51 |
52 | * **`query`** (`str`, required):
53 | The natural language query string to search for.
54 | * **`top_k`** (`int`, default: `5`):
55 | The maximum number of search results to return.
56 |
57 | **Returns:** `List[Dict[str, Any]]`
58 |
59 | A list of dictionaries, where each dictionary represents a search hit.
60 | Each hit typically includes metadata, a score, an ID, and the summary text.
61 |
--------------------------------------------------------------------------------
/docs/src/content/docs/changelog.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Changelog"
3 | description: "Track changes and improvements in Kit releases"
4 | ---
5 |
6 | # Changelog
7 |
8 | All notable changes to Kit will be documented in this file.
9 |
10 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
11 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
12 |
13 | ## [0.6.3]
14 |
15 | ### 🐛 Bug Fixes
16 |
17 | - **Symbol Type Extraction Fix**: Fixed bug where some symbol types were incorrectly processed
18 | - Classes and other symbol types no longer have characters incorrectly stripped
19 | - Added comprehensive test coverage for symbol type processing edge cases
20 |
21 | ---
22 |
23 | ## [0.6.2]
24 |
25 | ### 🎉 Major Features
26 |
27 | - **Ollama Support**: Complete local LLM inference support with Ollama
28 | - Zero-cost PR reviews with local models
29 | - Support for popular models like DeepSeek R1, Qwen2.5-coder, CodeLlama
30 | - Automatic provider detection from model names (e.g., `deepseek-r1:latest`)
31 | - First-class integration with kit's repository intelligence
32 |
33 | - **DeepSeek R1 Reasoning Model Support**
34 | - **Thinking Token Stripping**: Automatically removes `...` tags from reasoning models
35 | - Clean, professional output without internal reasoning clutter
36 | - Preserves the analytical capabilities while improving output quality
37 | - Works in both summarization and PR review workflows
38 |
39 | - **Plain Output Mode**: New `--plain` / `-p` flag for pipe-friendly output
40 | - Removes all formatting and status messages
41 | - Perfect for piping to Claude Code or other AI tools
42 | - Enables powerful multi-stage AI workflows (e.g., `kit review -p | claude`)
43 | - Quiet mode suppresses all progress/status output
44 |
45 | ### ✨ Enhanced Features
46 |
47 | - **CLI Improvements**
48 | - Added `--version` flag to display current kit version
49 | - Model override support: `--model` / `-m` flag for per-review model selection
50 | - Better error messages and help text
51 |
52 | - **Documentation**
53 | - Comprehensive Ollama integration guides
54 | - Claude Code workflow examples
55 | - Multi-stage AI analysis patterns
56 | - Updated CLI reference with new flags
57 |
58 | ### 🔧 Developer Experience
59 |
60 | - **Community**
61 | - Added Discord community server for support and discussions
62 | - Improved README with better getting started instructions
63 |
64 | - **Testing**
65 | - Comprehensive test suite for thinking token stripping
66 | - Ollama integration tests with mock scenarios
67 | - PR reviewer test coverage for new features
68 |
69 | ### 💰 Cost Optimization
70 |
71 | - **Free Local Analysis**: Use Ollama for zero-cost code analysis
72 | - **Hybrid Workflows**: Combine free local analysis with premium cloud implementation
73 | - **Provider Switching**: Automatic provider detection and switching
74 |
75 | ---
76 |
77 | ## [0.6.1]
78 |
79 | ### 🔧 Improvements
80 |
81 | - Enhanced line number accuracy in PR reviews
82 | - Improved debug output for troubleshooting
83 | - Better test coverage for core functionality
84 | - Performance optimizations for large repositories
85 |
86 | ### 🐛 Bug Fixes
87 |
88 | - Fixed edge cases in symbol extraction
89 | - Improved error handling for malformed diffs
90 | - Better validation for GitHub URLs
91 |
92 | ---
93 |
94 | ## [0.6.0]
95 |
96 | ### 🎉 Major Features
97 |
98 | - Advanced PR reviews
99 | - Enhanced line number context and accuracy fore reviews
100 | - Comprehensive cost tracking and pricing updates for reviews
101 | - Improved repository intelligence with better symbol analysis
102 |
103 | ### ✨ Enhanced Features
104 |
105 | - Better diff parsing and analysis
106 | - Enhanced file prioritization algorithms for reviews
107 | - Improved cost breakdown reporting
108 |
109 | ---
110 |
111 | ## Links
112 |
113 | - [GitHub Releases](https://github.com/cased/kit/releases)
114 | - [Issues](https://github.com/cased/kit/issues)
--------------------------------------------------------------------------------
/docs/src/content/docs/core-concepts/context-assembly.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Assembling Context
3 | ---
4 |
5 | When you send code to an LLM you usually **don’t** want the entire repository –
6 | just the *most relevant* bits. `ContextAssembler` helps you stitch those bits
7 | together into a single prompt-sized string.
8 |
9 | ## Why you need it
10 |
11 | * **Token limits** – GPT-4o tops out at ~128k tokens; some models less.
12 | * **Signal-to-noise** – Cut boilerplate, focus the model on what matters.
13 | * **Automatic truncation** – Keeps prompts within your chosen character budget.
14 |
15 | ## Quick start
16 |
17 | ```python
18 | from kit import Repository, ContextAssembler
19 |
20 | repo = Repository("/path/to/project")
21 |
22 | # Assume you already have chunks, e.g. from repo.search_semantic()
23 | chunks = repo.search_text("jwt decode")
24 |
25 | assembler = ContextAssembler(max_chars=12_000)
26 | context = assembler.from_chunks(chunks)
27 |
28 | print(context) # → Ready to drop into your chat prompt
29 | ```
30 |
31 | `chunks` can be any list of dicts that include a `code` key – the helper trims
32 | and orders them by length until the budget is filled.
33 |
34 | ### Fine-tuning
35 |
36 | | Parameter | Default | Description |
37 | |-----------|---------|-------------|
38 | | `max_chars` | `12000` | Rough character cap for the final string. |
39 | | `separator` | `"\n\n---\n\n"` | Separator inserted between chunks. |
40 | | `header` / `footer` | `""` | Optional strings prepended/appended. |
41 |
42 | ```python
43 | assembler = ContextAssembler(
44 | max_chars=8000,
45 | header="### Code context\n",
46 | footer="\n### End context",
47 | )
48 | ```
49 |
50 | ## Combining with other tools
51 |
52 | 1. **Vector search → assemble → chat**
53 | ```python
54 | chunks = repo.search_semantic("retry backoff", embed_fn, top_k=10)
55 | prompt = assembler.from_chunks(chunks)
56 | response = my_llm.chat(prompt + "\n\nQ: …")
57 | ```
58 | 2. **Docstring search first** – Use `SummarySearcher` for high-level matches,
59 | then pull full code for those files via `repo.context`.
60 | 3. **Diff review bots** – Feed only the changed lines + surrounding context.
61 |
62 | ## API reference
63 |
64 | ```python
65 | from kit.llm_context import ContextAssembler
66 | ```
67 |
68 | ### `__init__(repo, *, title=None)`
69 |
70 | Constructs a new `ContextAssembler`.
71 |
72 | * `repo`: A `kit.repository.Repository` instance.
73 | * `title` (optional): A string to prepend to the assembled context.
74 |
75 | ### `from_chunks(chunks, max_chars=12000, separator="...", header="", footer="")`
76 |
77 | This is the primary method for assembling context from a list of code chunks.
78 |
79 | * `chunks`: A list of dictionaries, each with a `"code"` key.
80 | * `max_chars`: Target maximum character length for the output string.
81 | * `separator`: String to insert between chunks.
82 | * `header` / `footer`: Optional strings to wrap the entire context.
83 |
84 | Returns a single string with concatenated, truncated chunks.
85 |
86 | ### Other methods
87 |
88 | While `from_chunks` is the most common entry point, `ContextAssembler` also offers methods to add specific types of context if you're building a prompt manually:
89 |
90 | * `add_diff(diff_text)`: Adds a Git diff.
91 | * `add_file(file_path, highlight_changes=False)`: Adds the full content of a file.
92 | * `add_symbol_dependencies(file_path, max_depth=1)`: Adds content of files that `file_path` depends on.
93 | * `add_search_results(results, query)`: Formats and adds semantic search results.
94 | * `format_context()`: Returns the accumulated context as a string.
95 |
--------------------------------------------------------------------------------
/docs/src/content/docs/core-concepts/repository-api.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: The Repository Interface
3 | ---
4 |
5 | import { Aside } from "@astrojs/starlight/components";
6 |
7 | The `kit.Repository` object is the backbone of the library. It serves as your primary interface for accessing, analyzing, and understanding codebases, regardless of their language or location (local path or remote Git URL).
8 |
9 | ## Why the `Repository` Object?
10 |
11 | Interacting directly with code across different languages, file structures, and potential locations (local vs. remote) can be cumbersome. The `Repository` object provides a **unified and consistent abstraction layer** to handle this complexity.
12 |
13 | Key benefits include:
14 |
15 | - **Unified Access:** Provides a single entry point to read files, extract code structures (symbols), perform searches, and more.
16 | - **Location Agnostic:** Works seamlessly with both local file paths and remote Git repository URLs (handling cloning and caching automatically when needed).
17 | - **Language Abstraction:** Leverages `tree-sitter` parsers under the hood to understand the syntax of various programming languages, allowing you to work with symbols (functions, classes, etc.) in a standardized way.
18 | - **Foundation for Tools:** Acts as the foundation upon which you can build higher-level developer tools and workflows, such as documentation generators, AI code reviewers, or semantic search engines.
19 |
20 | ## What Can You Do with a `Repository`?
21 |
22 | Once you instantiate a `Repository` object pointing to your target codebase:
23 |
24 | ```python
25 | from kit import Repository
26 |
27 | # Point to a local project
28 | my_repo = Repository("/path/to/local/project")
29 |
30 | # Or point to a remote GitHub repo
31 | # github_repo = Repository("https://github.com/owner/repo-name")
32 |
33 | # Or analyze a specific version
34 | # versioned_repo = Repository("https://github.com/owner/repo-name", ref="v1.2.3")
35 | ```
36 |
37 | You can perform various code intelligence tasks:
38 |
39 | - **Explore Structure:** Get the file tree (`.get_file_tree()`).
40 | - **Read Content:** Access the raw content of specific files (`.get_file_content()`).
41 | - **Understand Code:** Extract detailed information about functions, classes, and other symbols (`.extract_symbols()`).
42 | - **Access Git Metadata:** Get current commit SHA, branch, and remote URL (`.current_sha`, `.current_branch`, `.remote_url`).
43 | - **Search & Navigate:** Find text patterns (`.search_text()`) or semantically similar code (`.search_semantic()`).
44 | - **Analyze Dependencies:** Find where symbols are defined and used (`.find_symbol_usages()`).
45 | - **Prepare for LLMs:** Chunk code intelligently by lines or symbols (`.chunk_file_by_lines()`, `.chunk_file_by_symbols()`) and get code context around specific lines (`.extract_context_around_line()`).
46 | - **Integrate with AI:** Obtain configured summarizers (`.get_summarizer()`) or vector searchers (`.get_vector_searcher()`) for advanced AI workflows.
47 | - **Export Data:** Save the file tree, symbol information, or full repository index to structured formats like JSON (`.write_index()`, `.write_symbols()`, etc.).
48 |
49 | The following table lists some of the key classes and tools you can access through the `Repository` object:
50 |
51 | | Class/Tool | Description |
52 | | ------------------ | ---------------------------------------------- |
53 | | `Summarizer` | Generate summaries of code using LLMs |
54 | | `VectorSearcher` | Query vector index of code for semantic search |
55 | | `DocstringIndexer` | Build vector index of LLM-generated summaries |
56 | | `SummarySearcher` | Query that index |
57 |
58 |
59 |
63 |
64 |
65 |
73 |
--------------------------------------------------------------------------------
/docs/src/content/docs/core-concepts/search-approaches.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Searching
3 | ---
4 |
5 | Not sure **which `kit` feature to reach for**? Use this page as a mental map of
6 | search-and-discovery tools – from plain-text grep all the way to LLM-powered
7 | semantic retrieval.
8 |
9 | ## Decision table
10 |
11 | | Your goal | Best tool | One-liner | Docs |
12 | |-----------|-----------|-----------|------|
13 | | Find an exact string or regex | `repo.search_text()` | `repo.search_text("JWT", "*.go")` | [Text search](/docs/core-concepts/semantic-search#exact-keyword) |
14 | | List symbols in a file | `repo.extract_symbols()` | `repo.extract_symbols("src/db.py")` | [Repository API](/docs/core-concepts/repository-api) |
15 | | See where a function is used | `repo.find_symbol_usages()` | `repo.find_symbol_usages("login")` | ^ |
16 | | Get a concise overview of a file / function | `Summarizer` | `summarizer.summarize_file(path)` | [Code summarization](/docs/core-concepts/code-summarization) |
17 | | Semantic search over **raw code chunks** | `VectorSearcher` | `repo.search_semantic()` | [Semantic search](/docs/core-concepts/semantic-search) |
18 | | Semantic search over **LLM summaries** | `DocstringIndexer` + `SummarySearcher` | see below | [Docstring index](/docs/core-concepts/docstring-indexing) |
19 | | Build an LLM prompt with only the *relevant* code | `ContextAssembler` | `assembler.from_chunks(chunks)` | [Context assembly](/docs/core-concepts/context-assembly) |
20 |
21 | > **Tip:** You can mix-and-match. For instance, run a docstring search first,
22 | > then feed the matching files into `ContextAssembler` for an LLM chat.
23 |
24 | ## Approaches in detail
25 |
26 | ### 1. Plain-text / regex search
27 |
28 | Fast, zero-setup, works everywhere. Use when you *know* what string you’re
29 | looking for.
30 |
31 | ```python
32 | repo.search_text("parse_jwt", file_pattern="*.py")
33 | ```
34 |
35 | ### 2. Symbol indexing
36 |
37 | `extract_symbols()` uses **tree-sitter** queries (Python, JS, Go, etc.) to list
38 | functions, classes, variables – handy for nav trees or refactoring tools.
39 |
40 | ### 3. LLM summarization
41 |
42 | Generate natural-language summaries for files, classes, or functions with
43 | `Summarizer`. Great for onboarding or API docs.
44 |
45 | ### 4. Vector search (raw code)
46 |
47 | `VectorSearcher` chunks code (symbols or lines) → embeds chunks → stores them in
48 | a local vector database. Good when wording of the query is *similar* to the
49 | code.
50 |
51 | ### 5. Docstring vector search
52 |
53 | `DocstringIndexer` first *summarizes* code, then embeds the summary. The
54 | resulting vectors capture **intent**, not syntax; queries like “retry back-off
55 | logic” match even if the code uses exponential delays without those words.
56 |
57 | ---
58 |
59 | Still unsure? Start with text-search (cheap), move to vector search (smart),
60 | and layer summaries when you need *meaning* over *matching*.
61 |
--------------------------------------------------------------------------------
/docs/src/content/docs/development/running-tests.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Running Tests
3 | ---
4 |
5 | To run tests using uv and pytest, first ensure you have the development dependencies installed:
6 |
7 | ```sh
8 | # Install all deps
9 | uv pip install -e .
10 | ```
11 |
12 | Then, run the full test suite using:
13 |
14 | ```sh
15 | uv run pytest
16 | ```
17 |
18 | Or to run a specific test file:
19 |
20 | ```sh
21 | uv run pytest tests/test_hcl_symbols.py
22 | ```
23 |
24 | ## Code Style and Formatting
25 |
26 | Kit uses [Ruff](https://docs.astral.sh/ruff/) for linting, formatting, and import sorting with a line length of 120 characters. Our configuration can be found in `pyproject.toml`.
27 |
28 | To check your code against our style guidelines:
29 |
30 | ```sh
31 | # Run linting checks
32 | ruff check .
33 |
34 | # Check format (doesn't modify files)
35 | ruff format --check .
36 | ```
37 |
38 | To automatically fix linting issues and format your code:
39 |
40 | ```sh
41 | # Fix linting issues
42 | ruff check --fix .
43 |
44 | # Format code
45 | ruff format .
46 | ```
47 |
48 | These checks are enforced in CI, so we recommend running them locally before pushing changes.
49 |
--------------------------------------------------------------------------------
/docs/src/content/docs/extending/adding-languages.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Adding New Languages
3 | ---
4 |
5 | - To add a new language:
6 | 1. Add a tree-sitter grammar and build it (see [tree-sitter docs](https://tree-sitter.github.io/tree-sitter/creating-parsers)).
7 | 2. Add a `queries//tags.scm` file with queries for symbols you want to extract.
8 | 3. Add the file extension to `TreeSitterSymbolExtractor.LANGUAGES`.
9 | 4. Write/expand tests for the new language.
10 |
11 | **Why?**
12 | - This approach lets you support any language with a tree-sitter grammar—no need to change core logic.
13 | - `tags.scm` queries make symbol extraction flexible and community-driven.
14 |
--------------------------------------------------------------------------------
/docs/src/content/docs/introduction/overview.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | ## kit: Code Intelligence Toolkit
6 |
7 | A modular, production-grade toolkit for codebase mapping, symbol extraction, code search, and LLM-powered developer workflows. Supports multi-language codebases via `tree-sitter`.
8 |
9 | `kit` features a "mid-level API" to build your own custom tools, applications, agents, and workflows: easily build code review bots, semantic code search, documentation generators, and more.
10 |
11 | `kit` is **free and open source** with a permissive MIT license. Check it out on [GitHub](https://github.com/cased/kit).
12 |
13 | ## Installation
14 | ### Install from PyPI
15 | ```bash
16 | # Basic installation (includes PR reviewer, no ML dependencies)
17 | pip install cased-kit
18 |
19 | # With semantic search features (includes PyTorch, sentence-transformers)
20 | pip install cased-kit[ml]
21 |
22 | # Everything (all features)
23 | pip install cased-kit[all]
24 | ```
25 |
26 | ### Install from Source
27 | ```bash
28 | git clone https://github.com/cased/kit.git
29 | cd kit
30 | uv venv .venv
31 | source .venv/bin/activate
32 | uv pip install -e .
33 | ```
34 |
35 | ## Why Use kit?
36 |
37 | `kit` helps with:
38 |
39 | * **Unifying Code Access:** Provides a single, consistent `Repository` object to interact with files, symbols, and search across diverse codebases, regardless of language.
40 | * **Deep Code Understanding:** Leverages `tree-sitter` for accurate, language-specific parsing, enabling reliable symbol extraction and structural analysis across an entire codebase.
41 | * **Bridging Code and LLMs:** Offers tools specifically designed to chunk code effectively and retrieve relevant context for large language models, powering smarter AI developer tools.
42 |
43 | ## Core Philosophy
44 |
45 | `kit` aims to be a **toolkit** for building applications, agents, and workflows.
46 | It handles the low-level parsing and indexing complexity, and allows you to adapt these components to your specific needs.
47 |
48 | We believe the building blocks for code intelligence and LLM workflows for developer tools should be free and open source,
49 | so you can build amazing products and experiences.
50 |
51 |
52 | ## Where to Go Next
53 |
54 | * **Dive into the API:** Explore the [Core Concepts](/core-concepts/repository-api) to understand the `Repository` object and its capabilities.
55 | * **Build Something:** Follow the [Tutorials](/tutorials/ai_pr_reviewer) for step-by-step guides on creating practical tools.
56 |
57 | ## LLM Documentation
58 |
59 | This documentation site provides generated text files suitable for LLM consumption:
60 |
61 | - [`/llms.txt`](/llms.txt): Entrypoint file following the llms.txt standard.
62 | - [`/llms-full.txt`](/llms-full.txt): Complete documentation content concatenated into a single file.
63 | - [`/llms-small.txt`](/llms-small.txt): Minified documentation content for models with smaller context windows.
64 |
--------------------------------------------------------------------------------
/docs/src/content/docs/introduction/quickstart.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Quickstart
3 | ---
4 |
5 | ```bash
6 | git clone https://github.com/cased/kit.git
7 | cd kit
8 | uv venv .venv
9 | source .venv/bin/activate
10 | uv pip install -e .
11 | ```
12 |
13 | Now, you can use kit!
14 | kit ships with a demonstration repository at `tests/fixtures/` you can use to get started.
15 |
16 | Try this simple Python script (e.g., save as `test_kit.py` in the `kit` directory you cloned):
17 |
18 | ```python
19 | import kit
20 | import os
21 |
22 | # Path to the demo repository
23 | repo_path = "tests/fixtures/realistic_repo"
24 |
25 | print(f"Loading repository at: {repo_path}")
26 | # Ensure you have cloned the 'kit' repository and are in its root directory
27 | # for this relative path to work correctly.
28 | repo = kit.Repository(repo_path)
29 |
30 | # Print the first 5 Python files found in the demo repo
31 | print("\nFound Python files in the demo repo (first 5):")
32 | count = 0
33 | for file in repo.files('*.py'):
34 | print(f"- {file.path}")
35 | count += 1
36 | if count >= 5:
37 | break
38 |
39 | if count == 0:
40 | print("No Python files found in the demo repository.")
41 |
42 | # Extract symbols from a specific file in the demo repo (e.g., app.py)
43 | target_file = 'app.py'
44 | print(f"\nExtracting symbols from {target_file} in the demo repo (first 5):")
45 | try:
46 | symbols = repo.extract_symbols(target_file)
47 | if symbols:
48 | for i, symbol in enumerate(symbols):
49 | print(f"- {symbol.name} ({symbol.kind}) at line {symbol.range.start.line}")
50 | if i >= 4:
51 | break
52 | else:
53 | print(f"No symbols found or file not parseable: {target_file}")
54 | except FileNotFoundError:
55 | print(f"File not found: {target_file}")
56 | except Exception as e:
57 | print(f"An error occurred extracting symbols: {e}")
58 |
59 | ```
60 |
61 | Run it with `python test_kit.py`.
62 |
63 | Next, explore the [Usage Guide](/introduction/usage-guide) to understand the core concepts.
64 |
--------------------------------------------------------------------------------
/docs/src/content/docs/mcp/using-kit-with-mcp.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Using kit with MCP
3 | description: Learn how to use kit with the Model Context Protocol (MCP) for AI-powered code understanding
4 | ---
5 |
6 | Note: MCP support is currently in alpha.
7 |
8 | The Model Context Protocol (MCP) provides a unified API for codebase operations, making it easy to integrate kit's capabilities with AI tools and IDEs. This guide will help you set up and use kit with MCP.
9 |
10 | Kit provides a MCP server implementation that exposes its code intelligence capabilities through a standardized protocol. When using kit as an MCP server, you gain access to:
11 |
12 | - **Code Search**: Perform text-based and semantic code searches
13 | - **Code Analysis**: Extract symbols, find symbol usages, and analyze dependencies
14 | - **Code Summarization**: Create natural language summaries of code
15 | - **File Navigation**: Explore file trees and repository structure
16 |
17 | This document guides you through setting up and using `kit` with MCP-compatible tools like Cursor or Claude Desktop.
18 |
19 | ## What is MCP?
20 |
21 | MCP (Model Context Protocol) is a specification that allows AI agents and development tools to interact with your codebase programmatically via a local server. `kit` implements an MCP server to expose its code intelligence features.
22 |
23 | ## Available MCP Tools in `kit`
24 |
25 | Currently, `kit` exposes the following functionalities via MCP tools:
26 |
27 | * `open_repository`: Opens a local or remote Git repository. Supports `ref` parameter for specific commits, tags, or branches.
28 | * `get_file_tree`: Retrieves the file and directory structure of the open repository.
29 | * `get_file_content`: Reads the content of a specific file.
30 | * `search_code`: Performs text-based search across repository files.
31 | * `extract_symbols`: Extracts functions, classes, and other symbols from a file.
32 | * `find_symbol_usages`: Finds where a specific symbol is used across the repository.
33 | * `get_code_summary`: Provides AI-generated summaries for files, functions, or classes.
34 | * `get_git_info`: Retrieves git metadata including current SHA, branch, and remote URL.
35 |
36 | ### Opening Repositories with Specific Versions
37 |
38 | The `open_repository` tool supports analyzing specific versions of repositories using the optional `ref` parameter:
39 |
40 | ```json
41 | {
42 | "tool": "open_repository",
43 | "arguments": {
44 | "path_or_url": "https://github.com/owner/repo",
45 | "ref": "v1.2.3"
46 | }
47 | }
48 | ```
49 |
50 | The `ref` parameter accepts:
51 | - **Commit SHAs**: `"abc123def456"`
52 | - **Tags**: `"v1.2.3"`, `"release-2024"`
53 | - **Branches**: `"main"`, `"develop"`, `"feature-branch"`
54 |
55 | ### Accessing Git Metadata
56 |
57 | Use the `get_git_info` tool to access repository metadata:
58 |
59 | ```json
60 | {
61 | "tool": "get_git_info",
62 | "arguments": {
63 | "repo_id": "your-repo-id"
64 | }
65 | }
66 | ```
67 |
68 | This returns information like current commit SHA, branch name, and remote URL - useful for understanding what version of code you're analyzing.
69 |
70 | More MCP features are coming soon.
71 |
72 | ## Setup
73 |
74 | 1. After installing `kit`, configure your MCP-compatible client by adding a stanza like this to your settings:
75 |
76 | Available environment variables for the `env` section:
77 | - `OPENAI_API_KEY`
78 | - `KIT_MCP_LOG_LEVEL`
79 |
80 | ```json
81 | {
82 | "mcpServers": {
83 | "kit-mcp": {
84 | "command": "python",
85 | "args": ["-m", "kit.mcp"],
86 | "env": {
87 | "KIT_MCP_LOG_LEVEL": "DEBUG"
88 | }
89 | }
90 | }
91 | }
92 | ```
93 |
94 | The `python` executable invoked must be the one where `cased-kit` is installed.
95 | If you see `ModuleNotFoundError: No module named 'kit'`, ensure the Python
96 | interpreter your MCP client is using is the correct one.
--------------------------------------------------------------------------------
/docs/src/content/docs/tutorials/docstring_search.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Build a Docstring Search Engine
3 | ---
4 |
5 | In this tutorial you'll build a semantic search tool on top of `kit`
6 | using **docstring-based indexing**.
7 |
8 | Why docstrings? Summaries distill *intent* rather than syntax. Embedding these
9 | short natural-language strings lets the vector DB focus on meaning, giving you
10 | relevant hits even when the literal code differs (e.g., `retry()` vs
11 | `attempt_again()`). It also keeps the index small (one embedding per file or
12 | symbol instead of dozens of raw-code chunks).
13 |
14 | ---
15 |
16 | ## 1. Install dependencies
17 |
18 | ```bash
19 | uv pip install kit sentence-transformers chromadb
20 | ```
21 |
22 | ## 2. Initialise a repo and summarizer
23 |
24 | ```python
25 | import kit
26 | from kit import Repository, DocstringIndexer, Summarizer, SummarySearcher
27 | from sentence_transformers import SentenceTransformer
28 |
29 | REPO_PATH = "/path/to/your/project"
30 | repo = Repository(REPO_PATH)
31 |
32 | summarizer = repo.get_summarizer() # defaults to OpenAIConfig
33 | ```
34 |
35 | ## 3. Build the docstring index
36 |
37 | ```python
38 | embed_model = SentenceTransformer("all-MiniLM-L6-v2")
39 | embed_fn = lambda txt: embed_model.encode(txt).tolist()
40 |
41 | indexer = DocstringIndexer(repo, summarizer, embed_fn)
42 | indexer.build() # writes REPO_PATH/.kit_cache/docstring_db
43 | ```
44 |
45 | The first run will take time depending on repo size and LLM latency.
46 | Summaries are cached inside the vector DB (and in a meta.json within the persist_dir),
47 | so subsequent runs are cheap if code hasn't changed.
48 |
49 | ## 4. Query the index
50 |
51 | ```python
52 | searcher = indexer.get_searcher()
53 |
54 | results = searcher.search("How is the retry back-off implemented?", top_k=3)
55 | for hit in results:
56 | print(f"→ File: {hit.get('file_path', 'N/A')}\n Summary: {hit.get('summary', 'N/A')}")
57 | ```
58 |
59 | You now have a semantic code searcher, using powerful docstring summaries,
60 | as easy as that.
61 |
62 |
--------------------------------------------------------------------------------
/docs/src/content/docs/tutorials/dump_repo_map.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Dump Repo Map
3 | ---
4 |
5 | import { Aside } from '@astrojs/starlight/components';
6 |
7 | This tutorial explains how to use `kit` to dump a complete map of your repository—including the file tree and all extracted symbols—as a JSON file. This is useful for further analysis, visualization, or integration with other tools. `kit` provides a convenient method on the `Repository` object to achieve this directly.
8 |
9 | ## Step 1: Create the Script
10 |
11 | Create a Python script named `dump_repo_map.py` with the following content. This script uses `argparse` to accept the repository path and the desired output file path.
12 |
13 | ```python
14 | # dump_repo_map.py
15 | from kit import Repository # Import the main Repository class
16 | import argparse
17 | import sys
18 | import os
19 |
20 | def main():
21 | parser = argparse.ArgumentParser(description="Dump a repository's file tree and symbols as JSON using kit.")
22 | parser.add_argument("repo_path", help="Path to the repository directory.")
23 | parser.add_argument("output_file", help="Path to the output JSON file.")
24 | args = parser.parse_args()
25 |
26 | repo_path = args.repo_path
27 | if not os.path.isdir(repo_path):
28 | print(f"Error: Repository path not found or not a directory: {repo_path}", file=sys.stderr)
29 | sys.exit(1)
30 |
31 | try:
32 | print(f"Initializing repository at: {repo_path}", file=sys.stderr)
33 | repo = Repository(repo_path)
34 |
35 | print(f"Dumping repository index to: {args.output_file}", file=sys.stderr)
36 | repo.write_index(args.output_file) # Use the direct method
37 |
38 | print(f"Successfully wrote repository map to {args.output_file}", file=sys.stderr)
39 | except Exception as e:
40 | print(f"Error processing repository: {e}", file=sys.stderr)
41 | sys.exit(1)
42 |
43 | if __name__ == "__main__":
44 | main()
45 | ```
46 |
47 | ---
48 |
49 | ## Step 2: Run the Script
50 |
51 | Save the code above as `dump_repo_map.py`. You can then run it from your terminal, providing the path to the repository you want to map and the desired output file name:
52 |
53 | ```sh
54 | python dump_repo_map.py /path/to/repo repo_map.json
55 | ```
56 |
57 | This will create a JSON file (e.g., `repo_map.json`) containing the structure and symbols of your codebase.
58 |
59 | ---
60 |
61 | ## Example JSON Output
62 |
63 | The output JSON file will contain a `file_tree` (also aliased as `files`) and a `symbols` map.
64 |
65 | ```json
66 | {
67 | "file_tree": [
68 | {
69 | "path": "src",
70 | "is_dir": true,
71 | "name": "src",
72 | "size": 0
73 | },
74 | {
75 | "path": "src/main.py",
76 | "is_dir": false,
77 | "name": "main.py",
78 | "size": 1024
79 | },
80 | {
81 | "path": "README.md",
82 | "is_dir": false,
83 | "name": "README.md",
84 | "size": 2048
85 | }
86 | // ... more files and directories
87 | ],
88 | "files": [
89 | // ... same content as file_tree ...
90 | ],
91 | "symbols": {
92 | "src/main.py": [
93 | {
94 | "type": "function",
95 | "name": "main",
96 | "start_line": 10,
97 | "end_line": 25,
98 | "code": "def main():\n pass"
99 | },
100 | {
101 | "type": "class",
102 | "name": "App",
103 | "start_line": 30,
104 | "end_line": 55
105 | }
106 | ],
107 | "src/utils.py": [
108 | {
109 | "type": "function",
110 | "name": "helper",
111 | "start_line": 5,
112 | "end_line": 12
113 | }
114 | ]
115 | // ... more files and their symbols
116 | }
117 | }
118 | ```
119 |
120 |
123 |
124 | ---
125 |
126 | ## Integration Ideas
127 |
128 | - Use the JSON output to feed custom dashboards or documentation tools.
129 | - Integrate with code search or visualization tools.
130 | - Use for code audits, onboarding, or automated reporting.
131 |
132 | ---
133 |
134 | ## Conclusion
135 |
136 | With `kit`, you can easily export a structured map of your repository using `repo.write_index()`, making this data readily available for various downstream use cases and custom tooling.
137 |
--------------------------------------------------------------------------------
/docs/src/content/docs/tutorials/integrating_supersonic.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Integrating with Supersonic
3 | description: Using kit for code analysis and Supersonic for automated PR creation.
4 | ---
5 |
6 | import { Aside } from '@astrojs/starlight/components';
7 |
8 | `kit` excels at understanding and analyzing codebases, while [Supersonic](https://github.com/cased/supersonic) provides a high-level Python API specifically designed for programmatically creating GitHub Pull Requests. Combining them allows you to build powerful workflows that analyze code, generate changes, and automatically propose those changes via PRs.
9 |
10 |
14 |
15 | ## The Workflow: Analyze with `kit`, Act with `Supersonic`
16 |
17 | A typical integration pattern looks like this:
18 |
19 | 1. **Analyze Code with `kit`**: Use `kit.Repository` methods like `extract_symbols`, `find_symbol_usages`, or `search_semantic` to understand the codebase or identify areas for modification.
20 | 2. **Generate Changes**: Based on the analysis (potentially involving an LLM), generate the new code content or identify necessary file modifications.
21 | 3. **Create PR with `Supersonic`**: Use `Supersonic`'s simple API (`create_pr_from_content`, `create_pr_from_file`, etc.) to package the generated changes into a new Pull Request on GitHub.
22 |
23 | ## Example: AI Refactoring Suggestion
24 |
25 | Imagine an AI tool that uses `kit` to analyze a Python file, identifies a potential refactoring, generates the improved code, and then uses `Supersonic` to create a PR.
26 |
27 | ```python
28 | import kit
29 | from supersonic import Supersonic
30 | import os
31 |
32 | # Assume kit.Repository is initialized with a local path
33 | LOCAL_REPO_PATH = "/path/to/your/local/repo/clone"
34 | # repo_analyzer = kit.Repository(LOCAL_REPO_PATH)
35 | # Note: kit analysis methods like extract_symbols would still be used here in a real scenario.
36 |
37 | # Assume 'ai_generate_refactoring' is your function that uses an LLM
38 | # potentially fed with context from kit (not shown here for brevity)
39 | def ai_generate_refactoring(original_code: str) -> str:
40 | # ... your AI logic here ...
41 | improved_code = original_code.replace("old_function", "new_function") # Simplified example
42 | return improved_code
43 |
44 | # --- Configuration ---
45 | GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
46 | REPO_OWNER_SLASH_NAME = "your-org/your-repo" # For Supersonic PR creation
47 | RELATIVE_FILE_PATH = "src/legacy_module.py" # Relative path within the repo
48 | FULL_FILE_PATH = os.path.join(LOCAL_REPO_PATH, RELATIVE_FILE_PATH)
49 | TARGET_BRANCH = "main" # Or dynamically determine
50 |
51 | # --- Main Workflow ---
52 |
53 | try:
54 | # 1. Get original content (assuming local repo)
55 | if not os.path.exists(FULL_FILE_PATH):
56 | print(f"Error: File not found at {FULL_FILE_PATH}")
57 | exit()
58 |
59 | with open(FULL_FILE_PATH, 'r') as f:
60 | original_content = f.read()
61 |
62 | # 2. Generate Changes (using AI or other logic)
63 | refactored_content = ai_generate_refactoring(original_content)
64 |
65 | if refactored_content != original_content:
66 | # 3. Create PR with Supersonic
67 | supersonic_client = Supersonic(GITHUB_TOKEN)
68 | pr_title = f"AI Refactor: Improve {RELATIVE_FILE_PATH}"
69 | pr_body = f"""
70 | AI analysis suggests refactoring in `{RELATIVE_FILE_PATH}`.
71 |
72 | This PR applies the suggested changes. Please review carefully.
73 | """
74 |
75 | pr_url = supersonic_client.create_pr_from_content(
76 | repo=REPO_OWNER_SLASH_NAME,
77 | content=refactored_content,
78 | upstream_path=RELATIVE_FILE_PATH, # Path within the target repo
79 | title=pr_title,
80 | description=pr_body,
81 | base_branch=TARGET_BRANCH,
82 | labels=["ai-refactor", "needs-review"],
83 | draft=True # Good practice for AI suggestions
84 | )
85 | print(f"Successfully created PR: {pr_url}")
86 | else:
87 | print("No changes generated.")
88 |
89 | except Exception as e:
90 | print(f"An error occurred: {e}")
91 |
92 | ```
93 |
94 | This example illustrates how `kit`'s analytical strengths can be combined with `Supersonic`'s action-oriented PR capabilities to build powerful code automation.
95 |
--------------------------------------------------------------------------------
/docs/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
--------------------------------------------------------------------------------
/docs/src/styles/fonts/IBMPlexSansV.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cased/kit/7b2d248e06f9105dd51ef7968c0573041c19a80b/docs/src/styles/fonts/IBMPlexSansV.ttf
--------------------------------------------------------------------------------
/docs/src/styles/fonts/iAWriterQuattroV.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cased/kit/7b2d248e06f9105dd51ef7968c0573041c19a80b/docs/src/styles/fonts/iAWriterQuattroV.ttf
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/base"
3 | }
4 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kit",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {}
6 | }
7 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "cased-kit"
3 | version = "0.6.3"
4 | description = "A modular toolkit for LLM-powered codebase understanding."
5 | authors = [
6 | { name = "Cased", email = "ted@cased.com" }
7 | ]
8 | readme = "README.md"
9 | requires-python = ">=3.10"
10 | license = {text = "MIT"}
11 | dependencies = [
12 | "tree-sitter-language-pack>=0.7.2",
13 | "pathspec>=0.11.1",
14 | "pytest>=8.3.5",
15 | "numpy>=1.25",
16 | "fastapi==0.110.0",
17 | "uvicorn[standard]>=0.20",
18 | "typer>=0.9,<0.15",
19 | "click>=8.0,<8.2",
20 | "openai>=1.0.0",
21 | "tiktoken>=0.4.0",
22 | "anthropic>=0.20.0",
23 | "google-genai>=1.14.0",
24 | "python-hcl2>=7.2.0",
25 | "mypy",
26 | "ruff",
27 | "mcp>=1.8.0,<2.0.0",
28 | "redis>=5.0.0",
29 | "requests>=2.25.0",
30 | "pyyaml>=6.0",
31 | "types-PyYAML>=6.0.12.20250516", # Type stubs for yaml
32 | "types-requests>=2.32.0.20250515", # Type stubs for requests
33 | ]
34 |
35 | [project.urls]
36 | Homepage = "https://github.com/cased/kit"
37 |
38 | [project.scripts]
39 | kit = "kit.cli:app"
40 | kit-mcp = "kit.mcp:main"
41 |
42 | [tool.setuptools]
43 | package-dir = {"" = "src"}
44 |
45 | [tool.setuptools.packages.find]
46 | where = ["src"]
47 |
48 | [tool.setuptools.package-data]
49 | "kit.queries" = ["*/*.scm"]
50 | "kit" = ["queries/*/*/*.scm"]
51 |
52 | [build-system]
53 | requires = ["setuptools>=61.0"]
54 | build-backend = "setuptools.build_meta"
55 |
56 | [tool.pytest.ini_options]
57 | minversion = "6.0"
58 | addopts = "-ra -q"
59 | testpaths = [
60 | "tests"
61 | ]
62 | python_files = "test_*.py"
63 | python_classes = "Test*"
64 | python_functions = "test_*"
65 | markers = [
66 | "asyncio: mark test as asyncio to run with pytest-asyncio",
67 | "integration: marks tests as integration tests (may be slower)",
68 | "llm: marks tests that call LLM APIs (expensive, requires API keys)",
69 | "expensive: marks tests that are expensive/slow to run",
70 | "performance: marks tests that measure performance characteristics",
71 | "ci_skip: marks tests that should be skipped in CI environments",
72 | ]
73 |
74 | [tool.mypy]
75 | ignore_missing_imports = true
76 |
77 | [project.optional-dependencies]
78 | dev = [
79 | "build", # build wheels
80 | "twine", # publish to PyPI
81 | ]
82 | test-api = [
83 | "fastapi", # For TestClient
84 | "pytest" # Already in core, but good to list for a test group
85 | ]
86 | ml = [
87 | "sentence-transformers>=2.2.0", # For VectorSearcher and DocstringIndexer
88 | "chromadb>=0.5.23", # Vector database for semantic search
89 | ]
90 | all = [
91 | "sentence-transformers>=2.2.0",
92 | "chromadb>=0.5.23",
93 | ]
94 |
95 | [tool.ruff]
96 | # Set line length to 120 characters
97 | line-length = 120
98 | # Target Python 3.10 as specified in our requires-python
99 | target-version = "py310"
100 |
101 | # Configure linting
102 | [tool.ruff.lint]
103 | # Select these rule sets (categories)
104 | select = ["E", "F", "W", "I", "RUF"]
105 | ignore = []
106 |
107 | # Configure isort rules
108 | [tool.ruff.lint.isort]
109 | known-first-party = ["kit", "cased_kit"]
110 |
111 | # Configure formatter
112 | [tool.ruff.format]
113 | # Formatting uses line-length from the top level
114 |
--------------------------------------------------------------------------------
/scripts/benchmark.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from kit.repository import Repository as Repo
4 |
5 |
6 | def main():
7 | import argparse
8 |
9 | parser = argparse.ArgumentParser(description="Benchmark kit repo indexing.")
10 | parser.add_argument("repo", nargs="?", default=".", help="Path to repo root (default: .)")
11 | args = parser.parse_args()
12 | repo = Repo(args.repo)
13 |
14 | print(f"Indexing repo at {args.repo} ...")
15 | start = time.time()
16 | idx = repo.index()
17 | elapsed = time.time() - start
18 | num_files = len(idx["file_tree"])
19 | num_symbols = sum(len(syms) for syms in idx["symbols"].values())
20 | print(f"Indexed {num_files} files, {num_symbols} symbols in {elapsed:.2f} seconds.")
21 |
22 |
23 | if __name__ == "__main__":
24 | main()
25 |
--------------------------------------------------------------------------------
/scripts/format.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # This script runs linting and formatting checks using Ruff.
3 | # Pass --fix as the first argument to automatically apply fixes.
4 |
5 | # Exit immediately if a command exits with a non-zero status.
6 | set -e
7 |
8 | # Navigate to the root of the repository relative to the script directory
9 | cd "$(dirname "$0")/.."
10 |
11 | # Check the first argument
12 | if [ "$1" == "--fix" ]; then
13 | echo "Running Ruff to apply fixes (linting and formatting)..."
14 | # Apply lint rule fixes (autofixable ones)
15 | ruff check . --fix
16 | # Apply formatting fixes
17 | ruff format .
18 | echo "Ruff fixes applied successfully!"
19 | else
20 | echo "Running Ruff linter and formatting check (no fixes applied)..."
21 | # Ruff check combines linting and format checking
22 | ruff check .
23 | echo "Ruff checks passed successfully!"
24 | fi
--------------------------------------------------------------------------------
/scripts/index.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | CLI: Index a repo and print the file tree and symbols as JSON
4 | Usage:
5 | python scripts/index.py /path/to/repo
6 | """
7 |
8 | import json
9 | import sys
10 |
11 | from kit import Repository
12 |
13 | if __name__ == "__main__":
14 | repo_path = sys.argv[1] if len(sys.argv) > 1 else "."
15 | repo = Repository(repo_path)
16 | index = repo.index()
17 | print(json.dumps(index, indent=2))
18 |
--------------------------------------------------------------------------------
/scripts/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Ensure all deps (including vector search) are installed, then run tests
3 |
4 | export PYTHONPATH=src
5 | python -m pytest "$@"
6 |
--------------------------------------------------------------------------------
/scripts/typecheck.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Run mypy type checks for all source and test code
3 | export PYTHONPATH=src
4 | mypy src/kit
5 | mypy tests
6 |
--------------------------------------------------------------------------------
/src/kit/api/__init__.py:
--------------------------------------------------------------------------------
1 | """kit REST API package."""
2 |
3 | from .app import app # re-export for `uvicorn kit.api:app`
4 |
--------------------------------------------------------------------------------
/src/kit/dependency_analyzer/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .dependency_analyzer import DependencyAnalyzer
4 |
5 | __all__ = ["DependencyAnalyzer"]
6 |
--------------------------------------------------------------------------------
/src/kit/llm_context.py:
--------------------------------------------------------------------------------
1 | """Utilities to assemble rich prompts for LLMs.
2 |
3 | This is intentionally lightweight – it glues together repository data
4 | (diff, file bodies, search hits, etc.) into a single string that can be
5 | fed straight into a chat completion.
6 | """
7 |
8 | from __future__ import annotations
9 |
10 | from pathlib import Path
11 | from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence
12 |
13 | if TYPE_CHECKING:
14 | from .repository import Repository
15 |
16 |
17 | class ContextAssembler:
18 | """Collects pieces of context and spits out a prompt blob.
19 |
20 | Parameters
21 | ----------
22 | repo
23 | A :class:`kit.repository.Repository` object representing the codebase
24 | we want to reason about. The assembler uses it to fetch file content
25 | and (in the future) symbol relationships.
26 | title
27 | Optional global title prepended to the context (not used by default).
28 | """
29 |
30 | def __init__(self, repo: Repository, *, title: Optional[str] = None) -> None:
31 | self.repo = repo
32 | self._sections: List[str] = []
33 | if title:
34 | self._sections.append(f"# {title}\n")
35 |
36 | def add_diff(self, diff: str) -> None:
37 | """Add a raw git diff section."""
38 | if not diff.strip():
39 | return
40 | self._sections.append("## Diff\n```diff\n" + diff.strip() + "\n```")
41 |
42 | def add_file(
43 | self,
44 | file_path: str,
45 | *,
46 | highlight_changes: bool = False,
47 | max_lines: int | None = None,
48 | max_bytes: int | None = None,
49 | skip_if_name_in: Optional[Sequence[str]] = None,
50 | ) -> None:
51 | """Embed full file content.
52 |
53 | If *highlight_changes* is true we still just inline raw content –
54 | markup is left to the caller/LLM.
55 | """
56 | # Guard: skip by exact filename
57 | if skip_if_name_in and Path(file_path).name in skip_if_name_in:
58 | return
59 |
60 | try:
61 | code = self.repo.get_file_content(file_path)
62 | except FileNotFoundError:
63 | return
64 |
65 | # Guards: size limits
66 | if max_bytes is not None and len(code.encode("utf-8", "ignore")) > max_bytes:
67 | return
68 | if max_lines is not None and code.count("\n") + 1 > max_lines:
69 | return
70 |
71 | lang = Path(file_path).suffix.lstrip(".") or "text"
72 | header = f"## {file_path} (full)" if not highlight_changes else f"## {file_path} (with changes highlighted)"
73 | self._sections.append(f"{header}\n```{lang}\n{code}\n```")
74 |
75 | def add_search_results(self, results: Sequence[Dict[str, Any]], *, query: str) -> None:
76 | """Append semantic search matches to the context."""
77 | if not results:
78 | return
79 | blob = [f"## Semantic search for: {query}"]
80 | for i, res in enumerate(results, 1):
81 | code = res.get("code") or res.get("snippet") or ""
82 | file = res.get("file", f"result_{i}")
83 | blob.append(f"### {file}\n```\n{code}\n```")
84 | self._sections.append("\n".join(blob))
85 |
86 | def format_context(self) -> str:
87 | """Return the accumulated context."""
88 | return "\n\n".join(self._sections)
89 |
--------------------------------------------------------------------------------
/src/kit/mcp/__init__.py:
--------------------------------------------------------------------------------
1 | """kit.mcp – Model Context Protocol server wrapper."""
2 |
3 | from __future__ import annotations
4 |
5 | from .main import main as main
6 | from .server import serve as serve
7 |
8 | __all__ = ["main", "serve"]
9 |
--------------------------------------------------------------------------------
/src/kit/mcp/__main__.py:
--------------------------------------------------------------------------------
1 | """Entry point for the MCP module."""
2 |
3 | from __future__ import annotations
4 |
5 | from .main import main
6 |
7 | if __name__ == "__main__":
8 | main()
9 |
--------------------------------------------------------------------------------
/src/kit/mcp/main.py:
--------------------------------------------------------------------------------
1 | """Console-script entry point for the Kit MCP server."""
2 |
3 | from __future__ import annotations
4 |
5 | import asyncio
6 | import logging
7 | import sys
8 |
9 | from .server import serve
10 |
11 |
12 | def main() -> None:
13 | """Launch the Kit MCP server."""
14 | try:
15 | asyncio.run(serve())
16 | except KeyboardInterrupt:
17 | logging.info("Server stopped by user")
18 | except Exception as e: # pragma: no cover
19 | logging.error(f"Server error: {e!s}", exc_info=True)
20 | sys.exit(1)
21 |
22 |
23 | if __name__ == "__main__":
24 | main()
25 |
--------------------------------------------------------------------------------
/src/kit/pr_review/ROADMAP.md:
--------------------------------------------------------------------------------
1 | # Kit Roadmap
2 |
3 | This roadmap outlines planned features and improvements for kit, prioritized by user feedback and strategic value.
4 |
5 | ## 📅 Planned Features
6 |
7 | #### Per-User/Per-Organization Custom Context
8 | Store custom guidelines, coding standards, and preferences that get automatically included in reviews.
9 |
10 | ```bash
11 | # Example usage
12 | kit profile create --name "company-standards" --file coding-guidelines.md
13 | kit review --profile company-standards
14 | ```
15 |
16 | #### Feedback Learning System
17 | Simple database to store review feedback and adapt over time.
18 |
19 | ```bash
20 | # Example feedback workflow
21 | kit review # Generates review
22 | kit feedback --helpful/--not-helpful --notes "Missed performance issue"
23 | kit insights # Show what's working well
24 | ```
25 |
26 | #### Inline Comments & GitHub Review API
27 | Post comments directly on specific lines instead of single review comment.
28 |
29 | ```bash
30 | kit review --mode inline # Line-by-line comments
31 | ```
32 |
33 | ### 🎯 Medium Term (Q3-Q4 2025)
34 |
35 | #### Multi-Model Consensus
36 | Route different aspects to different models and aggregate insights.
37 |
38 | ```bash
39 | kit review --consensus # Use multiple models, combine results
40 | ```
41 |
42 | #### Repository Context Learning
43 | Learn which types of context are most valuable and adapt automatically.
44 |
45 | #### IDE Integration
46 | Real-time suggestions in VS Code and other editors while coding.
47 |
48 | ---
49 |
50 | ## 🔧 Technical Improvements
51 |
52 | - **Model Router**: Intelligent routing to optimal models based on PR complexity
53 | - **Context Optimization**: Smarter context selection to maximize LLM effectiveness
54 | - **Plugin System**: Simple plugin architecture for custom analyzers
55 |
56 | ---
57 |
58 | ## 🎯 Success Metrics
59 |
60 | ### User Experience
61 | - **Review Relevance**: >80% of suggestions rated as helpful
62 | - **Response Time**: <30 seconds for standard reviews
63 | - **Cost Efficiency**: <$0.10 per review for typical usage
64 | - **Adoption Rate**: >90% of PRs reviewed within 1 hour
65 |
66 | ### Technical Quality
67 | - **Uptime**: >99.9% availability for cloud service
68 | - **Accuracy**: <5% false positive rate on issue detection
69 | - **Performance**: Support for repositories up to 1M lines of code
70 | - **Scalability**: Handle 10,000+ reviews per day per organization
71 |
72 | ### Business Impact
73 | - **Code Quality**: Measurable improvement in code quality metrics
74 | - **Development Velocity**: Faster PR review cycles
75 | - **Bug Reduction**: Fewer bugs in production
76 | - **Developer Satisfaction**: High satisfaction scores from development teams
77 |
78 | ---
79 |
80 | ## 📞 Get Involved
81 |
82 | - **Feature Requests**: [Open an issue](https://github.com/cased/kit/issues) with your ideas
83 | - **User Feedback**: Join our [Discord community](https://discord.gg/fbAVtCeU) soon for discussions
84 | - **Contributions**: Submit PRs for features you'd like to see
85 |
86 | ---
87 |
--------------------------------------------------------------------------------
/src/kit/pr_review/__init__.py:
--------------------------------------------------------------------------------
1 | """PR Review functionality for kit."""
2 |
3 | from .cache import RepoCache
4 | from .config import ReviewConfig
5 | from .reviewer import PRReviewer
6 |
7 | __all__ = ["PRReviewer", "RepoCache", "ReviewConfig"]
8 |
--------------------------------------------------------------------------------
/src/kit/pr_review/__main__.py:
--------------------------------------------------------------------------------
1 | """Entry point for running the PR review debug CLI as a module."""
2 |
3 | from .debug import app
4 |
5 | if __name__ == "__main__":
6 | app()
7 |
--------------------------------------------------------------------------------
/src/kit/pr_review/debug.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """Debug CLI for PR review testing."""
3 |
4 | from typing import Optional
5 |
6 | import typer
7 |
8 | app = typer.Typer(help="Debug tools for PR review testing.")
9 |
10 |
11 | @app.command("review")
12 | def review_pr(
13 | pr_url: str,
14 | config: Optional[str] = typer.Option(None, "--config", "-c", help="Path to config file"),
15 | dry_run: bool = typer.Option(True, "--dry-run/--post", help="Run analysis but do not post comment"),
16 | ):
17 | """Review a GitHub PR using kit analysis for testing."""
18 | try:
19 | from .config import ReviewConfig
20 | from .reviewer import PRReviewer
21 |
22 | # Load configuration
23 | if config:
24 | review_config = ReviewConfig.from_file(config)
25 | else:
26 | review_config = ReviewConfig.from_file()
27 |
28 | # Override post_as_comment if dry run
29 | if dry_run:
30 | review_config.post_as_comment = False
31 |
32 | # Run review
33 | reviewer = PRReviewer(review_config)
34 | result = reviewer.review_pr(pr_url)
35 |
36 | if dry_run:
37 | typer.echo("\n" + "=" * 50)
38 | typer.echo("REVIEW RESULT (DRY RUN)")
39 | typer.echo("=" * 50)
40 | typer.echo(result)
41 | else:
42 | typer.echo("✅ Review posted to PR")
43 |
44 | except Exception as e:
45 | typer.echo(f"❌ Error during review: {e}", err=True)
46 | raise typer.Exit(1)
47 |
48 |
49 | if __name__ == "__main__":
50 | app()
51 |
--------------------------------------------------------------------------------
/src/kit/pr_review/example_reviews/biopython_204_documentation_fix.md:
--------------------------------------------------------------------------------
1 | # Example Review: Biopython Documentation Fix PR #204
2 |
3 | **Repository**: [biopython/biopython.github.io](https://github.com/biopython/biopython.github.io)
4 | **PR**: [#204 - Add correct import statement to FAQ](https://github.com/biopython/biopython.github.io/pull/204)
5 | **Status**: Merged ✅
6 | **Changed Files**: 1
7 | **Review Model**: Claude Sonnet 4
8 | **Cost**: $0.0064
9 |
10 | ## PR Summary
11 |
12 | This is a simple documentation fix that adds a correct import statement to the Biopython Structural Bioinformatics FAQ. The author experienced an error when following the documentation and fixed it by adding the proper import statement that was missing.
13 |
14 | **Problem**: `MMCIF2Dict("5SWE.Cif")` was failing with "TypeError: 'module' object is not callable" because the import statement only imported the module, not the class.
15 |
16 | **Solution**: Added the correct import statement to make the code examples work properly.
17 |
18 | ---
19 |
20 | ## Kit AI Review Output
21 |
22 | ### Priority Issues
23 | No significant issues identified. This is a straightforward documentation improvement.
24 |
25 | ### Summary
26 | This PR adds a correct import statement to the Biopython Structural Bioinformatics FAQ documentation. The change appears to be a minor documentation fix, adding 2 lines to clarify proper import usage for users following the FAQ guide.
27 |
28 | Based on the file analysis showing:
29 | - Single markdown file modified (`wiki/The_Biopython_Structural_Bioinformatics_FAQ.md`)
30 | - 2 lines added, 0 lines removed
31 | - No symbols or code dependencies affected
32 |
33 | This is a low-risk documentation enhancement that should improve user experience by providing clearer import guidance.
34 |
35 | ### Recommendations
36 |
37 | **Documentation Quality:**
38 | - Since the actual diff content isn't accessible due to the 404 error, I recommend verifying that:
39 | - The import statement follows current Biopython conventions
40 | - The syntax is correct and tested
41 | - The import aligns with the specific FAQ context where it's being added
42 |
43 | **Process Improvement:**
44 | - Consider adding a brief comment in the PR description explaining which specific import was corrected and why, to help future maintainers understand the context
45 |
46 | **Validation:**
47 | - Ensure the import statement works with the current version of Biopython being documented
48 | - Verify the import is placed in the appropriate section of the FAQ for logical flow
49 |
50 | This appears to be a beneficial change that enhances the documentation's accuracy and user-friendliness with minimal risk.
51 |
52 | ---
53 |
54 | ## Review Quality Metrics
55 |
56 | - **File References**: 1
57 | - **Line References**: 0
58 | - **Specific Issues**: 1
59 | - **Vague Statements**: 0
60 | - **GitHub Links**: 0
61 | - **Code Relevance**: 0.8
62 | - **Change Coverage**: 1.0
63 | - **Overall Score**: 1.00/1.0
64 |
65 | ## Key Insights
66 |
67 | 1. **Proportional Response**: Kit provided an appropriately scaled review for a small documentation change
68 | 2. **Risk Assessment**: Correctly identified this as a low-risk documentation enhancement
69 | 3. **Context Understanding**: Recognized the fix was about import statement corrections
70 | 4. **Practical Recommendations**: Focused on documentation quality and validation rather than complex code issues
71 | 5. **Cost Efficiency**: Minimal cost ($0.0064) for appropriate level of analysis
72 |
73 | This review demonstrates Kit's ability to scale its analysis appropriately for different types of changes, providing useful feedback without over-engineering the response for simple fixes.
--------------------------------------------------------------------------------
/src/kit/pr_review/example_reviews/fastapi_11935_standard_dependencies.md:
--------------------------------------------------------------------------------
1 | # Example Review: FastAPI PR #11935
2 |
3 | **Repository**: [tiangolo/fastapi](https://github.com/tiangolo/fastapi)
4 | **PR**: [#11935 - Add support for `pip install "fastapi[standard]"` with standard dependencies](https://github.com/tiangolo/fastapi/pull/11935)
5 | **Status**: Merged ✅
6 | **Changed Files**: 15
7 | **Review Model**: Claude Sonnet 4
8 | **Cost**: $0.0340
9 |
10 | ## PR Summary
11 |
12 | This PR introduces a significant packaging change for FastAPI, moving from a "batteries-included" default installation to an opt-in approach for standard dependencies. The change allows users to install either:
13 | - `pip install fastapi` (minimal installation)
14 | - `pip install "fastapi[standard]"` (full experience with CLI and development tools)
15 |
16 | ---
17 |
18 | ## Kit AI Review Output
19 |
20 | ### Priority Issues
21 |
22 | **Medium Priority**
23 | - [fastapi/cli.py:12](https://github.com/fastapi/fastapi/blob/main/fastapi/cli.py#L12): The error handling raises a RuntimeError after printing the message, which could be confusing in programmatic usage. Consider using a more specific exception type like `ImportError` or `ModuleNotFoundError`.
24 |
25 | **Low Priority**
26 | - [tests/test_fastapi_cli.py:14](https://github.com/fastapi/fastapi/blob/main/tests/test_fastapi_cli.py#L14): The test uses coverage run which adds complexity. Consider testing the CLI functionality more directly or documenting why coverage is needed here.
27 |
28 | ### Summary
29 |
30 | This PR introduces a significant packaging change for FastAPI, moving from a "batteries-included" default installation to an opt-in approach for standard dependencies. Key changes include:
31 |
32 | - **New installation pattern**: Users now install `pip install "fastapi[standard]"` for the full experience, while `pip install fastapi` provides a minimal installation
33 | - **CLI integration**: Adds `python -m fastapi` support through new `__main__.py` and `cli.py` modules
34 | - **Graceful degradation**: When CLI dependencies aren't available, provides clear error messages with installation instructions
35 | - **Documentation updates**: Comprehensive updates across README and docs to reflect the new installation approach
36 |
37 | The architectural change simplifies the core FastAPI package while maintaining backward compatibility through optional dependencies.
38 |
39 | ### Recommendations
40 |
41 | **Error Handling Enhancement**
42 | ```python
43 | # In fastapi/cli.py, consider using a more specific exception:
44 | def main() -> None:
45 | if not cli_main:
46 | message = 'To use the fastapi command, please install "fastapi[standard]":\n\n\tpip install "fastapi[standard]"\n'
47 | print(message)
48 | raise ImportError(message) from None # More semantically correct
49 | ```
50 |
51 | **Test Coverage Improvement**
52 | - Consider adding a test that verifies the CLI works when `fastapi-cli` is properly installed
53 | - The current test only covers the error case and uses subprocess with coverage, which may be brittle
54 |
55 | **Documentation Consistency**
56 | - Verify that all code examples in tutorials and documentation are updated to use the new installation pattern
57 | - Consider adding a migration guide for existing users
58 |
59 | **Cross-codebase Impact**
60 | - This change will affect all downstream projects and tutorials that reference FastAPI installation
61 | - Consider coordinating with the ecosystem (tutorials, courses, etc.) for a smooth transition
62 | - The change is well-documented but represents a significant shift in user experience
63 |
64 | The implementation is solid and the graceful error handling for missing CLI dependencies is well-designed. The packaging simplification aligns with modern Python practices of minimal default installations with optional extras.
65 |
66 | ---
67 |
68 | ## Review Quality Metrics
69 |
70 | - **File References**: 3
71 | - **Line References**: 4
72 | - **Specific Issues**: 7
73 | - **Vague Statements**: 0
74 | - **GitHub Links**: 2
75 | - **Code Relevance**: 1.0
76 | - **Change Coverage**: 1.0
77 | - **Overall Score**: 1.00/1.0
78 |
79 | ## Key Insights
80 |
81 | 1. **Comprehensive Analysis**: Kit identified both the immediate code changes and broader ecosystem impact
82 | 2. **Specific Recommendations**: Provided concrete code suggestions with rationale
83 | 3. **Quality Focus**: Flagged potential issues in error handling and test design
84 | 4. **Context Awareness**: Understood this was a breaking change requiring ecosystem coordination
85 |
86 | This review demonstrates Kit's ability to understand architectural changes and their broader implications beyond just code syntax.
--------------------------------------------------------------------------------
/src/kit/pr_review/example_reviews/react_dev_6986_branding_menu.md:
--------------------------------------------------------------------------------
1 | # Example Review: React.dev PR #6986
2 |
3 | **Repository**: [reactjs/react.dev](https://github.com/reactjs/react.dev)
4 | **PR**: [#6986 - Add branding context menu](https://github.com/reactjs/react.dev/pull/6986)
5 | **Status**: Merged ✅
6 | **Changed Files**: 8
7 | **Review Model**: Claude Sonnet 4
8 | **Cost**: $0.0118
9 |
10 | ## PR Summary
11 |
12 | This PR adds a context menu to the React logo in the top navigation that provides access to React branding materials. When users right-click on the logo, they can access brand assets including logos and wordmarks in both light and dark variants.
13 |
14 | ---
15 |
16 | ## Kit AI Review Output
17 |
18 | ### Priority Issues
19 |
20 | **Medium Priority:**
21 | - [src/components/Layout/TopNav/BrandMenu.tsx:1](https://github.com/rickhanlonii/react.dev/blob/main/src/components/Layout/TopNav/BrandMenu.tsx#L1) - Missing accessibility attributes for the dropdown menu. The menu button should have `aria-expanded`, `aria-haspopup`, and proper ARIA labeling for screen readers.
22 |
23 | - [src/components/Layout/TopNav/BrandMenu.tsx:1](https://github.com/rickhanlonii/react.dev/blob/main/src/components/Layout/TopNav/BrandMenu.tsx#L1) - No keyboard navigation support. Users should be able to navigate menu items with arrow keys and close with Escape key.
24 |
25 | **Low Priority:**
26 | - [src/components/Layout/TopNav/TopNav.tsx:1](https://github.com/reactjs/react.dev/blob/main/src/components/Layout/TopNav/TopNav.tsx#L1) - The modification to existing TopNav component may affect existing functionality. Ensure backward compatibility is maintained.
27 |
28 | ### Summary
29 |
30 | This PR adds a branding context menu to the top navigation, introducing:
31 | - A new `BrandMenu` component with dropdown functionality
32 | - Brand assets (logos and wordmarks) in both light and dark variants
33 | - Integration with the existing `TopNav` component
34 | - Addition of a new dependency in package.json
35 |
36 | The implementation appears to be a self-contained feature addition that provides users with access to React branding materials through a dropdown menu in the navigation bar.
37 |
38 | ### Recommendations
39 |
40 | **Accessibility Improvements:**
41 | ```tsx
42 | // Add proper ARIA attributes to the menu button
43 |