@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.
- package/.build-stamp +1 -1
- package/{CodeAgent-6cm97kay.js → CodeAgent-awv258wb.js} +2 -2
- package/{CodeTui-za4jsm41.js → CodeTui-1nqh35ez.js} +20 -22
- package/TunnelShare-scf4e4pd.js +9 -0
- package/{agent.command-e0wpbbyg.js → agent.command-1s9ag7sb.js} +8 -9
- package/akanCode.js +4 -4
- package/{application.command-8wyxqc8q.js → application.command-49hwy6va.js} +25 -56
- package/{applicationBuildRunner-n9gzaxd0.js → applicationBuildRunner-ybyp97pv.js} +33 -59
- package/{applicationReleasePackager-vpggfqgq.js → applicationReleasePackager-esnrphw8.js} +40 -60
- package/buildBatch.proc.js +19 -24
- package/{capacitorApp-q3z0qht0.js → capacitorApp-1synz4en.js} +3 -4
- package/{cloud.command-4zwa5dsx.js → cloud.command-d7rqtzt9.js} +16 -26
- package/cloud.script-bkbpcr96.js +19 -0
- package/{code.command-468c9d7s.js → code.command-nn48xzej.js} +22 -37
- package/context.command-s3mcmvpa.js +48 -0
- package/context.runner-k99nb5pk.js +21 -0
- package/{dependencyScanner-0z2h2tks.js → dependencyScanner-ye2e6pdz.js} +2 -2
- package/{devTui-ffjsarqa.js → devTui-q7k7bakd.js} +5 -9
- package/fileSys-5ngz93ga.js +9 -0
- package/{guideline.command-vhw13pqr.js → guideline.command-sct4qnt5.js} +4 -5
- package/guidelines/conventions/conventions.instruction.md +5 -1
- package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
- package/incrementalBuilder.proc.js +30 -48
- package/{index-s5rhm04y.js → index-0bq14vr1.js} +1 -1
- package/{index-10dkrrww.js → index-13ffe9wp.js} +4 -4
- package/{index-srmay5jw.js → index-22d57v4c.js} +84 -67
- package/{index-53176s7j.js → index-31yr441d.js} +10 -17
- package/index-3hx1z96c.js +87 -0
- package/{index-4m929vvn.js → index-3sq321ak.js} +10 -18
- package/{index-bhtmj233.js → index-3t7g9e4r.js} +41 -78
- package/{index-q0y2jq9j.js → index-5b6tavv3.js} +6 -3
- package/{index-47pj3aee.js → index-5e0n4hqx.js} +11 -12
- package/{index-7ep8qtvp.js → index-5pc1qrbv.js} +5 -8
- package/{index-esk82rvk.js → index-8mna0947.js} +34 -71
- package/{index-sq2dzkzm.js → index-8sf7wmdr.js} +6 -6
- package/{index-crmeqnmf.js → index-9d9bgcx4.js} +283 -722
- package/{index-bwf965h6.js → index-ahemdr5n.js} +6 -6
- package/{index-ab0c38ea.js → index-as7xmyz8.js} +20 -20
- package/{index-bc88j1ry.js → index-axzjaqve.js} +94 -142
- package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
- package/{index-667w0yah.js → index-c6eggbee.js} +2 -5
- package/{index-a1w6934z.js → index-ddxvdd1p.js} +169 -305
- package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
- package/{index-22xtgmhn.js → index-dzf3r49a.js} +1 -1
- package/{index-89hy31kf.js → index-fgq75haa.js} +172 -287
- package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
- package/{index-hwkygn9s.js → index-khpfpcsd.js} +302 -33
- package/{index-vqx8bdxz.js → index-mxav6j3c.js} +78 -231
- package/{index-2446k7b4.js → index-myhc3c1j.js} +512 -588
- package/{index-3jrp517k.js → index-nv5976x3.js} +45 -128
- package/{index-zqgj2rt2.js → index-przybvy5.js} +69 -147
- package/{index-n3cv0tm4.js → index-smme4r47.js} +1 -1
- package/{index-qdgzsnhg.js → index-w2zdcw3k.js} +110 -231
- package/{index-14zrtgfa.js → index-wa5jbxj1.js} +6 -39
- package/{index-bftkz6cp.js → index-ww4z397j.js} +198 -555
- package/{index-kwaq3n9n.js → index-xqjwd384.js} +4 -7
- package/{index-txr7dj2g.js → index-xqpzbab5.js} +106 -240
- package/{index-e4v6vhxq.js → index-xsjh6nzh.js} +178 -165
- package/{index-18zybgkc.js → index-ygn77a5w.js} +47 -99
- package/{index-9d6nvkz2.js → index-ztp3e73t.js} +79 -35
- package/index.js +23 -24
- package/{library.command-cqr175dy.js → library.command-1gx04jgn.js} +4 -5
- package/{localRegistry.command-49z55qqz.js → localRegistry.command-zndxj1q6.js} +21 -42
- package/{module.command-9p8mm3b0.js → module.command-3waddk95.js} +6 -7
- package/{package.command-wxyz909t.js → package.command-zrc7br1y.js} +5 -6
- package/package.json +2 -2
- package/{page.command-gsrsfqqs.js → page.command-vpjgardh.js} +4 -5
- package/{primitive.command-ns1mptje.js → primitive.command-sz84tk4t.js} +9 -20
- package/{prompter-1f8d9pcc.js → prompter-ptaa3nk0.js} +2 -2
- package/{quality.command-e76k2q9k.js → quality.command-g869hafs.js} +129 -363
- package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
- package/{repair.command-pkrsm3cw.js → repair.command-chsnjvvv.js} +11 -35
- package/{scalar.command-0cpt3fc8.js → scalar.command-2v21newx.js} +5 -6
- package/skills/akan-code/SKILL.md +12 -4
- package/{subspace.command-fktpwp0g.js → subspace.command-ckcbwfp1.js} +39 -58
- package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +3 -3
- package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +3 -3
- package/templates/client.ts +7 -30
- package/templates/lib/__lib/lib.dictionary.ts +0 -2
- package/templates/lib/__lib/lib.document.ts +0 -2
- package/templates/lib/sig.ts +8 -30
- package/templates/server.ts +0 -2
- package/{tunnel.command-d5jy9gk8.js → tunnel.command-kd2yr4fx.js} +5 -6
- package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
- package/typecheck.proc.js +1 -1
- package/workflow.command-44252cqv.js +79 -0
- package/{workspace.command-gv84eh1p.js → workspace.command-fqcztt5p.js} +72 -107
- package/TunnelShare-2j6s511d.js +0 -9
- package/cloud.script-fwx3vb34.js +0 -20
- package/context.command-dsnw0jby.js +0 -80
- package/context.runner-rs4rj15d.js +0 -22
- package/devTuiView-1q1mdgrv.js +0 -9
- package/getDirname-dr3jz1xg.js +0 -7
- package/index-6wwzs1bc.js +0 -7
- package/workflow.command-6tkcysmx.js +0 -105
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
CommandExecutionError
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-9d9bgcx4.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveMobilePath,
|
|
7
7
|
targetHtmlFilename
|
|
8
|
-
} from "./index-
|
|
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
|
-
|
|
39
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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(
|
|
236
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
839
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1354
|
-
CFBundleURLName: this.target.appId,
|
|
1355
|
-
|
|
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#
|
|
1318
|
+
async#setDeepLinksInAndroid(schemes, domains) {
|
|
1437
1319
|
const manifestPath = path.join(this.app.cwdPath, this.androidRootPath, "app/src/main/AndroidManifest.xml");
|
|
1438
|
-
|
|
1439
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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.#
|
|
1351
|
+
if (this.#androidManifestNames("uses-feature").includes(feature)) {
|
|
1487
1352
|
this.app.logger.info(`${feature} already exists in android`);
|
|
1488
|
-
return
|
|
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.#
|
|
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
|
-
#
|
|
1518
|
-
const
|
|
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
|
-
|
|
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
|
|