@tuanhung303/opencode-acp 2.1.1 → 2.2.1
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 +131 -71
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/commands/budget.d.ts +15 -0
- package/dist/lib/commands/budget.d.ts.map +1 -0
- package/dist/lib/commands/budget.js +120 -0
- package/dist/lib/commands/budget.js.map +1 -0
- package/dist/lib/commands/context.d.ts +1 -1
- package/dist/lib/commands/context.js +4 -4
- package/dist/lib/commands/context.js.map +1 -1
- package/dist/lib/commands/help.d.ts +2 -2
- package/dist/lib/commands/help.d.ts.map +1 -1
- package/dist/lib/commands/help.js +8 -6
- package/dist/lib/commands/help.js.map +1 -1
- package/dist/lib/commands/protected.d.ts +17 -0
- package/dist/lib/commands/protected.d.ts.map +1 -0
- package/dist/lib/commands/protected.js +50 -0
- package/dist/lib/commands/protected.js.map +1 -0
- package/dist/lib/commands/stats.d.ts +1 -1
- package/dist/lib/commands/stats.d.ts.map +1 -1
- package/dist/lib/commands/stats.js +24 -4
- package/dist/lib/commands/stats.js.map +1 -1
- package/dist/lib/commands/sweep.d.ts +3 -3
- package/dist/lib/commands/sweep.d.ts.map +1 -1
- package/dist/lib/commands/sweep.js +10 -7
- package/dist/lib/commands/sweep.js.map +1 -1
- package/dist/lib/config-schema.d.ts +119 -0
- package/dist/lib/config-schema.d.ts.map +1 -0
- package/dist/lib/config-schema.js +97 -0
- package/dist/lib/config-schema.js.map +1 -0
- package/dist/lib/config.d.ts +7 -30
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +59 -497
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/hooks.d.ts +14 -0
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/hooks.js +126 -19
- package/dist/lib/hooks.js.map +1 -1
- package/dist/lib/logger.d.ts +25 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +46 -5
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/messages/index.d.ts +1 -1
- package/dist/lib/messages/index.d.ts.map +1 -1
- package/dist/lib/messages/index.js +1 -1
- package/dist/lib/messages/index.js.map +1 -1
- package/dist/lib/messages/inject.d.ts +6 -1
- package/dist/lib/messages/inject.d.ts.map +1 -1
- package/dist/lib/messages/inject.js +8 -125
- package/dist/lib/messages/inject.js.map +1 -1
- package/dist/lib/messages/prune.d.ts +8 -0
- package/dist/lib/messages/prune.d.ts.map +1 -1
- package/dist/lib/messages/prune.js +89 -2
- package/dist/lib/messages/prune.js.map +1 -1
- package/dist/lib/messages/utils.d.ts +12 -0
- package/dist/lib/messages/utils.d.ts.map +1 -1
- package/dist/lib/messages/utils.js +34 -0
- package/dist/lib/messages/utils.js.map +1 -1
- package/dist/lib/prompts/discard-tool-spec.d.ts +1 -1
- package/dist/lib/prompts/discard-tool-spec.d.ts.map +1 -1
- package/dist/lib/prompts/discard-tool-spec.js +30 -17
- package/dist/lib/prompts/discard-tool-spec.js.map +1 -1
- package/dist/lib/prompts/extract-tool-spec.d.ts +1 -1
- package/dist/lib/prompts/extract-tool-spec.d.ts.map +1 -1
- package/dist/lib/prompts/extract-tool-spec.js +19 -11
- package/dist/lib/prompts/extract-tool-spec.js.map +1 -1
- package/dist/lib/prompts/index.d.ts.map +1 -1
- package/dist/lib/prompts/index.js +2 -7
- package/dist/lib/prompts/index.js.map +1 -1
- package/dist/lib/prompts/restore-tool-spec.d.ts +2 -0
- package/dist/lib/prompts/restore-tool-spec.d.ts.map +1 -0
- package/dist/lib/prompts/restore-tool-spec.js +37 -0
- package/dist/lib/prompts/restore-tool-spec.js.map +1 -0
- package/dist/lib/prompts/system/both.d.ts +1 -1
- package/dist/lib/prompts/system/both.d.ts.map +1 -1
- package/dist/lib/prompts/system/both.js +20 -16
- package/dist/lib/prompts/system/both.js.map +1 -1
- package/dist/lib/prompts/system/discard.d.ts +1 -1
- package/dist/lib/prompts/system/discard.d.ts.map +1 -1
- package/dist/lib/prompts/system/discard.js +19 -16
- package/dist/lib/prompts/system/discard.js.map +1 -1
- package/dist/lib/prompts/system/extract.d.ts +1 -1
- package/dist/lib/prompts/system/extract.d.ts.map +1 -1
- package/dist/lib/prompts/system/extract.js +19 -16
- package/dist/lib/prompts/system/extract.js.map +1 -1
- package/dist/lib/protected-file-patterns.js +1 -1
- package/dist/lib/protected-file-patterns.js.map +1 -1
- package/dist/lib/safe-execute.d.ts +20 -0
- package/dist/lib/safe-execute.d.ts.map +1 -0
- package/dist/lib/safe-execute.js +38 -0
- package/dist/lib/safe-execute.js.map +1 -0
- package/dist/lib/shared-utils.js +1 -1
- package/dist/lib/shared-utils.js.map +1 -1
- package/dist/lib/state/persistence.d.ts +8 -3
- package/dist/lib/state/persistence.d.ts.map +1 -1
- package/dist/lib/state/persistence.js +62 -4
- 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 +54 -3
- package/dist/lib/state/state.js.map +1 -1
- package/dist/lib/state/tool-cache.d.ts +2 -0
- package/dist/lib/state/tool-cache.d.ts.map +1 -1
- package/dist/lib/state/tool-cache.js +34 -12
- package/dist/lib/state/tool-cache.js.map +1 -1
- package/dist/lib/state/types.d.ts +50 -5
- package/dist/lib/state/types.d.ts.map +1 -1
- package/dist/lib/strategies/deduplication.d.ts +1 -0
- package/dist/lib/strategies/deduplication.d.ts.map +1 -1
- package/dist/lib/strategies/deduplication.js +87 -3
- package/dist/lib/strategies/deduplication.js.map +1 -1
- package/dist/lib/strategies/index.d.ts +1 -5
- package/dist/lib/strategies/index.d.ts.map +1 -1
- package/dist/lib/strategies/index.js +1 -5
- package/dist/lib/strategies/index.js.map +1 -1
- package/dist/lib/strategies/purge-errors.d.ts.map +1 -1
- package/dist/lib/strategies/purge-errors.js +4 -1
- package/dist/lib/strategies/purge-errors.js.map +1 -1
- package/dist/lib/strategies/supersede-writes.d.ts.map +1 -1
- package/dist/lib/strategies/supersede-writes.js +7 -1
- package/dist/lib/strategies/supersede-writes.js.map +1 -1
- package/dist/lib/strategies/tools.d.ts +1 -0
- package/dist/lib/strategies/tools.d.ts.map +1 -1
- package/dist/lib/strategies/tools.js +215 -62
- package/dist/lib/strategies/tools.js.map +1 -1
- package/dist/lib/ui/notification.d.ts +5 -2
- package/dist/lib/ui/notification.d.ts.map +1 -1
- package/dist/lib/ui/notification.js +10 -6
- package/dist/lib/ui/notification.js.map +1 -1
- package/dist/lib/ui/utils.d.ts +3 -3
- package/dist/lib/ui/utils.d.ts.map +1 -1
- package/dist/lib/ui/utils.js +38 -12
- package/dist/lib/ui/utils.js.map +1 -1
- package/package.json +7 -12
- package/dist/lib/prompts/nudge/both.d.ts +0 -2
- package/dist/lib/prompts/nudge/both.d.ts.map +0 -1
- package/dist/lib/prompts/nudge/both.js +0 -11
- package/dist/lib/prompts/nudge/both.js.map +0 -1
- package/dist/lib/prompts/nudge/discard.d.ts +0 -2
- package/dist/lib/prompts/nudge/discard.d.ts.map +0 -1
- package/dist/lib/prompts/nudge/discard.js +0 -10
- package/dist/lib/prompts/nudge/discard.js.map +0 -1
- package/dist/lib/prompts/nudge/extract.d.ts +0 -2
- package/dist/lib/prompts/nudge/extract.d.ts.map +0 -1
- package/dist/lib/prompts/nudge/extract.js +0 -10
- package/dist/lib/prompts/nudge/extract.js.map +0 -1
- package/dist/lib/strategies/head-tail-truncation.d.ts +0 -15
- package/dist/lib/strategies/head-tail-truncation.d.ts.map +0 -1
- package/dist/lib/strategies/head-tail-truncation.js +0 -144
- package/dist/lib/strategies/head-tail-truncation.js.map +0 -1
- package/dist/lib/strategies/placeholder-compression.d.ts +0 -5
- package/dist/lib/strategies/placeholder-compression.d.ts.map +0 -1
- package/dist/lib/strategies/placeholder-compression.js +0 -148
- package/dist/lib/strategies/placeholder-compression.js.map +0 -1
- package/dist/lib/strategies/prune-thinking.d.ts +0 -15
- package/dist/lib/strategies/prune-thinking.d.ts.map +0 -1
- package/dist/lib/strategies/prune-thinking.js +0 -79
- package/dist/lib/strategies/prune-thinking.js.map +0 -1
- package/dist/lib/strategies/read-consolidation.d.ts +0 -21
- package/dist/lib/strategies/read-consolidation.d.ts.map +0 -1
- package/dist/lib/strategies/read-consolidation.js +0 -155
- package/dist/lib/strategies/read-consolidation.js.map +0 -1
package/dist/lib/config.js
CHANGED
|
@@ -2,7 +2,17 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from "fs
|
|
|
2
2
|
import { join, dirname } from "path";
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import { parse } from "jsonc-parser";
|
|
5
|
+
import { validateConfig, getUnknownKeys } from "./config-schema";
|
|
6
|
+
/**
|
|
7
|
+
* Tools that should never be pruned.
|
|
8
|
+
*
|
|
9
|
+
* - `context_info`: Synthetic tool used to inject prunable-tools context
|
|
10
|
+
* for DeepSeek/Kimi models. Must be protected to prevent self-pruning
|
|
11
|
+
* which would break the context management feedback loop.
|
|
12
|
+
* See lib/messages/utils.ts createSyntheticToolPart()
|
|
13
|
+
*/
|
|
5
14
|
const DEFAULT_PROTECTED_TOOLS = [
|
|
15
|
+
"context_info", // Synthetic tool for context injection
|
|
6
16
|
"task",
|
|
7
17
|
"todowrite",
|
|
8
18
|
"todoread",
|
|
@@ -14,424 +24,33 @@ const DEFAULT_PROTECTED_TOOLS = [
|
|
|
14
24
|
"plan_enter",
|
|
15
25
|
"plan_exit",
|
|
16
26
|
];
|
|
17
|
-
//
|
|
18
|
-
export const VALID_CONFIG_KEYS = new Set([
|
|
19
|
-
// Top-level keys
|
|
20
|
-
"$schema",
|
|
21
|
-
"enabled",
|
|
22
|
-
"debug",
|
|
23
|
-
"showUpdateToasts", // Deprecated but kept for backwards compatibility
|
|
24
|
-
"pruneNotification",
|
|
25
|
-
"turnProtection",
|
|
26
|
-
"turnProtection.enabled",
|
|
27
|
-
"turnProtection.turns",
|
|
28
|
-
"protectedFilePatterns",
|
|
29
|
-
"commands",
|
|
30
|
-
"commands.enabled",
|
|
31
|
-
"commands.protectedTools",
|
|
32
|
-
"tools",
|
|
33
|
-
"tools.settings",
|
|
34
|
-
"tools.settings.nudgeEnabled",
|
|
35
|
-
"tools.settings.nudgeFrequency",
|
|
36
|
-
"tools.settings.protectedTools",
|
|
37
|
-
"tools.discard",
|
|
38
|
-
"tools.discard.enabled",
|
|
39
|
-
"tools.extract",
|
|
40
|
-
"tools.extract.enabled",
|
|
41
|
-
"tools.extract.showDistillation",
|
|
42
|
-
"strategies",
|
|
43
|
-
// strategies.deduplication
|
|
44
|
-
"strategies.deduplication",
|
|
45
|
-
"strategies.deduplication.enabled",
|
|
46
|
-
"strategies.deduplication.protectedTools",
|
|
47
|
-
// strategies.supersedeWrites
|
|
48
|
-
"strategies.supersedeWrites",
|
|
49
|
-
"strategies.supersedeWrites.enabled",
|
|
50
|
-
// strategies.purgeErrors
|
|
51
|
-
"strategies.purgeErrors",
|
|
52
|
-
"strategies.purgeErrors.enabled",
|
|
53
|
-
"strategies.purgeErrors.turns",
|
|
54
|
-
"strategies.purgeErrors.protectedTools",
|
|
55
|
-
// strategies.pruneThinking
|
|
56
|
-
"strategies.pruneThinking",
|
|
57
|
-
"strategies.pruneThinking.enabled",
|
|
58
|
-
"strategies.pruneThinking.delayTurns",
|
|
59
|
-
// strategies.placeholderCompression
|
|
60
|
-
"strategies.placeholderCompression",
|
|
61
|
-
"strategies.placeholderCompression.enabled",
|
|
62
|
-
"strategies.placeholderCompression.delayTurns",
|
|
63
|
-
"strategies.placeholderCompression.minOutputTokens",
|
|
64
|
-
"strategies.placeholderCompression.protectedTools",
|
|
65
|
-
// strategies.headTailTruncation
|
|
66
|
-
"strategies.headTailTruncation",
|
|
67
|
-
"strategies.headTailTruncation.enabled",
|
|
68
|
-
"strategies.headTailTruncation.delayTurns",
|
|
69
|
-
"strategies.headTailTruncation.headRatio",
|
|
70
|
-
"strategies.headTailTruncation.tailRatio",
|
|
71
|
-
"strategies.headTailTruncation.protectedTools",
|
|
72
|
-
// strategies.readConsolidation
|
|
73
|
-
"strategies.readConsolidation",
|
|
74
|
-
"strategies.readConsolidation.enabled",
|
|
75
|
-
"strategies.readConsolidation.tools",
|
|
76
|
-
]);
|
|
77
|
-
// Extract all key paths from a config object for validation
|
|
78
|
-
function getConfigKeyPaths(obj, prefix = "") {
|
|
79
|
-
const keys = [];
|
|
80
|
-
for (const key of Object.keys(obj)) {
|
|
81
|
-
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
82
|
-
keys.push(fullKey);
|
|
83
|
-
if (obj[key] && typeof obj[key] === "object" && !Array.isArray(obj[key])) {
|
|
84
|
-
keys.push(...getConfigKeyPaths(obj[key], fullKey));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return keys;
|
|
88
|
-
}
|
|
89
|
-
// Returns invalid keys found in user config
|
|
90
|
-
export function getInvalidConfigKeys(userConfig) {
|
|
91
|
-
const userKeys = getConfigKeyPaths(userConfig);
|
|
92
|
-
return userKeys.filter((key) => !VALID_CONFIG_KEYS.has(key));
|
|
93
|
-
}
|
|
94
|
-
function validateConfigTypes(config) {
|
|
95
|
-
const errors = [];
|
|
96
|
-
// Top-level validators
|
|
97
|
-
if (config.enabled !== undefined && typeof config.enabled !== "boolean") {
|
|
98
|
-
errors.push({ key: "enabled", expected: "boolean", actual: typeof config.enabled });
|
|
99
|
-
}
|
|
100
|
-
if (config.debug !== undefined && typeof config.debug !== "boolean") {
|
|
101
|
-
errors.push({ key: "debug", expected: "boolean", actual: typeof config.debug });
|
|
102
|
-
}
|
|
103
|
-
if (config.pruneNotification !== undefined) {
|
|
104
|
-
const validValues = ["off", "minimal", "detailed"];
|
|
105
|
-
if (!validValues.includes(config.pruneNotification)) {
|
|
106
|
-
errors.push({
|
|
107
|
-
key: "pruneNotification",
|
|
108
|
-
expected: '"off" | "minimal" | "detailed"',
|
|
109
|
-
actual: JSON.stringify(config.pruneNotification),
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (config.protectedFilePatterns !== undefined) {
|
|
114
|
-
if (!Array.isArray(config.protectedFilePatterns)) {
|
|
115
|
-
errors.push({
|
|
116
|
-
key: "protectedFilePatterns",
|
|
117
|
-
expected: "string[]",
|
|
118
|
-
actual: typeof config.protectedFilePatterns,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
else if (!config.protectedFilePatterns.every((v) => typeof v === "string")) {
|
|
122
|
-
errors.push({
|
|
123
|
-
key: "protectedFilePatterns",
|
|
124
|
-
expected: "string[]",
|
|
125
|
-
actual: "non-string entries",
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
// Top-level turnProtection validator
|
|
130
|
-
if (config.turnProtection) {
|
|
131
|
-
if (config.turnProtection.enabled !== undefined &&
|
|
132
|
-
typeof config.turnProtection.enabled !== "boolean") {
|
|
133
|
-
errors.push({
|
|
134
|
-
key: "turnProtection.enabled",
|
|
135
|
-
expected: "boolean",
|
|
136
|
-
actual: typeof config.turnProtection.enabled,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
if (config.turnProtection.turns !== undefined &&
|
|
140
|
-
typeof config.turnProtection.turns !== "number") {
|
|
141
|
-
errors.push({
|
|
142
|
-
key: "turnProtection.turns",
|
|
143
|
-
expected: "number",
|
|
144
|
-
actual: typeof config.turnProtection.turns,
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
// Commands validator
|
|
149
|
-
const commands = config.commands;
|
|
150
|
-
if (commands !== undefined) {
|
|
151
|
-
if (typeof commands === "object") {
|
|
152
|
-
if (commands.enabled !== undefined && typeof commands.enabled !== "boolean") {
|
|
153
|
-
errors.push({
|
|
154
|
-
key: "commands.enabled",
|
|
155
|
-
expected: "boolean",
|
|
156
|
-
actual: typeof commands.enabled,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
if (commands.protectedTools !== undefined && !Array.isArray(commands.protectedTools)) {
|
|
160
|
-
errors.push({
|
|
161
|
-
key: "commands.protectedTools",
|
|
162
|
-
expected: "string[]",
|
|
163
|
-
actual: typeof commands.protectedTools,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
errors.push({
|
|
169
|
-
key: "commands",
|
|
170
|
-
expected: "{ enabled: boolean, protectedTools: string[] }",
|
|
171
|
-
actual: typeof commands,
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
// Tools validators
|
|
176
|
-
const tools = config.tools;
|
|
177
|
-
if (tools) {
|
|
178
|
-
if (tools.settings) {
|
|
179
|
-
if (tools.settings.nudgeEnabled !== undefined &&
|
|
180
|
-
typeof tools.settings.nudgeEnabled !== "boolean") {
|
|
181
|
-
errors.push({
|
|
182
|
-
key: "tools.settings.nudgeEnabled",
|
|
183
|
-
expected: "boolean",
|
|
184
|
-
actual: typeof tools.settings.nudgeEnabled,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
if (tools.settings.nudgeFrequency !== undefined &&
|
|
188
|
-
typeof tools.settings.nudgeFrequency !== "number") {
|
|
189
|
-
errors.push({
|
|
190
|
-
key: "tools.settings.nudgeFrequency",
|
|
191
|
-
expected: "number",
|
|
192
|
-
actual: typeof tools.settings.nudgeFrequency,
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
if (tools.settings.protectedTools !== undefined &&
|
|
196
|
-
!Array.isArray(tools.settings.protectedTools)) {
|
|
197
|
-
errors.push({
|
|
198
|
-
key: "tools.settings.protectedTools",
|
|
199
|
-
expected: "string[]",
|
|
200
|
-
actual: typeof tools.settings.protectedTools,
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (tools.discard) {
|
|
205
|
-
if (tools.discard.enabled !== undefined && typeof tools.discard.enabled !== "boolean") {
|
|
206
|
-
errors.push({
|
|
207
|
-
key: "tools.discard.enabled",
|
|
208
|
-
expected: "boolean",
|
|
209
|
-
actual: typeof tools.discard.enabled,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (tools.extract) {
|
|
214
|
-
if (tools.extract.enabled !== undefined && typeof tools.extract.enabled !== "boolean") {
|
|
215
|
-
errors.push({
|
|
216
|
-
key: "tools.extract.enabled",
|
|
217
|
-
expected: "boolean",
|
|
218
|
-
actual: typeof tools.extract.enabled,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
if (tools.extract.showDistillation !== undefined &&
|
|
222
|
-
typeof tools.extract.showDistillation !== "boolean") {
|
|
223
|
-
errors.push({
|
|
224
|
-
key: "tools.extract.showDistillation",
|
|
225
|
-
expected: "boolean",
|
|
226
|
-
actual: typeof tools.extract.showDistillation,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
// Strategies validators
|
|
232
|
-
const strategies = config.strategies;
|
|
233
|
-
if (strategies) {
|
|
234
|
-
// deduplication
|
|
235
|
-
if (strategies.deduplication?.enabled !== undefined &&
|
|
236
|
-
typeof strategies.deduplication.enabled !== "boolean") {
|
|
237
|
-
errors.push({
|
|
238
|
-
key: "strategies.deduplication.enabled",
|
|
239
|
-
expected: "boolean",
|
|
240
|
-
actual: typeof strategies.deduplication.enabled,
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
if (strategies.deduplication?.protectedTools !== undefined &&
|
|
244
|
-
!Array.isArray(strategies.deduplication.protectedTools)) {
|
|
245
|
-
errors.push({
|
|
246
|
-
key: "strategies.deduplication.protectedTools",
|
|
247
|
-
expected: "string[]",
|
|
248
|
-
actual: typeof strategies.deduplication.protectedTools,
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
// supersedeWrites
|
|
252
|
-
if (strategies.supersedeWrites) {
|
|
253
|
-
if (strategies.supersedeWrites.enabled !== undefined &&
|
|
254
|
-
typeof strategies.supersedeWrites.enabled !== "boolean") {
|
|
255
|
-
errors.push({
|
|
256
|
-
key: "strategies.supersedeWrites.enabled",
|
|
257
|
-
expected: "boolean",
|
|
258
|
-
actual: typeof strategies.supersedeWrites.enabled,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
// purgeErrors
|
|
263
|
-
if (strategies.purgeErrors) {
|
|
264
|
-
if (strategies.purgeErrors.enabled !== undefined &&
|
|
265
|
-
typeof strategies.purgeErrors.enabled !== "boolean") {
|
|
266
|
-
errors.push({
|
|
267
|
-
key: "strategies.purgeErrors.enabled",
|
|
268
|
-
expected: "boolean",
|
|
269
|
-
actual: typeof strategies.purgeErrors.enabled,
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
if (strategies.purgeErrors.turns !== undefined &&
|
|
273
|
-
typeof strategies.purgeErrors.turns !== "number") {
|
|
274
|
-
errors.push({
|
|
275
|
-
key: "strategies.purgeErrors.turns",
|
|
276
|
-
expected: "number",
|
|
277
|
-
actual: typeof strategies.purgeErrors.turns,
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
if (strategies.purgeErrors.protectedTools !== undefined &&
|
|
281
|
-
!Array.isArray(strategies.purgeErrors.protectedTools)) {
|
|
282
|
-
errors.push({
|
|
283
|
-
key: "strategies.purgeErrors.protectedTools",
|
|
284
|
-
expected: "string[]",
|
|
285
|
-
actual: typeof strategies.purgeErrors.protectedTools,
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
// pruneThinking
|
|
290
|
-
if (strategies.pruneThinking) {
|
|
291
|
-
if (strategies.pruneThinking.enabled !== undefined &&
|
|
292
|
-
typeof strategies.pruneThinking.enabled !== "boolean") {
|
|
293
|
-
errors.push({
|
|
294
|
-
key: "strategies.pruneThinking.enabled",
|
|
295
|
-
expected: "boolean",
|
|
296
|
-
actual: typeof strategies.pruneThinking.enabled,
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
if (strategies.pruneThinking.delayTurns !== undefined &&
|
|
300
|
-
typeof strategies.pruneThinking.delayTurns !== "number") {
|
|
301
|
-
errors.push({
|
|
302
|
-
key: "strategies.pruneThinking.delayTurns",
|
|
303
|
-
expected: "number",
|
|
304
|
-
actual: typeof strategies.pruneThinking.delayTurns,
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
// placeholderCompression
|
|
309
|
-
if (strategies.placeholderCompression) {
|
|
310
|
-
if (strategies.placeholderCompression.enabled !== undefined &&
|
|
311
|
-
typeof strategies.placeholderCompression.enabled !== "boolean") {
|
|
312
|
-
errors.push({
|
|
313
|
-
key: "strategies.placeholderCompression.enabled",
|
|
314
|
-
expected: "boolean",
|
|
315
|
-
actual: typeof strategies.placeholderCompression.enabled,
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
if (strategies.placeholderCompression.delayTurns !== undefined &&
|
|
319
|
-
typeof strategies.placeholderCompression.delayTurns !== "number") {
|
|
320
|
-
errors.push({
|
|
321
|
-
key: "strategies.placeholderCompression.delayTurns",
|
|
322
|
-
expected: "number",
|
|
323
|
-
actual: typeof strategies.placeholderCompression.delayTurns,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
if (strategies.placeholderCompression.minOutputTokens !== undefined &&
|
|
327
|
-
typeof strategies.placeholderCompression.minOutputTokens !== "number") {
|
|
328
|
-
errors.push({
|
|
329
|
-
key: "strategies.placeholderCompression.minOutputTokens",
|
|
330
|
-
expected: "number",
|
|
331
|
-
actual: typeof strategies.placeholderCompression.minOutputTokens,
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
if (strategies.placeholderCompression.protectedTools !== undefined &&
|
|
335
|
-
!Array.isArray(strategies.placeholderCompression.protectedTools)) {
|
|
336
|
-
errors.push({
|
|
337
|
-
key: "strategies.placeholderCompression.protectedTools",
|
|
338
|
-
expected: "string[]",
|
|
339
|
-
actual: typeof strategies.placeholderCompression.protectedTools,
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
// headTailTruncation
|
|
344
|
-
if (strategies.headTailTruncation) {
|
|
345
|
-
if (strategies.headTailTruncation.enabled !== undefined &&
|
|
346
|
-
typeof strategies.headTailTruncation.enabled !== "boolean") {
|
|
347
|
-
errors.push({
|
|
348
|
-
key: "strategies.headTailTruncation.enabled",
|
|
349
|
-
expected: "boolean",
|
|
350
|
-
actual: typeof strategies.headTailTruncation.enabled,
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
if (strategies.headTailTruncation.delayTurns !== undefined &&
|
|
354
|
-
typeof strategies.headTailTruncation.delayTurns !== "number") {
|
|
355
|
-
errors.push({
|
|
356
|
-
key: "strategies.headTailTruncation.delayTurns",
|
|
357
|
-
expected: "number",
|
|
358
|
-
actual: typeof strategies.headTailTruncation.delayTurns,
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
if (strategies.headTailTruncation.headRatio !== undefined &&
|
|
362
|
-
typeof strategies.headTailTruncation.headRatio !== "number") {
|
|
363
|
-
errors.push({
|
|
364
|
-
key: "strategies.headTailTruncation.headRatio",
|
|
365
|
-
expected: "number",
|
|
366
|
-
actual: typeof strategies.headTailTruncation.headRatio,
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
if (strategies.headTailTruncation.tailRatio !== undefined &&
|
|
370
|
-
typeof strategies.headTailTruncation.tailRatio !== "number") {
|
|
371
|
-
errors.push({
|
|
372
|
-
key: "strategies.headTailTruncation.tailRatio",
|
|
373
|
-
expected: "number",
|
|
374
|
-
actual: typeof strategies.headTailTruncation.tailRatio,
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
if (strategies.headTailTruncation.protectedTools !== undefined &&
|
|
378
|
-
!Array.isArray(strategies.headTailTruncation.protectedTools)) {
|
|
379
|
-
errors.push({
|
|
380
|
-
key: "strategies.headTailTruncation.protectedTools",
|
|
381
|
-
expected: "string[]",
|
|
382
|
-
actual: typeof strategies.headTailTruncation.protectedTools,
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
// readConsolidation
|
|
387
|
-
if (strategies.readConsolidation) {
|
|
388
|
-
if (strategies.readConsolidation.enabled !== undefined &&
|
|
389
|
-
typeof strategies.readConsolidation.enabled !== "boolean") {
|
|
390
|
-
errors.push({
|
|
391
|
-
key: "strategies.readConsolidation.enabled",
|
|
392
|
-
expected: "boolean",
|
|
393
|
-
actual: typeof strategies.readConsolidation.enabled,
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
if (strategies.readConsolidation.tools !== undefined &&
|
|
397
|
-
!Array.isArray(strategies.readConsolidation.tools)) {
|
|
398
|
-
errors.push({
|
|
399
|
-
key: "strategies.readConsolidation.tools",
|
|
400
|
-
expected: "string[]",
|
|
401
|
-
actual: typeof strategies.readConsolidation.tools,
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
return errors;
|
|
407
|
-
}
|
|
408
|
-
// Show validation warnings for a config file
|
|
27
|
+
// Show validation warnings for a config file using Zod schema
|
|
409
28
|
function showConfigValidationWarnings(ctx, configPath, configData, isProject) {
|
|
410
|
-
const
|
|
411
|
-
const
|
|
412
|
-
if (
|
|
29
|
+
const validationErrors = validateConfig(configData);
|
|
30
|
+
const unknownKeys = getUnknownKeys(configData);
|
|
31
|
+
if (validationErrors.length === 0 && unknownKeys.length === 0) {
|
|
413
32
|
return;
|
|
414
33
|
}
|
|
415
34
|
const configType = isProject ? "project config" : "config";
|
|
416
35
|
const messages = [];
|
|
417
|
-
if (
|
|
418
|
-
const keyList =
|
|
419
|
-
const suffix =
|
|
36
|
+
if (unknownKeys.length > 0) {
|
|
37
|
+
const keyList = unknownKeys.slice(0, 3).join(", ");
|
|
38
|
+
const suffix = unknownKeys.length > 3 ? ` (+${unknownKeys.length - 3} more)` : "";
|
|
420
39
|
messages.push(`Unknown keys: ${keyList}${suffix}`);
|
|
421
40
|
}
|
|
422
|
-
if (
|
|
423
|
-
for (const err of
|
|
424
|
-
messages.push(
|
|
41
|
+
if (validationErrors.length > 0) {
|
|
42
|
+
for (const err of validationErrors.slice(0, 2)) {
|
|
43
|
+
messages.push(err);
|
|
425
44
|
}
|
|
426
|
-
if (
|
|
427
|
-
messages.push(`(+${
|
|
45
|
+
if (validationErrors.length > 2) {
|
|
46
|
+
messages.push(`(+${validationErrors.length - 2} more validation errors)`);
|
|
428
47
|
}
|
|
429
48
|
}
|
|
430
49
|
setTimeout(() => {
|
|
431
50
|
try {
|
|
432
51
|
ctx.client.tui.showToast({
|
|
433
52
|
body: {
|
|
434
|
-
title: `
|
|
53
|
+
title: `ACP: Invalid ${configType}`,
|
|
435
54
|
message: `${configPath}\n${messages.join("\n")}`,
|
|
436
55
|
variant: "warning",
|
|
437
56
|
duration: 7000,
|
|
@@ -441,10 +60,11 @@ function showConfigValidationWarnings(ctx, configPath, configData, isProject) {
|
|
|
441
60
|
catch { }
|
|
442
61
|
}, 7000);
|
|
443
62
|
}
|
|
444
|
-
|
|
63
|
+
const defaultConfig = {
|
|
445
64
|
enabled: true,
|
|
446
65
|
debug: false,
|
|
447
66
|
pruneNotification: "detailed",
|
|
67
|
+
autoPruneAfterTool: true,
|
|
448
68
|
commands: {
|
|
449
69
|
enabled: true,
|
|
450
70
|
protectedTools: [...DEFAULT_PROTECTED_TOOLS],
|
|
@@ -453,11 +73,22 @@ export const DEFAULT_CONFIG = {
|
|
|
453
73
|
enabled: false,
|
|
454
74
|
turns: 4,
|
|
455
75
|
},
|
|
456
|
-
protectedFilePatterns: [
|
|
76
|
+
protectedFilePatterns: [
|
|
77
|
+
// Environment and secrets
|
|
78
|
+
"**/.env",
|
|
79
|
+
"**/.env.*",
|
|
80
|
+
"**/credentials.json",
|
|
81
|
+
"**/secrets.json",
|
|
82
|
+
"**/*.pem",
|
|
83
|
+
"**/*.key",
|
|
84
|
+
// Config files users likely want to keep visible
|
|
85
|
+
"**/package.json",
|
|
86
|
+
"**/tsconfig.json",
|
|
87
|
+
"**/pyproject.toml",
|
|
88
|
+
"**/Cargo.toml",
|
|
89
|
+
],
|
|
457
90
|
tools: {
|
|
458
91
|
settings: {
|
|
459
|
-
nudgeEnabled: true,
|
|
460
|
-
nudgeFrequency: 5,
|
|
461
92
|
protectedTools: [...DEFAULT_PROTECTED_TOOLS],
|
|
462
93
|
},
|
|
463
94
|
discard: {
|
|
@@ -474,39 +105,18 @@ export const DEFAULT_CONFIG = {
|
|
|
474
105
|
protectedTools: [],
|
|
475
106
|
},
|
|
476
107
|
supersedeWrites: {
|
|
477
|
-
enabled: true,
|
|
478
|
-
},
|
|
479
|
-
purgeErrors: {
|
|
480
|
-
enabled: true,
|
|
481
|
-
turns: 2,
|
|
482
|
-
protectedTools: [],
|
|
483
|
-
},
|
|
484
|
-
pruneThinking: {
|
|
485
|
-
enabled: true,
|
|
486
|
-
delayTurns: 1,
|
|
487
|
-
},
|
|
488
|
-
placeholderCompression: {
|
|
489
108
|
enabled: false,
|
|
490
|
-
delayTurns: 2,
|
|
491
|
-
minOutputTokens: 100,
|
|
492
|
-
protectedTools: [],
|
|
493
109
|
},
|
|
494
|
-
|
|
110
|
+
purgeErrors: {
|
|
495
111
|
enabled: true,
|
|
496
|
-
|
|
497
|
-
headRatio: 0.2,
|
|
498
|
-
tailRatio: 0.3,
|
|
112
|
+
turns: 4,
|
|
499
113
|
protectedTools: [],
|
|
500
114
|
},
|
|
501
|
-
readConsolidation: {
|
|
502
|
-
enabled: true,
|
|
503
|
-
tools: ["read", "glob", "grep", "webfetch", "bash"],
|
|
504
|
-
},
|
|
505
115
|
},
|
|
506
116
|
};
|
|
507
117
|
const GLOBAL_CONFIG_DIR = join(homedir(), ".config", "opencode");
|
|
508
|
-
const GLOBAL_CONFIG_PATH_JSONC = join(GLOBAL_CONFIG_DIR, "
|
|
509
|
-
const GLOBAL_CONFIG_PATH_JSON = join(GLOBAL_CONFIG_DIR, "
|
|
118
|
+
const GLOBAL_CONFIG_PATH_JSONC = join(GLOBAL_CONFIG_DIR, "acp.jsonc");
|
|
119
|
+
const GLOBAL_CONFIG_PATH_JSON = join(GLOBAL_CONFIG_DIR, "acp.json");
|
|
510
120
|
function findOpencodeDir(startDir) {
|
|
511
121
|
let current = startDir;
|
|
512
122
|
while (current !== "/") {
|
|
@@ -522,7 +132,7 @@ function findOpencodeDir(startDir) {
|
|
|
522
132
|
return null;
|
|
523
133
|
}
|
|
524
134
|
function getConfigPaths(ctx) {
|
|
525
|
-
// Global: ~/.config/opencode/
|
|
135
|
+
// Global: ~/.config/opencode/acp.jsonc|json
|
|
526
136
|
let globalPath = null;
|
|
527
137
|
if (existsSync(GLOBAL_CONFIG_PATH_JSONC)) {
|
|
528
138
|
globalPath = GLOBAL_CONFIG_PATH_JSONC;
|
|
@@ -530,12 +140,12 @@ function getConfigPaths(ctx) {
|
|
|
530
140
|
else if (existsSync(GLOBAL_CONFIG_PATH_JSON)) {
|
|
531
141
|
globalPath = GLOBAL_CONFIG_PATH_JSON;
|
|
532
142
|
}
|
|
533
|
-
// Custom config directory: $OPENCODE_CONFIG_DIR/
|
|
143
|
+
// Custom config directory: $OPENCODE_CONFIG_DIR/acp.jsonc|json
|
|
534
144
|
let configDirPath = null;
|
|
535
145
|
const opencodeConfigDir = process.env.OPENCODE_CONFIG_DIR;
|
|
536
146
|
if (opencodeConfigDir) {
|
|
537
|
-
const configJsonc = join(opencodeConfigDir, "
|
|
538
|
-
const configJson = join(opencodeConfigDir, "
|
|
147
|
+
const configJsonc = join(opencodeConfigDir, "acp.jsonc");
|
|
148
|
+
const configJson = join(opencodeConfigDir, "acp.json");
|
|
539
149
|
if (existsSync(configJsonc)) {
|
|
540
150
|
configDirPath = configJsonc;
|
|
541
151
|
}
|
|
@@ -543,13 +153,13 @@ function getConfigPaths(ctx) {
|
|
|
543
153
|
configDirPath = configJson;
|
|
544
154
|
}
|
|
545
155
|
}
|
|
546
|
-
// Project: <project>/.opencode/
|
|
156
|
+
// Project: <project>/.opencode/acp.jsonc|json
|
|
547
157
|
let projectPath = null;
|
|
548
158
|
if (ctx?.directory) {
|
|
549
159
|
const opencodeDir = findOpencodeDir(ctx.directory);
|
|
550
160
|
if (opencodeDir) {
|
|
551
|
-
const projectJsonc = join(opencodeDir, "
|
|
552
|
-
const projectJson = join(opencodeDir, "
|
|
161
|
+
const projectJsonc = join(opencodeDir, "acp.jsonc");
|
|
162
|
+
const projectJson = join(opencodeDir, "acp.json");
|
|
553
163
|
if (existsSync(projectJsonc)) {
|
|
554
164
|
projectPath = projectJsonc;
|
|
555
165
|
}
|
|
@@ -565,7 +175,7 @@ function createDefaultConfig() {
|
|
|
565
175
|
mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
566
176
|
}
|
|
567
177
|
const configContent = `{
|
|
568
|
-
"$schema": "https://raw.githubusercontent.com/
|
|
178
|
+
"$schema": "https://raw.githubusercontent.com/opencode-acp/opencode-acp/master/acp.schema.json"
|
|
569
179
|
}
|
|
570
180
|
`;
|
|
571
181
|
writeFileSync(GLOBAL_CONFIG_PATH_JSONC, configContent, "utf-8");
|
|
@@ -616,39 +226,6 @@ function mergeStrategies(base, override) {
|
|
|
616
226
|
]),
|
|
617
227
|
],
|
|
618
228
|
},
|
|
619
|
-
pruneThinking: {
|
|
620
|
-
enabled: override.pruneThinking?.enabled ?? base.pruneThinking.enabled,
|
|
621
|
-
delayTurns: override.pruneThinking?.delayTurns ?? base.pruneThinking.delayTurns,
|
|
622
|
-
},
|
|
623
|
-
placeholderCompression: {
|
|
624
|
-
enabled: override.placeholderCompression?.enabled ?? base.placeholderCompression.enabled,
|
|
625
|
-
delayTurns: override.placeholderCompression?.delayTurns ??
|
|
626
|
-
base.placeholderCompression.delayTurns,
|
|
627
|
-
minOutputTokens: override.placeholderCompression?.minOutputTokens ??
|
|
628
|
-
base.placeholderCompression.minOutputTokens,
|
|
629
|
-
protectedTools: [
|
|
630
|
-
...new Set([
|
|
631
|
-
...base.placeholderCompression.protectedTools,
|
|
632
|
-
...(override.placeholderCompression?.protectedTools ?? []),
|
|
633
|
-
]),
|
|
634
|
-
],
|
|
635
|
-
},
|
|
636
|
-
headTailTruncation: {
|
|
637
|
-
enabled: override.headTailTruncation?.enabled ?? base.headTailTruncation.enabled,
|
|
638
|
-
delayTurns: override.headTailTruncation?.delayTurns ?? base.headTailTruncation.delayTurns,
|
|
639
|
-
headRatio: override.headTailTruncation?.headRatio ?? base.headTailTruncation.headRatio,
|
|
640
|
-
tailRatio: override.headTailTruncation?.tailRatio ?? base.headTailTruncation.tailRatio,
|
|
641
|
-
protectedTools: [
|
|
642
|
-
...new Set([
|
|
643
|
-
...base.headTailTruncation.protectedTools,
|
|
644
|
-
...(override.headTailTruncation?.protectedTools ?? []),
|
|
645
|
-
]),
|
|
646
|
-
],
|
|
647
|
-
},
|
|
648
|
-
readConsolidation: {
|
|
649
|
-
enabled: override.readConsolidation?.enabled ?? base.readConsolidation.enabled,
|
|
650
|
-
tools: override.readConsolidation?.tools ?? base.readConsolidation.tools,
|
|
651
|
-
},
|
|
652
229
|
};
|
|
653
230
|
}
|
|
654
231
|
function mergeTools(base, override) {
|
|
@@ -656,8 +233,6 @@ function mergeTools(base, override) {
|
|
|
656
233
|
return base;
|
|
657
234
|
return {
|
|
658
235
|
settings: {
|
|
659
|
-
nudgeEnabled: override.settings?.nudgeEnabled ?? base.settings.nudgeEnabled,
|
|
660
|
-
nudgeFrequency: override.settings?.nudgeFrequency ?? base.settings.nudgeFrequency,
|
|
661
236
|
protectedTools: [
|
|
662
237
|
...new Set([
|
|
663
238
|
...base.settings.protectedTools,
|
|
@@ -693,7 +268,6 @@ function deepCloneConfig(config) {
|
|
|
693
268
|
protectedFilePatterns: [...config.protectedFilePatterns],
|
|
694
269
|
tools: {
|
|
695
270
|
settings: {
|
|
696
|
-
...config.tools.settings,
|
|
697
271
|
protectedTools: [...config.tools.settings.protectedTools],
|
|
698
272
|
},
|
|
699
273
|
discard: { ...config.tools.discard },
|
|
@@ -711,26 +285,11 @@ function deepCloneConfig(config) {
|
|
|
711
285
|
...config.strategies.purgeErrors,
|
|
712
286
|
protectedTools: [...config.strategies.purgeErrors.protectedTools],
|
|
713
287
|
},
|
|
714
|
-
pruneThinking: {
|
|
715
|
-
...config.strategies.pruneThinking,
|
|
716
|
-
},
|
|
717
|
-
placeholderCompression: {
|
|
718
|
-
...config.strategies.placeholderCompression,
|
|
719
|
-
protectedTools: [...config.strategies.placeholderCompression.protectedTools],
|
|
720
|
-
},
|
|
721
|
-
headTailTruncation: {
|
|
722
|
-
...config.strategies.headTailTruncation,
|
|
723
|
-
protectedTools: [...config.strategies.headTailTruncation.protectedTools],
|
|
724
|
-
},
|
|
725
|
-
readConsolidation: {
|
|
726
|
-
...config.strategies.readConsolidation,
|
|
727
|
-
tools: [...config.strategies.readConsolidation.tools],
|
|
728
|
-
},
|
|
729
288
|
},
|
|
730
289
|
};
|
|
731
290
|
}
|
|
732
291
|
export function getConfig(ctx) {
|
|
733
|
-
let config = deepCloneConfig(
|
|
292
|
+
let config = deepCloneConfig(defaultConfig);
|
|
734
293
|
const configPaths = getConfigPaths(ctx);
|
|
735
294
|
// Load and merge global config
|
|
736
295
|
if (configPaths.global) {
|
|
@@ -740,7 +299,7 @@ export function getConfig(ctx) {
|
|
|
740
299
|
try {
|
|
741
300
|
ctx.client.tui.showToast({
|
|
742
301
|
body: {
|
|
743
|
-
title: "
|
|
302
|
+
title: "ACP: Invalid config",
|
|
744
303
|
message: `${configPaths.global}\n${result.parseError}\nUsing default values`,
|
|
745
304
|
variant: "warning",
|
|
746
305
|
duration: 7000,
|
|
@@ -757,6 +316,7 @@ export function getConfig(ctx) {
|
|
|
757
316
|
enabled: result.data.enabled ?? config.enabled,
|
|
758
317
|
debug: result.data.debug ?? config.debug,
|
|
759
318
|
pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
|
|
319
|
+
autoPruneAfterTool: result.data.autoPruneAfterTool ?? config.autoPruneAfterTool,
|
|
760
320
|
commands: mergeCommands(config.commands, result.data.commands),
|
|
761
321
|
turnProtection: {
|
|
762
322
|
enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
|
|
@@ -777,7 +337,7 @@ export function getConfig(ctx) {
|
|
|
777
337
|
// No config exists, create default
|
|
778
338
|
createDefaultConfig();
|
|
779
339
|
}
|
|
780
|
-
// Load and merge $OPENCODE_CONFIG_DIR/
|
|
340
|
+
// Load and merge $OPENCODE_CONFIG_DIR/acp.jsonc|json (overrides global)
|
|
781
341
|
if (configPaths.configDir) {
|
|
782
342
|
const result = loadConfigFile(configPaths.configDir);
|
|
783
343
|
if (result.parseError) {
|
|
@@ -785,7 +345,7 @@ export function getConfig(ctx) {
|
|
|
785
345
|
try {
|
|
786
346
|
ctx.client.tui.showToast({
|
|
787
347
|
body: {
|
|
788
|
-
title: "
|
|
348
|
+
title: "ACP: Invalid configDir config",
|
|
789
349
|
message: `${configPaths.configDir}\n${result.parseError}\nUsing global/default values`,
|
|
790
350
|
variant: "warning",
|
|
791
351
|
duration: 7000,
|
|
@@ -802,6 +362,7 @@ export function getConfig(ctx) {
|
|
|
802
362
|
enabled: result.data.enabled ?? config.enabled,
|
|
803
363
|
debug: result.data.debug ?? config.debug,
|
|
804
364
|
pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
|
|
365
|
+
autoPruneAfterTool: result.data.autoPruneAfterTool ?? config.autoPruneAfterTool,
|
|
805
366
|
commands: mergeCommands(config.commands, result.data.commands),
|
|
806
367
|
turnProtection: {
|
|
807
368
|
enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
|
|
@@ -826,7 +387,7 @@ export function getConfig(ctx) {
|
|
|
826
387
|
try {
|
|
827
388
|
ctx.client.tui.showToast({
|
|
828
389
|
body: {
|
|
829
|
-
title: "
|
|
390
|
+
title: "ACP: Invalid project config",
|
|
830
391
|
message: `${configPaths.project}\n${result.parseError}\nUsing global/default values`,
|
|
831
392
|
variant: "warning",
|
|
832
393
|
duration: 7000,
|
|
@@ -843,6 +404,7 @@ export function getConfig(ctx) {
|
|
|
843
404
|
enabled: result.data.enabled ?? config.enabled,
|
|
844
405
|
debug: result.data.debug ?? config.debug,
|
|
845
406
|
pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
|
|
407
|
+
autoPruneAfterTool: result.data.autoPruneAfterTool ?? config.autoPruneAfterTool,
|
|
846
408
|
commands: mergeCommands(config.commands, result.data.commands),
|
|
847
409
|
turnProtection: {
|
|
848
410
|
enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
|