@p4r4d0xb0x/opencode-dcp 3.0.5

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.
Files changed (203) hide show
  1. package/LICENSE +619 -0
  2. package/README.md +229 -0
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +88 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/auth.d.ts +4 -0
  8. package/dist/lib/auth.d.ts.map +1 -0
  9. package/dist/lib/auth.js +32 -0
  10. package/dist/lib/auth.js.map +1 -0
  11. package/dist/lib/commands/context.d.ts +52 -0
  12. package/dist/lib/commands/context.d.ts.map +1 -0
  13. package/dist/lib/commands/context.js +241 -0
  14. package/dist/lib/commands/context.js.map +1 -0
  15. package/dist/lib/commands/decompress.d.ts +12 -0
  16. package/dist/lib/commands/decompress.d.ts.map +1 -0
  17. package/dist/lib/commands/decompress.js +159 -0
  18. package/dist/lib/commands/decompress.js.map +1 -0
  19. package/dist/lib/commands/help.d.ts +17 -0
  20. package/dist/lib/commands/help.d.ts.map +1 -0
  21. package/dist/lib/commands/help.js +52 -0
  22. package/dist/lib/commands/help.js.map +1 -0
  23. package/dist/lib/commands/manual.d.ts +22 -0
  24. package/dist/lib/commands/manual.d.ts.map +1 -0
  25. package/dist/lib/commands/manual.js +48 -0
  26. package/dist/lib/commands/manual.js.map +1 -0
  27. package/dist/lib/commands/recompress.d.ts +12 -0
  28. package/dist/lib/commands/recompress.d.ts.map +1 -0
  29. package/dist/lib/commands/recompress.js +137 -0
  30. package/dist/lib/commands/recompress.js.map +1 -0
  31. package/dist/lib/commands/stats.d.ts +15 -0
  32. package/dist/lib/commands/stats.d.ts.map +1 -0
  33. package/dist/lib/commands/stats.js +62 -0
  34. package/dist/lib/commands/stats.js.map +1 -0
  35. package/dist/lib/commands/sweep.d.ts +23 -0
  36. package/dist/lib/commands/sweep.d.ts.map +1 -0
  37. package/dist/lib/commands/sweep.js +194 -0
  38. package/dist/lib/commands/sweep.js.map +1 -0
  39. package/dist/lib/config.d.ts +72 -0
  40. package/dist/lib/config.d.ts.map +1 -0
  41. package/dist/lib/config.js +766 -0
  42. package/dist/lib/config.js.map +1 -0
  43. package/dist/lib/hooks.d.ts +33 -0
  44. package/dist/lib/hooks.d.ts.map +1 -0
  45. package/dist/lib/hooks.js +195 -0
  46. package/dist/lib/hooks.js.map +1 -0
  47. package/dist/lib/host-permissions.d.ts +11 -0
  48. package/dist/lib/host-permissions.d.ts.map +1 -0
  49. package/dist/lib/host-permissions.js +58 -0
  50. package/dist/lib/host-permissions.js.map +1 -0
  51. package/dist/lib/logger.d.ts +31 -0
  52. package/dist/lib/logger.d.ts.map +1 -0
  53. package/dist/lib/logger.js +204 -0
  54. package/dist/lib/logger.js.map +1 -0
  55. package/dist/lib/message-ids.d.ts +19 -0
  56. package/dist/lib/message-ids.d.ts.map +1 -0
  57. package/dist/lib/message-ids.js +112 -0
  58. package/dist/lib/message-ids.js.map +1 -0
  59. package/dist/lib/messages/index.d.ts +7 -0
  60. package/dist/lib/messages/index.d.ts.map +1 -0
  61. package/dist/lib/messages/index.js +7 -0
  62. package/dist/lib/messages/index.js.map +1 -0
  63. package/dist/lib/messages/inject/inject.d.ts +7 -0
  64. package/dist/lib/messages/inject/inject.d.ts.map +1 -0
  65. package/dist/lib/messages/inject/inject.js +131 -0
  66. package/dist/lib/messages/inject/inject.js.map +1 -0
  67. package/dist/lib/messages/inject/subagent-results.d.ts +4 -0
  68. package/dist/lib/messages/inject/subagent-results.d.ts.map +1 -0
  69. package/dist/lib/messages/inject/subagent-results.js +58 -0
  70. package/dist/lib/messages/inject/subagent-results.js.map +1 -0
  71. package/dist/lib/messages/inject/utils.d.ts +25 -0
  72. package/dist/lib/messages/inject/utils.d.ts.map +1 -0
  73. package/dist/lib/messages/inject/utils.js +198 -0
  74. package/dist/lib/messages/inject/utils.js.map +1 -0
  75. package/dist/lib/messages/prune.d.ts +5 -0
  76. package/dist/lib/messages/prune.d.ts.map +1 -0
  77. package/dist/lib/messages/prune.js +177 -0
  78. package/dist/lib/messages/prune.js.map +1 -0
  79. package/dist/lib/messages/reasoning-strip.d.ts +8 -0
  80. package/dist/lib/messages/reasoning-strip.d.ts.map +1 -0
  81. package/dist/lib/messages/reasoning-strip.js +33 -0
  82. package/dist/lib/messages/reasoning-strip.js.map +1 -0
  83. package/dist/lib/messages/sync.d.ts +4 -0
  84. package/dist/lib/messages/sync.d.ts.map +1 -0
  85. package/dist/lib/messages/sync.js +93 -0
  86. package/dist/lib/messages/sync.js.map +1 -0
  87. package/dist/lib/messages/utils.d.ts +21 -0
  88. package/dist/lib/messages/utils.d.ts.map +1 -0
  89. package/dist/lib/messages/utils.js +118 -0
  90. package/dist/lib/messages/utils.js.map +1 -0
  91. package/dist/lib/prompts/compress.d.ts +2 -0
  92. package/dist/lib/prompts/compress.d.ts.map +1 -0
  93. package/dist/lib/prompts/compress.js +85 -0
  94. package/dist/lib/prompts/compress.js.map +1 -0
  95. package/dist/lib/prompts/context-limit-nudge.d.ts +2 -0
  96. package/dist/lib/prompts/context-limit-nudge.d.ts.map +1 -0
  97. package/dist/lib/prompts/context-limit-nudge.js +25 -0
  98. package/dist/lib/prompts/context-limit-nudge.js.map +1 -0
  99. package/dist/lib/prompts/index.d.ts +3 -0
  100. package/dist/lib/prompts/index.d.ts.map +1 -0
  101. package/dist/lib/prompts/index.js +19 -0
  102. package/dist/lib/prompts/index.js.map +1 -0
  103. package/dist/lib/prompts/internal-overlays.d.ts +5 -0
  104. package/dist/lib/prompts/internal-overlays.d.ts.map +1 -0
  105. package/dist/lib/prompts/internal-overlays.js +43 -0
  106. package/dist/lib/prompts/internal-overlays.js.map +1 -0
  107. package/dist/lib/prompts/iteration-nudge.d.ts +2 -0
  108. package/dist/lib/prompts/iteration-nudge.d.ts.map +1 -0
  109. package/dist/lib/prompts/iteration-nudge.js +9 -0
  110. package/dist/lib/prompts/iteration-nudge.js.map +1 -0
  111. package/dist/lib/prompts/store.d.ts +24 -0
  112. package/dist/lib/prompts/store.d.ts.map +1 -0
  113. package/dist/lib/prompts/store.js +346 -0
  114. package/dist/lib/prompts/store.js.map +1 -0
  115. package/dist/lib/prompts/system.d.ts +2 -0
  116. package/dist/lib/prompts/system.d.ts.map +1 -0
  117. package/dist/lib/prompts/system.js +30 -0
  118. package/dist/lib/prompts/system.js.map +1 -0
  119. package/dist/lib/prompts/turn-nudge.d.ts +2 -0
  120. package/dist/lib/prompts/turn-nudge.d.ts.map +1 -0
  121. package/dist/lib/prompts/turn-nudge.js +12 -0
  122. package/dist/lib/prompts/turn-nudge.js.map +1 -0
  123. package/dist/lib/protected-patterns.d.ts +5 -0
  124. package/dist/lib/protected-patterns.d.ts.map +1 -0
  125. package/dist/lib/protected-patterns.js +107 -0
  126. package/dist/lib/protected-patterns.js.map +1 -0
  127. package/dist/lib/shared-utils.d.ts +8 -0
  128. package/dist/lib/shared-utils.d.ts.map +1 -0
  129. package/dist/lib/shared-utils.js +30 -0
  130. package/dist/lib/shared-utils.js.map +1 -0
  131. package/dist/lib/state/index.d.ts +4 -0
  132. package/dist/lib/state/index.d.ts.map +1 -0
  133. package/dist/lib/state/index.js +4 -0
  134. package/dist/lib/state/index.js.map +1 -0
  135. package/dist/lib/state/persistence.d.ts +41 -0
  136. package/dist/lib/state/persistence.d.ts.map +1 -0
  137. package/dist/lib/state/persistence.js +174 -0
  138. package/dist/lib/state/persistence.js.map +1 -0
  139. package/dist/lib/state/state.d.ts +7 -0
  140. package/dist/lib/state/state.d.ts.map +1 -0
  141. package/dist/lib/state/state.js +134 -0
  142. package/dist/lib/state/state.js.map +1 -0
  143. package/dist/lib/state/tool-cache.d.ts +13 -0
  144. package/dist/lib/state/tool-cache.d.ts.map +1 -0
  145. package/dist/lib/state/tool-cache.js +69 -0
  146. package/dist/lib/state/tool-cache.js.map +1 -0
  147. package/dist/lib/state/types.d.ts +90 -0
  148. package/dist/lib/state/types.d.ts.map +1 -0
  149. package/dist/lib/state/types.js +2 -0
  150. package/dist/lib/state/types.js.map +1 -0
  151. package/dist/lib/state/utils.d.ts +18 -0
  152. package/dist/lib/state/utils.d.ts.map +1 -0
  153. package/dist/lib/state/utils.js +196 -0
  154. package/dist/lib/state/utils.js.map +1 -0
  155. package/dist/lib/strategies/deduplication.d.ts +10 -0
  156. package/dist/lib/strategies/deduplication.d.ts.map +1 -0
  157. package/dist/lib/strategies/deduplication.js +100 -0
  158. package/dist/lib/strategies/deduplication.js.map +1 -0
  159. package/dist/lib/strategies/index.d.ts +4 -0
  160. package/dist/lib/strategies/index.d.ts.map +1 -0
  161. package/dist/lib/strategies/index.js +4 -0
  162. package/dist/lib/strategies/index.js.map +1 -0
  163. package/dist/lib/strategies/purge-errors.d.ts +13 -0
  164. package/dist/lib/strategies/purge-errors.d.ts.map +1 -0
  165. package/dist/lib/strategies/purge-errors.js +62 -0
  166. package/dist/lib/strategies/purge-errors.js.map +1 -0
  167. package/dist/lib/strategies/supersede-writes.d.ts +13 -0
  168. package/dist/lib/strategies/supersede-writes.d.ts.map +1 -0
  169. package/dist/lib/strategies/supersede-writes.js +94 -0
  170. package/dist/lib/strategies/supersede-writes.js.map +1 -0
  171. package/dist/lib/strategies/utils.d.ts +21 -0
  172. package/dist/lib/strategies/utils.d.ts.map +1 -0
  173. package/dist/lib/strategies/utils.js +128 -0
  174. package/dist/lib/strategies/utils.js.map +1 -0
  175. package/dist/lib/subagents/subagent-results.d.ts +5 -0
  176. package/dist/lib/subagents/subagent-results.d.ts.map +1 -0
  177. package/dist/lib/subagents/subagent-results.js +52 -0
  178. package/dist/lib/subagents/subagent-results.js.map +1 -0
  179. package/dist/lib/tools/compress.d.ts +4 -0
  180. package/dist/lib/tools/compress.d.ts.map +1 -0
  181. package/dist/lib/tools/compress.js +110 -0
  182. package/dist/lib/tools/compress.js.map +1 -0
  183. package/dist/lib/tools/index.d.ts +3 -0
  184. package/dist/lib/tools/index.d.ts.map +1 -0
  185. package/dist/lib/tools/index.js +2 -0
  186. package/dist/lib/tools/index.js.map +1 -0
  187. package/dist/lib/tools/types.d.ts +13 -0
  188. package/dist/lib/tools/types.d.ts.map +1 -0
  189. package/dist/lib/tools/types.js +2 -0
  190. package/dist/lib/tools/types.js.map +1 -0
  191. package/dist/lib/tools/utils.d.ts +80 -0
  192. package/dist/lib/tools/utils.d.ts.map +1 -0
  193. package/dist/lib/tools/utils.js +675 -0
  194. package/dist/lib/tools/utils.js.map +1 -0
  195. package/dist/lib/ui/notification.d.ts +10 -0
  196. package/dist/lib/ui/notification.d.ts.map +1 -0
  197. package/dist/lib/ui/notification.js +182 -0
  198. package/dist/lib/ui/notification.js.map +1 -0
  199. package/dist/lib/ui/utils.d.ts +10 -0
  200. package/dist/lib/ui/utils.d.ts.map +1 -0
  201. package/dist/lib/ui/utils.js +255 -0
  202. package/dist/lib/ui/utils.js.map +1 -0
  203. package/package.json +61 -0
