@akanjs/cli 2.1.1-rc.0 → 2.1.1-rc.2

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.
@@ -17,10 +17,7 @@ import { ChatOpenAI } from "@langchain/openai";
17
17
  import { Logger as Logger2 } from "akanjs/common";
18
18
  import chalk from "chalk";
19
19
 
20
- // pkgs/@akanjs/devkit/auth.ts
21
- import { mkdir } from "fs/promises";
22
-
23
- // pkgs/@akanjs/devkit/constants.ts
20
+ // pkgs/@akanjs/devkit/cloud/constants.ts
24
21
  var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
25
22
  var configPath = `${basePath}/config.json`;
26
23
  var akanCloudHost = process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? "http://localhost" : "https://cloud.akanjs.com";
@@ -28,9 +25,14 @@ var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE ===
28
25
  var defaultHostConfig = {};
29
26
  var defaultAkanGlobalConfig = {
30
27
  cloudHost: {},
28
+ remoteEnvServers: {},
31
29
  llm: null
32
30
  };
33
31
 
32
+ // pkgs/@akanjs/devkit/cloud/globalConfig.ts
33
+ import { mkdir } from "fs/promises";
34
+ import dayjs from "dayjs";
35
+
34
36
  // pkgs/@akanjs/devkit/fileSys.ts
35
37
  import { stat } from "fs/promises";
36
38
  import { Logger } from "akanjs/common";
@@ -69,35 +71,198 @@ class FileSys {
69
71
  }
70
72
  }
71
73
 
72
- // pkgs/@akanjs/devkit/auth.ts
73
- var getAkanGlobalConfig = async () => {
74
- const exists = await FileSys.fileExists(configPath);
75
- const akanConfig = exists ? await FileSys.readJson(configPath) : defaultAkanGlobalConfig;
76
- return akanConfig;
77
- };
78
- var setAkanGlobalConfig = async (akanConfig) => {
79
- await mkdir(basePath, { recursive: true });
80
- await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
81
- };
82
- var getHostConfig = async (host = akanCloudHost) => {
83
- const akanConfig = await getAkanGlobalConfig();
84
- return akanConfig.cloudHost[host] ?? defaultHostConfig;
85
- };
86
- var setHostConfig = async (host = akanCloudHost, config = {}) => {
87
- const akanConfig = await getAkanGlobalConfig();
88
- akanConfig.cloudHost[host] = config;
89
- await setAkanGlobalConfig(akanConfig);
90
- };
91
- var getSelf = async (token) => {
92
- try {
93
- const res = await fetch(`${akanCloudUrl}/user/getSelf`, { headers: { Authorization: `Bearer ${token}` } });
94
- const user = await res.json();
95
- return user;
96
- } catch (e) {
97
- return null;
74
+ // pkgs/@akanjs/devkit/cloud/globalConfig.ts
75
+ class GlobalConfig {
76
+ static async#getAkanGlobalConfig() {
77
+ const exists = await FileSys.fileExists(configPath);
78
+ const akanConfig = exists ? await FileSys.readJson(configPath) : {};
79
+ return {
80
+ ...defaultAkanGlobalConfig,
81
+ ...akanConfig,
82
+ cloudHost: akanConfig.cloudHost ?? defaultAkanGlobalConfig.cloudHost,
83
+ remoteEnvServers: akanConfig.remoteEnvServers ?? defaultAkanGlobalConfig.remoteEnvServers
84
+ };
98
85
  }
99
- };
86
+ static async#setAkanGlobalConfig(akanConfig) {
87
+ await mkdir(basePath, { recursive: true });
88
+ await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
89
+ }
90
+ static async getHostConfig(host = akanCloudHost) {
91
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
92
+ return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? defaultHostConfig);
93
+ }
94
+ static async setHostConfig(host = akanCloudHost, config = {}) {
95
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
96
+ akanConfig.cloudHost[host] = GlobalConfig.toHostConfigDto(config);
97
+ await GlobalConfig.#setAkanGlobalConfig(akanConfig);
98
+ }
99
+ static async getLlmConfig() {
100
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
101
+ return akanConfig.llm ?? null;
102
+ }
103
+ static async setLlmConfig(llmConfig) {
104
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
105
+ await GlobalConfig.#setAkanGlobalConfig({ ...akanConfig, llm: llmConfig });
106
+ }
107
+ static async getRemoteEnvServers() {
108
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
109
+ return akanConfig.remoteEnvServers;
110
+ }
111
+ static async setRemoteEnvServer(name, config) {
112
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
113
+ await GlobalConfig.#setAkanGlobalConfig({
114
+ ...akanConfig,
115
+ remoteEnvServers: {
116
+ ...akanConfig.remoteEnvServers,
117
+ [name]: config
118
+ }
119
+ });
120
+ }
121
+ static async removeRemoteEnvServer(name) {
122
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
123
+ const { [name]: _, ...remoteEnvServers } = akanConfig.remoteEnvServers;
124
+ await GlobalConfig.#setAkanGlobalConfig({
125
+ ...akanConfig,
126
+ remoteEnvServers
127
+ });
128
+ }
129
+ static needRefreshToken(accessToken) {
130
+ return !!accessToken?.expiresAt?.isBefore(dayjs().add(1, "hour"));
131
+ }
132
+ static toAccessToken(accessToken) {
133
+ return {
134
+ jwt: accessToken.jwt,
135
+ refreshToken: accessToken.refreshToken ?? null,
136
+ expiresAt: accessToken.expiresAt ? dayjs(accessToken.expiresAt) : null
137
+ };
138
+ }
139
+ static toAccessTokenDto(accessToken) {
140
+ return {
141
+ jwt: accessToken.jwt,
142
+ refreshToken: accessToken.refreshToken ?? null,
143
+ expiresAt: accessToken.expiresAt?.toString() ?? null
144
+ };
145
+ }
146
+ static toHostConfigDto(hostConfig) {
147
+ return {
148
+ auth: {
149
+ accessToken: hostConfig.auth?.accessToken ? GlobalConfig.toAccessTokenDto(hostConfig.auth.accessToken) : undefined,
150
+ self: hostConfig.auth?.self
151
+ }
152
+ };
153
+ }
154
+ static toHostConfig(hostConfigDto) {
155
+ return {
156
+ auth: {
157
+ accessToken: hostConfigDto.auth?.accessToken ? GlobalConfig.toAccessToken(hostConfigDto.auth.accessToken) : undefined,
158
+ self: hostConfigDto.auth?.self
159
+ }
160
+ };
161
+ }
162
+ }
100
163
 
