@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.
Files changed (148) hide show
  1. package/.env.example +13 -0
  2. package/.eslintrc.js +24 -0
  3. package/.github/ISSUE_TEMPLATE/phase-1-foundation.md +1078 -0
  4. package/.github/workflows/publish.yml +277 -0
  5. package/.github/workflows/test-app-token.yml +54 -0
  6. package/.npmrc.backup +3 -0
  7. package/.npmrc.example +6 -0
  8. package/.prettierignore +4 -0
  9. package/.prettierrc +8 -0
  10. package/CHANGELOG.md +138 -0
  11. package/PLATFORM_TESTING.md +243 -0
  12. package/README.md +986 -0
  13. package/RELEASE.md +428 -0
  14. package/RELEASE_READINESS.md +253 -0
  15. package/USAGE.md +1373 -0
  16. package/bin/mx.js +2 -0
  17. package/dist/commands/apikeys.d.ts +7 -0
  18. package/dist/commands/apikeys.d.ts.map +1 -0
  19. package/dist/commands/apikeys.js +133 -0
  20. package/dist/commands/apikeys.js.map +1 -0
  21. package/dist/commands/artifacts.d.ts +7 -0
  22. package/dist/commands/artifacts.d.ts.map +1 -0
  23. package/dist/commands/artifacts.js +277 -0
  24. package/dist/commands/artifacts.js.map +1 -0
  25. package/dist/commands/auth.d.ts +7 -0
  26. package/dist/commands/auth.d.ts.map +1 -0
  27. package/dist/commands/auth.js +119 -0
  28. package/dist/commands/auth.js.map +1 -0
  29. package/dist/commands/communities.d.ts +7 -0
  30. package/dist/commands/communities.d.ts.map +1 -0
  31. package/dist/commands/communities.js +137 -0
  32. package/dist/commands/communities.js.map +1 -0
  33. package/dist/commands/config.d.ts +7 -0
  34. package/dist/commands/config.d.ts.map +1 -0
  35. package/dist/commands/config.js +138 -0
  36. package/dist/commands/config.js.map +1 -0
  37. package/dist/commands/conversations.d.ts +7 -0
  38. package/dist/commands/conversations.d.ts.map +1 -0
  39. package/dist/commands/conversations.js +160 -0
  40. package/dist/commands/conversations.js.map +1 -0
  41. package/dist/commands/facts.d.ts +7 -0
  42. package/dist/commands/facts.d.ts.map +1 -0
  43. package/dist/commands/facts.js +298 -0
  44. package/dist/commands/facts.js.map +1 -0
  45. package/dist/commands/graphrag.d.ts +7 -0
  46. package/dist/commands/graphrag.d.ts.map +1 -0
  47. package/dist/commands/graphrag.js +139 -0
  48. package/dist/commands/graphrag.js.map +1 -0
  49. package/dist/commands/memories.d.ts +7 -0
  50. package/dist/commands/memories.d.ts.map +1 -0
  51. package/dist/commands/memories.js +304 -0
  52. package/dist/commands/memories.js.map +1 -0
  53. package/dist/commands/patterns.d.ts +7 -0
  54. package/dist/commands/patterns.d.ts.map +1 -0
  55. package/dist/commands/patterns.js +227 -0
  56. package/dist/commands/patterns.js.map +1 -0
  57. package/dist/commands/system.d.ts +7 -0
  58. package/dist/commands/system.d.ts.map +1 -0
  59. package/dist/commands/system.js +97 -0
  60. package/dist/commands/system.js.map +1 -0
  61. package/dist/commands/topics.d.ts +7 -0
  62. package/dist/commands/topics.d.ts.map +1 -0
  63. package/dist/commands/topics.js +314 -0
  64. package/dist/commands/topics.js.map +1 -0
  65. package/dist/index.d.ts +3 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +44 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/lib/api-client.d.ts +29 -0
  70. package/dist/lib/api-client.d.ts.map +1 -0
  71. package/dist/lib/api-client.js +64 -0
  72. package/dist/lib/api-client.js.map +1 -0
  73. package/dist/lib/auth.d.ts +10 -0
  74. package/dist/lib/auth.d.ts.map +1 -0
  75. package/dist/lib/auth.js +47 -0
  76. package/dist/lib/auth.js.map +1 -0
  77. package/dist/lib/config.d.ts +19 -0
  78. package/dist/lib/config.d.ts.map +1 -0
  79. package/dist/lib/config.js +59 -0
  80. package/dist/lib/config.js.map +1 -0
  81. package/dist/lib/errors.d.ts +7 -0
  82. package/dist/lib/errors.d.ts.map +1 -0
  83. package/dist/lib/errors.js +133 -0
  84. package/dist/lib/errors.js.map +1 -0
  85. package/dist/lib/formatters.d.ts +12 -0
  86. package/dist/lib/formatters.d.ts.map +1 -0
  87. package/dist/lib/formatters.js +103 -0
  88. package/dist/lib/formatters.js.map +1 -0
  89. package/dist/lib/spinner.d.ts +54 -0
  90. package/dist/lib/spinner.d.ts.map +1 -0
  91. package/dist/lib/spinner.js +108 -0
  92. package/dist/lib/spinner.js.map +1 -0
  93. package/dist/lib/validators.d.ts +92 -0
  94. package/dist/lib/validators.d.ts.map +1 -0
  95. package/dist/lib/validators.js +257 -0
  96. package/dist/lib/validators.js.map +1 -0
  97. package/dist/types/index.d.ts +13 -0
  98. package/dist/types/index.d.ts.map +1 -0
  99. package/dist/types/index.js +3 -0
  100. package/dist/types/index.js.map +1 -0
  101. package/docs/README.md +219 -0
  102. package/docs/code-generation-strategy.md +560 -0
  103. package/docs/prd.md +748 -0
  104. package/docs/sync-strategy.md +533 -0
  105. package/jest.config.js +30 -0
  106. package/package.json +67 -0
  107. package/scripts/install-deps.sh +38 -0
  108. package/src/commands/apikeys.ts +144 -0
  109. package/src/commands/artifacts.ts +296 -0
  110. package/src/commands/auth.ts +122 -0
  111. package/src/commands/communities.ts +153 -0
  112. package/src/commands/config.ts +144 -0
  113. package/src/commands/conversations.ts +176 -0
  114. package/src/commands/facts.ts +320 -0
  115. package/src/commands/graphrag.ts +149 -0
  116. package/src/commands/memories.ts +332 -0
  117. package/src/commands/patterns.ts +251 -0
  118. package/src/commands/system.ts +102 -0
  119. package/src/commands/topics.ts +354 -0
  120. package/src/index.ts +43 -0
  121. package/src/lib/api-client.ts +68 -0
  122. package/src/lib/auth.ts +42 -0
  123. package/src/lib/config.ts +68 -0
  124. package/src/lib/errors.ts +143 -0
  125. package/src/lib/formatters.ts +123 -0
  126. package/src/lib/spinner.ts +113 -0
  127. package/src/lib/validators.ts +302 -0
  128. package/src/types/index.ts +17 -0
  129. package/tests/__mocks__/chalk.ts +16 -0
  130. package/tests/__mocks__/cli-table3.ts +37 -0
  131. package/tests/__mocks__/configstore.ts +38 -0
  132. package/tests/commands/apikeys.test.ts +179 -0
  133. package/tests/commands/artifacts.test.ts +194 -0
  134. package/tests/commands/auth.test.ts +120 -0
  135. package/tests/commands/communities.test.ts +154 -0
  136. package/tests/commands/config.test.ts +154 -0
  137. package/tests/commands/conversations.test.ts +136 -0
  138. package/tests/commands/facts.test.ts +210 -0
  139. package/tests/commands/graphrag.test.ts +194 -0
  140. package/tests/commands/memories.test.ts +215 -0
  141. package/tests/commands/patterns.test.ts +201 -0
  142. package/tests/commands/system.test.ts +172 -0
  143. package/tests/commands/topics.test.ts +274 -0
  144. package/tests/lib/auth.test.ts +77 -0
  145. package/tests/lib/config.test.ts +50 -0
  146. package/tests/lib/errors.test.ts +126 -0
  147. package/tests/lib/formatters.test.ts +87 -0
  148. 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
+ }