@akanjs/cli 0.0.136 → 0.0.138

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,5 +20,22 @@ akan create-workspace
20
20
  # How to start your project
21
21
 
22
22
  ```bash
23
- cd <workspace-name> && akan start <app-name> --open=true
23
+ cd <workspace-name> && akan start <app-name> --open
24
+ ```
25
+
26
+ you can navigate to default webpage
27
+
28
+ - home: http://localhost:4200
29
+
30
+ # Recipes
31
+
32
+ ```bash
33
+ # set llm model
34
+ akan set-llm
35
+
36
+ # create module
37
+ akan create-module
38
+
39
+ # create scalar with ai (experimental)
40
+ akan create-scalar
24
41
  ```
package/cjs/index.js CHANGED
@@ -914,11 +914,58 @@ var TypeScriptDependencyScanner = class {
914
914
  }
915
915
  };
916
916
 
917
+ // pkgs/@akanjs/devkit/src/spinner.ts
918
+ var import_ora2 = __toESM(require("ora"));
919
+ var Spinner = class {
920
+ spinner;
921
+ stopWatch;
922
+ startAt;
923
+ message;
924
+ constructor(message, { prefix = "", indent = 0 } = {}) {
925
+ this.message = message;
926
+ this.spinner = (0, import_ora2.default)(message);
927
+ this.spinner.prefixText = prefix;
928
+ this.spinner.indent = indent;
929
+ }
930
+ start() {
931
+ this.startAt = /* @__PURE__ */ new Date();
932
+ const spinner = this.spinner.start();
933
+ this.stopWatch = setInterval(() => {
934
+ spinner.text = `${this.message} (${this.#getElapsedTimeStr()})`;
935
+ }, 1e3);
936
+ return this;
937
+ }
938
+ succeed(message) {
939
+ clearInterval(this.stopWatch);
940
+ this.spinner.succeed(`${message} (${this.#getElapsedTimeStr()})`);
941
+ }
942
+ #getElapsedTimeStr() {
943
+ const ms = (/* @__PURE__ */ new Date()).getTime() - this.startAt.getTime();
944
+ if (ms < 1e3)
945
+ return `${ms}ms`;
946
+ const s = Math.floor(ms / 1e3);
947
+ if (s < 60)
948
+ return `${s}s`;
949
+ const m = Math.floor(s / 60);
950
+ return `${m}m ${s % 60}s`;
951
+ }
952
+ };
953
+
917
954
  // pkgs/@akanjs/devkit/src/executors.ts
