@akanjs/cli 3.0.0-beta.2 → 3.0.0-beta.21

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 (190) hide show
  1. package/.build-stamp +1 -1
  2. package/CodeAgent-q2m47rqp.js +9 -0
  3. package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
  4. package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
  5. package/CodeTui-pdqhc3sn.js +1457 -0
  6. package/README.md +3 -0
  7. package/TunnelShare-scf4e4pd.js +9 -0
  8. package/{agent.command-d2gfxfck.js → agent.command-ttn09rx3.js} +8 -9
  9. package/akanCode.js +102 -0
  10. package/application.command-7gweenv7.js +179 -0
  11. package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-38exmejd.js} +63 -64
  12. package/buildBatch.proc.js +26 -25
  13. package/cloud.command-bhztw7c2.js +95 -0
  14. package/cloud.script-aabyhgba.js +20 -0
  15. package/code.command-6s8c0k91.js +154 -0
  16. package/commandManifest.json +1 -1
  17. package/consoleToStderr-h5bryj94.js +7 -0
  18. package/context.command-phmgywt2.js +48 -0
  19. package/context.runner-yvyw5g2d.js +21 -0
  20. package/{dependencyScanner-shs82ynp.js → dependencyScanner-ye2e6pdz.js} +2 -2
  21. package/{devTui-40ggmd99.js → devTui-q7k7bakd.js} +122 -40
  22. package/fileSys-5ngz93ga.js +9 -0
  23. package/guideline.command-7jk47fgq.js +42 -0
  24. package/guidelines/agentRule/agentRule.instruction.md +209 -28
  25. package/guidelines/conventions/conventions.instruction.md +96 -29
  26. package/guidelines/fieldRule/fieldRule.instruction.md +1 -0
  27. package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
  28. package/guidelines/queryRule/queryRule.instruction.md +17 -7
  29. package/guidelines/runtimeRule/runtimeRule.instruction.md +77 -3
  30. package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
  31. package/guidelines/transportRule/transportRule.instruction.md +51 -0
  32. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
  33. package/incrementalBuilder.proc.js +31 -48
  34. package/{index-h7yw2z9n.js → index-0bq14vr1.js} +8 -14
  35. package/{index-259dsnz3.js → index-1db2cw0y.js} +5 -8
  36. package/index-22d57v4c.js +266 -0
  37. package/index-3hx1z96c.js +87 -0
  38. package/{index-kcxmv48c.js → index-3t7g9e4r.js} +45 -79
  39. package/{index-ne2qy0nk.js → index-4dn1p115.js} +12 -12
  40. package/{index-q0y2jq9j.js → index-5b6tavv3.js} +6 -3
  41. package/index-7cqjvraf.js +69 -0
  42. package/index-7md2g9vw.js +6 -0
  43. package/{index-zry5nz81.js → index-8kb5p54p.js} +51 -30
  44. package/{index-ktb5njgy.js → index-9629w7ns.js} +49 -99
  45. package/index-9dp031by.js +12 -0
  46. package/{index-a64esmtb.js → index-aadpbnt2.js} +172 -308
  47. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  48. package/index-c6eggbee.js +123 -0
  49. package/index-d0arnrm8.js +700 -0
  50. package/index-d2242ksy.js +99 -0
  51. package/{index-600zhnve.js → index-dg97qp24.js} +70 -200
  52. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  53. package/{index-w8kmx1b6.js → index-fgq75haa.js} +198 -290
  54. package/{index-2tv3fdx4.js → index-ga6hygxr.js} +944 -1333
  55. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  56. package/index-hr5n7t4x.js +465 -0
  57. package/{index-hwkygn9s.js → index-khpfpcsd.js} +302 -33
  58. package/{index-7737gxcp.js → index-m0ms3n1c.js} +107 -241
  59. package/{index-ws5e0j51.js → index-mgfx3mfs.js} +43 -26
  60. package/index-p6pbz9n5.js +25 -0
  61. package/index-pp54p5zk.js +53 -0
  62. package/{index-j9yhg404.js → index-q44jbw48.js} +4 -7
  63. package/{index-mak3cd28.js → index-rmcw8yc8.js} +137 -255
  64. package/{index-pnqbkf5p.js → index-rnt66vym.js} +6 -2
  65. package/index-smme4r47.js +49 -0
  66. package/index-tgjy8xf3.js +187 -0
  67. package/index-v5eayqqw.js +2729 -0
  68. package/index-wa5jbxj1.js +760 -0
  69. package/{index-4edzf1gr.js → index-wp43xrjv.js} +77 -150
  70. package/{index-fz5q3gd7.js → index-ya5qbmyg.js} +10 -17
  71. package/index-yjkte9aj.js +1119 -0
  72. package/{index-gyd220p2.js → index-yy4s1j72.js} +554 -577
  73. package/{index-v0qh106m.js → index-z50k041j.js} +580 -862
  74. package/index.js +23 -22
  75. package/{library.command-nbsky672.js → library.command-ccb1cp92.js} +4 -5
  76. package/{localRegistry.command-yeq57wjr.js → localRegistry.command-ajb9n87j.js} +23 -42
  77. package/{module.command-29vqzrh8.js → module.command-5k6h407d.js} +8 -11
  78. package/{package.command-axv0abmn.js → package.command-e6ntvpez.js} +6 -7
  79. package/package.json +14 -6
  80. package/{page.command-vs9s3zrh.js → page.command-v4f90wb8.js} +4 -5
  81. package/{primitive.command-cbxmqbtc.js → primitive.command-g6km57q5.js} +9 -22
  82. package/prompter-ptaa3nk0.js +8 -0
  83. package/{quality.command-gmbs7nws.js → quality.command-de3p36pz.js} +205 -377
  84. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  85. package/{repair.command-bqsjptsj.js → repair.command-d3x1javq.js} +11 -35
  86. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  87. package/{scalar.command-6k1vhe9s.js → scalar.command-7ezrac2b.js} +7 -10
  88. package/skills/akan-code/SKILL.md +130 -0
  89. package/skills/akan-debug/SKILL.md +42 -0
  90. package/skills/akan-deps/SKILL.md +50 -0
  91. package/skills/akan-err/SKILL.md +39 -0
  92. package/skills/akan-module/SKILL.md +45 -0
  93. package/skills/akan-scaffold/SKILL.md +76 -0
  94. package/skills/akan-scalar/SKILL.md +52 -0
  95. package/skills/akan-service/SKILL.md +34 -0
  96. package/skills/akan-store/SKILL.md +67 -0
  97. package/skills/akan-ui/SKILL.md +63 -0
  98. package/skills/akan-validate/SKILL.md +44 -0
  99. package/{subspace.command-fwjfcts7.js → subspace.command-ps71ynp6.js} +138 -67
  100. package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
  101. package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
  102. package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
  103. package/templates/appSample/lib/task/task.abstract.ts +12 -32
  104. package/templates/appSample/lib/task/task.signal.spec.ts +15 -18
  105. package/templates/appSample/lib/task/task.signal.test.ts +15 -1
  106. package/templates/appSample/lib/task/task.signal.ts +1 -1
  107. package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
  108. package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
  109. package/templates/client.ts +7 -30
  110. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
  111. package/templates/crudPages/[__model__Id]/page.tsx +2 -1
  112. package/templates/crudPages/new/page.tsx +2 -1
  113. package/templates/crudPages/page.tsx +2 -1
  114. package/templates/crudSinglePage/page.tsx +2 -1
  115. package/templates/lib/__lib/lib.dictionary.ts +0 -2
  116. package/templates/lib/__lib/lib.document.ts +0 -2
  117. package/templates/lib/sig.ts +8 -30
  118. package/templates/localDev/docker-compose.yaml.template +3 -14
  119. package/templates/module/__model__.signal.ts +12 -4
  120. package/templates/pkgRoot/tsconfig.json.template +2 -7
  121. package/templates/server.ts +0 -2
  122. package/templates/service/__model__.abstract.md.template +8 -0
  123. package/templates/workspaceRoot/.gitignore.template +0 -1
  124. package/tunnel.command-hsrv2mny.js +129 -0
  125. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  126. package/typecheck.proc.js +1 -1
  127. package/workflow.command-z2p32nmf.js +79 -0
  128. package/{workspace.command-8s050m0h.js → workspace.command-tmdqkrh0.js} +77 -109
  129. package/abstractCompactor-mjh5ppsq.js +0 -101
  130. package/application.command-pj2m7584.js +0 -204
  131. package/applicationReleasePackager-4yasxwv9.js +0 -244
  132. package/capacitorApp-36rbr858.js +0 -12
  133. package/cloud.command-jshwdq22.js +0 -93
  134. package/context.command-ez8a0zyz.js +0 -80
  135. package/devTuiView-c08ccbat.js +0 -9
  136. package/getDirname-dr3jz1xg.js +0 -7
  137. package/guideline.command-xmqwx8zm.js +0 -359
  138. package/guidelines/agentRule/agentRule.generate.json +0 -31
  139. package/guidelines/componentRule/componentRule.generate.json +0 -31
  140. package/guidelines/conventions/conventions.generate.json +0 -25
  141. package/guidelines/cssRule/cssRule.generate.json +0 -31
  142. package/guidelines/docPageRule/docPageRule.generate.json +0 -31
  143. package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
  144. package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
  145. package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
  146. package/guidelines/enumConstant/enumConstant.generate.json +0 -31
  147. package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
  148. package/guidelines/fieldRule/fieldRule.generate.json +0 -31
  149. package/guidelines/framework/framework.generate.json +0 -32
  150. package/guidelines/mcpRule/mcpRule.generate.json +0 -35
  151. package/guidelines/modelConstant/modelConstant.generate.json +0 -32
  152. package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
  153. package/guidelines/modelDocument/modelDocument.generate.json +0 -31
  154. package/guidelines/modelService/modelService.generate.json +0 -31
  155. package/guidelines/modelSignal/modelSignal.generate.json +0 -31
  156. package/guidelines/modelStore/modelStore.generate.json +0 -31
  157. package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
  158. package/guidelines/modelUnit/modelUnit.generate.json +0 -31
  159. package/guidelines/modelUtil/modelUtil.generate.json +0 -31
  160. package/guidelines/modelView/modelView.generate.json +0 -31
  161. package/guidelines/modelZone/modelZone.generate.json +0 -31
  162. package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
  163. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
  164. package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
  165. package/guidelines/queryRule/queryRule.generate.json +0 -31
  166. package/guidelines/recipeRule/recipeRule.generate.json +0 -31
  167. package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
  168. package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
  169. package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
  170. package/guidelines/scalarModule/scalarModule.generate.json +0 -31
  171. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
  172. package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
  173. package/guidelines/ssrRule/ssrRule.generate.json +0 -31
  174. package/guidelines/transportRule/transportRule.generate.json +0 -31
  175. package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
  176. package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
  177. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
  178. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -33
  179. package/index-2hq52jq3.js +0 -465
  180. package/index-47pj3aee.js +0 -76
  181. package/index-6wwzs1bc.js +0 -7
  182. package/index-8pm30m73.js +0 -841
  183. package/index-kn1h7p1x.js +0 -560
  184. package/index-meh558jy.js +0 -65
  185. package/index-rwg2aa4f.js +0 -229
  186. package/index-wt7qrtd4.js +0 -1516
  187. package/templates/__scalar/__model__/__model__.abstract.md +0 -28
  188. package/templates/module/__model__.abstract.md +0 -28
  189. package/templates/service/__model__.abstract.md +0 -28
  190. package/workflow.command-nwpcdc8p.js +0 -107
