@syntero/orca-cli 1.0.0 → 1.1.1
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/assistant.d.ts +17 -3
- package/dist/assistant.d.ts.map +1 -1
- package/dist/assistant.js +217 -22
- package/dist/assistant.js.map +1 -1
- package/dist/auth.d.ts +97 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +437 -0
- package/dist/auth.js.map +1 -0
- package/dist/autocomplete.d.ts +24 -0
- package/dist/autocomplete.d.ts.map +1 -0
- package/dist/autocomplete.js +43 -0
- package/dist/autocomplete.js.map +1 -0
- package/dist/components/ChatApp.d.ts +32 -0
- package/dist/components/ChatApp.d.ts.map +1 -0
- package/dist/components/ChatApp.js +470 -0
- package/dist/components/ChatApp.js.map +1 -0
- package/dist/components/CommandPalette.d.ts +15 -0
- package/dist/components/CommandPalette.d.ts.map +1 -0
- package/dist/components/CommandPalette.js +22 -0
- package/dist/components/CommandPalette.js.map +1 -0
- package/dist/components/ConfigWizard.d.ts +25 -0
- package/dist/components/ConfigWizard.d.ts.map +1 -0
- package/dist/components/ConfigWizard.js +401 -0
- package/dist/components/ConfigWizard.js.map +1 -0
- package/dist/components/InputFooter.d.ts +33 -0
- package/dist/components/InputFooter.d.ts.map +1 -0
- package/dist/components/InputFooter.js +618 -0
- package/dist/components/InputFooter.js.map +1 -0
- package/dist/components/InputModal.d.ts +25 -0
- package/dist/components/InputModal.d.ts.map +1 -0
- package/dist/components/InputModal.js +529 -0
- package/dist/components/InputModal.js.map +1 -0
- package/dist/components/ModelMenu.d.ts +24 -0
- package/dist/components/ModelMenu.d.ts.map +1 -0
- package/dist/components/ModelMenu.js +175 -0
- package/dist/components/ModelMenu.js.map +1 -0
- package/dist/components/ProviderMenu.d.ts +20 -0
- package/dist/components/ProviderMenu.d.ts.map +1 -0
- package/dist/components/ProviderMenu.js +31 -0
- package/dist/components/ProviderMenu.js.map +1 -0
- package/dist/components/SyncMenu.d.ts +23 -0
- package/dist/components/SyncMenu.d.ts.map +1 -0
- package/dist/components/SyncMenu.js +135 -0
- package/dist/components/SyncMenu.js.map +1 -0
- package/dist/components/TokenInput.d.ts +15 -0
- package/dist/components/TokenInput.d.ts.map +1 -0
- package/dist/components/TokenInput.js +103 -0
- package/dist/components/TokenInput.js.map +1 -0
- package/dist/index.js +323 -173
- package/dist/index.js.map +1 -1
- package/dist/ink-input.d.ts +14 -0
- package/dist/ink-input.d.ts.map +1 -0
- package/dist/ink-input.js +92 -0
- package/dist/ink-input.js.map +1 -0
- package/dist/models.d.ts +115 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +221 -0
- package/dist/models.js.map +1 -0
- package/dist/providers.d.ts +19 -4
- package/dist/providers.d.ts.map +1 -1
- package/dist/providers.js +80 -112
- package/dist/providers.js.map +1 -1
- package/dist/settings.d.ts +15 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +56 -21
- package/dist/settings.js.map +1 -1
- package/dist/sync/docker.d.ts +68 -0
- package/dist/sync/docker.d.ts.map +1 -0
- package/dist/sync/docker.js +234 -0
- package/dist/sync/docker.js.map +1 -0
- package/dist/sync/download.d.ts +87 -0
- package/dist/sync/download.d.ts.map +1 -0
- package/dist/sync/download.js +291 -0
- package/dist/sync/download.js.map +1 -0
- package/dist/sync/hash.d.ts +60 -0
- package/dist/sync/hash.d.ts.map +1 -0
- package/dist/sync/hash.js +92 -0
- package/dist/sync/hash.js.map +1 -0
- package/dist/sync/index.d.ts +15 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +21 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/manifest.d.ts +132 -0
- package/dist/sync/manifest.d.ts.map +1 -0
- package/dist/sync/manifest.js +260 -0
- package/dist/sync/manifest.js.map +1 -0
- package/dist/sync/progress.d.ts +164 -0
- package/dist/sync/progress.d.ts.map +1 -0
- package/dist/sync/progress.js +233 -0
- package/dist/sync/progress.js.map +1 -0
- package/dist/sync/services.d.ts +70 -0
- package/dist/sync/services.d.ts.map +1 -0
- package/dist/sync/services.js +134 -0
- package/dist/sync/services.js.map +1 -0
- package/dist/sync/sync-engine.d.ts +69 -0
- package/dist/sync/sync-engine.d.ts.map +1 -0
- package/dist/sync/sync-engine.js +533 -0
- package/dist/sync/sync-engine.js.map +1 -0
- package/dist/tokens.d.ts +70 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +198 -0
- package/dist/tokens.js.map +1 -0
- package/dist/tools.d.ts +60 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +34 -0
- package/dist/tools.js.map +1 -1
- package/dist/types/sync.d.ts +284 -0
- package/dist/types/sync.d.ts.map +1 -0
- package/dist/types/sync.js +5 -0
- package/dist/types/sync.js.map +1 -0
- package/package.json +10 -2
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress display utilities for library sync.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Progress state during sync.
|
|
6
|
+
*/
|
|
7
|
+
export interface ProgressState {
|
|
8
|
+
phase: 'preflight' | 'manifest' | 'comparing' | 'downloading' | 'cleaning' | 'complete';
|
|
9
|
+
currentSolution?: string;
|
|
10
|
+
currentFile?: string;
|
|
11
|
+
filesTotal: number;
|
|
12
|
+
filesComplete: number;
|
|
13
|
+
bytesTotal: number;
|
|
14
|
+
bytesComplete: number;
|
|
15
|
+
startTime: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Format bytes into human-readable string.
|
|
19
|
+
*
|
|
20
|
+
* @param bytes Number of bytes
|
|
21
|
+
* @returns Formatted string (e.g., "1.5 MB")
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatBytes(bytes: number): string;
|
|
24
|
+
/**
|
|
25
|
+
* Format duration in milliseconds to human-readable string.
|
|
26
|
+
*
|
|
27
|
+
* @param ms Duration in milliseconds
|
|
28
|
+
* @returns Formatted string (e.g., "2m 30s")
|
|
29
|
+
*/
|
|
30
|
+
export declare function formatDuration(ms: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* Create a progress bar string.
|
|
33
|
+
*
|
|
34
|
+
* @param percent Percentage complete (0-100)
|
|
35
|
+
* @param width Width of progress bar in characters
|
|
36
|
+
* @returns Progress bar string
|
|
37
|
+
*/
|
|
38
|
+
export declare function createProgressBar(percent: number, width?: number): string;
|
|
39
|
+
/**
|
|
40
|
+
* Display sync progress.
|
|
41
|
+
*
|
|
42
|
+
* @param state Current progress state
|
|
43
|
+
*/
|
|
44
|
+
export declare function displayProgress(state: ProgressState): void;
|
|
45
|
+
/**
|
|
46
|
+
* Display phase message.
|
|
47
|
+
*
|
|
48
|
+
* @param phase Current phase
|
|
49
|
+
* @param message Optional additional message
|
|
50
|
+
*/
|
|
51
|
+
export declare function displayPhase(phase: string, message?: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Display a section header.
|
|
54
|
+
*
|
|
55
|
+
* @param title Section title
|
|
56
|
+
*/
|
|
57
|
+
export declare function displayHeader(title: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Display a success message.
|
|
60
|
+
*
|
|
61
|
+
* @param message Message to display
|
|
62
|
+
*/
|
|
63
|
+
export declare function displaySuccess(message: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Display a warning message.
|
|
66
|
+
*
|
|
67
|
+
* @param message Message to display
|
|
68
|
+
*/
|
|
69
|
+
export declare function displayWarning(message: string): void;
|
|
70
|
+
/**
|
|
71
|
+
* Display an error message.
|
|
72
|
+
*
|
|
73
|
+
* @param message Message to display
|
|
74
|
+
*/
|
|
75
|
+
export declare function displayError(message: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Display sync plan summary.
|
|
78
|
+
*
|
|
79
|
+
* @param plan Sync plan details
|
|
80
|
+
*/
|
|
81
|
+
export declare function displaySyncPlan(plan: {
|
|
82
|
+
newSolutions: string[];
|
|
83
|
+
modifiedSolutions: string[];
|
|
84
|
+
deletedSolutions: string[];
|
|
85
|
+
filesToDownload: {
|
|
86
|
+
solution: string;
|
|
87
|
+
path: string;
|
|
88
|
+
size: number;
|
|
89
|
+
}[];
|
|
90
|
+
filesToDelete: {
|
|
91
|
+
solution: string;
|
|
92
|
+
path: string;
|
|
93
|
+
}[];
|
|
94
|
+
}): void;
|
|
95
|
+
/**
|
|
96
|
+
* Display detailed sync plan (for verbose mode).
|
|
97
|
+
*
|
|
98
|
+
* @param plan Sync plan details
|
|
99
|
+
* @param remoteManifest Remote manifest for additional details
|
|
100
|
+
*/
|
|
101
|
+
export declare function displayVerboseSyncPlan(plan: {
|
|
102
|
+
newSolutions: string[];
|
|
103
|
+
modifiedSolutions: string[];
|
|
104
|
+
deletedSolutions: string[];
|
|
105
|
+
filesToDownload: {
|
|
106
|
+
solution: string;
|
|
107
|
+
path: string;
|
|
108
|
+
size: number;
|
|
109
|
+
}[];
|
|
110
|
+
filesToDelete: {
|
|
111
|
+
solution: string;
|
|
112
|
+
path: string;
|
|
113
|
+
}[];
|
|
114
|
+
}): void;
|
|
115
|
+
/**
|
|
116
|
+
* Display dry run plan.
|
|
117
|
+
*
|
|
118
|
+
* @param plan Sync plan details
|
|
119
|
+
*/
|
|
120
|
+
export declare function displayDryRunPlan(plan: {
|
|
121
|
+
newSolutions: string[];
|
|
122
|
+
modifiedSolutions: string[];
|
|
123
|
+
deletedSolutions: string[];
|
|
124
|
+
filesToDownload: {
|
|
125
|
+
solution: string;
|
|
126
|
+
path: string;
|
|
127
|
+
size: number;
|
|
128
|
+
}[];
|
|
129
|
+
filesToDelete: {
|
|
130
|
+
solution: string;
|
|
131
|
+
path: string;
|
|
132
|
+
}[];
|
|
133
|
+
}): void;
|
|
134
|
+
/**
|
|
135
|
+
* Display sync completion summary.
|
|
136
|
+
*
|
|
137
|
+
* @param stats Sync statistics
|
|
138
|
+
*/
|
|
139
|
+
export declare function displaySyncComplete(stats: {
|
|
140
|
+
newSolutions: number;
|
|
141
|
+
updatedSolutions: number;
|
|
142
|
+
deletedSolutions: number;
|
|
143
|
+
filesDownloaded: number;
|
|
144
|
+
filesDeleted: number;
|
|
145
|
+
bytesDownloaded: number;
|
|
146
|
+
durationMs: number;
|
|
147
|
+
}): void;
|
|
148
|
+
/**
|
|
149
|
+
* Display sync status.
|
|
150
|
+
*
|
|
151
|
+
* @param status Status information
|
|
152
|
+
*/
|
|
153
|
+
export declare function displaySyncStatus(status: {
|
|
154
|
+
syncStatus: string;
|
|
155
|
+
lastSyncTime?: string;
|
|
156
|
+
lastSyncRelative?: string;
|
|
157
|
+
solutionCount: number;
|
|
158
|
+
fileCount: number;
|
|
159
|
+
totalSize: number;
|
|
160
|
+
orgId?: string;
|
|
161
|
+
endpoint?: string;
|
|
162
|
+
pendingFiles?: number;
|
|
163
|
+
}): void;
|
|
164
|
+
//# sourceMappingURL=progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/sync/progress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress display utilities for library sync.
|
|
3
|
+
*/
|
|
4
|
+
import { Colors, color } from '../utils.js';
|
|
5
|
+
/**
|
|
6
|
+
* Format bytes into human-readable string.
|
|
7
|
+
*
|
|
8
|
+
* @param bytes Number of bytes
|
|
9
|
+
* @returns Formatted string (e.g., "1.5 MB")
|
|
10
|
+
*/
|
|
11
|
+
export function formatBytes(bytes) {
|
|
12
|
+
if (bytes === 0)
|
|
13
|
+
return '0 B';
|
|
14
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
15
|
+
const k = 1024;
|
|
16
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
17
|
+
const value = bytes / Math.pow(k, i);
|
|
18
|
+
return `${value.toFixed(i > 0 ? 1 : 0)} ${units[i]}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Format duration in milliseconds to human-readable string.
|
|
22
|
+
*
|
|
23
|
+
* @param ms Duration in milliseconds
|
|
24
|
+
* @returns Formatted string (e.g., "2m 30s")
|
|
25
|
+
*/
|
|
26
|
+
export function formatDuration(ms) {
|
|
27
|
+
if (ms < 1000)
|
|
28
|
+
return `${Math.round(ms)}ms`;
|
|
29
|
+
const seconds = Math.floor(ms / 1000);
|
|
30
|
+
const minutes = Math.floor(seconds / 60);
|
|
31
|
+
const hours = Math.floor(minutes / 60);
|
|
32
|
+
if (hours > 0) {
|
|
33
|
+
return `${hours}h ${minutes % 60}m`;
|
|
34
|
+
}
|
|
35
|
+
if (minutes > 0) {
|
|
36
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
37
|
+
}
|
|
38
|
+
return `${seconds}s`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a progress bar string.
|
|
42
|
+
*
|
|
43
|
+
* @param percent Percentage complete (0-100)
|
|
44
|
+
* @param width Width of progress bar in characters
|
|
45
|
+
* @returns Progress bar string
|
|
46
|
+
*/
|
|
47
|
+
export function createProgressBar(percent, width = 30) {
|
|
48
|
+
const filled = Math.round((percent / 100) * width);
|
|
49
|
+
const empty = width - filled;
|
|
50
|
+
return '[' + '#'.repeat(filled) + '-'.repeat(empty) + ']';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Display sync progress.
|
|
54
|
+
*
|
|
55
|
+
* @param state Current progress state
|
|
56
|
+
*/
|
|
57
|
+
export function displayProgress(state) {
|
|
58
|
+
const elapsed = Date.now() - state.startTime;
|
|
59
|
+
const percent = state.filesTotal > 0
|
|
60
|
+
? Math.round((state.filesComplete / state.filesTotal) * 100)
|
|
61
|
+
: 0;
|
|
62
|
+
// Calculate speed
|
|
63
|
+
let speed = '';
|
|
64
|
+
if (state.bytesComplete > 0 && elapsed > 0) {
|
|
65
|
+
const bytesPerSecond = state.bytesComplete / (elapsed / 1000);
|
|
66
|
+
speed = ` ${formatBytes(bytesPerSecond)}/s`;
|
|
67
|
+
}
|
|
68
|
+
// Calculate ETA
|
|
69
|
+
let eta = '';
|
|
70
|
+
if (state.filesComplete > 0 && state.filesComplete < state.filesTotal) {
|
|
71
|
+
const avgTimePerFile = elapsed / state.filesComplete;
|
|
72
|
+
const remainingFiles = state.filesTotal - state.filesComplete;
|
|
73
|
+
const remainingTime = avgTimePerFile * remainingFiles;
|
|
74
|
+
eta = ` ETA: ${formatDuration(remainingTime)}`;
|
|
75
|
+
}
|
|
76
|
+
// Build progress line
|
|
77
|
+
const progressBar = createProgressBar(percent, 20);
|
|
78
|
+
const line = `${progressBar} ${state.filesComplete}/${state.filesTotal} files (${percent}%)${speed}${eta}`;
|
|
79
|
+
// Clear line and write progress
|
|
80
|
+
process.stdout.write(`\r${color(line, Colors.cyan)}`);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Display phase message.
|
|
84
|
+
*
|
|
85
|
+
* @param phase Current phase
|
|
86
|
+
* @param message Optional additional message
|
|
87
|
+
*/
|
|
88
|
+
export function displayPhase(phase, message) {
|
|
89
|
+
const fullMessage = message ? `${phase}: ${message}` : phase;
|
|
90
|
+
console.log(color(fullMessage, Colors.dim));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Display a section header.
|
|
94
|
+
*
|
|
95
|
+
* @param title Section title
|
|
96
|
+
*/
|
|
97
|
+
export function displayHeader(title) {
|
|
98
|
+
console.log(color(`\n${title}`, Colors.bold));
|
|
99
|
+
console.log(color('-'.repeat(40), Colors.dim));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Display a success message.
|
|
103
|
+
*
|
|
104
|
+
* @param message Message to display
|
|
105
|
+
*/
|
|
106
|
+
export function displaySuccess(message) {
|
|
107
|
+
console.log(color(message, Colors.green));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Display a warning message.
|
|
111
|
+
*
|
|
112
|
+
* @param message Message to display
|
|
113
|
+
*/
|
|
114
|
+
export function displayWarning(message) {
|
|
115
|
+
console.log(color(message, Colors.yellow));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Display an error message.
|
|
119
|
+
*
|
|
120
|
+
* @param message Message to display
|
|
121
|
+
*/
|
|
122
|
+
export function displayError(message) {
|
|
123
|
+
console.log(color(message, Colors.red));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Display sync plan summary.
|
|
127
|
+
*
|
|
128
|
+
* @param plan Sync plan details
|
|
129
|
+
*/
|
|
130
|
+
export function displaySyncPlan(plan) {
|
|
131
|
+
console.log('\nChanges detected:');
|
|
132
|
+
if (plan.newSolutions.length > 0) {
|
|
133
|
+
console.log(color(` + ${plan.newSolutions.length} new solution${plan.newSolutions.length > 1 ? 's' : ''}`, Colors.green));
|
|
134
|
+
}
|
|
135
|
+
if (plan.modifiedSolutions.length > 0) {
|
|
136
|
+
console.log(color(` ~ ${plan.modifiedSolutions.length} modified solution${plan.modifiedSolutions.length > 1 ? 's' : ''}`, Colors.yellow));
|
|
137
|
+
}
|
|
138
|
+
if (plan.deletedSolutions.length > 0) {
|
|
139
|
+
console.log(color(` - ${plan.deletedSolutions.length} deleted solution${plan.deletedSolutions.length > 1 ? 's' : ''}`, Colors.red));
|
|
140
|
+
}
|
|
141
|
+
if (plan.newSolutions.length === 0 && plan.modifiedSolutions.length === 0 && plan.deletedSolutions.length === 0) {
|
|
142
|
+
console.log(color(' No changes detected', Colors.dim));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Display detailed sync plan (for verbose mode).
|
|
147
|
+
*
|
|
148
|
+
* @param plan Sync plan details
|
|
149
|
+
* @param remoteManifest Remote manifest for additional details
|
|
150
|
+
*/
|
|
151
|
+
export function displayVerboseSyncPlan(plan) {
|
|
152
|
+
// New solutions
|
|
153
|
+
for (const solutionId of plan.newSolutions) {
|
|
154
|
+
const files = plan.filesToDownload.filter(f => f.solution === solutionId);
|
|
155
|
+
const totalSize = files.reduce((sum, f) => sum + f.size, 0);
|
|
156
|
+
console.log(color(` + ${solutionId}`, Colors.green) + ` (new, ${files.length} files, ${formatBytes(totalSize)})`);
|
|
157
|
+
}
|
|
158
|
+
// Modified solutions
|
|
159
|
+
for (const solutionId of plan.modifiedSolutions) {
|
|
160
|
+
const downloads = plan.filesToDownload.filter(f => f.solution === solutionId);
|
|
161
|
+
const deletes = plan.filesToDelete.filter(f => f.solution === solutionId);
|
|
162
|
+
console.log(color(` ~ ${solutionId}`, Colors.yellow) + ` (${downloads.length} files to update, ${deletes.length} to delete)`);
|
|
163
|
+
}
|
|
164
|
+
// Deleted solutions
|
|
165
|
+
for (const solutionId of plan.deletedSolutions) {
|
|
166
|
+
console.log(color(` - ${solutionId}`, Colors.red) + ' (will be removed)');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Display dry run plan.
|
|
171
|
+
*
|
|
172
|
+
* @param plan Sync plan details
|
|
173
|
+
*/
|
|
174
|
+
export function displayDryRunPlan(plan) {
|
|
175
|
+
console.log(color('\nDry run - no changes will be made\n', Colors.yellow));
|
|
176
|
+
console.log('Changes that would be applied:');
|
|
177
|
+
displayVerboseSyncPlan(plan);
|
|
178
|
+
const totalDownloadSize = plan.filesToDownload.reduce((sum, f) => sum + f.size, 0);
|
|
179
|
+
console.log(`\nTotal: ${plan.filesToDownload.length} files to download (${formatBytes(totalDownloadSize)}), ${plan.filesToDelete.length} to delete`);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Display sync completion summary.
|
|
183
|
+
*
|
|
184
|
+
* @param stats Sync statistics
|
|
185
|
+
*/
|
|
186
|
+
export function displaySyncComplete(stats) {
|
|
187
|
+
console.log('\n'); // New line after progress bar
|
|
188
|
+
displaySuccess('Sync complete!');
|
|
189
|
+
console.log(` New: ${stats.newSolutions} solution${stats.newSolutions !== 1 ? 's' : ''}`);
|
|
190
|
+
console.log(` Updated: ${stats.updatedSolutions} solution${stats.updatedSolutions !== 1 ? 's' : ''}`);
|
|
191
|
+
console.log(` Removed: ${stats.deletedSolutions} solution${stats.deletedSolutions !== 1 ? 's' : ''}`);
|
|
192
|
+
console.log(` Files: ${stats.filesDownloaded} downloaded, ${stats.filesDeleted} deleted`);
|
|
193
|
+
console.log(` Size: ${formatBytes(stats.bytesDownloaded)}`);
|
|
194
|
+
console.log(` Duration: ${formatDuration(stats.durationMs)}`);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Display sync status.
|
|
198
|
+
*
|
|
199
|
+
* @param status Status information
|
|
200
|
+
*/
|
|
201
|
+
export function displaySyncStatus(status) {
|
|
202
|
+
displayHeader('Library Sync Status');
|
|
203
|
+
if (status.orgId) {
|
|
204
|
+
console.log(`Organization: ${color(status.orgId, Colors.cyan)}`);
|
|
205
|
+
}
|
|
206
|
+
if (status.endpoint) {
|
|
207
|
+
console.log(`Endpoint: ${color(status.endpoint, Colors.dim)}`);
|
|
208
|
+
}
|
|
209
|
+
if (status.lastSyncTime) {
|
|
210
|
+
console.log(`Last sync: ${status.lastSyncTime}${status.lastSyncRelative ? ` (${status.lastSyncRelative})` : ''}`);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
console.log(`Last sync: ${color('Never', Colors.yellow)}`);
|
|
214
|
+
}
|
|
215
|
+
console.log('\nLocal Library:');
|
|
216
|
+
console.log(` Solutions: ${status.solutionCount}`);
|
|
217
|
+
console.log(` Files: ${status.fileCount}`);
|
|
218
|
+
console.log(` Size: ${formatBytes(status.totalSize)}`);
|
|
219
|
+
if (status.syncStatus === 'in_progress') {
|
|
220
|
+
console.log(`\nStatus: ${color('Sync in progress', Colors.yellow)}`);
|
|
221
|
+
}
|
|
222
|
+
else if (status.syncStatus === 'interrupted' && status.pendingFiles) {
|
|
223
|
+
console.log(`\nStatus: ${color(`Interrupted (${status.pendingFiles} files pending)`, Colors.yellow)}`);
|
|
224
|
+
console.log(color(' Run /sync resume to continue', Colors.dim));
|
|
225
|
+
}
|
|
226
|
+
else if (status.syncStatus === 'error') {
|
|
227
|
+
console.log(`\nStatus: ${color('Error', Colors.red)}`);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
console.log(`\nStatus: ${color('Up to date', Colors.green)}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/sync/progress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Services registry merge logic for library sync.
|
|
3
|
+
*
|
|
4
|
+
* Handles merging remote and local services registries to preserve
|
|
5
|
+
* local-only services that are not being synced.
|
|
6
|
+
*/
|
|
7
|
+
import { ServicesRegistry } from '../types/sync.js';
|
|
8
|
+
/**
|
|
9
|
+
* Merge remote and local services registries.
|
|
10
|
+
*
|
|
11
|
+
* Strategy:
|
|
12
|
+
* - Remote services: Always updated (source of truth for synced solutions)
|
|
13
|
+
* - Local-only services: Preserved (not in remote, not being synced)
|
|
14
|
+
* - Deleted remote services: Removed from local if their solution was synced
|
|
15
|
+
*
|
|
16
|
+
* @param remote Services from remote manifest
|
|
17
|
+
* @param local Current local services (from container)
|
|
18
|
+
* @param syncedSolutions Set of solution IDs being synced
|
|
19
|
+
* @returns Merged services registry
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* Remote services: { "bom-analyzer": {...}, "cost-calc": {...} }
|
|
23
|
+
* Local services: { "bom-analyzer": {...}, "local-tool": {...} }
|
|
24
|
+
* Synced solutions: ["bom-analyzer", "cost-calc"]
|
|
25
|
+
*
|
|
26
|
+
* Result: { "bom-analyzer": {...}, // Updated from remote
|
|
27
|
+
* "cost-calc": {...}, // Added from remote
|
|
28
|
+
* "local-tool": {...} } // Preserved (not in synced solutions)
|
|
29
|
+
*/
|
|
30
|
+
export declare function mergeServicesRegistry(remote: ServicesRegistry, local: ServicesRegistry, syncedSolutions: Set<string>): ServicesRegistry;
|
|
31
|
+
/**
|
|
32
|
+
* Get the set of services that will be removed after merge.
|
|
33
|
+
*
|
|
34
|
+
* @param remote Remote services registry
|
|
35
|
+
* @param local Local services registry
|
|
36
|
+
* @param syncedSolutions Solutions being synced
|
|
37
|
+
* @returns Set of service names that will be removed
|
|
38
|
+
*/
|
|
39
|
+
export declare function getServicesToRemove(remote: ServicesRegistry, local: ServicesRegistry, syncedSolutions: Set<string>): Set<string>;
|
|
40
|
+
/**
|
|
41
|
+
* Get the set of new services that will be added after merge.
|
|
42
|
+
*
|
|
43
|
+
* @param remote Remote services registry
|
|
44
|
+
* @param local Local services registry
|
|
45
|
+
* @returns Set of service names that will be added
|
|
46
|
+
*/
|
|
47
|
+
export declare function getServicesToAdd(remote: ServicesRegistry, local: ServicesRegistry): Set<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Get the set of services that will be updated after merge.
|
|
50
|
+
*
|
|
51
|
+
* @param remote Remote services registry
|
|
52
|
+
* @param local Local services registry
|
|
53
|
+
* @returns Set of service names that will be updated
|
|
54
|
+
*/
|
|
55
|
+
export declare function getServicesToUpdate(remote: ServicesRegistry, local: ServicesRegistry): Set<string>;
|
|
56
|
+
/**
|
|
57
|
+
* Get a summary of changes to the services registry.
|
|
58
|
+
*
|
|
59
|
+
* @param remote Remote services registry
|
|
60
|
+
* @param local Local services registry
|
|
61
|
+
* @param syncedSolutions Solutions being synced
|
|
62
|
+
* @returns Object with added, updated, removed, and preserved service counts
|
|
63
|
+
*/
|
|
64
|
+
export declare function getServicesMergeSummary(remote: ServicesRegistry, local: ServicesRegistry, syncedSolutions: Set<string>): {
|
|
65
|
+
added: number;
|
|
66
|
+
updated: number;
|
|
67
|
+
removed: number;
|
|
68
|
+
preserved: number;
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=services.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/sync/services.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAgB,MAAM,kBAAkB,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,gBAAgB,EACvB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,GAC3B,gBAAgB,CAqBlB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,gBAAgB,EACvB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,GAC3B,GAAG,CAAC,MAAM,CAAC,CAab;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,gBAAgB,GACtB,GAAG,CAAC,MAAM,CAAC,CAUb;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,gBAAgB,GACtB,GAAG,CAAC,MAAM,CAAC,CAoBb;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,gBAAgB,EACvB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,GAC3B;IACD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,CAmBA"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Services registry merge logic for library sync.
|
|
3
|
+
*
|
|
4
|
+
* Handles merging remote and local services registries to preserve
|
|
5
|
+
* local-only services that are not being synced.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Merge remote and local services registries.
|
|
9
|
+
*
|
|
10
|
+
* Strategy:
|
|
11
|
+
* - Remote services: Always updated (source of truth for synced solutions)
|
|
12
|
+
* - Local-only services: Preserved (not in remote, not being synced)
|
|
13
|
+
* - Deleted remote services: Removed from local if their solution was synced
|
|
14
|
+
*
|
|
15
|
+
* @param remote Services from remote manifest
|
|
16
|
+
* @param local Current local services (from container)
|
|
17
|
+
* @param syncedSolutions Set of solution IDs being synced
|
|
18
|
+
* @returns Merged services registry
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* Remote services: { "bom-analyzer": {...}, "cost-calc": {...} }
|
|
22
|
+
* Local services: { "bom-analyzer": {...}, "local-tool": {...} }
|
|
23
|
+
* Synced solutions: ["bom-analyzer", "cost-calc"]
|
|
24
|
+
*
|
|
25
|
+
* Result: { "bom-analyzer": {...}, // Updated from remote
|
|
26
|
+
* "cost-calc": {...}, // Added from remote
|
|
27
|
+
* "local-tool": {...} } // Preserved (not in synced solutions)
|
|
28
|
+
*/
|
|
29
|
+
export function mergeServicesRegistry(remote, local, syncedSolutions) {
|
|
30
|
+
const merged = {};
|
|
31
|
+
// 1. Add all remote services (source of truth for synced content)
|
|
32
|
+
for (const [name, entry] of Object.entries(remote)) {
|
|
33
|
+
merged[name] = entry;
|
|
34
|
+
}
|
|
35
|
+
// 2. Preserve local-only services (not from synced solutions)
|
|
36
|
+
for (const [name, entry] of Object.entries(local)) {
|
|
37
|
+
// Skip if already in remote
|
|
38
|
+
if (merged[name])
|
|
39
|
+
continue;
|
|
40
|
+
// Skip if this service belongs to a synced solution (means it was deleted remotely)
|
|
41
|
+
if (syncedSolutions.has(entry.library_id))
|
|
42
|
+
continue;
|
|
43
|
+
// Preserve local-only service
|
|
44
|
+
merged[name] = entry;
|
|
45
|
+
}
|
|
46
|
+
return merged;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the set of services that will be removed after merge.
|
|
50
|
+
*
|
|
51
|
+
* @param remote Remote services registry
|
|
52
|
+
* @param local Local services registry
|
|
53
|
+
* @param syncedSolutions Solutions being synced
|
|
54
|
+
* @returns Set of service names that will be removed
|
|
55
|
+
*/
|
|
56
|
+
export function getServicesToRemove(remote, local, syncedSolutions) {
|
|
57
|
+
const toRemove = new Set();
|
|
58
|
+
for (const [name, entry] of Object.entries(local)) {
|
|
59
|
+
// Service will be removed if:
|
|
60
|
+
// 1. It's not in the remote registry
|
|
61
|
+
// 2. AND its solution was synced (meaning it was deleted remotely)
|
|
62
|
+
if (!remote[name] && syncedSolutions.has(entry.library_id)) {
|
|
63
|
+
toRemove.add(name);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return toRemove;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get the set of new services that will be added after merge.
|
|
70
|
+
*
|
|
71
|
+
* @param remote Remote services registry
|
|
72
|
+
* @param local Local services registry
|
|
73
|
+
* @returns Set of service names that will be added
|
|
74
|
+
*/
|
|
75
|
+
export function getServicesToAdd(remote, local) {
|
|
76
|
+
const toAdd = new Set();
|
|
77
|
+
for (const name of Object.keys(remote)) {
|
|
78
|
+
if (!local[name]) {
|
|
79
|
+
toAdd.add(name);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return toAdd;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the set of services that will be updated after merge.
|
|
86
|
+
*
|
|
87
|
+
* @param remote Remote services registry
|
|
88
|
+
* @param local Local services registry
|
|
89
|
+
* @returns Set of service names that will be updated
|
|
90
|
+
*/
|
|
91
|
+
export function getServicesToUpdate(remote, local) {
|
|
92
|
+
const toUpdate = new Set();
|
|
93
|
+
for (const [name, remoteEntry] of Object.entries(remote)) {
|
|
94
|
+
const localEntry = local[name];
|
|
95
|
+
if (localEntry) {
|
|
96
|
+
// Check if any field is different
|
|
97
|
+
if (localEntry.description !== remoteEntry.description ||
|
|
98
|
+
localEntry.library_id !== remoteEntry.library_id ||
|
|
99
|
+
localEntry.author_id !== remoteEntry.author_id ||
|
|
100
|
+
localEntry.registered_at !== remoteEntry.registered_at ||
|
|
101
|
+
JSON.stringify(localEntry.functions) !== JSON.stringify(remoteEntry.functions)) {
|
|
102
|
+
toUpdate.add(name);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return toUpdate;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get a summary of changes to the services registry.
|
|
110
|
+
*
|
|
111
|
+
* @param remote Remote services registry
|
|
112
|
+
* @param local Local services registry
|
|
113
|
+
* @param syncedSolutions Solutions being synced
|
|
114
|
+
* @returns Object with added, updated, removed, and preserved service counts
|
|
115
|
+
*/
|
|
116
|
+
export function getServicesMergeSummary(remote, local, syncedSolutions) {
|
|
117
|
+
const toAdd = getServicesToAdd(remote, local);
|
|
118
|
+
const toUpdate = getServicesToUpdate(remote, local);
|
|
119
|
+
const toRemove = getServicesToRemove(remote, local, syncedSolutions);
|
|
120
|
+
// Preserved = local services that are kept (not in remote, not synced)
|
|
121
|
+
let preserved = 0;
|
|
122
|
+
for (const [name, entry] of Object.entries(local)) {
|
|
123
|
+
if (!remote[name] && !syncedSolutions.has(entry.library_id)) {
|
|
124
|
+
preserved++;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
added: toAdd.size,
|
|
129
|
+
updated: toUpdate.size,
|
|
130
|
+
removed: toRemove.size,
|
|
131
|
+
preserved
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=services.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/sync/services.ts"],"names":[],"mappings":"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"}
|