@akanjs/cli 0.0.89 → 0.0.90

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.
Files changed (25) hide show
  1. package/index.js +1094 -336
  2. package/package.json +1 -1
  3. package/pkgs/@akanjs/cli/src/application/application.command.d.ts +2 -2
  4. package/pkgs/@akanjs/cli/src/application/application.runner.d.ts +3 -1
  5. package/pkgs/@akanjs/cli/src/application/application.script.d.ts +3 -1
  6. package/pkgs/@akanjs/cli/src/cloud/cloud.command.d.ts +3 -0
  7. package/pkgs/@akanjs/cli/src/cloud/cloud.runner.d.ts +2 -0
  8. package/pkgs/@akanjs/cli/src/cloud/cloud.script.d.ts +3 -0
  9. package/pkgs/@akanjs/cli/src/library/library.command.d.ts +1 -1
  10. package/pkgs/@akanjs/cli/src/library/library.runner.d.ts +2 -0
  11. package/pkgs/@akanjs/cli/src/library/library.script.d.ts +2 -0
  12. package/pkgs/@akanjs/cli/src/module/module.prompt.d.ts +17 -8
  13. package/pkgs/@akanjs/cli/src/module/module.runner.d.ts +1 -3
  14. package/pkgs/@akanjs/cli/src/module/module.script.d.ts +1 -1
  15. package/pkgs/@akanjs/cli/src/package/package.command.d.ts +1 -1
  16. package/pkgs/@akanjs/cli/src/package/package.runner.d.ts +1 -0
  17. package/pkgs/@akanjs/cli/src/package/package.script.d.ts +1 -0
  18. package/pkgs/@akanjs/devkit/src/aiEditor.d.ts +14 -0
  19. package/pkgs/@akanjs/devkit/src/constants.d.ts +8 -1
  20. package/pkgs/@akanjs/devkit/src/executors.d.ts +21 -1
  21. package/pkgs/@akanjs/devkit/src/getRelatedCnsts.d.ts +52 -8
  22. package/src/templates/workspaceRoot/package.json.template +5 -0
  23. /package/pkgs/@akanjs/cli/src/{package/page → page}/page.command.d.ts +0 -0
  24. /package/pkgs/@akanjs/cli/src/{package/page → page}/page.runner.d.ts +0 -0
  25. /package/pkgs/@akanjs/cli/src/{package/page → page}/page.script.d.ts +0 -0
package/index.js CHANGED
@@ -58,8 +58,8 @@ var createTunnel = async ({ app, environment, port = 27017 }) => {
58
58
  };
59
59
 
60
60
  // pkgs/@akanjs/devkit/src/getCredentials.ts
