@decocms/blocks-cli 7.5.1 → 7.5.3

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.
Files changed (43) hide show
  1. package/package.json +2 -2
  2. package/scripts/generate-invoke.ts +10 -0
  3. package/scripts/generate-schema.ts +46 -15
  4. package/scripts/generate-sections.test.ts +67 -0
  5. package/scripts/generate-sections.ts +16 -2
  6. package/scripts/lib/codegenExclusions.test.ts +16 -6
  7. package/scripts/lib/codegenExclusions.ts +13 -1
  8. package/scripts/migrate/analyzers/loader-inventory.ts +1 -1
  9. package/scripts/migrate/phase-analyze.ts +3 -3
  10. package/scripts/migrate/phase-cleanup.test.ts +70 -1
  11. package/scripts/migrate/phase-cleanup.ts +47 -26
  12. package/scripts/migrate/phase-report.ts +7 -7
  13. package/scripts/migrate/phase-scaffold.ts +4 -4
  14. package/scripts/migrate/phase-transform.ts +1 -1
  15. package/scripts/migrate/phase-verify.ts +6 -5
  16. package/scripts/migrate/post-cleanup/rules.ts +55 -44
  17. package/scripts/migrate/post-cleanup/runner.test.ts +58 -34
  18. package/scripts/migrate/templates/cache-config.ts +4 -4
  19. package/scripts/migrate/templates/commerce-loaders.ts +10 -10
  20. package/scripts/migrate/templates/cursor-rules.test.ts +6 -0
  21. package/scripts/migrate/templates/cursor-rules.ts +12 -11
  22. package/scripts/migrate/templates/hooks.test.ts +7 -7
  23. package/scripts/migrate/templates/hooks.ts +10 -10
  24. package/scripts/migrate/templates/lib-utils.test.ts +2 -2
  25. package/scripts/migrate/templates/lib-utils.ts +4 -4
  26. package/scripts/migrate/templates/no-legacy-packages.test.ts +147 -0
  27. package/scripts/migrate/templates/package-json.ts +30 -10
  28. package/scripts/migrate/templates/routes.ts +8 -10
  29. package/scripts/migrate/templates/sdk-gen.ts +1 -1
  30. package/scripts/migrate/templates/section-loaders.ts +7 -7
  31. package/scripts/migrate/templates/server-entry.ts +37 -37
  32. package/scripts/migrate/templates/setup.ts +6 -6
  33. package/scripts/migrate/templates/types-gen.ts +2 -2
  34. package/scripts/migrate/templates/ui-components.ts +2 -2
  35. package/scripts/migrate/templates/vite-config.ts +12 -3
  36. package/scripts/migrate/transforms/fresh-apis.ts +5 -5
  37. package/scripts/migrate/transforms/imports.test.ts +138 -0
  38. package/scripts/migrate/transforms/imports.ts +65 -43
  39. package/scripts/migrate/transforms/jsx.ts +8 -0
  40. package/scripts/migrate/transforms/section-conventions.ts +1 -1
  41. package/scripts/migrate/types.ts +1 -1
  42. package/scripts/migrate-post-cleanup.ts +8 -8
  43. package/scripts/migrate.ts +11 -11
