@akanjs/cli 3.0.0-alpha.7 → 3.0.0-alpha.70

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 (119) hide show
  1. package/.build-stamp +1 -1
  2. package/README.ko.md +1 -1
  3. package/README.md +1 -1
  4. package/{abstractCompactor-e5yq60qz.js → abstractCompactor-20e0cwbs.js} +2 -2
  5. package/{agent.command-pggr92jj.js → agent.command-964bf8qg.js} +9 -7
  6. package/{application.command-692yap1d.js → application.command-n45n18sc.js} +8 -6
  7. package/{applicationBuildRunner-ha3y8ew8.js → applicationBuildRunner-af0wtspv.js} +19 -14
  8. package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-93nzdfsy.js} +1 -1
  9. package/buildBatch.proc.js +7 -5
  10. package/{capacitorApp-p0z5yab2.js → capacitorApp-vnvnvdhf.js} +29 -27
  11. package/{cloud.command-wqfsyzv2.js → cloud.command-kx1bh5yq.js} +12 -10
  12. package/{context.command-9bxtdn0w.js → context.command-g1a65x6j.js} +17 -15
  13. package/{dependencyScanner-f6grrep3.js → dependencyScanner-rbs2407b.js} +1 -1
  14. package/getDirname-ka11hm7e.js +8 -0
  15. package/{guideline.command-nfqahxex.js → guideline.command-xphyhvwh.js} +8 -6
  16. package/guidelines/agentRule/agentRule.generate.json +31 -0
  17. package/guidelines/agentRule/agentRule.instruction.md +525 -0
  18. package/guidelines/conventions/conventions.generate.json +25 -0
  19. package/guidelines/conventions/conventions.instruction.md +1020 -0
  20. package/guidelines/cssRule/cssRule.instruction.md +7 -0
  21. package/guidelines/framework/framework.instruction.md +1 -0
  22. package/guidelines/mcpRule/mcpRule.generate.json +25 -0
  23. package/guidelines/mcpRule/mcpRule.instruction.md +220 -0
  24. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +24 -0
  25. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +638 -0
  26. package/incrementalBuilder.proc.js +8 -6
  27. package/{index-azv0xjb5.js → index-0ngvvgry.js} +8 -4
  28. package/index-1577bej2.js +7 -0
  29. package/{index-p3f4q532.js → index-4rw4qhe6.js} +14 -13
  30. package/{index-bjpxzr6s.js → index-5vy2jzar.js} +1 -1
  31. package/{index-js368gk9.js → index-8gybxemv.js} +6 -6
  32. package/{index-qb61h0k7.js → index-abyjt72y.js} +333 -540
  33. package/{index-4hek879p.js → index-bqqts262.js} +1 -1
  34. package/{index-6rhabeev.js → index-e31ghfp5.js} +5 -3
  35. package/index-f39512t6.js +255 -0
  36. package/{index-5pmx7bkg.js → index-fahkq20v.js} +3 -3
  37. package/{index-xhgtkekh.js → index-hee7egtm.js} +1 -1
  38. package/{index-7myvn0f0.js → index-j37qq1f2.js} +1 -1
  39. package/{index-5dw57f0d.js → index-mkn5qagt.js} +14 -14
  40. package/{index-ztpw544k.js → index-nj3w0r34.js} +3 -3
  41. package/{index-vg0sj9nc.js → index-nkwmnqwn.js} +257 -97
  42. package/{index-a1e0j63x.js → index-p681w089.js} +15 -7
  43. package/{index-j9cxndc0.js → index-qnv0aqmm.js} +9 -6
  44. package/{index-w6wbb612.js → index-qt4nfr0n.js} +13 -13
  45. package/{index-bz2sfzzt.js → index-rb65xnw9.js} +4 -4
  46. package/{index-gex7c8kd.js → index-rbnpe8cp.js} +37 -6
  47. package/{index-0cj2zxbm.js → index-sh01r3pm.js} +1 -1
  48. package/{index-gmy45vz2.js → index-v5fdxdre.js} +4 -4
  49. package/{index-mssqn2sq.js → index-va15r8h5.js} +54 -15
  50. package/{index-vtj3zps1.js → index-yg3hxk2k.js} +8 -8
  51. package/{index-2c3e2xh8.js → index-ytaqtc04.js} +1 -1
  52. package/index.js +21 -19
  53. package/{library.command-md9715jz.js → library.command-rfpd27yv.js} +6 -4
  54. package/{localRegistry.command-exkbamyj.js → localRegistry.command-pyxfe0fs.js} +11 -9
  55. package/{module.command-w5aaddxk.js → module.command-qhaxad0p.js} +10 -8
  56. package/{package.command-yfkrcy0z.js → package.command-2k22q9nt.js} +6 -4
  57. package/package.json +4 -5
  58. package/{page.command-echbavp4.js → page.command-ymk9dqh4.js} +6 -4
  59. package/{primitive.command-9fbhspw2.js → primitive.command-9k45zpc1.js} +11 -9
  60. package/{quality.command-3pnt9yep.js → quality.command-bf6vkxe5.js} +192 -97
  61. package/{recipeScanner-tghkzrrt.js → recipeScanner-zrzev25x.js} +3 -3
  62. package/{repair.command-carj4vax.js → repair.command-egvvm6xf.js} +8 -6
  63. package/{routeSourceValidator-e4jmbfcx.js → routeSourceValidator-7fycdqyv.js} +1 -1
  64. package/{scalar.command-51ryzypc.js → scalar.command-bt1facyj.js} +9 -7
  65. package/templates/app/env/env.client.debug.ts.template +1 -5
  66. package/templates/app/env/env.client.develop.ts.template +1 -5
  67. package/templates/app/env/env.client.local.ts.template +1 -5
  68. package/templates/app/env/env.client.main.ts.template +1 -5
  69. package/templates/app/env/env.client.testing.ts.template +1 -5
  70. package/templates/app/env/env.client.type.ts +2 -6
  71. package/templates/app/env/env.server.debug.ts.template +1 -5
  72. package/templates/app/env/env.server.develop.ts.template +1 -5
  73. package/templates/app/env/env.server.local.ts.template +1 -5
  74. package/templates/app/env/env.server.main.ts.template +1 -5
  75. package/templates/app/main.ts +3 -1
  76. package/templates/app/page/styles.css.template +3 -3
  77. package/templates/appSample/srvkit/AuthGuard.ts +9 -5
  78. package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
  79. package/templates/crudPages/[__model__Id]/edit/page.tsx +1 -1
  80. package/templates/crudPages/new/page.tsx +1 -1
  81. package/templates/crudSinglePage/page.tsx +1 -1
  82. package/templates/env/_env.server.type.ts +7 -5
  83. package/templates/lib/db.ts +1 -1
  84. package/templates/lib/dict.ts +1 -1
  85. package/templates/lib/sig.ts +1 -1
  86. package/templates/lib/srv.ts +6 -2
  87. package/templates/module/__Model__.Util.tsx +1 -1
  88. package/templates/module/__Model__.Zone.tsx +3 -5
  89. package/templates/workspaceRoot/AGENTS.md.template +0 -972
  90. package/templates/workspaceRoot/CLAUDE.md.template +19 -0
  91. package/templates/workspaceRoot/biome.json.template +4 -244
  92. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +10 -14
  93. package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
  94. package/templates/workspaceRoot/package.json.template +1 -1
  95. package/{typeChecker-kravn7ns.js → typeChecker-g6bh0xfv.js} +1 -1
  96. package/typecheck.proc.js +1 -1
  97. package/{workflow.command-91wmvm8k.js → workflow.command-v1n3wg7v.js} +16 -14
  98. package/{workspace.command-wa10mfd9.js → workspace.command-yvvqvhzz.js} +71 -52
  99. package/templates/workspaceRoot/.cursor/rules/akan-page-routing.mdc.template +0 -43
  100. package/templates/workspaceRoot/.cursor/rules/akan-sync-conventions.mdc.template +0 -34
  101. package/templates/workspaceRoot/.cursor/rules/application-test-commands.mdc.template +0 -16
  102. package/templates/workspaceRoot/.cursor/rules/change-scope.mdc.template +0 -12
  103. package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +0 -18
  104. package/templates/workspaceRoot/.cursor/rules/coding-comments.mdc.template +0 -25
  105. package/templates/workspaceRoot/.cursor/rules/coding-style.mdc.template +0 -44
  106. package/templates/workspaceRoot/.cursor/rules/domain-module-conventions.mdc.template +0 -17
  107. package/templates/workspaceRoot/.cursor/rules/format-lint.mdc.template +0 -12
  108. package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +0 -19
  109. package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +0 -62
  110. package/templates/workspaceRoot/.cursor/rules/naming-conventions.mdc.template +0 -15
  111. package/templates/workspaceRoot/.cursor/rules/react-component-style.mdc.template +0 -21
  112. package/templates/workspaceRoot/.cursor/rules/repo-overview.mdc.template +0 -17
  113. package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +0 -99
  114. package/templates/workspaceRoot/.cursor/rules/secrets-and-env.mdc.template +0 -13
  115. package/templates/workspaceRoot/.cursor/rules/service-signal-conventions.mdc.template +0 -83
  116. package/templates/workspaceRoot/.cursor/rules/srvkit-adapters-and-guards.mdc.template +0 -50
  117. package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +0 -59
  118. package/templates/workspaceRoot/.cursor/rules/typescript-imports.mdc.template +0 -16
  119. /package/{index-r24hmh0q.js → index-yb2wsc7f.js} +0 -0
