sync-omo-config 1.0.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 +85 -0
- package/dist/index.js +141 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# sync-omo-config
|
|
2
|
+
|
|
3
|
+
OpenCode plugin that syncs `omo` configuration from `.well-known/opencode` endpoints to local `oh-my-opencode.json`.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
When OpenCode starts, this plugin:
|
|
8
|
+
|
|
9
|
+
1. Reads `auth.json` to find wellknown authentication entries
|
|
10
|
+
2. Fetches `.well-known/opencode` from each server
|
|
11
|
+
3. Extracts the `omo` field from responses
|
|
12
|
+
4. Merges and writes to `oh-my-opencode.json`
|
|
13
|
+
|
|
14
|
+
This enables centralized distribution of oh-my-opencode configurations via your enterprise well-known server.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Using bun
|
|
20
|
+
bun add sync-omo-config
|
|
21
|
+
|
|
22
|
+
# Using npm
|
|
23
|
+
npm install sync-omo-config
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
Add to your `opencode.json`:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"plugin": ["sync-omo-config"]
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Server Setup
|
|
37
|
+
|
|
38
|
+
Your `.well-known/opencode` endpoint should return:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"config": {
|
|
43
|
+
// OpenCode config (validated by schema)
|
|
44
|
+
},
|
|
45
|
+
"omo": {
|
|
46
|
+
// oh-my-opencode config (synced by this plugin)
|
|
47
|
+
"agents": {
|
|
48
|
+
"oracle": {
|
|
49
|
+
"model": "anthropic/claude-sonnet-4-20250514"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"categories": {
|
|
53
|
+
"quick": {
|
|
54
|
+
"model": "openai/gpt-4o-mini"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The `omo` field is placed **outside** of `config` to avoid OpenCode's strict schema validation.
|
|
62
|
+
|
|
63
|
+
## File Locations
|
|
64
|
+
|
|
65
|
+
| Platform | auth.json | oh-my-opencode.json |
|
|
66
|
+
| -------- | -------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
67
|
+
| macOS | `~/Library/Application Support/opencode/auth.json` | `~/.config/opencode/oh-my-opencode.json` |
|
|
68
|
+
| Linux | `~/.local/share/opencode/auth.json` | `~/.config/opencode/oh-my-opencode.json` |
|
|
69
|
+
| Windows | `%APPDATA%/opencode/auth.json` | `~/.config/opencode/oh-my-opencode.json` or `%APPDATA%/opencode/oh-my-opencode.json` |
|
|
70
|
+
|
|
71
|
+
## Merge Behavior
|
|
72
|
+
|
|
73
|
+
- Server config is **deep merged** with existing local config
|
|
74
|
+
- Server values **override** local values for the same keys
|
|
75
|
+
- Multiple wellknown servers are processed in order (later overrides earlier)
|
|
76
|
+
|
|
77
|
+
## Requirements
|
|
78
|
+
|
|
79
|
+
- OpenCode 1.0+
|
|
80
|
+
- Bun runtime
|
|
81
|
+
- Wellknown authentication configured (`opencode auth add --wellknown <url>`)
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/index.ts
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
import { mkdir } from "fs/promises";
|
|
6
|
+
import path from "path";
|
|
7
|
+
function getDataDir() {
|
|
8
|
+
const home = homedir();
|
|
9
|
+
if (process.platform === "darwin") {
|
|
10
|
+
return path.join(home, "Library", "Application Support", "opencode");
|
|
11
|
+
}
|
|
12
|
+
if (process.platform === "win32") {
|
|
13
|
+
const appData = process.env.APPDATA || path.join(home, "AppData", "Roaming");
|
|
14
|
+
return path.join(appData, "opencode");
|
|
15
|
+
}
|
|
16
|
+
const xdgData = process.env.XDG_DATA_HOME || path.join(home, ".local", "share");
|
|
17
|
+
return path.join(xdgData, "opencode");
|
|
18
|
+
}
|
|
19
|
+
function getConfigDir() {
|
|
20
|
+
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
21
|
+
if (envConfigDir) {
|
|
22
|
+
return path.resolve(envConfigDir);
|
|
23
|
+
}
|
|
24
|
+
const home = homedir();
|
|
25
|
+
if (process.platform === "win32") {
|
|
26
|
+
const crossPlatformDir = path.join(home, ".config", "opencode");
|
|
27
|
+
const crossPlatformConfig = path.join(crossPlatformDir, "opencode.json");
|
|
28
|
+
if (existsSync(crossPlatformConfig)) {
|
|
29
|
+
return crossPlatformDir;
|
|
30
|
+
}
|
|
31
|
+
const appData = process.env.APPDATA || path.join(home, "AppData", "Roaming");
|
|
32
|
+
const appdataDir = path.join(appData, "opencode");
|
|
33
|
+
const appdataConfig = path.join(appdataDir, "opencode.json");
|
|
34
|
+
if (existsSync(appdataConfig)) {
|
|
35
|
+
return appdataDir;
|
|
36
|
+
}
|
|
37
|
+
return crossPlatformDir;
|
|
38
|
+
}
|
|
39
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(home, ".config");
|
|
40
|
+
return path.join(xdgConfig, "opencode");
|
|
41
|
+
}
|
|
42
|
+
function isObject(item) {
|
|
43
|
+
return Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
44
|
+
}
|
|
45
|
+
function deepMerge(target, source) {
|
|
46
|
+
const output = { ...target };
|
|
47
|
+
for (const key of Object.keys(source)) {
|
|
48
|
+
const sourceValue = source[key];
|
|
49
|
+
const targetValue = output[key];
|
|
50
|
+
if (isObject(sourceValue) && isObject(targetValue)) {
|
|
51
|
+
output[key] = deepMerge(targetValue, sourceValue);
|
|
52
|
+
} else {
|
|
53
|
+
output[key] = sourceValue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return output;
|
|
57
|
+
}
|
|
58
|
+
function isWellKnownAuth(auth) {
|
|
59
|
+
return auth.type === "wellknown";
|
|
60
|
+
}
|
|
61
|
+
async function syncOmoConfig() {
|
|
62
|
+
const LOG_PREFIX = "[sync-omo-config]";
|
|
63
|
+
try {
|
|
64
|
+
const authPath = path.join(getDataDir(), "auth.json");
|
|
65
|
+
const authFile = Bun.file(authPath);
|
|
66
|
+
if (!await authFile.exists()) {
|
|
67
|
+
console.log(`${LOG_PREFIX} auth.json not found at ${authPath}, skipping sync`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
let auth;
|
|
71
|
+
try {
|
|
72
|
+
auth = await authFile.json();
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.error(`${LOG_PREFIX} Failed to parse auth.json:`, e);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const omoConfigs = [];
|
|
78
|
+
for (const [serverUrl, authInfo] of Object.entries(auth)) {
|
|
79
|
+
if (!isWellKnownAuth(authInfo)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
console.log(`${LOG_PREFIX} Fetching config from ${serverUrl}`);
|
|
83
|
+
try {
|
|
84
|
+
const wellKnownUrl = `${serverUrl}/.well-known/opencode`;
|
|
85
|
+
const response = await fetch(wellKnownUrl, {
|
|
86
|
+
headers: {
|
|
87
|
+
Accept: "application/json"
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
console.warn(`${LOG_PREFIX} Failed to fetch from ${wellKnownUrl}: ${response.status} ${response.statusText}`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const data = await response.json();
|
|
95
|
+
if (data.omo && typeof data.omo === "object") {
|
|
96
|
+
console.log(`${LOG_PREFIX} Found omo config from ${serverUrl}`);
|
|
97
|
+
omoConfigs.push(data.omo);
|
|
98
|
+
}
|
|
99
|
+
} catch (e) {
|
|
100
|
+
console.warn(`${LOG_PREFIX} Error fetching from ${serverUrl}:`, e);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (omoConfigs.length === 0) {
|
|
105
|
+
console.log(`${LOG_PREFIX} No omo configs found, skipping write`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log(`${LOG_PREFIX} Found ${omoConfigs.length} omo config(s)`);
|
|
109
|
+
const configDir = getConfigDir();
|
|
110
|
+
await mkdir(configDir, { recursive: true });
|
|
111
|
+
const omoPath = path.join(configDir, "oh-my-opencode.json");
|
|
112
|
+
const omoFile = Bun.file(omoPath);
|
|
113
|
+
let existingConfig = {};
|
|
114
|
+
if (await omoFile.exists()) {
|
|
115
|
+
try {
|
|
116
|
+
existingConfig = await omoFile.json();
|
|
117
|
+
console.log(`${LOG_PREFIX} Loaded existing oh-my-opencode.json`);
|
|
118
|
+
} catch (e) {
|
|
119
|
+
console.warn(`${LOG_PREFIX} Failed to parse existing oh-my-opencode.json, starting fresh:`, e);
|
|
120
|
+
existingConfig = {};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
let mergedConfig = existingConfig;
|
|
124
|
+
for (const omoConfig of omoConfigs) {
|
|
125
|
+
mergedConfig = deepMerge(mergedConfig, omoConfig);
|
|
126
|
+
}
|
|
127
|
+
await Bun.write(omoPath, JSON.stringify(mergedConfig, null, 2));
|
|
128
|
+
console.log(`${LOG_PREFIX} Successfully wrote oh-my-opencode.json to ${omoPath}`);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error(`${LOG_PREFIX} Unexpected error during sync:`, error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
var SyncOmoConfigPlugin = async function SyncOmoConfigPlugin2() {
|
|
134
|
+
await syncOmoConfig();
|
|
135
|
+
return {};
|
|
136
|
+
};
|
|
137
|
+
var src_default = SyncOmoConfigPlugin;
|
|
138
|
+
export {
|
|
139
|
+
src_default as default,
|
|
140
|
+
SyncOmoConfigPlugin
|
|
141
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sync-omo-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenCode plugin to sync omo config from well-known endpoint to oh-my-opencode.json",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target bun",
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"prepublishOnly": "bun run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"opencode",
|
|
18
|
+
"opencode-plugin",
|
|
19
|
+
"oh-my-opencode",
|
|
20
|
+
"well-known",
|
|
21
|
+
"config-sync"
|
|
22
|
+
],
|
|
23
|
+
"author": "",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@opencode-ai/plugin": ">=0.1.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@opencode-ai/plugin": "latest",
|
|
30
|
+
"@types/bun": "latest",
|
|
31
|
+
"typescript": "^5.0.0"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": ""
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"bun": ">=1.0.0"
|
|
39
|
+
}
|
|
40
|
+
}
|