@akanjs/cli 3.0.0-alpha.1 → 3.0.0-alpha.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.build-stamp +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/{abstractCompactor-e5yq60qz.js → abstractCompactor-byytxs22.js} +3 -5
- package/{agent.command-yv00p0s0.js → agent.command-v1a4746v.js} +11 -12
- package/{application.command-0qsczf4k.js → application.command-fzdcnzhg.js} +65 -37
- package/{applicationBuildRunner-ct2pxyvw.js → applicationBuildRunner-s4gsk728.js} +28 -24
- package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-28v9vbzk.js} +8 -9
- package/buildBatch.proc.js +12 -13
- package/capacitorApp-8d6d4zkm.js +12 -0
- package/{cloud.command-dxfv18sa.js → cloud.command-wygy2z05.js} +15 -17
- package/commandManifest.json +1 -1
- package/{context.command-8d9e3k6b.js → context.command-4vdt1aqq.js} +19 -22
- package/dependencyScanner-shs82ynp.js +8 -0
- package/devTui-qnf1txdz.js +553 -0
- package/devTuiView-yzct2cq6.js +9 -0
- package/getDirname-dr3jz1xg.js +7 -0
- package/{guideline.command-3jbkxzh6.js → guideline.command-p92dq6ts.js} +16 -17
- package/guidelines/agentRule/agentRule.generate.json +31 -0
- package/guidelines/agentRule/agentRule.instruction.md +533 -0
- package/guidelines/conventions/conventions.generate.json +25 -0
- package/guidelines/conventions/conventions.instruction.md +908 -0
- package/guidelines/cssRule/cssRule.instruction.md +7 -0
- package/guidelines/framework/framework.generate.json +3 -2
- package/guidelines/framework/framework.instruction.md +1 -9
- package/guidelines/mcpRule/mcpRule.generate.json +25 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +217 -0
- package/guidelines/modelStore/modelStore.instruction.md +12 -0
- package/guidelines/modelTemplate/modelTemplate.instruction.md +5 -0
- package/guidelines/queryRule/queryRule.generate.json +31 -0
- package/guidelines/queryRule/queryRule.instruction.md +175 -0
- package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
- package/guidelines/runtimeRule/runtimeRule.instruction.md +220 -0
- package/guidelines/ssrRule/ssrRule.instruction.md +49 -5
- package/guidelines/transportRule/transportRule.generate.json +31 -0
- package/guidelines/transportRule/transportRule.instruction.md +60 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +24 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +263 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +402 -0
- package/incrementalBuilder.proc.js +26 -24
- package/{index-mr5s7mqd.js → index-0amdxycf.js} +8 -8
- package/{index-t3723f99.js → index-1yxtbmbj.js} +111 -42
- package/{index-ej426mcr.js → index-29sxqfaw.js} +65 -38
- package/index-3d9y066c.js +76 -0
- package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
- package/index-5svjba73.js +159 -0
- package/index-6wwzs1bc.js +7 -0
- package/{index-k95xkh4p.js → index-7d6vny25.js} +16 -12
- package/{index-ec09pws3.js → index-8p8p0cf8.js} +14 -14
- package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
- package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
- package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
- package/{index-0cj2zxbm.js → index-c69j78kk.js} +12 -11
- package/{index-rzwcpcc3.js → index-fc1bh0a7.js} +4 -4
- package/{index-7c6k4yvg.js → index-gq44bqjt.js} +58 -25
- package/{index-a00jg8x8.js → index-gtmz74tj.js} +79 -55
- package/{index-tdbas9r0.js → index-h7yw2z9n.js} +7 -7
- package/{index-bjpxzr6s.js → index-hwkygn9s.js} +51 -3
- package/{index-bbkek1bp.js → index-hyywke0f.js} +1 -1
- package/{index-46tjzh6s.js → index-kcxmv48c.js} +29 -29
- package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
- package/{index-pyt2b4nw.js → index-p5neav9b.js} +1129 -1356
- package/{index-67546d0j.js → index-q0y2jq9j.js} +14 -2
- package/{index-bekddz9q.js → index-qkk27bk6.js} +32 -32
- package/{index-hgna5rjy.js → index-qsq3q8fy.js} +1034 -257
- package/{index-2q1f5j9k.js → index-srdssqj7.js} +18 -18
- package/{index-rh16j3c7.js → index-w8kmx1b6.js} +23 -13
- package/{index-nm6wghb6.js → index-yks023mb.js} +13 -13
- package/{index-1pvex4az.js → index-yza7zkpt.js} +94 -61
- package/{index-yzmhasdb.js → index-zmjppp25.js} +57 -57
- package/{index-8hsbnyes.js → index-znynzt5w.js} +100 -30
- package/{index-zasydjxd.js → index-zxgr3s8s.js} +31 -30
- package/{index-e16gnn26.js → index-zz5jyd94.js} +1002 -128
- package/index.js +22 -24
- package/{library.command-ebdj1vnm.js → library.command-s4fszngs.js} +11 -9
- package/{localRegistry.command-gb178ne8.js → localRegistry.command-gyw4da9z.js} +20 -22
- package/{module.command-9c1bnsx4.js → module.command-6n7dwvav.js} +13 -15
- package/{package.command-t93p4jkj.js → package.command-gr82ypnr.js} +8 -9
- package/package.json +5 -7
- package/{page.command-k3k0meh2.js → page.command-7gvgb3jb.js} +7 -8
- package/{primitive.command-de6nktdt.js → primitive.command-tk5ckw38.js} +13 -15
- package/{quality.command-z5kth2wa.js → quality.command-38v81baf.js} +229 -138
- package/recipeScanner-fpagtgc1.js +11 -0
- package/{repair.command-ehf2g112.js → repair.command-5xbwvsxp.js} +12 -13
- package/{routeSourceValidator-cncd92fv.js → routeSourceValidator-ze6x894c.js} +2 -40
- package/{scalar.command-7a2jtv33.js → scalar.command-0epwcr5k.js} +11 -13
- package/subspace.command-e2t36xb2.js +755 -0
- package/templates/app/env/env.client.debug.ts.template +1 -5
- package/templates/app/env/env.client.develop.ts.template +1 -5
- package/templates/app/env/env.client.local.ts.template +1 -5
- package/templates/app/env/env.client.main.ts.template +1 -5
- package/templates/app/env/env.client.testing.ts.template +1 -5
- package/templates/app/env/env.client.type.ts +2 -6
- package/templates/app/env/env.server.debug.ts.template +1 -5
- package/templates/app/env/env.server.develop.ts.template +1 -5
- package/templates/app/env/env.server.local.ts.template +1 -5
- package/templates/app/env/env.server.main.ts.template +1 -5
- package/templates/app/main.ts +3 -1
- package/templates/app/page/styles.css.template +3 -3
- package/templates/appSample/lib/task/task.signal.ts +11 -6
- package/templates/appSample/srvkit/AuthGuard.ts +9 -5
- package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
- package/templates/crudPages/[__model__Id]/edit/page.tsx +6 -6
- package/templates/crudPages/[__model__Id]/page.tsx +10 -13
- package/templates/crudPages/new/page.tsx +6 -6
- package/templates/crudPages/page.tsx +9 -9
- package/templates/crudSinglePage/page.tsx +11 -7
- package/templates/env/_env.server.type.ts +7 -5
- package/templates/lib/db.ts +4 -2
- package/templates/lib/dict.ts +1 -1
- package/templates/lib/sig.ts +5 -1
- package/templates/lib/srv.ts +6 -2
- package/templates/lib/useClient.ts +9 -3
- package/templates/module/__Model__.Util.tsx +1 -1
- package/templates/module/__Model__.Zone.tsx +3 -5
- 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 -948
- package/templates/workspaceRoot/CLAUDE.md.template +19 -0
- package/templates/workspaceRoot/biome.json.template +4 -198
- package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +15 -16
- 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-e0tt0vk2.js → workflow.command-kphbr7eh.js} +21 -23
- package/{workspace.command-fpda0evj.js → workspace.command-j1gatz3d.js} +108 -91
- package/capacitorApp-4r9sm3qg.js +0 -58
- package/dependencyScanner-f6grrep3.js +0 -9
- package/index-mxvakhsm.js +0 -66
- package/index-r24hmh0q.js +0 -4
- package/recipeScanner-tghkzrrt.js +0 -12
- package/templates/libRoot/base/baseLogic.ts +0 -14
- package/templates/libRoot/base/index.ts +0 -8
- package/templates/workspaceRoot/.cursor/rules/akan-page-routing.mdc.template +0 -43
- package/templates/workspaceRoot/.cursor/rules/akan-sync-conventions.mdc.template +0 -33
- package/templates/workspaceRoot/.cursor/rules/application-test-commands.mdc.template +0 -16
- package/templates/workspaceRoot/.cursor/rules/change-scope.mdc.template +0 -12
- package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +0 -18
- package/templates/workspaceRoot/.cursor/rules/coding-comments.mdc.template +0 -25
- package/templates/workspaceRoot/.cursor/rules/coding-style.mdc.template +0 -44
- package/templates/workspaceRoot/.cursor/rules/domain-module-conventions.mdc.template +0 -17
- package/templates/workspaceRoot/.cursor/rules/format-lint.mdc.template +0 -12
- package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +0 -18
- package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +0 -61
- package/templates/workspaceRoot/.cursor/rules/naming-conventions.mdc.template +0 -15
- package/templates/workspaceRoot/.cursor/rules/react-component-style.mdc.template +0 -21
- package/templates/workspaceRoot/.cursor/rules/repo-overview.mdc.template +0 -17
- package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +0 -58
- package/templates/workspaceRoot/.cursor/rules/secrets-and-env.mdc.template +0 -13
- package/templates/workspaceRoot/.cursor/rules/service-signal-conventions.mdc.template +0 -83
- package/templates/workspaceRoot/.cursor/rules/srvkit-adapters-and-guards.mdc.template +0 -50
- package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +0 -59
- package/templates/workspaceRoot/.cursor/rules/typescript-imports.mdc.template +0 -16
- 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,33 +1,45 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
extractBlockVersion,
|
|
4
|
+
readDevkitVersion,
|
|
5
|
+
rootAllowedFiles,
|
|
6
|
+
rootAllowedDirs,
|
|
7
|
+
isScannedRootEntry,
|
|
7
8
|
AppExecutor,
|
|
8
9
|
LibExecutor
|
|
9
|
-
} from "./index-
|
|
10
|
-
import {
|
|
11
|
-
collectRecipeSources,
|
|
12
|
-
findInlineRecipeDuplicates,
|
|
13
|
-
scanRecipes
|
|
14
|
-
} from "./index-xys926f2.js";
|
|
10
|
+
} from "./index-qsq3q8fy.js";
|
|
15
11
|
import {
|
|
16
12
|
FileSys
|
|
17
|
-
} from "./index-
|
|
13
|
+
} from "./index-q0y2jq9j.js";
|
|
14
|
+
import {
|
|
15
|
+
collectRecipeSources2,
|
|
16
|
+
scanRecipes2,
|
|
17
|
+
findInlineRecipeDuplicates2
|
|
18
|
+
} from "./index-by5gpp8x.js";
|
|
19
|
+
import {
|
|
20
|
+
workflowRunArtifactPath,
|
|
21
|
+
workflowSyncDir
|
|
22
|
+
} from "./index-fc1bh0a7.js";
|
|
18
23
|
|
|
19
24
|
// pkgs/@akanjs/devkit/akanContext.ts
|
|
20
25
|
import { readdir } from "fs/promises";
|
|
21
26
|
import path from "path";
|
|
22
27
|
import { capitalize } from "akanjs/common";
|
|
23
|
-
var
|
|
28
|
+
var guidelineResourceUri = (name) => `akan://guidelines/${name}`;
|
|
29
|
+
var staticResourceList = [
|
|
24
30
|
{ uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
|
|
25
|
-
{ uri: "akan://guidelines/framework", name: "Framework guideline", mimeType: "text/markdown" },
|
|
26
|
-
{ uri: "akan://guidelines/modelSignal", name: "Model signal guideline", mimeType: "text/markdown" },
|
|
27
31
|
{ uri: "akan://workspace/summary", name: "Workspace summary", mimeType: "application/json" },
|
|
28
32
|
{ uri: "akan://workspace/apps", name: "Workspace apps", mimeType: "application/json" },
|
|
29
33
|
{ uri: "akan://workspace/modules", name: "Workspace modules", mimeType: "application/json" }
|
|
30
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
|
+
];
|
|
31
43
|
var cursorMcpConfigPath = ".cursor/mcp.json";
|
|
32
44
|
var claudeMcpConfigPath = ".mcp.json";
|
|
33
45
|
var codexMcpConfigPath = ".codex/config.toml";
|
|
@@ -121,7 +133,9 @@ var validationCommands = [
|
|
|
121
133
|
"akan typecheck <app-name>",
|
|
122
134
|
"akan test <app-or-lib-or-pkg>",
|
|
123
135
|
"akan build <app-name>",
|
|
124
|
-
"akan doctor --strict --format json"
|
|
136
|
+
"akan doctor --strict --format json",
|
|
137
|
+
"akan quality scan [--format json]",
|
|
138
|
+
"akan quality ssr [--format json]"
|
|
125
139
|
];
|
|
126
140
|
var unknownGeneratedFilesFreshness = {
|
|
127
141
|
status: "unknown",
|
|
@@ -150,33 +164,6 @@ var moduleShapeFiles = (module) => {
|
|
|
150
164
|
];
|
|
151
165
|
};
|
|
152
166
|
var constantFieldNames = (content) => [...content.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*field\(/g)].map((match) => match[1]).filter(Boolean);
|
|
153
|
-
var appRootAllowFiles = new Set([
|
|
154
|
-
"AGENTS.md",
|
|
155
|
-
"CLAUDE.md",
|
|
156
|
-
"akan.app.json",
|
|
157
|
-
"akan.config.ts",
|
|
158
|
-
"capacitor.config.ts",
|
|
159
|
-
"client.ts",
|
|
160
|
-
"main.ts",
|
|
161
|
-
"package.json",
|
|
162
|
-
"server.ts",
|
|
163
|
-
"tsconfig.json"
|
|
164
|
-
]);
|
|
165
|
-
var appRootAllowDirs = new Set([
|
|
166
|
-
".akan",
|
|
167
|
-
"android",
|
|
168
|
-
"common",
|
|
169
|
-
"env",
|
|
170
|
-
"ios",
|
|
171
|
-
"lib",
|
|
172
|
-
"page",
|
|
173
|
-
"private",
|
|
174
|
-
"public",
|
|
175
|
-
"script",
|
|
176
|
-
"srvkit",
|
|
177
|
-
"ui",
|
|
178
|
-
"webkit"
|
|
179
|
-
]);
|
|
180
167
|
var safeReadDir = async (dirPath) => {
|
|
181
168
|
try {
|
|
182
169
|
return (await readdir(dirPath, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -389,6 +376,29 @@ class AkanContextAnalyzer {
|
|
|
389
376
|
validationCommands
|
|
390
377
|
};
|
|
391
378
|
}
|
|
379
|
+
static async#agentGuideDrift(workspace) {
|
|
380
|
+
const installed = await readDevkitVersion();
|
|
381
|
+
if (!installed)
|
|
382
|
+
return null;
|
|
383
|
+
const content = await safeReadText(path.join(workspace.workspaceRoot, "AGENTS.md"));
|
|
384
|
+
if (content === null)
|
|
385
|
+
return null;
|
|
386
|
+
const stamped = extractBlockVersion(content);
|
|
387
|
+
if (stamped === installed)
|
|
388
|
+
return null;
|
|
389
|
+
const hint = "Re-render the AGENTS.md managed block from the installed framework release.";
|
|
390
|
+
if (!stamped)
|
|
391
|
+
return {
|
|
392
|
+
code: "agent-guide-unstamped",
|
|
393
|
+
message: `AGENTS.md carries no generated-version stamp, so its conventions may predate @akanjs/devkit ${installed}`,
|
|
394
|
+
hint
|
|
395
|
+
};
|
|
396
|
+
return {
|
|
397
|
+
code: "agent-guide-stale",
|
|
398
|
+
message: `AGENTS.md was generated by @akanjs/devkit ${stamped}, but ${installed} is installed`,
|
|
399
|
+
hint
|
|
400
|
+
};
|
|
401
|
+
}
|
|
392
402
|
static async doctor(workspace, {
|
|
393
403
|
strict = false,
|
|
394
404
|
runIdOrPlan = null,
|
|
@@ -401,23 +411,37 @@ class AkanContextAnalyzer {
|
|
|
401
411
|
repairAction("generated", "akan repair generated --app <app-or-lib>", "Refresh generated Akan files.", true),
|
|
402
412
|
repairAction("format", "akan repair format --target <app-or-lib-or-pkg>", "Run the formatter/linter repair path.", true)
|
|
403
413
|
];
|
|
404
|
-
for (const
|
|
405
|
-
const
|
|
406
|
-
for (const entry of await safeReadDir(
|
|
407
|
-
|
|
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))
|
|
418
|
+
continue;
|
|
419
|
+
const allowed = entry.isDirectory() ? rootAllowedDirs[sys.type].has(entry.name) : rootAllowedFiles[sys.type].has(entry.name);
|
|
408
420
|
if (!allowed) {
|
|
409
|
-
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);
|
|
410
422
|
diagnostics.push({
|
|
411
423
|
severity: "error",
|
|
412
|
-
code:
|
|
413
|
-
path: `${
|
|
414
|
-
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}`,
|
|
415
427
|
repairActions: [action]
|
|
416
428
|
});
|
|
417
429
|
repairActions.push(action);
|
|
418
430
|
}
|
|
419
431
|
}
|
|
420
432
|
}
|
|
433
|
+
const agentDrift = await AkanContextAnalyzer.#agentGuideDrift(workspace);
|
|
434
|
+
if (agentDrift) {
|
|
435
|
+
const action = repairAction("generated", "akan agent install agents-md", agentDrift.hint, true);
|
|
436
|
+
diagnostics.push({
|
|
437
|
+
severity: "warning",
|
|
438
|
+
code: agentDrift.code,
|
|
439
|
+
path: "AGENTS.md",
|
|
440
|
+
message: agentDrift.message,
|
|
441
|
+
repairActions: [action]
|
|
442
|
+
});
|
|
443
|
+
repairActions.push(action);
|
|
444
|
+
}
|
|
421
445
|
for (const sys of [...context.apps, ...context.libs]) {
|
|
422
446
|
for (const module of sys.modules) {
|
|
423
447
|
if (!module.abstract.exists) {
|
|
@@ -469,10 +493,10 @@ class AkanContextAnalyzer {
|
|
|
469
493
|
}
|
|
470
494
|
}
|
|
471
495
|
for (const sys of [...context.apps, ...context.libs]) {
|
|
472
|
-
const sources = await
|
|
496
|
+
const sources = await collectRecipeSources2(path.join(workspace.workspaceRoot, sys.path, "ui"), "ui");
|
|
473
497
|
if (sources.length === 0)
|
|
474
498
|
continue;
|
|
475
|
-
const recipes =
|
|
499
|
+
const recipes = scanRecipes2(sources);
|
|
476
500
|
const files = [];
|
|
477
501
|
const glob = new Bun.Glob("**/*.tsx");
|
|
478
502
|
for await (const abs of glob.scan({ cwd: path.join(workspace.workspaceRoot, sys.path), absolute: true })) {
|
|
@@ -483,7 +507,7 @@ class AkanContextAnalyzer {
|
|
|
483
507
|
content: await Bun.file(abs).text().catch(() => "")
|
|
484
508
|
});
|
|
485
509
|
}
|
|
486
|
-
const duplicates =
|
|
510
|
+
const duplicates = findInlineRecipeDuplicates2(recipes, files);
|
|
487
511
|
if (duplicates.length === 0)
|
|
488
512
|
continue;
|
|
489
513
|
const preview = duplicates.slice(0, 3).map((duplicate) => `${path.relative(workspace.workspaceRoot, duplicate.path)}:${duplicate.line}`).join(", ");
|
|
@@ -494,7 +518,7 @@ class AkanContextAnalyzer {
|
|
|
494
518
|
message: `${sys.name}: ${duplicates.length} inline className(s) re-author a recipe fingerprint (${preview}${duplicates.length > 3 ? ", \u2026" : ""}) \u2014 consume the recipe instead.`
|
|
495
519
|
});
|
|
496
520
|
}
|
|
497
|
-
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));
|
|
498
522
|
const declaredByImport = new Map;
|
|
499
523
|
declaredByImport.set("akanjs/ui", await scanNames(path.join(workspace.workspaceRoot, "pkgs/akanjs/ui"), "recipe"));
|
|
500
524
|
for (const sys of [...context.apps, ...context.libs])
|
|
@@ -609,4 +633,4 @@ class AkanContextAnalyzer {
|
|
|
609
633
|
}
|
|
610
634
|
}
|
|
611
635
|
|
|
612
|
-
export {
|
|
636
|
+
export { buildResourceList, codexMcpConfigPath, akanMcpInstallTargets, akanMcpInstallConfigPaths, createAkanMcpServer, createAkanCodexMcpServerBlock, upsertCodexMcpServerBlock, renderDoctorText, AkanContextAnalyzer };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "./index-
|
|
3
|
+
getDirname2
|
|
4
|
+
} from "./index-6wwzs1bc.js";
|
|
5
5
|
|
|
6
6
|
// pkgs/@akanjs/devkit/prompter.ts
|
|
7
7
|
import fsPromise from "fs/promises";
|
|
8
8
|
import { input, select } from "@inquirer/prompts";
|
|
9
9
|
class Prompter {
|
|
10
10
|
static async#getGuidelineRoot() {
|
|
11
|
-
const dirname =
|
|
11
|
+
const dirname = getDirname2(import.meta.url);
|
|
12
12
|
const candidates = [`${dirname}/guidelines`, `${dirname}/../cli/guidelines`];
|
|
13
13
|
for (const candidate of candidates) {
|
|
14
14
|
try {
|
|
@@ -19,7 +19,6 @@ class Prompter {
|
|
|
19
19
|
return candidates[0];
|
|
20
20
|
}
|
|
21
21
|
static async selectGuideline() {
|
|
22
|
-
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
23
22
|
const guideNames = await Prompter.listGuidelines();
|
|
24
23
|
return await select({
|
|
25
24
|
message: "Select a guideline",
|
|
@@ -37,10 +36,11 @@ class Prompter {
|
|
|
37
36
|
return JSON.parse(guideJson);
|
|
38
37
|
}
|
|
39
38
|
static async getInstruction(guideName) {
|
|
39
|
+
const guideNames = await Prompter.listGuidelines();
|
|
40
|
+
if (!guideNames.includes(guideName))
|
|
41
|
+
throw new Error(`Unknown guideline "${guideName}". Available: ${guideNames.join(", ")}`);
|
|
40
42
|
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
41
|
-
|
|
42
|
-
const content = await fsPromise.readFile(filePath, "utf-8");
|
|
43
|
-
return content;
|
|
43
|
+
return await fsPromise.readFile(`${guidelineRoot}/${guideName}/${guideName}.instruction.md`, "utf-8");
|
|
44
44
|
}
|
|
45
45
|
static async getUpdateRequest(guideName) {
|
|
46
46
|
return await input({
|
|
@@ -422,7 +422,7 @@ class HmrWatcher {
|
|
|
422
422
|
this.#unreportedChanges += unreported;
|
|
423
423
|
if (!this.#reportedCompensating) {
|
|
424
424
|
this.#reportedCompensating = true;
|
|
425
|
-
this.#logger.
|
|
425
|
+
this.#logger.verbose(`[hmr] recovered ${unreported} change(s) that fs.watch did not report; Bun coalesces concurrent saves and drops all but one, so changes are resolved by mtime`);
|
|
426
426
|
}
|
|
427
427
|
this.#logger.verbose(`[hmr] mtime scan found ${unreported} change(s) fs.watch never reported (${this.#unreportedChanges} total)`);
|
|
428
428
|
}
|
|
@@ -463,6 +463,7 @@ class HmrWatcher {
|
|
|
463
463
|
|
|
464
464
|
// pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
|
|
465
465
|
import fs2 from "fs";
|
|
466
|
+
import { readFile } from "fs/promises";
|
|
466
467
|
import path4 from "path";
|
|
467
468
|
|
|
468
469
|
class WatchRootResolver {
|
|
@@ -472,6 +473,10 @@ class WatchRootResolver {
|
|
|
472
473
|
}
|
|
473
474
|
async resolve() {
|
|
474
475
|
const tsconfig = await this.#app.getTsConfig();
|
|
476
|
+
const appDir = path4.resolve(this.#app.cwdPath);
|
|
477
|
+
const appsContainer = path4.dirname(appDir);
|
|
478
|
+
const libsContainer = path4.resolve(this.#app.workspace.workspaceRoot, "libs");
|
|
479
|
+
const libRoots = await this.#resolveLibRoots(libsContainer);
|
|
475
480
|
const set = new Set;
|
|
476
481
|
set.add(path4.resolve(`${this.#app.cwdPath}/page`));
|
|
477
482
|
for (const targets of Object.values(tsconfig.compilerOptions.paths ?? {})) {
|
|
@@ -482,12 +487,55 @@ class WatchRootResolver {
|
|
|
482
487
|
continue;
|
|
483
488
|
const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
|
|
484
489
|
const resolved = path4.resolve(this.#app.workspace.workspaceRoot, cleaned);
|
|
485
|
-
if (
|
|
486
|
-
|
|
490
|
+
if (resolved === libsContainer && libRoots) {
|
|
491
|
+
for (const root of libRoots)
|
|
492
|
+
set.add(root);
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
const root = resolved === appsContainer ? appDir : resolved;
|
|
496
|
+
if (fs2.existsSync(root))
|
|
497
|
+
set.add(root);
|
|
487
498
|
}
|
|
488
499
|
}
|
|
489
500
|
return [...set];
|
|
490
501
|
}
|
|
502
|
+
async#resolveLibRoots(libsContainer) {
|
|
503
|
+
const libDeps = await this.#resolveLibDeps(libsContainer);
|
|
504
|
+
if (!libDeps)
|
|
505
|
+
return null;
|
|
506
|
+
return libDeps.map((name) => path4.join(libsContainer, name)).filter((dir) => fs2.existsSync(dir));
|
|
507
|
+
}
|
|
508
|
+
async#resolveLibDeps(libsContainer) {
|
|
509
|
+
const scanInfo = this.#app.getScanInfo({ allowEmpty: true });
|
|
510
|
+
if (scanInfo?.type === "app")
|
|
511
|
+
return scanInfo.libDeps;
|
|
512
|
+
const direct = await WatchRootResolver.#readManifestLibDeps(path4.join(this.#app.cwdPath, "akan.app.json"));
|
|
513
|
+
if (!direct)
|
|
514
|
+
return null;
|
|
515
|
+
const closure = new Set;
|
|
516
|
+
const queue = [...direct];
|
|
517
|
+
while (queue.length > 0) {
|
|
518
|
+
const name = queue.shift();
|
|
519
|
+
if (!name || closure.has(name))
|
|
520
|
+
continue;
|
|
521
|
+
closure.add(name);
|
|
522
|
+
const nested = await WatchRootResolver.#readManifestLibDeps(path4.join(libsContainer, name, "akan.lib.json"));
|
|
523
|
+
if (!nested)
|
|
524
|
+
return null;
|
|
525
|
+
queue.push(...nested);
|
|
526
|
+
}
|
|
527
|
+
return [...closure];
|
|
528
|
+
}
|
|
529
|
+
static async#readManifestLibDeps(manifestPath) {
|
|
530
|
+
try {
|
|
531
|
+
const parsed = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
532
|
+
if (!Array.isArray(parsed.libDeps))
|
|
533
|
+
return null;
|
|
534
|
+
return parsed.libDeps.filter((name) => typeof name === "string" && name.length > 0);
|
|
535
|
+
} catch {
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
491
539
|
}
|
|
492
540
|
|
|
493
541
|
export { HmrWatcher, WatchRootResolver };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
FileSys
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-q0y2jq9j.js";
|
|
5
5
|
|
|
6
6
|
// pkgs/@akanjs/devkit/dependencyScanner.ts
|
|
7
7
|
import { builtinModules } from "module";
|
|
@@ -9,39 +9,41 @@ import * as path from "path";
|
|
|
9
9
|
import ignore from "ignore";
|
|
10
10
|
import ts from "typescript";
|
|
11
11
|
var testFileRegex = /\.(?:test|spec)\.[cm]?[tj]sx?$/;
|
|
12
|
+
var skipDirs = ["node_modules", "dist", "build", ".git", ".next", "public", "ios", "android", "__fixtures__"];
|
|
13
|
+
var isSkippedPath = (filePath) => skipDirs.some((dir) => filePath.includes(`/${dir}/`) || filePath.startsWith(`${dir}/`));
|
|
12
14
|
var builtinModuleSet = new Set([...builtinModules, ...builtinModules.map((mod) => `node:${mod}`)]);
|
|
13
15
|
var stripShebang = (source) => source.replace(/^#!.*(?:\r?\n|$)/, "");
|
|
14
16
|
|
|
15
|
-
class
|
|
17
|
+
class TypeScriptDependencyScanner2 {
|
|
16
18
|
#fileDependencies = new Map;
|
|
17
19
|
#fileRuntimeDependencies = new Map;
|
|
18
20
|
#fileTypeDependencies = new Map;
|
|
19
21
|
#visitedFiles = new Set;
|
|
20
22
|
#tsTranspiler = new Bun.Transpiler({ loader: "ts" });
|
|
21
23
|
#tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
|
|
22
|
-
directory;
|
|
23
|
-
rootPackageJson;
|
|
24
|
-
ig;
|
|
25
|
-
workspaceRoot;
|
|
24
|
+
#directory;
|
|
25
|
+
#rootPackageJson;
|
|
26
|
+
#ig;
|
|
27
|
+
#workspaceRoot;
|
|
26
28
|
constructor(directory, {
|
|
27
29
|
workspaceRoot,
|
|
28
30
|
rootPackageJson,
|
|
29
31
|
gitignorePatterns = []
|
|
30
32
|
}) {
|
|
31
|
-
this
|
|
32
|
-
this
|
|
33
|
-
this
|
|
34
|
-
this
|
|
33
|
+
this.#directory = directory;
|
|
34
|
+
this.#rootPackageJson = rootPackageJson;
|
|
35
|
+
this.#ig = ignore().add(gitignorePatterns);
|
|
36
|
+
this.#workspaceRoot = workspaceRoot;
|
|
35
37
|
}
|
|
36
38
|
async getMonorepoDependencies(projectName, { pkgs = [], libs = [] } = {}) {
|
|
37
|
-
const npmSet = new Set(Object.keys({ ...this
|
|
39
|
+
const npmSet = new Set(Object.keys({ ...this.#rootPackageJson.dependencies, ...this.#rootPackageJson.devDependencies }));
|
|
38
40
|
const pkgPathSet = new Set(pkgs);
|
|
39
41
|
const libPathSet = new Set(libs.map((lib) => `@libs/${lib}`));
|
|
40
42
|
await this.getDependencies();
|
|
41
43
|
const [npmDepSet, pkgPathDepSet, libPathDepSet] = this.#getImportSetsFromDependencies([npmSet, pkgPathSet, libPathSet], this.#fileRuntimeDependencies);
|
|
42
44
|
const [npmDevDepSet] = this.#getImportSetsFromDependencies([npmSet], this.#fileTypeDependencies);
|
|
43
45
|
const pkgDeps = [...pkgPathDepSet];
|
|
44
|
-
const libDeps = [...libPathDepSet].map((
|
|
46
|
+
const libDeps = [...libPathDepSet].map((path) => path.replace("@libs/", "")).filter((libName) => libName !== projectName);
|
|
45
47
|
return {
|
|
46
48
|
pkgDeps,
|
|
47
49
|
libDeps,
|
|
@@ -52,11 +54,11 @@ class TypeScriptDependencyScanner {
|
|
|
52
54
|
async getPackageBuildDependencies(projectName) {
|
|
53
55
|
const runtimeDeps = new Set;
|
|
54
56
|
const devDeps = new Set;
|
|
55
|
-
const sourceFiles = await this.#findTypeScriptFiles(this
|
|
57
|
+
const sourceFiles = await this.#findTypeScriptFiles(this.#directory, {
|
|
56
58
|
excludeBuildFiles: true,
|
|
57
59
|
excludeTestFiles: true
|
|
58
60
|
});
|
|
59
|
-
const cssFiles = await this.#findCssFiles(this
|
|
61
|
+
const cssFiles = await this.#findCssFiles(this.#directory);
|
|
60
62
|
for (const filePath of sourceFiles) {
|
|
61
63
|
const fileContent = await FileSys.readText(filePath);
|
|
62
64
|
const { imports, typeImports } = this.#extractImports(fileContent, filePath);
|
|
@@ -67,7 +69,7 @@ class TypeScriptDependencyScanner {
|
|
|
67
69
|
const fileContent = await FileSys.readText(filePath);
|
|
68
70
|
this.#addNormalizedImports(runtimeDeps, this.#extractCssPluginImports(fileContent), projectName);
|
|
69
71
|
}
|
|
70
|
-
const buildFilePath = path.join(this
|
|
72
|
+
const buildFilePath = path.join(this.#directory, "build.ts");
|
|
71
73
|
if (await FileSys.fileExists(buildFilePath)) {
|
|
72
74
|
const fileContent = await FileSys.readText(buildFilePath);
|
|
73
75
|
const { imports, typeImports } = this.#extractImports(fileContent, buildFilePath);
|
|
@@ -75,7 +77,7 @@ class TypeScriptDependencyScanner {
|
|
|
75
77
|
}
|
|
76
78
|
for (const dep of runtimeDeps)
|
|
77
79
|
devDeps.delete(dep);
|
|
78
|
-
const rootDeps = { ...this
|
|
80
|
+
const rootDeps = { ...this.#rootPackageJson.dependencies, ...this.#rootPackageJson.devDependencies };
|
|
79
81
|
const missingDeps = [];
|
|
80
82
|
for (const dep of [...runtimeDeps, ...devDeps]) {
|
|
81
83
|
if (rootDeps[dep] || await this.#hasWorkspacePackage(dep))
|
|
@@ -89,7 +91,7 @@ class TypeScriptDependencyScanner {
|
|
|
89
91
|
};
|
|
90
92
|
}
|
|
91
93
|
async#hasWorkspacePackage(dep) {
|
|
92
|
-
const packageJsonPath = path.join(this
|
|
94
|
+
const packageJsonPath = path.join(this.#workspaceRoot, "pkgs", dep, "package.json");
|
|
93
95
|
if (!await Bun.file(packageJsonPath).exists())
|
|
94
96
|
return false;
|
|
95
97
|
try {
|
|
@@ -132,9 +134,9 @@ class TypeScriptDependencyScanner {
|
|
|
132
134
|
this.#fileRuntimeDependencies.clear();
|
|
133
135
|
this.#fileTypeDependencies.clear();
|
|
134
136
|
this.#visitedFiles.clear();
|
|
135
|
-
const files = await this.#findTypeScriptFiles(this
|
|
137
|
+
const files = await this.#findTypeScriptFiles(this.#directory);
|
|
136
138
|
for (const file of files)
|
|
137
|
-
await this.#analyzeFile(file, this
|
|
139
|
+
await this.#analyzeFile(file, this.#directory);
|
|
138
140
|
return this.#fileDependencies;
|
|
139
141
|
}
|
|
140
142
|
async#findTypeScriptFiles(directory, {
|
|
@@ -142,18 +144,17 @@ class TypeScriptDependencyScanner {
|
|
|
142
144
|
excludeTestFiles = false
|
|
143
145
|
} = {}) {
|
|
144
146
|
const files = [];
|
|
145
|
-
const skipDirs = ["node_modules", "dist", "build", ".git", ".next", "public", "ios", "android"];
|
|
146
147
|
const glob = new Bun.Glob("**/*.{ts,tsx}");
|
|
147
148
|
for await (const filePath of glob.scan({ cwd: directory, onlyFiles: true })) {
|
|
148
|
-
if (
|
|
149
|
+
if (isSkippedPath(filePath))
|
|
149
150
|
continue;
|
|
150
151
|
if (excludeBuildFiles && filePath === "build.ts")
|
|
151
152
|
continue;
|
|
152
153
|
if (excludeTestFiles && testFileRegex.test(filePath))
|
|
153
154
|
continue;
|
|
154
155
|
const fullPath = path.join(directory, filePath);
|
|
155
|
-
const relativePath = path.relative(this
|
|
156
|
-
if (this
|
|
156
|
+
const relativePath = path.relative(this.#workspaceRoot, fullPath);
|
|
157
|
+
if (this.#ig.ignores(relativePath))
|
|
157
158
|
continue;
|
|
158
159
|
files.push(fullPath);
|
|
159
160
|
}
|
|
@@ -161,14 +162,13 @@ class TypeScriptDependencyScanner {
|
|
|
161
162
|
}
|
|
162
163
|
async#findCssFiles(directory) {
|
|
163
164
|
const files = [];
|
|
164
|
-
const skipDirs = ["node_modules", "dist", "build", ".git", ".next", "public", "ios", "android"];
|
|
165
165
|
const glob = new Bun.Glob("**/*.css");
|
|
166
166
|
for await (const filePath of glob.scan({ cwd: directory, onlyFiles: true })) {
|
|
167
|
-
if (
|
|
167
|
+
if (isSkippedPath(filePath))
|
|
168
168
|
continue;
|
|
169
169
|
const fullPath = path.join(directory, filePath);
|
|
170
|
-
const relativePath = path.relative(this
|
|
171
|
-
if (this
|
|
170
|
+
const relativePath = path.relative(this.#workspaceRoot, fullPath);
|
|
171
|
+
if (this.#ig.ignores(relativePath))
|
|
172
172
|
continue;
|
|
173
173
|
files.push(fullPath);
|
|
174
174
|
}
|
|
@@ -289,7 +289,7 @@ class TypeScriptDependencyScanner {
|
|
|
289
289
|
exec.workspace.getPackageJson(),
|
|
290
290
|
exec.workspace.getGitignorePatterns()
|
|
291
291
|
]);
|
|
292
|
-
return new
|
|
292
|
+
return new TypeScriptDependencyScanner2(exec.cwdPath, {
|
|
293
293
|
workspaceRoot: exec.workspace.cwdPath,
|
|
294
294
|
tsconfig,
|
|
295
295
|
rootPackageJson,
|
|
@@ -298,4 +298,4 @@ class TypeScriptDependencyScanner {
|
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
export {
|
|
301
|
+
export { TypeScriptDependencyScanner2 };
|
|
@@ -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;
|