Skip to content

Commit ed025b7

Browse files
Nagi-ovoclaude
andcommitted
refactor(plugins): migrate claude-timeline to scope-based lifecycle
The 12-resource hand-written destroy() is gone: every timer, listener, observer, DOM node, and the preview panel's destroy() chain now registers on the PluginScope and unwinds automatically. Two behaviors this adds: - data-gv-claude-turn-id stamps on Claude's own turn nodes are rolled back on unmount (previously leaked). - coachmarks accept an AbortSignal; a disposed scope closes an in-flight guide as 'skipped' without burning its once-per-user seen state. Startup registers as a pending scope effect, so unmounting mid-start barriers on it instead of relying on a destroyed flag. updateSettings stays as the fine-grained path — grow-only virtualized markers and the rail DOM survive settings changes, unchanged. One-shot scope timers and frames now release their ledger slot on firing, keeping debounce-heavy consumers bounded. The 641-line behavior suite passes with only the stop-is-now-async await adjustments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 97ee149 commit ed025b7

8 files changed

Lines changed: 258 additions & 118 deletions

File tree

src/features/plugins/builtin/claudeTimeline/index.test.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ describe('Claude timeline', () => {
100100
Object.defineProperty(window, 'scrollY', { configurable: true, value: 0 });
101101
});
102102

103-
afterEach(() => {
104-
stopClaudeTimeline();
103+
afterEach(async () => {
104+
await stopClaudeTimeline();
105105
vi.useRealTimers();
106106
});
107107

@@ -627,13 +627,23 @@ describe('Claude timeline', () => {
627627
queryAll.mockRestore();
628628
});
629629

630+
it('rolls back data-gv-claude-turn-id stamps on stop', async () => {
631+
addTurn('first prompt');
632+
startClaudeTimeline();
633+
await flush();
634+
expect(document.querySelectorAll('[data-gv-claude-turn-id]').length).toBeGreaterThan(0);
635+
636+
await stopClaudeTimeline();
637+
expect(document.querySelectorAll('[data-gv-claude-turn-id]').length).toBe(0);
638+
});
639+
630640
it('removes UI on stop', async () => {
631641
addTurn('first prompt');
632642
startClaudeTimeline();
633643
await flush();
634644
expect(document.querySelector('.gemini-timeline-bar')).toBeTruthy();
635645

636-
stopClaudeTimeline();
646+
await stopClaudeTimeline();
637647
expect(document.querySelector('.gemini-timeline-bar')).toBeNull();
638648
expect(document.querySelector('.timeline-preview-toggle')).toBeNull();
639649
expect(document.querySelector('#claude-timeline-tooltip')).toBeNull();

0 commit comments

Comments
 (0)