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

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 (135) 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-byytxs22.js} +3 -5
  5. package/{agent.command-f0gqkfgz.js → agent.command-v1a4746v.js} +11 -13
  6. package/{application.command-x903m2qq.js → application.command-fzdcnzhg.js} +65 -38
  7. package/{applicationBuildRunner-ha3y8ew8.js → applicationBuildRunner-s4gsk728.js} +27 -23
  8. package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-28v9vbzk.js} +8 -9
  9. package/buildBatch.proc.js +12 -14
  10. package/capacitorApp-8d6d4zkm.js +12 -0
  11. package/{cloud.command-zs6kyf83.js → cloud.command-wygy2z05.js} +15 -18
  12. package/commandManifest.json +1 -1
  13. package/{context.command-fmepgjzg.js → context.command-4vdt1aqq.js} +19 -23
  14. package/dependencyScanner-shs82ynp.js +8 -0
  15. package/devTui-qnf1txdz.js +553 -0
  16. package/devTuiView-yzct2cq6.js +9 -0
  17. package/getDirname-dr3jz1xg.js +7 -0
  18. package/{guideline.command-n6sw0a0c.js → guideline.command-p92dq6ts.js} +16 -18
  19. package/guidelines/agentRule/agentRule.generate.json +31 -0
  20. package/guidelines/agentRule/agentRule.instruction.md +533 -0
  21. package/guidelines/conventions/conventions.instruction.md +447 -197
  22. package/guidelines/cssRule/cssRule.instruction.md +7 -0
  23. package/guidelines/framework/framework.generate.json +3 -2
  24. package/guidelines/framework/framework.instruction.md +1 -9
  25. package/guidelines/mcpRule/mcpRule.generate.json +35 -0
  26. package/guidelines/mcpRule/mcpRule.instruction.md +366 -0
  27. package/guidelines/modelStore/modelStore.instruction.md +12 -0
  28. package/guidelines/modelTemplate/modelTemplate.instruction.md +5 -0
  29. package/guidelines/queryRule/queryRule.generate.json +31 -0
  30. package/guidelines/queryRule/queryRule.instruction.md +178 -0
  31. package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
  32. package/guidelines/runtimeRule/runtimeRule.instruction.md +220 -0
  33. package/guidelines/ssrRule/ssrRule.instruction.md +49 -5
  34. package/guidelines/transportRule/transportRule.generate.json +31 -0
  35. package/guidelines/transportRule/transportRule.instruction.md +60 -0
  36. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +51 -760
  37. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
  38. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +402 -0
  39. package/incrementalBuilder.proc.js +26 -25
  40. package/{index-jf2ya7r2.js → index-0amdxycf.js} +8 -8
  41. package/{index-779ske1y.js → index-1yxtbmbj.js} +27 -27
  42. package/{index-eyyf2149.js → index-29sxqfaw.js} +36 -37
  43. package/index-3d9y066c.js +76 -0
  44. package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
  45. package/index-5svjba73.js +159 -0
  46. package/{index-1577bej2.js → index-6wwzs1bc.js} +2 -2
  47. package/{index-gcv8ncfh.js → index-7d6vny25.js} +16 -12
  48. package/{index-y4vkyhvv.js → index-8p8p0cf8.js} +14 -14
  49. package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
  50. package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
  51. package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
  52. package/{index-0cj2zxbm.js → index-c69j78kk.js} +12 -11
  53. package/{index-rxkpk7n4.js → index-fc1bh0a7.js} +4 -4
  54. package/{index-d43t8af2.js → index-gq44bqjt.js} +58 -25
  55. package/{index-774gcx29.js → index-gtmz74tj.js} +41 -34
  56. package/{index-j37qq1f2.js → index-h7yw2z9n.js} +7 -7
  57. package/{index-bjpxzr6s.js → index-hwkygn9s.js} +51 -3
  58. package/{index-xmmzf150.js → index-hyywke0f.js} +1 -1
  59. package/{index-46tjzh6s.js → index-kcxmv48c.js} +29 -29
  60. package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
  61. package/{index-qb61h0k7.js → index-p5neav9b.js} +1098 -1360
  62. package/{index-67546d0j.js → index-q0y2jq9j.js} +14 -2
  63. package/{index-3vta1tqa.js → index-qkk27bk6.js} +32 -32
  64. package/{index-z8ptfkzv.js → index-qsq3q8fy.js} +975 -242
  65. package/{index-qzdjd4ct.js → index-srdssqj7.js} +18 -18
  66. package/{index-j9cxndc0.js → index-w8kmx1b6.js} +20 -11
  67. package/{index-82jrh4hj.js → index-yks023mb.js} +13 -13
  68. package/{index-5sn5w2mt.js → index-yza7zkpt.js} +94 -61
  69. package/{index-jhpa13zj.js → index-zmjppp25.js} +57 -57
  70. package/{index-kdh76j26.js → index-znynzt5w.js} +100 -32
  71. package/{index-4m0bphac.js → index-zxgr3s8s.js} +31 -30
  72. package/{index-62955kn5.js → index-zz5jyd94.js} +1002 -128
  73. package/index.js +22 -25
  74. package/{library.command-cv9gdbmg.js → library.command-s4fszngs.js} +11 -10
  75. package/{localRegistry.command-d8fg36zc.js → localRegistry.command-gyw4da9z.js} +20 -23
  76. package/{module.command-qyr1s9cn.js → module.command-6n7dwvav.js} +13 -16
  77. package/{package.command-wsjx0k47.js → package.command-gr82ypnr.js} +8 -10
  78. package/package.json +5 -7
  79. package/{page.command-rdzg65rm.js → page.command-7gvgb3jb.js} +7 -9
  80. package/{primitive.command-89g38b53.js → primitive.command-tk5ckw38.js} +13 -16
  81. package/{quality.command-0cs2z92d.js → quality.command-38v81baf.js} +226 -105
  82. package/recipeScanner-fpagtgc1.js +11 -0
  83. package/{repair.command-6fphxfwj.js → repair.command-5xbwvsxp.js} +12 -14
  84. package/{routeSourceValidator-e4jmbfcx.js → routeSourceValidator-ze6x894c.js} +0 -2
  85. package/{scalar.command-xfer69s6.js → scalar.command-0epwcr5k.js} +11 -14
  86. package/subspace.command-e2t36xb2.js +755 -0
  87. package/templates/app/env/env.client.debug.ts.template +1 -5
  88. package/templates/app/env/env.client.develop.ts.template +1 -5
  89. package/templates/app/env/env.client.local.ts.template +1 -5
  90. package/templates/app/env/env.client.main.ts.template +1 -5
  91. package/templates/app/env/env.client.testing.ts.template +1 -5
  92. package/templates/app/env/env.client.type.ts +2 -6
  93. package/templates/app/env/env.server.debug.ts.template +1 -5
  94. package/templates/app/env/env.server.develop.ts.template +1 -5
  95. package/templates/app/env/env.server.local.ts.template +1 -5
  96. package/templates/app/env/env.server.main.ts.template +1 -5
  97. package/templates/app/main.ts +3 -1
  98. package/templates/appSample/lib/task/task.signal.ts +11 -6
  99. package/templates/appSample/srvkit/AuthGuard.ts +9 -5
  100. package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
  101. package/templates/crudPages/[__model__Id]/edit/page.tsx +5 -5
  102. package/templates/crudPages/[__model__Id]/page.tsx +10 -13
  103. package/templates/crudPages/new/page.tsx +5 -5
  104. package/templates/crudPages/page.tsx +9 -9
  105. package/templates/crudSinglePage/page.tsx +11 -7
  106. package/templates/env/_env.server.type.ts +7 -5
  107. package/templates/lib/db.ts +1 -1
  108. package/templates/lib/dict.ts +1 -1
  109. package/templates/lib/sig.ts +5 -1
  110. package/templates/lib/srv.ts +6 -2
  111. package/templates/module/__model__.dictionary.ts +4 -1
  112. package/templates/module/__model__.signal.ts +2 -3
  113. package/templates/module/__model__.store.ts +1 -2
  114. package/templates/workspaceRoot/.gitignore.template +0 -1
  115. package/templates/workspaceRoot/.husky/pre-commit.template +16 -0
  116. package/templates/workspaceRoot/.vscode/settings.json.template +1 -1
  117. package/templates/workspaceRoot/AGENTS.md.template +4 -0
  118. package/templates/workspaceRoot/CLAUDE.md.template +19 -0
  119. package/templates/workspaceRoot/biome.json.template +2 -1
  120. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +10 -14
  121. package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
  122. package/templates/workspaceRoot/package.json.template +2 -4
  123. package/typeChecker-3xgrzc2v.js +7 -0
  124. package/typecheck.proc.js +4 -5
  125. package/{workflow.command-2ygfqt4f.js → workflow.command-kphbr7eh.js} +22 -25
  126. package/{workspace.command-vbgpjkf9.js → workspace.command-j1gatz3d.js} +96 -81
  127. package/capacitorApp-9xswcgx7.js +0 -61
  128. package/dependencyScanner-f6grrep3.js +0 -9
  129. package/getDirname-m9s0cmhq.js +0 -8
  130. package/index-mxvakhsm.js +0 -66
  131. package/index-r24hmh0q.js +0 -4
  132. package/recipeScanner-tghkzrrt.js +0 -12
  133. package/typeChecker-kravn7ns.js +0 -8
  134. /package/{index-0wae5ebk.js → index-meh558jy.js} +0 -0
  135. /package/{index-ss469dec.js → index-nz8prx9g.js} +0 -0
