Package Exports
- androidsprintteam-solver-sdk
Readme
Code Solver SDK v7.1.1
Backend SDK для интеграции с Code Solver API (Pure Cloud-First)
📑 Навигация
Быстрый старт:
Работа с проектами:
Типы и решение проблем:
🔒 Установка (GitHub Packages - Private)
SDK теперь приватный и публикуется в GitHub Packages.
Требования:
- GitHub Personal Access Token с правами
read:packages - Доступ к организации
AndroidSprintTeam
Установка:
# 1. Создай .npmrc в корне проекта
cat > .npmrc << 'EOF'
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
@androidsprintteam:registry=https://npm.pkg.github.com
always-auth=true
EOF
# 2. Установи SDK
npm install @androidsprintteam/solver-sdkСоздание токена: https://github.com/settings/tokens/new (scopes: read:packages, repo)
Полная документация: см. GITHUB_PACKAGES_SETUP.md
🚀 Быстрый старт
Локальная разработка
import { CodeSolverSDK } from '@androidsprintteam/solver-sdk';
const sdk = await CodeSolverSDK.create({
baseURL: 'http://localhost:3000',
apiKey: 'your-api-key'
});Production с OAuth
const sdk = await CodeSolverSDK.create({
baseURL: 'https://workai.su/api/v1',
headers: { Authorization: `Bearer ${oauth_token}` },
webSocket: { enabled: true }
});🔑 Динамическое обновление токена (v6.1.4+)
const sdk = await CodeSolverSDK.create({
baseURL: 'https://workai.su/api/v1',
getAuthToken: async () => {
if (authManager.isTokenExpired()) {
await authManager.refreshAccessToken();
}
return authManager.getAccessToken();
}
});📖 Быстрая справка
| Задача | Метод | Назначение |
|---|---|---|
| Индексация | ||
| Синхронизировать проект | sdk.deltaManager.syncEncryptedChunks(projectId, chunks, rootHash) |
Единственный способ индексации |
| Проверить статус | sdk.projects.getProjectState(projectId, clientRootHash?) |
Получить состояние + totalFiles |
| Проверить recovery | sdk.projects.getRecoveryStatus(projectId) |
Нужно ли возобновить прерванную синхронизацию |
| Возобновить синхронизацию | sdk.projects.resumeSync(projectId) |
Продолжить прерванную индексацию |
| Real-time прогресс | ||
| Подключить WebSocket | await sdk.connectWebSocket() |
Для live обновлений |
| Подписаться на проект | sdk.projectSync.subscribeToProject(projectId) |
Получать события по проекту |
| Прогресс индексации | sdk.projectSync.on('sync-progress', callback) |
data.processedFiles / data.totalFiles |
| Завершение индексации | sdk.projectSync.on('sync-completed', callback) |
data.statistics.totalFiles |
| Проекты | ||
| Получить все проекты | sdk.projects.getAllProjects() |
Список всех проектов |
| Найти или создать | sdk.projects.findOrCreateProject(name) |
Idempotent создание |
| Получить проект | sdk.projects.getProject(projectId) |
Детали проекта |
| Поиск | ||
| Поиск по коду | sdk.search.searchCode(projectId, query) |
Semantic search с reranker |
| Поиск функций | sdk.search.searchFunctions(projectId, query) |
Только функции/методы |
| Чат | ||
| Streaming чат | sdk.chat.streamChat(messages, options) |
AsyncGenerator chunks |
| Обычный чат | sdk.chat.chat(messages, options) |
Promise response |
📖 API Reference (подробно)
Projects API (sdk.projects) - управление проектами
// Основные методы
getAllProjects(): Promise<Project[]>
getProject(projectId: string): Promise<Project>
findOrCreateProject(projectName: string): Promise<Project>
// Индексация
getProjectState(projectId: string, clientRootHash?: string): Promise<ProjectState>
getIndexingStatus(projectId: string): Promise<any>
// Recovery
getRecoveryStatus(projectId: string): Promise<any>
resumeSync(projectId: string, options?: any): Promise<any>
cancelRecovery(projectId: string): Promise<any>Delta Manager API (sdk.deltaManager) - индексация проекта
// Основной метод индексации
syncEncryptedChunks(
projectId: string,
encryptedChunks: any[],
rootHash: string,
options?: { batchSize?: number; onProgress?: (current, total) => void }
): Promise<any>
// Вспомогательные
getSyncStatus(projectId: string): Promise<SyncStatus>
cancelSync(projectId: string): Promise<boolean>
cleanupDeletedFiles(projectId: string, activeFiles: any[]): Promise<any>Search API (sdk.search) - поиск по коду
searchCode(projectId: string, query: string, options?: any): Promise<any[]>
searchFunctions(projectId: string, query: string, options?: any): Promise<any[]>
semanticSearch(projectId: string, query: string, options?: any): Promise<any[]>Chat API (sdk.chat) - AI чат
// Streaming
streamChat(messages: ChatMessage[], options?: ChatStreamOptions): AsyncGenerator<ChatStreamChunk>
// Обычный
chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>
chatWithRegionFailover(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>WebSocket API (sdk.projectSync)
// Подключение
await sdk.connectWebSocket()
sdk.disconnectWebSocket()
sdk.isWebSocketConnected
// Подписка
sdk.projectSync.subscribeToProject(projectId)
sdk.projectSync.unsubscribeFromProject(projectId)
// События
sdk.projectSync.on('sync-status-update', callback) // {projectId, status, timestamp}
sdk.projectSync.on('sync-progress', callback) // {projectId, progress, processedFiles, totalFiles}
sdk.projectSync.on('sync-completed', callback) // {projectId, processedChunks, statistics}
sdk.projectSync.on('sync-error', callback) // {projectId, error, timestamp}
// Пример: Cursor-like прогресс по файлам (v7.1.1+)
sdk.projectSync.on('sync-progress', (data) => {
if (data.totalFiles && data.processedFiles) {
// User-friendly: "450 of 722 files"
console.log(`${data.processedFiles}/${data.totalFiles} files (${data.progress}%)`);
updateUI(data.processedFiles, data.totalFiles, data.progress);
} else {
// Fallback: chunks (для старых версий backend)
console.log(`${data.currentChunk}/${data.totalChunks} chunks`);
}
});
sdk.projectSync.on('sync-completed', (data) => {
const files = data.statistics?.totalFiles || 0;
console.log(`Indexed ${files} files in ${data.duration}ms`);
});🔧 Как работать с SDK
Индексация проекта
// ✅ ЕДИНСТВЕННЫЙ способ индексации (v6.2.2+):
await sdk.deltaManager.syncEncryptedChunks(projectId, chunks, rootHash, {
batchSize: 50,
onProgress: (current, total) => console.log(`${current}/${total}`)
});
// ❌ УДАЛЕНО: sdk.projects.startIndexing() - больше не существует
// ❌ УДАЛЕНО: filesystem индексация на сервереВажно: Client Extension создает chunks → SDK отправляет на сервер → Сервер индексирует
Session Recovery
// Всегда проверять при старте проекта
const recovery = await sdk.projects.getRecoveryStatus(projectId);
if (recovery.needsRecovery) {
// ✨ v6.2.2+: показывает "480 из 642 файлов" вместо "0 из 0"
// Показать диалог: Continue (67%) — 480/642 files | Start Fresh
await sdk.projects.resumeSync(projectId); // или cancelRecovery()
}WebSocket
- Требуется OAuth токен в production
- Автоматическое переподключение при разрыве
- События фильтруются по
projectId - Fallback на HTTP polling если недоступен
Авторизация
- Локально:
apiKeyдля HTTP API - Production: OAuth
access_tokenдля HTTP + WebSocket - v6.1.4+:
getAuthToken()для автоматического обновления токенов
Graceful Auth Errors (v7.0.1+)
По умолчанию SDK тихо обрабатывает 401/403 ошибки (возвращает null) вместо выброса исключения.
Это предотвращает ERR логи в VS Code Extension Host.
const sdk = await CodeSolverSDK.create({
baseURL: 'https://workai.su/api/v1',
suppressAuthErrors: true // По умолчанию true
});
// Если токен истек, SDK вернет null вместо throw
const projects = await sdk.projects.getAllProjects();
if (!projects) {
// Extension сам обрабатывает auth ошибку
await authManager.refreshToken();
}Отключить (старое поведение):
const sdk = await CodeSolverSDK.create({
suppressAuthErrors: false // SDK будет бросать ошибки как раньше
});📝 Примеры
Базовый workflow
const sdk = await CodeSolverSDK.create({
baseURL: 'https://workai.su/api/v1',
getAuthToken: () => authManager.getAccessToken()
});
// 1. Найти/создать проект
const project = await sdk.projects.findOrCreateProject('/path/to/project');
// 2. Проверить recovery
const recovery = await sdk.projects.getRecoveryStatus(project.id);
if (recovery.needsRecovery) {
await sdk.projects.resumeSync(project.id);
return;
}
// 3. Проверить нужна ли синхронизация
const state = await sdk.projects.getProjectState(project.id, clientRootHash);
if (!state.syncRequired) {
console.log('Проект синхронизирован');
return;
}
// 4. Подключить WebSocket для прогресса
await sdk.connectWebSocket();
sdk.projectSync.subscribeToProject(project.id);
sdk.projectSync.on('sync-progress', (data) => {
console.log(`Прогресс: ${data.progress}%`);
});
// 5. Синхронизировать
await sdk.deltaManager.syncEncryptedChunks(project.id, chunks, rootHash);
// 6. Поиск по проекту
const results = await sdk.search.searchCode(project.id, 'function handleClick');Chat с streaming
for await (const chunk of sdk.chat.streamChat(messages, { model: 'claude-3-5-sonnet' })) {
if (chunk.type === 'content_block_delta') {
process.stdout.write(chunk.delta.text);
}
}ℹ️ Архитектура
Pure Cloud-First:
- Backend SDK — HTTP клиент (НЕ работает с файлами)
- Client Extension — сканирует файлы, создает chunks
- Только Delta-Chunking — filesystem индексация удалена
Миграция с v6.x
BREAKING CHANGES:
- ❌ Удален
sdk.projects.startIndexing() - ✅ Используйте
sdk.deltaManager.syncEncryptedChunks()
// ❌ Старый код:
// await sdk.projects.startIndexing(projectId);
// ✅ Новый код:
const chunks = await extension.scanAndCreateChunks();
const hash = extension.calculateMerkleRoot();
await sdk.deltaManager.syncEncryptedChunks(projectId, chunks, hash);📦 Ключевые типы данных
ProjectState (v7.1.0+)
interface ProjectState {
projectId: string;
projectName: string;
merkleRootHash: string | null; // Server Merkle root для сравнения
lastIndexedAt: Date | null;
totalChunks: number; // Технические детали
totalFiles: number; // ✨ Количество файлов для UI
indexingStatus: 'pending' | 'in-progress' | 'complete' | 'failed' | 'cancelled';
syncRequired?: boolean; // true если нужна синхронизация
lastSyncSessionId?: string;
}
// Использование:
const state = await sdk.projects.getProjectState(projectId, clientRootHash);
if (state.syncRequired) {
// Нужна синхронизация
}
console.log(`${state.totalFiles} files indexed`);SyncProgressEvent (v7.1.1+)
interface SyncProgressEvent {
projectId: string;
sessionId: string;
stage: 'receiving_chunks' | 'processing_chunks' | 'creating_embeddings' | 'updating_tree' | 'finalizing';
progress: number; // 0-100
// User-friendly (файлы) - основное для UI
processedFiles?: number; // 450
totalFiles?: number; // 722
// Technical (чанки) - опционально
currentChunk?: number;
totalChunks?: number;
estimatedTimeRemaining?: number; // секунды
details?: string;
timestamp: Date;
}
// Использование:
sdk.projectSync.on('sync-progress', (data) => {
if (data.totalFiles) {
statusBar.text = `${data.processedFiles}/${data.totalFiles} files`;
}
});SyncCompletedEvent (v7.1.1+)
interface SyncCompletedEvent {
projectId: string;
sessionId: string;
status: 'success' | 'failed' | 'cancelled';
totalProcessed: number;
duration: number; // миллисекунды
errors?: string[];
warnings?: string[];
statistics?: {
filesIndexed: number;
embeddingsCreated: number;
chunksProcessed: number;
totalSize: number;
totalFiles?: number; // ✨ Для финального отображения
};
}RecoveryInfo
interface RecoveryInfo {
sessionId: string;
projectId: string;
projectName: string;
status: 'interrupted' | 'paused' | 'active' | 'uploading';
progress: {
received: number; // Чанки получены
processed: number; // Чанки обработаны
total: number; // Всего ожидается
percentage: number; // 0-100
processedFiles?: number; // ✨ Файлы обработаны
totalFiles?: number; // ✨ Всего файлов
filesPercentage?: number; // ✨ 0-100 по файлам
};
canResume: boolean;
needsRecovery: boolean;
interruptedAt?: Date;
}🆘 Быстрое решение проблем
Проблема: "0 files" после индексации
// Проверить:
const state = await sdk.projects.getProjectState(projectId);
console.log(state.totalFiles); // Должно быть > 0
// Если 0 - backend не сохранил totalFiles
// Решение: Обновите backend до последней версииПроблема: Нет WebSocket обновлений
// 1. Проверить подключение
console.log(sdk.isWebSocketConnected); // должно быть true
// 2. Проверить подписку
sdk.projectSync.subscribeToProject(projectId);
// 3. Проверить токен (production)
const sdk = await CodeSolverSDK.create({
baseURL: 'https://workai.su/api/v1',
getAuthToken: () => authManager.getAccessToken() // OAuth required
});
// 4. Fallback на HTTP polling
const status = await sdk.projects.getIndexingStatus(projectId);Проблема: Прерванная синхронизация
// Проверить recovery status
const recovery = await sdk.projects.getRecoveryStatus(projectId);
if (recovery.needsRecovery) {
// Показать UI диалог
const percentage = recovery.progress.filesPercentage || recovery.progress.percentage;
const files = `${recovery.progress.processedFiles}/${recovery.progress.totalFiles}`;
// Пользователь выбирает:
await sdk.projects.resumeSync(projectId); // Продолжить
// или
await sdk.projects.cancelRecovery(projectId); // Начать заново
}Проблема: 401/403 ошибки
// v7.0.1+: По умолчанию возвращает null
const projects = await sdk.projects.getAllProjects();
if (!projects) {
// Токен истек
await authManager.refreshToken();
// Повторить запрос
}
// Старое поведение (throw):
const sdk = await CodeSolverSDK.create({
suppressAuthErrors: false
});📚 Справка
TypeScript типы
import {
ChatMessage,
ChatOptions,
Project,
ProjectState,
SyncProgressEvent,
SyncCompletedEvent,
RecoveryInfo
} from '@androidsprintteam/solver-sdk';Debug режим
const sdk = await CodeSolverSDK.create({
debug: 'verbose', // silent | error | warn | info | debug | verbose
webSocket: { debug: true }
});Обработка ошибок
try {
await sdk.projects.getProject(projectId);
} catch (error) {
console.error(`[HTTP ${error.status}] ${error.message}`);
}📄 License
MIT