@comfanion/workflow 4.36.4 → 4.36.6
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 +78 -9
- package/package.json +2 -1
- package/src/build-info.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -8,6 +8,24 @@ import fs from 'fs-extra';
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
import { execSync } from 'child_process';
|
|
11
|
+
import yaml from 'js-yaml';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Deep merge two objects. User values override defaults.
|
|
15
|
+
* Arrays are replaced, not merged.
|
|
16
|
+
*/
|
|
17
|
+
function deepMerge(defaults, user) {
|
|
18
|
+
const result = { ...defaults };
|
|
19
|
+
for (const key of Object.keys(user)) {
|
|
20
|
+
if (user[key] !== null && typeof user[key] === 'object' && !Array.isArray(user[key]) &&
|
|
21
|
+
defaults[key] !== null && typeof defaults[key] === 'object' && !Array.isArray(defaults[key])) {
|
|
22
|
+
result[key] = deepMerge(defaults[key], user[key]);
|
|
23
|
+
} else {
|
|
24
|
+
result[key] = user[key];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
11
29
|
|
|
12
30
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
31
|
const PACKAGE_DIR = path.join(__dirname, '..');
|
|
@@ -260,6 +278,8 @@ program
|
|
|
260
278
|
let hadVectorizer = false;
|
|
261
279
|
let hadVectors = false;
|
|
262
280
|
|
|
281
|
+
let existingConfigContent = null;
|
|
282
|
+
|
|
263
283
|
if (await fs.pathExists(targetDir)) {
|
|
264
284
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
265
285
|
const backupDir = path.join(process.cwd(), `.opencode.backup-${timestamp}`);
|
|
@@ -268,6 +288,12 @@ program
|
|
|
268
288
|
hadVectorizer = await fs.pathExists(vectorizerNodeModules);
|
|
269
289
|
hadVectors = await fs.pathExists(vectorsDir);
|
|
270
290
|
|
|
291
|
+
// Read existing config.yaml for merge
|
|
292
|
+
const existingConfigPath = path.join(targetDir, 'config.yaml');
|
|
293
|
+
if (await fs.pathExists(existingConfigPath)) {
|
|
294
|
+
existingConfigContent = await fs.readFile(existingConfigPath, 'utf8');
|
|
295
|
+
}
|
|
296
|
+
|
|
271
297
|
// Preserve vectorizer node_modules (100MB+, don't backup)
|
|
272
298
|
if (hadVectorizer) {
|
|
273
299
|
spinner.text = 'Preserving vectorizer dependencies...';
|
|
@@ -323,18 +349,37 @@ program
|
|
|
323
349
|
const configPath = path.join(targetDir, 'config.yaml');
|
|
324
350
|
let configContent = await fs.readFile(configPath, 'utf8');
|
|
325
351
|
|
|
352
|
+
// If we had existing config, merge it (preserve user customizations)
|
|
353
|
+
if (existingConfigContent) {
|
|
354
|
+
try {
|
|
355
|
+
const newConfig = yaml.load(configContent) || {};
|
|
356
|
+
const existingConfig = yaml.load(existingConfigContent) || {};
|
|
357
|
+
const mergedConfig = deepMerge(newConfig, existingConfig);
|
|
358
|
+
configContent = yaml.dump(mergedConfig, {
|
|
359
|
+
indent: 2,
|
|
360
|
+
lineWidth: 120,
|
|
361
|
+
noRefs: true,
|
|
362
|
+
sortKeys: false
|
|
363
|
+
});
|
|
364
|
+
console.log(chalk.green(' ✅ Merged existing config settings'));
|
|
365
|
+
} catch (e) {
|
|
366
|
+
// Merge failed, continue with new config + user values
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Apply user's answers from prompts
|
|
326
371
|
configContent = configContent
|
|
327
|
-
.replace(/user_name:
|
|
328
|
-
.replace(/communication_language:
|
|
329
|
-
.replace(/project_name:
|
|
372
|
+
.replace(/user_name: .*/, `user_name: "${config.user_name}"`)
|
|
373
|
+
.replace(/communication_language: .*/, `communication_language: "${config.communication_language}"`)
|
|
374
|
+
.replace(/project_name: .*/, `project_name: "${config.project_name}"`)
|
|
330
375
|
.replace(/methodology: (tdd|stub)/, `methodology: ${config.methodology}`);
|
|
331
376
|
|
|
332
377
|
// Jira config
|
|
333
378
|
if (config.jira_enabled) {
|
|
334
379
|
configContent = configContent
|
|
335
380
|
.replace(/enabled: false\s+# Jira/, `enabled: true # Jira`)
|
|
336
|
-
.replace(/base_url:
|
|
337
|
-
.replace(/project_key:
|
|
381
|
+
.replace(/base_url: .*/, `base_url: "${config.jira_url}"`)
|
|
382
|
+
.replace(/project_key: .*/, `project_key: "${config.jira_project}"`);
|
|
338
383
|
}
|
|
339
384
|
|
|
340
385
|
// Vectorizer config
|
|
@@ -572,10 +617,34 @@ program
|
|
|
572
617
|
await fs.move(tempVectors, path.join(targetDir, 'vectors'), { overwrite: true });
|
|
573
618
|
}
|
|
574
619
|
|
|
575
|
-
//
|
|
576
|
-
spinner.text = '
|
|
577
|
-
|
|
578
|
-
|
|
620
|
+
// Merge config.yaml: new defaults + user overrides
|
|
621
|
+
spinner.text = 'Merging config.yaml...';
|
|
622
|
+
try {
|
|
623
|
+
const newConfigPath = path.join(targetDir, 'config.yaml');
|
|
624
|
+
const newConfigContent = await fs.readFile(newConfigPath, 'utf8');
|
|
625
|
+
|
|
626
|
+
// Parse both configs
|
|
627
|
+
const newConfig = yaml.load(newConfigContent) || {};
|
|
628
|
+
const userConfig = yaml.load(configBackup) || {};
|
|
629
|
+
|
|
630
|
+
// Deep merge: defaults from new config, overridden by user values
|
|
631
|
+
const mergedConfig = deepMerge(newConfig, userConfig);
|
|
632
|
+
|
|
633
|
+
// Dump back to YAML with nice formatting
|
|
634
|
+
const mergedContent = yaml.dump(mergedConfig, {
|
|
635
|
+
indent: 2,
|
|
636
|
+
lineWidth: 120,
|
|
637
|
+
noRefs: true,
|
|
638
|
+
sortKeys: false
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
await fs.writeFile(configPath, mergedContent);
|
|
642
|
+
console.log(chalk.green(' ✅ config.yaml merged (your settings preserved, new options added)'));
|
|
643
|
+
} catch (e) {
|
|
644
|
+
// Fallback: just restore user's config if merge fails
|
|
645
|
+
await fs.writeFile(configPath, configBackup);
|
|
646
|
+
console.log(chalk.yellow(' ⚠️ config.yaml restored (merge failed, using your original)'));
|
|
647
|
+
}
|
|
579
648
|
|
|
580
649
|
// Install plugin dependencies
|
|
581
650
|
spinner.text = 'Installing plugin dependencies...';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comfanion/workflow",
|
|
3
|
-
"version": "4.36.
|
|
3
|
+
"version": "4.36.6",
|
|
4
4
|
"description": "Initialize OpenCode Workflow system for AI-assisted development with semantic code search",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"glob": "^10.5.0",
|
|
51
51
|
"ignore": "^5.3.0",
|
|
52
52
|
"inquirer": "^9.2.0",
|
|
53
|
+
"js-yaml": "^4.1.1",
|
|
53
54
|
"ora": "^7.0.0"
|
|
54
55
|
}
|
|
55
56
|
}
|