codespine 0.7.0__tar.gz → 0.7.2__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 (60) hide show
  1. {codespine-0.7.0 → codespine-0.7.2}/PKG-INFO +125 -36
  2. {codespine-0.7.0 → codespine-0.7.2}/README.md +125 -36
  3. {codespine-0.7.0 → codespine-0.7.2}/codespine/__init__.py +1 -1
  4. {codespine-0.7.0 → codespine-0.7.2}/codespine/analysis/coupling.py +8 -8
  5. {codespine-0.7.0 → codespine-0.7.2}/codespine/cli.py +5 -5
  6. {codespine-0.7.0 → codespine-0.7.2}/codespine/config.py +1 -1
  7. {codespine-0.7.0 → codespine-0.7.2}/codespine/db/store.py +3 -3
  8. {codespine-0.7.0 → codespine-0.7.2}/codespine/guide.py +1 -1
  9. {codespine-0.7.0 → codespine-0.7.2}/codespine/mcp/server.py +3 -3
  10. {codespine-0.7.0 → codespine-0.7.2}/codespine.egg-info/PKG-INFO +125 -36
  11. {codespine-0.7.0 → codespine-0.7.2}/pyproject.toml +1 -1
  12. {codespine-0.7.0 → codespine-0.7.2}/LICENSE +0 -0
  13. {codespine-0.7.0 → codespine-0.7.2}/codespine/analysis/__init__.py +0 -0
  14. {codespine-0.7.0 → codespine-0.7.2}/codespine/analysis/community.py +0 -0
  15. {codespine-0.7.0 → codespine-0.7.2}/codespine/analysis/context.py +0 -0
  16. {codespine-0.7.0 → codespine-0.7.2}/codespine/analysis/crossmodule.py +0 -0
  17. {codespine-0.7.0 → codespine-0.7.2}/codespine/analysis/deadcode.py +0 -0
  18. {codespine-0.7.0 → codespine-0.7.2}/codespine/analysis/flow.py +0 -0
  19. {codespine-0.7.0 → codespine-0.7.2}/codespine/analysis/impact.py +0 -0
  20. {codespine-0.7.0 → codespine-0.7.2}/codespine/db/__init__.py +0 -0
  21. {codespine-0.7.0 → codespine-0.7.2}/codespine/db/schema.py +0 -0
  22. {codespine-0.7.0 → codespine-0.7.2}/codespine/diff/__init__.py +0 -0
  23. {codespine-0.7.0 → codespine-0.7.2}/codespine/diff/branch_diff.py +0 -0
  24. {codespine-0.7.0 → codespine-0.7.2}/codespine/indexer/__init__.py +0 -0
  25. {codespine-0.7.0 → codespine-0.7.2}/codespine/indexer/call_resolver.py +0 -0
  26. {codespine-0.7.0 → codespine-0.7.2}/codespine/indexer/engine.py +0 -0
  27. {codespine-0.7.0 → codespine-0.7.2}/codespine/indexer/java_parser.py +0 -0
  28. {codespine-0.7.0 → codespine-0.7.2}/codespine/indexer/symbol_builder.py +0 -0
  29. {codespine-0.7.0 → codespine-0.7.2}/codespine/mcp/__init__.py +0 -0
  30. {codespine-0.7.0 → codespine-0.7.2}/codespine/noise/__init__.py +0 -0
  31. {codespine-0.7.0 → codespine-0.7.2}/codespine/noise/blocklist.py +0 -0
  32. {codespine-0.7.0 → codespine-0.7.2}/codespine/overlay/__init__.py +0 -0
  33. {codespine-0.7.0 → codespine-0.7.2}/codespine/overlay/git_state.py +0 -0
  34. {codespine-0.7.0 → codespine-0.7.2}/codespine/overlay/merge.py +0 -0
  35. {codespine-0.7.0 → codespine-0.7.2}/codespine/overlay/store.py +0 -0
  36. {codespine-0.7.0 → codespine-0.7.2}/codespine/search/__init__.py +0 -0
  37. {codespine-0.7.0 → codespine-0.7.2}/codespine/search/bm25.py +0 -0
  38. {codespine-0.7.0 → codespine-0.7.2}/codespine/search/fuzzy.py +0 -0
  39. {codespine-0.7.0 → codespine-0.7.2}/codespine/search/hybrid.py +0 -0
  40. {codespine-0.7.0 → codespine-0.7.2}/codespine/search/rrf.py +0 -0
  41. {codespine-0.7.0 → codespine-0.7.2}/codespine/search/vector.py +0 -0
  42. {codespine-0.7.0 → codespine-0.7.2}/codespine/watch/__init__.py +0 -0
  43. {codespine-0.7.0 → codespine-0.7.2}/codespine/watch/watcher.py +0 -0
  44. {codespine-0.7.0 → codespine-0.7.2}/codespine.egg-info/SOURCES.txt +0 -0
  45. {codespine-0.7.0 → codespine-0.7.2}/codespine.egg-info/dependency_links.txt +0 -0
  46. {codespine-0.7.0 → codespine-0.7.2}/codespine.egg-info/entry_points.txt +0 -0
  47. {codespine-0.7.0 → codespine-0.7.2}/codespine.egg-info/requires.txt +0 -0
  48. {codespine-0.7.0 → codespine-0.7.2}/codespine.egg-info/top_level.txt +0 -0
  49. {codespine-0.7.0 → codespine-0.7.2}/gindex.py +0 -0
  50. {codespine-0.7.0 → codespine-0.7.2}/setup.cfg +0 -0
  51. {codespine-0.7.0 → codespine-0.7.2}/tests/test_branch_diff_normalize.py +0 -0
  52. {codespine-0.7.0 → codespine-0.7.2}/tests/test_call_resolver.py +0 -0
  53. {codespine-0.7.0 → codespine-0.7.2}/tests/test_community_detection.py +0 -0
  54. {codespine-0.7.0 → codespine-0.7.2}/tests/test_deadcode.py +0 -0
  55. {codespine-0.7.0 → codespine-0.7.2}/tests/test_index_and_hybrid.py +0 -0
  56. {codespine-0.7.0 → codespine-0.7.2}/tests/test_java_parser.py +0 -0
  57. {codespine-0.7.0 → codespine-0.7.2}/tests/test_multimodule_index.py +0 -0
  58. {codespine-0.7.0 → codespine-0.7.2}/tests/test_overlay.py +0 -0
  59. {codespine-0.7.0 → codespine-0.7.2}/tests/test_search_ranking.py +0 -0
  60. {codespine-0.7.0 → codespine-0.7.2}/tests/test_store_recovery.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codespine
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Local Java code intelligence indexer backed by a graph database
5
5
  Author: CodeSpine contributors
