@akanjs/cli 3.0.0-beta.27 → 3.0.0-beta.29

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 (63) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-h19atbr3.js → CodeAgent-86q8d13j.js} +2 -2
  3. package/{CodeTui-46zygq8p.js → CodeTui-r8tgxsyb.js} +1 -1
  4. package/{agent.command-rp505zxa.js → agent.command-q9bmqrag.js} +5 -5
  5. package/akanCode.js +2 -2
  6. package/{application.command-1p0cpt6y.js → application.command-712jd2z8.js} +70 -8
  7. package/{applicationBuildRunner-r6b9rkb8.js → applicationBuildRunner-ez37p161.js} +67 -22
  8. package/buildBatch.proc.js +3 -3
  9. package/{cloud.command-ps9dabbg.js → cloud.command-8eegwcsc.js} +9 -9
  10. package/cloud.script-55s1cmz9.js +20 -0
  11. package/{code.command-78qw3q3f.js → code.command-n0c2tyzx.js} +6 -6
  12. package/commandManifest.json +1 -1
  13. package/{context.command-x5f7t3gk.js → context.command-vxf6d7q2.js} +13 -13
  14. package/context.runner-70r2fmty.js +21 -0
  15. package/{guideline.command-d5qmxx29.js → guideline.command-ene55fkr.js} +2 -2
  16. package/guidelines/conventions/conventions.instruction.md +27 -7
  17. package/guidelines/runtimeRule/runtimeRule.instruction.md +116 -1
  18. package/incrementalBuilder.proc.js +2 -2
  19. package/{index-hzy4pe24.js → index-0pqzrbpr.js} +2 -2
  20. package/{index-w5pet0nq.js → index-16k7m3cs.js} +11 -9
  21. package/index-1hs6jrys.js +994 -0
  22. package/{index-6dt6zft6.js → index-20r2g1t3.js} +4 -4
  23. package/{index-xfgdmm5d.js → index-2ctqegdm.js} +2 -2
  24. package/{index-d65fzxvd.js → index-2s2e5qnd.js} +1 -1
  25. package/{index-j9z8vg2n.js → index-2yvy9ztj.js} +4 -4
  26. package/{index-t02g6dpn.js → index-2z30v4k5.js} +3 -3
  27. package/{index-vxqe24mp.js → index-8ej6r02m.js} +1 -1
  28. package/{index-58cyna2s.js → index-b68zfsvz.js} +1 -1
  29. package/{index-bp9b1g2r.js → index-fy42hyb9.js} +7 -3
  30. package/{index-tg09x14f.js → index-g44da4r2.js} +5 -5
  31. package/{index-zazvn45w.js → index-genegfnt.js} +4 -4
  32. package/{index-da72pfdv.js → index-h9ed99ax.js} +7 -7
  33. package/{index-per2kqy9.js → index-k7809wmg.js} +2 -2
  34. package/{index-2zcm7fjd.js → index-krwz9ek9.js} +3 -3
  35. package/{index-118vq9dh.js → index-n9gxx7bp.js} +247 -47
  36. package/{index-860zjnr1.js → index-nbg9bfnr.js} +1 -1
  37. package/{index-5mm3g24t.js → index-qtz88kh0.js} +2 -2
  38. package/{index-0n9q1f23.js → index-r8gp8zk3.js} +231 -98
  39. package/{index-ggfhz9ab.js → index-rbeahw6j.js} +3 -3
  40. package/{index-56xwsgyn.js → index-rrt9pnb4.js} +2 -2
  41. package/{index-v4hnkqz9.js → index-ss828r32.js} +1 -1
  42. package/{index-5kjsr2pg.js → index-ttn00pr3.js} +38 -3
  43. package/index.js +21 -21
  44. package/{library.command-sv6g1h2g.js → library.command-tz7vnwea.js} +3 -3
  45. package/{localRegistry.command-zppa6w7q.js → localRegistry.command-7dd85czz.js} +8 -8
  46. package/{module.command-ccdeder9.js → module.command-qhc9ns0s.js} +5 -5
  47. package/{package.command-xmw605b1.js → package.command-z3epnvas.js} +3 -3
  48. package/package.json +3 -3
  49. package/{page.command-ky7vafsn.js → page.command-exd2vakz.js} +3 -3
  50. package/{primitive.command-bh6j8nfs.js → primitive.command-0w6cha4j.js} +6 -6
  51. package/{quality.command-rqqrpe98.js → quality.command-je4kc9yv.js} +2 -2
  52. package/{repair.command-n9nsm9qe.js → repair.command-knvwfgtg.js} +5 -5
  53. package/{scalar.command-t09gmck8.js → scalar.command-60nxfchc.js} +4 -4
  54. package/{subspace.command-gx2cjpnv.js → subspace.command-683qxcw9.js} +4 -4
  55. package/templates/server.ts +1 -1
  56. package/{tunnel.command-4g95vhsn.js → tunnel.command-7m2kxtat.js} +2 -2
  57. package/{workflow.command-b91ph8sx.js → workflow.command-j5tk13ds.js} +10 -10
  58. package/{workspace.command-1r29qzzk.js → workspace.command-jxdm0wrb.js} +20 -20
  59. package/README.ko.md +0 -72
  60. package/README.md +0 -88
  61. package/cloud.script-wrw1kz6k.js +0 -20
  62. package/context.runner-nfs8ksh3.js +0 -21
  63. package/index-y736f42m.js +0 -556
@@ -516,7 +516,7 @@ import {
516
516
  stat as stat2,
517
517
  symlink
518
518
  } from "fs/promises";
519
- import path8 from "path";
519
+ import path9 from "path";
520
520
  import { pathToFileURL } from "url";
