repograph-codeintel 0.1.1__tar.gz → 0.1.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 (25) hide show
  1. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/PKG-INFO +2 -2
  2. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/README.md +1 -1
  3. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/pyproject.toml +1 -1
  4. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/__init__.py +1 -1
  5. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/agent_setup.py +57 -9
  6. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/cli.py +9 -6
  7. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/mcp_server.py +3 -2
  8. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph_codeintel.egg-info/PKG-INFO +2 -2
  9. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/LICENSE +0 -0
  10. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/setup.cfg +0 -0
  11. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/__main__.py +0 -0
  12. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/config.py +0 -0
  13. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/extract.py +0 -0
  14. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/impact.py +0 -0
  15. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/indexer.py +0 -0
  16. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/query.py +0 -0
  17. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/resolve.py +0 -0
  18. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/scanner.py +0 -0
  19. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/store.py +0 -0
  20. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph/test_gate.py +0 -0
  21. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph_codeintel.egg-info/SOURCES.txt +0 -0
  22. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph_codeintel.egg-info/dependency_links.txt +0 -0
  23. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph_codeintel.egg-info/entry_points.txt +0 -0
  24. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph_codeintel.egg-info/requires.txt +0 -0
  25. {repograph_codeintel-0.1.1 → repograph_codeintel-0.1.2}/src/repograph_codeintel.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: repograph-codeintel
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Evidence-backed codebase intelligence and change-impact analysis for AI coding agents
5
5
  Author: RepoGraph contributors
6
6
  License: Apache-2.0
@@ -150,7 +150,7 @@ One command registers the server **and** installs the instructions that make the
150
150
  repograph setup .
151
151
  ```
152
152
 
153
- It writes a project `.mcp.json` plus a Claude Code skill (and a Cursor rule when `.cursor/` exists), shows the diff first, and backs up any file it changes. Add `--client codex` to register it in `~/.codex/config.toml`; `--dry-run` writes nothing.
153
+ It writes a project `.mcp.json` plus a Claude Code skill (and a Cursor rule when `.cursor/` exists), shows the diff first, and backs up any file it changes. Add `--client codex` to register it in `~/.codex/config.toml`, or `--client opencode` to register it in `opencode.json` and write the instructions into `AGENTS.md`; `--dry-run` writes nothing.
154
154
 
155
155
  Restart your agent, then ask:
156
156
 
@@ -121,7 +121,7 @@ One command registers the server **and** installs the instructions that make the
121
121
  repograph setup .
122
122
  ```
123
123
 
124
- It writes a project `.mcp.json` plus a Claude Code skill (and a Cursor rule when `.cursor/` exists), shows the diff first, and backs up any file it changes. Add `--client codex` to register it in `~/.codex/config.toml`; `--dry-run` writes nothing.
124
+ It writes a project `.mcp.json` plus a Claude Code skill (and a Cursor rule when `.cursor/` exists), shows the diff first, and backs up any file it changes. Add `--client codex` to register it in `~/.codex/config.toml`, or `--client opencode` to register it in `opencode.json` and write the instructions into `AGENTS.md`; `--dry-run` writes nothing.
125
125
 
126
126
  Restart your agent, then ask:
127
127
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "repograph-codeintel"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "Evidence-backed codebase intelligence and change-impact analysis for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,3 +1,3 @@
1
1
  """RepoGraph: evidence-backed codebase intelligence for AI coding agents."""
2
2
 
3
- __version__ = "0.1.1"
3
+ __version__ = "0.1.2"
@@ -31,8 +31,8 @@ repository code.
31
31
  ## When to call
32
32
 
33
33
  Call `analyze_change_impact` before a change that crosses a file boundary:
34
- renaming or moving a symbol, changing a signature, editing a shared module, a
35
- route handler, or a database model.
34
+ renaming, moving or deleting a symbol or a file, changing a signature, editing a
35
+ shared module, a route handler, or a database model.
36
36
 
37
37
  Skip it for edits fully contained in one file with no importers, for prose or
38
38
  dependency bumps, and for runtime-behaviour questions — the graph is static.
@@ -96,7 +96,9 @@ def server_entry(root: Path) -> dict[str, object]:
96
96
  return {"command": sys.executable, "args": ["-m", "repograph", *args]}
