Newer
Older
abysiuscodium / extensions / abysius-ai / src / extension.ts
import * as vscode from 'vscode';
import { InlineCompletionProvider } from './inlineCompletion';
import { ChatPanel } from './chatPanel';
import { AbysiusApi } from './api';

let inlineProvider: InlineCompletionProvider | undefined;
let chatPanel: ChatPanel | undefined;
let api: AbysiusApi;

async function showPrivacyNotice(context: vscode.ExtensionContext) {
    const result = await vscode.window.showInformationMessage(
        'Abysius AI sends code snippets to remote servers. Please review our Privacy Policy and Terms.',
        'Open Privacy Policy',
        'Open Terms',
        'I Consent'
    );

    if (result === 'I Consent') {
        const config = vscode.workspace.getConfiguration('abysius');
        await config.update('privacyConsent', true, true);
    } else if (result === 'Open Privacy Policy') {
        vscode.env.openExternal(vscode.Uri.file('/workspace/PRIVACY.md'));
    } else if (result === 'Open Terms') {
        vscode.env.openExternal(vscode.Uri.file('/workspace/TERMS.md'));
    }
}

export function activate(context: vscode.ExtensionContext) {
    const config = vscode.workspace.getConfiguration('abysius');

    const privacyConsent = config.get<boolean>('privacyConsent', false);
    if (!privacyConsent) {
        showPrivacyNotice(context);
    }

    api = new AbysiusApi({
        apiKey: config.get<string>('apiKey', 'sk-doom'),

        // OpenAI-compatible endpoints
        chatEndpoint: config.get<string>(
            'chatEndpoint',
            'https://api.abysius.ai/v1/chat/completions'
        ),
        inlineEndpoint: config.get<string>(
            'inlineEndpoint',
            'https://api.abysius.ai/v1/completions'
        ),

        model: config.get<string>('model', 'kimi-k2'),

        dataResidency: config.get<'auto' | 'us' | 'eu' | 'asia'>('dataResidency', 'auto'),
        enableAuditLog: config.get<boolean>('enableAuditLog', true),
        geoBlockRestrictedRegions: config.get<boolean>('geoBlockRestrictedRegions', true),
        anonymizeFilePaths: config.get<boolean>('anonymizeFilePaths', true)
    });

    if (config.get<boolean>('enableInlineCompletions', true)) {
        inlineProvider = new InlineCompletionProvider(api);

        const selector: vscode.DocumentSelector = [
            { scheme: 'file' },
            { scheme: 'untitled' }
        ];

        const provider = vscode.languages.registerInlineCompletionItemProvider(
            selector,
            inlineProvider
        );

        context.subscriptions.push(provider);
    }

    chatPanel = new ChatPanel(context.extensionUri, api);

    const chatViewProvider = vscode.window.registerWebviewViewProvider(
        'abysius.chatPanel',
        chatPanel,
        { webviewOptions: { retainContextWhenHidden: true } }
    );

    context.subscriptions.push(chatViewProvider);

    vscode.commands.executeCommand('setContext', 'abysiusChatEnabled', true);

    context.subscriptions.push(
        vscode.commands.registerCommand('abysius.openChat', () => {
            chatPanel?.show();
        }),

        vscode.commands.registerCommand('abysius.acceptInlineCompletion', () => {
            inlineProvider?.accept();
        }),

        vscode.commands.registerCommand('abysius.rejectInlineCompletion', () => {
            inlineProvider?.reject();
        }),

        vscode.commands.registerCommand('abysius.triggerInlineCompletion', () => {
            inlineProvider?.trigger();
        }),

        vscode.commands.registerCommand('abysius.acceptNextWord', () => {
            inlineProvider?.acceptNextWord();
        }),

        vscode.commands.registerCommand('abysius.openSettings', () => {
            vscode.commands.executeCommand('workbench.action.openSettings', 'abysius');
        }),

        vscode.commands.registerCommand('abysius.clearChat', () => {
            chatPanel?.clear();
        })
    );

    context.subscriptions.push(
        vscode.workspace.onDidChangeConfiguration(e => {
            if (e.affectsConfiguration('abysius')) {
                const newConfig = vscode.workspace.getConfiguration('abysius');

                api.updateConfig({
                    apiKey: newConfig.get<string>('apiKey', 'sk-doom'),

                    // OpenAI-compatible endpoints
                    chatEndpoint: newConfig.get<string>(
                        'chatEndpoint',
                        'https://api.abysius.ai/v1/chat/completions'
                    ),
                    inlineEndpoint: newConfig.get<string>(
                        'inlineEndpoint',
                        'https://api.abysius.ai/v1/completions'
                    ),

                    model: newConfig.get<string>('model', 'kimi-k2'),

                    dataResidency: newConfig.get<'auto' | 'us' | 'eu' | 'asia'>('dataResidency', 'auto'),
                    enableAuditLog: newConfig.get<boolean>('enableAuditLog', true),
                    geoBlockRestrictedRegions: newConfig.get<boolean>('geoBlockRestrictedRegions', true),
                    anonymizeFilePaths: newConfig.get<boolean>('anonymizeFilePaths', true)
                });
            }
        })
    );

    const statusItem = vscode.window.createStatusBarItem(
        vscode.StatusBarAlignment.Right,
        100
    );

    statusItem.text = "$(sparkle) Abysius";
    statusItem.tooltip = "Abysius AI is active";
    statusItem.command = 'abysius.openChat';
    statusItem.show();

    context.subscriptions.push(statusItem);

    console.log('[Abysius AI] Extension activated');
}

export function deactivate() {
    inlineProvider?.dispose();
    chatPanel?.dispose();
    console.log('[Abysius AI] Extension deactivated');
}