@lanonasis/cli 3.9.14 → 3.9.15
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog - @lanonasis/cli
|
|
2
2
|
|
|
3
|
+
## [3.9.15] - 2026-04-04
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- **Displayed memory ID prefixes now work across CLI memory reads and deletes**: `lanonasis memory get`, `memory update`, and `memory delete` now resolve 8+ character prefixes from the list output before calling the live API, so operators no longer need to paste full UUIDs for routine follow-up actions.
|
|
8
|
+
- **Legacy memory route drift no longer breaks prefix fetches**: Memory lookups now retry against the compatibility `GET /api/v1/memory/get?id=...` and delete fallback routes only when the canonical plural endpoint returns the known `Memory ID is required` validation drift.
|
|
9
|
+
- **MCP memory tools now accept both `id` and `memory_id`**: The bundled LanOnasis MCP server and remote MCP bridge now normalize legacy `memory_id` callers onto the live `id` contract, which restores OpenClaw and similar clients when they pass the older field name.
|
|
10
|
+
|
|
3
11
|
## [3.9.14] - 2026-04-03
|
|
4
12
|
|
|
5
13
|
### 🐛 Bug Fixes
|
|
@@ -43,6 +43,15 @@ export class LanonasisMCPServer {
|
|
|
43
43
|
// Setup error handling
|
|
44
44
|
this.setupErrorHandling();
|
|
45
45
|
}
|
|
46
|
+
extractMemoryIdentifier(args) {
|
|
47
|
+
const id = typeof args.id === 'string' ? args.id.trim() : '';
|
|
48
|
+
const legacyId = typeof args.memory_id === 'string' ? args.memory_id.trim() : '';
|
|
49
|
+
const resolved = id || legacyId;
|
|
50
|
+
if (!resolved) {
|
|
51
|
+
throw new Error('Memory ID is required');
|
|
52
|
+
}
|
|
53
|
+
return resolved;
|
|
54
|
+
}
|
|
46
55
|
/**
|
|
47
56
|
* Initialize the server
|
|
48
57
|
*/
|
|
@@ -170,12 +179,19 @@ export class LanonasisMCPServer {
|
|
|
170
179
|
inputSchema: {
|
|
171
180
|
type: 'object',
|
|
172
181
|
properties: {
|
|
182
|
+
id: {
|
|
183
|
+
type: 'string',
|
|
184
|
+
description: 'Memory ID or displayed prefix'
|
|
185
|
+
},
|
|
173
186
|
memory_id: {
|
|
174
187
|
type: 'string',
|
|
175
|
-
description: '
|
|
188
|
+
description: 'Legacy alias for memory ID or displayed prefix'
|
|
176
189
|
}
|
|
177
190
|
},
|
|
178
|
-
|
|
191
|
+
anyOf: [
|
|
192
|
+
{ required: ['id'] },
|
|
193
|
+
{ required: ['memory_id'] }
|
|
194
|
+
]
|
|
179
195
|
}
|
|
180
196
|
},
|
|
181
197
|
{
|
|
@@ -184,9 +200,13 @@ export class LanonasisMCPServer {
|
|
|
184
200
|
inputSchema: {
|
|
185
201
|
type: 'object',
|
|
186
202
|
properties: {
|
|
203
|
+
id: {
|
|
204
|
+
type: 'string',
|
|
205
|
+
description: 'Memory ID or displayed prefix'
|
|
206
|
+
},
|
|
187
207
|
memory_id: {
|
|
188
208
|
type: 'string',
|
|
189
|
-
description: '
|
|
209
|
+
description: 'Legacy alias for memory ID or displayed prefix'
|
|
190
210
|
},
|
|
191
211
|
title: {
|
|
192
212
|
type: 'string',
|
|
@@ -202,7 +222,10 @@ export class LanonasisMCPServer {
|
|
|
202
222
|
description: 'New tags (optional)'
|
|
203
223
|
}
|
|
204
224
|
},
|
|
205
|
-
|
|
225
|
+
anyOf: [
|
|
226
|
+
{ required: ['id'] },
|
|
227
|
+
{ required: ['memory_id'] }
|
|
228
|
+
]
|
|
206
229
|
}
|
|
207
230
|
},
|
|
208
231
|
{
|
|
@@ -211,12 +234,19 @@ export class LanonasisMCPServer {
|
|
|
211
234
|
inputSchema: {
|
|
212
235
|
type: 'object',
|
|
213
236
|
properties: {
|
|
237
|
+
id: {
|
|
238
|
+
type: 'string',
|
|
239
|
+
description: 'Memory ID or displayed prefix'
|
|
240
|
+
},
|
|
214
241
|
memory_id: {
|
|
215
242
|
type: 'string',
|
|
216
|
-
description: '
|
|
243
|
+
description: 'Legacy alias for memory ID or displayed prefix'
|
|
217
244
|
}
|
|
218
245
|
},
|
|
219
|
-
|
|
246
|
+
anyOf: [
|
|
247
|
+
{ required: ['id'] },
|
|
248
|
+
{ required: ['memory_id'] }
|
|
249
|
+
]
|
|
220
250
|
}
|
|
221
251
|
},
|
|
222
252
|
// Topic tools
|
|
@@ -647,11 +677,13 @@ Please choose an option (1-4):`
|
|
|
647
677
|
topic_id: args.topic_id
|
|
648
678
|
});
|
|
649
679
|
case 'memory_get':
|
|
650
|
-
return await this.apiClient.getMemory(args
|
|
680
|
+
return await this.apiClient.getMemory(this.extractMemoryIdentifier(args));
|
|
651
681
|
case 'memory_update':
|
|
652
|
-
|
|
682
|
+
const memoryId = this.extractMemoryIdentifier(args);
|
|
683
|
+
const { id: _id, memory_id: _legacyId, ...updateArgs } = args;
|
|
684
|
+
return await this.apiClient.updateMemory(memoryId, updateArgs);
|
|
653
685
|
case 'memory_delete':
|
|
654
|
-
return await this.apiClient.deleteMemory(args
|
|
686
|
+
return await this.apiClient.deleteMemory(this.extractMemoryIdentifier(args));
|
|
655
687
|
// Topic operations
|
|
656
688
|
case 'topic_create':
|
|
657
689
|
return await this.apiClient.createTopic(args);
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -198,6 +198,8 @@ export declare class APIClient {
|
|
|
198
198
|
private shouldUseLegacyMemoryRpcFallback;
|
|
199
199
|
private shouldRetryViaApiGateway;
|
|
200
200
|
private shouldRetryViaSupabaseMemoryFunctions;
|
|
201
|
+
private isUuid;
|
|
202
|
+
resolveMemoryId(idOrPrefix: string): Promise<string>;
|
|
201
203
|
private shouldUsePostListFallback;
|
|
202
204
|
private getSupabaseFunctionsBaseUrl;
|
|
203
205
|
private mapMemoryApiRouteToSupabaseFunctions;
|
package/dist/utils/api.js
CHANGED
|
@@ -10,6 +10,7 @@ const MEMORY_TYPES = [
|
|
|
10
10
|
'personal',
|
|
11
11
|
'workflow'
|
|
12
12
|
];
|
|
13
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
13
14
|
export class APIClient {
|
|
14
15
|
client;
|
|
15
16
|
config;
|
|
@@ -166,6 +167,61 @@ export class APIClient {
|
|
|
166
167
|
const hasVendorKey = this.config.hasVendorKey();
|
|
167
168
|
return hasVendorKey || hasOpaqueToken || authMethod === 'oauth' || authMethod === 'oauth2';
|
|
168
169
|
}
|
|
170
|
+
isUuid(value) {
|
|
171
|
+
return UUID_PATTERN.test(value);
|
|
172
|
+
}
|
|
173
|
+
async resolveMemoryId(idOrPrefix) {
|
|
174
|
+
const candidate = idOrPrefix.trim();
|
|
175
|
+
if (!candidate) {
|
|
176
|
+
throw new Error('Memory ID is required.');
|
|
177
|
+
}
|
|
178
|
+
if (this.isUuid(candidate)) {
|
|
179
|
+
return candidate;
|
|
180
|
+
}
|
|
181
|
+
if (candidate.length < 8) {
|
|
182
|
+
throw new Error('Memory ID prefix must be at least 8 characters or a full UUID.');
|
|
183
|
+
}
|
|
184
|
+
const matches = new Set();
|
|
185
|
+
const normalizedCandidate = candidate.toLowerCase();
|
|
186
|
+
const limit = 100;
|
|
187
|
+
let page = 1;
|
|
188
|
+
while (true) {
|
|
189
|
+
const result = await this.getMemories({ page, limit });
|
|
190
|
+
const memories = result.memories || result.data || [];
|
|
191
|
+
if (memories.length === 0) {
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
for (const memory of memories) {
|
|
195
|
+
if (memory.id.toLowerCase().startsWith(normalizedCandidate)) {
|
|
196
|
+
matches.add(memory.id);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const pagination = result.pagination || {
|
|
200
|
+
total: memories.length,
|
|
201
|
+
limit,
|
|
202
|
+
offset: 0,
|
|
203
|
+
has_more: false,
|
|
204
|
+
};
|
|
205
|
+
const totalPages = Number.isFinite(Number(pagination.pages))
|
|
206
|
+
? Number(pagination.pages)
|
|
207
|
+
: Math.max(1, Math.ceil(Number(pagination.total || memories.length) / limit));
|
|
208
|
+
const hasMore = typeof pagination.has_more === 'boolean'
|
|
209
|
+
? pagination.has_more
|
|
210
|
+
: page < totalPages;
|
|
211
|
+
if (!hasMore) {
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
page += 1;
|
|
215
|
+
}
|
|
216
|
+
const resolvedMatches = [...matches];
|
|
217
|
+
if (resolvedMatches.length === 0) {
|
|
218
|
+
throw new Error(`Memory not found for ID/prefix: ${candidate}`);
|
|
219
|
+
}
|
|
220
|
+
if (resolvedMatches.length > 1) {
|
|
221
|
+
throw new Error(`Memory ID prefix is ambiguous: ${candidate}. Matches: ${resolvedMatches.slice(0, 5).join(', ')}`);
|
|
222
|
+
}
|
|
223
|
+
return resolvedMatches[0];
|
|
224
|
+
}
|
|
169
225
|
shouldUsePostListFallback(error) {
|
|
170
226
|
const status = Number(error?.response?.status || 0);
|
|
171
227
|
if (status === 405)
|
|
@@ -627,13 +683,16 @@ export class APIClient {
|
|
|
627
683
|
}
|
|
628
684
|
}
|
|
629
685
|
async getMemory(id) {
|
|
686
|
+
const resolvedId = await this.resolveMemoryId(id);
|
|
630
687
|
try {
|
|
631
|
-
const response = await this.client.get(`/api/v1/memories/${
|
|
688
|
+
const response = await this.client.get(`/api/v1/memories/${encodeURIComponent(resolvedId)}`);
|
|
632
689
|
return this.normalizeMemoryEntry(response.data);
|
|
633
690
|
}
|
|
634
691
|
catch (error) {
|
|
635
692
|
if (this.shouldUseLegacyMemoryRpcFallback(error)) {
|
|
636
|
-
const fallback = await this.client.
|
|
693
|
+
const fallback = await this.client.get('/api/v1/memory/get', {
|
|
694
|
+
params: { id: resolvedId }
|
|
695
|
+
});
|
|
637
696
|
const payload = fallback.data && typeof fallback.data === 'object'
|
|
638
697
|
? fallback.data.data ?? fallback.data
|
|
639
698
|
: fallback.data;
|
|
@@ -643,14 +702,15 @@ export class APIClient {
|
|
|
643
702
|
}
|
|
644
703
|
}
|
|
645
704
|
async updateMemory(id, data) {
|
|
705
|
+
const resolvedId = await this.resolveMemoryId(id);
|
|
646
706
|
try {
|
|
647
|
-
const response = await this.client.put(`/api/v1/memories/${
|
|
707
|
+
const response = await this.client.put(`/api/v1/memories/${encodeURIComponent(resolvedId)}`, data);
|
|
648
708
|
return this.normalizeMemoryEntry(response.data);
|
|
649
709
|
}
|
|
650
710
|
catch (error) {
|
|
651
711
|
if (this.shouldUseLegacyMemoryRpcFallback(error) || error?.response?.status === 404) {
|
|
652
712
|
const fallback = await this.client.post('/api/v1/memory/update', {
|
|
653
|
-
id,
|
|
713
|
+
id: resolvedId,
|
|
654
714
|
...data
|
|
655
715
|
});
|
|
656
716
|
const payload = fallback.data && typeof fallback.data === 'object'
|
|
@@ -662,12 +722,15 @@ export class APIClient {
|
|
|
662
722
|
}
|
|
663
723
|
}
|
|
664
724
|
async deleteMemory(id) {
|
|
725
|
+
const resolvedId = await this.resolveMemoryId(id);
|
|
665
726
|
try {
|
|
666
|
-
await this.client.delete(`/api/v1/memories/${
|
|
727
|
+
await this.client.delete(`/api/v1/memories/${encodeURIComponent(resolvedId)}`);
|
|
667
728
|
}
|
|
668
729
|
catch (error) {
|
|
669
730
|
if (this.shouldUseLegacyMemoryRpcFallback(error) || error?.response?.status === 404) {
|
|
670
|
-
await this.client.
|
|
731
|
+
await this.client.delete('/api/v1/memory/delete', {
|
|
732
|
+
params: { id: resolvedId }
|
|
733
|
+
});
|
|
671
734
|
return;
|
|
672
735
|
}
|
|
673
736
|
throw error;
|
package/dist/utils/mcp-client.js
CHANGED
|
@@ -5,6 +5,13 @@ import { CLIConfig } from './config.js';
|
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import { EventSource } from 'eventsource';
|
|
7
7
|
import WebSocket from 'ws';
|
|
8
|
+
function getMemoryToolId(args) {
|
|
9
|
+
const id = typeof args.id === 'string' ? args.id.trim() : '';
|
|
10
|
+
if (id)
|
|
11
|
+
return id;
|
|
12
|
+
const legacyId = typeof args.memory_id === 'string' ? args.memory_id.trim() : '';
|
|
13
|
+
return legacyId || undefined;
|
|
14
|
+
}
|
|
8
15
|
export class MCPClient {
|
|
9
16
|
client = null;
|
|
10
17
|
config;
|
|
@@ -838,6 +845,7 @@ export class MCPClient {
|
|
|
838
845
|
endpoint: '/memory/{id}',
|
|
839
846
|
transform: (args) => {
|
|
840
847
|
const data = { ...args };
|
|
848
|
+
delete data.id;
|
|
841
849
|
delete data.memory_id;
|
|
842
850
|
return data;
|
|
843
851
|
}
|
|
@@ -861,9 +869,9 @@ export class MCPClient {
|
|
|
861
869
|
const axios = (await import('axios')).default;
|
|
862
870
|
// Handle dynamic endpoint for memory operations that need ID
|
|
863
871
|
let endpoint = mapping.endpoint;
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
endpoint = endpoint.replace('{id}',
|
|
872
|
+
const memoryId = getMemoryToolId(args);
|
|
873
|
+
if (endpoint.includes('{id}') && memoryId) {
|
|
874
|
+
endpoint = endpoint.replace('{id}', encodeURIComponent(memoryId));
|
|
867
875
|
}
|
|
868
876
|
const response = await axios({
|
|
869
877
|
method: mapping.method,
|
|
@@ -873,7 +881,7 @@ export class MCPClient {
|
|
|
873
881
|
'Content-Type': 'application/json'
|
|
874
882
|
},
|
|
875
883
|
data: mapping.transform ? mapping.transform(args) : undefined,
|
|
876
|
-
params: mapping.method === 'GET' ? args : undefined
|
|
884
|
+
params: mapping.method === 'GET' && !mapping.endpoint.includes('{id}') ? args : undefined
|
|
877
885
|
});
|
|
878
886
|
return response.data;
|
|
879
887
|
}
|
package/package.json
CHANGED