@@ -0,0 +1,87 @@
1
+ // @bun
2
+ // pkgs/@akanjs/devkit/cloud/configLock.ts
3
+ import { mkdir, open, readFile, rm, stat } from "fs/promises";
4
+ import path from "path";
5
+
6
+ class ConfigLock {
7
+ static waitTimeoutMs = 30000;
8
+ static #unknownHolderStaleMs = 1e4;
9
+ static #pollMs = 50;
10
+ static async run(lockPath, fn) {
11
+ await mkdir(path.dirname(lockPath), { recursive: true, mode: 448 });
12
+ const deadline = Date.now() + ConfigLock.waitTimeoutMs;
13
+ while (!await ConfigLock.#take(lockPath)) {
14
+ if (Date.now() >= deadline) {
15
+ const holder = (await ConfigLock.#holder(lockPath))?.pid ?? "unknown";
16
+ throw new Error(`${lockPath} is held by process ${holder}; if no akan command is running, delete it and retry.`);
17
+ }
18
+ await ConfigLock.#reclaimIfAbandoned(lockPath);
19
+ await Bun.sleep(ConfigLock.#pollMs);
20
+ }
21
+ try {
22
+ return await fn();
23
+ } finally {
24
+ await rm(lockPath, { force: true });
25
+ }
26
+ }
27
+ static async#take(lockPath) {
28
+ const handle = await open(lockPath, "wx", 384).catch((error) => {
29
+ if (error.code === "EEXIST")
30
+ return null;
31
+ throw error;
32
+ });
33
+ if (!handle)
34
+ return false;
35
+ try {
36
+ await handle.writeFile(JSON.stringify({ pid: process.pid, at: Date.now() }));
37
+ } finally {
38
+ await handle.close();
39
+ }
40
+ return true;
41
+ }
42
+ static async#reclaimIfAbandoned(lockPath) {
43
+ if (!await ConfigLock.#abandoned(lockPath))
44
+ return;
45
+ const guard = `${lockPath}.reclaim`;
46
+ if (!await ConfigLock.#take(guard)) {
47
+ if (await ConfigLock.#abandoned(guard))
48
+ await rm(guard, { force: true });
49
+ return;
50
+ }
51
+ try {
52
+ if (await ConfigLock.#abandoned(lockPath))
53
+ await rm(lockPath, { force: true });
54
+ } finally {
55
+ await rm(guard, { force: true });
56
+ }
57
+ }
58
+ static async#abandoned(lockPath) {
59
+ const info = await stat(lockPath).catch(() => null);
60
+ if (!info)
61
+ return false;
62
+ const holder = await ConfigLock.#holder(lockPath);
63
+ if (!holder)
64
+ return Date.now() - info.mtimeMs > ConfigLock.#unknownHolderStaleMs;
65
+ return !ConfigLock.#isAlive(holder.pid);
66
+ }
67
+ static async#holder(lockPath) {
68
+ try {
69
+ const parsed = JSON.parse(await readFile(lockPath, "utf8"));
70
+ return typeof parsed.pid === "number" && typeof parsed.at === "number" ? { pid: parsed.pid, at: parsed.at } : null;
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+ static #isAlive(pid) {
76
+ if (!Number.isInteger(pid) || pid <= 0)
77
+ return false;
78
+ try {
79
+ process.kill(pid, 0);
80
+ return true;
81
+ } catch (error) {
82
+ return error.code === "EPERM";
83
+ }
84
+ }
85
+ }
86
+
87
+ export { ConfigLock };
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
- FileSys
4
- } from "./index-q0y2jq9j.js";
3
+ FileSys2
4
+ } from "./index-5b6tavv3.js";
5
5
 
