sampler-cli 0.2.0__tar.gz → 0.2.1__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.
Files changed (42) hide show
  1. sampler_cli-0.2.1/PKG-INFO +182 -0
  2. sampler_cli-0.2.1/README.md +145 -0
  3. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/pyproject.toml +1 -1
  4. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/__init__.py +1 -1
  5. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/cli/main.py +87 -5
  6. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/db.py +30 -0
  7. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/query/engine.py +4 -0
  8. sampler_cli-0.2.1/src/sampler_cli.egg-info/PKG-INFO +182 -0
  9. sampler_cli-0.2.0/PKG-INFO +0 -130
  10. sampler_cli-0.2.0/README.md +0 -93
  11. sampler_cli-0.2.0/src/sampler_cli.egg-info/PKG-INFO +0 -130
  12. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/LICENSE +0 -0
  13. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/setup.cfg +0 -0
  14. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/__main__.py +0 -0
  15. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/cli/__init__.py +0 -0
  16. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/config.py +0 -0
  17. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/__init__.py +0 -0
  18. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/builder.py +0 -0
  19. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/discover.py +0 -0
  20. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/parsers/__init__.py +0 -0
  21. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/parsers/base.py +0 -0
  22. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/parsers/go.py +0 -0
  23. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/parsers/python.py +0 -0
  24. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/parsers/typescript.py +0 -0
  25. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/indexer/store.py +0 -0
  26. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/mcp/__init__.py +0 -0
  27. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/mcp/server.py +0 -0
  28. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/models.py +0 -0
  29. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/query/__init__.py +0 -0
  30. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler/query/semantic.py +0 -0
  31. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler_cli.egg-info/SOURCES.txt +0 -0
  32. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler_cli.egg-info/dependency_links.txt +0 -0
  33. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler_cli.egg-info/entry_points.txt +0 -0
  34. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler_cli.egg-info/requires.txt +0 -0
  35. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/src/sampler_cli.egg-info/top_level.txt +0 -0
  36. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/tests/test_cli.py +0 -0
  37. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/tests/test_config.py +0 -0
  38. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/tests/test_db.py +0 -0
  39. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/tests/test_discover.py +0 -0
  40. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/tests/test_index_query.py +0 -0
  41. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/tests/test_python_parser.py +0 -0
  42. {sampler_cli-0.2.0 → sampler_cli-0.2.1}/tests/test_smoke.py +0 -0
