Commit Graph

115 Commits

Author SHA1 Message Date
Marcos 4129f217fa fix(post): anchor inline review comments via new_position (Gitea 1.26.x)
Gitea 1.26.x's POST /pulls/{i}/reviews does NOT honor the line/side fields
used by newer Gitea — it silently drops them, leaving the comment unpositioned.
Gitea then renders a file-level review comment on EVERY diff line of the file,
so a 5-finding review on a 25-line diff showed ~125 comment blocks in the
Files Changed view (the flood reported on canalhandia PR #2).

The 1.26 schema anchors inline review comments with new_position (line in the
post-change file) + old_position: 0. f["line"] is already a validated
post-change (RIGHT-side) line from split_findings, so it maps directly to
new_position. Verified: new_position=98 -> position=98 + populated diff_hunk
(positioned, renders on line 98 only); the old line/side form -> position=0,
empty diff_hunk (unpositioned).

49 tests pass (no test asserted the POST payload shape).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-18 00:54:13 +00:00
Marcos c7c6c3edd2 fix(opencode): resolve /usr/local/bin -> /usr/bin opencode path in pod
The npm prefix in the Dockerfile is /usr, so opencode installs to
/usr/bin/opencode (symlink to /usr/lib/node_modules/...), not
/usr/local/bin/opencode. The cluster E2E failed with ENOENT on
/usr/local/bin/opencode. Fix in three places:
- Dockerfile ENV PRAGENT_OPENCODE_BIN=/usr/bin/opencode
- ~/k8s/pragent-webhook.yaml env value
- _opencode_bin() now defensive: if the configured path is missing,
  falls back to shutil.which('opencode') before the linuxbrew last-resort.
- Dockerfile + README deploy notes: containerd import is sudoless via
  the group-readable raw socket (the microk8s ctr wrapper sudo-wraps).

Verified: rebuilt + reimported + rolled out; PR #5 (sha 985061c0) review
posted in-pod via the opencode engine (findings=2 inline=2 ok=True),
summary + 2 [CRITICAL] inline comments with suggestions + refs + sha marker.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 23:31:53 +00:00
Marcos 8912f6721b deploy: combined opencode image + k8s + docs
- pilot/Dockerfile: python:3.12-slim + node 20 + opencode-ai@1.3.10 +
  ripgrep + pyright/typescript-language-server/eslint (npm) + ruff (pip).
  Factory + pilot scripts baked at /app. imagePullPolicy: Never (local
  import into microk8s containerd).
- .dockerignore: lean build context.
- ~/k8s/pragent-webhook.yaml: image pragent-webhook:opencode, emptyDir work
  at /tmp/pragent-work, env (PRAGENT_ENGINE, OPENCODE_MODEL, PRAGENT_FACTORY_DIR,
  PRAGENT_OPENCODE_BIN, PRAGENT_WORK_ROOT, PRAGENT_RTK_DIR='', timeout 540),
  resources 200m/512Mi -> 1500m/2Gi. Drops the ConfigMap scripts volume.
- pilot/README-webhook.md + .opencode/README.md: opencode engine section,
  build/import/apply steps, factory guide fixes (parse_review_output, steps).

Image builds (1.62GB, smoke-tested: opencode+LSPs+factory+env all present).
Import into microk8s containerd + apply pending (ctr needs sudo).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 23:11:58 +00:00
Marcos 6e3a9eb5b0 feat: opencode review engine + .opencode factory
Replace the single Python model-call reviewer with an opencode agent
factory. A primary 'pragent' agent reads a brief (title/body/diff/config/
prior reviews), inspects the checked-out repo, runs the repo's own linters
via bash, loads review-methodology + findings-schema skills, and emits a
{summary, findings} JSON with per-finding severity/path/line/problem/fix/
suggestion/reference. Dormant security/tests/perf subagent lenses fan out
only on large/risky diffs (lean by default).

pilot/opencode_review.py: fetches the repo archive at the head sha into a
temp workdir, writes .pragent/brief.md, drops the factory, runs
'opencode run --pure --agent pragent --dir <workdir>' headlessly. Isolates
HOME (shared, warmed), strips ANTHROPIC_* env (leaked host vars caused
ProviderModelNotFoundError), stdin=DEVNULL (opencode blocks on stdin),
maps the bare OLLAMA_MODEL to the provider-prefixed ref. No Gitea I/O —
ai_review.review_pr parses + anchors + posts (reuses all v2 logic/tests).

PRAGENT_ENGINE=opencode (default) selects it; =ollama keeps the legacy
direct-call path. Verified end-to-end: posts a real review with a summary
section, inline [CRITICAL]/[HIGH] comments + apply-able suggestions +
reference links, and the sha dedupe marker. 49 tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 23:01:59 +00:00
Marcos 8758b22802 docs: techspark user webhook (id=6) + org-webhook note + cleanup token
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 20:38:14 +00:00
Marcos 90cea84f6f pilot: dedupe + repo config + inline comments w/ suggestions
- Dedupe: Gitea-as-state. Scan existing reviews for a hidden
  <!-- pragent:sha=... --> marker matching the head sha; skip if present
  (kills duplicate reviews on label-toggle / re-fire). Prior review bodies
  fed back as 'already said' context (light framework §6.1).
- Repo-local focus: optional .pr-review.json at repo root
  ({focus,exclude_paths,languages,instructions}), fetched at head ref.
- Inline comments + apply-able suggestions: model emits JSON findings
  {severity,path,line,problem,fix,suggestion}; diff hunks parsed into valid
  (path,new_line) RIGHT-side anchors; anchored findings become positional
  review comments with a ```suggestion fence (Gitea apply-button);
  unanchored findings fold into the summary body.
- Tests: parse_diff_anchors, parse_findings (tolerant JSON), split_findings,
  inline_comment_body, summary_bullets, parse_repo_config, reviewed_shas,
  prior_review_bodies, sha-marker. 35 pass.
- Bump OLLAMA_MAX_TOKENS default 6000 -> 8000 (suggestions add length).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 19:59:36 +00:00
Marcos 789fb38bae pilot: central webhook service (user-level Gitea webhook + AI-REVIEW gate)
- pilot/webhook_server.py: stdlib HTTP receiver. HMAC-verifies X-Gitea-Signature,
  gates on pull_request action + AI-REVIEW label, runs review_pr in a background
  thread (responds 202 immediately so Gitea's delivery timeout never fires).
  Accepts both GitHub-style (labeled/synchronize) and Gitea event-type-style
  (label_updated/synchronized) action names.
- pilot/ai_review.py: extract review_pr() core so both the CI run() and the
  webhook server share one review path. run() is now an env-driven wrapper.
- pilot/README-webhook.md: architecture, onboarding, one-time per-owner
  user-webhook setup, the Gitea 1.26.1 system-webhook bug, the SSRF
  ALLOWED_HOST_LIST change, K8s deploy + script-update recipe.
- README.md + design doc: note the webhook service as the preferred delivery
  path (partially reverses 'central webhook = non-goal', pilot only).

Gitea 1.26.1 system webhooks broken (POST /admin/hooks -> 201 but never
persists); user-level webhooks (one per repo-owner) are the working fallback.
Gitea SSRF allow-list blocks in-cluster webhook targets by default; required a
scoped [webhook] ALLOWED_HOST_LIST addition + gitea restart.

E2E verified 2026-08-17: pragent-bot reviewed gitea_admin/pragent PR #2 and
masi/portfolio PR #3 via the webhook service (glm-5.2:cloud).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 19:38:07 +00:00
gitea_admin 9379b52334 retire self-CI AI review workflow (central webhook service takes over) 2026-08-17 19:31:43 +00:00
Marcos 0baefad4ad ci: enable pragent pilot self-review on this repo
Adds .gitea/workflows/ai-review.yml so pragent dogfoods its own pilot: PRs
with the AI-REVIEW label get reviewed by pragent-bot.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 18:20:52 +00:00
Marcos c4dab0f38a fix(pilot): use correct Gitea raw API path (?ref=main) in workflow template
The previous /raw/branch/main/<path> form 404s on private repos; Gitea's raw
endpoint is /raw/<path>?ref=<ref>. Verified the bot token fetches the script
with the corrected form.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 18:20:06 +00:00
Marcos 6f012e9b66 feat(pilot): minimal AI review bot for Gitea Actions
Ships a working pragent pilot ahead of the framework build (design doc
deferred). Single stdlib-only reviewer script fetched at runtime by a per-repo
Gitea Action; reviews fire only on PRs with the AI-REVIEW label; model is
glm-5.2:cloud via the on-network headroom proxy; fail-open.

- pilot/ai_review.py: fetch PR diff, call model, post review as pragent-bot
- pilot/workflow-template.yml: per-repo Gitea Action gated on AI-REVIEW label
- pilot/README.md: onboarding (bot collaborator + secret + workflow + label)
- tests/pilot/test_ai_review.py: 15 unit tests for pure helpers (no network)
- README/design doc: note pilot is the bootstrap; framework build deferred

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 18:18:06 +00:00
Marcos 8a4239a9d9 docs: rework design after prior-art review
Red Hat's MIT ai-code-review already implements phases 1-2 (four forge clients,
six providers, CI integration, repo context file). Adds a research writeup,
inserts Phase 0 (evaluate it before building), and folds in seven requirements
the original design missed — chiefly prior-comment synthesis, without which our
own 1.7-runs-per-PR assumption means every push re-posts dismissed findings.

Amends implementation tasks 4, 5, 6, 9, 10 and gates the subagent briefs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ye1KNFMkkUtmzTypHXkoK
2026-08-04 17:27:15 +00:00
Marcos 8d690f5717 docs: add subagent dispatch briefs for phase 1
Per-task briefs a cold subagent can execute without conversation history:
objective, deliverables, constraints, done criteria, likely failure modes.
Adds orchestrator instructions (dependency graph, model tiers, dispatch loop,
stopping conditions), a shared context block, a review gate checklist, and
notes for running the plan on a non-Claude model.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ye1KNFMkkUtmzTypHXkoK
2026-08-04 17:21:17 +00:00
Marcos 9b017475c9 docs: add phase 1 implementation plan
TDD task breakdown for the walking skeleton: diff parsing, forge adapter port
with a local git implementation, rules-based tiering, config loading, analyzer
runner behind a ModelClient port, pi SDK client, aggregator, JSONL emitter, CLI.
Later phases recorded as milestones with done-when criteria.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ye1KNFMkkUtmzTypHXkoK
2026-08-04 16:40:05 +00:00
Marcos 1c0c576e40 docs: initial pragent design and README
Extensible PR review framework: CLI-in-CI delivery, pi SDK agent loop,
deterministic-plus-LLM tiering, committed repo profile, JSONL/OTel analytics.
Design doc records the decisions, cost model, and rollout phases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ye1KNFMkkUtmzTypHXkoK
2026-08-04 16:35:35 +00:00