codexmate 0.0.45 → 0.0.47
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 +20 -7
- package/README.zh.md +20 -7
- package/cli.js +473 -3
- package/package.json +2 -1
- package/web-ui/app.js +27 -4
- package/web-ui/index.html +1 -0
- package/web-ui/modules/app.constants.mjs +13 -0
- package/web-ui/modules/app.methods.index.mjs +6 -0
- package/web-ui/modules/app.methods.opencode-config.mjs +228 -0
- package/web-ui/modules/app.methods.startup-claude.mjs +3 -1
- package/web-ui/modules/app.methods.tool-config-permissions.mjs +3 -2
- package/web-ui/modules/config-mode.computed.mjs +17 -1
- package/web-ui/modules/i18n/locales/en.mjs +42 -0
- package/web-ui/modules/i18n/locales/ja.mjs +42 -0
- package/web-ui/modules/i18n/locales/vi.mjs +43 -0
- package/web-ui/modules/i18n/locales/zh-tw.mjs +1269 -0
- package/web-ui/modules/i18n/locales/zh.mjs +42 -0
- package/web-ui/modules/i18n.dict.mjs +2 -0
- package/web-ui/modules/i18n.mjs +3 -2
- package/web-ui/partials/index/layout-header.html +30 -2
- package/web-ui/partials/index/panel-config-claude.html +6 -6
- package/web-ui/partials/index/panel-config-codex.html +6 -6
- package/web-ui/partials/index/panel-config-opencode.html +166 -0
- package/web-ui/res/web-ui-render.precompiled.js +467 -55
- package/web-ui/styles/controls-forms.css +62 -4
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
function normalizeOpencodeProviderName(value) {
|
|
2
|
+
const name = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
3
|
+
return /^[a-z0-9_.-]+$/.test(name) ? name : '';
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function normalizeOpencodeAgentName(value) {
|
|
7
|
+
const name = typeof value === 'string' ? value.trim() : '';
|
|
8
|
+
return /^[a-zA-Z0-9_.-]+$/.test(name) ? name : '';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getOpencodeJsonParser() {
|
|
12
|
+
const root = typeof globalThis !== 'undefined' ? globalThis : {};
|
|
13
|
+
const json5 = root.JSON5 || (root.window && root.window.JSON5);
|
|
14
|
+
if (json5 && typeof json5.parse === 'function') {
|
|
15
|
+
return json5;
|
|
16
|
+
}
|
|
17
|
+
return JSON;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function summarizeOpencodeDraft(content) {
|
|
21
|
+
const parsed = getOpencodeJsonParser().parse(content || '{}');
|
|
22
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
23
|
+
throw new Error('OpenCode config must be a JSON/JSONC object');
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function createOpencodeConfigMethods(options = {}) {
|
|
29
|
+
const { api, modelCatalog = {} } = options;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
opencodeProviderCatalog() {
|
|
33
|
+
const configured = Array.isArray(this.opencodeProviders)
|
|
34
|
+
? this.opencodeProviders.map(item => item && item.name).filter(Boolean)
|
|
35
|
+
: [];
|
|
36
|
+
const builtin = Object.keys(modelCatalog || {});
|
|
37
|
+
return [...new Set([...configured, ...builtin])].sort((a, b) => a.localeCompare(b));
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
opencodeModelCatalogForProvider(providerName = this.opencodeProvider) {
|
|
41
|
+
const provider = normalizeOpencodeProviderName(providerName);
|
|
42
|
+
const list = provider && Array.isArray(modelCatalog[provider]) ? modelCatalog[provider] : [];
|
|
43
|
+
const configured = Array.isArray(this.opencodeAgents)
|
|
44
|
+
? this.opencodeAgents.map(item => item && item.model).filter(Boolean)
|
|
45
|
+
: [];
|
|
46
|
+
return [...new Set([...list, ...configured])];
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
fillOpencodeProvider(provider) {
|
|
50
|
+
const name = normalizeOpencodeProviderName(provider);
|
|
51
|
+
if (!name) return;
|
|
52
|
+
this.opencodeProvider = name;
|
|
53
|
+
const models = this.opencodeModelCatalogForProvider(name);
|
|
54
|
+
if (!this.opencodeModel || !models.includes(this.opencodeModel)) {
|
|
55
|
+
this.opencodeModel = models[0] || '';
|
|
56
|
+
}
|
|
57
|
+
const selectedProvider = Array.isArray(this.opencodeProviders)
|
|
58
|
+
? this.opencodeProviders.find(item => normalizeOpencodeProviderName(item && item.name) === name)
|
|
59
|
+
: null;
|
|
60
|
+
this.opencodeProviderDisabled = !!(selectedProvider && selectedProvider.disabled);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
refreshOpencodeSelectionFromSummary(res = {}) {
|
|
64
|
+
const providers = Array.isArray(res.providers) ? res.providers : [];
|
|
65
|
+
const agents = Array.isArray(res.agents) ? res.agents : [];
|
|
66
|
+
this.opencodeProviders = providers;
|
|
67
|
+
this.opencodeAgents = agents;
|
|
68
|
+
const currentAgent = normalizeOpencodeAgentName(res.currentAgent) || 'build';
|
|
69
|
+
this.opencodeAgent = currentAgent;
|
|
70
|
+
const currentModel = typeof res.currentModel === 'string' ? res.currentModel.trim() : '';
|
|
71
|
+
this.opencodeModel = currentModel;
|
|
72
|
+
if (typeof res.autoCompact === 'boolean') {
|
|
73
|
+
this.opencodeAutoCompact = res.autoCompact;
|
|
74
|
+
}
|
|
75
|
+
const enabledProvider = providers.find(item => item && item.disabled !== true && item.hasKey);
|
|
76
|
+
const firstProvider = providers.find(item => item && item.name);
|
|
77
|
+
this.opencodeProvider = normalizeOpencodeProviderName(res.currentProvider)
|
|
78
|
+
|| normalizeOpencodeProviderName(enabledProvider && enabledProvider.name)
|
|
79
|
+
|| normalizeOpencodeProviderName(firstProvider && firstProvider.name)
|
|
80
|
+
|| normalizeOpencodeProviderName(this.opencodeProvider)
|
|
81
|
+
|| 'anthropic';
|
|
82
|
+
const selectedProvider = providers.find(item => normalizeOpencodeProviderName(item && item.name) === this.opencodeProvider);
|
|
83
|
+
this.opencodeProviderDisabled = !!(selectedProvider && selectedProvider.disabled);
|
|
84
|
+
const models = this.opencodeModelCatalogForProvider(this.opencodeProvider);
|
|
85
|
+
if (!this.opencodeModel || (models.length && !models.includes(this.opencodeModel))) {
|
|
86
|
+
this.opencodeModel = models[0] || '';
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
async loadOpencodeConfig(options = {}) {
|
|
91
|
+
if (this.opencodeLoading) return;
|
|
92
|
+
this.opencodeLoading = true;
|
|
93
|
+
this.opencodeError = '';
|
|
94
|
+
try {
|
|
95
|
+
const res = await api('get-opencode-config');
|
|
96
|
+
if (res && res.error) {
|
|
97
|
+
this.opencodeError = res.error;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
this.opencodeContent = typeof res.content === 'string' ? res.content : '{}';
|
|
101
|
+
this.opencodeConfigPath = typeof res.targetPath === 'string' ? res.targetPath : '';
|
|
102
|
+
this.opencodeProviderStorePath = typeof res.providerStorePath === 'string' ? res.providerStorePath : '';
|
|
103
|
+
this.opencodeConfigExists = res.exists === true;
|
|
104
|
+
this.refreshOpencodeSelectionFromSummary(res || {});
|
|
105
|
+
if (options.toast === true) {
|
|
106
|
+
this.showMessage('OpenCode 配置已刷新', 'success');
|
|
107
|
+
}
|
|
108
|
+
} catch (e) {
|
|
109
|
+
this.opencodeError = e && e.message ? e.message : '读取 OpenCode 配置失败';
|
|
110
|
+
} finally {
|
|
111
|
+
this.opencodeLoading = false;
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
parseOpencodeImportContent(content, fileName = '') {
|
|
116
|
+
const raw = typeof content === 'string' ? content : '';
|
|
117
|
+
if (!raw.trim()) {
|
|
118
|
+
return { error: '导入文件为空' };
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const parsed = summarizeOpencodeDraft(raw);
|
|
122
|
+
const pretty = JSON.stringify(parsed, null, 2) + '\n';
|
|
123
|
+
return { content: pretty, fileName };
|
|
124
|
+
} catch (e) {
|
|
125
|
+
return { error: `OpenCode JSON/JSONC 解析失败: ${e.message}` };
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
async handleOpencodeImportChange(event) {
|
|
130
|
+
const input = event && event.target ? event.target : null;
|
|
131
|
+
const file = input && input.files && input.files[0] ? input.files[0] : null;
|
|
132
|
+
if (!file) return;
|
|
133
|
+
this.opencodeImportError = '';
|
|
134
|
+
try {
|
|
135
|
+
const content = await file.text();
|
|
136
|
+
const parsed = this.parseOpencodeImportContent(content, file.name || '');
|
|
137
|
+
if (parsed.error) {
|
|
138
|
+
this.opencodeImportError = parsed.error;
|
|
139
|
+
this.showMessage(parsed.error, 'error');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
this.opencodeContent = parsed.content;
|
|
143
|
+
this.opencodeImportFileName = parsed.fileName;
|
|
144
|
+
this.showMessage('已解析 OpenCode 配置,确认后可保存', 'success');
|
|
145
|
+
} catch (e) {
|
|
146
|
+
this.opencodeImportError = e && e.message ? e.message : '读取导入文件失败';
|
|
147
|
+
this.showMessage(this.opencodeImportError, 'error');
|
|
148
|
+
} finally {
|
|
149
|
+
if (input) input.value = '';
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
async saveOpencodeConfig() {
|
|
154
|
+
if (this.opencodeSaving) return;
|
|
155
|
+
if (!this.isToolConfigWriteAllowed('opencode')) {
|
|
156
|
+
this.showMessage('请先打开 OpenCode 写入开关', 'error');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
this.opencodeSaving = true;
|
|
160
|
+
this.opencodeError = '';
|
|
161
|
+
try {
|
|
162
|
+
const res = await api('apply-opencode-config', { content: this.opencodeContent });
|
|
163
|
+
if (res && res.error) {
|
|
164
|
+
this.opencodeError = res.error;
|
|
165
|
+
this.showMessage(res.error, 'error');
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.opencodeConfigExists = true;
|
|
169
|
+
if (res && typeof res.targetPath === 'string') this.opencodeConfigPath = res.targetPath;
|
|
170
|
+
if (res && typeof res.providerStorePath === 'string') this.opencodeProviderStorePath = res.providerStorePath;
|
|
171
|
+
this.refreshOpencodeSelectionFromSummary(res || {});
|
|
172
|
+
this.showMessage('OpenCode 配置已保存', 'success');
|
|
173
|
+
await this.loadOpencodeConfig();
|
|
174
|
+
} catch (e) {
|
|
175
|
+
this.opencodeError = e && e.message ? e.message : '保存 OpenCode 配置失败';
|
|
176
|
+
this.showMessage(this.opencodeError, 'error');
|
|
177
|
+
} finally {
|
|
178
|
+
this.opencodeSaving = false;
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
async applyOpencodeSelection() {
|
|
183
|
+
if (this.opencodeApplying) return;
|
|
184
|
+
if (!this.isToolConfigWriteAllowed('opencode')) {
|
|
185
|
+
this.showMessage('请先打开 OpenCode 写入开关', 'error');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const provider = normalizeOpencodeProviderName(this.opencodeProvider);
|
|
189
|
+
const model = typeof this.opencodeModel === 'string' ? this.opencodeModel.trim() : '';
|
|
190
|
+
if (!provider || !model) {
|
|
191
|
+
this.showMessage('请选择 OpenCode provider 和 model', 'error');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
this.opencodeApplying = true;
|
|
195
|
+
this.opencodeError = '';
|
|
196
|
+
try {
|
|
197
|
+
const res = await api('update-opencode-selection', {
|
|
198
|
+
provider,
|
|
199
|
+
model,
|
|
200
|
+
apiKey: this.opencodeApiKey,
|
|
201
|
+
agent: this.opencodeAgent || 'build',
|
|
202
|
+
applyToCoreAgents: this.opencodeApplyToCoreAgents === true,
|
|
203
|
+
disabled: this.opencodeProviderDisabled === true,
|
|
204
|
+
autoCompact: this.opencodeAutoCompact !== false,
|
|
205
|
+
maxTokens: this.opencodeMaxTokens,
|
|
206
|
+
reasoningEffort: this.opencodeReasoningEffort
|
|
207
|
+
});
|
|
208
|
+
if (res && res.error) {
|
|
209
|
+
this.opencodeError = res.error;
|
|
210
|
+
this.showMessage(res.error, 'error');
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (res && typeof res.content === 'string') this.opencodeContent = res.content;
|
|
214
|
+
if (res && typeof res.targetPath === 'string') this.opencodeConfigPath = res.targetPath;
|
|
215
|
+
if (res && typeof res.providerStorePath === 'string') this.opencodeProviderStorePath = res.providerStorePath;
|
|
216
|
+
this.opencodeConfigExists = true;
|
|
217
|
+
this.opencodeApiKey = '';
|
|
218
|
+
this.refreshOpencodeSelectionFromSummary(res || {});
|
|
219
|
+
this.showMessage('OpenCode provider/model 已应用', 'success');
|
|
220
|
+
} catch (e) {
|
|
221
|
+
this.opencodeError = e && e.message ? e.message : '应用 OpenCode 配置失败';
|
|
222
|
+
this.showMessage(this.opencodeError, 'error');
|
|
223
|
+
} finally {
|
|
224
|
+
this.opencodeApplying = false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
@@ -125,7 +125,8 @@ export function createStartupClaudeMethods(options = {}) {
|
|
|
125
125
|
if (statusRes.toolConfigPermissions && typeof statusRes.toolConfigPermissions === 'object') {
|
|
126
126
|
this.toolConfigPermissions = {
|
|
127
127
|
codex: statusRes.toolConfigPermissions.codex === true,
|
|
128
|
-
claude: statusRes.toolConfigPermissions.claude === true
|
|
128
|
+
claude: statusRes.toolConfigPermissions.claude === true,
|
|
129
|
+
opencode: statusRes.toolConfigPermissions.opencode === true
|
|
129
130
|
};
|
|
130
131
|
try {
|
|
131
132
|
localStorage.setItem('toolConfigPermissions', JSON.stringify(this.toolConfigPermissions));
|
|
@@ -134,6 +135,7 @@ export function createStartupClaudeMethods(options = {}) {
|
|
|
134
135
|
this.providersList = listRes.providers;
|
|
135
136
|
if (typeof this.loadLocalBridgeExcluded === 'function') { this.loadLocalBridgeExcluded(); }
|
|
136
137
|
if (typeof this.loadClaudeLocalBridgeStatus === 'function') { this.loadClaudeLocalBridgeStatus(); }
|
|
138
|
+
if (typeof this.loadOpencodeConfig === 'function') { this.loadOpencodeConfig(); }
|
|
137
139
|
if (statusRes.configReady === false) {
|
|
138
140
|
this.showMessage('配置已加载', 'info');
|
|
139
141
|
}
|
|
@@ -3,14 +3,15 @@ export function createToolConfigPermissionMethods(options = {}) {
|
|
|
3
3
|
|
|
4
4
|
function normalizeTarget(value) {
|
|
5
5
|
const target = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
6
|
-
return target === 'codex' || target === 'claude' ? target : '';
|
|
6
|
+
return target === 'codex' || target === 'claude' || target === 'opencode' ? target : '';
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function normalizePermissions(value) {
|
|
10
10
|
const source = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
11
11
|
return {
|
|
12
12
|
codex: source.codex === true,
|
|
13
|
-
claude: source.claude === true
|
|
13
|
+
claude: source.claude === true,
|
|
14
|
+
opencode: source.opencode === true
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
export const CONFIG_MODE_SET = new Set([
|
|
11
11
|
...Object.keys(PROVIDER_CONFIG_MODE_META),
|
|
12
12
|
'claude',
|
|
13
|
-
'openclaw'
|
|
13
|
+
'openclaw',
|
|
14
|
+
'opencode'
|
|
14
15
|
]);
|
|
15
16
|
|
|
16
17
|
export function getProviderConfigModeMeta(mode) {
|
|
@@ -61,6 +62,7 @@ export function createConfigModeComputed() {
|
|
|
61
62
|
if (providerMeta) return providerMeta.label;
|
|
62
63
|
if (this.configMode === 'claude') return 'Claude Code';
|
|
63
64
|
if (this.configMode === 'openclaw') return 'OpenClaw';
|
|
65
|
+
if (this.configMode === 'opencode') return 'OpenCode';
|
|
64
66
|
return '未选择';
|
|
65
67
|
},
|
|
66
68
|
inspectorCurrentConfigLabel() {
|
|
@@ -76,6 +78,10 @@ export function createConfigModeComputed() {
|
|
|
76
78
|
const openclaw = typeof this.currentOpenclawConfig === 'string' ? this.currentOpenclawConfig.trim() : '';
|
|
77
79
|
return openclaw || '未选择';
|
|
78
80
|
}
|
|
81
|
+
if (this.configMode === 'opencode') {
|
|
82
|
+
const provider = typeof this.opencodeProvider === 'string' ? this.opencodeProvider.trim() : '';
|
|
83
|
+
return provider || '未选择';
|
|
84
|
+
}
|
|
79
85
|
return '未选择';
|
|
80
86
|
},
|
|
81
87
|
inspectorCurrentModelLabel() {
|
|
@@ -93,6 +99,10 @@ export function createConfigModeComputed() {
|
|
|
93
99
|
: '';
|
|
94
100
|
return model || '按配置文件';
|
|
95
101
|
}
|
|
102
|
+
if (this.configMode === 'opencode') {
|
|
103
|
+
const model = typeof this.opencodeModel === 'string' ? this.opencodeModel.trim() : '';
|
|
104
|
+
return model || '未选择';
|
|
105
|
+
}
|
|
96
106
|
return '未选择';
|
|
97
107
|
},
|
|
98
108
|
inspectorTemplateStatus() {
|
|
@@ -118,6 +128,12 @@ export function createConfigModeComputed() {
|
|
|
118
128
|
}
|
|
119
129
|
return 'JSON5 可保存并应用';
|
|
120
130
|
}
|
|
131
|
+
if (this.configMode === 'opencode') {
|
|
132
|
+
if (this.opencodeSaving || this.opencodeApplying) {
|
|
133
|
+
return 'OpenCode 保存/应用中';
|
|
134
|
+
}
|
|
135
|
+
return 'JSON 可编辑并应用';
|
|
136
|
+
}
|
|
121
137
|
return '未选择';
|
|
122
138
|
}
|
|
123
139
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const en = Object.freeze({
|
|
2
2
|
// Global
|
|
3
3
|
'lang.zh': '中文',
|
|
4
|
+
'lang.zh-tw': '繁體中文',
|
|
4
5
|
'lang.en': 'English',
|
|
5
6
|
'lang.vi': 'Vietnamese',
|
|
6
7
|
'lang.label': 'Language',
|
|
@@ -65,6 +66,8 @@ const en = Object.freeze({
|
|
|
65
66
|
'common.none': 'None',
|
|
66
67
|
'common.configured': 'Configured',
|
|
67
68
|
'common.notConfigured': 'Not configured',
|
|
69
|
+
'common.enabled': 'Enabled',
|
|
70
|
+
'common.disabled': 'Disabled',
|
|
68
71
|
'cli.missing.title': '{name} CLI not installed',
|
|
69
72
|
'cli.missing.subtitle': 'Install {name} CLI before using this page.',
|
|
70
73
|
'cli.missing.openDocs': 'Open install guide',
|
|
@@ -125,6 +128,7 @@ const en = Object.freeze({
|
|
|
125
128
|
'tab.config.codex': 'Codex',
|
|
126
129
|
'tab.config.claude': 'Claude',
|
|
127
130
|
'tab.config.openclaw': 'OpenClaw',
|
|
131
|
+
'tab.config.opencode': 'OpenCode',
|
|
128
132
|
'tab.sessions': 'Sessions',
|
|
129
133
|
'tab.usage': 'Usage',
|
|
130
134
|
'tab.orchestration': 'Tasks',
|
|
@@ -166,6 +170,8 @@ const en = Object.freeze({
|
|
|
166
170
|
'side.config.claude.meta': 'Claude Settings',
|
|
167
171
|
'side.config.openclaw': 'OpenClaw',
|
|
168
172
|
'side.config.openclaw.meta': 'JSON5 / AGENTS',
|
|
173
|
+
'side.config.opencode': 'OpenCode',
|
|
174
|
+
'side.config.opencode.meta': 'Config / Provider',
|
|
169
175
|
'side.sessions.browser': 'Session Browser',
|
|
170
176
|
'side.sessions.browser.meta': 'Browse / Export / Cleanup',
|
|
171
177
|
'side.prompts.agents': 'AGENTS.md',
|
|
@@ -805,6 +811,39 @@ const en = Object.freeze({
|
|
|
805
811
|
'toolConfig.claude.lockedTitle': 'Claude providers are read-only',
|
|
806
812
|
'toolConfig.claude.lockedDesc': 'Claude config will not be modified. Enable writes in this tab to add, apply, edit, or delete providers.',
|
|
807
813
|
'toolConfig.claude.confirmMessage': 'After enabling this, apply actions in the Claude tab may write ~/.claude/settings.json and related Claude config.',
|
|
814
|
+
'toolConfig.opencode.title': 'OpenCode config writes',
|
|
815
|
+
'toolConfig.opencode.desc': 'Read-only by default; enable to write OpenCode config.',
|
|
816
|
+
'toolConfig.opencode.lockedTitle': 'Read-only',
|
|
817
|
+
'toolConfig.opencode.lockedDesc': 'Enable write access to save, import, or apply config.',
|
|
818
|
+
'toolConfig.opencode.confirmMessage': 'After enabling this, actions in the OpenCode tab may write the XDG OpenCode config file (for example ~/.config/opencode/opencode.jsonc) or the file specified by OPENCODE_CONFIG.',
|
|
819
|
+
'opencode.providerModel.title': 'OpenCode provider / model',
|
|
820
|
+
'opencode.writeAria': 'OpenCode write access',
|
|
821
|
+
'opencode.applySelection': 'Apply to OpenCode',
|
|
822
|
+
'opencode.targetFile': 'Active OpenCode config: {path} · {status}',
|
|
823
|
+
'opencode.providerStoreFile': 'Provider draft store: {path} (written to OpenCode on apply)',
|
|
824
|
+
'opencode.field.agent': 'Agent',
|
|
825
|
+
'opencode.field.apiKeyKeep': 'API key (leave blank to keep current key)',
|
|
826
|
+
'opencode.field.maxTokens': 'maxTokens (optional)',
|
|
827
|
+
'opencode.field.reasoningEffort': 'reasoningEffort (optional)',
|
|
828
|
+
'opencode.option.keepUnchanged': 'Keep unchanged',
|
|
829
|
+
'opencode.option.reasoningLow': 'low',
|
|
830
|
+
'opencode.option.reasoningMedium': 'medium',
|
|
831
|
+
'opencode.option.reasoningHigh': 'high',
|
|
832
|
+
'opencode.applyToCoreAgents': 'Apply to all core agents',
|
|
833
|
+
'opencode.enableAutoCompaction': 'Enable compaction.auto',
|
|
834
|
+
'opencode.disableProvider': 'Disable this provider',
|
|
835
|
+
'opencode.configFile.title': 'OpenCode config file',
|
|
836
|
+
'opencode.importParse': 'Import / parse file',
|
|
837
|
+
'opencode.saveConfig': 'Save config',
|
|
838
|
+
'opencode.parsedFile': 'Parsed: {file}',
|
|
839
|
+
'opencode.textarea.placeholder': 'Edit OpenCode config',
|
|
840
|
+
'opencode.configFile.hint': 'Active config preview; drafts stored in separate Provider store.',
|
|
841
|
+
'opencode.summary.title': 'Parsed summary',
|
|
842
|
+
'opencode.summary.noApiKey': 'No API key configured',
|
|
843
|
+
'opencode.summary.noModel': 'No model set',
|
|
844
|
+
'opencode.summary.agentType': 'agent',
|
|
845
|
+
'opencode.summary.sourceCodexMate': 'CodexMate store',
|
|
846
|
+
'opencode.summary.sourceOpenCode': 'Active OpenCode',
|
|
808
847
|
'config.providerTemplate.title': 'Provider presets',
|
|
809
848
|
'config.models': 'Model',
|
|
810
849
|
'config.modelLoading': 'Loading...',
|
|
@@ -1026,6 +1065,9 @@ const en = Object.freeze({
|
|
|
1026
1065
|
'status.claudeConfig': 'Claude config',
|
|
1027
1066
|
'status.claudeModel': 'Claude model',
|
|
1028
1067
|
'status.openclawConfig': 'OpenClaw config',
|
|
1068
|
+
'status.opencodeProvider': 'OpenCode provider',
|
|
1069
|
+
'status.opencodeModel': 'OpenCode model',
|
|
1070
|
+
'status.opencodeConfig': 'OpenCode config',
|
|
1029
1071
|
'status.workspaceFile': 'Workspace file',
|
|
1030
1072
|
'status.configMode': 'Config mode',
|
|
1031
1073
|
'status.currentProvider': 'Current provider',
|
|
@@ -2,6 +2,7 @@ const ja = Object.freeze({
|
|
|
2
2
|
|
|
3
3
|
// Global
|
|
4
4
|
'lang.zh': '中国語',
|
|
5
|
+
'lang.zh-tw': '繁體中文',
|
|
5
6
|
'lang.en': 'English',
|
|
6
7
|
'lang.vi': 'ベトナム語',
|
|
7
8
|
'lang.label': '言語',
|
|
@@ -66,6 +67,8 @@ const ja = Object.freeze({
|
|
|
66
67
|
'common.none': 'なし',
|
|
67
68
|
'common.configured': '設定済み',
|
|
68
69
|
'common.notConfigured': '未設定',
|
|
70
|
+
'common.enabled': '有効',
|
|
71
|
+
'common.disabled': '無効',
|
|
69
72
|
'cli.missing.title': '{name} CLI がインストールされていません',
|
|
70
73
|
'cli.missing.subtitle': '{name} CLI をインストールしてからこのページをご利用ください。',
|
|
71
74
|
'cli.missing.openDocs': 'インストールガイドを開く',
|
|
@@ -126,6 +129,7 @@ const ja = Object.freeze({
|
|
|
126
129
|
'tab.config.codex': 'Codex',
|
|
127
130
|
'tab.config.claude': 'Claude',
|
|
128
131
|
'tab.config.openclaw': 'OpenClaw',
|
|
132
|
+
'tab.config.opencode': 'OpenCode',
|
|
129
133
|
'tab.sessions': 'セッション',
|
|
130
134
|
'tab.usage': '使用量',
|
|
131
135
|
'tab.orchestration': 'タスク',
|
|
@@ -167,6 +171,8 @@ const ja = Object.freeze({
|
|
|
167
171
|
'side.config.claude.meta': 'Claude Settings',
|
|
168
172
|
'side.config.openclaw': 'OpenClaw',
|
|
169
173
|
'side.config.openclaw.meta': 'JSON5 / AGENTS',
|
|
174
|
+
'side.config.opencode': 'OpenCode',
|
|
175
|
+
'side.config.opencode.meta': 'Config / Provider',
|
|
170
176
|
'side.sessions.browser': 'セッション閲覧',
|
|
171
177
|
'side.sessions.browser.meta': '閲覧 / エクスポート / クリーンアップ',
|
|
172
178
|
'side.prompts.agents': 'AGENTS.md',
|
|
@@ -794,6 +800,39 @@ const ja = Object.freeze({
|
|
|
794
800
|
'toolConfig.claude.lockedTitle': 'Claude プロバイダーは読み取り専用です',
|
|
795
801
|
'toolConfig.claude.lockedDesc': 'Claude 設定には書き込みません。追加・適用・編集・削除するには、このタブの書き込みを有効化してください。',
|
|
796
802
|
'toolConfig.claude.confirmMessage': '有効化すると、Claude タブ内の適用操作が ~/.claude/settings.json などの Claude 設定を書き込みます。',
|
|
803
|
+
'toolConfig.opencode.title': 'OpenCode 設定の書き込み',
|
|
804
|
+
'toolConfig.opencode.desc': 'デフォルトは読み取り専用。有効化すると OpenCode 設定ファイルに書き込みます。',
|
|
805
|
+
'toolConfig.opencode.lockedTitle': '読み取り専用',
|
|
806
|
+
'toolConfig.opencode.lockedDesc': '書き込み権限を有効化すると、保存・インポート・設定の適用ができます。',
|
|
807
|
+
'toolConfig.opencode.confirmMessage': '有効化すると、OpenCode タブ内の操作が XDG OpenCode 設定ファイル(例: ~/.config/opencode/opencode.jsonc)または OPENCODE_CONFIG 指定ファイルを書き込みます。',
|
|
808
|
+
'opencode.providerModel.title': 'OpenCode provider / model',
|
|
809
|
+
'opencode.writeAria': 'OpenCode 書き込み',
|
|
810
|
+
'opencode.applySelection': 'OpenCode に適用',
|
|
811
|
+
'opencode.targetFile': '有効な OpenCode 設定: {path} · {status}',
|
|
812
|
+
'opencode.providerStoreFile': 'プロバイダ下書きストア:{path}(適用時に OpenCode へ書き込み)',
|
|
813
|
+
'opencode.field.agent': 'Agent',
|
|
814
|
+
'opencode.field.apiKeyKeep': 'API Key(空なら既存 key を保持)',
|
|
815
|
+
'opencode.field.maxTokens': 'maxTokens(任意)',
|
|
816
|
+
'opencode.field.reasoningEffort': 'reasoningEffort(任意)',
|
|
817
|
+
'opencode.option.keepUnchanged': '変更しない',
|
|
818
|
+
'opencode.option.reasoningLow': 'low',
|
|
819
|
+
'opencode.option.reasoningMedium': 'medium',
|
|
820
|
+
'opencode.option.reasoningHigh': 'high',
|
|
821
|
+
'opencode.applyToCoreAgents': 'すべてのコア agent に適用',
|
|
822
|
+
'opencode.enableAutoCompaction': 'compaction.auto を有効化',
|
|
823
|
+
'opencode.disableProvider': 'この provider を無効化',
|
|
824
|
+
'opencode.configFile.title': 'OpenCode 設定ファイル',
|
|
825
|
+
'opencode.importParse': 'ファイルをインポート/解析',
|
|
826
|
+
'opencode.saveConfig': '設定を保存',
|
|
827
|
+
'opencode.parsedFile': '解析済み: {file}',
|
|
828
|
+
'opencode.textarea.placeholder': 'OpenCode 設定を編集',
|
|
829
|
+
'opencode.configFile.hint': '有効設定のプレビュー。下書きは個別のプロバイダストアに保存されます。',
|
|
830
|
+
'opencode.summary.title': '解析サマリー',
|
|
831
|
+
'opencode.summary.noApiKey': 'API Key 未設定',
|
|
832
|
+
'opencode.summary.noModel': 'model 未設定',
|
|
833
|
+
'opencode.summary.agentType': 'agent',
|
|
834
|
+
'opencode.summary.sourceCodexMate': 'CodexMate store',
|
|
835
|
+
'opencode.summary.sourceOpenCode': 'Active OpenCode',
|
|
797
836
|
'config.providerTemplate.title': 'プリセットプロバイダー',
|
|
798
837
|
'config.models': 'モデル',
|
|
799
838
|
'config.modelLoading': '読み込み中...',
|
|
@@ -1015,6 +1054,9 @@ const ja = Object.freeze({
|
|
|
1015
1054
|
'status.claudeConfig': 'Claude 設定',
|
|
1016
1055
|
'status.claudeModel': 'Claude モデル',
|
|
1017
1056
|
'status.openclawConfig': 'OpenClaw 設定',
|
|
1057
|
+
'status.opencodeProvider': 'OpenCode Provider',
|
|
1058
|
+
'status.opencodeModel': 'OpenCode モデル',
|
|
1059
|
+
'status.opencodeConfig': 'OpenCode 設定',
|
|
1018
1060
|
'status.workspaceFile': 'ワークスペースファイル',
|
|
1019
1061
|
'status.configMode': '設定モード',
|
|
1020
1062
|
'status.currentProvider': '現在の Provider',
|
|
@@ -10,6 +10,7 @@ const vi = Object.freeze({
|
|
|
10
10
|
'plugins.builtin.ruleAck.line1': 'Hãy làm theo【{{rule}}】, nhận được thì phản hồi',
|
|
11
11
|
// Global
|
|
12
12
|
'lang.zh': 'Tiếng Trung',
|
|
13
|
+
'lang.zh-tw': 'Tiếng Trung (Phồn thể)',
|
|
13
14
|
'lang.en': 'Tiếng Anh',
|
|
14
15
|
'lang.vi': 'Tiếng Việt',
|
|
15
16
|
'lang.label': 'Ngôn ngữ',
|
|
@@ -75,6 +76,8 @@ const vi = Object.freeze({
|
|
|
75
76
|
'common.none': 'Không có',
|
|
76
77
|
'common.configured': 'Đã cấu hình',
|
|
77
78
|
'common.notConfigured': 'Chưa cấu hình',
|
|
79
|
+
'common.enabled': 'Đã bật',
|
|
80
|
+
'common.disabled': 'Đã tắt',
|
|
78
81
|
'common.notSelected': 'Chưa chọn',
|
|
79
82
|
|
|
80
83
|
// Roles / labels
|
|
@@ -86,6 +89,7 @@ const vi = Object.freeze({
|
|
|
86
89
|
'tab.dashboard': 'Tổng quan',
|
|
87
90
|
'tab.docs': 'Tài liệu',
|
|
88
91
|
'tab.config': 'Cấu hình',
|
|
92
|
+
'tab.config.opencode': 'OpenCode',
|
|
89
93
|
'tab.sessions': 'Phiên',
|
|
90
94
|
'tab.usage': 'Sử dụng',
|
|
91
95
|
'tab.orchestration': 'Tác vụ',
|
|
@@ -127,6 +131,8 @@ const vi = Object.freeze({
|
|
|
127
131
|
'side.config.claude.meta': 'Cài đặt Claude',
|
|
128
132
|
'side.config.openclaw': 'OpenClaw',
|
|
129
133
|
'side.config.openclaw.meta': 'JSON5 / AGENTS',
|
|
134
|
+
'side.config.opencode': 'OpenCode',
|
|
135
|
+
'side.config.opencode.meta': 'Config / Provider',
|
|
130
136
|
'side.sessions.browser': 'Trình duyệt phiên',
|
|
131
137
|
'side.sessions.browser.meta': 'Duyệt / Xuất / Dọn dẹp',
|
|
132
138
|
'side.prompts.agents': 'AGENTS.md',
|
|
@@ -157,6 +163,39 @@ const vi = Object.freeze({
|
|
|
157
163
|
'toolConfig.claude.lockedTitle': 'Provider Claude đang chỉ đọc',
|
|
158
164
|
'toolConfig.claude.lockedDesc': 'Cấu hình Claude sẽ không bị sửa. Hãy bật ghi trong tab này để thêm, áp dụng, sửa hoặc xóa provider.',
|
|
159
165
|
'toolConfig.claude.confirmMessage': 'Sau khi bật, thao tác áp dụng trong tab Claude có thể ghi ~/.claude/settings.json và cấu hình Claude liên quan.',
|
|
166
|
+
'toolConfig.opencode.title': 'Ghi cấu hình OpenCode',
|
|
167
|
+
'toolConfig.opencode.desc': 'Mặc định chỉ đọc; bật để ghi cấu hình OpenCode.',
|
|
168
|
+
'toolConfig.opencode.lockedTitle': 'Chỉ đọc',
|
|
169
|
+
'toolConfig.opencode.lockedDesc': 'Bật quyền ghi để lưu, nhập hoặc áp dụng cấu hình.',
|
|
170
|
+
'toolConfig.opencode.confirmMessage': 'Sau khi bật, thao tác trong tab OpenCode có thể ghi file cấu hình XDG OpenCode (ví dụ ~/.config/opencode/opencode.jsonc) hoặc file do OPENCODE_CONFIG chỉ định.',
|
|
171
|
+
'opencode.providerModel.title': 'Provider / model OpenCode',
|
|
172
|
+
'opencode.writeAria': 'Quyền ghi OpenCode',
|
|
173
|
+
'opencode.applySelection': 'Áp dụng vào OpenCode',
|
|
174
|
+
'opencode.targetFile': 'Cấu hình OpenCode đang có hiệu lực: {path} · {status}',
|
|
175
|
+
'opencode.providerStoreFile': 'Kho nháp provider: {path} (ghi vào OpenCode khi áp dụng)',
|
|
176
|
+
'opencode.field.agent': 'Agent',
|
|
177
|
+
'opencode.field.apiKeyKeep': 'API Key (để trống để giữ key hiện tại)',
|
|
178
|
+
'opencode.field.maxTokens': 'maxTokens (tùy chọn)',
|
|
179
|
+
'opencode.field.reasoningEffort': 'reasoningEffort (tùy chọn)',
|
|
180
|
+
'opencode.option.keepUnchanged': 'Giữ nguyên',
|
|
181
|
+
'opencode.option.reasoningLow': 'low',
|
|
182
|
+
'opencode.option.reasoningMedium': 'medium',
|
|
183
|
+
'opencode.option.reasoningHigh': 'high',
|
|
184
|
+
'opencode.applyToCoreAgents': 'Áp dụng cho tất cả agent cốt lõi',
|
|
185
|
+
'opencode.enableAutoCompaction': 'Bật compaction.auto',
|
|
186
|
+
'opencode.disableProvider': 'Tắt provider này',
|
|
187
|
+
'opencode.configFile.title': 'File cấu hình OpenCode',
|
|
188
|
+
'opencode.importParse': 'Nhập / phân tích file',
|
|
189
|
+
'opencode.saveConfig': 'Lưu cấu hình',
|
|
190
|
+
'opencode.parsedFile': 'Đã phân tích: {file}',
|
|
191
|
+
'opencode.textarea.placeholder': 'Chỉnh sửa cấu hình OpenCode',
|
|
192
|
+
'opencode.configFile.hint': 'Xem trước cấu hình đang hoạt động; bản nháp lưu trong kho Provider riêng.',
|
|
193
|
+
'opencode.summary.title': 'Tóm tắt đã phân tích',
|
|
194
|
+
'opencode.summary.noApiKey': 'Chưa cấu hình API Key',
|
|
195
|
+
'opencode.summary.noModel': 'Chưa đặt model',
|
|
196
|
+
'opencode.summary.agentType': 'agent',
|
|
197
|
+
'opencode.summary.sourceCodexMate': 'CodexMate store',
|
|
198
|
+
'opencode.summary.sourceOpenCode': 'Active OpenCode',
|
|
160
199
|
'side.usage.meta': 'Thống kê / Xu hướng',
|
|
161
200
|
'side.orchestration.meta': 'Kế hoạch / Hàng đợi / Runs',
|
|
162
201
|
|
|
@@ -328,6 +367,10 @@ const vi = Object.freeze({
|
|
|
328
367
|
'modal.claudeDelete.confirm': 'Xóa',
|
|
329
368
|
'modal.claudeDelete.cancel': 'Hủy',
|
|
330
369
|
|
|
370
|
+
'status.opencodeProvider': 'Provider OpenCode',
|
|
371
|
+
'status.opencodeModel': 'Model OpenCode',
|
|
372
|
+
'status.opencodeConfig': 'Cấu hình OpenCode',
|
|
373
|
+
|
|
331
374
|
// Sessions
|
|
332
375
|
'sessions.preview.openLink': 'Mở liên kết',
|
|
333
376
|
|