@olonjs/cli 3.0.121 → 3.0.122

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.
@@ -1644,7 +1644,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
1644
1644
  "@tiptap/extension-link": "^2.11.5",
1645
1645
  "@tiptap/react": "^2.11.5",
1646
1646
  "@tiptap/starter-kit": "^2.11.5",
1647
- "@olonjs/core": "^1.0.110",
1647
+ "@olonjs/core": "^1.0.111",
1648
1648
  "class-variance-authority": "^0.7.1",
1649
1649
  "clsx": "^2.1.1",
1650
1650
  "lucide-react": "^0.474.0",
@@ -3138,6 +3138,7 @@ const CLOUD_API_URL =
3138
3138
  import.meta.env.VITE_OLONJS_CLOUD_URL ?? import.meta.env.VITE_JSONPAGES_CLOUD_URL;
3139
3139
  const CLOUD_API_KEY =
3140
3140
  import.meta.env.VITE_OLONJS_API_KEY ?? import.meta.env.VITE_JSONPAGES_API_KEY;
3141
+ const SAVE2REPO_ENABLED = import.meta.env.VITE_SAVE2REPO === 'true';
3141
3142
 
3142
3143
  const themeConfig = themeData as unknown as ThemeConfig;
3143
3144
  const menuConfig: MenuConfig = { main: [] };
@@ -3404,6 +3405,45 @@ function normalizeSlugForCache(slug: string): string {
3404
3405
  );
3405
3406
  }
3406
3407
 
3408
+ function buildPublishedPageHref(slug: string): string {
3409
+ return `/pages/${normalizeSlugForCache(slug)}.json`;
3410
+ }
3411
+
3412
+ async function loadPublishedStaticContent(
3413
+ knownSlugs: string[]
3414
+ ): Promise<{ pages: Record<string, PageConfig>; siteConfig: SiteConfig }> {
3415
+ const siteResponse = await fetch('/config/site.json', { cache: 'no-store' });
3416
+ if (!siteResponse.ok) {
3417
+ throw new Error(`Static site config unavailable: ${siteResponse.status}`);
3418
+ }
3419
+
3420
+ const sitePayload = (await siteResponse.json().catch(() => null)) as unknown;
3421
+ const nextSite = coerceSiteConfig(sitePayload);
3422
+ if (!nextSite) {
3423
+ throw new Error('Static site config is invalid.');
3424
+ }
3425
+
3426
+ const pageEntries = await Promise.all(
3427
+ knownSlugs.map(async (slug) => {
3428
+ const response = await fetch(buildPublishedPageHref(slug), { cache: 'no-store' });
3429
+ if (!response.ok) {
3430
+ throw new Error(`Static page unavailable for slug "${slug}": ${response.status}`);
3431
+ }
3432
+ return [slug, (await response.json().catch(() => null)) as unknown] as const;
3433
+ })
3434
+ );
3435
+
3436
+ const nextPages = normalizePageRegistry(Object.fromEntries(pageEntries));
3437
+ if (Object.keys(nextPages).length === 0) {
3438
+ throw new Error('Static published pages are empty.');
3439
+ }
3440
+
3441
+ return {
3442
+ pages: nextPages,
3443
+ siteConfig: nextSite,
3444
+ };
3445
+ }
3446
+
3407
3447
  function readCachedCloudContent(fingerprint: string): CachedCloudContent | null {
3408
3448
  try {
3409
3449
  const raw = localStorage.getItem(CLOUD_CACHE_KEY);
@@ -3447,6 +3487,8 @@ function setTenantPreviewReady(ready: boolean): void {
3447
3487
 
3448
3488
  function App() {
3449
3489
  const isCloudMode = Boolean(CLOUD_API_URL && CLOUD_API_KEY);
3490
+ const isSave2RepoMode = isCloudMode && SAVE2REPO_ENABLED;
3491
+ const isHotSaveMode = isCloudMode && !isSave2RepoMode;
3450
3492
  const localInitialData = useMemo(() => (isCloudMode ? null : getInitialData()), [isCloudMode]);
3451
3493
  const localInitialPages = useMemo(() => {
3452
3494
  if (!localInitialData) return {};
@@ -3528,6 +3570,54 @@ function App() {
3528
3570
  logBootstrapEvent('boot.local.ready', { mode: 'local' });
3529
3571
  return;
3530
3572
  }
3573
+
3574
+ if (isSave2RepoMode) {
3575
+ if (contentLoadInFlight.current) {
3576
+ return;
3577
+ }
3578
+
3579
+ setContentMode('cloud');
3580
+ setContentFallback(null);
3581
+ setShowTopProgress(true);
3582
+ setHasInitialCloudResolved(false);
3583
+ logBootstrapEvent('boot.start', { mode: 'save2repo-static', pageCount: Object.keys(filePages).length });
3584
+
3585
+ let inFlight: Promise<void> | null = null;
3586
+ inFlight = loadPublishedStaticContent(Object.keys(filePages))
3587
+ .then(({ pages: nextPages, siteConfig: nextSite }) => {
3588
+ setPages(nextPages);
3589
+ setSiteConfig(nextSite);
3590
+ setContentMode('cloud');
3591
+ setContentFallback(null);
3592
+ setHasInitialCloudResolved(true);
3593
+ logBootstrapEvent('boot.save2repo.success', {
3594
+ mode: 'save2repo-static',
3595
+ pageCount: Object.keys(nextPages).length,
3596
+ });
3597
+ })
3598
+ .catch((error: unknown) => {
3599
+ const failure = toCloudLoadFailure(error);
3600
+ setContentMode('error');
3601
+ setContentFallback(failure);
3602
+ setHasInitialCloudResolved(true);
3603
+ logBootstrapEvent('boot.save2repo.error', {
3604
+ mode: 'save2repo-static',
3605
+ reasonCode: failure.reasonCode,
3606
+ correlationId: failure.correlationId ?? null,
3607
+ });
3608
+ })
3609
+ .finally(() => {
3610
+ setShowTopProgress(false);
3611
+ if (contentLoadInFlight.current === inFlight) {
3612
+ contentLoadInFlight.current = null;
3613
+ }
3614
+ });
3615
+ contentLoadInFlight.current = inFlight;
3616
+ return () => {
3617
+ contentLoadInFlight.current = null;
3618
+ };
3619
+ }
3620
+
3531
3621
  if (contentLoadInFlight.current) {
3532
3622
  return;
3533
3623
  }
@@ -3700,7 +3790,7 @@ function App() {
3700
3790
  });
3701
3791
  contentLoadInFlight.current = inFlight;
3702
3792
  return () => controller.abort();
3703
- }, [isCloudMode, CLOUD_API_KEY, CLOUD_API_URL, cloudApiCandidates, bootstrapRunId]);
3793
+ }, [isCloudMode, isSave2RepoMode, CLOUD_API_KEY, CLOUD_API_URL, cloudApiCandidates, bootstrapRunId]);
3704
3794
 
3705
3795
  const runCloudSave = useCallback(
3706
3796
  async (
@@ -3862,8 +3952,12 @@ function App() {
3862
3952
  },
3863
3953
  });
3864
3954
  },
