archicore 0.1.8 → 0.2.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 (42) hide show
  1. package/dist/cli/commands/auth.d.ts +4 -0
  2. package/dist/cli/commands/auth.js +58 -0
  3. package/dist/cli/commands/index.d.ts +2 -1
  4. package/dist/cli/commands/index.js +2 -1
  5. package/dist/cli/commands/interactive.js +107 -59
  6. package/dist/cli/ui/index.d.ts +1 -0
  7. package/dist/cli/ui/index.js +1 -0
  8. package/dist/cli/ui/progress.d.ts +57 -0
  9. package/dist/cli/ui/progress.js +149 -0
  10. package/dist/cli/utils/error-handler.d.ts +40 -0
  11. package/dist/cli/utils/error-handler.js +234 -0
  12. package/dist/cli/utils/index.d.ts +2 -0
  13. package/dist/cli/utils/index.js +3 -0
  14. package/dist/cli/utils/project-selector.d.ts +33 -0
  15. package/dist/cli/utils/project-selector.js +148 -0
  16. package/dist/cli.js +3 -1
  17. package/dist/code-index/ast-parser.d.ts +1 -1
  18. package/dist/code-index/ast-parser.js +9 -3
  19. package/dist/code-index/index.d.ts +1 -1
  20. package/dist/code-index/index.js +2 -2
  21. package/dist/github/github-service.js +8 -1
  22. package/dist/orchestrator/index.js +29 -1
  23. package/dist/semantic-memory/embedding-service.d.ts +4 -1
  24. package/dist/semantic-memory/embedding-service.js +58 -11
  25. package/dist/semantic-memory/index.d.ts +1 -1
  26. package/dist/semantic-memory/index.js +54 -7
  27. package/dist/server/config.d.ts +52 -0
  28. package/dist/server/config.js +88 -0
  29. package/dist/server/index.d.ts +3 -0
  30. package/dist/server/index.js +115 -10
  31. package/dist/server/routes/admin.js +3 -3
  32. package/dist/server/routes/api.js +199 -2
  33. package/dist/server/routes/auth.js +79 -5
  34. package/dist/server/routes/device-auth.js +1 -1
  35. package/dist/server/routes/github.js +33 -0
  36. package/dist/server/services/auth-service.d.ts +5 -0
  37. package/dist/server/services/auth-service.js +10 -0
  38. package/dist/server/services/project-service.d.ts +15 -1
  39. package/dist/server/services/project-service.js +185 -26
  40. package/dist/types/user.d.ts +2 -2
  41. package/dist/types/user.js +13 -4
  42. package/package.json +9 -1
@@ -34,5 +34,9 @@ export declare function logout(): Promise<void>;
34
34
  * Require authentication - prompt login if needed
35
35
  */
36
36
  export declare function requireAuth(): Promise<TokenResponse['user'] | null>;
37
+ /**
38
+ * Register auth CLI commands
39
+ */
40
+ export declare function registerAuthCommands(program: any): void;
37
41
  export {};
38
42
  //# sourceMappingURL=auth.d.ts.map
