toggle-oh-my 1.0.0 → 1.0.2
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 +5 -5
- package/index.js +63 -43
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,10 +8,10 @@ The plugin reads your opencode config (`~/.config/opencode/opencode.jsonc` or pr
|
|
|
8
8
|
|
|
9
9
|
| State | plugin entry |
|
|
10
10
|
|-------|-------------|
|
|
11
|
-
| **ON** | `"oh-my-
|
|
12
|
-
| **OFF** | `"disabled_oh-my-
|
|
11
|
+
| **ON** | `"oh-my-openagent@latest"` (or `oh-my-opencode@latest`) |
|
|
12
|
+
| **OFF** | `"disabled_oh-my-openagent@latest"` (or `disabled_oh-my-opencode@latest`) |
|
|
13
13
|
|
|
14
|
-
The version string (`@latest`, `@1.2.3`, etc.) is preserved during the toggle, so you never lose the version pin.
|
|
14
|
+
Both `oh-my-openagent` and `oh-my-opencode` names are supported (they are the same npm package). The version string (`@latest`, `@1.2.3`, etc.) is preserved during the toggle, so you never lose the version pin.
|
|
15
15
|
|
|
16
16
|
## Usage
|
|
17
17
|
|
|
@@ -31,10 +31,10 @@ Then add to your `opencode.json` / `opencode.jsonc`:
|
|
|
31
31
|
|
|
32
32
|
```json
|
|
33
33
|
{
|
|
34
|
-
"plugin": ["toggle-oh-my", "oh-my-
|
|
34
|
+
"plugin": ["toggle-oh-my", "oh-my-openagent@latest"]
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
## Compatibility
|
|
39
39
|
|
|
40
|
-
Works with any version
|
|
40
|
+
Works with any version (oh-my-openagent, oh-my-opencode). The version specifier (`@latest`, `@1.x`, etc.) is preserved through toggles.
|
package/index.js
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
2
2
|
import { homedir, platform } from 'os';
|
|
3
|
-
import { join
|
|
3
|
+
import { join } from 'path';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const PLUGIN_NAMES = ['oh-my-openagent', 'oh-my-opencode'];
|
|
6
6
|
const DISABLED_PREFIX = 'disabled_';
|
|
7
|
-
const PLUGIN_DISPLAY = 'oh-my-
|
|
7
|
+
const PLUGIN_DISPLAY = 'oh-my-openagent';
|
|
8
|
+
|
|
9
|
+
function escapeRegex(str) {
|
|
10
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
11
|
+
}
|
|
8
12
|
|
|
9
13
|
/**
|
|
10
|
-
* Find and read the opencode config file that contains the plugin
|
|
14
|
+
* Find and read the opencode config file that contains any of the known plugin names.
|
|
11
15
|
* Checks project-level config first, then user-level config.
|
|
12
16
|
*/
|
|
13
17
|
function findConfig() {
|
|
18
|
+
const hasAnyPlugin = (raw) =>
|
|
19
|
+
PLUGIN_NAMES.some((n) => raw.includes(n) || raw.includes(DISABLED_PREFIX + n));
|
|
20
|
+
|
|
14
21
|
// project-level: <cwd>/.opencode/opencode.json
|
|
15
22
|
const projectCandidates = [
|
|
16
23
|
join(process.cwd(), '.opencode', 'opencode.json'),
|
|
@@ -19,69 +26,89 @@ function findConfig() {
|
|
|
19
26
|
for (const fp of projectCandidates) {
|
|
20
27
|
if (!existsSync(fp)) continue;
|
|
21
28
|
const raw = readFileSync(fp, 'utf-8');
|
|
22
|
-
if (
|
|
29
|
+
if (hasAnyPlugin(raw)) {
|
|
23
30
|
return { path: fp, raw, format: fp.endsWith('.jsonc') ? 'jsonc' : 'json' };
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
// user-level:
|
|
34
|
+
// user-level configs: check ALL known platform paths
|
|
28
35
|
const home = homedir();
|
|
29
36
|
const userCandidates = [
|
|
37
|
+
// Windows paths (opencode on Windows may use any of these)
|
|
30
38
|
join(home, '.config', 'opencode', 'opencode.jsonc'),
|
|
31
39
|
join(home, '.config', 'opencode', 'opencode.json'),
|
|
32
40
|
join(home, '.opencode.json'),
|
|
33
41
|
];
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
// Windows: %APPDATA%/opencode/config.json
|
|
43
|
+
if (platform() === 'win32' && process.env.APPDATA) {
|
|
44
|
+
userCandidates.push(
|
|
45
|
+
join(process.env.APPDATA, 'opencode', 'config.json'),
|
|
46
|
+
join(process.env.APPDATA, 'opencode', 'opencode.jsonc'),
|
|
47
|
+
);
|
|
38
48
|
}
|
|
39
|
-
|
|
40
|
-
// Linux/macOS fallback: $XDG_CONFIG_HOME/opencode/opencode.jsonc
|
|
49
|
+
// Linux/macOS: $XDG_CONFIG_HOME
|
|
41
50
|
if (platform() !== 'win32') {
|
|
42
51
|
const xdg = process.env.XDG_CONFIG_HOME || join(home, '.config');
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
userCandidates.push(join(xdg, 'opencode', 'opencode.jsonc'));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const fp of userCandidates) {
|
|
56
|
+
if (!existsSync(fp)) continue;
|
|
57
|
+
try {
|
|
45
58
|
const raw = readFileSync(fp, 'utf-8');
|
|
46
|
-
return { path: fp, raw, format: 'jsonc' };
|
|
47
|
-
}
|
|
59
|
+
return { path: fp, raw, format: fp.endsWith('.jsonc') ? 'jsonc' : 'json' };
|
|
60
|
+
} catch { /* permission issue, try next */ }
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
return null;
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
|
|
67
|
+
* Detect which plugin name is currently in the config (enabled or disabled).
|
|
68
|
+
* Returns the actual name found, or null.
|
|
69
|
+
*/
|
|
70
|
+
function detectActiveName(raw) {
|
|
71
|
+
for (const name of PLUGIN_NAMES) {
|
|
72
|
+
const enabledRE = new RegExp(`"(${escapeRegex(name)}(?:@[^"]*)?)"`);
|
|
73
|
+
const disabledRE = new RegExp(`"(${escapeRegex(DISABLED_PREFIX)}${escapeRegex(name)}(?:@[^"]*)?)"`);
|
|
74
|
+
if (enabledRE.test(raw) || disabledRE.test(raw)) {
|
|
75
|
+
return name;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Toggle the plugin in the raw config text.
|
|
83
|
+
* Preserves version and original formatting.
|
|
57
84
|
*/
|
|
58
85
|
function toggleInText(raw) {
|
|
59
|
-
|
|
60
|
-
|
|
86
|
+
const activeName = detectActiveName(raw);
|
|
87
|
+
if (!activeName) {
|
|
88
|
+
return { raw: null, newState: 'not-found', version: '' };
|
|
89
|
+
}
|
|
90
|
+
|
|
61
91
|
const enabledPattern = new RegExp(
|
|
62
|
-
`"(${escapeRegex(
|
|
92
|
+
`"(${escapeRegex(activeName)}(?:@[^"]*)?)"`,
|
|
63
93
|
'g'
|
|
64
94
|
);
|
|
65
95
|
const disabledPattern = new RegExp(
|
|
66
|
-
`"(${escapeRegex(DISABLED_PREFIX)}${escapeRegex(
|
|
96
|
+
`"(${escapeRegex(DISABLED_PREFIX)}${escapeRegex(activeName)}(?:@[^"]*)?)"`,
|
|
67
97
|
'g'
|
|
68
98
|
);
|
|
69
99
|
|
|
70
100
|
let isCurrentlyEnabled = false;
|
|
71
101
|
let version = '';
|
|
72
102
|
|
|
73
|
-
// Check if currently enabled
|
|
74
103
|
let match;
|
|
75
104
|
enabledPattern.lastIndex = 0;
|
|
76
105
|
while ((match = enabledPattern.exec(raw)) !== null) {
|
|
77
106
|
isCurrentlyEnabled = true;
|
|
78
|
-
// Extract version from the match
|
|
79
107
|
const atIdx = match[1].indexOf('@');
|
|
80
108
|
version = atIdx >= 0 ? match[1].slice(atIdx) : '';
|
|
81
109
|
break;
|
|
82
110
|
}
|
|
83
111
|
|
|
84
|
-
// Check if currently disabled
|
|
85
112
|
disabledPattern.lastIndex = 0;
|
|
86
113
|
let disabledVersion = '';
|
|
87
114
|
while ((match = disabledPattern.exec(raw)) !== null) {
|
|
@@ -91,31 +118,23 @@ function toggleInText(raw) {
|
|
|
91
118
|
break;
|
|
92
119
|
}
|
|
93
120
|
|
|
94
|
-
let toggledText;
|
|
95
121
|
if (isCurrentlyEnabled) {
|
|
96
|
-
|
|
97
|
-
toggledText = raw.replace(
|
|
122
|
+
const toggledText = raw.replace(
|
|
98
123
|
enabledPattern,
|
|
99
|
-
`"${DISABLED_PREFIX}${
|
|
124
|
+
`"${DISABLED_PREFIX}${activeName}${version}"`
|
|
100
125
|
);
|
|
101
|
-
return { raw: toggledText, newState: 'disabled', version };
|
|
126
|
+
return { raw: toggledText, newState: 'disabled', version, activeName };
|
|
102
127
|
} else if (disabledVersion !== '') {
|
|
103
|
-
|
|
104
|
-
toggledText = raw.replace(
|
|
128
|
+
const toggledText = raw.replace(
|
|
105
129
|
disabledPattern,
|
|
106
|
-
`"${
|
|
130
|
+
`"${activeName}${disabledVersion}"`
|
|
107
131
|
);
|
|
108
|
-
return { raw: toggledText, newState: 'enabled', version: disabledVersion };
|
|
132
|
+
return { raw: toggledText, newState: 'enabled', version: disabledVersion, activeName };
|
|
109
133
|
}
|
|
110
134
|
|
|
111
|
-
// Not found in any form
|
|
112
135
|
return { raw: null, newState: 'not-found', version: '' };
|
|
113
136
|
}
|
|
114
137
|
|
|
115
|
-
function escapeRegex(str) {
|
|
116
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
117
|
-
}
|
|
118
|
-
|
|
119
138
|
export const ToggleOhMyPlugin = async () => {
|
|
120
139
|
return {
|
|
121
140
|
config: async (opencodeConfig) => {
|
|
@@ -146,7 +165,7 @@ export const ToggleOhMyPlugin = async () => {
|
|
|
146
165
|
if (result.newState === 'not-found') {
|
|
147
166
|
output.parts = [{
|
|
148
167
|
type: 'text',
|
|
149
|
-
text: `⚠️
|
|
168
|
+
text: `⚠️ Plugin not found in ${configFile.path}. Nothing to toggle.`,
|
|
150
169
|
}];
|
|
151
170
|
return;
|
|
152
171
|
}
|
|
@@ -154,9 +173,10 @@ export const ToggleOhMyPlugin = async () => {
|
|
|
154
173
|
// Write the modified config back
|
|
155
174
|
writeFileSync(configFile.path, result.raw, 'utf-8');
|
|
156
175
|
|
|
176
|
+
const name = result.activeName || PLUGIN_DISPLAY;
|
|
157
177
|
const message = result.newState === 'enabled'
|
|
158
|
-
? `✅ **${
|
|
159
|
-
: `❌ **${
|
|
178
|
+
? `✅ **${name}${result.version}** is now **ENABLED**\n Restart opencode to apply.`
|
|
179
|
+
: `❌ **${name}${result.version}** is now **DISABLED**\n Restart opencode to apply.`;
|
|
160
180
|
|
|
161
181
|
output.parts = [{ type: 'text', text: message }];
|
|
162
182
|
},
|