@akanjs/cli 2.2.10-rc.1 → 2.2.11
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/README.md +15 -0
- package/guidelines/moduleOverview/moduleOverview.instruction.md +5 -1
- package/incrementalBuilder.proc.js +532 -253
- package/index.js +1039 -339
- package/package.json +2 -2
- package/templates/__scalar/__model__/__model__.abstract.md +28 -0
- package/templates/module/__model__.abstract.md +28 -0
- package/templates/service/__model__.abstract.md +28 -0
- package/templates/workspaceRoot/.cursor/rules/akan.mdc.template +26 -0
- package/templates/workspaceRoot/AGENTS.md.template +88 -0
package/index.js
CHANGED
|
@@ -1721,6 +1721,10 @@ var rootSignalTestFilePattern = /^[A-Za-z][A-Za-z0-9_-]*\.signal\.(test|spec)\.(
|
|
|
1721
1721
|
var isAllowedTestFile = (filename) => testFilePattern.test(filename);
|
|
1722
1722
|
var isAllowedLibRootFile = (filename) => libRootAllowedFiles.has(filename) || rootSignalTestFilePattern.test(filename);
|
|
1723
1723
|
var getScanPath = (exec, relativePath) => path5.posix.join(`${exec.type}s`, exec.name, relativePath.split(path5.sep).join("/"));
|
|
1724
|
+
var getModuleNameFromPath = (kind, modulePath) => {
|
|
1725
|
+
const dirname = path5.basename(modulePath);
|
|
1726
|
+
return kind === "service" ? dirname.replace(/^_+/, "") : dirname;
|
|
1727
|
+
};
|
|
1724
1728
|
async function assertScanConvention(exec, libRoot) {
|
|
1725
1729
|
const violations = [];
|
|
1726
1730
|
const addViolation = (relativePath, reason) => {
|
|
@@ -1757,6 +1761,7 @@ ${violations.sort().map((violation) => `- ${violation}`).join(`
|
|
|
1757
1761
|
}
|
|
1758
1762
|
async function validateModuleFiles(exec, violations, kind, modulePath) {
|
|
1759
1763
|
const { files, dirs } = await exec.getFilesAndDirs(modulePath);
|
|
1764
|
+
const moduleName = getModuleNameFromPath(kind, modulePath);
|
|
1760
1765
|
dirs.forEach((dirname) => {
|
|
1761
1766
|
violations.push(`${getScanPath(exec, path5.join(modulePath, dirname))}: unsupported module folder`);
|
|
1762
1767
|
});
|
|
@@ -1764,6 +1769,8 @@ async function validateModuleFiles(exec, violations, kind, modulePath) {
|
|
|
1764
1769
|
const filePath = path5.join(modulePath, filename);
|
|
1765
1770
|
if (filename === "index.ts" || filename === "index.tsx" || isAllowedTestFile(filename))
|
|
1766
1771
|
return;
|
|
1772
|
+
if (filename === `${moduleName}.abstract.md`)
|
|
1773
|
+
return;
|
|
1767
1774
|
const uiMatch = filename.match(/\.([A-Z][A-Za-z0-9]*)\.tsx$/);
|
|
1768
1775
|
if (uiMatch) {
|
|
1769
1776
|
const fileType = uiMatch[1];
|
|
@@ -2108,7 +2115,7 @@ class PkgInfo {
|
|
|
2108
2115
|
exec;
|
|
2109
2116
|
name;
|
|
2110
2117
|
scanResult;
|
|
2111
|
-
static async
|
|
2118
|
+
static async scanExecutor(exec) {
|
|
2112
2119
|
const [tsconfig, rootPackageJson] = await Promise.all([exec.getTsConfig(), exec.workspace.getPackageJson()]);
|
|
2113
2120
|
const scanner = await TypeScriptDependencyScanner.from(exec);
|
|
2114
2121
|
const npmSet = new Set(Object.keys({ ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies }));
|
|
@@ -2130,7 +2137,7 @@ class PkgInfo {
|
|
|
2130
2137
|
const existingPkgInfo = PkgInfo.#pkgInfos.get(exec.name);
|
|
2131
2138
|
if (existingPkgInfo && !options.refresh)
|
|
2132
2139
|
return existingPkgInfo;
|
|
2133
|
-
const scanResult = await PkgInfo.
|
|
2140
|
+
const scanResult = await PkgInfo.scanExecutor(exec);
|
|
2134
2141
|
const pkgInfo = new PkgInfo(exec, scanResult);
|
|
2135
2142
|
PkgInfo.#pkgInfos.set(exec.name, pkgInfo);
|
|
2136
2143
|
return pkgInfo;
|
|
@@ -4458,6 +4465,240 @@ class AkanAppHost {
|
|
|
4458
4465
|
this.#builder = null;
|
|
4459
4466
|
}
|
|
4460
4467
|
}
|
|
4468
|
+
// pkgs/@akanjs/devkit/akanContext.ts
|
|
4469
|
+
import { readdir } from "fs/promises";
|
|
4470
|
+
import path10 from "path";
|
|
4471
|
+
import { capitalize as capitalize2 } from "akanjs/common";
|
|
4472
|
+
var generatedFiles = [
|
|
4473
|
+
"cnst.ts",
|
|
4474
|
+
"db.ts",
|
|
4475
|
+
"dict.ts",
|
|
4476
|
+
"option.ts",
|
|
4477
|
+
"sig.ts",
|
|
4478
|
+
"srv.ts",
|
|
4479
|
+
"st.ts",
|
|
4480
|
+
"useClient.ts",
|
|
4481
|
+
"useServer.ts"
|
|
4482
|
+
];
|
|
4483
|
+
var appRootAllowFiles = new Set([
|
|
4484
|
+
"akan.app.json",
|
|
4485
|
+
"akan.config.ts",
|
|
4486
|
+
"capacitor.config.ts",
|
|
4487
|
+
"client.ts",
|
|
4488
|
+
"main.ts",
|
|
4489
|
+
"package.json",
|
|
4490
|
+
"server.ts",
|
|
4491
|
+
"tsconfig.json"
|
|
4492
|
+
]);
|
|
4493
|
+
var appRootAllowDirs = new Set([
|
|
4494
|
+
".akan",
|
|
4495
|
+
"android",
|
|
4496
|
+
"common",
|
|
4497
|
+
"env",
|
|
4498
|
+
"ios",
|
|
4499
|
+
"lib",
|
|
4500
|
+
"page",
|
|
4501
|
+
"private",
|
|
4502
|
+
"public",
|
|
4503
|
+
"script",
|
|
4504
|
+
"srvkit",
|
|
4505
|
+
"ui",
|
|
4506
|
+
"webkit"
|
|
4507
|
+
]);
|
|
4508
|
+
var safeReadDir = async (dirPath) => {
|
|
4509
|
+
try {
|
|
4510
|
+
return (await readdir(dirPath, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
4511
|
+
} catch {
|
|
4512
|
+
return [];
|
|
4513
|
+
}
|
|
4514
|
+
};
|
|
4515
|
+
var safeReadText = async (filePath) => {
|
|
4516
|
+
try {
|
|
4517
|
+
return await FileSys.readText(filePath);
|
|
4518
|
+
} catch {
|
|
4519
|
+
return null;
|
|
4520
|
+
}
|
|
4521
|
+
};
|
|
4522
|
+
var safeReadJson = async (filePath) => {
|
|
4523
|
+
try {
|
|
4524
|
+
return await FileSys.readJson(filePath);
|
|
4525
|
+
} catch {
|
|
4526
|
+
return null;
|
|
4527
|
+
}
|
|
4528
|
+
};
|
|
4529
|
+
var parseAbstractSummary = (relativePath, content, includeContent) => {
|
|
4530
|
+
if (content === null)
|
|
4531
|
+
return { path: relativePath, exists: false, headings: [] };
|
|
4532
|
+
const headings = content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.startsWith("#")).map((line) => line.replace(/^#+\s*/, "").trim()).filter(Boolean);
|
|
4533
|
+
return {
|
|
4534
|
+
path: relativePath,
|
|
4535
|
+
exists: true,
|
|
4536
|
+
title: headings[0],
|
|
4537
|
+
headings: headings.slice(0, 8),
|
|
4538
|
+
...includeContent ? { content } : {}
|
|
4539
|
+
};
|
|
4540
|
+
};
|
|
4541
|
+
var readFiles = async (dirPath) => (await safeReadDir(dirPath)).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
4542
|
+
var getRelative = (workspace, absolutePath) => path10.relative(workspace.workspaceRoot, absolutePath).replaceAll(path10.sep, "/");
|
|
4543
|
+
var createModuleContext = async (workspace, sys2, kind, folderName, moduleName, includeAbstractContent) => {
|
|
4544
|
+
const modulePath = kind === "scalar" ? path10.join(sys2.cwdPath, "lib", "__scalar", moduleName) : path10.join(sys2.cwdPath, "lib", folderName);
|
|
4545
|
+
const relativePath = getRelative(workspace, modulePath);
|
|
4546
|
+
const abstractPath = `${relativePath}/${moduleName}.abstract.md`;
|
|
4547
|
+
const abstractContent = await safeReadText(path10.join(workspace.workspaceRoot, abstractPath));
|
|
4548
|
+
return {
|
|
4549
|
+
kind,
|
|
4550
|
+
name: moduleName,
|
|
4551
|
+
folderName,
|
|
4552
|
+
sysName: sys2.name,
|
|
4553
|
+
sysType: sys2.type,
|
|
4554
|
+
path: relativePath,
|
|
4555
|
+
abstract: parseAbstractSummary(abstractPath, abstractContent, includeAbstractContent),
|
|
4556
|
+
files: await readFiles(modulePath)
|
|
4557
|
+
};
|
|
4558
|
+
};
|
|
4559
|
+
var getSysModules = async (workspace, sys2, {
|
|
4560
|
+
includeAbstractContent = false,
|
|
4561
|
+
module: moduleFilter
|
|
4562
|
+
} = {}) => {
|
|
4563
|
+
const libPath = path10.join(sys2.cwdPath, "lib");
|
|
4564
|
+
const entries = await safeReadDir(libPath);
|
|
4565
|
+
const modules = [];
|
|
4566
|
+
for (const entry of entries) {
|
|
4567
|
+
if (!entry.isDirectory())
|
|
4568
|
+
continue;
|
|
4569
|
+
if (entry.name === "__scalar")
|
|
4570
|
+
continue;
|
|
4571
|
+
if (entry.name.startsWith("__"))
|
|
4572
|
+
continue;
|
|
4573
|
+
if (entry.name.startsWith("_")) {
|
|
4574
|
+
const serviceName = entry.name.replace(/^_+/, "");
|
|
4575
|
+
if (moduleFilter && moduleFilter !== serviceName && moduleFilter !== entry.name)
|
|
4576
|
+
continue;
|
|
4577
|
+
if (!await FileSys.fileExists(path10.join(libPath, entry.name, `${serviceName}.service.ts`)))
|
|
4578
|
+
continue;
|
|
4579
|
+
modules.push(await createModuleContext(workspace, sys2, "service", entry.name, serviceName, includeAbstractContent));
|
|
4580
|
+
} else {
|
|
4581
|
+
if (moduleFilter && moduleFilter !== entry.name)
|
|
4582
|
+
continue;
|
|
4583
|
+
if (!await FileSys.fileExists(path10.join(libPath, entry.name, `${entry.name}.constant.ts`)))
|
|
4584
|
+
continue;
|
|
4585
|
+
modules.push(await createModuleContext(workspace, sys2, "domain", entry.name, entry.name, includeAbstractContent));
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
const scalarRoot = path10.join(libPath, "__scalar");
|
|
4589
|
+
for (const entry of await safeReadDir(scalarRoot)) {
|
|
4590
|
+
if (!entry.isDirectory() || entry.name.startsWith("_"))
|
|
4591
|
+
continue;
|
|
4592
|
+
if (moduleFilter && moduleFilter !== entry.name)
|
|
4593
|
+
continue;
|
|
4594
|
+
if (!await FileSys.fileExists(path10.join(scalarRoot, entry.name, `${entry.name}.constant.ts`)))
|
|
4595
|
+
continue;
|
|
4596
|
+
modules.push(await createModuleContext(workspace, sys2, "scalar", entry.name, entry.name, includeAbstractContent));
|
|
4597
|
+
}
|
|
4598
|
+
return modules.sort((a, b) => `${a.sysName}:${a.path}`.localeCompare(`${b.sysName}:${b.path}`));
|
|
4599
|
+
};
|
|
4600
|
+
var getSysContext = async (workspace, type, name, options) => {
|
|
4601
|
+
const sys2 = type === "app" ? AppExecutor.from(workspace, name) : LibExecutor.from(workspace, name);
|
|
4602
|
+
return {
|
|
4603
|
+
type,
|
|
4604
|
+
name,
|
|
4605
|
+
path: `${type}s/${name}`,
|
|
4606
|
+
hasConfig: await FileSys.fileExists(path10.join(sys2.cwdPath, "akan.config.ts")),
|
|
4607
|
+
modules: await getSysModules(workspace, sys2, {
|
|
4608
|
+
includeAbstractContent: options.includeAbstractContent,
|
|
4609
|
+
module: options.module
|
|
4610
|
+
})
|
|
4611
|
+
};
|
|
4612
|
+
};
|
|
4613
|
+
|
|
4614
|
+
class AkanContextAnalyzer {
|
|
4615
|
+
static async analyze(workspace, options = {}) {
|
|
4616
|
+
const [appNames, libNames, pkgNames] = await workspace.getExecs();
|
|
4617
|
+
const rootPackageJson = await safeReadJson(path10.join(workspace.workspaceRoot, "package.json"));
|
|
4618
|
+
const filteredApps = options.app ? appNames.filter((name) => name === options.app) : appNames;
|
|
4619
|
+
const [apps, libs, pkgs] = await Promise.all([
|
|
4620
|
+
Promise.all(filteredApps.map((name) => getSysContext(workspace, "app", name, options))),
|
|
4621
|
+
Promise.all(libNames.map((name) => getSysContext(workspace, "lib", name, options))),
|
|
4622
|
+
Promise.all(pkgNames.map(async (name) => {
|
|
4623
|
+
const packageJson = await safeReadJson(path10.join(workspace.workspaceRoot, "pkgs", name, "package.json"));
|
|
4624
|
+
return {
|
|
4625
|
+
name,
|
|
4626
|
+
path: `pkgs/${name}`,
|
|
4627
|
+
...packageJson?.version ? { version: packageJson.version } : {}
|
|
4628
|
+
};
|
|
4629
|
+
}))
|
|
4630
|
+
]);
|
|
4631
|
+
return {
|
|
4632
|
+
schemaVersion: 1,
|
|
4633
|
+
repoName: workspace.repoName,
|
|
4634
|
+
root: workspace.workspaceRoot,
|
|
4635
|
+
packageVersion: rootPackageJson?.dependencies?.akanjs ?? rootPackageJson?.devDependencies?.["@akanjs/devkit"],
|
|
4636
|
+
apps,
|
|
4637
|
+
libs,
|
|
4638
|
+
pkgs,
|
|
4639
|
+
generatedFiles,
|
|
4640
|
+
validationCommands: ["akan lint <app-or-lib-or-pkg>", "akan build <app-name>", "akan start <app-name>"]
|
|
4641
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
static async doctor(workspace, { strict = false } = {}) {
|
|
4644
|
+
const context = await AkanContextAnalyzer.analyze(workspace);
|
|
4645
|
+
const diagnostics = [];
|
|
4646
|
+
for (const app of context.apps) {
|
|
4647
|
+
const appPath = path10.join(workspace.workspaceRoot, app.path);
|
|
4648
|
+
for (const entry of await safeReadDir(appPath)) {
|
|
4649
|
+
const allowed = entry.isDirectory() ? appRootAllowDirs.has(entry.name) : appRootAllowFiles.has(entry.name);
|
|
4650
|
+
if (!allowed) {
|
|
4651
|
+
diagnostics.push({
|
|
4652
|
+
severity: "warning",
|
|
4653
|
+
code: "app-root-unknown-entry",
|
|
4654
|
+
path: `${app.path}/${entry.name}`,
|
|
4655
|
+
message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in app root: ${app.path}/${entry.name}`
|
|
4656
|
+
});
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4660
|
+
for (const sys2 of [...context.apps, ...context.libs]) {
|
|
4661
|
+
for (const module of sys2.modules) {
|
|
4662
|
+
if (!module.abstract.exists) {
|
|
4663
|
+
diagnostics.push({
|
|
4664
|
+
severity: strict ? "error" : "warning",
|
|
4665
|
+
code: "module-abstract-missing",
|
|
4666
|
+
path: module.abstract.path,
|
|
4667
|
+
message: `${capitalize2(module.kind)} module ${sys2.name}:${module.name} should include ${module.abstract.path}`
|
|
4668
|
+
});
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
return { schemaVersion: 1, strict, diagnostics };
|
|
4673
|
+
}
|
|
4674
|
+
static findModules(context, moduleName) {
|
|
4675
|
+
const modules = [...context.apps, ...context.libs].flatMap((sys2) => sys2.modules);
|
|
4676
|
+
return moduleName ? modules.filter((module) => module.name === moduleName || module.folderName === moduleName) : modules;
|
|
4677
|
+
}
|
|
4678
|
+
static renderMarkdown(context, { module: moduleName } = {}) {
|
|
4679
|
+
const lines = [`# Akan Workspace Context`, "", `- Repo: ${context.repoName}`, `- Root: ${context.root}`];
|
|
4680
|
+
if (context.packageVersion)
|
|
4681
|
+
lines.push(`- Akan version: ${context.packageVersion}`);
|
|
4682
|
+
lines.push("", "## Apps", ...context.apps.map((app) => `- ${app.name}: ${app.modules.length} module(s)`));
|
|
4683
|
+
lines.push("", "## Libraries", ...context.libs.map((lib) => `- ${lib.name}: ${lib.modules.length} module(s)`));
|
|
4684
|
+
lines.push("", "## Packages", ...context.pkgs.map((pkg) => `- ${pkg.name}${pkg.version ? ` (${pkg.version})` : ""}`));
|
|
4685
|
+
const modules = AkanContextAnalyzer.findModules(context, moduleName);
|
|
4686
|
+
lines.push("", "## Modules");
|
|
4687
|
+
for (const module of modules) {
|
|
4688
|
+
lines.push("", `### ${module.sysName}:${module.name} (${module.kind})`, `- Path: ${module.path}`);
|
|
4689
|
+
lines.push(`- Abstract: ${module.abstract.exists ? module.abstract.path : "missing"}`);
|
|
4690
|
+
if (module.abstract.exists && module.abstract.content)
|
|
4691
|
+
lines.push("", module.abstract.content.trim(), "");
|
|
4692
|
+
else if (module.abstract.headings.length)
|
|
4693
|
+
lines.push(`- Abstract headings: ${module.abstract.headings.join(", ")}`);
|
|
4694
|
+
lines.push(`- Files: ${module.files.join(", ") || "none"}`);
|
|
4695
|
+
}
|
|
4696
|
+
lines.push("", "## Validation", ...context.validationCommands.map((command) => `- \`${command}\``));
|
|
4697
|
+
return `${lines.join(`
|
|
4698
|
+
`)}
|
|
4699
|
+
`;
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4461
4702
|
// pkgs/@akanjs/devkit/applicationBuildReporter.ts
|
|
4462
4703
|
import { Logger as Logger6 } from "akanjs/common";
|
|
4463
4704
|
|
|
@@ -4504,20 +4745,20 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
|
|
|
4504
4745
|
}
|
|
4505
4746
|
// pkgs/@akanjs/devkit/applicationBuildRunner.ts
|
|
4506
4747
|
import { mkdir as mkdir7, rm as rm2 } from "fs/promises";
|
|
4507
|
-
import
|
|
4748
|
+
import path33 from "path";
|
|
4508
4749
|
|
|
4509
4750
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
4510
|
-
import
|
|
4751
|
+
import path20 from "path";
|
|
4511
4752
|
|
|
4512
4753
|
// pkgs/@akanjs/devkit/artifact/implicitRootLayout.ts
|
|
4513
4754
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
4514
|
-
import
|
|
4755
|
+
import path11 from "path";
|
|
4515
4756
|
var LAYOUT_KEY_RE = /^\.\/(.+\/)?_layout\.(tsx|ts|jsx|js)$/;
|
|
4516
4757
|
async function appHasStModule(appCwdPath) {
|
|
4517
|
-
return Bun.file(
|
|
4758
|
+
return Bun.file(path11.join(appCwdPath, "lib", "st.ts")).exists();
|
|
4518
4759
|
}
|
|
4519
|
-
var IMPLICIT_LAYOUT_DIR =
|
|
4520
|
-
var IMPLICIT_DICT_DIR =
|
|
4760
|
+
var IMPLICIT_LAYOUT_DIR = path11.join(".akan", "generated", "root-layouts");
|
|
4761
|
+
var IMPLICIT_DICT_DIR = path11.join(".akan", "generated", "dict");
|
|
4521
4762
|
function getRootBoundarySegments(key) {
|
|
4522
4763
|
const match = LAYOUT_KEY_RE.exec(key);
|
|
4523
4764
|
if (!match)
|
|
@@ -4532,10 +4773,10 @@ function implicitRootLayoutKey(segments) {
|
|
|
4532
4773
|
}
|
|
4533
4774
|
function implicitRootLayoutAbsPath(appCwdPath, segments) {
|
|
4534
4775
|
const filename = segments.length ? `${segments.join("__")}__root_layout.tsx` : "__root_layout.tsx";
|
|
4535
|
-
return
|
|
4776
|
+
return path11.join(path11.resolve(appCwdPath), IMPLICIT_LAYOUT_DIR, filename);
|
|
4536
4777
|
}
|
|
4537
4778
|
function implicitDictionaryMacroAbsPath(appCwdPath) {
|
|
4538
|
-
return
|
|
4779
|
+
return path11.join(path11.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
|
|
4539
4780
|
}
|
|
4540
4781
|
function isRootBoundarySegments(segments, basePaths) {
|
|
4541
4782
|
const firstVisibleIndex = segments.findIndex((segment) => !/^\(.+\)$/.test(segment));
|
|
@@ -4558,7 +4799,7 @@ function findRootBoundaries(pageKeys, appCwdPath, basePaths) {
|
|
|
4558
4799
|
const id = segments.join("/");
|
|
4559
4800
|
boundaries.set(id, {
|
|
4560
4801
|
sourceKey: key,
|
|
4561
|
-
sourceAbsPath:
|
|
4802
|
+
sourceAbsPath: path11.resolve(appCwdPath, "page", key.replace(/^\.\//, "")),
|
|
4562
4803
|
segments
|
|
4563
4804
|
});
|
|
4564
4805
|
}
|
|
@@ -4576,21 +4817,21 @@ function findExplicitRootLayoutAbsPath(pageKeys, appCwdPath) {
|
|
|
4576
4817
|
const segments = getRootBoundarySegments(key);
|
|
4577
4818
|
return segments !== null && segments.length === 0;
|
|
4578
4819
|
});
|
|
4579
|
-
return rootLayoutKey ?
|
|
4820
|
+
return rootLayoutKey ? path11.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
|
|
4580
4821
|
}
|
|
4581
4822
|
function routePrefixForSegments(segments) {
|
|
4582
4823
|
const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
|
|
4583
4824
|
return visible[0] ?? null;
|
|
4584
4825
|
}
|
|
4585
4826
|
async function assertEnvClientConvention(appCwdPath, appName) {
|
|
4586
|
-
const envPath =
|
|
4827
|
+
const envPath = path11.join(appCwdPath, "env", "env.client.ts");
|
|
4587
4828
|
if (!await Bun.file(envPath).exists()) {
|
|
4588
4829
|
throw new Error(`[route-convention] app "${appName}" must provide env/env.client.ts exporting "env" for generated System.Provider`);
|
|
4589
4830
|
}
|
|
4590
4831
|
}
|
|
4591
4832
|
async function writeGeneratedDictionaryMacroFile(appCwdPath, appName) {
|
|
4592
4833
|
const absPath = implicitDictionaryMacroAbsPath(appCwdPath);
|
|
4593
|
-
await mkdir3(
|
|
4834
|
+
await mkdir3(path11.dirname(absPath), { recursive: true });
|
|
4594
4835
|
await Bun.write(absPath, `import { getAllDictionary } from "@apps/${appName}/lib/dict" with { type: "macro" };
|
|
4595
4836
|
|
|
4596
4837
|
export const allDictionary = getAllDictionary();
|
|
@@ -4601,13 +4842,13 @@ async function writeGeneratedRootLayoutFile(opts) {
|
|
|
4601
4842
|
await assertEnvClientConvention(opts.appCwdPath, opts.appName);
|
|
4602
4843
|
const dictMacroAbsPath = opts.includeSystemProvider ? await writeGeneratedDictionaryMacroFile(opts.appCwdPath, opts.appName) : null;
|
|
4603
4844
|
const absPath = implicitRootLayoutAbsPath(opts.appCwdPath, opts.boundary.segments);
|
|
4604
|
-
await mkdir3(
|
|
4605
|
-
const dictMacroRel = dictMacroAbsPath ?
|
|
4845
|
+
await mkdir3(path11.dirname(absPath), { recursive: true });
|
|
4846
|
+
const dictMacroRel = dictMacroAbsPath ? path11.relative(path11.dirname(absPath), dictMacroAbsPath).split(path11.sep).join("/") : null;
|
|
4606
4847
|
const dictMacroSpecifier = dictMacroRel ? dictMacroRel.startsWith(".") ? dictMacroRel : `./${dictMacroRel}` : null;
|
|
4607
|
-
const sourceRel = opts.boundary.sourceAbsPath ?
|
|
4848
|
+
const sourceRel = opts.boundary.sourceAbsPath ? path11.relative(path11.dirname(absPath), opts.boundary.sourceAbsPath).split(path11.sep).join("/") : null;
|
|
4608
4849
|
const sourceSpecifier = sourceRel ? sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}` : null;
|
|
4609
4850
|
const inheritedSourceAbsPath = opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
|
|
4610
|
-
const inheritedSourceRel = inheritedSourceAbsPath ?
|
|
4851
|
+
const inheritedSourceRel = inheritedSourceAbsPath ? path11.relative(path11.dirname(absPath), inheritedSourceAbsPath).split(path11.sep).join("/") : null;
|
|
4611
4852
|
const inheritedSourceSpecifier = inheritedSourceRel ? inheritedSourceRel.startsWith(".") ? inheritedSourceRel : `./${inheritedSourceRel}` : null;
|
|
4612
4853
|
const clientImport = opts.includeStInit ? `import { st } from "@apps/${opts.appName}/client";
|
|
4613
4854
|
void st;
|
|
@@ -4685,7 +4926,7 @@ export default function GeneratedLayout({ children, params, searchParams }: Layo
|
|
|
4685
4926
|
return absPath;
|
|
4686
4927
|
}
|
|
4687
4928
|
async function resolveSsrPageEntries(opts) {
|
|
4688
|
-
const absPageDir =
|
|
4929
|
+
const absPageDir = path11.resolve(opts.appCwdPath, "page");
|
|
4689
4930
|
const hasSt = await appHasStModule(opts.appCwdPath);
|
|
4690
4931
|
const basePaths = opts.basePaths ?? [];
|
|
4691
4932
|
const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
|
|
@@ -4696,7 +4937,7 @@ async function resolveSsrPageEntries(opts) {
|
|
|
4696
4937
|
}));
|
|
4697
4938
|
const base = opts.pageKeys.filter((key) => !rootLayoutKeys.has(key)).map((key) => ({
|
|
4698
4939
|
key,
|
|
4699
|
-
moduleAbsPath:
|
|
4940
|
+
moduleAbsPath: path11.resolve(absPageDir, key)
|
|
4700
4941
|
}));
|
|
4701
4942
|
const generated = await Promise.all(rootBoundaries.map(async (boundary) => ({
|
|
4702
4943
|
key: implicitRootLayoutKey(boundary.segments),
|
|
@@ -4720,14 +4961,14 @@ async function resolveSsrPageEntriesForApp(app, pageKeys) {
|
|
|
4720
4961
|
}
|
|
4721
4962
|
|
|
4722
4963
|
// pkgs/@akanjs/devkit/artifact/routeSeedIndex.ts
|
|
4723
|
-
import
|
|
4964
|
+
import path12 from "path";
|
|
4724
4965
|
import { assertUniqueRoutePatterns, compareRouteSpecificity, parseRouteModuleKey as parseRouteModuleKey2 } from "akanjs/common";
|
|
4725
4966
|
function computeRouteSeedIndex(pageEntries) {
|
|
4726
4967
|
const layoutsByPrefix = new Map;
|
|
4727
4968
|
const pagesBySegments = [];
|
|
4728
4969
|
for (const { key, moduleAbsPath, seedAbsPaths } of pageEntries) {
|
|
4729
4970
|
const parsed = parseRouteModuleKey2(key);
|
|
4730
|
-
const files = [
|
|
4971
|
+
const files = [path12.resolve(moduleAbsPath), ...(seedAbsPaths ?? []).map((seed) => path12.resolve(seed))];
|
|
4731
4972
|
if (parsed.kind === "layout") {
|
|
4732
4973
|
const prefix = parsed.routeSegments.join("/");
|
|
4733
4974
|
const prev = layoutsByPrefix.get(prefix) ?? [];
|
|
@@ -4764,7 +5005,7 @@ function computeRouteSeedIndex(pageEntries) {
|
|
|
4764
5005
|
}
|
|
4765
5006
|
var ROUTE_SEED_INDEX_JSON = "route-seed-index.json";
|
|
4766
5007
|
function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
4767
|
-
const normalizedArtifactDir =
|
|
5008
|
+
const normalizedArtifactDir = path12.resolve(artifactDir);
|
|
4768
5009
|
if (options.production) {
|
|
4769
5010
|
return {
|
|
4770
5011
|
entries: index.entries.map((entry) => ({ routeId: entry.routeId }))
|
|
@@ -4779,22 +5020,22 @@ function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
|
4779
5020
|
};
|
|
4780
5021
|
}
|
|
4781
5022
|
async function saveRouteSeedIndex(artifactDir, index, options = {}) {
|
|
4782
|
-
const absPath =
|
|
5023
|
+
const absPath = path12.join(path12.resolve(artifactDir), ROUTE_SEED_INDEX_JSON);
|
|
4783
5024
|
await Bun.write(absPath, `${JSON.stringify(serializeRouteSeedIndexForArtifact(index, artifactDir, options), null, 2)}
|
|
4784
5025
|
`);
|
|
4785
5026
|
return absPath;
|
|
4786
5027
|
}
|
|
4787
5028
|
function serializeArtifactPath(artifactPath, artifactDir) {
|
|
4788
|
-
if (!
|
|
5029
|
+
if (!path12.isAbsolute(artifactPath))
|
|
4789
5030
|
return artifactPath;
|
|
4790
|
-
return
|
|
5031
|
+
return path12.relative(artifactDir, artifactPath).split(path12.sep).join("/");
|
|
4791
5032
|
}
|
|
4792
5033
|
|
|
4793
5034
|
// pkgs/@akanjs/devkit/frontendBuild/clientEntryDiscovery.ts
|
|
4794
|
-
import
|
|
5035
|
+
import path15 from "path";
|
|
4795
5036
|
|
|
4796
5037
|
// pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
|
|
4797
|
-
import
|
|
5038
|
+
import path13 from "path";
|
|
4798
5039
|
import { Logger as Logger7 } from "akanjs/common";
|
|
4799
5040
|
var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
|
|
4800
5041
|
var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
|
|
@@ -4917,7 +5158,7 @@ class BarrelAnalyzer {
|
|
|
4917
5158
|
}
|
|
4918
5159
|
#scanExports(source, absFile) {
|
|
4919
5160
|
try {
|
|
4920
|
-
const transpiler = [".tsx", ".jsx"].includes(
|
|
5161
|
+
const transpiler = [".tsx", ".jsx"].includes(path13.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
|
|
4921
5162
|
const { exports } = transpiler.scan(source);
|
|
4922
5163
|
return new Set(exports);
|
|
4923
5164
|
} catch (err) {
|
|
@@ -4926,16 +5167,16 @@ class BarrelAnalyzer {
|
|
|
4926
5167
|
}
|
|
4927
5168
|
}
|
|
4928
5169
|
#subpathFor(pkg, absFile) {
|
|
4929
|
-
const rel =
|
|
4930
|
-
if (!rel || rel.startsWith("..") ||
|
|
5170
|
+
const rel = path13.relative(pkg.pkgDir, absFile);
|
|
5171
|
+
if (!rel || rel.startsWith("..") || path13.isAbsolute(rel))
|
|
4931
5172
|
return null;
|
|
4932
5173
|
if (pkg.preserveFilePath)
|
|
4933
|
-
return `${pkg.pkgName}/${rel.split(
|
|
5174
|
+
return `${pkg.pkgName}/${rel.split(path13.sep).join("/")}`;
|
|
4934
5175
|
const noExt = stripKnownExt(rel);
|
|
4935
5176
|
const tail = collapseIndex(noExt);
|
|
4936
5177
|
if (tail === "")
|
|
4937
5178
|
return pkg.pkgName;
|
|
4938
|
-
return `${pkg.pkgName}/${tail.split(
|
|
5179
|
+
return `${pkg.pkgName}/${tail.split(path13.sep).join("/")}`;
|
|
4939
5180
|
}
|
|
4940
5181
|
async#resolveRel(fromFile, relSpec) {
|
|
4941
5182
|
if (this.#opts.resolveRelative)
|
|
@@ -4976,9 +5217,9 @@ var readIfExists = async (absFile) => {
|
|
|
4976
5217
|
return file.text();
|
|
4977
5218
|
};
|
|
4978
5219
|
var defaultResolveRelative = async (fromFile, relSpec) => {
|
|
4979
|
-
const baseDir =
|
|
4980
|
-
const joined =
|
|
4981
|
-
if (
|
|
5220
|
+
const baseDir = path13.dirname(fromFile);
|
|
5221
|
+
const joined = path13.resolve(baseDir, relSpec);
|
|
5222
|
+
if (path13.extname(joined)) {
|
|
4982
5223
|
if (await Bun.file(joined).exists())
|
|
4983
5224
|
return joined;
|
|
4984
5225
|
return null;
|
|
@@ -4989,7 +5230,7 @@ var defaultResolveRelative = async (fromFile, relSpec) => {
|
|
|
4989
5230
|
return cand;
|
|
4990
5231
|
}
|
|
4991
5232
|
for (const ext of CANDIDATE_EXTS) {
|
|
4992
|
-
const cand =
|
|
5233
|
+
const cand = path13.join(joined, `index${ext}`);
|
|
4993
5234
|
if (await Bun.file(cand).exists())
|
|
4994
5235
|
return cand;
|
|
4995
5236
|
}
|
|
@@ -5003,14 +5244,14 @@ var stripKnownExt = (relPath) => {
|
|
|
5003
5244
|
return relPath;
|
|
5004
5245
|
};
|
|
5005
5246
|
var collapseIndex = (relPathNoExt) => {
|
|
5006
|
-
const parts = relPathNoExt.split(
|
|
5247
|
+
const parts = relPathNoExt.split(path13.sep);
|
|
5007
5248
|
if (parts[parts.length - 1] === "index")
|
|
5008
5249
|
parts.pop();
|
|
5009
|
-
return parts.join(
|
|
5250
|
+
return parts.join(path13.sep);
|
|
5010
5251
|
};
|
|
5011
5252
|
|
|
5012
5253
|
// pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
|
|
5013
|
-
import
|
|
5254
|
+
import path14 from "path";
|
|
5014
5255
|
import ts4 from "typescript";
|
|
5015
5256
|
var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
|
|
5016
5257
|
const akanConfig2 = await app.getConfig();
|
|
@@ -5069,10 +5310,10 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
5069
5310
|
const raw = exact[0];
|
|
5070
5311
|
if (!raw)
|
|
5071
5312
|
return null;
|
|
5072
|
-
const entryFile =
|
|
5313
|
+
const entryFile = path14.resolve(app.workspace.workspaceRoot, raw);
|
|
5073
5314
|
if (!await Bun.file(entryFile).exists())
|
|
5074
5315
|
return null;
|
|
5075
|
-
const parsed =
|
|
5316
|
+
const parsed = path14.parse(entryFile);
|
|
5076
5317
|
const lastSlash = pkgName.lastIndexOf("/");
|
|
5077
5318
|
if (parsed.name !== "index" && lastSlash !== -1) {
|
|
5078
5319
|
const facet = pkgName.slice(lastSlash + 1);
|
|
@@ -5081,7 +5322,7 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
5081
5322
|
return { pkgName: parentSpec, entryFile, pkgDir: parsed.dir };
|
|
5082
5323
|
}
|
|
5083
5324
|
}
|
|
5084
|
-
return { pkgName, entryFile, pkgDir:
|
|
5325
|
+
return { pkgName, entryFile, pkgDir: path14.dirname(entryFile) };
|
|
5085
5326
|
}
|
|
5086
5327
|
for (const { prefix, replacements } of wildcardEntries) {
|
|
5087
5328
|
if (!pkgName.startsWith(prefix))
|
|
@@ -5091,7 +5332,7 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
5091
5332
|
if (!repl)
|
|
5092
5333
|
continue;
|
|
5093
5334
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
5094
|
-
const candidate =
|
|
5335
|
+
const candidate = path14.resolve(app.workspace.workspaceRoot, replPath + suffix);
|
|
5095
5336
|
for (const ext of CANDIDATE_EXTS2) {
|
|
5096
5337
|
const file = `${candidate}${ext}`;
|
|
5097
5338
|
if (await Bun.file(file).exists()) {
|
|
@@ -5099,14 +5340,14 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
5099
5340
|
if (lastSlash !== -1) {
|
|
5100
5341
|
const parentSpec = pkgName.slice(0, lastSlash);
|
|
5101
5342
|
if (parentSpec.length > 0) {
|
|
5102
|
-
return { pkgName: parentSpec, entryFile: file, pkgDir:
|
|
5343
|
+
return { pkgName: parentSpec, entryFile: file, pkgDir: path14.dirname(file) };
|
|
5103
5344
|
}
|
|
5104
5345
|
}
|
|
5105
|
-
return { pkgName, entryFile: file, pkgDir:
|
|
5346
|
+
return { pkgName, entryFile: file, pkgDir: path14.dirname(file) };
|
|
5106
5347
|
}
|
|
5107
5348
|
}
|
|
5108
5349
|
for (const ext of CANDIDATE_EXTS2) {
|
|
5109
|
-
const file =
|
|
5350
|
+
const file = path14.join(candidate, `index${ext}`);
|
|
5110
5351
|
if (await Bun.file(file).exists()) {
|
|
5111
5352
|
return { pkgName, entryFile: file, pkgDir: candidate };
|
|
5112
5353
|
}
|
|
@@ -5117,16 +5358,16 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
5117
5358
|
const exported = await resolveNodePackageExport(app.workspace.workspaceRoot, pkgName);
|
|
5118
5359
|
if (exported)
|
|
5119
5360
|
return exported;
|
|
5120
|
-
const pkgJsonPath =
|
|
5361
|
+
const pkgJsonPath = path14.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
|
|
5121
5362
|
if (!await Bun.file(pkgJsonPath).exists())
|
|
5122
5363
|
return null;
|
|
5123
5364
|
try {
|
|
5124
5365
|
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
5125
5366
|
const rel = pkgJson.module ?? pkgJson.main ?? "index.js";
|
|
5126
|
-
const entryFile =
|
|
5367
|
+
const entryFile = path14.resolve(path14.dirname(pkgJsonPath), rel);
|
|
5127
5368
|
if (!await Bun.file(entryFile).exists())
|
|
5128
5369
|
return null;
|
|
5129
|
-
return { pkgName, entryFile, pkgDir:
|
|
5370
|
+
return { pkgName, entryFile, pkgDir: path14.dirname(pkgJsonPath) };
|
|
5130
5371
|
} catch {
|
|
5131
5372
|
return null;
|
|
5132
5373
|
}
|
|
@@ -5140,22 +5381,22 @@ var resolveNodePackageExport = async (workspaceRoot, specifier) => {
|
|
|
5140
5381
|
const packageName = getPackageName(specifier);
|
|
5141
5382
|
if (!packageName)
|
|
5142
5383
|
return null;
|
|
5143
|
-
const pkgJsonPath =
|
|
5384
|
+
const pkgJsonPath = path14.join(workspaceRoot, "node_modules", packageName, "package.json");
|
|
5144
5385
|
if (!await Bun.file(pkgJsonPath).exists())
|
|
5145
5386
|
return null;
|
|
5146
5387
|
try {
|
|
5147
|
-
const pkgDir =
|
|
5388
|
+
const pkgDir = path14.dirname(pkgJsonPath);
|
|
5148
5389
|
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
5149
5390
|
const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
|
|
5150
5391
|
const exported = resolvePackageExport(pkgJson.exports, subpath);
|
|
5151
5392
|
const rel = exported ?? (subpath === "." ? pkgJson.module ?? pkgJson.main ?? "index.js" : null);
|
|
5152
5393
|
if (!rel || !rel.startsWith("."))
|
|
5153
5394
|
return null;
|
|
5154
|
-
const entryFile = await resolveFileCandidate(
|
|
5395
|
+
const entryFile = await resolveFileCandidate(path14.resolve(pkgDir, rel));
|
|
5155
5396
|
if (!entryFile)
|
|
5156
5397
|
return null;
|
|
5157
5398
|
const pkgEntryName = specifier;
|
|
5158
|
-
return { pkgName: pkgEntryName, entryFile, pkgDir:
|
|
5399
|
+
return { pkgName: pkgEntryName, entryFile, pkgDir: path14.dirname(entryFile), preserveFilePath: true };
|
|
5159
5400
|
} catch {
|
|
5160
5401
|
return null;
|
|
5161
5402
|
}
|
|
@@ -5212,7 +5453,7 @@ var getPackageName = (specifier) => {
|
|
|
5212
5453
|
var resolveFileCandidate = async (candidate) => {
|
|
5213
5454
|
if (await Bun.file(candidate).exists())
|
|
5214
5455
|
return candidate;
|
|
5215
|
-
if (
|
|
5456
|
+
if (path14.extname(candidate))
|
|
5216
5457
|
return null;
|
|
5217
5458
|
for (const ext of CANDIDATE_EXTS2) {
|
|
5218
5459
|
const file = `${candidate}${ext}`;
|
|
@@ -5220,7 +5461,7 @@ var resolveFileCandidate = async (candidate) => {
|
|
|
5220
5461
|
return file;
|
|
5221
5462
|
}
|
|
5222
5463
|
for (const ext of CANDIDATE_EXTS2) {
|
|
5223
|
-
const file =
|
|
5464
|
+
const file = path14.join(candidate, `index${ext}`);
|
|
5224
5465
|
if (await Bun.file(file).exists())
|
|
5225
5466
|
return file;
|
|
5226
5467
|
}
|
|
@@ -5434,7 +5675,7 @@ class GraphClientEntryDiscovery {
|
|
|
5434
5675
|
}
|
|
5435
5676
|
invalidate(files) {
|
|
5436
5677
|
for (const file of files) {
|
|
5437
|
-
const absPath =
|
|
5678
|
+
const absPath = path15.resolve(file);
|
|
5438
5679
|
this.#readCache.delete(absPath);
|
|
5439
5680
|
this.#rewriteCache.delete(absPath);
|
|
5440
5681
|
this.#importCache.delete(absPath);
|
|
@@ -5444,7 +5685,7 @@ class GraphClientEntryDiscovery {
|
|
|
5444
5685
|
this.#reachableEntriesCache.clear();
|
|
5445
5686
|
}
|
|
5446
5687
|
async#fileExists(p) {
|
|
5447
|
-
const absPath =
|
|
5688
|
+
const absPath = path15.resolve(p);
|
|
5448
5689
|
let cached = this.#fileExistsCache.get(absPath);
|
|
5449
5690
|
if (!cached) {
|
|
5450
5691
|
cached = Bun.file(absPath).exists();
|
|
@@ -5453,7 +5694,7 @@ class GraphClientEntryDiscovery {
|
|
|
5453
5694
|
return cached;
|
|
5454
5695
|
}
|
|
5455
5696
|
#readFile(file) {
|
|
5456
|
-
const absPath =
|
|
5697
|
+
const absPath = path15.resolve(file);
|
|
5457
5698
|
let cached = this.#readCache.get(absPath);
|
|
5458
5699
|
if (!cached) {
|
|
5459
5700
|
cached = Bun.file(absPath).text().catch(() => null);
|
|
@@ -5462,7 +5703,7 @@ class GraphClientEntryDiscovery {
|
|
|
5462
5703
|
return cached;
|
|
5463
5704
|
}
|
|
5464
5705
|
async#resolveFileCandidate(absPathNoExt) {
|
|
5465
|
-
const cacheKey =
|
|
5706
|
+
const cacheKey = path15.resolve(absPathNoExt);
|
|
5466
5707
|
let cached = this.#resolvedFileCache.get(cacheKey);
|
|
5467
5708
|
if (cached)
|
|
5468
5709
|
return cached;
|
|
@@ -5475,7 +5716,7 @@ class GraphClientEntryDiscovery {
|
|
|
5475
5716
|
return f;
|
|
5476
5717
|
}
|
|
5477
5718
|
for (const ext of SOURCE_EXTS2) {
|
|
5478
|
-
const f =
|
|
5719
|
+
const f = path15.join(cacheKey, `index${ext}`);
|
|
5479
5720
|
if (await this.#fileExists(f))
|
|
5480
5721
|
return f;
|
|
5481
5722
|
}
|
|
@@ -5491,7 +5732,7 @@ class GraphClientEntryDiscovery {
|
|
|
5491
5732
|
return cached;
|
|
5492
5733
|
cached = (async () => {
|
|
5493
5734
|
if (spec.startsWith(".") || spec.startsWith("/")) {
|
|
5494
|
-
const abs = spec.startsWith("/") ? spec :
|
|
5735
|
+
const abs = spec.startsWith("/") ? spec : path15.resolve(importerDir, spec);
|
|
5495
5736
|
return this.#resolveFileCandidate(abs);
|
|
5496
5737
|
}
|
|
5497
5738
|
const pkg = await this.#resolvePackage(spec);
|
|
@@ -5503,7 +5744,7 @@ class GraphClientEntryDiscovery {
|
|
|
5503
5744
|
return cached;
|
|
5504
5745
|
}
|
|
5505
5746
|
async#getRewrittenSource(file, content) {
|
|
5506
|
-
const absPath =
|
|
5747
|
+
const absPath = path15.resolve(file);
|
|
5507
5748
|
let cached = this.#rewriteCache.get(absPath);
|
|
5508
5749
|
if (!cached) {
|
|
5509
5750
|
cached = (async () => {
|
|
@@ -5520,7 +5761,7 @@ class GraphClientEntryDiscovery {
|
|
|
5520
5761
|
return cached;
|
|
5521
5762
|
}
|
|
5522
5763
|
async#getImports(file, source) {
|
|
5523
|
-
const absPath =
|
|
5764
|
+
const absPath = path15.resolve(file);
|
|
5524
5765
|
let cached = this.#importCache.get(absPath);
|
|
5525
5766
|
if (!cached) {
|
|
5526
5767
|
cached = Promise.resolve().then(() => {
|
|
@@ -5535,7 +5776,7 @@ class GraphClientEntryDiscovery {
|
|
|
5535
5776
|
return cached;
|
|
5536
5777
|
}
|
|
5537
5778
|
async#discoverFromFile(file, visiting) {
|
|
5538
|
-
const absPath =
|
|
5779
|
+
const absPath = path15.resolve(file);
|
|
5539
5780
|
const cached = this.#reachableEntriesCache.get(absPath);
|
|
5540
5781
|
if (cached)
|
|
5541
5782
|
return new Set(cached);
|
|
@@ -5552,7 +5793,7 @@ class GraphClientEntryDiscovery {
|
|
|
5552
5793
|
}
|
|
5553
5794
|
const source = await this.#getRewrittenSource(absPath, content);
|
|
5554
5795
|
const imports = await this.#getImports(absPath, source);
|
|
5555
|
-
const importerDir =
|
|
5796
|
+
const importerDir = path15.dirname(absPath);
|
|
5556
5797
|
for (const imp of imports) {
|
|
5557
5798
|
const spec = imp.path;
|
|
5558
5799
|
if (!spec)
|
|
@@ -5578,14 +5819,14 @@ class GraphClientEntryDiscovery {
|
|
|
5578
5819
|
|
|
5579
5820
|
// pkgs/@akanjs/devkit/frontendBuild/routeClientBuilder.ts
|
|
5580
5821
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
5581
|
-
import
|
|
5822
|
+
import path18 from "path";
|
|
5582
5823
|
|
|
5583
5824
|
// pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
|
|
5584
|
-
import
|
|
5825
|
+
import path16 from "path";
|
|
5585
5826
|
var USE_CLIENT_RE2 = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
|
|
5586
5827
|
var IMPLICIT_ROOT_LAYOUT_RE = /[/\\]\.akan[/\\]generated[/\\](?:implicit-root-layout|root-layouts[/\\].*__root_layout)\.(tsx|ts|jsx|js)$/;
|
|
5587
5828
|
function toClientReferencePath(absPath, workspaceRoot) {
|
|
5588
|
-
return
|
|
5829
|
+
return path16.relative(path16.resolve(workspaceRoot), path16.resolve(absPath)).split(path16.sep).join("/");
|
|
5589
5830
|
}
|
|
5590
5831
|
function transformUseClient(source, args) {
|
|
5591
5832
|
if (!USE_CLIENT_RE2.test(source))
|
|
@@ -5621,7 +5862,7 @@ function loaderFor2(absPath) {
|
|
|
5621
5862
|
|
|
5622
5863
|
// pkgs/@akanjs/devkit/frontendBuild/clientEntriesBundler.ts
|
|
5623
5864
|
import fs2 from "fs";
|
|
5624
|
-
import
|
|
5865
|
+
import path17 from "path";
|
|
5625
5866
|
|
|
5626
5867
|
// pkgs/@akanjs/devkit/frontendBuild/clientBuildTypes.ts
|
|
5627
5868
|
var CLIENT_BUNDLE_NAMING = {
|
|
@@ -5710,23 +5951,23 @@ class ClientEntriesBundler {
|
|
|
5710
5951
|
};
|
|
5711
5952
|
}
|
|
5712
5953
|
async#createOpaqueEntryAliases() {
|
|
5713
|
-
const aliasDir =
|
|
5954
|
+
const aliasDir = path17.join(this.#app.cwdPath, ".akan", "generated", "client-entry-alias", this.#outputSubdir);
|
|
5714
5955
|
fs2.mkdirSync(aliasDir, { recursive: true });
|
|
5715
5956
|
const originalByAlias = new Map;
|
|
5716
5957
|
const aliasedEntries = await Promise.all(this.#entries.map(async (entry) => {
|
|
5717
|
-
const absEntry =
|
|
5958
|
+
const absEntry = path17.resolve(entry);
|
|
5718
5959
|
const hash = Bun.hash(`${this.#app.name}
|
|
5719
5960
|
${this.#outputSubdir}
|
|
5720
5961
|
${absEntry}`).toString(36);
|
|
5721
|
-
const aliasPath =
|
|
5962
|
+
const aliasPath = path17.join(aliasDir, `${hash}.tsx`);
|
|
5722
5963
|
await Bun.write(aliasPath, this.#createOpaqueEntryAliasSource(absEntry, await this.#scanEntryExportNames(absEntry)));
|
|
5723
|
-
originalByAlias.set(
|
|
5964
|
+
originalByAlias.set(path17.resolve(aliasPath), absEntry);
|
|
5724
5965
|
return aliasPath;
|
|
5725
5966
|
}));
|
|
5726
5967
|
return { entries: aliasedEntries, originalByAlias, aliasDir };
|
|
5727
5968
|
}
|
|
5728
5969
|
#createOpaqueEntryAliasSource(absEntry, exportNames) {
|
|
5729
|
-
const entryLit = JSON.stringify(
|
|
5970
|
+
const entryLit = JSON.stringify(path17.resolve(absEntry));
|
|
5730
5971
|
if (exportNames.length === 0)
|
|
5731
5972
|
return `export * from ${entryLit};
|
|
5732
5973
|
`;
|
|
@@ -5809,16 +6050,16 @@ ${absEntry}`).toString(36);
|
|
|
5809
6050
|
return rewritten;
|
|
5810
6051
|
}
|
|
5811
6052
|
#toServeUrl(absOutPath) {
|
|
5812
|
-
const rel =
|
|
6053
|
+
const rel = path17.relative(this.#outdir, absOutPath).split(path17.sep).join("/");
|
|
5813
6054
|
return `${this.#servePrefix}/${rel}`;
|
|
5814
6055
|
}
|
|
5815
6056
|
#absFromOutdir(p) {
|
|
5816
|
-
return
|
|
6057
|
+
return path17.isAbsolute(p) ? p : path17.resolve(this.#outdir, p);
|
|
5817
6058
|
}
|
|
5818
6059
|
#absFromEntryPoint(p) {
|
|
5819
|
-
if (
|
|
5820
|
-
return
|
|
5821
|
-
const candidates = [
|
|
6060
|
+
if (path17.isAbsolute(p))
|
|
6061
|
+
return path17.resolve(p);
|
|
6062
|
+
const candidates = [path17.resolve(process.cwd(), p), path17.resolve(this.#app.cwdPath, p)];
|
|
5822
6063
|
return candidates.find((candidate) => fs2.existsSync(candidate)) ?? candidates[0];
|
|
5823
6064
|
}
|
|
5824
6065
|
#collectChunkUrls(absOutPath, visited = new Set) {
|
|
@@ -5968,13 +6209,13 @@ class RouteClientBuilder {
|
|
|
5968
6209
|
ssrModuleMap[row.id][row.name] = { id: ssrOutput, chunks: [ssrOutput, ssrOutput], name: row.name, async: true };
|
|
5969
6210
|
}
|
|
5970
6211
|
for (const entry of bootstrapEntries.buildEntries) {
|
|
5971
|
-
const buildEntry =
|
|
5972
|
-
const originalEntry =
|
|
6212
|
+
const buildEntry = path18.resolve(entry);
|
|
6213
|
+
const originalEntry = path18.resolve(bootstrapEntries.originalByBuildEntry.get(buildEntry) ?? buildEntry);
|
|
5973
6214
|
if (!acceptedEntries.has(originalEntry))
|
|
5974
6215
|
continue;
|
|
5975
6216
|
const deps = new Set([originalEntry]);
|
|
5976
6217
|
for (const dep of browserBundle.entryDepsByAbsPath.get(buildEntry) ?? [])
|
|
5977
|
-
deps.add(
|
|
6218
|
+
deps.add(path18.resolve(dep));
|
|
5978
6219
|
const sortedDeps = [...deps].sort();
|
|
5979
6220
|
clientDepsByEntry[originalEntry] = sortedDeps;
|
|
5980
6221
|
for (const dep of sortedDeps)
|
|
@@ -6026,25 +6267,25 @@ class RouteClientBuilder {
|
|
|
6026
6267
|
}).bundle();
|
|
6027
6268
|
}
|
|
6028
6269
|
async#createBootstrapEntries(entries) {
|
|
6029
|
-
if (!await Bun.file(
|
|
6270
|
+
if (!await Bun.file(path18.join(this.#app.cwdPath, "lib", "st.ts")).exists()) {
|
|
6030
6271
|
return { buildEntries: entries, originalByBuildEntry: new Map };
|
|
6031
6272
|
}
|
|
6032
|
-
const outdir =
|
|
6273
|
+
const outdir = path18.join(this.#app.cwdPath, ".akan", "generated", "client-entry-bootstrap");
|
|
6033
6274
|
await mkdir4(outdir, { recursive: true });
|
|
6034
6275
|
const originalByBuildEntry = new Map;
|
|
6035
6276
|
const buildEntries = await Promise.all(entries.map(async (entry) => {
|
|
6036
|
-
const absEntry =
|
|
6277
|
+
const absEntry = path18.resolve(entry);
|
|
6037
6278
|
const hash = Bun.hash(`${this.#app.name}
|
|
6038
6279
|
${absEntry}`).toString(36);
|
|
6039
|
-
const base =
|
|
6040
|
-
const wrapperEntry =
|
|
6280
|
+
const base = path18.basename(absEntry).replace(/[^A-Za-z0-9._-]/g, "_");
|
|
6281
|
+
const wrapperEntry = path18.join(outdir, `${base}-${hash}.tsx`);
|
|
6041
6282
|
const exportNames = await this.#scanExportNames(absEntry);
|
|
6042
6283
|
await Bun.write(wrapperEntry, RouteClientBuilder.createStoreBootstrapEntrySource({
|
|
6043
6284
|
appName: this.#app.name,
|
|
6044
6285
|
originalEntry: absEntry,
|
|
6045
6286
|
exportNames
|
|
6046
6287
|
}));
|
|
6047
|
-
originalByBuildEntry.set(
|
|
6288
|
+
originalByBuildEntry.set(path18.resolve(wrapperEntry), absEntry);
|
|
6048
6289
|
return wrapperEntry;
|
|
6049
6290
|
}));
|
|
6050
6291
|
return { buildEntries, originalByBuildEntry };
|
|
@@ -6096,11 +6337,11 @@ ${defaultNames.map((name) => `export default ${name};`).join(`
|
|
|
6096
6337
|
try {
|
|
6097
6338
|
return Bun.resolveSync("akanjs/server", import.meta.dir);
|
|
6098
6339
|
} catch {
|
|
6099
|
-
return
|
|
6340
|
+
return path18.resolve(import.meta.dir, "../../../server/index.ts");
|
|
6100
6341
|
}
|
|
6101
6342
|
}
|
|
6102
6343
|
static createStoreBootstrapEntrySource(args) {
|
|
6103
|
-
const originalEntry = JSON.stringify(
|
|
6344
|
+
const originalEntry = JSON.stringify(path18.resolve(args.originalEntry));
|
|
6104
6345
|
const namedExports = args.exportNames.filter((name) => name !== "default");
|
|
6105
6346
|
const lines = [
|
|
6106
6347
|
`import ${JSON.stringify(`@apps/${args.appName}/client`)};`,
|
|
@@ -6126,7 +6367,7 @@ ${defaultNames.map((name) => `export default ${name};`).join(`
|
|
|
6126
6367
|
}
|
|
6127
6368
|
|
|
6128
6369
|
// pkgs/@akanjs/devkit/frontendBuild/routesManifestArtifactSerializer.ts
|
|
6129
|
-
import
|
|
6370
|
+
import path19 from "path";
|
|
6130
6371
|
|
|
6131
6372
|
class RoutesManifestArtifactSerializer {
|
|
6132
6373
|
#manifest;
|
|
@@ -6134,7 +6375,7 @@ class RoutesManifestArtifactSerializer {
|
|
|
6134
6375
|
#production;
|
|
6135
6376
|
constructor(manifest, artifactDir, options = {}) {
|
|
6136
6377
|
this.#manifest = manifest;
|
|
6137
|
-
this.#artifactDir =
|
|
6378
|
+
this.#artifactDir = path19.resolve(artifactDir);
|
|
6138
6379
|
this.#production = options.production ?? false;
|
|
6139
6380
|
}
|
|
6140
6381
|
static serialize(manifest, artifactDir, options = {}) {
|
|
@@ -6167,9 +6408,9 @@ class RoutesManifestArtifactSerializer {
|
|
|
6167
6408
|
};
|
|
6168
6409
|
}
|
|
6169
6410
|
#serializeArtifactPath(artifactPath) {
|
|
6170
|
-
if (!
|
|
6411
|
+
if (!path19.isAbsolute(artifactPath))
|
|
6171
6412
|
return artifactPath;
|
|
6172
|
-
return
|
|
6413
|
+
return path19.relative(this.#artifactDir, artifactPath).split(path19.sep).join("/");
|
|
6173
6414
|
}
|
|
6174
6415
|
}
|
|
6175
6416
|
|
|
@@ -6209,7 +6450,7 @@ class AllRoutesBuilder {
|
|
|
6209
6450
|
routeIds: this.#routeIds,
|
|
6210
6451
|
...this.#merged
|
|
6211
6452
|
};
|
|
6212
|
-
const manifestPath =
|
|
6453
|
+
const manifestPath = path20.join(path20.resolve(this.#artifactDir), "routes-manifest.json");
|
|
6213
6454
|
await Bun.write(manifestPath, `${JSON.stringify(RoutesManifestArtifactSerializer.serialize(manifest, this.#artifactDir, {
|
|
6214
6455
|
production: this.#command === "build"
|
|
6215
6456
|
}), null, 2)}
|
|
@@ -6246,11 +6487,11 @@ class AllRoutesBuilder {
|
|
|
6246
6487
|
}
|
|
6247
6488
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
6248
6489
|
import { mkdir as mkdir5, rm, unlink } from "fs/promises";
|
|
6249
|
-
import
|
|
6490
|
+
import path22 from "path";
|
|
6250
6491
|
|
|
6251
6492
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
6252
6493
|
import fs3 from "fs";
|
|
6253
|
-
import
|
|
6494
|
+
import path21 from "path";
|
|
6254
6495
|
import ts5 from "typescript";
|
|
6255
6496
|
|
|
6256
6497
|
class PagesEntrySourceGenerator {
|
|
@@ -6263,7 +6504,7 @@ class PagesEntrySourceGenerator {
|
|
|
6263
6504
|
}
|
|
6264
6505
|
generate() {
|
|
6265
6506
|
const lines = this.#pageEntries.map(({ key, moduleAbsPath }) => {
|
|
6266
|
-
const absPath =
|
|
6507
|
+
const absPath = path21.resolve(moduleAbsPath);
|
|
6267
6508
|
return ` ${JSON.stringify(key)}: () => import(${JSON.stringify(absPath)}),`;
|
|
6268
6509
|
});
|
|
6269
6510
|
return `export const pages = {
|
|
@@ -6277,7 +6518,7 @@ ${lines.join(`
|
|
|
6277
6518
|
}
|
|
6278
6519
|
generateStatic() {
|
|
6279
6520
|
const imports = this.#pageEntries.map(({ moduleAbsPath }, index) => {
|
|
6280
|
-
const absPath =
|
|
6521
|
+
const absPath = path21.resolve(moduleAbsPath);
|
|
6281
6522
|
return `import * as page${index} from ${JSON.stringify(absPath)};`;
|
|
6282
6523
|
});
|
|
6283
6524
|
const entries = this.#pageEntries.map(({ key, moduleAbsPath }, index) => {
|
|
@@ -6294,7 +6535,7 @@ ${entries.join(`
|
|
|
6294
6535
|
}
|
|
6295
6536
|
static #hasAsyncDefaultExport(moduleAbsPath) {
|
|
6296
6537
|
try {
|
|
6297
|
-
const source = fs3.readFileSync(
|
|
6538
|
+
const source = fs3.readFileSync(path21.resolve(moduleAbsPath), "utf8");
|
|
6298
6539
|
const sourceFile = ts5.createSourceFile(moduleAbsPath, source, ts5.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
|
|
6299
6540
|
return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile);
|
|
6300
6541
|
} catch {
|
|
@@ -6373,7 +6614,7 @@ class CsrArtifactBuilder {
|
|
|
6373
6614
|
const csrBasePaths = [...akanConfig2.basePaths];
|
|
6374
6615
|
const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
|
|
6375
6616
|
await rm(this.#outputDir, { recursive: true, force: true });
|
|
6376
|
-
await mkdir5(
|
|
6617
|
+
await mkdir5(path22.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
|
|
6377
6618
|
const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath2) => this.#createHtmlFile(basePath2)));
|
|
6378
6619
|
const result = await Bun.build({
|
|
6379
6620
|
target: "browser",
|
|
@@ -6405,7 +6646,7 @@ ${logs}` : ""}`);
|
|
|
6405
6646
|
return { outputDir: this.#outputDir };
|
|
6406
6647
|
}
|
|
6407
6648
|
get #outputDir() {
|
|
6408
|
-
return
|
|
6649
|
+
return path22.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
|
|
6409
6650
|
}
|
|
6410
6651
|
#define() {
|
|
6411
6652
|
const nodeEnv = this.#command === "build" ? "production" : "development";
|
|
@@ -6436,8 +6677,8 @@ ${logs}` : ""}`);
|
|
|
6436
6677
|
];
|
|
6437
6678
|
}
|
|
6438
6679
|
async#loadCsrArtifact() {
|
|
6439
|
-
const artifactDir =
|
|
6440
|
-
const artifactFile = Bun.file(
|
|
6680
|
+
const artifactDir = path22.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
|
|
6681
|
+
const artifactFile = Bun.file(path22.join(artifactDir, "base-artifact.json"));
|
|
6441
6682
|
if (!await artifactFile.exists())
|
|
6442
6683
|
return { cssAssets: {} };
|
|
6443
6684
|
const artifact = await artifactFile.json();
|
|
@@ -6450,7 +6691,7 @@ ${logs}` : ""}`);
|
|
|
6450
6691
|
const htmlFile = Bun.file(htmlPath);
|
|
6451
6692
|
if (!await htmlFile.exists())
|
|
6452
6693
|
continue;
|
|
6453
|
-
const basePath2 =
|
|
6694
|
+
const basePath2 = path22.basename(htmlPath, ".html") === "index" ? "" : path22.basename(htmlPath, ".html");
|
|
6454
6695
|
const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAssets[basePath2]);
|
|
6455
6696
|
for (const filePath of inlined.jsFiles)
|
|
6456
6697
|
jsFiles.add(filePath);
|
|
@@ -6492,7 +6733,7 @@ ${remainingAssets.join(`
|
|
|
6492
6733
|
next = CsrArtifactBuilder.injectBeforeHeadEnd(next, style);
|
|
6493
6734
|
}
|
|
6494
6735
|
if (cssAsset) {
|
|
6495
|
-
const cssPath =
|
|
6736
|
+
const cssPath = path22.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
|
|
6496
6737
|
const css = await Bun.file(cssPath).text();
|
|
6497
6738
|
const style = CsrArtifactBuilder.createInlineStyle(css);
|
|
6498
6739
|
if (!next.includes(style))
|
|
@@ -6563,16 +6804,16 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
|
6563
6804
|
throw new Error(`[csr-build] cannot inline external script: ${src}`);
|
|
6564
6805
|
}
|
|
6565
6806
|
const normalized = src.startsWith("/") ? src.slice(1) : src;
|
|
6566
|
-
return
|
|
6807
|
+
return path22.resolve(path22.dirname(htmlPath), normalized);
|
|
6567
6808
|
}
|
|
6568
6809
|
}
|
|
6569
6810
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
6570
|
-
import
|
|
6811
|
+
import path24 from "path";
|
|
6571
6812
|
import { Logger as Logger8 } from "akanjs/common";
|
|
6572
6813
|
import { compile } from "tailwindcss";
|
|
6573
6814
|
|
|
6574
6815
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
6575
|
-
import
|
|
6816
|
+
import path23 from "path";
|
|
6576
6817
|
var CSS_IMPORT_EXTS = ["", ".css", "/styles.css", "/index.css"];
|
|
6577
6818
|
|
|
6578
6819
|
class CssImportResolver {
|
|
@@ -6625,7 +6866,7 @@ class CssImportResolver {
|
|
|
6625
6866
|
const exact = this.#paths[id];
|
|
6626
6867
|
if (exact) {
|
|
6627
6868
|
for (const repl of exact) {
|
|
6628
|
-
const resolved = await this.#firstExisting(
|
|
6869
|
+
const resolved = await this.#firstExisting(path23.resolve(this.#workspaceRoot, repl));
|
|
6629
6870
|
if (resolved)
|
|
6630
6871
|
return resolved;
|
|
6631
6872
|
}
|
|
@@ -6636,7 +6877,7 @@ class CssImportResolver {
|
|
|
6636
6877
|
const suffix = id.slice(prefix.length);
|
|
6637
6878
|
for (const repl of replacements) {
|
|
6638
6879
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
6639
|
-
const resolved = await this.#firstExisting(
|
|
6880
|
+
const resolved = await this.#firstExisting(path23.resolve(this.#workspaceRoot, replPath + suffix));
|
|
6640
6881
|
if (resolved)
|
|
6641
6882
|
return resolved;
|
|
6642
6883
|
}
|
|
@@ -6666,25 +6907,25 @@ class CssImportResolver {
|
|
|
6666
6907
|
try {
|
|
6667
6908
|
if (!await Bun.file(pkgPath).exists())
|
|
6668
6909
|
return null;
|
|
6669
|
-
const pkgDir =
|
|
6910
|
+
const pkgDir = path23.dirname(pkgPath);
|
|
6670
6911
|
const pkg = await Bun.file(pkgPath).json();
|
|
6671
6912
|
const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
|
|
6672
6913
|
const exportValue = pkg.exports?.[subpath];
|
|
6673
6914
|
const styleEntry = (typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default) || pkg.exports?.["."]?.style || pkg.style || "index.css";
|
|
6674
|
-
return await this.#firstExisting(
|
|
6915
|
+
return await this.#firstExisting(path23.resolve(pkgDir, styleEntry));
|
|
6675
6916
|
} catch {
|
|
6676
6917
|
return null;
|
|
6677
6918
|
}
|
|
6678
6919
|
}
|
|
6679
6920
|
#resolutionBases(fromBase) {
|
|
6680
|
-
return [fromBase, this.#workspaceRoot,
|
|
6921
|
+
return [fromBase, this.#workspaceRoot, path23.dirname(Bun.main), path23.resolve(path23.dirname(Bun.main), "../..")];
|
|
6681
6922
|
}
|
|
6682
6923
|
#packageJsonCandidates(pkgName) {
|
|
6683
6924
|
return [
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6925
|
+
path23.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
|
|
6926
|
+
path23.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
|
|
6927
|
+
path23.join(path23.dirname(Bun.main), "node_modules", pkgName, "package.json"),
|
|
6928
|
+
path23.join(path23.dirname(Bun.main), "../../", pkgName, "package.json")
|
|
6688
6929
|
];
|
|
6689
6930
|
}
|
|
6690
6931
|
async#firstExisting(basePath2) {
|
|
@@ -6702,7 +6943,7 @@ class CssImportResolver {
|
|
|
6702
6943
|
return parts[0] ?? null;
|
|
6703
6944
|
}
|
|
6704
6945
|
static isCssFile(filePath) {
|
|
6705
|
-
return
|
|
6946
|
+
return path23.extname(filePath) === ".css";
|
|
6706
6947
|
}
|
|
6707
6948
|
}
|
|
6708
6949
|
|
|
@@ -6769,7 +7010,7 @@ class CssCompiler {
|
|
|
6769
7010
|
pageKeys
|
|
6770
7011
|
} = {}) {
|
|
6771
7012
|
pageKeys ??= await this.#app.getPageKeys({ refresh });
|
|
6772
|
-
const seeds = pageKeys.map((key) =>
|
|
7013
|
+
const seeds = pageKeys.map((key) => path24.resolve(this.#app.cwdPath, "page", key));
|
|
6773
7014
|
const cssFiles = new Set;
|
|
6774
7015
|
const sourceFiles = new Set;
|
|
6775
7016
|
const queue = [...seeds];
|
|
@@ -6801,7 +7042,7 @@ class CssCompiler {
|
|
|
6801
7042
|
} catch {
|
|
6802
7043
|
continue;
|
|
6803
7044
|
}
|
|
6804
|
-
const importerDir =
|
|
7045
|
+
const importerDir = path24.dirname(filePath);
|
|
6805
7046
|
for (const imp of imports) {
|
|
6806
7047
|
const spec = imp.path;
|
|
6807
7048
|
if (!spec)
|
|
@@ -6827,7 +7068,7 @@ class CssCompiler {
|
|
|
6827
7068
|
const compileStarted = Date.now();
|
|
6828
7069
|
const compilers = await Promise.all(cssPaths.map(async (cssPath) => {
|
|
6829
7070
|
const css = await Bun.file(cssPath).text();
|
|
6830
|
-
const base =
|
|
7071
|
+
const base = path24.dirname(cssPath);
|
|
6831
7072
|
const compiler = await compile(css, {
|
|
6832
7073
|
base,
|
|
6833
7074
|
loadStylesheet: (id, fromBase) => this.#loadStylesheet(id, fromBase),
|
|
@@ -6858,11 +7099,11 @@ class CssCompiler {
|
|
|
6858
7099
|
async#loadStylesheet(id, fromBase) {
|
|
6859
7100
|
const p = await this.#resolveCssImport(id, fromBase);
|
|
6860
7101
|
const content = await Bun.file(p).text();
|
|
6861
|
-
return { path: p, base:
|
|
7102
|
+
return { path: p, base: path24.dirname(p), content };
|
|
6862
7103
|
}
|
|
6863
7104
|
async#resolveCssImport(id, fromBase) {
|
|
6864
7105
|
if (id.startsWith(".") || id.startsWith("/"))
|
|
6865
|
-
return
|
|
7106
|
+
return path24.resolve(fromBase, id);
|
|
6866
7107
|
const resolver = await this.#getCssImportResolver();
|
|
6867
7108
|
const resolved = await resolver.resolve(id, fromBase);
|
|
6868
7109
|
if (resolved)
|
|
@@ -6878,11 +7119,11 @@ class CssCompiler {
|
|
|
6878
7119
|
async#loadModule(id, fromBase) {
|
|
6879
7120
|
const p = __require.resolve(id, { paths: [fromBase] });
|
|
6880
7121
|
const mod = await import(p);
|
|
6881
|
-
return { path: p, base:
|
|
7122
|
+
return { path: p, base: path24.dirname(p), module: mod.default ?? mod };
|
|
6882
7123
|
}
|
|
6883
7124
|
async#resolveSourceImport(id, fromBase, resolvePackage) {
|
|
6884
7125
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
6885
|
-
const abs = id.startsWith("/") ? id :
|
|
7126
|
+
const abs = id.startsWith("/") ? id : path24.resolve(fromBase, id);
|
|
6886
7127
|
return resolveSourceFileCandidate(abs);
|
|
6887
7128
|
}
|
|
6888
7129
|
const pkg = await resolvePackage(id);
|
|
@@ -6924,7 +7165,7 @@ async function resolveSourceFileCandidate(absPathNoExt) {
|
|
|
6924
7165
|
return filePath;
|
|
6925
7166
|
}
|
|
6926
7167
|
for (const ext of SOURCE_EXTS3) {
|
|
6927
|
-
const filePath =
|
|
7168
|
+
const filePath = path24.join(absPathNoExt, `index${ext}`);
|
|
6928
7169
|
if (await Bun.file(filePath).exists())
|
|
6929
7170
|
return filePath;
|
|
6930
7171
|
}
|
|
@@ -6947,20 +7188,20 @@ function resolveSourceWithRequire(id, fromBase) {
|
|
|
6947
7188
|
}
|
|
6948
7189
|
}
|
|
6949
7190
|
function isSourceFile(filePath) {
|
|
6950
|
-
return SOURCE_EXTS3.includes(
|
|
7191
|
+
return SOURCE_EXTS3.includes(path24.extname(filePath));
|
|
6951
7192
|
}
|
|
6952
7193
|
function isIgnoredNodeModuleSource(filePath) {
|
|
6953
7194
|
return NODE_MODULES_RE3.test(filePath) && !AKANJS_NODE_MODULE_RE3.test(filePath);
|
|
6954
7195
|
}
|
|
6955
7196
|
function getPageKeyBasePath(pageKey, basePaths) {
|
|
6956
|
-
const normalized = pageKey.split(
|
|
7197
|
+
const normalized = pageKey.split(path24.sep).join("/").replace(/^\.\//, "");
|
|
6957
7198
|
const segments = normalized.split("/");
|
|
6958
7199
|
const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
|
|
6959
7200
|
return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
|
|
6960
7201
|
}
|
|
6961
7202
|
// pkgs/@akanjs/devkit/frontendBuild/fontOptimizer.ts
|
|
6962
7203
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
6963
|
-
import
|
|
7204
|
+
import path25 from "path";
|
|
6964
7205
|
import {
|
|
6965
7206
|
generateFontFace,
|
|
6966
7207
|
getMetricsForFamily,
|
|
@@ -6984,7 +7225,7 @@ class FontOptimizer {
|
|
|
6984
7225
|
constructor(app, command = "start") {
|
|
6985
7226
|
this.#app = app;
|
|
6986
7227
|
this.#command = command;
|
|
6987
|
-
this.#artifactRoot =
|
|
7228
|
+
this.#artifactRoot = path25.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
|
|
6988
7229
|
}
|
|
6989
7230
|
async optimize() {
|
|
6990
7231
|
const fonts = await this.discoverFonts();
|
|
@@ -7003,7 +7244,7 @@ class FontOptimizer {
|
|
|
7003
7244
|
const pageKeys = await this.#app.getPageKeys();
|
|
7004
7245
|
const fonts = [];
|
|
7005
7246
|
await Promise.all(pageKeys.map(async (key) => {
|
|
7006
|
-
const filePath =
|
|
7247
|
+
const filePath = path25.resolve(this.#app.cwdPath, "page", key);
|
|
7007
7248
|
const file = Bun.file(filePath);
|
|
7008
7249
|
if (!await file.exists())
|
|
7009
7250
|
return;
|
|
@@ -7019,8 +7260,8 @@ class FontOptimizer {
|
|
|
7019
7260
|
this.#app.logger.warn(`[font] source not found: ${face.src}`);
|
|
7020
7261
|
continue;
|
|
7021
7262
|
}
|
|
7022
|
-
const outputPath =
|
|
7023
|
-
await mkdir6(
|
|
7263
|
+
const outputPath = path25.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
|
|
7264
|
+
await mkdir6(path25.dirname(outputPath), { recursive: true });
|
|
7024
7265
|
const sourceBuffer = Buffer.from(await Bun.file(sourcePath).arrayBuffer());
|
|
7025
7266
|
const outputBuffer = font.subset === false ? await this.#convertToWoff2(sourceBuffer, sourcePath) : await subsetFont(sourceBuffer, await this.#getSubsetText(font), { targetFormat: "woff2" });
|
|
7026
7267
|
await Bun.write(outputPath, outputBuffer);
|
|
@@ -7167,8 +7408,8 @@ class FontOptimizer {
|
|
|
7167
7408
|
return null;
|
|
7168
7409
|
const rel = src.replace(/^\//, "");
|
|
7169
7410
|
const candidates = [
|
|
7170
|
-
this.#command === "build" ?
|
|
7171
|
-
|
|
7411
|
+
this.#command === "build" ? path25.join(this.#app.dist.cwdPath, "public", rel) : null,
|
|
7412
|
+
path25.join(this.#app.cwdPath, "public", rel),
|
|
7172
7413
|
this.#resolveWorkspacePublicPath(rel)
|
|
7173
7414
|
].filter(Boolean);
|
|
7174
7415
|
for (const candidate of candidates) {
|
|
@@ -7196,7 +7437,7 @@ class FontOptimizer {
|
|
|
7196
7437
|
return "woff2";
|
|
7197
7438
|
if (signature === "OTTO")
|
|
7198
7439
|
return "otf";
|
|
7199
|
-
const ext =
|
|
7440
|
+
const ext = path25.extname(sourcePath).slice(1).toLowerCase();
|
|
7200
7441
|
if (ext === "otf" || ext === "woff" || ext === "woff2")
|
|
7201
7442
|
return ext;
|
|
7202
7443
|
return "ttf";
|
|
@@ -7205,7 +7446,7 @@ class FontOptimizer {
|
|
|
7205
7446
|
const [root, dep, ...rest] = rel.split("/");
|
|
7206
7447
|
if (root !== "libs" || !dep || rest.length === 0)
|
|
7207
7448
|
return null;
|
|
7208
|
-
return
|
|
7449
|
+
return path25.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
|
|
7209
7450
|
}
|
|
7210
7451
|
async#getSubsetText(font) {
|
|
7211
7452
|
const parts = new Set;
|
|
@@ -7215,7 +7456,7 @@ class FontOptimizer {
|
|
|
7215
7456
|
if (font.subsetText)
|
|
7216
7457
|
parts.add(font.subsetText);
|
|
7217
7458
|
for (const filePath of font.subsetFiles ?? []) {
|
|
7218
|
-
const abs =
|
|
7459
|
+
const abs = path25.isAbsolute(filePath) ? filePath : path25.join(this.#app.cwdPath, filePath);
|
|
7219
7460
|
const file = Bun.file(abs);
|
|
7220
7461
|
if (await file.exists())
|
|
7221
7462
|
parts.add(await file.text());
|
|
@@ -7234,7 +7475,7 @@ class FontOptimizer {
|
|
|
7234
7475
|
return "";
|
|
7235
7476
|
}
|
|
7236
7477
|
async#collectAutoSubsetText() {
|
|
7237
|
-
const roots = ["page", "ui"].map((dir) =>
|
|
7478
|
+
const roots = ["page", "ui"].map((dir) => path25.join(this.#app.cwdPath, dir));
|
|
7238
7479
|
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,html,md}");
|
|
7239
7480
|
const parts = [];
|
|
7240
7481
|
await Promise.all(roots.map(async (root) => {
|
|
@@ -7348,7 +7589,7 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
|
|
|
7348
7589
|
}
|
|
7349
7590
|
}
|
|
7350
7591
|
// pkgs/@akanjs/devkit/frontendBuild/hmrChangeClassifier.ts
|
|
7351
|
-
import
|
|
7592
|
+
import path26 from "path";
|
|
7352
7593
|
var SOURCE_EXTS4 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
7353
7594
|
var CSS_EXTS = new Set([".css"]);
|
|
7354
7595
|
var CONFIG_BASENAMES = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
|
|
@@ -7357,10 +7598,10 @@ class HmrChangeClassifier {
|
|
|
7357
7598
|
classify(abs) {
|
|
7358
7599
|
if (this.#isUninteresting(abs))
|
|
7359
7600
|
return "ignore";
|
|
7360
|
-
const base =
|
|
7601
|
+
const base = path26.basename(abs);
|
|
7361
7602
|
if (CONFIG_BASENAMES.has(base))
|
|
7362
7603
|
return "config";
|
|
7363
|
-
const ext =
|
|
7604
|
+
const ext = path26.extname(abs).toLowerCase();
|
|
7364
7605
|
if (CSS_EXTS.has(ext))
|
|
7365
7606
|
return "css";
|
|
7366
7607
|
if (SOURCE_EXTS4.has(ext))
|
|
@@ -7368,23 +7609,23 @@ class HmrChangeClassifier {
|
|
|
7368
7609
|
return "ignore";
|
|
7369
7610
|
}
|
|
7370
7611
|
#isUninteresting(abs) {
|
|
7371
|
-
const base =
|
|
7612
|
+
const base = path26.basename(abs);
|
|
7372
7613
|
if (!base)
|
|
7373
7614
|
return true;
|
|
7374
7615
|
if (base.startsWith("."))
|
|
7375
7616
|
return true;
|
|
7376
7617
|
if (base.endsWith("~") || base.endsWith(".swp") || base.endsWith(".swx") || base.endsWith(".tmp"))
|
|
7377
7618
|
return true;
|
|
7378
|
-
if (abs.includes(`${
|
|
7619
|
+
if (abs.includes(`${path26.sep}node_modules${path26.sep}`))
|
|
7379
7620
|
return true;
|
|
7380
|
-
if (abs.includes(`${
|
|
7621
|
+
if (abs.includes(`${path26.sep}.akan${path26.sep}`))
|
|
7381
7622
|
return true;
|
|
7382
7623
|
return false;
|
|
7383
7624
|
}
|
|
7384
7625
|
}
|
|
7385
7626
|
// pkgs/@akanjs/devkit/frontendBuild/hmrWatcher.ts
|
|
7386
7627
|
import fs4 from "fs";
|
|
7387
|
-
import
|
|
7628
|
+
import path27 from "path";
|
|
7388
7629
|
class HmrWatcher {
|
|
7389
7630
|
#roots;
|
|
7390
7631
|
#debounceMs;
|
|
@@ -7397,7 +7638,7 @@ class HmrWatcher {
|
|
|
7397
7638
|
#stopped = false;
|
|
7398
7639
|
#flushing = false;
|
|
7399
7640
|
constructor(opts) {
|
|
7400
|
-
this.#roots = [...new Set(opts.roots.map((r) =>
|
|
7641
|
+
this.#roots = [...new Set(opts.roots.map((r) => path27.resolve(r)))];
|
|
7401
7642
|
this.#debounceMs = opts.debounceMs ?? 80;
|
|
7402
7643
|
this.#onBatch = opts.onBatch;
|
|
7403
7644
|
this.#logger = opts.logger;
|
|
@@ -7408,7 +7649,7 @@ class HmrWatcher {
|
|
|
7408
7649
|
const w = fs4.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
|
|
7409
7650
|
if (!filename)
|
|
7410
7651
|
return;
|
|
7411
|
-
const abs =
|
|
7652
|
+
const abs = path27.resolve(root, filename.toString());
|
|
7412
7653
|
this.#queue(abs);
|
|
7413
7654
|
});
|
|
7414
7655
|
this.#watchers.push(w);
|
|
@@ -7466,10 +7707,10 @@ class HmrWatcher {
|
|
|
7466
7707
|
}
|
|
7467
7708
|
}
|
|
7468
7709
|
// pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
|
|
7469
|
-
import
|
|
7710
|
+
import path29 from "path";
|
|
7470
7711
|
|
|
7471
7712
|
// pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
|
|
7472
|
-
import
|
|
7713
|
+
import path28 from "path";
|
|
7473
7714
|
var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
|
|
7474
7715
|
var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "akanjs/server", "@akanjs/cli", "@akanjs/devkit"]);
|
|
7475
7716
|
var DEFAULT_EXCLUDE_PREFIX = ["akanjs/server/", "@akanjs/cli/", "@akanjs/devkit/"];
|
|
@@ -7504,7 +7745,7 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
7504
7745
|
const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
|
|
7505
7746
|
if (!replPath)
|
|
7506
7747
|
continue;
|
|
7507
|
-
const candidate =
|
|
7748
|
+
const candidate = path28.resolve(workspaceRoot, replPath + suffix);
|
|
7508
7749
|
const hit = await firstExisting(candidate);
|
|
7509
7750
|
if (hit)
|
|
7510
7751
|
return hit;
|
|
@@ -7516,8 +7757,8 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
7516
7757
|
if (spec === pkg)
|
|
7517
7758
|
continue;
|
|
7518
7759
|
const suffix = spec.slice(pkg.length + 1);
|
|
7519
|
-
const pkgDir =
|
|
7520
|
-
const candidate =
|
|
7760
|
+
const pkgDir = path28.dirname(path28.resolve(workspaceRoot, entryFile));
|
|
7761
|
+
const candidate = path28.join(pkgDir, suffix);
|
|
7521
7762
|
const hit = await firstExisting(candidate);
|
|
7522
7763
|
if (hit)
|
|
7523
7764
|
return hit;
|
|
@@ -7565,7 +7806,7 @@ async function firstExisting(basePath2) {
|
|
|
7565
7806
|
return candidate;
|
|
7566
7807
|
}
|
|
7567
7808
|
for (const ext of CANDIDATE_EXTS3) {
|
|
7568
|
-
const candidate =
|
|
7809
|
+
const candidate = path28.join(basePath2, `index${ext}`);
|
|
7569
7810
|
if (await Bun.file(candidate).exists())
|
|
7570
7811
|
return candidate;
|
|
7571
7812
|
}
|
|
@@ -7654,11 +7895,11 @@ class PagesBundleBuilder {
|
|
|
7654
7895
|
const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
|
|
7655
7896
|
if (!entryArtifact)
|
|
7656
7897
|
throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
|
|
7657
|
-
const bundlePath =
|
|
7898
|
+
const bundlePath = path29.resolve(entryArtifact.path);
|
|
7658
7899
|
const buildId = Date.now();
|
|
7659
7900
|
const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
|
|
7660
7901
|
const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
|
|
7661
|
-
this.#app.verbose(`[PagesBundleBuilder] ${
|
|
7902
|
+
this.#app.verbose(`[PagesBundleBuilder] ${path29.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
|
|
7662
7903
|
return {
|
|
7663
7904
|
bundlePath,
|
|
7664
7905
|
buildId,
|
|
@@ -7701,11 +7942,11 @@ class PagesBundleBuilder {
|
|
|
7701
7942
|
}
|
|
7702
7943
|
// pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
|
|
7703
7944
|
import fs5 from "fs";
|
|
7704
|
-
import
|
|
7945
|
+
import path30 from "path";
|
|
7705
7946
|
var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
|
|
7706
7947
|
var MIN_COMPRESS_BYTES = 1024;
|
|
7707
7948
|
async function precompressArtifacts(app) {
|
|
7708
|
-
const roots = [
|
|
7949
|
+
const roots = [path30.join(app.dist.cwdPath, ".akan/artifact/client")];
|
|
7709
7950
|
const result = { files: 0, inputBytes: 0, outputBytes: 0 };
|
|
7710
7951
|
await Promise.all(roots.map((root) => precompressRoot(root, result)));
|
|
7711
7952
|
if (result.files > 0) {
|
|
@@ -7731,7 +7972,7 @@ async function precompressRoot(root, result) {
|
|
|
7731
7972
|
async function shouldPrecompress(filePath) {
|
|
7732
7973
|
if (filePath.endsWith(".gz"))
|
|
7733
7974
|
return false;
|
|
7734
|
-
if (!COMPRESSIBLE_EXTS.has(
|
|
7975
|
+
if (!COMPRESSIBLE_EXTS.has(path30.extname(filePath).toLowerCase()))
|
|
7735
7976
|
return false;
|
|
7736
7977
|
const file = Bun.file(filePath);
|
|
7737
7978
|
if (!await file.exists())
|
|
@@ -7749,7 +7990,7 @@ function formatBytes(bytes) {
|
|
|
7749
7990
|
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
7750
7991
|
}
|
|
7751
7992
|
// pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
|
|
7752
|
-
import
|
|
7993
|
+
import path31 from "path";
|
|
7753
7994
|
import { optimize } from "@tailwindcss/node";
|
|
7754
7995
|
function prepareCssAsset(command, basePath2, cssText) {
|
|
7755
7996
|
return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: command === "build" }).code;
|
|
@@ -7765,7 +8006,7 @@ class SsrBaseArtifactBuilder {
|
|
|
7765
8006
|
this.#app = app;
|
|
7766
8007
|
this.#command = command;
|
|
7767
8008
|
this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
|
|
7768
|
-
this.#absArtifactDir =
|
|
8009
|
+
this.#absArtifactDir = path31.resolve(this.#artifactDir);
|
|
7769
8010
|
}
|
|
7770
8011
|
async build() {
|
|
7771
8012
|
const akanConfig2 = await this.#app.getConfig();
|
|
@@ -7785,7 +8026,7 @@ class SsrBaseArtifactBuilder {
|
|
|
7785
8026
|
rscClientUrl,
|
|
7786
8027
|
vendorMap,
|
|
7787
8028
|
cssAssets,
|
|
7788
|
-
pagesBundlePath: this.#command === "build" ?
|
|
8029
|
+
pagesBundlePath: this.#command === "build" ? path31.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
|
|
7789
8030
|
pagesBundleBuildId: pagesBundle.buildId,
|
|
7790
8031
|
domains: [...akanConfig2.domains],
|
|
7791
8032
|
subRoutes: Object.fromEntries(Array.from(akanConfig2.subRoutes.entries()).map(([basePath2, domains]) => [basePath2, [...domains]])),
|
|
@@ -7794,7 +8035,7 @@ class SsrBaseArtifactBuilder {
|
|
|
7794
8035
|
i18n: akanConfig2.i18n,
|
|
7795
8036
|
imageConfig: akanConfig2.images
|
|
7796
8037
|
};
|
|
7797
|
-
await Bun.write(
|
|
8038
|
+
await Bun.write(path31.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
|
|
7798
8039
|
`);
|
|
7799
8040
|
this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
|
|
7800
8041
|
return { artifact, seedIndex, cssCompiler, optimizedFonts };
|
|
@@ -7816,15 +8057,15 @@ class SsrBaseArtifactBuilder {
|
|
|
7816
8057
|
async#resolveAkanServerPath() {
|
|
7817
8058
|
const candidates = [];
|
|
7818
8059
|
try {
|
|
7819
|
-
candidates.push(
|
|
8060
|
+
candidates.push(path31.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
|
|
7820
8061
|
} catch {}
|
|
7821
|
-
candidates.push(
|
|
8062
|
+
candidates.push(path31.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path31.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
|
|
7822
8063
|
try {
|
|
7823
|
-
candidates.push(
|
|
8064
|
+
candidates.push(path31.dirname(Bun.resolveSync("akanjs/server", path31.dirname(Bun.main))));
|
|
7824
8065
|
} catch {}
|
|
7825
|
-
candidates.push(
|
|
8066
|
+
candidates.push(path31.join(path31.dirname(Bun.main), "node_modules/akanjs/server"), path31.join(path31.dirname(Bun.main), "../../akanjs/server"), path31.resolve(import.meta.dir, "../../server"), path31.resolve(import.meta.dir, "../server"));
|
|
7826
8067
|
for (const candidate of candidates) {
|
|
7827
|
-
if (await Bun.file(
|
|
8068
|
+
if (await Bun.file(path31.join(candidate, "rscClient.tsx")).exists())
|
|
7828
8069
|
return candidate;
|
|
7829
8070
|
}
|
|
7830
8071
|
throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
|
|
@@ -7853,14 +8094,14 @@ ${preparedCssText}`).toString(36);
|
|
|
7853
8094
|
`styles/${cssAssetName}-${cssHash}.css`,
|
|
7854
8095
|
`/_akan/styles/${cssAssetName}-${cssHash}.css`
|
|
7855
8096
|
];
|
|
7856
|
-
await Bun.write(
|
|
8097
|
+
await Bun.write(path31.join(this.#absArtifactDir, cssRelPath), preparedCssText);
|
|
7857
8098
|
this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
|
|
7858
8099
|
return [basePath2, { cssUrl, cssRelPath }];
|
|
7859
8100
|
}
|
|
7860
8101
|
}
|
|
7861
8102
|
// pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
|
|
7862
8103
|
import fs6 from "fs";
|
|
7863
|
-
import
|
|
8104
|
+
import path32 from "path";
|
|
7864
8105
|
|
|
7865
8106
|
class WatchRootResolver {
|
|
7866
8107
|
#app;
|
|
@@ -7870,15 +8111,15 @@ class WatchRootResolver {
|
|
|
7870
8111
|
async resolve() {
|
|
7871
8112
|
const tsconfig = await this.#app.getTsConfig();
|
|
7872
8113
|
const set = new Set;
|
|
7873
|
-
set.add(
|
|
8114
|
+
set.add(path32.resolve(`${this.#app.cwdPath}/page`));
|
|
7874
8115
|
for (const targets of Object.values(tsconfig.compilerOptions.paths ?? {})) {
|
|
7875
8116
|
for (const target of targets) {
|
|
7876
8117
|
if (!target)
|
|
7877
8118
|
continue;
|
|
7878
|
-
if (
|
|
8119
|
+
if (path32.isAbsolute(target))
|
|
7879
8120
|
continue;
|
|
7880
8121
|
const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
|
|
7881
|
-
const resolved =
|
|
8122
|
+
const resolved = path32.resolve(this.#app.workspace.workspaceRoot, cleaned);
|
|
7882
8123
|
if (fs6.existsSync(resolved))
|
|
7883
8124
|
set.add(resolved);
|
|
7884
8125
|
}
|
|
@@ -7945,7 +8186,7 @@ class ApplicationBuildRunner {
|
|
|
7945
8186
|
phases: this.#phases,
|
|
7946
8187
|
durationMs: Date.now() - this.#startedAt,
|
|
7947
8188
|
outputDir: this.#app.dist.cwdPath,
|
|
7948
|
-
artifactDir:
|
|
8189
|
+
artifactDir: path33.join(this.#app.dist.cwdPath, ".akan/artifact")
|
|
7949
8190
|
};
|
|
7950
8191
|
}
|
|
7951
8192
|
async typecheck(options = {}) {
|
|
@@ -7953,7 +8194,7 @@ class ApplicationBuildRunner {
|
|
|
7953
8194
|
await this.#app.getPageKeys({ refresh: true });
|
|
7954
8195
|
const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
|
|
7955
8196
|
if (clean)
|
|
7956
|
-
await rm2(
|
|
8197
|
+
await rm2(path33.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
|
|
7957
8198
|
await this.#checkProjectInChildProcess(tsconfigPath);
|
|
7958
8199
|
}
|
|
7959
8200
|
async#runPhase(id, label, task, summarize, options = {}) {
|
|
@@ -7996,6 +8237,7 @@ class ApplicationBuildRunner {
|
|
|
7996
8237
|
outdir: this.#app.dist.cwdPath,
|
|
7997
8238
|
target: "bun",
|
|
7998
8239
|
minify: true,
|
|
8240
|
+
naming: { entry: "[name].[ext]", chunk: "chunk-[hash].[ext]" },
|
|
7999
8241
|
define: { "process.env.NODE_ENV": JSON.stringify("production") },
|
|
8000
8242
|
plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
|
|
8001
8243
|
});
|
|
@@ -8009,16 +8251,52 @@ class ApplicationBuildRunner {
|
|
|
8009
8251
|
define: { "process.env.NODE_ENV": JSON.stringify("production") },
|
|
8010
8252
|
plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
|
|
8011
8253
|
});
|
|
8254
|
+
const consoleRuntimeResult = await this.#buildOrThrow("console-runtime", {
|
|
8255
|
+
entrypoints: [this.#resolveConsoleRuntimeBuildEntry()],
|
|
8256
|
+
outdir: this.#app.dist.cwdPath,
|
|
8257
|
+
target: "bun",
|
|
8258
|
+
minify: true,
|
|
8259
|
+
naming: { entry: "console-runtime.[ext]", chunk: "chunk-[hash].[ext]" },
|
|
8260
|
+
define: { "process.env.NODE_ENV": JSON.stringify("production") }
|
|
8261
|
+
});
|
|
8262
|
+
await this.#writeConsoleShim();
|
|
8012
8263
|
return {
|
|
8013
|
-
entrypoints: backendEntryPoints.length +
|
|
8014
|
-
outputs: backendResult.outputs.length + rscWorkerResult.outputs.length
|
|
8264
|
+
entrypoints: backendEntryPoints.length + 2,
|
|
8265
|
+
outputs: backendResult.outputs.length + rscWorkerResult.outputs.length + consoleRuntimeResult.outputs.length + 1
|
|
8015
8266
|
};
|
|
8016
8267
|
}
|
|
8268
|
+
async#writeConsoleShim() {
|
|
8269
|
+
await Bun.write(path33.join(this.#app.dist.cwdPath, "console.js"), `import { cnst, db, dict, option, server, sig, srv } from "./server.js";
|
|
8270
|
+
import { assertAkanConsoleAllowed, startAkanConsole } from "./console-runtime.js";
|
|
8271
|
+
|
|
8272
|
+
const run = async () => {
|
|
8273
|
+
assertAkanConsoleAllowed(server.env);
|
|
8274
|
+
await server.start({ listen: false, web: false });
|
|
8275
|
+
try {
|
|
8276
|
+
await startAkanConsole(server, { globals: { cnst, db, dict, option, sig, srv } });
|
|
8277
|
+
} finally {
|
|
8278
|
+
await server.stop();
|
|
8279
|
+
}
|
|
8280
|
+
};
|
|
8281
|
+
|
|
8282
|
+
void run().catch((error) => {
|
|
8283
|
+
console.error(error);
|
|
8284
|
+
process.exit(1);
|
|
8285
|
+
});
|
|
8286
|
+
`);
|
|
8287
|
+
}
|
|
8017
8288
|
#resolveRscWorkerBuildEntry() {
|
|
8018
8289
|
try {
|
|
8019
8290
|
return Bun.resolveSync("akanjs/server/rsc-worker", import.meta.dir);
|
|
8020
8291
|
} catch {
|
|
8021
|
-
return
|
|
8292
|
+
return path33.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
|
|
8293
|
+
}
|
|
8294
|
+
}
|
|
8295
|
+
#resolveConsoleRuntimeBuildEntry() {
|
|
8296
|
+
try {
|
|
8297
|
+
return path33.join(path33.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
|
|
8298
|
+
} catch {
|
|
8299
|
+
return path33.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
|
|
8022
8300
|
}
|
|
8023
8301
|
}
|
|
8024
8302
|
async#buildCsr() {
|
|
@@ -8035,7 +8313,7 @@ class ApplicationBuildRunner {
|
|
|
8035
8313
|
return { base, allRoutes };
|
|
8036
8314
|
}
|
|
8037
8315
|
async#writeTypecheckTsconfig({ incremental = true } = {}) {
|
|
8038
|
-
const typecheckDir =
|
|
8316
|
+
const typecheckDir = path33.join(this.#app.cwdPath, ".akan", "typecheck");
|
|
8039
8317
|
await mkdir7(typecheckDir, { recursive: true });
|
|
8040
8318
|
const tsconfig = {
|
|
8041
8319
|
extends: "../../tsconfig.json",
|
|
@@ -8054,7 +8332,7 @@ class ApplicationBuildRunner {
|
|
|
8054
8332
|
],
|
|
8055
8333
|
references: []
|
|
8056
8334
|
};
|
|
8057
|
-
const tsconfigPath =
|
|
8335
|
+
const tsconfigPath = path33.join(typecheckDir, "tsconfig.json");
|
|
8058
8336
|
await Bun.write(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
8059
8337
|
`);
|
|
8060
8338
|
return { typecheckDir, tsconfigPath };
|
|
@@ -8080,10 +8358,10 @@ class ApplicationBuildRunner {
|
|
|
8080
8358
|
}
|
|
8081
8359
|
async#resolveTypecheckWorkerEntry() {
|
|
8082
8360
|
const candidates = [
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8361
|
+
path33.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
8362
|
+
path33.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
8363
|
+
path33.join(import.meta.dir, "typecheck.proc.js"),
|
|
8364
|
+
path33.join(import.meta.dir, "typecheck.proc.ts")
|
|
8087
8365
|
];
|
|
8088
8366
|
for (const candidate of candidates)
|
|
8089
8367
|
if (await Bun.file(candidate).exists())
|
|
@@ -8259,13 +8537,13 @@ class ApplicationReleasePackager {
|
|
|
8259
8537
|
await cp(this.#app.dist.cwdPath, `${sourceRoot}/apps/${this.#app.name}`, { recursive: true });
|
|
8260
8538
|
const libDeps = ["social", "shared", "platform", "util"];
|
|
8261
8539
|
await Promise.all(libDeps.map((lib) => cp(`${this.#app.workspace.cwdPath}/libs/${lib}`, `${sourceRoot}/libs/${lib}`, { recursive: true })));
|
|
8262
|
-
await Promise.all([".next", "ios", "android", "public/libs"].map(async (
|
|
8263
|
-
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${
|
|
8540
|
+
await Promise.all([".next", "ios", "android", "public/libs"].map(async (path34) => {
|
|
8541
|
+
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path34}`;
|
|
8264
8542
|
if (await FileSys.dirExists(targetPath))
|
|
8265
8543
|
await rm3(targetPath, { recursive: true, force: true });
|
|
8266
8544
|
}));
|
|
8267
8545
|
const syncPaths = [".husky", ".gitignore", "package.json"];
|
|
8268
|
-
await Promise.all(syncPaths.map((
|
|
8546
|
+
await Promise.all(syncPaths.map((path34) => cp(`${this.#app.workspace.cwdPath}/${path34}`, `${sourceRoot}/${path34}`, { recursive: true })));
|
|
8269
8547
|
await this.#writeSourceTsconfig(sourceRoot, libDeps);
|
|
8270
8548
|
await Bun.write(`${sourceRoot}/README.md`, readme);
|
|
8271
8549
|
await this.#app.workspace.spawn("tar", [
|
|
@@ -8356,20 +8634,20 @@ class ApplicationReleasePackager {
|
|
|
8356
8634
|
}
|
|
8357
8635
|
}
|
|
8358
8636
|
// pkgs/@akanjs/devkit/applicationTestPreload.ts
|
|
8359
|
-
import
|
|
8637
|
+
import path34 from "path";
|
|
8360
8638
|
var SIGNAL_TEST_PRELOAD_PATH = "test/signalTest.preload.ts";
|
|
8361
8639
|
async function resolveSignalTestPreloadPath(target) {
|
|
8362
8640
|
const candidates = [];
|
|
8363
8641
|
const addResolvedPackageCandidate = (basePath2) => {
|
|
8364
8642
|
try {
|
|
8365
|
-
candidates.push(
|
|
8643
|
+
candidates.push(path34.join(path34.dirname(Bun.resolveSync("akanjs/package.json", basePath2)), SIGNAL_TEST_PRELOAD_PATH));
|
|
8366
8644
|
} catch {}
|
|
8367
8645
|
};
|
|
8368
8646
|
addResolvedPackageCandidate(target.cwdPath);
|
|
8369
8647
|
addResolvedPackageCandidate(process.cwd());
|
|
8370
|
-
addResolvedPackageCandidate(
|
|
8648
|
+
addResolvedPackageCandidate(path34.dirname(Bun.main));
|
|
8371
8649
|
addResolvedPackageCandidate(import.meta.dir);
|
|
8372
|
-
candidates.push(
|
|
8650
|
+
candidates.push(path34.join(target.cwdPath, "../../node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path34.join(target.cwdPath, "../../pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path34.join(process.cwd(), "node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path34.join(process.cwd(), "pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path34.join(path34.dirname(Bun.main), "../../akanjs", SIGNAL_TEST_PRELOAD_PATH), path34.resolve(import.meta.dir, "../../akanjs", SIGNAL_TEST_PRELOAD_PATH));
|
|
8373
8651
|
for (const candidate of [...new Set(candidates)]) {
|
|
8374
8652
|
if (await Bun.file(candidate).exists())
|
|
8375
8653
|
return candidate;
|
|
@@ -8379,7 +8657,7 @@ async function resolveSignalTestPreloadPath(target) {
|
|
|
8379
8657
|
// pkgs/@akanjs/devkit/builder.ts
|
|
8380
8658
|
import { existsSync as existsSync2 } from "fs";
|
|
8381
8659
|
import { mkdir as mkdir9 } from "fs/promises";
|
|
8382
|
-
import
|
|
8660
|
+
import path35 from "path";
|
|
8383
8661
|
var SKIP_ENTRY_DIR_SET = new Set(["node_modules", "dist", "build", ".git", ".next"]);
|
|
8384
8662
|
var assetExtensions = [".css", ".md", ".js", ".png", ".ico", ".svg", ".json", ".template"];
|
|
8385
8663
|
var assetLoader = Object.fromEntries(assetExtensions.map((ext) => [ext, "file"]));
|
|
@@ -8396,14 +8674,14 @@ class Builder {
|
|
|
8396
8674
|
#globEntrypoints(cwd, pattern) {
|
|
8397
8675
|
const glob = new Bun.Glob(pattern);
|
|
8398
8676
|
return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
|
|
8399
|
-
const segments = relativePath.split(
|
|
8677
|
+
const segments = relativePath.split(path35.sep);
|
|
8400
8678
|
return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
|
|
8401
|
-
}).map((rel) =>
|
|
8679
|
+
}).map((rel) => path35.join(cwd, rel));
|
|
8402
8680
|
}
|
|
8403
8681
|
#globFiles(cwd, pattern = "**/*.*") {
|
|
8404
8682
|
const glob = new Bun.Glob(pattern);
|
|
8405
8683
|
return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
|
|
8406
|
-
const segments = relativePath.split(
|
|
8684
|
+
const segments = relativePath.split(path35.sep);
|
|
8407
8685
|
return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
|
|
8408
8686
|
});
|
|
8409
8687
|
}
|
|
@@ -8411,17 +8689,17 @@ class Builder {
|
|
|
8411
8689
|
const out = [];
|
|
8412
8690
|
for (const p of additionalEntryPoints) {
|
|
8413
8691
|
if (p.includes("*")) {
|
|
8414
|
-
const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${
|
|
8692
|
+
const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path35.sep}`) ? p.slice(cwd.length + 1) : p;
|
|
8415
8693
|
out.push(...this.#globEntrypoints(cwd, rel));
|
|
8416
8694
|
} else
|
|
8417
|
-
out.push(
|
|
8695
|
+
out.push(path35.isAbsolute(p) ? p : path35.join(cwd, p));
|
|
8418
8696
|
}
|
|
8419
8697
|
return out;
|
|
8420
8698
|
}
|
|
8421
8699
|
#getBuildOptions({ bundle = false, additionalEntryPoints = [] } = {}) {
|
|
8422
8700
|
const cwd = this.#executor.cwdPath;
|
|
8423
8701
|
const entrypoints = [
|
|
8424
|
-
...bundle ? [
|
|
8702
|
+
...bundle ? [path35.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
|
|
8425
8703
|
...this.#resolveAdditionalEntrypoints(cwd, additionalEntryPoints)
|
|
8426
8704
|
];
|
|
8427
8705
|
return {
|
|
@@ -8442,9 +8720,9 @@ class Builder {
|
|
|
8442
8720
|
for (const relativePath of this.#globFiles(cwd)) {
|
|
8443
8721
|
if (relativePath === "package.json")
|
|
8444
8722
|
continue;
|
|
8445
|
-
const sourcePath =
|
|
8446
|
-
const targetPath =
|
|
8447
|
-
await mkdir9(
|
|
8723
|
+
const sourcePath = path35.join(cwd, relativePath);
|
|
8724
|
+
const targetPath = path35.join(this.#distExecutor.cwdPath, relativePath);
|
|
8725
|
+
await mkdir9(path35.dirname(targetPath), { recursive: true });
|
|
8448
8726
|
await Bun.write(targetPath, Bun.file(sourcePath));
|
|
8449
8727
|
}
|
|
8450
8728
|
}
|
|
@@ -8455,13 +8733,13 @@ class Builder {
|
|
|
8455
8733
|
return withoutFormatDir;
|
|
8456
8734
|
if (!hasDotSlash && withoutFormatDir === publishedPath)
|
|
8457
8735
|
return publishedPath;
|
|
8458
|
-
const parsed =
|
|
8736
|
+
const parsed = path35.posix.parse(withoutFormatDir);
|
|
8459
8737
|
if (![".js", ".mjs", ".cjs"].includes(parsed.ext))
|
|
8460
8738
|
return withoutFormatDir;
|
|
8461
|
-
const withoutExt =
|
|
8739
|
+
const withoutExt = path35.posix.join(parsed.dir, parsed.name);
|
|
8462
8740
|
const sourcePath = withoutExt.startsWith("./") ? withoutExt.slice(2) : withoutExt;
|
|
8463
8741
|
const sourceCandidates = [`${sourcePath}.ts`, `${sourcePath}.tsx`];
|
|
8464
|
-
const matchedSource = sourceCandidates.find((candidate) => existsSync2(
|
|
8742
|
+
const matchedSource = sourceCandidates.find((candidate) => existsSync2(path35.join(this.#executor.cwdPath, candidate)));
|
|
8465
8743
|
if (!matchedSource)
|
|
8466
8744
|
return withoutFormatDir;
|
|
8467
8745
|
return hasDotSlash ? `./${matchedSource}` : matchedSource;
|
|
@@ -8511,9 +8789,9 @@ class Builder {
|
|
|
8511
8789
|
}
|
|
8512
8790
|
// pkgs/@akanjs/devkit/capacitorApp.ts
|
|
8513
8791
|
import { cp as cp2, mkdir as mkdir10, rm as rm4 } from "fs/promises";
|
|
8514
|
-
import
|
|
8792
|
+
import path36 from "path";
|
|
8515
8793
|
import { MobileProject } from "@trapezedev/project";
|
|
8516
|
-
import { capitalize as
|
|
8794
|
+
import { capitalize as capitalize3 } from "akanjs/common";
|
|
8517
8795
|
|
|
8518
8796
|
// pkgs/@akanjs/devkit/fileEditor.ts
|
|
8519
8797
|
class FileEditor {
|
|
@@ -8706,10 +8984,10 @@ class CapacitorApp {
|
|
|
8706
8984
|
constructor(app, target) {
|
|
8707
8985
|
this.app = app;
|
|
8708
8986
|
this.target = target;
|
|
8709
|
-
this.targetRootPath =
|
|
8710
|
-
this.targetRoot =
|
|
8711
|
-
this.targetWebRoot =
|
|
8712
|
-
this.targetAssetRoot =
|
|
8987
|
+
this.targetRootPath = path36.posix.join(".akan", "mobile", this.target.name);
|
|
8988
|
+
this.targetRoot = path36.join(this.app.cwdPath, this.targetRootPath);
|
|
8989
|
+
this.targetWebRoot = path36.join(this.targetRoot, "www");
|
|
8990
|
+
this.targetAssetRoot = path36.join(this.targetRoot, "assets");
|
|
8713
8991
|
this.project = new MobileProject(this.app.cwdPath, {
|
|
8714
8992
|
android: { path: this.androidRootPath },
|
|
8715
8993
|
ios: { path: this.iosProjectPath }
|
|
@@ -8725,9 +9003,9 @@ class CapacitorApp {
|
|
|
8725
9003
|
await this.#writeCapacitorConfig();
|
|
8726
9004
|
if (regenerate) {
|
|
8727
9005
|
if (!platform || platform === "ios")
|
|
8728
|
-
await rm4(
|
|
9006
|
+
await rm4(path36.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
|
|
8729
9007
|
if (!platform || platform === "android")
|
|
8730
|
-
await rm4(
|
|
9008
|
+
await rm4(path36.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
|
|
8731
9009
|
}
|
|
8732
9010
|
const project = this.project;
|
|
8733
9011
|
await this.project.load();
|
|
@@ -8791,7 +9069,7 @@ class CapacitorApp {
|
|
|
8791
9069
|
await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
|
|
8792
9070
|
}
|
|
8793
9071
|
async#updateAndroidBuildTypes() {
|
|
8794
|
-
const appGradle = await FileEditor.create(
|
|
9072
|
+
const appGradle = await FileEditor.create(path36.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
|
|
8795
9073
|
const buildTypesBlock = `
|
|
8796
9074
|
debug {
|
|
8797
9075
|
applicationIdSuffix ".debug"
|
|
@@ -8834,7 +9112,7 @@ class CapacitorApp {
|
|
|
8834
9112
|
const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
|
|
8835
9113
|
await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
|
|
8836
9114
|
stdio: "inherit",
|
|
8837
|
-
cwd:
|
|
9115
|
+
cwd: path36.join(this.app.cwdPath, this.androidRootPath),
|
|
8838
9116
|
env: await this.#commandEnv("release", env)
|
|
8839
9117
|
});
|
|
8840
9118
|
}
|
|
@@ -8842,10 +9120,10 @@ class CapacitorApp {
|
|
|
8842
9120
|
await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
|
|
8843
9121
|
}
|
|
8844
9122
|
async#ensureAndroidAssetsDir() {
|
|
8845
|
-
await mkdir10(
|
|
9123
|
+
await mkdir10(path36.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
|
|
8846
9124
|
}
|
|
8847
9125
|
async#ensureAndroidDebugKeystore() {
|
|
8848
|
-
const keystorePath =
|
|
9126
|
+
const keystorePath = path36.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
|
|
8849
9127
|
if (await Bun.file(keystorePath).exists())
|
|
8850
9128
|
return;
|
|
8851
9129
|
await this.#spawn("keytool", [
|
|
@@ -8891,12 +9169,12 @@ class CapacitorApp {
|
|
|
8891
9169
|
await this.#prepareAndroid({ operation: "release", env: "main" });
|
|
8892
9170
|
}
|
|
8893
9171
|
async prepareWww() {
|
|
8894
|
-
const htmlSource =
|
|
9172
|
+
const htmlSource = path36.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
|
|
8895
9173
|
if (!await Bun.file(htmlSource).exists())
|
|
8896
9174
|
throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
|
|
8897
9175
|
await rm4(this.targetWebRoot, { recursive: true, force: true });
|
|
8898
9176
|
await mkdir10(this.targetWebRoot, { recursive: true });
|
|
8899
|
-
await Bun.write(
|
|
9177
|
+
await Bun.write(path36.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
|
|
8900
9178
|
}
|
|
8901
9179
|
#injectMobileTargetMeta(html) {
|
|
8902
9180
|
const basePath2 = this.target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
|
|
@@ -8908,7 +9186,7 @@ class CapacitorApp {
|
|
|
8908
9186
|
}
|
|
8909
9187
|
async#writeCapacitorConfig() {
|
|
8910
9188
|
await mkdir10(this.targetRoot, { recursive: true });
|
|
8911
|
-
const appInfoPath =
|
|
9189
|
+
const appInfoPath = path36.relative(this.app.cwdPath, path36.join(this.app.cwdPath, "akan.app.json")).split(path36.sep).join("/");
|
|
8912
9190
|
const content = `import type { AppScanResult } from "akanjs";
|
|
8913
9191
|
import { withBase } from "${process.env.USE_AKANJS_PKGS === "true" ? "../../pkgs/" : ""}akanjs/capacitor.base.config";
|
|
8914
9192
|
import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
|
|
@@ -8929,18 +9207,18 @@ export default withBase(
|
|
|
8929
9207
|
appInfo as AppScanResult,
|
|
8930
9208
|
);
|
|
8931
9209
|
`;
|
|
8932
|
-
await Bun.write(
|
|
9210
|
+
await Bun.write(path36.join(this.app.cwdPath, "capacitor.config.ts"), content);
|
|
8933
9211
|
}
|
|
8934
9212
|
async#prepareTargetAssets() {
|
|
8935
9213
|
if (!this.target.assets)
|
|
8936
9214
|
return;
|
|
8937
9215
|
await mkdir10(this.targetAssetRoot, { recursive: true });
|
|
8938
9216
|
if (this.target.assets.icon)
|
|
8939
|
-
await cp2(
|
|
9217
|
+
await cp2(path36.join(this.app.cwdPath, this.target.assets.icon), path36.join(this.targetAssetRoot, "icon.png"), {
|
|
8940
9218
|
force: true
|
|
8941
9219
|
});
|
|
8942
9220
|
if (this.target.assets.splash)
|
|
8943
|
-
await cp2(
|
|
9221
|
+
await cp2(path36.join(this.app.cwdPath, this.target.assets.splash), path36.join(this.targetAssetRoot, "splash.png"), {
|
|
8944
9222
|
force: true
|
|
8945
9223
|
});
|
|
8946
9224
|
}
|
|
@@ -8948,11 +9226,11 @@ export default withBase(
|
|
|
8948
9226
|
const files = this.target.files?.[platform];
|
|
8949
9227
|
if (!files)
|
|
8950
9228
|
return;
|
|
8951
|
-
const platformRoot =
|
|
9229
|
+
const platformRoot = path36.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
|
|
8952
9230
|
await Promise.all(Object.entries(files).map(async ([to, from]) => {
|
|
8953
|
-
const targetPath =
|
|
8954
|
-
await mkdir10(
|
|
8955
|
-
await cp2(
|
|
9231
|
+
const targetPath = path36.join(platformRoot, to);
|
|
9232
|
+
await mkdir10(path36.dirname(targetPath), { recursive: true });
|
|
9233
|
+
await cp2(path36.join(this.app.cwdPath, from), targetPath, { force: true });
|
|
8956
9234
|
}));
|
|
8957
9235
|
}
|
|
8958
9236
|
async#generateAssets({ operation, env }) {
|
|
@@ -8962,7 +9240,7 @@ export default withBase(
|
|
|
8962
9240
|
"@capacitor/assets",
|
|
8963
9241
|
"generate",
|
|
8964
9242
|
"--assetPath",
|
|
8965
|
-
|
|
9243
|
+
path36.posix.join(this.targetRootPath, "assets"),
|
|
8966
9244
|
"--iosProject",
|
|
8967
9245
|
this.iosProjectPath,
|
|
8968
9246
|
"--androidProject",
|
|
@@ -9064,7 +9342,7 @@ export default withBase(
|
|
|
9064
9342
|
this.#setPermissionsInAndroid(["POST_NOTIFICATIONS"]);
|
|
9065
9343
|
}
|
|
9066
9344
|
async#setPermissionInIos(permissions) {
|
|
9067
|
-
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${
|
|
9345
|
+
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${capitalize3(key)}`, value]));
|
|
9068
9346
|
await Promise.all([
|
|
9069
9347
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", updateNs),
|
|
9070
9348
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", updateNs)
|
|
@@ -9149,15 +9427,15 @@ var Pkg = createInternalArgToken("Pkg");
|
|
|
9149
9427
|
var Module = createInternalArgToken("Module");
|
|
9150
9428
|
var Workspace = createInternalArgToken("Workspace");
|
|
9151
9429
|
// pkgs/@akanjs/devkit/commandDecorators/command.ts
|
|
9152
|
-
import
|
|
9430
|
+
import path37 from "path";
|
|
9153
9431
|
import { confirm, input as input2, select as select2 } from "@inquirer/prompts";
|
|
9154
9432
|
import { Logger as Logger10 } from "akanjs/common";
|
|
9155
9433
|
import chalk6 from "chalk";
|
|
9156
9434
|
import { program } from "commander";
|
|
9157
9435
|
|
|
9158
9436
|
// pkgs/@akanjs/devkit/commandDecorators/dependencyBuilder.ts
|
|
9159
|
-
var
|
|
9160
|
-
var createDependencyKey = (refName, kind) => `${refName}${
|
|
9437
|
+
var capitalize4 = (value) => value.slice(0, 1).toUpperCase() + value.slice(1);
|
|
9438
|
+
var createDependencyKey = (refName, kind) => `${refName}${capitalize4(kind)}`;
|
|
9161
9439
|
|
|
9162
9440
|
class CommandContainer {
|
|
9163
9441
|
static #instances = new Map;
|
|
@@ -9649,7 +9927,7 @@ var runCommands = async (...commands) => {
|
|
|
9649
9927
|
process.exit(1);
|
|
9650
9928
|
});
|
|
9651
9929
|
const __dirname2 = getDirname(import.meta.url);
|
|
9652
|
-
const packageJsonCandidates = [`${
|
|
9930
|
+
const packageJsonCandidates = [`${path37.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
|
|
9653
9931
|
let cliPackageJson = null;
|
|
9654
9932
|
for (const packageJsonPath of packageJsonCandidates) {
|
|
9655
9933
|
if (!await FileSys.fileExists(packageJsonPath))
|
|
@@ -9925,8 +10203,8 @@ var scanModuleSpecifiers = (source, filePath, includeExports) => {
|
|
|
9925
10203
|
return importSpecifiers;
|
|
9926
10204
|
};
|
|
9927
10205
|
var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
|
|
9928
|
-
const configFile = ts7.readConfigFile(tsConfigPath, (
|
|
9929
|
-
return ts7.sys.readFile(
|
|
10206
|
+
const configFile = ts7.readConfigFile(tsConfigPath, (path38) => {
|
|
10207
|
+
return ts7.sys.readFile(path38);
|
|
9930
10208
|
});
|
|
9931
10209
|
return ts7.parseJsonConfigFileContent(configFile.config, ts7.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
|
|
9932
10210
|
};
|
|
@@ -10075,10 +10353,7 @@ import { input as input3, select as select3 } from "@inquirer/prompts";
|
|
|
10075
10353
|
class Prompter {
|
|
10076
10354
|
static async#getGuidelineRoot() {
|
|
10077
10355
|
const dirname2 = getDirname(import.meta.url);
|
|
10078
|
-
const candidates = [
|
|
10079
|
-
`${dirname2}/guidelines`,
|
|
10080
|
-
`${dirname2}/../cli/guidelines`
|
|
10081
|
-
];
|
|
10356
|
+
const candidates = [`${dirname2}/guidelines`, `${dirname2}/../cli/guidelines`];
|
|
10082
10357
|
for (const candidate of candidates) {
|
|
10083
10358
|
try {
|
|
10084
10359
|
await fsPromise.access(candidate);
|
|
@@ -10089,12 +10364,16 @@ class Prompter {
|
|
|
10089
10364
|
}
|
|
10090
10365
|
static async selectGuideline() {
|
|
10091
10366
|
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
10092
|
-
const guideNames =
|
|
10367
|
+
const guideNames = await Prompter.listGuidelines();
|
|
10093
10368
|
return await select3({
|
|
10094
10369
|
message: "Select a guideline",
|
|
10095
10370
|
choices: guideNames.map((name) => ({ name, value: name }))
|
|
10096
10371
|
});
|
|
10097
10372
|
}
|
|
10373
|
+
static async listGuidelines() {
|
|
10374
|
+
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
10375
|
+
return (await fsPromise.readdir(guidelineRoot)).filter((name) => !name.startsWith("_")).sort();
|
|
10376
|
+
}
|
|
10098
10377
|
static async getGuideJson(guideName) {
|
|
10099
10378
|
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
10100
10379
|
const filePath = `${guidelineRoot}/${guideName}/${guideName}.generate.json`;
|
|
@@ -10165,12 +10444,106 @@ import { Box as Box2, Newline, Text as Text2, useInput as useInput2 } from "ink"
|
|
|
10165
10444
|
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
10166
10445
|
import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
|
|
10167
10446
|
"use client";
|
|
10447
|
+
// pkgs/@akanjs/cli/agent/agent.script.ts
|
|
10448
|
+
import { Logger as Logger11 } from "akanjs/common";
|
|
10449
|
+
|
|
10450
|
+
// pkgs/@akanjs/cli/agent/agent.runner.ts
|
|
10451
|
+
var targetPaths = {
|
|
10452
|
+
cursor: ".cursor/rules/akan.mdc",
|
|
10453
|
+
"agents-md": "AGENTS.md",
|
|
10454
|
+
claude: "CLAUDE.md"
|
|
10455
|
+
};
|
|
10456
|
+
var targetTitle = {
|
|
10457
|
+
cursor: "Akan Cursor Rules",
|
|
10458
|
+
"agents-md": "Akan Agent Rules",
|
|
10459
|
+
claude: "Akan Claude Rules"
|
|
10460
|
+
};
|
|
10461
|
+
var renderAgentRules = async (workspace, target) => {
|
|
10462
|
+
const context = await AkanContextAnalyzer.analyze(workspace);
|
|
10463
|
+
const frameworkGuide = await Prompter.getInstruction("framework");
|
|
10464
|
+
return `# ${targetTitle[target]}
|
|
10465
|
+
|
|
10466
|
+
This file is generated by \`akan agent install ${target}\`.
|
|
10467
|
+
|
|
10468
|
+
## Workspace
|
|
10469
|
+
|
|
10470
|
+
- Repo: ${context.repoName}
|
|
10471
|
+
- Apps: ${context.apps.map((app) => app.name).join(", ") || "none"}
|
|
10472
|
+
- Libraries: ${context.libs.map((lib) => lib.name).join(", ") || "none"}
|
|
10473
|
+
- Packages: ${context.pkgs.map((pkg) => pkg.name).join(", ") || "none"}
|
|
10474
|
+
|
|
10475
|
+
## Akan Module Abstracts
|
|
10476
|
+
|
|
10477
|
+
- Before changing a domain, service, or scalar module, read its \`*.abstract.md\` file first.
|
|
10478
|
+
- Update the abstract when business invariants, workflows, or public behavior change.
|
|
10479
|
+
- Do not update the abstract for formatting-only, import-only, or style-only changes.
|
|
10480
|
+
- Service modules live in \`lib/_<service>\`, but their abstract file is \`<service>.abstract.md\`.
|
|
10481
|
+
|
|
10482
|
+
## Generated Files
|
|
10483
|
+
|
|
10484
|
+
Do not hand-edit generated registry files such as ${context.generatedFiles.map((file) => `\`${file}\``).join(", ")}.
|
|
10485
|
+
|
|
10486
|
+
## Validation
|
|
10487
|
+
|
|
10488
|
+
${context.validationCommands.map((command3) => `- \`${command3}\``).join(`
|
|
10489
|
+
`)}
|
|
10490
|
+
|
|
10491
|
+
## Framework Guide
|
|
10492
|
+
|
|
10493
|
+
${frameworkGuide.trim()}
|
|
10494
|
+
`;
|
|
10495
|
+
};
|
|
10496
|
+
|
|
10497
|
+
class AgentRunner extends runner("agent") {
|
|
10498
|
+
async install(workspace, targets, { force = false } = {}) {
|
|
10499
|
+
const written = [];
|
|
10500
|
+
for (const target of targets) {
|
|
10501
|
+
const filePath = targetPaths[target];
|
|
10502
|
+
if (!force && await workspace.exists(filePath)) {
|
|
10503
|
+
throw new Error(`${filePath} already exists. Re-run with --force to overwrite it.`);
|
|
10504
|
+
}
|
|
10505
|
+
const content = await renderAgentRules(workspace, target);
|
|
10506
|
+
await workspace.writeFile(filePath, content, { overwrite: force });
|
|
10507
|
+
written.push(filePath);
|
|
10508
|
+
}
|
|
10509
|
+
return written;
|
|
10510
|
+
}
|
|
10511
|
+
}
|
|
10512
|
+
|
|
10513
|
+
// pkgs/@akanjs/cli/agent/agent.script.ts
|
|
10514
|
+
var resolveTargets = (target) => {
|
|
10515
|
+
if (!target || target === "all")
|
|
10516
|
+
return ["cursor", "agents-md", "claude"];
|
|
10517
|
+
if (target === "cursor" || target === "agents-md" || target === "claude")
|
|
10518
|
+
return [target];
|
|
10519
|
+
throw new Error(`Unknown agent target: ${target}. Use cursor, agents-md, claude, or all.`);
|
|
10520
|
+
};
|
|
10521
|
+
|
|
10522
|
+
class AgentScript extends script("agent", [AgentRunner]) {
|
|
10523
|
+
async agent(workspace, action, target, { force = false } = {}) {
|
|
10524
|
+
if (action !== "install")
|
|
10525
|
+
throw new Error(`Unknown agent action: ${action}. Use "install".`);
|
|
10526
|
+
const written = await this.agentRunner.install(workspace, resolveTargets(target), { force });
|
|
10527
|
+
Logger11.rawLog(`Agent rules written:
|
|
10528
|
+
${written.map((file) => `- ${file}`).join(`
|
|
10529
|
+
`)}`);
|
|
10530
|
+
}
|
|
10531
|
+
}
|
|
10532
|
+
|
|
10533
|
+
// pkgs/@akanjs/cli/agent/agent.command.ts
|
|
10534
|
+
class AgentCommand extends command("agent", [AgentScript], ({ public: target }) => ({
|
|
10535
|
+
agent: target({ desc: "Install Akan agent rules for editors and coding agents" }).arg("action", String, { desc: "install" }).arg("target", String, { desc: "cursor, agents-md, claude, or all", nullable: true }).option("force", Boolean, { desc: "overwrite existing rule files", default: false }).with(Workspace).exec(async function(action, targetName, force, workspace) {
|
|
10536
|
+
await this.agentScript.agent(workspace, action, targetName, { force });
|
|
10537
|
+
})
|
|
10538
|
+
})) {
|
|
10539
|
+
}
|
|
10540
|
+
|
|
10168
10541
|
// pkgs/@akanjs/cli/application/application.command.ts
|
|
10169
10542
|
import { select as select6 } from "@inquirer/prompts";
|
|
10170
10543
|
|
|
10171
10544
|
// pkgs/@akanjs/cli/application/application.script.ts
|
|
10172
10545
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
10173
|
-
import { Logger as
|
|
10546
|
+
import { Logger as Logger13 } from "akanjs/common";
|
|
10174
10547
|
|
|
10175
10548
|
// pkgs/@akanjs/cli/semver.ts
|
|
10176
10549
|
function parseVersion(version) {
|
|
@@ -10288,7 +10661,7 @@ import { StringOutputParser } from "@langchain/core/output_parsers";
|
|
|
10288
10661
|
import { PromptTemplate as PromptTemplate2 } from "@langchain/core/prompts";
|
|
10289
10662
|
import { RunnableSequence as RunnableSequence2 } from "@langchain/core/runnables";
|
|
10290
10663
|
import { ChatOpenAI as ChatOpenAI3 } from "@langchain/openai";
|
|
10291
|
-
import { Logger as
|
|
10664
|
+
import { Logger as Logger12 } from "akanjs/common";
|
|
10292
10665
|
import ora3 from "ora";
|
|
10293
10666
|
|
|
10294
10667
|
// pkgs/@akanjs/cli/openBrowser.ts
|
|
@@ -10343,6 +10716,37 @@ class ApplicationRunner extends runner("application") {
|
|
|
10343
10716
|
stdio: "inherit"
|
|
10344
10717
|
});
|
|
10345
10718
|
}
|
|
10719
|
+
async runConsole(app) {
|
|
10720
|
+
const serverPath = `${app.cwdPath}/server.ts`;
|
|
10721
|
+
if (!await app.exists("server.ts"))
|
|
10722
|
+
throw new Error(`Server file not found: apps/${app.name}/server.ts`);
|
|
10723
|
+
const code = `
|
|
10724
|
+
const serverModule = await import(${JSON.stringify(serverPath)});
|
|
10725
|
+
const { assertAkanConsoleAllowed, startAkanConsole } = await import("akanjs/server");
|
|
10726
|
+
const server = serverModule.server;
|
|
10727
|
+
if (!server?.start) throw new Error("server.ts must export server with start()");
|
|
10728
|
+
assertAkanConsoleAllowed(server.env);
|
|
10729
|
+
await server.start({ listen: false, web: false });
|
|
10730
|
+
try {
|
|
10731
|
+
await startAkanConsole(server, {
|
|
10732
|
+
globals: {
|
|
10733
|
+
srv: serverModule.srv,
|
|
10734
|
+
sig: serverModule.sig,
|
|
10735
|
+
db: serverModule.db,
|
|
10736
|
+
cnst: serverModule.cnst,
|
|
10737
|
+
dict: serverModule.dict,
|
|
10738
|
+
option: serverModule.option,
|
|
10739
|
+
},
|
|
10740
|
+
});
|
|
10741
|
+
} finally {
|
|
10742
|
+
await server.stop();
|
|
10743
|
+
}
|
|
10744
|
+
`;
|
|
10745
|
+
await app.spawn("bun", ["-e", code], {
|
|
10746
|
+
env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "console" }),
|
|
10747
|
+
stdio: "inherit"
|
|
10748
|
+
});
|
|
10749
|
+
}
|
|
10346
10750
|
async typecheck(app, options = {}) {
|
|
10347
10751
|
await new ApplicationBuildRunner(app).typecheck(options);
|
|
10348
10752
|
}
|
|
@@ -10477,7 +10881,7 @@ class ApplicationRunner extends runner("application") {
|
|
|
10477
10881
|
return;
|
|
10478
10882
|
for (const failure of failures) {
|
|
10479
10883
|
const message = failure.error instanceof Error ? failure.error.message : String(failure.error);
|
|
10480
|
-
|
|
10884
|
+
Logger12.rawLog(`Mobile target ${failure.target} failed: ${message}`, undefined, "error");
|
|
10481
10885
|
}
|
|
10482
10886
|
throw new Error(`${failures.length}/${results.length} mobile targets failed`);
|
|
10483
10887
|
}
|
|
@@ -10650,6 +11054,10 @@ class ApplicationScript extends script("application", [
|
|
|
10650
11054
|
await app.scanSync();
|
|
10651
11055
|
await this.applicationRunner.runScript(app, scriptFilename);
|
|
10652
11056
|
}
|
|
11057
|
+
async console(app) {
|
|
11058
|
+
await app.scanSync();
|
|
11059
|
+
await this.applicationRunner.runConsole(app);
|
|
11060
|
+
}
|
|
10653
11061
|
async build(app, {
|
|
10654
11062
|
write = true,
|
|
10655
11063
|
fast = false,
|
|
@@ -10657,18 +11065,18 @@ class ApplicationScript extends script("application", [
|
|
|
10657
11065
|
} = {}) {
|
|
10658
11066
|
await app.scanSync({ write });
|
|
10659
11067
|
if (!quiet)
|
|
10660
|
-
|
|
11068
|
+
Logger13.rawLog(`Creating an optimized production build for ${app.name}...`);
|
|
10661
11069
|
try {
|
|
10662
11070
|
const result = await this.applicationRunner.build(app, {
|
|
10663
11071
|
fast,
|
|
10664
11072
|
spinner: !quiet
|
|
10665
11073
|
});
|
|
10666
|
-
|
|
11074
|
+
Logger13.rawLog(`${app.name} built in dist/apps/${app.name}`);
|
|
10667
11075
|
if (!quiet)
|
|
10668
11076
|
ApplicationBuildReporter.printSummary(result);
|
|
10669
11077
|
} catch (error) {
|
|
10670
|
-
|
|
10671
|
-
|
|
11078
|
+
Logger13.rawLog(`${app.name} build failed in dist/apps/${app.name}`, undefined, "error");
|
|
11079
|
+
Logger13.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
|
|
10672
11080
|
throw error;
|
|
10673
11081
|
}
|
|
10674
11082
|
}
|
|
@@ -10684,7 +11092,7 @@ class ApplicationScript extends script("application", [
|
|
|
10684
11092
|
spinner2.succeed(`${app.name} typechecked`);
|
|
10685
11093
|
} catch (error) {
|
|
10686
11094
|
spinner2.fail(`${app.name} typecheck failed`);
|
|
10687
|
-
|
|
11095
|
+
Logger13.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
|
|
10688
11096
|
throw error;
|
|
10689
11097
|
}
|
|
10690
11098
|
}
|
|
@@ -10866,6 +11274,9 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
|
|
|
10866
11274
|
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) {
|
|
10867
11275
|
await this.applicationScript.script(app, filename);
|
|
10868
11276
|
}),
|
|
11277
|
+
console: target({ desc: "Open an interactive server console for the application" }).with(App).exec(async function(app) {
|
|
11278
|
+
await this.applicationScript.console(app);
|
|
11279
|
+
}),
|
|
10869
11280
|
build: target({ short: true, desc: "Build the application for production (frontend + backend)" }).with(App).option("write", Boolean, { desc: "write code generation", default: true }).option("fast", Boolean, { desc: "fast build", default: false }).option("quiet", Boolean, { desc: "hide build progress output", default: false }).exec(async function(app, write, fast, quiet) {
|
|
10870
11281
|
await this.applicationScript.build(app, { write, fast, quiet });
|
|
10871
11282
|
}),
|
|
@@ -10987,11 +11398,11 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
|
|
|
10987
11398
|
}
|
|
10988
11399
|
|
|
10989
11400
|
// pkgs/@akanjs/cli/cloud/cloud.script.ts
|
|
10990
|
-
import { Logger as
|
|
11401
|
+
import { Logger as Logger16 } from "akanjs/common";
|
|
10991
11402
|
|
|
10992
11403
|
// pkgs/@akanjs/cli/package/package.runner.ts
|
|
10993
|
-
import
|
|
10994
|
-
import { Logger as
|
|
11404
|
+
import path38 from "path";
|
|
11405
|
+
import { Logger as Logger14 } from "akanjs/common";
|
|
10995
11406
|
var {$: $2 } = globalThis.Bun;
|
|
10996
11407
|
|
|
10997
11408
|
class PackageRunner extends runner("package") {
|
|
@@ -10999,16 +11410,16 @@ class PackageRunner extends runner("package") {
|
|
|
10999
11410
|
const pkgJson = process.env.USE_AKANJS_PKGS === "true" ? await FileSys.readJson(`${workspace?.workspaceRoot ?? process.cwd()}/pkgs/akanjs/package.json`) : await this.#getInstalledPackageJson();
|
|
11000
11411
|
const version = pkgJson.name === "akanjs" ? pkgJson.version : pkgJson.dependencies?.akanjs ?? pkgJson.version;
|
|
11001
11412
|
if (log)
|
|
11002
|
-
|
|
11413
|
+
Logger14.rawLog(`akanjs@${version}`);
|
|
11003
11414
|
return version;
|
|
11004
11415
|
}
|
|
11005
11416
|
async#getInstalledPackageJson() {
|
|
11006
11417
|
const packageJsonCandidates = [
|
|
11007
|
-
`${
|
|
11418
|
+
`${path38.dirname(Bun.main)}/package.json`,
|
|
11008
11419
|
`${process.cwd()}/node_modules/akanjs/package.json`
|
|
11009
11420
|
];
|
|
11010
11421
|
try {
|
|
11011
|
-
packageJsonCandidates.unshift(Bun.resolveSync("akanjs/package.json",
|
|
11422
|
+
packageJsonCandidates.unshift(Bun.resolveSync("akanjs/package.json", path38.dirname(Bun.main)));
|
|
11012
11423
|
} catch {}
|
|
11013
11424
|
for (const packageJsonPath of packageJsonCandidates) {
|
|
11014
11425
|
if (!await Bun.file(packageJsonPath).exists())
|
|
@@ -11017,7 +11428,7 @@ class PackageRunner extends runner("package") {
|
|
|
11017
11428
|
if (packageJson.name === "akanjs" || packageJson.name === "@akanjs/cli")
|
|
11018
11429
|
return packageJson;
|
|
11019
11430
|
}
|
|
11020
|
-
throw new Error(`[package] failed to locate akanjs package.json from ${
|
|
11431
|
+
throw new Error(`[package] failed to locate akanjs package.json from ${path38.dirname(Bun.main)}`);
|
|
11021
11432
|
}
|
|
11022
11433
|
async createPackage(workspace, pkgName) {
|
|
11023
11434
|
await workspace.applyTemplate({ basePath: `pkgs/${pkgName}`, template: "pkgRoot", dict: { pkgName } });
|
|
@@ -11125,9 +11536,9 @@ class PackageScript extends script("package", [PackageRunner]) {
|
|
|
11125
11536
|
}
|
|
11126
11537
|
|
|
11127
11538
|
// pkgs/@akanjs/cli/cloud/cloud.runner.ts
|
|
11128
|
-
import
|
|
11539
|
+
import path39 from "path";
|
|
11129
11540
|
import { confirm as confirm4, input as input5, select as select7 } from "@inquirer/prompts";
|
|
11130
|
-
import { Logger as
|
|
11541
|
+
import { Logger as Logger15, sleep } from "akanjs/common";
|
|
11131
11542
|
import chalk7 from "chalk";
|
|
11132
11543
|
import * as QRcode from "qrcode";
|
|
11133
11544
|
|
|
@@ -11202,7 +11613,7 @@ class CloudRunner extends runner("cloud") {
|
|
|
11202
11613
|
const servers = await GlobalConfig.getRemoteEnvServers();
|
|
11203
11614
|
const serverEntries = Object.entries(servers).sort(([nameA], [nameB]) => nameA.localeCompare(nameB));
|
|
11204
11615
|
if (serverEntries.length === 0) {
|
|
11205
|
-
|
|
11616
|
+
Logger15.info("No remote env servers configured. Add the first remote server for SCP mode.");
|
|
11206
11617
|
return await this.#addRemoteEnvServer();
|
|
11207
11618
|
}
|
|
11208
11619
|
const selectedName = await select7({
|
|
@@ -11242,7 +11653,7 @@ class CloudRunner extends runner("cloud") {
|
|
|
11242
11653
|
if (!shouldRemove)
|
|
11243
11654
|
return;
|
|
11244
11655
|
await GlobalConfig.removeRemoteEnvServer(selectedName);
|
|
11245
|
-
|
|
11656
|
+
Logger15.info(`Removed remote env server "${selectedName}"`);
|
|
11246
11657
|
}
|
|
11247
11658
|
async#getRemoteEnvServerWithUsername() {
|
|
11248
11659
|
const remoteServer = await this.#selectRemoteEnvServer();
|
|
@@ -11283,17 +11694,17 @@ class CloudRunner extends runner("cloud") {
|
|
|
11283
11694
|
const cloudApi2 = new CloudApi(workspace, config);
|
|
11284
11695
|
const self = config.auth ? await cloudApi2.getRemoteSelf() : null;
|
|
11285
11696
|
if (self) {
|
|
11286
|
-
|
|
11697
|
+
Logger15.rawLog(chalk7.green(`
|
|
11287
11698
|
\u2713 Already logged in akan cloud as ${self.nickname}
|
|
11288
11699
|
`));
|
|
11289
11700
|
return true;
|
|
11290
11701
|
}
|
|
11291
11702
|
const remoteId = crypto.randomUUID();
|
|
11292
11703
|
const signinUrl = `${cloudApi2.host}/remoteAuth?remoteId=${encodeURIComponent(remoteId)}`;
|
|
11293
|
-
|
|
11704
|
+
Logger15.rawLog(chalk7.bold(`
|
|
11294
11705
|
${chalk7.green("\u27A4")} Authentication Required`));
|
|
11295
|
-
|
|
11296
|
-
|
|
11706
|
+
Logger15.rawLog(chalk7.dim("Please visit or click the following URL:"));
|
|
11707
|
+
Logger15.rawLog(`${chalk7.cyan.underline(signinUrl)}
|
|
11297
11708
|
`);
|
|
11298
11709
|
try {
|
|
11299
11710
|
const qrcode = await new Promise((resolve, reject) => {
|
|
@@ -11303,23 +11714,23 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11303
11714
|
resolve(data);
|
|
11304
11715
|
});
|
|
11305
11716
|
});
|
|
11306
|
-
|
|
11717
|
+
Logger15.rawLog(qrcode);
|
|
11307
11718
|
await openBrowser(signinUrl);
|
|
11308
|
-
|
|
11719
|
+
Logger15.rawLog(chalk7.dim("Opening browser..."));
|
|
11309
11720
|
} catch {
|
|
11310
|
-
|
|
11721
|
+
Logger15.rawLog(chalk7.yellow("Could not open browser. Please visit the URL manually."));
|
|
11311
11722
|
}
|
|
11312
|
-
|
|
11723
|
+
Logger15.rawLog(chalk7.dim("Waiting for authentication..."));
|
|
11313
11724
|
const MAX_RETRY = 300;
|
|
11314
11725
|
for (let i = 0;i < MAX_RETRY; i++) {
|
|
11315
11726
|
const accessToken = await cloudApi2.getRemoteAuthToken(remoteId);
|
|
11316
11727
|
const self2 = await cloudApi2.getRemoteSelf();
|
|
11317
11728
|
if (accessToken && self2) {
|
|
11318
11729
|
await GlobalConfig.setHostConfig({ host: config.host, auth: { accessToken, self: self2 } });
|
|
11319
|
-
|
|
11320
|
-
|
|
11730
|
+
Logger15.rawLog(chalk7.green(`\r\u2713 Authentication successful!`));
|
|
11731
|
+
Logger15.rawLog(chalk7.green.bold(`
|
|
11321
11732
|
\u2728 Welcome aboard, ${self2.nickname ?? "anonymous"}!`));
|
|
11322
|
-
|
|
11733
|
+
Logger15.rawLog(chalk7.dim(`You're now ready to use Akan CLI!
|
|
11323
11734
|
`));
|
|
11324
11735
|
return true;
|
|
11325
11736
|
}
|
|
@@ -11331,17 +11742,17 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11331
11742
|
const config = await GlobalConfig.getHostConfig(host);
|
|
11332
11743
|
if (config.auth?.self) {
|
|
11333
11744
|
await GlobalConfig.setHostConfig(getDefaultHostConfig(config.host));
|
|
11334
|
-
|
|
11745
|
+
Logger15.rawLog(chalk7.magenta.bold(`
|
|
11335
11746
|
\uD83D\uDC4B Goodbye, ${config.auth.self.nickname ?? "anonymous"}!`));
|
|
11336
|
-
|
|
11747
|
+
Logger15.rawLog(chalk7.dim(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
11337
11748
|
`));
|
|
11338
|
-
|
|
11339
|
-
|
|
11749
|
+
Logger15.rawLog(chalk7.cyan("You have been successfully logged out."));
|
|
11750
|
+
Logger15.rawLog(chalk7.dim(`Thank you for using Akan CLI. Come back soon! \uD83C\uDF1F
|
|
11340
11751
|
`));
|
|
11341
11752
|
} else {
|
|
11342
|
-
|
|
11753
|
+
Logger15.rawLog(chalk7.yellow.bold(`
|
|
11343
11754
|
\u26A0\uFE0F No active session found`));
|
|
11344
|
-
|
|
11755
|
+
Logger15.rawLog(chalk7.dim(`You were not logged in to begin with
|
|
11345
11756
|
`));
|
|
11346
11757
|
}
|
|
11347
11758
|
}
|
|
@@ -11350,7 +11761,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11350
11761
|
}
|
|
11351
11762
|
resetLlm() {
|
|
11352
11763
|
AiSession.setLlmConfig(null);
|
|
11353
|
-
|
|
11764
|
+
Logger15.rawLog(chalk7.green("\u2611\uFE0F LLM model config is cleared. Please run `akan set-llm` to set a new LLM model."));
|
|
11354
11765
|
}
|
|
11355
11766
|
async getAkanPkgs(workspace) {
|
|
11356
11767
|
const pkgs = await workspace.getPkgs();
|
|
@@ -11374,8 +11785,8 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11374
11785
|
}
|
|
11375
11786
|
};
|
|
11376
11787
|
const { nextVersion, latestPublishedVersion } = await getNextVersion(targetVersionPrefix, tag);
|
|
11377
|
-
|
|
11378
|
-
|
|
11788
|
+
Logger15.info(`Latest published version of akanjs: ${latestPublishedVersion ?? "none"}`);
|
|
11789
|
+
Logger15.info(`Next version of akanjs: ${nextVersion}`);
|
|
11379
11790
|
for (const library of akanPkgs) {
|
|
11380
11791
|
const packageJson = await workspace.readJson(`pkgs/${library}/package.json`);
|
|
11381
11792
|
const newPackageJsonStr = JSON.stringify(this.#normalizeAkanPackageJson(packageJson, library, nextVersion), null, 2);
|
|
@@ -11389,20 +11800,20 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11389
11800
|
message: "Are you sure you want to deploy the libraries?"
|
|
11390
11801
|
});
|
|
11391
11802
|
if (!isDeployConfirmed) {
|
|
11392
|
-
|
|
11803
|
+
Logger15.error("Deployment cancelled");
|
|
11393
11804
|
return;
|
|
11394
11805
|
}
|
|
11395
11806
|
}
|
|
11396
11807
|
await Promise.all(akanPkgs.map(async (library) => {
|
|
11397
|
-
|
|
11808
|
+
Logger15.info(`Publishing ${library}@${nextVersion} to ${registry ?? "npm"}...`);
|
|
11398
11809
|
await workspace.spawn("npm", ["publish", "--tag", tag, ...this.#getRegistryArgs(registry), ...this.#getLocalRegistryAuthArgs(registry)], {
|
|
11399
|
-
cwd:
|
|
11810
|
+
cwd: path39.join(workspace.workspaceRoot, "dist/pkgs", library),
|
|
11400
11811
|
env: this.#getRegistryEnv(registry),
|
|
11401
11812
|
stdio: "inherit"
|
|
11402
11813
|
});
|
|
11403
|
-
|
|
11814
|
+
Logger15.info(`${library}@${nextVersion} is published to ${registry ?? "npm"}`);
|
|
11404
11815
|
}));
|
|
11405
|
-
|
|
11816
|
+
Logger15.info(`All libraries are published to ${registry ?? "npm"}`);
|
|
11406
11817
|
}
|
|
11407
11818
|
async update(workspace, tag = "latest", { registryUrl } = {}) {
|
|
11408
11819
|
const registry = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
|
|
@@ -11454,7 +11865,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11454
11865
|
await workspace.remove(localPath);
|
|
11455
11866
|
}
|
|
11456
11867
|
async uploadEnv(cloudApi2, workspaceId, filePath) {
|
|
11457
|
-
const file = new File([Bun.file(filePath)],
|
|
11868
|
+
const file = new File([Bun.file(filePath)], path39.basename(filePath));
|
|
11458
11869
|
await cloudApi2.uploadEnv(workspaceId, file);
|
|
11459
11870
|
}
|
|
11460
11871
|
async downloadEnvByScp(workspace) {
|
|
@@ -11465,7 +11876,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11465
11876
|
await workspace.mkdir("local");
|
|
11466
11877
|
await workspace.remove(envArchivePath);
|
|
11467
11878
|
try {
|
|
11468
|
-
|
|
11879
|
+
Logger15.info(`Downloading env archive from remote server "${remoteServer.name}"...`);
|
|
11469
11880
|
await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, remoteTarget, envArchivePath), {
|
|
11470
11881
|
cwd: workspace.workspaceRoot,
|
|
11471
11882
|
stdio: "inherit"
|
|
@@ -11488,7 +11899,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11488
11899
|
cwd: workspace.workspaceRoot,
|
|
11489
11900
|
stdio: "inherit"
|
|
11490
11901
|
});
|
|
11491
|
-
|
|
11902
|
+
Logger15.info(`Uploading env archive to remote server "${remoteServer.name}"...`);
|
|
11492
11903
|
await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, filePath, remoteTarget), {
|
|
11493
11904
|
cwd: workspace.workspaceRoot,
|
|
11494
11905
|
stdio: "inherit"
|
|
@@ -11512,7 +11923,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11512
11923
|
await workspace.spawn("tar", ["-cf", "local/env.tar", ...envFilePaths], {
|
|
11513
11924
|
cwd: workspace.workspaceRoot
|
|
11514
11925
|
});
|
|
11515
|
-
|
|
11926
|
+
Logger15.info(`Archived ${envFilePaths.length} environment files to local/env.tar`);
|
|
11516
11927
|
return { files: envFilePaths, path: "local/env.tar" };
|
|
11517
11928
|
}
|
|
11518
11929
|
}
|
|
@@ -11546,13 +11957,13 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
|
|
|
11546
11957
|
}
|
|
11547
11958
|
async uploadEnv(workspace) {
|
|
11548
11959
|
const workspaceId = workspace.getWorkspaceId({ allowEmpty: true });
|
|
11549
|
-
const { path:
|
|
11960
|
+
const { path: path40 } = await this.cloudRunner.gatherEnvFiles(workspace);
|
|
11550
11961
|
if (workspaceId) {
|
|
11551
11962
|
const cloudApi2 = await CloudApi.fromHost(workspace);
|
|
11552
|
-
await this.cloudRunner.uploadEnv(cloudApi2, workspaceId,
|
|
11963
|
+
await this.cloudRunner.uploadEnv(cloudApi2, workspaceId, path40);
|
|
11553
11964
|
return;
|
|
11554
11965
|
}
|
|
11555
|
-
await this.cloudRunner.uploadEnvByScp(workspace,
|
|
11966
|
+
await this.cloudRunner.uploadEnvByScp(workspace, path40);
|
|
11556
11967
|
}
|
|
11557
11968
|
async deployAkan(workspace, { test = true, registryUrl } = {}) {
|
|
11558
11969
|
const akanPkgs = await this.cloudRunner.getAkanPkgs(workspace);
|
|
@@ -11569,7 +11980,7 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
|
|
|
11569
11980
|
const spinner2 = workspace.spinning("Updating Akan.js packages and CLI...");
|
|
11570
11981
|
await this.cloudRunner.update(workspace, tag, { registryUrl });
|
|
11571
11982
|
spinner2.succeed("Akan.js packages and CLI updated, global version is below");
|
|
11572
|
-
|
|
11983
|
+
Logger16.raw("> Akan version: ");
|
|
11573
11984
|
await workspace.spawn("akan", ["--version"], { stdio: "inherit" });
|
|
11574
11985
|
}
|
|
11575
11986
|
}
|
|
@@ -11643,6 +12054,235 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
|
|
|
11643
12054
|
})) {
|
|
11644
12055
|
}
|
|
11645
12056
|
|
|
12057
|
+
// pkgs/@akanjs/cli/context/context.script.ts
|
|
12058
|
+
import { Logger as Logger17 } from "akanjs/common";
|
|
12059
|
+
|
|
12060
|
+
// pkgs/@akanjs/cli/context/context.runner.ts
|
|
12061
|
+
var jsonText = (value) => JSON.stringify(value, null, 2);
|
|
12062
|
+
var renderDoctorText = (result) => {
|
|
12063
|
+
if (result.diagnostics.length === 0)
|
|
12064
|
+
return `No Akan workspace diagnostics found.
|
|
12065
|
+
`;
|
|
12066
|
+
return `${result.diagnostics.map((diagnostic) => [
|
|
12067
|
+
`[${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`,
|
|
12068
|
+
diagnostic.path ? ` ${diagnostic.path}` : ""
|
|
12069
|
+
].filter(Boolean).join(`
|
|
12070
|
+
`)).join(`
|
|
12071
|
+
|
|
12072
|
+
`)}
|
|
12073
|
+
`;
|
|
12074
|
+
};
|
|
12075
|
+
var resourceList = [
|
|
12076
|
+
{ uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
|
|
12077
|
+
{ uri: "akan://guidelines/framework", name: "Framework guideline", mimeType: "text/markdown" },
|
|
12078
|
+
{ uri: "akan://guidelines/modelSignal", name: "Model signal guideline", mimeType: "text/markdown" },
|
|
12079
|
+
{ uri: "akan://workspace/summary", name: "Workspace summary", mimeType: "application/json" },
|
|
12080
|
+
{ uri: "akan://workspace/apps", name: "Workspace apps", mimeType: "application/json" },
|
|
12081
|
+
{ uri: "akan://workspace/modules", name: "Workspace modules", mimeType: "application/json" }
|
|
12082
|
+
];
|
|
12083
|
+
|
|
12084
|
+
class ContextRunner extends runner("context") {
|
|
12085
|
+
async getContext(workspace, {
|
|
12086
|
+
format = "markdown",
|
|
12087
|
+
app = null,
|
|
12088
|
+
module = null
|
|
12089
|
+
} = {}) {
|
|
12090
|
+
const context = await AkanContextAnalyzer.analyze(workspace, {
|
|
12091
|
+
app,
|
|
12092
|
+
module,
|
|
12093
|
+
includeAbstractContent: !!module
|
|
12094
|
+
});
|
|
12095
|
+
return format === "json" ? `${jsonText(context)}
|
|
12096
|
+
` : AkanContextAnalyzer.renderMarkdown(context, { module });
|
|
12097
|
+
}
|
|
12098
|
+
async doctor(workspace, { format = "text", strict = false } = {}) {
|
|
12099
|
+
const result = await AkanContextAnalyzer.doctor(workspace, { strict });
|
|
12100
|
+
return format === "json" ? `${jsonText(result)}
|
|
12101
|
+
` : renderDoctorText(result);
|
|
12102
|
+
}
|
|
12103
|
+
async getGuidelineResource(name) {
|
|
12104
|
+
return await Prompter.getInstruction(name);
|
|
12105
|
+
}
|
|
12106
|
+
async runMcp(workspace) {
|
|
12107
|
+
const decoder = new TextDecoder;
|
|
12108
|
+
let buffer = "";
|
|
12109
|
+
const respond = (id, result) => {
|
|
12110
|
+
const payload = JSON.stringify({ jsonrpc: "2.0", id, result });
|
|
12111
|
+
process.stdout.write(`Content-Length: ${Buffer.byteLength(payload)}\r
|
|
12112
|
+
\r
|
|
12113
|
+
${payload}`);
|
|
12114
|
+
};
|
|
12115
|
+
const respondError = (id, code, message) => {
|
|
12116
|
+
const payload = JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
|
|
12117
|
+
process.stdout.write(`Content-Length: ${Buffer.byteLength(payload)}\r
|
|
12118
|
+
\r
|
|
12119
|
+
${payload}`);
|
|
12120
|
+
};
|
|
12121
|
+
const readResource = async (uri) => {
|
|
12122
|
+
const context = await AkanContextAnalyzer.analyze(workspace);
|
|
12123
|
+
if (uri === "akan://docs/framework" || uri === "akan://guidelines/framework")
|
|
12124
|
+
return { uri, mimeType: "text/markdown", text: await Prompter.getInstruction("framework") };
|
|
12125
|
+
if (uri === "akan://guidelines/modelSignal")
|
|
12126
|
+
return { uri, mimeType: "text/markdown", text: await Prompter.getInstruction("modelSignal") };
|
|
12127
|
+
if (uri === "akan://workspace/summary")
|
|
12128
|
+
return { uri, mimeType: "application/json", text: jsonText(context) };
|
|
12129
|
+
if (uri === "akan://workspace/apps")
|
|
12130
|
+
return { uri, mimeType: "application/json", text: jsonText(context.apps) };
|
|
12131
|
+
if (uri === "akan://workspace/modules")
|
|
12132
|
+
return { uri, mimeType: "application/json", text: jsonText(AkanContextAnalyzer.findModules(context)) };
|
|
12133
|
+
const abstractMatch = uri.match(/^akan:\/\/workspace\/modules\/(.+)\/abstract$/);
|
|
12134
|
+
if (abstractMatch) {
|
|
12135
|
+
const detailed = await AkanContextAnalyzer.analyze(workspace, {
|
|
12136
|
+
module: abstractMatch[1],
|
|
12137
|
+
includeAbstractContent: true
|
|
12138
|
+
});
|
|
12139
|
+
const abstract = AkanContextAnalyzer.findModules(detailed, abstractMatch[1])[0]?.abstract;
|
|
12140
|
+
return { uri, mimeType: "text/markdown", text: abstract?.content ?? "" };
|
|
12141
|
+
}
|
|
12142
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
12143
|
+
};
|
|
12144
|
+
const handle = async (request) => {
|
|
12145
|
+
const params = request.params ?? {};
|
|
12146
|
+
if (request.method === "initialize") {
|
|
12147
|
+
respond(request.id, {
|
|
12148
|
+
protocolVersion: "2024-11-05",
|
|
12149
|
+
capabilities: { tools: {}, resources: {} },
|
|
12150
|
+
serverInfo: { name: "akan", version: process.env.AKAN_VERSION ?? "0.0.0" }
|
|
12151
|
+
});
|
|
12152
|
+
} else if (request.method === "tools/list") {
|
|
12153
|
+
respond(request.id, {
|
|
12154
|
+
tools: [
|
|
12155
|
+
{ name: "get_workspace_summary", inputSchema: { type: "object", properties: {} } },
|
|
12156
|
+
{ name: "list_apps", inputSchema: { type: "object", properties: {} } },
|
|
12157
|
+
{ name: "list_modules", inputSchema: { type: "object", properties: {} } },
|
|
12158
|
+
{
|
|
12159
|
+
name: "get_module_context",
|
|
12160
|
+
inputSchema: { type: "object", properties: { module: { type: "string" } } }
|
|
12161
|
+
},
|
|
12162
|
+
{
|
|
12163
|
+
name: "get_guideline",
|
|
12164
|
+
inputSchema: { type: "object", properties: { name: { type: "string" } }, required: ["name"] }
|
|
12165
|
+
},
|
|
12166
|
+
{
|
|
12167
|
+
name: "explain_command",
|
|
12168
|
+
inputSchema: { type: "object", properties: { command: { type: "string" } }, required: ["command"] }
|
|
12169
|
+
},
|
|
12170
|
+
{ name: "doctor_workspace", inputSchema: { type: "object", properties: { strict: { type: "boolean" } } } }
|
|
12171
|
+
]
|
|
12172
|
+
});
|
|
12173
|
+
} else if (request.method === "tools/call") {
|
|
12174
|
+
const name = params.name;
|
|
12175
|
+
const args = params.arguments ?? {};
|
|
12176
|
+
const context = await AkanContextAnalyzer.analyze(workspace, {
|
|
12177
|
+
module: args.module ?? null,
|
|
12178
|
+
includeAbstractContent: name === "get_module_context"
|
|
12179
|
+
});
|
|
12180
|
+
const result = await (async () => {
|
|
12181
|
+
if (name === "get_workspace_summary")
|
|
12182
|
+
return context;
|
|
12183
|
+
if (name === "list_apps")
|
|
12184
|
+
return context.apps;
|
|
12185
|
+
if (name === "list_modules")
|
|
12186
|
+
return AkanContextAnalyzer.findModules(context);
|
|
12187
|
+
if (name === "get_module_context")
|
|
12188
|
+
return AkanContextAnalyzer.findModules(context, args.module);
|
|
12189
|
+
if (name === "get_guideline")
|
|
12190
|
+
return await Prompter.getInstruction(args.name);
|
|
12191
|
+
if (name === "doctor_workspace")
|
|
12192
|
+
return await AkanContextAnalyzer.doctor(workspace, { strict: !!args.strict });
|
|
12193
|
+
if (name === "explain_command")
|
|
12194
|
+
return this.explainCommand(args.command);
|
|
12195
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
12196
|
+
})();
|
|
12197
|
+
respond(request.id, {
|
|
12198
|
+
content: [{ type: "text", text: typeof result === "string" ? result : jsonText(result) }]
|
|
12199
|
+
});
|
|
12200
|
+
} else if (request.method === "resources/list") {
|
|
12201
|
+
respond(request.id, { resources: resourceList });
|
|
12202
|
+
} else if (request.method === "resources/read") {
|
|
12203
|
+
respond(request.id, { contents: [await readResource(params.uri)] });
|
|
12204
|
+
} else if (!request.method.endsWith("/initialized")) {
|
|
12205
|
+
respondError(request.id, -32601, `Unknown method: ${request.method}`);
|
|
12206
|
+
}
|
|
12207
|
+
};
|
|
12208
|
+
const parse = async () => {
|
|
12209
|
+
while (true) {
|
|
12210
|
+
const headerEnd = buffer.indexOf(`\r
|
|
12211
|
+
\r
|
|
12212
|
+
`);
|
|
12213
|
+
if (headerEnd < 0)
|
|
12214
|
+
return;
|
|
12215
|
+
const header = buffer.slice(0, headerEnd);
|
|
12216
|
+
const match = /Content-Length:\s*(\d+)/i.exec(header);
|
|
12217
|
+
if (!match) {
|
|
12218
|
+
buffer = buffer.slice(headerEnd + 4);
|
|
12219
|
+
continue;
|
|
12220
|
+
}
|
|
12221
|
+
const length = Number(match[1]);
|
|
12222
|
+
const bodyStart = headerEnd + 4;
|
|
12223
|
+
const bodyEnd = bodyStart + length;
|
|
12224
|
+
if (buffer.length < bodyEnd)
|
|
12225
|
+
return;
|
|
12226
|
+
const body = buffer.slice(bodyStart, bodyEnd);
|
|
12227
|
+
buffer = buffer.slice(bodyEnd);
|
|
12228
|
+
await handle(JSON.parse(body));
|
|
12229
|
+
}
|
|
12230
|
+
};
|
|
12231
|
+
for await (const chunk of Bun.stdin.stream()) {
|
|
12232
|
+
buffer += decoder.decode(chunk);
|
|
12233
|
+
await parse();
|
|
12234
|
+
}
|
|
12235
|
+
}
|
|
12236
|
+
explainCommand(command3) {
|
|
12237
|
+
const explanations = {
|
|
12238
|
+
context: "`akan context` prints agent-readable workspace, app, module, and abstract metadata.",
|
|
12239
|
+
doctor: "`akan doctor` reports workspace convention diagnostics. Use `--format json` for agents.",
|
|
12240
|
+
"guideline show": "`akan guideline show <name>` prints an Akan codegen guideline instruction.",
|
|
12241
|
+
agent: "`akan agent install <target>` writes editor-specific agent rules with overwrite protection.",
|
|
12242
|
+
mcp: "`akan mcp` starts the read-only Akan MCP server over stdio."
|
|
12243
|
+
};
|
|
12244
|
+
return explanations[command3] ?? `No detailed explanation is available for ${command3}. Run \`akan --help\` for command help.`;
|
|
12245
|
+
}
|
|
12246
|
+
}
|
|
12247
|
+
|
|
12248
|
+
// pkgs/@akanjs/cli/context/context.script.ts
|
|
12249
|
+
class ContextScript extends script("context", [ContextRunner]) {
|
|
12250
|
+
async context(workspace, options = {}) {
|
|
12251
|
+
Logger17.rawLog(await this.contextRunner.getContext(workspace, options));
|
|
12252
|
+
}
|
|
12253
|
+
async doctor(workspace, options = {}) {
|
|
12254
|
+
Logger17.rawLog(await this.contextRunner.doctor(workspace, options));
|
|
12255
|
+
}
|
|
12256
|
+
async mcp(workspace) {
|
|
12257
|
+
await this.contextRunner.runMcp(workspace);
|
|
12258
|
+
}
|
|
12259
|
+
}
|
|
12260
|
+
|
|
12261
|
+
// pkgs/@akanjs/cli/context/context.command.ts
|
|
12262
|
+
class ContextCommand extends command("context", [ContextScript], ({ public: target }) => ({
|
|
12263
|
+
context: target({ desc: "Print agent-readable Akan workspace context" }).option("format", String, {
|
|
12264
|
+
desc: "output format",
|
|
12265
|
+
default: "markdown",
|
|
12266
|
+
enum: ["markdown", "json"]
|
|
12267
|
+
}).option("app", String, { desc: "app name to include", nullable: true }).option("module", String, { desc: "module name to include with abstract content", nullable: true }).with(Workspace).exec(async function(format, app, module, workspace) {
|
|
12268
|
+
await this.contextScript.context(workspace, { format, app, module });
|
|
12269
|
+
}),
|
|
12270
|
+
doctor: target({ desc: "Report Akan workspace convention diagnostics" }).option("format", String, {
|
|
12271
|
+
desc: "output format",
|
|
12272
|
+
default: "text",
|
|
12273
|
+
enum: ["text", "json"]
|
|
12274
|
+
}).option("strict", Boolean, { desc: "treat recommended conventions as errors", default: false }).with(Workspace).exec(async function(format, strict, workspace) {
|
|
12275
|
+
await this.contextScript.doctor(workspace, { format, strict });
|
|
12276
|
+
}),
|
|
12277
|
+
mcp: target({ desc: "Start the read-only Akan MCP server over stdio" }).with(Workspace).exec(async function(workspace) {
|
|
12278
|
+
await this.contextScript.mcp(workspace);
|
|
12279
|
+
})
|
|
12280
|
+
})) {
|
|
12281
|
+
}
|
|
12282
|
+
|
|
12283
|
+
// pkgs/@akanjs/cli/guideline/guideline.script.ts
|
|
12284
|
+
import { Logger as Logger18 } from "akanjs/common";
|
|
12285
|
+
|
|
11646
12286
|
// pkgs/@akanjs/cli/guideline/guideline.prompt.ts
|
|
11647
12287
|
import { randomPicks } from "akanjs/common";
|
|
11648
12288
|
|
|
@@ -11664,14 +12304,14 @@ class GuidelinePrompt extends Prompter {
|
|
|
11664
12304
|
async#getScanFilePaths(matchPattern, { avoidDirs = ["node_modules", ".next"], filterText } = {}) {
|
|
11665
12305
|
const glob = new Bun.Glob(matchPattern);
|
|
11666
12306
|
const paths = [];
|
|
11667
|
-
for await (const
|
|
11668
|
-
if (avoidDirs.some((dir) =>
|
|
12307
|
+
for await (const path40 of glob.scan({ cwd: this.workspace.workspaceRoot, absolute: true })) {
|
|
12308
|
+
if (avoidDirs.some((dir) => path40.includes(dir)))
|
|
11669
12309
|
continue;
|
|
11670
|
-
const fileContent = await FileSys.readText(
|
|
12310
|
+
const fileContent = await FileSys.readText(path40);
|
|
11671
12311
|
const textFilter = filterText ? new RegExp(filterText) : null;
|
|
11672
12312
|
if (filterText && !textFilter?.test(fileContent))
|
|
11673
12313
|
continue;
|
|
11674
|
-
paths.push(
|
|
12314
|
+
paths.push(path40);
|
|
11675
12315
|
}
|
|
11676
12316
|
return paths;
|
|
11677
12317
|
}
|
|
@@ -11906,6 +12546,22 @@ class GuidelineRunner extends runner("guideline") {
|
|
|
11906
12546
|
|
|
11907
12547
|
// pkgs/@akanjs/cli/guideline/guideline.script.ts
|
|
11908
12548
|
class GuidelineScript extends script("guideline", [GuidelineRunner]) {
|
|
12549
|
+
async guideline(action, name = null, format = "markdown") {
|
|
12550
|
+
if (action === "list") {
|
|
12551
|
+
const guidelines = await Prompter.listGuidelines();
|
|
12552
|
+
Logger18.rawLog(format === "json" ? JSON.stringify({ guidelines }, null, 2) : guidelines.join(`
|
|
12553
|
+
`));
|
|
12554
|
+
return;
|
|
12555
|
+
}
|
|
12556
|
+
if (action === "show") {
|
|
12557
|
+
if (!name)
|
|
12558
|
+
throw new Error("Guideline name is required. Example: akan guideline show framework");
|
|
12559
|
+
const [instruction, guideJson] = await Promise.all([Prompter.getInstruction(name), Prompter.getGuideJson(name)]);
|
|
12560
|
+
Logger18.rawLog(format === "json" ? JSON.stringify({ name, instruction, guideJson }, null, 2) : instruction);
|
|
12561
|
+
return;
|
|
12562
|
+
}
|
|
12563
|
+
throw new Error(`Unknown guideline action: ${action}. Use "list" or "show".`);
|
|
12564
|
+
}
|
|
11909
12565
|
async generateInstruction(workspace, name = null) {
|
|
11910
12566
|
const guideName = name ?? await Prompter.selectGuideline();
|
|
11911
12567
|
await this.guidelineRunner.generateInstruction(workspace, guideName);
|
|
@@ -11934,6 +12590,13 @@ class GuidelineScript extends script("guideline", [GuidelineRunner]) {
|
|
|
11934
12590
|
|
|
11935
12591
|
// pkgs/@akanjs/cli/guideline/guideline.command.ts
|
|
11936
12592
|
class GuidelineCommand extends command("guideline", [GuidelineScript], ({ public: target }) => ({
|
|
12593
|
+
guideline: target({ desc: "List or show Akan AI guideline instructions" }).arg("action", String, { desc: "list or show" }).arg("name", String, { desc: "guideline name for show", nullable: true }).option("format", String, {
|
|
12594
|
+
desc: "output format",
|
|
12595
|
+
default: "markdown",
|
|
12596
|
+
enum: ["markdown", "json"]
|
|
12597
|
+
}).exec(async function(action, name, format) {
|
|
12598
|
+
await this.guidelineScript.guideline(action, name, format);
|
|
12599
|
+
}),
|
|
11937
12600
|
generateInstruction: target({ devOnly: true, desc: "Generate AI development guideline/instruction for your project" }).arg("name", String, { ask: "name of the instruction", nullable: true }).with(Workspace).exec(async function(name, workspace) {
|
|
11938
12601
|
await this.guidelineScript.generateInstruction(workspace, name);
|
|
11939
12602
|
}),
|
|
@@ -11968,8 +12631,8 @@ class LibraryCommand extends command("library", [LibraryScript], ({ public: targ
|
|
|
11968
12631
|
|
|
11969
12632
|
// pkgs/@akanjs/cli/localRegistry/localRegistry.runner.ts
|
|
11970
12633
|
import { mkdir as mkdir11, rm as rm5 } from "fs/promises";
|
|
11971
|
-
import
|
|
11972
|
-
import { Logger as
|
|
12634
|
+
import path40 from "path";
|
|
12635
|
+
import { Logger as Logger19 } from "akanjs/common";
|
|
11973
12636
|
var defaultLocalRegistryUrl = "http://127.0.0.1:4873";
|
|
11974
12637
|
var containerName = "akan-verdaccio";
|
|
11975
12638
|
var smokeRepoName = "akan-local-smoke";
|
|
@@ -11983,11 +12646,11 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
11983
12646
|
const registry = this.getRegistryUrl(registryUrl);
|
|
11984
12647
|
try {
|
|
11985
12648
|
await workspace.spawn("docker", ["inspect", containerName]);
|
|
11986
|
-
|
|
12649
|
+
Logger19.info(`Local registry is already running at ${registry}`);
|
|
11987
12650
|
return registry;
|
|
11988
12651
|
} catch {}
|
|
11989
|
-
const configPath2 =
|
|
11990
|
-
const storagePath =
|
|
12652
|
+
const configPath2 = path40.join(workspace.workspaceRoot, "pkgs/@akanjs/cli/localRegistry/verdaccio.yaml");
|
|
12653
|
+
const storagePath = path40.join(workspace.workspaceRoot, ".akan/verdaccio/storage");
|
|
11991
12654
|
await mkdir11(storagePath, { recursive: true });
|
|
11992
12655
|
await workspace.spawn("docker", [
|
|
11993
12656
|
"run",
|
|
@@ -12003,20 +12666,20 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
12003
12666
|
`${storagePath}:/verdaccio/storage`,
|
|
12004
12667
|
"verdaccio/verdaccio:6"
|
|
12005
12668
|
], { stdio: "inherit" });
|
|
12006
|
-
|
|
12669
|
+
Logger19.info(`Local registry is running at ${registry}`);
|
|
12007
12670
|
return registry;
|
|
12008
12671
|
}
|
|
12009
12672
|
async reset(workspace) {
|
|
12010
12673
|
try {
|
|
12011
12674
|
await workspace.spawn("docker", ["rm", "-f", containerName], { stdio: "inherit" });
|
|
12012
12675
|
} catch {}
|
|
12013
|
-
await rm5(
|
|
12014
|
-
|
|
12676
|
+
await rm5(path40.join(workspace.workspaceRoot, ".akan/verdaccio"), { recursive: true, force: true });
|
|
12677
|
+
Logger19.info("Local registry storage has been reset");
|
|
12015
12678
|
}
|
|
12016
12679
|
async smoke(workspace, { registryUrl } = {}) {
|
|
12017
12680
|
const registry = this.getRegistryUrl(registryUrl);
|
|
12018
|
-
const smokeRoot =
|
|
12019
|
-
await rm5(
|
|
12681
|
+
const smokeRoot = path40.join(workspace.workspaceRoot, ".akan/e2e");
|
|
12682
|
+
await rm5(path40.join(smokeRoot, smokeRepoName), { recursive: true, force: true });
|
|
12020
12683
|
await workspace.spawn(process.execPath, [
|
|
12021
12684
|
"dist/pkgs/create-akan-workspace/index.js",
|
|
12022
12685
|
smokeRepoName,
|
|
@@ -12033,11 +12696,11 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
12033
12696
|
stdio: "inherit"
|
|
12034
12697
|
});
|
|
12035
12698
|
await workspace.spawn("akan", ["build", smokeAppName], {
|
|
12036
|
-
cwd:
|
|
12699
|
+
cwd: path40.join(smokeRoot, smokeRepoName),
|
|
12037
12700
|
env: { ...process.env, AKAN_NPM_REGISTRY: registry, NPM_CONFIG_REGISTRY: registry },
|
|
12038
12701
|
stdio: "inherit"
|
|
12039
12702
|
});
|
|
12040
|
-
|
|
12703
|
+
Logger19.info(`Local registry smoke test completed for ${smokeRepoName}/${smokeAppName}`);
|
|
12041
12704
|
}
|
|
12042
12705
|
}
|
|
12043
12706
|
|
|
@@ -12112,7 +12775,7 @@ import { lowerlize } from "akanjs/common";
|
|
|
12112
12775
|
|
|
12113
12776
|
// pkgs/@akanjs/cli/module/module.script.ts
|
|
12114
12777
|
import { input as input6 } from "@inquirer/prompts";
|
|
12115
|
-
import { capitalize as
|
|
12778
|
+
import { capitalize as capitalize7, randomPicks as randomPicks2 } from "akanjs/common";
|
|
12116
12779
|
|
|
12117
12780
|
// pkgs/@akanjs/cli/page/page.runner.ts
|
|
12118
12781
|
class PageRunner extends runner("page") {
|
|
@@ -12142,7 +12805,7 @@ function pluralizeName(name) {
|
|
|
12142
12805
|
}
|
|
12143
12806
|
|
|
12144
12807
|
// pkgs/@akanjs/cli/module/module.request.ts
|
|
12145
|
-
import { capitalize as
|
|
12808
|
+
import { capitalize as capitalize5 } from "akanjs/common";
|
|
12146
12809
|
|
|
12147
12810
|
// pkgs/@akanjs/cli/module/module.prompt.ts
|
|
12148
12811
|
var componentDefaultDescription = ({
|
|
@@ -12267,7 +12930,7 @@ var requestTemplate = ({
|
|
|
12267
12930
|
${componentDefaultDescription({
|
|
12268
12931
|
sysName,
|
|
12269
12932
|
modelName,
|
|
12270
|
-
ModelName: ModelName ??
|
|
12933
|
+
ModelName: ModelName ?? capitalize5(modelName),
|
|
12271
12934
|
exampleFiles,
|
|
12272
12935
|
constant,
|
|
12273
12936
|
properties
|
|
@@ -12324,7 +12987,7 @@ var requestView = ({
|
|
|
12324
12987
|
${componentDefaultDescription({
|
|
12325
12988
|
sysName,
|
|
12326
12989
|
modelName,
|
|
12327
|
-
ModelName: ModelName ??
|
|
12990
|
+
ModelName: ModelName ?? capitalize5(modelName),
|
|
12328
12991
|
exampleFiles,
|
|
12329
12992
|
constant,
|
|
12330
12993
|
properties
|
|
@@ -12385,7 +13048,7 @@ var requestUnit = ({
|
|
|
12385
13048
|
${componentDefaultDescription({
|
|
12386
13049
|
sysName,
|
|
12387
13050
|
modelName,
|
|
12388
|
-
ModelName: ModelName ??
|
|
13051
|
+
ModelName: ModelName ?? capitalize5(modelName),
|
|
12389
13052
|
exampleFiles,
|
|
12390
13053
|
constant,
|
|
12391
13054
|
properties
|
|
@@ -12434,7 +13097,7 @@ var requestUnit = ({
|
|
|
12434
13097
|
`;
|
|
12435
13098
|
|
|
12436
13099
|
// pkgs/@akanjs/cli/module/module.runner.ts
|
|
12437
|
-
import { capitalize as
|
|
13100
|
+
import { capitalize as capitalize6 } from "akanjs/common";
|
|
12438
13101
|
class ModuleRunner extends runner("module") {
|
|
12439
13102
|
async createService(module) {
|
|
12440
13103
|
const serviceName = module.name.replace(/^_+/, "");
|
|
@@ -12443,13 +13106,15 @@ class ModuleRunner extends runner("module") {
|
|
|
12443
13106
|
template: "service",
|
|
12444
13107
|
dict: { model: serviceName, sysName: module.sys.name }
|
|
12445
13108
|
});
|
|
12446
|
-
const [dictionaryContent, serviceContent, signalContent, storeContent] = await Promise.all([
|
|
13109
|
+
const [abstractContent, dictionaryContent, serviceContent, signalContent, storeContent] = await Promise.all([
|
|
13110
|
+
module.readFile(`${serviceName}.abstract.md`),
|
|
12447
13111
|
module.readFile(`${serviceName}.dictionary.ts`),
|
|
12448
13112
|
module.readFile(`${serviceName}.service.ts`),
|
|
12449
13113
|
module.readFile(`${serviceName}.signal.ts`),
|
|
12450
13114
|
module.readFile(`${serviceName}.store.ts`)
|
|
12451
13115
|
]);
|
|
12452
13116
|
return {
|
|
13117
|
+
abstract: { filename: `${serviceName}.abstract.md`, content: abstractContent },
|
|
12453
13118
|
dictionary: { filename: `${serviceName}.dictionary.ts`, content: dictionaryContent },
|
|
12454
13119
|
service: { filename: `${serviceName}.service.ts`, content: serviceContent },
|
|
12455
13120
|
signal: { filename: `${serviceName}.signal.ts`, content: signalContent },
|
|
@@ -12462,13 +13127,13 @@ class ModuleRunner extends runner("module") {
|
|
|
12462
13127
|
async createComponentTemplate(module, type) {
|
|
12463
13128
|
await module.sys.applyTemplate({
|
|
12464
13129
|
basePath: `./lib/${module.name}`,
|
|
12465
|
-
template: `module/__Model__.${
|
|
13130
|
+
template: `module/__Model__.${capitalize6(type)}.tsx`,
|
|
12466
13131
|
dict: { model: module.name, appName: module.sys.name }
|
|
12467
13132
|
});
|
|
12468
13133
|
return {
|
|
12469
13134
|
component: {
|
|
12470
|
-
filename: `${module.name}.${
|
|
12471
|
-
content: await module.sys.readFile(`lib/${module.name}/${
|
|
13135
|
+
filename: `${module.name}.${capitalize6(type)}.tsx`,
|
|
13136
|
+
content: await module.sys.readFile(`lib/${module.name}/${capitalize6(module.name)}.${capitalize6(type)}.tsx`)
|
|
12472
13137
|
}
|
|
12473
13138
|
};
|
|
12474
13139
|
}
|
|
@@ -12480,6 +13145,7 @@ class ModuleRunner extends runner("module") {
|
|
|
12480
13145
|
dict: { model: module.name, models: names, sysName: module.sys.name }
|
|
12481
13146
|
});
|
|
12482
13147
|
const [
|
|
13148
|
+
abstractContent,
|
|
12483
13149
|
constantContent,
|
|
12484
13150
|
dictionaryContent,
|
|
12485
13151
|
serviceContent,
|
|
@@ -12491,6 +13157,7 @@ class ModuleRunner extends runner("module") {
|
|
|
12491
13157
|
zoneContent,
|
|
12492
13158
|
utilContent
|
|
12493
13159
|
] = await Promise.all([
|
|
13160
|
+
module.readFile(`${module.name}.abstract.md`),
|
|
12494
13161
|
module.readFile(`${module.name}.constant.ts`),
|
|
12495
13162
|
module.readFile(`${module.name}.dictionary.ts`),
|
|
12496
13163
|
module.readFile(`${module.name}.service.ts`),
|
|
@@ -12503,6 +13170,7 @@ class ModuleRunner extends runner("module") {
|
|
|
12503
13170
|
module.readFile(`${module.name}.Util.tsx`)
|
|
12504
13171
|
]);
|
|
12505
13172
|
return {
|
|
13173
|
+
abstract: { filename: `${module.name}.abstract.md`, content: abstractContent },
|
|
12506
13174
|
constant: { filename: `${module.name}.constant.ts`, content: constantContent },
|
|
12507
13175
|
dictionary: { filename: `${module.name}.dictionary.ts`, content: dictionaryContent },
|
|
12508
13176
|
service: { filename: `${module.name}.service.ts`, content: serviceContent },
|
|
@@ -12591,7 +13259,7 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
|
|
|
12591
13259
|
async createTemplate(mod) {
|
|
12592
13260
|
const { component: template } = await this.moduleRunner.createComponentTemplate(mod, "template");
|
|
12593
13261
|
const templateExampleFiles = (await mod.sys.getTemplatesSourceCode()).filter((f) => !f.filePath.includes(`${mod.name}.Template.tsx`));
|
|
12594
|
-
const Name =
|
|
13262
|
+
const Name = capitalize7(mod.name);
|
|
12595
13263
|
const relatedCnsts = getRelatedCnsts(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
12596
13264
|
const constant = await FileSys.readText(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
12597
13265
|
const session = new AiSession("createTemplate", { workspace: mod.sys.workspace, cacheKey: mod.name });
|
|
@@ -12610,7 +13278,7 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
|
|
|
12610
13278
|
}
|
|
12611
13279
|
async createUnit(mod) {
|
|
12612
13280
|
const { component: unit } = await this.moduleRunner.createComponentTemplate(mod, "unit");
|
|
12613
|
-
const Name =
|
|
13281
|
+
const Name = capitalize7(mod.name);
|
|
12614
13282
|
const unitExampleFiles = (await mod.sys.getUnitsSourceCode()).filter((f) => !f.filePath.includes(`${mod.name}.Unit.tsx`));
|
|
12615
13283
|
const relatedCnsts = getRelatedCnsts(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
12616
13284
|
const constant = await FileSys.readText(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
@@ -12631,7 +13299,7 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
|
|
|
12631
13299
|
async createView(mod) {
|
|
12632
13300
|
const { component: view } = await this.moduleRunner.createComponentTemplate(mod, "view");
|
|
12633
13301
|
const viewExampleFiles = (await mod.sys.getViewsSourceCode()).filter((f) => !f.filePath.includes(`${mod.name}.View.tsx`));
|
|
12634
|
-
const Name =
|
|
13302
|
+
const Name = capitalize7(mod.name);
|
|
12635
13303
|
const relatedCnsts = getRelatedCnsts(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
12636
13304
|
const constant = await FileSys.readText(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
12637
13305
|
const session = new AiSession("createView", { workspace: mod.sys.workspace, cacheKey: mod.name });
|
|
@@ -12902,11 +13570,11 @@ class ScalarCommand extends command("scalar", [ScalarScript], ({ public: target
|
|
|
12902
13570
|
}
|
|
12903
13571
|
|
|
12904
13572
|
// pkgs/@akanjs/cli/workspace/workspace.script.ts
|
|
12905
|
-
import
|
|
12906
|
-
import { Logger as
|
|
13573
|
+
import path42 from "path";
|
|
13574
|
+
import { Logger as Logger20 } from "akanjs/common";
|
|
12907
13575
|
|
|
12908
13576
|
// pkgs/@akanjs/cli/workspace/workspace.runner.ts
|
|
12909
|
-
import
|
|
13577
|
+
import path41 from "path";
|
|
12910
13578
|
var defaultWorkspacePeerDependencies = new Set([
|
|
12911
13579
|
"@react-spring/web",
|
|
12912
13580
|
"@use-gesture/react",
|
|
@@ -12925,6 +13593,30 @@ var defaultWorkspacePeerDependencies = new Set([
|
|
|
12925
13593
|
]);
|
|
12926
13594
|
|
|
12927
13595
|
class WorkspaceRunner extends runner("workspace") {
|
|
13596
|
+
async generateAgentRules(workspace, { overwrite = false, cursorRules = true } = {}) {
|
|
13597
|
+
const [appNames] = await workspace.getExecs();
|
|
13598
|
+
const dict = {
|
|
13599
|
+
repoName: workspace.repoName,
|
|
13600
|
+
appName: appNames[0] ?? "app"
|
|
13601
|
+
};
|
|
13602
|
+
const created = await workspace.applyTemplate({
|
|
13603
|
+
basePath: ".",
|
|
13604
|
+
template: "workspaceRoot/AGENTS.md.template",
|
|
13605
|
+
dict,
|
|
13606
|
+
overwrite
|
|
13607
|
+
});
|
|
13608
|
+
if (!cursorRules)
|
|
13609
|
+
return created;
|
|
13610
|
+
return [
|
|
13611
|
+
...created,
|
|
13612
|
+
...await workspace.applyTemplate({
|
|
13613
|
+
basePath: ".cursor/rules",
|
|
13614
|
+
template: "workspaceRoot/.cursor/rules/akan.mdc.template",
|
|
13615
|
+
dict,
|
|
13616
|
+
overwrite
|
|
13617
|
+
})
|
|
13618
|
+
];
|
|
13619
|
+
}
|
|
12928
13620
|
async createWorkspace(repoName, appName, {
|
|
12929
13621
|
dirname: dirname2 = ".",
|
|
12930
13622
|
init = true,
|
|
@@ -12932,7 +13624,7 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
12932
13624
|
registryUrl
|
|
12933
13625
|
}) {
|
|
12934
13626
|
const cwdPath = process.cwd();
|
|
12935
|
-
const workspaceRoot =
|
|
13627
|
+
const workspaceRoot = path41.join(cwdPath, dirname2, repoName);
|
|
12936
13628
|
const normalizedRegistryUrl = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
|
|
12937
13629
|
const workspace = WorkspaceExecutor.fromRoot({ workspaceRoot, repoName });
|
|
12938
13630
|
const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname2}/${repoName}...`);
|
|
@@ -12988,9 +13680,9 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
12988
13680
|
}
|
|
12989
13681
|
async#getCliPackageJson() {
|
|
12990
13682
|
const packageJsonCandidates = [
|
|
12991
|
-
|
|
12992
|
-
|
|
12993
|
-
|
|
13683
|
+
path41.join(import.meta.dir, "../package.json"),
|
|
13684
|
+
path41.join(import.meta.dir, "package.json"),
|
|
13685
|
+
path41.join(path41.dirname(Bun.main), "package.json")
|
|
12994
13686
|
];
|
|
12995
13687
|
try {
|
|
12996
13688
|
packageJsonCandidates.unshift(Bun.resolveSync("@akanjs/cli/package.json", import.meta.dir));
|
|
@@ -13006,9 +13698,9 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
13006
13698
|
}
|
|
13007
13699
|
async#getAkanPackageJson() {
|
|
13008
13700
|
const packageJsonCandidates = [
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
|
|
13701
|
+
path41.join(import.meta.dir, "../../../akanjs/package.json"),
|
|
13702
|
+
path41.join(process.cwd(), "pkgs/akanjs/package.json"),
|
|
13703
|
+
path41.join(path41.dirname(Bun.main), "node_modules/akanjs/package.json")
|
|
13012
13704
|
];
|
|
13013
13705
|
try {
|
|
13014
13706
|
packageJsonCandidates.unshift(Bun.resolveSync("akanjs/package.json", import.meta.dir));
|
|
@@ -13022,13 +13714,13 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
13022
13714
|
}
|
|
13023
13715
|
let current = import.meta.dir;
|
|
13024
13716
|
for (let depth = 0;depth < 6; depth++) {
|
|
13025
|
-
const packageJsonPath =
|
|
13717
|
+
const packageJsonPath = path41.join(current, "package.json");
|
|
13026
13718
|
if (await Bun.file(packageJsonPath).exists()) {
|
|
13027
13719
|
const packageJson = await FileSys.readJson(packageJsonPath);
|
|
13028
13720
|
if (packageJson.name === "akanjs")
|
|
13029
13721
|
return packageJson;
|
|
13030
13722
|
}
|
|
13031
|
-
const parent =
|
|
13723
|
+
const parent = path41.dirname(current);
|
|
13032
13724
|
if (parent === current)
|
|
13033
13725
|
break;
|
|
13034
13726
|
current = parent;
|
|
@@ -13077,13 +13769,18 @@ class WorkspaceScript extends script("workspace", [
|
|
|
13077
13769
|
} catch (_) {
|
|
13078
13770
|
gitSpinner.fail("Git repository initialization failed. It's not fatal, you can commit manually");
|
|
13079
13771
|
}
|
|
13080
|
-
const workspacePath =
|
|
13081
|
-
|
|
13772
|
+
const workspacePath = path42.join(dirname2, repoName);
|
|
13773
|
+
Logger20.rawLog(`
|
|
13082
13774
|
\uD83C\uDF89 Welcome aboard! Workspace created in ${dirname2}/${repoName}`);
|
|
13083
|
-
|
|
13084
|
-
|
|
13775
|
+
Logger20.rawLog(`\uD83D\uDE80 Run \`cd ${workspacePath} && akan start ${appName}\` to start the development server.`);
|
|
13776
|
+
Logger20.rawLog(`
|
|
13085
13777
|
\uD83D\uDC4B Happy coding!`);
|
|
13086
13778
|
}
|
|
13779
|
+
async generateAgentRules(workspace, { overwrite = false, cursorRules = true } = {}) {
|
|
13780
|
+
const spinner2 = workspace.spinning("Generating agent rules...");
|
|
13781
|
+
const files = await this.workspaceRunner.generateAgentRules(workspace, { overwrite, cursorRules });
|
|
13782
|
+
spinner2.succeed(`Agent rules ready (${files.length} file${files.length === 1 ? "" : "s"})`);
|
|
13783
|
+
}
|
|
13087
13784
|
async lint(exec2, workspace, { fix = true } = {}) {
|
|
13088
13785
|
if (exec2 instanceof AppExecutor)
|
|
13089
13786
|
await this.applicationScript.sync(exec2);
|
|
@@ -13143,6 +13840,9 @@ class WorkspaceCommand extends command("workspace", [WorkspaceScript], ({ public
|
|
|
13143
13840
|
const appName = app || "app";
|
|
13144
13841
|
await this.workspaceScript.createWorkspace(workspaceName.toLowerCase().replace(/ /g, "-"), appName.toLowerCase().replace(/ /g, "-"), { dirname: dir, installLibs: libs, init, ...registry ? { registryUrl: registry } : {} });
|
|
13145
13842
|
}),
|
|
13843
|
+
generateAgentRules: target({ desc: "Generate AGENTS.md and optional Cursor rules for Akan coding agents" }).option("overwrite", Boolean, { desc: "Overwrite existing agent rule files", default: false }).option("cursorRules", Boolean, { desc: "Generate .cursor/rules/akan.mdc", default: true }).with(Workspace).exec(async function(overwrite, cursorRules, workspace) {
|
|
13844
|
+
await this.workspaceScript.generateAgentRules(workspace, { overwrite, cursorRules });
|
|
13845
|
+
}),
|
|
13146
13846
|
lint: target({ desc: "Lint and fix code in a specific app/lib/pkg" }).with(Exec).option("fix", Boolean, { default: true }).with(Workspace).exec(async function(exec2, fix, workspace) {
|
|
13147
13847
|
await this.workspaceScript.lint(exec2, workspace, { fix });
|
|
13148
13848
|
}),
|
|
@@ -13156,4 +13856,4 @@ class WorkspaceCommand extends command("workspace", [WorkspaceScript], ({ public
|
|
|
13156
13856
|
}
|
|
13157
13857
|
|
|
13158
13858
|
// pkgs/@akanjs/cli/index.ts
|
|
13159
|
-
runCommands(WorkspaceCommand, ApplicationCommand, LibraryCommand, LocalRegistryCommand, PackageCommand, ModuleCommand, PageCommand, CloudCommand, GuidelineCommand, ScalarCommand);
|
|
13859
|
+
runCommands(WorkspaceCommand, AgentCommand, ApplicationCommand, LibraryCommand, LocalRegistryCommand, PackageCommand, ModuleCommand, PageCommand, ContextCommand, CloudCommand, GuidelineCommand, ScalarCommand);
|