521
521
  import {
522
522
  capitalize,
@@ -668,17 +668,83 @@ var renderScopeClaudeMd = (scope) => `# ${scope.name} \u2014 Claude Code Guide
668
668
  ${CLAUDE_COMMENT_RULE}
669
669
  `;
670
670
 
671
- // pkgs/@akanjs/devkit/akanConfig/akanConfig.ts
672
- import fs2 from "fs";
671
+ // pkgs/@akanjs/devkit/akanConfig/akanBin.ts
673
672
  import path4 from "path";
674
- import { fileURLToPath } from "url";
675
- import { DatabaseModes, normalizeRoutePrefix } from "akanjs/base";
676
- import { resolveAkanI18nConfig } from "akanjs/common";
677
673
 
678
674
  // pkgs/@akanjs/devkit/akanConfig/types.ts
679
- import { archs } from "akanjs";
675
+ import { archs, binPlatforms } from "akanjs";
680
676
 
677
+ // pkgs/@akanjs/devkit/akanConfig/akanBin.ts
678
+ class AkanBin {
679
+ static archive = /\.(zip|tar\.gz|tgz|tar\.xz|txz|tar\.bz2|tbz2|tar)$/i;
680
+ static fileName = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
681
+ static parse(declared, owner, baseDir) {
682
+ if (declared === undefined)
683
+ return {};
684
+ if (!declared || typeof declared !== "object" || Array.isArray(declared))
685
+ throw new Error(`${owner}: bin maps each executable's name to its platforms`);
686
+ return Object.fromEntries(Object.entries(declared).map(([name, platforms]) => [name, AkanBin.#platforms(name, platforms, owner, baseDir)]));
687
+ }
688
+ static isArchive(source) {
689
+ return AkanBin.archive.test("url" in source ? new URL(source.url).pathname : source.path);
690
+ }
691
+ static #platforms(name, platforms, owner, baseDir) {
692
+ if (!AkanBin.fileName.test(name))
693
+ throw new Error(`${owner}: bin.${name} is not a file name`);
694
+ if (!platforms || typeof platforms !== "object" || Array.isArray(platforms))
695
+ throw new Error(`${owner}: bin.${name} maps platforms (${binPlatforms.join(", ")}) to where the file comes from`);
696
+ const resolved = {};
697
+ for (const [platform, source] of Object.entries(platforms)) {
698
+ if (!binPlatforms.includes(platform))
699
+ throw new Error(`${owner}: bin.${name}.${platform} is not one of ${binPlatforms.join(", ")}`);
700
+ resolved[platform] = AkanBin.#source(`${owner}: bin.${name}.${platform}`, source, baseDir);
701
+ }
702
+ return resolved;
703
+ }
704
+ static #source(at, source, baseDir) {
705
+ if (!source || typeof source !== "object" || Array.isArray(source))
706
+ throw new Error(`${at} must be { url, sha256 } or { path }`);
707
+ const { url, sha256, path: localPath, file, ...rest } = source;
708
+ const extra = Object.keys(rest);
709
+ if (extra.length)
710
+ throw new Error(`${at}: unknown key ${extra.join(", ")}`);
711
+ if (url === undefined === (localPath === undefined))
712
+ throw new Error(`${at} takes either url and sha256, or path`);
713
+ const resolved = url !== undefined ? AkanBin.#urlSource(at, url, sha256) : AkanBin.#pathSource(at, localPath, sha256, baseDir);
714
+ const archive = AkanBin.isArchive(resolved);
715
+ if (file === undefined) {
716
+ if (archive)
717
+ throw new Error(`${at} names an archive: file picks the executable inside it`);
718
+ return resolved;
719
+ }
720
+ if (!archive)
721
+ throw new Error(`${at}: file picks the executable out of an archive, and this source is none`);
722
+ const parts = typeof file === "string" ? file.split(/[\\/]/).filter((part) => part && part !== ".") : [];
723
+ if (!parts.length || path4.isAbsolute(file) || parts.includes(".."))
724
+ throw new Error(`${at}: file must be a path inside the archive (got ${JSON.stringify(file)})`);
725
+ return { ...resolved, file: parts.join("/") };
726
+ }
727
+ static #urlSource(at, url, sha256) {
728
+ if (typeof url !== "string" || !URL.canParse(url) || !/^https?:$/.test(new URL(url).protocol))
729
+ throw new Error(`${at}: url must be an http(s) address`);
730
+ if (typeof sha256 !== "string" || !/^[0-9a-f]{64}$/i.test(sha256))
731
+ throw new Error(`${at}: sha256 must be the downloaded file's 64-digit hex digest`);
732
+ return { url, sha256: sha256.toLowerCase() };
733
+ }
734
+ static #pathSource(at, localPath, sha256, baseDir) {
735
+ if (typeof localPath !== "string" || !localPath)
736
+ throw new Error(`${at}: path must name a file`);
737
+ if (sha256 !== undefined)
738
+ throw new Error(`${at}: sha256 checks a download, and a path source downloads nothing`);
739
+ return { path: path4.resolve(baseDir, localPath) };
740
+ }
741
+ }
681
742
  // pkgs/@akanjs/devkit/akanConfig/akanConfig.ts
743
+ import fs2 from "fs";
744
+ import path5 from "path";
745
+ import { fileURLToPath } from "url";
746
+ import { DatabaseModes, normalizeRoutePrefix } from "akanjs/base";
747
+ import { resolveAkanI18nConfig } from "akanjs/common";
682
748
  var DEFAULT_BARREL_IMPORTS = ["akanjs/webkit", "akanjs/common", "akanjs/ui", "akanjs/server"];
