@lanonasis/cli 1.4.2 → 1.5.0

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.
@@ -57,7 +57,7 @@ export interface GetMemoriesParams {
57
57
  limit?: number;
58
58
  offset?: number;
59
59
  memory_type?: MemoryType;
60
- tags?: string[] | string;
60
+ tags?: string[];
61
61
  topic_id?: string;
62
62
  sort_by?: 'created_at' | 'updated_at' | 'last_accessed' | 'access_count';
63
63
  sort_order?: 'asc' | 'desc';
@@ -125,19 +125,13 @@ export interface HealthStatus {
125
125
  }>;
126
126
  }
127
127
  export interface PaginatedResponse<T> {
128
- data?: T[];
129
- memories?: T[];
130
- results?: T[];
128
+ data: T[];
131
129
  pagination: {
132
130
  total: number;
133
131
  limit: number;
134
132
  offset: number;
135
133
  has_more: boolean;
136
- page?: number;
137
- pages?: number;
138
134
  };
139
- total_results?: number;
140
- search_time_ms?: number;
141
135
  }
142
136
  export interface ApiErrorResponse {
143
137
  error: string;
@@ -165,10 +159,6 @@ export declare class APIClient {
165
159
  updateTopic(id: string, data: UpdateTopicRequest): Promise<MemoryTopic>;
166
160
  deleteTopic(id: string): Promise<void>;
167
161
  getHealth(): Promise<HealthStatus>;
168
- get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
169
- post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
170
- put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
171
- delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
172
162
  request<T = Record<string, unknown>>(config: AxiosRequestConfig): Promise<T>;
173
163
  }
174
164
  export declare const apiClient: APIClient;
package/dist/utils/api.js CHANGED
@@ -132,23 +132,6 @@ export class APIClient {
132
132
  const response = await this.client.get('/api/v1/health');
133
133
  return response.data;
134
134
  }
135
- // Generic HTTP methods
136
- async get(url, config) {
137
- const response = await this.client.get(url, config);
138
- return response.data;
139
- }
140
- async post(url, data, config) {
141
- const response = await this.client.post(url, data, config);
142
- return response.data;
143
- }
144
- async put(url, data, config) {
145
- const response = await this.client.put(url, data, config);
146
- return response.data;
147
- }
148
- async delete(url, config) {
149
- const response = await this.client.delete(url, config);
150
- return response.data;
151
- }
152
135
  // Generic request method
153
136
  async request(config) {
154
137
  const response = await this.client.request(config);
@@ -0,0 +1,28 @@
1
+ export interface CompletionData {
2
+ commands: string[];
3
+ memory: {
4
+ types: string[];
5
+ tags: string[];
6
+ recentIds: string[];
7
+ };
8
+ topics: string[];
9
+ organizations: string[];
10
+ }
11
+ export declare class TabCompletions {
12
+ private config;
13
+ private completionData;
14
+ constructor();
15
+ init(): Promise<void>;
16
+ private loadDynamicCompletions;
17
+ private loadRecentMemories;
18
+ private loadTopics;
19
+ private loadTags;
20
+ getCompletions(line: string, position: number): string[];
21
+ private getMemoryCompletions;
22
+ private getCreateCompletions;
23
+ private getSearchCompletions;
24
+ private getListCompletions;
25
+ private getTopicCompletions;
26
+ generateBashCompletion(): string;
27
+ generateZshCompletion(): string;
28
+ }
@@ -0,0 +1,276 @@
1
+ import chalk from 'chalk';
2
+ import { CLIConfig } from './config.js';
3
+ export class TabCompletions {
4
+ config;
5
+ completionData;
6
+ constructor() {
7
+ this.config = new CLIConfig();
8
+ this.completionData = {
9
+ commands: [
10
+ 'auth', 'login', 'logout', 'status',
11
+ 'memory', 'mem', 'create', 'search', 'list', 'get', 'update', 'delete',
12
+ 'topic', 'topics', 'org', 'organization',
13
+ 'config', 'mcp', 'init', 'docs', 'help'
14
+ ],
15
+ memory: {
16
+ types: ['context', 'project', 'knowledge', 'reference', 'personal', 'workflow'],
17
+ tags: [],
18
+ recentIds: []
19
+ },
20
+ topics: [],
21
+ organizations: []
22
+ };
23
+ }
24
+ async init() {
25
+ await this.config.init();
26
+ await this.loadDynamicCompletions();
27
+ }
28
+ async loadDynamicCompletions() {
29
+ const isAuth = await this.config.isAuthenticated();
30
+ if (!isAuth)
31
+ return;
32
+ try {
33
+ // Load recent memory IDs, tags, topics from API
34
+ // This would be enhanced with actual API calls
35
+ await this.loadRecentMemories();
36
+ await this.loadTopics();
37
+ await this.loadTags();
38
+ }
39
+ catch (error) {
40
+ // Fail silently for completions
41
+ if (process.env.CLI_VERBOSE === 'true') {
42
+ console.error(chalk.gray('Failed to load completions data'));
43
+ }
44
+ }
45
+ }
46
+ async loadRecentMemories() {
47
+ // This would call the API to get recent memory IDs
48
+ // For now, we'll use mock data
49
+ this.completionData.memory.recentIds = [
50
+ 'mem_12345', 'mem_67890', 'mem_abcdef'
51
+ ];
52
+ }
53
+ async loadTopics() {
54
+ // This would call the API to get user's topics
55
+ this.completionData.topics = [
56
+ 'work', 'personal', 'learning', 'projects'
57
+ ];
58
+ }
59
+ async loadTags() {
60
+ // This would call the API to get commonly used tags
61
+ this.completionData.memory.tags = [
62
+ 'important', 'todo', 'reference', 'meeting', 'idea'
63
+ ];
64
+ }
65
+ getCompletions(line, position) {
66
+ const words = line.trim().split(/\s+/);
67
+ const currentWord = words[words.length - 1] || '';
68
+ // If we're at the beginning or after a space, suggest commands
69
+ if (words.length <= 1 || line.endsWith(' ')) {
70
+ return this.completionData.commands.filter(cmd => cmd.startsWith(currentWord.toLowerCase()));
71
+ }
72
+ const command = words[0];
73
+ const subcommand = words[1];
74
+ // Context-aware completions
75
+ switch (command) {
76
+ case 'memory':
77
+ case 'mem':
78
+ return this.getMemoryCompletions(words, currentWord);
79
+ case 'topic':
80
+ case 'topics':
81
+ return this.getTopicCompletions(words, currentWord);
82
+ case 'auth':
83
+ return ['login', 'logout', 'status'].filter(cmd => cmd.startsWith(currentWord));
84
+ case 'config':
85
+ return ['show', 'set', 'get', 'reset'].filter(cmd => cmd.startsWith(currentWord));
86
+ default:
87
+ return [];
88
+ }
89
+ }
90
+ getMemoryCompletions(words, currentWord) {
91
+ if (words.length === 2) {
92
+ // Memory subcommands
93
+ return ['create', 'search', 'list', 'get', 'update', 'delete', 'stats']
94
+ .filter(cmd => cmd.startsWith(currentWord));
95
+ }
96
+ const subcommand = words[1];
97
+ switch (subcommand) {
98
+ case 'create':
99
+ return this.getCreateCompletions(words, currentWord);
100
+ case 'search':
101
+ return this.getSearchCompletions(words, currentWord);
102
+ case 'list':
103
+ return this.getListCompletions(words, currentWord);
104
+ case 'get':
105
+ case 'update':
106
+ case 'delete':
107
+ return this.completionData.memory.recentIds.filter(id => id.startsWith(currentWord));
108
+ default:
109
+ return [];
110
+ }
111
+ }
112
+ getCreateCompletions(words, currentWord) {
113
+ // Look for flags
114
+ const prevWord = words[words.length - 2];
115
+ if (prevWord === '--type' || prevWord === '-t') {
116
+ return this.completionData.memory.types.filter(type => type.startsWith(currentWord));
117
+ }
118
+ if (prevWord === '--tags') {
119
+ return this.completionData.memory.tags.filter(tag => tag.startsWith(currentWord));
120
+ }
121
+ // Suggest flags
122
+ if (currentWord.startsWith('-')) {
123
+ return ['--title', '--content', '--type', '--tags', '--topic']
124
+ .filter(flag => flag.startsWith(currentWord));
125
+ }
126
+ return [];
127
+ }
128
+ getSearchCompletions(words, currentWord) {
129
+ const prevWord = words[words.length - 2];
130
+ if (prevWord === '--type') {
131
+ return this.completionData.memory.types.filter(type => type.startsWith(currentWord));
132
+ }
133
+ if (prevWord === '--topic') {
134
+ return this.completionData.topics.filter(topic => topic.startsWith(currentWord));
135
+ }
136
+ if (currentWord.startsWith('-')) {
137
+ return ['--limit', '--type', '--topic', '--tags']
138
+ .filter(flag => flag.startsWith(currentWord));
139
+ }
140
+ return [];
141
+ }
142
+ getListCompletions(words, currentWord) {
143
+ const prevWord = words[words.length - 2];
144
+ if (prevWord === '--type') {
145
+ return this.completionData.memory.types.filter(type => type.startsWith(currentWord));
146
+ }
147
+ if (currentWord.startsWith('-')) {
148
+ return ['--limit', '--type', '--topic', '--tags']
149
+ .filter(flag => flag.startsWith(currentWord));
150
+ }
151
+ return [];
152
+ }
153
+ getTopicCompletions(words, currentWord) {
154
+ if (words.length === 2) {
155
+ return ['list', 'create', 'get', 'update', 'delete']
156
+ .filter(cmd => cmd.startsWith(currentWord));
157
+ }
158
+ const subcommand = words[1];
159
+ if (['get', 'update', 'delete'].includes(subcommand)) {
160
+ return this.completionData.topics.filter(topic => topic.startsWith(currentWord));
161
+ }
162
+ return [];
163
+ }
164
+ // Generate shell completion scripts
165
+ generateBashCompletion() {
166
+ return `
167
+ _lanonasis_completion() {
168
+ local cur prev opts
169
+ COMPREPLY=()
170
+ cur="\${COMP_WORDS[COMP_CWORD]}"
171
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
172
+
173
+ # Basic command completion
174
+ if [[ \${COMP_CWORD} == 1 ]] ; then
175
+ opts="auth login logout status memory mem topic topics config mcp init docs help"
176
+ COMPREPLY=( \$(compgen -W "\${opts}" -- \${cur}) )
177
+ return 0
178
+ fi
179
+
180
+ # Memory subcommands
181
+ if [[ \${COMP_WORDS[1]} == "memory" || \${COMP_WORDS[1]} == "mem" ]] ; then
182
+ if [[ \${COMP_CWORD} == 2 ]] ; then
183
+ opts="create search list get update delete stats"
184
+ COMPREPLY=( \$(compgen -W "\${opts}" -- \${cur}) )
185
+ return 0
186
+ fi
187
+ fi
188
+
189
+ # Topic subcommands
190
+ if [[ \${COMP_WORDS[1]} == "topic" || \${COMP_WORDS[1]} == "topics" ]] ; then
191
+ if [[ \${COMP_CWORD} == 2 ]] ; then
192
+ opts="list create get update delete"
193
+ COMPREPLY=( \$(compgen -W "\${opts}" -- \${cur}) )
194
+ return 0
195
+ fi
196
+ fi
197
+ }
198
+
199
+ complete -F _lanonasis_completion lanonasis onasis memory maas
200
+ `;
201
+ }
202
+ generateZshCompletion() {
203
+ return `
204
+ #compdef lanonasis onasis memory maas
205
+
206
+ _lanonasis() {
207
+ local context state line
208
+ typeset -A opt_args
209
+
210
+ _arguments -C \\
211
+ '1: :_lanonasis_commands' \\
212
+ '*::arg:->args'
213
+
214
+ case $state in
215
+ args)
216
+ case $words[1] in
217
+ memory|mem)
218
+ _lanonasis_memory
219
+ ;;
220
+ topic|topics)
221
+ _lanonasis_topic
222
+ ;;
223
+ auth)
224
+ _arguments \\
225
+ '1:(login logout status)'
226
+ ;;
227
+ esac
228
+ ;;
229
+ esac
230
+ }
231
+
232
+ _lanonasis_commands() {
233
+ local commands
234
+ commands=(
235
+ 'auth:Authentication commands'
236
+ 'memory:Memory management'
237
+ 'topic:Topic management'
238
+ 'config:Configuration'
239
+ 'mcp:MCP server management'
240
+ 'init:Initialize CLI'
241
+ 'docs:Open documentation'
242
+ 'help:Show help'
243
+ )
244
+ _describe 'commands' commands
245
+ }
246
+
247
+ _lanonasis_memory() {
248
+ local subcommands
249
+ subcommands=(
250
+ 'create:Create new memory'
251
+ 'search:Search memories'
252
+ 'list:List memories'
253
+ 'get:Get specific memory'
254
+ 'update:Update memory'
255
+ 'delete:Delete memory'
256
+ 'stats:Memory statistics'
257
+ )
258
+ _describe 'memory commands' subcommands
259
+ }
260
+
261
+ _lanonasis_topic() {
262
+ local subcommands
263
+ subcommands=(
264
+ 'list:List topics'
265
+ 'create:Create topic'
266
+ 'get:Get topic'
267
+ 'update:Update topic'
268
+ 'delete:Delete topic'
269
+ )
270
+ _describe 'topic commands' subcommands
271
+ }
272
+
273
+ _lanonasis
274
+ `;
275
+ }
276
+ }
@@ -16,6 +16,8 @@ export declare class CLIConfig {
16
16
  setApiUrl(url: string): Promise<void>;
17
17
  setToken(token: string): Promise<void>;
18
18
  getToken(): string | undefined;
19
+ setApiKey(apiKey: string): Promise<void>;
20
+ getApiKey(): string | undefined;
19
21
  getCurrentUser(): Promise<UserProfile | undefined>;
20
22
  isAuthenticated(): Promise<boolean>;
21
23
  logout(): Promise<void>;
@@ -39,7 +39,7 @@ export class CLIConfig {
39
39
  getApiUrl() {
40
40
  return process.env.MEMORY_API_URL ||
41
41
  this.config.apiUrl ||
42
- 'https://dashboard.lanonasis.com/api/v1';
42
+ 'http://localhost:3000/api/v1';
43
43
  }
44
44
  async setApiUrl(url) {
45
45
  this.config.apiUrl = url;
@@ -67,10 +67,22 @@ export class CLIConfig {
67
67
  getToken() {
68
68
  return this.config.token;
69
69
  }
70
+ async setApiKey(apiKey) {
71
+ this.config.apiKey = apiKey;
72
+ await this.save();
73
+ }
74
+ getApiKey() {
75
+ return this.config.apiKey || process.env.LANONASIS_API_KEY;
76
+ }
70
77
  async getCurrentUser() {
71
78
  return this.config.user;
72
79
  }
73
80
  async isAuthenticated() {
81
+ // Check for API key first
82
+ const apiKey = this.getApiKey();
83
+ if (apiKey)
84
+ return true;
85
+ // Then check for valid JWT token
74
86
  const token = this.getToken();
75
87
  if (!token)
76
88
  return false;
@@ -85,6 +97,7 @@ export class CLIConfig {
85
97
  }
86
98
  async logout() {
87
99
  this.config.token = undefined;
100
+ this.config.apiKey = undefined;
88
101
  this.config.user = undefined;
89
102
  await this.save();
90
103
  }
@@ -120,7 +133,7 @@ export class CLIConfig {
120
133
  return this.config.mcpServerPath || path.join(__dirname, '../../../../onasis-gateway/mcp-server/server.js');
121
134
  }
122
135
  getMCPServerUrl() {
123
- return this.config.mcpServerUrl || 'https://dashboard.lanonasis.com';
136
+ return this.config.mcpServerUrl || 'https://api.lanonasis.com';
124
137
  }
125
138
  shouldUseRemoteMCP() {
126
139
  const preference = this.config.mcpPreference || 'auto';
@@ -2,5 +2,3 @@ export declare function formatOutput(data: unknown, format?: string): void;
2
2
  export declare function formatBytes(bytes: number): string;
3
3
  export declare function truncateText(text: string, maxLength: number): string;
4
4
  export declare function formatDuration(ms: number): string;
5
- export declare function formatDate(date: string | Date): string;
6
- export declare function formatTableData(data: unknown[]): string[][];
@@ -32,16 +32,3 @@ export function formatDuration(ms) {
32
32
  return `${(ms / 1000).toFixed(1)}s`;
33
33
  return `${(ms / 60000).toFixed(1)}m`;
34
34
  }
35
- export function formatDate(date) {
36
- const d = new Date(date);
37
- return d.toLocaleString();
38
- }
39
- export function formatTableData(data) {
40
- return data.map(item => {
41
- if (Array.isArray(item))
42
- return item.map(String);
43
- if (typeof item === 'object' && item !== null)
44
- return Object.values(item).map(String);
45
- return [String(item)];
46
- });
47
- }
@@ -2,70 +2,27 @@ interface MCPConnectionOptions {
2
2
  serverPath?: string;
3
3
  serverUrl?: string;
4
4
  useRemote?: boolean;
5
- useWebSocket?: boolean;
6
- connectionMode?: 'local' | 'remote' | 'websocket';
7
- }
8
- /**
9
- * Interface for MCP tool arguments
10
- */
11
- interface MCPToolArgs {
12
- [key: string]: unknown;
13
- }
14
- /**
15
- * Interface for MCP tool response
16
- */
17
- export interface MCPToolResponse {
18
- result?: unknown;
19
- error?: {
20
- code: number;
21
- message: string;
22
- };
23
- id?: string;
24
- title?: string;
25
- memory_type?: string;
26
- length?: number;
27
- forEach?: (callback: (item: any, index: number) => void) => void;
28
- code?: number;
29
- message?: string;
30
- response?: any;
31
- }
32
- /**
33
- * Interface for MCP WebSocket messages
34
- */
35
- export interface MCPWebSocketMessage {
36
- id: number;
37
- method?: string;
38
- params?: Record<string, unknown>;
39
- result?: Record<string, unknown>;
40
- error?: {
41
- code: number;
42
- message: string;
43
- data?: unknown;
44
- };
5
+ mode?: 'local' | 'remote' | 'websocket';
45
6
  }
46
7
  export declare class MCPClient {
47
8
  private client;
48
9
  private config;
49
10
  private isConnected;
50
11
  private sseConnection;
51
- private wsConnection;
12
+ private wsClient;
52
13
  constructor();
53
14
  /**
54
15
  * Connect to MCP server (local or remote)
55
16
  */
56
17
  connect(options?: MCPConnectionOptions): Promise<boolean>;
57
18
  /**
58
- * Initialize SSE connection for real-time updates
59
- */
60
- private initializeSSE;
61
- /**
62
- * Initialize WebSocket connection for enterprise MCP server
19
+ * Initialize WebSocket MCP connection for enterprise users
63
20
  */
64
21
  private initializeWebSocket;
65
22
  /**
66
- * Send a message over the WebSocket connection
23
+ * Initialize SSE connection for real-time updates
67
24
  */
68
- private sendWebSocketMessage;
25
+ private initializeSSE;
69
26
  /**
70
27
  * Disconnect from MCP server
71
28
  */
@@ -73,7 +30,7 @@ export declare class MCPClient {
73
30
  /**
74
31
  * Call an MCP tool
75
32
  */
76
- callTool(toolName: string, args: MCPToolArgs): Promise<MCPToolResponse>;
33
+ callTool(toolName: string, args: any): Promise<any>;
77
34
  /**
78
35
  * Call remote tool via REST API with MCP interface
79
36
  */