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

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 (140) 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-mjh5ppsq.js} +3 -5
  5. package/{agent.command-a3n15c6t.js → agent.command-d2gfxfck.js} +11 -13
  6. package/{application.command-rdm3et0g.js → application.command-pj2m7584.js} +65 -38
  7. package/{applicationBuildRunner-6m8n71w4.js → applicationBuildRunner-kxwbssgn.js} +27 -23
  8. package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-4yasxwv9.js} +8 -9
  9. package/buildBatch.proc.js +12 -14
  10. package/capacitorApp-36rbr858.js +12 -0
  11. package/{cloud.command-56aeekqn.js → cloud.command-gxqp8xdv.js} +15 -18
  12. package/commandManifest.json +1 -1
  13. package/{context.command-ysxawe7h.js → context.command-ez8a0zyz.js} +19 -23
  14. package/dependencyScanner-shs82ynp.js +8 -0
  15. package/devTui-40ggmd99.js +553 -0
  16. package/devTuiView-c08ccbat.js +9 -0
  17. package/getDirname-dr3jz1xg.js +7 -0
  18. package/{guideline.command-yqf9a372.js → guideline.command-xmqwx8zm.js} +24 -22
  19. package/guidelines/agentRule/agentRule.generate.json +31 -0
  20. package/guidelines/agentRule/agentRule.instruction.md +531 -0
  21. package/guidelines/conventions/conventions.instruction.md +493 -369
  22. package/guidelines/framework/framework.generate.json +3 -2
  23. package/guidelines/framework/framework.instruction.md +0 -9
  24. package/guidelines/mcpRule/mcpRule.generate.json +35 -0
  25. package/guidelines/mcpRule/mcpRule.instruction.md +460 -0
  26. package/guidelines/modelStore/modelStore.instruction.md +12 -0
  27. package/guidelines/modelTemplate/modelTemplate.instruction.md +5 -0
  28. package/guidelines/queryRule/queryRule.generate.json +31 -0
  29. package/guidelines/queryRule/queryRule.instruction.md +178 -0
  30. package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
  31. package/guidelines/runtimeRule/runtimeRule.instruction.md +220 -0
  32. package/guidelines/ssrRule/ssrRule.instruction.md +51 -5
  33. package/guidelines/transportRule/transportRule.generate.json +31 -0
  34. package/guidelines/transportRule/transportRule.instruction.md +60 -0
  35. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +54 -764
  36. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
  37. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +467 -0
  38. package/incrementalBuilder.proc.js +26 -25
  39. package/{index-8pd02prk.js → index-259dsnz3.js} +58 -25
  40. package/{index-yzsxc30b.js → index-2tv3fdx4.js} +975 -234
  41. package/index-3d9y066c.js +76 -0
  42. package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
  43. package/{index-m90fn8xe.js → index-4edzf1gr.js} +32 -32
  44. package/{index-3789fdpg.js → index-600zhnve.js} +94 -61
  45. package/{index-1577bej2.js → index-6wwzs1bc.js} +2 -2
  46. package/{index-cv9cxs5k.js → index-7737gxcp.js} +18 -18
  47. package/{index-a5cs7d8r.js → index-8few9nyh.js} +13 -13
  48. package/{index-mewacxye.js → index-8pm30m73.js} +57 -57
  49. package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
  50. package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
  51. package/{index-cav1azma.js → index-a64esmtb.js} +1106 -1369
  52. package/{index-nwqqssnb.js → index-aj7tyh5w.js} +26 -23
  53. package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
  54. package/{index-yzmqvg23.js → index-fz5q3gd7.js} +8 -8
  55. package/{index-kcsa1zff.js → index-gyd220p2.js} +4 -4
  56. package/{index-j37qq1f2.js → index-h7yw2z9n.js} +7 -7
  57. package/{index-bjpxzr6s.js → index-hwkygn9s.js} +51 -3
  58. package/index-j9yhg404.js +159 -0
  59. package/{index-46tjzh6s.js → index-kcxmv48c.js} +29 -29
  60. package/{index-0cj2zxbm.js → index-kn1h7p1x.js} +12 -11
  61. package/{index-e4b2ae6b.js → index-ktb5njgy.js} +41 -34
  62. package/{index-etwh7sd3.js → index-mak3cd28.js} +100 -32
  63. package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
  64. package/{index-z1s5f4e0.js → index-ne2qy0nk.js} +36 -37
  65. package/{index-65aeh789.js → index-pnqbkf5p.js} +1 -1
  66. package/{index-67546d0j.js → index-q0y2jq9j.js} +14 -2
  67. package/{index-4mgkgba3.js → index-rwg2aa4f.js} +14 -14
  68. package/{index-bzznxgcx.js → index-v0qh106m.js} +1002 -128
  69. package/{index-j9cxndc0.js → index-w8kmx1b6.js} +20 -11
  70. package/{index-h5whaj26.js → index-ws5e0j51.js} +16 -12
  71. package/{index-9va8zayb.js → index-wt7qrtd4.js} +27 -27
  72. package/index.js +22 -25
  73. package/{library.command-x6t29a30.js → library.command-nbsky672.js} +11 -10
  74. package/{localRegistry.command-649g1n7b.js → localRegistry.command-ts6t5e5a.js} +20 -23
  75. package/{module.command-8w8ys5t3.js → module.command-29vqzrh8.js} +13 -16
  76. package/{package.command-zgy7f3fz.js → package.command-axv0abmn.js} +8 -10
  77. package/package.json +5 -7
  78. package/{page.command-yjmnkyk2.js → page.command-vs9s3zrh.js} +7 -9
  79. package/{primitive.command-gfqaagsg.js → primitive.command-cbxmqbtc.js} +13 -16
  80. package/{quality.command-ec8r1dn3.js → quality.command-gmbs7nws.js} +184 -334
  81. package/recipeScanner-fpagtgc1.js +11 -0
  82. package/{repair.command-p9ey6mkm.js → repair.command-bqsjptsj.js} +12 -14
  83. package/{routeSourceValidator-e4jmbfcx.js → routeSourceValidator-apyqw7wk.js} +90 -19
  84. package/{scalar.command-9dhmqhtm.js → scalar.command-6k1vhe9s.js} +11 -14
  85. package/subspace.command-35a3t6vv.js +755 -0
  86. package/templates/app/env/env.client.debug.ts.template +1 -5
  87. package/templates/app/env/env.client.develop.ts.template +1 -5
  88. package/templates/app/env/env.client.local.ts.template +1 -5
  89. package/templates/app/env/env.client.main.ts.template +1 -5
  90. package/templates/app/env/env.client.testing.ts.template +1 -5
  91. package/templates/app/env/env.client.type.ts +2 -6
  92. package/templates/app/env/env.server.debug.ts.template +1 -5
  93. package/templates/app/env/env.server.develop.ts.template +1 -5
  94. package/templates/app/env/env.server.local.ts.template +1 -5
  95. package/templates/app/env/env.server.main.ts.template +1 -5
  96. package/templates/app/main.ts +3 -1
  97. package/templates/app/page/_index.tsx +3 -3
  98. package/templates/app/page/_layout.tsx +31 -32
  99. package/templates/appSample/lib/task/task.signal.ts +11 -6
  100. package/templates/appSample/page/task/[taskId]/_index.tsx +22 -27
  101. package/templates/appSample/page/task/[taskId]/edit.tsx +25 -30
  102. package/templates/appSample/page/task/_index.tsx +3 -7
  103. package/templates/appSample/page/task/_layout.tsx +4 -15
  104. package/templates/appSample/page/task/new.tsx +4 -10
  105. package/templates/appSample/srvkit/AuthGuard.ts +2 -2
  106. package/templates/crudPages/[__model__Id]/edit/page.tsx +27 -29
  107. package/templates/crudPages/[__model__Id]/page.tsx +24 -32
  108. package/templates/crudPages/new/page.tsx +26 -25
  109. package/templates/crudPages/page.tsx +27 -26
  110. package/templates/crudSinglePage/page.tsx +26 -21
  111. package/templates/env/_env.server.type.ts +7 -5
  112. package/templates/lib/db.ts +1 -1
  113. package/templates/lib/dict.ts +1 -1
  114. package/templates/lib/sig.ts +5 -1
  115. package/templates/lib/srv.ts +6 -2
  116. package/templates/module/__model__.dictionary.ts +4 -1
  117. package/templates/module/__model__.signal.ts +2 -3
  118. package/templates/module/__model__.store.ts +1 -2
  119. package/templates/workspaceRoot/.gitignore.template +0 -1
  120. package/templates/workspaceRoot/.husky/pre-commit.template +16 -0
  121. package/templates/workspaceRoot/.vscode/settings.json.template +1 -1
  122. package/templates/workspaceRoot/AGENTS.md.template +4 -0
  123. package/templates/workspaceRoot/CLAUDE.md.template +19 -0
  124. package/templates/workspaceRoot/biome.json.template +1 -1
  125. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +10 -14
  126. package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
  127. package/templates/workspaceRoot/package.json.template +2 -4
  128. package/typeChecker-3xgrzc2v.js +7 -0
  129. package/typecheck.proc.js +4 -5
  130. package/{workflow.command-ycwc6zr6.js → workflow.command-nwpcdc8p.js} +22 -25
  131. package/{workspace.command-xhyhajxa.js → workspace.command-aczjxzbf.js} +64 -66
  132. package/capacitorApp-mr81qdxq.js +0 -61
  133. package/dependencyScanner-f6grrep3.js +0 -9
  134. package/getDirname-m9s0cmhq.js +0 -8
  135. package/index-mxvakhsm.js +0 -66
  136. package/index-r24hmh0q.js +0 -4
  137. package/recipeScanner-tghkzrrt.js +0 -12
  138. package/typeChecker-kravn7ns.js +0 -8
  139. /package/{index-0wae5ebk.js → index-meh558jy.js} +0 -0
  140. /package/{index-ss469dec.js → index-nz8prx9g.js} +0 -0
