archicore 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 (118) hide show
  1. package/README.md +530 -0
  2. package/dist/analyzers/dead-code.d.ts +95 -0
  3. package/dist/analyzers/dead-code.js +327 -0
  4. package/dist/analyzers/duplication.d.ts +90 -0
  5. package/dist/analyzers/duplication.js +344 -0
  6. package/dist/analyzers/security.d.ts +79 -0
  7. package/dist/analyzers/security.js +484 -0
  8. package/dist/architecture/index.d.ts +35 -0
  9. package/dist/architecture/index.js +249 -0
  10. package/dist/cli/commands/analyzers.d.ts +6 -0
  11. package/dist/cli/commands/analyzers.js +431 -0
  12. package/dist/cli/commands/export.d.ts +6 -0
  13. package/dist/cli/commands/export.js +78 -0
  14. package/dist/cli/commands/index.d.ts +8 -0
  15. package/dist/cli/commands/index.js +8 -0
  16. package/dist/cli/commands/init.d.ts +26 -0
  17. package/dist/cli/commands/init.js +140 -0
  18. package/dist/cli/commands/interactive.d.ts +7 -0
  19. package/dist/cli/commands/interactive.js +522 -0
  20. package/dist/cli/commands/projects.d.ts +6 -0
  21. package/dist/cli/commands/projects.js +249 -0
  22. package/dist/cli/index.d.ts +7 -0
  23. package/dist/cli/index.js +7 -0
  24. package/dist/cli/ui/box.d.ts +17 -0
  25. package/dist/cli/ui/box.js +62 -0
  26. package/dist/cli/ui/colors.d.ts +49 -0
  27. package/dist/cli/ui/colors.js +86 -0
  28. package/dist/cli/ui/index.d.ts +9 -0
  29. package/dist/cli/ui/index.js +9 -0
  30. package/dist/cli/ui/prompt.d.ts +34 -0
  31. package/dist/cli/ui/prompt.js +122 -0
  32. package/dist/cli/ui/spinner.d.ts +29 -0
  33. package/dist/cli/ui/spinner.js +80 -0
  34. package/dist/cli/ui/table.d.ts +33 -0
  35. package/dist/cli/ui/table.js +84 -0
  36. package/dist/cli/utils/config.d.ts +23 -0
  37. package/dist/cli/utils/config.js +73 -0
  38. package/dist/cli/utils/index.d.ts +6 -0
  39. package/dist/cli/utils/index.js +6 -0
  40. package/dist/cli/utils/session.d.ts +27 -0
  41. package/dist/cli/utils/session.js +117 -0
  42. package/dist/cli.d.ts +8 -0
  43. package/dist/cli.js +295 -0
  44. package/dist/code-index/ast-parser.d.ts +16 -0
  45. package/dist/code-index/ast-parser.js +330 -0
  46. package/dist/code-index/dependency-graph.d.ts +16 -0
  47. package/dist/code-index/dependency-graph.js +161 -0
  48. package/dist/code-index/index.d.ts +44 -0
  49. package/dist/code-index/index.js +124 -0
  50. package/dist/code-index/symbol-extractor.d.ts +13 -0
  51. package/dist/code-index/symbol-extractor.js +150 -0
  52. package/dist/export/index.d.ts +92 -0
  53. package/dist/export/index.js +676 -0
  54. package/dist/github/github-service.d.ts +146 -0
  55. package/dist/github/github-service.js +609 -0
  56. package/dist/impact-engine/index.d.ts +25 -0
  57. package/dist/impact-engine/index.js +284 -0
  58. package/dist/index.d.ts +60 -0
  59. package/dist/index.js +149 -0
  60. package/dist/metrics/index.d.ts +136 -0
  61. package/dist/metrics/index.js +525 -0
  62. package/dist/orchestrator/deepseek-optimizer.d.ts +67 -0
  63. package/dist/orchestrator/deepseek-optimizer.js +320 -0
  64. package/dist/orchestrator/index.d.ts +34 -0
  65. package/dist/orchestrator/index.js +305 -0
  66. package/dist/pr-guardian/index.d.ts +143 -0
  67. package/dist/pr-guardian/index.js +553 -0
  68. package/dist/refactoring/index.d.ts +108 -0
  69. package/dist/refactoring/index.js +580 -0
  70. package/dist/rules-engine/index.d.ts +129 -0
  71. package/dist/rules-engine/index.js +482 -0
  72. package/dist/semantic-memory/embedding-service.d.ts +24 -0
  73. package/dist/semantic-memory/embedding-service.js +120 -0
  74. package/dist/semantic-memory/index.d.ts +45 -0
  75. package/dist/semantic-memory/index.js +206 -0
  76. package/dist/semantic-memory/vector-store.d.ts +27 -0
  77. package/dist/semantic-memory/vector-store.js +166 -0
  78. package/dist/server/index.d.ts +28 -0
  79. package/dist/server/index.js +141 -0
  80. package/dist/server/middleware/api-auth.d.ts +43 -0
  81. package/dist/server/middleware/api-auth.js +256 -0
  82. package/dist/server/routes/admin.d.ts +5 -0
  83. package/dist/server/routes/admin.js +123 -0
  84. package/dist/server/routes/api.d.ts +7 -0
  85. package/dist/server/routes/api.js +362 -0
  86. package/dist/server/routes/auth.d.ts +16 -0
  87. package/dist/server/routes/auth.js +191 -0
  88. package/dist/server/routes/developer.d.ts +8 -0
  89. package/dist/server/routes/developer.js +439 -0
  90. package/dist/server/routes/github.d.ts +7 -0
  91. package/dist/server/routes/github.js +495 -0
  92. package/dist/server/routes/upload.d.ts +7 -0
  93. package/dist/server/routes/upload.js +196 -0
  94. package/dist/server/services/api-key-service.d.ts +81 -0
  95. package/dist/server/services/api-key-service.js +281 -0
  96. package/dist/server/services/auth-service.d.ts +40 -0
  97. package/dist/server/services/auth-service.js +315 -0
  98. package/dist/server/services/project-service.d.ts +123 -0
  99. package/dist/server/services/project-service.js +533 -0
  100. package/dist/server/services/token-service.d.ts +107 -0
  101. package/dist/server/services/token-service.js +416 -0
  102. package/dist/server/services/upload-service.d.ts +93 -0
  103. package/dist/server/services/upload-service.js +464 -0
  104. package/dist/types/api.d.ts +188 -0
  105. package/dist/types/api.js +86 -0
  106. package/dist/types/github.d.ts +335 -0
  107. package/dist/types/github.js +5 -0
  108. package/dist/types/index.d.ts +265 -0
  109. package/dist/types/index.js +32 -0
  110. package/dist/types/user.d.ts +69 -0
  111. package/dist/types/user.js +42 -0
  112. package/dist/utils/file-utils.d.ts +20 -0
  113. package/dist/utils/file-utils.js +163 -0
  114. package/dist/utils/logger.d.ts +17 -0
  115. package/dist/utils/logger.js +41 -0
  116. package/dist/watcher/index.d.ts +125 -0
  117. package/dist/watcher/index.js +397 -0
  118. package/package.json +71 -0