97
97
 
98
98
 
99
- def _merge_json(path: Path, key: str, entry: dict[str, object], note: str) -> Change:
99
+ def _merge_json(
100
+ path: Path, keys: str | tuple[str, ...], entry: dict[str, object], note: str
101
+ ) -> Change:
100
102
  before = path.read_text(encoding="utf-8") if path.is_file() else ""
101
103
  try:
102
104
  data = json.loads(before) if before.strip() else {}
@@ -104,11 +106,14 @@ def _merge_json(path: Path, key: str, entry: dict[str, object], note: str) -> Ch
104
106
  raise ValueError(f"{path} is not valid JSON; fix it before running setup") from exc
105
107
  if not isinstance(data, dict):
106
108
  raise ValueError(f"{path} must contain a JSON object")
107
- servers = data.get(key)
108
- if servers is not None and not isinstance(servers, dict):
109
- raise ValueError(f"{path}: {key!r} must be an object")
110
- data.setdefault(key, {})
111
- data[key][SKILL_NAME] = entry
109
+ keys = (keys,) if isinstance(keys, str) else keys
110
+ node = data
111
+ for key in keys:
112
+ child = node.setdefault(key, {})
113
+ if not isinstance(child, dict):
114
+ raise ValueError(f"{path}: {key!r} must be an object")
115
+ node = child
116
+ node[SKILL_NAME] = entry
112
117
  after = json.dumps(data, indent=2, ensure_ascii=False) + "\n"
113
118
  return Change(path=path, before=before, after=after, note=note)
114
119
 
@@ -163,6 +168,32 @@ def _cursor_rule(root: Path) -> Change:
163
168
  return Change(path=path, before=before, after=after, note="Cursor rule")
164
169
 
165
170
 
171
+ AGENTS_START = "<!-- repograph:start (managed by `repograph setup`) -->"
172
+ AGENTS_END = "<!-- repograph:end -->"
173
+
174
+
175
+ def _opencode_entry(entry: dict[str, object]) -> dict[str, object]:
176
+ """OpenCode takes one argv array, unlike Claude/Cursor's command+args pair.
177
+
178
+ Emitting the other shape is silently skipped by the client, so the server
179
+ looks configured but never starts.
180
+ """
181
+ return {"type": "local", "command": [entry["command"], *entry["args"]]} # type: ignore[misc]
182
+
183
+
184
+ def _opencode_rule(root: Path) -> Change:
185
+ """OpenCode reads project instructions from AGENTS.md, keyed by markers."""
186
+ path = root / "AGENTS.md"
187
+ before = path.read_text(encoding="utf-8") if path.is_file() else ""
188
+ block = f"{AGENTS_START}\n{SKILL_BODY}{AGENTS_END}\n"
189
+ pattern = re.compile(r"<!-- repograph:start.*?<!-- repograph:end -->\n?", re.DOTALL)
190
+ if pattern.search(before):
191
+ after = pattern.sub(block, before, count=1)
192
+ else:
193
+ after = before + ("\n" if before and not before.endswith("\n") else "") + block
194
+ return Change(path=path, before=before, after=after, note="OpenCode instructions (AGENTS.md)")
195
+
196
+
166
197
  def detect_clients(root: Path, home: Path) -> list[str]:
