UNPKG

@stackmemoryai/stackmemory

Version:

Lossless, project-scoped memory for AI coding tools. Durable context across sessions with 56 MCP tools, FTS5 search, conductor orchestrator, loop/watch monitoring, snapshot capture, pre-flight overlap checks, Claude/Codex/OpenCode wrappers, Linear sync, a

102 lines (101 loc) 2.87 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { DEFAULT_GREPTILE_CONFIG } from "./config.js"; class GreptileClientError extends Error { constructor(message, code) { super(message); this.code = code; this.name = "GreptileClientError"; } } class GreptileClient { config; client = null; transport = null; connecting = null; constructor(config = {}) { this.config = { ...DEFAULT_GREPTILE_CONFIG, ...config }; if (!this.config.enabled || !this.config.apiKey) { throw new GreptileClientError( "Greptile integration disabled (GREPTILE_API_KEY not set)", "DISABLED" ); } } async ensureConnected() { if (this.client) return this.client; if (this.connecting) { await this.connecting; return this.client; } this.connecting = this.connect(); try { await this.connecting; return this.client; } finally { this.connecting = null; } } async connect() { const transport = new StreamableHTTPClientTransport( new URL(this.config.mcpEndpoint), { requestInit: { headers: { Authorization: `Bearer ${this.config.apiKey}` } }, reconnectionOptions: { maxRetries: this.config.maxRetries, initialReconnectionDelay: 1e3, reconnectionDelayGrowFactor: 1.5, maxReconnectionDelay: 1e4 } } ); const client = new Client( { name: "stackmemory-greptile", version: "1.0.0" }, { capabilities: {} } ); transport.onclose = () => { this.client = null; this.transport = null; }; await client.connect(transport); this.client = client; this.transport = transport; } async callTool(name, args = {}) { const client = await this.ensureConnected(); const result = await client.callTool({ name, arguments: args }); if (result.content && Array.isArray(result.content)) { const textParts = result.content.filter( (c) => c.type === "text" && typeof c.text === "string" ).map((c) => c.text); if (textParts.length === 0) return result; const combined = textParts.join("\n"); try { return JSON.parse(combined); } catch { return combined; } } return result; } async disconnect() { if (this.transport) { await this.transport.close(); } this.client = null; this.transport = null; this.connecting = null; } } export { GreptileClient, GreptileClientError };