@akanjs/cli 3.0.0-beta.19 → 3.0.0-beta.20

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 (95) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-6cm97kay.js → CodeAgent-awv258wb.js} +2 -2
  3. package/{CodeTui-za4jsm41.js → CodeTui-1nqh35ez.js} +20 -22
  4. package/TunnelShare-scf4e4pd.js +9 -0
  5. package/{agent.command-e0wpbbyg.js → agent.command-1s9ag7sb.js} +8 -9
  6. package/akanCode.js +4 -4
  7. package/{application.command-8wyxqc8q.js → application.command-49hwy6va.js} +25 -56
  8. package/{applicationBuildRunner-n9gzaxd0.js → applicationBuildRunner-ybyp97pv.js} +33 -59
  9. package/{applicationReleasePackager-vpggfqgq.js → applicationReleasePackager-esnrphw8.js} +40 -60
  10. package/buildBatch.proc.js +19 -24
  11. package/{capacitorApp-q3z0qht0.js → capacitorApp-1synz4en.js} +3 -4
  12. package/{cloud.command-4zwa5dsx.js → cloud.command-d7rqtzt9.js} +16 -26
  13. package/cloud.script-bkbpcr96.js +19 -0
  14. package/{code.command-468c9d7s.js → code.command-nn48xzej.js} +22 -37
  15. package/context.command-s3mcmvpa.js +48 -0
  16. package/context.runner-k99nb5pk.js +21 -0
  17. package/{dependencyScanner-0z2h2tks.js → dependencyScanner-ye2e6pdz.js} +2 -2
  18. package/{devTui-ffjsarqa.js → devTui-q7k7bakd.js} +5 -9
  19. package/fileSys-5ngz93ga.js +9 -0
  20. package/{guideline.command-vhw13pqr.js → guideline.command-sct4qnt5.js} +4 -5
  21. package/guidelines/conventions/conventions.instruction.md +5 -1
  22. package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
  23. package/incrementalBuilder.proc.js +30 -48
  24. package/{index-s5rhm04y.js → index-0bq14vr1.js} +1 -1
  25. package/{index-10dkrrww.js → index-13ffe9wp.js} +4 -4
  26. package/{index-srmay5jw.js → index-22d57v4c.js} +84 -67
  27. package/{index-53176s7j.js → index-31yr441d.js} +10 -17
  28. package/index-3hx1z96c.js +87 -0
  29. package/{index-4m929vvn.js → index-3sq321ak.js} +10 -18
  30. package/{index-bhtmj233.js → index-3t7g9e4r.js} +41 -78
  31. package/{index-q0y2jq9j.js → index-5b6tavv3.js} +6 -3
  32. package/{index-47pj3aee.js → index-5e0n4hqx.js} +11 -12
  33. package/{index-7ep8qtvp.js → index-5pc1qrbv.js} +5 -8
  34. package/{index-esk82rvk.js → index-8mna0947.js} +34 -71
  35. package/{index-sq2dzkzm.js → index-8sf7wmdr.js} +6 -6
  36. package/{index-crmeqnmf.js → index-9d9bgcx4.js} +283 -722
  37. package/{index-bwf965h6.js → index-ahemdr5n.js} +6 -6
  38. package/{index-ab0c38ea.js → index-as7xmyz8.js} +20 -20
  39. package/{index-bc88j1ry.js → index-axzjaqve.js} +94 -142
  40. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  41. package/{index-667w0yah.js → index-c6eggbee.js} +2 -5
  42. package/{index-a1w6934z.js → index-ddxvdd1p.js} +169 -305
  43. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  44. package/{index-22xtgmhn.js → index-dzf3r49a.js} +1 -1
  45. package/{index-89hy31kf.js → index-fgq75haa.js} +172 -287
  46. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  47. package/{index-hwkygn9s.js → index-khpfpcsd.js} +302 -33
  48. package/{index-vqx8bdxz.js → index-mxav6j3c.js} +78 -231
  49. package/{index-2446k7b4.js → index-myhc3c1j.js} +512 -588
  50. package/{index-3jrp517k.js → index-nv5976x3.js} +45 -128
  51. package/{index-zqgj2rt2.js → index-przybvy5.js} +69 -147
  52. package/{index-n3cv0tm4.js → index-smme4r47.js} +1 -1
  53. package/{index-qdgzsnhg.js → index-w2zdcw3k.js} +110 -231
  54. package/{index-14zrtgfa.js → index-wa5jbxj1.js} +6 -39
  55. package/{index-bftkz6cp.js → index-ww4z397j.js} +198 -555
  56. package/{index-kwaq3n9n.js → index-xqjwd384.js} +4 -7
  57. package/{index-txr7dj2g.js → index-xqpzbab5.js} +106 -240
  58. package/{index-e4v6vhxq.js → index-xsjh6nzh.js} +178 -165
  59. package/{index-18zybgkc.js → index-ygn77a5w.js} +47 -99
  60. package/{index-9d6nvkz2.js → index-ztp3e73t.js} +79 -35
  61. package/index.js +23 -24
  62. package/{library.command-cqr175dy.js → library.command-1gx04jgn.js} +4 -5
  63. package/{localRegistry.command-49z55qqz.js → localRegistry.command-zndxj1q6.js} +21 -42
  64. package/{module.command-9p8mm3b0.js → module.command-3waddk95.js} +6 -7
  65. package/{package.command-wxyz909t.js → package.command-zrc7br1y.js} +5 -6
  66. package/package.json +2 -2
  67. package/{page.command-gsrsfqqs.js → page.command-vpjgardh.js} +4 -5
  68. package/{primitive.command-ns1mptje.js → primitive.command-sz84tk4t.js} +9 -20
  69. package/{prompter-1f8d9pcc.js → prompter-ptaa3nk0.js} +2 -2
  70. package/{quality.command-e76k2q9k.js → quality.command-g869hafs.js} +129 -363
  71. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  72. package/{repair.command-pkrsm3cw.js → repair.command-chsnjvvv.js} +11 -35
  73. package/{scalar.command-0cpt3fc8.js → scalar.command-2v21newx.js} +5 -6
  74. package/skills/akan-code/SKILL.md +12 -4
  75. package/{subspace.command-fktpwp0g.js → subspace.command-ckcbwfp1.js} +39 -58
  76. package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +3 -3
  77. package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +3 -3
  78. package/templates/client.ts +7 -30
  79. package/templates/lib/__lib/lib.dictionary.ts +0 -2
  80. package/templates/lib/__lib/lib.document.ts +0 -2
  81. package/templates/lib/sig.ts +8 -30
  82. package/templates/server.ts +0 -2
  83. package/{tunnel.command-d5jy9gk8.js → tunnel.command-kd2yr4fx.js} +5 -6
  84. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  85. package/typecheck.proc.js +1 -1
  86. package/workflow.command-44252cqv.js +79 -0
  87. package/{workspace.command-gv84eh1p.js → workspace.command-fqcztt5p.js} +72 -107
  88. package/TunnelShare-2j6s511d.js +0 -9
  89. package/cloud.script-fwx3vb34.js +0 -20
  90. package/context.command-dsnw0jby.js +0 -80
  91. package/context.runner-rs4rj15d.js +0 -22
  92. package/devTuiView-1q1mdgrv.js +0 -9
  93. package/getDirname-dr3jz1xg.js +0 -7
  94. package/index-6wwzs1bc.js +0 -7
  95. package/workflow.command-6tkcysmx.js +0 -105
