@akanjs/devkit 3.0.0-beta.2 → 3.0.0-beta.21

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 (289) hide show
  1. package/README.ko.md +2 -2
  2. package/README.md +3 -2
  3. package/abstractDoc.test.ts +6 -15
  4. package/abstractDoc.ts +6 -8
  5. package/agentsIndex.test.ts +4 -7
  6. package/agentsIndex.ts +6 -22
  7. package/akanApp/BackendImportGraph.test.ts +8 -22
  8. package/akanApp/BackendImportGraph.ts +1 -20
  9. package/akanApp/akanApp.host.test.ts +1 -3
  10. package/akanApp/akanApp.host.ts +82 -254
  11. package/akanApp/devHostPolicy.test.ts +10 -34
  12. package/akanApp/devHostPolicy.ts +12 -98
  13. package/akanConfig/akanConfig.test.ts +142 -106
  14. package/akanConfig/akanConfig.ts +147 -191
  15. package/akanConfig/types.ts +4 -3
  16. package/akanContext.ts +110 -160
  17. package/akanMcpContract.ts +28 -73
  18. package/appSelectionMemory.ts +1 -4
  19. package/applicationBuildReporter.ts +37 -5
  20. package/applicationBuildRunner.test.ts +5 -3
  21. package/applicationBuildRunner.ts +54 -61
  22. package/applicationTestPreload.ts +3 -12
  23. package/artifact/implicitRootLayout.test.ts +32 -30
  24. package/artifact/implicitRootLayout.ts +58 -106
  25. package/artifact/routeSeedIndex.test.ts +7 -6
  26. package/artifact/routeSeedIndex.ts +11 -44
  27. package/biome.base.json +32 -1
  28. package/biomeBase.ts +2 -5
  29. package/cloud/cloudApi.test.ts +202 -0
  30. package/cloud/cloudApi.ts +77 -39
  31. package/cloud/configLock.test.ts +64 -0
  32. package/cloud/configLock.ts +96 -0
  33. package/cloud/constants.ts +26 -5
  34. package/cloud/globalConfig.ts +70 -32
  35. package/codeAgent/agent/AkanCodeServices.ts +97 -0
  36. package/codeAgent/agent/AkanContextFiles.ts +94 -0
  37. package/codeAgent/agent/CodeAgent.ts +551 -0
  38. package/codeAgent/agent/CodeAgentAsks.ts +66 -0
  39. package/codeAgent/agent/CodeAgentEventMapper.ts +225 -0
  40. package/codeAgent/agent/CodeAgentGate.ts +93 -0
  41. package/codeAgent/agent/CodeAgentProxy.ts +82 -0
  42. package/codeAgent/agent/CodeAgentRpcHost.ts +103 -0
  43. package/codeAgent/agent/CodeAgentRpcListener.ts +109 -0
  44. package/codeAgent/agent/CodeAgentStreamPrinter.ts +86 -0
  45. package/codeAgent/agent/CodeAgentSuspended.ts +85 -0
  46. package/codeAgent/agent/CodeAgentUi.ts +47 -0
  47. package/codeAgent/agent/CodeMailbox.ts +148 -0
  48. package/codeAgent/agent/CodeSessionFork.ts +56 -0
  49. package/codeAgent/agent/CodeSessionIndex.ts +78 -0
  50. package/codeAgent/agent/SubagentPool.ts +214 -0
  51. package/codeAgent/agent/akanCodeModel.ts +47 -0
  52. package/codeAgent/agent/akanCodePaths.ts +31 -0
  53. package/codeAgent/agent/akanContextFiles.test.ts +114 -0
  54. package/codeAgent/agent/akanSystemPrompt.ts +46 -0
  55. package/codeAgent/agent/codeAgent.test.ts +178 -0
  56. package/codeAgent/agent/codeAgentContract.test.ts +523 -0
  57. package/codeAgent/agent/codeAgentProxy.test.ts +74 -0
  58. package/codeAgent/agent/codeAgentRpcListener.test.ts +113 -0
  59. package/codeAgent/agent/codeAgentSuspended.test.ts +47 -0
  60. package/codeAgent/agent/codeMailbox.test.ts +76 -0
  61. package/codeAgent/agent/codeSessionFork.test.ts +58 -0
  62. package/codeAgent/agent/codeSessionIndex.test.ts +77 -0
  63. package/codeAgent/agent/consoleToStderr.ts +8 -0
  64. package/codeAgent/agent/jsonLines.ts +29 -0
  65. package/codeAgent/agent/stringArg.ts +5 -0
  66. package/codeAgent/feedback/DevLogFeedback.ts +82 -0
  67. package/codeAgent/feedback/PreviewChrome.ts +82 -0
  68. package/codeAgent/feedback/PreviewFeedback.ts +46 -0
  69. package/codeAgent/feedback/PreviewView.ts +95 -0
  70. package/codeAgent/feedback/TurnFeedback.ts +98 -0
  71. package/codeAgent/feedback/VerifyFeedback.ts +40 -0
  72. package/codeAgent/feedback/previewChrome.test.ts +73 -0
  73. package/codeAgent/index.ts +34 -0
  74. package/codeAgent/skills/akan-code/SKILL.md +130 -0
  75. package/codeAgent/skills/akan-debug/SKILL.md +42 -0
  76. package/codeAgent/skills/akan-deps/SKILL.md +50 -0
  77. package/codeAgent/skills/akan-err/SKILL.md +39 -0
  78. package/codeAgent/skills/akan-module/SKILL.md +45 -0
  79. package/codeAgent/skills/akan-scaffold/SKILL.md +76 -0
  80. package/codeAgent/skills/akan-scalar/SKILL.md +52 -0
  81. package/codeAgent/skills/akan-service/SKILL.md +34 -0
  82. package/codeAgent/skills/akan-store/SKILL.md +67 -0
  83. package/codeAgent/skills/akan-ui/SKILL.md +63 -0
  84. package/codeAgent/skills/akan-validate/SKILL.md +44 -0
  85. package/codeAgent/tools/AkanCli.ts +50 -0
  86. package/codeAgent/tools/AkanCodePlugins.ts +136 -0
  87. package/codeAgent/tools/AkanEditScope.ts +48 -0
  88. package/codeAgent/tools/AkanEnvKeys.ts +50 -0
  89. package/codeAgent/tools/AkanToolPack.ts +92 -0
  90. package/codeAgent/tools/AkanVerifier.ts +48 -0
  91. package/codeAgent/tools/AskToolPack.ts +99 -0
  92. package/codeAgent/tools/MailToolPack.ts +76 -0
  93. package/codeAgent/tools/McpClient.ts +187 -0
  94. package/codeAgent/tools/McpOAuth.ts +233 -0
  95. package/codeAgent/tools/McpOAuthLoopback.ts +64 -0
  96. package/codeAgent/tools/McpServerConfig.ts +129 -0
  97. package/codeAgent/tools/McpSignIn.ts +158 -0
  98. package/codeAgent/tools/McpTokenStore.ts +81 -0
  99. package/codeAgent/tools/McpToolPack.ts +199 -0
  100. package/codeAgent/tools/SessionToolPack.ts +91 -0
  101. package/codeAgent/tools/WebToolPack.ts +147 -0
  102. package/codeAgent/tools/akanCodePlugins.test.ts +677 -0
  103. package/codeAgent/tools/askToolPack.test.ts +116 -0
  104. package/codeAgent/tools/mcpOAuth.test.ts +612 -0
  105. package/codeAgent/tools/mcpServerConfig.test.ts +212 -0
  106. package/codegenLock.test.ts +4 -13
  107. package/codegenLock.ts +3 -17
  108. package/commandDecorators/argMeta.ts +1 -5
  109. package/commandDecorators/camelToKebabCase.ts +1 -0
  110. package/commandDecorators/command.ts +46 -102
  111. package/commandDecorators/commandBuilder.ts +30 -61
  112. package/commandDecorators/commandDecorators.test.ts +2 -10
  113. package/commandDecorators/dependencyBuilder.ts +10 -1
  114. package/commandDecorators/helpFormatter.ts +68 -145
  115. package/commandDecorators/index.ts +0 -2
  116. package/commandDecorators/targetMeta.ts +9 -7
  117. package/createTunnel.ts +7 -14
  118. package/dependencyScanner.test.ts +4 -16
  119. package/dependencyScanner.ts +31 -80
  120. package/devkitUtils.test.ts +48 -20
  121. package/executors.linkFallback.test.ts +103 -0
  122. package/executors.test.ts +132 -106
  123. package/executors.ts +195 -496
  124. package/fileEditor.ts +9 -37
  125. package/{getDirname.test.ts → fileSys.test.ts} +5 -3
  126. package/fileSys.ts +6 -8
  127. package/formSetterScanner.ts +3 -16
  128. package/frontendBuild/allRoutesBuilder.ts +7 -21
  129. package/frontendBuild/autoImportSync.test.ts +27 -38
  130. package/frontendBuild/autoImportSync.ts +31 -65
  131. package/frontendBuild/buildRouteClient.test.ts +62 -37
  132. package/frontendBuild/bundleDefine.ts +12 -0
  133. package/frontendBuild/clientBuildTypes.ts +5 -36
  134. package/frontendBuild/clientEntriesBundler.ts +9 -40
  135. package/frontendBuild/clientEntryDiscovery.ts +6 -41
  136. package/frontendBuild/csrArtifactBuilder.ts +6 -25
  137. package/frontendBuild/cssCandidateCache.test.ts +0 -6
  138. package/frontendBuild/cssCandidateCache.ts +6 -41
  139. package/frontendBuild/cssCompiler.ts +29 -78
  140. package/frontendBuild/cssImportResolver.ts +6 -19
  141. package/frontendBuild/devChangePlanner.ts +7 -10
  142. package/frontendBuild/devGeneratedIndexSync.test.ts +12 -27
  143. package/frontendBuild/devGeneratedIndexSync.ts +1 -4
  144. package/frontendBuild/fontOptimizer.test.ts +6 -14
  145. package/frontendBuild/fontOptimizer.ts +15 -72
  146. package/frontendBuild/fontPruner.test.ts +5 -10
  147. package/frontendBuild/fontPruner.ts +5 -20
  148. package/frontendBuild/frontendBuild.test.ts +46 -69
  149. package/frontendBuild/hmrChangeClassifier.ts +2 -2
  150. package/frontendBuild/hmrWatcher.test.ts +8 -32
  151. package/frontendBuild/hmrWatcher.ts +14 -71
  152. package/frontendBuild/pagesBundleBuilder.ts +4 -29
  153. package/frontendBuild/precompressArtifacts.ts +5 -18
  154. package/frontendBuild/routeClientBuilder.ts +23 -46
  155. package/frontendBuild/routesManifestArtifactSerializer.ts +5 -36
  156. package/frontendBuild/sourceMtimeIndex.test.ts +41 -97
  157. package/frontendBuild/sourceMtimeIndex.ts +19 -130
  158. package/frontendBuild/ssrBaseArtifactBuilder.ts +2 -8
  159. package/frontendBuild/styleContract.ts +1 -8
  160. package/frontendBuild/themeValidator.ts +4 -26
  161. package/frontendBuild/watchRootResolver.test.ts +23 -42
  162. package/frontendBuild/watchRootResolver.ts +5 -27
  163. package/getRelatedCnsts.ts +12 -92
  164. package/incrementalBuilder/buildBatch.proc.ts +29 -58
  165. package/incrementalBuilder/buildBatchProtocol.ts +8 -36
  166. package/incrementalBuilder/buildBatchRunner.test.ts +34 -0
  167. package/incrementalBuilder/buildBatchRunner.ts +10 -31
  168. package/incrementalBuilder/builderChannel.test.ts +24 -49
  169. package/incrementalBuilder/builderChannel.ts +6 -37
  170. package/incrementalBuilder/builderRequestRouter.test.ts +0 -8
  171. package/incrementalBuilder/builderRequestRouter.ts +5 -24
  172. package/incrementalBuilder/devWatchBatch.test.ts +21 -24
  173. package/incrementalBuilder/incrementalBuilder.host.test.ts +18 -55
  174. package/incrementalBuilder/incrementalBuilder.host.ts +18 -76
  175. package/incrementalBuilder/incrementalBuilder.proc.test.ts +81 -0
  176. package/incrementalBuilder/incrementalBuilder.proc.ts +49 -161
  177. package/index.ts +5 -19
  178. package/integration/devResourceProbe.ts +50 -56
  179. package/integration/devStability.integration.test.ts +47 -194
  180. package/integration/devStabilityHarness.test.ts +13 -28
  181. package/integration/devStabilityHarness.ts +65 -330
  182. package/integration/ssrMemoryProbe.ts +41 -167
  183. package/libSource.test.ts +4 -15
  184. package/libSource.ts +19 -31
  185. package/lint/__fixtures__/no-document-cookie/bad.tsx +4 -0
  186. package/lint/__fixtures__/no-document-cookie/good.tsx +7 -0
  187. package/lint/__fixtures__/no-web-only-api-outside-webkit/bad.tsx +7 -0
  188. package/lint/__fixtures__/no-web-only-api-outside-webkit/good.tsx +11 -0
  189. package/lint/__fixtures__/no-web-storage/bad.tsx +6 -0
  190. package/lint/__fixtures__/no-web-storage/good.tsx +7 -0
  191. package/lint/gritRules.test.ts +8 -24
  192. package/lint/no-deep-internal-import.grit +2 -2
  193. package/lint/no-document-cookie.grit +29 -0
  194. package/lint/no-redeclare-predefined-endpoint.grit +2 -1
  195. package/lint/no-web-only-api-outside-webkit.grit +44 -0
  196. package/lint/no-web-storage.grit +30 -0
  197. package/linter.test.ts +1 -2
  198. package/linter.ts +26 -116
  199. package/mobile/index.ts +6 -0
  200. package/mobile/mobileTarget.ts +16 -13
  201. package/mobile/nativeApi.test.ts +30 -0
  202. package/mobile/nativeApi.ts +40 -0
  203. package/mobile/nativeApp.test.ts +85 -0
  204. package/mobile/nativeApp.ts +210 -0
  205. package/mobile/nativeConfig.test.ts +199 -0
  206. package/mobile/nativeConfig.ts +184 -0
  207. package/mobile/nativeWebDir.test.ts +80 -0
  208. package/mobile/nativeWebDir.ts +62 -0
  209. package/mobile/placeholderAppId.test.ts +13 -0
  210. package/mobile/placeholderAppId.ts +16 -0
  211. package/mobile/usageDescriptions.test.ts +27 -0
  212. package/mobile/usageDescriptions.ts +24 -0
  213. package/package.json +10 -10
  214. package/packageExports.test.ts +3 -18
  215. package/packageExportsMap.ts +3 -19
  216. package/piDependencyPins.test.ts +46 -0
  217. package/platformTest/BunTestReport.test.ts +60 -0
  218. package/platformTest/BunTestReport.ts +65 -0
  219. package/platformTest/IdleWatchedProcess.test.ts +56 -0
  220. package/platformTest/IdleWatchedProcess.ts +73 -0
  221. package/platformTest/LinuxDockerTarget.ts +105 -0
  222. package/platformTest/PlatformTestRun.test.ts +64 -0
  223. package/platformTest/PlatformTestRun.ts +141 -0
  224. package/platformTest/PlatformTestTarget.ts +142 -0
  225. package/platformTest/TestSnapshot.test.ts +72 -0
  226. package/platformTest/TestSnapshot.ts +103 -0
  227. package/platformTest/WindowsSshTarget.ts +151 -0
  228. package/prompter.ts +3 -13
  229. package/qualityScanner.test.ts +9 -26
  230. package/qualityScanner.ts +200 -286
  231. package/recipeScanner.test.ts +7 -12
  232. package/recipeScanner.ts +9 -38
  233. package/repoIdentity.ts +2 -9
  234. package/routeSourceValidator.test.ts +0 -1
  235. package/routeSourceValidator.ts +7 -42
  236. package/scanInfo.ts +91 -225
  237. package/selectModel.ts +1 -2
  238. package/semver.ts +3 -5
  239. package/slicePlanner.test.ts +6 -24
  240. package/slicePlanner.ts +11 -32
  241. package/spinner.test.ts +3 -8
  242. package/spinner.ts +4 -16
  243. package/sshTunnel.ts +1 -6
  244. package/ssrScanner.test.ts +1 -6
  245. package/ssrScanner.ts +103 -113
  246. package/stripAnsi.ts +3 -0
  247. package/subspace.test.ts +30 -25
  248. package/subspace.ts +81 -115
  249. package/subspaceConfig.ts +11 -9
  250. package/testHelpers.ts +194 -0
  251. package/transforms/asyncDefaultExportDetector.ts +3 -11
  252. package/transforms/barrelAnalyzer.ts +43 -135
  253. package/transforms/barrelImportsPlugin.ts +38 -175
  254. package/transforms/externalizeFrameworkPlugin.test.ts +39 -118
  255. package/transforms/externalizeFrameworkPlugin.ts +13 -87
  256. package/transforms/moduleSyntax.ts +32 -0
  257. package/transforms/rscUseClientTransform.ts +35 -20
  258. package/transforms/transforms.test.ts +153 -44
  259. package/transforms/tsconfigPackageResolver.test.ts +6 -24
  260. package/transforms/useClientBundlePlugin.ts +2 -22
  261. package/typeChecker.ts +7 -63
  262. package/types.ts +1 -0
  263. package/uploadRelease.ts +10 -25
  264. package/workflow/artifacts.ts +18 -0
  265. package/workflow/executor.test.ts +1 -12
  266. package/workflow/executor.ts +101 -110
  267. package/workflow/index.ts +0 -1
  268. package/workflow/moduleIndex.test.ts +4 -15
  269. package/workflow/moduleIndex.ts +9 -49
  270. package/workflow/plan.ts +18 -25
  271. package/workflow/render.ts +80 -96
  272. package/workflow/rolloutGate.test.ts +1 -1
  273. package/workflow/source.ts +52 -69
  274. package/workflow/sourceAst.ts +50 -0
  275. package/workspaceLayout.test.ts +13 -3
  276. package/workspaceLayout.ts +20 -23
  277. package/abstractCompactor.ts +0 -112
  278. package/aiEditor.test.ts +0 -60
  279. package/aiEditor.ts +0 -387
  280. package/applicationReleasePackager.ts +0 -209
  281. package/capacitorApp.test.ts +0 -372
  282. package/capacitorApp.ts +0 -1648
  283. package/commandDecorators/commandMeta.ts +0 -7
  284. package/commandDecorators/types.ts +0 -10
  285. package/getDirname.ts +0 -4
  286. package/guideline.ts +0 -19
  287. package/local/optimize-resource/ipcprobe/child.ts +0 -1
  288. package/local/optimize-resource/ipcprobe/parent.ts +0 -11
  289. package/workflow/primitive.ts +0 -59
