@comfanion/workflow 4.36.17 → 4.36.18

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