164
+ // pkgs/@akanjs/devkit/cloud/cloudApi.ts
165
+ class HttpClient {
166
+ baseUrl;
167
+ headers = {};
168
+ constructor(baseUrl, headers = {}) {
169
+ this.baseUrl = baseUrl;
170
+ this.headers = headers;
171
+ }
172
+ async get(url, { headers } = {}) {
173
+ const response = await fetch(`${this.baseUrl}${url}`, {
174
+ headers: {
175
+ "Content-Type": "application/json",
176
+ ...this.headers,
177
+ ...headers
178
+ }
179
+ });
180
+ return response.json();
181
+ }
182
+ async getFile(url, localPath, headers) {
183
+ const response = await fetch(`${this.baseUrl}${url}`, {
184
+ headers: { ...this.headers, ...headers }
185
+ });
186
+ if (!response.ok)
187
+ throw new Error(`Failed to download file: ${response.status} ${response.statusText}`);
188
+ await Bun.write(localPath, response);
189
+ }
190
+ async post(url, data, { headers } = {}) {
191
+ const isFormData = data instanceof FormData;
192
+ const response = await fetch(`${this.baseUrl}${url}`, {
193
+ method: "POST",
194
+ body: isFormData ? data : JSON.stringify(data),
195
+ headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers }
196
+ });
197
+ return response.json();
198
+ }
199
+ setHeaders(headers) {
200
+ Object.assign(this.headers, headers);
201
+ return this;
202
+ }
203
+ }
204
+
205
+ class CloudApi {
206
+ #api;
207
+ #accessToken = null;
208
+ static async fromHost(host) {
209
+ const hostConfig = await GlobalConfig.getHostConfig(host);
210
+ return new CloudApi(hostConfig);
211
+ }
212
+ constructor(hostConfig) {
213
+ const host = akanCloudHost;
214
+ this.#api = new HttpClient(`${host}/api`);
215
+ this.#accessToken = hostConfig.auth?.accessToken ?? null;
216
+ if (this.#accessToken && !GlobalConfig.needRefreshToken(this.#accessToken))
217
+ this.#api.setHeaders({
218
+ Authorization: `Bearer ${this.#accessToken.jwt}`
219
+ });
220
+ }
221
+ async uploadEnv(devProjectId, file) {
222
+ const formData = new FormData;
223
+ formData.append("devProjectId", devProjectId);
224
+ formData.append("file", file);
225
+ const data = await this.#api.post(`/uploadEnv/${devProjectId}`, formData);
226
+ return data;
227
+ }
228
+ async downloadEnv(devProjectId, localPath) {
229
+ await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
230
+ }
231
+ async getRemoteAuthToken(remoteId) {
232
+ try {
233
+ if (this.#accessToken) {
234
+ if (GlobalConfig.needRefreshToken(this.#accessToken))
235
+ return await this.refreshAuthToken();
236
+ else
237
+ return await this.refreshAuthToken();
238
+ }
239
+ const accessToken = await this.#api.get(`/getRemoteAuthToken/${remoteId}`);
240
+ this.#accessToken = GlobalConfig.toAccessToken(accessToken);
241
+ this.#api.setHeaders({
242
+ Authorization: `Bearer ${this.#accessToken.jwt}`
243
+ });
244
+ return this.#accessToken;
245
+ } catch (_) {
246
+ return null;
247
+ }
248
+ }
249
+ async refreshAuthToken() {
250
+ const response = await this.#api.post(`/refreshRemoteAuthToken`, {
251
+ refreshToken: this.#accessToken?.refreshToken
252
+ });
253
+ this.#accessToken = GlobalConfig.toAccessToken(response);
254
+ this.#api.setHeaders({ Authorization: `Bearer ${this.#accessToken.jwt}` });
255
+ return this.#accessToken;
256
+ }
257
+ async getRemoteSelf() {
258
+ try {
259
+ const data = await this.#api.get(`/getRemoteSelf`);
260
+ return data;
261
+ } catch {
262
+ return null;
263
+ }
264
+ }
265
+ }
101
266
  // pkgs/@akanjs/devkit/spinner.ts