@@ -1,11 +1,11 @@
1
1
  // @bun
2
2
  import {
3
3
  CommandExecutionError
4
- } from "./index-crmeqnmf.js";
4
+ } from "./index-9d9bgcx4.js";
5
5
  import {
6
6
  resolveMobilePath,
7
7
  targetHtmlFilename
8
- } from "./index-47pj3aee.js";
8
+ } from "./index-5e0n4hqx.js";
9
9
 
10
10
  // pkgs/@akanjs/devkit/capacitorApp.ts
11
11
  import { cp, mkdir, readFile, rm, writeFile } from "fs/promises";
@@ -13,7 +13,7 @@ import os from "os";
13
13
  import path from "path";
14
14
  import { select } from "@inquirer/prompts";
15
15
  import { MobileProject } from "@trapezedev/project";
16
- import { capitalize } from "akanjs/common";
16
+ import { capitalize, isRecord } from "akanjs/common";
17
17
 
18
18
  // pkgs/@akanjs/devkit/fileEditor.ts
19
19
  class FileEditor {
@@ -32,52 +32,28 @@ class FileEditor {
32
32
  }
33
33
  }
34
34
  find(pattern) {
35
- const lines = this.#content.split(`
36
- `);
37
35
  const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
38
- for (let i = 0;i < lines.length; i++) {
39
- const line = lines[i];
40
- if (!line)
41
- continue;
42
- if (regex.test(line))
43
- return i;
44
- }
45
- return -1;
36
+ return this.#content.split(`
37
+ `).findIndex((line) => !!line && regex.test(line));
46
38
  }
47
39
  findAll(pattern) {
48
- const lines = this.#content.split(`
49
- `);
50
40
  const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
51
- const matches = [];
52
- for (let i = 0;i < lines.length; i++) {
53
- const line = lines[i];
54
- if (!line)
55
- continue;
56
- if (regex.test(line))
57
- matches.push(i);
58
- }
59
- return matches;
41
+ return this.#content.split(`
42
+ `).flatMap((line, index) => line && regex.test(line) ? [index] : []);
60
43
  }
61
44
  insertAfter(pattern, data) {
62
- const lineIndex = this.find(pattern);
63
- if (lineIndex === -1) {
64
- throw new Error(`Pattern not found: ${pattern}`);
65
- }
66
- const lines = this.#content.split(`
67
- `);
68
- lines.splice(lineIndex + 1, 0, data);
69
- this.#content = lines.join(`
70
- `);
71
- return this;
45
+ return this.#insertAt(pattern, data, 1);
72
46
  }
73
47
  insertBefore(pattern, data) {
48
+ return this.#insertAt(pattern, data, 0);
49
+ }
50
+ #insertAt(pattern, data, offset) {
74
51
  const lineIndex = this.find(pattern);
75
- if (lineIndex === -1) {
52
+ if (lineIndex === -1)
76
53
  throw new Error(`Pattern not found: ${pattern}`);
77
- }
78
54
  const lines = this.#content.split(`
79
55
  `);
80
- lines.splice(lineIndex, 0, data);
56
+ lines.splice(lineIndex + offset, 0, data);
81
57
  this.#content = lines.join(`
82
58
  `);
83
59
  return this;
@@ -115,30 +91,7 @@ ${this.#content}`;
115
91
 
116
92
  // pkgs/@akanjs/devkit/capacitorApp.ts
117
93
  var SWIFTUICORE_MIN_IOS_MAJOR = 18;
118
- var iosNativeBlockedEnvKeys = new Set([
119
- "AR",
120
- "AS",
121
- "CC",
122
- "CFLAGS",
123
- "CONDA_BUILD_SYSROOT",
124
- "CONDA_PREFIX",
125
- "CPP",
126
- "CPPFLAGS",
127
- "CPATH",
128
- "CXX",
129
- "CXXFLAGS",
130
- "LD",
131
- "LDFLAGS",
132
- "LIBRARY_PATH",
133
- "MACOSX_DEPLOYMENT_TARGET",
134
- "NM",
135
- "OBJC",
136
- "OBJCXX",
137
- "PREFIX",
138
- "RANLIB",
139
- "SDKROOT",
140
- "STRIP"
141
- ]);
94
+ var iosNativeBlockedEnvKeys = new Set("AR AS CC CFLAGS CONDA_BUILD_SYSROOT CONDA_PREFIX CPP CPPFLAGS CPATH CXX CXXFLAGS LD LDFLAGS LIBRARY_PATH".split(" ").concat("MACOSX_DEPLOYMENT_TARGET NM OBJC OBJCXX PREFIX RANLIB SDKROOT STRIP".split(" ")));
142
95
  var rootCapacitorConfigFilenames = [
143
96
  "capacitor.config.ts",
144
97
  "capacitor.config.js",
@@ -152,22 +105,7 @@ async function writeRootCapacitorConfig(appRoot, content) {
152
105
  await clearRootCapacitorConfigs(appRoot);
153
106
  await Bun.write(path.join(appRoot, "capacitor.config.json"), content);
154
107
  }
155
- var virtualInterfacePrefixes = [
156
- "bridge",
157
- "utun",
158
- "llw",
159
- "awdl",
160
- "ap",
161
- "vmnet",
162
- "vnic",
163
- "tap",
164
- "tun",
165
- "docker",
166
- "veth",
167
- "vboxnet",
168
- "gif",
169
- "stf"
170
- ];
108
+ var virtualInterfacePrefixes = "bridge utun llw awdl ap vmnet vnic tap tun docker veth vboxnet gif stf".split(" ");
171
109
  var physicalInterfacePrefixes = ["en", "eth", "wlan", "wlp", "enp", "eno", "wlo"];
172
110
  var isPrivateLanIpv4 = (address) => {
173
111
  if (address.startsWith("10.") || address.startsWith("192.168."))
@@ -203,7 +141,6 @@ var selectLocalDevHost = (interfaces, { override } = {}) => {
203
141
  const [best] = [...candidates].sort((a, b) => scoreDevHostCandidate(b.name, b.address) - scoreDevHostCandidate(a.name, a.address) || a.name.localeCompare(b.name) || a.address.localeCompare(b.address));
204
142
  return best ? { host: best.address, source: "detected", candidates } : { host: "127.0.0.1", source: "loopback", candidates };
205
143
  };
206
- var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
207
144
  var asString = (value) => typeof value === "string" ? value : undefined;
208
145
  var firstString = (...values) => values.find((value) => typeof value === "string");
209
146
  var scoreIosDeviceTarget = (target) => {
@@ -232,11 +169,8 @@ var formatSimctlRuntime = (key) => {
232
169
  return `${match[1]} ${match[2]}${match[3] ? `.${match[3]}` : ""}`;
233
170
  };
234
171
  var parseIosRuntimeMajor = (runtime) => {
235
- const major = runtime?.match(/(\d+)/)?.[1];
236
- if (major === undefined)
237
- return;
238
- const parsed = Number.parseInt(major, 10);
239
- return Number.isNaN(parsed) ? undefined : parsed;
172
+ const major = runtime?.match(/\d+/)?.[0];
173
+ return major === undefined ? undefined : Number.parseInt(major, 10);
240
174
  };
241
175
  var iosRunTargetRank = (target) => {
242
176
  const state = target.state?.toLowerCase() ?? "";
@@ -566,9 +500,8 @@ function assertJsonSerializable(value, label = "capacitor.config", seen = new We
566
500
  throw new Error(`${label} must be JSON serializable. Found circular reference.`);
567
501
  seen.add(objectValue);
568
502
  if (Array.isArray(value)) {
569
- value.forEach((item, index) => {
503
+ for (const [index, item] of value.entries())
570
504
  assertJsonSerializable(item, `${label}[${index}]`, seen);
571
- });
572
505
  return;
573
506
  }
574
507
  for (const [key, item] of Object.entries(value)) {
@@ -729,7 +662,6 @@ class CapacitorApp2 {
729
662
  await this.#prepareIos({ operation: "release", env, regenerate });
730
663
  await this.#spawnMobile("npx", ["cap", "build", "ios"], { operation: "release", env }, { stdio: "inherit" });
731
664
  this.app.verbose(`build completed iOS.`);
732
- return;
733
665
  }
734
666
  async syncIos() {
735
667
  await this.#spawnMobile("npx", ["cap", "sync", "ios"], { operation: "local", env: "local" });
@@ -749,7 +681,10 @@ class CapacitorApp2 {
749
681
  await this.#runIosPhysicalDevice({ operation, env, runTarget, noAllowProvisioningUpdates });
750
682
  }
751
683
  async#selectIosRunTarget(deviceId) {
752
- const targets = sortIosRunTargets(await this.#loadIosRunTargets());
684
+ const targets = sortIosRunTargets([
685
+ ...await this.#loadPhysicalIosDevices(),
686
+ ...await this.#loadIosSimulators()
687
+ ]);
753
688
  if (deviceId) {
754
689
  const needle = deviceId.toLowerCase();
755
690
  const found = targets.find((target) => target.id === deviceId) ?? targets.find((target) => target.name.toLowerCase() === needle) ?? targets.find((target) => target.name.toLowerCase().includes(needle) || target.id.toLowerCase().includes(needle) || (target.runtime?.toLowerCase().includes(needle) ?? false));
@@ -781,11 +716,6 @@ class CapacitorApp2 {
781
716
  return;
782
717
  this.app.logger.warn(`Selected simulator runs ${target.runtime ?? "an older iOS"}. Recent SDK builds link SwiftUICore and require iOS ${SWIFTUICORE_MIN_IOS_MAJOR}+; if the app crashes at launch with a "Library not loaded: SwiftUICore" dyld error, pick an iOS ${SWIFTUICORE_MIN_IOS_MAJOR}+ simulator instead.`);
783
718
  }
784
- async#loadIosRunTargets() {
785
- const devices = await this.#loadPhysicalIosDevices();
786
- const simulators = await this.#loadIosSimulators();
787
- return [...devices, ...simulators];
788
- }
789
719
  async#loadPhysicalIosDevices() {
790
720
  try {
791
721
  return parseDevicectlDevices(await this.#spawn("xcrun", ["devicectl", "list", "devices", "--json-output", "-"]));
@@ -820,12 +750,11 @@ ${textError instanceof Error ? textError.message : ""}`);
820
750
  }) {
821
751
  const mobileEnv = sanitizeIosNativeRunEnv(await this.#commandEnv(operation, env));
822
752
  const configContent = await this.#writeCapacitorConfig({ operation, platform: "ios", iosRunTargetKind: runTarget.kind }, mobileEnv);
823
- await this.#writeRootCapacitorConfig(configContent);
824
- const scheme = this.#iosScheme();
753
+ await writeRootCapacitorConfig(this.app.cwdPath, configContent);
825
754
  const command = buildIosNativeRunCommand({
826
755
  appRoot: this.app.cwdPath,
827
756
  device: runTarget,
828
- scheme,
757
+ scheme: isRecord(this.target.ios) && typeof this.target.ios.scheme === "string" ? this.target.ios.scheme : "App",
829
758
  configuration: operation === "release" ? "Release" : "Debug"
830
759
  });
831
760
  const xcodebuildArgs = noAllowProvisioningUpdates ? command.xcodebuildArgs : [...command.xcodebuildArgs.slice(0, -1), "-allowProvisioningUpdates", ...command.xcodebuildArgs.slice(-1)];
@@ -835,12 +764,9 @@ ${textError instanceof Error ? textError.message : ""}`);
835
764
  env: mobileEnv
836
765
  });
837
766
  const devicectlId = runTarget.devicectlId ?? runTarget.id;
838
- await this.#spawn("xcrun", ["devicectl", "device", "install", "app", "--device", devicectlId, command.appPath], {
839
- env: mobileEnv
840
- });
841
- await this.#spawn("xcrun", ["devicectl", "device", "process", "launch", "--device", devicectlId, this.target.appId], {
842
- env: mobileEnv
843
- });
767
+ const devicectl = (verb, subject) => this.#spawn("xcrun", ["devicectl", "device", ...verb, "--device", devicectlId, subject], { env: mobileEnv });
768
+ await devicectl(["install", "app"], command.appPath);
769
+ await devicectl(["process", "launch"], this.target.appId);
844
770
  } catch (error) {
845
771
  throw new Error(formatIosRunFailureMessage({
846
772
  classification: classifyIosRunFailure(this.#errorOutput(error)),
@@ -849,12 +775,9 @@ ${textError instanceof Error ? textError.message : ""}`);
849
775
  teamId: await this.#getIosDevelopmentTeam()
850
776
  }));
851
777
  } finally {
852
- await this.#clearRootCapacitorConfigs();
778
+ await clearRootCapacitorConfigs(this.app.cwdPath);
853
779
  }
854
780
  }
855
- #iosScheme() {
856
- return isRecord(this.target.ios) && typeof this.target.ios.scheme === "string" ? this.target.ios.scheme : "App";
857
- }
858
781
  async#getIosDevelopmentTeam() {
859
782
  const pbxprojPath = path.join(this.app.cwdPath, this.iosProjectPath, "App.xcodeproj/project.pbxproj");
860
783
  if (!await Bun.file(pbxprojPath).exists())
@@ -879,7 +802,7 @@ ${error.message}`;
879
802
  await this.#disableNativeKeyboardResizeInAndroid();
880
803
  await this.project.commit();
881
804
  await this.#generateAssets({ operation, env });
882
- await this.#ensureAndroidAssetsDir();
805
+ await mkdir(path.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
883
806
  await this.#ensureAndroidDebugKeystore();
884
807
  await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
885
808
  await this.#setDeepLinksInAndroid(this.target.deepLinks?.schemes ?? [], this.target.deepLinks?.domains ?? []);
@@ -925,8 +848,7 @@ ${error.message}`;
925
848
  await this.#prepareAndroid({ operation: "release", env, regenerate });
926
849
  await this.#assertAndroidReleaseSigningConfig();
927
850
  await this.#updateAndroidBuildTypes();
928
- const isWindows = process.platform === "win32";
929
- const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
851
+ const gradleCommand = process.platform === "win32" ? "gradlew.bat" : "./gradlew";
930
852
  await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
931
853
  stdio: "inherit",
932
854
  cwd: path.join(this.app.cwdPath, this.androidRootPath),
@@ -953,30 +875,17 @@ ${error.message}`;
953
875
  if (changed)
954
876
  await writeFile(manifestPath, manifest);
955
877
  }
956
- async#ensureAndroidAssetsDir() {
957
- await mkdir(path.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
958
- }
959
878
  async#ensureAndroidDebugKeystore() {
960
879
  const keystorePath = path.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
961
880
  if (await Bun.file(keystorePath).exists())
962
881
  return;
882
+ const options = "-storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000";
963
883
  await this.#spawn("keytool", [
964
884
  "-genkeypair",
965
885
  "-v",
966
886
  "-keystore",
967
887
  keystorePath,
968
- "-storepass",
969
- "android",
970
- "-alias",
971
- "androiddebugkey",
972
- "-keypass",
973
- "android",
974
- "-keyalg",
975
- "RSA",
976
- "-keysize",
977
- "2048",
978
- "-validity",
979
- "10000",
888
+ ...options.split(" "),
980
889
  "-dname",
981
890
  "CN=Android Debug,O=Android,C=US"
982
891
  ]);
@@ -992,8 +901,7 @@ ${error.message}`;
992
901
  await this.#prepareAndroid({ operation, env, regenerate });
993
902
  await this.#assertAndroidAdbReady();
994
903
  this.app.logger.info(`Running Android in ${operation} mode on ${env} env`);
995
- const args = ["cap", "run", "android"];
996
- await this.#spawnMobile("npx", args, { operation, env }, { stdio: "inherit" });
904
+ await this.#spawnMobile("npx", ["cap", "run", "android"], { operation, env }, { stdio: "inherit" });
997
905
  }
998
906
  async#assertAndroidReleaseSigningConfig() {
999
907
  const gradlePropertiesPath = path.join(this.app.cwdPath, this.androidRootPath, "gradle.properties");
@@ -1100,14 +1008,12 @@ ${error.message}`;
1100
1008
  if (!this.target.assets)
1101
1009
  return;
1102
1010
  await mkdir(this.targetAssetRoot, { recursive: true });
1103
- if (this.target.assets.icon)
1104
- await cp(path.join(this.app.cwdPath, this.target.assets.icon), path.join(this.targetAssetRoot, "icon.png"), {
1105
- force: true
1106
- });
1107
- if (this.target.assets.splash)
1108
- await cp(path.join(this.app.cwdPath, this.target.assets.splash), path.join(this.targetAssetRoot, "splash.png"), {
1109
- force: true
1110
- });
1011
+ for (const [name, source] of [
1012
+ ["icon", this.target.assets.icon],
1013
+ ["splash", this.target.assets.splash]
1014
+ ])
1015
+ if (source)
1016
+ await cp(path.join(this.app.cwdPath, source), path.join(this.targetAssetRoot, `${name}.png`), { force: true });
1111
1017
  }
1112
1018
  async#prepareExternalFiles(platform) {
1113
1019
  const files = this.target.files?.[platform];
@@ -1193,20 +1099,11 @@ ${error.message}`;
1193
1099
  operation,
1194
1100
  env,
1195
1101
  setIosUsageDescriptions: (descriptions) => this.#setPermissionInIos(descriptions),
1196
- updateIosInfoPlist: async (values) => {
1197
- await Promise.all([
1198
- this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", values),
1199
- this.project.ios.updateInfoPlist(this.iosTargetName, "Release", values)
1200
- ]);
1201
- },
1102
+ updateIosInfoPlist: (values) => this.#updateIosInfoPlist(values),
1202
1103
  addIosEntitlements: (entitlements) => this.#addIosEntitlements(entitlements),
1203
1104
  editIosAppDelegate: (transform) => this.#editIosAppDelegate(transform),
1204
- addAndroidPermissions: (permissions) => {
1205
- this.#setPermissionsInAndroid(permissions);
1206
- },
1207
- addAndroidFeatures: (features) => {
1208
- this.#setFeaturesInAndroid(features);
1209
- }
1105
+ addAndroidPermissions: (permissions) => this.#setPermissionsInAndroid(permissions),
1106
+ addAndroidFeatures: (features) => this.#setFeaturesInAndroid(features)
1210
1107
  };
1211
1108
  }
1212
1109
  async#applyDeepLinks(platform, { operation, env }) {
@@ -1277,12 +1174,6 @@ ${error.message}`;
1277
1174
  params.set("akanMobileIndexPath", this.target.indexPath);
1278
1175
  return `http://${ip}:${port}/${pathname}?${params}`;
1279
1176
  }
1280
- async#clearRootCapacitorConfigs() {
1281
- await clearRootCapacitorConfigs(this.app.cwdPath);
1282
- }
1283
- async#writeRootCapacitorConfig(content) {
1284
- await writeRootCapacitorConfig(this.app.cwdPath, content);
1285
- }
1286
1177
  async#spawn(command, args = [], options = {}) {
1287
1178
  return await this.app.spawn(command, args, { cwd: this.app.cwdPath, ...options });
1288
1179
  }
@@ -1290,14 +1181,11 @@ ${error.message}`;
1290
1181
  const { iosRunTargetKind, platform, ...spawnOptions } = options;
1291
1182
  const mobileEnv = { ...await this.#commandEnv(operation, env), ...options.env };
1292
1183
  const configContent = await this.#writeCapacitorConfig({ operation, platform: platform ?? this.#inferMobilePlatform(args), iosRunTargetKind }, mobileEnv);
1293
- await this.#writeRootCapacitorConfig(configContent);
1184
+ await writeRootCapacitorConfig(this.app.cwdPath, configContent);
1294
1185
  try {
1295
- return await this.#spawn(command, args, {
1296
- ...spawnOptions,
1297
- env: mobileEnv
1298
- });
1186
+ return await this.#spawn(command, args, { ...spawnOptions, env: mobileEnv });
1299
1187
  } finally {
1300
- await this.#clearRootCapacitorConfigs();
1188
+ await clearRootCapacitorConfigs(this.app.cwdPath);
1301
1189
  }
1302
1190
  }
1303
1191
  #inferMobilePlatform(args) {
@@ -1342,22 +1230,16 @@ ${error.message}`;
1342
1230
  if (next !== content)
1343
1231
  await editor.setContent(next).save();
1344
1232
  }
