feat: vscode extension (#59)

* feat: add initial VS Code extension plan and implementation tasks

* feat(vscode): added initial version of an Openchamber VSCode extension

* feat(vscode): enhance VS Code extension with theme integration and session management

* feat(vscode): implement connection status handling and overlay in VSCode layout

* feat: move extension to secondary sidebar

* chore: upgrade @opencode-ai/sdk to 1.0.150

* vscode: editor bridge, file picker, click-to-open in tool parts

* vscode: layout session lifecycle, theme sync, typography overrides

* ui: compact mode for vscode, model search, autocomplete width fixes

* perf: scroll force flag, raf placeholder, git polling backoff

* ui: tool output styling, markdown code block fix, gitignore

* refactor: update typography handling for VSCode runtime, remove unused styles

* docs: update README with VS Code extension details and add extension image

* docs: update changelog with new features and performance improvements
This commit is contained in:
Bohdan Triapitsyn
2025-12-13 16:34:17 +02:00
committed by GitHub
parent 610ccf4c62
commit bb72c0fb0c
76 changed files with 6097 additions and 296 deletions
@@ -34,6 +34,8 @@ export function WorkingPlaceholder({
const fadeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const resultTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const transitionTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const rafIdRef = useRef<number | null>(null);
const lastCheckTimeRef = useRef<number>(0);
const lastActiveStatusRef = useRef<string | null>(null);
const hasShownActivityRef = useRef<boolean>(false);
const wasAbortedRef = useRef<boolean>(false);
@@ -207,7 +209,16 @@ export function WorkingPlaceholder({
wasAbortedRef.current = false;
};
const checkInterval = setInterval(() => {
const CHECK_THROTTLE_MS = 150; // Throttle checks to ~6-7 times per second
const checkLoop = (timestamp: number) => {
// Throttle: skip if less than CHECK_THROTTLE_MS since last check
if (timestamp - lastCheckTimeRef.current < CHECK_THROTTLE_MS) {
rafIdRef.current = requestAnimationFrame(checkLoop);
return;
}
lastCheckTimeRef.current = timestamp;
const now = Date.now();
const elapsed = now - displayStartTimeRef.current;
@@ -216,6 +227,7 @@ export function WorkingPlaceholder({
const shouldWaitForMinTime = !isDone && statusQueueRef.current.length > 0;
if (shouldWaitForMinTime && elapsed < MIN_DISPLAY_TIME) {
rafIdRef.current = requestAnimationFrame(checkLoop);
return;
}
@@ -257,14 +269,24 @@ export function WorkingPlaceholder({
lastActiveStatusRef.current = null;
removalPendingRef.current = false;
wasAbortedRef.current = false;
rafIdRef.current = requestAnimationFrame(checkLoop);
return;
}
startFadeOut(result);
}
}, 50);
return () => clearInterval(checkInterval);
rafIdRef.current = requestAnimationFrame(checkLoop);
};
rafIdRef.current = requestAnimationFrame(checkLoop);
return () => {
if (rafIdRef.current !== null) {
cancelAnimationFrame(rafIdRef.current);
rafIdRef.current = null;
}
};
}, [isFadingOut]);