102
267
  import ora from "ora";
103
268
 
@@ -160,12 +325,18 @@ class Spinner {
160
325
 
161
326
  // pkgs/@akanjs/devkit/aiEditor.ts
162
327
  var MAX_ASK_TRY = 300;
163
- var supportedLlmModels = ["deepseek-chat", "deepseek-reasoner"];
328
+ var supportedLlmModels = [
329
+ "deepseek-chat",
330
+ "deepseek-reasoner"
331
+ ];
164
332
 
165
333
  class AiSession {
166
334
  static #cacheDir = "node_modules/.cache/akan/aiSession";
167
335
  static #chat = null;
168
- static async init({ temperature = 0, useExisting = true } = {}) {
336
+ static async init({
337
+ temperature = 0,
338
+ useExisting = true
339
+ } = {}) {
169
340
  if (useExisting) {
170
341
  const llmConfig2 = await AiSession.getLlmConfig();
171
342
  if (llmConfig2) {
@@ -192,22 +363,24 @@ class AiSession {
192
363
  return AiSession;
193
364
  }
194
365
  static async getLlmConfig() {
195
- const akanConfig = await getAkanGlobalConfig();
196
- return akanConfig.llm ?? null;
366
+ return await GlobalConfig.getLlmConfig();
197
367
  }
198
368
  static async setLlmConfig(llmConfig) {
199
- const akanConfig = await getAkanGlobalConfig();
200
- akanConfig.llm = llmConfig;
201
- await setAkanGlobalConfig(akanConfig);
369
+ await GlobalConfig.setLlmConfig(llmConfig);
202
370
  return AiSession;
203
371
  }
204
372
  static async#requestLlmConfig() {
205
- const model = await select({ message: "Select a LLM model", choices: supportedLlmModels });
373
+ const model = await select({
374
+ message: "Select a LLM model",
375
+ choices: supportedLlmModels
376
+ });
206
377
  const apiKey = await input({ message: "Enter your API key" });
207
378
  return { model, apiKey };
208
379
  }
209
380
  static async#validateApiKey(modelName, apiKey) {
210
- const spinner = new Spinner("Validating LLM API key...", { prefix: `\uD83E\uDD16akan-editor` }).start();
381
+ const spinner = new Spinner("Validating LLM API key...", {
382
+ prefix: `\uD83E\uDD16akan-editor`
383
+ }).start();
211
384
  const chat = new ChatOpenAI({
212
385
  modelName,
213
386
  temperature: 0,
@@ -230,7 +403,11 @@ class AiSession {
230
403
  sessionKey;
231
404
  isCacheLoaded = false;
232
405
  workspace;
233
- constructor(type, { workspace, cacheKey, isContinued }) {
406
+ constructor(type, {
407
+ workspace,
408
+ cacheKey,
409
+ isContinued
410
+ }) {
234
411
  this.workspace = workspace;
235
412
  this.sessionKey = `${type}${cacheKey ? `-${cacheKey}` : ""}`;
236
413
  if (isContinued)
@@ -305,7 +482,13 @@ class AiSession {
305
482
  throw new Error("Failed to stream response");
306
483
  }
307
484
  }
308
- async edit(question, { onChunk, onReasoning, maxTry = MAX_ASK_TRY, validate, approve } = {}) {
485
+ async edit(question, {
486
+ onChunk,
487
+ onReasoning,
488
+ maxTry = MAX_ASK_TRY,
489
+ validate,
490
+ approve
491
+ } = {}) {
309
492
  for (let tryCount = 0;tryCount < maxTry; tryCount++) {
310
493
  let response = await this.ask(question, { onChunk, onReasoning });
311
494
  if (validate?.length && tryCount === 0) {
@@ -358,7 +541,9 @@ ${validate.map((v) => `- ${v}`).join(`
358
541
  async#tryFixTypescripts(writes, executor, options = {}) {
359
542
  const MAX_EDIT_TRY = 5;
360
543
  for (let tryCount = 0;tryCount < MAX_EDIT_TRY; tryCount++) {
361
- const loader = new Spinner(`Type checking and linting...`, { prefix: `\uD83E\uDD16akan-editor` }).start();
544
+ const loader = new Spinner(`Type checking and linting...`, {
545
+ prefix: `\uD83E\uDD16akan-editor`
546
+ }).start();
362
547
  const fileChecks = await Promise.all(writes.map(async ({ filePath }) => {
363
548
  const typeCheckResult = executor.typeCheck(filePath);
364
549
  const lintResult = await executor.lint(filePath);
@@ -2166,11 +2351,26 @@ class Executor {
2166
2351
  });
2167
2352
  return new Promise((resolve, reject) => {
2168
2353
  proc.on("error", (error) => {
2169
- reject(new CommandExecutionError({ command, cwd, code: null, signal: null, stdout, stderr, cause: error }));
2354
+ reject(new CommandExecutionError({
2355
+ command,
2356
+ cwd,
2357
+ code: null,
2358
+ signal: null,
2359
+ stdout,
2360
+ stderr,
2361
+ cause: error
2362
+ }));
2170
2363
  });
2171
2364
  proc.on("exit", (code, signal) => {
2172
2365
  if (!!code || signal)
2173
- reject(new CommandExecutionError({ command, cwd, code, signal, stdout, stderr }));
2366
+ reject(new CommandExecutionError({
2367
+ command,
2368
+ cwd,
2369
+ code,
2370
+ signal,
2371
+ stdout,
2372
+ stderr
2373
+ }));
2174
2374
  else
2175
2375
  resolve({ code, signal });
2176
2376
  });
@@ -2196,11 +2396,28 @@ class Executor {
2196
2396
  });
2197
2397
  return new Promise((resolve, reject) => {
2198
2398
  proc.on("error", (error) => {
2199
- reject(new CommandExecutionError({ command, args, cwd, code: null, signal: null, stdout, stderr, cause: error }));
2399
+ reject(new CommandExecutionError({
2400
+ command,
2401
+ args,
2402
+ cwd,
2403
+ code: null,
2404
+ signal: null,
2405
+ stdout,
2406
+ stderr,
2407
+ cause: error
2408
+ }));
2200
2409
  });
2201
2410
  proc.on("close", (code, signal) => {
2202
2411
  if (code !== 0 || signal)
2203
- reject(new CommandExecutionError({ command, args, cwd, code, signal, stdout, stderr }));
2412
+ reject(new CommandExecutionError({
2413
+ command,
2414
+ args,
2415
+ cwd,
2416
+ code,
2417
+ signal,
2418
+ stdout,
2419
+ stderr
2420
+ }));
2204
2421
  else
2205
2422
  resolve(stdout);
2206
2423
  });
@@ -2244,7 +2461,15 @@ class Executor {
2244
2461
  });
2245
2462
  proc.on("exit", (code, signal) => {
2246
2463
  if (!!code || signal)
2247
- reject(new CommandExecutionError({ command: modulePath, args, cwd, code, signal, stdout, stderr }));
2464
+ reject(new CommandExecutionError({
2465
+ command: modulePath,
2466
+ args,
2467
+ cwd,
2468
+ code,
2469
+ signal,
2470
+ stdout,
2471
+ stderr
2472
+ }));
2248
2473
  else
2249
2474
  resolve({ code, signal });
2250
2475
  });
@@ -2391,7 +2616,10 @@ class Executor {
2391
2616
  const result = {
2392
2617
  ...extendsTsconfig,
2393
2618
  ...tsconfig,
2394
- compilerOptions: { ...extendsTsconfig.compilerOptions, ...tsconfig.compilerOptions }
2619
+ compilerOptions: {
2620
+ ...extendsTsconfig.compilerOptions,
2621
+ ...tsconfig.compilerOptions
2622
+ }
2395
2623
  };
2396
2624
  this.#tsconfig = result;
2397
2625
  return result;
@@ -2446,7 +2674,9 @@ class Executor {
2446
2674
  const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath.slice(0, -9));
2447
2675
  const convertedContent = Object.entries(dict).reduce((data, [key, value]) => data.replace(new RegExp(`<%= ${key} %>`, "g"), value), content);
2448
2676
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2449
- return this.writeFile(convertedTargetPath, convertedContent, { overwrite });
2677
+ return this.writeFile(convertedTargetPath, convertedContent, {
2678
+ overwrite
2679
+ });
2450
2680
  } else if (staticTemplateFileExtensions.has(path7.extname(targetPath).toLowerCase())) {
2451
2681
  const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath);
2452
2682
  const writePath = this.getPath(convertedTargetPath);
@@ -2472,14 +2702,24 @@ class Executor {
2472
2702
  const prefixTemplatePath = templatePath;
2473
2703
  if ((await stat2(prefixTemplatePath)).isFile()) {
2474
2704
  const filename = path7.basename(prefixTemplatePath);
2475
- const fileContent = await this.#applyTemplateFile({ templatePath: prefixTemplatePath, targetPath: path7.join(basePath2, filename), scanInfo, overwrite }, dict, options);
2705
+ const fileContent = await this.#applyTemplateFile({
2706
+ templatePath: prefixTemplatePath,
2707
+ targetPath: path7.join(basePath2, filename),
2708
+ scanInfo,
2709
+ overwrite
2710
+ }, dict, options);
2476
2711
  return fileContent ? [fileContent] : [];
2477
2712
  } else {
2478
2713
  const subdirs = await readDirEntries(templatePath);
2479
2714
  const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
2480
2715
  const subpath = path7.join(templatePath, subdir);
2481
2716
  if ((await stat2(subpath)).isFile()) {
2482
- const fileContent = await this.#applyTemplateFile({ templatePath: subpath, targetPath: path7.join(basePath2, subdir), scanInfo, overwrite }, dict, options);
2717
+ const fileContent = await this.#applyTemplateFile({
2718
+ templatePath: subpath,
2719
+ targetPath: path7.join(basePath2, subdir),
2720
+ scanInfo,
2721
+ overwrite
2722
+ }, dict, options);
2483
2723
  return fileContent ? [fileContent] : [];
2484
2724
  } else
2485
2725
  return await this._applyTemplate({
@@ -2530,7 +2770,10 @@ class Executor {
2530
2770
  async lint(filePath, { fix = false, dryRun = false } = {}) {
2531
2771
  const path8 = this.getPath(filePath);
2532
2772
  const linter = this.getLinter();
2533
- const { results, errors, warnings } = await linter.lint(path8, { fix, dryRun });
2773
+ const { results, errors, warnings } = await linter.lint(path8, {
2774
+ fix,
2775
+ dryRun
2776
+ });
2534
2777
  const message = linter.formatLintResults(results);
2535
2778
  return { results, message, errors, warnings };
2536
2779
  }
@@ -2556,6 +2799,7 @@ class WorkspaceExecutor extends Executor {
2556
2799
  const sourceEnv = envPath ? { ...process.env, ...parseEnvFile(envPath) } : process.env;
2557
2800
  const appName = sourceEnv.AKAN_PUBLIC_APP_NAME;
2558
2801
  const workspaceRoot = sourceEnv.AKAN_WORKSPACE_ROOT;
2802
+ const workspaceId = sourceEnv.AKAN_WORKSPACE_ID;
2559
2803
  const repoName = sourceEnv.AKAN_PUBLIC_REPO_NAME;
2560
2804
  if (!repoName)
2561
2805
  throw new Error("AKAN_PUBLIC_REPO_NAME is not set");
@@ -2566,7 +2810,15 @@ class WorkspaceExecutor extends Executor {
2566
2810
  const env = sourceEnv.AKAN_PUBLIC_ENV ?? "debug";
2567
2811
  if (!env)
2568
2812
  throw new Error("AKAN_PUBLIC_ENV is not set");
2569
- return { ...appName ? { appName } : {}, workspaceRoot, repoName, serveDomain, env, portOffset };
2813
+ return { ...appName ? { appName } : {}, workspaceRoot, repoName, serveDomain, env, portOffset, workspaceId };
2814
+ }
2815
+ getWorkspaceId({
2816
+ allowEmpty
2817
+ } = {}) {
2818
+ const { workspaceId } = WorkspaceExecutor.getBaseDevEnv();
2819
+ if (!workspaceId && !allowEmpty)
2820
+ throw new Error("Workspace ID is not found");
2821
+ return workspaceId;
2570
2822
  }
2571
2823
  async scan() {
2572
2824
  return await WorkspaceInfo.fromExecutor(this);
@@ -2770,7 +3022,11 @@ class SysExecutor extends Executor {
2770
3022
  } = {}) {
2771
3023
  if (this.#scanInfo && !refresh)
2772
3024
  return this.#scanInfo;
2773
- const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, { refresh }) : await LibInfo.fromExecutor(this, { refresh });
3025
+ const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, {
3026
+ refresh
3027
+ }) : await LibInfo.fromExecutor(this, {
3028
+ refresh
3029
+ });
2774
3030
  if (write) {
2775
3031
  await Promise.all(this.#getScanTemplateTasks(scanInfo));
2776
3032
  await this.writeJson(`akan.${this.type}.json`, scanInfo.getScanResult());
@@ -2879,7 +3135,11 @@ class SysExecutor extends Executor {
2879
3135
  ...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [capitalize(key), capitalize(value)]))
2880
3136
  };
2881
3137
  const scanInfo = await this.scan();
2882
- const fileContents = await this._applyTemplate({ ...options, scanInfo, dict });
3138
+ const fileContents = await this._applyTemplate({
3139
+ ...options,
3140
+ scanInfo,
3141
+ dict
3142
+ });
2883
3143
  await this.scan();
2884
3144
  return fileContents;
2885
3145
  }
@@ -2985,7 +3245,11 @@ class AppExecutor extends SysExecutor {
2985
3245
  this.#pageKeys = [];
2986
3246
  return this.#pageKeys;
2987
3247
  }
2988
- for await (const rel of glob.scan({ cwd: pageDir, absolute: false, onlyFiles: true })) {
3248
+ for await (const rel of glob.scan({
3249
+ cwd: pageDir,
3250
+ absolute: false,
3251
+ onlyFiles: true
3252
+ })) {
2989
3253
  const segments = rel.split(path7.sep);
2990
3254
  if (segments.some((s) => s === "node_modules"))
2991
3255
  continue;
@@ -2995,7 +3259,10 @@ class AppExecutor extends SysExecutor {
2995
3259
  if (!isRouteSourceFile(posix))
2996
3260
  continue;
2997
3261
  const key = `./${posix}`;
2998
- validateSubRoutePageKey(key, akanConfig2.basePaths, { appName: this.name, filePath: absPath });
3262
+ validateSubRoutePageKey(key, akanConfig2.basePaths, {
3263
+ appName: this.name,
3264
+ filePath: absPath
3265
+ });
2999
3266
  const parsed = parseRouteModuleKey(key);
3000
3267
  if (parsed.isInternalRootLayout) {
3001
3268
  throw new Error(`[route-convention] __root_layout is reserved for Akan.js generated root layout: ${absPath}`);
@@ -3035,7 +3302,11 @@ class AppExecutor extends SysExecutor {
3035
3302
  ]);
3036
3303
  }
3037
3304
  async scanSync({ refresh = false, write = true } = {}) {
3038
- const scanInfo = await this.scan({ refresh, write, writeLib: write });
3305
+ const scanInfo = await this.scan({
3306
+ refresh,
3307
+ write,
3308
+ writeLib: write
3309
+ });
3039
3310
  if (write)
3040
3311
  await this.syncAssets(scanInfo.getScanResult().libDeps);
3041
3312
  return scanInfo;
@@ -3099,7 +3370,10 @@ class PkgExecutor extends Executor {
3099
3370
  return scanInfo;
3100
3371
  }
3101
3372
  async#getDependencyVersion(rootPackageJson, dep) {
3102
- const rootDeps = { ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies };
3373
+ const rootDeps = {
3374
+ ...rootPackageJson.dependencies,
3375
+ ...rootPackageJson.devDependencies
3376
+ };
3103
3377
  const rootVersion = rootDeps[dep];
3104
3378
  if (rootVersion)
3105
3379
  return rootVersion;
@@ -3155,7 +3429,14 @@ class PkgExecutor extends Executor {
3155
3429
  const distPkgJson = {
3156
3430
  ...pkgJson,
3157
3431
  type: "module",
3158
- exports: { ...pkgJson.exports, ".": { import: "./index.ts", types: "./index.ts", default: "./index.ts" } },
3432
+ exports: {
3433
+ ...pkgJson.exports,
3434
+ ".": {
3435
+ import: "./index.ts",
3436
+ types: "./index.ts",
3437
+ default: "./index.ts"
3438
+ }
3439
+ },
3159
3440
  engines: { bun: ">=1.3.13" },
3160
3441
  ...dependencyMaps
3161
3442
  };
@@ -7449,7 +7730,7 @@ class ApplicationBuildRunner {
7449
7730
  import { cp, mkdir as mkdir8, rm as rm3 } from "fs/promises";
7450
7731
 
7451
7732
  // pkgs/@akanjs/devkit/uploadRelease.ts
7452
- import { HttpClient, Logger as Logger10 } from "akanjs/common";
7733
+ import { HttpClient as HttpClient2, Logger as Logger10 } from "akanjs/common";
7453
7734
  var spinning = (message) => {
7454
7735
  const spinner = new Spinner(message, { prefix: message, enableSpin: true }).start();
7455
7736
  return spinner;
@@ -7464,7 +7745,7 @@ var uploadRelease = async (appName, {
7464
7745
  }) => {
7465
7746
  const logger = new Logger10("uploadRelease");
7466
7747
  const basePath2 = local ? "http://localhost:8282/backend" : "https://cloud.akanjs.com/backend";
7467
- const httpClient = new HttpClient(basePath2);
7748
+ const httpClient = new HttpClient2(basePath2);
7468
7749
  const buildPath = `${workspaceRoot}/releases/builds/${appName}-release.tar.gz`;
7469
7750
  const appBuildPath = `${workspaceRoot}/releases/builds/${appName}-appBuild.zip`;
7470
7751
  const sourcePath = `${workspaceRoot}/releases/sources/${appName}-source.tar.gz`;
@@ -9451,75 +9732,6 @@ import { Box as Box2, Newline, Text as Text2, useInput as useInput2 } from "ink"
9451
9732
  import { useEffect as useEffect3, useState as useState3 } from "react";
9452
9733
  import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
9453
9734
  "use client";
9454
- // pkgs/@akanjs/devkit/cloud/cloudApi.ts
9455
- class HttpClient2 {
9456
- baseUrl;
9457
- constructor(baseUrl) {
9458
- this.baseUrl = baseUrl;
9459
- }
9460
- async get(url, { headers } = {}) {
9461
- const response = await fetch(`${this.baseUrl}${url}`, {
9462
- headers: { "Content-Type": "application/json", ...headers }
9463
- });
9464
- return response.json();
9465
- }
9466
- async post(url, data, { headers } = {}) {
9467
- const isFormData = data instanceof FormData;
9468
- const response = await fetch(`${this.baseUrl}${url}`, {
9469
- method: "POST",
9470
- body: isFormData ? data : JSON.stringify(data),
9471
- headers: isFormData ? headers : { "Content-Type": "application/json", ...headers }
9472
- });
9473
- return response.json();
9474
- }
9475
- }
9476
-
9477
- class CloudApi {
9478
- api;
9479
- #accessToken = null;
9480
- constructor(host, { accessToken } = {}) {
9481
- this.api = new HttpClient2(`${host}/api`);
9482
- this.#accessToken = accessToken ?? null;
9483
- }
9484
- async uploadEnv(devProjectId, fileStream) {
9485
- const formData = new FormData;
9486
- formData.append("devProjectId", devProjectId);
9487
- formData.append("fileStream", await new Response(fileStream).blob());
9488
- const response = await this.api.post(`/uploadEnv/${devProjectId}`, formData);
9489
- return response.success;
9490
- }
9491
- async downloadEnv(devProjectId) {
9492
- const response = await this.api.get(`/downloadEnv/${devProjectId}`);
9493
- return response.success;
9494
- }
9495
- async getRemoteAuthToken(remoteId) {
9496
- if (this.#needRefreshToken())
9497
- return await this.refreshAuthToken();
9498
- else if (this.#accessToken)
9499
- return this.#accessToken;
9500
- const accessToken = await this.api.get(`/getRemoteAuthToken/${remoteId}`);
9501
- this.#accessToken = {
9502
- jwt: accessToken.jwt,
9503
- refreshToken: accessToken.refreshToken,
9504
- expiresAt: new Date(accessToken.expiresAt)
9505
- };
9506
- return accessToken;
9507
- }
9508
- async refreshAuthToken() {
9509
- const response = await this.api.post(`/refreshRemoteAuthToken`, {
9510
- refreshToken: this.#accessToken?.refreshToken
9511
- });
9512
- this.#accessToken = {
9513
- jwt: response.jwt,
9514
- refreshToken: response.refreshToken,
9515
- expiresAt: new Date(response.expiresAt)
9516
- };
9517
- return response;
9518
- }
9519
- #needRefreshToken() {
9520
- return !!(this.#accessToken?.expiresAt && this.#accessToken.expiresAt.getTime() < Date.now() - 1000 * 60 * 60);
9521
- }
9522
- }
9523
9735
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
9524
9736
  import { Logger as Logger12 } from "akanjs/common";
9525
9737