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

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 (88) hide show
  1. package/.build-stamp +1 -1
  2. package/{agent.command-yv00p0s0.js → agent.command-a3n15c6t.js} +7 -6
  3. package/{application.command-0qsczf4k.js → application.command-rdm3et0g.js} +5 -4
  4. package/{applicationBuildRunner-ct2pxyvw.js → applicationBuildRunner-6m8n71w4.js} +3 -3
  5. package/buildBatch.proc.js +4 -3
  6. package/{capacitorApp-4r9sm3qg.js → capacitorApp-mr81qdxq.js} +5 -2
  7. package/{cloud.command-dxfv18sa.js → cloud.command-56aeekqn.js} +8 -7
  8. package/{context.command-8d9e3k6b.js → context.command-ysxawe7h.js} +14 -13
  9. package/getDirname-m9s0cmhq.js +8 -0
  10. package/{guideline.command-3jbkxzh6.js → guideline.command-yqf9a372.js} +5 -4
  11. package/guidelines/conventions/conventions.generate.json +25 -0
  12. package/guidelines/conventions/conventions.instruction.md +825 -0
  13. package/guidelines/cssRule/cssRule.instruction.md +7 -0
  14. package/guidelines/framework/framework.instruction.md +1 -0
  15. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +24 -0
  16. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +974 -0
  17. package/incrementalBuilder.proc.js +3 -2
  18. package/index-1577bej2.js +7 -0
  19. package/{index-1pvex4az.js → index-3789fdpg.js} +13 -13
  20. package/{index-ec09pws3.js → index-4mgkgba3.js} +3 -3
  21. package/{index-bbkek1bp.js → index-65aeh789.js} +1 -1
  22. package/{index-7c6k4yvg.js → index-8pd02prk.js} +2 -2
  23. package/{index-t3723f99.js → index-9va8zayb.js} +86 -17
  24. package/{index-nm6wghb6.js → index-a5cs7d8r.js} +5 -5
  25. package/{index-e16gnn26.js → index-bzznxgcx.js} +7 -7
  26. package/{index-pyt2b4nw.js → index-cav1azma.js} +103 -22
  27. package/{index-2q1f5j9k.js → index-cv9cxs5k.js} +3 -3
  28. package/{index-a00jg8x8.js → index-e4b2ae6b.js} +49 -32
  29. package/{index-8hsbnyes.js → index-etwh7sd3.js} +4 -2
  30. package/{index-k95xkh4p.js → index-h5whaj26.js} +2 -2
  31. package/{index-tdbas9r0.js → index-j37qq1f2.js} +1 -1
  32. package/{index-rh16j3c7.js → index-j9cxndc0.js} +3 -2
  33. package/{index-rzwcpcc3.js → index-kcsa1zff.js} +1 -1
  34. package/{index-bekddz9q.js → index-m90fn8xe.js} +4 -4
  35. package/{index-yzmhasdb.js → index-mewacxye.js} +7 -7
  36. package/{index-zasydjxd.js → index-nwqqssnb.js} +8 -10
  37. package/{index-mr5s7mqd.js → index-yzmqvg23.js} +3 -3
  38. package/{index-hgna5rjy.js → index-yzsxc30b.js} +94 -47
  39. package/{index-ej426mcr.js → index-z1s5f4e0.js} +34 -6
  40. package/index.js +19 -18
  41. package/{library.command-ebdj1vnm.js → library.command-x6t29a30.js} +4 -3
  42. package/{localRegistry.command-gb178ne8.js → localRegistry.command-649g1n7b.js} +7 -6
  43. package/{module.command-9c1bnsx4.js → module.command-8w8ys5t3.js} +7 -6
  44. package/{package.command-t93p4jkj.js → package.command-zgy7f3fz.js} +4 -3
  45. package/package.json +2 -2
  46. package/{page.command-k3k0meh2.js → page.command-yjmnkyk2.js} +4 -3
  47. package/{primitive.command-de6nktdt.js → primitive.command-gfqaagsg.js} +8 -7
  48. package/{quality.command-z5kth2wa.js → quality.command-ec8r1dn3.js} +369 -128
  49. package/{repair.command-ehf2g112.js → repair.command-p9ey6mkm.js} +6 -5
  50. package/{routeSourceValidator-cncd92fv.js → routeSourceValidator-e4jmbfcx.js} +2 -38
  51. package/{scalar.command-7a2jtv33.js → scalar.command-9dhmqhtm.js} +6 -5
  52. package/templates/app/page/styles.css.template +3 -3
  53. package/templates/appSample/srvkit/AuthGuard.ts +9 -5
  54. package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
  55. package/templates/crudPages/[__model__Id]/edit/page.tsx +1 -1
  56. package/templates/crudPages/new/page.tsx +1 -1
  57. package/templates/crudSinglePage/page.tsx +1 -1
  58. package/templates/lib/db.ts +3 -1
  59. package/templates/lib/useClient.ts +9 -3
  60. package/templates/module/__Model__.Util.tsx +1 -1
  61. package/templates/module/__Model__.Zone.tsx +3 -5
  62. package/templates/workspaceRoot/AGENTS.md.template +0 -948
  63. package/templates/workspaceRoot/biome.json.template +4 -198
  64. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +4 -1
  65. package/{workflow.command-e0tt0vk2.js → workflow.command-ycwc6zr6.js} +13 -12
  66. package/{workspace.command-fpda0evj.js → workspace.command-xhyhajxa.js} +67 -48
  67. package/templates/libRoot/base/baseLogic.ts +0 -14
  68. package/templates/libRoot/base/index.ts +0 -8
  69. package/templates/workspaceRoot/.cursor/rules/akan-page-routing.mdc.template +0 -43
  70. package/templates/workspaceRoot/.cursor/rules/akan-sync-conventions.mdc.template +0 -33
  71. package/templates/workspaceRoot/.cursor/rules/application-test-commands.mdc.template +0 -16
  72. package/templates/workspaceRoot/.cursor/rules/change-scope.mdc.template +0 -12
  73. package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +0 -18
  74. package/templates/workspaceRoot/.cursor/rules/coding-comments.mdc.template +0 -25
  75. package/templates/workspaceRoot/.cursor/rules/coding-style.mdc.template +0 -44
  76. package/templates/workspaceRoot/.cursor/rules/domain-module-conventions.mdc.template +0 -17
  77. package/templates/workspaceRoot/.cursor/rules/format-lint.mdc.template +0 -12
  78. package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +0 -18
  79. package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +0 -61
  80. package/templates/workspaceRoot/.cursor/rules/naming-conventions.mdc.template +0 -15
  81. package/templates/workspaceRoot/.cursor/rules/react-component-style.mdc.template +0 -21
  82. package/templates/workspaceRoot/.cursor/rules/repo-overview.mdc.template +0 -17
  83. package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +0 -58
  84. package/templates/workspaceRoot/.cursor/rules/secrets-and-env.mdc.template +0 -13
  85. package/templates/workspaceRoot/.cursor/rules/service-signal-conventions.mdc.template +0 -83
  86. package/templates/workspaceRoot/.cursor/rules/srvkit-adapters-and-guards.mdc.template +0 -50
  87. package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +0 -59
  88. package/templates/workspaceRoot/.cursor/rules/typescript-imports.mdc.template +0 -16
