@tarquinen/opencode-dcp 2.1.6 → 2.2.0-beta0
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 +30 -49
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -29
- package/dist/index.js.map +1 -1
- package/dist/lib/commands/context.d.ts.map +1 -1
- package/dist/lib/commands/context.js +36 -8
- package/dist/lib/commands/context.js.map +1 -1
- package/dist/lib/commands/help.d.ts.map +1 -1
- package/dist/lib/commands/help.js +2 -6
- package/dist/lib/commands/help.js.map +1 -1
- package/dist/lib/commands/manual.d.ts +1 -3
- package/dist/lib/commands/manual.d.ts.map +1 -1
- package/dist/lib/commands/manual.js +4 -43
- package/dist/lib/commands/manual.js.map +1 -1
- package/dist/lib/commands/sweep.js +1 -1
- package/dist/lib/commands/sweep.js.map +1 -1
- package/dist/lib/compress-logger.d.ts +15 -0
- package/dist/lib/compress-logger.d.ts.map +1 -0
- package/dist/lib/compress-logger.js +132 -0
- package/dist/lib/compress-logger.js.map +1 -0
- package/dist/lib/config.d.ts +5 -20
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +172 -346
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/hooks.d.ts +7 -0
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/hooks.js +23 -16
- package/dist/lib/hooks.js.map +1 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +6 -0
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/messages/index.d.ts +2 -2
- package/dist/lib/messages/index.d.ts.map +1 -1
- package/dist/lib/messages/index.js +2 -2
- package/dist/lib/messages/index.js.map +1 -1
- package/dist/lib/messages/inject/inject.d.ts +6 -0
- package/dist/lib/messages/inject/inject.d.ts.map +1 -0
- package/dist/lib/messages/inject/inject.js +99 -0
- package/dist/lib/messages/inject/inject.js.map +1 -0
- package/dist/lib/messages/inject/utils.d.ts +20 -0
- package/dist/lib/messages/inject/utils.d.ts.map +1 -0
- package/dist/lib/messages/inject/utils.js +137 -0
- package/dist/lib/messages/inject/utils.js.map +1 -0
- package/dist/lib/messages/prune.js +7 -7
- package/dist/lib/messages/prune.js.map +1 -1
- package/dist/lib/messages/utils.d.ts +16 -28
- package/dist/lib/messages/utils.d.ts.map +1 -1
- package/dist/lib/messages/utils.js +40 -133
- package/dist/lib/messages/utils.js.map +1 -1
- package/dist/lib/prompts/_codegen/system.generated.d.ts +1 -1
- package/dist/lib/prompts/_codegen/system.generated.d.ts.map +1 -1
- package/dist/lib/prompts/_codegen/system.generated.js +36 -32
- package/dist/lib/prompts/_codegen/system.generated.js.map +1 -1
- package/dist/lib/prompts/compress.d.ts +2 -0
- package/dist/lib/prompts/compress.d.ts.map +1 -0
- package/dist/lib/prompts/compress.js +122 -0
- package/dist/lib/prompts/compress.js.map +1 -0
- package/dist/lib/prompts/index.d.ts +6 -10
- package/dist/lib/prompts/index.d.ts.map +1 -1
- package/dist/lib/prompts/index.js +17 -40
- package/dist/lib/prompts/index.js.map +1 -1
- package/dist/lib/prompts/iteration-nudge.d.ts +2 -0
- package/dist/lib/prompts/iteration-nudge.d.ts.map +1 -0
- package/dist/lib/prompts/iteration-nudge.js +9 -0
- package/dist/lib/prompts/iteration-nudge.js.map +1 -0
- package/dist/lib/prompts/nudge.d.ts +2 -0
- package/dist/lib/prompts/nudge.d.ts.map +1 -0
- package/dist/lib/prompts/nudge.js +40 -0
- package/dist/lib/prompts/nudge.js.map +1 -0
- package/dist/lib/prompts/turn-nudge.d.ts +2 -0
- package/dist/lib/prompts/turn-nudge.d.ts.map +1 -0
- package/dist/lib/prompts/turn-nudge.js +12 -0
- package/dist/lib/prompts/turn-nudge.js.map +1 -0
- package/dist/lib/state/persistence.d.ts +6 -0
- package/dist/lib/state/persistence.d.ts.map +1 -1
- package/dist/lib/state/persistence.js +58 -38
- package/dist/lib/state/persistence.js.map +1 -1
- package/dist/lib/state/state.d.ts.map +1 -1
- package/dist/lib/state/state.js +20 -5
- package/dist/lib/state/state.js.map +1 -1
- package/dist/lib/state/tool-cache.d.ts.map +1 -1
- package/dist/lib/state/tool-cache.js +3 -17
- package/dist/lib/state/tool-cache.js.map +1 -1
- package/dist/lib/state/types.d.ts +7 -2
- package/dist/lib/state/types.d.ts.map +1 -1
- package/dist/lib/state/utils.d.ts +1 -0
- package/dist/lib/state/utils.d.ts.map +1 -1
- package/dist/lib/state/utils.js +33 -6
- package/dist/lib/state/utils.js.map +1 -1
- package/dist/lib/strategies/index.d.ts +0 -1
- package/dist/lib/strategies/index.d.ts.map +1 -1
- package/dist/lib/strategies/index.js +0 -1
- package/dist/lib/strategies/index.js.map +1 -1
- package/dist/lib/strategies/utils.d.ts +1 -0
- package/dist/lib/strategies/utils.d.ts.map +1 -1
- package/dist/lib/strategies/utils.js +15 -0
- package/dist/lib/strategies/utils.js.map +1 -1
- package/dist/lib/tools/compress-utils.d.ts +7 -4
- package/dist/lib/tools/compress-utils.d.ts.map +1 -1
- package/dist/lib/tools/compress-utils.js +34 -25
- package/dist/lib/tools/compress-utils.js.map +1 -1
- package/dist/lib/tools/compress.d.ts +2 -2
- package/dist/lib/tools/compress.d.ts.map +1 -1
- package/dist/lib/tools/compress.js +21 -58
- package/dist/lib/tools/compress.js.map +1 -1
- package/dist/lib/tools/index.d.ts +1 -3
- package/dist/lib/tools/index.d.ts.map +1 -1
- package/dist/lib/tools/index.js +0 -2
- package/dist/lib/tools/index.js.map +1 -1
- package/dist/lib/tools/types.d.ts +1 -1
- package/dist/lib/tools/types.d.ts.map +1 -1
- package/dist/lib/ui/notification.d.ts +2 -2
- package/dist/lib/ui/notification.d.ts.map +1 -1
- package/dist/lib/ui/notification.js +31 -28
- package/dist/lib/ui/notification.js.map +1 -1
- package/dist/lib/ui/utils.d.ts +3 -4
- package/dist/lib/ui/utils.d.ts.map +1 -1
- package/dist/lib/ui/utils.js +165 -24
- package/dist/lib/ui/utils.js.map +1 -1
- package/package.json +2 -1
- package/dist/lib/messages/inject.d.ts +0 -14
- package/dist/lib/messages/inject.d.ts.map +0 -1
- package/dist/lib/messages/inject.js +0 -266
- package/dist/lib/messages/inject.js.map +0 -1
- package/dist/lib/prompts/_codegen/compress-nudge.generated.d.ts +0 -2
- package/dist/lib/prompts/_codegen/compress-nudge.generated.d.ts.map +0 -1
- package/dist/lib/prompts/_codegen/compress-nudge.generated.js +0 -15
- package/dist/lib/prompts/_codegen/compress-nudge.generated.js.map +0 -1
- package/dist/lib/prompts/_codegen/compress.generated.d.ts +0 -2
- package/dist/lib/prompts/_codegen/compress.generated.d.ts.map +0 -1
- package/dist/lib/prompts/_codegen/compress.generated.js +0 -66
- package/dist/lib/prompts/_codegen/compress.generated.js.map +0 -1
- package/dist/lib/prompts/_codegen/distill.generated.d.ts +0 -2
- package/dist/lib/prompts/_codegen/distill.generated.d.ts.map +0 -1
- package/dist/lib/prompts/_codegen/distill.generated.js +0 -33
- package/dist/lib/prompts/_codegen/distill.generated.js.map +0 -1
- package/dist/lib/prompts/_codegen/nudge.generated.d.ts +0 -2
- package/dist/lib/prompts/_codegen/nudge.generated.d.ts.map +0 -1
- package/dist/lib/prompts/_codegen/nudge.generated.js +0 -17
- package/dist/lib/prompts/_codegen/nudge.generated.js.map +0 -1
- package/dist/lib/prompts/_codegen/prune.generated.d.ts +0 -2
- package/dist/lib/prompts/_codegen/prune.generated.d.ts.map +0 -1
- package/dist/lib/prompts/_codegen/prune.generated.js +0 -23
- package/dist/lib/prompts/_codegen/prune.generated.js.map +0 -1
- package/dist/lib/tools/distill.d.ts +0 -4
- package/dist/lib/tools/distill.d.ts.map +0 -1
- package/dist/lib/tools/distill.js +0 -41
- package/dist/lib/tools/distill.js.map +0 -1
- package/dist/lib/tools/prune-shared.d.ts +0 -6
- package/dist/lib/tools/prune-shared.d.ts.map +0 -1
- package/dist/lib/tools/prune-shared.js +0 -113
- package/dist/lib/tools/prune-shared.js.map +0 -1
- package/dist/lib/tools/prune.d.ts +0 -4
- package/dist/lib/tools/prune.d.ts.map +0 -1
- package/dist/lib/tools/prune.js +0 -28
- package/dist/lib/tools/prune.js.map +0 -1
package/dist/lib/config.js
CHANGED
|
@@ -6,20 +6,16 @@ const DEFAULT_PROTECTED_TOOLS = [
|
|
|
6
6
|
"task",
|
|
7
7
|
"todowrite",
|
|
8
8
|
"todoread",
|
|
9
|
-
"distill",
|
|
10
9
|
"compress",
|
|
11
|
-
"prune",
|
|
12
10
|
"batch",
|
|
13
11
|
"plan_enter",
|
|
14
12
|
"plan_exit",
|
|
15
13
|
];
|
|
16
|
-
// Valid config keys for validation against user config
|
|
17
14
|
export const VALID_CONFIG_KEYS = new Set([
|
|
18
|
-
// Top-level keys
|
|
19
15
|
"$schema",
|
|
20
16
|
"enabled",
|
|
21
17
|
"debug",
|
|
22
|
-
"showUpdateToasts",
|
|
18
|
+
"showUpdateToasts",
|
|
23
19
|
"pruneNotification",
|
|
24
20
|
"pruneNotificationType",
|
|
25
21
|
"turnProtection",
|
|
@@ -32,43 +28,31 @@ export const VALID_CONFIG_KEYS = new Set([
|
|
|
32
28
|
"manualMode",
|
|
33
29
|
"manualMode.enabled",
|
|
34
30
|
"manualMode.automaticStrategies",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"tools.distill",
|
|
43
|
-
"tools.distill.permission",
|
|
44
|
-
"tools.distill.showDistillation",
|
|
45
|
-
"tools.compress",
|
|
46
|
-
"tools.compress.permission",
|
|
47
|
-
"tools.compress.showCompression",
|
|
48
|
-
"tools.prune",
|
|
49
|
-
"tools.prune.permission",
|
|
31
|
+
"compress",
|
|
32
|
+
"compress.permission",
|
|
33
|
+
"compress.showCompression",
|
|
34
|
+
"compress.contextLimit",
|
|
35
|
+
"compress.modelLimits",
|
|
36
|
+
"compress.nudgeFrequency",
|
|
37
|
+
"compress.iterationNudgeThreshold",
|
|
50
38
|
"strategies",
|
|
51
|
-
// strategies.deduplication
|
|
52
39
|
"strategies.deduplication",
|
|
53
40
|
"strategies.deduplication.enabled",
|
|
54
41
|
"strategies.deduplication.protectedTools",
|
|
55
|
-
// strategies.supersedeWrites
|
|
56
42
|
"strategies.supersedeWrites",
|
|
57
43
|
"strategies.supersedeWrites.enabled",
|
|
58
|
-
// strategies.purgeErrors
|
|
59
44
|
"strategies.purgeErrors",
|
|
60
45
|
"strategies.purgeErrors.enabled",
|
|
61
46
|
"strategies.purgeErrors.turns",
|
|
62
47
|
"strategies.purgeErrors.protectedTools",
|
|
63
48
|
]);
|
|
64
|
-
// Extract all key paths from a config object for validation
|
|
65
49
|
function getConfigKeyPaths(obj, prefix = "") {
|
|
66
50
|
const keys = [];
|
|
67
51
|
for (const key of Object.keys(obj)) {
|
|
68
52
|
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
69
53
|
keys.push(fullKey);
|
|
70
54
|
// modelLimits is a dynamic map keyed by providerID/modelID; do not recurse into arbitrary IDs.
|
|
71
|
-
if (fullKey === "
|
|
55
|
+
if (fullKey === "compress.modelLimits") {
|
|
72
56
|
continue;
|
|
73
57
|
}
|
|
74
58
|
if (obj[key] && typeof obj[key] === "object" && !Array.isArray(obj[key])) {
|
|
@@ -77,14 +61,12 @@ function getConfigKeyPaths(obj, prefix = "") {
|
|
|
77
61
|
}
|
|
78
62
|
return keys;
|
|
79
63
|
}
|
|
80
|
-
// Returns invalid keys found in user config
|
|
81
64
|
export function getInvalidConfigKeys(userConfig) {
|
|
82
65
|
const userKeys = getConfigKeyPaths(userConfig);
|
|
83
66
|
return userKeys.filter((key) => !VALID_CONFIG_KEYS.has(key));
|
|
84
67
|
}
|
|
85
68
|
export function validateConfigTypes(config) {
|
|
86
69
|
const errors = [];
|
|
87
|
-
// Top-level validators
|
|
88
70
|
if (config.enabled !== undefined && typeof config.enabled !== "boolean") {
|
|
89
71
|
errors.push({ key: "enabled", expected: "boolean", actual: typeof config.enabled });
|
|
90
72
|
}
|
|
@@ -127,7 +109,6 @@ export function validateConfigTypes(config) {
|
|
|
127
109
|
});
|
|
128
110
|
}
|
|
129
111
|
}
|
|
130
|
-
// Top-level turnProtection validator
|
|
131
112
|
if (config.turnProtection) {
|
|
132
113
|
if (config.turnProtection.enabled !== undefined &&
|
|
133
114
|
typeof config.turnProtection.enabled !== "boolean") {
|
|
@@ -153,10 +134,16 @@ export function validateConfigTypes(config) {
|
|
|
153
134
|
});
|
|
154
135
|
}
|
|
155
136
|
}
|
|
156
|
-
// Commands validator
|
|
157
137
|
const commands = config.commands;
|
|
158
138
|
if (commands !== undefined) {
|
|
159
|
-
if (typeof commands
|
|
139
|
+
if (typeof commands !== "object" || commands === null || Array.isArray(commands)) {
|
|
140
|
+
errors.push({
|
|
141
|
+
key: "commands",
|
|
142
|
+
expected: "object",
|
|
143
|
+
actual: typeof commands,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
160
147
|
if (commands.enabled !== undefined && typeof commands.enabled !== "boolean") {
|
|
161
148
|
errors.push({
|
|
162
149
|
key: "commands.enabled",
|
|
@@ -172,18 +159,17 @@ export function validateConfigTypes(config) {
|
|
|
172
159
|
});
|
|
173
160
|
}
|
|
174
161
|
}
|
|
175
|
-
else {
|
|
176
|
-
errors.push({
|
|
177
|
-
key: "commands",
|
|
178
|
-
expected: "{ enabled: boolean, protectedTools: string[] }",
|
|
179
|
-
actual: typeof commands,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
162
|
}
|
|
183
|
-
// Manual mode validator
|
|
184
163
|
const manualMode = config.manualMode;
|
|
185
164
|
if (manualMode !== undefined) {
|
|
186
|
-
if (typeof manualMode
|
|
165
|
+
if (typeof manualMode !== "object" || manualMode === null || Array.isArray(manualMode)) {
|
|
166
|
+
errors.push({
|
|
167
|
+
key: "manualMode",
|
|
168
|
+
expected: "object",
|
|
169
|
+
actual: typeof manualMode,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
187
173
|
if (manualMode.enabled !== undefined && typeof manualMode.enabled !== "boolean") {
|
|
188
174
|
errors.push({
|
|
189
175
|
key: "manualMode.enabled",
|
|
@@ -200,78 +186,76 @@ export function validateConfigTypes(config) {
|
|
|
200
186
|
});
|
|
201
187
|
}
|
|
202
188
|
}
|
|
203
|
-
|
|
189
|
+
}
|
|
190
|
+
const compress = config.compress;
|
|
191
|
+
if (compress !== undefined) {
|
|
192
|
+
if (typeof compress !== "object" || compress === null || Array.isArray(compress)) {
|
|
204
193
|
errors.push({
|
|
205
|
-
key: "
|
|
206
|
-
expected: "
|
|
207
|
-
actual: typeof
|
|
194
|
+
key: "compress",
|
|
195
|
+
expected: "object",
|
|
196
|
+
actual: typeof compress,
|
|
208
197
|
});
|
|
209
198
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (tools) {
|
|
214
|
-
if (tools.settings) {
|
|
215
|
-
if (tools.settings.nudgeEnabled !== undefined &&
|
|
216
|
-
typeof tools.settings.nudgeEnabled !== "boolean") {
|
|
199
|
+
else {
|
|
200
|
+
if (compress.nudgeFrequency !== undefined &&
|
|
201
|
+
typeof compress.nudgeFrequency !== "number") {
|
|
217
202
|
errors.push({
|
|
218
|
-
key: "
|
|
219
|
-
expected: "
|
|
220
|
-
actual: typeof
|
|
203
|
+
key: "compress.nudgeFrequency",
|
|
204
|
+
expected: "number",
|
|
205
|
+
actual: typeof compress.nudgeFrequency,
|
|
221
206
|
});
|
|
222
207
|
}
|
|
223
|
-
if (
|
|
224
|
-
typeof tools.settings.nudgeFrequency !== "number") {
|
|
208
|
+
if (typeof compress.nudgeFrequency === "number" && compress.nudgeFrequency < 1) {
|
|
225
209
|
errors.push({
|
|
226
|
-
key: "
|
|
227
|
-
expected: "number",
|
|
228
|
-
actual:
|
|
210
|
+
key: "compress.nudgeFrequency",
|
|
211
|
+
expected: "positive number (>= 1)",
|
|
212
|
+
actual: `${compress.nudgeFrequency} (will be clamped to 1)`,
|
|
229
213
|
});
|
|
230
214
|
}
|
|
231
|
-
if (
|
|
232
|
-
|
|
215
|
+
if (compress.iterationNudgeThreshold !== undefined &&
|
|
216
|
+
typeof compress.iterationNudgeThreshold !== "number") {
|
|
233
217
|
errors.push({
|
|
234
|
-
key: "
|
|
235
|
-
expected: "
|
|
236
|
-
actual:
|
|
218
|
+
key: "compress.iterationNudgeThreshold",
|
|
219
|
+
expected: "number",
|
|
220
|
+
actual: typeof compress.iterationNudgeThreshold,
|
|
237
221
|
});
|
|
238
222
|
}
|
|
239
|
-
if (
|
|
240
|
-
|
|
223
|
+
if (typeof compress.iterationNudgeThreshold === "number" &&
|
|
224
|
+
compress.iterationNudgeThreshold < 1) {
|
|
241
225
|
errors.push({
|
|
242
|
-
key: "
|
|
243
|
-
expected: "
|
|
244
|
-
actual:
|
|
226
|
+
key: "compress.iterationNudgeThreshold",
|
|
227
|
+
expected: "positive number (>= 1)",
|
|
228
|
+
actual: `${compress.iterationNudgeThreshold} (will be clamped to 1)`,
|
|
245
229
|
});
|
|
246
230
|
}
|
|
247
|
-
if (
|
|
248
|
-
const isValidNumber = typeof
|
|
249
|
-
const isPercentString = typeof
|
|
250
|
-
tools.settings.contextLimit.endsWith("%");
|
|
231
|
+
if (compress.contextLimit !== undefined) {
|
|
232
|
+
const isValidNumber = typeof compress.contextLimit === "number";
|
|
233
|
+
const isPercentString = typeof compress.contextLimit === "string" && compress.contextLimit.endsWith("%");
|
|
251
234
|
if (!isValidNumber && !isPercentString) {
|
|
252
235
|
errors.push({
|
|
253
|
-
key: "
|
|
236
|
+
key: "compress.contextLimit",
|
|
254
237
|
expected: 'number | "${number}%"',
|
|
255
|
-
actual: JSON.stringify(
|
|
238
|
+
actual: JSON.stringify(compress.contextLimit),
|
|
256
239
|
});
|
|
257
240
|
}
|
|
258
241
|
}
|
|
259
|
-
if (
|
|
260
|
-
if (typeof
|
|
261
|
-
|
|
242
|
+
if (compress.modelLimits !== undefined) {
|
|
243
|
+
if (typeof compress.modelLimits !== "object" ||
|
|
244
|
+
compress.modelLimits === null ||
|
|
245
|
+
Array.isArray(compress.modelLimits)) {
|
|
262
246
|
errors.push({
|
|
263
|
-
key: "
|
|
247
|
+
key: "compress.modelLimits",
|
|
264
248
|
expected: "Record<string, number | ${number}%>",
|
|
265
|
-
actual: typeof
|
|
249
|
+
actual: typeof compress.modelLimits,
|
|
266
250
|
});
|
|
267
251
|
}
|
|
268
252
|
else {
|
|
269
|
-
for (const [providerModelKey, limit] of Object.entries(
|
|
253
|
+
for (const [providerModelKey, limit] of Object.entries(compress.modelLimits)) {
|
|
270
254
|
const isValidNumber = typeof limit === "number";
|
|
271
255
|
const isPercentString = typeof limit === "string" && /^\d+(?:\.\d+)?%$/.test(limit);
|
|
272
256
|
if (!isValidNumber && !isPercentString) {
|
|
273
257
|
errors.push({
|
|
274
|
-
key: `
|
|
258
|
+
key: `compress.modelLimits.${providerModelKey}`,
|
|
275
259
|
expected: 'number | "${number}%"',
|
|
276
260
|
actual: JSON.stringify(limit),
|
|
277
261
|
});
|
|
@@ -279,64 +263,26 @@ export function validateConfigTypes(config) {
|
|
|
279
263
|
}
|
|
280
264
|
}
|
|
281
265
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
actual: JSON.stringify(tools.distill.permission),
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
if (tools.distill.showDistillation !== undefined &&
|
|
294
|
-
typeof tools.distill.showDistillation !== "boolean") {
|
|
295
|
-
errors.push({
|
|
296
|
-
key: "tools.distill.showDistillation",
|
|
297
|
-
expected: "boolean",
|
|
298
|
-
actual: typeof tools.distill.showDistillation,
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
if (tools.compress) {
|
|
304
|
-
if (tools.compress.permission !== undefined) {
|
|
305
|
-
const validValues = ["ask", "allow", "deny"];
|
|
306
|
-
if (!validValues.includes(tools.compress.permission)) {
|
|
307
|
-
errors.push({
|
|
308
|
-
key: "tools.compress.permission",
|
|
309
|
-
expected: '"ask" | "allow" | "deny"',
|
|
310
|
-
actual: JSON.stringify(tools.compress.permission),
|
|
311
|
-
});
|
|
312
|
-
}
|
|
266
|
+
const validValues = ["ask", "allow", "deny"];
|
|
267
|
+
if (compress.permission !== undefined && !validValues.includes(compress.permission)) {
|
|
268
|
+
errors.push({
|
|
269
|
+
key: "compress.permission",
|
|
270
|
+
expected: '"ask" | "allow" | "deny"',
|
|
271
|
+
actual: JSON.stringify(compress.permission),
|
|
272
|
+
});
|
|
313
273
|
}
|
|
314
|
-
if (
|
|
315
|
-
typeof
|
|
274
|
+
if (compress.showCompression !== undefined &&
|
|
275
|
+
typeof compress.showCompression !== "boolean") {
|
|
316
276
|
errors.push({
|
|
317
|
-
key: "
|
|
277
|
+
key: "compress.showCompression",
|
|
318
278
|
expected: "boolean",
|
|
319
|
-
actual: typeof
|
|
279
|
+
actual: typeof compress.showCompression,
|
|
320
280
|
});
|
|
321
281
|
}
|
|
322
282
|
}
|
|
323
|
-
if (tools.prune) {
|
|
324
|
-
if (tools.prune.permission !== undefined) {
|
|
325
|
-
const validValues = ["ask", "allow", "deny"];
|
|
326
|
-
if (!validValues.includes(tools.prune.permission)) {
|
|
327
|
-
errors.push({
|
|
328
|
-
key: "tools.prune.permission",
|
|
329
|
-
expected: '"ask" | "allow" | "deny"',
|
|
330
|
-
actual: JSON.stringify(tools.prune.permission),
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
283
|
}
|
|
336
|
-
// Strategies validators
|
|
337
284
|
const strategies = config.strategies;
|
|
338
285
|
if (strategies) {
|
|
339
|
-
// deduplication
|
|
340
286
|
if (strategies.deduplication?.enabled !== undefined &&
|
|
341
287
|
typeof strategies.deduplication.enabled !== "boolean") {
|
|
342
288
|
errors.push({
|
|
@@ -353,7 +299,6 @@ export function validateConfigTypes(config) {
|
|
|
353
299
|
actual: typeof strategies.deduplication.protectedTools,
|
|
354
300
|
});
|
|
355
301
|
}
|
|
356
|
-
// supersedeWrites
|
|
357
302
|
if (strategies.supersedeWrites) {
|
|
358
303
|
if (strategies.supersedeWrites.enabled !== undefined &&
|
|
359
304
|
typeof strategies.supersedeWrites.enabled !== "boolean") {
|
|
@@ -364,7 +309,6 @@ export function validateConfigTypes(config) {
|
|
|
364
309
|
});
|
|
365
310
|
}
|
|
366
311
|
}
|
|
367
|
-
// purgeErrors
|
|
368
312
|
if (strategies.purgeErrors) {
|
|
369
313
|
if (strategies.purgeErrors.enabled !== undefined &&
|
|
370
314
|
typeof strategies.purgeErrors.enabled !== "boolean") {
|
|
@@ -403,7 +347,6 @@ export function validateConfigTypes(config) {
|
|
|
403
347
|
}
|
|
404
348
|
return errors;
|
|
405
349
|
}
|
|
406
|
-
// Show validation warnings for a config file
|
|
407
350
|
function showConfigValidationWarnings(ctx, configPath, configData, isProject) {
|
|
408
351
|
const invalidKeys = getInvalidConfigKeys(configData);
|
|
409
352
|
const typeErrors = validateConfigTypes(configData);
|
|
@@ -429,7 +372,7 @@ function showConfigValidationWarnings(ctx, configPath, configData, isProject) {
|
|
|
429
372
|
try {
|
|
430
373
|
ctx.client.tui.showToast({
|
|
431
374
|
body: {
|
|
432
|
-
title: `DCP:
|
|
375
|
+
title: `DCP: ${configType} warning`,
|
|
433
376
|
message: `${configPath}\n${messages.join("\n")}`,
|
|
434
377
|
variant: "warning",
|
|
435
378
|
duration: 7000,
|
|
@@ -457,24 +400,12 @@ const defaultConfig = {
|
|
|
457
400
|
turns: 4,
|
|
458
401
|
},
|
|
459
402
|
protectedFilePatterns: [],
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
},
|
|
467
|
-
distill: {
|
|
468
|
-
permission: "allow",
|
|
469
|
-
showDistillation: false,
|
|
470
|
-
},
|
|
471
|
-
compress: {
|
|
472
|
-
permission: "deny",
|
|
473
|
-
showCompression: false,
|
|
474
|
-
},
|
|
475
|
-
prune: {
|
|
476
|
-
permission: "allow",
|
|
477
|
-
},
|
|
403
|
+
compress: {
|
|
404
|
+
permission: "allow",
|
|
405
|
+
showCompression: false,
|
|
406
|
+
contextLimit: 100000,
|
|
407
|
+
nudgeFrequency: 5,
|
|
408
|
+
iterationNudgeThreshold: 15,
|
|
478
409
|
},
|
|
479
410
|
strategies: {
|
|
480
411
|
deduplication: {
|
|
@@ -504,50 +435,44 @@ function findOpencodeDir(startDir) {
|
|
|
504
435
|
return candidate;
|
|
505
436
|
}
|
|
506
437
|
const parent = dirname(current);
|
|
507
|
-
if (parent === current)
|
|
438
|
+
if (parent === current) {
|
|
508
439
|
break;
|
|
440
|
+
}
|
|
509
441
|
current = parent;
|
|
510
442
|
}
|
|
511
443
|
return null;
|
|
512
444
|
}
|
|
513
445
|
function getConfigPaths(ctx) {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
globalPath = GLOBAL_CONFIG_PATH_JSON;
|
|
521
|
-
}
|
|
522
|
-
// Custom config directory: $OPENCODE_CONFIG_DIR/dcp.jsonc|json
|
|
523
|
-
let configDirPath = null;
|
|
446
|
+
const global = existsSync(GLOBAL_CONFIG_PATH_JSONC)
|
|
447
|
+
? GLOBAL_CONFIG_PATH_JSONC
|
|
448
|
+
: existsSync(GLOBAL_CONFIG_PATH_JSON)
|
|
449
|
+
? GLOBAL_CONFIG_PATH_JSON
|
|
450
|
+
: null;
|
|
451
|
+
let configDir = null;
|
|
524
452
|
const opencodeConfigDir = process.env.OPENCODE_CONFIG_DIR;
|
|
525
453
|
if (opencodeConfigDir) {
|
|
526
454
|
const configJsonc = join(opencodeConfigDir, "dcp.jsonc");
|
|
527
455
|
const configJson = join(opencodeConfigDir, "dcp.json");
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
}
|
|
456
|
+
configDir = existsSync(configJsonc)
|
|
457
|
+
? configJsonc
|
|
458
|
+
: existsSync(configJson)
|
|
459
|
+
? configJson
|
|
460
|
+
: null;
|
|
534
461
|
}
|
|
535
|
-
|
|
536
|
-
let projectPath = null;
|
|
462
|
+
let project = null;
|
|
537
463
|
if (ctx?.directory) {
|
|
538
464
|
const opencodeDir = findOpencodeDir(ctx.directory);
|
|
539
465
|
if (opencodeDir) {
|
|
540
466
|
const projectJsonc = join(opencodeDir, "dcp.jsonc");
|
|
541
467
|
const projectJson = join(opencodeDir, "dcp.json");
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
}
|
|
468
|
+
project = existsSync(projectJsonc)
|
|
469
|
+
? projectJsonc
|
|
470
|
+
: existsSync(projectJson)
|
|
471
|
+
? projectJson
|
|
472
|
+
: null;
|
|
548
473
|
}
|
|
549
474
|
}
|
|
550
|
-
return { global
|
|
475
|
+
return { global, configDir, project };
|
|
551
476
|
}
|
|
552
477
|
function createDefaultConfig() {
|
|
553
478
|
if (!existsSync(GLOBAL_CONFIG_DIR)) {
|
|
@@ -560,16 +485,15 @@ function createDefaultConfig() {
|
|
|
560
485
|
writeFileSync(GLOBAL_CONFIG_PATH_JSONC, configContent, "utf-8");
|
|
561
486
|
}
|
|
562
487
|
function loadConfigFile(configPath) {
|
|
563
|
-
let fileContent;
|
|
488
|
+
let fileContent = "";
|
|
564
489
|
try {
|
|
565
490
|
fileContent = readFileSync(configPath, "utf-8");
|
|
566
491
|
}
|
|
567
492
|
catch {
|
|
568
|
-
// File doesn't exist or can't be read - not a parse error
|
|
569
493
|
return { data: null };
|
|
570
494
|
}
|
|
571
495
|
try {
|
|
572
|
-
const parsed = parse(fileContent);
|
|
496
|
+
const parsed = parse(fileContent, undefined, { allowTrailingComma: true });
|
|
573
497
|
if (parsed === undefined || parsed === null) {
|
|
574
498
|
return { data: null, parseError: "Config file is empty or invalid" };
|
|
575
499
|
}
|
|
@@ -580,8 +504,9 @@ function loadConfigFile(configPath) {
|
|
|
580
504
|
}
|
|
581
505
|
}
|
|
582
506
|
function mergeStrategies(base, override) {
|
|
583
|
-
if (!override)
|
|
507
|
+
if (!override) {
|
|
584
508
|
return base;
|
|
509
|
+
}
|
|
585
510
|
return {
|
|
586
511
|
deduplication: {
|
|
587
512
|
enabled: override.deduplication?.enabled ?? base.deduplication.enabled,
|
|
@@ -607,38 +532,23 @@ function mergeStrategies(base, override) {
|
|
|
607
532
|
},
|
|
608
533
|
};
|
|
609
534
|
}
|
|
610
|
-
function
|
|
611
|
-
if (!override)
|
|
535
|
+
function mergeCompress(base, override) {
|
|
536
|
+
if (!override) {
|
|
612
537
|
return base;
|
|
538
|
+
}
|
|
613
539
|
return {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
...(override.settings?.protectedTools ?? []),
|
|
621
|
-
]),
|
|
622
|
-
],
|
|
623
|
-
contextLimit: override.settings?.contextLimit ?? base.settings.contextLimit,
|
|
624
|
-
modelLimits: override.settings?.modelLimits ?? base.settings.modelLimits,
|
|
625
|
-
},
|
|
626
|
-
distill: {
|
|
627
|
-
permission: override.distill?.permission ?? base.distill.permission,
|
|
628
|
-
showDistillation: override.distill?.showDistillation ?? base.distill.showDistillation,
|
|
629
|
-
},
|
|
630
|
-
compress: {
|
|
631
|
-
permission: override.compress?.permission ?? base.compress.permission,
|
|
632
|
-
showCompression: override.compress?.showCompression ?? base.compress.showCompression,
|
|
633
|
-
},
|
|
634
|
-
prune: {
|
|
635
|
-
permission: override.prune?.permission ?? base.prune.permission,
|
|
636
|
-
},
|
|
540
|
+
permission: override.permission ?? base.permission,
|
|
541
|
+
showCompression: override.showCompression ?? base.showCompression,
|
|
542
|
+
contextLimit: override.contextLimit ?? base.contextLimit,
|
|
543
|
+
modelLimits: override.modelLimits ?? base.modelLimits,
|
|
544
|
+
nudgeFrequency: override.nudgeFrequency ?? base.nudgeFrequency,
|
|
545
|
+
iterationNudgeThreshold: override.iterationNudgeThreshold ?? base.iterationNudgeThreshold,
|
|
637
546
|
};
|
|
638
547
|
}
|
|
639
548
|
function mergeCommands(base, override) {
|
|
640
|
-
if (override
|
|
549
|
+
if (!override) {
|
|
641
550
|
return base;
|
|
551
|
+
}
|
|
642
552
|
return {
|
|
643
553
|
enabled: override.enabled ?? base.enabled,
|
|
644
554
|
protectedTools: [...new Set([...base.protectedTools, ...(override.protectedTools ?? [])])],
|
|
@@ -665,24 +575,16 @@ function deepCloneConfig(config) {
|
|
|
665
575
|
},
|
|
666
576
|
turnProtection: { ...config.turnProtection },
|
|
667
577
|
protectedFilePatterns: [...config.protectedFilePatterns],
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
protectedTools: [...config.tools.settings.protectedTools],
|
|
672
|
-
modelLimits: { ...config.tools.settings.modelLimits },
|
|
673
|
-
},
|
|
674
|
-
distill: { ...config.tools.distill },
|
|
675
|
-
compress: { ...config.tools.compress },
|
|
676
|
-
prune: { ...config.tools.prune },
|
|
578
|
+
compress: {
|
|
579
|
+
...config.compress,
|
|
580
|
+
modelLimits: { ...config.compress.modelLimits },
|
|
677
581
|
},
|
|
678
582
|
strategies: {
|
|
679
583
|
deduplication: {
|
|
680
584
|
...config.strategies.deduplication,
|
|
681
585
|
protectedTools: [...config.strategies.deduplication.protectedTools],
|
|
682
586
|
},
|
|
683
|
-
supersedeWrites: {
|
|
684
|
-
...config.strategies.supersedeWrites,
|
|
685
|
-
},
|
|
587
|
+
supersedeWrites: { ...config.strategies.supersedeWrites },
|
|
686
588
|
purgeErrors: {
|
|
687
589
|
...config.strategies.purgeErrors,
|
|
688
590
|
protectedTools: [...config.strategies.purgeErrors.protectedTools],
|
|
@@ -690,141 +592,65 @@ function deepCloneConfig(config) {
|
|
|
690
592
|
},
|
|
691
593
|
};
|
|
692
594
|
}
|
|
595
|
+
function mergeLayer(config, data) {
|
|
596
|
+
return {
|
|
597
|
+
enabled: data.enabled ?? config.enabled,
|
|
598
|
+
debug: data.debug ?? config.debug,
|
|
599
|
+
pruneNotification: data.pruneNotification ?? config.pruneNotification,
|
|
600
|
+
pruneNotificationType: data.pruneNotificationType ?? config.pruneNotificationType,
|
|
601
|
+
commands: mergeCommands(config.commands, data.commands),
|
|
602
|
+
manualMode: mergeManualMode(config.manualMode, data.manualMode),
|
|
603
|
+
turnProtection: {
|
|
604
|
+
enabled: data.turnProtection?.enabled ?? config.turnProtection.enabled,
|
|
605
|
+
turns: data.turnProtection?.turns ?? config.turnProtection.turns,
|
|
606
|
+
},
|
|
607
|
+
protectedFilePatterns: [
|
|
608
|
+
...new Set([...config.protectedFilePatterns, ...(data.protectedFilePatterns ?? [])]),
|
|
609
|
+
],
|
|
610
|
+
compress: mergeCompress(config.compress, data.compress),
|
|
611
|
+
strategies: mergeStrategies(config.strategies, data.strategies),
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
function scheduleParseWarning(ctx, title, message) {
|
|
615
|
+
setTimeout(() => {
|
|
616
|
+
try {
|
|
617
|
+
ctx.client.tui.showToast({
|
|
618
|
+
body: {
|
|
619
|
+
title,
|
|
620
|
+
message,
|
|
621
|
+
variant: "warning",
|
|
622
|
+
duration: 7000,
|
|
623
|
+
},
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
catch { }
|
|
627
|
+
}, 7000);
|
|
628
|
+
}
|
|
693
629
|
export function getConfig(ctx) {
|
|
694
630
|
let config = deepCloneConfig(defaultConfig);
|
|
695
631
|
const configPaths = getConfigPaths(ctx);
|
|
696
|
-
|
|
697
|
-
if (configPaths.global) {
|
|
698
|
-
const result = loadConfigFile(configPaths.global);
|
|
699
|
-
if (result.parseError) {
|
|
700
|
-
setTimeout(async () => {
|
|
701
|
-
try {
|
|
702
|
-
ctx.client.tui.showToast({
|
|
703
|
-
body: {
|
|
704
|
-
title: "DCP: Invalid config",
|
|
705
|
-
message: `${configPaths.global}\n${result.parseError}\nUsing default values`,
|
|
706
|
-
variant: "warning",
|
|
707
|
-
duration: 7000,
|
|
708
|
-
},
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
catch { }
|
|
712
|
-
}, 7000);
|
|
713
|
-
}
|
|
714
|
-
else if (result.data) {
|
|
715
|
-
// Validate config keys and types
|
|
716
|
-
showConfigValidationWarnings(ctx, configPaths.global, result.data, false);
|
|
717
|
-
config = {
|
|
718
|
-
enabled: result.data.enabled ?? config.enabled,
|
|
719
|
-
debug: result.data.debug ?? config.debug,
|
|
720
|
-
pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
|
|
721
|
-
pruneNotificationType: result.data.pruneNotificationType ?? config.pruneNotificationType,
|
|
722
|
-
commands: mergeCommands(config.commands, result.data.commands),
|
|
723
|
-
manualMode: mergeManualMode(config.manualMode, result.data.manualMode),
|
|
724
|
-
turnProtection: {
|
|
725
|
-
enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
|
|
726
|
-
turns: result.data.turnProtection?.turns ?? config.turnProtection.turns,
|
|
727
|
-
},
|
|
728
|
-
protectedFilePatterns: [
|
|
729
|
-
...new Set([
|
|
730
|
-
...config.protectedFilePatterns,
|
|
731
|
-
...(result.data.protectedFilePatterns ?? []),
|
|
732
|
-
]),
|
|
733
|
-
],
|
|
734
|
-
tools: mergeTools(config.tools, result.data.tools),
|
|
735
|
-
strategies: mergeStrategies(config.strategies, result.data.strategies),
|
|
736
|
-
};
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
else {
|
|
740
|
-
// No config exists, create default
|
|
632
|
+
if (!configPaths.global) {
|
|
741
633
|
createDefaultConfig();
|
|
742
634
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
title: "DCP: Invalid configDir config",
|
|
752
|
-
message: `${configPaths.configDir}\n${result.parseError}\nUsing global/default values`,
|
|
753
|
-
variant: "warning",
|
|
754
|
-
duration: 7000,
|
|
755
|
-
},
|
|
756
|
-
});
|
|
757
|
-
}
|
|
758
|
-
catch { }
|
|
759
|
-
}, 7000);
|
|
760
|
-
}
|
|
761
|
-
else if (result.data) {
|
|
762
|
-
// Validate config keys and types
|
|
763
|
-
showConfigValidationWarnings(ctx, configPaths.configDir, result.data, true);
|
|
764
|
-
config = {
|
|
765
|
-
enabled: result.data.enabled ?? config.enabled,
|
|
766
|
-
debug: result.data.debug ?? config.debug,
|
|
767
|
-
pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
|
|
768
|
-
pruneNotificationType: result.data.pruneNotificationType ?? config.pruneNotificationType,
|
|
769
|
-
commands: mergeCommands(config.commands, result.data.commands),
|
|
770
|
-
manualMode: mergeManualMode(config.manualMode, result.data.manualMode),
|
|
771
|
-
turnProtection: {
|
|
772
|
-
enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
|
|
773
|
-
turns: result.data.turnProtection?.turns ?? config.turnProtection.turns,
|
|
774
|
-
},
|
|
775
|
-
protectedFilePatterns: [
|
|
776
|
-
...new Set([
|
|
777
|
-
...config.protectedFilePatterns,
|
|
778
|
-
...(result.data.protectedFilePatterns ?? []),
|
|
779
|
-
]),
|
|
780
|
-
],
|
|
781
|
-
tools: mergeTools(config.tools, result.data.tools),
|
|
782
|
-
strategies: mergeStrategies(config.strategies, result.data.strategies),
|
|
783
|
-
};
|
|
635
|
+
const layers = [
|
|
636
|
+
{ path: configPaths.global, name: "config", isProject: false },
|
|
637
|
+
{ path: configPaths.configDir, name: "configDir config", isProject: true },
|
|
638
|
+
{ path: configPaths.project, name: "project config", isProject: true },
|
|
639
|
+
];
|
|
640
|
+
for (const layer of layers) {
|
|
641
|
+
if (!layer.path) {
|
|
642
|
+
continue;
|
|
784
643
|
}
|
|
785
|
-
|
|
786
|
-
// Load and merge project config (overrides global)
|
|
787
|
-
if (configPaths.project) {
|
|
788
|
-
const result = loadConfigFile(configPaths.project);
|
|
644
|
+
const result = loadConfigFile(layer.path);
|
|
789
645
|
if (result.parseError) {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
ctx.client.tui.showToast({
|
|
793
|
-
body: {
|
|
794
|
-
title: "DCP: Invalid project config",
|
|
795
|
-
message: `${configPaths.project}\n${result.parseError}\nUsing global/default values`,
|
|
796
|
-
variant: "warning",
|
|
797
|
-
duration: 7000,
|
|
798
|
-
},
|
|
799
|
-
});
|
|
800
|
-
}
|
|
801
|
-
catch { }
|
|
802
|
-
}, 7000);
|
|
646
|
+
scheduleParseWarning(ctx, `DCP: Invalid ${layer.name}`, `${layer.path}\n${result.parseError}\nUsing previous/default values`);
|
|
647
|
+
continue;
|
|
803
648
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
showConfigValidationWarnings(ctx, configPaths.project, result.data, true);
|
|
807
|
-
config = {
|
|
808
|
-
enabled: result.data.enabled ?? config.enabled,
|
|
809
|
-
debug: result.data.debug ?? config.debug,
|
|
810
|
-
pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
|
|
811
|
-
pruneNotificationType: result.data.pruneNotificationType ?? config.pruneNotificationType,
|
|
812
|
-
commands: mergeCommands(config.commands, result.data.commands),
|
|
813
|
-
manualMode: mergeManualMode(config.manualMode, result.data.manualMode),
|
|
814
|
-
turnProtection: {
|
|
815
|
-
enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
|
|
816
|
-
turns: result.data.turnProtection?.turns ?? config.turnProtection.turns,
|
|
817
|
-
},
|
|
818
|
-
protectedFilePatterns: [
|
|
819
|
-
...new Set([
|
|
820
|
-
...config.protectedFilePatterns,
|
|
821
|
-
...(result.data.protectedFilePatterns ?? []),
|
|
822
|
-
]),
|
|
823
|
-
],
|
|
824
|
-
tools: mergeTools(config.tools, result.data.tools),
|
|
825
|
-
strategies: mergeStrategies(config.strategies, result.data.strategies),
|
|
826
|
-
};
|
|
649
|
+
if (!result.data) {
|
|
650
|
+
continue;
|
|
827
651
|
}
|
|
652
|
+
showConfigValidationWarnings(ctx, layer.path, result.data, layer.isProject);
|
|
653
|
+
config = mergeLayer(config, result.data);
|
|
828
654
|
}
|
|
829
655
|
return config;
|
|
830
656
|
}
|