@oh-my-pi/cli 0.3.0 → 0.5.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/README.md +79 -84
- package/dist/cli.js +5025 -1016
- package/dist/commands/config.d.ts +27 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/features.d.ts.map +1 -1
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/install.d.ts +6 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/link.d.ts +1 -0
- package/dist/commands/link.d.ts.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/outdated.d.ts.map +1 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/uninstall.d.ts +3 -0
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/update.d.ts +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/why.d.ts.map +1 -1
- package/dist/conflicts.d.ts +7 -2
- package/dist/conflicts.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lock.d.ts.map +1 -1
- package/dist/lockfile.d.ts +24 -3
- package/dist/lockfile.d.ts.map +1 -1
- package/dist/manifest.d.ts +12 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/npm.d.ts +11 -0
- package/dist/npm.d.ts.map +1 -1
- package/dist/output.d.ts +51 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/paths.d.ts +5 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/progress.d.ts +78 -0
- package/dist/progress.d.ts.map +1 -0
- 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 +24 -10
- package/.github/icon.png +0 -0
- package/.github/logo.png +0 -0
- package/.github/workflows/ci.yml +0 -32
- package/.github/workflows/publish.yml +0 -42
- package/biome.json +0 -29
- package/bun.lock +0 -109
- package/plugins/exa/README.md +0 -153
- package/plugins/exa/package.json +0 -56
- package/plugins/exa/tools/exa/company.ts +0 -35
- package/plugins/exa/tools/exa/index.ts +0 -66
- package/plugins/exa/tools/exa/linkedin.ts +0 -35
- package/plugins/exa/tools/exa/researcher.ts +0 -40
- package/plugins/exa/tools/exa/runtime.json +0 -4
- package/plugins/exa/tools/exa/search.ts +0 -46
- package/plugins/exa/tools/exa/shared.ts +0 -230
- package/plugins/exa/tools/exa/websets.ts +0 -62
- package/plugins/metal-theme/README.md +0 -13
- package/plugins/metal-theme/omp.json +0 -8
- package/plugins/metal-theme/package.json +0 -19
- package/plugins/metal-theme/themes/metal.json +0 -79
- package/plugins/subagents/README.md +0 -25
- package/plugins/subagents/agents/explore.md +0 -71
- package/plugins/subagents/agents/planner.md +0 -51
- package/plugins/subagents/agents/reviewer.md +0 -53
- package/plugins/subagents/agents/task.md +0 -46
- package/plugins/subagents/commands/architect-plan.md +0 -9
- package/plugins/subagents/commands/implement-with-critic.md +0 -10
- package/plugins/subagents/commands/implement.md +0 -10
- package/plugins/subagents/omp.json +0 -15
- package/plugins/subagents/package.json +0 -26
- package/plugins/subagents/tools/task/index.ts +0 -1019
- package/plugins/user-prompt/README.md +0 -130
- package/plugins/user-prompt/package.json +0 -19
- package/plugins/user-prompt/tools/user-prompt/index.ts +0 -235
- package/scripts/bump-version.sh +0 -52
- package/scripts/publish.sh +0 -35
- package/src/cli.ts +0 -242
- package/src/commands/config.ts +0 -384
- package/src/commands/create.ts +0 -203
- package/src/commands/doctor.ts +0 -305
- package/src/commands/enable.ts +0 -122
- package/src/commands/env.ts +0 -38
- package/src/commands/features.ts +0 -295
- package/src/commands/info.ts +0 -120
- package/src/commands/init.ts +0 -60
- package/src/commands/install.ts +0 -700
- package/src/commands/link.ts +0 -159
- package/src/commands/list.ts +0 -186
- package/src/commands/outdated.ts +0 -87
- package/src/commands/search.ts +0 -77
- package/src/commands/uninstall.ts +0 -124
- package/src/commands/update.ts +0 -170
- package/src/commands/why.ts +0 -136
- package/src/conflicts.ts +0 -116
- package/src/errors.ts +0 -22
- package/src/index.ts +0 -46
- package/src/lock.ts +0 -46
- package/src/lockfile.ts +0 -132
- package/src/manifest.ts +0 -360
- package/src/npm.ts +0 -206
- package/src/paths.ts +0 -137
- package/src/runtime.ts +0 -116
- package/src/symlinks.ts +0 -455
- package/tsconfig.json +0 -28
package/src/cli.ts
DELETED
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
import { configCommand } from "@omp/commands/config";
|
|
4
|
-
import { createPlugin } from "@omp/commands/create";
|
|
5
|
-
import { runDoctor } from "@omp/commands/doctor";
|
|
6
|
-
import { disablePlugin, enablePlugin } from "@omp/commands/enable";
|
|
7
|
-
import { envCommand } from "@omp/commands/env";
|
|
8
|
-
import { featuresCommand } from "@omp/commands/features";
|
|
9
|
-
import { showInfo } from "@omp/commands/info";
|
|
10
|
-
import { initProject } from "@omp/commands/init";
|
|
11
|
-
import { installPlugin } from "@omp/commands/install";
|
|
12
|
-
import { linkPlugin } from "@omp/commands/link";
|
|
13
|
-
import { listPlugins } from "@omp/commands/list";
|
|
14
|
-
import { showOutdated } from "@omp/commands/outdated";
|
|
15
|
-
import { searchPlugins } from "@omp/commands/search";
|
|
16
|
-
import { uninstallPlugin } from "@omp/commands/uninstall";
|
|
17
|
-
import { updatePlugin } from "@omp/commands/update";
|
|
18
|
-
import { whyFile } from "@omp/commands/why";
|
|
19
|
-
import { withErrorHandling } from "@omp/errors";
|
|
20
|
-
import { checkNpmAvailable } from "@omp/npm";
|
|
21
|
-
import chalk from "chalk";
|
|
22
|
-
import { program } from "commander";
|
|
23
|
-
|
|
24
|
-
// Check npm availability at startup
|
|
25
|
-
const npmCheck = checkNpmAvailable();
|
|
26
|
-
if (!npmCheck.available) {
|
|
27
|
-
console.log(chalk.red(npmCheck.error));
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
program.name("omp").description("Oh My Pi - Plugin manager for pi configuration").version("0.2.0");
|
|
32
|
-
|
|
33
|
-
// ============================================================================
|
|
34
|
-
// Core Commands
|
|
35
|
-
// ============================================================================
|
|
36
|
-
|
|
37
|
-
program
|
|
38
|
-
.command("install [packages...]")
|
|
39
|
-
.alias("i")
|
|
40
|
-
.description("Install plugin(s). No args = install from plugins.json")
|
|
41
|
-
.addHelpText(
|
|
42
|
-
"after",
|
|
43
|
-
`
|
|
44
|
-
Examples:
|
|
45
|
-
$ omp install @oh-my-pi/subagents # Install from npm (all features)
|
|
46
|
-
$ omp install @oh-my-pi/exa[search] # Install with specific features
|
|
47
|
-
$ omp install @oh-my-pi/exa[search,websets] # Multiple features
|
|
48
|
-
$ omp install @oh-my-pi/exa[*] # Explicitly all features
|
|
49
|
-
$ omp install @oh-my-pi/exa[] # No optional features (core only)
|
|
50
|
-
$ omp install @oh-my-pi/subagents@^2.0.0 # Specific version range
|
|
51
|
-
$ omp install ./local/path # Local directory (copies)
|
|
52
|
-
$ omp install # Install all from plugins.json
|
|
53
|
-
`,
|
|
54
|
-
)
|
|
55
|
-
.option("-g, --global", "Install globally to ~/.pi")
|
|
56
|
-
.option("-l, --local", "Install to project-local .pi/")
|
|
57
|
-
.option("-S, --save", "Add to plugins.json")
|
|
58
|
-
.option("-D, --save-dev", "Add as dev dependency")
|
|
59
|
-
.option("--force", "Overwrite conflicts without prompting")
|
|
60
|
-
.option("--json", "Output as JSON")
|
|
61
|
-
.action(withErrorHandling(installPlugin));
|
|
62
|
-
|
|
63
|
-
program
|
|
64
|
-
.command("uninstall <name>")
|
|
65
|
-
.alias("rm")
|
|
66
|
-
.description("Remove plugin and its symlinks")
|
|
67
|
-
.option("-g, --global", "Uninstall from ~/.pi")
|
|
68
|
-
.option("-l, --local", "Uninstall from project-local .pi/")
|
|
69
|
-
.option("--json", "Output as JSON")
|
|
70
|
-
.action(withErrorHandling(uninstallPlugin));
|
|
71
|
-
|
|
72
|
-
program
|
|
73
|
-
.command("update [name]")
|
|
74
|
-
.alias("up")
|
|
75
|
-
.description("Update to latest within semver range")
|
|
76
|
-
.option("-g, --global", "Update global plugins")
|
|
77
|
-
.option("-l, --local", "Update project-local plugins")
|
|
78
|
-
.option("--json", "Output as JSON")
|
|
79
|
-
.action(withErrorHandling(updatePlugin));
|
|
80
|
-
|
|
81
|
-
program
|
|
82
|
-
.command("list")
|
|
83
|
-
.alias("ls")
|
|
84
|
-
.description("Show installed plugins")
|
|
85
|
-
.option("-g, --global", "List global plugins")
|
|
86
|
-
.option("-l, --local", "List project-local plugins")
|
|
87
|
-
.option("--json", "Output as JSON")
|
|
88
|
-
.action(withErrorHandling(listPlugins));
|
|
89
|
-
|
|
90
|
-
program
|
|
91
|
-
.command("link <path>")
|
|
92
|
-
.description("Symlink local plugin (dev mode)")
|
|
93
|
-
.addHelpText(
|
|
94
|
-
"after",
|
|
95
|
-
`
|
|
96
|
-
Unlike install, link creates a symlink to the original directory,
|
|
97
|
-
so changes are reflected immediately without reinstalling.
|
|
98
|
-
`,
|
|
99
|
-
)
|
|
100
|
-
.option("-n, --name <name>", "Custom name for the plugin")
|
|
101
|
-
.option("-g, --global", "Link globally")
|
|
102
|
-
.option("-l, --local", "Link to project-local .pi/")
|
|
103
|
-
.option("--force", "Overwrite existing npm-installed plugin")
|
|
104
|
-
.action(withErrorHandling(linkPlugin));
|
|
105
|
-
|
|
106
|
-
// ============================================================================
|
|
107
|
-
// New Commands
|
|
108
|
-
// ============================================================================
|
|
109
|
-
|
|
110
|
-
program
|
|
111
|
-
.command("init")
|
|
112
|
-
.description("Create .pi/plugins.json in current project")
|
|
113
|
-
.option("--force", "Overwrite existing plugins.json")
|
|
114
|
-
.action(withErrorHandling(initProject));
|
|
115
|
-
|
|
116
|
-
program
|
|
117
|
-
.command("search <query>")
|
|
118
|
-
.description("Search npm for omp-plugin keyword")
|
|
119
|
-
.option("--json", "Output as JSON")
|
|
120
|
-
.option("--limit <n>", "Maximum results to show", "20")
|
|
121
|
-
.action(
|
|
122
|
-
withErrorHandling((query, options) => searchPlugins(query, { ...options, limit: parseInt(options.limit, 10) })),
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
program
|
|
126
|
-
.command("info <package>")
|
|
127
|
-
.description("Show plugin details before install")
|
|
128
|
-
.option("--json", "Output as JSON")
|
|
129
|
-
.option("--versions", "Show available versions")
|
|
130
|
-
.option("--all-versions", "Show all published versions")
|
|
131
|
-
.action(withErrorHandling(showInfo));
|
|
132
|
-
|
|
133
|
-
program
|
|
134
|
-
.command("outdated")
|
|
135
|
-
.description("List plugins with newer versions")
|
|
136
|
-
.option("-g, --global", "Check global plugins")
|
|
137
|
-
.option("-l, --local", "Check project-local plugins")
|
|
138
|
-
.option("--json", "Output as JSON")
|
|
139
|
-
.action(withErrorHandling(showOutdated));
|
|
140
|
-
|
|
141
|
-
program
|
|
142
|
-
.command("doctor")
|
|
143
|
-
.description("Check for broken symlinks, conflicts")
|
|
144
|
-
.option("-g, --global", "Check global plugins")
|
|
145
|
-
.option("-l, --local", "Check project-local plugins")
|
|
146
|
-
.option("--fix", "Attempt to fix issues")
|
|
147
|
-
.option("--json", "Output as JSON")
|
|
148
|
-
.action(withErrorHandling(runDoctor));
|
|
149
|
-
|
|
150
|
-
program
|
|
151
|
-
.command("create <name>")
|
|
152
|
-
.description("Scaffold new plugin from template")
|
|
153
|
-
.option("-d, --description <desc>", "Plugin description")
|
|
154
|
-
.option("-a, --author <author>", "Plugin author")
|
|
155
|
-
.action(withErrorHandling(createPlugin));
|
|
156
|
-
|
|
157
|
-
program
|
|
158
|
-
.command("why <file>")
|
|
159
|
-
.description("Show which plugin installed a file")
|
|
160
|
-
.option("-g, --global", "Check global plugins")
|
|
161
|
-
.option("-l, --local", "Check project-local plugins")
|
|
162
|
-
.option("--json", "Output as JSON")
|
|
163
|
-
.action(withErrorHandling(whyFile));
|
|
164
|
-
|
|
165
|
-
program
|
|
166
|
-
.command("enable <name>")
|
|
167
|
-
.description("Enable a disabled plugin")
|
|
168
|
-
.option("-g, --global", "Target global plugins")
|
|
169
|
-
.option("-l, --local", "Target project-local plugins")
|
|
170
|
-
.option("--json", "Output as JSON")
|
|
171
|
-
.action(withErrorHandling(enablePlugin));
|
|
172
|
-
|
|
173
|
-
program
|
|
174
|
-
.command("disable <name>")
|
|
175
|
-
.description("Disable plugin without uninstalling")
|
|
176
|
-
.option("-g, --global", "Target global plugins")
|
|
177
|
-
.option("-l, --local", "Target project-local plugins")
|
|
178
|
-
.option("--json", "Output as JSON")
|
|
179
|
-
.action(withErrorHandling(disablePlugin));
|
|
180
|
-
|
|
181
|
-
program
|
|
182
|
-
.command("features <name>")
|
|
183
|
-
.description("List or configure plugin features")
|
|
184
|
-
.addHelpText(
|
|
185
|
-
"after",
|
|
186
|
-
`
|
|
187
|
-
Examples:
|
|
188
|
-
$ omp features @oh-my-pi/exa # List available features
|
|
189
|
-
$ omp features @oh-my-pi/exa --enable websets # Enable a feature
|
|
190
|
-
$ omp features @oh-my-pi/exa --disable search # Disable a feature
|
|
191
|
-
$ omp features @oh-my-pi/exa --set search,websets # Set exact features
|
|
192
|
-
$ omp features @oh-my-pi/exa --set '*' # Enable all features
|
|
193
|
-
$ omp features @oh-my-pi/exa --set '' # Disable all optional features
|
|
194
|
-
`,
|
|
195
|
-
)
|
|
196
|
-
.option("-g, --global", "Target global plugins")
|
|
197
|
-
.option("-l, --local", "Target project-local plugins")
|
|
198
|
-
.option("--enable <features...>", "Enable specific features")
|
|
199
|
-
.option("--disable <features...>", "Disable specific features")
|
|
200
|
-
.option("--set <features>", "Set exact feature list (comma-separated, '*' for all, '' for none)")
|
|
201
|
-
.option("--json", "Output as JSON")
|
|
202
|
-
.action(withErrorHandling(featuresCommand));
|
|
203
|
-
|
|
204
|
-
program
|
|
205
|
-
.command("config <name> [key] [value]")
|
|
206
|
-
.description("Get or set plugin configuration variables")
|
|
207
|
-
.addHelpText(
|
|
208
|
-
"after",
|
|
209
|
-
`
|
|
210
|
-
Examples:
|
|
211
|
-
$ omp config @oh-my-pi/exa # List all variables
|
|
212
|
-
$ omp config @oh-my-pi/exa apiKey # Get value of apiKey
|
|
213
|
-
$ omp config @oh-my-pi/exa apiKey sk-xxx # Set apiKey to sk-xxx
|
|
214
|
-
$ omp config @oh-my-pi/exa apiKey --delete # Reset apiKey to default
|
|
215
|
-
`,
|
|
216
|
-
)
|
|
217
|
-
.option("-g, --global", "Target global plugins")
|
|
218
|
-
.option("-l, --local", "Target project-local plugins")
|
|
219
|
-
.option("--delete", "Delete/reset the variable to its default")
|
|
220
|
-
.option("--json", "Output as JSON")
|
|
221
|
-
.action(withErrorHandling(configCommand));
|
|
222
|
-
|
|
223
|
-
program
|
|
224
|
-
.command("env")
|
|
225
|
-
.description("Print plugin environment variables for shell eval")
|
|
226
|
-
.addHelpText(
|
|
227
|
-
"after",
|
|
228
|
-
`
|
|
229
|
-
Examples:
|
|
230
|
-
$ eval "$(omp env)" # Load env vars in current shell
|
|
231
|
-
$ omp env >> ~/.bashrc # Persist to shell config
|
|
232
|
-
$ omp env --fish | source # Fish shell syntax
|
|
233
|
-
$ omp env --json # JSON format for scripts
|
|
234
|
-
`,
|
|
235
|
-
)
|
|
236
|
-
.option("-g, --global", "Target global plugins")
|
|
237
|
-
.option("-l, --local", "Target project-local plugins")
|
|
238
|
-
.option("--fish", "Output fish shell syntax instead of POSIX")
|
|
239
|
-
.option("--json", "Output as JSON")
|
|
240
|
-
.action(withErrorHandling(envCommand));
|
|
241
|
-
|
|
242
|
-
program.parse();
|
package/src/commands/config.ts
DELETED
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
import type { OmpVariable } from "@omp/manifest";
|
|
2
|
-
import { loadPluginsJson, readPluginPackageJson, savePluginsJson } from "@omp/manifest";
|
|
3
|
-
import { resolveScope } from "@omp/paths";
|
|
4
|
-
import chalk from "chalk";
|
|
5
|
-
|
|
6
|
-
export interface ConfigOptions {
|
|
7
|
-
global?: boolean;
|
|
8
|
-
local?: boolean;
|
|
9
|
-
json?: boolean;
|
|
10
|
-
delete?: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Collect all variables from a plugin (top-level + enabled features)
|
|
15
|
-
*/
|
|
16
|
-
function collectVariables(
|
|
17
|
-
pkgJson: { omp?: { variables?: Record<string, OmpVariable>; features?: Record<string, { variables?: Record<string, OmpVariable> }> } },
|
|
18
|
-
enabledFeatures: string[],
|
|
19
|
-
): Record<string, OmpVariable> {
|
|
20
|
-
const vars: Record<string, OmpVariable> = {};
|
|
21
|
-
|
|
22
|
-
// Top-level variables
|
|
23
|
-
if (pkgJson.omp?.variables) {
|
|
24
|
-
Object.assign(vars, pkgJson.omp.variables);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Variables from enabled features
|
|
28
|
-
if (pkgJson.omp?.features) {
|
|
29
|
-
for (const fname of enabledFeatures) {
|
|
30
|
-
const feature = pkgJson.omp.features[fname];
|
|
31
|
-
if (feature?.variables) {
|
|
32
|
-
Object.assign(vars, feature.variables);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return vars;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Parse a string value to the appropriate type based on variable definition
|
|
42
|
-
*/
|
|
43
|
-
function parseValue(value: string, varDef: OmpVariable): string | number | boolean | string[] {
|
|
44
|
-
switch (varDef.type) {
|
|
45
|
-
case "number":
|
|
46
|
-
const num = Number(value);
|
|
47
|
-
if (isNaN(num)) {
|
|
48
|
-
throw new Error(`Invalid number: ${value}`);
|
|
49
|
-
}
|
|
50
|
-
return num;
|
|
51
|
-
case "boolean":
|
|
52
|
-
if (value === "true" || value === "1" || value === "yes") return true;
|
|
53
|
-
if (value === "false" || value === "0" || value === "no") return false;
|
|
54
|
-
throw new Error(`Invalid boolean: ${value}. Use true/false, 1/0, or yes/no`);
|
|
55
|
-
case "string[]":
|
|
56
|
-
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
57
|
-
default:
|
|
58
|
-
return value;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Format a value for display
|
|
64
|
-
*/
|
|
65
|
-
function formatValue(value: unknown, varDef: OmpVariable): string {
|
|
66
|
-
if (value === undefined) {
|
|
67
|
-
return chalk.dim("(not set)");
|
|
68
|
-
}
|
|
69
|
-
if (varDef.type === "string[]" && Array.isArray(value)) {
|
|
70
|
-
return value.join(", ");
|
|
71
|
-
}
|
|
72
|
-
if (typeof value === "string" && varDef.env) {
|
|
73
|
-
// Mask sensitive values (likely API keys)
|
|
74
|
-
if (value.length > 8) {
|
|
75
|
-
return `${value.slice(0, 4)}...${value.slice(-4)}`;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return String(value);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Resolve which features are currently enabled
|
|
83
|
-
*
|
|
84
|
-
* - null/undefined: use plugin defaults (features with default !== false)
|
|
85
|
-
* - ["*"]: explicitly all features
|
|
86
|
-
* - []: no optional features
|
|
87
|
-
* - ["f1", "f2"]: specific features
|
|
88
|
-
*/
|
|
89
|
-
function resolveEnabledFeatures(
|
|
90
|
-
allFeatureNames: string[],
|
|
91
|
-
storedFeatures: string[] | null | undefined,
|
|
92
|
-
pluginFeatures: Record<string, { default?: boolean }>,
|
|
93
|
-
): string[] {
|
|
94
|
-
// Explicit "all features" request
|
|
95
|
-
if (Array.isArray(storedFeatures) && storedFeatures.includes("*")) return allFeatureNames;
|
|
96
|
-
// Explicit feature list (including empty array = no features)
|
|
97
|
-
if (Array.isArray(storedFeatures)) return storedFeatures;
|
|
98
|
-
// null/undefined = use defaults
|
|
99
|
-
return Object.entries(pluginFeatures)
|
|
100
|
-
.filter(([_, f]) => f.default !== false)
|
|
101
|
-
.map(([name]) => name);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* List all configurable variables for a plugin
|
|
106
|
-
* omp config @oh-my-pi/exa
|
|
107
|
-
*/
|
|
108
|
-
export async function listConfig(name: string, options: ConfigOptions = {}): Promise<void> {
|
|
109
|
-
const isGlobal = resolveScope(options);
|
|
110
|
-
const pluginsJson = await loadPluginsJson(isGlobal);
|
|
111
|
-
|
|
112
|
-
if (!pluginsJson.plugins[name]) {
|
|
113
|
-
console.log(chalk.yellow(`Plugin "${name}" is not installed.`));
|
|
114
|
-
process.exitCode = 1;
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const pkgJson = await readPluginPackageJson(name, isGlobal);
|
|
119
|
-
if (!pkgJson) {
|
|
120
|
-
console.log(chalk.red(`Could not read package.json for ${name}`));
|
|
121
|
-
process.exitCode = 1;
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const allFeatureNames = Object.keys(pkgJson.omp?.features || {});
|
|
126
|
-
const config = pluginsJson.config?.[name];
|
|
127
|
-
const enabledFeatures = resolveEnabledFeatures(allFeatureNames, config?.features, pkgJson.omp?.features || {});
|
|
128
|
-
const variables = collectVariables(pkgJson, enabledFeatures);
|
|
129
|
-
|
|
130
|
-
if (Object.keys(variables).length === 0) {
|
|
131
|
-
console.log(chalk.yellow(`Plugin "${name}" has no configurable variables.`));
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const userVars = config?.variables || {};
|
|
136
|
-
|
|
137
|
-
if (options.json) {
|
|
138
|
-
console.log(
|
|
139
|
-
JSON.stringify(
|
|
140
|
-
{
|
|
141
|
-
plugin: name,
|
|
142
|
-
variables: Object.entries(variables).map(([vname, vdef]) => ({
|
|
143
|
-
name: vname,
|
|
144
|
-
type: vdef.type,
|
|
145
|
-
value: userVars[vname],
|
|
146
|
-
default: vdef.default,
|
|
147
|
-
required: vdef.required,
|
|
148
|
-
env: vdef.env,
|
|
149
|
-
description: vdef.description,
|
|
150
|
-
})),
|
|
151
|
-
},
|
|
152
|
-
null,
|
|
153
|
-
2,
|
|
154
|
-
),
|
|
155
|
-
);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
console.log(chalk.bold(`\nVariables for ${name}:\n`));
|
|
160
|
-
|
|
161
|
-
for (const [vname, vdef] of Object.entries(variables)) {
|
|
162
|
-
const currentValue = userVars[vname];
|
|
163
|
-
const hasValue = currentValue !== undefined;
|
|
164
|
-
const hasDefault = vdef.default !== undefined;
|
|
165
|
-
|
|
166
|
-
const icon = hasValue ? chalk.green("✓") : hasDefault ? chalk.blue("○") : vdef.required ? chalk.red("!") : chalk.gray("○");
|
|
167
|
-
const requiredStr = vdef.required && !hasValue ? chalk.red(" (required)") : "";
|
|
168
|
-
const envStr = vdef.env ? chalk.dim(` [${vdef.env}]`) : "";
|
|
169
|
-
|
|
170
|
-
console.log(`${icon} ${chalk.bold(vname)}${requiredStr}${envStr}`);
|
|
171
|
-
|
|
172
|
-
if (vdef.description) {
|
|
173
|
-
console.log(chalk.dim(` ${vdef.description}`));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
console.log(chalk.dim(` Type: ${vdef.type}`));
|
|
177
|
-
|
|
178
|
-
if (hasValue) {
|
|
179
|
-
console.log(` Value: ${formatValue(currentValue, vdef)}`);
|
|
180
|
-
} else if (hasDefault) {
|
|
181
|
-
console.log(` Default: ${formatValue(vdef.default, vdef)}`);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
console.log();
|
|
186
|
-
console.log(chalk.dim(`Set a value: omp config ${name} <variable> <value>`));
|
|
187
|
-
console.log(chalk.dim(`Delete a value: omp config ${name} <variable> --delete`));
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Get a specific variable value
|
|
192
|
-
* omp config @oh-my-pi/exa apiKey
|
|
193
|
-
*/
|
|
194
|
-
export async function getConfig(name: string, key: string, options: ConfigOptions = {}): Promise<void> {
|
|
195
|
-
const isGlobal = resolveScope(options);
|
|
196
|
-
const pluginsJson = await loadPluginsJson(isGlobal);
|
|
197
|
-
|
|
198
|
-
if (!pluginsJson.plugins[name]) {
|
|
199
|
-
console.log(chalk.yellow(`Plugin "${name}" is not installed.`));
|
|
200
|
-
process.exitCode = 1;
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const pkgJson = await readPluginPackageJson(name, isGlobal);
|
|
205
|
-
if (!pkgJson) {
|
|
206
|
-
console.log(chalk.red(`Could not read package.json for ${name}`));
|
|
207
|
-
process.exitCode = 1;
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const allFeatureNames = Object.keys(pkgJson.omp?.features || {});
|
|
212
|
-
const config = pluginsJson.config?.[name];
|
|
213
|
-
const enabledFeatures = resolveEnabledFeatures(allFeatureNames, config?.features, pkgJson.omp?.features || {});
|
|
214
|
-
const variables = collectVariables(pkgJson, enabledFeatures);
|
|
215
|
-
|
|
216
|
-
const varDef = variables[key];
|
|
217
|
-
if (!varDef) {
|
|
218
|
-
console.log(chalk.red(`Unknown variable "${key}".`));
|
|
219
|
-
console.log(chalk.dim(`Available: ${Object.keys(variables).join(", ") || "(none)"}`));
|
|
220
|
-
process.exitCode = 1;
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const userValue = config?.variables?.[key];
|
|
225
|
-
const value = userValue ?? varDef.default;
|
|
226
|
-
|
|
227
|
-
if (options.json) {
|
|
228
|
-
console.log(JSON.stringify({ plugin: name, variable: key, value, default: varDef.default }, null, 2));
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (value !== undefined) {
|
|
233
|
-
console.log(formatValue(value, varDef));
|
|
234
|
-
} else {
|
|
235
|
-
console.log(chalk.dim("(not set)"));
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Set a variable value
|
|
241
|
-
* omp config @oh-my-pi/exa apiKey sk-xxx
|
|
242
|
-
*/
|
|
243
|
-
export async function setConfig(name: string, key: string, value: string, options: ConfigOptions = {}): Promise<void> {
|
|
244
|
-
const isGlobal = resolveScope(options);
|
|
245
|
-
const pluginsJson = await loadPluginsJson(isGlobal);
|
|
246
|
-
|
|
247
|
-
if (!pluginsJson.plugins[name]) {
|
|
248
|
-
console.log(chalk.yellow(`Plugin "${name}" is not installed.`));
|
|
249
|
-
process.exitCode = 1;
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const pkgJson = await readPluginPackageJson(name, isGlobal);
|
|
254
|
-
if (!pkgJson) {
|
|
255
|
-
console.log(chalk.red(`Could not read package.json for ${name}`));
|
|
256
|
-
process.exitCode = 1;
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const allFeatureNames = Object.keys(pkgJson.omp?.features || {});
|
|
261
|
-
const config = pluginsJson.config?.[name];
|
|
262
|
-
const enabledFeatures = resolveEnabledFeatures(allFeatureNames, config?.features, pkgJson.omp?.features || {});
|
|
263
|
-
const variables = collectVariables(pkgJson, enabledFeatures);
|
|
264
|
-
|
|
265
|
-
const varDef = variables[key];
|
|
266
|
-
if (!varDef) {
|
|
267
|
-
console.log(chalk.red(`Unknown variable "${key}".`));
|
|
268
|
-
console.log(chalk.dim(`Available: ${Object.keys(variables).join(", ") || "(none)"}`));
|
|
269
|
-
process.exitCode = 1;
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Parse and validate value
|
|
274
|
-
let parsed: string | number | boolean | string[];
|
|
275
|
-
try {
|
|
276
|
-
parsed = parseValue(value, varDef);
|
|
277
|
-
} catch (err) {
|
|
278
|
-
console.log(chalk.red((err as Error).message));
|
|
279
|
-
process.exitCode = 1;
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Update config
|
|
284
|
-
if (!pluginsJson.config) pluginsJson.config = {};
|
|
285
|
-
if (!pluginsJson.config[name]) pluginsJson.config[name] = {};
|
|
286
|
-
if (!pluginsJson.config[name].variables) pluginsJson.config[name].variables = {};
|
|
287
|
-
|
|
288
|
-
pluginsJson.config[name].variables[key] = parsed;
|
|
289
|
-
await savePluginsJson(pluginsJson, isGlobal);
|
|
290
|
-
|
|
291
|
-
console.log(chalk.green(`✓ Set ${name}.${key} = ${JSON.stringify(parsed)}`));
|
|
292
|
-
|
|
293
|
-
if (varDef.env) {
|
|
294
|
-
console.log(chalk.dim(` Environment variable: ${varDef.env}`));
|
|
295
|
-
console.log(chalk.dim(` Export with: omp env`));
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (options.json) {
|
|
299
|
-
console.log(JSON.stringify({ plugin: name, variable: key, value: parsed }, null, 2));
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Delete a variable override (revert to default)
|
|
305
|
-
* omp config @oh-my-pi/exa apiKey --delete
|
|
306
|
-
*/
|
|
307
|
-
export async function deleteConfig(name: string, key: string, options: ConfigOptions = {}): Promise<void> {
|
|
308
|
-
const isGlobal = resolveScope(options);
|
|
309
|
-
const pluginsJson = await loadPluginsJson(isGlobal);
|
|
310
|
-
|
|
311
|
-
if (!pluginsJson.plugins[name]) {
|
|
312
|
-
console.log(chalk.yellow(`Plugin "${name}" is not installed.`));
|
|
313
|
-
process.exitCode = 1;
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const config = pluginsJson.config?.[name];
|
|
318
|
-
// Check key presence with hasOwnProperty, not truthiness (allows deleting falsy values like false, 0, "", [])
|
|
319
|
-
if (!config?.variables || !Object.prototype.hasOwnProperty.call(config.variables, key)) {
|
|
320
|
-
console.log(chalk.yellow(`Variable "${key}" is not set for ${name}.`));
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
delete pluginsJson.config![name].variables![key];
|
|
325
|
-
|
|
326
|
-
// Clean up empty objects
|
|
327
|
-
if (Object.keys(pluginsJson.config![name].variables!).length === 0) {
|
|
328
|
-
delete pluginsJson.config![name].variables;
|
|
329
|
-
}
|
|
330
|
-
if (Object.keys(pluginsJson.config![name]).length === 0) {
|
|
331
|
-
delete pluginsJson.config![name];
|
|
332
|
-
}
|
|
333
|
-
if (Object.keys(pluginsJson.config!).length === 0) {
|
|
334
|
-
delete pluginsJson.config;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
await savePluginsJson(pluginsJson, isGlobal);
|
|
338
|
-
|
|
339
|
-
console.log(chalk.green(`✓ Deleted ${name}.${key} (reverted to default)`));
|
|
340
|
-
|
|
341
|
-
if (options.json) {
|
|
342
|
-
console.log(JSON.stringify({ plugin: name, variable: key, deleted: true }, null, 2));
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Main config command handler
|
|
348
|
-
* Routes to list, get, set, or delete based on arguments
|
|
349
|
-
*/
|
|
350
|
-
export async function configCommand(
|
|
351
|
-
name: string,
|
|
352
|
-
keyOrOptions?: string | ConfigOptions,
|
|
353
|
-
valueOrOptions?: string | ConfigOptions,
|
|
354
|
-
options: ConfigOptions = {},
|
|
355
|
-
): Promise<void> {
|
|
356
|
-
// Handle different argument patterns
|
|
357
|
-
let key: string | undefined;
|
|
358
|
-
let value: string | undefined;
|
|
359
|
-
let opts: ConfigOptions;
|
|
360
|
-
|
|
361
|
-
if (typeof keyOrOptions === "object") {
|
|
362
|
-
// omp config <name> [options]
|
|
363
|
-
opts = keyOrOptions;
|
|
364
|
-
} else if (typeof valueOrOptions === "object") {
|
|
365
|
-
// omp config <name> <key> [options]
|
|
366
|
-
key = keyOrOptions;
|
|
367
|
-
opts = valueOrOptions;
|
|
368
|
-
} else {
|
|
369
|
-
// omp config <name> <key> <value> [options]
|
|
370
|
-
key = keyOrOptions;
|
|
371
|
-
value = valueOrOptions;
|
|
372
|
-
opts = options;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (!key) {
|
|
376
|
-
await listConfig(name, opts);
|
|
377
|
-
} else if (opts.delete) {
|
|
378
|
-
await deleteConfig(name, key, opts);
|
|
379
|
-
} else if (value !== undefined) {
|
|
380
|
-
await setConfig(name, key, value, opts);
|
|
381
|
-
} else {
|
|
382
|
-
await getConfig(name, key, opts);
|
|
383
|
-
}
|
|
384
|
-
}
|