@@ -5,7 +5,7 @@ import * as path from "path";
5
5
  import chalk from "chalk";
6
6
  import * as ts from "typescript";
7
7
 
8
- class TypeChecker {
8
+ class TypeChecker2 {
9
9
  configPath;
10
10
  configFile;
11
11
  config;
@@ -143,12 +143,12 @@ ${summary.join(", ")} found${output.join(`
143
143
  try {
144
144
  const { diagnostics } = this.check(filePath);
145
145
  return diagnostics.length === 0;
146
- } catch (error) {
146
+ } catch (_error) {
147
147
  return false;
148
148
  }
149
149
  }
150
150
  static checkProject(configPath) {
151
- const parsedConfig = TypeChecker.parseConfig(configPath);
151
+ const parsedConfig = TypeChecker2.parseConfig(configPath);
152
152
  const host = ts.createIncrementalCompilerHost(parsedConfig.options);
153
153
  const builderProgram = ts.createIncrementalProgram({
154
154
  rootNames: parsedConfig.fileNames,
@@ -166,19 +166,19 @@ ${summary.join(", ")} found${output.join(`
166
166
  diagnostics,
167
167
  errors,
168
168
  warnings,
169
- message: TypeChecker.formatDiagnosticMessages(diagnostics)
169
+ message: TypeChecker2.formatDiagnosticMessages(diagnostics)
170
170
  };
171
171
  }
172
172
  static parseConfig(configPath) {
173
173
  const configFile = ts.readConfigFile(configPath, (fileName) => ts.sys.readFile(fileName));
174
174
  const configDiagnostics = configFile.error ? [configFile.error] : [];
175
175
  if (!configFile.config) {
176
- const message = TypeChecker.formatDiagnosticMessages(configDiagnostics);
176
+ const message = TypeChecker2.formatDiagnosticMessages(configDiagnostics);
177
177
  throw new Error(message || `Error reading tsconfig.json: ${configPath}`);
178
178
  }
179
179
  const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configPath), undefined, configPath);
180
180
  if (parsedConfig.errors.length > 0)
181
- throw new Error(TypeChecker.formatDiagnosticMessages(parsedConfig.errors));
181
+ throw new Error(TypeChecker2.formatDiagnosticMessages(parsedConfig.errors));
182
182
  return parsedConfig;
183
183
  }
