@akanjs/cli 3.0.0 → 3.0.2-rc.0

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 (75) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-2vmp9qe0.js → CodeAgent-szbjv4gv.js} +2 -2
  3. package/{CodeTui-5ed6bg2a.js → CodeTui-5nw86ab6.js} +1 -1
  4. package/{agent.command-gn73rhe7.js → agent.command-np1dffkb.js} +5 -5
  5. package/akanCode.js +2 -2
  6. package/{application.command-e968t0hw.js → application.command-fyjy9ryc.js} +8 -8
  7. package/{applicationBuildRunner-64taxseg.js → applicationBuildRunner-etrzfwjj.js} +3 -3
  8. package/buildBatch.proc.js +4 -4
  9. package/{cloud.command-0jm301rr.js → cloud.command-c0rnwy65.js} +10 -10
  10. package/cloud.script-6ba8e9v8.js +20 -0
  11. package/{code.command-18kcm7hq.js → code.command-hmtx14b2.js} +6 -6
  12. package/{context.command-trd9bn18.js → context.command-6aqvdx43.js} +13 -13
  13. package/context.runner-hnkvv3z3.js +21 -0
  14. package/{guideline.command-bdmdn2de.js → guideline.command-axvf68gc.js} +2 -2
  15. package/guidelines/conventions/conventions.instruction.md +93 -17
  16. package/guidelines/queryRule/queryRule.instruction.md +4 -2
  17. package/guidelines/runtimeRule/runtimeRule.instruction.md +10 -5
  18. package/guidelines/transportRule/transportRule.instruction.md +40 -4
  19. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +1 -1
  20. package/incrementalBuilder.proc.js +3 -3
  21. package/{index-mgxpx3f2.js → index-1bjkfvm9.js} +29 -27
  22. package/{index-wprnsjms.js → index-1gs9g12n.js} +3 -3
  23. package/{index-by9pxkr0.js → index-3xmzr1p1.js} +2 -2
  24. package/{index-jmrn54tt.js → index-50jjwg8y.js} +1 -1
  25. package/{index-3w94e7n3.js → index-50wb2a26.js} +315 -94
  26. package/{index-p993efkq.js → index-61mmsdjg.js} +9 -8
  27. package/{index-kqabytj7.js → index-6keyf4sg.js} +4 -4
  28. package/{index-f3c78nd6.js → index-bsv901fd.js} +7 -7
  29. package/{index-hsmtysz4.js → index-cb6yc5mb.js} +2 -2
  30. package/{index-kcdj1z5v.js → index-d95tfg3n.js} +15 -11
  31. package/{index-4npz05nm.js → index-f4e08ptp.js} +4 -4
  32. package/{index-mbxbhay5.js → index-g38nhv87.js} +1 -1
  33. package/{index-pmhqttv3.js → index-gvpvxdm1.js} +5 -5
  34. package/{index-y3mphr1m.js → index-h9ht6s60.js} +1 -1
  35. package/{index-93j60em0.js → index-hp3stk1m.js} +3 -3
  36. package/{index-drehwpdt.js → index-hxnnfy57.js} +6 -5
  37. package/{index-abxpehf8.js → index-j38qkvkk.js} +7 -7
  38. package/{index-0wpybxtr.js → index-jb0hmt3k.js} +3 -3
  39. package/{index-gbggbqcp.js → index-jk9xnck6.js} +33 -11
  40. package/{index-6he6gvfg.js → index-krjcg4y6.js} +29 -11
  41. package/{index-vpj42xwt.js → index-q6ft9fkc.js} +4 -4
  42. package/{index-48k96p55.js → index-senscydg.js} +6 -0
  43. package/{index-tqm7jjcn.js → index-xwprn9nr.js} +1 -1
  44. package/{index-yg7jhz8x.js → index-zwd84m0w.js} +4 -4
  45. package/{index-9z771ptz.js → index-zyw622y1.js} +12 -2
  46. package/index.js +21 -21
  47. package/{library.command-9h749a1x.js → library.command-9m2rdwwz.js} +3 -3
  48. package/{localRegistry.command-2bqqhxyz.js → localRegistry.command-vacc2njh.js} +9 -9
  49. package/{module.command-nv8nzgft.js → module.command-q63dffya.js} +5 -5
  50. package/{package.command-mq4bggp6.js → package.command-y2jh0m99.js} +3 -3
  51. package/package.json +2 -2
  52. package/{page.command-j639n707.js → page.command-f3e4cwhh.js} +3 -3
  53. package/{primitive.command-kz6849th.js → primitive.command-r4kq75qj.js} +6 -6
  54. package/{quality.command-4hyabwkb.js → quality.command-f7gzh26z.js} +9 -2
  55. package/{repair.command-a9awpbqr.js → repair.command-0qmyr6qa.js} +5 -5
  56. package/{scalar.command-ma4fpm9m.js → scalar.command-kddn7av4.js} +4 -4
  57. package/{subspace.command-3k2pmrs4.js → subspace.command-j7ayp382.js} +5 -7
  58. package/templates/app/ui/Recipe/jellyButton.ts +1 -0
  59. package/templates/facetIndex/index.ts +21 -6
  60. package/templates/lib/dict.ts +9 -1
  61. package/templates/lib/srv.ts +2 -3
  62. package/templates/libRoot/common/index.ts +2 -7
  63. package/templates/libRoot/srvkit/index.ts +2 -7
  64. package/templates/libRoot/ui/index.ts +2 -7
  65. package/templates/libRoot/webkit/index.ts +2 -7
  66. package/templates/moduleRoot/index.tsx +3 -3
  67. package/{tunnel.command-xwr46b66.js → tunnel.command-b3ymdk4f.js} +2 -2
  68. package/{workflow.command-t7wqe4h7.js → workflow.command-z1srcdfw.js} +10 -10
  69. package/{workspace.command-4derhzrh.js → workspace.command-17c46dbp.js} +21 -21
  70. package/cloud.script-nemnzjpv.js +0 -20
  71. package/context.runner-y5hwh673.js +0 -21
  72. package/index-bjwxs904.js +0 -77
  73. package/templates/libRoot/common/commonLogic.ts +0 -14
  74. package/templates/libRoot/srvkit/backendLogic.ts +0 -13
  75. package/templates/libRoot/webkit/frontendLogic.ts +0 -13
@@ -242,6 +242,7 @@ const defaultFonts = userFonts.filter((font) => font.default);
242
242
  if (defaultFonts.length > 1) throw new Error("[route-convention] only one default font is allowed per root layout");
243
243
  const defaultFont = defaultFonts[0];
244
244
  const defaultFontClassName = defaultFont ? (defaultFont.className ?? \`font-\${defaultFont.name}\`) : undefined;
245
+ export const theme = userLayout.theme ?? inheritedLayout.theme;
245
246
 
246
247
  ${layoutExports}(
247
248
  <System.Provider
@@ -251,7 +252,7 @@ ${layoutExports}(
251
252
  ` : ""}params={params}
