@memoryrelay/mcp-server 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -3
- package/dist/{chunk-P6TZEH6O.js → chunk-PFC5Z5ZD.js} +62 -5
- package/dist/chunk-PFC5Z5ZD.js.map +1 -0
- package/dist/cli/test.js +1 -1
- package/dist/index.js +254 -3
- package/dist/index.js.map +1 -1
- package/docs/OPENCLAW_GUIDE.md +64 -13
- package/docs/SECURITY.md +6 -6
- package/package.json +1 -1
- package/dist/chunk-P6TZEH6O.js.map +0 -1
package/docs/OPENCLAW_GUIDE.md
CHANGED
|
@@ -79,40 +79,91 @@ For most OpenClaw setups, setting `OPENCLAW_AGENT_NAME` in the config is suffici
|
|
|
79
79
|
|
|
80
80
|
## Available Tools
|
|
81
81
|
|
|
82
|
-
The MCP server exposes
|
|
82
|
+
The MCP server exposes 44 tools across 8 groups:
|
|
83
83
|
|
|
84
|
-
### Memory Tools
|
|
84
|
+
### Memory Tools (core)
|
|
85
85
|
|
|
86
86
|
| Tool | Description |
|
|
87
87
|
|---|---|
|
|
88
|
-
| `memory_store` | Store a new memory with optional metadata and
|
|
88
|
+
| `memory_store` | Store a new memory with optional metadata, deduplication, and entity extraction. |
|
|
89
89
|
| `memory_search` | Semantic search across memories using natural language queries. |
|
|
90
90
|
| `memory_list` | List recent memories chronologically with pagination. |
|
|
91
91
|
| `memory_get` | Retrieve a specific memory by its UUID. |
|
|
92
92
|
| `memory_update` | Update the content or metadata of an existing memory. |
|
|
93
93
|
| `memory_delete` | Permanently delete a memory by its UUID. |
|
|
94
|
+
| `memory_forget` | Alias for memory_delete (natural language convenience). |
|
|
95
|
+
| `memory_recall` | Alias for memory_search (natural language convenience). |
|
|
96
|
+
| `memory_batch_store` | Store multiple memories in a single request. |
|
|
97
|
+
| `memory_context` | Build a context string from relevant memories. |
|
|
98
|
+
| `entity_create` | Create a named entity (person, place, organization, project, concept). |
|
|
99
|
+
| `entity_link` | Link an entity to a memory with a relationship label. |
|
|
100
|
+
| `entity_list` | List entities in the knowledge graph with pagination. |
|
|
101
|
+
| `entity_graph` | Get an entity's neighborhood in the knowledge graph. |
|
|
102
|
+
| `agent_list` | List all agents with their memory counts. |
|
|
103
|
+
| `agent_create` | Create a new named agent (memory namespace). |
|
|
104
|
+
| `agent_get` | Get details of a specific agent by ID. |
|
|
105
|
+
| `memory_health` | Check API connectivity and server health status. |
|
|
94
106
|
|
|
95
|
-
###
|
|
107
|
+
### V2 Async Tools (v2)
|
|
96
108
|
|
|
97
109
|
| Tool | Description |
|
|
98
110
|
|---|---|
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
111
|
+
| `memory_store_async` | Store a memory asynchronously (returns immediately with job ID). |
|
|
112
|
+
| `memory_status` | Check processing status of an async memory. |
|
|
113
|
+
| `context_build` | Build a ranked context bundle with optional AI summarization. |
|
|
102
114
|
|
|
103
|
-
###
|
|
115
|
+
### Session Tools (sessions)
|
|
104
116
|
|
|
105
117
|
| Tool | Description |
|
|
106
118
|
|---|---|
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
119
|
+
| `session_start` | Start a new development session. |
|
|
120
|
+
| `session_end` | End an active session with optional summary. |
|
|
121
|
+
| `session_recall` | Get a session by ID with its memories. |
|
|
122
|
+
| `session_list` | List sessions with optional filters. |
|
|
110
123
|
|
|
111
|
-
###
|
|
124
|
+
### Decision Tools (decisions)
|
|
112
125
|
|
|
113
126
|
| Tool | Description |
|
|
114
127
|
|---|---|
|
|
115
|
-
| `
|
|
128
|
+
| `decision_record` | Record an architectural decision with rationale. |
|
|
129
|
+
| `decision_list` | List decisions with optional filters. |
|
|
130
|
+
| `decision_supersede` | Supersede a decision with a new one. |
|
|
131
|
+
| `decision_check` | Check for existing decisions about a topic. |
|
|
132
|
+
|
|
133
|
+
### Pattern Tools (patterns)
|
|
134
|
+
|
|
135
|
+
| Tool | Description |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `pattern_create` | Create a reusable pattern. |
|
|
138
|
+
| `pattern_search` | Search patterns using semantic search. |
|
|
139
|
+
| `pattern_adopt` | Adopt a pattern for a project. |
|
|
140
|
+
| `pattern_suggest` | Suggest patterns for a project. |
|
|
141
|
+
|
|
142
|
+
### Project Tools (projects)
|
|
143
|
+
|
|
144
|
+
| Tool | Description |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `project_register` | Register a new project. |
|
|
147
|
+
| `project_list` | List projects with pagination. |
|
|
148
|
+
| `project_info` | Get project details by slug. |
|
|
149
|
+
|
|
150
|
+
### Relationship Tools (relationships)
|
|
151
|
+
|
|
152
|
+
| Tool | Description |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `project_add_relationship` | Add a relationship between two projects. |
|
|
155
|
+
| `project_dependencies` | Get what a project depends on. |
|
|
156
|
+
| `project_dependents` | Get what depends on a project. |
|
|
157
|
+
| `project_related` | Get all related projects. |
|
|
158
|
+
| `project_impact` | Run impact analysis for a project change. |
|
|
159
|
+
| `project_shared_patterns` | Find patterns shared between two projects. |
|
|
160
|
+
|
|
161
|
+
### Context Tools (context)
|
|
162
|
+
|
|
163
|
+
| Tool | Description |
|
|
164
|
+
|---|---|
|
|
165
|
+
| `project_context` | Get full project context (hot memories, decisions, patterns). |
|
|
166
|
+
| `memory_promote` | Promote/demote a memory by updating importance and tier. |
|
|
116
167
|
|
|
117
168
|
---
|
|
118
169
|
|
package/docs/SECURITY.md
CHANGED
|
@@ -198,7 +198,7 @@ All tool inputs are validated using Zod schemas:
|
|
|
198
198
|
|
|
199
199
|
#### Memory Content
|
|
200
200
|
- Type: String (required)
|
|
201
|
-
-
|
|
201
|
+
- 50,000 character limit (validated client-side before API call)
|
|
202
202
|
- HTML-encoded when used in entity names
|
|
203
203
|
|
|
204
204
|
#### Entity Names
|
|
@@ -282,8 +282,8 @@ Errors are sanitized before being returned to clients:
|
|
|
282
282
|
The MCP server respects API rate limits:
|
|
283
283
|
|
|
284
284
|
- **Timeout**: Default 30 seconds per request (configurable)
|
|
285
|
-
- **Retries**:
|
|
286
|
-
- **Backoff**:
|
|
285
|
+
- **Retries**: Automatic retries with exponential backoff (up to 3 retries for transient errors)
|
|
286
|
+
- **Backoff**: Exponential backoff with jitter on 5xx and timeout errors; 429 rate-limit responses honored via Retry-After header
|
|
287
287
|
|
|
288
288
|
### API Rate Limits
|
|
289
289
|
|
|
@@ -439,11 +439,11 @@ To enable comprehensive audit logging:
|
|
|
439
439
|
## 📚 Further Reading
|
|
440
440
|
|
|
441
441
|
- [MCP Security Best Practices](https://modelcontextprotocol.io/security)
|
|
442
|
-
- [MemoryRelay API Documentation](https://
|
|
442
|
+
- [MemoryRelay API Documentation](https://docs.memoryrelay.ai/)
|
|
443
443
|
- [OWASP Secure Coding Practices](https://owasp.org/www-project-secure-coding-practices-quick-reference-guide/)
|
|
444
444
|
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
|
|
445
445
|
|
|
446
446
|
---
|
|
447
447
|
|
|
448
|
-
**Last Updated:** 2026-
|
|
449
|
-
**Version:** 0.
|
|
448
|
+
**Last Updated:** 2026-03-24
|
|
449
|
+
**Version:** 0.4.0
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/logger.ts","../src/client.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Configuration schema with security validation\n */\nexport const configSchema = z.object({\n apiKey: z.string()\n .startsWith('mem_', { message: 'API key must start with \"mem_\"' })\n .min(20, { message: 'API key appears to be invalid (too short)' }),\n apiUrl: z.string()\n .url({ message: 'API URL must be a valid URL' })\n .default('https://api.memoryrelay.net'),\n agentId: z.string()\n .optional()\n .describe('Agent identifier - auto-detected if not provided'),\n timeout: z.number()\n .positive({ message: 'Timeout must be positive' })\n .default(30000),\n logLevel: z.enum(['debug', 'info', 'warn', 'error'])\n .default('info'),\n});\n\nexport type Config = z.infer<typeof configSchema>;\n\n/**\n * Tool groups that can be enabled/disabled via MEMORYRELAY_TOOLS env var.\n * Default (when unset or 'all'): all groups enabled.\n */\nexport const TOOL_GROUPS: Record<string, string[]> = {\n core: [\n 'memory_store', 'memory_search', 'memory_list', 'memory_get',\n 'memory_update', 'memory_delete', 'entity_create', 'entity_link',\n 'entity_list', 'entity_graph', 'memory_batch_store', 'memory_context',\n 'agent_list', 'agent_create', 'agent_get', 'memory_health',\n ],\n sessions: ['session_start', 'session_end', 'session_recall', 'session_list'],\n decisions: ['decision_record', 'decision_list', 'decision_supersede', 'decision_check'],\n patterns: ['pattern_create', 'pattern_search', 'pattern_adopt', 'pattern_suggest'],\n projects: ['project_register', 'project_list', 'project_info'],\n relationships: [\n 'project_add_relationship', 'project_dependencies', 'project_dependents',\n 'project_related', 'project_impact', 'project_shared_patterns',\n ],\n context: ['project_context', 'memory_promote'],\n};\n\n/**\n * Parse MEMORYRELAY_TOOLS env var and return set of enabled tool names.\n * Returns null if all tools should be enabled (default behavior).\n */\nexport function getEnabledTools(): Set<string> | null {\n const raw = process.env.MEMORYRELAY_TOOLS;\n if (!raw || raw.trim().toLowerCase() === 'all') {\n return null; // all tools enabled\n }\n\n const groups = raw.split(',').map(g => g.trim().toLowerCase());\n const enabled = new Set<string>();\n for (const group of groups) {\n const tools = TOOL_GROUPS[group];\n if (tools) {\n for (const tool of tools) {\n enabled.add(tool);\n }\n }\n }\n return enabled;\n}\n\n/**\n * Load and validate configuration from environment variables\n */\nexport function loadConfig(): Config {\n try {\n const config = configSchema.parse({\n apiKey: process.env.MEMORYRELAY_API_KEY,\n apiUrl: process.env.MEMORYRELAY_API_URL,\n agentId: process.env.MEMORYRELAY_AGENT_ID,\n timeout: process.env.MEMORYRELAY_TIMEOUT \n ? parseInt(process.env.MEMORYRELAY_TIMEOUT, 10) \n : undefined,\n logLevel: process.env.MEMORYRELAY_LOG_LEVEL,\n });\n\n return config;\n } catch (error) {\n if (error instanceof z.ZodError) {\n const issues = error.issues.map(issue => \n ` - ${issue.path.join('.')}: ${issue.message}`\n ).join('\\n');\n \n throw new Error(\n `Configuration validation failed:\\n${issues}\\n\\n` +\n 'Please check your environment variables:\\n' +\n ' - MEMORYRELAY_API_KEY (required, starts with \"mem_\")\\n' +\n ' - MEMORYRELAY_API_URL (optional, default: https://api.memoryrelay.net)\\n' +\n ' - MEMORYRELAY_AGENT_ID (optional, auto-detected)\\n' +\n ' - MEMORYRELAY_TIMEOUT (optional, default: 30000)\\n' +\n ' - MEMORYRELAY_LOG_LEVEL (optional, default: info)',\n { cause: error }\n );\n }\n throw error;\n }\n}\n\n/**\n * Get or generate agent ID.\n *\n * Priority order:\n * 1. MEMORYRELAY_AGENT_ID (explicit configuration)\n * 2. OPENCLAW_AGENT_NAME (OpenClaw auto-detection)\n * 3. Auto-generated from username + hostname\n *\n * When no explicit ID is provided we build a human-readable identifier\n * from the current user and hostname so that memories are easier to\n * attribute in the dashboard (e.g. \"sparc-DESKTOP\" instead of \"agent-a1b2c3d4\").\n */\nexport function getAgentId(config: Config): string {\n if (config.agentId) {\n return config.agentId;\n }\n\n // OpenClaw auto-detection: use agent name from OpenClaw environment\n const openclawAgent = process.env.OPENCLAW_AGENT_NAME;\n if (openclawAgent) {\n return openclawAgent.slice(0, 32);\n }\n\n const hostname = process.env.HOSTNAME || process.env.COMPUTERNAME || 'unknown';\n const user = process.env.USER || process.env.USERNAME || '';\n return user\n ? `${user}-${hostname}`.slice(0, 32)\n : `mcp-${hostname}`.slice(0, 32);\n}\n","/**\n * Security-hardened logger for MCP server\n * \n * - All output to stderr (stdout reserved for MCP protocol)\n * - Automatic masking of API keys (anything starting with \"mem_\")\n * - No internal paths in error messages\n */\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nexport class Logger {\n private minLevel: number;\n\n constructor(level: LogLevel = 'info') {\n this.minLevel = LOG_LEVELS[level];\n }\n\n /**\n * Mask sensitive data in log messages\n * - API keys starting with \"mem_\" are masked\n * - Internal paths are sanitized\n */\n private sanitize(message: string): string {\n let sanitized = message;\n\n // Mask API keys (mem_xxx -> mem_****)\n sanitized = sanitized.replace(/mem_[a-zA-Z0-9_-]+/g, 'mem_****');\n\n // Remove internal paths (anything that looks like a file path)\n sanitized = sanitized.replace(/\\/[a-zA-Z0-9_\\-./]+\\.(ts|js|json)/g, '<file>');\n sanitized = sanitized.replace(/at\\s+[^\\s]+\\s+\\([^)]+\\)/g, 'at <location>');\n\n return sanitized;\n }\n\n /**\n * Format log message with timestamp and level\n */\n private format(level: LogLevel, message: string, data?: unknown): string {\n const timestamp = new Date().toISOString();\n const sanitizedMessage = this.sanitize(message);\n \n let output = `[${timestamp}] [${level.toUpperCase()}] ${sanitizedMessage}`;\n \n if (data !== undefined) {\n const sanitizedData = this.sanitize(JSON.stringify(data, null, 2));\n output += `\\n${sanitizedData}`;\n }\n \n return output;\n }\n\n debug(message: string, data?: unknown): void {\n if (this.minLevel <= LOG_LEVELS.debug) {\n console.error(this.format('debug', message, data));\n }\n }\n\n info(message: string, data?: unknown): void {\n if (this.minLevel <= LOG_LEVELS.info) {\n console.error(this.format('info', message, data));\n }\n }\n\n warn(message: string, data?: unknown): void {\n if (this.minLevel <= LOG_LEVELS.warn) {\n console.error(this.format('warn', message, data));\n }\n }\n\n error(message: string, data?: unknown): void {\n if (this.minLevel <= LOG_LEVELS.error) {\n console.error(this.format('error', message, data));\n }\n }\n}\n\n// Export singleton instance\nlet logger: Logger;\n\nexport function initLogger(level: LogLevel = 'info'): Logger {\n logger = new Logger(level);\n return logger;\n}\n\nexport function getLogger(): Logger {\n if (!logger) {\n logger = new Logger();\n }\n return logger;\n}\n","/**\n * MemoryRelay API client with retry logic and error handling\n */\n\nimport type {\n Memory,\n Entity,\n Agent,\n Session,\n SessionDetail,\n Decision,\n DecisionCheckResult,\n Project,\n Pattern,\n PatternSearchResult,\n SearchResult,\n ListResponse,\n ClientConfig,\n EntityType,\n BatchMemoryItem,\n BatchStoreResponse,\n} from './types.js';\nimport { getLogger } from './logger.js';\n\n// Retry configuration\nconst MAX_RETRIES = 3;\nconst INITIAL_DELAY_MS = 1000;\nconst MAX_CONTENT_SIZE = 50 * 1024; // 50KB\n\n/**\n * Exponential backoff retry wrapper\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n retries: number = MAX_RETRIES\n): Promise<T> {\n let lastError: Error | undefined;\n \n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n \n // Don't retry on certain errors\n if (\n lastError.message.includes('401') ||\n lastError.message.includes('403') ||\n lastError.message.includes('404') ||\n lastError.message.includes('400')\n ) {\n throw lastError;\n }\n \n // On last attempt, throw the error\n if (attempt === retries) {\n throw lastError;\n }\n \n // Exponential backoff with jitter\n const delay = INITIAL_DELAY_MS * Math.pow(2, attempt);\n const jitter = Math.random() * 0.3 * delay;\n await new Promise(resolve => setTimeout(resolve, delay + jitter));\n }\n }\n \n throw lastError || new Error('Retry failed');\n}\n\n/**\n * Mask API key in error messages for security\n */\nfunction maskApiKey(message: string, apiKey: string): string {\n if (!apiKey) return message;\n const maskedKey = apiKey.substring(0, 8) + '***';\n return message.replace(new RegExp(apiKey, 'g'), maskedKey);\n}\n\nexport class MemoryRelayClient {\n private config: ClientConfig;\n private logger = getLogger();\n\n constructor(config: ClientConfig) {\n this.config = config;\n this.logger.info('MemoryRelay client initialized', {\n apiUrl: config.apiUrl,\n agentId: config.agentId,\n });\n }\n\n /**\n * Make authenticated HTTP request to MemoryRelay API with retry logic\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n return withRetry(async () => {\n const url = `${this.config.apiUrl}${path}`;\n \n this.logger.debug(`API request: ${method} ${path}`);\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n 'User-Agent': '@memoryrelay/mcp-server',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Handle rate limiting with retry\n if (response.status === 429) {\n const retryAfter = response.headers.get('Retry-After');\n const waitMs = retryAfter ? parseInt(retryAfter) * 1000 : 5000;\n this.logger.warn(`Rate limited, waiting ${waitMs}ms`);\n await new Promise(resolve => setTimeout(resolve, waitMs));\n throw new Error(`Rate limited: 429 - Retry after ${waitMs}ms`);\n }\n\n const errorData = await response.json().catch(() => ({})) as { message?: string };\n const errorMsg = `API request failed: ${response.status} ${response.statusText}` +\n (errorData.message ? ` - ${errorData.message}` : '');\n \n // Mask API key in error message\n throw new Error(maskApiKey(errorMsg, this.config.apiKey));\n }\n\n const data = await response.json();\n this.logger.debug(`API response: ${method} ${path}`, { status: response.status });\n \n return data as T;\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new Error(`Request timeout after ${this.config.timeout}ms`, { cause: error });\n }\n // Mask API key in all error messages\n error.message = maskApiKey(error.message, this.config.apiKey);\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n });\n }\n\n /**\n * Validate content size\n */\n private validateContentSize(content: string): void {\n if (content.length > MAX_CONTENT_SIZE) {\n throw new Error(`Content exceeds maximum size of ${MAX_CONTENT_SIZE} bytes`);\n }\n }\n\n /**\n * Store a new memory\n */\n async storeMemory(\n content: string,\n metadata?: Record<string, string>,\n deduplicate?: boolean,\n dedupThreshold?: number,\n project?: string,\n importance?: number,\n tier?: string\n ): Promise<Memory> {\n this.validateContentSize(content);\n\n const body: Record<string, unknown> = {\n content,\n metadata,\n agent_id: this.config.agentId,\n };\n if (deduplicate) {\n body.deduplicate = true;\n }\n if (dedupThreshold !== undefined) {\n body.dedup_threshold = dedupThreshold;\n }\n if (project) {\n body.project = project;\n }\n if (importance !== undefined) {\n body.importance = importance;\n }\n if (tier) {\n body.tier = tier;\n }\n\n return this.request<Memory>('POST', '/v1/memories', body);\n }\n\n /**\n * Search memories using semantic search\n * @param agentId - Optional agent ID override. If omitted, uses config agentId. Pass null for cross-agent search.\n * @param includeConfidential - Include confidential memories in results\n * @param includeArchived - Include archived memories in results\n * @param project - Optional project slug to filter by\n */\n async searchMemories(\n query: string,\n limit: number = 10,\n threshold: number = 0.5,\n agentId?: string | null,\n includeConfidential: boolean = false,\n includeArchived: boolean = false,\n compress: boolean = false,\n maxContextTokens?: number,\n project?: string,\n tier?: string,\n minImportance?: number\n ): Promise<SearchResult[]> {\n this.validateContentSize(query);\n\n // If agentId is explicitly null, omit it (cross-agent search).\n // If agentId is undefined, use the default from config.\n const effectiveAgentId = agentId === null ? undefined : (agentId ?? this.config.agentId);\n\n const body: Record<string, unknown> = { query, limit, threshold };\n if (effectiveAgentId) {\n body.agent_id = effectiveAgentId;\n }\n if (includeConfidential) {\n body.include_confidential = true;\n }\n if (includeArchived) {\n body.include_archived = true;\n }\n if (compress) {\n body.compress = true;\n }\n if (maxContextTokens !== undefined) {\n body.max_context_tokens = maxContextTokens;\n }\n if (project) {\n body.project = project;\n }\n if (tier) {\n body.tier = tier;\n }\n if (minImportance !== undefined) {\n body.min_importance = minImportance;\n }\n\n const response = await this.request<{ data: SearchResult[] }>(\n 'POST',\n '/v1/memories/search',\n body\n );\n return response.data;\n }\n\n /**\n * List recent memories with pagination\n */\n async listMemories(limit: number = 20, offset: number = 0): Promise<ListResponse<Memory>> {\n return this.request<ListResponse<Memory>>(\n 'GET',\n `/v1/memories?limit=${limit}&offset=${offset}`\n );\n }\n\n /**\n * Get a specific memory by ID\n */\n async getMemory(id: string): Promise<Memory> {\n return this.request<Memory>('GET', `/v1/memories/${id}`);\n }\n\n /**\n * Update an existing memory\n */\n async updateMemory(\n id: string,\n content: string,\n metadata?: Record<string, string>\n ): Promise<Memory> {\n this.validateContentSize(content);\n \n return this.request<Memory>('PATCH', `/v1/memories/${id}`, {\n content,\n metadata,\n });\n }\n\n /**\n * Delete a memory\n */\n async deleteMemory(id: string): Promise<void> {\n await this.request<void>('DELETE', `/v1/memories/${id}`);\n }\n\n /**\n * Create a named entity\n */\n async createEntity(\n name: string,\n type: EntityType,\n metadata?: Record<string, string>\n ): Promise<Entity> {\n this.validateContentSize(name);\n \n return this.request<Entity>('POST', '/v1/entities', {\n name,\n type,\n metadata,\n });\n }\n\n /**\n * Link an entity to a memory\n */\n async linkEntity(\n entityId: string,\n memoryId: string,\n relationship: string = 'mentioned_in'\n ): Promise<void> {\n await this.request<void>('POST', '/v1/entities/links', {\n entity_id: entityId,\n memory_id: memoryId,\n relationship,\n });\n }\n\n /**\n * Get an entity by ID\n */\n async getEntity(id: string): Promise<Entity> {\n return this.request<Entity>('GET', `/v1/entities/${id}`);\n }\n\n /**\n * List entities with pagination\n */\n async listEntities(limit: number = 20, offset: number = 0): Promise<ListResponse<Entity>> {\n return this.request<ListResponse<Entity>>(\n 'GET',\n `/v1/entities?limit=${limit}&offset=${offset}`\n );\n }\n\n /**\n * Get entity neighborhood (ego-centric subgraph).\n * Returns the entity's 1-hop or 2-hop neighbors and relationships.\n */\n async getEntityNeighborhood(\n entityId: string,\n depth: number = 1,\n maxNeighbors: number = 50\n ): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>(\n 'GET',\n `/v1/entities/${entityId}/neighborhood?depth=${depth}&max_neighbors=${maxNeighbors}`\n );\n }\n\n /**\n * Delete an entity\n */\n async deleteEntity(id: string): Promise<void> {\n await this.request<void>('DELETE', `/v1/entities/${id}`);\n }\n\n /**\n * List agents with pagination\n */\n async listAgents(limit: number = 20, offset: number = 0): Promise<ListResponse<Agent>> {\n return this.request<ListResponse<Agent>>(\n 'GET',\n `/v1/agents?limit=${limit}&offset=${offset}`\n );\n }\n\n /**\n * Create a new agent\n */\n async createAgent(\n name: string,\n description?: string,\n metadata?: Record<string, string>\n ): Promise<Agent> {\n const body: Record<string, unknown> = { name };\n if (description) body.description = description;\n if (metadata) body.metadata = metadata;\n\n return this.request<Agent>('POST', '/v1/agents', body);\n }\n\n /**\n * Get an agent by ID\n */\n async getAgent(id: string): Promise<Agent> {\n return this.request<Agent>('GET', `/v1/agents/${id}`);\n }\n\n /**\n * Batch store multiple memories in a single API call.\n * Uses the /v1/memories/batch endpoint.\n */\n async batchStoreMemories(\n items: BatchMemoryItem[]\n ): Promise<BatchStoreResponse> {\n if (items.length === 0) {\n return { success: true, total: 0, succeeded: 0, failed: 0, skipped: 0, results: [] };\n }\n if (items.length > 100) {\n throw new Error('Batch size exceeds maximum of 100 memories');\n }\n\n // Attach default agent_id to items that don't have one\n const memories = items.map(item => ({\n content: item.content,\n metadata: item.metadata || {},\n agent_id: item.agent_id || this.config.agentId,\n }));\n\n return this.request<BatchStoreResponse>('POST', '/v1/memories/batch', { memories });\n }\n\n /**\n * Build a context string from search results.\n * Searches for relevant memories, formats them, and returns\n * a single string ready for prompt injection.\n */\n async buildContext(\n query: string,\n limit: number = 10,\n threshold: number = 0.5,\n maxTokens?: number\n ): Promise<{ context: string; memories_used: number; total_chars: number }> {\n const results = await this.searchMemories(\n query,\n limit,\n threshold,\n undefined, // use default agent\n false, // no confidential\n false, // no archived\n !!maxTokens, // compress if token budget provided\n maxTokens\n );\n\n if (results.length === 0) {\n return { context: '', memories_used: 0, total_chars: 0 };\n }\n\n const lines: string[] = [];\n for (const result of results) {\n const score = (result.score * 100).toFixed(0);\n lines.push(`[${score}%] ${result.memory.content}`);\n }\n\n const context = lines.join('\\n\\n');\n\n // Rough token budget enforcement (1 token ≈ 4 chars)\n let finalContext = context;\n if (maxTokens) {\n const charBudget = maxTokens * 4;\n if (finalContext.length > charBudget) {\n finalContext = finalContext.slice(0, charBudget) + '\\n\\n[...truncated]';\n }\n }\n\n return {\n context: finalContext,\n memories_used: results.length,\n total_chars: finalContext.length,\n };\n }\n\n /**\n * Start a new session\n */\n async startSession(\n title?: string,\n project?: string,\n metadata?: Record<string, string>\n ): Promise<Session> {\n const body: Record<string, unknown> = {};\n if (this.config.agentId) body.agent_id = this.config.agentId;\n if (title) body.title = title;\n if (project) body.project = project;\n if (metadata) body.metadata = metadata;\n return this.request<Session>('POST', '/v1/sessions', body);\n }\n\n /**\n * End an active session\n */\n async endSession(\n sessionId: string,\n summary?: string,\n ): Promise<Session> {\n const body: Record<string, unknown> = {};\n if (summary) body.summary = summary;\n return this.request<Session>('PUT', `/v1/sessions/${sessionId}/end`, body);\n }\n\n /**\n * Get a session by ID with its memories\n */\n async getSession(sessionId: string): Promise<SessionDetail> {\n return this.request<SessionDetail>(\n 'GET',\n `/v1/sessions/${sessionId}?include_memories=true`\n );\n }\n\n /**\n * List sessions with optional filters\n */\n async listSessions(\n limit: number = 20,\n agentId?: string,\n project?: string,\n status?: string,\n ): Promise<ListResponse<Session>> {\n const params = new URLSearchParams();\n params.set('limit', String(limit));\n const effectiveAgentId = agentId ?? this.config.agentId;\n if (effectiveAgentId) params.set('agent_id', effectiveAgentId);\n if (project) params.set('project', project);\n if (status) params.set('status', status);\n return this.request<ListResponse<Session>>(\n 'GET',\n `/v1/sessions?${params.toString()}`\n );\n }\n\n /**\n * Record a new decision\n */\n async recordDecision(\n title: string,\n rationale: string,\n alternatives?: string,\n project?: string,\n tags?: string[],\n status?: string,\n metadata?: Record<string, string>\n ): Promise<Decision> {\n const body: Record<string, unknown> = { title, rationale };\n if (this.config.agentId) body.agent_id = this.config.agentId;\n if (alternatives) body.alternatives = alternatives;\n if (project) body.project_slug = project;\n if (tags) body.tags = tags;\n if (status) body.status = status;\n if (metadata) body.metadata = metadata;\n return this.request<Decision>('POST', '/v1/decisions', body);\n }\n\n /**\n * List decisions with optional filters\n */\n async listDecisions(\n limit?: number,\n project?: string,\n status?: string,\n tags?: string,\n ): Promise<ListResponse<Decision>> {\n const params = new URLSearchParams();\n if (limit) params.set('limit', String(limit));\n if (project) params.set('project', project);\n if (status) params.set('status', status);\n if (tags) params.set('tags', tags);\n return this.request<ListResponse<Decision>>(\n 'GET',\n `/v1/decisions?${params.toString()}`\n );\n }\n\n /**\n * Supersede a decision with a new one\n */\n async supersedeDecision(\n decisionId: string,\n title: string,\n rationale: string,\n alternatives?: string,\n tags?: string[],\n ): Promise<Decision> {\n const body: Record<string, unknown> = { title, rationale };\n if (alternatives) body.alternatives = alternatives;\n if (tags) body.tags = tags;\n return this.request<Decision>(\n 'POST',\n `/v1/decisions/${decisionId}/supersede`,\n body\n );\n }\n\n /**\n * Check for existing decisions about a topic (semantic search)\n */\n async checkDecisions(\n query: string,\n project?: string,\n limit?: number,\n threshold?: number,\n includeSuperseded?: boolean,\n ): Promise<{ data: DecisionCheckResult[]; query: string; total: number }> {\n const params = new URLSearchParams();\n params.set('query', query);\n if (limit) params.set('limit', String(limit));\n if (threshold !== undefined) params.set('threshold', String(threshold));\n if (project) params.set('project', project);\n if (includeSuperseded) params.set('include_superseded', 'true');\n return this.request<{ data: DecisionCheckResult[]; query: string; total: number }>(\n 'GET',\n `/v1/decisions/check?${params.toString()}`\n );\n }\n\n /**\n * Register a new project\n */\n async createProject(\n slug: string,\n name: string,\n description?: string,\n stack?: Record<string, unknown>,\n repo_url?: string,\n metadata?: Record<string, unknown>\n ): Promise<Project> {\n const body: Record<string, unknown> = { slug, name };\n if (description) body.description = description;\n if (stack) body.stack = stack;\n if (repo_url) body.repo_url = repo_url;\n if (metadata) body.metadata = metadata;\n return this.request<Project>('POST', '/v1/projects', body);\n }\n\n /**\n * List projects with optional pagination\n */\n async listProjects(\n limit: number = 20,\n cursor?: string\n ): Promise<ListResponse<Project>> {\n const params = new URLSearchParams();\n params.set('limit', String(limit));\n if (cursor) params.set('cursor', cursor);\n return this.request<ListResponse<Project>>(\n 'GET',\n `/v1/projects?${params.toString()}`\n );\n }\n\n /**\n * Get a project by slug\n */\n async getProject(slug: string): Promise<Project> {\n return this.request<Project>('GET', `/v1/projects/${slug}`);\n }\n\n /**\n * Create a reusable pattern\n */\n async createPattern(\n title: string,\n description: string,\n category?: string,\n example_code?: string,\n scope?: string,\n tags?: string[],\n source_project?: string,\n metadata?: Record<string, unknown>\n ): Promise<Pattern> {\n const body: Record<string, unknown> = { title, description };\n if (category) body.category = category;\n if (example_code) body.example_code = example_code;\n if (scope) body.scope = scope;\n if (tags) body.tags = tags;\n if (source_project) body.source_project = source_project;\n if (metadata) body.metadata = metadata;\n return this.request<Pattern>('POST', '/v1/patterns', body);\n }\n\n /**\n * Search patterns using semantic search\n */\n async searchPatterns(\n query: string,\n category?: string,\n project?: string,\n limit?: number,\n threshold?: number,\n ): Promise<{ data: PatternSearchResult[]; query: string; total: number }> {\n const params = new URLSearchParams();\n params.set('query', query);\n if (category) params.set('category', category);\n if (project) params.set('project', project);\n if (limit) params.set('limit', String(limit));\n if (threshold !== undefined) params.set('threshold', String(threshold));\n return this.request<{ data: PatternSearchResult[]; query: string; total: number }>(\n 'GET',\n `/v1/patterns/search?${params.toString()}`\n );\n }\n\n /**\n * Adopt a pattern for a project\n */\n async adoptPattern(\n patternId: string,\n project: string,\n ): Promise<Pattern> {\n return this.request<Pattern>(\n 'POST',\n `/v1/patterns/${patternId}/adopt`,\n { project }\n );\n }\n\n /**\n * Suggest patterns for a project\n */\n async suggestPatterns(\n project: string,\n limit?: number,\n ): Promise<{ data: Pattern[]; project: string; total: number }> {\n const params = new URLSearchParams();\n params.set('project', project);\n if (limit) params.set('limit', String(limit));\n return this.request<{ data: Pattern[]; project: string; total: number }>(\n 'GET',\n `/v1/patterns/suggest?${params.toString()}`\n );\n }\n\n // ── Project Relationships (Issue #186) ──\n\n /**\n * Add a relationship between two projects\n */\n async addProjectRelationship(\n sourceSlug: string,\n targetProject: string,\n relationshipType: string,\n metadata?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n const body: Record<string, unknown> = {\n target_project: targetProject,\n relationship_type: relationshipType,\n };\n if (metadata) body.metadata = metadata;\n return this.request<Record<string, unknown>>(\n 'POST',\n `/v1/projects/${sourceSlug}/relationships`,\n body,\n );\n }\n\n /**\n * Get what this project depends on\n */\n async getProjectDependencies(slug: string): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>(\n 'GET',\n `/v1/projects/${slug}/dependencies`,\n );\n }\n\n /**\n * Get what depends on this project\n */\n async getProjectDependents(slug: string): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>(\n 'GET',\n `/v1/projects/${slug}/dependents`,\n );\n }\n\n /**\n * Get all related projects\n */\n async getProjectRelated(slug: string): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>(\n 'GET',\n `/v1/projects/${slug}/related`,\n );\n }\n\n /**\n * Run impact analysis for a project change\n */\n async projectImpactAnalysis(\n project: string,\n changeDescription: string,\n ): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>(\n 'POST',\n '/v1/projects/impact-analysis',\n { project, change_description: changeDescription },\n );\n }\n\n /**\n * Find patterns shared between two projects\n */\n async getSharedPatterns(\n slugA: string,\n slugB: string,\n ): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>(\n 'GET',\n `/v1/projects/shared-patterns?a=${encodeURIComponent(slugA)}&b=${encodeURIComponent(slugB)}`,\n );\n }\n\n /**\n * Get full project context (hot memories, decisions, patterns, formatted text)\n */\n async getProjectContext(slug: string): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>(\n 'GET',\n `/v1/projects/${encodeURIComponent(slug)}/context`,\n );\n }\n\n /**\n * Promote/demote a memory by updating its importance and tier\n */\n async promoteMemory(\n memoryId: string,\n importance: number,\n tier?: string\n ): Promise<Memory> {\n const body: Record<string, unknown> = { importance };\n if (tier) {\n body.tier = tier;\n }\n return this.request<Memory>(\n 'PUT',\n `/v1/memories/${encodeURIComponent(memoryId)}/importance`,\n body,\n );\n }\n\n /**\n * Health check - verify API connectivity\n */\n async healthCheck(): Promise<{ status: string; message: string }> {\n try {\n // Simple GET request to check API is reachable\n await this.request<{ status: string }>('GET', '/v1/health');\n return {\n status: 'healthy',\n message: 'API connection successful',\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : 'Unknown error';\n return {\n status: 'unhealthy',\n message: `API connection failed: ${errorMsg}`,\n };\n }\n }\n}\n"],"mappings":"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","names":[]}
|