3865
- showLegacySave: !isCloudMode,
3866
- showHotSave: isCloudMode,
3955
+ async coldSave(state: ProjectState, slug: string): Promise<void> {
3956
+ await runCloudSave({ state, slug }, true);
3957
+ },
3958
+ showLocalSave: !isCloudMode,
3959
+ showHotSave: isHotSaveMode,
3960
+ showColdSave: isSave2RepoMode,
3867
3961
  },
3868
3962
  assets: {
3869
3963
  assetsBaseUrl: '/assets',
@@ -4093,7 +4187,6 @@ function App() {
4093
4187
 
4094
4188
  export default App;
4095
4189
 
4096
-
4097
4190
  END_OF_FILE_CONTENT
4098
4191
  mkdir -p "src/components"
4099
4192
  echo "Creating src/components/NotFound.tsx..."
@@ -11548,8 +11641,8 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
11548
11641
  "href": "#architecture"
11549
11642
  },
11550
11643
  "image": {
11551
- "url": "/assets/images/plug-graded-square.jpg",
11552
- "alt": "Olon interface port engraved into a dark stone surface"
11644
+ "url": "/assets/images/1775421583171-Screenshot_2026-04-05_at_20-08-49_OlonJS_MCP___LinkedIn_Cover.png",
11645
+ "alt": "1775421583171-Screenshot_2026-04-05_at_20-08-49_OlonJS_MCP___LinkedIn_Cover.png"
11553
11646
  }
11554
11647
  }
11555
11648
  },
@@ -11726,7 +11819,6 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
11726
11819
  }
11727
11820
  ]
11728
11821
  }
11729
-
11730
11822
  END_OF_FILE_CONTENT
11731
11823
  echo "Creating src/data/pages/home_.json..."
11732
11824
  cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home_.json"
@@ -596,7 +596,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
596
596
  "@tiptap/extension-link": "^2.11.5",
597
597
  "@tiptap/react": "^2.11.5",
598
598
  "@tiptap/starter-kit": "^2.11.5",
599
- "@olonjs/core": "^1.0.110",
599
+ "@olonjs/core": "^1.0.111",
600
600
  "clsx": "^2.1.1",
601
601
  "lucide-react": "^0.474.0",
602
602
  "react": "^19.0.0",
