@coderook/cli 0.42.3 → 0.42.4

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.
@@ -2,7 +2,7 @@
2
2
  "name": "coderook",
3
3
  "displayName": "CodeRook",
4
4
  "description": "Save, browse and restore whole-snapshot versions of a project on CodeRook, with cbx or plain git, from Claude Code.",
5
- "version": "0.42.3",
5
+ "version": "0.42.4",
6
6
  "author": {
7
7
  "name": "ACCA Gaming Productions",
8
8
  "url": "https://coderook.com"
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.MACHINE_OPERATIONS = void 0;
7
+ exports.readWhole = readWhole;
7
8
  exports.commandWorkspaceMachine = commandWorkspaceMachine;
8
9
  exports.commandMachines = commandMachines;
9
10
  /**
@@ -23,7 +24,7 @@ exports.commandMachines = commandMachines;
23
24
  * it, and its record lives in .coderook/workspace.json. Edits go in as the
24
25
  * draft's own changes, each checked against the copy this folder last had,
25
26
  * so somebody else's edit to the same file in the meantime is refused rather
26
- * than overwritten. Text only, 256 KiB a file, as the draft itself allows.
27
+ * than overwritten. Text only, 1 MiB a file, as the draft itself allows.
27
28
  */
28
29
  const node_crypto_1 = require("node:crypto");
29
30
  const node_fs_1 = require("node:fs");
@@ -36,8 +37,29 @@ const config_js_1 = require("./config.js");
36
37
  const machine_js_1 = require("./machine.js");
37
38
  const colour_js_1 = require("./colour.js");
38
39
  const RECORD = node_path_1.default.join(".coderook", "workspace.json");
39
- const MAX_FILE = 256 * 1024;
40
- const MAX_BATCH = 900 * 1024;
40
+ /* The draft's own limit per text file (backend remote_workspaces.ts MAX_EDIT_BYTES). */
41
+ const MAX_FILE = 1024 * 1024;
42
+ /*
43
+ One request to the draft may be 2 MiB. Batches are measured as the JSON that
44
+ is sent, since escaping makes content larger than its bytes on disk, and kept
45
+ well under the cap.
46
+ */
47
+ const MAX_REQUEST = 2 * 1024 * 1024;
48
+ const MAX_BATCH = 1536 * 1024;
49
+ const encodedSize = (change) => Buffer.byteLength(JSON.stringify(change));
50
+ /** One draft text file in full, from the line-paged read (2,000 lines a request). */
51
+ async function readWhole(draft, filePath, read = (route) => (0, api_js_1.callApi)(route)) {
52
+ const lines = [];
53
+ for (let start = 1;;) {
54
+ const page = await read(`${draft}/files?path=${encodeURIComponent(filePath)}&startLine=${start}&lines=2000`);
55
+ const got = page.content.split("\n");
56
+ lines.push(...got);
57
+ if (!page.truncated)
58
+ break;
59
+ start += got.length;
60
+ }
61
+ return lines.join("\n");
62
+ }
41
63
  function flag(parsed, ...names) {
42
64
  for (const name of names) {
43
65
  const value = parsed.flags.get(name);
@@ -149,6 +171,14 @@ async function checkout(found, draft, workspaceId, into) {
149
171
  delete manifest[change.path];
150
172
  }
151
173
  else {
174
+ /*
175
+ A diff page carries at most 4 MiB of content; a text file past that
176
+ budget comes with only its digest, and is read on its own, a page of
177
+ lines at a time.
178
+ */
179
+ if (change.after.content === null && change.after.reason?.startsWith("page byte limit")) {
180
+ change.after.content = await readWhole(draft, change.path);
181
+ }
152
182
  if (change.after.content === null) {
153
183
  throw new Error(`The draft's copy of ${change.path} could not be read as text (${change.after.reason ?? "unreadable"}).`);
154
184
  }
@@ -199,10 +229,16 @@ async function push(parsed, where) {
199
229
  refused.push(file.path);
200
230
  continue;
201
231
  }
202
- changes.push({ path: file.path, content: bytes.toString("utf8"), expectedSha256: record.files[file.path] ?? null });
232
+ const change = { path: file.path, content: bytes.toString("utf8"), expectedSha256: record.files[file.path] ?? null };
233
+ /* Under 1 MiB but so full of escapes that it cannot travel in one request. */
234
+ if (encodedSize(change) > MAX_REQUEST - 64 * 1024) {
235
+ refused.push(file.path);
236
+ continue;
237
+ }
238
+ changes.push(change);
203
239
  }
204
240
  if (refused.length) {
205
- console.error((0, colour_js_1.red)(`${refused.length} file${refused.length === 1 ? " is" : "s are"} binary or over 256 KiB, which a draft cannot take:`));
241
+ console.error((0, colour_js_1.red)(`${refused.length} file${refused.length === 1 ? " is" : "s are"} binary or over 1 MiB, which a draft cannot take:`));
206
242
  for (const one of refused.slice(0, 20))
207
243
  console.error(` ${one}`);
208
244
  console.error((0, colour_js_1.dim)("Nothing was sent. Leave them out, or save them with a normal upload from a linked folder."));
@@ -225,7 +261,7 @@ async function push(parsed, where) {
225
261
  let bytes = 0;
226
262
  while (start < changes.length) {
227
263
  const next = changes[start];
228
- const size = next.content ? Buffer.byteLength(next.content) : 0;
264
+ const size = encodedSize(next);
229
265
  if (batch.length && bytes + size > MAX_BATCH)
230
266
  break;
231
267
  batch.push(next);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coderook/cli",
3
- "version": "0.42.3",
3
+ "version": "0.42.4",
4
4
  "description": "The command line for CodeRook (coderook.com): version control and project hosting for projects of any size. Every save is a compressed snapshot, private or public, never used to train AI.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://coderook.com",