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 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.
@@ -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;AA0YvD,eAAO,MAAM,eAAe,EAAE,MA2H7B,CAAA;AAGD,eAAe,eAAe,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 sendTUINotification(client, sessionID, filePath, workingDir, insertions, deletions, modifiedTokens) {
306
- const shortPath = shortenPath(filePath, workingDir);
307
- const tokenStr = formatTokenCount(modifiedTokens);
308
- const message = [
309
- `▣ Fast Apply | ~${tokenStr} tokens modified`,
310
- "",
311
- "Applied changes:",
312
- `→ ${shortPath}: +${insertions} -${deletions}`
313
- ].join("\n");
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
- return formatErrorOutput(result.error || "Unknown error", target_filepath, directory);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-fast-apply",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "OpenCode plugin for Fast Apply - High-performance code editing with OpenAI-compatible APIs (LM Studio, Ollama)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",