opencode-fast-apply 2.1.2 → 2.1.4
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/README.md +0 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +50 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,16 +20,6 @@ OpenCode plugin for Fast Apply - High-performance code editing with OpenAI-compa
|
|
|
20
20
|
npm install -g opencode-fast-apply
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Or add to your OpenCode config to auto-install:
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"plugin": [
|
|
28
|
-
"opencode-fast-apply"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
23
|
### 2. Configure your API endpoint
|
|
34
24
|
|
|
35
25
|
For **LM Studio** (default):
|
|
@@ -62,7 +52,6 @@ Add to your global config (`~/.config/opencode/opencode.json` or `opencode.jsonc
|
|
|
62
52
|
```json
|
|
63
53
|
{
|
|
64
54
|
"plugin": [
|
|
65
|
-
"opencode-pty",
|
|
66
55
|
"opencode-fast-apply"
|
|
67
56
|
]
|
|
68
57
|
}
|
|
@@ -109,9 +98,7 @@ function validateToken(token) {
|
|
|
109
98
|
| `FAST_APPLY_API_KEY` | `optional-api-key` | API key (optional for local servers) |
|
|
110
99
|
| `FAST_APPLY_URL` | `http://localhost:1234/v1` | OpenAI-compatible API endpoint |
|
|
111
100
|
| `FAST_APPLY_MODEL` | `fastapply-1.5b` | Model name |
|
|
112
|
-
| `FAST_APPLY_TIMEOUT` | `30000` | Request timeout in ms |
|
|
113
101
|
| `FAST_APPLY_TEMPERATURE` | `0.05` | Temperature (0.0-2.0) |
|
|
114
|
-
| `FAST_APPLY_MAX_TOKENS` | `8000` | Maximum tokens in response |
|
|
115
102
|
|
|
116
103
|
## How It Works
|
|
117
104
|
|
|
@@ -174,12 +161,6 @@ curl -X POST http://localhost:1234/v1/chat/completions \
|
|
|
174
161
|
- Use Q4 quantization for faster inference
|
|
175
162
|
- Increase `FAST_APPLY_MAX_TOKENS` if responses are truncated
|
|
176
163
|
|
|
177
|
-
### Timeout Errors
|
|
178
|
-
```bash
|
|
179
|
-
# Increase timeout for slower hardware
|
|
180
|
-
export FAST_APPLY_TIMEOUT="60000" # 60 seconds
|
|
181
|
-
```
|
|
182
|
-
|
|
183
164
|
## Contributing
|
|
184
165
|
|
|
185
166
|
Contributions welcome! This plugin could potentially be integrated into OpenCode core.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,qBAAqB,CAAA;AA0avD,eAAO,MAAM,eAAe,EAAE,MA4J7B,CAAA;AAGD,eAAe,eAAe,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -11,13 +11,12 @@ import { tool } from "@opencode-ai/plugin";
|
|
|
11
11
|
import { createTwoFilesPatch } from "diff";
|
|
12
12
|
import { readFile, writeFile, access } from "fs/promises";
|
|
13
13
|
import { constants } from "fs";
|
|
14
|
+
const sessionParamsCache = new Map();
|
|
14
15
|
// Get API key from environment (set in mcpm/jarvis config)
|
|
15
16
|
const FAST_APPLY_API_KEY = process.env.FAST_APPLY_API_KEY || "optional-api-key";
|
|
16
17
|
const FAST_APPLY_URL = (process.env.FAST_APPLY_URL || "http://localhost:1234/v1").replace(/\/v1\/?$/, "");
|
|
17
18
|
const FAST_APPLY_MODEL = process.env.FAST_APPLY_MODEL || "fastapply-1.5b";
|
|
18
|
-
const FAST_APPLY_TIMEOUT = parseInt(process.env.FAST_APPLY_TIMEOUT || "30000", 10);
|
|
19
19
|
const FAST_APPLY_TEMPERATURE = parseFloat(process.env.FAST_APPLY_TEMPERATURE || "0.05");
|
|
20
|
-
const FAST_APPLY_MAX_TOKENS = parseInt(process.env.FAST_APPLY_MAX_TOKENS || "8000", 10);
|
|
21
20
|
const FAST_APPLY_SYSTEM_PROMPT = "You are a coding assistant that helps merge code updates, ensuring every modification is fully integrated.";
|
|
22
21
|
const FAST_APPLY_USER_PROMPT = `Merge all changes from the <update> snippet into the <code> below.
|
|
23
22
|
- Preserve the code's structure, order, comments, and indentation exactly.
|
|
@@ -191,11 +190,6 @@ function shortenPath(filePath, workingDir) {
|
|
|
191
190
|
}
|
|
192
191
|
return filePath;
|
|
193
192
|
}
|
|
194
|
-
function truncate(str, maxLen = 80) {
|
|
195
|
-
if (str.length <= maxLen)
|
|
196
|
-
return str;
|
|
197
|
-
return str.slice(0, maxLen - 3) + "...";
|
|
198
|
-
}
|
|
199
193
|
function estimateTokens(text) {
|
|
200
194
|
return Math.ceil(text.length / 4);
|
|
201
195
|
}
|
|
@@ -234,8 +228,6 @@ async function callFastApply(originalCode, codeEdit, instructions) {
|
|
|
234
228
|
error: "FAST_APPLY_API_KEY not set. Get one at https://openai.com/api",
|
|
235
229
|
};
|
|
236
230
|
}
|
|
237
|
-
const controller = new AbortController();
|
|
238
|
-
const timeoutId = setTimeout(() => controller.abort(), FAST_APPLY_TIMEOUT);
|
|
239
231
|
try {
|
|
240
232
|
const escapedOriginalCode = escapeXmlTags(originalCode);
|
|
241
233
|
const escapedCodeEdit = escapeXmlTags(codeEdit);
|
|
@@ -261,11 +253,8 @@ async function callFastApply(originalCode, codeEdit, instructions) {
|
|
|
261
253
|
},
|
|
262
254
|
],
|
|
263
255
|
temperature: FAST_APPLY_TEMPERATURE,
|
|
264
|
-
max_tokens: FAST_APPLY_MAX_TOKENS,
|
|
265
256
|
}),
|
|
266
|
-
signal: controller.signal,
|
|
267
257
|
});
|
|
268
|
-
clearTimeout(timeoutId);
|
|
269
258
|
if (!response.ok) {
|
|
270
259
|
const errorText = await response.text();
|
|
271
260
|
return {
|
|
@@ -288,34 +277,30 @@ async function callFastApply(originalCode, codeEdit, instructions) {
|
|
|
288
277
|
};
|
|
289
278
|
}
|
|
290
279
|
catch (err) {
|
|
291
|
-
clearTimeout(timeoutId);
|
|
292
280
|
const error = err;
|
|
293
|
-
if (error.name === "AbortError") {
|
|
294
|
-
return {
|
|
295
|
-
success: false,
|
|
296
|
-
error: `Fast Apply API timeout after ${FAST_APPLY_TIMEOUT}ms`,
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
281
|
return {
|
|
300
282
|
success: false,
|
|
301
283
|
error: `Fast Apply API request failed: ${error.message}`,
|
|
302
284
|
};
|
|
303
285
|
}
|
|
304
286
|
}
|
|
305
|
-
async function
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
287
|
+
async function sendTUIMessage(client, sessionID, message, params) {
|
|
288
|
+
const agent = params.agent || undefined;
|
|
289
|
+
const variant = params.variant || undefined;
|
|
290
|
+
const model = params.providerId && params.modelId
|
|
291
|
+
? {
|
|
292
|
+
providerID: params.providerId,
|
|
293
|
+
modelID: params.modelId,
|
|
294
|
+
}
|
|
295
|
+
: undefined;
|
|
314
296
|
try {
|
|
315
297
|
await client.session.prompt({
|
|
316
298
|
path: { id: sessionID },
|
|
317
299
|
body: {
|
|
318
300
|
noReply: true,
|
|
301
|
+
agent: agent,
|
|
302
|
+
model: model,
|
|
303
|
+
variant: variant,
|
|
319
304
|
parts: [
|
|
320
305
|
{
|
|
321
306
|
type: "text",
|
|
@@ -330,6 +315,29 @@ async function sendTUINotification(client, sessionID, filePath, workingDir, inse
|
|
|
330
315
|
console.error("[fast-apply] Failed to send TUI notification:", error.message);
|
|
331
316
|
}
|
|
332
317
|
}
|
|
318
|
+
async function sendTUINotification(client, sessionID, filePath, workingDir, insertions, deletions, modifiedTokens, params) {
|
|
319
|
+
const shortPath = shortenPath(filePath, workingDir);
|
|
320
|
+
const tokenStr = formatTokenCount(modifiedTokens);
|
|
321
|
+
const message = [
|
|
322
|
+
`▣ Fast Apply | ~${tokenStr} tokens modified`,
|
|
323
|
+
"",
|
|
324
|
+
"Applied changes:",
|
|
325
|
+
`→ ${shortPath}: +${insertions} -${deletions}`
|
|
326
|
+
].join("\n");
|
|
327
|
+
await sendTUIMessage(client, sessionID, message, params);
|
|
328
|
+
}
|
|
329
|
+
async function sendTUIErrorNotification(client, sessionID, filePath, workingDir, errorMessage, params) {
|
|
330
|
+
const shortPath = shortenPath(filePath, workingDir);
|
|
331
|
+
const message = [
|
|
332
|
+
`✗ Fast Apply Error`,
|
|
333
|
+
"",
|
|
334
|
+
`File: ${shortPath}`,
|
|
335
|
+
`Error: ${errorMessage}`,
|
|
336
|
+
"",
|
|
337
|
+
"Fallback: Use native 'edit' tool"
|
|
338
|
+
].join("\n");
|
|
339
|
+
await sendTUIMessage(client, sessionID, message, params);
|
|
340
|
+
}
|
|
333
341
|
export const FastApplyPlugin = async ({ directory, client }) => {
|
|
334
342
|
if (!FAST_APPLY_API_KEY) {
|
|
335
343
|
console.warn("[fast-apply] FAST_APPLY_API_KEY not set - fast_apply_edit tool will be disabled");
|
|
@@ -338,6 +346,14 @@ export const FastApplyPlugin = async ({ directory, client }) => {
|
|
|
338
346
|
console.log(`[fast-apply] Plugin loaded with model: ${FAST_APPLY_MODEL} at ${FAST_APPLY_URL}`);
|
|
339
347
|
}
|
|
340
348
|
return {
|
|
349
|
+
"chat.message": async (input) => {
|
|
350
|
+
sessionParamsCache.set(input.sessionID, {
|
|
351
|
+
agent: input.agent,
|
|
352
|
+
providerId: input.model?.providerID,
|
|
353
|
+
modelId: input.model?.modelID,
|
|
354
|
+
variant: input.variant,
|
|
355
|
+
});
|
|
356
|
+
},
|
|
341
357
|
tool: {
|
|
342
358
|
fast_apply_edit: tool({
|
|
343
359
|
description: TOOL_INSTRUCTIONS,
|
|
@@ -354,6 +370,7 @@ export const FastApplyPlugin = async ({ directory, client }) => {
|
|
|
354
370
|
},
|
|
355
371
|
async execute(args, toolCtx) {
|
|
356
372
|
const { target_filepath, instructions, code_edit } = args;
|
|
373
|
+
const params = sessionParamsCache.get(toolCtx.sessionID) || {};
|
|
357
374
|
// Resolve file path relative to project directory
|
|
358
375
|
const filepath = target_filepath.startsWith("/")
|
|
359
376
|
? target_filepath
|
|
@@ -392,7 +409,9 @@ write({
|
|
|
392
409
|
// Call OpenAI API to merge the edit
|
|
393
410
|
const result = await callFastApply(originalCode, code_edit, instructions);
|
|
394
411
|
if (!result.success || !result.content) {
|
|
395
|
-
|
|
412
|
+
const errorMsg = result.error || "Unknown error";
|
|
413
|
+
await sendTUIErrorNotification(client, toolCtx.sessionID, target_filepath, directory, errorMsg, params);
|
|
414
|
+
return formatErrorOutput(errorMsg, target_filepath, directory);
|
|
396
415
|
}
|
|
397
416
|
const mergedCode = result.content;
|
|
398
417
|
try {
|
|
@@ -400,12 +419,13 @@ write({
|
|
|
400
419
|
}
|
|
401
420
|
catch (err) {
|
|
402
421
|
const error = err;
|
|
422
|
+
await sendTUIErrorNotification(client, toolCtx.sessionID, target_filepath, directory, error.message, params);
|
|
403
423
|
return formatErrorOutput(error.message, target_filepath, directory);
|
|
404
424
|
}
|
|
405
425
|
const diff = generateUnifiedDiff(target_filepath, originalCode, mergedCode);
|
|
406
426
|
const { added, removed } = countChanges(diff);
|
|
407
427
|
const modifiedTokens = estimateTokens(diff);
|
|
408
|
-
await sendTUINotification(client, toolCtx.sessionID, target_filepath, directory, added, removed, modifiedTokens);
|
|
428
|
+
await sendTUINotification(client, toolCtx.sessionID, target_filepath, directory, added, removed, modifiedTokens, params);
|
|
409
429
|
return formatFastApplyResult(target_filepath, directory, added, removed, diff, modifiedTokens);
|
|
410
430
|
},
|
|
411
431
|
}),
|
package/package.json
CHANGED