683
749
  var DEFAULT_OPTIMIZE_IMPORTS = [
684
750
  "lucide-react date-fns lodash-es ramda antd react-bootstrap ahooks @ant-design/icons @headlessui/react",
@@ -750,9 +816,18 @@ var normalizeDeepLinks = (deepLinks) => {
750
816
  };
751
817
  var emptyLibContributions = () => ({
752
818
  externalLibs: [],
819
+ trustedDependencies: [],
820
+ bin: [],
753
821
  docker: { preRuns: [], postRuns: [] },
754
822
  keepFonts: []
755
823
  });
824
+ var normalizePackageNames = (names, owner) => {
825
+ if (names === undefined)
826
+ return [];
827
+ if (!Array.isArray(names) || names.some((name) => typeof name !== "string" || !name.trim()))
828
+ throw new Error(`${owner}: trustedDependencies lists package names`);
829
+ return [...new Set(names.map((name) => name.trim()))];
830
+ };
756
831
  var normalizeKeepFonts = (keepFonts) => [
757
832
  ...new Set((keepFonts ?? []).map((glob) => glob.trim().replace(/^\/+/, "")).filter(Boolean))
758
833
  ];
@@ -771,6 +846,9 @@ class AkanAppConfig {
771
846
  database;
772
847
  web;
773
848
  externalLibs;
849
+ trustedDependencies;
850
+ bin;
851
+ libBins;
774
852
  barrelImports;
775
853
  optimizeImports;
776
854
  images;
@@ -798,6 +876,15 @@ class AkanAppConfig {
798
876
  this.#applyRoutes(config?.routes);
799
877
  this.database = AkanAppConfig.#database(app, config);
800
878
  this.externalLibs = [...new Set([...config?.externalLibs ?? [], ...libContributions.externalLibs])];
879
+ const owner = `apps/${app.name}/akan.config.ts`;
880
+ this.trustedDependencies = [
881
+ ...new Set([
882
+ ...normalizePackageNames(config?.trustedDependencies, owner),
883
+ ...libContributions.trustedDependencies ?? []
884
+ ])
885
+ ];
886
+ this.bin = AkanBin.parse(config?.bin, owner, app.cwdPath);
887
+ this.libBins = libContributions.bin ?? [];
801
888
  this.barrelImports = [
802
889
  ...DEFAULT_BARREL_IMPORTS,
803
890
  ...WORKSPACE_BARREL_FACETS.map((facet) => `@apps/${app.name}/${facet}`),
@@ -851,6 +938,7 @@ class AkanAppConfig {
851
938
  const buildNum = rawMobile.buildNum ?? 1;
852
939
  const files = AkanAppConfig.#resolveMobileFiles(rawMobile.files, "mobile", configPath);
853
940
  const native = rawMobile.native;
941
+ const updates = rawMobile.updates;
854
942
  const defaultTargetName = this.#defaultMobileTargetName(rawTargets);
855
943
  const targetEntries = Object.entries(rawTargets ?? {
856
944
  [defaultTargetName]: {}
@@ -868,6 +956,9 @@ class AkanAppConfig {
868
956
  }
869
957
  const targetFiles = AkanAppConfig.#resolveMobileFiles(target.files, where, configPath);
870
958
  const fileName = target.fileName ?? rawMobile.fileName;
959
+ const targetUpdates = updates || target.updates ? { ...updates, ...target.updates } : undefined;
960
+ if (targetUpdates && (!targetUpdates.url || !targetUpdates.publicKey))
961
+ throw new Error(`${where}.updates in ${configPath} has no url or publicKey; give them in mobile.updates or the target's own.`);
871
962
  const resolved = {
872
963
  name,
873
964
  basePath,
@@ -881,7 +972,8 @@ class AkanAppConfig {
881
972
  ...target.assets ? { assets: target.assets } : {},
882
973
  ...target.permissions ? { permissions: target.permissions } : {},
883
974
  ...files || targetFiles ? { files: { ...files, ...targetFiles } } : {},
884
- ...native || target.native ? { native: AkanAppConfig.#mergeNative(native, target.native) } : {}
975
+ ...native || target.native ? { native: AkanAppConfig.#mergeNative(native, target.native) } : {},
976
+ ...targetUpdates ? { updates: targetUpdates } : {}
885
977
  };
886
978
  return [name, resolved];
887
979
  }));
@@ -893,10 +985,11 @@ class AkanAppConfig {
893
985
  buildNum,
894
986
  ...files ? { files } : {},
895
987
  ...native ? { native } : {},
988
+ ...updates ? { updates } : {},
896
989
  targets
897
990
  };
898
991
  }
899
- static #mobileKeys = ["appName", "appId", "fileName", "version", "buildNum", "files", "native"];
992
+ static #mobileKeys = ["appName", "appId", "fileName", "version", "buildNum", "files", "native", "updates"];
900
993
  static #targetKeys = [
901
994
  "basePath",
902
995
  "indexPath",
@@ -909,7 +1002,8 @@ class AkanAppConfig {
909
1002
  "permissions",
910
1003
  "deepLinks",
911
1004
  "files",
912
- "native"
1005
+ "native",
1006
+ "updates"
913
1007
  ];
914
1008
  static #assertMobileKeys(section, known, where, configPath) {
915
1009
  for (const key of Object.keys(section)) {
@@ -946,10 +1040,21 @@ class AkanAppConfig {
946
1040
  else
947
1041
  delete android[key];
948
1042
  }
1043
+ const pushAndroid = { ...base?.push?.android, ...override?.push?.android };
1044
+ const privacy = { ...base?.privacy, ...override?.privacy };
1045
+ const window = { ...base?.desktop?.window, ...override?.desktop?.window };
1046
+ const desktop = {
1047
+ ...base?.desktop,
1048
+ ...override?.desktop,
1049
+ ...Object.keys(window).length ? { window } : {}
1050
+ };
949
1051
  return {
950
1052
  ...plugins.length ? { plugins } : {},
951
1053
  ...Object.keys(ios).length ? { ios } : {},
952
- ...Object.keys(android).length ? { android } : {}
1054
+ ...Object.keys(android).length ? { android } : {},
1055
+ ...Object.keys(pushAndroid).length ? { push: { android: pushAndroid } } : {},
1056
+ ...Object.keys(privacy).length ? { privacy } : {},
1057
+ ...Object.keys(desktop).length ? { desktop } : {}
953
1058
  };
954
1059
  }
955
1060
  #defaultMobileTargetName(rawTargets) {
@@ -1004,18 +1109,37 @@ class AkanAppConfig {
1004
1109
  command: docker?.command ?? ["bun", "main.js"]
1005
1110
  };
1006
1111
  }
1007
- #makeDockerfile() {
1112
+ getProductionEnv(environment = this.baseDevEnv.env) {
1113
+ return {
1114
+ PORT: "8282",
1115
+ NODE_ENV: "production",
1116
+ AKAN_PUBLIC_REPO_NAME: this.baseDevEnv.repoName,
1117
+ AKAN_PUBLIC_SERVE_DOMAIN: this.baseDevEnv.serveDomain,
1118
+ AKAN_PUBLIC_APP_NAME: this.app.name,
1119
+ AKAN_PUBLIC_ENV: environment,
1120
+ ...this.basePaths.size ? { AKAN_PUBLIC_BASE_PATHS: [...this.basePaths].join(",") } : {},
1121
+ AKAN_PUBLIC_DEFAULT_LOCALE: this.i18n.defaultLocale,
1122
+ AKAN_PUBLIC_LOCALES: this.i18n.locales.join(","),
1123
+ AKAN_PUBLIC_API_PREFIX: this.api.prefix,
1124
+ AKAN_PUBLIC_WS_PREFIX: this.api.websocketPrefix,
1125
+ AKAN_PUBLIC_OPERATION_MODE: "cloud",
1126
+ AKAN_DATABASE_MODES: this.database.modes.join(","),
1127
+ AKAN_LOG_TO_FILE: "0",
1128
+ ...this.web.ssr ? {} : { AKAN_SSR: "false" },
1129
+ ...this.web.csr ? {} : { AKAN_CSR: "false" }
1130
+ };
1131
+ }
1132
+ dockerfileFor(environment) {
1133
+ return this.#makeDockerfile(environment);
1134
+ }
1135
+ #makeDockerfile(environment) {
1008
1136
  if (typeof this.docker === "string")
1009
1137
  return this.docker;
1010
1138
  const { image, preRuns, postRuns, command } = this.docker;
1011
1139
  const preRunScripts = this.#getDockerRunScripts(preRuns);
1012
1140
  const postRunScripts = this.#getDockerRunScripts(postRuns);
1013
1141
  const imageScript = this.#getDockerImageScript(image, DEFAULT_DOCKER_IMAGE);
1014
- const webEnvLines = [
1015
- ...this.web.ssr ? [] : ["ENV AKAN_SSR=false"],
1016
- ...this.web.csr ? [] : ["ENV AKAN_CSR=false"]
1017
- ].join(`
1018
- `);
1142
+ const envLines = Object.entries(this.getProductionEnv(environment)).map(([key, value]) => `ENV ${key}=${value}`);
1019
1143
  return `${imageScript}
1020
1144
  RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends ca-certificates tzdata && rm -rf /var/lib/apt/lists/*
1021
1145
  RUN ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
@@ -1029,21 +1153,8 @@ RUN bun install --production
1029
1153
  ${postRunScripts.join(`
1030
1154
  `)}
1031
1155
  COPY . .
1032
- ENV PORT=8282
1033
- ENV NODE_ENV=production
1034
- ENV AKAN_PUBLIC_REPO_NAME=${this.baseDevEnv.repoName}
1035
- ENV AKAN_PUBLIC_SERVE_DOMAIN=${this.baseDevEnv.serveDomain}
1036
- ENV AKAN_PUBLIC_APP_NAME=${this.app.name}
1037
- ENV AKAN_PUBLIC_ENV=${this.baseDevEnv.env}
1038
- ${this.basePaths.size ? `ENV AKAN_PUBLIC_BASE_PATHS=${[...this.basePaths].join(",")}` : ""}
1039
- ENV AKAN_PUBLIC_DEFAULT_LOCALE=${this.i18n.defaultLocale}
1040
- ENV AKAN_PUBLIC_LOCALES=${this.i18n.locales.join(",")}
1041
- ENV AKAN_PUBLIC_API_PREFIX=${this.api.prefix}
1042
- ENV AKAN_PUBLIC_WS_PREFIX=${this.api.websocketPrefix}
1043
- ENV AKAN_PUBLIC_OPERATION_MODE=cloud
1044
- ENV AKAN_DATABASE_MODES=${this.database.modes.join(",")}
1045
- ENV AKAN_LOG_TO_FILE=0
1046
- ${webEnvLines}
1156
+ ${envLines.join(`
1157
+ `)}
1047
1158
  CMD [${command.map((c) => `"${c}"`).join(",")}]`;
1048
1159
  }
1049
1160
  static #importGeneration = 0;
@@ -1055,7 +1166,7 @@ CMD [${command.map((c) => `"${c}"`).join(",")}]`;
1055
1166
  static async from(app, { bustImportCache = false } = {}) {
1056
1167
  const [configImp, baseDevEnv, libs, rootPackageJson] = await Promise.all([
1057
1168
  AkanAppConfig.importConfigModule(app.cwdPath, { bustImportCache }),
1058
- WorkspaceExecutor.getBaseDevEnv(path4.join(app.workspace.workspaceRoot, ".env")),
1169
+ WorkspaceExecutor.getBaseDevEnv(path5.join(app.workspace.workspaceRoot, ".env")),
1059
1170
  app.workspace.getLibs(),
1060
1171
  app.workspace.getPackageJson()
1061
1172
  ]);
@@ -1071,6 +1182,8 @@ CMD [${command.map((c) => `"${c}"`).join(",")}]`;
1071
1182
  })));
