@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.
Files changed (108) hide show
  1. package/README.md +79 -84
  2. package/dist/cli.js +5025 -1016
  3. package/dist/commands/config.d.ts +27 -0
  4. package/dist/commands/config.d.ts.map +1 -1
  5. package/dist/commands/create.d.ts.map +1 -1
  6. package/dist/commands/doctor.d.ts +2 -0
  7. package/dist/commands/doctor.d.ts.map +1 -1
  8. package/dist/commands/env.d.ts.map +1 -1
  9. package/dist/commands/features.d.ts.map +1 -1
  10. package/dist/commands/info.d.ts.map +1 -1
  11. package/dist/commands/init.d.ts.map +1 -1
  12. package/dist/commands/install.d.ts +6 -0
  13. package/dist/commands/install.d.ts.map +1 -1
  14. package/dist/commands/link.d.ts +1 -0
  15. package/dist/commands/link.d.ts.map +1 -1
  16. package/dist/commands/list.d.ts.map +1 -1
  17. package/dist/commands/outdated.d.ts.map +1 -1
  18. package/dist/commands/search.d.ts.map +1 -1
  19. package/dist/commands/uninstall.d.ts +3 -0
  20. package/dist/commands/uninstall.d.ts.map +1 -1
  21. package/dist/commands/update.d.ts +1 -0
  22. package/dist/commands/update.d.ts.map +1 -1
  23. package/dist/commands/why.d.ts.map +1 -1
  24. package/dist/conflicts.d.ts +7 -2
  25. package/dist/conflicts.d.ts.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/lock.d.ts.map +1 -1
  29. package/dist/lockfile.d.ts +24 -3
  30. package/dist/lockfile.d.ts.map +1 -1
  31. package/dist/manifest.d.ts +12 -1
  32. package/dist/manifest.d.ts.map +1 -1
  33. package/dist/npm.d.ts +11 -0
  34. package/dist/npm.d.ts.map +1 -1
  35. package/dist/output.d.ts +51 -0
  36. package/dist/output.d.ts.map +1 -0
  37. package/dist/paths.d.ts +5 -0
  38. package/dist/paths.d.ts.map +1 -1
  39. package/dist/progress.d.ts +78 -0
  40. package/dist/progress.d.ts.map +1 -0
  41. package/dist/runtime.d.ts.map +1 -1
  42. package/dist/symlinks.d.ts +1 -0
  43. package/dist/symlinks.d.ts.map +1 -1
  44. package/package.json +24 -10
  45. package/.github/icon.png +0 -0
  46. package/.github/logo.png +0 -0
  47. package/.github/workflows/ci.yml +0 -32
  48. package/.github/workflows/publish.yml +0 -42
  49. package/biome.json +0 -29
  50. package/bun.lock +0 -109
  51. package/plugins/exa/README.md +0 -153
  52. package/plugins/exa/package.json +0 -56
  53. package/plugins/exa/tools/exa/company.ts +0 -35
  54. package/plugins/exa/tools/exa/index.ts +0 -66
  55. package/plugins/exa/tools/exa/linkedin.ts +0 -35
  56. package/plugins/exa/tools/exa/researcher.ts +0 -40
  57. package/plugins/exa/tools/exa/runtime.json +0 -4
  58. package/plugins/exa/tools/exa/search.ts +0 -46
  59. package/plugins/exa/tools/exa/shared.ts +0 -230
  60. package/plugins/exa/tools/exa/websets.ts +0 -62
  61. package/plugins/metal-theme/README.md +0 -13
  62. package/plugins/metal-theme/omp.json +0 -8
  63. package/plugins/metal-theme/package.json +0 -19
  64. package/plugins/metal-theme/themes/metal.json +0 -79
  65. package/plugins/subagents/README.md +0 -25
  66. package/plugins/subagents/agents/explore.md +0 -71
  67. package/plugins/subagents/agents/planner.md +0 -51
  68. package/plugins/subagents/agents/reviewer.md +0 -53
  69. package/plugins/subagents/agents/task.md +0 -46
  70. package/plugins/subagents/commands/architect-plan.md +0 -9
  71. package/plugins/subagents/commands/implement-with-critic.md +0 -10
  72. package/plugins/subagents/commands/implement.md +0 -10
  73. package/plugins/subagents/omp.json +0 -15
  74. package/plugins/subagents/package.json +0 -26
  75. package/plugins/subagents/tools/task/index.ts +0 -1019
  76. package/plugins/user-prompt/README.md +0 -130
  77. package/plugins/user-prompt/package.json +0 -19
  78. package/plugins/user-prompt/tools/user-prompt/index.ts +0 -235
  79. package/scripts/bump-version.sh +0 -52
  80. package/scripts/publish.sh +0 -35
  81. package/src/cli.ts +0 -242
  82. package/src/commands/config.ts +0 -384
  83. package/src/commands/create.ts +0 -203
  84. package/src/commands/doctor.ts +0 -305
  85. package/src/commands/enable.ts +0 -122
  86. package/src/commands/env.ts +0 -38
  87. package/src/commands/features.ts +0 -295
  88. package/src/commands/info.ts +0 -120
  89. package/src/commands/init.ts +0 -60
  90. package/src/commands/install.ts +0 -700
  91. package/src/commands/link.ts +0 -159
  92. package/src/commands/list.ts +0 -186
  93. package/src/commands/outdated.ts +0 -87
  94. package/src/commands/search.ts +0 -77
  95. package/src/commands/uninstall.ts +0 -124
  96. package/src/commands/update.ts +0 -170
  97. package/src/commands/why.ts +0 -136
  98. package/src/conflicts.ts +0 -116
  99. package/src/errors.ts +0 -22
  100. package/src/index.ts +0 -46
  101. package/src/lock.ts +0 -46
  102. package/src/lockfile.ts +0 -132
  103. package/src/manifest.ts +0 -360
  104. package/src/npm.ts +0 -206
  105. package/src/paths.ts +0 -137
  106. package/src/runtime.ts +0 -116
  107. package/src/symlinks.ts +0 -455
  108. package/tsconfig.json +0 -28
