archyra 1.0.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/LICENSE +21 -0
- package/README.md +399 -0
- package/dist/index.css +820 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.js +11094 -0
- package/dist/index.mjs +11075 -0
- package/dist/mcp/cli.js +274 -0
- package/dist/mcp/server.js +25509 -0
- package/dist/styles.css +638 -0
- package/mcp/cli.ts +326 -0
- package/mcp/registry.ts +5835 -0
- package/mcp/server.ts +363 -0
- package/package.json +116 -0
package/mcp/cli.ts
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Archyra - MCP CLI
|
|
3
|
+
*
|
|
4
|
+
* Initialize MCP configuration for different AI coding tools.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx archyra init --client claude
|
|
8
|
+
* npx archyra init --client cursor
|
|
9
|
+
* npx archyra init --client windsurf
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import * as os from 'os';
|
|
15
|
+
import * as readline from 'readline';
|
|
16
|
+
import { spawn } from 'child_process';
|
|
17
|
+
|
|
18
|
+
const PACKAGE_NAME = 'archyra';
|
|
19
|
+
|
|
20
|
+
// Client configurations
|
|
21
|
+
const CLIENT_CONFIGS: Record<string, {
|
|
22
|
+
name: string;
|
|
23
|
+
configPaths: string[];
|
|
24
|
+
description: string;
|
|
25
|
+
}> = {
|
|
26
|
+
claude: {
|
|
27
|
+
name: 'Claude Code',
|
|
28
|
+
configPaths: [
|
|
29
|
+
path.join(os.homedir(), '.claude', 'claude_desktop_config.json'),
|
|
30
|
+
path.join(os.homedir(), '.mcp.json'),
|
|
31
|
+
],
|
|
32
|
+
description: 'Anthropic Claude Code CLI',
|
|
33
|
+
},
|
|
34
|
+
cursor: {
|
|
35
|
+
name: 'Cursor',
|
|
36
|
+
configPaths: [
|
|
37
|
+
path.join(process.cwd(), '.cursor', 'mcp.json'),
|
|
38
|
+
path.join(os.homedir(), '.cursor', 'mcp.json'),
|
|
39
|
+
],
|
|
40
|
+
description: 'Cursor AI Editor',
|
|
41
|
+
},
|
|
42
|
+
windsurf: {
|
|
43
|
+
name: 'Windsurf',
|
|
44
|
+
configPaths: [
|
|
45
|
+
path.join(os.homedir(), '.codeium', 'windsurf', 'mcp_config.json'),
|
|
46
|
+
],
|
|
47
|
+
description: 'Codeium Windsurf Editor',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Colors for terminal output
|
|
52
|
+
const colors = {
|
|
53
|
+
reset: '\x1b[0m',
|
|
54
|
+
bright: '\x1b[1m',
|
|
55
|
+
dim: '\x1b[2m',
|
|
56
|
+
green: '\x1b[32m',
|
|
57
|
+
yellow: '\x1b[33m',
|
|
58
|
+
blue: '\x1b[34m',
|
|
59
|
+
magenta: '\x1b[35m',
|
|
60
|
+
cyan: '\x1b[36m',
|
|
61
|
+
red: '\x1b[31m',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function log(message: string) {
|
|
65
|
+
console.log(message);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function success(message: string) {
|
|
69
|
+
console.log(`${colors.green}✓${colors.reset} ${message}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function info(message: string) {
|
|
73
|
+
console.log(`${colors.blue}ℹ${colors.reset} ${message}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function warn(message: string) {
|
|
77
|
+
console.log(`${colors.yellow}⚠${colors.reset} ${message}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function error(message: string) {
|
|
81
|
+
console.log(`${colors.red}✗${colors.reset} ${message}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function printBanner() {
|
|
85
|
+
console.log(`
|
|
86
|
+
${colors.magenta}╔═══════════════════════════════════════════════════╗
|
|
87
|
+
║ ║
|
|
88
|
+
║ ${colors.bright}Archyra${colors.reset}${colors.magenta} ║
|
|
89
|
+
║ ${colors.dim}MCP Server Configuration${colors.reset}${colors.magenta} ║
|
|
90
|
+
║ ║
|
|
91
|
+
╚═══════════════════════════════════════════════════╝${colors.reset}
|
|
92
|
+
`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getMcpConfig() {
|
|
96
|
+
// Use npx with explicit package name to run the server
|
|
97
|
+
// The @latest tag ensures we always get the current version
|
|
98
|
+
return {
|
|
99
|
+
command: 'npx',
|
|
100
|
+
args: ['-y', 'archyra@latest', 'serve'],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function findExistingConfig(configPaths: string[]): string | null {
|
|
105
|
+
for (const configPath of configPaths) {
|
|
106
|
+
if (fs.existsSync(configPath)) {
|
|
107
|
+
return configPath;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function ensureDirectoryExists(filePath: string) {
|
|
114
|
+
const dir = path.dirname(filePath);
|
|
115
|
+
if (!fs.existsSync(dir)) {
|
|
116
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function readJsonFile(filePath: string): Record<string, any> {
|
|
121
|
+
try {
|
|
122
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
123
|
+
return JSON.parse(content);
|
|
124
|
+
} catch {
|
|
125
|
+
return {};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function writeJsonFile(filePath: string, data: Record<string, any>) {
|
|
130
|
+
ensureDirectoryExists(filePath);
|
|
131
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function prompt(question: string): Promise<string> {
|
|
135
|
+
const rl = readline.createInterface({
|
|
136
|
+
input: process.stdin,
|
|
137
|
+
output: process.stdout,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return new Promise((resolve) => {
|
|
141
|
+
rl.question(question, (answer) => {
|
|
142
|
+
rl.close();
|
|
143
|
+
resolve(answer.trim());
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function selectClient(): Promise<string> {
|
|
149
|
+
log('\nSelect your AI coding tool:\n');
|
|
150
|
+
|
|
151
|
+
const clients = Object.entries(CLIENT_CONFIGS);
|
|
152
|
+
clients.forEach(([key, config], index) => {
|
|
153
|
+
log(` ${colors.cyan}${index + 1}${colors.reset}) ${config.name} ${colors.dim}(${config.description})${colors.reset}`);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
log('');
|
|
157
|
+
const answer = await prompt(`Enter choice (1-${clients.length}): `);
|
|
158
|
+
const index = parseInt(answer) - 1;
|
|
159
|
+
|
|
160
|
+
if (index >= 0 && index < clients.length) {
|
|
161
|
+
return clients[index][0];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
error('Invalid selection. Please try again.');
|
|
165
|
+
return selectClient();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function initMcp(clientKey: string) {
|
|
169
|
+
const client = CLIENT_CONFIGS[clientKey];
|
|
170
|
+
|
|
171
|
+
if (!client) {
|
|
172
|
+
error(`Unknown client: ${clientKey}`);
|
|
173
|
+
log(`\nSupported clients: ${Object.keys(CLIENT_CONFIGS).join(', ')}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
info(`Configuring MCP for ${colors.bright}${client.name}${colors.reset}...`);
|
|
178
|
+
log('');
|
|
179
|
+
|
|
180
|
+
// Find existing config or use first path
|
|
181
|
+
let configPath = findExistingConfig(client.configPaths);
|
|
182
|
+
|
|
183
|
+
if (!configPath) {
|
|
184
|
+
// Use the first config path as default
|
|
185
|
+
configPath = client.configPaths[0];
|
|
186
|
+
info(`Creating new config at: ${colors.dim}${configPath}${colors.reset}`);
|
|
187
|
+
} else {
|
|
188
|
+
info(`Found existing config at: ${colors.dim}${configPath}${colors.reset}`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Read existing config
|
|
192
|
+
const config = readJsonFile(configPath);
|
|
193
|
+
|
|
194
|
+
// Initialize mcpServers if not present
|
|
195
|
+
if (!config.mcpServers) {
|
|
196
|
+
config.mcpServers = {};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check if already configured
|
|
200
|
+
if (config.mcpServers[PACKAGE_NAME]) {
|
|
201
|
+
warn(`${PACKAGE_NAME} is already configured.`);
|
|
202
|
+
const answer = await prompt('Overwrite existing configuration? (y/N): ');
|
|
203
|
+
if (answer.toLowerCase() !== 'y') {
|
|
204
|
+
info('Skipping configuration.');
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Add our MCP config
|
|
210
|
+
config.mcpServers[PACKAGE_NAME] = getMcpConfig();
|
|
211
|
+
|
|
212
|
+
// Write config
|
|
213
|
+
writeJsonFile(configPath, config);
|
|
214
|
+
|
|
215
|
+
log('');
|
|
216
|
+
success(`Successfully configured ${colors.bright}${PACKAGE_NAME}${colors.reset} for ${client.name}!`);
|
|
217
|
+
log('');
|
|
218
|
+
|
|
219
|
+
// Print next steps
|
|
220
|
+
log(`${colors.bright}Next steps:${colors.reset}`);
|
|
221
|
+
log('');
|
|
222
|
+
log(` 1. Restart ${client.name} to load the MCP server`);
|
|
223
|
+
log('');
|
|
224
|
+
log(` 2. Ask your AI assistant:`);
|
|
225
|
+
log(` ${colors.cyan}"List all animation components"${colors.reset}`);
|
|
226
|
+
log(` ${colors.cyan}"Add LoadingDots to my project"${colors.reset}`);
|
|
227
|
+
log(` ${colors.cyan}"Show me the AiCreating2 source code"${colors.reset}`);
|
|
228
|
+
log('');
|
|
229
|
+
log(`${colors.dim}Config location: ${configPath}${colors.reset}`);
|
|
230
|
+
log('');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function serveMcp() {
|
|
234
|
+
// Get the path to the server.js file
|
|
235
|
+
const serverPath = path.join(__dirname, 'server.js');
|
|
236
|
+
|
|
237
|
+
if (!fs.existsSync(serverPath)) {
|
|
238
|
+
error('MCP server not found. Please reinstall the package.');
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Run the server
|
|
243
|
+
const child = spawn('node', [serverPath], {
|
|
244
|
+
stdio: 'inherit',
|
|
245
|
+
env: process.env,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
child.on('error', (err) => {
|
|
249
|
+
error(`Failed to start MCP server: ${err.message}`);
|
|
250
|
+
process.exit(1);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
child.on('exit', (code) => {
|
|
254
|
+
process.exit(code || 0);
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function showHelp() {
|
|
259
|
+
printBanner();
|
|
260
|
+
|
|
261
|
+
log(`${colors.bright}Usage:${colors.reset}`);
|
|
262
|
+
log('');
|
|
263
|
+
log(` npx ${PACKAGE_NAME} init [--client <name>] Configure MCP for an AI tool`);
|
|
264
|
+
log(` npx ${PACKAGE_NAME} serve Start the MCP server`);
|
|
265
|
+
log(` npx ${PACKAGE_NAME} --help Show this help message`);
|
|
266
|
+
log('');
|
|
267
|
+
log(`${colors.bright}Supported clients:${colors.reset}`);
|
|
268
|
+
log('');
|
|
269
|
+
Object.entries(CLIENT_CONFIGS).forEach(([key, config]) => {
|
|
270
|
+
log(` ${colors.cyan}${key.padEnd(12)}${colors.reset} ${config.name} (${config.description})`);
|
|
271
|
+
});
|
|
272
|
+
log('');
|
|
273
|
+
log(`${colors.bright}Examples:${colors.reset}`);
|
|
274
|
+
log('');
|
|
275
|
+
log(` ${colors.dim}# Interactive mode - select your AI tool${colors.reset}`);
|
|
276
|
+
log(` npx ${PACKAGE_NAME} init`);
|
|
277
|
+
log('');
|
|
278
|
+
log(` ${colors.dim}# Direct configuration for Claude Code${colors.reset}`);
|
|
279
|
+
log(` npx ${PACKAGE_NAME} init --client claude`);
|
|
280
|
+
log('');
|
|
281
|
+
log(` ${colors.dim}# Direct configuration for Cursor${colors.reset}`);
|
|
282
|
+
log(` npx ${PACKAGE_NAME} init --client cursor`);
|
|
283
|
+
log('');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async function main() {
|
|
287
|
+
const args = process.argv.slice(2);
|
|
288
|
+
const command = args[0];
|
|
289
|
+
|
|
290
|
+
if (!command || command === '--help' || command === '-h') {
|
|
291
|
+
showHelp();
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (command === 'serve') {
|
|
296
|
+
serveMcp();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (command === 'init') {
|
|
301
|
+
printBanner();
|
|
302
|
+
|
|
303
|
+
// Check for --client flag
|
|
304
|
+
const clientIndex = args.indexOf('--client');
|
|
305
|
+
let clientKey: string;
|
|
306
|
+
|
|
307
|
+
if (clientIndex !== -1 && args[clientIndex + 1]) {
|
|
308
|
+
clientKey = args[clientIndex + 1].toLowerCase();
|
|
309
|
+
} else {
|
|
310
|
+
clientKey = await selectClient();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
await initMcp(clientKey);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
error(`Unknown command: ${command}`);
|
|
318
|
+
log('');
|
|
319
|
+
log(`Run ${colors.cyan}npx ${PACKAGE_NAME} --help${colors.reset} for usage information.`);
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
main().catch((err) => {
|
|
324
|
+
error(err.message);
|
|
325
|
+
process.exit(1);
|
|
326
|
+
});
|