-
Notifications
You must be signed in to change notification settings - Fork 884
feat(terminal): add cursor style setting (bar/block/underline) #908
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
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,112 @@ | ||
| --- | ||
| 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 | ||
|
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 Use The project defines 🧰 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] 111: [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 |
||
| ``` | ||
|
|
||
| ### 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. Create PR on the fork (roberto-fernandino/terax-ai-fork) | ||
|
|
||
| ```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 template. The PR body template includes a robot emoji, which violates the project convention: "Do not use emojis anywhere." As per coding guidelines, no emojis anywhere. 🧰 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] 111: [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 | ||
| )" | ||
| ``` | ||
|
|
||
| ### 6. Create cross-fork PR on the upstream (crynta/terax-ai) | ||
|
|
||
| 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 "..." | ||
| ``` | ||
|
|
||
| ### 7. Merge the fork PR | ||
|
|
||
| ```bash | ||
| gh pr merge <pr-number> --repo roberto-fernandino/terax-ai-fork --merge --auto | ||
| ``` | ||
|
|
||
| ### 8. Return to main and pull | ||
|
|
||
| ```bash | ||
| git checkout main | ||
| git pull origin main | ||
| ``` | ||
|
|
||
| ## Rules | ||
|
|
||
| - ALWAYS create a branch — never commit directly to main. | ||
| - ALWAYS open TWO PRs: 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. | ||
| - 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 |
|---|---|---|
|
|
@@ -11,6 +11,8 @@ import { quoteShellArg } from "@/lib/shellQuote"; | |
| import { useZoom } from "@/lib/useZoom"; | ||
| import { getCurrentWindow } from "@tauri-apps/api/window"; | ||
| import { AgentNotificationsBridge, nextAttentionTarget } from "@/modules/agents"; | ||
| import { useAgentStore } from "@/modules/agents/store/agentStore"; | ||
| import { AgentsPanel } from "@/modules/agents-panel"; | ||
| import { | ||
| AgentRunBridge, | ||
| AiMiniWindow, | ||
|
|
@@ -258,6 +260,21 @@ export default function App() { | |
| [tabs, activeSpaceId], | ||
| ); | ||
|
|
||
| const agentStoreSessions = useAgentStore((s) => s.sessions); | ||
| const agentSessions = useMemo( | ||
| () => Object.values(agentStoreSessions), | ||
| [agentStoreSessions], | ||
| ); | ||
| const agentsByTabId = useMemo(() => { | ||
| const map = new Map<number, string>(); | ||
| for (const s of agentSessions) { | ||
| map.set(s.tabId, s.agent); | ||
| } | ||
| return map; | ||
| }, [agentSessions]); | ||
|
|
||
| const showAgentsTab = usePreferencesStore((s) => s.showAgentsTab); | ||
|
|
||
| const { | ||
| sidebarRef, | ||
| sidebarWidthRef, | ||
|
|
@@ -267,7 +284,7 @@ export default function App() { | |
| cycleSidebarView, | ||
| persistSidebarWidth, | ||
| toggleExplorerFocus, | ||
| } = useSidebarPanel(explorerRef); | ||
| } = useSidebarPanel(explorerRef, showAgentsTab); | ||
|
|
||
| const [newEditorOpen, setNewEditorOpen] = useState(false); | ||
| const [commandPaletteOpen, setCommandPaletteOpen] = useState(false); | ||
|
|
@@ -284,6 +301,7 @@ export default function App() { | |
| const miniOpen = useChatStore((s) => s.mini.open); | ||
| const miniPresence = usePresence(miniOpen, 200); | ||
| const openMini = useChatStore((s) => s.openMini); | ||
| const toggleMini = useChatStore((s) => s.toggleMini); | ||
| const focusInput = useChatStore((s) => s.focusInput); | ||
| const openPanel = useChatStore((s) => s.openPanel); | ||
| const panelOpen = useChatStore((s) => s.panelOpen); | ||
|
|
@@ -378,6 +396,23 @@ export default function App() { | |
| useEffect(() => { | ||
| mruRef.current = [activeId, ...mruRef.current.filter((id) => id !== activeId)]; | ||
| }, [activeId]); | ||
|
|
||
| // When the user NAVIGATES to a terminal tab, reset any non-idle agent status | ||
| // back to idle — they are looking at it so notifications are moot, and | ||
| // Ctrl+C won't fire a finished signal so "working" would otherwise get stuck. | ||
| // Uses tabsRef (not tabs) so this only fires on activeId change, not on every | ||
| // tab title update (which would kill real-time "working" display). | ||
| useEffect(() => { | ||
| const tab = tabsRef.current.find((t) => t.id === activeId); | ||
| if (!tab || tab.kind !== "terminal") return; | ||
| const store = useAgentStore.getState(); | ||
| for (const s of Object.values(store.sessions)) { | ||
| if (s.tabId === activeId && s.status !== "idle") { | ||
| store.setStatus(s.leafId, "idle"); | ||
| } | ||
| } | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, [activeId]); | ||
|
Comment on lines
+399
to
+415
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. 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift Do not clear agent status on tab switch. This rewrites real lifecycle state as a visibility side effect: a running or waiting agent in the active tab becomes 🤖 Prompt for AI AgentsSource: Path instructions |
||
| useEffect(() => { | ||
| const live = new Set(tabs.map((t) => t.id)); | ||
| mruRef.current = mruRef.current.filter((id) => live.has(id)); | ||
|
|
@@ -653,7 +688,11 @@ export default function App() { | |
| "tab.close": handleCloseTabOrPane, | ||
| "tab.next": () => stepSwitcher(1), | ||
| "tab.prev": () => stepSwitcher(-1), | ||
| "tab.selectByIndex": (e) => selectByIndex(parseInt(e.key, 10) - 1), | ||
| "tab.selectByIndex": (e) => | ||
| selectByIndex( | ||
| parseInt(e.key, 10) - 1, | ||
| activeSpaceId ?? DEFAULT_SPACE_ID, | ||
| ), | ||
| "space.next": () => cycleSpace(1), | ||
| "space.prev": () => cycleSpace(-1), | ||
| "space.overview": () => setSwitcherOpen(true), | ||
|
|
@@ -662,6 +701,7 @@ export default function App() { | |
| "pane.focusNext": () => focusNextPaneInTab(activeId, 1), | ||
| "pane.focusPrev": () => focusNextPaneInTab(activeId, -1), | ||
| "pane.source": toggleSourceControl, | ||
| "sidebar.files": () => cycleSidebarView("explorer"), | ||
| "terminal.clear": () => { | ||
| clearFocusedTerminal(); | ||
| }, | ||
|
|
@@ -671,6 +711,13 @@ export default function App() { | |
| "blocks.next": () => navigateFocusedBlocks(1), | ||
| "search.focus": () => searchInlineRef.current?.focus(), | ||
| "ai.toggle": togglePanelAndFocus, | ||
| "ai.toggleMini": () => { | ||
| if (!hasComposer) { | ||
| void openSettingsWindow("models"); | ||
| return; | ||
| } | ||
| toggleMini(); | ||
| }, | ||
| "ai.askSelection": askFromSelection, | ||
| "agent.focusAttention": () => { | ||
| const t = nextAttentionTarget(); | ||
|
|
@@ -700,7 +747,9 @@ export default function App() { | |
| splitActivePaneInActiveTab, | ||
| focusNextPaneInTab, | ||
| toggleSourceControl, | ||
| hasComposer, | ||
| togglePanelAndFocus, | ||
| toggleMini, | ||
| askFromSelection, | ||
| toggleSidebar, | ||
| toggleExplorerFocus, | ||
|
|
@@ -979,6 +1028,7 @@ export default function App() { | |
| openNewPreview: () => openPreviewTab(""), | ||
| openGitGraph: openGitGraphFromContext, | ||
| toggleSourceControl, | ||
| toggleFilesExplorer: () => cycleSidebarView("explorer"), | ||
| closeActiveTabOrPane: handleCloseTabOrPane, | ||
| splitPaneRight: () => splitActivePaneInActiveTab("row"), | ||
| splitPaneDown: () => splitActivePaneInActiveTab("col"), | ||
|
|
@@ -994,6 +1044,12 @@ export default function App() { | |
| openSpacesOverview: () => setSwitcherOpen(true), | ||
| newSpace: () => void handleNewSpace(), | ||
| switchSpace: (id) => useSpaces.getState().setActive(id), | ||
| terminalTabs: tabs.filter( | ||
| (t) => | ||
| t.kind === "terminal" && | ||
| t.spaceId === (activeSpaceId ?? DEFAULT_SPACE_ID), | ||
| ), | ||
| switchTab: (id) => setActiveId(id), | ||
| }) | ||
| : [], | ||
| [ | ||
|
|
@@ -1009,6 +1065,7 @@ export default function App() { | |
| openPreviewTab, | ||
| openGitGraphFromContext, | ||
| toggleSourceControl, | ||
| cycleSidebarView, | ||
| handleCloseTabOrPane, | ||
| splitActivePaneInActiveTab, | ||
| toggleSidebar, | ||
|
|
@@ -1082,6 +1139,7 @@ export default function App() { | |
| searchTarget={searchTarget} | ||
| searchRef={searchInlineRef} | ||
| onOverrideLanguage={setOverrideLanguage} | ||
| agentsByTabId={agentsByTabId} | ||
| /> | ||
| )} | ||
|
|
||
|
|
@@ -1118,6 +1176,12 @@ export default function App() { | |
| onRevealInTerminal={cdInNewTab} | ||
| onAttachToAgent={handleAttachFileToAgent} | ||
| /> | ||
| ) : sidebarView === "agents" ? ( | ||
| <AgentsPanel | ||
| sessions={agentSessions} | ||
| tabs={tabs} | ||
| onSelectTab={setActiveId} | ||
| /> | ||
|
Comment on lines
+1179
to
+1184
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. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Use
🤖 Prompt for AI AgentsSource: Path instructions |
||
| ) : ( | ||
| <SourceControlPanel | ||
| open | ||
|
|
@@ -1133,6 +1197,8 @@ export default function App() { | |
| activeView={sidebarView} | ||
| onSelectView={persistSidebarView} | ||
| changedCount={sourceControl.changedCount} | ||
| showAgentsTab={showAgentsTab} | ||
| agentCount={agentSessions.filter((s) => s.status !== "idle").length} | ||
| /> | ||
| </div> | ||
| </ResizablePanel> | ||
|
|
||
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-dash from skill description.
The description field contains an em-dash, which violates the project convention: "Do not use em-dash anywhere, including code, comments, commits, and docs." As per coding guidelines, no em-dashes anywhere.
🧰 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] 111: [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