@oh-my-pi/cli 0.3.0 → 0.4.0
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/.editorconfig +14 -0
- package/.prettierrc +6 -0
- package/README.md +65 -71
- package/bun.lock +13 -10
- package/dist/cli.js +114 -34
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/features.d.ts.map +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/symlinks.d.ts +1 -0
- package/dist/symlinks.d.ts.map +1 -1
- package/package.json +11 -4
- package/plugins/exa/README.md +44 -38
- package/plugins/exa/package.json +44 -11
- package/plugins/exa/tools/exa/company.ts +24 -13
- package/plugins/exa/tools/exa/index.ts +43 -34
- package/plugins/exa/tools/exa/linkedin.ts +24 -13
- package/plugins/exa/tools/exa/researcher.ts +26 -18
- package/plugins/exa/tools/exa/search.ts +31 -20
- package/plugins/exa/tools/exa/shared.ts +182 -156
- package/plugins/exa/tools/exa/websets.ts +39 -28
- package/plugins/metal-theme/package.json +13 -4
- package/plugins/subagents/README.md +3 -0
- package/plugins/subagents/agents/explore.md +11 -0
- package/plugins/subagents/agents/planner.md +3 -0
- package/plugins/subagents/agents/reviewer.md +6 -0
- package/plugins/subagents/agents/task.md +8 -1
- package/plugins/subagents/commands/architect-plan.md +1 -0
- package/plugins/subagents/commands/implement-with-critic.md +1 -0
- package/plugins/subagents/commands/implement.md +1 -0
- package/plugins/subagents/package.json +43 -11
- package/plugins/subagents/tools/task/index.ts +1089 -861
- package/plugins/user-prompt/README.md +22 -66
- package/plugins/user-prompt/package.json +15 -4
- package/plugins/user-prompt/tools/user-prompt/index.ts +185 -157
- package/scripts/bump-version.sh +10 -13
- package/src/cli.ts +1 -1
- package/src/commands/config.ts +21 -6
- package/src/commands/features.ts +49 -12
- package/src/commands/install.ts +91 -24
- package/src/commands/list.ts +14 -3
- package/src/commands/uninstall.ts +4 -1
- package/src/commands/update.ts +6 -1
- package/src/runtime.ts +3 -10
- package/src/symlinks.ts +12 -7
package/src/commands/features.ts
CHANGED
|
@@ -41,15 +41,25 @@ export async function interactiveFeatures(name: string, options: FeaturesOptions
|
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
// Get runtime config path
|
|
44
|
+
// Get runtime config path
|
|
45
45
|
const runtimePath = getRuntimeConfigPath(pkgJson, isGlobal);
|
|
46
46
|
if (!runtimePath) {
|
|
47
47
|
console.log(chalk.yellow(`Plugin "${name}" does not have a runtime.json config file.`));
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
// Determine currently enabled features:
|
|
52
|
+
// 1. Check plugins.json config (source of truth after omp features changes)
|
|
53
|
+
// 2. Fall back to runtime.json
|
|
54
|
+
// 3. Fall back to plugin defaults
|
|
55
|
+
const pluginConfig = pluginsJson.config?.[name];
|
|
56
|
+
let enabledFeatures: string[];
|
|
57
|
+
if (Array.isArray(pluginConfig?.features)) {
|
|
58
|
+
enabledFeatures = pluginConfig.features;
|
|
59
|
+
} else {
|
|
60
|
+
const runtimeConfig = readRuntimeConfig(runtimePath);
|
|
61
|
+
enabledFeatures = runtimeConfig.features ?? getDefaultFeatures(features);
|
|
62
|
+
}
|
|
53
63
|
|
|
54
64
|
// JSON output mode - just list
|
|
55
65
|
if (options.json) {
|
|
@@ -99,8 +109,8 @@ export async function interactiveFeatures(name: string, options: FeaturesOptions
|
|
|
99
109
|
});
|
|
100
110
|
|
|
101
111
|
// Apply changes
|
|
102
|
-
await applyFeatureChanges(name, runtimePath, features, enabledFeatures, selected);
|
|
103
|
-
} catch (
|
|
112
|
+
await applyFeatureChanges(name, runtimePath, features, enabledFeatures, selected, isGlobal);
|
|
113
|
+
} catch (_err) {
|
|
104
114
|
// User cancelled (Ctrl+C)
|
|
105
115
|
console.log(chalk.dim("\nCancelled."));
|
|
106
116
|
}
|
|
@@ -111,7 +121,14 @@ export async function interactiveFeatures(name: string, options: FeaturesOptions
|
|
|
111
121
|
*/
|
|
112
122
|
function listFeaturesNonInteractive(
|
|
113
123
|
name: string,
|
|
114
|
-
features: Record<
|
|
124
|
+
features: Record<
|
|
125
|
+
string,
|
|
126
|
+
{
|
|
127
|
+
description?: string;
|
|
128
|
+
default?: boolean;
|
|
129
|
+
variables?: Record<string, unknown>;
|
|
130
|
+
}
|
|
131
|
+
>,
|
|
115
132
|
enabledFeatures: string[],
|
|
116
133
|
): void {
|
|
117
134
|
console.log(chalk.bold(`\nFeatures for ${name}:\n`));
|
|
@@ -141,7 +158,14 @@ function listFeaturesNonInteractive(
|
|
|
141
158
|
async function applyFeatureChanges(
|
|
142
159
|
name: string,
|
|
143
160
|
runtimePath: string,
|
|
144
|
-
|
|
161
|
+
_features: Record<
|
|
162
|
+
string,
|
|
163
|
+
{
|
|
164
|
+
description?: string;
|
|
165
|
+
default?: boolean;
|
|
166
|
+
variables?: Record<string, unknown>;
|
|
167
|
+
}
|
|
168
|
+
>,
|
|
145
169
|
currentlyEnabled: string[],
|
|
146
170
|
newEnabled: string[],
|
|
147
171
|
isGlobal: boolean,
|
|
@@ -214,7 +238,7 @@ export async function configureFeatures(name: string, options: FeaturesOptions =
|
|
|
214
238
|
|
|
215
239
|
const allFeatureNames = Object.keys(features);
|
|
216
240
|
|
|
217
|
-
// Get runtime config
|
|
241
|
+
// Get runtime config path
|
|
218
242
|
const runtimePath = getRuntimeConfigPath(pkgJson, isGlobal);
|
|
219
243
|
if (!runtimePath) {
|
|
220
244
|
console.log(chalk.yellow(`Plugin "${name}" does not have a runtime.json config file.`));
|
|
@@ -222,8 +246,18 @@ export async function configureFeatures(name: string, options: FeaturesOptions =
|
|
|
222
246
|
return;
|
|
223
247
|
}
|
|
224
248
|
|
|
225
|
-
|
|
226
|
-
|
|
249
|
+
// Determine currently enabled features:
|
|
250
|
+
// 1. Check plugins.json config (source of truth after omp features changes)
|
|
251
|
+
// 2. Fall back to runtime.json
|
|
252
|
+
// 3. Fall back to plugin defaults
|
|
253
|
+
const pluginConfig = pluginsJson.config?.[name];
|
|
254
|
+
let currentlyEnabled: string[];
|
|
255
|
+
if (Array.isArray(pluginConfig?.features)) {
|
|
256
|
+
currentlyEnabled = pluginConfig.features;
|
|
257
|
+
} else {
|
|
258
|
+
const runtimeConfig = readRuntimeConfig(runtimePath);
|
|
259
|
+
currentlyEnabled = runtimeConfig.features ?? getDefaultFeatures(features);
|
|
260
|
+
}
|
|
227
261
|
|
|
228
262
|
let newEnabled: string[];
|
|
229
263
|
|
|
@@ -234,7 +268,10 @@ export async function configureFeatures(name: string, options: FeaturesOptions =
|
|
|
234
268
|
} else if (options.set === "") {
|
|
235
269
|
newEnabled = [];
|
|
236
270
|
} else {
|
|
237
|
-
newEnabled = options.set
|
|
271
|
+
newEnabled = options.set
|
|
272
|
+
.split(",")
|
|
273
|
+
.map((f) => f.trim())
|
|
274
|
+
.filter(Boolean);
|
|
238
275
|
// Validate
|
|
239
276
|
for (const f of newEnabled) {
|
|
240
277
|
if (!features[f]) {
|
|
@@ -273,7 +310,7 @@ export async function configureFeatures(name: string, options: FeaturesOptions =
|
|
|
273
310
|
}
|
|
274
311
|
}
|
|
275
312
|
|
|
276
|
-
await applyFeatureChanges(name, runtimePath, features, currentlyEnabled, newEnabled);
|
|
313
|
+
await applyFeatureChanges(name, runtimePath, features, currentlyEnabled, newEnabled, isGlobal);
|
|
277
314
|
|
|
278
315
|
if (options.json) {
|
|
279
316
|
console.log(JSON.stringify({ plugin: name, enabled: newEnabled }, null, 2));
|
package/src/commands/install.ts
CHANGED
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
loadPluginsJson,
|
|
13
13
|
type PluginConfig,
|
|
14
14
|
type PluginPackageJson,
|
|
15
|
-
type PluginsJson,
|
|
16
15
|
readPluginPackageJson,
|
|
17
16
|
savePluginsJson,
|
|
18
17
|
} from "@omp/manifest";
|
|
@@ -59,7 +58,12 @@ export function parsePackageSpecWithFeatures(spec: string): ParsedPackageSpec {
|
|
|
59
58
|
|
|
60
59
|
if (!match) {
|
|
61
60
|
// Fallback: treat as plain name
|
|
62
|
-
return {
|
|
61
|
+
return {
|
|
62
|
+
name: spec,
|
|
63
|
+
version: "latest",
|
|
64
|
+
features: null,
|
|
65
|
+
allFeatures: false,
|
|
66
|
+
};
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
const [, name, featuresStr, version = "latest"] = match;
|
|
@@ -80,7 +84,10 @@ export function parsePackageSpecWithFeatures(spec: string): ParsedPackageSpec {
|
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
// [f1,f2,...] = specific features
|
|
83
|
-
const features = featuresStr
|
|
87
|
+
const features = featuresStr
|
|
88
|
+
.split(",")
|
|
89
|
+
.map((f) => f.trim())
|
|
90
|
+
.filter(Boolean);
|
|
84
91
|
return { name, version, features, allFeatures: false };
|
|
85
92
|
}
|
|
86
93
|
|
|
@@ -287,7 +294,12 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
287
294
|
// Get existing plugins for conflict detection
|
|
288
295
|
const existingPlugins = await getInstalledPlugins(isGlobal);
|
|
289
296
|
|
|
290
|
-
const results: Array<{
|
|
297
|
+
const results: Array<{
|
|
298
|
+
name: string;
|
|
299
|
+
version: string;
|
|
300
|
+
success: boolean;
|
|
301
|
+
error?: string;
|
|
302
|
+
}> = [];
|
|
291
303
|
|
|
292
304
|
// Load plugins.json once for reinstall detection and config storage
|
|
293
305
|
let pluginsJson = await loadPluginsJson(isGlobal);
|
|
@@ -322,7 +334,12 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
322
334
|
if (!info) {
|
|
323
335
|
console.log(chalk.red(` ✗ Package not found: ${name}`));
|
|
324
336
|
process.exitCode = 1;
|
|
325
|
-
results.push({
|
|
337
|
+
results.push({
|
|
338
|
+
name,
|
|
339
|
+
version,
|
|
340
|
+
success: false,
|
|
341
|
+
error: "Package not found",
|
|
342
|
+
});
|
|
326
343
|
continue;
|
|
327
344
|
}
|
|
328
345
|
resolvedVersion = info.version;
|
|
@@ -340,7 +357,12 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
340
357
|
console.log(chalk.red(` ${dupe.dest} ← ${dupe.sources.join(", ")}`));
|
|
341
358
|
}
|
|
342
359
|
process.exitCode = 1;
|
|
343
|
-
results.push({
|
|
360
|
+
results.push({
|
|
361
|
+
name,
|
|
362
|
+
version: info.version,
|
|
363
|
+
success: false,
|
|
364
|
+
error: "Duplicate destinations in plugin",
|
|
365
|
+
});
|
|
344
366
|
continue;
|
|
345
367
|
}
|
|
346
368
|
|
|
@@ -382,7 +404,12 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
382
404
|
if (abort) {
|
|
383
405
|
console.log(chalk.yellow(` Aborted due to conflicts (before download)`));
|
|
384
406
|
process.exitCode = 1;
|
|
385
|
-
results.push({
|
|
407
|
+
results.push({
|
|
408
|
+
name,
|
|
409
|
+
version: info.version,
|
|
410
|
+
success: false,
|
|
411
|
+
error: "Conflicts",
|
|
412
|
+
});
|
|
386
413
|
continue;
|
|
387
414
|
}
|
|
388
415
|
}
|
|
@@ -412,9 +439,16 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
412
439
|
console.log(chalk.red(` ${dupe.dest} ← ${dupe.sources.join(", ")}`));
|
|
413
440
|
}
|
|
414
441
|
// Rollback: uninstall the package
|
|
415
|
-
execFileSync("npm", ["uninstall", "--prefix", prefix, name], {
|
|
442
|
+
execFileSync("npm", ["uninstall", "--prefix", prefix, name], {
|
|
443
|
+
stdio: "pipe",
|
|
444
|
+
});
|
|
416
445
|
process.exitCode = 1;
|
|
417
|
-
results.push({
|
|
446
|
+
results.push({
|
|
447
|
+
name,
|
|
448
|
+
version: info.version,
|
|
449
|
+
success: false,
|
|
450
|
+
error: "Duplicate destinations in plugin",
|
|
451
|
+
});
|
|
418
452
|
continue;
|
|
419
453
|
}
|
|
420
454
|
|
|
@@ -428,7 +462,9 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
428
462
|
console.log(chalk.yellow(` ⚠ ${formatConflicts([conflict])[0]}`));
|
|
429
463
|
}
|
|
430
464
|
// Rollback: uninstall the package
|
|
431
|
-
execFileSync("npm", ["uninstall", "--prefix", prefix, name], {
|
|
465
|
+
execFileSync("npm", ["uninstall", "--prefix", prefix, name], {
|
|
466
|
+
stdio: "pipe",
|
|
467
|
+
});
|
|
432
468
|
process.exitCode = 1;
|
|
433
469
|
results.push({
|
|
434
470
|
name,
|
|
@@ -455,21 +491,23 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
455
491
|
if (abort) {
|
|
456
492
|
console.log(chalk.yellow(` Aborted due to conflicts`));
|
|
457
493
|
// Rollback: uninstall the package
|
|
458
|
-
execFileSync("npm", ["uninstall", "--prefix", prefix, name], {
|
|
494
|
+
execFileSync("npm", ["uninstall", "--prefix", prefix, name], {
|
|
495
|
+
stdio: "pipe",
|
|
496
|
+
});
|
|
459
497
|
process.exitCode = 1;
|
|
460
|
-
results.push({
|
|
498
|
+
results.push({
|
|
499
|
+
name,
|
|
500
|
+
version: info.version,
|
|
501
|
+
success: false,
|
|
502
|
+
error: "Conflicts",
|
|
503
|
+
});
|
|
461
504
|
continue;
|
|
462
505
|
}
|
|
463
506
|
}
|
|
464
507
|
}
|
|
465
508
|
|
|
466
509
|
// 6. Resolve features and create symlinks
|
|
467
|
-
const { enabledFeatures, configToStore } = resolveFeatures(
|
|
468
|
-
pkgJson,
|
|
469
|
-
parsed,
|
|
470
|
-
existingConfig,
|
|
471
|
-
isReinstall,
|
|
472
|
-
);
|
|
510
|
+
const { enabledFeatures, configToStore } = resolveFeatures(pkgJson, parsed, existingConfig, isReinstall);
|
|
473
511
|
|
|
474
512
|
// Log feature selection if plugin has features
|
|
475
513
|
const allFeatureNames = getAllFeatureNames(pkgJson);
|
|
@@ -484,7 +522,14 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
484
522
|
}
|
|
485
523
|
|
|
486
524
|
// Create symlinks for omp.install entries (skip destinations user assigned to existing plugins)
|
|
487
|
-
const symlinkResult = await createPluginSymlinks(
|
|
525
|
+
const symlinkResult = await createPluginSymlinks(
|
|
526
|
+
name,
|
|
527
|
+
pkgJson,
|
|
528
|
+
isGlobal,
|
|
529
|
+
true,
|
|
530
|
+
skipDestinations,
|
|
531
|
+
enabledFeatures,
|
|
532
|
+
);
|
|
488
533
|
createdSymlinks = symlinkResult.created;
|
|
489
534
|
|
|
490
535
|
// 7. Process dependencies with omp field (with cycle detection)
|
|
@@ -553,14 +598,21 @@ export async function installPlugin(packages?: string[], options: InstallOptions
|
|
|
553
598
|
if (npmInstallSucceeded) {
|
|
554
599
|
console.log(chalk.dim(" Rolling back npm install..."));
|
|
555
600
|
try {
|
|
556
|
-
execFileSync("npm", ["uninstall", "--prefix", prefix, name], {
|
|
601
|
+
execFileSync("npm", ["uninstall", "--prefix", prefix, name], {
|
|
602
|
+
stdio: "pipe",
|
|
603
|
+
});
|
|
557
604
|
} catch {
|
|
558
605
|
// Ignore cleanup errors
|
|
559
606
|
}
|
|
560
607
|
}
|
|
561
608
|
|
|
562
609
|
process.exitCode = 1;
|
|
563
|
-
results.push({
|
|
610
|
+
results.push({
|
|
611
|
+
name,
|
|
612
|
+
version: resolvedVersion,
|
|
613
|
+
success: false,
|
|
614
|
+
error: errorMsg,
|
|
615
|
+
});
|
|
564
616
|
}
|
|
565
617
|
}
|
|
566
618
|
|
|
@@ -589,7 +641,12 @@ async function installLocalPlugin(
|
|
|
589
641
|
localPath: string,
|
|
590
642
|
isGlobal: boolean,
|
|
591
643
|
_options: InstallOptions,
|
|
592
|
-
): Promise<{
|
|
644
|
+
): Promise<{
|
|
645
|
+
name: string;
|
|
646
|
+
version: string;
|
|
647
|
+
success: boolean;
|
|
648
|
+
error?: string;
|
|
649
|
+
}> {
|
|
593
650
|
// Expand ~ to home directory
|
|
594
651
|
if (localPath.startsWith("~")) {
|
|
595
652
|
localPath = join(process.env.HOME || "", localPath.slice(1));
|
|
@@ -599,7 +656,12 @@ async function installLocalPlugin(
|
|
|
599
656
|
if (!existsSync(localPath)) {
|
|
600
657
|
console.log(chalk.red(`Error: Path does not exist: ${localPath}`));
|
|
601
658
|
process.exitCode = 1;
|
|
602
|
-
return {
|
|
659
|
+
return {
|
|
660
|
+
name: basename(localPath),
|
|
661
|
+
version: "local",
|
|
662
|
+
success: false,
|
|
663
|
+
error: "Path not found",
|
|
664
|
+
};
|
|
603
665
|
}
|
|
604
666
|
|
|
605
667
|
const _prefix = isGlobal ? PLUGINS_DIR : ".pi";
|
|
@@ -695,6 +757,11 @@ async function installLocalPlugin(
|
|
|
695
757
|
const errorMsg = (err as Error).message;
|
|
696
758
|
console.log(chalk.red(` ✗ Failed: ${errorMsg}`));
|
|
697
759
|
process.exitCode = 1;
|
|
698
|
-
return {
|
|
760
|
+
return {
|
|
761
|
+
name: basename(localPath),
|
|
762
|
+
version: "local",
|
|
763
|
+
success: false,
|
|
764
|
+
error: errorMsg,
|
|
765
|
+
};
|
|
699
766
|
}
|
|
700
767
|
}
|
package/src/commands/list.ts
CHANGED
|
@@ -47,20 +47,31 @@ const FILE_CATEGORIES: FileCategory[] = [
|
|
|
47
47
|
pattern: /^agent\/prompts?\//,
|
|
48
48
|
label: "Prompts",
|
|
49
49
|
color: chalk.blue,
|
|
50
|
-
extractName: (dest) =>
|
|
50
|
+
extractName: (dest) =>
|
|
51
|
+
dest
|
|
52
|
+
.split("/")
|
|
53
|
+
.pop()
|
|
54
|
+
?.replace(/\.[^.]+$/, "") || dest,
|
|
51
55
|
},
|
|
52
56
|
{
|
|
53
57
|
pattern: /^agent\/hooks?\//,
|
|
54
58
|
label: "Hooks",
|
|
55
59
|
color: chalk.red,
|
|
56
|
-
extractName: (dest) =>
|
|
60
|
+
extractName: (dest) =>
|
|
61
|
+
dest
|
|
62
|
+
.split("/")
|
|
63
|
+
.pop()
|
|
64
|
+
?.replace(/\.[^.]+$/, "") || dest,
|
|
57
65
|
},
|
|
58
66
|
];
|
|
59
67
|
|
|
60
68
|
/**
|
|
61
69
|
* Categorize installed files into known categories
|
|
62
70
|
*/
|
|
63
|
-
function categorizeFiles(files: string[]): {
|
|
71
|
+
function categorizeFiles(files: string[]): {
|
|
72
|
+
categorized: Map<string, string[]>;
|
|
73
|
+
uncategorized: string[];
|
|
74
|
+
} {
|
|
64
75
|
const categorized = new Map<string, string[]>();
|
|
65
76
|
const uncategorized: string[] = [];
|
|
66
77
|
|
|
@@ -70,7 +70,10 @@ export async function uninstallPlugin(name: string, options: UninstallOptions =
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
73
|
-
const rl = createInterface({
|
|
73
|
+
const rl = createInterface({
|
|
74
|
+
input: process.stdin,
|
|
75
|
+
output: process.stdout,
|
|
76
|
+
});
|
|
74
77
|
const answer = await new Promise<string>((resolve) => {
|
|
75
78
|
rl.question(chalk.yellow("Delete these files anyway? [y/N] "), (ans) => {
|
|
76
79
|
rl.close();
|
package/src/commands/update.ts
CHANGED
|
@@ -68,7 +68,12 @@ export async function updatePlugin(name?: string, options: UpdateOptions = {}):
|
|
|
68
68
|
|
|
69
69
|
console.log(chalk.blue(`Updating ${npmPlugins.length} plugin(s)...`));
|
|
70
70
|
|
|
71
|
-
const results: Array<{
|
|
71
|
+
const results: Array<{
|
|
72
|
+
name: string;
|
|
73
|
+
from: string;
|
|
74
|
+
to: string;
|
|
75
|
+
success: boolean;
|
|
76
|
+
}> = [];
|
|
72
77
|
|
|
73
78
|
// Save old package info before removing symlinks (for recovery on failure)
|
|
74
79
|
const oldPkgJsons = new Map<string, PluginPackageJson>();
|
package/src/runtime.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import type { OmpVariable, PluginPackageJson
|
|
1
|
+
import type { OmpVariable, PluginPackageJson } from "@omp/manifest";
|
|
2
2
|
import { loadPluginsJson, readPluginPackageJson } from "@omp/manifest";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Collect all variables from a plugin (top-level + enabled features)
|
|
6
6
|
*/
|
|
7
|
-
function collectVariables(
|
|
8
|
-
pkgJson: PluginPackageJson,
|
|
9
|
-
enabledFeatures: string[],
|
|
10
|
-
): Record<string, OmpVariable> {
|
|
7
|
+
function collectVariables(pkgJson: PluginPackageJson, enabledFeatures: string[]): Record<string, OmpVariable> {
|
|
11
8
|
const vars: Record<string, OmpVariable> = {};
|
|
12
9
|
|
|
13
10
|
// Top-level variables
|
|
@@ -67,11 +64,7 @@ export async function getPluginEnvVars(global = true): Promise<Record<string, st
|
|
|
67
64
|
|
|
68
65
|
const config = pluginsJson.config?.[pluginName];
|
|
69
66
|
const allFeatureNames = Object.keys(pkgJson.omp.features || {});
|
|
70
|
-
const enabledFeatures = resolveEnabledFeatures(
|
|
71
|
-
allFeatureNames,
|
|
72
|
-
config?.features,
|
|
73
|
-
pkgJson.omp.features || {},
|
|
74
|
-
);
|
|
67
|
+
const enabledFeatures = resolveEnabledFeatures(allFeatureNames, config?.features, pkgJson.omp.features || {});
|
|
75
68
|
|
|
76
69
|
// Collect variables from top-level and enabled features
|
|
77
70
|
const variables = collectVariables(pkgJson, enabledFeatures);
|
package/src/symlinks.ts
CHANGED
|
@@ -18,10 +18,7 @@ export function getInstallEntries(pkgJson: PluginPackageJson): OmpInstallEntry[]
|
|
|
18
18
|
/**
|
|
19
19
|
* @deprecated Use getInstallEntries instead. Features no longer have install arrays.
|
|
20
20
|
*/
|
|
21
|
-
export function getEnabledInstallEntries(
|
|
22
|
-
pkgJson: PluginPackageJson,
|
|
23
|
-
_enabledFeatures?: string[],
|
|
24
|
-
): OmpInstallEntry[] {
|
|
21
|
+
export function getEnabledInstallEntries(pkgJson: PluginPackageJson, _enabledFeatures?: string[]): OmpInstallEntry[] {
|
|
25
22
|
return getInstallEntries(pkgJson);
|
|
26
23
|
}
|
|
27
24
|
|
|
@@ -245,7 +242,7 @@ export async function writeRuntimeConfig(
|
|
|
245
242
|
features: config.features ?? existing.features ?? [],
|
|
246
243
|
options: { ...existing.options, ...config.options },
|
|
247
244
|
};
|
|
248
|
-
writeFileSync(runtimePath, JSON.stringify(merged, null, 2)
|
|
245
|
+
writeFileSync(runtimePath, `${JSON.stringify(merged, null, 2)}\n`);
|
|
249
246
|
if (verbose) {
|
|
250
247
|
console.log(chalk.dim(` Updated: ${runtimePath}`));
|
|
251
248
|
}
|
|
@@ -275,7 +272,11 @@ export async function removePluginSymlinks(
|
|
|
275
272
|
global = true,
|
|
276
273
|
verbose = true,
|
|
277
274
|
): Promise<SymlinkRemovalResult> {
|
|
278
|
-
const result: SymlinkRemovalResult = {
|
|
275
|
+
const result: SymlinkRemovalResult = {
|
|
276
|
+
removed: [],
|
|
277
|
+
errors: [],
|
|
278
|
+
skippedNonSymlinks: [],
|
|
279
|
+
};
|
|
279
280
|
|
|
280
281
|
const installEntries = getInstallEntries(pkgJson);
|
|
281
282
|
if (installEntries.length === 0) {
|
|
@@ -350,7 +351,11 @@ export async function checkPluginSymlinks(
|
|
|
350
351
|
pkgJson: PluginPackageJson,
|
|
351
352
|
global = true,
|
|
352
353
|
): Promise<{ valid: string[]; broken: string[]; missing: string[] }> {
|
|
353
|
-
const result = {
|
|
354
|
+
const result = {
|
|
355
|
+
valid: [] as string[],
|
|
356
|
+
broken: [] as string[],
|
|
357
|
+
missing: [] as string[],
|
|
358
|
+
};
|
|
354
359
|
const sourceDir = getPluginSourceDir(pluginName, global);
|
|
355
360
|
const baseDir = getBaseDir(global);
|
|
356
361
|
|