feat(cli): add event protocol and GitHub context adapter#23
Conversation
Abdulmuiz44
commented
Jun 2, 2026
- Adds Codra CLI foundation with codra run --task .
- Adds JSONL event protocol for agent runs.
- Adds GitHub Actions context adapter for PR/issue metadata.
- Adds local git fallback context.
- Implements deterministic review-pr, explain-issue, and summarize-context task runners.
- Does not call AI providers or require API keys.
- Prepares Codra for future GitHub Action and interactive bot phases.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 28d4d71c14
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| fn build_pr_summary(pr: &crate::context::types::CodraPullRequestContext) -> Value { | ||
| let title = pr.title.as_deref().unwrap_or("(no title)"); | ||
| let file_count = pr.changed_files.as_ref().map(|f| f.len()).unwrap_or(0); |
There was a problem hiding this comment.
Report missing PR stats as unknown
When this runs without GITHUB_TOKEN (documented as optional) or when API enrichment fails, pr.changed_files stays None, but this path reports Changed files: 0 (+0/-0) for an actual PR. That corrupts the review summary and can hide large/high-risk changes; treat missing enrichment as unknown or use counts available from the webhook/API response instead of defaulting to zero.
Useful? React with 👍 / 👎.
| .push("GitHub API: failed to fetch pull request details".to_string()); | ||
| } | ||
|
|
||
| let files_url = format!("{base}/pulls/{number}/files?per_page={MAX_CHANGED_FILES}"); |
There was a problem hiding this comment.
For PRs touching more than 100 files, this request only reads page 1, so changedFiles, totals, and risk detection silently omit the rest of the diff. GitHub documents this endpoint as paginated with per_page max 100 and a page parameter (https://docs.github.com/en/rest/pulls/pulls#list-pull-requests-files), so the adapter should either follow pagination or clearly mark the result as truncated.
Useful? React with 👍 / 👎.
| if p.len() <= MAX_PATCH_LEN { | ||
| p.to_string() | ||
| } else { | ||
| format!("{}… [truncated]", &p[..MAX_PATCH_LEN]) |
There was a problem hiding this comment.
When a fetched patch or diff exceeds 32 KB and byte 32000 lands inside a non-ASCII UTF-8 character, this slice panics because Rust string indices must be character boundaries. That makes the whole CLI fail on otherwise valid PRs containing long Unicode diffs; truncate via char_indices or another boundary-safe method instead.
Useful? React with 👍 / 👎.
| for marker in ["ghp_", "github_pat_", "Bearer ", "Authorization:"] { | ||
| if let Some(idx) = out.find(marker) { | ||
| let end = out[idx..] | ||
| .find(|c: char| c.is_whitespace() || c == '\n') |
There was a problem hiding this comment.
Redact credentials after auth markers
If a logged error contains a standard header like Authorization: Bearer ghs_..., this delimiter search stops at the space inside the marker itself, so only Bearer/Authorization: is replaced and the token remains in the warning or failure message. Since this helper is used before emitting errors, redact through the credential value (and cover GitHub ghs_ tokens) rather than stopping at the marker's first whitespace.
Useful? React with 👍 / 👎.
| "issue_comment" => { | ||
| if let Some(issue) = payload.get("issue") { | ||
| merge_issue(ctx, issue); |
There was a problem hiding this comment.
Preserve the triggering issue comment
For issue_comment workflows without GITHUB_TOKEN (which the README says is optional), the event payload already includes the comment that triggered the run, but this branch only copies the issue object and leaves issue.comments empty. As a result explain-issue reports zero comments and omits the user's actual request/comment body unless API enrichment succeeds; parse the payload's comment field into the context before relying on the comments API.
Useful? React with 👍 / 👎.