@@ -1,372 +0,0 @@
1
- import { afterEach, describe, expect, test } from "bun:test";
2
- import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
- import os from "node:os";
4
- import path from "node:path";
5
- import type { AkanMobileTargetConfig } from "./akanConfig";
6
- import {
7
- ANDROID_MIN_SDK_VERSION,
8
- assertJsonSerializable,
9
- buildIosNativeRunCommand,
10
- classifyIosRunFailure,
11
- clearRootCapacitorConfigs,
12
- formatAndroidReleaseSigningError,
13
- getAdbDeviceStateIssues,
14
- getAndroidLocalServerHost,
15
- getMissingAndroidReleaseSigningKeys,
16
- isPlaceholderAppId,
17
- materializeCapacitorConfig,
18
- parseDevicectlDevices,
19
- parseIosRuntimeMajor,
20
- parseSimctlDevices,
21
- raiseGradleMinSdkVersion,
22
- rootCapacitorConfigFilenames,
23
- SWIFTUICORE_MIN_IOS_MAJOR,
24
- sanitizeIosNativeRunEnv,
25
- selectLocalDevHost,
26
- sortIosRunTargets,
27
- writeRootCapacitorConfig,
28
- } from "./capacitorApp";
29
-
30
- const tempRoots: string[] = [];
31
-
32
- const makeTempRoot = async () => {
33
- const root = await mkdtemp(path.join(os.tmpdir(), "akan-capacitor-app-"));
34
- tempRoots.push(root);
35
- return root;
36
- };
37
-
38
- const baseTarget: AkanMobileTargetConfig = {
39
- name: "default",
40
- appName: "Minimal",
41
- appId: "com.minimal.app",
42
- version: "1.2.3",
43
- buildNum: 7,
44
- basePath: "admin",
45
- indexPath: "/dashboard",
46
- assets: { icon: "mobile/icon.png" },
47
- permissions: ["camera"],
48
- deepLinks: { schemes: ["minimal"], domains: ["minimal.app"] },
49
- files: { android: { "app/google-services.json": "private/google-services.json" } },
50
- };
51
-
52
- afterEach(async () => {
53
- await Promise.all(tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
54
- });
55
-
56
- describe("materializeCapacitorConfig", () => {
57
- test("writes only Capacitor fields for release config", () => {
58
- const config = materializeCapacitorConfig(
59
- {
60
- ...baseTarget,
61
- plugins: { CapacitorHttp: { enabled: true } },
62
- android: { flavor: "qa" },
63
- ios: { scheme: "App QA" },
64
- cordova: { preferences: { ScrollEnabled: "false" } },
65
- experimental: { ios: { spm: { swiftToolsVersion: "5.9" } } },
66
- },
67
- { operation: "release" },
68
- );
69
-
70
- expect(config).toMatchObject({
71
- appId: "com.minimal.app",
72
- appName: "Minimal",
73
- webDir: ".akan/mobile/default/www",
74
- plugins: {
75
- CapacitorCookies: { enabled: true },
76
- CapacitorHttp: { enabled: true },
77
- Keyboard: { resize: "none" },
78
- },
79
- android: { flavor: "qa", path: "android" },
80
- ios: { scheme: "App QA", path: "ios" },
81
- cordova: { preferences: { ScrollEnabled: "false" } },
82
- experimental: { ios: { spm: { swiftToolsVersion: "5.9" } } },
83
- });
84
- expect(config).not.toHaveProperty("name");
85
- expect(config).not.toHaveProperty("basePath");
86
- expect(config).not.toHaveProperty("indexPath");
87
- expect(config).not.toHaveProperty("version");
88
- expect(config).not.toHaveProperty("buildNum");
89
- expect(config).not.toHaveProperty("assets");
90
- expect(config).not.toHaveProperty("permissions");
91
- expect(config).not.toHaveProperty("deepLinks");
92
- expect(config).not.toHaveProperty("files");
93
- expect(config).not.toHaveProperty("server");
94
- });
95
-
96
- test("adds local server config without requiring env target switching", () => {
97
- const config = materializeCapacitorConfig(
98
- {
99
- ...baseTarget,
100
- server: {
101
- hostname: "localhost",
102
- allowNavigation: ["api.example.com"],
103
- },
104
- },
105
- {
106
- operation: "local",
107
- localIp: "192.168.0.5",
108
- localServerUrl: "http://192.168.0.5:8282/en/admin?csr=true&akanMobileTarget=default",
109
- },
110
- );
111
-
112
- expect(config.server).toEqual({
113
- hostname: "localhost",
114
- androidScheme: "http",
115
- url: "http://192.168.0.5:8282/en/admin?csr=true&akanMobileTarget=default",
116
- cleartext: true,
117
- allowNavigation: ["api.example.com", "192.168.0.5", "localhost"],
118
- });
119
- });
120
-
121
- test("allows mobile targets to override the default keyboard resize mode", () => {
122
- const config = materializeCapacitorConfig(
123
- {
124
- ...baseTarget,
125
- plugins: { Keyboard: { resize: "native" } },
126
- },
127
- { operation: "release" },
128
- );
129
-
130
- expect(config.plugins).toMatchObject({
131
- Keyboard: { resize: "native" },
132
- });
133
- });
134
-
135
- test("rejects non-json config values", () => {
136
- expect(() => assertJsonSerializable({ plugins: { Custom: () => null } })).toThrow("must be JSON serializable");
137
- });
138
- });
139
-
140
- describe("root capacitor config helpers", () => {
141
- test("clears root configs before writing the temporary json config", async () => {
142
- const root = await makeTempRoot();
143
- await Promise.all(rootCapacitorConfigFilenames.map((file) => writeFile(path.join(root, file), `old ${file}\n`)));
144
-
145
- await writeRootCapacitorConfig(root, '{\n "appId": "com.minimal.app"\n}\n');
146
-
147
- expect(await Bun.file(path.join(root, "capacitor.config.ts")).exists()).toBe(false);
148
- expect(await Bun.file(path.join(root, "capacitor.config.js")).exists()).toBe(false);
149
- expect(await Bun.file(path.join(root, "capacitor.config.json")).text()).toBe(
150
- '{\n "appId": "com.minimal.app"\n}\n',
151
- );
152
-
153
- await clearRootCapacitorConfigs(root);
154
-
155
- expect(await Bun.file(path.join(root, "capacitor.config.json")).exists()).toBe(false);
156
- });
157
- });
158
-
159
- describe("iOS native run helpers", () => {
160
- test("parses xcrun device and simulator outputs", () => {
161
- expect(
162
- parseDevicectlDevices(
163
- JSON.stringify({
164
- result: {
165
- devices: [
166
- {
167
- identifier: "1BCB6563-02FF-5D49-9655-1BFF02A638D3",
168
- connectionProperties: { pairingState: "paired", transportType: "wired", tunnelState: "available" },
169
- deviceProperties: { name: "Seok iPhone" },
170
- hardwareProperties: { udid: "00008130-000200113EC1001C" },
171
- },
172
- ],
173
- },
174
- }),
175
- ),
176
- ).toEqual([
177
- {
178
- id: "00008130-000200113EC1001C",
179
- name: "Seok iPhone",
180
- kind: "device",
181
- state: "available wired paired",
182
- devicectlId: "1BCB6563-02FF-5D49-9655-1BFF02A638D3",
183
- xcodebuildId: "00008130-000200113EC1001C",
184
- },
185
- ]);
186
-
187
- expect(
188
- parseSimctlDevices(
189
- JSON.stringify({
190
- devices: {
191
- "com.apple.CoreSimulator.SimRuntime.iOS-18-2": [
192
- { udid: "11111111-2222-3333-4444-555555555555", name: "iPhone 16", state: "Shutdown", isAvailable: true },
193
- ],
194
- },
195
- }),
196
- ),
197
- ).toEqual([
198
- {
199
- id: "11111111-2222-3333-4444-555555555555",
200
- name: "iPhone 16",
201
- kind: "simulator",
202
- state: "Shutdown",
203
- runtime: "iOS 18.2",
204
- },
205
- ]);
206
- });
207
-
208
- test("sorts run targets so booted / connected / newest-runtime targets come first", () => {
209
- const ios17 = { id: "a", name: "iPhone 15", kind: "simulator" as const, state: "Shutdown", runtime: "iOS 17.5" };
210
- const ios18 = { id: "b", name: "iPhone 16", kind: "simulator" as const, state: "Shutdown", runtime: "iOS 18.2" };
211
- const booted17 = { id: "c", name: "iPhone SE", kind: "simulator" as const, state: "Booted", runtime: "iOS 17.0" };
212
- const device = { id: "d", name: "Seok iPhone", kind: "device" as const, state: "available wired paired" };
213
- // Input is in the old ascending-runtime order that used to default to iOS 17.
214
- const sorted = sortIosRunTargets([ios17, ios18, booted17, device]);
215
- expect(sorted.map((t) => t.id)).toEqual(["d", "c", "b", "a"]);
216
- // Newest available simulator beats the older one, so the interactive default is no longer iOS 17.
217
- expect(sortIosRunTargets([ios17, ios18]).map((t) => t.id)).toEqual(["b", "a"]);
218
- });
219
-
220
- test("parses the major iOS runtime version", () => {
221
- expect(parseIosRuntimeMajor("iOS 18.2")).toBe(18);
222
- expect(parseIosRuntimeMajor("iOS 17.5")).toBe(17);
223
- expect(parseIosRuntimeMajor(undefined)).toBeUndefined();
224
- expect(SWIFTUICORE_MIN_IOS_MAJOR).toBe(18);
225
- });
226
-
227
- test("builds xcodebuild destinations and output paths by target kind", () => {
228
- const deviceCommand = buildIosNativeRunCommand({
229
- appRoot: "/repo/apps/minimal",
230
- device: { id: "device-1", name: "iPhone", kind: "device" },
231
- scheme: "App QA",
232
- configuration: "Debug",
233
- });
234
- expect(deviceCommand.xcodebuildArgs).toContain("id=device-1");
235
- expect(deviceCommand.xcodebuildArgs).toContain("App QA");
236
- expect(deviceCommand.appPath).toBe(
237
- "/repo/apps/minimal/ios/DerivedData/device-1/Build/Products/Debug-iphoneos/App.app",
238
- );
239
-
240
- const simulatorCommand = buildIosNativeRunCommand({
241
- appRoot: "/repo/apps/minimal",
242
- device: { id: "sim-1", name: "Simulator", kind: "simulator" },
243
- });
244
- expect(simulatorCommand.xcodebuildArgs).toContain("platform=iOS Simulator,id=sim-1");
245
- expect(simulatorCommand.appPath).toBe(
246
- "/repo/apps/minimal/ios/DerivedData/sim-1/Build/Products/Debug-iphonesimulator/App.app",
247
- );
248
- });
249
-
250
- test("classifies iOS signing and device-state failures", () => {
251
- expect(classifyIosRunFailure("There are no accounts registered with Xcode").kind).toBe("apple-account");
252
- expect(
253
- classifyIosRunFailure(
254
- 'Failed Registering Bundle Identifier: The app identifier "com.minimal.app" cannot be registered to your development team',
255
- ).kind,
256
- ).toBe("bundle-identifier");
257
- expect(classifyIosRunFailure("No profiles for 'com.minimal.app' were found").kind).toBe("provisioning-profile");
258
- expect(classifyIosRunFailure("Developer Mode is disabled on this device").kind).toBe("device-state");
259
- expect(classifyIosRunFailure("arm64-apple-darwin20.0: error: unknown argument: '-index-store-path'").kind).toBe(
260
- "compiler-toolchain",
261
- );
262
- expect(
263
- classifyIosRunFailure(
264
- "dyld[1234]: Library not loaded: /System/Library/Frameworks/SwiftUICore.framework/SwiftUICore",
265
- ).kind,
266
- ).toBe("simulator-runtime");
267
- });
268
-
269
- test("removes shell compiler variables from iOS native run env", () => {
270
- expect(
271
- sanitizeIosNativeRunEnv({
272
- AKAN_PUBLIC_APP_NAME: "minimal",
273
- CC: "arm64-apple-darwin20.0.0-clang",
274
- CXX: "arm64-apple-darwin20.0.0-clang++",
275
- SDKROOT: "/wrong/sdk",
276
- }),
277
- ).toEqual({ AKAN_PUBLIC_APP_NAME: "minimal" });
278
- });
279
-
280
- test("flags placeholder bundle identifiers that Apple's portal already claims", () => {
281
- for (const appId of ["com.myapp.app", "com.myorg.myapp", "com.example.foo", "com.changeme.app", ""]) {
282
- expect(isPlaceholderAppId(appId)).toBe(true);
283
- }
284
- for (const appId of ["com.minimal.app", "com.nearthlab.leadingflight", "io.akanjs.demo"]) {
285
- expect(isPlaceholderAppId(appId)).toBe(false);
286
- }
287
- });
288
- });
289
-
290
- describe("selectLocalDevHost", () => {
291
- const build = (map: Record<string, { family: string; address: string; internal?: boolean }[]>) =>
292
- map as unknown as Parameters<typeof selectLocalDevHost>[0];
293
-
294
- test("prefers a routable LAN NIC over an inactive bridge enumerated first", () => {
295
- const resolution = selectLocalDevHost(
296
- build({
297
- bridge0: [{ family: "IPv4", address: "192.168.2.1" }],
298
- en0: [{ family: "IPv4", address: "172.25.140.140" }],
299
- bridge100: [{ family: "IPv4", address: "192.168.3.1" }],
300
- en8: [{ family: "IPv4", address: "172.25.40.227" }],
301
- }),
302
- );
303
- expect(resolution.host).toBe("172.25.140.140");
304
- expect(resolution.source).toBe("detected");
305
- });
306
-
307
- test("an explicit override always wins and is trimmed", () => {
308
- const resolution = selectLocalDevHost(build({ en0: [{ family: "IPv4", address: "172.25.140.140" }] }), {
309
- override: " 10.0.0.9 ",
310
- });
311
- expect(resolution).toMatchObject({ host: "10.0.0.9", source: "override" });
312
- });
313
-
314
- test("never selects a link-local address when a real LAN address exists", () => {
315
- const resolution = selectLocalDevHost(
316
- build({
317
- en0: [{ family: "IPv4", address: "169.254.10.10" }],
318
- en1: [{ family: "IPv4", address: "192.168.1.5" }],
319
- }),
320
- );
321
- expect(resolution.host).toBe("192.168.1.5");
322
- });
323
-
324
- test("falls back to loopback when nothing routable is present", () => {
325
- const resolution = selectLocalDevHost(build({ lo0: [{ family: "IPv4", address: "127.0.0.1", internal: true }] }));
326
- expect(resolution).toMatchObject({ host: "127.0.0.1", source: "loopback" });
327
- });
328
- });
329
-
330
- describe("Android signing diagnostics", () => {
331
- test("reports missing release signing keys and adb authorization issues", () => {
332
- expect(
333
- getMissingAndroidReleaseSigningKeys({
334
- env: { MYAPP_RELEASE_STORE_FILE: "release.jks" } as NodeJS.ProcessEnv,
335
- gradleProperties: "MYAPP_RELEASE_STORE_PASSWORD=secret\n",
336
- }),
337
- ).toEqual(["MYAPP_RELEASE_KEY_ALIAS", "MYAPP_RELEASE_KEY_PASSWORD"]);
338
- expect(formatAndroidReleaseSigningError(["MYAPP_RELEASE_KEY_ALIAS"])).toContain("MYAPP_RELEASE_KEY_ALIAS");
339
- expect(getAdbDeviceStateIssues("List of devices attached\nabc123 unauthorized\nxyz offline\n")).toEqual([
340
- "Android device abc123 is unauthorized. Confirm USB debugging authorization on the device.",
341
- "Android device xyz is offline. Reconnect the device or restart adb.",
342
- ]);
343
- expect(getAndroidLocalServerHost("List of devices attached\nemulator-5554 device\n", "192.168.0.5")).toBe(
344
- "10.0.2.2",
345
- );
346
- expect(getAndroidLocalServerHost("List of devices attached\nabc123 device\n", "192.168.0.5")).toBe("192.168.0.5");
347
- expect(
348
- getAndroidLocalServerHost("List of devices attached\nemulator-5554 device\nabc123 device\n", "192.168.0.5"),
349
- ).toBe("192.168.0.5");
350
- });
351
- });
352
-
353
- describe("raiseGradleMinSdkVersion", () => {
354
- test("raises the scaffold minSdkVersion to the bundled-plugin floor, preserving formatting", () => {
355
- const scaffold = "ext {\n minSdkVersion = 24\n compileSdkVersion = 35\n}\n";
356
- expect(raiseGradleMinSdkVersion(scaffold)).toBe(
357
- `ext {\n minSdkVersion = ${ANDROID_MIN_SDK_VERSION}\n compileSdkVersion = 35\n}\n`,
358
- );
359
- });
360
-
361
- test("returns null when nothing needs changing", () => {
362
- // Already at the floor, already above it, and no assignment present.
363
- expect(raiseGradleMinSdkVersion(`ext {\n minSdkVersion = ${ANDROID_MIN_SDK_VERSION}\n}\n`)).toBeNull();
364
- expect(raiseGradleMinSdkVersion("ext {\n minSdkVersion = 34\n}\n")).toBeNull();
365
- expect(raiseGradleMinSdkVersion("ext {\n compileSdkVersion = 35\n}\n")).toBeNull();
366
- });
367
-
368
- test("honors an explicit floor and leaves higher user values untouched", () => {
369
- expect(raiseGradleMinSdkVersion("minSdkVersion = 21", 23)).toBe("minSdkVersion = 23");
370
- expect(raiseGradleMinSdkVersion("minSdkVersion = 28", 26)).toBeNull();
371
- });
372
- });