@@ -9,7 +9,7 @@ import {
9
9
  createTsconfigPackageResolver,
10
10
  rewriteBarrelImports,
11
11
  transformUseClient
12
- } from "./index-rh16j3c7.js";
12
+ } from "./index-j9cxndc0.js";
13
13
  import {
14
14
  __require
15
15
  } from "./index-r24hmh0q.js";
@@ -415,11 +415,21 @@ class AllRoutesBuilder {
415
415
  const seedIndex = computeRouteSeedIndex(pageEntries);
416
416
  this.#app.verbose(`[build-all] discovered ${seedIndex.entries.length} routes`);
417
417
  this.#discovery = await GraphClientEntryDiscovery.create(this.#app);
418
+ const allEntries = [];
419
+ const seen = new Set;
418
420
  for (const entry of seedIndex.entries) {
419
421
  const seeds = Array.from(new Set([...seedIndex.globalLayoutFiles, ...entry.seeds]));
420
- const delta = await this.#buildRoute(entry.routeId, seeds);
421
- this.#mergeRoute(entry.routeId, delta);
422
+ for (const discovered of await this.#discovery.discover(seeds)) {
423
+ if (seen.has(discovered))
424
+ continue;
425
+ seen.add(discovered);
426
+ allEntries.push(discovered);
427
+ }
428
+ this.#routeIds.push(entry.routeId);
422
429
  }
430
+ this.#app.verbose(`[build-all] ${allEntries.length} client entries across ${this.#routeIds.length} routes`);
431
+ const delta = await this.#buildEntries(allEntries);
432
+ this.#mergeDelta(delta);
423
433
  this.#merged.knownEntries = Array.from(this.#knownSet);
424
434
  const manifest = {
425
435
  routeIds: this.#routeIds,
@@ -433,23 +443,30 @@ class AllRoutesBuilder {
433
443
  this.#app.verbose(`[build-all] wrote ${manifestPath} routes=${this.#routeIds.length} entries=${this.#merged.knownEntries.length}`);
434
444
  return { manifest, manifestPath, seedIndex };
435
445
  }
436
- async#buildRoute(routeId, seeds) {
446
+ async#buildEntries(entries) {
437
447
  if (!this.#discovery)
438
448
  throw new Error("[build-all] client entry discovery is not initialized");
449
+ if (entries.length === 0)
450
+ return {
451
+ manifestDelta: {},
452
+ ssrManifestDelta: { moduleLoading: null, moduleMap: {} },
453
+ newEntries: [],
454
+ clientDeps: []
455
+ };
439
456
  const started = Date.now();
440
457
  const delta = await new RouteClientBuilder({
441
458
  app: this.#app,
442
- routeId,
443
- seeds,
459
+ seeds: [],
460
+ entries,
444
461
  artifact: this.#artifact,
445
462
  knownEntries: this.#knownSet,
446
463
  discovery: this.#discovery,
447
464
  command: this.#command
448
465
  }).build();
449
- this.#app.verbose(`[build-all] ${routeId} +${delta.newEntries.length} entries (${Date.now() - started}ms)`);
466
+ this.#app.verbose(`[build-all] bundled ${delta.newEntries.length} entries (${Date.now() - started}ms)`);
450
467
  return delta;
451
468
  }
452
- #mergeRoute(routeId, delta) {
469
+ #mergeDelta(delta) {
453
470
  for (const [key, row] of Object.entries(delta.manifestDelta))
454
471
  this.#merged.clientManifest[key] = row;
455
472
  for (const [url, byName] of Object.entries(delta.ssrManifestDelta.moduleMap)) {
@@ -457,7 +474,6 @@ class AllRoutesBuilder {
457
474
  }
458
475
  for (const abs of delta.newEntries)
459
476
  this.#knownSet.add(abs);
460
- this.#routeIds.push(routeId);
461
477
  }
462
478
  }
463
479
 
@@ -794,10 +810,10 @@ import { compile } from "tailwindcss";
794
810
 
795
811
  // pkgs/@akanjs/devkit/frontendBuild/cssCandidateCache.ts
796
812
  import { stat } from "fs/promises";
797
- var CANDIDATE_RE = /-?[\w@][\w:/.-]*(?:\[[^\]]+\][\w:/.-]*)*/g;
813
+ var CANDIDATE_RE = /-?(?:[\w@]|\[[^\]\s]+\])[\w:/.-]*(?:\[[^\]\s]+\][\w:/.-]*)*/g;
798
814
 
