@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,153 @@
1
+ import { Command } from 'commander';
2
+ import inquirer from 'inquirer';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import {
6
+ listCommunities,
7
+ getCommunityById,
8
+ mergeCommunities,
9
+ } from '@memnexus-ai/mx-typescript-sdk';
10
+ import { getApiOptions } from '../lib/api-client';
11
+ import { handleError } from '../lib/errors';
12
+ import { printOutput } from '../lib/formatters';
13
+ import { OutputFormat } from '../types';
14
+
15
+ /**
16
+ * Register community management commands
17
+ * @param program - Commander program instance
18
+ */
19
+ export function registerCommunitiesCommands(program: Command): void {
20
+ const communities = program.command('communities').description('Manage topic communities');
21
+
22
+ /**
23
+ * mx communities list [options]
24
+ * List communities with pagination
25
+ */
26
+ communities
27
+ .command('list')
28
+ .description('List communities')
29
+ .option('--page <number>', 'Page number', '0')
30
+ .option('--limit <number>', 'Results per page', '20')
31
+ .option('--context-id <id>', 'Filter by context')
32
+ .option('--min-size <number>', 'Minimum community size')
33
+ .option('--format <format>', 'Output format (json|table|yaml)')
34
+ .action(async (options) => {
35
+ try {
36
+ const page = parseInt(options.page, 10);
37
+ const limit = parseInt(options.limit, 10);
38
+ const offset = page * limit;
39
+
40
+ const result = await listCommunities({
41
+ ...getApiOptions(),
42
+ query: {
43
+ limit,
44
+ offset,
45
+ },
46
+ });
47
+
48
+ const responseData = result.data as any;
49
+
50
+ if (options.format === 'table' || !options.format) {
51
+ const tableData = (responseData?.data || []).map((c: any) => ({
52
+ id: c.id,
53
+ name: c.name || 'N/A',
54
+ memberCount: c.memberCount || 0,
55
+ topicCount: c.topicCount || 0,
56
+ createdAt: new Date(c.createdAt).toLocaleDateString(),
57
+ }));
58
+
59
+ printOutput(tableData, options.format as OutputFormat, {
60
+ columns: ['id', 'name', 'memberCount', 'topicCount', 'createdAt'],
61
+ maxColumnWidth: 20,
62
+ });
63
+
64
+ const pagination = responseData?.pagination;
65
+ if (pagination) {
66
+ console.log(
67
+ chalk.gray(
68
+ `\nShowing ${pagination.offset + 1}-${
69
+ pagination.offset + (responseData?.data?.length || 0)
70
+ } (Page ${page + 1})`
71
+ )
72
+ );
73
+ }
74
+ } else {
75
+ printOutput(responseData, options.format as OutputFormat);
76
+ }
77
+ } catch (error) {
78
+ handleError(error);
79
+ }
80
+ });
81
+
82
+ /**
83
+ * mx communities get <id>
84
+ * Get a specific community by ID
85
+ */
86
+ communities
87
+ .command('get <id>')
88
+ .description('Get community details')
89
+ .option('--format <format>', 'Output format (json|table|yaml)')
90
+ .action(async (id: string, options) => {
91
+ try {
92
+ const result = await getCommunityById({
93
+ ...getApiOptions(),
94
+ path: { id },
95
+ });
96
+
97
+ printOutput(result.data, options.format as OutputFormat);
98
+ } catch (error) {
99
+ handleError(error);
100
+ }
101
+ });
102
+
103
+ /**
104
+ * mx communities merge [options]
105
+ * Merge two communities
106
+ */
107
+ communities
108
+ .command('merge')
109
+ .description('Merge two communities')
110
+ .option('--source-id <id>', 'Source community ID')
111
+ .option('--target-id <id>', 'Target community ID')
112
+ .option('--force', 'Skip confirmation')
113
+ .option('--format <format>', 'Output format (json|table|yaml)')
114
+ .action(async (options) => {
115
+ try {
116
+ if (!options.sourceId || !options.targetId) {
117
+ console.log(chalk.red('Error: --source-id and --target-id are required'));
118
+ return;
119
+ }
120
+
121
+ if (!options.force) {
122
+ const answer = await inquirer.prompt([
123
+ {
124
+ type: 'confirm',
125
+ name: 'confirm',
126
+ message: `Merge community ${options.sourceId} into ${options.targetId}?`,
127
+ default: false,
128
+ },
129
+ ]);
130
+
131
+ if (!answer.confirm) {
132
+ console.log(chalk.gray('Merge cancelled'));
133
+ return;
134
+ }
135
+ }
136
+
137
+ const spinner = ora('Merging communities...').start();
138
+
139
+ const result = await mergeCommunities({
140
+ ...getApiOptions(),
141
+ body: {
142
+ sourceCommunityId: options.sourceId,
143
+ targetCommunityId: options.targetId,
144
+ },
145
+ });
146
+
147
+ spinner.succeed('Communities merged successfully');
148
+ printOutput(result.data, options.format as OutputFormat);
149
+ } catch (error) {
150
+ handleError(error);
151
+ }
152
+ });
153
+ }
@@ -0,0 +1,144 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import Table from 'cli-table3';
4
+ import { config } from '../lib/config';
5
+ import { handleError, CLIError } from '../lib/errors';
6
+ import { CLIConfig } from '../types';
7
+
8
+ /**
9
+ * Register configuration commands
10
+ * @param program - Commander program instance
11
+ */
12
+ export function registerConfigCommands(program: Command): void {
13
+ const configCmd = program.command('config').description('Manage CLI configuration');
14
+
15
+ /**
16
+ * mx config get <key>
17
+ * Get a specific configuration value
18
+ */
19
+ configCmd
20
+ .command('get <key>')
21
+ .description('Get a configuration value')
22
+ .action(async (key: string) => {
23
+ try {
24
+ const validKeys: (keyof CLIConfig)[] = ['apiUrl', 'defaultFormat', 'defaultPageSize'];
25
+
26
+ if (!validKeys.includes(key as keyof CLIConfig)) {
27
+ throw new CLIError(`Invalid config key: ${key}. Valid keys are: ${validKeys.join(', ')}`);
28
+ }
29
+
30
+ const value = config.get(key as keyof CLIConfig);
31
+
32
+ if (value === undefined) {
33
+ console.log(chalk.gray('(not set)'));
34
+ } else {
35
+ console.log(value);
36
+ }
37
+ } catch (error) {
38
+ handleError(error);
39
+ }
40
+ });
41
+
42
+ /**
43
+ * mx config set <key> <value>
44
+ * Set a configuration value
45
+ */
46
+ configCmd
47
+ .command('set <key> <value>')
48
+ .description('Set a configuration value')
49
+ .action(async (key: string, value: string) => {
50
+ try {
51
+ // Validate key
52
+ const validKeys: (keyof CLIConfig)[] = ['apiUrl', 'defaultFormat', 'defaultPageSize'];
53
+
54
+ if (!validKeys.includes(key as keyof CLIConfig)) {
55
+ throw new CLIError(`Invalid config key: ${key}. Valid keys are: ${validKeys.join(', ')}`);
56
+ }
57
+
58
+ // Validate value based on key
59
+ if (key === 'apiUrl') {
60
+ try {
61
+ new URL(value);
62
+ } catch {
63
+ throw new CLIError('Invalid URL format');
64
+ }
65
+ } else if (key === 'defaultFormat') {
66
+ if (!['json', 'table', 'yaml'].includes(value)) {
67
+ throw new CLIError('Invalid format. Must be one of: json, table, yaml');
68
+ }
69
+ } else if (key === 'defaultPageSize') {
70
+ const num = parseInt(value, 10);
71
+ if (isNaN(num) || num < 1 || num > 100) {
72
+ throw new CLIError('Invalid page size. Must be a number between 1 and 100');
73
+ }
74
+ config.set(key, num);
75
+ console.log(chalk.green(`✓ ${key} set to ${num}`));
76
+ return;
77
+ }
78
+
79
+ config.set(key as keyof CLIConfig, value);
80
+ console.log(chalk.green(`✓ ${key} set to ${value}`));
81
+ } catch (error) {
82
+ handleError(error);
83
+ }
84
+ });
85
+
86
+ /**
87
+ * mx config list
88
+ * List all configuration values
89
+ */
90
+ configCmd
91
+ .command('list')
92
+ .description('List all configuration values')
93
+ .action(async () => {
94
+ try {
95
+ const allConfig = config.get() as CLIConfig;
96
+
97
+ const table = new Table({
98
+ head: [chalk.cyan('Key'), chalk.cyan('Value'), chalk.cyan('Source')],
99
+ colWidths: [25, 40, 20],
100
+ wordWrap: true,
101
+ });
102
+
103
+ // Check for environment variable overrides
104
+ const envOverrides = {
105
+ apiUrl: process.env.MX_API_URL,
106
+ defaultFormat: process.env.MX_OUTPUT_FORMAT,
107
+ };
108
+
109
+ table.push(
110
+ [
111
+ 'apiUrl',
112
+ envOverrides.apiUrl || allConfig.apiUrl,
113
+ envOverrides.apiUrl ? chalk.yellow('env') : 'config',
114
+ ],
115
+ [
116
+ 'defaultFormat',
117
+ envOverrides.defaultFormat || allConfig.defaultFormat,
118
+ envOverrides.defaultFormat ? chalk.yellow('env') : 'config',
119
+ ],
120
+ ['defaultPageSize', String(allConfig.defaultPageSize), 'config']
121
+ );
122
+
123
+ console.log(table.toString());
124
+ } catch (error) {
125
+ handleError(error);
126
+ }
127
+ });
128
+
129
+ /**
130
+ * mx config reset
131
+ * Reset configuration to defaults
132
+ */
133
+ configCmd
134
+ .command('reset')
135
+ .description('Reset configuration to defaults')
136
+ .action(async () => {
137
+ try {
138
+ config.reset();
139
+ console.log(chalk.green('✓ Configuration reset to defaults'));
140
+ } catch (error) {
141
+ handleError(error);
142
+ }
143
+ });
144
+ }
@@ -0,0 +1,176 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import {
4
+ listConversations,
5
+ searchConversations,
6
+ getConversationSummary,
7
+ getConversationTimeline,
8
+ findConversationsByTopic,
9
+ } from '@memnexus-ai/mx-typescript-sdk';
10
+ import { getApiOptions } from '../lib/api-client';
11
+ import { handleError } from '../lib/errors';
12
+ import { printOutput } from '../lib/formatters';
13
+ import { OutputFormat } from '../types';
14
+
15
+ /**
16
+ * Register conversation query commands
17
+ * @param program - Commander program instance
18
+ */
19
+ export function registerConversationsCommands(program: Command): void {
20
+ const conversations = program
21
+ .command('conversations')
22
+ .description('Query and manage conversations');
23
+
24
+ /**
25
+ * mx conversations list [options]
26
+ * List conversations with pagination
27
+ */
28
+ conversations
29
+ .command('list')
30
+ .description('List conversations')
31
+ .option('--page <number>', 'Page number', '0')
32
+ .option('--limit <number>', 'Results per page', '20')
33
+ .option('--format <format>', 'Output format (json|table|yaml)')
34
+ .action(async (options) => {
35
+ try {
36
+ const page = parseInt(options.page, 10);
37
+ const limit = parseInt(options.limit, 10);
38
+ const offset = page * limit;
39
+
40
+ const result = await listConversations({
41
+ ...getApiOptions(),
42
+ query: { limit, offset },
43
+ });
44
+
45
+ const responseData = result.data as any;
46
+
47
+ // Format for table display
48
+ if (options.format === 'table' || !options.format) {
49
+ const tableData = (responseData?.data || []).map((c: any) => ({
50
+ id: c.id,
51
+ title: c.title || c.id,
52
+ messageCount: c.messageCount || 0,
53
+ createdAt: new Date(c.createdAt).toLocaleDateString(),
54
+ }));
55
+
56
+ printOutput(tableData, options.format as OutputFormat, {
57
+ columns: ['id', 'title', 'messageCount', 'createdAt'],
58
+ maxColumnWidth: 30,
59
+ });
60
+
61
+ const pagination = responseData?.pagination;
62
+ if (pagination) {
63
+ console.log(
64
+ chalk.gray(
65
+ `\nShowing ${pagination.offset + 1}-${
66
+ pagination.offset + (responseData?.data?.length || 0)
67
+ } (Page ${page + 1})`
68
+ )
69
+ );
70
+ }
71
+ } else {
72
+ printOutput(responseData, options.format as OutputFormat);
73
+ }
74
+ } catch (error) {
75
+ handleError(error);
76
+ }
77
+ });
78
+
79
+ /**
80
+ * mx conversations summary <id>
81
+ * Get conversation summary
82
+ */
83
+ conversations
84
+ .command('summary <id>')
85
+ .description('Get conversation summary')
86
+ .option('--format <format>', 'Output format (json|table|yaml)')
87
+ .action(async (id: string, options) => {
88
+ try {
89
+ const result = await getConversationSummary({
90
+ ...getApiOptions(),
91
+ path: { conversationId: id },
92
+ });
93
+ printOutput(result.data, options.format as OutputFormat);
94
+ } catch (error) {
95
+ handleError(error);
96
+ }
97
+ });
98
+
99
+ /**
100
+ * mx conversations timeline <id>
101
+ * Get conversation timeline (chronological messages)
102
+ */
103
+ conversations
104
+ .command('timeline <id>')
105
+ .description('Get conversation timeline')
106
+ .option('--format <format>', 'Output format (json|table|yaml)')
107
+ .action(async (id: string, options) => {
108
+ try {
109
+ const result = await getConversationTimeline({
110
+ ...getApiOptions(),
111
+ path: { conversationId: id },
112
+ });
113
+ printOutput(result.data, options.format as OutputFormat);
114
+ } catch (error) {
115
+ handleError(error);
116
+ }
117
+ });
118
+
119
+ /**
120
+ * mx conversations search [options]
121
+ * Search conversations
122
+ */
123
+ conversations
124
+ .command('search')
125
+ .description('Search conversations')
126
+ .option('--query <text>', 'Search query')
127
+ .option('--limit <number>', 'Maximum results', '20')
128
+ .option('--format <format>', 'Output format (json|table|yaml)')
129
+ .action(async (options) => {
130
+ try {
131
+ if (!options.query) {
132
+ console.log(chalk.red('Error: --query is required'));
133
+ return;
134
+ }
135
+
136
+ const result = await searchConversations({
137
+ ...getApiOptions(),
138
+ body: {
139
+ query: options.query,
140
+ limit: parseInt(options.limit, 10),
141
+ },
142
+ });
143
+
144
+ printOutput(result.data, options.format as OutputFormat);
145
+ } catch (error) {
146
+ handleError(error);
147
+ }
148
+ });
149
+
150
+ /**
151
+ * mx conversations by-topic [options]
152
+ * Find conversations by topic
153
+ */
154
+ conversations
155
+ .command('by-topic')
156
+ .description('Find conversations by topic')
157
+ .option('--topic-id <id>', 'Topic ID')
158
+ .option('--format <format>', 'Output format (json|table|yaml)')
159
+ .action(async (options) => {
160
+ try {
161
+ if (!options.topicId) {
162
+ console.log(chalk.red('Error: --topic-id is required'));
163
+ return;
164
+ }
165
+
166
+ const result = await findConversationsByTopic({
167
+ ...getApiOptions(),
168
+ body: { topicId: options.topicId },
169
+ });
170
+
171
+ printOutput(result.data, options.format as OutputFormat);
172
+ } catch (error) {
173
+ handleError(error);
174
+ }
175
+ });
176
+ }