252
253
  manifest={userLayout.manifest ?? inheritedLayout.manifest}
253
254
  env={env}
254
- theme={userLayout.theme ?? inheritedLayout.theme}
255
+ theme={theme}
255
256
  fonts={loadFonts(userFonts)}
256
257
  className={defaultFontClassName}
257
258
  layoutStyle={userLayout.layoutStyle ?? inheritedLayout.layoutStyle}
@@ -516,7 +517,7 @@ import {
516
517
  stat as stat2,
517
518
  symlink
518
519
  } from "fs/promises";
519
- import path9 from "path";
520
+ import path10 from "path";
520
521
  import { pathToFileURL } from "url";
521
522
  import {
522
523
  capitalize,
@@ -1043,8 +1044,9 @@ class AkanAppConfig {
1043
1044
  "activity",
1044
1045
  "files"
1045
1046
  ],
1046
- desktop: ["indexPath", "server", "recovery", "window", "screenCapture", "entitlements"],
1047
+ desktop: ["indexPath", "server", "recovery", "window", "screenCapture", "entitlements", "dmg"],
1047
1048
  desktopServer: ["omit"],
1049
+ dmg: ["background", "background2x", "window", "iconSize", "textSize", "app", "applications"],
1048
1050
  deepLinks: ["schemes", "domains"]
1049
1051
  };
1050
1052
  static #movedKeys = {
@@ -1073,6 +1075,7 @@ class AkanAppConfig {
1073
1075
  check(settings.android, AkanAppConfig.#nativeKeys.android, `${where}.android`, "android");
1074
1076
  check(settings.desktop, AkanAppConfig.#nativeKeys.desktop, `${where}.desktop`, "desktop");
1075
1077
  check(settings.desktop?.server, AkanAppConfig.#nativeKeys.desktopServer, `${where}.desktop.server`, "desktopServer");
1078
+ check(settings.desktop?.dmg, AkanAppConfig.#nativeKeys.dmg, `${where}.desktop.dmg`, "dmg");
1076
1079
  check(settings.deepLinks, AkanAppConfig.#nativeKeys.deepLinks, `${where}.deepLinks`, "deepLinks");
1077
1080
  }
1078
1081
  static #androidFilePattern = /^(?:res\/[^/]+\/[^/]+|assets\/.+)$/;
@@ -1351,10 +1354,85 @@ var shiftBuildNum = async (app, delta) => {
1351
1354
  };
1352
1355
  var increaseBuildNum = async (app) => await shiftBuildNum(app, 1);
1353
1356
  var decreaseBuildNum = async (app) => await shiftBuildNum(app, -1);
1357
+ // pkgs/@akanjs/devkit/jsonFormatter.ts
1358
+ import path6 from "path";
1359
+
1360
+ class JsonFormatter {
1361
+ static lineWidth = 120;
1362
+ static stringify(value, filePath) {
1363
+ const json = JSON.stringify(value, null, 2);
1364
+ if (path6.basename(filePath) === "package.json")
1365
+ return `${json}
1366
+ `;
1367
+ return `${JsonFormatter.#print(JSON.parse(json), 0, { column: 0, trailing: 0 })}
1368
+ `;
1369
+ }
1370
+ static #print(value, depth, placement) {
1371
+ if (Array.isArray(value))
1372
+ return JsonFormatter.#printArray(value, depth, placement);
1373
+ if (value === null || typeof value !== "object")
1374
+ return JSON.stringify(value);
1375
+ const entries = Object.entries(value);
1376
+ if (!entries.length)
1377
+ return "{}";
1378
+ const indent = " ".repeat(depth + 1);
1379
+ const members = entries.map(([key, member], idx) => {
1380
+ const prefix = `${indent}${JSON.stringify(key)}: `;
1381
+ const trailing = idx < entries.length - 1 ? 1 : 0;
1382
+ return `${prefix}${JsonFormatter.#print(member, depth + 1, { column: Bun.stringWidth(prefix), trailing })}`;
1383
+ });
1384
+ return `{
1385
+ ${members.join(`,
1386
+ `)}
1387
+ ${" ".repeat(depth)}}`;
1388
+ }
1389
+ static #printArray(items, depth, { column, trailing }) {
1390
+ if (!items.length)
1391
+ return "[]";
1392
+ const flat = JsonFormatter.#flat(items);
1393
+ if (flat !== null && column + Bun.stringWidth(flat) + trailing <= JsonFormatter.lineWidth)
1394
+ return flat;
1395
+ const indent = " ".repeat(depth + 1);
1396
+ const isLast = (idx) => idx === items.length - 1;
1397
+ const body = items.every((item) => typeof item === "number") ? JsonFormatter.#fill(items.map((item, idx) => `${JSON.stringify(item)}${isLast(idx) ? "" : ","}`), indent) : items.map((item, idx) => {
1398
+ const placement = { column: indent.length, trailing: isLast(idx) ? 0 : 1 };
1399
+ return `${indent}${JsonFormatter.#print(item, depth + 1, placement)}`;
1400
+ }).join(`,
1401
+ `);
1402
+ return `[
1403
+ ${body}
1404
+ ${" ".repeat(depth)}]`;
1405
+ }
1406
+ static #fill(tokens, indent) {
1407
+ const lines = [];
1408
+ let line = "";
1409
+ for (const token of tokens) {
1410
+ if (line && Bun.stringWidth(line) + 1 + Bun.stringWidth(token) <= JsonFormatter.lineWidth) {
1411
+ line = `${line} ${token}`;
1412
+ continue;
1413
+ }
1414
+ if (line)
1415
+ lines.push(line);
1416
+ line = `${indent}${token}`;
1417
+ }
1418
+ return [...lines, line].join(`
1419
+ `);
1420
+ }
1421
+ static #flat(value) {
1422
+ if (Array.isArray(value)) {
1423
+ const items = value.map((item) => JsonFormatter.#flat(item));
1424
+ return items.includes(null) ? null : `[${items.join(", ")}]`;
1425
+ }
1426
+ if (value === null || typeof value !== "object")
1427
+ return JSON.stringify(value);
1428
+ return Object.keys(value).length ? null : "{}";
1429
+ }
1430
+ }
1431
+
1354
1432
  // pkgs/@akanjs/devkit/linter.ts
1355
1433
  import { spawn } from "child_process";
1356
1434
  import { existsSync, readFileSync } from "fs";
1357
- import path6 from "path";
1435
+ import path7 from "path";
1358
1436
  import chalk from "chalk";
