topchester-ai 0.66.0 → 0.67.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/dist/bin.mjs
CHANGED
|
@@ -9,8 +9,9 @@ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
|
9
9
|
import { generateText, stepCountIs, streamText, tool } from "ai";
|
|
10
10
|
import { ZodError, z } from "zod";
|
|
11
11
|
import { execFile, spawn } from "node:child_process";
|
|
12
|
-
import { accessSync, constants, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { accessSync, constants, createReadStream, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { createHash, randomUUID } from "node:crypto";
|
|
14
|
+
import { TextDecoder as TextDecoder$1 } from "node:util";
|
|
14
15
|
import { parseDocument } from "yaml";
|
|
15
16
|
import { fileURLToPath } from "node:url";
|
|
16
17
|
import pino from "pino";
|
|
@@ -4107,6 +4108,10 @@ const planTodoTool = defineTool({
|
|
|
4107
4108
|
};
|
|
4108
4109
|
}
|
|
4109
4110
|
});
|
|
4111
|
+
//#endregion
|
|
4112
|
+
//#region src/agent/tools/read-file.ts
|
|
4113
|
+
const MAX_UTF8_READ_BYTES = 512 * 1024;
|
|
4114
|
+
const SAMPLE_BYTES = 256;
|
|
4110
4115
|
const readFileTool = defineTool({
|
|
4111
4116
|
name: "read_file",
|
|
4112
4117
|
description: "Read a UTF-8 file inside the workspace.",
|
|
@@ -4133,15 +4138,94 @@ async function readWorkspaceFile(workspaceRoot, path) {
|
|
|
4133
4138
|
const resolvedPath = isAbsolute(path) ? resolve(path) : resolve(resolvedWorkspace, path);
|
|
4134
4139
|
const relativePath = relative(resolvedWorkspace, resolvedPath);
|
|
4135
4140
|
if (relativePath.startsWith("..") || isAbsolute(relativePath)) throw new Error(`read_file can only read files inside the workspace: ${path}`);
|
|
4141
|
+
const fileStat = await stat(resolvedPath);
|
|
4142
|
+
if (!fileStat.isFile()) throw new Error(`read_file can only read regular files: ${path}`);
|
|
4143
|
+
if (fileStat.size > MAX_UTF8_READ_BYTES) {
|
|
4144
|
+
const [sample, hash] = await Promise.all([readFileSample(resolvedPath, SAMPLE_BYTES), hashFile$2(resolvedPath)]);
|
|
4145
|
+
return {
|
|
4146
|
+
tool: "read_file",
|
|
4147
|
+
path: relativePath || ".",
|
|
4148
|
+
content: formatSkippedReadSummary({
|
|
4149
|
+
reason: "too_large",
|
|
4150
|
+
relativePath: relativePath || ".",
|
|
4151
|
+
bytes: fileStat.size,
|
|
4152
|
+
sample
|
|
4153
|
+
}),
|
|
4154
|
+
hash,
|
|
4155
|
+
skipped: "too_large",
|
|
4156
|
+
bytes: fileStat.size,
|
|
4157
|
+
warning: `Skipped reading ${relativePath || "."}: file is ${fileStat.size} bytes, above the ${MAX_UTF8_READ_BYTES} byte read_file limit.`
|
|
4158
|
+
};
|
|
4159
|
+
}
|
|
4136
4160
|
const bytes = await readFile(resolvedPath);
|
|
4161
|
+
const hash = `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
4162
|
+
if (looksBinary$1(bytes) || !isValidUtf8(bytes)) {
|
|
4163
|
+
const sample = bytes.subarray(0, SAMPLE_BYTES);
|
|
4164
|
+
return {
|
|
4165
|
+
tool: "read_file",
|
|
4166
|
+
path: relativePath || ".",
|
|
4167
|
+
content: formatSkippedReadSummary({
|
|
4168
|
+
reason: "binary",
|
|
4169
|
+
relativePath: relativePath || ".",
|
|
4170
|
+
bytes: fileStat.size,
|
|
4171
|
+
sample
|
|
4172
|
+
}),
|
|
4173
|
+
hash,
|
|
4174
|
+
skipped: "binary",
|
|
4175
|
+
bytes: fileStat.size,
|
|
4176
|
+
warning: `Skipped reading ${relativePath || "."}: file appears to be binary or non-UTF-8.`
|
|
4177
|
+
};
|
|
4178
|
+
}
|
|
4137
4179
|
const content = bytes.toString("utf8");
|
|
4138
4180
|
return {
|
|
4139
4181
|
tool: "read_file",
|
|
4140
4182
|
path: relativePath || ".",
|
|
4141
4183
|
content,
|
|
4142
|
-
hash
|
|
4184
|
+
hash
|
|
4143
4185
|
};
|
|
4144
4186
|
}
|
|
4187
|
+
function looksBinary$1(bytes) {
|
|
4188
|
+
return bytes.subarray(0, Math.min(bytes.length, SAMPLE_BYTES)).includes(0);
|
|
4189
|
+
}
|
|
4190
|
+
function isValidUtf8(bytes) {
|
|
4191
|
+
try {
|
|
4192
|
+
new TextDecoder$1("utf-8", { fatal: true }).decode(bytes);
|
|
4193
|
+
return true;
|
|
4194
|
+
} catch {
|
|
4195
|
+
return false;
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
function formatSkippedReadSummary(options) {
|
|
4199
|
+
const reason = options.reason === "binary" ? "read_file did not return file contents because this file appears to be binary or non-UTF-8." : `read_file did not return file contents because this file is ${options.bytes} bytes, above the ${MAX_UTF8_READ_BYTES} byte limit.`;
|
|
4200
|
+
const sampleHex = options.sample.length > 0 ? options.sample.toString("hex").match(/.{1,2}/g)?.join(" ") : "";
|
|
4201
|
+
return [
|
|
4202
|
+
reason,
|
|
4203
|
+
`path: ${options.relativePath}`,
|
|
4204
|
+
`bytes: ${options.bytes}`,
|
|
4205
|
+
sampleHex ? `first_${options.sample.length}_bytes_hex: ${sampleHex}` : "first_bytes_hex: <empty>",
|
|
4206
|
+
"Use shell inspection tools such as `file`, `xxd`, `readelf`, `objdump`, `strings`, or a focused parser instead of reading the whole file into context."
|
|
4207
|
+
].join("\n");
|
|
4208
|
+
}
|
|
4209
|
+
async function readFileSample(path, maxBytes) {
|
|
4210
|
+
const handle = await open(path, "r");
|
|
4211
|
+
try {
|
|
4212
|
+
const sample = Buffer.alloc(maxBytes);
|
|
4213
|
+
const { bytesRead } = await handle.read(sample, 0, maxBytes, 0);
|
|
4214
|
+
return sample.subarray(0, bytesRead);
|
|
4215
|
+
} finally {
|
|
4216
|
+
await handle.close();
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
async function hashFile$2(path) {
|
|
4220
|
+
const hash = createHash("sha256");
|
|
4221
|
+
await new Promise((resolvePromise, reject) => {
|
|
4222
|
+
const stream = createReadStream(path);
|
|
4223
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
4224
|
+
stream.on("error", reject);
|
|
4225
|
+
stream.on("end", resolvePromise);
|
|
4226
|
+
});
|
|
4227
|
+
return `sha256:${hash.digest("hex")}`;
|
|
4228
|
+
}
|
|
4145
4229
|
//#endregion
|
|
4146
4230
|
//#region src/agent/tools/command-policy.ts
|
|
4147
4231
|
const PACKAGE_MANAGERS = new Set([
|
|
@@ -14087,6 +14171,14 @@ function getToolCallDisplayDiff(result) {
|
|
|
14087
14171
|
function readMaxToolCallsPerTurn() {
|
|
14088
14172
|
const raw = process.env[MAX_TOOL_CALLS_PER_TURN_ENV]?.trim();
|
|
14089
14173
|
if (!raw) return DEFAULT_MAX_TOOL_CALLS_PER_TURN;
|
|
14174
|
+
if ([
|
|
14175
|
+
"0",
|
|
14176
|
+
"off",
|
|
14177
|
+
"false",
|
|
14178
|
+
"none",
|
|
14179
|
+
"unlimited",
|
|
14180
|
+
"disabled"
|
|
14181
|
+
].includes(raw.toLowerCase())) return Number.POSITIVE_INFINITY;
|
|
14090
14182
|
const parsed = Number(raw);
|
|
14091
14183
|
if (!Number.isInteger(parsed) || parsed <= 0) return DEFAULT_MAX_TOOL_CALLS_PER_TURN;
|
|
14092
14184
|
return parsed;
|
|
@@ -16554,4 +16646,4 @@ function formatDryRunSyncStatus(status) {
|
|
|
16554
16646
|
//#endregion
|
|
16555
16647
|
export { runTopchesterCli as t };
|
|
16556
16648
|
|
|
16557
|
-
//# sourceMappingURL=cli-
|
|
16649
|
+
//# sourceMappingURL=cli-DfgLjXLl.mjs.map
|