955
+ var execEmoji = {
956
+ workspace: "\u{1F3E0}",
957
+ app: "\u{1F680}",
958
+ lib: "\u{1F527}",
959
+ pkg: "\u{1F4E6}",
960
+ dist: "\u{1F4BF}",
961
+ default: "\u2708\uFE0F"
962
+ // for sys executor
963
+ };
918
964
  var Executor = class {
919
965
  name;
920
966
  logger;
921
967
  cwdPath;
968
+ emoji = execEmoji.default;
922
969
  constructor(name, cwdPath) {
923
970
  this.name = name;
924
971
  this.logger = new Logger(name);
@@ -1045,6 +1092,9 @@ var Executor = class {
1045
1092
  this.logger.verbose(msg);
1046
1093
  return this;
1047
1094
  }
1095
+ spinning(msg, { prefix = `${this.emoji}${this.name} -`, indent = 0 } = {}) {
1096
+ return new Spinner(msg, { prefix, indent }).start();
1097
+ }
1048
1098
  getTsConfig(pathname = "tsconfig.json") {
1049
1099
  const tsconfig = this.readJson(pathname);
1050
1100
  if (tsconfig.extends) {
@@ -1076,7 +1126,7 @@ var Executor = class {
1076
1126
  `${dirname}/${filename}`
1077
1127
  );
1078
1128
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
1079
- this.writeFile(convertedTargetPath, content);
1129
+ this.writeFile(convertedTargetPath, content, { overwrite });
1080
1130
  } else if (targetPath.endsWith(".template")) {
1081
1131
  const content = await import_promises.default.readFile(templatePath, "utf8");
1082
1132
  const convertedTargetPath = Object.entries(dict).reduce(
@@ -1088,7 +1138,7 @@ var Executor = class {
1088
1138
  content
1089
1139
  );
1090
1140
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
1091
- this.writeFile(convertedTargetPath, convertedContent);
1141
+ this.writeFile(convertedTargetPath, convertedContent, { overwrite });
1092
1142
  }
1093
1143
  }
1094
1144
  async applyTemplate({
@@ -1131,8 +1181,9 @@ var Executor = class {
1131
1181
  var WorkspaceExecutor = class _WorkspaceExecutor extends Executor {
1132
1182
  workspaceRoot;
1133
1183
  repoName;
1184
+ emoji = execEmoji.workspace;
1134
1185
  constructor({ workspaceRoot, repoName }) {
1135
- super(`${repoName} Executor`, workspaceRoot);
1186
+ super("workspace", workspaceRoot);
1136
1187
  this.workspaceRoot = workspaceRoot;
1137
1188
  this.repoName = repoName;
1138
1189
  }
@@ -1287,11 +1338,13 @@ var SysExecutor = class extends Executor {
1287
1338
  workspace;
1288
1339
  name;
1289
1340
  type;
1341
+ emoji;
1290
1342
  constructor({ workspace = WorkspaceExecutor.fromRoot(), name, type }) {
1291
- super(`${name} Sys Executor`, `${workspace.workspaceRoot}/${type}s/${name}`);
1343
+ super(name, `${workspace.workspaceRoot}/${type}s/${name}`);
1292
1344
  this.workspace = workspace;
1293
1345
  this.name = name;
1294
1346
  this.type = type;
1347
+ this.emoji = execEmoji[type];
1295
1348
  }
1296
1349
  async getConfig(command) {
1297
1350
  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 });
@@ -1512,9 +1565,10 @@ var SysExecutor = class extends Executor {
1512
1565
  };
1513
1566
  var AppExecutor = class _AppExecutor extends SysExecutor {
1514
1567
  dist;
1568
+ emoji = execEmoji.app;
1515
1569
  constructor({ workspace, name }) {
1516
1570
  super({ workspace, name, type: "app" });
1517
- this.dist = new Executor(`${name} Dist App Executor`, `${this.workspace.workspaceRoot}/dist/apps/${name}`);
1571
+ this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/apps/${name}`);
1518
1572
  }
1519
1573
  static from(executor, name) {
1520
1574
  if (executor instanceof WorkspaceExecutor)
@@ -1548,9 +1602,10 @@ var LibExecutor = class _LibExecutor extends SysExecutor {
1548
1602
  workspaceRoot;
1549
1603
  repoName;
1550
1604
  dist;
1605
+ emoji = execEmoji.lib;
1551
1606
  constructor({ workspace, name }) {
1552
1607
  super({ workspace, name, type: "lib" });
1553
- this.dist = new Executor(`${name} Dist Lib Executor`, `${this.workspace.workspaceRoot}/dist/libs/${name}`);
1608
+ this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/libs/${name}`);
1554
1609
  }
1555
1610
  static from(executor, name) {
1556
1611
  if (executor instanceof WorkspaceExecutor)
@@ -1570,11 +1625,12 @@ var PkgExecutor = class _PkgExecutor extends Executor {
1570
1625
  workspace;
1571
1626
  name;
1572
1627
  dist;
1628
+ emoji = execEmoji.pkg;
1573
1629
  constructor({ workspace = WorkspaceExecutor.fromRoot(), name }) {
1574
- super(`${name} Pkg Executor`, `${workspace.workspaceRoot}/pkgs/${name}`);
1630
+ super(name, `${workspace.workspaceRoot}/pkgs/${name}`);
1575
1631
  this.workspace = workspace;
1576
1632
  this.name = name;
1577
- this.dist = new Executor(`${name} Dist Pkg Executor`, `${this.workspace.workspaceRoot}/dist/pkgs/${name}`);
1633
+ this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/pkgs/${name}`);
1578
1634
  }
1579
1635
  static from(executor, name) {
1580
1636
  if (executor instanceof WorkspaceExecutor)
@@ -2177,6 +2233,7 @@ var import_prompts4 = require("@inquirer/prompts");
2177
2233
  var import_messages = require("@langchain/core/messages");
2178
2234
  var import_openai2 = require("@langchain/openai");
2179
2235
  var import_chalk3 = __toESM(require("chalk"));
2236
+ var import_ora3 = __toESM(require("ora"));
2180
2237
  var MAX_ASK_TRY = 300;
2181
2238
  var supportedLlmModels = ["deepseek-chat", "deepseek-reasoner"];
2182
2239
  var AiSession = class _AiSession {
@@ -2247,23 +2304,28 @@ var AiSession = class _AiSession {
2247
2304
  await _AiSession.init();
2248
2305
  if (!_AiSession.#chat)
2249
2306
  throw new Error("Failed to initialize the AI session");
2307
+ const loader = (0, import_ora3.default)(`${_AiSession.#chat.model} is thinking...`).start();
2250
2308
  try {
2251
2309
  const humanMessage = new import_messages.HumanMessage(question);
2252
2310
  this.messageHistory.push(humanMessage);
2253
2311
  const stream = await _AiSession.#chat.stream(this.messageHistory);
2254
- let fullResponse = "";
2312
+ let fullResponse = "", tokenIdx = 0;
2255
2313
  for await (const chunk of stream) {
2314
+ if (loader.isSpinning)
2315
+ loader.succeed(`${_AiSession.#chat.model} responded`);
2256
2316
  const content = chunk.content;
2257
2317
  if (typeof content === "string") {
2258
2318
  fullResponse += content;
2259
2319
  onChunk(content);
2260
2320
  }
2321
+ tokenIdx++;
2261
2322
  }
2262
2323
  fullResponse += "\n";
2263
2324
  onChunk("\n");
2264
2325
  this.messageHistory.push(new import_messages.AIMessage(fullResponse));
2265
2326
  return { content: fullResponse, messageHistory: this.messageHistory };
2266
2327
  } catch (error) {
2328
+ loader.fail(`${_AiSession.#chat.model} failed to respond`);
2267
2329
  throw new Error("Failed to stream response");
2268
2330
  }
2269
2331
  }
@@ -2517,7 +2579,7 @@ var import_fs9 = __toESM(require("fs"));
2517
2579
  var import_promises2 = __toESM(require("fs/promises"));
2518
2580
  var import_js_yaml2 = __toESM(require("js-yaml"));
2519
2581
  var import_open = __toESM(require("open"));
2520
- var import_ora2 = __toESM(require("ora"));
2582
+ var import_ora4 = __toESM(require("ora"));
2521
2583
  var import_path4 = __toESM(require("path"));
2522
2584
  var vite = __toESM(require("vite"));
2523
2585
  var import_vite_plugin_commonjs = __toESM(require("vite-plugin-commonjs"));
@@ -4509,7 +4571,7 @@ var ApplicationRunner = class {
4509
4571
  async buildFrontend(app) {
4510
4572
  const { env } = await this.#prepareCommand(app, "build", "frontend");
4511
4573
  const akanConfig = await app.getConfig("build");
4512
- await app.spawn("npx", ["next", "build", "--no-lint"], { env });
4574
+ await app.spawn("npx", ["next", "build", "--no-lint"], { env, stdio: "ignore" });
4513
4575
  const buildResult = await esbuild2.build({
4514
4576
  entryPoints: [`${app.cwdPath}/next.config.ts`],
4515
4577
  outdir: `${app.dist.cwdPath}/frontend`,
@@ -4530,9 +4592,7 @@ var ApplicationRunner = class {
4530
4592
  version: "1.0.0",
4531
4593
  engines: { node: ">=22" },
4532
4594
  dependencies,
4533
- scripts: {
4534
- start: "next start"
4535
- }
4595
+ scripts: { start: "next start" }
4536
4596
  };
4537
4597
  app.dist.writeJson("frontend/package.json", appPackageJson);
4538
4598
  await Promise.all([
@@ -4697,10 +4757,13 @@ var ApplicationRunner = class {
4697
4757
  dict: { repoName: workspace.repoName },
4698
4758
  overwrite: false
4699
4759
  });
4700
- await workspace.spawn(`docker`, ["compose", "up", "-d"], { cwd: `${workspace.workspaceRoot}/local` });
4760
+ await workspace.spawn(`docker`, ["compose", "up", "-d"], {
4761
+ cwd: `${workspace.workspaceRoot}/local`,
4762
+ stdio: "ignore"
4763
+ });
4701
4764
  }
4702
4765
  async dbdown(workspace) {
4703
- await workspace.spawn(`docker`, ["compose", "down"], { cwd: `${workspace.workspaceRoot}/local` });
4766
+ await workspace.spawn(`docker`, ["compose", "down"], { cwd: `${workspace.workspaceRoot}/local`, stdio: "ignore" });
4704
4767
  }
4705
4768
  async configureApp(app) {
4706
4769
  const capacitorApp = new CapacitorApp(app);
@@ -4860,7 +4923,7 @@ var ApplicationRunner = class {
4860
4923
  const chatModel = new import_openai3.ChatOpenAI({ modelName: "gpt-4o", openAIApiKey });
4861
4924
  const projectName = await (0, import_prompts5.input)({ message: "please enter project name." });
4862
4925
  const projectDesc = await (0, import_prompts5.input)({ message: "please enter project description. (40 ~ 60 characters)" });
4863
- const spinner = (0, import_ora2.default)("Gerating project files...");
4926
+ const spinner = (0, import_ora4.default)("Gerating project files...");
4864
4927
  const mainPrompt = import_prompts6.PromptTemplate.fromTemplate(requestApplication());
4865
4928
  const chain = import_runnables2.RunnableSequence.from([mainPrompt, chatModel, new import_output_parsers.StringOutputParser()]);
4866
4929
  const resultOne = await chain.invoke({ projectName, projectDesc });
@@ -4907,16 +4970,13 @@ var ApplicationScript = class {
4907
4970
  async removeApplication(app) {
4908
4971
  await this.#runner.removeApplication(app);
4909
4972
  }
4910
- async scanApplication(app, verbose = false) {
4973
+ async syncApplication(app, verbose = false) {
4974
+ const spinner = app.spinning("Scanning application...");
4911
4975
  const akanConfig = await this.#runner.getConfig(app);
4912
4976
  const scanResult = await this.#runner.scanSync(app, akanConfig);
4913
4977
  if (verbose)
4914
4978
  app.logger.rawLog(JSON.stringify(scanResult, null, 2));
4915
- return scanResult;
4916
- }
4917
- async syncApplication(app) {
4918
- const akanConfig = await this.#runner.getConfig(app);
4919
- const scanResult = await this.#runner.scanSync(app, akanConfig);
4979
+ spinner.succeed("Application scanned");
4920
4980
  return scanResult;
4921
4981
  }
4922
4982
  async build(app) {
@@ -4932,7 +4992,9 @@ var ApplicationScript = class {
4932
4992
  async buildBackend(app, { sync = true } = {}) {
4933
4993
  if (sync)
4934
4994
  await this.syncApplication(app);
4995
+ const spinner = app.spinning("Building backend...");
4935
4996
  await this.#runner.buildBackend(app);
4997
+ spinner.succeed(`Successfully built in dist/apps/${app.name}/backend`);
4936
4998
  }
4937
4999
  async startBackend(app, { open: open2 = false, sync = true } = {}) {
4938
5000
  if (sync)
@@ -4942,7 +5004,9 @@ var ApplicationScript = class {
4942
5004
  async buildFrontend(app, { sync = true } = {}) {
4943
5005
  if (sync)
4944
5006
  await this.syncApplication(app);
5007
+ const spinner = app.spinning("Building frontend...");
4945
5008
  await this.#runner.buildFrontend(app);
5009
+ spinner.succeed(`Successfully built in dist/apps/${app.name}/frontend`);
4946
5010
  }
4947
5011
  async startFrontend(app, { open: open2 = false, turbo = false, sync = true } = {}) {
4948
5012
  if (sync)
@@ -4952,7 +5016,9 @@ var ApplicationScript = class {
4952
5016
  async buildCsr(app, { sync = true } = {}) {
4953
5017
  if (sync)
4954
5018
  await this.syncApplication(app);
5019
+ const spinner = app.spinning("Building CSR...");
4955
5020
  await this.#runner.buildCsr(app);
5021
+ spinner.succeed(`Successfully built in dist/apps/${app.name}/csr`);
4956
5022
  }
4957
5023
  async startCsr(app, { open: open2 = false, sync = true } = {}) {
4958
5024
  if (sync)
@@ -5016,10 +5082,16 @@ var ApplicationScript = class {
5016
5082
  await this.#runner.releaseSource(app, options);
5017
5083
  }
5018
5084
  async dbup(workspace) {
5085
+ const spinner = workspace.spinning("Starting local database...");
5019
5086
  await this.#runner.dbup(workspace);
5087
+ spinner.succeed(
5088
+ "Local database(/local/docker-compose.yaml) is up, you can start your application and connect to the database"
5089
+ );
5020
5090
  }
5021
5091
  async dbdown(workspace) {
5092
+ const spinner = workspace.spinning("Stopping local database...");
5022
5093
  await this.#runner.dbdown(workspace);
5094
+ spinner.succeed("Local database(/local/docker-compose.yaml) is down");
5023
5095
  }
5024
5096
  async testSys(sys2) {
5025
5097
  if (sys2.type === "app")
@@ -5036,13 +5108,13 @@ var ApplicationScript = class {
5036
5108
  var ApplicationCommand = class {
5037
5109
  applicationScript = new ApplicationScript();
5038
5110
  async createApplication(name, start, workspace) {
5039
- await this.applicationScript.createApplication(name, workspace, { start });
5111
+ await this.applicationScript.createApplication(name.toLowerCase().replace(/ /g, "-"), workspace, { start });
5040
5112
  }
5041
5113
  async removeApplication(app) {
5042
5114
  await this.applicationScript.removeApplication(app);
5043
5115
  }
5044
- async scanApplication(app) {
5045
- await this.applicationScript.scanApplication(app, true);
5116
+ async syncApplication(app, verbose) {
5117
+ await this.applicationScript.syncApplication(app, verbose);
5046
5118
  }
5047
5119
  async build(app) {
5048
5120
  await this.applicationScript.build(app);
@@ -5123,8 +5195,9 @@ __decorateClass([
5123
5195
  ], ApplicationCommand.prototype, "removeApplication", 1);
5124
5196
  __decorateClass([
5125
5197
  Target.Public(),
5126
- __decorateParam(0, App())
5127
- ], ApplicationCommand.prototype, "scanApplication", 1);
5198
+ __decorateParam(0, App()),
5199
+ __decorateParam(1, Option("verbose", { type: "boolean", desc: "verbose", default: false }))
5200
+ ], ApplicationCommand.prototype, "syncApplication", 1);
5128
5201
  __decorateClass([
5129
5202
  Target.Public({ short: true }),
5130
5203
  __decorateParam(0, App())
@@ -5535,7 +5608,7 @@ CloudCommand = __decorateClass([
5535
5608
  var LibraryCommand = class {
5536
5609
  libraryScript = new LibraryScript();
5537
5610
  async createLibrary(name, workspace) {
5538
- await this.libraryScript.createLibrary(name, workspace);
5611
+ await this.libraryScript.createLibrary(name.toLowerCase().replace(/ /g, "-"), workspace);
5539
5612
  }
5540
5613
  async removeLibrary(lib) {
5541
5614
  await this.libraryScript.removeLibrary(lib);
@@ -5604,11 +5677,19 @@ var ModuleRunner = class {
5604
5677
  async createScalarTemplate(sys2, name) {
5605
5678
  const akanConfig = await sys2.getConfig();
5606
5679
  const scanResult = await sys2.scan({ akanConfig });
5680
+ const names = (0, import_pluralize.default)(name);
5607
5681
  await sys2.applyTemplate({
5608
5682
  basePath: "./lib/__scalar",
5609
5683
  template: "__scalar",
5610
5684
  scanResult,
5611
- dict: { model: name, Model: capitalize(name), sysName: sys2.name, SysName: capitalize(sys2.name) }
5685
+ dict: {
5686
+ model: name,
5687
+ Model: capitalize(name),
5688
+ models: names,
5689
+ Models: capitalize(names),
5690
+ sysName: sys2.name,
5691
+ SysName: capitalize(sys2.name)
5692
+ }
5612
5693
  });
5613
5694
  await sys2.scan({ akanConfig });
5614
5695
  return {
@@ -5647,11 +5728,19 @@ var ModuleRunner = class {
5647
5728
  async createModuleTemplate(sys2, name) {
5648
5729
  const akanConfig = await sys2.getConfig();
5649
5730
  const scanResult = await sys2.scan({ akanConfig });
5731
+ const names = (0, import_pluralize.default)(name);
5650
5732
  await sys2.applyTemplate({
5651
5733
  basePath: `./lib/${name}`,
5652
5734
  template: "module",
5653
5735
  scanResult,
5654
- dict: { model: name, Model: capitalize(name), sysName: sys2.name, SysName: capitalize(sys2.name) }
5736
+ dict: {
5737
+ model: name,
5738
+ Model: capitalize(name),
5739
+ models: names,
5740
+ Models: capitalize(names),
5741
+ sysName: sys2.name,
5742
+ SysName: capitalize(sys2.name)
5743
+ }
5655
5744
  });
5656
5745
  await sys2.scan({ akanConfig });
5657
5746
  return {
@@ -5944,7 +6033,7 @@ var PackageCommand = class {
5944
6033
  await this.packageScript.version(workspace);
5945
6034
  }
5946
6035
  async createPackage(name, workspace) {
5947
- await this.packageScript.createPackage(workspace, name);
6036
+ await this.packageScript.createPackage(workspace, name.toLowerCase().replace(/ /g, "-"));
5948
6037
  }
5949
6038
  async removePackage(pkg) {
5950
6039
  await this.packageScript.removePackage(pkg);
@@ -6154,7 +6243,7 @@ var WorkspaceScript = class {
6154
6243
  var WorkspaceCommand = class {
6155
6244
  workspaceScript = new WorkspaceScript();
6156
6245
  async createWorkspace(name, app, dir) {
6157
- await this.workspaceScript.createWorkspace(name, app, dir);
6246
+ await this.workspaceScript.createWorkspace(name, app.toLowerCase().replace(/ /g, "-"), dir);
6158
6247
  }
6159
6248
  async generateMongo(workspace) {
6160
6249
  await this.workspaceScript.generateMongo(workspace);
@@ -26,6 +26,7 @@ function getContent(scanResult, dict) {
26
26
  return {
27
27
  filename: "layout.tsx",
28
28
  content: `
29
+ import "../(${dict.appName})/styles.css";
29
30
  import { System } from "@shared/ui";
30
31
  import { env } from "@${dict.appName}/env/env.client";
31
32
  import { fetch } from "@${dict.appName}/client";
@@ -20,6 +20,7 @@
20
20
  "jiti": "^2.4.2",
21
21
  "os-browserify": "^0.3.0",
22
22
  "prettier": "^3.5.3",
23
+ "prettier-plugin-tailwindcss": "^0.6.11",
23
24
  "process": "^0.11.10",
24
25
  "stream-browserify": "^3.0.0",
25
26
  "stream-http": "^3.2.0",
package/esm/index.js CHANGED
@@ -901,11 +901,58 @@ var TypeScriptDependencyScanner = class {
901
901
  }
902
902
  };
903
903
 
904
+ // pkgs/@akanjs/devkit/src/spinner.ts
905
+ import ora2 from "ora";
906
+ var Spinner = class {
907
+ spinner;
908
+ stopWatch;
909
+ startAt;
910
+ message;
911
+ constructor(message, { prefix = "", indent = 0 } = {}) {
912
+ this.message = message;
913
+ this.spinner = ora2(message);
914
+ this.spinner.prefixText = prefix;
915
+ this.spinner.indent = indent;
916
+ }
917
+ start() {
918
+ this.startAt = /* @__PURE__ */ new Date();
919
+ const spinner = this.spinner.start();
920
+ this.stopWatch = setInterval(() => {
921
+ spinner.text = `${this.message} (${this.#getElapsedTimeStr()})`;
922
+ }, 1e3);
923
+ return this;
924
+ }
925
+ succeed(message) {
926
+ clearInterval(this.stopWatch);
927
+ this.spinner.succeed(`${message} (${this.#getElapsedTimeStr()})`);
928
+ }
929
+ #getElapsedTimeStr() {
930
+ const ms = (/* @__PURE__ */ new Date()).getTime() - this.startAt.getTime();
931
+ if (ms < 1e3)
932
+ return `${ms}ms`;
933
+ const s = Math.floor(ms / 1e3);
934
+ if (s < 60)
935
+ return `${s}s`;
936
+ const m = Math.floor(s / 60);
937
+ return `${m}m ${s % 60}s`;
938
+ }
939
+ };
940
+
904
941
  // pkgs/@akanjs/devkit/src/executors.ts
942
+ var execEmoji = {
943
+ workspace: "\u{1F3E0}",
944
+ app: "\u{1F680}",
945
+ lib: "\u{1F527}",
946
+ pkg: "\u{1F4E6}",
947
+ dist: "\u{1F4BF}",
948
+ default: "\u2708\uFE0F"
949
+ // for sys executor
950
+ };
905
951
  var Executor = class {
906
952
  name;
907
953
  logger;
908
954
  cwdPath;
955
+ emoji = execEmoji.default;
909
956
  constructor(name, cwdPath) {
910
957
  this.name = name;
911
958
  this.logger = new Logger(name);
@@ -1032,6 +1079,9 @@ var Executor = class {
1032
1079
  this.logger.verbose(msg);
1033
1080
  return this;
1034
1081
  }
1082
+ spinning(msg, { prefix = `${this.emoji}${this.name} -`, indent = 0 } = {}) {
1083
+ return new Spinner(msg, { prefix, indent }).start();
1084
+ }
1035
1085
  getTsConfig(pathname = "tsconfig.json") {
1036
1086
  const tsconfig = this.readJson(pathname);
1037
1087
  if (tsconfig.extends) {
@@ -1063,7 +1113,7 @@ var Executor = class {
1063
1113
  `${dirname}/${filename}`
1064
1114
  );
1065
1115
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
1066
- this.writeFile(convertedTargetPath, content);
1116
+ this.writeFile(convertedTargetPath, content, { overwrite });
1067
1117
  } else if (targetPath.endsWith(".template")) {
1068
1118
  const content = await fsPromise.readFile(templatePath, "utf8");
1069
1119
  const convertedTargetPath = Object.entries(dict).reduce(
@@ -1075,7 +1125,7 @@ var Executor = class {
1075
1125
  content
1076
1126
  );
1077
1127
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
1078
- this.writeFile(convertedTargetPath, convertedContent);
1128
+ this.writeFile(convertedTargetPath, convertedContent, { overwrite });
1079
1129
  }
1080
1130
  }
1081
1131
  async applyTemplate({
@@ -1118,8 +1168,9 @@ var Executor = class {
1118
1168
  var WorkspaceExecutor = class _WorkspaceExecutor extends Executor {
1119
1169
  workspaceRoot;
1120
1170
  repoName;
1171
+ emoji = execEmoji.workspace;
1121
1172
  constructor({ workspaceRoot, repoName }) {
1122
- super(`${repoName} Executor`, workspaceRoot);
1173
+ super("workspace", workspaceRoot);
1123
1174
  this.workspaceRoot = workspaceRoot;
1124
1175
  this.repoName = repoName;
1125
1176
  }
@@ -1274,11 +1325,13 @@ var SysExecutor = class extends Executor {
1274
1325
  workspace;
1275
1326
  name;
1276
1327
  type;
1328
+ emoji;
1277
1329
  constructor({ workspace = WorkspaceExecutor.fromRoot(), name, type }) {
1278
- super(`${name} Sys Executor`, `${workspace.workspaceRoot}/${type}s/${name}`);
1330
+ super(name, `${workspace.workspaceRoot}/${type}s/${name}`);
1279
1331
  this.workspace = workspace;
1280
1332
  this.name = name;
1281
1333
  this.type = type;
1334
+ this.emoji = execEmoji[type];
1282
1335
  }
1283
1336
  async getConfig(command) {
1284
1337
  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 });
@@ -1499,9 +1552,10 @@ var SysExecutor = class extends Executor {
1499
1552
  };
1500
1553
  var AppExecutor = class _AppExecutor extends SysExecutor {
1501
1554
  dist;
1555
+ emoji = execEmoji.app;
1502
1556
  constructor({ workspace, name }) {
1503
1557
  super({ workspace, name, type: "app" });
1504
- this.dist = new Executor(`${name} Dist App Executor`, `${this.workspace.workspaceRoot}/dist/apps/${name}`);
1558
+ this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/apps/${name}`);
1505
1559
  }
1506
1560
  static from(executor, name) {
1507
1561
  if (executor instanceof WorkspaceExecutor)
@@ -1535,9 +1589,10 @@ var LibExecutor = class _LibExecutor extends SysExecutor {
1535
1589
  workspaceRoot;
1536
1590
  repoName;
1537
1591
  dist;
1592
+ emoji = execEmoji.lib;
1538
1593
  constructor({ workspace, name }) {
1539
1594
  super({ workspace, name, type: "lib" });
1540
- this.dist = new Executor(`${name} Dist Lib Executor`, `${this.workspace.workspaceRoot}/dist/libs/${name}`);
1595
+ this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/libs/${name}`);
1541
1596
  }
1542
1597
  static from(executor, name) {
1543
1598
  if (executor instanceof WorkspaceExecutor)
@@ -1557,11 +1612,12 @@ var PkgExecutor = class _PkgExecutor extends Executor {
1557
1612
  workspace;
1558
1613
  name;
1559
1614
  dist;
1615
+ emoji = execEmoji.pkg;
1560
1616
  constructor({ workspace = WorkspaceExecutor.fromRoot(), name }) {
1561
- super(`${name} Pkg Executor`, `${workspace.workspaceRoot}/pkgs/${name}`);
1617
+ super(name, `${workspace.workspaceRoot}/pkgs/${name}`);
1562
1618
  this.workspace = workspace;
1563
1619
  this.name = name;
1564
- this.dist = new Executor(`${name} Dist Pkg Executor`, `${this.workspace.workspaceRoot}/dist/pkgs/${name}`);
1620
+ this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/pkgs/${name}`);
1565
1621
  }
1566
1622
  static from(executor, name) {
1567
1623
  if (executor instanceof WorkspaceExecutor)
@@ -2164,6 +2220,7 @@ import { input as input2, select as select3 } from "@inquirer/prompts";
2164
2220
  import { AIMessage, HumanMessage } from "@langchain/core/messages";
2165
2221
  import { ChatOpenAI as ChatOpenAI2 } from "@langchain/openai";
2166
2222
  import chalk3 from "chalk";
2223
+ import ora3 from "ora";
2167
2224
  var MAX_ASK_TRY = 300;
2168
2225
  var supportedLlmModels = ["deepseek-chat", "deepseek-reasoner"];
2169
2226
  var AiSession = class _AiSession {
@@ -2234,23 +2291,28 @@ var AiSession = class _AiSession {
2234
2291
  await _AiSession.init();
2235
2292
  if (!_AiSession.#chat)
2236
2293
  throw new Error("Failed to initialize the AI session");
2294
+ const loader = ora3(`${_AiSession.#chat.model} is thinking...`).start();
2237
2295
  try {
2238
2296
  const humanMessage = new HumanMessage(question);
2239
2297
  this.messageHistory.push(humanMessage);
2240
2298
  const stream = await _AiSession.#chat.stream(this.messageHistory);
2241
- let fullResponse = "";
2299
+ let fullResponse = "", tokenIdx = 0;
2242
2300
  for await (const chunk of stream) {
2301
+ if (loader.isSpinning)
2302
+ loader.succeed(`${_AiSession.#chat.model} responded`);
2243
2303
  const content = chunk.content;
2244
2304
  if (typeof content === "string") {
2245
2305
  fullResponse += content;
2246
2306
  onChunk(content);
2247
2307
  }
2308
+ tokenIdx++;
2248
2309
  }
2249
2310
  fullResponse += "\n";
2250
2311
  onChunk("\n");
2251
2312
  this.messageHistory.push(new AIMessage(fullResponse));
2252
2313
  return { content: fullResponse, messageHistory: this.messageHistory };
2253
2314
  } catch (error) {
2315
+ loader.fail(`${_AiSession.#chat.model} failed to respond`);
2254
2316
  throw new Error("Failed to stream response");
2255
2317
  }
2256
2318
  }
@@ -2504,7 +2566,7 @@ import fs11 from "fs";
2504
2566
  import fsPromise2 from "fs/promises";
2505
2567
  import yaml2 from "js-yaml";
2506
2568
  import openBrowser from "open";
2507
- import ora2 from "ora";
2569
+ import ora4 from "ora";
2508
2570
  import path5 from "path";
2509
2571
  import * as vite from "vite";
2510
2572
  import commonjs from "vite-plugin-commonjs";
@@ -4496,7 +4558,7 @@ var ApplicationRunner = class {
4496
4558
  async buildFrontend(app) {
4497
4559
  const { env } = await this.#prepareCommand(app, "build", "frontend");
4498
4560
  const akanConfig = await app.getConfig("build");
4499
- await app.spawn("npx", ["next", "build", "--no-lint"], { env });
4561
+ await app.spawn("npx", ["next", "build", "--no-lint"], { env, stdio: "ignore" });
4500
4562
  const buildResult = await esbuild2.build({
4501
4563
  entryPoints: [`${app.cwdPath}/next.config.ts`],
4502
4564
  outdir: `${app.dist.cwdPath}/frontend`,
@@ -4517,9 +4579,7 @@ var ApplicationRunner = class {
4517
4579
  version: "1.0.0",
4518
4580
  engines: { node: ">=22" },
4519
4581
  dependencies,
4520
- scripts: {
4521
- start: "next start"
4522
- }
4582
+ scripts: { start: "next start" }
4523
4583
  };
4524
4584
  app.dist.writeJson("frontend/package.json", appPackageJson);
4525
4585
  await Promise.all([
@@ -4684,10 +4744,13 @@ var ApplicationRunner = class {
4684
4744
  dict: { repoName: workspace.repoName },
4685
4745
  overwrite: false
4686
4746
  });
4687
- await workspace.spawn(`docker`, ["compose", "up", "-d"], { cwd: `${workspace.workspaceRoot}/local` });
4747
+ await workspace.spawn(`docker`, ["compose", "up", "-d"], {
4748
+ cwd: `${workspace.workspaceRoot}/local`,
4749
+ stdio: "ignore"
4750
+ });
4688
4751
  }
4689
4752
  async dbdown(workspace) {
4690
- await workspace.spawn(`docker`, ["compose", "down"], { cwd: `${workspace.workspaceRoot}/local` });
4753
+ await workspace.spawn(`docker`, ["compose", "down"], { cwd: `${workspace.workspaceRoot}/local`, stdio: "ignore" });
4691
4754
  }
4692
4755
  async configureApp(app) {
4693
4756
  const capacitorApp = new CapacitorApp(app);
@@ -4847,7 +4910,7 @@ var ApplicationRunner = class {
4847
4910
  const chatModel = new ChatOpenAI3({ modelName: "gpt-4o", openAIApiKey });
4848
4911
  const projectName = await input3({ message: "please enter project name." });
4849
4912
  const projectDesc = await input3({ message: "please enter project description. (40 ~ 60 characters)" });
4850
- const spinner = ora2("Gerating project files...");
4913
+ const spinner = ora4("Gerating project files...");
4851
4914
  const mainPrompt = PromptTemplate2.fromTemplate(requestApplication());
4852
4915
  const chain = RunnableSequence2.from([mainPrompt, chatModel, new StringOutputParser()]);
4853
4916
  const resultOne = await chain.invoke({ projectName, projectDesc });
@@ -4894,16 +4957,13 @@ var ApplicationScript = class {
4894
4957
  async removeApplication(app) {
4895
4958
  await this.#runner.removeApplication(app);
4896
4959
  }
4897
- async scanApplication(app, verbose = false) {
4960
+ async syncApplication(app, verbose = false) {
4961
+ const spinner = app.spinning("Scanning application...");
4898
4962
  const akanConfig = await this.#runner.getConfig(app);
4899
4963
  const scanResult = await this.#runner.scanSync(app, akanConfig);
4900
4964
  if (verbose)
4901
4965
  app.logger.rawLog(JSON.stringify(scanResult, null, 2));
4902
- return scanResult;
4903
- }
4904
- async syncApplication(app) {
4905
- const akanConfig = await this.#runner.getConfig(app);
4906
- const scanResult = await this.#runner.scanSync(app, akanConfig);
4966
+ spinner.succeed("Application scanned");
4907
4967
  return scanResult;
4908
4968
  }
4909
4969
  async build(app) {
@@ -4919,7 +4979,9 @@ var ApplicationScript = class {
4919
4979
  async buildBackend(app, { sync = true } = {}) {
4920
4980
  if (sync)
4921
4981
  await this.syncApplication(app);
4982
+ const spinner = app.spinning("Building backend...");
4922
4983
  await this.#runner.buildBackend(app);
4984
+ spinner.succeed(`Successfully built in dist/apps/${app.name}/backend`);
4923
4985
  }
4924
4986
  async startBackend(app, { open: open2 = false, sync = true } = {}) {
4925
4987
  if (sync)
@@ -4929,7 +4991,9 @@ var ApplicationScript = class {
4929
4991
  async buildFrontend(app, { sync = true } = {}) {
4930
4992
  if (sync)
4931
4993
  await this.syncApplication(app);
4994
+ const spinner = app.spinning("Building frontend...");
4932
4995
  await this.#runner.buildFrontend(app);
4996
+ spinner.succeed(`Successfully built in dist/apps/${app.name}/frontend`);
4933
4997
  }
4934
4998
  async startFrontend(app, { open: open2 = false, turbo = false, sync = true } = {}) {
4935
4999
  if (sync)
@@ -4939,7 +5003,9 @@ var ApplicationScript = class {
4939
5003
  async buildCsr(app, { sync = true } = {}) {
4940
5004
  if (sync)
4941
5005
  await this.syncApplication(app);
5006
+ const spinner = app.spinning("Building CSR...");
4942
5007
  await this.#runner.buildCsr(app);
5008
+ spinner.succeed(`Successfully built in dist/apps/${app.name}/csr`);
4943
5009
  }
4944
5010
  async startCsr(app, { open: open2 = false, sync = true } = {}) {
4945
5011
  if (sync)
@@ -5003,10 +5069,16 @@ var ApplicationScript = class {
5003
5069
  await this.#runner.releaseSource(app, options);
5004
5070
  }
5005
5071
  async dbup(workspace) {
5072
+ const spinner = workspace.spinning("Starting local database...");
5006
5073
  await this.#runner.dbup(workspace);
5074
+ spinner.succeed(
5075
+ "Local database(/local/docker-compose.yaml) is up, you can start your application and connect to the database"
5076
+ );
5007
5077
  }
5008
5078
  async dbdown(workspace) {
5079
+ const spinner = workspace.spinning("Stopping local database...");
5009
5080
  await this.#runner.dbdown(workspace);
5081
+ spinner.succeed("Local database(/local/docker-compose.yaml) is down");
5010
5082
  }
5011
5083
  async testSys(sys2) {
5012
5084
  if (sys2.type === "app")
@@ -5023,13 +5095,13 @@ var ApplicationScript = class {
5023
5095
  var ApplicationCommand = class {
5024
5096
  applicationScript = new ApplicationScript();
5025
5097
  async createApplication(name, start, workspace) {
5026
- await this.applicationScript.createApplication(name, workspace, { start });
5098
+ await this.applicationScript.createApplication(name.toLowerCase().replace(/ /g, "-"), workspace, { start });
5027
5099
  }
5028
5100
  async removeApplication(app) {
5029
5101
  await this.applicationScript.removeApplication(app);
5030
5102
  }
5031
- async scanApplication(app) {
5032
- await this.applicationScript.scanApplication(app, true);
5103
+ async syncApplication(app, verbose) {
5104
+ await this.applicationScript.syncApplication(app, verbose);
5033
5105
  }
5034
5106
  async build(app) {
5035
5107
  await this.applicationScript.build(app);
@@ -5110,8 +5182,9 @@ __decorateClass([
5110
5182
  ], ApplicationCommand.prototype, "removeApplication", 1);
5111
5183
  __decorateClass([
5112
5184
  Target.Public(),
5113
- __decorateParam(0, App())
5114
- ], ApplicationCommand.prototype, "scanApplication", 1);
5185
+ __decorateParam(0, App()),
5186
+ __decorateParam(1, Option("verbose", { type: "boolean", desc: "verbose", default: false }))
5187
+ ], ApplicationCommand.prototype, "syncApplication", 1);
5115
5188
  __decorateClass([
5116
5189
  Target.Public({ short: true }),
5117
5190
  __decorateParam(0, App())
@@ -5522,7 +5595,7 @@ CloudCommand = __decorateClass([
5522
5595
  var LibraryCommand = class {
5523
5596
  libraryScript = new LibraryScript();
5524
5597
  async createLibrary(name, workspace) {
5525
- await this.libraryScript.createLibrary(name, workspace);
5598
+ await this.libraryScript.createLibrary(name.toLowerCase().replace(/ /g, "-"), workspace);
5526
5599
  }
5527
5600
  async removeLibrary(lib) {
5528
5601
  await this.libraryScript.removeLibrary(lib);
@@ -5591,11 +5664,19 @@ var ModuleRunner = class {
5591
5664
  async createScalarTemplate(sys2, name) {
5592
5665
  const akanConfig = await sys2.getConfig();
5593
5666
  const scanResult = await sys2.scan({ akanConfig });
5667
+ const names = pluralize(name);
5594
5668
  await sys2.applyTemplate({
5595
5669
  basePath: "./lib/__scalar",
5596
5670
  template: "__scalar",
5597
5671
  scanResult,
5598
- dict: { model: name, Model: capitalize(name), sysName: sys2.name, SysName: capitalize(sys2.name) }
5672
+ dict: {
5673
+ model: name,
5674
+ Model: capitalize(name),
5675
+ models: names,
5676
+ Models: capitalize(names),
5677
+ sysName: sys2.name,
5678
+ SysName: capitalize(sys2.name)
5679
+ }
5599
5680
  });
5600
5681
  await sys2.scan({ akanConfig });
5601
5682
  return {
@@ -5634,11 +5715,19 @@ var ModuleRunner = class {
5634
5715
  async createModuleTemplate(sys2, name) {
5635
5716
  const akanConfig = await sys2.getConfig();
5636
5717
  const scanResult = await sys2.scan({ akanConfig });
5718
+ const names = pluralize(name);
5637
5719
  await sys2.applyTemplate({
5638
5720
  basePath: `./lib/${name}`,
5639
5721
  template: "module",
5640
5722
  scanResult,
5641
- dict: { model: name, Model: capitalize(name), sysName: sys2.name, SysName: capitalize(sys2.name) }
5723
+ dict: {
5724
+ model: name,
5725
+ Model: capitalize(name),
5726
+ models: names,
5727
+ Models: capitalize(names),
5728
+ sysName: sys2.name,
5729
+ SysName: capitalize(sys2.name)
5730
+ }
5642
5731
  });
5643
5732
  await sys2.scan({ akanConfig });
5644
5733
  return {
@@ -5931,7 +6020,7 @@ var PackageCommand = class {
5931
6020
  await this.packageScript.version(workspace);
5932
6021
  }
5933
6022
  async createPackage(name, workspace) {
5934
- await this.packageScript.createPackage(workspace, name);
6023
+ await this.packageScript.createPackage(workspace, name.toLowerCase().replace(/ /g, "-"));
5935
6024
  }
5936
6025
  async removePackage(pkg) {
5937
6026
  await this.packageScript.removePackage(pkg);
@@ -6141,7 +6230,7 @@ var WorkspaceScript = class {
6141
6230
  var WorkspaceCommand = class {
6142
6231
  workspaceScript = new WorkspaceScript();
6143
6232
  async createWorkspace(name, app, dir) {
6144
- await this.workspaceScript.createWorkspace(name, app, dir);
6233
+ await this.workspaceScript.createWorkspace(name, app.toLowerCase().replace(/ /g, "-"), dir);
6145
6234
  }
6146
6235
  async generateMongo(workspace) {
6147
6236
  await this.workspaceScript.generateMongo(workspace);
@@ -3,6 +3,7 @@ function getContent(scanResult, dict) {
3
3
  return {
4
4
  filename: "layout.tsx",
5
5
  content: `
6
+ import "../(${dict.appName})/styles.css";
6
7
  import { System } from "@shared/ui";
7
8
  import { env } from "@${dict.appName}/env/env.client";
8
9
  import { fetch } from "@${dict.appName}/client";
@@ -20,6 +20,7 @@
20
20
  "jiti": "^2.4.2",
21
21
  "os-browserify": "^0.3.0",
22
22
  "prettier": "^3.5.3",
23
+ "prettier-plugin-tailwindcss": "^0.6.11",
23
24
  "process": "^0.11.10",
24
25
  "stream-browserify": "^3.0.0",
25
26
  "stream-http": "^3.2.0",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "sourceType": "module",
3
3
  "name": "@akanjs/cli",
4
- "version": "0.0.136",
4
+ "version": "0.0.138",
5
5
  "bin": {
6
6
  "akan": "cjs/index.js"
7
7
  },
@@ -4,7 +4,7 @@ export declare class ApplicationCommand {
4
4
  applicationScript: ApplicationScript;
5
5
  createApplication(name: string, start: boolean, workspace: Workspace): Promise<void>;
6
6
  removeApplication(app: App): Promise<void>;
7
- scanApplication(app: App): Promise<void>;
7
+ syncApplication(app: App, verbose: boolean): Promise<void>;
8
8
  build(app: App): Promise<void>;
9
9
  buildBackend(app: App): Promise<void>;
10
10
  buildFrontend(app: App): Promise<void>;
@@ -8,8 +8,7 @@ export declare class ApplicationScript {
8
8
  start?: boolean;
9
9
  }): Promise<void>;
10
10
  removeApplication(app: App): Promise<void>;
11
- scanApplication(app: App, verbose?: boolean): Promise<import("@akanjs/config").AppScanResult | import("@akanjs/config").LibScanResult>;
12
- syncApplication(app: App): Promise<import("@akanjs/config").AppScanResult | import("@akanjs/config").LibScanResult>;
11
+ syncApplication(app: App, verbose?: boolean): Promise<import("@akanjs/config").AppScanResult | import("@akanjs/config").LibScanResult>;
13
12
  build(app: App): Promise<void>;
14
13
  start(app: App, { open }?: {
15
14
  open?: boolean;