@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/commands/create.ts
DELETED
|
@@ -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
|
-
}
|
package/src/commands/doctor.ts
DELETED
|
@@ -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
|
-
}
|
package/src/commands/enable.ts
DELETED
|
@@ -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
|
-
}
|
package/src/commands/env.ts
DELETED
|
@@ -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
|
-
}
|