vibecodingmachine-cli 2026.3.10-1807 ā 2026.3.14-1528
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/README.md +85 -85
- package/bin/vibecodingmachine.js +3 -0
- package/package.json +4 -3
- package/scripts/postinstall.js +161 -161
- package/src/commands/auth.js +100 -100
- package/src/commands/auto-direct.js +16 -5
- package/src/commands/auto-execution.js +25 -0
- package/src/commands/auto-requirement-management.js +8 -8
- package/src/commands/auto-status-helpers.js +5 -3
- package/src/commands/computers.js +318 -318
- package/src/commands/feature.js +123 -123
- package/src/commands/locale.js +72 -72
- package/src/commands/repo.js +163 -163
- package/src/commands/setup.js +93 -93
- package/src/commands/sync.js +287 -287
- package/src/index.js +5 -5
- package/src/utils/agent-selector.js +50 -50
- package/src/utils/asset-cleanup.js +60 -60
- package/src/utils/auto-mode-ansi-ui.js +237 -237
- package/src/utils/auto-mode-simple-ui.js +141 -141
- package/src/utils/copy-with-progress.js +167 -167
- package/src/utils/download-with-progress.js +84 -84
- package/src/utils/keyboard-handler.js +153 -153
- package/src/utils/kiro-installer.js +178 -178
- package/src/utils/logger.js +4 -4
- package/src/utils/persistent-header.js +114 -114
- package/src/utils/prompt-helper.js +63 -63
- package/src/utils/provider-checker/agent-checker.js +25 -1
- package/src/utils/provider-checker/agent-runner.js +115 -37
- package/src/utils/provider-checker/agents-manager.js +210 -0
- package/src/utils/provider-checker/provider-validator.js +5 -49
- package/src/utils/provider-checker/requirements-manager.js +86 -65
- package/src/utils/provider-checker/test-requirements.js +25 -17
- package/src/utils/status-card.js +121 -121
- package/src/utils/stdout-interceptor.js +127 -127
- package/src/utils/user-tracking.js +299 -299
package/src/commands/sync.js
CHANGED
|
@@ -1,287 +1,287 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
|
-
const Table = require('cli-table3');
|
|
3
|
-
const SyncEngine = require('vibecodingmachine-core/src/sync/sync-engine');
|
|
4
|
-
const { t, errorReporter } = require('vibecodingmachine-core');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Trigger immediate sync
|
|
8
|
-
*/
|
|
9
|
-
async function syncNow() {
|
|
10
|
-
const syncEngine = new SyncEngine();
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
console.log(chalk.cyan(`\nš ${t('sync.starting')}\n`));
|
|
14
|
-
|
|
15
|
-
await syncEngine.initialize();
|
|
16
|
-
|
|
17
|
-
// Listen for sync completion
|
|
18
|
-
const syncPromise = new Promise((resolve, reject) => {
|
|
19
|
-
syncEngine.once('sync-complete', (result) => {
|
|
20
|
-
if (result.status === 'error') {
|
|
21
|
-
reject(new Error(result.error || 'Sync failed'));
|
|
22
|
-
} else {
|
|
23
|
-
resolve(result);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Start sync
|
|
29
|
-
await syncEngine.sync();
|
|
30
|
-
|
|
31
|
-
// Wait for completion
|
|
32
|
-
const result = await syncPromise;
|
|
33
|
-
|
|
34
|
-
const status = syncEngine.getStatus();
|
|
35
|
-
|
|
36
|
-
console.log(chalk.green(`ā ${t('sync.complete')}\n`));
|
|
37
|
-
console.log(chalk.white(t('sync.last.sync').padEnd(17)) + new Date(status.lastSyncTime).toLocaleString());
|
|
38
|
-
console.log(chalk.white(t('sync.remote.changes').padEnd(17)) + (result.remoteChanges || 0));
|
|
39
|
-
console.log(chalk.white(t('sync.local.changes').padEnd(17)) + (result.localChanges || 0));
|
|
40
|
-
console.log(chalk.white(t('sync.conflicts').padEnd(17)) + (result.conflicts || 0));
|
|
41
|
-
console.log(chalk.white(t('sync.queued.changes').padEnd(17)) + status.queuedChanges);
|
|
42
|
-
console.log('');
|
|
43
|
-
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error(chalk.red(`\nā ${t('sync.failed')}`), error.message);
|
|
46
|
-
console.log(chalk.gray(`\n${t('sync.tip.aws')}\n`));
|
|
47
|
-
await errorReporter.reportError(error, {
|
|
48
|
-
command: 'syncNow'
|
|
49
|
-
});
|
|
50
|
-
// Don't throw - just log the error
|
|
51
|
-
} finally {
|
|
52
|
-
syncEngine.stop();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Show sync status and statistics
|
|
58
|
-
*/
|
|
59
|
-
async function syncStatus() {
|
|
60
|
-
const syncEngine = new SyncEngine();
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
await syncEngine.initialize();
|
|
64
|
-
|
|
65
|
-
const status = syncEngine.getStatus();
|
|
66
|
-
|
|
67
|
-
console.log('\n' + chalk.bold.cyan(t('sync.status.title')));
|
|
68
|
-
console.log(chalk.gray('ā'.repeat(60)));
|
|
69
|
-
|
|
70
|
-
// Connection status
|
|
71
|
-
const onlineIcon = status.isOnline ? chalk.green('ā') : chalk.red('ā');
|
|
72
|
-
const onlineText = status.isOnline ? t('sync.status.online') : t('sync.status.offline');
|
|
73
|
-
console.log(chalk.white(t('sync.connection').padEnd(17)) + onlineIcon + ' ' + onlineText);
|
|
74
|
-
|
|
75
|
-
// Sync status
|
|
76
|
-
const syncingIcon = status.isSyncing ? chalk.yellow('ā³') : chalk.gray('ā');
|
|
77
|
-
const syncingText = status.isSyncing ? t('sync.status.syncing') : t('sync.status.idle');
|
|
78
|
-
console.log(chalk.white(t('sync.status').padEnd(17)) + syncingIcon + ' ' + syncingText);
|
|
79
|
-
|
|
80
|
-
// Last sync
|
|
81
|
-
const lastSync = status.lastSyncTime
|
|
82
|
-
? new Date(status.lastSyncTime).toLocaleString()
|
|
83
|
-
: t('sync.never');
|
|
84
|
-
console.log(chalk.white(t('sync.last.sync').padEnd(17)) + lastSync);
|
|
85
|
-
|
|
86
|
-
// Queued changes
|
|
87
|
-
const queueColor = status.queuedChanges > 0 ? chalk.yellow : chalk.gray;
|
|
88
|
-
console.log(chalk.white(t('sync.queued.changes').padEnd(17)) + queueColor(status.queuedChanges));
|
|
89
|
-
|
|
90
|
-
// Conflict strategy
|
|
91
|
-
console.log(chalk.white(t('sync.conflict.mode').padEnd(17)) + status.conflictStrategy);
|
|
92
|
-
|
|
93
|
-
// Computer ID
|
|
94
|
-
console.log(chalk.white(t('sync.computer.id').padEnd(17)) + status.computerId);
|
|
95
|
-
|
|
96
|
-
console.log('');
|
|
97
|
-
|
|
98
|
-
// Show recent sync events
|
|
99
|
-
const history = syncEngine.getHistory(5);
|
|
100
|
-
if (history.length > 0) {
|
|
101
|
-
console.log(chalk.bold.cyan(t('sync.recent.events')));
|
|
102
|
-
console.log(chalk.gray('ā'.repeat(60)));
|
|
103
|
-
|
|
104
|
-
for (const event of history.reverse()) {
|
|
105
|
-
const time = new Date(event.timestamp).toLocaleTimeString();
|
|
106
|
-
const icon = event.type === 'conflict-resolution' ? chalk.yellow('ā ') : chalk.gray('ā¢');
|
|
107
|
-
console.log(`${icon} ${chalk.gray(time)} ${event.type}`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
console.log('');
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error(chalk.red(`\nā ${t('sync.status.failed')}`), error.message);
|
|
115
|
-
await errorReporter.reportError(error, {
|
|
116
|
-
command: 'syncStatus'
|
|
117
|
-
});
|
|
118
|
-
throw error;
|
|
119
|
-
} finally {
|
|
120
|
-
syncEngine.stop();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* View pending changes in offline queue
|
|
126
|
-
*/
|
|
127
|
-
async function viewQueue() {
|
|
128
|
-
const syncEngine = new SyncEngine();
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
await syncEngine.initialize();
|
|
132
|
-
|
|
133
|
-
const status = syncEngine.getStatus();
|
|
134
|
-
|
|
135
|
-
if (status.queuedChanges === 0) {
|
|
136
|
-
console.log(chalk.gray(`\n${t('sync.queue.no.pending')}\n`));
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
console.log(chalk.cyan(`\nš ${t('sync.queue.title', { count: status.queuedChanges })}\n`));
|
|
141
|
-
|
|
142
|
-
// Create table
|
|
143
|
-
const table = new Table({
|
|
144
|
-
head: [
|
|
145
|
-
chalk.cyan(t('sync.queue.header.number')),
|
|
146
|
-
chalk.cyan(t('sync.queue.header.type')),
|
|
147
|
-
chalk.cyan(t('sync.queue.header.requirement')),
|
|
148
|
-
chalk.cyan(t('sync.queue.header.timestamp'))
|
|
149
|
-
],
|
|
150
|
-
colWidths: [5, 15, 40, 20]
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// Add rows (accessing internal queue - in production, add a public getter)
|
|
154
|
-
syncEngine.offlineQueue.forEach((change, index) => {
|
|
155
|
-
table.push([
|
|
156
|
-
index + 1,
|
|
157
|
-
change.type || 'update',
|
|
158
|
-
truncate(change.requirementName || change.requirementId || '-', 38),
|
|
159
|
-
new Date(change.timestamp).toLocaleString()
|
|
160
|
-
]);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
console.log(table.toString() + '\n');
|
|
164
|
-
|
|
165
|
-
console.log(chalk.gray(`${t('sync.queue.will.sync')}\n`));
|
|
166
|
-
console.log(chalk.white(t('sync.queue.commands')));
|
|
167
|
-
console.log(chalk.gray(' vcm sync:force ') + `- ${t('sync.queue.force.now')}`);
|
|
168
|
-
console.log(chalk.gray(' vcm sync:now ') + `- ${t('sync.queue.sync.online')}`);
|
|
169
|
-
console.log('');
|
|
170
|
-
|
|
171
|
-
} catch (error) {
|
|
172
|
-
console.error(chalk.red(`\nā ${t('sync.queue.view.failed')}`), error.message);
|
|
173
|
-
throw error;
|
|
174
|
-
} finally {
|
|
175
|
-
syncEngine.stop();
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Force sync even if offline
|
|
181
|
-
*/
|
|
182
|
-
async function forceSync() {
|
|
183
|
-
const syncEngine = new SyncEngine();
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
console.log(chalk.yellow(`\nā ${t('sync.force.starting')}\n`));
|
|
187
|
-
|
|
188
|
-
await syncEngine.initialize();
|
|
189
|
-
|
|
190
|
-
// Temporarily set online
|
|
191
|
-
const wasOnline = syncEngine.isOnline;
|
|
192
|
-
syncEngine.setOnlineMode(true);
|
|
193
|
-
|
|
194
|
-
try {
|
|
195
|
-
await syncEngine.sync();
|
|
196
|
-
console.log(chalk.green(`ā ${t('sync.force.complete')}\n`));
|
|
197
|
-
} finally {
|
|
198
|
-
// Restore original online status
|
|
199
|
-
syncEngine.setOnlineMode(wasOnline);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
} catch (error) {
|
|
203
|
-
console.error(chalk.red(`\nā ${t('sync.force.failed')}`), error.message);
|
|
204
|
-
console.log(chalk.gray(`\n${t('sync.force.unreachable')}\n`));
|
|
205
|
-
throw error;
|
|
206
|
-
} finally {
|
|
207
|
-
syncEngine.stop();
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* View sync history
|
|
213
|
-
*/
|
|
214
|
-
async function viewHistory(options = {}) {
|
|
215
|
-
const syncEngine = new SyncEngine();
|
|
216
|
-
|
|
217
|
-
try {
|
|
218
|
-
await syncEngine.initialize();
|
|
219
|
-
|
|
220
|
-
const limit = parseInt(options.limit) || 50;
|
|
221
|
-
const history = syncEngine.getHistory(limit);
|
|
222
|
-
|
|
223
|
-
if (history.length === 0) {
|
|
224
|
-
console.log(chalk.gray(`\n${t('sync.history.no.events')}\n`));
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
console.log(chalk.cyan(`\nš ${t('sync.history.title', { count: history.length })}\n`));
|
|
229
|
-
|
|
230
|
-
// Create table
|
|
231
|
-
const table = new Table({
|
|
232
|
-
head: [
|
|
233
|
-
chalk.cyan(t('sync.history.header.time')),
|
|
234
|
-
chalk.cyan(t('sync.history.header.type')),
|
|
235
|
-
chalk.cyan(t('sync.history.header.details'))
|
|
236
|
-
],
|
|
237
|
-
colWidths: [20, 20, 50]
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
// Add rows
|
|
241
|
-
for (const event of history.reverse()) {
|
|
242
|
-
const time = new Date(event.timestamp).toLocaleString();
|
|
243
|
-
const type = event.type;
|
|
244
|
-
const details = getEventDetails(event);
|
|
245
|
-
|
|
246
|
-
table.push([time, type, details]);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
console.log(table.toString() + '\n');
|
|
250
|
-
|
|
251
|
-
} catch (error) {
|
|
252
|
-
console.error(chalk.red(`\nā ${t('sync.history.view.failed')}`), error.message);
|
|
253
|
-
throw error;
|
|
254
|
-
} finally {
|
|
255
|
-
syncEngine.stop();
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Helper functions
|
|
260
|
-
|
|
261
|
-
function truncate(str, maxLength) {
|
|
262
|
-
if (str.length <= maxLength) return str;
|
|
263
|
-
return str.substring(0, maxLength - 3) + '...';
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function getEventDetails(event) {
|
|
267
|
-
switch (event.type) {
|
|
268
|
-
case 'conflict-resolution':
|
|
269
|
-
return t('sync.event.resolved', { id: event.resolution?.requirementId || 'unknown' });
|
|
270
|
-
case 'sync-complete':
|
|
271
|
-
return t('sync.event.remote.local', { remote: event.remoteChanges || 0, local: event.localChanges || 0 });
|
|
272
|
-
case 'remote-change-applied':
|
|
273
|
-
return t('sync.event.applied', { id: event.change?.requirementId || 'unknown' });
|
|
274
|
-
case 'local-change-pushed':
|
|
275
|
-
return t('sync.event.pushed', { id: event.change?.requirementId || 'unknown' });
|
|
276
|
-
default:
|
|
277
|
-
return JSON.stringify(event).substring(0, 47);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
module.exports = {
|
|
282
|
-
syncNow,
|
|
283
|
-
syncStatus,
|
|
284
|
-
viewQueue,
|
|
285
|
-
forceSync,
|
|
286
|
-
viewHistory
|
|
287
|
-
};
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const Table = require('cli-table3');
|
|
3
|
+
const SyncEngine = require('vibecodingmachine-core/src/sync/sync-engine');
|
|
4
|
+
const { t, errorReporter } = require('vibecodingmachine-core');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Trigger immediate sync
|
|
8
|
+
*/
|
|
9
|
+
async function syncNow() {
|
|
10
|
+
const syncEngine = new SyncEngine();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
console.log(chalk.cyan(`\nš ${t('sync.starting')}\n`));
|
|
14
|
+
|
|
15
|
+
await syncEngine.initialize();
|
|
16
|
+
|
|
17
|
+
// Listen for sync completion
|
|
18
|
+
const syncPromise = new Promise((resolve, reject) => {
|
|
19
|
+
syncEngine.once('sync-complete', (result) => {
|
|
20
|
+
if (result.status === 'error') {
|
|
21
|
+
reject(new Error(result.error || 'Sync failed'));
|
|
22
|
+
} else {
|
|
23
|
+
resolve(result);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Start sync
|
|
29
|
+
await syncEngine.sync();
|
|
30
|
+
|
|
31
|
+
// Wait for completion
|
|
32
|
+
const result = await syncPromise;
|
|
33
|
+
|
|
34
|
+
const status = syncEngine.getStatus();
|
|
35
|
+
|
|
36
|
+
console.log(chalk.green(`ā ${t('sync.complete')}\n`));
|
|
37
|
+
console.log(chalk.white(t('sync.last.sync').padEnd(17)) + new Date(status.lastSyncTime).toLocaleString());
|
|
38
|
+
console.log(chalk.white(t('sync.remote.changes').padEnd(17)) + (result.remoteChanges || 0));
|
|
39
|
+
console.log(chalk.white(t('sync.local.changes').padEnd(17)) + (result.localChanges || 0));
|
|
40
|
+
console.log(chalk.white(t('sync.conflicts').padEnd(17)) + (result.conflicts || 0));
|
|
41
|
+
console.log(chalk.white(t('sync.queued.changes').padEnd(17)) + status.queuedChanges);
|
|
42
|
+
console.log('');
|
|
43
|
+
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(chalk.red(`\nā ${t('sync.failed')}`), error.message);
|
|
46
|
+
console.log(chalk.gray(`\n${t('sync.tip.aws')}\n`));
|
|
47
|
+
await errorReporter.reportError(error, {
|
|
48
|
+
command: 'syncNow'
|
|
49
|
+
});
|
|
50
|
+
// Don't throw - just log the error
|
|
51
|
+
} finally {
|
|
52
|
+
syncEngine.stop();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Show sync status and statistics
|
|
58
|
+
*/
|
|
59
|
+
async function syncStatus() {
|
|
60
|
+
const syncEngine = new SyncEngine();
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
await syncEngine.initialize();
|
|
64
|
+
|
|
65
|
+
const status = syncEngine.getStatus();
|
|
66
|
+
|
|
67
|
+
console.log('\n' + chalk.bold.cyan(t('sync.status.title')));
|
|
68
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
69
|
+
|
|
70
|
+
// Connection status
|
|
71
|
+
const onlineIcon = status.isOnline ? chalk.green('ā') : chalk.red('ā');
|
|
72
|
+
const onlineText = status.isOnline ? t('sync.status.online') : t('sync.status.offline');
|
|
73
|
+
console.log(chalk.white(t('sync.connection').padEnd(17)) + onlineIcon + ' ' + onlineText);
|
|
74
|
+
|
|
75
|
+
// Sync status
|
|
76
|
+
const syncingIcon = status.isSyncing ? chalk.yellow('ā³') : chalk.gray('ā');
|
|
77
|
+
const syncingText = status.isSyncing ? t('sync.status.syncing') : t('sync.status.idle');
|
|
78
|
+
console.log(chalk.white(t('sync.status').padEnd(17)) + syncingIcon + ' ' + syncingText);
|
|
79
|
+
|
|
80
|
+
// Last sync
|
|
81
|
+
const lastSync = status.lastSyncTime
|
|
82
|
+
? new Date(status.lastSyncTime).toLocaleString()
|
|
83
|
+
: t('sync.never');
|
|
84
|
+
console.log(chalk.white(t('sync.last.sync').padEnd(17)) + lastSync);
|
|
85
|
+
|
|
86
|
+
// Queued changes
|
|
87
|
+
const queueColor = status.queuedChanges > 0 ? chalk.yellow : chalk.gray;
|
|
88
|
+
console.log(chalk.white(t('sync.queued.changes').padEnd(17)) + queueColor(status.queuedChanges));
|
|
89
|
+
|
|
90
|
+
// Conflict strategy
|
|
91
|
+
console.log(chalk.white(t('sync.conflict.mode').padEnd(17)) + status.conflictStrategy);
|
|
92
|
+
|
|
93
|
+
// Computer ID
|
|
94
|
+
console.log(chalk.white(t('sync.computer.id').padEnd(17)) + status.computerId);
|
|
95
|
+
|
|
96
|
+
console.log('');
|
|
97
|
+
|
|
98
|
+
// Show recent sync events
|
|
99
|
+
const history = syncEngine.getHistory(5);
|
|
100
|
+
if (history.length > 0) {
|
|
101
|
+
console.log(chalk.bold.cyan(t('sync.recent.events')));
|
|
102
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
103
|
+
|
|
104
|
+
for (const event of history.reverse()) {
|
|
105
|
+
const time = new Date(event.timestamp).toLocaleTimeString();
|
|
106
|
+
const icon = event.type === 'conflict-resolution' ? chalk.yellow('ā ') : chalk.gray('ā¢');
|
|
107
|
+
console.log(`${icon} ${chalk.gray(time)} ${event.type}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log('');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error(chalk.red(`\nā ${t('sync.status.failed')}`), error.message);
|
|
115
|
+
await errorReporter.reportError(error, {
|
|
116
|
+
command: 'syncStatus'
|
|
117
|
+
});
|
|
118
|
+
throw error;
|
|
119
|
+
} finally {
|
|
120
|
+
syncEngine.stop();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* View pending changes in offline queue
|
|
126
|
+
*/
|
|
127
|
+
async function viewQueue() {
|
|
128
|
+
const syncEngine = new SyncEngine();
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
await syncEngine.initialize();
|
|
132
|
+
|
|
133
|
+
const status = syncEngine.getStatus();
|
|
134
|
+
|
|
135
|
+
if (status.queuedChanges === 0) {
|
|
136
|
+
console.log(chalk.gray(`\n${t('sync.queue.no.pending')}\n`));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log(chalk.cyan(`\nš ${t('sync.queue.title', { count: status.queuedChanges })}\n`));
|
|
141
|
+
|
|
142
|
+
// Create table
|
|
143
|
+
const table = new Table({
|
|
144
|
+
head: [
|
|
145
|
+
chalk.cyan(t('sync.queue.header.number')),
|
|
146
|
+
chalk.cyan(t('sync.queue.header.type')),
|
|
147
|
+
chalk.cyan(t('sync.queue.header.requirement')),
|
|
148
|
+
chalk.cyan(t('sync.queue.header.timestamp'))
|
|
149
|
+
],
|
|
150
|
+
colWidths: [5, 15, 40, 20]
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Add rows (accessing internal queue - in production, add a public getter)
|
|
154
|
+
syncEngine.offlineQueue.forEach((change, index) => {
|
|
155
|
+
table.push([
|
|
156
|
+
index + 1,
|
|
157
|
+
change.type || 'update',
|
|
158
|
+
truncate(change.requirementName || change.requirementId || '-', 38),
|
|
159
|
+
new Date(change.timestamp).toLocaleString()
|
|
160
|
+
]);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
console.log(table.toString() + '\n');
|
|
164
|
+
|
|
165
|
+
console.log(chalk.gray(`${t('sync.queue.will.sync')}\n`));
|
|
166
|
+
console.log(chalk.white(t('sync.queue.commands')));
|
|
167
|
+
console.log(chalk.gray(' vcm sync:force ') + `- ${t('sync.queue.force.now')}`);
|
|
168
|
+
console.log(chalk.gray(' vcm sync:now ') + `- ${t('sync.queue.sync.online')}`);
|
|
169
|
+
console.log('');
|
|
170
|
+
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error(chalk.red(`\nā ${t('sync.queue.view.failed')}`), error.message);
|
|
173
|
+
throw error;
|
|
174
|
+
} finally {
|
|
175
|
+
syncEngine.stop();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Force sync even if offline
|
|
181
|
+
*/
|
|
182
|
+
async function forceSync() {
|
|
183
|
+
const syncEngine = new SyncEngine();
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
console.log(chalk.yellow(`\nā ${t('sync.force.starting')}\n`));
|
|
187
|
+
|
|
188
|
+
await syncEngine.initialize();
|
|
189
|
+
|
|
190
|
+
// Temporarily set online
|
|
191
|
+
const wasOnline = syncEngine.isOnline;
|
|
192
|
+
syncEngine.setOnlineMode(true);
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
await syncEngine.sync();
|
|
196
|
+
console.log(chalk.green(`ā ${t('sync.force.complete')}\n`));
|
|
197
|
+
} finally {
|
|
198
|
+
// Restore original online status
|
|
199
|
+
syncEngine.setOnlineMode(wasOnline);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error(chalk.red(`\nā ${t('sync.force.failed')}`), error.message);
|
|
204
|
+
console.log(chalk.gray(`\n${t('sync.force.unreachable')}\n`));
|
|
205
|
+
throw error;
|
|
206
|
+
} finally {
|
|
207
|
+
syncEngine.stop();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* View sync history
|
|
213
|
+
*/
|
|
214
|
+
async function viewHistory(options = {}) {
|
|
215
|
+
const syncEngine = new SyncEngine();
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
await syncEngine.initialize();
|
|
219
|
+
|
|
220
|
+
const limit = parseInt(options.limit) || 50;
|
|
221
|
+
const history = syncEngine.getHistory(limit);
|
|
222
|
+
|
|
223
|
+
if (history.length === 0) {
|
|
224
|
+
console.log(chalk.gray(`\n${t('sync.history.no.events')}\n`));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
console.log(chalk.cyan(`\nš ${t('sync.history.title', { count: history.length })}\n`));
|
|
229
|
+
|
|
230
|
+
// Create table
|
|
231
|
+
const table = new Table({
|
|
232
|
+
head: [
|
|
233
|
+
chalk.cyan(t('sync.history.header.time')),
|
|
234
|
+
chalk.cyan(t('sync.history.header.type')),
|
|
235
|
+
chalk.cyan(t('sync.history.header.details'))
|
|
236
|
+
],
|
|
237
|
+
colWidths: [20, 20, 50]
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Add rows
|
|
241
|
+
for (const event of history.reverse()) {
|
|
242
|
+
const time = new Date(event.timestamp).toLocaleString();
|
|
243
|
+
const type = event.type;
|
|
244
|
+
const details = getEventDetails(event);
|
|
245
|
+
|
|
246
|
+
table.push([time, type, details]);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
console.log(table.toString() + '\n');
|
|
250
|
+
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error(chalk.red(`\nā ${t('sync.history.view.failed')}`), error.message);
|
|
253
|
+
throw error;
|
|
254
|
+
} finally {
|
|
255
|
+
syncEngine.stop();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Helper functions
|
|
260
|
+
|
|
261
|
+
function truncate(str, maxLength) {
|
|
262
|
+
if (str.length <= maxLength) return str;
|
|
263
|
+
return str.substring(0, maxLength - 3) + '...';
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function getEventDetails(event) {
|
|
267
|
+
switch (event.type) {
|
|
268
|
+
case 'conflict-resolution':
|
|
269
|
+
return t('sync.event.resolved', { id: event.resolution?.requirementId || 'unknown' });
|
|
270
|
+
case 'sync-complete':
|
|
271
|
+
return t('sync.event.remote.local', { remote: event.remoteChanges || 0, local: event.localChanges || 0 });
|
|
272
|
+
case 'remote-change-applied':
|
|
273
|
+
return t('sync.event.applied', { id: event.change?.requirementId || 'unknown' });
|
|
274
|
+
case 'local-change-pushed':
|
|
275
|
+
return t('sync.event.pushed', { id: event.change?.requirementId || 'unknown' });
|
|
276
|
+
default:
|
|
277
|
+
return JSON.stringify(event).substring(0, 47);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
module.exports = {
|
|
282
|
+
syncNow,
|
|
283
|
+
syncStatus,
|
|
284
|
+
viewQueue,
|
|
285
|
+
forceSync,
|
|
286
|
+
viewHistory
|
|
287
|
+
};
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Entry point placeholder to satisfy package.json main
|
|
2
|
-
module.exports = {};
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// Entry point placeholder to satisfy package.json main
|
|
2
|
+
module.exports = {};
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|