@akanjs/cli 2.1.1-rc.2 → 2.1.1
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/guidelines/modelConstant/modelConstant.generate.json +1 -0
- package/guidelines/modelDictionary/modelDictionary.generate.json +1 -0
- package/guidelines/scalarConstant/scalarConstant.generate.json +1 -0
- package/guidelines/scalarDictionary/scalarDictionary.generate.json +1 -0
- package/incrementalBuilder.proc.js +454 -137
- package/index.js +513 -196
- package/package.json +2 -2
- package/templates/module/__Model__.Unit.tsx +5 -2
- package/typecheck.proc.js +19 -0
package/index.js
CHANGED
|
@@ -327,6 +327,31 @@ var supportedLlmModels = [
|
|
|
327
327
|
"deepseek-chat",
|
|
328
328
|
"deepseek-reasoner"
|
|
329
329
|
];
|
|
330
|
+
var parseTypescriptFileBlocks = (text) => {
|
|
331
|
+
const fileBlocks = [];
|
|
332
|
+
const codeBlockRegex = /```(?:typescript|ts|tsx)\s*\n([\s\S]*?)```/gi;
|
|
333
|
+
const filePathRegex = /^\s*\/\/\s*File:\s*(.+?)\s*$/im;
|
|
334
|
+
for (const codeBlock of text.matchAll(codeBlockRegex)) {
|
|
335
|
+
const content = codeBlock[1]?.trim();
|
|
336
|
+
if (!content)
|
|
337
|
+
continue;
|
|
338
|
+
const filePath = filePathRegex.exec(content)?.[1]?.trim();
|
|
339
|
+
if (!filePath)
|
|
340
|
+
continue;
|
|
341
|
+
fileBlocks.push({
|
|
342
|
+
filePath,
|
|
343
|
+
content: content.replace(filePathRegex, "").trim()
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
return fileBlocks;
|
|
347
|
+
};
|
|
348
|
+
var preserveTypescriptResponseContent = (previousContent, nextContent) => {
|
|
349
|
+
const previousWrites = parseTypescriptFileBlocks(previousContent);
|
|
350
|
+
const nextWrites = parseTypescriptFileBlocks(nextContent);
|
|
351
|
+
if (previousWrites.length > 0 && nextWrites.length === 0)
|
|
352
|
+
return previousContent;
|
|
353
|
+
return nextContent;
|
|
354
|
+
};
|
|
330
355
|
|
|
331
356
|
class AiSession {
|
|
332
357
|
static #cacheDir = "node_modules/.cache/akan/aiSession";
|
|
@@ -446,7 +471,7 @@ class AiSession {
|
|
|
446
471
|
const humanMessage = new HumanMessage(question);
|
|
447
472
|
this.messageHistory.push(humanMessage);
|
|
448
473
|
const stream = await AiSession.#chat.stream(this.messageHistory);
|
|
449
|
-
let reasoningResponse = "", fullResponse = ""
|
|
474
|
+
let reasoningResponse = "", fullResponse = "";
|
|
450
475
|
for await (const chunk of stream) {
|
|
451
476
|
if (loader.isSpinning())
|
|
452
477
|
loader.succeed(`${AiSession.#chat.model} responded`);
|
|
@@ -467,7 +492,6 @@ class AiSession {
|
|
|
467
492
|
fullResponse += content;
|
|
468
493
|
onChunk(content);
|
|
469
494
|
}
|
|
470
|
-
tokenIdx++;
|
|
471
495
|
}
|
|
472
496
|
fullResponse += `
|
|
473
497
|
`;
|
|
@@ -475,7 +499,7 @@ class AiSession {
|
|
|
475
499
|
`);
|
|
476
500
|
this.messageHistory.push(new AIMessage(fullResponse));
|
|
477
501
|
return { content: fullResponse, messageHistory: this.messageHistory };
|
|
478
|
-
} catch
|
|
502
|
+
} catch {
|
|
479
503
|
loader.fail(`${AiSession.#chat.model} failed to respond`);
|
|
480
504
|
throw new Error("Failed to stream response");
|
|
481
505
|
}
|
|
@@ -485,7 +509,8 @@ class AiSession {
|
|
|
485
509
|
onReasoning,
|
|
486
510
|
maxTry = MAX_ASK_TRY,
|
|
487
511
|
validate,
|
|
488
|
-
approve
|
|
512
|
+
approve,
|
|
513
|
+
fallbackToPreviousTypescript
|
|
489
514
|
} = {}) {
|
|
490
515
|
for (let tryCount = 0;tryCount < maxTry; tryCount++) {
|
|
491
516
|
let response = await this.ask(question, { onChunk, onReasoning });
|
|
@@ -493,7 +518,14 @@ class AiSession {
|
|
|
493
518
|
const validateQuestion = `Double check if the response meets the requirements and conditions, and follow the instructions. If not, rewrite it.
|
|
494
519
|
${validate.map((v) => `- ${v}`).join(`
|
|
495
520
|
`)}`;
|
|
496
|
-
|
|
521
|
+
const validateResponse = await this.ask(validateQuestion, {
|
|
522
|
+
onChunk,
|
|
523
|
+
onReasoning
|
|
524
|
+
});
|
|
525
|
+
response = {
|
|
526
|
+
...validateResponse,
|
|
527
|
+
content: fallbackToPreviousTypescript ? preserveTypescriptResponseContent(response.content, validateResponse.content) : validateResponse.content
|
|
528
|
+
};
|
|
497
529
|
}
|
|
498
530
|
const isConfirmed = approve ? true : await select({
|
|
499
531
|
message: "Do you want to edit the response?",
|
|
@@ -526,15 +558,28 @@ ${validate.map((v) => `- ${v}`).join(`
|
|
|
526
558
|
return this;
|
|
527
559
|
}
|
|
528
560
|
async writeTypescripts(question, executor, options = {}) {
|
|
529
|
-
const content = await this.edit(question,
|
|
561
|
+
const content = await this.edit(question, {
|
|
562
|
+
...options,
|
|
563
|
+
fallbackToPreviousTypescript: true
|
|
564
|
+
});
|
|
530
565
|
const writes = this.#getTypescriptCodes(content);
|
|
566
|
+
if (!writes.length)
|
|
567
|
+
throw new Error("No parseable TypeScript file blocks were found in the AI response. Include `// File: <path>` in each code block.");
|
|
531
568
|
for (const write of writes)
|
|
532
569
|
await executor.writeFile(write.filePath, write.content);
|
|
533
570
|
return await this.#tryFixTypescripts(writes, executor, options);
|
|
534
571
|
}
|
|
535
|
-
async#editTypescripts(question, options = {}) {
|
|
536
|
-
const content = await this.edit(question,
|
|
537
|
-
|
|
572
|
+
async#editTypescripts(question, options = {}, fallbackWrites) {
|
|
573
|
+
const content = await this.edit(question, {
|
|
574
|
+
...options,
|
|
575
|
+
fallbackToPreviousTypescript: true
|
|
576
|
+
});
|
|
577
|
+
const writes = this.#getTypescriptCodes(content);
|
|
578
|
+
if (!writes.length && fallbackWrites?.length)
|
|
579
|
+
return fallbackWrites;
|
|
580
|
+
if (!writes.length)
|
|
581
|
+
throw new Error("No parseable TypeScript file blocks were found in the AI response. Include `// File: <path>` in each code block.");
|
|
582
|
+
return writes;
|
|
538
583
|
}
|
|
539
584
|
async#tryFixTypescripts(writes, executor, options = {}) {
|
|
540
585
|
const MAX_EDIT_TRY = 5;
|
|
@@ -543,13 +588,15 @@ ${validate.map((v) => `- ${v}`).join(`
|
|
|
543
588
|
prefix: `\uD83E\uDD16akan-editor`
|
|
544
589
|
}).start();
|
|
545
590
|
const fileChecks = await Promise.all(writes.map(async ({ filePath }) => {
|
|
546
|
-
const
|
|
547
|
-
const
|
|
548
|
-
const
|
|
549
|
-
|
|
591
|
+
const lintResult = await executor.lint(filePath, { fix: true });
|
|
592
|
+
const typeCheckResult = await executor.typeCheckAsync(filePath);
|
|
593
|
+
const hasTypeErrors = typeCheckResult.fileErrors.length > 0;
|
|
594
|
+
const hasLintErrors = lintResult.errors.length > 0;
|
|
595
|
+
const needFix = hasTypeErrors || hasLintErrors;
|
|
596
|
+
return { filePath, typeCheckResult, lintResult, needFix };
|
|
550
597
|
}));
|
|
551
|
-
const
|
|
552
|
-
if (
|
|
598
|
+
const hasAnyFix = fileChecks.some((fileCheck) => fileCheck.needFix);
|
|
599
|
+
if (hasAnyFix) {
|
|
553
600
|
loader.fail("Type checking and linting has some errors, try to fix them");
|
|
554
601
|
fileChecks.forEach((fileCheck) => {
|
|
555
602
|
Logger2.rawLog(`TypeCheck Result
|
|
@@ -565,7 +612,7 @@ ${fileCheck.lintResult.message}`);
|
|
|
565
612
|
...options,
|
|
566
613
|
validate: undefined,
|
|
567
614
|
approve: true
|
|
568
|
-
});
|
|
615
|
+
}, writes);
|
|
569
616
|
for (const write of writes)
|
|
570
617
|
await executor.writeFile(write.filePath, write.content);
|
|
571
618
|
} else {
|
|
@@ -576,21 +623,7 @@ ${fileCheck.lintResult.message}`);
|
|
|
576
623
|
throw new Error("Failed to create scalar");
|
|
577
624
|
}
|
|
578
625
|
#getTypescriptCodes(text) {
|
|
579
|
-
|
|
580
|
-
if (!codes)
|
|
581
|
-
return [];
|
|
582
|
-
const result = codes.map((code) => {
|
|
583
|
-
const content = /```(typescript|tsx)([\s\S]*?)```/.exec(code)?.[2];
|
|
584
|
-
if (!content)
|
|
585
|
-
return null;
|
|
586
|
-
const filePath = /\/\/ File: (.*?)(?:\n|$)/.exec(content)?.[1]?.trim();
|
|
587
|
-
if (!filePath)
|
|
588
|
-
return null;
|
|
589
|
-
const contentWithoutFilepath = content.replace(`// File: ${filePath}
|
|
590
|
-
`, "").trim();
|
|
591
|
-
return { filePath, content: contentWithoutFilepath };
|
|
592
|
-
});
|
|
593
|
-
return result.filter((code) => code !== null);
|
|
626
|
+
return parseTypescriptFileBlocks(text);
|
|
594
627
|
}
|
|
595
628
|
async editMarkdown(request, options = {}) {
|
|
596
629
|
const content = await this.edit(request, options);
|
|
@@ -608,21 +641,26 @@ ${fileCheck.lintResult.message}`);
|
|
|
608
641
|
}
|
|
609
642
|
// pkgs/@akanjs/devkit/akanApp/akanApp.host.ts
|
|
610
643
|
import path9 from "path";
|
|
611
|
-
import { Logger as
|
|
644
|
+
import { Logger as Logger5 } from "akanjs/common";
|
|
612
645
|
|
|
613
646
|
// pkgs/@akanjs/devkit/executors.ts
|
|
614
647
|
import {
|
|
615
648
|
exec,
|
|
616
649
|
fork,
|
|
617
|
-
spawn
|
|
650
|
+
spawn as spawn2
|
|
618
651
|
} from "child_process";
|
|
619
652
|
import { readFileSync as readFileSync3 } from "fs";
|
|
620
|
-
import {
|
|
653
|
+
import {
|
|
654
|
+
copyFile,
|
|
655
|
+
mkdir as mkdir2,
|
|
656
|
+
readdir as readDirEntries,
|
|
657
|
+
stat as stat2
|
|
658
|
+
} from "fs/promises";
|
|
621
659
|
import path7 from "path";
|
|
622
660
|
import {
|
|
623
661
|
capitalize,
|
|
624
662
|
isRouteSourceFile,
|
|
625
|
-
Logger as
|
|
663
|
+
Logger as Logger3,
|
|
626
664
|
parseRouteModuleKey,
|
|
627
665
|
validatePageSourceFile,
|
|
628
666
|
validateSubRoutePageKey
|
|
@@ -985,23 +1023,146 @@ import path2 from "path";
|
|
|
985
1023
|
var getDirname = (url) => path2.dirname(new URL(url).pathname);
|
|
986
1024
|
|
|
987
1025
|
// pkgs/@akanjs/devkit/linter.ts
|
|
1026
|
+
import { spawn } from "child_process";
|
|
988
1027
|
import { existsSync, readFileSync } from "fs";
|
|
989
|
-
import
|
|
990
|
-
import { Logger as Logger3 } from "akanjs/common";
|
|
1028
|
+
import path3 from "path";
|
|
991
1029
|
import chalk2 from "chalk";
|
|
992
1030
|
|
|
993
1031
|
class Linter {
|
|
994
|
-
#logger = new Logger3("Linter");
|
|
995
1032
|
lintRoot;
|
|
1033
|
+
#biomeBin;
|
|
996
1034
|
constructor(cwdPath) {
|
|
997
|
-
this.lintRoot = this.#
|
|
1035
|
+
this.lintRoot = this.#findBiomeRootPath(cwdPath);
|
|
1036
|
+
const localBiomeBin = path3.join(this.lintRoot, "node_modules/.bin/biome");
|
|
1037
|
+
this.#biomeBin = existsSync(localBiomeBin) ? localBiomeBin : "biome";
|
|
998
1038
|
}
|
|
999
|
-
#
|
|
1000
|
-
const configPath2 = path3.join(dir, "
|
|
1039
|
+
#findBiomeRootPath(dir) {
|
|
1040
|
+
const configPath2 = path3.join(dir, "biome.json");
|
|
1001
1041
|
if (existsSync(configPath2))
|
|
1002
1042
|
return dir;
|
|
1003
1043
|
const parentDir = path3.dirname(dir);
|
|
1004
|
-
|
|
1044
|
+
if (parentDir === dir)
|
|
1045
|
+
throw new Error(`biome.json not found from ${dir}`);
|
|
1046
|
+
return this.#findBiomeRootPath(parentDir);
|
|
1047
|
+
}
|
|
1048
|
+
#toBiomePath(filePath) {
|
|
1049
|
+
const relativePath = path3.relative(this.lintRoot, filePath);
|
|
1050
|
+
if (!relativePath.startsWith("..") && !path3.isAbsolute(relativePath))
|
|
1051
|
+
return relativePath;
|
|
1052
|
+
return filePath;
|
|
1053
|
+
}
|
|
1054
|
+
#resolveFilePath(filePath) {
|
|
1055
|
+
return path3.isAbsolute(filePath) ? filePath : path3.join(this.lintRoot, filePath);
|
|
1056
|
+
}
|
|
1057
|
+
async#runBiome(args, input2) {
|
|
1058
|
+
return await new Promise((resolve, reject) => {
|
|
1059
|
+
const proc = spawn(this.#biomeBin, args, {
|
|
1060
|
+
cwd: this.lintRoot,
|
|
1061
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1062
|
+
});
|
|
1063
|
+
let stdout = "";
|
|
1064
|
+
let stderr = "";
|
|
1065
|
+
proc.stdout.on("data", (data) => {
|
|
1066
|
+
stdout += data.toString();
|
|
1067
|
+
});
|
|
1068
|
+
proc.stderr.on("data", (data) => {
|
|
1069
|
+
stderr += data.toString();
|
|
1070
|
+
});
|
|
1071
|
+
proc.on("error", reject);
|
|
1072
|
+
proc.on("close", (code) => resolve({ stdout, stderr, code }));
|
|
1073
|
+
proc.stdin.end(input2);
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
#parseBiomeReport(output) {
|
|
1077
|
+
const jsonStart = output.indexOf("{");
|
|
1078
|
+
const jsonEnd = output.lastIndexOf("}");
|
|
1079
|
+
if (jsonStart === -1 || jsonEnd === -1 || jsonEnd < jsonStart)
|
|
1080
|
+
throw new Error(output.trim() || "No Biome JSON output");
|
|
1081
|
+
return JSON.parse(output.slice(jsonStart, jsonEnd + 1));
|
|
1082
|
+
}
|
|
1083
|
+
#diagnosticFilePath(diagnostic, fallbackFilePath) {
|
|
1084
|
+
const diagnosticPath = diagnostic.location?.path;
|
|
1085
|
+
if (!diagnosticPath)
|
|
1086
|
+
return fallbackFilePath;
|
|
1087
|
+
return path3.isAbsolute(diagnosticPath) ? diagnosticPath : path3.join(this.lintRoot, diagnosticPath);
|
|
1088
|
+
}
|
|
1089
|
+
#createLintMessage(diagnostic) {
|
|
1090
|
+
const start = diagnostic.location?.start;
|
|
1091
|
+
const end = diagnostic.location?.end;
|
|
1092
|
+
return {
|
|
1093
|
+
line: Math.max(1, start?.line ?? 1),
|
|
1094
|
+
column: Math.max(1, start?.column ?? 1),
|
|
1095
|
+
endLine: end?.line,
|
|
1096
|
+
endColumn: end?.column,
|
|
1097
|
+
message: diagnostic.message,
|
|
1098
|
+
ruleId: diagnostic.category ?? null,
|
|
1099
|
+
severity: diagnostic.severity === "error" ? 2 : 1
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
#toLintResults(report, filePath) {
|
|
1103
|
+
const resultsByPath = new Map;
|
|
1104
|
+
for (const diagnostic of report.diagnostics ?? []) {
|
|
1105
|
+
if (diagnostic.severity !== "error" && diagnostic.severity !== "warning")
|
|
1106
|
+
continue;
|
|
1107
|
+
const diagnosticFilePath = this.#diagnosticFilePath(diagnostic, filePath);
|
|
1108
|
+
const result = resultsByPath.get(diagnosticFilePath) ?? {
|
|
1109
|
+
filePath: diagnosticFilePath,
|
|
1110
|
+
messages: [],
|
|
1111
|
+
errorCount: 0,
|
|
1112
|
+
warningCount: 0,
|
|
1113
|
+
fixableErrorCount: 0,
|
|
1114
|
+
fixableWarningCount: 0
|
|
1115
|
+
};
|
|
1116
|
+
const message = this.#createLintMessage(diagnostic);
|
|
1117
|
+
result.messages.push(message);
|
|
1118
|
+
if (message.severity === 2)
|
|
1119
|
+
result.errorCount += 1;
|
|
1120
|
+
else
|
|
1121
|
+
result.warningCount += 1;
|
|
1122
|
+
resultsByPath.set(diagnosticFilePath, result);
|
|
1123
|
+
}
|
|
1124
|
+
return [
|
|
1125
|
+
resultsByPath.get(filePath) ?? {
|
|
1126
|
+
filePath,
|
|
1127
|
+
messages: [],
|
|
1128
|
+
errorCount: 0,
|
|
1129
|
+
warningCount: 0,
|
|
1130
|
+
fixableErrorCount: 0,
|
|
1131
|
+
fixableWarningCount: 0
|
|
1132
|
+
},
|
|
1133
|
+
...[...resultsByPath.entries()].filter(([resultPath]) => resultPath !== filePath).map(([, result]) => result)
|
|
1134
|
+
];
|
|
1135
|
+
}
|
|
1136
|
+
#splitMessages(results) {
|
|
1137
|
+
const messages = results.flatMap((result) => result.messages);
|
|
1138
|
+
return {
|
|
1139
|
+
errors: messages.filter((message) => message.severity === 2),
|
|
1140
|
+
warnings: messages.filter((message) => message.severity === 1)
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
async#checkFile(filePath, { write = false } = {}) {
|
|
1144
|
+
const originalContent = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
|
|
1145
|
+
const { stdout, stderr } = await this.#runBiome([
|
|
1146
|
+
"check",
|
|
1147
|
+
...write ? ["--write"] : [],
|
|
1148
|
+
"--reporter=json",
|
|
1149
|
+
"--max-diagnostics=none",
|
|
1150
|
+
"--no-errors-on-unmatched",
|
|
1151
|
+
"--config-path",
|
|
1152
|
+
path3.join(this.lintRoot, "biome.json"),
|
|
1153
|
+
this.#toBiomePath(filePath)
|
|
1154
|
+
]);
|
|
1155
|
+
const report = this.#parseBiomeReport(stdout || stderr);
|
|
1156
|
+
const results = this.#toLintResults(report, filePath);
|
|
1157
|
+
const { errors, warnings } = this.#splitMessages(results);
|
|
1158
|
+
const output = write && existsSync(filePath) ? readFileSync(filePath, "utf8") : undefined;
|
|
1159
|
+
return {
|
|
1160
|
+
fixed: write && output !== originalContent,
|
|
1161
|
+
output,
|
|
1162
|
+
results,
|
|
1163
|
+
errors,
|
|
1164
|
+
warnings
|
|
1165
|
+
};
|
|
1005
1166
|
}
|
|
1006
1167
|
async lint(filePath, { fix = false, dryRun = false } = {}) {
|
|
1007
1168
|
if (fix)
|
|
@@ -1009,9 +1170,10 @@ class Linter {
|
|
|
1009
1170
|
return await this.lintFile(filePath);
|
|
1010
1171
|
}
|
|
1011
1172
|
async lintFile(filePath) {
|
|
1012
|
-
|
|
1173
|
+
const resolvedFilePath = this.#resolveFilePath(filePath);
|
|
1174
|
+
if (!existsSync(resolvedFilePath))
|
|
1013
1175
|
throw new Error(`File not found: ${filePath}`);
|
|
1014
|
-
return
|
|
1176
|
+
return await this.#checkFile(resolvedFilePath);
|
|
1015
1177
|
}
|
|
1016
1178
|
formatLintResults(results) {
|
|
1017
1179
|
if (results.length === 0)
|
|
@@ -1031,12 +1193,12 @@ ${chalk2.cyan(result.filePath)}`);
|
|
|
1031
1193
|
const sourceContent = readFileSync(result.filePath, "utf8");
|
|
1032
1194
|
sourceLines = sourceContent.split(`
|
|
1033
1195
|
`);
|
|
1034
|
-
} catch
|
|
1196
|
+
} catch {}
|
|
1035
1197
|
}
|
|
1036
1198
|
result.messages.forEach((message) => {
|
|
1037
1199
|
const type = message.severity === 2 ? "error" : "warning";
|
|
1038
1200
|
const typeColor = message.severity === 2 ? chalk2.red : chalk2.yellow;
|
|
1039
|
-
const icon = message.severity === 2 ? "
|
|
1201
|
+
const icon = message.severity === 2 ? "x" : "!";
|
|
1040
1202
|
const ruleInfo = message.ruleId ? chalk2.dim(` (${message.ruleId})`) : "";
|
|
1041
1203
|
output.push(`
|
|
1042
1204
|
${icon} ${typeColor(type)}: ${message.message}${ruleInfo}`);
|
|
@@ -1055,7 +1217,7 @@ ${chalk2.dim(`${lineNumber} |`)} ${sourceLine}`);
|
|
|
1055
1217
|
}
|
|
1056
1218
|
});
|
|
1057
1219
|
if (totalErrors === 0 && totalWarnings === 0)
|
|
1058
|
-
return chalk2.bold("
|
|
1220
|
+
return chalk2.bold("No Biome errors or warnings found");
|
|
1059
1221
|
const errorText = totalErrors > 0 ? chalk2.red(`${totalErrors} error(s)`) : "0 errors";
|
|
1060
1222
|
const warningText = totalWarnings > 0 ? chalk2.yellow(`${totalWarnings} warning(s)`) : "0 warnings";
|
|
1061
1223
|
const summary = [`
|
|
@@ -1070,23 +1232,26 @@ ${errorText}, ${warningText} found`];
|
|
|
1070
1232
|
column: message.column,
|
|
1071
1233
|
message: message.message,
|
|
1072
1234
|
ruleId: message.ruleId,
|
|
1073
|
-
severity: message.severity === 2 ? "error" : "warning"
|
|
1074
|
-
fix: message.fix,
|
|
1075
|
-
suggestions: message.suggestions
|
|
1235
|
+
severity: message.severity === 2 ? "error" : "warning"
|
|
1076
1236
|
})));
|
|
1077
1237
|
const stats = results.reduce((acc, result) => ({
|
|
1078
1238
|
errorCount: acc.errorCount + result.errorCount,
|
|
1079
1239
|
warningCount: acc.warningCount + result.warningCount,
|
|
1080
1240
|
fixableErrorCount: acc.fixableErrorCount + result.fixableErrorCount,
|
|
1081
1241
|
fixableWarningCount: acc.fixableWarningCount + result.fixableWarningCount
|
|
1082
|
-
}), {
|
|
1242
|
+
}), {
|
|
1243
|
+
errorCount: 0,
|
|
1244
|
+
warningCount: 0,
|
|
1245
|
+
fixableErrorCount: 0,
|
|
1246
|
+
fixableWarningCount: 0
|
|
1247
|
+
});
|
|
1083
1248
|
return { results, details, stats };
|
|
1084
1249
|
}
|
|
1085
1250
|
async hasNoLintErrors(filePath) {
|
|
1086
1251
|
try {
|
|
1087
1252
|
const { results } = await this.lintFile(filePath);
|
|
1088
1253
|
return results.every((result) => result.errorCount === 0);
|
|
1089
|
-
} catch
|
|
1254
|
+
} catch {
|
|
1090
1255
|
return false;
|
|
1091
1256
|
}
|
|
1092
1257
|
}
|
|
@@ -1099,12 +1264,28 @@ ${errorText}, ${warningText} found`];
|
|
|
1099
1264
|
return results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
|
|
1100
1265
|
}
|
|
1101
1266
|
async fixFile(filePath, dryRun = false) {
|
|
1102
|
-
|
|
1267
|
+
const resolvedFilePath = this.#resolveFilePath(filePath);
|
|
1268
|
+
if (!existsSync(resolvedFilePath))
|
|
1103
1269
|
throw new Error(`File not found: ${filePath}`);
|
|
1104
|
-
|
|
1270
|
+
if (!dryRun)
|
|
1271
|
+
return await this.#checkFile(resolvedFilePath, { write: true });
|
|
1272
|
+
const source = readFileSync(resolvedFilePath, "utf8");
|
|
1273
|
+
const { stdout } = await this.#runBiome([
|
|
1274
|
+
"check",
|
|
1275
|
+
"--write",
|
|
1276
|
+
"--config-path",
|
|
1277
|
+
path3.join(this.lintRoot, "biome.json"),
|
|
1278
|
+
"--stdin-file-path",
|
|
1279
|
+
this.#toBiomePath(resolvedFilePath)
|
|
1280
|
+
], source);
|
|
1281
|
+
const lintResult = await this.lintFile(resolvedFilePath);
|
|
1282
|
+
return { ...lintResult, fixed: stdout !== source, output: stdout };
|
|
1105
1283
|
}
|
|
1106
1284
|
async getConfigForFile(filePath) {
|
|
1107
|
-
|
|
1285
|
+
const resolvedFilePath = this.#resolveFilePath(filePath);
|
|
1286
|
+
if (!existsSync(resolvedFilePath))
|
|
1287
|
+
throw new Error(`File not found: ${filePath}`);
|
|
1288
|
+
return JSON.parse(readFileSync(path3.join(this.lintRoot, "biome.json"), "utf8"));
|
|
1108
1289
|
}
|
|
1109
1290
|
async getProblematicRules(filePath) {
|
|
1110
1291
|
const { results } = await this.lintFile(filePath);
|
|
@@ -1494,23 +1675,23 @@ async function assertScanConvention(exec, libRoot) {
|
|
|
1494
1675
|
files.filter((filename) => !appRootAllowedFiles.has(filename)).forEach((filename) => {
|
|
1495
1676
|
addViolation(filename, "unsupported app root file");
|
|
1496
1677
|
});
|
|
1497
|
-
dirs.filter((
|
|
1498
|
-
addViolation(
|
|
1678
|
+
dirs.filter((dirname) => !appRootAllowedDirs.has(dirname)).forEach((dirname) => {
|
|
1679
|
+
addViolation(dirname, "unsupported app root folder");
|
|
1499
1680
|
});
|
|
1500
1681
|
}
|
|
1501
1682
|
libRoot.files.filter((filename) => !isAllowedLibRootFile(filename)).forEach((filename) => {
|
|
1502
1683
|
addViolation(path5.join("lib", filename), "unsupported lib root file");
|
|
1503
1684
|
});
|
|
1504
|
-
libRoot.dirs.filter((
|
|
1505
|
-
addViolation(path5.join("lib",
|
|
1685
|
+
libRoot.dirs.filter((dirname) => dirname.startsWith("__") && !internalLibDirs.has(dirname)).forEach((dirname) => {
|
|
1686
|
+
addViolation(path5.join("lib", dirname), "unsupported internal lib folder");
|
|
1506
1687
|
});
|
|
1507
|
-
const databaseDirs = libRoot.dirs.filter((
|
|
1508
|
-
const serviceDirs = libRoot.dirs.filter((
|
|
1688
|
+
const databaseDirs = libRoot.dirs.filter((dirname) => !dirname.startsWith("_"));
|
|
1689
|
+
const serviceDirs = libRoot.dirs.filter((dirname) => dirname.startsWith("_") && !dirname.startsWith("__"));
|
|
1509
1690
|
const scalarDirs = await exec.readdir("lib/__scalar");
|
|
1510
1691
|
await Promise.all([
|
|
1511
|
-
...databaseDirs.map((
|
|
1512
|
-
...serviceDirs.map((
|
|
1513
|
-
...scalarDirs.map((
|
|
1692
|
+
...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database", path5.join("lib", dirname))),
|
|
1693
|
+
...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service", path5.join("lib", dirname))),
|
|
1694
|
+
...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar", path5.join("lib/__scalar", dirname)))
|
|
1514
1695
|
]);
|
|
1515
1696
|
if (violations.length > 0) {
|
|
1516
1697
|
throw new Error(`[scan-convention]
|
|
@@ -1520,8 +1701,8 @@ ${violations.sort().map((violation) => `- ${violation}`).join(`
|
|
|
1520
1701
|
}
|
|
1521
1702
|
async function validateModuleFiles(exec, violations, kind, modulePath) {
|
|
1522
1703
|
const { files, dirs } = await exec.getFilesAndDirs(modulePath);
|
|
1523
|
-
dirs.forEach((
|
|
1524
|
-
violations.push(`${getScanPath(exec, path5.join(modulePath,
|
|
1704
|
+
dirs.forEach((dirname) => {
|
|
1705
|
+
violations.push(`${getScanPath(exec, path5.join(modulePath, dirname))}: unsupported module folder`);
|
|
1525
1706
|
});
|
|
1526
1707
|
files.forEach((filename) => {
|
|
1527
1708
|
const filePath = path5.join(modulePath, filename);
|
|
@@ -1620,9 +1801,9 @@ class ScanInfo {
|
|
|
1620
1801
|
files.zone.databases.push(name);
|
|
1621
1802
|
});
|
|
1622
1803
|
}),
|
|
1623
|
-
...serviceDirs.map(async (
|
|
1624
|
-
const name =
|
|
1625
|
-
const filenames = await exec.readdir(path5.join("lib",
|
|
1804
|
+
...serviceDirs.map(async (dirname) => {
|
|
1805
|
+
const name = dirname.slice(1);
|
|
1806
|
+
const filenames = await exec.readdir(path5.join("lib", dirname));
|
|
1626
1807
|
filenames.forEach((filename) => {
|
|
1627
1808
|
if (filename.endsWith(".dictionary.ts"))
|
|
1628
1809
|
files.dictionary.services.push(name);
|
|
@@ -2191,8 +2372,13 @@ class CommandExecutionError extends Error {
|
|
|
2191
2372
|
const displayCommand = formatCommandForDisplay(command, args);
|
|
2192
2373
|
const status = signal ? `signal: ${signal}` : `exit code: ${code ?? "unknown"}`;
|
|
2193
2374
|
const output = (stderr || stdout).trim();
|
|
2194
|
-
super([
|
|
2195
|
-
|
|
2375
|
+
super([
|
|
2376
|
+
`Command failed: ${displayCommand}`,
|
|
2377
|
+
`cwd: ${cwd}`,
|
|
2378
|
+
status,
|
|
2379
|
+
output ? `
|
|
2380
|
+
${output}` : ""
|
|
2381
|
+
].join(`
|
|
2196
2382
|
`), {
|
|
2197
2383
|
cause
|
|
2198
2384
|
});
|
|
@@ -2241,7 +2427,13 @@ var parseEnvFile = (envPath) => {
|
|
|
2241
2427
|
}
|
|
2242
2428
|
return env;
|
|
2243
2429
|
};
|
|
2244
|
-
var PAGE_ROUTE_EXPORTS = new Set([
|
|
2430
|
+
var PAGE_ROUTE_EXPORTS = new Set([
|
|
2431
|
+
"default",
|
|
2432
|
+
"pageConfig",
|
|
2433
|
+
"head",
|
|
2434
|
+
"generateHead",
|
|
2435
|
+
"Loading"
|
|
2436
|
+
]);
|
|
2245
2437
|
var ROOT_LAYOUT_EXPORTS = new Set([
|
|
2246
2438
|
"default",
|
|
2247
2439
|
"head",
|
|
@@ -2254,7 +2446,12 @@ var ROOT_LAYOUT_EXPORTS = new Set([
|
|
|
2254
2446
|
"gaTrackingId",
|
|
2255
2447
|
"Loading"
|
|
2256
2448
|
]);
|
|
2257
|
-
var LAYOUT_ROUTE_EXPORTS = new Set([
|
|
2449
|
+
var LAYOUT_ROUTE_EXPORTS = new Set([
|
|
2450
|
+
"default",
|
|
2451
|
+
"head",
|
|
2452
|
+
"generateHead",
|
|
2453
|
+
"Loading"
|
|
2454
|
+
]);
|
|
2258
2455
|
function validateRouteSourceExports(source, filePath, kind, options = {}) {
|
|
2259
2456
|
const sourceFile = ts3.createSourceFile(filePath, source, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
|
|
2260
2457
|
const allowed = kind === "page" ? PAGE_ROUTE_EXPORTS : options.rootLayout ? ROOT_LAYOUT_EXPORTS : LAYOUT_ROUTE_EXPORTS;
|
|
@@ -2323,16 +2520,16 @@ class Executor {
|
|
|
2323
2520
|
linter = null;
|
|
2324
2521
|
constructor(name, cwdPath) {
|
|
2325
2522
|
this.name = name;
|
|
2326
|
-
this.logger = new
|
|
2523
|
+
this.logger = new Logger3(name);
|
|
2327
2524
|
this.logs = [];
|
|
2328
2525
|
this.cwdPath = cwdPath;
|
|
2329
2526
|
}
|
|
2330
2527
|
#stdout(data) {
|
|
2331
2528
|
if (Executor.verbose)
|
|
2332
|
-
|
|
2529
|
+
Logger3.raw(chalk4.dim(data.toString()));
|
|
2333
2530
|
}
|
|
2334
2531
|
#stderr(data) {
|
|
2335
|
-
|
|
2532
|
+
Logger3.raw(chalk4.red(data.toString()));
|
|
2336
2533
|
}
|
|
2337
2534
|
exec(command, options = {}) {
|
|
2338
2535
|
const cwd = options.cwd?.toString() ?? this.cwdPath;
|
|
@@ -2376,7 +2573,7 @@ class Executor {
|
|
|
2376
2573
|
}
|
|
2377
2574
|
spawn(command, args = [], options = {}) {
|
|
2378
2575
|
const cwd = options.cwd?.toString() ?? this.cwdPath;
|
|
2379
|
-
const proc =
|
|
2576
|
+
const proc = spawn2(command, args, {
|
|
2380
2577
|
cwd: this.cwdPath,
|
|
2381
2578
|
...options
|
|
2382
2579
|
});
|
|
@@ -2422,7 +2619,7 @@ class Executor {
|
|
|
2422
2619
|
});
|
|
2423
2620
|
}
|
|
2424
2621
|
spawnSync(command, args = [], options = {}) {
|
|
2425
|
-
const proc =
|
|
2622
|
+
const proc = spawn2(command, args, {
|
|
2426
2623
|
cwd: this.cwdPath,
|
|
2427
2624
|
...options
|
|
2428
2625
|
});
|
|
@@ -2554,7 +2751,7 @@ class Executor {
|
|
|
2554
2751
|
contentStr = currentContent;
|
|
2555
2752
|
} else {
|
|
2556
2753
|
await FileSys.writeText(writePath, contentStr);
|
|
2557
|
-
if (
|
|
2754
|
+
if (Logger3.isVerbose())
|
|
2558
2755
|
this.logger.rawLog(chalk4.yellow(`File Update: ${filePath}`));
|
|
2559
2756
|
}
|
|
2560
2757
|
} else {
|
|
@@ -2601,7 +2798,11 @@ class Executor {
|
|
|
2601
2798
|
this.logger.debug(msg);
|
|
2602
2799
|
return this;
|
|
2603
2800
|
}
|
|
2604
|
-
spinning(msg, {
|
|
2801
|
+
spinning(msg, {
|
|
2802
|
+
prefix = `${this.emoji}${this.name}`,
|
|
2803
|
+
indent = 0,
|
|
2804
|
+
enableSpin = !Executor.verbose
|
|
2805
|
+
} = {}) {
|
|
2605
2806
|
return new Spinner(msg, { prefix, indent, enableSpin }).start();
|
|
2606
2807
|
}
|
|
2607
2808
|
#tsconfig = null;
|
|
@@ -2630,7 +2831,9 @@ class Executor {
|
|
|
2630
2831
|
this.#tsconfig = tsconfig;
|
|
2631
2832
|
}
|
|
2632
2833
|
#packageJson = null;
|
|
2633
|
-
async getPackageJson({
|
|
2834
|
+
async getPackageJson({
|
|
2835
|
+
refresh
|
|
2836
|
+
} = {}) {
|
|
2634
2837
|
if (this.#packageJson && !refresh)
|
|
2635
2838
|
return this.#packageJson;
|
|
2636
2839
|
const packageJson = await this.readJson("package.json");
|
|
@@ -2663,8 +2866,8 @@ class Executor {
|
|
|
2663
2866
|
return null;
|
|
2664
2867
|
const filename = typeof result === "object" ? result.filename : path7.basename(targetPath).replace(".js", ".ts");
|
|
2665
2868
|
const content = typeof result === "object" ? result.content : result;
|
|
2666
|
-
const
|
|
2667
|
-
const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), `${
|
|
2869
|
+
const dirname2 = path7.dirname(targetPath);
|
|
2870
|
+
const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), `${dirname2}/${filename}`);
|
|
2668
2871
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2669
2872
|
return this.writeFile(convertedTargetPath, content, { overwrite });
|
|
2670
2873
|
} else if (targetPath.endsWith(".template")) {
|
|
@@ -2678,9 +2881,9 @@ class Executor {
|
|
|
2678
2881
|
} else if (staticTemplateFileExtensions.has(path7.extname(targetPath).toLowerCase())) {
|
|
2679
2882
|
const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath);
|
|
2680
2883
|
const writePath = this.getPath(convertedTargetPath);
|
|
2681
|
-
const
|
|
2682
|
-
if (!await FileSys.dirExists(
|
|
2683
|
-
await mkdir2(
|
|
2884
|
+
const dirname2 = path7.dirname(writePath);
|
|
2885
|
+
if (!await FileSys.dirExists(dirname2))
|
|
2886
|
+
await mkdir2(dirname2, { recursive: true });
|
|
2684
2887
|
await copyFile(templatePath, writePath);
|
|
2685
2888
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2686
2889
|
return { filePath: writePath, content: "" };
|
|
@@ -2746,7 +2949,10 @@ class Executor {
|
|
|
2746
2949
|
async applyTemplate(options) {
|
|
2747
2950
|
const dict = {
|
|
2748
2951
|
...options.dict ?? {},
|
|
2749
|
-
...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
|
|
2952
|
+
...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
|
|
2953
|
+
capitalize(key),
|
|
2954
|
+
capitalize(value)
|
|
2955
|
+
]))
|
|
2750
2956
|
};
|
|
2751
2957
|
return this._applyTemplate({ ...options, dict });
|
|
2752
2958
|
}
|
|
@@ -2761,6 +2967,48 @@ class Executor {
|
|
|
2761
2967
|
const message = typeChecker.formatDiagnostics(fileDiagnostics);
|
|
2762
2968
|
return { fileDiagnostics, fileErrors, fileWarnings, message };
|
|
2763
2969
|
}
|
|
2970
|
+
async typeCheckAsync(filePath) {
|
|
2971
|
+
const path8 = this.getPath(filePath);
|
|
2972
|
+
const entry = await this.#resolveTypecheckWorkerEntry();
|
|
2973
|
+
const proc = Bun.spawn([process.execPath, entry], {
|
|
2974
|
+
cwd: this.cwdPath,
|
|
2975
|
+
env: {
|
|
2976
|
+
...process.env,
|
|
2977
|
+
AKAN_TYPECHECK_CWD: this.cwdPath,
|
|
2978
|
+
AKAN_TYPECHECK_FILE: path8
|
|
2979
|
+
},
|
|
2980
|
+
stdout: "pipe",
|
|
2981
|
+
stderr: "pipe"
|
|
2982
|
+
});
|
|
2983
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
2984
|
+
new Response(proc.stdout).text(),
|
|
2985
|
+
new Response(proc.stderr).text(),
|
|
2986
|
+
proc.exited
|
|
2987
|
+
]);
|
|
2988
|
+
if (exitCode !== 0)
|
|
2989
|
+
throw new Error((stderr || stdout).trim() || `Typecheck failed with exit code ${exitCode}`);
|
|
2990
|
+
const result = JSON.parse(stdout);
|
|
2991
|
+
return {
|
|
2992
|
+
fileDiagnostics: Array.from({ length: result.fileDiagnosticsCount }),
|
|
2993
|
+
fileErrors: Array.from({ length: result.fileErrorsCount }),
|
|
2994
|
+
fileWarnings: Array.from({ length: result.fileWarningsCount }),
|
|
2995
|
+
message: result.message
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2998
|
+
async#resolveTypecheckWorkerEntry() {
|
|
2999
|
+
const dirname2 = getDirname(import.meta.url);
|
|
3000
|
+
const candidates = [
|
|
3001
|
+
path7.join(process.cwd(), "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
3002
|
+
path7.join(process.cwd(), "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
3003
|
+
path7.join(dirname2, "typecheck/typecheck.proc.ts"),
|
|
3004
|
+
path7.join(dirname2, "typecheck.proc.js"),
|
|
3005
|
+
path7.join(dirname2, "typecheck.proc.ts")
|
|
3006
|
+
];
|
|
3007
|
+
for (const candidate of candidates)
|
|
3008
|
+
if (await Bun.file(candidate).exists())
|
|
3009
|
+
return candidate;
|
|
3010
|
+
throw new Error(`[devkit] typecheck worker entry not found; looked in: ${candidates.join(", ")}`);
|
|
3011
|
+
}
|
|
2764
3012
|
getLinter() {
|
|
2765
3013
|
this.linter ??= new Linter(this.cwdPath);
|
|
2766
3014
|
return this.linter;
|
|
@@ -2808,7 +3056,15 @@ class WorkspaceExecutor extends Executor {
|
|
|
2808
3056
|
const env = sourceEnv.AKAN_PUBLIC_ENV ?? "debug";
|
|
2809
3057
|
if (!env)
|
|
2810
3058
|
throw new Error("AKAN_PUBLIC_ENV is not set");
|
|
2811
|
-
return {
|
|
3059
|
+
return {
|
|
3060
|
+
...appName ? { appName } : {},
|
|
3061
|
+
workspaceRoot,
|
|
3062
|
+
repoName,
|
|
3063
|
+
serveDomain,
|
|
3064
|
+
env,
|
|
3065
|
+
portOffset,
|
|
3066
|
+
workspaceId
|
|
3067
|
+
};
|
|
2812
3068
|
}
|
|
2813
3069
|
getWorkspaceId({
|
|
2814
3070
|
allowEmpty
|
|
@@ -2832,7 +3088,10 @@ class WorkspaceExecutor extends Executor {
|
|
|
2832
3088
|
return await this.#getDirHasFile(`${this.workspaceRoot}/libs`, "akan.config.ts");
|
|
2833
3089
|
}
|
|
2834
3090
|
async getSyss() {
|
|
2835
|
-
const [appNames, libNames] = await Promise.all([
|
|
3091
|
+
const [appNames, libNames] = await Promise.all([
|
|
3092
|
+
this.getApps(),
|
|
3093
|
+
this.getLibs()
|
|
3094
|
+
]);
|
|
2836
3095
|
return [appNames, libNames];
|
|
2837
3096
|
}
|
|
2838
3097
|
async getPkgs() {
|
|
@@ -2841,7 +3100,11 @@ class WorkspaceExecutor extends Executor {
|
|
|
2841
3100
|
return await this.#getDirHasFile(`${this.workspaceRoot}/pkgs`, "package.json");
|
|
2842
3101
|
}
|
|
2843
3102
|
async getExecs() {
|
|
2844
|
-
const [appNames, libNames, pkgNames] = await Promise.all([
|
|
3103
|
+
const [appNames, libNames, pkgNames] = await Promise.all([
|
|
3104
|
+
this.getApps(),
|
|
3105
|
+
this.getLibs(),
|
|
3106
|
+
this.getPkgs()
|
|
3107
|
+
]);
|
|
2845
3108
|
return [appNames, libNames, pkgNames];
|
|
2846
3109
|
}
|
|
2847
3110
|
async setPkgTsPaths(name) {
|
|
@@ -2859,7 +3122,10 @@ class WorkspaceExecutor extends Executor {
|
|
|
2859
3122
|
async unsetPkgTsPaths(name) {
|
|
2860
3123
|
const rootTsConfig = await this.readJson("tsconfig.json");
|
|
2861
3124
|
const filteredKeys = Object.keys(rootTsConfig.compilerOptions.paths ?? {}).filter((key) => key !== name && key !== `${name}/*`);
|
|
2862
|
-
rootTsConfig.compilerOptions.paths = Object.fromEntries(filteredKeys.map((key) => [
|
|
3125
|
+
rootTsConfig.compilerOptions.paths = Object.fromEntries(filteredKeys.map((key) => [
|
|
3126
|
+
key,
|
|
3127
|
+
rootTsConfig.compilerOptions.paths?.[key] ?? []
|
|
3128
|
+
]));
|
|
2863
3129
|
if (rootTsConfig.references) {
|
|
2864
3130
|
rootTsConfig.references = rootTsConfig.references.filter((ref) => ref.path !== `./pkgs/${name}/tsconfig.json`);
|
|
2865
3131
|
}
|
|
@@ -2868,12 +3134,12 @@ class WorkspaceExecutor extends Executor {
|
|
|
2868
3134
|
}
|
|
2869
3135
|
async getDirInModule(basePath2, name) {
|
|
2870
3136
|
const AVOID_DIRS = ["__lib", "__scalar", `_`, `_${name}`];
|
|
2871
|
-
const getDirs = async (
|
|
2872
|
-
const dirs = await this.readdir(
|
|
3137
|
+
const getDirs = async (dirname2, maxDepth = 3, results = [], prefix = "") => {
|
|
3138
|
+
const dirs = await this.readdir(dirname2);
|
|
2873
3139
|
await Promise.all(dirs.map(async (dir) => {
|
|
2874
3140
|
if (dir.includes("_") || AVOID_DIRS.includes(dir))
|
|
2875
3141
|
return;
|
|
2876
|
-
const dirPath = path7.join(
|
|
3142
|
+
const dirPath = path7.join(dirname2, dir);
|
|
2877
3143
|
if ((await stat2(dirPath)).isDirectory()) {
|
|
2878
3144
|
results.push(`${prefix}${dir}`);
|
|
2879
3145
|
if (maxDepth > 0)
|
|
@@ -2893,12 +3159,12 @@ class WorkspaceExecutor extends Executor {
|
|
|
2893
3159
|
}
|
|
2894
3160
|
async#getDirHasFile(basePath2, targetFilename) {
|
|
2895
3161
|
const AVOID_DIRS = ["node_modules", "dist", "public", "webkit"];
|
|
2896
|
-
const getDirs = async (
|
|
2897
|
-
const dirs = await this.readdir(
|
|
3162
|
+
const getDirs = async (dirname2, maxDepth = 3, results = [], prefix = "") => {
|
|
3163
|
+
const dirs = await this.readdir(dirname2);
|
|
2898
3164
|
await Promise.all(dirs.map(async (dir) => {
|
|
2899
3165
|
if (AVOID_DIRS.includes(dir))
|
|
2900
3166
|
return;
|
|
2901
|
-
const dirPath = path7.join(
|
|
3167
|
+
const dirPath = path7.join(dirname2, dir);
|
|
2902
3168
|
if ((await stat2(dirPath)).isDirectory()) {
|
|
2903
3169
|
const hasTargetFile = await FileSys.fileExists(path7.join(dirPath, targetFilename));
|
|
2904
3170
|
if (hasTargetFile)
|
|
@@ -2951,7 +3217,11 @@ class SysExecutor extends Executor {
|
|
|
2951
3217
|
name;
|
|
2952
3218
|
type;
|
|
2953
3219
|
emoji;
|
|
2954
|
-
constructor({
|
|
3220
|
+
constructor({
|
|
3221
|
+
workspace = WorkspaceExecutor.fromRoot(),
|
|
3222
|
+
name,
|
|
3223
|
+
type
|
|
3224
|
+
}) {
|
|
2955
3225
|
super(name, `${workspace.workspaceRoot}/${type}s/${name}`);
|
|
2956
3226
|
this.workspace = workspace;
|
|
2957
3227
|
this.name = name;
|
|
@@ -3054,7 +3324,10 @@ class SysExecutor extends Executor {
|
|
|
3054
3324
|
},
|
|
3055
3325
|
devDependencies: {
|
|
3056
3326
|
...Object.fromEntries(Object.entries(libPackageJson.devDependencies ?? {}).filter(([dep]) => !dependencySet.has(dep))),
|
|
3057
|
-
...Object.fromEntries(devDependencies.filter((dep) => rootPackageJson.dependencies?.[dep] || rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [
|
|
3327
|
+
...Object.fromEntries(devDependencies.filter((dep) => rootPackageJson.dependencies?.[dep] || rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [
|
|
3328
|
+
dep,
|
|
3329
|
+
rootPackageJson.devDependencies?.[dep] ?? rootPackageJson.dependencies?.[dep]
|
|
3330
|
+
]))
|
|
3058
3331
|
}
|
|
3059
3332
|
};
|
|
3060
3333
|
await this.setPackageJson(libPkgJsonWithDeps);
|
|
@@ -3121,7 +3394,11 @@ class SysExecutor extends Executor {
|
|
|
3121
3394
|
...await LibExecutor.from(this, lib).getConstantFiles(),
|
|
3122
3395
|
...await LibExecutor.from(this, lib).getScalarConstantFiles()
|
|
3123
3396
|
]));
|
|
3124
|
-
return [
|
|
3397
|
+
return [
|
|
3398
|
+
...sysContantFiles,
|
|
3399
|
+
...sysScalarConstantFiles,
|
|
3400
|
+
...libConstantFiles.flat()
|
|
3401
|
+
];
|
|
3125
3402
|
}
|
|
3126
3403
|
async getDictionaryFiles() {
|
|
3127
3404
|
const modules = await this.getModules();
|
|
@@ -3130,7 +3407,10 @@ class SysExecutor extends Executor {
|
|
|
3130
3407
|
async applyTemplate(options) {
|
|
3131
3408
|
const dict = {
|
|
3132
3409
|
...options.dict ?? {},
|
|
3133
|
-
...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
|
|
3410
|
+
...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
|
|
3411
|
+
capitalize(key),
|
|
3412
|
+
capitalize(value)
|
|
3413
|
+
]))
|
|
3134
3414
|
};
|
|
3135
3415
|
const scanInfo = await this.scan();
|
|
3136
3416
|
const fileContents = await this._applyTemplate({
|
|
@@ -3189,7 +3469,10 @@ class AppExecutor extends SysExecutor {
|
|
|
3189
3469
|
if (type === "build") {
|
|
3190
3470
|
if (await this.exists(this.dist.cwdPath))
|
|
3191
3471
|
await this.dist.exec(`rm -rf ${this.dist.cwdPath}`);
|
|
3192
|
-
await Promise.all([
|
|
3472
|
+
await Promise.all([
|
|
3473
|
+
this.dist.mkdir("private"),
|
|
3474
|
+
this.dist.mkdir("public")
|
|
3475
|
+
]);
|
|
3193
3476
|
await Promise.all([
|
|
3194
3477
|
this.cp("private", `${this.dist.cwdPath}/private`),
|
|
3195
3478
|
this.cp("public", `${this.dist.cwdPath}/public`)
|
|
@@ -3232,7 +3515,9 @@ class AppExecutor extends SysExecutor {
|
|
|
3232
3515
|
return this.#akanConfig;
|
|
3233
3516
|
}
|
|
3234
3517
|
#pageKeys = null;
|
|
3235
|
-
async getPageKeys({
|
|
3518
|
+
async getPageKeys({
|
|
3519
|
+
refresh
|
|
3520
|
+
} = {}) {
|
|
3236
3521
|
if (this.#pageKeys && !refresh)
|
|
3237
3522
|
return this.#pageKeys;
|
|
3238
3523
|
const akanConfig2 = await this.getConfig();
|
|
@@ -3281,7 +3566,10 @@ class AppExecutor extends SysExecutor {
|
|
|
3281
3566
|
const projectAssetsPath = `${this.cwdPath}/private`;
|
|
3282
3567
|
const projectPublicLibPath = `${projectPublicPath}/libs`;
|
|
3283
3568
|
const projectAssetsLibPath = `${projectAssetsPath}/libs`;
|
|
3284
|
-
await Promise.all([
|
|
3569
|
+
await Promise.all([
|
|
3570
|
+
this.removeDir(projectPublicLibPath),
|
|
3571
|
+
this.removeDir(projectAssetsLibPath)
|
|
3572
|
+
]);
|
|
3285
3573
|
const targetPublicDeps = [];
|
|
3286
3574
|
for (const dep of libDeps) {
|
|
3287
3575
|
if (await this.exists(`${this.workspace.workspaceRoot}/libs/${dep}/public`))
|
|
@@ -3299,7 +3587,10 @@ class AppExecutor extends SysExecutor {
|
|
|
3299
3587
|
...targetAssetsDeps.map((dep) => this.cp(`${this.workspace.workspaceRoot}/libs/${dep}/private`, `${projectAssetsLibPath}/${dep}`))
|
|
3300
3588
|
]);
|
|
3301
3589
|
}
|
|
3302
|
-
async scanSync({
|
|
3590
|
+
async scanSync({
|
|
3591
|
+
refresh = false,
|
|
3592
|
+
write = true
|
|
3593
|
+
} = {}) {
|
|
3303
3594
|
const scanInfo = await this.scan({
|
|
3304
3595
|
refresh,
|
|
3305
3596
|
write,
|
|
@@ -3348,7 +3639,10 @@ class PkgExecutor extends Executor {
|
|
|
3348
3639
|
name;
|
|
3349
3640
|
dist;
|
|
3350
3641
|
emoji = execEmoji.pkg;
|
|
3351
|
-
constructor({
|
|
3642
|
+
constructor({
|
|
3643
|
+
workspace = WorkspaceExecutor.fromRoot(),
|
|
3644
|
+
name
|
|
3645
|
+
}) {
|
|
3352
3646
|
super(name, `${workspace.workspaceRoot}/pkgs/${name}`);
|
|
3353
3647
|
this.workspace = workspace;
|
|
3354
3648
|
this.name = name;
|
|
@@ -3412,7 +3706,10 @@ class PkgExecutor extends Executor {
|
|
|
3412
3706
|
};
|
|
3413
3707
|
}
|
|
3414
3708
|
async updatePackageJsonDependencies(dependencies = [], devDependencies = []) {
|
|
3415
|
-
const [rootPackageJson, pkgJson] = await Promise.all([
|
|
3709
|
+
const [rootPackageJson, pkgJson] = await Promise.all([
|
|
3710
|
+
this.workspace.getPackageJson(),
|
|
3711
|
+
this.getPackageJson()
|
|
3712
|
+
]);
|
|
3416
3713
|
const dependencyMaps = await this.#toDependencyMap(rootPackageJson, dependencies, devDependencies);
|
|
3417
3714
|
const newPkgJson = {
|
|
3418
3715
|
...pkgJson,
|
|
@@ -3422,7 +3719,10 @@ class PkgExecutor extends Executor {
|
|
|
3422
3719
|
return newPkgJson;
|
|
3423
3720
|
}
|
|
3424
3721
|
async generateDistPackageJson(dependencies = [], devDependencies = []) {
|
|
3425
|
-
const [rootPackageJson, pkgJson] = await Promise.all([
|
|
3722
|
+
const [rootPackageJson, pkgJson] = await Promise.all([
|
|
3723
|
+
this.workspace.getPackageJson(),
|
|
3724
|
+
this.getPackageJson()
|
|
3725
|
+
]);
|
|
3426
3726
|
const dependencyMaps = await this.#toDependencyMap(rootPackageJson, dependencies, devDependencies);
|
|
3427
3727
|
const distPkgJson = {
|
|
3428
3728
|
...pkgJson,
|
|
@@ -3438,7 +3738,10 @@ class PkgExecutor extends Executor {
|
|
|
3438
3738
|
engines: { bun: ">=1.3.13" },
|
|
3439
3739
|
...dependencyMaps
|
|
3440
3740
|
};
|
|
3441
|
-
await Promise.all([
|
|
3741
|
+
await Promise.all([
|
|
3742
|
+
this.dist.writeJson("package.json", distPkgJson),
|
|
3743
|
+
this.writeJson("package.json", distPkgJson)
|
|
3744
|
+
]);
|
|
3442
3745
|
return distPkgJson;
|
|
3443
3746
|
}
|
|
3444
3747
|
async build() {
|
|
@@ -3451,7 +3754,10 @@ class PkgExecutor extends Executor {
|
|
|
3451
3754
|
await this.cp(`${this.cwdPath}/dist`, this.dist.cwdPath);
|
|
3452
3755
|
}
|
|
3453
3756
|
async generateTsconfigJson() {
|
|
3454
|
-
const [rootTsconfig, pkgTsconfig] = await Promise.all([
|
|
3757
|
+
const [rootTsconfig, pkgTsconfig] = await Promise.all([
|
|
3758
|
+
this.workspace.getTsConfig(),
|
|
3759
|
+
this.getTsConfig()
|
|
3760
|
+
]);
|
|
3455
3761
|
const tsconfig = {
|
|
3456
3762
|
...rootTsconfig,
|
|
3457
3763
|
...pkgTsconfig,
|
|
@@ -3615,7 +3921,7 @@ var createTunnel = async (service, { app, environment, port = service === "postg
|
|
|
3615
3921
|
|
|
3616
3922
|
// pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.host.ts
|
|
3617
3923
|
import path8 from "path";
|
|
3618
|
-
import { Logger as
|
|
3924
|
+
import { Logger as Logger4 } from "akanjs/common";
|
|
3619
3925
|
var builderMsgTypeSet = new Set([
|
|
3620
3926
|
"build-route-res",
|
|
3621
3927
|
"builder-ready",
|
|
@@ -3627,7 +3933,7 @@ var builderMsgTypeSet = new Set([
|
|
|
3627
3933
|
class IncrementalBuilderHost {
|
|
3628
3934
|
static #restartBaseDelayMs = 1000;
|
|
3629
3935
|
static #restartMaxDelayMs = 30000;
|
|
3630
|
-
logger = new
|
|
3936
|
+
logger = new Logger4("IncrementalBuilderHost");
|
|
3631
3937
|
entry;
|
|
3632
3938
|
env;
|
|
3633
3939
|
app;
|
|
@@ -3875,7 +4181,7 @@ class BackendImportGraph {
|
|
|
3875
4181
|
|
|
3876
4182
|
class AkanAppHost {
|
|
3877
4183
|
app;
|
|
3878
|
-
logger = new
|
|
4184
|
+
logger = new Logger5("AkanAppHost");
|
|
3879
4185
|
withInk;
|
|
3880
4186
|
env;
|
|
3881
4187
|
#backend = null;
|
|
@@ -4158,19 +4464,19 @@ class AkanAppHost {
|
|
|
4158
4464
|
}
|
|
4159
4465
|
}
|
|
4160
4466
|
// pkgs/@akanjs/devkit/applicationBuildReporter.ts
|
|
4161
|
-
import { Logger as
|
|
4467
|
+
import { Logger as Logger6 } from "akanjs/common";
|
|
4162
4468
|
|
|
4163
4469
|
class ApplicationBuildReporter {
|
|
4164
4470
|
static create() {
|
|
4165
4471
|
return {
|
|
4166
|
-
phaseDone: (phase) =>
|
|
4472
|
+
phaseDone: (phase) => Logger6.rawLog(ApplicationBuildReporter.formatPhaseLine(phase))
|
|
4167
4473
|
};
|
|
4168
4474
|
}
|
|
4169
4475
|
static printSummary(result) {
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4476
|
+
Logger6.rawLog("");
|
|
4477
|
+
Logger6.rawLog(`Route artifacts: ${result.artifactDir}`);
|
|
4478
|
+
Logger6.rawLog(`Server output: ${result.outputDir}`);
|
|
4479
|
+
Logger6.rawLog(`Done in ${ApplicationBuildReporter.formatDuration(result.durationMs)}`);
|
|
4174
4480
|
}
|
|
4175
4481
|
static formatError(error) {
|
|
4176
4482
|
if (error instanceof AggregateError) {
|
|
@@ -4469,13 +4775,13 @@ import path14 from "path";
|
|
|
4469
4775
|
|
|
4470
4776
|
// pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
|
|
4471
4777
|
import path12 from "path";
|
|
4472
|
-
import { Logger as
|
|
4778
|
+
import { Logger as Logger7 } from "akanjs/common";
|
|
4473
4779
|
var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
|
|
4474
4780
|
var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
|
|
4475
4781
|
var CANDIDATE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
4476
4782
|
|
|
4477
4783
|
class BarrelAnalyzer {
|
|
4478
|
-
#logger = new
|
|
4784
|
+
#logger = new Logger7("BarrelAnalyzer");
|
|
4479
4785
|
#opts;
|
|
4480
4786
|
#cache = new Map;
|
|
4481
4787
|
#tsTranspiler = new Bun.Transpiler({ loader: "ts" });
|
|
@@ -6175,7 +6481,7 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
|
6175
6481
|
}
|
|
6176
6482
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
6177
6483
|
import path23 from "path";
|
|
6178
|
-
import { Logger as
|
|
6484
|
+
import { Logger as Logger8 } from "akanjs/common";
|
|
6179
6485
|
import { compile } from "tailwindcss";
|
|
6180
6486
|
|
|
6181
6487
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
@@ -6320,7 +6626,7 @@ var NODE_MODULES_RE3 = /[\\/]node_modules[\\/]/;
|
|
|
6320
6626
|
var AKANJS_NODE_MODULE_RE3 = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
6321
6627
|
|
|
6322
6628
|
class CssCompiler {
|
|
6323
|
-
#logger = new
|
|
6629
|
+
#logger = new Logger8("CssCompiler");
|
|
6324
6630
|
#transpiler = new Bun.Transpiler({ loader: "tsx" });
|
|
6325
6631
|
#app;
|
|
6326
6632
|
#cssImportResolver = null;
|
|
@@ -7728,7 +8034,7 @@ class ApplicationBuildRunner {
|
|
|
7728
8034
|
import { cp, mkdir as mkdir8, rm as rm3 } from "fs/promises";
|
|
7729
8035
|
|
|
7730
8036
|
// pkgs/@akanjs/devkit/uploadRelease.ts
|
|
7731
|
-
import { HttpClient as HttpClient2, Logger as
|
|
8037
|
+
import { HttpClient as HttpClient2, Logger as Logger9 } from "akanjs/common";
|
|
7732
8038
|
var spinning = (message) => {
|
|
7733
8039
|
const spinner = new Spinner(message, { prefix: message, enableSpin: true }).start();
|
|
7734
8040
|
return spinner;
|
|
@@ -7741,7 +8047,7 @@ var uploadRelease = async (appName, {
|
|
|
7741
8047
|
os,
|
|
7742
8048
|
local
|
|
7743
8049
|
}) => {
|
|
7744
|
-
const logger = new
|
|
8050
|
+
const logger = new Logger9("uploadRelease");
|
|
7745
8051
|
const basePath2 = local ? "http://localhost:8282/backend" : "https://cloud.akanjs.com/backend";
|
|
7746
8052
|
const httpClient = new HttpClient2(basePath2);
|
|
7747
8053
|
const buildPath = `${workspaceRoot}/releases/builds/${appName}-release.tar.gz`;
|
|
@@ -8727,7 +9033,7 @@ var Workspace = createInternalArgToken("Workspace");
|
|
|
8727
9033
|
// pkgs/@akanjs/devkit/commandDecorators/command.ts
|
|
8728
9034
|
import path36 from "path";
|
|
8729
9035
|
import { confirm, input as input2, select as select2 } from "@inquirer/prompts";
|
|
8730
|
-
import { Logger as
|
|
9036
|
+
import { Logger as Logger10 } from "akanjs/common";
|
|
8731
9037
|
import chalk6 from "chalk";
|
|
8732
9038
|
import { program } from "commander";
|
|
8733
9039
|
|
|
@@ -9012,7 +9318,7 @@ var printCliError = (error) => {
|
|
|
9012
9318
|
if (loggedCliErrorMessages.has(message))
|
|
9013
9319
|
return;
|
|
9014
9320
|
loggedCliErrorMessages.add(message);
|
|
9015
|
-
|
|
9321
|
+
Logger10.rawLog(`
|
|
9016
9322
|
${chalk6.red(message)}`);
|
|
9017
9323
|
};
|
|
9018
9324
|
var handleOption = (programCommand, argMeta) => {
|
|
@@ -9241,7 +9547,7 @@ var runCommands = async (...commands) => {
|
|
|
9241
9547
|
const hasCommand = process.argv.length > 2 && !process.argv[2]?.startsWith("-");
|
|
9242
9548
|
if (hasHelpFlag || !hasCommand) {
|
|
9243
9549
|
if (process.argv.length === 2 || process.argv.length === 3 && hasHelpFlag) {
|
|
9244
|
-
|
|
9550
|
+
Logger10.rawLog(formatHelp(commands, process.env.AKAN_VERSION));
|
|
9245
9551
|
process.exit(0);
|
|
9246
9552
|
}
|
|
9247
9553
|
}
|
|
@@ -9250,7 +9556,7 @@ var runCommands = async (...commands) => {
|
|
|
9250
9556
|
});
|
|
9251
9557
|
const installedAkanPackageJson = await FileSys.fileExists("./node_modules/akanjs/package.json") ? await FileSys.readJson("./node_modules/akanjs/package.json") : null;
|
|
9252
9558
|
if (installedAkanPackageJson && installedAkanPackageJson.version !== process.env.AKAN_VERSION) {
|
|
9253
|
-
|
|
9559
|
+
Logger10.rawLog(chalk6.yellow(`
|
|
9254
9560
|
Akan CLI version is mismatch with installed package. ${process.env.AKAN_VERSION} (global) vs ${installedAkanPackageJson.version} (akanjs)
|
|
9255
9561
|
It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`));
|
|
9256
9562
|
}
|
|
@@ -9286,7 +9592,7 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
|
|
|
9286
9592
|
return formatCommandHelp(command, targetMeta.key);
|
|
9287
9593
|
};
|
|
9288
9594
|
programCommand.action(async (...args) => {
|
|
9289
|
-
|
|
9595
|
+
Logger10.rawLog();
|
|
9290
9596
|
const cmdArgs = args.slice(0, args.length - 2);
|
|
9291
9597
|
const opt = args[args.length - 2];
|
|
9292
9598
|
const commandArgs = [];
|
|
@@ -9310,7 +9616,7 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
|
|
|
9310
9616
|
const cmd = CommandContainer.get(command);
|
|
9311
9617
|
try {
|
|
9312
9618
|
await targetMeta.handler.call(cmd, ...commandArgs);
|
|
9313
|
-
|
|
9619
|
+
Logger10.rawLog();
|
|
9314
9620
|
} catch (e) {
|
|
9315
9621
|
printCliError(e);
|
|
9316
9622
|
throw e;
|
|
@@ -9650,8 +9956,11 @@ import fsPromise from "fs/promises";
|
|
|
9650
9956
|
import { input as input3, select as select3 } from "@inquirer/prompts";
|
|
9651
9957
|
class Prompter {
|
|
9652
9958
|
static async#getGuidelineRoot() {
|
|
9653
|
-
const
|
|
9654
|
-
const candidates = [
|
|
9959
|
+
const dirname2 = getDirname(import.meta.url);
|
|
9960
|
+
const candidates = [
|
|
9961
|
+
`${dirname2}/guidelines`,
|
|
9962
|
+
`${dirname2}/../cli/guidelines`
|
|
9963
|
+
];
|
|
9655
9964
|
for (const candidate of candidates) {
|
|
9656
9965
|
try {
|
|
9657
9966
|
await fsPromise.access(candidate);
|
|
@@ -9663,7 +9972,10 @@ class Prompter {
|
|
|
9663
9972
|
static async selectGuideline() {
|
|
9664
9973
|
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
9665
9974
|
const guideNames = (await fsPromise.readdir(guidelineRoot)).filter((name) => !name.startsWith("_"));
|
|
9666
|
-
return await select3({
|
|
9975
|
+
return await select3({
|
|
9976
|
+
message: "Select a guideline",
|
|
9977
|
+
choices: guideNames.map((name) => ({ name, value: name }))
|
|
9978
|
+
});
|
|
9667
9979
|
}
|
|
9668
9980
|
static async getGuideJson(guideName) {
|
|
9669
9981
|
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
@@ -9678,13 +9990,18 @@ class Prompter {
|
|
|
9678
9990
|
return content;
|
|
9679
9991
|
}
|
|
9680
9992
|
static async getUpdateRequest(guideName) {
|
|
9681
|
-
return await input3({
|
|
9993
|
+
return await input3({
|
|
9994
|
+
message: `What do you want to update in ${guideName}?`
|
|
9995
|
+
});
|
|
9682
9996
|
}
|
|
9683
9997
|
async makeTsFileUpdatePrompt({ context, request }) {
|
|
9684
9998
|
return `You are a senior developer writing TypeScript-based programs using Akan.js, an in-house framework. Here's an overview of the Akan.js framework:
|
|
9685
9999
|
${await this.getDocumentation("framework")}
|
|
9686
10000
|
Please understand the following background information, write code that meets the requirements, verify that it satisfies the validation conditions, and return the result.
|
|
9687
10001
|
|
|
10002
|
+
# Code Style
|
|
10003
|
+
- Use double quotes for all string literals in TypeScript/TSX code. Do not use single quotes.
|
|
10004
|
+
|
|
9688
10005
|
# Background Information
|
|
9689
10006
|
\`\`\`markdown
|
|
9690
10007
|
${context}
|
|
@@ -9734,7 +10051,7 @@ import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime"
|
|
|
9734
10051
|
import { select as select6 } from "@inquirer/prompts";
|
|
9735
10052
|
|
|
9736
10053
|
// pkgs/@akanjs/cli/application/application.script.ts
|
|
9737
|
-
import { Logger as
|
|
10054
|
+
import { Logger as Logger12 } from "akanjs/common";
|
|
9738
10055
|
|
|
9739
10056
|
// pkgs/@akanjs/cli/semver.ts
|
|
9740
10057
|
function parseVersion(version) {
|
|
@@ -9852,14 +10169,14 @@ import { StringOutputParser } from "@langchain/core/output_parsers";
|
|
|
9852
10169
|
import { PromptTemplate as PromptTemplate2 } from "@langchain/core/prompts";
|
|
9853
10170
|
import { RunnableSequence as RunnableSequence2 } from "@langchain/core/runnables";
|
|
9854
10171
|
import { ChatOpenAI as ChatOpenAI3 } from "@langchain/openai";
|
|
9855
|
-
import { Logger as
|
|
10172
|
+
import { Logger as Logger11 } from "akanjs/common";
|
|
9856
10173
|
import ora3 from "ora";
|
|
9857
10174
|
|
|
9858
10175
|
// pkgs/@akanjs/cli/openBrowser.ts
|
|
9859
|
-
import { spawn as
|
|
10176
|
+
import { spawn as spawn3 } from "child_process";
|
|
9860
10177
|
function openBrowser(url) {
|
|
9861
10178
|
const command3 = process.platform === "darwin" ? ["open", url] : process.platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
|
|
9862
|
-
const child =
|
|
10179
|
+
const child = spawn3(command3[0], command3.slice(1), { detached: true, stdio: "ignore" });
|
|
9863
10180
|
child.on("error", () => {});
|
|
9864
10181
|
child.unref();
|
|
9865
10182
|
return Promise.resolve();
|
|
@@ -10045,7 +10362,7 @@ class ApplicationRunner extends runner("application") {
|
|
|
10045
10362
|
return;
|
|
10046
10363
|
for (const failure of failures) {
|
|
10047
10364
|
const message = failure.error instanceof Error ? failure.error.message : String(failure.error);
|
|
10048
|
-
|
|
10365
|
+
Logger11.rawLog(`Mobile target ${failure.target} failed: ${message}`, undefined, "error");
|
|
10049
10366
|
}
|
|
10050
10367
|
throw new Error(`${failures.length}/${results.length} mobile targets failed`);
|
|
10051
10368
|
}
|
|
@@ -10190,18 +10507,18 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
10190
10507
|
async build(app, { write = true, fast = false, quiet = false } = {}) {
|
|
10191
10508
|
await app.scanSync({ write });
|
|
10192
10509
|
if (!quiet)
|
|
10193
|
-
|
|
10510
|
+
Logger12.rawLog(`Creating an optimized production build for ${app.name}...`);
|
|
10194
10511
|
try {
|
|
10195
10512
|
const result = await this.applicationRunner.build(app, {
|
|
10196
10513
|
fast,
|
|
10197
10514
|
spinner: !quiet
|
|
10198
10515
|
});
|
|
10199
|
-
|
|
10516
|
+
Logger12.rawLog(`${app.name} built in dist/apps/${app.name}`);
|
|
10200
10517
|
if (!quiet)
|
|
10201
10518
|
ApplicationBuildReporter.printSummary(result);
|
|
10202
10519
|
} catch (error) {
|
|
10203
|
-
|
|
10204
|
-
|
|
10520
|
+
Logger12.rawLog(`${app.name} build failed in dist/apps/${app.name}`, undefined, "error");
|
|
10521
|
+
Logger12.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
|
|
10205
10522
|
throw error;
|
|
10206
10523
|
}
|
|
10207
10524
|
}
|
|
@@ -10213,7 +10530,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
10213
10530
|
spinner2.succeed(`${app.name} typechecked`);
|
|
10214
10531
|
} catch (error) {
|
|
10215
10532
|
spinner2.fail(`${app.name} typecheck failed`);
|
|
10216
|
-
|
|
10533
|
+
Logger12.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
|
|
10217
10534
|
throw error;
|
|
10218
10535
|
}
|
|
10219
10536
|
}
|
|
@@ -10477,11 +10794,11 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
|
|
|
10477
10794
|
}
|
|
10478
10795
|
|
|
10479
10796
|
// pkgs/@akanjs/cli/cloud/cloud.script.ts
|
|
10480
|
-
import { Logger as
|
|
10797
|
+
import { Logger as Logger15 } from "akanjs/common";
|
|
10481
10798
|
|
|
10482
10799
|
// pkgs/@akanjs/cli/package/package.runner.ts
|
|
10483
10800
|
import path37 from "path";
|
|
10484
|
-
import { Logger as
|
|
10801
|
+
import { Logger as Logger13 } from "akanjs/common";
|
|
10485
10802
|
var {$: $2 } = globalThis.Bun;
|
|
10486
10803
|
|
|
10487
10804
|
class PackageRunner extends runner("package") {
|
|
@@ -10489,7 +10806,7 @@ class PackageRunner extends runner("package") {
|
|
|
10489
10806
|
const pkgJson = process.env.USE_AKANJS_PKGS === "true" ? await FileSys.readJson(`${workspace?.workspaceRoot ?? process.cwd()}/pkgs/akanjs/package.json`) : await this.#getInstalledPackageJson();
|
|
10490
10807
|
const version = pkgJson.name === "akanjs" ? pkgJson.version : pkgJson.dependencies?.akanjs ?? pkgJson.version;
|
|
10491
10808
|
if (log)
|
|
10492
|
-
|
|
10809
|
+
Logger13.rawLog(`akanjs@${version}`);
|
|
10493
10810
|
return version;
|
|
10494
10811
|
}
|
|
10495
10812
|
async#getInstalledPackageJson() {
|
|
@@ -10617,7 +10934,7 @@ class PackageScript extends script("package", [PackageRunner]) {
|
|
|
10617
10934
|
// pkgs/@akanjs/cli/cloud/cloud.runner.ts
|
|
10618
10935
|
import path38 from "path";
|
|
10619
10936
|
import { confirm as confirm3, input as input5, select as select7 } from "@inquirer/prompts";
|
|
10620
|
-
import { Logger as
|
|
10937
|
+
import { Logger as Logger14, sleep } from "akanjs/common";
|
|
10621
10938
|
import chalk7 from "chalk";
|
|
10622
10939
|
import * as QRcode from "qrcode";
|
|
10623
10940
|
|
|
@@ -10697,7 +11014,7 @@ class CloudRunner extends runner("cloud") {
|
|
|
10697
11014
|
const servers = await GlobalConfig.getRemoteEnvServers();
|
|
10698
11015
|
const serverEntries = Object.entries(servers).sort(([nameA], [nameB]) => nameA.localeCompare(nameB));
|
|
10699
11016
|
if (serverEntries.length === 0) {
|
|
10700
|
-
|
|
11017
|
+
Logger14.info("No remote env servers configured. Add the first remote server for SCP mode.");
|
|
10701
11018
|
return await this.#addRemoteEnvServer();
|
|
10702
11019
|
}
|
|
10703
11020
|
const selectedName = await select7({
|
|
@@ -10737,7 +11054,7 @@ class CloudRunner extends runner("cloud") {
|
|
|
10737
11054
|
if (!shouldRemove)
|
|
10738
11055
|
return;
|
|
10739
11056
|
await GlobalConfig.removeRemoteEnvServer(selectedName);
|
|
10740
|
-
|
|
11057
|
+
Logger14.info(`Removed remote env server "${selectedName}"`);
|
|
10741
11058
|
}
|
|
10742
11059
|
async#getRemoteEnvServerWithUsername() {
|
|
10743
11060
|
const remoteServer = await this.#selectRemoteEnvServer();
|
|
@@ -10786,17 +11103,17 @@ class CloudRunner extends runner("cloud") {
|
|
|
10786
11103
|
const cloudApi2 = new CloudApi(config);
|
|
10787
11104
|
const self = config.auth ? await cloudApi2.getRemoteSelf() : null;
|
|
10788
11105
|
if (self) {
|
|
10789
|
-
|
|
11106
|
+
Logger14.rawLog(chalk7.green(`
|
|
10790
11107
|
\u2713 Already logged in akan cloud as ${self.nickname}
|
|
10791
11108
|
`));
|
|
10792
11109
|
return true;
|
|
10793
11110
|
}
|
|
10794
11111
|
const remoteId = crypto.randomUUID();
|
|
10795
11112
|
const signinUrl = `${akanCloudUrl}/signin?remoteId=${remoteId}`;
|
|
10796
|
-
|
|
11113
|
+
Logger14.rawLog(chalk7.bold(`
|
|
10797
11114
|
${chalk7.green("\u27A4")} Authentication Required`));
|
|
10798
|
-
|
|
10799
|
-
|
|
11115
|
+
Logger14.rawLog(chalk7.dim("Please visit or click the following URL:"));
|
|
11116
|
+
Logger14.rawLog(`${chalk7.cyan.underline(signinUrl)}
|
|
10800
11117
|
`);
|
|
10801
11118
|
try {
|
|
10802
11119
|
const qrcode = await new Promise((resolve, reject) => {
|
|
@@ -10806,13 +11123,13 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
10806
11123
|
resolve(data);
|
|
10807
11124
|
});
|
|
10808
11125
|
});
|
|
10809
|
-
|
|
11126
|
+
Logger14.rawLog(qrcode);
|
|
10810
11127
|
await openBrowser(signinUrl);
|
|
10811
|
-
|
|
11128
|
+
Logger14.rawLog(chalk7.dim("Opening browser..."));
|
|
10812
11129
|
} catch {
|
|
10813
|
-
|
|
11130
|
+
Logger14.rawLog(chalk7.yellow("Could not open browser. Please visit the URL manually."));
|
|
10814
11131
|
}
|
|
10815
|
-
|
|
11132
|
+
Logger14.rawLog(chalk7.dim("Waiting for authentication..."));
|
|
10816
11133
|
const MAX_RETRY = 300;
|
|
10817
11134
|
for (let i = 0;i < MAX_RETRY; i++) {
|
|
10818
11135
|
const accessToken = await cloudApi2.getRemoteAuthToken(remoteId);
|
|
@@ -10821,10 +11138,10 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
10821
11138
|
await GlobalConfig.setHostConfig(akanCloudHost, {
|
|
10822
11139
|
auth: { accessToken, self: self2 }
|
|
10823
11140
|
});
|
|
10824
|
-
|
|
10825
|
-
|
|
11141
|
+
Logger14.rawLog(chalk7.green(`\r\u2713 Authentication successful!`));
|
|
11142
|
+
Logger14.rawLog(chalk7.green.bold(`
|
|
10826
11143
|
\u2728 Welcome aboard, ${self2.nickname}!`));
|
|
10827
|
-
|
|
11144
|
+
Logger14.rawLog(chalk7.dim(`You're now ready to use Akan CLI!
|
|
10828
11145
|
`));
|
|
10829
11146
|
return true;
|
|
10830
11147
|
}
|
|
@@ -10836,17 +11153,17 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
10836
11153
|
const config = await GlobalConfig.getHostConfig();
|
|
10837
11154
|
if (config.auth?.self) {
|
|
10838
11155
|
await GlobalConfig.setHostConfig(akanCloudHost, {});
|
|
10839
|
-
|
|
11156
|
+
Logger14.rawLog(chalk7.magenta.bold(`
|
|
10840
11157
|
\uD83D\uDC4B Goodbye, ${config.auth.self.nickname}!`));
|
|
10841
|
-
|
|
11158
|
+
Logger14.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
|
|
10842
11159
|
`));
|
|
10843
|
-
|
|
10844
|
-
|
|
11160
|
+
Logger14.rawLog(chalk7.cyan("You have been successfully logged out."));
|
|
11161
|
+
Logger14.rawLog(chalk7.dim(`Thank you for using Akan CLI. Come back soon! \uD83C\uDF1F
|
|
10845
11162
|
`));
|
|
10846
11163
|
} else {
|
|
10847
|
-
|
|
11164
|
+
Logger14.rawLog(chalk7.yellow.bold(`
|
|
10848
11165
|
\u26A0\uFE0F No active session found`));
|
|
10849
|
-
|
|
11166
|
+
Logger14.rawLog(chalk7.dim(`You were not logged in to begin with
|
|
10850
11167
|
`));
|
|
10851
11168
|
}
|
|
10852
11169
|
}
|
|
@@ -10855,7 +11172,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
10855
11172
|
}
|
|
10856
11173
|
resetLlm() {
|
|
10857
11174
|
AiSession.setLlmConfig(null);
|
|
10858
|
-
|
|
11175
|
+
Logger14.rawLog(chalk7.green("\u2611\uFE0F LLM model config is cleared. Please run `akan set-llm` to set a new LLM model."));
|
|
10859
11176
|
}
|
|
10860
11177
|
async getAkanPkgs(workspace) {
|
|
10861
11178
|
const pkgs = await workspace.getPkgs();
|
|
@@ -10879,8 +11196,8 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
10879
11196
|
}
|
|
10880
11197
|
};
|
|
10881
11198
|
const { nextVersion, latestPublishedVersion } = await getNextVersion(targetVersionPrefix, tag);
|
|
10882
|
-
|
|
10883
|
-
|
|
11199
|
+
Logger14.info(`Latest published version of akanjs: ${latestPublishedVersion ?? "none"}`);
|
|
11200
|
+
Logger14.info(`Next version of akanjs: ${nextVersion}`);
|
|
10884
11201
|
for (const library of akanPkgs) {
|
|
10885
11202
|
const packageJson = await workspace.readJson(`pkgs/${library}/package.json`);
|
|
10886
11203
|
const newPackageJsonStr = JSON.stringify(this.#normalizeAkanPackageJson(packageJson, library, nextVersion), null, 2);
|
|
@@ -10894,12 +11211,12 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
10894
11211
|
message: "Are you sure you want to deploy the libraries?"
|
|
10895
11212
|
});
|
|
10896
11213
|
if (!isDeployConfirmed) {
|
|
10897
|
-
|
|
11214
|
+
Logger14.error("Deployment cancelled");
|
|
10898
11215
|
return;
|
|
10899
11216
|
}
|
|
10900
11217
|
}
|
|
10901
11218
|
await Promise.all(akanPkgs.map(async (library) => {
|
|
10902
|
-
|
|
11219
|
+
Logger14.info(`Publishing ${library}@${nextVersion} to ${registry ?? "npm"}...`);
|
|
10903
11220
|
await workspace.spawn("npm", [
|
|
10904
11221
|
"publish",
|
|
10905
11222
|
"--tag",
|
|
@@ -10911,9 +11228,9 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
10911
11228
|
env: this.#getRegistryEnv(registry),
|
|
10912
11229
|
stdio: "inherit"
|
|
10913
11230
|
});
|
|
10914
|
-
|
|
11231
|
+
Logger14.info(`${library}@${nextVersion} is published to ${registry ?? "npm"}`);
|
|
10915
11232
|
}));
|
|
10916
|
-
|
|
11233
|
+
Logger14.info(`All libraries are published to ${registry ?? "npm"}`);
|
|
10917
11234
|
}
|
|
10918
11235
|
async update(workspace, tag = "latest", { registryUrl } = {}) {
|
|
10919
11236
|
const registry = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
|
|
@@ -10992,7 +11309,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
10992
11309
|
await workspace.mkdir("local");
|
|
10993
11310
|
await workspace.remove(envArchivePath);
|
|
10994
11311
|
try {
|
|
10995
|
-
|
|
11312
|
+
Logger14.info(`Downloading env archive from remote server "${remoteServer.name}"...`);
|
|
10996
11313
|
await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, remoteTarget, envArchivePath), {
|
|
10997
11314
|
cwd: workspace.workspaceRoot,
|
|
10998
11315
|
stdio: "inherit"
|
|
@@ -11015,7 +11332,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11015
11332
|
cwd: workspace.workspaceRoot,
|
|
11016
11333
|
stdio: "inherit"
|
|
11017
11334
|
});
|
|
11018
|
-
|
|
11335
|
+
Logger14.info(`Uploading env archive to remote server "${remoteServer.name}"...`);
|
|
11019
11336
|
await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, filePath, remoteTarget), {
|
|
11020
11337
|
cwd: workspace.workspaceRoot,
|
|
11021
11338
|
stdio: "inherit"
|
|
@@ -11039,7 +11356,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11039
11356
|
await workspace.spawn("tar", ["-cf", "local/env.tar", ...envFilePaths], {
|
|
11040
11357
|
cwd: workspace.workspaceRoot
|
|
11041
11358
|
});
|
|
11042
|
-
|
|
11359
|
+
Logger14.info(`Archived ${envFilePaths.length} environment files to local/env.tar`);
|
|
11043
11360
|
return { files: envFilePaths, path: "local/env.tar" };
|
|
11044
11361
|
}
|
|
11045
11362
|
}
|
|
@@ -11100,7 +11417,7 @@ class CloudScript extends script("cloud", [
|
|
|
11100
11417
|
const spinner2 = workspace.spinning("Updating Akan.js packages and CLI...");
|
|
11101
11418
|
await this.cloudRunner.update(workspace, tag, { registryUrl });
|
|
11102
11419
|
spinner2.succeed("Akan.js packages and CLI updated, global version is below");
|
|
11103
|
-
|
|
11420
|
+
Logger15.raw("> Akan version: ");
|
|
11104
11421
|
await workspace.spawn("akan", ["--version"], { stdio: "inherit" });
|
|
11105
11422
|
}
|
|
11106
11423
|
}
|
|
@@ -11499,7 +11816,7 @@ class LibraryCommand extends command("library", [LibraryScript], ({ public: targ
|
|
|
11499
11816
|
// pkgs/@akanjs/cli/localRegistry/localRegistry.runner.ts
|
|
11500
11817
|
import { mkdir as mkdir11, rm as rm5 } from "fs/promises";
|
|
11501
11818
|
import path39 from "path";
|
|
11502
|
-
import { Logger as
|
|
11819
|
+
import { Logger as Logger16 } from "akanjs/common";
|
|
11503
11820
|
var defaultLocalRegistryUrl = "http://127.0.0.1:4873";
|
|
11504
11821
|
var containerName = "akan-verdaccio";
|
|
11505
11822
|
var smokeRepoName = "akan-local-smoke";
|
|
@@ -11513,7 +11830,7 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
11513
11830
|
const registry = this.getRegistryUrl(registryUrl);
|
|
11514
11831
|
try {
|
|
11515
11832
|
await workspace.spawn("docker", ["inspect", containerName]);
|
|
11516
|
-
|
|
11833
|
+
Logger16.info(`Local registry is already running at ${registry}`);
|
|
11517
11834
|
return registry;
|
|
11518
11835
|
} catch {}
|
|
11519
11836
|
const configPath2 = path39.join(workspace.workspaceRoot, "pkgs/@akanjs/cli/localRegistry/verdaccio.yaml");
|
|
@@ -11533,7 +11850,7 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
11533
11850
|
`${storagePath}:/verdaccio/storage`,
|
|
11534
11851
|
"verdaccio/verdaccio:6"
|
|
11535
11852
|
], { stdio: "inherit" });
|
|
11536
|
-
|
|
11853
|
+
Logger16.info(`Local registry is running at ${registry}`);
|
|
11537
11854
|
return registry;
|
|
11538
11855
|
}
|
|
11539
11856
|
async reset(workspace) {
|
|
@@ -11541,7 +11858,7 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
11541
11858
|
await workspace.spawn("docker", ["rm", "-f", containerName], { stdio: "inherit" });
|
|
11542
11859
|
} catch {}
|
|
11543
11860
|
await rm5(path39.join(workspace.workspaceRoot, ".akan/verdaccio"), { recursive: true, force: true });
|
|
11544
|
-
|
|
11861
|
+
Logger16.info("Local registry storage has been reset");
|
|
11545
11862
|
}
|
|
11546
11863
|
async smoke(workspace, { registryUrl } = {}) {
|
|
11547
11864
|
const registry = this.getRegistryUrl(registryUrl);
|
|
@@ -11567,7 +11884,7 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
11567
11884
|
env: { ...process.env, AKAN_NPM_REGISTRY: registry, NPM_CONFIG_REGISTRY: registry },
|
|
11568
11885
|
stdio: "inherit"
|
|
11569
11886
|
});
|
|
11570
|
-
|
|
11887
|
+
Logger16.info(`Local registry smoke test completed for ${smokeRepoName}/${smokeAppName}`);
|
|
11571
11888
|
}
|
|
11572
11889
|
}
|
|
11573
11890
|
|
|
@@ -12433,7 +12750,7 @@ class ScalarCommand extends command("scalar", [ScalarScript], ({ public: target
|
|
|
12433
12750
|
|
|
12434
12751
|
// pkgs/@akanjs/cli/workspace/workspace.script.ts
|
|
12435
12752
|
import path41 from "path";
|
|
12436
|
-
import { Logger as
|
|
12753
|
+
import { Logger as Logger17 } from "akanjs/common";
|
|
12437
12754
|
|
|
12438
12755
|
// pkgs/@akanjs/cli/workspace/workspace.runner.ts
|
|
12439
12756
|
import path40 from "path";
|
|
@@ -12457,16 +12774,16 @@ var defaultWorkspacePeerDependencies = new Set([
|
|
|
12457
12774
|
|
|
12458
12775
|
class WorkspaceRunner extends runner("workspace") {
|
|
12459
12776
|
async createWorkspace(repoName, appName, {
|
|
12460
|
-
dirname:
|
|
12777
|
+
dirname: dirname2 = ".",
|
|
12461
12778
|
init = true,
|
|
12462
12779
|
akanVersion,
|
|
12463
12780
|
registryUrl
|
|
12464
12781
|
}) {
|
|
12465
12782
|
const cwdPath = process.cwd();
|
|
12466
|
-
const workspaceRoot = path40.join(cwdPath,
|
|
12783
|
+
const workspaceRoot = path40.join(cwdPath, dirname2, repoName);
|
|
12467
12784
|
const normalizedRegistryUrl = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
|
|
12468
12785
|
const workspace = WorkspaceExecutor.fromRoot({ workspaceRoot, repoName });
|
|
12469
|
-
const templateSpinner = workspace.spinning(`Creating workspace template files in ${
|
|
12786
|
+
const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname2}/${repoName}...`);
|
|
12470
12787
|
const [latestBiomeVersion, latestTypesBunVersion] = await Promise.all([
|
|
12471
12788
|
getLatestPackageVersion("@biomejs/biome", "latest", normalizedRegistryUrl),
|
|
12472
12789
|
getLatestPackageVersion("@types/bun", "latest", normalizedRegistryUrl)
|
|
@@ -12479,7 +12796,7 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
12479
12796
|
if (normalizedRegistryUrl)
|
|
12480
12797
|
await workspace.writeFile(".npmrc", `registry=${normalizedRegistryUrl}/
|
|
12481
12798
|
`);
|
|
12482
|
-
templateSpinner.succeed(`Workspace files created in ${
|
|
12799
|
+
templateSpinner.succeed(`Workspace files created in ${dirname2}/${repoName}`);
|
|
12483
12800
|
const [rootPackageJson, peerDependencies] = await Promise.all([
|
|
12484
12801
|
workspace.getPackageJson(),
|
|
12485
12802
|
this.#getAkanPeerDependencies()
|
|
@@ -12584,14 +12901,14 @@ class WorkspaceScript extends script("workspace", [
|
|
|
12584
12901
|
PackageScript
|
|
12585
12902
|
]) {
|
|
12586
12903
|
async createWorkspace(repoName, appName, {
|
|
12587
|
-
dirname:
|
|
12904
|
+
dirname: dirname2 = ".",
|
|
12588
12905
|
installLibs = false,
|
|
12589
12906
|
init = true,
|
|
12590
12907
|
registryUrl
|
|
12591
12908
|
}) {
|
|
12592
12909
|
const akanVersion = await this.packageScript.version(null, { log: false });
|
|
12593
12910
|
const workspace = await this.workspaceRunner.createWorkspace(repoName, appName, {
|
|
12594
|
-
dirname:
|
|
12911
|
+
dirname: dirname2,
|
|
12595
12912
|
init,
|
|
12596
12913
|
akanVersion,
|
|
12597
12914
|
...registryUrl ? { registryUrl } : {}
|
|
@@ -12608,11 +12925,11 @@ class WorkspaceScript extends script("workspace", [
|
|
|
12608
12925
|
} catch (_) {
|
|
12609
12926
|
gitSpinner.fail("Git repository initialization failed. It's not fatal, you can commit manually");
|
|
12610
12927
|
}
|
|
12611
|
-
const workspacePath = path41.join(
|
|
12612
|
-
|
|
12613
|
-
\uD83C\uDF89 Welcome aboard! Workspace created in ${
|
|
12614
|
-
|
|
12615
|
-
|
|
12928
|
+
const workspacePath = path41.join(dirname2, repoName);
|
|
12929
|
+
Logger17.rawLog(`
|
|
12930
|
+
\uD83C\uDF89 Welcome aboard! Workspace created in ${dirname2}/${repoName}`);
|
|
12931
|
+
Logger17.rawLog(`\uD83D\uDE80 Run \`cd ${workspacePath} && akan start ${appName}\` to start the development server.`);
|
|
12932
|
+
Logger17.rawLog(`
|
|
12616
12933
|
\uD83D\uDC4B Happy coding!`);
|
|
12617
12934
|
}
|
|
12618
12935
|
async lint(exec2, workspace, { fix = true } = {}) {
|