@akanjs/cli 2.4.2-rc.2 → 2.4.2-rc.3
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-ghh1q9an.js +103 -0
- package/{agent.command-ej4g9pbb.js → agent.command-de4r6vk8.js} +1 -1
- package/{application.command-smn51a28.js → application.command-nfsfm96y.js} +11 -1
- package/{cloud.command-2v7ga38h.js → cloud.command-1qf95x67.js} +4 -4
- package/commandManifest.json +1 -1
- package/index-0wae5ebk.js +65 -0
- package/{index-panyahn4.js → index-fbv96xaw.js} +17 -3
- package/{index-j3j3qc9j.js → index-h5cvg9z9.js} +1 -1
- package/{index-majzj044.js → index-h6eav7zx.js} +5 -5
- package/{index-40w1kqp1.js → index-zn9rh7sh.js} +1 -0
- package/index.js +6 -6
- package/{localRegistry.command-nmyc5vwv.js → localRegistry.command-84dz000g.js} +5 -5
- package/package.json +2 -2
- package/{quality.command-vap6xegb.js → quality.command-r9cageqb.js} +28 -3
- package/{workspace.command-hq1x5605.js → workspace.command-stv9g4a0.js} +7 -7
package/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
521ade138cb20f2efa62ad3bbf6f52195b7e4717e808fb5a3808f73ede5cb3f0
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
AbstractDoc
|
|
4
|
+
} from "./index-0wae5ebk.js";
|
|
5
|
+
import {
|
|
6
|
+
AiSession
|
|
7
|
+
} from "./index-nsj2ftxj.js";
|
|
8
|
+
import"./index-67546d0j.js";
|
|
9
|
+
import"./index-6pz1j0zj.js";
|
|
10
|
+
import"./index-r24hmh0q.js";
|
|
11
|
+
|
|
12
|
+
// pkgs/@akanjs/devkit/abstractCompactor.ts
|
|
13
|
+
import { Logger } from "akanjs/common";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
class AbstractCompactor {
|
|
16
|
+
static #reviewRequest = `Review the compacted file you just wrote against the original.
|
|
17
|
+
- Did you drop an invariant, a security reason, or a workflow step that the source files cannot show by themselves? Restore it.
|
|
18
|
+
- Did you keep anything that only restates code, scaffold wording, or history? Remove it.
|
|
19
|
+
- Is it in the same language as the original, within the line budget, and one short line per bullet?
|
|
20
|
+
Respond with exactly one \`\`\`markdown code block holding the corrected file and nothing else. If nothing needs to change, repeat the file unchanged.`;
|
|
21
|
+
#sys;
|
|
22
|
+
#minLines;
|
|
23
|
+
#interactive;
|
|
24
|
+
constructor(sys, { minLines = AbstractDoc.compactMinLines, interactive = false } = {}) {
|
|
25
|
+
this.#sys = sys;
|
|
26
|
+
this.#minLines = minLines;
|
|
27
|
+
this.#interactive = interactive;
|
|
28
|
+
}
|
|
29
|
+
async compactAll({ module } = {}) {
|
|
30
|
+
const docs = await AbstractDoc.findAll(this.#sys, { module });
|
|
31
|
+
const targets = docs.filter((doc) => doc.lineCount > this.#minLines);
|
|
32
|
+
const reports = [];
|
|
33
|
+
for (const doc of targets)
|
|
34
|
+
reports.push(await this.compact(doc));
|
|
35
|
+
return { scanned: docs.length, reports };
|
|
36
|
+
}
|
|
37
|
+
async compact(doc) {
|
|
38
|
+
const session = new AiSession("compactAbstract", {
|
|
39
|
+
workspace: this.#sys.workspace,
|
|
40
|
+
cacheKey: `${this.#sys.name}-${doc.moduleName}`
|
|
41
|
+
});
|
|
42
|
+
const approve = !this.#interactive;
|
|
43
|
+
const compacted = await session.editMarkdown(this.#request(doc), { approve });
|
|
44
|
+
const reviewed = await session.editMarkdown(AbstractCompactor.#reviewRequest, { approve });
|
|
45
|
+
const next = [reviewed, compacted].map((candidate) => candidate.trim()).find((candidate) => doc.canReplaceWith(candidate));
|
|
46
|
+
const beforeLines = doc.lineCount;
|
|
47
|
+
if (!next) {
|
|
48
|
+
Logger.rawLog(chalk.yellow(`${doc.path}: the editor returned no shorter abstract, keeping the current file`));
|
|
49
|
+
return { path: doc.path, beforeLines, afterLines: beforeLines, status: "failed" };
|
|
50
|
+
}
|
|
51
|
+
if (next === doc.content.trim())
|
|
52
|
+
return { path: doc.path, beforeLines, afterLines: beforeLines, status: "unchanged" };
|
|
53
|
+
const content = `${next}
|
|
54
|
+
`;
|
|
55
|
+
await this.#sys.writeFile(doc.path, content);
|
|
56
|
+
return { path: doc.path, beforeLines, afterLines: AbstractDoc.lineCountOf(content), status: "compacted" };
|
|
57
|
+
}
|
|
58
|
+
#targetShape(kind) {
|
|
59
|
+
if (kind === "other")
|
|
60
|
+
return " - keep the headings that still carry information and drop the rest; do not impose a new structure";
|
|
61
|
+
return [
|
|
62
|
+
" - `# <name> Abstract` title line",
|
|
63
|
+
" - one declarative sentence naming what this module owns",
|
|
64
|
+
" - `## Rules` \u2014 two to five bullets, each an invariant the code cannot show by itself",
|
|
65
|
+
" - optional `## Workflow` \u2014 the lifecycle as an arrow chain (`draft -> signed -> active`) or a few bullets"
|
|
66
|
+
].join(`
|
|
67
|
+
`);
|
|
68
|
+
}
|
|
69
|
+
#request(doc) {
|
|
70
|
+
return `You are compacting an Akan.js abstract file.
|
|
71
|
+
|
|
72
|
+
An abstract is the summary a coding agent reads before changing a module. Repeated edits have made this one
|
|
73
|
+
bloated, and it has to shrink back to what the source files cannot show by themselves.
|
|
74
|
+
|
|
75
|
+
# Target file
|
|
76
|
+
${this.#sys.type}s/${this.#sys.name}/${doc.path} (${doc.kind} module "${doc.moduleName}", ${doc.lineCount} lines)
|
|
77
|
+
|
|
78
|
+
# Source files in the same folder
|
|
79
|
+
${doc.siblingFiles.join(", ") || "none"}
|
|
80
|
+
|
|
81
|
+
# Current content
|
|
82
|
+
\`\`\`markdown
|
|
83
|
+
${doc.content}
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
# Rules for the compacted file
|
|
87
|
+
- Write it in the SAME language as the current content. Never translate.
|
|
88
|
+
- Keep every invariant, constraint, security reason, and workflow step that the source files cannot show by
|
|
89
|
+
themselves. Merge duplicates instead of dropping either one.
|
|
90
|
+
- Delete what the code already states: field lists, types, labels, signatures, file lists, and imports.
|
|
91
|
+
- Delete scaffold and placeholder wording, changelog or migration history, TODOs, and any instruction about
|
|
92
|
+
reading or updating this file.
|
|
93
|
+
- Never invent a rule that the current content does not state.
|
|
94
|
+
- Keep every bullet to one short line, and stay under ${AbstractDoc.compactMinLines} lines in total.
|
|
95
|
+
- Shape:
|
|
96
|
+
${this.#targetShape(doc.kind)}
|
|
97
|
+
|
|
98
|
+
Respond with exactly one \`\`\`markdown code block holding the whole new file and nothing else.`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
AbstractCompactor
|
|
103
|
+
};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
AbstractDoc
|
|
4
|
+
} from "./index-0wae5ebk.js";
|
|
2
5
|
import {
|
|
3
6
|
ApplicationScript
|
|
4
|
-
} from "./index-
|
|
7
|
+
} from "./index-fbv96xaw.js";
|
|
5
8
|
import {
|
|
6
9
|
getMobileTargetChoices
|
|
7
10
|
} from "./index-76rn3g2c.js";
|
|
@@ -39,6 +42,13 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
|
|
|
39
42
|
sync: target({ desc: "Sync dependencies and configuration for an app or library" }).with(Sys).exec(async function(sys) {
|
|
40
43
|
await this.applicationScript.sync(sys);
|
|
41
44
|
}),
|
|
45
|
+
compact: target({ desc: "Compact the *.abstract.md files of an app or library with the AI editor" }).with(Sys).option("module", String, { desc: "single module to compact", nullable: true }).option("minLines", Number, {
|
|
46
|
+
flag: "n",
|
|
47
|
+
desc: "only compact abstracts longer than this",
|
|
48
|
+
default: AbstractDoc.compactMinLines
|
|
49
|
+
}).option("interactive", Boolean, { desc: "confirm or refine each rewrite", default: false }).exec(async function(sys, module, minLines, interactive) {
|
|
50
|
+
await this.applicationScript.compact(sys, { module, minLines, interactive });
|
|
51
|
+
}),
|
|
42
52
|
script: target({ desc: "Run a custom script in the application" }).with(App).arg("filename", String, { desc: "name of script", nullable: true }).exec(async function(app, filename) {
|
|
43
53
|
await this.applicationScript.script(app, filename);
|
|
44
54
|
}),
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
CloudScript
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
4
|
+
} from "./index-h6eav7zx.js";
|
|
5
|
+
import"./index-h5cvg9z9.js";
|
|
6
|
+
import"./index-z36qzgzp.js";
|
|
6
7
|
import {
|
|
7
8
|
GlobalConfig
|
|
8
9
|
} from "./index-nsj2ftxj.js";
|
|
9
|
-
import"./index-
|
|
10
|
+
import"./index-fbv96xaw.js";
|
|
10
11
|
import"./index-76rn3g2c.js";
|
|
11
12
|
import"./index-s9s0n5fz.js";
|
|
12
|
-
import"./index-z36qzgzp.js";
|
|
13
13
|
import {
|
|
14
14
|
Workspace,
|
|
15
15
|
command
|
package/commandManifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"byCommand":{"create-workspace":"workspace","generate-agent-rules":"workspace","lint":"workspace","lint-all":"workspace","sync-all":"workspace","init":"workspace","agent":"agent","create-application":"application","remove-application":"application","sync":"application","script":"application","console":"application","build":"application","b":"application","typecheck":"application","t":"application","test":"application","build-ios":"application","bi":"application","build-android":"application","ba":"application","start":"application","s":"application","start-ios":"application","si":"application","start-android":"application","sa":"application","release-ios":"application","release-android":"application","release-source":"application","codepush":"application","dbup":"application","dbdown":"application","configure-app":"application","create-library":"library","remove-library":"library","sync-library":"library","install-library":"library","start-registry":"localRegistry","reset-registry":"localRegistry","smoke-registry":"localRegistry","version":"package","create-package":"package","remove-package":"package","sync-package":"package","build-package":"package","verify-dist-package":"package","verify-akan-publish-packages":"package","create-module":"module","remove-module":"module","create-service":"module","create-view":"module","create-unit":"module","create-template":"module","create-crud-page":"page","context":"context","doctor":"context","mcp-install":"context","mcp":"context","mcp-call":"context","login":"cloud","logout":"cloud","set-llm":"cloud","reset-llm":"cloud","ask":"cloud","deploy-akan":"cloud","update":"cloud","download-env":"cloud","upload-env":"cloud","guideline":"guideline","generate-instruction":"guideline","update-instruction":"guideline","generate-document":"guideline","reapply-instruction":"guideline","create-scalar":"scalar","remove-scalar":"scalar","create-ui":"primitive","add-field":"primitive","add-enum-field":"primitive","quality":"quality","repair":"repair","workflow":"workflow"}}
|
|
1
|
+
{"byCommand":{"create-workspace":"workspace","generate-agent-rules":"workspace","lint":"workspace","lint-all":"workspace","sync-all":"workspace","init":"workspace","agent":"agent","create-application":"application","remove-application":"application","sync":"application","compact":"application","script":"application","console":"application","build":"application","b":"application","typecheck":"application","t":"application","test":"application","build-ios":"application","bi":"application","build-android":"application","ba":"application","start":"application","s":"application","start-ios":"application","si":"application","start-android":"application","sa":"application","release-ios":"application","release-android":"application","release-source":"application","codepush":"application","dbup":"application","dbdown":"application","configure-app":"application","create-library":"library","remove-library":"library","sync-library":"library","install-library":"library","start-registry":"localRegistry","reset-registry":"localRegistry","smoke-registry":"localRegistry","version":"package","create-package":"package","remove-package":"package","sync-package":"package","build-package":"package","verify-dist-package":"package","verify-akan-publish-packages":"package","create-module":"module","remove-module":"module","create-service":"module","create-view":"module","create-unit":"module","create-template":"module","create-crud-page":"page","context":"context","doctor":"context","mcp-install":"context","mcp":"context","mcp-call":"context","login":"cloud","logout":"cloud","set-llm":"cloud","reset-llm":"cloud","ask":"cloud","deploy-akan":"cloud","update":"cloud","download-env":"cloud","upload-env":"cloud","guideline":"guideline","generate-instruction":"guideline","update-instruction":"guideline","generate-document":"guideline","reapply-instruction":"guideline","create-scalar":"scalar","remove-scalar":"scalar","create-ui":"primitive","add-field":"primitive","add-enum-field":"primitive","quality":"quality","repair":"repair","workflow":"workflow"}}
|
|
@@ -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 };
|
|
@@ -1901,6 +1901,7 @@ function openBrowser(url) {
|
|
|
1901
1901
|
var loadBuildRunner = async () => (await import("./applicationBuildRunner-554a2vnk.js")).ApplicationBuildRunner;
|
|
1902
1902
|
var loadReleasePackager = async () => (await import("./applicationReleasePackager-pjbxc793.js")).ApplicationReleasePackager;
|
|
1903
1903
|
var loadCapacitorApp = async () => (await import("./capacitorApp-yg9b4ajz.js")).CapacitorApp;
|
|
1904
|
+
var loadAbstractCompactor = async () => (await import("./abstractCompactor-ghh1q9an.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,7 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
CloudRunner
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-h5cvg9z9.js";
|
|
5
|
+
import {
|
|
6
|
+
PackageScript
|
|
7
|
+
} from "./index-z36qzgzp.js";
|
|
5
8
|
import {
|
|
6
9
|
AiSession,
|
|
7
10
|
CloudApi,
|
|
@@ -9,10 +12,7 @@ import {
|
|
|
9
12
|
} from "./index-nsj2ftxj.js";
|
|
10
13
|
import {
|
|
11
14
|
ApplicationScript
|
|
12
|
-
} from "./index-
|
|
13
|
-
import {
|
|
14
|
-
PackageScript
|
|
15
|
-
} from "./index-z36qzgzp.js";
|
|
15
|
+
} from "./index-fbv96xaw.js";
|
|
16
16
|
import {
|
|
17
17
|
script
|
|
18
18
|
} from "./index-d0h48d2f.js";
|
|
@@ -79,6 +79,7 @@ ${sampleCleanup}## Akan Module Abstracts
|
|
|
79
79
|
- Update the abstract when business invariants, workflows, or public behavior change.
|
|
80
80
|
- Do not update the abstract for formatting-only, import-only, or style-only changes.
|
|
81
81
|
- Service modules live in \`lib/_<service>\`, but their abstract file is \`<service>.abstract.md\`.
|
|
82
|
+
- 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
83
|
|
|
83
84
|
## Generated Files
|
|
84
85
|
|
package/index.js
CHANGED
|
@@ -17,20 +17,20 @@ import path from "path";
|
|
|
17
17
|
|
|
18
18
|
// pkgs/@akanjs/cli/commandModules.ts
|
|
19
19
|
var commandModules = {
|
|
20
|
-
workspace: async () => (await import("./workspace.command-
|
|
21
|
-
agent: async () => (await import("./agent.command-
|
|
22
|
-
application: async () => (await import("./application.command-
|
|
20
|
+
workspace: async () => (await import("./workspace.command-stv9g4a0.js")).WorkspaceCommand,
|
|
21
|
+
agent: async () => (await import("./agent.command-de4r6vk8.js")).AgentCommand,
|
|
22
|
+
application: async () => (await import("./application.command-nfsfm96y.js")).ApplicationCommand,
|
|
23
23
|
library: async () => (await import("./library.command-68ah07a3.js")).LibraryCommand,
|
|
24
|
-
localRegistry: async () => (await import("./localRegistry.command-
|
|
24
|
+
localRegistry: async () => (await import("./localRegistry.command-84dz000g.js")).LocalRegistryCommand,
|
|
25
25
|
package: async () => (await import("./package.command-00ncttab.js")).PackageCommand,
|
|
26
26
|
module: async () => (await import("./module.command-t68xhamx.js")).ModuleCommand,
|
|
27
27
|
page: async () => (await import("./page.command-1096s18n.js")).PageCommand,
|
|
28
28
|
context: async () => (await import("./context.command-hhjyjtp7.js")).ContextCommand,
|
|
29
|
-
cloud: async () => (await import("./cloud.command-
|
|
29
|
+
cloud: async () => (await import("./cloud.command-1qf95x67.js")).CloudCommand,
|
|
30
30
|
guideline: async () => (await import("./guideline.command-vj956kfr.js")).GuidelineCommand,
|
|
31
31
|
scalar: async () => (await import("./scalar.command-3kxy3fkh.js")).ScalarCommand,
|
|
32
32
|
primitive: async () => (await import("./primitive.command-02eqpx6t.js")).PrimitiveCommand,
|
|
33
|
-
quality: async () => (await import("./quality.command-
|
|
33
|
+
quality: async () => (await import("./quality.command-r9cageqb.js")).QualityCommand,
|
|
34
34
|
repair: async () => (await import("./repair.command-7dynpnf1.js")).RepairCommand,
|
|
35
35
|
workflow: async () => (await import("./workflow.command-yy0d9gk3.js")).WorkflowCommand
|
|
36
36
|
};
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
import {
|
|
3
3
|
CloudRunner,
|
|
4
4
|
getNpmRegistryUrl
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-h5cvg9z9.js";
|
|
6
|
+
import {
|
|
7
|
+
PackageScript
|
|
8
|
+
} from "./index-z36qzgzp.js";
|
|
6
9
|
import"./index-nsj2ftxj.js";
|
|
7
10
|
import {
|
|
8
11
|
ApplicationScript
|
|
9
|
-
} from "./index-
|
|
12
|
+
} from "./index-fbv96xaw.js";
|
|
10
13
|
import"./index-76rn3g2c.js";
|
|
11
14
|
import"./index-s9s0n5fz.js";
|
|
12
|
-
import {
|
|
13
|
-
PackageScript
|
|
14
|
-
} from "./index-z36qzgzp.js";
|
|
15
15
|
import {
|
|
16
16
|
Workspace,
|
|
17
17
|
command,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/cli",
|
|
3
|
-
"version": "2.4.2-rc.
|
|
3
|
+
"version": "2.4.2-rc.3",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@langchain/openai": "^1.4.6",
|
|
35
35
|
"@tailwindcss/node": "^4.3.0",
|
|
36
36
|
"@trapezedev/project": "^7.1.4",
|
|
37
|
-
"akanjs": "2.4.2-rc.
|
|
37
|
+
"akanjs": "2.4.2-rc.3",
|
|
38
38
|
"chalk": "^5.6.2",
|
|
39
39
|
"commander": "^14.0.3",
|
|
40
40
|
"daisyui": "5.5.23",
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
AbstractDoc
|
|
4
|
+
} from "./index-0wae5ebk.js";
|
|
2
5
|
import {
|
|
3
6
|
Workspace,
|
|
4
7
|
command,
|
|
@@ -87,6 +90,7 @@ var RULE_FIXES = {
|
|
|
87
90
|
"akan.global.duplicate-exported-function-body": "Extract the shared implementation into a single exported helper and import it, instead of copying the body.",
|
|
88
91
|
"akan.file.recommended-max-lines": "Split the file by responsibility \u2014 move Zones, Utils, or subcomponents into sibling files.",
|
|
89
92
|
"akan.file.max-lines": "Break the file into smaller focused modules; keep one primary responsibility per file.",
|
|
93
|
+
"akan.file.abstract-max-lines": "Run `akan compact <app-or-lib>` to rewrite the abstract with the AI editor, keeping only the invariants and workflows the source files cannot show.",
|
|
90
94
|
"akan.file.placeholder-export": "Remove the placeholder export; generated indexes should only re-export real modules.",
|
|
91
95
|
"akan.file.dictionary-stale-text": "Replace the scaffold text with real localized copy for this dictionary entry.",
|
|
92
96
|
"akan.file.global-declaration": "Move the global declaration into an approved low-level integration file (e.g. webkit) and keep it isolated.",
|
|
@@ -108,17 +112,19 @@ function getRuleFix(rule) {
|
|
|
108
112
|
class AkanQualityScanner {
|
|
109
113
|
async scan(workspaceRoot) {
|
|
110
114
|
const targetFiles = await this.#collectTargetFiles(workspaceRoot);
|
|
111
|
-
const sourceFiles = await Promise.all(targetFiles.map((file) => this.#readSourceFile(workspaceRoot, file)));
|
|
115
|
+
const sourceFiles = await Promise.all(targetFiles.filter((file) => !AbstractDoc.isAbstractPath(file)).map((file) => this.#readSourceFile(workspaceRoot, file)));
|
|
116
|
+
const abstractFiles = await Promise.all(targetFiles.filter((file) => AbstractDoc.isAbstractPath(file)).map((file) => this.#readTextFile(workspaceRoot, file)));
|
|
112
117
|
const warnings = [
|
|
113
118
|
...this.#scanGlobalQuality(sourceFiles),
|
|
114
119
|
...sourceFiles.flatMap((sourceFile) => this.#scanSingleFileQuality(sourceFile)),
|
|
115
120
|
...sourceFiles.flatMap((sourceFile) => this.#scanComponentQuality(sourceFile)),
|
|
116
121
|
...sourceFiles.flatMap((sourceFile) => this.#scanConventionQuality(sourceFile)),
|
|
117
|
-
...sourceFiles.flatMap((sourceFile) => this.#scanLayoutQuality(sourceFile))
|
|
122
|
+
...sourceFiles.flatMap((sourceFile) => this.#scanLayoutQuality(sourceFile)),
|
|
123
|
+
...abstractFiles.flatMap((abstractFile) => this.#scanAbstractQuality(abstractFile))
|
|
118
124
|
];
|
|
119
125
|
return {
|
|
120
126
|
workspaceRoot,
|
|
121
|
-
scannedFiles: sourceFiles.length,
|
|
127
|
+
scannedFiles: sourceFiles.length + abstractFiles.length,
|
|
122
128
|
warnings: warnings.map((warning) => ({ ...warning, fix: warning.fix ?? getRuleFix(warning.rule) })).sort(compareWarnings),
|
|
123
129
|
suggestedRules: SUGGESTED_RULES
|
|
124
130
|
};
|
|
@@ -153,6 +159,8 @@ class AkanQualityScanner {
|
|
|
153
159
|
}
|
|
154
160
|
if ((relativePath.endsWith(".ts") || relativePath.endsWith(".tsx")) && !relativePath.endsWith(".d.ts")) {
|
|
155
161
|
files.push(relativePath);
|
|
162
|
+
} else if (AbstractDoc.isAbstractPath(relativePath)) {
|
|
163
|
+
files.push(relativePath);
|
|
156
164
|
}
|
|
157
165
|
}
|
|
158
166
|
}
|
|
@@ -166,6 +174,9 @@ class AkanQualityScanner {
|
|
|
166
174
|
sourceFile: ts.createSourceFile(file, content, ts.ScriptTarget.Latest, true, getScriptKind(file))
|
|
167
175
|
};
|
|
168
176
|
}
|
|
177
|
+
async#readTextFile(workspaceRoot, file) {
|
|
178
|
+
return { file, content: await readFile(path.join(workspaceRoot, file), "utf8") };
|
|
179
|
+
}
|
|
169
180
|
#scanGlobalQuality(sourceFiles) {
|
|
170
181
|
const exportedFunctionLikes = sourceFiles.flatMap((sourceFile) => getExportedFunctionLikes(sourceFile));
|
|
171
182
|
const warnings = [];
|
|
@@ -304,6 +315,20 @@ class AkanQualityScanner {
|
|
|
304
315
|
}
|
|
305
316
|
return warnings;
|
|
306
317
|
}
|
|
318
|
+
#scanAbstractQuality({ file, content }) {
|
|
319
|
+
const lineCount = AbstractDoc.lineCountOf(content);
|
|
320
|
+
if (lineCount <= AbstractDoc.maxLines)
|
|
321
|
+
return [];
|
|
322
|
+
return [
|
|
323
|
+
{
|
|
324
|
+
rule: "akan.file.abstract-max-lines",
|
|
325
|
+
scope: "file",
|
|
326
|
+
severity: "warning",
|
|
327
|
+
file,
|
|
328
|
+
message: `Abstract has ${lineCount} lines. Keep abstracts under ${AbstractDoc.maxLines} lines and compact them periodically.`
|
|
329
|
+
}
|
|
330
|
+
];
|
|
331
|
+
}
|
|
307
332
|
#scanLayoutQuality(sourceFile) {
|
|
308
333
|
const segments = sourceFile.file.split("/");
|
|
309
334
|
const warnings = [];
|
|
@@ -6,7 +6,7 @@ import"./index-7ppn9v4n.js";
|
|
|
6
6
|
import"./index-h971erkm.js";
|
|
7
7
|
import {
|
|
8
8
|
CloudScript
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-h6eav7zx.js";
|
|
10
10
|
import"./index-z5v766nx.js";
|
|
11
11
|
import"./index-acwxfncv.js";
|
|
12
12
|
import"./index-04as43rp.js";
|
|
@@ -15,27 +15,27 @@ import"./index-ss469dec.js";
|
|
|
15
15
|
import"./index-zfp1gz9f.js";
|
|
16
16
|
import {
|
|
17
17
|
AgentScript
|
|
18
|
-
} from "./index-
|
|
18
|
+
} from "./index-zn9rh7sh.js";
|
|
19
19
|
import"./index-v9jqrdd1.js";
|
|
20
20
|
import"./index-pfnh87f9.js";
|
|
21
21
|
import"./index-xftstr5s.js";
|
|
22
22
|
import {
|
|
23
23
|
getLatestPackageVersion,
|
|
24
24
|
getNpmRegistryUrl
|
|
25
|
-
} from "./index-
|
|
25
|
+
} from "./index-h5cvg9z9.js";
|
|
26
|
+
import {
|
|
27
|
+
PackageScript
|
|
28
|
+
} from "./index-z36qzgzp.js";
|
|
26
29
|
import {
|
|
27
30
|
GlobalConfig
|
|
28
31
|
} from "./index-nsj2ftxj.js";
|
|
29
32
|
import {
|
|
30
33
|
ApplicationScript
|
|
31
|
-
} from "./index-
|
|
34
|
+
} from "./index-fbv96xaw.js";
|
|
32
35
|
import"./index-76rn3g2c.js";
|
|
33
36
|
import {
|
|
34
37
|
LibraryScript
|
|
35
38
|
} from "./index-s9s0n5fz.js";
|
|
36
|
-
import {
|
|
37
|
-
PackageScript
|
|
38
|
-
} from "./index-z36qzgzp.js";
|
|
39
39
|
import {
|
|
40
40
|
Exec,
|
|
41
41
|
Workspace,
|