799
815
  class CssCandidateCache {
800
- static #version = 1;
816
+ static #version = 3;
801
817
  #path;
802
818
  #entries = new Map;
803
819
  #dirty = false;
@@ -957,8 +973,12 @@ class CssImportResolver {
957
973
  const pkg = await Bun.file(pkgPath).json();
958
974
  const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
959
975
  const exportValue = pkg.exports?.[subpath];
960
- const styleEntry = (typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default) || pkg.exports?.["."]?.style || pkg.style || "index.css";
961
- return await this.#firstExisting(path7.resolve(pkgDir, styleEntry));
976
+ const exportedEntry = typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default;
977
+ if (exportedEntry)
978
+ return await this.#firstExisting(path7.resolve(pkgDir, exportedEntry));
979
+ if (subpath !== ".")
980
+ return await this.#firstExisting(path7.resolve(pkgDir, subpath));
981
+ return await this.#firstExisting(path7.resolve(pkgDir, pkg.exports?.["."]?.style || pkg.style || "index.css"));
962
982
  } catch {
963
983
  return null;
964
984
  }
@@ -1015,6 +1035,7 @@ class CssCompiler {
1015
1035
  #fileExistsCache = new Map;
1016
1036
  #resolvedFileCache = new Map;
1017
1037
  #resolvedSpecifierCache = new Map;
1038
+ #discoveredCssPaths = new Set;
1018
1039
  #fileExists(absPath) {
1019
1040
  let cached = this.#fileExistsCache.get(absPath);
1020
1041
  if (!cached) {
@@ -1048,13 +1069,16 @@ class CssCompiler {
1048
1069
  async getCss({ refresh } = {}) {
1049
1070
  if (this.#cssText !== null && !refresh)
1050
1071
  return this.#cssText;
1072
+ this.#discoveredCssPaths.clear();
1051
1073
  const { cssPaths, sourcePaths } = await this.discoverCssAndSources({ refresh });
1052
1074
  this.#cssText = await this.compileCss(cssPaths, sourcePaths);
1075
+ await this.#warnUnreachableStylesheets();
1053
1076
  return this.#cssText;
1054
1077
  }
1055
1078
  async getCssByBasePath({ refresh } = {}) {
1056
1079
  if (this.#cssTextByBasePath !== null && !refresh)
1057
1080
  return this.#cssTextByBasePath;
1081
+ this.#discoveredCssPaths.clear();
1058
1082
  const akanConfig = await this.#app.getConfig({ refresh });
1059
1083
  const pageKeys = await this.#app.getPageKeys({ refresh });
1060
1084
  const basePaths = [...akanConfig.basePaths];
@@ -1081,8 +1105,20 @@ class CssCompiler {
1081
1105
  })
1082
1106
  ]);
1083
1107
  this.#cssTextByBasePath = Object.fromEntries(cssEntries);
1108
+ await this.#warnUnreachableStylesheets();
1084
1109
  return this.#cssTextByBasePath;
1085
1110
  }
1111
+ async#warnUnreachableStylesheets() {
1112
+ const pageDir = path8.join(this.#app.cwdPath, "page");
1113
+ const glob = new Bun.Glob("**/*.css");
1114
+ for await (const cssPath of glob.scan({ cwd: pageDir, absolute: true })) {
1115
+ if (cssPath.includes(`${path8.sep}(libs)${path8.sep}`))
1116
+ continue;
1117
+ if (this.#discoveredCssPaths.has(cssPath))
1118
+ continue;
1119
+ this.#logger.warn(`css ${path8.relative(this.#app.cwdPath, cssPath)} is imported by no route and never compiled`);
1120
+ }
1121
+ }
1086
1122
  async discoverCss({ refresh } = {}) {
1087
1123
  const { cssPaths } = await this.discoverCssAndSources({ refresh });
1088
1124
  return cssPaths;
@@ -1142,7 +1178,28 @@ class CssCompiler {
1142
1178
  queue.push(resolved);
1143
1179
  }
1144
1180
  }
1145
- return { cssPaths: [...cssFiles], sourcePaths: [...sourceFiles] };
1181
+ const tokenPaths = await this.#libTokenStylesheets(sourceFiles);
1182
+ const cssPaths = [...new Set([...tokenPaths, ...cssFiles])];
1183
+ for (const cssPath of cssPaths)
1184
+ this.#discoveredCssPaths.add(cssPath);
1185
+ return { cssPaths, sourcePaths: [...sourceFiles] };
1186
+ }
1187
+ async#libTokenStylesheets(sourceFiles) {
1188
+ const libsRoot = path8.join(this.#app.workspace.workspaceRoot, "libs");
1189
+ const libNames = new Set;
1190
+ for (const filePath of sourceFiles) {
1191
+ const relPath = path8.relative(libsRoot, filePath);
1192
+ if (relPath.startsWith("..") || path8.isAbsolute(relPath))
1193
+ continue;
1194
+ const [libName] = relPath.split(path8.sep);
1195
+ if (libName)
1196
+ libNames.add(libName);
1197
+ }
1198
+ const tokenPaths = await Promise.all([...libNames].sort().map(async (libName) => {
1199
+ const tokensPath = path8.join(libsRoot, libName, "ui/tokens.css");
1200
+ return await this.#fileExists(tokensPath) ? tokensPath : null;
1201
+ }));
1202
+ return tokenPaths.filter((tokensPath) => !!tokensPath);
1146
1203
  }
1147
1204
  async compileCss(cssPaths, sourcePaths) {
1148
1205
  if (cssPaths.length === 0)
@@ -1180,12 +1237,17 @@ class CssCompiler {
1180
1237
  }
1181
1238
  async#loadStylesheet(id, fromBase) {
1182
1239
  const p = await this.#resolveCssImport(id, fromBase);
1240
+ this.#discoveredCssPaths.add(p);
1183
1241
  const content = await Bun.file(p).text();
1184
1242
  return { path: p, base: path8.dirname(p), content };
1185
1243
  }
1186
1244
  async#resolveCssImport(id, fromBase) {
1187
- if (id.startsWith(".") || id.startsWith("/"))
1188
- return path8.resolve(fromBase, id);
1245
+ if (id.startsWith(".") || id.startsWith("/")) {
1246
+ const filePath = path8.resolve(fromBase, id);
1247
+ if (await this.#fileExists(filePath))
1248
+ return filePath;
1249
+ throw new Error(`[css] failed to resolve stylesheet import "${id}" from ${fromBase} (no file at ${filePath})`);
1250
+ }
1189
1251
  const resolver = await this.#getCssImportResolver();
1190
1252
  const resolved = await resolver.resolve(id, fromBase);
1191
1253
  if (resolved)
@@ -2025,14 +2087,21 @@ function loaderFor2(absPath) {
2025
2087
  // pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
2026
2088
  import fs2 from "fs";
2027
2089
  import path12 from "path";
2090
+ import zlib from "zlib";
2028
2091
  var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
2029
2092
  var MIN_COMPRESS_BYTES = 1024;
2093
+ var BROTLI_QUALITY_BY_EXT = { ".css": 11 };
2094
+ var DEFAULT_BROTLI_QUALITY = 9;
2095
+ var GZIP_LEVEL = 9;
2030
2096
  async function precompressArtifacts(app) {
2031
- const roots = [path12.join(app.dist.cwdPath, ".akan/artifact/client")];
2032
- const result = { files: 0, inputBytes: 0, outputBytes: 0 };
2097
+ const roots = [
2098
+ path12.join(app.dist.cwdPath, ".akan/artifact/client"),
2099
+ path12.join(app.dist.cwdPath, ".akan/artifact/styles")
2100
+ ];
2101
+ const result = { files: 0, inputBytes: 0, outputBytes: 0, brotliBytes: 0 };
2033
2102
  await Promise.all(roots.map((root) => precompressRoot(root, result)));
2034
2103
  if (result.files > 0) {
2035
- app.verbose(`[precompress] wrote ${result.files} gzip sidecars (${formatBytes(result.inputBytes)} -> ${formatBytes(result.outputBytes)})`);
2104
+ app.verbose(`[precompress] wrote ${result.files} sidecars (${formatBytes(result.inputBytes)} -> gzip ${formatBytes(result.outputBytes)} / br ${formatBytes(result.brotliBytes)})`);
2036
2105
  }
2037
2106
  return result;
2038
2107
  }
@@ -2044,15 +2113,27 @@ async function precompressRoot(root, result) {
2044
2113
  if (!await shouldPrecompress(filePath))
2045
2114
  continue;
2046
2115
  const bytes = await Bun.file(filePath).bytes();
2047
- const gz = Bun.gzipSync(toArrayBuffer(bytes));
2048
- await Bun.write(`${filePath}.gz`, gz);
2116
+ const buffer = toArrayBuffer(bytes);
2117
+ const gz = Bun.gzipSync(buffer, { level: GZIP_LEVEL });
2118
+ const br = brotliCompress(buffer, path12.extname(filePath).toLowerCase());
2119
+ await Promise.all([Bun.write(`${filePath}.gz`, gz), Bun.write(`${filePath}.br`, br)]);
2049
2120
  result.files += 1;
2050
2121
  result.inputBytes += bytes.byteLength;
2051
2122
  result.outputBytes += gz.byteLength;
2123
+ result.brotliBytes += br.byteLength;
2052
2124
  }
2053
2125
  }
2126
+ function brotliCompress(buffer, ext) {
2127
+ const quality = BROTLI_QUALITY_BY_EXT[ext] ?? DEFAULT_BROTLI_QUALITY;
2128
+ return zlib.brotliCompressSync(buffer, {
2129
+ params: {
2130
+ [zlib.constants.BROTLI_PARAM_QUALITY]: quality,
2131
+ [zlib.constants.BROTLI_PARAM_SIZE_HINT]: buffer.byteLength
2132
+ }
2133
+ });
2134
+ }
2054
2135
  async function shouldPrecompress(filePath) {
2055
- if (filePath.endsWith(".gz"))
2136
+ if (filePath.endsWith(".gz") || filePath.endsWith(".br"))
2056
2137
  return false;
2057
2138
  if (!COMPRESSIBLE_EXTS.has(path12.extname(filePath).toLowerCase()))
2058
2139
  return false;
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  AkanContextAnalyzer
4
- } from "./index-a00jg8x8.js";
4
+ } from "./index-e4b2ae6b.js";
5
5
  import {
6
6
  WorkflowExecutor,
7
7
  compactWorkflowInputs,
@@ -23,10 +23,10 @@ import {
23
23
  workflowCommandsForPlan,
24
24
  workflowPlanApproval,
25
25
  writeWorkflowRunArtifact
26
- } from "./index-rzwcpcc3.js";
26
+ } from "./index-kcsa1zff.js";
27
27
  import {
28
28
  runner
29
- } from "./index-8hsbnyes.js";
29
+ } from "./index-etwh7sd3.js";
30
30
 
31
31
  // pkgs/@akanjs/cli/workflow/workflow.runner.ts
32
32
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -2,11 +2,16 @@
2
2
  import {
3
3
  workflowRunArtifactPath,
4
4
  workflowSyncDir
5
- } from "./index-rzwcpcc3.js";
5
+ } from "./index-kcsa1zff.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-yzsxc30b.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,9 +5,11 @@ import {
5
5
  LibExecutor,
6
6
  ModuleExecutor,
7
7
  PkgExecutor,
8
- WorkspaceExecutor,
8
+ WorkspaceExecutor
9
+ } from "./index-yzsxc30b.js";
10
+ import {
9
11
  getDirname
10
- } from "./index-hgna5rjy.js";
12
+ } from "./index-1577bej2.js";
11
13
  import {
12
14
  FileSys
13
15
  } from "./index-67546d0j.js";
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-8hsbnyes.js";
5
+ } from "./index-etwh7sd3.js";
6
6
  import {
7
7
  PkgExecutor
8
- } from "./index-hgna5rjy.js";
8
+ } from "./index-yzsxc30b.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";
@@ -1143,16 +1143,17 @@ class RouteClientBuilder {
1143
1143
  #knownEntries;
1144
1144
  #command;
1145
1145
  #discovery;
1146
+ #entries;
1146
1147
  constructor(options) {
1147
1148
  this.#app = options.app;
1148
1149
  this.#seeds = options.seeds;
1149
1150
  this.#knownEntries = options.knownEntries ?? new Set;
1150
1151
  this.#command = options.command ?? "start";
1151
1152
  this.#discovery = options.discovery;
1153
+ this.#entries = options.entries;
1152
1154
  }
1153
1155
  async build() {
1154
- const discovery = this.#discovery ?? await GraphClientEntryDiscovery.create(this.#app);
1155
- const discovered = await discovery.discover(this.#seeds);
1156
+ const discovered = this.#entries ?? await (this.#discovery ?? await GraphClientEntryDiscovery.create(this.#app)).discover(this.#seeds);
1156
1157
  const entries = discovered.filter((e) => !this.#knownEntries.has(e));
1157
1158
  if (entries.length === 0)
1158
1159
  return this.#emptyResult(discovered);
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  AppExecutor,
4
4
  LibExecutor
5
- } from "./index-hgna5rjy.js";
5
+ } from "./index-yzsxc30b.js";
6
6
 
7
7
  // pkgs/@akanjs/devkit/workflow/utils.ts
8
8
  var jsonText = (value, { trailingNewline = true } = {}) => `${JSON.stringify(value, null, 2)}${trailingNewline ? `
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  ModuleScript
4
- } from "./index-yzmhasdb.js";
4
+ } from "./index-mewacxye.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-kcsa1zff.js";
38
38
  import {
39
39
  script
40
- } from "./index-8hsbnyes.js";
40
+ } from "./index-etwh7sd3.js";
41
41
  import {
42
42
  AppExecutor,
43
43
  LibExecutor,
44
44
  ModuleExecutor
45
- } from "./index-hgna5rjy.js";
45
+ } from "./index-yzsxc30b.js";
46
46
 