@@ -1,13 +1,20 @@
1
1
  // @bun
2
+ import {
3
+ getRootBoundarySegments,
4
+ isRootBoundarySegments
5
+ } from "./index-f39512t6.js";
2
6
  import {
3
7
  Spinner
4
8
  } from "./index-mxvakhsm.js";
9
+ import {
10
+ getDirname
11
+ } from "./index-1577bej2.js";
5
12
  import {
6
13
  FileSys
7
14
  } from "./index-67546d0j.js";
8
15
  import {
9
16
  __require
10
- } from "./index-r24hmh0q.js";
17
+ } from "./index-yb2wsc7f.js";
11
18
 
12
19
  // pkgs/@akanjs/devkit/executors.ts
13
20
  import {
@@ -30,6 +37,7 @@ import path5 from "path";
30
37
  import { pathToFileURL } from "url";
31
38
  import {
32
39
  capitalize,
40
+ getPageSourceFileViolation,
33
41
  isRouteSourceFile,
34
42
  Logger,
35
43
  parseRouteModuleKey,
@@ -41,9 +49,24 @@ import chalk2 from "chalk";
41
49
 
42
50
  // pkgs/@akanjs/devkit/agentsIndex.ts
43
51
  var recipeScannerLoad = null;
44
- var loadRecipeScanner = () => recipeScannerLoad ??= import("./recipeScanner-tghkzrrt.js");
52
+ var loadRecipeScanner = () => recipeScannerLoad ??= import("./recipeScanner-zrzev25x.js");
45
53
  var AGENT_BLOCK_START = "<!-- akan:agent:start -->";
46
54
  var AGENT_BLOCK_END = "<!-- akan:agent:end -->";
55
+ var AGENT_VERSION_PREFIX = "<!-- akan:agent:version ";
56
+ var stampBlockVersion = (block, version) => `${AGENT_VERSION_PREFIX}${version} -->
57
+
58
+ ${block}`;
59
+ var extractBlockVersion = (content) => content.match(/<!-- akan:agent:version ([^\s]+) -->/)?.[1] ?? null;
60
+ var readDevkitVersion = async () => {
61
+ const { readFile } = await import("fs/promises");
62
+ const { getDirname: getDirname2 } = await import("./getDirname-ka11hm7e.js");
63
+ try {
64
+ const raw = await readFile(`${getDirname2(import.meta.url)}/package.json`, "utf-8");
65
+ return JSON.parse(raw).version ?? null;
66
+ } catch {
67
+ return null;
68
+ }
69
+ };
47
70
  var upsertAgentBlock = (existing, block) => {
48
71
  const managed = `${AGENT_BLOCK_START}
49
72
  ${block}
@@ -137,9 +160,29 @@ ${AGENT_BLOCK_START}
137
160
  ${block}
138
161
  ${AGENT_BLOCK_END}
139
162
  `;
163
+ var CLAUDE_COMMENT_RULE = `## Comments \u2014 Overrides Your Default
164
+
165
+ Write **no comments** unless the comment passes the test below. This is the rule agents break most often here, so it
166
+ is repeated outside the guide: a diff that adds a comment the test rejects is a diff to redo.
167
+
168
+ Before typing \`//\`, \`/*\`, or a doc block, ask \u2014 **does this sentence carry a fact that is nowhere in the code?**
169
+
170
+ - Restates the identifier, the signature, or the line under it \u2192 delete it.
171
+ - Labels a section (\`// helpers\`, \`// state\`) or narrates a step (\`// fetch the user\`, \`// then save\`) \u2192 delete it.
172
+ - JSDoc on an ordinary function, or a why/how preamble on ordinary logic \u2192 delete it.
173
+ - Explains the edit you just made, for whoever reads the diff \u2192 say it in your reply, not in the file.
174
+ - Names a vendor or protocol quirk, an infrastructure constraint, a library gotcha, security reasoning, a math
175
+ derivation, a domain field's business meaning, a state transition, or why an obvious alternative was rejected \u2192
176
+ keep it, one line.
177
+
178
+ That keep-list is exact \u2014 \`Comments\` in the guide is the full version. "It aids readability" and "this logic is
179
+ subtle" are not on it: rename or split the code instead. When you edit an existing file, match its density; if the
180
+ surrounding code carries none, your diff carries none.`;
140
181
  var renderScopeClaudeMd = (scope) => `# ${scope.name} \u2014 Claude Code Guide
141
182
 
142
183
  @AGENTS.md
184
+
185
+ ${CLAUDE_COMMENT_RULE}
143
186
  `;
144
187
 
145
188
  // pkgs/@akanjs/devkit/akanConfig/akanConfig.ts
@@ -181,9 +224,8 @@ var DEFAULT_OPTIMIZE_IMPORTS = [
181
224
  "react-icons/*"
182
225
  ];
183
226
  var WORKSPACE_BARREL_FACETS = ["ui", "webkit", "common", "client", "server"];
227
+ var DEFAULT_DOCKER_IMAGE = "oven/bun:1-slim";
184
228
  var SSR_RUNTIME_PACKAGES = ["react", "react-dom", "react-server-dom-webpack"];
185
- var NATIVE_RUNTIME_PACKAGES = ["sharp"];
186
- var DEFAULT_BACKEND_RUNTIME_PACKAGES = ["croner"];
187
229
  var MOBILE_RUNTIME_PACKAGES = [
188
230
  "@capacitor/cli",
189
231
  "@capacitor/core",
@@ -212,8 +254,6 @@ var DATABASE_MODE_RUNTIME_PACKAGES = {
212
254
  };
213
255
  var AKAN_RUNTIME_PACKAGES = new Set([
214
256
  ...SSR_RUNTIME_PACKAGES,
215
- ...NATIVE_RUNTIME_PACKAGES,
216
- ...DEFAULT_BACKEND_RUNTIME_PACKAGES,
217
257
  ...MOBILE_RUNTIME_PACKAGES,
218
258
  ...Object.values(DATABASE_MODE_RUNTIME_PACKAGES).flat()
219
259
  ]);
@@ -228,7 +268,8 @@ var DEFAULT_AKAN_IMAGE_CONFIG = {
228
268
  dangerouslyAllowSVG: false,
229
269
  maximumRedirects: 3,
230
270
  fetchTimeoutMs: 7000,
231
- maxRemoteBytes: 25 * 1024 * 1024
271
+ maxRemoteBytes: 25 * 1024 * 1024,
272
+ maxConcurrency: 0
232
273
  };
233
274
  var normalizeIndexPath = (indexPath) => {
234
275
  const normalized = indexPath?.trim();
@@ -275,12 +316,28 @@ var normalizeDeepLinks = (deepLinks) => {
275
316
  ...sha256CertFingerprints ? { android: { sha256CertFingerprints } } : {}
276
317
  };
277
318
  };
319
+ var emptyLibContributions = () => ({
320
+ externalLibs: [],
321
+ docker: { preRuns: [], postRuns: [] },
322
+ keepFonts: []
323
+ });
324
+ var normalizeKeepFonts = (keepFonts) => [
325
+ ...new Set((keepFonts ?? []).map((glob) => glob.trim().replace(/^\/+/, "")).filter(Boolean))
326
+ ];
327
+ var dedupeDockerRuns = (runs) => {
328
+ const byKey = new Map;
329
+ for (const run of runs)
330
+ byKey.set(typeof run === "string" ? run : JSON.stringify(run), run);
331
+ return [...byKey.values()];
332
+ };
278
333
 
279
334
  class AkanAppConfig {
280
335
  app;
281
336
  rootPackageJson;
282
337
  docker;
338
+ dockerfile;
283
339
  defaultDatabaseMode;
340
+ web;
284
341
  externalLibs;
285
342
  barrelImports;
286
343
  optimizeImports;
@@ -290,6 +347,7 @@ class AkanAppConfig {
290
347
  mobile;
291
348
  hasMobileConfig;
292
349
  secrets;
350
+ assets;
293
351
  syncPageLibs;
294
352
  baseDevEnv;
295
353
  libs;
@@ -298,7 +356,7 @@ class AkanAppConfig {
298
356
  subRoutes = new Map;
299
357
  basePaths = new Set;
300
358
  branches = new Set(["debug", "develop", "main"]);
301
- constructor(app, libs, rootPackageJson, config, baseDevEnv, plugins = []) {
359
+ constructor(app, libs, rootPackageJson, config, baseDevEnv, plugins = [], libContributions = emptyLibContributions()) {
302
360
  this.app = app;
303
361
  this.rootPackageJson = rootPackageJson;
304
362
  this.libs = libs;
@@ -306,7 +364,7 @@ class AkanAppConfig {
306
364
  this.plugins = plugins;
307
365
  this.#applyRoutes(config?.routes);
308
366
  this.defaultDatabaseMode = config?.defaultDatabaseMode ?? "single";
309
- this.externalLibs = config?.externalLibs ?? [];
367
+ this.externalLibs = [...new Set([...config?.externalLibs ?? [], ...libContributions.externalLibs])];
310
368
  this.barrelImports = [
311
369
  ...DEFAULT_BARREL_IMPORTS,
312
370
  ...WORKSPACE_BARREL_FACETS.map((facet) => `@apps/${app.name}/${facet}`),
@@ -320,10 +378,25 @@ class AkanAppConfig {
320
378
  process.env.AKAN_PUBLIC_LOCALES = this.i18n.locales.join(",");
321
379
  this.publicEnv = config?.publicEnv ?? [];
322
380
  this.secrets = config?.secrets ?? [];
381
+ this.assets = {
382
+ pruneFonts: config?.assets?.pruneFonts ?? true,
383
+ keepFonts: [
384
+ ...normalizeKeepFonts(config?.assets?.keepFonts),
385
+ ...libContributions.keepFonts ?? []
386
+ ]
387
+ };
323
388
  this.syncPageLibs = config?.syncPageLibs ?? false;
324
389
  this.hasMobileConfig = Boolean(config.mobile);
325
390
  this.mobile = this.#resolveMobileConfig(config.mobile);
326
- this.docker = this.#makeDockerContent(config?.docker ?? {});
391
+ this.web = this.#resolveWebConfig(config.web);
392
+ this.docker = AkanAppConfig.#resolveDocker(config.docker, libContributions.docker);
393
+ this.dockerfile = this.#makeDockerfile();
394
+ }
395
+ #resolveWebConfig(web) {
396
+ const resolved = typeof web === "object" ? { ssr: true, csr: web.csr } : { ssr: web ?? true, csr: web ?? true };
397
+ if (!resolved.csr && this.hasMobileConfig)
398
+ throw new Error(`apps/${this.app.name}/akan.config.ts turns the CSR bundle off but declares mobile targets; the Capacitor build ships that bundle. Drop the mobile section or leave CSR on.`);
399
+ return resolved;
327
400
  }
328
401
  #resolveMobileConfig(mobile) {
329
402
  const {
@@ -433,23 +506,31 @@ class AkanAppConfig {
433
506
  return archs.map((arch) => `FROM ${image[arch] ?? defaultImage} AS ${arch}`).join(`
434
507
  `);
435
508
  }
436
- #makeDockerContent(docker) {
437
- if (docker.content)
438
- return {
439
- content: docker.content,
440
- image: {},
441
- preRuns: [],
442
- postRuns: [],
443
- command: []
444
- };
445
- const preRunScripts = this.#getDockerRunScripts(docker.preRuns ?? []);
446
- const postRunScripts = this.#getDockerRunScripts(docker.postRuns ?? []);
447
- const imageScript = docker.image ? this.#getDockerImageScript(docker.image, "oven/bun:1-slim") : "FROM oven/bun:1-slim";
448
- const command = docker.command ?? ["bun", "main.js"];
449
- const content = `${imageScript}
509
+ static #resolveDocker(docker, libDocker) {
510
+ if (typeof docker === "string")
511
+ return docker;
512
+ return {
513
+ image: docker?.image ?? DEFAULT_DOCKER_IMAGE,
514
+ preRuns: dedupeDockerRuns([...libDocker.preRuns, ...docker?.preRuns ?? []]),
515
+ postRuns: dedupeDockerRuns([...libDocker.postRuns, ...docker?.postRuns ?? []]),
516
+ command: docker?.command ?? ["bun", "main.js"]
517
+ };
518
+ }
519
+ #makeDockerfile() {
520
+ if (typeof this.docker === "string")
521
+ return this.docker;
522
+ const { image, preRuns, postRuns, command } = this.docker;
523
+ const preRunScripts = this.#getDockerRunScripts(preRuns);
524
+ const postRunScripts = this.#getDockerRunScripts(postRuns);
525
+ const imageScript = this.#getDockerImageScript(image, DEFAULT_DOCKER_IMAGE);
526
+ const webEnvLines = [
527
+ ...this.web.ssr ? [] : ["ENV AKAN_SSR=false"],
528
+ ...this.web.csr ? [] : ["ENV AKAN_CSR=false"]
529
+ ].join(`
530
+ `);
531
+ return `${imageScript}
532
+ RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends ca-certificates tzdata && rm -rf /var/lib/apt/lists/*
450
533
  RUN ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
451
- RUN apt-get update && apt-get upgrade -y
452
- RUN apt-get install -y --no-install-recommends git redis build-essential python3 ca-certificates fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils udev ffmpeg
453
534
  ARG TARGETARCH
454
535
  ${preRunScripts.join(`
455
536
  `)}
@@ -470,15 +551,8 @@ ${this.basePaths.size ? `ENV AKAN_PUBLIC_BASE_PATHS=${[...this.basePaths].join("
470
551
  ENV AKAN_PUBLIC_DEFAULT_LOCALE=${this.i18n.defaultLocale}
471
552
  ENV AKAN_PUBLIC_LOCALES=${this.i18n.locales.join(",")}
472
553
  ENV AKAN_PUBLIC_OPERATION_MODE=cloud
473
-
554
+ ${webEnvLines}
474
555
  CMD [${command.map((c) => `"${c}"`).join(",")}]`;
475
- return {
476
- content,
477
- image: imageScript,
478
- preRuns: docker.preRuns ?? [],
479
- postRuns: docker.postRuns ?? [],
480
- command
481
- };
482
556
  }
483
557
  static #importGeneration = 0;
484
558
  static async importConfigModule(cwdPath, { bustImportCache = false } = {}) {
@@ -495,7 +569,22 @@ CMD [${command.map((c) => `"${c}"`).join(",")}]`;
495
569
  ]);
496
570
  const resolved = typeof configImp === "function" ? configImp(app) : configImp;
497
571
  const { plugins, ...config } = resolved ?? {};
498
- return new AkanAppConfig(app, libs, rootPackageJson, config, baseDevEnv, plugins ?? []);
572
+ const libContributions = await AkanAppConfig.#collectLibContributions(app, libs, bustImportCache);
573
+ return new AkanAppConfig(app, libs, rootPackageJson, config, baseDevEnv, plugins ?? [], libContributions);
574
+ }
575
+ static async#collectLibContributions(app, libs, bustImportCache) {
576
+ const libConfigs = await Promise.all(libs.map(async (libName) => LibExecutor.from(app, libName).getConfig({ refresh: bustImportCache }).catch((error) => {
577
+ app.logger.warn(`Skipped libs/${libName}/akan.config.ts contributions: ${String(error)}`);
578
+ return null;
579
+ })));
580
+ return {
581
+ externalLibs: libConfigs.flatMap((libConfig) => libConfig?.externalLibs ?? []),
582
+ docker: {
583
+ preRuns: libConfigs.flatMap((libConfig) => libConfig?.docker.preRuns ?? []),
584
+ postRuns: libConfigs.flatMap((libConfig) => libConfig?.docker.postRuns ?? [])
585
+ },
586
+ keepFonts: libConfigs.flatMap((libConfig) => (libConfig?.assets.keepFonts ?? []).map((glob) => `libs/${libConfig?.lib.name}/${glob}`))
587
+ };
499
588
  }
500
589
  #resolveProductionDependencyVersion(lib) {
501
590
  const rootVersion = this.rootPackageJson.dependencies?.[lib] ?? this.rootPackageJson.devDependencies?.[lib];
@@ -505,13 +594,7 @@ CMD [${command.map((c) => `"${c}"`).join(",")}]`;
505
594
  return akanPackageJson.dependencies?.[lib] ?? akanPackageJson.peerDependencies?.[lib];
506
595
  }
507
596
  #getProductionRuntimePackages() {
508
- return [
509
- ...this.externalLibs,
510
- ...SSR_RUNTIME_PACKAGES,
511
- ...NATIVE_RUNTIME_PACKAGES,
512
- ...DEFAULT_BACKEND_RUNTIME_PACKAGES,
513
- ...this.getDatabaseModeRuntimePackages()
514
- ];
597
+ return [...this.externalLibs, ...SSR_RUNTIME_PACKAGES, ...this.getDatabaseModeRuntimePackages()];
515
598
  }
516
599
  getDatabaseModeRuntimePackages(databaseMode = this.defaultDatabaseMode) {
517
600
  return [...DATABASE_MODE_RUNTIME_PACKAGES[databaseMode]];
@@ -599,14 +682,18 @@ function mergeImageConfig(config = {}) {
599
682
  class AkanLibConfig {
600
683
  lib;
601
684
  externalLibs;
685
+ docker;
686
+ assets;
602
687
  plugins;
603
688
  constructor(lib, config, plugins = []) {
604
689
  this.lib = lib;
605
690
  this.externalLibs = config?.externalLibs ?? [];
691
+ this.docker = { preRuns: config?.docker?.preRuns ?? [], postRuns: config?.docker?.postRuns ?? [] };
692
+ this.assets = { keepFonts: normalizeKeepFonts(config?.assets?.keepFonts) };
606
693
  this.plugins = plugins;
607
694
  }
608
- static async from(lib) {
609
- const [configImp] = await Promise.all([import(`${lib.cwdPath}/akan.config.ts`).then((mod) => mod.default)]);
695
+ static async from(lib, { bustImportCache = false } = {}) {
696
+ const configImp = await AkanAppConfig.importConfigModule(lib.cwdPath, { bustImportCache });
610
697
  const resolved = typeof configImp === "function" ? configImp(lib) : configImp;
611
698
  const { plugins, ...config } = resolved ?? {};
612
699
  return new AkanLibConfig(lib, config, plugins ?? []);
@@ -627,42 +714,47 @@ var decreaseBuildNum = async (app) => {
627
714
  const akanConfigContent = akanConfig.replace(`buildNum: ${appConfig.mobile.buildNum}`, `buildNum: ${appConfig.mobile.buildNum - 1}`);
628
715
  fs.writeFileSync(akanConfigPath, akanConfigContent);
629
716
  };
630
- // pkgs/@akanjs/devkit/getDirname.ts
631
- import path2 from "path";
632
- import { fileURLToPath as fileURLToPath2 } from "url";
633
- var getDirname = (url) => path2.dirname(fileURLToPath2(url));
634
-
635
717
  // pkgs/@akanjs/devkit/linter.ts
636
718
  import { spawn } from "child_process";
637
719
  import { existsSync, readFileSync } from "fs";
638
- import path3 from "path";
720
+ import path2 from "path";
639
721
  import chalk from "chalk";
722
+ var BIOME_CONFIG_FILES = ["biome.json", "biome.jsonc"];
640
723
 
641
724
  class Linter {
642
725
  lintRoot;
726
+ configPath;
643
727
  #biomeBin;
644
728
  constructor(cwdPath) {
645
729
  this.lintRoot = this.#findBiomeRootPath(cwdPath);
646
- const localBiomeBin = path3.join(this.lintRoot, "node_modules/.bin/biome");
730
+ this.configPath = Linter.#configPathIn(this.lintRoot) ?? path2.join(this.lintRoot, "biome.json");
731
+ const localBiomeBin = path2.join(this.lintRoot, "node_modules/.bin/biome");
647
732
  this.#biomeBin = existsSync(localBiomeBin) ? localBiomeBin : "biome";
648
733
  }
734
+ static #configPathIn(dir) {
735
+ for (const fileName of BIOME_CONFIG_FILES) {
736
+ const configPath = path2.join(dir, fileName);
737
+ if (existsSync(configPath))
738
+ return configPath;
739
+ }
740
+ return null;
741
+ }
649
742
  #findBiomeRootPath(dir) {
650
- const configPath = path3.join(dir, "biome.json");
651
- if (existsSync(configPath))
743
+ if (Linter.#configPathIn(dir))
652
744
  return dir;
653
- const parentDir = path3.dirname(dir);
745
+ const parentDir = path2.dirname(dir);
654
746
  if (parentDir === dir)
655
747
  throw new Error(`biome.json not found from ${dir}`);
656
748
  return this.#findBiomeRootPath(parentDir);
657
749
  }
658
750
  #toBiomePath(filePath) {
659
- const relativePath = path3.relative(this.lintRoot, filePath);
660
- if (!relativePath.startsWith("..") && !path3.isAbsolute(relativePath))
751
+ const relativePath = path2.relative(this.lintRoot, filePath);
752
+ if (!relativePath.startsWith("..") && !path2.isAbsolute(relativePath))
661
753
  return relativePath;
662
754
  return filePath;
663
755
  }
664
756
  #resolveFilePath(filePath) {
665
- return path3.isAbsolute(filePath) ? filePath : path3.join(this.lintRoot, filePath);
757
+ return path2.isAbsolute(filePath) ? filePath : path2.join(this.lintRoot, filePath);
666
758
  }
667
759
  async#runBiome(args, input) {
668
760
  return await new Promise((resolve, reject) => {
@@ -694,7 +786,7 @@ class Linter {
694
786
  const diagnosticPath = diagnostic.location?.path;
695
787
  if (!diagnosticPath)
696
788
  return fallbackFilePath;
697
- return path3.isAbsolute(diagnosticPath) ? diagnosticPath : path3.join(this.lintRoot, diagnosticPath);
789
+ return path2.isAbsolute(diagnosticPath) ? diagnosticPath : path2.join(this.lintRoot, diagnosticPath);
698
790
  }
699
791
  #createLintMessage(diagnostic) {
700
792
  const start = diagnostic.location?.start;
@@ -759,7 +851,7 @@ class Linter {
759
851
  "--max-diagnostics=none",
760
852
  "--no-errors-on-unmatched",
761
853
  "--config-path",
762
- path3.join(this.lintRoot, "biome.json"),
854
+ this.configPath,
763
855
  this.#toBiomePath(filePath)
764
856
  ]);
765
857
  const report = this.#parseBiomeReport(stdout || stderr);
@@ -880,14 +972,7 @@ ${errorText}, ${warningText} found`];
880
972
  if (!dryRun)
881
973
  return await this.#checkFile(resolvedFilePath, { write: true });
882
974
  const source = readFileSync(resolvedFilePath, "utf8");
883
- const { stdout } = await this.#runBiome([
884
- "check",
885
- "--write",
886
- "--config-path",
887
- path3.join(this.lintRoot, "biome.json"),
888
- "--stdin-file-path",
889
- this.#toBiomePath(resolvedFilePath)
890
- ], source);
975
+ const { stdout } = await this.#runBiome(["check", "--write", "--config-path", this.configPath, "--stdin-file-path", this.#toBiomePath(resolvedFilePath)], source);
891
976
  const lintResult = await this.lintFile(resolvedFilePath);
892
977
  return { ...lintResult, fixed: stdout !== source, output: stdout };
893
978
  }
@@ -895,7 +980,7 @@ ${errorText}, ${warningText} found`];
895
980
  const resolvedFilePath = this.#resolveFilePath(filePath);
896
981
  if (!existsSync(resolvedFilePath))
897
982
  throw new Error(`File not found: ${filePath}`);
898
- return JSON.parse(readFileSync(path3.join(this.lintRoot, "biome.json"), "utf8"));
983
+ return JSON.parse(readFileSync(this.configPath, "utf8"));
899
984
  }
900
985
  async getProblematicRules(filePath) {
901
986
  const { results } = await this.lintFile(filePath);
@@ -910,6 +995,31 @@ ${errorText}, ${warningText} found`];
910
995
  }
911
996
  }
912
997
 
998
+ // pkgs/@akanjs/devkit/repoIdentity.ts
999
+ import { execFileSync } from "child_process";
1000
+ import path3 from "path";
1001
+ var resolved = new Map;
1002
+ var readRemoteName = (workspaceRoot) => {
1003
+ try {
1004
+ const url = execFileSync("git", ["config", "--get", "remote.origin.url"], {
1005
+ cwd: workspaceRoot,
1006
+ encoding: "utf-8",
1007
+ stdio: ["ignore", "pipe", "ignore"]
1008
+ }).trim();
1009
+ return url.replace(/\.git$/, "").split(/[/:]/).pop() || null;
1010
+ } catch {
1011
+ return null;
1012
+ }
1013
+ };
1014
+ var resolveRepoName = (workspaceRoot) => {
1015
+ const cached = resolved.get(workspaceRoot);
1016
+ if (cached)
1017
+ return cached;
1018
+ const repoName = readRemoteName(workspaceRoot) ?? path3.basename(workspaceRoot);
1019
+ resolved.set(workspaceRoot, repoName);
1020
+ return repoName;
1021
+ };
1022
+
913
1023
  // pkgs/@akanjs/devkit/scanInfo.ts
914
1024
  import { rm } from "fs/promises";
915
1025
  import path4 from "path";
@@ -946,6 +1056,34 @@ var appRootAllowedDirs = new Set([
946
1056
  "ui",
947
1057
  "webkit"
948
1058
  ]);
1059
+ var libRootAllowedFiles = new Set([
1060
+ "AGENTS.md",
1061
+ "CLAUDE.md",
1062
+ "README.md",
1063
+ "akan.config.ts",
1064
+ "akan.lib.json",
1065
+ "client.ts",
1066
+ "index.ts",
1067
+ "package.json",
1068
+ "server.ts",
1069
+ "tsconfig.json",
1070
+ "tsconfig.spec.json",
1071
+ "tsconfig.tsbuildinfo"
1072
+ ]);
1073
+ var libRootAllowedDirs = new Set([
1074
+ "common",
1075
+ "env",
1076
+ "lib",
1077
+ "page",
1078
+ "plugin",
1079
+ "private",
1080
+ "public",
1081
+ "srvkit",
1082
+ "ui",
1083
+ "webkit"
1084
+ ]);
1085
+ var rootAllowedFiles = { app: appRootAllowedFiles, lib: libRootAllowedFiles };
1086
+ var rootAllowedDirs = { app: appRootAllowedDirs, lib: libRootAllowedDirs };
949
1087
  var libFacetRootAllowedFiles = new Set([
950
1088
  "cnst.ts",
951
1089
  "db.ts",
@@ -957,7 +1095,9 @@ var libFacetRootAllowedFiles = new Set([
957
1095
  "useClient.ts",
958
1096
  "useServer.ts"
959
1097
  ]);
960
- var isScannedAppRootEntry = (name) => !name.startsWith(".") || appRootAllowedDirs.has(name);
1098
+ var libFacetRootTestPattern = /^[A-Za-z][A-Za-z0-9_-]*\.signal\.(test|spec)\.(ts|tsx)$/;
1099
+ var isAllowedLibFacetRootFile = (filename) => libFacetRootAllowedFiles.has(filename) || libFacetRootTestPattern.test(filename);
1100
+ var isScannedRootEntry = (type, name) => !name.startsWith(".") || rootAllowedDirs[type].has(name);
961
1101
 
962
1102
  // pkgs/@akanjs/devkit/scanInfo.ts
963
1103
  var databaseFileTypes = [
@@ -986,10 +1126,8 @@ var moduleUiFileTypes = {
986
1126
  scalar: new Set(["Template", "Unit"])
987
1127
  };
988
1128
  var testFilePattern = /\.(test|spec)\.(ts|tsx)$/;
989
- var rootSignalTestFilePattern = /^[A-Za-z][A-Za-z0-9_-]*\.signal\.(test|spec)\.(ts|tsx)$/;
990
- var createDependencyScanner = async (exec) => (await import("./dependencyScanner-f6grrep3.js")).TypeScriptDependencyScanner.from(exec);
1129
+ var createDependencyScanner = async (exec) => (await import("./dependencyScanner-rbs2407b.js")).TypeScriptDependencyScanner.from(exec);
991
1130
  var isAllowedTestFile = (filename) => testFilePattern.test(filename);
992
- var isAllowedLibRootFile = (filename) => libFacetRootAllowedFiles.has(filename) || rootSignalTestFilePattern.test(filename);
993
1131
  var getScanPath = (exec, relativePath) => path4.posix.join(`${exec.type}s`, exec.name, relativePath.split(path4.sep).join("/"));
994
1132
  async function clearGeneratedRootCapacitorConfigs(exec) {
995
1133
  if (exec.type !== "app")
@@ -1006,17 +1144,20 @@ async function assertScanConvention(exec, libRoot) {
1006
1144
  const addViolation = (relativePath, reason) => {
1007
1145
  violations.push(`${getScanPath(exec, relativePath)}: ${reason}`);
1008
1146
  };
1009
- if (exec.type === "app") {
1010
- const { files, dirs } = await exec.getFilesAndDirs(".");
1011
- files.filter((filename) => !appRootAllowedFiles.has(filename)).forEach((filename) => {
1012
- addViolation(filename, "unsupported app root file");
1013
- });
1014
- dirs.filter((dirname) => !appRootAllowedDirs.has(dirname)).forEach((dirname) => {
1015
- addViolation(dirname, "unsupported app root folder");
1016
- });
1017
- }
1018
- libRoot.files.filter((filename) => !isAllowedLibRootFile(filename)).forEach((filename) => {
1019
- addViolation(path4.join("lib", filename), "unsupported lib root file");
1147
+ const allowedRootFiles = rootAllowedFiles[exec.type];
1148
+ const allowedRootDirs = rootAllowedDirs[exec.type];
1149
+ const { files, dirs } = await exec.getFilesAndDirs(".");
1150
+ files.filter((filename) => !allowedRootFiles.has(filename)).forEach((filename) => {
1151
+ addViolation(filename, `unsupported ${exec.type} root file`);
1152
+ });
1153
+ dirs.filter((dirname) => !allowedRootDirs.has(dirname)).forEach((dirname) => {
1154
+ addViolation(dirname, `unsupported ${exec.type} root folder`);
1155
+ });
1156
+ if (exec.type === "lib")
1157
+ for (const { relativePath, reason } of await exec.getPageConventionViolations())
1158
+ addViolation(relativePath, reason);
1159
+ libRoot.files.filter((filename) => !isAllowedLibFacetRootFile(filename)).forEach((filename) => {
1160
+ addViolation(path4.join("lib", filename), "unsupported lib facet root file");
1020
1161
  });
1021
1162
  libRoot.dirs.filter((dirname) => dirname.startsWith("__") && !internalLibDirs.has(dirname)).forEach((dirname) => {
1022
1163
  addViolation(path4.join("lib", dirname), "unsupported internal lib folder");
@@ -1196,12 +1337,11 @@ class ScanInfo {
1196
1337
  })
1197
1338
  ]);
1198
1339
  const routes = exec.type === "lib" ? [] : await exec.getPageKeys();
1199
- const scanResult = {
1340
+ const common = {
1200
1341
  name: exec.name,
1201
1342
  type: exec.type,
1202
1343
  repoName: exec.workspace.repoName,
1203
1344
  serveDomain: WorkspaceExecutor.getBaseDevEnv(path4.join(exec.workspace.workspaceRoot, ".env")).serveDomain,
1204
- akanConfig: akanConfig2,
1205
1345
  files,
1206
1346
  libDeps,
1207
1347
  pkgDeps,
@@ -1209,6 +1349,7 @@ class ScanInfo {
1209
1349
  devDependencies: npmDevDeps.filter((dep) => !isAkanFrameworkDependency(dep)),
1210
1350
  routes
1211
1351
  };
1352
+ const scanResult = akanConfig2 instanceof AkanAppConfig ? { ...common, akanConfig: akanConfig2 } : { ...common, akanConfig: akanConfig2 };
1212
1353
  return scanResult;
1213
1354
  }
1214
1355
  constructor(scanResult) {
@@ -1634,7 +1775,7 @@ class Executor {
1634
1775
  }));
1635
1776
  });
1636
1777
  proc.on("exit", (code, signal) => {
1637
- if (!!code || signal)
1778
+ if (code || signal)
1638
1779
  reject(new CommandExecutionError({
1639
1780
  command,
1640
1781
  cwd,
@@ -1732,7 +1873,7 @@ class Executor {
1732
1873
  }));
1733
1874
  });
1734
1875
  proc.on("exit", (code, signal) => {
1735
- if (!!code || signal)
1876
+ if (code || signal)
1736
1877
  reject(new CommandExecutionError({
1737
1878
  command: modulePath,
1738
1879
  args,
@@ -1819,7 +1960,8 @@ class Executor {
1819
1960
  const dir = path5.dirname(writePath);
1820
1961
  if (!await FileSys.dirExists(dir))
1821
1962
  await mkdir(dir, { recursive: true });
1822
- let contentStr = typeof content === "string" ? content : JSON.stringify(content, null, 2);
1963
+ let contentStr = typeof content === "string" ? content : `${JSON.stringify(content, null, 2)}
1964
+ `;
1823
1965
  if (await FileSys.fileExists(writePath)) {
1824
1966
  const currentContent = await FileSys.readText(writePath);
1825
1967
  if (currentContent === contentStr || !overwrite) {
@@ -2028,7 +2170,7 @@ class Executor {
2028
2170
  return this._applyTemplate({ ...options, dict });
2029
2171
  }
2030
2172
  async getTypeChecker() {
2031
- const { TypeChecker } = await import("./typeChecker-kravn7ns.js");
2173
+ const { TypeChecker } = await import("./typeChecker-g6bh0xfv.js");
2032
2174
  this.typeChecker ??= new TypeChecker(this);
2033
2175
  return this.typeChecker;
2034
2176
  }
@@ -2109,7 +2251,7 @@ class WorkspaceExecutor extends Executor {
2109
2251
  static #execs = new Map;
2110
2252
  static fromRoot({
2111
2253
  workspaceRoot = process.cwd(),
2112
- repoName = path5.basename(process.cwd())
2254
+ repoName = resolveRepoName(workspaceRoot)
2113
2255
  } = {}) {
2114
2256
  return WorkspaceExecutor.#execs.get(repoName) ?? new WorkspaceExecutor({ workspaceRoot, repoName });
2115
2257
  }
@@ -2297,6 +2439,18 @@ class SysExecutor extends Executor {
2297
2439
  const path6 = this.type === "app" ? `apps/${this.name}/lib` : `libs/${this.name}/lib`;
2298
2440
  return await this.workspace.getDirInModule(path6, this.name);
2299
2441
  }
2442
+ async getPageConventionViolations() {
2443
+ if (!await this.exists("page"))
2444
+ return [];
2445
+ const violations = [];
2446
+ for (const entry of await this.getAllFiles("**/*", { cwd: this.getPath("page") })) {
2447
+ const relativePath = entry.split(path5.sep).join("/");
2448
+ const reason = getPageSourceFileViolation(relativePath);
2449
+ if (reason)
2450
+ violations.push({ relativePath: `page/${relativePath}`, reason });
2451
+ }
2452
+ return violations;
2453
+ }
2300
2454
  #scanInfo = null;
2301
2455
  hasScanInfo() {
2302
2456
  return this.#scanInfo !== null;
@@ -2485,7 +2639,7 @@ class SysExecutor extends Executor {
2485
2639
  class AppExecutor extends SysExecutor {
2486
2640
  static #routeSourceValidator = null;
2487
2641
  static async#getRouteSourceValidator() {
2488
- AppExecutor.#routeSourceValidator ??= (await import("./routeSourceValidator-e4jmbfcx.js")).RouteSourceValidator;
2642
+ AppExecutor.#routeSourceValidator ??= (await import("./routeSourceValidator-7fycdqyv.js")).RouteSourceValidator;
2489
2643
  return AppExecutor.#routeSourceValidator;
2490
2644
  }
2491
2645
  dist;
@@ -2549,10 +2703,15 @@ class AppExecutor extends SysExecutor {
2549
2703
  await Promise.all([this.dist.mkdir("private"), this.dist.mkdir("public")]);
2550
2704
  await Promise.all([
2551
2705
  this.cp("private", `${this.dist.cwdPath}/private`, { dereference: true }),
2552
- this.cp("public", `${this.dist.cwdPath}/public`, { dereference: true })
2706
+ ...akanConfig2.web.ssr ? [this.cp("public", `${this.dist.cwdPath}/public`, { dereference: true })] : []
2553
2707
  ]);
2554
- } else
2708
+ } else {
2555
2709
  await this.removeDir(".akan");
2710
+ if (!akanConfig2.web.ssr || !akanConfig2.web.csr)
2711
+ this.logger.verbose(`akan.config.ts disables web.${!akanConfig2.web.ssr ? "ssr" : "csr"}; \`akan start\` still serves it, \`akan build\` will not`);
2712
+ }
2713
+ if (type === "start")
2714
+ process.env.NODE_ENV = "development";
2556
2715
  const devPort = type === "start" ? (await this.getDevPort()).toString() : undefined;
2557
2716
  const env = this.getCommandEnv({
2558
2717
  AKAN_COMMAND_TYPE: type,
@@ -2641,7 +2800,8 @@ class AppExecutor extends SysExecutor {
2641
2800
  }
2642
2801
  if (!owner)
2643
2802
  owners.set(routeId, { absPath, fromLib });
2644
- const isRootLayout = parsed.kind === "layout" && parsed.moduleSegments.at(-1) === "_layout";
2803
+ const layoutSegments = getRootBoundarySegments(key);
2804
+ const isRootLayout = layoutSegments !== null && isRootBoundarySegments(layoutSegments, akanConfig2.basePaths);
2645
2805
  const routeSource = await Bun.file(absPath).text();
2646
2806
  const validator = await AppExecutor.#getRouteSourceValidator();
2647
2807
  if (parsed.kind === "overrides")
@@ -2869,7 +3029,7 @@ class LibExecutor extends SysExecutor {
2869
3029
  async getConfig({ refresh } = {}) {
2870
3030
  if (this.#akanConfig && !refresh)
2871
3031
  return this.#akanConfig;
2872
- this.#akanConfig = await AkanLibConfig.from(this);
3032
+ this.#akanConfig = await AkanLibConfig.from(this, { bustImportCache: refresh });
2873
3033
  return this.#akanConfig;
2874
3034
  }
2875
3035
  }
@@ -2966,7 +3126,7 @@ class PkgExecutor extends Executor {
2966
3126
  default: "./index.ts"
2967
3127
  }
2968
3128
  },
2969
- engines: { bun: ">=1.3.13" },
3129
+ engines: { bun: ">=1.4.0" },
2970
3130
  ...dependencyMaps
2971
3131
  };
2972
3132
  await Promise.all([this.dist.writeJson("package.json", distPkgJson), this.writeJson("package.json", distPkgJson)]);
@@ -3009,4 +3169,4 @@ class ModuleExecutor extends Executor {
3009
3169
  }
3010
3170
  }
3011
3171
 
3012
- export { AGENT_BLOCK_START, AGENT_BLOCK_END, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, getDirname, appRootAllowedFiles, appRootAllowedDirs, libFacetRootAllowedFiles, isScannedAppRootEntry, CommandExecutionError, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
3172
+ export { AGENT_BLOCK_START, AGENT_BLOCK_END, stampBlockVersion, extractBlockVersion, readDevkitVersion, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, CLAUDE_COMMENT_RULE, rootAllowedFiles, rootAllowedDirs, isAllowedLibFacetRootFile, isScannedRootEntry, CommandExecutionError, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };