@akanjs/cli 3.0.0-alpha.1 → 3.0.0-alpha.10

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 (84) hide show
  1. package/.build-stamp +1 -1
  2. package/{agent.command-yv00p0s0.js → agent.command-f0gqkfgz.js} +7 -6
  3. package/{application.command-0qsczf4k.js → application.command-x903m2qq.js} +5 -4
  4. package/{applicationBuildRunner-ct2pxyvw.js → applicationBuildRunner-ha3y8ew8.js} +3 -3
  5. package/buildBatch.proc.js +4 -3
  6. package/{capacitorApp-4r9sm3qg.js → capacitorApp-9xswcgx7.js} +5 -2
  7. package/{cloud.command-dxfv18sa.js → cloud.command-zs6kyf83.js} +8 -7
  8. package/{context.command-8d9e3k6b.js → context.command-fmepgjzg.js} +14 -13
  9. package/getDirname-m9s0cmhq.js +8 -0
  10. package/{guideline.command-3jbkxzh6.js → guideline.command-n6sw0a0c.js} +5 -4
  11. package/guidelines/conventions/conventions.generate.json +25 -0
  12. package/guidelines/conventions/conventions.instruction.md +668 -0
  13. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +24 -0
  14. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +972 -0
  15. package/incrementalBuilder.proc.js +3 -2
  16. package/index-1577bej2.js +7 -0
  17. package/{index-bekddz9q.js → index-3vta1tqa.js} +4 -4
  18. package/{index-zasydjxd.js → index-4m0bphac.js} +3 -3
  19. package/{index-1pvex4az.js → index-5sn5w2mt.js} +13 -13
  20. package/{index-e16gnn26.js → index-62955kn5.js} +7 -7
  21. package/{index-a00jg8x8.js → index-774gcx29.js} +49 -32
  22. package/{index-t3723f99.js → index-779ske1y.js} +86 -17
  23. package/{index-nm6wghb6.js → index-82jrh4hj.js} +5 -5
  24. package/{index-7c6k4yvg.js → index-d43t8af2.js} +2 -2
  25. package/{index-ej426mcr.js → index-eyyf2149.js} +34 -6
  26. package/{index-k95xkh4p.js → index-gcv8ncfh.js} +2 -2
  27. package/{index-tdbas9r0.js → index-j37qq1f2.js} +1 -1
  28. package/{index-rh16j3c7.js → index-j9cxndc0.js} +3 -2
  29. package/{index-mr5s7mqd.js → index-jf2ya7r2.js} +3 -3
  30. package/{index-yzmhasdb.js → index-jhpa13zj.js} +7 -7
  31. package/{index-8hsbnyes.js → index-kdh76j26.js} +4 -2
  32. package/{index-pyt2b4nw.js → index-qb61h0k7.js} +52 -17
  33. package/{index-2q1f5j9k.js → index-qzdjd4ct.js} +3 -3
  34. package/{index-rzwcpcc3.js → index-rxkpk7n4.js} +1 -1
  35. package/{index-bbkek1bp.js → index-xmmzf150.js} +1 -1
  36. package/{index-ec09pws3.js → index-y4vkyhvv.js} +3 -3
  37. package/{index-hgna5rjy.js → index-z8ptfkzv.js} +83 -39
  38. package/index.js +19 -18
  39. package/{library.command-ebdj1vnm.js → library.command-cv9gdbmg.js} +4 -3
  40. package/{localRegistry.command-gb178ne8.js → localRegistry.command-d8fg36zc.js} +7 -6
  41. package/{module.command-9c1bnsx4.js → module.command-qyr1s9cn.js} +7 -6
  42. package/{package.command-t93p4jkj.js → package.command-wsjx0k47.js} +4 -3
  43. package/package.json +2 -2
  44. package/{page.command-k3k0meh2.js → page.command-rdzg65rm.js} +4 -3
  45. package/{primitive.command-de6nktdt.js → primitive.command-89g38b53.js} +8 -7
  46. package/{quality.command-z5kth2wa.js → quality.command-0cs2z92d.js} +10 -40
  47. package/{repair.command-ehf2g112.js → repair.command-6fphxfwj.js} +6 -5
  48. package/{routeSourceValidator-cncd92fv.js → routeSourceValidator-e4jmbfcx.js} +2 -38
  49. package/{scalar.command-7a2jtv33.js → scalar.command-xfer69s6.js} +6 -5
  50. package/templates/app/page/styles.css.template +3 -3
  51. package/templates/crudPages/[__model__Id]/edit/page.tsx +1 -1
  52. package/templates/crudPages/new/page.tsx +1 -1
  53. package/templates/crudSinglePage/page.tsx +1 -1
  54. package/templates/lib/db.ts +3 -1
  55. package/templates/lib/useClient.ts +9 -3
  56. package/templates/module/__Model__.Util.tsx +1 -1
  57. package/templates/module/__Model__.Zone.tsx +3 -5
  58. package/templates/workspaceRoot/AGENTS.md.template +0 -948
  59. package/templates/workspaceRoot/biome.json.template +3 -198
  60. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +4 -1
  61. package/{workflow.command-e0tt0vk2.js → workflow.command-2ygfqt4f.js} +13 -12
  62. package/{workspace.command-fpda0evj.js → workspace.command-vbgpjkf9.js} +35 -33
  63. package/templates/libRoot/base/baseLogic.ts +0 -14
  64. package/templates/libRoot/base/index.ts +0 -8
  65. package/templates/workspaceRoot/.cursor/rules/akan-page-routing.mdc.template +0 -43
  66. package/templates/workspaceRoot/.cursor/rules/akan-sync-conventions.mdc.template +0 -33
  67. package/templates/workspaceRoot/.cursor/rules/application-test-commands.mdc.template +0 -16
  68. package/templates/workspaceRoot/.cursor/rules/change-scope.mdc.template +0 -12
  69. package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +0 -18
  70. package/templates/workspaceRoot/.cursor/rules/coding-comments.mdc.template +0 -25
  71. package/templates/workspaceRoot/.cursor/rules/coding-style.mdc.template +0 -44
  72. package/templates/workspaceRoot/.cursor/rules/domain-module-conventions.mdc.template +0 -17
  73. package/templates/workspaceRoot/.cursor/rules/format-lint.mdc.template +0 -12
  74. package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +0 -18
  75. package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +0 -61
  76. package/templates/workspaceRoot/.cursor/rules/naming-conventions.mdc.template +0 -15
  77. package/templates/workspaceRoot/.cursor/rules/react-component-style.mdc.template +0 -21
  78. package/templates/workspaceRoot/.cursor/rules/repo-overview.mdc.template +0 -17
  79. package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +0 -58
  80. package/templates/workspaceRoot/.cursor/rules/secrets-and-env.mdc.template +0 -13
  81. package/templates/workspaceRoot/.cursor/rules/service-signal-conventions.mdc.template +0 -83
  82. package/templates/workspaceRoot/.cursor/rules/srvkit-adapters-and-guards.mdc.template +0 -50
  83. package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +0 -59
  84. package/templates/workspaceRoot/.cursor/rules/typescript-imports.mdc.template +0 -16
