@lanonasis/cli 3.9.4 → 3.9.6

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/dist/index.js CHANGED
@@ -53,6 +53,18 @@ program
53
53
  process.env.MEMORY_API_URL = opts.apiUrl;
54
54
  }
55
55
  process.env.CLI_OUTPUT_FORMAT = opts.output;
56
+ const forceApiFromEnv = process.env.LANONASIS_FORCE_API === 'true' ||
57
+ process.env.CLI_FORCE_API === 'true' ||
58
+ process.env.ONASIS_FORCE_API === 'true';
59
+ const forceApiFromConfig = cliConfig.get('forceApi') === true ||
60
+ cliConfig.get('connectionTransport') === 'api';
61
+ const forceDirectApi = forceApiFromEnv || forceApiFromConfig || opts.mcp === false;
62
+ if (process.env.CLI_VERBOSE === 'true') {
63
+ console.log(colors.muted(`transport flags: env=${forceApiFromEnv} config=${forceApiFromConfig} no_mcp=${opts.mcp === false}`));
64
+ }
65
+ if (forceDirectApi) {
66
+ process.env.LANONASIS_FORCE_API = 'true';
67
+ }
56
68
  const skipOnboarding = actionCommand.name() === 'init' ||
57
69
  actionCommand.name() === 'auth' ||
58
70
  actionCommand.parent?.name?.() === 'auth';
@@ -76,7 +88,9 @@ program
76
88
  actionCommand.parent?.name?.() === 'mcp' ||
77
89
  actionCommand.name() === 'mcp-server' ||
78
90
  actionCommand.parent?.name?.() === 'mcp-server';
79
- if (opts.mcp !== false && !isMcpFlow && !['init', 'auth', 'login', 'health', 'status'].includes(actionCommand.name())) {
91
+ const isConfigFlow = actionCommand.name() === 'config' ||
92
+ actionCommand.parent?.name?.() === 'config';
93
+ if (!forceDirectApi && !isMcpFlow && !isConfigFlow && !['init', 'auth', 'login', 'health', 'status'].includes(actionCommand.name())) {
80
94
  try {
81
95
  const client = getMCPClient();
82
96
  if (!client.isConnectedToServer()) {
@@ -94,6 +108,9 @@ program
94
108
  }
95
109
  }
96
110
  }
111
+ else if (forceDirectApi && process.env.CLI_VERBOSE === 'true') {
112
+ console.log(colors.muted('MCP auto-connect skipped (force direct API enabled)'));
113
+ }
97
114
  });
98
115
  // Enhanced global error handler