@@ -1,13 +1,13 @@
1
1
  // @bun
2
- import {
3
- Spinner
4
- } from "./index-mxvakhsm.js";
5
2
  import {
6
3
  FileSys
7
- } from "./index-67546d0j.js";
4
+ } from "./index-q0y2jq9j.js";
5
+ import {
6
+ Spinner
7
+ } from "./index-2tv3fdx4.js";
8
8
 
9
9
  // pkgs/@akanjs/devkit/cloud/globalConfig.ts
10
- import { mkdir } from "fs/promises";
10
+ import { chmod, mkdir } from "fs/promises";
11
11
  import dayjs from "dayjs";
12
12
 
13
13
  // pkgs/@akanjs/devkit/cloud/constants.ts
@@ -34,8 +34,9 @@ class GlobalConfig {
34
34
  };
35
35
  }
36
36
  static async#setAkanGlobalConfig(akanConfig) {
37
- await mkdir(basePath, { recursive: true });
37
+ await mkdir(basePath, { recursive: true, mode: 448 });
38
38
  await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
39
+ await chmod(configPath, 384);
39
40
  }
40
41
  static async getHostConfig(host = GlobalConfig.akanCloudHost) {
41
42
  const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
@@ -240,7 +241,7 @@ import { ChatOpenAI } from "@langchain/openai";
240
241
  import { Logger } from "akanjs/common";
241
242
  import chalk from "chalk";
242
243
  var MAX_ASK_TRY = 300;
243
- var deepSeekLlmModels = ["deepseek-chat", "deepseek-reasoner"];
244
+ var deepSeekLlmModels = ["deepseek-v4-flash", "deepseek-v4-pro"];
244
245
  var openAiLlmModels = ["gpt-5.5"];
245
246
  var supportedLlmModels = [...deepSeekLlmModels, ...openAiLlmModels];
246
247
  var isOpenAiLlmModel = (model) => openAiLlmModels.includes(model);
@@ -275,10 +276,10 @@ class AiSession {
275
276
  static #chat = null;
276
277
  static async init({ temperature = 0, useExisting = true } = {}) {
277
278
  if (useExisting) {
278
- const llmConfig2 = await AiSession.getLlmConfig();
279
- if (llmConfig2) {
280
- AiSession.#setChatModel(llmConfig2.model, llmConfig2.apiKey);
281
- Logger.rawLog(chalk.dim(`\uD83E\uDD16akan editor uses existing LLM config (${llmConfig2.model})`));
279
+ const llmConfig = await AiSession.getLlmConfig();
280
+ if (llmConfig) {
281
+ AiSession.#setChatModel(llmConfig.model, llmConfig.apiKey);
282
+ Logger.rawLog(chalk.dim(`\uD83E\uDD16akan editor uses existing LLM config (${llmConfig.model})`));
282
283
  return AiSession;
283
284
  }
284
285
  } else
@@ -1,38 +1,45 @@
1
1
  // @bun
2
2
  import {
3
- workflowRunArtifactPath,
4
- workflowSyncDir
5
- } from "./index-kcsa1zff.js";
6
- import {
7
- AppExecutor,
8
- LibExecutor,
9
- appRootAllowedDirs,
10
- appRootAllowedFiles,
11
3
  extractBlockVersion,
12
- isScannedAppRootEntry,
13
- readDevkitVersion
14
- } from "./index-yzsxc30b.js";
15
- import {
16
- collectRecipeSources,
17
- findInlineRecipeDuplicates,
18
- scanRecipes
19
- } from "./index-xys926f2.js";
4
+ readDevkitVersion,
5
+ rootAllowedFiles,
6
+ rootAllowedDirs,
7
+ isScannedRootEntry,
8
+ AppExecutor,
9
+ LibExecutor
10
+ } from "./index-2tv3fdx4.js";
20
11
  import {
21
12
  FileSys
22
- } from "./index-67546d0j.js";
13
+ } from "./index-q0y2jq9j.js";
14
+ import {
15
+ collectRecipeSources2,
16
+ scanRecipes2,
17
+ findInlineRecipeDuplicates2
18
+ } from "./index-by5gpp8x.js";
19
+ import {
20
+ workflowRunArtifactPath,
21
+ workflowSyncDir
22
+ } from "./index-gyd220p2.js";
23
23
 
24
24
  // pkgs/@akanjs/devkit/akanContext.ts
25
25
  import { readdir } from "fs/promises";
26
26
  import path from "path";
27
27
  import { capitalize } from "akanjs/common";
28
- var resourceList = [
28
+ var guidelineResourceUri = (name) => `akan://guidelines/${name}`;
29
+ var staticResourceList = [
29
30
  { uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
30
- { uri: "akan://guidelines/framework", name: "Framework guideline", mimeType: "text/markdown" },
31
- { uri: "akan://guidelines/modelSignal", name: "Model signal guideline", mimeType: "text/markdown" },
32
31
  { uri: "akan://workspace/summary", name: "Workspace summary", mimeType: "application/json" },
33
32
  { uri: "akan://workspace/apps", name: "Workspace apps", mimeType: "application/json" },
34
33
  { uri: "akan://workspace/modules", name: "Workspace modules", mimeType: "application/json" }
35
34
  ];
35
+ var buildResourceList = (guidelineNames) => [
36
+ ...staticResourceList,
37
+ ...guidelineNames.map((name) => ({
38
+ uri: guidelineResourceUri(name),
39
+ name: `${name} guideline`,
40
+ mimeType: "text/markdown"
41
+ }))
42
+ ];
36
43
  var cursorMcpConfigPath = ".cursor/mcp.json";
37
44
  var claudeMcpConfigPath = ".mcp.json";
38
45
  var codexMcpConfigPath = ".codex/config.toml";
@@ -404,19 +411,19 @@ class AkanContextAnalyzer {
404
411
  repairAction("generated", "akan repair generated --app <app-or-lib>", "Refresh generated Akan files.", true),
405
412
  repairAction("format", "akan repair format --target <app-or-lib-or-pkg>", "Run the formatter/linter repair path.", true)
406
413
  ];
407
- for (const app of context.apps) {
408
- const appPath = path.join(workspace.workspaceRoot, app.path);
409
- for (const entry of await safeReadDir(appPath)) {
410
- if (!isScannedAppRootEntry(entry.name))
414
+ for (const sys of [...context.apps, ...context.libs]) {
415
+ const sysPath = path.join(workspace.workspaceRoot, sys.path);
416
+ for (const entry of await safeReadDir(sysPath)) {
417
+ if (!isScannedRootEntry(sys.type, entry.name))
411
418
  continue;
412
- const allowed = entry.isDirectory() ? appRootAllowedDirs.has(entry.name) : appRootAllowedFiles.has(entry.name);
419
+ const allowed = entry.isDirectory() ? rootAllowedDirs[sys.type].has(entry.name) : rootAllowedFiles[sys.type].has(entry.name);
413
420
  if (!allowed) {
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);
421
+ const action = repairAction("module-shape", `akan repair module-shape --app ${sys.name}`, `Review ${sys.type} root shape and remove or move the unknown entry.`, false);
415
422
  diagnostics.push({
416
423
  severity: "error",
417
- code: "app-root-unknown-entry",
418
- path: `${app.path}/${entry.name}`,
419
- message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in app root: ${app.path}/${entry.name}`,
424
+ code: `${sys.type}-root-unknown-entry`,
425
+ path: `${sys.path}/${entry.name}`,
426
+ message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in ${sys.type} root: ${sys.path}/${entry.name}`,
420
427
  repairActions: [action]
421
428
  });
422
429
  repairActions.push(action);
@@ -486,10 +493,10 @@ class AkanContextAnalyzer {
486
493
  }
487
494
  }
488
495
  for (const sys of [...context.apps, ...context.libs]) {
489
- const sources = await collectRecipeSources(path.join(workspace.workspaceRoot, sys.path, "ui"), "ui");
496
+ const sources = await collectRecipeSources2(path.join(workspace.workspaceRoot, sys.path, "ui"), "ui");
490
497
  if (sources.length === 0)
491
498
  continue;
492
- const recipes = scanRecipes(sources);
499
+ const recipes = scanRecipes2(sources);
493
500
  const files = [];
494
501
  const glob = new Bun.Glob("**/*.tsx");
495
502
  for await (const abs of glob.scan({ cwd: path.join(workspace.workspaceRoot, sys.path), absolute: true })) {
@@ -500,7 +507,7 @@ class AkanContextAnalyzer {
500
507
  content: await Bun.file(abs).text().catch(() => "")
501
508
  });
502
509
  }
503
- const duplicates = findInlineRecipeDuplicates(recipes, files);
510
+ const duplicates = findInlineRecipeDuplicates2(recipes, files);
504
511
  if (duplicates.length === 0)
505
512
  continue;
506
513
  const preview = duplicates.slice(0, 3).map((duplicate) => `${path.relative(workspace.workspaceRoot, duplicate.path)}:${duplicate.line}`).join(", ");
@@ -511,7 +518,7 @@ class AkanContextAnalyzer {
511
518
  message: `${sys.name}: ${duplicates.length} inline className(s) re-author a recipe fingerprint (${preview}${duplicates.length > 3 ? ", \u2026" : ""}) \u2014 consume the recipe instead.`
512
519
  });
513
520
  }
514
- const scanNames = async (uiDirPath, basename) => new Set(scanRecipes(await collectRecipeSources(uiDirPath, "ui", basename)).map((info) => info.name));
521
+ const scanNames = async (uiDirPath, basename) => new Set(scanRecipes2(await collectRecipeSources2(uiDirPath, "ui", basename)).map((info) => info.name));
515
522
  const declaredByImport = new Map;
516
523
  declaredByImport.set("akanjs/ui", await scanNames(path.join(workspace.workspaceRoot, "pkgs/akanjs/ui"), "recipe"));
517
524
  for (const sys of [...context.apps, ...context.libs])
@@ -626,4 +633,4 @@ class AkanContextAnalyzer {
626
633
  }
627
634
  }
628
635
 
629
- export { resourceList, codexMcpConfigPath, akanMcpInstallTargets, akanMcpInstallConfigPaths, createAkanMcpServer, createAkanCodexMcpServerBlock, upsertCodexMcpServerBlock, renderDoctorText, AkanContextAnalyzer };
636
+ export { buildResourceList, codexMcpConfigPath, akanMcpInstallTargets, akanMcpInstallConfigPaths, createAkanMcpServer, createAkanCodexMcpServerBlock, upsertCodexMcpServerBlock, renderDoctorText, AkanContextAnalyzer };
@@ -1,21 +1,18 @@
1
1
  // @bun
2
2
  import {
3
- AppExecutor,
3
+ FileSys
4
+ } from "./index-q0y2jq9j.js";
5
+ import {
4
6
  Executor,
7
+ WorkspaceExecutor,
8
+ AppExecutor,
5
9
  LibExecutor,
6
- ModuleExecutor,
7
10
  PkgExecutor,
8
- WorkspaceExecutor
9
- } from "./index-yzsxc30b.js";
10
- import {
11
- getDirname
12
- } from "./index-1577bej2.js";
13
- import {
14
- FileSys
15
- } from "./index-67546d0j.js";
11
+ ModuleExecutor
12
+ } from "./index-2tv3fdx4.js";
16
13
  import {
17
- __require
18
- } from "./index-r24hmh0q.js";
14
+ getDirname2
15
+ } from "./index-6wwzs1bc.js";
19
16
 
20
17
  // pkgs/@akanjs/devkit/commandDecorators/targetMeta.ts
21
18
  var COMMAND_META = Symbol("akan.command.meta");
@@ -54,6 +51,7 @@ var normalizePrimitiveArgType = (type) => {
54
51
  throw new Error(`Invalid primitive argument type: ${type}`);
55
52
  };
56
53
  var App = createInternalArgToken("App");
54
+ var Apps = createInternalArgToken("Apps");
57
55
  var Lib = createInternalArgToken("Lib");
58
56
  var Sys = createInternalArgToken("Sys");
59
57
  var Exec = createInternalArgToken("Exec");
@@ -62,11 +60,29 @@ var Module = createInternalArgToken("Module");
62
60
  var Workspace = createInternalArgToken("Workspace");
63
61
 
64
62
  // pkgs/@akanjs/devkit/commandDecorators/command.ts
65
- import path from "path";
63
+ import path2 from "path";
66
64
  import { Logger } from "akanjs/common";
67
65
  import chalk2 from "chalk";
68
66
  import { program } from "commander";
69
67
 
68
+ // pkgs/@akanjs/devkit/appSelectionMemory.ts
69
+ import path from "path";
70
+ class AppSelectionMemory {
71
+ static pathIn(workspaceRoot) {
72
+ return path.join(workspaceRoot, "local", ".akan", "lastStart.json");
73
+ }
74
+ static async read(workspaceRoot) {
75
+ const stored = await Bun.file(AppSelectionMemory.pathIn(workspaceRoot)).json().catch(() => null);
76
+ const apps = stored?.apps;
77
+ return Array.isArray(apps) ? apps.filter((name) => typeof name === "string") : [];
78
+ }
79
+ static async write(workspaceRoot, apps) {
80
+ await FileSys.writeJson(AppSelectionMemory.pathIn(workspaceRoot), { apps }).catch(() => {
81
+ return;
82
+ });
83
+ }
84
+ }
85
+
70
86
  // pkgs/@akanjs/devkit/commandDecorators/dependencyBuilder.ts
71
87
  var capitalize = (value) => value.slice(0, 1).toUpperCase() + value.slice(1);
72
88
  var createDependencyKey = (refName, kind) => `${refName}${capitalize(kind)}`;
@@ -264,6 +280,8 @@ var formatCommandHelp = (command, key) => {
264
280
  return "";
265
281
  if (arg.type === "Module")
266
282
  return "[sys:module]";
283
+ if (arg.type === "Apps")
284
+ return "[apps...]";
267
285
  if (arg.type === "Argument") {
268
286
  return `[${camelToKebabCase2(arg.name)}]`;
269
287
  }
@@ -290,6 +308,9 @@ var formatCommandHelp = (command, key) => {
290
308
  } else if (arg.type === "Module") {
291
309
  argName = "sys:module";
292
310
  argDesc = "Module in format: app-name:module-name or lib-name:module-name";
311
+ } else if (arg.type === "Apps") {
312
+ argName = "apps...";
313
+ argDesc = "App names, space- or comma-separated, or all. Omit to pick them interactively";
293
314
  } else {
294
315
  argName = arg.type.toLowerCase();
295
316
  argDesc = `${arg.type} name in this workspace`;
@@ -383,6 +404,17 @@ var prompts = async () => await import("@inquirer/prompts");
383
404
  var select = (config, context) => prompts().then((m) => m.select(config, context));
384
405
  var confirm = (config, context) => prompts().then((m) => m.confirm(config, context));
385
406
  var input = (config, context) => prompts().then((m) => m.input(config, context));
407
+ var checkbox = (config, context) => prompts().then((m) => m.checkbox(config, context));
408
+ var assertEnumChoice = (argMeta, value) => {
409
+ const enumChoices = argMeta.argsOption.enum;
410
+ if (!enumChoices || typeof enumChoices === "function")
411
+ return;
412
+ const choices = normalizeEnumChoices(enumChoices);
413
+ if (choices.some((choice) => String(choice.value) === String(value)))
414
+ return;
415
+ const label = argMeta.type === "Option" ? `option '--${camelToKebabCase3(argMeta.name)}'` : `argument '${argMeta.name}'`;
416
+ throw new Error(`${label} argument '${String(value)}' is invalid. Allowed choices are ${choices.map((choice) => choice.name).join(", ")}.`);
417
+ };
386
418
  var resolveEnumChoices = async (argMeta, context) => {
387
419
  const enumChoices = argMeta.argsOption.enum;
388
420
  if (!enumChoices)
@@ -396,9 +428,10 @@ var getOptionValue = async (argMeta, opt, context) => {
396
428
  name,
397
429
  argsOption: { enum: enumChoices, default: defaultValue, type, desc, nullable, example, ask }
398
430
  } = argMeta;
399
- if (opt[argMeta.name] !== undefined)
431
+ if (opt[argMeta.name] !== undefined) {
432
+ assertEnumChoice(argMeta, opt[argMeta.name]);
400
433
  return convertArgValue(opt[argMeta.name], type ?? "string");
401
- else if (defaultValue !== undefined)
434
+ } else if (defaultValue !== undefined)
402
435
  return defaultValue;
403
436
  if (enumChoices) {
404
437
  const choices = normalizeEnumChoices(await resolveEnumChoices(argMeta, context) ?? []);
@@ -424,9 +457,10 @@ var getArgumentValue = async (argMeta, value) => {
424
457
  name,
425
458
  argsOption: { default: defaultValue, type, desc, nullable, example, ask }
426
459
  } = argMeta;
427
- if (value !== undefined)
460
+ if (value !== undefined) {
461
+ assertEnumChoice(argMeta, value);
428
462
  return convertArgValue(value, type ?? "string");
429
- else if (defaultValue !== undefined)
463
+ } else if (defaultValue !== undefined)
430
464
  return defaultValue;
431
465
  else if (nullable)
432
466
  return null;
@@ -465,6 +499,31 @@ var assertCurrentDirectoryIsWorkspaceRoot = async () => {
465
499
  ].join(`
466
500
  `));
467
501
  };
502
+ var parseAppNameList = (value) => (Array.isArray(value) ? value : value === undefined ? [] : [value]).flatMap((entry) => entry.split(",")).map((entry) => entry.trim()).filter(Boolean);
503
+ var getAppsArgumentValue = async (value, workspace) => {
504
+ const appNames = await workspace.getApps();
505
+ if (appNames.length === 0)
506
+ throw new Error("No apps found in this workspace (apps/<appName>/akan.config.ts)");
507
+ const requested = parseAppNameList(value);
508
+ if (requested.includes("all"))
509
+ return appNames.map((name) => AppExecutor.from(workspace, name));
510
+ if (requested.length) {
511
+ const unknown = requested.filter((name) => !appNames.includes(name));
512
+ if (unknown.length)
513
+ throw new Error(`Unknown app${unknown.length > 1 ? "s" : ""}: ${unknown.join(", ")}. Available: ${appNames.join(", ")}, all`);
514
+ return [...new Set(requested)].map((name) => AppExecutor.from(workspace, name));
515
+ }
516
+ if (appNames.length === 1 && appNames[0])
517
+ return [AppExecutor.from(workspace, appNames[0])];
518
+ const remembered = new Set(await AppSelectionMemory.read(workspace.workspaceRoot));
519
+ const picked = await checkbox({
520
+ message: "Select the apps to run (space to toggle, enter to confirm)",
521
+ choices: appNames.map((name) => ({ name, value: name, checked: remembered.has(name) })),
522
+ required: true
523
+ });
524
+ await AppSelectionMemory.write(workspace.workspaceRoot, picked);
525
+ return picked.map((name) => AppExecutor.from(workspace, name));
526
+ };
468
527
  var getInternalArgumentValue = async (argMeta, value, workspace) => {
469
528
  if (argMeta.type === "Workspace")
470
529
  return workspace;
@@ -528,36 +587,36 @@ var getInternalArgumentValue = async (argMeta, value, workspace) => {
528
587
  return PkgExecutor.from(workspace, pkgName);
529
588
  } else if (sysType === "module") {
530
589
  if (value) {
531
- const [sysName, moduleName2] = value.split(":");
532
- if (!sysName || !moduleName2)
590
+ const [sysName, moduleName] = value.split(":");
591
+ if (!sysName || !moduleName)
533
592
  throw new Error(`Invalid module name: ${value}`);
534
593
  if (appNames.includes(sysName)) {
535
594
  const app = AppExecutor.from(workspace, sysName);
536
- const modules2 = await app.getModules();
537
- if (modules2.includes(moduleName2))
538
- return ModuleExecutor.from(app, moduleName2);
595
+ const modules = await app.getModules();
596
+ if (modules.includes(moduleName))
597
+ return ModuleExecutor.from(app, moduleName);
539
598
  else
540
- throw new Error(`Invalid module name: ${moduleName2}`);
599
+ throw new Error(`Invalid module name: ${moduleName}`);
541
600
  } else if (libNames.includes(sysName)) {
542
601
  const lib = LibExecutor.from(workspace, sysName);
543
- const modules2 = await lib.getModules();
544
- if (modules2.includes(moduleName2))
545
- return ModuleExecutor.from(lib, moduleName2);
602
+ const modules = await lib.getModules();
603
+ if (modules.includes(moduleName))
604
+ return ModuleExecutor.from(lib, moduleName);
546
605
  } else
547
606
  throw new Error(`Invalid system name: ${sysName}`);
548
607
  }
549
608
  const { type, name } = await select({
550
609
  message: `select the App or Lib name`,
551
610
  choices: [
552
- ...appNames.map((name2) => ({ name: name2, value: { type: "app", name: name2 } })),
553
- ...libNames.map((name2) => ({ name: name2, value: { type: "lib", name: name2 } }))
611
+ ...appNames.map((name) => ({ name, value: { type: "app", name } })),
612
+ ...libNames.map((name) => ({ name, value: { type: "lib", name } }))
554
613
  ]
555
614
  });
556
615
  const executor = type === "app" ? AppExecutor.from(workspace, name) : LibExecutor.from(workspace, name);
557
616
  const modules = await executor.getModules();
558
617
  const moduleName = await select({
559
618
  message: `Select the module name`,
560
- choices: modules.map((name2) => ({ name: `${executor.name}:${name2}`, value: name2 }))
619
+ choices: modules.map((name) => ({ name: `${executor.name}:${name}`, value: name }))
561
620
  });
562
621
  return ModuleExecutor.from(executor, moduleName);
563
622
  } else
@@ -568,8 +627,8 @@ var runCommands = async (...commands) => {
568
627
  printCliError(error);
569
628
  process.exit(1);
570
629
  });
571
- const __dirname2 = getDirname(import.meta.url);
572
- const packageJsonCandidates = [`${path.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
630
+ const __dirname2 = getDirname2(import.meta.url);
631
+ const packageJsonCandidates = [`${path2.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
573
632
  let cliPackageJson = null;
574
633
  for (const packageJsonPath of packageJsonCandidates) {
575
634
  if (!await FileSys.fileExists(packageJsonPath))
@@ -616,6 +675,8 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
616
675
  continue;
617
676
  else if (argMeta.type === "Module") {
618
677
  programCommand = programCommand.argument(`[sys-name:module-name]`, `${argMeta.type} in this workspace (apps|libs)/<sys-name>/lib/<module-name>`);
678
+ } else if (argMeta.type === "Apps") {
679
+ programCommand = programCommand.argument(`[apps...]`, `apps in this workspace apps/<appName>, or all (space- or comma-separated; omit to pick interactively)`);
619
680
  } else {
620
681
  const sysType = argMeta.type.toLowerCase();
621
682
  programCommand = programCommand.argument(`[${sysType}]`, `${sysType} in this workspace ${sysType}s/<${sysType}Name>`);
@@ -640,10 +701,17 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
640
701
  commandArgs[argMeta.idx] = await getOptionValue(argMeta, opt, commandContext);
641
702
  else if (argMeta.type === "Argument")
642
703
  commandArgs[argMeta.idx] = await getArgumentValue(argMeta, cmdArgs[argMeta.idx]);
704
+ else if (argMeta.type === "Apps")
705
+ commandArgs[argMeta.idx] = await getAppsArgumentValue(cmdArgs[argMeta.idx], workspace);
643
706
  else
644
707
  commandArgs[argMeta.idx] = await getInternalArgumentValue(argMeta, cmdArgs[argMeta.idx], workspace);
645
708
  if (commandArgs[argMeta.idx] instanceof AppExecutor)
646
709
  process.env.AKAN_PUBLIC_APP_NAME = commandArgs[argMeta.idx].name;
710
+ else if (Array.isArray(commandArgs[argMeta.idx])) {
711
+ const apps = commandArgs[argMeta.idx];
712
+ if (apps.length === 1 && apps[0])
713
+ process.env.AKAN_PUBLIC_APP_NAME = apps[0].name;
714
+ }
647
715
  assignCommandContext(commandContext, argMeta, commandArgs[argMeta.idx]);
648
716
  if (opt.verbose)
649
717
  Executor.setVerbose(true);
@@ -763,4 +831,4 @@ function command(refName, depsOrBuilder, builder) {
763
831
  }
764
832
  return CommandBase;
765
833
  }
766
- export { getTargetMetas, getTargetCommandNames, App, Lib, Sys, Exec, Pkg, Module, Workspace, CommandContainer, runner, script, runCommands, command };
834
+ export { getTargetMetas, getTargetCommandNames, App, Apps, Lib, Sys, Exec, Pkg, Module, Workspace, CommandContainer, runner, script, runCommands, command };
@@ -1,20 +1,11 @@
1
1
  // @bun
2
2
  // pkgs/@akanjs/devkit/frontendBuild/styleContract.ts
3
- var countBlocking = (v) => v.style.filter((s) => s.severity === "error").length + v.theme.length;
4
- var formatStyleContract = (v) => {
5
- const lines = [];
6
- for (const s of v.style) {
7
- lines.push(` [${s.severity}] ${s.rule} ${s.path}:${s.line}`);
8
- lines.push(` ${s.snippet}`);
9
- lines.push(` \u2192 ${s.suggestion}`);
10
- }
11
- for (const t of v.theme) {
12
- lines.push(` [error] contrast ${t.scope} ${t.pair} = ${t.ratio}:1 (min ${t.threshold}:1)`);
13
- lines.push(` \u2192 ${t.suggestion}`);
14
- }
15
- return lines.join(`
3
+ var countBlocking = (violations) => violations.theme.length;
4
+ var formatStyleContract = (violations) => violations.theme.flatMap((theme) => [
5
+ ` [error] contrast ${theme.scope} ${theme.pair} = ${theme.ratio}:1 (min ${theme.threshold}:1)`,
6
+ ` \u2192 ${theme.suggestion}`
7
+ ]).join(`
16
8
  `);
17
- };
18
9
 
19
10
  // pkgs/@akanjs/devkit/frontendBuild/themeValidator.ts
20
11
  var PAIRS = [
@@ -66,7 +57,7 @@ class ThemeValidator {
66
57
  foreground: front,
67
58
  ratio: Math.round(ratio * 100) / 100,
68
59
  threshold,
69
- suggestion: `${scope}\uC758 --${base}(${bg})\uC640 --${fg}(${front}) \uB300\uBE44\uAC00 ${ratio.toFixed(2)}:1 \uB85C \uCD5C\uC18C ${threshold}:1 \uBBF8\uB9CC\uC785\uB2C8\uB2E4. \uD55C\uCABD\uC744 \uB354 \uBC1D\uAC8C/\uC5B4\uB461\uAC8C \uC870\uC815\uD574 \uB300\uBE44\uB97C \uD655\uBCF4\uD558\uC138\uC694.`
60
+ suggestion: `In ${scope}, --${base} (${bg}) against --${fg} (${front}) is ${ratio.toFixed(2)}:1, under the ${threshold}:1 minimum. Lighten or darken one of them until it clears.`
70
61
  });
71
62
  }
72
63
  return violations;
@@ -1,28 +1,29 @@
1
1
  // @bun
2
- import {
3
- AkanContextAnalyzer
4
- } from "./index-e4b2ae6b.js";
5
- import {
6
- Prompter
7
- } from "./index-j37qq1f2.js";
8
2
  import {
9
3
  runner,
10
4
  script
11
- } from "./index-etwh7sd3.js";
5
+ } from "./index-mak3cd28.js";
12
6
  import {
13
- AGENT_BLOCK_END,
14
7
  AGENT_BLOCK_START,
15
- AppExecutor,
16
- LibExecutor,
8
+ AGENT_BLOCK_END,
9
+ stampBlockVersion,
17
10
  readDevkitVersion,
11
+ upsertAgentBlock,
18
12
  renderRecipeEntries,
19
- stampBlockVersion,
20
- upsertAgentBlock
21
- } from "./index-yzsxc30b.js";
13
+ CLAUDE_COMMENT_RULE,
14
+ AppExecutor,
15
+ LibExecutor
16
+ } from "./index-2tv3fdx4.js";
22
17
  import {
23
- collectRecipeSources,
24
- scanRecipes
25
- } from "./index-xys926f2.js";
18
+ collectRecipeSources2,
19
+ scanRecipes2
20
+ } from "./index-by5gpp8x.js";
21
+ import {
22
+ AkanContextAnalyzer
23
+ } from "./index-ktb5njgy.js";
24
+ import {
25
+ Prompter
26
+ } from "./index-h7yw2z9n.js";
26
27
 
27
28
  // pkgs/@akanjs/cli/agent/agent.script.ts
28
29
  import { Logger as Logger2 } from "akanjs/common";
@@ -76,8 +77,8 @@ Keep a sample only while you are still learning its pattern; delete it once your
76
77
  `;
77
78
  };
78
79
  var renderRecipeIndex = async (workspace) => {
79
- const sources = await collectRecipeSources(`${workspace.workspaceRoot}/pkgs/akanjs/ui`, "akanjs/ui", "recipe");
80
- const recipes = scanRecipes(sources);
80
+ const sources = await collectRecipeSources2(`${workspace.workspaceRoot}/pkgs/akanjs/ui`, "akanjs/ui", "recipe");
81
+ const recipes = scanRecipes2(sources);
81
82
  const scopeIndexPointer = `App and lib recipes are **not** listed here. Each app/lib carries its own generated index \u2014
82
83
  \`apps/<app>/AGENTS.md\` / \`libs/<lib>/AGENTS.md\` (\`## Recipes In Scope\`) \u2014 regenerated by \`akan sync\` and
83
84
  verified by \`akan lint\`. When working inside an app or lib, consult that file before consuming or authoring a look.`;
@@ -89,15 +90,14 @@ ${scopeIndexPointer}
89
90
  `;
90
91
  return `## Recipes
91
92
 
92
- Framework UI recipes (Tailwind-variant look factories), importable from every app and lib. Consume by exact name \u2014
93
- \`import { <name> } from "akanjs/ui"\`, then \`<name>(variants?, className?)\`. The second arg merges internally and
94
- takes **an array too**, so never wrap it in \`cn()\`: \`<name>({}, ["h-full", isWide && "w-full", className])\`.
95
- Do not guess recipe names, import paths, or variant values; the list below carries
96
- the full contract (\`*\` marks the default, \`key?\` is a boolean flag), so there is no need to open the recipe file to
97
- consume one. tsc still reports variant mistakes. **Before inlining a repeated surface (card, box,
98
- tile, \u2026): reuse a recipe, or add one as \`apps/<app>/ui/Recipe/<name>.ts\` (one recipe per file, re-exported from
99
- that folder's \`index.ts\`) \u2014 never re-implement the same look inline in several places, and never author a
100
- near-duplicate.** Full authoring/consumption policy: the \`recipeRule\` guideline.
93
+ Framework UI recipes (Tailwind-variant look factories), importable from every app and lib: \`import { <name> } from
94
+ "akanjs/ui"\`, then \`<name>(variants?, className?)\`. The second arg merges internally and takes **an array too**, so
95
+ never wrap it in \`cn()\`: \`<name>({}, ["h-full", isWide && "w-full", className])\`. The list below is the full
96
+ contract (\`*\` marks the default, \`key?\` is a boolean flag) \u2014 do not guess a name, path, or variant value, and do
97
+ not open the recipe file to consume one. **Before inlining a repeated surface (card, box, tile, \u2026): reuse a recipe,
98
+ or add one as \`apps/<app>/ui/Recipe/<name>.ts\`, one per file, re-exported from that folder's \`index.ts\` \u2014 never
99
+ re-implement the same look inline in several places, and never author a near-duplicate.** Full policy: the
100
+ \`recipeRule\` guideline.
101
101
 
102
102
  ${renderRecipeEntries(recipes)}
103
103
 
@@ -147,15 +147,12 @@ If generated output is stale or broken, update the owning source file and run \`
147
147
 
148
148
  ${recipeIndex}## MCP Workflow Policy
149
149
 
150
- - Prefer Akan MCP workflows before direct source edits.
151
- - Direct source edits are denied when an allowlisted Akan workflow or repair tool can perform the change.
152
- - Use \`akan mcp --mode plan\` to inspect \`list_workflows\`, \`explain_workflow\`, and \`plan_workflow\`.
153
- - If \`plan_workflow\` returns \`planPath\` or \`next.tool=apply_workflow\`, call \`apply_workflow({ planPath })\` before editing source files directly.
154
- - Use \`akan mcp --mode apply\` only for allowlisted \`apply_workflow\`, \`run_validation\`, and repair tools.
155
- - After \`apply_workflow\`, run \`run_validation\` with \`validationTarget\` when present; otherwise use \`applyReportPath\`.
156
- - If no workflow exists, or apply reports unsupported/no-op/failed diagnostics that require manual action, keep edits scoped to owning source files and never patch generated files directly.
157
- - For compound requests, split the request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
158
- - **CLI-only fallback (MCP not connected):** \`akan mcp\` starts a stdio MCP server, so the \`list_workflows\`/\`plan_workflow\`/\`apply_workflow\` tools exist only when your agent is wired to it as an MCP client. When they are unavailable, the CLI is a first-class equivalent: \`akan workflow list\` / \`explain <name>\` / \`plan <name> ... --format json --out <planPath>\` / \`apply <planPath> --format json\`, \`akan doctor --strict --format json\` for validation, and \`akan repair generated|imports|module-shape --app <app> --format json\` for repairs. Scaffolding primitives (\`create-module\`/\`create-scalar\`/\`create-service\` take the target app/lib as a POSITIONAL arg; \`add-field\`/\`add-enum-field\` use \`--app\`/\`--module\` flags) call the same code the workflows do.
150
+ - **Prefer an Akan workflow to a direct source edit.** A direct edit is denied when an allowlisted workflow or repair tool can make the change.
151
+ - Inspect with \`akan mcp --mode plan\` (\`list_workflows\`, \`explain_workflow\`, \`plan_workflow\`); apply with \`akan mcp --mode apply\`, which allowlists \`apply_workflow\`, \`run_validation\`, and the repair tools.
152
+ - If \`plan_workflow\` returns \`planPath\` or \`next.tool=apply_workflow\`, call \`apply_workflow({ planPath })\` before editing source. Then run \`run_validation\` with \`validationTarget\` when present, otherwise \`applyReportPath\`.
153
+ - Split a compound request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
154
+ - When no workflow exists, or apply reports unsupported/no-op/failed diagnostics needing manual action, keep edits scoped to owning source files and never patch generated files directly.
155
+ - **MCP not connected?** The CLI is a first-class equivalent \u2014 \`akan workflow list\` / \`explain\` / \`plan\` / \`apply\`, \`akan doctor\`, \`akan repair\`. See the onboarding guide's CLI-only fallback for the exact flags.
159
156
 
160
157
  ## Validation
161
158
 
@@ -199,6 +196,8 @@ var renderClaudeMd = async (workspace) => {
199
196
  return `# ${context.repoName} \u2014 Claude Code Guide
200
197
 
201
198
  @AGENTS.md
199
+
200
+ ${CLAUDE_COMMENT_RULE}
202
201
  `;
203
202
  };
204
203
  var renderCursorRule = () => `---
@@ -246,7 +245,7 @@ class AgentRunner extends runner("agent") {
246
245
  written.push(`${exec.type}s/${exec.name}/AGENTS.md`);
247
246
  } catch (error) {
248
247
  const message = error instanceof Error ? error.message : String(error);
249
- Logger.rawLog(`Skipped ${exec.type}s/${exec.name}/AGENTS.md (${message})`, undefined, "warn");
248
+ Logger.rawLog(`Skipped ${exec.type}s/${exec.name}/AGENTS.md (${message})`, undefined, "error");
250
249
  }
251
250
  };
252
251
  for (const name of libNames)
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-etwh7sd3.js";
5
+ } from "./index-mak3cd28.js";
6
6
 
7
7
  // pkgs/@akanjs/cli/page/page.runner.ts
8
8
  class PageRunner extends runner("page") {
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // pkgs/@akanjs/devkit/fileSys.ts
3
- import { lstat, stat } from "fs/promises";
3
+ import { lstat, rename, rm, stat } from "fs/promises";
4
4
  import { Logger } from "akanjs/common";
5
5
 
6
6
  class FileSys {
@@ -9,7 +9,7 @@ class FileSys {
9
9
  return await Bun.file(path).exists();
10
10
  }
11
11
  static async dirExists(path) {
12
- return await stat(path).then((stat2) => stat2.isDirectory()).catch(() => false);
12
+ return await stat(path).then((stat) => stat.isDirectory()).catch(() => false);
13
13
  }
14
14
  static async exists(path) {
15
15
  return await stat(path).then(() => true).catch(() => false);
@@ -34,6 +34,18 @@ class FileSys {
34
34
  static async writeText(path, content) {
35
35
  return await Bun.file(path).write(content);
36
36
  }
37
+ static async writeTextAtomic(filePath, content) {
38
+ const temp = `${filePath}.${process.pid}.${Date.now().toString(36)}.tmp`;
39
+ try {
40
+ await Bun.write(temp, content);
41
+ await rename(temp, filePath);
42
+ } catch (error) {
43
+ await rm(temp, { force: true }).catch(() => {
44
+ return;
45
+ });
46
+ throw error;
47
+ }
48
+ }
37
49
  static async writeJson(path, content) {
38
50
  return await Bun.file(path).write(`${JSON.stringify(content, null, 2)}
39
51
  `);