Show rewrite selection generation activity

This commit is contained in:
murashit 2026-05-18 12:52:14 +09:00
parent b5cb26e7e4
commit 0fd33fc1cc
3 changed files with 52 additions and 4 deletions

View file

@ -6,7 +6,7 @@ import { isRewriteGenerateKey } from "./keys";
import { canApplyRewrite, type RewriteRuntimeSettings, type RewriteSession } from "./model";
import { RewriteOutputError } from "./output";
import { buildRewritePrompt } from "./prompt";
import { runRewriteSelection } from "./runner";
import { runRewriteSelection, type RewriteActivity } from "./runner";
import type { SendShortcut } from "../settings/model";
const POPOVER_MARGIN = 8;
@ -127,7 +127,7 @@ export class RewriteSelectionPopover {
this.previewEl?.setText("");
this.diffEl?.empty();
this.renderDebug();
this.setStatus("Generating patch...");
this.setStatus("Generating patch", { active: true });
this.syncControls();
try {
@ -136,6 +136,7 @@ export class RewriteSelectionPopover {
cwd: this.options.cwd,
prompt: buildRewritePrompt(this.options.session),
runtimeSettings: this.options.runtimeSettings,
onActivity: (activity) => this.updateActivity(activity),
onPreview: (text) => this.updatePreview(text),
});
this.options.session.replacementText = output.replacementText;
@ -156,9 +157,14 @@ export class RewriteSelectionPopover {
private updatePreview(text: string): void {
this.options.session.streamText = text;
this.previewEl?.setText(text);
this.setStatus("Writing replacement", { active: true });
this.position();
}
private updateActivity(activity: RewriteActivity): void {
this.setStatus(activity === "reasoning" ? "Reasoning" : "Writing replacement", { active: true });
}
private renderDiff(): void {
const replacement = this.options.session.replacementText;
if (replacement === null || !this.diffEl) return;
@ -199,8 +205,16 @@ export class RewriteSelectionPopover {
this.close();
}
private setStatus(text: string): void {
this.statusEl?.setText(text);
private setStatus(text: string, options: { active?: boolean } = {}): void {
if (!this.statusEl) return;
this.statusEl.empty();
this.statusEl.classList.toggle("is-active", Boolean(options.active));
this.statusEl.createSpan({ text });
if (!options.active) return;
const dots = this.statusEl.createSpan({ cls: "codex-panel-rewrite-popover__status-dots" });
dots.createSpan({ text: "." });
dots.createSpan({ text: "." });
dots.createSpan({ text: "." });
}
private syncControls(): void {

View file

@ -28,9 +28,12 @@ export interface RunRewriteSelectionOptions {
cwd: string;
prompt: string;
runtimeSettings?: RewriteRuntimeSettings;
onActivity?: (activity: RewriteActivity) => void;
onPreview?: (text: string) => void;
}
export type RewriteActivity = "reasoning" | "writing";
export async function runRewriteSelection(options: RunRewriteSelectionOptions): Promise<RewriteOutput> {
let threadId: string | null = null;
let expectedTurnId: string | null = null;
@ -54,10 +57,21 @@ export async function runRewriteSelection(options: RunRewriteSelectionOptions):
if (notification.method === "item/agentMessage/delta") {
if (!threadId || notification.params.threadId !== threadId) return;
if (expectedTurnId && notification.params.turnId !== expectedTurnId) return;
options.onActivity?.("writing");
preview += notification.params.delta;
options.onPreview?.(preview);
return;
}
if (
notification.method === "item/reasoning/summaryTextDelta" ||
notification.method === "item/reasoning/textDelta" ||
notification.method === "item/reasoning/summaryPartAdded"
) {
if (!threadId || notification.params.threadId !== threadId) return;
if (expectedTurnId && notification.params.turnId !== expectedTurnId) return;
options.onActivity?.("reasoning");
return;
}
if (notification.method === "item/completed") {
if (!threadId || notification.params.threadId !== threadId) return;
if (expectedTurnId && notification.params.turnId !== expectedTurnId) return;

View file

@ -1430,6 +1430,26 @@
font-size: var(--font-ui-small);
}
.codex-panel-rewrite-popover__status.is-active {
color: var(--text-faint);
}
.codex-panel-rewrite-popover__status-dots span {
opacity: 0.35;
}
.codex-panel-rewrite-popover__status.is-active .codex-panel-rewrite-popover__status-dots span {
animation: codex-panel-reasoning-dot 1.2s infinite ease-in-out;
}
.codex-panel-rewrite-popover__status.is-active .codex-panel-rewrite-popover__status-dots span:nth-child(2) {
animation-delay: 0.18s;
}
.codex-panel-rewrite-popover__status.is-active .codex-panel-rewrite-popover__status-dots span:nth-child(3) {
animation-delay: 0.36s;
}
.codex-panel-rewrite-popover__preview {
display: none;
max-height: 120px;