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.
- package/dist/cli/commands/auth.d.ts +4 -0
- package/dist/cli/commands/auth.js +58 -0
- package/dist/cli/commands/index.d.ts +2 -1
- package/dist/cli/commands/index.js +2 -1
- package/dist/cli/commands/interactive.js +107 -59
- package/dist/cli/ui/index.d.ts +1 -0
- package/dist/cli/ui/index.js +1 -0
- package/dist/cli/ui/progress.d.ts +57 -0
- package/dist/cli/ui/progress.js +149 -0
- package/dist/cli/utils/error-handler.d.ts +40 -0
- package/dist/cli/utils/error-handler.js +234 -0
- package/dist/cli/utils/index.d.ts +2 -0
- package/dist/cli/utils/index.js +3 -0
- package/dist/cli/utils/project-selector.d.ts +33 -0
- package/dist/cli/utils/project-selector.js +148 -0
- package/dist/cli.js +3 -1
- package/dist/code-index/ast-parser.d.ts +1 -1
- package/dist/code-index/ast-parser.js +9 -3
- package/dist/code-index/index.d.ts +1 -1
- package/dist/code-index/index.js +2 -2
- package/dist/github/github-service.js +8 -1
- package/dist/orchestrator/index.js +29 -1
- package/dist/semantic-memory/embedding-service.d.ts +4 -1
- package/dist/semantic-memory/embedding-service.js +58 -11
- package/dist/semantic-memory/index.d.ts +1 -1
- package/dist/semantic-memory/index.js +54 -7
- package/dist/server/config.d.ts +52 -0
- package/dist/server/config.js +88 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +115 -10
- package/dist/server/routes/admin.js +3 -3
- package/dist/server/routes/api.js +199 -2
- package/dist/server/routes/auth.js +79 -5
- package/dist/server/routes/device-auth.js +1 -1
- package/dist/server/routes/github.js +33 -0
- package/dist/server/services/auth-service.d.ts +5 -0
- package/dist/server/services/auth-service.js +10 -0
- package/dist/server/services/project-service.d.ts +15 -1
- package/dist/server/services/project-service.js +185 -26
- package/dist/types/user.d.ts +2 -2
- package/dist/types/user.js +13 -4
- 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
|
-
|
|
75
|
-
console.log();
|
|
75
|
+
printFormattedError(error, { operation: 'Unexpected error' });
|
|
76
76
|
});
|
|
77
77
|
process.on('unhandledRejection', (reason) => {
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
281
|
-
|
|
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
|
-
|
|
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
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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
|
|
620
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: ${
|
|
792
|
-
console.log(` Duplication rate: ${(
|
|
793
|
-
console.log(` Duplicated lines: ${
|
|
794
|
-
if (
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
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
|
-
|
|
938
|
+
printFormattedError(error, { operation: 'Rules check' });
|
|
891
939
|
}
|
|
892
940
|
}
|
|
893
941
|
async function handleDocsCommand(args) {
|
package/dist/cli/ui/index.d.ts
CHANGED
package/dist/cli/ui/index.js
CHANGED
|
@@ -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
|