Support line ranges in assistant file links (#1067)

This commit is contained in:
Mohamed Boudra
2026-05-17 22:55:46 +08:00
committed by GitHub
parent efc9c2d345
commit ee44b536f5
29 changed files with 504 additions and 115 deletions
+6 -13
View File
@@ -32,7 +32,6 @@ import {
} from "@/hooks/use-agent-screen-state-machine";
import { useArchiveAgent } from "@/hooks/use-archive-agent";
import { useKeyboardShiftStyle } from "@/hooks/use-keyboard-shift-style";
import { useStableEvent } from "@/hooks/use-stable-event";
import { usePaneContext, usePaneFocus } from "@/panels/pane-context";
import type { PanelDescriptor, PanelRegistration } from "@/panels/panel-registry";
import {
@@ -59,7 +58,7 @@ import type { PendingPermission } from "@/types/shared";
import type { StreamItem } from "@/types/stream";
import { getInitDeferred, getInitKey } from "@/utils/agent-initialization";
import { derivePendingPermissionKey, normalizeAgentSnapshot } from "@/utils/agent-snapshots";
import type { OpenFileDisposition } from "@/utils/workspace-file-open";
import type { WorkspaceFileOpenRequest } from "@/workspace/file-open";
import { mergePendingCreateImages } from "@/utils/pending-create-images";
import { navigateToAgent } from "@/utils/navigate-to-agent";
import { deriveSidebarStateBucket } from "@/utils/sidebar-agent-state";
@@ -289,18 +288,12 @@ function AgentPanel() {
const { isInteractive } = usePaneFocus();
invariant(target.kind === "agent", "AgentPanel requires agent target");
const handleOpenWorkspaceFile = useStableEvent(
({ filePath, disposition }: { filePath: string; disposition: OpenFileDisposition }) => {
openFileInWorkspace(filePath, disposition);
},
);
return (
<AgentPanelContent
serverId={serverId}
agentId={target.agentId}
isPaneFocused={isInteractive}
onOpenWorkspaceFile={handleOpenWorkspaceFile}
onOpenWorkspaceFile={openFileInWorkspace}
/>
);
}
@@ -366,7 +359,7 @@ function AgentPanelContent({
serverId: string;
agentId: string;
isPaneFocused: boolean;
onOpenWorkspaceFile?: (input: { filePath: string; disposition: OpenFileDisposition }) => void;
onOpenWorkspaceFile?: (request: WorkspaceFileOpenRequest) => void;
}) {
const resolvedAgentId = agentId.trim() || undefined;
const resolvedServerId = serverId.trim() || undefined;
@@ -428,7 +421,7 @@ function AgentPanelBody({
client: NonNullable<ReturnType<typeof useHostRuntimeClient>>;
isConnected: boolean;
connectionStatus: HostRuntimeConnectionStatus;
onOpenWorkspaceFile?: (input: { filePath: string; disposition: OpenFileDisposition }) => void;
onOpenWorkspaceFile?: (request: WorkspaceFileOpenRequest) => void;
}) {
const { isArchivingAgent: _isArchivingAgent } = useArchiveAgent();
const hasSession = useSessionStore((state) => Boolean(state.sessions[serverId]));
@@ -593,7 +586,7 @@ function ChatAgentContent({
client: NonNullable<ReturnType<typeof useHostRuntimeClient>>;
isConnected: boolean;
connectionStatus: HostRuntimeConnectionStatus;
onOpenWorkspaceFile?: (input: { filePath: string; disposition: OpenFileDisposition }) => void;
onOpenWorkspaceFile?: (request: WorkspaceFileOpenRequest) => void;
}) {
const panelToast = useToastHost();
const { isArchivingAgent } = useArchiveAgent();
@@ -1042,7 +1035,7 @@ function AgentStreamSection({
routeBottomAnchorRequest: RouteBottomAnchorRequest;
hasAppliedAuthoritativeHistory: boolean;
toast: ReturnType<typeof useToastHost>["api"];
onOpenWorkspaceFile?: (input: { filePath: string; disposition: OpenFileDisposition }) => void;
onOpenWorkspaceFile?: (request: WorkspaceFileOpenRequest) => void;
}) {
const streamItemsRaw = useSessionStore((state) =>
agentId ? state.sessions[serverId]?.agentStreamTail?.get(agentId) : undefined,
+1 -9
View File
@@ -6,7 +6,6 @@ import { usePaneContext, usePaneFocus } from "@/panels/pane-context";
import type { PanelRegistration } from "@/panels/panel-registry";
import { useSessionStore } from "@/stores/session-store";
import { normalizeAgentSnapshot } from "@/utils/agent-snapshots";
import type { OpenFileDisposition } from "@/utils/workspace-file-open";
function useDraftPanelDescriptor() {
return {
@@ -31,13 +30,6 @@ function DraftPanel() {
const { isInteractive } = usePaneFocus();
invariant(target.kind === "draft", "DraftPanel requires draft target");
const handleOpenWorkspaceFile = useCallback(
({ filePath, disposition }: { filePath: string; disposition: OpenFileDisposition }) => {
openFileInWorkspace(filePath, disposition);
},
[openFileInWorkspace],
);
const handleCreated = useCallback(
(agentSnapshot: Parameters<typeof normalizeAgentSnapshot>[0]) => {
const normalized = normalizeAgentSnapshot(agentSnapshot, serverId);
@@ -59,7 +51,7 @@ function DraftPanel() {
draftId={target.draftId}
initialSetup={target.setup}
isPaneFocused={isInteractive}
onOpenWorkspaceFile={handleOpenWorkspaceFile}
onOpenWorkspaceFile={openFileInWorkspace}
onCreated={handleCreated}
onOpenImportSheet={openImportSheet}
/>
+1 -1
View File
@@ -38,7 +38,7 @@ function FilePanel() {
</View>
);
}
return <FilePane serverId={serverId} workspaceRoot={workspaceDirectory} filePath={target.path} />;
return <FilePane serverId={serverId} workspaceRoot={workspaceDirectory} location={target} />;
}
export const filePanelRegistration: PanelRegistration<"file"> = {
+2 -2
View File
@@ -1,7 +1,7 @@
import React, { createContext, useContext, type ReactNode } from "react";
import invariant from "tiny-invariant";
import type { WorkspaceTabTarget } from "@/stores/workspace-tabs-store";
import type { OpenFileDisposition } from "@/utils/workspace-file-open";
import type { WorkspaceFileOpenRequest } from "@/workspace/file-open";
export interface PaneContextValue {
serverId: string;
@@ -11,7 +11,7 @@ export interface PaneContextValue {
openTab: (target: WorkspaceTabTarget) => void;
closeCurrentTab: () => void;
retargetCurrentTab: (target: WorkspaceTabTarget) => void;
openFileInWorkspace: (filePath: string, disposition: OpenFileDisposition) => void;
openFileInWorkspace: (request: WorkspaceFileOpenRequest) => void;
openImportSheet: () => void;
}