oh-my-claudecode-opencode 0.4.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 +87 -12
- package/assets/skills/doctor.md +50 -154
- package/bin/doctor.js +264 -0
- package/bin/doctor.ts +358 -0
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -8,6 +8,41 @@ Like Sisyphus condemned to roll his boulder eternally, this plugin ensures your
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
## 🚀 Quick Install
|
|
12
|
+
|
|
13
|
+
### For Humans (Recommended)
|
|
14
|
+
|
|
15
|
+
Just tell your AI assistant:
|
|
16
|
+
|
|
17
|
+
> **"Install oh-my-claudecode-opencode by following these instructions: https://raw.githubusercontent.com/devswha/oh-my-claudecode-opencode/main/docs/guide/installation.md"**
|
|
18
|
+
|
|
19
|
+
That's it. The AI will handle the rest.
|
|
20
|
+
|
|
21
|
+
### One-liner (If you insist on doing it yourself)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest && cat > opencode.json << 'EOF'
|
|
25
|
+
{
|
|
26
|
+
"plugin": ["oh-my-claudecode-opencode"]
|
|
27
|
+
}
|
|
28
|
+
EOF
|
|
29
|
+
echo "✅ Restart OpenCode to activate OMCO"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Magic Keywords
|
|
33
|
+
|
|
34
|
+
Once installed, just include these keywords in your prompts:
|
|
35
|
+
|
|
36
|
+
| Keyword | Effect |
|
|
37
|
+
|---------|--------|
|
|
38
|
+
| `ultrawork` or `ulw` | Maximum intensity parallel execution |
|
|
39
|
+
| `ralph` | Persistence mode - won't stop until complete |
|
|
40
|
+
| `autopilot` | Full autonomous execution |
|
|
41
|
+
|
|
42
|
+
Example: `ulw implement user authentication with tests`
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
11
46
|
## 🎯 What is this?
|
|
12
47
|
|
|
13
48
|
This project **ports the powerful features** of [oh-my-claudecode](https://github.com/Yeachan-Heo/oh-my-claudecode) v3.3.6 (a Claude Code plugin) to the **OpenCode platform**.
|
|
@@ -67,25 +102,27 @@ This project **ports the powerful features** of [oh-my-claudecode](https://githu
|
|
|
67
102
|
|
|
68
103
|
## Installation
|
|
69
104
|
|
|
70
|
-
|
|
71
|
-
# Using npm
|
|
72
|
-
npm install oh-my-claudecode-opencode
|
|
73
|
-
|
|
74
|
-
# Using bun
|
|
75
|
-
bun add oh-my-claudecode-opencode
|
|
105
|
+
> 💡 **Recommended**: Let your AI handle it! See [Quick Install](#-quick-install) above.
|
|
76
106
|
|
|
77
|
-
|
|
78
|
-
pnpm add oh-my-claudecode-opencode
|
|
79
|
-
```
|
|
107
|
+
### Manual Installation
|
|
80
108
|
|
|
81
|
-
|
|
109
|
+
```bash
|
|
110
|
+
# Install in OpenCode config directory
|
|
111
|
+
cd ~/.config/opencode
|
|
112
|
+
npm install oh-my-claudecode-opencode
|
|
82
113
|
|
|
83
|
-
|
|
114
|
+
# Register plugin in opencode.json
|
|
115
|
+
cat > opencode.json << 'EOF'
|
|
84
116
|
{
|
|
85
|
-
"
|
|
117
|
+
"plugin": ["oh-my-claudecode-opencode"]
|
|
86
118
|
}
|
|
119
|
+
EOF
|
|
120
|
+
|
|
121
|
+
# Restart OpenCode to activate
|
|
87
122
|
```
|
|
88
123
|
|
|
124
|
+
For detailed instructions, see [Installation Guide](docs/guide/installation.md).
|
|
125
|
+
|
|
89
126
|
## Usage
|
|
90
127
|
|
|
91
128
|
### Ultrawork Mode
|
|
@@ -388,6 +425,44 @@ When triggered:
|
|
|
388
425
|
3. Minimizes confirmation requests
|
|
389
426
|
4. Maximizes throughput
|
|
390
427
|
|
|
428
|
+
## Troubleshooting
|
|
429
|
+
|
|
430
|
+
### Agents not showing in Tab menu?
|
|
431
|
+
|
|
432
|
+
Run the diagnostic tool:
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
npx oh-my-claudecode-opencode doctor
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
This checks:
|
|
439
|
+
1. Plugin installation in `~/.config/opencode/node_modules/`
|
|
440
|
+
2. Plugin registration in `opencode.json`
|
|
441
|
+
3. Asset files present
|
|
442
|
+
4. Package dependencies
|
|
443
|
+
5. OMCO configuration validity
|
|
444
|
+
|
|
445
|
+
### Common Issues
|
|
446
|
+
|
|
447
|
+
| Issue | Solution |
|
|
448
|
+
|-------|----------|
|
|
449
|
+
| "Plugin not installed" | `cd ~/.config/opencode && npm install oh-my-claudecode-opencode` |
|
|
450
|
+
| "Plugin not in opencode.json" | Add `"oh-my-claudecode-opencode"` to `"plugin"` array |
|
|
451
|
+
| "Assets directory missing" | Reinstall: `npm install oh-my-claudecode-opencode@latest` |
|
|
452
|
+
|
|
453
|
+
### Exit Codes
|
|
454
|
+
|
|
455
|
+
| Code | Meaning |
|
|
456
|
+
|------|---------|
|
|
457
|
+
| 0 | All checks passed |
|
|
458
|
+
| 1 | Critical failure found |
|
|
459
|
+
| 2 | Warnings only |
|
|
460
|
+
|
|
461
|
+
### Getting Help
|
|
462
|
+
|
|
463
|
+
1. Run `/doctor` in OpenCode and share the report
|
|
464
|
+
2. Open an issue: https://github.com/devswha/oh-my-claudecode-opencode/issues
|
|
465
|
+
|
|
391
466
|
## Development
|
|
392
467
|
|
|
393
468
|
```bash
|
package/assets/skills/doctor.md
CHANGED
|
@@ -1,192 +1,88 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: doctor
|
|
3
|
-
description: Diagnose and fix
|
|
3
|
+
description: Diagnose and fix OMCO installation issues for OpenCode
|
|
4
4
|
user-invocable: true
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Doctor Skill
|
|
7
|
+
# Doctor Skill (OpenCode)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Quick Diagnosis
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
### Step 1: Check Plugin Version
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
# Get installed version
|
|
17
|
-
INSTALLED=$(ls ~/.claude/plugins/cache/omc/oh-my-claudecode/ 2>/dev/null | sort -V | tail -1)
|
|
18
|
-
echo "Installed: $INSTALLED"
|
|
19
|
-
|
|
20
|
-
# Get latest from npm
|
|
21
|
-
LATEST=$(npm view oh-my-claudecode version 2>/dev/null)
|
|
22
|
-
echo "Latest: $LATEST"
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
**Diagnosis**:
|
|
26
|
-
- If no version installed: CRITICAL - plugin not installed
|
|
27
|
-
- If INSTALLED != LATEST: WARN - outdated plugin
|
|
28
|
-
- If multiple versions exist: WARN - stale cache
|
|
29
|
-
|
|
30
|
-
### Step 2: Check for Legacy Hooks in settings.json
|
|
31
|
-
|
|
32
|
-
Read `~/.claude/settings.json` and check if there's a `"hooks"` key with entries like:
|
|
33
|
-
- `bash $HOME/.claude/hooks/keyword-detector.sh`
|
|
34
|
-
- `bash $HOME/.claude/hooks/persistent-mode.sh`
|
|
35
|
-
- `bash $HOME/.claude/hooks/session-start.sh`
|
|
36
|
-
|
|
37
|
-
**Diagnosis**:
|
|
38
|
-
- If found: CRITICAL - legacy hooks causing duplicates
|
|
39
|
-
|
|
40
|
-
### Step 3: Check for Legacy Bash Hook Scripts
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
ls -la ~/.claude/hooks/*.sh 2>/dev/null
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
**Diagnosis**:
|
|
47
|
-
- If `keyword-detector.sh`, `persistent-mode.sh`, `session-start.sh`, or `stop-continuation.sh` exist: WARN - legacy scripts (can cause confusion)
|
|
48
|
-
|
|
49
|
-
### Step 4: Check CLAUDE.md
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# Check if CLAUDE.md exists
|
|
53
|
-
ls -la ~/.claude/CLAUDE.md 2>/dev/null
|
|
54
|
-
|
|
55
|
-
# Check for OMC marker
|
|
56
|
-
grep -q "oh-my-claudecode Multi-Agent System" ~/.claude/CLAUDE.md 2>/dev/null && echo "Has OMC config" || echo "Missing OMC config"
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
**Diagnosis**:
|
|
60
|
-
- If missing: CRITICAL - CLAUDE.md not configured
|
|
61
|
-
- If missing OMC marker: WARN - outdated CLAUDE.md
|
|
62
|
-
|
|
63
|
-
### Step 5: Check for Stale Plugin Cache
|
|
11
|
+
When users report "OMCO agent not showing in Tab menu" or similar issues, guide them to run:
|
|
64
12
|
|
|
65
13
|
```bash
|
|
66
|
-
|
|
67
|
-
ls ~/.claude/plugins/cache/omc/oh-my-claudecode/ 2>/dev/null | wc -l
|
|
14
|
+
npx oh-my-claudecode-opencode doctor
|
|
68
15
|
```
|
|
69
16
|
|
|
70
|
-
|
|
71
|
-
- If > 1 version: WARN - multiple cached versions (cleanup recommended)
|
|
72
|
-
|
|
73
|
-
### Step 6: Check for Legacy Curl-Installed Content
|
|
74
|
-
|
|
75
|
-
Check for legacy agents, commands, and skills installed via curl (before plugin system):
|
|
76
|
-
|
|
17
|
+
Or if npx is not available:
|
|
77
18
|
```bash
|
|
78
|
-
|
|
79
|
-
ls -la ~/.claude/agents/ 2>/dev/null
|
|
80
|
-
|
|
81
|
-
# Check for legacy commands directory
|
|
82
|
-
ls -la ~/.claude/commands/ 2>/dev/null
|
|
83
|
-
|
|
84
|
-
# Check for legacy skills directory
|
|
85
|
-
ls -la ~/.claude/skills/ 2>/dev/null
|
|
19
|
+
cd ~/.config/opencode && node node_modules/oh-my-claudecode-opencode/bin/doctor.js
|
|
86
20
|
```
|
|
87
21
|
|
|
88
|
-
|
|
89
|
-
- If `~/.claude/agents/` exists with oh-my-claudecode-related files: WARN - legacy agents (now provided by plugin)
|
|
90
|
-
- If `~/.claude/commands/` exists with oh-my-claudecode-related files: WARN - legacy commands (now provided by plugin)
|
|
91
|
-
- If `~/.claude/skills/` exists with oh-my-claudecode-related files: WARN - legacy skills (now provided by plugin)
|
|
22
|
+
## 5 Failure Modes
|
|
92
23
|
|
|
93
|
-
|
|
94
|
-
- `architect.md`, `researcher.md`, `explore.md`, `executor.md`, etc. in agents/
|
|
95
|
-
- `ultrawork.md`, `omc-default.md`, `omc-default-global.md`, `deepsearch.md`, etc. in commands/
|
|
96
|
-
- Any oh-my-claudecode-related `.md` files in skills/
|
|
24
|
+
The doctor tool checks for 5 common failure modes:
|
|
97
25
|
|
|
98
|
-
|
|
26
|
+
| # | Check | What It Means |
|
|
27
|
+
|---|-------|---------------|
|
|
28
|
+
| 1 | Plugin Installed | Is the package in `~/.config/opencode/node_modules/`? |
|
|
29
|
+
| 2 | Plugin in Config | Is it registered in `opencode.json` `plugin` array? |
|
|
30
|
+
| 3 | Assets Present | Do `assets/agents/*.md` files exist? |
|
|
31
|
+
| 4 | Package Dependency | Is it listed in `package.json` dependencies? |
|
|
32
|
+
| 5 | OMCO Config Valid | Is `omco.json` valid JSON (if exists)? |
|
|
99
33
|
|
|
100
|
-
## Report
|
|
34
|
+
## Report Analysis
|
|
101
35
|
|
|
102
|
-
|
|
36
|
+
When a user pastes a diagnostic report (JSON or text), analyze it:
|
|
103
37
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
### Summary
|
|
108
|
-
[HEALTHY / ISSUES FOUND]
|
|
109
|
-
|
|
110
|
-
### Checks
|
|
111
|
-
|
|
112
|
-
| Check | Status | Details |
|
|
113
|
-
|-------|--------|---------|
|
|
114
|
-
| Plugin Version | OK/WARN/CRITICAL | ... |
|
|
115
|
-
| Legacy Hooks (settings.json) | OK/CRITICAL | ... |
|
|
116
|
-
| Legacy Scripts (~/.claude/hooks/) | OK/WARN | ... |
|
|
117
|
-
| CLAUDE.md | OK/WARN/CRITICAL | ... |
|
|
118
|
-
| Plugin Cache | OK/WARN | ... |
|
|
119
|
-
| Legacy Agents (~/.claude/agents/) | OK/WARN | ... |
|
|
120
|
-
| Legacy Commands (~/.claude/commands/) | OK/WARN | ... |
|
|
121
|
-
| Legacy Skills (~/.claude/skills/) | OK/WARN | ... |
|
|
122
|
-
|
|
123
|
-
### Issues Found
|
|
124
|
-
1. [Issue description]
|
|
125
|
-
2. [Issue description]
|
|
126
|
-
|
|
127
|
-
### Recommended Fixes
|
|
128
|
-
[List fixes based on issues]
|
|
129
|
-
```
|
|
38
|
+
1. **Identify failures**: Look for `FAIL` or `status: "FAIL"` entries
|
|
39
|
+
2. **Check warnings**: Look for `WARN` entries
|
|
40
|
+
3. **Extract recommendations**: The report includes fix commands
|
|
130
41
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
## Auto-Fix (if user confirms)
|
|
134
|
-
|
|
135
|
-
If issues found, ask user: "Would you like me to fix these issues automatically?"
|
|
42
|
+
## Interpreting Results
|
|
136
43
|
|
|
137
|
-
|
|
44
|
+
### Exit Codes
|
|
45
|
+
- **0**: All checks passed - plugin should work
|
|
46
|
+
- **1**: Critical failure - plugin won't work until fixed
|
|
47
|
+
- **2**: Warnings only - plugin may work but issues exist
|
|
138
48
|
|
|
139
|
-
###
|
|
140
|
-
Remove the `"hooks"` section from `~/.claude/settings.json` (keep other settings intact)
|
|
49
|
+
### Common Fixes
|
|
141
50
|
|
|
142
|
-
|
|
51
|
+
**Plugin Not Installed (FAIL)**
|
|
143
52
|
```bash
|
|
144
|
-
|
|
145
|
-
rm -f ~/.claude/hooks/persistent-mode.sh
|
|
146
|
-
rm -f ~/.claude/hooks/session-start.sh
|
|
147
|
-
rm -f ~/.claude/hooks/stop-continuation.sh
|
|
53
|
+
cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest
|
|
148
54
|
```
|
|
149
55
|
|
|
150
|
-
|
|
56
|
+
**Plugin Not in Config (FAIL)**
|
|
151
57
|
```bash
|
|
152
|
-
|
|
153
|
-
|
|
58
|
+
# Create or edit ~/.config/opencode/opencode.json
|
|
59
|
+
cat > ~/.config/opencode/opencode.json << 'EOF'
|
|
60
|
+
{
|
|
61
|
+
"plugin": ["oh-my-claudecode-opencode"]
|
|
62
|
+
}
|
|
63
|
+
EOF
|
|
154
64
|
```
|
|
155
65
|
|
|
156
|
-
|
|
66
|
+
**Assets Directory Missing (FAIL)**
|
|
157
67
|
```bash
|
|
158
|
-
#
|
|
159
|
-
cd ~/.
|
|
160
|
-
ls | sort -V | head -n -1 | xargs rm -rf
|
|
68
|
+
# Reinstall to get fresh assets
|
|
69
|
+
cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest --force
|
|
161
70
|
```
|
|
162
71
|
|
|
163
|
-
|
|
164
|
-
Fetch latest from GitHub and write to `~/.claude/CLAUDE.md`:
|
|
165
|
-
```
|
|
166
|
-
WebFetch(url: "https://raw.githubusercontent.com/Yeachan-Heo/oh-my-claudecode/main/docs/CLAUDE.md", prompt: "Return the complete raw markdown content exactly as-is")
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### Fix: Legacy Curl-Installed Content
|
|
170
|
-
|
|
171
|
-
Remove legacy agents, commands, and skills directories (now provided by plugin):
|
|
172
|
-
|
|
72
|
+
**Package Dependency Missing (WARN)**
|
|
173
73
|
```bash
|
|
174
|
-
|
|
175
|
-
# mv ~/.claude/agents ~/.claude/agents.bak
|
|
176
|
-
# mv ~/.claude/commands ~/.claude/commands.bak
|
|
177
|
-
# mv ~/.claude/skills ~/.claude/skills.bak
|
|
178
|
-
|
|
179
|
-
# Or remove directly
|
|
180
|
-
rm -rf ~/.claude/agents
|
|
181
|
-
rm -rf ~/.claude/commands
|
|
182
|
-
rm -rf ~/.claude/skills
|
|
74
|
+
cd ~/.config/opencode && npm install oh-my-claudecode-opencode --save
|
|
183
75
|
```
|
|
184
76
|
|
|
185
|
-
|
|
77
|
+
## After Fixes
|
|
186
78
|
|
|
187
|
-
|
|
79
|
+
Always remind users to **restart OpenCode** after making fixes:
|
|
80
|
+
- Close OpenCode (Ctrl+C)
|
|
81
|
+
- Reopen OpenCode
|
|
188
82
|
|
|
189
|
-
##
|
|
83
|
+
## Reporting Issues
|
|
190
84
|
|
|
191
|
-
|
|
192
|
-
|
|
85
|
+
If the doctor tool doesn't identify the problem, ask users to:
|
|
86
|
+
1. Share the full doctor report (JSON format preferred)
|
|
87
|
+
2. Share their OpenCode version: `opencode --version`
|
|
88
|
+
3. Open an issue: https://github.com/devswha/oh-my-claudecode-opencode/issues
|
package/bin/doctor.js
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// bin/doctor.ts
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import * as os from "node:os";
|
|
7
|
+
var OPENCODE_CONFIG_DIR = path.join(os.homedir(), ".config", "opencode");
|
|
8
|
+
var PLUGIN_NAME = "oh-my-claudecode-opencode";
|
|
9
|
+
function checkPluginInstalled() {
|
|
10
|
+
const pluginPath = path.join(OPENCODE_CONFIG_DIR, "node_modules", PLUGIN_NAME);
|
|
11
|
+
try {
|
|
12
|
+
const stats = fs.statSync(pluginPath);
|
|
13
|
+
if (stats.isDirectory()) {
|
|
14
|
+
const pkgPath = path.join(pluginPath, "package.json");
|
|
15
|
+
if (fs.existsSync(pkgPath)) {
|
|
16
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
17
|
+
return {
|
|
18
|
+
status: "OK",
|
|
19
|
+
message: `Plugin installed (v${pkg.version})`,
|
|
20
|
+
details: pluginPath
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
status: "WARN",
|
|
25
|
+
message: "Plugin directory exists but package.json missing",
|
|
26
|
+
details: pluginPath,
|
|
27
|
+
fix: "Run: cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest"
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {}
|
|
31
|
+
return {
|
|
32
|
+
status: "FAIL",
|
|
33
|
+
message: "Plugin not installed",
|
|
34
|
+
fix: "Run: cd ~/.config/opencode && npm install oh-my-claudecode-opencode"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function checkPluginInConfig() {
|
|
38
|
+
const configPath = path.join(OPENCODE_CONFIG_DIR, "opencode.json");
|
|
39
|
+
try {
|
|
40
|
+
if (!fs.existsSync(configPath)) {
|
|
41
|
+
return {
|
|
42
|
+
status: "FAIL",
|
|
43
|
+
message: "opencode.json not found",
|
|
44
|
+
fix: `Create ${configPath} with: { "plugin": ["oh-my-claudecode-opencode"] }`
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
48
|
+
const plugins = config.plugin || config.plugins || [];
|
|
49
|
+
if (Array.isArray(plugins) && plugins.includes(PLUGIN_NAME)) {
|
|
50
|
+
return {
|
|
51
|
+
status: "OK",
|
|
52
|
+
message: "Plugin registered in opencode.json",
|
|
53
|
+
details: `plugins: ${JSON.stringify(plugins)}`
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
status: "FAIL",
|
|
58
|
+
message: "Plugin not in opencode.json plugin array",
|
|
59
|
+
details: `Current plugins: ${JSON.stringify(plugins)}`,
|
|
60
|
+
fix: `Add "${PLUGIN_NAME}" to the "plugin" array in opencode.json`
|
|
61
|
+
};
|
|
62
|
+
} catch (e) {
|
|
63
|
+
return {
|
|
64
|
+
status: "FAIL",
|
|
65
|
+
message: `Failed to parse opencode.json: ${e.message}`,
|
|
66
|
+
fix: "Check opencode.json for JSON syntax errors"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function checkAssetsPresent() {
|
|
71
|
+
const pluginPath = path.join(OPENCODE_CONFIG_DIR, "node_modules", PLUGIN_NAME);
|
|
72
|
+
const assetsPath = path.join(pluginPath, "assets", "agents");
|
|
73
|
+
try {
|
|
74
|
+
if (!fs.existsSync(assetsPath)) {
|
|
75
|
+
return {
|
|
76
|
+
status: "FAIL",
|
|
77
|
+
message: "Assets directory missing",
|
|
78
|
+
details: `Expected: ${assetsPath}`,
|
|
79
|
+
fix: "Reinstall: cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const agentFiles = fs.readdirSync(assetsPath).filter((f) => f.endsWith(".md"));
|
|
83
|
+
if (agentFiles.length === 0) {
|
|
84
|
+
return {
|
|
85
|
+
status: "FAIL",
|
|
86
|
+
message: "No agent files in assets/agents/",
|
|
87
|
+
fix: "Reinstall: cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest"
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
status: "OK",
|
|
92
|
+
message: `Found ${agentFiles.length} agent definitions`,
|
|
93
|
+
details: agentFiles.slice(0, 5).join(", ") + (agentFiles.length > 5 ? "..." : "")
|
|
94
|
+
};
|
|
95
|
+
} catch (e) {
|
|
96
|
+
return {
|
|
97
|
+
status: "FAIL",
|
|
98
|
+
message: `Failed to check assets: ${e.message}`,
|
|
99
|
+
fix: "Check filesystem permissions"
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function checkPackageDependency() {
|
|
104
|
+
const pkgPath = path.join(OPENCODE_CONFIG_DIR, "package.json");
|
|
105
|
+
try {
|
|
106
|
+
if (!fs.existsSync(pkgPath)) {
|
|
107
|
+
return {
|
|
108
|
+
status: "WARN",
|
|
109
|
+
message: "No package.json in ~/.config/opencode/",
|
|
110
|
+
details: "Plugin may have been installed globally or manually",
|
|
111
|
+
fix: "Initialize: cd ~/.config/opencode && npm init -y && npm install oh-my-claudecode-opencode"
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
115
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
116
|
+
if (deps[PLUGIN_NAME]) {
|
|
117
|
+
return {
|
|
118
|
+
status: "OK",
|
|
119
|
+
message: `Listed in package.json: ${deps[PLUGIN_NAME]}`,
|
|
120
|
+
details: pkgPath
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
status: "WARN",
|
|
125
|
+
message: "Plugin not in package.json dependencies",
|
|
126
|
+
details: "Plugin may work but won't survive npm prune",
|
|
127
|
+
fix: "Run: cd ~/.config/opencode && npm install oh-my-claudecode-opencode --save"
|
|
128
|
+
};
|
|
129
|
+
} catch (e) {
|
|
130
|
+
return {
|
|
131
|
+
status: "WARN",
|
|
132
|
+
message: `Failed to parse package.json: ${e.message}`,
|
|
133
|
+
fix: "Check package.json for JSON syntax errors"
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function checkOmcoConfig() {
|
|
138
|
+
const localConfig = path.join(process.cwd(), ".opencode", "omco.json");
|
|
139
|
+
const globalConfig = path.join(OPENCODE_CONFIG_DIR, "omco.json");
|
|
140
|
+
const configPaths = [localConfig, globalConfig];
|
|
141
|
+
for (const configPath of configPaths) {
|
|
142
|
+
if (fs.existsSync(configPath)) {
|
|
143
|
+
try {
|
|
144
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
145
|
+
return {
|
|
146
|
+
status: "OK",
|
|
147
|
+
message: "OMCO config found and valid",
|
|
148
|
+
details: configPath
|
|
149
|
+
};
|
|
150
|
+
} catch (e) {
|
|
151
|
+
return {
|
|
152
|
+
status: "FAIL",
|
|
153
|
+
message: `Invalid JSON in omco.json`,
|
|
154
|
+
details: configPath,
|
|
155
|
+
fix: "Fix JSON syntax errors in omco.json"
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
status: "OK",
|
|
162
|
+
message: "No omco.json (using defaults)",
|
|
163
|
+
details: "Optional: create .opencode/omco.json for custom config"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function runDiagnostics() {
|
|
167
|
+
const checks = {
|
|
168
|
+
pluginInstalled: checkPluginInstalled(),
|
|
169
|
+
pluginInConfig: checkPluginInConfig(),
|
|
170
|
+
assetsPresent: checkAssetsPresent(),
|
|
171
|
+
packageDependency: checkPackageDependency(),
|
|
172
|
+
omcoConfigValid: checkOmcoConfig()
|
|
173
|
+
};
|
|
174
|
+
const values = Object.values(checks);
|
|
175
|
+
const summary = {
|
|
176
|
+
total: values.length,
|
|
177
|
+
ok: values.filter((c) => c.status === "OK").length,
|
|
178
|
+
warn: values.filter((c) => c.status === "WARN").length,
|
|
179
|
+
fail: values.filter((c) => c.status === "FAIL").length
|
|
180
|
+
};
|
|
181
|
+
const recommendations = [];
|
|
182
|
+
for (const check of values) {
|
|
183
|
+
if (check.fix && check.status !== "OK") {
|
|
184
|
+
recommendations.push(check.fix);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
let omcoVersion = null;
|
|
188
|
+
const pluginPkgPath = path.join(OPENCODE_CONFIG_DIR, "node_modules", PLUGIN_NAME, "package.json");
|
|
189
|
+
if (fs.existsSync(pluginPkgPath)) {
|
|
190
|
+
try {
|
|
191
|
+
const pkg = JSON.parse(fs.readFileSync(pluginPkgPath, "utf-8"));
|
|
192
|
+
omcoVersion = pkg.version;
|
|
193
|
+
} catch {}
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
timestamp: new Date().toISOString(),
|
|
197
|
+
omcoVersion,
|
|
198
|
+
nodeVersion: process.version,
|
|
199
|
+
platform: process.platform,
|
|
200
|
+
installPath: path.join(OPENCODE_CONFIG_DIR, "node_modules", PLUGIN_NAME),
|
|
201
|
+
checks,
|
|
202
|
+
summary,
|
|
203
|
+
recommendations
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function formatTextReport(report) {
|
|
207
|
+
const lines = [];
|
|
208
|
+
lines.push("═══════════════════════════════════════════════════════════════");
|
|
209
|
+
lines.push(" OMCO Doctor Report ");
|
|
210
|
+
lines.push("═══════════════════════════════════════════════════════════════");
|
|
211
|
+
lines.push("");
|
|
212
|
+
lines.push(`Timestamp: ${report.timestamp}`);
|
|
213
|
+
lines.push(`OMCO Version: ${report.omcoVersion || "NOT INSTALLED"}`);
|
|
214
|
+
lines.push(`Node Version: ${report.nodeVersion}`);
|
|
215
|
+
lines.push(`Platform: ${report.platform}`);
|
|
216
|
+
lines.push("");
|
|
217
|
+
lines.push("───────────────────────────────────────────────────────────────");
|
|
218
|
+
lines.push(" Diagnostic Checks ");
|
|
219
|
+
lines.push("───────────────────────────────────────────────────────────────");
|
|
220
|
+
lines.push("");
|
|
221
|
+
const statusIcon = (s) => s === "OK" ? "✓" : s === "WARN" ? "⚠" : "✗";
|
|
222
|
+
for (const [name, check] of Object.entries(report.checks)) {
|
|
223
|
+
const icon = statusIcon(check.status);
|
|
224
|
+
lines.push(`[${icon}] ${check.status.padEnd(4)} | ${name}`);
|
|
225
|
+
lines.push(` ${check.message}`);
|
|
226
|
+
if (check.details) {
|
|
227
|
+
lines.push(` Details: ${check.details}`);
|
|
228
|
+
}
|
|
229
|
+
lines.push("");
|
|
230
|
+
}
|
|
231
|
+
lines.push("───────────────────────────────────────────────────────────────");
|
|
232
|
+
lines.push(`Summary: ${report.summary.ok} OK, ${report.summary.warn} WARN, ${report.summary.fail} FAIL`);
|
|
233
|
+
lines.push("───────────────────────────────────────────────────────────────");
|
|
234
|
+
if (report.recommendations.length > 0) {
|
|
235
|
+
lines.push("");
|
|
236
|
+
lines.push("Recommended Fixes:");
|
|
237
|
+
for (let i = 0;i < report.recommendations.length; i++) {
|
|
238
|
+
lines.push(` ${i + 1}. ${report.recommendations[i]}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
lines.push("");
|
|
242
|
+
lines.push("═══════════════════════════════════════════════════════════════");
|
|
243
|
+
return lines.join(`
|
|
244
|
+
`);
|
|
245
|
+
}
|
|
246
|
+
var args = process.argv.slice(2);
|
|
247
|
+
var jsonOutput = args.includes("--json");
|
|
248
|
+
var outputIndex = args.indexOf("--output");
|
|
249
|
+
var outputFile = outputIndex !== -1 ? args[outputIndex + 1] : null;
|
|
250
|
+
var report = runDiagnostics();
|
|
251
|
+
var output = jsonOutput ? JSON.stringify(report, null, 2) : formatTextReport(report);
|
|
252
|
+
if (outputFile) {
|
|
253
|
+
fs.writeFileSync(outputFile, output);
|
|
254
|
+
console.log(`Report saved to: ${outputFile}`);
|
|
255
|
+
} else {
|
|
256
|
+
console.log(output);
|
|
257
|
+
}
|
|
258
|
+
if (report.summary.fail > 0) {
|
|
259
|
+
process.exit(1);
|
|
260
|
+
} else if (report.summary.warn > 0) {
|
|
261
|
+
process.exit(2);
|
|
262
|
+
} else {
|
|
263
|
+
process.exit(0);
|
|
264
|
+
}
|
package/bin/doctor.ts
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bin/doctor.ts - Compiled to bin/doctor.js
|
|
3
|
+
|
|
4
|
+
import * as fs from 'node:fs';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import * as os from 'node:os';
|
|
7
|
+
|
|
8
|
+
const OPENCODE_CONFIG_DIR = path.join(os.homedir(), '.config', 'opencode');
|
|
9
|
+
const PLUGIN_NAME = 'oh-my-claudecode-opencode';
|
|
10
|
+
|
|
11
|
+
interface CheckResult {
|
|
12
|
+
status: 'OK' | 'WARN' | 'FAIL';
|
|
13
|
+
message: string;
|
|
14
|
+
details?: string;
|
|
15
|
+
fix?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface DiagnosticReport {
|
|
19
|
+
timestamp: string;
|
|
20
|
+
omcoVersion: string | null;
|
|
21
|
+
nodeVersion: string;
|
|
22
|
+
platform: string;
|
|
23
|
+
installPath: string | null;
|
|
24
|
+
checks: {
|
|
25
|
+
pluginInstalled: CheckResult;
|
|
26
|
+
pluginInConfig: CheckResult;
|
|
27
|
+
assetsPresent: CheckResult;
|
|
28
|
+
packageDependency: CheckResult;
|
|
29
|
+
omcoConfigValid: CheckResult;
|
|
30
|
+
};
|
|
31
|
+
summary: {
|
|
32
|
+
total: number;
|
|
33
|
+
ok: number;
|
|
34
|
+
warn: number;
|
|
35
|
+
fail: number;
|
|
36
|
+
};
|
|
37
|
+
recommendations: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============================================================
|
|
41
|
+
// CHECK 1: Plugin Installation
|
|
42
|
+
// ============================================================
|
|
43
|
+
function checkPluginInstalled(): CheckResult {
|
|
44
|
+
const pluginPath = path.join(OPENCODE_CONFIG_DIR, 'node_modules', PLUGIN_NAME);
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const stats = fs.statSync(pluginPath);
|
|
48
|
+
if (stats.isDirectory()) {
|
|
49
|
+
// Read version from package.json
|
|
50
|
+
const pkgPath = path.join(pluginPath, 'package.json');
|
|
51
|
+
if (fs.existsSync(pkgPath)) {
|
|
52
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
53
|
+
return {
|
|
54
|
+
status: 'OK',
|
|
55
|
+
message: `Plugin installed (v${pkg.version})`,
|
|
56
|
+
details: pluginPath
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
status: 'WARN',
|
|
61
|
+
message: 'Plugin directory exists but package.json missing',
|
|
62
|
+
details: pluginPath,
|
|
63
|
+
fix: 'Run: cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest'
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
} catch (e) {
|
|
67
|
+
// Directory doesn't exist
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
status: 'FAIL',
|
|
72
|
+
message: 'Plugin not installed',
|
|
73
|
+
fix: 'Run: cd ~/.config/opencode && npm install oh-my-claudecode-opencode'
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ============================================================
|
|
78
|
+
// CHECK 2: Plugin in opencode.json
|
|
79
|
+
// ============================================================
|
|
80
|
+
function checkPluginInConfig(): CheckResult {
|
|
81
|
+
const configPath = path.join(OPENCODE_CONFIG_DIR, 'opencode.json');
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
if (!fs.existsSync(configPath)) {
|
|
85
|
+
return {
|
|
86
|
+
status: 'FAIL',
|
|
87
|
+
message: 'opencode.json not found',
|
|
88
|
+
fix: `Create ${configPath} with: { "plugin": ["oh-my-claudecode-opencode"] }`
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
93
|
+
const plugins = config.plugin || config.plugins || [];
|
|
94
|
+
|
|
95
|
+
if (Array.isArray(plugins) && plugins.includes(PLUGIN_NAME)) {
|
|
96
|
+
return {
|
|
97
|
+
status: 'OK',
|
|
98
|
+
message: 'Plugin registered in opencode.json',
|
|
99
|
+
details: `plugins: ${JSON.stringify(plugins)}`
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
status: 'FAIL',
|
|
105
|
+
message: 'Plugin not in opencode.json plugin array',
|
|
106
|
+
details: `Current plugins: ${JSON.stringify(plugins)}`,
|
|
107
|
+
fix: `Add "${PLUGIN_NAME}" to the "plugin" array in opencode.json`
|
|
108
|
+
};
|
|
109
|
+
} catch (e) {
|
|
110
|
+
return {
|
|
111
|
+
status: 'FAIL',
|
|
112
|
+
message: `Failed to parse opencode.json: ${(e as Error).message}`,
|
|
113
|
+
fix: 'Check opencode.json for JSON syntax errors'
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ============================================================
|
|
119
|
+
// CHECK 3: Assets Directory Present
|
|
120
|
+
// ============================================================
|
|
121
|
+
function checkAssetsPresent(): CheckResult {
|
|
122
|
+
const pluginPath = path.join(OPENCODE_CONFIG_DIR, 'node_modules', PLUGIN_NAME);
|
|
123
|
+
const assetsPath = path.join(pluginPath, 'assets', 'agents');
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
if (!fs.existsSync(assetsPath)) {
|
|
127
|
+
return {
|
|
128
|
+
status: 'FAIL',
|
|
129
|
+
message: 'Assets directory missing',
|
|
130
|
+
details: `Expected: ${assetsPath}`,
|
|
131
|
+
fix: 'Reinstall: cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest'
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const agentFiles = fs.readdirSync(assetsPath).filter(f => f.endsWith('.md'));
|
|
136
|
+
if (agentFiles.length === 0) {
|
|
137
|
+
return {
|
|
138
|
+
status: 'FAIL',
|
|
139
|
+
message: 'No agent files in assets/agents/',
|
|
140
|
+
fix: 'Reinstall: cd ~/.config/opencode && npm install oh-my-claudecode-opencode@latest'
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
status: 'OK',
|
|
146
|
+
message: `Found ${agentFiles.length} agent definitions`,
|
|
147
|
+
details: agentFiles.slice(0, 5).join(', ') + (agentFiles.length > 5 ? '...' : '')
|
|
148
|
+
};
|
|
149
|
+
} catch (e) {
|
|
150
|
+
return {
|
|
151
|
+
status: 'FAIL',
|
|
152
|
+
message: `Failed to check assets: ${(e as Error).message}`,
|
|
153
|
+
fix: 'Check filesystem permissions'
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ============================================================
|
|
159
|
+
// CHECK 4: package.json Dependency
|
|
160
|
+
// ============================================================
|
|
161
|
+
function checkPackageDependency(): CheckResult {
|
|
162
|
+
const pkgPath = path.join(OPENCODE_CONFIG_DIR, 'package.json');
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
if (!fs.existsSync(pkgPath)) {
|
|
166
|
+
return {
|
|
167
|
+
status: 'WARN',
|
|
168
|
+
message: 'No package.json in ~/.config/opencode/',
|
|
169
|
+
details: 'Plugin may have been installed globally or manually',
|
|
170
|
+
fix: 'Initialize: cd ~/.config/opencode && npm init -y && npm install oh-my-claudecode-opencode'
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
175
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
176
|
+
|
|
177
|
+
if (deps[PLUGIN_NAME]) {
|
|
178
|
+
return {
|
|
179
|
+
status: 'OK',
|
|
180
|
+
message: `Listed in package.json: ${deps[PLUGIN_NAME]}`,
|
|
181
|
+
details: pkgPath
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
status: 'WARN',
|
|
187
|
+
message: 'Plugin not in package.json dependencies',
|
|
188
|
+
details: 'Plugin may work but won\'t survive npm prune',
|
|
189
|
+
fix: 'Run: cd ~/.config/opencode && npm install oh-my-claudecode-opencode --save'
|
|
190
|
+
};
|
|
191
|
+
} catch (e) {
|
|
192
|
+
return {
|
|
193
|
+
status: 'WARN',
|
|
194
|
+
message: `Failed to parse package.json: ${(e as Error).message}`,
|
|
195
|
+
fix: 'Check package.json for JSON syntax errors'
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ============================================================
|
|
201
|
+
// CHECK 5: OMCO Config Valid
|
|
202
|
+
// ============================================================
|
|
203
|
+
function checkOmcoConfig(): CheckResult {
|
|
204
|
+
const localConfig = path.join(process.cwd(), '.opencode', 'omco.json');
|
|
205
|
+
const globalConfig = path.join(OPENCODE_CONFIG_DIR, 'omco.json');
|
|
206
|
+
|
|
207
|
+
const configPaths = [localConfig, globalConfig];
|
|
208
|
+
|
|
209
|
+
for (const configPath of configPaths) {
|
|
210
|
+
if (fs.existsSync(configPath)) {
|
|
211
|
+
try {
|
|
212
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
213
|
+
return {
|
|
214
|
+
status: 'OK',
|
|
215
|
+
message: 'OMCO config found and valid',
|
|
216
|
+
details: configPath
|
|
217
|
+
};
|
|
218
|
+
} catch (e) {
|
|
219
|
+
return {
|
|
220
|
+
status: 'FAIL',
|
|
221
|
+
message: `Invalid JSON in omco.json`,
|
|
222
|
+
details: configPath,
|
|
223
|
+
fix: 'Fix JSON syntax errors in omco.json'
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// No config found - this is optional
|
|
230
|
+
return {
|
|
231
|
+
status: 'OK',
|
|
232
|
+
message: 'No omco.json (using defaults)',
|
|
233
|
+
details: 'Optional: create .opencode/omco.json for custom config'
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ============================================================
|
|
238
|
+
// MAIN
|
|
239
|
+
// ============================================================
|
|
240
|
+
function runDiagnostics(): DiagnosticReport {
|
|
241
|
+
const checks = {
|
|
242
|
+
pluginInstalled: checkPluginInstalled(),
|
|
243
|
+
pluginInConfig: checkPluginInConfig(),
|
|
244
|
+
assetsPresent: checkAssetsPresent(),
|
|
245
|
+
packageDependency: checkPackageDependency(),
|
|
246
|
+
omcoConfigValid: checkOmcoConfig(),
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const values = Object.values(checks);
|
|
250
|
+
const summary = {
|
|
251
|
+
total: values.length,
|
|
252
|
+
ok: values.filter(c => c.status === 'OK').length,
|
|
253
|
+
warn: values.filter(c => c.status === 'WARN').length,
|
|
254
|
+
fail: values.filter(c => c.status === 'FAIL').length,
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const recommendations: string[] = [];
|
|
258
|
+
for (const check of values) {
|
|
259
|
+
if (check.fix && check.status !== 'OK') {
|
|
260
|
+
recommendations.push(check.fix);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Get installed version
|
|
265
|
+
let omcoVersion: string | null = null;
|
|
266
|
+
const pluginPkgPath = path.join(OPENCODE_CONFIG_DIR, 'node_modules', PLUGIN_NAME, 'package.json');
|
|
267
|
+
if (fs.existsSync(pluginPkgPath)) {
|
|
268
|
+
try {
|
|
269
|
+
const pkg = JSON.parse(fs.readFileSync(pluginPkgPath, 'utf-8'));
|
|
270
|
+
omcoVersion = pkg.version;
|
|
271
|
+
} catch {}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
timestamp: new Date().toISOString(),
|
|
276
|
+
omcoVersion,
|
|
277
|
+
nodeVersion: process.version,
|
|
278
|
+
platform: process.platform,
|
|
279
|
+
installPath: path.join(OPENCODE_CONFIG_DIR, 'node_modules', PLUGIN_NAME),
|
|
280
|
+
checks,
|
|
281
|
+
summary,
|
|
282
|
+
recommendations,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function formatTextReport(report: DiagnosticReport): string {
|
|
287
|
+
const lines: string[] = [];
|
|
288
|
+
|
|
289
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
290
|
+
lines.push(' OMCO Doctor Report ');
|
|
291
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
292
|
+
lines.push('');
|
|
293
|
+
lines.push(`Timestamp: ${report.timestamp}`);
|
|
294
|
+
lines.push(`OMCO Version: ${report.omcoVersion || 'NOT INSTALLED'}`);
|
|
295
|
+
lines.push(`Node Version: ${report.nodeVersion}`);
|
|
296
|
+
lines.push(`Platform: ${report.platform}`);
|
|
297
|
+
lines.push('');
|
|
298
|
+
lines.push('───────────────────────────────────────────────────────────────');
|
|
299
|
+
lines.push(' Diagnostic Checks ');
|
|
300
|
+
lines.push('───────────────────────────────────────────────────────────────');
|
|
301
|
+
lines.push('');
|
|
302
|
+
|
|
303
|
+
const statusIcon = (s: string) => s === 'OK' ? '✓' : s === 'WARN' ? '⚠' : '✗';
|
|
304
|
+
|
|
305
|
+
for (const [name, check] of Object.entries(report.checks)) {
|
|
306
|
+
const icon = statusIcon(check.status);
|
|
307
|
+
lines.push(`[${icon}] ${check.status.padEnd(4)} | ${name}`);
|
|
308
|
+
lines.push(` ${check.message}`);
|
|
309
|
+
if (check.details) {
|
|
310
|
+
lines.push(` Details: ${check.details}`);
|
|
311
|
+
}
|
|
312
|
+
lines.push('');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
lines.push('───────────────────────────────────────────────────────────────');
|
|
316
|
+
lines.push(`Summary: ${report.summary.ok} OK, ${report.summary.warn} WARN, ${report.summary.fail} FAIL`);
|
|
317
|
+
lines.push('───────────────────────────────────────────────────────────────');
|
|
318
|
+
|
|
319
|
+
if (report.recommendations.length > 0) {
|
|
320
|
+
lines.push('');
|
|
321
|
+
lines.push('Recommended Fixes:');
|
|
322
|
+
for (let i = 0; i < report.recommendations.length; i++) {
|
|
323
|
+
lines.push(` ${i + 1}. ${report.recommendations[i]}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
lines.push('');
|
|
328
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
329
|
+
|
|
330
|
+
return lines.join('\n');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Parse args
|
|
334
|
+
const args = process.argv.slice(2);
|
|
335
|
+
const jsonOutput = args.includes('--json');
|
|
336
|
+
const outputIndex = args.indexOf('--output');
|
|
337
|
+
const outputFile = outputIndex !== -1 ? args[outputIndex + 1] : null;
|
|
338
|
+
|
|
339
|
+
const report = runDiagnostics();
|
|
340
|
+
|
|
341
|
+
// Output
|
|
342
|
+
const output = jsonOutput ? JSON.stringify(report, null, 2) : formatTextReport(report);
|
|
343
|
+
|
|
344
|
+
if (outputFile) {
|
|
345
|
+
fs.writeFileSync(outputFile, output);
|
|
346
|
+
console.log(`Report saved to: ${outputFile}`);
|
|
347
|
+
} else {
|
|
348
|
+
console.log(output);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Exit code: 0=OK, 1=FAIL, 2=WARN
|
|
352
|
+
if (report.summary.fail > 0) {
|
|
353
|
+
process.exit(1);
|
|
354
|
+
} else if (report.summary.warn > 0) {
|
|
355
|
+
process.exit(2);
|
|
356
|
+
} else {
|
|
357
|
+
process.exit(0);
|
|
358
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-claudecode-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "OpenCode port of oh-my-claudecode - Multi-agent orchestration plugin (omco)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"omco-doctor": "./bin/doctor.js",
|
|
10
|
+
"oh-my-claudecode-opencode": "./bin/doctor.js"
|
|
11
|
+
},
|
|
8
12
|
"files": [
|
|
9
13
|
"dist",
|
|
10
|
-
"assets"
|
|
14
|
+
"assets",
|
|
15
|
+
"bin"
|
|
11
16
|
],
|
|
12
17
|
"exports": {
|
|
13
18
|
".": {
|
|
@@ -17,7 +22,7 @@
|
|
|
17
22
|
"./schema.json": "./assets/omco.schema.json"
|
|
18
23
|
},
|
|
19
24
|
"scripts": {
|
|
20
|
-
"build": "bun build src/index.ts --outdir dist --target bun --format esm && tsc --emitDeclarationOnly",
|
|
25
|
+
"build": "bun build src/index.ts --outdir dist --target bun --format esm && bun build bin/doctor.ts --outfile bin/doctor.js --target node --format esm && tsc --emitDeclarationOnly",
|
|
21
26
|
"build:watch": "bun build src/index.ts --outdir dist --target bun --format esm --watch",
|
|
22
27
|
"clean": "rm -rf dist",
|
|
23
28
|
"prepublishOnly": "bun run clean && bun run build",
|