@@ -8,7 +8,7 @@ import {
8
8
  DevGeneratedIndexSync,
9
9
  GraphClientEntryDiscovery,
10
10
  RouteClientBuilder
11
- } from "./index-rh16j3c7.js";
11
+ } from "./index-j9cxndc0.js";
12
12
  import {
13
13
  HmrWatcher,
14
14
  WatchRootResolver
@@ -16,8 +16,9 @@ import {
16
16
  import {
17
17
  AppExecutor,
18
18
  WorkspaceExecutor
19
- } from "./index-hgna5rjy.js";
19
+ } from "./index-z8ptfkzv.js";
20
20
  import"./index-mxvakhsm.js";
21
+ import"./index-1577bej2.js";
21
22
  import"./index-67546d0j.js";
22
23
  import"./index-r24hmh0q.js";
23
24
 
@@ -0,0 +1,7 @@
1
+ // @bun
2
+ // pkgs/@akanjs/devkit/getDirname.ts
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ var getDirname = (url) => path.dirname(fileURLToPath(url));
6
+
7
+ export { getDirname };
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  ModuleScript
4
- } from "./index-yzmhasdb.js";
4
+ } from "./index-jhpa13zj.js";
5
5
  import {
6
6
  addFieldUiPolicyForType,
7
7
  coerceFieldDefault,
@@ -34,15 +34,15 @@ import {
34
34
  sourceFile,
35
35
  validationCommandsForTarget,
36
36
  viaBuilderParameterName
37
- } from "./index-rzwcpcc3.js";
37
+ } from "./index-rxkpk7n4.js";
38
38
  import {
39
39
  script
40
- } from "./index-8hsbnyes.js";
40
+ } from "./index-kdh76j26.js";
41
41
  import {
42
42
  AppExecutor,
43
43
  LibExecutor,
44
44
  ModuleExecutor
45
- } from "./index-hgna5rjy.js";
45
+ } from "./index-z8ptfkzv.js";
46
46
 
47
47
  // pkgs/@akanjs/cli/primitive/primitive.script.ts
48
48
  import { capitalize } from "akanjs/common";
@@ -7,14 +7,14 @@ import {
7
7
  } from "./index-0cj2zxbm.js";
8
8
  import {
9
9
  openBrowser
10
- } from "./index-e16gnn26.js";
10
+ } from "./index-62955kn5.js";
11
11
  import {
12
12
  runner
13
- } from "./index-8hsbnyes.js";
13
+ } from "./index-kdh76j26.js";
14
14
  import {
15
15
  AppExecutor,
16
16
  WorkspaceExecutor
17
- } from "./index-hgna5rjy.js";
17
+ } from "./index-z8ptfkzv.js";
18
18
 
19
19
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
20
20
  import path from "path";
@@ -1,22 +1,22 @@
1
1
  // @bun
