@akanjs/cli 3.0.0-beta.20 → 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 (64) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-awv258wb.js → CodeAgent-q2m47rqp.js} +2 -2
  3. package/{CodeTui-1nqh35ez.js → CodeTui-pdqhc3sn.js} +1 -1
  4. package/{agent.command-1s9ag7sb.js → agent.command-ttn09rx3.js} +5 -5
  5. package/akanCode.js +2 -2
  6. package/{application.command-49hwy6va.js → application.command-7gweenv7.js} +43 -41
  7. package/{applicationBuildRunner-ybyp97pv.js → applicationBuildRunner-38exmejd.js} +2 -2
  8. package/buildBatch.proc.js +10 -4
  9. package/{cloud.command-d7rqtzt9.js → cloud.command-bhztw7c2.js} +9 -8
  10. package/cloud.script-aabyhgba.js +20 -0
  11. package/{code.command-nn48xzej.js → code.command-6s8c0k91.js} +6 -6
  12. package/commandManifest.json +1 -1
  13. package/{context.command-s3mcmvpa.js → context.command-phmgywt2.js} +13 -13
  14. package/context.runner-yvyw5g2d.js +21 -0
  15. package/{guideline.command-sct4qnt5.js → guideline.command-7jk47fgq.js} +2 -2
  16. package/guidelines/agentRule/agentRule.instruction.md +3 -3
  17. package/guidelines/conventions/conventions.instruction.md +17 -5
  18. package/guidelines/runtimeRule/runtimeRule.instruction.md +3 -3
  19. package/incrementalBuilder.proc.js +1 -1
  20. package/{index-5pc1qrbv.js → index-1db2cw0y.js} +2 -2
  21. package/{index-ahemdr5n.js → index-4dn1p115.js} +3 -3
  22. package/{index-13ffe9wp.js → index-7cqjvraf.js} +4 -4
  23. package/{index-8sf7wmdr.js → index-8kb5p54p.js} +5 -5
  24. package/{index-ygn77a5w.js → index-9629w7ns.js} +5 -3
  25. package/{index-ddxvdd1p.js → index-aadpbnt2.js} +5 -5
  26. package/{index-ztp3e73t.js → index-d0arnrm8.js} +1 -1
  27. package/{index-nv5976x3.js → index-dg97qp24.js} +24 -13
  28. package/{index-9d9bgcx4.js → index-ga6hygxr.js} +514 -480
  29. package/index-hr5n7t4x.js +465 -0
  30. package/{index-xqpzbab5.js → index-m0ms3n1c.js} +7 -7
  31. package/{index-as7xmyz8.js → index-mgfx3mfs.js} +5 -4
  32. package/{index-3sq321ak.js → index-pp54p5zk.js} +2 -2
  33. package/{index-xqjwd384.js → index-q44jbw48.js} +1 -1
  34. package/{index-w2zdcw3k.js → index-rmcw8yc8.js} +1 -1
  35. package/{index-dzf3r49a.js → index-rnt66vym.js} +1 -1
  36. package/{index-8mna0947.js → index-tgjy8xf3.js} +4 -4
  37. package/{index-xsjh6nzh.js → index-v5eayqqw.js} +3 -3
  38. package/{index-przybvy5.js → index-wp43xrjv.js} +4 -4
  39. package/{index-31yr441d.js → index-ya5qbmyg.js} +3 -3
  40. package/{index-axzjaqve.js → index-yjkte9aj.js} +5 -4
  41. package/{index-myhc3c1j.js → index-yy4s1j72.js} +1 -1
  42. package/{index-ww4z397j.js → index-z50k041j.js} +82 -168
  43. package/index.js +21 -21
  44. package/{library.command-1gx04jgn.js → library.command-ccb1cp92.js} +3 -3
  45. package/{localRegistry.command-zndxj1q6.js → localRegistry.command-ajb9n87j.js} +8 -7
  46. package/{module.command-3waddk95.js → module.command-5k6h407d.js} +5 -5
  47. package/{package.command-zrc7br1y.js → package.command-e6ntvpez.js} +3 -3
  48. package/package.json +2 -3
  49. package/{page.command-vpjgardh.js → page.command-v4f90wb8.js} +3 -3
  50. package/{primitive.command-sz84tk4t.js → primitive.command-g6km57q5.js} +6 -6
  51. package/{quality.command-g869hafs.js → quality.command-de3p36pz.js} +5 -4
  52. package/{repair.command-chsnjvvv.js → repair.command-d3x1javq.js} +5 -5
  53. package/{scalar.command-2v21newx.js → scalar.command-7ezrac2b.js} +4 -4
  54. package/{subspace.command-ckcbwfp1.js → subspace.command-ps71ynp6.js} +4 -4
  55. package/templates/workspaceRoot/.gitignore.template +0 -1
  56. package/{tunnel.command-kd2yr4fx.js → tunnel.command-hsrv2mny.js} +2 -2
  57. package/{workflow.command-44252cqv.js → workflow.command-z2p32nmf.js} +10 -10
  58. package/{workspace.command-fqcztt5p.js → workspace.command-tmdqkrh0.js} +20 -20
  59. package/applicationReleasePackager-esnrphw8.js +0 -224
  60. package/capacitorApp-1synz4en.js +0 -11
  61. package/cloud.script-bkbpcr96.js +0 -19
  62. package/context.runner-k99nb5pk.js +0 -21
  63. package/index-5e0n4hqx.js +0 -75
  64. package/index-mxav6j3c.js +0 -1377
