feat(robomp): added local issue indexing and commit-search tool support

- Added `ROBOMP_ISSUE_INDEX_SYNC_SECONDS` configuration and lifecycle-managed issue indexing through startup/shutdown hooks.
- Added issue/PR index tables with FTS5 triggers plus upsert and keyword/filter search helpers for indexed records.
- Added GitHub backend/proxy support for `IssueIndexEntry` and issue-index page retrieval, including webhook ingestion and periodic watermark-driven sync.
- Updated `gh_search_issues` to prefer local index queries when synchronized and added `search_commits` host tool with query modes and validation.
This commit is contained in:
can1357
2026-07-15 00:46:08 +02:00
parent 8e2aa9ea94
commit e426186e46
16 changed files with 1129 additions and 29 deletions
+36
View File
@@ -25,6 +25,7 @@ from robomp.git_ops import GitCommandError, HeadDriftError, PushResult
from robomp.github_client import (
CommentInfo,
GitHubError,
IssueIndexEntry,
IssueInfo,
IssueSummary,
PullRequestFileInfo,
@@ -212,6 +213,20 @@ class GitHubProxyClient:
)
return [_issue_summary_from(item) for item in (data.get("items") if isinstance(data, dict) else None) or []]
async def list_issue_index_entries(
self,
repo: str,
*,
since: str | None = None,
page: int = 1,
per_page: int = 100,
) -> list[IssueIndexEntry]:
params: dict[str, Any] = {"repo": repo, "page": page, "per_page": per_page}
if since:
params["since"] = since
data = await self._request("GET", "/gh/v1/issue_index_entries", params=params)
return [_index_entry_from(item) for item in (data.get("items") if isinstance(data, dict) else None) or []]
async def list_comments(self, repo: str, number: int) -> list[CommentInfo]:
data = await self._request("GET", "/gh/v1/comments", params={"repo": repo, "number": number})
return [_comment_from(item) for item in (data.get("items") if isinstance(data, dict) else None) or []]
@@ -511,6 +526,27 @@ def _issue_summary_from(data: Any) -> IssueSummary:
)
def _index_entry_from(data: Any) -> IssueIndexEntry:
if not isinstance(data, dict):
raise GitHubError(500, "proxy returned malformed issue index payload")
return IssueIndexEntry(
repo=str(data["repo"]),
number=int(data["number"]),
is_pull_request=bool(data.get("is_pull_request")),
title=str(data.get("title") or ""),
body=str(data.get("body") or ""),
state=str(data.get("state") or ""),
state_reason=str(data.get("state_reason") or ""),
merged_at=str(data.get("merged_at") or ""),
author=str(data.get("author") or ""),
labels=tuple(str(x) for x in (data.get("labels") or [])),
comments=int(data.get("comments") or 0),
created_at=str(data.get("created_at") or ""),
updated_at=str(data.get("updated_at") or ""),
html_url=str(data.get("html_url") or ""),
)
def _comment_from(data: Any) -> CommentInfo:
if not isinstance(data, dict):
raise GitHubError(500, "proxy returned malformed comment payload")