@agent-sh/harness-read 0.2.0 → 0.4.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/index.cjs CHANGED
@@ -4,6 +4,8 @@ var buffer = require('buffer');
4
4
  var crypto = require('crypto');
5
5
  var path3 = require('path');
6
6
  var harnessCore = require('@agent-sh/harness-core');
7
+ var readline = require('readline');
8
+ var stream = require('stream');
7
9
  var v = require('valibot');
8
10
 
9
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -27,6 +29,7 @@ function _interopNamespace(e) {
27
29
  }
28
30
 
29
31
  var path3__default = /*#__PURE__*/_interopDefault(path3);
32
+ var readline__default = /*#__PURE__*/_interopDefault(readline);
30
33
  var v__namespace = /*#__PURE__*/_interopNamespace(v);
31
34
 
32
35
  // src/read.ts
@@ -149,6 +152,31 @@ function formatAttachment(kind) {
149
152
  return `${kind} read successfully`;
150
153
  }
151
154
  async function streamLines(ops, path4, opts) {
155
+ const signalOpt = {};
156
+ if (opts.signal !== void 0) signalOpt.signal = opts.signal;
157
+ const iter = ops.openLineStream(path4, signalOpt);
158
+ return consumeLines(iter, opts);
159
+ }
160
+ async function streamLinesFromBytes(bytes, opts) {
161
+ const str = buffer.Buffer.from(bytes).toString("utf8");
162
+ const rl = readline__default.default.createInterface({
163
+ input: stream.Readable.from([str]),
164
+ crlfDelay: Infinity
165
+ });
166
+ const signal = opts.signal;
167
+ const iter = (async function* () {
168
+ try {
169
+ for await (const line of rl) {
170
+ if (signal?.aborted) break;
171
+ yield line;
172
+ }
173
+ } finally {
174
+ rl.close();
175
+ }
176
+ })();
177
+ return consumeLines(iter, opts);
178
+ }
179
+ async function consumeLines(iter, opts) {
152
180
  const maxBytes = opts.maxBytes ?? MAX_BYTES;
153
181
  const maxLineLen = opts.maxLineLength ?? MAX_LINE_LENGTH;
154
182
  const start = opts.offset - 1;
@@ -157,9 +185,6 @@ async function streamLines(ops, path4, opts) {
157
185
  let totalLines = 0;
158
186
  let more = false;
159
187
  let byteCap = false;
160
- const signalOpt = {};
161
- if (opts.signal !== void 0) signalOpt.signal = opts.signal;
162
- const iter = ops.openLineStream(path4, signalOpt);
163
188
  for await (const raw of iter) {
164
189
  totalLines += 1;
165
190
  if (totalLines <= start) continue;
@@ -327,11 +352,6 @@ async function fencePath(ops, session, resolvedPath) {
327
352
  );
328
353
  }
329
354
  if (!insideWorkspace && permissions.bypassWorkspaceGuard !== true && permissions.hook === void 0) {
330
- if (process.env.E2E_DEBUG_PERMISSIONS) {
331
- console.error(
332
- `[read fencePath] OUTSIDE_WORKSPACE reject: resolvedPath=${JSON.stringify(resolvedPath)} roots=${JSON.stringify(permissions.roots)}`
333
- );
334
- }
335
355
  return harnessCore.toolError(
336
356
  "OUTSIDE_WORKSPACE",
337
357
  `Path is outside all configured workspace roots: ${resolvedPath}`,
@@ -496,12 +516,14 @@ async function readText(ops, session, resolvedPath, stat, params) {
496
516
  return cached;
497
517
  }
498
518
  }
519
+ const bytes = await ops.readFile(resolvedPath);
520
+ const sha256 = crypto.createHash("sha256").update(bytes).digest("hex");
499
521
  const lineStreamOpts = { offset, limit };
500
522
  if (session.maxBytes !== void 0) lineStreamOpts.maxBytes = session.maxBytes;
501
523
  if (session.maxLineLength !== void 0)
502
524
  lineStreamOpts.maxLineLength = session.maxLineLength;
503
525
  if (session.signal !== void 0) lineStreamOpts.signal = session.signal;
504
- const result = await streamLines(ops, resolvedPath, lineStreamOpts);
526
+ const result = await streamLinesFromBytes(bytes, lineStreamOpts);
505
527
  if (result.totalLines > 0 && offset > result.totalLines) {
506
528
  return err(
507
529
  harnessCore.toolError(
@@ -511,8 +533,6 @@ async function readText(ops, session, resolvedPath, stat, params) {
511
533
  )
512
534
  );
513
535
  }
514
- const bytes = await ops.readFile(resolvedPath);
515
- const sha256 = crypto.createHash("sha256").update(bytes).digest("hex");
516
536
  const output = formatText({
517
537
  path: resolvedPath,
518
538
  offset,
@@ -585,6 +605,7 @@ exports.read = read;
585
605
  exports.readToolDefinition = readToolDefinition;
586
606
  exports.safeParseReadParams = safeParseReadParams;
587
607
  exports.streamLines = streamLines;
608
+ exports.streamLinesFromBytes = streamLinesFromBytes;
588
609
  exports.suggestSiblings = suggestSiblings;
589
610
  //# sourceMappingURL=index.cjs.map
590
611
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/binary.ts","../src/format.ts","../src/lines.ts","../src/schema.ts","../src/suggest.ts","../src/read.ts"],"names":["path","Buffer","v","toolError","defaultNodeOperations","withFileLock","matchesAnyPattern","isInsideAnyRoot","createHash"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_LIMIT = 2000;\nexport const MAX_LINE_LENGTH = 2000;\nexport const MAX_LINE_SUFFIX = `... (line truncated to ${MAX_LINE_LENGTH} chars)`;\nexport const MAX_BYTES = 50 * 1024;\nexport const MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB`;\nexport const MAX_FILE_SIZE = 5 * 1024 * 1024;\nexport const BINARY_SAMPLE_BYTES = 4096;\nexport const FUZZY_SUGGESTION_LIMIT = 3;\n\nexport const BINARY_EXTENSIONS: ReadonlySet<string> = new Set([\n \".zip\",\n \".tar\",\n \".gz\",\n \".exe\",\n \".dll\",\n \".so\",\n \".class\",\n \".jar\",\n \".war\",\n \".7z\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".odt\",\n \".ods\",\n \".odp\",\n \".bin\",\n \".dat\",\n \".obj\",\n \".o\",\n \".a\",\n \".lib\",\n \".wasm\",\n \".pyc\",\n \".pyo\",\n]);\n","import path from \"node:path\";\nimport { BINARY_EXTENSIONS } from \"./constants.js\";\n\nexport function isBinaryByExtension(filepath: string): boolean {\n return BINARY_EXTENSIONS.has(path.extname(filepath).toLowerCase());\n}\n\nexport function isBinaryByContent(sample: Uint8Array): boolean {\n if (sample.length === 0) return false;\n let nonPrintable = 0;\n for (let i = 0; i < sample.length; i++) {\n const b = sample[i] as number;\n if (b === 0) return true;\n if (b < 9 || (b > 13 && b < 32)) nonPrintable++;\n }\n return nonPrintable / sample.length > 0.3;\n}\n\nexport function isBinary(filepath: string, sample: Uint8Array): boolean {\n return isBinaryByExtension(filepath) || isBinaryByContent(sample);\n}\n\nexport function isImageMime(mime: string): boolean {\n if (!mime.startsWith(\"image/\")) return false;\n if (mime === \"image/svg+xml\") return false;\n return true;\n}\n\nexport function isPdfMime(mime: string): boolean {\n return mime === \"application/pdf\";\n}\n","import { MAX_BYTES_LABEL } from \"./constants.js\";\nimport type {\n AttachmentReadResult,\n DirReadResult,\n TextReadResult,\n} from \"./types.js\";\n\nexport function formatText(\n params: {\n path: string;\n offset: number;\n lines: readonly string[];\n totalLines: number;\n more: boolean;\n byteCap: boolean;\n },\n): string {\n const { path, offset, lines, totalLines, more, byteCap } = params;\n const header = `<path>${path}</path>\\n<type>file</type>\\n<content>`;\n\n if (lines.length === 0 && totalLines === 0) {\n return `${header}\\n(File exists but is empty)\\n</content>`;\n }\n\n const body = lines.map((line, i) => `${offset + i}: ${line}`).join(\"\\n\");\n const last = offset + lines.length - 1;\n const next = last + 1;\n\n let hint: string;\n if (byteCap) {\n const pct = totalLines > 0 ? Math.round((last / totalLines) * 100) : 0;\n const remaining = Math.max(totalLines - last, 0);\n hint = `(Output capped at ${MAX_BYTES_LABEL}. Showing lines ${offset}-${last} of ${totalLines} · ${pct}% covered · ${remaining} lines remaining. Next offset: ${next}.)`;\n } else if (more) {\n const pct = Math.round((last / totalLines) * 100);\n const remaining = Math.max(totalLines - last, 0);\n hint = `(Showing lines ${offset}-${last} of ${totalLines} · ${pct}% covered · ${remaining} lines remaining. Next offset: ${next}.)`;\n } else {\n hint = `(End of file · ${totalLines} lines total)`;\n }\n\n return `${header}\\n${body}\\n\\n${hint}\\n</content>`;\n}\n\nexport function formatDirectory(params: {\n path: string;\n entries: readonly string[];\n offset: number;\n totalEntries: number;\n more: boolean;\n}): string {\n const { path, entries, offset, totalEntries, more } = params;\n const header = `<path>${path}</path>\\n<type>directory</type>\\n<entries>`;\n const body = entries.join(\"\\n\");\n const last = offset + entries.length - 1;\n const next = last + 1;\n const remaining = Math.max(totalEntries - last, 0);\n const hint = more\n ? `(Showing ${entries.length} of ${totalEntries} entries · ${remaining} remaining. Next offset: ${next}.)`\n : `(${totalEntries} entries)`;\n return `${header}\\n${body}\\n\\n${hint}\\n</entries>`;\n}\n\nexport function formatAttachment(kind: \"Image\" | \"PDF\"): string {\n return `${kind} read successfully`;\n}\n\nexport function asTextResult(x: TextReadResult): TextReadResult {\n return x;\n}\nexport function asDirResult(x: DirReadResult): DirReadResult {\n return x;\n}\nexport function asAttachResult(x: AttachmentReadResult): AttachmentReadResult {\n return x;\n}\n","import { Buffer } from \"node:buffer\";\nimport type { ReadOperations } from \"@agent-sh/harness-core\";\nimport {\n MAX_BYTES,\n MAX_LINE_LENGTH,\n MAX_LINE_SUFFIX,\n} from \"./constants.js\";\n\nexport interface StreamLinesOptions {\n readonly offset: number;\n readonly limit: number;\n readonly maxBytes?: number;\n readonly maxLineLength?: number;\n readonly signal?: AbortSignal;\n}\n\nexport interface StreamLinesResult {\n readonly lines: readonly string[];\n readonly totalLines: number;\n readonly offset: number;\n readonly more: boolean;\n readonly byteCap: boolean;\n}\n\nexport async function streamLines(\n ops: ReadOperations,\n path: string,\n opts: StreamLinesOptions,\n): Promise<StreamLinesResult> {\n const maxBytes = opts.maxBytes ?? MAX_BYTES;\n const maxLineLen = opts.maxLineLength ?? MAX_LINE_LENGTH;\n const start = opts.offset - 1;\n\n const out: string[] = [];\n let bytes = 0;\n let totalLines = 0;\n let more = false;\n let byteCap = false;\n\n const signalOpt: { signal?: AbortSignal } = {};\n if (opts.signal !== undefined) signalOpt.signal = opts.signal;\n\n const iter = ops.openLineStream(path, signalOpt);\n\n for await (const raw of iter) {\n totalLines += 1;\n if (totalLines <= start) continue;\n\n if (out.length >= opts.limit) {\n more = true;\n continue;\n }\n\n const truncated =\n raw.length > maxLineLen ? raw.substring(0, maxLineLen) + MAX_LINE_SUFFIX : raw;\n\n const size = Buffer.byteLength(truncated, \"utf8\") + (out.length > 0 ? 1 : 0);\n if (bytes + size > maxBytes) {\n byteCap = true;\n more = true;\n break;\n }\n\n out.push(truncated);\n bytes += size;\n }\n\n return {\n lines: out,\n totalLines,\n offset: opts.offset,\n more,\n byteCap,\n };\n}\n","import * as v from \"valibot\";\nimport type { ToolDefinition } from \"@agent-sh/harness-core\";\nimport type { ReadParams } from \"./types.js\";\n\nexport const ReadParamsSchema = v.object({\n path: v.pipe(v.string(), v.minLength(1, \"path must not be empty\")),\n offset: v.optional(\n v.pipe(v.number(), v.integer(), v.minValue(1, \"offset must be >= 1\")),\n ),\n limit: v.optional(\n v.pipe(v.number(), v.integer(), v.minValue(1, \"limit must be >= 1\")),\n ),\n});\n\nexport type ParsedReadParams = v.InferOutput<typeof ReadParamsSchema>;\n\nexport function parseReadParams(input: unknown): ParsedReadParams {\n return v.parse(ReadParamsSchema, input);\n}\n\nexport function safeParseReadParams(input: unknown):\n | { ok: true; value: ReadParams }\n | { ok: false; issues: v.BaseIssue<unknown>[] } {\n const result = v.safeParse(ReadParamsSchema, input);\n if (result.success) return { ok: true, value: result.output };\n return { ok: false, issues: result.issues };\n}\n\nexport const READ_TOOL_NAME = \"read\";\n\nexport const READ_TOOL_DESCRIPTION = `Read a file or directory from the local filesystem.\n\nUsage:\n- The path parameter should be an absolute path. If relative, it resolves against the session working directory.\n- By default, returns up to 2000 lines from the start of the file.\n- The offset parameter is the 1-indexed line number to start from.\n- For later sections, call this tool again with a larger offset.\n- Use the grep tool for content search in large files; glob to locate files by pattern.\n- Contents are returned with each line prefixed by its line number as \"<line>: <content>\".\n- Any line longer than 2000 characters is truncated.\n- Call this tool in parallel when reading multiple files.\n- Avoid tiny repeated slices (under 30 lines). Read a larger window instead.\n- Images and PDFs are returned as file attachments.\n- Binary files are refused; use specialized tools.`;\n\nexport const readToolDefinition: ToolDefinition = {\n name: READ_TOOL_NAME,\n description: READ_TOOL_DESCRIPTION,\n inputSchema: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description:\n \"Absolute path (preferred) or path relative to the session cwd.\",\n },\n offset: {\n type: \"integer\",\n minimum: 1,\n description: \"1-indexed line number to start reading from.\",\n },\n limit: {\n type: \"integer\",\n minimum: 1,\n description: \"Maximum number of lines to read. Defaults to 2000.\",\n },\n },\n required: [\"path\"],\n additionalProperties: false,\n },\n};\n","import path from \"node:path\";\nimport type { ReadOperations } from \"@agent-sh/harness-core\";\nimport { FUZZY_SUGGESTION_LIMIT } from \"./constants.js\";\n\nexport async function suggestSiblings(\n ops: ReadOperations,\n missingPath: string,\n): Promise<readonly string[]> {\n const dir = path.dirname(missingPath);\n const base = path.basename(missingPath).toLowerCase();\n let entries: readonly string[];\n try {\n entries = await ops.readDirectory(dir);\n } catch {\n return [];\n }\n const scored: { p: string; score: number }[] = [];\n for (const entry of entries) {\n const lower = entry.toLowerCase();\n const score = similarity(base, lower);\n if (score > 0) scored.push({ p: path.join(dir, entry), score });\n }\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, FUZZY_SUGGESTION_LIMIT).map((s) => s.p);\n}\n\nfunction similarity(a: string, b: string): number {\n if (a === b) return 1000;\n if (a.length === 0 || b.length === 0) return 0;\n if (a.includes(b) || b.includes(a)) return 500;\n const prefix = commonPrefix(a, b);\n if (prefix >= 3) return 200 + prefix;\n if (prefix >= 2 && Math.abs(a.length - b.length) <= 2) return 100 + prefix;\n const aExt = extOf(a);\n const bExt = extOf(b);\n if (aExt && aExt === bExt) return 10;\n return 0;\n}\n\nfunction commonPrefix(a: string, b: string): number {\n const n = Math.min(a.length, b.length);\n let i = 0;\n while (i < n && a[i] === b[i]) i++;\n return i;\n}\n\nfunction extOf(name: string): string {\n const dot = name.lastIndexOf(\".\");\n return dot > 0 ? name.slice(dot) : \"\";\n}\n","import { Buffer } from \"node:buffer\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n defaultNodeOperations,\n isInsideAnyRoot,\n matchesAnyPattern,\n toolError,\n withFileLock,\n type ReadOperations,\n type ToolError,\n} from \"@agent-sh/harness-core\";\nimport { isBinary, isImageMime, isPdfMime } from \"./binary.js\";\nimport {\n BINARY_SAMPLE_BYTES,\n DEFAULT_LIMIT,\n MAX_FILE_SIZE,\n} from \"./constants.js\";\nimport {\n formatAttachment,\n formatDirectory,\n formatText,\n} from \"./format.js\";\nimport { streamLines } from \"./lines.js\";\nimport { safeParseReadParams } from \"./schema.js\";\nimport { suggestSiblings } from \"./suggest.js\";\nimport type {\n AttachmentReadResult,\n DirReadResult,\n ErrorReadResult,\n ReadParams,\n ReadResult,\n ReadSessionConfig,\n TextReadResult,\n} from \"./types.js\";\n\nfunction err(error: ToolError): ErrorReadResult {\n return { kind: \"error\", error };\n}\n\nexport async function read(\n input: unknown,\n session: ReadSessionConfig,\n): Promise<ReadResult> {\n const parsed = safeParseReadParams(input);\n if (!parsed.ok) {\n const messages = parsed.issues.map((i) => i.message).join(\"; \");\n return err(toolError(\"INVALID_PARAM\", messages, { cause: parsed.issues }));\n }\n const params = parsed.value;\n\n const ops = session.ops ?? defaultNodeOperations();\n\n const resolvedPath = await resolvePath(ops, session.cwd, params.path);\n const fence = await fencePath(ops, session, resolvedPath);\n if (fence !== undefined) return err(fence);\n\n return withFileLock(resolvedPath, () =>\n executeRead(ops, session, resolvedPath, params),\n );\n}\n\nasync function resolvePath(\n ops: ReadOperations,\n cwd: string,\n input: string,\n): Promise<string> {\n const absolute = path.isAbsolute(input) ? input : path.resolve(cwd, input);\n try {\n return await ops.realpath(absolute);\n } catch {\n return absolute;\n }\n}\n\nasync function fencePath(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n): Promise<ToolError | undefined> {\n const { permissions } = session;\n\n const isSensitive = matchesAnyPattern(\n resolvedPath,\n permissions.sensitivePatterns,\n );\n const insideWorkspace = isInsideAnyRoot(resolvedPath, permissions.roots);\n const needsAsk =\n isSensitive ||\n (!insideWorkspace && permissions.bypassWorkspaceGuard !== true);\n\n if (isSensitive && permissions.hook === undefined) {\n return toolError(\n \"SENSITIVE\",\n `Refusing to read sensitive path: ${resolvedPath}`,\n { meta: { path: resolvedPath } },\n );\n }\n\n if (\n !insideWorkspace &&\n permissions.bypassWorkspaceGuard !== true &&\n permissions.hook === undefined\n ) {\n if (process.env.E2E_DEBUG_PERMISSIONS) {\n // eslint-disable-next-line no-console\n console.error(\n `[read fencePath] OUTSIDE_WORKSPACE reject: resolvedPath=${JSON.stringify(resolvedPath)} roots=${JSON.stringify(permissions.roots)}`,\n );\n }\n return toolError(\n \"OUTSIDE_WORKSPACE\",\n `Path is outside all configured workspace roots: ${resolvedPath}`,\n { meta: { path: resolvedPath, roots: permissions.roots } },\n );\n }\n\n if (permissions.hook !== undefined) {\n const reason = isSensitive\n ? \"sensitive\"\n : !insideWorkspace\n ? \"outside_workspace\"\n : \"in_workspace\";\n const alwaysPatterns = needsAsk\n ? [path.dirname(resolvedPath) + \"/*\"]\n : [\"*\"];\n const decision = await permissions.hook({\n tool: \"read\",\n path: resolvedPath,\n action: \"read\",\n always_patterns: alwaysPatterns,\n metadata: { reason },\n });\n if (decision === \"deny\") {\n return toolError(\n \"PERMISSION_DENIED\",\n `Read denied by user: ${resolvedPath}`,\n { meta: { path: resolvedPath } },\n );\n }\n }\n\n return undefined;\n}\n\nasync function executeRead(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n params: ReadParams,\n): Promise<ReadResult> {\n let stat;\n try {\n stat = await ops.stat(resolvedPath);\n } catch (e) {\n return err(\n toolError(\"IO_ERROR\", `stat failed: ${(e as Error).message}`, {\n cause: e,\n }),\n );\n }\n\n if (!stat) {\n const suggestions = await suggestSiblings(ops, resolvedPath);\n const msg =\n suggestions.length > 0\n ? `File not found: ${resolvedPath}\\n\\nDid you mean one of these?\\n${suggestions.join(\"\\n\")}`\n : `File not found: ${resolvedPath}`;\n return err(\n toolError(\"NOT_FOUND\", msg, { meta: { path: resolvedPath, suggestions } }),\n );\n }\n\n if (stat.type === \"directory\") {\n return readDirectory(ops, resolvedPath, params);\n }\n\n const maxSize = session.maxFileSize ?? MAX_FILE_SIZE;\n if (stat.size > maxSize) {\n return err(\n toolError(\n \"TOO_LARGE\",\n `File size ${stat.size} exceeds max ${maxSize}. Use a narrower offset/limit or grep first.`,\n { meta: { path: resolvedPath, size: stat.size, maxSize } },\n ),\n );\n }\n\n const half = session.modelContextTokens\n ? Math.floor(session.modelContextTokens / 2)\n : undefined;\n const tokensPerByte = session.tokensPerByte ?? 0.3;\n if (half !== undefined && stat.size * tokensPerByte > half) {\n return err(\n toolError(\n \"TOO_LARGE\",\n `File would consume more than half of the model context (~${Math.floor(stat.size * tokensPerByte)} tokens > ${half}). Use offset/limit or grep first.`,\n { meta: { path: resolvedPath, size: stat.size, half } },\n ),\n );\n }\n\n const mime = ops.mimeType(resolvedPath);\n if (isImageMime(mime) || isPdfMime(mime)) {\n return readAttachment(ops, resolvedPath, mime, stat.size);\n }\n\n const sample = await readSample(ops, resolvedPath, stat.size);\n if (isBinary(resolvedPath, sample)) {\n return err(\n toolError(\"BINARY\", `Cannot read binary file: ${resolvedPath}`, {\n meta: { path: resolvedPath },\n }),\n );\n }\n\n return readText(ops, session, resolvedPath, stat, params);\n}\n\nasync function readSample(\n ops: ReadOperations,\n p: string,\n size: number,\n): Promise<Uint8Array> {\n if (size === 0) return new Uint8Array();\n const bytes = await ops.readFile(p);\n return bytes.length > BINARY_SAMPLE_BYTES\n ? bytes.subarray(0, BINARY_SAMPLE_BYTES)\n : bytes;\n}\n\nasync function readDirectory(\n ops: ReadOperations,\n resolvedPath: string,\n params: ReadParams,\n): Promise<DirReadResult> {\n const entries = await ops.readDirectoryEntries(resolvedPath);\n const named = await Promise.all(\n entries.map(async (e) => {\n if (e.type === \"directory\") return e.name + \"/\";\n if (e.type !== \"symlink\") return e.name;\n const target = await ops\n .stat(path.join(resolvedPath, e.name))\n .catch(() => undefined);\n return target?.type === \"directory\" ? e.name + \"/\" : e.name;\n }),\n );\n named.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: \"base\" }));\n\n const offset = params.offset ?? 1;\n const limit = params.limit ?? DEFAULT_LIMIT;\n const start = offset - 1;\n const sliced = named.slice(start, start + limit);\n const more = start + sliced.length < named.length;\n\n const output = formatDirectory({\n path: resolvedPath,\n entries: sliced,\n offset,\n totalEntries: named.length,\n more,\n });\n\n return {\n kind: \"directory\",\n output,\n meta: {\n path: resolvedPath,\n totalEntries: named.length,\n returnedEntries: sliced.length,\n offset,\n limit,\n more,\n },\n };\n}\n\nasync function readAttachment(\n ops: ReadOperations,\n resolvedPath: string,\n mime: string,\n size: number,\n): Promise<AttachmentReadResult> {\n const bytes = await ops.readFile(resolvedPath);\n const kind: \"Image\" | \"PDF\" = mime === \"application/pdf\" ? \"PDF\" : \"Image\";\n const dataUrl = `data:${mime};base64,${Buffer.from(bytes).toString(\"base64\")}`;\n return {\n kind: \"attachment\",\n output: formatAttachment(kind),\n attachments: [{ mime, dataUrl }],\n meta: { path: resolvedPath, mime, size_bytes: size },\n };\n}\n\nasync function readText(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n stat: { size: number; mtime_ms: number },\n params: ReadParams,\n): Promise<ReadResult> {\n const offset = params.offset ?? 1;\n const limit = params.limit ?? session.defaultLimit ?? DEFAULT_LIMIT;\n\n if (session.cache) {\n const cached = session.cache.get({\n path: resolvedPath,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n offset,\n limit,\n });\n if (cached) {\n if (session.ledger) {\n session.ledger.record({\n path: resolvedPath,\n sha256: cached.meta.sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n lines_returned: cached.meta.returnedLines,\n offset,\n limit,\n timestamp_ms: Date.now(),\n });\n }\n return cached;\n }\n }\n\n const lineStreamOpts: {\n offset: number;\n limit: number;\n maxBytes?: number;\n maxLineLength?: number;\n signal?: AbortSignal;\n } = { offset, limit };\n if (session.maxBytes !== undefined) lineStreamOpts.maxBytes = session.maxBytes;\n if (session.maxLineLength !== undefined)\n lineStreamOpts.maxLineLength = session.maxLineLength;\n if (session.signal !== undefined) lineStreamOpts.signal = session.signal;\n\n const result = await streamLines(ops, resolvedPath, lineStreamOpts);\n\n if (result.totalLines > 0 && offset > result.totalLines) {\n return err(\n toolError(\n \"INVALID_PARAM\",\n `Offset ${offset} is out of range for this file (${result.totalLines} lines)`,\n { meta: { path: resolvedPath, totalLines: result.totalLines } },\n ),\n );\n }\n\n const bytes = await ops.readFile(resolvedPath);\n const sha256 = createHash(\"sha256\").update(bytes).digest(\"hex\");\n\n const output = formatText({\n path: resolvedPath,\n offset,\n lines: result.lines,\n totalLines: result.totalLines,\n more: result.more,\n byteCap: result.byteCap,\n });\n\n const textResult: TextReadResult = {\n kind: \"text\",\n output,\n meta: {\n path: resolvedPath,\n totalLines: result.totalLines,\n returnedLines: result.lines.length,\n offset,\n limit,\n byteCap: result.byteCap,\n more: result.more,\n sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n },\n };\n\n if (session.cache) {\n session.cache.set(\n {\n path: resolvedPath,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n offset,\n limit,\n },\n textResult,\n );\n }\n\n if (session.ledger) {\n session.ledger.record({\n path: resolvedPath,\n sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n lines_returned: result.lines.length,\n offset,\n limit,\n timestamp_ms: Date.now(),\n });\n }\n\n return textResult;\n}\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/binary.ts","../src/format.ts","../src/lines.ts","../src/schema.ts","../src/suggest.ts","../src/read.ts"],"names":["path","Buffer","readline","Readable","v","toolError","defaultNodeOperations","withFileLock","matchesAnyPattern","isInsideAnyRoot","createHash"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_LIMIT = 2000;\nexport const MAX_LINE_LENGTH = 2000;\nexport const MAX_LINE_SUFFIX = `... (line truncated to ${MAX_LINE_LENGTH} chars)`;\nexport const MAX_BYTES = 50 * 1024;\nexport const MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB`;\nexport const MAX_FILE_SIZE = 5 * 1024 * 1024;\nexport const BINARY_SAMPLE_BYTES = 4096;\nexport const FUZZY_SUGGESTION_LIMIT = 3;\n\nexport const BINARY_EXTENSIONS: ReadonlySet<string> = new Set([\n \".zip\",\n \".tar\",\n \".gz\",\n \".exe\",\n \".dll\",\n \".so\",\n \".class\",\n \".jar\",\n \".war\",\n \".7z\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".odt\",\n \".ods\",\n \".odp\",\n \".bin\",\n \".dat\",\n \".obj\",\n \".o\",\n \".a\",\n \".lib\",\n \".wasm\",\n \".pyc\",\n \".pyo\",\n]);\n","import path from \"node:path\";\nimport { BINARY_EXTENSIONS } from \"./constants.js\";\n\nexport function isBinaryByExtension(filepath: string): boolean {\n return BINARY_EXTENSIONS.has(path.extname(filepath).toLowerCase());\n}\n\nexport function isBinaryByContent(sample: Uint8Array): boolean {\n if (sample.length === 0) return false;\n let nonPrintable = 0;\n for (let i = 0; i < sample.length; i++) {\n const b = sample[i] as number;\n if (b === 0) return true;\n if (b < 9 || (b > 13 && b < 32)) nonPrintable++;\n }\n return nonPrintable / sample.length > 0.3;\n}\n\nexport function isBinary(filepath: string, sample: Uint8Array): boolean {\n return isBinaryByExtension(filepath) || isBinaryByContent(sample);\n}\n\nexport function isImageMime(mime: string): boolean {\n if (!mime.startsWith(\"image/\")) return false;\n if (mime === \"image/svg+xml\") return false;\n return true;\n}\n\nexport function isPdfMime(mime: string): boolean {\n return mime === \"application/pdf\";\n}\n","import { MAX_BYTES_LABEL } from \"./constants.js\";\nimport type {\n AttachmentReadResult,\n DirReadResult,\n TextReadResult,\n} from \"./types.js\";\n\nexport function formatText(\n params: {\n path: string;\n offset: number;\n lines: readonly string[];\n totalLines: number;\n more: boolean;\n byteCap: boolean;\n },\n): string {\n const { path, offset, lines, totalLines, more, byteCap } = params;\n const header = `<path>${path}</path>\\n<type>file</type>\\n<content>`;\n\n if (lines.length === 0 && totalLines === 0) {\n return `${header}\\n(File exists but is empty)\\n</content>`;\n }\n\n const body = lines.map((line, i) => `${offset + i}: ${line}`).join(\"\\n\");\n const last = offset + lines.length - 1;\n const next = last + 1;\n\n let hint: string;\n if (byteCap) {\n const pct = totalLines > 0 ? Math.round((last / totalLines) * 100) : 0;\n const remaining = Math.max(totalLines - last, 0);\n hint = `(Output capped at ${MAX_BYTES_LABEL}. Showing lines ${offset}-${last} of ${totalLines} · ${pct}% covered · ${remaining} lines remaining. Next offset: ${next}.)`;\n } else if (more) {\n const pct = Math.round((last / totalLines) * 100);\n const remaining = Math.max(totalLines - last, 0);\n hint = `(Showing lines ${offset}-${last} of ${totalLines} · ${pct}% covered · ${remaining} lines remaining. Next offset: ${next}.)`;\n } else {\n hint = `(End of file · ${totalLines} lines total)`;\n }\n\n return `${header}\\n${body}\\n\\n${hint}\\n</content>`;\n}\n\nexport function formatDirectory(params: {\n path: string;\n entries: readonly string[];\n offset: number;\n totalEntries: number;\n more: boolean;\n}): string {\n const { path, entries, offset, totalEntries, more } = params;\n const header = `<path>${path}</path>\\n<type>directory</type>\\n<entries>`;\n const body = entries.join(\"\\n\");\n const last = offset + entries.length - 1;\n const next = last + 1;\n const remaining = Math.max(totalEntries - last, 0);\n const hint = more\n ? `(Showing ${entries.length} of ${totalEntries} entries · ${remaining} remaining. Next offset: ${next}.)`\n : `(${totalEntries} entries)`;\n return `${header}\\n${body}\\n\\n${hint}\\n</entries>`;\n}\n\nexport function formatAttachment(kind: \"Image\" | \"PDF\"): string {\n return `${kind} read successfully`;\n}\n\nexport function asTextResult(x: TextReadResult): TextReadResult {\n return x;\n}\nexport function asDirResult(x: DirReadResult): DirReadResult {\n return x;\n}\nexport function asAttachResult(x: AttachmentReadResult): AttachmentReadResult {\n return x;\n}\n","import { Buffer } from \"node:buffer\";\nimport readline from \"node:readline\";\nimport { Readable } from \"node:stream\";\nimport type { ReadOperations } from \"@agent-sh/harness-core\";\nimport {\n MAX_BYTES,\n MAX_LINE_LENGTH,\n MAX_LINE_SUFFIX,\n} from \"./constants.js\";\n\nexport interface StreamLinesOptions {\n readonly offset: number;\n readonly limit: number;\n readonly maxBytes?: number;\n readonly maxLineLength?: number;\n readonly signal?: AbortSignal;\n}\n\nexport interface StreamLinesResult {\n readonly lines: readonly string[];\n readonly totalLines: number;\n readonly offset: number;\n readonly more: boolean;\n readonly byteCap: boolean;\n}\n\nexport async function streamLines(\n ops: ReadOperations,\n path: string,\n opts: StreamLinesOptions,\n): Promise<StreamLinesResult> {\n const signalOpt: { signal?: AbortSignal } = {};\n if (opts.signal !== undefined) signalOpt.signal = opts.signal;\n\n const iter = ops.openLineStream(path, signalOpt);\n return consumeLines(iter, opts);\n}\n\n/**\n * Same line-oriented contract as {@link streamLines}, but sourced from bytes\n * already held in memory instead of a fresh filesystem read. Lets a caller\n * that has read the file once (e.g. for hashing) reuse those bytes for line\n * content without a second OS read. Uses Node's own readline over an in-memory\n * Readable so CRLF stripping, trailing-newline, and empty-file semantics match\n * {@link ReadOperations.openLineStream} exactly.\n */\nexport async function streamLinesFromBytes(\n bytes: Uint8Array,\n opts: StreamLinesOptions,\n): Promise<StreamLinesResult> {\n const str = Buffer.from(bytes).toString(\"utf8\");\n const rl = readline.createInterface({\n input: Readable.from([str]),\n crlfDelay: Infinity,\n });\n const signal = opts.signal;\n const iter: AsyncIterableIterator<string> = (async function* () {\n try {\n for await (const line of rl) {\n if (signal?.aborted) break;\n yield line;\n }\n } finally {\n rl.close();\n }\n })();\n return consumeLines(iter, opts);\n}\n\nasync function consumeLines(\n iter: AsyncIterable<string>,\n opts: StreamLinesOptions,\n): Promise<StreamLinesResult> {\n const maxBytes = opts.maxBytes ?? MAX_BYTES;\n const maxLineLen = opts.maxLineLength ?? MAX_LINE_LENGTH;\n const start = opts.offset - 1;\n\n const out: string[] = [];\n let bytes = 0;\n let totalLines = 0;\n let more = false;\n let byteCap = false;\n\n for await (const raw of iter) {\n totalLines += 1;\n if (totalLines <= start) continue;\n\n if (out.length >= opts.limit) {\n more = true;\n continue;\n }\n\n const truncated =\n raw.length > maxLineLen ? raw.substring(0, maxLineLen) + MAX_LINE_SUFFIX : raw;\n\n const size = Buffer.byteLength(truncated, \"utf8\") + (out.length > 0 ? 1 : 0);\n if (bytes + size > maxBytes) {\n byteCap = true;\n more = true;\n break;\n }\n\n out.push(truncated);\n bytes += size;\n }\n\n return {\n lines: out,\n totalLines,\n offset: opts.offset,\n more,\n byteCap,\n };\n}\n","import * as v from \"valibot\";\nimport type { ToolDefinition } from \"@agent-sh/harness-core\";\nimport type { ReadParams } from \"./types.js\";\n\nexport const ReadParamsSchema = v.object({\n path: v.pipe(v.string(), v.minLength(1, \"path must not be empty\")),\n offset: v.optional(\n v.pipe(v.number(), v.integer(), v.minValue(1, \"offset must be >= 1\")),\n ),\n limit: v.optional(\n v.pipe(v.number(), v.integer(), v.minValue(1, \"limit must be >= 1\")),\n ),\n});\n\nexport type ParsedReadParams = v.InferOutput<typeof ReadParamsSchema>;\n\nexport function parseReadParams(input: unknown): ParsedReadParams {\n return v.parse(ReadParamsSchema, input);\n}\n\nexport function safeParseReadParams(input: unknown):\n | { ok: true; value: ReadParams }\n | { ok: false; issues: v.BaseIssue<unknown>[] } {\n const result = v.safeParse(ReadParamsSchema, input);\n if (result.success) return { ok: true, value: result.output };\n return { ok: false, issues: result.issues };\n}\n\nexport const READ_TOOL_NAME = \"read\";\n\nexport const READ_TOOL_DESCRIPTION = `Read a file or directory from the local filesystem.\n\nUsage:\n- The path parameter should be an absolute path. If relative, it resolves against the session working directory.\n- By default, returns up to 2000 lines from the start of the file.\n- The offset parameter is the 1-indexed line number to start from.\n- For later sections, call this tool again with a larger offset.\n- Use the grep tool for content search in large files; glob to locate files by pattern.\n- Contents are returned with each line prefixed by its line number as \"<line>: <content>\".\n- Any line longer than 2000 characters is truncated.\n- Call this tool in parallel when reading multiple files.\n- Avoid tiny repeated slices (under 30 lines). Read a larger window instead.\n- Images and PDFs are returned as file attachments.\n- Binary files are refused; use specialized tools.`;\n\nexport const readToolDefinition: ToolDefinition = {\n name: READ_TOOL_NAME,\n description: READ_TOOL_DESCRIPTION,\n inputSchema: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description:\n \"Absolute path (preferred) or path relative to the session cwd.\",\n },\n offset: {\n type: \"integer\",\n minimum: 1,\n description: \"1-indexed line number to start reading from.\",\n },\n limit: {\n type: \"integer\",\n minimum: 1,\n description: \"Maximum number of lines to read. Defaults to 2000.\",\n },\n },\n required: [\"path\"],\n additionalProperties: false,\n },\n};\n","import path from \"node:path\";\nimport type { ReadOperations } from \"@agent-sh/harness-core\";\nimport { FUZZY_SUGGESTION_LIMIT } from \"./constants.js\";\n\nexport async function suggestSiblings(\n ops: ReadOperations,\n missingPath: string,\n): Promise<readonly string[]> {\n const dir = path.dirname(missingPath);\n const base = path.basename(missingPath).toLowerCase();\n let entries: readonly string[];\n try {\n entries = await ops.readDirectory(dir);\n } catch {\n return [];\n }\n const scored: { p: string; score: number }[] = [];\n for (const entry of entries) {\n const lower = entry.toLowerCase();\n const score = similarity(base, lower);\n if (score > 0) scored.push({ p: path.join(dir, entry), score });\n }\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, FUZZY_SUGGESTION_LIMIT).map((s) => s.p);\n}\n\nfunction similarity(a: string, b: string): number {\n if (a === b) return 1000;\n if (a.length === 0 || b.length === 0) return 0;\n if (a.includes(b) || b.includes(a)) return 500;\n const prefix = commonPrefix(a, b);\n if (prefix >= 3) return 200 + prefix;\n if (prefix >= 2 && Math.abs(a.length - b.length) <= 2) return 100 + prefix;\n const aExt = extOf(a);\n const bExt = extOf(b);\n if (aExt && aExt === bExt) return 10;\n return 0;\n}\n\nfunction commonPrefix(a: string, b: string): number {\n const n = Math.min(a.length, b.length);\n let i = 0;\n while (i < n && a[i] === b[i]) i++;\n return i;\n}\n\nfunction extOf(name: string): string {\n const dot = name.lastIndexOf(\".\");\n return dot > 0 ? name.slice(dot) : \"\";\n}\n","import { Buffer } from \"node:buffer\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n defaultNodeOperations,\n isInsideAnyRoot,\n matchesAnyPattern,\n toolError,\n withFileLock,\n type ReadOperations,\n type ToolError,\n} from \"@agent-sh/harness-core\";\nimport { isBinary, isImageMime, isPdfMime } from \"./binary.js\";\nimport {\n BINARY_SAMPLE_BYTES,\n DEFAULT_LIMIT,\n MAX_FILE_SIZE,\n} from \"./constants.js\";\nimport {\n formatAttachment,\n formatDirectory,\n formatText,\n} from \"./format.js\";\nimport { streamLinesFromBytes } from \"./lines.js\";\nimport { safeParseReadParams } from \"./schema.js\";\nimport { suggestSiblings } from \"./suggest.js\";\nimport type {\n AttachmentReadResult,\n DirReadResult,\n ErrorReadResult,\n ReadParams,\n ReadResult,\n ReadSessionConfig,\n TextReadResult,\n} from \"./types.js\";\n\nfunction err(error: ToolError): ErrorReadResult {\n return { kind: \"error\", error };\n}\n\nexport async function read(\n input: unknown,\n session: ReadSessionConfig,\n): Promise<ReadResult> {\n const parsed = safeParseReadParams(input);\n if (!parsed.ok) {\n const messages = parsed.issues.map((i) => i.message).join(\"; \");\n return err(toolError(\"INVALID_PARAM\", messages, { cause: parsed.issues }));\n }\n const params = parsed.value;\n\n const ops = session.ops ?? defaultNodeOperations();\n\n const resolvedPath = await resolvePath(ops, session.cwd, params.path);\n const fence = await fencePath(ops, session, resolvedPath);\n if (fence !== undefined) return err(fence);\n\n return withFileLock(resolvedPath, () =>\n executeRead(ops, session, resolvedPath, params),\n );\n}\n\nasync function resolvePath(\n ops: ReadOperations,\n cwd: string,\n input: string,\n): Promise<string> {\n const absolute = path.isAbsolute(input) ? input : path.resolve(cwd, input);\n try {\n return await ops.realpath(absolute);\n } catch {\n return absolute;\n }\n}\n\nasync function fencePath(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n): Promise<ToolError | undefined> {\n const { permissions } = session;\n\n const isSensitive = matchesAnyPattern(\n resolvedPath,\n permissions.sensitivePatterns,\n );\n const insideWorkspace = isInsideAnyRoot(resolvedPath, permissions.roots);\n const needsAsk =\n isSensitive ||\n (!insideWorkspace && permissions.bypassWorkspaceGuard !== true);\n\n if (isSensitive && permissions.hook === undefined) {\n return toolError(\n \"SENSITIVE\",\n `Refusing to read sensitive path: ${resolvedPath}`,\n { meta: { path: resolvedPath } },\n );\n }\n\n if (\n !insideWorkspace &&\n permissions.bypassWorkspaceGuard !== true &&\n permissions.hook === undefined\n ) {\n return toolError(\n \"OUTSIDE_WORKSPACE\",\n `Path is outside all configured workspace roots: ${resolvedPath}`,\n { meta: { path: resolvedPath, roots: permissions.roots } },\n );\n }\n\n if (permissions.hook !== undefined) {\n const reason = isSensitive\n ? \"sensitive\"\n : !insideWorkspace\n ? \"outside_workspace\"\n : \"in_workspace\";\n const alwaysPatterns = needsAsk\n ? [path.dirname(resolvedPath) + \"/*\"]\n : [\"*\"];\n const decision = await permissions.hook({\n tool: \"read\",\n path: resolvedPath,\n action: \"read\",\n always_patterns: alwaysPatterns,\n metadata: { reason },\n });\n if (decision === \"deny\") {\n return toolError(\n \"PERMISSION_DENIED\",\n `Read denied by user: ${resolvedPath}`,\n { meta: { path: resolvedPath } },\n );\n }\n }\n\n return undefined;\n}\n\nasync function executeRead(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n params: ReadParams,\n): Promise<ReadResult> {\n let stat;\n try {\n stat = await ops.stat(resolvedPath);\n } catch (e) {\n return err(\n toolError(\"IO_ERROR\", `stat failed: ${(e as Error).message}`, {\n cause: e,\n }),\n );\n }\n\n if (!stat) {\n const suggestions = await suggestSiblings(ops, resolvedPath);\n const msg =\n suggestions.length > 0\n ? `File not found: ${resolvedPath}\\n\\nDid you mean one of these?\\n${suggestions.join(\"\\n\")}`\n : `File not found: ${resolvedPath}`;\n return err(\n toolError(\"NOT_FOUND\", msg, { meta: { path: resolvedPath, suggestions } }),\n );\n }\n\n if (stat.type === \"directory\") {\n return readDirectory(ops, resolvedPath, params);\n }\n\n const maxSize = session.maxFileSize ?? MAX_FILE_SIZE;\n if (stat.size > maxSize) {\n return err(\n toolError(\n \"TOO_LARGE\",\n `File size ${stat.size} exceeds max ${maxSize}. Use a narrower offset/limit or grep first.`,\n { meta: { path: resolvedPath, size: stat.size, maxSize } },\n ),\n );\n }\n\n const half = session.modelContextTokens\n ? Math.floor(session.modelContextTokens / 2)\n : undefined;\n const tokensPerByte = session.tokensPerByte ?? 0.3;\n if (half !== undefined && stat.size * tokensPerByte > half) {\n return err(\n toolError(\n \"TOO_LARGE\",\n `File would consume more than half of the model context (~${Math.floor(stat.size * tokensPerByte)} tokens > ${half}). Use offset/limit or grep first.`,\n { meta: { path: resolvedPath, size: stat.size, half } },\n ),\n );\n }\n\n const mime = ops.mimeType(resolvedPath);\n if (isImageMime(mime) || isPdfMime(mime)) {\n return readAttachment(ops, resolvedPath, mime, stat.size);\n }\n\n const sample = await readSample(ops, resolvedPath, stat.size);\n if (isBinary(resolvedPath, sample)) {\n return err(\n toolError(\"BINARY\", `Cannot read binary file: ${resolvedPath}`, {\n meta: { path: resolvedPath },\n }),\n );\n }\n\n return readText(ops, session, resolvedPath, stat, params);\n}\n\nasync function readSample(\n ops: ReadOperations,\n p: string,\n size: number,\n): Promise<Uint8Array> {\n if (size === 0) return new Uint8Array();\n const bytes = await ops.readFile(p);\n return bytes.length > BINARY_SAMPLE_BYTES\n ? bytes.subarray(0, BINARY_SAMPLE_BYTES)\n : bytes;\n}\n\nasync function readDirectory(\n ops: ReadOperations,\n resolvedPath: string,\n params: ReadParams,\n): Promise<DirReadResult> {\n const entries = await ops.readDirectoryEntries(resolvedPath);\n const named = await Promise.all(\n entries.map(async (e) => {\n if (e.type === \"directory\") return e.name + \"/\";\n if (e.type !== \"symlink\") return e.name;\n const target = await ops\n .stat(path.join(resolvedPath, e.name))\n .catch(() => undefined);\n return target?.type === \"directory\" ? e.name + \"/\" : e.name;\n }),\n );\n named.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: \"base\" }));\n\n const offset = params.offset ?? 1;\n const limit = params.limit ?? DEFAULT_LIMIT;\n const start = offset - 1;\n const sliced = named.slice(start, start + limit);\n const more = start + sliced.length < named.length;\n\n const output = formatDirectory({\n path: resolvedPath,\n entries: sliced,\n offset,\n totalEntries: named.length,\n more,\n });\n\n return {\n kind: \"directory\",\n output,\n meta: {\n path: resolvedPath,\n totalEntries: named.length,\n returnedEntries: sliced.length,\n offset,\n limit,\n more,\n },\n };\n}\n\nasync function readAttachment(\n ops: ReadOperations,\n resolvedPath: string,\n mime: string,\n size: number,\n): Promise<AttachmentReadResult> {\n const bytes = await ops.readFile(resolvedPath);\n const kind: \"Image\" | \"PDF\" = mime === \"application/pdf\" ? \"PDF\" : \"Image\";\n const dataUrl = `data:${mime};base64,${Buffer.from(bytes).toString(\"base64\")}`;\n return {\n kind: \"attachment\",\n output: formatAttachment(kind),\n attachments: [{ mime, dataUrl }],\n meta: { path: resolvedPath, mime, size_bytes: size },\n };\n}\n\nasync function readText(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n stat: { size: number; mtime_ms: number },\n params: ReadParams,\n): Promise<ReadResult> {\n const offset = params.offset ?? 1;\n const limit = params.limit ?? session.defaultLimit ?? DEFAULT_LIMIT;\n\n if (session.cache) {\n const cached = session.cache.get({\n path: resolvedPath,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n offset,\n limit,\n });\n if (cached) {\n if (session.ledger) {\n session.ledger.record({\n path: resolvedPath,\n sha256: cached.meta.sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n lines_returned: cached.meta.returnedLines,\n offset,\n limit,\n timestamp_ms: Date.now(),\n });\n }\n return cached;\n }\n }\n\n const bytes = await ops.readFile(resolvedPath);\n const sha256 = createHash(\"sha256\").update(bytes).digest(\"hex\");\n\n const lineStreamOpts: {\n offset: number;\n limit: number;\n maxBytes?: number;\n maxLineLength?: number;\n signal?: AbortSignal;\n } = { offset, limit };\n if (session.maxBytes !== undefined) lineStreamOpts.maxBytes = session.maxBytes;\n if (session.maxLineLength !== undefined)\n lineStreamOpts.maxLineLength = session.maxLineLength;\n if (session.signal !== undefined) lineStreamOpts.signal = session.signal;\n\n const result = await streamLinesFromBytes(bytes, lineStreamOpts);\n\n if (result.totalLines > 0 && offset > result.totalLines) {\n return err(\n toolError(\n \"INVALID_PARAM\",\n `Offset ${offset} is out of range for this file (${result.totalLines} lines)`,\n { meta: { path: resolvedPath, totalLines: result.totalLines } },\n ),\n );\n }\n\n const output = formatText({\n path: resolvedPath,\n offset,\n lines: result.lines,\n totalLines: result.totalLines,\n more: result.more,\n byteCap: result.byteCap,\n });\n\n const textResult: TextReadResult = {\n kind: \"text\",\n output,\n meta: {\n path: resolvedPath,\n totalLines: result.totalLines,\n returnedLines: result.lines.length,\n offset,\n limit,\n byteCap: result.byteCap,\n more: result.more,\n sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n },\n };\n\n if (session.cache) {\n session.cache.set(\n {\n path: resolvedPath,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n offset,\n limit,\n },\n textResult,\n );\n }\n\n if (session.ledger) {\n session.ledger.record({\n path: resolvedPath,\n sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n lines_returned: result.lines.length,\n offset,\n limit,\n timestamp_ms: Date.now(),\n });\n }\n\n return textResult;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -3,8 +3,8 @@ import * as v from 'valibot';
3
3
 
4
4
  interface ReadParams {
5
5
  readonly path: string;
6
- readonly offset?: number;
7
- readonly limit?: number;
6
+ readonly offset?: number | undefined;
7
+ readonly limit?: number | undefined;
8
8
  }
9
9
  interface ReadSessionConfig {
10
10
  readonly cwd: string;
@@ -74,9 +74,9 @@ type ReadResult = TextReadResult | DirReadResult | AttachmentReadResult | ErrorR
74
74
  declare function read(input: unknown, session: ReadSessionConfig): Promise<ReadResult>;
75
75
 
76
76
  declare const ReadParamsSchema: v.ObjectSchema<{
77
- readonly path: v.SchemaWithPipe<[v.StringSchema<undefined>, v.MinLengthAction<string, 1, "path must not be empty">]>;
78
- readonly offset: v.OptionalSchema<v.SchemaWithPipe<[v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, "offset must be >= 1">]>, never>;
79
- readonly limit: v.OptionalSchema<v.SchemaWithPipe<[v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, "limit must be >= 1">]>, never>;
77
+ readonly path: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "path must not be empty">]>;
78
+ readonly offset: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, "offset must be >= 1">]>, undefined>;
79
+ readonly limit: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, "limit must be >= 1">]>, undefined>;
80
80
  }, undefined>;
81
81
  type ParsedReadParams = v.InferOutput<typeof ReadParamsSchema>;
82
82
  declare function parseReadParams(input: unknown): ParsedReadParams;
@@ -112,6 +112,15 @@ interface StreamLinesResult {
112
112
  readonly byteCap: boolean;
113
113
  }
114
114
  declare function streamLines(ops: ReadOperations, path: string, opts: StreamLinesOptions): Promise<StreamLinesResult>;
115
+ /**
116
+ * Same line-oriented contract as {@link streamLines}, but sourced from bytes
117
+ * already held in memory instead of a fresh filesystem read. Lets a caller
118
+ * that has read the file once (e.g. for hashing) reuse those bytes for line
119
+ * content without a second OS read. Uses Node's own readline over an in-memory
120
+ * Readable so CRLF stripping, trailing-newline, and empty-file semantics match
121
+ * {@link ReadOperations.openLineStream} exactly.
122
+ */
123
+ declare function streamLinesFromBytes(bytes: Uint8Array, opts: StreamLinesOptions): Promise<StreamLinesResult>;
115
124
 
116
125
  declare function suggestSiblings(ops: ReadOperations, missingPath: string): Promise<readonly string[]>;
117
126
 
@@ -138,4 +147,4 @@ declare const MAX_BYTES: number;
138
147
  declare const MAX_FILE_SIZE: number;
139
148
  declare const BINARY_EXTENSIONS: ReadonlySet<string>;
140
149
 
141
- export { type Attachment, type AttachmentMeta, type AttachmentReadResult, BINARY_EXTENSIONS, DEFAULT_LIMIT, type DirMeta, type DirReadResult, type ErrorReadResult, MAX_BYTES, MAX_FILE_SIZE, MAX_LINE_LENGTH, READ_TOOL_DESCRIPTION, READ_TOOL_NAME, type ReadParams, ReadParamsSchema, type ReadResult, type ReadSessionConfig, type TextMeta, type TextReadResult, formatAttachment, formatDirectory, formatText, isBinary, isBinaryByContent, isBinaryByExtension, isImageMime, isPdfMime, parseReadParams, read, readToolDefinition, safeParseReadParams, streamLines, suggestSiblings };
150
+ export { type Attachment, type AttachmentMeta, type AttachmentReadResult, BINARY_EXTENSIONS, DEFAULT_LIMIT, type DirMeta, type DirReadResult, type ErrorReadResult, MAX_BYTES, MAX_FILE_SIZE, MAX_LINE_LENGTH, READ_TOOL_DESCRIPTION, READ_TOOL_NAME, type ReadParams, ReadParamsSchema, type ReadResult, type ReadSessionConfig, type TextMeta, type TextReadResult, formatAttachment, formatDirectory, formatText, isBinary, isBinaryByContent, isBinaryByExtension, isImageMime, isPdfMime, parseReadParams, read, readToolDefinition, safeParseReadParams, streamLines, streamLinesFromBytes, suggestSiblings };
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@ import * as v from 'valibot';
3
3
 
4
4
  interface ReadParams {
5
5
  readonly path: string;
6
- readonly offset?: number;
7
- readonly limit?: number;
6
+ readonly offset?: number | undefined;
7
+ readonly limit?: number | undefined;
8
8
  }
9
9
  interface ReadSessionConfig {
10
10
  readonly cwd: string;
@@ -74,9 +74,9 @@ type ReadResult = TextReadResult | DirReadResult | AttachmentReadResult | ErrorR
74
74
  declare function read(input: unknown, session: ReadSessionConfig): Promise<ReadResult>;
75
75
 
76
76
  declare const ReadParamsSchema: v.ObjectSchema<{
77
- readonly path: v.SchemaWithPipe<[v.StringSchema<undefined>, v.MinLengthAction<string, 1, "path must not be empty">]>;
78
- readonly offset: v.OptionalSchema<v.SchemaWithPipe<[v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, "offset must be >= 1">]>, never>;
79
- readonly limit: v.OptionalSchema<v.SchemaWithPipe<[v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, "limit must be >= 1">]>, never>;
77
+ readonly path: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "path must not be empty">]>;
78
+ readonly offset: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, "offset must be >= 1">]>, undefined>;
79
+ readonly limit: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, "limit must be >= 1">]>, undefined>;
80
80
  }, undefined>;
81
81
  type ParsedReadParams = v.InferOutput<typeof ReadParamsSchema>;
82
82
  declare function parseReadParams(input: unknown): ParsedReadParams;
@@ -112,6 +112,15 @@ interface StreamLinesResult {
112
112
  readonly byteCap: boolean;
113
113
  }
114
114
  declare function streamLines(ops: ReadOperations, path: string, opts: StreamLinesOptions): Promise<StreamLinesResult>;
115
+ /**
116
+ * Same line-oriented contract as {@link streamLines}, but sourced from bytes
117
+ * already held in memory instead of a fresh filesystem read. Lets a caller
118
+ * that has read the file once (e.g. for hashing) reuse those bytes for line
119
+ * content without a second OS read. Uses Node's own readline over an in-memory
120
+ * Readable so CRLF stripping, trailing-newline, and empty-file semantics match
121
+ * {@link ReadOperations.openLineStream} exactly.
122
+ */
123
+ declare function streamLinesFromBytes(bytes: Uint8Array, opts: StreamLinesOptions): Promise<StreamLinesResult>;
115
124
 
116
125
  declare function suggestSiblings(ops: ReadOperations, missingPath: string): Promise<readonly string[]>;
117
126
 
@@ -138,4 +147,4 @@ declare const MAX_BYTES: number;
138
147
  declare const MAX_FILE_SIZE: number;
139
148
  declare const BINARY_EXTENSIONS: ReadonlySet<string>;
140
149
 
141
- export { type Attachment, type AttachmentMeta, type AttachmentReadResult, BINARY_EXTENSIONS, DEFAULT_LIMIT, type DirMeta, type DirReadResult, type ErrorReadResult, MAX_BYTES, MAX_FILE_SIZE, MAX_LINE_LENGTH, READ_TOOL_DESCRIPTION, READ_TOOL_NAME, type ReadParams, ReadParamsSchema, type ReadResult, type ReadSessionConfig, type TextMeta, type TextReadResult, formatAttachment, formatDirectory, formatText, isBinary, isBinaryByContent, isBinaryByExtension, isImageMime, isPdfMime, parseReadParams, read, readToolDefinition, safeParseReadParams, streamLines, suggestSiblings };
150
+ export { type Attachment, type AttachmentMeta, type AttachmentReadResult, BINARY_EXTENSIONS, DEFAULT_LIMIT, type DirMeta, type DirReadResult, type ErrorReadResult, MAX_BYTES, MAX_FILE_SIZE, MAX_LINE_LENGTH, READ_TOOL_DESCRIPTION, READ_TOOL_NAME, type ReadParams, ReadParamsSchema, type ReadResult, type ReadSessionConfig, type TextMeta, type TextReadResult, formatAttachment, formatDirectory, formatText, isBinary, isBinaryByContent, isBinaryByExtension, isImageMime, isPdfMime, parseReadParams, read, readToolDefinition, safeParseReadParams, streamLines, streamLinesFromBytes, suggestSiblings };
package/dist/index.js CHANGED
@@ -2,6 +2,8 @@ import { Buffer } from 'buffer';
2
2
  import { createHash } from 'crypto';
3
3
  import path3 from 'path';
4
4
  import { toolError, defaultNodeOperations, withFileLock, matchesAnyPattern, isInsideAnyRoot } from '@agent-sh/harness-core';
5
+ import readline from 'readline';
6
+ import { Readable } from 'stream';
5
7
  import * as v from 'valibot';
6
8
 
7
9
  // src/read.ts
@@ -124,6 +126,31 @@ function formatAttachment(kind) {
124
126
  return `${kind} read successfully`;
125
127
  }
126
128
  async function streamLines(ops, path4, opts) {
129
+ const signalOpt = {};
130
+ if (opts.signal !== void 0) signalOpt.signal = opts.signal;
131
+ const iter = ops.openLineStream(path4, signalOpt);
132
+ return consumeLines(iter, opts);
133
+ }
134
+ async function streamLinesFromBytes(bytes, opts) {
135
+ const str = Buffer.from(bytes).toString("utf8");
136
+ const rl = readline.createInterface({
137
+ input: Readable.from([str]),
138
+ crlfDelay: Infinity
139
+ });
140
+ const signal = opts.signal;
141
+ const iter = (async function* () {
142
+ try {
143
+ for await (const line of rl) {
144
+ if (signal?.aborted) break;
145
+ yield line;
146
+ }
147
+ } finally {
148
+ rl.close();
149
+ }
150
+ })();
151
+ return consumeLines(iter, opts);
152
+ }
153
+ async function consumeLines(iter, opts) {
127
154
  const maxBytes = opts.maxBytes ?? MAX_BYTES;
128
155
  const maxLineLen = opts.maxLineLength ?? MAX_LINE_LENGTH;
129
156
  const start = opts.offset - 1;
@@ -132,9 +159,6 @@ async function streamLines(ops, path4, opts) {
132
159
  let totalLines = 0;
133
160
  let more = false;
134
161
  let byteCap = false;
135
- const signalOpt = {};
136
- if (opts.signal !== void 0) signalOpt.signal = opts.signal;
137
- const iter = ops.openLineStream(path4, signalOpt);
138
162
  for await (const raw of iter) {
139
163
  totalLines += 1;
140
164
  if (totalLines <= start) continue;
@@ -302,11 +326,6 @@ async function fencePath(ops, session, resolvedPath) {
302
326
  );
303
327
  }
304
328
  if (!insideWorkspace && permissions.bypassWorkspaceGuard !== true && permissions.hook === void 0) {
305
- if (process.env.E2E_DEBUG_PERMISSIONS) {
306
- console.error(
307
- `[read fencePath] OUTSIDE_WORKSPACE reject: resolvedPath=${JSON.stringify(resolvedPath)} roots=${JSON.stringify(permissions.roots)}`
308
- );
309
- }
310
329
  return toolError(
311
330
  "OUTSIDE_WORKSPACE",
312
331
  `Path is outside all configured workspace roots: ${resolvedPath}`,
@@ -471,12 +490,14 @@ async function readText(ops, session, resolvedPath, stat, params) {
471
490
  return cached;
472
491
  }
473
492
  }
493
+ const bytes = await ops.readFile(resolvedPath);
494
+ const sha256 = createHash("sha256").update(bytes).digest("hex");
474
495
  const lineStreamOpts = { offset, limit };
475
496
  if (session.maxBytes !== void 0) lineStreamOpts.maxBytes = session.maxBytes;
476
497
  if (session.maxLineLength !== void 0)
477
498
  lineStreamOpts.maxLineLength = session.maxLineLength;
478
499
  if (session.signal !== void 0) lineStreamOpts.signal = session.signal;
479
- const result = await streamLines(ops, resolvedPath, lineStreamOpts);
500
+ const result = await streamLinesFromBytes(bytes, lineStreamOpts);
480
501
  if (result.totalLines > 0 && offset > result.totalLines) {
481
502
  return err(
482
503
  toolError(
@@ -486,8 +507,6 @@ async function readText(ops, session, resolvedPath, stat, params) {
486
507
  )
487
508
  );
488
509
  }
489
- const bytes = await ops.readFile(resolvedPath);
490
- const sha256 = createHash("sha256").update(bytes).digest("hex");
491
510
  const output = formatText({
492
511
  path: resolvedPath,
493
512
  offset,
@@ -539,6 +558,6 @@ async function readText(ops, session, resolvedPath, stat, params) {
539
558
  return textResult;
540
559
  }
541
560
 
542
- export { BINARY_EXTENSIONS, DEFAULT_LIMIT, MAX_BYTES, MAX_FILE_SIZE, MAX_LINE_LENGTH, READ_TOOL_DESCRIPTION, READ_TOOL_NAME, ReadParamsSchema, formatAttachment, formatDirectory, formatText, isBinary, isBinaryByContent, isBinaryByExtension, isImageMime, isPdfMime, parseReadParams, read, readToolDefinition, safeParseReadParams, streamLines, suggestSiblings };
561
+ export { BINARY_EXTENSIONS, DEFAULT_LIMIT, MAX_BYTES, MAX_FILE_SIZE, MAX_LINE_LENGTH, READ_TOOL_DESCRIPTION, READ_TOOL_NAME, ReadParamsSchema, formatAttachment, formatDirectory, formatText, isBinary, isBinaryByContent, isBinaryByExtension, isImageMime, isPdfMime, parseReadParams, read, readToolDefinition, safeParseReadParams, streamLines, streamLinesFromBytes, suggestSiblings };
543
562
  //# sourceMappingURL=index.js.map
544
563
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/binary.ts","../src/format.ts","../src/lines.ts","../src/schema.ts","../src/suggest.ts","../src/read.ts"],"names":["path","Buffer"],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_LIMIT = 2000;\nexport const MAX_LINE_LENGTH = 2000;\nexport const MAX_LINE_SUFFIX = `... (line truncated to ${MAX_LINE_LENGTH} chars)`;\nexport const MAX_BYTES = 50 * 1024;\nexport const MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB`;\nexport const MAX_FILE_SIZE = 5 * 1024 * 1024;\nexport const BINARY_SAMPLE_BYTES = 4096;\nexport const FUZZY_SUGGESTION_LIMIT = 3;\n\nexport const BINARY_EXTENSIONS: ReadonlySet<string> = new Set([\n \".zip\",\n \".tar\",\n \".gz\",\n \".exe\",\n \".dll\",\n \".so\",\n \".class\",\n \".jar\",\n \".war\",\n \".7z\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".odt\",\n \".ods\",\n \".odp\",\n \".bin\",\n \".dat\",\n \".obj\",\n \".o\",\n \".a\",\n \".lib\",\n \".wasm\",\n \".pyc\",\n \".pyo\",\n]);\n","import path from \"node:path\";\nimport { BINARY_EXTENSIONS } from \"./constants.js\";\n\nexport function isBinaryByExtension(filepath: string): boolean {\n return BINARY_EXTENSIONS.has(path.extname(filepath).toLowerCase());\n}\n\nexport function isBinaryByContent(sample: Uint8Array): boolean {\n if (sample.length === 0) return false;\n let nonPrintable = 0;\n for (let i = 0; i < sample.length; i++) {\n const b = sample[i] as number;\n if (b === 0) return true;\n if (b < 9 || (b > 13 && b < 32)) nonPrintable++;\n }\n return nonPrintable / sample.length > 0.3;\n}\n\nexport function isBinary(filepath: string, sample: Uint8Array): boolean {\n return isBinaryByExtension(filepath) || isBinaryByContent(sample);\n}\n\nexport function isImageMime(mime: string): boolean {\n if (!mime.startsWith(\"image/\")) return false;\n if (mime === \"image/svg+xml\") return false;\n return true;\n}\n\nexport function isPdfMime(mime: string): boolean {\n return mime === \"application/pdf\";\n}\n","import { MAX_BYTES_LABEL } from \"./constants.js\";\nimport type {\n AttachmentReadResult,\n DirReadResult,\n TextReadResult,\n} from \"./types.js\";\n\nexport function formatText(\n params: {\n path: string;\n offset: number;\n lines: readonly string[];\n totalLines: number;\n more: boolean;\n byteCap: boolean;\n },\n): string {\n const { path, offset, lines, totalLines, more, byteCap } = params;\n const header = `<path>${path}</path>\\n<type>file</type>\\n<content>`;\n\n if (lines.length === 0 && totalLines === 0) {\n return `${header}\\n(File exists but is empty)\\n</content>`;\n }\n\n const body = lines.map((line, i) => `${offset + i}: ${line}`).join(\"\\n\");\n const last = offset + lines.length - 1;\n const next = last + 1;\n\n let hint: string;\n if (byteCap) {\n const pct = totalLines > 0 ? Math.round((last / totalLines) * 100) : 0;\n const remaining = Math.max(totalLines - last, 0);\n hint = `(Output capped at ${MAX_BYTES_LABEL}. Showing lines ${offset}-${last} of ${totalLines} · ${pct}% covered · ${remaining} lines remaining. Next offset: ${next}.)`;\n } else if (more) {\n const pct = Math.round((last / totalLines) * 100);\n const remaining = Math.max(totalLines - last, 0);\n hint = `(Showing lines ${offset}-${last} of ${totalLines} · ${pct}% covered · ${remaining} lines remaining. Next offset: ${next}.)`;\n } else {\n hint = `(End of file · ${totalLines} lines total)`;\n }\n\n return `${header}\\n${body}\\n\\n${hint}\\n</content>`;\n}\n\nexport function formatDirectory(params: {\n path: string;\n entries: readonly string[];\n offset: number;\n totalEntries: number;\n more: boolean;\n}): string {\n const { path, entries, offset, totalEntries, more } = params;\n const header = `<path>${path}</path>\\n<type>directory</type>\\n<entries>`;\n const body = entries.join(\"\\n\");\n const last = offset + entries.length - 1;\n const next = last + 1;\n const remaining = Math.max(totalEntries - last, 0);\n const hint = more\n ? `(Showing ${entries.length} of ${totalEntries} entries · ${remaining} remaining. Next offset: ${next}.)`\n : `(${totalEntries} entries)`;\n return `${header}\\n${body}\\n\\n${hint}\\n</entries>`;\n}\n\nexport function formatAttachment(kind: \"Image\" | \"PDF\"): string {\n return `${kind} read successfully`;\n}\n\nexport function asTextResult(x: TextReadResult): TextReadResult {\n return x;\n}\nexport function asDirResult(x: DirReadResult): DirReadResult {\n return x;\n}\nexport function asAttachResult(x: AttachmentReadResult): AttachmentReadResult {\n return x;\n}\n","import { Buffer } from \"node:buffer\";\nimport type { ReadOperations } from \"@agent-sh/harness-core\";\nimport {\n MAX_BYTES,\n MAX_LINE_LENGTH,\n MAX_LINE_SUFFIX,\n} from \"./constants.js\";\n\nexport interface StreamLinesOptions {\n readonly offset: number;\n readonly limit: number;\n readonly maxBytes?: number;\n readonly maxLineLength?: number;\n readonly signal?: AbortSignal;\n}\n\nexport interface StreamLinesResult {\n readonly lines: readonly string[];\n readonly totalLines: number;\n readonly offset: number;\n readonly more: boolean;\n readonly byteCap: boolean;\n}\n\nexport async function streamLines(\n ops: ReadOperations,\n path: string,\n opts: StreamLinesOptions,\n): Promise<StreamLinesResult> {\n const maxBytes = opts.maxBytes ?? MAX_BYTES;\n const maxLineLen = opts.maxLineLength ?? MAX_LINE_LENGTH;\n const start = opts.offset - 1;\n\n const out: string[] = [];\n let bytes = 0;\n let totalLines = 0;\n let more = false;\n let byteCap = false;\n\n const signalOpt: { signal?: AbortSignal } = {};\n if (opts.signal !== undefined) signalOpt.signal = opts.signal;\n\n const iter = ops.openLineStream(path, signalOpt);\n\n for await (const raw of iter) {\n totalLines += 1;\n if (totalLines <= start) continue;\n\n if (out.length >= opts.limit) {\n more = true;\n continue;\n }\n\n const truncated =\n raw.length > maxLineLen ? raw.substring(0, maxLineLen) + MAX_LINE_SUFFIX : raw;\n\n const size = Buffer.byteLength(truncated, \"utf8\") + (out.length > 0 ? 1 : 0);\n if (bytes + size > maxBytes) {\n byteCap = true;\n more = true;\n break;\n }\n\n out.push(truncated);\n bytes += size;\n }\n\n return {\n lines: out,\n totalLines,\n offset: opts.offset,\n more,\n byteCap,\n };\n}\n","import * as v from \"valibot\";\nimport type { ToolDefinition } from \"@agent-sh/harness-core\";\nimport type { ReadParams } from \"./types.js\";\n\nexport const ReadParamsSchema = v.object({\n path: v.pipe(v.string(), v.minLength(1, \"path must not be empty\")),\n offset: v.optional(\n v.pipe(v.number(), v.integer(), v.minValue(1, \"offset must be >= 1\")),\n ),\n limit: v.optional(\n v.pipe(v.number(), v.integer(), v.minValue(1, \"limit must be >= 1\")),\n ),\n});\n\nexport type ParsedReadParams = v.InferOutput<typeof ReadParamsSchema>;\n\nexport function parseReadParams(input: unknown): ParsedReadParams {\n return v.parse(ReadParamsSchema, input);\n}\n\nexport function safeParseReadParams(input: unknown):\n | { ok: true; value: ReadParams }\n | { ok: false; issues: v.BaseIssue<unknown>[] } {\n const result = v.safeParse(ReadParamsSchema, input);\n if (result.success) return { ok: true, value: result.output };\n return { ok: false, issues: result.issues };\n}\n\nexport const READ_TOOL_NAME = \"read\";\n\nexport const READ_TOOL_DESCRIPTION = `Read a file or directory from the local filesystem.\n\nUsage:\n- The path parameter should be an absolute path. If relative, it resolves against the session working directory.\n- By default, returns up to 2000 lines from the start of the file.\n- The offset parameter is the 1-indexed line number to start from.\n- For later sections, call this tool again with a larger offset.\n- Use the grep tool for content search in large files; glob to locate files by pattern.\n- Contents are returned with each line prefixed by its line number as \"<line>: <content>\".\n- Any line longer than 2000 characters is truncated.\n- Call this tool in parallel when reading multiple files.\n- Avoid tiny repeated slices (under 30 lines). Read a larger window instead.\n- Images and PDFs are returned as file attachments.\n- Binary files are refused; use specialized tools.`;\n\nexport const readToolDefinition: ToolDefinition = {\n name: READ_TOOL_NAME,\n description: READ_TOOL_DESCRIPTION,\n inputSchema: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description:\n \"Absolute path (preferred) or path relative to the session cwd.\",\n },\n offset: {\n type: \"integer\",\n minimum: 1,\n description: \"1-indexed line number to start reading from.\",\n },\n limit: {\n type: \"integer\",\n minimum: 1,\n description: \"Maximum number of lines to read. Defaults to 2000.\",\n },\n },\n required: [\"path\"],\n additionalProperties: false,\n },\n};\n","import path from \"node:path\";\nimport type { ReadOperations } from \"@agent-sh/harness-core\";\nimport { FUZZY_SUGGESTION_LIMIT } from \"./constants.js\";\n\nexport async function suggestSiblings(\n ops: ReadOperations,\n missingPath: string,\n): Promise<readonly string[]> {\n const dir = path.dirname(missingPath);\n const base = path.basename(missingPath).toLowerCase();\n let entries: readonly string[];\n try {\n entries = await ops.readDirectory(dir);\n } catch {\n return [];\n }\n const scored: { p: string; score: number }[] = [];\n for (const entry of entries) {\n const lower = entry.toLowerCase();\n const score = similarity(base, lower);\n if (score > 0) scored.push({ p: path.join(dir, entry), score });\n }\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, FUZZY_SUGGESTION_LIMIT).map((s) => s.p);\n}\n\nfunction similarity(a: string, b: string): number {\n if (a === b) return 1000;\n if (a.length === 0 || b.length === 0) return 0;\n if (a.includes(b) || b.includes(a)) return 500;\n const prefix = commonPrefix(a, b);\n if (prefix >= 3) return 200 + prefix;\n if (prefix >= 2 && Math.abs(a.length - b.length) <= 2) return 100 + prefix;\n const aExt = extOf(a);\n const bExt = extOf(b);\n if (aExt && aExt === bExt) return 10;\n return 0;\n}\n\nfunction commonPrefix(a: string, b: string): number {\n const n = Math.min(a.length, b.length);\n let i = 0;\n while (i < n && a[i] === b[i]) i++;\n return i;\n}\n\nfunction extOf(name: string): string {\n const dot = name.lastIndexOf(\".\");\n return dot > 0 ? name.slice(dot) : \"\";\n}\n","import { Buffer } from \"node:buffer\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n defaultNodeOperations,\n isInsideAnyRoot,\n matchesAnyPattern,\n toolError,\n withFileLock,\n type ReadOperations,\n type ToolError,\n} from \"@agent-sh/harness-core\";\nimport { isBinary, isImageMime, isPdfMime } from \"./binary.js\";\nimport {\n BINARY_SAMPLE_BYTES,\n DEFAULT_LIMIT,\n MAX_FILE_SIZE,\n} from \"./constants.js\";\nimport {\n formatAttachment,\n formatDirectory,\n formatText,\n} from \"./format.js\";\nimport { streamLines } from \"./lines.js\";\nimport { safeParseReadParams } from \"./schema.js\";\nimport { suggestSiblings } from \"./suggest.js\";\nimport type {\n AttachmentReadResult,\n DirReadResult,\n ErrorReadResult,\n ReadParams,\n ReadResult,\n ReadSessionConfig,\n TextReadResult,\n} from \"./types.js\";\n\nfunction err(error: ToolError): ErrorReadResult {\n return { kind: \"error\", error };\n}\n\nexport async function read(\n input: unknown,\n session: ReadSessionConfig,\n): Promise<ReadResult> {\n const parsed = safeParseReadParams(input);\n if (!parsed.ok) {\n const messages = parsed.issues.map((i) => i.message).join(\"; \");\n return err(toolError(\"INVALID_PARAM\", messages, { cause: parsed.issues }));\n }\n const params = parsed.value;\n\n const ops = session.ops ?? defaultNodeOperations();\n\n const resolvedPath = await resolvePath(ops, session.cwd, params.path);\n const fence = await fencePath(ops, session, resolvedPath);\n if (fence !== undefined) return err(fence);\n\n return withFileLock(resolvedPath, () =>\n executeRead(ops, session, resolvedPath, params),\n );\n}\n\nasync function resolvePath(\n ops: ReadOperations,\n cwd: string,\n input: string,\n): Promise<string> {\n const absolute = path.isAbsolute(input) ? input : path.resolve(cwd, input);\n try {\n return await ops.realpath(absolute);\n } catch {\n return absolute;\n }\n}\n\nasync function fencePath(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n): Promise<ToolError | undefined> {\n const { permissions } = session;\n\n const isSensitive = matchesAnyPattern(\n resolvedPath,\n permissions.sensitivePatterns,\n );\n const insideWorkspace = isInsideAnyRoot(resolvedPath, permissions.roots);\n const needsAsk =\n isSensitive ||\n (!insideWorkspace && permissions.bypassWorkspaceGuard !== true);\n\n if (isSensitive && permissions.hook === undefined) {\n return toolError(\n \"SENSITIVE\",\n `Refusing to read sensitive path: ${resolvedPath}`,\n { meta: { path: resolvedPath } },\n );\n }\n\n if (\n !insideWorkspace &&\n permissions.bypassWorkspaceGuard !== true &&\n permissions.hook === undefined\n ) {\n if (process.env.E2E_DEBUG_PERMISSIONS) {\n // eslint-disable-next-line no-console\n console.error(\n `[read fencePath] OUTSIDE_WORKSPACE reject: resolvedPath=${JSON.stringify(resolvedPath)} roots=${JSON.stringify(permissions.roots)}`,\n );\n }\n return toolError(\n \"OUTSIDE_WORKSPACE\",\n `Path is outside all configured workspace roots: ${resolvedPath}`,\n { meta: { path: resolvedPath, roots: permissions.roots } },\n );\n }\n\n if (permissions.hook !== undefined) {\n const reason = isSensitive\n ? \"sensitive\"\n : !insideWorkspace\n ? \"outside_workspace\"\n : \"in_workspace\";\n const alwaysPatterns = needsAsk\n ? [path.dirname(resolvedPath) + \"/*\"]\n : [\"*\"];\n const decision = await permissions.hook({\n tool: \"read\",\n path: resolvedPath,\n action: \"read\",\n always_patterns: alwaysPatterns,\n metadata: { reason },\n });\n if (decision === \"deny\") {\n return toolError(\n \"PERMISSION_DENIED\",\n `Read denied by user: ${resolvedPath}`,\n { meta: { path: resolvedPath } },\n );\n }\n }\n\n return undefined;\n}\n\nasync function executeRead(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n params: ReadParams,\n): Promise<ReadResult> {\n let stat;\n try {\n stat = await ops.stat(resolvedPath);\n } catch (e) {\n return err(\n toolError(\"IO_ERROR\", `stat failed: ${(e as Error).message}`, {\n cause: e,\n }),\n );\n }\n\n if (!stat) {\n const suggestions = await suggestSiblings(ops, resolvedPath);\n const msg =\n suggestions.length > 0\n ? `File not found: ${resolvedPath}\\n\\nDid you mean one of these?\\n${suggestions.join(\"\\n\")}`\n : `File not found: ${resolvedPath}`;\n return err(\n toolError(\"NOT_FOUND\", msg, { meta: { path: resolvedPath, suggestions } }),\n );\n }\n\n if (stat.type === \"directory\") {\n return readDirectory(ops, resolvedPath, params);\n }\n\n const maxSize = session.maxFileSize ?? MAX_FILE_SIZE;\n if (stat.size > maxSize) {\n return err(\n toolError(\n \"TOO_LARGE\",\n `File size ${stat.size} exceeds max ${maxSize}. Use a narrower offset/limit or grep first.`,\n { meta: { path: resolvedPath, size: stat.size, maxSize } },\n ),\n );\n }\n\n const half = session.modelContextTokens\n ? Math.floor(session.modelContextTokens / 2)\n : undefined;\n const tokensPerByte = session.tokensPerByte ?? 0.3;\n if (half !== undefined && stat.size * tokensPerByte > half) {\n return err(\n toolError(\n \"TOO_LARGE\",\n `File would consume more than half of the model context (~${Math.floor(stat.size * tokensPerByte)} tokens > ${half}). Use offset/limit or grep first.`,\n { meta: { path: resolvedPath, size: stat.size, half } },\n ),\n );\n }\n\n const mime = ops.mimeType(resolvedPath);\n if (isImageMime(mime) || isPdfMime(mime)) {\n return readAttachment(ops, resolvedPath, mime, stat.size);\n }\n\n const sample = await readSample(ops, resolvedPath, stat.size);\n if (isBinary(resolvedPath, sample)) {\n return err(\n toolError(\"BINARY\", `Cannot read binary file: ${resolvedPath}`, {\n meta: { path: resolvedPath },\n }),\n );\n }\n\n return readText(ops, session, resolvedPath, stat, params);\n}\n\nasync function readSample(\n ops: ReadOperations,\n p: string,\n size: number,\n): Promise<Uint8Array> {\n if (size === 0) return new Uint8Array();\n const bytes = await ops.readFile(p);\n return bytes.length > BINARY_SAMPLE_BYTES\n ? bytes.subarray(0, BINARY_SAMPLE_BYTES)\n : bytes;\n}\n\nasync function readDirectory(\n ops: ReadOperations,\n resolvedPath: string,\n params: ReadParams,\n): Promise<DirReadResult> {\n const entries = await ops.readDirectoryEntries(resolvedPath);\n const named = await Promise.all(\n entries.map(async (e) => {\n if (e.type === \"directory\") return e.name + \"/\";\n if (e.type !== \"symlink\") return e.name;\n const target = await ops\n .stat(path.join(resolvedPath, e.name))\n .catch(() => undefined);\n return target?.type === \"directory\" ? e.name + \"/\" : e.name;\n }),\n );\n named.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: \"base\" }));\n\n const offset = params.offset ?? 1;\n const limit = params.limit ?? DEFAULT_LIMIT;\n const start = offset - 1;\n const sliced = named.slice(start, start + limit);\n const more = start + sliced.length < named.length;\n\n const output = formatDirectory({\n path: resolvedPath,\n entries: sliced,\n offset,\n totalEntries: named.length,\n more,\n });\n\n return {\n kind: \"directory\",\n output,\n meta: {\n path: resolvedPath,\n totalEntries: named.length,\n returnedEntries: sliced.length,\n offset,\n limit,\n more,\n },\n };\n}\n\nasync function readAttachment(\n ops: ReadOperations,\n resolvedPath: string,\n mime: string,\n size: number,\n): Promise<AttachmentReadResult> {\n const bytes = await ops.readFile(resolvedPath);\n const kind: \"Image\" | \"PDF\" = mime === \"application/pdf\" ? \"PDF\" : \"Image\";\n const dataUrl = `data:${mime};base64,${Buffer.from(bytes).toString(\"base64\")}`;\n return {\n kind: \"attachment\",\n output: formatAttachment(kind),\n attachments: [{ mime, dataUrl }],\n meta: { path: resolvedPath, mime, size_bytes: size },\n };\n}\n\nasync function readText(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n stat: { size: number; mtime_ms: number },\n params: ReadParams,\n): Promise<ReadResult> {\n const offset = params.offset ?? 1;\n const limit = params.limit ?? session.defaultLimit ?? DEFAULT_LIMIT;\n\n if (session.cache) {\n const cached = session.cache.get({\n path: resolvedPath,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n offset,\n limit,\n });\n if (cached) {\n if (session.ledger) {\n session.ledger.record({\n path: resolvedPath,\n sha256: cached.meta.sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n lines_returned: cached.meta.returnedLines,\n offset,\n limit,\n timestamp_ms: Date.now(),\n });\n }\n return cached;\n }\n }\n\n const lineStreamOpts: {\n offset: number;\n limit: number;\n maxBytes?: number;\n maxLineLength?: number;\n signal?: AbortSignal;\n } = { offset, limit };\n if (session.maxBytes !== undefined) lineStreamOpts.maxBytes = session.maxBytes;\n if (session.maxLineLength !== undefined)\n lineStreamOpts.maxLineLength = session.maxLineLength;\n if (session.signal !== undefined) lineStreamOpts.signal = session.signal;\n\n const result = await streamLines(ops, resolvedPath, lineStreamOpts);\n\n if (result.totalLines > 0 && offset > result.totalLines) {\n return err(\n toolError(\n \"INVALID_PARAM\",\n `Offset ${offset} is out of range for this file (${result.totalLines} lines)`,\n { meta: { path: resolvedPath, totalLines: result.totalLines } },\n ),\n );\n }\n\n const bytes = await ops.readFile(resolvedPath);\n const sha256 = createHash(\"sha256\").update(bytes).digest(\"hex\");\n\n const output = formatText({\n path: resolvedPath,\n offset,\n lines: result.lines,\n totalLines: result.totalLines,\n more: result.more,\n byteCap: result.byteCap,\n });\n\n const textResult: TextReadResult = {\n kind: \"text\",\n output,\n meta: {\n path: resolvedPath,\n totalLines: result.totalLines,\n returnedLines: result.lines.length,\n offset,\n limit,\n byteCap: result.byteCap,\n more: result.more,\n sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n },\n };\n\n if (session.cache) {\n session.cache.set(\n {\n path: resolvedPath,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n offset,\n limit,\n },\n textResult,\n );\n }\n\n if (session.ledger) {\n session.ledger.record({\n path: resolvedPath,\n sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n lines_returned: result.lines.length,\n offset,\n limit,\n timestamp_ms: Date.now(),\n });\n }\n\n return textResult;\n}\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/binary.ts","../src/format.ts","../src/lines.ts","../src/schema.ts","../src/suggest.ts","../src/read.ts"],"names":["path","Buffer"],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_LIMIT = 2000;\nexport const MAX_LINE_LENGTH = 2000;\nexport const MAX_LINE_SUFFIX = `... (line truncated to ${MAX_LINE_LENGTH} chars)`;\nexport const MAX_BYTES = 50 * 1024;\nexport const MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB`;\nexport const MAX_FILE_SIZE = 5 * 1024 * 1024;\nexport const BINARY_SAMPLE_BYTES = 4096;\nexport const FUZZY_SUGGESTION_LIMIT = 3;\n\nexport const BINARY_EXTENSIONS: ReadonlySet<string> = new Set([\n \".zip\",\n \".tar\",\n \".gz\",\n \".exe\",\n \".dll\",\n \".so\",\n \".class\",\n \".jar\",\n \".war\",\n \".7z\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".odt\",\n \".ods\",\n \".odp\",\n \".bin\",\n \".dat\",\n \".obj\",\n \".o\",\n \".a\",\n \".lib\",\n \".wasm\",\n \".pyc\",\n \".pyo\",\n]);\n","import path from \"node:path\";\nimport { BINARY_EXTENSIONS } from \"./constants.js\";\n\nexport function isBinaryByExtension(filepath: string): boolean {\n return BINARY_EXTENSIONS.has(path.extname(filepath).toLowerCase());\n}\n\nexport function isBinaryByContent(sample: Uint8Array): boolean {\n if (sample.length === 0) return false;\n let nonPrintable = 0;\n for (let i = 0; i < sample.length; i++) {\n const b = sample[i] as number;\n if (b === 0) return true;\n if (b < 9 || (b > 13 && b < 32)) nonPrintable++;\n }\n return nonPrintable / sample.length > 0.3;\n}\n\nexport function isBinary(filepath: string, sample: Uint8Array): boolean {\n return isBinaryByExtension(filepath) || isBinaryByContent(sample);\n}\n\nexport function isImageMime(mime: string): boolean {\n if (!mime.startsWith(\"image/\")) return false;\n if (mime === \"image/svg+xml\") return false;\n return true;\n}\n\nexport function isPdfMime(mime: string): boolean {\n return mime === \"application/pdf\";\n}\n","import { MAX_BYTES_LABEL } from \"./constants.js\";\nimport type {\n AttachmentReadResult,\n DirReadResult,\n TextReadResult,\n} from \"./types.js\";\n\nexport function formatText(\n params: {\n path: string;\n offset: number;\n lines: readonly string[];\n totalLines: number;\n more: boolean;\n byteCap: boolean;\n },\n): string {\n const { path, offset, lines, totalLines, more, byteCap } = params;\n const header = `<path>${path}</path>\\n<type>file</type>\\n<content>`;\n\n if (lines.length === 0 && totalLines === 0) {\n return `${header}\\n(File exists but is empty)\\n</content>`;\n }\n\n const body = lines.map((line, i) => `${offset + i}: ${line}`).join(\"\\n\");\n const last = offset + lines.length - 1;\n const next = last + 1;\n\n let hint: string;\n if (byteCap) {\n const pct = totalLines > 0 ? Math.round((last / totalLines) * 100) : 0;\n const remaining = Math.max(totalLines - last, 0);\n hint = `(Output capped at ${MAX_BYTES_LABEL}. Showing lines ${offset}-${last} of ${totalLines} · ${pct}% covered · ${remaining} lines remaining. Next offset: ${next}.)`;\n } else if (more) {\n const pct = Math.round((last / totalLines) * 100);\n const remaining = Math.max(totalLines - last, 0);\n hint = `(Showing lines ${offset}-${last} of ${totalLines} · ${pct}% covered · ${remaining} lines remaining. Next offset: ${next}.)`;\n } else {\n hint = `(End of file · ${totalLines} lines total)`;\n }\n\n return `${header}\\n${body}\\n\\n${hint}\\n</content>`;\n}\n\nexport function formatDirectory(params: {\n path: string;\n entries: readonly string[];\n offset: number;\n totalEntries: number;\n more: boolean;\n}): string {\n const { path, entries, offset, totalEntries, more } = params;\n const header = `<path>${path}</path>\\n<type>directory</type>\\n<entries>`;\n const body = entries.join(\"\\n\");\n const last = offset + entries.length - 1;\n const next = last + 1;\n const remaining = Math.max(totalEntries - last, 0);\n const hint = more\n ? `(Showing ${entries.length} of ${totalEntries} entries · ${remaining} remaining. Next offset: ${next}.)`\n : `(${totalEntries} entries)`;\n return `${header}\\n${body}\\n\\n${hint}\\n</entries>`;\n}\n\nexport function formatAttachment(kind: \"Image\" | \"PDF\"): string {\n return `${kind} read successfully`;\n}\n\nexport function asTextResult(x: TextReadResult): TextReadResult {\n return x;\n}\nexport function asDirResult(x: DirReadResult): DirReadResult {\n return x;\n}\nexport function asAttachResult(x: AttachmentReadResult): AttachmentReadResult {\n return x;\n}\n","import { Buffer } from \"node:buffer\";\nimport readline from \"node:readline\";\nimport { Readable } from \"node:stream\";\nimport type { ReadOperations } from \"@agent-sh/harness-core\";\nimport {\n MAX_BYTES,\n MAX_LINE_LENGTH,\n MAX_LINE_SUFFIX,\n} from \"./constants.js\";\n\nexport interface StreamLinesOptions {\n readonly offset: number;\n readonly limit: number;\n readonly maxBytes?: number;\n readonly maxLineLength?: number;\n readonly signal?: AbortSignal;\n}\n\nexport interface StreamLinesResult {\n readonly lines: readonly string[];\n readonly totalLines: number;\n readonly offset: number;\n readonly more: boolean;\n readonly byteCap: boolean;\n}\n\nexport async function streamLines(\n ops: ReadOperations,\n path: string,\n opts: StreamLinesOptions,\n): Promise<StreamLinesResult> {\n const signalOpt: { signal?: AbortSignal } = {};\n if (opts.signal !== undefined) signalOpt.signal = opts.signal;\n\n const iter = ops.openLineStream(path, signalOpt);\n return consumeLines(iter, opts);\n}\n\n/**\n * Same line-oriented contract as {@link streamLines}, but sourced from bytes\n * already held in memory instead of a fresh filesystem read. Lets a caller\n * that has read the file once (e.g. for hashing) reuse those bytes for line\n * content without a second OS read. Uses Node's own readline over an in-memory\n * Readable so CRLF stripping, trailing-newline, and empty-file semantics match\n * {@link ReadOperations.openLineStream} exactly.\n */\nexport async function streamLinesFromBytes(\n bytes: Uint8Array,\n opts: StreamLinesOptions,\n): Promise<StreamLinesResult> {\n const str = Buffer.from(bytes).toString(\"utf8\");\n const rl = readline.createInterface({\n input: Readable.from([str]),\n crlfDelay: Infinity,\n });\n const signal = opts.signal;\n const iter: AsyncIterableIterator<string> = (async function* () {\n try {\n for await (const line of rl) {\n if (signal?.aborted) break;\n yield line;\n }\n } finally {\n rl.close();\n }\n })();\n return consumeLines(iter, opts);\n}\n\nasync function consumeLines(\n iter: AsyncIterable<string>,\n opts: StreamLinesOptions,\n): Promise<StreamLinesResult> {\n const maxBytes = opts.maxBytes ?? MAX_BYTES;\n const maxLineLen = opts.maxLineLength ?? MAX_LINE_LENGTH;\n const start = opts.offset - 1;\n\n const out: string[] = [];\n let bytes = 0;\n let totalLines = 0;\n let more = false;\n let byteCap = false;\n\n for await (const raw of iter) {\n totalLines += 1;\n if (totalLines <= start) continue;\n\n if (out.length >= opts.limit) {\n more = true;\n continue;\n }\n\n const truncated =\n raw.length > maxLineLen ? raw.substring(0, maxLineLen) + MAX_LINE_SUFFIX : raw;\n\n const size = Buffer.byteLength(truncated, \"utf8\") + (out.length > 0 ? 1 : 0);\n if (bytes + size > maxBytes) {\n byteCap = true;\n more = true;\n break;\n }\n\n out.push(truncated);\n bytes += size;\n }\n\n return {\n lines: out,\n totalLines,\n offset: opts.offset,\n more,\n byteCap,\n };\n}\n","import * as v from \"valibot\";\nimport type { ToolDefinition } from \"@agent-sh/harness-core\";\nimport type { ReadParams } from \"./types.js\";\n\nexport const ReadParamsSchema = v.object({\n path: v.pipe(v.string(), v.minLength(1, \"path must not be empty\")),\n offset: v.optional(\n v.pipe(v.number(), v.integer(), v.minValue(1, \"offset must be >= 1\")),\n ),\n limit: v.optional(\n v.pipe(v.number(), v.integer(), v.minValue(1, \"limit must be >= 1\")),\n ),\n});\n\nexport type ParsedReadParams = v.InferOutput<typeof ReadParamsSchema>;\n\nexport function parseReadParams(input: unknown): ParsedReadParams {\n return v.parse(ReadParamsSchema, input);\n}\n\nexport function safeParseReadParams(input: unknown):\n | { ok: true; value: ReadParams }\n | { ok: false; issues: v.BaseIssue<unknown>[] } {\n const result = v.safeParse(ReadParamsSchema, input);\n if (result.success) return { ok: true, value: result.output };\n return { ok: false, issues: result.issues };\n}\n\nexport const READ_TOOL_NAME = \"read\";\n\nexport const READ_TOOL_DESCRIPTION = `Read a file or directory from the local filesystem.\n\nUsage:\n- The path parameter should be an absolute path. If relative, it resolves against the session working directory.\n- By default, returns up to 2000 lines from the start of the file.\n- The offset parameter is the 1-indexed line number to start from.\n- For later sections, call this tool again with a larger offset.\n- Use the grep tool for content search in large files; glob to locate files by pattern.\n- Contents are returned with each line prefixed by its line number as \"<line>: <content>\".\n- Any line longer than 2000 characters is truncated.\n- Call this tool in parallel when reading multiple files.\n- Avoid tiny repeated slices (under 30 lines). Read a larger window instead.\n- Images and PDFs are returned as file attachments.\n- Binary files are refused; use specialized tools.`;\n\nexport const readToolDefinition: ToolDefinition = {\n name: READ_TOOL_NAME,\n description: READ_TOOL_DESCRIPTION,\n inputSchema: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description:\n \"Absolute path (preferred) or path relative to the session cwd.\",\n },\n offset: {\n type: \"integer\",\n minimum: 1,\n description: \"1-indexed line number to start reading from.\",\n },\n limit: {\n type: \"integer\",\n minimum: 1,\n description: \"Maximum number of lines to read. Defaults to 2000.\",\n },\n },\n required: [\"path\"],\n additionalProperties: false,\n },\n};\n","import path from \"node:path\";\nimport type { ReadOperations } from \"@agent-sh/harness-core\";\nimport { FUZZY_SUGGESTION_LIMIT } from \"./constants.js\";\n\nexport async function suggestSiblings(\n ops: ReadOperations,\n missingPath: string,\n): Promise<readonly string[]> {\n const dir = path.dirname(missingPath);\n const base = path.basename(missingPath).toLowerCase();\n let entries: readonly string[];\n try {\n entries = await ops.readDirectory(dir);\n } catch {\n return [];\n }\n const scored: { p: string; score: number }[] = [];\n for (const entry of entries) {\n const lower = entry.toLowerCase();\n const score = similarity(base, lower);\n if (score > 0) scored.push({ p: path.join(dir, entry), score });\n }\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, FUZZY_SUGGESTION_LIMIT).map((s) => s.p);\n}\n\nfunction similarity(a: string, b: string): number {\n if (a === b) return 1000;\n if (a.length === 0 || b.length === 0) return 0;\n if (a.includes(b) || b.includes(a)) return 500;\n const prefix = commonPrefix(a, b);\n if (prefix >= 3) return 200 + prefix;\n if (prefix >= 2 && Math.abs(a.length - b.length) <= 2) return 100 + prefix;\n const aExt = extOf(a);\n const bExt = extOf(b);\n if (aExt && aExt === bExt) return 10;\n return 0;\n}\n\nfunction commonPrefix(a: string, b: string): number {\n const n = Math.min(a.length, b.length);\n let i = 0;\n while (i < n && a[i] === b[i]) i++;\n return i;\n}\n\nfunction extOf(name: string): string {\n const dot = name.lastIndexOf(\".\");\n return dot > 0 ? name.slice(dot) : \"\";\n}\n","import { Buffer } from \"node:buffer\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n defaultNodeOperations,\n isInsideAnyRoot,\n matchesAnyPattern,\n toolError,\n withFileLock,\n type ReadOperations,\n type ToolError,\n} from \"@agent-sh/harness-core\";\nimport { isBinary, isImageMime, isPdfMime } from \"./binary.js\";\nimport {\n BINARY_SAMPLE_BYTES,\n DEFAULT_LIMIT,\n MAX_FILE_SIZE,\n} from \"./constants.js\";\nimport {\n formatAttachment,\n formatDirectory,\n formatText,\n} from \"./format.js\";\nimport { streamLinesFromBytes } from \"./lines.js\";\nimport { safeParseReadParams } from \"./schema.js\";\nimport { suggestSiblings } from \"./suggest.js\";\nimport type {\n AttachmentReadResult,\n DirReadResult,\n ErrorReadResult,\n ReadParams,\n ReadResult,\n ReadSessionConfig,\n TextReadResult,\n} from \"./types.js\";\n\nfunction err(error: ToolError): ErrorReadResult {\n return { kind: \"error\", error };\n}\n\nexport async function read(\n input: unknown,\n session: ReadSessionConfig,\n): Promise<ReadResult> {\n const parsed = safeParseReadParams(input);\n if (!parsed.ok) {\n const messages = parsed.issues.map((i) => i.message).join(\"; \");\n return err(toolError(\"INVALID_PARAM\", messages, { cause: parsed.issues }));\n }\n const params = parsed.value;\n\n const ops = session.ops ?? defaultNodeOperations();\n\n const resolvedPath = await resolvePath(ops, session.cwd, params.path);\n const fence = await fencePath(ops, session, resolvedPath);\n if (fence !== undefined) return err(fence);\n\n return withFileLock(resolvedPath, () =>\n executeRead(ops, session, resolvedPath, params),\n );\n}\n\nasync function resolvePath(\n ops: ReadOperations,\n cwd: string,\n input: string,\n): Promise<string> {\n const absolute = path.isAbsolute(input) ? input : path.resolve(cwd, input);\n try {\n return await ops.realpath(absolute);\n } catch {\n return absolute;\n }\n}\n\nasync function fencePath(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n): Promise<ToolError | undefined> {\n const { permissions } = session;\n\n const isSensitive = matchesAnyPattern(\n resolvedPath,\n permissions.sensitivePatterns,\n );\n const insideWorkspace = isInsideAnyRoot(resolvedPath, permissions.roots);\n const needsAsk =\n isSensitive ||\n (!insideWorkspace && permissions.bypassWorkspaceGuard !== true);\n\n if (isSensitive && permissions.hook === undefined) {\n return toolError(\n \"SENSITIVE\",\n `Refusing to read sensitive path: ${resolvedPath}`,\n { meta: { path: resolvedPath } },\n );\n }\n\n if (\n !insideWorkspace &&\n permissions.bypassWorkspaceGuard !== true &&\n permissions.hook === undefined\n ) {\n return toolError(\n \"OUTSIDE_WORKSPACE\",\n `Path is outside all configured workspace roots: ${resolvedPath}`,\n { meta: { path: resolvedPath, roots: permissions.roots } },\n );\n }\n\n if (permissions.hook !== undefined) {\n const reason = isSensitive\n ? \"sensitive\"\n : !insideWorkspace\n ? \"outside_workspace\"\n : \"in_workspace\";\n const alwaysPatterns = needsAsk\n ? [path.dirname(resolvedPath) + \"/*\"]\n : [\"*\"];\n const decision = await permissions.hook({\n tool: \"read\",\n path: resolvedPath,\n action: \"read\",\n always_patterns: alwaysPatterns,\n metadata: { reason },\n });\n if (decision === \"deny\") {\n return toolError(\n \"PERMISSION_DENIED\",\n `Read denied by user: ${resolvedPath}`,\n { meta: { path: resolvedPath } },\n );\n }\n }\n\n return undefined;\n}\n\nasync function executeRead(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n params: ReadParams,\n): Promise<ReadResult> {\n let stat;\n try {\n stat = await ops.stat(resolvedPath);\n } catch (e) {\n return err(\n toolError(\"IO_ERROR\", `stat failed: ${(e as Error).message}`, {\n cause: e,\n }),\n );\n }\n\n if (!stat) {\n const suggestions = await suggestSiblings(ops, resolvedPath);\n const msg =\n suggestions.length > 0\n ? `File not found: ${resolvedPath}\\n\\nDid you mean one of these?\\n${suggestions.join(\"\\n\")}`\n : `File not found: ${resolvedPath}`;\n return err(\n toolError(\"NOT_FOUND\", msg, { meta: { path: resolvedPath, suggestions } }),\n );\n }\n\n if (stat.type === \"directory\") {\n return readDirectory(ops, resolvedPath, params);\n }\n\n const maxSize = session.maxFileSize ?? MAX_FILE_SIZE;\n if (stat.size > maxSize) {\n return err(\n toolError(\n \"TOO_LARGE\",\n `File size ${stat.size} exceeds max ${maxSize}. Use a narrower offset/limit or grep first.`,\n { meta: { path: resolvedPath, size: stat.size, maxSize } },\n ),\n );\n }\n\n const half = session.modelContextTokens\n ? Math.floor(session.modelContextTokens / 2)\n : undefined;\n const tokensPerByte = session.tokensPerByte ?? 0.3;\n if (half !== undefined && stat.size * tokensPerByte > half) {\n return err(\n toolError(\n \"TOO_LARGE\",\n `File would consume more than half of the model context (~${Math.floor(stat.size * tokensPerByte)} tokens > ${half}). Use offset/limit or grep first.`,\n { meta: { path: resolvedPath, size: stat.size, half } },\n ),\n );\n }\n\n const mime = ops.mimeType(resolvedPath);\n if (isImageMime(mime) || isPdfMime(mime)) {\n return readAttachment(ops, resolvedPath, mime, stat.size);\n }\n\n const sample = await readSample(ops, resolvedPath, stat.size);\n if (isBinary(resolvedPath, sample)) {\n return err(\n toolError(\"BINARY\", `Cannot read binary file: ${resolvedPath}`, {\n meta: { path: resolvedPath },\n }),\n );\n }\n\n return readText(ops, session, resolvedPath, stat, params);\n}\n\nasync function readSample(\n ops: ReadOperations,\n p: string,\n size: number,\n): Promise<Uint8Array> {\n if (size === 0) return new Uint8Array();\n const bytes = await ops.readFile(p);\n return bytes.length > BINARY_SAMPLE_BYTES\n ? bytes.subarray(0, BINARY_SAMPLE_BYTES)\n : bytes;\n}\n\nasync function readDirectory(\n ops: ReadOperations,\n resolvedPath: string,\n params: ReadParams,\n): Promise<DirReadResult> {\n const entries = await ops.readDirectoryEntries(resolvedPath);\n const named = await Promise.all(\n entries.map(async (e) => {\n if (e.type === \"directory\") return e.name + \"/\";\n if (e.type !== \"symlink\") return e.name;\n const target = await ops\n .stat(path.join(resolvedPath, e.name))\n .catch(() => undefined);\n return target?.type === \"directory\" ? e.name + \"/\" : e.name;\n }),\n );\n named.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: \"base\" }));\n\n const offset = params.offset ?? 1;\n const limit = params.limit ?? DEFAULT_LIMIT;\n const start = offset - 1;\n const sliced = named.slice(start, start + limit);\n const more = start + sliced.length < named.length;\n\n const output = formatDirectory({\n path: resolvedPath,\n entries: sliced,\n offset,\n totalEntries: named.length,\n more,\n });\n\n return {\n kind: \"directory\",\n output,\n meta: {\n path: resolvedPath,\n totalEntries: named.length,\n returnedEntries: sliced.length,\n offset,\n limit,\n more,\n },\n };\n}\n\nasync function readAttachment(\n ops: ReadOperations,\n resolvedPath: string,\n mime: string,\n size: number,\n): Promise<AttachmentReadResult> {\n const bytes = await ops.readFile(resolvedPath);\n const kind: \"Image\" | \"PDF\" = mime === \"application/pdf\" ? \"PDF\" : \"Image\";\n const dataUrl = `data:${mime};base64,${Buffer.from(bytes).toString(\"base64\")}`;\n return {\n kind: \"attachment\",\n output: formatAttachment(kind),\n attachments: [{ mime, dataUrl }],\n meta: { path: resolvedPath, mime, size_bytes: size },\n };\n}\n\nasync function readText(\n ops: ReadOperations,\n session: ReadSessionConfig,\n resolvedPath: string,\n stat: { size: number; mtime_ms: number },\n params: ReadParams,\n): Promise<ReadResult> {\n const offset = params.offset ?? 1;\n const limit = params.limit ?? session.defaultLimit ?? DEFAULT_LIMIT;\n\n if (session.cache) {\n const cached = session.cache.get({\n path: resolvedPath,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n offset,\n limit,\n });\n if (cached) {\n if (session.ledger) {\n session.ledger.record({\n path: resolvedPath,\n sha256: cached.meta.sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n lines_returned: cached.meta.returnedLines,\n offset,\n limit,\n timestamp_ms: Date.now(),\n });\n }\n return cached;\n }\n }\n\n const bytes = await ops.readFile(resolvedPath);\n const sha256 = createHash(\"sha256\").update(bytes).digest(\"hex\");\n\n const lineStreamOpts: {\n offset: number;\n limit: number;\n maxBytes?: number;\n maxLineLength?: number;\n signal?: AbortSignal;\n } = { offset, limit };\n if (session.maxBytes !== undefined) lineStreamOpts.maxBytes = session.maxBytes;\n if (session.maxLineLength !== undefined)\n lineStreamOpts.maxLineLength = session.maxLineLength;\n if (session.signal !== undefined) lineStreamOpts.signal = session.signal;\n\n const result = await streamLinesFromBytes(bytes, lineStreamOpts);\n\n if (result.totalLines > 0 && offset > result.totalLines) {\n return err(\n toolError(\n \"INVALID_PARAM\",\n `Offset ${offset} is out of range for this file (${result.totalLines} lines)`,\n { meta: { path: resolvedPath, totalLines: result.totalLines } },\n ),\n );\n }\n\n const output = formatText({\n path: resolvedPath,\n offset,\n lines: result.lines,\n totalLines: result.totalLines,\n more: result.more,\n byteCap: result.byteCap,\n });\n\n const textResult: TextReadResult = {\n kind: \"text\",\n output,\n meta: {\n path: resolvedPath,\n totalLines: result.totalLines,\n returnedLines: result.lines.length,\n offset,\n limit,\n byteCap: result.byteCap,\n more: result.more,\n sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n },\n };\n\n if (session.cache) {\n session.cache.set(\n {\n path: resolvedPath,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n offset,\n limit,\n },\n textResult,\n );\n }\n\n if (session.ledger) {\n session.ledger.record({\n path: resolvedPath,\n sha256,\n mtime_ms: stat.mtime_ms,\n size_bytes: stat.size,\n lines_returned: result.lines.length,\n offset,\n limit,\n timestamp_ms: Date.now(),\n });\n }\n\n return textResult;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-sh/harness-read",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Read tool for AI agent harnesses — safe, bounded, line-numbered file reading with pluggable I/O, permissions, ledger, and cache",
5
5
  "keywords": [
6
6
  "ai",
@@ -44,7 +44,7 @@
44
44
  "node": ">=20"
45
45
  },
46
46
  "dependencies": {
47
- "valibot": "^0.42.1",
47
+ "valibot": "^1.2.0",
48
48
  "@agent-sh/harness-core": "0.2.0"
49
49
  },
50
50
  "devDependencies": {