@akanjs/cli 3.0.0-alpha.11 → 3.0.0-alpha.111
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-mjh5ppsq.js} +3 -5
- package/{agent.command-a3n15c6t.js → agent.command-d2gfxfck.js} +11 -13
- package/{application.command-rdm3et0g.js → application.command-pj2m7584.js} +65 -38
- package/{applicationBuildRunner-6m8n71w4.js → applicationBuildRunner-kxwbssgn.js} +27 -23
- package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-4yasxwv9.js} +8 -9
- package/buildBatch.proc.js +12 -14
- package/capacitorApp-36rbr858.js +12 -0
- package/{cloud.command-56aeekqn.js → cloud.command-gxqp8xdv.js} +15 -18
- package/commandManifest.json +1 -1
- package/{context.command-ysxawe7h.js → context.command-ez8a0zyz.js} +19 -23
- package/dependencyScanner-shs82ynp.js +8 -0
- package/devTui-40ggmd99.js +553 -0
- package/devTuiView-c08ccbat.js +9 -0
- package/getDirname-dr3jz1xg.js +7 -0
- package/{guideline.command-yqf9a372.js → guideline.command-xmqwx8zm.js} +24 -22
- package/guidelines/agentRule/agentRule.generate.json +31 -0
- package/guidelines/agentRule/agentRule.instruction.md +531 -0
- package/guidelines/conventions/conventions.instruction.md +493 -369
- package/guidelines/framework/framework.generate.json +3 -2
- package/guidelines/framework/framework.instruction.md +0 -9
- package/guidelines/mcpRule/mcpRule.generate.json +35 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +460 -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 +178 -0
- package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
- package/guidelines/runtimeRule/runtimeRule.instruction.md +220 -0
- package/guidelines/ssrRule/ssrRule.instruction.md +51 -5
- package/guidelines/transportRule/transportRule.generate.json +31 -0
- package/guidelines/transportRule/transportRule.instruction.md +60 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +54 -764
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +467 -0
- package/incrementalBuilder.proc.js +26 -25
- package/{index-8pd02prk.js → index-259dsnz3.js} +58 -25
- package/{index-yzsxc30b.js → index-2tv3fdx4.js} +975 -234
- package/index-3d9y066c.js +76 -0
- package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
- package/{index-m90fn8xe.js → index-4edzf1gr.js} +32 -32
- package/{index-3789fdpg.js → index-600zhnve.js} +94 -61
- package/{index-1577bej2.js → index-6wwzs1bc.js} +2 -2
- package/{index-cv9cxs5k.js → index-7737gxcp.js} +18 -18
- package/{index-a5cs7d8r.js → index-8few9nyh.js} +13 -13
- package/{index-mewacxye.js → index-8pm30m73.js} +57 -57
- package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
- package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
- package/{index-cav1azma.js → index-a64esmtb.js} +1106 -1369
- package/{index-nwqqssnb.js → index-aj7tyh5w.js} +26 -23
- package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
- package/{index-yzmqvg23.js → index-fz5q3gd7.js} +8 -8
- package/{index-kcsa1zff.js → index-gyd220p2.js} +4 -4
- package/{index-j37qq1f2.js → index-h7yw2z9n.js} +7 -7
- package/{index-bjpxzr6s.js → index-hwkygn9s.js} +51 -3
- package/index-j9yhg404.js +159 -0
- package/{index-46tjzh6s.js → index-kcxmv48c.js} +29 -29
- package/{index-0cj2zxbm.js → index-kn1h7p1x.js} +12 -11
- package/{index-e4b2ae6b.js → index-ktb5njgy.js} +41 -34
- package/{index-etwh7sd3.js → index-mak3cd28.js} +100 -32
- package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
- package/{index-z1s5f4e0.js → index-ne2qy0nk.js} +36 -37
- package/{index-65aeh789.js → index-pnqbkf5p.js} +1 -1
- package/{index-67546d0j.js → index-q0y2jq9j.js} +14 -2
- package/{index-4mgkgba3.js → index-rwg2aa4f.js} +14 -14
- package/{index-bzznxgcx.js → index-v0qh106m.js} +1002 -128
- package/{index-j9cxndc0.js → index-w8kmx1b6.js} +20 -11
- package/{index-h5whaj26.js → index-ws5e0j51.js} +16 -12
- package/{index-9va8zayb.js → index-wt7qrtd4.js} +27 -27
- package/index.js +22 -25
- package/{library.command-x6t29a30.js → library.command-nbsky672.js} +11 -10
- package/{localRegistry.command-649g1n7b.js → localRegistry.command-ts6t5e5a.js} +20 -23
- package/{module.command-8w8ys5t3.js → module.command-29vqzrh8.js} +13 -16
- package/{package.command-zgy7f3fz.js → package.command-axv0abmn.js} +8 -10
- package/package.json +5 -7
- package/{page.command-yjmnkyk2.js → page.command-vs9s3zrh.js} +7 -9
- package/{primitive.command-gfqaagsg.js → primitive.command-cbxmqbtc.js} +13 -16
- package/{quality.command-ec8r1dn3.js → quality.command-gmbs7nws.js} +184 -334
- package/recipeScanner-fpagtgc1.js +11 -0
- package/{repair.command-p9ey6mkm.js → repair.command-bqsjptsj.js} +12 -14
- package/{routeSourceValidator-e4jmbfcx.js → routeSourceValidator-apyqw7wk.js} +90 -19
- package/{scalar.command-9dhmqhtm.js → scalar.command-6k1vhe9s.js} +11 -14
- package/subspace.command-35a3t6vv.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/app/page/_index.tsx +3 -3
- package/templates/app/page/_layout.tsx +31 -32
- package/templates/appSample/lib/task/task.signal.ts +11 -6
- package/templates/appSample/page/task/[taskId]/_index.tsx +22 -27
- package/templates/appSample/page/task/[taskId]/edit.tsx +25 -30
- package/templates/appSample/page/task/_index.tsx +3 -7
- package/templates/appSample/page/task/_layout.tsx +4 -15
- package/templates/appSample/page/task/new.tsx +4 -10
- package/templates/appSample/srvkit/AuthGuard.ts +2 -2
- package/templates/crudPages/[__model__Id]/edit/page.tsx +27 -29
- package/templates/crudPages/[__model__Id]/page.tsx +24 -32
- package/templates/crudPages/new/page.tsx +26 -25
- package/templates/crudPages/page.tsx +27 -26
- package/templates/crudSinglePage/page.tsx +26 -21
- 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 +1 -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-ycwc6zr6.js → workflow.command-nwpcdc8p.js} +22 -25
- package/{workspace.command-xhyhajxa.js → workspace.command-aczjxzbf.js} +64 -66
- package/capacitorApp-mr81qdxq.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
|
@@ -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-2tv3fdx4.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
|
|
@@ -1,38 +1,45 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
workflowRunArtifactPath,
|
|
4
|
-
workflowSyncDir
|
|
5
|
-
} from "./index-kcsa1zff.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-2tv3fdx4.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-gyd220p2.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,21 +1,18 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
FileSys
|
|
4
|
+
} from "./index-q0y2jq9j.js";
|
|
5
|
+
import {
|
|
4
6
|
Executor,
|
|
7
|
+
WorkspaceExecutor,
|
|
8
|
+
AppExecutor,
|
|
5
9
|
LibExecutor,
|
|
6
|
-
ModuleExecutor,
|
|
7
10
|
PkgExecutor,
|
|
8
|
-
|
|
9
|
-
} from "./index-
|
|
10
|
-
import {
|
|
11
|
-
getDirname
|
|
12
|
-
} from "./index-1577bej2.js";
|
|
13
|
-
import {
|
|
14
|
-
FileSys
|
|
15
|
-
} from "./index-67546d0j.js";
|
|
11
|
+
ModuleExecutor
|
|
12
|
+
} from "./index-2tv3fdx4.js";
|
|
16
13
|
import {
|
|
17
|
-
|
|
18
|
-
} from "./index-
|
|
14
|
+
getDirname2
|
|
15
|
+
} from "./index-6wwzs1bc.js";
|
|
19
16
|
|
|
20
17
|
// pkgs/@akanjs/devkit/commandDecorators/targetMeta.ts
|
|
21
18
|
var COMMAND_META = Symbol("akan.command.meta");
|
|
@@ -54,6 +51,7 @@ var normalizePrimitiveArgType = (type) => {
|
|
|
54
51
|
throw new Error(`Invalid primitive argument type: ${type}`);
|
|
55
52
|
};
|
|
56
53
|
var App = createInternalArgToken("App");
|
|
54
|
+
var Apps = createInternalArgToken("Apps");
|
|
57
55
|
var Lib = createInternalArgToken("Lib");
|
|
58
56
|
var Sys = createInternalArgToken("Sys");
|
|
59
57
|
var Exec = createInternalArgToken("Exec");
|
|
@@ -62,11 +60,29 @@ var Module = createInternalArgToken("Module");
|
|
|
62
60
|
var Workspace = createInternalArgToken("Workspace");
|
|
63
61
|
|
|
64
62
|
// pkgs/@akanjs/devkit/commandDecorators/command.ts
|
|
65
|
-
import
|
|
63
|
+
import path2 from "path";
|
|
66
64
|
import { Logger } from "akanjs/common";
|
|
67
65
|
import chalk2 from "chalk";
|
|
68
66
|
import { program } from "commander";
|
|
69
67
|
|
|
68
|
+
// pkgs/@akanjs/devkit/appSelectionMemory.ts
|
|
69
|
+
import path from "path";
|
|
70
|
+
class AppSelectionMemory {
|
|
71
|
+
static pathIn(workspaceRoot) {
|
|
72
|
+
return path.join(workspaceRoot, "local", ".akan", "lastStart.json");
|
|
73
|
+
}
|
|
74
|
+
static async read(workspaceRoot) {
|
|
75
|
+
const stored = await Bun.file(AppSelectionMemory.pathIn(workspaceRoot)).json().catch(() => null);
|
|
76
|
+
const apps = stored?.apps;
|
|
77
|
+
return Array.isArray(apps) ? apps.filter((name) => typeof name === "string") : [];
|
|
78
|
+
}
|
|
79
|
+
static async write(workspaceRoot, apps) {
|
|
80
|
+
await FileSys.writeJson(AppSelectionMemory.pathIn(workspaceRoot), { apps }).catch(() => {
|
|
81
|
+
return;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
70
86
|
// pkgs/@akanjs/devkit/commandDecorators/dependencyBuilder.ts
|
|
71
87
|
var capitalize = (value) => value.slice(0, 1).toUpperCase() + value.slice(1);
|
|
72
88
|
var createDependencyKey = (refName, kind) => `${refName}${capitalize(kind)}`;
|
|
@@ -264,6 +280,8 @@ var formatCommandHelp = (command, key) => {
|
|
|
264
280
|
return "";
|
|
265
281
|
if (arg.type === "Module")
|
|
266
282
|
return "[sys:module]";
|
|
283
|
+
if (arg.type === "Apps")
|
|
284
|
+
return "[apps...]";
|
|
267
285
|
if (arg.type === "Argument") {
|
|
268
286
|
return `[${camelToKebabCase2(arg.name)}]`;
|
|
269
287
|
}
|
|
@@ -290,6 +308,9 @@ var formatCommandHelp = (command, key) => {
|
|
|
290
308
|
} else if (arg.type === "Module") {
|
|
291
309
|
argName = "sys:module";
|
|
292
310
|
argDesc = "Module in format: app-name:module-name or lib-name:module-name";
|
|
311
|
+
} else if (arg.type === "Apps") {
|
|
312
|
+
argName = "apps...";
|
|
313
|
+
argDesc = "App names, space- or comma-separated, or all. Omit to pick them interactively";
|
|
293
314
|
} else {
|
|
294
315
|
argName = arg.type.toLowerCase();
|
|
295
316
|
argDesc = `${arg.type} name in this workspace`;
|
|
@@ -383,6 +404,17 @@ var prompts = async () => await import("@inquirer/prompts");
|
|
|
383
404
|
var select = (config, context) => prompts().then((m) => m.select(config, context));
|
|
384
405
|
var confirm = (config, context) => prompts().then((m) => m.confirm(config, context));
|
|
385
406
|
var input = (config, context) => prompts().then((m) => m.input(config, context));
|
|
407
|
+
var checkbox = (config, context) => prompts().then((m) => m.checkbox(config, context));
|
|
408
|
+
var assertEnumChoice = (argMeta, value) => {
|
|
409
|
+
const enumChoices = argMeta.argsOption.enum;
|
|
410
|
+
if (!enumChoices || typeof enumChoices === "function")
|
|
411
|
+
return;
|
|
412
|
+
const choices = normalizeEnumChoices(enumChoices);
|
|
413
|
+
if (choices.some((choice) => String(choice.value) === String(value)))
|
|
414
|
+
return;
|
|
415
|
+
const label = argMeta.type === "Option" ? `option '--${camelToKebabCase3(argMeta.name)}'` : `argument '${argMeta.name}'`;
|
|
416
|
+
throw new Error(`${label} argument '${String(value)}' is invalid. Allowed choices are ${choices.map((choice) => choice.name).join(", ")}.`);
|
|
417
|
+
};
|
|
386
418
|
var resolveEnumChoices = async (argMeta, context) => {
|
|
387
419
|
const enumChoices = argMeta.argsOption.enum;
|
|
388
420
|
if (!enumChoices)
|
|
@@ -396,9 +428,10 @@ var getOptionValue = async (argMeta, opt, context) => {
|
|
|
396
428
|
name,
|
|
397
429
|
argsOption: { enum: enumChoices, default: defaultValue, type, desc, nullable, example, ask }
|
|
398
430
|
} = argMeta;
|
|
399
|
-
if (opt[argMeta.name] !== undefined)
|
|
431
|
+
if (opt[argMeta.name] !== undefined) {
|
|
432
|
+
assertEnumChoice(argMeta, opt[argMeta.name]);
|
|
400
433
|
return convertArgValue(opt[argMeta.name], type ?? "string");
|
|
401
|
-
else if (defaultValue !== undefined)
|
|
434
|
+
} else if (defaultValue !== undefined)
|
|
402
435
|
return defaultValue;
|
|
403
436
|
if (enumChoices) {
|
|
404
437
|
const choices = normalizeEnumChoices(await resolveEnumChoices(argMeta, context) ?? []);
|
|
@@ -424,9 +457,10 @@ var getArgumentValue = async (argMeta, value) => {
|
|
|
424
457
|
name,
|
|
425
458
|
argsOption: { default: defaultValue, type, desc, nullable, example, ask }
|
|
426
459
|
} = argMeta;
|
|
427
|
-
if (value !== undefined)
|
|
460
|
+
if (value !== undefined) {
|
|
461
|
+
assertEnumChoice(argMeta, value);
|
|
428
462
|
return convertArgValue(value, type ?? "string");
|
|
429
|
-
else if (defaultValue !== undefined)
|
|
463
|
+
} else if (defaultValue !== undefined)
|
|
430
464
|
return defaultValue;
|
|
431
465
|
else if (nullable)
|
|
432
466
|
return null;
|
|
@@ -465,6 +499,31 @@ var assertCurrentDirectoryIsWorkspaceRoot = async () => {
|
|
|
465
499
|
].join(`
|
|
466
500
|
`));
|
|
467
501
|
};
|
|
502
|
+
var parseAppNameList = (value) => (Array.isArray(value) ? value : value === undefined ? [] : [value]).flatMap((entry) => entry.split(",")).map((entry) => entry.trim()).filter(Boolean);
|
|
503
|
+
var getAppsArgumentValue = async (value, workspace) => {
|
|
504
|
+
const appNames = await workspace.getApps();
|
|
505
|
+
if (appNames.length === 0)
|
|
506
|
+
throw new Error("No apps found in this workspace (apps/<appName>/akan.config.ts)");
|
|
507
|
+
const requested = parseAppNameList(value);
|
|
508
|
+
if (requested.includes("all"))
|
|
509
|
+
return appNames.map((name) => AppExecutor.from(workspace, name));
|
|
510
|
+
if (requested.length) {
|
|
511
|
+
const unknown = requested.filter((name) => !appNames.includes(name));
|
|
512
|
+
if (unknown.length)
|
|
513
|
+
throw new Error(`Unknown app${unknown.length > 1 ? "s" : ""}: ${unknown.join(", ")}. Available: ${appNames.join(", ")}, all`);
|
|
514
|
+
return [...new Set(requested)].map((name) => AppExecutor.from(workspace, name));
|
|
515
|
+
}
|
|
516
|
+
if (appNames.length === 1 && appNames[0])
|
|
517
|
+
return [AppExecutor.from(workspace, appNames[0])];
|
|
518
|
+
const remembered = new Set(await AppSelectionMemory.read(workspace.workspaceRoot));
|
|
519
|
+
const picked = await checkbox({
|
|
520
|
+
message: "Select the apps to run (space to toggle, enter to confirm)",
|
|
521
|
+
choices: appNames.map((name) => ({ name, value: name, checked: remembered.has(name) })),
|
|
522
|
+
required: true
|
|
523
|
+
});
|
|
524
|
+
await AppSelectionMemory.write(workspace.workspaceRoot, picked);
|
|
525
|
+
return picked.map((name) => AppExecutor.from(workspace, name));
|
|
526
|
+
};
|
|
468
527
|
var getInternalArgumentValue = async (argMeta, value, workspace) => {
|
|
469
528
|
if (argMeta.type === "Workspace")
|
|
470
529
|
return workspace;
|
|
@@ -528,36 +587,36 @@ var getInternalArgumentValue = async (argMeta, value, workspace) => {
|
|
|
528
587
|
return PkgExecutor.from(workspace, pkgName);
|
|
529
588
|
} else if (sysType === "module") {
|
|
530
589
|
if (value) {
|
|
531
|
-
const [sysName,
|
|
532
|
-
if (!sysName || !
|
|
590
|
+
const [sysName, moduleName] = value.split(":");
|
|
591
|
+
if (!sysName || !moduleName)
|
|
533
592
|
throw new Error(`Invalid module name: ${value}`);
|
|
534
593
|
if (appNames.includes(sysName)) {
|
|
535
594
|
const app = AppExecutor.from(workspace, sysName);
|
|
536
|
-
const
|
|
537
|
-
if (
|
|
538
|
-
return ModuleExecutor.from(app,
|
|
595
|
+
const modules = await app.getModules();
|
|
596
|
+
if (modules.includes(moduleName))
|
|
597
|
+
return ModuleExecutor.from(app, moduleName);
|
|
539
598
|
else
|
|
540
|
-
throw new Error(`Invalid module name: ${
|
|
599
|
+
throw new Error(`Invalid module name: ${moduleName}`);
|
|
541
600
|
} else if (libNames.includes(sysName)) {
|
|
542
601
|
const lib = LibExecutor.from(workspace, sysName);
|
|
543
|
-
const
|
|
544
|
-
if (
|
|
545
|
-
return ModuleExecutor.from(lib,
|
|
602
|
+
const modules = await lib.getModules();
|
|
603
|
+
if (modules.includes(moduleName))
|
|
604
|
+
return ModuleExecutor.from(lib, moduleName);
|
|
546
605
|
} else
|
|
547
606
|
throw new Error(`Invalid system name: ${sysName}`);
|
|
548
607
|
}
|
|
549
608
|
const { type, name } = await select({
|
|
550
609
|
message: `select the App or Lib name`,
|
|
551
610
|
choices: [
|
|
552
|
-
...appNames.map((
|
|
553
|
-
...libNames.map((
|
|
611
|
+
...appNames.map((name) => ({ name, value: { type: "app", name } })),
|
|
612
|
+
...libNames.map((name) => ({ name, value: { type: "lib", name } }))
|
|
554
613
|
]
|
|
555
614
|
});
|
|
556
615
|
const executor = type === "app" ? AppExecutor.from(workspace, name) : LibExecutor.from(workspace, name);
|
|
557
616
|
const modules = await executor.getModules();
|
|
558
617
|
const moduleName = await select({
|
|
559
618
|
message: `Select the module name`,
|
|
560
|
-
choices: modules.map((
|
|
619
|
+
choices: modules.map((name) => ({ name: `${executor.name}:${name}`, value: name }))
|
|
561
620
|
});
|
|
562
621
|
return ModuleExecutor.from(executor, moduleName);
|
|
563
622
|
} else
|
|
@@ -568,8 +627,8 @@ var runCommands = async (...commands) => {
|
|
|
568
627
|
printCliError(error);
|
|
569
628
|
process.exit(1);
|
|
570
629
|
});
|
|
571
|
-
const __dirname2 =
|
|
572
|
-
const packageJsonCandidates = [`${
|
|
630
|
+
const __dirname2 = getDirname2(import.meta.url);
|
|
631
|
+
const packageJsonCandidates = [`${path2.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
|
|
573
632
|
let cliPackageJson = null;
|
|
574
633
|
for (const packageJsonPath of packageJsonCandidates) {
|
|
575
634
|
if (!await FileSys.fileExists(packageJsonPath))
|
|
@@ -616,6 +675,8 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
|
|
|
616
675
|
continue;
|
|
617
676
|
else if (argMeta.type === "Module") {
|
|
618
677
|
programCommand = programCommand.argument(`[sys-name:module-name]`, `${argMeta.type} in this workspace (apps|libs)/<sys-name>/lib/<module-name>`);
|
|
678
|
+
} else if (argMeta.type === "Apps") {
|
|
679
|
+
programCommand = programCommand.argument(`[apps...]`, `apps in this workspace apps/<appName>, or all (space- or comma-separated; omit to pick interactively)`);
|
|
619
680
|
} else {
|
|
620
681
|
const sysType = argMeta.type.toLowerCase();
|
|
621
682
|
programCommand = programCommand.argument(`[${sysType}]`, `${sysType} in this workspace ${sysType}s/<${sysType}Name>`);
|
|
@@ -640,10 +701,17 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
|
|
|
640
701
|
commandArgs[argMeta.idx] = await getOptionValue(argMeta, opt, commandContext);
|
|
641
702
|
else if (argMeta.type === "Argument")
|
|
642
703
|
commandArgs[argMeta.idx] = await getArgumentValue(argMeta, cmdArgs[argMeta.idx]);
|
|
704
|
+
else if (argMeta.type === "Apps")
|
|
705
|
+
commandArgs[argMeta.idx] = await getAppsArgumentValue(cmdArgs[argMeta.idx], workspace);
|
|
643
706
|
else
|
|
644
707
|
commandArgs[argMeta.idx] = await getInternalArgumentValue(argMeta, cmdArgs[argMeta.idx], workspace);
|
|
645
708
|
if (commandArgs[argMeta.idx] instanceof AppExecutor)
|
|
646
709
|
process.env.AKAN_PUBLIC_APP_NAME = commandArgs[argMeta.idx].name;
|
|
710
|
+
else if (Array.isArray(commandArgs[argMeta.idx])) {
|
|
711
|
+
const apps = commandArgs[argMeta.idx];
|
|
712
|
+
if (apps.length === 1 && apps[0])
|
|
713
|
+
process.env.AKAN_PUBLIC_APP_NAME = apps[0].name;
|
|
714
|
+
}
|
|
647
715
|
assignCommandContext(commandContext, argMeta, commandArgs[argMeta.idx]);
|
|
648
716
|
if (opt.verbose)
|
|
649
717
|
Executor.setVerbose(true);
|
|
@@ -763,4 +831,4 @@ function command(refName, depsOrBuilder, builder) {
|
|
|
763
831
|
}
|
|
764
832
|
return CommandBase;
|
|
765
833
|
}
|
|
766
|
-
export { getTargetMetas, getTargetCommandNames, App, Lib, Sys, Exec, Pkg, Module, Workspace, CommandContainer, runner, script, runCommands, command };
|
|
834
|
+
export { getTargetMetas, getTargetCommandNames, App, Apps, Lib, Sys, Exec, Pkg, Module, Workspace, CommandContainer, runner, script, runCommands, command };
|
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// pkgs/@akanjs/devkit/frontendBuild/styleContract.ts
|
|
3
|
-
var countBlocking = (
|
|
4
|
-
var formatStyleContract = (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
lines.push(` ${s.snippet}`);
|
|
9
|
-
lines.push(` \u2192 ${s.suggestion}`);
|
|
10
|
-
}
|
|
11
|
-
for (const t of v.theme) {
|
|
12
|
-
lines.push(` [error] contrast ${t.scope} ${t.pair} = ${t.ratio}:1 (min ${t.threshold}:1)`);
|
|
13
|
-
lines.push(` \u2192 ${t.suggestion}`);
|
|
14
|
-
}
|
|
15
|
-
return lines.join(`
|
|
3
|
+
var countBlocking = (violations) => violations.theme.length;
|
|
4
|
+
var formatStyleContract = (violations) => violations.theme.flatMap((theme) => [
|
|
5
|
+
` [error] contrast ${theme.scope} ${theme.pair} = ${theme.ratio}:1 (min ${theme.threshold}:1)`,
|
|
6
|
+
` \u2192 ${theme.suggestion}`
|
|
7
|
+
]).join(`
|
|
16
8
|
`);
|
|
17
|
-
};
|
|
18
9
|
|
|
19
10
|
// pkgs/@akanjs/devkit/frontendBuild/themeValidator.ts
|
|
20
11
|
var PAIRS = [
|
|
@@ -66,7 +57,7 @@ class ThemeValidator {
|
|
|
66
57
|
foreground: front,
|
|
67
58
|
ratio: Math.round(ratio * 100) / 100,
|
|
68
59
|
threshold,
|
|
69
|
-
suggestion:
|
|
60
|
+
suggestion: `In ${scope}, --${base} (${bg}) against --${fg} (${front}) is ${ratio.toFixed(2)}:1, under the ${threshold}:1 minimum. Lighten or darken one of them until it clears.`
|
|
70
61
|
});
|
|
71
62
|
}
|
|
72
63
|
return violations;
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
AkanContextAnalyzer
|
|
4
|
-
} from "./index-e4b2ae6b.js";
|
|
5
|
-
import {
|
|
6
|
-
Prompter
|
|
7
|
-
} from "./index-j37qq1f2.js";
|
|
8
2
|
import {
|
|
9
3
|
runner,
|
|
10
4
|
script
|
|
11
|
-
} from "./index-
|
|
5
|
+
} from "./index-mak3cd28.js";
|
|
12
6
|
import {
|
|
13
|
-
AGENT_BLOCK_END,
|
|
14
7
|
AGENT_BLOCK_START,
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
AGENT_BLOCK_END,
|
|
9
|
+
stampBlockVersion,
|
|
17
10
|
readDevkitVersion,
|
|
11
|
+
upsertAgentBlock,
|
|
18
12
|
renderRecipeEntries,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
CLAUDE_COMMENT_RULE,
|
|
14
|
+
AppExecutor,
|
|
15
|
+
LibExecutor
|
|
16
|
+
} from "./index-2tv3fdx4.js";
|
|
22
17
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} from "./index-
|
|
18
|
+
collectRecipeSources2,
|
|
19
|
+
scanRecipes2
|
|
20
|
+
} from "./index-by5gpp8x.js";
|
|
21
|
+
import {
|
|
22
|
+
AkanContextAnalyzer
|
|
23
|
+
} from "./index-ktb5njgy.js";
|
|
24
|
+
import {
|
|
25
|
+
Prompter
|
|
26
|
+
} from "./index-h7yw2z9n.js";
|
|
26
27
|
|
|
27
28
|
// pkgs/@akanjs/cli/agent/agent.script.ts
|
|
28
29
|
import { Logger as Logger2 } from "akanjs/common";
|
|
@@ -76,8 +77,8 @@ Keep a sample only while you are still learning its pattern; delete it once your
|
|
|
76
77
|
`;
|
|
77
78
|
};
|
|
78
79
|
var renderRecipeIndex = async (workspace) => {
|
|
79
|
-
const sources = await
|
|
80
|
-
const recipes =
|
|
80
|
+
const sources = await collectRecipeSources2(`${workspace.workspaceRoot}/pkgs/akanjs/ui`, "akanjs/ui", "recipe");
|
|
81
|
+
const recipes = scanRecipes2(sources);
|
|
81
82
|
const scopeIndexPointer = `App and lib recipes are **not** listed here. Each app/lib carries its own generated index \u2014
|
|
82
83
|
\`apps/<app>/AGENTS.md\` / \`libs/<lib>/AGENTS.md\` (\`## Recipes In Scope\`) \u2014 regenerated by \`akan sync\` and
|
|
83
84
|
verified by \`akan lint\`. When working inside an app or lib, consult that file before consuming or authoring a look.`;
|
|
@@ -89,15 +90,14 @@ ${scopeIndexPointer}
|
|
|
89
90
|
`;
|
|
90
91
|
return `## Recipes
|
|
91
92
|
|
|
92
|
-
Framework UI recipes (Tailwind-variant look factories), importable from every app and lib
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
the
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
near-duplicate.** Full authoring/consumption policy: the \`recipeRule\` guideline.
|
|
93
|
+
Framework UI recipes (Tailwind-variant look factories), importable from every app and lib: \`import { <name> } from
|
|
94
|
+
"akanjs/ui"\`, then \`<name>(variants?, className?)\`. The second arg merges internally and takes **an array too**, so
|
|
95
|
+
never wrap it in \`cn()\`: \`<name>({}, ["h-full", isWide && "w-full", className])\`. The list below is the full
|
|
96
|
+
contract (\`*\` marks the default, \`key?\` is a boolean flag) \u2014 do not guess a name, path, or variant value, and do
|
|
97
|
+
not open the recipe file to consume one. **Before inlining a repeated surface (card, box, tile, \u2026): reuse a recipe,
|
|
98
|
+
or add one as \`apps/<app>/ui/Recipe/<name>.ts\`, one per file, re-exported from that folder's \`index.ts\` \u2014 never
|
|
99
|
+
re-implement the same look inline in several places, and never author a near-duplicate.** Full policy: the
|
|
100
|
+
\`recipeRule\` guideline.
|
|
101
101
|
|
|
102
102
|
${renderRecipeEntries(recipes)}
|
|
103
103
|
|
|
@@ -147,15 +147,12 @@ If generated output is stale or broken, update the owning source file and run \`
|
|
|
147
147
|
|
|
148
148
|
${recipeIndex}## MCP Workflow Policy
|
|
149
149
|
|
|
150
|
-
- Prefer Akan
|
|
151
|
-
-
|
|
152
|
-
-
|
|
153
|
-
-
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
- If no workflow exists, or apply reports unsupported/no-op/failed diagnostics that require manual action, keep edits scoped to owning source files and never patch generated files directly.
|
|
157
|
-
- For compound requests, split the request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
|
|
158
|
-
- **CLI-only fallback (MCP not connected):** \`akan mcp\` starts a stdio MCP server, so the \`list_workflows\`/\`plan_workflow\`/\`apply_workflow\` tools exist only when your agent is wired to it as an MCP client. When they are unavailable, the CLI is a first-class equivalent: \`akan workflow list\` / \`explain <name>\` / \`plan <name> ... --format json --out <planPath>\` / \`apply <planPath> --format json\`, \`akan doctor --strict --format json\` for validation, and \`akan repair generated|imports|module-shape --app <app> --format json\` for repairs. Scaffolding primitives (\`create-module\`/\`create-scalar\`/\`create-service\` take the target app/lib as a POSITIONAL arg; \`add-field\`/\`add-enum-field\` use \`--app\`/\`--module\` flags) call the same code the workflows do.
|
|
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.
|
|
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
|
+
- Split a compound request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
|
|
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.
|
|
155
|
+
- **MCP not connected?** The CLI is a first-class equivalent \u2014 \`akan workflow list\` / \`explain\` / \`plan\` / \`apply\`, \`akan doctor\`, \`akan repair\`. See the onboarding guide's CLI-only fallback for the exact flags.
|
|
159
156
|
|
|
160
157
|
## Validation
|
|
161
158
|
|
|
@@ -199,6 +196,8 @@ var renderClaudeMd = async (workspace) => {
|
|
|
199
196
|
return `# ${context.repoName} \u2014 Claude Code Guide
|
|
200
197
|
|
|
201
198
|
@AGENTS.md
|
|
199
|
+
|
|
200
|
+
${CLAUDE_COMMENT_RULE}
|
|
202
201
|
`;
|
|
203
202
|
};
|
|
204
203
|
var renderCursorRule = () => `---
|
|
@@ -246,7 +245,7 @@ class AgentRunner extends runner("agent") {
|
|
|
246
245
|
written.push(`${exec.type}s/${exec.name}/AGENTS.md`);
|
|
247
246
|
} catch (error) {
|
|
248
247
|
const message = error instanceof Error ? error.message : String(error);
|
|
249
|
-
Logger.rawLog(`Skipped ${exec.type}s/${exec.name}/AGENTS.md (${message})`, undefined, "
|
|
248
|
+
Logger.rawLog(`Skipped ${exec.type}s/${exec.name}/AGENTS.md (${message})`, undefined, "error");
|
|
250
249
|
}
|
|
251
250
|
};
|
|
252
251
|
for (const name of libNames)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// pkgs/@akanjs/devkit/fileSys.ts
|
|
3
|
-
import { lstat, stat } from "fs/promises";
|
|
3
|
+
import { lstat, rename, rm, stat } from "fs/promises";
|
|
4
4
|
import { Logger } from "akanjs/common";
|
|
5
5
|
|
|
6
6
|
class FileSys {
|
|
@@ -9,7 +9,7 @@ class FileSys {
|
|
|
9
9
|
return await Bun.file(path).exists();
|
|
10
10
|
}
|
|
11
11
|
static async dirExists(path) {
|
|
12
|
-
return await stat(path).then((
|
|
12
|
+
return await stat(path).then((stat) => stat.isDirectory()).catch(() => false);
|
|
13
13
|
}
|
|
14
14
|
static async exists(path) {
|
|
15
15
|
return await stat(path).then(() => true).catch(() => false);
|
|
@@ -34,6 +34,18 @@ class FileSys {
|
|
|
34
34
|
static async writeText(path, content) {
|
|
35
35
|
return await Bun.file(path).write(content);
|
|
36
36
|
}
|
|
37
|
+
static async writeTextAtomic(filePath, content) {
|
|
38
|
+
const temp = `${filePath}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
39
|
+
try {
|
|
40
|
+
await Bun.write(temp, content);
|
|
41
|
+
await rename(temp, filePath);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
await rm(temp, { force: true }).catch(() => {
|
|
44
|
+
return;
|
|
45
|
+
});
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
37
49
|
static async writeJson(path, content) {
|
|
38
50
|
return await Bun.file(path).write(`${JSON.stringify(content, null, 2)}
|
|
39
51
|
`);
|