2
2
  import {
3
3
  RepairRunner
4
- } from "./index-mr5s7mqd.js";
4
+ } from "./index-jf2ya7r2.js";
5
5
  import {
6
6
  WorkflowRunner
7
- } from "./index-2q1f5j9k.js";
7
+ } from "./index-qzdjd4ct.js";
8
+ import {
9
+ ScalarScript
10
+ } from "./index-y4vkyhvv.js";
8
11
  import {
9
12
  PrimitiveScript
10
- } from "./index-bekddz9q.js";
13
+ } from "./index-3vta1tqa.js";
11
14
  import {
12
15
  ModuleScript
13
- } from "./index-yzmhasdb.js";
14
- import {
15
- ScalarScript
16
- } from "./index-ec09pws3.js";
16
+ } from "./index-jhpa13zj.js";
17
17
  import {
18
18
  isPlaceholderAppId
19
- } from "./index-t3723f99.js";
19
+ } from "./index-779ske1y.js";
20
20
  import {
21
21
  AkanContextAnalyzer,
22
22
  akanMcpInstallConfigPaths,
@@ -27,17 +27,17 @@ import {
27
27
  renderDoctorText,
28
28
  resourceList,
29
29
  upsertCodexMcpServerBlock
30
- } from "./index-a00jg8x8.js";
30
+ } from "./index-774gcx29.js";
31
31
  import {
32
32
  buildAkanModuleContextIndex,
33
33
  createWorkflowBaselineSummary,
34
34
  createWorkflowStepRegistry,
35
35
  jsonText,
36
36
  toolingRolloutGate
37
- } from "./index-rzwcpcc3.js";
37
+ } from "./index-rxkpk7n4.js";
38
38
  import {
39
39
  Prompter
40
- } from "./index-tdbas9r0.js";
40
+ } from "./index-j37qq1f2.js";
41
41
  import {
42
42
  getMobileTargets
43
43
  } from "./index-76rn3g2c.js";
@@ -45,10 +45,10 @@ import {
45
45
  CommandContainer,
46
46
  runner,
47
47
  script
48
- } from "./index-8hsbnyes.js";
48
+ } from "./index-kdh76j26.js";
49
49
  import {
50
50
  AppExecutor
51
- } from "./index-hgna5rjy.js";
51
+ } from "./index-z8ptfkzv.js";
52
52
 
53
53
  // pkgs/@akanjs/cli/context/context.script.ts
54
54
  import { Logger } from "akanjs/common";
@@ -1,14 +1,14 @@
1
1
  // @bun
2
+ import {
3
+ LibraryScript
4
+ } from "./index-d43t8af2.js";
2
5
  import {
3
6
  resolveMobileTargets
4
7
  } from "./index-76rn3g2c.js";
5
- import {
6
- LibraryScript
7
- } from "./index-7c6k4yvg.js";
8
8
  import {
9
9
  runner,
10
10
  script
11
- } from "./index-8hsbnyes.js";
11
+ } from "./index-kdh76j26.js";
12
12
  import {
13
13
  HmrWatcher,
14
14
  WatchRootResolver
@@ -18,7 +18,7 @@ import {
18
18
  LibExecutor,
19
19
  PkgExecutor,
20
20
  WorkspaceExecutor
21
- } from "./index-hgna5rjy.js";
21
+ } from "./index-z8ptfkzv.js";
22
22
  import {
23
23
  __require
24
24
  } from "./index-r24hmh0q.js";
@@ -1898,9 +1898,9 @@ function openBrowser(url) {
1898
1898
  }
1899
1899
 
1900
1900
  // pkgs/@akanjs/cli/application/application.runner.ts
1901
- var loadBuildRunner = async () => (await import("./applicationBuildRunner-ct2pxyvw.js")).ApplicationBuildRunner;
1901
+ var loadBuildRunner = async () => (await import("./applicationBuildRunner-ha3y8ew8.js")).ApplicationBuildRunner;
1902
1902
  var loadReleasePackager = async () => (await import("./applicationReleasePackager-gg8ccbeh.js")).ApplicationReleasePackager;
1903
- var loadCapacitorApp = async () => (await import("./capacitorApp-4r9sm3qg.js")).CapacitorApp;
1903
+ var loadCapacitorApp = async () => (await import("./capacitorApp-9xswcgx7.js")).CapacitorApp;
1904
1904
  var loadAbstractCompactor = async () => (await import("./abstractCompactor-e5yq60qz.js")).AbstractCompactor;
1905
1905
  var loadPrompts = async () => await import("@inquirer/prompts");
1906
1906
 