@@ -0,0 +1,465 @@
1
+ // @bun
2
+ // pkgs/@akanjs/devkit/mobile/mobileTarget.ts
3
+ var trimSlashes = (value) => value.replace(/^\/+|\/+$/g, "");
4
+ var getMobileTargets = async (app) => {
5
+ const config = await app.getConfig();
6
+ return Object.entries(config.mobile.targets).map(([name, target]) => ({ name, config: target }));
7
+ };
8
+ var getMobileTargetChoices = async (app) => {
9
+ const config = await app.getConfig();
10
+ const targetNames = Object.keys(config.mobile.targets);
11
+ if (targetNames.length > 0)
12
+ return targetNames;
13
+ return [...config.basePaths];
14
+ };
15
+ var resolveMobileTargetByBasePath = (targets, basePath) => {
16
+ const normalizedBasePath = trimSlashes(basePath);
17
+ const byBasePath = targets.find(({ config }) => config.basePath !== undefined && trimSlashes(config.basePath) === normalizedBasePath);
18
+ if (byBasePath)
19
+ return byBasePath;
20
+ const [template] = targets;
21
+ if (!template)
22
+ return;
23
+ return {
24
+ name: normalizedBasePath,
25
+ config: { ...template.config, name: normalizedBasePath, basePath: normalizedBasePath }
26
+ };
27
+ };
28
+ var resolveMobileTargets = async (app, selection) => {
29
+ const config = await app.getConfig();
30
+ const targets = await getMobileTargets(app);
31
+ if (targets.length === 0)
32
+ throw new Error(`No mobile targets configured for ${app.name}`);
33
+ if (!selection && targets.length === 1)
34
+ return targets;
35
+ if (!selection) {
36
+ const choices = await getMobileTargetChoices(app);
37
+ if (choices.length === 1)
38
+ return resolveMobileTargets(app, choices[0]);
39
+ throw new Error(`Multiple mobile targets found for ${app.name}. Pass --target <${choices.join("|")}|all>.`);
40
+ }
41
+ if (selection === "all") {
42
+ if (Object.keys(config.mobile.targets).length > 1)
43
+ return targets;
44
+ const basePaths = [...config.basePaths];
45
+ if (basePaths.length > 1) {
46
+ return basePaths.flatMap((basePath) => {
47
+ const resolved = resolveMobileTargetByBasePath(targets, basePath);
48
+ return resolved ? [resolved] : [];
49
+ });
50
+ }
51
+ return targets;
52
+ }
53
+ const target = targets.find((candidate) => candidate.name === selection);
54
+ if (target)
55
+ return [target];
56
+ const basePathTarget = resolveMobileTargetByBasePath(targets, selection);
57
+ if (basePathTarget && config.basePaths.has(trimSlashes(selection)))
58
+ return [basePathTarget];
59
+ const choices = await getMobileTargetChoices(app);
60
+ throw new Error(`Mobile target '${selection}' was not found. Available: ${choices.join(", ")}`);
61
+ };
62
+ var targetHtmlFilename = (target) => {
63
+ const basePath = trimSlashes(target.basePath ?? "");
64
+ return basePath ? `${basePath}.html` : "index.html";
65
+ };
66
+
67
+ // pkgs/@akanjs/devkit/mobile/nativeApp.ts
68
+ import { mkdir as mkdir2 } from "fs/promises";
69
+ import path4 from "path";
70
+
71
+ // pkgs/@akanjs/devkit/mobile/nativeApi.ts
72
+ import path from "path";
73
+
74
+ class NativeApi {
75
+ static supportedMajor = 0;
76
+ static entryOf(appDir) {
77
+ const workspaceEntry = NativeApi.#resolve("@akanjs/native/api", appDir);
78
+ if (workspaceEntry)
79
+ return workspaceEntry;
80
+ const akanjsPackage = NativeApi.#resolve("akanjs/package.json", appDir);
81
+ if (!akanjsPackage)
82
+ throw new Error(`akanjs is not installed for ${appDir}; the native build ships inside it.`);
83
+ return path.join(path.dirname(akanjsPackage), "vendor", "@akanjs", "native", "packages", "cli", "src", "api.ts");
84
+ }
85
+ static async load(appDir) {
86
+ const entry = NativeApi.entryOf(appDir);
87
+ if (!await Bun.file(entry).exists())
88
+ throw new Error(`The installed akanjs has no native build at ${entry}; update akanjs.`);
89
+ const api = await import(entry);
90
+ const major = Number(api.API_VERSION.split(".")[0]);
91
+ if (major !== NativeApi.supportedMajor)
92
+ throw new Error(`The native build API is ${api.API_VERSION}, and this akan CLI speaks ${NativeApi.supportedMajor}.x; install matching versions of akanjs and @akanjs/cli.`);
93
+ return api;
94
+ }
95
+ static #resolve(specifier, from) {
96
+ try {
97
+ return Bun.resolveSync(specifier, from);
98
+ } catch {
99
+ return null;
100
+ }
101
+ }
102
+ }
103
+
104
+ // pkgs/@akanjs/devkit/mobile/nativeConfig.ts
105
+ import path2 from "path";
106
+
107
+ // pkgs/@akanjs/devkit/mobile/usageDescriptions.ts
108
+ import { capitalize } from "akanjs/common";
109
+ var iosUsageDescriptionKeys = {
110
+ cameraUsageDescription: ["NSCameraUsageDescription"],
111
+ photoAddUsageDescription: ["NSPhotoLibraryAddUsageDescription"],
112
+ photoUsageDescription: ["NSPhotoLibraryUsageDescription"],
113
+ contactsUsageDescription: ["NSContactsUsageDescription"],
114
+ locationAlwaysUsageDescription: ["NSLocationAlwaysAndWhenInUseUsageDescription", "NSLocationAlwaysUsageDescription"],
115
+ locationWhenInUseUsageDescription: ["NSLocationWhenInUseUsageDescription"],
116
+ microphoneUsageDescription: ["NSMicrophoneUsageDescription"],
117
+ speechRecognitionUsageDescription: ["NSSpeechRecognitionUsageDescription"]
118
+ };
119
+ var toIosInfoPlistUsageDescriptions = (descriptions) => Object.fromEntries(Object.entries(descriptions).flatMap(([key, value]) => {
120
+ const plistKeys = Object.hasOwn(iosUsageDescriptionKeys, key) ? iosUsageDescriptionKeys[key] : [`NS${capitalize(key)}`];
121
+ return plistKeys.map((plistKey) => [plistKey, value]);
122
+ }));
123
+
124
+ // pkgs/@akanjs/devkit/mobile/nativeConfig.ts
125
+ class NativeConfig {
126
+ static basePlugins = [
127
+ "app",
128
+ "app-state",
129
+ "browser",
130
+ "opener",
131
+ "auth-session",
132
+ "device",
133
+ "dialog",
134
+ "keyboard",
135
+ "preferences",
136
+ "secure-storage",
137
+ "haptics"
138
+ ];
139
+ static builtinContributions = {
140
+ camera: {
141
+ permission: "camera",
142
+ plugins: ["camera"],
143
+ usageDescriptions: {
144
+ cameraUsageDescription: "$(PRODUCT_NAME) requires access to the camera to take photos.",
145
+ photoAddUsageDescription: "$(PRODUCT_NAME) requires access to the photo library to take photos.",
146
+ photoUsageDescription: "$(PRODUCT_NAME) requires access to the photo library to take photos."
147
+ }
148
+ },
149
+ contacts: { permission: "contacts" },
150
+ location: {
151
+ permission: "location",
152
+ plugins: ["geolocation"],
153
+ usageDescriptions: {
154
+ locationAlwaysUsageDescription: "$(PRODUCT_NAME) requires access to the location to get the user's location.",
155
+ locationWhenInUseUsageDescription: "$(PRODUCT_NAME) requires access to the location to get the user's location."
156
+ }
157
+ },
158
+ push: { permission: "push", plugins: ["push"] },
159
+ speech: { permission: "speech" }
160
+ };
161
+ static build({ appPath, target, webDir, contributions, locales }) {
162
+ const warnings = [];
163
+ const applied = (target.permissions ?? []).flatMap((permission) => {
164
+ const claimed = contributions.filter((contribution) => contribution.permission === permission);
165
+ const used = claimed.length ? claimed : [NativeConfig.builtinContributions[permission]];
166
+ if (!used.some((contribution) => contribution.plugins?.length))
167
+ warnings.push(`Permission '${permission}' has no native plugin yet; the app ships without it.`);
168
+ return used;
169
+ });
170
+ const abs = (relative) => path2.resolve(appPath, relative);
171
+ const plugins = [
172
+ ...new Set([
173
+ ...NativeConfig.basePlugins,
174
+ ...applied.flatMap((contribution) => contribution.plugins ?? []),
175
+ ...target.native?.plugins ?? []
176
+ ])
177
+ ];
178
+ const usageDescriptions = Object.fromEntries(Object.entries(toIosInfoPlistUsageDescriptions(Object.assign({}, ...applied.map((contribution) => contribution.usageDescriptions ?? {})))).map(([key, text]) => [key, text.replaceAll("$(PRODUCT_NAME)", target.appName)]));
179
+ const ios = NativeConfig.#compact({
180
+ infoPlist: NativeConfig.#merged(applied.map((c) => c.infoPlist), target.native?.ios?.infoPlist),
181
+ entitlements: NativeConfig.#merged(applied.map((c) => c.entitlements), target.native?.ios?.entitlements)
182
+ });
183
+ const manifest = [
184
+ ...[...new Set(applied.flatMap((c) => c.androidPermissions ?? []))].map((name) => `<uses-permission android:name="android.permission.${name}" />`),
185
+ ...[...new Set(applied.flatMap((c) => c.androidFeatures ?? []))].map((name) => `<uses-feature android:name="${name}" android:required="false" />`),
186
+ ...target.native?.android?.manifest ?? []
187
+ ];
188
+ const android = NativeConfig.#compact({
189
+ manifest,
190
+ application: target.native?.android?.application ?? [],
191
+ activity: target.native?.android?.activity ?? []
192
+ });
193
+ const resources = Object.entries(target.files ?? {}).map(([to, from]) => ({ from: abs(from), to }));
194
+ const native = NativeConfig.#compact({ ios, android, resources });
195
+ const googleServices = target.native?.android?.googleServices;
196
+ const config = {
197
+ app: {
198
+ id: target.appId,
199
+ name: target.appName,
200
+ fileName: target.fileName ?? NativeConfig.fileNameOf(path2.basename(appPath)),
201
+ version: target.version,
202
+ build: target.buildNum
203
+ },
204
+ web: { dir: webDir },
205
+ plugins,
206
+ capabilities: [
207
+ {
208
+ identifier: "app",
209
+ description: `The plugins ${target.appName} ships, each with its default permissions`,
210
+ permissions: plugins.map((plugin) => `${plugin}:default`)
211
+ }
212
+ ],
213
+ ...Object.keys(usageDescriptions).length ? { usageDescriptions } : {},
214
+ ...target.deepLinks?.schemes?.length || target.deepLinks?.domains?.length ? { deepLinks: NativeConfig.#deepLinks(target, locales) } : {},
215
+ ...native ? { native } : {},
216
+ android: { debugAppIdSuffix: ".debug", ...googleServices ? { googleServices: abs(googleServices) } : {} },
217
+ keyboard: { resize: "none" },
218
+ ...target.assets?.icon ? { icon: abs(target.assets.icon) } : {},
219
+ ...target.assets?.splash ? { splash: { image: abs(target.assets.splash) } } : {}
220
+ };
221
+ return { config, warnings };
222
+ }
223
+ static fileNameOf(name) {
224
+ return name.replace(/[^A-Za-z0-9._-]/g, "-").replace(/^[-.]+|[-.]+$/g, "") || "app";
225
+ }
226
+ static #compact(value) {
227
+ const kept = Object.entries(value).filter(([, entry]) => Array.isArray(entry) ? entry.length > 0 : entry && typeof entry === "object" ? Object.keys(entry).length > 0 : entry !== undefined);
228
+ return kept.length ? Object.fromEntries(kept) : undefined;
229
+ }
230
+ static #merged(contributed, own) {
231
+ return Object.assign({}, ...contributed, own);
232
+ }
233
+ static #deepLinks(target, locales) {
234
+ const basePath = target.basePath?.replace(/^\/+|\/+$/g, "");
235
+ const pathPrefixes = basePath ? locales.map((locale) => `/${locale}/${basePath}`) : undefined;
236
+ return {
237
+ ...target.deepLinks?.schemes?.length ? { schemes: target.deepLinks.schemes } : {},
238
+ ...target.deepLinks?.domains?.length ? { domains: target.deepLinks.domains.map((host) => pathPrefixes ? { host, pathPrefixes } : host) } : {}
239
+ };
240
+ }
241
+ }
242
+
243
+ // pkgs/@akanjs/devkit/mobile/nativeWebDir.ts
244
+ import { cp, mkdir, rm, stat } from "fs/promises";
245
+ import path3 from "path";
246
+
247
+ class NativeWebDir {
248
+ dir;
249
+ static reservedEntry = "__akan_native";
250
+ constructor(dir) {
251
+ this.dir = dir;
252
+ }
253
+ static injectTarget(html, target) {
254
+ if (html.includes(NativeWebDir.#targetTag))
255
+ return html;
256
+ const basePath = target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
257
+ const script = `${NativeWebDir.#targetTag}${JSON.stringify({
258
+ name: target.name,
259
+ basePath,
260
+ indexPath: target.indexPath
261
+ })};</script>`;
262
+ const head = /<head(?:\s[^>]*)?>/i.exec(html);
263
+ if (!head)
264
+ return `${script}
265
+ ${html}`;
266
+ const at = head.index + head[0].length;
267
+ return `${html.slice(0, at)}
268
+ ${script}${html.slice(at)}`;
269
+ }
270
+ static #targetTag = "<script>window.__AKAN_MOBILE_TARGET__=";
271
+ async assemble(target, { html, publicDir, fontsDir }) {
272
+ if (!await Bun.file(html).exists())
273
+ throw new Error(`CSR html for mobile target '${target.name}' not found: ${html}`);
274
+ await rm(this.dir, { recursive: true, force: true });
275
+ await mkdir(this.dir, { recursive: true });
276
+ if (publicDir && await NativeWebDir.#isDir(publicDir))
277
+ await cp(publicDir, this.dir, { recursive: true });
278
+ if (fontsDir && await NativeWebDir.#isDir(fontsDir))
279
+ await cp(fontsDir, path3.join(this.dir, "_akan", "fonts"), { recursive: true });
280
+ if (await NativeWebDir.#isDir(path3.join(this.dir, NativeWebDir.reservedEntry)))
281
+ throw new Error(`public/${NativeWebDir.reservedEntry} is reserved for the native runtime.`);
282
+ await Bun.write(path3.join(this.dir, "index.html"), NativeWebDir.injectTarget(await Bun.file(html).text(), target));
283
+ const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: this.dir, onlyFiles: true, dot: true }));
284
+ return files.map((file) => file.split(path3.sep).join("/")).sort();
285
+ }
286
+ static async#isDir(dir) {
287
+ try {
288
+ return (await stat(dir)).isDirectory();
289
+ } catch {
290
+ return false;
291
+ }
292
+ }
293
+ }
294
+
295
+ // pkgs/@akanjs/devkit/mobile/nativeApp.ts
296
+ class NativeApp {
297
+ app;
298
+ target;
299
+ targetRoot;
300
+ web;
301
+ constructor(app, target) {
302
+ this.app = app;
303
+ this.target = target;
304
+ this.targetRoot = path4.join(app.cwdPath, ".akan", "mobile", target.name);
305
+ this.web = new NativeWebDir(path4.join(this.targetRoot, "web"));
306
+ }
307
+ outDir(platform) {
308
+ return path4.join(this.targetRoot, "native", platform);
309
+ }
310
+ async assembleWeb() {
311
+ const dist = this.app.dist.cwdPath;
312
+ return await this.web.assemble(this.target.config, {
313
+ html: path4.join(dist, "csr", targetHtmlFilename(this.target.config)),
314
+ publicDir: path4.join(dist, "public"),
315
+ fontsDir: path4.join(dist, ".akan", "artifact", "fonts")
316
+ });
317
+ }
318
+ async config() {
319
+ const [appConfig, plugins] = await Promise.all([this.app.getConfig(), this.app.collectPlugins()]);
320
+ return NativeConfig.build({
321
+ appPath: this.app.cwdPath,
322
+ target: this.target.config,
323
+ webDir: this.web.dir,
324
+ contributions: plugins.flatMap((plugin) => plugin.native ? [plugin.native] : []),
325
+ locales: appConfig.i18n.locales
326
+ });
327
+ }
328
+ async prepare() {
329
+ const [api, { config, warnings }] = await Promise.all([NativeApi.load(this.app.cwdPath), this.config()]);
330
+ for (const warning of warnings)
331
+ this.app.logger.warn(warning);
332
+ const problems = api.validateConfig(config, { appDir: this.app.cwdPath });
333
+ if (problems.length)
334
+ throw new Error(`Mobile target '${this.target.name}' makes an invalid native config:
335
+ - ${problems.join(`
336
+ - `)}`);
337
+ return { api, config };
338
+ }
339
+ #appLine = (line) => {
340
+ this.app.logger.info(`[${this.target.name}] ${line}`);
341
+ };
342
+ #task(platform, config) {
343
+ return {
344
+ appDir: this.app.cwdPath,
345
+ config,
346
+ platform,
347
+ outDir: this.outDir(platform),
348
+ envFiles: false,
349
+ skipWebBuild: true,
350
+ log: (event) => {
351
+ if (event.level === "error")
352
+ this.app.logger.error(event.message);
353
+ else if (event.level === "warn")
354
+ this.app.logger.warn(event.message);
355
+ else if (event.level === "tool")
356
+ this.app.logger.verbose(event.message);
357
+ else
358
+ this.app.logger.info(event.message);
359
+ }
360
+ };
361
+ }
362
+ async build(platform, { profile = "release" } = {}) {
363
+ await this.assembleWeb();
364
+ const { api, config } = await this.prepare();
365
+ return await api.build({ ...this.#task(platform, config), profile });
366
+ }
367
+ async run(platform, { device, teamId, profile = "debug" } = {}) {
368
+ await this.assembleWeb();
369
+ const { api, config } = await this.prepare();
370
+ return await api.run({
371
+ ...this.#task(platform, config),
372
+ profile,
373
+ onLine: this.#appLine,
374
+ ...device ? { device } : {},
375
+ ...teamId ? { ios: { signing: { teamId } } } : {}
376
+ });
377
+ }
378
+ async dev(platform, { upstream, lang, device, teamId }) {
379
+ await mkdir2(this.web.dir, { recursive: true });
380
+ const [{ api, config }, { api: routes }] = await Promise.all([this.prepare(), this.app.getConfig()]);
381
+ return await api.dev({
382
+ ...this.#task(platform, config),
383
+ upstream,
384
+ hmrPath: "/_akan/hmr",
385
+ wsPaths: [`${routes.prefix}${routes.websocketPrefix}`],
386
+ onLine: this.#appLine,
387
+ startPath: this.startPath(lang),
388
+ ...device ? { device } : {},
389
+ ...teamId ? { ios: { signing: { teamId } } } : {}
390
+ });
391
+ }
392
+ async releaseIos({ teamId, adHoc = false } = {}) {
393
+ await this.assembleWeb();
394
+ const { api, config } = await this.prepare();
395
+ return await api.release({
396
+ ...this.#task("ios", config),
397
+ platform: "ios",
398
+ signing: { ...teamId ? { teamId } : {}, ...adHoc ? { distribution: "ad-hoc" } : {} }
399
+ });
400
+ }
401
+ async releaseAndroid({ formats = ["aab"] } = {}) {
402
+ const signing = NativeApp.androidSigning();
403
+ await this.assembleWeb();
404
+ const { api, config } = await this.prepare();
405
+ return await api.release({ ...this.#task("android", config), platform: "android", signing, formats });
406
+ }
407
+ static androidSigning(env = process.env) {
408
+ const keystore = env.MYAPP_RELEASE_STORE_FILE;
409
+ const storePassword = env.MYAPP_RELEASE_STORE_PASSWORD;
410
+ const alias = env.MYAPP_RELEASE_KEY_ALIAS;
411
+ const keyPassword = env.MYAPP_RELEASE_KEY_PASSWORD;
412
+ if (!keystore || !storePassword || !alias) {
413
+ const missing = Object.entries({
414
+ MYAPP_RELEASE_STORE_FILE: keystore,
415
+ MYAPP_RELEASE_STORE_PASSWORD: storePassword,
416
+ MYAPP_RELEASE_KEY_ALIAS: alias
417
+ }).flatMap(([key, value]) => value ? [] : [key]);
418
+ throw new Error(`An Android release is signed with the upload key; set ${missing.join(", ")} in the environment.`);
419
+ }
420
+ return { keystore, storePassword, alias, ...keyPassword ? { keyPassword } : {} };
421
+ }
422
+ startPath(lang) {
423
+ const basePath = this.target.config.basePath?.replace(/^\/+|\/+$/g, "");
424
+ const params = new URLSearchParams({ csr: "true", akanMobileTarget: this.target.name });
425
+ if (basePath)
426
+ params.set("akanMobileBasePath", basePath);
427
+ if (this.target.config.indexPath)
428
+ params.set("akanMobileIndexPath", this.target.config.indexPath);
429
+ const home = [lang, basePath, this.target.config.indexPath].flatMap((part) => (part ?? "").split("/")).filter((segment) => segment.length > 0);
430
+ return `/${home.join("/")}?${params}`;
431
+ }
432
+ static desktopPlatform(host = process.platform) {
433
+ if (host === "darwin")
434
+ return "macos";
435
+ if (host === "win32")
436
+ return "windows";
437
+ if (host === "linux")
438
+ return "linux";
439
+ throw new Error(`A desktop app builds on macOS, Windows or Linux, not on ${host}.`);
440
+ }
441
+ static async devices(appDir, platform) {
442
+ return await (await NativeApi.load(appDir)).devices({ platform });
443
+ }
444
+ static async doctor(appDir, platforms) {
445
+ return await (await NativeApi.load(appDir)).doctor({ platforms });
446
+ }
447
+ }
448
+
449
+ // pkgs/@akanjs/devkit/mobile/placeholderAppId.ts
450
+ var PLACEHOLDER_APP_IDS = [
451
+ "com.myapp.app",
452
+ "com.myorg.myapp",
453
+ "com.example.app",
454
+ "com.example.myapp"
455
+ ];
456
+ var placeholderAppIdSegment = /^(example|examples|myorg|myapp|mycompany|myorganization|changeme|todo|sample|test)$/;
457
+ var isPlaceholderAppId = (appId) => {
458
+ const normalized = appId?.trim().toLowerCase() ?? "";
459
+ if (!normalized)
460
+ return true;
461
+ if (PLACEHOLDER_APP_IDS.includes(normalized))
462
+ return true;
463
+ return normalized.split(".").some((segment) => placeholderAppIdSegment.test(segment));
464
+ };
465
+ export { getMobileTargets, getMobileTargetChoices, resolveMobileTargets, NativeApp, isPlaceholderAppId };
@@ -22,26 +22,26 @@ import {
22
22
  renderWorkflowApply,
23
23
  renderWorkflowValidation,
24
24
  renderWorkflowRunArtifact
25
- } from "./index-myhc3c1j.js";
25
+ } from "./index-yy4s1j72.js";
26
26
  import {
27
27
  AkanContextAnalyzer
28
- } from "./index-ygn77a5w.js";
28
+ } from "./index-9629w7ns.js";
29
29
  import {
30
30
  CommandContainer,
31
31
  runner
32
- } from "./index-w2zdcw3k.js";
32
+ } from "./index-rmcw8yc8.js";
33
33
  import {
34
34
  ModuleScript
35
- } from "./index-8mna0947.js";
35
+ } from "./index-tgjy8xf3.js";
36
36
  import {
37
37
  PrimitiveScript
38
- } from "./index-przybvy5.js";
38
+ } from "./index-wp43xrjv.js";
39
39
  import {
40
40
  spawnShell
41
- } from "./index-31yr441d.js";
41
+ } from "./index-ya5qbmyg.js";
42
42
  import {
43
43
  ScalarScript
44
- } from "./index-3sq321ak.js";
44
+ } from "./index-pp54p5zk.js";
45
45
 
