@memnexus-ai/cli 0.1.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.
- package/.env.example +13 -0
- package/.eslintrc.js +24 -0
- package/.github/ISSUE_TEMPLATE/phase-1-foundation.md +1078 -0
- package/.github/workflows/publish.yml +277 -0
- package/.github/workflows/test-app-token.yml +54 -0
- package/.npmrc.backup +3 -0
- package/.npmrc.example +6 -0
- package/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/CHANGELOG.md +138 -0
- package/PLATFORM_TESTING.md +243 -0
- package/README.md +986 -0
- package/RELEASE.md +428 -0
- package/RELEASE_READINESS.md +253 -0
- package/USAGE.md +1373 -0
- package/bin/mx.js +2 -0
- package/dist/commands/apikeys.d.ts +7 -0
- package/dist/commands/apikeys.d.ts.map +1 -0
- package/dist/commands/apikeys.js +133 -0
- package/dist/commands/apikeys.js.map +1 -0
- package/dist/commands/artifacts.d.ts +7 -0
- package/dist/commands/artifacts.d.ts.map +1 -0
- package/dist/commands/artifacts.js +277 -0
- package/dist/commands/artifacts.js.map +1 -0
- package/dist/commands/auth.d.ts +7 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +119 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/communities.d.ts +7 -0
- package/dist/commands/communities.d.ts.map +1 -0
- package/dist/commands/communities.js +137 -0
- package/dist/commands/communities.js.map +1 -0
- package/dist/commands/config.d.ts +7 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +138 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/conversations.d.ts +7 -0
- package/dist/commands/conversations.d.ts.map +1 -0
- package/dist/commands/conversations.js +160 -0
- package/dist/commands/conversations.js.map +1 -0
- package/dist/commands/facts.d.ts +7 -0
- package/dist/commands/facts.d.ts.map +1 -0
- package/dist/commands/facts.js +298 -0
- package/dist/commands/facts.js.map +1 -0
- package/dist/commands/graphrag.d.ts +7 -0
- package/dist/commands/graphrag.d.ts.map +1 -0
- package/dist/commands/graphrag.js +139 -0
- package/dist/commands/graphrag.js.map +1 -0
- package/dist/commands/memories.d.ts +7 -0
- package/dist/commands/memories.d.ts.map +1 -0
- package/dist/commands/memories.js +304 -0
- package/dist/commands/memories.js.map +1 -0
- package/dist/commands/patterns.d.ts +7 -0
- package/dist/commands/patterns.d.ts.map +1 -0
- package/dist/commands/patterns.js +227 -0
- package/dist/commands/patterns.js.map +1 -0
- package/dist/commands/system.d.ts +7 -0
- package/dist/commands/system.d.ts.map +1 -0
- package/dist/commands/system.js +97 -0
- package/dist/commands/system.js.map +1 -0
- package/dist/commands/topics.d.ts +7 -0
- package/dist/commands/topics.d.ts.map +1 -0
- package/dist/commands/topics.js +314 -0
- package/dist/commands/topics.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +29 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +64 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/auth.d.ts +10 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +47 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/config.d.ts +19 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +59 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/errors.d.ts +7 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +133 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/formatters.d.ts +12 -0
- package/dist/lib/formatters.d.ts.map +1 -0
- package/dist/lib/formatters.js +103 -0
- package/dist/lib/formatters.js.map +1 -0
- package/dist/lib/spinner.d.ts +54 -0
- package/dist/lib/spinner.d.ts.map +1 -0
- package/dist/lib/spinner.js +108 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/validators.d.ts +92 -0
- package/dist/lib/validators.d.ts.map +1 -0
- package/dist/lib/validators.js +257 -0
- package/dist/lib/validators.js.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/docs/README.md +219 -0
- package/docs/code-generation-strategy.md +560 -0
- package/docs/prd.md +748 -0
- package/docs/sync-strategy.md +533 -0
- package/jest.config.js +30 -0
- package/package.json +67 -0
- package/scripts/install-deps.sh +38 -0
- package/src/commands/apikeys.ts +144 -0
- package/src/commands/artifacts.ts +296 -0
- package/src/commands/auth.ts +122 -0
- package/src/commands/communities.ts +153 -0
- package/src/commands/config.ts +144 -0
- package/src/commands/conversations.ts +176 -0
- package/src/commands/facts.ts +320 -0
- package/src/commands/graphrag.ts +149 -0
- package/src/commands/memories.ts +332 -0
- package/src/commands/patterns.ts +251 -0
- package/src/commands/system.ts +102 -0
- package/src/commands/topics.ts +354 -0
- package/src/index.ts +43 -0
- package/src/lib/api-client.ts +68 -0
- package/src/lib/auth.ts +42 -0
- package/src/lib/config.ts +68 -0
- package/src/lib/errors.ts +143 -0
- package/src/lib/formatters.ts +123 -0
- package/src/lib/spinner.ts +113 -0
- package/src/lib/validators.ts +302 -0
- package/src/types/index.ts +17 -0
- package/tests/__mocks__/chalk.ts +16 -0
- package/tests/__mocks__/cli-table3.ts +37 -0
- package/tests/__mocks__/configstore.ts +38 -0
- package/tests/commands/apikeys.test.ts +179 -0
- package/tests/commands/artifacts.test.ts +194 -0
- package/tests/commands/auth.test.ts +120 -0
- package/tests/commands/communities.test.ts +154 -0
- package/tests/commands/config.test.ts +154 -0
- package/tests/commands/conversations.test.ts +136 -0
- package/tests/commands/facts.test.ts +210 -0
- package/tests/commands/graphrag.test.ts +194 -0
- package/tests/commands/memories.test.ts +215 -0
- package/tests/commands/patterns.test.ts +201 -0
- package/tests/commands/system.test.ts +172 -0
- package/tests/commands/topics.test.ts +274 -0
- package/tests/lib/auth.test.ts +77 -0
- package/tests/lib/config.test.ts +50 -0
- package/tests/lib/errors.test.ts +126 -0
- package/tests/lib/formatters.test.ts +87 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import {
|
|
5
|
+
listMemories,
|
|
6
|
+
getMemoryById,
|
|
7
|
+
createMemory,
|
|
8
|
+
updateMemory,
|
|
9
|
+
deleteMemory,
|
|
10
|
+
searchMemories,
|
|
11
|
+
} from '@memnexus-ai/mx-typescript-sdk';
|
|
12
|
+
import { getApiOptions } from '../lib/api-client';
|
|
13
|
+
import { handleError } from '../lib/errors';
|
|
14
|
+
import { printOutput } from '../lib/formatters';
|
|
15
|
+
import { createSpinner } from '../lib/spinner';
|
|
16
|
+
import { OutputFormat } from '../types';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Register memory management commands
|
|
20
|
+
* @param program - Commander program instance
|
|
21
|
+
*/
|
|
22
|
+
export function registerMemoriesCommands(program: Command): void {
|
|
23
|
+
const memories = program.command('memories').description('Manage memories');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* mx memories list [options]
|
|
27
|
+
* List memories with pagination
|
|
28
|
+
*/
|
|
29
|
+
memories
|
|
30
|
+
.command('list')
|
|
31
|
+
.description('List memories')
|
|
32
|
+
.option('--page <number>', 'Page number', '0')
|
|
33
|
+
.option('--limit <number>', 'Results per page', '20')
|
|
34
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
35
|
+
.action(async (options) => {
|
|
36
|
+
try {
|
|
37
|
+
const page = parseInt(options.page, 10);
|
|
38
|
+
const limit = parseInt(options.limit, 10);
|
|
39
|
+
const offset = page * limit;
|
|
40
|
+
|
|
41
|
+
const spinner = createSpinner('Fetching memories...', options.format).start();
|
|
42
|
+
|
|
43
|
+
const result = await listMemories({
|
|
44
|
+
...getApiOptions(),
|
|
45
|
+
query: { limit, offset },
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
spinner.succeed(`Found ${result.data?.data?.length || 0} memories`);
|
|
49
|
+
|
|
50
|
+
// Format for table display
|
|
51
|
+
if (options.format === 'table' || !options.format) {
|
|
52
|
+
const tableData =
|
|
53
|
+
result.data?.data?.map((m: any) => ({
|
|
54
|
+
id: m.id,
|
|
55
|
+
content: m.content?.substring(0, 50) + (m.content?.length > 50 ? '...' : ''),
|
|
56
|
+
memoryType: m.memoryType || 'N/A',
|
|
57
|
+
createdAt: new Date(m.createdAt).toLocaleDateString(),
|
|
58
|
+
})) || [];
|
|
59
|
+
|
|
60
|
+
printOutput(tableData, options.format as OutputFormat, {
|
|
61
|
+
columns: ['id', 'content', 'memoryType', 'createdAt'],
|
|
62
|
+
maxColumnWidth: 30,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const pagination = result.data?.pagination;
|
|
66
|
+
if (pagination) {
|
|
67
|
+
console.log(
|
|
68
|
+
chalk.gray(
|
|
69
|
+
`\nShowing ${pagination.offset + 1}-${
|
|
70
|
+
pagination.offset + (result.data?.data?.length || 0)
|
|
71
|
+
} (Page ${page + 1})`
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
printOutput(result.data, options.format as OutputFormat);
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
handleError(error);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* mx memories get <id>
|
|
85
|
+
* Get a specific memory by ID
|
|
86
|
+
*/
|
|
87
|
+
memories
|
|
88
|
+
.command('get <id>')
|
|
89
|
+
.description('Get a specific memory')
|
|
90
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
91
|
+
.action(async (id: string, options) => {
|
|
92
|
+
try {
|
|
93
|
+
const result = await getMemoryById({
|
|
94
|
+
...getApiOptions(),
|
|
95
|
+
path: { id },
|
|
96
|
+
});
|
|
97
|
+
printOutput(result.data, options.format as OutputFormat);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
handleError(error);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* mx memories create [options]
|
|
105
|
+
* Create a new memory
|
|
106
|
+
*/
|
|
107
|
+
memories
|
|
108
|
+
.command('create')
|
|
109
|
+
.description('Create a new memory')
|
|
110
|
+
.option('--content <text>', 'Memory content')
|
|
111
|
+
.option('--memory-type <type>', 'Memory type (episodic|semantic|procedural)')
|
|
112
|
+
.option('--context <context>', 'Context identifier')
|
|
113
|
+
.option('--topics <topics>', 'Comma-separated topics')
|
|
114
|
+
.option('--importance <number>', 'Importance score (0-1)')
|
|
115
|
+
.option('--interactive', 'Interactive mode')
|
|
116
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
117
|
+
.action(async (options) => {
|
|
118
|
+
try {
|
|
119
|
+
let memoryData: any = {};
|
|
120
|
+
|
|
121
|
+
if (options.interactive || !options.content) {
|
|
122
|
+
// Interactive mode
|
|
123
|
+
const answers = await inquirer.prompt([
|
|
124
|
+
{
|
|
125
|
+
type: 'input',
|
|
126
|
+
name: 'content',
|
|
127
|
+
message: 'Memory content:',
|
|
128
|
+
default: options.content,
|
|
129
|
+
validate: (input: string) => input.trim().length > 0 || 'Content is required',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
type: 'list',
|
|
133
|
+
name: 'memoryType',
|
|
134
|
+
message: 'Memory type:',
|
|
135
|
+
choices: ['episodic', 'semantic', 'procedural'],
|
|
136
|
+
default: options.memoryType || 'episodic',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
type: 'input',
|
|
140
|
+
name: 'context',
|
|
141
|
+
message: 'Context (optional):',
|
|
142
|
+
default: options.context,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'input',
|
|
146
|
+
name: 'topics',
|
|
147
|
+
message: 'Topics (comma-separated, optional):',
|
|
148
|
+
default: options.topics,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
type: 'number',
|
|
152
|
+
name: 'importance',
|
|
153
|
+
message: 'Importance (0-1, optional):',
|
|
154
|
+
default: options.importance ? parseFloat(options.importance) : undefined,
|
|
155
|
+
},
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
memoryData = {
|
|
159
|
+
content: answers.content,
|
|
160
|
+
memoryType: answers.memoryType,
|
|
161
|
+
context: answers.context || undefined,
|
|
162
|
+
topics: answers.topics
|
|
163
|
+
? answers.topics.split(',').map((t: string) => t.trim())
|
|
164
|
+
: undefined,
|
|
165
|
+
importance: answers.importance || undefined,
|
|
166
|
+
};
|
|
167
|
+
} else {
|
|
168
|
+
// Direct mode
|
|
169
|
+
memoryData = {
|
|
170
|
+
content: options.content,
|
|
171
|
+
memoryType: options.memoryType || 'episodic',
|
|
172
|
+
context: options.context,
|
|
173
|
+
topics: options.topics
|
|
174
|
+
? options.topics.split(',').map((t: string) => t.trim())
|
|
175
|
+
: undefined,
|
|
176
|
+
importance: options.importance ? parseFloat(options.importance) : undefined,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const spinner = createSpinner('Creating memory...', options.format).start();
|
|
181
|
+
|
|
182
|
+
const result = await createMemory({
|
|
183
|
+
...getApiOptions(),
|
|
184
|
+
body: memoryData,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const memory = result.data?.data;
|
|
188
|
+
spinner.succeed(`Memory created with ID: ${memory?.id}`);
|
|
189
|
+
printOutput(memory, options.format as OutputFormat);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
handleError(error);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* mx memories update <id> [options]
|
|
197
|
+
* Update an existing memory
|
|
198
|
+
*/
|
|
199
|
+
memories
|
|
200
|
+
.command('update <id>')
|
|
201
|
+
.description('Update an existing memory')
|
|
202
|
+
.option('--content <text>', 'Updated content')
|
|
203
|
+
.option('--memory-type <type>', 'Updated memory type')
|
|
204
|
+
.option('--context <context>', 'Updated context')
|
|
205
|
+
.option('--topics <topics>', 'Updated topics (comma-separated)')
|
|
206
|
+
.option('--importance <number>', 'Updated importance (0-1)')
|
|
207
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
208
|
+
.action(async (id: string, options) => {
|
|
209
|
+
try {
|
|
210
|
+
const updates: any = {};
|
|
211
|
+
|
|
212
|
+
if (options.content) updates.content = options.content;
|
|
213
|
+
if (options.memoryType) updates.memoryType = options.memoryType;
|
|
214
|
+
if (options.context) updates.context = options.context;
|
|
215
|
+
if (options.topics) updates.topics = options.topics.split(',').map((t: string) => t.trim());
|
|
216
|
+
if (options.importance) updates.importance = parseFloat(options.importance);
|
|
217
|
+
|
|
218
|
+
if (Object.keys(updates).length === 0) {
|
|
219
|
+
console.log(chalk.yellow('No updates provided. Use --help to see available options.'));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const spinner = createSpinner('Updating memory...', options.format).start();
|
|
224
|
+
|
|
225
|
+
const result = await updateMemory({
|
|
226
|
+
...getApiOptions(),
|
|
227
|
+
path: { id },
|
|
228
|
+
body: updates,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const memory = result.data?.data;
|
|
232
|
+
spinner.succeed(`Memory ${id} updated successfully`);
|
|
233
|
+
printOutput(memory, options.format as OutputFormat);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
handleError(error);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* mx memories delete <id>
|
|
241
|
+
* Delete a memory
|
|
242
|
+
*/
|
|
243
|
+
memories
|
|
244
|
+
.command('delete <id>')
|
|
245
|
+
.description('Delete a memory')
|
|
246
|
+
.option('--force', 'Skip confirmation prompt')
|
|
247
|
+
.action(async (id: string, options) => {
|
|
248
|
+
try {
|
|
249
|
+
if (!options.force) {
|
|
250
|
+
const answers = await inquirer.prompt([
|
|
251
|
+
{
|
|
252
|
+
type: 'confirm',
|
|
253
|
+
name: 'confirm',
|
|
254
|
+
message: `Are you sure you want to delete memory ${id}?`,
|
|
255
|
+
default: false,
|
|
256
|
+
},
|
|
257
|
+
]);
|
|
258
|
+
|
|
259
|
+
if (!answers.confirm) {
|
|
260
|
+
console.log(chalk.yellow('Delete cancelled'));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const spinner = createSpinner('Deleting memory...', 'table').start();
|
|
266
|
+
|
|
267
|
+
await deleteMemory({
|
|
268
|
+
...getApiOptions(),
|
|
269
|
+
path: { id },
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
spinner.succeed(`Memory ${id} deleted successfully`);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
handleError(error);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* mx memories search [options]
|
|
280
|
+
* Search memories
|
|
281
|
+
*/
|
|
282
|
+
memories
|
|
283
|
+
.command('search')
|
|
284
|
+
.description('Search memories')
|
|
285
|
+
.option('--query <text>', 'Search query')
|
|
286
|
+
.option('--limit <number>', 'Maximum results', '20')
|
|
287
|
+
.option('--mode <mode>', 'Search mode (unified|content|facts)', 'unified')
|
|
288
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
289
|
+
.action(async (options) => {
|
|
290
|
+
try {
|
|
291
|
+
if (!options.query) {
|
|
292
|
+
console.log(chalk.red('Error: --query is required'));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const spinner = createSpinner('Searching memories...', options.format).start();
|
|
297
|
+
|
|
298
|
+
const result = await searchMemories({
|
|
299
|
+
...getApiOptions(),
|
|
300
|
+
body: {
|
|
301
|
+
query: options.query,
|
|
302
|
+
limit: parseInt(options.limit, 10),
|
|
303
|
+
mode: options.mode as 'unified' | 'content' | 'facts',
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const searchData = result.data;
|
|
308
|
+
spinner.succeed(`Found ${searchData?.data?.length || 0} results`);
|
|
309
|
+
|
|
310
|
+
// Format for table display
|
|
311
|
+
if (options.format === 'table' || !options.format) {
|
|
312
|
+
const tableData = (searchData?.data || []).map((memory: any) => ({
|
|
313
|
+
id: memory.id || 'N/A',
|
|
314
|
+
content: memory.content?.substring(0, 50) + (memory.content?.length > 50 ? '...' : ''),
|
|
315
|
+
memoryType: memory.memoryType || 'N/A',
|
|
316
|
+
createdAt: new Date(memory.createdAt).toLocaleDateString(),
|
|
317
|
+
}));
|
|
318
|
+
|
|
319
|
+
printOutput(tableData, options.format as OutputFormat, {
|
|
320
|
+
columns: ['id', 'content', 'memoryType', 'createdAt'],
|
|
321
|
+
maxColumnWidth: 30,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
console.log(chalk.gray(`\nFound ${searchData?.count || 0} results`));
|
|
325
|
+
} else {
|
|
326
|
+
printOutput(searchData, options.format as OutputFormat);
|
|
327
|
+
}
|
|
328
|
+
} catch (error) {
|
|
329
|
+
handleError(error);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import {
|
|
5
|
+
listPatterns,
|
|
6
|
+
compilePatterns,
|
|
7
|
+
updatePattern,
|
|
8
|
+
recordPatternFeedback,
|
|
9
|
+
getBehavioralState,
|
|
10
|
+
updateBehavioralState,
|
|
11
|
+
} from '@memnexus-ai/mx-typescript-sdk';
|
|
12
|
+
import { getApiOptions } from '../lib/api-client';
|
|
13
|
+
import { handleError } from '../lib/errors';
|
|
14
|
+
import { printOutput } from '../lib/formatters';
|
|
15
|
+
import { OutputFormat } from '../types';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Register pattern management commands
|
|
19
|
+
* @param program - Commander program instance
|
|
20
|
+
*/
|
|
21
|
+
export function registerPatternsCommands(program: Command): void {
|
|
22
|
+
const patterns = program.command('patterns').description('Manage behavioral patterns');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* mx patterns list [options]
|
|
26
|
+
* List patterns with pagination
|
|
27
|
+
*/
|
|
28
|
+
patterns
|
|
29
|
+
.command('list')
|
|
30
|
+
.description('List patterns')
|
|
31
|
+
.option('--page <number>', 'Page number', '0')
|
|
32
|
+
.option('--limit <number>', 'Results per page', '20')
|
|
33
|
+
.option('--context-id <id>', 'Filter by context')
|
|
34
|
+
.option('--type <type>', 'Pattern type (behavioral|temporal|semantic)')
|
|
35
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
36
|
+
.action(async (options) => {
|
|
37
|
+
try {
|
|
38
|
+
const page = parseInt(options.page, 10);
|
|
39
|
+
const limit = parseInt(options.limit, 10);
|
|
40
|
+
const offset = page * limit;
|
|
41
|
+
|
|
42
|
+
const result = await listPatterns({
|
|
43
|
+
...getApiOptions(),
|
|
44
|
+
query: {
|
|
45
|
+
limit,
|
|
46
|
+
offset,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const responseData = result.data as any;
|
|
51
|
+
if (options.format === 'table' || !options.format) {
|
|
52
|
+
const tableData = (responseData?.data || []).map((p: any) => ({
|
|
53
|
+
id: p.id,
|
|
54
|
+
type: p.type || 'N/A',
|
|
55
|
+
description:
|
|
56
|
+
p.description?.substring(0, 40) + (p.description?.length > 40 ? '...' : ''),
|
|
57
|
+
confidence: p.confidence || 0,
|
|
58
|
+
lastUpdated: new Date(p.lastUpdated).toLocaleDateString(),
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
printOutput(tableData, options.format as OutputFormat, {
|
|
62
|
+
columns: ['id', 'type', 'description', 'confidence', 'lastUpdated'],
|
|
63
|
+
maxColumnWidth: 20,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const pagination = responseData?.pagination;
|
|
67
|
+
if (pagination) {
|
|
68
|
+
console.log(
|
|
69
|
+
chalk.gray(
|
|
70
|
+
`\nShowing ${pagination.offset + 1}-${
|
|
71
|
+
pagination.offset + pagination.count
|
|
72
|
+
} (Page ${page + 1})`
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
printOutput(responseData, options.format as OutputFormat);
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
handleError(error);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* mx patterns compile [options]
|
|
86
|
+
* Compile patterns from memories
|
|
87
|
+
*/
|
|
88
|
+
patterns
|
|
89
|
+
.command('compile')
|
|
90
|
+
.description('Compile patterns from memories')
|
|
91
|
+
.option('--context-id <id>', 'Context ID (required)')
|
|
92
|
+
.option('--force', 'Force recompilation')
|
|
93
|
+
.option('--pattern-types <types>', 'Comma-separated pattern types to compile')
|
|
94
|
+
.action(async (options) => {
|
|
95
|
+
try {
|
|
96
|
+
if (!options.contextId) {
|
|
97
|
+
console.log(chalk.red('Error: --context-id is required'));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const spinner = ora('Compiling patterns...').start();
|
|
102
|
+
|
|
103
|
+
const result = await compilePatterns({
|
|
104
|
+
...getApiOptions(),
|
|
105
|
+
body: {
|
|
106
|
+
minOccurrences: 2,
|
|
107
|
+
timeWindow: '30d',
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
spinner.succeed('Patterns compiled successfully');
|
|
112
|
+
printOutput(result.data, 'json');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
handleError(error);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* mx patterns update <id> [options]
|
|
120
|
+
* Update a pattern
|
|
121
|
+
*/
|
|
122
|
+
patterns
|
|
123
|
+
.command('update <id>')
|
|
124
|
+
.description('Update a pattern')
|
|
125
|
+
.option('--description <text>', 'Updated description')
|
|
126
|
+
.option('--confidence <number>', 'Updated confidence (0-1)')
|
|
127
|
+
.option('--active <boolean>', 'Enable/disable pattern')
|
|
128
|
+
.option('--metadata <json>', 'Updated metadata')
|
|
129
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
130
|
+
.action(async (id: string, options) => {
|
|
131
|
+
try {
|
|
132
|
+
if (!options.description && !options.confidence && !options.active && !options.metadata) {
|
|
133
|
+
console.log(chalk.red('Error: At least one option is required'));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const updates: any = {};
|
|
138
|
+
|
|
139
|
+
if (options.description) updates.description = options.description;
|
|
140
|
+
if (options.confidence) updates.confidence = parseFloat(options.confidence);
|
|
141
|
+
if (options.active) updates.active = options.active === 'true';
|
|
142
|
+
if (options.metadata) updates.metadata = JSON.parse(options.metadata);
|
|
143
|
+
|
|
144
|
+
const result = await updatePattern({
|
|
145
|
+
...getApiOptions(),
|
|
146
|
+
path: { id },
|
|
147
|
+
body: updates,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
console.log(chalk.green('✓ Pattern updated successfully'));
|
|
151
|
+
printOutput(result.data, options.format as OutputFormat);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
handleError(error);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* mx patterns feedback [options]
|
|
159
|
+
* Record pattern feedback
|
|
160
|
+
*/
|
|
161
|
+
patterns
|
|
162
|
+
.command('feedback')
|
|
163
|
+
.description('Record pattern feedback')
|
|
164
|
+
.option('--pattern-id <id>', 'Pattern ID (required)')
|
|
165
|
+
.option('--feedback-type <type>', 'Feedback type (positive|negative|neutral) (required)')
|
|
166
|
+
.option('--comment <text>', 'Feedback comment')
|
|
167
|
+
.option('--context-id <id>', 'Context ID')
|
|
168
|
+
.action(async (options) => {
|
|
169
|
+
try {
|
|
170
|
+
if (!options.patternId || !options.feedbackType) {
|
|
171
|
+
console.log(chalk.red('Error: --pattern-id and --feedback-type are required'));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const spinner = ora('Recording feedback...').start();
|
|
176
|
+
|
|
177
|
+
await recordPatternFeedback({
|
|
178
|
+
...getApiOptions(),
|
|
179
|
+
body: {
|
|
180
|
+
patternId: options.patternId,
|
|
181
|
+
feedback: options.feedbackType,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
spinner.succeed('Feedback recorded successfully');
|
|
186
|
+
console.log(chalk.green('✓ Feedback recorded'));
|
|
187
|
+
} catch (error) {
|
|
188
|
+
handleError(error);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* mx patterns behavior-state [options]
|
|
194
|
+
* Get behavioral state
|
|
195
|
+
*/
|
|
196
|
+
patterns
|
|
197
|
+
.command('behavior-state')
|
|
198
|
+
.description('Get behavioral state')
|
|
199
|
+
.option('--context-id <id>', 'Context ID (required)')
|
|
200
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
201
|
+
.action(async (options) => {
|
|
202
|
+
try {
|
|
203
|
+
if (!options.contextId) {
|
|
204
|
+
console.log(chalk.red('Error: --context-id is required'));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const result = await getBehavioralState({
|
|
209
|
+
...getApiOptions(),
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
printOutput(result.data, options.format as OutputFormat);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
handleError(error);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* mx patterns set-behavior-state [options]
|
|
220
|
+
* Set behavioral state
|
|
221
|
+
*/
|
|
222
|
+
patterns
|
|
223
|
+
.command('set-behavior-state')
|
|
224
|
+
.description('Set behavioral state')
|
|
225
|
+
.option('--context-id <id>', 'Context ID (required)')
|
|
226
|
+
.option('--state <json>', 'Behavioral state JSON (required)')
|
|
227
|
+
.option('--merge', 'Merge with existing state instead of replacing')
|
|
228
|
+
.action(async (options) => {
|
|
229
|
+
try {
|
|
230
|
+
if (!options.contextId || !options.state) {
|
|
231
|
+
console.log(chalk.red('Error: --context-id and --state are required'));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const spinner = ora('Setting behavioral state...').start();
|
|
236
|
+
|
|
237
|
+
const state = JSON.parse(options.state);
|
|
238
|
+
await updateBehavioralState({
|
|
239
|
+
...getApiOptions(),
|
|
240
|
+
body: {
|
|
241
|
+
state,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
spinner.succeed('Behavioral state set successfully');
|
|
246
|
+
console.log(chalk.green('✓ State updated'));
|
|
247
|
+
} catch (error) {
|
|
248
|
+
handleError(error);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { getSystemHealth, getContextStatus, getFeatureFlags } from '@memnexus-ai/mx-typescript-sdk';
|
|
5
|
+
import { getApiOptions } from '../lib/api-client';
|
|
6
|
+
import { handleError } from '../lib/errors';
|
|
7
|
+
import { printOutput } from '../lib/formatters';
|
|
8
|
+
import { OutputFormat } from '../types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Register system management commands
|
|
12
|
+
* @param program - Commander program instance
|
|
13
|
+
*/
|
|
14
|
+
export function registerSystemCommands(program: Command): void {
|
|
15
|
+
const system = program.command('system').description('System health and statistics');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* mx system health
|
|
19
|
+
* Check system health status
|
|
20
|
+
*/
|
|
21
|
+
system
|
|
22
|
+
.command('health')
|
|
23
|
+
.description('Check system health')
|
|
24
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
25
|
+
.action(async (options) => {
|
|
26
|
+
try {
|
|
27
|
+
const spinner = ora('Checking system health...').start();
|
|
28
|
+
|
|
29
|
+
const result = await getSystemHealth({
|
|
30
|
+
...getApiOptions(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
spinner.succeed('Health check completed');
|
|
34
|
+
|
|
35
|
+
const healthData = result.data as any;
|
|
36
|
+
if (healthData) {
|
|
37
|
+
const status = healthData.status === 'healthy' ? chalk.green('✓') : chalk.red('✗');
|
|
38
|
+
console.log(`${status} Status: ${healthData.status}`);
|
|
39
|
+
|
|
40
|
+
if (healthData.components) {
|
|
41
|
+
console.log(chalk.gray('\nComponent Status:'));
|
|
42
|
+
Object.entries(healthData.components).forEach(([name, status]: [string, any]) => {
|
|
43
|
+
const icon = status.status === 'healthy' ? chalk.green('✓') : chalk.red('✗');
|
|
44
|
+
console.log(` ${icon} ${name}: ${status.status}`);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (options.format && options.format !== 'table') {
|
|
49
|
+
printOutput(healthData, options.format as OutputFormat);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
handleError(error);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* mx system status
|
|
59
|
+
* Get detailed system status
|
|
60
|
+
*/
|
|
61
|
+
system
|
|
62
|
+
.command('status')
|
|
63
|
+
.description('Get system status')
|
|
64
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
65
|
+
.action(async (options) => {
|
|
66
|
+
try {
|
|
67
|
+
const spinner = ora('Fetching system status...').start();
|
|
68
|
+
|
|
69
|
+
const result = await getContextStatus({
|
|
70
|
+
...getApiOptions(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
spinner.succeed('Status retrieved');
|
|
74
|
+
printOutput(result.data, options.format as OutputFormat);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
handleError(error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* mx system features
|
|
82
|
+
* Get feature flags
|
|
83
|
+
*/
|
|
84
|
+
system
|
|
85
|
+
.command('features')
|
|
86
|
+
.description('Get feature flags')
|
|
87
|
+
.option('--format <format>', 'Output format (json|table|yaml)')
|
|
88
|
+
.action(async (options) => {
|
|
89
|
+
try {
|
|
90
|
+
const spinner = ora('Fetching feature flags...').start();
|
|
91
|
+
|
|
92
|
+
const result = await getFeatureFlags({
|
|
93
|
+
...getApiOptions(),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
spinner.succeed('Feature flags retrieved');
|
|
97
|
+
printOutput(result.data, options.format as OutputFormat);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
handleError(error);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|