99
116
  process.on('uncaughtException', (error) => {
@@ -399,11 +416,10 @@ const topicCmd = program
399
416
  .description('Topic management commands');
400
417
  requireAuth(topicCmd);
401
418
  topicCommands(topicCmd);
402
- // Configuration commands (require auth)
419
+ // Configuration commands (no auth required)
403
420
  const configCmd = program
404
421
  .command('config')
405
422
  .description('Configuration management');
406
- requireAuth(configCmd);
407
423
  configCommands(configCmd);
408
424
  // Organization commands (require auth)
409
425
  const orgCmd = program
@@ -614,18 +630,30 @@ program
614
630
  .description('Show overall system status')
615
631
  .action(async () => {
616
632
  await cliConfig.init();
617
- const isAuth = await cliConfig.isAuthenticated();
633
+ const verification = await cliConfig.verifyCurrentCredentialsWithServer().catch((error) => ({
634
+ valid: false,
635
+ method: 'none',
636
+ endpoint: undefined,
637
+ reason: error instanceof Error ? error.message : String(error)
638
+ }));
639
+ const isAuth = verification.valid;
618
640
  const apiUrl = cliConfig.getApiUrl();
619
641
  console.log(chalk.blue.bold('MaaS CLI Status'));
620
642
  console.log(`API URL: ${apiUrl}`);
621
643
  console.log(`Authenticated: ${isAuth ? chalk.green('Yes') : chalk.red('No')}`);
644
+ if (process.env.CLI_VERBOSE === 'true' && verification.endpoint) {
645
+ console.log(`Verified via: ${verification.endpoint}`);
646
+ }
622
647
  if (isAuth) {
623
648
  const user = await cliConfig.getCurrentUser();
624
649
  if (user) {
625
650
  console.log(`User: ${user.email}`);
626
651
  console.log(`Plan: ${user.plan}`);
627
652
  }
653
+ return;
628
654
  }
655
+ console.log(chalk.yellow(`Auth check: ${verification.reason || 'Credential validation failed'}`));
656
+ console.log(chalk.yellow('Please run:'), chalk.white('lanonasis auth login'));
629
657
  });
630
658
  // Health command using the healthCheck function
631
659
  program
@@ -14,16 +14,16 @@ export declare const MemoryCreateSchema: z.ZodObject<{
14
14
  title?: string;
15
15
  content?: string;
16
16
  tags?: string[];
17
+ memory_type?: "context" | "reference" | "note";
17
18
  topic_id?: string;
18
19
  metadata?: Record<string, any>;
19
- memory_type?: "context" | "reference" | "note";
20
20
  }, {
21
21
  title?: string;
22
22
  content?: string;
23
23
  tags?: string[];
24
+ memory_type?: "context" | "reference" | "note";
24
25
  topic_id?: string;
25
26
  metadata?: Record<string, any>;
26
- memory_type?: "context" | "reference" | "note";
27
27
  }>;
28
28
  export declare const MemorySearchSchema: z.ZodObject<{
29
29
  query: z.ZodString;
@@ -36,16 +36,16 @@ export declare const MemorySearchSchema: z.ZodObject<{
36
36
  query?: string;
37
37
  tags?: string[];
38
38
  limit?: number;
39
+ memory_type?: "context" | "reference" | "note";
39
40
  topic_id?: string;
40
41
  threshold?: number;
41
- memory_type?: "context" | "reference" | "note";
42
42
  }, {
43
43
  query?: string;
44
44
  tags?: string[];
45
45
  limit?: number;
46
+ memory_type?: "context" | "reference" | "note";
46
47
  topic_id?: string;
47
48
  threshold?: number;
48
- memory_type?: "context" | "reference" | "note";
49
49
  }>;
50
50
  export declare const MemoryUpdateSchema: z.ZodObject<{
51
51
  memory_id: z.ZodString;
@@ -58,16 +58,16 @@ export declare const MemoryUpdateSchema: z.ZodObject<{
58
58
  title?: string;
59
59
  content?: string;
60
60
  tags?: string[];
61
+ memory_type?: "context" | "reference" | "note";
61
62
  memory_id?: string;
62
63
  metadata?: Record<string, any>;
63
- memory_type?: "context" | "reference" | "note";
64
64
  }, {
65
65
  title?: string;
66
66
  content?: string;
67
67
  tags?: string[];
68
+ memory_type?: "context" | "reference" | "note";
68
69
  memory_id?: string;
69
70
  metadata?: Record<string, any>;
70
- memory_type?: "context" | "reference" | "note";
71
71
  }>;
72
72
  export declare const MemoryDeleteSchema: z.ZodObject<{
73
73
  memory_id: z.ZodString;
@@ -90,17 +90,17 @@ export declare const MemoryListSchema: z.ZodObject<{
90
90
  }, "strip", z.ZodTypeAny, {
91
91
  tags?: string[];
92
92
  limit?: number;
93
- topic_id?: string;
94
- memory_type?: "context" | "reference" | "note";
95
93
  offset?: number;
94
+ memory_type?: "context" | "reference" | "note";
95
+ topic_id?: string;
96
96
  sort_by?: "title" | "created_at" | "updated_at";
97
97
  order?: "desc" | "asc";
98
98
  }, {
99
99
  tags?: string[];
100
100
  limit?: number;
101
- topic_id?: string;
102
- memory_type?: "context" | "reference" | "note";
103
101
  offset?: number;
102
+ memory_type?: "context" | "reference" | "note";
103
+ topic_id?: string;
104
104
  sort_by?: "title" | "created_at" | "updated_at";
105
105
  order?: "desc" | "asc";
106
106
  }>;
@@ -201,14 +201,14 @@ export declare const SystemConfigSchema: z.ZodObject<{
201
201
  scope: z.ZodDefault<z.ZodEnum<["user", "global"]>>;
202
202
  }, "strip", z.ZodTypeAny, {
203
203
  value?: any;
204
- key?: string;
205
204
  action?: "get" | "set" | "reset";
206
205
  scope?: "user" | "global";
206
+ key?: string;
207
207
  }, {
208
208
  value?: any;
209
- key?: string;
210
209
  action?: "get" | "set" | "reset";
211
210
  scope?: "user" | "global";
211
+ key?: string;
212
212
  }>;
213
213
  export declare const BulkOperationSchema: z.ZodObject<{
214
214
  operation: z.ZodEnum<["create", "update", "delete"]>;
@@ -386,16 +386,16 @@ export declare const MCPSchemas: {
386
386
  title?: string;
387
387
  content?: string;
388
388
  tags?: string[];
389
+ memory_type?: "context" | "reference" | "note";
389
390
  topic_id?: string;
390
391
  metadata?: Record<string, any>;
391
- memory_type?: "context" | "reference" | "note";
392
392
  }, {
393
393
  title?: string;
394
394
  content?: string;
395
395
  tags?: string[];
396
+ memory_type?: "context" | "reference" | "note";
396
397
  topic_id?: string;
397
398
  metadata?: Record<string, any>;
398
- memory_type?: "context" | "reference" | "note";
399
399
  }>;
400
400
  search: z.ZodObject<{
401
401
  query: z.ZodString;
@@ -408,16 +408,16 @@ export declare const MCPSchemas: {
408
408
  query?: string;
409
409
  tags?: string[];
410
410
  limit?: number;
411
+ memory_type?: "context" | "reference" | "note";
411
412
  topic_id?: string;
412
413
  threshold?: number;
413
- memory_type?: "context" | "reference" | "note";
414
414
  }, {
415
415
  query?: string;
416
416
  tags?: string[];
417
417
  limit?: number;
418
+ memory_type?: "context" | "reference" | "note";
418
419
  topic_id?: string;
419
420
  threshold?: number;
420
- memory_type?: "context" | "reference" | "note";
421
421
  }>;
422
422
  update: z.ZodObject<{
423
423
  memory_id: z.ZodString;
@@ -430,16 +430,16 @@ export declare const MCPSchemas: {
430
430
  title?: string;
431
431
  content?: string;
432
432
  tags?: string[];
433
+ memory_type?: "context" | "reference" | "note";
433
434
  memory_id?: string;
434
435
  metadata?: Record<string, any>;
435
- memory_type?: "context" | "reference" | "note";
436
436
  }, {
437
437
  title?: string;
438
438
  content?: string;
439
439
  tags?: string[];
440
+ memory_type?: "context" | "reference" | "note";
440
441
  memory_id?: string;
441
442
  metadata?: Record<string, any>;
442
- memory_type?: "context" | "reference" | "note";
443
443
  }>;
444
444
  delete: z.ZodObject<{
445
445
  memory_id: z.ZodString;
@@ -462,17 +462,17 @@ export declare const MCPSchemas: {
462
462
  }, "strip", z.ZodTypeAny, {
463
463
  tags?: string[];
464
464
  limit?: number;
465
- topic_id?: string;
466
- memory_type?: "context" | "reference" | "note";
467
465
  offset?: number;
466
+ memory_type?: "context" | "reference" | "note";
467
+ topic_id?: string;
468
468
  sort_by?: "title" | "created_at" | "updated_at";
469
469
  order?: "desc" | "asc";
470
470
  }, {
471
471
  tags?: string[];
472
472
  limit?: number;
473
- topic_id?: string;
474
- memory_type?: "context" | "reference" | "note";
475
473
  offset?: number;
474
+ memory_type?: "context" | "reference" | "note";
475
+ topic_id?: string;
476
476
  sort_by?: "title" | "created_at" | "updated_at";
477
477
  order?: "desc" | "asc";
478
478
  }>;
@@ -579,14 +579,14 @@ export declare const MCPSchemas: {
579
579
  scope: z.ZodDefault<z.ZodEnum<["user", "global"]>>;
580
580
  }, "strip", z.ZodTypeAny, {
581
581
  value?: any;
582
- key?: string;
583
582
  action?: "get" | "set" | "reset";
584
583
  scope?: "user" | "global";
584
+ key?: string;
585
585
  }, {
586
586
  value?: any;
587
- key?: string;
588
587
  action?: "get" | "set" | "reset";
589
588
  scope?: "user" | "global";
589
+ key?: string;
590
590
  }>;
591
591
  };
592
592
  operations: {
@@ -54,11 +54,15 @@ export interface UpdateMemoryRequest {
54
54
  metadata?: Record<string, unknown>;
55
55
  }
56
56
  export interface GetMemoriesParams {
57
+ page?: number;
57
58
  limit?: number;
58
59
  offset?: number;
59
60
  memory_type?: MemoryType;
60
61
  tags?: string[] | string;
61
62
  topic_id?: string;
63
+ user_id?: string;
64
+ sort?: 'created_at' | 'updated_at' | 'last_accessed' | 'access_count' | 'title';
65
+ order?: 'asc' | 'desc';
62
66
  sort_by?: 'created_at' | 'updated_at' | 'last_accessed' | 'access_count';
63
67
  sort_order?: 'asc' | 'desc';
64
68
  }
@@ -148,6 +152,8 @@ export interface ApiErrorResponse {
148
152
  export declare class APIClient {
149
153
  private client;
150
154
  private config;
155
+ private normalizeMemoryEntry;
156
+ private shouldUseLegacyMemoryRpcFallback;
151
157
  constructor();
152
158
  login(email: string, password: string): Promise<AuthResponse>;
153
159
  register(email: string, password: string, organizationName?: string): Promise<AuthResponse>;
package/dist/utils/api.js CHANGED
@@ -5,6 +5,41 @@ import { CLIConfig } from './config.js';
5
5
  export class APIClient {
6
6
  client;
7
7
  config;
8
+ normalizeMemoryEntry(payload) {
9
+ // API responses are inconsistent across gateways:
10
+ // - Some return the memory entry directly
11
+ // - Some wrap it in `{ data: <memory>, message?: string }`
12
+ if (payload && typeof payload === 'object') {
13
+ const obj = payload;
14
+ const directId = obj.id;
15
+ if (typeof directId === 'string' && directId.length > 0) {
16
+ return payload;
17
+ }
18
+ const data = obj.data;
19
+ if (data && typeof data === 'object') {
20
+ const dataObj = data;
21
+ if (typeof dataObj.id === 'string' && dataObj.id.length > 0) {
22
+ return data;
23
+ }
24
+ }
25
+ }
26
+ return payload;
27
+ }
28
+ shouldUseLegacyMemoryRpcFallback(error) {
29
+ const status = error?.response?.status;
30
+ const errorData = error?.response?.data;
31
+ const message = `${errorData?.error || ''} ${errorData?.message || ''}`.toLowerCase();
32
+ if (status === 405) {
33
+ return true;
34
+ }
35
+ if (status === 400 && message.includes('memory id is required')) {
36
+ return true;
37
+ }
38
+ if (status === 400 && message.includes('method not allowed')) {
39
+ return true;
40
+ }
41
+ return false;
42
+ }
8
43
  constructor() {
9
44
  this.config = new CLIConfig();
10
45
  this.client = axios.create({
@@ -13,6 +48,8 @@ export class APIClient {
13
48
  // Setup request interceptor to add auth token and headers
14
49
  this.client.interceptors.request.use(async (config) => {
15
50
  await this.config.init();
51
+ // Keep OAuth sessions alive automatically (prevents intermittent "auth required" cutouts).
52
+ await this.config.refreshTokenIfNeeded();
16
53
  // Service Discovery
17
54
  await this.config.discoverServices();
18
55
  // Use appropriate base URL based on endpoint and auth method
@@ -20,17 +57,28 @@ export class APIClient {
20
57
  const discoveredServices = this.config.get('discoveredServices');
21
58
  const authMethod = this.config.get('authMethod');
22
59
  const vendorKey = await this.config.getVendorKeyAsync();
60
+ const token = this.config.getToken();
61
+ const isMemoryEndpoint = typeof config.url === 'string' && config.url.startsWith('/api/v1/memories');
62
+ const forceApiFromEnv = process.env.LANONASIS_FORCE_API === 'true'
63
+ || process.env.CLI_FORCE_API === 'true'
64
+ || process.env.ONASIS_FORCE_API === 'true';
65
+ const forceApiFromConfig = this.config.get('forceApi') === true
66
+ || this.config.get('connectionTransport') === 'api';
67
+ // Memory CRUD/search endpoints should always use the API gateway path.
68
+ const forceDirectApi = forceApiFromEnv || forceApiFromConfig || isMemoryEndpoint;
69
+ const prefersTokenAuth = Boolean(token) && (authMethod === 'jwt' || authMethod === 'oauth' || authMethod === 'oauth2');
70
+ const useVendorKeyAuth = Boolean(vendorKey) && !prefersTokenAuth;
23
71
  // Determine the correct API base URL:
24
72
  // - Auth endpoints -> auth.lanonasis.com
25
73
  // - JWT auth (no vendor key) -> mcp.lanonasis.com (supports JWT tokens)
26
74
  // - Vendor key auth -> api.lanonasis.com (requires vendor key)
27
75
  let apiBaseUrl;
28
- const useMcpServer = !vendorKey && (authMethod === 'jwt' || authMethod === 'oauth' || authMethod === 'oauth2');
76
+ const useMcpServer = !forceDirectApi && prefersTokenAuth && !useVendorKeyAuth;
29
77
  if (isAuthEndpoint) {
30
78
  apiBaseUrl = discoveredServices?.auth_base || 'https://auth.lanonasis.com';
31
79
  }
32
- else if (vendorKey) {
33
- // Vendor key works with api.lanonasis.com
80
+ else if (forceDirectApi) {
81
+ // Force direct REST API mode to bypass MCP routing for troubleshooting.
34
82
  apiBaseUrl = this.config.getApiUrl();
35
83
  }
36
84
  else if (useMcpServer) {
@@ -51,8 +99,22 @@ export class APIClient {
51
99
  config.headers['X-Project-Scope'] = 'lanonasis-maas';
52
100
  }
53
101
  // Enhanced Authentication Support
54
- const token = this.config.getToken();
55
- if (vendorKey) {
102
+ // Even in forced direct-API mode, prefer bearer token auth when available.
103
+ // This avoids accidentally sending an OAuth access token as X-API-Key (we store it
104
+ // in secure storage for MCP/WebSocket usage), which can cause 401s.
105
+ const preferVendorKeyInDirectApiMode = forceDirectApi && Boolean(vendorKey) && !prefersTokenAuth;
106
+ if (preferVendorKeyInDirectApiMode) {
107
+ // Vendor key authentication (validated server-side)
108
+ // Send raw key - server handles hashing for comparison
109
+ config.headers['X-API-Key'] = vendorKey;
110
+ config.headers['X-Auth-Method'] = 'vendor_key';
111
+ }
112
+ else if (prefersTokenAuth) {
113
+ // JWT/OAuth token authentication takes precedence when both are present.
114
+ config.headers.Authorization = `Bearer ${token}`;
115
+ config.headers['X-Auth-Method'] = 'jwt';
116
+ }
117
+ else if (vendorKey) {
56
118
  // Vendor key authentication (validated server-side)
57
119
  // Send raw key - server handles hashing for comparison
58
120
  config.headers['X-API-Key'] = vendorKey;
@@ -69,7 +131,10 @@ export class APIClient {
69
131
  // Add project scope for Golden Contract compliance
70
132
  config.headers['X-Project-Scope'] = 'lanonasis-maas';
71
133
  if (process.env.CLI_VERBOSE === 'true') {
134
+ const transportMode = forceDirectApi ? 'api-forced' : (useMcpServer ? 'mcp-http' : 'api');
135
+ config.headers['X-Transport-Mode'] = transportMode;
72
136
  console.log(chalk.dim(`→ ${config.method?.toUpperCase()} ${config.url} [${requestId}]`));
137
+ console.log(chalk.dim(` transport=${transportMode} baseURL=${config.baseURL}`));
73
138
  }
74
139
  return config;
75
140
  });
@@ -84,7 +149,7 @@ export class APIClient {
84
149
  const { status, data } = error.response;
85
150
  if (status === 401) {
86
151
  console.error(chalk.red('✖ Authentication failed'));
87
- console.log(chalk.yellow('Please run:'), chalk.white('memory login'));
152
+ console.log(chalk.yellow('Please run:'), chalk.white('lanonasis auth login'));
88
153
  process.exit(1);
89
154
  }
90
155
  if (status === 403) {
@@ -127,22 +192,207 @@ export class APIClient {
127
192
  // All memory endpoints use /api/v1/memories path (plural, per REST conventions)
128
193
  async createMemory(data) {
129
194
  const response = await this.client.post('/api/v1/memories', data);
130
- return response.data;
195
+ return this.normalizeMemoryEntry(response.data);
131
196
  }
132
197
  async getMemories(params = {}) {
133
- const response = await this.client.get('/api/v1/memories', { params });
134
- return response.data;
198
+ try {
199
+ const response = await this.client.get('/api/v1/memories', { params });
200
+ return response.data;
201
+ }
202
+ catch (error) {
203
+ // Backward-compatible fallback: newer API contracts may reject GET list.
204
+ if (error?.response?.status === 405) {
205
+ const limit = Number(params.limit || 20);
206
+ const page = Number(params.page || 1);
207
+ const offset = Number(params.offset ?? Math.max(0, (page - 1) * limit));
208
+ // Preferred fallback: POST list endpoint (avoids triggering vector search for plain listings).
209
+ const listPayload = {
210
+ limit,
211
+ offset
212
+ };
213
+ if (params.memory_type) {
214
+ listPayload.memory_type = params.memory_type;
215
+ }
216
+ if (params.tags) {
217
+ listPayload.tags = Array.isArray(params.tags)
218
+ ? params.tags
219
+ : String(params.tags).split(',').map((tag) => tag.trim()).filter(Boolean);
220
+ }
221
+ if (params.topic_id) {
222
+ listPayload.topic_id = params.topic_id;
223
+ }
224
+ if (params.user_id) {
225
+ listPayload.user_id = params.user_id;
226
+ }
227
+ if (params.sort || params.sort_by) {
228
+ listPayload.sort_by = params.sort_by || params.sort;
229
+ }
230
+ if (params.order || params.sort_order) {
231
+ listPayload.sort_order = params.sort_order || params.order;
232
+ }
233
+ for (const endpoint of ['/api/v1/memories/list', '/api/v1/memory/list']) {
234
+ try {
235
+ const listResponse = await this.client.post(endpoint, listPayload);
236
+ const payload = listResponse.data || {};
237
+ const resultsArray = Array.isArray(payload.data)
238
+ ? payload.data
239
+ : Array.isArray(payload.memories)
240
+ ? payload.memories
241
+ : Array.isArray(payload.results)
242
+ ? payload.results
243
+ : [];
244
+ const memories = resultsArray.map((entry) => this.normalizeMemoryEntry(entry));
245
+ const pagination = (payload.pagination && typeof payload.pagination === 'object')
246
+ ? payload.pagination
247
+ : {};
248
+ const total = Number.isFinite(Number(pagination.total))
249
+ ? Number(pagination.total)
250
+ : Number.isFinite(Number(payload.total))
251
+ ? Number(payload.total)
252
+ : memories.length;
253
+ const pages = Number.isFinite(Number(pagination.total_pages))
254
+ ? Number(pagination.total_pages)
255
+ : Number.isFinite(Number(pagination.pages))
256
+ ? Number(pagination.pages)
257
+ : Math.max(1, Math.ceil(total / limit));
258
+ const currentPage = Number.isFinite(Number(pagination.page))
259
+ ? Number(pagination.page)
260
+ : Math.max(1, Math.floor(offset / limit) + 1);
261
+ const hasMore = typeof pagination.has_more === 'boolean'
262
+ ? pagination.has_more
263
+ : typeof pagination.has_next === 'boolean'
264
+ ? pagination.has_next
265
+ : (offset + memories.length) < total;
266
+ return {
267
+ ...payload,
268
+ data: memories,
269
+ memories,
270
+ pagination: {
271
+ total,
272
+ limit,
273
+ offset,
274
+ has_more: hasMore,
275
+ page: currentPage,
276
+ pages
277
+ }
278
+ };
279
+ }
280
+ catch (listError) {
281
+ if (listError?.response?.status === 404 || listError?.response?.status === 405) {
282
+ continue;
283
+ }
284
+ throw listError;
285
+ }
286
+ }
287
+ // Secondary fallback: search endpoint for legacy contracts that expose only search.
288
+ const searchPayload = {
289
+ query: '*',
290
+ limit,
291
+ threshold: 0
292
+ };
293
+ if (params.memory_type) {
294
+ searchPayload.memory_types = [params.memory_type];
295
+ }
296
+ if (params.tags) {
297
+ searchPayload.tags = Array.isArray(params.tags)
298
+ ? params.tags
299
+ : String(params.tags).split(',').map((tag) => tag.trim()).filter(Boolean);
300
+ }
301
+ if (params.topic_id) {
302
+ searchPayload.topic_id = params.topic_id;
303
+ }
304
+ if (offset > 0) {
305
+ searchPayload.offset = offset;
306
+ }
307
+ const fallback = await this.client.post('/api/v1/memories/search', searchPayload);
308
+ const payload = fallback.data || {};
309
+ const resultsArray = Array.isArray(payload.data)
310
+ ? payload.data
311
+ : Array.isArray(payload.results)
312
+ ? payload.results
313
+ : [];
314
+ const memories = resultsArray
315
+ .map((entry) => {
316
+ // Some gateways/search endpoints wrap results as `{ data: <memory> }`.
317
+ if (entry && typeof entry === 'object') {
318
+ const obj = entry;
319
+ const data = obj.data;
320
+ if (data && typeof data === 'object') {
321
+ const dataObj = data;
322
+ if (typeof dataObj.id === 'string' && dataObj.id.length > 0) {
323
+ return data;
324
+ }
325
+ }
326
+ }
327
+ return entry;
328
+ })
329
+ .map((entry) => this.normalizeMemoryEntry(entry));
330
+ const total = Number.isFinite(payload.total) ? Number(payload.total) : memories.length;
331
+ const pages = Math.max(1, Math.ceil(total / limit));
332
+ const currentPage = Math.max(1, Math.floor(offset / limit) + 1);
333
+ return {
334
+ ...payload,
335
+ data: memories,
336
+ memories,
337
+ pagination: {
338
+ total,
339
+ limit,
340
+ offset,
341
+ has_more: (offset + memories.length) < total,
342
+ page: currentPage,
343
+ pages
344
+ }
345
+ };
346
+ }
347
+ throw error;
348
+ }
135
349
  }
136
350
  async getMemory(id) {
137
- const response = await this.client.get(`/api/v1/memories/${id}`);
138
- return response.data;
351
+ try {
352
+ const response = await this.client.get(`/api/v1/memories/${id}`);
353
+ return this.normalizeMemoryEntry(response.data);
354
+ }
355
+ catch (error) {
356
+ if (this.shouldUseLegacyMemoryRpcFallback(error)) {
357
+ const fallback = await this.client.post('/api/v1/memory/get', { id });
358
+ const payload = fallback.data && typeof fallback.data === 'object'
359
+ ? fallback.data.data ?? fallback.data
360
+ : fallback.data;
361
+ return this.normalizeMemoryEntry(payload);
362
+ }
363
+ throw error;
364
+ }
139
365
  }
140
366
  async updateMemory(id, data) {
141
- const response = await this.client.put(`/api/v1/memories/${id}`, data);
142
- return response.data;
367
+ try {
368
+ const response = await this.client.put(`/api/v1/memories/${id}`, data);
369
+ return this.normalizeMemoryEntry(response.data);
370
+ }
371
+ catch (error) {
372
+ if (this.shouldUseLegacyMemoryRpcFallback(error)) {
373
+ const fallback = await this.client.post('/api/v1/memory/update', {
374
+ id,
375
+ ...data
376
+ });
377
+ const payload = fallback.data && typeof fallback.data === 'object'
378
+ ? fallback.data.data ?? fallback.data
379
+ : fallback.data;
380
+ return this.normalizeMemoryEntry(payload);
381
+ }
382
+ throw error;
383
+ }
143
384
  }
144
385
  async deleteMemory(id) {
145
- await this.client.delete(`/api/v1/memories/${id}`);
386
+ try {
387
+ await this.client.delete(`/api/v1/memories/${id}`);
388
+ }
389
+ catch (error) {
390
+ if (this.shouldUseLegacyMemoryRpcFallback(error)) {
391
+ await this.client.post('/api/v1/memory/delete', { id });
392
+ return;
393
+ }
394
+ throw error;
395
+ }
146
396
  }
147
397
  async searchMemories(query, options = {}) {
148
398
  const response = await this.client.post('/api/v1/memories/search', {
@@ -34,6 +34,12 @@ interface CLIConfigData {
34
34
  lastAuthFailure?: string | undefined;
35
35
  [key: string]: unknown;
36
36
  }
37
+ export type RemoteAuthVerification = {
38
+ valid: boolean;
39
+ method: 'token' | 'vendor_key' | 'none';
40
+ endpoint?: string;
41
+ reason?: string;
42
+ };
37
43
  export declare class CLIConfig {
38
44
  private configDir;
39
45
  private configPath;
@@ -70,6 +76,11 @@ export declare class CLIConfig {
70
76
  private resolveFallbackEndpoints;
71
77
  private logFallbackUsage;
72
78
  private pingAuthHealth;
79
+ private getAuthVerificationEndpoints;
80
+ private extractAuthErrorMessage;
81
+ private verifyTokenWithAuthGateway;
82
+ private verifyVendorKeyWithAuthGateway;
83
+ verifyCurrentCredentialsWithServer(): Promise<RemoteAuthVerification>;
73
84
  setManualEndpoints(endpoints: Partial<CLIConfigData['discoveredServices']>): Promise<void>;
74
85
  hasManualEndpointOverrides(): boolean;
75
86
  clearManualEndpointOverrides(): Promise<void>;