46
46
  // pkgs/@akanjs/cli/workflow/workflow.runner.ts
47
47
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-w2zdcw3k.js";
5
+ } from "./index-rmcw8yc8.js";
6
6
  import {
7
7
  FileSys2
8
8
  } from "./index-5b6tavv3.js";
9
9
  import {
10
10
  PkgExecutor
11
- } from "./index-9d9bgcx4.js";
11
+ } from "./index-ga6hygxr.js";
12
12
  import {
13
13
  TypeScriptDependencyScanner2
14
14
  } from "./index-3t7g9e4r.js";
@@ -175,8 +175,9 @@ class PackageRunner extends runner("package") {
175
175
  ].filter((dep) => dep !== "akanjs" && dep !== "@akanjs/devkit");
176
176
  }
177
177
  const packageBundledRuntimeDependencies = {
178
- "@akanjs/cli": ["@akanjs/devkit"],
179
- akanjs: ["use-agentic"]
178
+ "@akanjs/cli": ["@akanjs/devkit", "@akanjs/native"],
179
+ "@akanjs/devkit": ["@akanjs/native"],
180
+ akanjs: ["use-agentic", "@akanjs/native"]
180
181
  };
181
182
  const bundledRuntimeDeps = new Set(packageBundledRuntimeDependencies[pkg.name] ?? []);
