Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/signals/focus-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,15 @@ function normalizeStringList(value: JsonValue | undefined, field: string, warnin
}
const trimmed = entry.trim();
if (!trimmed) continue;
if (trimmed.length > MAX_ITEM_LENGTH) {
// Truncate in place, then flow through the same de-dup and cap logic. Falling through (rather than
// `continue`-ing) keeps over-long entries subject to both limits, so untrusted manifests cannot
// bypass de-duplication or the MAX_LIST_ITEMS safety cap via pathological long entries.
let normalized = trimmed;
if (normalized.length > MAX_ITEM_LENGTH) {
warnings.push(`Manifest field "${field}" truncated an over-long entry.`);
result.push(trimmed.slice(0, MAX_ITEM_LENGTH));
continue;
normalized = normalized.slice(0, MAX_ITEM_LENGTH);
}
if (!result.includes(trimmed)) result.push(trimmed);
if (!result.includes(normalized)) result.push(normalized);
if (result.length >= MAX_LIST_ITEMS) {
warnings.push(`Manifest field "${field}" exceeded ${MAX_LIST_ITEMS} entries; extra entries ignored.`);
break;
Expand Down
14 changes: 14 additions & 0 deletions test/unit/focus-manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ describe("parseFocusManifest", () => {
expect(manifest.wantedPaths).toEqual(["src/", "lib/"]);
});

it("de-duplicates over-long entries after truncation", () => {
const prefix = "a".repeat(300);
const manifest = parseFocusManifest({ wantedPaths: [`${prefix}X`, `${prefix}Y`] });
expect(manifest.wantedPaths).toEqual([prefix]);
expect(manifest.warnings.join(" ")).toMatch(/truncated an over-long entry/);
});

it("applies the list cap to over-long entries", () => {
const overLong = Array.from({ length: 250 }, (_, index) => `path-${index}-${"x".repeat(300)}`);
const manifest = parseFocusManifest({ wantedPaths: overLong });
expect(manifest.wantedPaths.length).toBe(200);
expect(manifest.warnings.join(" ")).toMatch(/exceeded 200 entries/);
});

it("marks a manifest with no recognized fields as absent", () => {
const manifest = parseFocusManifest({ unrelated: "value" });
expect(manifest.present).toBe(false);
Expand Down