@tuanhung303/opencode-acp 0.0.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.
Files changed (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +166 -0
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +79 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/commands/budget.d.ts +15 -0
  8. package/dist/lib/commands/budget.d.ts.map +1 -0
  9. package/dist/lib/commands/budget.js +120 -0
  10. package/dist/lib/commands/budget.js.map +1 -0
  11. package/dist/lib/commands/context.d.ts +49 -0
  12. package/dist/lib/commands/context.d.ts.map +1 -0
  13. package/dist/lib/commands/context.js +191 -0
  14. package/dist/lib/commands/context.js.map +1 -0
  15. package/dist/lib/commands/help.d.ts +15 -0
  16. package/dist/lib/commands/help.d.ts.map +1 -0
  17. package/dist/lib/commands/help.js +28 -0
  18. package/dist/lib/commands/help.js.map +1 -0
  19. package/dist/lib/commands/protected.d.ts +17 -0
  20. package/dist/lib/commands/protected.d.ts.map +1 -0
  21. package/dist/lib/commands/protected.js +50 -0
  22. package/dist/lib/commands/protected.js.map +1 -0
  23. package/dist/lib/commands/stats.d.ts +15 -0
  24. package/dist/lib/commands/stats.d.ts.map +1 -0
  25. package/dist/lib/commands/stats.js +64 -0
  26. package/dist/lib/commands/stats.js.map +1 -0
  27. package/dist/lib/commands/sweep.d.ts +23 -0
  28. package/dist/lib/commands/sweep.d.ts.map +1 -0
  29. package/dist/lib/commands/sweep.js +194 -0
  30. package/dist/lib/commands/sweep.js.map +1 -0
  31. package/dist/lib/config-schema.d.ts +119 -0
  32. package/dist/lib/config-schema.d.ts.map +1 -0
  33. package/dist/lib/config-schema.js +97 -0
  34. package/dist/lib/config-schema.js.map +1 -0
  35. package/dist/lib/config.d.ts +59 -0
  36. package/dist/lib/config.d.ts.map +1 -0
  37. package/dist/lib/config.js +426 -0
  38. package/dist/lib/config.js.map +1 -0
  39. package/dist/lib/hooks.d.ts +31 -0
  40. package/dist/lib/hooks.d.ts.map +1 -0
  41. package/dist/lib/hooks.js +230 -0
  42. package/dist/lib/hooks.js.map +1 -0
  43. package/dist/lib/logger.d.ts +55 -0
  44. package/dist/lib/logger.d.ts.map +1 -0
  45. package/dist/lib/logger.js +230 -0
  46. package/dist/lib/logger.js.map +1 -0
  47. package/dist/lib/messages/index.d.ts +3 -0
  48. package/dist/lib/messages/index.d.ts.map +1 -0
  49. package/dist/lib/messages/index.js +3 -0
  50. package/dist/lib/messages/index.js.map +1 -0
  51. package/dist/lib/messages/inject.d.ts +10 -0
  52. package/dist/lib/messages/inject.d.ts.map +1 -0
  53. package/dist/lib/messages/inject.js +10 -0
  54. package/dist/lib/messages/inject.js.map +1 -0
  55. package/dist/lib/messages/prune.d.ts +13 -0
  56. package/dist/lib/messages/prune.d.ts.map +1 -0
  57. package/dist/lib/messages/prune.js +173 -0
  58. package/dist/lib/messages/prune.js.map +1 -0
  59. package/dist/lib/messages/utils.d.ts +43 -0
  60. package/dist/lib/messages/utils.d.ts.map +1 -0
  61. package/dist/lib/messages/utils.js +262 -0
  62. package/dist/lib/messages/utils.js.map +1 -0
  63. package/dist/lib/prompts/discard-tool-spec.d.ts +2 -0
  64. package/dist/lib/prompts/discard-tool-spec.d.ts.map +1 -0
  65. package/dist/lib/prompts/discard-tool-spec.js +54 -0
  66. package/dist/lib/prompts/discard-tool-spec.js.map +1 -0
  67. package/dist/lib/prompts/extract-tool-spec.d.ts +2 -0
  68. package/dist/lib/prompts/extract-tool-spec.d.ts.map +1 -0
  69. package/dist/lib/prompts/extract-tool-spec.js +56 -0
  70. package/dist/lib/prompts/extract-tool-spec.js.map +1 -0
  71. package/dist/lib/prompts/index.d.ts +2 -0
  72. package/dist/lib/prompts/index.d.ts.map +1 -0
  73. package/dist/lib/prompts/index.js +29 -0
  74. package/dist/lib/prompts/index.js.map +1 -0
  75. package/dist/lib/prompts/restore-tool-spec.d.ts +2 -0
  76. package/dist/lib/prompts/restore-tool-spec.d.ts.map +1 -0
  77. package/dist/lib/prompts/restore-tool-spec.js +37 -0
  78. package/dist/lib/prompts/restore-tool-spec.js.map +1 -0
  79. package/dist/lib/prompts/system/both.d.ts +2 -0
  80. package/dist/lib/prompts/system/both.d.ts.map +1 -0
  81. package/dist/lib/prompts/system/both.js +65 -0
  82. package/dist/lib/prompts/system/both.js.map +1 -0
  83. package/dist/lib/prompts/system/discard.d.ts +2 -0
  84. package/dist/lib/prompts/system/discard.d.ts.map +1 -0
  85. package/dist/lib/prompts/system/discard.js +55 -0
  86. package/dist/lib/prompts/system/discard.js.map +1 -0
  87. package/dist/lib/prompts/system/extract.d.ts +2 -0
  88. package/dist/lib/prompts/system/extract.d.ts.map +1 -0
  89. package/dist/lib/prompts/system/extract.js +55 -0
  90. package/dist/lib/prompts/system/extract.js.map +1 -0
  91. package/dist/lib/protected-file-patterns.d.ts +12 -0
  92. package/dist/lib/protected-file-patterns.d.ts.map +1 -0
  93. package/dist/lib/protected-file-patterns.js +69 -0
  94. package/dist/lib/protected-file-patterns.js.map +1 -0
  95. package/dist/lib/safe-execute.d.ts +20 -0
  96. package/dist/lib/safe-execute.d.ts.map +1 -0
  97. package/dist/lib/safe-execute.js +38 -0
  98. package/dist/lib/safe-execute.js.map +1 -0
  99. package/dist/lib/shared-utils.d.ts +4 -0
  100. package/dist/lib/shared-utils.d.ts.map +1 -0
  101. package/dist/lib/shared-utils.js +14 -0
  102. package/dist/lib/shared-utils.js.map +1 -0
  103. package/dist/lib/state/index.d.ts +4 -0
  104. package/dist/lib/state/index.d.ts.map +1 -0
  105. package/dist/lib/state/index.js +4 -0
  106. package/dist/lib/state/index.js.map +1 -0
  107. package/dist/lib/state/persistence.d.ts +27 -0
  108. package/dist/lib/state/persistence.d.ts.map +1 -0
  109. package/dist/lib/state/persistence.js +165 -0
  110. package/dist/lib/state/persistence.js.map +1 -0
  111. package/dist/lib/state/state.d.ts +8 -0
  112. package/dist/lib/state/state.d.ts.map +1 -0
  113. package/dist/lib/state/state.js +166 -0
  114. package/dist/lib/state/state.js.map +1 -0
  115. package/dist/lib/state/tool-cache.d.ts +15 -0
  116. package/dist/lib/state/tool-cache.d.ts.map +1 -0
  117. package/dist/lib/state/tool-cache.js +99 -0
  118. package/dist/lib/state/tool-cache.js.map +1 -0
  119. package/dist/lib/state/types.d.ts +83 -0
  120. package/dist/lib/state/types.d.ts.map +1 -0
  121. package/dist/lib/state/types.js +2 -0
  122. package/dist/lib/state/types.js.map +1 -0
  123. package/dist/lib/state/utils.d.ts +2 -0
  124. package/dist/lib/state/utils.d.ts.map +1 -0
  125. package/dist/lib/state/utils.js +10 -0
  126. package/dist/lib/state/utils.js.map +1 -0
  127. package/dist/lib/strategies/deduplication.d.ts +11 -0
  128. package/dist/lib/strategies/deduplication.d.ts.map +1 -0
  129. package/dist/lib/strategies/deduplication.js +178 -0
  130. package/dist/lib/strategies/deduplication.js.map +1 -0
  131. package/dist/lib/strategies/index.d.ts +5 -0
  132. package/dist/lib/strategies/index.d.ts.map +1 -0
  133. package/dist/lib/strategies/index.js +5 -0
  134. package/dist/lib/strategies/index.js.map +1 -0
  135. package/dist/lib/strategies/purge-errors.d.ts +13 -0
  136. package/dist/lib/strategies/purge-errors.d.ts.map +1 -0
  137. package/dist/lib/strategies/purge-errors.js +62 -0
  138. package/dist/lib/strategies/purge-errors.js.map +1 -0
  139. package/dist/lib/strategies/supersede-writes.d.ts +13 -0
  140. package/dist/lib/strategies/supersede-writes.d.ts.map +1 -0
  141. package/dist/lib/strategies/supersede-writes.js +90 -0
  142. package/dist/lib/strategies/supersede-writes.js.map +1 -0
  143. package/dist/lib/strategies/tools.d.ts +15 -0
  144. package/dist/lib/strategies/tools.d.ts.map +1 -0
  145. package/dist/lib/strategies/tools.js +288 -0
  146. package/dist/lib/strategies/tools.js.map +1 -0
  147. package/dist/lib/strategies/utils.d.ts +11 -0
  148. package/dist/lib/strategies/utils.d.ts.map +1 -0
  149. package/dist/lib/strategies/utils.js +75 -0
  150. package/dist/lib/strategies/utils.js.map +1 -0
  151. package/dist/lib/ui/notification.d.ts +12 -0
  152. package/dist/lib/ui/notification.d.ts.map +1 -0
  153. package/dist/lib/ui/notification.js +81 -0
  154. package/dist/lib/ui/notification.js.map +1 -0
  155. package/dist/lib/ui/utils.d.ts +10 -0
  156. package/dist/lib/ui/utils.d.ts.map +1 -0
  157. package/dist/lib/ui/utils.js +113 -0
  158. package/dist/lib/ui/utils.js.map +1 -0
  159. package/package.json +62 -0
@@ -0,0 +1,178 @@
1
+ import { buildToolIdList } from "../messages/utils";
2
+ import { getFilePathFromParameters, isProtectedFilePath } from "../protected-file-patterns";
3
+ import { calculateTokensSaved } from "./utils";
4
+ /**
5
+ * Deduplication strategy - prunes older tool calls that have identical
6
+ * tool name and parameters, keeping only the most recent occurrence.
7
+ * Also handles fuzzy deduplication for overlapping file reads.
8
+ * Modifies the session state in place to add pruned tool call IDs.
9
+ */
10
+ export const deduplicate = (state, logger, config, messages) => {
11
+ if (!config.strategies.deduplication.enabled) {
12
+ return;
13
+ }
14
+ // Build list of all tool call IDs from messages (chronological order)
15
+ const allToolIds = buildToolIdList(state, messages, logger);
16
+ if (allToolIds.length === 0) {
17
+ return;
18
+ }
19
+ // Filter out IDs already pruned
20
+ const alreadyPruned = new Set(state.prune.toolIds);
21
+ const unprunedIds = allToolIds.filter((id) => !alreadyPruned.has(id));
22
+ if (unprunedIds.length === 0) {
23
+ return;
24
+ }
25
+ const protectedTools = config.strategies.deduplication.protectedTools;
26
+ // Group by signature (tool name + normalized parameters)
27
+ const signatureMap = new Map();
28
+ for (const id of unprunedIds) {
29
+ const metadata = state.toolParameters.get(id);
30
+ if (!metadata) {
31
+ // logger.warn(`Missing metadata for tool call ID: ${id}`)
32
+ continue;
33
+ }
34
+ // Skip protected tools
35
+ if (protectedTools.includes(metadata.tool)) {
36
+ continue;
37
+ }
38
+ const filePath = getFilePathFromParameters(metadata.parameters);
39
+ if (isProtectedFilePath(filePath, config.protectedFilePatterns)) {
40
+ continue;
41
+ }
42
+ const signature = createToolSignature(metadata.tool, metadata.parameters);
43
+ if (!signatureMap.has(signature)) {
44
+ signatureMap.set(signature, []);
45
+ }
46
+ signatureMap.get(signature).push(id);
47
+ }
48
+ // Find duplicates - keep only the most recent (last) in each group
49
+ const newPruneIds = [];
50
+ for (const [, ids] of signatureMap.entries()) {
51
+ if (ids.length > 1) {
52
+ // All except last (most recent) should be pruned
53
+ const idsToRemove = ids.slice(0, -1);
54
+ newPruneIds.push(...idsToRemove);
55
+ }
56
+ }
57
+ state.stats.totalPruneTokens += calculateTokensSaved(state, messages, newPruneIds);
58
+ const allDeduplicatedIds = [...newPruneIds];
59
+ // Phase 2: Fuzzy deduplication for overlapping file reads
60
+ const overlappingReads = findOverlappingReads(state, unprunedIds, protectedTools, config);
61
+ if (overlappingReads.length > 0) {
62
+ allDeduplicatedIds.push(...overlappingReads);
63
+ logger.debug(`Marked ${overlappingReads.length} overlapping file reads for pruning`);
64
+ }
65
+ if (allDeduplicatedIds.length > 0) {
66
+ state.prune.toolIds.push(...allDeduplicatedIds);
67
+ const tokensSaved = calculateTokensSaved(state, messages, allDeduplicatedIds);
68
+ state.stats.totalPruneTokens += tokensSaved;
69
+ state.stats.strategyStats.deduplication.count += allDeduplicatedIds.length;
70
+ state.stats.strategyStats.deduplication.tokens += tokensSaved;
71
+ logger.debug(`Marked ${allDeduplicatedIds.length} duplicate tool calls for pruning`);
72
+ }
73
+ };
74
+ /**
75
+ * Find overlapping file reads that can be safely pruned.
76
+ * If a file is read with overlapping ranges, older reads that are
77
+ * fully contained within newer reads can be pruned.
78
+ */
79
+ function findOverlappingReads(state, toolIds, protectedTools, config) {
80
+ const fileReads = new Map();
81
+ // Collect all read operations with file paths
82
+ for (const id of toolIds) {
83
+ const metadata = state.toolParameters.get(id);
84
+ if (!metadata || metadata.tool !== "read")
85
+ continue;
86
+ if (protectedTools.includes(metadata.tool))
87
+ continue;
88
+ const filePath = getFilePathFromParameters(metadata.parameters);
89
+ if (!filePath || isProtectedFilePath(filePath, config.protectedFilePatterns))
90
+ continue;
91
+ const params = metadata.parameters || {};
92
+ const offset = typeof params.offset === "number" ? params.offset : 0;
93
+ const limit = typeof params.limit === "number" ? params.limit : undefined;
94
+ if (!fileReads.has(filePath)) {
95
+ fileReads.set(filePath, []);
96
+ }
97
+ fileReads.get(filePath).push({ id, filePath, offset, limit });
98
+ }
99
+ const toPrune = [];
100
+ // For each file, check for overlapping ranges
101
+ for (const [, reads] of fileReads.entries()) {
102
+ if (reads.length < 2)
103
+ continue;
104
+ // Sort by offset (ascending), then by limit (descending for same offset)
105
+ reads.sort((a, b) => {
106
+ if (a.offset !== b.offset)
107
+ return a.offset - b.offset;
108
+ // If same offset, prefer the one with larger limit (or undefined = unlimited)
109
+ if (a.limit === undefined)
110
+ return 1;
111
+ if (b.limit === undefined)
112
+ return -1;
113
+ return b.limit - a.limit;
114
+ });
115
+ // Check each read against later reads (which are more recent due to chronological order)
116
+ for (let i = 0; i < reads.length - 1; i++) {
117
+ const older = reads[i];
118
+ const newer = reads[reads.length - 1]; // Most recent read of this file
119
+ if (older.id === newer.id)
120
+ continue;
121
+ // Check if older read is fully contained within newer read
122
+ if (isRangeContained(older, newer)) {
123
+ toPrune.push(older.id);
124
+ }
125
+ }
126
+ }
127
+ return toPrune;
128
+ }
129
+ /**
130
+ * Check if range A is fully contained within range B.
131
+ */
132
+ function isRangeContained(a, b) {
133
+ // If b has no limit (read entire file), it contains everything
134
+ if (b.limit === undefined) {
135
+ return a.offset >= b.offset;
136
+ }
137
+ // If a has no limit but b does, a might be larger
138
+ if (a.limit === undefined) {
139
+ return false;
140
+ }
141
+ const aEnd = a.offset + a.limit;
142
+ const bEnd = b.offset + b.limit;
143
+ // A is contained in B if A starts at or after B and ends at or before B
144
+ return a.offset >= b.offset && aEnd <= bEnd;
145
+ }
146
+ function createToolSignature(tool, parameters) {
147
+ if (!parameters) {
148
+ return tool;
149
+ }
150
+ const normalized = normalizeParameters(parameters);
151
+ const sorted = sortObjectKeys(normalized);
152
+ return `${tool}::${JSON.stringify(sorted)}`;
153
+ }
154
+ function normalizeParameters(params) {
155
+ if (typeof params !== "object" || params === null)
156
+ return params;
157
+ if (Array.isArray(params))
158
+ return params;
159
+ const normalized = {};
160
+ for (const [key, value] of Object.entries(params)) {
161
+ if (value !== undefined && value !== null) {
162
+ normalized[key] = value;
163
+ }
164
+ }
165
+ return normalized;
166
+ }
167
+ function sortObjectKeys(obj) {
168
+ if (typeof obj !== "object" || obj === null)
169
+ return obj;
170
+ if (Array.isArray(obj))
171
+ return obj.map(sortObjectKeys);
172
+ const sorted = {};
173
+ for (const key of Object.keys(obj).sort()) {
174
+ sorted[key] = sortObjectKeys(obj[key]);
175
+ }
176
+ return sorted;
177
+ }
178
+ //# sourceMappingURL=deduplication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deduplication.js","sourceRoot":"","sources":["../../../lib/strategies/deduplication.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { deduplicate } from "./deduplication";
2
+ export { createDiscardTool, createExtractTool, createRestoreTool } from "./tools";
3
+ export { supersedeWrites } from "./supersede-writes";
4
+ export { purgeErrors } from "./purge-errors";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/strategies/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,5 @@
1
+ export { deduplicate } from "./deduplication";
2
+ export { createDiscardTool, createExtractTool, createRestoreTool } from "./tools";
3
+ export { supersedeWrites } from "./supersede-writes";
4
+ export { purgeErrors } from "./purge-errors";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/strategies/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { PluginConfig } from "../config";
2
+ import { Logger } from "../logger";
3
+ import type { SessionState, WithParts } from "../state";
4
+ /**
5
+ * Purge Errors strategy - prunes tool inputs for tools that errored
6
+ * after they are older than a configurable number of turns.
7
+ * The error message is preserved, but the (potentially large) inputs
8
+ * are removed to save context.
9
+ *
10
+ * Modifies the session state in place to add pruned tool call IDs.
11
+ */
12
+ export declare const purgeErrors: (state: SessionState, logger: Logger, config: PluginConfig, messages: WithParts[]) => void;
13
+ //# sourceMappingURL=purge-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purge-errors.d.ts","sourceRoot":"","sources":["../../../lib/strategies/purge-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAKvD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GACpB,OAAO,YAAY,EACnB,QAAQ,MAAM,EACd,QAAQ,YAAY,EACpB,UAAU,SAAS,EAAE,KACtB,IA8DF,CAAA"}
@@ -0,0 +1,62 @@
1
+ import { buildToolIdList } from "../messages/utils";
2
+ import { getFilePathFromParameters, isProtectedFilePath } from "../protected-file-patterns";
3
+ import { calculateTokensSaved } from "./utils";
4
+ /**
5
+ * Purge Errors strategy - prunes tool inputs for tools that errored
6
+ * after they are older than a configurable number of turns.
7
+ * The error message is preserved, but the (potentially large) inputs
8
+ * are removed to save context.
9
+ *
10
+ * Modifies the session state in place to add pruned tool call IDs.
11
+ */
12
+ export const purgeErrors = (state, logger, config, messages) => {
13
+ if (!config.strategies.purgeErrors.enabled) {
14
+ return;
15
+ }
16
+ // Build list of all tool call IDs from messages (chronological order)
17
+ const allToolIds = buildToolIdList(state, messages, logger);
18
+ if (allToolIds.length === 0) {
19
+ return;
20
+ }
21
+ // Filter out IDs already pruned
22
+ const alreadyPruned = new Set(state.prune.toolIds);
23
+ const unprunedIds = allToolIds.filter((id) => !alreadyPruned.has(id));
24
+ if (unprunedIds.length === 0) {
25
+ return;
26
+ }
27
+ const protectedTools = config.strategies.purgeErrors.protectedTools;
28
+ const turnThreshold = config.strategies.purgeErrors.turns;
29
+ const newPruneIds = [];
30
+ for (const id of unprunedIds) {
31
+ const metadata = state.toolParameters.get(id);
32
+ if (!metadata) {
33
+ continue;
34
+ }
35
+ // Skip protected tools
36
+ if (protectedTools.includes(metadata.tool)) {
37
+ continue;
38
+ }
39
+ const filePath = getFilePathFromParameters(metadata.parameters);
40
+ if (isProtectedFilePath(filePath, config.protectedFilePatterns)) {
41
+ continue;
42
+ }
43
+ // Only process error tools
44
+ if (metadata.status !== "error") {
45
+ continue;
46
+ }
47
+ // Check if the tool is old enough to prune
48
+ const turnAge = state.currentTurn - metadata.turn;
49
+ if (turnAge >= turnThreshold) {
50
+ newPruneIds.push(id);
51
+ }
52
+ }
53
+ if (newPruneIds.length > 0) {
54
+ const tokensSaved = calculateTokensSaved(state, messages, newPruneIds);
55
+ state.stats.totalPruneTokens += tokensSaved;
56
+ state.stats.strategyStats.purgeErrors.count += newPruneIds.length;
57
+ state.stats.strategyStats.purgeErrors.tokens += tokensSaved;
58
+ state.prune.toolIds.push(...newPruneIds);
59
+ logger.debug(`Marked ${newPruneIds.length} error tool calls for pruning (older than ${turnThreshold} turns)`);
60
+ }
61
+ };
62
+ //# sourceMappingURL=purge-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purge-errors.js","sourceRoot":"","sources":["../../../lib/strategies/purge-errors.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAE9C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACvB,KAAmB,EACnB,MAAc,EACd,MAAoB,EACpB,QAAqB,EACjB,EAAE;IACN,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACzC,OAAM;IACV,CAAC;IAED,sEAAsE;IACtE,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC3D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAM;IACV,CAAC;IAED,gCAAgC;IAChC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAClD,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IAErE,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAM;IACV,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,cAAc,CAAA;IACnE,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAA;IAEzD,MAAM,WAAW,GAAa,EAAE,CAAA;IAEhC,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,SAAQ;QACZ,CAAC;QAED,uBAAuB;QACvB,IAAI,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,SAAQ;QACZ,CAAC;QAED,MAAM,QAAQ,GAAG,yBAAyB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;QAC/D,IAAI,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC;YAC9D,SAAQ;QACZ,CAAC;QAED,2BAA2B;QAC3B,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAC9B,SAAQ;QACZ,CAAC;QAED,2CAA2C;QAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAA;QACjD,IAAI,OAAO,IAAI,aAAa,EAAE,CAAC;YAC3B,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACxB,CAAC;IACL,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;QACtE,KAAK,CAAC,KAAK,CAAC,gBAAgB,IAAI,WAAW,CAAA;QAC3C,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,MAAM,CAAA;QACjE,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,MAAM,IAAI,WAAW,CAAA;QAC3D,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAA;QACxC,MAAM,CAAC,KAAK,CACR,UAAU,WAAW,CAAC,MAAM,6CAA6C,aAAa,SAAS,CAClG,CAAA;IACL,CAAC;AACL,CAAC,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { PluginConfig } from "../config";
2
+ import { Logger } from "../logger";
3
+ import type { SessionState, WithParts } from "../state";
4
+ /**
5
+ * Supersede Writes strategy - prunes write tool inputs for files that have
6
+ * subsequently been read. When a file is written and later read, the original
7
+ * write content becomes redundant since the current file state is captured
8
+ * in the read result.
9
+ *
10
+ * Modifies the session state in place to add pruned tool call IDs.
11
+ */
12
+ export declare const supersedeWrites: (state: SessionState, logger: Logger, config: PluginConfig, messages: WithParts[]) => void;
13
+ //# sourceMappingURL=supersede-writes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supersede-writes.d.ts","sourceRoot":"","sources":["../../../lib/strategies/supersede-writes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAKvD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GACxB,OAAO,YAAY,EACnB,QAAQ,MAAM,EACd,QAAQ,YAAY,EACpB,UAAU,SAAS,EAAE,KACtB,IA0FF,CAAA"}
@@ -0,0 +1,90 @@
1
+ import { buildToolIdList } from "../messages/utils";
2
+ import { getFilePathFromParameters, isProtectedFilePath } from "../protected-file-patterns";
3
+ import { calculateTokensSaved } from "./utils";
4
+ /**
5
+ * Supersede Writes strategy - prunes write tool inputs for files that have
6
+ * subsequently been read. When a file is written and later read, the original
7
+ * write content becomes redundant since the current file state is captured
8
+ * in the read result.
9
+ *
10
+ * Modifies the session state in place to add pruned tool call IDs.
11
+ */
12
+ export const supersedeWrites = (state, logger, config, messages) => {
13
+ if (!config.strategies.supersedeWrites.enabled) {
14
+ return;
15
+ }
16
+ // Build list of all tool call IDs from messages (chronological order)
17
+ const allToolIds = buildToolIdList(state, messages, logger);
18
+ if (allToolIds.length === 0) {
19
+ return;
20
+ }
21
+ // Filter out IDs already pruned
22
+ const alreadyPruned = new Set(state.prune.toolIds);
23
+ const unprunedIds = allToolIds.filter((id) => !alreadyPruned.has(id));
24
+ if (unprunedIds.length === 0) {
25
+ return;
26
+ }
27
+ // Track write tools by file path: filePath -> [{ id, index }]
28
+ // We track index to determine chronological order
29
+ const writesByFile = new Map();
30
+ // Track read file paths with their index
31
+ const readsByFile = new Map();
32
+ for (let i = 0; i < allToolIds.length; i++) {
33
+ const id = allToolIds[i];
34
+ if (!id) {
35
+ continue;
36
+ }
37
+ const metadata = state.toolParameters.get(id);
38
+ if (!metadata) {
39
+ continue;
40
+ }
41
+ const filePath = getFilePathFromParameters(metadata.parameters);
42
+ if (!filePath) {
43
+ continue;
44
+ }
45
+ if (isProtectedFilePath(filePath, config.protectedFilePatterns)) {
46
+ continue;
47
+ }
48
+ if (metadata.tool === "write") {
49
+ if (!writesByFile.has(filePath)) {
50
+ writesByFile.set(filePath, []);
51
+ }
52
+ writesByFile.get(filePath).push({ id, index: i });
53
+ }
54
+ else if (metadata.tool === "read") {
55
+ if (!readsByFile.has(filePath)) {
56
+ readsByFile.set(filePath, []);
57
+ }
58
+ readsByFile.get(filePath).push(i);
59
+ }
60
+ }
61
+ // Find writes that are superseded by subsequent reads
62
+ const newPruneIds = [];
63
+ for (const [filePath, writes] of writesByFile.entries()) {
64
+ const reads = readsByFile.get(filePath);
65
+ if (!reads || reads.length === 0) {
66
+ continue;
67
+ }
68
+ // For each write, check if there's a read that comes after it
69
+ for (const write of writes) {
70
+ // Skip if already pruned
71
+ if (alreadyPruned.has(write.id)) {
72
+ continue;
73
+ }
74
+ // Check if any read comes after this write
75
+ const hasSubsequentRead = reads.some((readIndex) => readIndex > write.index);
76
+ if (hasSubsequentRead) {
77
+ newPruneIds.push(write.id);
78
+ }
79
+ }
80
+ }
81
+ if (newPruneIds.length > 0) {
82
+ const tokensSaved = calculateTokensSaved(state, messages, newPruneIds);
83
+ state.stats.totalPruneTokens += tokensSaved;
84
+ state.stats.strategyStats.supersedeWrites.count += newPruneIds.length;
85
+ state.stats.strategyStats.supersedeWrites.tokens += tokensSaved;
86
+ state.prune.toolIds.push(...newPruneIds);
87
+ logger.debug(`Marked ${newPruneIds.length} superseded write tool calls for pruning`);
88
+ }
89
+ };
90
+ //# sourceMappingURL=supersede-writes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supersede-writes.js","sourceRoot":"","sources":["../../../lib/strategies/supersede-writes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+ import type { SessionState } from "../state";
3
+ import type { PluginConfig } from "../config";
4
+ import type { Logger } from "../logger";
5
+ export interface PruneToolContext {
6
+ client: any;
7
+ state: SessionState;
8
+ logger: Logger;
9
+ config: PluginConfig;
10
+ workingDirectory: string;
11
+ }
12
+ export declare function createDiscardTool(ctx: PruneToolContext): ReturnType<typeof tool>;
13
+ export declare function createExtractTool(ctx: PruneToolContext): ReturnType<typeof tool>;
14
+ export declare function createRestoreTool(ctx: PruneToolContext): ReturnType<typeof tool>;
15
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../lib/strategies/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAiC,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAK7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AASvC,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,YAAY,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;CAC3B;AAoJD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAqFhF;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CA4EhF;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CA0EhF"}