61
- var import_fs = __toESM(require("fs"), 1);
62
- var import_js_yaml = __toESM(require("js-yaml"), 1);
61
+ var import_fs = __toESM(require("fs"));
62
+ var import_js_yaml = __toESM(require("js-yaml"));
63
63
  var getCredentials = (app, environment) => {
64
64
  const secret = import_js_yaml.default.load(
65
65
  import_fs.default.readFileSync(`${app.workspace.workspaceRoot}/infra/app/values/${app.name}-secret.yaml`, "utf-8")
@@ -68,9 +68,9 @@ var getCredentials = (app, environment) => {
68
68
  };
69
69
 
70
70
  // pkgs/@akanjs/devkit/src/uploadRelease.ts
71
- var import_axios = __toESM(require("axios"), 1);
72
- var import_form_data = __toESM(require("form-data"), 1);
73
- var import_fs2 = __toESM(require("fs"), 1);
71
+ var import_axios = __toESM(require("axios"));
72
+ var import_form_data = __toESM(require("form-data"));
73
+ var import_fs2 = __toESM(require("fs"));
74
74
  var uploadRelease = async (projectName, {
75
75
  workspaceRoot,
76
76
  environment,
@@ -119,58 +119,96 @@ var uploadRelease = async (projectName, {
119
119
  };
120
120
 
121
121
  // pkgs/@akanjs/devkit/src/getModelFileData.ts
122
- var import_fs3 = __toESM(require("fs"), 1);
123
- var getModelFileData = (modulePath, modelName) => {
124
- const moduleType = modulePath.startsWith("apps") ? "app" : "lib";
125
- const moduleName = modulePath.split("/")[1];
126
- const constantFilePath = `${modulePath}/lib/${modelName}/${modelName}.constant.ts`;
127
- const unitFilePath = `${modulePath}/lib/${modelName}/${modelName}.Unit.tsx`;
128
- const viewFilePath = `${modulePath}/lib/${modelName}/${modelName}.View.tsx`;
129
- const constantFileStr = import_fs3.default.readFileSync(constantFilePath, "utf8");
130
- const unitFileStr = import_fs3.default.readFileSync(unitFilePath, "utf8");
131
- const viewFileStr = import_fs3.default.readFileSync(viewFilePath, "utf8");
132
- const constantFileLines = constantFileStr.split("\n");
133
- const importLibNames = constantFileLines.filter((line) => line.startsWith("import { cnst as ")).map((line) => line.split("cnst as ")[1].split(" ")[0]);
134
- const importLocalPaths = constantFileLines.filter((line) => line.startsWith("import { ") && line.includes('from "../')).map((line) => line.split("from ")[1].split('"')[1]);
135
- const importModelNames = importLocalPaths.map((path7) => path7.split("/")[1]).filter((name) => !name.startsWith("_"));
136
- const hasImportScalar = !!importLocalPaths.map((path7) => path7.split("/")[1]).filter((name) => name.startsWith("_")).length;
137
- return {
138
- moduleType,
139
- moduleName,
140
- modelName,
141
- constantFilePath,
142
- unitFilePath,
143
- viewFilePath,
144
- importModelNames,
145
- hasImportScalar,
146
- importLibNames,
147
- constantFileStr,
148
- unitFileStr,
149
- viewFileStr
150
- };
151
- };
122
+ var import_fs3 = __toESM(require("fs"));
152
123
 
153
124
  // pkgs/@akanjs/devkit/src/getRelatedCnsts.ts
154
- var import_fs4 = __toESM(require("fs"), 1);
155
- var import_ora = __toESM(require("ora"), 1);
156
- var ts = __toESM(require("typescript"), 1);
157
- var getRelatedCnsts = (constantFilePath) => {
158
- const tsConfigPath = `./tsconfig.json`;
125
+ var fs4 = __toESM(require("fs"));
126
+ var import_ora = __toESM(require("ora"));
127
+ var ts = __toESM(require("typescript"));
128
+ var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
159
129
  const configFile = ts.readConfigFile(tsConfigPath, (path7) => {
160
130
  return ts.sys.readFile(path7);
161
131
  });
162
- const parsedConfig = ts.parseJsonConfigFileContent(
132
+ return ts.parseJsonConfigFileContent(
163
133
  configFile.config,
164
134
  ts.sys,
165
- import_fs4.default.realpathSync(tsConfigPath).replace(/[^/\\]+$/, "")
135
+ fs4.realpathSync(tsConfigPath).replace(/[^/\\]+$/, "")
166
136
  );
137
+ };
138
+ var collectImportedFiles = (constantFilePath, parsedConfig) => {
139
+ const allFilesToAnalyze = /* @__PURE__ */ new Set([constantFilePath]);
140
+ const analyzedFiles = /* @__PURE__ */ new Set();
141
+ const spinner = (0, import_ora.default)("Collecting related files...");
142
+ spinner.start();
143
+ function collectImported(filePath) {
144
+ if (analyzedFiles.has(filePath))
145
+ return;
146
+ analyzedFiles.add(filePath);
147
+ const tempProgram = ts.createProgram([filePath], parsedConfig.options);
148
+ const source = tempProgram.getSourceFile(filePath);
149
+ if (!source)
150
+ return;
151
+ function collectImports(node) {
152
+ if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
153
+ const importPath = node.moduleSpecifier.text;
154
+ if (importPath.startsWith(".")) {
155
+ const resolved = ts.resolveModuleName(importPath, filePath, parsedConfig.options, ts.sys).resolvedModule?.resolvedFileName;
156
+ if (resolved && !allFilesToAnalyze.has(resolved)) {
157
+ allFilesToAnalyze.add(resolved);
158
+ collectImported(resolved);
159
+ }
160
+ }
161
+ }
162
+ ts.forEachChild(node, collectImports);
163
+ }
164
+ collectImports(source);
165
+ }
166
+ collectImported(constantFilePath);
167
+ spinner.succeed(`Found ${allFilesToAnalyze.size} related files.`);
168
+ return {
169
+ allFilesToAnalyze,
170
+ analyzedFiles
171
+ };
172
+ };
173
+ var createTsProgram = (filePaths, options) => {
174
+ const spinner = (0, import_ora.default)("Creating TypeScript program for all files...");
175
+ spinner.start();
176
+ const program2 = ts.createProgram(Array.from(filePaths), options);
177
+ const checker = program2.getTypeChecker();
178
+ spinner.succeed("TypeScript program created.");
179
+ return {
180
+ program: program2,
181
+ checker
182
+ };
183
+ };
184
+ var createSymbolCache = (checker) => {
185
+ const symbolCache = /* @__PURE__ */ new Map();
186
+ return (node) => {
187
+ const cacheKey = `${node.getSourceFile().fileName}:${node.pos}:${node.end}`;
188
+ if (!symbolCache.has(cacheKey)) {
189
+ symbolCache.set(cacheKey, checker.getSymbolAtLocation(node));
190
+ }
191
+ return symbolCache.get(cacheKey);
192
+ };
193
+ };
194
+ var analyzeProperties = (filesToAnalyze, program2, checker) => {
167
195
  const propertyMap = /* @__PURE__ */ new Map();
168
- function findPropertyOriginAll(filePath) {
169
- const program2 = ts.createProgram([filePath], parsedConfig.options);
170
- const checker = program2.getTypeChecker();
196
+ const analyzedFiles = /* @__PURE__ */ new Set();
197
+ const sourceLineCache = /* @__PURE__ */ new Map();
198
+ const getCachedSymbol = createSymbolCache(checker);
199
+ const spinner = (0, import_ora.default)("Analyzing property relationships...");
200
+ spinner.start();
201
+ function analyzeFileProperties(filePath) {
202
+ if (analyzedFiles.has(filePath))
203
+ return;
204
+ analyzedFiles.add(filePath);
171
205
  const source = program2.getSourceFile(filePath);
172
206
  if (!source)
173
- return null;
207
+ return;
208
+ if (!sourceLineCache.has(filePath)) {
209
+ sourceLineCache.set(filePath, source.getFullText().split("\n"));
210
+ }
211
+ const sourceLines = sourceLineCache.get(filePath);
174
212
  function visit(node) {
175
213
  if (!source)
176
214
  return;
@@ -178,37 +216,38 @@ var getRelatedCnsts = (constantFilePath) => {
178
216
  const left = node.expression;
179
217
  const right = node.name;
180
218
  const { line } = ts.getLineAndCharacterOfPosition(source, node.getStart());
181
- const sourceLines = source.getFullText().split("\n");
182
- if (ts.isIdentifier(left) && sourceLines.length && (sourceLines[line].includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
183
- const symbol = checker.getSymbolAtLocation(right);
219
+ if (ts.isIdentifier(left) && sourceLines && sourceLines.length > line && (sourceLines[line].includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
220
+ const symbol = getCachedSymbol(right);
184
221
  if (symbol?.declarations && symbol.declarations.length > 0) {
185
222
  const key = symbol.declarations[0].getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
186
223
  const property = propertyMap.get(key);
187
224
  const isScalar = symbol.declarations[0].getSourceFile().fileName.includes("_");
188
- const filePath2 = symbol.declarations[0].getSourceFile().fileName.replace(`${ts.sys.getCurrentDirectory()}/`, "");
225
+ const symbolFilePath = symbol.declarations[0].getSourceFile().fileName.replace(`${ts.sys.getCurrentDirectory()}/`, "");
189
226
  if (property) {
190
227
  propertyMap.set(`${left.text}.${right.text}`, {
191
- filePath: filePath2,
228
+ filePath: symbolFilePath,
192
229
  isLibModule: true,
193
230
  isImport: false,
194
231
  libName: left.text,
232
+ source: fs4.readFileSync(symbolFilePath, "utf-8"),
195
233
  isScalar
196
234
  });
197
- } else
235
+ } else {
198
236
  propertyMap.set(key, {
199
- filePath: filePath2,
237
+ filePath: symbolFilePath,
200
238
  isLibModule: true,
201
239
  isImport: false,
202
240
  libName: left.text,
203
- isScalar
241
+ isScalar,
242
+ source: fs4.readFileSync(symbolFilePath, "utf-8")
204
243
  });
205
- findPropertyOriginAll(filePath2);
244
+ }
206
245
  }
207
246
  }
208
- } else if (ts.isImportDeclaration(node)) {
209
- const importPath = node.moduleSpecifier.getText().slice(1, -1);
247
+ } else if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
248
+ const importPath = node.moduleSpecifier.text;
210
249
  if (importPath.startsWith(".")) {
211
- const resolved = ts.resolveModuleName(importPath, filePath, parsedConfig.options, ts.sys).resolvedModule?.resolvedFileName;
250
+ const resolved = ts.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts.sys).resolvedModule?.resolvedFileName;
212
251
  const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
213
252
  const property = propertyMap.get(moduleName);
214
253
  const isScalar = importPath.includes("_");
@@ -217,87 +256,38 @@ var getRelatedCnsts = (constantFilePath) => {
217
256
  filePath: resolved,
218
257
  isLibModule: false,
219
258
  isImport: true,
220
- isScalar
259
+ isScalar,
260
+ source: fs4.readFileSync(resolved, "utf-8")
221
261
  });
222
- findPropertyOriginAll(resolved);
223
262
  }
224
263
  }
225
264
  }
226
265
  ts.forEachChild(node, visit);
227
266
  }
228
267
  visit(source);
229
- return propertyMap;
230
268
  }
231
- function findPropertyOrigin(filePath, aliasName, libName) {
232
- const program2 = ts.createProgram([filePath], parsedConfig.options);
233
- const checker = program2.getTypeChecker();
234
- const source = program2.getSourceFile(filePath);
235
- const propertyMap2 = /* @__PURE__ */ new Map();
236
- if (!source)
237
- return null;
238
- function visit(node) {
239
- if (ts.isPropertyAccessExpression(node)) {
240
- const left = node.expression;
241
- const right = node.name;
242
- if (ts.isIdentifier(left) && left.text === aliasName && right.text === libName) {
243
- const symbol = checker.getSymbolAtLocation(right);
244
- if (symbol?.declarations && symbol.declarations.length > 0) {
245
- return symbol.declarations[0].getSourceFile().fileName;
246
- }
247
- }
248
- }
249
- return ts.forEachChild(node, visit) || null;
250
- }
251
- return visit(source);
269
+ for (const filePath of filesToAnalyze) {
270
+ analyzeFileProperties(filePath);
252
271
  }
253
- const spinner = (0, import_ora.default)("Finding property origin...");
254
- spinner.start();
255
- const paths = findPropertyOriginAll(constantFilePath);
256
- spinner.succeed("property origin found.");
257
- return { paths };
272
+ spinner.succeed(`Analysis complete. Found ${propertyMap.size} properties.`);
273
+ return propertyMap;
274
+ };
275
+ var getRelatedCnsts = (constantFilePath) => {
276
+ const parsedConfig = parseTsConfig();
277
+ const { allFilesToAnalyze } = collectImportedFiles(constantFilePath, parsedConfig);
278
+ const { program: program2, checker } = createTsProgram(allFilesToAnalyze, parsedConfig.options);
279
+ const propertyMap = analyzeProperties(allFilesToAnalyze, program2, checker);
280
+ return Array.from(propertyMap.entries()).map(([key, value]) => ({ key, ...value }));
258
281
  };
259
282
 
260
283
  // pkgs/@akanjs/devkit/src/selectModel.ts
261
284
  var import_prompts = require("@inquirer/prompts");
262
- var import_fs5 = __toESM(require("fs"), 1);
285
+ var import_fs4 = __toESM(require("fs"));
263
286
 
264
287
  // pkgs/@akanjs/devkit/src/streamAi.ts
265
288
  var import_prompts2 = require("@langchain/core/prompts");
266
289
  var import_runnables = require("@langchain/core/runnables");
267
290
  var import_openai = require("@langchain/openai");
268
- var streamAi = async (question, callback = (chunk) => {
269
- process.stdout.write(chunk);
270
- }) => {
271
- const createStreamingModel = (apiKey = process.env.DEEPSEEK_API_KEY) => {
272
- if (!apiKey)
273
- throw new Error(`process.env.DEEPSEEK_API_KEY is not set`);
274
- return new import_openai.ChatOpenAI({
275
- modelName: "deepseek-reasoner",
276
- temperature: 0.7,
277
- streaming: true,
278
- // Enable streaming
279
- configuration: { baseURL: "https://api.deepseek.com/v1", apiKey }
280
- });
281
- };
282
- const createProcessingChain = () => {
283
- return import_runnables.RunnableSequence.from([import_prompts2.PromptTemplate.fromTemplate(`Answer concisely: {question}`), createStreamingModel()]);
284
- };
285
- try {
286
- const chain = createProcessingChain();
287
- const stream = await chain.stream({ question });
288
- let fullResponse = "";
289
- for await (const chunk of stream) {
290
- const content = chunk.content;
291
- if (typeof content === "string") {
292
- fullResponse += content;
293
- callback(content);
294
- }
295
- }
296
- return { content: fullResponse };
297
- } catch (error) {
298
- throw new Error("Failed to stream response");
299
- }
300
- };
301
291
 
302
292
  // pkgs/@akanjs/common/isDayjs.ts
303
293
  var import_dayjs = require("dayjs");
@@ -483,7 +473,7 @@ var sleep = async (ms) => {
483
473
  };
484
474
 
485
475
  // pkgs/@akanjs/config/src/akanConfig.ts
486
- var import_fs6 = __toESM(require("fs"));
476
+ var import_fs5 = __toESM(require("fs"));
487
477
  var import_path2 = __toESM(require("path"));
488
478
 
489
479
  // pkgs/@akanjs/config/src/nextConfig.ts
@@ -698,7 +688,7 @@ CMD ["npm", "start"]`,
698
688
  };
699
689
  var getAppConfig = async (appRoot, props) => {
700
690
  const akanConfigPath = import_path2.default.join(appRoot, "akan.config.ts");
701
- if (!import_fs6.default.existsSync(akanConfigPath))
691
+ if (!import_fs5.default.existsSync(akanConfigPath))
702
692
  throw new Error(`application akan.config.ts is not found ${appRoot}`);
703
693
  const configImp = (await import(`${appRoot}/akan.config.ts`)).default;
704
694
  const config = typeof configImp === "function" ? configImp(props) : configImp;
@@ -718,7 +708,7 @@ var makeLibConfig = (config, props) => {
718
708
  };
719
709
  var getLibConfig = async (libRoot, props) => {
720
710
  const akanConfigPath = import_path2.default.join(libRoot, "akan.config.ts");
721
- if (!import_fs6.default.existsSync(akanConfigPath))
711
+ if (!import_fs5.default.existsSync(akanConfigPath))
722
712
  throw new Error(`library akan.config.ts is not found ${libRoot}`);
723
713
  const configImp = (await import(`${libRoot}/akan.config.ts`)).default;
724
714
  const config = typeof configImp === "function" ? configImp(props) : configImp;
@@ -764,15 +754,15 @@ var getDefaultFileScan = () => ({
764
754
 
765
755
  // pkgs/@akanjs/devkit/src/executors.ts
766
756
  var import_child_process = require("child_process");
767
- var import_dotenv = __toESM(require("dotenv"), 1);
768
- var import_fs7 = __toESM(require("fs"), 1);
769
- var import_promises = __toESM(require("fs/promises"), 1);
770
- var import_path3 = __toESM(require("path"), 1);
757
+ var import_dotenv = __toESM(require("dotenv"));
758
+ var import_fs6 = __toESM(require("fs"));
759
+ var import_promises = __toESM(require("fs/promises"));
760
+ var import_path3 = __toESM(require("path"));
771
761
 
772
762
  // pkgs/@akanjs/devkit/src/dependencyScanner.ts
773
- var fs7 = __toESM(require("fs"), 1);
774
- var path3 = __toESM(require("path"), 1);
775
- var ts2 = __toESM(require("typescript"), 1);
763
+ var fs7 = __toESM(require("fs"));
764
+ var path3 = __toESM(require("path"));
765
+ var ts2 = __toESM(require("typescript"));
776
766
  var TypeScriptDependencyScanner = class {
777
767
  constructor(directory) {
778
768
  this.directory = directory;
@@ -923,8 +913,8 @@ var Executor = class {
923
913
  constructor(name, cwdPath) {
924
914
  this.logger = new Logger(name);
925
915
  this.cwdPath = cwdPath;
926
- if (!import_fs7.default.existsSync(cwdPath))
927
- import_fs7.default.mkdirSync(cwdPath, { recursive: true });
916
+ if (!import_fs6.default.existsSync(cwdPath))
917
+ import_fs6.default.mkdirSync(cwdPath, { recursive: true });
928
918
  }
929
919
  exec(command, options = {}) {
930
920
  const proc = (0, import_child_process.exec)(command, { cwd: this.cwdPath, ...options });
@@ -983,31 +973,31 @@ var Executor = class {
983
973
  }
984
974
  mkdir(dirPath) {
985
975
  const writePath = this.#getPath(dirPath);
986
- if (!import_fs7.default.existsSync(writePath))
987
- import_fs7.default.mkdirSync(writePath, { recursive: true });
976
+ if (!import_fs6.default.existsSync(writePath))
977
+ import_fs6.default.mkdirSync(writePath, { recursive: true });
988
978
  this.logger.verbose(`Make directory ${writePath}`);
989
979
  return this;
990
980
  }
991
981
  exists(filePath) {
992
982
  const readPath = this.#getPath(filePath);
993
- return import_fs7.default.existsSync(readPath);
983
+ return import_fs6.default.existsSync(readPath);
994
984
  }
995
985
  writeFile(filePath, content, { overwrite = true } = {}) {
996
986
  const writePath = this.#getPath(filePath);
997
987
  const dir = import_path3.default.dirname(writePath);
998
- if (!import_fs7.default.existsSync(dir))
999
- import_fs7.default.mkdirSync(dir, { recursive: true });
988
+ if (!import_fs6.default.existsSync(dir))
989
+ import_fs6.default.mkdirSync(dir, { recursive: true });
1000
990
  const contentStr = typeof content === "string" ? content : JSON.stringify(content, null, 2);
1001
- if (import_fs7.default.existsSync(writePath)) {
1002
- const currentContent = import_fs7.default.readFileSync(writePath, "utf8");
991
+ if (import_fs6.default.existsSync(writePath)) {
992
+ const currentContent = import_fs6.default.readFileSync(writePath, "utf8");
1003
993
  if (currentContent === contentStr || !overwrite)
1004
994
  this.logger.verbose(`File ${writePath} is unchanged`);
1005
995
  else {
1006
- import_fs7.default.writeFileSync(writePath, contentStr, "utf8");
996
+ import_fs6.default.writeFileSync(writePath, contentStr, "utf8");
1007
997
  this.logger.verbose(`File ${writePath} is changed`);
1008
998
  }
1009
999
  } else {
1010
- import_fs7.default.writeFileSync(writePath, contentStr, "utf8");
1000
+ import_fs6.default.writeFileSync(writePath, contentStr, "utf8");
1011
1001
  this.logger.verbose(`File ${writePath} is created`);
1012
1002
  }
1013
1003
  return this;
@@ -1023,11 +1013,11 @@ var Executor = class {
1023
1013
  }
1024
1014
  readFile(filePath) {
1025
1015
  const readPath = this.#getPath(filePath);
1026
- return import_fs7.default.readFileSync(readPath, "utf8");
1016
+ return import_fs6.default.readFileSync(readPath, "utf8");
1027
1017
  }
1028
1018
  readJson(filePath) {
1029
1019
  const readPath = this.#getPath(filePath);
1030
- return JSON.parse(import_fs7.default.readFileSync(readPath, "utf8"));
1020
+ return JSON.parse(import_fs6.default.readFileSync(readPath, "utf8"));
1031
1021
  }
1032
1022
  async cp(srcPath, destPath) {
1033
1023
  const src = this.#getPath(srcPath);
@@ -1096,7 +1086,7 @@ var Executor = class {
1096
1086
  overwrite = true
1097
1087
  }) {
1098
1088
  const templatePath = `${__dirname}/src/templates${template ? `/${template}` : ""}`.replace(".ts", ".js");
1099
- if (import_fs7.default.statSync(templatePath).isFile()) {
1089
+ if (import_fs6.default.statSync(templatePath).isFile()) {
1100
1090
  const filename = import_path3.default.basename(templatePath);
1101
1091
  await this.#applyTemplateFile(
1102
1092
  { templatePath, targetPath: import_path3.default.join(basePath2, filename), scanResult, overwrite },
@@ -1107,7 +1097,7 @@ var Executor = class {
1107
1097
  await Promise.all(
1108
1098
  subdirs.map(async (subdir) => {
1109
1099
  const subpath = import_path3.default.join(templatePath, subdir);
1110
- if (import_fs7.default.statSync(subpath).isFile())
1100
+ if (import_fs6.default.statSync(subpath).isFile())
1111
1101
  await this.#applyTemplateFile(
1112
1102
  { templatePath: subpath, targetPath: import_path3.default.join(basePath2, subdir), scanResult, overwrite },
1113
1103
  dict
@@ -1204,6 +1194,26 @@ var WorkspaceExecutor = class _WorkspaceExecutor extends Executor {
1204
1194
  this.writeJson("tsconfig.json", rootTsConfig);
1205
1195
  return this;
1206
1196
  }
1197
+ async getDirInModule(basePath2, name) {
1198
+ const AVOID_DIRS = ["__lib", "__scalar", `_${name}`];
1199
+ const getDirs = async (dirname, maxDepth = 3, results = [], prefix = "") => {
1200
+ const dirs = await import_promises.default.readdir(dirname);
1201
+ await Promise.all(
1202
+ dirs.map(async (dir) => {
1203
+ if (AVOID_DIRS.includes(dir))
1204
+ return;
1205
+ const dirPath = import_path3.default.join(dirname, dir);
1206
+ if (import_fs6.default.lstatSync(dirPath).isDirectory()) {
1207
+ results.push(`${name}/${prefix}${dir}`);
1208
+ if (maxDepth > 0)
1209
+ await getDirs(dirPath, maxDepth - 1, results, `${prefix}${dir}/`);
1210
+ }
1211
+ })
1212
+ );
1213
+ return results;
1214
+ };
1215
+ return await getDirs(basePath2);
1216
+ }
1207
1217
  async commit(message, { init = false, add = true } = {}) {
1208
1218
  if (init)
1209
1219
  await this.exec(`git init --quiet`);
@@ -1220,8 +1230,8 @@ var WorkspaceExecutor = class _WorkspaceExecutor extends Executor {
1220
1230
  if (AVOID_DIRS.includes(dir))
1221
1231
  return;
1222
1232
  const dirPath = import_path3.default.join(dirname, dir);
1223
- if (import_fs7.default.lstatSync(dirPath).isDirectory()) {
1224
- const hasTargetFile = import_fs7.default.existsSync(import_path3.default.join(dirPath, targetFilename));
1233
+ if (import_fs6.default.lstatSync(dirPath).isDirectory()) {
1234
+ const hasTargetFile = import_fs6.default.existsSync(import_path3.default.join(dirPath, targetFilename));
1225
1235
  if (hasTargetFile)
1226
1236
  results.push(`${prefix}${dir}`);
1227
1237
  if (maxDepth > 0)
@@ -1241,6 +1251,14 @@ var WorkspaceExecutor = class _WorkspaceExecutor extends Executor {
1241
1251
  ];
1242
1252
  return scalarConstantExampleFiles;
1243
1253
  }
1254
+ async getViewFiles() {
1255
+ const [appNames, libNames] = await this.getSyss();
1256
+ const viewExampleFiles = [
1257
+ ...(await Promise.all(appNames.map((appName) => AppExecutor.from(this, appName).getViewsSourceCode()))).flat(),
1258
+ ...(await Promise.all(libNames.map((libName) => LibExecutor.from(this, libName).getViewsSourceCode()))).flat()
1259
+ ];
1260
+ return viewExampleFiles;
1261
+ }
1244
1262
  };
1245
1263
  var SysExecutor = class extends Executor {
1246
1264
  workspace;
@@ -1255,6 +1273,10 @@ var SysExecutor = class extends Executor {
1255
1273
  async getConfig(command) {
1256
1274
  return this.type === "app" ? await getAppConfig(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "app", name: this.name, command }) : await getLibConfig(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "lib", name: this.name, command });
1257
1275
  }
1276
+ async getModules() {
1277
+ const path7 = this.type === "app" ? `apps/${this.name}/lib` : `libs/${this.name}/lib`;
1278
+ return await this.workspace.getDirInModule(path7, this.name);
1279
+ }
1258
1280
  async scan({
1259
1281
  tsconfig = this.getTsConfig(`${this.cwdPath}/tsconfig.json`),
1260
1282
  akanConfig
@@ -1279,11 +1301,11 @@ var SysExecutor = class extends Executor {
1279
1301
  const pathSplitLength = path7.split("/").length;
1280
1302
  return tsconfig.compilerOptions.paths[path7][0].split("/").slice(1, 1 + pathSplitLength).join("/");
1281
1303
  }).filter((libName) => libName !== this.name);
1282
- if (!import_fs7.default.existsSync(`${this.cwdPath}/lib/__scalar`))
1283
- import_fs7.default.mkdirSync(`${this.cwdPath}/lib/__scalar`, { recursive: true });
1304
+ if (!import_fs6.default.existsSync(`${this.cwdPath}/lib/__scalar`))
1305
+ import_fs6.default.mkdirSync(`${this.cwdPath}/lib/__scalar`, { recursive: true });
1284
1306
  const files = getDefaultFileScan();
1285
1307
  const dirnames = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter(
1286
- (name) => import_fs7.default.lstatSync(`${this.cwdPath}/lib/${name}`).isDirectory()
1308
+ (name) => import_fs6.default.lstatSync(`${this.cwdPath}/lib/${name}`).isDirectory()
1287
1309
  );
1288
1310
  const databaseDirs = dirnames.filter((name) => !name.startsWith("_"));
1289
1311
  const serviceDirs = dirnames.filter((name) => name.startsWith("_") && !name.startsWith("__"));
@@ -1411,20 +1433,42 @@ var SysExecutor = class extends Executor {
1411
1433
  return { filepath, content };
1412
1434
  }
1413
1435
  async getDatabaseModules() {
1414
- const databaseModules = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => import_fs7.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.constant.ts`));
1436
+ const databaseModules = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => import_fs6.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.constant.ts`));
1415
1437
  return databaseModules;
1416
1438
  }
1417
1439
  async getServiceModules() {
1418
- const serviceModules = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => name.startsWith("_") && !name.startsWith("__")).filter((name) => import_fs7.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.service.ts`));
1440
+ const serviceModules = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => name.startsWith("_") && !name.startsWith("__")).filter((name) => import_fs6.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.service.ts`));
1419
1441
  return serviceModules;
1420
1442
  }
1421
1443
  async getScalarModules() {
1422
- const scalarModules = (await import_promises.default.readdir(`${this.cwdPath}/lib/__scalar`)).filter((name) => !name.startsWith("_")).filter((name) => import_fs7.default.existsSync(`${this.cwdPath}/lib/__scalar/${name}/${name}.constant.ts`));
1444
+ const scalarModules = (await import_promises.default.readdir(`${this.cwdPath}/lib/__scalar`)).filter((name) => !name.startsWith("_")).filter((name) => import_fs6.default.existsSync(`${this.cwdPath}/lib/__scalar/${name}/${name}.constant.ts`));
1423
1445
  return scalarModules;
1424
1446
  }
1425
- async getViewModules() {
1426
- const viewModules = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => import_fs7.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.View.tsx`));
1427
- return viewModules;
1447
+ async getViewComponents() {
1448
+ const viewComponents = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => import_fs6.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.View.tsx`));
1449
+ return viewComponents;
1450
+ }
1451
+ async getUnitComponents() {
1452
+ const unitComponents = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => name.startsWith("_") && !name.startsWith("__")).filter((name) => import_fs6.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.Unit.tsx`));
1453
+ return unitComponents;
1454
+ }
1455
+ async getTemplateComponents() {
1456
+ const templateComponents = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => name.startsWith("_") && !name.startsWith("__")).filter((name) => import_fs6.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.Template.tsx`));
1457
+ return templateComponents;
1458
+ }
1459
+ async getViewsSourceCode() {
1460
+ const viewComponents = await this.getViewComponents();
1461
+ return viewComponents.map((viewComponent) => this.getLocalFile(`lib/${viewComponent}/${viewComponent}.View.tsx`));
1462
+ }
1463
+ async getUnitsSourceCode() {
1464
+ const unitComponents = await this.getUnitComponents();
1465
+ return unitComponents.map((unitComponent) => this.getLocalFile(`lib/${unitComponent}/${unitComponent}.Unit.tsx`));
1466
+ }
1467
+ async getTemplatesSourceCode() {
1468
+ const templateComponents = await this.getTemplateComponents();
1469
+ return templateComponents.map(
1470
+ (templateComponent) => this.getLocalFile(`lib/${templateComponent}/${templateComponent}.Template.tsx`)
1471
+ );
1428
1472
  }
1429
1473
  async getScalarConstantFiles() {
1430
1474
  const scalarModules = await this.getScalarModules();
@@ -1464,9 +1508,9 @@ var AppExecutor = class _AppExecutor extends SysExecutor {
1464
1508
  }
1465
1509
  async syncAssets(libDeps) {
1466
1510
  const projectPublicLibPath = `${this.cwdPath}/public/libs`;
1467
- if (import_fs7.default.existsSync(projectPublicLibPath))
1511
+ if (import_fs6.default.existsSync(projectPublicLibPath))
1468
1512
  await import_promises.default.rm(projectPublicLibPath, { recursive: true });
1469
- const targetDeps = libDeps.filter((dep) => import_fs7.default.existsSync(`${this.workspace.workspaceRoot}/libs/${dep}/public`));
1513
+ const targetDeps = libDeps.filter((dep) => import_fs6.default.existsSync(`${this.workspace.workspaceRoot}/libs/${dep}/public`));
1470
1514
  await Promise.all(targetDeps.map((dep) => import_promises.default.mkdir(`${projectPublicLibPath}/${dep}`, { recursive: true })));
1471
1515
  await Promise.all(
1472
1516
  targetDeps.map(
@@ -1546,21 +1590,21 @@ var akanCloudHost = process.env.NEXT_PUBLIC_OPERATION_MODE === "local" ? "http:/
1546
1590
  var akanCloudBackendUrl = `${akanCloudHost}${process.env.NEXT_PUBLIC_OPERATION_MODE === "local" ? ":8080" : ""}/backend`;
1547
1591
  var akanCloudClientUrl = `${akanCloudHost}${process.env.NEXT_PUBLIC_OPERATION_MODE === "local" ? ":4200" : ""}`;
1548
1592
  var defaultHostConfig = {};
1549
- var defaultAkanGlobalConfig = {};
1593
+ var defaultAkanGlobalConfig = { cloudHost: {}, llm: null };
1550
1594
 
1551
1595
  // pkgs/@akanjs/devkit/src/auth.ts
1552
- var import_fs8 = __toESM(require("fs"), 1);
1596
+ var import_fs7 = __toESM(require("fs"));
1553
1597
  var getAkanGlobalConfig = () => {
1554
- const akanConfig = import_fs8.default.existsSync(configPath) ? JSON.parse(import_fs8.default.readFileSync(configPath, "utf8")) : defaultAkanGlobalConfig;
1598
+ const akanConfig = import_fs7.default.existsSync(configPath) ? JSON.parse(import_fs7.default.readFileSync(configPath, "utf8")) : defaultAkanGlobalConfig;
1555
1599
  return akanConfig;
1556
1600
  };
1557
1601
  var setAkanGlobalConfig = (akanConfig) => {
1558
- import_fs8.default.mkdirSync(basePath, { recursive: true });
1559
- import_fs8.default.writeFileSync(configPath, JSON.stringify(akanConfig, null, 2));
1602
+ import_fs7.default.mkdirSync(basePath, { recursive: true });
1603
+ import_fs7.default.writeFileSync(configPath, JSON.stringify(akanConfig, null, 2));
1560
1604
  };
1561
1605
  var getHostConfig = (host = akanCloudHost) => {
1562
1606
  const akanConfig = getAkanGlobalConfig();
1563
- return akanConfig[host] ?? defaultHostConfig;
1607
+ return akanConfig.cloudHost[host] ?? defaultHostConfig;
1564
1608
  };
1565
1609
  var setHostConfig = (host = akanCloudHost, config = {}) => {
1566
1610
  const akanConfig = getAkanGlobalConfig();
@@ -1579,7 +1623,7 @@ var getSelf = async (token) => {
1579
1623
 
1580
1624
  // pkgs/@akanjs/devkit/src/capacitorApp.ts
1581
1625
  var import_project = require("@trapezedev/project");
1582
- var import_fs9 = __toESM(require("fs"), 1);
1626
+ var import_fs8 = __toESM(require("fs"));
1583
1627
  var CapacitorApp = class {
1584
1628
  constructor(app) {
1585
1629
  this.app = app;
@@ -1605,7 +1649,7 @@ var CapacitorApp = class {
1605
1649
  await this.project.commit();
1606
1650
  }
1607
1651
  async releaseIos() {
1608
- const isAdded = import_fs9.default.existsSync(`${this.app.cwdPath}/ios/App/Podfile`);
1652
+ const isAdded = import_fs8.default.existsSync(`${this.app.cwdPath}/ios/App/Podfile`);
1609
1653
  if (!isAdded) {
1610
1654
  await this.app.spawn("npx cap add ios");
1611
1655
  await this.app.spawn("npx @capacitor/assets generate");
@@ -1614,7 +1658,7 @@ var CapacitorApp = class {
1614
1658
  await this.app.spawn("cross-env", ["APP_OPERATION_MODE=release", "npx", "cap", "sync", "ios"]);
1615
1659
  }
1616
1660
  async releaseAndroid() {
1617
- const isAdded = import_fs9.default.existsSync(`${this.app.cwdPath}/android/app/build.gradle`);
1661
+ const isAdded = import_fs8.default.existsSync(`${this.app.cwdPath}/android/app/build.gradle`);
1618
1662
  if (!isAdded) {
1619
1663
  await this.app.spawn("npx cap add android");
1620
1664
  await this.app.spawn("npx @capacitor/assets generate");
@@ -1855,7 +1899,7 @@ var Target = {
1855
1899
  // pkgs/@akanjs/devkit/src/commandDecorators/command.ts
1856
1900
  var import_prompts3 = require("@inquirer/prompts");
1857
1901
  var import_commander = require("commander");
1858
- var import_fs10 = __toESM(require("fs"), 1);
1902
+ var import_fs9 = __toESM(require("fs"));
1859
1903
  var camelToKebabCase = (str) => str.replace(/([A-Z])/g, "-$1").toLowerCase();
1860
1904
  var handleOption = (programCommand, argMeta) => {
1861
1905
  const {
@@ -1902,7 +1946,7 @@ var getOptionValue = async (argMeta, opt) => {
1902
1946
  const message = ask ?? `Do you want to set ${name}? ${desc ? ` (${desc})` : ""}: `;
1903
1947
  return await (0, import_prompts3.confirm)({ message });
1904
1948
  } else {
1905
- const message = ask ?? `Enter the ${name} value${example ? ` (example: ${example})` : ""}: `;
1949
+ const message = ask ? `${ask}: ` : `Enter the ${name} value${example ? ` (example: ${example})` : ""}: `;
1906
1950
  if (argMeta.argsOption.nullable)
1907
1951
  return await (0, import_prompts3.input)({ message });
1908
1952
  else
@@ -1951,8 +1995,8 @@ var getArgumentValue = async (argMeta, value, workspace) => {
1951
1995
  throw new Error(`Invalid system type: ${argMeta.type}`);
1952
1996
  };
1953
1997
  var runCommands = async (...commands) => {
1954
- const hasPackageJson = import_fs10.default.existsSync(`${__dirname}/package.json`);
1955
- const version = hasPackageJson ? JSON.parse(import_fs10.default.readFileSync(`${__dirname}/package.json`, "utf8")).version : "0.0.1";
1998
+ const hasPackageJson = import_fs9.default.existsSync(`${__dirname}/package.json`);
1999
+ const version = hasPackageJson ? JSON.parse(import_fs9.default.readFileSync(`${__dirname}/package.json`, "utf8")).version : "0.0.1";
1956
2000
  import_commander.program.version(version).description("Akan CLI");
1957
2001
  for (const command of commands) {
1958
2002
  const targetMetas = getTargetMetas(command);
@@ -2002,15 +2046,64 @@ var runCommands = async (...commands) => {
2002
2046
  var import_prompts4 = require("@inquirer/prompts");
2003
2047
  var import_messages = require("@langchain/core/messages");
2004
2048
  var import_openai2 = require("@langchain/openai");
2049
+ var import_chalk = __toESM(require("chalk"));
2005
2050
  var MAX_ASK_TRY = 300;
2051
+ var supportedLlmModels = ["deepseek-chat", "deepseek-reasoner"];
2006
2052
  var AiSession = class _AiSession {
2007
- static #chat = new import_openai2.ChatOpenAI({
2008
- modelName: "deepseek-chat",
2009
- temperature: 0.7,
2010
- streaming: true,
2011
- // Enable streaming
2012
- configuration: { baseURL: "https://api.deepseek.com/v1", apiKey: process.env.DEEPSEEK_API_KEY }
2013
- });
2053
+ static #chat = null;
2054
+ static async init({ temperature = 0.7, useExisting = true } = {}) {
2055
+ if (useExisting) {
2056
+ const llmConfig2 = this.getLlmConfig();
2057
+ if (llmConfig2)
2058
+ return this.#setChatModel(llmConfig2.model, llmConfig2.apiKey);
2059
+ }
2060
+ const llmConfig = await this.#requestLlmConfig();
2061
+ const { model, apiKey } = llmConfig;
2062
+ await this.#validateApiKey(model, apiKey);
2063
+ return this.#setChatModel(model, apiKey, { temperature }).setLlmConfig({ model, apiKey });
2064
+ }
2065
+ static #setChatModel(model, apiKey, { temperature = 0.7 } = {}) {
2066
+ this.#chat = new import_openai2.ChatOpenAI({
2067
+ modelName: model,
2068
+ temperature,
2069
+ streaming: true,
2070
+ configuration: { baseURL: "https://api.deepseek.com/v1", apiKey }
2071
+ });
2072
+ return this;
2073
+ }
2074
+ static getLlmConfig() {
2075
+ const akanConfig = getAkanGlobalConfig();
2076
+ return akanConfig.llm ?? null;
2077
+ }
2078
+ static setLlmConfig(llmConfig) {
2079
+ const akanConfig = getAkanGlobalConfig();
2080
+ akanConfig.llm = llmConfig;
2081
+ setAkanGlobalConfig(akanConfig);
2082
+ return this;
2083
+ }
2084
+ static async #requestLlmConfig() {
2085
+ const model = await (0, import_prompts4.select)({ message: "Select a LLM model", choices: supportedLlmModels });
2086
+ const apiKey = await (0, import_prompts4.input)({ message: "Enter your API key" });
2087
+ return { model, apiKey };
2088
+ }
2089
+ static async #validateApiKey(modelName, apiKey) {
2090
+ const chat = new import_openai2.ChatOpenAI({
2091
+ modelName,
2092
+ temperature: 0,
2093
+ configuration: { baseURL: "https://api.deepseek.com/v1", apiKey }
2094
+ });
2095
+ try {
2096
+ await chat.invoke("Hi, and just say 'ok'");
2097
+ return true;
2098
+ } catch (error) {
2099
+ Logger.rawLog(
2100
+ import_chalk.default.red(
2101
+ `LLM API key is invalid. Please check your API key and try again. You can set it again by running "akan set-llm" or reset by running "akan reset-llm"`
2102
+ )
2103
+ );
2104
+ throw error;
2105
+ }
2106
+ }
2014
2107
  messageHistory = [];
2015
2108
  constructor(messageHistory = []) {
2016
2109
  this.messageHistory = messageHistory;
@@ -2020,6 +2113,8 @@ var AiSession = class _AiSession {
2020
2113
  Logger.raw(chunk);
2021
2114
  }
2022
2115
  } = {}) {
2116
+ if (!_AiSession.#chat)
2117
+ throw new Error("Please initialize the AI session first");
2023
2118
  try {
2024
2119
  const humanMessage = new import_messages.HumanMessage(question);
2025
2120
  this.messageHistory.push(humanMessage);
@@ -2032,6 +2127,8 @@ var AiSession = class _AiSession {
2032
2127
  onChunk(content);
2033
2128
  }
2034
2129
  }
2130
+ fullResponse += "\n";
2131
+ onChunk("\n");
2035
2132
  this.messageHistory.push(new import_messages.AIMessage(fullResponse));
2036
2133
  return { content: fullResponse, messageHistory: this.messageHistory };
2037
2134
  } catch (error) {
@@ -2060,8 +2157,8 @@ var AiSession = class _AiSession {
2060
2157
  return this.#getTypescriptCode(content);
2061
2158
  }
2062
2159
  #getTypescriptCode(content) {
2063
- const code = /```typescript([\s\S]*?)```/.exec(content);
2064
- return code ? code[1] : content;
2160
+ const code = /```(typescript|tsx)([\s\S]*?)```/.exec(content);
2161
+ return code ? code[2] : content;
2065
2162
  }
2066
2163
  };
2067
2164
 
@@ -2074,6 +2171,12 @@ var LibraryRunner = class {
2074
2171
  const scanResult = await lib.scan({ akanConfig });
2075
2172
  return scanResult;
2076
2173
  }
2174
+ async createLibrary(libName, workspace) {
2175
+ }
2176
+ async removeLibrary(lib) {
2177
+ await lib.workspace.exec(`rm -rf libs/${lib.name}`);
2178
+ lib.log(`Library ${lib.name} removed`);
2179
+ }
2077
2180
  async installLibrary(workspace, libName) {
2078
2181
  workspace.log(`Installing ${libName} library as git subtree...`);
2079
2182
  await workspace.exec(
@@ -2165,6 +2268,12 @@ var LibraryScript = class {
2165
2268
  for (const libName of scanResult.akanConfig.libs)
2166
2269
  await this.syncLibrary(LibExecutor.from(lib.workspace, libName), { recursive: false });
2167
2270
  }
2271
+ async createLibrary(libName, workspace) {
2272
+ await this.#runner.createLibrary(libName, workspace);
2273
+ }
2274
+ async removeLibrary(lib) {
2275
+ await this.#runner.removeLibrary(lib);
2276
+ }
2168
2277
  async installLibrary(workspace, libName) {
2169
2278
  const lib = await this.#runner.installLibrary(workspace, libName);
2170
2279
  workspace.log(`${libName} library installed`);
@@ -2191,7 +2300,7 @@ var import_openai3 = require("@langchain/openai");
2191
2300
  var import_plugin_react = __toESM(require("@vitejs/plugin-react"));
2192
2301
  var import_dotenv3 = __toESM(require("dotenv"));
2193
2302
  var esbuild = __toESM(require("esbuild"));
2194
- var import_fs12 = __toESM(require("fs"));
2303
+ var import_fs10 = __toESM(require("fs"));
2195
2304
  var import_promises2 = __toESM(require("fs/promises"));
2196
2305
  var import_js_yaml2 = __toESM(require("js-yaml"));
2197
2306
  var import_open = __toESM(require("open"));
@@ -2202,8 +2311,9 @@ var import_vite_plugin_node_polyfills = require("vite-plugin-node-polyfills");
2202
2311
  var import_vite_tsconfig_paths = __toESM(require("vite-tsconfig-paths"));
2203
2312
 
2204
2313
  // pkgs/@akanjs/cli/src/module/module.prompt.ts
2205
- var import_fs11 = __toESM(require("fs"));
2206
- var frameworkDescription = `\uB098\uB294 \uC880 \uB354 \uD6A8\uC728\uC801\uC73C\uB85C \uCF54\uB529\uC744 \uD558\uAE30 \uC704\uD574\uC11C \uC790\uCCB4 \uD504\uB808\uC784\uC6CC\uD06C\uB97C \uC81C\uC791\uD588\uC5B4. \uADF8\uB798\uC11C \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC744 \uD574\uC904\uD14C\uB2C8\uAE4C \uC798 \uC774\uD574\uD558\uB3C4\uB85D \uD574. \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uB294 next.js 13\uACFC nest.js, capacitor.js, nx, mongoDB \uAE30\uBC18\uC758 \uD504\uB860\uD2B8\uC5D4\uB4DC, \uC571, \uBC31\uC5D4\uB4DC \uD1B5\uD569 \uD504\uB808\uC784\uC6CC\uD06C\uC57C. \uADF8\uB798\uC11C \uBC31\uC5D4\uB4DC, \uD504\uB860\uD2B8\uC5D4\uB4DC, DB Schema\uC5D0 \uB300\uD55C \uCF54\uB4DC\uAC00 \uBAA8\uB450 \uD55C \uD3F4\uB354 \uC548\uC5D0 \uC788\uC5B4. \uADF8\uB798\uC11C \uC790\uBC14\uC2A4\uD06C\uB9BD\uD2B8, \uD0C0\uC785\uC2A4\uD06C\uB9BD\uD2B8, \uADF8\uB9AC\uACE0 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC774\uD574\uB9CC \uC788\uB2E4\uBA74 \uAD6C\uBD84\uC9D3\uC9C0 \uC54A\uACE0 \uC0AC\uC6A9\uD560 \uC218 \uC788\uB2E4\uB294 \uC7A5\uC810\uC774 \uC788\uC5B4.
2314
+ var frameworkDescription = `
2315
+ \uB098\uB294 \uC880 \uB354 \uD6A8\uC728\uC801\uC73C\uB85C \uCF54\uB529\uC744 \uD558\uAE30 \uC704\uD574\uC11C \uC790\uCCB4 \uD504\uB808\uC784\uC6CC\uD06C\uB97C \uC81C\uC791\uD588\uC5B4.
2316
+ \uADF8\uB798\uC11C \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC744 \uD574\uC904\uD14C\uB2C8\uAE4C \uC798 \uC774\uD574\uD558\uB3C4\uB85D \uD574. \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uB294 next.js 13\uACFC nest.js, capacitor.js, nx, mongoDB \uAE30\uBC18\uC758 \uD504\uB860\uD2B8\uC5D4\uB4DC, \uC571, \uBC31\uC5D4\uB4DC \uD1B5\uD569 \uD504\uB808\uC784\uC6CC\uD06C\uC57C. \uADF8\uB798\uC11C \uBC31\uC5D4\uB4DC, \uD504\uB860\uD2B8\uC5D4\uB4DC, DB Schema\uC5D0 \uB300\uD55C \uCF54\uB4DC\uAC00 \uBAA8\uB450 \uD55C \uD3F4\uB354 \uC548\uC5D0 \uC788\uC5B4. \uADF8\uB798\uC11C \uC790\uBC14\uC2A4\uD06C\uB9BD\uD2B8, \uD0C0\uC785\uC2A4\uD06C\uB9BD\uD2B8, \uADF8\uB9AC\uACE0 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC774\uD574\uB9CC \uC788\uB2E4\uBA74 \uAD6C\uBD84\uC9D3\uC9C0 \uC54A\uACE0 \uC0AC\uC6A9\uD560 \uC218 \uC788\uB2E4\uB294 \uC7A5\uC810\uC774 \uC788\uC5B4.
2207
2317
 
2208
2318
  \uAC00\uC7A5 \uC678\uBD80\uC758 \uAD6C\uC870\uB294
2209
2319
  - app
@@ -2721,6 +2831,433 @@ export const General = ({ className, \${dict.model}, self }: \${dict.Model}ViewP
2721
2831
 
2722
2832
  \uC77C\uB2E8 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC740 \uC774 \uC815\uB3C4\uB85C \uD558\uACE0 \uC774 \uC815\uBCF4\uB4E4\uC744 \uAE30\uBC18\uC73C\uB85C \uB0B4\uAC00 \uC6D0\uD558\uB294 \uC694\uAD6C\uB97C \uB4E4\uC5B4\uC918.
2723
2833
  `;
2834
+ var moduleDesription = `
2835
+
2836
+ The project follows a modular architecture with clear separation of concerns. Each module in lib/<model>/ represents a domain
2837
+ entity with a standardized file structure that promotes consistency and maintainability.
2838
+
2839
+ ## Core Components
2840
+
2841
+ ### <Model>.View.tsx
2842
+ Presentation-only components that render data without managing state.
2843
+ It works as a server component, They accept model data as props and display it according to specific layouts.
2844
+ These components focus purely on how data looks to the user.
2845
+ only use the full model.
2846
+ This component is only viewing the component. So don't use click event or other interaction events.
2847
+ If you need interaction, possible to wrapping the component with the <Model>.Zone.tsx component.
2848
+ But useable the Link component for navigation.
2849
+ Components created in Model.View.tsx should primarily be made to show the entire detailed data of the model rather than showing only partial data of the model.
2850
+
2851
+
2852
+ ### <Model>.Template.tsx
2853
+ Reusable layout patterns with integrated state management. It works as a client component, These components provide consistent UI patterns and handle data
2854
+ binding, often using store hooks to access application state.
2855
+
2856
+ ### <Model>.Unit.tsx
2857
+ Small, self-contained UI components representing individual model instances. It works as a server component, They're designed for rendering single items in
2858
+ lists or grids, displaying model data in compact formats. only use the light model.
2859
+
2860
+ ### <Model>.Zone.tsx
2861
+ Top-level container components that orchestrate other components. It works as a client component, They compose views, templates, and units into complete UI
2862
+ sections while managing data flow to child components.
2863
+
2864
+ ### <Model>.Util.tsx
2865
+ Specialized components and utility functions specific to a model, It works as a client component, providing both UI components and helper functions for
2866
+ model-specific functionality.
2867
+
2868
+ ## Data Management
2869
+
2870
+ ### <model>.signal.ts
2871
+ Defines API endpoints with type safety using decorators for GraphQL queries and mutations, creating a type-safe bridge between
2872
+ frontend and backend.
2873
+
2874
+ ### <model>.store.ts
2875
+ Manages client-side state with typed actions and state, handling UI state, form state, and cached data.
2876
+
2877
+ ### <model>.service.ts
2878
+ Implements server-side business logic with dependency injection, handling data processing and complex operations.
2879
+
2880
+ ### <model>.constant.ts
2881
+ Defines type definitions and model schemas using decorators to structure model fields, validation, and relationships.
2882
+
2883
+ ### <model>.dictionary.ts
2884
+ Provides internationalization and label definitions for model properties and operations.
2885
+
2886
+ ### <model>.document.ts
2887
+ Defines database schema and model operations with decorators for database interaction.
2888
+
2889
+ ## Data Flow
2890
+ The architecture follows a clear data flow pattern:
2891
+ - Server-side: Document \u2192 Service \u2192 Signal \u2192 API
2892
+ - Client-side: API \u2192 Store \u2192 Components (Zone \u2192 Template/View/Unit)
2893
+
2894
+ This modular structure enables rapid development while maintaining consistency, type safety, and testability throughout the
2895
+ application.
2896
+ `;
2897
+ var utilUiDescription = `
2898
+ This UI kit is an internally developed UI kit within the Akan.js framework.
2899
+ The libs/util/ui directory contains a comprehensive React component library designed for modern web applications.
2900
+ This framework provides a complete set of production-ready, reusable UI components with consistent styling, type safety, and advanced functionality.
2901
+
2902
+ - Every component must be used exactly as described in the documentation.
2903
+ - Do not add any additional props to the components.
2904
+ - Must use the written props exactly.
2905
+ - Only the components explicitly listed in the documentation are available\u2014no additional components exist beyond those specified.
2906
+
2907
+
2908
+
2909
+ Architecture & Foundation
2910
+
2911
+ Core Technologies:
2912
+ - Built on React 18+ with TypeScript for strict type safety
2913
+ - Styled with Tailwind CSS and DaisyUI for consistent design system
2914
+ - Implements modern React patterns including hooks, context providers, and portals
2915
+ - Full internationalization (i18n) support for multilingual applications
2916
+ - Responsive-first design with mobile optimization
2917
+
2918
+ Design Principles:
2919
+ - Composable component architecture with predictable APIs
2920
+ - Accessibility (a11y) compliance throughout
2921
+ - Performance optimization with lazy loading and code splitting
2922
+ - Consistent error handling and validation patterns
2923
+ - Session storage integration for form state persistence
2924
+
2925
+ Component Categories
2926
+
2927
+ Core Input Components
2928
+
2929
+ Essential form controls with advanced validation and user experience features:
2930
+ - Button - Async-aware button with automatic loading/success/error states
2931
+ - Input - Comprehensive input system with real-time validation, multiple variants (Text, Password, Email, Number, Checkbox), and
2932
+ session caching
2933
+ - Select - Advanced dropdown with search, multi-select, and custom rendering
2934
+ - DatePicker - Date/time selection with range support and custom formatting
2935
+ - CodeInput - PIN/verification code input with auto-focus management
2936
+ - Upload - File upload system with drag-drop, progress tracking, image cropping, and multiple file support
2937
+
2938
+ Data Display Components
2939
+
2940
+ Components for presenting and organizing information:
2941
+ - Chart - Visualization suite (Bar, Line, Pie, Doughnut) built on Chart.js
2942
+ - Avatar - User profile images with intelligent fallbacks
2943
+ - ChatBubble - Chat interface with message grouping and timestamps
2944
+ - Empty - Customizable empty state displays
2945
+ - QRCode - QR code generation with click-to-open functionality
2946
+
2947
+ Layout & Navigation System
2948
+
2949
+ Comprehensive layout framework for application structure:
2950
+ - Layout - Complete layout system with Header (auto-hide), Sider (collapsible), Navbar (portal-based), BottomTab (with badges),
2951
+ and container components
2952
+ - Modal/Dialog - Composable dialog system with backdrop, animations, and gesture support
2953
+ - BottomSheet - Mobile-optimized bottom sheet with drag gestures
2954
+ - Menu - Navigation menus with horizontal/vertical modes and submenu support
2955
+ - Tab - Tabbed interfaces with lazy loading and scroll management
2956
+ - ScreenNavigator - Gesture-based screen navigation with spring animations
2957
+
2958
+ Interactive Components
2959
+
2960
+ Advanced user interaction components:
2961
+ - Pagination - Smart page navigation with ellipsis and responsive design
2962
+ - InfiniteScroll - Automatic content loading with intersection observer
2963
+ - DndKit - Drag and drop functionality with provider pattern
2964
+ - Radio - Radio button groups with custom styling
2965
+ - ToggleSelect - Button-based selection with single/multi-select modes
2966
+ - Share - Native share API with copy fallback
2967
+
2968
+ Utility & Feedback Components
2969
+
2970
+ Supporting components for enhanced user experience:
2971
+ - Loading - Comprehensive loading states (Area, Button, Input, Skeleton, Spin, ProgressBar) with animations
2972
+ - Link - Adaptive navigation links with SSR/CSR compatibility
2973
+ - MapView - Map integration supporting both Google Maps and Pigeon Maps with markers and overlays
2974
+ - Image - Optimized image component with blur placeholders and SSR support
2975
+ - Portal - Teleportation component for rendering outside component tree
2976
+
2977
+ Advanced Features
2978
+
2979
+ State Management Integration
2980
+
2981
+ - Context-driven architecture for complex components
2982
+ - Signal-based real-time communication components
2983
+ - Session storage integration for form persistence
2984
+ - Theme-aware styling with automatic adaptation
2985
+
2986
+ Performance Optimizations
2987
+
2988
+ - Lazy loading support for heavy components
2989
+ - Code splitting at component level
2990
+ - Optimized re-rendering with React.memo patterns
2991
+ - Intersection Observer for scroll-based interactions
2992
+
2993
+ Developer Experience
2994
+
2995
+ - Comprehensive TypeScript interfaces for all props
2996
+ - Consistent naming conventions and API patterns
2997
+ - Built-in error boundaries and fallback handling
2998
+ - Extensive JSDoc documentation
2999
+ - Hot reload support for development
3000
+
3001
+ Accessibility & Internationalization
3002
+
3003
+ - ARIA attributes and keyboard navigation support
3004
+ - Screen reader compatibility
3005
+ - RTL (right-to-left) language support
3006
+ - Localized date/time formatting
3007
+ - Color contrast compliance
3008
+
3009
+ Usage Patterns
3010
+
3011
+ The library follows a consistent component composition pattern where complex components are built from smaller, focused
3012
+ subcomponents. For example:
3013
+
3014
+ - Chart.Bar, Chart.Line for different visualization types
3015
+ - Dialog.Modal, Dialog.Title, Dialog.Content for composable modals
3016
+ - Layout.Header, Layout.Sider, Layout.Navbar for layout construction
3017
+ - Upload.File, Upload.Image, Upload.Images for different upload scenarios
3018
+
3019
+ This design enables maximum flexibility while maintaining consistency across the application. Components are designed to work
3020
+ seamlessly together, sharing common styling patterns, validation systems, and state management approaches.
3021
+
3022
+ The library serves as a comprehensive foundation for building modern, accessible, and performant web applications with a focus
3023
+ on developer productivity and end-user experience.
3024
+
3025
+ Avatar
3026
+ - Displays user profile images with automatic fallback to user icon
3027
+ - Props: className?: string, icon?: ReactNode, src?: string
3028
+
3029
+ Button
3030
+ - Enhanced button with automatic loading states and error handling
3031
+ - Props: onClick: (e, {onError}) => Promise<Result>, onSuccess?: (result) => void, className?, children, standard button props
3032
+
3033
+ Input
3034
+ - Comprehensive input system with real-time validation and caching
3035
+ - Props: value: string, validate: (value) => boolean | string, onChange?, nullable?, inputStyleType?: "bordered" | "borderless"
3036
+ | "underline", icon?, cacheKey?
3037
+ - Variants: Input.TextArea, Input.Password, Input.Email, Input.Number, Input.Checkbox
3038
+
3039
+ Select
3040
+ - Advanced dropdown with search and multi-select capabilities
3041
+ - Props: value: T | T[], options: {label, value}[], multiple?, searchable?, onChange, onSearch?, renderOption?, renderSelected?
3042
+
3043
+ DatePicker
3044
+ - Date/time picker with range selection support
3045
+ - Props: value?: Dayjs, onChange, showTime?, format?, disabledDate?
3046
+ - Variants: DatePicker.RangePicker, DatePicker.TimePicker
3047
+
3048
+ CodeInput
3049
+ - PIN/code input with individual character boxes
3050
+ - Props: maxNum: number, value: string, onChange, unitStyle?: "box" | "underline", autoComplete?
3051
+
3052
+ Display Components
3053
+
3054
+ Table
3055
+ - Feature-rich data table with pagination and responsive design
3056
+ - Props: columns: Column[], dataSource: any[], loading?, pagination?, onRow?, rowClassName?
3057
+
3058
+ Modal
3059
+ - Dialog modal with backdrop and action buttons
3060
+ - Props: open: boolean, onCancel, title?, action?, confirmClose?
3061
+ - Variants: Modal.Window
3062
+
3063
+ Image
3064
+ - Optimized image component with blur placeholder and SSR support
3065
+ - Props: src?, file?: ProtoFile, abstractData?, alt?, standard Next.js Image props
3066
+
3067
+ ChatBubble
3068
+ - Chat message bubble with avatar and timestamp
3069
+ - Props: avatar?, hasPrev?, hasNext?, isMe?, name?, at?: Dayjs, children
3070
+
3071
+ Empty
3072
+ - Empty state placeholder with customizable message
3073
+ - Props: description?, minHeight?, children?
3074
+
3075
+ QRCode
3076
+ - QR code generator with click-to-open functionality
3077
+ - Props: href: string, className?
3078
+
3079
+ Layout Components
3080
+
3081
+ BottomSheet
3082
+ - Only mobile bottom sheet with drag gestures
3083
+ - Props: open: boolean, onCancel, type: "full" | "half", children
3084
+
3085
+ Layout
3086
+ Layout - Complete layout framework with responsive design
3087
+ - Layout.Header - Top header with auto-hide functionality
3088
+ - Props: className?: string, type?: "static" | "hide", children?: any, height?: number
3089
+ - Features: Auto-hide on scroll, fixed positioning
3090
+ - Layout.Sider - Collapsible sidebar
3091
+ - Props: className?: string, bgClassName?: string, children?: any
3092
+ - Features: Drawer-based with toggle functionality
3093
+ - Layout.Navbar - Navigation bar with portal content
3094
+ - Props: className?: string, children?: ReactNode, height?:
3095
+
3096
+ Menu
3097
+ - Navigation menu with horizontal/vertical modes and submenu support
3098
+ - Props: items: MenuItem[], mode?: "horizontal" | "inline", selectedKeys?, onClick?, inlineCollapsed?
3099
+
3100
+
3101
+ Tab
3102
+ - Tabbed interface system
3103
+ - Tab.Provider - Tab context provider
3104
+ - Props: className?: string, defaultMenu?: string | null, children?: any
3105
+ - Tab.Menu - Tab menu item
3106
+ - Props: className?: string, activeClassName?: string, disabledClassName?: string, disabled?: boolean, menu: string, children:
3107
+ any, scrollToTop?: boolean, tooltip?: string
3108
+ - Tab.Panel - Tab content panel
3109
+ - Props: className?: string, menu: string, children?: any, loading?: "eager" | "lazy" | "every"
3110
+ - Features: Lazy loading support
3111
+
3112
+ ScreenNavigator
3113
+ - Gesture-based screen navigation
3114
+ - ScreenNavigator.Provider - Navigation context provider
3115
+ - Props: setMenu?: (menu: string) => void, children: ReactNode, menus: string[]
3116
+ - Features: Gesture-based navigation, spring animations
3117
+ - ScreenNavigator.Screen - Individual screen container
3118
+ - Props: children: ReactNode, className?: string
3119
+ - ScreenNavigator.NavbarItem - Navigation bar item
3120
+ - Props: menu: string, children: ReactNode, className?: string
3121
+
3122
+ Upload
3123
+ - File upload system with multiple modes
3124
+ - Upload
3125
+ - Basic file upload with drag & drop
3126
+ - Props: onChange?: (fileList: FileList) => void; multiple?: boolean; accept?: string; className?: string; uploadClassName?: string; children: React.ReactNode; disabled?: boolean;
3127
+ - Upload.File
3128
+ - Single file upload with preview
3129
+ - Props: multiple?: boolean; file: ProtoFile | null; render?: (file: ProtoFile) => React.ReactNode; onChange?: (e: File | FileList) => void | Promise<void>; onRemove?: (e: any) => void; children?: React.ReactNode; disabled?: boolean; maxCount?: number; className?: string; uploadClassName?: string; accept?: string;
3130
+ - Upload.FileList
3131
+ - Multiple files with table view and progress tracking
3132
+ - Props: multiple?: boolean; fileList: ProtoFile[]; render?: (file: ProtoFile) => React.ReactNode; onChange?: (e: File | FileList) => void | Promise<void>; onRemove?: (e: any) => void; children?: React.ReactNode; disabled?: boolean; maxCount?: number; className?: string; uploadClassName?: string; accept?: string;
3133
+ - Upload.Image
3134
+ - Image upload with integrated cropping functionality
3135
+ - Props: multiple?: boolean; file: ProtoFile | null; render?: (file: ProtoFile) => React.ReactNode; onChange?: (e: File | FileList) => void | Promise<void>; onRemove?: (e: any) => void; children?: React.ReactNode; disabled?: boolean; maxCount?: number; className?: string; uploadClassName?: string; accept?: string;
3136
+ - Upload.Images
3137
+ - Multiple image upload with gallery preview
3138
+ - Props: multiple?: boolean; fileList: ProtoFile[]; render?: (file: ProtoFile) => React.ReactNode; onChange?: (e: File | FileList) => void | Promise<void>; onRemove?: (e: any) => void; children?: React.ReactNode; disabled?: boolean; maxCount?: number; className?: string; uploadClassName?: string; accept?: string;
3139
+
3140
+ DndKit
3141
+ - Drag and drop functionality built on @dnd-kit
3142
+ - DndKit.Provider
3143
+ - DnD context provider
3144
+ - Props: className?: string + all DndContextProps
3145
+ - DndKit.DraggableUnit
3146
+ - Draggable item wrapper
3147
+ - Props: id: string, children: ReactNode, className?: string, onClick?: () => void | Promise<void>
3148
+ - DndKit.DroppableColumn
3149
+ - Drop target column
3150
+ - Props: id: string, items: T[], className?: string, children: ReactNode, onOver?: (id, items, event) => void, onEnd?: (id,
3151
+ item, event) => void
3152
+
3153
+ MapView
3154
+ - Map integration with multiple providers
3155
+ - MapView.Map
3156
+ - Main map container with theme awareness
3157
+ - Props: className?: string, onLoad?: () => void, onClick?: (coordinate) => void, onRightClick?: (coordinate) => void,
3158
+ onMouseMove?: (coordinate) => void, children: any
3159
+ - MapView.Marker
3160
+ - Map marker component
3161
+ - Props: coordinate: cnst.Coordinate, zIndex?: number, children?: any
3162
+ - MapView.Google
3163
+ - Google Maps implementation
3164
+ - Props: id?: string, className?: string, mapKey: string, onClick/onRightClick?: (coordinate) => void, center?:
3165
+ cnst.Coordinate, onChangeCenter?: (coordinate) => void, zoom?: number, onChangeZoom?: (zoom) => void, bounds?: {minLat, maxLat,
3166
+ minLng, maxLng}, onLoad?: () => void, onMouseMove?: (coordinate, event) => void, options?: google.maps.MapOptions, children: any
3167
+ - MapView.Pigeon
3168
+ - Pigeon Maps implementation (lightweight alternative)
3169
+ - Props: id?: string, className?: string, onLoad?: () => void, onClick/onRightClick?: (coordinate) => void, center?:
3170
+ cnst.Coordinate, onChangeCenter?: (coordinate) => void, zoom?: number, onChangeZoom?: (zoom) => void, bounds?: {minLat, maxLat,
3171
+ minLng, maxLng}, onChangeBounds?: (bounds) => void, mouseEvents?: boolean, onMouseMove?: (coordinate) => void, mapTiler?: (x, y,
3172
+ z, dpr) => string, children?: any, zoomControlStyle?: CSSProperties
3173
+
3174
+
3175
+ Pagination
3176
+ - Page navigation with smart ellipsis and responsive design
3177
+ - Props: currentPage: number, total: number, onPageSelect, itemsPerPage: number
3178
+
3179
+ Radio
3180
+ - Radio button group with custom styling support
3181
+ - Props: value, children: ReactElement[], onChange, disabled?
3182
+
3183
+ ToggleSelect
3184
+ - Button-based selection with single/multi-select modes
3185
+ - Props: items, value, validate, onChange, nullable
3186
+ - Variants: ToggleSelect.Multi
3187
+
3188
+ Share
3189
+ - Native share API with copy fallback
3190
+ - Props: title: string, url: string, children
3191
+
3192
+ Specialized Component Groups
3193
+
3194
+ Chart
3195
+ - Visualization components built on Chart.js and react-chartjs-2
3196
+ - Chart.Bar - Bar chart component
3197
+ - Props: data: ChartData<"bar">, options?: ChartOptions<"bar">
3198
+ - Features: Responsive layout, legend display, title configuration
3199
+ - Chart.Line - Line chart component
3200
+ - Props: data: ChartData<"line">, options?: ChartOptions<"line">
3201
+ - Features: Line-specific Chart.js configuration with curve interpolation
3202
+ - Chart.Pie - Pie chart component
3203
+ - Props: data: ChartData<"pie">, options?: ChartOptions<"pie">
3204
+ - Features: ArcElement rendering, responsive design
3205
+ - Chart.Doughnut - Doughnut chart component
3206
+ - Props: data: ChartData<"doughnut">, options?: ChartOptions<"doughnut">
3207
+ - Features: Similar to pie but with center cutout
3208
+
3209
+ Dialog
3210
+ - Composable modal dialog system built on Radix UI
3211
+ - Dialog.Provider - Dialog context provider
3212
+ - Props: className?: string, open?: boolean, defaultOpen?: boolean, children?: any
3213
+ - Dialog.Modal - Main modal container
3214
+ - Props: className?: string, bodyClassName?: string, confirmClose?: boolean, children?: any, onCancel?: () => void
3215
+ - Features: Drag gestures, spring animations, responsive design, close confirmation
3216
+ - Dialog.Title - Modal title component
3217
+ - Props: children?: ReactNode
3218
+ - Dialog.Content - Modal content area
3219
+ - Props: className?: string, children?: ReactNode
3220
+ - Dialog.Action - Modal action buttons container
3221
+ - Props: children?: ReactNode
3222
+ - Dialog.Trigger - Modal trigger element
3223
+ - Props: className?: string, children?: any
3224
+
3225
+ Link
3226
+ - Adaptive navigation system
3227
+ - Link
3228
+ - Main adaptive link (auto-switches between CSR/Next.js based on render mode)
3229
+ - Link.Back - Back navigation link
3230
+ - Props: className?: string, children?: any
3231
+ - Features: Browser history integration
3232
+ - Link.Close - Window close link
3233
+ - Props: Similar to Back but closes window
3234
+ - Link.CsrLink & Link.NextLink - Environment-specific implementations with active state support
3235
+
3236
+
3237
+ Loading
3238
+ - Loading states for different UI elements
3239
+ - Loading.Area - Full-screen loading overlay with animated dots
3240
+ - Loading.Button - Button loading skeleton
3241
+ - Props: className?: string, active?: boolean, style?: CSSProperties
3242
+ - Loading.Input - Input loading skeleton
3243
+ - Loading.Skeleton - Multi-line content skeleton with pulse animation
3244
+ - Loading.Spin - Custom loading spinner
3245
+ - Props: indicator?: ReactNode, isCenter?: boolean
3246
+ - Loading.ProgressBar - Animated progress bar
3247
+ - Props: className?: string, value: number, max: number
3248
+ - Features: React Spring animations
3249
+
3250
+ Key Framework Features
3251
+
3252
+ - TypeScript support with strict typing
3253
+ - Responsive design with mobile-first approach
3254
+ - Internationalization (i18n) integration
3255
+ - Session storage caching for form inputs
3256
+ - Accessibility compliance
3257
+ - Consistent DaisyUI/Tailwind CSS styling
3258
+ - Modern React patterns (hooks, context, providers)
3259
+ - Error handling and validation systems
3260
+ `;
2724
3261
  var frameworkAbstract = `
2725
3262
  Intro
2726
3263
  - Build an all-stack application at once.
@@ -2740,7 +3277,66 @@ Procedure
2740
3277
  - No Spaghetti Components anymore, build your page with domain-driven components
2741
3278
  - write one page, use SSR on Next.js and build Android&iOS CSR app with beautiful page transitions!
2742
3279
  - built-in ai code generation, tell about business, the logic is generated.
3280
+
3281
+
2743
3282
  `;
3283
+ var eslintDescription = `
3284
+ Core ESLint Extensions
3285
+
3286
+ Base Configurations:
3287
+ - eslint:recommended - Standard ESLint recommended rules
3288
+ - next & next/core-web-vitals - Next.js specific linting rules
3289
+ - @typescript-eslint/recommended-type-checked - TypeScript recommended rules with type checking
3290
+ - @typescript-eslint/strict-type-checked - Strict TypeScript type checking rules
3291
+ - @typescript-eslint/stylistic-type-checked - TypeScript stylistic rules with type checking
3292
+
3293
+ Third-Party Plugins
3294
+
3295
+ 1. eslint-plugin-unused-imports
3296
+ - Automatically detects and warns about unused imports
3297
+ - Helps keep code clean by removing unnecessary import statements
3298
+
3299
+ 2. eslint-plugin-simple-import-sort
3300
+ - Automatically sorts import statements in a consistent order
3301
+ - Enforces clean import organization throughout the codebase
3302
+
3303
+ Custom Plugin: @akanjs/lint
3304
+
3305
+ 1. useClientByFile
3306
+ - Enforces proper "use client" directive usage in Next.js App Router
3307
+ - Server files must NOT have "use client" directive
3308
+ - Client files MUST have "use client" directive at the top
3309
+
3310
+ 2. noImportClientFunctions
3311
+ - Prevents server files from importing client-side functions
3312
+ - Ensures proper separation between server and client code
3313
+
3314
+ 3. nonScalarPropsRestricted
3315
+ - Prevents non-scalar props (functions) in server components
3316
+ - Specifically targets page.tsx and layout.tsx files
3317
+ - Allows exceptions for specific props like "loader", "render", and "of"
3318
+
3319
+ 4. noImportExternalLibrary
3320
+ - Restricts external library imports in pure import/re-export files
3321
+ - Only allows imports from the same app scope (@appName/...)
3322
+ - Promotes clean architecture and prevents dependency leakage
3323
+
3324
+ Key Rule Configurations
3325
+
3326
+ Disabled Rules:
3327
+ - no-console: "error" - Prevents console statements in production code
3328
+ - Various TypeScript strict rules are disabled for flexibility
3329
+ - React and Next.js specific rules are relaxed for development ease
3330
+
3331
+ Import Management:
3332
+ - unused-imports/no-unused-imports: "warn" - Warns about unused imports
3333
+ - simple-import-sort/imports: "warn" - Enforces import sorting
3334
+ - import/first: "warn" - Ensures imports come first
3335
+ - import/newline-after-import: "warn" - Enforces newline after imports
3336
+
3337
+ This configuration creates a robust linting setup that enforces Next.js App Router best practices, maintains clean code
3338
+ organization, and ensures proper server/client code separation.
3339
+ `;
2744
3340
  var scalarConstantDescription = `
2745
3341
  Purpose and Structure
2746
3342
 
@@ -3095,10 +3691,10 @@ ${frameworkAbstract}
3095
3691
  2. <model>.constant.ts \uD30C\uC77C\uC5D0 \uB300\uD55C \uAC1C\uC694
3096
3692
  ${scalarConstantDescription}
3097
3693
 
3098
- 3. <model.constant.ts \uD30C\uC77C\uC758 Enum \uC791\uC131\uBC95
3694
+ 3. <model>.constant.ts \uD30C\uC77C\uC758 Enum \uC791\uC131\uBC95
3099
3695
  ${howToSetEnumInModelConstant}
3100
3696
 
3101
- 4. <model.constant.ts \uD30C\uC77C\uC758 Field \uC791\uC131\uBC95
3697
+ 4. <model>.constant.ts \uD30C\uC77C\uC758 Field \uC791\uC131\uBC95
3102
3698
  ${howToSetFieldInModelConstant}
3103
3699
 
3104
3700
  5. \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8 \uB0B4 \uB2E4\uB978 constant.ts \uD30C\uC77C\uB4E4\uC5D0 \uB300\uD55C \uC608\uC2DC
@@ -3123,6 +3719,87 @@ Target filename: ${modelName}.constant.ts
3123
3719
  \`\`\`
3124
3720
  ${boilerplate}
3125
3721
  \`\`\`
3722
+ `;
3723
+ var requestView = ({
3724
+ sysName,
3725
+ modelName,
3726
+ ModelName,
3727
+ boilerplate,
3728
+ constant,
3729
+ properties,
3730
+ exampleFiles
3731
+ }) => `
3732
+
3733
+
3734
+ 1. Akan.js \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uAC1C\uC694
3735
+ ${frameworkAbstract}
3736
+
3737
+ 2. Akan.js\uD504\uB808\uC784\uC6CC\uD06C \uB370\uC774\uD130 \uAE30\uBC18 \uBAA8\uB4C8\uC5D0 \uB300\uD55C \uAC1C\uC694
3738
+ ${moduleDesription}
3739
+
3740
+ 3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uAC1C\uC694
3741
+ ${eslintDescription}
3742
+
3743
+ 4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uAC1C\uC694
3744
+ ${utilUiDescription}
3745
+
3746
+
3747
+
3748
+ 5. ${ModelName}.constant.ts \uD30C\uC77C\uC5D0 \uB300\uD55C \uC815\uBCF4
3749
+ ${constant}
3750
+
3751
+ 6. ${modelName}\uC5D0\uC11C \uC885\uC18D\uB418\uB294 \uB2E4\uB978 \uBAA8\uB378\uB4E4\uC758 \uD0C0\uC785 \uC815\uC758
3752
+ ${properties.map(
3753
+ (property) => `
3754
+ \`\`\`
3755
+ ${property.key}.constant.ts
3756
+
3757
+
3758
+ ${property.source}
3759
+ \`\`\`
3760
+ `
3761
+ ).join("\n\n")}
3762
+
3763
+
3764
+ 7. \uC608\uC2DC \uD30C\uC77C\uB4E4
3765
+ ${exampleFiles.map(
3766
+ (example) => `
3767
+ Example filename: ${example.filepath}
3768
+ \`\`\`
3769
+ ${example.content}
3770
+ \`\`\`
3771
+ `
3772
+ ).join("\n\n")}
3773
+
3774
+
3775
+
3776
+ Application name: ${sysName}
3777
+ Model name: ${modelName}
3778
+ Target filename: ${ModelName}.View.tsx
3779
+
3780
+
3781
+ \uB108\uB294 Akan.js\uB77C\uB294 \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C\uB85C Typescript \uAE30\uBC18 \uD504\uB85C\uADF8\uB7A8\uC744 \uC791\uC131\uD558\uB294 \uC2DC\uB2C8\uC5B4 \uAC1C\uBC1C\uC790\uC57C.
3782
+ \uADF8 \uC911\uC5D0\uC11C\uB3C4 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790.
3783
+ \uB9CC\uC57D\uC5D0 \uC544\uC774\uCF58 \uC0AC\uC6A9\uC774 \uD544\uC694\uD558\uBA74 react-icons \uB77C\uC774\uBE0C\uB7EC\uB9AC\uC5D0\uC11C \uC801\uD569\uD55C \uC544\uC774\uCF58\uC744 \uCC3E\uC544\uC11C \uC0AC\uC6A9\uD574\uC918.
3784
+ \uB610, \uC0C9\uC0C1\uC744 \uC0AC\uC6A9\uD558\uB824\uACE0 \uD558\uBA74 \uD558\uB4DC\uCF54\uB529\uB41C \uC0C9\uC0C1(bg-red)\uC774 \uC544\uB2CC \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary)\uC744 \uC0AC\uC6A9\uD574\uC11C \uC791\uC131\uD574\uC918.
3785
+ \uADF8\uB9AC\uACE0 optional\uD55C \uD544\uB4DC\uB294 field && <div>... \uAC00 \uC544\uB2CC, field ? <div>... : null \uD615\uD0DC\uB85C \uC791\uC131\uD574\uC918.
3786
+ css\uB77C\uC774\uBE0C\uB7EC\uB9AC\uB294 DaisyUI\uB97C \uAE30\uBC18\uC73C\uB85C \uC791\uC131\uD574\uC8FC\uB294\uB370, btn, input, badge\uC640 \uAC19\uC740 \uB2E8\uC21C\uD55C \uAE30\uBCF8 css\uB294 \uC0AC\uC6A9\uD574\uB3C4 \uAD1C\uCC2E\uC544. \uADF8\uB7F0\uB370 card, hero\uAC19\uC774 \uBCF5\uC7A1\uD55C \uCEF4\uD3EC\uB10C\uD2B8\uB294 \uC0AC\uC6A9\uD558\uBA74 \uC548\uB3FC.
3787
+ \uBAA8\uB378\uC5D0 \uB300\uD574\uC11C object destructuring\uC740 \uD558\uC9C0\uB9D0\uACE0 ${modelName}.field \uD615\uD0DC\uB85C \uC811\uADFC\uD558\uACE0, \uD0C0\uC785\uC5D0 \uC5D0\uB7EC\uB294 \uC808\uB300\uB85C \uBC1C\uC0DD\uD558\uC9C0 \uC54A\uB3C4\uB85D ${modelName}.constant.ts\uC5D0 \uC791\uC131\uB418\uC788\uB294 \uC2A4\uD0A4\uB9C8\uB97C \uBCF4\uACE0 \uC791\uC131\uD574.
3788
+ \uC870\uAC74\uBD80 className\uC774 \uD544\uC694\uD55C \uACBD\uC6B0\uC5D0\uB294 clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC\uB97C \uC0AC\uC6A9\uD574\uC57C\uB3FC.
3789
+ \uBAA8\uB4E0 \uBAA8\uB378 \uD544\uB4DC\uC5D0 \uC811\uADFC\uD558\uAE30 \uC804\uC5D0, \uAC01 \uC2A4\uD0A4\uB9C8\uC758 \uC2E4\uC81C \uD544\uB4DC \uB9AC\uC2A4\uD2B8\uB97C \uC791\uC131\uD558\uACE0 \uAC80\uD1A0\uD574. \uD2B9\uD788 \uC911\uCCA9\uB41C \uAC1D\uCCB4( ex) XXX.XXX.XXX )\uC5D0 \uC811\uADFC\uD560 \uB54C\uB294 \uB354\uC6B1 \uC8FC\uC758\uD574.
3790
+ \uB610\uD55C ${modelName}\uACFC \uC885\uC18D\uC131\uC774 \uC788\uB294 \uB2E4\uB978 \uBAA8\uB378\uB4E4\uC758 \uD0C0\uC785\uB4E4\uB3C4 \uBAA8\uB450 \uC704\uBC30\uD558\uC9C0\uB9D0\uACE0 \uC798 \uD30C\uC545\uD558\uACE0 \uC791\uC131\uD574.
3791
+ \uC704\uC5D0\uC11C \uC124\uBA85\uD55C \uBAA8\uB4E0 \uB8F0\uACFC \uC124\uBA85, \uD0C0\uC785\uC744 \uC808\uB300\uB85C \uC704\uBC30\uD558\uC9C0\uB9D0\uACE0 \uC798 \uD30C\uC545\uD558\uACE0 \uC791\uC131\uD574.(\uAC01 \uB370\uC774\uD130\uC758 \uD0C0\uC785, \uCEF4\uD3EC\uB10C\uD2B8\uC758 props\uB4F1...)
3792
+ \uC124\uBA85\uD55C \uB0B4\uC6A9 \uC774\uC678\uC5D0 \uB0B4\uC6A9\uC73C\uB85C \uB2C8\uAC00 \uCD94\uC0C1\uD574\uC11C \uC4F0\uC9C0\uB9D0\uACE0 \uC704\uC5D0 \uBA85\uC2DC\uB418\uC788\uB294 \uB8F0 \uC548\uC5D0\uC11C\uB9CC \uC791\uC131\uD574. \uC788\uC9C0\uB3C4 \uC54A\uC740 \uAC83\uB4E4 \uB9CC\uB4E4\uC5B4\uC11C \uCD94\uC0C1\uD654 \uC2DC\uCF1C\uC11C \uC790\uAFB8 \uC4F0\uB294 \uC77C\uC740 \uC808\uB300\uB85C \uD558\uC9C0\uB9C8.
3793
+ \uD2B9\uD788\uB098 \uBC29\uAE08 \uB9D0\uD55C \uC774 \uC704 \uB450 \uBB38\uC7A5\uC740 \uC808\uB300\uC801\uC73C\uB85C \uC9C0\uCF1C\uC57C \uD560 \uB8F0\uC774\uC57C \uC791\uC131\uD560 \uB54C \uD56D\uC0C1 \uC9C0\uD0A4\uACE0 \uB530\uB77C.
3794
+ ${ModelName}.View.tsx \uCF54\uB4DC\uB97C \uC791\uC131\uD574\uC918. \uC77C\uBC18\uC801\uC73C\uB85C \uC0AC\uC6A9\uD560 \uC218 \uC788\uB294 \uB514\uC790\uC778\uC758 \uCEF4\uD3EC\uB10C\uD2B8\uB97C 4\uAC1C \uC815\uB3C4 \uB9CC\uB4E4\uC5B4\uC918. (ex card, table...)
3795
+ \uC608\uC2DC \uB4E4\uC5B4\uC92C\uB2E4\uACE0 \uC608\uC2DC\uB9CC \uB9CC\uB4E4\uC9C0 \uB9D0\uACE0 \uB2C8 \uC0DD\uAC01\uC5D0 \uC77C\uBC18\uC801\uC73C\uB85C \uC0AC\uC6A9\uD55C\uB2E4 \uD558\uB294 \uCEF4\uD3EC\uB10C\uD2B8\uB85C \uC0DD\uAC01\uD574\uC11C \uB9CC\uB4E4\uC5B4.
3796
+
3797
+ Target filename: ${ModelName}.View.tsx
3798
+ \`\`\`
3799
+
3800
+ \`\`\`
3801
+
3802
+
3126
3803
  `;
