opencode-morphllm 0.0.4 → 0.0.6
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 +15 -1
- package/dist/index.js +3 -3
- package/dist/{mcps.js → morph/mcps.js} +1 -1
- package/dist/morph/mcps.test.d.ts +1 -0
- package/dist/morph/mcps.test.js +39 -0
- package/dist/{router.js → morph/router.js} +21 -4
- package/dist/morph/router.test.d.ts +1 -0
- package/dist/morph/router.test.js +240 -0
- package/dist/shared/config.d.ts +31 -0
- package/dist/shared/config.js +82 -0
- package/dist/shared/config.test.d.ts +1 -0
- package/dist/shared/config.test.js +204 -0
- package/dist/shared/opencode-config-dir.d.ts +9 -0
- package/dist/shared/opencode-config-dir.js +56 -0
- package/package.json +2 -2
- package/src/index.ts +3 -3
- package/src/morph/mcps.test.ts +51 -0
- package/src/{mcps.ts → morph/mcps.ts} +1 -1
- package/src/morph/router.test.ts +266 -0
- package/src/{router.ts → morph/router.ts} +24 -7
- package/src/shared/config.test.ts +245 -0
- package/src/shared/config.ts +118 -0
- package/src/shared/opencode-config-dir.ts +77 -0
- package/dist/const.d.ts +0 -6
- package/dist/const.js +0 -20
- package/src/const.ts +0 -32
- /package/dist/{mcps.d.ts → morph/mcps.d.ts} +0 -0
- /package/dist/{router.d.ts → morph/router.d.ts} +0 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
it,
|
|
4
|
+
expect,
|
|
5
|
+
beforeEach,
|
|
6
|
+
afterEach,
|
|
7
|
+
vi,
|
|
8
|
+
beforeAll,
|
|
9
|
+
afterAll,
|
|
10
|
+
} from 'bun:test';
|
|
11
|
+
import {
|
|
12
|
+
existsSync,
|
|
13
|
+
writeFileSync,
|
|
14
|
+
readFileSync,
|
|
15
|
+
rmSync,
|
|
16
|
+
mkdirSync,
|
|
17
|
+
} from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { tmpdir } from 'node:os';
|
|
20
|
+
|
|
21
|
+
// Mock the opencode-config-dir module before importing config
|
|
22
|
+
const mockConfigDir = join(tmpdir(), 'mock-opencode-config-test');
|
|
23
|
+
const mockMorphJson = join(mockConfigDir, 'morph.json');
|
|
24
|
+
const mockMorphJsonc = join(mockConfigDir, 'morph.jsonc');
|
|
25
|
+
|
|
26
|
+
vi.mock('./opencode-config-dir', () => ({
|
|
27
|
+
getOpenCodeConfigDir: vi.fn(() => mockConfigDir),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
getMorphPluginConfigPath,
|
|
32
|
+
loadMorphPluginConfig,
|
|
33
|
+
loadMorphPluginConfigWithProjectOverride,
|
|
34
|
+
} from './config';
|
|
35
|
+
|
|
36
|
+
describe('config.ts', () => {
|
|
37
|
+
beforeAll(() => {
|
|
38
|
+
// Create mock config directory
|
|
39
|
+
if (!existsSync(mockConfigDir)) {
|
|
40
|
+
mkdirSync(mockConfigDir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
// Cleanup
|
|
46
|
+
try {
|
|
47
|
+
if (existsSync(mockMorphJson)) rmSync(mockMorphJson);
|
|
48
|
+
if (existsSync(mockMorphJsonc)) rmSync(mockMorphJsonc);
|
|
49
|
+
if (existsSync(mockConfigDir)) rmSync(mockConfigDir, { recursive: true });
|
|
50
|
+
} catch {
|
|
51
|
+
// Ignore cleanup errors
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
// Clean up any existing config files before each test
|
|
57
|
+
try {
|
|
58
|
+
if (existsSync(mockMorphJson)) rmSync(mockMorphJson);
|
|
59
|
+
if (existsSync(mockMorphJsonc)) rmSync(mockMorphJsonc);
|
|
60
|
+
} catch {
|
|
61
|
+
// Ignore cleanup errors
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('getMorphPluginConfigPath', () => {
|
|
66
|
+
it('should return path to morph.json in config directory', () => {
|
|
67
|
+
const path = getMorphPluginConfigPath();
|
|
68
|
+
expect(path).toContain('morph.json');
|
|
69
|
+
expect(path).toContain(mockConfigDir);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('loadMorphPluginConfig', () => {
|
|
74
|
+
it('should return null when no config files exist', () => {
|
|
75
|
+
const result = loadMorphPluginConfig();
|
|
76
|
+
expect(result).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should load config from .jsonc file', () => {
|
|
80
|
+
const content = `{
|
|
81
|
+
"MORPH_API_KEY": "test-key-123",
|
|
82
|
+
"MORPH_ROUTER_ENABLED": false
|
|
83
|
+
}`;
|
|
84
|
+
writeFileSync(mockMorphJsonc, content);
|
|
85
|
+
|
|
86
|
+
const result = loadMorphPluginConfig();
|
|
87
|
+
expect(result).not.toBeNull();
|
|
88
|
+
expect(result?.MORPH_API_KEY).toBe('test-key-123');
|
|
89
|
+
expect(result?.MORPH_ROUTER_ENABLED).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should load config from .json file', () => {
|
|
93
|
+
const content = JSON.stringify({
|
|
94
|
+
MORPH_API_KEY: 'json-key-456',
|
|
95
|
+
MORPH_MODEL_EASY: 'provider/model-easy',
|
|
96
|
+
});
|
|
97
|
+
writeFileSync(mockMorphJson, content);
|
|
98
|
+
|
|
99
|
+
const result = loadMorphPluginConfig();
|
|
100
|
+
expect(result).not.toBeNull();
|
|
101
|
+
expect(result?.MORPH_API_KEY).toBe('json-key-456');
|
|
102
|
+
expect(result?.MORPH_MODEL_EASY).toBe('provider/model-easy');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should prefer .jsonc over .json when both exist', () => {
|
|
106
|
+
const jsoncContent = '{"MORPH_API_KEY": "from-jsonc"}';
|
|
107
|
+
const jsonContent = '{"MORPH_API_KEY": "from-json"}';
|
|
108
|
+
|
|
109
|
+
writeFileSync(mockMorphJsonc, jsoncContent);
|
|
110
|
+
writeFileSync(mockMorphJson, jsonContent);
|
|
111
|
+
|
|
112
|
+
const result = loadMorphPluginConfig();
|
|
113
|
+
expect(result?.MORPH_API_KEY).toBe('from-jsonc');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should return null for invalid .jsonc content', () => {
|
|
117
|
+
writeFileSync(mockMorphJsonc, 'invalid json content');
|
|
118
|
+
|
|
119
|
+
const result = loadMorphPluginConfig();
|
|
120
|
+
expect(result).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should return null for invalid .json content', () => {
|
|
124
|
+
writeFileSync(mockMorphJson, 'invalid json content');
|
|
125
|
+
|
|
126
|
+
const result = loadMorphPluginConfig();
|
|
127
|
+
expect(result).toBeNull();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should handle all MORPH config fields', () => {
|
|
131
|
+
const content = JSON.stringify({
|
|
132
|
+
MORPH_API_KEY: 'api-key',
|
|
133
|
+
MORPH_ROUTER_ENABLED: true,
|
|
134
|
+
MORPH_MODEL_EASY: 'easy/provider/model',
|
|
135
|
+
MORPH_MODEL_MEDIUM: 'medium/provider/model',
|
|
136
|
+
MORPH_MODEL_HARD: 'hard/provider/model',
|
|
137
|
+
MORPH_MODEL_DEFAULT: 'default/provider/model',
|
|
138
|
+
});
|
|
139
|
+
writeFileSync(mockMorphJson, content);
|
|
140
|
+
|
|
141
|
+
const result = loadMorphPluginConfig();
|
|
142
|
+
expect(result).toEqual({
|
|
143
|
+
MORPH_API_KEY: 'api-key',
|
|
144
|
+
MORPH_ROUTER_ENABLED: true,
|
|
145
|
+
MORPH_MODEL_EASY: 'easy/provider/model',
|
|
146
|
+
MORPH_MODEL_MEDIUM: 'medium/provider/model',
|
|
147
|
+
MORPH_MODEL_HARD: 'hard/provider/model',
|
|
148
|
+
MORPH_MODEL_DEFAULT: 'default/provider/model',
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should handle nested MORPH_ROUTER_CONFIGS', () => {
|
|
153
|
+
const content = JSON.stringify({
|
|
154
|
+
MORPH_API_KEY: 'api-key',
|
|
155
|
+
MORPH_ROUTER_CONFIGS: {
|
|
156
|
+
MORPH_ROUTER_ENABLED: true,
|
|
157
|
+
MORPH_MODEL_EASY: 'easy/provider/model',
|
|
158
|
+
MORPH_MODEL_MEDIUM: 'medium/provider/model',
|
|
159
|
+
MORPH_MODEL_HARD: 'hard/provider/model',
|
|
160
|
+
MORPH_MODEL_DEFAULT: 'default/provider/model',
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
writeFileSync(mockMorphJson, content);
|
|
164
|
+
|
|
165
|
+
const result = loadMorphPluginConfig();
|
|
166
|
+
expect(result?.MORPH_API_KEY).toBe('api-key');
|
|
167
|
+
expect(result?.MORPH_ROUTER_CONFIGS).toEqual({
|
|
168
|
+
MORPH_ROUTER_ENABLED: true,
|
|
169
|
+
MORPH_MODEL_EASY: 'easy/provider/model',
|
|
170
|
+
MORPH_MODEL_MEDIUM: 'medium/provider/model',
|
|
171
|
+
MORPH_MODEL_HARD: 'hard/provider/model',
|
|
172
|
+
MORPH_MODEL_DEFAULT: 'default/provider/model',
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe('loadMorphPluginConfigWithProjectOverride', () => {
|
|
178
|
+
it('should return empty object when no config exists', () => {
|
|
179
|
+
const result =
|
|
180
|
+
loadMorphPluginConfigWithProjectOverride('/non-existent-path');
|
|
181
|
+
expect(result).toEqual({});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should merge user config with project config', () => {
|
|
185
|
+
// Create user config
|
|
186
|
+
writeFileSync(
|
|
187
|
+
mockMorphJson,
|
|
188
|
+
JSON.stringify({
|
|
189
|
+
MORPH_API_KEY: 'user-api-key',
|
|
190
|
+
MORPH_MODEL_EASY: 'user-easy-model',
|
|
191
|
+
})
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// Create project config directory
|
|
195
|
+
const projectDir = join(tmpdir(), 'test-project');
|
|
196
|
+
const projectConfigDir = join(projectDir, '.opencode');
|
|
197
|
+
const projectConfigPath = join(projectConfigDir, 'morph.json');
|
|
198
|
+
|
|
199
|
+
mkdirSync(projectConfigDir, { recursive: true });
|
|
200
|
+
writeFileSync(
|
|
201
|
+
projectConfigPath,
|
|
202
|
+
JSON.stringify({
|
|
203
|
+
MORPH_API_KEY: 'project-api-key',
|
|
204
|
+
MORPH_MODEL_HARD: 'project-hard-model',
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const result = loadMorphPluginConfigWithProjectOverride(projectDir);
|
|
209
|
+
|
|
210
|
+
// Project config should override user config
|
|
211
|
+
expect(result.MORPH_API_KEY).toBe('project-api-key');
|
|
212
|
+
expect(result.MORPH_MODEL_EASY).toBe('user-easy-model');
|
|
213
|
+
expect(result.MORPH_MODEL_HARD).toBe('project-hard-model');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('should handle project .jsonc config', () => {
|
|
217
|
+
// Create user config
|
|
218
|
+
writeFileSync(
|
|
219
|
+
mockMorphJson,
|
|
220
|
+
JSON.stringify({
|
|
221
|
+
MORPH_API_KEY: 'user-key',
|
|
222
|
+
})
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
// Create project config with .jsonc
|
|
226
|
+
const projectDir = join(tmpdir(), 'test-project2');
|
|
227
|
+
const projectConfigDir = join(projectDir, '.opencode');
|
|
228
|
+
const projectConfigPath = join(projectConfigDir, 'morph.jsonc');
|
|
229
|
+
|
|
230
|
+
mkdirSync(projectConfigDir, { recursive: true });
|
|
231
|
+
const jsoncContent = `
|
|
232
|
+
// Project config with comments
|
|
233
|
+
{
|
|
234
|
+
"MORPH_MODEL_MEDIUM": "project-medium-model"
|
|
235
|
+
}
|
|
236
|
+
`;
|
|
237
|
+
writeFileSync(projectConfigPath, jsoncContent);
|
|
238
|
+
|
|
239
|
+
const result = loadMorphPluginConfigWithProjectOverride(projectDir);
|
|
240
|
+
|
|
241
|
+
expect(result.MORPH_API_KEY).toBe('user-key');
|
|
242
|
+
expect(result.MORPH_MODEL_MEDIUM).toBe('project-medium-model');
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { getOpenCodeConfigDir } from './opencode-config-dir';
|
|
4
|
+
|
|
5
|
+
const MORPH_PLUGIN_NAME = 'morph';
|
|
6
|
+
|
|
7
|
+
export function getMorphPluginConfigPath(): string {
|
|
8
|
+
const configDir = getOpenCodeConfigDir({ binary: 'opencode' });
|
|
9
|
+
return join(configDir, `${MORPH_PLUGIN_NAME}.json`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface MorphRouterConfigs {
|
|
13
|
+
MORPH_ROUTER_ENABLED?: boolean;
|
|
14
|
+
MORPH_ROUTER_ONLY_FIRST_MESSAGE?: boolean;
|
|
15
|
+
MORPH_MODEL_EASY?: string;
|
|
16
|
+
MORPH_MODEL_MEDIUM?: string;
|
|
17
|
+
MORPH_MODEL_HARD?: string;
|
|
18
|
+
MORPH_MODEL_DEFAULT?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface MorphConfig {
|
|
22
|
+
MORPH_API_KEY?: string;
|
|
23
|
+
MORPH_ROUTER_CONFIGS?: MorphRouterConfigs;
|
|
24
|
+
// Legacy fields for backward compatibility
|
|
25
|
+
MORPH_ROUTER_ENABLED?: boolean;
|
|
26
|
+
MORPH_ROUTER_ONLY_FIRST_MESSAGE?: boolean;
|
|
27
|
+
MORPH_MODEL_EASY?: string;
|
|
28
|
+
MORPH_MODEL_MEDIUM?: string;
|
|
29
|
+
MORPH_MODEL_HARD?: string;
|
|
30
|
+
MORPH_MODEL_DEFAULT?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseJsonc<T>(content: string): T | null {
|
|
34
|
+
try {
|
|
35
|
+
// A simple JSONC parser that removes comments
|
|
36
|
+
const cleanedContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
|
|
37
|
+
return JSON.parse(cleanedContent) as T;
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function loadMorphPluginConfig(): MorphConfig | null {
|
|
44
|
+
const jsoncPath = getMorphPluginConfigPath().replace('.json', '.jsonc');
|
|
45
|
+
const jsonPath = getMorphPluginConfigPath();
|
|
46
|
+
|
|
47
|
+
if (existsSync(jsoncPath)) {
|
|
48
|
+
try {
|
|
49
|
+
const content = readFileSync(jsoncPath, 'utf-8');
|
|
50
|
+
return parseJsonc<MorphConfig>(content);
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (existsSync(jsonPath)) {
|
|
57
|
+
try {
|
|
58
|
+
const content = readFileSync(jsonPath, 'utf-8');
|
|
59
|
+
return JSON.parse(content) as MorphConfig;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function loadMorphPluginConfigWithProjectOverride(
|
|
69
|
+
projectDir: string = process.cwd()
|
|
70
|
+
): MorphConfig {
|
|
71
|
+
const userConfig = loadMorphPluginConfig() ?? {};
|
|
72
|
+
|
|
73
|
+
const projectBasePath = join(projectDir, '.opencode', MORPH_PLUGIN_NAME);
|
|
74
|
+
const projectJsoncPath = `${projectBasePath}.jsonc`;
|
|
75
|
+
const projectJsonPath = `${projectBasePath}.json`;
|
|
76
|
+
|
|
77
|
+
let projectConfig: MorphConfig = {};
|
|
78
|
+
|
|
79
|
+
if (existsSync(projectJsoncPath)) {
|
|
80
|
+
try {
|
|
81
|
+
const content = readFileSync(projectJsoncPath, 'utf-8');
|
|
82
|
+
projectConfig = parseJsonc<MorphConfig>(content) ?? {};
|
|
83
|
+
} catch {
|
|
84
|
+
// Ignore parse errors
|
|
85
|
+
}
|
|
86
|
+
} else if (existsSync(projectJsonPath)) {
|
|
87
|
+
try {
|
|
88
|
+
const content = readFileSync(projectJsonPath, 'utf-8');
|
|
89
|
+
projectConfig = JSON.parse(content) as MorphConfig;
|
|
90
|
+
} catch {
|
|
91
|
+
// Ignore parse errors
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return { ...userConfig, ...projectConfig };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const config = loadMorphPluginConfigWithProjectOverride();
|
|
99
|
+
|
|
100
|
+
const routerConfigs = config.MORPH_ROUTER_CONFIGS || {};
|
|
101
|
+
|
|
102
|
+
export const API_KEY = config.MORPH_API_KEY || '';
|
|
103
|
+
export const MORPH_MODEL_EASY =
|
|
104
|
+
routerConfigs.MORPH_MODEL_EASY || config.MORPH_MODEL_EASY || '';
|
|
105
|
+
export const MORPH_MODEL_MEDIUM =
|
|
106
|
+
routerConfigs.MORPH_MODEL_MEDIUM || config.MORPH_MODEL_MEDIUM || '';
|
|
107
|
+
export const MORPH_MODEL_HARD =
|
|
108
|
+
routerConfigs.MORPH_MODEL_HARD || config.MORPH_MODEL_HARD || '';
|
|
109
|
+
export const MORPH_MODEL_DEFAULT =
|
|
110
|
+
routerConfigs.MORPH_MODEL_DEFAULT ||
|
|
111
|
+
config.MORPH_MODEL_DEFAULT ||
|
|
112
|
+
MORPH_MODEL_MEDIUM;
|
|
113
|
+
export const MORPH_ROUTER_ENABLED =
|
|
114
|
+
routerConfigs.MORPH_ROUTER_ENABLED ?? config.MORPH_ROUTER_ENABLED ?? true;
|
|
115
|
+
export const MORPH_ROUTER_ONLY_FIRST_MESSAGE =
|
|
116
|
+
routerConfigs.MORPH_ROUTER_ONLY_FIRST_MESSAGE ??
|
|
117
|
+
config.MORPH_ROUTER_ONLY_FIRST_MESSAGE ??
|
|
118
|
+
false;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
interface OpenCodeConfigDirOptions {
|
|
6
|
+
binary: 'opencode' | 'opencode-desktop';
|
|
7
|
+
version?: string | null;
|
|
8
|
+
checkExisting?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getTauriConfigDir(identifier: string): string {
|
|
12
|
+
const platform = process.platform;
|
|
13
|
+
|
|
14
|
+
switch (platform) {
|
|
15
|
+
case 'darwin':
|
|
16
|
+
return join(homedir(), 'Library', 'Application Support', identifier);
|
|
17
|
+
|
|
18
|
+
case 'win32': {
|
|
19
|
+
const appData =
|
|
20
|
+
process.env.APPDATA || join(homedir(), 'AppData', 'Roaming');
|
|
21
|
+
return join(appData, identifier);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
case 'linux':
|
|
25
|
+
default: {
|
|
26
|
+
const xdgConfig =
|
|
27
|
+
process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
|
|
28
|
+
return join(xdgConfig, identifier);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getCliConfigDir(): string {
|
|
34
|
+
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
35
|
+
if (envConfigDir) {
|
|
36
|
+
return resolve(envConfigDir);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (process.platform === 'win32') {
|
|
40
|
+
const crossPlatformDir = join(homedir(), '.config', 'opencode');
|
|
41
|
+
const crossPlatformConfig = join(crossPlatformDir, 'opencode.json');
|
|
42
|
+
|
|
43
|
+
if (existsSync(crossPlatformConfig)) {
|
|
44
|
+
return crossPlatformDir;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const appData =
|
|
48
|
+
process.env.APPDATA || join(homedir(), 'AppData', 'Roaming');
|
|
49
|
+
const appdataDir = join(appData, 'opencode');
|
|
50
|
+
const appdataConfig = join(appdataDir, 'opencode.json');
|
|
51
|
+
|
|
52
|
+
if (existsSync(appdataConfig)) {
|
|
53
|
+
return appdataDir;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return crossPlatformDir;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
|
|
60
|
+
return join(xdgConfig, 'opencode');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function getOpenCodeConfigDir(
|
|
64
|
+
options: OpenCodeConfigDirOptions
|
|
65
|
+
): string {
|
|
66
|
+
if (options.binary === 'opencode-desktop') {
|
|
67
|
+
const version = options.version;
|
|
68
|
+
const isDev =
|
|
69
|
+
!!version && (version.includes('-dev') || version.includes('.dev'));
|
|
70
|
+
const identifier = isDev
|
|
71
|
+
? 'ai.opencode.desktop.dev'
|
|
72
|
+
: 'ai.opencode.desktop';
|
|
73
|
+
return getTauriConfigDir(identifier);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return getCliConfigDir();
|
|
77
|
+
}
|
package/dist/const.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare const API_KEY: string;
|
|
2
|
-
export declare const MORPH_MODEL_EASY: string;
|
|
3
|
-
export declare const MORPH_MODEL_MEDIUM: string;
|
|
4
|
-
export declare const MORPH_MODEL_HARD: string;
|
|
5
|
-
export declare const MORPH_MODEL_DEFAULT: string;
|
|
6
|
-
export declare const MORPH_ROUTER_ENABLED: boolean;
|
package/dist/const.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
const configPath = path.join(
|
|
4
|
-
process.env.HOME || process.env.USERPROFILE || '',
|
|
5
|
-
'.config/opencode/morph.json'
|
|
6
|
-
);
|
|
7
|
-
let config = {};
|
|
8
|
-
try {
|
|
9
|
-
if (fs.existsSync(configPath)) {
|
|
10
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
11
|
-
}
|
|
12
|
-
} catch (e) {
|
|
13
|
-
console.warn('[Morph Plugin] Failed to load config file:', configPath);
|
|
14
|
-
}
|
|
15
|
-
export const API_KEY = config.MORPH_API_KEY || '';
|
|
16
|
-
export const MORPH_MODEL_EASY = config.MORPH_MODEL_EASY || '';
|
|
17
|
-
export const MORPH_MODEL_MEDIUM = config.MORPH_MODEL_MEDIUM || '';
|
|
18
|
-
export const MORPH_MODEL_HARD = config.MORPH_MODEL_HARD || '';
|
|
19
|
-
export const MORPH_MODEL_DEFAULT = config.MORPH_MODEL_DEFAULT || '';
|
|
20
|
-
export const MORPH_ROUTER_ENABLED = config.MORPH_ROUTER_ENABLED ?? true;
|
package/src/const.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
interface MorphConfig {
|
|
4
|
-
MORPH_API_KEY?: string;
|
|
5
|
-
MORPH_ROUTER_ENABLED?: boolean;
|
|
6
|
-
MORPH_MODEL_EASY?: string;
|
|
7
|
-
MORPH_MODEL_MEDIUM?: string;
|
|
8
|
-
MORPH_MODEL_HARD?: string;
|
|
9
|
-
MORPH_MODEL_DEFAULT?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const configPath = path.join(
|
|
13
|
-
process.env.HOME || process.env.USERPROFILE || '',
|
|
14
|
-
'.config/opencode/morph.json'
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
let config: MorphConfig = {};
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
if (fs.existsSync(configPath)) {
|
|
21
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
22
|
-
}
|
|
23
|
-
} catch (e) {
|
|
24
|
-
console.warn('[Morph Plugin] Failed to load config file:', configPath);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const API_KEY = config.MORPH_API_KEY || '';
|
|
28
|
-
export const MORPH_MODEL_EASY = config.MORPH_MODEL_EASY || '';
|
|
29
|
-
export const MORPH_MODEL_MEDIUM = config.MORPH_MODEL_MEDIUM || '';
|
|
30
|
-
export const MORPH_MODEL_HARD = config.MORPH_MODEL_HARD || '';
|
|
31
|
-
export const MORPH_MODEL_DEFAULT = config.MORPH_MODEL_DEFAULT || '';
|
|
32
|
-
export const MORPH_ROUTER_ENABLED = config.MORPH_ROUTER_ENABLED ?? true;
|
|
File without changes
|
|
File without changes
|