ContextKeeper v1.0.0 — Persistent AI coding session context Chrome extension

This commit is contained in:
Bun Bun
2026-06-21 00:22:17 +00:00
commit 73f7b13e9d
25 changed files with 4544 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
import { describe, it, expect } from 'vitest';
import { PlatformDetector } from '../src/lib/detector';
describe('PlatformDetector', () => {
const detector = new PlatformDetector();
it('detects ChatGPT URLs', () => {
expect(detector.detect('https://chatgpt.com/c/123')).toBe('chatgpt');
expect(detector.detect('https://chat.openai.com/chat')).toBe('chatgpt');
});
it('detects Claude URLs', () => {
expect(detector.detect('https://claude.ai/chat/abc')).toBe('claude');
});
it('detects Cursor URLs', () => {
expect(detector.detect('https://cursor.sh/chat')).toBe('cursor');
});
it('detects Gemini URLs', () => {
expect(detector.detect('https://gemini.google.com/app')).toBe('gemini');
expect(detector.detect('https://aistudio.google.com/app')).toBe('gemini');
});
it('detects Copilot URLs', () => {
expect(detector.detect('https://copilot.microsoft.com/')).toBe('copilot');
expect(detector.detect('https://github.com/copilot')).toBe('copilot');
});
it('returns null for unrelated URLs', () => {
expect(detector.detect('https://google.com')).toBeNull();
expect(detector.detect('https://example.com')).toBeNull();
});
it('maps platform keys to display names', () => {
expect(detector.getPlatformName('chatgpt')).toBe('ChatGPT');
expect(detector.getPlatformName('claude')).toBe('Claude');
expect(detector.getPlatformName('unknown')).toBe('unknown');
});
it('lists all supported platforms', () => {
const platforms = detector.getSupportedPlatforms();
expect(platforms).toContain('chatgpt');
expect(platforms).toContain('claude');
expect(platforms).toContain('cursor');
expect(platforms).toContain('gemini');
expect(platforms).toContain('copilot');
});
});
+86
View File
@@ -0,0 +1,86 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { ContextExtractor } from '../src/lib/extractor';
describe('ContextExtractor', () => {
let extractor: ContextExtractor;
beforeEach(() => {
extractor = new ContextExtractor();
});
it('extracts nothing for unknown platforms', () => {
expect(extractor.extract('unknown')).toBe('');
});
it('extracts ChatGPT conversation turns', () => {
document.body.innerHTML = `
<div data-testid="conversation-turn-1">
<div>Hello AI</div>
</div>
<div data-testid="conversation-turn-2">
<div>Hi there!</div>
</div>
`;
const result = extractor.extract('chatgpt');
expect(result).toContain('[user]: Hello AI');
expect(result).toContain('[assistant]: Hi there!');
});
it('falls back to article elements for ChatGPT', () => {
document.body.innerHTML = `
<article>First message</article>
<article>Second message</article>
`;
const result = extractor.extract('chatgpt');
expect(result).toContain('[user]: First message');
expect(result).toContain('[assistant]: Second message');
});
it('extracts Claude messages', () => {
document.body.innerHTML = `
<div class="message">How do I refactor this?</div>
<div class="message">Here is a suggestion...</div>
`;
const result = extractor.extract('claude');
expect(result).toContain('[human]: How do I refactor this?');
expect(result).toContain('[assistant]: Here is a suggestion...');
});
it('extracts Cursor chat', () => {
document.body.innerHTML = `
<div class="chat-message">Fix this bug</div>
<div class="chat-message">The issue is...</div>
`;
const result = extractor.extract('cursor');
expect(result).toContain('[user]: Fix this bug');
expect(result).toContain('[assistant]: The issue is...');
});
it('removes buttons and timestamps from content', () => {
document.body.innerHTML = `
<article>
Some code
<button>Copy</button>
<span class="timestamp">2:30 PM</span>
</article>
`;
const result = extractor.extract('chatgpt');
expect(result).toContain('Some code');
expect(result).not.toContain('Copy');
expect(result).not.toContain('2:30 PM');
});
it('returns empty string when no elements found', () => {
document.body.innerHTML = '<div>Empty page</div>';
expect(extractor.extract('chatgpt')).toBe('');
});
it('skips very short text', () => {
document.body.innerHTML = `
<article>Hi</article>
<article></article>
`;
const result = extractor.extract('chatgpt');
expect(result).toBe('');
});
});