const express = require('express'); const path = require('path'); const fs = require('fs'); const os = require('os'); const { createRequire } = require('module'); const app = express(); app.use(express.json({ limit: '10mb' })); app.use(express.static(path.join(__dirname, 'public'))); const MODELS = { sonnet: 'claude-sonnet-4-6', haiku: 'claude-haiku-4-5-20251001', }; function getAccessToken() { const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude'); const credsPath = path.join(configDir, '.credentials.json'); try { const creds = JSON.parse(fs.readFileSync(credsPath, 'utf8')); return creds?.claudeAiOauth?.accessToken || null; } catch (e) { return null; } } function createClient(accessToken) { const Anthropic = require('@anthropic-ai/sdk'); // OAuth token: use as apiKey — SDK sends x-api-key header // Some versions also support authToken for Bearer auth try { return new Anthropic({ authToken: accessToken }); } catch (e) { return new Anthropic({ apiKey: accessToken }); } } app.post('/api/chat', async (req, res) => { const { text, model = 'sonnet' } = req.body; if (!text?.trim()) return res.status(400).json({ error: 'text required' }); const modelId = MODELS[model] || MODELS.sonnet; const accessToken = getAccessToken(); if (!accessToken) { return res.status(500).json({ error: 'No credentials found in ' + (process.env.CLAUDE_CONFIG_DIR || '~/.claude') }); } res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.flushHeaders(); const heartbeat = setInterval(() => res.write(': ping\n\n'), 15000); try { const client = createClient(accessToken); const stream = await client.messages.stream({ model: modelId, max_tokens: 8192, messages: [{ role: 'user', content: text }], }); for await (const event of stream) { if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta') { res.write(`data: ${JSON.stringify({ text: event.delta.text })}\n\n`); } } } catch (err) { console.error('[api error]', err.message); res.write(`data: ${JSON.stringify({ error: err.message })}\n\n`); } finally { clearInterval(heartbeat); res.write('data: [DONE]\n\n'); res.end(); } }); app.listen(8108, () => console.log('sechenov :8108'));