Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 23 additions & 0 deletions apps/code/src/main/services/agent/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1628,6 +1628,29 @@ For git operations while detached:
error: err,
});
});

// The user-initiated PR-creation flow links the current branch to the
// workspace atomically (see GitService.createPr). PRs created via bash —
// e.g. an agent running a `/commit-and-pr` skill — never go through that
// flow, so `workspace.linkedBranch` would otherwise stay unset and
// PR-aware UI (the unified PR badge, branch mismatch warning, diff
// source) would have no anchor. Emit AgentFileActivity here too so
// WorkspaceService.handleAgentFileActivity links the current feature
// branch the moment we observe a PR for it.
getCurrentBranch(session.repoPath)
.then((branchName) => {
this.emit(AgentServiceEvent.AgentFileActivity, {
taskId: session.taskId,
branchName,
});
})
.catch((err) => {
log.warn("Failed to resolve branch for PR auto-link", {
taskRunId,
taskId: session.taskId,
error: err,
});
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,6 @@ interface TaskActionsMenuProps {
* list. Cloud tasks without a PR render nothing.
*/
export function TaskActionsMenu({ taskId, isCloud }: TaskActionsMenuProps) {
// PR URL resolution — pick the right source based on task kind.
const cloudPrUrl = useCloudPrUrl(taskId);
const linkedPrUrl = useLinkedBranchPrUrl(taskId);
const prUrl = isCloud ? cloudPrUrl : linkedPrUrl;

const {
meta: { state: prState, merged, draft },
} = usePrDetails(prUrl);
const { execute: executePrAction, isPending: isPrActionPending } =
usePrActions(prUrl);

// Git state (skipped for cloud — useGitInteraction handles undefined repo).
const workspace = useWorkspace(taskId);
const isFocused = useFocusStore(
Expand All @@ -84,18 +73,47 @@ export function TaskActionsMenu({ taskId, isCloud }: TaskActionsMenuProps) {
actions: gitActions,
} = useGitInteraction(taskId, isCloud ? undefined : localRepoPath);

// PR URL resolution — pick the right source based on task kind.
// For local tasks, prefer the explicitly linked-branch lookup but fall back
// to whatever `getPrStatus` found on the current branch. The fallback
// catches PRs created outside the in-app flow (e.g. agents/skills running
// `gh pr create` via bash) where `workspace.linkedBranch` may not be set
// yet.
const cloudPrUrl = useCloudPrUrl(taskId);
const linkedPrUrl = useLinkedBranchPrUrl(taskId);
const prUrl = isCloud ? cloudPrUrl : (linkedPrUrl ?? gitState.prUrl ?? null);

const {
meta: { state: prState, merged, draft },
} = usePrDetails(prUrl);
const { execute: executePrAction, isPending: isPrActionPending } =
usePrActions(prUrl);

const pr = prUrl && prState !== null ? { url: prUrl, state: prState } : null;

// Cloud tasks only appear when they have a PR.
if (isCloud && !pr) return null;

// "view-pr" is redundant when the badge itself links to the PR;
// "create-pr" is redundant once a PR exists.
// When a PR exists the badge handles "view PR" and "create PR" is moot.
// The work-shipping slots (commit and the push/sync/publish trio) only get
// disabled to signal "nothing to do" (no changes, branch up to date, no
// commits to publish) — that's noise next to a PR badge, so drop them.
// Other disabled actions stay so their `disabledReason` tooltip can still
// explain why they're unavailable.
const noWorkSlots = new Set<GitMenuActionId>([
"commit",
"push",
"sync",
"publish",
]);
const gitItems = isCloud
? []
: gitState.actions.filter(
(a) => !(pr && (a.id === "view-pr" || a.id === "create-pr")),
);
: gitState.actions.filter((a) => {
if (!pr) return true;
if (a.id === "view-pr" || a.id === "create-pr") return false;
if (!a.enabled && noWorkSlots.has(a.id)) return false;
return true;
});
Comment thread
richardsolomou marked this conversation as resolved.

return (
<>
Expand Down
Loading