openslimedit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +306 -0
- package/package.json +42 -0
- package/scripts/postinstall.js +55 -0
- package/src/index.ts +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Artur
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# OpenSlimedit
|
|
2
|
+
|
|
3
|
+
An [OpenCode](https://github.com/anomalyco/opencode) plugin that reduces token usage by up to 33% with zero configuration. It compresses tool descriptions, compacts read output, and adds line-range edit support.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Token Savings at a Glance
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Total tokens vs baseline (lower is better)
|
|
11
|
+
|
|
12
|
+
Claude Opus 4.6 [=================> ] -21.8% saved
|
|
13
|
+
Claude Sonnet 4.5 [========================> ] -32.6% saved
|
|
14
|
+
GPT 5.2 Codex [====================> ] -26.7% saved
|
|
15
|
+
Minimax M2.5 Free [==================> ] -24.8% saved
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Model | Baseline | OpenSlimedit | Saved |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| Claude Opus 4.6 | 60,841 tokens | 47,590 tokens | **-21.8%** |
|
|
21
|
+
| Claude Sonnet 4.5 | 120,884 tokens | 81,471 tokens | **-32.6%** |
|
|
22
|
+
| GPT 5.2 Codex | 39,185 tokens | 28,713 tokens | **-26.7%** |
|
|
23
|
+
| Minimax M2.5 Free | 28,031 tokens | 21,073 tokens | **-24.8%** |
|
|
24
|
+
|
|
25
|
+
> Measured across 4 edit tasks (single-edit, multi-line-replace, multi-edit, large-file-edit) on small test files. Separate sessions, no prompt caching.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
Three optimizations that compound across every API call:
|
|
32
|
+
|
|
33
|
+
1. **Tool description compression** — Replaces verbose built-in tool descriptions with minimal versions. Since tool schemas are sent with every API call, this saves thousands of input tokens per step.
|
|
34
|
+
|
|
35
|
+
2. **Compact read output** — Shortens absolute file paths to relative paths, strips type tags and footer boilerplate from file reads.
|
|
36
|
+
|
|
37
|
+
3. **Line-range edit expansion** — Allows the model to specify `oldString` as a line range like `"55-64"` instead of reproducing exact file content. The plugin transparently expands the range to the actual lines before the edit tool runs.
|
|
38
|
+
|
|
39
|
+
No custom tools. No system prompt injection. No modifications to built-in tool behavior. Everything works through lightweight hooks.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
### Prerequisites
|
|
46
|
+
|
|
47
|
+
- [OpenCode](https://github.com/anomalyco/opencode) with plugin hook support
|
|
48
|
+
- [Bun](https://bun.sh) runtime
|
|
49
|
+
|
|
50
|
+
### Option 1: Install from npm
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install openslimedit
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
or with Bun:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
bun add openslimedit
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The postinstall script automatically adds the plugin to your project's `.opencode/opencode.json` config.
|
|
63
|
+
|
|
64
|
+
### Option 2: Install from source
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/ASidorenkoCode/openslimedit.git
|
|
68
|
+
cd openslimedit
|
|
69
|
+
bun install
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then add to your OpenCode config:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"plugins": {
|
|
77
|
+
"openslimedit": {
|
|
78
|
+
"module": "file:///path/to/openslimedit/src/index.ts"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Start OpenCode
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
opencode
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
That's it. The plugin activates automatically and reduces token usage on every interaction.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Benchmark
|
|
95
|
+
|
|
96
|
+
We tested multiple approaches to find the most token-efficient editing strategy. All benchmarks run on an isolated test folder with no project context, 1 iteration per case, separate sessions to avoid prompt caching effects.
|
|
97
|
+
|
|
98
|
+
**Test cases:**
|
|
99
|
+
- **single-edit** — 21-line file, change one word
|
|
100
|
+
- **multi-line-replace** — 48-line file, rewrite a function body
|
|
101
|
+
- **multi-edit** — 35-line file, 3 separate changes across the file
|
|
102
|
+
- **large-file-edit** — 115-line file, add try/catch + retry logic
|
|
103
|
+
|
|
104
|
+
**Approaches tested:**
|
|
105
|
+
- **baseline** — No plugin, default OpenCode behavior
|
|
106
|
+
- **hashline** — Tags every line with a content hash, model references lines by hash instead of reproducing content. Custom tool schema, system prompt injection.
|
|
107
|
+
- **smart_edit** — Shortens descriptions of unused tools only + line-range expansion in edit. No custom tools.
|
|
108
|
+
- **OpenSlimedit** (current) — Aggressively shortens ALL tool descriptions + compact read output + line-range expansion. No custom tools, no system prompt.
|
|
109
|
+
|
|
110
|
+
### Why Not Hashline?
|
|
111
|
+
|
|
112
|
+
The hashline approach seemed promising in theory: tag lines with hashes so models don't need to reproduce code. In practice, it **increases** token usage for most models:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
Total token change vs baseline (negative = savings, positive = regression)
|
|
116
|
+
|
|
117
|
+
Hashline:
|
|
118
|
+
Claude Opus 4.6 ██████████████ +14.0%
|
|
119
|
+
Claude Sonnet 4.5 ███████████████ +15.2%
|
|
120
|
+
GPT 5.2 Codex █████████████████████████████████████████████████ +49.9%
|
|
121
|
+
Minimax M2.5 Free █████████ +9.1%
|
|
122
|
+
|
|
123
|
+
OpenSlimedit:
|
|
124
|
+
Claude Opus 4.6 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ -21.8%
|
|
125
|
+
Claude Sonnet 4.5 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ -32.6%
|
|
126
|
+
GPT 5.2 Codex ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ -26.7%
|
|
127
|
+
Minimax M2.5 Free ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ -24.8%
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The hash-tagged read output, custom tool schemas, and system prompt injection add per-step overhead that outweighs any savings from shorter `oldString` values. The biggest win comes from **compressing tool descriptions** — they're sent with every API call and the savings compound.
|
|
131
|
+
|
|
132
|
+
### Results — Total Tokens (% vs baseline)
|
|
133
|
+
|
|
134
|
+
#### Claude Opus 4.6
|
|
135
|
+
|
|
136
|
+
| Case | Baseline | Hashline | Smart Edit | OpenSlimedit |
|
|
137
|
+
|---|---|---|---|---|
|
|
138
|
+
| single-edit | 13,419 | 13,915 (+3.7%) | 12,739 (-5.1%) | **9,902 (-26.2%)** |
|
|
139
|
+
| multi-line-replace | 13,965 | 16,940 (+21.3%) | 13,289 (-4.8%) | **10,547 (-24.5%)** |
|
|
140
|
+
| multi-edit | 17,583 | 19,125 (+8.8%) | 16,572 (-5.7%) | **13,743 (-21.8%)** |
|
|
141
|
+
| large-file-edit | 15,874 | 19,377 (+22.1%) | 16,691 (+5.1%) | **13,398 (-15.6%)** |
|
|
142
|
+
| **Total** | **60,841** | **69,357 (+14.0%)** | **59,291 (-2.5%)** | **47,590 (-21.8%)** |
|
|
143
|
+
|
|
144
|
+
#### Claude Sonnet 4.5
|
|
145
|
+
|
|
146
|
+
| Case | Baseline | Hashline | OpenSlimedit |
|
|
147
|
+
|---|---|---|---|
|
|
148
|
+
| single-edit | 38,111 | 26,881 (-29.5%) | **18,460 (-51.6%)** |
|
|
149
|
+
| multi-line-replace | 26,997 | 19,039 (-29.5%) | 20,042 (-25.8%) |
|
|
150
|
+
| multi-edit | 39,785 | 47,923 (+20.5%) | **19,940 (-49.9%)** |
|
|
151
|
+
| large-file-edit | 15,991 | 45,429 (+184.1%) | 23,029 (+44.0%) |
|
|
152
|
+
| **Total** | **120,884** | **139,272 (+15.2%)** | **81,471 (-32.6%)** |
|
|
153
|
+
|
|
154
|
+
#### GPT 5.2 Codex
|
|
155
|
+
|
|
156
|
+
| Case | Baseline | Hashline | OpenSlimedit |
|
|
157
|
+
|---|---|---|---|
|
|
158
|
+
| single-edit | 8,002 | 11,208 (+40.1%) | 14,027 (+75.3%) |
|
|
159
|
+
| multi-line-replace | 8,325 | 19,350 (+132.4%) | **7,019 (-15.7%)** |
|
|
160
|
+
| multi-edit | 9,510 | FAIL | **4,797 (-49.5%)** |
|
|
161
|
+
| large-file-edit | 13,348 | 8,189 (-38.6%) | **2,870 (-78.5%)** |
|
|
162
|
+
| **Total** | **39,185** | **58,747*** | **28,713 (-26.7%)** |
|
|
163
|
+
|
|
164
|
+
*\*Hashline multi-edit failed (760s timeout loop); total includes failed run*
|
|
165
|
+
|
|
166
|
+
#### Minimax M2.5 Free
|
|
167
|
+
|
|
168
|
+
| Case | Baseline | Hashline | Smart Edit | OpenSlimedit |
|
|
169
|
+
|---|---|---|---|---|
|
|
170
|
+
| single-edit | 10,691 | 11,098 (+3.8%) | 9,994 (-6.5%) | **7,405 (-30.7%)** |
|
|
171
|
+
| multi-line-replace | 11,105 | 12,045 (+8.5%) | 10,396 (-6.4%) | **1,721 (-84.5%)** |
|
|
172
|
+
| multi-edit | 2,308 | 2,331 (+1.0%) | 2,357 (+2.1%) | 8,034 (+248.1%) |
|
|
173
|
+
| large-file-edit | 3,927 | 5,100 (+29.9%) | 3,986 (+1.5%) | **3,913 (-0.4%)** |
|
|
174
|
+
| **Total** | **28,031** | **30,574 (+9.1%)** | **26,733 (-4.6%)** | **21,073 (-24.8%)** |
|
|
175
|
+
|
|
176
|
+
### Summary
|
|
177
|
+
|
|
178
|
+
| Model | Hashline | Smart Edit | OpenSlimedit |
|
|
179
|
+
|---|---|---|---|
|
|
180
|
+
| **Claude Opus 4.6** | +14.0% | -2.5% | **-21.8%** |
|
|
181
|
+
| **Claude Sonnet 4.5** | +15.2% | — | **-32.6%** |
|
|
182
|
+
| **GPT 5.2 Codex** | +49.9%* | — | **-26.7%** |
|
|
183
|
+
| **Minimax M2.5 Free** | +9.1% | -4.6% | **-24.8%** |
|
|
184
|
+
|
|
185
|
+
*\*Includes failed multi-edit run*
|
|
186
|
+
|
|
187
|
+
### Key Findings
|
|
188
|
+
|
|
189
|
+
- **Tool description compression is the biggest win.** Tool schemas are sent with every API call. Shortening them saves thousands of input tokens per step, and this compounds across multi-step tasks.
|
|
190
|
+
- **Hashline increases token usage for most models.** The hash-tagged read output, custom tool schemas, and system prompt injection add per-step overhead that outweighs the savings from shorter `oldString` values.
|
|
191
|
+
- **OpenSlimedit consistently saves 21-33% across all tested models** with zero regressions on Opus 4.6. Some models show regressions on individual cases (Minimax on multi-edit, Codex on single-edit) but the total is always significantly lower.
|
|
192
|
+
- **Custom tools confuse some models.** Minimax and Codex struggle with non-standard tool schemas, leading to extra steps or failures. OpenSlimedit avoids this entirely by only modifying descriptions of existing tools.
|
|
193
|
+
|
|
194
|
+
> **Note:** These benchmarks use small files (21-115 lines). On larger files, the relative savings from tool description compression become even more significant as more API steps are needed.
|
|
195
|
+
|
|
196
|
+
<details>
|
|
197
|
+
<summary>Raw data — Hashline runs</summary>
|
|
198
|
+
|
|
199
|
+
| Mode | Model | Case | Time | Input | Output | Total | Success |
|
|
200
|
+
|---|---|---|---|---|---|---|---|
|
|
201
|
+
| hashline | claude-sonnet-4.5 | single-edit | 10,745 ms | 26,582 | 299 | 26,881 | yes |
|
|
202
|
+
| hashline | claude-sonnet-4.5 | multi-line-replace | 37,231 ms | 17,188 | 1,851 | 19,039 | yes |
|
|
203
|
+
| hashline | claude-sonnet-4.5 | multi-edit | 52,668 ms | 44,604 | 3,319 | 47,923 | yes |
|
|
204
|
+
| hashline | claude-sonnet-4.5 | large-file-edit | 25,097 ms | 44,466 | 963 | 45,429 | yes |
|
|
205
|
+
| hashline | claude-opus-4.6 | single-edit | 12,994 ms | 13,617 | 298 | 13,915 | yes |
|
|
206
|
+
| hashline | claude-opus-4.6 | multi-line-replace | 21,080 ms | 16,208 | 732 | 16,940 | yes |
|
|
207
|
+
| hashline | claude-opus-4.6 | multi-edit | 46,637 ms | 17,031 | 2,094 | 19,125 | yes |
|
|
208
|
+
| hashline | claude-opus-4.6 | large-file-edit | 25,787 ms | 18,401 | 976 | 19,377 | yes |
|
|
209
|
+
| hashline | gpt-5.2-codex | single-edit | 12,458 ms | 10,929 | 279 | 11,208 | yes |
|
|
210
|
+
| hashline | gpt-5.2-codex | multi-line-replace | 24,931 ms | 18,381 | 969 | 19,350 | yes |
|
|
211
|
+
| hashline | gpt-5.2-codex | multi-edit | 760,890 ms | 146,516 | 53,250 | 199,766 | **no** |
|
|
212
|
+
| hashline | gpt-5.2-codex | large-file-edit | 27,601 ms | 6,979 | 1,210 | 8,189 | yes |
|
|
213
|
+
| hashline | minimax-m2.5-free | single-edit | 13,806 ms | 10,680 | 418 | 11,098 | yes |
|
|
214
|
+
| hashline | minimax-m2.5-free | multi-line-replace | 56,046 ms | 11,082 | 963 | 12,045 | yes |
|
|
215
|
+
| hashline | minimax-m2.5-free | multi-edit | 19,062 ms | 1,654 | 677 | 2,331 | yes |
|
|
216
|
+
| hashline | minimax-m2.5-free | large-file-edit | 61,973 ms | 3,222 | 1,878 | 5,100 | yes |
|
|
217
|
+
|
|
218
|
+
</details>
|
|
219
|
+
|
|
220
|
+
<details>
|
|
221
|
+
<summary>Raw data — Baseline runs</summary>
|
|
222
|
+
|
|
223
|
+
| Mode | Model | Case | Time | Input | Output | Total | Success |
|
|
224
|
+
|---|---|---|---|---|---|---|---|
|
|
225
|
+
| baseline | claude-sonnet-4.5 | single-edit | 11,107 ms | 37,775 | 336 | 38,111 | yes |
|
|
226
|
+
| baseline | claude-sonnet-4.5 | multi-line-replace | 12,876 ms | 26,541 | 456 | 26,997 | yes |
|
|
227
|
+
| baseline | claude-sonnet-4.5 | multi-edit | 17,343 ms | 38,890 | 895 | 39,785 | yes |
|
|
228
|
+
| baseline | claude-sonnet-4.5 | large-file-edit | 21,273 ms | 15,035 | 956 | 15,991 | yes |
|
|
229
|
+
| baseline | claude-opus-4.6 | single-edit | 12,464 ms | 13,146 | 273 | 13,419 | yes |
|
|
230
|
+
| baseline | claude-opus-4.6 | multi-line-replace | 14,016 ms | 13,554 | 411 | 13,965 | yes |
|
|
231
|
+
| baseline | claude-opus-4.6 | multi-edit | 43,656 ms | 15,873 | 1,710 | 17,583 | yes |
|
|
232
|
+
| baseline | claude-opus-4.6 | large-file-edit | 20,120 ms | 14,981 | 893 | 15,874 | yes |
|
|
233
|
+
| baseline | gpt-5.2-codex | single-edit | 11,662 ms | 7,656 | 346 | 8,002 | yes |
|
|
234
|
+
| baseline | gpt-5.2-codex | multi-line-replace | 11,922 ms | 8,039 | 286 | 8,325 | yes |
|
|
235
|
+
| baseline | gpt-5.2-codex | multi-edit | 22,087 ms | 8,519 | 991 | 9,510 | yes |
|
|
236
|
+
| baseline | gpt-5.2-codex | large-file-edit | 29,591 ms | 11,701 | 1,647 | 13,348 | yes |
|
|
237
|
+
| baseline | minimax-m2.5-free | single-edit | 10,740 ms | 10,389 | 302 | 10,691 | yes |
|
|
238
|
+
| baseline | minimax-m2.5-free | multi-line-replace | 16,274 ms | 10,668 | 437 | 11,105 | yes |
|
|
239
|
+
| baseline | minimax-m2.5-free | multi-edit | 43,462 ms | 1,233 | 1,075 | 2,308 | yes |
|
|
240
|
+
| baseline | minimax-m2.5-free | large-file-edit | 20,430 ms | 3,250 | 677 | 3,927 | yes |
|
|
241
|
+
|
|
242
|
+
</details>
|
|
243
|
+
|
|
244
|
+
<details>
|
|
245
|
+
<summary>Raw data — Smart Edit runs</summary>
|
|
246
|
+
|
|
247
|
+
| Mode | Model | Case | Time | Input | Output | Total | Success |
|
|
248
|
+
|---|---|---|---|---|---|---|---|
|
|
249
|
+
| smart_edit | claude-opus-4.6 | single-edit | 13,016 ms | 12,432 | 307 | 12,739 | yes |
|
|
250
|
+
| smart_edit | claude-opus-4.6 | multi-line-replace | 15,812 ms | 12,847 | 442 | 13,289 | yes |
|
|
251
|
+
| smart_edit | claude-opus-4.6 | multi-edit | 40,820 ms | 14,919 | 1,653 | 16,572 | yes |
|
|
252
|
+
| smart_edit | claude-opus-4.6 | large-file-edit | 32,170 ms | 15,377 | 1,314 | 16,691 | yes |
|
|
253
|
+
| smart_edit | minimax-m2.5-free | single-edit | 11,149 ms | 9,707 | 287 | 9,994 | yes |
|
|
254
|
+
| smart_edit | minimax-m2.5-free | multi-line-replace | 21,405 ms | 9,992 | 404 | 10,396 | yes |
|
|
255
|
+
| smart_edit | minimax-m2.5-free | multi-edit | 20,998 ms | 1,377 | 980 | 2,357 | yes |
|
|
256
|
+
| smart_edit | minimax-m2.5-free | large-file-edit | 41,250 ms | 3,212 | 774 | 3,986 | yes |
|
|
257
|
+
|
|
258
|
+
</details>
|
|
259
|
+
|
|
260
|
+
<details>
|
|
261
|
+
<summary>Raw data — OpenSlimedit runs</summary>
|
|
262
|
+
|
|
263
|
+
| Mode | Model | Case | Time | Input | Output | Total | Success |
|
|
264
|
+
|---|---|---|---|---|---|---|---|
|
|
265
|
+
| openslimedit | claude-opus-4.6 | single-edit | 12,126 ms | 9,629 | 273 | 9,902 | yes |
|
|
266
|
+
| openslimedit | claude-opus-4.6 | multi-line-replace | 15,326 ms | 10,066 | 481 | 10,547 | yes |
|
|
267
|
+
| openslimedit | claude-opus-4.6 | multi-edit | 41,378 ms | 12,095 | 1,648 | 13,743 | yes |
|
|
268
|
+
| openslimedit | claude-opus-4.6 | large-file-edit | 28,135 ms | 12,161 | 1,237 | 13,398 | yes |
|
|
269
|
+
| openslimedit | claude-sonnet-4.5 | single-edit | 10,884 ms | 18,148 | 312 | 18,460 | yes |
|
|
270
|
+
| openslimedit | claude-sonnet-4.5 | multi-line-replace | 13,208 ms | 19,528 | 514 | 20,042 | yes |
|
|
271
|
+
| openslimedit | claude-sonnet-4.5 | multi-edit | 20,895 ms | 18,985 | 955 | 19,940 | yes |
|
|
272
|
+
| openslimedit | claude-sonnet-4.5 | large-file-edit | 20,498 ms | 22,053 | 976 | 23,029 | yes |
|
|
273
|
+
| openslimedit | gpt-5.2-codex | single-edit | 8,745 ms | 13,841 | 186 | 14,027 | yes |
|
|
274
|
+
| openslimedit | gpt-5.2-codex | multi-line-replace | 10,123 ms | 6,770 | 249 | 7,019 | yes |
|
|
275
|
+
| openslimedit | gpt-5.2-codex | multi-edit | 13,653 ms | 4,239 | 558 | 4,797 | yes |
|
|
276
|
+
| openslimedit | gpt-5.2-codex | large-file-edit | 14,786 ms | 2,206 | 664 | 2,870 | yes |
|
|
277
|
+
| openslimedit | minimax-m2.5-free | single-edit | 15,159 ms | 7,140 | 265 | 7,405 | yes |
|
|
278
|
+
| openslimedit | minimax-m2.5-free | multi-line-replace | 14,744 ms | 1,316 | 405 | 1,721 | yes |
|
|
279
|
+
| openslimedit | minimax-m2.5-free | multi-edit | 13,289 ms | 7,385 | 649 | 8,034 | yes |
|
|
280
|
+
| openslimedit | minimax-m2.5-free | large-file-edit | 21,090 ms | 3,214 | 699 | 3,913 | yes |
|
|
281
|
+
|
|
282
|
+
</details>
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Project Structure
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
openslimedit/
|
|
290
|
+
├── src/
|
|
291
|
+
│ └── index.ts # Plugin implementation (single file)
|
|
292
|
+
├── package.json
|
|
293
|
+
├── tsconfig.json
|
|
294
|
+
├── LICENSE
|
|
295
|
+
└── README.md
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Contributing
|
|
301
|
+
|
|
302
|
+
Contributions are welcome. Please open an issue or submit a pull request.
|
|
303
|
+
|
|
304
|
+
## License
|
|
305
|
+
|
|
306
|
+
This project is licensed under the [MIT License](LICENSE).
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openslimedit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenCode plugin that reduces token usage by up to 33% — compresses tool descriptions, compacts read output, adds line-range edit support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "ASidorenkoCode",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/ASidorenkoCode/openslimedit.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/ASidorenkoCode/openslimedit",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/ASidorenkoCode/openslimedit/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"opencode",
|
|
18
|
+
"opencode-plugin",
|
|
19
|
+
"token-optimization",
|
|
20
|
+
"llm",
|
|
21
|
+
"code-editing",
|
|
22
|
+
"ai"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"postinstall": "node scripts/postinstall.js"
|
|
26
|
+
},
|
|
27
|
+
"exports": {
|
|
28
|
+
".": "./src/index.ts"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"src",
|
|
32
|
+
"scripts",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"@opencode-ai/plugin": "*"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@opencode-ai/plugin": "latest"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from "fs"
|
|
2
|
+
import path from "path"
|
|
3
|
+
|
|
4
|
+
const PLUGIN_NAME = "openslimedit"
|
|
5
|
+
|
|
6
|
+
// INIT_CWD is set by npm/bun to the directory where install was run
|
|
7
|
+
const projectDir = process.env.INIT_CWD
|
|
8
|
+
if (!projectDir) {
|
|
9
|
+
console.log(` openslimedit installed. Add "${PLUGIN_NAME}" to your .opencode/opencode.json plugins array.`)
|
|
10
|
+
process.exit(0)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const configDir = path.join(projectDir, ".opencode")
|
|
14
|
+
const configFile = path.join(configDir, "opencode.json")
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
let config = {}
|
|
18
|
+
|
|
19
|
+
if (fs.existsSync(configFile)) {
|
|
20
|
+
const raw = fs.readFileSync(configFile, "utf-8")
|
|
21
|
+
config = JSON.parse(raw)
|
|
22
|
+
} else {
|
|
23
|
+
// Also check for opencode.jsonc
|
|
24
|
+
const jsoncFile = path.join(configDir, "opencode.jsonc")
|
|
25
|
+
if (fs.existsSync(jsoncFile)) {
|
|
26
|
+
console.log(` openslimedit: found opencode.jsonc — please add "${PLUGIN_NAME}" to the plugin array manually.`)
|
|
27
|
+
process.exit(0)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!Array.isArray(config.plugin)) {
|
|
32
|
+
config.plugin = []
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Check if already configured (with or without version suffix)
|
|
36
|
+
const alreadyExists = config.plugin.some(
|
|
37
|
+
(p) => p === PLUGIN_NAME || p.startsWith(PLUGIN_NAME + "@")
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if (alreadyExists) {
|
|
41
|
+
console.log(` openslimedit: already configured in ${configFile}`)
|
|
42
|
+
process.exit(0)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
config.plugin.push(PLUGIN_NAME)
|
|
46
|
+
|
|
47
|
+
if (!fs.existsSync(configDir)) {
|
|
48
|
+
fs.mkdirSync(configDir, { recursive: true })
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n")
|
|
52
|
+
console.log(` openslimedit: added to ${configFile}`)
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.log(` openslimedit installed. Add "${PLUGIN_NAME}" to your .opencode/opencode.json plugins array.`)
|
|
55
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin"
|
|
2
|
+
import * as fs from "fs"
|
|
3
|
+
import * as path from "path"
|
|
4
|
+
|
|
5
|
+
const LINE_RANGE_RE = /^(\d+)(?:\s*-\s*(\d+))?$/
|
|
6
|
+
|
|
7
|
+
export const OpenSlimeditPlugin: Plugin = async ({ directory }) => {
|
|
8
|
+
function resolvePath(filePath: string): string {
|
|
9
|
+
if (path.isAbsolute(filePath)) return path.normalize(filePath)
|
|
10
|
+
return path.resolve(directory, filePath)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
// Aggressively shorten ALL tool descriptions
|
|
15
|
+
"tool.definition": async (input: any, output: any) => {
|
|
16
|
+
const SLIM: Record<string, string> = {
|
|
17
|
+
read: "Read file content.",
|
|
18
|
+
edit: "Edit file. oldString can be line range '55-64'.",
|
|
19
|
+
write: "Write file.",
|
|
20
|
+
bash: "Run shell command.",
|
|
21
|
+
glob: "Find files.",
|
|
22
|
+
grep: "Search in files.",
|
|
23
|
+
list: "List directory.",
|
|
24
|
+
fetch: "Fetch URL.",
|
|
25
|
+
}
|
|
26
|
+
if (SLIM[input.toolID]) {
|
|
27
|
+
output.description = SLIM[input.toolID]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// Compact read output: shorten path, strip footer
|
|
32
|
+
"tool.execute.after": async (input, output) => {
|
|
33
|
+
if (input.tool !== "read") return
|
|
34
|
+
if (output.output.includes("<type>directory</type>")) return
|
|
35
|
+
|
|
36
|
+
const pathMatch = output.output.match(/<path>(.+?)<\/path>/)
|
|
37
|
+
if (!pathMatch) return
|
|
38
|
+
|
|
39
|
+
// Shorten to relative path
|
|
40
|
+
const absPath = path.normalize(pathMatch[1])
|
|
41
|
+
const relPath = path.relative(directory, absPath)
|
|
42
|
+
output.output = output.output.replace(
|
|
43
|
+
`<path>${pathMatch[1]}</path>`,
|
|
44
|
+
`<path>${relPath}</path>`,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
// Remove type tag and footer
|
|
48
|
+
output.output = output.output.replace("<type>file</type>\n", "")
|
|
49
|
+
output.output = output.output.replace(
|
|
50
|
+
/\n\n\(End of file - total \d+ lines\)\n/,
|
|
51
|
+
"\n",
|
|
52
|
+
)
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// Expand line ranges in oldString
|
|
56
|
+
"tool.execute.before": async (input, output) => {
|
|
57
|
+
if (input.tool !== "edit") return
|
|
58
|
+
const args = output.args
|
|
59
|
+
if (!args.oldString || !args.filePath) return
|
|
60
|
+
|
|
61
|
+
const filePath = resolvePath(args.filePath)
|
|
62
|
+
let content: string
|
|
63
|
+
try {
|
|
64
|
+
content = fs.readFileSync(filePath, "utf-8")
|
|
65
|
+
} catch {
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (content.includes(args.oldString)) return
|
|
70
|
+
|
|
71
|
+
const match = args.oldString.trim().match(LINE_RANGE_RE)
|
|
72
|
+
if (!match) return
|
|
73
|
+
|
|
74
|
+
const lines = content.split("\n")
|
|
75
|
+
const startLine = parseInt(match[1], 10)
|
|
76
|
+
const endLine = match[2] ? parseInt(match[2], 10) : startLine
|
|
77
|
+
|
|
78
|
+
if (startLine >= 1 && endLine <= lines.length && startLine <= endLine) {
|
|
79
|
+
args.oldString = lines.slice(startLine - 1, endLine).join("\n")
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
} as any
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default OpenSlimeditPlugin
|