184
184
  static formatDiagnosticMessages(diagnostics) {
@@ -190,4 +190,4 @@ ${summary.join(", ")} found${output.join(`
190
190
  }
191
191
  }
192
192
 
193
- export { TypeChecker };
193
+ export { TypeChecker2 };
@@ -19,12 +19,14 @@ var prepareDevWatchBatch = ({
19
19
  generatedFiles: indexSync.changedFiles
20
20
  });
21
21
  if (indexSync.errors.length > 0 && !devPlan.actions.includes("report-error")) {
22
- devPlan.actions = [...devPlan.actions, "report-error"].sort();
22
+ const withReport = [...devPlan.actions, "report-error"];
23
+ devPlan.actions = withReport.sort();
23
24
  }
24
25
  return {
25
26
  files,
26
27
  kinds,
27
28
  expandedBatch,
29
+ devPlan,
28
30
  event: { type: "invalidate", kinds, files, generation, devPlan },
29
31
  hasSyncErrors: indexSync.errors.length > 0
30
32
  };
@@ -2,7 +2,7 @@
2
2
  // pkgs/@akanjs/devkit/recipeScanner.ts
3
3
  import { readdir } from "fs/promises";
4
4
  import ts from "typescript";
5
- var collectRecipeSources = async (uiDirPath, importFrom, basename = "Recipe") => {
5
+ var collectRecipeSources2 = async (uiDirPath, importFrom, basename = "Recipe") => {
6
6
  const read = async (filePath) => {
7
7
  const content = await Bun.file(filePath).text().catch(() => "");
8
8
  return content ? { path: filePath, content, importFrom } : null;
@@ -12,7 +12,7 @@ var collectRecipeSources = async (uiDirPath, importFrom, basename = "Recipe") =>
12
12
  const fromDir = await Promise.all(dirEntries.filter((entry) => entry.endsWith(".ts") && entry !== "index.ts" && !/\.(test|spec)\.ts$/.test(entry)).sort().map((entry) => read(`${uiDirPath}/${basename}/${entry}`)));
13
13
  return [flat, ...fromDir].filter((source) => !!source);
14
14
  };
15
- var scanRecipes = (sources) => {
15
+ var scanRecipes2 = (sources) => {
16
16
  const recipes = [];
17
17
  for (const source of sources) {
18
18
  const sourceFile = ts.createSourceFile(source.path, source.content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
@@ -87,7 +87,7 @@ var isNamed = (name) => ts.isIdentifier(name) || ts.isStringLiteral(name);
87
87
  var propName = (name) => name.text;
88
88
  var DUPLICATE_TOKEN_RATIO = 0.7;
89
89
  var MIN_FINGERPRINT_TOKENS = 3;
90
- var findInlineRecipeDuplicates = (recipes, files) => {
90
+ var findInlineRecipeDuplicates2 = (recipes, files) => {
91
91
  const fingerprints = recipes.map((recipe) => ({ recipe: recipe.name, tokens: (recipe.base ?? "").split(/\s+/).filter(Boolean) })).filter((fingerprint) => fingerprint.tokens.length >= MIN_FINGERPRINT_TOKENS).map((fingerprint) => ({ ...fingerprint, needed: Math.ceil(fingerprint.tokens.length * DUPLICATE_TOKEN_RATIO) }));
92
92
  if (fingerprints.length === 0)
93
93
  return [];
@@ -133,4 +133,4 @@ var getLeadingDoc = (fullText, node) => {
133
133
  return line || undefined;
134
134
  };
135
135
 
136
- export { collectRecipeSources, scanRecipes, findInlineRecipeDuplicates };
136
+ export { collectRecipeSources2, scanRecipes2, findInlineRecipeDuplicates2 };
@@ -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-qsq3q8fy.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
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  AppExecutor,
4
4
  LibExecutor
5
- } from "./index-z8ptfkzv.js";
5
+ } from "./index-qsq3q8fy.js";
6
6
 
7
7
  // pkgs/@akanjs/devkit/workflow/utils.ts
8
8
  var jsonText = (value, { trailingNewline = true } = {}) => `${JSON.stringify(value, null, 2)}${trailingNewline ? `
@@ -914,9 +914,9 @@ ${options.closingIndent}}`);
914
914
  const beforeField = locator.fields[insertIndex];
915
915
  if (beforeField) {
916
916
  const leadingComments = ts.getLeadingCommentRanges(content, beforeField.fullStart) ?? [];
917
- const insertAt2 = lineStartAt(content, leadingComments[0]?.pos ?? beforeField.start);
918
- const indent2 = lineIndentAt(content, beforeField.start) || options.fieldIndent;
919
- return spliceText(content, insertAt2, insertAt2, `${indent2}${formattedLine}
917
+ const insertAt = lineStartAt(content, leadingComments[0]?.pos ?? beforeField.start);
918
+ const indent = lineIndentAt(content, beforeField.start) || options.fieldIndent;
919
+ return spliceText(content, insertAt, insertAt, `${indent}${formattedLine}
920
920
  `);
921
921
  }
922
922
  const afterField = locator.fields[locator.fields.length - 1];
@@ -2,16 +2,24 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-kdh76j26.js";
5
+ } from "./index-znynzt5w.js";
6
6
  import {
7
7
  LibExecutor
8
- } from "./index-z8ptfkzv.js";
8
+ } from "./index-qsq3q8fy.js";
9
+ import {
10
+ LibSource,
11
+ formatLibStatuses
12
+ } from "./index-3d9y066c.js";
13
+
14
+ // pkgs/@akanjs/cli/library/library.script.ts
15
+ import { Logger } from "akanjs/common";
9
16
 
10
- // pkgs/@akanjs/cli/semver.ts
11
- function parseVersion(version) {
17
+ // pkgs/@akanjs/devkit/semver.ts
18
+ var stripRangeOperator = (version) => version.replace(/^[\s^~>=<v]+/, "").trim();
19
+ var parseVersion = (version) => {
12
20
  return version.replace(/^[^\d]*/, "").split(/[.-]/).map((part) => Number.parseInt(part, 10)).map((part) => Number.isFinite(part) ? part : 0);
13
- }
14
- function compareSemver(a, b) {
21
+ };
22
+ var compareNumeric = (a, b) => {
15
23
  const left = parseVersion(a);
16
24
  const right = parseVersion(b);
17
25
  const length = Math.max(left.length, right.length);
@@ -21,40 +29,64 @@ function compareSemver(a, b) {
21
29
  return diff > 0 ? 1 : -1;
22
30
  }
23
31
  return 0;
24
- }
32
+ };
33
+ var compareSemver = (a, b) => {
34
+ try {
35
+ return Bun.semver.order(stripRangeOperator(a), stripRangeOperator(b));
36
+ } catch {
37
+ return compareNumeric(a, b);
38
+ }
39
+ };
25
40
 
26
41
  // pkgs/@akanjs/cli/library/library.runner.ts
27
42
  class LibraryRunner extends runner("library") {
43
+ static libraryRepository = "https://github.com/akan-team/akanjs.git";
28
44
  async createLibrary(libName, workspace) {
29
- await workspace.exec(`mkdir -p libs/${libName}`);
45
+ await workspace.mkdir(`libs/${libName}`);
30
46
  await workspace.applyTemplate({ basePath: `libs/${libName}`, template: "libRoot", dict: { libName } });
31
47
  const lib = LibExecutor.from(workspace, libName);
32
48
  return lib;
33
49
  }
34
50
  async removeLibrary(lib) {
35
- await lib.workspace.exec(`rm -rf libs/${lib.name}`);
51
+ await lib.workspace.removeDir(`libs/${lib.name}`);
36
52
  }
37
53
  async#copyInstalledLibrary(workspace, libName) {
38
54
  const installedPackageJson = `node_modules/akanjs/libs/${libName}/package.json`;
39
55
  if (!await workspace.exists(installedPackageJson))
40
- return false;
56
+ return null;
41
57
  await workspace.cp(`node_modules/akanjs/libs/${libName}`, `libs/${libName}`);
42
- return true;
58
+ return { origin: "akanjs", sha: await this.#installedAkanVersion(workspace) };
59
+ }
60
+ async#installedAkanVersion(workspace) {
61
+ const manifestPath = "node_modules/akanjs/package.json";
62
+ if (!await workspace.exists(manifestPath))
63
+ return "unknown";
64
+ const { version } = await workspace.readJson(manifestPath);
65
+ return version ?? "unknown";
43
66
  }
44
67
  async#copyLibraryFromRepository(workspace, libName) {
45
68
  await workspace.mkdir("node_modules/.akan");
46
69
  if (await workspace.exists("node_modules/.akan/akanjs"))
47
70
  await workspace.removeDir("node_modules/.akan/akanjs");
48
- await workspace.exec(`cd node_modules/.akan && git clone https://github.com/akan-team/akanjs.git`);
71
+ await workspace.exec(`cd node_modules/.akan && git clone ${LibraryRunner.libraryRepository}`);
49
72
  await workspace.cp(`node_modules/.akan/akanjs/libs/${libName}`, `libs/${libName}`);
73
+ const sha = await workspace.spawn("git", ["-C", "node_modules/.akan/akanjs", "rev-parse", "HEAD"]);
74
+ return { origin: LibraryRunner.libraryRepository, sha: sha.trim().slice(0, 12) };
50
75
  }
51
76
  async installLibrary(workspace, libName) {
52
- const copiedFromInstalledPackage = await this.#copyInstalledLibrary(workspace, libName);
53
- if (!copiedFromInstalledPackage)
54
- await this.#copyLibraryFromRepository(workspace, libName);
55
- await workspace.cp(`libs/${libName}/env/env.server.example.ts`, `libs/${libName}/env/env.server.testing.ts`);
56
- await workspace.commit(`Add ${libName} library`);
57
- return LibExecutor.from(workspace, libName);
77
+ const source = await this.#copyInstalledLibrary(workspace, libName) ?? await this.#copyLibraryFromRepository(workspace, libName);
78
+ const testingEnv = `libs/${libName}/env/env.server.testing.ts`;
79
+ if (!await workspace.exists(testingEnv))
80
+ await workspace.cp(`libs/${libName}/env/env.server.example.ts`, testingEnv);
81
+ const lib = LibExecutor.from(workspace, libName);
82
+ const stamp = await new LibSource(lib).write(source);
83
+ if (await workspace.hasChanges())
84
+ await workspace.commit(`Install ${libName} library from ${stamp.origin}`);
85
+ return lib;
86
+ }
87
+ async libraryStatuses(workspace) {
88
+ const libNames = await workspace.getLibs();
89
+ return await Promise.all(libNames.map((libName) => new LibSource(LibExecutor.from(workspace, libName)).status()));
58
90
  }
59
91
  async mergeLibraryDependencies(lib) {
60
92
  const libPackageJson = await lib.getPackageJson();
@@ -70,7 +102,7 @@ class LibraryRunner extends runner("library") {
70
102
  return [dep, newerVersion];
71
103
  }));
72
104
  Object.keys(allDependencies).sort().forEach((dep) => {
73
- if (!!libPackageJson.dependencies?.[dep] || !!rootPackageJson.dependencies?.[dep])
105
+ if (libPackageJson.dependencies?.[dep] || rootPackageJson.dependencies?.[dep])
74
106
  dependencies[dep] = allDependencies[dep];
75
107
  else
76
108
  devDependencies[dep] = allDependencies[dep];
@@ -80,7 +112,6 @@ class LibraryRunner extends runner("library") {
80
112
  await lib.workspace.spawn("bun", ["install"]);
81
113
  await lib.workspace.commit(`Merge ${lib.name} library dependencies`);
82
114
  }
83
- async testLibrary(lib) {}
84
115
  }
85
116
 
86
117
  // pkgs/@akanjs/cli/library/library.script.ts
@@ -102,6 +133,13 @@ class LibraryScript extends script("library", [LibraryRunner]) {
102
133
  await this.libraryRunner.removeLibrary(lib);
103
134
  spinner.succeed(`Library ${lib.name} (libs/${lib.name}) is removed`);
104
135
  }
136
+ async libraryStatus(workspace, format = "text") {
137
+ const spinner = workspace.spinning("Checking library sources...");
138
+ const statuses = await this.libraryRunner.libraryStatuses(workspace);
139
+ const drifted = statuses.filter((status) => status.drift === "drifted").length;
140
+ spinner.succeed(`Checked ${statuses.length} libraries (${drifted} drifted)`);
141
+ Logger.rawLog(format === "json" ? JSON.stringify(statuses, null, 2) : formatLibStatuses(statuses));
142
+ }
105
143
  async installLibrary(workspace, libName) {
106
144
  const installSpinner = workspace.spinning(`Installing ${libName} library`);
107
145
  const lib = await this.libraryRunner.installLibrary(workspace, libName);
@@ -110,11 +148,6 @@ class LibraryScript extends script("library", [LibraryRunner]) {
110
148
  await this.libraryRunner.mergeLibraryDependencies(lib);
111
149
  mergeSpinner.succeed(`${libName} library (libs/${libName}) dependencies merged to root package.json`);
112
150
  }
113
- async testLibrary(lib) {
114
- const spinner = lib.spinning("Testing library...");
115
- await this.libraryRunner.testLibrary(lib);
116
- spinner.succeed(`Library ${lib.name} (libs/${lib.name}) test is successful`);
117
- }
118
151
  }
119
152
 
120
153
  export { LibraryScript };
@@ -1,38 +1,45 @@
1
1
  // @bun
2
2
  import {
3
- workflowRunArtifactPath,
4
- workflowSyncDir
5
- } from "./index-rxkpk7n4.js";
6
- import {
7
- AppExecutor,
8
- LibExecutor,
9
- appRootAllowedDirs,
10
- appRootAllowedFiles,
11
3
  extractBlockVersion,
12
- isScannedAppRootEntry,
13
- readDevkitVersion
14
- } from "./index-z8ptfkzv.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-qsq3q8fy.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-fc1bh0a7.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,14 +1,14 @@
1
1
  // @bun
2
2
  import {
3
- getDirname
4
- } from "./index-1577bej2.js";
3
+ getDirname2
4
+ } from "./index-6wwzs1bc.js";
5
5
 
6
6
  // pkgs/@akanjs/devkit/prompter.ts
7
7
  import fsPromise from "fs/promises";
8
8
  import { input, select } from "@inquirer/prompts";
9
9
  class Prompter {
10
10
  static async#getGuidelineRoot() {
11
- const dirname = getDirname(import.meta.url);
11
+ const dirname = getDirname2(import.meta.url);
12
12
  const candidates = [`${dirname}/guidelines`, `${dirname}/../cli/guidelines`];
13
13
  for (const candidate of candidates) {
14
14
  try {
@@ -19,7 +19,6 @@ class Prompter {
19
19
  return candidates[0];
20
20
  }
21
21
  static async selectGuideline() {
22
- const guidelineRoot = await Prompter.#getGuidelineRoot();
23
22
  const guideNames = await Prompter.listGuidelines();
24
23
  return await select({
25
24
  message: "Select a guideline",
@@ -37,10 +36,11 @@ class Prompter {
37
36
  return JSON.parse(guideJson);
38
37
  }
39
38
  static async getInstruction(guideName) {
39
+ const guideNames = await Prompter.listGuidelines();
40
+ if (!guideNames.includes(guideName))
41
+ throw new Error(`Unknown guideline "${guideName}". Available: ${guideNames.join(", ")}`);
40
42
  const guidelineRoot = await Prompter.#getGuidelineRoot();
41
- const filePath = `${guidelineRoot}/${guideName}/${guideName}.instruction.md`;
42
- const content = await fsPromise.readFile(filePath, "utf-8");
43
- return content;
43
+ return await fsPromise.readFile(`${guidelineRoot}/${guideName}/${guideName}.instruction.md`, "utf-8");
44
44
  }
45
45
  static async getUpdateRequest(guideName) {
46
46
  return await input({
@@ -422,7 +422,7 @@ class HmrWatcher {
422
422
  this.#unreportedChanges += unreported;
423
423
  if (!this.#reportedCompensating) {
424
424
  this.#reportedCompensating = true;
425
- this.#logger.info(`[hmr] recovered ${unreported} change(s) that fs.watch did not report; Bun coalesces concurrent saves and drops all but one, so changes are resolved by mtime`);
425
+ this.#logger.verbose(`[hmr] recovered ${unreported} change(s) that fs.watch did not report; Bun coalesces concurrent saves and drops all but one, so changes are resolved by mtime`);
426
426
  }
427
427
  this.#logger.verbose(`[hmr] mtime scan found ${unreported} change(s) fs.watch never reported (${this.#unreportedChanges} total)`);
428
428
  }
@@ -463,6 +463,7 @@ class HmrWatcher {
463
463
 
464
464
  // pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
465
465
  import fs2 from "fs";
466
+ import { readFile } from "fs/promises";
466
467
  import path4 from "path";
467
468
 
468
469
  class WatchRootResolver {
@@ -472,6 +473,10 @@ class WatchRootResolver {
472
473
  }
473
474
  async resolve() {
474
475
  const tsconfig = await this.#app.getTsConfig();
476
+ const appDir = path4.resolve(this.#app.cwdPath);
477
+ const appsContainer = path4.dirname(appDir);
478
+ const libsContainer = path4.resolve(this.#app.workspace.workspaceRoot, "libs");
479
+ const libRoots = await this.#resolveLibRoots(libsContainer);
475
480
  const set = new Set;
476
481
  set.add(path4.resolve(`${this.#app.cwdPath}/page`));
477
482
  for (const targets of Object.values(tsconfig.compilerOptions.paths ?? {})) {
@@ -482,12 +487,55 @@ class WatchRootResolver {
482
487
  continue;
483
488
  const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
484
489
  const resolved = path4.resolve(this.#app.workspace.workspaceRoot, cleaned);
485
- if (fs2.existsSync(resolved))
486
- set.add(resolved);
490
+ if (resolved === libsContainer && libRoots) {
491
+ for (const root of libRoots)
492
+ set.add(root);
493
+ continue;
494
+ }
495
+ const root = resolved === appsContainer ? appDir : resolved;
496
+ if (fs2.existsSync(root))
497
+ set.add(root);
487
498
  }
488
499
  }
489
500
  return [...set];
490
501
  }
502
+ async#resolveLibRoots(libsContainer) {
503
+ const libDeps = await this.#resolveLibDeps(libsContainer);
504
+ if (!libDeps)
505
+ return null;
506
+ return libDeps.map((name) => path4.join(libsContainer, name)).filter((dir) => fs2.existsSync(dir));
507
+ }
508
+ async#resolveLibDeps(libsContainer) {
509
+ const scanInfo = this.#app.getScanInfo({ allowEmpty: true });
510
+ if (scanInfo?.type === "app")
511
+ return scanInfo.libDeps;
512
+ const direct = await WatchRootResolver.#readManifestLibDeps(path4.join(this.#app.cwdPath, "akan.app.json"));
513
+ if (!direct)
514
+ return null;
515
+ const closure = new Set;
516
+ const queue = [...direct];
517
+ while (queue.length > 0) {
518
+ const name = queue.shift();
519
+ if (!name || closure.has(name))
520
+ continue;
521
+ closure.add(name);
522
+ const nested = await WatchRootResolver.#readManifestLibDeps(path4.join(libsContainer, name, "akan.lib.json"));
523
+ if (!nested)
524
+ return null;
525
+ queue.push(...nested);
526
+ }
527
+ return [...closure];
528
+ }
529
+ static async#readManifestLibDeps(manifestPath) {
530
+ try {
531
+ const parsed = JSON.parse(await readFile(manifestPath, "utf8"));
532
+ if (!Array.isArray(parsed.libDeps))
533
+ return null;
534
+ return parsed.libDeps.filter((name) => typeof name === "string" && name.length > 0);
535
+ } catch {
536
+ return null;
537
+ }
538
+ }
491
539
  }
492
540
 
493
541
  export { HmrWatcher, WatchRootResolver };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-kdh76j26.js";
5
+ } from "./index-znynzt5w.js";
6
6
 
7
7
  // pkgs/@akanjs/cli/page/page.runner.ts
8
8
  class PageRunner extends runner("page") {