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