@akanjs/cli 3.0.2 → 3.1.0-rc.1

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 (87) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-szbjv4gv.js → CodeAgent-kyprmy06.js} +2 -2
  3. package/{CodeTui-5nw86ab6.js → CodeTui-21mtze3j.js} +1 -1
  4. package/{TunnelShare-cwh9ezsm.js → TunnelShare-q4jq08qg.js} +2 -2
  5. package/{agent.command-np1dffkb.js → agent.command-f3gsc1gd.js} +5 -5
  6. package/akanCode.js +2 -2
  7. package/{application.command-gk69v1xs.js → application.command-5s780vnz.js} +37 -15
  8. package/{applicationBuildRunner-wx09n9g6.js → applicationBuildRunner-1yaqsrdq.js} +115 -103
  9. package/buildBatch.proc.js +16 -5
  10. package/cloud.command-yj6xb2a7.js +192 -0
  11. package/cloud.script-h6pvcpa2.js +20 -0
  12. package/{code.command-hmtx14b2.js → code.command-3wkn4ja5.js} +6 -6
  13. package/commandManifest.json +1 -1
  14. package/{context.command-6aqvdx43.js → context.command-9jjn3gcw.js} +13 -13
  15. package/context.runner-atcrzz5b.js +21 -0
  16. package/{guideline.command-axvf68gc.js → guideline.command-dtczrqpf.js} +2 -2
  17. package/guidelines/agentRule/agentRule.instruction.md +10 -2
  18. package/guidelines/conventions/conventions.instruction.md +70 -25
  19. package/guidelines/cssRule/cssRule.instruction.md +19 -0
  20. package/guidelines/mcpRule/mcpRule.instruction.md +72 -12
  21. package/guidelines/queryRule/queryRule.instruction.md +11 -1
  22. package/guidelines/runtimeRule/runtimeRule.instruction.md +97 -16
  23. package/guidelines/ssrRule/ssrRule.instruction.md +10 -7
  24. package/guidelines/transportRule/transportRule.instruction.md +19 -0
  25. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +6 -6
  26. package/incrementalBuilder.proc.js +24 -3
  27. package/{index-h9ht6s60.js → index-05g3jayg.js} +1 -1
  28. package/{index-jk9xnck6.js → index-1w2qaee2.js} +240 -133
  29. package/{index-g38nhv87.js → index-2etcv0sc.js} +1 -1
  30. package/{index-zyw622y1.js → index-2mx692qq.js} +3 -3
  31. package/{index-50wb2a26.js → index-55mynnqs.js} +354 -129
  32. package/{index-2wc41k5w.js → index-56d2g8ms.js} +2 -2
  33. package/{index-q6ft9fkc.js → index-6jjtnhkw.js} +8 -3
  34. package/index-6w0rbr9d.js +68 -0
  35. package/{index-hxnnfy57.js → index-8ggztp8k.js} +204 -8
  36. package/{index-zwd84m0w.js → index-8r4d7cmt.js} +4 -4
  37. package/{index-j38qkvkk.js → index-ae5pwhgs.js} +12 -10
  38. package/{index-gtjgnv36.js → index-aprt7pkz.js} +6 -9
  39. package/{index-1bjkfvm9.js → index-c1x0be5j.js} +2 -2
  40. package/{index-z750gk1j.js → index-c2yrsxdh.js} +13 -7
  41. package/{index-cb6yc5mb.js → index-c76k723e.js} +2 -2
  42. package/{index-6keyf4sg.js → index-ctanya41.js} +4 -4
  43. package/{index-f4e08ptp.js → index-e0cvze1s.js} +4 -4
  44. package/{index-hp3stk1m.js → index-fm46xrf1.js} +3 -3
  45. package/{index-3xmzr1p1.js → index-gnyf1fqy.js} +2 -2
  46. package/{index-nwd6qzvv.js → index-jx4bzvwg.js} +138 -55
  47. package/{index-jb0hmt3k.js → index-krq7btbt.js} +3 -3
  48. package/{index-94s080qm.js → index-pgj2rt78.js} +139 -1
  49. package/index-q958tqqg.js +77 -0
  50. package/{index-50jjwg8y.js → index-qt22xstj.js} +1 -1
  51. package/index-rc5rwyps.js +201 -0
  52. package/{index-xwprn9nr.js → index-rtct7d43.js} +1 -1
  53. package/{index-bsv901fd.js → index-rwq3ekqc.js} +7 -7
  54. package/{index-1gs9g12n.js → index-v29746vb.js} +4 -4
  55. package/index-ww9bhp67.js +62 -0
  56. package/index.js +22 -21
  57. package/{library.command-9m2rdwwz.js → library.command-gaga5bmq.js} +3 -3
  58. package/{localRegistry.command-kda81jyk.js → localRegistry.command-vsreyy42.js} +9 -9
  59. package/{module.command-q63dffya.js → module.command-7vpf6db4.js} +5 -5
  60. package/{package.command-y2jh0m99.js → package.command-twmvvf69.js} +3 -3
  61. package/package.json +2 -2
  62. package/{page.command-f3e4cwhh.js → page.command-5asq7fdf.js} +3 -3
  63. package/pipeline.command-d0v38572.js +1334 -0
  64. package/{primitive.command-r4kq75qj.js → primitive.command-dyrs2fm8.js} +6 -6
  65. package/projectTypecheck-cvtkrzp2.js +7 -0
  66. package/{quality.command-f7gzh26z.js → quality.command-6emsqpbg.js} +5 -4
  67. package/{repair.command-0qmyr6qa.js → repair.command-8t6aegv5.js} +5 -5
  68. package/{scalar.command-kddn7av4.js → scalar.command-bnggy1x7.js} +4 -4
  69. package/{subspace.command-ft65qvc4.js → subspace.command-md2teygq.js} +158 -91
  70. package/templates/app/env/env.client.type.ts +2 -3
  71. package/templates/app/page/styles.css.template +8 -0
  72. package/templates/appSample/page/task/[taskId]/_index.tsx +2 -2
  73. package/templates/appSample/page/task/[taskId]/edit.tsx +2 -2
  74. package/templates/appSample/page/task/_index.tsx +2 -2
  75. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -2
  76. package/templates/crudPages/[__model__Id]/page.tsx +3 -3
  77. package/templates/crudPages/page.tsx +2 -2
  78. package/templates/crudSinglePage/page.tsx +3 -3
  79. package/templates/lib/cnst.ts +2 -2
  80. package/templates/lib/sig.ts +3 -3
  81. package/{tunnel.command-b3ymdk4f.js → tunnel.command-jx3tdm2d.js} +16 -13
  82. package/{workflow.command-z1srcdfw.js → workflow.command-jx0wag5r.js} +10 -10
  83. package/{workspace.command-vp6vmx3z.js → workspace.command-yxd7rr7g.js} +57 -27
  84. package/cloud.command-tw06613r.js +0 -95
  85. package/cloud.script-64gzba8r.js +0 -20
  86. package/context.runner-hnkvv3z3.js +0 -21
  87. package/index-t91a7339.js +0 -104
