@comfanion/workflow 4.36.17 → 4.36.19
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/cli.js +131 -60
- package/package.json +1 -1
- package/src/build-info.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import inquirer from 'inquirer';
|
|
|
6
6
|
import ora from 'ora';
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
8
|
import path from 'path';
|
|
9
|
+
import crypto from 'crypto';
|
|
9
10
|
import { fileURLToPath } from 'url';
|
|
10
11
|
import { execSync } from 'child_process';
|
|
11
12
|
import yaml from 'js-yaml';
|
|
@@ -274,16 +275,27 @@ program
|
|
|
274
275
|
const vectorizerDir = path.join(targetDir, 'vectorizer');
|
|
275
276
|
const vectorsDir = path.join(targetDir, 'vectors');
|
|
276
277
|
const tempVectors = path.join(process.cwd(), '.vectors-temp');
|
|
278
|
+
const tempNodeModules = path.join(process.cwd(), '.vectorizer-nm-temp');
|
|
277
279
|
|
|
278
280
|
let hadVectors = false;
|
|
281
|
+
let hadVectorizerModules = false;
|
|
282
|
+
let oldPkgHash = null;
|
|
279
283
|
let existingConfigContent = null;
|
|
280
284
|
|
|
281
285
|
if (await fs.pathExists(targetDir)) {
|
|
282
286
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
283
287
|
const backupDir = path.join(process.cwd(), `.opencode.backup-${timestamp}`);
|
|
284
288
|
|
|
285
|
-
// Check what we need to preserve
|
|
289
|
+
// Check what we need to preserve
|
|
286
290
|
hadVectors = await fs.pathExists(vectorsDir);
|
|
291
|
+
hadVectorizerModules = await fs.pathExists(path.join(vectorizerDir, 'node_modules'));
|
|
292
|
+
|
|
293
|
+
// Get old package.json hash
|
|
294
|
+
const oldPkgPath = path.join(vectorizerDir, 'package.json');
|
|
295
|
+
if (await fs.pathExists(oldPkgPath)) {
|
|
296
|
+
const oldPkg = await fs.readFile(oldPkgPath, 'utf8');
|
|
297
|
+
oldPkgHash = crypto.createHash('md5').update(oldPkg).digest('hex');
|
|
298
|
+
}
|
|
287
299
|
|
|
288
300
|
// Read existing config.yaml for merge
|
|
289
301
|
const existingConfigPath = path.join(targetDir, 'config.yaml');
|
|
@@ -291,12 +303,18 @@ program
|
|
|
291
303
|
existingConfigContent = await fs.readFile(existingConfigPath, 'utf8');
|
|
292
304
|
}
|
|
293
305
|
|
|
294
|
-
// Preserve vector indexes
|
|
306
|
+
// Preserve vector indexes
|
|
295
307
|
if (hadVectors) {
|
|
296
308
|
spinner.text = 'Preserving vector indexes...';
|
|
297
309
|
await fs.move(vectorsDir, tempVectors, { overwrite: true });
|
|
298
310
|
}
|
|
299
311
|
|
|
312
|
+
// Preserve vectorizer node_modules
|
|
313
|
+
if (hadVectorizerModules) {
|
|
314
|
+
spinner.text = 'Preserving vectorizer cache...';
|
|
315
|
+
await fs.move(path.join(vectorizerDir, 'node_modules'), tempNodeModules, { overwrite: true });
|
|
316
|
+
}
|
|
317
|
+
|
|
300
318
|
// Create backup (without node_modules and vectors)
|
|
301
319
|
spinner.text = 'Creating backup...';
|
|
302
320
|
await fs.copy(targetDir, backupDir, {
|
|
@@ -314,41 +332,59 @@ program
|
|
|
314
332
|
// Copy .opencode structure (fresh, no old files)
|
|
315
333
|
await fs.copy(OPENCODE_SRC, targetDir);
|
|
316
334
|
|
|
317
|
-
// Copy vectorizer source files
|
|
335
|
+
// Copy vectorizer source files
|
|
318
336
|
if (await fs.pathExists(VECTORIZER_SRC)) {
|
|
319
337
|
const newVectorizerDir = path.join(targetDir, 'vectorizer');
|
|
320
338
|
await fs.ensureDir(newVectorizerDir);
|
|
321
339
|
await fs.copy(path.join(VECTORIZER_SRC, 'index.js'), path.join(newVectorizerDir, 'index.js'));
|
|
322
340
|
await fs.copy(path.join(VECTORIZER_SRC, 'package.json'), path.join(newVectorizerDir, 'package.json'));
|
|
323
341
|
|
|
324
|
-
// Install dependencies only if vectorizer is enabled
|
|
325
342
|
if (config.vectorizer_enabled) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
343
|
+
// Check if package.json changed
|
|
344
|
+
const newPkgPath = path.join(newVectorizerDir, 'package.json');
|
|
345
|
+
const newPkg = await fs.readFile(newPkgPath, 'utf8');
|
|
346
|
+
const newPkgHash = crypto.createHash('md5').update(newPkg).digest('hex');
|
|
347
|
+
|
|
348
|
+
if (hadVectorizerModules && oldPkgHash === newPkgHash) {
|
|
349
|
+
// Dependencies unchanged - restore cached node_modules
|
|
350
|
+
spinner.text = 'Restoring vectorizer cache (deps unchanged)...';
|
|
351
|
+
await fs.move(tempNodeModules, path.join(newVectorizerDir, 'node_modules'), { overwrite: true });
|
|
352
|
+
} else {
|
|
353
|
+
// Dependencies changed or new install
|
|
354
|
+
spinner.text = 'Installing vectorizer dependencies...';
|
|
355
|
+
if (await fs.pathExists(tempNodeModules)) {
|
|
356
|
+
await fs.remove(tempNodeModules);
|
|
357
|
+
}
|
|
358
|
+
try {
|
|
359
|
+
const steps = [
|
|
360
|
+
'Installing vectorizer dependencies...',
|
|
361
|
+
'Downloading @xenova/transformers (~50MB)...',
|
|
362
|
+
'Installing vectordb...',
|
|
363
|
+
'Installing glob...',
|
|
364
|
+
'Finalizing vectorizer setup...'
|
|
365
|
+
];
|
|
366
|
+
let stepIndex = 0;
|
|
367
|
+
const progressInterval = setInterval(() => {
|
|
368
|
+
stepIndex = (stepIndex + 1) % steps.length;
|
|
369
|
+
spinner.text = steps[stepIndex];
|
|
370
|
+
}, 3000);
|
|
371
|
+
|
|
372
|
+
execSync('npm install', {
|
|
373
|
+
cwd: newVectorizerDir,
|
|
374
|
+
stdio: 'pipe',
|
|
375
|
+
timeout: 180000
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
clearInterval(progressInterval);
|
|
379
|
+
spinner.text = 'Vectorizer installed!';
|
|
380
|
+
} catch (e) {
|
|
381
|
+
// Non-fatal
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
} else {
|
|
385
|
+
// Vectorizer disabled - clean up temp
|
|
386
|
+
if (await fs.pathExists(tempNodeModules)) {
|
|
387
|
+
await fs.remove(tempNodeModules);
|
|
352
388
|
}
|
|
353
389
|
}
|
|
354
390
|
}
|
|
@@ -576,8 +612,17 @@ program
|
|
|
576
612
|
spinner.text = 'Reading config.yaml...';
|
|
577
613
|
const configBackup = await fs.readFile(configPath, 'utf8');
|
|
578
614
|
|
|
579
|
-
// Check
|
|
615
|
+
// Check what exists
|
|
580
616
|
const hasVectors = await fs.pathExists(vectorsDir);
|
|
617
|
+
const hasVectorizerModules = await fs.pathExists(path.join(vectorizerDir, 'node_modules'));
|
|
618
|
+
|
|
619
|
+
// Get old package.json hash (to check if deps changed)
|
|
620
|
+
let oldPkgHash = null;
|
|
621
|
+
const oldPkgPath = path.join(vectorizerDir, 'package.json');
|
|
622
|
+
if (await fs.pathExists(oldPkgPath)) {
|
|
623
|
+
const oldPkg = await fs.readFile(oldPkgPath, 'utf8');
|
|
624
|
+
oldPkgHash = crypto.createHash('md5').update(oldPkg).digest('hex');
|
|
625
|
+
}
|
|
581
626
|
|
|
582
627
|
// Create full backup (unless --no-backup)
|
|
583
628
|
if (options.backup !== false) {
|
|
@@ -587,13 +632,20 @@ program
|
|
|
587
632
|
});
|
|
588
633
|
}
|
|
589
634
|
|
|
590
|
-
// Preserve
|
|
635
|
+
// Preserve vector indexes
|
|
591
636
|
const tempVectors = path.join(process.cwd(), '.vectors-temp');
|
|
592
637
|
if (hasVectors) {
|
|
593
638
|
spinner.text = 'Preserving vector indexes...';
|
|
594
639
|
await fs.move(vectorsDir, tempVectors, { overwrite: true });
|
|
595
640
|
}
|
|
596
641
|
|
|
642
|
+
// Preserve vectorizer node_modules (will restore if package.json unchanged)
|
|
643
|
+
const tempNodeModules = path.join(process.cwd(), '.vectorizer-nm-temp');
|
|
644
|
+
if (hasVectorizerModules) {
|
|
645
|
+
spinner.text = 'Preserving vectorizer cache...';
|
|
646
|
+
await fs.move(path.join(vectorizerDir, 'node_modules'), tempNodeModules, { overwrite: true });
|
|
647
|
+
}
|
|
648
|
+
|
|
597
649
|
// Remove old .opencode directory
|
|
598
650
|
spinner.text = 'Removing old files...';
|
|
599
651
|
await fs.remove(targetDir);
|
|
@@ -602,7 +654,7 @@ program
|
|
|
602
654
|
spinner.text = 'Installing new version...';
|
|
603
655
|
await fs.copy(OPENCODE_SRC, targetDir);
|
|
604
656
|
|
|
605
|
-
// Copy vectorizer source files
|
|
657
|
+
// Copy vectorizer source files
|
|
606
658
|
if (await fs.pathExists(VECTORIZER_SRC)) {
|
|
607
659
|
const newVectorizerDir = path.join(targetDir, 'vectorizer');
|
|
608
660
|
await fs.ensureDir(newVectorizerDir);
|
|
@@ -612,34 +664,53 @@ program
|
|
|
612
664
|
// Check if vectorizer is enabled in user's config
|
|
613
665
|
const vectorizerEnabled = /vectorizer:[\s\S]*?enabled:\s*true/i.test(configBackup);
|
|
614
666
|
|
|
615
|
-
// Install dependencies only if vectorizer is enabled
|
|
616
667
|
if (vectorizerEnabled) {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
668
|
+
// Check if package.json changed
|
|
669
|
+
const newPkgPath = path.join(newVectorizerDir, 'package.json');
|
|
670
|
+
const newPkg = await fs.readFile(newPkgPath, 'utf8');
|
|
671
|
+
const newPkgHash = crypto.createHash('md5').update(newPkg).digest('hex');
|
|
672
|
+
|
|
673
|
+
if (hasVectorizerModules && oldPkgHash === newPkgHash) {
|
|
674
|
+
// Dependencies unchanged - restore cached node_modules
|
|
675
|
+
spinner.text = 'Restoring vectorizer cache (deps unchanged)...';
|
|
676
|
+
await fs.move(tempNodeModules, path.join(newVectorizerDir, 'node_modules'), { overwrite: true });
|
|
677
|
+
} else {
|
|
678
|
+
// Dependencies changed or new install - run npm install
|
|
679
|
+
spinner.text = 'Installing vectorizer dependencies...';
|
|
680
|
+
// Clean up temp if exists
|
|
681
|
+
if (await fs.pathExists(tempNodeModules)) {
|
|
682
|
+
await fs.remove(tempNodeModules);
|
|
683
|
+
}
|
|
684
|
+
try {
|
|
685
|
+
const steps = [
|
|
686
|
+
'Installing vectorizer dependencies...',
|
|
687
|
+
'Downloading @xenova/transformers (~50MB)...',
|
|
688
|
+
'Installing vectordb...',
|
|
689
|
+
'Installing glob...',
|
|
690
|
+
'Finalizing vectorizer setup...'
|
|
691
|
+
];
|
|
692
|
+
let stepIndex = 0;
|
|
693
|
+
const progressInterval = setInterval(() => {
|
|
694
|
+
stepIndex = (stepIndex + 1) % steps.length;
|
|
695
|
+
spinner.text = steps[stepIndex];
|
|
696
|
+
}, 3000);
|
|
697
|
+
|
|
698
|
+
execSync('npm install', {
|
|
699
|
+
cwd: newVectorizerDir,
|
|
700
|
+
stdio: 'pipe',
|
|
701
|
+
timeout: 180000
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
clearInterval(progressInterval);
|
|
705
|
+
spinner.text = 'Vectorizer installed!';
|
|
706
|
+
} catch (e) {
|
|
707
|
+
// Non-fatal
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
} else {
|
|
711
|
+
// Vectorizer disabled - clean up temp
|
|
712
|
+
if (await fs.pathExists(tempNodeModules)) {
|
|
713
|
+
await fs.remove(tempNodeModules);
|
|
643
714
|
}
|
|
644
715
|
}
|
|
645
716
|
}
|
package/package.json
CHANGED