1072
1183
  return {
1073
1184
  externalLibs: libConfigs.flatMap((libConfig) => libConfig?.externalLibs ?? []),
1185
+ trustedDependencies: libConfigs.flatMap((libConfig) => libConfig?.trustedDependencies ?? []),
1186
+ bin: libConfigs.flatMap((libConfig) => libConfig && Object.keys(libConfig.bin).length ? [{ lib: libConfig.lib.name, bin: libConfig.bin }] : []),
1074
1187
  docker: {
1075
1188
  preRuns: libConfigs.flatMap((libConfig) => libConfig?.docker.preRuns ?? []),
1076
1189
  postRuns: libConfigs.flatMap((libConfig) => libConfig?.docker.postRuns ?? [])
@@ -1133,6 +1246,7 @@ CMD [${command.map((c) => `"${c}"`).join(",")}]`;
1133
1246
  lib,
1134
1247
  this.#resolveProductionDependencyVersion(lib)
1135
1248
  ])),
1249
+ ...this.trustedDependencies.length ? { trustedDependencies: this.trustedDependencies } : {},
1136
1250
  ...data
1137
1251
  };
1138
1252
  }
@@ -1141,11 +1255,11 @@ var akanPackageJson = null;
1141
1255
  function getAkanPackageJson() {
1142
1256
  if (akanPackageJson)
1143
1257
  return akanPackageJson;
1144
- const sourceDir = path4.dirname(fileURLToPath(import.meta.url));
1258
+ const sourceDir = path5.dirname(fileURLToPath(import.meta.url));
1145
1259
  const packageJsonPaths = [
1146
- path4.join(sourceDir, "../../../akanjs/package.json"),
1147
- path4.join(process.cwd(), "pkgs/akanjs/package.json"),
1148
- path4.join(path4.dirname(Bun.main), "node_modules/akanjs/package.json")
1260
+ path5.join(sourceDir, "../../../akanjs/package.json"),
1261
+ path5.join(process.cwd(), "pkgs/akanjs/package.json"),
1262
+ path5.join(path5.dirname(Bun.main), "node_modules/akanjs/package.json")
1149
1263
  ];
1150
1264
  try {
1151
1265
  packageJsonPaths.unshift(Bun.resolveSync("akanjs/package.json", sourceDir));
@@ -1180,12 +1294,17 @@ function mergeImageConfig(config = {}) {
1180
1294
  class AkanLibConfig {
1181
1295
  lib;
1182
1296
  externalLibs;
1297
+ trustedDependencies;
1298
+ bin;
1183
1299
  docker;
1184
1300
  assets;
1185
1301
  plugins;
1186
1302
  constructor(lib, config, plugins = []) {
1187
1303
  this.lib = lib;
1188
1304
  this.externalLibs = config?.externalLibs ?? [];
1305
+ const owner = `libs/${lib.name}/akan.config.ts`;
1306
+ this.trustedDependencies = normalizePackageNames(config?.trustedDependencies, owner);
1307
+ this.bin = AkanBin.parse(config?.bin, owner, lib.cwdPath);
1189
1308
  this.docker = { preRuns: config?.docker?.preRuns ?? [], postRuns: config?.docker?.postRuns ?? [] };
1190
1309
  this.assets = { keepFonts: normalizeKeepFonts(config?.assets?.keepFonts) };
1191
1310
  this.plugins = plugins;
@@ -1200,7 +1319,7 @@ class AkanLibConfig {
1200
1319
  //! need to refactor
1201
1320
  var shiftBuildNum = async (app, delta) => {
1202
1321
  const { buildNum } = (await AkanAppConfig.from(app)).mobile;
1203
- const akanConfigPath = path4.join(app.cwdPath, "akan.config.ts");
1322
+ const akanConfigPath = path5.join(app.cwdPath, "akan.config.ts");
1204
1323
  const akanConfig = fs2.readFileSync(akanConfigPath, "utf8");
1205
1324
  fs2.writeFileSync(akanConfigPath, akanConfig.replace(`buildNum: ${buildNum}`, `buildNum: ${buildNum + delta}`));
1206
1325
  };
@@ -1209,7 +1328,7 @@ var decreaseBuildNum = async (app) => await shiftBuildNum(app, -1);
1209
1328
  // pkgs/@akanjs/devkit/linter.ts
1210
1329
  import { spawn } from "child_process";
1211
1330
  import { existsSync, readFileSync } from "fs";
1212
- import path5 from "path";
1331
+ import path6 from "path";
1213
1332
  import chalk from "chalk";
1214
1333
  var parseBiomeReport = (output) => {
1215
1334
  for (let start = output.indexOf("{");start !== -1; start = output.indexOf("{", start + 1)) {
@@ -1275,13 +1394,13 @@ class Linter {
1275
1394
  #biomeBin;
1276
1395
  constructor(cwdPath) {
1277
1396
  this.lintRoot = this.#findBiomeRootPath(cwdPath);
1278
- this.configPath = Linter.#configPathIn(this.lintRoot) ?? path5.join(this.lintRoot, "biome.json");
1279
- const localBiomeBin = path5.join(this.lintRoot, "node_modules", ".bin", Linter.biomeBinName);
1397
+ this.configPath = Linter.#configPathIn(this.lintRoot) ?? path6.join(this.lintRoot, "biome.json");
1398
+ const localBiomeBin = path6.join(this.lintRoot, "node_modules", ".bin", Linter.biomeBinName);
1280
1399
  this.#biomeBin = existsSync(localBiomeBin) ? localBiomeBin : "biome";
1281
1400
  }
1282
1401
  static #configPathIn(dir) {
1283
1402
  for (const fileName of BIOME_CONFIG_FILES) {
1284
- const configPath = path5.join(dir, fileName);
1403
+ const configPath = path6.join(dir, fileName);
1285
1404
  if (existsSync(configPath))
1286
1405
  return configPath;
1287
1406
  }
@@ -1290,19 +1409,19 @@ class Linter {
1290
1409
  #findBiomeRootPath(dir) {
1291
1410
  if (Linter.#configPathIn(dir))
1292
1411
  return dir;
1293
- const parentDir = path5.dirname(dir);
1412
+ const parentDir = path6.dirname(dir);
1294
1413
  if (parentDir === dir)
1295
1414
  throw new Error(`biome.json not found from ${dir}`);
1296
1415
  return this.#findBiomeRootPath(parentDir);
1297
1416
  }
1298
1417
  #toBiomePath(filePath) {
1299
- const relativePath = path5.relative(this.lintRoot, filePath);
1300
- if (!relativePath.startsWith("..") && !path5.isAbsolute(relativePath))
1418
+ const relativePath = path6.relative(this.lintRoot, filePath);
1419
+ if (!relativePath.startsWith("..") && !path6.isAbsolute(relativePath))
1301
1420
  return relativePath;
1302
1421
  return filePath;
1303
1422
  }
1304
1423
  #resolveFilePath(filePath) {
1305
- return path5.isAbsolute(filePath) ? filePath : path5.join(this.lintRoot, filePath);
1424
+ return path6.isAbsolute(filePath) ? filePath : path6.join(this.lintRoot, filePath);
1306
1425
  }
1307
1426
  async#runBiome(args, input) {
1308
1427
  return await new Promise((resolve, reject) => {
@@ -1327,7 +1446,7 @@ class Linter {
1327
1446
  const diagnosticPath = diagnostic.location?.path;
1328
1447
  if (!diagnosticPath)
1329
1448
  return fallbackFilePath;
1330
- return path5.isAbsolute(diagnosticPath) ? diagnosticPath : path5.join(this.lintRoot, diagnosticPath);
1449
+ return path6.isAbsolute(diagnosticPath) ? diagnosticPath : path6.join(this.lintRoot, diagnosticPath);
1331
1450
  }
1332
1451
  #createLintMessage(diagnostic) {
1333
1452
  const start = diagnostic.location?.start;
@@ -1535,7 +1654,7 @@ ${errorText}, ${warningText} found`];
1535
1654
 
1536
1655
  // pkgs/@akanjs/devkit/repoIdentity.ts
1537
1656
  import { execFileSync } from "child_process";
1538
- import path6 from "path";
1657
+ import path7 from "path";
1539
1658
  var resolved = new Map;
1540
1659
  var readRemoteName = (workspaceRoot) => {
1541
1660
  try {
@@ -1553,13 +1672,13 @@ var resolveRepoName = (workspaceRoot) => {
1553
1672
  const cached = resolved.get(workspaceRoot);
1554
1673
  if (cached)
1555
1674
  return cached;
1556
- const repoName = readRemoteName(workspaceRoot) ?? path6.basename(workspaceRoot);
1675
+ const repoName = readRemoteName(workspaceRoot) ?? path7.basename(workspaceRoot);
1557
1676
  resolved.set(workspaceRoot, repoName);
1558
1677
  return repoName;
1559
1678
  };
1560
1679
 
1561
1680
  // pkgs/@akanjs/devkit/scanInfo.ts
1562
- import path7 from "path";
1681
+ import path8 from "path";
1563
1682
 
1564
1683
  // pkgs/@akanjs/devkit/workspaceLayout.ts
1565
1684
  var appRootAllowedFiles = new Set([
@@ -1579,6 +1698,7 @@ var appRootAllowedDirs = new Set([
1579
1698
  "common",
1580
1699
  "env",
1581
1700
  "lib",
1701
+ "native",
1582
1702
  "page",
1583
1703
  "plugin",
1584
1704
  "private",
@@ -1607,6 +1727,7 @@ var libRootAllowedDirs = new Set([
1607
1727
  "common",
1608
1728
  "env",
1609
1729
  "lib",
1730
+ "native",
1610
1731
  "page",
1611
1732
  "plugin",
1612
1733
  "private",
@@ -1668,9 +1789,9 @@ var moduleUiFileTypes = {
1668
1789
  scalar: new Set(["Template", "Unit"])
1669
1790
  };
1670
1791
  var createDependencyScanner = async (exec) => (await import("./dependencyScanner-06z2dmrr.js")).TypeScriptDependencyScanner.from(exec);
1671
- var getScanPath = (exec, relativePath) => path7.posix.join(`${exec.type}s`, exec.name, relativePath.split(path7.sep).join("/"));
1792
+ var getScanPath = (exec, relativePath) => path8.posix.join(`${exec.type}s`, exec.name, relativePath.split(path8.sep).join("/"));
1672
1793
  var getModuleNameFromPath = (kind, modulePath) => {
1673
- const dirname = path7.basename(modulePath);
1794
+ const dirname = path8.basename(modulePath);
1674
1795
  return kind === "service" ? dirname.replace(/^_+/, "") : dirname;
1675
1796
  };
1676
1797
  async function assertScanConvention(exec, libRoot) {
@@ -1692,17 +1813,17 @@ async function assertScanConvention(exec, libRoot) {
1692
1813
  addViolation(relativePath, reason);
1693
1814
  for (const filename of libRoot.files)
1694
1815
  if (!isAllowedLibFacetRootFile(filename))
1695
- addViolation(path7.join("lib", filename), "unsupported lib facet root file");
1816
+ addViolation(path8.join("lib", filename), "unsupported lib facet root file");
1696
1817
  for (const dirname of libRoot.dirs)
1697
1818
  if (dirname.startsWith("__") && !internalLibDirs.has(dirname))
1698
- addViolation(path7.join("lib", dirname), "unsupported internal lib folder");
1819
+ addViolation(path8.join("lib", dirname), "unsupported internal lib folder");
1699
1820
  const databaseDirs = libRoot.dirs.filter((dirname) => !dirname.startsWith("_"));
1700
1821
  const serviceDirs = libRoot.dirs.filter((dirname) => dirname.startsWith("_") && !dirname.startsWith("__"));
1701
1822
  const scalarDirs = await exec.readdir("lib/__scalar");
1702
1823
  await Promise.all([
1703
- ...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database", path7.join("lib", dirname))),
1704
- ...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service", path7.join("lib", dirname))),
1705
- ...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar", path7.join("lib/__scalar", dirname)))
1824
+ ...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database", path8.join("lib", dirname))),
1825
+ ...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service", path8.join("lib", dirname))),
1826
+ ...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar", path8.join("lib/__scalar", dirname)))
1706
1827
  ]);
1707
1828
  if (violations.length > 0) {
1708
1829
  throw new Error(`[scan-convention]
@@ -1714,11 +1835,11 @@ async function validateModuleFiles(exec, violations, kind, modulePath) {
1714
1835
  const { files, dirs } = await exec.getFilesAndDirs(modulePath);
1715
1836
  const moduleName = getModuleNameFromPath(kind, modulePath);
1716
1837
  dirs.forEach((dirname) => {
1717
- violations.push(`${getScanPath(exec, path7.join(modulePath, dirname))}: unsupported module folder`);
1838
+ violations.push(`${getScanPath(exec, path8.join(modulePath, dirname))}: unsupported module folder`);
1718
1839
  });
1719
1840
  const uiModuleName = moduleName[0].toUpperCase() + moduleName.slice(1);
1720
1841
  for (const filename of files) {
1721
- const scanPath = getScanPath(exec, path7.join(modulePath, filename));
1842
+ const scanPath = getScanPath(exec, path8.join(modulePath, filename));
1722
1843
  if (filename === "index.ts" || filename === "index.tsx" || /\.(test|spec)\.(ts|tsx)$/.test(filename))
1723
1844
  continue;
1724
1845
  if (filename === `${moduleName}.abstract.md`)
@@ -1791,16 +1912,16 @@ class ScanInfo {
1791
1912
  }
1792
1913
  };
1793
1914
  await Promise.all([
1794
- ...databaseDirs.map((name) => collect(path7.join("lib", name), name, "databases")),
1795
- ...serviceDirs.map((dirname) => collect(path7.join("lib", dirname), dirname.slice(1), "services")),
1796
- ...scalarDirs.map((name) => collect(path7.join("lib/__scalar", name), name, "scalars"))
1915
+ ...databaseDirs.map((name) => collect(path8.join("lib", name), name, "databases")),
1916
+ ...serviceDirs.map((dirname) => collect(path8.join("lib", dirname), dirname.slice(1), "services")),
1917
+ ...scalarDirs.map((name) => collect(path8.join("lib/__scalar", name), name, "scalars"))
1797
1918
  ]);
1798
1919
  const routes = exec.type === "lib" ? [] : await exec.getPageKeys();
1799
1920
  const common = {
1800
1921
  name: exec.name,
1801
1922
  type: exec.type,
1802
1923
  repoName: exec.workspace.repoName,
1803
- serveDomain: WorkspaceExecutor.getBaseDevEnv(path7.join(exec.workspace.workspaceRoot, ".env")).serveDomain,
1924
+ serveDomain: WorkspaceExecutor.getBaseDevEnv(path8.join(exec.workspace.workspaceRoot, ".env")).serveDomain,
1804
1925
  files,
1805
1926
  libDeps,
1806
1927
  pkgDeps,
@@ -2182,10 +2303,10 @@ class Executor {
2182
2303
  return this.#settle(proc, target, { redStderr: true }).then(({ code, signal }) => ({ code, signal }));
2183
2304
  }
2184
2305
  getPath(filePath) {
2185
- if (path8.isAbsolute(filePath))
2306
+ if (path9.isAbsolute(filePath))
2186
2307
  return filePath;
2187
2308
  if (filePath.startsWith("."))
2188
- return path8.join(this.cwdPath, filePath);
2309
+ return path9.join(this.cwdPath, filePath);
2189
2310
  const baseParts = this.cwdPath.split(/[\\/]/).filter(Boolean);
2190
2311
  const targetParts = filePath.split(/[\\/]/).filter(Boolean);
2191
2312
  let overlapLength = 0;
@@ -2199,7 +2320,7 @@ class Executor {
2199
2320
  if (isOverlap)
2200
2321
  overlapLength = i;
2201
2322
  }
2202
- return path8.join(this.cwdPath, ...targetParts.slice(overlapLength));
2323
+ return path9.join(this.cwdPath, ...targetParts.slice(overlapLength));
2203
2324
  }
2204
2325
  async mkdir(dirPath) {
2205
2326
  const writePath = this.getPath(dirPath);
@@ -2240,7 +2361,7 @@ class Executor {
2240
2361
  return this;
2241
2362
  }
2242
2363
  async removeDir(dirPath) {
2243
- const readPath = path8.join(this.getPath(dirPath), ".");
2364
+ const readPath = path9.join(this.getPath(dirPath), ".");
2244
2365
  if (await FileSys2.entryExists(readPath))
2245
2366
  await rm3(readPath, { recursive: true, force: true });
2246
2367
  this.logger.verbose(`Remove directory ${readPath}`);
@@ -2248,7 +2369,7 @@ class Executor {
2248
2369
  }
2249
2370
  async writeFile(filePath, content, { overwrite = true, silent = false } = {}) {
2250
2371
  const writePath = this.getPath(filePath);
2251
- const dir = path8.dirname(writePath);
2372
+ const dir = path9.dirname(writePath);
2252
2373
  if (!await FileSys2.dirExists(dir))
2253
2374
  await mkdir2(dir, { recursive: true });
2254
2375
  let contentStr = typeof content === "string" ? content : `${JSON.stringify(content, null, 2)}
@@ -2274,7 +2395,7 @@ class Executor {
2274
2395
  await this.writeFile(filePath, content);
2275
2396
  }
2276
2397
  async getLocalFile(targetPath) {
2277
- const filePath = path8.isAbsolute(targetPath) ? targetPath : targetPath.replace(this.cwdPath, "");
2398
+ const filePath = path9.isAbsolute(targetPath) ? targetPath : targetPath.replace(this.cwdPath, "");
2278
2399
  const content = await this.readFile(filePath);
2279
2400
  return { filePath, content };
2280
2401
  }
@@ -2361,9 +2482,9 @@ class Executor {
2361
2482
  const result = await getContent.default(scanInfo ?? null, dict, options);
2362
2483
  if (result === null)
2363
2484
  return null;
2364
- const filename = typeof result === "object" ? result.filename : path8.basename(targetPath).replace(".js", ".ts");
2485
+ const filename = typeof result === "object" ? result.filename : path9.basename(targetPath).replace(".js", ".ts");
2365
2486
  const content = typeof result === "object" ? result.content : result;
2366
- const convertedTargetPath = convertPath(`${path8.dirname(targetPath)}/${filename}`);
2487
+ const convertedTargetPath = convertPath(`${path9.dirname(targetPath)}/${filename}`);
2367
2488
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2368
2489
  return this.writeFile(convertedTargetPath, content, { overwrite });
2369
2490
  } else if (targetPath.endsWith(".template")) {
@@ -2372,10 +2493,10 @@ class Executor {
2372
2493
  const convertedContent = Object.entries(dict).reduce((data, [key, value]) => data.replace(new RegExp(`<%= ${key} %>`, "g"), value), content);
2373
2494
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2374
2495
  return this.writeFile(convertedTargetPath, convertedContent, { overwrite });
2375
- } else if (staticTemplateFileExtensions.has(path8.extname(targetPath).toLowerCase())) {
2496
+ } else if (staticTemplateFileExtensions.has(path9.extname(targetPath).toLowerCase())) {
2376
2497
  const convertedTargetPath = convertPath(targetPath);
2377
2498
  const writePath = this.getPath(convertedTargetPath);
2378
- const dirname = path8.dirname(writePath);
2499
+ const dirname = path9.dirname(writePath);
2379
2500
  if (!await FileSys2.dirExists(dirname))
2380
2501
  await mkdir2(dirname, { recursive: true });
2381
2502
  await copyFile(templatePath, writePath);
@@ -2397,7 +2518,7 @@ class Executor {
2397
2518
  if ((await stat2(templatePath)).isFile()) {
2398
2519
  const fileContent = await this.#applyTemplateFile({
2399
2520
  templatePath,
2400
- targetPath: path8.join(basePath, path8.basename(templatePath)),
2521
+ targetPath: path9.join(basePath, path9.basename(templatePath)),
2401
2522
  scanInfo,
2402
2523
  overwrite
2403
2524
  }, dict, options);
@@ -2405,19 +2526,19 @@ class Executor {
2405
2526
  } else {
2406
2527
  const subdirs = await readDirEntries(templatePath);
2407
2528
  const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
2408
- const subpath = path8.join(templatePath, subdir);
2529
+ const subpath = path9.join(templatePath, subdir);
2409
2530
  if ((await stat2(subpath)).isFile()) {
2410
2531
  const fileContent = await this.#applyTemplateFile({
2411
2532
  templatePath: subpath,
2412
- targetPath: path8.join(basePath, subdir),
2533
+ targetPath: path9.join(basePath, subdir),
2413
2534
  scanInfo,
2414
2535
  overwrite
2415
2536
  }, dict, options);
2416
2537
  return fileContent ? [fileContent] : [];
2417
2538
  } else
2418
2539
  return await this._applyTemplate({
2419
- basePath: path8.join(basePath, subdir),
2420
- template: path8.join(template, subdir),
2540
+ basePath: path9.join(basePath, subdir),
2541
+ template: path9.join(template, subdir),
2421
2542
  scanInfo,
2422
2543
  dict,
2423
2544
  overwrite,
@@ -2429,8 +2550,8 @@ class Executor {
2429
2550
  }
2430
2551
  async#resolveTemplateRoot() {
2431
2552
  const candidates = [
2432
- path8.resolve(getDirname2(import.meta.url), "templates"),
2433
- path8.resolve(getDirname2(import.meta.url), "../cli/templates")
2553
+ path9.resolve(getDirname2(import.meta.url), "templates"),
2554
+ path9.resolve(getDirname2(import.meta.url), "../cli/templates")
2434
2555
  ];
2435
2556
  for (const candidate of candidates) {
2436
2557
  if (await FileSys2.dirExists(candidate))
@@ -2498,11 +2619,11 @@ class Executor {
2498
2619
  async#resolveTypecheckWorkerEntry() {
2499
2620
  const dirname = getDirname2(import.meta.url);
2500
2621
  const candidates = [
2501
- path8.join(process.cwd(), "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
2502
- path8.join(process.cwd(), "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
2503
- path8.join(dirname, "typecheck/typecheck.proc.ts"),
2504
- path8.join(dirname, "typecheck.proc.js"),
2505
- path8.join(dirname, "typecheck.proc.ts")
2622
+ path9.join(process.cwd(), "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
2623
+ path9.join(process.cwd(), "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
2624
+ path9.join(dirname, "typecheck/typecheck.proc.ts"),
2625
+ path9.join(dirname, "typecheck.proc.js"),
2626
+ path9.join(dirname, "typecheck.proc.ts")
2506
2627
  ];
2507
2628
  for (const candidate of candidates)
2508
2629
  if (await Bun.file(candidate).exists())
@@ -2622,7 +2743,7 @@ class WorkspaceExecutor extends Executor {
2622
2743
  await Promise.all(dirs.map(async (dir) => {
2623
2744
  if (dir.includes("_") || AVOID_DIRS.includes(dir))
2624
2745
  return;
2625
- const dirPath = path8.join(dirname, dir);
2746
+ const dirPath = path9.join(dirname, dir);
2626
2747
  if ((await stat2(dirPath)).isDirectory()) {
2627
2748
  results.push(`${prefix}${dir}`);
2628
2749
  if (maxDepth > 0)
@@ -2653,15 +2774,15 @@ class WorkspaceExecutor extends Executor {
2653
2774
  async#getDirHasFile(basePath, targetFilename) {
2654
2775
  if (!await FileSys2.dirExists(basePath))
2655
2776
  return [];
2656
- const AVOID_DIRS = ["node_modules", "dist", "public", "webkit"];
2777
+ const AVOID_DIRS = ["node_modules", "dist", "public", "webkit", "local"];
2657
2778
  const getDirs = async (dirname, maxDepth = 3, results = [], prefix = "") => {
2658
2779
  const dirs = await this.readdir(dirname);
2659
2780
  await Promise.all(dirs.map(async (dir) => {
2660
2781
  if (AVOID_DIRS.includes(dir))
2661
2782
  return;
2662
- const dirPath = path8.join(dirname, dir);
2783
+ const dirPath = path9.join(dirname, dir);
2663
2784
  if (await FileSys2.dirExists(dirPath)) {
2664
- const hasTargetFile = await FileSys2.fileExists(path8.join(dirPath, targetFilename));
2785
+ const hasTargetFile = await FileSys2.fileExists(path9.join(dirPath, targetFilename));
2665
2786
  if (hasTargetFile)
2666
2787
  results.push(`${prefix}${dir}`);
2667
2788
  if (maxDepth > 0)
@@ -2721,7 +2842,7 @@ class SysExecutor extends Executor {
2721
2842
  return [];
2722
2843
  const violations = [];
2723
2844
  for (const entry of await this.getAllFiles("**/*", { cwd: this.getPath("page") })) {
2724
- const relativePath = entry.split(path8.sep).join("/");
2845
+ const relativePath = entry.split(path9.sep).join("/");
2725
2846
  const reason = getPageSourceFileViolation(relativePath);
2726
2847
  if (reason)
2727
2848
  violations.push({ relativePath: `page/${relativePath}`, reason });
@@ -2818,7 +2939,7 @@ class SysExecutor extends Executor {
2818
2939
  await this.setPackageJson(libPkgJsonWithDeps);
2819
2940
  }
2820
2941
  async getLocalFile(targetPath) {
2821
- const filePath = path8.isAbsolute(targetPath) ? targetPath : `${this.type}s/${this.name}/${targetPath}`;
2942
+ const filePath = path9.isAbsolute(targetPath) ? targetPath : `${this.type}s/${this.name}/${targetPath}`;
2822
2943
  const content = await this.workspace.readFile(filePath);
2823
2944
  return { filePath, content };
2824
2945
  }
@@ -2906,6 +3027,18 @@ class AppExecutor extends SysExecutor {
2906
3027
  static from(executor, name) {
2907
3028
  return new AppExecutor({ workspace: executor instanceof WorkspaceExecutor ? executor : executor.workspace, name });
2908
3029
  }
3030
+ static #keptOnStart = [path9.join(".akan", "mobile"), path9.join(".akan", "cache", "bin")];
3031
+ async#removeDevOutput(dir = ".akan") {
3032
+ const entries = await readDirEntries(this.getPath(dir)).catch(() => []);
3033
+ await Promise.all(entries.map(async (name) => {
3034
+ const entry = path9.join(dir, name);
3035
+ if (AppExecutor.#keptOnStart.includes(entry))
3036
+ return;
3037
+ if (AppExecutor.#keptOnStart.some((kept) => kept.startsWith(`${entry}${path9.sep}`)))
3038
+ return await this.#removeDevOutput(entry);
3039
+ await this.removeDir(entry);
3040
+ }));
3041
+ }
2909
3042
  getEnv() {
2910
3043
  return WorkspaceExecutor.getBaseDevEnv().env;
2911
3044
  }
@@ -2959,7 +3092,7 @@ class AppExecutor extends SysExecutor {
2959
3092
  ...akanConfig.web.ssr ? [this.cp("public", `${this.dist.cwdPath}/public`, { dereference: true })] : []
2960
3093
  ]);
2961
3094
  } else {
2962
- await this.removeDir(".akan");
3095
+ await this.#removeDevOutput();
2963
3096
  if (!akanConfig.web.ssr || !akanConfig.web.csr)
2964
3097
  this.logger.verbose(`akan.config.ts disables web.${!akanConfig.web.ssr ? "ssr" : "csr"}; \`akan start\` still serves it, \`akan build\` will not`);
2965
3098
  }
@@ -3025,13 +3158,13 @@ class AppExecutor extends SysExecutor {
3025
3158
  absolute: false,
3026
3159
  onlyFiles: true
3027
3160
  })) {
3028
- const segments = rel.split(path8.sep);
3161
+ const segments = rel.split(path9.sep);
3029
3162
  if (segments.some((s) => s === "node_modules"))
3030
3163
  continue;
3031
3164
  const posix = `${root.keyPrefix}${segments.join("/")}`;
3032
3165
  if (!root.keyPrefix && libKeyPrefixes.some((prefix) => posix.startsWith(prefix)))
3033
3166
  continue;
3034
- const absPath = path8.join(root.dir, ...segments);
3167
+ const absPath = path9.join(root.dir, ...segments);
3035
3168
  validatePageSourceFile(posix, { filePath: absPath });
3036
3169
  if (!isRouteSourceFile(posix))
3037
3170
  continue;
@@ -3172,7 +3305,7 @@ class AppExecutor extends SysExecutor {
3172
3305
  static async#linkLibAsset(targetPath, linkPath) {
3173
3306
  const isWindows = process.platform === "win32";
3174
3307
  try {
3175
- const target = isWindows ? targetPath : path8.relative(path8.dirname(linkPath), targetPath);
3308
+ const target = isWindows ? targetPath : path9.relative(path9.dirname(linkPath), targetPath);
3176
3309
  await symlink(target, linkPath, isWindows ? "junction" : "dir");
3177
3310
  } catch (error) {
3178
3311
  if (!isWindows)
@@ -3215,7 +3348,7 @@ class AppExecutor extends SysExecutor {
3215
3348
  await this.writeFile(rel, content, opts);
3216
3349
  },
3217
3350
  readEnvClient: async () => {
3218
- const envClientPath = path8.join(this.cwdPath, "env", "env.client.ts");
3351
+ const envClientPath = path9.join(this.cwdPath, "env", "env.client.ts");
3219
3352
  if (!await FileSys2.fileExists(envClientPath))
3220
3353
  return null;
3221
3354
  try {
@@ -3309,7 +3442,7 @@ class PkgExecutor extends Executor {
3309
3442
  return overrideVersion;
3310
3443
  try {
3311
3444
  const packageJsonPath = `pkgs/${dep}/package.json`;
3312
- if (!await Bun.file(path8.join(this.workspace.workspaceRoot, packageJsonPath)).exists())
3445
+ if (!await Bun.file(path9.join(this.workspace.workspaceRoot, packageJsonPath)).exists())
3313
3446
  return;
3314
3447
  const packageJson = await this.workspace.readJson(packageJsonPath);
3315
3448
  if (packageJson.name === dep)
@@ -3402,4 +3535,4 @@ class ModuleExecutor extends Executor {
3402
3535
  }
3403
3536
  }
3404
3537
 
3405
- export { AGENT_BLOCK_START, AGENT_BLOCK_END, stampBlockVersion, extractBlockVersion, readDevkitVersion, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, CLAUDE_COMMENT_RULE, AsyncDefaultExportDetector, resolveSsrPageEntriesForApp, CodegenLock, Linter, rootAllowedFiles, rootAllowedDirs, isAllowedLibFacetRootFile, rootEntryHintOf, isScannedRootEntry, AppInfo, Spinner, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
3538
+ 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 };