@cue-dev/retrieval-core 0.1.3 → 0.1.5
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/.tsbuildinfo +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -69
- package/dist/indexing-ignore.d.ts +1 -0
- package/dist/indexing-ignore.js +10 -0
- package/dist/remote-sync.d.ts +2 -0
- package/dist/remote-sync.js +109 -15
- package/package.json +4 -4
- package/src/index.ts +6 -72
- package/src/indexing-ignore.ts +11 -0
- package/src/remote-sync.ts +126 -15
- package/test/claude-agent-provider.test.ts +3 -0
- package/test/remote-sync.integration.test.ts +119 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
1
|
+
import { mkdtemp, mkdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { afterEach, describe, expect, it } from "vitest";
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
RemoteSyncHttpResponseError,
|
|
7
7
|
buildRemoteSyncDeltaFromState,
|
|
8
8
|
collectProjectFileStats,
|
|
9
|
+
estimateRemoteSyncDeltaRequestSize,
|
|
9
10
|
runRemoteAdaptiveSync,
|
|
10
11
|
runRemoteDeltaSync,
|
|
11
12
|
type RemoteSyncStateFile
|
|
@@ -129,6 +130,29 @@ describe("runRemoteDeltaSync", () => {
|
|
|
129
130
|
expect(stats.get("src/legacy.cts")?.language).toBe("typescript");
|
|
130
131
|
});
|
|
131
132
|
|
|
133
|
+
it("skips symlinks that could escape project root", async () => {
|
|
134
|
+
const root = await createProject();
|
|
135
|
+
const outside = await mkdtemp(join(tmpdir(), "cue-remote-sync-outside-"));
|
|
136
|
+
tempDirs.push(outside);
|
|
137
|
+
await writeFile(join(outside, "secret.txt"), "top-secret\n");
|
|
138
|
+
await symlink(join(outside, "secret.txt"), join(root, "src", "secret-link.txt"));
|
|
139
|
+
|
|
140
|
+
const stats = await collectProjectFileStats(root);
|
|
141
|
+
expect(stats.has("src/secret-link.txt")).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("fails fast when scan exceeds max_files limit", async () => {
|
|
145
|
+
const root = await createProject();
|
|
146
|
+
await writeFile(join(root, "src", "a.ts"), "export const A = 1;\n");
|
|
147
|
+
await writeFile(join(root, "src", "b.ts"), "export const B = 1;\n");
|
|
148
|
+
|
|
149
|
+
await expect(
|
|
150
|
+
collectProjectFileStats(root, {
|
|
151
|
+
max_files: 1
|
|
152
|
+
})
|
|
153
|
+
).rejects.toThrow(/max_files/i);
|
|
154
|
+
});
|
|
155
|
+
|
|
132
156
|
it("applies add/modify/delete changes incrementally", async () => {
|
|
133
157
|
const root = await createProject();
|
|
134
158
|
await writeFile(join(root, "src", "a.ts"), "export const A = 1;\n");
|
|
@@ -228,6 +252,100 @@ describe("runRemoteDeltaSync", () => {
|
|
|
228
252
|
expect(result.index_version).toBe("idx-v1");
|
|
229
253
|
});
|
|
230
254
|
|
|
255
|
+
it("adapts delta batch size when upstream body limit is lower than advertised max_body_bytes", async () => {
|
|
256
|
+
const root = await createProject();
|
|
257
|
+
const fileCount = 220;
|
|
258
|
+
for (let index = 0; index < fileCount; index += 1) {
|
|
259
|
+
const suffix = String(index).padStart(3, "0");
|
|
260
|
+
await writeFile(join(root, "src", `body-limit-${suffix}.ts`), `export const VALUE_${suffix} = "${"x".repeat(7000)}";\n`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const ingressBodyLimitBytes = 1_000_000;
|
|
264
|
+
const payloadSizes: number[] = [];
|
|
265
|
+
let version = 0;
|
|
266
|
+
const result = await runRemoteDeltaSync({
|
|
267
|
+
project_root_path: root,
|
|
268
|
+
workspace_id: "ws-1",
|
|
269
|
+
max_body_bytes: 52_428_800,
|
|
270
|
+
retries: 1,
|
|
271
|
+
push_delta: async (request) => {
|
|
272
|
+
const payloadSize = estimateRemoteSyncDeltaRequestSize({
|
|
273
|
+
project_root_path: request.project_root_path,
|
|
274
|
+
workspace_id: request.workspace_id,
|
|
275
|
+
base_index_version: request.base_index_version,
|
|
276
|
+
upsert_files: request.upsert_files,
|
|
277
|
+
deleted_paths: request.deleted_paths
|
|
278
|
+
});
|
|
279
|
+
payloadSizes.push(payloadSize);
|
|
280
|
+
if (payloadSize > ingressBodyLimitBytes) {
|
|
281
|
+
throw new RemoteSyncHttpResponseError("Request Entity Too Large", 413);
|
|
282
|
+
}
|
|
283
|
+
version += 1;
|
|
284
|
+
return {
|
|
285
|
+
workspace_id: "ws-1",
|
|
286
|
+
index_version: `idx-v${version}`
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
expect(result.changed).toBe(true);
|
|
292
|
+
expect(result.applied_delta).toEqual({
|
|
293
|
+
upsert_files: fileCount,
|
|
294
|
+
deleted_paths: 0
|
|
295
|
+
});
|
|
296
|
+
expect(payloadSizes.some((size) => size > ingressBodyLimitBytes)).toBe(true);
|
|
297
|
+
const successfulPayloads = payloadSizes.filter((size) => size <= ingressBodyLimitBytes);
|
|
298
|
+
expect(successfulPayloads.length).toBeGreaterThan(0);
|
|
299
|
+
expect(Math.max(...successfulPayloads)).toBeLessThanOrEqual(ingressBodyLimitBytes);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("adapts delta batch size when upstream times out on oversized batches", async () => {
|
|
303
|
+
const root = await createProject();
|
|
304
|
+
const fileCount = 220;
|
|
305
|
+
for (let index = 0; index < fileCount; index += 1) {
|
|
306
|
+
const suffix = String(index).padStart(3, "0");
|
|
307
|
+
await writeFile(join(root, "src", `timeout-limit-${suffix}.ts`), `export const VALUE_${suffix} = "${"x".repeat(7000)}";\n`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const timeoutLimitBytes = 400_000;
|
|
311
|
+
const payloadSizes: number[] = [];
|
|
312
|
+
let version = 0;
|
|
313
|
+
const result = await runRemoteDeltaSync({
|
|
314
|
+
project_root_path: root,
|
|
315
|
+
workspace_id: "ws-1",
|
|
316
|
+
max_body_bytes: 52_428_800,
|
|
317
|
+
retries: 1,
|
|
318
|
+
push_delta: async (request) => {
|
|
319
|
+
const payloadSize = estimateRemoteSyncDeltaRequestSize({
|
|
320
|
+
project_root_path: request.project_root_path,
|
|
321
|
+
workspace_id: request.workspace_id,
|
|
322
|
+
base_index_version: request.base_index_version,
|
|
323
|
+
upsert_files: request.upsert_files,
|
|
324
|
+
deleted_paths: request.deleted_paths
|
|
325
|
+
});
|
|
326
|
+
payloadSizes.push(payloadSize);
|
|
327
|
+
if (payloadSize > timeoutLimitBytes) {
|
|
328
|
+
throw new RemoteSyncHttpResponseError("Gateway Time-out", 504);
|
|
329
|
+
}
|
|
330
|
+
version += 1;
|
|
331
|
+
return {
|
|
332
|
+
workspace_id: "ws-1",
|
|
333
|
+
index_version: `idx-timeout-v${version}`
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
expect(result.changed).toBe(true);
|
|
339
|
+
expect(result.applied_delta).toEqual({
|
|
340
|
+
upsert_files: fileCount,
|
|
341
|
+
deleted_paths: 0
|
|
342
|
+
});
|
|
343
|
+
expect(payloadSizes.some((size) => size > timeoutLimitBytes)).toBe(true);
|
|
344
|
+
const successfulPayloads = payloadSizes.filter((size) => size <= timeoutLimitBytes);
|
|
345
|
+
expect(successfulPayloads.length).toBeGreaterThan(0);
|
|
346
|
+
expect(Math.max(...successfulPayloads)).toBeLessThanOrEqual(timeoutLimitBytes);
|
|
347
|
+
});
|
|
348
|
+
|
|
231
349
|
it("retries once with full-upsert when base index is stale", async () => {
|
|
232
350
|
const root = await createProject();
|
|
233
351
|
await writeFile(join(root, "src", "retry.ts"), "export const RETRY = 1;\n");
|