codebase-brief 0.1.2__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.4
4
+
5
+ - Refresh the package listing with the current first-run instructions, product fit, limitations, and importer-aware `--base` behavior.
6
+ - Link package metadata to the project site and keep source-code and issue links explicit.
7
+
8
+ ## 0.1.3
9
+
10
+ - Find task-matching snippets deeper inside selected source files and show their line ranges instead of always starting at the file's beginning.
11
+ - Keep excerpt reads bounded and apply the existing secret redaction before including source snippets.
12
+
3
13
  ## 0.1.2
4
14
 
5
15
  - Add `brief --demo`, which generates a real example brief from temporary sample files without reading or modifying the user's project.
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codebase-brief
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Local-first CLI that builds task-focused context briefs from code repositories
5
5
  Author: Mohamed Maggy
6
6
  License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/mohamed1111111m/codebase-brief
7
+ Project-URL: Homepage, https://mohamed1111111m.github.io/codebase-brief/
8
8
  Project-URL: Repository, https://github.com/mohamed1111111m/codebase-brief
9
9
  Project-URL: Issues, https://github.com/mohamed1111111m/codebase-brief/issues
10
10
  Keywords: developer-tools,codebase,context,cli
@@ -33,11 +33,13 @@ Dynamic: license-file
33
33
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
34
34
  [![MIT License](https://img.shields.io/badge/license-MIT-8A63D2.svg)](LICENSE)
35
35
 
36
- **Browser-based coding chats cannot see your local repo.** Codebase Brief turns one coding task into a short, reviewable file shortlist—with excerpts, reasons, and source paths—so you can give ChatGPT, Claude, or another chat the project context it cannot inspect itself.
36
+ **Need a reviewed, task-specific handoff for a coding chat?** Codebase Brief turns one coding task into a short file shortlist—with excerpts, reasons, and source paths—when your assistant cannot access the project directly or you want to choose exactly what context to share.
37
37
 
38
- It works locally, without an AI service or account. Review the brief, save it, or paste it into ChatGPT, Claude, or another assistant that cannot inspect your local working tree.
38
+ It works locally, without an AI service or account. Review the brief, save it, or paste it into the assistant you want to use.
39
39
 
40
- **Best fit:** a browser chat that cannot inspect your local files, or a task where you want to choose exactly what context to share. If your coding agent already reads and indexes the working tree, its built-in repo tools may be enough.
40
+ ## When Codebase Brief fits
41
+
42
+ It is most useful when your chat cannot access the current local project, or when you want a small, reviewable handoff instead of giving an assistant broad repo access. Some tools now offer local-folder or GitHub-repository access—for example, [ChatGPT Work and Codex](https://help.openai.com/en/articles/20001275), [Claude's local and GitHub connections](https://support.anthropic.com/en/articles/11725091-when-to-use-desktop-and-web-connectors), and [Gemini's GitHub import](https://support.google.com/gemini/answer/16176929). Availability depends on the tool, plan, and setup. If your assistant can already read the current working tree and do the task safely, its built-in repo access may be simpler; you may not need Codebase Brief.
41
43
 
42
44
  ## See it in action
43
45
 
@@ -53,7 +55,7 @@ The first image is a terminal-style rendering of the app's actual numbered menu.
53
55
 
54
56
  You need Python 3.10 or newer. Git is optional, but required for recent-history and base-diff details.
55
57
 
56
- The current PyPI release is `0.1.2` and includes the review-feedback summary, importer-aware `--base` selection, and a sample demo. Install it with `pipx`:
58
+ The current PyPI package includes the review-feedback summary, importer-aware `--base` selection, and a sample demo. Install it with `pipx`:
57
59
 
58
60
  ```powershell
59
61
  pipx install codebase-brief
@@ -90,6 +92,8 @@ When the menu opens, it uses the folder you launched it from as the starting pro
90
92
 
91
93
  In plain terms, Codebase Brief makes a small guide to a project so an AI coding assistant can get oriented before helping with a task. It does not write or fix code. It reads project information locally and prepares a guide for you to review and share.
92
94
 
95
+ For selected source files, it looks for code near words in your task and labels each excerpt with its source line range. This is a bounded, best-effort search: if it finds no clear match, it falls back to a general excerpt. Check the cited lines in your editor before relying on them.
96
+
93
97
  Before generating the brief, the tool shows suggested files and why they were selected. Press Enter to keep the checked files, type file numbers to toggle selections, or use `add path/to/file.py` to include another safe text file from the repository. Type `none` for an overview without source excerpts. After the brief is shown, saved, or copied, Codebase Brief prints a copyable summary of files kept, removed, added from suggestions, and manually added. To help improve file selection, paste that summary into the [tester feedback form](https://github.com/mohamed1111111m/codebase-brief/issues/new?template=tester-feedback.yml) along with your task and whether the brief helped. Do not include private source code or secrets. The menu's save-here choice writes `context.md` in the folder where you launched the menu; if that is the target repository, the file will be created there. Choose the show or copy option to avoid writing a file into that folder.
94
98
 
95
99
  For your first try, choose a project you know and a task you understand. Check whether the suggested files are the ones you would have shown a coding assistant yourself.
@@ -8,11 +8,13 @@
8
8
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
9
9
  [![MIT License](https://img.shields.io/badge/license-MIT-8A63D2.svg)](LICENSE)
10
10
 
11
- **Browser-based coding chats cannot see your local repo.** Codebase Brief turns one coding task into a short, reviewable file shortlist—with excerpts, reasons, and source paths—so you can give ChatGPT, Claude, or another chat the project context it cannot inspect itself.
11
+ **Need a reviewed, task-specific handoff for a coding chat?** Codebase Brief turns one coding task into a short file shortlist—with excerpts, reasons, and source paths—when your assistant cannot access the project directly or you want to choose exactly what context to share.
12
12
 
13
- It works locally, without an AI service or account. Review the brief, save it, or paste it into ChatGPT, Claude, or another assistant that cannot inspect your local working tree.
13
+ It works locally, without an AI service or account. Review the brief, save it, or paste it into the assistant you want to use.
14
14
 
15
- **Best fit:** a browser chat that cannot inspect your local files, or a task where you want to choose exactly what context to share. If your coding agent already reads and indexes the working tree, its built-in repo tools may be enough.
15
+ ## When Codebase Brief fits
16
+
17
+ It is most useful when your chat cannot access the current local project, or when you want a small, reviewable handoff instead of giving an assistant broad repo access. Some tools now offer local-folder or GitHub-repository access—for example, [ChatGPT Work and Codex](https://help.openai.com/en/articles/20001275), [Claude's local and GitHub connections](https://support.anthropic.com/en/articles/11725091-when-to-use-desktop-and-web-connectors), and [Gemini's GitHub import](https://support.google.com/gemini/answer/16176929). Availability depends on the tool, plan, and setup. If your assistant can already read the current working tree and do the task safely, its built-in repo access may be simpler; you may not need Codebase Brief.
16
18
 
17
19
  ## See it in action
18
20
 
@@ -28,7 +30,7 @@ The first image is a terminal-style rendering of the app's actual numbered menu.
28
30
 
29
31
  You need Python 3.10 or newer. Git is optional, but required for recent-history and base-diff details.
30
32
 
31
- The current PyPI release is `0.1.2` and includes the review-feedback summary, importer-aware `--base` selection, and a sample demo. Install it with `pipx`:
33
+ The current PyPI package includes the review-feedback summary, importer-aware `--base` selection, and a sample demo. Install it with `pipx`:
32
34
 
33
35
  ```powershell
34
36
  pipx install codebase-brief
@@ -65,6 +67,8 @@ When the menu opens, it uses the folder you launched it from as the starting pro
65
67
 
66
68
  In plain terms, Codebase Brief makes a small guide to a project so an AI coding assistant can get oriented before helping with a task. It does not write or fix code. It reads project information locally and prepares a guide for you to review and share.
67
69
 
70
+ For selected source files, it looks for code near words in your task and labels each excerpt with its source line range. This is a bounded, best-effort search: if it finds no clear match, it falls back to a general excerpt. Check the cited lines in your editor before relying on them.
71
+
68
72
  Before generating the brief, the tool shows suggested files and why they were selected. Press Enter to keep the checked files, type file numbers to toggle selections, or use `add path/to/file.py` to include another safe text file from the repository. Type `none` for an overview without source excerpts. After the brief is shown, saved, or copied, Codebase Brief prints a copyable summary of files kept, removed, added from suggestions, and manually added. To help improve file selection, paste that summary into the [tester feedback form](https://github.com/mohamed1111111m/codebase-brief/issues/new?template=tester-feedback.yml) along with your task and whether the brief helped. Do not include private source code or secrets. The menu's save-here choice writes `context.md` in the folder where you launched the menu; if that is the target repository, the file will be created there. Choose the show or copy option to avoid writing a file into that folder.
69
73
 
70
74
  For your first try, choose a project you know and a task you understand. Check whether the suggested files are the ones you would have shown a coding assistant yourself.
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codebase-brief
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Local-first CLI that builds task-focused context briefs from code repositories
5
5
  Author: Mohamed Maggy
6
6
  License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/mohamed1111111m/codebase-brief
7
+ Project-URL: Homepage, https://mohamed1111111m.github.io/codebase-brief/
8
8
  Project-URL: Repository, https://github.com/mohamed1111111m/codebase-brief
9
9
  Project-URL: Issues, https://github.com/mohamed1111111m/codebase-brief/issues
10
10
  Keywords: developer-tools,codebase,context,cli
@@ -33,11 +33,13 @@ Dynamic: license-file
33
33
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
34
34
  [![MIT License](https://img.shields.io/badge/license-MIT-8A63D2.svg)](LICENSE)
35
35
 
36
- **Browser-based coding chats cannot see your local repo.** Codebase Brief turns one coding task into a short, reviewable file shortlist—with excerpts, reasons, and source paths—so you can give ChatGPT, Claude, or another chat the project context it cannot inspect itself.
36
+ **Need a reviewed, task-specific handoff for a coding chat?** Codebase Brief turns one coding task into a short file shortlist—with excerpts, reasons, and source paths—when your assistant cannot access the project directly or you want to choose exactly what context to share.
37
37
 
38
- It works locally, without an AI service or account. Review the brief, save it, or paste it into ChatGPT, Claude, or another assistant that cannot inspect your local working tree.
38
+ It works locally, without an AI service or account. Review the brief, save it, or paste it into the assistant you want to use.
39
39
 
40
- **Best fit:** a browser chat that cannot inspect your local files, or a task where you want to choose exactly what context to share. If your coding agent already reads and indexes the working tree, its built-in repo tools may be enough.
40
+ ## When Codebase Brief fits
41
+
42
+ It is most useful when your chat cannot access the current local project, or when you want a small, reviewable handoff instead of giving an assistant broad repo access. Some tools now offer local-folder or GitHub-repository access—for example, [ChatGPT Work and Codex](https://help.openai.com/en/articles/20001275), [Claude's local and GitHub connections](https://support.anthropic.com/en/articles/11725091-when-to-use-desktop-and-web-connectors), and [Gemini's GitHub import](https://support.google.com/gemini/answer/16176929). Availability depends on the tool, plan, and setup. If your assistant can already read the current working tree and do the task safely, its built-in repo access may be simpler; you may not need Codebase Brief.
41
43
 
42
44
  ## See it in action
43
45
 
@@ -53,7 +55,7 @@ The first image is a terminal-style rendering of the app's actual numbered menu.
53
55
 
54
56
  You need Python 3.10 or newer. Git is optional, but required for recent-history and base-diff details.
55
57
 
56
- The current PyPI release is `0.1.2` and includes the review-feedback summary, importer-aware `--base` selection, and a sample demo. Install it with `pipx`:
58
+ The current PyPI package includes the review-feedback summary, importer-aware `--base` selection, and a sample demo. Install it with `pipx`:
57
59
 
58
60
  ```powershell
59
61
  pipx install codebase-brief
@@ -90,6 +92,8 @@ When the menu opens, it uses the folder you launched it from as the starting pro
90
92
 
91
93
  In plain terms, Codebase Brief makes a small guide to a project so an AI coding assistant can get oriented before helping with a task. It does not write or fix code. It reads project information locally and prepares a guide for you to review and share.
92
94
 
95
+ For selected source files, it looks for code near words in your task and labels each excerpt with its source line range. This is a bounded, best-effort search: if it finds no clear match, it falls back to a general excerpt. Check the cited lines in your editor before relying on them.
96
+
93
97
  Before generating the brief, the tool shows suggested files and why they were selected. Press Enter to keep the checked files, type file numbers to toggle selections, or use `add path/to/file.py` to include another safe text file from the repository. Type `none` for an overview without source excerpts. After the brief is shown, saved, or copied, Codebase Brief prints a copyable summary of files kept, removed, added from suggestions, and manually added. To help improve file selection, paste that summary into the [tester feedback form](https://github.com/mohamed1111111m/codebase-brief/issues/new?template=tester-feedback.yml) along with your task and whether the brief helped. Do not include private source code or secrets. The menu's save-here choice writes `context.md` in the folder where you launched the menu; if that is the target repository, the file will be created there. Choose the show or copy option to avoid writing a file into that folder.
94
98
 
95
99
  For your first try, choose a project you know and a task you understand. Check whether the suggested files are the ones you would have shown a coding assistant yourself.
@@ -24,7 +24,7 @@ MAX_KEY_FILES = 12
24
24
  MAX_SELECTION_CHOICES = 30
25
25
  MAX_DISCOVERED_FILES = 20_000
26
26
  IMPORT_SUFFIXES = {".py", ".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"}
27
- VERSION = "0.1.2"
27
+ VERSION = "0.1.4"
28
28
  MANIFESTS = (
29
29
  "package.json", "pyproject.toml", "requirements.txt", "Cargo.toml",
30
30
  "go.mod", "Gemfile", "composer.json", "pom.xml",
@@ -203,6 +203,103 @@ def task_words(task: str) -> set[str]:
203
203
  return {word.lower() for word in re.findall(r"[A-Za-z][A-Za-z0-9_-]{2,}", task)}
204
204
 
205
205
 
206
+ _TASK_STOP_WORDS = {
207
+ "about", "after", "also", "and", "are", "does", "from", "give", "help",
208
+ "how", "into", "its", "make", "show", "that", "the", "this", "what", "with",
209
+ }
210
+
211
+
212
+ def read_task_excerpt(
213
+ root: Path, relative: str, task: str, limit: int = 1050,
214
+ max_bytes: int = 96_000,
215
+ ) -> str | None:
216
+ """Find compact, task-related source windows, including later definitions.
217
+
218
+ File ranking alone is not enough: returning only the first lines of a large
219
+ file can omit the function that made it relevant. Reads remain bounded and
220
+ pass through the same path and secret safeguards as ordinary excerpts.
221
+ """
222
+ path = safe_path(root, relative)
223
+ if path is None:
224
+ return None
225
+ try:
226
+ with path.open("rb") as source:
227
+ raw = source.read(max_bytes + 1)
228
+ except OSError:
229
+ return None
230
+ if b"\0" in raw[:4096]:
231
+ return None
232
+
233
+ truncated = len(raw) > max_bytes
234
+ text = raw[:max_bytes].decode("utf-8", errors="replace")
235
+ all_lines = text.splitlines()
236
+ if not all_lines:
237
+ return None
238
+ lines = [line[:500] for line in all_lines[:1500]]
239
+ truncated = truncated or len(all_lines) > len(lines) or any(len(line) > 500 for line in all_lines[:1500])
240
+ terms = {term for term in task_words(task) if term not in _TASK_STOP_WORDS}
241
+ # Split snake_case and hyphenated identifiers so "demo" can match
242
+ # generate_demo_brief without requiring an exact function-name query.
243
+ tokenized_lines = [
244
+ {part.lower() for part in re.findall(r"[A-Za-z][A-Za-z0-9]*", line)}
245
+ for line in lines
246
+ ]
247
+ frequencies = {
248
+ term: sum(term in line_terms for line_terms in tokenized_lines)
249
+ for term in terms
250
+ }
251
+ scores: list[float] = []
252
+ for line_terms in tokenized_lines:
253
+ scores.append(sum(
254
+ 1 + math.log((len(lines) + 1) / (frequencies[term] + 1))
255
+ for term in terms if term in line_terms
256
+ ))
257
+ for index, line in enumerate(lines):
258
+ if scores[index] and re.match(r"\s*(?:async\s+)?(?:def|class)\s+", line):
259
+ # In source files, a matching function/class declaration is a
260
+ # stronger anchor than a help string that merely mentions the task.
261
+ scores[index] += 8
262
+
263
+ if not any(scores):
264
+ return compact(redact("\n".join(lines)), limit)
265
+
266
+ # Make short windows around the strongest matching lines. Merge overlaps,
267
+ # then take the best windows until the excerpt budget is used.
268
+ candidates = sorted(range(len(lines)), key=lambda index: (-scores[index], index))
269
+ windows: list[tuple[int, int]] = []
270
+ for index in candidates:
271
+ if scores[index] == 0:
272
+ break
273
+ start, end = max(0, index - 4), min(len(lines), index + 11)
274
+ if any(start <= old_end and end >= old_start for old_start, old_end in windows):
275
+ continue
276
+ windows.append((start, end))
277
+ selected: list[tuple[int, int, str]] = []
278
+ used = 0
279
+ for start, end in windows:
280
+ body = "\n".join(lines[start:end]).strip()
281
+ snippet = f"Lines {start + 1}–{end}:\n{body}"
282
+ if not body:
283
+ continue
284
+ remaining = limit - used
285
+ if remaining <= 0:
286
+ break
287
+ if len(snippet) > remaining:
288
+ break
289
+ selected.append((start, end, snippet))
290
+ used += len(snippet) + 2
291
+ if not selected:
292
+ return compact("\n".join(lines), limit)
293
+
294
+ selected.sort(key=lambda item: item[0])
295
+ result = "\n…\n".join(snippet for _start, _end, snippet in selected)
296
+ if truncated:
297
+ result += "\nMore of this file was left out to keep the brief short."
298
+ elif len(selected) < len(windows):
299
+ result += "\nOther matching sections were left out to keep the brief short."
300
+ return redact(result)
301
+
302
+
206
303
  def discover_files(root: Path) -> list[str]:
207
304
  found: list[str] = []
208
305
  visited_dirs = 0
@@ -816,12 +913,14 @@ def gather(
816
913
  if label and label != "additional project file":
817
914
  key.append(f"{relative} is already included above; it was also {label}.")
818
915
  continue
819
- excerpt = read_excerpt(root, relative)
916
+ excerpt = read_task_excerpt(root, relative, task)
917
+ if excerpt is None:
918
+ fallback = read_excerpt(root, relative)
919
+ excerpt = fallback[0] if fallback else None
820
920
  if excerpt:
821
- content, truncated = excerpt
822
- content = compact(content, 1050)
921
+ content = compact(excerpt, 1050)
823
922
  label = reasons.get(relative, "selected by project signals")
824
- shortened_note = "" if "Some lines were left out" in content else ("\nMore of this file was left out to keep the brief short." if truncated else "")
923
+ shortened_note = "" if "Some lines were left out" in content or "More of this file was left out" in content else ""
825
924
  key.append(f"{relative} — {label}\n{excerpt_for_brief(relative, content)}" + shortened_note)
826
925
  if not key:
827
926
  if selected_files is not None and not key_files:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codebase-brief"
7
- version = "0.1.2"
7
+ version = "0.1.4"
8
8
  description = "Local-first CLI that builds task-focused context briefs from code repositories"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -27,7 +27,7 @@ classifiers = [
27
27
  ]
28
28
 
29
29
  [project.urls]
30
- Homepage = "https://github.com/mohamed1111111m/codebase-brief"
30
+ Homepage = "https://mohamed1111111m.github.io/codebase-brief/"
31
31
  Repository = "https://github.com/mohamed1111111m/codebase-brief"
32
32
  Issues = "https://github.com/mohamed1111111m/codebase-brief/issues"
33
33
 
@@ -6,7 +6,7 @@ import unittest
6
6
  from pathlib import Path
7
7
  from unittest.mock import patch
8
8
 
9
- from context_inject.cli import DEFAULT_BUDGET_TOKENS, MAX_CHARS, MAX_FILE_BYTES, MAX_KEY_FILES, choose_files, compact, copy_to_clipboard, gather, interactive, local_imports, main, read_excerpt, redact, review_feedback, safe_path, suggest_file_details, suggest_files
9
+ from context_inject.cli import DEFAULT_BUDGET_TOKENS, MAX_CHARS, MAX_FILE_BYTES, MAX_KEY_FILES, VERSION, choose_files, compact, copy_to_clipboard, gather, interactive, local_imports, main, read_excerpt, read_task_excerpt, redact, review_feedback, safe_path, suggest_file_details, suggest_files
10
10
 
11
11
 
12
12
  class ContextInjectTests(unittest.TestCase):
@@ -75,6 +75,21 @@ class ContextInjectTests(unittest.TestCase):
75
75
  self.assertLess(output.index("Files that may help"), output.index("Technology and commands"))
76
76
  self.assertLessEqual(len(output), 1000 * 4)
77
77
 
78
+ def test_task_excerpt_finds_relevant_function_beyond_file_prefix(self):
79
+ filler = "\n".join(f"def unrelated_{index}(): return {index}" for index in range(180))
80
+ source = filler + "\n\ndef build_demo_brief():\n return gather(sample_files, task)\n"
81
+ self.put("src/app.py", source)
82
+
83
+ excerpt = read_task_excerpt(
84
+ self.root, "src/app.py",
85
+ "Explain how the built-in demo creates a sample context brief",
86
+ )
87
+
88
+ self.assertIsNotNone(excerpt)
89
+ self.assertIn("def build_demo_brief", excerpt)
90
+ self.assertIn("return gather(sample_files, task)", excerpt)
91
+ self.assertNotIn("def unrelated_0", excerpt)
92
+
78
93
  def test_excerpt_shortening_stops_on_a_word_boundary(self):
79
94
  excerpt = compact("This is a long sentence that should end on a complete word. " * 3, 90)
80
95
  self.assertTrue(excerpt.startswith("This is a long sentence that should\nSome lines were left out"))
@@ -486,7 +501,7 @@ class ContextInjectTests(unittest.TestCase):
486
501
  plain = __import__("re").sub(r"\x1b\[[0-9;]*m", "", output.getvalue())
487
502
  self.assertIn("CODEBASE", plain)
488
503
  self.assertIn("BRIEF", plain)
489
- self.assertIn("v0.1.2", plain)
504
+ self.assertIn(f"v{VERSION}", plain)
490
505
  self.assertIn("Meet Briefy - your repo guide", plain)
491
506
  self.assertIn("WHAT THIS DOES", plain)
492
507
  self.assertIn("Makes a short guide to your project for an AI coding assistant", plain)
File without changes
File without changes