6
6
  // pkgs/@akanjs/devkit/dependencyScanner.ts
7
7
  import { builtinModules } from "module";
@@ -10,7 +10,10 @@ import ignore from "ignore";
10
10
  import ts from "typescript";
11
11
  var testFileRegex = /\.(?:test|spec)\.[cm]?[tj]sx?$/;
12
12
  var skipDirs = ["node_modules", "dist", "build", ".git", ".next", "public", "ios", "android", "__fixtures__"];
13
- var isSkippedPath = (filePath) => skipDirs.some((dir) => filePath.includes(`/${dir}/`) || filePath.startsWith(`${dir}/`));
13
+ var isSkippedPath = (filePath) => {
14
+ const posixPath = filePath.split(path.sep).join("/");
15
+ return skipDirs.some((dir) => posixPath.includes(`/${dir}/`) || posixPath.startsWith(`${dir}/`));
16
+ };
14
17
  var builtinModuleSet = new Set([...builtinModules, ...builtinModules.map((mod) => `node:${mod}`)]);
15
18
  var stripShebang = (source) => source.replace(/^#!.*(?:\r?\n|$)/, "");
16
19
 
@@ -54,24 +57,21 @@ class TypeScriptDependencyScanner2 {
54
57
  async getPackageBuildDependencies(projectName) {
55
58
  const runtimeDeps = new Set;
56
59
  const devDeps = new Set;
57
- const sourceFiles = await this.#findTypeScriptFiles(this.#directory, {
58
- excludeBuildFiles: true,
59
- excludeTestFiles: true
60
- });
61
- const cssFiles = await this.#findCssFiles(this.#directory);
60
+ const sourceFiles = await this.#findFiles("**/*.{ts,tsx}", { excludeBuildFiles: true, excludeTestFiles: true });
61
+ const cssFiles = await this.#findFiles("**/*.css");
62
62
  for (const filePath of sourceFiles) {
63
- const fileContent = await FileSys.readText(filePath);
63
+ const fileContent = await FileSys2.readText(filePath);
64
64
  const { imports, typeImports } = this.#extractImports(fileContent, filePath);
65
65
  this.#addNormalizedImports(runtimeDeps, imports, projectName);
66
66
  this.#addNormalizedImports(devDeps, typeImports, projectName);
67
67
  }
68
68
  for (const filePath of cssFiles) {
69
- const fileContent = await FileSys.readText(filePath);
69
+ const fileContent = await FileSys2.readText(filePath);
70
70
  this.#addNormalizedImports(runtimeDeps, this.#extractCssPluginImports(fileContent), projectName);
71
71
  }
72
72
  const buildFilePath = path.join(this.#directory, "build.ts");
73
- if (await FileSys.fileExists(buildFilePath)) {
74
- const fileContent = await FileSys.readText(buildFilePath);
73
+ if (await FileSys2.fileExists(buildFilePath)) {
74
+ const fileContent = await FileSys2.readText(buildFilePath);
75
75
  const { imports, typeImports } = this.#extractImports(fileContent, buildFilePath);
76
76
  this.#addNormalizedImports(devDeps, [...imports, ...typeImports], projectName);
77
77
  }
@@ -95,7 +95,7 @@ class TypeScriptDependencyScanner2 {
95
95
  if (!await Bun.file(packageJsonPath).exists())
96
96
  return false;
97
97
  try {
98
- const packageJson = await FileSys.readJson(packageJsonPath);
98
+ const packageJson = await FileSys2.readJson(packageJsonPath);
99
99
  return packageJson.name === dep && !!packageJson.version;
100
100
  } catch {
101
101
  return false;
@@ -106,27 +106,21 @@ class TypeScriptDependencyScanner2 {
106
106
  return this.#getImportSetsFromDependencies(depSets, fileDependencies);
107
107
  }
108
108
  #getImportSetsFromDependencies(depSets, fileDependencies) {
109
- const importedDepSets = new Array(depSets.length);
110
- for (let i = 0;i < depSets.length; i++)
111
- importedDepSets[i] = new Set;
112
- fileDependencies.forEach((imps) => {
113
- imps.forEach((imp) => {
109
+ const importedDepSets = depSets.map(() => new Set);
110
+ for (const imps of fileDependencies.values())
111
+ for (const imp of imps) {
114
112
  if (imp.startsWith("."))
115
- return;
116
- const moduleName = imp;
117
- const moduleNameParts = moduleName.split("/");
118
- const subModuleLength = moduleNameParts.length;
119
- for (let i = 0;i < subModuleLength; i++) {
120
- const importName = moduleNameParts.slice(0, i + 1).join("/");
121
- for (let j = 0;j < depSets.length; j++) {
122
- if (depSets[j]?.has(importName)) {
123
- importedDepSets[j]?.add(importName);
124
- return;
125
- }
126
- }
113
+ continue;
114
+ const parts = imp.split("/");
115
+ for (let length = 1;length <= parts.length; length++) {
116
+ const importName = parts.slice(0, length).join("/");
117
+ const setIndex = depSets.findIndex((depSet) => depSet.has(importName));
118
+ if (setIndex === -1)
119
+ continue;
120
+ importedDepSets[setIndex]?.add(importName);
121
+ break;
127
122
  }
128
- });
129
- });
123
+ }
130
124
  return importedDepSets;
131
125
  }
132
126
  async getDependencies() {
@@ -134,43 +128,25 @@ class TypeScriptDependencyScanner2 {
134
128
  this.#fileRuntimeDependencies.clear();
135
129
  this.#fileTypeDependencies.clear();
136
130
  this.#visitedFiles.clear();
137
- const files = await this.#findTypeScriptFiles(this.#directory);
138
- for (const file of files)
131
+ for (const file of await this.#findFiles("**/*.{ts,tsx}"))
139
132
  await this.#analyzeFile(file, this.#directory);
140
133
  return this.#fileDependencies;
141
134
  }
142
- async#findTypeScriptFiles(directory, {
135
+ async#findFiles(pattern, {
143
136
  excludeBuildFiles = false,
144
137
  excludeTestFiles = false
145
138
  } = {}) {
146
139
  const files = [];
147
- const glob = new Bun.Glob("**/*.{ts,tsx}");
148
- for await (const filePath of glob.scan({ cwd: directory, onlyFiles: true })) {
140
+ for await (const filePath of new Bun.Glob(pattern).scan({ cwd: this.#directory, onlyFiles: true })) {
149
141
  if (isSkippedPath(filePath))
150
142
  continue;
151
143
  if (excludeBuildFiles && filePath === "build.ts")
152
144
  continue;
153
145
  if (excludeTestFiles && testFileRegex.test(filePath))
154
146
  continue;
155
- const fullPath = path.join(directory, filePath);
156
- const relativePath = path.relative(this.#workspaceRoot, fullPath);
157
- if (this.#ig.ignores(relativePath))
158
- continue;
159
- files.push(fullPath);
160
- }
161
- return files;
162
- }
163
- async#findCssFiles(directory) {
164
- const files = [];
165
- const glob = new Bun.Glob("**/*.css");
166
- for await (const filePath of glob.scan({ cwd: directory, onlyFiles: true })) {
167
- if (isSkippedPath(filePath))
168
- continue;
169
- const fullPath = path.join(directory, filePath);
170
- const relativePath = path.relative(this.#workspaceRoot, fullPath);
171
- if (this.#ig.ignores(relativePath))
172
- continue;
173
- files.push(fullPath);
147
+ const fullPath = path.join(this.#directory, filePath);
148
+ if (!this.#ig.ignores(path.relative(this.#workspaceRoot, fullPath)))
149
+ files.push(fullPath);
174
150
  }
175
151
  return files;
176
152
  }
@@ -179,7 +155,7 @@ class TypeScriptDependencyScanner2 {
179
155
  return;
180
156
  this.#visitedFiles.add(filePath);
181
157
  try {
182
- const fileContent = await FileSys.readText(filePath);
158
+ const fileContent = await FileSys2.readText(filePath);
183
159
  const { imports, typeImports } = this.#extractImports(fileContent, filePath);
184
160
  const resolvedImports = await this.#resolveImports(imports, filePath, baseDir);
185
161
  const resolvedTypeImports = await this.#resolveImports(typeImports, filePath, baseDir);
@@ -191,19 +167,17 @@ class TypeScriptDependencyScanner2 {
191
167
  }
192
168
  async#resolveImports(imports, filePath, baseDir) {
193
169
  return await Promise.all(imports.map(async (importPath) => {
194
- if (importPath.startsWith(".")) {
195
- const resolvedPath = `./${path.join(path.relative(baseDir, filePath), importPath)}`;
196
- return await this.#ensureExtension(resolvedPath);
197
- }
198
- return importPath;
170
+ if (!importPath.startsWith("."))
171
+ return importPath;
172
+ return await this.#ensureExtension(`./${path.join(path.relative(baseDir, filePath), importPath)}`);
199
173
  }));
200
174
  }
201
175
  async#ensureExtension(filePath) {
202
- if (await FileSys.fileExists(`${filePath}.ts`))
176
+ if (await FileSys2.fileExists(`${filePath}.ts`))
203
177
  return `${filePath}.ts`;
204
- else if (await FileSys.fileExists(`${filePath}.tsx`))
178
+ else if (await FileSys2.fileExists(`${filePath}.tsx`))
205
179
  return `${filePath}.tsx`;
206
- else if (await FileSys.fileExists(filePath))
180
+ else if (await FileSys2.fileExists(filePath))
207
181
  return filePath;
208
182
  return `${filePath}.ts`;
209
183
  }
@@ -262,22 +236,14 @@ class TypeScriptDependencyScanner2 {
262
236
  `;
263
237
  const projectImports = imports.filter((i) => !i.startsWith("react") && !i.startsWith("@"));
264
238
  const externalImports = imports.filter((i) => i.startsWith("react") || i.startsWith("@"));
265
- if (projectImports.length > 0) {
239
+ if (projectImports.length > 0)
266
240
  graph += ` Project dependencies:
267
- `;
268
- projectImports.forEach((imp) => {
269
- graph += ` \u2192 ${imp}
270
- `;
271
- });
272
- }
273
- if (externalImports.length > 0) {
241
+ ${projectImports.map((imp) => ` \u2192 ${imp}
242
+ `).join("")}`;
243
+ if (externalImports.length > 0)
274
244
  graph += ` External dependencies:
275
- `;
276
- externalImports.forEach((imp) => {
277
- graph += ` \u2192 ${imp}
278
- `;
279
- });
280
- }
245
+ ${externalImports.map((imp) => ` \u2192 ${imp}
246
+ `).join("")}`;
281
247
  graph += `
282
248
  `;
283
249
  }
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-mak3cd28.js";
5
+ } from "./index-rmcw8yc8.js";
6
6
  import {
7
7
  AGENT_BLOCK_START,
8
8
  AGENT_BLOCK_END,
@@ -13,17 +13,17 @@ import {
13
13
  CLAUDE_COMMENT_RULE,
14
14
  AppExecutor,
15
15
  LibExecutor
16
- } from "./index-2tv3fdx4.js";
16
+ } from "./index-ga6hygxr.js";
17
17
  import {
18
18
  collectRecipeSources2,
19
19
  scanRecipes2
20
- } from "./index-by5gpp8x.js";
20
+ } from "./index-hj6w4ka1.js";
21
21
  import {
22
22
  AkanContextAnalyzer
23
- } from "./index-ktb5njgy.js";
23
+ } from "./index-9629w7ns.js";
24
24
  import {
25
- Prompter
26
- } from "./index-h7yw2z9n.js";
25
+ Prompter2
26
+ } from "./index-0bq14vr1.js";
27
27
 
28
28
  // pkgs/@akanjs/cli/agent/agent.script.ts
29
29
  import { Logger as Logger2 } from "akanjs/common";
@@ -106,10 +106,10 @@ ${scopeIndexPointer}
106
106
  `;
107
107
  };
108
108
  var renderGuides = async (context) => {
109
- const conventions = (await Prompter.getInstruction("conventions")).trim();
109
+ const conventions = (await Prompter2.getInstruction("conventions")).trim();
110
110
  if (context.pkgs.some((pkg) => pkg.name === "akanjs"))
111
111
  return conventions;
112
- const onboarding = (await Prompter.getInstruction("workspaceOnboarding")).trim();
112
+ const onboarding = (await Prompter2.getInstruction("workspaceOnboarding")).trim();
113
113
  const appName = context.apps[0]?.name ?? "app";
114
114
  return `${conventions}
115
115
 
@@ -117,7 +117,7 @@ ${onboarding.replaceAll("<%= appName %>", appName)}`;
117
117
  };
118
118
  var renderManagedBlock = async (workspace) => {
119
119
  const context = await AkanContextAnalyzer.analyze(workspace);
120
- const frameworkGuide = await Prompter.getInstruction("framework");
120
+ const frameworkGuide = await Prompter2.getInstruction("framework");
121
121
  const appNames = context.apps.map((app) => app.name);
122
122
  const sampleCleanup = await renderSampleCleanup(workspace, appNames);
123
123
  const recipeIndex = await renderRecipeIndex(workspace);
@@ -126,7 +126,7 @@ var renderManagedBlock = async (workspace) => {
126
126
  const block = `## Workspace
127
127
 
128
128
  - Repo: ${context.repoName}
129
- - Apps: ${context.apps.map((app) => app.name).join(", ") || "none"}
129
+ - Apps: ${appNames.join(", ") || "none"}
130
130
  - Libraries: ${context.libs.map((lib) => lib.name).join(", ") || "none"}
131
131
  - Packages: ${context.pkgs.map((pkg) => pkg.name).join(", ") || "none"}
132
132
 
@@ -138,7 +138,7 @@ ${sampleCleanup}## Akan Module Abstracts
138
138
  - Update the abstract when business invariants, workflows, or public behavior change.
139
139
  - Do not update the abstract for formatting-only, import-only, or style-only changes.
140
140
  - Service modules live in \`lib/_<service>\`, but their abstract file is \`<service>.abstract.md\`.
141
- - Keep an abstract short. Run \`akan compact <app-or-lib>\` to rewrite bloated abstracts down to the invariants the code cannot show; \`akan quality scan\` warns past 300 lines.
141
+ - Keep an abstract short \u2014 the invariants the code cannot show, and nothing it already states. \`akan quality scan\` warns past 300 lines.
142
142
 
143
143
  ## Generated Files
144
144
 
@@ -148,7 +148,7 @@ If generated output is stale or broken, update the owning source file and run \`
148
148
  ${recipeIndex}## MCP Workflow Policy
149
149
 
150
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.
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 three of the five repair tools \u2014 \`repair_generated\`, \`repair_imports\` and \`repair_module_shape\`. \`akan repair format\` and \`akan repair dictionary\` are CLI-only.
152
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
153
  - Split a compound request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
154
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.
@@ -1,9 +1,12 @@
1
1
  // @bun
2
2
  // pkgs/@akanjs/devkit/fileSys.ts
3
3
  import { lstat, rename, rm, stat } from "fs/promises";
4
+ import nodePath from "path";
5
+ import { fileURLToPath } from "url";
4
6
  import { Logger } from "akanjs/common";
7
+ var getDirname2 = (url) => nodePath.dirname(fileURLToPath(url));
5
8
 
6
- class FileSys {
9
+ class FileSys2 {
7
10
  static logger = new Logger("FileSys");
8
11
  static async fileExists(path) {
9
12
  return await Bun.file(path).exists();
@@ -24,7 +27,7 @@ class FileSys {
24
27
  try {
25
28
  return await Bun.file(path).json();
26
29
  } catch (error) {
27
- FileSys.logger.error(`Failed to read JSON file: ${path}`);
30
+ FileSys2.logger.error(`Failed to read JSON file: ${path}`);
28
31
  throw error;
29
32
  }
30
33
  }
@@ -52,4 +55,4 @@ class FileSys {
52
55
  }
53
56
  }
54
57
 
55
- export { FileSys };
58
+ export { getDirname2, FileSys2 };
@@ -0,0 +1,69 @@
1
+ // @bun
2
+ import {
3
+ jsonText
4
+ } from "./index-yy4s1j72.js";
5
+ import {
6
+ akanMcpInstallTargets
7
+ } from "./index-9629w7ns.js";
8
+ import {
9
+ script
10
+ } from "./index-rmcw8yc8.js";
11
+ import {
12
+ ContextRunner2
13
+ } from "./index-dg97qp24.js";
14
+
15
+ // pkgs/@akanjs/cli/context/context.script.ts
16
+ import { Logger } from "akanjs/common";
17
+ var resolveMcpInstallTargets = (target) => {
18
+ if (!target || target === "all")
19
+ return [...akanMcpInstallTargets];
20
+ if (akanMcpInstallTargets.includes(target))
21
+ return [target];
22
+ throw new Error(`Unknown MCP install target: ${target}. Use cursor, claude, codex, or all.`);
23
+ };
24
+ var mcpTargetLabels = {
25
+ cursor: "Cursor",
26
+ claude: "Claude Code",
27
+ codex: "Codex"
28
+ };
29
+
30
+ class ContextScript extends script("context", [ContextRunner2]) {
31
+ async context(workspace, options = {}) {
32
+ Logger.rawLog(await this.contextRunner.getContext(workspace, options));
33
+ }
34
+ async doctor(workspace, options = {}) {
35
+ Logger.rawLog(await this.contextRunner.doctor(workspace, options));
36
+ }
37
+ async mcpInstall(workspace, target, { force = false, mode = "apply" } = {}) {
38
+ const targets = resolveMcpInstallTargets(target);
39
+ const written = [];
40
+ for (const t of targets) {
41
+ const configPath = await this.contextRunner.installMcp(workspace, t, { force, mode });
42
+ written.push(`${mcpTargetLabels[t]}: ${configPath}`);
43
+ }
44
+ Logger.rawLog(`Akan MCP server installed (${mode} mode):
45
+ ${written.map((line) => `- ${line}`).join(`
46
+ `)}`);
47
+ }
48
+ async mcp(workspace, { mode = "apply" } = {}) {
49
+ await this.contextRunner.runMcp(workspace, { mode });
50
+ }
51
+ async mcpCall(workspace, tool, {
52
+ mode = "readonly",
53
+ args = null,
54
+ format = "json"
55
+ } = {}) {
56
+ let parsedArgs = {};
57
+ if (args) {
58
+ const parsed = JSON.parse(args);
59
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
60
+ throw new Error("MCP call args must be a JSON object.");
61
+ }
62
+ parsedArgs = parsed;
63
+ }
64
+ const result = await this.contextRunner.callMcpTool(workspace, tool, parsedArgs, { mode });
65
+ Logger.rawLog(format === "json" ? jsonText(result) : String(result));
66
+ }
67
+ }
68
+
69
+ export { ContextScript };
@@ -0,0 +1,6 @@
1
+ // @bun
2
+ // pkgs/@akanjs/devkit/stripAnsi.ts
3
+ var ansi = new RegExp(`${String.fromCharCode(27)}(?:[@-Z\\\\-_]|\\[[\\s\\S]*?[@-~])`, "g");
4
+ var stripAnsi = (text) => text.replace(ansi, "");
5
+
6
+ export { stripAnsi };
@@ -1,44 +1,33 @@
1
1
  // @bun
2
2
  import {
3
3
  GlobalConfig,
4
- CloudApi,
5
- AiSession
6
- } from "./index-kn1h7p1x.js";
7
- import {
8
- PkgExecutor
9
- } from "./index-2tv3fdx4.js";
4
+ CloudApi
5
+ } from "./index-22d57v4c.js";
10
6
  import {
11
7
  script
12
- } from "./index-mak3cd28.js";
8
+ } from "./index-rmcw8yc8.js";
9
+ import {
10
+ PkgExecutor
11
+ } from "./index-ga6hygxr.js";
13
12
  import {
14
13
  ApplicationScript
15
- } from "./index-v0qh106m.js";
14
+ } from "./index-z50k041j.js";
16
15
  import {
17
16
  PackageScript
18
- } from "./index-ws5e0j51.js";
17
+ } from "./index-mgfx3mfs.js";
19
18
  import {
20
19
  CloudRunner
21
- } from "./index-2hq52jq3.js";
20
+ } from "./index-yjkte9aj.js";
22
21
 
23
22
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
24
23
  import { Logger } from "akanjs/common";
25
- class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, PackageScript]) {
24
+ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, PackageScript]) {
26
25
  async login(workspace, host = GlobalConfig.akanCloudHost) {
27
26
  await this.cloudRunner.login(host, workspace);
28
27
  }
29
28
  async logout(workspace, host = GlobalConfig.akanCloudHost) {
30
29
  await this.cloudRunner.logout(host);
31
30
  }
32
- async setLlm(workspace) {
33
- await this.cloudRunner.setLlm();
34
- }
35
- resetLlm(workspace) {
36
- this.cloudRunner.resetLlm();
37
- }
38
- async ask(question, workspace) {
39
- const session = new AiSession("general", { workspace, isContinued: true });
40
- await session.ask(question);
41
- }
42
31
  async downloadEnv(workspace, workspaceId = workspace.getWorkspaceId({ allowEmpty: true }), { host = GlobalConfig.akanCloudHost } = {}) {
43
32
  if (workspaceId) {
44
33
  await this.login(workspace, host);
@@ -48,29 +37,61 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
48
37
  }
49
38
  await this.cloudRunner.downloadEnvByScp(workspace);
50
39
  }
51
- async uploadEnv(workspace, { host = GlobalConfig.akanCloudHost } = {}) {
52
- const workspaceId = workspace.getWorkspaceId({ allowEmpty: true });
53
- const { path } = await this.cloudRunner.gatherEnvFiles(workspace);
40
+ async uploadEnv(workspace, {
41
+ host = GlobalConfig.akanCloudHost,
42
+ workspaceId = workspace.getWorkspaceId({ allowEmpty: true }),
43
+ scope,
44
+ archivePath
45
+ } = {}) {
46
+ if (scope && !workspaceId)
47
+ throw new Error("A scoped env upload needs a cloud workspace id \u2014 the scp target is workspace-wide.");
48
+ const { files, path } = await this.cloudRunner.gatherEnvFiles(workspace, { scope, archivePath });
54
49
  if (workspaceId) {
55
50
  await this.login(workspace, host);
56
51
  const cloudApi = await CloudApi.fromHost(workspace, host);
57
52
  await this.cloudRunner.uploadEnv(cloudApi, workspaceId, path);
58
- return;
53
+ return { workspaceId, files };
59
54
  }
60
55
  await this.cloudRunner.uploadEnvByScp(workspace, path);
56
+ return { workspaceId: null, files };
61
57
  }
62
- async deployAkan(workspace, { test = true, registryUrl } = {}) {
58
+ async deployAkan(workspace, {
59
+ test = true,
60
+ registryUrl,
61
+ platforms = []
62
+ } = {}) {
63
63
  const akanPkgs = await this.cloudRunner.getAkanPkgs(workspace);
64
64
  await this.packageScript.updateWorskpaceRootPackageJson(workspace);
65
65
  const pkgs = akanPkgs.map((pkgName) => PkgExecutor.from(workspace, pkgName));
66
- if (test)
67
- for (const pkg of pkgs)
68
- await this.applicationScript.test(pkg);
66
+ if (test) {
67
+ const platformRun = platforms.length ? await this.cloudRunner.startPlatformTests(workspace, platforms, akanPkgs) : null;
68
+ let localFailure = null;
69
+ try {
70
+ for (const pkg of pkgs)
71
+ await this.applicationScript.test(pkg);
72
+ } catch (error) {
73
+ localFailure = error;
74
+ }
75
+ if (platformRun)
76
+ await this.cloudRunner.settlePlatformTests(platformRun, {
77
+ interactive: !localFailure,
78
+ recordStreaks: !localFailure,
79
+ checkDrift: true
80
+ });
81
+ if (localFailure)
82
+ throw localFailure;
83
+ }
69
84
  for (const pkg of pkgs)
70
85
  await this.packageScript.buildPackage(pkg);
71
86
  await this.packageScript.verifyAkanPublishPackages(workspace);
72
87
  await this.cloudRunner.deployAkan(workspace, akanPkgs, { registryUrl });
73
88
  }
89
+ async testPlatforms(workspace, { platforms, pkgs }) {
90
+ if (!platforms.length)
91
+ throw new Error("No platform to test on \u2014 pass --platforms linux,windows");
92
+ const run = await this.cloudRunner.startPlatformTests(workspace, platforms, pkgs ?? await this.cloudRunner.getAkanPkgs(workspace));
93
+ await this.cloudRunner.settlePlatformTests(run, { interactive: false, recordStreaks: false, checkDrift: false });
94
+ }
74
95
  async update(workspace, tag = "latest", { registryUrl } = {}) {
75
96
  const spinner = workspace.spinning("Updating Akan.js packages and CLI...");
76
97
  await this.cloudRunner.update(workspace, tag, { registryUrl });
@@ -80,4 +101,4 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
80
101
  }
81
102
  }
82
103
 
83
- export { CloudScript };
104
+ export { CloudScript2 };