182
183
  const forcedRuntimeDeps = packageRuntimeDependencies[pkg.name] ?? [];
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-w2zdcw3k.js";
5
+ } from "./index-rmcw8yc8.js";
6
6
  import {
7
7
  generatedFilesForSync,
8
8
  createPassedPrimitiveReport,
9
9
  scalarChangedFiles
10
- } from "./index-myhc3c1j.js";
10
+ } from "./index-yy4s1j72.js";
11
11
  import {
12
12
  pluralizeName
13
13
  } from "./index-nz8prx9g.js";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  AppInfo
4
- } from "./index-9d9bgcx4.js";
4
+ } from "./index-ga6hygxr.js";
5
5
 
6
6
  // pkgs/@akanjs/devkit/slicePlanner.ts
7
7
  class SlicePlanner {
@@ -10,7 +10,7 @@ import {
10
10
  LibExecutor,
11
11
  PkgExecutor,
12
12
  ModuleExecutor
13
- } from "./index-9d9bgcx4.js";
13
+ } from "./index-ga6hygxr.js";
14
14
 
15
15
  // pkgs/@akanjs/devkit/commandDecorators/camelToKebabCase.ts
16
16
  var camelToKebabCase = (str) => str.replace(/([A-Z])/g, "-$1").toLowerCase();
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-w2zdcw3k.js";
5
+ } from "./index-rmcw8yc8.js";
6
6
 
