@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.
- package/.build-stamp +1 -1
- package/CodeAgent-q2m47rqp.js +9 -0
- package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
- package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
- package/CodeTui-pdqhc3sn.js +1457 -0
- package/README.md +3 -0
- package/TunnelShare-scf4e4pd.js +9 -0
- package/{agent.command-d2gfxfck.js → agent.command-ttn09rx3.js} +8 -9
- package/akanCode.js +102 -0
- package/application.command-7gweenv7.js +179 -0
- package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-38exmejd.js} +63 -64
- package/buildBatch.proc.js +26 -25
- package/cloud.command-bhztw7c2.js +95 -0
- package/cloud.script-aabyhgba.js +20 -0
- package/code.command-6s8c0k91.js +154 -0
- package/commandManifest.json +1 -1
- package/consoleToStderr-h5bryj94.js +7 -0
- package/context.command-phmgywt2.js +48 -0
- package/context.runner-yvyw5g2d.js +21 -0
- package/{dependencyScanner-shs82ynp.js → dependencyScanner-ye2e6pdz.js} +2 -2
- package/{devTui-40ggmd99.js → devTui-q7k7bakd.js} +122 -40
- package/fileSys-5ngz93ga.js +9 -0
- package/guideline.command-7jk47fgq.js +42 -0
- package/guidelines/agentRule/agentRule.instruction.md +209 -28
- package/guidelines/conventions/conventions.instruction.md +96 -29
- package/guidelines/fieldRule/fieldRule.instruction.md +1 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
- package/guidelines/queryRule/queryRule.instruction.md +17 -7
- package/guidelines/runtimeRule/runtimeRule.instruction.md +77 -3
- package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
- package/guidelines/transportRule/transportRule.instruction.md +51 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
- package/incrementalBuilder.proc.js +31 -48
- package/{index-h7yw2z9n.js → index-0bq14vr1.js} +8 -14
- package/{index-259dsnz3.js → index-1db2cw0y.js} +5 -8
- package/index-22d57v4c.js +266 -0
- package/index-3hx1z96c.js +87 -0
- package/{index-kcxmv48c.js → index-3t7g9e4r.js} +45 -79
- package/{index-ne2qy0nk.js → index-4dn1p115.js} +12 -12
- package/{index-q0y2jq9j.js → index-5b6tavv3.js} +6 -3
- package/index-7cqjvraf.js +69 -0
- package/index-7md2g9vw.js +6 -0
- package/{index-zry5nz81.js → index-8kb5p54p.js} +51 -30
- package/{index-ktb5njgy.js → index-9629w7ns.js} +49 -99
- package/index-9dp031by.js +12 -0
- package/{index-a64esmtb.js → index-aadpbnt2.js} +172 -308
- package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
- package/index-c6eggbee.js +123 -0
- package/index-d0arnrm8.js +700 -0
- package/index-d2242ksy.js +99 -0
- package/{index-600zhnve.js → index-dg97qp24.js} +70 -200
- package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
- package/{index-w8kmx1b6.js → index-fgq75haa.js} +198 -290
- package/{index-2tv3fdx4.js → index-ga6hygxr.js} +944 -1333
- package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
- package/index-hr5n7t4x.js +465 -0
- package/{index-hwkygn9s.js → index-khpfpcsd.js} +302 -33
- package/{index-7737gxcp.js → index-m0ms3n1c.js} +107 -241
- package/{index-ws5e0j51.js → index-mgfx3mfs.js} +43 -26
- package/index-p6pbz9n5.js +25 -0
- package/index-pp54p5zk.js +53 -0
- package/{index-j9yhg404.js → index-q44jbw48.js} +4 -7
- package/{index-mak3cd28.js → index-rmcw8yc8.js} +137 -255
- package/{index-pnqbkf5p.js → index-rnt66vym.js} +6 -2
- package/index-smme4r47.js +49 -0
- package/index-tgjy8xf3.js +187 -0
- package/index-v5eayqqw.js +2729 -0
- package/index-wa5jbxj1.js +760 -0
- package/{index-4edzf1gr.js → index-wp43xrjv.js} +77 -150
- package/{index-fz5q3gd7.js → index-ya5qbmyg.js} +10 -17
- package/index-yjkte9aj.js +1119 -0
- package/{index-gyd220p2.js → index-yy4s1j72.js} +554 -577
- package/{index-v0qh106m.js → index-z50k041j.js} +580 -862
- package/index.js +23 -22
- package/{library.command-nbsky672.js → library.command-ccb1cp92.js} +4 -5
- package/{localRegistry.command-yeq57wjr.js → localRegistry.command-ajb9n87j.js} +23 -42
- package/{module.command-29vqzrh8.js → module.command-5k6h407d.js} +8 -11
- package/{package.command-axv0abmn.js → package.command-e6ntvpez.js} +6 -7
- package/package.json +14 -6
- package/{page.command-vs9s3zrh.js → page.command-v4f90wb8.js} +4 -5
- package/{primitive.command-cbxmqbtc.js → primitive.command-g6km57q5.js} +9 -22
- package/prompter-ptaa3nk0.js +8 -0
- package/{quality.command-gmbs7nws.js → quality.command-de3p36pz.js} +205 -377
- package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
- package/{repair.command-bqsjptsj.js → repair.command-d3x1javq.js} +11 -35
- package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
- package/{scalar.command-6k1vhe9s.js → scalar.command-7ezrac2b.js} +7 -10
- package/skills/akan-code/SKILL.md +130 -0
- package/skills/akan-debug/SKILL.md +42 -0
- package/skills/akan-deps/SKILL.md +50 -0
- package/skills/akan-err/SKILL.md +39 -0
- package/skills/akan-module/SKILL.md +45 -0
- package/skills/akan-scaffold/SKILL.md +76 -0
- package/skills/akan-scalar/SKILL.md +52 -0
- package/skills/akan-service/SKILL.md +34 -0
- package/skills/akan-store/SKILL.md +67 -0
- package/skills/akan-ui/SKILL.md +63 -0
- package/skills/akan-validate/SKILL.md +44 -0
- package/{subspace.command-fwjfcts7.js → subspace.command-ps71ynp6.js} +138 -67
- package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
- package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
- package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
- package/templates/appSample/lib/task/task.abstract.ts +12 -32
- package/templates/appSample/lib/task/task.signal.spec.ts +15 -18
- package/templates/appSample/lib/task/task.signal.test.ts +15 -1
- package/templates/appSample/lib/task/task.signal.ts +1 -1
- package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
- package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
- package/templates/client.ts +7 -30
- package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
- package/templates/crudPages/[__model__Id]/page.tsx +2 -1
- package/templates/crudPages/new/page.tsx +2 -1
- package/templates/crudPages/page.tsx +2 -1
- package/templates/crudSinglePage/page.tsx +2 -1
- package/templates/lib/__lib/lib.dictionary.ts +0 -2
- package/templates/lib/__lib/lib.document.ts +0 -2
- package/templates/lib/sig.ts +8 -30
- package/templates/localDev/docker-compose.yaml.template +3 -14
- package/templates/module/__model__.signal.ts +12 -4
- package/templates/pkgRoot/tsconfig.json.template +2 -7
- package/templates/server.ts +0 -2
- package/templates/service/__model__.abstract.md.template +8 -0
- package/templates/workspaceRoot/.gitignore.template +0 -1
- package/tunnel.command-hsrv2mny.js +129 -0
- package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
- package/typecheck.proc.js +1 -1
- package/workflow.command-z2p32nmf.js +79 -0
- package/{workspace.command-8s050m0h.js → workspace.command-tmdqkrh0.js} +77 -109
- package/abstractCompactor-mjh5ppsq.js +0 -101
- package/application.command-pj2m7584.js +0 -204
- package/applicationReleasePackager-4yasxwv9.js +0 -244
- package/capacitorApp-36rbr858.js +0 -12
- package/cloud.command-jshwdq22.js +0 -93
- package/context.command-ez8a0zyz.js +0 -80
- package/devTuiView-c08ccbat.js +0 -9
- package/getDirname-dr3jz1xg.js +0 -7
- package/guideline.command-xmqwx8zm.js +0 -359
- package/guidelines/agentRule/agentRule.generate.json +0 -31
- package/guidelines/componentRule/componentRule.generate.json +0 -31
- package/guidelines/conventions/conventions.generate.json +0 -25
- package/guidelines/cssRule/cssRule.generate.json +0 -31
- package/guidelines/docPageRule/docPageRule.generate.json +0 -31
- package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
- package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
- package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
- package/guidelines/enumConstant/enumConstant.generate.json +0 -31
- package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
- package/guidelines/fieldRule/fieldRule.generate.json +0 -31
- package/guidelines/framework/framework.generate.json +0 -32
- package/guidelines/mcpRule/mcpRule.generate.json +0 -35
- package/guidelines/modelConstant/modelConstant.generate.json +0 -32
- package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
- package/guidelines/modelDocument/modelDocument.generate.json +0 -31
- package/guidelines/modelService/modelService.generate.json +0 -31
- package/guidelines/modelSignal/modelSignal.generate.json +0 -31
- package/guidelines/modelStore/modelStore.generate.json +0 -31
- package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
- package/guidelines/modelUnit/modelUnit.generate.json +0 -31
- package/guidelines/modelUtil/modelUtil.generate.json +0 -31
- package/guidelines/modelView/modelView.generate.json +0 -31
- package/guidelines/modelZone/modelZone.generate.json +0 -31
- package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
- package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
- package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
- package/guidelines/queryRule/queryRule.generate.json +0 -31
- package/guidelines/recipeRule/recipeRule.generate.json +0 -31
- package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
- package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
- package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
- package/guidelines/scalarModule/scalarModule.generate.json +0 -31
- package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
- package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
- package/guidelines/ssrRule/ssrRule.generate.json +0 -31
- package/guidelines/transportRule/transportRule.generate.json +0 -31
- package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
- package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
- package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -33
- package/index-2hq52jq3.js +0 -465
- package/index-47pj3aee.js +0 -76
- package/index-6wwzs1bc.js +0 -7
- package/index-8pm30m73.js +0 -841
- package/index-kn1h7p1x.js +0 -560
- package/index-meh558jy.js +0 -65
- package/index-rwg2aa4f.js +0 -229
- package/index-wt7qrtd4.js +0 -1516
- package/templates/__scalar/__model__/__model__.abstract.md +0 -28
- package/templates/module/__model__.abstract.md +0 -28
- package/templates/service/__model__.abstract.md +0 -28
- 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
|
-
|
|
4
|
-
} from "./index-
|
|
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) =>
|
|
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.#
|
|
58
|
-
|
|
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
|
|
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
|
|
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
|
|
74
|
-
const fileContent = await
|
|
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
|
|
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 =
|
|
110
|
-
for (
|
|
111
|
-
|
|
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
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
|
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#
|
|
135
|
+
async#findFiles(pattern, {
|
|
143
136
|
excludeBuildFiles = false,
|
|
144
137
|
excludeTestFiles = false
|
|
145
138
|
} = {}) {
|
|
146
139
|
const files = [];
|
|
147
|
-
const
|
|
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
|
-
|
|
157
|
-
|
|
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
|
|
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
|
-
|
|
196
|
-
|
|
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
|
|
176
|
+
if (await FileSys2.fileExists(`${filePath}.ts`))
|
|
203
177
|
return `${filePath}.ts`;
|
|
204
|
-
else if (await
|
|
178
|
+
else if (await FileSys2.fileExists(`${filePath}.tsx`))
|
|
205
179
|
return `${filePath}.tsx`;
|
|
206
|
-
else if (await
|
|
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
|
-
|
|
269
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
16
|
+
} from "./index-ga6hygxr.js";
|
|
17
17
|
import {
|
|
18
18
|
collectRecipeSources2,
|
|
19
19
|
scanRecipes2
|
|
20
|
-
} from "./index-
|
|
20
|
+
} from "./index-hj6w4ka1.js";
|
|
21
21
|
import {
|
|
22
22
|
AkanContextAnalyzer
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-9629w7ns.js";
|
|
24
24
|
import {
|
|
25
|
-
|
|
26
|
-
} from "./index-
|
|
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
|
|
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
|
|
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
|
|
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: ${
|
|
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
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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 };
|
|
@@ -1,44 +1,33 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
GlobalConfig,
|
|
4
|
-
CloudApi
|
|
5
|
-
|
|
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-
|
|
8
|
+
} from "./index-rmcw8yc8.js";
|
|
9
|
+
import {
|
|
10
|
+
PkgExecutor
|
|
11
|
+
} from "./index-ga6hygxr.js";
|
|
13
12
|
import {
|
|
14
13
|
ApplicationScript
|
|
15
|
-
} from "./index-
|
|
14
|
+
} from "./index-z50k041j.js";
|
|
16
15
|
import {
|
|
17
16
|
PackageScript
|
|
18
|
-
} from "./index-
|
|
17
|
+
} from "./index-mgfx3mfs.js";
|
|
19
18
|
import {
|
|
20
19
|
CloudRunner
|
|
21
|
-
} from "./index-
|
|
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
|
|
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, {
|
|
52
|
-
|
|
53
|
-
|
|
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, {
|
|
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
|
-
|
|
68
|
-
|
|
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 {
|
|
104
|
+
export { CloudScript2 };
|