@tarquinen/opencode-dcp 3.1.7 → 3.1.10

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