@@ -0,0 +1,182 @@
1
+ Metadata-Version: 2.4
2
+ Name: sampler-cli
3
+ Version: 0.2.1
4
+ Summary: Token-efficient CLI for indexing and searching code symbols (Python-first, designed for minimal LLM/agent context size)
5
+ Author: Samuel Ignacio Carmona Rodriguez
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/sicr0/sampler-cli
8
+ Project-URL: Repository, https://github.com/sicr0/sampler-cli
9
+ Project-URL: Issues, https://github.com/sicr0/sampler-cli/issues
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Classifier: Topic :: Software Development :: Code Generators
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: typer>=0.12.0
21
+ Requires-Dist: rich>=13.7.0
22
+ Requires-Dist: tree-sitter>=0.21.0
23
+ Requires-Dist: tree-sitter-python>=0.23.0
24
+ Requires-Dist: gitignore-parser>=0.1.11
25
+ Requires-Dist: pydantic>=2.6.0
26
+ Requires-Dist: pyyaml>=6.0.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
29
+ Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
30
+ Requires-Dist: ruff>=0.5.0; extra == "dev"
31
+ Requires-Dist: mypy>=1.7.0; extra == "dev"
32
+ Provides-Extra: mcp
33
+ Requires-Dist: fastmcp>=0.1.0; extra == "mcp"
34
+ Provides-Extra: semantic
35
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "semantic"
36
+ Dynamic: license-file
37
+
38
+ # Sampler
39
+
40
+ **Token-efficient CLI for indexing and searching code symbols across multiple projects.**
41
+
42
+ Current version: 0.2.1
43
+
44
+ Designed for humans and LLMs/agents: default outputs are compact, single-line, with short paths and no noisy table formatting.
45
+
46
+ ## Requirements
47
+
48
+ - Python 3.11+
49
+ - (Optional) Go, if you plan to use Go parser support in the future
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ pip install sampler-cli
55
+ ```
56
+
57
+ For development (tests, linters, etc.):
58
+
59
+ ```bash
60
+ pip install -e '.[dev]'
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ```bash
66
+ sampler init
67
+ sampler project add myproj /absolute/path/to/project --language python
68
+ sampler project list
69
+ sampler index myproj
70
+ sampler search add --project myproj
71
+ sampler overview /absolute/path/to/project/some/file.py
72
+ sampler symbols myproj
73
+ ```
74
+
75
+ ## Examples with Output
76
+
77
+ **List projects (compact):**
78
+ ```bash
79
+ $ sampler project list
80
+ myproj /home/user/projects/myproj
81
+ demo ~/work/demo
82
+ ```
83
+
84
+ **Search (default compact, LLM-friendly):**
85
+ ```bash
86
+ $ sampler search worker --project myproj
87
+ myproj:src/tasks/celery_app.py:70 function on_worker_ready def on_worker_ready(sender)
88
+ ```
89
+
90
+ **List all symbols for a project:**
91
+ ```bash
92
+ $ sampler symbols myproj --type function --limit 5
93
+ myproj:src/utils.py:10 function helper def helper(x)
94
+ myproj:src/models.py:25 function validate def validate(data)
95
+ ...
96
+ ```
97
+
98
+ **Overview of a file (supports relative paths):**
99
+ ```bash
100
+ $ sampler overview src/app.py
101
+ 12: function main def main()
102
+ 25: class App class App
103
+ ```
104
+
105
+ If the file has no indexed symbols (or was never indexed):
106
+ ```bash
107
+ $ sampler overview nonexistent.py
108
+ No symbols found for file: nonexistent.py
109
+ Tip: Make sure the project is registered with 'sampler project add' and indexed with 'sampler index <project>'.
110
+ The path must match a file that was indexed (relative paths are resolved to absolute).
111
+ ```
112
+
113
+ ## Why "project add" is required
114
+
115
+ - `sampler project add <name> <path>` registers the project in `~/.sampler/config.yaml`.
116
+ - `index` looks up the project there to know the root path and language.
117
+ - Without it, commands like `index`, `symbols`, and filtered searches will fail with a clear "not found" message and usage hint.
118
+ - The actual symbol data lives in the SQLite DB (`~/.sampler/graph.db`), but registration is the control plane.
119
+
120
+ You can have data in the DB without the config entry (e.g. after `project remove`), but you won't be able to re-index or easily manage it.
121
+
122
+ ## Relative Paths
123
+
124
+ - `overview` now resolves relative paths against the current working directory (e.g. `sampler overview ./src/app.py` or `sampler overview ../other/file.py`).
125
+ - Stored paths are absolute (resolved at index time), so the resolution makes overview work naturally.
126
+ - Other file-based commands behave similarly where applicable.
127
+
128
+ ## Error Messages & Help
129
+
130
+ We try to give actionable errors:
131
+
132
+ - Unknown project → tells you the exact `project add` command to run and suggests `project list`.
133
+ - File with no symbols → clear "No symbols found" + tips.
134
+ - Typer automatically shows command usage and available options on invalid arguments.
135
+
136
+ Run any command with `--help` for full details (e.g. `sampler search --help`, `sampler symbols --help`).
137
+
138
+ ## Current Features
139
+
140
+ - Global config in `~/.sampler/config.yaml`
141
+ - Project management (`add`, `list`, `remove`)
142
+ - Incremental indexing with file hashing (Python AST-based parser)
143
+ - Compact, token-efficient output by default (great for LLMs)
144
+ - Search with type filters and limits
145
+ - `search-all` across every registered project
146
+ - `symbols <project>` to dump/list symbols for a project
147
+ - `overview <file>` (relative paths supported)
148
+ - Basic relationship extraction (CALLS, CONTAINS)
149
+
150
+ ## Stability Note
151
+
152
+ - Python parser uses stdlib `ast` (we switched from tree-sitter-python after native crashes on macOS ARM during real indexing).
153
+ - Go and TypeScript/JavaScript parsers are stubs for now (return no symbols).
154
+
155
+ ## Project Structure
156
+
157
+ ```
158
+ src/sampler/
159
+ ├── cli/main.py # Typer commands (search, overview, symbols, index, project ...)
160
+ ├── config.py # YAML config manager
161
+ ├── db.py # SQLite layer
162
+ ├── indexer/
163
+ │ ├── builder.py
164
+ │ ├── discover.py
165
+ │ ├── store.py
166
+ │ └── parsers/python.py
167
+ └── query/engine.py
168
+ ```
169
+
170
+ ## Running Tests
171
+
172
+ ```bash
173
+ pytest -q
174
+ ```
175
+
176
+ ## Roadmap Highlights (see TODO.md and PLAN.md)
177
+
178
+ - Cross-file relation improvements
179
+ - Better call graph queries (`callers`, `usages`, ...)
180
+ - Real Go / TypeScript parsers
181
+ - Semantic search + MCP server (for agents)
182
+ - More context-generation helpers
@@ -0,0 +1,145 @@
1
+ # Sampler
2
+
3
+ **Token-efficient CLI for indexing and searching code symbols across multiple projects.**
4
+
5
+ Current version: 0.2.1
6
+
7
+ Designed for humans and LLMs/agents: default outputs are compact, single-line, with short paths and no noisy table formatting.
8
+
9
+ ## Requirements
10
+
11
+ - Python 3.11+
12
+ - (Optional) Go, if you plan to use Go parser support in the future
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install sampler-cli
18
+ ```
19
+
20
+ For development (tests, linters, etc.):
21
+
22
+ ```bash
23
+ pip install -e '.[dev]'
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```bash
29
+ sampler init
30
+ sampler project add myproj /absolute/path/to/project --language python
31
+ sampler project list
32
+ sampler index myproj
33
+ sampler search add --project myproj
34
+ sampler overview /absolute/path/to/project/some/file.py
35
+ sampler symbols myproj
36
+ ```
37
+
38
+ ## Examples with Output
39
+
40
+ **List projects (compact):**
41
+ ```bash
42
+ $ sampler project list
43
+ myproj /home/user/projects/myproj
44
+ demo ~/work/demo
45
+ ```
46
+
47
+ **Search (default compact, LLM-friendly):**
48
+ ```bash
49
+ $ sampler search worker --project myproj
50
+ myproj:src/tasks/celery_app.py:70 function on_worker_ready def on_worker_ready(sender)
51
+ ```
52
+
53
+ **List all symbols for a project:**
54
+ ```bash
55
+ $ sampler symbols myproj --type function --limit 5
56
+ myproj:src/utils.py:10 function helper def helper(x)
57
+ myproj:src/models.py:25 function validate def validate(data)
58
+ ...
59
+ ```
60
+
61
+ **Overview of a file (supports relative paths):**
62
+ ```bash
63
+ $ sampler overview src/app.py
64
+ 12: function main def main()
65
+ 25: class App class App
66
+ ```
67
+
68
+ If the file has no indexed symbols (or was never indexed):
69
+ ```bash
70
+ $ sampler overview nonexistent.py
71
+ No symbols found for file: nonexistent.py
72
+ Tip: Make sure the project is registered with 'sampler project add' and indexed with 'sampler index <project>'.
73
+ The path must match a file that was indexed (relative paths are resolved to absolute).
74
+ ```
75
+
76
+ ## Why "project add" is required
77
+
78
+ - `sampler project add <name> <path>` registers the project in `~/.sampler/config.yaml`.
79
+ - `index` looks up the project there to know the root path and language.
80
+ - Without it, commands like `index`, `symbols`, and filtered searches will fail with a clear "not found" message and usage hint.
81
+ - The actual symbol data lives in the SQLite DB (`~/.sampler/graph.db`), but registration is the control plane.
82
+
83
+ You can have data in the DB without the config entry (e.g. after `project remove`), but you won't be able to re-index or easily manage it.
84
+
85
+ ## Relative Paths
86
+
87
+ - `overview` now resolves relative paths against the current working directory (e.g. `sampler overview ./src/app.py` or `sampler overview ../other/file.py`).
88
+ - Stored paths are absolute (resolved at index time), so the resolution makes overview work naturally.
89
+ - Other file-based commands behave similarly where applicable.
90
+
91
+ ## Error Messages & Help
92
+
93
+ We try to give actionable errors:
94
+
95
+ - Unknown project → tells you the exact `project add` command to run and suggests `project list`.
96
+ - File with no symbols → clear "No symbols found" + tips.
97
+ - Typer automatically shows command usage and available options on invalid arguments.
98
+
99
+ Run any command with `--help` for full details (e.g. `sampler search --help`, `sampler symbols --help`).
100
+
101
+ ## Current Features
102
+
103
+ - Global config in `~/.sampler/config.yaml`
104
+ - Project management (`add`, `list`, `remove`)
105
+ - Incremental indexing with file hashing (Python AST-based parser)
106
+ - Compact, token-efficient output by default (great for LLMs)
107
+ - Search with type filters and limits
108
+ - `search-all` across every registered project
109
+ - `symbols <project>` to dump/list symbols for a project
110
+ - `overview <file>` (relative paths supported)
111
+ - Basic relationship extraction (CALLS, CONTAINS)
112
+
113
+ ## Stability Note
114
+
115
+ - Python parser uses stdlib `ast` (we switched from tree-sitter-python after native crashes on macOS ARM during real indexing).
116
+ - Go and TypeScript/JavaScript parsers are stubs for now (return no symbols).
117
+
118
+ ## Project Structure
119
+
120
+ ```
121
+ src/sampler/
122
+ ├── cli/main.py # Typer commands (search, overview, symbols, index, project ...)
123
+ ├── config.py # YAML config manager
124
+ ├── db.py # SQLite layer
125
+ ├── indexer/
126
+ │ ├── builder.py
127
+ │ ├── discover.py
128
+ │ ├── store.py
129
+ │ └── parsers/python.py
130
+ └── query/engine.py
131
+ ```
132
+
133
+ ## Running Tests
134
+
135
+ ```bash
136
+ pytest -q
137
+ ```
138
+
139
+ ## Roadmap Highlights (see TODO.md and PLAN.md)
140
+
141
+ - Cross-file relation improvements
142
+ - Better call graph queries (`callers`, `usages`, ...)
143
+ - Real Go / TypeScript parsers
144
+ - Semantic search + MCP server (for agents)
145
+ - More context-generation helpers
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sampler-cli"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  description = "Token-efficient CLI for indexing and searching code symbols (Python-first, designed for minimal LLM/agent context size)"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -1,3 +1,3 @@
1
1
  __all__ = ["__version__"]
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.2.1"
@@ -9,7 +9,7 @@ from sampler.db import Database
9
9
  from sampler.indexer.builder import IndexBuilder