6
6
  License: MIT License
@@ -223,45 +223,134 @@ If the client launches the wrong Python environment, use the absolute binary pat
223
223
  }
224
224
  ```
225
225
 
226
- Common MCP tools:
226
+ ### Agent Onboarding
227
227
 
228
- - `search_hybrid(query, k, project)`
229
- - `find_symbol(name, kind, project, limit)`
230
- - `get_symbol_context(query, max_depth, project)`
231
- - `get_impact(symbol, max_depth, project)`
232
- - `detect_dead_code(limit, project, strict)`
233
- - `trace_execution_flows(entry_symbol, max_depth, project)`
234
- - `get_symbol_community(symbol)`
235
- - `get_change_coupling(months, min_strength, min_cochanges, project)`
236
- - `compare_branches(base_ref, head_ref)`
237
- - `get_codebase_stats()`
228
+ When an agent connects to CodeSpine for the first time, it should call:
238
229
 
239
- ## CLI
230
+ 1. **`guide()`** — returns a structured catalog of every tool, organized by category, with recommended workflows and tips.
231
+ 2. **`get_capabilities()`** — returns what is indexed right now, which features are ready, and what's missing.
240
232
 
241
- Core commands:
233
+ The same information is available from the CLI:
242
234
 
243
235
  ```bash