@@ -5,13 +5,13 @@ import {
5
5
  writeGeneratedSyncState,
6
6
  createRepairReport,
7
7
  renderRepairReport
8
- } from "./index-h9ht6s60.js";
8
+ } from "./index-05g3jayg.js";
9
9
  import {
10
10
  AkanContextAnalyzer
11
- } from "./index-zyw622y1.js";
11
+ } from "./index-2mx692qq.js";
12
12
  import {
13
13
  runner
14
- } from "./index-q6ft9fkc.js";
14
+ } from "./index-6jjtnhkw.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], {
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-q6ft9fkc.js";
5
+ } from "./index-6jjtnhkw.js";
6
6
  import {
7
7
  FileSys2
8
8
  } from "./index-52w0fvh8.js";
9
9
  import {
10
10
  PkgExecutor
11
- } from "./index-50wb2a26.js";
11
+ } from "./index-55mynnqs.js";
12
12
  import {
13
13
  TypeScriptDependencyScanner2
14
14
  } from "./index-2ahj896a.js";
@@ -39,29 +39,32 @@ import {
39
39
  import {
40
40
  runner,
41
41
  script
42
- } from "./index-q6ft9fkc.js";
42
+ } from "./index-6jjtnhkw.js";
43
43
  import {
44
44
  WorkspaceExecutor,
45
45
  AppExecutor,
46
46
  LibExecutor,
47
47
  PkgExecutor
48
- } from "./index-50wb2a26.js";
48
+ } from "./index-55mynnqs.js";
49
49
  import {
50
50
  DesktopServerStage,
51
- resolveMobileTargets,
52
- resolveAppId,
53
- NativeApp
54
- } from "./index-jk9xnck6.js";
51
+ NativeApp,
52
+ UpdateUploader
53
+ } from "./index-1w2qaee2.js";
55
54
  import {
56
55
  LibraryScript
57
- } from "./index-1bjkfvm9.js";
56
+ } from "./index-c1x0be5j.js";
58
57
  import {
59
58
  stripAnsi
60
59
  } from "./index-7md2g9vw.js";
61
60
  import {
62
61
  SlicePlanner,
63
62
  formatSlicePlan
64
- } from "./index-50jjwg8y.js";
63
+ } from "./index-qt22xstj.js";
64
+ import {
65
+ resolveMobileTargets,
66
+ resolveAppId
67
+ } from "./index-q958tqqg.js";
65
68
  import {
66
69
  openBrowser
67
70
  } from "./index-9dp031by.js";
@@ -1832,7 +1835,7 @@ ${this.#backendStderrTail.join(`
1832
1835
  this.#wakeFromIdle(`${message.type} arrived while suspended`);
1833
1836
  return;
1834
1837
  }
