-
Notifications
You must be signed in to change notification settings - Fork 880
feat(editor): show git blame for current line in status bar #910
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b502645
af93248
023baa1
bda8dfb
2b644ff
1a6b366
81e752f
df23232
9bf6a2d
2a5d3b2
b679121
a22273a
bf8faf9
fec2a7d
8a76492
74b3f6c
497e6b8
2f9e17f
a893d44
1b92a83
14c1ae1
d292c64
f61a0c8
10c67c3
e454866
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| --- | ||
| name: terax-pr-workflow | ||
| description: Use this skill whenever making ANY change to this repository — features, fixes, shortcuts, refactors, anything. It enforces the mandatory branch → commit → dual-PR (fork + upstream) → merge-fork → back-to-main workflow. Trigger on phrases like "create a PR", "add a feature", "fix this", "push this", "open a pull request", or any task that involves committing and shipping code changes. | ||
| user-invocable: true | ||
| --- | ||
|
|
||
| # Terax PR Workflow | ||
|
|
||
| Every change to this repo MUST follow this exact workflow. No exceptions. | ||
|
|
||
| ## Remotes | ||
|
|
||
| - `origin` → `https://github.com/roberto-fernandino/terax-ai-fork.git` (the fork — you have write access) | ||
| - `upstream` → `https://github.com/crynta/terax-ai.git` (the original — NO push access, use cross-fork PRs) | ||
|
|
||
| ## Step-by-step | ||
|
|
||
| ### 1. Create a branch | ||
|
|
||
| ```bash | ||
| git checkout main | ||
| git pull origin main | ||
| git checkout -b feat/<descriptive-name> | ||
| # or fix/<name>, chore/<name>, etc. | ||
| ``` | ||
|
|
||
| Branch name must be kebab-case and describe the change. | ||
|
|
||
| ### 2. Make the changes | ||
|
|
||
| Implement the feature/fix. Type-check before committing: | ||
|
|
||
| ```bash | ||
| npx tsc --noEmit | ||
| ``` | ||
|
|
||
| ### 3. Commit | ||
|
|
||
| Stage only the relevant files (never `git add -A` blindly): | ||
|
|
||
| ```bash | ||
| git add <specific files> | ||
| git commit -m "$(cat <<'EOF' | ||
| feat/fix/chore(scope): short imperative description | ||
|
|
||
| Longer explanation if needed. | ||
|
|
||
| Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> | ||
| EOF | ||
| )" | ||
| ``` | ||
|
|
||
| ### 4. Push to fork | ||
|
|
||
| ```bash | ||
| git push origin <branch-name> | ||
| ``` | ||
|
|
||
| ### 5. Check for existing open PRs — BEFORE creating new ones | ||
|
|
||
| **This step is mandatory.** Before opening any PR, check whether one already exists for the same feature area: | ||
|
|
||
| ```bash | ||
| gh pr list --repo roberto-fernandino/terax-ai-fork --state open | ||
| gh pr list --repo crynta/terax-ai --author roberto-fernandino --state open | ||
| ``` | ||
|
|
||
| - If an open PR exists for the same feature/area → push commits to that branch and update the existing PR. Do NOT create a new one. | ||
| - Only create a new PR if no related open PR exists. | ||
|
|
||
| Related means: same feature, same subsystem, or a fix that belongs to an in-progress feature branch. When in doubt, add to the existing PR. | ||
|
|
||
| ### 6. Create PR on the fork (roberto-fernandino/terax-ai-fork) | ||
|
|
||
| Only if no existing open PR covers this change: | ||
|
|
||
| ```bash | ||
| gh pr create \ | ||
| --repo roberto-fernandino/terax-ai-fork \ | ||
| --base main \ | ||
| --head <branch-name> \ | ||
| --title "<same as commit title>" \ | ||
| --body "$(cat <<'EOF' | ||
| ## Summary | ||
| - bullet points | ||
|
|
||
| ## Test plan | ||
| - [ ] item | ||
|
|
||
| 🤖 Generated with [Claude Code](https://claude.com/claude-code) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Remove emoji from PR body template. The project prohibits emojis in all files. Replace with plain text, e.g., 🧰 Tools🪛 SkillSpector (2.3.7)[warning] 34: [RP1] null: npx commands without a version suffix (e.g. Remediation: Pin the version: npx (MCP Rug Pull (RP1)) [warning] 129: [RP1] null: npx commands without a version suffix (e.g. Remediation: Pin the version: npx (MCP Rug Pull (RP1)) 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| EOF | ||
| )" | ||
| ``` | ||
|
|
||
| ### 7. Create cross-fork PR on the upstream (crynta/terax-ai) | ||
|
|
||
| Only if no existing open upstream PR covers this change. Push access is denied to upstream, so use the fork branch as head: | ||
|
|
||
| ```bash | ||
| gh pr create \ | ||
| --repo crynta/terax-ai \ | ||
| --base main \ | ||
| --head roberto-fernandino:<branch-name> \ | ||
| --title "<same as commit title>" \ | ||
| --body "..." | ||
| ``` | ||
|
|
||
| ### 8. Merge the fork PR | ||
|
|
||
| ```bash | ||
| gh pr merge <pr-number> --repo roberto-fernandino/terax-ai-fork --merge --auto | ||
| ``` | ||
|
|
||
| ### 9. Return to main and pull | ||
|
|
||
| ```bash | ||
| git checkout main | ||
| git pull origin main | ||
| ``` | ||
|
|
||
| ## Rules | ||
|
|
||
| - ALWAYS create a branch — never commit directly to main. | ||
| - ALWAYS check for existing open PRs before creating new ones (step 5). Push to the existing branch/PR when the change belongs to the same feature or subsystem. | ||
| - ALWAYS open TWO PRs when creating new ones: one on the fork, one on the upstream (cross-fork). | ||
| - ALWAYS merge the fork PR and return to main at the end. | ||
| - NEVER push directly to upstream (no access); always use `--head roberto-fernandino:<branch>` for the upstream PR. | ||
| - NEVER open a new PR for a fix that belongs to an existing open feature PR — add the commit to that branch instead. | ||
| - Type-check (`npx tsc --noEmit`) before committing. | ||
| - Use conventional commit prefixes: `feat`, `fix`, `chore`, `refactor`, `docs`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,8 +8,8 @@ use crate::modules::git::process::{ | |
| read_text_file, run_git, | ||
| }; | ||
| use crate::modules::git::types::{ | ||
| DiscardEntry, GitBranchEntry, GitBranchListResult, GitCommitFileChange, GitCommitResult, | ||
| GitDiffContentResult, GitDiffResult, GitLogEntry, GitOutput, GitPanelSnapshot, | ||
| DiscardEntry, GitBlameLineInfo, GitBranchEntry, GitBranchListResult, GitCommitFileChange, | ||
| GitCommitResult, GitDiffContentResult, GitDiffResult, GitLogEntry, GitOutput, GitPanelSnapshot, | ||
| GitPushResult, GitRepoInfo, GitStatusSnapshot, TextSource, DEFAULT_TIMEOUT_SECS, | ||
| NETWORK_TIMEOUT_SECS, | ||
| }; | ||
|
|
@@ -1147,6 +1147,59 @@ pub fn checkout_branch( | |
| ensure_success(&output, "git checkout failed") | ||
| } | ||
|
|
||
| pub fn blame_line( | ||
| registry: &WorkspaceRegistry, | ||
| cwd: &str, | ||
| path: &str, | ||
| line: u32, | ||
| workspace: &WorkspaceEnv, | ||
| ) -> Result<Option<GitBlameLineInfo>> { | ||
| if line == 0 { | ||
| return Ok(None); | ||
| } | ||
| let dir = canonical_dir(registry, cwd, workspace)?; | ||
| if !registry.is_authorized(&dir.local_path) { | ||
| return Err(GitError::PathOutsideWorkspace(dir.local_path)); | ||
| } | ||
| ensure_git_available(&dir.workspace)?; | ||
|
|
||
| let line_spec = format!("{},{}", line, line); | ||
| let output = run_git( | ||
| &dir.workspace, | ||
| Some(&dir.git_path), | ||
| ["blame", "-L", &line_spec, "--porcelain", "--", path], | ||
| DEFAULT_TIMEOUT_SECS, | ||
| )?; | ||
|
|
||
| if output.exit_code != Some(0) { | ||
| return Ok(None); | ||
| } | ||
|
|
||
| let text = String::from_utf8_lossy(&output.stdout); | ||
| let mut author: Option<String> = None; | ||
| let mut timestamp: Option<i64> = None; | ||
|
|
||
| for line_text in text.lines() { | ||
| if let Some(name) = line_text.strip_prefix("author ") { | ||
| author = Some(name.to_string()); | ||
| } else if let Some(ts) = line_text.strip_prefix("author-time ") { | ||
| if let Ok(t) = ts.trim().parse::<i64>() { | ||
| timestamp = Some(t); | ||
| } | ||
| } | ||
| if author.is_some() && timestamp.is_some() { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| Ok(match (author, timestamp) { | ||
| (Some(a), Some(t)) if a != "Not Committed Yet" => { | ||
| Some(GitBlameLineInfo { author: a, timestamp: t }) | ||
| } | ||
| _ => None, | ||
| }) | ||
| } | ||
|
Comment on lines
+1150
to
+1201
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win Extract the porcelain parser into a pure function and add a test for it. The parsing logic (lines 1178-1200) is sound, but it's fused to the Splitting the As per coding guidelines, "A change to a core subsystem (terminal/shell spawn, workspace auth, git, fs, IPC or AI tool surface) needs a test that locks the invariant," and "new or changed logic lives in pure, dependency-light functions (functional core)." ♻️ Suggested splitfn parse_blame_porcelain(text: &str) -> Option<GitBlameLineInfo> {
let mut author: Option<String> = None;
let mut timestamp: Option<i64> = None;
for line_text in text.lines() {
if let Some(name) = line_text.strip_prefix("author ") {
author = Some(name.to_string());
} else if let Some(ts) = line_text.strip_prefix("author-time ") {
if let Ok(t) = ts.trim().parse::<i64>() {
timestamp = Some(t);
}
}
if author.is_some() && timestamp.is_some() {
break;
}
}
match (author, timestamp) {
(Some(a), Some(t)) if a != "Not Committed Yet" => Some(GitBlameLineInfo { author: a, timestamp: t }),
_ => None,
}
}Then 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove em-dashes from skill description.
The project prohibits em dashes in all files. Replace with hyphens or commas. As per coding guidelines, do not use em dashes anywhere, including code, comments, commits, and docs.
🧰 Tools
🪛 SkillSpector (2.3.7)
[warning] 34: [RP1] null: npx commands without a version suffix (e.g.
@1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.Remediation: Pin the version: npx
@scope/server@1.2.3(MCP Rug Pull (RP1))
[warning] 129: [RP1] null: npx commands without a version suffix (e.g.
@1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.Remediation: Pin the version: npx
@scope/server@1.2.3(MCP Rug Pull (RP1))
🤖 Prompt for AI Agents
Source: Coding guidelines