mirror of
https://github.com/cline/cline.git
synced 2026-10-24 02:02:27 +08:00
refactor(desktop): remove redundant handoff draft state
This commit is contained in:
@@ -130,7 +130,7 @@ async function prepareCloudHandoff(
|
||||
};
|
||||
const cwd = readWorkspacePath(config) ?? readWorkspacePath(persisted);
|
||||
if (!cwd) throw new Error("Cloud handoff requires a workspace path.");
|
||||
return { sessionId, manager, config, cwd };
|
||||
return { manager, config, cwd };
|
||||
}
|
||||
|
||||
function assertHandoffAccount(
|
||||
|
||||
@@ -1410,7 +1410,6 @@ function ChatThreadPane({
|
||||
setPendingAttachments,
|
||||
clearPromptForSend,
|
||||
promptDraft,
|
||||
promptInputRef,
|
||||
setPromptInput,
|
||||
handlePromptInputChange,
|
||||
} = usePromptDraft(promptDrafts, threadId);
|
||||
@@ -2034,7 +2033,7 @@ function ChatThreadPane({
|
||||
const preserveComposer =
|
||||
historySession.origin === "cloud" &&
|
||||
Boolean(
|
||||
promptInputRef.current.trim() || draftRef.current.attachments.length,
|
||||
draftRef.current.text.trim() || draftRef.current.attachments.length,
|
||||
);
|
||||
if (!preserveComposer) {
|
||||
setPromptInput(initialPromptDraft ?? "");
|
||||
@@ -2062,7 +2061,6 @@ function ChatThreadPane({
|
||||
initialAttachments,
|
||||
initialPromptDraft,
|
||||
onInitialPromptDraftConsumed,
|
||||
promptInputRef,
|
||||
sessionId,
|
||||
setPendingAttachments,
|
||||
setPromptInput,
|
||||
|
||||
@@ -110,7 +110,7 @@ describe("usePromptDraft", () => {
|
||||
send.resolve(false);
|
||||
await send.finished;
|
||||
});
|
||||
expect(current.promptInputRef.current).toBe("");
|
||||
expect(current.draftRef.current.text).toBe("");
|
||||
expect(drafts.get("new-session")?.text).toBe("");
|
||||
});
|
||||
|
||||
@@ -137,12 +137,12 @@ describe("usePromptDraft", () => {
|
||||
first.resolve(false);
|
||||
await first.finished;
|
||||
});
|
||||
expect(current.promptInputRef.current).toBe("");
|
||||
expect(current.draftRef.current.text).toBe("");
|
||||
await act(async () => {
|
||||
second.resolve(false);
|
||||
await second.finished;
|
||||
});
|
||||
expect(current.promptInputRef.current).toBe("Submitted prompt");
|
||||
expect(current.draftRef.current.text).toBe("Submitted prompt");
|
||||
});
|
||||
|
||||
it("does not let a retired pane's failed send overwrite a newer draft", async () => {
|
||||
@@ -182,7 +182,7 @@ describe("usePromptDraft", () => {
|
||||
await send.finished;
|
||||
});
|
||||
expect(drafts.has("new-session")).toBe(false);
|
||||
expect(current.promptInputRef.current).toBe("");
|
||||
expect(current.draftRef.current.text).toBe("");
|
||||
});
|
||||
|
||||
it("preserves a newly started session's follow-up when reopened through history", async () => {
|
||||
@@ -195,7 +195,7 @@ describe("usePromptDraft", () => {
|
||||
act(() => current.handlePromptInputChange("Follow-up to my new session"));
|
||||
// The same session ID on a different host must not reuse the local thread.
|
||||
await openSession("remote");
|
||||
expect(current.promptInputRef.current).toBe("");
|
||||
expect(current.draftRef.current.text).toBe("");
|
||||
act(() => current.handlePromptInputChange("Remote follow-up"));
|
||||
await openSession("local");
|
||||
expect(appState.navigation.current.activeThreadId).toBe("new-session");
|
||||
@@ -212,10 +212,10 @@ describe("usePromptDraft", () => {
|
||||
sessionId: "existing-session",
|
||||
});
|
||||
act(() => current.handlePromptInputChange("Unsent follow-up"));
|
||||
const inputRef = current.promptInputRef;
|
||||
const draftRef = current.draftRef;
|
||||
await openSession();
|
||||
expect(current.promptInputRef).toBe(inputRef);
|
||||
expect(current.promptInputRef.current).toBe("Unsent follow-up");
|
||||
expect(current.draftRef).toBe(draftRef);
|
||||
expect(current.draftRef.current.text).toBe("Unsent follow-up");
|
||||
expect(appState.threads).toHaveLength(1);
|
||||
});
|
||||
|
||||
@@ -233,7 +233,7 @@ describe("usePromptDraft", () => {
|
||||
|
||||
await navigate({ type: "back" });
|
||||
expect(current.promptDraft.value).toBe("Unsent prompt\nwith more detail");
|
||||
expect(current.promptInputRef.current).toBe(current.promptDraft.value);
|
||||
expect(current.draftRef.current.text).toBe(current.promptDraft.value);
|
||||
await navigate({ type: "forward" });
|
||||
expect(current.promptDraft.value).toBe("Follow-up draft");
|
||||
});
|
||||
@@ -317,7 +317,7 @@ describe("usePromptDraft", () => {
|
||||
destination: { ...appState.navigation.current, view: "sessions" },
|
||||
});
|
||||
await openSession();
|
||||
expect(current.promptInputRef.current).toBe("Edited follow-up");
|
||||
expect(current.draftRef.current.text).toBe("Edited follow-up");
|
||||
expect(current.pendingAttachments).toEqual([image]);
|
||||
act(() => {
|
||||
current.handlePromptInputChange("");
|
||||
@@ -325,7 +325,7 @@ describe("usePromptDraft", () => {
|
||||
});
|
||||
await navigate({ type: "back" });
|
||||
await openSession();
|
||||
expect(current.promptInputRef.current).toBe("");
|
||||
expect(current.draftRef.current.text).toBe("");
|
||||
expect(current.pendingAttachments).toEqual([]);
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ export function usePromptDraft(
|
||||
const draftRef = useRef<PromptDraft>(
|
||||
drafts.get(threadId) ?? { text: "", attachments: [] },
|
||||
);
|
||||
const promptInputRef = useRef(draftRef.current.text);
|
||||
const [pendingAttachments, setAttachments] = useState(
|
||||
draftRef.current.attachments,
|
||||
);
|
||||
@@ -51,14 +50,13 @@ export function usePromptDraft(
|
||||
);
|
||||
const [promptDraft, setPromptDraft] = useState(() => ({
|
||||
version: 0,
|
||||
value: promptInputRef.current,
|
||||
value: draftRef.current.text,
|
||||
}));
|
||||
const handlePromptInputChange = useCallback((value: string) => {
|
||||
if (!mountedRef.current) return;
|
||||
// The composer echoes external replacements. Those acknowledgements
|
||||
// aren't new edits and must not invalidate a pending send's recovery.
|
||||
if (promptInputRef.current !== value) revisionRef.current += 1;
|
||||
promptInputRef.current = value;
|
||||
if (draftRef.current.text !== value) revisionRef.current += 1;
|
||||
draftRef.current.text = value;
|
||||
}, []);
|
||||
const setPromptInput = useCallback(
|
||||
@@ -91,7 +89,6 @@ export function usePromptDraft(
|
||||
draftRef,
|
||||
pendingAttachments,
|
||||
setPendingAttachments,
|
||||
promptInputRef,
|
||||
promptDraft,
|
||||
setPromptInput,
|
||||
handlePromptInputChange,
|
||||
|
||||
@@ -188,7 +188,7 @@ export function createHandoffLifecycle(effects: HandoffLifecycleEffects) {
|
||||
},
|
||||
async onRpcRejected(
|
||||
sourceSessionId: string,
|
||||
ctx: RpcContext & { error: unknown; silent?: boolean },
|
||||
ctx: RpcContext & { error: unknown },
|
||||
): Promise<void> {
|
||||
const attempt = current(sourceSessionId, ctx.handoffAttemptId);
|
||||
if (!attempt || attempt.completed) return;
|
||||
@@ -214,14 +214,12 @@ export function createHandoffLifecycle(effects: HandoffLifecycleEffects) {
|
||||
retryDraft: ctx.nextCommand,
|
||||
retryAttachments: ctx.sourceAttachments,
|
||||
});
|
||||
if (!ctx.silent) {
|
||||
effects.toast({
|
||||
title: "Handoff failed",
|
||||
description: message,
|
||||
variant: "destructive",
|
||||
connectUrl,
|
||||
});
|
||||
}
|
||||
effects.toast({
|
||||
title: "Handoff failed",
|
||||
description: message,
|
||||
variant: "destructive",
|
||||
connectUrl,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user