witan-code 0.13.3__tar.gz → 0.13.5__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 (100) hide show
  1. {witan_code-0.13.3 → witan_code-0.13.5}/CHANGELOG.md +23 -0
  2. {witan_code-0.13.3 → witan_code-0.13.5}/PKG-INFO +2 -2
  3. {witan_code-0.13.3 → witan_code-0.13.5}/pyproject.toml +12 -3
  4. witan_code-0.13.5/tests/test_tool_schema.py +49 -0
  5. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/graph.py +9 -1
  6. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/server.py +45 -0
  7. {witan_code-0.13.3 → witan_code-0.13.5}/.gitignore +0 -0
  8. {witan_code-0.13.3 → witan_code-0.13.5}/README.md +0 -0
  9. {witan_code-0.13.3 → witan_code-0.13.5}/config/claude.json +0 -0
  10. {witan_code-0.13.3 → witan_code-0.13.5}/config/copilot.json +0 -0
  11. {witan_code-0.13.3 → witan_code-0.13.5}/config/pi.json +0 -0
  12. {witan_code-0.13.3 → witan_code-0.13.5}/docs/BRANCH_INDEXING.md +0 -0
  13. {witan_code-0.13.3 → witan_code-0.13.5}/docs/CLI_REFERENCE.md +0 -0
  14. {witan_code-0.13.3 → witan_code-0.13.5}/docs/EDGE_PRECISION_TIERS.md +0 -0
  15. {witan_code-0.13.3 → witan_code-0.13.5}/docs/PACKAGE_MAP.md +0 -0
  16. {witan_code-0.13.3 → witan_code-0.13.5}/docs/STAGE2_STITCHING.md +0 -0
  17. {witan_code-0.13.3 → witan_code-0.13.5}/docs/SYMBOL_FORMAT.md +0 -0
  18. {witan_code-0.13.3 → witan_code-0.13.5}/docs/SYMBOL_TABLE.md +0 -0
  19. {witan_code-0.13.3 → witan_code-0.13.5}/docs/USER_GUIDE.md +0 -0
  20. {witan_code-0.13.3 → witan_code-0.13.5}/install.sh +0 -0
  21. {witan_code-0.13.3 → witan_code-0.13.5}/tests/__init__.py +0 -0
  22. {witan_code-0.13.3 → witan_code-0.13.5}/tests/conftest.py +0 -0
  23. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_batched_deletes.py +0 -0
  24. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_branches.py +0 -0
  25. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_bridge.py +0 -0
  26. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_chunked_load.py +0 -0
  27. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_cli_dispatch.py +0 -0
  28. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_cli_hooks.py +0 -0
  29. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_cli_output_format.py +0 -0
  30. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_config.py +0 -0
  31. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_config_targets.py +0 -0
  32. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_context.py +0 -0
  33. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_crossrepo.py +0 -0
  34. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_edges.py +0 -0
  35. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_elicit.py +0 -0
  36. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_enrichment.py +0 -0
  37. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_github_app.py +0 -0
  38. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_graph.py +0 -0
  39. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_hooks.py +0 -0
  40. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_identity.py +0 -0
  41. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_indexer.py +0 -0
  42. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_indexer_scope.py +0 -0
  43. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_ingest.py +0 -0
  44. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_languages.py +0 -0
  45. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_maintenance.py +0 -0
  46. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_package_map.py +0 -0
  47. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_reaper.py +0 -0
  48. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_remote_proxy.py +0 -0
  49. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_remote_store.py +0 -0
  50. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_repo.py +0 -0
  51. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_server.py +0 -0
  52. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_setup.py +0 -0
  53. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_stitch.py +0 -0
  54. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_store.py +0 -0
  55. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_symbol_table.py +0 -0
  56. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_tasks.py +0 -0
  57. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_views.py +0 -0
  58. {witan_code-0.13.3 → witan_code-0.13.5}/tests/test_visualize.py +0 -0
  59. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/__init__.py +0 -0
  60. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/__main__.py +0 -0
  61. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/bridge.py +0 -0
  62. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/bridge_extractors.py +0 -0
  63. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/cli.py +0 -0
  64. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/config.py +0 -0
  65. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/context.py +0 -0
  66. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/edges.py +0 -0
  67. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/elicit.py +0 -0
  68. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/extensions/pi/codegraph.ts +0 -0
  69. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/github_app.py +0 -0
  70. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/hooks.py +0 -0
  71. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/identity.py +0 -0
  72. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/indexer.py +0 -0
  73. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/ingest.py +0 -0
  74. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/maintenance.py +0 -0
  75. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/output.py +0 -0
  76. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/package_map.py +0 -0
  77. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries/bridge.gq +0 -0
  78. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries/code_mutations.gq +0 -0
  79. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries/code_read.gq +0 -0
  80. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries/delete.gq +0 -0
  81. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries_ts/bash.scm +0 -0
  82. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries_ts/hcl.scm +0 -0
  83. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries_ts/python.scm +0 -0
  84. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries_ts/sql.scm +0 -0
  85. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries_ts/typescript.scm +0 -0
  86. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/queries_ts/yaml.scm +0 -0
  87. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/reaper.py +0 -0
  88. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/remote/__init__.py +0 -0
  89. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/remote/oidc.py +0 -0
  90. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/remote/proxy.py +0 -0
  91. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/remote/store.py +0 -0
  92. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/repo.py +0 -0
  93. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/schema/bridge-schema.pg +0 -0
  94. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/schema/code-schema.pg +0 -0
  95. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/setup.py +0 -0
  96. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/skills/witan-code/SKILL.md +0 -0
  97. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/stitch.py +0 -0
  98. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/store.py +0 -0
  99. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/views.py +0 -0
  100. {witan_code-0.13.3 → witan_code-0.13.5}/witan_code/visualize.py +0 -0