@@ -1,203 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { mkdir, writeFile } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import chalk from "chalk";
5
-
6
- export interface CreateOptions {
7
- description?: string;
8
- author?: string;
9
- }
10
-
11
- const VALID_NPM_CHARS = new Set("abcdefghijklmnopqrstuvwxyz0123456789-_.");
12
-
13
- /**
14
- * Validate that a name conforms to npm naming rules
15
- */
16
- function isValidNpmName(name: string): boolean {
17
- if (!name || name.length === 0) return false;
18
- if (name.startsWith(".") || name.startsWith("_")) return false;
19
- if (name.includes(" ")) return false;
20
- for (const char of name) {
21
- if (!VALID_NPM_CHARS.has(char)) return false;
22
- }
23
- return true;
24
- }
25
-
26
- /**
27
- * Normalize a string to be a valid npm package name
28
- */
29
- function normalizePluginName(name: string): string {
30
- let normalized = name.toLowerCase().split(" ").join("-");
31
-
32
- // Remove invalid characters (keep alphanumeric, -, _, .)
33
- normalized = Array.from(normalized)
34
- .filter((char) => VALID_NPM_CHARS.has(char))
35
- .join("");
36
-
37
- // Can't start with . or _ or -
38
- while (normalized.startsWith(".") || normalized.startsWith("_") || normalized.startsWith("-")) {
39
- normalized = normalized.slice(1);
40
- }
41
-
42
- return normalized;
43
- }
44
-
45
- /**
46
- * Scaffold a new plugin from template
47
- */
48
- export async function createPlugin(name: string, options: CreateOptions = {}): Promise<void> {
49
- // Ensure name follows conventions
50
- let pluginName = name.startsWith("omp-") ? name : `omp-${name}`;
51
-
52
- // Validate and normalize the plugin name
53
- if (!isValidNpmName(pluginName)) {
54
- const normalized = normalizePluginName(pluginName);
55
- if (!normalized || normalized === "omp-" || normalized === "omp") {
56
- console.log(chalk.red(`Error: Invalid plugin name "${name}" cannot be normalized to a valid npm name`));
57
- process.exitCode = 1;
58
- return;
59
- }
60
- // Ensure omp- prefix after normalization
61
- const finalName = normalized.startsWith("omp-") ? normalized : `omp-${normalized}`;
62
- console.log(chalk.yellow(`Invalid plugin name. Normalized to: ${finalName}`));
63
- pluginName = finalName;
64
- }
65
- const pluginDir = pluginName;
66
-
67
- if (existsSync(pluginDir)) {
68
- console.log(chalk.red(`Error: Directory ${pluginDir} already exists`));
69
- process.exitCode = 1;
70
- return;
71
- }
72
-
73
- console.log(chalk.blue(`Creating plugin: ${pluginName}...`));
74
-
75
- try {
76
- // Create directory structure
77
- await mkdir(pluginDir, { recursive: true });
78
- await mkdir(join(pluginDir, "agents"), { recursive: true });
79
- await mkdir(join(pluginDir, "tools"), { recursive: true });
80
- await mkdir(join(pluginDir, "themes"), { recursive: true });
81
- await mkdir(join(pluginDir, "commands"), { recursive: true });
82
-
83
- // Create package.json
84
- const packageJson = {
85
- name: pluginName,
86
- version: "0.1.0",
87
- description: options.description || `A pi plugin`,
88
- keywords: ["omp-plugin"],
89
- author: options.author || "",
90
- license: "MIT",
91
- omp: {
92
- install: [],
93
- },
94
- files: ["agents", "tools", "themes", "commands"],
95
- };
96
-
97
- await writeFile(join(pluginDir, "package.json"), JSON.stringify(packageJson, null, 2));
98
-
99
- // Create README.md
100
- const readme = `# ${pluginName}
101
-
102
- ${options.description || "A pi plugin."}
103
-
104
- ## Installation
105
-
106
- \`\`\`bash
107
- omp install ${pluginName}
108
- \`\`\`
109
-
110
- ## Contents
111
-
112
- ### Agents
113
-
114
- Add agent markdown files to \`agents/\` directory.
115
-
116
- ### Tools
117
-
118
- Add tool implementations to \`tools/\` directory.
119
-
120
- ### Themes
121
-
122
- Add theme JSON files to \`themes/\` directory.
123
-
124
- ### Commands
125
-
126
- Add command markdown files to \`commands/\` directory.
127
-
128
- ## Configuration
129
-
130
- Edit \`package.json\` to configure which files are installed:
131
-
132
- \`\`\`json
133
- {
134
- "omp": {
135
- "install": [
136
- { "src": "agents/my-agent.md", "dest": "agent/agents/my-agent.md" },
137
- { "src": "tools/my-tool/", "dest": "agent/tools/my-tool/" }
138
- ]
139
- }
140
- }
141
- \`\`\`
142
-
143
- ## Publishing
144
-
145
- 1. Update version in package.json
146
- 2. Run \`npm publish\`
147
-
148
- Users can then install with: \`omp install ${pluginName}\`
149
-
150
- ## License
151
-
152
- MIT
153
- `;
154
-
155
- await writeFile(join(pluginDir, "README.md"), readme);
156
-
157
- // Create example agent
158
- const exampleAgent = `# Example Agent
159
-
160
- This is an example agent for ${pluginName}.
161
-
162
- ## Description
163
-
164
- Describe what this agent does.
165
-
166
- ## Instructions
167
-
168
- Provide instructions for the agent here.
169
- `;
170
-
171
- await writeFile(join(pluginDir, "agents", "example.md"), exampleAgent);
172
-
173
- // Create .gitignore
174
- const gitignore = `node_modules/
175
- .DS_Store
176
- *.log
177
- `;
178
- await writeFile(join(pluginDir, ".gitignore"), gitignore);
179
-
180
- console.log(chalk.green(`\n✓ Created plugin at ${pluginDir}/`));
181
- console.log();
182
- console.log(chalk.dim("Directory structure:"));
183
- console.log(chalk.dim(` ${pluginDir}/`));
184
- console.log(chalk.dim(" ├── package.json"));
185
- console.log(chalk.dim(" ├── README.md"));
186
- console.log(chalk.dim(" ├── .gitignore"));
187
- console.log(chalk.dim(" ├── agents/"));
188
- console.log(chalk.dim(" │ └── example.md"));
189
- console.log(chalk.dim(" ├── tools/"));
190
- console.log(chalk.dim(" ├── themes/"));
191
- console.log(chalk.dim(" └── commands/"));
192
- console.log();
193
- console.log(chalk.dim("Next steps:"));
194
- console.log(chalk.dim(` 1. cd ${pluginDir}`));
195
- console.log(chalk.dim(" 2. Add your agents, tools, themes, or commands"));
196
- console.log(chalk.dim(" 3. Update omp.install in package.json"));
197
- console.log(chalk.dim(" 4. Test locally: omp link ."));
198
- console.log(chalk.dim(" 5. Publish: npm publish"));
199
- } catch (err) {
200
- console.log(chalk.red(`Error creating plugin: ${(err as Error).message}`));
201
- process.exitCode = 1;
202
- }
203
- }
@@ -1,305 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { detectAllConflicts, formatConflicts } from "@omp/conflicts";
3
- import { getInstalledPlugins, loadPluginsJson, readPluginPackageJson, savePluginsJson } from "@omp/manifest";
4
- import {
5
- GLOBAL_PACKAGE_JSON,
6
- NODE_MODULES_DIR,
7
- PLUGINS_DIR,
8
- PROJECT_NODE_MODULES,
9
- PROJECT_PLUGINS_JSON,
10
- resolveScope,
11
- } from "@omp/paths";
12
- import { checkPluginSymlinks, createPluginSymlinks } from "@omp/symlinks";
13
- import chalk from "chalk";
14
-
15
- export interface DoctorOptions {
16
- global?: boolean;
17
- local?: boolean;
18
- fix?: boolean;
19
- json?: boolean;
20
- }
21
-
22
- interface DiagnosticResult {
23
- check: string;
24
- status: "ok" | "warning" | "error";
25
- message: string;
26
- fix?: string;
27
- }
28
-
29
- /**
30
- * Run health checks on the plugin system
31
- */
32
- export async function runDoctor(options: DoctorOptions = {}): Promise<void> {
33
- const isGlobal = resolveScope(options);
34
- const results: DiagnosticResult[] = [];
35
-
36
- console.log(chalk.blue("Running health checks...\n"));
37
-
38
- // 1. Check plugins directory exists
39
- const pluginsDir = isGlobal ? PLUGINS_DIR : ".pi";
40
- if (!existsSync(pluginsDir)) {
41
- results.push({
42
- check: "Plugins directory",
43
- status: "warning",
44
- message: `${pluginsDir} does not exist`,
45
- fix: "Run: omp install <package>",
46
- });
47
- } else {
48
- results.push({
49
- check: "Plugins directory",
50
- status: "ok",
51
- message: pluginsDir,
52
- });
53
- }
54
-
55
- // 2. Check package.json exists
56
- const packageJsonPath = isGlobal ? GLOBAL_PACKAGE_JSON : PROJECT_PLUGINS_JSON;
57
- if (!existsSync(packageJsonPath)) {
58
- results.push({
59
- check: "Package manifest",
60
- status: "warning",
61
- message: `${packageJsonPath} does not exist`,
62
- fix: isGlobal ? "Run: omp install <package>" : "Run: omp init",
63
- });
64
- } else {
65
- results.push({
66
- check: "Package manifest",
67
- status: "ok",
68
- message: packageJsonPath,
69
- });
70
- }
71
-
72
- // 3. Check node_modules exists
73
- const nodeModules = isGlobal ? NODE_MODULES_DIR : PROJECT_NODE_MODULES;
74
- if (!existsSync(nodeModules)) {
75
- results.push({
76
- check: "Node modules",
77
- status: "warning",
78
- message: `${nodeModules} does not exist`,
79
- });
80
- } else {
81
- results.push({
82
- check: "Node modules",
83
- status: "ok",
84
- message: nodeModules,
85
- });
86
- }
87
-
88
- // 4. Check each plugin's symlinks
89
- const installedPlugins = await getInstalledPlugins(isGlobal);
90
- const brokenSymlinks: string[] = [];
91
- const missingSymlinks: string[] = [];
92
-
93
- for (const [name, pkgJson] of installedPlugins) {
94
- const symlinkStatus = await checkPluginSymlinks(name, pkgJson, isGlobal);
95
-
96
- if (symlinkStatus.broken.length > 0) {
97
- brokenSymlinks.push(...symlinkStatus.broken.map((s) => `${name}: ${s}`));
98
- }
99
- if (symlinkStatus.missing.length > 0) {
100
- missingSymlinks.push(...symlinkStatus.missing.map((s) => `${name}: ${s}`));
101
- }
102
- }
103
-
104
- if (brokenSymlinks.length > 0) {
105
- results.push({
106
- check: "Broken symlinks",
107
- status: "error",
108
- message: `${brokenSymlinks.length} broken symlink(s)`,
109
- fix: "Run: omp update <plugin> to re-create symlinks",
110
- });
111
- } else {
112
- results.push({
113
- check: "Symlinks",
114
- status: "ok",
115
- message: "All symlinks valid",
116
- });
117
- }
118
-
119
- if (missingSymlinks.length > 0) {
120
- results.push({
121
- check: "Missing symlinks",
122
- status: "warning",
123
- message: `${missingSymlinks.length} expected symlink(s) not found`,
124
- fix: "Run: omp update <plugin> to re-create symlinks",
125
- });
126
- }
127
-
128
- // 5. Check for conflicts
129
- const conflicts = detectAllConflicts(installedPlugins);
130
- if (conflicts.length > 0) {
131
- results.push({
132
- check: "Conflicts",
133
- status: "warning",
134
- message: formatConflicts(conflicts).join("; "),
135
- });
136
- } else {
137
- results.push({
138
- check: "Conflicts",
139
- status: "ok",
140
- message: "No conflicts detected",
141
- });
142
- }
143
-
144
- // 6. Check for orphaned entries in package.json
145
- const pluginsJson = await loadPluginsJson(isGlobal);
146
- const orphaned: string[] = [];
147
- for (const name of Object.keys(pluginsJson.plugins)) {
148
- const pkgJson = await readPluginPackageJson(name, isGlobal);
149
- if (!pkgJson) {
150
- orphaned.push(name);
151
- }
152
- }
153
-
154
- if (orphaned.length > 0) {
155
- results.push({
156
- check: "Orphaned entries",
157
- status: "warning",
158
- message: `${orphaned.length} plugin(s) in manifest but not in node_modules: ${orphaned.join(", ")}`,
159
- fix: "Run: omp install (to reinstall) or remove from manifest",
160
- });
161
- }
162
-
163
- // 7. Check for missing omp dependencies
164
- const missingDeps: string[] = [];
165
- for (const [name, pkgJson] of installedPlugins) {
166
- if (pkgJson.dependencies) {
167
- for (const depName of Object.keys(pkgJson.dependencies)) {
168
- const depPkgJson = await readPluginPackageJson(depName, isGlobal);
169
- if (!depPkgJson) {
170
- // Dependency not found in node_modules
171
- // Check if it's supposed to be an omp plugin by looking in the plugins manifest
172
- if (pluginsJson.plugins[depName]) {
173
- missingDeps.push(`${name} requires ${depName} (not in node_modules)`);
174
- }
175
- } else if (depPkgJson.omp?.install && depPkgJson.omp.install.length > 0) {
176
- // Dependency is an omp plugin (has install entries) and is present - that's fine
177
- // But check if it's registered in the plugins manifest
178
- if (!pluginsJson.plugins[depName]) {
179
- missingDeps.push(`${name} requires omp plugin ${depName} (installed but not in manifest)`);
180
- }
181
- }
182
- }
183
- }
184
- }
185
-
186
- if (missingDeps.length > 0) {
187
- results.push({
188
- check: "Missing omp dependencies",
189
- status: "warning",
190
- message: missingDeps.join("; "),
191
- fix: isGlobal ? "Run: npm install in ~/.pi/plugins" : "Run: npm install in .pi",
192
- });
193
- }
194
-
195
- // Output results
196
- if (options.json) {
197
- console.log(JSON.stringify({ results }, null, 2));
198
- return;
199
- }
200
-
201
- for (const result of results) {
202
- let icon: string;
203
- let color: typeof chalk;
204
-
205
- switch (result.status) {
206
- case "ok":
207
- icon = "✓";
208
- color = chalk.green;
209
- break;
210
- case "warning":
211
- icon = "⚠";
212
- color = chalk.yellow;
213
- break;
214
- case "error":
215
- icon = "✗";
216
- color = chalk.red;
217
- break;
218
- }
219
-
220
- console.log(color(`${icon} ${result.check}: `) + result.message);
221
-
222
- if (result.fix && result.status !== "ok") {
223
- console.log(chalk.dim(` ${result.fix}`));
224
- }
225
- }
226
-
227
- // Summary
228
- const errors = results.filter((r) => r.status === "error");
229
- const warnings = results.filter((r) => r.status === "warning");
230
-
231
- console.log();
232
- if (errors.length === 0 && warnings.length === 0) {
233
- console.log(chalk.green("✓ All checks passed!"));
234
- } else {
235
- if (errors.length > 0) {
236
- console.log(chalk.red(`${errors.length} error(s) found`));
237
- process.exitCode = 1;
238
- }
239
- if (warnings.length > 0) {
240
- console.log(chalk.yellow(`${warnings.length} warning(s) found`));
241
- }
242
- }
243
-
244
- // Show broken symlinks details
245
- if (brokenSymlinks.length > 0) {
246
- console.log(chalk.red("\nBroken symlinks:"));
247
- for (const s of brokenSymlinks) {
248
- console.log(chalk.dim(` - ${s}`));
249
- }
250
- }
251
-
252
- if (missingSymlinks.length > 0) {
253
- console.log(chalk.yellow("\nMissing symlinks:"));
254
- for (const s of missingSymlinks) {
255
- console.log(chalk.dim(` - ${s}`));
256
- }
257
- }
258
-
259
- // Apply fixes if --fix flag was passed
260
- if (options.fix) {
261
- let fixedAnything = false;
262
-
263
- // Fix broken/missing symlinks by re-creating them
264
- if (brokenSymlinks.length > 0 || missingSymlinks.length > 0) {
265
- console.log(chalk.blue("\nAttempting to fix broken/missing symlinks..."));
266
- for (const [name, pkgJson] of installedPlugins) {
267
- const symlinkResult = await createPluginSymlinks(name, pkgJson, isGlobal, false);
268
- if (symlinkResult.created.length > 0) {
269
- fixedAnything = true;
270
- console.log(chalk.green(` ✓ Re-created symlinks for ${name}`));
271
- }
272
- if (symlinkResult.errors.length > 0) {
273
- for (const err of symlinkResult.errors) {
274
- console.log(chalk.red(` ✗ ${name}: ${err}`));
275
- }
276
- }
277
- }
278
- }
279
-
280
- // Remove orphaned manifest entries
281
- if (orphaned.length > 0) {
282
- console.log(chalk.blue("\nRemoving orphaned entries from manifest..."));
283
- for (const name of orphaned) {
284
- delete pluginsJson.plugins[name];
285
- console.log(chalk.green(` ✓ Removed ${name}`));
286
- }
287
- await savePluginsJson(pluginsJson, isGlobal);
288
- fixedAnything = true;
289
- }
290
-
291
- // Conflicts cannot be auto-fixed
292
- if (conflicts.length > 0) {
293
- console.log(chalk.yellow("\nConflicts cannot be auto-fixed. Please resolve manually:"));
294
- for (const conflict of formatConflicts(conflicts)) {
295
- console.log(chalk.dim(` - ${conflict}`));
296
- }
297
- }
298
-
299
- if (fixedAnything) {
300
- console.log(chalk.green("\n✓ Fixes applied. Run 'omp doctor' again to verify."));
301
- } else if (conflicts.length === 0) {
302
- console.log(chalk.dim("\nNo fixable issues found."));
303
- }
304
- }
305
- }
@@ -1,122 +0,0 @@
1
- import { loadPluginsJson, readPluginPackageJson, savePluginsJson } from "@omp/manifest";
2
- import { resolveScope } from "@omp/paths";
3
- import { checkPluginSymlinks, createPluginSymlinks, removePluginSymlinks } from "@omp/symlinks";
4
- import chalk from "chalk";
5
-
6
- export interface EnableDisableOptions {
7
- global?: boolean;
8
- local?: boolean;
9
- json?: boolean;
10
- }
11
-
12
- /**
13
- * Enable a disabled plugin (re-create symlinks)
14
- */
15
- export async function enablePlugin(name: string, options: EnableDisableOptions = {}): Promise<void> {
16
- const isGlobal = resolveScope(options);
17
-
18
- const pluginsJson = await loadPluginsJson(isGlobal);
19
-
20
- // Check if plugin exists
21
- if (!pluginsJson.plugins[name]) {
22
- console.log(chalk.yellow(`Plugin "${name}" is not installed.`));
23
- process.exitCode = 1;
24
- return;
25
- }
26
-
27
- // Check if already enabled
28
- if (!pluginsJson.disabled?.includes(name)) {
29
- console.log(chalk.yellow(`Plugin "${name}" is already enabled.`));
30
- process.exitCode = 1;
31
- return;
32
- }
33
-
34
- try {
35
- // Read package.json
36
- const pkgJson = await readPluginPackageJson(name, isGlobal);
37
- if (!pkgJson) {
38
- console.log(chalk.red(`Could not read package.json for ${name}`));
39
- process.exitCode = 1;
40
- return;
41
- }
42
-
43
- // Check if symlinks are already in place
44
- const symlinkStatus = await checkPluginSymlinks(name, pkgJson, isGlobal);
45
-
46
- if (symlinkStatus.valid.length > 0 && symlinkStatus.broken.length === 0 && symlinkStatus.missing.length === 0) {
47
- console.log(chalk.yellow(`Plugin "${name}" symlinks are already in place.`));
48
- } else {
49
- // Re-create symlinks
50
- console.log(chalk.blue(`Enabling ${name}...`));
51
- await createPluginSymlinks(name, pkgJson, isGlobal);
52
- }
53
-
54
- // Remove from disabled list
55
- pluginsJson.disabled = pluginsJson.disabled.filter((n) => n !== name);
56
- await savePluginsJson(pluginsJson, isGlobal);
57
-
58
- console.log(chalk.green(`✓ Enabled "${name}"`));
59
-
60
- if (options.json) {
61
- console.log(JSON.stringify({ name, enabled: true }, null, 2));
62
- }
63
- } catch (err) {
64
- console.log(chalk.red(`Error enabling plugin: ${(err as Error).message}`));
65
- process.exitCode = 1;
66
- }
67
- }
68
-
69
- /**
70
- * Disable a plugin (remove symlinks but keep installed)
71
- */
72
- export async function disablePlugin(name: string, options: EnableDisableOptions = {}): Promise<void> {
73
- const isGlobal = resolveScope(options);
74
-
75
- const pluginsJson = await loadPluginsJson(isGlobal);
76
-
77
- // Check if plugin exists
78
- if (!pluginsJson.plugins[name]) {
79
- console.log(chalk.yellow(`Plugin "${name}" is not installed.`));
80
- process.exitCode = 1;
81
- return;
82
- }
83
-
84
- // Check if already disabled
85
- if (pluginsJson.disabled?.includes(name)) {
86
- console.log(chalk.yellow(`Plugin "${name}" is already disabled.`));
87
- process.exitCode = 1;
88
- return;
89
- }
90
-
91
- try {
92
- // Read package.json
93
- const pkgJson = await readPluginPackageJson(name, isGlobal);
94
- if (!pkgJson) {
95
- console.log(chalk.red(`Could not read package.json for ${name}`));
96
- process.exitCode = 1;
97
- return;
98
- }
99
-
100
- // Remove symlinks
101
- console.log(chalk.blue(`Disabling ${name}...`));
102
- await removePluginSymlinks(name, pkgJson, isGlobal);
103
-
104
- // Add to disabled list
105
- if (!pluginsJson.disabled) {
106
- pluginsJson.disabled = [];
107
- }
108
- pluginsJson.disabled.push(name);
109
- await savePluginsJson(pluginsJson, isGlobal);
110
-
111
- console.log(chalk.green(`✓ Disabled "${name}"`));
112
- console.log(chalk.dim(" Plugin is still installed, symlinks removed"));
113
- console.log(chalk.dim(` Re-enable with: omp enable ${name}`));
114
-
115
- if (options.json) {
116
- console.log(JSON.stringify({ name, enabled: false }, null, 2));
117
- }
118
- } catch (err) {
119
- console.log(chalk.red(`Error disabling plugin: ${(err as Error).message}`));
120
- process.exitCode = 1;
121
- }
122
- }
@@ -1,38 +0,0 @@
1
- import { resolveScope } from "@omp/paths";
2
- import { generateEnvScript, getEnvJson } from "@omp/runtime";
3
- import chalk from "chalk";
4
-
5
- export interface EnvOptions {
6
- global?: boolean;
7
- local?: boolean;
8
- json?: boolean;
9
- fish?: boolean;
10
- }
11
-
12
- /**
13
- * Output environment variables for plugins
14
- * omp env # Print shell exports (sh/bash/zsh)
15
- * omp env --fish # Print fish shell syntax
16
- * omp env --json # Print as JSON
17
- */
18
- export async function envCommand(options: EnvOptions = {}): Promise<void> {
19
- const isGlobal = resolveScope(options);
20
-
21
- if (options.json) {
22
- const vars = await getEnvJson(isGlobal);
23
- console.log(JSON.stringify(vars, null, 2));
24
- return;
25
- }
26
-
27
- const shell = options.fish ? "fish" : "sh";
28
- const script = await generateEnvScript(isGlobal, shell);
29
-
30
- if (script.length === 0) {
31
- console.error(chalk.yellow("No environment variables configured."));
32
- console.error(chalk.dim("Set variables with: omp config <plugin> <variable> <value>"));
33
- return;
34
- }
35
-
36
- // Output script directly (for eval or sourcing)
37
- console.log(script);
38
- }