@@ -242,10 +242,10 @@ describe("rule: dead-runtime-shim", () => {
242
242
 
243
243
  it("does NOT flag the Wave 15-A canonical re-export shape", () => {
244
244
  // The migration template now scaffolds a thin re-export from
245
- // @decocms/start/sdk plus a Runtime alias. No inline proxy body.
245
+ // @decocms/blocks/sdk/invoke plus a Runtime alias. No inline proxy body.
246
246
  const fs = makeFs({
247
247
  "/site/src/runtime.ts":
248
- 'import { invoke } from "@decocms/start/sdk";\nexport { invoke };\nexport const Runtime = { invoke };\n',
248
+ 'import { invoke } from "@decocms/blocks/sdk/invoke";\nexport { invoke };\nexport const Runtime = { invoke };\n',
249
249
  });
250
250
  const report = runAudit(SITE, fs);
251
251
  const r = report.rules.find((r) => r.rule === "dead-runtime-shim")!;
@@ -330,7 +330,7 @@ describe("rule: site-local-with-globals", () => {
330
330
  it("does not flag a re-export from the framework", () => {
331
331
  const fs = makeFs({
332
332
  "/site/src/server/routes/withSiteGlobals.ts":
333
- 'export { withSiteGlobals } from "@decocms/start/routes";\n',
333
+ 'export { withSiteGlobals } from "@decocms/tanstack";\n',
334
334
  });
335
335
  const report = runAudit(SITE, fs);
336
336
  const r = report.rules.find((r) => r.rule === "site-local-with-globals")!;
@@ -492,12 +492,12 @@ describe("rule: vtex-shim-regression — per-symbol fix hints", () => {
492
492
  const r = report.rules.find((r) => r.rule === "vtex-shim-regression")!;
493
493
  expect(r.findings).toHaveLength(1);
494
494
  const f = r.findings[0];
495
- expect(f.fix).toContain("toProduct → @decocms/apps/vtex/utils/transform");
495
+ expect(f.fix).toContain("toProduct → @decocms/apps-vtex/utils/transform");
496
496
  expect(f.fix).toContain("1:1 import swap");
497
497
  expect(f.meta?.fixHints).toEqual({
498
498
  toProduct: {
499
499
  kind: "swap",
500
- canonical: "@decocms/apps/vtex/utils/transform",
500
+ canonical: "@decocms/apps-vtex/utils/transform",
501
501
  note: expect.stringContaining("canonical signature"),
502
502
  },
503
503
  });
@@ -537,7 +537,7 @@ describe("rule: vtex-shim-regression — per-symbol fix hints", () => {
537
537
  const r = report.rules.find((r) => r.rule === "vtex-shim-regression")!;
538
538
  const f = r.findings[0];
539
539
  expect(f.fix).toContain("getSegmentFromBag → call-site refactor");
540
- expect(f.fix).toContain("toProduct → @decocms/apps/vtex/utils/transform");
540
+ expect(f.fix).toContain("toProduct → @decocms/apps-vtex/utils/transform");
541
541
  // Joined with " | " for visual separation.
542
542
  expect(f.fix).toContain(" | ");
543
543
  expect(Object.keys(f.meta?.fixHints as object)).toEqual(
@@ -555,7 +555,7 @@ describe("rule: vtex-shim-regression — per-symbol fix hints", () => {
555
555
  const report = runAudit(SITE, fs);
556
556
  const r = report.rules.find((r) => r.rule === "vtex-shim-regression")!;
557
557
  const f = r.findings[0];
558
- expect(f.fix).toContain("unknownStub → repoint to '@decocms/apps/vtex/...");
558
+ expect(f.fix).toContain("unknownStub → repoint to '@decocms/apps-vtex/...");
559
559
  // No fixHints in meta when no symbols match the table.
560
560
  expect(f.meta?.fixHints).toBeUndefined();
561
561
  });
@@ -573,7 +573,7 @@ describe("rule: vtex-shim-regression — per-symbol fix hints", () => {
573
573
  const report = runAudit(SITE, fs);
574
574
  const r = report.rules.find((r) => r.rule === "vtex-shim-regression")!;
575
575
  const f = r.findings[0];
576
- expect(f.fix).toContain("toProduct → @decocms/apps/vtex/utils/transform");
576
+ expect(f.fix).toContain("toProduct → @decocms/apps-vtex/utils/transform");
577
577
  expect(f.fix).toContain("unknownStub → repoint");
578
578
  // Only the known symbol shows up in fixHints.
579
579
  expect(f.meta?.fixHints).toEqual({
@@ -665,6 +665,30 @@ export default createDecoWorkerEntry(serverEntry, {
665
665
  expect(r.findings).toEqual([]);
666
666
  });
667
667
 
668
+ it("recognizes the current @decocms/apps-vtex package name (post-7.x split)", () => {
669
+ // Sites migrated with the current scaffolder emit `@decocms/apps-vtex`,
670
+ // not the retired `@decocms/apps/vtex` monolith path. Both the isVtex
671
+ // signal and the proxy-import detection must recognize the new form.
672
+ const currentWorkerEntry = `
673
+ import { createDecoWorkerEntry } from "@decocms/tanstack";
674
+ import { shouldProxyToVtex, createVtexCheckoutProxy } from "@decocms/apps-vtex/utils/proxy";
675
+ const proxy = createVtexCheckoutProxy({ account: "x", checkoutOrigin: "x.vtexcommercestable.com.br" });
676
+ export default createDecoWorkerEntry(serverEntry, {
677
+ proxyHandler: async (req, url) => {
678
+ if (!shouldProxyToVtex(url.pathname)) return null;
679
+ return proxy(req, url);
680
+ },
681
+ });
682
+ `;
683
+ const fs = makeFs({
684
+ "/site/src/commerceLoaders.ts": 'import {} from "@decocms/apps-vtex/mod";',
685
+ "/site/src/worker-entry.ts": currentWorkerEntry,
686
+ });
687
+ const report = runAudit(SITE, fs);
688
+ const r = report.rules.find((r) => r.rule === "vtex-proxy-handler-missing")!;
689
+ expect(r.findings).toEqual([]);
690
+ });
691
+
668
692
  it("flags VTEX site missing src/worker-entry.ts entirely", () => {
669
693
  const fs = makeFs({
670
694
  "/site/src/commerceLoaders.ts": "import {} from \"@decocms/apps/vtex/mod\";",
@@ -687,7 +711,7 @@ export default createDecoWorkerEntry(serverEntry, { admin: {} });
687
711
  const report = runAudit(SITE, fs);
688
712
  const r = report.rules.find((r) => r.rule === "vtex-proxy-handler-missing")!;
689
713
  expect(r.findings).toHaveLength(1);
690
- expect(r.findings[0].message).toContain("no `@decocms/apps/vtex/utils/proxy` import");
714
+ expect(r.findings[0].message).toContain("no `@decocms/apps-vtex/utils/proxy` import");
691
715
  });
692
716
 
693
717
  it("does not flag VTEX site using object-shorthand proxyHandler wiring", () => {
@@ -821,8 +845,8 @@ describe("runAudit — fix mode", () => {
821
845
  expect(r.fixes).toHaveLength(1);
822
846
  expect(r.fixes![0].detail).toMatch(/rewrote 2 import/);
823
847
  expect("/site/src/runtime.ts" in store).toBe(false);
824
- expect(store["/site/src/sections/A.tsx"]).toContain('"@decocms/start/sdk"');
825
- expect(store["/site/src/sections/B.tsx"]).toContain("'@decocms/start/sdk'");
848
+ expect(store["/site/src/sections/A.tsx"]).toContain('"@decocms/blocks/sdk/invoke"');
849
+ expect(store["/site/src/sections/B.tsx"]).toContain("'@decocms/blocks/sdk/invoke'");
826
850
  expect(store["/site/src/sections/C.tsx"]).toContain('"~/something-else"');
827
851
  expect(log.filter((e) => e.kind === "delete")).toHaveLength(1);
828
852
  expect(log.filter((e) => e.kind === "write")).toHaveLength(2);
@@ -841,8 +865,8 @@ describe("runAudit — fix mode", () => {
841
865
  expect(r.fixes).toHaveLength(1);
842
866
  expect(r.fixes![0].detail).toMatch(/rewrote 2 import/);
843
867
  expect("/site/src/types/widgets.ts" in store).toBe(false);
844
- expect(store["/site/src/sections/A.tsx"]).toContain('"@decocms/start/types/widgets"');
845
- expect(store["/site/src/sections/B.tsx"]).toContain("'@decocms/start/types/widgets'");
868
+ expect(store["/site/src/sections/A.tsx"]).toContain('"@decocms/blocks/types/widgets"');
869
+ expect(store["/site/src/sections/B.tsx"]).toContain("'@decocms/blocks/types/widgets'");
846
870
  });
847
871
 
848
872
  it("fix mode is a no-op for rules without applyFix (e.g. framework-todos)", () => {
@@ -865,7 +889,7 @@ describe("runAudit — fix mode", () => {
865
889
  'import type { ImageWidget } from "~/types/widgets";\nimport thing from "~/types/widgets-extra";\n',
866
890
  });
867
891
  runAudit(SITE, fs, { writer });
868
- expect(store["/site/src/sections/A.tsx"]).toContain('"@decocms/start/types/widgets"');
892
+ expect(store["/site/src/sections/A.tsx"]).toContain('"@decocms/blocks/types/widgets"');
869
893
  expect(store["/site/src/sections/A.tsx"]).toContain('"~/types/widgets-extra"');
870
894
  });
871
895
  });
@@ -887,10 +911,10 @@ describe("runAudit — fix mode — vtex-shim-regression swap cases", () => {
887
911
  expect(r.fixes).toHaveLength(1);
888
912
  expect(r.fixes![0].file).toBe("src/loaders/search.ts");
889
913
  expect(r.fixes![0].kind).toBe("rewrite-imports");
890
- expect(r.fixes![0].detail).toContain("@decocms/apps/vtex/utils/transform");
914
+ expect(r.fixes![0].detail).toContain("@decocms/apps-vtex/utils/transform");
891
915
  expect(r.fixes![0].detail).toContain("toProduct");
892
916
  expect(store["/site/src/loaders/search.ts"]).toContain(
893
- '"@decocms/apps/vtex/utils/transform"',
917
+ '"@decocms/apps-vtex/utils/transform"',
894
918
  );
895
919
  expect(store["/site/src/loaders/search.ts"]).not.toContain('"~/lib/vtex-transform"');
896
920
  });
@@ -907,9 +931,9 @@ describe("runAudit — fix mode — vtex-shim-regression swap cases", () => {
907
931
  const report = runAudit(SITE, fs, { writer });
908
932
  const r = report.rules.find((r) => r.rule === "vtex-shim-regression")!;
909
933
  expect(r.fixes).toHaveLength(1);
910
- expect(r.fixes![0].detail).toContain("@decocms/apps/vtex/utils/segment");
934
+ expect(r.fixes![0].detail).toContain("@decocms/apps-vtex/utils/segment");
911
935
  expect(store["/site/src/loaders/x.ts"]).toContain(
912
- '"@decocms/apps/vtex/utils/segment"',
936
+ '"@decocms/apps-vtex/utils/segment"',
913
937
  );
914
938
  });
915
939
 
@@ -964,10 +988,10 @@ describe("runAudit — fix mode — vtex-shim-regression swap cases", () => {
964
988
  const r = report.rules.find((r) => r.rule === "vtex-shim-regression")!;
965
989
  expect(r.fixes!.length).toBe(2);
966
990
  expect(store["/site/src/loaders/A.ts"]).toContain(
967
- '"@decocms/apps/vtex/utils/transform"',
991
+ '"@decocms/apps-vtex/utils/transform"',
968
992
  );
969
993
  expect(store["/site/src/loaders/B.ts"]).toContain(
970
- "'@decocms/apps/vtex/utils/transform'",
994
+ "'@decocms/apps-vtex/utils/transform'",
971
995
  );
972
996
  });
973
997
 
@@ -983,7 +1007,7 @@ describe("runAudit — fix mode — vtex-shim-regression swap cases", () => {
983
1007
  });
984
1008
  runAudit(SITE, fs, { writer });
985
1009
  expect(store["/site/src/loaders/x.ts"]).toContain(
986
- 'import { toProduct as toP } from "@decocms/apps/vtex/utils/transform"',
1010
+ 'import { toProduct as toP } from "@decocms/apps-vtex/utils/transform"',
987
1011
  );
988
1012
  });
989
1013
  });
@@ -1296,7 +1320,7 @@ describe("rule: local-framework-duplicate", () => {
1296
1320
  expect(r.findings[0].message).toContain("pure dup");
1297
1321
  expect(r.findings[0].meta?.id).toBe("clx");
1298
1322
  expect(r.findings[0].meta?.safeToAutoFix).toBe(true);
1299
- expect(r.findings[0].meta?.canonicalImport).toBe("@decocms/start/sdk/clx");
1323
+ expect(r.findings[0].meta?.canonicalImport).toBe("@decocms/blocks/sdk/clx");
1300
1324
  });
1301
1325
 
1302
1326
  it("flags src/sdk/clx.ts when site adds a clsx alias (signature still matches)", () => {
@@ -1328,7 +1352,7 @@ describe("rule: local-framework-duplicate", () => {
1328
1352
  it("flags src/sdk/useSendEvent.ts as warn-only (typing regression risk)", () => {
1329
1353
  const fs = makeFs({
1330
1354
  "/site/src/sdk/useSendEvent.ts":
1331
- 'import { AnalyticsEvent } from "@decocms/apps/commerce/types";\n' +
1355
+ 'import { AnalyticsEvent } from "@decocms/apps-commerce/types";\n' +
1332
1356
  "export const useSendEvent = <E extends AnalyticsEvent>(\n" +
1333
1357
  " { event, on }: { event: E; on: 'click' | 'view' | 'change' },\n" +
1334
1358
  ") => ({\n" +
@@ -1367,7 +1391,7 @@ describe("rule: local-framework-duplicate", () => {
1367
1391
  expect(r.findings[0].meta?.id).toBe("url-relative");
1368
1392
  expect(r.findings[0].meta?.safeToAutoFix).toBe(false);
1369
1393
  expect(r.findings[0].meta?.canonicalImport).toBe(
1370
- "@decocms/apps/commerce/sdk/url",
1394
+ "@decocms/apps-commerce/sdk/url",
1371
1395
  );
1372
1396
  expect(r.findings[0].fix).toContain("stripSearchParams");
1373
1397
  });
@@ -1393,7 +1417,7 @@ describe("rule: local-framework-duplicate", () => {
1393
1417
  expect(r.findings[0].meta?.id).toBe("use-suggestions");
1394
1418
  expect(r.findings[0].meta?.safeToAutoFix).toBe(false);
1395
1419
  expect(r.findings[0].meta?.canonicalImport).toBe(
1396
- "@decocms/start/sdk/useSuggestions",
1420
+ "@decocms/blocks/sdk/useSuggestions",
1397
1421
  );
1398
1422
  expect(r.findings[0].fix).toContain("createUseSuggestions");
1399
1423
  });
@@ -1404,7 +1428,7 @@ describe("rule: local-framework-duplicate", () => {
1404
1428
  // strings. The rule's signature must NOT fire on the shim.
1405
1429
  const fs = makeFs({
1406
1430
  "/site/src/sdk/useSuggestions.ts":
1407
- 'import { createUseSuggestions } from "@decocms/start/sdk/useSuggestions";\n' +
1431
+ 'import { createUseSuggestions } from "@decocms/blocks/sdk/useSuggestions";\n' +
1408
1432
  'import * as Sentry from "@sentry/react";\n' +
1409
1433
  "export const { useSuggestions } = createUseSuggestions({\n" +
1410
1434
  " onError: (err) => Sentry.captureException(err),\n" +
@@ -1437,7 +1461,7 @@ describe("rule: local-framework-duplicate", () => {
1437
1461
  it("flags src/matchers/location.ts as warn-only (behaviour-superset opportunity)", () => {
1438
1462
  const fs = makeFs({
1439
1463
  "/site/src/matchers/location.ts":
1440
- 'import { registerMatcher } from "@decocms/start/cms";\n' +
1464
+ 'import { registerMatcher } from "@decocms/blocks/cms";\n' +
1441
1465
  "export function registerLocationMatcher(): void {\n" +
1442
1466
  ' registerMatcher("website/matchers/location.ts", (rule, ctx) => {\n' +
1443
1467
  " const cookies = ctx.cookies ?? {};\n" +
@@ -1457,7 +1481,7 @@ describe("rule: local-framework-duplicate", () => {
1457
1481
  it("emits zero findings on a clean tree (no duplicates present)", () => {
1458
1482
  const fs = makeFs({
1459
1483
  "/site/src/sections/Hello.tsx":
1460
- 'import { clx } from "@decocms/start/sdk/clx";\nexport default () => <div className={clx("a")}>x</div>;\n',
1484
+ 'import { clx } from "@decocms/blocks/sdk/clx";\nexport default () => <div className={clx("a")}>x</div>;\n',
1461
1485
  });
1462
1486
  const report = runAudit(SITE, fs);
1463
1487
  const r = report.rules.find((r) => r.rule === "local-framework-duplicate")!;
@@ -1485,7 +1509,7 @@ describe("rule: local-framework-duplicate", () => {
1485
1509
  "/site/src/components/B.tsx":
1486
1510
  'import { clx } from "~/sdk/clx";\nimport React from "react";\nexport default () => clx("y");\n',
1487
1511
  "/site/src/components/Unrelated.tsx":
1488
- 'import { clx } from "@decocms/start/sdk/clx";\nexport default () => clx("z");\n',
1512
+ 'import { clx } from "@decocms/blocks/sdk/clx";\nexport default () => clx("z");\n',
1489
1513
  });
1490
1514
  const report = runAudit(SITE, fs, { writer });
1491
1515
  const r = report.rules.find((r) => r.rule === "local-framework-duplicate")!;
@@ -1497,14 +1521,14 @@ describe("rule: local-framework-duplicate", () => {
1497
1521
  expect(store["/site/src/sdk/clx.ts"]).toBeUndefined();
1498
1522
  // Importers rewritten
1499
1523
  expect(store["/site/src/components/A.tsx"]).toContain(
1500
- 'from "@decocms/start/sdk/clx"',
1524
+ 'from "@decocms/blocks/sdk/clx"',
1501
1525
  );
1502
1526
  expect(store["/site/src/components/B.tsx"]).toContain(
1503
- 'from "@decocms/start/sdk/clx"',
1527
+ 'from "@decocms/blocks/sdk/clx"',
1504
1528
  );
1505
1529
  // Already-canonical import untouched
1506
1530
  expect(store["/site/src/components/Unrelated.tsx"]).toContain(
1507
- 'from "@decocms/start/sdk/clx"',
1531
+ 'from "@decocms/blocks/sdk/clx"',
1508
1532
  );
1509
1533
  expect(store["/site/src/components/Unrelated.tsx"]).not.toMatch(/~\/sdk\/clx/);
1510
1534
  });
@@ -1512,12 +1536,12 @@ describe("rule: local-framework-duplicate", () => {
1512
1536
  it("auto-fix is a no-op for warn-only entries (does NOT delete partial-overlap files)", () => {
1513
1537
  const { fs, writer, store } = makeMutableFs({
1514
1538
  "/site/src/sdk/useSendEvent.ts":
1515
- 'import { AnalyticsEvent } from "@decocms/apps/commerce/types";\n' +
1539
+ 'import { AnalyticsEvent } from "@decocms/apps-commerce/types";\n' +
1516
1540
  "export const useSendEvent = <E extends AnalyticsEvent>() => ({\n" +
1517
1541
  ' "data-event": encodeURIComponent("x"),\n' +
1518
1542
  "});\n",
1519
1543
  "/site/src/matchers/location.ts":
1520
- 'import { registerMatcher } from "@decocms/start/cms";\n' +
1544
+ 'import { registerMatcher } from "@decocms/blocks/cms";\n' +
1521
1545
  'registerMatcher("website/matchers/location.ts", () => Boolean(__cf_geo_country));\n',
1522
1546
  });
1523
1547
  const report = runAudit(SITE, fs, { writer });
@@ -4,18 +4,18 @@ export function generateCacheConfig(ctx: MigrationContext): string {
4
4
  if (ctx.platform !== "vtex") {
5
5
  return `/**
6
6
  * Cache configuration — customize edge cache profiles per route type.
7
- * See @decocms/start/sdk/cacheHeaders for available profiles.
7
+ * See @decocms/blocks/sdk/cacheHeaders for available profiles.
8
8
  */
9
- // import { setCacheProfile } from "@decocms/start/sdk/cacheHeaders";
9
+ // import { setCacheProfile } from "@decocms/blocks/sdk/cacheHeaders";
10
10
  // setCacheProfile("product", { sMaxAge: 300, staleWhileRevalidate: 600 });
11
11
  `;
12
12
  }
13
13
 
14
14
  return `/**
15
15
  * Cache configuration for VTEX storefront.
16
- * Overrides default cache profiles from @decocms/start/sdk/cacheHeaders.
16
+ * Overrides default cache profiles from @decocms/blocks/sdk/cacheHeaders.
17
17
  */
18
- // import { setCacheProfile } from "@decocms/start/sdk/cacheHeaders";
18
+ // import { setCacheProfile } from "@decocms/blocks/sdk/cacheHeaders";
19
19
 
20
20
  // Uncomment and adjust as needed:
21
21
  // setCacheProfile("product", { sMaxAge: 300, staleWhileRevalidate: 600 });
@@ -37,15 +37,15 @@ export function generateCommerceLoaders(ctx: MigrationContext): string {
37
37
  lines.push(` */`);
38
38
 
39
39
  if (ctx.platform === "vtex") {
40
- lines.push(`import { getVtexConfig } from "@decocms/apps/vtex";`);
41
- lines.push(`import { createVtexCommerceLoaders, createCachedPDPLoader } from "@decocms/apps/vtex/commerceLoaders";`);
40
+ lines.push(`import { getVtexConfig } from "@decocms/apps-vtex";`);
41
+ lines.push(`import { createVtexCommerceLoaders, createCachedPDPLoader } from "@decocms/apps-vtex/commerceLoaders";`);
42
42
  if (hasAutocomplete) {
43
- lines.push(`import { autocompleteSearch } from "@decocms/apps/vtex/loaders/autocomplete";`);
43
+ lines.push(`import { autocompleteSearch } from "@decocms/apps-vtex/loaders/autocomplete";`);
44
44
  }
45
- lines.push(`import { getAddressByPostalCode } from "@decocms/apps/vtex/loaders/address";`);
46
- lines.push(`import { createAddressFromRequest, updateAddressFromRequest, deleteAddressFromRequest } from "@decocms/apps/vtex/actions/address";`);
47
- lines.push(`import { updateProfileFromRequest, newsletterProfileFromRequest, deletePaymentFromRequest, getPasswordLastUpdate } from "@decocms/apps/vtex/actions/profile";`);
48
- lines.push(`import { createCachedLoader } from "@decocms/start/sdk/cachedLoader";`);
45
+ lines.push(`import { getAddressByPostalCode } from "@decocms/apps-vtex/loaders/address";`);
46
+ lines.push(`import { createAddressFromRequest, updateAddressFromRequest, deleteAddressFromRequest } from "@decocms/apps-vtex/actions/address";`);
47
+ lines.push(`import { updateProfileFromRequest, newsletterProfileFromRequest, deletePaymentFromRequest, getPasswordLastUpdate } from "@decocms/apps-vtex/actions/profile";`);
48
+ lines.push(`import { createCachedLoader } from "@decocms/blocks/sdk/cachedLoader";`);
49
49
 
50
50
  if (hasVtexAuth) {
51
51
  lines.push(`import vtexAuthLoader from "../loaders/vtex-auth-loader";`);
@@ -92,7 +92,7 @@ export function generateCommerceLoaders(ctx: MigrationContext): string {
92
92
 
93
93
  // Autocomplete aliases
94
94
  if (hasAutocomplete) {
95
- lines.push(` // Autocomplete search — from @decocms/apps`);
95
+ lines.push(` // Autocomplete search — from @decocms/apps-vtex`);
96
96
  lines.push(` "site/loaders/search/intelligenseSearch.ts": cachedAutocomplete,`);
97
97
  lines.push(` "site/loaders/search/intelligenseSearch": cachedAutocomplete,`);
98
98
  lines.push(``);
@@ -109,7 +109,7 @@ export function generateCommerceLoaders(ctx: MigrationContext): string {
109
109
  }
110
110
 
111
111
  // VTEX address CRUD
112
- lines.push(` // VTEX address CRUD — request-aware wrappers from @decocms/apps`);
112
+ lines.push(` // VTEX address CRUD — request-aware wrappers from @decocms/apps-vtex`);
113
113
  lines.push(` "vtex/actions/address/createAddress": createAddressFromRequest as any,`);
114
114
  lines.push(` "vtex/actions/address/updateAddress": updateAddressFromRequest as any,`);
115
115
  lines.push(` "vtex/actions/address/deleteAddress": deleteAddressFromRequest as any,`);
@@ -215,7 +215,7 @@ export function generateCommerceLoaders(ctx: MigrationContext): string {
215
215
 
216
216
  lines.push(``);
217
217
  // Profile actions
218
- lines.push(` // Profile actions — request-aware wrappers from @decocms/apps`);
218
+ lines.push(` // Profile actions — request-aware wrappers from @decocms/apps-vtex`);
219
219
  lines.push(` "vtex/actions/profile/updateProfile": updateProfileFromRequest as any,`);
220
220
  lines.push(` "vtex/actions/profile/updateProfile.ts": updateProfileFromRequest as any,`);
221
221
  lines.push(` "vtex/actions/profile/newsletterProfile": newsletterProfileFromRequest as any,`);
@@ -43,6 +43,12 @@ describe("generateMigrationPolicyPointerRule", () => {
43
43
  expect(body.length).toBeLessThan(3000);
44
44
  });
45
45
 
46
+ it("does not emit the pre-split @decocms/start or @decocms/apps package names", () => {
47
+ expect(body).not.toContain("@decocms/start");
48
+ expect(body).not.toContain("@decocms/apps\`");
49
+ expect(body).toContain("@decocms/blocks-cli");
50
+ });
51
+
46
52
  it("is deterministic — same site name, same output", () => {
47
53
  const a = generateMigrationPolicyPointerRule("foo");
48
54
  const b = generateMigrationPolicyPointerRule("foo");
@@ -26,10 +26,11 @@ alwaysApply: true
26
26
 
27
27
  # Migration Tooling Policy — Pointer
28
28
 
29
- > This site (\`${siteName}\`) was generated by the \`@decocms/start\`
30
- > migration script. The canonical policy that governs how the migration
31
- > tooling, framework (\`@decocms/start\`), and commerce layer
32
- > (\`@decocms/apps\`) evolve lives **upstream**, not in this repo.
29
+ > This site (\`${siteName}\`) was generated by the \`@decocms/blocks-cli\`
30
+ > migration script (\`deco-migrate\`). The canonical policy that governs how
31
+ > the migration tooling, framework (\`@decocms/blocks\` + \`@decocms/tanstack\`),
32
+ > and commerce layer (\`@decocms/apps-*\`) evolve lives **upstream**, not in
33
+ > this repo.
33
34
 
34
35
  ## Where to read
35
36
 
@@ -38,24 +39,24 @@ alwaysApply: true
38
39
  - **Plan (living tracker, decisions + waves):**
39
40
  https://github.com/decocms/deco-start/blob/main/MIGRATION_TOOLING_PLAN.md
40
41
  - **Migration skill (phase playbook):**
41
- \`@decocms/start/.agents/skills/deco-to-tanstack-migration\`
42
+ https://github.com/decocms/deco-start/blob/main/.agents/skills/deco-to-tanstack-migration/SKILL.md
42
43
 
43
44
  ## What you need to know in this site
44
45
 
45
46
  | ID | Decision | What it means here |
46
47
  |----|----------|--------------------|
47
- | **D1** | Force convergence — no fork runtime support | Site customisations live in \`src/apps/local/\` or open a PR to \`@decocms/apps\`. Don't wrap framework/commerce code in soft adapters. |
48
+ | **D1** | Force convergence — no fork runtime support | Site customisations live in \`src/apps/local/\` or open a PR to \`@decocms/apps-*\`. Don't wrap framework/commerce code in soft adapters. |
48
49
  | **D2** | Rewrite HTMX on migration | If you find HTMX residue, rewrite to React. Don't bring back \`hx-*\` runtime. |
49
- | **D3** | Generated stubs throw at runtime | If a \`~/lib/vtex-*\` import comes from a stub that returns \`null\` / \`{}\` / identity-cast, replace it. \`npx -p @decocms/start deco-post-cleanup --fix\` does the safe swaps automatically. |
50
- | **D4** | Site-local apps by default, promote at 3+ sites | Don't try to upstream a pattern that has only shipped here. Build it twice in different sites first, then PR it to \`@decocms/apps\`. |
50
+ | **D3** | Generated stubs throw at runtime | If a \`~/lib/vtex-*\` import comes from a stub that returns \`null\` / \`{}\` / identity-cast, replace it. \`npx -p @decocms/blocks-cli deco-post-cleanup --fix\` does the safe swaps automatically. |
51
+ | **D4** | Site-local apps by default, promote at 3+ sites | Don't try to upstream a pattern that has only shipped here. Build it twice in different sites first, then PR it to \`@decocms/apps-*\`. |
51
52
  | **D5** | Failed migrations: \`rm -rf\` and re-run | No restart-mode magic. If the migration goes sideways, blow away the working tree and run again. |
52
53
 
53
54
  ## How to find issues this rule wants you to fix
54
55
 
55
56
  \`\`\`bash
56
- npx -p @decocms/start deco-post-cleanup # audit only
57
- npx -p @decocms/start deco-post-cleanup --fix # auto-fix the safe rules
58
- npx -p @decocms/start deco-post-cleanup --strict # exit 1 on any finding (CI)
57
+ npx -p @decocms/blocks-cli deco-post-cleanup # audit only
58
+ npx -p @decocms/blocks-cli deco-post-cleanup --fix # auto-fix the safe rules
59
+ npx -p @decocms/blocks-cli deco-post-cleanup --strict # exit 1 on any finding (CI)
59
60
  \`\`\`
60
61
 
61
62
  ## Process
@@ -44,12 +44,12 @@ describe("generateHooks (vtex)", () => {
44
44
  const code = files["src/hooks/useCart.ts"];
45
45
  // Imports from the framework factory.
46
46
  expect(code).toContain(
47
- 'import { createUseCart } from "@decocms/apps/vtex/hooks/createUseCart"',
47
+ 'import { createUseCart } from "@decocms/apps-vtex/hooks/createUseCart"',
48
48
  );
49
49
  expect(code).toContain('import { invoke } from "~/server/invoke"');
50
- // Re-exports types from @decocms/apps directly.
50
+ // Re-exports types from @decocms/apps-vtex directly.
51
51
  expect(code).toContain(
52
- 'export type { OrderForm, OrderFormItem } from "@decocms/apps/vtex/types"',
52
+ 'export type { OrderForm, OrderFormItem } from "@decocms/apps-vtex/types"',
53
53
  );
54
54
  // Calls the factory with invoke and destructures the public API.
55
55
  expect(code).toContain(
@@ -70,11 +70,11 @@ describe("generateHooks (vtex)", () => {
70
70
  it("useUser is the createUseUser factory shim (no signal-stub boilerplate)", () => {
71
71
  const code = files["src/hooks/useUser.ts"];
72
72
  expect(code).toContain(
73
- 'import { createUseUser } from "@decocms/apps/vtex/hooks/createUseUser"',
73
+ 'import { createUseUser } from "@decocms/apps-vtex/hooks/createUseUser"',
74
74
  );
75
75
  expect(code).toContain('import { invoke } from "~/server/invoke"');
76
76
  expect(code).toContain(
77
- 'export type { Person } from "@decocms/apps/vtex/loaders/user"',
77
+ 'export type { Person } from "@decocms/apps-vtex/loaders/user"',
78
78
  );
79
79
  expect(code).toContain("export const { useUser, resetUser } = createUseUser");
80
80
  // Must NOT scaffold the legacy signal stub.
@@ -85,11 +85,11 @@ describe("generateHooks (vtex)", () => {
85
85
  it("useWishlist is the createUseWishlist factory shim", () => {
86
86
  const code = files["src/hooks/useWishlist.ts"];
87
87
  expect(code).toContain(
88
- 'import { createUseWishlist } from "@decocms/apps/vtex/hooks/createUseWishlist"',
88
+ 'import { createUseWishlist } from "@decocms/apps-vtex/hooks/createUseWishlist"',
89
89
  );
90
90
  expect(code).toContain('import { invoke } from "~/server/invoke"');
91
91
  expect(code).toContain(
92
- 'export type { WishlistItem } from "@decocms/apps/vtex/loaders/wishlist"',
92
+ 'export type { WishlistItem } from "@decocms/apps-vtex/loaders/wishlist"',
93
93
  );
94
94
  expect(code).toContain(
95
95
  "export const { useWishlist, resetWishlist } = createUseWishlist",
@@ -19,11 +19,11 @@ export function generateHooks(ctx: MigrationContext): Record<string, string> {
19
19
  function generateVtexUseCart(): string {
20
20
  // The legacy invoke-based useCart hook is now a 5-line factory call —
21
21
  // the heavy lifting (singleton state, listener pattern, async actions,
22
- // analytics helpers) lives in @decocms/apps/vtex/hooks/createUseCart.
23
- return `import { createUseCart } from "@decocms/apps/vtex/hooks/createUseCart";
22
+ // analytics helpers) lives in @decocms/apps-vtex/hooks/createUseCart.
23
+ return `import { createUseCart } from "@decocms/apps-vtex/hooks/createUseCart";
24
24
  import { invoke } from "~/server/invoke";
25
25
 
26
- export type { OrderForm, OrderFormItem } from "@decocms/apps/vtex/types";
26
+ export type { OrderForm, OrderFormItem } from "@decocms/apps-vtex/types";
27
27
 
28
28
  export const { useCart, resetCart, itemToAnalyticsItem } = createUseCart({
29
29
  invoke,
@@ -70,22 +70,22 @@ export default useCart;
70
70
  // VTEX path — these are five-line factory shims. The heavy lifting
71
71
  // (singleton state, listener pattern, async actions, signal-shaped
72
72
  // accessors, legacy arg-swap conventions) lives in
73
- // @decocms/apps/vtex/hooks/createUseUser and createUseWishlist.
73
+ // @decocms/apps-vtex/hooks/createUseUser and createUseWishlist.
74
74
  function generateVtexUseUser(): string {
75
- return `import { createUseUser } from "@decocms/apps/vtex/hooks/createUseUser";
75
+ return `import { createUseUser } from "@decocms/apps-vtex/hooks/createUseUser";
76
76
  import { invoke } from "~/server/invoke";
77
77
 
78
- export type { Person } from "@decocms/apps/vtex/loaders/user";
78
+ export type { Person } from "@decocms/apps-vtex/loaders/user";
79
79
 
80
80
  export const { useUser, resetUser } = createUseUser({ invoke });
81
81
  `;
82
82
  }
83
83
 
84
84
  function generateVtexUseWishlist(): string {
85
- return `import { createUseWishlist } from "@decocms/apps/vtex/hooks/createUseWishlist";
85
+ return `import { createUseWishlist } from "@decocms/apps-vtex/hooks/createUseWishlist";
86
86
  import { invoke } from "~/server/invoke";
87
87
 
88
- export type { WishlistItem } from "@decocms/apps/vtex/loaders/wishlist";
88
+ export type { WishlistItem } from "@decocms/apps-vtex/loaders/wishlist";
89
89
 
90
90
  export const { useWishlist, resetWishlist } = createUseWishlist({ invoke });
91
91
  `;
@@ -98,7 +98,7 @@ function generateGenericUseUser(): string {
98
98
  return `/**
99
99
  * User Hook — wire to invoke.site.loaders for your platform's user API.
100
100
  *
101
- * VTEX sites get a real factory from @decocms/apps/vtex/hooks/createUseUser;
101
+ * VTEX sites get a real factory from @decocms/apps-vtex/hooks/createUseUser;
102
102
  * see migration template hooks.ts for the canonical five-line shim.
103
103
  */
104
104
  import { signal } from "~/sdk/signal";
@@ -125,7 +125,7 @@ function generateGenericUseWishlist(): string {
125
125
  return `/**
126
126
  * Wishlist Hook — wire to invoke.site.loaders/actions for your platform.
127
127
  *
128
- * VTEX sites get a real factory from @decocms/apps/vtex/hooks/createUseWishlist;
128
+ * VTEX sites get a real factory from @decocms/apps-vtex/hooks/createUseWishlist;
129
129
  * see migration template hooks.ts for the canonical five-line shim.
130
130
  */
131
131
  import { signal } from "~/sdk/signal";
@@ -99,7 +99,7 @@ describe("D3 — generated stubs throw at runtime", () => {
99
99
  it("vtex-transform.toProduct throws and points at the canonical path", () => {
100
100
  const src = LIB_TEMPLATES["src/lib/vtex-transform.ts"];
101
101
  expect(src).toMatch(/throw new Error/);
102
- expect(src).toMatch(/@decocms\/apps\/vtex\/utils\/transform/);
102
+ expect(src).toMatch(/@decocms\/apps-vtex\/utils\/transform/);
103
103
  expect(src).toMatch(/\[deco-migrate\]/);
104
104
  });
105
105
 
@@ -117,7 +117,7 @@ describe("D3 — generated stubs throw at runtime", () => {
117
117
  const src = LIB_TEMPLATES["src/lib/vtex-segment.ts"];
118
118
  expect(src).toMatch(/getSegmentFromBag[\s\S]*?throw new Error/);
119
119
  expect(src).toMatch(/withSegmentCookie[\s\S]*?throw new Error/);
120
- expect(src).toMatch(/@decocms\/apps\/vtex\/utils\/segment/);
120
+ expect(src).toMatch(/@decocms\/apps-vtex\/utils\/segment/);
121
121
  });
122
122
 
123
123
  it("non-stub helpers stay implemented (negative check — no throw)", () => {
@@ -46,11 +46,11 @@ export function selectImportedLibTemplates(
46
46
  //
47
47
  // Each thrown message points at the canonical replacement so the fix
48
48
  // is mechanical. `deco-post-cleanup --fix` automates the swap.
49
- const LIB_VTEX_TRANSFORM = `import type { Product } from "@decocms/apps/commerce/types";
49
+ const LIB_VTEX_TRANSFORM = `import type { Product } from "@decocms/apps-commerce/types";
50
50
 
51
51
  const STUB =
52
52
  "[deco-migrate] \`~/lib/vtex-transform.toProduct\` is a generated stub. " +
53
- "Replace with: import { toProduct } from '@decocms/apps/vtex/utils/transform' " +
53
+ "Replace with: import { toProduct } from '@decocms/apps-vtex/utils/transform' " +
54
54
  "(canonical signature: \`toProduct(product, sku, level, options)\`). " +
55
55
  "Run \`deco-post-cleanup --fix\` or see the deco-to-tanstack-migration skill " +
56
56
  "(post-migration-cleanup § 5).";
@@ -119,13 +119,13 @@ const LIB_VTEX_SEGMENT = `// Per the migration tooling policy (D3): both these s
119
119
  const STUB_GET_SEGMENT_FROM_BAG =
120
120
  "[deco-migrate] \`~/lib/vtex-segment.getSegmentFromBag\` is a generated " +
121
121
  "stub. Refactor: read cookies via \`request.headers.get('cookie')\` then " +
122
- "call \`buildSegmentFromCookies()\` from '@decocms/apps/vtex/utils/segment'. " +
122
+ "call \`buildSegmentFromCookies()\` from '@decocms/apps-vtex/utils/segment'. " +
123
123
  "The bag-based lookup mechanism does not exist on TanStack Start.";
124
124
 
125
125
  const STUB_WITH_SEGMENT_COOKIE =
126
126
  "[deco-migrate] \`~/lib/vtex-segment.withSegmentCookie\` is a generated " +
127
127
  "stub. Replace with: import { withSegmentCookie } from " +
128
- "'@decocms/apps/vtex/utils/segment' (canonical signature: " +
128
+ "'@decocms/apps-vtex/utils/segment' (canonical signature: " +
129
129
  "\`withSegmentCookie(segment, headers?)\`). Run \`deco-post-cleanup --fix\` " +
130
130
  "or see the deco-to-tanstack-migration skill.";
131
131