244
- codespine analyse <path>
245
- codespine analyse <path> --full
246
- codespine analyse <path> --deep
247
- codespine analyse <path> --embed
248
- codespine watch --path .
249
- codespine watch --path . --overlay-debounce-ms 1500
250
- codespine search "query"
251
- codespine context "symbol"
252
- codespine impact "symbol"
253
- codespine deadcode
254
- codespine flow
255
- codespine community
256
- codespine coupling
257
- codespine diff main..feature
258
- codespine stats
259
- codespine list
260
- codespine overlay-status
261
- codespine overlay-promote
262
- codespine overlay-clear
263
- codespine clear-project <project_id>
264
- codespine clear-index
236
+ codespine guide # tool catalog, workflows, tips
237
+ codespine guide --json # structured JSON for tooling
238
+ ```
239
+
240
+ ### MCP Tools
241
+
242
+ **Discovery & Status**
243
+
244
+ | Tool | Description |
245
+ |------|-------------|
246
+ | `guide()` | Tool catalog, workflows, and tips. Call first if new to CodeSpine. |
247
+ | `get_capabilities()` | What is indexed and which features are available right now. |
248
+ | `list_projects()` | All indexed projects with symbol/file counts. |
249
+ | `get_codebase_stats()` | Per-project stats: files, classes, methods, call edges, embeddings. |
250
+ | `list_packages(project)` | Java packages in the index. |
251
+ | `ping()` | Verify the MCP server is alive. |
252
+
253
+ **Search & Lookup**
254
+
255
+ | Tool | Description |
256
+ |------|-------------|
257
+ | `search_hybrid(query, k, project)` | Ranked symbol search (BM25 + vector + fuzzy via RRF). |
258
+ | `find_symbol(name, kind, project, limit)` | Exact/prefix name lookup across all projects. |
259
+ | `get_symbol_context(query, max_depth, project)` | One-shot deep context: search + impact + community + flows. |
260
+ | `get_neighborhood(symbol, project)` | Callers, callees, siblings, and override/implements. |
261
+
262
+ **Analysis**
263
+
264
+ | Tool | Description |
265
+ |------|-------------|
266
+ | `get_impact(symbol, max_depth, project)` | Caller-tree impact analysis with confidence scores. |
267
+ | `detect_dead_code(limit, project, strict)` | Methods with no callers (Java-aware exemptions). |
268
+ | `trace_execution_flows(entry_symbol, max_depth, project)` | Execution paths from entry points. |
269
+ | `get_symbol_community(symbol)` | Architectural community cluster for a symbol. |
270
+ | `get_change_coupling(months, min_strength, min_cochanges)` | Files that historically change together. |
271
+
272
+ **Git**
273
+
274
+ | Tool | Description |
275
+ |------|-------------|
276
+ | `git_log(file_path, limit, project)` | Recent git commits. |
277
+ | `git_diff(ref, file_path, project)` | Git diff (working tree vs ref, or between refs). |
278
+ | `compare_branches(base_ref, head_ref, project)` | Symbol-level diff between two git refs. |
279
+
280
+ **Indexing & Watch**
281
+
282
+ | Tool | Description |
283
+ |------|-------------|
284
+ | `analyse_project(path, full, deep, embed)` | Index a Java project (background job). |
285
+ | `get_analyse_status()` | Poll analysis progress. |
286
+ | `reindex_file(file_path, project)` | Re-index a single `.java` file (<1 s). |
287
+ | `start_watch(path)` | Watch for `.java` changes and update overlay in real time. |
288
+ | `stop_watch()` | Stop the background watch process. |
289
+ | `get_watch_status()` | Watch mode status: running, path, uptime. |
290
+
291
+ **Overlay**
292
+
293
+ | Tool | Description |
294
+ |------|-------------|
295
+ | `get_overlay_status(project)` | Uncommitted overlay state by project/module. |
296
+ | `promote_overlay(project)` | Commit dirty overlay into the base index. |
297
+ | `clear_overlay(project)` | Discard dirty overlay without changing the base. |
298
+
299
+ **Reset**
300
+
301
+ | Tool | Description |
302
+ |------|-------------|
303
+ | `reset_project(project_id)` | Remove all data for one project. |
304
+ | `reset_index()` | Remove ALL data across every project. |
305
+ | `force_reset_index()` | Emergency: delete data files when normal reset fails. |
306
+
307
+ **Advanced**
308
+
309
+ | Tool | Description |
310
+ |------|-------------|
311
+ | `run_cypher(query)` | Run a raw Cypher query against the graph DB. |
312
+
313
+ ## CLI
314
+
315
+ ```bash
316
+ # Indexing
317
+ codespine analyse <path> # incremental index
318
+ codespine analyse <path> --full # full re-index
319
+ codespine analyse <path> --deep # + communities, flows, dead code, coupling
320
+ codespine analyse <path> --embed # + vector embeddings
321
+ codespine watch --path . # live re-index on file changes
322
+
323
+ # Search & Analysis
324
+ codespine search "query" # hybrid search
325
+ codespine context "symbol" # one-shot deep context
326
+ codespine impact "symbol" # caller-tree impact
327
+ codespine deadcode # dead code candidates
328
+ codespine flow # execution flows
329
+ codespine community # architectural clusters
330
+ codespine coupling # git change coupling
331
+ codespine diff main..feature # symbol-level branch diff
332
+
333
+ # Status & Info
334
+ codespine stats # per-project statistics
335
+ codespine list # indexed projects
336
+ codespine status # service and database status
337
+ codespine guide # tool catalog and workflows
338
+
339
+ # Overlay
340
+ codespine overlay-status # dirty overlay state
341
+ codespine overlay-promote # commit overlay to base
342
+ codespine overlay-clear # discard overlay
343
+
344
+ # Server Management
345
+ codespine start # launch background MCP server
346
+ codespine stop # stop background MCP server
347
+ codespine mcp # foreground MCP (stdio, for IDE)
348
+
349
+ # Cleanup & Reset
350
+ codespine clear-project <project_id> # remove one project
351
+ codespine clear-index # remove all indexed data
352
+ codespine force-reset # emergency: delete all data files
353
+ codespine setup # check dependencies
265
354
  ```
266
355
 
267
356
  `analyse` defaults to incremental mode. Repeat runs are designed to be fast when files have not changed.
@@ -323,8 +412,8 @@ Running `codespine analyse --deep --embed` on one project while querying a diffe
323
412
  - `codespine start` launches a background MCP server. Most IDE MCP clients should use `codespine mcp` instead and manage the process themselves.
324
413
  - `codespine watch` updates the dirty overlay first; it does not rewrite the committed base index on every save.
325
414
  - `codespine clear-index` rebuilds the local index database from scratch. This also removes the read replica; run `analyse` again to republish it.
415
+ - `codespine force-reset` is the nuclear option — it deletes all data files without going through the DB engine. Use it when `clear-index` fails due to DB corruption.
326
416
  - For large Spring or JPA-heavy repos, dead-code results should still be reviewed before deletion. The tool is conservative, not authoritative.
327
- - The first run after upgrading to v0.5.7 will not have a read replica yet. Run `codespine analyse` once to create it.
328
417
 
329
418
  ## Project Docs
330
419
 
@@ -159,45 +159,134 @@ If the client launches the wrong Python environment, use the absolute binary pat
159
159
  }
160
160
  ```
161
161
 