@@ -0,0 +1,522 @@
1
+ /**
2
+ * ArchiCore CLI - Interactive Mode
3
+ *
4
+ * REPL-style interface similar to Claude Code
5
+ */
6
+ import * as readline from 'readline';
7
+ import { loadConfig } from '../utils/config.js';
8
+ import { checkServerConnection } from '../utils/session.js';
9
+ import { isInitialized, getLocalProject } from './init.js';
10
+ import { colors, icons, createSpinner, printHelp, printGoodbye, printSection, printSuccess, printError, printWarning, printInfo, printKeyValue, header, } from '../ui/index.js';
11
+ const state = {
12
+ running: true,
13
+ projectId: null,
14
+ projectName: null,
15
+ projectPath: process.cwd(),
16
+ history: [],
17
+ };
18
+ export async function startInteractiveMode() {
19
+ // Check if initialized in current directory
20
+ const initialized = await isInitialized(state.projectPath);
21
+ if (!initialized) {
22
+ console.log();
23
+ printError('ArchiCore not initialized in this directory');
24
+ console.log();
25
+ printInfo('Run `archicore init` to initialize');
26
+ console.log();
27
+ process.exit(1);
28
+ }
29
+ // Load local project config
30
+ const localProject = await getLocalProject(state.projectPath);
31
+ if (localProject) {
32
+ state.projectId = localProject.id || null;
33
+ state.projectName = localProject.name;
34
+ }
35
+ // Check server connection
36
+ const spinner = createSpinner('Connecting to ArchiCore...').start();
37
+ const connected = await checkServerConnection();
38
+ if (!connected) {
39
+ spinner.fail('Cannot connect to ArchiCore server');
40
+ printError('Make sure the server is running: npm run server');
41
+ process.exit(1);
42
+ }
43
+ spinner.succeed('Connected');
44
+ // Print welcome
45
+ console.log();
46
+ console.log(header('ArchiCore', 'AI Software Architect'));
47
+ if (state.projectName) {
48
+ console.log(colors.muted(` Project: ${colors.primary(state.projectName)}`));
49
+ }
50
+ console.log();
51
+ console.log(colors.muted(' Type /help for commands or ask a question about your code.'));
52
+ console.log();
53
+ // Start REPL
54
+ const rl = readline.createInterface({
55
+ input: process.stdin,
56
+ output: process.stdout,
57
+ terminal: true,
58
+ });
59
+ const prompt = () => {
60
+ const prefix = state.projectName
61
+ ? colors.muted(`[${state.projectName}] `)
62
+ : '';
63
+ process.stdout.write(`${prefix}${colors.primary(icons.arrow)} `);
64
+ };
65
+ prompt();
66
+ const processLine = async (input) => {
67
+ const trimmed = input.trim();
68
+ if (!trimmed) {
69
+ prompt();
70
+ return;
71
+ }
72
+ state.history.push(trimmed);
73
+ try {
74
+ await handleInput(trimmed);
75
+ }
76
+ catch (error) {
77
+ printError(String(error));
78
+ }
79
+ if (state.running) {
80
+ console.log();
81
+ prompt();
82
+ }
83
+ else {
84
+ rl.close();
85
+ }
86
+ };
87
+ rl.on('line', (input) => {
88
+ processLine(input).catch((err) => {
89
+ printError(String(err));
90
+ prompt();
91
+ });
92
+ });
93
+ rl.on('close', () => {
94
+ if (state.running) {
95
+ // Unexpected close, try to restart
96
+ console.log();
97
+ printWarning('Input stream closed unexpectedly');
98
+ }
99
+ else {
100
+ printGoodbye();
101
+ }
102
+ process.exit(0);
103
+ });
104
+ // Handle SIGINT (Ctrl+C)
105
+ process.on('SIGINT', () => {
106
+ console.log();
107
+ state.running = false;
108
+ rl.close();
109
+ });
110
+ }
111
+ async function handleInput(input) {
112
+ // Handle slash commands
113
+ if (input.startsWith('/')) {
114
+ await handleCommand(input);
115
+ return;
116
+ }
117
+ // Natural language query
118
+ await handleQuery(input);
119
+ }
120
+ async function handleCommand(input) {
121
+ const parts = input.slice(1).split(/\s+/);
122
+ const command = parts[0].toLowerCase();
123
+ const args = parts.slice(1);
124
+ switch (command) {
125
+ case 'help':
126
+ case 'h':
127
+ printHelp();
128
+ break;
129
+ case 'exit':
130
+ case 'quit':
131
+ case 'q':
132
+ state.running = false;
133
+ break;
134
+ case 'clear':
135
+ case 'cls':
136
+ console.clear();
137
+ break;
138
+ case 'index':
139
+ case 'i':
140
+ await handleIndexCommand();
141
+ break;
142
+ case 'analyze':
143
+ case 'impact':
144
+ await handleAnalyzeCommand(args);
145
+ break;
146
+ case 'search':
147
+ case 's':
148
+ await handleSearchCommand(args.join(' '));
149
+ break;
150
+ case 'dead-code':
151
+ case 'deadcode':
152
+ await handleDeadCodeCommand();
153
+ break;
154
+ case 'security':
155
+ case 'sec':
156
+ await handleSecurityCommand();
157
+ break;
158
+ case 'metrics':
159
+ case 'stats':
160
+ await handleMetricsCommand();
161
+ break;
162
+ case 'export':
163
+ await handleExportCommand(args);
164
+ break;
165
+ case 'status':
166
+ await handleStatusCommand();
167
+ break;
168
+ default:
169
+ printError(`Unknown command: /${command}`);
170
+ printInfo('Use /help to see available commands');
171
+ }
172
+ }
173
+ async function handleIndexCommand() {
174
+ if (!state.projectId) {
175
+ // Try to register project first
176
+ const spinner = createSpinner('Registering project...').start();
177
+ try {
178
+ const config = await loadConfig();
179
+ const response = await fetch(`${config.serverUrl}/api/projects`, {
180
+ method: 'POST',
181
+ headers: { 'Content-Type': 'application/json' },
182
+ body: JSON.stringify({ name: state.projectName, path: state.projectPath }),
183
+ });
184
+ if (response.ok) {
185
+ const data = await response.json();
186
+ state.projectId = data.id || data.project?.id;
187
+ }
188
+ spinner.stop();
189
+ }
190
+ catch {
191
+ spinner.fail('Failed to register project');
192
+ return;
193
+ }
194
+ }
195
+ if (!state.projectId) {
196
+ printError('Failed to register project with server');
197
+ return;
198
+ }
199
+ const spinner = createSpinner('Indexing project...').start();
200
+ try {
201
+ const config = await loadConfig();
202
+ const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/index`, {
203
+ method: 'POST',
204
+ });
205
+ if (!response.ok) {
206
+ throw new Error('Indexing failed');
207
+ }
208
+ const data = await response.json();
209
+ spinner.succeed('Project indexed');
210
+ printKeyValue('Files', String(data.statistics?.totalFiles || 0));
211
+ printKeyValue('Symbols', String(data.statistics?.totalSymbols || 0));
212
+ // Update local config
213
+ const { getLocalProject } = await import('./init.js');
214
+ const localProject = await getLocalProject(state.projectPath);
215
+ if (localProject) {
216
+ localProject.id = state.projectId;
217
+ localProject.indexed = true;
218
+ const fs = await import('fs/promises');
219
+ const path = await import('path');
220
+ await fs.writeFile(path.join(state.projectPath, '.archicore', 'project.json'), JSON.stringify(localProject, null, 2));
221
+ }
222
+ }
223
+ catch (error) {
224
+ spinner.fail('Indexing failed');
225
+ printError(String(error));
226
+ }
227
+ }
228
+ async function handleAnalyzeCommand(args) {
229
+ if (!state.projectId) {
230
+ printError('No project selected');
231
+ printInfo('Use /projects select <id> first');
232
+ return;
233
+ }
234
+ const description = args.join(' ') || 'General analysis';
235
+ const spinner = createSpinner('Analyzing impact...').start();
236
+ try {
237
+ const config = await loadConfig();
238
+ const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/analyze`, {
239
+ method: 'POST',
240
+ headers: { 'Content-Type': 'application/json' },
241
+ body: JSON.stringify({
242
+ description,
243
+ files: [],
244
+ symbols: [],
245
+ type: 'modify',
246
+ }),
247
+ });
248
+ if (!response.ok)
249
+ throw new Error('Analysis failed');
250
+ const data = await response.json();
251
+ spinner.succeed('Analysis complete');
252
+ printSection('Impact Analysis');
253
+ const impact = data.impact;
254
+ // Affected components
255
+ const affected = impact.affectedNodes || [];
256
+ console.log(` ${colors.highlight('Affected Components:')} ${affected.length}`);
257
+ const byLevel = {
258
+ critical: affected.filter((n) => n.impactLevel === 'critical'),
259
+ high: affected.filter((n) => n.impactLevel === 'high'),
260
+ medium: affected.filter((n) => n.impactLevel === 'medium'),
261
+ low: affected.filter((n) => n.impactLevel === 'low'),
262
+ };
263
+ if (byLevel.critical.length > 0) {
264
+ console.log(` ${colors.critical(`${icons.severityCritical} Critical: ${byLevel.critical.length}`)}`);
265
+ }
266
+ if (byLevel.high.length > 0) {
267
+ console.log(` ${colors.high(`${icons.severityHigh} High: ${byLevel.high.length}`)}`);
268
+ }
269
+ if (byLevel.medium.length > 0) {
270
+ console.log(` ${colors.medium(`${icons.severityMedium} Medium: ${byLevel.medium.length}`)}`);
271
+ }
272
+ if (byLevel.low.length > 0) {
273
+ console.log(` ${colors.low(`${icons.severityLow} Low: ${byLevel.low.length}`)}`);
274
+ }
275
+ // Risks
276
+ if (impact.risks?.length > 0) {
277
+ console.log();
278
+ console.log(` ${colors.highlight('Risks:')}`);
279
+ for (const risk of impact.risks.slice(0, 5)) {
280
+ console.log(` ${colors.warning(icons.warning)} ${risk.description}`);
281
+ }
282
+ }
283
+ // Recommendations
284
+ if (impact.recommendations?.length > 0) {
285
+ console.log();
286
+ console.log(` ${colors.highlight('Recommendations:')}`);
287
+ for (const rec of impact.recommendations.slice(0, 3)) {
288
+ console.log(` ${colors.info(icons.info)} ${rec.description}`);
289
+ }
290
+ }
291
+ }
292
+ catch (error) {
293
+ spinner.fail('Analysis failed');
294
+ throw error;
295
+ }
296
+ }
297
+ async function handleSearchCommand(query) {
298
+ if (!state.projectId) {
299
+ printError('No project selected');
300
+ printInfo('Use /projects select <id> first');
301
+ return;
302
+ }
303
+ if (!query) {
304
+ printError('Usage: /search <query>');
305
+ return;
306
+ }
307
+ const spinner = createSpinner('Searching...').start();
308
+ try {
309
+ const config = await loadConfig();
310
+ const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/search`, {
311
+ method: 'POST',
312
+ headers: { 'Content-Type': 'application/json' },
313
+ body: JSON.stringify({ query, limit: 10 }),
314
+ });
315
+ if (!response.ok)
316
+ throw new Error('Search failed');
317
+ const data = await response.json();
318
+ const results = data.results || [];
319
+ spinner.succeed(`Found ${results.length} results`);
320
+ if (results.length === 0) {
321
+ printWarning('No results found');
322
+ return;
323
+ }
324
+ console.log();
325
+ for (const [i, result] of results.entries()) {
326
+ const score = ((result.score || 0) * 100).toFixed(0);
327
+ const file = result.chunk?.metadata?.filePath || result.filePath || 'unknown';
328
+ const line = result.chunk?.metadata?.startLine || result.line || '';
329
+ console.log(` ${colors.secondary(`${i + 1}.`)} ${colors.highlight(file)}${line ? `:${line}` : ''}`);
330
+ console.log(` ${colors.muted(`${score}% match`)}`);
331
+ if (result.context || result.chunk?.content) {
332
+ const preview = (result.context || result.chunk?.content || '')
333
+ .slice(0, 100)
334
+ .replace(/\n/g, ' ');
335
+ console.log(` ${colors.dim(preview)}${preview.length >= 100 ? '...' : ''}`);
336
+ }
337
+ console.log();
338
+ }
339
+ }
340
+ catch (error) {
341
+ spinner.fail('Search failed');
342
+ throw error;
343
+ }
344
+ }
345
+ async function handleQuery(query) {
346
+ if (!state.projectId) {
347
+ printError('No project selected');
348
+ printInfo('Use /projects to list and select a project first');
349
+ return;
350
+ }
351
+ const spinner = createSpinner('Thinking...').start();
352
+ try {
353
+ const config = await loadConfig();
354
+ const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/ask`, {
355
+ method: 'POST',
356
+ headers: { 'Content-Type': 'application/json' },
357
+ body: JSON.stringify({ question: query }),
358
+ });
359
+ if (!response.ok)
360
+ throw new Error('Query failed');
361
+ const data = await response.json();
362
+ spinner.stop();
363
+ console.log();
364
+ console.log(colors.primary(' ' + icons.lightning + ' ArchiCore'));
365
+ console.log();
366
+ // Format the answer
367
+ const answer = data.answer || data.response || 'No response';
368
+ const lines = answer.split('\n');
369
+ for (const line of lines) {
370
+ console.log(' ' + line);
371
+ }
372
+ }
373
+ catch (error) {
374
+ spinner.fail('Query failed');
375
+ throw error;
376
+ }
377
+ }
378
+ async function handleDeadCodeCommand() {
379
+ if (!state.projectId) {
380
+ printError('No project selected');
381
+ return;
382
+ }
383
+ const spinner = createSpinner('Analyzing dead code...').start();
384
+ try {
385
+ const config = await loadConfig();
386
+ const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/dead-code`);
387
+ if (!response.ok)
388
+ throw new Error('Analysis failed');
389
+ const data = await response.json();
390
+ const result = data.deadCode;
391
+ spinner.succeed('Analysis complete');
392
+ printSection('Dead Code');
393
+ console.log(` Unused exports: ${result.unusedExports?.length || 0}`);
394
+ console.log(` Unused variables: ${result.unusedVariables?.length || 0}`);
395
+ console.log(` Unreachable code: ${result.unreachableCode?.length || 0}`);
396
+ if (result.unusedExports?.length > 0) {
397
+ console.log();
398
+ console.log(colors.muted(' Top unused exports:'));
399
+ for (const item of result.unusedExports.slice(0, 5)) {
400
+ console.log(` ${colors.warning(icons.warning)} ${item.name} ${colors.dim(`(${item.filePath})`)}`);
401
+ }
402
+ }
403
+ }
404
+ catch (error) {
405
+ spinner.fail('Analysis failed');
406
+ throw error;
407
+ }
408
+ }
409
+ async function handleSecurityCommand() {
410
+ if (!state.projectId) {
411
+ printError('No project selected');
412
+ return;
413
+ }
414
+ const spinner = createSpinner('Analyzing security...').start();
415
+ try {
416
+ const config = await loadConfig();
417
+ const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/security`);
418
+ if (!response.ok)
419
+ throw new Error('Analysis failed');
420
+ const data = await response.json();
421
+ const vulns = data.security?.vulnerabilities || [];
422
+ spinner.succeed('Analysis complete');
423
+ printSection('Security');
424
+ if (vulns.length === 0) {
425
+ printSuccess('No vulnerabilities found!');
426
+ return;
427
+ }
428
+ const counts = {
429
+ critical: vulns.filter((v) => v.severity === 'critical').length,
430
+ high: vulns.filter((v) => v.severity === 'high').length,
431
+ medium: vulns.filter((v) => v.severity === 'medium').length,
432
+ low: vulns.filter((v) => v.severity === 'low').length,
433
+ };
434
+ console.log(` ${colors.critical(`Critical: ${counts.critical}`)}`);
435
+ console.log(` ${colors.high(`High: ${counts.high}`)}`);
436
+ console.log(` ${colors.medium(`Medium: ${counts.medium}`)}`);
437
+ console.log(` ${colors.low(`Low: ${counts.low}`)}`);
438
+ if (counts.critical > 0 || counts.high > 0) {
439
+ console.log();
440
+ console.log(colors.muted(' Critical/High issues:'));
441
+ for (const v of vulns.filter((v) => v.severity === 'critical' || v.severity === 'high').slice(0, 5)) {
442
+ console.log(` ${colors.error(icons.error)} ${v.type}: ${v.description}`);
443
+ }
444
+ }
445
+ }
446
+ catch (error) {
447
+ spinner.fail('Analysis failed');
448
+ throw error;
449
+ }
450
+ }
451
+ async function handleMetricsCommand() {
452
+ if (!state.projectId) {
453
+ printError('No project selected');
454
+ return;
455
+ }
456
+ const spinner = createSpinner('Calculating metrics...').start();
457
+ try {
458
+ const config = await loadConfig();
459
+ const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/metrics`);
460
+ if (!response.ok)
461
+ throw new Error('Analysis failed');
462
+ const data = await response.json();
463
+ const metrics = data.metrics;
464
+ spinner.succeed('Metrics calculated');
465
+ printSection('Code Metrics');
466
+ if (metrics.summary) {
467
+ console.log(` Files: ${metrics.summary.totalFiles || 0}`);
468
+ console.log(` Lines: ${metrics.summary.totalLines || 0}`);
469
+ console.log(` Avg Complexity: ${(metrics.summary.avgComplexity || 0).toFixed(2)}`);
470
+ console.log(` Avg Maintainability: ${(metrics.summary.avgMaintainability || 0).toFixed(1)}`);
471
+ }
472
+ }
473
+ catch (error) {
474
+ spinner.fail('Analysis failed');
475
+ throw error;
476
+ }
477
+ }
478
+ async function handleExportCommand(args) {
479
+ if (!state.projectId) {
480
+ printError('No project selected');
481
+ return;
482
+ }
483
+ const format = args[0] || 'json';
484
+ const output = args[1] || `archicore-export.${format === 'markdown' ? 'md' : format}`;
485
+ const spinner = createSpinner(`Exporting as ${format}...`).start();
486
+ try {
487
+ const config = await loadConfig();
488
+ const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/export`, {
489
+ method: 'POST',
490
+ headers: { 'Content-Type': 'application/json' },
491
+ body: JSON.stringify({ format }),
492
+ });
493
+ if (!response.ok)
494
+ throw new Error('Export failed');
495
+ const data = await response.json();
496
+ const { writeFile } = await import('fs/promises');
497
+ const content = format === 'json'
498
+ ? JSON.stringify(data.data || data, null, 2)
499
+ : data.content || JSON.stringify(data, null, 2);
500
+ await writeFile(output, content);
501
+ spinner.succeed('Export complete');
502
+ printKeyValue('Output', output);
503
+ }
504
+ catch (error) {
505
+ spinner.fail('Export failed');
506
+ throw error;
507
+ }
508
+ }
509
+ async function handleStatusCommand() {
510
+ const config = await loadConfig();
511
+ printSection('Status');
512
+ const connected = await checkServerConnection();
513
+ console.log(` Server: ${connected ? colors.success('Connected') : colors.error('Disconnected')}`);
514
+ console.log(` URL: ${colors.muted(config.serverUrl)}`);
515
+ if (state.projectId) {
516
+ console.log(` Project: ${colors.primary(state.projectName || state.projectId)}`);
517
+ }
518
+ else {
519
+ console.log(` Project: ${colors.muted('None selected')}`);
520
+ }
521
+ }
522
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * ArchiCore CLI - Projects Commands
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function registerProjectsCommand(program: Command): void;
6
+ //# sourceMappingURL=projects.d.ts.map