archicore 0.2.3 → 0.2.5

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.
@@ -10,6 +10,8 @@ import { printFormattedError, printStartupError, } from '../utils/error-handler.
10
10
  import { isInitialized, getLocalProject } from './init.js';
11
11
  import { requireAuth, logout } from './auth.js';
12
12
  import { colors, icons, createSpinner, printHelp, printGoodbye, printSection, printSuccess, printError, printWarning, printInfo, printKeyValue, header, } from '../ui/index.js';
13
+ import { createSession, loadLastSession, addMessage, getContextMessages, listSessions, searchHistory, exportSessionAsText, clearAllHistory, } from '../utils/conversation-history.js';
14
+ import { uploadIndexData, analyzeNetworkError, analyzeHttpError, } from '../utils/upload-utils.js';
13
15
  // Command registry with descriptions (like Claude CLI)
14
16
  const COMMANDS = [
15
17
  { name: 'index', aliases: ['i'], description: 'Index your codebase for analysis' },
@@ -23,6 +25,8 @@ const COMMANDS = [
23
25
  { name: 'rules', aliases: [], description: 'Check architectural rules' },
24
26
  { name: 'docs', aliases: ['documentation'], description: 'Generate architecture documentation' },
25
27
  { name: 'export', aliases: [], description: 'Export analysis results' },
28
+ { name: 'history', aliases: ['hist'], description: 'View and search conversation history' },
29
+ { name: 'resume', aliases: [], description: 'Resume previous conversation session' },
26
30
  { name: 'status', aliases: [], description: 'Show connection and project status' },
27
31
  { name: 'clear', aliases: ['cls'], description: 'Clear the screen' },
28
32
  { name: 'help', aliases: ['h'], description: 'Show available commands' },
@@ -36,6 +40,7 @@ const state = {
36
40
  projectPath: process.cwd(),
37
41
  history: [],
38
42
  user: null,
43
+ conversationSession: null,
39
44
  };
40
45
  // Track token usage for session
41
46
  let sessionTokensUsed = 0;
@@ -124,6 +129,23 @@ export async function startInteractiveMode() {
124
129
  process.exit(1);
125
130
  }
126
131
  state.user = user;
132
+ // Initialize or resume conversation session
133
+ const lastSession = await loadLastSession(state.projectId || undefined);
134
+ if (lastSession) {
135
+ // Check if last session was recent (within 1 hour)
136
+ const lastActivity = new Date(lastSession.lastActivityAt).getTime();
137
+ const oneHourAgo = Date.now() - 60 * 60 * 1000;
138
+ if (lastActivity > oneHourAgo) {
139
+ state.conversationSession = lastSession;
140
+ console.log(colors.muted(` ${icons.info} Resuming previous session (${lastSession.messages.length} messages)`));
141
+ }
142
+ else {
143
+ state.conversationSession = await createSession(state.projectId || undefined, state.projectName || undefined);
144
+ }
145
+ }
146
+ else {
147
+ state.conversationSession = await createSession(state.projectId || undefined, state.projectName || undefined);
148
+ }
127
149
  // Print welcome
128
150
  console.log();
129
151
  console.log(header('ArchiCore', 'AI Software Architect'));
@@ -134,6 +156,7 @@ export async function startInteractiveMode() {
134
156
  console.log();
135
157
  console.log(colors.muted(' Type / to see commands, or ask a question about your code.'));
136
158
  console.log(colors.muted(' Press Tab to autocomplete. Type ? for shortcuts.'));
159
+ console.log(colors.muted(' Use /history to view past conversations, /resume to continue.'));
137
160
  console.log();
138
161
  // Interactive input with real-time autocomplete
139
162
  await startInteractiveInput(state);
@@ -473,6 +496,13 @@ async function handleCommand(input) {
473
496
  await logout();
474
497
  state.running = false;
475
498
  break;
499
+ case 'history':
500
+ case 'hist':
501
+ await handleHistoryCommand(args);
502
+ break;
503
+ case 'resume':
504
+ await handleResumeCommand(args);
505
+ break;
476
506
  default:
477
507
  printFormattedError(`Unknown command: /${command}`, {
478
508
  suggestion: 'Use /help to see available commands',
@@ -496,11 +526,24 @@ async function handleIndexCommand() {
496
526
  if (response.ok) {
497
527
  const data = await response.json();
498
528
  state.projectId = data.id || data.project?.id;
529
+ registerSpinner.succeed('Project registered');
530
+ }
531
+ else {
532
+ const errorBody = await response.json().catch(() => ({}));
533
+ const errorDetails = analyzeHttpError(response.status, errorBody);
534
+ registerSpinner.fail('Failed to register project');
535
+ printError(errorDetails.message);
536
+ printInfo(errorDetails.suggestion);
537
+ console.log(colors.dim(` Technical: ${errorDetails.technicalDetails}`));
538
+ return;
499
539
  }
500
- registerSpinner.succeed('Project registered');
501
540
  }
502
- catch {
541
+ catch (error) {
542
+ const errorDetails = analyzeNetworkError(error);
503
543
  registerSpinner.fail('Failed to register project');
544
+ printError(errorDetails.message);
545
+ printInfo(errorDetails.suggestion);
546
+ console.log(colors.dim(` Technical: ${errorDetails.technicalDetails}`));
504
547
  return;
505
548
  }
506
549
  }
@@ -524,22 +567,28 @@ async function handleIndexCommand() {
524
567
  indexSpinner.update(`Found ${symbols.size} symbols, building graph...`);
525
568
  // Строим граф зависимостей
526
569
  const graph = codeIndex.buildDependencyGraph(asts, symbols);
527
- indexSpinner.update('Reading file contents...');
528
- // Читаем содержимое файлов
570
+ // Определяем размер проекта для оптимизации
571
+ const isLargeProject = symbols.size > 50000 || asts.size > 1000;
572
+ // Читаем содержимое файлов (с оптимизацией для больших проектов)
529
573
  const fileContents = [];
530
- for (const [filePath] of asts) {
531
- try {
532
- const fullPath = pathModule.default.isAbsolute(filePath)
533
- ? filePath
534
- : pathModule.default.join(state.projectPath, filePath);
535
- const content = await fs.readFile(fullPath, 'utf-8');
536
- fileContents.push([filePath, content]);
537
- }
538
- catch {
539
- // Игнорируем ошибки чтения
574
+ if (!isLargeProject) {
575
+ indexSpinner.update('Reading file contents...');
576
+ for (const [filePath] of asts) {
577
+ try {
578
+ const fullPath = pathModule.default.isAbsolute(filePath)
579
+ ? filePath
580
+ : pathModule.default.join(state.projectPath, filePath);
581
+ const content = await fs.readFile(fullPath, 'utf-8');
582
+ fileContents.push([filePath, content]);
583
+ }
584
+ catch {
585
+ // Игнорируем ошибки чтения отдельных файлов
586
+ }
540
587
  }
541
588
  }
542
- indexSpinner.update('Uploading to server...');
589
+ else {
590
+ indexSpinner.update('Large project detected, skipping file contents for faster upload...');
591
+ }
543
592
  // Конвертируем Maps в массивы для JSON
544
593
  const astsArray = Array.from(asts.entries());
545
594
  const symbolsArray = Array.from(symbols.entries());
@@ -547,89 +596,78 @@ async function handleIndexCommand() {
547
596
  nodes: Array.from(graph.nodes.entries()),
548
597
  edges: Array.from(graph.edges.entries()),
549
598
  };
550
- // Отправляем на сервер
551
- const response = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/upload-index`, {
552
- method: 'POST',
553
- headers: {
554
- 'Content-Type': 'application/json',
555
- 'Authorization': `Bearer ${config.accessToken}`,
599
+ const indexData = {
600
+ asts: astsArray,
601
+ symbols: symbolsArray,
602
+ graph: graphData,
603
+ fileContents,
604
+ statistics: {
605
+ totalFiles: asts.size,
606
+ totalSymbols: symbols.size,
556
607
  },
557
- body: JSON.stringify({
558
- asts: astsArray,
559
- symbols: symbolsArray,
560
- graph: graphData,
561
- fileContents,
562
- statistics: {
563
- totalFiles: asts.size,
564
- totalSymbols: symbols.size,
565
- },
566
- }),
608
+ };
609
+ // Загружаем на сервер с прогрессом и обработкой ошибок
610
+ const uploadResult = await uploadIndexData(state.projectId, indexData, (progress) => {
611
+ indexSpinner.update(progress.message);
567
612
  });
568
- if (!response.ok) {
569
- const errorData = await response.json().catch(() => ({}));
570
- // If access denied, re-register project with current user
571
- if (response.status === 403 && errorData.error?.includes('Access denied')) {
572
- indexSpinner.update('Re-registering project with current user...');
573
- // Clear old project ID and re-register
574
- const reRegisterResponse = await fetch(`${config.serverUrl}/api/projects`, {
575
- method: 'POST',
576
- headers: {
577
- 'Content-Type': 'application/json',
578
- 'Authorization': `Bearer ${config.accessToken}`,
579
- },
580
- body: JSON.stringify({ name: state.projectName, path: state.projectPath }),
581
- });
582
- if (reRegisterResponse.ok) {
583
- const reData = await reRegisterResponse.json();
584
- state.projectId = reData.id || reData.project?.id;
585
- // Retry upload with new project ID
586
- indexSpinner.update('Uploading to server...');
587
- const retryResponse = await fetch(`${config.serverUrl}/api/projects/${state.projectId}/upload-index`, {
588
- method: 'POST',
589
- headers: {
590
- 'Content-Type': 'application/json',
591
- 'Authorization': `Bearer ${config.accessToken}`,
592
- },
593
- body: JSON.stringify({
594
- asts: astsArray,
595
- symbols: symbolsArray,
596
- graph: graphData,
597
- fileContents,
598
- statistics: {
599
- totalFiles: asts.size,
600
- totalSymbols: symbols.size,
613
+ if (!uploadResult.success) {
614
+ // Детальная обработка ошибок
615
+ indexSpinner.fail('Indexing failed');
616
+ // Debug output to see what's in the result
617
+ console.log(colors.dim(` [DEBUG] uploadResult: ${JSON.stringify(uploadResult, null, 2)}`));
618
+ if (uploadResult.errorDetails) {
619
+ const { code, message, suggestion, technicalDetails } = uploadResult.errorDetails;
620
+ console.log();
621
+ console.log(colors.error(` ${icons.error} Error: ${message}`));
622
+ console.log(colors.warning(` ${icons.info} ${suggestion}`));
623
+ if (code === 'FORBIDDEN') {
624
+ // Пробуем перерегистрировать проект
625
+ console.log(colors.muted(' Attempting to re-register project...'));
626
+ try {
627
+ const reRegisterResponse = await fetch(`${config.serverUrl}/api/projects`, {
628
+ method: 'POST',
629
+ headers: {
630
+ 'Content-Type': 'application/json',
631
+ 'Authorization': `Bearer ${config.accessToken}`,
601
632
  },
602
- }),
603
- });
604
- if (!retryResponse.ok) {
605
- throw new Error('Upload failed after re-registration');
633
+ body: JSON.stringify({ name: state.projectName, path: state.projectPath }),
634
+ });
635
+ if (reRegisterResponse.ok) {
636
+ const reData = await reRegisterResponse.json();
637
+ state.projectId = reData.id || reData.project?.id;
638
+ printInfo('Project re-registered. Run /index again to complete indexing.');
639
+ // Обновляем локальный конфиг
640
+ const localProjectRetry = await getLocalProject(state.projectPath);
641
+ if (localProjectRetry && state.projectId) {
642
+ localProjectRetry.id = state.projectId;
643
+ await fs.writeFile(pathModule.default.join(state.projectPath, '.archicore', 'project.json'), JSON.stringify(localProjectRetry, null, 2));
644
+ }
645
+ }
606
646
  }
607
- // Use retry response for data
608
- const retryData = await retryResponse.json();
609
- indexSpinner.succeed('Project re-registered and indexed');
610
- printKeyValue('Files', String(retryData.statistics?.filesCount || asts.size));
611
- printKeyValue('Symbols', String(retryData.statistics?.symbolsCount || symbols.size));
612
- // Update local config with new project ID
613
- const localProjectRetry = await getLocalProject(state.projectPath);
614
- if (localProjectRetry && state.projectId) {
615
- localProjectRetry.id = state.projectId;
616
- localProjectRetry.indexed = true;
617
- await fs.writeFile(pathModule.default.join(state.projectPath, '.archicore', 'project.json'), JSON.stringify(localProjectRetry, null, 2));
647
+ catch {
648
+ // Игнорируем ошибку перерегистрации
618
649
  }
619
- return; // Exit early - already handled
620
- }
621
- else {
622
- throw new Error('Failed to re-register project');
623
650
  }
651
+ console.log(colors.dim(` [${code}] ${technicalDetails}`));
624
652
  }
625
653
  else {
626
- throw new Error(errorData.error || 'Upload failed');
654
+ printError(uploadResult.error || 'Unknown upload error');
627
655
  }
656
+ return;
628
657
  }
629
- const data = await response.json();
630
658
  indexSpinner.succeed('Project indexed and uploaded');
631
- printKeyValue('Files', String(data.statistics?.filesCount || asts.size));
632
- printKeyValue('Symbols', String(data.statistics?.symbolsCount || symbols.size));
659
+ // Показываем статистику
660
+ const stats = uploadResult.statistics;
661
+ if (stats) {
662
+ printKeyValue('Files', String(stats.filesCount));
663
+ printKeyValue('Symbols', String(stats.symbolsCount));
664
+ if (stats.nodesCount) {
665
+ printKeyValue('Graph nodes', String(stats.nodesCount));
666
+ }
667
+ if (stats.edgesCount) {
668
+ printKeyValue('Graph edges', String(stats.edgesCount));
669
+ }
670
+ }
633
671
  // Обновляем локальный конфиг
634
672
  const localProject = await getLocalProject(state.projectPath);
635
673
  if (localProject) {
@@ -640,7 +678,28 @@ async function handleIndexCommand() {
640
678
  }
641
679
  catch (error) {
642
680
  indexSpinner.fail('Indexing failed');
643
- printError(String(error));
681
+ // Детальный анализ ошибки
682
+ const errorStr = String(error);
683
+ if (errorStr.includes('ENOENT') || errorStr.includes('no such file')) {
684
+ printError('File not found during indexing');
685
+ printInfo('Some files may have been deleted during the indexing process. Try again.');
686
+ }
687
+ else if (errorStr.includes('ENOMEM') || errorStr.includes('heap out of memory')) {
688
+ printError('Out of memory');
689
+ printInfo('The project is too large to index. Try increasing Node.js memory limit:');
690
+ console.log(colors.muted(' NODE_OPTIONS="--max-old-space-size=4096" archicore'));
691
+ }
692
+ else if (errorStr.includes('EACCES') || errorStr.includes('permission denied')) {
693
+ printError('Permission denied');
694
+ printInfo('Check that you have read access to all project files.');
695
+ }
696
+ else {
697
+ // Общая ошибка
698
+ const errorDetails = analyzeNetworkError(error);
699
+ printError(errorDetails.message);
700
+ printInfo(errorDetails.suggestion);
701
+ console.log(colors.dim(` Technical: ${errorDetails.technicalDetails}`));
702
+ }
644
703
  }
645
704
  }
646
705
  async function handleAnalyzeCommand(args) {
@@ -790,12 +849,30 @@ async function handleQuery(query) {
790
849
  printInfo('Use /projects to list and select a project first');
791
850
  return;
792
851
  }
852
+ // Save user message to history
853
+ if (state.conversationSession) {
854
+ await addMessage(state.conversationSession, 'user', query, {
855
+ tokens: estimateTokens(query),
856
+ });
857
+ }
793
858
  const spinner = createSpinner('Thinking...').start();
794
859
  try {
795
860
  const config = await loadConfig();
861
+ // Get context from conversation history for better responses
862
+ let contextMessages = [];
863
+ if (state.conversationSession) {
864
+ const history = getContextMessages(state.conversationSession, 10, 3000);
865
+ contextMessages = history.slice(0, -1).map(m => ({
866
+ role: m.role,
867
+ content: m.content,
868
+ }));
869
+ }
796
870
  const response = await apiFetch(`${config.serverUrl}/api/projects/${state.projectId}/ask`, {
797
871
  method: 'POST',
798
- body: JSON.stringify({ question: query }),
872
+ body: JSON.stringify({
873
+ question: query,
874
+ context: contextMessages.length > 0 ? contextMessages : undefined,
875
+ }),
799
876
  });
800
877
  if (!response.ok)
801
878
  throw new Error('Query failed');
@@ -811,6 +888,12 @@ async function handleQuery(query) {
811
888
  for (const line of lines) {
812
889
  console.log(' ' + line);
813
890
  }
891
+ // Save assistant response to history
892
+ if (state.conversationSession) {
893
+ await addMessage(state.conversationSession, 'assistant', answer, {
894
+ tokens: estimateTokens(answer),
895
+ });
896
+ }
814
897
  showTokenUsage();
815
898
  }
816
899
  catch (error) {
@@ -1203,4 +1286,168 @@ async function handleDocsCommand(args) {
1203
1286
  throw error;
1204
1287
  }
1205
1288
  }
1289
+ /**
1290
+ * /history command - View and search conversation history
1291
+ *
1292
+ * Usage:
1293
+ * /history - Show recent sessions
1294
+ * /history search <query> - Search in history
1295
+ * /history export - Export current session
1296
+ * /history clear - Clear all history
1297
+ */
1298
+ async function handleHistoryCommand(args) {
1299
+ const subcommand = args[0]?.toLowerCase();
1300
+ switch (subcommand) {
1301
+ case 'search': {
1302
+ const query = args.slice(1).join(' ');
1303
+ if (!query) {
1304
+ printError('Usage: /history search <query>');
1305
+ return;
1306
+ }
1307
+ const spinner = createSpinner('Searching history...').start();
1308
+ const results = await searchHistory(query, { limit: 15 });
1309
+ spinner.stop();
1310
+ if (results.length === 0) {
1311
+ printWarning('No matches found');
1312
+ return;
1313
+ }
1314
+ printSection(`Search Results (${results.length})`);
1315
+ for (const { session, message } of results) {
1316
+ const date = new Date(message.timestamp).toLocaleDateString();
1317
+ const time = new Date(message.timestamp).toLocaleTimeString();
1318
+ const role = message.role === 'user' ? colors.primary('You') : colors.secondary('ArchiCore');
1319
+ const projectName = session.projectName || 'Unknown project';
1320
+ console.log();
1321
+ console.log(` ${colors.dim(`[${date} ${time}]`)} ${role} ${colors.dim(`in ${projectName}`)}`);
1322
+ // Show snippet with highlighted query
1323
+ const content = message.content.slice(0, 200);
1324
+ const queryLower = query.toLowerCase();
1325
+ const contentLower = content.toLowerCase();
1326
+ const idx = contentLower.indexOf(queryLower);
1327
+ if (idx >= 0) {
1328
+ const before = content.slice(0, idx);
1329
+ const match = content.slice(idx, idx + query.length);
1330
+ const after = content.slice(idx + query.length);
1331
+ console.log(` ${before}${colors.highlight(match)}${after}${content.length >= 200 ? '...' : ''}`);
1332
+ }
1333
+ else {
1334
+ console.log(` ${content}${content.length >= 200 ? '...' : ''}`);
1335
+ }
1336
+ }
1337
+ break;
1338
+ }
1339
+ case 'export': {
1340
+ if (!state.conversationSession) {
1341
+ printError('No active session to export');
1342
+ return;
1343
+ }
1344
+ const { writeFile } = await import('fs/promises');
1345
+ const exportContent = exportSessionAsText(state.conversationSession);
1346
+ const filename = `archicore-conversation-${state.conversationSession.id}.txt`;
1347
+ await writeFile(filename, exportContent);
1348
+ printSuccess(`Session exported to ${filename}`);
1349
+ break;
1350
+ }
1351
+ case 'clear': {
1352
+ const count = await clearAllHistory();
1353
+ printSuccess(`Cleared ${count} session(s) from history`);
1354
+ // Create a new session
1355
+ state.conversationSession = await createSession(state.projectId || undefined, state.projectName || undefined);
1356
+ break;
1357
+ }
1358
+ case 'context': {
1359
+ // Show current context being sent to AI
1360
+ if (!state.conversationSession) {
1361
+ printError('No active session');
1362
+ return;
1363
+ }
1364
+ const contextMessages = getContextMessages(state.conversationSession, 10, 2000);
1365
+ printSection(`Context (${contextMessages.length} messages)`);
1366
+ for (const msg of contextMessages) {
1367
+ const role = msg.role === 'user' ? colors.primary('You') : colors.secondary('ArchiCore');
1368
+ const time = new Date(msg.timestamp).toLocaleTimeString();
1369
+ const preview = msg.content.slice(0, 100).replace(/\n/g, ' ');
1370
+ console.log(` ${colors.dim(`[${time}]`)} ${role}: ${preview}${msg.content.length > 100 ? '...' : ''}`);
1371
+ }
1372
+ break;
1373
+ }
1374
+ default: {
1375
+ // Show recent sessions
1376
+ const sessions = await listSessions({ limit: 10 });
1377
+ if (sessions.length === 0) {
1378
+ printInfo('No conversation history yet');
1379
+ return;
1380
+ }
1381
+ printSection('Recent Sessions');
1382
+ for (const session of sessions) {
1383
+ const startDate = new Date(session.startedAt);
1384
+ const isActive = state.conversationSession?.id === session.id;
1385
+ const activeMarker = isActive ? colors.success(' (active)') : '';
1386
+ console.log();
1387
+ console.log(` ${colors.primary(session.id)}${activeMarker}`);
1388
+ console.log(` ${colors.dim('Project:')} ${session.projectName || 'N/A'}`);
1389
+ console.log(` ${colors.dim('Started:')} ${startDate.toLocaleString()}`);
1390
+ console.log(` ${colors.dim('Messages:')} ${session.messages.length}`);
1391
+ if (session.metadata?.commandsUsed && session.metadata.commandsUsed.length > 0) {
1392
+ console.log(` ${colors.dim('Commands:')} ${session.metadata.commandsUsed.slice(0, 5).join(', ')}`);
1393
+ }
1394
+ }
1395
+ console.log();
1396
+ console.log(colors.muted(' Use /resume <session_id> to continue a session'));
1397
+ console.log(colors.muted(' Use /history search <query> to search in history'));
1398
+ console.log(colors.muted(' Use /history export to save current session'));
1399
+ break;
1400
+ }
1401
+ }
1402
+ }
1403
+ /**
1404
+ * /resume command - Resume a previous conversation session
1405
+ */
1406
+ async function handleResumeCommand(args) {
1407
+ const sessionId = args[0];
1408
+ if (!sessionId) {
1409
+ // Show recent sessions to choose from
1410
+ const sessions = await listSessions({ limit: 5 });
1411
+ if (sessions.length === 0) {
1412
+ printInfo('No sessions available to resume');
1413
+ return;
1414
+ }
1415
+ printSection('Available Sessions');
1416
+ for (const session of sessions) {
1417
+ const date = new Date(session.startedAt).toLocaleString();
1418
+ const messages = session.messages.length;
1419
+ console.log(` ${colors.primary(session.id)}`);
1420
+ console.log(` ${session.projectName || 'Unknown'} - ${messages} messages - ${date}`);
1421
+ }
1422
+ console.log();
1423
+ printInfo('Usage: /resume <session_id>');
1424
+ return;
1425
+ }
1426
+ const spinner = createSpinner('Loading session...').start();
1427
+ try {
1428
+ const { loadSession } = await import('../utils/conversation-history.js');
1429
+ const session = await loadSession(sessionId);
1430
+ if (!session) {
1431
+ spinner.fail('Session not found');
1432
+ return;
1433
+ }
1434
+ state.conversationSession = session;
1435
+ spinner.succeed(`Resumed session with ${session.messages.length} messages`);
1436
+ // Show last few messages for context
1437
+ const recentMessages = session.messages.slice(-5);
1438
+ if (recentMessages.length > 0) {
1439
+ console.log();
1440
+ console.log(colors.muted(' Recent messages:'));
1441
+ for (const msg of recentMessages) {
1442
+ const role = msg.role === 'user' ? colors.primary('You') : colors.secondary('ArchiCore');
1443
+ const preview = msg.content.slice(0, 80).replace(/\n/g, ' ');
1444
+ console.log(` ${role}: ${preview}${msg.content.length > 80 ? '...' : ''}`);
1445
+ }
1446
+ }
1447
+ }
1448
+ catch (error) {
1449
+ spinner.fail('Failed to load session');
1450
+ printError(String(error));
1451
+ }
1452
+ }
1206
1453
  //# sourceMappingURL=interactive.js.map
@@ -0,0 +1,84 @@
1
+ /**
2
+ * ArchiCore CLI - Conversation History Management
3
+ *
4
+ * Сохранение и загрузка истории диалогов между сессиями
5
+ */
6
+ export interface ConversationMessage {
7
+ role: 'user' | 'assistant' | 'system';
8
+ content: string;
9
+ timestamp: string;
10
+ command?: string;
11
+ tokens?: number;
12
+ }
13
+ export interface ConversationSession {
14
+ id: string;
15
+ projectId?: string;
16
+ projectName?: string;
17
+ startedAt: string;
18
+ lastActivityAt: string;
19
+ messages: ConversationMessage[];
20
+ metadata?: {
21
+ totalTokens?: number;
22
+ commandsUsed?: string[];
23
+ };
24
+ }
25
+ /**
26
+ * Создать новую сессию разговора
27
+ */
28
+ export declare function createSession(projectId?: string, projectName?: string): Promise<ConversationSession>;
29
+ /**
30
+ * Сохранить сессию на диск
31
+ */
32
+ export declare function saveSession(session: ConversationSession): Promise<void>;
33
+ /**
34
+ * Загрузить сессию с диска
35
+ */
36
+ export declare function loadSession(sessionId: string): Promise<ConversationSession | null>;
37
+ /**
38
+ * Загрузить последнюю сессию для проекта
39
+ */
40
+ export declare function loadLastSession(projectId?: string): Promise<ConversationSession | null>;
41
+ /**
42
+ * Добавить сообщение в сессию
43
+ */
44
+ export declare function addMessage(session: ConversationSession, role: 'user' | 'assistant' | 'system', content: string, options?: {
45
+ command?: string;
46
+ tokens?: number;
47
+ }): Promise<void>;
48
+ /**
49
+ * Получить контекст для AI (последние N сообщений)
50
+ */
51
+ export declare function getContextMessages(session: ConversationSession, maxMessages?: number, maxTokens?: number): ConversationMessage[];
52
+ /**
53
+ * Получить список всех сессий
54
+ */
55
+ export declare function listSessions(options?: {
56
+ projectId?: string;
57
+ limit?: number;
58
+ search?: string;
59
+ }): Promise<ConversationSession[]>;
60
+ /**
61
+ * Поиск по истории сообщений
62
+ */
63
+ export declare function searchHistory(query: string, options?: {
64
+ projectId?: string;
65
+ limit?: number;
66
+ role?: 'user' | 'assistant';
67
+ }): Promise<Array<{
68
+ session: ConversationSession;
69
+ message: ConversationMessage;
70
+ index: number;
71
+ }>>;
72
+ /**
73
+ * Удалить сессию
74
+ */
75
+ export declare function deleteSession(sessionId: string): Promise<boolean>;
76
+ /**
77
+ * Очистить всю историю
78
+ */
79
+ export declare function clearAllHistory(): Promise<number>;
80
+ /**
81
+ * Экспорт сессии в текстовый формат
82
+ */
83
+ export declare function exportSessionAsText(session: ConversationSession): string;
84
+ //# sourceMappingURL=conversation-history.d.ts.map