@akanjs/cli 2.4.2-rc.2 → 3.0.0-alpha.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/abstractCompactor-rk6twzvj.js +103 -0
- package/{agent.command-ej4g9pbb.js → agent.command-jfz8yfwy.js} +8 -7
- package/{application.command-smn51a28.js → application.command-3smsv7mq.js} +15 -5
- package/{applicationBuildRunner-554a2vnk.js → applicationBuildRunner-aq7mb3z6.js} +2 -1
- package/buildBatch.proc.js +7 -6
- package/{capacitorApp-yg9b4ajz.js → capacitorApp-q3mpmkkz.js} +3 -3
- package/{cloud.command-2v7ga38h.js → cloud.command-rk4e9vrt.js} +10 -10
- package/commandManifest.json +1 -1
- package/{context.command-hhjyjtp7.js → context.command-ygzyb0xb.js} +16 -15
- package/{guideline.command-vj956kfr.js → guideline.command-1m1ctar3.js} +10 -10
- package/guidelines/componentRule/componentRule.instruction.md +2 -2
- package/guidelines/cssRule/cssRule.generate.json +1 -1
- package/guidelines/cssRule/cssRule.instruction.md +57 -34
- package/guidelines/framework/framework.instruction.md +1 -1
- package/guidelines/recipeRule/recipeRule.generate.json +31 -0
- package/guidelines/recipeRule/recipeRule.instruction.md +72 -0
- package/incrementalBuilder.proc.js +5 -5
- package/index-0wae5ebk.js +65 -0
- package/{index-v9jqrdd1.js → index-4yp06pn1.js} +100 -2
- package/{index-pfnh87f9.js → index-4zgs8g1w.js} +1 -1
- package/{index-7ppn9v4n.js → index-b978vs2e.js} +3 -3
- package/{index-s9s0n5fz.js → index-cn24dcqn.js} +2 -2
- package/{index-h971erkm.js → index-csqk9z5j.js} +3 -3
- package/{index-z36qzgzp.js → index-e3qskyt2.js} +3 -4
- package/{index-panyahn4.js → index-ev6rjw9n.js} +27 -13
- package/{index-majzj044.js → index-f4gqk0dd.js} +8 -8
- package/{index-z5v766nx.js → index-fmgbwsr5.js} +6 -6
- package/{index-y1e79mz3.js → index-h0bngh79.js} +13 -13
- package/{index-dgeaqwmw.js → index-hjzr8ja1.js} +1 -1
- package/{index-d0h48d2f.js → index-jk9q6pse.js} +1 -1
- package/{index-xwfg9bam.js → index-jtm86byd.js} +120 -4
- package/{index-j3j3qc9j.js → index-ktprgc5g.js} +4 -4
- package/{index-40w1kqp1.js → index-n0z3f2xg.js} +74 -24
- package/{index-7k9sj7j5.js → index-pyt2b4nw.js} +212 -0
- package/{index-acwxfncv.js → index-r4w8cry5.js} +4 -4
- package/{index-zfp1gz9f.js → index-sggm9qkv.js} +1 -1
- package/{index-04as43rp.js → index-vhv3xnjz.js} +16 -15
- package/index-xjd3rqzj.js +129 -0
- package/{index-xftstr5s.js → index-xwgm94zr.js} +1 -1
- package/index-xys926f2.js +136 -0
- package/index.js +19 -19
- package/{library.command-68ah07a3.js → library.command-pwfx8dx2.js} +4 -4
- package/{localRegistry.command-nmyc5vwv.js → localRegistry.command-bxhqmd1d.js} +11 -11
- package/{module.command-t68xhamx.js → module.command-0t3ewata.js} +8 -8
- package/{package.command-00ncttab.js → package.command-7hmkxvpa.js} +4 -4
- package/package.json +2 -3
- package/{page.command-1096s18n.js → page.command-st6r4s0q.js} +4 -4
- package/{primitive.command-02eqpx6t.js → primitive.command-1qkxpzsn.js} +9 -9
- package/{quality.command-vap6xegb.js → quality.command-hy5vt1bh.js} +31 -6
- package/recipeScanner-tghkzrrt.js +12 -0
- package/{repair.command-7dynpnf1.js → repair.command-nakkq2zp.js} +7 -6
- package/{scalar.command-3kxy3fkh.js → scalar.command-fjq272gs.js} +7 -7
- package/templates/app/page/_index.tsx +55 -52
- package/templates/app/page/styles.css.template +12 -71
- package/templates/appSample/lib/task/Task.Template.tsx +2 -2
- package/templates/appSample/lib/task/Task.Unit.tsx +11 -11
- package/templates/appSample/lib/task/Task.Util.tsx +27 -28
- package/templates/appSample/lib/task/Task.View.tsx +22 -19
- package/templates/appSample/lib/task/Task.Zone.tsx +3 -3
- package/templates/appSample/page/task/[taskId]/_index.tsx +3 -3
- package/templates/appSample/page/task/[taskId]/edit.tsx +5 -5
- package/templates/appSample/page/task/_index.tsx +4 -4
- package/templates/appSample/page/task/_layout.tsx +1 -1
- package/templates/appSample/page/task/new.tsx +5 -5
- package/templates/appSample/ui/GlobalLoading.tsx +4 -4
- package/templates/appSample/ui/QuantityControl.tsx +5 -4
- package/templates/crudPages/[__model__Id]/page.tsx +1 -1
- package/templates/crudPages/page.tsx +1 -1
- package/templates/crudSinglePage/page.tsx +1 -1
- package/templates/module/__Model__.Template.tsx +2 -1
- package/templates/module/__Model__.Unit.tsx +2 -1
- package/templates/module/__Model__.Util.tsx +2 -1
- package/templates/module/__Model__.View.tsx +4 -3
- package/templates/module/__Model__.Zone.tsx +2 -1
- package/templates/workspaceRoot/AGENTS.md.template +11 -13
- package/templates/workspaceRoot/biome.json.template +1 -1
- package/{workflow.command-yy0d9gk3.js → workflow.command-jswbgk90.js} +15 -14
- package/{workspace.command-hq1x5605.js → workspace.command-p9r9nckg.js} +89 -29
- package/{applicationReleasePackager-pjbxc793.js → applicationReleasePackager-yrrhbkv3.js} +3 -3
- package/{index-nsj2ftxj.js → index-3pgtw35d.js} +3 -3
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
FileSys
|
|
4
|
-
} from "./index-67546d0j.js";
|
|
5
2
|
import {
|
|
6
3
|
Spinner
|
|
7
4
|
} from "./index-6pz1j0zj.js";
|
|
5
|
+
import {
|
|
6
|
+
FileSys
|
|
7
|
+
} from "./index-67546d0j.js";
|
|
8
8
|
import {
|
|
9
9
|
__require
|
|
10
10
|
} from "./index-r24hmh0q.js";
|
|
@@ -39,6 +39,109 @@ import {
|
|
|
39
39
|
var {$ } = globalThis.Bun;
|
|
40
40
|
import chalk2 from "chalk";
|
|
41
41
|
|
|
42
|
+
// pkgs/@akanjs/devkit/agentsIndex.ts
|
|
43
|
+
var recipeScannerLoad = null;
|
|
44
|
+
var loadRecipeScanner = () => recipeScannerLoad ??= import("./recipeScanner-tghkzrrt.js");
|
|
45
|
+
var AGENT_BLOCK_START = "<!-- akan:agent:start -->";
|
|
46
|
+
var AGENT_BLOCK_END = "<!-- akan:agent:end -->";
|
|
47
|
+
var upsertAgentBlock = (existing, block) => {
|
|
48
|
+
const managed = `${AGENT_BLOCK_START}
|
|
49
|
+
${block}
|
|
50
|
+
${AGENT_BLOCK_END}`;
|
|
51
|
+
const startIndex = existing.indexOf(AGENT_BLOCK_START);
|
|
52
|
+
const endIndex = existing.indexOf(AGENT_BLOCK_END);
|
|
53
|
+
if (startIndex >= 0 && endIndex > startIndex) {
|
|
54
|
+
return `${existing.slice(0, startIndex)}${managed}${existing.slice(endIndex + AGENT_BLOCK_END.length)}`;
|
|
55
|
+
}
|
|
56
|
+
return `${existing.replace(/\s*$/, "")}
|
|
57
|
+
|
|
58
|
+
${managed}
|
|
59
|
+
`;
|
|
60
|
+
};
|
|
61
|
+
var extractAgentBlock = (content) => {
|
|
62
|
+
const startIndex = content.indexOf(AGENT_BLOCK_START);
|
|
63
|
+
const endIndex = content.indexOf(AGENT_BLOCK_END);
|
|
64
|
+
if (startIndex < 0 || endIndex <= startIndex)
|
|
65
|
+
return null;
|
|
66
|
+
return content.slice(startIndex + AGENT_BLOCK_START.length, endIndex).trim();
|
|
67
|
+
};
|
|
68
|
+
var signatureOf = (recipe) => {
|
|
69
|
+
const entries = Object.entries(recipe.variants);
|
|
70
|
+
if (entries.length === 0)
|
|
71
|
+
return "";
|
|
72
|
+
const parts = entries.map(([key, values]) => {
|
|
73
|
+
if (values.length === 1 && values[0] === "true")
|
|
74
|
+
return `${key}?`;
|
|
75
|
+
const def = recipe.defaultVariants?.[key];
|
|
76
|
+
return `${key}: ${values.map((value) => value === def ? `${value}*` : value).join("|")}`;
|
|
77
|
+
});
|
|
78
|
+
return `(${parts.join(" \xB7 ")})`;
|
|
79
|
+
};
|
|
80
|
+
var renderRecipeEntries = (recipes) => {
|
|
81
|
+
const groups = new Map;
|
|
82
|
+
for (const recipe of recipes)
|
|
83
|
+
groups.set(recipe.importFrom, [...groups.get(recipe.importFrom) ?? [], recipe]);
|
|
84
|
+
return [...groups.entries()].map(([importFrom, list]) => {
|
|
85
|
+
const items = list.sort((a, b) => a.name.localeCompare(b.name)).map((recipe) => `- \`${recipe.name}\`${signatureOf(recipe)}${recipe.doc ? ` \u2014 ${recipe.doc}` : ""}`).join(`
|
|
86
|
+
`);
|
|
87
|
+
return `Import from \`${importFrom}\`:
|
|
88
|
+
${items}`;
|
|
89
|
+
}).join(`
|
|
90
|
+
|
|
91
|
+
`);
|
|
92
|
+
};
|
|
93
|
+
var collectScopeRecipeSources = async (workspaceRoot, scope, libDeps) => {
|
|
94
|
+
const { collectRecipeSources } = await loadRecipeScanner();
|
|
95
|
+
const sources = [
|
|
96
|
+
...await collectRecipeSources(`${workspaceRoot}/${scope.type}s/${scope.name}/ui`, `@${scope.type}s/${scope.name}/ui`)
|
|
97
|
+
];
|
|
98
|
+
for (const lib of [...new Set(libDeps)].sort()) {
|
|
99
|
+
if (scope.type === "lib" && lib === scope.name)
|
|
100
|
+
continue;
|
|
101
|
+
sources.push(...await collectRecipeSources(`${workspaceRoot}/libs/${lib}/ui`, `@libs/${lib}/ui`));
|
|
102
|
+
}
|
|
103
|
+
return sources;
|
|
104
|
+
};
|
|
105
|
+
var scanScopeRecipes = async (workspaceRoot, scope, libDeps) => {
|
|
106
|
+
const { scanRecipes } = await loadRecipeScanner();
|
|
107
|
+
return scanRecipes(await collectScopeRecipeSources(workspaceRoot, scope, libDeps));
|
|
108
|
+
};
|
|
109
|
+
var renderScopeAgentBlock = (scope, recipes) => {
|
|
110
|
+
const scopePath = `${scope.type}s/${scope.name}`;
|
|
111
|
+
const intro = `## Recipes In Scope
|
|
112
|
+
|
|
113
|
+
UI recipes importable from \`${scopePath}\` code, **in addition to** the framework recipes indexed in the root
|
|
114
|
+
\`AGENTS.md\` \`## Recipes\`. Same contract: import by exact name, then \`<name>(variants?, className?)\` \u2014 the second
|
|
115
|
+
arg merges internally and takes an array too, so never wrap it in \`cn()\`. \`*\` marks the default, \`key?\` is a
|
|
116
|
+
boolean flag. Do not guess recipe names or import paths; this index is regenerated by \`akan sync ${scope.name}\`
|
|
117
|
+
and verified by \`akan lint ${scope.name}\`.`;
|
|
118
|
+
if (recipes.length === 0) {
|
|
119
|
+
return `${intro}
|
|
120
|
+
|
|
121
|
+
No scope recipes yet. Before inlining a repeated surface (card, box, tile, \u2026), reuse a framework recipe from the
|
|
122
|
+
root \`AGENTS.md\` or author one as \`${scopePath}/ui/Recipe/<name>.ts\` (one recipe per file, re-exported from that
|
|
123
|
+
folder's \`index.ts\`) \u2014 see the \`recipeRule\` guideline.`;
|
|
124
|
+
}
|
|
125
|
+
return `${intro}
|
|
126
|
+
|
|
127
|
+
${renderRecipeEntries(recipes)}`;
|
|
128
|
+
};
|
|
129
|
+
var renderScopeAgentsMd = (scope, block) => `# ${scope.name} \u2014 Agent Guide
|
|
130
|
+
|
|
131
|
+
Scoped guide for coding agents working in \`${scope.type}s/${scope.name}\`. Workspace-wide conventions live in the
|
|
132
|
+
root \`AGENTS.md\`; this file carries what is importable from this ${scope.type === "app" ? "app" : "library"}. The
|
|
133
|
+
section between the \`akan:agent\` markers is regenerated by \`akan sync ${scope.name}\`; edit anything outside the
|
|
134
|
+
markers freely.
|
|
135
|
+
|
|
136
|
+
${AGENT_BLOCK_START}
|
|
137
|
+
${block}
|
|
138
|
+
${AGENT_BLOCK_END}
|
|
139
|
+
`;
|
|
140
|
+
var renderScopeClaudeMd = (scope) => `# ${scope.name} \u2014 Claude Code Guide
|
|
141
|
+
|
|
142
|
+
@AGENTS.md
|
|
143
|
+
`;
|
|
144
|
+
|
|
42
145
|
// pkgs/@akanjs/devkit/akanConfig/akanConfig.ts
|
|
43
146
|
import fs from "fs";
|
|
44
147
|
import path from "path";
|
|
@@ -824,6 +927,8 @@ var databaseFileTypes = [
|
|
|
824
927
|
"zone"
|
|
825
928
|
];
|
|
826
929
|
var appRootAllowedFiles = new Set([
|
|
930
|
+
"AGENTS.md",
|
|
931
|
+
"CLAUDE.md",
|
|
827
932
|
"akan.app.json",
|
|
828
933
|
"akan.config.ts",
|
|
829
934
|
"capacitor.config.ts",
|
|
@@ -2252,10 +2357,21 @@ class SysExecutor extends Executor {
|
|
|
2252
2357
|
await this.#updateDependencies(scanInfo);
|
|
2253
2358
|
await Promise.all(libInfos.flatMap((libInfo) => libInfo.exec.#getScanTemplateTasks(libInfo)));
|
|
2254
2359
|
}
|
|
2360
|
+
await this.syncAgentsIndex(scanInfo);
|
|
2255
2361
|
}
|
|
2256
2362
|
this.#scanInfo = scanInfo;
|
|
2257
2363
|
return scanInfo;
|
|
2258
2364
|
}
|
|
2365
|
+
async syncAgentsIndex(scanInfo) {
|
|
2366
|
+
const info = scanInfo ?? await this.scan({ write: false });
|
|
2367
|
+
const scope = { type: this.type, name: this.name };
|
|
2368
|
+
const recipes = await scanScopeRecipes(this.workspace.workspaceRoot, scope, info.getScanResult().libDeps);
|
|
2369
|
+
const block = renderScopeAgentBlock(scope, recipes);
|
|
2370
|
+
const existing = await this.exists("AGENTS.md") ? await this.readFile("AGENTS.md") : null;
|
|
2371
|
+
await this.writeFile("AGENTS.md", existing?.trim() ? upsertAgentBlock(existing, block) : renderScopeAgentsMd(scope, block));
|
|
2372
|
+
if (!await this.exists("CLAUDE.md"))
|
|
2373
|
+
await this.writeFile("CLAUDE.md", renderScopeClaudeMd(scope));
|
|
2374
|
+
}
|
|
2259
2375
|
async#updateDependencies(scanInfo) {
|
|
2260
2376
|
const rootPackageJson = await this.workspace.getPackageJson();
|
|
2261
2377
|
const libPackageJson = await this.getPackageJson();
|
|
@@ -2887,4 +3003,4 @@ class ModuleExecutor extends Executor {
|
|
|
2887
3003
|
}
|
|
2888
3004
|
}
|
|
2889
3005
|
|
|
2890
|
-
export { getDirname, CommandExecutionError, Executor, WorkspaceExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
|
|
3006
|
+
export { AGENT_BLOCK_START, AGENT_BLOCK_END, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, getDirname, CommandExecutionError, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
|
|
@@ -4,17 +4,17 @@ import {
|
|
|
4
4
|
CloudApi,
|
|
5
5
|
GlobalConfig,
|
|
6
6
|
getDefaultHostConfig
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-3pgtw35d.js";
|
|
8
8
|
import {
|
|
9
9
|
openBrowser
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-ev6rjw9n.js";
|
|
11
11
|
import {
|
|
12
12
|
runner
|
|
13
|
-
} from "./index-
|
|
13
|
+
} from "./index-jk9q6pse.js";
|
|
14
14
|
import {
|
|
15
15
|
AppExecutor,
|
|
16
16
|
WorkspaceExecutor
|
|
17
|
-
} from "./index-
|
|
17
|
+
} from "./index-jtm86byd.js";
|
|
18
18
|
|
|
19
19
|
// pkgs/@akanjs/cli/cloud/cloud.runner.ts
|
|
20
20
|
import path from "path";
|
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
AkanContextAnalyzer
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-4yp06pn1.js";
|
|
5
5
|
import {
|
|
6
6
|
Prompter
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-xwgm94zr.js";
|
|
8
8
|
import {
|
|
9
9
|
runner,
|
|
10
10
|
script
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-jk9q6pse.js";
|
|
12
|
+
import {
|
|
13
|
+
AGENT_BLOCK_END,
|
|
14
|
+
AGENT_BLOCK_START,
|
|
15
|
+
AppExecutor,
|
|
16
|
+
LibExecutor,
|
|
17
|
+
renderRecipeEntries,
|
|
18
|
+
upsertAgentBlock
|
|
19
|
+
} from "./index-jtm86byd.js";
|
|
20
|
+
import {
|
|
21
|
+
collectRecipeSources,
|
|
22
|
+
scanRecipes
|
|
23
|
+
} from "./index-xys926f2.js";
|
|
12
24
|
|
|
13
25
|
// pkgs/@akanjs/cli/agent/agent.script.ts
|
|
14
|
-
import { Logger } from "akanjs/common";
|
|
26
|
+
import { Logger as Logger2 } from "akanjs/common";
|
|
15
27
|
|
|
16
28
|
// pkgs/@akanjs/cli/agent/agent.runner.ts
|
|
29
|
+
import { Logger } from "akanjs/common";
|
|
17
30
|
var targetPaths = {
|
|
18
31
|
cursor: ".cursor/rules/akan.mdc",
|
|
19
32
|
"agents-md": "AGENTS.md",
|
|
20
33
|
claude: "CLAUDE.md"
|
|
21
34
|
};
|
|
22
|
-
var AGENT_BLOCK_START = "<!-- akan:agent:start -->";
|
|
23
|
-
var AGENT_BLOCK_END = "<!-- akan:agent:end -->";
|
|
24
35
|
var SAMPLE_ARTIFACTS = [
|
|
25
36
|
{ probe: "lib/task/task.constant.ts", target: "lib/task", label: "sample database module" },
|
|
26
37
|
{ probe: "lib/_noti/noti.service.ts", target: "lib/_noti", label: "sample service module" },
|
|
@@ -60,12 +71,44 @@ ${items.join(`
|
|
|
60
71
|
|
|
61
72
|
Keep a sample only while you are still learning its pattern; delete it once your own modules cover the same ground.
|
|
62
73
|
|
|
74
|
+
`;
|
|
75
|
+
};
|
|
76
|
+
var renderRecipeIndex = async (workspace) => {
|
|
77
|
+
const sources = await collectRecipeSources(`${workspace.workspaceRoot}/pkgs/akanjs/ui`, "akanjs/ui", "recipe");
|
|
78
|
+
const recipes = scanRecipes(sources);
|
|
79
|
+
const scopeIndexPointer = `App and lib recipes are **not** listed here. Each app/lib carries its own generated index \u2014
|
|
80
|
+
\`apps/<app>/AGENTS.md\` / \`libs/<lib>/AGENTS.md\` (\`## Recipes In Scope\`) \u2014 regenerated by \`akan sync\` and
|
|
81
|
+
verified by \`akan lint\`. When working inside an app or lib, consult that file before consuming or authoring a look.`;
|
|
82
|
+
if (recipes.length === 0)
|
|
83
|
+
return `## Recipes
|
|
84
|
+
|
|
85
|
+
${scopeIndexPointer}
|
|
86
|
+
|
|
87
|
+
`;
|
|
88
|
+
return `## Recipes
|
|
89
|
+
|
|
90
|
+
Framework UI recipes (Tailwind-variant look factories), importable from every app and lib. Consume by exact name \u2014
|
|
91
|
+
\`import { <name> } from "akanjs/ui"\`, then \`<name>(variants?, className?)\`. The second arg merges internally and
|
|
92
|
+
takes **an array too**, so never wrap it in \`cn()\`: \`<name>({}, ["h-full", isWide && "w-full", className])\`.
|
|
93
|
+
Do not guess recipe names, import paths, or variant values; the list below carries
|
|
94
|
+
the full contract (\`*\` marks the default, \`key?\` is a boolean flag), so there is no need to open the recipe file to
|
|
95
|
+
consume one. tsc still reports variant mistakes. **Before inlining a repeated surface (card, box,
|
|
96
|
+
tile, \u2026): reuse a recipe, or add one as \`apps/<app>/ui/Recipe/<name>.ts\` (one recipe per file, re-exported from
|
|
97
|
+
that folder's \`index.ts\`) \u2014 never re-implement the same look inline in several places, and never author a
|
|
98
|
+
near-duplicate.** Full authoring/consumption policy: the \`recipeRule\` guideline.
|
|
99
|
+
|
|
100
|
+
${renderRecipeEntries(recipes)}
|
|
101
|
+
|
|
102
|
+
${scopeIndexPointer}
|
|
103
|
+
|
|
63
104
|
`;
|
|
64
105
|
};
|
|
65
106
|
var renderManagedBlock = async (workspace) => {
|
|
66
107
|
const context = await AkanContextAnalyzer.analyze(workspace);
|
|
67
108
|
const frameworkGuide = await Prompter.getInstruction("framework");
|
|
68
|
-
const
|
|
109
|
+
const appNames = context.apps.map((app) => app.name);
|
|
110
|
+
const sampleCleanup = await renderSampleCleanup(workspace, appNames);
|
|
111
|
+
const recipeIndex = await renderRecipeIndex(workspace);
|
|
69
112
|
return `## Workspace
|
|
70
113
|
|
|
71
114
|
- Repo: ${context.repoName}
|
|
@@ -79,13 +122,14 @@ ${sampleCleanup}## Akan Module Abstracts
|
|
|
79
122
|
- Update the abstract when business invariants, workflows, or public behavior change.
|
|
80
123
|
- Do not update the abstract for formatting-only, import-only, or style-only changes.
|
|
81
124
|
- Service modules live in \`lib/_<service>\`, but their abstract file is \`<service>.abstract.md\`.
|
|
125
|
+
- Keep an abstract short. Run \`akan compact <app-or-lib>\` to rewrite bloated abstracts down to the invariants the code cannot show; \`akan quality scan\` warns past 300 lines.
|
|
82
126
|
|
|
83
127
|
## Generated Files
|
|
84
128
|
|
|
85
129
|
Do not hand-edit generated Akan files such as ${context.generatedFiles.map((file) => `\`${file}\``).join(", ")}.
|
|
86
130
|
If generated output is stale or broken, update the owning source file and run \`akan repair generated\` or \`akan sync <app-or-lib>\`.
|
|
87
131
|
|
|
88
|
-
## MCP Workflow Policy
|
|
132
|
+
${recipeIndex}## MCP Workflow Policy
|
|
89
133
|
|
|
90
134
|
- Prefer Akan MCP workflows before direct source edits.
|
|
91
135
|
- Direct source edits are denied when an allowlisted Akan workflow or repair tool can perform the change.
|
|
@@ -106,24 +150,10 @@ ${context.validationCommands.map((command) => `- \`${command}\``).join(`
|
|
|
106
150
|
|
|
107
151
|
${frameworkGuide.trim()}`;
|
|
108
152
|
};
|
|
109
|
-
var upsertManagedBlock = (existing, block) => {
|
|
110
|
-
const managed = `${AGENT_BLOCK_START}
|
|
111
|
-
${block}
|
|
112
|
-
${AGENT_BLOCK_END}`;
|
|
113
|
-
const startIndex = existing.indexOf(AGENT_BLOCK_START);
|
|
114
|
-
const endIndex = existing.indexOf(AGENT_BLOCK_END);
|
|
115
|
-
if (startIndex >= 0 && endIndex > startIndex) {
|
|
116
|
-
return `${existing.slice(0, startIndex)}${managed}${existing.slice(endIndex + AGENT_BLOCK_END.length)}`;
|
|
117
|
-
}
|
|
118
|
-
return `${existing.replace(/\s*$/, "")}
|
|
119
|
-
|
|
120
|
-
${managed}
|
|
121
|
-
`;
|
|
122
|
-
};
|
|
123
153
|
var renderAgentsMd = async (workspace, existing) => {
|
|
124
154
|
const block = await renderManagedBlock(workspace);
|
|
125
155
|
if (existing?.trim())
|
|
126
|
-
return
|
|
156
|
+
return upsertAgentBlock(existing, block);
|
|
127
157
|
const context = await AkanContextAnalyzer.analyze(workspace);
|
|
128
158
|
return `# ${context.repoName} Agent Guide
|
|
129
159
|
|
|
@@ -175,6 +205,26 @@ class AgentRunner extends runner("agent") {
|
|
|
175
205
|
await workspace.writeFile(filePath, content, { overwrite: true });
|
|
176
206
|
written.push(filePath);
|
|
177
207
|
}
|
|
208
|
+
if (targets.includes("agents-md"))
|
|
209
|
+
written.push(...await this.#installScopeIndexes(workspace));
|
|
210
|
+
return written;
|
|
211
|
+
}
|
|
212
|
+
async#installScopeIndexes(workspace) {
|
|
213
|
+
const [appNames, libNames] = await workspace.getExecs();
|
|
214
|
+
const written = [];
|
|
215
|
+
const syncScope = async (exec) => {
|
|
216
|
+
try {
|
|
217
|
+
await exec.syncAgentsIndex();
|
|
218
|
+
written.push(`${exec.type}s/${exec.name}/AGENTS.md`);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
221
|
+
Logger.rawLog(`Skipped ${exec.type}s/${exec.name}/AGENTS.md (${message})`, undefined, "warn");
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
for (const name of libNames)
|
|
225
|
+
await syncScope(LibExecutor.from(workspace, name));
|
|
226
|
+
for (const name of appNames)
|
|
227
|
+
await syncScope(AppExecutor.from(workspace, name));
|
|
178
228
|
return written;
|
|
179
229
|
}
|
|
180
230
|
}
|
|
@@ -193,7 +243,7 @@ class AgentScript extends script("agent", [AgentRunner]) {
|
|
|
193
243
|
if (action !== "install")
|
|
194
244
|
throw new Error(`Unknown agent action: ${action}. Use "install".`);
|
|
195
245
|
const written = await this.agentRunner.install(workspace, resolveTargets(target), { force });
|
|
196
|
-
|
|
246
|
+
Logger2.rawLog(`Agent rules written:
|
|
197
247
|
${written.map((file) => `- ${file}`).join(`
|
|
198
248
|
`)}`);
|
|
199
249
|
}
|
|
@@ -2217,4 +2217,216 @@ ${preparedCssText}`).toString(36);
|
|
|
2217
2217
|
return [basePath, { cssUrl, cssRelPath }];
|
|
2218
2218
|
}
|
|
2219
2219
|
}
|
|
2220
|
+
// pkgs/@akanjs/devkit/frontendBuild/styleGuard.ts
|
|
2221
|
+
var PREFIX = "(?:bg|text|border(?:-[tblrxy])?(?:-[se])?|ring(?:-offset)?|fill|stroke|shadow|from|to|via|divide|outline|decoration|placeholder|caret|accent)";
|
|
2222
|
+
var PALETTE = "(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)";
|
|
2223
|
+
var LEAD = "(^|[\\s\"'`{(\\[:!])";
|
|
2224
|
+
var TAIL = "(?=[\\s\"'`})\\]:/!,]|$)";
|
|
2225
|
+
var RAW_PALETTE_RE = new RegExp(`${LEAD}((?:${PREFIX})-)${PALETTE}-\\d{2,3}${TAIL}`, "g");
|
|
2226
|
+
var ARBITRARY_COLOR_RE = /\[(#[0-9a-fA-F]{3,8}|(?:rgb|rgba|hsl|hsla|oklch|oklab|lab|lch|hwb|color)\([^\]]*\))\]/g;
|
|
2227
|
+
var INTERPOLATED_ARBITRARY_RE = new RegExp(`${LEAD}[a-z][a-z0-9-]*-\\[[^\\]\`]*\\$\\{`, "g");
|
|
2228
|
+
var STYLE_OBJECT_RE = /style=\{\{([\s\S]*?)\}\}/g;
|
|
2229
|
+
var STYLE_TAG_RE = /<style[^>]*>([\s\S]*?)<\/style>/g;
|
|
2230
|
+
var INLINE_COLOR_LITERAL_RE = /#[0-9a-fA-F]{3,8}\b|(?:rgb|rgba|hsl|hsla|oklch|oklab|lab|lch|hwb)\(/g;
|
|
2231
|
+
var DAISYUI_LEGACY_RE = new RegExp(`${LEAD}(?:` + "btn-(?:primary|secondary|accent|neutral|info|success|warning|error|ghost|link|outline|square|circle|wide|block|xs|sm|md|lg)|" + "badge-(?:primary|secondary|accent|neutral|info|success|warning|error|ghost|outline)|" + "alert-(?:info|success|warning|error)|" + "input-(?:bordered|primary|secondary|accent|ghost|error)|" + "select-(?:bordered|primary|ghost)|textarea-(?:bordered|primary|ghost)|" + "checkbox-(?:primary|secondary|accent)|toggle-(?:primary|secondary|accent)|" + "loading-(?:spinner|dots|ring|ball|bars|infinity)|" + "card-(?:body|title|actions)|modal-(?:box|action|backdrop)|" + "collapse-(?:title|content|arrow|plus)|dropdown-(?:content|end|start|hover)|" + "stat-(?:title|value|desc)|tabs-(?:boxed|lifted|bordered)|tab-active|" + "menu-(?:title|dropdown)|steps-(?:horizontal|vertical)|join-item|" + "mockup-(?:code|phone|browser|window)|drawer-(?:side|content|toggle)" + `)${TAIL}`, "g");
|
|
2232
|
+
var ALL_RULES = [
|
|
2233
|
+
"raw-palette",
|
|
2234
|
+
"arbitrary-color",
|
|
2235
|
+
"inline-color",
|
|
2236
|
+
"daisyui-legacy",
|
|
2237
|
+
"interpolated-arbitrary"
|
|
2238
|
+
];
|
|
2239
|
+
|
|
2240
|
+
class StyleGuard {
|
|
2241
|
+
run(files) {
|
|
2242
|
+
const out = [];
|
|
2243
|
+
for (const file of files) {
|
|
2244
|
+
const directives = this.#parseDirectives(file.content);
|
|
2245
|
+
const scan = this.#stripComments(file.content);
|
|
2246
|
+
const local = [];
|
|
2247
|
+
this.#scanClassLiterals(file, scan, local);
|
|
2248
|
+
this.#scanInlineColors(file, scan, local);
|
|
2249
|
+
for (const v of local)
|
|
2250
|
+
if (!this.#isSuppressed(v, directives))
|
|
2251
|
+
out.push(v);
|
|
2252
|
+
}
|
|
2253
|
+
return out;
|
|
2254
|
+
}
|
|
2255
|
+
#stripComments(src) {
|
|
2256
|
+
const out = src.split("");
|
|
2257
|
+
const blank = (i2) => {
|
|
2258
|
+
if (src[i2] !== `
|
|
2259
|
+
`)
|
|
2260
|
+
out[i2] = " ";
|
|
2261
|
+
};
|
|
2262
|
+
let state = "code";
|
|
2263
|
+
let i = 0;
|
|
2264
|
+
while (i < src.length) {
|
|
2265
|
+
const c = src[i];
|
|
2266
|
+
const d = src[i + 1];
|
|
2267
|
+
if (state === "code") {
|
|
2268
|
+
if (c === "/" && d === "/") {
|
|
2269
|
+
blank(i);
|
|
2270
|
+
blank(i + 1);
|
|
2271
|
+
state = "line";
|
|
2272
|
+
i += 2;
|
|
2273
|
+
} else if (c === "/" && d === "*") {
|
|
2274
|
+
blank(i);
|
|
2275
|
+
blank(i + 1);
|
|
2276
|
+
state = "block";
|
|
2277
|
+
i += 2;
|
|
2278
|
+
} else {
|
|
2279
|
+
if (c === "'")
|
|
2280
|
+
state = "squote";
|
|
2281
|
+
else if (c === '"')
|
|
2282
|
+
state = "dquote";
|
|
2283
|
+
else if (c === "`")
|
|
2284
|
+
state = "template";
|
|
2285
|
+
i++;
|
|
2286
|
+
}
|
|
2287
|
+
} else if (state === "line") {
|
|
2288
|
+
if (c === `
|
|
2289
|
+
`)
|
|
2290
|
+
state = "code";
|
|
2291
|
+
else
|
|
2292
|
+
blank(i);
|
|
2293
|
+
i++;
|
|
2294
|
+
} else if (state === "block") {
|
|
2295
|
+
if (c === "*" && d === "/") {
|
|
2296
|
+
blank(i);
|
|
2297
|
+
blank(i + 1);
|
|
2298
|
+
state = "code";
|
|
2299
|
+
i += 2;
|
|
2300
|
+
} else {
|
|
2301
|
+
blank(i);
|
|
2302
|
+
i++;
|
|
2303
|
+
}
|
|
2304
|
+
} else {
|
|
2305
|
+
const close = state === "squote" ? "'" : state === "dquote" ? '"' : "`";
|
|
2306
|
+
if (c === "\\")
|
|
2307
|
+
i += 2;
|
|
2308
|
+
else {
|
|
2309
|
+
if (c === close)
|
|
2310
|
+
state = "code";
|
|
2311
|
+
i++;
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return out.join("");
|
|
2316
|
+
}
|
|
2317
|
+
#parseDirectives(content) {
|
|
2318
|
+
const directives = { file: null, nextLine: new Map };
|
|
2319
|
+
const lines = content.split(`
|
|
2320
|
+
`);
|
|
2321
|
+
for (let i = 0;i < lines.length; i++) {
|
|
2322
|
+
const line = lines[i];
|
|
2323
|
+
const nextLineMatch = line.match(/styleguard-disable-next-line\b(.*)$/);
|
|
2324
|
+
if (nextLineMatch) {
|
|
2325
|
+
directives.nextLine.set(i + 2, this.#extractRules(nextLineMatch[1]));
|
|
2326
|
+
continue;
|
|
2327
|
+
}
|
|
2328
|
+
const fileMatch = line.match(/styleguard-disable\b(.*)$/);
|
|
2329
|
+
if (fileMatch)
|
|
2330
|
+
directives.file = this.#mergeFileScope(directives.file, this.#extractRules(fileMatch[1]));
|
|
2331
|
+
}
|
|
2332
|
+
return directives;
|
|
2333
|
+
}
|
|
2334
|
+
#extractRules(tail) {
|
|
2335
|
+
const found = ALL_RULES.filter((rule) => tail.includes(rule));
|
|
2336
|
+
return found.length === 0 ? "all" : new Set(found);
|
|
2337
|
+
}
|
|
2338
|
+
#mergeFileScope(prev, next) {
|
|
2339
|
+
if (prev === "all" || next === "all")
|
|
2340
|
+
return "all";
|
|
2341
|
+
return new Set([...prev ?? [], ...next]);
|
|
2342
|
+
}
|
|
2343
|
+
#isSuppressed(v, directives) {
|
|
2344
|
+
if (directives.file === "all" || directives.file?.has(v.rule))
|
|
2345
|
+
return true;
|
|
2346
|
+
const nextLine = directives.nextLine.get(v.line);
|
|
2347
|
+
return nextLine === "all" || (nextLine?.has(v.rule) ?? false);
|
|
2348
|
+
}
|
|
2349
|
+
#scanClassLiterals(file, scan, out) {
|
|
2350
|
+
for (const m of scan.matchAll(RAW_PALETTE_RE)) {
|
|
2351
|
+
out.push(this.#violation(file, m.index ?? 0, {
|
|
2352
|
+
rule: "raw-palette",
|
|
2353
|
+
severity: "error",
|
|
2354
|
+
suggestion: "\uC2DC\uB9E8\uD2F1 \uD1A0\uD070\uC73C\uB85C \uAD50\uCCB4\uD558\uC138\uC694 \u2014 \uC608: text-gray-500\u2192text-muted-foreground, bg-red-500\u2192bg-destructive, bg-blue-500\u2192bg-info. \uBE0C\uB79C\uB4DC \uC0C9\uC740 page/styles.css \uD1A0\uD070\uC5D0\uC11C \uC870\uC815\uD569\uB2C8\uB2E4."
|
|
2355
|
+
}));
|
|
2356
|
+
}
|
|
2357
|
+
for (const m of scan.matchAll(ARBITRARY_COLOR_RE)) {
|
|
2358
|
+
out.push(this.#violation(file, m.index ?? 0, {
|
|
2359
|
+
rule: "arbitrary-color",
|
|
2360
|
+
severity: "error",
|
|
2361
|
+
suggestion: "\uC784\uC758 \uC0C9 \uB9AC\uD130\uB7F4 \uB300\uC2E0 \uD1A0\uD070\uC744 \uC4F0\uC138\uC694 \u2014 bg-[#3b82f6]\u2192bg-info, text-[rgb(...)]\u2192\uC2DC\uB9E8\uD2F1 \uD1A0\uD070. \uAF2D \uD544\uC694\uD558\uBA74 \uC2A4\uCF54\uD504 \uD1A0\uD070(.campaign-x { --primary: \u2026 })\uC744 \uC815\uC758\uD558\uC138\uC694."
|
|
2362
|
+
}));
|
|
2363
|
+
}
|
|
2364
|
+
for (const m of scan.matchAll(DAISYUI_LEGACY_RE)) {
|
|
2365
|
+
out.push(this.#violation(file, m.index ?? 0, {
|
|
2366
|
+
rule: "daisyui-legacy",
|
|
2367
|
+
severity: "error",
|
|
2368
|
+
suggestion: "daisyUI \uD074\uB798\uC2A4\uB294 \uC81C\uAC70\uB410\uC2B5\uB2C8\uB2E4. akanjs/ui \uD504\uB9AC\uBBF8\uD2F0\uBE0C(Button/Badge \uB4F1)\uB098 buttonRecipe()/badgeRecipe() + \uC2DC\uB9E8\uD2F1 \uD1A0\uD070\uC73C\uB85C \uAD50\uCCB4\uD558\uC138\uC694."
|
|
2369
|
+
}));
|
|
2370
|
+
}
|
|
2371
|
+
for (const m of scan.matchAll(INTERPOLATED_ARBITRARY_RE)) {
|
|
2372
|
+
out.push(this.#violation(file, m.index ?? 0, {
|
|
2373
|
+
rule: "interpolated-arbitrary",
|
|
2374
|
+
severity: "error",
|
|
2375
|
+
suggestion: "\uB7F0\uD0C0\uC784 \uAC12\uC73C\uB85C \uC784\uC758\uAC12 \uD074\uB798\uC2A4\uB97C \uC870\uB9BD\uD558\uBA74 CSS \uAC00 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uC2A4\uCE90\uB108\uB294 \uC18C\uC2A4 \uD14D\uC2A4\uD2B8\uB97C \uC77D\uC2B5\uB2C8\uB2E4). \uD06C\uAE30/\uC704\uCE58\uB294 style prop \uC73C\uB85C \uB118\uAE30\uC138\uC694 \u2014 style={{ minHeight }}. \uAC12\uC774 enum \uC774\uBA74 \uB9AC\uD130\uB7F4 \uD074\uB798\uC2A4 \uB9F5\uC73C\uB85C \uB450\uC138\uC694."
|
|
2376
|
+
}));
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
#scanInlineColors(file, scan, out) {
|
|
2380
|
+
const push = (index) => out.push(this.#violation(file, index, {
|
|
2381
|
+
rule: "inline-color",
|
|
2382
|
+
severity: "error",
|
|
2383
|
+
suggestion: "\uC778\uB77C\uC778 \uC0C9 \uB9AC\uD130\uB7F4 \uB300\uC2E0 CSS \uBCC0\uC218/\uD1A0\uD070\uC744 \uCC38\uC870\uD558\uC138\uC694 \u2014 style={{ color: 'var(--primary)' }} \uB610\uB294 \uC2DC\uB9E8\uD2F1 \uD074\uB798\uC2A4(text-primary). \uD558\uB4DC\uCF54\uB529 hex/rgb \uB294 \uD14C\uB9C8 \uC804\uD658\uC744 \uAE68\uB728\uB9BD\uB2C8\uB2E4."
|
|
2384
|
+
}));
|
|
2385
|
+
for (const region of [STYLE_OBJECT_RE, STYLE_TAG_RE]) {
|
|
2386
|
+
for (const m of scan.matchAll(region)) {
|
|
2387
|
+
const inner = m[1] ?? "";
|
|
2388
|
+
const innerStart = (m.index ?? 0) + m[0].indexOf(inner);
|
|
2389
|
+
for (const lit of inner.matchAll(INLINE_COLOR_LITERAL_RE)) {
|
|
2390
|
+
push(innerStart + (lit.index ?? 0));
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
#violation(file, index, base) {
|
|
2396
|
+
const before = file.content.slice(0, index);
|
|
2397
|
+
const line = before.length === 0 ? 1 : before.split(`
|
|
2398
|
+
`).length;
|
|
2399
|
+
const lineStart = before.lastIndexOf(`
|
|
2400
|
+
`) + 1;
|
|
2401
|
+
const lineEnd = file.content.indexOf(`
|
|
2402
|
+
`, index);
|
|
2403
|
+
const snippet = file.content.slice(lineStart, lineEnd === -1 ? undefined : lineEnd).trim();
|
|
2404
|
+
return { ...base, path: file.path, line, snippet };
|
|
2405
|
+
}
|
|
2406
|
+
static countNamedComponentClasses(css) {
|
|
2407
|
+
const names = new Set;
|
|
2408
|
+
const layerRe = /@layer\s+components\s*\{/g;
|
|
2409
|
+
for (const layer of css.matchAll(layerRe)) {
|
|
2410
|
+
const bodyStart = (layer.index ?? 0) + layer[0].length;
|
|
2411
|
+
const body = StyleGuard.#extractBalanced(css, bodyStart);
|
|
2412
|
+
for (const sel of body.matchAll(/(^|[\s}])\.(-?[a-zA-Z_][\w-]*)/g))
|
|
2413
|
+
names.add(sel[2]);
|
|
2414
|
+
}
|
|
2415
|
+
return { count: names.size, names: [...names].sort() };
|
|
2416
|
+
}
|
|
2417
|
+
static #extractBalanced(css, start) {
|
|
2418
|
+
let depth = 1;
|
|
2419
|
+
for (let i = start;i < css.length; i++) {
|
|
2420
|
+
const ch = css[i];
|
|
2421
|
+
if (ch === "{")
|
|
2422
|
+
depth++;
|
|
2423
|
+
else if (ch === "}") {
|
|
2424
|
+
depth--;
|
|
2425
|
+
if (depth === 0)
|
|
2426
|
+
return css.slice(start, i);
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
return css.slice(start);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2220
2432
|
export { AllRoutesBuilder, CsrArtifactBuilder, CssCompiler, FontOptimizer, PagesBundleBuilder, precompressArtifacts, SsrBaseArtifactBuilder };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
ModuleScript
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-vhv3xnjz.js";
|
|
5
5
|
import {
|
|
6
6
|
addFieldUiPolicyForType,
|
|
7
7
|
coerceFieldDefault,
|
|
@@ -34,15 +34,15 @@ import {
|
|
|
34
34
|
sourceFile,
|
|
35
35
|
validationCommandsForTarget,
|
|
36
36
|
viaBuilderParameterName
|
|
37
|
-
} from "./index-
|
|
37
|
+
} from "./index-4zgs8g1w.js";
|
|
38
38
|
import {
|
|
39
39
|
script
|
|
40
|
-
} from "./index-
|
|
40
|
+
} from "./index-jk9q6pse.js";
|
|
41
41
|
import {
|
|
42
42
|
AppExecutor,
|
|
43
43
|
LibExecutor,
|
|
44
44
|
ModuleExecutor
|
|
45
|
-
} from "./index-
|
|
45
|
+
} from "./index-jtm86byd.js";
|
|
46
46
|
|
|
47
47
|
// pkgs/@akanjs/cli/primitive/primitive.script.ts
|
|
48
48
|
import { capitalize } from "akanjs/common";
|