@akanjs/cli 3.0.0-alpha.67 → 3.0.0-alpha.69

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 (51) hide show
  1. package/.build-stamp +1 -1
  2. package/{agent.command-0p7p9ba8.js → agent.command-964bf8qg.js} +5 -5
  3. package/{application.command-5bafqeva.js → application.command-n45n18sc.js} +4 -4
  4. package/{applicationBuildRunner-jnjag4ay.js → applicationBuildRunner-af0wtspv.js} +5 -2
  5. package/buildBatch.proc.js +2 -2
  6. package/{capacitorApp-6mcsqh9k.js → capacitorApp-vnvnvdhf.js} +2 -2
  7. package/{cloud.command-d111e7st.js → cloud.command-kx1bh5yq.js} +7 -7
  8. package/{context.command-ypb8e1yj.js → context.command-g1a65x6j.js} +12 -12
  9. package/{guideline.command-g6nfb85d.js → guideline.command-xphyhvwh.js} +2 -2
  10. package/guidelines/conventions/conventions.instruction.md +51 -3
  11. package/guidelines/mcpRule/mcpRule.instruction.md +46 -5
  12. package/incrementalBuilder.proc.js +1 -1
  13. package/{index-sfbb92q2.js → index-0ngvvgry.js} +2 -2
  14. package/{index-9kbervcd.js → index-4rw4qhe6.js} +3 -3
  15. package/{index-x8d7krmm.js → index-8gybxemv.js} +5 -5
  16. package/{index-xesyg6bc.js → index-abyjt72y.js} +191 -27
  17. package/{index-amghj6k5.js → index-bqqts262.js} +1 -1
  18. package/{index-4e84gbad.js → index-e31ghfp5.js} +1 -1
  19. package/{index-5nj96dm3.js → index-fahkq20v.js} +3 -3
  20. package/{index-pbb97b16.js → index-hee7egtm.js} +1 -1
  21. package/{index-hjh8czbk.js → index-mkn5qagt.js} +5 -5
  22. package/{index-kvqvzgjq.js → index-nj3w0r34.js} +3 -3
  23. package/{index-vfnmsp1a.js → index-nkwmnqwn.js} +21 -4
  24. package/{index-77s16neb.js → index-p681w089.js} +2 -2
  25. package/{index-h33m7gbq.js → index-qt4nfr0n.js} +10 -10
  26. package/{index-w626d6zw.js → index-rb65xnw9.js} +4 -4
  27. package/{index-fc98hz1w.js → index-rbnpe8cp.js} +3 -3
  28. package/{index-bgjyden1.js → index-v5fdxdre.js} +2 -2
  29. package/{index-n2sz0qq3.js → index-va15r8h5.js} +2 -2
  30. package/{index-w627vcya.js → index-yg3hxk2k.js} +4 -4
  31. package/{index-4h99bj2e.js → index-ytaqtc04.js} +1 -1
  32. package/index.js +18 -18
  33. package/{library.command-j195dmpk.js → library.command-rfpd27yv.js} +3 -3
  34. package/{localRegistry.command-gz6mh6s0.js → localRegistry.command-pyxfe0fs.js} +6 -6
  35. package/{module.command-y306b14r.js → module.command-qhaxad0p.js} +5 -5
  36. package/{package.command-f7gdscaj.js → package.command-2k22q9nt.js} +3 -3
  37. package/package.json +3 -3
  38. package/{page.command-56kkr187.js → page.command-ymk9dqh4.js} +3 -3
  39. package/{primitive.command-9exysfem.js → primitive.command-9k45zpc1.js} +6 -6
  40. package/{quality.command-yace5341.js → quality.command-bf6vkxe5.js} +2 -2
  41. package/{repair.command-fyzwaa7c.js → repair.command-egvvm6xf.js} +5 -5
  42. package/{scalar.command-kdqx816z.js → scalar.command-bt1facyj.js} +4 -4
  43. package/templates/app/env/env.client.debug.ts.template +1 -5
  44. package/templates/app/env/env.client.develop.ts.template +1 -5
  45. package/templates/app/env/env.client.local.ts.template +1 -5
  46. package/templates/app/env/env.client.main.ts.template +1 -5
  47. package/templates/app/env/env.client.testing.ts.template +1 -5
  48. package/templates/app/env/env.client.type.ts +2 -6
  49. package/templates/workspaceRoot/package.json.template +1 -1
  50. package/{workflow.command-vs112teg.js → workflow.command-v1n3wg7v.js} +9 -9
  51. package/{workspace.command-rbzq1e56.js → workspace.command-yvvqvhzz.js} +18 -18
@@ -1575,11 +1575,175 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
1575
1575
  }
1576
1576
  }
1577
1577
 