47
47
  // pkgs/@akanjs/cli/primitive/primitive.script.ts
48
48
  import { capitalize } from "akanjs/common";
@@ -1,10 +1,10 @@
1
1
  // @bun
2
- import {
3
- PageScript
4
- } from "./index-bbkek1bp.js";
5
2
  import {
6
3
  pluralizeName
7
4
  } from "./index-ss469dec.js";
5
+ import {
6
+ PageScript
7
+ } from "./index-65aeh789.js";
8
8
  import {
9
9
  AiSession
10
10
  } from "./index-0cj2zxbm.js";
@@ -15,17 +15,17 @@ import {
15
15
  generatedFilesForSync,
16
16
  moduleSourcePaths,
17
17
  sourceFile
18
- } from "./index-rzwcpcc3.js";
18
+ } from "./index-kcsa1zff.js";
19
19
  import {
20
20
  Prompter
21
- } from "./index-tdbas9r0.js";
21
+ } from "./index-j37qq1f2.js";
22
22
  import {
23
23
  runner,
24
24
  script
25
- } from "./index-8hsbnyes.js";
25
+ } from "./index-etwh7sd3.js";
26
26
  import {
27
27
  ModuleExecutor
28
- } from "./index-hgna5rjy.js";
28
+ } from "./index-yzsxc30b.js";
29
29
  import {
30
30
  FileSys
31
31
  } from "./index-67546d0j.js";