7
7
  // pkgs/@akanjs/cli/page/page.runner.ts
8
8
  class PageRunner extends runner("page") {
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-w2zdcw3k.js";
5
+ } from "./index-rmcw8yc8.js";
6
6
  import {
7
7
  ModuleExecutor
8
- } from "./index-9d9bgcx4.js";
8
+ } from "./index-ga6hygxr.js";
9
9
  import {
10
10
  sourceFile,
11
11
  moduleSourcePaths,
@@ -13,10 +13,10 @@ import {
13
13
  createPassedPrimitiveReport,
14
14
  bilingualLabelForField,
15
15
  bilingualDescriptionForField
16
- } from "./index-myhc3c1j.js";
16
+ } from "./index-yy4s1j72.js";
17
17
  import {
18
18
  PageScript
19
- } from "./index-dzf3r49a.js";
19
+ } from "./index-rnt66vym.js";
20
20
  import {
21
21
  pluralizeName
22
22
  } from "./index-nz8prx9g.js";
@@ -4,7 +4,7 @@ import {
4
4
  akanCodePaths2,
5
5
  McpServerConfig,
6
6
  McpSignIn
7
- } from "./index-ztp3e73t.js";
7
+ } from "./index-d0arnrm8.js";
8
8
  import {
9
9
  stripAnsi
10
10
  } from "./index-7md2g9vw.js";
