Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b502645
feat(tabs): select tabs by index within active space
Jun 26, 2026
af93248
Merge pull request #1 from roberto-fernandino/fix-tab-picker
roberto-fernandino Jun 26, 2026
023baa1
feat(shortcuts): add ai toggle mini shortcut
Jun 26, 2026
bda8dfb
Merge pull request #2 from roberto-fernandino/feat/toggle-ai-chat-win…
roberto-fernandino Jun 26, 2026
2b644ff
feat: terminals in command-palette
Jun 26, 2026
1a6b366
Merge pull request #3 from roberto-fernandino/feat/terminals-in-comma…
roberto-fernandino Jun 26, 2026
81e752f
feat(shortcuts): add configurable shortcut to show Files sidebar
Jun 27, 2026
df23232
Merge pull request #4 from roberto-fernandino/feat/files-sidebar-shor…
roberto-fernandino Jun 27, 2026
9bf6a2d
chore: add terax-pr-workflow project skill
Jun 27, 2026
2a5d3b2
Merge remote-tracking branch 'upstream/main'
roberto-fernandino Jun 27, 2026
b679121
feat(sidebar): add Agents tab showing all active AI agent sessions
roberto-fernandino Jun 27, 2026
a22273a
Merge pull request #6 from roberto-fernandino/feat/agents-sidebar-tab…
roberto-fernandino Jun 27, 2026
bf8faf9
fix(agents): show idle status when agent is at prompt, not working
roberto-fernandino Jun 27, 2026
fec2a7d
Merge pull request #7 from roberto-fernandino/fix/agents-idle-status
roberto-fernandino Jun 27, 2026
8a76492
feat(ai): open AI panel by default on startup
roberto-fernandino Jun 27, 2026
74b3f6c
Merge pull request #8 from roberto-fernandino/feat/ai-panel-open-by-d…
roberto-fernandino Jun 27, 2026
497e6b8
fix(agents): clear needs-input when tab focused; finished resets to idle
roberto-fernandino Jun 27, 2026
2f9e17f
Merge pull request #9 from roberto-fernandino/fix/agents-needs-input-…
roberto-fernandino Jun 27, 2026
a893d44
fix(agents): reset working status to idle when terminal tab is focused
roberto-fernandino Jun 28, 2026
1b92a83
Merge pull request #10 from roberto-fernandino/fix/agents-working-stu…
roberto-fernandino Jun 28, 2026
14c1ae1
fix(agents): use tabsRef in focus-reset effect to preserve real-time …
roberto-fernandino Jun 28, 2026
d292c64
feat(terminal): add cursor style setting (bar/block/underline)
roberto-fernandino Jun 30, 2026
f61a0c8
Merge pull request #12 from roberto-fernandino/feat/terminal-cursor-s…
roberto-fernandino Jun 30, 2026
10c67c3
chore: merge upstream/main (sidebar persist, workspace env, Linux cli…
roberto-fernandino Jun 30, 2026
e454866
feat(editor): show git blame for current line in status bar
roberto-fernandino Jun 30, 2026
5e7c13c
Merge pull request #13 from roberto-fernandino/feat/git-blame-statusbar
roberto-fernandino Jun 30, 2026
c84686d
feat(sidebar): show processes alongside agents
roberto-fernandino Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions .claude/skills/terax-pr-workflow/SKILL.md
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
```
Comment on lines +33 to +35

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use pnpm instead of npx for type-checking.

The project conventions mandate pnpm exclusively, never npm/npx. The repo already defines "check-types": "tsc --noEmit" in package.json and all other documentation (PR template, CONTRIBUTING.md) uses pnpm exec tsc --noEmit. Using npx here risks version skew from a globally-installed tsc and breaks workflow consistency. As per coding guidelines, pnpm only, never npm/npx/yarn.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/terax-pr-workflow/SKILL.md around lines 33 - 35, The workflow
instruction currently uses npx for type-checking, which conflicts with the
repo’s pnpm-only convention. Update the type-checking command in SKILL.md to use
pnpm exec tsc --noEmit (or the existing check-types script via pnpm) and ensure
any references in this workflow doc consistently avoid npx/npm/yarn; this change
is localized to the type-checking step in the skill instructions.

Source: Coding guidelines


### 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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove emoji from skill document.

The robot emoji violates the project-wide "No emojis anywhere" rule that applies to code, comments, commits, and docs. As per coding guidelines, no emojis anywhere.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/terax-pr-workflow/SKILL.md at line 74, The skill document
contains an emoji in the generated-by line, which violates the no-emojis rule.
Remove the robot emoji from the affected line in SKILL.md and keep the rest of
the attribution text unchanged so the document remains compliant with the
project-wide formatting guidelines.

Source: 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`.
4 changes: 3 additions & 1 deletion src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub mod modules;

use modules::{agent, fs, git, history, net, pty, secrets, shell, workspace};
use modules::{agent, fs, git, history, net, proc, pty, secrets, shell, workspace};
use std::sync::Mutex;
use tauri::{Emitter, Manager, State, WebviewUrl, WebviewWindowBuilder};
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -235,6 +235,7 @@ pub fn run() {
git::commands::git_remote_url,
git::commands::git_list_branches,
git::commands::git_checkout_branch,
git::commands::git_blame,
shell::shell_run_command,
shell::shell_session_open,
shell::shell_session_run,
Expand All @@ -252,6 +253,7 @@ pub fn run() {
open_settings_window,
agent::agent_enable_hooks,
agent::agent_hooks_status,
proc::proc_list_terminal_processes,
secrets::secrets_get,
secrets::secrets_set,
secrets::secrets_delete,
Expand Down
17 changes: 16 additions & 1 deletion src-tauri/src/modules/git/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use tauri::{AppHandle, Manager};

use crate::modules::git::operations;
use crate::modules::git::types::{
DiscardEntry, GitBranchListResult, GitCommitFileChange, GitCommitResult,
DiscardEntry, GitBlameLineInfo, GitBranchListResult, GitCommitFileChange, GitCommitResult,
GitDiffContentResult, GitDiffResult, GitLogEntry, GitPanelSnapshot, GitPushResult,
GitRepoInfo, GitStatusSnapshot,
};
Expand Down Expand Up @@ -309,3 +309,18 @@ pub async fn git_checkout_branch(
})
.await
}

#[tauri::command]
pub async fn git_blame(
cwd: String,
path: String,
line: u32,
workspace: Option<WorkspaceEnv>,
app: AppHandle,
) -> Result<Option<GitBlameLineInfo>, String> {
let workspace = WorkspaceEnv::from_option(workspace);
blocking(app, move |r| {
operations::blame_line(r, &cwd, &path, line, &workspace).map_err(Into::into)
})
.await
}
57 changes: 55 additions & 2 deletions src-tauri/src/modules/git/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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,
})
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
7 changes: 7 additions & 0 deletions src-tauri/src/modules/git/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ pub struct GitBranchListResult {
pub branches: Vec<GitBranchEntry>,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GitBlameLineInfo {
pub author: String,
pub timestamp: i64,
}

pub(crate) struct GitOutput {
pub(crate) stdout: Vec<u8>,
pub(crate) stderr: Vec<u8>,
Expand Down
Loading
Loading