@@ -7,21 +7,14 @@ import {
7
7
  } from "./index-0cj2zxbm.js";
8
8
  import {
9
9
  openBrowser
10
- } from "./index-e16gnn26.js";
10
+ } from "./index-bzznxgcx.js";
11
11
  import {
12
12
  runner
13
- } from "./index-8hsbnyes.js";
13
+ } from "./index-etwh7sd3.js";
14
14
  import {
15
15
  AppExecutor,
16
16
  WorkspaceExecutor
17
- } from "./index-hgna5rjy.js";
18
-
19
- // pkgs/@akanjs/cli/cloud/cloud.runner.ts
20
- import path from "path";
21
- import { confirm, input, select } from "@inquirer/prompts";
22
- import { Logger, sleep } from "akanjs/common";
23
- import chalk from "chalk";
24
- import * as QRcode from "qrcode";
17
+ } from "./index-yzsxc30b.js";
25
18
 
26
19
  // pkgs/@akanjs/cli/npmRegistry.ts
27
20
  var defaultNpmRegistry = "https://registry.npmjs.org";
@@ -40,6 +33,11 @@ async function getLatestPackageVersion(packageName, tag = "latest", registryUrl)
40
33
  }
41
34
 
42
35
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
36
+ import path from "path";
37
+ import { confirm, input, select } from "@inquirer/prompts";
38
+ import { Logger, sleep } from "akanjs/common";
39
+ import chalk from "chalk";
40
+ import * as QRcode from "qrcode";
43
41
  var addRemoteEnvServerValue = "__addRemoteEnvServer";
44
42
  var removeRemoteEnvServerValue = "__removeRemoteEnvServer";
45
43
 
@@ -1,17 +1,17 @@
1
1
  // @bun
2
2
  import {
3
3
  AkanContextAnalyzer
4
- } from "./index-a00jg8x8.js";
4
+ } from "./index-e4b2ae6b.js";
5
5
  import {
6
6
  createRepairReport,
7
7
  generatedFilePathsForTarget,
8
8
  renderRepairReport,
9
9
  writeGeneratedSyncState,
10
10
  writeWorkflowRunArtifact
11
- } from "./index-rzwcpcc3.js";
11
+ } from "./index-kcsa1zff.js";
12
12
  import {
13
13
  runner
14
- } from "./index-8hsbnyes.js";
14
+ } from "./index-etwh7sd3.js";
15
15
 
16
16
  // pkgs/@akanjs/cli/repair/repair.runner.ts
17
17
  var commandForShell = (command) => command.startsWith("akan ") ? `bun run ${command}` : command;