162
- Common MCP tools:
163
-
164
- - `search_hybrid(query, k, project)`
165
- - `find_symbol(name, kind, project, limit)`
166
- - `get_symbol_context(query, max_depth, project)`
167
- - `get_impact(symbol, max_depth, project)`
168
- - `detect_dead_code(limit, project, strict)`
169
- - `trace_execution_flows(entry_symbol, max_depth, project)`
170
- - `get_symbol_community(symbol)`
171
- - `get_change_coupling(months, min_strength, min_cochanges, project)`
172
- - `compare_branches(base_ref, head_ref)`
173
- - `get_codebase_stats()`
162
+ ### Agent Onboarding
174
163
 
175
- ## CLI
164
+ When an agent connects to CodeSpine for the first time, it should call:
165
+
166
+ 1. **`guide()`** — returns a structured catalog of every tool, organized by category, with recommended workflows and tips.
167
+ 2. **`get_capabilities()`** — returns what is indexed right now, which features are ready, and what's missing.
176
168
 
177
- Core commands:
169
+ The same information is available from the CLI:
178
170
 
179
171
  ```bash
180
- codespine analyse <path>
181
- codespine analyse <path> --full
182
- codespine analyse <path> --deep
183
- codespine analyse <path> --embed
184
- codespine watch --path .
185
- codespine watch --path . --overlay-debounce-ms 1500
186
- codespine search "query"
187
- codespine context "symbol"
188
- codespine impact "symbol"
189
- codespine deadcode
190
- codespine flow
191
- codespine community
192
- codespine coupling
193
- codespine diff main..feature
194
- codespine stats
195
- codespine list
196
- codespine overlay-status
197
- codespine overlay-promote
198
- codespine overlay-clear
199
- codespine clear-project <project_id>
200
- codespine clear-index
172
+ codespine guide # tool catalog, workflows, tips
173
+ codespine guide --json # structured JSON for tooling
174
+ ```
175
+
176
+ ### MCP Tools
177
+
178
+ **Discovery & Status**
179
+
180
+ | Tool | Description |
181
+ |------|-------------|
182
+ | `guide()` | Tool catalog, workflows, and tips. Call first if new to CodeSpine. |
183
+ | `get_capabilities()` | What is indexed and which features are available right now. |
184
+ | `list_projects()` | All indexed projects with symbol/file counts. |
185
+ | `get_codebase_stats()` | Per-project stats: files, classes, methods, call edges, embeddings. |
186
+ | `list_packages(project)` | Java packages in the index. |
187
+ | `ping()` | Verify the MCP server is alive. |
188
+
189
+ **Search & Lookup**
190
+
191
+ | Tool | Description |
192
+ |------|-------------|
193
+ | `search_hybrid(query, k, project)` | Ranked symbol search (BM25 + vector + fuzzy via RRF). |
194
+ | `find_symbol(name, kind, project, limit)` | Exact/prefix name lookup across all projects. |
195
+ | `get_symbol_context(query, max_depth, project)` | One-shot deep context: search + impact + community + flows. |
196
+ | `get_neighborhood(symbol, project)` | Callers, callees, siblings, and override/implements. |
197
+
198
+ **Analysis**
199
+
200
+ | Tool | Description |
201
+ |------|-------------|
202
+ | `get_impact(symbol, max_depth, project)` | Caller-tree impact analysis with confidence scores. |
203
+ | `detect_dead_code(limit, project, strict)` | Methods with no callers (Java-aware exemptions). |
204
+ | `trace_execution_flows(entry_symbol, max_depth, project)` | Execution paths from entry points. |
205
+ | `get_symbol_community(symbol)` | Architectural community cluster for a symbol. |
206
+ | `get_change_coupling(months, min_strength, min_cochanges)` | Files that historically change together. |
207
+
208
+ **Git**
209
+
210
+ | Tool | Description |
211
+ |------|-------------|
212
+ | `git_log(file_path, limit, project)` | Recent git commits. |
213
+ | `git_diff(ref, file_path, project)` | Git diff (working tree vs ref, or between refs). |
214
+ | `compare_branches(base_ref, head_ref, project)` | Symbol-level diff between two git refs. |
215
+
216
+ **Indexing & Watch**
217
+
218
+ | Tool | Description |
219
+ |------|-------------|
220
+ | `analyse_project(path, full, deep, embed)` | Index a Java project (background job). |
221
+ | `get_analyse_status()` | Poll analysis progress. |
222
+ | `reindex_file(file_path, project)` | Re-index a single `.java` file (<1 s). |
223
+ | `start_watch(path)` | Watch for `.java` changes and update overlay in real time. |
224
+ | `stop_watch()` | Stop the background watch process. |
225
+ | `get_watch_status()` | Watch mode status: running, path, uptime. |
226
+
227
+ **Overlay**
228
+
229
+ | Tool | Description |
230
+ |------|-------------|
231
+ | `get_overlay_status(project)` | Uncommitted overlay state by project/module. |
232
+ | `promote_overlay(project)` | Commit dirty overlay into the base index. |
233
+ | `clear_overlay(project)` | Discard dirty overlay without changing the base. |
234
+
235
+ **Reset**
236
+
237
+ | Tool | Description |
238
+ |------|-------------|
239
+ | `reset_project(project_id)` | Remove all data for one project. |
240
+ | `reset_index()` | Remove ALL data across every project. |
241
+ | `force_reset_index()` | Emergency: delete data files when normal reset fails. |
242
+
243
+ **Advanced**
244
+
245
+ | Tool | Description |
246
+ |------|-------------|
247
+ | `run_cypher(query)` | Run a raw Cypher query against the graph DB. |
248
+
249
+ ## CLI
250
+
251
+ ```bash
252
+ # Indexing
253
+ codespine analyse <path> # incremental index
254
+ codespine analyse <path> --full # full re-index
255
+ codespine analyse <path> --deep # + communities, flows, dead code, coupling
256
+ codespine analyse <path> --embed # + vector embeddings
257
+ codespine watch --path . # live re-index on file changes
258
+
259
+ # Search & Analysis
260
+ codespine search "query" # hybrid search
261
+ codespine context "symbol" # one-shot deep context
262
+ codespine impact "symbol" # caller-tree impact
263
+ codespine deadcode # dead code candidates
264
+ codespine flow # execution flows
265
+ codespine community # architectural clusters
266
+ codespine coupling # git change coupling
267
+ codespine diff main..feature # symbol-level branch diff
268
+
269
+ # Status & Info
270
+ codespine stats # per-project statistics
271
+ codespine list # indexed projects
272
+ codespine status # service and database status
273
+ codespine guide # tool catalog and workflows
274
+
275
+ # Overlay
276
+ codespine overlay-status # dirty overlay state
277
+ codespine overlay-promote # commit overlay to base
278
+ codespine overlay-clear # discard overlay
279
+
280
+ # Server Management
281
+ codespine start # launch background MCP server
282
+ codespine stop # stop background MCP server
283
+ codespine mcp # foreground MCP (stdio, for IDE)
284
+
285
+ # Cleanup & Reset
286
+ codespine clear-project <project_id> # remove one project
287
+ codespine clear-index # remove all indexed data
288
+ codespine force-reset # emergency: delete all data files
289
+ codespine setup # check dependencies
201
290
  ```