1233
+ async#updateIosInfoPlist(values) {
1234
+ await Promise.all(["Debug", "Release"].map((build) => this.project.ios.updateInfoPlist(this.iosTargetName, build, values)));
1235
+ }
1345
1236
  async#setPermissionInIos(permissions) {
1346
- const updateNs = toIosInfoPlistUsageDescriptions(permissions);
1347
- await Promise.all([
1348
- this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", updateNs),
1349
- this.project.ios.updateInfoPlist(this.iosTargetName, "Release", updateNs)
1350
- ]);
1237
+ await this.#updateIosInfoPlist(toIosInfoPlistUsageDescriptions(permissions));
1351
1238
  }
1352
1239
  async#setUrlSchemesInIos(schemes) {
1353
- const urlTypes = schemes.map((scheme) => ({
1354
- CFBundleURLName: this.target.appId,
1355
- CFBundleURLSchemes: [scheme]
1356
- }));
1357
- await Promise.all([
1358
- this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", { CFBundleURLTypes: urlTypes }),
1359
- this.project.ios.updateInfoPlist(this.iosTargetName, "Release", { CFBundleURLTypes: urlTypes })
1360
- ]);
1240
+ await this.#updateIosInfoPlist({
1241
+ CFBundleURLTypes: schemes.map((scheme) => ({ CFBundleURLName: this.target.appId, CFBundleURLSchemes: [scheme] }))
1242
+ });
1361
1243
  }