@@ -6,6 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/) (pre-1.0:
7
7
  a MINOR bump may include breaking changes).
8
8
 
9
+ ## [0.13.5] - 2026-08-21
10
+
11
+ ### Changed
12
+
13
+ - Raised the `witan-core` floor to `>=0.28` for the refreshed omnigraph
14
+ `edge` digest (see witan-core's CHANGELOG) — a version below it fails
15
+ `witan-code setup`'s checksum and leaves the indexer with no binary to
16
+ shell out to.
17
+
18
+ ## [0.13.4] - 2026-08-19
19
+
20
+ ### Changed
21
+
22
+ - **Every `code_*` tool parameter now carries a description in its JSON
23
+ Schema.** Seven parameters across seven tools had none — the `symbol_id`
24
+ argument of `code_callers`, `code_find_references`, `code_impact`, and
25
+ `code_cross_repo_impact`, the `repo` filter on `code_find_definition` and
26
+ `code_search_symbol`, and `branch` on `code_indexed_branches`. FastMCP
27
+ sends these schemas to the model, so an undescribed parameter leaves the
28
+ calling agent guessing. `symbol_id` in particular now says where the value
29
+ comes from (the `symbol_id` field of `code_find_definition` /
30
+ `code_search_symbol`) and what shape it has.
31
+
9
32
  ## [0.13.3] - 2026-08-18
10
33
 
11
34
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: witan-code
3
- Version: 0.13.3
3
+ Version: 0.13.5
4
4
  Summary: witan-code — tree-sitter code graph + cross-repo bridge (mounts under `witan code`)
5
5
  Project-URL: Homepage, https://github.com/mitodl/agent-kit/tree/main/mcp/servers/witan-code
6
6
  Project-URL: Repository, https://github.com/mitodl/agent-kit
@@ -26,7 +26,7 @@ Requires-Dist: tree-sitter-sql<0.4,>=0.3
26
26
  Requires-Dist: tree-sitter-typescript<0.24,>=0.23
27
27
  Requires-Dist: tree-sitter-yaml<0.8,>=0.7
28
28
  Requires-Dist: tree-sitter<0.26,>=0.25
29
- Requires-Dist: witan-core[cli,observability,remote,sentry]<1,>=0.24
29
+ Requires-Dist: witan-core[cli,observability,remote,sentry]<1,>=0.28
30
30
  Provides-Extra: tasks
31
31
  Requires-Dist: fastmcp-tasks<5,>=4.0.0b1; extra == 'tasks'
32
32
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "witan-code"
3
- version = "0.13.3"
3
+ version = "0.13.5"
4
4
  description = "witan-code — tree-sitter code graph + cross-repo bridge (mounts under `witan code`)"
5
5
  readme = "README.md"
6
6
  license = "BSD-3-Clause"
@@ -78,7 +78,16 @@ dependencies = [
78
78
  # published, so anything resolving below 0.24 would silently install
79
79
  # without sentry-sdk (or error on the unknown extra) rather than getting
80
80
  # Sentry reporting at all.
81
- "witan-core[cli,remote,observability,sentry]>=0.24,<1",
81
+ #
82
+ # ★ >=0.28 IS NOT ABOUT AN IMPORT, same exception witan-council's floor
83
+ # documents: witan-core 0.28.0 carries the current omnigraph `edge`
84
+ # digest, and every version below it fails `witan setup`'s checksum and
85
+ # installs no binary at all — indexer tests skip without one
86
+ # (tests/conftest.py) and a real indexer run has nothing to shell out to.
87
+ # Expect this floor to keep moving while omnigraph 0.10.0 stays on the
88
+ # moving `edge` tag; see
89
+ # packages/witan-core/witan_core/omnigraph_install.py.
90
+ "witan-core[cli,remote,observability,sentry]>=0.28,<1",
82
91
  "fastmcp>=3.4.2,<5",
83
92
  "cyclopts>=4,<5",
84
93
  # [targets.<name>] override models (config.py) — also transitively pulled
@@ -162,7 +171,7 @@ testpaths = ["tests"]
162
171
  packages = ["witan_code"]
163
172
 
164
173
  [tool.bumpversion]
165
- current_version = "0.13.3"
174
+ current_version = "0.13.5"
166
175
  allow_dirty = true
167
176
 
168
177
  [[tool.bumpversion.files]]
@@ -0,0 +1,49 @@
1
+ """Every `code_*` tool parameter must carry a description in its schema.
2
+
3
+ The witan-council twin of this file explains the reasoning at length; briefly:
4
+ FastMCP derives each tool's JSON Schema from its docstring's numpydoc
5
+ ``Parameters`` section, and that schema is what the calling model sees. Seven
6
+ parameters here — including the ``symbol_id`` of ``code_callers``,
7
+ ``code_find_references``, ``code_impact`` and ``code_cross_repo_impact`` —
8
+ reached the model with nothing but a name and a type, and the existing
9
+ ``list_tools`` coverage asserts only that ``code_reindex`` exists, so a
10
+ regression would not have been reported.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import asyncio
16
+
17
+
18
+ def _tool_properties() -> list[tuple[str, str, dict]]:
19
+ """(tool, parameter, schema) for every exposed parameter of every tool."""
20
+ from witan_code import server as code_server
21
+
22
+ tools = asyncio.run(code_server.mcp._list_tools())
23
+ return [
24
+ (tool.name, name, schema)
25
+ for tool in tools
26
+ for name, schema in ((tool.parameters or {}).get("properties", {})).items()
27
+ ]
28
+
29
+
30
+ def test_every_tool_parameter_has_a_description():
31
+ missing = [
32
+ f"{tool}.{param}"
33
+ for tool, param, schema in _tool_properties()
34
+ if not (schema.get("description") or "").strip()
35
+ ]
36
+ assert not missing, (
37
+ f"{len(missing)} tool parameter(s) reach the model with no description. "
38
+ "Add a numpydoc `Parameters` entry for each in witan_code/server.py:\n "
39
+ + "\n ".join(sorted(missing))
40
+ )
41
+
42
+
43
+ def test_the_tool_surface_is_actually_being_inspected():
44
+ """Guard the guard — an empty listing would make the assertion vacuous."""
45
+ properties = _tool_properties()
46
+ assert len(properties) > 20, (
47
+ f"only {len(properties)} tool parameters found; the code_* surface is "
48
+ "larger than that, so the schema inspection is probably broken"
49
+ )
@@ -249,11 +249,19 @@ class OmnigraphClient(_BaseOmnigraphClient):
249
249
  f"omnigraph commit list returned no commit array for branch "
250
250
  f"{name!r}: {parsed!r}"
251
251
  )
252
+ # ★ TWO FIELD NAMES, ONE MEANING. omnigraph's 2026-08-20 vocabulary
253
+ # sweep (upstream ecf1d6aedd, #538) renamed `manifest_branch` to
254
+ # `graph_branch` in `commit list --json` without bumping the reported
255
+ # version, so both are in the wild. Reading only one is not a cosmetic
256
+ # miss here: no row matches, `stamps` is empty, and this returns None —
257
+ # which the docstring above makes load-bearing as "never reap this
258
+ # view". The reaper would then quietly stop reaping anything at all,
259
+ # and nothing would raise to say so.
252
260
  stamps = [
253
261
  row["created_at"]
254
262
  for row in commits
255
263
  if isinstance(row, dict)
256
- and row.get("manifest_branch") == name
264
+ and name in (row.get("manifest_branch"), row.get("graph_branch"))
257
265
  and isinstance(row.get("created_at"), (int, float))
258
266
  ]
259
267
  # created_at is microseconds since the epoch.
@@ -424,6 +424,12 @@ async def code_find_definition(
424
424
  ----------
425
425
  name:
426
426
  Bare name (``run``) or qualified name (``Service.run``).
427
+ repo:
428
+ Canonical repo URI to search. Defaults to the repo detected from the
429
+ checkout, and fans out across every indexed repo only when no repo is
430
+ detected at all. Note this differs from the witan memory/task tools:
431
+ ``repo=""`` does **not** force a fan-out here — it is falsy, so it
432
+ behaves exactly like omitting the argument.
427
433
  branch:
428
434
  Git branch whose indexed view to query (e.g. another agent's in-flight
429
435
  branch). Defaults to the checkout's branch when querying the current
@@ -464,6 +470,13 @@ async def code_find_references(
464
470
 
465
471
  Supersets code_callers (references includes calls); use code_callers when
466
472
  you want calls only. Heuristic — may miss or over-report.
473
+
474
+ Parameters
475
+ ----------
476
+ symbol_id:
477
+ The symbol to start from, as returned in the ``symbol_id`` field of
478
+ code_find_definition or code_search_symbol. Form:
479
+ ``<repo>#<path/to/file.py>::<QualifiedName>``.
467
480
  """
468
481
  client = _client_for_symbol(symbol_id)
469
482
  if client is None:
@@ -483,6 +496,13 @@ async def code_callers(symbol_id: str, ctx: Context | None = None) -> list[dict]
483
496
 
484
497
  Heuristic name-resolution based; not a precise call graph. For calls plus
485
498
  other references use code_find_references.
499
+
500
+ Parameters
501
+ ----------
502
+ symbol_id:
503
+ The symbol to start from, as returned in the ``symbol_id`` field of
504
+ code_find_definition or code_search_symbol. Form:
505
+ ``<repo>#<path/to/file.py>::<QualifiedName>``.
486
506
  """
487
507
  client = _client_for_symbol(symbol_id)
488
508
  if client is None:
@@ -508,6 +528,12 @@ async def code_impact(
508
528
 
509
529
  Parameters
510
530
  ----------
531
+ symbol_id:
532
+ The symbol to start from, as returned in the ``symbol_id`` field of
533
+ code_find_definition or code_search_symbol. Form:
534
+ ``<repo>#<path/to/file.py>::<QualifiedName>``.
535
+ This is the symbol you are about to change; the result is its blast
536
+ radius.
511
537
  max_depth:
512
538
  Maximum BFS depth (default 5).
513
539
  max_nodes:
@@ -635,6 +661,13 @@ def code_search_symbol(
635
661
  ``class``, ``module``, ``variable``, ``interface``, ``type``, ``enum``,
636
662
  ``key``, ``table``, ``cte``, or ``block``. Pass e.g. ``kind="function"``
637
663
  to exclude the many YAML ``key`` symbols when searching for code.
664
+ repo:
665
+ Canonical repo URI to search. Defaults to the repo detected from the
666
+ checkout, and fans out across every indexed repo only when no repo is
667
+ detected at all — ``repo=""`` does **not** force that, unlike the witan
668
+ memory/task tools; it is falsy and behaves like omitting the argument.
669
+ BM25 ranking is per-store, so a fan-out concatenates each store's
670
+ ranked results rather than producing one global ordering.
638
671
  branch:
639
672
  Git branch whose indexed view to query. Defaults to the checkout's
640
673
  branch when querying the current repo; when ``repo`` names a different
@@ -767,6 +800,11 @@ async def code_cross_repo_impact(
767
800
 
768
801
  Parameters
769
802
  ----------
803
+ symbol_id:
804
+ The symbol whose cross-repo surface to trace, as returned in the
805
+ ``symbol_id`` field of code_find_definition or code_search_symbol. Its
806
+ repo prefix also scopes the bridge read, so asking about another repo's
807
+ symbol does not pick up an unrelated overlay from your own checkout.
770
808
  min_precision:
771
809
  ``heuristic`` (default) | ``precise`` — see server instructions.
772
810
  """
@@ -1018,6 +1056,13 @@ def code_indexed_branches(branch: str | None = None) -> list[dict]:
1018
1056
  sanitized git branch it is a view of, ``actor`` its owner (null on a
1019
1057
  single-writer local store). ``views`` is null for a store that could not be
1020
1058
  listed.
1059
+
1060
+ Parameters
1061
+ ----------
1062
+ branch:
1063
+ A raw git branch name (not a view name) to filter by, showing every
1064
+ writer's view of that one branch — this is how you find a teammate's
1065
+ in-flight work. Omit to list every view of every indexed repo.
1021
1066
  """
1022
1067
  wanted = repo_module.branch_store_name(branch) if branch else None
1023
1068
 
File without changes
File without changes
File without changes
File without changes