@@ -511,7 +511,7 @@ class AkanToolPack2 {
511
511
  return { name: "akan-tools", factory: async (pi) => await this.#register(pi) };
512
512
  }
513
513
  async names() {
514
- const { ContextRunner } = await import("./context.runner-k99nb5pk.js");
514
+ const { ContextRunner } = await import("./context.runner-yvyw5g2d.js");
515
515
  return [
516
516
  ...new ContextRunner().listMcpTools(this.#options.mode).map((tool) => tool.name),
517
517
  AkanToolPack2.verifyToolName
@@ -519,7 +519,7 @@ class AkanToolPack2 {
519
519
  }
520
520
  static verifyToolName = "akan_verify";
521
521
  async#register(pi) {
522
- const { ContextRunner } = await import("./context.runner-k99nb5pk.js");
522
+ const { ContextRunner } = await import("./context.runner-yvyw5g2d.js");
523
523
  const runner = new ContextRunner;
524
524
  const guidelineNames = await AkanToolPack2.#guidelineNames();
525
525
  for (const tool of runner.listMcpTools(this.#options.mode, { guidelineNames })) {
@@ -1,12 +1,12 @@
1
1
  // @bun
2
2
  import {
3
3
  script
4
- } from "./index-w2zdcw3k.js";
4
+ } from "./index-rmcw8yc8.js";
5
5
  import {
6
6
  AppExecutor,
7
7
  LibExecutor,
8
8
  ModuleExecutor
9
- } from "./index-9d9bgcx4.js";
9
+ } from "./index-ga6hygxr.js";
10
10
  import {
11
11
  workflowStatus,
12
12
  compactDiagnostics,
@@ -41,10 +41,10 @@ import {
41
41
  hasSignalFactoryEntry,
42
42
  insertSignalFactoryEntry,
43
43
  addFieldUiPolicyForType
44
- } from "./index-myhc3c1j.js";
44
+ } from "./index-yy4s1j72.js";
45
45
  import {
46
46
  ModuleScript
47
- } from "./index-8mna0947.js";
47
+ } from "./index-tgjy8xf3.js";
48
48
 
49
49
  // pkgs/@akanjs/cli/primitive/primitive.script.ts
50
50
  import { capitalize, lowerlize } from "akanjs/common";
@@ -5,13 +5,13 @@ import {
5
5
  writeGeneratedSyncState,
6
6
  createRepairReport,
7
7
  renderRepairReport
8
- } from "./index-myhc3c1j.js";
8
+ } from "./index-yy4s1j72.js";
9
9
  import {
10
10
  AkanContextAnalyzer
11
- } from "./index-ygn77a5w.js";
11
+ } from "./index-9629w7ns.js";
12
12
  import {
13
13
  runner
14
- } from "./index-w2zdcw3k.js";
14
+ } from "./index-rmcw8yc8.js";
15
15
 
16
16
  // pkgs/@akanjs/cli/repair/repair.runner.ts
17
17
  var spawnShell = async (workspace, command) => await workspace.spawn("bash", ["-lc", command.startsWith("akan ") ? `bun run ${command}` : command], {