167
198
  """Project-scoped clients only.
168
199
 
@@ -173,6 +204,12 @@ def detect_clients(root: Path, home: Path) -> list[str]:
173
204
  found: list[str] = []
174
205
  if (root / ".cursor").is_dir():
175
206
  found.append("cursor")
207
+ if (
208
+ (root / "opencode.json").is_file()
209
+ or (root / ".opencode").is_dir()
210
+ or (home / ".config" / "opencode" / "opencode.json").is_file()
211
+ ):
212
+ found.append("opencode")
176
213
  # Claude Code is the default: it is the client that reads project `.mcp.json`
177
214
  # and the skill directory, and it is where the invocation gap was measured.
178
215
  found.append("claude")
@@ -189,7 +226,7 @@ def plan(
189
226
  home = (home or Path.home()).expanduser().resolve()
190
227
  entry = server_entry(root)
191
228
  changes: list[Change] = []
192
- unknown = set(clients) - {"claude", "cursor", "codex"}
229
+ unknown = set(clients) - {"claude", "cursor", "codex", "opencode"}
193
230
  if unknown:
194
231
  raise ValueError(f"unknown client(s): {', '.join(sorted(unknown))}")
195
232
 
@@ -197,6 +234,17 @@ def plan(
197
234
  changes.append(_merge_json(root / ".mcp.json", "mcpServers", entry, "project MCP config"))
198
235
  if include_skill:
199
236
  changes.append(_skill_file(root))
237
+ if "opencode" in clients:
238
+ changes.append(
239
+ _merge_json(
240
+ root / "opencode.json",
241
+ ("mcp", "servers"),
242
+ _opencode_entry(entry),
243
+ "OpenCode MCP config",
244
+ )
245
+ )
246
+ if include_skill:
247
+ changes.append(_opencode_rule(root))
200
248
  if "cursor" in clients:
201
249
  changes.append(
202
250
  _merge_json(root / ".cursor" / "mcp.json", "mcpServers", entry, "Cursor MCP config")
@@ -377,7 +377,7 @@ def arch(
377
377
  def setup(
378
378
  path: Optional[Path] = typer.Argument(None, help="Repository root (default: cwd)."),
379
379
  client: Optional[list[str]] = typer.Option(
380
- None, "--client", "-c", help="claude, cursor, codex. Repeatable. Default: detected."
380
+ None, "--client", "-c", help="claude, cursor, codex, opencode. Repeatable. Default: detected."
381
381
  ),
382
382
  yes: bool = typer.Option(False, "--yes", "-y", help="Apply without asking."),
383
383
  dry_run: bool = typer.Option(False, "--dry-run", help="Show changes and write nothing."),
@@ -445,11 +445,14 @@ def serve(
445
445
  from .mcp_server import build_server
446
446
 
447
447
  root = _root(path)
448
- try:
449
- server = build_server(root)
450
- except FileNotFoundError as exc:
451
- typer.echo(str(exc), err=True)
452
- raise typer.Exit(1) from exc
448
+ settings = load_settings(root)
449
+ if not settings.db_path.exists():
450
+ typer.echo(
451
+ f"warning: no index at {settings.db_path}; tools return that error until "
452
+ f"`repograph index {root}` runs",
453
+ err=True,
454
+ )
455
+ server = build_server(root)
453
456
  if http:
454
457
  server.settings.host = host
455
458
  server.settings.port = port
@@ -38,8 +38,9 @@ def _store(root: Path) -> Store:
38
38
 
39
39
  def build_server(root: str | Path) -> MCPServer:
40
40
  root = Path(root).expanduser().resolve()
41
- _store(root).close() # fail fast with a clear error if unindexed
42
-
41
+ # No fail-fast here on purpose. An MCP client reports a process exit as a
42
+ # disconnected server, and the agent is then left with no tool to call.
43
+ # Tools return the missing-index error instead, which is actionable.
43
44
  server = MCPServer("repograph", instructions=INSTRUCTIONS, version=__version__)
44
45
 
45
46
  @server.tool(description="Search indexed symbols by name or qualified name. Returns definitions with file:line evidence.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: repograph-codeintel
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Evidence-backed codebase intelligence and change-impact analysis for AI coding agents
5
5
  Author: RepoGraph contributors
6
6
  License: Apache-2.0
@@ -150,7 +150,7 @@ One command registers the server **and** installs the instructions that make the
150
150
  repograph setup .
151
151
  ```
152
152
 
153
- It writes a project `.mcp.json` plus a Claude Code skill (and a Cursor rule when `.cursor/` exists), shows the diff first, and backs up any file it changes. Add `--client codex` to register it in `~/.codex/config.toml`; `--dry-run` writes nothing.
153
+ It writes a project `.mcp.json` plus a Claude Code skill (and a Cursor rule when `.cursor/` exists), shows the diff first, and backs up any file it changes. Add `--client codex` to register it in `~/.codex/config.toml`, or `--client opencode` to register it in `opencode.json` and write the instructions into `AGENTS.md`; `--dry-run` writes nothing.
154
154
 
155
155
  Restart your agent, then ask:
156
156