@proagentstore/cli 0.4.76 → 0.4.77

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.
@@ -159,8 +159,15 @@ export class InspectError extends Error {
159
159
  }
160
160
  const DEFAULT_MAX_FILE_BYTES = 64 * 1024;
161
161
  const HARD_MAX_FILE_BYTES = 128 * 1024;
162
- /** Read a text file inside the repo. Rejects traversal, oversize, and binary files. */
163
- export function readRepoFile(workDir, relPath, maxBytes) {
162
+ /**
163
+ * Read a text file inside the repo. Rejects traversal and binary files; returns at most `maxBytes`.
164
+ *
165
+ * Ranged from #954: `startLine`/`startColumn` say where the returned bytes begin, so no part of a file
166
+ * is out of reach — before it, a read always began at byte 0 and nothing past the cap could be read.
167
+ * `firstLine`/`firstColumn`/`totalLines` are always present, which is how the cloud tells a runner that
168
+ * honours the range from an older one that silently started at the top.
169
+ */
170
+ export function readRepoFile(workDir, relPath, maxBytes, from = {}) {
164
171
  const abs = resolveInside(workDir, relPath, { checkSymlink: true });
165
172
  const st = statSync(abs);
166
173
  if (!st.isFile())
@@ -171,8 +178,31 @@ export function readRepoFile(workDir, relPath, maxBytes) {
171
178
  const head = buf.subarray(0, 8192);
172
179
  if (head.includes(0))
173
180
  return { path: relPath, size: st.size, truncated: false, binary: true };
174
- const truncated = buf.length > cap;
175
- return { path: relPath, size: st.size, truncated, content: buf.subarray(0, cap).toString("utf-8") };
181
+ let newlines = 0;
182
+ for (let i = buf.indexOf(10); i !== -1; i = buf.indexOf(10, i + 1))
183
+ newlines++;
184
+ const totalLines = newlines + (buf.length > 0 && buf[buf.length - 1] !== 10 ? 1 : 0);
185
+ const firstLine = Math.max(1, Math.trunc(Number(from.startLine) || 1));
186
+ const firstColumn = Math.max(1, Math.trunc(Number(from.startColumn) || 1));
187
+ const ranged = { firstLine, firstColumn, totalLines };
188
+ if (firstLine > totalLines)
189
+ return { path: relPath, size: st.size, truncated: false, content: "", ...ranged };
190
+ // The byte where line `firstLine` begins…
191
+ let start = 0;
192
+ for (let line = 1; line < firstLine; line++)
193
+ start = buf.indexOf(10, start) + 1;
194
+ // …and, for a column past the first, where that CHARACTER begins — counted on the decoded line, so
195
+ // a multi-byte character is never split.
196
+ if (firstColumn > 1) {
197
+ const eol = buf.indexOf(10, start);
198
+ const lineText = buf.subarray(start, eol === -1 ? buf.length : eol).toString("utf-8");
199
+ start += Buffer.byteLength(lineText.slice(0, firstColumn - 1), "utf-8");
200
+ }
201
+ let end = Math.min(buf.length, start + cap);
202
+ // Never end inside a multi-byte character: it would decode as U+FFFD at the cut.
203
+ while (end < buf.length && end > start && (buf[end] & 0xc0) === 0x80)
204
+ end--;
205
+ return { path: relPath, size: st.size, truncated: end < buf.length, content: buf.subarray(start, end).toString("utf-8"), ...ranged };
176
206
  }
177
207
  /** Run a whitelisted read-only git command in the repo. Never uses a shell. */
178
208
  export function runRepoGit(workDir, cmd, opts = {}) {
@@ -53,7 +53,7 @@ export class CodingRuntime {
53
53
  }
54
54
  /** Read one file inside the session's repo (traversal-guarded, size-capped). */
55
55
  readFile(input) {
56
- return readRepoFile(this.resolveWorkDir(input), input.path, input.maxBytes);
56
+ return readRepoFile(this.resolveWorkDir(input), input.path, input.maxBytes, { startLine: input.startLine, startColumn: input.startColumn });
57
57
  }
58
58
  /** Run a whitelisted read-only git command in the session's repo. */
59
59
  git(input) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proagentstore/cli",
3
- "version": "0.4.76",
3
+ "version": "0.4.77",
4
4
  "description": "CLI for creating, publishing, and running ProAgentStore agents",
5
5
  "license": "MIT",
6
6
  "type": "module",