@slkiser/opencode-quota 3.1.4 → 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 -559
- package/dist/lib/anthropic.js +1 -1
- package/dist/lib/anthropic.js.map +1 -1
- package/dist/lib/cache.d.ts +17 -27
- package/dist/lib/cache.d.ts.map +1 -1
- package/dist/lib/cache.js +62 -65
- package/dist/lib/cache.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 +448 -214
- 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 +6 -2
- 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 +2 -1
- package/dist/lib/format.d.ts.map +1 -1
- package/dist/lib/format.js +12 -6
- 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/init-installer.d.ts +2 -1
- package/dist/lib/init-installer.d.ts.map +1 -1
- package/dist/lib/init-installer.js +10 -6
- package/dist/lib/init-installer.js.map +1 -1
- package/dist/lib/opencode-go.js +1 -1
- package/dist/lib/opencode-go.js.map +1 -1
- package/dist/lib/provider-metadata.d.ts +2 -1
- package/dist/lib/provider-metadata.d.ts.map +1 -1
- package/dist/lib/provider-metadata.js +27 -0
- package/dist/lib/provider-metadata.js.map +1 -1
- package/dist/lib/quota-format-style.d.ts +21 -0
- package/dist/lib/quota-format-style.d.ts.map +1 -0
- package/dist/lib/quota-format-style.js +38 -0
- package/dist/lib/quota-format-style.js.map +1 -0
- package/dist/lib/quota-render-data.d.ts +4 -12
- package/dist/lib/quota-render-data.d.ts.map +1 -1
- package/dist/lib/quota-render-data.js +83 -70
- 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-state.d.ts +21 -0
- package/dist/lib/quota-state.d.ts.map +1 -0
- package/dist/lib/quota-state.js +228 -0
- package/dist/lib/quota-state.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 +1 -2
- package/dist/lib/tui-runtime.d.ts.map +1 -1
- package/dist/lib/tui-runtime.js +24 -17
- package/dist/lib/tui-runtime.js.map +1 -1
- package/dist/lib/tui-sidebar-format.d.ts.map +1 -1
- package/dist/lib/tui-sidebar-format.js +2 -10
- package/dist/lib/tui-sidebar-format.js.map +1 -1
- package/dist/lib/types.d.ts +51 -9
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +2 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +448 -242
- package/dist/plugin.js.map +1 -1
- package/dist/providers/alibaba-coding-plan.d.ts.map +1 -1
- package/dist/providers/alibaba-coding-plan.js +0 -16
- package/dist/providers/alibaba-coding-plan.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +15 -29
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/copilot.d.ts.map +1 -1
- package/dist/providers/copilot.js +27 -53
- package/dist/providers/copilot.js.map +1 -1
- package/dist/providers/cursor.d.ts.map +1 -1
- package/dist/providers/cursor.js +38 -79
- 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/kimi-code.d.ts.map +1 -1
- package/dist/providers/kimi-code.js +3 -15
- package/dist/providers/kimi-code.js.map +1 -1
- package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
- package/dist/providers/minimax-coding-plan.js +3 -17
- package/dist/providers/minimax-coding-plan.js.map +1 -1
- package/dist/providers/nanogpt.d.ts.map +1 -1
- package/dist/providers/nanogpt.js +23 -42
- package/dist/providers/nanogpt.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +6 -23
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/qwen-code.d.ts.map +1 -1
- package/dist/providers/qwen-code.js +7 -23
- package/dist/providers/qwen-code.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/dist/providers/result-helpers.d.ts +2 -2
- package/dist/providers/result-helpers.d.ts.map +1 -1
- package/dist/providers/result-helpers.js +7 -2
- package/dist/providers/result-helpers.js.map +1 -1
- package/dist/providers/synthetic.d.ts.map +1 -1
- package/dist/providers/synthetic.js +5 -14
- package/dist/providers/synthetic.js.map +1 -1
- package/dist/providers/zai.d.ts.map +1 -1
- package/dist/providers/zai.js +6 -28
- package/dist/providers/zai.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.tsx +1 -15
- package/package.json +2 -1
package/dist/lib/config.js
CHANGED
|
@@ -3,24 +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";
|
|
10
|
+
import { isQuotaFormatStyle, resolveQuotaFormatStyle } from "./quota-format-style.js";
|
|
11
11
|
import { parseJsonOrJsonc } from "./jsonc.js";
|
|
12
|
-
import { normalizeQuotaProviderId } from "./provider-metadata.js";
|
|
12
|
+
import { getQuotaProviderShape, normalizeQuotaProviderId } from "./provider-metadata.js";
|
|
13
13
|
import { existsSync } from "fs";
|
|
14
14
|
import { readFile } from "fs/promises";
|
|
15
15
|
import { join } from "path";
|
|
16
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
|
+
];
|
|
17
44
|
export function createLoadConfigMeta() {
|
|
18
|
-
return {
|
|
45
|
+
return {
|
|
46
|
+
source: "defaults",
|
|
47
|
+
paths: [],
|
|
48
|
+
globalConfigPaths: [],
|
|
49
|
+
workspaceConfigPaths: [],
|
|
50
|
+
settingSources: {},
|
|
51
|
+
networkSettingSources: {},
|
|
52
|
+
configIssues: [],
|
|
53
|
+
};
|
|
19
54
|
}
|
|
20
|
-
const
|
|
55
|
+
const CONFIG_FILENAMES = ["opencode.json", "opencode.jsonc"];
|
|
56
|
+
const NETWORK_SETTING_SOURCE_KEYS = [
|
|
21
57
|
"enabled",
|
|
22
58
|
"enabledProviders",
|
|
23
59
|
"minIntervalMs",
|
|
60
|
+
"pricingSnapshot.source",
|
|
61
|
+
"pricingSnapshot.autoRefresh",
|
|
24
62
|
"showOnIdle",
|
|
25
63
|
"showOnQuestion",
|
|
26
64
|
"showOnCompact",
|
|
@@ -39,8 +77,7 @@ function isValidGoogleModelId(id) {
|
|
|
39
77
|
return typeof id === "string" && ["G3PRO", "G3FLASH", "CLAUDE", "G3IMAGE"].includes(id);
|
|
40
78
|
}
|
|
41
79
|
function isValidCursorQuotaPlan(plan) {
|
|
42
|
-
return (typeof plan === "string" &&
|
|
43
|
-
["none", "pro", "pro-plus", "ultra"].includes(plan));
|
|
80
|
+
return (typeof plan === "string" && ["none", "pro", "pro-plus", "ultra"].includes(plan));
|
|
44
81
|
}
|
|
45
82
|
function isValidPricingSnapshotSource(source) {
|
|
46
83
|
return typeof source === "string" && ["auto", "bundled", "runtime"].includes(source);
|
|
@@ -48,12 +85,18 @@ function isValidPricingSnapshotSource(source) {
|
|
|
48
85
|
function isValidPricingSnapshotAutoRefresh(value) {
|
|
49
86
|
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
50
87
|
}
|
|
51
|
-
function isValidFormatStyle(value) {
|
|
52
|
-
return value === "classic" || value === "grouped";
|
|
53
|
-
}
|
|
54
88
|
function isValidPercentDisplayMode(value) {
|
|
55
89
|
return value === "remaining" || value === "used";
|
|
56
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
|
+
}
|
|
57
100
|
function normalizeOptionalString(value) {
|
|
58
101
|
if (typeof value !== "string") {
|
|
59
102
|
return undefined;
|
|
@@ -61,59 +104,350 @@ function normalizeOptionalString(value) {
|
|
|
61
104
|
const trimmed = value.trim();
|
|
62
105
|
return trimmed ? trimmed : undefined;
|
|
63
106
|
}
|
|
107
|
+
function getConfiguredFormatStyle(quotaToastConfig) {
|
|
108
|
+
if (!quotaToastConfig) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
if (isQuotaFormatStyle(quotaToastConfig.formatStyle)) {
|
|
112
|
+
return resolveQuotaFormatStyle(quotaToastConfig.formatStyle);
|
|
113
|
+
}
|
|
114
|
+
const legacyFormatStyle = quotaToastConfig.toastStyle;
|
|
115
|
+
if (isQuotaFormatStyle(legacyFormatStyle)) {
|
|
116
|
+
return resolveQuotaFormatStyle(legacyFormatStyle);
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
64
120
|
/**
|
|
65
121
|
* Remove duplicates from an array while preserving order
|
|
66
122
|
*/
|
|
67
123
|
function dedupe(list) {
|
|
68
124
|
return [...new Set(list)];
|
|
69
125
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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);
|
|
86
242
|
}
|
|
87
|
-
|
|
88
|
-
|
|
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;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (hasOwnKey(quotaToastConfig, "googleModels")) {
|
|
257
|
+
const googleModels = normalizeGoogleModels(quotaToastConfig.googleModels);
|
|
258
|
+
if (googleModels !== undefined) {
|
|
259
|
+
patch.googleModels = googleModels;
|
|
89
260
|
}
|
|
90
261
|
}
|
|
91
|
-
|
|
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;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return patch;
|
|
317
|
+
}
|
|
318
|
+
function applySettingSource(settingSources, key, sourcePath) {
|
|
319
|
+
settingSources[key] = sourcePath;
|
|
92
320
|
}
|
|
93
|
-
function
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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);
|
|
105
385
|
}
|
|
106
386
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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);
|
|
112
423
|
}
|
|
113
|
-
if ("
|
|
114
|
-
|
|
424
|
+
if (hasOwnKey(patch.layout, "tinyAt")) {
|
|
425
|
+
config.layout.tinyAt = patch.layout.tinyAt;
|
|
426
|
+
applySettingSource(settingSources, "layout.tinyAt", sourcePath);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
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;
|
|
115
436
|
}
|
|
116
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
|
+
];
|
|
117
451
|
}
|
|
118
452
|
/**
|
|
119
453
|
* Load plugin configuration from OpenCode config
|
|
@@ -122,109 +456,6 @@ function recordNetworkSettingSource(sources, quotaToast, sourcePath) {
|
|
|
122
456
|
* @returns Merged configuration with defaults
|
|
123
457
|
*/
|
|
124
458
|
export async function loadConfig(client, meta, options) {
|
|
125
|
-
function normalize(quotaToastConfig) {
|
|
126
|
-
if (!quotaToastConfig)
|
|
127
|
-
return DEFAULT_CONFIG;
|
|
128
|
-
const config = {
|
|
129
|
-
enabled: typeof quotaToastConfig.enabled === "boolean"
|
|
130
|
-
? quotaToastConfig.enabled
|
|
131
|
-
: DEFAULT_CONFIG.enabled,
|
|
132
|
-
enableToast: typeof quotaToastConfig.enableToast === "boolean"
|
|
133
|
-
? quotaToastConfig.enableToast
|
|
134
|
-
: DEFAULT_CONFIG.enableToast,
|
|
135
|
-
formatStyle: isValidFormatStyle(quotaToastConfig.formatStyle)
|
|
136
|
-
? quotaToastConfig.formatStyle
|
|
137
|
-
: isValidFormatStyle(quotaToastConfig.toastStyle)
|
|
138
|
-
? quotaToastConfig.toastStyle
|
|
139
|
-
: DEFAULT_CONFIG.formatStyle,
|
|
140
|
-
percentDisplayMode: isValidPercentDisplayMode(quotaToastConfig.percentDisplayMode)
|
|
141
|
-
? quotaToastConfig.percentDisplayMode
|
|
142
|
-
: DEFAULT_CONFIG.percentDisplayMode,
|
|
143
|
-
minIntervalMs: typeof quotaToastConfig.minIntervalMs === "number" && quotaToastConfig.minIntervalMs > 0
|
|
144
|
-
? quotaToastConfig.minIntervalMs
|
|
145
|
-
: DEFAULT_CONFIG.minIntervalMs,
|
|
146
|
-
debug: typeof quotaToastConfig.debug === "boolean" ? quotaToastConfig.debug : DEFAULT_CONFIG.debug,
|
|
147
|
-
enabledProviders: quotaToastConfig.enabledProviders === "auto"
|
|
148
|
-
? "auto"
|
|
149
|
-
: Array.isArray(quotaToastConfig.enabledProviders)
|
|
150
|
-
? dedupe(quotaToastConfig.enabledProviders
|
|
151
|
-
.filter((p) => typeof p === "string")
|
|
152
|
-
.map(normalizeQuotaProviderId)
|
|
153
|
-
.filter(Boolean))
|
|
154
|
-
: DEFAULT_CONFIG.enabledProviders,
|
|
155
|
-
anthropicBinaryPath: normalizeOptionalString(quotaToastConfig.anthropicBinaryPath) ??
|
|
156
|
-
DEFAULT_CONFIG.anthropicBinaryPath,
|
|
157
|
-
googleModels: Array.isArray(quotaToastConfig.googleModels)
|
|
158
|
-
? quotaToastConfig.googleModels.filter(isValidGoogleModelId)
|
|
159
|
-
: DEFAULT_CONFIG.googleModels,
|
|
160
|
-
alibabaCodingPlanTier: quotaToastConfig.alibabaCodingPlanTier === "lite" ||
|
|
161
|
-
quotaToastConfig.alibabaCodingPlanTier === "pro"
|
|
162
|
-
? quotaToastConfig.alibabaCodingPlanTier
|
|
163
|
-
: DEFAULT_CONFIG.alibabaCodingPlanTier,
|
|
164
|
-
cursorPlan: isValidCursorQuotaPlan(quotaToastConfig.cursorPlan)
|
|
165
|
-
? quotaToastConfig.cursorPlan
|
|
166
|
-
: DEFAULT_CONFIG.cursorPlan,
|
|
167
|
-
cursorIncludedApiUsd: typeof quotaToastConfig.cursorIncludedApiUsd === "number" &&
|
|
168
|
-
Number.isFinite(quotaToastConfig.cursorIncludedApiUsd) &&
|
|
169
|
-
quotaToastConfig.cursorIncludedApiUsd > 0
|
|
170
|
-
? quotaToastConfig.cursorIncludedApiUsd
|
|
171
|
-
: undefined,
|
|
172
|
-
cursorBillingCycleStartDay: typeof quotaToastConfig.cursorBillingCycleStartDay === "number" &&
|
|
173
|
-
Number.isInteger(quotaToastConfig.cursorBillingCycleStartDay) &&
|
|
174
|
-
quotaToastConfig.cursorBillingCycleStartDay >= 1 &&
|
|
175
|
-
quotaToastConfig.cursorBillingCycleStartDay <= 28
|
|
176
|
-
? quotaToastConfig.cursorBillingCycleStartDay
|
|
177
|
-
: undefined,
|
|
178
|
-
pricingSnapshot: {
|
|
179
|
-
source: isValidPricingSnapshotSource(quotaToastConfig.pricingSnapshot?.source)
|
|
180
|
-
? quotaToastConfig.pricingSnapshot.source
|
|
181
|
-
: DEFAULT_CONFIG.pricingSnapshot.source,
|
|
182
|
-
autoRefresh: isValidPricingSnapshotAutoRefresh(quotaToastConfig.pricingSnapshot?.autoRefresh)
|
|
183
|
-
? quotaToastConfig.pricingSnapshot.autoRefresh
|
|
184
|
-
: DEFAULT_CONFIG.pricingSnapshot.autoRefresh,
|
|
185
|
-
},
|
|
186
|
-
showOnIdle: typeof quotaToastConfig.showOnIdle === "boolean"
|
|
187
|
-
? quotaToastConfig.showOnIdle
|
|
188
|
-
: DEFAULT_CONFIG.showOnIdle,
|
|
189
|
-
showOnQuestion: typeof quotaToastConfig.showOnQuestion === "boolean"
|
|
190
|
-
? quotaToastConfig.showOnQuestion
|
|
191
|
-
: DEFAULT_CONFIG.showOnQuestion,
|
|
192
|
-
showOnCompact: typeof quotaToastConfig.showOnCompact === "boolean"
|
|
193
|
-
? quotaToastConfig.showOnCompact
|
|
194
|
-
: DEFAULT_CONFIG.showOnCompact,
|
|
195
|
-
showOnBothFail: typeof quotaToastConfig.showOnBothFail === "boolean"
|
|
196
|
-
? quotaToastConfig.showOnBothFail
|
|
197
|
-
: DEFAULT_CONFIG.showOnBothFail,
|
|
198
|
-
toastDurationMs: typeof quotaToastConfig.toastDurationMs === "number" && quotaToastConfig.toastDurationMs > 0
|
|
199
|
-
? quotaToastConfig.toastDurationMs
|
|
200
|
-
: DEFAULT_CONFIG.toastDurationMs,
|
|
201
|
-
onlyCurrentModel: typeof quotaToastConfig.onlyCurrentModel === "boolean"
|
|
202
|
-
? quotaToastConfig.onlyCurrentModel
|
|
203
|
-
: DEFAULT_CONFIG.onlyCurrentModel,
|
|
204
|
-
showSessionTokens: typeof quotaToastConfig.showSessionTokens === "boolean"
|
|
205
|
-
? quotaToastConfig.showSessionTokens
|
|
206
|
-
: DEFAULT_CONFIG.showSessionTokens,
|
|
207
|
-
layout: {
|
|
208
|
-
maxWidth: typeof quotaToastConfig.layout?.maxWidth === "number" &&
|
|
209
|
-
quotaToastConfig.layout.maxWidth > 0
|
|
210
|
-
? quotaToastConfig.layout.maxWidth
|
|
211
|
-
: DEFAULT_CONFIG.layout.maxWidth,
|
|
212
|
-
narrowAt: typeof quotaToastConfig.layout?.narrowAt === "number" &&
|
|
213
|
-
quotaToastConfig.layout.narrowAt > 0
|
|
214
|
-
? quotaToastConfig.layout.narrowAt
|
|
215
|
-
: DEFAULT_CONFIG.layout.narrowAt,
|
|
216
|
-
tinyAt: typeof quotaToastConfig.layout?.tinyAt === "number" && quotaToastConfig.layout.tinyAt > 0
|
|
217
|
-
? quotaToastConfig.layout.tinyAt
|
|
218
|
-
: DEFAULT_CONFIG.layout.tinyAt,
|
|
219
|
-
},
|
|
220
|
-
};
|
|
221
|
-
// enabledProviders: "auto" means auto-detect; explicit array means user-specified.
|
|
222
|
-
// Ensure at least one Google model is configured
|
|
223
|
-
if (config.googleModels.length === 0) {
|
|
224
|
-
config.googleModels = DEFAULT_CONFIG.googleModels;
|
|
225
|
-
}
|
|
226
|
-
return config;
|
|
227
|
-
}
|
|
228
459
|
async function readJson(path) {
|
|
229
460
|
try {
|
|
230
461
|
const content = await readFile(path, "utf-8");
|
|
@@ -234,72 +465,58 @@ export async function loadConfig(client, meta, options) {
|
|
|
234
465
|
return null;
|
|
235
466
|
}
|
|
236
467
|
}
|
|
237
|
-
async function loadQuotaToastFromLocations(locations) {
|
|
238
|
-
const quota = {};
|
|
239
|
-
const usedPaths = [];
|
|
240
|
-
const networkSettingSources = {};
|
|
241
|
-
for (const dir of locations) {
|
|
242
|
-
for (const filename of ["opencode.json", "opencode.jsonc"]) {
|
|
243
|
-
const p = join(dir, filename);
|
|
244
|
-
if (!existsSync(p))
|
|
245
|
-
continue;
|
|
246
|
-
const parsed = await readJson(p);
|
|
247
|
-
if (!parsed || typeof parsed !== "object")
|
|
248
|
-
continue;
|
|
249
|
-
const root = parsed;
|
|
250
|
-
const rawQuotaToast = root?.experimental?.quotaToast;
|
|
251
|
-
if (!rawQuotaToast || typeof rawQuotaToast !== "object")
|
|
252
|
-
continue;
|
|
253
|
-
Object.assign(quota, rawQuotaToast);
|
|
254
|
-
const sourcePath = `${p} (experimental.quotaToast)`;
|
|
255
|
-
usedPaths.push(sourcePath);
|
|
256
|
-
recordNetworkSettingSource(networkSettingSources, rawQuotaToast, sourcePath);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return { quota, usedPaths, networkSettingSources };
|
|
260
|
-
}
|
|
261
468
|
async function loadFromFiles() {
|
|
262
|
-
const
|
|
469
|
+
const configRootDir = options?.configRootDir ?? options?.cwd ?? process.cwd();
|
|
263
470
|
const { configDirs } = getOpencodeRuntimeDirCandidates();
|
|
264
|
-
const
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
const quota = {
|
|
275
|
-
...globalConfig.quota,
|
|
276
|
-
...localConfig.quota,
|
|
277
|
-
};
|
|
278
|
-
for (const key of NETWORK_AFFECTING_KEYS) {
|
|
279
|
-
if (hasOwnKey(globalConfig.quota, key)) {
|
|
280
|
-
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;
|
|
281
480
|
}
|
|
282
|
-
|
|
283
|
-
|
|
481
|
+
const parsed = await readJson(candidate.path);
|
|
482
|
+
if (!isPlainObject(parsed) || !isPlainObject(parsed.experimental)) {
|
|
483
|
+
continue;
|
|
284
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);
|
|
285
500
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (hasMergedPricingSnapshot) {
|
|
297
|
-
quota.pricingSnapshot = mergedPricingSnapshot;
|
|
501
|
+
if (usedPaths.length === 0) {
|
|
502
|
+
return {
|
|
503
|
+
config: null,
|
|
504
|
+
usedPaths: [],
|
|
505
|
+
globalConfigPaths: [],
|
|
506
|
+
workspaceConfigPaths: [],
|
|
507
|
+
settingSources: {},
|
|
508
|
+
networkSettingSources: {},
|
|
509
|
+
configIssues: [],
|
|
510
|
+
};
|
|
298
511
|
}
|
|
299
512
|
return {
|
|
300
|
-
config
|
|
513
|
+
config,
|
|
301
514
|
usedPaths,
|
|
302
|
-
|
|
515
|
+
globalConfigPaths,
|
|
516
|
+
workspaceConfigPaths,
|
|
517
|
+
settingSources,
|
|
518
|
+
networkSettingSources: projectNetworkSettingSources(settingSources),
|
|
519
|
+
configIssues,
|
|
303
520
|
};
|
|
304
521
|
}
|
|
305
522
|
const fileConfig = await loadFromFiles();
|
|
@@ -307,7 +524,11 @@ export async function loadConfig(client, meta, options) {
|
|
|
307
524
|
if (meta) {
|
|
308
525
|
meta.source = "files";
|
|
309
526
|
meta.paths = fileConfig.usedPaths;
|
|
527
|
+
meta.globalConfigPaths = fileConfig.globalConfigPaths;
|
|
528
|
+
meta.workspaceConfigPaths = fileConfig.workspaceConfigPaths;
|
|
529
|
+
meta.settingSources = fileConfig.settingSources;
|
|
310
530
|
meta.networkSettingSources = fileConfig.networkSettingSources;
|
|
531
|
+
meta.configIssues = fileConfig.configIssues;
|
|
311
532
|
}
|
|
312
533
|
return fileConfig.config;
|
|
313
534
|
}
|
|
@@ -317,14 +538,23 @@ export async function loadConfig(client, meta, options) {
|
|
|
317
538
|
// OpenCode config schema is strict; plugin-specific config must live under
|
|
318
539
|
// experimental.* to avoid "unrecognized key" validation errors.
|
|
319
540
|
const quotaToastConfig = response.data?.experimental?.quotaToast;
|
|
320
|
-
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);
|
|
321
548
|
if (meta) {
|
|
322
549
|
meta.source = "sdk";
|
|
323
550
|
meta.paths = ["client.config.get"];
|
|
324
|
-
meta.
|
|
325
|
-
|
|
551
|
+
meta.globalConfigPaths = [];
|
|
552
|
+
meta.workspaceConfigPaths = [];
|
|
553
|
+
meta.settingSources = settingSources;
|
|
554
|
+
meta.networkSettingSources = projectNetworkSettingSources(settingSources);
|
|
555
|
+
meta.configIssues = configIssues;
|
|
326
556
|
}
|
|
327
|
-
return
|
|
557
|
+
return config;
|
|
328
558
|
}
|
|
329
559
|
}
|
|
330
560
|
catch {
|
|
@@ -334,7 +564,11 @@ export async function loadConfig(client, meta, options) {
|
|
|
334
564
|
if (meta) {
|
|
335
565
|
meta.source = "defaults";
|
|
336
566
|
meta.paths = [];
|
|
567
|
+
meta.globalConfigPaths = [];
|
|
568
|
+
meta.workspaceConfigPaths = [];
|
|
569
|
+
meta.settingSources = {};
|
|
337
570
|
meta.networkSettingSources = {};
|
|
571
|
+
meta.configIssues = [];
|
|
338
572
|
}
|
|
339
573
|
return DEFAULT_CONFIG;
|
|
340
574
|
}
|