10
10
  from sampler.query.engine import QueryEngine
11
11
 
12
- app = typer.Typer(help="Sampler CLI")
12
+ app = typer.Typer(help="Sampler CLI", no_args_is_help=True)
13
13
  project_app = typer.Typer(help="Project management commands")
14
14
  app.add_typer(project_app, name="project")
15
15
  console = Console()
@@ -93,7 +93,7 @@ def project_add(name: str, path: str, language: str = "python") -> None:
93
93
  try:
94
94
  project = config.add_project(name=name, path=path, language=language)
95
95
  except ValueError as exc:
96
- raise typer.BadParameter(str(exc)) from exc
96
+ raise typer.BadParameter(f"{exc}\nTip: Use an absolute path that exists.") from exc
97
97
  console.print(f"Added project [bold]{project.name}[/bold]")
98
98
 
99
99
 
@@ -147,13 +147,57 @@ def search_all(
147
147
  search(query=query, project=None, type=type, limit=limit)
148
148
 
149
149
 
150
+ @app.command("symbols")
151
+ def symbols(
152
+ project: str,
153
+ type: str | None = typer.Option(None, "--type", "-t", help="filter e.g. function,class"),
154
+ limit: int = typer.Option(100, "--limit", "-l"),
155
+ ) -> None:
156
+ """List all symbols for a project (useful for getting a quick overview)."""
157
+ config = ConfigManager()
158
+ if config.get_project(project) is None:
159
+ raise typer.BadParameter(
160
+ f"Project '{project}' not found.\n"
161
+ f"Run: sampler project add {project} <absolute/path> --language python\n"
162
+ "Use 'sampler project list' to see registered projects."
163
+ )
164
+
165
+ engine = QueryEngine(db=_database())
166
+ types = [x.strip() for x in type.split(",")] if type else None
167
+ if types:
168
+ exp = set(types)
169
+ for t in list(types):
170
+ if t == "function":
171
+ exp.add("async function")
172
+ elif t == "method":
173
+ exp.add("async method")
174
+ types = list(exp)
175
+
176
+ rows = engine.list_symbols(project_name=project, types=types, limit=limit)
177
+ roots = _get_project_roots()
178
+
179
+ for r in rows:
180
+ shortf = _short_path(r["project_name"], r["file_path"], roots)
181
+ name = r["qualified_name"] or r["name"]
182
+ sig = r.get("signature") or ""
183
+ line = f"{r['project_name']}:{shortf}:{r['start_line'] or '-'} {r['type']} {name}"
184
+ if sig:
185
+ line += f" {sig}"
186
+ console.print(line)
187
+
188
+
150
189
  @app.command("index")
151
190
  def index(project: str) -> None:
152
191
  """Index selected project."""
153
192
  config = ConfigManager()
154
193
  project_cfg = config.get_project(project)
155
194
  if project_cfg is None:
156
- raise typer.BadParameter(f"Project '{project}' not found. Use 'sampler project list'.")
195
+ raise typer.BadParameter(
196
+ f"Project '{project}' not found.\n"
197
+ f"Run: sampler project add {project} <absolute/path> --language python\n"
198
+ "Then: sampler index {project}\n"
199
+ "Use 'sampler project list' to see registered projects."
200
+ )
157
201
 
158
202
  builder = IndexBuilder(db=_database())
159
203
  stats = builder.index_project(
@@ -170,9 +214,47 @@ def index(project: str) -> None:
170
214
 
171
215
  @app.command("overview")
172
216
  def overview(filepath: str) -> None:
173
- """Show symbols for file."""
217
+ """Show symbols for a file.
218
+
219
+ Supports absolute and relative paths.
220
+ Relative paths are first resolved from cwd; if nothing matches we also try
221
+ resolving relative to each registered project's root (very convenient).
222
+ """
223
+ config = ConfigManager()
224
+ projects = config.list_projects()
225
+
226
+ candidates = []
227
+ try:
228
+ candidates.append(str(Path(filepath).resolve()))
229
+ except Exception:
230
+ candidates.append(filepath)
231
+
232
+ # Try resolving relative to each project root (helps when you're inside the project)
233
+ for p in projects:
234
+ try:
235
+ root = Path(p.path).resolve()
236
+ rel = root / filepath
237
+ candidates.append(str(rel.resolve()))
238
+ except Exception:
239
+ pass
240
+
241
+ # Dedup while preserving order
242
+ seen = set()
243
+ candidates = [c for c in candidates if not (c in seen or seen.add(c))]
244
+
174
245
  engine = QueryEngine(db=_database())
175
- rows = engine.overview(filepath=filepath)
246
+ rows = []
247
+ matched_path = None
248
+ for cand in candidates:
249
+ rows = engine.overview(filepath=cand)
250
+ if rows:
251
+ matched_path = cand
252
+ break
253
+
254
+ if not rows:
255
+ console.print(f"No symbols found for file: {filepath}")
256
+ console.print("Tip: Make sure the project is registered with 'sampler project add' and indexed with 'sampler index <project>'.")
257
+ return
176
258
 
177
259
  for r in rows:
178
260
  name = r["qualified_name"] or r["name"]
@@ -314,3 +314,33 @@ class Database:
314
314
  """,
315
315
  params,
316
316
  ).fetchall()
317
+
318
+ def list_symbols(self, project_name: str, types: list[str] | None = None, limit: int | None = None, offset: int = 0) -> list[sqlite3.Row]:
319
+ where = "WHERE p.name = ?"
320
+ params: list = [project_name]
321
+ if types:
322
+ ph = ",".join("?" * len(types))
323
+ where += f" AND s.type IN ({ph})"
324
+ params.extend(types)
325
+
326
+ sql = f"""
327
+ SELECT
328
+ s.type,
329
+ s.name,
330
+ s.qualified_name,
331
+ s.signature,
332
+ s.start_line,
333
+ f.path AS file_path,
334
+ p.name AS project_name
335
+ FROM symbols s
336
+ JOIN files f ON s.file_id = f.id
337
+ JOIN projects p ON f.project_id = p.id
338
+ {where}
339
+ ORDER BY f.path, s.start_line
340
+ """
341
+ if limit is not None:
342
+ sql += " LIMIT ? OFFSET ?"
343
+ params.extend([limit, offset])
344
+
345
+ with self.connect() as conn:
346
+ return conn.execute(sql, params).fetchall()
@@ -14,3 +14,7 @@ class QueryEngine:
14
14
  def overview(self, filepath: str, project_name: str | None = None) -> list[dict]:
15
15
  rows = self.db.get_symbols_by_filepath(filepath=filepath, project_name=project_name)
16
16
  return [dict(row) for row in rows]
17
+
18
+ def list_symbols(self, project_name: str, types: list[str] | None = None, limit: int | None = None, offset: int = 0) -> list[dict]:
19
+ rows = self.db.list_symbols(project_name=project_name, types=types, limit=limit, offset=offset)
20
+ return [dict(row) for row in rows]
@@ -0,0 +1,182 @@
1
+ Metadata-Version: 2.4
2
+ Name: sampler-cli
3
+ Version: 0.2.1
4
+ Summary: Token-efficient CLI for indexing and searching code symbols (Python-first, designed for minimal LLM/agent context size)
5
+ Author: Samuel Ignacio Carmona Rodriguez
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/sicr0/sampler-cli
8
+ Project-URL: Repository, https://github.com/sicr0/sampler-cli
9
+ Project-URL: Issues, https://github.com/sicr0/sampler-cli/issues
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Classifier: Topic :: Software Development :: Code Generators
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: typer>=0.12.0
21
+ Requires-Dist: rich>=13.7.0
22
+ Requires-Dist: tree-sitter>=0.21.0
23
+ Requires-Dist: tree-sitter-python>=0.23.0
24
+ Requires-Dist: gitignore-parser>=0.1.11
25
+ Requires-Dist: pydantic>=2.6.0
26
+ Requires-Dist: pyyaml>=6.0.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
29
+ Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
30
+ Requires-Dist: ruff>=0.5.0; extra == "dev"
31
+ Requires-Dist: mypy>=1.7.0; extra == "dev"
32
+ Provides-Extra: mcp
33
+ Requires-Dist: fastmcp>=0.1.0; extra == "mcp"
34
+ Provides-Extra: semantic
35
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "semantic"
36
+ Dynamic: license-file
37
+
38
+ # Sampler
39
+
40
+ **Token-efficient CLI for indexing and searching code symbols across multiple projects.**
41
+
42
+ Current version: 0.2.1
43
+
44
+ Designed for humans and LLMs/agents: default outputs are compact, single-line, with short paths and no noisy table formatting.
45
+
46
+ ## Requirements
47
+
48
+ - Python 3.11+
49
+ - (Optional) Go, if you plan to use Go parser support in the future
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ pip install sampler-cli
55
+ ```
56
+
57
+ For development (tests, linters, etc.):
58
+
59
+ ```bash
60
+ pip install -e '.[dev]'
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ```bash
66
+ sampler init
67
+ sampler project add myproj /absolute/path/to/project --language python
68
+ sampler project list
69
+ sampler index myproj
70
+ sampler search add --project myproj
71
+ sampler overview /absolute/path/to/project/some/file.py
72
+ sampler symbols myproj
73
+ ```
74
+
75
+ ## Examples with Output
76
+
77
+ **List projects (compact):**
78
+ ```bash
79
+ $ sampler project list
80
+ myproj /home/user/projects/myproj
81
+ demo ~/work/demo
82
+ ```
83
+
84
+ **Search (default compact, LLM-friendly):**
85
+ ```bash
86
+ $ sampler search worker --project myproj
87
+ myproj:src/tasks/celery_app.py:70 function on_worker_ready def on_worker_ready(sender)
88
+ ```
89
+
90
+ **List all symbols for a project:**
91
+ ```bash
92
+ $ sampler symbols myproj --type function --limit 5
93
+ myproj:src/utils.py:10 function helper def helper(x)
94
+ myproj:src/models.py:25 function validate def validate(data)
95
+ ...
96
+ ```
97
+
98
+ **Overview of a file (supports relative paths):**
99
+ ```bash
100
+ $ sampler overview src/app.py
101
+ 12: function main def main()
102
+ 25: class App class App
103
+ ```
104
+
105
+ If the file has no indexed symbols (or was never indexed):
106
+ ```bash
107
+ $ sampler overview nonexistent.py
108
+ No symbols found for file: nonexistent.py
109
+ Tip: Make sure the project is registered with 'sampler project add' and indexed with 'sampler index <project>'.
110
+ The path must match a file that was indexed (relative paths are resolved to absolute).
111
+ ```
112
+
113
+ ## Why "project add" is required
114
+
115
+ - `sampler project add <name> <path>` registers the project in `~/.sampler/config.yaml`.
116
+ - `index` looks up the project there to know the root path and language.
117
+ - Without it, commands like `index`, `symbols`, and filtered searches will fail with a clear "not found" message and usage hint.
118
+ - The actual symbol data lives in the SQLite DB (`~/.sampler/graph.db`), but registration is the control plane.
119
+
120
+ You can have data in the DB without the config entry (e.g. after `project remove`), but you won't be able to re-index or easily manage it.
121
+
122
+ ## Relative Paths
123
+
124
+ - `overview` now resolves relative paths against the current working directory (e.g. `sampler overview ./src/app.py` or `sampler overview ../other/file.py`).
125
+ - Stored paths are absolute (resolved at index time), so the resolution makes overview work naturally.
126
+ - Other file-based commands behave similarly where applicable.
127
+
128
+ ## Error Messages & Help
129
+
130
+ We try to give actionable errors:
131
+
132
+ - Unknown project → tells you the exact `project add` command to run and suggests `project list`.
133
+ - File with no symbols → clear "No symbols found" + tips.
134
+ - Typer automatically shows command usage and available options on invalid arguments.
135
+
136
+ Run any command with `--help` for full details (e.g. `sampler search --help`, `sampler symbols --help`).
137
+
138
+ ## Current Features
139
+
140
+ - Global config in `~/.sampler/config.yaml`
141
+ - Project management (`add`, `list`, `remove`)
142
+ - Incremental indexing with file hashing (Python AST-based parser)
143
+ - Compact, token-efficient output by default (great for LLMs)
144
+ - Search with type filters and limits
145
+ - `search-all` across every registered project
146
+ - `symbols <project>` to dump/list symbols for a project
147
+ - `overview <file>` (relative paths supported)
148
+ - Basic relationship extraction (CALLS, CONTAINS)
149
+
150
+ ## Stability Note
151
+
152
+ - Python parser uses stdlib `ast` (we switched from tree-sitter-python after native crashes on macOS ARM during real indexing).
153
+ - Go and TypeScript/JavaScript parsers are stubs for now (return no symbols).
154
+
155
+ ## Project Structure
156
+
157
+ ```
158
+ src/sampler/
159
+ ├── cli/main.py # Typer commands (search, overview, symbols, index, project ...)
160
+ ├── config.py # YAML config manager
161
+ ├── db.py # SQLite layer
162
+ ├── indexer/
163
+ │ ├── builder.py
164
+ │ ├── discover.py
165
+ │ ├── store.py
166
+ │ └── parsers/python.py
167
+ └── query/engine.py
168
+ ```
169
+
170
+ ## Running Tests
171
+
172
+ ```bash
173
+ pytest -q
174
+ ```
175
+
176
+ ## Roadmap Highlights (see TODO.md and PLAN.md)
177
+
178
+ - Cross-file relation improvements
179
+ - Better call graph queries (`callers`, `usages`, ...)
180
+ - Real Go / TypeScript parsers
181
+ - Semantic search + MCP server (for agents)
182
+ - More context-generation helpers
@@ -1,130 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: sampler-cli
3
- Version: 0.2.0
4
- Summary: Token-efficient CLI for indexing and searching code symbols (Python-first, designed for minimal LLM/agent context size)
5
- Author: Samuel Ignacio Carmona Rodriguez
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/sicr0/sampler-cli
8
- Project-URL: Repository, https://github.com/sicr0/sampler-cli
9
- Project-URL: Issues, https://github.com/sicr0/sampler-cli/issues
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
- Classifier: Topic :: Software Development :: Code Generators
17
- Requires-Python: >=3.11
18
- Description-Content-Type: text/markdown
19
- License-File: LICENSE
20
- Requires-Dist: typer>=0.12.0
21
- Requires-Dist: rich>=13.7.0
22
- Requires-Dist: tree-sitter>=0.21.0
23
- Requires-Dist: tree-sitter-python>=0.23.0
24
- Requires-Dist: gitignore-parser>=0.1.11
25
- Requires-Dist: pydantic>=2.6.0
26
- Requires-Dist: pyyaml>=6.0.0
27
- Provides-Extra: dev
28
- Requires-Dist: pytest>=7.4.0; extra == "dev"
29
- Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
30
- Requires-Dist: ruff>=0.5.0; extra == "dev"
31
- Requires-Dist: mypy>=1.7.0; extra == "dev"
32
- Provides-Extra: mcp
33
- Requires-Dist: fastmcp>=0.1.0; extra == "mcp"
34
- Provides-Extra: semantic
35
- Requires-Dist: sentence-transformers>=2.2.0; extra == "semantic"
36
- Dynamic: license-file
37
-
38
- # Sampler
39
-
40
- CLI indexer para navegar símbolos y relaciones en codebases multiproyecto.
41
-
42
- Versión actual: 0.1.2
43
-
44
- ## Requisitos
45
-
46
- - Python 3.11+
47
- - `uv` (recomendado)
48
- - Go (instalado para soporte parser Fase 1)
49
-
50
- ## Instalación de Go (macOS)
51
-
52
- ```bash
53
- brew install go
54
- go version
55
- ```
56
-
57
- ## Instalación
58
-
59
- ```bash
60
- pip install sampler-cli
61
- ```
62
-
63
- Para desarrollo (incluye tests, linters):
64
-
65
- ```bash
66
- pip install -e '.[dev]'
67
- ```
68
-
69
- ## Uso rápido
70
-
71
- ```bash
72
- pip install sampler-cli
73
- sampler init
74
- sampler project add myproj /absolute/path --language python
75
- sampler project list
76
- sampler index myproj
77
- sampler search add --project myproj
78
- sampler overview /absolute/path/file.py
79
- ```
80
-
81
- **Demo / LLM use (token-efficient by design):**
82
- - Default outputs are compact single-line (no tables, short paths, no noise).
83
- - Ideal for pasting into agents/LLMs with minimal context size.
84
- - Example: `sampler search worker --project myproj` → `myproj:src/tasks.py:42 function process def process()`
85
-
86
- ## Estado actual
87
-
88
- Implementado:
89
-
90
- - Bootstrap inicial de Fase 0
91
- - Configuración global con archivo `~/.sampler/config.yaml`
92
- - CRUD de proyectos en config (`add`, `list`, `remove`)
93
- - Esquema SQLite core + queries de index/search en `src/sampler/db.py`
94
- - Discovery de archivos por lenguaje con soporte `.gitignore`
95
- - Parser Python estable basado en AST
96
- - Indexer real (hash incremental + persistencia)
97
- - Query engine real (`search`, `overview`)
98
- - CI básico con GitHub Actions (`pytest -q`)
99
- - Tests: smoke, config, db, cli, discovery, python_parser, index_query
100
-
101
- Nota de estabilidad:
102
-
103
- - Se desactivó uso runtime de tree-sitter en parser Python por crash nativo (`BUS/SEGV`) en indexación real.
104
- - Se mantiene estrategia AST para estabilidad en producción local.
105
-
106
- Pendiente inmediato:
107
-
108
- - Filtros y paginación en búsqueda
109
- - Comandos `callers`, `usages`, `related`
110
- - Parsers Go y TypeScript/JavaScript
111
-
112
- ## Estructura clave
113
-
114
- ```text
115
- src/sampler/cli/main.py # comandos CLI
116
- src/sampler/config.py # config global YAML
117
- src/sampler/db.py # capa SQLite
118
- src/sampler/indexer/builder.py # indexación de proyectos
119
- src/sampler/indexer/store.py # persistencia de símbolos/relaciones
120
- src/sampler/indexer/parsers/python.py # parser python estable
121
- src/sampler/query/engine.py # search/overview
122
- src/sampler/indexer/discover.py # discovery y filtros
123
- tests/ # pruebas base
124
- ```
125
-
126
- ## Ejecutar pruebas
127
-
128
- ```bash
129
- pytest -q
130
- ```
@@ -1,93 +0,0 @@
1
- # Sampler
2
-
3
- CLI indexer para navegar símbolos y relaciones en codebases multiproyecto.
4
-
5
- Versión actual: 0.1.2
6
-
7
- ## Requisitos
8
-
9
- - Python 3.11+
10
- - `uv` (recomendado)
11
- - Go (instalado para soporte parser Fase 1)
12
-
13
- ## Instalación de Go (macOS)
14
-
15
- ```bash
16
- brew install go
17
- go version
18
- ```
19
-
20
- ## Instalación
21
-
22
- ```bash
23
- pip install sampler-cli
24
- ```
25
-
26
- Para desarrollo (incluye tests, linters):
27
-
28
- ```bash
29
- pip install -e '.[dev]'
30
- ```
31
-
32
- ## Uso rápido
33
-
34
- ```bash
35
- pip install sampler-cli
36
- sampler init
37
- sampler project add myproj /absolute/path --language python
38
- sampler project list
39
- sampler index myproj
40
- sampler search add --project myproj
41
- sampler overview /absolute/path/file.py
42
- ```
43
-
44
- **Demo / LLM use (token-efficient by design):**
45
- - Default outputs are compact single-line (no tables, short paths, no noise).
46
- - Ideal for pasting into agents/LLMs with minimal context size.
47
- - Example: `sampler search worker --project myproj` → `myproj:src/tasks.py:42 function process def process()`
48
-
49
- ## Estado actual
50
-
51
- Implementado:
52
-
53
- - Bootstrap inicial de Fase 0
54
- - Configuración global con archivo `~/.sampler/config.yaml`
55
- - CRUD de proyectos en config (`add`, `list`, `remove`)
56
- - Esquema SQLite core + queries de index/search en `src/sampler/db.py`
57
- - Discovery de archivos por lenguaje con soporte `.gitignore`
58
- - Parser Python estable basado en AST
59
- - Indexer real (hash incremental + persistencia)
60
- - Query engine real (`search`, `overview`)
61
- - CI básico con GitHub Actions (`pytest -q`)
62
- - Tests: smoke, config, db, cli, discovery, python_parser, index_query
63
-
64
- Nota de estabilidad:
65
-
66
- - Se desactivó uso runtime de tree-sitter en parser Python por crash nativo (`BUS/SEGV`) en indexación real.
67
- - Se mantiene estrategia AST para estabilidad en producción local.
68
-
69
- Pendiente inmediato:
70
-
71
- - Filtros y paginación en búsqueda
72
- - Comandos `callers`, `usages`, `related`
73
- - Parsers Go y TypeScript/JavaScript
74
-
75
- ## Estructura clave
76
-
77
- ```text
78
- src/sampler/cli/main.py # comandos CLI
79
- src/sampler/config.py # config global YAML
80
- src/sampler/db.py # capa SQLite
81
- src/sampler/indexer/builder.py # indexación de proyectos
82
- src/sampler/indexer/store.py # persistencia de símbolos/relaciones
83
- src/sampler/indexer/parsers/python.py # parser python estable
84
- src/sampler/query/engine.py # search/overview
85
- src/sampler/indexer/discover.py # discovery y filtros
86
- tests/ # pruebas base
87
- ```
88
-
89
- ## Ejecutar pruebas
90
-
91
- ```bash
92
- pytest -q
93
- ```
@@ -1,130 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: sampler-cli
3
- Version: 0.2.0
4
- Summary: Token-efficient CLI for indexing and searching code symbols (Python-first, designed for minimal LLM/agent context size)
5
- Author: Samuel Ignacio Carmona Rodriguez
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/sicr0/sampler-cli
8
- Project-URL: Repository, https://github.com/sicr0/sampler-cli
9
- Project-URL: Issues, https://github.com/sicr0/sampler-cli/issues
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
- Classifier: Topic :: Software Development :: Code Generators
17
- Requires-Python: >=3.11
18
- Description-Content-Type: text/markdown
19
- License-File: LICENSE
20
- Requires-Dist: typer>=0.12.0
21
- Requires-Dist: rich>=13.7.0
22
- Requires-Dist: tree-sitter>=0.21.0
23
- Requires-Dist: tree-sitter-python>=0.23.0
24
- Requires-Dist: gitignore-parser>=0.1.11
25
- Requires-Dist: pydantic>=2.6.0
26
- Requires-Dist: pyyaml>=6.0.0
27
- Provides-Extra: dev
28
- Requires-Dist: pytest>=7.4.0; extra == "dev"
29
- Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
30
- Requires-Dist: ruff>=0.5.0; extra == "dev"
31
- Requires-Dist: mypy>=1.7.0; extra == "dev"
32
- Provides-Extra: mcp
33
- Requires-Dist: fastmcp>=0.1.0; extra == "mcp"
34
- Provides-Extra: semantic
35
- Requires-Dist: sentence-transformers>=2.2.0; extra == "semantic"
36
- Dynamic: license-file
37
-
38
- # Sampler
39
-
40
- CLI indexer para navegar símbolos y relaciones en codebases multiproyecto.
41
-
42
- Versión actual: 0.1.2
43
-
44
- ## Requisitos
45
-
46
- - Python 3.11+
47
- - `uv` (recomendado)
48
- - Go (instalado para soporte parser Fase 1)
49
-
50
- ## Instalación de Go (macOS)
51
-
52
- ```bash
53
- brew install go
54
- go version
55
- ```
56
-
57
- ## Instalación
58
-
59
- ```bash
60
- pip install sampler-cli
61
- ```
62
-
63
- Para desarrollo (incluye tests, linters):
64
-
65
- ```bash
66
- pip install -e '.[dev]'
67
- ```
68
-
69
- ## Uso rápido
70
-
71
- ```bash
72
- pip install sampler-cli
73
- sampler init
74
- sampler project add myproj /absolute/path --language python
75
- sampler project list
76
- sampler index myproj
77
- sampler search add --project myproj
78
- sampler overview /absolute/path/file.py
79
- ```
80
-
81
- **Demo / LLM use (token-efficient by design):**
82
- - Default outputs are compact single-line (no tables, short paths, no noise).
83
- - Ideal for pasting into agents/LLMs with minimal context size.
84
- - Example: `sampler search worker --project myproj` → `myproj:src/tasks.py:42 function process def process()`
85
-
86
- ## Estado actual
87
-
88
- Implementado:
89
-
90
- - Bootstrap inicial de Fase 0
91
- - Configuración global con archivo `~/.sampler/config.yaml`
92
- - CRUD de proyectos en config (`add`, `list`, `remove`)
93
- - Esquema SQLite core + queries de index/search en `src/sampler/db.py`
94
- - Discovery de archivos por lenguaje con soporte `.gitignore`
95
- - Parser Python estable basado en AST
96
- - Indexer real (hash incremental + persistencia)
97
- - Query engine real (`search`, `overview`)
98
- - CI básico con GitHub Actions (`pytest -q`)
99
- - Tests: smoke, config, db, cli, discovery, python_parser, index_query
100
-
101
- Nota de estabilidad:
102
-
103
- - Se desactivó uso runtime de tree-sitter en parser Python por crash nativo (`BUS/SEGV`) en indexación real.
104
- - Se mantiene estrategia AST para estabilidad en producción local.
105
-
106
- Pendiente inmediato:
107
-
108
- - Filtros y paginación en búsqueda
109
- - Comandos `callers`, `usages`, `related`
110
- - Parsers Go y TypeScript/JavaScript
111
-
112
- ## Estructura clave
113
-
114
- ```text
115
- src/sampler/cli/main.py # comandos CLI
116
- src/sampler/config.py # config global YAML
117
- src/sampler/db.py # capa SQLite
118
- src/sampler/indexer/builder.py # indexación de proyectos
119
- src/sampler/indexer/store.py # persistencia de símbolos/relaciones
120
- src/sampler/indexer/parsers/python.py # parser python estable
121
- src/sampler/query/engine.py # search/overview
122
- src/sampler/indexer/discover.py # discovery y filtros
123
- tests/ # pruebas base
124
- ```
125
-
126
- ## Ejecutar pruebas
127
-
128
- ```bash
129
- pytest -q
130
- ```
File without changes
File without changes