@@ -161,4 +161,62 @@ export async function requireAuth() {
161
161
  function sleep(ms) {
162
162
  return new Promise(resolve => setTimeout(resolve, ms));
163
163
  }
164
+ /**
165
+ * Register auth CLI commands
166
+ */
167
+ export function registerAuthCommands(program) {
168
+ program
169
+ .command('login')
170
+ .description('Login to ArchiCore')
171
+ .action(async () => {
172
+ const user = await getCurrentUser();
173
+ if (user) {
174
+ printInfo(`Already logged in as ${user.name || user.email}`);
175
+ return;
176
+ }
177
+ await login();
178
+ });
179
+ program
180
+ .command('logout')
181
+ .description('Logout from ArchiCore')
182
+ .action(async () => {
183
+ await logout();
184
+ });
185
+ program
186
+ .command('status')
187
+ .description('Show authentication and subscription status')
188
+ .action(async () => {
189
+ const config = await loadConfig();
190
+ const user = await getCurrentUser();
191
+ console.log();
192
+ if (user) {
193
+ printSuccess(`Logged in as: ${user.name || user.email}`);
194
+ printInfo(`Tier: ${user.tier}`);
195
+ // Get subscription details
196
+ try {
197
+ const response = await fetch(`${config.serverUrl}/api/auth/subscription`, {
198
+ headers: {
199
+ 'Authorization': `Bearer ${config.accessToken}`,
200
+ },
201
+ });
202
+ if (response.ok) {
203
+ const data = await response.json();
204
+ console.log();
205
+ printInfo(`Requests used today: ${data.usage?.used || 0}/${data.limits?.requestsPerDay === -1 ? '∞' : data.limits?.requestsPerDay || 0}`);
206
+ if (data.expiresAt) {
207
+ printInfo(`Subscription expires: ${new Date(data.expiresAt).toLocaleDateString()}`);
208
+ }
209
+ }
210
+ }
211
+ catch {
212
+ // Ignore errors
213
+ }
214
+ }
215
+ else {
216
+ printError('Not logged in');
217
+ printInfo('Use "archicore login" to authenticate');
218
+ }
219
+ console.log();
220
+ });
221
+ }
164
222
  //# sourceMappingURL=auth.js.map
@@ -3,7 +3,8 @@
3
3
  */
4
4
  export { registerAnalyzerCommands } from './analyzers.js';
5
5
  export { registerExportCommand } from './export.js';
6
+ export { registerProjectsCommand } from './projects.js';
6
7
  export { startInteractiveMode } from './interactive.js';
7
8
  export { initProject, isInitialized, getLocalProject } from './init.js';
8
- export { login, logout, isAuthenticated, getCurrentUser, requireAuth } from './auth.js';
9
+ export { login, logout, isAuthenticated, getCurrentUser, requireAuth, registerAuthCommands } from './auth.js';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -3,7 +3,8 @@
3
3
  */
4
4
  export { registerAnalyzerCommands } from './analyzers.js';
5
5
  export { registerExportCommand } from './export.js';
6
+ export { registerProjectsCommand } from './projects.js';
6
7
  export { startInteractiveMode } from './interactive.js';
7
8
  export { initProject, isInitialized, getLocalProject } from './init.js';
8
- export { login, logout, isAuthenticated, getCurrentUser, requireAuth } from './auth.js';
9
+ export { login, logout, isAuthenticated, getCurrentUser, requireAuth, registerAuthCommands } from './auth.js';
9
10
  //# sourceMappingURL=index.js.map
@@ -6,6 +6,7 @@
6
6
  import * as readline from 'readline';
7
7
  import { loadConfig } from '../utils/config.js';
8
8
  import { checkServerConnection } from '../utils/session.js';
9
+ import { printFormattedError, printStartupError, } from '../utils/error-handler.js';
9
10
  import { isInitialized, getLocalProject } from './init.js';
10
11
  import { requireAuth, logout } from './auth.js';
11
12
  import { colors, icons, createSpinner, printHelp, printGoodbye, printSection, printSuccess, printError, printWarning, printInfo, printKeyValue, header, } from '../ui/index.js';
@@ -71,21 +72,15 @@ function showTokenUsage() {
71
72
  export async function startInteractiveMode() {
72
73
  // Prevent process from exiting on unhandled errors
73
74
  process.on('uncaughtException', (error) => {
74
- printError(`Unexpected error: ${error.message}`);
75
- console.log();
75
+ printFormattedError(error, { operation: 'Unexpected error' });
76
76
  });
77
77
  process.on('unhandledRejection', (reason) => {
78
- printError(`Unhandled promise rejection: ${reason}`);
79
- console.log();
78
+ printFormattedError(reason, { operation: 'Unhandled promise' });
80
79
  });
81
80
  // Check if initialized in current directory
82
81
  const initialized = await isInitialized(state.projectPath);
83
82
  if (!initialized) {
84
- console.log();
85
- printError('ArchiCore not initialized in this directory');
86
- console.log();
87
- printInfo('Run `archicore init` to initialize');
88
- console.log();
83
+ printStartupError(new Error('ArchiCore not initialized in this directory'));
89
84
  process.exit(1);
90
85
  }
91
86
  // Load local project config
@@ -99,14 +94,14 @@ export async function startInteractiveMode() {
99
94
  const connected = await checkServerConnection();
100
95
  if (!connected) {
101
96
  spinner.fail('Cannot connect to ArchiCore server');
102
- printError('Make sure the server is running');
97
+ printStartupError(new Error('Cannot connect to server'));
103
98
  process.exit(1);
104
99
  }
105
100
  spinner.succeed('Connected');
106
101
  // Require authentication
107
102
  const user = await requireAuth();
108
103
  if (!user) {
109
- printError('Authentication required');
104
+ printStartupError(new Error('Authentication required'));
110
105
  process.exit(1);
111
106
  }
112
107
  state.user = user;
@@ -277,8 +272,9 @@ async function handleCommand(input) {
277
272
  state.running = false;
278
273
  break;
279
274
  default:
280
- printError(`Unknown command: /${command}`);
281
- printInfo('Use /help to see available commands');
275
+ printFormattedError(`Unknown command: /${command}`, {
276
+ suggestion: 'Use /help to see available commands',
277
+ });
282
278
  }
283
279
  }
284
280
  async function handleIndexCommand() {
@@ -607,23 +603,33 @@ async function handleDeadCodeCommand() {
607
603
  if (!response.ok)
608
604
  throw new Error('Analysis failed');
609
605
  const data = await response.json();
610
- const result = data.deadCode;
606
+ // Handle various response formats
607
+ const result = data.deadCode || data.result || data || {};
611
608
  spinner.succeed('Analysis complete');
612
609
  printSection('Dead Code');
613
- console.log(` Unused exports: ${result.unusedExports?.length || 0}`);
614
- console.log(` Unused variables: ${result.unusedVariables?.length || 0}`);
615
- console.log(` Unreachable code: ${result.unreachableCode?.length || 0}`);
616
- if (result.unusedExports?.length > 0) {
610
+ const unusedExports = result.unusedExports || [];
611
+ const unusedVariables = result.unusedVariables || [];
612
+ const unreachableCode = result.unreachableCode || [];
613
+ console.log(` Unused exports: ${unusedExports.length}`);
614
+ console.log(` Unused variables: ${unusedVariables.length}`);
615
+ console.log(` Unreachable code: ${unreachableCode.length}`);
616
+ if (unusedExports.length === 0 && unusedVariables.length === 0 && unreachableCode.length === 0) {
617
+ printSuccess('No dead code found!');
618
+ return;
619
+ }
620
+ if (unusedExports.length > 0) {
617
621
  console.log();
618
622
  console.log(colors.muted(' Top unused exports:'));
619
- for (const item of result.unusedExports.slice(0, 5)) {
620
- console.log(` ${colors.warning(icons.warning)} ${item.name} ${colors.dim(`(${item.filePath})`)}`);
623
+ for (const item of unusedExports.slice(0, 5)) {
624
+ const name = item.name || item.symbol || 'unknown';
625
+ const file = item.filePath || item.file || '';
626
+ console.log(` ${colors.warning(icons.warning)} ${name} ${colors.dim(`(${file})`)}`);
621
627
  }
622
628
  }
623
629
  }
624
630
  catch (error) {
625
631
  spinner.fail('Analysis failed');
626
- throw error;
632
+ printFormattedError(error, { operation: 'Dead code analysis' });
627
633
  }
628
634
  }
629
635
  async function handleSecurityCommand() {
@@ -638,7 +644,9 @@ async function handleSecurityCommand() {
638
644
  if (!response.ok)
639
645
  throw new Error('Analysis failed');
640
646
  const data = await response.json();
641
- const vulns = data.security?.vulnerabilities || [];
647
+ // Handle various response formats
648
+ const security = data.security || data.result || data || {};
649
+ const vulns = security.vulnerabilities || security.issues || [];
642
650
  spinner.succeed('Analysis complete');
643
651
  printSection('Security');
644
652
  if (vulns.length === 0) {
@@ -659,13 +667,15 @@ async function handleSecurityCommand() {
659
667
  console.log();
660
668
  console.log(colors.muted(' Critical/High issues:'));
661
669
  for (const v of vulns.filter((v) => v.severity === 'critical' || v.severity === 'high').slice(0, 5)) {
662
- console.log(` ${colors.error(icons.error)} ${v.type}: ${v.description}`);
670
+ const type = v.type || v.category || 'Issue';
671
+ const desc = v.description || v.message || 'No description';
672
+ console.log(` ${colors.error(icons.error)} ${type}: ${desc}`);
663
673
  }
664
674
  }
665
675
  }
666
676
  catch (error) {
667
677
  spinner.fail('Analysis failed');
668
- throw error;
678
+ printFormattedError(error, { operation: 'Security analysis' });
669
679
  }
670
680
  }
671
681
  async function handleMetricsCommand() {
@@ -680,19 +690,38 @@ async function handleMetricsCommand() {
680
690
  if (!response.ok)
681
691
  throw new Error('Analysis failed');
682
692
  const data = await response.json();
683
- const metrics = data.metrics;
693
+ // Handle various response formats
694
+ const metrics = data.metrics || data.result || data || {};
695
+ const summary = metrics.summary || metrics || {};
684
696
  spinner.succeed('Metrics calculated');
685
697
  printSection('Code Metrics');
686
- if (metrics.summary) {
687
- console.log(` Files: ${metrics.summary.totalFiles || 0}`);
688
- console.log(` Lines: ${metrics.summary.totalLines || 0}`);
689
- console.log(` Avg Complexity: ${(metrics.summary.avgComplexity || 0).toFixed(2)}`);
690
- console.log(` Avg Maintainability: ${(metrics.summary.avgMaintainability || 0).toFixed(1)}`);
698
+ // Display available metrics
699
+ const totalFiles = summary.totalFiles || summary.files || metrics.totalFiles || 0;
700
+ const totalLines = summary.totalLines || summary.lines || metrics.totalLines || 0;
701
+ const avgComplexity = summary.avgComplexity || summary.complexity || metrics.avgComplexity || 0;
702
+ const avgMaintainability = summary.avgMaintainability || summary.maintainability || metrics.avgMaintainability || 0;
703
+ console.log(` Files: ${totalFiles}`);
704
+ console.log(` Lines: ${totalLines}`);
705
+ if (avgComplexity > 0) {
706
+ console.log(` Avg Complexity: ${Number(avgComplexity).toFixed(2)}`);
707
+ }
708
+ if (avgMaintainability > 0) {
709
+ console.log(` Avg Maintainability: ${Number(avgMaintainability).toFixed(1)}`);
710
+ }
711
+ // Show additional metrics if available
712
+ if (metrics.functions || summary.functions) {
713
+ console.log(` Functions: ${metrics.functions || summary.functions}`);
714
+ }
715
+ if (metrics.classes || summary.classes) {
716
+ console.log(` Classes: ${metrics.classes || summary.classes}`);
717
+ }
718
+ if (totalFiles === 0 && totalLines === 0) {
719
+ printWarning('No metrics data available. Make sure project is indexed.');
691
720
  }
692
721
  }
693
722
  catch (error) {
694
723
  spinner.fail('Analysis failed');
695
- throw error;
724
+ printFormattedError(error, { operation: 'Metrics calculation' });
696
725
  }
697
726
  }
698
727
  async function handleExportCommand(args) {
@@ -785,28 +814,37 @@ async function handleDuplicationCommand() {
785
814
  if (!response.ok)
786
815
  throw new Error('Analysis failed');
787
816
  const data = await response.json();
788
- const result = data.duplication;
817
+ // Handle various response formats
818
+ const result = data.duplication || data.result || data || {};
819
+ const clones = result.clones || [];
820
+ const duplicationRate = result.duplicationRate || result.rate || 0;
821
+ const duplicatedLines = result.duplicatedLines || result.lines || 0;
789
822
  spinner.succeed('Analysis complete');
790
823
  printSection('Code Duplication');
791
- console.log(` Code clones: ${result.clones?.length || 0}`);
792
- console.log(` Duplication rate: ${(result.duplicationRate || 0).toFixed(1)}%`);
793
- console.log(` Duplicated lines: ${result.duplicatedLines || 0}`);
794
- if (result.clones?.length > 0) {
795
- console.log();
796
- console.log(colors.muted(' Top duplicates:'));
797
- for (const clone of result.clones.slice(0, 5)) {
798
- console.log(` ${colors.warning(icons.warning)} ${clone.files?.length || 2} files, ${clone.lines || 0} lines`);
799
- if (clone.files) {
800
- for (const f of clone.files.slice(0, 2)) {
801
- console.log(` ${colors.dim(f)}`);
802
- }
824
+ console.log(` Code clones: ${clones.length}`);
825
+ console.log(` Duplication rate: ${Number(duplicationRate).toFixed(1)}%`);
826
+ console.log(` Duplicated lines: ${duplicatedLines}`);
827
+ if (clones.length === 0) {
828
+ printSuccess('No code duplication found!');
829
+ return;
830
+ }
831
+ console.log();
832
+ console.log(colors.muted(' Top duplicates:'));
833
+ for (const clone of clones.slice(0, 5)) {
834
+ const files = clone.files || clone.locations || [];
835
+ const lines = clone.lines || clone.lineCount || 0;
836
+ console.log(` ${colors.warning(icons.warning)} ${files.length || 2} files, ${lines} lines`);
837
+ if (files.length > 0) {
838
+ for (const f of files.slice(0, 2)) {
839
+ const filePath = typeof f === 'string' ? f : f.file || f.path || '';
840
+ console.log(` ${colors.dim(filePath)}`);
803
841
  }
804
842
  }
805
843
  }
806
844
  }
807
845
  catch (error) {
808
846
  spinner.fail('Analysis failed');
809
- throw error;
847
+ printFormattedError(error, { operation: 'Duplication analysis' });
810
848
  }
811
849
  }
812
850
  async function handleRefactoringCommand() {
@@ -822,7 +860,9 @@ async function handleRefactoringCommand() {
822
860
  if (!response.ok)
823
861
  throw new Error('Analysis failed');
824
862
  const data = await response.json();
825
- const suggestions = data.refactoring?.suggestions || [];
863
+ // Handle various response formats
864
+ const refactoring = data.refactoring || data.result || data || {};
865
+ const suggestions = refactoring.suggestions || refactoring.items || [];
826
866
  spinner.succeed('Analysis complete');
827
867
  printSection('Refactoring Suggestions');
828
868
  if (suggestions.length === 0) {
@@ -841,17 +881,20 @@ async function handleRefactoringCommand() {
841
881
  console.log();
842
882
  console.log(colors.muted(' Top suggestions:'));
843
883
  for (const s of suggestions.slice(0, 5)) {
844
- const priorityColor = s.priority === 'critical' ? colors.critical :
845
- s.priority === 'high' ? colors.high : colors.muted;
846
- console.log(` ${priorityColor(`[${s.priority}]`)} ${s.type}: ${s.description}`);
847
- if (s.file) {
848
- console.log(` ${colors.dim(s.file)}`);
884
+ const priority = s.priority || 'medium';
885
+ const type = s.type || s.category || 'Suggestion';
886
+ const desc = s.description || s.message || '';
887
+ const priorityColor = priority === 'critical' ? colors.critical :
888
+ priority === 'high' ? colors.high : colors.muted;
889
+ console.log(` ${priorityColor(`[${priority}]`)} ${type}: ${desc}`);
890
+ if (s.file || s.filePath) {
891
+ console.log(` ${colors.dim(s.file || s.filePath)}`);
849
892
  }
850
893
  }
851
894
  }
852
895
  catch (error) {
853
896
  spinner.fail('Analysis failed');
854
- throw error;
897
+ printFormattedError(error, { operation: 'Refactoring analysis' });
855
898
  }
856
899
  }
857
900
  async function handleRulesCommand() {
@@ -867,7 +910,9 @@ async function handleRulesCommand() {
867
910
  if (!response.ok)
868
911
  throw new Error('Analysis failed');
869
912
  const data = await response.json();
870
- const violations = data.rules?.violations || [];
913
+ // Handle various response formats
914
+ const rules = data.rules || data.result || data || {};
915
+ const violations = rules.violations || rules.issues || [];
871
916
  spinner.succeed('Analysis complete');
872
917
  printSection('Architectural Rules');
873
918
  if (violations.length === 0) {
@@ -877,17 +922,20 @@ async function handleRulesCommand() {
877
922
  console.log(` Violations: ${violations.length}`);
878
923
  console.log();
879
924
  for (const v of violations.slice(0, 10)) {
880
- const severityColor = v.severity === 'error' ? colors.error :
881
- v.severity === 'warning' ? colors.warning : colors.muted;
882
- console.log(` ${severityColor(icons.error)} ${v.rule}: ${v.message}`);
883
- if (v.file) {
884
- console.log(` ${colors.dim(v.file)}`);
925
+ const severity = v.severity || 'warning';
926
+ const rule = v.rule || v.name || 'Unknown rule';
927
+ const message = v.message || v.description || '';
928
+ const severityColor = severity === 'error' ? colors.error :
929
+ severity === 'warning' ? colors.warning : colors.muted;
930
+ console.log(` ${severityColor(icons.error)} ${rule}: ${message}`);
931
+ if (v.file || v.filePath) {
932
+ console.log(` ${colors.dim(v.file || v.filePath)}`);
885
933
  }
886
934
  }
887
935
  }
888
936
  catch (error) {
889
937
  spinner.fail('Analysis failed');
890
- throw error;
938
+ printFormattedError(error, { operation: 'Rules check' });
891
939
  }
892
940
  }
893
941
  async function handleDocsCommand(args) {
@@ -6,4 +6,5 @@ export * from './box.js';
6
6
  export * from './table.js';
7
7
  export * from './spinner.js';
8
8
  export * from './prompt.js';
9
+ export * from './progress.js';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -6,4 +6,5 @@ export * from './box.js';
6
6
  export * from './table.js';
7
7
  export * from './spinner.js';
8
8
  export * from './prompt.js';
9
+ export * from './progress.js';
9
10
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * ArchiCore CLI Progress Bar Component
3
+ *
4
+ * Visual progress bar for batch operations
5
+ */
6
+ import cliProgress from 'cli-progress';
7
+ export interface ProgressBarOptions {
8
+ total: number;
9
+ label?: string;
10
+ format?: string;
11
+ showEta?: boolean;
12
+ showSpeed?: boolean;
13
+ }
14
+ /**
15
+ * Create a styled progress bar
16
+ */
17
+ export declare function createProgressBar(options: ProgressBarOptions): cliProgress.SingleBar;
18
+ /**
19
+ * Multi-bar for parallel operations
20
+ */
21
+ export declare function createMultiProgressBar(): cliProgress.MultiBar;
22
+ /**
23
+ * Wrapper for batch processing with progress
24
+ */
25
+ export declare function withProgress<T, R>(items: T[], processor: (item: T, index: number) => Promise<R>, options?: {
26
+ label?: string;
27
+ concurrency?: number;
28
+ onError?: (error: Error, item: T, index: number) => void;
29
+ }): Promise<{
30
+ results: R[];
31
+ errors: Array<{
32
+ item: T;
33
+ error: Error;
34
+ }>;
35
+ }>;
36
+ /**
37
+ * File indexing progress (specialized for code indexing)
38
+ */
39
+ export declare class IndexingProgress {
40
+ private multiBar;
41
+ private parseBar;
42
+ private symbolBar;
43
+ private uploadBar;
44
+ constructor();
45
+ startParsing(total: number): void;
46
+ updateParsing(current: number): void;
47
+ startSymbols(total: number): void;
48
+ updateSymbols(current: number): void;
49
+ startUpload(total: number): void;
50
+ updateUpload(current: number): void;
51
+ stop(): void;
52
+ }
53
+ /**
54
+ * Simple percentage display for quick operations
55
+ */
56
+ export declare function printProgress(current: number, total: number, label?: string): void;
57
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1,149 @@
1
+ /**
2
+ * ArchiCore CLI Progress Bar Component
3
+ *
4
+ * Visual progress bar for batch operations
5
+ */
6
+ import cliProgress from 'cli-progress';
7
+ import chalk from 'chalk';
8
+ const DEFAULT_FORMAT = ' {bar} {percentage}% | {value}/{total} | {label}';
9
+ const DEFAULT_FORMAT_WITH_ETA = ' {bar} {percentage}% | {value}/{total} | ETA: {eta}s | {label}';
10
+ /**
11
+ * Create a styled progress bar
12
+ */
13
+ export function createProgressBar(options) {
14
+ const format = options.showEta ? DEFAULT_FORMAT_WITH_ETA : (options.format || DEFAULT_FORMAT);
15
+ const bar = new cliProgress.SingleBar({
16
+ format: chalk.cyan('{bar}') + chalk.gray(format.replace('{bar}', '')),
17
+ barCompleteChar: '\u2588',
18
+ barIncompleteChar: '\u2591',
19
+ hideCursor: true,
20
+ clearOnComplete: false,
21
+ stopOnComplete: true,
22
+ forceRedraw: true,
23
+ }, cliProgress.Presets.shades_classic);
24
+ bar.start(options.total, 0, { label: options.label || '' });
25
+ return bar;
26
+ }
27
+ /**
28
+ * Multi-bar for parallel operations
29
+ */
30
+ export function createMultiProgressBar() {
31
+ return new cliProgress.MultiBar({
32
+ format: chalk.cyan('{bar}') + chalk.gray(' {percentage}% | {value}/{total} | {label}'),
33
+ barCompleteChar: '\u2588',
34
+ barIncompleteChar: '\u2591',
35
+ hideCursor: true,
36
+ clearOnComplete: false,
37
+ stopOnComplete: true,
38
+ }, cliProgress.Presets.shades_classic);
39
+ }
40
+ /**
41
+ * Wrapper for batch processing with progress
42
+ */
43
+ export async function withProgress(items, processor, options = {}) {
44
+ const { label = 'Processing', concurrency = 1, onError } = options;
45
+ const results = [];
46
+ const errors = [];
47
+ if (items.length === 0) {
48
+ return { results, errors };
49
+ }
50
+ const bar = createProgressBar({
51
+ total: items.length,
52
+ label,
53
+ showEta: items.length > 10,
54
+ });
55
+ if (concurrency === 1) {
56
+ // Sequential processing
57
+ for (let i = 0; i < items.length; i++) {
58
+ try {
59
+ const result = await processor(items[i], i);
60
+ results.push(result);
61
+ }
62
+ catch (error) {
63
+ const err = error instanceof Error ? error : new Error(String(error));
64
+ errors.push({ item: items[i], error: err });
65
+ onError?.(err, items[i], i);
66
+ }
67
+ bar.update(i + 1, { label: `${label} (${i + 1}/${items.length})` });
68
+ }
69
+ }
70
+ else {
71
+ // Parallel processing with concurrency limit
72
+ const chunks = [];
73
+ for (let i = 0; i < items.length; i += concurrency) {
74
+ chunks.push(items.slice(i, i + concurrency));
75
+ }
76
+ let processed = 0;
77
+ for (const chunk of chunks) {
78
+ const chunkResults = await Promise.allSettled(chunk.map((item, i) => processor(item, processed + i)));
79
+ for (let i = 0; i < chunkResults.length; i++) {
80
+ const result = chunkResults[i];
81
+ if (result.status === 'fulfilled') {
82
+ results.push(result.value);
83
+ }
84
+ else {
85
+ const err = result.reason instanceof Error ? result.reason : new Error(String(result.reason));
86
+ errors.push({ item: chunk[i], error: err });
87
+ onError?.(err, chunk[i], processed + i);
88
+ }
89
+ processed++;
90
+ bar.update(processed, { label: `${label} (${processed}/${items.length})` });
91
+ }
92
+ }
93
+ }
94
+ bar.stop();
95
+ return { results, errors };
96
+ }
97
+ /**
98
+ * File indexing progress (specialized for code indexing)
99
+ */
100
+ export class IndexingProgress {
101
+ multiBar;
102
+ parseBar = null;
103
+ symbolBar = null;
104
+ uploadBar = null;
105
+ constructor() {
106
+ this.multiBar = new cliProgress.MultiBar({
107
+ format: ' {stage} ' + chalk.cyan('{bar}') + chalk.gray(' {percentage}% | {value}/{total}'),
108
+ barCompleteChar: '\u2588',
109
+ barIncompleteChar: '\u2591',
110
+ hideCursor: true,
111
+ clearOnComplete: false,
112
+ }, cliProgress.Presets.shades_classic);
113
+ }
114
+ startParsing(total) {
115
+ this.parseBar = this.multiBar.create(total, 0, { stage: chalk.blue('Parsing ') });
116
+ }
117
+ updateParsing(current) {
118
+ this.parseBar?.update(current);
119
+ }
120
+ startSymbols(total) {
121
+ this.symbolBar = this.multiBar.create(total, 0, { stage: chalk.yellow('Symbols ') });
122
+ }
123
+ updateSymbols(current) {
124
+ this.symbolBar?.update(current);
125
+ }
126
+ startUpload(total) {
127
+ this.uploadBar = this.multiBar.create(total, 0, { stage: chalk.green('Upload ') });
128
+ }
129
+ updateUpload(current) {
130
+ this.uploadBar?.update(current);
131
+ }
132
+ stop() {
133
+ this.multiBar.stop();
134
+ }
135
+ }
136
+ /**
137
+ * Simple percentage display for quick operations
138
+ */
139
+ export function printProgress(current, total, label = '') {
140
+ const percentage = Math.round((current / total) * 100);
141
+ const filled = Math.round(percentage / 5);
142
+ const empty = 20 - filled;
143
+ const bar = chalk.cyan('\u2588'.repeat(filled)) + chalk.gray('\u2591'.repeat(empty));
144
+ process.stdout.write(`\r ${bar} ${percentage}% ${label}`);
145
+ if (current >= total) {
146
+ process.stdout.write('\n');
147
+ }
148
+ }
149
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * ArchiCore CLI - Error Handler
3
+ *
4
+ * User-friendly error messages with suggestions
5
+ */
6
+ export interface ErrorContext {
7
+ code?: string;
8
+ statusCode?: number;
9
+ operation?: string;
10
+ suggestion?: string;
11
+ details?: string;
12
+ }
13
+ /**
14
+ * Format error for CLI display
15
+ */
16
+ export declare function formatError(error: unknown, context?: ErrorContext): string;
17
+ /**
18
+ * Print error with formatting
19
+ */
20
+ export declare function printFormattedError(error: unknown, context?: ErrorContext): void;
21
+ /**
22
+ * Wrap async operation with error handling
23
+ */
24
+ export declare function withErrorHandler<T>(operation: () => Promise<T>, context?: ErrorContext): Promise<T | null>;
25
+ /**
26
+ * Create contextual error handler
27
+ */
28
+ export declare function createErrorHandler(defaultContext: Partial<ErrorContext>): {
29
+ handle: (error: unknown, additionalContext?: Partial<ErrorContext>) => void;
30
+ wrap: <T>(operation: () => Promise<T>, additionalContext?: Partial<ErrorContext>) => Promise<T | null>;
31
+ };
32
+ /**
33
+ * HTTP response error handler
34
+ */
35
+ export declare function handleResponseError(response: Response, operation?: string): Promise<never>;
36
+ /**
37
+ * Print startup errors nicely
38
+ */
39
+ export declare function printStartupError(error: unknown): void;
40
+ //# sourceMappingURL=error-handler.d.ts.map