@@ -1653,7 +1653,7 @@ function App() {
1653
1653
  throw new Error(body.error || body.code || `Hot save failed: ${res.status}`);
1654
1654
  }
1655
1655
  },
1656
- showLegacySave: !isCloudMode,
1656
+ showLocalSave: !isCloudMode,
1657
1657
  showHotSave: isCloudMode,
1658
1658
  },
1659
1659
  assets: {
@@ -1644,7 +1644,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
1644
1644
  "@tiptap/extension-link": "^2.11.5",
1645
1645
  "@tiptap/react": "^2.11.5",
1646
1646
  "@tiptap/starter-kit": "^2.11.5",
1647
- "@olonjs/core": "^1.0.110",
1647
+ "@olonjs/core": "^1.0.111",
1648
1648
  "class-variance-authority": "^0.7.1",
1649
1649
  "clsx": "^2.1.1",
1650
1650
  "lucide-react": "^0.474.0",
@@ -3138,6 +3138,7 @@ const CLOUD_API_URL =
3138
3138
  import.meta.env.VITE_OLONJS_CLOUD_URL ?? import.meta.env.VITE_JSONPAGES_CLOUD_URL;
3139
3139
  const CLOUD_API_KEY =
3140
3140
  import.meta.env.VITE_OLONJS_API_KEY ?? import.meta.env.VITE_JSONPAGES_API_KEY;
3141
+ const SAVE2REPO_ENABLED = import.meta.env.VITE_SAVE2REPO === 'true';
3141
3142
 
3142
3143
  const themeConfig = themeData as unknown as ThemeConfig;
3143
3144
  const menuConfig: MenuConfig = { main: [] };
@@ -3404,6 +3405,45 @@ function normalizeSlugForCache(slug: string): string {
3404
3405
  );
3405
3406
  }
3406
3407
 
3408
+ function buildPublishedPageHref(slug: string): string {
3409
+ return `/pages/${normalizeSlugForCache(slug)}.json`;
3410
+ }
3411
+
3412
+ async function loadPublishedStaticContent(
3413
+ knownSlugs: string[]
3414
+ ): Promise<{ pages: Record<string, PageConfig>; siteConfig: SiteConfig }> {
3415
+ const siteResponse = await fetch('/config/site.json', { cache: 'no-store' });
3416
+ if (!siteResponse.ok) {
3417
+ throw new Error(`Static site config unavailable: ${siteResponse.status}`);
3418
+ }
3419
+
3420
+ const sitePayload = (await siteResponse.json().catch(() => null)) as unknown;
3421
+ const nextSite = coerceSiteConfig(sitePayload);
3422
+ if (!nextSite) {
3423
+ throw new Error('Static site config is invalid.');
3424
+ }
3425
+
3426
+ const pageEntries = await Promise.all(
3427
+ knownSlugs.map(async (slug) => {
3428
+ const response = await fetch(buildPublishedPageHref(slug), { cache: 'no-store' });
3429
+ if (!response.ok) {
3430
+ throw new Error(`Static page unavailable for slug "${slug}": ${response.status}`);
3431
+ }
3432
+ return [slug, (await response.json().catch(() => null)) as unknown] as const;
3433
+ })
3434
+ );
3435
+
3436
+ const nextPages = normalizePageRegistry(Object.fromEntries(pageEntries));
3437
+ if (Object.keys(nextPages).length === 0) {
3438
+ throw new Error('Static published pages are empty.');
3439
+ }
3440
+
3441
+ return {
3442
+ pages: nextPages,
3443
+ siteConfig: nextSite,
3444
+ };
3445
+ }
3446
+
3407
3447
  function readCachedCloudContent(fingerprint: string): CachedCloudContent | null {
3408
3448
  try {
3409
3449
  const raw = localStorage.getItem(CLOUD_CACHE_KEY);
@@ -3447,6 +3487,8 @@ function setTenantPreviewReady(ready: boolean): void {
3447
3487
 
3448
3488
  function App() {
3449
3489
  const isCloudMode = Boolean(CLOUD_API_URL && CLOUD_API_KEY);
3490
+ const isSave2RepoMode = isCloudMode && SAVE2REPO_ENABLED;
3491
+ const isHotSaveMode = isCloudMode && !isSave2RepoMode;
3450
3492
  const localInitialData = useMemo(() => (isCloudMode ? null : getInitialData()), [isCloudMode]);
3451
3493
  const localInitialPages = useMemo(() => {
3452
3494
  if (!localInitialData) return {};
@@ -3528,6 +3570,54 @@ function App() {
3528
3570
  logBootstrapEvent('boot.local.ready', { mode: 'local' });
3529
3571
  return;
3530
3572
  }
3573
+
3574
+ if (isSave2RepoMode) {
3575
+ if (contentLoadInFlight.current) {
3576
+ return;
3577
+ }
3578
+
3579
+ setContentMode('cloud');
3580
+ setContentFallback(null);
3581
+ setShowTopProgress(true);
3582
+ setHasInitialCloudResolved(false);
3583
+ logBootstrapEvent('boot.start', { mode: 'save2repo-static', pageCount: Object.keys(filePages).length });
3584
+
3585
+ let inFlight: Promise<void> | null = null;
3586
+ inFlight = loadPublishedStaticContent(Object.keys(filePages))
3587
+ .then(({ pages: nextPages, siteConfig: nextSite }) => {
3588
+ setPages(nextPages);
3589
+ setSiteConfig(nextSite);
3590
+ setContentMode('cloud');
3591
+ setContentFallback(null);
3592
+ setHasInitialCloudResolved(true);
3593
+ logBootstrapEvent('boot.save2repo.success', {
3594
+ mode: 'save2repo-static',
3595
+ pageCount: Object.keys(nextPages).length,
3596
+ });
3597
+ })
3598
+ .catch((error: unknown) => {
3599
+ const failure = toCloudLoadFailure(error);
3600
+ setContentMode('error');
3601
+ setContentFallback(failure);
3602
+ setHasInitialCloudResolved(true);
3603
+ logBootstrapEvent('boot.save2repo.error', {
3604
+ mode: 'save2repo-static',
3605
+ reasonCode: failure.reasonCode,
3606
+ correlationId: failure.correlationId ?? null,
3607
+ });
3608
+ })
3609
+ .finally(() => {
3610
+ setShowTopProgress(false);
3611
+ if (contentLoadInFlight.current === inFlight) {
3612
+ contentLoadInFlight.current = null;
3613
+ }
3614
+ });
3615
+ contentLoadInFlight.current = inFlight;
3616
+ return () => {
3617
+ contentLoadInFlight.current = null;
3618
+ };
3619
+ }
3620
+
3531
3621
  if (contentLoadInFlight.current) {
3532
3622
  return;
3533
3623
  }
@@ -3700,7 +3790,7 @@ function App() {
3700
3790
  });
3701
3791
  contentLoadInFlight.current = inFlight;
3702
3792
  return () => controller.abort();
3703
- }, [isCloudMode, CLOUD_API_KEY, CLOUD_API_URL, cloudApiCandidates, bootstrapRunId]);
3793
+ }, [isCloudMode, isSave2RepoMode, CLOUD_API_KEY, CLOUD_API_URL, cloudApiCandidates, bootstrapRunId]);
3704
3794
 
3705
3795
  const runCloudSave = useCallback(
3706
3796
  async (
@@ -3862,8 +3952,12 @@ function App() {
3862
3952
  },
3863
3953
  });
3864
3954
  },