1362
1244
  #serializeIosEntitlements(entitlements) {
1363
1245
  const lines = [];
@@ -1433,97 +1315,62 @@ ${error.message}`;
1433
1315
  return;
1434
1316
  await this.#setCodeSignEntitlementsInIos(entitlementsRelPath);
1435
1317
  }
1436
- async#setUrlSchemesInAndroid(schemes) {
1318
+ async#setDeepLinksInAndroid(schemes, domains) {
1437
1319
  const manifestPath = path.join(this.app.cwdPath, this.androidRootPath, "app/src/main/AndroidManifest.xml");
1438
- let manifest = await readFile(manifestPath, "utf8");
1439
- let changed = false;
1320
+ const original = await readFile(manifestPath, "utf8");
1321
+ const pathPrefix = resolveMobilePath(this.target, "/");
1322
+ let manifest = original;
1440
1323
  for (const scheme of schemes) {
1441
1324
  if (manifest.includes(`android:scheme="${scheme}"`))
1442
1325
  continue;
1443
- const filter = [
1444
- " <intent-filter>",
1445
- ' <action android:name="android.intent.action.VIEW" />',
1446
- ' <category android:name="android.intent.category.DEFAULT" />',
1447
- ' <category android:name="android.intent.category.BROWSABLE" />',
1448
- ` <data android:scheme="${scheme}" />`,
1449
- " </intent-filter>"
1450
- ].join(`
1451
- `);
1452
- manifest = manifest.replace(/(\s*<\/activity>)/, `
1453
- ${filter}$1`);
1454
- changed = true;
1326
+ manifest = CapacitorApp2.#withIntentFilter(manifest, "<intent-filter>", `<data android:scheme="${scheme}" />`);
1455
1327
  }
1456
- if (changed)
1457
- await writeFile(manifestPath, manifest);
1458
- }
1459
- async#setDeepLinksInAndroid(schemes, domains) {
1460
- await this.#setUrlSchemesInAndroid(schemes);
1461
- const manifestPath = path.join(this.app.cwdPath, this.androidRootPath, "app/src/main/AndroidManifest.xml");
1462
- let manifest = await readFile(manifestPath, "utf8");
1463
- let changed = false;
1464
- const pathPrefix = resolveMobilePath(this.target, "/");
1465
1328
  for (const domain of domains) {
1466
1329
  if (manifest.includes(`android:host="${domain}"`) && manifest.includes('android:scheme="https"'))
1467
1330
  continue;
1468
- const filter = [
1469
- ' <intent-filter android:autoVerify="true">',
1470
- ' <action android:name="android.intent.action.VIEW" />',
1471
- ' <category android:name="android.intent.category.DEFAULT" />',
1472
- ' <category android:name="android.intent.category.BROWSABLE" />',
1473
- ` <data android:scheme="https" android:host="${domain}" android:pathPrefix="${pathPrefix}" />`,
1474
- " </intent-filter>"
1475
- ].join(`
1476
- `);
1477
- manifest = manifest.replace(/(\s*<\/activity>)/, `
1478
- ${filter}$1`);
1479
- changed = true;
1331
+ manifest = CapacitorApp2.#withIntentFilter(manifest, '<intent-filter android:autoVerify="true">', `<data android:scheme="https" android:host="${domain}" android:pathPrefix="${pathPrefix}" />`);
1480
1332
  }
1481
- if (changed)
1333
+ if (manifest !== original)
1482
1334
  await writeFile(manifestPath, manifest);
1483
1335
  }
1336
+ static #withIntentFilter(manifest, open, data) {
1337
+ const filter = [
1338
+ ` ${open}`,
1339
+ ' <action android:name="android.intent.action.VIEW" />',
1340
+ ' <category android:name="android.intent.category.DEFAULT" />',
1341
+ ' <category android:name="android.intent.category.BROWSABLE" />',
1342
+ ` ${data}`,
1343
+ " </intent-filter>"
1344
+ ].join(`
1345
+ `);
1346
+ return manifest.replace(/(\s*<\/activity>)/, `
1347
+ ${filter}$1`);
1348
+ }
1484
1349
  #setFeaturesInAndroid(features) {
1485
1350
  for (const feature of features) {
1486
- if (this.#hasFeatureInAndroid(feature)) {
1351
+ if (this.#androidManifestNames("uses-feature").includes(feature)) {
1487
1352
  this.app.logger.info(`${feature} already exists in android`);
1488
- return this;
1353
+ return;
1489
1354
  }
1490
1355
  this.app.logger.info(`Adding ${feature} to android`);
1491
1356
  this.project.android.getAndroidManifest().injectFragment("manifest", `<uses-feature android:name="${feature}" />`);
1492
1357
  }
1493
- return this;
1494
- }
1495
- #getFeaturesInAndroid() {
1496
- const androidManifest = this.project.android.getAndroidManifest();
1497
- const element = androidManifest.getDocumentElement();
1498
- if (!element)
1499
- throw new Error("manifest not found");
1500
- const usesFeature = element.getElementsByTagName("uses-feature");
1501
- return Array.from(usesFeature).map((feature) => feature.getAttribute("android:name"));
1502
- }
1503
- #hasFeatureInAndroid(feature) {
1504
- return this.#getFeaturesInAndroid().includes(feature);
1505
1358
  }
1506
1359
  #setPermissionsInAndroid(permissions) {
1507
1360
  for (const permission of permissions) {
1508
- if (this.#hasPermissionInAndroid(permission)) {
1361
+ if (this.#androidManifestNames("uses-permission").includes(`android.permission.${permission}`)) {
1509
1362
  this.app.logger.info(`${permission} already exists in android`);
1510
1363
  continue;
1511
1364
  }
1512
1365
  this.app.logger.info(`Adding ${permission} to android`);
1513
1366
  this.project.android.getAndroidManifest().injectFragment("manifest", `<uses-permission android:name="android.permission.${permission}" />`);
1514
1367
  }
1515
- return this;
1516
1368
  }
1517
- #getPermissionsInAndroid() {
1518
- const androidManifest = this.project.android.getAndroidManifest();
1519
- const element = androidManifest.getDocumentElement();
1369
+ #androidManifestNames(tagName) {
1370
+ const element = this.project.android.getAndroidManifest().getDocumentElement();
1520
1371
  if (!element)
1521
1372
  throw new Error("manifest not found");
1522
- const usesPermission = element.getElementsByTagName("uses-permission");
1523
- return Array.from(usesPermission).map((permission) => permission.getAttribute("android:name"));
1524
- }
1525
- #hasPermissionInAndroid(permission) {
1526
- return this.#getPermissionsInAndroid().includes(`android.permission.${permission}`);
1373
+ return Array.from(element.getElementsByTagName(tagName)).map((node) => node.getAttribute("android:name"));
1527
1374
  }
1528
1375
  }
1529
1376