@akanjs/cli 3.0.0-beta.8 → 3.0.0
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-2vmp9qe0.js +9 -0
- package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
- package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
- package/CodeTui-5ed6bg2a.js +1457 -0
- package/README.ko.md +83 -28
- package/README.md +70 -27
- package/TunnelShare-cwh9ezsm.js +9 -0
- package/{agent.command-0q17pnrs.js → agent.command-gn73rhe7.js} +8 -9
- package/akanCode.js +102 -0
- package/application.command-e968t0hw.js +246 -0
- package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-64taxseg.js} +121 -77
- package/buildBatch.proc.js +120 -32
- package/cloud.command-0jm301rr.js +95 -0
- package/cloud.script-nemnzjpv.js +20 -0
- package/code.command-18kcm7hq.js +154 -0
- package/commandManifest.json +1 -1
- package/consoleToStderr-h5bryj94.js +7 -0
- package/context.command-trd9bn18.js +48 -0
- package/context.runner-y5hwh673.js +21 -0
- package/{dependencyScanner-shs82ynp.js → dependencyScanner-06z2dmrr.js} +2 -2
- package/{devTui-m1atgkc9.js → devTui-q7k7bakd.js} +122 -40
- package/fileSys-wzzrntkw.js +9 -0
- package/guideline.command-bdmdn2de.js +42 -0
- package/guidelines/agentRule/agentRule.instruction.md +154 -26
- package/guidelines/conventions/conventions.instruction.md +134 -48
- package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
- package/guidelines/queryRule/queryRule.instruction.md +21 -7
- package/guidelines/runtimeRule/runtimeRule.instruction.md +291 -6
- package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
- package/guidelines/transportRule/transportRule.instruction.md +10 -8
- package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +20 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
- package/incrementalBuilder.proc.js +564 -109
- package/index-0wpybxtr.js +2729 -0
- package/{index-kcxmv48c.js → index-2ahj896a.js} +45 -79
- package/index-2wc41k5w.js +49 -0
- package/index-3hx1z96c.js +87 -0
- package/{index-2tv3fdx4.js → index-3w94e7n3.js} +1228 -1458
- package/{index-hwkygn9s.js → index-48k96p55.js} +325 -36
- package/index-4npz05nm.js +187 -0
- package/{index-q0y2jq9j.js → index-52w0fvh8.js} +21 -4
- package/index-6he6gvfg.js +4300 -0
- package/index-7md2g9vw.js +6 -0
- package/{index-04bk599g.js → index-93j60em0.js} +10 -17
- package/index-94s080qm.js +266 -0
- package/index-9dp031by.js +12 -0
- package/{index-ktb5njgy.js → index-9z771ptz.js} +49 -99
- package/{index-y6n8nmny.js → index-abxpehf8.js} +75 -203
- package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
- package/{index-9077wzd2.js → index-by9pxkr0.js} +43 -26
- package/index-c6eggbee.js +123 -0
- package/index-d2242ksy.js +99 -0
- package/index-drehwpdt.js +1119 -0
- package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
- package/{index-ffvk10zz.js → index-f3c78nd6.js} +107 -241
- package/index-gbggbqcp.js +1058 -0
- package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
- package/index-hsmtysz4.js +53 -0
- package/{index-j9yhg404.js → index-jmrn54tt.js} +4 -7
- package/{index-a64esmtb.js → index-kcdj1z5v.js} +523 -1022
- package/{index-d43r08tf.js → index-kqabytj7.js} +77 -150
- package/{index-vyvre9en.js → index-mbxbhay5.js} +6 -2
- package/{index-vxtad5bd.js → index-mgxpx3f2.js} +5 -8
- package/index-p6pbz9n5.js +25 -0
- package/{index-sj5vxr8f.js → index-p993efkq.js} +981 -897
- package/{index-2xp0kfkt.js → index-pmhqttv3.js} +37 -25
- package/index-tqm7jjcn.js +700 -0
- package/{index-0g7r8xz3.js → index-vpj42xwt.js} +114 -232
- package/index-wa5jbxj1.js +760 -0
- package/{index-k2j1hc4r.js → index-wprnsjms.js} +12 -12
- package/{index-gyd220p2.js → index-y3mphr1m.js} +554 -577
- package/index-yg7jhz8x.js +69 -0
- package/{index-h7yw2z9n.js → index-zzvvc845.js} +8 -14
- package/index.js +23 -22
- package/{library.command-qzzbj6d8.js → library.command-9h749a1x.js} +4 -5
- package/{localRegistry.command-vyrgg4xw.js → localRegistry.command-2bqqhxyz.js} +23 -43
- package/{module.command-rq5hq3ax.js → module.command-nv8nzgft.js} +8 -12
- package/{package.command-d9hd6v9n.js → package.command-mq4bggp6.js} +6 -7
- package/package.json +15 -7
- package/{page.command-126d56te.js → page.command-j639n707.js} +4 -5
- package/{primitive.command-taxd1538.js → primitive.command-kz6849th.js} +9 -23
- package/prompter-76k56b37.js +8 -0
- package/{quality.command-6gsna0a3.js → quality.command-4hyabwkb.js} +205 -377
- package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
- package/{repair.command-tq2dgy72.js → repair.command-a9awpbqr.js} +11 -35
- package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
- package/{scalar.command-3bcmrrkv.js → scalar.command-ma4fpm9m.js} +7 -11
- 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-eddzqpx3.js → subspace.command-3k2pmrs4.js} +53 -62
- package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
- package/templates/app/page/_index.tsx +257 -258
- package/templates/app/page/_layout.tsx +5 -1
- package/templates/app/page/_overrides.tsx +12 -0
- package/templates/app/page/styles.css.template +316 -14
- package/templates/app/public/apple-touch-icon.png +0 -0
- package/templates/app/public/favicon.ico +0 -0
- package/templates/app/public/jelly/cloud.webp +0 -0
- package/templates/app/public/jelly/comet.webp +0 -0
- package/templates/app/public/jelly/moon.webp +0 -0
- package/templates/app/public/jelly/planet.webp +0 -0
- package/templates/app/public/jelly/rocket.webp +0 -0
- package/templates/app/public/jelly/star.webp +0 -0
- package/templates/app/public/jelly/sugar.webp +0 -0
- package/templates/app/public/logo.png +0 -0
- package/templates/app/ui/Recipe/index.ts +9 -0
- package/templates/app/ui/Recipe/jellyButton.ts +63 -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.Unit.tsx +1 -1
- package/templates/appSample/lib/task/Task.Util.tsx +10 -13
- package/templates/appSample/lib/task/Task.View.tsx +2 -2
- package/templates/appSample/lib/task/Task.Zone.tsx +5 -2
- package/templates/appSample/lib/task/task.abstract.ts +12 -32
- package/templates/appSample/lib/task/task.signal.spec.ts +1 -15
- package/templates/appSample/lib/task/task.signal.test.ts +15 -1
- package/templates/appSample/lib/task/task.signal.ts +10 -8
- package/templates/appSample/page/task/[taskId]/_index.tsx +6 -6
- package/templates/appSample/page/task/[taskId]/edit.tsx +5 -4
- package/templates/appSample/page/task/_index.tsx +4 -3
- package/templates/appSample/page/task/_layout.tsx +1 -1
- package/templates/appSample/page/task/new.tsx +5 -4
- package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
- package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
- package/templates/appSample/ui/GlobalLoading.tsx +2 -1
- package/templates/appSample/ui/QuantityControl.tsx +3 -3
- 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 +1 -3
- package/templates/service/__model__.abstract.md.template +8 -0
- package/templates/workspaceRoot/.gitignore.template +0 -1
- package/templates/workspaceRoot/AGENTS.md.template +6 -0
- package/templates/workspaceRoot/package.json.template +1 -3
- package/tunnel.command-xwr46b66.js +129 -0
- package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
- package/typecheck.proc.js +1 -1
- package/workflow.command-t7wqe4h7.js +79 -0
- package/{workspace.command-06wvstgr.js → workspace.command-4derhzrh.js} +79 -109
- package/abstractCompactor-gmkc0z8j.js +0 -102
- package/application.command-18y0s485.js +0 -204
- package/applicationReleasePackager-4yasxwv9.js +0 -244
- package/capacitorApp-36rbr858.js +0 -12
- package/cloud.command-av97ndh6.js +0 -94
- package/cloud.script-cm11xjdz.js +0 -20
- package/context.command-5v37ef3n.js +0 -81
- package/devTuiView-0hc2emhe.js +0 -9
- package/getDirname-dr3jz1xg.js +0 -7
- package/guideline.command-4pz9g1rt.js +0 -360
- 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-47pj3aee.js +0 -76
- package/index-5ystnsd5.js +0 -841
- package/index-6wwzs1bc.js +0 -7
- package/index-a17x49vg.js +0 -229
- package/index-m0xccmmm.js +0 -228
- package/index-meh558jy.js +0 -65
- package/index-rtxxan88.js +0 -471
- package/index-te54x9zm.js +0 -338
- package/index-w8kmx1b6.js +0 -2176
- 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/templates/workspaceRoot/patches/react-dom@19.2.7.patch.template +0 -62
- package/workflow.command-gtdnzvbz.js +0 -108
|
@@ -5,33 +5,26 @@ import {
|
|
|
5
5
|
writeGeneratedSyncState,
|
|
6
6
|
createRepairReport,
|
|
7
7
|
renderRepairReport
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-y3mphr1m.js";
|
|
9
9
|
import {
|
|
10
10
|
AkanContextAnalyzer
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-9z771ptz.js";
|
|
12
12
|
import {
|
|
13
13
|
runner
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-vpj42xwt.js";
|
|
15
15
|
|
|
16
16
|
// pkgs/@akanjs/cli/repair/repair.runner.ts
|
|
17
|
-
var
|
|
17
|
+
var spawnShell = async (workspace, command) => await workspace.spawn("bash", ["-lc", command.startsWith("akan ") ? `bun run ${command}` : command], {
|
|
18
|
+
cwd: workspace.workspaceRoot
|
|
19
|
+
});
|
|
18
20
|
var defaultExecutor = (workspace) => async (command) => {
|
|
21
|
+
const base = { command: command.command, reason: command.reason };
|
|
19
22
|
try {
|
|
20
|
-
|
|
21
|
-
cwd: workspace.workspaceRoot
|
|
22
|
-
});
|
|
23
|
-
return {
|
|
24
|
-
command: command.command,
|
|
25
|
-
reason: command.reason,
|
|
26
|
-
status: "passed",
|
|
27
|
-
exitCode: 0,
|
|
28
|
-
stdout
|
|
29
|
-
};
|
|
23
|
+
return { ...base, status: "passed", exitCode: 0, stdout: await spawnShell(workspace, command.command) };
|
|
30
24
|
} catch (error) {
|
|
31
25
|
const commandError = error;
|
|
32
26
|
return {
|
|
33
|
-
|
|
34
|
-
reason: command.reason,
|
|
27
|
+
...base,
|
|
35
28
|
status: "failed",
|
|
36
29
|
exitCode: commandError.code ?? 1,
|
|
37
30
|
stdout: commandError.stdout,
|
|
@@ -158,4 +151,4 @@ class RepairRunner extends runner("repair") {
|
|
|
158
151
|
}
|
|
159
152
|
}
|
|
160
153
|
|
|
161
|
-
export { RepairRunner };
|
|
154
|
+
export { spawnShell, RepairRunner };
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
FileSys2
|
|
4
|
+
} from "./index-52w0fvh8.js";
|
|
5
|
+
import {
|
|
6
|
+
ConfigLock
|
|
7
|
+
} from "./index-3hx1z96c.js";
|
|
8
|
+
|
|
9
|
+
// pkgs/@akanjs/devkit/cloud/globalConfig.ts
|
|
10
|
+
import { mkdir, rm, writeFile } from "fs/promises";
|
|
11
|
+
import dayjs from "dayjs";
|
|
12
|
+
|
|
13
|
+
// pkgs/@akanjs/devkit/cloud/constants.ts
|
|
14
|
+
import path from "path";
|
|
15
|
+
var basePath = path.join(Bun.env.HOME ?? Bun.env.USERPROFILE ?? "", ".akan");
|
|
16
|
+
var configPath = path.join(basePath, "config.json");
|
|
17
|
+
var getDefaultHostConfig = (host = GlobalConfig.akanCloudHost) => ({ host });
|
|
18
|
+
var defaultAkanGlobalConfig = {
|
|
19
|
+
cloudHost: {},
|
|
20
|
+
remoteEnvServers: {},
|
|
21
|
+
testTargets: {}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// pkgs/@akanjs/devkit/cloud/globalConfig.ts
|
|
25
|
+
class GlobalConfig {
|
|
26
|
+
static akanCloudHost = process.env.USE_AKANJS_PKGS === "true" ? `http://localhost:${process.env.CLOUD_HOST_PORT ?? 8283}` : "https://cloud.akanjs.com";
|
|
27
|
+
static async#getAkanGlobalConfig() {
|
|
28
|
+
const exists = await FileSys2.fileExists(configPath);
|
|
29
|
+
const akanConfig = exists ? await FileSys2.readJson(configPath) : {};
|
|
30
|
+
return {
|
|
31
|
+
...defaultAkanGlobalConfig,
|
|
32
|
+
...akanConfig,
|
|
33
|
+
cloudHost: akanConfig.cloudHost ?? defaultAkanGlobalConfig.cloudHost,
|
|
34
|
+
remoteEnvServers: akanConfig.remoteEnvServers ?? defaultAkanGlobalConfig.remoteEnvServers,
|
|
35
|
+
testTargets: akanConfig.testTargets ?? defaultAkanGlobalConfig.testTargets
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
static async#setAkanGlobalConfig(akanConfig) {
|
|
39
|
+
await mkdir(basePath, { recursive: true, mode: 448 });
|
|
40
|
+
const temp = `${configPath}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
41
|
+
try {
|
|
42
|
+
await writeFile(temp, JSON.stringify(akanConfig, null, 2), { mode: 384 });
|
|
43
|
+
await FileSys2.replace(temp, configPath);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
await rm(temp, { force: true });
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
static #lockPath = `${configPath}.lock`;
|
|
50
|
+
static async#update(mutate) {
|
|
51
|
+
await ConfigLock.run(GlobalConfig.#lockPath, async () => {
|
|
52
|
+
await GlobalConfig.#setAkanGlobalConfig(mutate(await GlobalConfig.#getAkanGlobalConfig()));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
static async getHostConfig(host = GlobalConfig.akanCloudHost) {
|
|
56
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
57
|
+
return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? getDefaultHostConfig(host));
|
|
58
|
+
}
|
|
59
|
+
static async setHostConfig(config = getDefaultHostConfig()) {
|
|
60
|
+
await GlobalConfig.#update((akanConfig) => GlobalConfig.#withHost(akanConfig, config));
|
|
61
|
+
}
|
|
62
|
+
static #withHost(akanConfig, config) {
|
|
63
|
+
return {
|
|
64
|
+
...akanConfig,
|
|
65
|
+
cloudHost: { ...akanConfig.cloudHost, [config.host]: GlobalConfig.toHostConfigDto(config) }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
static async refreshHostAuth(host, refresh) {
|
|
69
|
+
try {
|
|
70
|
+
return await ConfigLock.run(GlobalConfig.#lockPath, async () => {
|
|
71
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
72
|
+
const current = GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? getDefaultHostConfig(host));
|
|
73
|
+
const accessToken = current.auth?.accessToken;
|
|
74
|
+
const refreshToken = accessToken?.refreshToken;
|
|
75
|
+
if (!accessToken || !refreshToken || !GlobalConfig.needRefreshToken(accessToken))
|
|
76
|
+
return current;
|
|
77
|
+
const claimed = {
|
|
78
|
+
...current,
|
|
79
|
+
auth: { ...current.auth, accessToken: { ...accessToken, refreshToken: null } }
|
|
80
|
+
};
|
|
81
|
+
await GlobalConfig.#setAkanGlobalConfig(GlobalConfig.#withHost(akanConfig, claimed));
|
|
82
|
+
const next = await refresh(refreshToken).catch(() => null);
|
|
83
|
+
if (!next?.jwt)
|
|
84
|
+
return claimed;
|
|
85
|
+
const refreshed = { ...current, auth: { ...current.auth, accessToken: next } };
|
|
86
|
+
await GlobalConfig.#setAkanGlobalConfig(GlobalConfig.#withHost(await GlobalConfig.#getAkanGlobalConfig(), refreshed));
|
|
87
|
+
return refreshed;
|
|
88
|
+
});
|
|
89
|
+
} catch {
|
|
90
|
+
return await GlobalConfig.getHostConfig(host);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
static async getRemoteEnvServers() {
|
|
94
|
+
return (await GlobalConfig.#getAkanGlobalConfig()).remoteEnvServers;
|
|
95
|
+
}
|
|
96
|
+
static async setRemoteEnvServer(name, config) {
|
|
97
|
+
await GlobalConfig.#update((akanConfig) => ({
|
|
98
|
+
...akanConfig,
|
|
99
|
+
remoteEnvServers: { ...akanConfig.remoteEnvServers, [name]: config }
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
static async removeRemoteEnvServer(name) {
|
|
103
|
+
await GlobalConfig.#update((akanConfig) => {
|
|
104
|
+
const { [name]: _, ...remoteEnvServers } = akanConfig.remoteEnvServers;
|
|
105
|
+
return { ...akanConfig, remoteEnvServers };
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
static async getTestTargets() {
|
|
109
|
+
return (await GlobalConfig.#getAkanGlobalConfig()).testTargets;
|
|
110
|
+
}
|
|
111
|
+
static async setTestTargets(testTargets) {
|
|
112
|
+
await GlobalConfig.#update((akanConfig) => ({
|
|
113
|
+
...akanConfig,
|
|
114
|
+
testTargets: { ...akanConfig.testTargets, ...testTargets }
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
static needRefreshToken(accessToken) {
|
|
118
|
+
return !!accessToken?.expiresAt?.isBefore(dayjs().add(1, "hour"));
|
|
119
|
+
}
|
|
120
|
+
static toAccessToken(accessToken) {
|
|
121
|
+
return {
|
|
122
|
+
jwt: accessToken.jwt,
|
|
123
|
+
refreshToken: accessToken.refreshToken ?? null,
|
|
124
|
+
expiresAt: accessToken.expiresAt ? dayjs(accessToken.expiresAt) : null
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
static toAccessTokenDto(accessToken) {
|
|
128
|
+
return {
|
|
129
|
+
jwt: accessToken.jwt,
|
|
130
|
+
refreshToken: accessToken.refreshToken ?? null,
|
|
131
|
+
expiresAt: accessToken.expiresAt?.toString() ?? null
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
static toHostConfigDto(hostConfig) {
|
|
135
|
+
return {
|
|
136
|
+
host: hostConfig.host,
|
|
137
|
+
auth: {
|
|
138
|
+
accessToken: hostConfig.auth?.accessToken ? GlobalConfig.toAccessTokenDto(hostConfig.auth.accessToken) : undefined,
|
|
139
|
+
self: hostConfig.auth?.self
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
static toHostConfig(hostConfigDto) {
|
|
144
|
+
return {
|
|
145
|
+
host: hostConfigDto.host,
|
|
146
|
+
auth: {
|
|
147
|
+
accessToken: hostConfigDto.auth?.accessToken ? GlobalConfig.toAccessToken(hostConfigDto.auth.accessToken) : undefined,
|
|
148
|
+
self: hostConfigDto.auth?.self
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// pkgs/@akanjs/devkit/cloud/cloudApi.ts
|
|
155
|
+
class HttpClient {
|
|
156
|
+
baseUrl;
|
|
157
|
+
headers = {};
|
|
158
|
+
constructor(baseUrl, headers = {}) {
|
|
159
|
+
this.baseUrl = baseUrl;
|
|
160
|
+
this.headers = headers;
|
|
161
|
+
}
|
|
162
|
+
async get(url, { headers, signal } = {}) {
|
|
163
|
+
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
164
|
+
headers: { "Content-Type": "application/json", ...this.headers, ...headers },
|
|
165
|
+
...signal ? { signal } : {}
|
|
166
|
+
});
|
|
167
|
+
return await HttpClient.#body(response, url);
|
|
168
|
+
}
|
|
169
|
+
async getFile(url, localPath, headers) {
|
|
170
|
+
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
171
|
+
headers: { ...this.headers, ...headers }
|
|
172
|
+
});
|
|
173
|
+
if (!response.ok)
|
|
174
|
+
throw new Error(`Failed to download file: ${response.status} ${response.statusText}`);
|
|
175
|
+
await Bun.write(localPath, response);
|
|
176
|
+
}
|
|
177
|
+
async post(url, data, { headers, signal } = {}) {
|
|
178
|
+
const isFormData = data instanceof FormData;
|
|
179
|
+
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
180
|
+
method: "POST",
|
|
181
|
+
body: isFormData ? data : JSON.stringify(data),
|
|
182
|
+
headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers },
|
|
183
|
+
...signal ? { signal } : {}
|
|
184
|
+
});
|
|
185
|
+
return await HttpClient.#body(response, url);
|
|
186
|
+
}
|
|
187
|
+
static async#body(response, url) {
|
|
188
|
+
const text = await response.text();
|
|
189
|
+
if (!response.ok)
|
|
190
|
+
throw new Error(`${response.status} ${response.statusText} from ${url}: ${text.slice(0, 200)}`);
|
|
191
|
+
return JSON.parse(text);
|
|
192
|
+
}
|
|
193
|
+
setHeaders(headers) {
|
|
194
|
+
Object.assign(this.headers, headers);
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
class CloudApi {
|
|
200
|
+
#api;
|
|
201
|
+
#accessToken = null;
|
|
202
|
+
#workspace;
|
|
203
|
+
host;
|
|
204
|
+
url;
|
|
205
|
+
static async fromHost(workspace, host) {
|
|
206
|
+
const hostConfig = await GlobalConfig.getHostConfig(host);
|
|
207
|
+
const accessToken = hostConfig.auth?.accessToken;
|
|
208
|
+
if (!accessToken || !GlobalConfig.needRefreshToken(accessToken))
|
|
209
|
+
return new CloudApi(workspace, hostConfig);
|
|
210
|
+
const tokenless = new CloudApi(workspace, hostConfig);
|
|
211
|
+
const refreshed = await GlobalConfig.refreshHostAuth(hostConfig.host, (refreshToken) => tokenless.refreshAuthToken(refreshToken));
|
|
212
|
+
return new CloudApi(workspace, refreshed);
|
|
213
|
+
}
|
|
214
|
+
constructor(workspace, hostConfig) {
|
|
215
|
+
this.#workspace = workspace;
|
|
216
|
+
this.#accessToken = hostConfig.auth?.accessToken ?? null;
|
|
217
|
+
this.host = hostConfig.host;
|
|
218
|
+
this.url = `${this.host}/api`;
|
|
219
|
+
this.#api = new HttpClient(this.url);
|
|
220
|
+
if (this.#accessToken && !GlobalConfig.needRefreshToken(this.#accessToken))
|
|
221
|
+
this.#api.setHeaders({ Authorization: `Bearer ${this.#accessToken.jwt}` });
|
|
222
|
+
}
|
|
223
|
+
#authorize(accessTokenDto) {
|
|
224
|
+
this.#accessToken = GlobalConfig.toAccessToken(accessTokenDto);
|
|
225
|
+
this.#api.setHeaders({ Authorization: `Bearer ${this.#accessToken.jwt}` });
|
|
226
|
+
return this.#accessToken;
|
|
227
|
+
}
|
|
228
|
+
async uploadEnv(devProjectId, file) {
|
|
229
|
+
const formData = new FormData;
|
|
230
|
+
formData.append("devProjectId", devProjectId);
|
|
231
|
+
formData.append("file", file);
|
|
232
|
+
return await this.#api.post(`/uploadEnv/${devProjectId}`, formData);
|
|
233
|
+
}
|
|
234
|
+
async downloadEnv(devProjectId) {
|
|
235
|
+
const localPath = `${this.#workspace.workspaceRoot}/local/env.tar`;
|
|
236
|
+
await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
|
|
237
|
+
return localPath;
|
|
238
|
+
}
|
|
239
|
+
async getRemoteAuthToken(remoteId) {
|
|
240
|
+
try {
|
|
241
|
+
return this.#authorize(await this.#api.get(`/getRemoteAuthToken/${remoteId}`));
|
|
242
|
+
} catch (_) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async refreshAuthToken(refreshToken) {
|
|
247
|
+
return this.#authorize(await this.#api.post(`/refreshAuthToken`, { refreshToken }, { signal: AbortSignal.timeout(20000) }));
|
|
248
|
+
}
|
|
249
|
+
async requestTunnel(input) {
|
|
250
|
+
return await this.#api.post(`/tunnel/requestTunnel`, input);
|
|
251
|
+
}
|
|
252
|
+
async tunnelListInSelf() {
|
|
253
|
+
return await this.#api.get(`/tunnel/tunnelListInSelf`);
|
|
254
|
+
}
|
|
255
|
+
async revokeTunnel(code) {
|
|
256
|
+
return await this.#api.post(`/tunnel/revokeTunnel`, { code }, { signal: AbortSignal.timeout(5000) });
|
|
257
|
+
}
|
|
258
|
+
async getRemoteSelf() {
|
|
259
|
+
try {
|
|
260
|
+
return await this.#api.get(`/getRemoteSelf`);
|
|
261
|
+
} catch {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
export { getDefaultHostConfig, GlobalConfig, CloudApi };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// pkgs/@akanjs/cli/openBrowser.ts
|
|
3
|
+
import { spawn } from "child_process";
|
|
4
|
+
function openBrowser(url) {
|
|
5
|
+
const command = process.platform === "darwin" ? ["open", url] : process.platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
|
|
6
|
+
const child = spawn(command[0], command.slice(1), { detached: true, stdio: "ignore" });
|
|
7
|
+
child.on("error", () => {});
|
|
8
|
+
child.unref();
|
|
9
|
+
return Promise.resolve();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { openBrowser };
|
|
@@ -4,27 +4,29 @@ import {
|
|
|
4
4
|
readDevkitVersion,
|
|
5
5
|
rootAllowedFiles,
|
|
6
6
|
rootAllowedDirs,
|
|
7
|
+
rootEntryHintOf,
|
|
7
8
|
isScannedRootEntry,
|
|
8
9
|
AppExecutor,
|
|
9
10
|
LibExecutor
|
|
10
|
-
} from "./index-
|
|
11
|
+
} from "./index-3w94e7n3.js";
|
|
11
12
|
import {
|
|
12
|
-
|
|
13
|
-
} from "./index-
|
|
13
|
+
FileSys2
|
|
14
|
+
} from "./index-52w0fvh8.js";
|
|
14
15
|
import {
|
|
15
16
|
collectRecipeSources2,
|
|
16
17
|
scanRecipes2,
|
|
17
18
|
findInlineRecipeDuplicates2
|
|
18
|
-
} from "./index-
|
|
19
|
+
} from "./index-hj6w4ka1.js";
|
|
19
20
|
import {
|
|
21
|
+
workflowPathsForPlan,
|
|
20
22
|
workflowRunArtifactPath,
|
|
21
23
|
workflowSyncDir
|
|
22
|
-
} from "./index-
|
|
24
|
+
} from "./index-y3mphr1m.js";
|
|
23
25
|
|
|
24
26
|
// pkgs/@akanjs/devkit/akanContext.ts
|
|
25
27
|
import { readdir } from "fs/promises";
|
|
26
28
|
import path from "path";
|
|
27
|
-
import { capitalize } from "akanjs/common";
|
|
29
|
+
import { capitalize, isRecord } from "akanjs/common";
|
|
28
30
|
var guidelineResourceUri = (name) => `akan://guidelines/${name}`;
|
|
29
31
|
var staticResourceList = [
|
|
30
32
|
{ uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
|
|
@@ -52,16 +54,13 @@ var akanMcpInstallConfigPaths = {
|
|
|
52
54
|
var cursorWorkspaceFolder = "$" + "{workspaceFolder}";
|
|
53
55
|
var claudeProjectDir = "$CLAUDE_PROJECT_DIR";
|
|
54
56
|
var akanMcpCommand = (mode, { cd } = {}) => cd ? `cd "${cd}" && akan mcp --mode ${mode}` : `akan mcp --mode ${mode}`;
|
|
55
|
-
var
|
|
57
|
+
var bashMcpServer = (mode, cd) => ({
|
|
56
58
|
type: "stdio",
|
|
57
59
|
command: "bash",
|
|
58
|
-
args: ["-lc", akanMcpCommand(mode, { cd
|
|
59
|
-
});
|
|
60
|
-
var createAkanClaudeMcpServer = (mode = "readonly") => ({
|
|
61
|
-
type: "stdio",
|
|
62
|
-
command: "bash",
|
|
63
|
-
args: ["-lc", akanMcpCommand(mode, { cd: claudeProjectDir })]
|
|
60
|
+
args: ["-lc", akanMcpCommand(mode, { cd })]
|
|
64
61
|
});
|
|
62
|
+
var createAkanCursorMcpServer = (mode = "readonly") => bashMcpServer(mode, cursorWorkspaceFolder);
|
|
63
|
+
var createAkanClaudeMcpServer = (mode = "readonly") => bashMcpServer(mode, claudeProjectDir);
|
|
65
64
|
var createAkanMcpServer = (target, mode = "readonly") => target === "cursor" ? createAkanCursorMcpServer(mode) : createAkanClaudeMcpServer(mode);
|
|
66
65
|
var akanCursorMcpServer = createAkanCursorMcpServer();
|
|
67
66
|
var codexMcpServerTableHeader = "[mcp_servers.akan]";
|
|
@@ -164,41 +163,13 @@ var moduleShapeFiles = (module) => {
|
|
|
164
163
|
];
|
|
165
164
|
};
|
|
166
165
|
var constantFieldNames = (content) => [...content.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*field\(/g)].map((match) => match[1]).filter(Boolean);
|
|
167
|
-
var safeReadDir = async (dirPath) => {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
};
|
|
174
|
-
var safeReadText = async (filePath) => {
|
|
175
|
-
try {
|
|
176
|
-
return await FileSys.readText(filePath);
|
|
177
|
-
} catch {
|
|
178
|
-
return null;
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
var safeReadJson = async (filePath) => {
|
|
182
|
-
try {
|
|
183
|
-
return await FileSys.readJson(filePath);
|
|
184
|
-
} catch {
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
var isWorkflowPlan = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1 && ("mode" in value) && value.mode === "plan";
|
|
189
|
-
var isWorkflowApplyReport = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1 && ("mode" in value) && (value.mode === "apply" || value.mode === "dry-run");
|
|
166
|
+
var safeReadDir = async (dirPath) => (await readdir(dirPath, { withFileTypes: true }).catch(() => [])).sort((a, b) => a.name.localeCompare(b.name));
|
|
167
|
+
var safeReadText = (filePath) => FileSys2.readText(filePath).catch(() => null);
|
|
168
|
+
var safeReadJson = (filePath) => FileSys2.readJson(filePath).catch(() => null);
|
|
169
|
+
var isWorkflowPlan = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1 && ("mode" in value) && value.mode === "plan" && ("inputs" in value) && isRecord(value.inputs) && ("predictedChanges" in value) && Array.isArray(value.predictedChanges) && value.predictedChanges.every((change) => isRecord(change) && typeof change.target === "string");
|
|
170
|
+
var isPathList = (value) => Array.isArray(value) && value.every((file) => isRecord(file) && typeof file.path === "string");
|
|
171
|
+
var isWorkflowApplyReport = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1 && ("mode" in value) && (value.mode === "apply" || value.mode === "dry-run") && ("changedFiles" in value) && isPathList(value.changedFiles) && ("generatedFiles" in value) && isPathList(value.generatedFiles) && ("plan" in value) && isWorkflowPlan(value.plan);
|
|
190
172
|
var isWorkflowRunArtifact = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1;
|
|
191
|
-
var planInputString = (plan, key) => {
|
|
192
|
-
const value = plan.inputs[key];
|
|
193
|
-
return typeof value === "string" ? value : "";
|
|
194
|
-
};
|
|
195
|
-
var expandWorkflowTarget = (target, plan) => {
|
|
196
|
-
const app = planInputString(plan, "app");
|
|
197
|
-
const module = planInputString(plan, "module");
|
|
198
|
-
const moduleClass = module ? capitalize(module) : "<Module>";
|
|
199
|
-
return target.replace(/^\*\//, app ? `apps/${app}/` : "").replaceAll("<module>", module || "<module>").replaceAll("<Module>", moduleClass);
|
|
200
|
-
};
|
|
201
|
-
var workflowPathsForPlan = (plan) => plan.predictedChanges.map((change) => expandWorkflowTarget(change.target, plan));
|
|
202
173
|
var workflowPathsForArtifact = (artifact) => {
|
|
203
174
|
if (isWorkflowPlan(artifact))
|
|
204
175
|
return workflowPathsForPlan(artifact);
|
|
@@ -209,7 +180,7 @@ var workflowPathsForArtifact = (artifact) => {
|
|
|
209
180
|
...workflowPathsForPlan(artifact.plan)
|
|
210
181
|
];
|
|
211
182
|
}
|
|
212
|
-
if ("mode" in artifact && artifact.mode === "validate" && artifact.plan)
|
|
183
|
+
if ("mode" in artifact && artifact.mode === "validate" && isWorkflowPlan(artifact.plan))
|
|
213
184
|
return workflowPathsForPlan(artifact.plan);
|
|
214
185
|
return [];
|
|
215
186
|
};
|
|
@@ -310,13 +281,13 @@ var getSysModules = async (workspace, sys, {
|
|
|
310
281
|
const serviceName = entry.name.replace(/^_+/, "");
|
|
311
282
|
if (moduleFilter && moduleFilter !== serviceName && moduleFilter !== entry.name)
|
|
312
283
|
continue;
|
|
313
|
-
if (!await
|
|
284
|
+
if (!await FileSys2.fileExists(path.join(libPath, entry.name, `${serviceName}.service.ts`)))
|
|
314
285
|
continue;
|
|
315
286
|
modules.push(await createModuleContext(workspace, sys, "service", entry.name, serviceName, includeAbstractContent));
|
|
316
287
|
} else {
|
|
317
288
|
if (moduleFilter && moduleFilter !== entry.name)
|
|
318
289
|
continue;
|
|
319
|
-
if (!await
|
|
290
|
+
if (!await FileSys2.fileExists(path.join(libPath, entry.name, `${entry.name}.constant.ts`)))
|
|
320
291
|
continue;
|
|
321
292
|
modules.push(await createModuleContext(workspace, sys, "domain", entry.name, entry.name, includeAbstractContent));
|
|
322
293
|
}
|
|
@@ -327,7 +298,7 @@ var getSysModules = async (workspace, sys, {
|
|
|
327
298
|
continue;
|
|
328
299
|
if (moduleFilter && moduleFilter !== entry.name)
|
|
329
300
|
continue;
|
|
330
|
-
if (!await
|
|
301
|
+
if (!await FileSys2.fileExists(path.join(scalarRoot, entry.name, `${entry.name}.constant.ts`)))
|
|
331
302
|
continue;
|
|
332
303
|
modules.push(await createModuleContext(workspace, sys, "scalar", entry.name, entry.name, includeAbstractContent));
|
|
333
304
|
}
|
|
@@ -339,7 +310,7 @@ var getSysContext = async (workspace, type, name, options) => {
|
|
|
339
310
|
type,
|
|
340
311
|
name,
|
|
341
312
|
path: `${type}s/${name}`,
|
|
342
|
-
hasConfig: await
|
|
313
|
+
hasConfig: await FileSys2.fileExists(path.join(sys.cwdPath, "akan.config.ts")),
|
|
343
314
|
modules: await getSysModules(workspace, sys, {
|
|
344
315
|
includeAbstractContent: options.includeAbstractContent,
|
|
345
316
|
module: options.module
|
|
@@ -411,62 +382,47 @@ class AkanContextAnalyzer {
|
|
|
411
382
|
repairAction("generated", "akan repair generated --app <app-or-lib>", "Refresh generated Akan files.", true),
|
|
412
383
|
repairAction("format", "akan repair format --target <app-or-lib-or-pkg>", "Run the formatter/linter repair path.", true)
|
|
413
384
|
];
|
|
385
|
+
const report = (diagnostic, action) => {
|
|
386
|
+
diagnostics.push({ ...diagnostic, repairActions: [action] });
|
|
387
|
+
repairActions.push(action);
|
|
388
|
+
};
|
|
414
389
|
for (const sys of [...context.apps, ...context.libs]) {
|
|
415
390
|
const sysPath = path.join(workspace.workspaceRoot, sys.path);
|
|
416
391
|
for (const entry of await safeReadDir(sysPath)) {
|
|
417
392
|
if (!isScannedRootEntry(sys.type, entry.name))
|
|
418
393
|
continue;
|
|
419
394
|
const allowed = entry.isDirectory() ? rootAllowedDirs[sys.type].has(entry.name) : rootAllowedFiles[sys.type].has(entry.name);
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
395
|
+
const rootEntryHint = rootEntryHintOf(sys.type, entry.name);
|
|
396
|
+
if (!allowed)
|
|
397
|
+
report({
|
|
423
398
|
severity: "error",
|
|
424
399
|
code: `${sys.type}-root-unknown-entry`,
|
|
425
400
|
path: `${sys.path}/${entry.name}`,
|
|
426
|
-
message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in ${sys.type} root: ${sys.path}/${entry.name}
|
|
427
|
-
|
|
428
|
-
});
|
|
429
|
-
repairActions.push(action);
|
|
430
|
-
}
|
|
401
|
+
message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in ${sys.type} root: ${sys.path}/${entry.name}${rootEntryHint ? ` (${rootEntryHint})` : ""}`
|
|
402
|
+
}, repairAction("module-shape", `akan repair module-shape --app ${sys.name}`, `Review ${sys.type} root shape and remove or move the unknown entry.`, false));
|
|
431
403
|
}
|
|
432
404
|
}
|
|
433
405
|
const agentDrift = await AkanContextAnalyzer.#agentGuideDrift(workspace);
|
|
434
|
-
if (agentDrift)
|
|
435
|
-
|
|
436
|
-
diagnostics.push({
|
|
437
|
-
severity: "warning",
|
|
438
|
-
code: agentDrift.code,
|
|
439
|
-
path: "AGENTS.md",
|
|
440
|
-
message: agentDrift.message,
|
|
441
|
-
repairActions: [action]
|
|
442
|
-
});
|
|
443
|
-
repairActions.push(action);
|
|
444
|
-
}
|
|
406
|
+
if (agentDrift)
|
|
407
|
+
report({ severity: "warning", code: agentDrift.code, path: "AGENTS.md", message: agentDrift.message }, repairAction("generated", "akan agent install agents-md", agentDrift.hint, true));
|
|
445
408
|
for (const sys of [...context.apps, ...context.libs]) {
|
|
446
409
|
for (const module of sys.modules) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
410
|
+
const moduleShapeCommand = `akan repair module-shape --app ${sys.name} --module ${module.name}`;
|
|
411
|
+
if (!module.abstract.exists)
|
|
412
|
+
report({
|
|
450
413
|
severity: strict ? "error" : "warning",
|
|
451
414
|
code: "module-abstract-missing",
|
|
452
415
|
path: module.abstract.path,
|
|
453
|
-
message: `${capitalize(module.kind)} module ${sys.name}:${module.name} should include ${module.abstract.path}
|
|
454
|
-
|
|
455
|
-
});
|
|
456
|
-
repairActions.push(action);
|
|
457
|
-
}
|
|
416
|
+
message: `${capitalize(module.kind)} module ${sys.name}:${module.name} should include ${module.abstract.path}`
|
|
417
|
+
}, repairAction("module-shape", moduleShapeCommand, "Create the missing module abstract or inspect required source files.", false));
|
|
458
418
|
const missingFiles = moduleShapeFiles(module).filter((filename) => !module.files.includes(filename));
|
|
459
|
-
if (missingFiles.length)
|
|
460
|
-
|
|
461
|
-
diagnostics.push({
|
|
419
|
+
if (missingFiles.length)
|
|
420
|
+
report({
|
|
462
421
|
severity: "error",
|
|
463
422
|
code: "module-shape-invalid",
|
|
464
423
|
path: module.path,
|
|
465
|
-
message: `${capitalize(module.kind)} module ${sys.name}:${module.name} is missing required files: ${missingFiles.join(", ")}
|
|
466
|
-
|
|
467
|
-
});
|
|
468
|
-
repairActions.push(action);
|
|
469
|
-
}
|
|
424
|
+
message: `${capitalize(module.kind)} module ${sys.name}:${module.name} is missing required files: ${missingFiles.join(", ")}`
|
|
425
|
+
}, repairAction("module-shape", moduleShapeCommand, "Review missing required module source files.", false));
|
|
470
426
|
if (module.kind !== "service" && module.files.includes(`${module.name}.dictionary.ts`)) {
|
|
471
427
|
const constantPath = path.join(workspace.workspaceRoot, module.path, `${module.name}.constant.ts`);
|
|
472
428
|
const dictionaryPath = path.join(workspace.workspaceRoot, module.path, `${module.name}.dictionary.ts`);
|
|
@@ -478,15 +434,12 @@ class AkanContextAnalyzer {
|
|
|
478
434
|
for (const fieldName of constantFieldNames(constantContent)) {
|
|
479
435
|
if (new RegExp(`\\b${fieldName}\\s*:`).test(dictionaryContent))
|
|
480
436
|
continue;
|
|
481
|
-
|
|
482
|
-
diagnostics.push({
|
|
437
|
+
report({
|
|
483
438
|
severity: "warning",
|
|
484
439
|
code: "dictionary-label-missing",
|
|
485
440
|
path: `${module.path}/${module.name}.dictionary.ts`,
|
|
486
|
-
message: `Dictionary labels for ${sys.name}:${module.name}.${fieldName} were not found
|
|
487
|
-
|
|
488
|
-
});
|
|
489
|
-
repairActions.push(action);
|
|
441
|
+
message: `Dictionary labels for ${sys.name}:${module.name}.${fieldName} were not found.`
|
|
442
|
+
}, repairAction("dictionary", `akan repair dictionary --app ${sys.name} --module ${module.name}`, "Add missing dictionary labels for source constant fields.", false));
|
|
490
443
|
}
|
|
491
444
|
}
|
|
492
445
|
}
|
|
@@ -554,19 +507,16 @@ class AkanContextAnalyzer {
|
|
|
554
507
|
const pushIndexDiagnostic = (indexPath, missing, stale, repairCommand) => {
|
|
555
508
|
if (missing.length === 0 && stale.length === 0)
|
|
556
509
|
return;
|
|
557
|
-
const action = repairAction("generated", repairCommand, "Regenerate the recipe index from the scanned recipes.", true);
|
|
558
510
|
const parts = [
|
|
559
511
|
missing.length > 0 ? `${missing.length} declared but unlisted (${missing.slice(0, 5).join(", ")})` : "",
|
|
560
512
|
stale.length > 0 ? `${stale.length} listed but gone (${stale.slice(0, 5).join(", ")})` : ""
|
|
561
513
|
].filter(Boolean);
|
|
562
|
-
|
|
514
|
+
report({
|
|
563
515
|
severity: "error",
|
|
564
516
|
code: "recipe-index-stale",
|
|
565
517
|
path: indexPath,
|
|
566
|
-
message: `${indexPath} recipe index is out of date \u2014 ${parts.join("; ")}. Agents read this list as authoritative
|
|
567
|
-
|
|
568
|
-
});
|
|
569
|
-
repairActions.push(action);
|
|
518
|
+
message: `${indexPath} recipe index is out of date \u2014 ${parts.join("; ")}. Agents read this list as authoritative.`
|
|
519
|
+
}, repairAction("generated", repairCommand, "Regenerate the recipe index from the scanned recipes.", true));
|
|
570
520
|
};
|
|
571
521
|
const frameworkDeclared = declaredByImport.get("akanjs/ui") ?? new Set;
|
|
572
522
|
if (frameworkDeclared.size > 0) {
|