3865
- showLegacySave: !isCloudMode,
3866
- showHotSave: isCloudMode,
3955
+ async coldSave(state: ProjectState, slug: string): Promise<void> {
3956
+ await runCloudSave({ state, slug }, true);
3957
+ },
3958
+ showLocalSave: !isCloudMode,
3959
+ showHotSave: isHotSaveMode,
3960
+ showColdSave: isSave2RepoMode,
3867
3961
  },
3868
3962
  assets: {
3869
3963
  assetsBaseUrl: '/assets',
@@ -4093,7 +4187,6 @@ function App() {
4093
4187
 
4094
4188
  export default App;
4095
4189
 
4096
-
4097
4190
  END_OF_FILE_CONTENT
4098
4191
  mkdir -p "src/components"
4099
4192
  echo "Creating src/components/NotFound.tsx..."
@@ -11548,8 +11641,8 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
11548
11641
  "href": "#architecture"
11549
11642
  },
11550
11643
  "image": {
11551
- "url": "/assets/images/plug-graded-square.jpg",
11552
- "alt": "Olon interface port engraved into a dark stone surface"
11644
+ "url": "/assets/images/1775421583171-Screenshot_2026-04-05_at_20-08-49_OlonJS_MCP___LinkedIn_Cover.png",
11645
+ "alt": "1775421583171-Screenshot_2026-04-05_at_20-08-49_OlonJS_MCP___LinkedIn_Cover.png"
11553
11646
  }
11554
11647
  }
11555
11648
  },
@@ -11726,7 +11819,6 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
11726
11819
  }
11727
11820
  ]
11728
11821
  }
11729
-
11730
11822
  END_OF_FILE_CONTENT
11731
11823
  echo "Creating src/data/pages/home_.json..."
11732
11824
  cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home_.json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olonjs/cli",
3
- "version": "3.0.121",
3
+ "version": "3.0.122",
4
4
  "description": "The Sovereign CLI Engine for OlonJS.",
5
5
  "type": "module",
6
6
  "bin": {