1578
+ // pkgs/@akanjs/devkit/frontendBuild/fontPruner.ts
1579
+ import { rm as rm2, rmdir, stat as stat3 } from "fs/promises";
1580
+ import path9 from "path";
1581
+ import { isFontOptimizationEnabled } from "akanjs/client";
1582
+ var FONT_GLOB = "**/*.{woff2,woff,ttf,otf,ttc,eot}";
1583
+ var REFERRER_GLOB = "**/*.{css,js,mjs,cjs,json,html,htm,svg,xml,webmanifest}";
1584
+
1585
+ class FontPruner {
1586
+ #app;
1587
+ #keepGlobs;
1588
+ #publicRoot;
1589
+ #artifactRoot;
1590
+ constructor(app, { keepFonts = [] } = {}) {
1591
+ this.#app = app;
1592
+ this.#keepGlobs = keepFonts;
1593
+ this.#publicRoot = path9.join(app.dist.cwdPath, "public");
1594
+ this.#artifactRoot = path9.join(app.dist.cwdPath, ".akan/artifact");
1595
+ }
1596
+ async prune() {
1597
+ const empty = { removed: [], kept: [], freedBytes: 0 };
1598
+ if (!await this.#isDirectory(this.#publicRoot))
1599
+ return empty;
1600
+ const candidates = await this.#collectCandidates();
1601
+ if (!candidates.length)
1602
+ return empty;
1603
+ const fonts = await new FontOptimizer(this.#app, "build").discoverFonts();
1604
+ const unoptimizedSrcs = new Set;
1605
+ const optimizedSrcs = new Set;
1606
+ for (const font of fonts) {
1607
+ const target = isFontOptimizationEnabled(font) ? optimizedSrcs : unoptimizedSrcs;
1608
+ for (const fontPath of font.paths)
1609
+ target.add(path9.posix.basename(fontPath.src));
1610
+ }
1611
+ const result = { removed: [], kept: [], freedBytes: 0 };
1612
+ const undecided = [];
1613
+ for (const candidate of candidates) {
1614
+ const reason = this.#staticKeepReason(candidate, unoptimizedSrcs);
1615
+ if (reason)
1616
+ result.kept.push({ file: candidate.rel, bytes: candidate.bytes, reason });
1617
+ else
1618
+ undecided.push(candidate);
1619
+ }
1620
+ if (undecided.length) {
1621
+ const referrers = await this.#findReferrers(undecided, optimizedSrcs);
1622
+ for (const candidate of undecided) {
1623
+ const referrer = referrers.get(candidate.rel);
1624
+ if (referrer)
1625
+ result.kept.push({ file: candidate.rel, bytes: candidate.bytes, reason: { kind: "referenced", referrer } });
1626
+ else
1627
+ result.removed.push({ file: candidate.rel, bytes: candidate.bytes });
1628
+ }
1629
+ }
1630
+ await this.#remove(result.removed.map(({ file }) => file));
1631
+ result.freedBytes = result.removed.reduce((total, { bytes }) => total + bytes, 0);
1632
+ this.#report(result);
1633
+ return result;
1634
+ }
1635
+ #staticKeepReason(candidate, unoptimizedSrcs) {
1636
+ if (unoptimizedSrcs.has(candidate.basename))
1637
+ return { kind: "unoptimized" };
1638
+ for (const glob of this.#keepGlobs) {
1639
+ if (new Bun.Glob(glob).match(candidate.rel))
1640
+ return { kind: "declared", glob };
1641
+ }
1642
+ return null;
1643
+ }
1644
+ async#collectCandidates() {
1645
+ const candidates = [];
1646
+ for await (const rel of new Bun.Glob(FONT_GLOB).scan({ cwd: this.#publicRoot, dot: false })) {
1647
+ const entry = await stat3(path9.join(this.#publicRoot, rel)).catch(() => null);
1648
+ if (!entry?.isFile())
1649
+ continue;
1650
+ candidates.push({ rel: rel.split(path9.sep).join("/"), basename: path9.basename(rel), bytes: entry.size });
1651
+ }
1652
+ return candidates;
1653
+ }
1654
+ async#findReferrers(candidates, optimizedSrcs) {
1655
+ const referrers = new Map;
1656
+ const authoritative = candidates;
1657
+ const bundled = candidates.filter((candidate) => !optimizedSrcs.has(candidate.basename));
1658
+ const roots = [
1659
+ { dir: this.#publicRoot, label: "public", needles: authoritative },
1660
+ { dir: path9.join(this.#artifactRoot, "styles"), label: ".akan/artifact/styles", needles: authoritative },
1661
+ { dir: path9.join(this.#artifactRoot, "client"), label: ".akan/artifact/client", needles: bundled },
1662
+ { dir: path9.join(this.#artifactRoot, "client-ssr"), label: ".akan/artifact/client-ssr", needles: bundled },
1663
+ { dir: path9.join(this.#artifactRoot, "server"), label: ".akan/artifact/server", needles: bundled },
1664
+ { dir: path9.join(this.#app.dist.cwdPath, "csr"), label: "csr", needles: bundled }
1665
+ ];
1666
+ for (const root of roots) {
1667
+ const pending = root.needles.filter((candidate) => !referrers.has(candidate.rel));
1668
+ if (!pending.length || !await this.#isDirectory(root.dir))
1669
+ continue;
1670
+ await this.#scanRoot(root, pending, referrers);
1671
+ }
1672
+ return referrers;
1673
+ }
1674
+ async#scanRoot(root, pending, referrers) {
1675
+ const needles = pending.map((candidate) => ({
1676
+ rel: candidate.rel,
1677
+ forms: [...new Set([candidate.basename, encodeURIComponent(candidate.basename)])]
1678
+ }));
1679
+ for await (const rel of new Bun.Glob(REFERRER_GLOB).scan({ cwd: root.dir, dot: false })) {
1680
+ const remaining = needles.filter((needle) => !referrers.has(needle.rel));
1681
+ if (!remaining.length)
1682
+ return;
1683
+ const text = await Bun.file(path9.join(root.dir, rel)).text().catch(() => "");
1684
+ if (!text)
1685
+ continue;
1686
+ for (const needle of remaining) {
1687
+ if (needle.forms.some((form) => text.includes(form)))
1688
+ referrers.set(needle.rel, `${root.label}/${rel.split(path9.sep).join("/")}`);
1689
+ }
1690
+ }
1691
+ }
1692
+ async#remove(files) {
1693
+ await Promise.all(files.map((file) => rm2(path9.join(this.#publicRoot, file), { force: true })));
1694
+ const dirs = [...new Set(files.map((file) => path9.posix.dirname(file)))].filter((dir) => dir !== "." && dir !== "/").sort((a, b) => b.length - a.length);
1695
+ for (const dir of dirs)
1696
+ await rmdir(path9.join(this.#publicRoot, dir)).catch(() => {
1697
+ return;
1698
+ });
1699
+ }
1700
+ #report(result) {
1701
+ if (!result.removed.length && !result.kept.length)
1702
+ return;
1703
+ for (const { file, bytes } of result.removed)
1704
+ this.#app.verbose(`[font-prune] dropped public/${file} (${FontPruner.formatBytes(bytes)})`);
1705
+ for (const { file, reason } of result.kept)
1706
+ this.#app.verbose(`[font-prune] kept public/${file} \u2014 ${FontPruner.describe(reason)}`);
1707
+ const byReferrer = new Map;
1708
+ for (const { bytes, reason } of result.kept) {
1709
+ if (reason.kind !== "referenced")
1710
+ continue;
1711
+ const entry = byReferrer.get(reason.referrer) ?? { files: 0, bytes: 0 };
1712
+ entry.files += 1;
1713
+ entry.bytes += bytes;
1714
+ byReferrer.set(reason.referrer, entry);
1715
+ }
1716
+ if (!byReferrer.size)
1717
+ return;
1718
+ const ranked = [...byReferrer.entries()].sort(([, a], [, b]) => b.bytes - a.bytes);
1719
+ const named = ranked.slice(0, 3).map(([referrer, { files, bytes }]) => `${referrer} (${files}, ${FontPruner.formatBytes(bytes)})`);
1720
+ const rest = ranked.length - named.length;
1721
+ this.#app.logger.info(`[font-prune] kept ${FontPruner.formatBytes(ranked.reduce((total, [, entry]) => total + entry.bytes, 0))} of fonts in public/ because these reference them: ${named.join(", ")}${rest > 0 ? ` and ${rest} more` : ""}`);
1722
+ }
1723
+ static describe(reason) {
1724
+ if (reason.kind === "unoptimized")
1725
+ return "declared with optimize: false, so the runtime CSS serves it";
1726
+ if (reason.kind === "declared")
1727
+ return `kept by assets.keepFonts "${reason.glob}"`;
1728
+ return `referenced by ${reason.referrer}`;
1729
+ }
1730
+ static formatBytes(bytes) {
1731
+ if (bytes < 1024)
1732
+ return `${bytes}B`;
1733
+ if (bytes < 1024 * 1024)
1734
+ return `${(bytes / 1024).toFixed(1)}KB`;
1735
+ return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
1736
+ }
1737
+ async#isDirectory(dir) {
1738
+ return await stat3(dir).then((entry) => entry.isDirectory(), () => false);
1739
+ }
1740
+ }
1741
+
1578
1742
  // pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
1579
- import path10 from "path";
1743
+ import path11 from "path";
1580
1744
 
1581
1745
  // pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
1582
- import path9 from "path";
1746
+ import path10 from "path";
1583
1747
  var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
1584
1748
  var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
1585
1749
  var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
@@ -1621,7 +1785,7 @@ async function createExternalizeFrameworkPlugin(options) {
1621
1785
  const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
1622
1786
  if (!replPath)
1623
1787
  continue;
1624
- const candidate = path9.resolve(workspaceRoot, replPath + suffix);
1788
+ const candidate = path10.resolve(workspaceRoot, replPath + suffix);
1625
1789
  const hit = await firstExisting(candidate);
1626
1790
  if (hit)
1627
1791
  return hit;
@@ -1633,8 +1797,8 @@ async function createExternalizeFrameworkPlugin(options) {
1633
1797
  if (spec === pkg)
1634
1798
  continue;
1635
1799
  const suffix = spec.slice(pkg.length + 1);
1636
- const pkgDir = path9.dirname(path9.resolve(workspaceRoot, entryFile));
1637
- const candidate = path9.join(pkgDir, suffix);
1800
+ const pkgDir = path10.dirname(path10.resolve(workspaceRoot, entryFile));
1801
+ const candidate = path10.join(pkgDir, suffix);
1638
1802
  const hit = await firstExisting(candidate);
1639
1803
  if (hit)
1640
1804
  return hit;
@@ -1684,7 +1848,7 @@ async function firstExisting(basePath) {
1684
1848
  return candidate;
1685
1849
  }
1686
1850
  for (const ext of CANDIDATE_EXTS) {
1687
- const candidate = path9.join(basePath, `index${ext}`);
1851
+ const candidate = path10.join(basePath, `index${ext}`);
1688
1852
  if (await Bun.file(candidate).exists())
1689
1853
  return candidate;
1690
1854
  }
@@ -1775,11 +1939,11 @@ class PagesBundleBuilder {
1775
1939
  const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
1776
1940
  if (!entryArtifact)
1777
1941
  throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
1778
- const bundlePath = path10.resolve(entryArtifact.path);
1942
+ const bundlePath = path11.resolve(entryArtifact.path);
1779
1943
  const buildId = Date.now();
1780
1944
  const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
1781
1945
  const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
1782
- this.#app.verbose(`[PagesBundleBuilder] ${path10.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
1946
+ this.#app.verbose(`[PagesBundleBuilder] ${path11.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
1783
1947
  return {
1784
1948
  bundlePath,
1785
1949
  buildId,
@@ -1862,7 +2026,7 @@ function loaderFor2(absPath) {
1862
2026
 
1863
2027
  // pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
1864
2028
  import fs2 from "fs";
1865
- import path11 from "path";
2029
+ import path12 from "path";
1866
2030
  import zlib from "zlib";
1867
2031
  var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
1868
2032
  var MIN_COMPRESS_BYTES = 1024;
@@ -1871,8 +2035,8 @@ var DEFAULT_BROTLI_QUALITY = 9;
1871
2035
  var GZIP_LEVEL = 9;
1872
2036
  async function precompressArtifacts(app) {
1873
2037
  const roots = [
1874
- path11.join(app.dist.cwdPath, ".akan/artifact/client"),
1875
- path11.join(app.dist.cwdPath, ".akan/artifact/styles")
2038
+ path12.join(app.dist.cwdPath, ".akan/artifact/client"),
2039
+ path12.join(app.dist.cwdPath, ".akan/artifact/styles")
1876
2040
  ];
1877
2041
  const result = { files: 0, inputBytes: 0, outputBytes: 0, brotliBytes: 0 };
1878
2042
  await Promise.all(roots.map((root) => precompressRoot(root, result)));
@@ -1891,7 +2055,7 @@ async function precompressRoot(root, result) {
1891
2055
  const bytes = await Bun.file(filePath).bytes();
1892
2056
  const buffer = toArrayBuffer(bytes);
1893
2057
  const gz = Bun.gzipSync(buffer, { level: GZIP_LEVEL });
1894
- const br = brotliCompress(buffer, path11.extname(filePath).toLowerCase());
2058
+ const br = brotliCompress(buffer, path12.extname(filePath).toLowerCase());
1895
2059
  await Promise.all([Bun.write(`${filePath}.gz`, gz), Bun.write(`${filePath}.br`, br)]);
1896
2060
  result.files += 1;
1897
2061
  result.inputBytes += bytes.byteLength;
@@ -1911,7 +2075,7 @@ function brotliCompress(buffer, ext) {
1911
2075
  async function shouldPrecompress(filePath) {
1912
2076
  if (filePath.endsWith(".gz") || filePath.endsWith(".br"))
1913
2077
  return false;
1914
- if (!COMPRESSIBLE_EXTS.has(path11.extname(filePath).toLowerCase()))
2078
+ if (!COMPRESSIBLE_EXTS.has(path12.extname(filePath).toLowerCase()))
1915
2079
  return false;
1916
2080
  const file = Bun.file(filePath);
1917
2081
  if (!await file.exists())
@@ -1930,7 +2094,7 @@ function formatBytes(bytes) {
1930
2094
  }
1931
2095
 
1932
2096
  // pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
1933
- import path12 from "path";
2097
+ import path13 from "path";
1934
2098
  import { optimize } from "@tailwindcss/node";
1935
2099
  function prepareCssAsset(command, basePath, cssText) {
1936
2100
  return optimize(cssText, { file: `${basePath || "root"}.css`, minify: command === "build" }).code;
@@ -1946,7 +2110,7 @@ class SsrBaseArtifactBuilder {
1946
2110
  this.#app = app;
1947
2111
  this.#command = command;
1948
2112
  this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
1949
- this.#absArtifactDir = path12.resolve(this.#artifactDir);
2113
+ this.#absArtifactDir = path13.resolve(this.#artifactDir);
1950
2114
  }
1951
2115
  async build() {
1952
2116
  const akanConfig = await this.#app.getConfig();
@@ -1968,7 +2132,7 @@ class SsrBaseArtifactBuilder {
1968
2132
  rscRuntimeSsrManifest,
1969
2133
  vendorMap,
1970
2134
  cssAssets,
1971
- pagesBundlePath: this.#command === "build" ? path12.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
2135
+ pagesBundlePath: this.#command === "build" ? path13.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
1972
2136
  pagesBundleBuildId: pagesBundle.buildId,
1973
2137
  domains: [...akanConfig.domains],
1974
2138
  subRoutes: Object.fromEntries(Array.from(akanConfig.subRoutes.entries()).map(([basePath, domains]) => [basePath, [...domains]])),
@@ -1985,18 +2149,18 @@ class SsrBaseArtifactBuilder {
1985
2149
  androidSha256CertFingerprints: target.deepLinks?.android?.sha256CertFingerprints
1986
2150
  }))
1987
2151
  };
1988
- await Bun.write(path12.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
2152
+ await Bun.write(path13.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
1989
2153
  `);
1990
2154
  this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
1991
2155
  return { artifact, seedIndex, cssCompiler, optimizedFonts };
1992
2156
  }
1993
2157
  async#buildRuntimeClientEntries() {
1994
2158
  const akanServerPath = await this.#resolveAkanServerPath();
1995
- const rscClientEntry = path12.resolve(akanServerPath, "rscClient.tsx");
1996
- const rscSegmentOutletEntry = path12.resolve(akanServerPath, "rscSegmentOutlet.tsx");
2159
+ const rscClientEntry = path13.resolve(akanServerPath, "rscClient.tsx");
2160
+ const rscSegmentOutletEntry = path13.resolve(akanServerPath, "rscSegmentOutlet.tsx");
1997
2161
  const vendorEntries = VENDOR_SPECIFIERS.map((specifier) => ({
1998
2162
  specifier,
1999
- absPath: path12.resolve(akanServerPath, "vendor", `${specifier.replaceAll("/", "-").replaceAll(".", "-")}.ts`)
2163
+ absPath: path13.resolve(akanServerPath, "vendor", `${specifier.replaceAll("/", "-").replaceAll(".", "-")}.ts`)
2000
2164
  }));
2001
2165
  const entries = [rscClientEntry, rscSegmentOutletEntry, ...vendorEntries.map((v) => v.absPath)];
2002
2166
  const clientBundle = await new ClientEntriesBundler({ app: this.#app, entries, command: this.#command }).bundle();
@@ -2033,15 +2197,15 @@ class SsrBaseArtifactBuilder {
2033
2197
  async#resolveAkanServerPath() {
2034
2198
  const candidates = [];
2035
2199
  try {
2036
- candidates.push(path12.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
2200
+ candidates.push(path13.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
2037
2201
  } catch {}
2038
- candidates.push(path12.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path12.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
2202
+ candidates.push(path13.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path13.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
2039
2203
  try {
2040
- candidates.push(path12.dirname(Bun.resolveSync("akanjs/server", path12.dirname(Bun.main))));
2204
+ candidates.push(path13.dirname(Bun.resolveSync("akanjs/server", path13.dirname(Bun.main))));
2041
2205
  } catch {}
2042
- candidates.push(path12.join(path12.dirname(Bun.main), "node_modules/akanjs/server"), path12.join(path12.dirname(Bun.main), "../../akanjs/server"), path12.resolve(import.meta.dir, "../../server"), path12.resolve(import.meta.dir, "../server"));
2206
+ candidates.push(path13.join(path13.dirname(Bun.main), "node_modules/akanjs/server"), path13.join(path13.dirname(Bun.main), "../../akanjs/server"), path13.resolve(import.meta.dir, "../../server"), path13.resolve(import.meta.dir, "../server"));
2043
2207
  for (const candidate of candidates) {
2044
- if (await Bun.file(path12.join(candidate, "rscClient.tsx")).exists())
2208
+ if (await Bun.file(path13.join(candidate, "rscClient.tsx")).exists())
2045
2209
  return candidate;
2046
2210
  }
2047
2211
  throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
@@ -2070,7 +2234,7 @@ ${preparedCssText}`).toString(36);
2070
2234
  `styles/${cssAssetName}-${cssHash}.css`,
2071
2235
  `/_akan/styles/${cssAssetName}-${cssHash}.css`
2072
2236
  ];
2073
- await Bun.write(path12.join(this.#absArtifactDir, cssRelPath), preparedCssText);
2237
+ await Bun.write(path13.join(this.#absArtifactDir, cssRelPath), preparedCssText);
2074
2238
  SsrBaseArtifactBuilder.#warnDroppedImports(this.#app, cssRelPath, preparedCssText, imported);
2075
2239
  this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath} -> ${cssRelPath}`);
2076
2240
  return [basePath, { cssUrl, cssRelPath }];
@@ -2093,4 +2257,4 @@ var INTERPOLATED_ARBITRARY_RE = new RegExp(`${LEAD}[a-z][a-z0-9-]*-\\[[^\\]\`]*\
2093
2257
  var DAISYUI_LEGACY_RE = new RegExp(`${LEAD}(?:` + "btn-(?:primary|secondary|accent|neutral|info|success|warning|error|ghost|link|outline|square|circle|wide|block|xs|sm|md|lg)|" + "badge-(?:primary|secondary|accent|neutral|info|success|warning|error|ghost|outline)|" + "alert-(?:info|success|warning|error)|" + "input-(?:bordered|primary|secondary|accent|ghost|error)|" + "select-(?:bordered|primary|ghost)|textarea-(?:bordered|primary|ghost)|" + "checkbox-(?:primary|secondary|accent)|toggle-(?:primary|secondary|accent)|" + "loading-(?:spinner|dots|ring|ball|bars|infinity)|" + "card-(?:body|title|actions)|modal-(?:box|action|backdrop)|" + "collapse-(?:title|content|arrow|plus)|dropdown-(?:content|end|start|hover)|" + "stat-(?:title|value|desc)|tabs-(?:boxed|lifted|bordered)|tab-active|" + "menu-(?:title|dropdown)|steps-(?:horizontal|vertical)|join-item|" + "mockup-(?:code|phone|browser|window)|drawer-(?:side|content|toggle)" + `)${TAIL}`, "g");
2094
2258
  var DAISYUI_TOKEN = "(?:base-(?:100|200|300|content)|(?:primary|secondary|accent|neutral|info|success|warning|error)-content|error)";
2095
2259
  var DAISYUI_TOKEN_RE = new RegExp(`${LEAD}(?:${PREFIX})-${DAISYUI_TOKEN}${TAIL}`, "g");
2096
- export { AllRoutesBuilder, CsrArtifactBuilder, CssCompiler, FontOptimizer, PagesBundleBuilder, precompressArtifacts, SsrBaseArtifactBuilder };
2260
+ export { AllRoutesBuilder, CsrArtifactBuilder, CssCompiler, FontOptimizer, FontPruner, PagesBundleBuilder, precompressArtifacts, SsrBaseArtifactBuilder };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-4e84gbad.js";
5
+ } from "./index-e31ghfp5.js";
6
6
 
7
7
  // pkgs/@akanjs/cli/page/page.runner.ts
8
8
  class PageRunner extends runner("page") {
@@ -6,7 +6,7 @@ import {
6
6
  ModuleExecutor,
7
7
  PkgExecutor,
8
8
  WorkspaceExecutor
9
- } from "./index-vfnmsp1a.js";
9
+ } from "./index-nkwmnqwn.js";
10
10
  import {
11
11
  getDirname
12
12
  } from "./index-1577bej2.js";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  AkanContextAnalyzer
4
- } from "./index-n2sz0qq3.js";
4
+ } from "./index-va15r8h5.js";
5
5
  import {
6
6
  WorkflowExecutor,
7
7
  compactWorkflowInputs,
@@ -23,10 +23,10 @@ import {
23
23
  workflowCommandsForPlan,
24
24
  workflowPlanApproval,
25
25
  writeWorkflowRunArtifact
26
- } from "./index-4h99bj2e.js";
26
+ } from "./index-ytaqtc04.js";
27
27
  import {
28
28
  runner
29
- } from "./index-4e84gbad.js";
29
+ } from "./index-e31ghfp5.js";
30
30
 
31
31
  // pkgs/@akanjs/cli/workflow/workflow.runner.ts
32
32
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -5,7 +5,7 @@ import {
5
5
  } from "./index-76rn3g2c.js";
6
6
  import {
7
7
  CommandExecutionError
8
- } from "./index-vfnmsp1a.js";
8
+ } from "./index-nkwmnqwn.js";
9
9
 
10
10
  // pkgs/@akanjs/devkit/capacitorApp.ts
11
11
  import { cp, mkdir, readFile, rm, writeFile } from "fs/promises";
@@ -1,14 +1,14 @@
1
1
  // @bun
2
2
  import {
3
3
  LibraryScript
4
- } from "./index-77s16neb.js";
4
+ } from "./index-p681w089.js";
5
5
  import {
6
6
  resolveMobileTargets
7
7
  } from "./index-76rn3g2c.js";
8
8
  import {
9
9
  runner,
10
10
  script
11
- } from "./index-4e84gbad.js";
11
+ } from "./index-e31ghfp5.js";
12
12
  import {
13
13
  HmrWatcher,
14
14
  WatchRootResolver
@@ -18,7 +18,7 @@ import {
18
18
  LibExecutor,
19
19
  PkgExecutor,
20
20
  WorkspaceExecutor
21
- } from "./index-vfnmsp1a.js";
21
+ } from "./index-nkwmnqwn.js";
22
22
  import {
23
23
  __require
24
24
  } from "./index-yb2wsc7f.js";
@@ -1898,9 +1898,9 @@ function openBrowser(url) {
1898
1898
  }
1899
1899
 
1900
1900
  // pkgs/@akanjs/cli/application/application.runner.ts
1901
- var loadBuildRunner = async () => (await import("./applicationBuildRunner-jnjag4ay.js")).ApplicationBuildRunner;
1901
+ var loadBuildRunner = async () => (await import("./applicationBuildRunner-af0wtspv.js")).ApplicationBuildRunner;
1902
1902
  var loadReleasePackager = async () => (await import("./applicationReleasePackager-93nzdfsy.js")).ApplicationReleasePackager;
1903
- var loadCapacitorApp = async () => (await import("./capacitorApp-6mcsqh9k.js")).CapacitorApp;
1903
+ var loadCapacitorApp = async () => (await import("./capacitorApp-vnvnvdhf.js")).CapacitorApp;
1904
1904
  var loadAbstractCompactor = async () => (await import("./abstractCompactor-20e0cwbs.js")).AbstractCompactor;
1905
1905
  var loadPrompts = async () => await import("@inquirer/prompts");
1906
1906
 
@@ -1,17 +1,17 @@
1
1
  // @bun
2
2
  import {
3
3
  AkanContextAnalyzer
4
- } from "./index-n2sz0qq3.js";
4
+ } from "./index-va15r8h5.js";
5
5
  import {
6
6
  createRepairReport,
7
7
  generatedFilePathsForTarget,
8
8
  renderRepairReport,
9
9
  writeGeneratedSyncState,
10
10
  writeWorkflowRunArtifact
11
- } from "./index-4h99bj2e.js";
11
+ } from "./index-ytaqtc04.js";
12
12
  import {
13
13
  runner
14
- } from "./index-4e84gbad.js";
14
+ } from "./index-e31ghfp5.js";
15
15
 
16
16
  // pkgs/@akanjs/cli/repair/repair.runner.ts
17
17
  var commandForShell = (command) => command.startsWith("akan ") ? `bun run ${command}` : command;
@@ -268,7 +268,8 @@ var DEFAULT_AKAN_IMAGE_CONFIG = {
268
268
  dangerouslyAllowSVG: false,
269
269
  maximumRedirects: 3,
270
270
  fetchTimeoutMs: 7000,
271
- maxRemoteBytes: 25 * 1024 * 1024
271
+ maxRemoteBytes: 25 * 1024 * 1024,
272
+ maxConcurrency: 0
272
273
  };
273
274
  var normalizeIndexPath = (indexPath) => {
274
275
  const normalized = indexPath?.trim();
@@ -317,8 +318,12 @@ var normalizeDeepLinks = (deepLinks) => {
317
318
  };
318
319
  var emptyLibContributions = () => ({
319
320
  externalLibs: [],
320
- docker: { preRuns: [], postRuns: [] }
321
+ docker: { preRuns: [], postRuns: [] },
322
+ keepFonts: []
321
323
  });
324
+ var normalizeKeepFonts = (keepFonts) => [
325
+ ...new Set((keepFonts ?? []).map((glob) => glob.trim().replace(/^\/+/, "")).filter(Boolean))
326
+ ];
322
327
  var dedupeDockerRuns = (runs) => {
323
328
  const byKey = new Map;
324
329
  for (const run of runs)
@@ -342,6 +347,7 @@ class AkanAppConfig {
342
347
  mobile;
343
348
  hasMobileConfig;
344
349
  secrets;
350
+ assets;
345
351
  syncPageLibs;
346
352
  baseDevEnv;
347
353
  libs;
@@ -372,6 +378,13 @@ class AkanAppConfig {
372
378
  process.env.AKAN_PUBLIC_LOCALES = this.i18n.locales.join(",");
373
379
  this.publicEnv = config?.publicEnv ?? [];
374
380
  this.secrets = config?.secrets ?? [];
381
+ this.assets = {
382
+ pruneFonts: config?.assets?.pruneFonts ?? true,
383
+ keepFonts: [
384
+ ...normalizeKeepFonts(config?.assets?.keepFonts),
385
+ ...libContributions.keepFonts ?? []
386
+ ]
387
+ };
375
388
  this.syncPageLibs = config?.syncPageLibs ?? false;
376
389
  this.hasMobileConfig = Boolean(config.mobile);
377
390
  this.mobile = this.#resolveMobileConfig(config.mobile);
@@ -569,7 +582,8 @@ CMD [${command.map((c) => `"${c}"`).join(",")}]`;
569
582
  docker: {
570
583
  preRuns: libConfigs.flatMap((libConfig) => libConfig?.docker.preRuns ?? []),
571
584
  postRuns: libConfigs.flatMap((libConfig) => libConfig?.docker.postRuns ?? [])
572
- }
585
+ },
586
+ keepFonts: libConfigs.flatMap((libConfig) => (libConfig?.assets.keepFonts ?? []).map((glob) => `libs/${libConfig?.lib.name}/${glob}`))
573
587
  };
574
588
  }
575
589
  #resolveProductionDependencyVersion(lib) {
@@ -669,11 +683,13 @@ class AkanLibConfig {
669
683
  lib;
670
684
  externalLibs;
671
685
  docker;
686
+ assets;
672
687
  plugins;
673
688
  constructor(lib, config, plugins = []) {
674
689
  this.lib = lib;
675
690
  this.externalLibs = config?.externalLibs ?? [];
676
691
  this.docker = { preRuns: config?.docker?.preRuns ?? [], postRuns: config?.docker?.postRuns ?? [] };
692
+ this.assets = { keepFonts: normalizeKeepFonts(config?.assets?.keepFonts) };
677
693
  this.plugins = plugins;
678
694
  }
679
695
  static async from(lib, { bustImportCache = false } = {}) {
@@ -1944,7 +1960,8 @@ class Executor {
1944
1960
  const dir = path5.dirname(writePath);
1945
1961
  if (!await FileSys.dirExists(dir))
1946
1962
  await mkdir(dir, { recursive: true });
1947
- let contentStr = typeof content === "string" ? content : JSON.stringify(content, null, 2);
1963
+ let contentStr = typeof content === "string" ? content : `${JSON.stringify(content, null, 2)}
1964
+ `;
1948
1965
  if (await FileSys.fileExists(writePath)) {
1949
1966
  const currentContent = await FileSys.readText(writePath);
1950
1967
  if (currentContent === contentStr || !overwrite) {
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-4e84gbad.js";
5
+ } from "./index-e31ghfp5.js";
6
6
  import {
7
7
  LibExecutor
8
- } from "./index-vfnmsp1a.js";
8
+ } from "./index-nkwmnqwn.js";
9
9
 
10
10
  // pkgs/@akanjs/cli/semver.ts
11
11
  var stripRangeOperator = (version) => version.replace(/^[\s^~>=<v]+/, "").trim();
@@ -1,22 +1,22 @@
1
1
  // @bun
2
2
  import {
3
3
  RepairRunner
4
- } from "./index-kvqvzgjq.js";
4
+ } from "./index-nj3w0r34.js";
5
5
  import {
6
6
  WorkflowRunner
7
- } from "./index-5nj96dm3.js";
7
+ } from "./index-fahkq20v.js";
8
8
  import {
9
9
  ScalarScript
10
- } from "./index-bgjyden1.js";
10
+ } from "./index-v5fdxdre.js";
11
11
  import {
12
12
  PrimitiveScript
13
- } from "./index-w626d6zw.js";
13
+ } from "./index-rb65xnw9.js";
14
14
  import {
15
15
  ModuleScript
16
- } from "./index-w627vcya.js";
16
+ } from "./index-yg3hxk2k.js";
17
17
  import {
18
18
  isPlaceholderAppId
19
- } from "./index-pbb97b16.js";
19
+ } from "./index-hee7egtm.js";
20
20
  import {
21
21
  AkanContextAnalyzer,
22
22
  akanMcpInstallConfigPaths,
@@ -27,14 +27,14 @@ import {
27
27
  renderDoctorText,
28
28
  resourceList,
29
29
  upsertCodexMcpServerBlock
30
- } from "./index-n2sz0qq3.js";
30
+ } from "./index-va15r8h5.js";
31
31
  import {
32
32
  buildAkanModuleContextIndex,
33
33
  createWorkflowBaselineSummary,
34
34
  createWorkflowStepRegistry,
35
35
  jsonText,
36
36
  toolingRolloutGate
37
- } from "./index-4h99bj2e.js";
37
+ } from "./index-ytaqtc04.js";
38
38
  import {
39
39
  Prompter
40
40
  } from "./index-j37qq1f2.js";
@@ -45,10 +45,10 @@ import {
45
45
  CommandContainer,
46
46
  runner,
47
47
  script
48
- } from "./index-4e84gbad.js";
48
+ } from "./index-e31ghfp5.js";
49
49
  import {
50
50
  AppExecutor
51
- } from "./index-vfnmsp1a.js";
51
+ } from "./index-nkwmnqwn.js";
52
52
 
53
53
  // pkgs/@akanjs/cli/context/context.script.ts
54
54
  import { Logger } from "akanjs/common";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  ModuleScript
4
- } from "./index-w627vcya.js";
4
+ } from "./index-yg3hxk2k.js";
5
5
  import {
6
6
  addFieldUiPolicyForType,
7
7
  coerceFieldDefault,
@@ -34,15 +34,15 @@ import {
34
34
  sourceFile,
35
35
  validationCommandsForTarget,
36
36
  viaBuilderParameterName
37
- } from "./index-4h99bj2e.js";
37
+ } from "./index-ytaqtc04.js";
38
38
  import {
39
39
  script
40
- } from "./index-4e84gbad.js";
40
+ } from "./index-e31ghfp5.js";
41
41
  import {
42
42
  AppExecutor,
43
43
  LibExecutor,
44
44
  ModuleExecutor
45
- } from "./index-vfnmsp1a.js";
45
+ } from "./index-nkwmnqwn.js";
46
46
 
47
47
  // pkgs/@akanjs/cli/primitive/primitive.script.ts
48
48
  import { capitalize } from "akanjs/common";
@@ -1,14 +1,14 @@
1
1
  // @bun
2
2
  import {
3
3
  AkanContextAnalyzer
4
- } from "./index-n2sz0qq3.js";
4
+ } from "./index-va15r8h5.js";
5
5
  import {
6
6
  Prompter
7
7
  } from "./index-j37qq1f2.js";
8
8
  import {
9
9
  runner,
10
10
  script
11
- } from "./index-4e84gbad.js";
11
+ } from "./index-e31ghfp5.js";
12
12
  import {
13
13
  AGENT_BLOCK_END,
14
14
  AGENT_BLOCK_START,
@@ -19,7 +19,7 @@ import {
19
19
  renderRecipeEntries,
20
20
  stampBlockVersion,
21
21
  upsertAgentBlock
22
- } from "./index-vfnmsp1a.js";
22
+ } from "./index-nkwmnqwn.js";
23
23
  import {
24
24
  collectRecipeSources,
25
25
  scanRecipes