@exreve/exk 1.0.55 ā 1.0.56
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/bin/exk +5 -1
- package/dist/ttc-cli.tar.gz +0 -0
- package/package.json +1 -1
- package/dist/agentLogger.js +0 -143
- package/dist/app-child.js +0 -1038
- package/dist/appHandlers.js +0 -142
- package/dist/appManager.js +0 -212
- package/dist/appRunner.js +0 -383
- package/dist/benchmark-startup.js +0 -347
- package/dist/cloudflaredHandlers.js +0 -279
- package/dist/containerHandlers.js +0 -193
- package/dist/fsHandlers.js +0 -86
- package/dist/githubHandlers.js +0 -525
- package/dist/index.js +0 -1262
- package/dist/moduleMcpServer.js +0 -284
- package/dist/openaiAdapter.js +0 -181
- package/dist/projectAnalyzer.js +0 -330
- package/dist/projectManager.js +0 -69
- package/dist/runnerGenerator.js +0 -210
- package/dist/sessionHandlers.js +0 -271
- package/dist/skills/index.js +0 -117
- package/dist/transferService.js +0 -284
- package/dist/updateHandlers.js +0 -82
- package/dist/updater.js +0 -422
package/dist/updateHandlers.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Update & Version Handlers Module
|
|
3
|
-
*
|
|
4
|
-
* Handles update:check, update:start, version:info operations.
|
|
5
|
-
*/
|
|
6
|
-
import fsSync from 'fs';
|
|
7
|
-
import os from 'os';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import { createHash } from 'crypto';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
11
|
-
export function registerUpdateHandlers(socket, _foreground, readConfig, requestUpdateFromParent) {
|
|
12
|
-
socket.on('update:check', async (_data, callback) => {
|
|
13
|
-
try {
|
|
14
|
-
const config = await readConfig();
|
|
15
|
-
const currentHash = createHash('sha256').update(fsSync.readFileSync(fileURLToPath(import.meta.url))).digest('hex');
|
|
16
|
-
const response = await fetch(`${config.apiUrl}/update/check`, {
|
|
17
|
-
method: 'POST',
|
|
18
|
-
headers: { 'Content-Type': 'application/json' },
|
|
19
|
-
body: JSON.stringify({
|
|
20
|
-
hash: currentHash,
|
|
21
|
-
platform: os.platform(),
|
|
22
|
-
arch: os.arch()
|
|
23
|
-
})
|
|
24
|
-
});
|
|
25
|
-
if (!response.ok) {
|
|
26
|
-
callback?.({ success: false, error: `HTTP ${response.status}` });
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
const info = await response.json();
|
|
30
|
-
callback?.({
|
|
31
|
-
success: true,
|
|
32
|
-
updateAvailable: info.updateAvailable,
|
|
33
|
-
version: info.version,
|
|
34
|
-
changelog: info.changelog,
|
|
35
|
-
size: info.size
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
callback?.({ success: false, error: error.message });
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
socket.on('update:start', async (_data, callback) => {
|
|
43
|
-
try {
|
|
44
|
-
requestUpdateFromParent();
|
|
45
|
-
callback?.({
|
|
46
|
-
success: true,
|
|
47
|
-
message: 'Update initiated. The CLI will restart automatically when complete.'
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
callback?.({ success: false, error: error.message });
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
socket.on('version:info', async (_data, callback) => {
|
|
55
|
-
try {
|
|
56
|
-
const currentHash = createHash('sha256').update(fsSync.readFileSync(fileURLToPath(import.meta.url))).digest('hex');
|
|
57
|
-
let version = 'unknown';
|
|
58
|
-
let date = undefined;
|
|
59
|
-
try {
|
|
60
|
-
const hashesPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'binary-hashes.json');
|
|
61
|
-
const hashes = JSON.parse(fsSync.readFileSync(hashesPath, 'utf-8'));
|
|
62
|
-
if (hashes['js-bundle']) {
|
|
63
|
-
version = hashes['js-bundle'].version || version;
|
|
64
|
-
date = hashes['js-bundle'].date;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
catch { }
|
|
68
|
-
callback?.({
|
|
69
|
-
success: true,
|
|
70
|
-
version,
|
|
71
|
-
hash: currentHash.substring(0, 16) + '...',
|
|
72
|
-
date,
|
|
73
|
-
nodeVersion: process.version,
|
|
74
|
-
platform: os.platform(),
|
|
75
|
-
arch: os.arch()
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
callback?.({ success: false, error: error.message });
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
package/dist/updater.js
DELETED
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* TalkToCode CLI Updater - Standalone Update Process
|
|
4
|
-
*
|
|
5
|
-
* This is a minimal, robust updater that:
|
|
6
|
-
* 1. Runs as the main process
|
|
7
|
-
* 2. Spawns the app as a child process
|
|
8
|
-
* 3. Can update itself even if app is corrupted
|
|
9
|
-
* 4. Can recover from failed updates
|
|
10
|
-
*
|
|
11
|
-
* Architecture:
|
|
12
|
-
* - updater.ts (this file) -> Main process, handles updates
|
|
13
|
-
* - app-child.ts -> Child process, contains all app logic
|
|
14
|
-
*
|
|
15
|
-
* File structure:
|
|
16
|
-
* - ttc (updater) -> Main entry point
|
|
17
|
-
* - ttc-app.js -> Child bundle (updated via updates)
|
|
18
|
-
* - ttc-app.js.old -> Backup of last version
|
|
19
|
-
* - ttc-app.js.backup -> Secondary backup
|
|
20
|
-
*/
|
|
21
|
-
import { spawn } from 'child_process';
|
|
22
|
-
import fs from 'fs/promises';
|
|
23
|
-
import fsSync from 'fs';
|
|
24
|
-
import path from 'path';
|
|
25
|
-
import os from 'os';
|
|
26
|
-
import crypto from 'crypto';
|
|
27
|
-
import { fileURLToPath } from 'url';
|
|
28
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
29
|
-
const CONFIG_DIR = path.join(os.homedir(), '.talk-to-code');
|
|
30
|
-
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
31
|
-
// File paths
|
|
32
|
-
const APP_BUNDLE = path.join(__dirname, 'dist', 'app-child.js');
|
|
33
|
-
const APP_BUNDLE_BACKUP = APP_BUNDLE + '.backup';
|
|
34
|
-
const APP_BUNDLE_OLD = APP_BUNDLE + '.old';
|
|
35
|
-
const BUNDLE_HASHES_FILE = path.join(__dirname, 'binary-hashes.json');
|
|
36
|
-
// State
|
|
37
|
-
let childProcess = null;
|
|
38
|
-
let isUpdating = false;
|
|
39
|
-
let restartRequested = false;
|
|
40
|
-
async function readConfig() {
|
|
41
|
-
try {
|
|
42
|
-
const data = await fs.readFile(CONFIG_FILE, 'utf-8');
|
|
43
|
-
return JSON.parse(data);
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
return { apiUrl: 'https://api.talk-to-code.com' };
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// ============ Hash Utilities ============
|
|
50
|
-
function calculateHash(filePath) {
|
|
51
|
-
try {
|
|
52
|
-
const fileData = fsSync.readFileSync(filePath);
|
|
53
|
-
return crypto.createHash('sha256').update(fileData).digest('hex');
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
return '';
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
async function getBundleHashes() {
|
|
60
|
-
try {
|
|
61
|
-
const data = await fs.readFile(BUNDLE_HASHES_FILE, 'utf-8');
|
|
62
|
-
return JSON.parse(data);
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return {};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
async function checkForUpdates() {
|
|
69
|
-
try {
|
|
70
|
-
const config = await readConfig();
|
|
71
|
-
const currentHash = calculateHash(APP_BUNDLE);
|
|
72
|
-
if (!currentHash) {
|
|
73
|
-
console.warn('ā ļø Cannot calculate current bundle hash');
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
const response = await fetch(`${config.apiUrl}/update/check`, {
|
|
77
|
-
method: 'POST',
|
|
78
|
-
headers: { 'Content-Type': 'application/json' },
|
|
79
|
-
body: JSON.stringify({
|
|
80
|
-
hash: currentHash,
|
|
81
|
-
platform: os.platform(),
|
|
82
|
-
arch: os.arch()
|
|
83
|
-
})
|
|
84
|
-
});
|
|
85
|
-
if (!response.ok) {
|
|
86
|
-
console.warn(`ā ļø Update check failed: HTTP ${response.status}`);
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
const info = await response.json();
|
|
90
|
-
return info;
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
console.warn(`ā ļø Update check failed: ${error.message}`);
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
async function downloadUpdate(downloadUrl, expectedHash) {
|
|
98
|
-
console.log('š„ Downloading update...');
|
|
99
|
-
const response = await fetch(downloadUrl);
|
|
100
|
-
if (!response.ok) {
|
|
101
|
-
throw new Error(`Download failed: HTTP ${response.status}`);
|
|
102
|
-
}
|
|
103
|
-
const buffer = Buffer.from(await response.arrayBuffer());
|
|
104
|
-
const actualHash = crypto.createHash('sha256').update(buffer).digest('hex');
|
|
105
|
-
if (actualHash !== expectedHash) {
|
|
106
|
-
throw new Error(`Hash mismatch: expected ${expectedHash}, got ${actualHash}`);
|
|
107
|
-
}
|
|
108
|
-
console.log('ā Download verified');
|
|
109
|
-
return buffer;
|
|
110
|
-
}
|
|
111
|
-
async function applyUpdate(newBundle) {
|
|
112
|
-
console.log('š Applying update...');
|
|
113
|
-
// Create backup of current version if it exists
|
|
114
|
-
if (fsSync.existsSync(APP_BUNDLE)) {
|
|
115
|
-
try {
|
|
116
|
-
// Rotate backups: .old -> .backup (if exists), current -> .old
|
|
117
|
-
if (fsSync.existsSync(APP_BUNDLE_OLD)) {
|
|
118
|
-
await fs.copyFile(APP_BUNDLE_OLD, APP_BUNDLE_BACKUP);
|
|
119
|
-
}
|
|
120
|
-
await fs.copyFile(APP_BUNDLE, APP_BUNDLE_OLD);
|
|
121
|
-
console.log('ā Backup created');
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
console.warn(`ā ļø Backup creation failed: ${error.message}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
// Write new bundle
|
|
128
|
-
const tempPath = path.join(os.tmpdir(), `ttc-update-${Date.now()}.js`);
|
|
129
|
-
await fs.writeFile(tempPath, newBundle, { mode: 0o755 });
|
|
130
|
-
// Replace current bundle
|
|
131
|
-
await fs.rename(tempPath, APP_BUNDLE);
|
|
132
|
-
// Make executable
|
|
133
|
-
if (process.platform !== 'win32') {
|
|
134
|
-
await fs.chmod(APP_BUNDLE, 0o755);
|
|
135
|
-
}
|
|
136
|
-
console.log('ā Update applied');
|
|
137
|
-
}
|
|
138
|
-
async function performUpdate(info) {
|
|
139
|
-
if (!info.downloadUrl || !info.hash) {
|
|
140
|
-
console.error('ā Invalid update info');
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
const newBundle = await downloadUpdate(info.downloadUrl, info.hash);
|
|
145
|
-
await applyUpdate(newBundle);
|
|
146
|
-
if (info.version) {
|
|
147
|
-
console.log(`ā Updated to version ${info.version}`);
|
|
148
|
-
}
|
|
149
|
-
if (info.changelog) {
|
|
150
|
-
console.log(`\nš Changelog:\n${info.changelog}`);
|
|
151
|
-
}
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
catch (error) {
|
|
155
|
-
console.error(`ā Update failed: ${error.message}`);
|
|
156
|
-
// Attempt rollback
|
|
157
|
-
if (fsSync.existsSync(APP_BUNDLE_OLD)) {
|
|
158
|
-
console.log('š Rolling back to previous version...');
|
|
159
|
-
try {
|
|
160
|
-
await fs.copyFile(APP_BUNDLE_OLD, APP_BUNDLE);
|
|
161
|
-
console.log('ā Rollback complete');
|
|
162
|
-
}
|
|
163
|
-
catch (rollbackError) {
|
|
164
|
-
console.error(`ā Rollback failed: ${rollbackError.message}`);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
// ============ Child Process Management ============
|
|
171
|
-
function spawnChild() {
|
|
172
|
-
if (!fsSync.existsSync(APP_BUNDLE)) {
|
|
173
|
-
console.error(`ā App bundle not found: ${APP_BUNDLE}`);
|
|
174
|
-
console.error('Please run: npm run build:cli');
|
|
175
|
-
process.exit(1);
|
|
176
|
-
}
|
|
177
|
-
console.log(`š Spawning child process: ${APP_BUNDLE}`);
|
|
178
|
-
const child = spawn(process.execPath, [APP_BUNDLE, ...process.argv.slice(2)], {
|
|
179
|
-
stdio: 'inherit',
|
|
180
|
-
env: {
|
|
181
|
-
...process.env,
|
|
182
|
-
TTC_IS_CHILD: '1',
|
|
183
|
-
TTC_UPDATER_PID: process.pid.toString()
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
child.on('exit', (code, signal) => {
|
|
187
|
-
console.log(`\nš¦ Child process exited (code: ${code}, signal: ${signal})`);
|
|
188
|
-
childProcess = null;
|
|
189
|
-
// If update was requested, restart with new version
|
|
190
|
-
if (restartRequested) {
|
|
191
|
-
console.log('š Restarting with updated version...');
|
|
192
|
-
restartRequested = false;
|
|
193
|
-
childProcess = spawnChild();
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
// If child crashed, try to recover
|
|
197
|
-
if (code !== 0 && code !== null && !isUpdating) {
|
|
198
|
-
console.log('ā ļø Child process crashed, attempting recovery...');
|
|
199
|
-
// Try backup version if current is corrupted
|
|
200
|
-
if (fsSync.existsSync(APP_BUNDLE_OLD)) {
|
|
201
|
-
console.log('š Attempting to recover with backup...');
|
|
202
|
-
fs.copyFile(APP_BUNDLE_OLD, APP_BUNDLE)
|
|
203
|
-
.then(() => {
|
|
204
|
-
console.log('ā Recovered, restarting...');
|
|
205
|
-
childProcess = spawnChild();
|
|
206
|
-
})
|
|
207
|
-
.catch((_err) => {
|
|
208
|
-
console.error('ā Recovery failed, giving up');
|
|
209
|
-
process.exit(1);
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
console.error('ā No backup available, cannot recover');
|
|
214
|
-
process.exit(1);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
else if (signal !== 'SIGTERM' && signal !== 'SIGINT') {
|
|
218
|
-
// Normal exit or intentional signal
|
|
219
|
-
process.exit(code || 0);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
child.on('error', (error) => {
|
|
223
|
-
console.error('ā Child process error:', error);
|
|
224
|
-
childProcess = null;
|
|
225
|
-
});
|
|
226
|
-
return child;
|
|
227
|
-
}
|
|
228
|
-
// ============ Signal Handling ============
|
|
229
|
-
function setupSignalHandlers() {
|
|
230
|
-
// Forward signals to child
|
|
231
|
-
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGUSR1', 'SIGUSR2'];
|
|
232
|
-
signals.forEach(signal => {
|
|
233
|
-
process.on(signal, () => {
|
|
234
|
-
if (childProcess) {
|
|
235
|
-
console.log(`\nš” Forwarding ${signal} to child process...`);
|
|
236
|
-
childProcess.kill(signal);
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
process.exit(0);
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
// Handle uncaught exceptions
|
|
244
|
-
process.on('uncaughtException', (error) => {
|
|
245
|
-
console.error('ā Uncaught exception in updater:', error);
|
|
246
|
-
if (childProcess) {
|
|
247
|
-
childProcess.kill('SIGTERM');
|
|
248
|
-
}
|
|
249
|
-
process.exit(1);
|
|
250
|
-
});
|
|
251
|
-
process.on('unhandledRejection', (reason, _promise) => {
|
|
252
|
-
console.error('ā Unhandled rejection in updater:', reason);
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
// ============ CLI Interface ============
|
|
256
|
-
async function cmdUpdate() {
|
|
257
|
-
console.log('š Checking for updates...');
|
|
258
|
-
const info = await checkForUpdates();
|
|
259
|
-
if (!info) {
|
|
260
|
-
console.log('ā ļø Unable to check for updates');
|
|
261
|
-
process.exit(1);
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
if (!info.updateAvailable) {
|
|
265
|
-
console.log('ā Already up to date');
|
|
266
|
-
process.exit(0);
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
console.log('š¦ Update available!');
|
|
270
|
-
if (info.version) {
|
|
271
|
-
console.log(` Version: ${info.version}`);
|
|
272
|
-
}
|
|
273
|
-
if (info.changelog) {
|
|
274
|
-
console.log(`\nš Changelog:\n${info.changelog}`);
|
|
275
|
-
}
|
|
276
|
-
// Stop child process if running
|
|
277
|
-
if (childProcess) {
|
|
278
|
-
console.log('š Stopping child process...');
|
|
279
|
-
childProcess.kill('SIGTERM');
|
|
280
|
-
childProcess = null;
|
|
281
|
-
}
|
|
282
|
-
isUpdating = true;
|
|
283
|
-
const success = await performUpdate(info);
|
|
284
|
-
isUpdating = false;
|
|
285
|
-
if (success) {
|
|
286
|
-
console.log('\nā Update complete! Restarting...');
|
|
287
|
-
restartRequested = true;
|
|
288
|
-
childProcess = spawnChild();
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
console.error('\nā Update failed!');
|
|
292
|
-
process.exit(1);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
async function cmdUpdateCheck() {
|
|
296
|
-
console.log('š Checking for updates...');
|
|
297
|
-
const info = await checkForUpdates();
|
|
298
|
-
if (!info) {
|
|
299
|
-
console.log('ā ļø Unable to check for updates');
|
|
300
|
-
process.exit(1);
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
if (info.updateAvailable) {
|
|
304
|
-
console.log('š¦ Update available!');
|
|
305
|
-
if (info.version) {
|
|
306
|
-
console.log(` Version: ${info.version}`);
|
|
307
|
-
}
|
|
308
|
-
if (info.size) {
|
|
309
|
-
console.log(` Size: ${(info.size / 1024 / 1024).toFixed(2)} MB`);
|
|
310
|
-
}
|
|
311
|
-
if (info.changelog) {
|
|
312
|
-
console.log(`\nš Changelog:\n${info.changelog}`);
|
|
313
|
-
}
|
|
314
|
-
console.log('\nRun "ttc update" to apply the update');
|
|
315
|
-
process.exit(0);
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
console.log('ā Already up to date');
|
|
319
|
-
process.exit(0);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
async function cmdVersion() {
|
|
323
|
-
console.log(`TalkToCode CLI Updater`);
|
|
324
|
-
console.log(`Node: ${process.version}`);
|
|
325
|
-
console.log(`Platform: ${os.platform()} ${os.arch()}`);
|
|
326
|
-
const currentHash = calculateHash(APP_BUNDLE);
|
|
327
|
-
console.log(`Bundle hash: ${currentHash ? currentHash.substring(0, 16) + '...' : 'unknown'}`);
|
|
328
|
-
const hashes = await getBundleHashes();
|
|
329
|
-
if (hashes['js-bundle']) {
|
|
330
|
-
console.log(`Bundle version: ${hashes['js-bundle'].version || 'unknown'}`);
|
|
331
|
-
console.log(`Bundle date: ${hashes['js-bundle'].date || 'unknown'}`);
|
|
332
|
-
}
|
|
333
|
-
process.exit(0);
|
|
334
|
-
}
|
|
335
|
-
// ============ IPC from Child Process ============
|
|
336
|
-
/**
|
|
337
|
-
* The child process can request updates by writing to a special file
|
|
338
|
-
* or by sending a signal to the parent
|
|
339
|
-
*/
|
|
340
|
-
function setupChildIPC() {
|
|
341
|
-
// Listen for update requests via USR1 signal
|
|
342
|
-
process.on('SIGUSR1', async () => {
|
|
343
|
-
console.log('\nšØ Update requested by child process...');
|
|
344
|
-
const info = await checkForUpdates();
|
|
345
|
-
if (!info || !info.updateAvailable) {
|
|
346
|
-
console.log('ā No updates available');
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
console.log('š¦ Update available, applying...');
|
|
350
|
-
// Stop child process
|
|
351
|
-
if (childProcess) {
|
|
352
|
-
childProcess.kill('SIGTERM');
|
|
353
|
-
childProcess = null;
|
|
354
|
-
}
|
|
355
|
-
isUpdating = true;
|
|
356
|
-
const success = await performUpdate(info);
|
|
357
|
-
isUpdating = false;
|
|
358
|
-
if (success) {
|
|
359
|
-
console.log('ā Update complete! Restarting...');
|
|
360
|
-
restartRequested = true;
|
|
361
|
-
childProcess = spawnChild();
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
// ============ Main Entry Point ============
|
|
366
|
-
async function main() {
|
|
367
|
-
const args = process.argv.slice(2);
|
|
368
|
-
const command = args[0];
|
|
369
|
-
// Handle updater-specific commands
|
|
370
|
-
if (command === 'update') {
|
|
371
|
-
await cmdUpdate();
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
if (command === 'update:check' || command === 'check-update') {
|
|
375
|
-
await cmdUpdateCheck();
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
if (command === 'version' || command === '--version' || command === '-v') {
|
|
379
|
-
await cmdVersion();
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
if (command === 'help' || command === '--help' || command === '-h') {
|
|
383
|
-
console.log(`
|
|
384
|
-
TalkToCode CLI Updater
|
|
385
|
-
=====================
|
|
386
|
-
|
|
387
|
-
Commands:
|
|
388
|
-
ttc <command> Run command in child process (default)
|
|
389
|
-
ttc update Check and apply updates
|
|
390
|
-
ttc update:check Check for updates without applying
|
|
391
|
-
ttc version Show version information
|
|
392
|
-
ttc help Show this help message
|
|
393
|
-
|
|
394
|
-
The updater runs as the main process and spawns the app as a child.
|
|
395
|
-
This allows the updater to update itself even if the app is corrupted.
|
|
396
|
-
`);
|
|
397
|
-
process.exit(0);
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
// Default: spawn child process
|
|
401
|
-
console.log('šÆ TalkToCode CLI Updater');
|
|
402
|
-
console.log('====================================\n');
|
|
403
|
-
// Silent update check on startup
|
|
404
|
-
checkForUpdates().then(info => {
|
|
405
|
-
if (info?.updateAvailable) {
|
|
406
|
-
console.log('š¦ Update available! Run "ttc update" to apply.\n');
|
|
407
|
-
}
|
|
408
|
-
}).catch(() => { });
|
|
409
|
-
setupSignalHandlers();
|
|
410
|
-
setupChildIPC();
|
|
411
|
-
childProcess = spawnChild();
|
|
412
|
-
// Keep updater alive
|
|
413
|
-
process.on('exit', () => {
|
|
414
|
-
if (childProcess) {
|
|
415
|
-
childProcess.kill('SIGTERM');
|
|
416
|
-
}
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
main().catch(error => {
|
|
420
|
-
console.error('ā Fatal error:', error);
|
|
421
|
-
process.exit(1);
|
|
422
|
-
});
|