@@ -2,11 +2,16 @@
2
2
  import {
3
3
  workflowRunArtifactPath,
4
4
  workflowSyncDir
5
- } from "./index-rzwcpcc3.js";
5
+ } from "./index-rxkpk7n4.js";
6
6
  import {
7
7
  AppExecutor,
8
- LibExecutor
9
- } from "./index-hgna5rjy.js";
8
+ LibExecutor,
9
+ appRootAllowedDirs,
10
+ appRootAllowedFiles,
11
+ extractBlockVersion,
12
+ isScannedAppRootEntry,
13
+ readDevkitVersion
14
+ } from "./index-z8ptfkzv.js";
10
15
  import {
11
16
  collectRecipeSources,
12
17
  findInlineRecipeDuplicates,
@@ -121,7 +126,9 @@ var validationCommands = [
121
126
  "akan typecheck <app-name>",
122
127
  "akan test <app-or-lib-or-pkg>",
123
128
  "akan build <app-name>",
124
- "akan doctor --strict --format json"
129
+ "akan doctor --strict --format json",
130
+ "akan quality scan [--format json]",
131
+ "akan quality ssr [--format json]"
125
132
  ];
126
133
  var unknownGeneratedFilesFreshness = {
127
134
  status: "unknown",
@@ -150,33 +157,6 @@ var moduleShapeFiles = (module) => {
150
157
  ];
151
158
  };
152
159
  var constantFieldNames = (content) => [...content.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*field\(/g)].map((match) => match[1]).filter(Boolean);
153
- var appRootAllowFiles = new Set([
154
- "AGENTS.md",
155
- "CLAUDE.md",
156
- "akan.app.json",
157
- "akan.config.ts",
158
- "capacitor.config.ts",
159
- "client.ts",
160
- "main.ts",
161
- "package.json",
162
- "server.ts",
163
- "tsconfig.json"
164
- ]);
165
- var appRootAllowDirs = new Set([
166
- ".akan",
167
- "android",
168
- "common",
169
- "env",
170
- "ios",
171
- "lib",
172
- "page",
173
- "private",
174
- "public",
175
- "script",
176
- "srvkit",
177
- "ui",
178
- "webkit"
179
- ]);
180
160
  var safeReadDir = async (dirPath) => {
181
161
  try {
182
162
  return (await readdir(dirPath, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
@@ -389,6 +369,29 @@ class AkanContextAnalyzer {
389
369
  validationCommands
390
370
  };
391
371
  }
372
+ static async#agentGuideDrift(workspace) {
373
+ const installed = await readDevkitVersion();
374
+ if (!installed)
375
+ return null;
376
+ const content = await safeReadText(path.join(workspace.workspaceRoot, "AGENTS.md"));
377
+ if (content === null)
378
+ return null;
379
+ const stamped = extractBlockVersion(content);
380
+ if (stamped === installed)
381
+ return null;
382
+ const hint = "Re-render the AGENTS.md managed block from the installed framework release.";
383
+ if (!stamped)
384
+ return {
385
+ code: "agent-guide-unstamped",
386
+ message: `AGENTS.md carries no generated-version stamp, so its conventions may predate @akanjs/devkit ${installed}`,
387
+ hint
388
+ };
389
+ return {
390
+ code: "agent-guide-stale",
391
+ message: `AGENTS.md was generated by @akanjs/devkit ${stamped}, but ${installed} is installed`,
392
+ hint
393
+ };
394
+ }
392
395
  static async doctor(workspace, {
393
396
  strict = false,
394
397
  runIdOrPlan = null,
@@ -404,7 +407,9 @@ class AkanContextAnalyzer {
404
407
  for (const app of context.apps) {
405
408
  const appPath = path.join(workspace.workspaceRoot, app.path);
406
409
  for (const entry of await safeReadDir(appPath)) {
407
- const allowed = entry.isDirectory() ? appRootAllowDirs.has(entry.name) : appRootAllowFiles.has(entry.name);
410
+ if (!isScannedAppRootEntry(entry.name))
411
+ continue;
412
+ const allowed = entry.isDirectory() ? appRootAllowedDirs.has(entry.name) : appRootAllowedFiles.has(entry.name);
408
413
  if (!allowed) {
409
414
  const action = repairAction("module-shape", `akan repair module-shape --app ${app.name}`, "Review app root shape and remove or move the unknown entry.", false);
410
415
  diagnostics.push({
@@ -418,6 +423,18 @@ class AkanContextAnalyzer {
418
423
  }
419
424
  }
420
425
  }
426
+ const agentDrift = await AkanContextAnalyzer.#agentGuideDrift(workspace);
427
+ if (agentDrift) {
428
+ const action = repairAction("generated", "akan agent install agents-md", agentDrift.hint, true);
429
+ diagnostics.push({
430
+ severity: "warning",
431
+ code: agentDrift.code,
432
+ path: "AGENTS.md",
433
+ message: agentDrift.message,
434
+ repairActions: [action]
435
+ });
436
+ repairActions.push(action);
437
+ }
421
438
  for (const sys of [...context.apps, ...context.libs]) {
422
439
  for (const module of sys.modules) {
423
440
  if (!module.abstract.exists) {
@@ -5,7 +5,7 @@ import {
5
5
  } from "./index-76rn3g2c.js";
6
6
  import {
7
7
  CommandExecutionError
8
- } from "./index-hgna5rjy.js";
8
+ } from "./index-z8ptfkzv.js";
9
9
 
10
10
  // pkgs/@akanjs/devkit/capacitorApp.ts
11
11
  import { cp, mkdir, readFile, rm, writeFile } from "fs/promises";
@@ -514,6 +514,10 @@ function getAdbDeviceStateIssues(output) {
514
514
  return [];
515
515
  });
516
516
  }
517
+ function getAndroidLocalServerHost(adbDevicesOutput, fallbackHost) {
518
+ const onlineDeviceIds = adbDevicesOutput?.split(/\r?\n/).map((line) => line.trim().split(/\s+/)).filter(([id, state]) => id && state === "device").map(([id]) => id) ?? [];
519
+ return onlineDeviceIds.length === 1 && onlineDeviceIds[0]?.startsWith("emulator-") ? "10.0.2.2" : fallbackHost;
520
+ }
517
521
  var ANDROID_MIN_SDK_VERSION = 26;
518
522
  function raiseGradleMinSdkVersion(content, floor = ANDROID_MIN_SDK_VERSION) {
519
523
  const match = content.match(/minSdkVersion\s*=\s*(\d+)/);
@@ -691,7 +695,7 @@ class CapacitorApp {
691
695
  async save() {
692
696
  await this.project.commit();
693
697
  }
694
- async#prepareIos({ operation, env, regenerate = false }) {
698
+ async#prepareIos({ operation, env, regenerate = false, iosRunTargetKind }) {
695
699
  await this.init({ platform: "ios", operation, env, regenerate });
696
700
  await this.#prepareTargetAssets();
697
701
  await this.#prepareExternalFiles("ios");
@@ -700,9 +704,10 @@ class CapacitorApp {
700
704
  await this.#applyDeepLinks("ios", { operation, env });
701
705
  await this.#flushIosEntitlements();
702
706
  await this.project.commit();
707
+ await this.#setCodeSignEntitlementsInIosIfExists("App/App.entitlements");
703
708
  await this.#generateAssets({ operation, env });
704
709
  this.app.verbose(`syncing iOS`);
705
- await this.#spawnMobile("npx", ["cap", "sync", "ios"], { operation, env });
710
+ await this.#spawnMobile("npx", ["cap", "sync", "ios"], { operation, env }, { iosRunTargetKind });
706
711
  this.app.verbose(`sync completed.`);
707
712
  }
708
713
  async buildIos({ env = "debug", regenerate = false } = {}) {
@@ -721,10 +726,10 @@ class CapacitorApp {
721
726
  async runIos({ operation, env, regenerate = false, noAllowProvisioningUpdates = false, iosDeviceId }) {
722
727
  if (operation === "release")
723
728
  await this.prepareWww();
724
- await this.#prepareIos({ operation, env, regenerate });
725
729
  const runTarget = await this.#selectIosRunTarget(iosDeviceId);
730
+ await this.#prepareIos({ operation, env, regenerate, iosRunTargetKind: runTarget.kind });
726
731
  if (runTarget.kind === "simulator") {
727
- await this.#spawnMobile("npx", ["cap", "run", "ios", "--target", runTarget.id], { operation, env }, { stdio: "inherit" });
732
+ await this.#spawnMobile("npx", ["cap", "run", "ios", "--target", runTarget.id, "--no-sync"], { operation, env }, { stdio: "inherit", platform: "ios", iosRunTargetKind: runTarget.kind });
728
733
  return;
729
734
  }
730
735
  await this.#runIosPhysicalDevice({ operation, env, runTarget, noAllowProvisioningUpdates });
@@ -800,7 +805,7 @@ ${textError instanceof Error ? textError.message : ""}`);
800
805
  noAllowProvisioningUpdates
801
806
  }) {
802
807
  const mobileEnv = sanitizeIosNativeRunEnv(await this.#commandEnv(operation, env));
803
- const configContent = await this.#writeCapacitorConfig({ operation }, mobileEnv);
808
+ const configContent = await this.#writeCapacitorConfig({ operation, platform: "ios", iosRunTargetKind: runTarget.kind }, mobileEnv);
804
809
  await this.#writeRootCapacitorConfig(configContent);
805
810
  const scheme = this.#iosScheme();
806
811
  const command = buildIosNativeRunCommand({
@@ -857,6 +862,7 @@ ${error.message}`;
857
862
  await this.#applyAndroidMinSdkVersion();
858
863
  await this.#applyPermissions({ operation, env });
859
864
  await this.#applyDeepLinks("android", { operation, env });
865
+ await this.#disableNativeKeyboardResizeInAndroid();
860
866
  await this.project.commit();
861
867
  await this.#generateAssets({ operation, env });
862
868
  await this.#ensureAndroidAssetsDir();
@@ -916,6 +922,23 @@ ${error.message}`;
916
922
  async openAndroid() {
917
923
  await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
918
924
  }
925
+ async#disableNativeKeyboardResizeInAndroid() {
926
+ const manifestPath = path.join(this.app.cwdPath, this.androidRootPath, "app/src/main/AndroidManifest.xml");
927
+ let manifest = await readFile(manifestPath, "utf8");
928
+ let changed = false;
929
+ manifest = manifest.replace(/<activity\b[^>]*android:name="\.MainActivity"[^>]*>/, (activityTag) => {
930
+ if (activityTag.includes("android:windowSoftInputMode=")) {
931
+ const nextTag = activityTag.replace(/android:windowSoftInputMode="[^"]*"/, 'android:windowSoftInputMode="adjustNothing"');
932
+ changed ||= nextTag !== activityTag;
933
+ return nextTag;
934
+ }
935
+ changed = true;
936
+ return activityTag.replace(/>$/, `
937
+ android:windowSoftInputMode="adjustNothing">`);
938
+ });
939
+ if (changed)
940
+ await writeFile(manifestPath, manifest);
941
+ }
919
942
  async#ensureAndroidAssetsDir() {
920
943
  await mkdir(path.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
921
944
  }
@@ -1005,12 +1028,16 @@ ${error.message}`;
1005
1028
  return html.replace(/<\/head\s*>/i, `${script}
1006
1029
  </head>`);
1007
1030
  }
1008
- async#writeCapacitorConfig({ operation }, commandEnv) {
1031
+ async#writeCapacitorConfig({
1032
+ operation,
1033
+ platform,
1034
+ iosRunTargetKind
1035
+ }, commandEnv) {
1009
1036
  await mkdir(this.targetRoot, { recursive: true });
1010
1037
  let localIp;
1011
1038
  if (operation === "local") {
1012
1039
  const override = commandEnv.AKAN_PUBLIC_CLIENT_HOST ?? process.env.AKAN_PUBLIC_CLIENT_HOST;
1013
- const resolution = selectLocalDevHost(os.networkInterfaces(), { override });
1040
+ const resolution = await this.#resolveLocalDevHost({ override, platform, iosRunTargetKind });
1014
1041
  localIp = resolution.host;
1015
1042
  this.#logDevHostResolution(resolution, commandEnv);
1016
1043
  }
@@ -1024,9 +1051,29 @@ ${error.message}`;
1024
1051
  await Bun.write(path.join(this.targetRoot, "capacitor.config.json"), content);
1025
1052
  return content;
1026
1053
  }
1054
+ async#resolveLocalDevHost({
1055
+ override,
1056
+ platform,
1057
+ iosRunTargetKind
1058
+ }) {
1059
+ const resolution = selectLocalDevHost(os.networkInterfaces(), { override });
1060
+ if (resolution.source === "override")
1061
+ return resolution;
1062
+ if (platform === "ios" && iosRunTargetKind === "simulator")
1063
+ return { ...resolution, host: "localhost", source: "platform" };
1064
+ if (platform === "android") {
1065
+ try {
1066
+ const host = getAndroidLocalServerHost(await this.#spawn("adb", ["devices"]), resolution.host);
1067
+ return host === resolution.host ? resolution : { ...resolution, host, source: "platform" };
1068
+ } catch {
1069
+ return resolution;
1070
+ }
1071
+ }
1072
+ return resolution;
1073
+ }
1027
1074
  #logDevHostResolution(resolution, commandEnv) {
1028
1075
  this.app.log(`Mobile live-reload server: ${this.#localCsrUrl(resolution.host, commandEnv)}`);
1029
- if (resolution.source === "override")
1076
+ if (resolution.source === "override" || resolution.source === "platform")
1030
1077
  return;
1031
1078
  const suspicious = resolution.host === "127.0.0.1" || resolution.host.startsWith("169.254.");
1032
1079
  const alternatives = resolution.candidates.filter((candidate) => candidate.address !== resolution.host);
@@ -1226,18 +1273,26 @@ ${error.message}`;
1226
1273
  return await this.app.spawn(command, args, { cwd: this.app.cwdPath, ...options });
1227
1274
  }
1228
1275
  async#spawnMobile(command, args = [], { operation, env }, options = {}) {
1276
+ const { iosRunTargetKind, platform, ...spawnOptions } = options;
1229
1277
  const mobileEnv = { ...await this.#commandEnv(operation, env), ...options.env };
1230
- const configContent = await this.#writeCapacitorConfig({ operation }, mobileEnv);
1278
+ const configContent = await this.#writeCapacitorConfig({ operation, platform: platform ?? this.#inferMobilePlatform(args), iosRunTargetKind }, mobileEnv);
1231
1279
  await this.#writeRootCapacitorConfig(configContent);
1232
1280
  try {
1233
1281
  return await this.#spawn(command, args, {
1234
- ...options,
1282
+ ...spawnOptions,
1235
1283
  env: mobileEnv
1236
1284
  });
1237
1285
  } finally {
1238
1286
  await this.#clearRootCapacitorConfigs();
1239
1287
  }
1240
1288
  }
1289
+ #inferMobilePlatform(args) {
1290
+ if (args.includes("android"))
1291
+ return "android";
1292
+ if (args.includes("ios"))
1293
+ return "ios";
1294
+ return;
1295
+ }
1241
1296
  async addCamera() {
1242
1297
  await this.#setPermissionInIos({
1243
1298
  cameraUsageDescription: "$(PRODUCT_NAME) requires access to the camera to take photos.",
@@ -1339,17 +1394,31 @@ ${error.message}`;
1339
1394
  while (end < lines.length && !/^\s*\};\s*$/.test(lines[end] ?? ""))
1340
1395
  end++;
1341
1396
  const settings = lines.slice(start, end + 1);
1342
- if (settings.some((setting) => setting.includes("CODE_SIGN_ENTITLEMENTS")))
1343
- continue;
1397
+ const configName = lines.slice(end + 1, end + 8).find((setting) => setting.includes("name = ")) ?? "";
1344
1398
  const indent = line.match(/^\s*/)?.[0] ?? "";
1345
- lines.splice(index, 0, `${indent}CODE_SIGN_ENTITLEMENTS = ${entitlementsRelPath};`);
1346
- index++;
1347
- changed = true;
1399
+ const insertSettings = [];
1400
+ if (!settings.some((setting) => setting.includes("CODE_SIGN_ENTITLEMENTS"))) {
1401
+ insertSettings.push(`${indent}CODE_SIGN_ENTITLEMENTS = ${entitlementsRelPath};`);
1402
+ }
1403
+ if (configName.includes("name = Debug;") && !settings.some((setting) => setting.includes("CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION"))) {
1404
+ insertSettings.push(`${indent}CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES;`);
1405
+ }
1406
+ if (insertSettings.length > 0) {
1407
+ lines.splice(index, 0, ...insertSettings);
1408
+ index += insertSettings.length;
1409
+ changed = true;
1410
+ }
1348
1411
  }
1349
1412
  if (changed)
1350
1413
  await writeFile(pbxprojPath, lines.join(`
1351
1414
  `));
1352
1415
  }
1416
+ async#setCodeSignEntitlementsInIosIfExists(entitlementsRelPath) {
1417
+ const entitlementsPath = path.join(this.app.cwdPath, this.iosProjectPath, entitlementsRelPath);
1418
+ if (!await Bun.file(entitlementsPath).exists())
1419
+ return;
1420
+ await this.#setCodeSignEntitlementsInIos(entitlementsRelPath);
1421
+ }
1353
1422
  async#setUrlSchemesInAndroid(schemes) {
1354
1423
  const manifestPath = path.join(this.app.cwdPath, this.androidRootPath, "app/src/main/AndroidManifest.xml");
1355
1424
  let manifest = await readFile(manifestPath, "utf8");
@@ -1444,4 +1513,4 @@ ${filter}$1`);
1444
1513
  }
1445
1514
  }
1446
1515
 
1447
- export { SWIFTUICORE_MIN_IOS_MAJOR, rootCapacitorConfigFilenames, rootCapacitorConfigPaths, clearRootCapacitorConfigs, writeRootCapacitorConfig, selectLocalDevHost, parseIosRuntimeMajor, sortIosRunTargets, parseDevicectlDevices, parseSimctlDevices, buildIosNativeRunCommand, classifyIosRunFailure, formatIosRunFailureMessage, sanitizeIosNativeRunEnv, PLACEHOLDER_APP_IDS, isPlaceholderAppId, getMissingAndroidReleaseSigningKeys, formatAndroidReleaseSigningError, getAdbDeviceStateIssues, ANDROID_MIN_SDK_VERSION, raiseGradleMinSdkVersion, assertJsonSerializable, materializeCapacitorConfig, CapacitorApp };
1516
+ export { SWIFTUICORE_MIN_IOS_MAJOR, rootCapacitorConfigFilenames, rootCapacitorConfigPaths, clearRootCapacitorConfigs, writeRootCapacitorConfig, selectLocalDevHost, parseIosRuntimeMajor, sortIosRunTargets, parseDevicectlDevices, parseSimctlDevices, buildIosNativeRunCommand, classifyIosRunFailure, formatIosRunFailureMessage, sanitizeIosNativeRunEnv, PLACEHOLDER_APP_IDS, isPlaceholderAppId, getMissingAndroidReleaseSigningKeys, formatAndroidReleaseSigningError, getAdbDeviceStateIssues, getAndroidLocalServerHost, ANDROID_MIN_SDK_VERSION, raiseGradleMinSdkVersion, assertJsonSerializable, materializeCapacitorConfig, CapacitorApp };
@@ -1,10 +1,10 @@
1
1
  // @bun
2
2
  import {
3
3
  CloudRunner
4
- } from "./index-zasydjxd.js";
4
+ } from "./index-4m0bphac.js";
5
5
  import {
6
6
  PackageScript
7
- } from "./index-k95xkh4p.js";
7
+ } from "./index-gcv8ncfh.js";
8
8
  import {
9
9
  AiSession,
10
10
  CloudApi,
@@ -12,13 +12,13 @@ import {
12
12
  } from "./index-0cj2zxbm.js";
13
13
  import {
14
14
  ApplicationScript
15
- } from "./index-e16gnn26.js";
15
+ } from "./index-62955kn5.js";
16
16
  import {
17
17
  script
18
- } from "./index-8hsbnyes.js";
18
+ } from "./index-kdh76j26.js";
19
19
  import {
20
20
  PkgExecutor
21
- } from "./index-hgna5rjy.js";
21
+ } from "./index-z8ptfkzv.js";
22
22
 
23
23
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
24
24
  import { Logger } from "akanjs/common";
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-8hsbnyes.js";
5
+ } from "./index-kdh76j26.js";
6
6
  import {
7
7
  LibExecutor
8
- } from "./index-hgna5rjy.js";
8
+ } from "./index-z8ptfkzv.js";
9
9
 
10
10
  // pkgs/@akanjs/cli/semver.ts
11
11
  function parseVersion(version) {
@@ -1,22 +1,24 @@
1
1
  // @bun
2
2
  import {
3
3
  AkanContextAnalyzer
4
- } from "./index-a00jg8x8.js";
4
+ } from "./index-774gcx29.js";
5
5
  import {
6
6
  Prompter
7
- } from "./index-tdbas9r0.js";
7
+ } from "./index-j37qq1f2.js";
8
8
  import {
9
9
  runner,
10
10
  script
11
- } from "./index-8hsbnyes.js";
11
+ } from "./index-kdh76j26.js";
12
12
  import {
13
13
  AGENT_BLOCK_END,
14
14
  AGENT_BLOCK_START,
15
15
  AppExecutor,
16
16
  LibExecutor,
17
+ readDevkitVersion,
17
18
  renderRecipeEntries,
19
+ stampBlockVersion,
18
20
  upsertAgentBlock
19
- } from "./index-hgna5rjy.js";
21
+ } from "./index-z8ptfkzv.js";
20
22
  import {
21
23
  collectRecipeSources,
22
24
  scanRecipes
@@ -103,19 +105,33 @@ ${scopeIndexPointer}
103
105
 
104
106
  `;
105
107
  };
108
+ var renderGuides = async (context) => {
109
+ const conventions = (await Prompter.getInstruction("conventions")).trim();
110
+ if (context.pkgs.some((pkg) => pkg.name === "akanjs"))
111
+ return conventions;
112
+ const onboarding = (await Prompter.getInstruction("workspaceOnboarding")).trim();
113
+ const appName = context.apps[0]?.name ?? "app";
114
+ return `${conventions}
115
+
116
+ ${onboarding.replaceAll("<%= appName %>", appName)}`;
117
+ };
106
118
  var renderManagedBlock = async (workspace) => {
107
119
  const context = await AkanContextAnalyzer.analyze(workspace);
108
120
  const frameworkGuide = await Prompter.getInstruction("framework");
109
121
  const appNames = context.apps.map((app) => app.name);
110
122
  const sampleCleanup = await renderSampleCleanup(workspace, appNames);
111
123
  const recipeIndex = await renderRecipeIndex(workspace);
112
- return `## Workspace
124
+ const guides = await renderGuides(context);
125
+ const version = await readDevkitVersion();
126
+ const block = `## Workspace
113
127
 
114
128
  - Repo: ${context.repoName}
115
129
  - Apps: ${context.apps.map((app) => app.name).join(", ") || "none"}
116
130
  - Libraries: ${context.libs.map((lib) => lib.name).join(", ") || "none"}
117
131
  - Packages: ${context.pkgs.map((pkg) => pkg.name).join(", ") || "none"}
118
132
 
133
+ ${guides}
134
+
119
135
  ${sampleCleanup}## Akan Module Abstracts
120
136
 
121
137
  - Before changing a domain, service, or scalar module, read its \`*.abstract.md\` file first.
@@ -148,7 +164,19 @@ ${context.validationCommands.map((command) => `- \`${command}\``).join(`
148
164
 
149
165
  ## Framework Guide
150
166
 
151
- ${frameworkGuide.trim()}`;
167
+ ${frameworkGuide.trim()}
168
+
169
+ ## Before You Finish
170
+
171
+ 1. \`bun run akan lint <appName>\` \u2014 Tailwind class order, \`Err\`, \`console\`, \`#private\` scope, unused imports.
172
+ 2. \`bun run akan typecheck <appName>\` \u2014 server/client boundary violations.
173
+ 3. \`bun run akan sync <appName>\` if you added, renamed, or deleted any file.
174
+ 4. Did you write or change a \`.tsx\` file? \`bun run akan quality ssr\` \u2014 did the server share hold, and did you add
175
+ a \`"use client"\` you cannot justify?
176
+ 5. Re-read the file you wrote against its section above.
177
+ 6. Did you add a comment? Delete it unless it documents an external constraint or a security decision.
178
+ 7. Did behavior or an invariant change? Update the module's \`*.abstract.md\`.`;
179
+ return version ? stampBlockVersion(block, version) : block;
152
180
  };
153
181
  var renderAgentsMd = async (workspace, existing) => {
154
182
  const block = await renderManagedBlock(workspace);
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-8hsbnyes.js";
5
+ } from "./index-kdh76j26.js";
6
6
  import {
7
7
  PkgExecutor
8
- } from "./index-hgna5rjy.js";
8
+ } from "./index-z8ptfkzv.js";
9
9
  import {
10
10
  TypeScriptDependencyScanner
11
11
  } from "./index-46tjzh6s.js";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  getDirname
4
- } from "./index-hgna5rjy.js";
4
+ } from "./index-1577bej2.js";
5
5
 
6
6
  // pkgs/@akanjs/devkit/prompter.ts
7
7
  import fsPromise from "fs/promises";