granthi-review v1: estate-wide AI code review service

Webhook-driven central review service for Granthi forges: HMAC-verified
push/pull_request webhooks, per-repo serialization with global LLM
concurrency 1, shre-router powered rubric review (8 axes, strict JSON,
tolerant extractor + retry), commit statuses + PR scorecard comments,
sqlite attribution ledger with Co-Authored-By trailer parsing, per-repo
HTML history dashboard, nightly per-agent digests, fail-open-with-
visibility when the router is unavailable.

Posture: BLOCK on confirmed critical/high correctness+security findings;
admin merge is the human override.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Nirav Patel
2026-08-18 23:24:27 -04:00
co-authored by Claude Fable 5
commit 9ffd810943
22 changed files with 1255 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
// shre-router client. POST /v1/chat with stream:false.
// Real model answer lives in .message.content; top-level .content can carry an
// upstream-down apology — always prefer .message.content.
export async function chat({ routerUrl, model, messages, agentId, sessionId, tenantId, timeoutMs }) {
const res = await fetch(`${routerUrl.replace(/\/$/, '')}/v1/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model, messages, agentId, sessionId, tenantId, stream: false }),
signal: AbortSignal.timeout(timeoutMs)
});
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`router -> ${res.status}: ${text.slice(0, 300)}`);
}
const data = await res.json();
const content = data?.message?.content ?? data?.content;
if (typeof content !== 'string' || !content.trim()) {
throw new Error('router returned empty content');
}
return content;
}