1835
- if (message.type === "build-csr" && this.env.AKAN_DEV_CSR_REBUILD !== "1") {
1838
+ if (message.type === "build-csr" && !message.shell && this.env.AKAN_DEV_CSR_REBUILD !== "1") {
1836
1839
  Object.assign(this.env, { AKAN_DEV_CSR_REBUILD: "1" });
1837
1840
  this.logger.verbose(`[csr] armed dev CSR rebuilds (${message.reason})`);
1838
1841
  }
@@ -1886,7 +1889,7 @@ ${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
1886
1889
 
1887
1890
  // pkgs/@akanjs/cli/application/application.runner.ts
1888
1891
  import { Logger as Logger3 } from "akanjs/common";
1889
- var loadBuildRunner = async () => (await import("./applicationBuildRunner-wx09n9g6.js")).ApplicationBuildRunner;
1892
+ var loadBuildRunner = async () => (await import("./applicationBuildRunner-1yaqsrdq.js")).ApplicationBuildRunner;
1890
1893
  var loadPrompts = async () => await import("@inquirer/prompts");
1891
1894
 
1892
1895
  class ApplicationRunner extends runner("application") {
@@ -2043,6 +2046,18 @@ try {
2043
2046
  async typecheck(app, options = {}) {
2044
2047
  await new (await loadBuildRunner())(app).typecheck(options);
2045
2048
  }
2049
+ async typecheckLibrary(lib, options = {}) {
2050
+ const { ProjectTypecheck } = await import("./projectTypecheck-cvtkrzp2.js");
2051
+ const root = lib.workspace.workspaceRoot;
2052
+ await new ProjectTypecheck(lib.cwdPath, root, { ...process.env, AKAN_WORKSPACE_ROOT: root }).run([
2053
+ "../../server.ts",
2054
+ "../../client.ts",
2055
+ "../../index.ts",
2056
+ "../../page/**/*.ts",
2057
+ "../../page/**/*.tsx",
2058
+ "../../../../pkgs/akanjs/*/types/**/*.d.ts"
2059
+ ], options);
2060
+ }
2046
2061
  async test(exec) {
2047
2062
  const isSignalTarget = exec instanceof AppExecutor || exec instanceof LibExecutor;
2048
2063
  const preloadPath = isSignalTarget ? await resolveSignalTestPreloadPath(exec) : null;
@@ -2062,9 +2077,10 @@ try {
2062
2077
  async build(app, {
2063
2078
  fast = false,
2064
2079
  reporter,
2065
- spinner = false
2080
+ spinner = false,
2081
+ profile
2066
2082
  } = {}) {
2067
- return new (await loadBuildRunner())(app, { fast, reporter }).build({ spinner });
2083
+ return new (await loadBuildRunner())(app, { fast, reporter, profile }).build({ spinner });
2068
2084
  }
2069
2085
  async start(app, {
2070
2086
  open = false,
@@ -2079,7 +2095,15 @@ try {
2079
2095
  setTimeout(() => openBrowser(`http://localhost:${env.AKAN_PUBLIC_CLIENT_PORT ?? env.PORT ?? "8282"}`), 3000);
2080
2096
  return appHost;
2081
2097
  }
2082
- async buildMobile(app, platform, { target, env = "debug", profile = "release", installer = false, arch } = {}) {
2098
+ async buildMobile(app, platform, {
2099
+ target,
2100
+ env = "debug",
2101
+ profile = "release",
2102
+ installer = false,
2103
+ arch,
2104
+ sign = false,
2105
+ notarize = false
2106
+ } = {}) {
2083
2107
  const targets = await resolveMobileTargets(app, target);
2084
2108
  NativeApp.assertInstaller(platform, installer);
2085
2109
  if (arch && platform !== "macos" && platform !== "windows" && platform !== "linux")
@@ -2092,7 +2116,9 @@ try {
2092
2116
  profile,
2093
2117
  ...carried && ApplicationRunner.carriesServer(mobileTarget, platform) ? { server: carried } : {},
2094
2118
  ...installer ? { installer } : {},
2095
- ...arch ? { arch } : {}
2119
+ ...arch ? { arch } : {},
2120
+ sign,
2121
+ notarize
2096
2122
  }));
2097
2123
  });
2098
2124
  }
@@ -2182,20 +2208,26 @@ try {
2182
2208
  if (!mobileTarget || targets.length > 1)
2183
2209
  throw new Error("pack-update packs one native target at a time; pass --target <name>.");
2184
2210
  await this.#buildMobileCsr(app, env);
2185
- const packed = await new NativeApp(app, mobileTarget, env).packUpdate(platform, { out });
2186
- const size = packed.manifest.files.reduce((sum, file) => sum + file.size, 0);
2187
- app.logger.info(`packed ${mobileTarget.name} ${platform} for channel '${packed.channel}' to ${packed.out}: ${packed.manifest.files.length} files, ${(size / 1024).toFixed(0)} KiB, native API ${packed.manifest.nativeApi}`);
2188
- if (!against)
2189
- return;
2190
- const bundle = path5.join(packed.out, "bundle.json");
2191
- const compat = await NativeApp.compareBundles(app.cwdPath, against, bundle);
2192
- await Bun.write(path5.join(packed.out, "compat.json"), `${JSON.stringify({ against, ...compat }, null, 2)}
2211
+ const { pack } = await new NativeApp(app, mobileTarget, env).packUpdate(platform, { out });
2212
+ app.logger.info(`packed ${mobileTarget.name} ${platform} for channel '${pack.channel}' to ${pack.out}: ${pack.files} files, ${(pack.size / 1024).toFixed(0)} KiB, native API ${pack.nativeApi}`);
2213
+ if (against) {
2214
+ const compat = await NativeApp.compareBundles(app.cwdPath, against, path5.join(pack.out, "bundle.json"));
2215
+ pack.compat = { against, ...compat };
2216
+ await Bun.write(path5.join(pack.out, "compat.json"), `${JSON.stringify(pack.compat, null, 2)}
2193
2217
  `);
2194
- if (!compat.compatible)
2195
- throw new Error(`This bundle needs a new store build; the one ${against} came from provides another native API:
2196
- - ${compat.problems.join(`
2218
+ }
2219
+ await NativeApp.writePack(pack);
2220
+ if (!pack.compat)
2221
+ return pack;
2222
+ if (pack.compat.compatible) {
2223
+ app.logger.info(`runs in the store build of ${against}`);
2224
+ return pack;
2225
+ }
2226
+ app.logger.error(`This bundle needs a new store build; it differs from the one ${against} came from:
2227
+ - ${pack.compat.problems.join(`
2197
2228
  - `)}`);
2198
- app.logger.info(`runs in the store build of ${against}`);
2229
+ process.exitCode = 2;
2230
+ return pack;
2199
2231
  }
2200
2232
  async updateKeygen(app, platform, target) {
2201
2233
  const nativePlatform = platform === "desktop" ? NativeApp.desktopPlatform() : platform;
@@ -2207,30 +2239,47 @@ try {
2207
2239
  seen.add(appId);
2208
2240
  const { publicKey, keyPath, created } = await new NativeApp(app, mobileTarget).updateKeygen(nativePlatform);
2209
2241
  app.log(`${appId}: ${created ? "made" : "read"} ${keyPath}${created ? " (keep it private and backed up: without it, installed apps take no more updates)" : ""}`);
2210
- app.log(` native: { updates: { url: "https://\u2026/${app.name}", publicKey: ${JSON.stringify(publicKey)} } }`);
2211
- const declared = mobileTarget.config.updates?.publicKey;
2212
- if (declared && declared !== publicKey)
2213
- app.logger.warn(`native.targets.${mobileTarget.name}.updates.publicKey is another key's; releases would not verify.`);
2242
+ app.log(` native: { updates: { url: "https://\u2026/${app.name}", publicKeys: [${JSON.stringify(publicKey)}] } }`);
2243
+ const { publicKey: one, publicKeys } = mobileTarget.config.updates ?? {};
2244
+ const declared = publicKeys ?? (one ? [one] : null);
2245
+ if (declared && !declared.includes(publicKey))
2246
+ app.logger.warn(`native.targets.${mobileTarget.name}.updates.publicKeys does not hold this key; releases it signs would not verify.`);
2214
2247
  }
2215
2248
  }
2216
- async publishUpdate(app, platform, { target, env = "main", channel } = {}) {
2249
+ async publishUpdate(app, platform, { target, env = "main", channel, upload, arch, sign = false, notarize = false } = {}) {
2250
+ if (arch && platform !== "desktop")
2251
+ throw new Error(`--arch picks a desktop release's CPU; ${platform} publishes its web bundle.`);
2217
2252
  const targets = await resolveMobileTargets(app, target);
2253
+ if (upload && targets.length > 1)
2254
+ throw new Error(`--upload takes one target's release; name it with --target (${targets.map(({ name }) => name).join(", ")}).`);
2255
+ const uploader = upload ? UpdateUploader.forTarget(upload) : null;
2218
2256
  const nativePlatform = platform === "desktop" ? NativeApp.desktopPlatform() : platform;
2257
+ if (arch === "x64" && nativePlatform === "macos")
2258
+ throw new Error("A macOS app is built for Apple silicon (arm64) only.");
2219
2259
  for (const mobileTarget of targets)
2220
2260
  await new NativeApp(app, mobileTarget, env).assertPublishable(nativePlatform, {
2221
2261
  server: ApplicationRunner.carriesServer(mobileTarget, nativePlatform),
2222
- ...channel ? { channel } : {}
2262
+ ...channel ? { channel } : {},
2263
+ ...arch ? { arch } : {}
2223
2264
  });
2224
- const carried = await this.#stageMobile(app, nativePlatform, targets, env);
2265
+ const carried = await this.#stageMobile(app, nativePlatform, targets, env, arch);
2225
2266
  for (const mobileTarget of targets) {
2226
2267
  const nativeApp = new NativeApp(app, mobileTarget, env);
2227
2268
  const published = await nativeApp.publishUpdate(nativePlatform, {
2228
2269
  ...channel ? { channel } : {},
2270
+ ...arch ? { arch } : {},
2271
+ sign,
2272
+ notarize,
2229
2273
  ...carried && ApplicationRunner.carriesServer(mobileTarget, nativePlatform) ? { server: carried } : {}
2230
2274
  });
2231
2275
  this.#reportBuild(app, mobileTarget, published.build);
2232
2276
  app.log(`${app.name}/${mobileTarget.name} ${published.bundle}: ${published.dir}/${published.channel}.json, ${published.files} files, ${Math.round(published.size / 1024)} KiB`);
2233
- app.log(`Upload ${nativeApp.updatesDir} to ${mobileTarget.config.updates?.url}, the manifests last.`);
2277
+ if (!uploader) {
2278
+ app.log(`Upload ${nativeApp.updatesDir} to ${mobileTarget.config.updates?.url}, the manifests last.`);
2279
+ continue;
2280
+ }
2281
+ const { uploaded, skipped } = await uploader.upload(nativeApp.updatesDir);
2282
+ app.log(`Uploaded ${uploaded} file(s) to ${upload}, the manifests last; ${skipped} the bucket already held. Installed apps read ${mobileTarget.config.updates?.url}.`);
2234
2283
  }
2235
2284
  }
2236
2285
  #reportBuild(app, mobileTarget, { artifacts, warnings, signing }) {
@@ -2244,24 +2293,45 @@ try {
2244
2293
  static carriesServer({ config }, platform = NativeApp.desktopPlatform()) {
2245
2294
  return platform !== "ios" && platform !== "android" && !!config.desktop?.server;
2246
2295
  }
2247
- static serverOmit(targets, platform) {
2296
+ static carriedServer(targets, platform) {
2248
2297
  const carrying = targets.filter((target) => ApplicationRunner.carriesServer(target, platform));
2249
- const omits = carrying.map(({ config }) => {
2298
+ const servers = carrying.map(({ config }) => {
2250
2299
  const server = config.desktop?.server;
2251
- return typeof server === "object" ? server.omit ?? [] : [];
2300
+ if (typeof server !== "object")
2301
+ return { omit: [], modules: [] };
2302
+ const { omit = [], modules = [], profile, env, restart, watchdog } = server;
2303
+ return {
2304
+ omit,
2305
+ modules,
2306
+ ...profile ? { profile } : {},
2307
+ ...env ? { env } : {},
2308
+ ...restart !== undefined ? { restart } : {},
2309
+ ...typeof watchdog === "object" ? { watchdog } : {}
2310
+ };
2252
2311
  });
2253
- const [first = [], ...rest] = omits;
2254
- if (rest.some((omit) => omit.join("\x00") !== first.join("\x00")))
2255
- throw new Error(`The targets that carry the server omit different packages (${carrying.map(({ name }, idx) => `${name}: ${omits[idx]?.join(", ") || "none"}`).join("; ")}); build them one --target at a time.`);
2312
+ const [first = { omit: [], modules: [] }, ...rest] = servers;
2313
+ const agree = (what, of) => {
2314
+ if (rest.every((server) => of(server) === of(first)))
2315
+ return;
2316
+ throw new Error(`The targets that carry the server ${what} (${carrying.map(({ name }, idx) => `${name}: ${servers[idx] && of(servers[idx]) || "none"}`).join("; ")}); build them one --target at a time.`);
2317
+ };
2318
+ agree("omit different packages", ({ omit }) => omit.join(", "));
2319
+ agree("name different env profiles", ({ profile }) => profile ?? "");
2320
+ agree("mount different modules", ({ modules }) => modules.join(", "));
2321
+ agree("set a different env", ({ env }) => env ? JSON.stringify(env) : "");
2322
+ agree("restart differently", ({ restart }) => String(restart ?? ""));
2323
+ agree("watch it differently", ({ watchdog }) => watchdog ? JSON.stringify(watchdog) : "");
2256
2324
  return first;
2257
2325
  }
2258
2326
  async#stageMobile(app, platform, targets, env, arch) {
2259
2327
  const stage = targets.some((mobileTarget) => ApplicationRunner.carriesServer(mobileTarget, platform)) ? new DesktopServerStage(app) : null;
2260
- await stage?.install(arch, ApplicationRunner.serverOmit(targets, platform));
2261
- await this.#buildMobileCsr(app, env);
2262
- return await stage?.prepare(env);
2328
+ const server = ApplicationRunner.carriedServer(targets, platform);
2329
+ await stage?.install(arch, server.omit);
2330
+ await this.#buildMobileCsr(app, env, stage ? server.profile : undefined);
2331
+ const { modules, env: serverEnv, restart, watchdog } = server;
2332
+ return await stage?.prepare(env, { modules, env: serverEnv, restart, watchdog });
2263
2333
  }
2264
- async#buildMobileCsr(app, env) {
2334
+ async#buildMobileCsr(app, env, profile) {
2265
2335
  const prevEnv = {
2266
2336
  AKAN_PUBLIC_ENV: process.env.AKAN_PUBLIC_ENV,
2267
2337
  AKAN_PUBLIC_OPERATION_MODE: process.env.AKAN_PUBLIC_OPERATION_MODE,
@@ -2273,7 +2343,7 @@ try {
2273
2343
  APP_OPERATION_MODE: "release"
2274
2344
  });
2275
2345
  try {
2276
- await new (await loadBuildRunner())(app, { environment: env }).build({ spinner: true });
2346
+ await new (await loadBuildRunner())(app, { environment: env, profile }).build({ spinner: true });
2277
2347
  } finally {
2278
2348
  for (const [key, value] of Object.entries(prevEnv)) {
2279
2349
  if (value === undefined)
@@ -3232,12 +3302,17 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3232
3302
  async logs(app, options) {
3233
3303
  await this.applicationRunner.runLogs(app, options);
3234
3304
  }
3235
- async build(app, { write = true, fast = false, quiet = false } = {}) {
3305
+ async build(app, {
3306
+ write = true,
3307
+ fast = false,
3308
+ quiet = false,
3309
+ profile
3310
+ } = {}) {
3236
3311
  await app.scanSync({ write });
3237
3312
  if (!quiet)
3238
3313
  Logger6.rawLog(`Creating an optimized production build for ${app.name}...`);
3239
3314
  try {
3240
- const result = await this.applicationRunner.build(app, { fast, spinner: !quiet });
3315
+ const result = await this.applicationRunner.build(app, { fast, spinner: !quiet, profile });
3241
3316
  Logger6.rawLog(`${app.name} built in dist/apps/${app.name}`);
3242
3317
  if (!quiet)
3243
3318
  ApplicationBuildReporter.printSummary(result);
@@ -3247,14 +3322,22 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3247
3322
  throw error;
3248
3323
  }
3249
3324
  }
3250
- async typecheck(app, { write = true, clean = false, incremental = true } = {}) {
3251
- await app.scanSync({ write });
3252
- const spinner = app.spinning(`Typechecking ${app.name}...`);
3325
+ async typecheck(exec, { write = true, clean = false, incremental = true, tests = false } = {}) {
3326
+ if (!(exec instanceof AppExecutor) && !(exec instanceof LibExecutor))
3327
+ throw new Error(`akan typecheck takes an app or a library; ${exec.name} is a package, checked by its own tsconfig.`);
3328
+ if (exec instanceof LibExecutor)
3329
+ await this.libraryScript.syncLibrary(exec);
3330
+ else
3331
+ await exec.scanSync({ write });
3332
+ const spinner = exec.spinning(`Typechecking ${exec.name}${tests ? " with its tests" : ""}...`);
3253
3333
  try {
3254
- await this.applicationRunner.typecheck(app, { clean, incremental });
3255
- spinner.succeed(`${app.name} typechecked`);
3334
+ if (exec instanceof LibExecutor)
3335
+ await this.applicationRunner.typecheckLibrary(exec, { clean, incremental, tests });
3336
+ else
3337
+ await this.applicationRunner.typecheck(exec, { clean, incremental, tests });
3338
+ spinner.succeed(`${exec.name} typechecked`);
3256
3339
  } catch (error) {
3257
- spinner.fail(`${app.name} typecheck failed`);
3340
+ spinner.fail(`${exec.name} typecheck failed`);
3258
3341
  Logger6.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
3259
3342
  throw error;
3260
3343
  }
@@ -3456,7 +3539,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3456
3539
  } = {}) {
3457
3540
  await app.scanSync({ write });
3458
3541
  ApplicationScript.#assertReleaseEnv("packUpdate", options.env ?? "main", allowLocalRelease);
3459
- await this.applicationRunner.packUpdate(app, platform, options);
3542
+ return await this.applicationRunner.packUpdate(app, platform, options);
3460
3543
  }
3461
3544
  async updateKeygen(app, platform, { target } = {}) {
3462
3545
  await this.applicationRunner.updateKeygen(app, platform, target);
@@ -3510,7 +3593,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3510
3593
  await Promise.all(shares.map(async (share) => await share.close()));
3511
3594
  }, "Abandoning the tunnel release; the shares expire on their own.");
3512
3595
  await Promise.all(apps.map(async (app) => {
3513
- const { TunnelShare } = await import("./TunnelShare-cwh9ezsm.js");
3596
+ const { TunnelShare } = await import("./TunnelShare-q4jq08qg.js");
3514
3597
  const share = await TunnelShare.open(app, { workspace: app.workspace });
3515
3598
  shares.push(share);
3516
3599
  urls.set(app.name, share.url);
@@ -4,7 +4,7 @@ import {
4
4
  akanCodePaths2,
5
5
  McpServerConfig,
6
6
  McpSignIn
7
- } from "./index-xwprn9nr.js";
7
+ } from "./index-rtct7d43.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-hnkvv3z3.js");
514
+ const { ContextRunner } = await import("./context.runner-atcrzz5b.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-hnkvv3z3.js");
522
+ const { ContextRunner } = await import("./context.runner-atcrzz5b.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 })) {
@@ -52,6 +52,11 @@ class GlobalConfig {
52
52
  await GlobalConfig.#setAkanGlobalConfig(mutate(await GlobalConfig.#getAkanGlobalConfig()));
53
53
  });
54
54
  }
55
+ static async hostFor(workspace, host) {
56
+ if (host)
57
+ return host;
58
+ return (await workspace.getConfig()).cloudHost ?? GlobalConfig.akanCloudHost;
59
+ }
55
60
  static async getHostConfig(host = GlobalConfig.akanCloudHost) {
56
61
  const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
57
62
  return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? getDefaultHostConfig(host));
@@ -197,6 +202,10 @@ class HttpClient {
197
202
  }
198
203
 
199
204
  class CloudApi {
205
+ static statusOf(error) {
206
+ const status = Number(/(?:^|: )(\d{3}) /.exec(error instanceof Error ? error.message : String(error))?.[1]);
207
+ return Number.isNaN(status) ? null : status;
208
+ }
200
209
  #api;
201
210
  #accessToken = null;
202
211
  #workspace;
@@ -231,6 +240,36 @@ class CloudApi {
231
240
  formData.append("file", file);
232
241
  return await this.#api.post(`/uploadEnv/${devProjectId}`, formData);
233
242
  }
243
+ async uploadSecret(devProjectId, secret) {
244
+ return await this.#api.post(`/uploadSecret/${encodeURIComponent(devProjectId)}`, secret);
245
+ }
246
+ async listSecrets(devProjectId) {
247
+ return await this.#api.get(`/listSecrets/${encodeURIComponent(devProjectId)}`);
248
+ }
249
+ async removeSecret(devProjectId, secret) {
250
+ return await this.#api.post(`/removeSecret/${encodeURIComponent(devProjectId)}`, secret);
251
+ }
252
+ async requestUpdateUpload(devProjectId, upload) {
253
+ return await this.#api.post(`/requestUpdateUpload/${encodeURIComponent(devProjectId)}`, upload);
254
+ }
255
+ async commitUpdateUpload(devProjectId, uploadId) {
256
+ return await this.#api.post(`/commitUpdateUpload/${encodeURIComponent(devProjectId)}`, { uploadId }, { signal: AbortSignal.timeout(11 * 60000) });
257
+ }
258
+ async registerAppBinary(devProjectId, binary) {
259
+ const formData = new FormData;
260
+ for (const key of ["appName", "target", "distribution"])
261
+ formData.append(key, binary[key]);
262
+ if (binary.channel)
263
+ formData.append("channel", binary.channel);
264
+ formData.append("bundle", binary.bundle, "bundle.json");
265
+ if (binary.packUploadId)
266
+ formData.append("packUploadId", binary.packUploadId);
267
+ if (binary.pack)
268
+ formData.append("pack", binary.pack, "pack.tgz");
269
+ return await this.#api.post(`/registerAppBinary/${encodeURIComponent(devProjectId)}`, formData, {
270
+ signal: AbortSignal.timeout(11 * 60000)
271
+ });
272
+ }
234
273
  async downloadEnv(devProjectId) {
235
274
  const localPath = `${this.#workspace.workspaceRoot}/local/env.tar`;
236
275
  await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
@@ -263,4 +302,103 @@ class CloudApi {
263
302
  }
264
303
  }
265
304
  }
266
- export { getDefaultHostConfig, GlobalConfig, CloudApi };
305
+ // pkgs/@akanjs/devkit/cloud/updatePackUpload.ts
306
+ import { Logger, sleep } from "akanjs/common";
307
+ class UpdatePackUpload {
308
+ static maxBytes = 200 * 1024 * 1024;
309
+ static #transientPut = new Set([0, 408, 429, 500, 502, 503, 504]);
310
+ #api;
311
+ #devProjectId;
312
+ #putRetryMs;
313
+ #commitRetryMs;
314
+ #cutOffWindowMs;
315
+ #commitLimitMs;
316
+ constructor(api, devProjectId, {
317
+ putRetryMs = 1000,
318
+ commitRetryMs = 1e4,
319
+ cutOffWindowMs = 15 * 60000,
320
+ commitLimitMs = 60 * 60000
321
+ } = {}) {
322
+ this.#api = api;
323
+ this.#devProjectId = devProjectId;
324
+ this.#putRetryMs = putRetryMs;
325
+ this.#commitRetryMs = commitRetryMs;
326
+ this.#cutOffWindowMs = cutOffWindowMs;
327
+ this.#commitLimitMs = commitLimitMs;
328
+ }
329
+ async send(archive, fields) {
330
+ const uploadId = await this.stage(archive, fields);
331
+ return await this.settle(() => this.#api.commitUpdateUpload(this.#devProjectId, uploadId));
332
+ }
333
+ async stage(archive, fields) {
334
+ const file = Bun.file(archive);
335
+ if (file.size < 1 || file.size > UpdatePackUpload.maxBytes)
336
+ throw new Error(`The pack archive is ${file.size} bytes; a project takes 1 byte to 200 MiB.`);
337
+ const hasher = new Bun.CryptoHasher("sha256");
338
+ for await (const chunk of file.stream())
339
+ hasher.update(chunk);
340
+ const upload = { ...fields, size: file.size, sha256: hasher.digest("hex") };
341
+ for (let ticket = 1;; ticket++) {
342
+ const { uploadId, uploadUrl, contentType } = await this.#request(upload);
343
+ const status = await this.#put(uploadUrl, contentType, file);
344
+ if (status >= 200 && status < 300)
345
+ return uploadId;
346
+ if (status !== 403 || ticket === 2)
347
+ throw new Error(`The storage refused the pack upload (${status ? `HTTP ${status}` : "no response"}).`);
348
+ }
349
+ }
350
+ async#request(upload) {
351
+ return await this.#api.requestUpdateUpload(this.#devProjectId, upload).catch((error) => {
352
+ const message = error instanceof Error ? error.message : String(error);
353
+ if (CloudApi.statusOf(error) === 404 && !/"error"\s*:\s*"[\w$-]+\.error\.[\w$-]+"/.test(message))
354
+ throw new Error("The project's server does not take direct pack uploads yet: update akasys and try again, or upload the pack from the project's release screen.");
355
+ throw error;
356
+ });
357
+ }
358
+ async#put(url, contentType, file) {
359
+ for (let retry = 0;; retry++) {
360
+ const status = await fetch(url, { method: "PUT", body: file, headers: { "Content-Type": contentType } }).then(async (response) => {
361
+ await response.arrayBuffer().catch(() => {
362
+ return;
363
+ });
364
+ return response.status;
365
+ }).catch(() => 0);
366
+ if (retry === 3 || !UpdatePackUpload.#transientPut.has(status))
367
+ return status;
368
+ await sleep(this.#putRetryMs * (retry + 1));
369
+ }
370
+ }
371
+ async settle(call) {
372
+ const limit = performance.now() + this.#commitLimitMs;
373
+ let cutOffSince = null;
374
+ for (;; ) {
375
+ try {
376
+ return await call();
377
+ } catch (error) {
378
+ const now = performance.now();
379
+ if (UpdatePackUpload.#inProgress(error))
380
+ cutOffSince = null;
381
+ else if (UpdatePackUpload.#cutOff(error))
382
+ cutOffSince ??= now;
383
+ else
384
+ throw error;
385
+ const deadline = cutOffSince === null ? limit : Math.min(limit, cutOffSince + this.#cutOffWindowMs);
386
+ if (now + this.#commitRetryMs > deadline)
387
+ throw error;
388
+ Logger.rawLog(`The project is still taking the pack; asking again in ${Math.round(this.#commitRetryMs / 1000)}s.`);
389
+ await sleep(this.#commitRetryMs);
390
+ }
391
+ }
392
+ }
393
+ static #inProgress(error) {
394
+ const message = error instanceof Error ? error.message : String(error);
395
+ return CloudApi.statusOf(error) === 409 && message.includes("uploadCommitInProgress");
396
+ }
397
+ static #cutOff(error) {
398
+ const status = CloudApi.statusOf(error);
399
+ if (status === null)
400
+ return !(error instanceof SyntaxError);
401
+ return status === 502 || status === 504 || status >= 520 && status <= 527;
402
+ }
403
+ }
404
+ export { getDefaultHostConfig, GlobalConfig, CloudApi, UpdatePackUpload };
@@ -0,0 +1,77 @@
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.native.targets).map(([name, target]) => ({ name, config: target }));
7
+ };
8
+ var isTemplateOnly = ({ basePaths, native }) => basePaths.size > 0 && Object.values(native.targets).every((target) => !target.basePath);
9
+ var getMobileTargetChoices = async (app) => {
10
+ const config = await app.getConfig();
11
+ const targetNames = Object.keys(config.native.targets);
12
+ if (targetNames.length > 0 && !isTemplateOnly(config))
13
+ return targetNames;
14
+ return [...config.basePaths];
15
+ };
16
+ var resolveMobileTargetByBasePath = (targets, basePath) => {
17
+ const normalizedBasePath = trimSlashes(basePath);
18
+ const byBasePath = targets.find(({ config }) => config.basePath !== undefined && trimSlashes(config.basePath) === normalizedBasePath);
19
+ if (byBasePath)
20
+ return byBasePath;
21
+ const [template] = targets;
22
+ if (!template)
23
+ return;
24
+ return {
25
+ name: normalizedBasePath,
26
+ config: { ...template.config, name: normalizedBasePath, basePath: normalizedBasePath }
27
+ };
28
+ };
29
+ var resolveMobileTargets = async (app, selection) => {
30
+ const config = await app.getConfig();
31
+ const targets = await getMobileTargets(app);
32
+ if (targets.length === 0)
33
+ throw new Error(`No native targets configured for ${app.name}`);
34
+ if (!selection && targets.length === 1 && !isTemplateOnly(config))
35
+ return targets;
36
+ if (!selection) {
37
+ const choices = await getMobileTargetChoices(app);
38
+ if (choices.length === 1)
39
+ return resolveMobileTargets(app, choices[0]);
40
+ throw new Error(`Multiple native targets found for ${app.name}. Pass --target <${choices.join("|")}|all>.`);
41
+ }
42
+ if (selection === "all") {
43
+ if (Object.keys(config.native.targets).length > 1)
44
+ return targets;
45
+ const basePaths = [...config.basePaths];
46
+ if (basePaths.length > 1 || isTemplateOnly(config)) {
47
+ return basePaths.flatMap((basePath) => {
48
+ const resolved = resolveMobileTargetByBasePath(targets, basePath);
49
+ return resolved ? [resolved] : [];
50
+ });
51
+ }
52
+ return targets;
53
+ }
54
+ const target = targets.find((candidate) => candidate.name === selection);
55
+ if (target)
56
+ return [target];
57
+ const basePathTarget = resolveMobileTargetByBasePath(targets, selection);
58
+ if (basePathTarget && config.basePaths.has(trimSlashes(selection)))
59
+ return [basePathTarget];
60
+ const choices = await getMobileTargetChoices(app);
61
+ throw new Error(`Native target '${selection}' was not found. Available: ${choices.join(", ")}`);
62
+ };
63
+ var resolveAppId = (appId, platform) => {
64
+ if (typeof appId === "string")
65
+ return appId;
66
+ const id = appId[platform] ?? appId.default;
67
+ if (!id)
68
+ throw new Error(`native.appId names no id for ${platform}; give it ${platform} or default.`);
69
+ return id;
70
+ };
71
+ var appIdsOf = (appId) => typeof appId === "string" ? [appId] : Object.values(appId).filter((id) => !!id);
72
+ var targetHtmlFilename = (target) => {
73
+ const basePath = trimSlashes(target.basePath ?? "");
74
+ return basePath ? `${basePath}.html` : "index.html";
75
+ };
76
+
77
+ export { getMobileTargets, getMobileTargetChoices, resolveMobileTargets, resolveAppId, appIdsOf, targetHtmlFilename };
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  AppInfo
4
- } from "./index-50wb2a26.js";
4
+ } from "./index-55mynnqs.js";
5
5
 
6
6
  // pkgs/@akanjs/devkit/slicePlanner.ts
7
7
  class SlicePlanner {