opencode-readseek 0.9.0 → 0.9.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.
- package/index.ts +56 -10
- package/package.json +2 -2
package/index.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { tool, type Plugin, type PluginOptions, type ToolAttachment, type ToolCo
|
|
|
10
10
|
|
|
11
11
|
const require = createRequire(import.meta.url);
|
|
12
12
|
const MAX_OUTPUT_BYTES = 32 * 1024 * 1024;
|
|
13
|
+
const DEFAULT_READSEEK_TIMEOUT_MS = 120_000;
|
|
14
|
+
const DEFAULT_VISION_TIMEOUT_MS = 30 * 60 * 1000;
|
|
13
15
|
const DEFAULT_READ_LIMIT = 2000;
|
|
14
16
|
const EDIT_RESULT_READ_LIMIT = 40;
|
|
15
17
|
const MAX_DOCUMENT_OUTPUT_BYTES = 256 * 1024;
|
|
@@ -386,7 +388,7 @@ function readRangeArgs(filePath: string, start: number, end: number): string[] {
|
|
|
386
388
|
async function runDigestContent(
|
|
387
389
|
context: ToolContext,
|
|
388
390
|
args: string[],
|
|
389
|
-
options: { cancelable?: boolean } = {},
|
|
391
|
+
options: { cancelable?: boolean; timeoutMs?: number } = {},
|
|
390
392
|
): Promise<unknown> {
|
|
391
393
|
return requireDigestFacet(await runReadSeek(context, args, options), "content");
|
|
392
394
|
}
|
|
@@ -439,7 +441,7 @@ async function readBoundedText(
|
|
|
439
441
|
async function runReadSeekRaw(
|
|
440
442
|
context: ToolContext,
|
|
441
443
|
args: string[],
|
|
442
|
-
options: { cancelable?: boolean; stdin?: string } = {},
|
|
444
|
+
options: { cancelable?: boolean; stdin?: string; timeoutMs?: number } = {},
|
|
443
445
|
): Promise<string> {
|
|
444
446
|
context.abort.throwIfAborted();
|
|
445
447
|
const cancelable = options.cancelable !== false;
|
|
@@ -465,11 +467,31 @@ async function runReadSeekRaw(
|
|
|
465
467
|
// Preserve the output-limit error if the process exited concurrently.
|
|
466
468
|
}
|
|
467
469
|
};
|
|
468
|
-
const
|
|
470
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_READSEEK_TIMEOUT_MS;
|
|
471
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
472
|
+
const timeoutResult = new Promise<never>((_resolve, reject) => {
|
|
473
|
+
timeout = setTimeout(() => {
|
|
474
|
+
try {
|
|
475
|
+
child.kill("SIGKILL");
|
|
476
|
+
} catch {
|
|
477
|
+
// Preserve the timeout error if the process exited concurrently.
|
|
478
|
+
}
|
|
479
|
+
reject(new Error(`readseek timed out after ${timeoutMs} ms`));
|
|
480
|
+
}, timeoutMs);
|
|
481
|
+
timeout.unref?.();
|
|
482
|
+
});
|
|
483
|
+
const pending = Promise.all([
|
|
469
484
|
readBoundedText(child.stdout, "stdout", killForOverflow),
|
|
470
485
|
readBoundedText(child.stderr, "stderr", killForOverflow),
|
|
471
486
|
child.exited,
|
|
472
487
|
]);
|
|
488
|
+
let result: Awaited<typeof pending>;
|
|
489
|
+
try {
|
|
490
|
+
result = await Promise.race([pending, timeoutResult]);
|
|
491
|
+
} finally {
|
|
492
|
+
if (timeout !== undefined) clearTimeout(timeout);
|
|
493
|
+
}
|
|
494
|
+
const [stdout, stderr, exitCode] = result;
|
|
473
495
|
if (cancelable) context.abort.throwIfAborted();
|
|
474
496
|
if (exitCode !== 0) throw new Error(stderr.trim() || `readseek exited with status ${exitCode}`);
|
|
475
497
|
return stdout;
|
|
@@ -478,7 +500,7 @@ async function runReadSeekRaw(
|
|
|
478
500
|
async function runReadSeek(
|
|
479
501
|
context: ToolContext,
|
|
480
502
|
args: string[],
|
|
481
|
-
options: { cancelable?: boolean; stdin?: string } = {},
|
|
503
|
+
options: { cancelable?: boolean; stdin?: string; timeoutMs?: number } = {},
|
|
482
504
|
): Promise<unknown> {
|
|
483
505
|
const stdout = await runReadSeekRaw(context, args, options);
|
|
484
506
|
try {
|
|
@@ -495,7 +517,10 @@ async function postMutationPreview(
|
|
|
495
517
|
changed: boolean,
|
|
496
518
|
): Promise<unknown> {
|
|
497
519
|
try {
|
|
498
|
-
return await runDigestContent(context, args, {
|
|
520
|
+
return await runDigestContent(context, args, {
|
|
521
|
+
cancelable: false,
|
|
522
|
+
timeoutMs: DEFAULT_READSEEK_TIMEOUT_MS,
|
|
523
|
+
});
|
|
499
524
|
} catch (error) {
|
|
500
525
|
const previewError = error instanceof Error ? error.message : String(error);
|
|
501
526
|
return {
|
|
@@ -1150,7 +1175,11 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
|
|
|
1150
1175
|
|
|
1151
1176
|
let envelope: unknown;
|
|
1152
1177
|
try {
|
|
1153
|
-
envelope = await runReadSeek(
|
|
1178
|
+
envelope = await runReadSeek(
|
|
1179
|
+
context,
|
|
1180
|
+
digestArgs(filePath, "content", extra),
|
|
1181
|
+
image !== undefined && image !== "none" ? { timeoutMs: DEFAULT_VISION_TIMEOUT_MS } : {},
|
|
1182
|
+
);
|
|
1154
1183
|
} catch (error) {
|
|
1155
1184
|
// A visual or document file with an uncommon extension rejects text bounds before
|
|
1156
1185
|
// an envelope can be returned. Probe metadata only on this cold path.
|
|
@@ -1224,7 +1253,11 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
|
|
|
1224
1253
|
optionalFlag(args, input.outline as boolean | undefined, "--outline");
|
|
1225
1254
|
if (visionMode !== undefined) args.push("--vision-mode", visionMode);
|
|
1226
1255
|
if (visionLevel !== undefined) args.push("--vision-level", visionLevel);
|
|
1227
|
-
return runReadSeekRaw(
|
|
1256
|
+
return runReadSeekRaw(
|
|
1257
|
+
context,
|
|
1258
|
+
args,
|
|
1259
|
+
visionMode === undefined ? {} : { timeoutMs: DEFAULT_VISION_TIMEOUT_MS },
|
|
1260
|
+
);
|
|
1228
1261
|
},
|
|
1229
1262
|
(result) => ({ output: boundDocumentOutput(String(result)) }),
|
|
1230
1263
|
),
|
|
@@ -1262,7 +1295,13 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
|
|
|
1262
1295
|
if (input.language) args.push("--language", input.language as string);
|
|
1263
1296
|
if (visionMode !== undefined) args.push("--vision-mode", visionMode);
|
|
1264
1297
|
if (visionLevel !== undefined) args.push("--vision-level", visionLevel);
|
|
1265
|
-
return runReadSeek(
|
|
1298
|
+
return runReadSeek(
|
|
1299
|
+
context,
|
|
1300
|
+
args,
|
|
1301
|
+
visionMode === undefined || visionMode === "none"
|
|
1302
|
+
? {}
|
|
1303
|
+
: { timeoutMs: DEFAULT_VISION_TIMEOUT_MS },
|
|
1304
|
+
);
|
|
1266
1305
|
},
|
|
1267
1306
|
),
|
|
1268
1307
|
readseek_grep: readseekTool(
|
|
@@ -1457,7 +1496,10 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
|
|
|
1457
1496
|
throw new Error("readseek rename plan did not include a plan hash");
|
|
1458
1497
|
}
|
|
1459
1498
|
await authorizeEdit(context, files);
|
|
1460
|
-
return runReadSeek(context, [...args, "--plan-hash", planHash, "--apply"], {
|
|
1499
|
+
return runReadSeek(context, [...args, "--plan-hash", planHash, "--apply"], {
|
|
1500
|
+
cancelable: false,
|
|
1501
|
+
timeoutMs: DEFAULT_READSEEK_TIMEOUT_MS,
|
|
1502
|
+
});
|
|
1461
1503
|
},
|
|
1462
1504
|
),
|
|
1463
1505
|
readseek_edit: readseekTool(
|
|
@@ -1532,7 +1574,11 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
|
|
|
1532
1574
|
const applied = record(await runReadSeek(
|
|
1533
1575
|
context,
|
|
1534
1576
|
[...baseArgs, "--apply", "--plan-hash", plan.plan_hash],
|
|
1535
|
-
{
|
|
1577
|
+
{
|
|
1578
|
+
cancelable: false,
|
|
1579
|
+
stdin: request,
|
|
1580
|
+
timeoutMs: DEFAULT_READSEEK_TIMEOUT_MS,
|
|
1581
|
+
},
|
|
1536
1582
|
));
|
|
1537
1583
|
if (applied.applied !== true) {
|
|
1538
1584
|
throw new Error("readseek did not confirm that the edit was applied");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-readseek",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "OpenCode plugin for anchored file operations and structural code navigation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"node": ">=20.0.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@jarkkojs/readseek": "^0.9.
|
|
34
|
+
"@jarkkojs/readseek": "^0.9.1",
|
|
35
35
|
"@opencode-ai/plugin": "^1.17.20"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|