1359
1437
  var parseBiomeReport = (output) => {
1360
1438
  for (let start = output.indexOf("{");start !== -1; start = output.indexOf("{", start + 1)) {
@@ -1420,13 +1498,13 @@ class Linter {
1420
1498
  #biomeBin;
1421
1499
  constructor(cwdPath) {
1422
1500
  this.lintRoot = this.#findBiomeRootPath(cwdPath);
1423
- this.configPath = Linter.#configPathIn(this.lintRoot) ?? path6.join(this.lintRoot, "biome.json");
1424
- const localBiomeBin = path6.join(this.lintRoot, "node_modules", ".bin", Linter.biomeBinName);
1501
+ this.configPath = Linter.#configPathIn(this.lintRoot) ?? path7.join(this.lintRoot, "biome.json");
1502
+ const localBiomeBin = path7.join(this.lintRoot, "node_modules", ".bin", Linter.biomeBinName);
1425
1503
  this.#biomeBin = existsSync(localBiomeBin) ? localBiomeBin : "biome";
1426
1504
  }
1427
1505
  static #configPathIn(dir) {
1428
1506
  for (const fileName of BIOME_CONFIG_FILES) {
1429
- const configPath = path6.join(dir, fileName);
1507
+ const configPath = path7.join(dir, fileName);
1430
1508
  if (existsSync(configPath))
1431
1509
  return configPath;
1432
1510
  }
@@ -1435,19 +1513,19 @@ class Linter {
1435
1513
  #findBiomeRootPath(dir) {
1436
1514
  if (Linter.#configPathIn(dir))
1437
1515
  return dir;
1438
- const parentDir = path6.dirname(dir);
1516
+ const parentDir = path7.dirname(dir);
1439
1517
  if (parentDir === dir)
1440
1518
  throw new Error(`biome.json not found from ${dir}`);
1441
1519
  return this.#findBiomeRootPath(parentDir);
1442
1520
  }
1443
1521
  #toBiomePath(filePath) {
1444
- const relativePath = path6.relative(this.lintRoot, filePath);
1445
- if (!relativePath.startsWith("..") && !path6.isAbsolute(relativePath))
1522
+ const relativePath = path7.relative(this.lintRoot, filePath);
1523
+ if (!relativePath.startsWith("..") && !path7.isAbsolute(relativePath))
1446
1524
  return relativePath;
1447
1525
  return filePath;
1448
1526
  }
1449
1527
  #resolveFilePath(filePath) {
1450
- return path6.isAbsolute(filePath) ? filePath : path6.join(this.lintRoot, filePath);
1528
+ return path7.isAbsolute(filePath) ? filePath : path7.join(this.lintRoot, filePath);
1451
1529
  }
1452
1530
  async#runBiome(args, input) {
1453
1531
  return await new Promise((resolve, reject) => {
@@ -1472,7 +1550,7 @@ class Linter {
1472
1550
  const diagnosticPath = diagnostic.location?.path;
1473
1551
  if (!diagnosticPath)
1474
1552
  return fallbackFilePath;
1475
- return path6.isAbsolute(diagnosticPath) ? diagnosticPath : path6.join(this.lintRoot, diagnosticPath);
1553
+ return path7.isAbsolute(diagnosticPath) ? diagnosticPath : path7.join(this.lintRoot, diagnosticPath);
1476
1554
  }
1477
1555
  #createLintMessage(diagnostic) {
1478
1556
  const start = diagnostic.location?.start;
@@ -1678,9 +1756,137 @@ ${errorText}, ${warningText} found`];
1678
1756
  }
1679
1757
  }
1680
1758
 
1759
+ // pkgs/@akanjs/devkit/libSource.ts
1760
+ class LibSource {
1761
+ static manifestKey = "akan";
1762
+ static unhashedDirs = ["env"];
1763
+ #lib;
1764
+ constructor(lib) {
1765
+ this.#lib = lib;
1766
+ }
1767
+ get #prefix() {
1768
+ return `libs/${this.#lib.name}/`;
1769
+ }
1770
+ #isHashed(file) {
1771
+ const relative = file.slice(this.#prefix.length);
1772
+ return !LibSource.unhashedDirs.includes(relative.split("/")[0] ?? "");
1773
+ }
1774
+ static unstamped(manifestContent) {
1775
+ const manifest = JSON.parse(manifestContent);
1776
+ delete manifest[LibSource.manifestKey];
1777
+ return JSON.stringify(manifest);
1778
+ }
1779
+ static async hashFiles(files, manifestFile, read) {
1780
+ const hasher = new Bun.CryptoHasher("sha256");
1781
+ for (const file of files) {
1782
+ const content = await read(file);
1783
+ hasher.update(file);
1784
+ hasher.update("\x00");
1785
+ hasher.update(file === manifestFile ? LibSource.unstamped(content) : content);
1786
+ hasher.update("\x00");
1787
+ }
1788
+ return hasher.digest("hex").slice(0, 32);
1789
+ }
1790
+ async computeHash() {
1791
+ const files = (await this.#lib.workspace.listGitFiles([`libs/${this.#lib.name}`], { untracked: true })).filter((file) => this.#isHashed(file));
1792
+ return await LibSource.hashFiles(files, `${this.#prefix}package.json`, (file) => this.#lib.workspace.readFile(file));
1793
+ }
1794
+ async read() {
1795
+ const manifest = await this.#lib.getPackageJson();
1796
+ const akan = manifest[LibSource.manifestKey];
1797
+ return akan?.source ?? null;
1798
+ }
1799
+ async write({ origin, sha }) {
1800
+ const [manifest, hash] = await Promise.all([this.#lib.getPackageJson(), this.computeHash()]);
1801
+ const akan = manifest[LibSource.manifestKey] ?? {};
1802
+ const stamp = { origin, sha, hash, syncedAt: new Date().toISOString() };
1803
+ await this.#lib.setPackageJson({ ...manifest, [LibSource.manifestKey]: { ...akan, source: stamp } });
1804
+ return stamp;
1805
+ }
1806
+ async syncStamp({ origin, sha }) {
1807
+ const [current, hash] = await Promise.all([this.read(), this.computeHash()]);
1808
+ if (current?.origin === origin && current.sha === sha && current.hash === hash)
1809
+ return { stamp: current, changed: false };
1810
+ return { stamp: await this.write({ origin, sha }), changed: true };
1811
+ }
1812
+ async status() {
1813
+ const [stamp, hash] = await Promise.all([this.read(), this.computeHash()]);
1814
+ const drift = !stamp ? "unstamped" : stamp.hash === hash ? "clean" : "drifted";
1815
+ return { lib: this.#lib.name, drift, stamp, hash };
1816
+ }
1817
+ }
1818
+ function formatLibStatuses(statuses) {
1819
+ const marks = { clean: "clean ", drifted: "DRIFTED ", unstamped: "unstamped" };
1820
+ const sections = [
1821
+ "Akan Library Source Status",
1822
+ "",
1823
+ ...statuses.map((status) => {
1824
+ const origin = status.stamp ? `${status.stamp.origin}@${status.stamp.sha}` : "no akan.source in package.json";
1825
+ return ` ${marks[status.drift]} libs/${status.lib} ${origin}`;
1826
+ }),
1827
+ "",
1828
+ `drifted: ${statuses.filter((status) => status.drift === "drifted").length} / ${statuses.length}`
1829
+ ];
1830
+ return sections.join(`
1831
+ `);
1832
+ }
1833
+
1834
+ // pkgs/@akanjs/devkit/manifestDependencies.ts
1835
+ class ManifestDependencies {
1836
+ #root;
1837
+ #runtime;
1838
+ #typeOnly;
1839
+ #isKept;
1840
+ constructor(root, { runtime, typeOnly }, isKept) {
1841
+ this.#root = root;
1842
+ this.#runtime = new Set(runtime);
1843
+ this.#typeOnly = new Set(typeOnly);
1844
+ this.#isKept = isKept;
1845
+ }
1846
+ static keptBy(manifest) {
1847
+ const { keepDependencies } = manifest[LibSource.manifestKey] ?? {};
1848
+ return Array.isArray(keepDependencies) ? keepDependencies.filter((dep) => typeof dep === "string") : [];
1849
+ }
1850
+ realign(manifest) {
1851
+ const removed = [];
1852
+ const unverifiable = [];
1853
+ const dependencies = {};
1854
+ for (const [dep, version] of Object.entries(manifest.dependencies ?? {})) {
1855
+ if (this.#typeOnly.has(dep))
1856
+ continue;
1857
+ const rootVersion = this.#rootVersionOf(dep);
1858
+ if (!rootVersion) {
1859
+ unverifiable.push(dep);
1860
+ dependencies[dep] = version;
1861
+ } else if (this.#runtime.has(dep) || this.#isKept(dep))
1862
+ dependencies[dep] = rootVersion;
1863
+ else
1864
+ removed.push(dep);
1865
+ }
1866
+ const runtimeOfRootDependencies = [...this.#runtime].filter((dep) => this.#root.dependencies?.[dep]);
1867
+ this.#append(dependencies, runtimeOfRootDependencies);
1868
+ const devDependencies = {};
1869
+ for (const [dep, version] of Object.entries(manifest.devDependencies ?? {}))
1870
+ if (!Object.hasOwn(dependencies, dep))
1871
+ devDependencies[dep] = this.#rootVersionOf(dep) ?? version;
1872
+ this.#append(devDependencies, [...this.#typeOnly]);
1873
+ return { dependencies, devDependencies, removed, unverifiable };
1874
+ }
1875
+ #append(map, deps) {
1876
+ for (const dep of deps.filter((dep) => !Object.hasOwn(map, dep)).sort((a, b) => a < b ? -1 : 1)) {
1877
+ const rootVersion = this.#rootVersionOf(dep);
1878
+ if (rootVersion)
1879
+ map[dep] = rootVersion;
1880
+ }
1881
+ }
1882
+ #rootVersionOf(dep) {
1883
+ return this.#root.dependencies?.[dep] ?? this.#root.devDependencies?.[dep];
1884
+ }
1885
+ }
1886
+
1681
1887
  // pkgs/@akanjs/devkit/repoIdentity.ts
1682
1888
  import { execFileSync } from "child_process";
1683
- import path7 from "path";
1889
+ import path8 from "path";
1684
1890
  var resolved = new Map;
1685
1891
  var readRemoteName = (workspaceRoot) => {
1686
1892
  try {
@@ -1698,13 +1904,13 @@ var resolveRepoName = (workspaceRoot) => {
1698
1904
  const cached = resolved.get(workspaceRoot);
1699
1905
  if (cached)
1700
1906
  return cached;
1701
- const repoName = readRemoteName(workspaceRoot) ?? path7.basename(workspaceRoot);
1907
+ const repoName = readRemoteName(workspaceRoot) ?? path8.basename(workspaceRoot);
1702
1908
  resolved.set(workspaceRoot, repoName);
1703
1909
  return repoName;
1704
1910
  };
1705
1911
 
1706
1912
  // pkgs/@akanjs/devkit/scanInfo.ts
1707
- import path8 from "path";
1913
+ import path9 from "path";
1708
1914
 
1709
1915
  // pkgs/@akanjs/devkit/workspaceLayout.ts
1710
1916
  var appRootAllowedFiles = new Set([
@@ -1777,6 +1983,14 @@ var libFacetRootAllowedFiles = new Set([
1777
1983
  ]);
1778
1984
  var libFacetRootTestPattern = /^[A-Za-z][A-Za-z0-9_-]*\.signal\.(test|spec)\.(ts|tsx)$/;
1779
1985
  var isAllowedLibFacetRootFile = (filename) => libFacetRootAllowedFiles.has(filename) || libFacetRootTestPattern.test(filename);
1986
+ var barrelFacetDirs = ["ui", "webkit", "srvkit", "common", "plugin"];
1987
+ var barrelShadowingIndexFiles = new Set(["index.tsx", "index.jsx", "index.mts"]);
1988
+ var facetIndexShadowOf = (sysRelativePath) => {
1989
+ const [facet, filename = "", ...nested] = sysRelativePath.split("/");
1990
+ if (nested.length || !barrelShadowingIndexFiles.has(filename) || !barrelFacetDirs.some((dir) => dir === facet))
1991
+ return null;
1992
+ return `shadows the generated ${facet}/index.ts: Bun loads ${filename} and TypeScript checks index.ts, so a name only ` + `the generated barrel exports typechecks and is undefined at runtime. Delete it, since the generated barrel ` + `re-exports every file and folder in ${facet}/; a namespace it builds belongs in ${facet}/<Folder>/index.tsx`;
1993
+ };
1780
1994
  var retiredAppRootEntries = new Set([
1781
1995
  "android",
1782
1996
  "ios",
@@ -1785,7 +1999,7 @@ var retiredAppRootEntries = new Set([
1785
1999
  "capacitor.config.js",
1786
2000
  "capacitor.config.json"
1787
2001
  ]);
1788
- var rootEntryHintOf = (type, name) => type === "app" && retiredAppRootEntries.has(name) ? "a Capacitor-era entry; the native runtime generates its projects under .akan/native/<target>, so delete it" : null;
2002
+ var rootEntryHintOf = (type, name) => type === "app" && retiredAppRootEntries.has(name) ? "a Capacitor-era entry; the native runtime generates its projects under dist/native/<app>/<target>, so delete it" : null;
1789
2003
  var isScannedRootEntry = (type, name) => !name.startsWith(".") || rootAllowedDirs[type].has(name);
1790
2004
 
1791
2005
  // pkgs/@akanjs/devkit/scanInfo.ts
@@ -1815,9 +2029,9 @@ var moduleUiFileTypes = {
1815
2029
  scalar: new Set(["Template", "Unit"])
1816
2030
  };
1817
2031
  var createDependencyScanner = async (exec) => (await import("./dependencyScanner-06z2dmrr.js")).TypeScriptDependencyScanner.from(exec);
1818
- var getScanPath = (exec, relativePath) => path8.posix.join(`${exec.type}s`, exec.name, relativePath.split(path8.sep).join("/"));
2032
+ var getScanPath = (exec, relativePath) => path9.posix.join(`${exec.type}s`, exec.name, relativePath.split(path9.sep).join("/"));
1819
2033
  var getModuleNameFromPath = (kind, modulePath) => {
1820
- const dirname = path8.basename(modulePath);
2034
+ const dirname = path9.basename(modulePath);
1821
2035
  return kind === "service" ? dirname.replace(/^_+/, "") : dirname;
1822
2036
  };
1823
2037
  async function assertScanConvention(exec, libRoot) {
@@ -1834,22 +2048,28 @@ async function assertScanConvention(exec, libRoot) {
1834
2048
  for (const dirname of dirs)
1835
2049
  if (!allowedRootDirs.has(dirname))
1836
2050
  addViolation(dirname, rootEntryHintOf(exec.type, dirname) ?? `unsupported ${exec.type} root folder`);
2051
+ for (const facet of barrelFacetDirs)
2052
+ for (const filename of await exec.readdir(facet)) {
2053
+ const shadow = facetIndexShadowOf(`${facet}/${filename}`);
2054
+ if (shadow)
2055
+ addViolation(path9.join(facet, filename), shadow);
2056
+ }
1837
2057
  if (exec.type === "lib")
1838
2058
  for (const { relativePath, reason } of await exec.getPageConventionViolations())
1839
2059
  addViolation(relativePath, reason);
1840
2060
  for (const filename of libRoot.files)
1841
2061
  if (!isAllowedLibFacetRootFile(filename))
1842
- addViolation(path8.join("lib", filename), "unsupported lib facet root file");
2062
+ addViolation(path9.join("lib", filename), "unsupported lib facet root file");
1843
2063
  for (const dirname of libRoot.dirs)
1844
2064
  if (dirname.startsWith("__") && !internalLibDirs.has(dirname))
1845
- addViolation(path8.join("lib", dirname), "unsupported internal lib folder");
2065
+ addViolation(path9.join("lib", dirname), "unsupported internal lib folder");
1846
2066
  const databaseDirs = libRoot.dirs.filter((dirname) => !dirname.startsWith("_"));
1847
2067
  const serviceDirs = libRoot.dirs.filter((dirname) => dirname.startsWith("_") && !dirname.startsWith("__"));
1848
2068
  const scalarDirs = await exec.readdir("lib/__scalar");
1849
2069
  await Promise.all([
1850
- ...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database", path8.join("lib", dirname))),
1851
- ...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service", path8.join("lib", dirname))),
1852
- ...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar", path8.join("lib/__scalar", dirname)))
2070
+ ...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database", path9.join("lib", dirname))),
2071
+ ...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service", path9.join("lib", dirname))),
2072
+ ...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar", path9.join("lib/__scalar", dirname)))
1853
2073
  ]);
1854
2074
  if (violations.length > 0) {
1855
2075
  throw new Error(`[scan-convention]
@@ -1861,11 +2081,11 @@ async function validateModuleFiles(exec, violations, kind, modulePath) {
1861
2081
  const { files, dirs } = await exec.getFilesAndDirs(modulePath);
1862
2082
  const moduleName = getModuleNameFromPath(kind, modulePath);
1863
2083
  dirs.forEach((dirname) => {
1864
- violations.push(`${getScanPath(exec, path8.join(modulePath, dirname))}: unsupported module folder`);
2084
+ violations.push(`${getScanPath(exec, path9.join(modulePath, dirname))}: unsupported module folder`);
1865
2085
  });
1866
2086
  const uiModuleName = moduleName[0].toUpperCase() + moduleName.slice(1);
1867
2087
  for (const filename of files) {
1868
- const scanPath = getScanPath(exec, path8.join(modulePath, filename));
2088
+ const scanPath = getScanPath(exec, path9.join(modulePath, filename));
1869
2089
  if (filename === "index.ts" || filename === "index.tsx" || /\.(test|spec)\.(ts|tsx)$/.test(filename))
1870
2090
  continue;
1871
2091
  if (filename === `${moduleName}.abstract.md`)
@@ -1938,16 +2158,16 @@ class ScanInfo {
1938
2158
  }
1939
2159
  };
1940
2160
  await Promise.all([
1941
- ...databaseDirs.map((name) => collect(path8.join("lib", name), name, "databases")),
1942
- ...serviceDirs.map((dirname) => collect(path8.join("lib", dirname), dirname.slice(1), "services")),
1943
- ...scalarDirs.map((name) => collect(path8.join("lib/__scalar", name), name, "scalars"))
2161
+ ...databaseDirs.map((name) => collect(path9.join("lib", name), name, "databases")),
2162
+ ...serviceDirs.map((dirname) => collect(path9.join("lib", dirname), dirname.slice(1), "services")),
2163
+ ...scalarDirs.map((name) => collect(path9.join("lib/__scalar", name), name, "scalars"))
1944
2164
  ]);
1945
2165
  const routes = exec.type === "lib" ? [] : await exec.getPageKeys();
1946
2166
  const common = {
1947
2167
  name: exec.name,
1948
2168
  type: exec.type,
1949
2169
  repoName: exec.workspace.repoName,
1950
- serveDomain: WorkspaceExecutor.getBaseDevEnv(path8.join(exec.workspace.workspaceRoot, ".env")).serveDomain,
2170
+ serveDomain: WorkspaceExecutor.getBaseDevEnv(path9.join(exec.workspace.workspaceRoot, ".env")).serveDomain,
1951
2171
  files,
1952
2172
  libDeps,
1953
2173
  pkgDeps,
@@ -2329,10 +2549,10 @@ class Executor {
2329
2549
  return this.#settle(proc, target, { redStderr: true }).then(({ code, signal }) => ({ code, signal }));
2330
2550
  }
2331
2551
  getPath(filePath) {
2332
- if (path9.isAbsolute(filePath))
2552
+ if (path10.isAbsolute(filePath))
2333
2553
  return filePath;
2334
2554
  if (filePath.startsWith("."))
2335
- return path9.join(this.cwdPath, filePath);
2555
+ return path10.join(this.cwdPath, filePath);
2336
2556
  const baseParts = this.cwdPath.split(/[\\/]/).filter(Boolean);
2337
2557
  const targetParts = filePath.split(/[\\/]/).filter(Boolean);
2338
2558
  let overlapLength = 0;
@@ -2346,7 +2566,7 @@ class Executor {
2346
2566
  if (isOverlap)
2347
2567
  overlapLength = i;
2348
2568
  }
2349
- return path9.join(this.cwdPath, ...targetParts.slice(overlapLength));
2569
+ return path10.join(this.cwdPath, ...targetParts.slice(overlapLength));
2350
2570
  }
2351
2571
  async mkdir(dirPath) {
2352
2572
  const writePath = this.getPath(dirPath);
@@ -2387,7 +2607,7 @@ class Executor {
2387
2607
  return this;
2388
2608
  }
2389
2609
  async removeDir(dirPath) {
2390
- const readPath = path9.join(this.getPath(dirPath), ".");
2610
+ const readPath = path10.join(this.getPath(dirPath), ".");
2391
2611
  if (await FileSys2.entryExists(readPath))
2392
2612
  await rm3(readPath, { recursive: true, force: true });
2393
2613
  this.logger.verbose(`Remove directory ${readPath}`);
@@ -2395,11 +2615,10 @@ class Executor {
2395
2615
  }
2396
2616
  async writeFile(filePath, content, { overwrite = true, silent = false } = {}) {
2397
2617
  const writePath = this.getPath(filePath);
2398
- const dir = path9.dirname(writePath);
2618
+ const dir = path10.dirname(writePath);
2399
2619
  if (!await FileSys2.dirExists(dir))
2400
2620
  await mkdir2(dir, { recursive: true });
2401
- let contentStr = typeof content === "string" ? content : `${JSON.stringify(content, null, 2)}
2402
- `;
2621
+ let contentStr = typeof content === "string" ? content : JsonFormatter.stringify(content, writePath);
2403
2622
  if (await FileSys2.fileExists(writePath)) {
2404
2623
  const currentContent = await FileSys2.readText(writePath);
2405
2624
  if (currentContent === contentStr || !overwrite) {
@@ -2421,7 +2640,7 @@ class Executor {
2421
2640
  await this.writeFile(filePath, content);
2422
2641
  }
2423
2642
  async getLocalFile(targetPath) {
2424
- const filePath = path9.isAbsolute(targetPath) ? targetPath : targetPath.replace(this.cwdPath, "");
2643
+ const filePath = path10.isAbsolute(targetPath) ? targetPath : targetPath.replace(this.cwdPath, "");
2425
2644
  const content = await this.readFile(filePath);
2426
2645
  return { filePath, content };
2427
2646
  }
@@ -2508,9 +2727,9 @@ class Executor {
2508
2727
  const result = await getContent.default(scanInfo ?? null, dict, options);
2509
2728
  if (result === null)
2510
2729
  return null;
2511
- const filename = typeof result === "object" ? result.filename : path9.basename(targetPath).replace(".js", ".ts");
2730
+ const filename = typeof result === "object" ? result.filename : path10.basename(targetPath).replace(".js", ".ts");
2512
2731
  const content = typeof result === "object" ? result.content : result;
2513
- const convertedTargetPath = convertPath(`${path9.dirname(targetPath)}/${filename}`);
2732
+ const convertedTargetPath = convertPath(`${path10.dirname(targetPath)}/${filename}`);
2514
2733
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2515
2734
  return this.writeFile(convertedTargetPath, content, { overwrite });
2516
2735
  } else if (targetPath.endsWith(".template")) {
@@ -2519,10 +2738,10 @@ class Executor {
2519
2738
  const convertedContent = Object.entries(dict).reduce((data, [key, value]) => data.replace(new RegExp(`<%= ${key} %>`, "g"), value), content);
2520
2739
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2521
2740
  return this.writeFile(convertedTargetPath, convertedContent, { overwrite });
2522
- } else if (staticTemplateFileExtensions.has(path9.extname(targetPath).toLowerCase())) {
2741
+ } else if (staticTemplateFileExtensions.has(path10.extname(targetPath).toLowerCase())) {
2523
2742
  const convertedTargetPath = convertPath(targetPath);
2524
2743
  const writePath = this.getPath(convertedTargetPath);
2525
- const dirname = path9.dirname(writePath);
2744
+ const dirname = path10.dirname(writePath);
2526
2745
  if (!await FileSys2.dirExists(dirname))
2527
2746
  await mkdir2(dirname, { recursive: true });
2528
2747
  await copyFile(templatePath, writePath);
@@ -2544,7 +2763,7 @@ class Executor {
2544
2763
  if ((await stat2(templatePath)).isFile()) {
2545
2764
  const fileContent = await this.#applyTemplateFile({
2546
2765
  templatePath,
2547
- targetPath: path9.join(basePath, path9.basename(templatePath)),
2766
+ targetPath: path10.join(basePath, path10.basename(templatePath)),
2548
2767
  scanInfo,
2549
2768
  overwrite
2550
2769
  }, dict, options);
@@ -2552,19 +2771,19 @@ class Executor {
2552
2771
  } else {
2553
2772
  const subdirs = await readDirEntries(templatePath);
2554
2773
  const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
2555
- const subpath = path9.join(templatePath, subdir);
2774
+ const subpath = path10.join(templatePath, subdir);
2556
2775
  if ((await stat2(subpath)).isFile()) {
2557
2776
  const fileContent = await this.#applyTemplateFile({
2558
2777
  templatePath: subpath,
2559
- targetPath: path9.join(basePath, subdir),
2778
+ targetPath: path10.join(basePath, subdir),
2560
2779
  scanInfo,
2561
2780
  overwrite
2562
2781
  }, dict, options);
2563
2782
  return fileContent ? [fileContent] : [];
2564
2783
  } else
2565
2784
  return await this._applyTemplate({
2566
- basePath: path9.join(basePath, subdir),
2567
- template: path9.join(template, subdir),
2785
+ basePath: path10.join(basePath, subdir),
2786
+ template: path10.join(template, subdir),
2568
2787
  scanInfo,
2569
2788
  dict,
2570
2789
  overwrite,
@@ -2576,8 +2795,8 @@ class Executor {
2576
2795
  }
2577
2796
  async#resolveTemplateRoot() {
2578
2797
  const candidates = [
2579
- path9.resolve(getDirname2(import.meta.url), "templates"),
2580
- path9.resolve(getDirname2(import.meta.url), "../cli/templates")
2798
+ path10.resolve(getDirname2(import.meta.url), "templates"),
2799
+ path10.resolve(getDirname2(import.meta.url), "../cli/templates")
2581
2800
  ];
2582
2801
  for (const candidate of candidates) {
2583
2802
  if (await FileSys2.dirExists(candidate))
@@ -2645,11 +2864,11 @@ class Executor {
2645
2864
  async#resolveTypecheckWorkerEntry() {
2646
2865
  const dirname = getDirname2(import.meta.url);
2647
2866
  const candidates = [
2648
- path9.join(process.cwd(), "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
2649
- path9.join(process.cwd(), "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
2650
- path9.join(dirname, "typecheck/typecheck.proc.ts"),
2651
- path9.join(dirname, "typecheck.proc.js"),
2652
- path9.join(dirname, "typecheck.proc.ts")
2867
+ path10.join(process.cwd(), "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
2868
+ path10.join(process.cwd(), "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
2869
+ path10.join(dirname, "typecheck/typecheck.proc.ts"),
2870
+ path10.join(dirname, "typecheck.proc.js"),
2871
+ path10.join(dirname, "typecheck.proc.ts")
2653
2872
  ];
2654
2873
  for (const candidate of candidates)
2655
2874
  if (await Bun.file(candidate).exists())
@@ -2769,7 +2988,7 @@ class WorkspaceExecutor extends Executor {
2769
2988
  await Promise.all(dirs.map(async (dir) => {
2770
2989
  if (dir.includes("_") || AVOID_DIRS.includes(dir))
2771
2990
  return;
2772
- const dirPath = path9.join(dirname, dir);
2991
+ const dirPath = path10.join(dirname, dir);
2773
2992
  if ((await stat2(dirPath)).isDirectory()) {
2774
2993
  results.push(`${prefix}${dir}`);
2775
2994
  if (maxDepth > 0)
@@ -2806,9 +3025,9 @@ class WorkspaceExecutor extends Executor {
2806
3025
  await Promise.all(dirs.map(async (dir) => {
2807
3026
  if (AVOID_DIRS.includes(dir))
2808
3027
  return;
2809
- const dirPath = path9.join(dirname, dir);
3028
+ const dirPath = path10.join(dirname, dir);
2810
3029
  if (await FileSys2.dirExists(dirPath)) {
2811
- const hasTargetFile = await FileSys2.fileExists(path9.join(dirPath, targetFilename));
3030
+ const hasTargetFile = await FileSys2.fileExists(path10.join(dirPath, targetFilename));
2812
3031
  if (hasTargetFile)
2813
3032
  results.push(`${prefix}${dir}`);
2814
3033
  if (maxDepth > 0)
@@ -2838,7 +3057,6 @@ class WorkspaceExecutor extends Executor {
2838
3057
  return await this.#fromEverySys((sys) => sys.getViewsSourceCode());
2839
3058
  }
2840
3059
  }
2841
- var scanFacetDirs = ["ui", "webkit", "srvkit", "common", "plugin"];
2842
3060
 
2843
3061
  class SysExecutor extends Executor {
2844
3062
  workspace;
@@ -2868,7 +3086,7 @@ class SysExecutor extends Executor {
2868
3086
  return [];
2869
3087
  const violations = [];
2870
3088
  for (const entry of await this.getAllFiles("**/*", { cwd: this.getPath("page") })) {
2871
- const relativePath = entry.split(path9.sep).join("/");
3089
+ const relativePath = entry.split(path10.sep).join("/");
2872
3090
  const reason = getPageSourceFileViolation(relativePath);
2873
3091
  if (reason)
2874
3092
  violations.push({ relativePath: `page/${relativePath}`, reason });
@@ -2893,7 +3111,7 @@ class SysExecutor extends Executor {
2893
3111
  this._applyTemplate({ basePath: ".", template: "server.ts", scanInfo }),
2894
3112
  this._applyTemplate({ basePath: ".", template: "client.ts", scanInfo }),
2895
3113
  this.type === "lib" ? this._applyTemplate({ basePath: ".", template: "index.ts", scanInfo }) : null,
2896
- ...scanFacetDirs.map((facet) => this._applyTemplate({
3114
+ ...barrelFacetDirs.map((facet) => this._applyTemplate({
2897
3115
  basePath: facet,
2898
3116
  template: "facetIndex/index.ts",
2899
3117
  scanInfo,
@@ -2922,11 +3140,9 @@ class SysExecutor extends Executor {
2922
3140
  await CodegenLock.run(this.workspace.workspaceRoot, `scan:${this.name}`, async () => {
2923
3141
  await Promise.all(this.#getScanTemplateTasks(scanInfo));
2924
3142
  await this.writeJson(`akan.${this.type}.json`, scanInfo.getScanResult());
2925
- if (this.type === "lib")
2926
- this.#updateDependencies(scanInfo);
3143
+ await this.#updateDependencies(scanInfo);
2927
3144
  if (writeLib) {
2928
3145
  const libInfos = [...scanInfo.getLibInfos().values()];
2929
- await this.#updateDependencies(scanInfo);
2930
3146
  await Promise.all(libInfos.flatMap((libInfo) => libInfo.exec.#getScanTemplateTasks(libInfo)));
2931
3147
  }
2932
3148
  await this.syncAgentsIndex(scanInfo);
@@ -2945,27 +3161,27 @@ class SysExecutor extends Executor {
2945
3161
  await this.writeFile("CLAUDE.md", renderScopeClaudeMd(scope));
2946
3162
  }
2947
3163
  async#updateDependencies(scanInfo) {
2948
- const rootPackageJson = await this.workspace.getPackageJson();
2949
- const libPackageJson = await this.getPackageJson();
2950
- const dependencies = scanInfo.getScanResult().dependencies;
2951
- const devDependencies = scanInfo.getScanResult().devDependencies;
2952
- const dependencySet = new Set(dependencies);
2953
- const devDependencySet = new Set(devDependencies);
2954
- const libPkgJsonWithDeps = {
2955
- ...libPackageJson,
2956
- dependencies: {
2957
- ...Object.fromEntries(Object.entries(libPackageJson.dependencies ?? {}).filter(([dep]) => !devDependencySet.has(dep))),
2958
- ...Object.fromEntries(dependencies.filter((dep) => rootPackageJson.dependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.dependencies?.[dep]]))
2959
- },
2960
- devDependencies: {
2961
- ...Object.fromEntries(Object.entries(libPackageJson.devDependencies ?? {}).filter(([dep]) => !dependencySet.has(dep))),
2962
- ...Object.fromEntries(devDependencies.filter((dep) => rootPackageJson.dependencies?.[dep] || rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.devDependencies?.[dep] ?? rootPackageJson.dependencies?.[dep]]))
2963
- }
2964
- };
2965
- await this.setPackageJson(libPkgJsonWithDeps);
3164
+ const [rootPackageJson, packageJson] = await Promise.all([
3165
+ this.workspace.getPackageJson(),
3166
+ this.getPackageJson({ refresh: true })
3167
+ ]);
3168
+ const { dependencies: runtime, devDependencies: typeOnly, akanConfig } = scanInfo.getScanResult();
3169
+ const kept = new Set([
3170
+ ...ManifestDependencies.keptBy(packageJson),
3171
+ ...akanConfig.externalLibs,
3172
+ ...akanConfig.trustedDependencies
3173
+ ]);
3174
+ const isKept = (dep) => kept.has(dep) || isAkanFrameworkDependency(dep);
3175
+ const { dependencies, devDependencies, removed, unverifiable } = new ManifestDependencies(rootPackageJson, { runtime, typeOnly }, isKept).realign(packageJson);
3176
+ const manifestPath = `${this.type}s/${this.name}/package.json`;
3177
+ if (removed.length)
3178
+ this.logger.info(`Removed from ${manifestPath}, declared by the root and imported nowhere: ${removed.join(", ")} (list one in akan.keepDependencies to keep it)`);
3179
+ if (unverifiable.length)
3180
+ this.logger.warn(`${manifestPath} lists ${unverifiable.join(", ")}, which the root package.json does not declare, so sync cannot tell whether it is used; kept as is`);
3181
+ await this.setPackageJson({ ...packageJson, dependencies, devDependencies });
2966
3182
  }
2967
3183
  async getLocalFile(targetPath) {
2968
- const filePath = path9.isAbsolute(targetPath) ? targetPath : `${this.type}s/${this.name}/${targetPath}`;
3184
+ const filePath = path10.isAbsolute(targetPath) ? targetPath : `${this.type}s/${this.name}/${targetPath}`;
2969
3185
  const content = await this.workspace.readFile(filePath);
2970
3186
  return { filePath, content };
2971
3187
  }
@@ -3053,14 +3269,19 @@ class AppExecutor extends SysExecutor {
3053
3269
  static from(executor, name) {
3054
3270
  return new AppExecutor({ workspace: executor instanceof WorkspaceExecutor ? executor : executor.workspace, name });
3055
3271
  }
3056
- static #keptOnStart = [path9.join(".akan", "native"), path9.join(".akan", "cache", "bin")];
3272
+ static #keptOnStart = [path10.join(".akan", "cache", "bin")];
3273
+ static #legacyNative = path10.join(".akan", "native");
3057
3274
  async#removeDevOutput(dir = ".akan") {
3058
3275
  const entries = await readDirEntries(this.getPath(dir)).catch(() => []);
3059
3276
  await Promise.all(entries.map(async (name) => {
3060
- const entry = path9.join(dir, name);
3277
+ const entry = path10.join(dir, name);
3278
+ if (entry === AppExecutor.#legacyNative) {
3279
+ this.logger.warn(`apps/${this.name}/.akan/native holds native builds from before they moved to dist/native/${this.name}: upload any release waiting in its updates folders, then delete it.`);
3280
+ return;
3281
+ }
3061
3282
  if (AppExecutor.#keptOnStart.includes(entry))
3062
3283
  return;
3063
- if (AppExecutor.#keptOnStart.some((kept) => kept.startsWith(`${entry}${path9.sep}`)))
3284
+ if (AppExecutor.#keptOnStart.some((kept) => kept.startsWith(`${entry}${path10.sep}`)))
3064
3285
  return await this.#removeDevOutput(entry);
3065
3286
  await this.removeDir(entry);
3066
3287
  }));
@@ -3132,10 +3353,10 @@ class AppExecutor extends SysExecutor {
3132
3353
  });
3133
3354
  if (type === "build") {
3134
3355
  const buildEnv = { ...env };
3135
- delete buildEnv.AKAN_PUBLIC_CLIENT_PORT;
3136
- delete buildEnv.AKAN_PUBLIC_SERVER_PORT;
3137
- delete buildEnv.AKAN_PUBLIC_OPERATION_MODE;
3138
- delete process.env.AKAN_PUBLIC_OPERATION_MODE;
3356
+ for (const key of ["AKAN_PUBLIC_CLIENT_PORT", "AKAN_PUBLIC_SERVER_PORT", "AKAN_PUBLIC_OPERATION_MODE"]) {
3357
+ delete buildEnv[key];
3358
+ delete process.env[key];
3359
+ }
3139
3360
  Object.assign(process.env, buildEnv);
3140
3361
  }
3141
3362
  return { env };
@@ -3184,13 +3405,13 @@ class AppExecutor extends SysExecutor {
3184
3405
  absolute: false,
3185
3406
  onlyFiles: true
3186
3407
  })) {
3187
- const segments = rel.split(path9.sep);
3408
+ const segments = rel.split(path10.sep);
3188
3409
  if (segments.some((s) => s === "node_modules"))
3189
3410
  continue;
3190
3411
  const posix = `${root.keyPrefix}${segments.join("/")}`;
3191
3412
  if (!root.keyPrefix && libKeyPrefixes.some((prefix) => posix.startsWith(prefix)))
3192
3413
  continue;
3193
- const absPath = path9.join(root.dir, ...segments);
3414
+ const absPath = path10.join(root.dir, ...segments);
3194
3415
  validatePageSourceFile(posix, { filePath: absPath });
3195
3416
  if (!isRouteSourceFile(posix))
3196
3417
  continue;
@@ -3331,7 +3552,7 @@ class AppExecutor extends SysExecutor {
3331
3552
  static async#linkLibAsset(targetPath, linkPath) {
3332
3553
  const isWindows = process.platform === "win32";
3333
3554
  try {
3334
- const target = isWindows ? targetPath : path9.relative(path9.dirname(linkPath), targetPath);
3555
+ const target = isWindows ? targetPath : path10.relative(path10.dirname(linkPath), targetPath);
3335
3556
  await symlink(target, linkPath, isWindows ? "junction" : "dir");
3336
3557
  } catch (error) {
3337
3558
  if (!isWindows)
@@ -3374,7 +3595,7 @@ class AppExecutor extends SysExecutor {
3374
3595
  await this.writeFile(rel, content, opts);
3375
3596
  },
3376
3597
  readEnvClient: async () => {
3377
- const envClientPath = path9.join(this.cwdPath, "env", "env.client.ts");
3598
+ const envClientPath = path10.join(this.cwdPath, "env", "env.client.ts");
3378
3599
  if (!await FileSys2.fileExists(envClientPath))
3379
3600
  return null;
3380
3601
  try {
@@ -3468,7 +3689,7 @@ class PkgExecutor extends Executor {
3468
3689
  return overrideVersion;
3469
3690
  try {
3470
3691
  const packageJsonPath = `pkgs/${dep}/package.json`;
3471
- if (!await Bun.file(path9.join(this.workspace.workspaceRoot, packageJsonPath)).exists())
3692
+ if (!await Bun.file(path10.join(this.workspace.workspaceRoot, packageJsonPath)).exists())
3472
3693
  return;
3473
3694
  const packageJson = await this.workspace.readJson(packageJsonPath);
3474
3695
  if (packageJson.name === dep)
@@ -3561,4 +3782,4 @@ class ModuleExecutor extends Executor {
3561
3782
  }
3562
3783
  }
3563
3784
 
3564
- export { AGENT_BLOCK_START, AGENT_BLOCK_END, stampBlockVersion, extractBlockVersion, readDevkitVersion, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, CLAUDE_COMMENT_RULE, binPlatforms, AsyncDefaultExportDetector, resolveSsrPageEntriesForApp, CodegenLock, Linter, rootAllowedFiles, rootAllowedDirs, isAllowedLibFacetRootFile, rootEntryHintOf, isScannedRootEntry, AppInfo, Spinner, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
3785
+ export { AGENT_BLOCK_START, AGENT_BLOCK_END, stampBlockVersion, extractBlockVersion, readDevkitVersion, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, CLAUDE_COMMENT_RULE, binPlatforms, AsyncDefaultExportDetector, resolveSsrPageEntriesForApp, CodegenLock, Linter, LibSource, formatLibStatuses, rootAllowedFiles, rootAllowedDirs, isAllowedLibFacetRootFile, barrelFacetDirs, facetIndexShadowOf, rootEntryHintOf, isScannedRootEntry, AppInfo, Spinner, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };