@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
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Recipe Rule Guideline
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Recipes are the reusable-look layer of Akan UI: Tailwind-variant factories (`recipe(tv({...}))`) that sit between semantic
|
|
5
|
+
tokens (values) and components (behavior). This rule governs how agents **consume** and **author** recipes so a look is not
|
|
6
|
+
hallucinated, re-derived inline, or duplicated across an app.
|
|
7
|
+
|
|
8
|
+
## Ownership
|
|
9
|
+
- A recipe owns a **look** (a composition of semantic-token utility classes), never behavior. Behavior lives in components.
|
|
10
|
+
- **One recipe per file.** App/lib recipes live in `apps/<app>/ui/Recipe/<name>.ts` and `libs/<lib>/ui/Recipe/<name>.ts`,
|
|
11
|
+
re-exported from that folder's hand-written `index.ts`; framework recipes (`buttonRecipe`, `badgeRecipe`,
|
|
12
|
+
`inputRecipe`) mirror the same shape in `pkgs/akanjs/ui/recipe/<name>Recipe.ts`. Apps inherit the framework recipes by
|
|
13
|
+
re-exporting them from their own `Recipe/index.ts`, so a consumer imports every recipe from one barrel.
|
|
14
|
+
- The folder must be `Recipe` (PascalCase) in an app/lib `ui/`: the generated `ui/index.ts` exports PascalCase names
|
|
15
|
+
only, so a flat `appCard.recipe.ts` is silently skipped and becomes unimportable. Inside the folder any camelCase
|
|
16
|
+
filename is fine — the barrel only scans one level.
|
|
17
|
+
- Recipes use **semantic tokens only** in their `base`/`variants` (never raw palette or hex); they inherit the CSS token rules.
|
|
18
|
+
|
|
19
|
+
## Consuming Recipes
|
|
20
|
+
- Import by **exact name** from the owning barrel: `import { <name> } from "@apps/<app>/ui"` (or `akanjs/ui` for framework),
|
|
21
|
+
then call `<name>(variants?, className?)` — the second arg is merged automatically; no extra `cn()` wrapper is needed.
|
|
22
|
+
- The second arg is a `ClassNameValue`, so it takes **an array (and falsy entries), not just one string**:
|
|
23
|
+
`<name>({}, ["h-full", isWide && "w-full", className])`. Reaching for `cn()` to combine several classes is the
|
|
24
|
+
usual way the no-`cn` contract leaks — there is nothing `cn()` adds here that the recipe does not already do.
|
|
25
|
+
- **Do not guess** recipe names or import paths. The authoritative index is split by ownership: the root `AGENTS.md`
|
|
26
|
+
`## Recipes` (always loaded) lists **framework** recipes, and each app/lib's own `AGENTS.md` (`## Recipes In Scope`)
|
|
27
|
+
lists what that scope may additionally import — its own recipes plus its dependency libs'. Both carry every recipe's
|
|
28
|
+
variant surface and default, so consuming one never requires opening its file. The scoped index is regenerated by
|
|
29
|
+
`akan sync <name>` and kept honest by `akan lint <name>`, which fails when it is stale.
|
|
30
|
+
- Variant options are typed (`Parameters<typeof <name>>[0]`), so a wrong variant is a compile error — let tsc validate
|
|
31
|
+
options rather than memorizing strings.
|
|
32
|
+
|
|
33
|
+
## Recipe vs Component vs Constant — The Gate
|
|
34
|
+
The form of a shared look is decided by **counting**, not judgment (`akan lint` enforces this as `recipeGate`):
|
|
35
|
+
|
|
36
|
+
1. **Does the caller choose an option?** (at least one variant axis with 2+ values, or a boolean flag)
|
|
37
|
+
- **No** → it is **never a recipe** — a fixed look wrapped in a function is dead indirection.
|
|
38
|
+
- Reused with its own markup → a small **component** (`<Divider/>`, `<DocsList/>`, `<Screen/>`).
|
|
39
|
+
- Injected into another component's `className` prop → a shared **class constant** (`appNavClass`).
|
|
40
|
+
- Used once → plain **inline** classes.
|
|
41
|
+
- **Yes** → it is a recipe. Then:
|
|
42
|
+
2. **Does it need markup or behavior** (own tag, structure, state, a11y)?
|
|
43
|
+
- No → pages call the recipe directly on their own element (`panelRecipe({ padding: "row" })`).
|
|
44
|
+
- Yes → a component consumes the recipe internally (`<Button variant>` → `buttonRecipe`).
|
|
45
|
+
|
|
46
|
+
## Authoring Recipes
|
|
47
|
+
- A **reusable or repeated surface** (card, box, tile, chat bubble, hero, …) belongs in a recipe, **not** inline. If the same
|
|
48
|
+
token-class stack appears in more than one place, extract it into a recipe.
|
|
49
|
+
- **Before authoring, check the existing recipe indexes** (root `AGENTS.md` `## Recipes` for framework recipes, the
|
|
50
|
+
scope's own `AGENTS.md` `## Recipes In Scope` for app/lib recipes) and **reuse** a matching recipe instead of
|
|
51
|
+
creating a near-duplicate — registry sprawl comes from re-inventing looks that already exist.
|
|
52
|
+
- Add a new recipe as its own file, `ui/Recipe/<name>.ts` holding a single
|
|
53
|
+
`export const <name>Recipe = recipe(tv({ base, variants }))` plus a one-line JSDoc describing the surface, then
|
|
54
|
+
re-export it from `ui/Recipe/index.ts`. Name the export `<name>Recipe`; the filename drops the suffix.
|
|
55
|
+
- Keep declaration and css in that one file. Splitting a recipe into a hand-written variant type plus a separate style
|
|
56
|
+
file inverts the dependency: the variant type is currently *inferred* from the `tv` config
|
|
57
|
+
(`Parameters<typeof <name>Recipe>[0]`), which makes type/css drift structurally impossible, and the AGENTS listing
|
|
58
|
+
already exposes the surface without reading the file. There is nothing left for the split to buy.
|
|
59
|
+
- App recipes **extend** (surfaces the framework lacks); they never re-define a framework component's look in parallel.
|
|
60
|
+
|
|
61
|
+
## Codegen Rules
|
|
62
|
+
- Do not re-derive inline a look that an existing recipe already provides.
|
|
63
|
+
- Do not author a near-duplicate of an existing recipe; reuse or extend it.
|
|
64
|
+
- Do not guess recipe names or import paths; use the authoritative list.
|
|
65
|
+
- Do not put raw-palette / hex / inline color in a recipe; semantic tokens only.
|
|
66
|
+
|
|
67
|
+
## Review Checklist
|
|
68
|
+
- Repeated/variant surfaces are recipes, not inline class stacks duplicated across files.
|
|
69
|
+
- No two recipes describe the same look; consumers import by exact name from the correct barrel.
|
|
70
|
+
- New recipes live one-per-file in the owning `ui/Recipe/`, exported as `<name>Recipe`, token-only, with a one-line doc,
|
|
71
|
+
and re-exported from that folder's `index.ts`.
|
|
72
|
+
- The output contract tells the model which file paths to return.
|
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
import {
|
|
3
3
|
prepareDevWatchBatch
|
|
4
4
|
} from "./index-fgc8r6dj.js";
|
|
5
|
-
import {
|
|
6
|
-
AppExecutor,
|
|
7
|
-
WorkspaceExecutor
|
|
8
|
-
} from "./index-xwfg9bam.js";
|
|
9
|
-
import"./index-67546d0j.js";
|
|
10
5
|
import {
|
|
11
6
|
AutoImportSync,
|
|
12
7
|
DevChangePlanner,
|
|
@@ -18,7 +13,12 @@ import {
|
|
|
18
13
|
HmrWatcher,
|
|
19
14
|
WatchRootResolver
|
|
20
15
|
} from "./index-bjpxzr6s.js";
|
|
16
|
+
import {
|
|
17
|
+
AppExecutor,
|
|
18
|
+
WorkspaceExecutor
|
|
19
|
+
} from "./index-jtm86byd.js";
|
|
21
20
|
import"./index-6pz1j0zj.js";
|
|
21
|
+
import"./index-67546d0j.js";
|
|
22
22
|
import"./index-r24hmh0q.js";
|
|
23
23
|
|
|
24
24
|
// pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// pkgs/@akanjs/devkit/abstractDoc.ts
|
|
3
|
+
class AbstractDoc {
|
|
4
|
+
path;
|
|
5
|
+
content;
|
|
6
|
+
siblingFiles;
|
|
7
|
+
static suffix = ".abstract.md";
|
|
8
|
+
static maxLines = 300;
|
|
9
|
+
static compactMinLines = 40;
|
|
10
|
+
static #facetRoots = "{lib,ui,webkit,srvkit,common,plugin}";
|
|
11
|
+
static isAbstractPath(filePath) {
|
|
12
|
+
return filePath.endsWith(AbstractDoc.suffix);
|
|
13
|
+
}
|
|
14
|
+
static lineCountOf(content) {
|
|
15
|
+
return content.split(/\r?\n/).length;
|
|
16
|
+
}
|
|
17
|
+
static kindOf(filePath) {
|
|
18
|
+
const [root, folder, ...rest] = filePath.split("/");
|
|
19
|
+
if (root !== "lib" || !folder)
|
|
20
|
+
return "other";
|
|
21
|
+
if (folder === "__scalar")
|
|
22
|
+
return rest.length === 2 ? "scalar" : "other";
|
|
23
|
+
if (rest.length !== 1)
|
|
24
|
+
return "other";
|
|
25
|
+
return folder.startsWith("_") ? "service" : "domain";
|
|
26
|
+
}
|
|
27
|
+
static async findAll(sys, { module } = {}) {
|
|
28
|
+
const filePaths = (await sys.getAllFiles(`${AbstractDoc.#facetRoots}/**/*${AbstractDoc.suffix}`)).sort();
|
|
29
|
+
const docs = await Promise.all(filePaths.map((filePath) => AbstractDoc.read(sys, filePath)));
|
|
30
|
+
if (!module)
|
|
31
|
+
return docs;
|
|
32
|
+
return docs.filter((doc) => doc.moduleName === module || doc.folderName === module);
|
|
33
|
+
}
|
|
34
|
+
static async read(sys, filePath) {
|
|
35
|
+
const dirPath = filePath.split("/").slice(0, -1).join("/");
|
|
36
|
+
const [content, folderFiles] = await Promise.all([sys.readFile(filePath), sys.readdir(dirPath)]);
|
|
37
|
+
return new AbstractDoc(filePath, content, folderFiles.filter((fileName) => !AbstractDoc.isAbstractPath(fileName)));
|
|
38
|
+
}
|
|
39
|
+
constructor(path, content, siblingFiles) {
|
|
40
|
+
this.path = path;
|
|
41
|
+
this.content = content;
|
|
42
|
+
this.siblingFiles = siblingFiles;
|
|
43
|
+
}
|
|
44
|
+
get kind() {
|
|
45
|
+
return AbstractDoc.kindOf(this.path);
|
|
46
|
+
}
|
|
47
|
+
get folderName() {
|
|
48
|
+
return this.path.split("/").at(-2) ?? "";
|
|
49
|
+
}
|
|
50
|
+
get moduleName() {
|
|
51
|
+
return (this.path.split("/").at(-1) ?? "").slice(0, -AbstractDoc.suffix.length);
|
|
52
|
+
}
|
|
53
|
+
get lineCount() {
|
|
54
|
+
return AbstractDoc.lineCountOf(this.content);
|
|
55
|
+
}
|
|
56
|
+
canReplaceWith(candidate) {
|
|
57
|
+
const next = candidate.trim();
|
|
58
|
+
if (!next.startsWith("#"))
|
|
59
|
+
return false;
|
|
60
|
+
const lineCount = AbstractDoc.lineCountOf(next);
|
|
61
|
+
return lineCount >= 3 && lineCount < this.lineCount;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { AbstractDoc };
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
import {
|
|
3
3
|
workflowRunArtifactPath,
|
|
4
4
|
workflowSyncDir
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-4zgs8g1w.js";
|
|
6
6
|
import {
|
|
7
7
|
AppExecutor,
|
|
8
8
|
LibExecutor
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-jtm86byd.js";
|
|
10
|
+
import {
|
|
11
|
+
collectRecipeSources,
|
|
12
|
+
findInlineRecipeDuplicates,
|
|
13
|
+
scanRecipes
|
|
14
|
+
} from "./index-xys926f2.js";
|
|
10
15
|
import {
|
|
11
16
|
FileSys
|
|
12
17
|
} from "./index-67546d0j.js";
|
|
@@ -146,6 +151,8 @@ var moduleShapeFiles = (module) => {
|
|
|
146
151
|
};
|
|
147
152
|
var constantFieldNames = (content) => [...content.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*field\(/g)].map((match) => match[1]).filter(Boolean);
|
|
148
153
|
var appRootAllowFiles = new Set([
|
|
154
|
+
"AGENTS.md",
|
|
155
|
+
"CLAUDE.md",
|
|
149
156
|
"akan.app.json",
|
|
150
157
|
"akan.config.ts",
|
|
151
158
|
"capacitor.config.ts",
|
|
@@ -461,6 +468,97 @@ class AkanContextAnalyzer {
|
|
|
461
468
|
}
|
|
462
469
|
}
|
|
463
470
|
}
|
|
471
|
+
for (const sys of [...context.apps, ...context.libs]) {
|
|
472
|
+
const sources = await collectRecipeSources(path.join(workspace.workspaceRoot, sys.path, "ui"), "ui");
|
|
473
|
+
if (sources.length === 0)
|
|
474
|
+
continue;
|
|
475
|
+
const recipes = scanRecipes(sources);
|
|
476
|
+
const files = [];
|
|
477
|
+
const glob = new Bun.Glob("**/*.tsx");
|
|
478
|
+
for await (const abs of glob.scan({ cwd: path.join(workspace.workspaceRoot, sys.path), absolute: true })) {
|
|
479
|
+
if (/[\\/](node_modules|\.akan|dist)[\\/]|[\\/]v1[\\/]/.test(abs) || /\.(test|spec)\.tsx$/.test(abs))
|
|
480
|
+
continue;
|
|
481
|
+
files.push({
|
|
482
|
+
path: abs,
|
|
483
|
+
content: await Bun.file(abs).text().catch(() => "")
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
const duplicates = findInlineRecipeDuplicates(recipes, files);
|
|
487
|
+
if (duplicates.length === 0)
|
|
488
|
+
continue;
|
|
489
|
+
const preview = duplicates.slice(0, 3).map((duplicate) => `${path.relative(workspace.workspaceRoot, duplicate.path)}:${duplicate.line}`).join(", ");
|
|
490
|
+
diagnostics.push({
|
|
491
|
+
severity: "warning",
|
|
492
|
+
code: "recipe-inline-duplicate",
|
|
493
|
+
path: path.join(sys.path, "ui/Recipe"),
|
|
494
|
+
message: `${sys.name}: ${duplicates.length} inline className(s) re-author a recipe fingerprint (${preview}${duplicates.length > 3 ? ", \u2026" : ""}) \u2014 consume the recipe instead.`
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
const scanNames = async (uiDirPath, basename) => new Set(scanRecipes(await collectRecipeSources(uiDirPath, "ui", basename)).map((info) => info.name));
|
|
498
|
+
const declaredByImport = new Map;
|
|
499
|
+
declaredByImport.set("akanjs/ui", await scanNames(path.join(workspace.workspaceRoot, "pkgs/akanjs/ui"), "recipe"));
|
|
500
|
+
for (const sys of [...context.apps, ...context.libs])
|
|
501
|
+
declaredByImport.set(`@${sys.path}/ui`, await scanNames(path.join(workspace.workspaceRoot, sys.path, "ui")));
|
|
502
|
+
const sectionOf = (content, heading) => {
|
|
503
|
+
const match = new RegExp(`^${heading}$`, "m").exec(content);
|
|
504
|
+
if (!match)
|
|
505
|
+
return "";
|
|
506
|
+
const section = content.slice(match.index);
|
|
507
|
+
const sectionEnd = section.indexOf(`
|
|
508
|
+
## `, 1);
|
|
509
|
+
return sectionEnd === -1 ? section : section.slice(0, sectionEnd);
|
|
510
|
+
};
|
|
511
|
+
const listedByImport = (body) => {
|
|
512
|
+
const groups = new Map;
|
|
513
|
+
let current = null;
|
|
514
|
+
for (const line of body.split(`
|
|
515
|
+
`)) {
|
|
516
|
+
const group = /^Import from `([^`]+)`:/.exec(line);
|
|
517
|
+
if (group) {
|
|
518
|
+
current = groups.get(group[1]) ?? new Set;
|
|
519
|
+
groups.set(group[1], current);
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const item = /^- `([A-Za-z0-9_$]+)`/.exec(line);
|
|
523
|
+
if (item && current)
|
|
524
|
+
current.add(item[1]);
|
|
525
|
+
else if (!item)
|
|
526
|
+
current = null;
|
|
527
|
+
}
|
|
528
|
+
return groups;
|
|
529
|
+
};
|
|
530
|
+
const pushIndexDiagnostic = (indexPath, missing, stale, repairCommand) => {
|
|
531
|
+
if (missing.length === 0 && stale.length === 0)
|
|
532
|
+
return;
|
|
533
|
+
const action = repairAction("generated", repairCommand, "Regenerate the recipe index from the scanned recipes.", true);
|
|
534
|
+
const parts = [
|
|
535
|
+
missing.length > 0 ? `${missing.length} declared but unlisted (${missing.slice(0, 5).join(", ")})` : "",
|
|
536
|
+
stale.length > 0 ? `${stale.length} listed but gone (${stale.slice(0, 5).join(", ")})` : ""
|
|
537
|
+
].filter(Boolean);
|
|
538
|
+
diagnostics.push({
|
|
539
|
+
severity: "error",
|
|
540
|
+
code: "recipe-index-stale",
|
|
541
|
+
path: indexPath,
|
|
542
|
+
message: `${indexPath} recipe index is out of date \u2014 ${parts.join("; ")}. Agents read this list as authoritative.`,
|
|
543
|
+
repairActions: [action]
|
|
544
|
+
});
|
|
545
|
+
repairActions.push(action);
|
|
546
|
+
};
|
|
547
|
+
const frameworkDeclared = declaredByImport.get("akanjs/ui") ?? new Set;
|
|
548
|
+
if (frameworkDeclared.size > 0) {
|
|
549
|
+
const agentsMd = await Bun.file(path.join(workspace.workspaceRoot, "AGENTS.md")).text().catch(() => "");
|
|
550
|
+
const listed = listedByImport(sectionOf(agentsMd, "## Recipes")).get("akanjs/ui") ?? new Set;
|
|
551
|
+
pushIndexDiagnostic("AGENTS.md", [...frameworkDeclared].filter((name) => !listed.has(name)).sort(), [...listed].filter((name) => !frameworkDeclared.has(name)).sort(), "akan agent install agents-md");
|
|
552
|
+
}
|
|
553
|
+
for (const sys of [...context.apps, ...context.libs]) {
|
|
554
|
+
const own = declaredByImport.get(`@${sys.path}/ui`) ?? new Set;
|
|
555
|
+
const scopeMd = await Bun.file(path.join(workspace.workspaceRoot, sys.path, "AGENTS.md")).text().catch(() => "");
|
|
556
|
+
const groups = listedByImport(sectionOf(scopeMd, "## Recipes In Scope"));
|
|
557
|
+
const ownListed = groups.get(`@${sys.path}/ui`) ?? new Set;
|
|
558
|
+
const missing = [...own].filter((name) => !ownListed.has(name)).sort();
|
|
559
|
+
const stale = [...groups.entries()].flatMap(([importFrom, names]) => [...names].filter((name) => !(declaredByImport.get(importFrom) ?? new Set).has(name))).sort();
|
|
560
|
+
pushIndexDiagnostic(`${sys.path}/AGENTS.md`, missing, stale, `akan sync ${sys.name}`);
|
|
561
|
+
}
|
|
464
562
|
const scopedDiagnostics = diagnostics.map((diagnostic) => ({
|
|
465
563
|
...diagnostic,
|
|
466
564
|
scope: workflowPaths.length ? isWorkflowRelatedDiagnostic(diagnostic, workflowPaths) ? "workflow" : "baseline" : diagnostic.scope,
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
AkanContextAnalyzer
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-4yp06pn1.js";
|
|
5
5
|
import {
|
|
6
6
|
createRepairReport,
|
|
7
7
|
generatedFilePathsForTarget,
|
|
8
8
|
renderRepairReport,
|
|
9
9
|
writeGeneratedSyncState,
|
|
10
10
|
writeWorkflowRunArtifact
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-4zgs8g1w.js";
|
|
12
12
|
import {
|
|
13
13
|
runner
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-jk9q6pse.js";
|
|
15
15
|
|
|
16
16
|
// pkgs/@akanjs/cli/repair/repair.runner.ts
|
|
17
17
|
var commandForShell = (command) => command.startsWith("akan ") ? `bun run ${command}` : command;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
AkanContextAnalyzer
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-4yp06pn1.js";
|
|
5
5
|
import {
|
|
6
6
|
WorkflowExecutor,
|
|
7
7
|
compactWorkflowInputs,
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
workflowCommandsForPlan,
|
|
24
24
|
workflowPlanApproval,
|
|
25
25
|
writeWorkflowRunArtifact
|
|
26
|
-
} from "./index-
|
|
26
|
+
} from "./index-4zgs8g1w.js";
|
|
27
27
|
import {
|
|
28
28
|
runner
|
|
29
|
-
} from "./index-
|
|
29
|
+
} from "./index-jk9q6pse.js";
|
|
30
30
|
|
|
31
31
|
// pkgs/@akanjs/cli/workflow/workflow.runner.ts
|
|
32
32
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-jk9q6pse.js";
|
|
6
6
|
import {
|
|
7
7
|
PkgExecutor
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-jtm86byd.js";
|
|
9
9
|
import {
|
|
10
10
|
TypeScriptDependencyScanner
|
|
11
11
|
} from "./index-46tjzh6s.js";
|
|
@@ -153,14 +153,13 @@ class PackageRunner extends runner("package") {
|
|
|
153
153
|
const scanner = await TypeScriptDependencyScanner.from(pkg);
|
|
154
154
|
const { npmDeps, npmDevDeps, missingDeps } = await scanner.getPackageBuildDependencies(pkg.name);
|
|
155
155
|
const packageRuntimeDependencies = {
|
|
156
|
-
"@akanjs/devkit": ["
|
|
156
|
+
"@akanjs/devkit": ["tailwind-scrollbar"]
|
|
157
157
|
};
|
|
158
158
|
const packageRuntimeDevDependencies = { akanjs: ["@biomejs/biome", "@types/bun"] };
|
|
159
159
|
if (pkg.name === "@akanjs/cli") {
|
|
160
160
|
const devkitPackageJson = await pkg.workspace.readJson("pkgs/@akanjs/devkit/package.json");
|
|
161
161
|
packageRuntimeDependencies[pkg.name] = [
|
|
162
162
|
...Object.keys(devkitPackageJson.dependencies ?? {}),
|
|
163
|
-
"daisyui",
|
|
164
163
|
"tailwind-scrollbar"
|
|
165
164
|
].filter((dep) => dep !== "akanjs" && dep !== "@akanjs/devkit");
|
|
166
165
|
}
|
|
@@ -4,21 +4,21 @@ import {
|
|
|
4
4
|
} from "./index-76rn3g2c.js";
|
|
5
5
|
import {
|
|
6
6
|
LibraryScript
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-cn24dcqn.js";
|
|
8
8
|
import {
|
|
9
9
|
runner,
|
|
10
10
|
script
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-jk9q6pse.js";
|
|
12
|
+
import {
|
|
13
|
+
HmrWatcher,
|
|
14
|
+
WatchRootResolver
|
|
15
|
+
} from "./index-bjpxzr6s.js";
|
|
12
16
|
import {
|
|
13
17
|
AppExecutor,
|
|
14
18
|
LibExecutor,
|
|
15
19
|
PkgExecutor,
|
|
16
20
|
WorkspaceExecutor
|
|
17
|
-
} from "./index-
|
|
18
|
-
import {
|
|
19
|
-
HmrWatcher,
|
|
20
|
-
WatchRootResolver
|
|
21
|
-
} from "./index-bjpxzr6s.js";
|
|
21
|
+
} from "./index-jtm86byd.js";
|
|
22
22
|
import {
|
|
23
23
|
__require
|
|
24
24
|
} from "./index-r24hmh0q.js";
|
|
@@ -1898,9 +1898,10 @@ function openBrowser(url) {
|
|
|
1898
1898
|
}
|
|
1899
1899
|
|
|
1900
1900
|
// pkgs/@akanjs/cli/application/application.runner.ts
|
|
1901
|
-
var loadBuildRunner = async () => (await import("./applicationBuildRunner-
|
|
1902
|
-
var loadReleasePackager = async () => (await import("./applicationReleasePackager-
|
|
1903
|
-
var loadCapacitorApp = async () => (await import("./capacitorApp-
|
|
1901
|
+
var loadBuildRunner = async () => (await import("./applicationBuildRunner-aq7mb3z6.js")).ApplicationBuildRunner;
|
|
1902
|
+
var loadReleasePackager = async () => (await import("./applicationReleasePackager-yrrhbkv3.js")).ApplicationReleasePackager;
|
|
1903
|
+
var loadCapacitorApp = async () => (await import("./capacitorApp-q3mpmkkz.js")).CapacitorApp;
|
|
1904
|
+
var loadAbstractCompactor = async () => (await import("./abstractCompactor-rk6twzvj.js")).AbstractCompactor;
|
|
1904
1905
|
var loadPrompts = async () => await import("@inquirer/prompts");
|
|
1905
1906
|
|
|
1906
1907
|
class ApplicationRunner extends runner("application") {
|
|
@@ -1978,6 +1979,10 @@ try {
|
|
|
1978
1979
|
async typecheck(app, options = {}) {
|
|
1979
1980
|
await new (await loadBuildRunner())(app).typecheck(options);
|
|
1980
1981
|
}
|
|
1982
|
+
async compact(sys, { module, minLines, interactive } = {}) {
|
|
1983
|
+
const compactor = new (await loadAbstractCompactor())(sys, { minLines, interactive });
|
|
1984
|
+
return await compactor.compactAll({ module });
|
|
1985
|
+
}
|
|
1981
1986
|
async test(exec) {
|
|
1982
1987
|
const isSignalTarget = exec instanceof AppExecutor || exec instanceof LibExecutor;
|
|
1983
1988
|
const preloadPath = isSignalTarget ? await resolveSignalTestPreloadPath(exec) : null;
|
|
@@ -2231,9 +2236,7 @@ ${detail}`
|
|
|
2231
2236
|
const chain = RunnableSequence.from([mainPrompt, chatModel, new StringOutputParser]);
|
|
2232
2237
|
await chain.invoke({ projectName, projectDesc });
|
|
2233
2238
|
spinner.succeed("Loading complete!");
|
|
2234
|
-
//! add path in tsconfig.json
|
|
2235
2239
|
}
|
|
2236
|
-
async testApplication(app) {}
|
|
2237
2240
|
}
|
|
2238
2241
|
|
|
2239
2242
|
// pkgs/@akanjs/cli/application/application.script.ts
|
|
@@ -2331,6 +2334,17 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
2331
2334
|
else
|
|
2332
2335
|
await this.libraryScript.syncLibrary(sys);
|
|
2333
2336
|
}
|
|
2337
|
+
async compact(sys, { module = null, minLines, interactive = false } = {}) {
|
|
2338
|
+
const { scanned, reports } = await this.applicationRunner.compact(sys, { module, minLines, interactive });
|
|
2339
|
+
if (!reports.length) {
|
|
2340
|
+
Logger5.rawLog(`No abstract file long enough to compact in ${sys.name} (${scanned} scanned)`);
|
|
2341
|
+
return;
|
|
2342
|
+
}
|
|
2343
|
+
for (const report of reports)
|
|
2344
|
+
Logger5.rawLog(`${report.status}: ${report.path} (${report.beforeLines} -> ${report.afterLines} lines)`);
|
|
2345
|
+
const compactedNum = reports.filter((report) => report.status === "compacted").length;
|
|
2346
|
+
Logger5.rawLog(`Compacted ${compactedNum}/${reports.length} abstract files in ${sys.name}`);
|
|
2347
|
+
}
|
|
2334
2348
|
async script(app, filename) {
|
|
2335
2349
|
const scriptFilename = filename ?? await this.applicationRunner.getScriptFilename(app);
|
|
2336
2350
|
await app.scanSync();
|
|
@@ -2515,7 +2529,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
2515
2529
|
}
|
|
2516
2530
|
async testApplication(app) {
|
|
2517
2531
|
const spinner = app.spinning("Testing application...");
|
|
2518
|
-
await this.applicationRunner.
|
|
2532
|
+
await this.applicationRunner.test(app);
|
|
2519
2533
|
spinner.succeed(`Application ${app.name} (apps/${app.name}) test is successful`);
|
|
2520
2534
|
}
|
|
2521
2535
|
}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
CloudRunner
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-ktprgc5g.js";
|
|
5
|
+
import {
|
|
6
|
+
PackageScript
|
|
7
|
+
} from "./index-e3qskyt2.js";
|
|
5
8
|
import {
|
|
6
9
|
AiSession,
|
|
7
10
|
CloudApi,
|
|
8
11
|
GlobalConfig
|
|
9
|
-
} from "./index-
|
|
12
|
+
} from "./index-3pgtw35d.js";
|
|
10
13
|
import {
|
|
11
14
|
ApplicationScript
|
|
12
|
-
} from "./index-
|
|
13
|
-
import {
|
|
14
|
-
PackageScript
|
|
15
|
-
} from "./index-z36qzgzp.js";
|
|
15
|
+
} from "./index-ev6rjw9n.js";
|
|
16
16
|
import {
|
|
17
17
|
script
|
|
18
|
-
} from "./index-
|
|
18
|
+
} from "./index-jk9q6pse.js";
|
|
19
19
|
import {
|
|
20
20
|
PkgExecutor
|
|
21
|
-
} from "./index-
|
|
21
|
+
} from "./index-jtm86byd.js";
|
|
22
22
|
|
|
23
23
|
// pkgs/@akanjs/cli/cloud/cloud.script.ts
|
|
24
24
|
import { Logger } from "akanjs/common";
|
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
import {
|
|
3
3
|
pluralizeName
|
|
4
4
|
} from "./index-ss469dec.js";
|
|
5
|
+
import {
|
|
6
|
+
AiSession
|
|
7
|
+
} from "./index-3pgtw35d.js";
|
|
5
8
|
import {
|
|
6
9
|
createPassedPrimitiveReport,
|
|
7
10
|
generatedFilesForSync,
|
|
8
11
|
scalarChangedFiles
|
|
9
|
-
} from "./index-
|
|
12
|
+
} from "./index-4zgs8g1w.js";
|
|
10
13
|
import {
|
|
11
14
|
Prompter
|
|
12
|
-
} from "./index-
|
|
13
|
-
import {
|
|
14
|
-
AiSession
|
|
15
|
-
} from "./index-nsj2ftxj.js";
|
|
15
|
+
} from "./index-xwgm94zr.js";
|
|
16
16
|
import {
|
|
17
17
|
runner,
|
|
18
18
|
script
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-jk9q6pse.js";
|
|
20
20
|
|
|
21
21
|
// pkgs/@akanjs/cli/scalar/scalar.prompt.ts
|
|
22
22
|
import { input } from "@inquirer/prompts";
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
RepairRunner
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-b978vs2e.js";
|
|
5
5
|
import {
|
|
6
6
|
WorkflowRunner
|
|
7
|
-
} from "./index-
|
|
8
|
-
import {
|
|
9
|
-
ScalarScript
|
|
10
|
-
} from "./index-z5v766nx.js";
|
|
7
|
+
} from "./index-csqk9z5j.js";
|
|
11
8
|
import {
|
|
12
9
|
PrimitiveScript
|
|
13
|
-
} from "./index-
|
|
10
|
+
} from "./index-r4w8cry5.js";
|
|
14
11
|
import {
|
|
15
12
|
ModuleScript
|
|
16
|
-
} from "./index-
|
|
13
|
+
} from "./index-vhv3xnjz.js";
|
|
14
|
+
import {
|
|
15
|
+
ScalarScript
|
|
16
|
+
} from "./index-fmgbwsr5.js";
|
|
17
17
|
import {
|
|
18
18
|
isPlaceholderAppId
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-sggm9qkv.js";
|
|
20
20
|
import {
|
|
21
21
|
AkanContextAnalyzer,
|
|
22
22
|
akanMcpInstallConfigPaths,
|
|
@@ -27,17 +27,17 @@ import {
|
|
|
27
27
|
renderDoctorText,
|
|
28
28
|
resourceList,
|
|
29
29
|
upsertCodexMcpServerBlock
|
|
30
|
-
} from "./index-
|
|
30
|
+
} from "./index-4yp06pn1.js";
|
|
31
31
|
import {
|
|
32
32
|
buildAkanModuleContextIndex,
|
|
33
33
|
createWorkflowBaselineSummary,
|
|
34
34
|
createWorkflowStepRegistry,
|
|
35
35
|
jsonText,
|
|
36
36
|
toolingRolloutGate
|
|
37
|
-
} from "./index-
|
|
37
|
+
} from "./index-4zgs8g1w.js";
|
|
38
38
|
import {
|
|
39
39
|
Prompter
|
|
40
|
-
} from "./index-
|
|
40
|
+
} from "./index-xwgm94zr.js";
|
|
41
41
|
import {
|
|
42
42
|
getMobileTargets
|
|
43
43
|
} from "./index-76rn3g2c.js";
|
|
@@ -45,10 +45,10 @@ import {
|
|
|
45
45
|
CommandContainer,
|
|
46
46
|
runner,
|
|
47
47
|
script
|
|
48
|
-
} from "./index-
|
|
48
|
+
} from "./index-jk9q6pse.js";
|
|
49
49
|
import {
|
|
50
50
|
AppExecutor
|
|
51
|
-
} from "./index-
|
|
51
|
+
} from "./index-jtm86byd.js";
|
|
52
52
|
|
|
53
53
|
// pkgs/@akanjs/cli/context/context.script.ts
|
|
54
54
|
import { Logger } from "akanjs/common";
|