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 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