@@ -0,0 +1,766 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { homedir } from "os";
4
+ import { parse } from "jsonc-parser";
5
+ const DEFAULT_PROTECTED_TOOLS = [
6
+ "task",
7
+ "skill",
8
+ "todowrite",
9
+ "todoread",
10
+ "compress",
11
+ "batch",
12
+ "plan_enter",
13
+ "plan_exit",
14
+ "write",
15
+ "edit",
16
+ ];
17
+ const COMPRESS_DEFAULT_PROTECTED_TOOLS = ["task", "skill", "todowrite", "todoread"];
18
+ export const VALID_CONFIG_KEYS = new Set([
19
+ "$schema",
20
+ "enabled",
21
+ "debug",
22
+ "showUpdateToasts",
23
+ "pruneNotification",
24
+ "pruneNotificationType",
25
+ "turnProtection",
26
+ "turnProtection.enabled",
27
+ "turnProtection.turns",
28
+ "experimental",
29
+ "experimental.allowSubAgents",
30
+ "experimental.customPrompts",
31
+ "protectedFilePatterns",
32
+ "commands",
33
+ "commands.enabled",
34
+ "commands.protectedTools",
35
+ "manualMode",
36
+ "manualMode.enabled",
37
+ "manualMode.automaticStrategies",
38
+ "compress",
39
+ "compress.permission",
40
+ "compress.showCompression",
41
+ "compress.maxContextLimit",
42
+ "compress.minContextLimit",
43
+ "compress.modelMaxLimits",
44
+ "compress.modelMinLimits",
45
+ "compress.nudgeFrequency",
46
+ "compress.iterationNudgeThreshold",
47
+ "compress.nudgeForce",
48
+ "compress.flatSchema",
49
+ "compress.protectedTools",
50
+ "compress.protectUserMessages",
51
+ "strategies",
52
+ "strategies.deduplication",
53
+ "strategies.deduplication.enabled",
54
+ "strategies.deduplication.protectedTools",
55
+ "strategies.supersedeWrites",
56
+ "strategies.supersedeWrites.enabled",
57
+ "strategies.purgeErrors",
58
+ "strategies.purgeErrors.enabled",
59
+ "strategies.purgeErrors.turns",
60
+ "strategies.purgeErrors.protectedTools",
61
+ ]);
62
+ function getConfigKeyPaths(obj, prefix = "") {
63
+ const keys = [];
64
+ for (const key of Object.keys(obj)) {
65
+ const fullKey = prefix ? `${prefix}.${key}` : key;
66
+ keys.push(fullKey);
67
+ // model*Limits are dynamic maps keyed by providerID/modelID; do not recurse into arbitrary IDs.
68
+ if (fullKey === "compress.modelMaxLimits" || fullKey === "compress.modelMinLimits") {
69
+ continue;
70
+ }
71
+ if (obj[key] && typeof obj[key] === "object" && !Array.isArray(obj[key])) {
72
+ keys.push(...getConfigKeyPaths(obj[key], fullKey));
73
+ }
74
+ }
75
+ return keys;
76
+ }
77
+ export function getInvalidConfigKeys(userConfig) {
78
+ const userKeys = getConfigKeyPaths(userConfig);
79
+ return userKeys.filter((key) => !VALID_CONFIG_KEYS.has(key));
80
+ }
81
+ export function validateConfigTypes(config) {
82
+ const errors = [];
83
+ if (config.enabled !== undefined && typeof config.enabled !== "boolean") {
84
+ errors.push({ key: "enabled", expected: "boolean", actual: typeof config.enabled });
85
+ }
86
+ if (config.debug !== undefined && typeof config.debug !== "boolean") {
87
+ errors.push({ key: "debug", expected: "boolean", actual: typeof config.debug });
88
+ }
89
+ if (config.pruneNotification !== undefined) {
90
+ const validValues = ["off", "minimal", "detailed"];
91
+ if (!validValues.includes(config.pruneNotification)) {
92
+ errors.push({
93
+ key: "pruneNotification",
94
+ expected: '"off" | "minimal" | "detailed"',
95
+ actual: JSON.stringify(config.pruneNotification),
96
+ });
97
+ }
98
+ }
99
+ if (config.pruneNotificationType !== undefined) {
100
+ const validValues = ["chat", "toast"];
101
+ if (!validValues.includes(config.pruneNotificationType)) {
102
+ errors.push({
103
+ key: "pruneNotificationType",
104
+ expected: '"chat" | "toast"',
105
+ actual: JSON.stringify(config.pruneNotificationType),
106
+ });
107
+ }
108
+ }
109
+ if (config.protectedFilePatterns !== undefined) {
110
+ if (!Array.isArray(config.protectedFilePatterns)) {
111
+ errors.push({
112
+ key: "protectedFilePatterns",
113
+ expected: "string[]",
114
+ actual: typeof config.protectedFilePatterns,
115
+ });
116
+ }
117
+ else if (!config.protectedFilePatterns.every((v) => typeof v === "string")) {
118
+ errors.push({
119
+ key: "protectedFilePatterns",
120
+ expected: "string[]",
121
+ actual: "non-string entries",
122
+ });
123
+ }
124
+ }
125
+ if (config.turnProtection) {
126
+ if (config.turnProtection.enabled !== undefined &&
127
+ typeof config.turnProtection.enabled !== "boolean") {
128
+ errors.push({
129
+ key: "turnProtection.enabled",
130
+ expected: "boolean",
131
+ actual: typeof config.turnProtection.enabled,
132
+ });
133
+ }
134
+ if (config.turnProtection.turns !== undefined &&
135
+ typeof config.turnProtection.turns !== "number") {
136
+ errors.push({
137
+ key: "turnProtection.turns",
138
+ expected: "number",
139
+ actual: typeof config.turnProtection.turns,
140
+ });
141
+ }
142
+ if (typeof config.turnProtection.turns === "number" && config.turnProtection.turns < 1) {
143
+ errors.push({
144
+ key: "turnProtection.turns",
145
+ expected: "positive number (>= 1)",
146
+ actual: `${config.turnProtection.turns}`,
147
+ });
148
+ }
149
+ }
150
+ const experimental = config.experimental;
151
+ if (experimental !== undefined) {
152
+ if (typeof experimental !== "object" ||
153
+ experimental === null ||
154
+ Array.isArray(experimental)) {
155
+ errors.push({
156
+ key: "experimental",
157
+ expected: "object",
158
+ actual: typeof experimental,
159
+ });
160
+ }
161
+ else {
162
+ if (experimental.allowSubAgents !== undefined &&
163
+ typeof experimental.allowSubAgents !== "boolean") {
164
+ errors.push({
165
+ key: "experimental.allowSubAgents",
166
+ expected: "boolean",
167
+ actual: typeof experimental.allowSubAgents,
168
+ });
169
+ }
170
+ if (experimental.customPrompts !== undefined &&
171
+ typeof experimental.customPrompts !== "boolean") {
172
+ errors.push({
173
+ key: "experimental.customPrompts",
174
+ expected: "boolean",
175
+ actual: typeof experimental.customPrompts,
176
+ });
177
+ }
178
+ }
179
+ }
180
+ const commands = config.commands;
181
+ if (commands !== undefined) {
182
+ if (typeof commands !== "object" || commands === null || Array.isArray(commands)) {
183
+ errors.push({
184
+ key: "commands",
185
+ expected: "object",
186
+ actual: typeof commands,
187
+ });
188
+ }
189
+ else {
190
+ if (commands.enabled !== undefined && typeof commands.enabled !== "boolean") {
191
+ errors.push({
192
+ key: "commands.enabled",
193
+ expected: "boolean",
194
+ actual: typeof commands.enabled,
195
+ });
196
+ }
197
+ if (commands.protectedTools !== undefined && !Array.isArray(commands.protectedTools)) {
198
+ errors.push({
199
+ key: "commands.protectedTools",
200
+ expected: "string[]",
201
+ actual: typeof commands.protectedTools,
202
+ });
203
+ }
204
+ }
205
+ }
206
+ const manualMode = config.manualMode;
207
+ if (manualMode !== undefined) {
208
+ if (typeof manualMode !== "object" || manualMode === null || Array.isArray(manualMode)) {
209
+ errors.push({
210
+ key: "manualMode",
211
+ expected: "object",
212
+ actual: typeof manualMode,
213
+ });
214
+ }
215
+ else {
216
+ if (manualMode.enabled !== undefined && typeof manualMode.enabled !== "boolean") {
217
+ errors.push({
218
+ key: "manualMode.enabled",
219
+ expected: "boolean",
220
+ actual: typeof manualMode.enabled,
221
+ });
222
+ }
223
+ if (manualMode.automaticStrategies !== undefined &&
224
+ typeof manualMode.automaticStrategies !== "boolean") {
225
+ errors.push({
226
+ key: "manualMode.automaticStrategies",
227
+ expected: "boolean",
228
+ actual: typeof manualMode.automaticStrategies,
229
+ });
230
+ }
231
+ }
232
+ }
233
+ const compress = config.compress;
234
+ if (compress !== undefined) {
235
+ if (typeof compress !== "object" || compress === null || Array.isArray(compress)) {
236
+ errors.push({
237
+ key: "compress",
238
+ expected: "object",
239
+ actual: typeof compress,
240
+ });
241
+ }
242
+ else {
243
+ if (compress.nudgeFrequency !== undefined &&
244
+ typeof compress.nudgeFrequency !== "number") {
245
+ errors.push({
246
+ key: "compress.nudgeFrequency",
247
+ expected: "number",
248
+ actual: typeof compress.nudgeFrequency,
249
+ });
250
+ }
251
+ if (typeof compress.nudgeFrequency === "number" && compress.nudgeFrequency < 1) {
252
+ errors.push({
253
+ key: "compress.nudgeFrequency",
254
+ expected: "positive number (>= 1)",
255
+ actual: `${compress.nudgeFrequency} (will be clamped to 1)`,
256
+ });
257
+ }
258
+ if (compress.iterationNudgeThreshold !== undefined &&
259
+ typeof compress.iterationNudgeThreshold !== "number") {
260
+ errors.push({
261
+ key: "compress.iterationNudgeThreshold",
262
+ expected: "number",
263
+ actual: typeof compress.iterationNudgeThreshold,
264
+ });
265
+ }
266
+ if (compress.nudgeForce !== undefined &&
267
+ compress.nudgeForce !== "strong" &&
268
+ compress.nudgeForce !== "soft") {
269
+ errors.push({
270
+ key: "compress.nudgeForce",
271
+ expected: '"strong" | "soft"',
272
+ actual: JSON.stringify(compress.nudgeForce),
273
+ });
274
+ }
275
+ if (compress.flatSchema !== undefined && typeof compress.flatSchema !== "boolean") {
276
+ errors.push({
277
+ key: "compress.flatSchema",
278
+ expected: "boolean",
279
+ actual: typeof compress.flatSchema,
280
+ });
281
+ }
282
+ if (compress.protectedTools !== undefined && !Array.isArray(compress.protectedTools)) {
283
+ errors.push({
284
+ key: "compress.protectedTools",
285
+ expected: "string[]",
286
+ actual: typeof compress.protectedTools,
287
+ });
288
+ }
289
+ if (compress.protectUserMessages !== undefined &&
290
+ typeof compress.protectUserMessages !== "boolean") {
291
+ errors.push({
292
+ key: "compress.protectUserMessages",
293
+ expected: "boolean",
294
+ actual: typeof compress.protectUserMessages,
295
+ });
296
+ }
297
+ if (typeof compress.iterationNudgeThreshold === "number" &&
298
+ compress.iterationNudgeThreshold < 1) {
299
+ errors.push({
300
+ key: "compress.iterationNudgeThreshold",
301
+ expected: "positive number (>= 1)",
302
+ actual: `${compress.iterationNudgeThreshold} (will be clamped to 1)`,
303
+ });
304
+ }
305
+ const validateLimitValue = (key, value, actualValue = value) => {
306
+ const isValidNumber = typeof value === "number";
307
+ const isPercentString = typeof value === "string" && value.endsWith("%");
308
+ if (!isValidNumber && !isPercentString) {
309
+ errors.push({
310
+ key,
311
+ expected: 'number | "${number}%"',
312
+ actual: JSON.stringify(actualValue),
313
+ });
314
+ }
315
+ };
316
+ const validateModelLimits = (key, limits) => {
317
+ if (limits === undefined) {
318
+ return;
319
+ }
320
+ if (typeof limits !== "object" || limits === null || Array.isArray(limits)) {
321
+ errors.push({
322
+ key,
323
+ expected: "Record<string, number | ${number}%>",
324
+ actual: typeof limits,
325
+ });
326
+ return;
327
+ }
328
+ for (const [providerModelKey, limit] of Object.entries(limits)) {
329
+ const isValidNumber = typeof limit === "number";
330
+ const isPercentString = typeof limit === "string" && /^\d+(?:\.\d+)?%$/.test(limit);
331
+ if (!isValidNumber && !isPercentString) {
332
+ errors.push({
333
+ key: `${key}.${providerModelKey}`,
334
+ expected: 'number | "${number}%"',
335
+ actual: JSON.stringify(limit),
336
+ });
337
+ }
338
+ }
339
+ };
340
+ if (compress.maxContextLimit !== undefined) {
341
+ validateLimitValue("compress.maxContextLimit", compress.maxContextLimit);
342
+ }
343
+ if (compress.minContextLimit !== undefined) {
344
+ validateLimitValue("compress.minContextLimit", compress.minContextLimit);
345
+ }
346
+ validateModelLimits("compress.modelMaxLimits", compress.modelMaxLimits);
347
+ validateModelLimits("compress.modelMinLimits", compress.modelMinLimits);
348
+ const validValues = ["ask", "allow", "deny"];
349
+ if (compress.permission !== undefined && !validValues.includes(compress.permission)) {
350
+ errors.push({
351
+ key: "compress.permission",
352
+ expected: '"ask" | "allow" | "deny"',
353
+ actual: JSON.stringify(compress.permission),
354
+ });
355
+ }
356
+ if (compress.showCompression !== undefined &&
357
+ typeof compress.showCompression !== "boolean") {
358
+ errors.push({
359
+ key: "compress.showCompression",
360
+ expected: "boolean",
361
+ actual: typeof compress.showCompression,
362
+ });
363
+ }
364
+ }
365
+ }
366
+ const strategies = config.strategies;
367
+ if (strategies) {
368
+ if (strategies.deduplication?.enabled !== undefined &&
369
+ typeof strategies.deduplication.enabled !== "boolean") {
370
+ errors.push({
371
+ key: "strategies.deduplication.enabled",
372
+ expected: "boolean",
373
+ actual: typeof strategies.deduplication.enabled,
374
+ });
375
+ }
376
+ if (strategies.deduplication?.protectedTools !== undefined &&
377
+ !Array.isArray(strategies.deduplication.protectedTools)) {
378
+ errors.push({
379
+ key: "strategies.deduplication.protectedTools",
380
+ expected: "string[]",
381
+ actual: typeof strategies.deduplication.protectedTools,
382
+ });
383
+ }
384
+ if (strategies.supersedeWrites) {
385
+ if (strategies.supersedeWrites.enabled !== undefined &&
386
+ typeof strategies.supersedeWrites.enabled !== "boolean") {
387
+ errors.push({
388
+ key: "strategies.supersedeWrites.enabled",
389
+ expected: "boolean",
390
+ actual: typeof strategies.supersedeWrites.enabled,
391
+ });
392
+ }
393
+ }
394
+ if (strategies.purgeErrors) {
395
+ if (strategies.purgeErrors.enabled !== undefined &&
396
+ typeof strategies.purgeErrors.enabled !== "boolean") {
397
+ errors.push({
398
+ key: "strategies.purgeErrors.enabled",
399
+ expected: "boolean",
400
+ actual: typeof strategies.purgeErrors.enabled,
401
+ });
402
+ }
403
+ if (strategies.purgeErrors.turns !== undefined &&
404
+ typeof strategies.purgeErrors.turns !== "number") {
405
+ errors.push({
406
+ key: "strategies.purgeErrors.turns",
407
+ expected: "number",
408
+ actual: typeof strategies.purgeErrors.turns,
409
+ });
410
+ }
411
+ // Warn if turns is 0 or negative - will be clamped to 1
412
+ if (typeof strategies.purgeErrors.turns === "number" &&
413
+ strategies.purgeErrors.turns < 1) {
414
+ errors.push({
415
+ key: "strategies.purgeErrors.turns",
416
+ expected: "positive number (>= 1)",
417
+ actual: `${strategies.purgeErrors.turns} (will be clamped to 1)`,
418
+ });
419
+ }
420
+ if (strategies.purgeErrors.protectedTools !== undefined &&
421
+ !Array.isArray(strategies.purgeErrors.protectedTools)) {
422
+ errors.push({
423
+ key: "strategies.purgeErrors.protectedTools",
424
+ expected: "string[]",
425
+ actual: typeof strategies.purgeErrors.protectedTools,
426
+ });
427
+ }
428
+ }
429
+ }
430
+ return errors;
431
+ }
432
+ function showConfigWarnings(ctx, configPath, configData, isProject) {
433
+ const invalidKeys = getInvalidConfigKeys(configData);
434
+ const typeErrors = validateConfigTypes(configData);
435
+ if (invalidKeys.length === 0 && typeErrors.length === 0) {
436
+ return;
437
+ }
438
+ const configType = isProject ? "project config" : "config";
439
+ const messages = [];
440
+ if (invalidKeys.length > 0) {
441
+ const keyList = invalidKeys.slice(0, 3).join(", ");
442
+ const suffix = invalidKeys.length > 3 ? ` (+${invalidKeys.length - 3} more)` : "";
443
+ messages.push(`Unknown keys: ${keyList}${suffix}`);
444
+ }
445
+ if (typeErrors.length > 0) {
446
+ for (const err of typeErrors.slice(0, 2)) {
447
+ messages.push(`${err.key}: expected ${err.expected}, got ${err.actual}`);
448
+ }
449
+ if (typeErrors.length > 2) {
450
+ messages.push(`(+${typeErrors.length - 2} more type errors)`);
451
+ }
452
+ }
453
+ setTimeout(() => {
454
+ try {
455
+ ctx.client.tui.showToast({
456
+ body: {
457
+ title: `DCP: ${configType} warning`,
458
+ message: `${configPath}\n${messages.join("\n")}`,
459
+ variant: "warning",
460
+ duration: 7000,
461
+ },
462
+ });
463
+ }
464
+ catch { }
465
+ }, 7000);
466
+ }
467
+ const defaultConfig = {
468
+ enabled: true,
469
+ debug: false,
470
+ pruneNotification: "detailed",
471
+ pruneNotificationType: "chat",
472
+ commands: {
473
+ enabled: true,
474
+ protectedTools: [...DEFAULT_PROTECTED_TOOLS],
475
+ },
476
+ manualMode: {
477
+ enabled: false,
478
+ automaticStrategies: true,
479
+ },
480
+ turnProtection: {
481
+ enabled: false,
482
+ turns: 4,
483
+ },
484
+ experimental: {
485
+ allowSubAgents: false,
486
+ customPrompts: false,
487
+ },
488
+ protectedFilePatterns: [],
489
+ compress: {
490
+ permission: "allow",
491
+ showCompression: false,
492
+ maxContextLimit: 150000,
493
+ minContextLimit: 50000,
494
+ nudgeFrequency: 5,
495
+ iterationNudgeThreshold: 15,
496
+ nudgeForce: "soft",
497
+ flatSchema: false,
498
+ protectedTools: [...COMPRESS_DEFAULT_PROTECTED_TOOLS],
499
+ protectUserMessages: false,
500
+ },
501
+ strategies: {
502
+ deduplication: {
503
+ enabled: true,
504
+ protectedTools: [],
505
+ },
506
+ supersedeWrites: {
507
+ enabled: true,
508
+ },
509
+ purgeErrors: {
510
+ enabled: true,
511
+ turns: 4,
512
+ protectedTools: [],
513
+ },
514
+ },
515
+ };
516
+ const GLOBAL_CONFIG_DIR = process.env.XDG_CONFIG_HOME
517
+ ? join(process.env.XDG_CONFIG_HOME, "opencode")
518
+ : join(homedir(), ".config", "opencode");
519
+ const GLOBAL_CONFIG_PATH_JSONC = join(GLOBAL_CONFIG_DIR, "dcp.jsonc");
520
+ const GLOBAL_CONFIG_PATH_JSON = join(GLOBAL_CONFIG_DIR, "dcp.json");
521
+ function findOpencodeDir(startDir) {
522
+ let current = startDir;
523
+ while (current !== "/") {
524
+ const candidate = join(current, ".opencode");
525
+ if (existsSync(candidate) && statSync(candidate).isDirectory()) {
526
+ return candidate;
527
+ }
528
+ const parent = dirname(current);
529
+ if (parent === current) {
530
+ break;
531
+ }
532
+ current = parent;
533
+ }
534
+ return null;
535
+ }
536
+ function getConfigPaths(ctx) {
537
+ const global = existsSync(GLOBAL_CONFIG_PATH_JSONC)
538
+ ? GLOBAL_CONFIG_PATH_JSONC
539
+ : existsSync(GLOBAL_CONFIG_PATH_JSON)
540
+ ? GLOBAL_CONFIG_PATH_JSON
541
+ : null;
542
+ let configDir = null;
543
+ const opencodeConfigDir = process.env.OPENCODE_CONFIG_DIR;
544
+ if (opencodeConfigDir) {
545
+ const configJsonc = join(opencodeConfigDir, "dcp.jsonc");
546
+ const configJson = join(opencodeConfigDir, "dcp.json");
547
+ configDir = existsSync(configJsonc)
548
+ ? configJsonc
549
+ : existsSync(configJson)
550
+ ? configJson
551
+ : null;
552
+ }
553
+ let project = null;
554
+ if (ctx?.directory) {
555
+ const opencodeDir = findOpencodeDir(ctx.directory);
556
+ if (opencodeDir) {
557
+ const projectJsonc = join(opencodeDir, "dcp.jsonc");
558
+ const projectJson = join(opencodeDir, "dcp.json");
559
+ project = existsSync(projectJsonc)
560
+ ? projectJsonc
561
+ : existsSync(projectJson)
562
+ ? projectJson
563
+ : null;
564
+ }
565
+ }
566
+ return { global, configDir, project };
567
+ }
568
+ function createDefaultConfig() {
569
+ if (!existsSync(GLOBAL_CONFIG_DIR)) {
570
+ mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
571
+ }
572
+ const configContent = `{
573
+ "$schema": "https://raw.githubusercontent.com/Opencode-DCP/opencode-dynamic-context-pruning/master/dcp.schema.json"
574
+ }
575
+ `;
576
+ writeFileSync(GLOBAL_CONFIG_PATH_JSONC, configContent, "utf-8");
577
+ }
578
+ function loadConfigFile(configPath) {
579
+ let fileContent = "";
580
+ try {
581
+ fileContent = readFileSync(configPath, "utf-8");
582
+ }
583
+ catch {
584
+ return { data: null };
585
+ }
586
+ try {
587
+ const parsed = parse(fileContent, undefined, { allowTrailingComma: true });
588
+ if (parsed === undefined || parsed === null) {
589
+ return { data: null, parseError: "Config file is empty or invalid" };
590
+ }
591
+ return { data: parsed };
592
+ }
593
+ catch (error) {
594
+ return { data: null, parseError: error.message || "Failed to parse config" };
595
+ }
596
+ }
597
+ function mergeStrategies(base, override) {
598
+ if (!override) {
599
+ return base;
600
+ }
601
+ return {
602
+ deduplication: {
603
+ enabled: override.deduplication?.enabled ?? base.deduplication.enabled,
604
+ protectedTools: [
605
+ ...new Set([
606
+ ...base.deduplication.protectedTools,
607
+ ...(override.deduplication?.protectedTools ?? []),
608
+ ]),
609
+ ],
610
+ },
611
+ supersedeWrites: {
612
+ enabled: override.supersedeWrites?.enabled ?? base.supersedeWrites.enabled,
613
+ },
614
+ purgeErrors: {
615
+ enabled: override.purgeErrors?.enabled ?? base.purgeErrors.enabled,
616
+ turns: override.purgeErrors?.turns ?? base.purgeErrors.turns,
617
+ protectedTools: [
618
+ ...new Set([
619
+ ...base.purgeErrors.protectedTools,
620
+ ...(override.purgeErrors?.protectedTools ?? []),
621
+ ]),
622
+ ],
623
+ },
624
+ };
625
+ }
626
+ function mergeCompress(base, override) {
627
+ if (!override) {
628
+ return base;
629
+ }
630
+ return {
631
+ permission: override.permission ?? base.permission,
632
+ showCompression: override.showCompression ?? base.showCompression,
633
+ maxContextLimit: override.maxContextLimit ?? base.maxContextLimit,
634
+ minContextLimit: override.minContextLimit ?? base.minContextLimit,
635
+ modelMaxLimits: override.modelMaxLimits ?? base.modelMaxLimits,
636
+ modelMinLimits: override.modelMinLimits ?? base.modelMinLimits,
637
+ nudgeFrequency: override.nudgeFrequency ?? base.nudgeFrequency,
638
+ iterationNudgeThreshold: override.iterationNudgeThreshold ?? base.iterationNudgeThreshold,
639
+ nudgeForce: override.nudgeForce ?? base.nudgeForce,
640
+ flatSchema: override.flatSchema ?? base.flatSchema,
641
+ protectedTools: [...new Set([...base.protectedTools, ...(override.protectedTools ?? [])])],
642
+ protectUserMessages: override.protectUserMessages ?? base.protectUserMessages,
643
+ };
644
+ }
645
+ function mergeCommands(base, override) {
646
+ if (!override) {
647
+ return base;
648
+ }
649
+ return {
650
+ enabled: override.enabled ?? base.enabled,
651
+ protectedTools: [...new Set([...base.protectedTools, ...(override.protectedTools ?? [])])],
652
+ };
653
+ }
654
+ function mergeManualMode(base, override) {
655
+ if (override === undefined)
656
+ return base;
657
+ return {
658
+ enabled: override.enabled ?? base.enabled,
659
+ automaticStrategies: override.automaticStrategies ?? base.automaticStrategies,
660
+ };
661
+ }
662
+ function mergeExperimental(base, override) {
663
+ if (override === undefined)
664
+ return base;
665
+ return {
666
+ allowSubAgents: override.allowSubAgents ?? base.allowSubAgents,
667
+ customPrompts: override.customPrompts ?? base.customPrompts,
668
+ };
669
+ }
670
+ function deepCloneConfig(config) {
671
+ return {
672
+ ...config,
673
+ commands: {
674
+ enabled: config.commands.enabled,
675
+ protectedTools: [...config.commands.protectedTools],
676
+ },
677
+ manualMode: {
678
+ enabled: config.manualMode.enabled,
679
+ automaticStrategies: config.manualMode.automaticStrategies,
680
+ },
681
+ turnProtection: { ...config.turnProtection },
682
+ experimental: { ...config.experimental },
683
+ protectedFilePatterns: [...config.protectedFilePatterns],
684
+ compress: {
685
+ ...config.compress,
686
+ modelMaxLimits: { ...config.compress.modelMaxLimits },
687
+ modelMinLimits: { ...config.compress.modelMinLimits },
688
+ protectedTools: [...config.compress.protectedTools],
689
+ },
690
+ strategies: {
691
+ deduplication: {
692
+ ...config.strategies.deduplication,
693
+ protectedTools: [...config.strategies.deduplication.protectedTools],
694
+ },
695
+ supersedeWrites: { ...config.strategies.supersedeWrites },
696
+ purgeErrors: {
697
+ ...config.strategies.purgeErrors,
698
+ protectedTools: [...config.strategies.purgeErrors.protectedTools],
699
+ },
700
+ },
701
+ };
702
+ }
703
+ function mergeLayer(config, data) {
704
+ return {
705
+ enabled: data.enabled ?? config.enabled,
706
+ debug: data.debug ?? config.debug,
707
+ pruneNotification: data.pruneNotification ?? config.pruneNotification,
708
+ pruneNotificationType: data.pruneNotificationType ?? config.pruneNotificationType,
709
+ commands: mergeCommands(config.commands, data.commands),
710
+ manualMode: mergeManualMode(config.manualMode, data.manualMode),
711
+ turnProtection: {
712
+ enabled: data.turnProtection?.enabled ?? config.turnProtection.enabled,
713
+ turns: data.turnProtection?.turns ?? config.turnProtection.turns,
714
+ },
715
+ experimental: mergeExperimental(config.experimental, data.experimental),
716
+ protectedFilePatterns: [
717
+ ...new Set([...config.protectedFilePatterns, ...(data.protectedFilePatterns ?? [])]),
718
+ ],
719
+ compress: mergeCompress(config.compress, data.compress),
720
+ strategies: mergeStrategies(config.strategies, data.strategies),
721
+ };
722
+ }
723
+ function scheduleParseWarning(ctx, title, message) {
724
+ setTimeout(() => {
725
+ try {
726
+ ctx.client.tui.showToast({
727
+ body: {
728
+ title,
729
+ message,
730
+ variant: "warning",
731
+ duration: 7000,
732
+ },
733
+ });
734
+ }
735
+ catch { }
736
+ }, 7000);
737
+ }
738
+ export function getConfig(ctx) {
739
+ let config = deepCloneConfig(defaultConfig);
740
+ const configPaths = getConfigPaths(ctx);
741
+ if (!configPaths.global) {
742
+ createDefaultConfig();
743
+ }
744
+ const layers = [
745
+ { path: configPaths.global, name: "config", isProject: false },
746
+ { path: configPaths.configDir, name: "configDir config", isProject: true },
747
+ { path: configPaths.project, name: "project config", isProject: true },
748
+ ];
749
+ for (const layer of layers) {
750
+ if (!layer.path) {
751
+ continue;
752
+ }
753
+ const result = loadConfigFile(layer.path);
754
+ if (result.parseError) {
755
+ scheduleParseWarning(ctx, `DCP: Invalid ${layer.name}`, `${layer.path}\n${result.parseError}\nUsing previous/default values`);
756
+ continue;
757
+ }
758
+ if (!result.data) {
759
+ continue;
760
+ }
761
+ showConfigWarnings(ctx, layer.path, result.data, layer.isProject);
762
+ config = mergeLayer(config, result.data);
763
+ }
764
+ return config;
765
+ }
766
+ //# sourceMappingURL=config.js.map