202
291
 
203
292
  `analyse` defaults to incremental mode. Repeat runs are designed to be fast when files have not changed.
@@ -259,8 +348,8 @@ Running `codespine analyse --deep --embed` on one project while querying a diffe
259
348
  - `codespine start` launches a background MCP server. Most IDE MCP clients should use `codespine mcp` instead and manage the process themselves.
260
349
  - `codespine watch` updates the dirty overlay first; it does not rewrite the committed base index on every save.
261
350
  - `codespine clear-index` rebuilds the local index database from scratch. This also removes the read replica; run `analyse` again to republish it.
351
+ - `codespine force-reset` is the nuclear option — it deletes all data files without going through the DB engine. Use it when `clear-index` fails due to DB corruption.
262
352
  - For large Spring or JPA-heavy repos, dead-code results should still be reviewed before deletion. The tool is conservative, not authoritative.
263
- - The first run after upgrading to v0.5.7 will not have a read replica yet. Run `codespine analyse` once to create it.
264
353
 
265
354
  ## Project Docs
266
355
 
@@ -1,4 +1,4 @@
1
1
  """CodeSpine package."""
2
2
 
3
3
  __all__ = ["__version__"]
4
- __version__ = "0.7.0"
4
+ __version__ = "0.7.2"
@@ -9,7 +9,7 @@ from codespine.config import SETTINGS
9
9
  from codespine.indexer.symbol_builder import file_id
10
10
 
11
11
 
12
- def _git_changed_file_sets(repo_path: str, months: int) -> list[set[str]]:
12
+ def _git_changed_file_sets(repo_path: str, days: int) -> list[set[str]]:
13
13
  cmd = [
14
14
  "git",
15
15
  "-C",
@@ -17,7 +17,7 @@ def _git_changed_file_sets(repo_path: str, months: int) -> list[set[str]]:
17
17
  "log",
18
18
  "--name-only",
19
19
  "--pretty=format:__COMMIT__",
20
- f"--since={months}.months",
20
+ f"--since={days}.days",
21
21
  ]
22
22
  proc = subprocess.run(cmd, capture_output=True, text=True, check=False)
23
23
  if proc.returncode != 0:
@@ -43,7 +43,7 @@ def compute_coupling(
43
43
  store,
44
44
  repo_path: str,
45
45
  project_id: str,
46
- months: int = SETTINGS.default_coupling_months,
46
+ days: int = SETTINGS.default_coupling_days,
47
47
  min_strength: float = SETTINGS.default_min_coupling_strength,
48
48
  min_cochanges: int = SETTINGS.default_min_cochanges,
49
49
  progress=None,
@@ -53,7 +53,7 @@ def compute_coupling(
53
53
  progress(msg)
54
54
 
55
55
  _ping("reading git history")
56
- changesets = _git_changed_file_sets(repo_path, months)
56
+ changesets = _git_changed_file_sets(repo_path, days)
57
57
  if not changesets:
58
58
  return []
59
59
 
@@ -77,7 +77,7 @@ def compute_coupling(
77
77
 
78
78
  aid = file_id(project_id, a)
79
79
  bid = file_id(project_id, b)
80
- store.upsert_coupling(aid, bid, strength, pair_count, months)
80
+ store.upsert_coupling(aid, bid, strength, pair_count, days)
81
81
  results.append(
82
82
  {
83
83
  "file_a": a,
@@ -91,7 +91,7 @@ def compute_coupling(
91
91
  return results
92
92
 
93
93
 
94
- def get_coupling(store, symbol: str | None = None, months: int = 6, min_strength: float = 0.3, min_cochanges: int = 3) -> dict:
94
+ def get_coupling(store, symbol: str | None = None, days: int = 5, min_strength: float = 0.3, min_cochanges: int = 3) -> dict:
95
95
  if symbol:
96
96
  recs = store.query_records(
97
97
  """
@@ -113,13 +113,13 @@ def get_coupling(store, symbol: str | None = None, months: int = 6, min_strength
113
113
  recs = store.query_records(
114
114
  """
115
115
  MATCH (f:File)-[r:CO_CHANGED_WITH]-(f2:File)
116
- WHERE r.months = $months AND r.strength >= $min_strength AND r.cochanges >= $min_cochanges
116
+ WHERE r.days = $days AND r.strength >= $min_strength AND r.cochanges >= $min_cochanges
117
117
  RETURN f.path as file, f2.path as coupled_file, r.strength as strength, r.cochanges as cochanges
118
118
  ORDER BY strength DESC, cochanges DESC
119
119
  LIMIT 500
120
120
  """,
121
121
  {
122
- "months": months,
122
+ "days": days,
123
123
  "min_strength": min_strength,
124
124
  "min_cochanges": min_cochanges,
125
125
  },
@@ -314,7 +314,7 @@ def analyse(path: str, full: bool, deep: bool, embed: bool, allow_running: bool)
314
314
  store,
315
315
  coupling_root,
316
316
  coupling_project,
317
- months=SETTINGS.default_coupling_months,
317
+ days=SETTINGS.default_coupling_days,
318
318
  min_strength=SETTINGS.default_min_coupling_strength,
319
319
  min_cochanges=SETTINGS.default_min_cochanges,
320
320
  progress=lambda s: _live_phase(coup_label, s),
@@ -467,20 +467,20 @@ def community(symbol: str | None, as_json: bool) -> None:
467
467
 
468
468
 
469
469
  @main.command()
470
- @click.option("--months", default=6, show_default=True, type=int)
470
+ @click.option("--days", default=5, show_default=True, type=int)
471
471
  @click.option("--min-strength", default=0.3, show_default=True, type=float)
472
472
  @click.option("--min-cochanges", default=3, show_default=True, type=int)
473
473
  @click.option("--json", "as_json", is_flag=True)
474
- def coupling(months: int, min_strength: float, min_cochanges: int, as_json: bool) -> None:
474
+ def coupling(days: int, min_strength: float, min_cochanges: int, as_json: bool) -> None:
475
475
  """Compute and query git change coupling."""
476
476
  store = GraphStore(read_only=False)
477
477
  project = store.query_records("MATCH (p:Project) RETURN p.id as id LIMIT 1")
478
478
  project_id = project[0]["id"] if project else os.path.basename(os.getcwd())
479
- compute_coupling(store, os.getcwd(), project_id, months=months, min_strength=min_strength, min_cochanges=min_cochanges)
479
+ compute_coupling(store, os.getcwd(), project_id, days=days, min_strength=min_strength, min_cochanges=min_cochanges)
480
480
  result = get_coupling(
481
481
  store,
482
482
  symbol=None,
483
- months=months,
483
+ days=days,
484
484
  min_strength=min_strength,
485
485
  min_cochanges=min_cochanges,
486
486
  )
@@ -18,7 +18,7 @@ class Settings:
18
18
  write_batch_size: int = 500
19
19
  index_file_batch_size: int = 20
20
20
  edge_write_batch_size: int = 500
21
- default_coupling_months: int = 6
21
+ default_coupling_days: int = 5
22
22
  default_min_coupling_strength: float = 0.3
23
23
  default_min_cochanges: int = 3
24
24
  default_global_interval_s: int = 30
@@ -648,18 +648,18 @@ class GraphStore:
648
648
  )
649
649
  self._recycle_conn()
650
650
 
651
- def upsert_coupling(self, file_a: str, file_b: str, strength: float, cochanges: int, months: int) -> None:
651
+ def upsert_coupling(self, file_a: str, file_b: str, strength: float, cochanges: int, days: int) -> None:
652
652
  self.execute(
653
653
  """
654
654
  MATCH (a:File {id: $a}), (b:File {id: $b})
655
- MERGE (a)-[:CO_CHANGED_WITH {strength: $strength, cochanges: $cochanges, months: $months}]->(b)
655
+ MERGE (a)-[:CO_CHANGED_WITH {strength: $strength, cochanges: $cochanges, days: $days}]->(b)
656
656
  """,
657
657
  {
658
658
  "a": file_a,
659
659
  "b": file_b,
660
660
  "strength": strength,
661
661
  "cochanges": int(cochanges),
662
- "months": int(months),
662
+ "days": int(days),
663
663
  },
664
664
  )
665
665
 
@@ -60,7 +60,7 @@ GUIDE_SECTIONS: list[dict] = [
60
60
  {"name": "detect_dead_code", "one_liner": "Methods with no callers (Java-aware exemptions). strict=True for thorough audit."},
61
61
  {"name": "trace_execution_flows", "one_liner": "Execution paths from entry points (main methods, tests, controllers)."},
62
62
  {"name": "get_symbol_community", "one_liner": "Architectural community cluster a symbol belongs to."},
63
- {"name": "get_change_coupling", "one_liner": "Files that historically change together (git co-change analysis)."},
63
+ {"name": "get_change_coupling", "one_liner": "Files that changed together in the last N days (default 5). git co-change analysis."},
64
64
  ],
65
65
  },
66
66
  {
@@ -522,15 +522,15 @@ def build_mcp_server(store, repo_path_provider):
522
522
  @mcp.tool()
523
523
  def get_change_coupling(
524
524
  symbol: str | None = None,
525
- months: int = 6,
525
+ days: int = 5,
526
526
  min_strength: float = 0.3,
527
527
  min_cochanges: int = 3,
528
528
  ):
529
529
  """
530
- Files that historically change together (git co-change coupling).
530
+ Files that changed together in the last N days (git co-change coupling).
531
531
  Requires 'codespine analyse --deep' to have been run.
532
532
  """
533
- result = get_coupling(store, symbol=symbol, months=months, min_strength=min_strength, min_cochanges=min_cochanges)
533
+ result = get_coupling(store, symbol=symbol, days=days, min_strength=min_strength, min_cochanges=min_cochanges)
534
534
  if not result:
535
535
  return {
536
536
  "available": False,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codespine
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Local Java code intelligence indexer backed by a graph database
5
5
  Author: CodeSpine contributors
6
6
  License: MIT License
@@ -223,45 +223,134 @@ If the client launches the wrong Python environment, use the absolute binary pat
223
223
  }
224
224
  ```
225
225
 
226
- Common MCP tools:
226
+ ### Agent Onboarding
227
227
 
228
- - `search_hybrid(query, k, project)`
229
- - `find_symbol(name, kind, project, limit)`
230
- - `get_symbol_context(query, max_depth, project)`
231
- - `get_impact(symbol, max_depth, project)`
232
- - `detect_dead_code(limit, project, strict)`
233
- - `trace_execution_flows(entry_symbol, max_depth, project)`
234
- - `get_symbol_community(symbol)`
235
- - `get_change_coupling(months, min_strength, min_cochanges, project)`
236
- - `compare_branches(base_ref, head_ref)`
237
- - `get_codebase_stats()`
228
+ When an agent connects to CodeSpine for the first time, it should call:
238
229
 
239
- ## CLI
230
+ 1. **`guide()`** — returns a structured catalog of every tool, organized by category, with recommended workflows and tips.
231
+ 2. **`get_capabilities()`** — returns what is indexed right now, which features are ready, and what's missing.
240
232
 
241
- Core commands:
233
+ The same information is available from the CLI:
242
234
 
243
235
  ```bash
244
- codespine analyse <path>
245
- codespine analyse <path> --full
246
- codespine analyse <path> --deep
247
- codespine analyse <path> --embed
248
- codespine watch --path .
249
- codespine watch --path . --overlay-debounce-ms 1500
250
- codespine search "query"
251
- codespine context "symbol"
252
- codespine impact "symbol"
253
- codespine deadcode
254
- codespine flow
255
- codespine community
256
- codespine coupling
257
- codespine diff main..feature
258
- codespine stats
259
- codespine list
260
- codespine overlay-status
261
- codespine overlay-promote
262
- codespine overlay-clear
263
- codespine clear-project <project_id>
264
- codespine clear-index
236
+ codespine guide # tool catalog, workflows, tips
237
+ codespine guide --json # structured JSON for tooling
238
+ ```
239
+
240
+ ### MCP Tools
241
+
242
+ **Discovery & Status**
243
+
244
+ | Tool | Description |
245
+ |------|-------------|
246
+ | `guide()` | Tool catalog, workflows, and tips. Call first if new to CodeSpine. |
247
+ | `get_capabilities()` | What is indexed and which features are available right now. |
248
+ | `list_projects()` | All indexed projects with symbol/file counts. |
249
+ | `get_codebase_stats()` | Per-project stats: files, classes, methods, call edges, embeddings. |
250
+ | `list_packages(project)` | Java packages in the index. |
251
+ | `ping()` | Verify the MCP server is alive. |
252
+
253
+ **Search & Lookup**
254
+
255
+ | Tool | Description |
256
+ |------|-------------|
257
+ | `search_hybrid(query, k, project)` | Ranked symbol search (BM25 + vector + fuzzy via RRF). |
258
+ | `find_symbol(name, kind, project, limit)` | Exact/prefix name lookup across all projects. |
259
+ | `get_symbol_context(query, max_depth, project)` | One-shot deep context: search + impact + community + flows. |
260
+ | `get_neighborhood(symbol, project)` | Callers, callees, siblings, and override/implements. |
261
+
262
+ **Analysis**
263
+
264
+ | Tool | Description |
265
+ |------|-------------|
266
+ | `get_impact(symbol, max_depth, project)` | Caller-tree impact analysis with confidence scores. |
267
+ | `detect_dead_code(limit, project, strict)` | Methods with no callers (Java-aware exemptions). |
268
+ | `trace_execution_flows(entry_symbol, max_depth, project)` | Execution paths from entry points. |
269
+ | `get_symbol_community(symbol)` | Architectural community cluster for a symbol. |
270
+ | `get_change_coupling(months, min_strength, min_cochanges)` | Files that historically change together. |
271
+
272
+ **Git**
273
+
274
+ | Tool | Description |
275
+ |------|-------------|
276
+ | `git_log(file_path, limit, project)` | Recent git commits. |
277
+ | `git_diff(ref, file_path, project)` | Git diff (working tree vs ref, or between refs). |
278
+ | `compare_branches(base_ref, head_ref, project)` | Symbol-level diff between two git refs. |
279
+
280
+ **Indexing & Watch**
281
+
282
+ | Tool | Description |
283
+ |------|-------------|
284
+ | `analyse_project(path, full, deep, embed)` | Index a Java project (background job). |
285
+ | `get_analyse_status()` | Poll analysis progress. |
286
+ | `reindex_file(file_path, project)` | Re-index a single `.java` file (<1 s). |
287
+ | `start_watch(path)` | Watch for `.java` changes and update overlay in real time. |
288
+ | `stop_watch()` | Stop the background watch process. |
289
+ | `get_watch_status()` | Watch mode status: running, path, uptime. |
290
+
291
+ **Overlay**
292
+
293
+ | Tool | Description |
294
+ |------|-------------|
295
+ | `get_overlay_status(project)` | Uncommitted overlay state by project/module. |
296
+ | `promote_overlay(project)` | Commit dirty overlay into the base index. |
297
+ | `clear_overlay(project)` | Discard dirty overlay without changing the base. |
298
+
299
+ **Reset**
300
+
301
+ | Tool | Description |
302
+ |------|-------------|
303
+ | `reset_project(project_id)` | Remove all data for one project. |
304
+ | `reset_index()` | Remove ALL data across every project. |
305
+ | `force_reset_index()` | Emergency: delete data files when normal reset fails. |
306
+
307
+ **Advanced**
308
+
309
+ | Tool | Description |
310
+ |------|-------------|
311
+ | `run_cypher(query)` | Run a raw Cypher query against the graph DB. |
312
+
313
+ ## CLI
314
+
315
+ ```bash
316
+ # Indexing
317
+ codespine analyse <path> # incremental index
318
+ codespine analyse <path> --full # full re-index
319
+ codespine analyse <path> --deep # + communities, flows, dead code, coupling
320
+ codespine analyse <path> --embed # + vector embeddings
321
+ codespine watch --path . # live re-index on file changes
322
+
323
+ # Search & Analysis
324
+ codespine search "query" # hybrid search
325
+ codespine context "symbol" # one-shot deep context
326
+ codespine impact "symbol" # caller-tree impact
327
+ codespine deadcode # dead code candidates
328
+ codespine flow # execution flows
329
+ codespine community # architectural clusters
330
+ codespine coupling # git change coupling
331
+ codespine diff main..feature # symbol-level branch diff
332
+
333
+ # Status & Info
334
+ codespine stats # per-project statistics
335
+ codespine list # indexed projects
336
+ codespine status # service and database status
337
+ codespine guide # tool catalog and workflows
338
+
339
+ # Overlay
340
+ codespine overlay-status # dirty overlay state
341
+ codespine overlay-promote # commit overlay to base
342
+ codespine overlay-clear # discard overlay
343
+
344
+ # Server Management
345
+ codespine start # launch background MCP server
346
+ codespine stop # stop background MCP server
347
+ codespine mcp # foreground MCP (stdio, for IDE)
348
+
349
+ # Cleanup & Reset
350
+ codespine clear-project <project_id> # remove one project
351
+ codespine clear-index # remove all indexed data
352
+ codespine force-reset # emergency: delete all data files
353
+ codespine setup # check dependencies
265
354
  ```
266
355
 
267
356
  `analyse` defaults to incremental mode. Repeat runs are designed to be fast when files have not changed.
@@ -323,8 +412,8 @@ Running `codespine analyse --deep --embed` on one project while querying a diffe
323
412
  - `codespine start` launches a background MCP server. Most IDE MCP clients should use `codespine mcp` instead and manage the process themselves.
324
413
  - `codespine watch` updates the dirty overlay first; it does not rewrite the committed base index on every save.
325
414
  - `codespine clear-index` rebuilds the local index database from scratch. This also removes the read replica; run `analyse` again to republish it.
415
+ - `codespine force-reset` is the nuclear option — it deletes all data files without going through the DB engine. Use it when `clear-index` fails due to DB corruption.
326
416
  - For large Spring or JPA-heavy repos, dead-code results should still be reviewed before deletion. The tool is conservative, not authoritative.
327
- - The first run after upgrading to v0.5.7 will not have a read replica yet. Run `codespine analyse` once to create it.
328
417
 
329
418
  ## Project Docs
330
419
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codespine"
7
- version = "0.7.0"
7
+ version = "0.7.2"
8
8
  description = "Local Java code intelligence indexer backed by a graph database"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes
File without changes