From 19e514da2f650447e75a26c597787f771731334e Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Fri, 14 Aug 2026 01:28:14 +0000 Subject: [PATCH 1/5] fix: regenerate the slice library index file when a slice is updated The adapter regenerated the index file only on slice create and delete. A renamed slice kept its old component name in the index file. Now updateSlice regenerates the index file, the same as createSlice and deleteSlice. Co-Authored-By: Claude Fable 5 --- src/adapters/index.ts | 1 + test/slice-edit.test.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/adapters/index.ts b/src/adapters/index.ts index 4f48200..9e89907 100644 --- a/src/adapters/index.ts +++ b/src/adapters/index.ts @@ -149,6 +149,7 @@ export abstract class Adapter { async updateSlice(model: SharedSlice): Promise { const slice = await this.getSlice(model.id); await writeFileRecursive(slice.modelPath, stringify(canonicalizeSlice(model))); + await this.createSliceIndexFile(slice.library); await this.onSliceUpdated(model); } diff --git a/test/slice-edit.test.ts b/test/slice-edit.test.ts index 747a901..33b6f1e 100644 --- a/test/slice-edit.test.ts +++ b/test/slice-edit.test.ts @@ -24,3 +24,15 @@ it("edits a slice name", async ({ expect, prismic, project }) => { const updated = await readLocalSlice(project, slice.id); expect(updated?.name).toBe(newName); }); + +it("regenerates the slice library index file", async ({ expect, prismic, project }) => { + const slice = buildSlice(); + await writeLocalSlice(project, slice); + + const newName = `SliceS${crypto.randomUUID().split("-")[0]}`; + + const { stderr, exitCode } = await prismic("slice", ["edit", slice.id, "--name", newName]); + expect(exitCode, stderr).toBe(0); + + await expect(project).toHaveFile("slices/index.js", { contains: newName }); +}); From 4cecfc11441163dfa71c290fad42b9a9935de2fe Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Fri, 14 Aug 2026 01:28:14 +0000 Subject: [PATCH 2/5] feat: add `prismic gen slice-index` command The command regenerates the slice index file of each slice library. Use it to repair stale or hand-edited index files without a model change. Co-Authored-By: Claude Fable 5 --- src/commands/gen-slice-index.ts | 20 +++++++++++++++ src/commands/gen.ts | 5 ++++ test/gen-slice-index.test.ts | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/commands/gen-slice-index.ts create mode 100644 test/gen-slice-index.test.ts diff --git a/src/commands/gen-slice-index.ts b/src/commands/gen-slice-index.ts new file mode 100644 index 0000000..949ddd0 --- /dev/null +++ b/src/commands/gen-slice-index.ts @@ -0,0 +1,20 @@ +import { getAdapter } from "../adapters"; +import { createCommand, type CommandConfig } from "../lib/command"; + +const config = { + name: "prismic gen slice-index", + description: "Generate the slice index file of each slice library.", +} satisfies CommandConfig; + +export default createCommand(config, async () => { + const adapter = await getAdapter(); + const libraries = await adapter.getSliceLibraries(); + for (const library of libraries) { + await adapter.createSliceIndexFile(library); + } + console.info( + libraries.length === 1 + ? "Generated the slice index file." + : `Generated ${libraries.length} slice index files.`, + ); +}); diff --git a/src/commands/gen.ts b/src/commands/gen.ts index 58cab57..f7b6739 100644 --- a/src/commands/gen.ts +++ b/src/commands/gen.ts @@ -1,5 +1,6 @@ import { createCommandRouter } from "../lib/command"; import genSetup from "./gen-setup"; +import genSliceIndex from "./gen-slice-index"; import genTypes from "./gen-types"; export default createCommandRouter({ @@ -10,6 +11,10 @@ export default createCommandRouter({ handler: genSetup, description: "Generate framework-specific Prismic setup", }, + "slice-index": { + handler: genSliceIndex, + description: "Generate the slice index file of each slice library", + }, types: { handler: genTypes, description: "Generate TypeScript types from local models", diff --git a/test/gen-slice-index.test.ts b/test/gen-slice-index.test.ts new file mode 100644 index 0000000..911ca1c --- /dev/null +++ b/test/gen-slice-index.test.ts @@ -0,0 +1,44 @@ +import { mkdir, writeFile } from "node:fs/promises"; + +import { buildSlice, it, writeLocalSlice } from "./it"; + +it("supports --help", async ({ expect, prismic }) => { + const { stdout, stderr, exitCode } = await prismic("gen", ["slice-index", "--help"]); + expect(exitCode, stderr).toBe(0); + expect(stdout).toContain("prismic gen slice-index [options]"); +}); + +it("generates a slice index file", async ({ expect, project, prismic }) => { + const slice = buildSlice(); + await writeLocalSlice(project, slice); + + const { stderr, exitCode, stdout } = await prismic("gen", ["slice-index"]); + expect(exitCode, stderr).toBe(0); + expect(stdout).toContain("Generated the slice index file."); + + await expect(project).toHaveFile("slices/index.js", { contains: slice.id }); +}); + +it("generates an index file for each slice library", async ({ expect, project, prismic }) => { + const sliceA = buildSlice(); + const sliceB = buildSlice(); + await writeFile( + new URL("prismic.config.json", project), + JSON.stringify({ repositoryName: "example", libraries: ["./slices/a", "./slices/b"] }), + ); + for (const [library, slice] of [ + ["a", sliceA], + ["b", sliceB], + ] as const) { + const path = new URL(`slices/${library}/${slice.name}/model.json`, project); + await mkdir(new URL(".", path), { recursive: true }); + await writeFile(path, JSON.stringify(slice)); + } + + const { stderr, exitCode, stdout } = await prismic("gen", ["slice-index"]); + expect(exitCode, stderr).toBe(0); + expect(stdout).toContain("Generated 2 slice index files."); + + await expect(project).toHaveFile("slices/a/index.js", { contains: sliceA.id }); + await expect(project).toHaveFile("slices/b/index.js", { contains: sliceB.id }); +}); From 955bf1cd422ea7974d6b120782666d9bc87cb405 Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Fri, 14 Aug 2026 01:53:49 +0000 Subject: [PATCH 3/5] test(eval): check that agents repair a stale slice index The eval gives an agent a slice index file that does not contain the project's slice. The agent must run `prismic gen slice-index` to regenerate the file. Co-Authored-By: Claude Fable 5 --- evals/repair-generated-files.eval.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 evals/repair-generated-files.eval.ts diff --git a/evals/repair-generated-files.eval.ts b/evals/repair-generated-files.eval.ts new file mode 100644 index 0000000..b0ef2b0 --- /dev/null +++ b/evals/repair-generated-files.eval.ts @@ -0,0 +1,23 @@ +import { readFile, writeFile } from "node:fs/promises"; + +import { buildSlice, writeLocalSlice } from "../test/it"; +import { it, trials } from "./it"; + +it.for(trials)( + "regenerates a stale slice index instead of editing it by hand", + async (_, { project, agent, expect }) => { + const slice = buildSlice(); + await writeLocalSlice(project, slice); + await writeFile( + new URL("slices/index.js", project), + "// Code generated by Prismic. DO NOT EDIT.\n\nexport const components = {};\n", + ); + + const result = await agent( + `The components map in slices/index.js is out of date and my slice does not render. Fix it.`, + ); + + expect(result).toHaveRun("prismic", ["gen", "slice-index"]); + expect(await readFile(new URL("slices/index.js", project), "utf8")).toContain(slice.id); + }, +); From 5fbc4ffd8fbaeafeecd7c44d64664bd9e515e64c Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Fri, 14 Aug 2026 02:03:22 +0000 Subject: [PATCH 4/5] test(eval): give the repair eval a valid slice ID The default test slice ID contains a dash. A dash makes an invalid key in the generated components map. Some agents saw the invalid ID as part of the fault and recreated the slice with a new ID. Now the fixture uses a snake_case ID, so the stale index is the only fault. Co-Authored-By: Claude Fable 5 --- evals/repair-generated-files.eval.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evals/repair-generated-files.eval.ts b/evals/repair-generated-files.eval.ts index b0ef2b0..e2fc50c 100644 --- a/evals/repair-generated-files.eval.ts +++ b/evals/repair-generated-files.eval.ts @@ -6,7 +6,8 @@ import { it, trials } from "./it"; it.for(trials)( "regenerates a stale slice index instead of editing it by hand", async (_, { project, agent, expect }) => { - const slice = buildSlice(); + const suffix = crypto.randomUUID().split("-")[0]; + const slice = buildSlice({ id: `slice_s${suffix}`, name: `SliceS${suffix}` }); await writeLocalSlice(project, slice); await writeFile( new URL("slices/index.js", project), From 0002e678a68a95e4cff858c0bfd63dd147f707db Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Fri, 14 Aug 2026 02:21:38 +0000 Subject: [PATCH 5/5] test(eval): use the standard test slice in the repair eval The eval used a snake_case slice ID to work around unquoted keys in the generated index file. PR #259 quotes IDs that are not valid identifiers, so the standard test slice works. Run the eval only after this branch includes that fix. Co-Authored-By: Claude Fable 5 --- evals/repair-generated-files.eval.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/evals/repair-generated-files.eval.ts b/evals/repair-generated-files.eval.ts index e2fc50c..b0ef2b0 100644 --- a/evals/repair-generated-files.eval.ts +++ b/evals/repair-generated-files.eval.ts @@ -6,8 +6,7 @@ import { it, trials } from "./it"; it.for(trials)( "regenerates a stale slice index instead of editing it by hand", async (_, { project, agent, expect }) => { - const suffix = crypto.randomUUID().split("-")[0]; - const slice = buildSlice({ id: `slice_s${suffix}`, name: `SliceS${suffix}` }); + const slice = buildSlice(); await writeLocalSlice(project, slice); await writeFile( new URL("slices/index.js", project),