diff --git a/windows/src/core/state.ts b/windows/src/core/state.ts index 01236b80a9..71b4f59cb3 100644 --- a/windows/src/core/state.ts +++ b/windows/src/core/state.ts @@ -13,6 +13,11 @@ export interface AgentTask { state: BotStateName; stepIndex: number; steps: string[]; + /** + * Position of the newest step in the whole session. `steps` is capped, so + * `stepIndex` stops moving once it is full; this keeps counting. + */ + stepSeq?: number; source: AgentSource; isIntegration: boolean; emote?: BotEmoteName | null; @@ -186,9 +191,11 @@ class AppState { appendStep(id: string, step: string) { const t = this.tasks.find((x) => x.id === id); if (!t) return; + const newest = t.stepSeq ?? t.steps.length - 1; t.steps.push(step); if (t.steps.length > 20) t.steps.shift(); t.stepIndex = t.steps.length - 1; + t.stepSeq = newest + 1; this.notify(); } diff --git a/windows/src/island/hooks.ts b/windows/src/island/hooks.ts index d90a78f099..246c02ea30 100644 --- a/windows/src/island/hooks.ts +++ b/windows/src/island/hooks.ts @@ -132,6 +132,7 @@ function clearSession() { if (!t) return; t.steps = []; t.stepIndex = 0; + delete t.stepSeq; t.name = "VS Code"; t.pillBadge = null; } diff --git a/windows/src/views/ticker.ts b/windows/src/views/ticker.ts index 72b18023ef..6d03f2cdb2 100644 --- a/windows/src/views/ticker.ts +++ b/windows/src/views/ticker.ts @@ -96,31 +96,27 @@ export class Ticker { } sync(task: AgentTask | null) { - const steps = task && task.steps.length > 0 ? task.steps : ["…"]; - const idx = task ? Math.min(task.stepIndex, steps.length - 1) : -1; - - // First render: drop straight into place, no animation. - if (this.displayIndex < 0) { - this.displayIndex = idx; - setText(this.a, idx > 0 ? steps[idx - 1] : "…"); - setText(this.b, steps[Math.max(idx, 0)]); - this.rest(); - return; - } - - // The session restarted (steps were cleared): re-seed rather than scroll. - if (idx < this.displayIndex) { + const steps = task?.steps ?? []; + // Where the newest step sits in the whole session, not in `steps`: that + // list is capped at 20, and counting inside it made the ticker stop for + // good at the twentieth step of a session. + const newest = steps.length === 0 ? -1 : (task?.stepSeq ?? steps.length - 1); + + // First render, or the session restarted (steps were cleared): drop + // straight into place rather than scroll. + if (this.displayIndex < 0 || newest < this.displayIndex) { this.queue = []; this.startMs = null; - this.displayIndex = idx; - setText(this.a, idx > 0 ? steps[idx - 1] : "…"); - setText(this.b, steps[Math.max(idx, 0)]); + this.displayIndex = newest; + setText(this.a, steps.at(-2) ?? "…"); + setText(this.b, steps.at(-1) ?? "…"); this.rest(); return; } - for (let i = this.displayIndex + 1; i <= idx; i++) this.queue.push(steps[i]); - this.displayIndex = idx; + const fresh = Math.min(newest - this.displayIndex, steps.length); + if (fresh > 0) this.queue.push(...steps.slice(-fresh)); + this.displayIndex = newest; if (this.queue.length > MAX_QUEUE) { this.queue = this.queue.slice(-MAX_QUEUE); }