3127
3804
 
3128
3805
  // pkgs/@akanjs/cli/src/application/application.prompt.ts
@@ -3174,6 +3851,10 @@ var ApplicationRunner = class {
3174
3851
  workspace.setTsPaths("app", appName);
3175
3852
  return AppExecutor.from(workspace, appName);
3176
3853
  }
3854
+ async removeApplication(app) {
3855
+ await app.workspace.exec(`rm -rf apps/${app.name}`);
3856
+ app.log(`Application ${app.name} removed`);
3857
+ }
3177
3858
  async scanSync(app) {
3178
3859
  const akanConfig = await getAppConfig(app.cwdPath, {
3179
3860
  ...app.workspace.getBaseDevEnv(),
@@ -3281,11 +3962,11 @@ var ApplicationRunner = class {
3281
3962
  ]);
3282
3963
  app.dist.writeFile("frontend/Dockerfile", akanConfig.frontend.dockerfile);
3283
3964
  }
3284
- async serveFrontend(app, { open: open2 = false } = {}) {
3965
+ async serveFrontend(app, { open: open2 = false, turbo = true } = {}) {
3285
3966
  const { env } = await this.#prepareCommand(app, "serve", "frontend");
3286
3967
  if (open2)
3287
3968
  setTimeout(() => (0, import_open.default)("http://localhost:4200"), 3e3);
3288
- await app.spawn("npx", ["next", "dev", "-p", "4200"], { env });
3969
+ await app.spawn("npx", ["next", "dev", "-p", "4200", ...turbo ? ["--turbo"] : []], { env });
3289
3970
  }
3290
3971
  async #getViteConfig(app) {
3291
3972
  const { env } = await this.#prepareCommand(app, "build", "csr");
@@ -3366,7 +4047,7 @@ var ApplicationRunner = class {
3366
4047
  setTimeout(() => (0, import_open.default)("http://localhost:4201"), 3e3);
3367
4048
  }
3368
4049
  async #prepareIos(app) {
3369
- const isAdded = import_fs12.default.existsSync(`${app.cwdPath}/ios/App/Podfile`);
4050
+ const isAdded = import_fs10.default.existsSync(`${app.cwdPath}/ios/App/Podfile`);
3370
4051
  if (!isAdded) {
3371
4052
  await app.spawn("npx", ["cap", "add", "ios"]);
3372
4053
  await app.spawn("npx", ["@capacitor/assets", "generate"]);
@@ -3401,7 +4082,7 @@ var ApplicationRunner = class {
3401
4082
  await capacitorApp.releaseIos();
3402
4083
  }
3403
4084
  async #prepareAndroid(app) {
3404
- const isAdded = import_fs12.default.existsSync(`${app.cwdPath}/android/app/build.gradle`);
4085
+ const isAdded = import_fs10.default.existsSync(`${app.cwdPath}/android/app/build.gradle`);
3405
4086
  if (!isAdded) {
3406
4087
  await app.spawn("npx", ["cap", "add", "android"]);
3407
4088
  await app.spawn("npx", ["@capacitor/assets", "generate"]);
@@ -3483,14 +4164,14 @@ var ApplicationRunner = class {
3483
4164
  const buildRoot = `${app.workspace.workspaceRoot}/releases/builds/${app.name}`;
3484
4165
  const appVersionInfo = import_js_yaml2.default.load(app.readFile("config.yaml"));
3485
4166
  const platformVersion = appVersionInfo.platforms.android.versionName;
3486
- if (import_fs12.default.existsSync(buildRoot))
4167
+ if (import_fs10.default.existsSync(buildRoot))
3487
4168
  await import_promises2.default.rm(buildRoot, { recursive: true, force: true });
3488
4169
  await import_promises2.default.mkdir(buildRoot, { recursive: true });
3489
- if (rebuild || !import_fs12.default.existsSync(`${app.dist.cwdPath}/backend`))
4170
+ if (rebuild || !import_fs10.default.existsSync(`${app.dist.cwdPath}/backend`))
3490
4171
  await this.buildBackend(app);
3491
- if (rebuild || !import_fs12.default.existsSync(`${app.dist.cwdPath}/frontend`))
4172
+ if (rebuild || !import_fs10.default.existsSync(`${app.dist.cwdPath}/frontend`))
3492
4173
  await this.buildFrontend(app);
3493
- if (rebuild || !import_fs12.default.existsSync(`${app.dist.cwdPath}/csr`))
4174
+ if (rebuild || !import_fs10.default.existsSync(`${app.dist.cwdPath}/csr`))
3494
4175
  await this.buildCsr(app);
3495
4176
  const buildVersion = `${platformVersion}-${buildNum}`;
3496
4177
  const buildPath = `${buildRoot}/${buildVersion}`;
@@ -3505,7 +4186,7 @@ var ApplicationRunner = class {
3505
4186
  buildRoot,
3506
4187
  "./"
3507
4188
  ]);
3508
- if (import_fs12.default.existsSync(`${app.dist.cwdPath}/csr`)) {
4189
+ if (import_fs10.default.existsSync(`${app.dist.cwdPath}/csr`)) {
3509
4190
  await import_promises2.default.cp(`${app.dist.cwdPath}/csr`, "./csr", { recursive: true });
3510
4191
  await app.workspace.spawn("zip", [
3511
4192
  "-r",
@@ -3515,7 +4196,7 @@ var ApplicationRunner = class {
3515
4196
  await import_promises2.default.rm("./csr", { recursive: true, force: true });
3516
4197
  }
3517
4198
  const sourceRoot = `${app.workspace.workspaceRoot}/releases/sources/${app.name}`;
3518
- if (import_fs12.default.existsSync(sourceRoot)) {
4199
+ if (import_fs10.default.existsSync(sourceRoot)) {
3519
4200
  const MAX_RETRY = 3;
3520
4201
  for (let i = 0; i < MAX_RETRY; i++) {
3521
4202
  try {
@@ -3535,7 +4216,7 @@ var ApplicationRunner = class {
3535
4216
  await Promise.all(
3536
4217
  [".next", "ios", "android", "public/libs"].map(async (path7) => {
3537
4218
  const targetPath = `${sourceRoot}/apps/${app.name}/${path7}`;
3538
- if (import_fs12.default.existsSync(targetPath))
4219
+ if (import_fs10.default.existsSync(targetPath))
3539
4220
  await import_promises2.default.rm(targetPath, { recursive: true, force: true });
3540
4221
  })
3541
4222
  );
@@ -3563,8 +4244,8 @@ var ApplicationRunner = class {
3563
4244
  []
3564
4245
  )
3565
4246
  ]);
3566
- import_fs12.default.writeFileSync(`${sourceRoot}/tsconfig.json`, JSON.stringify(tsconfig, null, 2));
3567
- import_fs12.default.writeFileSync(
4247
+ import_fs10.default.writeFileSync(`${sourceRoot}/tsconfig.json`, JSON.stringify(tsconfig, null, 2));
4248
+ import_fs10.default.writeFileSync(
3568
4249
  `${sourceRoot}/README.md`,
3569
4250
  `# ${app.name}
3570
4251
  \uBCF8 \uD504\uB85C\uC81D\uD2B8\uC758 \uC18C\uC2A4\uCF54\uB4DC \uBC0F \uAD00\uB828\uC790\uB8CC\uB294 \uBAA8\uB450 \uBE44\uBC00\uC815\uBCF4\uB85C \uAD00\uB9AC\uB429\uB2C8\uB2E4.
@@ -3670,6 +4351,9 @@ var ApplicationScript = class {
3670
4351
  if (serve)
3671
4352
  await this.serve(app, { open: true });
3672
4353
  }
4354
+ async removeApplication(app) {
4355
+ await this.#runner.removeApplication(app);
4356
+ }
3673
4357
  async scanApplication(app, verbose = false) {
3674
4358
  const scanResult = await this.#runner.scanSync(app);
3675
4359
  if (verbose)
@@ -3685,7 +4369,7 @@ var ApplicationScript = class {
3685
4369
  }
3686
4370
  async build(app) {
3687
4371
  await this.syncApplication(app);
3688
- await Promise.all([this.buildBackend(app), this.buildFrontend(app)]);
4372
+ await Promise.all([this.buildBackend(app, { sync: false }), this.buildFrontend(app, { sync: false })]);
3689
4373
  }
3690
4374
  async serve(app, { open: open2 = false } = {}) {
3691
4375
  await this.syncApplication(app);
@@ -3706,10 +4390,10 @@ var ApplicationScript = class {
3706
4390
  await this.syncApplication(app);
3707
4391
  await this.#runner.buildFrontend(app);
3708
4392
  }
3709
- async serveFrontend(app, { open: open2 = false, sync = true } = {}) {
4393
+ async serveFrontend(app, { open: open2 = false, turbo = false, sync = true } = {}) {
3710
4394
  if (sync)
3711
4395
  await this.syncApplication(app);
3712
- await this.#runner.serveFrontend(app, { open: open2 });
4396
+ await this.#runner.serveFrontend(app, { open: open2, turbo });
3713
4397
  }
3714
4398
  async buildCsr(app, { sync = true } = {}) {
3715
4399
  if (sync)
@@ -3800,7 +4484,8 @@ var ApplicationCommand = class {
3800
4484
  async createApplication(name, serve, workspace) {
3801
4485
  await this.applicationScript.createApplication(name, workspace, { serve });
3802
4486
  }
3803
- async removeApplication(app, workspace) {
4487
+ async removeApplication(app) {
4488
+ await this.applicationScript.removeApplication(app);
3804
4489
  }
3805
4490
  async scanApplication(app) {
3806
4491
  await this.applicationScript.scanApplication(app, true);
@@ -3829,8 +4514,8 @@ var ApplicationCommand = class {
3829
4514
  async serveBackend(app, open2) {
3830
4515
  await this.applicationScript.serveBackend(app, { open: open2 });
3831
4516
  }
3832
- async serveFrontend(app, open2) {
3833
- await this.applicationScript.serveFrontend(app, { open: open2 });
4517
+ async serveFrontend(app, open2, turbo) {
4518
+ await this.applicationScript.serveFrontend(app, { open: open2, turbo });
3834
4519
  }
3835
4520
  async serveCsr(app, open2) {
3836
4521
  await this.applicationScript.serveCsr(app, { open: open2 });
@@ -3880,8 +4565,7 @@ __decorateClass([
3880
4565
  ], ApplicationCommand.prototype, "createApplication", 1);
3881
4566
  __decorateClass([
3882
4567
  Target.Public(),
3883
- __decorateParam(0, App()),
3884
- __decorateParam(1, Workspace())
4568
+ __decorateParam(0, App())
3885
4569
  ], ApplicationCommand.prototype, "removeApplication", 1);
3886
4570
  __decorateClass([
3887
4571
  Target.Public(),
@@ -3924,7 +4608,8 @@ __decorateClass([
3924
4608
  __decorateClass([
3925
4609
  Target.Public({ short: true }),
3926
4610
  __decorateParam(0, App()),
3927
- __decorateParam(1, Option("open", { type: "boolean", desc: "open web browser", default: false }))
4611
+ __decorateParam(1, Option("open", { type: "boolean", desc: "open web browser", default: false })),
4612
+ __decorateParam(2, Option("turbo", { type: "boolean", desc: "turbo", default: false }))
3928
4613
  ], ApplicationCommand.prototype, "serveFrontend", 1);
3929
4614
  __decorateClass([
3930
4615
  Target.Public({ short: true }),
@@ -4012,7 +4697,7 @@ ApplicationCommand = __decorateClass([
4012
4697
  // pkgs/@akanjs/cli/src/package/package.runner.ts
4013
4698
  var esbuild2 = __toESM(require("esbuild"));
4014
4699
  var import_esbuild_plugin_d = require("esbuild-plugin-d.ts");
4015
- var import_fs13 = __toESM(require("fs"));
4700
+ var import_fs11 = __toESM(require("fs"));
4016
4701
  var import_promises3 = __toESM(require("fs/promises"));
4017
4702
  var PackageRunner = class {
4018
4703
  async version(workspace) {
@@ -4027,6 +4712,10 @@ var PackageRunner = class {
4027
4712
  dict: { pkgName, PkgName: capitalize(pkgName) }
4028
4713
  });
4029
4714
  }
4715
+ async removePackage(pkg) {
4716
+ await pkg.workspace.exec(`rm -rf pkgs/${pkg.name}`);
4717
+ pkg.log(`Package ${pkg.name} removed`);
4718
+ }
4030
4719
  async scanSync(pkg) {
4031
4720
  const scanResult = await pkg.scan();
4032
4721
  return scanResult;
@@ -4034,7 +4723,7 @@ var PackageRunner = class {
4034
4723
  async buildPackage(pkg) {
4035
4724
  const rootPackageJson = pkg.workspace.readJson("package.json");
4036
4725
  const pkgJson = pkg.readJson("package.json");
4037
- if (import_fs13.default.existsSync(pkg.dist.cwdPath))
4726
+ if (import_fs11.default.existsSync(pkg.dist.cwdPath))
4038
4727
  await pkg.workspace.exec(`rm -rf ${pkg.dist.cwdPath}`);
4039
4728
  let buildResult;
4040
4729
  if (pkg.name === "@akanjs/config") {
@@ -4152,6 +4841,9 @@ var PackageScript = class {
4152
4841
  async createPackage(workspace, pkgName) {
4153
4842
  await this.#runner.createPackage(workspace, pkgName);
4154
4843
  }
4844
+ async removePackage(pkg) {
4845
+ await this.#runner.removePackage(pkg);
4846
+ }
4155
4847
  async scanPackage(pkg) {
4156
4848
  const scanResult = await this.#runner.scanSync(pkg);
4157
4849
  pkg.logger.rawLog(JSON.stringify(scanResult, null, 2));
@@ -4163,7 +4855,7 @@ var PackageScript = class {
4163
4855
 
4164
4856
  // pkgs/@akanjs/cli/src/cloud/cloud.runner.ts
4165
4857
  var import_prompts7 = require("@inquirer/prompts");
4166
- var import_chalk = __toESM(require("chalk"));
4858
+ var import_chalk2 = __toESM(require("chalk"));
4167
4859
  var import_latest_version = __toESM(require("latest-version"));
4168
4860
  var import_open2 = __toESM(require("open"));
4169
4861
  var QRcode = __toESM(require("qrcode"));
@@ -4173,17 +4865,17 @@ var CloudRunner = class {
4173
4865
  const config = getHostConfig();
4174
4866
  const self = config.auth ? await getSelf(config.auth.token) : null;
4175
4867
  if (self) {
4176
- Logger.rawLog(import_chalk.default.green(`
4868
+ Logger.rawLog(import_chalk2.default.green(`
4177
4869
  \u2713 Already logged in akan cloud as ${self.nickname}
4178
4870
  `));
4179
4871
  return true;
4180
4872
  }
4181
4873
  const remoteId = (0, import_uuid.v4)();
4182
4874
  const signinUrl = `${akanCloudClientUrl}/signin?remoteId=${remoteId}`;
4183
- Logger.rawLog(import_chalk.default.bold(`
4184
- ${import_chalk.default.green("\u27A4")} Authentication Required`));
4185
- Logger.rawLog(import_chalk.default.dim("Please visit or click the following URL:"));
4186
- Logger.rawLog(import_chalk.default.cyan.underline(signinUrl) + "\n");
4875
+ Logger.rawLog(import_chalk2.default.bold(`
4876
+ ${import_chalk2.default.green("\u27A4")} Authentication Required`));
4877
+ Logger.rawLog(import_chalk2.default.dim("Please visit or click the following URL:"));
4878
+ Logger.rawLog(import_chalk2.default.cyan.underline(signinUrl) + "\n");
4187
4879
  try {
4188
4880
  const qrcode = await new Promise((resolve, reject) => {
4189
4881
  QRcode.toString(signinUrl, { type: "terminal", small: true }, (err, data) => {
@@ -4194,11 +4886,11 @@ ${import_chalk.default.green("\u27A4")} Authentication Required`));
4194
4886
  });
4195
4887
  Logger.rawLog(qrcode);
4196
4888
  await (0, import_open2.default)(signinUrl);
4197
- Logger.rawLog(import_chalk.default.dim("Opening browser..."));
4889
+ Logger.rawLog(import_chalk2.default.dim("Opening browser..."));
4198
4890
  } catch {
4199
- Logger.rawLog(import_chalk.default.yellow("Could not open browser. Please visit the URL manually."));
4891
+ Logger.rawLog(import_chalk2.default.yellow("Could not open browser. Please visit the URL manually."));
4200
4892
  }
4201
- Logger.rawLog(import_chalk.default.dim("Waiting for authentication..."));
4893
+ Logger.rawLog(import_chalk2.default.dim("Waiting for authentication..."));
4202
4894
  const MAX_RETRY = 300;
4203
4895
  for (let i = 0; i < MAX_RETRY; i++) {
4204
4896
  const res = await fetch(`${akanCloudBackendUrl}/user/getRemoteAuthToken/${remoteId}`);
@@ -4206,30 +4898,38 @@ ${import_chalk.default.green("\u27A4")} Authentication Required`));
4206
4898
  const self2 = jwt ? await getSelf(jwt) : null;
4207
4899
  if (jwt && self2) {
4208
4900
  setHostConfig(akanCloudHost, { auth: { token: jwt, self: self2 } });
4209
- Logger.rawLog(import_chalk.default.green(`\r\u2713 Authentication successful!`));
4210
- Logger.rawLog(import_chalk.default.green.bold(`
4901
+ Logger.rawLog(import_chalk2.default.green(`\r\u2713 Authentication successful!`));
4902
+ Logger.rawLog(import_chalk2.default.green.bold(`
4211
4903
  \u2728 Welcome aboard, ${self2.nickname}!`));
4212
- Logger.rawLog(import_chalk.default.dim("You're now ready to use Akan CLI!\n"));
4904
+ Logger.rawLog(import_chalk2.default.dim("You're now ready to use Akan CLI!\n"));
4213
4905
  return true;
4214
4906
  }
4215
4907
  await sleep(2e3);
4216
4908
  }
4217
- throw new Error(import_chalk.default.red("\u2716 Authentication timed out after 10 minutes. Please try again."));
4909
+ throw new Error(import_chalk2.default.red("\u2716 Authentication timed out after 10 minutes. Please try again."));
4218
4910
  }
4219
4911
  logout() {
4220
4912
  const config = getHostConfig();
4221
4913
  if (config.auth) {
4222
4914
  setHostConfig(akanCloudHost, {});
4223
- Logger.rawLog(import_chalk.default.magenta.bold(`
4915
+ Logger.rawLog(import_chalk2.default.magenta.bold(`
4224
4916
  \u{1F44B} Goodbye, ${config.auth.self.nickname}!`));
4225
- Logger.rawLog(import_chalk.default.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\n"));
4226
- Logger.rawLog(import_chalk.default.cyan("You have been successfully logged out."));
4227
- Logger.rawLog(import_chalk.default.dim("Thank you for using Akan CLI. Come back soon! \u{1F31F}\n"));
4917
+ Logger.rawLog(import_chalk2.default.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\n"));
4918
+ Logger.rawLog(import_chalk2.default.cyan("You have been successfully logged out."));
4919
+ Logger.rawLog(import_chalk2.default.dim("Thank you for using Akan CLI. Come back soon! \u{1F31F}\n"));
4228
4920
  } else {
4229
- Logger.rawLog(import_chalk.default.yellow.bold("\n\u26A0\uFE0F No active session found"));
4230
- Logger.rawLog(import_chalk.default.dim("You were not logged in to begin with\n"));
4921
+ Logger.rawLog(import_chalk2.default.yellow.bold("\n\u26A0\uFE0F No active session found"));
4922
+ Logger.rawLog(import_chalk2.default.dim("You were not logged in to begin with\n"));
4231
4923
  }
4232
4924
  }
4925
+ async setLlm() {
4926
+ await AiSession.init({ useExisting: true });
4927
+ Logger.rawLog(import_chalk2.default.green("LLM model set successfully"));
4928
+ }
4929
+ resetLlm() {
4930
+ AiSession.setLlmConfig(null);
4931
+ Logger.rawLog(import_chalk2.default.green("LLM model reset successfully"));
4932
+ }
4233
4933
  async getAkanPkgs(workspace) {
4234
4934
  const pkgs = await workspace.getPkgs();
4235
4935
  const akanPkgs = pkgs.filter((pkg) => pkg.startsWith("@akanjs/"));
@@ -4251,20 +4951,7 @@ ${import_chalk.default.green("\u27A4")} Authentication Required`));
4251
4951
  const newPackageJsonStr = JSON.stringify({ ...packageJson, version: nextVersion }, null, 2);
4252
4952
  workspace.writeFile(`pkgs/${library}/package.json`, newPackageJsonStr);
4253
4953
  const distPackageJson = workspace.readJson(`dist/pkgs/${library}/package.json`);
4254
- const newDistPackageJson = {
4255
- ...distPackageJson,
4256
- // ...(distPackageJson.dependencies
4257
- // ? {
4258
- // dependencies: Object.fromEntries(
4259
- // Object.entries(distPackageJson.dependencies).map(([key, value]) => [
4260
- // key,
4261
- // value.startsWith("^") ? value : `^${value}`,
4262
- // ])
4263
- // ),
4264
- // }
4265
- // : {}),
4266
- version: nextVersion
4267
- };
4954
+ const newDistPackageJson = { ...distPackageJson, version: nextVersion };
4268
4955
  workspace.writeJson(`dist/pkgs/${library}/package.json`, newDistPackageJson);
4269
4956
  }
4270
4957
  const isDeployConfirmed = await (0, import_prompts7.confirm)({
@@ -4295,6 +4982,17 @@ var CloudScript = class {
4295
4982
  logout() {
4296
4983
  this.#runner.logout();
4297
4984
  }
4985
+ async setLlm() {
4986
+ await this.#runner.setLlm();
4987
+ }
4988
+ resetLlm() {
4989
+ this.#runner.resetLlm();
4990
+ }
4991
+ async ask(question) {
4992
+ await AiSession.init();
4993
+ const session = new AiSession();
4994
+ await session.ask(question);
4995
+ }
4298
4996
  async deployAkan(workspace) {
4299
4997
  const akanPkgs = await this.#runner.getAkanPkgs(workspace);
4300
4998
  await Promise.all(
@@ -4313,6 +5011,15 @@ var CloudCommand = class {
4313
5011
  logout() {
4314
5012
  this.cloudScript.logout();
4315
5013
  }
5014
+ async setLlm() {
5015
+ await this.cloudScript.setLlm();
5016
+ }
5017
+ resetLlm() {
5018
+ this.cloudScript.resetLlm();
5019
+ }
5020
+ async ask(question) {
5021
+ await this.cloudScript.ask(question);
5022
+ }
4316
5023
  async deployAkan(workspace) {
4317
5024
  await this.cloudScript.deployAkan(workspace);
4318
5025
  }
@@ -4323,6 +5030,16 @@ __decorateClass([
4323
5030
  __decorateClass([
4324
5031
  Target.Public()
4325
5032
  ], CloudCommand.prototype, "logout", 1);
5033
+ __decorateClass([
5034
+ Target.Public()
5035
+ ], CloudCommand.prototype, "setLlm", 1);
5036
+ __decorateClass([
5037
+ Target.Public()
5038
+ ], CloudCommand.prototype, "resetLlm", 1);
5039
+ __decorateClass([
5040
+ Target.Public(),
5041
+ __decorateParam(0, Option("question", { ask: "question to ask" }))
5042
+ ], CloudCommand.prototype, "ask", 1);
4326
5043
  __decorateClass([
4327
5044
  Target.Public({ devOnly: true }),
4328
5045
  __decorateParam(0, Workspace())
@@ -4335,8 +5052,10 @@ CloudCommand = __decorateClass([
4335
5052
  var LibraryCommand = class {
4336
5053
  libraryScript = new LibraryScript();
4337
5054
  async createLibrary(name, workspace) {
5055
+ await this.libraryScript.createLibrary(name, workspace);
4338
5056
  }
4339
- async removeLibrary(lib, workspace) {
5057
+ async removeLibrary(lib) {
5058
+ await this.libraryScript.removeLibrary(lib);
4340
5059
  }
4341
5060
  async scanLibrary(lib) {
4342
5061
  await this.libraryScript.scanLibrary(lib, true);
@@ -4360,8 +5079,7 @@ __decorateClass([
4360
5079
  ], LibraryCommand.prototype, "createLibrary", 1);
4361
5080
  __decorateClass([
4362
5081
  Target.Public(),
4363
- __decorateParam(0, Lib()),
4364
- __decorateParam(1, Workspace())
5082
+ __decorateParam(0, Lib())
4365
5083
  ], LibraryCommand.prototype, "removeLibrary", 1);
4366
5084
  __decorateClass([
4367
5085
  Target.Public(),
@@ -4390,8 +5108,11 @@ LibraryCommand = __decorateClass([
4390
5108
  Commands()
4391
5109
  ], LibraryCommand);
4392
5110
 
5111
+ // pkgs/@akanjs/cli/src/module/module.script.ts
5112
+ var import_prompts8 = require("@inquirer/prompts");
5113
+ var import_fs12 = __toESM(require("fs"));
5114
+
4393
5115
  // pkgs/@akanjs/cli/src/module/module.runner.ts
4394
- var import_fs14 = __toESM(require("fs"));
4395
5116
  var ModuleRunner = class {
4396
5117
  async createModule(workspace, sysType, sysName, moduleName, description) {
4397
5118
  }
@@ -4469,56 +5190,64 @@ var ModuleRunner = class {
4469
5190
  }
4470
5191
  };
4471
5192
  }
4472
- async createUnit(sys2, modelName) {
4473
- const modelFileData = getModelFileData(sys2.cwdPath, modelName);
4474
- const { paths } = getRelatedCnsts(modelFileData.constantFilePath);
4475
- const names = { model: modelName, Model: capitalize(modelName), LightModel: `Light${capitalize(modelName)}` };
4476
- const prompt = `
4477
-
4478
- \uB108\uB294 React, Typescript, TailwindCSS\uB97C \uAE30\uBC18\uC73C\uB85C \uCF54\uB529\uD558\uB294 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790\uC57C.
4479
- ${names.Model}\uC774\uB77C\uB294 \uB3C4\uBA54\uC778\uC5D0 \uB300\uD574\uC11C ${names.LightModel} \uC2A4\uD0A4\uB9C8\uB97C \uB300\uC0C1\uC73C\uB85C react component\uB97C \uB514\uC790\uC778\uD558\uB824\uACE0 \uD574. \uC544\uB798\uB294 \uD604\uC7AC \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8 \uD615\uD0DC\uC758 \uCEF4\uD3EC\uB10C\uD2B8\uC57C.
4480
-
4481
- \`\`\`
4482
- ${modelFileData.unitFileStr}
4483
- \`\`\`
4484
-
4485
- ${names.LightModel}\uC740 \uB2E4\uC74C\uACFC \uAC19\uC774 ${names.Model} \uC2A4\uD0A4\uB9C8\uC5D0\uC11C \uC77C\uBD80 \uD544\uB4DC\uB97C \uCD94\uCD9C\uD574\uC11C lightweight fetch\uB41C \uD615\uD0DC\uB85C \uC124\uACC4\uB418\uC5B4\uC788\uC5B4.
4486
- \`\`\`
4487
- ${modelFileData.constantFileStr}
4488
- \`\`\`
4489
-
4490
- \uC544\uB798\uB294 \uD604\uC7AC \uC2A4\uD0A4\uB9C8\uC640 \uC5F0\uAD00\uB41C \uC2A4\uD0A4\uB9C8 \uD30C\uC77C\uB4E4\uC774\uC57C. \uC2A4\uD0A4\uB9C8 \uD30C\uC77C\uB4E4\uC758 \uCF54\uB4DC\uB4E4\uC744 \uBCF4\uACE0 \uC11C\uB85C \uC5B4\uB5BB\uAC8C \uC5F0\uACC4 \uB418\uC5B4\uC788\uB294\uC9C0 \uC774\uD574\uD558\uB3C4\uB85D \uD574.
4491
- ${paths ? new Array(paths.size).fill(0).map((_, index) => {
4492
- const key = Array.from(paths.keys())[index];
4493
- const filePath = paths.get(key)?.filePath;
4494
- if (!filePath)
4495
- throw new Error("filePath is undefined");
4496
- return `${key}
4497
- \`\`\`${import_fs14.default.readFileSync(filePath, "utf8")}\`\`\`\`
4498
-
4499
- `;
4500
- }) : ""}
4501
-
4502
- \uCD94\uAC00\uB85C, \uB9CC\uC57D\uC5D0 \uC544\uC774\uCF58 \uC0AC\uC6A9\uC774 \uD544\uC694\uD558\uBA74 react-icons/bi \uB77C\uC774\uBE0C\uB7EC\uB9AC\uC5D0\uC11C \uC0AC\uC6A9\uD574\uC918.
4503
- \uB610, \uC0C9\uC0C1\uC744 \uC0AC\uC6A9\uD558\uB824\uACE0 \uD558\uBA74 \uD558\uB4DC\uCF54\uB529\uB41C \uC0C9\uC0C1(bg-red)\uC774 \uC544\uB2CC \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary)\uC744 \uC0AC\uC6A9\uD574\uC11C \uC791\uC131\uD574\uC918.
4504
- \uADF8\uB9AC\uACE0 optional\uD55C \uD544\uB4DC\uB294 field && <div>... \uAC00 \uC544\uB2CC, field ? <div>... : null \uD615\uD0DC\uB85C \uC791\uC131\uD574\uC918.
4505
- css\uB77C\uC774\uBE0C\uB7EC\uB9AC\uB294 DaisyUI\uB97C \uAE30\uBC18\uC73C\uB85C \uC791\uC131\uD574\uC8FC\uB294\uB370, btn, input, badge\uC640 \uAC19\uC740 \uB2E8\uC21C\uD55C \uAE30\uBCF8 css\uB294 \uC0AC\uC6A9\uD574\uB3C4 \uAD1C\uCC2E\uC544. \uADF8\uB7F0\uB370 card, hero\uAC19\uC774 \uBCF5\uC7A1\uD55C \uCEF4\uD3EC\uB10C\uD2B8\uB294 \uC0AC\uC6A9\uD558\uBA74 \uC548\uB3FC.
4506
- \uC870\uAC74\uBD80 className\uC774 \uD544\uC694\uD55C \uACBD\uC6B0\uC5D0\uB294 clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC\uB97C \uC0AC\uC6A9\uD574\uC11C \uC791\uC131\uD574\uC57C\uD574.
4507
- \uBAA8\uB378\uC5D0 \uB300\uD574\uC11C object destructuring\uC740 \uD558\uC9C0\uB9D0\uACE0 ${modelName}.field \uD615\uD0DC\uB85C \uC811\uADFC\uD558\uAC8C \uCF54\uB4DC\uB97C \uC791\uC131\uD574\uC57C\uD574.
4508
-
4509
- ${names.Model}.Unit.Card\uC758 \uB9AC\uC561\uD2B8 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uB514\uC790\uC778\uD574\uC11C \uC791\uC131\uD574\uC918.
4510
- `;
4511
- try {
4512
- import_fs14.default.writeFileSync("./local/prompt.txt", prompt);
4513
- const { content } = await streamAi(prompt, (chunk) => {
4514
- process.stdout.write(chunk);
4515
- });
4516
- import_fs14.default.writeFileSync("./local/result.txt", content);
4517
- } catch (error) {
4518
- }
4519
- }
4520
- async createView(sys2, modelName) {
4521
- }
5193
+ // async createUnit(sys: App | Lib, modelName: string) {
5194
+ // const modelFileData = getModelFileData(sys.cwdPath, modelName);
5195
+ // const { paths } = getRelatedCnsts(modelFileData.constantFilePath);
5196
+ // const names = { model: modelName, Model: capitalize(modelName), LightModel: `Light${capitalize(modelName)}` };
5197
+ // const prompt = `
5198
+ // 너는 React, Typescript, TailwindCSS를 기반으로 코딩하는 프론트엔드 개발자야.
5199
+ // ${names.Model}이라는 도메인에 대해서 ${names.LightModel} 스키마를 대상으로 react component를 디자인하려고 해. 아래는 현재 보일러플레이트 형태의 컴포넌트야.
5200
+ // \`\`\`
5201
+ // ${modelFileData.unitFileStr}
5202
+ // \`\`\`
5203
+ // ${names.LightModel}은 다음과 같이 ${names.Model} 스키마에서 일부 필드를 추출해서 lightweight fetch된 형태로 설계되어있어.
5204
+ // \`\`\`
5205
+ // ${modelFileData.constantFileStr}
5206
+ // \`\`\`
5207
+ // 아래는 현재 스키마와 연관된 스키마 파일들이야. 스키마 파일들의 코드들을 보고 서로 어떻게 연계 되어있는지 이해하도록 해.
5208
+ // ${
5209
+ // paths
5210
+ // ? new Array(paths.size).fill(0).map((_, index) => {
5211
+ // //순서대로 paths key 추출
5212
+ // const key = Array.from(paths.keys())[index];
5213
+ // const filePath = paths.get(key)?.filePath;
5214
+ // if (!filePath) throw new Error("filePath is undefined");
5215
+ // return `${key}\n\`\`\`${fs.readFileSync(filePath, "utf8")}\`\`\`\`\n\n`;
5216
+ // })
5217
+ // : ""
5218
+ // }
5219
+ // 추가로, 만약에 아이콘 사용이 필요하면 react-icons/bi 라이브러리에서 사용해줘.
5220
+ // 또, 색상을 사용하려고 하면 하드코딩된 색상(bg-red)이 아닌 테마 색상(bg-primary)을 사용해서 작성해줘.
5221
+ // 그리고 optional한 필드는 field && <div>... 가 아닌, field ? <div>... : null 형태로 작성해줘.
5222
+ // css라이브러리는 DaisyUI를 기반으로 작성해주는데, btn, input, badge와 같은 단순한 기본 css는 사용해도 괜찮아. 그런데 card, hero같이 복잡한 컴포넌트는 사용하면 안돼.
5223
+ // 조건부 className이 필요한 경우에는 clsx 라이브러리를 사용해서 작성해야해.
5224
+ // 모델에 대해서 object destructuring은 하지말고 ${modelName}.field 형태로 접근하게 코드를 작성해야해.
5225
+ // ${names.Model}.Unit.Card의 리액트 컴포넌트를 디자인해서 작성해줘.
5226
+ // `;
5227
+ // try {
5228
+ // fs.writeFileSync("./local/prompt.txt", prompt);
5229
+ // const { content } = await streamAi(prompt, (chunk) => {
5230
+ // process.stdout.write(chunk);
5231
+ // });
5232
+ // fs.writeFileSync("./local/result.txt", content);
5233
+ // } catch (error) {
5234
+ // // console.error("Application error:", error);
5235
+ // }
5236
+ // }
5237
+ // async createView(sys: App | Lib, modelName: string) {
5238
+ // const modelFileData = getModelFileData(sys.cwdPath, modelName);
5239
+ // // const modelFileData = getModelFileData(sys.cwdPath, modelName);
5240
+ // // const { paths } = getRelatedCnsts(modelFileData.constantFilePath);
5241
+ // // const names = { model: modelName, Model: capitalize(modelName), LightModel: `Light${capitalize(modelName)}` };
5242
+ // // const prompt = prompt.requestView({
5243
+ // // sysName: sys.name,
5244
+ // // modelName,
5245
+ // // modelDesc: modelFileData.modelDesc,
5246
+ // // modelSchemaDesign: modelFileData.modelSchemaDesign,
5247
+ // // boilerplate: modelFileData.viewFileStr,
5248
+ // // paths,
5249
+ // // });
5250
+ // }
4522
5251
  };
4523
5252
 
4524
5253
  // pkgs/@akanjs/cli/src/module/module.script.ts
@@ -4563,38 +5292,67 @@ var ModuleScript = class {
4563
5292
  }
4564
5293
  async createTest(workspace, name) {
4565
5294
  }
4566
- async createUnit(workspace, type, appOrLibName, modelName) {
4567
- const sys2 = type === "app" ? AppExecutor.from(workspace, appOrLibName) : LibExecutor.from(workspace, appOrLibName);
4568
- await this.#runner.createUnit(sys2, modelName);
5295
+ async createUnit(sys2) {
5296
+ const libs = await sys2.getModules();
5297
+ const unitExampleFiles = await sys2.getUnitsSourceCode();
5298
+ const lib = await (0, import_prompts8.select)({
5299
+ message: "Select the lib",
5300
+ choices: libs
5301
+ }).catch((e) => {
5302
+ Logger.error("canceled");
5303
+ return null;
5304
+ });
5305
+ if (!lib)
5306
+ return;
5307
+ const name = lib.split("/").pop();
5308
+ if (!name)
5309
+ return;
5310
+ const Name = capitalize(name);
5311
+ const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
5312
+ const constant = import_fs12.default.readFileSync(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`, "utf-8");
5313
+ const session = new AiSession();
5314
+ const promptRst = requestView({
5315
+ sysName: sys2.name,
5316
+ modelName: name,
5317
+ ModelName: Name,
5318
+ constant,
5319
+ properties: relatedCnsts.map((r) => ({ key: r.key, source: r.source })),
5320
+ exampleFiles: randomPicks(unitExampleFiles, Math.min(10, unitExampleFiles.length))
5321
+ });
5322
+ const content = await session.editTypescript(promptRst);
5323
+ import_fs12.default.writeFileSync(`${sys2.cwdPath}/prompt.txt`, promptRst);
5324
+ import_fs12.default.writeFileSync(`${sys2.cwdPath}/result.txt`, content);
4569
5325
  }
4570
5326
  async createView(sys2) {
4571
- const [appNames, libNames] = await sys2.workspace.getSyss();
4572
- const viewExampleFiles = [
4573
- ...(await Promise.all(
4574
- appNames.map(async (appName) => {
4575
- const app = AppExecutor.from(sys2.workspace, appName);
4576
- const viewModules = await app.getViewModules();
4577
- return await Promise.all(
4578
- viewModules.map((viewModule) => ({
4579
- path: `${appName}/${viewModule}/${viewModule}.View.tsx`,
4580
- content: app.readFile(`lib/${viewModule}/${viewModule}.View.tsx`)
4581
- }))
4582
- );
4583
- })
4584
- )).flat(),
4585
- ...(await Promise.all(
4586
- libNames.map(async (libName) => {
4587
- const lib = LibExecutor.from(sys2.workspace, libName);
4588
- const viewModules = await lib.getViewModules();
4589
- return await Promise.all(
4590
- viewModules.map((viewModule) => ({
4591
- path: `${libName}/${viewModule}/${viewModule}.View.tsx`,
4592
- content: lib.readFile(`lib/${viewModule}/${viewModule}.View.tsx`)
4593
- }))
4594
- );
4595
- })
4596
- )).flat()
4597
- ];
5327
+ const libs = await sys2.getModules();
5328
+ const lib = await (0, import_prompts8.select)({
5329
+ message: "Select the lib",
5330
+ choices: libs
5331
+ }).catch((e) => {
5332
+ Logger.error("canceled");
5333
+ return null;
5334
+ });
5335
+ if (!lib)
5336
+ return;
5337
+ const name = lib.split("/").pop();
5338
+ if (!name)
5339
+ return;
5340
+ const viewExampleFiles = (await sys2.getViewsSourceCode()).filter((f) => f.filepath.includes(`${name}.View.tsx`));
5341
+ const Name = capitalize(name);
5342
+ const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
5343
+ const constant = import_fs12.default.readFileSync(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`, "utf-8");
5344
+ const session = new AiSession();
5345
+ const promptRst = requestView({
5346
+ sysName: sys2.name,
5347
+ modelName: name,
5348
+ ModelName: Name,
5349
+ constant,
5350
+ properties: relatedCnsts.map((r) => ({ key: r.key, source: r.source })),
5351
+ exampleFiles: randomPicks(viewExampleFiles, Math.min(20, viewExampleFiles.length))
5352
+ });
5353
+ const content = await session.editTypescript(promptRst);
5354
+ import_fs12.default.writeFileSync(`${sys2.cwdPath}/prompt.txt`, promptRst);
5355
+ import_fs12.default.writeFileSync(`${sys2.cwdPath}/result.txt`, content);
4598
5356
  }
4599
5357
  };
4600
5358
 
@@ -4677,7 +5435,8 @@ var PackageCommand = class {
4677
5435
  async createPackage(name, workspace) {
4678
5436
  await this.packageScript.createPackage(workspace, name);
4679
5437
  }
4680
- async removePackage(name, workspace) {
5438
+ async removePackage(pkg) {
5439
+ await this.packageScript.removePackage(pkg);
4681
5440
  }
4682
5441
  async scanPackage(pkg) {
4683
5442
  await this.packageScript.scanPackage(pkg);
@@ -4697,8 +5456,7 @@ __decorateClass([
4697
5456
  ], PackageCommand.prototype, "createPackage", 1);
4698
5457
  __decorateClass([
4699
5458
  Target.Public(),
4700
- __decorateParam(0, Option("name", { desc: "name of package" })),
4701
- __decorateParam(1, Workspace())
5459
+ __decorateParam(0, Pkg())
4702
5460
  ], PackageCommand.prototype, "removePackage", 1);
4703
5461
  __decorateClass([
4704
5462
  Target.Public(),
@@ -4712,13 +5470,13 @@ PackageCommand = __decorateClass([
4712
5470
  Commands()
4713
5471
  ], PackageCommand);
4714
5472
 
4715
- // pkgs/@akanjs/cli/src/package/page/page.runner.ts
5473
+ // pkgs/@akanjs/cli/src/page/page.runner.ts
4716
5474
  var PageRunner = class {
4717
5475
  async createPage(app, name) {
4718
5476
  }
4719
5477
  };
4720
5478
 
4721
- // pkgs/@akanjs/cli/src/package/page/page.script.ts
5479
+ // pkgs/@akanjs/cli/src/page/page.script.ts
4722
5480
  var PageScript = class {
4723
5481
  #runner = new PageRunner();
4724
5482
  async createPage(app, name) {
@@ -4726,7 +5484,7 @@ var PageScript = class {
4726
5484
  }
4727
5485
  };
4728
5486
 
4729
- // pkgs/@akanjs/cli/src/package/page/page.command.ts
5487
+ // pkgs/@akanjs/cli/src/page/page.command.ts
4730
5488
  var PageCommand = class {
4731
5489
  pageScript = new PageScript();
4732
5490
  async createPage(app, name) {
@@ -4868,8 +5626,8 @@ var WorkspaceCommand = class {
4868
5626
  };
4869
5627
  __decorateClass([
4870
5628
  Target.Public(),
4871
- __decorateParam(0, Option("name", { desc: "name of workspace" })),
4872
- __decorateParam(1, Option("app", { desc: "application name" })),
5629
+ __decorateParam(0, Option("name", { desc: "what is the name of your organization?" })),
5630
+ __decorateParam(1, Option("app", { desc: "describe your first application to create." })),
4873
5631
  __decorateParam(2, Option("dir", { desc: "directory of workspace", default: process.env.USE_AKANJS_PKGS === "true" ? "local" : "." }))
4874
5632
  ], WorkspaceCommand.prototype, "createWorkspace", 1);
4875
5633
  __decorateClass([
@@ -4891,7 +5649,6 @@ void runCommands(
4891
5649
  PageCommand,
4892
5650
  CloudCommand
4893
5651
  );
4894
- //!Field.Prop 거르기가 빡세네.
4895
5652
  //! Temp
4896
5653
  //! zip 명령어는 압축시 폴더 경로를 무시하는 게 안됨
4897
5654
  //! 두 가지 방법이 있음
@@ -4900,3 +5657,4 @@ void runCommands(
4900
5657
  //! execSync를 가져오기 싫으니 일단 2번 방법으로 해보자
4901
5658
  //! add path in tsconfig.json
4902
5659
  //! Temporary fix for barrel library
5660
+ //! 파일을 {name}.View.tsx에 저장.