@arnilo/prism-coding-agent 0.0.5 → 0.0.6

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/truncate.js CHANGED
@@ -9,8 +9,8 @@
9
9
  *
10
10
  * Never returns partial lines (except the documented tail single-line edge case).
11
11
  */
12
- export const DEFAULT_MAX_LINES = 2000;
13
- export const DEFAULT_MAX_BYTES = 50 * 1024; // 50KB
12
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, HARD_MAX_BYTES, HARD_MAX_LINES, validateCodingLimit, } from "./limits.js";
13
+ export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from "./limits.js";
14
14
  /**
15
15
  * Default char cap for {@link truncateLine}. pi names this GREP_MAX_LINE_LENGTH
16
16
  * because grep is its only caller; grep is out of scope for this package, so the
@@ -41,8 +41,8 @@ export function formatSize(bytes) {
41
41
  * returns empty content with firstLineExceedsLimit=true.
42
42
  */
43
43
  export function truncateHead(content, options = {}) {
44
- const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
45
- const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
44
+ const maxLines = validateCodingLimit("maxLines", options.maxLines ?? DEFAULT_MAX_LINES, HARD_MAX_LINES);
45
+ const maxBytes = validateCodingLimit("maxBytes", options.maxBytes ?? DEFAULT_MAX_BYTES, HARD_MAX_BYTES);
46
46
  const totalBytes = Buffer.byteLength(content, "utf-8");
47
47
  const lines = splitLinesForCounting(content);
48
48
  const totalLines = lines.length;
@@ -118,8 +118,8 @@ export function truncateHead(content, options = {}) {
118
118
  * the byte limit.
119
119
  */
120
120
  export function truncateTail(content, options = {}) {
121
- const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
122
- const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
121
+ const maxLines = validateCodingLimit("maxLines", options.maxLines ?? DEFAULT_MAX_LINES, HARD_MAX_LINES);
122
+ const maxBytes = validateCodingLimit("maxBytes", options.maxBytes ?? DEFAULT_MAX_BYTES, HARD_MAX_BYTES);
123
123
  const totalBytes = Buffer.byteLength(content, "utf-8");
124
124
  const lines = splitLinesForCounting(content);
125
125
  const totalLines = lines.length;
package/dist/write.d.ts CHANGED
@@ -5,14 +5,21 @@ import type { ExecutionPolicy, ToolDefinition } from "@arnilo/prism";
5
5
  */
6
6
  export interface WriteOperations {
7
7
  /** Write content to a file (creating or overwriting). */
8
- writeFile: (absolutePath: string, content: string) => Promise<void>;
8
+ writeFile: (absolutePath: string, content: string, options?: {
9
+ maxBytes: number;
10
+ signal?: AbortSignal;
11
+ }) => Promise<void>;
9
12
  /** Create a directory recursively. */
10
- mkdir: (dir: string) => Promise<void>;
13
+ mkdir: (dir: string, options?: {
14
+ signal?: AbortSignal;
15
+ }) => Promise<void>;
11
16
  }
12
17
  export interface WriteToolOptions {
13
18
  /** Structured pre-execution policy checked before filesystem writes. */
14
19
  executionPolicy?: ExecutionPolicy;
15
20
  /** Custom operations backend (default: local filesystem). */
16
21
  operations?: WriteOperations;
22
+ /** Maximum UTF-8 input bytes accepted before any filesystem mutation (default 8 MiB). */
23
+ maxInputBytes?: number;
17
24
  }
18
25
  export declare function createWriteTool(cwd: string, options?: WriteToolOptions): ToolDefinition;
package/dist/write.js CHANGED
@@ -20,8 +20,9 @@ import { dirname } from "node:path";
20
20
  import { enforceExecutionPolicy } from "./execution-policy.js";
21
21
  import { resolveToCwd } from "./path-utils.js";
22
22
  import { withFileMutationQueue } from "./file-mutation-queue.js";
23
+ import { DEFAULT_MAX_WRITE_BYTES, HARD_MAX_WRITE_BYTES, validateCodingLimit, } from "./limits.js";
23
24
  const defaultWriteOperations = {
24
- writeFile: (path, content) => fsWriteFile(path, content, "utf-8"),
25
+ writeFile: (path, content, options) => fsWriteFile(path, content, { encoding: "utf-8", signal: options?.signal }),
25
26
  mkdir: (dir) => fsMkdir(dir, { recursive: true }).then(() => { }),
26
27
  };
27
28
  function errorResult(toolCallId, message) {
@@ -39,6 +40,7 @@ function countLines(content) {
39
40
  }
40
41
  export function createWriteTool(cwd, options) {
41
42
  const ops = options?.operations ?? defaultWriteOperations;
43
+ const maxInputBytes = validateCodingLimit("maxInputBytes", options?.maxInputBytes ?? DEFAULT_MAX_WRITE_BYTES, HARD_MAX_WRITE_BYTES);
42
44
  return {
43
45
  name: "write",
44
46
  description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
@@ -61,6 +63,10 @@ export function createWriteTool(cwd, options) {
61
63
  if (content === undefined) {
62
64
  return errorResult(toolCallId, "content is required and must be a string.");
63
65
  }
66
+ const bytes = Buffer.byteLength(content, "utf-8");
67
+ if (bytes > maxInputBytes) {
68
+ return errorResult(toolCallId, `Write input is ${bytes} bytes, exceeds ${maxInputBytes} byte limit.`);
69
+ }
64
70
  try {
65
71
  const absolutePath = resolveToCwd(path, cwd);
66
72
  const policyCheck = await enforceExecutionPolicy(options?.executionPolicy, {
@@ -68,7 +74,7 @@ export function createWriteTool(cwd, options) {
68
74
  operation: "write",
69
75
  paths: [absolutePath],
70
76
  risk: "medium",
71
- metadata: { bytes: Buffer.byteLength(content, "utf-8"), sessionId: context.sessionId, runId: context.runId, signal: context.signal },
77
+ metadata: { bytes, sessionId: context.sessionId, runId: context.runId, signal: context.signal },
72
78
  }, toolCallId, "write");
73
79
  if (!policyCheck.allowed)
74
80
  return policyCheck.result;
@@ -79,11 +85,10 @@ export function createWriteTool(cwd, options) {
79
85
  // do NOT throw from an abort listener: that could release the mutation queue mid-operation.
80
86
  if (context.signal?.aborted)
81
87
  return errorResult(toolCallId, "Operation aborted");
82
- await ops.mkdir(dir);
88
+ await ops.mkdir(dir, { signal: context.signal });
83
89
  if (context.signal?.aborted)
84
90
  return errorResult(toolCallId, "Operation aborted");
85
- await ops.writeFile(allowedPath, content);
86
- const bytes = Buffer.byteLength(content, "utf-8");
91
+ await ops.writeFile(allowedPath, content, { maxBytes: maxInputBytes, signal: context.signal });
87
92
  const lines = countLines(content);
88
93
  return {
89
94
  toolCallId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism-coding-agent",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Optional coding-agent tools (shell, read, write, edit) package for Prism.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,7 +28,7 @@
28
28
  "diff": "^8.0.4"
29
29
  },
30
30
  "peerDependencies": {
31
- "@arnilo/prism": "0.0.5"
31
+ "@arnilo/prism": "0.0.6"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@arnilo/prism": "file:../.."