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
@@ -17,6 +17,7 @@ import { useDeviceInfo } from '@/lib/device';
import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel';
import { useFileSearchStore } from '@/stores/useFileSearchStore';
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
import { useIsVSCodeRuntime } from '@/hooks/useRuntimeAPIs';
interface FileInfo {
name: string;
@@ -39,6 +40,8 @@ export const ServerFilePicker: React.FC<ServerFilePickerProps> = ({
children
}) => {
const { isMobile } = useDeviceInfo();
const isVSCodeRuntime = useIsVSCodeRuntime();
const isCompact = isMobile || isVSCodeRuntime;
const { currentDirectory } = useDirectoryStore();
const searchFiles = useFileSearchStore((state) => state.searchFiles);
const [open, setOpen] = React.useState(false);
@@ -331,7 +334,7 @@ export const ServerFilePicker: React.FC<ServerFilePickerProps> = ({
: file.name;
const shouldCompact = isSearchActive && rawLabel.includes('/') && rawLabel.length > 45;
const displayLabel = shouldCompact
? truncatePathMiddle(rawLabel, { maxLength: isMobile ? 42 : 48 })
? truncatePathMiddle(rawLabel, { maxLength: isCompact ? 42 : 48 })
: rawLabel;
const row = (
@@ -437,7 +440,7 @@ export const ServerFilePicker: React.FC<ServerFilePickerProps> = ({
</div>
);
const scrollAreaClass = isMobile ? 'flex-1 min-h-[240px]' : 'h-[300px]';
const scrollAreaClass = isCompact ? 'flex-1 min-h-[240px]' : 'h-[300px]';
const pickerBody = (
<>
@@ -524,7 +527,7 @@ export const ServerFilePicker: React.FC<ServerFilePickerProps> = ({
</span>
);
if (isMobile) {
if (isCompact) {
return (
<>
{mobileTrigger}