@slkiser/opencode-quota 3.2.0 → 3.3.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 +256 -561
- package/dist/lib/anthropic.js +1 -1
- package/dist/lib/anthropic.js.map +1 -1
- package/dist/lib/config-file-utils.d.ts +12 -0
- package/dist/lib/config-file-utils.d.ts.map +1 -1
- package/dist/lib/config-file-utils.js +23 -0
- package/dist/lib/config-file-utils.js.map +1 -1
- package/dist/lib/config.d.ts +16 -3
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +434 -216
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/copilot.d.ts.map +1 -1
- package/dist/lib/copilot.js +3 -2
- package/dist/lib/copilot.js.map +1 -1
- package/dist/lib/entries.d.ts +1 -1
- package/dist/lib/entries.d.ts.map +1 -1
- package/dist/lib/format-utils.d.ts.map +1 -1
- package/dist/lib/format-utils.js +3 -2
- package/dist/lib/format-utils.js.map +1 -1
- package/dist/lib/format.d.ts.map +1 -1
- package/dist/lib/format.js +4 -2
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/google-gemini-cli-companion.d.ts +29 -0
- package/dist/lib/google-gemini-cli-companion.d.ts.map +1 -0
- package/dist/lib/google-gemini-cli-companion.js +166 -0
- package/dist/lib/google-gemini-cli-companion.js.map +1 -0
- package/dist/lib/google-gemini-cli.d.ts +48 -0
- package/dist/lib/google-gemini-cli.d.ts.map +1 -0
- package/dist/lib/google-gemini-cli.js +404 -0
- package/dist/lib/google-gemini-cli.js.map +1 -0
- package/dist/lib/opencode-go.js +1 -1
- package/dist/lib/opencode-go.js.map +1 -1
- package/dist/lib/provider-metadata.d.ts +1 -1
- package/dist/lib/provider-metadata.d.ts.map +1 -1
- package/dist/lib/provider-metadata.js +19 -0
- package/dist/lib/provider-metadata.js.map +1 -1
- package/dist/lib/quota-render-data.d.ts +2 -0
- package/dist/lib/quota-render-data.d.ts.map +1 -1
- package/dist/lib/quota-render-data.js +2 -0
- package/dist/lib/quota-render-data.js.map +1 -1
- package/dist/lib/quota-runtime-context.d.ts +43 -0
- package/dist/lib/quota-runtime-context.d.ts.map +1 -0
- package/dist/lib/quota-runtime-context.js +61 -0
- package/dist/lib/quota-runtime-context.js.map +1 -0
- package/dist/lib/quota-status.d.ts +16 -0
- package/dist/lib/quota-status.d.ts.map +1 -1
- package/dist/lib/quota-status.js +63 -17
- package/dist/lib/quota-status.js.map +1 -1
- package/dist/lib/toast-format-grouped.d.ts.map +1 -1
- package/dist/lib/toast-format-grouped.js +5 -3
- package/dist/lib/toast-format-grouped.js.map +1 -1
- package/dist/lib/tui-config-diagnostics.d.ts +7 -2
- package/dist/lib/tui-config-diagnostics.d.ts.map +1 -1
- package/dist/lib/tui-config-diagnostics.js +27 -8
- package/dist/lib/tui-config-diagnostics.js.map +1 -1
- package/dist/lib/tui-runtime.d.ts.map +1 -1
- package/dist/lib/tui-runtime.js +24 -16
- package/dist/lib/tui-runtime.js.map +1 -1
- package/dist/lib/types.d.ts +37 -6
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +419 -159
- package/dist/plugin.js.map +1 -1
- package/dist/providers/cursor.js +2 -2
- package/dist/providers/cursor.js.map +1 -1
- package/dist/providers/google-gemini-cli.d.ts +3 -0
- package/dist/providers/google-gemini-cli.d.ts.map +1 -0
- package/dist/providers/google-gemini-cli.js +83 -0
- package/dist/providers/google-gemini-cli.js.map +1 -0
- package/dist/providers/minimax-coding-plan.js +2 -2
- package/dist/providers/minimax-coding-plan.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +2 -0
- package/dist/providers/registry.js.map +1 -1
- package/package.json +2 -1
package/dist/lib/config.js
CHANGED
|
@@ -3,25 +3,62 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Precedence model:
|
|
5
5
|
* - Global/user config provides defaults.
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* - SDK config is used only as a fallback when no config files are found.
|
|
6
|
+
* - Workspace config at the resolved config root overrides ordinary settings.
|
|
7
|
+
* - SDK config is used only as a fallback when no file-backed config exists.
|
|
9
8
|
*/
|
|
10
9
|
import { DEFAULT_CONFIG } from "./types.js";
|
|
11
10
|
import { isQuotaFormatStyle, resolveQuotaFormatStyle } from "./quota-format-style.js";
|
|
12
11
|
import { parseJsonOrJsonc } from "./jsonc.js";
|
|
13
|
-
import { normalizeQuotaProviderId } from "./provider-metadata.js";
|
|
12
|
+
import { getQuotaProviderShape, normalizeQuotaProviderId } from "./provider-metadata.js";
|
|
14
13
|
import { existsSync } from "fs";
|
|
15
14
|
import { readFile } from "fs/promises";
|
|
16
15
|
import { join } from "path";
|
|
17
16
|
import { getOpencodeRuntimeDirCandidates } from "./opencode-runtime-paths.js";
|
|
17
|
+
export const QUOTA_TOAST_SETTING_SOURCE_KEYS = [
|
|
18
|
+
"enabled",
|
|
19
|
+
"enableToast",
|
|
20
|
+
"formatStyle",
|
|
21
|
+
"percentDisplayMode",
|
|
22
|
+
"minIntervalMs",
|
|
23
|
+
"debug",
|
|
24
|
+
"enabledProviders",
|
|
25
|
+
"anthropicBinaryPath",
|
|
26
|
+
"googleModels",
|
|
27
|
+
"alibabaCodingPlanTier",
|
|
28
|
+
"cursorPlan",
|
|
29
|
+
"cursorIncludedApiUsd",
|
|
30
|
+
"cursorBillingCycleStartDay",
|
|
31
|
+
"pricingSnapshot.source",
|
|
32
|
+
"pricingSnapshot.autoRefresh",
|
|
33
|
+
"showOnIdle",
|
|
34
|
+
"showOnQuestion",
|
|
35
|
+
"showOnCompact",
|
|
36
|
+
"showOnBothFail",
|
|
37
|
+
"toastDurationMs",
|
|
38
|
+
"onlyCurrentModel",
|
|
39
|
+
"showSessionTokens",
|
|
40
|
+
"layout.maxWidth",
|
|
41
|
+
"layout.narrowAt",
|
|
42
|
+
"layout.tinyAt",
|
|
43
|
+
];
|
|
18
44
|
export function createLoadConfigMeta() {
|
|
19
|
-
return {
|
|
45
|
+
return {
|
|
46
|
+
source: "defaults",
|
|
47
|
+
paths: [],
|
|
48
|
+
globalConfigPaths: [],
|
|
49
|
+
workspaceConfigPaths: [],
|
|
50
|
+
settingSources: {},
|
|
51
|
+
networkSettingSources: {},
|
|
52
|
+
configIssues: [],
|
|
53
|
+
};
|
|
20
54
|
}
|
|
21
|
-
const
|
|
55
|
+
const CONFIG_FILENAMES = ["opencode.json", "opencode.jsonc"];
|
|
56
|
+
const NETWORK_SETTING_SOURCE_KEYS = [
|
|
22
57
|
"enabled",
|
|
23
58
|
"enabledProviders",
|
|
24
59
|
"minIntervalMs",
|
|
60
|
+
"pricingSnapshot.source",
|
|
61
|
+
"pricingSnapshot.autoRefresh",
|
|
25
62
|
"showOnIdle",
|
|
26
63
|
"showOnQuestion",
|
|
27
64
|
"showOnCompact",
|
|
@@ -40,8 +77,7 @@ function isValidGoogleModelId(id) {
|
|
|
40
77
|
return typeof id === "string" && ["G3PRO", "G3FLASH", "CLAUDE", "G3IMAGE"].includes(id);
|
|
41
78
|
}
|
|
42
79
|
function isValidCursorQuotaPlan(plan) {
|
|
43
|
-
return (typeof plan === "string" &&
|
|
44
|
-
["none", "pro", "pro-plus", "ultra"].includes(plan));
|
|
80
|
+
return (typeof plan === "string" && ["none", "pro", "pro-plus", "ultra"].includes(plan));
|
|
45
81
|
}
|
|
46
82
|
function isValidPricingSnapshotSource(source) {
|
|
47
83
|
return typeof source === "string" && ["auto", "bundled", "runtime"].includes(source);
|
|
@@ -52,6 +88,15 @@ function isValidPricingSnapshotAutoRefresh(value) {
|
|
|
52
88
|
function isValidPercentDisplayMode(value) {
|
|
53
89
|
return value === "remaining" || value === "used";
|
|
54
90
|
}
|
|
91
|
+
function isValidAlibabaCodingPlanTier(value) {
|
|
92
|
+
return value === "lite" || value === "pro";
|
|
93
|
+
}
|
|
94
|
+
function isPositiveNumber(value) {
|
|
95
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
96
|
+
}
|
|
97
|
+
function isValidCursorBillingCycleStartDay(value) {
|
|
98
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 28;
|
|
99
|
+
}
|
|
55
100
|
function normalizeOptionalString(value) {
|
|
56
101
|
if (typeof value !== "string") {
|
|
57
102
|
return undefined;
|
|
@@ -78,54 +123,332 @@ function getConfiguredFormatStyle(quotaToastConfig) {
|
|
|
78
123
|
function dedupe(list) {
|
|
79
124
|
return [...new Set(list)];
|
|
80
125
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
126
|
+
function cloneDefaultConfig() {
|
|
127
|
+
return {
|
|
128
|
+
...DEFAULT_CONFIG,
|
|
129
|
+
enabledProviders: Array.isArray(DEFAULT_CONFIG.enabledProviders)
|
|
130
|
+
? [...DEFAULT_CONFIG.enabledProviders]
|
|
131
|
+
: DEFAULT_CONFIG.enabledProviders,
|
|
132
|
+
googleModels: [...DEFAULT_CONFIG.googleModels],
|
|
133
|
+
pricingSnapshot: { ...DEFAULT_CONFIG.pricingSnapshot },
|
|
134
|
+
layout: { ...DEFAULT_CONFIG.layout },
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function describeInvalidProviderValue(value) {
|
|
138
|
+
return typeof value === "string" ? value : typeof value;
|
|
139
|
+
}
|
|
140
|
+
function normalizeEnabledProviders(value) {
|
|
141
|
+
if (value === "auto") {
|
|
142
|
+
return { value: "auto", issues: [] };
|
|
143
|
+
}
|
|
144
|
+
if (!Array.isArray(value)) {
|
|
145
|
+
return {
|
|
146
|
+
value: [],
|
|
147
|
+
issues: ["expected \"auto\" or an array of provider ids"],
|
|
148
|
+
invalidEmpty: true,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (value.length === 0) {
|
|
152
|
+
return { value: [], issues: [] };
|
|
153
|
+
}
|
|
154
|
+
const validProviders = [];
|
|
155
|
+
const invalidProviders = [];
|
|
156
|
+
for (const provider of value) {
|
|
157
|
+
if (typeof provider !== "string") {
|
|
158
|
+
invalidProviders.push(describeInvalidProviderValue(provider));
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const normalized = normalizeQuotaProviderId(provider);
|
|
162
|
+
if (normalized && getQuotaProviderShape(normalized)) {
|
|
163
|
+
validProviders.push(normalized);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
invalidProviders.push(provider);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const issues = invalidProviders.length
|
|
170
|
+
? [`unknown provider id(s): ${dedupe(invalidProviders).join(", ")}`]
|
|
171
|
+
: [];
|
|
172
|
+
const normalizedProviders = dedupe(validProviders);
|
|
173
|
+
return {
|
|
174
|
+
value: normalizedProviders,
|
|
175
|
+
issues,
|
|
176
|
+
invalidEmpty: normalizedProviders.length === 0 && invalidProviders.length > 0,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function normalizeGoogleModels(value) {
|
|
180
|
+
if (!Array.isArray(value)) {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
const models = value.filter(isValidGoogleModelId);
|
|
184
|
+
return models.length > 0 ? models : undefined;
|
|
185
|
+
}
|
|
186
|
+
function extractPricingSnapshotPatch(value) {
|
|
187
|
+
if (!isPlainObject(value)) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
const patch = {};
|
|
191
|
+
if (hasOwnKey(value, "source") && isValidPricingSnapshotSource(value.source)) {
|
|
192
|
+
patch.source = value.source;
|
|
193
|
+
}
|
|
194
|
+
if (hasOwnKey(value, "autoRefresh") && isValidPricingSnapshotAutoRefresh(value.autoRefresh)) {
|
|
195
|
+
patch.autoRefresh = value.autoRefresh;
|
|
196
|
+
}
|
|
197
|
+
return Object.keys(patch).length > 0 ? patch : undefined;
|
|
198
|
+
}
|
|
199
|
+
function extractLayoutPatch(value) {
|
|
200
|
+
if (!isPlainObject(value)) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
const patch = {};
|
|
204
|
+
if (hasOwnKey(value, "maxWidth") && isPositiveNumber(value.maxWidth)) {
|
|
205
|
+
patch.maxWidth = value.maxWidth;
|
|
206
|
+
}
|
|
207
|
+
if (hasOwnKey(value, "narrowAt") && isPositiveNumber(value.narrowAt)) {
|
|
208
|
+
patch.narrowAt = value.narrowAt;
|
|
209
|
+
}
|
|
210
|
+
if (hasOwnKey(value, "tinyAt") && isPositiveNumber(value.tinyAt)) {
|
|
211
|
+
patch.tinyAt = value.tinyAt;
|
|
212
|
+
}
|
|
213
|
+
return Object.keys(patch).length > 0 ? patch : undefined;
|
|
214
|
+
}
|
|
215
|
+
function extractValidatedQuotaToastPatch(quotaToastConfig, reportIssue) {
|
|
216
|
+
const patch = {};
|
|
217
|
+
if (hasOwnKey(quotaToastConfig, "enabled") && typeof quotaToastConfig.enabled === "boolean") {
|
|
218
|
+
patch.enabled = quotaToastConfig.enabled;
|
|
219
|
+
}
|
|
220
|
+
if (hasOwnKey(quotaToastConfig, "enableToast") &&
|
|
221
|
+
typeof quotaToastConfig.enableToast === "boolean") {
|
|
222
|
+
patch.enableToast = quotaToastConfig.enableToast;
|
|
223
|
+
}
|
|
224
|
+
const formatStyle = getConfiguredFormatStyle(quotaToastConfig);
|
|
225
|
+
if (formatStyle) {
|
|
226
|
+
patch.formatStyle = formatStyle;
|
|
227
|
+
}
|
|
228
|
+
if (hasOwnKey(quotaToastConfig, "percentDisplayMode") &&
|
|
229
|
+
isValidPercentDisplayMode(quotaToastConfig.percentDisplayMode)) {
|
|
230
|
+
patch.percentDisplayMode = quotaToastConfig.percentDisplayMode;
|
|
231
|
+
}
|
|
232
|
+
if (hasOwnKey(quotaToastConfig, "minIntervalMs") && isPositiveNumber(quotaToastConfig.minIntervalMs)) {
|
|
233
|
+
patch.minIntervalMs = quotaToastConfig.minIntervalMs;
|
|
234
|
+
}
|
|
235
|
+
if (hasOwnKey(quotaToastConfig, "debug") && typeof quotaToastConfig.debug === "boolean") {
|
|
236
|
+
patch.debug = quotaToastConfig.debug;
|
|
237
|
+
}
|
|
238
|
+
if (hasOwnKey(quotaToastConfig, "enabledProviders")) {
|
|
239
|
+
const enabledProviders = normalizeEnabledProviders(quotaToastConfig.enabledProviders);
|
|
240
|
+
for (const issue of enabledProviders.issues) {
|
|
241
|
+
reportIssue?.("enabledProviders", issue);
|
|
242
|
+
}
|
|
243
|
+
if (enabledProviders.value !== undefined) {
|
|
244
|
+
patch.enabledProviders = enabledProviders.value;
|
|
245
|
+
if (enabledProviders.invalidEmpty) {
|
|
246
|
+
patch.enabledProvidersInvalidEmpty = true;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (hasOwnKey(quotaToastConfig, "anthropicBinaryPath")) {
|
|
251
|
+
const anthropicBinaryPath = normalizeOptionalString(quotaToastConfig.anthropicBinaryPath);
|
|
252
|
+
if (anthropicBinaryPath !== undefined) {
|
|
253
|
+
patch.anthropicBinaryPath = anthropicBinaryPath;
|
|
97
254
|
}
|
|
98
|
-
|
|
99
|
-
|
|
255
|
+
}
|
|
256
|
+
if (hasOwnKey(quotaToastConfig, "googleModels")) {
|
|
257
|
+
const googleModels = normalizeGoogleModels(quotaToastConfig.googleModels);
|
|
258
|
+
if (googleModels !== undefined) {
|
|
259
|
+
patch.googleModels = googleModels;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (hasOwnKey(quotaToastConfig, "alibabaCodingPlanTier") &&
|
|
263
|
+
isValidAlibabaCodingPlanTier(quotaToastConfig.alibabaCodingPlanTier)) {
|
|
264
|
+
patch.alibabaCodingPlanTier = quotaToastConfig.alibabaCodingPlanTier;
|
|
265
|
+
}
|
|
266
|
+
if (hasOwnKey(quotaToastConfig, "cursorPlan") && isValidCursorQuotaPlan(quotaToastConfig.cursorPlan)) {
|
|
267
|
+
patch.cursorPlan = quotaToastConfig.cursorPlan;
|
|
268
|
+
}
|
|
269
|
+
if (hasOwnKey(quotaToastConfig, "cursorIncludedApiUsd") &&
|
|
270
|
+
isPositiveNumber(quotaToastConfig.cursorIncludedApiUsd)) {
|
|
271
|
+
patch.cursorIncludedApiUsd = quotaToastConfig.cursorIncludedApiUsd;
|
|
272
|
+
}
|
|
273
|
+
if (hasOwnKey(quotaToastConfig, "cursorBillingCycleStartDay") &&
|
|
274
|
+
isValidCursorBillingCycleStartDay(quotaToastConfig.cursorBillingCycleStartDay)) {
|
|
275
|
+
patch.cursorBillingCycleStartDay = quotaToastConfig.cursorBillingCycleStartDay;
|
|
276
|
+
}
|
|
277
|
+
if (hasOwnKey(quotaToastConfig, "pricingSnapshot")) {
|
|
278
|
+
const pricingSnapshot = extractPricingSnapshotPatch(quotaToastConfig.pricingSnapshot);
|
|
279
|
+
if (pricingSnapshot) {
|
|
280
|
+
patch.pricingSnapshot = pricingSnapshot;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (hasOwnKey(quotaToastConfig, "showOnIdle") && typeof quotaToastConfig.showOnIdle === "boolean") {
|
|
284
|
+
patch.showOnIdle = quotaToastConfig.showOnIdle;
|
|
285
|
+
}
|
|
286
|
+
if (hasOwnKey(quotaToastConfig, "showOnQuestion") &&
|
|
287
|
+
typeof quotaToastConfig.showOnQuestion === "boolean") {
|
|
288
|
+
patch.showOnQuestion = quotaToastConfig.showOnQuestion;
|
|
289
|
+
}
|
|
290
|
+
if (hasOwnKey(quotaToastConfig, "showOnCompact") &&
|
|
291
|
+
typeof quotaToastConfig.showOnCompact === "boolean") {
|
|
292
|
+
patch.showOnCompact = quotaToastConfig.showOnCompact;
|
|
293
|
+
}
|
|
294
|
+
if (hasOwnKey(quotaToastConfig, "showOnBothFail") &&
|
|
295
|
+
typeof quotaToastConfig.showOnBothFail === "boolean") {
|
|
296
|
+
patch.showOnBothFail = quotaToastConfig.showOnBothFail;
|
|
297
|
+
}
|
|
298
|
+
if (hasOwnKey(quotaToastConfig, "toastDurationMs") &&
|
|
299
|
+
isPositiveNumber(quotaToastConfig.toastDurationMs)) {
|
|
300
|
+
patch.toastDurationMs = quotaToastConfig.toastDurationMs;
|
|
301
|
+
}
|
|
302
|
+
if (hasOwnKey(quotaToastConfig, "onlyCurrentModel") &&
|
|
303
|
+
typeof quotaToastConfig.onlyCurrentModel === "boolean") {
|
|
304
|
+
patch.onlyCurrentModel = quotaToastConfig.onlyCurrentModel;
|
|
305
|
+
}
|
|
306
|
+
if (hasOwnKey(quotaToastConfig, "showSessionTokens") &&
|
|
307
|
+
typeof quotaToastConfig.showSessionTokens === "boolean") {
|
|
308
|
+
patch.showSessionTokens = quotaToastConfig.showSessionTokens;
|
|
309
|
+
}
|
|
310
|
+
if (hasOwnKey(quotaToastConfig, "layout")) {
|
|
311
|
+
const layout = extractLayoutPatch(quotaToastConfig.layout);
|
|
312
|
+
if (layout) {
|
|
313
|
+
patch.layout = layout;
|
|
100
314
|
}
|
|
101
315
|
}
|
|
102
|
-
return
|
|
316
|
+
return patch;
|
|
103
317
|
}
|
|
104
|
-
function
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
318
|
+
function applySettingSource(settingSources, key, sourcePath) {
|
|
319
|
+
settingSources[key] = sourcePath;
|
|
320
|
+
}
|
|
321
|
+
function applyValidatedQuotaToastPatch(config, patch, sourcePath, settingSources) {
|
|
322
|
+
if (hasOwnKey(patch, "enabled")) {
|
|
323
|
+
config.enabled = patch.enabled;
|
|
324
|
+
applySettingSource(settingSources, "enabled", sourcePath);
|
|
325
|
+
}
|
|
326
|
+
if (hasOwnKey(patch, "enableToast")) {
|
|
327
|
+
config.enableToast = patch.enableToast;
|
|
328
|
+
applySettingSource(settingSources, "enableToast", sourcePath);
|
|
329
|
+
}
|
|
330
|
+
if (hasOwnKey(patch, "formatStyle")) {
|
|
331
|
+
config.formatStyle = patch.formatStyle;
|
|
332
|
+
applySettingSource(settingSources, "formatStyle", sourcePath);
|
|
333
|
+
}
|
|
334
|
+
if (hasOwnKey(patch, "percentDisplayMode")) {
|
|
335
|
+
config.percentDisplayMode = patch.percentDisplayMode;
|
|
336
|
+
applySettingSource(settingSources, "percentDisplayMode", sourcePath);
|
|
337
|
+
}
|
|
338
|
+
if (hasOwnKey(patch, "minIntervalMs")) {
|
|
339
|
+
config.minIntervalMs = patch.minIntervalMs;
|
|
340
|
+
applySettingSource(settingSources, "minIntervalMs", sourcePath);
|
|
341
|
+
}
|
|
342
|
+
if (hasOwnKey(patch, "debug")) {
|
|
343
|
+
config.debug = patch.debug;
|
|
344
|
+
applySettingSource(settingSources, "debug", sourcePath);
|
|
345
|
+
}
|
|
346
|
+
if (hasOwnKey(patch, "enabledProviders")) {
|
|
347
|
+
if (!(patch.enabledProvidersInvalidEmpty && settingSources.enabledProviders)) {
|
|
348
|
+
config.enabledProviders =
|
|
349
|
+
patch.enabledProviders === "auto" ? "auto" : [...patch.enabledProviders];
|
|
350
|
+
applySettingSource(settingSources, "enabledProviders", sourcePath);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (hasOwnKey(patch, "anthropicBinaryPath")) {
|
|
354
|
+
config.anthropicBinaryPath = patch.anthropicBinaryPath;
|
|
355
|
+
applySettingSource(settingSources, "anthropicBinaryPath", sourcePath);
|
|
356
|
+
}
|
|
357
|
+
if (hasOwnKey(patch, "googleModels")) {
|
|
358
|
+
config.googleModels = [...patch.googleModels];
|
|
359
|
+
applySettingSource(settingSources, "googleModels", sourcePath);
|
|
360
|
+
}
|
|
361
|
+
if (hasOwnKey(patch, "alibabaCodingPlanTier")) {
|
|
362
|
+
config.alibabaCodingPlanTier = patch.alibabaCodingPlanTier;
|
|
363
|
+
applySettingSource(settingSources, "alibabaCodingPlanTier", sourcePath);
|
|
364
|
+
}
|
|
365
|
+
if (hasOwnKey(patch, "cursorPlan")) {
|
|
366
|
+
config.cursorPlan = patch.cursorPlan;
|
|
367
|
+
applySettingSource(settingSources, "cursorPlan", sourcePath);
|
|
368
|
+
}
|
|
369
|
+
if (hasOwnKey(patch, "cursorIncludedApiUsd")) {
|
|
370
|
+
config.cursorIncludedApiUsd = patch.cursorIncludedApiUsd;
|
|
371
|
+
applySettingSource(settingSources, "cursorIncludedApiUsd", sourcePath);
|
|
372
|
+
}
|
|
373
|
+
if (hasOwnKey(patch, "cursorBillingCycleStartDay")) {
|
|
374
|
+
config.cursorBillingCycleStartDay = patch.cursorBillingCycleStartDay;
|
|
375
|
+
applySettingSource(settingSources, "cursorBillingCycleStartDay", sourcePath);
|
|
376
|
+
}
|
|
377
|
+
if (patch.pricingSnapshot) {
|
|
378
|
+
if (hasOwnKey(patch.pricingSnapshot, "source")) {
|
|
379
|
+
config.pricingSnapshot.source = patch.pricingSnapshot.source;
|
|
380
|
+
applySettingSource(settingSources, "pricingSnapshot.source", sourcePath);
|
|
381
|
+
}
|
|
382
|
+
if (hasOwnKey(patch.pricingSnapshot, "autoRefresh")) {
|
|
383
|
+
config.pricingSnapshot.autoRefresh = patch.pricingSnapshot.autoRefresh;
|
|
384
|
+
applySettingSource(settingSources, "pricingSnapshot.autoRefresh", sourcePath);
|
|
116
385
|
}
|
|
117
386
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
387
|
+
if (hasOwnKey(patch, "showOnIdle")) {
|
|
388
|
+
config.showOnIdle = patch.showOnIdle;
|
|
389
|
+
applySettingSource(settingSources, "showOnIdle", sourcePath);
|
|
390
|
+
}
|
|
391
|
+
if (hasOwnKey(patch, "showOnQuestion")) {
|
|
392
|
+
config.showOnQuestion = patch.showOnQuestion;
|
|
393
|
+
applySettingSource(settingSources, "showOnQuestion", sourcePath);
|
|
394
|
+
}
|
|
395
|
+
if (hasOwnKey(patch, "showOnCompact")) {
|
|
396
|
+
config.showOnCompact = patch.showOnCompact;
|
|
397
|
+
applySettingSource(settingSources, "showOnCompact", sourcePath);
|
|
398
|
+
}
|
|
399
|
+
if (hasOwnKey(patch, "showOnBothFail")) {
|
|
400
|
+
config.showOnBothFail = patch.showOnBothFail;
|
|
401
|
+
applySettingSource(settingSources, "showOnBothFail", sourcePath);
|
|
402
|
+
}
|
|
403
|
+
if (hasOwnKey(patch, "toastDurationMs")) {
|
|
404
|
+
config.toastDurationMs = patch.toastDurationMs;
|
|
405
|
+
applySettingSource(settingSources, "toastDurationMs", sourcePath);
|
|
406
|
+
}
|
|
407
|
+
if (hasOwnKey(patch, "onlyCurrentModel")) {
|
|
408
|
+
config.onlyCurrentModel = patch.onlyCurrentModel;
|
|
409
|
+
applySettingSource(settingSources, "onlyCurrentModel", sourcePath);
|
|
410
|
+
}
|
|
411
|
+
if (hasOwnKey(patch, "showSessionTokens")) {
|
|
412
|
+
config.showSessionTokens = patch.showSessionTokens;
|
|
413
|
+
applySettingSource(settingSources, "showSessionTokens", sourcePath);
|
|
414
|
+
}
|
|
415
|
+
if (patch.layout) {
|
|
416
|
+
if (hasOwnKey(patch.layout, "maxWidth")) {
|
|
417
|
+
config.layout.maxWidth = patch.layout.maxWidth;
|
|
418
|
+
applySettingSource(settingSources, "layout.maxWidth", sourcePath);
|
|
419
|
+
}
|
|
420
|
+
if (hasOwnKey(patch.layout, "narrowAt")) {
|
|
421
|
+
config.layout.narrowAt = patch.layout.narrowAt;
|
|
422
|
+
applySettingSource(settingSources, "layout.narrowAt", sourcePath);
|
|
123
423
|
}
|
|
124
|
-
if ("
|
|
125
|
-
|
|
424
|
+
if (hasOwnKey(patch.layout, "tinyAt")) {
|
|
425
|
+
config.layout.tinyAt = patch.layout.tinyAt;
|
|
426
|
+
applySettingSource(settingSources, "layout.tinyAt", sourcePath);
|
|
126
427
|
}
|
|
127
428
|
}
|
|
128
429
|
}
|
|
430
|
+
function projectNetworkSettingSources(settingSources) {
|
|
431
|
+
const projected = {};
|
|
432
|
+
for (const key of NETWORK_SETTING_SOURCE_KEYS) {
|
|
433
|
+
const source = settingSources[key];
|
|
434
|
+
if (typeof source === "string" && source.length > 0) {
|
|
435
|
+
projected[key] = source;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return projected;
|
|
439
|
+
}
|
|
440
|
+
function buildConfigLayerCandidates(configDirs, configRootDir) {
|
|
441
|
+
const workspaceCandidates = CONFIG_FILENAMES.map((filename) => ({
|
|
442
|
+
path: join(configRootDir, filename),
|
|
443
|
+
scope: "workspace",
|
|
444
|
+
}));
|
|
445
|
+
const workspacePaths = new Set(workspaceCandidates.map((candidate) => candidate.path));
|
|
446
|
+
const globalCandidates = configDirs.flatMap((dir) => CONFIG_FILENAMES.map((filename) => ({ path: join(dir, filename), scope: "global" })));
|
|
447
|
+
return [
|
|
448
|
+
...globalCandidates.filter((candidate) => !workspacePaths.has(candidate.path)),
|
|
449
|
+
...workspaceCandidates,
|
|
450
|
+
];
|
|
451
|
+
}
|
|
129
452
|
/**
|
|
130
453
|
* Load plugin configuration from OpenCode config
|
|
131
454
|
*
|
|
@@ -133,106 +456,6 @@ function recordNetworkSettingSource(sources, quotaToast, sourcePath) {
|
|
|
133
456
|
* @returns Merged configuration with defaults
|
|
134
457
|
*/
|
|
135
458
|
export async function loadConfig(client, meta, options) {
|
|
136
|
-
function normalize(quotaToastConfig) {
|
|
137
|
-
if (!quotaToastConfig)
|
|
138
|
-
return DEFAULT_CONFIG;
|
|
139
|
-
const formatStyle = getConfiguredFormatStyle(quotaToastConfig) ?? DEFAULT_CONFIG.formatStyle;
|
|
140
|
-
const config = {
|
|
141
|
-
enabled: typeof quotaToastConfig.enabled === "boolean"
|
|
142
|
-
? quotaToastConfig.enabled
|
|
143
|
-
: DEFAULT_CONFIG.enabled,
|
|
144
|
-
enableToast: typeof quotaToastConfig.enableToast === "boolean"
|
|
145
|
-
? quotaToastConfig.enableToast
|
|
146
|
-
: DEFAULT_CONFIG.enableToast,
|
|
147
|
-
formatStyle,
|
|
148
|
-
percentDisplayMode: isValidPercentDisplayMode(quotaToastConfig.percentDisplayMode)
|
|
149
|
-
? quotaToastConfig.percentDisplayMode
|
|
150
|
-
: DEFAULT_CONFIG.percentDisplayMode,
|
|
151
|
-
minIntervalMs: typeof quotaToastConfig.minIntervalMs === "number" && quotaToastConfig.minIntervalMs > 0
|
|
152
|
-
? quotaToastConfig.minIntervalMs
|
|
153
|
-
: DEFAULT_CONFIG.minIntervalMs,
|
|
154
|
-
debug: typeof quotaToastConfig.debug === "boolean" ? quotaToastConfig.debug : DEFAULT_CONFIG.debug,
|
|
155
|
-
enabledProviders: quotaToastConfig.enabledProviders === "auto"
|
|
156
|
-
? "auto"
|
|
157
|
-
: Array.isArray(quotaToastConfig.enabledProviders)
|
|
158
|
-
? dedupe(quotaToastConfig.enabledProviders
|
|
159
|
-
.filter((p) => typeof p === "string")
|
|
160
|
-
.map(normalizeQuotaProviderId)
|
|
161
|
-
.filter(Boolean))
|
|
162
|
-
: DEFAULT_CONFIG.enabledProviders,
|
|
163
|
-
anthropicBinaryPath: normalizeOptionalString(quotaToastConfig.anthropicBinaryPath) ??
|
|
164
|
-
DEFAULT_CONFIG.anthropicBinaryPath,
|
|
165
|
-
googleModels: Array.isArray(quotaToastConfig.googleModels)
|
|
166
|
-
? quotaToastConfig.googleModels.filter(isValidGoogleModelId)
|
|
167
|
-
: DEFAULT_CONFIG.googleModels,
|
|
168
|
-
alibabaCodingPlanTier: quotaToastConfig.alibabaCodingPlanTier === "lite" ||
|
|
169
|
-
quotaToastConfig.alibabaCodingPlanTier === "pro"
|
|
170
|
-
? quotaToastConfig.alibabaCodingPlanTier
|
|
171
|
-
: DEFAULT_CONFIG.alibabaCodingPlanTier,
|
|
172
|
-
cursorPlan: isValidCursorQuotaPlan(quotaToastConfig.cursorPlan)
|
|
173
|
-
? quotaToastConfig.cursorPlan
|
|
174
|
-
: DEFAULT_CONFIG.cursorPlan,
|
|
175
|
-
cursorIncludedApiUsd: typeof quotaToastConfig.cursorIncludedApiUsd === "number" &&
|
|
176
|
-
Number.isFinite(quotaToastConfig.cursorIncludedApiUsd) &&
|
|
177
|
-
quotaToastConfig.cursorIncludedApiUsd > 0
|
|
178
|
-
? quotaToastConfig.cursorIncludedApiUsd
|
|
179
|
-
: undefined,
|
|
180
|
-
cursorBillingCycleStartDay: typeof quotaToastConfig.cursorBillingCycleStartDay === "number" &&
|
|
181
|
-
Number.isInteger(quotaToastConfig.cursorBillingCycleStartDay) &&
|
|
182
|
-
quotaToastConfig.cursorBillingCycleStartDay >= 1 &&
|
|
183
|
-
quotaToastConfig.cursorBillingCycleStartDay <= 28
|
|
184
|
-
? quotaToastConfig.cursorBillingCycleStartDay
|
|
185
|
-
: undefined,
|
|
186
|
-
pricingSnapshot: {
|
|
187
|
-
source: isValidPricingSnapshotSource(quotaToastConfig.pricingSnapshot?.source)
|
|
188
|
-
? quotaToastConfig.pricingSnapshot.source
|
|
189
|
-
: DEFAULT_CONFIG.pricingSnapshot.source,
|
|
190
|
-
autoRefresh: isValidPricingSnapshotAutoRefresh(quotaToastConfig.pricingSnapshot?.autoRefresh)
|
|
191
|
-
? quotaToastConfig.pricingSnapshot.autoRefresh
|
|
192
|
-
: DEFAULT_CONFIG.pricingSnapshot.autoRefresh,
|
|
193
|
-
},
|
|
194
|
-
showOnIdle: typeof quotaToastConfig.showOnIdle === "boolean"
|
|
195
|
-
? quotaToastConfig.showOnIdle
|
|
196
|
-
: DEFAULT_CONFIG.showOnIdle,
|
|
197
|
-
showOnQuestion: typeof quotaToastConfig.showOnQuestion === "boolean"
|
|
198
|
-
? quotaToastConfig.showOnQuestion
|
|
199
|
-
: DEFAULT_CONFIG.showOnQuestion,
|
|
200
|
-
showOnCompact: typeof quotaToastConfig.showOnCompact === "boolean"
|
|
201
|
-
? quotaToastConfig.showOnCompact
|
|
202
|
-
: DEFAULT_CONFIG.showOnCompact,
|
|
203
|
-
showOnBothFail: typeof quotaToastConfig.showOnBothFail === "boolean"
|
|
204
|
-
? quotaToastConfig.showOnBothFail
|
|
205
|
-
: DEFAULT_CONFIG.showOnBothFail,
|
|
206
|
-
toastDurationMs: typeof quotaToastConfig.toastDurationMs === "number" && quotaToastConfig.toastDurationMs > 0
|
|
207
|
-
? quotaToastConfig.toastDurationMs
|
|
208
|
-
: DEFAULT_CONFIG.toastDurationMs,
|
|
209
|
-
onlyCurrentModel: typeof quotaToastConfig.onlyCurrentModel === "boolean"
|
|
210
|
-
? quotaToastConfig.onlyCurrentModel
|
|
211
|
-
: DEFAULT_CONFIG.onlyCurrentModel,
|
|
212
|
-
showSessionTokens: typeof quotaToastConfig.showSessionTokens === "boolean"
|
|
213
|
-
? quotaToastConfig.showSessionTokens
|
|
214
|
-
: DEFAULT_CONFIG.showSessionTokens,
|
|
215
|
-
layout: {
|
|
216
|
-
maxWidth: typeof quotaToastConfig.layout?.maxWidth === "number" &&
|
|
217
|
-
quotaToastConfig.layout.maxWidth > 0
|
|
218
|
-
? quotaToastConfig.layout.maxWidth
|
|
219
|
-
: DEFAULT_CONFIG.layout.maxWidth,
|
|
220
|
-
narrowAt: typeof quotaToastConfig.layout?.narrowAt === "number" &&
|
|
221
|
-
quotaToastConfig.layout.narrowAt > 0
|
|
222
|
-
? quotaToastConfig.layout.narrowAt
|
|
223
|
-
: DEFAULT_CONFIG.layout.narrowAt,
|
|
224
|
-
tinyAt: typeof quotaToastConfig.layout?.tinyAt === "number" && quotaToastConfig.layout.tinyAt > 0
|
|
225
|
-
? quotaToastConfig.layout.tinyAt
|
|
226
|
-
: DEFAULT_CONFIG.layout.tinyAt,
|
|
227
|
-
},
|
|
228
|
-
};
|
|
229
|
-
// enabledProviders: "auto" means auto-detect; explicit array means user-specified.
|
|
230
|
-
// Ensure at least one Google model is configured
|
|
231
|
-
if (config.googleModels.length === 0) {
|
|
232
|
-
config.googleModels = DEFAULT_CONFIG.googleModels;
|
|
233
|
-
}
|
|
234
|
-
return config;
|
|
235
|
-
}
|
|
236
459
|
async function readJson(path) {
|
|
237
460
|
try {
|
|
238
461
|
const content = await readFile(path, "utf-8");
|
|
@@ -242,80 +465,58 @@ export async function loadConfig(client, meta, options) {
|
|
|
242
465
|
return null;
|
|
243
466
|
}
|
|
244
467
|
}
|
|
245
|
-
async function loadQuotaToastFromLocations(locations) {
|
|
246
|
-
const quota = {};
|
|
247
|
-
const usedPaths = [];
|
|
248
|
-
const networkSettingSources = {};
|
|
249
|
-
for (const dir of locations) {
|
|
250
|
-
for (const filename of ["opencode.json", "opencode.jsonc"]) {
|
|
251
|
-
const p = join(dir, filename);
|
|
252
|
-
if (!existsSync(p))
|
|
253
|
-
continue;
|
|
254
|
-
const parsed = await readJson(p);
|
|
255
|
-
if (!parsed || typeof parsed !== "object")
|
|
256
|
-
continue;
|
|
257
|
-
const root = parsed;
|
|
258
|
-
const rawQuotaToast = root?.experimental?.quotaToast;
|
|
259
|
-
if (!rawQuotaToast || typeof rawQuotaToast !== "object")
|
|
260
|
-
continue;
|
|
261
|
-
Object.assign(quota, rawQuotaToast);
|
|
262
|
-
const sourcePath = `${p} (experimental.quotaToast)`;
|
|
263
|
-
usedPaths.push(sourcePath);
|
|
264
|
-
recordNetworkSettingSource(networkSettingSources, rawQuotaToast, sourcePath);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return { quota, usedPaths, networkSettingSources };
|
|
268
|
-
}
|
|
269
468
|
async function loadFromFiles() {
|
|
270
|
-
const
|
|
469
|
+
const configRootDir = options?.configRootDir ?? options?.cwd ?? process.cwd();
|
|
271
470
|
const { configDirs } = getOpencodeRuntimeDirCandidates();
|
|
272
|
-
const
|
|
273
|
-
const
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
const quota = {
|
|
283
|
-
...globalConfig.quota,
|
|
284
|
-
...localConfig.quota,
|
|
285
|
-
};
|
|
286
|
-
for (const key of NETWORK_AFFECTING_KEYS) {
|
|
287
|
-
if (hasOwnKey(globalConfig.quota, key)) {
|
|
288
|
-
quota[key] = globalConfig.quota[key];
|
|
471
|
+
const config = cloneDefaultConfig();
|
|
472
|
+
const usedPaths = [];
|
|
473
|
+
const globalConfigPaths = [];
|
|
474
|
+
const workspaceConfigPaths = [];
|
|
475
|
+
const settingSources = {};
|
|
476
|
+
const configIssues = [];
|
|
477
|
+
for (const candidate of buildConfigLayerCandidates(configDirs, configRootDir)) {
|
|
478
|
+
if (!existsSync(candidate.path)) {
|
|
479
|
+
continue;
|
|
289
480
|
}
|
|
290
|
-
|
|
291
|
-
|
|
481
|
+
const parsed = await readJson(candidate.path);
|
|
482
|
+
if (!isPlainObject(parsed) || !isPlainObject(parsed.experimental)) {
|
|
483
|
+
continue;
|
|
292
484
|
}
|
|
485
|
+
const rawQuotaToast = parsed.experimental.quotaToast;
|
|
486
|
+
if (!isPlainObject(rawQuotaToast)) {
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
const sourcePath = `${candidate.path} (experimental.quotaToast)`;
|
|
490
|
+
usedPaths.push(sourcePath);
|
|
491
|
+
if (candidate.scope === "global") {
|
|
492
|
+
globalConfigPaths.push(sourcePath);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
workspaceConfigPaths.push(sourcePath);
|
|
496
|
+
}
|
|
497
|
+
applyValidatedQuotaToastPatch(config, extractValidatedQuotaToastPatch(rawQuotaToast, (key, message) => {
|
|
498
|
+
configIssues.push({ path: sourcePath, key, message });
|
|
499
|
+
}), sourcePath, settingSources);
|
|
293
500
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (hasMergedPricingSnapshot) {
|
|
305
|
-
quota.pricingSnapshot = mergedPricingSnapshot;
|
|
306
|
-
}
|
|
307
|
-
const localFormatStyle = getConfiguredFormatStyle(localConfig.quota);
|
|
308
|
-
const globalFormatStyle = getConfiguredFormatStyle(globalConfig.quota);
|
|
309
|
-
if (localFormatStyle) {
|
|
310
|
-
quota.formatStyle = localFormatStyle;
|
|
311
|
-
}
|
|
312
|
-
else if (globalFormatStyle) {
|
|
313
|
-
quota.formatStyle = globalFormatStyle;
|
|
501
|
+
if (usedPaths.length === 0) {
|
|
502
|
+
return {
|
|
503
|
+
config: null,
|
|
504
|
+
usedPaths: [],
|
|
505
|
+
globalConfigPaths: [],
|
|
506
|
+
workspaceConfigPaths: [],
|
|
507
|
+
settingSources: {},
|
|
508
|
+
networkSettingSources: {},
|
|
509
|
+
configIssues: [],
|
|
510
|
+
};
|
|
314
511
|
}
|
|
315
512
|
return {
|
|
316
|
-
config
|
|
513
|
+
config,
|
|
317
514
|
usedPaths,
|
|
318
|
-
|
|
515
|
+
globalConfigPaths,
|
|
516
|
+
workspaceConfigPaths,
|
|
517
|
+
settingSources,
|
|
518
|
+
networkSettingSources: projectNetworkSettingSources(settingSources),
|
|
519
|
+
configIssues,
|
|
319
520
|
};
|
|
320
521
|
}
|
|
321
522
|
const fileConfig = await loadFromFiles();
|
|
@@ -323,7 +524,11 @@ export async function loadConfig(client, meta, options) {
|
|
|
323
524
|
if (meta) {
|
|
324
525
|
meta.source = "files";
|
|
325
526
|
meta.paths = fileConfig.usedPaths;
|
|
527
|
+
meta.globalConfigPaths = fileConfig.globalConfigPaths;
|
|
528
|
+
meta.workspaceConfigPaths = fileConfig.workspaceConfigPaths;
|
|
529
|
+
meta.settingSources = fileConfig.settingSources;
|
|
326
530
|
meta.networkSettingSources = fileConfig.networkSettingSources;
|
|
531
|
+
meta.configIssues = fileConfig.configIssues;
|
|
327
532
|
}
|
|
328
533
|
return fileConfig.config;
|
|
329
534
|
}
|
|
@@ -333,14 +538,23 @@ export async function loadConfig(client, meta, options) {
|
|
|
333
538
|
// OpenCode config schema is strict; plugin-specific config must live under
|
|
334
539
|
// experimental.* to avoid "unrecognized key" validation errors.
|
|
335
540
|
const quotaToastConfig = response.data?.experimental?.quotaToast;
|
|
336
|
-
if (quotaToastConfig
|
|
541
|
+
if (isPlainObject(quotaToastConfig)) {
|
|
542
|
+
const config = cloneDefaultConfig();
|
|
543
|
+
const settingSources = {};
|
|
544
|
+
const configIssues = [];
|
|
545
|
+
applyValidatedQuotaToastPatch(config, extractValidatedQuotaToastPatch(quotaToastConfig, (key, message) => {
|
|
546
|
+
configIssues.push({ path: "client.config.get", key, message });
|
|
547
|
+
}), "client.config.get", settingSources);
|
|
337
548
|
if (meta) {
|
|
338
549
|
meta.source = "sdk";
|
|
339
550
|
meta.paths = ["client.config.get"];
|
|
340
|
-
meta.
|
|
341
|
-
|
|
551
|
+
meta.globalConfigPaths = [];
|
|
552
|
+
meta.workspaceConfigPaths = [];
|
|
553
|
+
meta.settingSources = settingSources;
|
|
554
|
+
meta.networkSettingSources = projectNetworkSettingSources(settingSources);
|
|
555
|
+
meta.configIssues = configIssues;
|
|
342
556
|
}
|
|
343
|
-
return
|
|
557
|
+
return config;
|
|
344
558
|
}
|
|
345
559
|
}
|
|
346
560
|
catch {
|
|
@@ -350,7 +564,11 @@ export async function loadConfig(client, meta, options) {
|
|
|
350
564
|
if (meta) {
|
|
351
565
|
meta.source = "defaults";
|
|
352
566
|
meta.paths = [];
|
|
567
|
+
meta.globalConfigPaths = [];
|
|
568
|
+
meta.workspaceConfigPaths = [];
|
|
569
|
+
meta.settingSources = {};
|
|
353
570
|
meta.networkSettingSources = {};
|
|
571
|
+
meta.configIssues = [];
|
|
354
572
|
}
|
|
355
573
|
return DEFAULT_CONFIG;
|
|
356
574
|
}
|